Sfoglia il codice sorgente

Got rid of funcName, using the callee object from the stack instead

Dmitry Panov 2 anni fa
parent
commit
bce2464272
5 ha cambiato i file con 81 aggiunte e 18 eliminazioni
  1. 2 2
      func.go
  2. 1 1
      proxy.go
  3. 1 1
      runtime.go
  4. 53 0
      runtime_test.go
  5. 24 14
      vm.go

+ 2 - 2
func.go

@@ -505,7 +505,7 @@ func (f *nativeFuncObject) vmCall(vm *vm, n int) {
 	if f.f != nil {
 		vm.pushCtx()
 		vm.prg = nil
-		vm.funcName = nilSafe(f.getStr("name", nil)).string()
+		vm.sb = vm.sp - n // so that [sb-1] points to the callee
 		ret := f.f(FunctionCall{
 			Arguments: vm.stack[vm.sp-n : vm.sp],
 			This:      vm.stack[vm.sp-n-2],
@@ -695,7 +695,7 @@ func (g *generator) storeLengths() {
 func (g *generator) enter() {
 	g.vm.pushCtx()
 	g.vm.pushTryFrame(tryPanicMarker, -1)
-	g.vm.prg, g.vm.funcName, g.vm.pc = nil, "", -2 // so that vm.run() halts after ret
+	g.vm.prg, g.vm.sb, g.vm.pc = nil, -1, -2 // so that vm.run() halts after ret
 	g.storeLengths()
 }
 

+ 1 - 1
proxy.go

@@ -868,7 +868,7 @@ func (p *proxyObject) assertCallable() (call func(FunctionCall) Value, ok bool)
 func (p *proxyObject) vmCall(vm *vm, n int) {
 	vm.pushCtx()
 	vm.prg = nil
-	vm.funcName = "proxy"
+	vm.sb = vm.sp - n // so that [sb-1] points to the callee
 	ret := p.apply(FunctionCall{This: vm.stack[vm.sp-n-2], Arguments: vm.stack[vm.sp-n : vm.sp]})
 	if ret == nil {
 		ret = _undefined

+ 1 - 1
runtime.go

@@ -1453,7 +1453,7 @@ func (r *Runtime) RunProgram(p *Program) (result Value, err error) {
 		vm.clearStack()
 	} else {
 		vm.prg = nil
-		vm.funcName = ""
+		vm.sb = -1
 		r.leave()
 	}
 	return

+ 53 - 0
runtime_test.go

@@ -2246,6 +2246,59 @@ func TestStacktraceLocationThrowFromGo(t *testing.T) {
 	}
 }
 
+func TestStacktraceLocationThrowNativeInTheMiddle(t *testing.T) {
+	vm := New()
+	v, err := vm.RunString(`(function f1() {
+		throw new Error("test")
+	})`)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	var f1 func()
+	err = vm.ExportTo(v, &f1)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	f := func() {
+		f1()
+	}
+	vm.Set("f", f)
+	_, err = vm.RunString(`
+	function main() {
+		(function noop() {})();
+		return callee();
+	}
+	function callee() {
+		return f();
+	}
+	main();
+	`)
+	if err == nil {
+		t.Fatal("Expected error")
+	}
+	stack := err.(*Exception).stack
+	if len(stack) != 5 {
+		t.Fatalf("Unexpected stack len: %v", stack)
+	}
+	if frame := stack[0]; frame.funcName != "f1" || frame.pc != 7 {
+		t.Fatalf("Unexpected stack frame 0: %#v", frame)
+	}
+	if frame := stack[1]; !strings.HasSuffix(frame.funcName.String(), "TestStacktraceLocationThrowNativeInTheMiddle.func1") {
+		t.Fatalf("Unexpected stack frame 1: %#v", frame)
+	}
+	if frame := stack[2]; frame.funcName != "callee" || frame.pc != 2 {
+		t.Fatalf("Unexpected stack frame 2: %#v", frame)
+	}
+	if frame := stack[3]; frame.funcName != "main" || frame.pc != 6 {
+		t.Fatalf("Unexpected stack frame 3: %#v", frame)
+	}
+	if frame := stack[4]; frame.funcName != "" || frame.pc != 4 {
+		t.Fatalf("Unexpected stack frame 4: %#v", frame)
+	}
+}
+
 func TestStrToInt64(t *testing.T) {
 	if _, ok := strToInt64(""); ok {
 		t.Fatal("<empty>")

+ 24 - 14
vm.go

@@ -34,7 +34,6 @@ type stash struct {
 
 type context struct {
 	prg       *Program
-	funcName  unistring.String // only valid when prg is nil
 	stash     *stash
 	privEnv   *privateEnv
 	newTarget Value
@@ -312,7 +311,6 @@ func (r *unresolvedRef) refname() unistring.String {
 type vm struct {
 	r            *Runtime
 	prg          *Program
-	funcName     unistring.String // only valid when prg == nil
 	pc           int
 	stack        valueStack
 	sp, sb, args int
@@ -596,25 +594,37 @@ func (vm *vm) ClearInterrupt() {
 	atomic.StoreUint32(&vm.interrupted, 0)
 }
 
+func getFuncName(stack []Value, sb int) unistring.String {
+	if sb > 0 {
+		if f, ok := stack[sb-1].(*Object); ok {
+			if _, isProxy := f.self.(*proxyObject); isProxy {
+				return "proxy"
+			}
+			return nilSafe(f.self.getStr("name", nil)).string()
+		}
+	}
+	return ""
+}
+
 func (vm *vm) captureStack(stack []StackFrame, ctxOffset int) []StackFrame {
 	// Unroll the context stack
-	if vm.pc != -1 {
+	if vm.prg != nil || vm.sb > 0 {
 		var funcName unistring.String
 		if vm.prg != nil {
 			funcName = vm.prg.funcName
 		} else {
-			funcName = vm.funcName
+			funcName = getFuncName(vm.stack, vm.sb)
 		}
 		stack = append(stack, StackFrame{prg: vm.prg, pc: vm.pc, funcName: funcName})
 	}
 	for i := len(vm.callStack) - 1; i > ctxOffset-1; i-- {
 		frame := &vm.callStack[i]
-		if frame.prg != nil || frame.funcName != "" {
+		if frame.prg != nil || frame.sb > 0 {
 			var funcName unistring.String
 			if prg := frame.prg; prg != nil {
 				funcName = prg.funcName
 			} else {
-				funcName = frame.funcName
+				funcName = getFuncName(vm.stack, frame.sb)
 			}
 			stack = append(stack, StackFrame{prg: vm.callStack[i].prg, pc: frame.pc, funcName: funcName})
 		}
@@ -630,12 +640,12 @@ func (vm *vm) captureAsyncStack(stack []StackFrame, runner *asyncRunner) []Stack
 		if len(promise.fulfillReactions) == 1 {
 			if r := promise.fulfillReactions[0].asyncRunner; r != nil {
 				ctx := &r.gen.ctx
-				if ctx.prg != nil || ctx.funcName != "" {
+				if ctx.prg != nil || ctx.sb > 0 {
 					var funcName unistring.String
 					if prg := ctx.prg; prg != nil {
 						funcName = prg.funcName
 					} else {
-						funcName = ctx.funcName
+						funcName = getFuncName(ctx.stack, 1)
 					}
 					stack = append(stack, StackFrame{prg: ctx.prg, pc: ctx.pc, funcName: funcName})
 				}
@@ -676,8 +686,8 @@ func (vm *vm) handleThrow(arg interface{}) *Exception {
 		}
 		if int(tf.callStackLen) < len(vm.callStack) {
 			ctx := &vm.callStack[tf.callStackLen]
-			vm.prg, vm.funcName, vm.newTarget, vm.result, vm.pc, vm.sb, vm.args =
-				ctx.prg, ctx.funcName, ctx.newTarget, ctx.result, ctx.pc, ctx.sb, ctx.args
+			vm.prg, vm.newTarget, vm.result, vm.pc, vm.sb, vm.args =
+				ctx.prg, ctx.newTarget, ctx.result, ctx.pc, ctx.sb, ctx.args
 			vm.callStack = vm.callStack[:tf.callStackLen]
 		}
 		vm.sp = int(tf.sp)
@@ -788,8 +798,8 @@ func (vm *vm) peek() Value {
 }
 
 func (vm *vm) saveCtx(ctx *context) {
-	ctx.prg, ctx.stash, ctx.privEnv, ctx.newTarget, ctx.result, ctx.pc, ctx.sb, ctx.args, ctx.funcName =
-		vm.prg, vm.stash, vm.privEnv, vm.newTarget, vm.result, vm.pc, vm.sb, vm.args, vm.funcName
+	ctx.prg, ctx.stash, ctx.privEnv, ctx.newTarget, ctx.result, ctx.pc, ctx.sb, ctx.args =
+		vm.prg, vm.stash, vm.privEnv, vm.newTarget, vm.result, vm.pc, vm.sb, vm.args
 }
 
 func (vm *vm) pushCtx() {
@@ -806,8 +816,8 @@ func (vm *vm) pushCtx() {
 }
 
 func (vm *vm) restoreCtx(ctx *context) {
-	vm.prg, vm.funcName, vm.stash, vm.privEnv, vm.newTarget, vm.result, vm.pc, vm.sb, vm.args =
-		ctx.prg, ctx.funcName, ctx.stash, ctx.privEnv, ctx.newTarget, ctx.result, ctx.pc, ctx.sb, ctx.args
+	vm.prg, vm.stash, vm.privEnv, vm.newTarget, vm.result, vm.pc, vm.sb, vm.args =
+		ctx.prg, ctx.stash, ctx.privEnv, ctx.newTarget, ctx.result, ctx.pc, ctx.sb, ctx.args
 }
 
 func (vm *vm) popCtx() {