Skip to content

Commit

Permalink
Use thrown object's stack trace when re-throwing. Fixes #517, closes #…
Browse files Browse the repository at this point in the history
  • Loading branch information
dop251 committed Oct 27, 2023
1 parent 5944104 commit b396bb4
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 19 deletions.
23 changes: 20 additions & 3 deletions runtime_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2325,15 +2325,32 @@ func TestStacktraceLocationThrowFromCatch(t *testing.T) {
t.Fatal("Expected error")
}
stack := err.(*Exception).stack
if len(stack) != 2 {
if len(stack) != 3 {
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)
}
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)
}
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) {
Expand Down
24 changes: 8 additions & 16 deletions vm.go
Original file line number Diff line number Diff line change
Expand Up @@ -4437,28 +4437,20 @@ var throw _throw

func (_throw) exec(vm *vm) {
v := vm.stack[vm.sp-1]
var ex *Exception
ex := &Exception{
val: v,
}

if o, ok := v.(*Object); ok {
if e, ok := o.self.(*errorObject); ok {
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 {
Expand Down

0 comments on commit b396bb4

Please sign in to comment.