Browse Source

Optimised memory usage when generating function and class initialisation code

Dmitry Panov 3 years ago
parent
commit
d11430fb5f
2 changed files with 38 additions and 12 deletions
  1. 19 5
      compiler.go
  2. 19 7
      compiler_expr.go

+ 19 - 5
compiler.go

@@ -83,6 +83,8 @@ type compiler struct {
 
 
 	evalVM *vm // VM used to evaluate constant expressions
 	evalVM *vm // VM used to evaluate constant expressions
 	ctxVM  *vm // VM in which an eval() code is compiled
 	ctxVM  *vm // VM in which an eval() code is compiled
+
+	codeScratchpad []instruction
 }
 }
 
 
 type binding struct {
 type binding struct {
@@ -813,13 +815,25 @@ func (s *scope) moveArgsToStash() {
 	s.needStash = true
 	s.needStash = true
 }
 }
 
 
+func (c *compiler) trimCode(delta int) {
+	src := c.p.code[delta:]
+	newCode := make([]instruction, len(src))
+	copy(newCode, src)
+	if cap(c.codeScratchpad) < cap(c.p.code) {
+		c.codeScratchpad = c.p.code[:0]
+	}
+	c.p.code = newCode
+}
+
 func (s *scope) trimCode(delta int) {
 func (s *scope) trimCode(delta int) {
-	s.c.p.code = s.c.p.code[delta:]
-	srcMap := s.c.p.srcMap
-	for i := range srcMap {
-		srcMap[i].pc -= delta
+	s.c.trimCode(delta)
+	if delta != 0 {
+		srcMap := s.c.p.srcMap
+		for i := range srcMap {
+			srcMap[i].pc -= delta
+		}
+		s.adjustBase(-delta)
 	}
 	}
-	s.adjustBase(-delta)
 }
 }
 
 
 func (s *scope) adjustBase(delta int) {
 func (s *scope) adjustBase(delta int) {

+ 19 - 7
compiler_expr.go

@@ -1327,12 +1327,27 @@ func (c *compiler) compileParameterPatternBinding(item ast.Expression) {
 	c.createBindings(item, c.compileParameterPatternIdBinding)
 	c.createBindings(item, c.compileParameterPatternIdBinding)
 }
 }
 
 
+func (c *compiler) newCode(length, minCap int) (buf []instruction) {
+	if c.codeScratchpad != nil {
+		buf = c.codeScratchpad
+		c.codeScratchpad = nil
+	}
+	if cap(buf) < minCap {
+		buf = make([]instruction, length, minCap)
+	} else {
+		buf = buf[:length]
+	}
+	return
+}
+
 func (e *compiledFunctionLiteral) compile() (prg *Program, name unistring.String, length int, strict bool) {
 func (e *compiledFunctionLiteral) compile() (prg *Program, name unistring.String, length int, strict bool) {
 	e.c.assert(e.typ != funcNone, e.offset, "compiledFunctionLiteral.typ is not set")
 	e.c.assert(e.typ != funcNone, e.offset, "compiledFunctionLiteral.typ is not set")
 
 
 	savedPrg := e.c.p
 	savedPrg := e.c.p
+	preambleLen := 8 // enter, boxThis, loadStack(0), initThis, createArgs, set, loadCallee, init
 	e.c.p = &Program{
 	e.c.p = &Program{
-		src: e.c.p.src,
+		src:  e.c.p.src,
+		code: e.c.newCode(preambleLen, 16),
 	}
 	}
 	e.c.newScope()
 	e.c.newScope()
 	s := e.c.scope
 	s := e.c.scope
@@ -1431,8 +1446,6 @@ func (e *compiledFunctionLiteral) compile() (prg *Program, name unistring.String
 	body := e.body
 	body := e.body
 	funcs := e.c.extractFunctions(body)
 	funcs := e.c.extractFunctions(body)
 	var calleeBinding *binding
 	var calleeBinding *binding
-	preambleLen := 8 // enter, boxThis, loadStack(0), initThis, createArgs, set, loadCallee, init
-	e.c.p.code = make([]instruction, preambleLen, 16)
 
 
 	emitArgsRestMark := -1
 	emitArgsRestMark := -1
 	firstForwardRef := -1
 	firstForwardRef := -1
@@ -1689,9 +1702,7 @@ func (e *compiledFunctionLiteral) compile() (prg *Program, name unistring.String
 		}
 		}
 	}
 	}
 	code[delta] = enter
 	code[delta] = enter
-	if delta != 0 {
-		s.trimCode(delta)
-	}
+	s.trimCode(delta)
 
 
 	strict = s.strict
 	strict = s.strict
 	prg = e.c.p
 	prg = e.c.p
@@ -2131,7 +2142,7 @@ func (e *compiledClassLiteral) compileFieldsAndStaticBlocks(elements []clsElemen
 	e.c.p = &Program{
 	e.c.p = &Program{
 		src:      savedPrg.src,
 		src:      savedPrg.src,
 		funcName: funcName,
 		funcName: funcName,
-		code:     make([]instruction, 2, len(elements)*2+3),
+		code:     e.c.newCode(2, 16),
 	}
 	}
 
 
 	e.c.newScope()
 	e.c.newScope()
@@ -2191,6 +2202,7 @@ func (e *compiledClassLiteral) compileFieldsAndStaticBlocks(elements []clsElemen
 			enter.names = s.makeNamesMap()
 			enter.names = s.makeNamesMap()
 		}
 		}
 		e.c.p.code[0] = enter
 		e.c.p.code[0] = enter
+		s.trimCode(0)
 	} else {
 	} else {
 		s.trimCode(2)
 		s.trimCode(2)
 	}
 	}