diff --git a/runtime/vm.go b/runtime/vm.go index a45ba35..0ec72d1 100644 --- a/runtime/vm.go +++ b/runtime/vm.go @@ -894,6 +894,8 @@ func (v *VM) callFunction(fn *objects.CompiledFunction, freeVars []*objects.Obje // |--------| // | *ARG1 | for next function (tail-call) // |--------| + // | FUNC | function itself + // |--------| // | LOCAL3 | for current function // |--------| // | LOCAL2 | for current function @@ -904,7 +906,7 @@ func (v *VM) callFunction(fn *objects.CompiledFunction, freeVars []*objects.Obje // |--------| copy(v.stack[curFrame.basePointer:], v.stack[v.sp-numArgs:v.sp]) - v.sp -= numArgs + v.sp -= numArgs + 1 curFrame.ip = -1 // stack after tail-call @@ -914,7 +916,9 @@ func (v *VM) callFunction(fn *objects.CompiledFunction, freeVars []*objects.Obje // |--------| // | *ARG2 | // |--------| - // | *ARG1 | <- SP current + // | *ARG1 | + // |--------| + // | FUNC | <- SP current // |--------| // | LOCAL3 | for current function // |--------| diff --git a/runtime/vm_tail_call_test.go b/runtime/vm_tail_call_test.go index 9a767b5..522b357 100644 --- a/runtime/vm_tail_call_test.go +++ b/runtime/vm_tail_call_test.go @@ -66,6 +66,19 @@ func TestTailCall(t *testing.T) { return f2(5, 0) } out = f1()`, 15) + + // tail-call replacing loop + // without tail-call optimization, this code will cause stack overflow + expect(t, ` +iter := func(n, max) { + if n == max { + return n + } + + return iter(n+1, max) +} +out = iter(0, 9999) +`, 9999) } // tail call with free vars diff --git a/runtime/vm_test.go b/runtime/vm_test.go index 83baa3a..569832c 100644 --- a/runtime/vm_test.go +++ b/runtime/vm_test.go @@ -148,7 +148,7 @@ func traceCompileRun(file *ast.File, symbols map[string]objects.Object) (res map var ipstr string if v != nil { frameIdx, ip := v.FrameInfo() - ipstr = fmt.Sprintf("\n (Frame=%d, IP=%d)", frameIdx, ip) + ipstr = fmt.Sprintf("\n (Frame=%d, IP=%d)", frameIdx, ip+1) } trace = append(trace, fmt.Sprintf("[Panic]\n\n %v%s\n", e, ipstr)) trace = append(trace, fmt.Sprintf("[Error Trace]\n\n %s\n", strings.Join(stackTrace, "\n "))) @@ -216,6 +216,9 @@ func traceCompileRun(file *ast.File, symbols map[string]objects.Object) (res map } } trace = append(trace, fmt.Sprintf("\n[Globals]\n\n%s", strings.Join(globalsStr, "\n"))) + + frameIdx, ip := v.FrameInfo() + trace = append(trace, fmt.Sprintf("\n[IP]\n\nFrame=%d, IP=%d", frameIdx, ip+1)) } if err != nil { return