Browse Source

Added missing support for setLocalP when converting non-dynamic catch blocks. Better mechanism for conversion.

Dmitry Panov 9 years ago
parent
commit
e7ca1f52dd
3 changed files with 51 additions and 66 deletions
  1. 27 30
      compiler.go
  2. 2 4
      compiler_expr.go
  3. 22 32
      compiler_stmt.go

+ 27 - 30
compiler.go

@@ -339,6 +339,24 @@ func (c *compiler) addDecls() []instruction {
 	return code
 }
 
+func (c *compiler) convertInstrToStashless(instr uint32, args int) (newIdx int, convert bool) {
+	level := instr >> 24
+	idx := instr & 0x00FFFFFF
+	if level > 0 {
+		level--
+		newIdx = int((level << 24) | idx)
+	} else {
+		iidx := int(idx)
+		if iidx < args {
+			newIdx = -iidx - 1
+		} else {
+			newIdx = iidx - args + 1
+		}
+		convert = true
+	}
+	return
+}
+
 func (c *compiler) convertFunctionToStashless(code []instruction, args int) {
 	code[0] = enterFuncStashless{stackSize: uint32(len(c.scope.names) - args), args: uint32(args)}
 	for pc := 1; pc < len(code); pc++ {
@@ -348,43 +366,22 @@ func (c *compiler) convertFunctionToStashless(code []instruction, args int) {
 		}
 		switch instr := instr.(type) {
 		case getLocal:
-			level := int(uint32(instr) >> 24)
-			idx := int(uint32(instr) & 0x00FFFFFF)
-			if level > 0 {
-				level--
-				code[pc] = getLocal((level << 24) | idx)
+			if newIdx, convert := c.convertInstrToStashless(uint32(instr), args); convert {
+				code[pc] = loadStack(newIdx)
 			} else {
-				if idx < args {
-					code[pc] = loadStack(-idx - 1)
-				} else {
-					code[pc] = loadStack(idx - args + 1)
-				}
+				code[pc] = getLocal(newIdx)
 			}
 		case setLocal:
-			level := int(uint32(instr) >> 24)
-			idx := int(instr & 0x00FFFFFF)
-			if level > 0 {
-				level--
-				code[pc] = setLocal((level << 24) | idx)
+			if newIdx, convert := c.convertInstrToStashless(uint32(instr), args); convert {
+				code[pc] = storeStack(newIdx)
 			} else {
-				if idx < args {
-					code[pc] = storeStack(-idx - 1)
-				} else {
-					code[pc] = storeStack(idx - args + 1)
-				}
+				code[pc] = setLocal(newIdx)
 			}
 		case setLocalP:
-			level := int(uint32(instr) >> 24)
-			idx := int(instr & 0x00FFFFFF)
-			if level > 0 {
-				level--
-				code[pc] = setLocal((level << 24) | idx)
+			if newIdx, convert := c.convertInstrToStashless(uint32(instr), args); convert {
+				code[pc] = storeStackP(newIdx)
 			} else {
-				if idx < args {
-					code[pc] = storeStackP(-idx - 1)
-				} else {
-					code[pc] = storeStackP(idx - args + 1)
-				}
+				code[pc] = setLocalP(newIdx)
 			}
 		case getVar:
 			level := instr.idx >> 24

+ 2 - 4
compiler_expr.go

@@ -806,7 +806,7 @@ func (e *compiledFunctionLiteral) emitGetter(putOnStack bool) {
 	} else {
 		l := 1 + len(e.c.scope.names)
 		if e.c.scope.argsNeeded {
-			l += 3
+			l += 2
 		}
 		if !e.c.scope.strict && e.c.scope.thisNeeded {
 			l++
@@ -835,9 +835,7 @@ func (e *compiledFunctionLiteral) emitGetter(putOnStack bool) {
 			if !exists {
 				panic("No arguments")
 			}
-			code[pos] = setLocal(idx)
-			pos++
-			code[pos] = pop
+			code[pos] = setLocalP(idx)
 			pos++
 		}
 

+ 22 - 32
compiler_stmt.go

@@ -115,42 +115,32 @@ func (c *compiler) compileTryStatement(v *ast.TryStatement) {
 			dynamicCatch = false
 			code := c.p.code[start+1:]
 			m := make(map[uint32]uint32)
+			remap := func(instr uint32) uint32 {
+				level := instr >> 24
+				idx := instr & 0x00FFFFFF
+				if level > 0 {
+					level--
+					return (level << 24) | idx
+				} else {
+					// remap
+					newIdx, exists := m[idx]
+					if !exists {
+						exname := " __tmp" + strconv.Itoa(c.scope.lastFreeTmp)
+						c.scope.lastFreeTmp++
+						newIdx, _ = c.scope.bindName(exname)
+						m[idx] = newIdx
+					}
+					return newIdx
+				}
+			}
 			for pc, instr := range code {
 				switch instr := instr.(type) {
 				case getLocal:
-					level := uint32(instr) >> 24
-					idx := uint32(instr) & 0x00FFFFFF
-					if level > 0 {
-						level--
-						code[pc] = getLocal((level << 24) | idx)
-					} else {
-						// remap
-						newIdx, exists := m[idx]
-						if !exists {
-							exname := " __tmp" + strconv.Itoa(c.scope.lastFreeTmp)
-							c.scope.lastFreeTmp++
-							newIdx, _ = c.scope.bindName(exname)
-							m[idx] = newIdx
-						}
-						code[pc] = getLocal(newIdx)
-					}
+					code[pc] = getLocal(remap(uint32(instr)))
 				case setLocal:
-					level := uint32(instr) >> 24
-					idx := uint32(instr) & 0x00FFFFFF
-					if level > 0 {
-						level--
-						code[pc] = setLocal((level << 24) | idx)
-					} else {
-						// remap
-						newIdx, exists := m[idx]
-						if !exists {
-							exname := " __tmp" + strconv.Itoa(c.scope.lastFreeTmp)
-							c.scope.lastFreeTmp++
-							newIdx, _ = c.scope.bindName(exname)
-							m[idx] = newIdx
-						}
-						code[pc] = setLocal(newIdx)
-					}
+					code[pc] = setLocal(remap(uint32(instr)))
+				case setLocalP:
+					code[pc] = setLocalP(remap(uint32(instr)))
 				}
 			}
 			if catchVarIdx, exists := m[0]; exists {