Browse Source

Use thrown object's stack trace when re-throwing. Fixes #517, closes #544.

Dmitry Panov 1 year ago
parent
commit
b396bb4c34
2 changed files with 28 additions and 19 deletions
  1. 20 3
      runtime_test.go
  2. 8 16
      vm.go

+ 20 - 3
runtime_test.go

@@ -2325,15 +2325,32 @@ func TestStacktraceLocationThrowFromCatch(t *testing.T) {
 		t.Fatal("Expected error")
 		t.Fatal("Expected error")
 	}
 	}
 	stack := err.(*Exception).stack
 	stack := err.(*Exception).stack
-	if len(stack) != 2 {
+	if len(stack) != 3 {
 		t.Fatalf("Unexpected stack len: %v", stack)
 		t.Fatalf("Unexpected stack len: %v", stack)
 	}
 	}
-	if frame := stack[0]; frame.funcName != "main" || frame.pc != 29 {
+	if frame := stack[0]; frame.funcName != "f2" || frame.pc != 2 {
 		t.Fatalf("Unexpected stack frame 0: %#v", frame)
 		t.Fatalf("Unexpected stack frame 0: %#v", frame)
 	}
 	}
-	if frame := stack[1]; frame.funcName != "" || frame.pc != 7 {
+	if frame := stack[1]; frame.funcName != "main" || frame.pc != 15 {
 		t.Fatalf("Unexpected stack frame 1: %#v", frame)
 		t.Fatalf("Unexpected stack frame 1: %#v", frame)
 	}
 	}
+	if frame := stack[2]; frame.funcName != "" || frame.pc != 7 {
+		t.Fatalf("Unexpected stack frame 2: %#v", frame)
+	}
+}
+
+func TestErrorStackRethrow(t *testing.T) {
+	const SCRIPT = `
+	function f(e) {
+		throw e;
+	}
+	try {
+		f(new Error());
+	} catch(e) {
+		assertStack(e, [["test.js", "", 6, 5]]);
+	}
+	`
+	testScriptWithTestLibX(SCRIPT, _undefined, t)
 }
 }
 
 
 func TestStacktraceLocationThrowFromGo(t *testing.T) {
 func TestStacktraceLocationThrowFromGo(t *testing.T) {

+ 8 - 16
vm.go

@@ -4437,28 +4437,20 @@ var throw _throw
 
 
 func (_throw) exec(vm *vm) {
 func (_throw) exec(vm *vm) {
 	v := vm.stack[vm.sp-1]
 	v := vm.stack[vm.sp-1]
-	var ex *Exception
+	ex := &Exception{
+		val: v,
+	}
+
 	if o, ok := v.(*Object); ok {
 	if o, ok := v.(*Object); ok {
 		if e, ok := o.self.(*errorObject); ok {
 		if e, ok := o.self.(*errorObject); ok {
 			if len(e.stack) > 0 {
 			if len(e.stack) > 0 {
-				frame0 := e.stack[0]
-				// If the Error was created immediately before throwing it (i.e. 'throw new Error(....)')
-				// avoid capturing the stack again by the reusing the stack from the Error.
-				// These stacks would be almost identical and the difference doesn't matter for debugging.
-				if frame0.prg == vm.prg && vm.pc-frame0.pc == 1 {
-					ex = &Exception{
-						val:   v,
-						stack: e.stack,
-					}
-				}
+				ex.stack = e.stack
 			}
 			}
 		}
 		}
 	}
 	}
-	if ex == nil {
-		ex = &Exception{
-			val:   v,
-			stack: vm.captureStack(make([]StackFrame, 0, len(vm.callStack)+1), 0),
-		}
+
+	if ex.stack == nil {
+		ex.stack = vm.captureStack(make([]StackFrame, 0, len(vm.callStack)+1), 0)
 	}
 	}
 
 
 	if ex = vm.handleThrow(ex); ex != nil {
 	if ex = vm.handleThrow(ex); ex != nil {