Переглянути джерело

Fixed extra value left on stack when 'this' escapes to stash.

Dmitry Panov 4 місяців тому
батько
коміт
cb187b0869
3 змінених файлів з 89 додано та 1 видалено
  1. 6 0
      compiler.go
  2. 4 1
      compiler_expr.go
  3. 79 0
      compiler_test.go

+ 6 - 0
compiler.go

@@ -649,6 +649,8 @@ func (s *scope) finaliseVarAlloc(stackOffset int) (stashSize, stackSize int) {
 								*ap = loadThisStash(idx)
 							case initStack:
 								*ap = initStash(idx)
+							case initStackP:
+								*ap = initStashP(idx)
 							case resolveThisStack:
 								*ap = resolveThisStash(idx)
 							case _ret:
@@ -665,6 +667,8 @@ func (s *scope) finaliseVarAlloc(stackOffset int) (stashSize, stackSize int) {
 								*ap = loadStash(idx)
 							case initStack:
 								*ap = initStash(idx)
+							case initStackP:
+								*ap = initStashP(idx)
 							default:
 								s.c.assert(false, s.c.p.sourceOffset(pc), "Unsupported instruction for 'this'")
 							}
@@ -734,6 +738,8 @@ func (s *scope) finaliseVarAlloc(stackOffset int) (stashSize, stackSize int) {
 								*ap = loadThisStack{}
 							case initStack:
 								// no-op
+							case initStackP:
+								// no-op
 							case resolveThisStack:
 								// no-op
 							case _ret:

+ 4 - 1
compiler_expr.go

@@ -1685,6 +1685,7 @@ func (e *compiledFunctionLiteral) compile() (prg *Program, name unistring.String
 		}
 	}
 
+	needInitThis := false
 	if thisBinding != nil {
 		if !s.isDynamic() && thisBinding.useCount() == 0 {
 			s.deleteBinding(thisBinding)
@@ -1693,13 +1694,15 @@ func (e *compiledFunctionLiteral) compile() (prg *Program, name unistring.String
 			if thisBinding.inStash || s.isDynamic() {
 				delta++
 				thisBinding.emitInitAtScope(s, preambleLen-delta)
+				needInitThis = true
 			}
 		}
 	}
 
 	stashSize, stackSize := s.finaliseVarAlloc(0)
 
-	if thisBinding != nil && thisBinding.inStash && (!s.argsInStash || stackSize > 0) {
+	if needInitThis && (s.numArgs > 0 && !s.argsInStash || stackSize > 0) {
+		code[preambleLen-delta] = initStashP(code[preambleLen-delta].(initStash))
 		delta++
 		code[preambleLen-delta] = loadStack(0)
 	} // otherwise, 'this' will be at stack[sp-1], no need to load

+ 79 - 0
compiler_test.go

@@ -5886,6 +5886,85 @@ func TestNestedDestructArray(t *testing.T) {
 	testScriptWithTestLib(SCRIPT, _undefined, t)
 }
 
+func TestThisInStash(t *testing.T) {
+	const SCRIPT = `
+	function f() {
+		globalThis.x = () => this; // move 'this' to stash
+		
+		{
+            try {
+                throw new Error("boo!");
+            } catch (e) {
+                if (e.message !== 'boo!') {
+					throw new Error("unexpected exception value");
+				}
+            }
+        }
+	}
+
+	function f1() {
+		globalThis.x = () => this; // move 'this' to stash
+		var v; // introduce a stack variable
+
+		{
+            try {
+                throw new Error("boo!");
+            } catch (e) {
+                if (e.message !== 'boo!') {
+					throw new Error("unexpected exception value");
+				}
+            }
+        }
+	}
+
+	f();
+	f1();
+`
+	testScript(SCRIPT, _undefined, t)
+}
+
+func TestThisInStashCtor(t *testing.T) {
+	const SCRIPT = `
+	class C extends Object {
+		constructor() {
+			super();
+			globalThis.x = () => this; // move 'this' to stash
+			{
+				try {
+					throw new Error("boo!");
+				} catch (e) {
+					if (e.message !== 'boo!') {
+						throw new Error("unexpected exception value");
+					}
+				}
+			}	
+		}
+	}
+
+	class C1 extends Object {
+		constructor() {
+			super();
+			globalThis.x = () => this; // move 'this' to stash
+			var v; // introduce a stack variable
+			{
+				try {
+					throw new Error("boo!");
+				} catch (e) {
+					if (e.message !== 'boo!') {
+						throw new Error("unexpected exception value");
+					}
+				}
+			}	
+		}
+	}
+
+	new C();
+	new C1();
+	undefined;
+`
+	testScript(SCRIPT, _undefined, t)
+}
+
 /*
 func TestBabel(t *testing.T) {
 	src, err := os.ReadFile("babel7.js")