diff --git a/core/continuations/continuations-tests.factor b/core/continuations/continuations-tests.factor index a6cead0bd9..371c546142 100644 --- a/core/continuations/continuations-tests.factor +++ b/core/continuations/continuations-tests.factor @@ -1,6 +1,5 @@ -USING: kernel math namespaces io tools.test sequences vectors -continuations debugger parser memory arrays words -kernel.private accessors eval ; +USING: accessors arrays continuations debugger eval io kernel kernel.private +math memory namespaces parser sequences system tools.test vectors words ; IN: continuations.tests : (callcc1-test) ( n obj -- n' obj ) @@ -56,6 +55,25 @@ IN: continuations.tests ! : callstack-overflow callstack-overflow f ; ! [ callstack-overflow ] must-fail +! This tries to verify that enough bytes are cut off from the +! callstack to run the error handler. +: pre ( -- ) nano-count 0 = [ ] [ ] if ; + +: post ( -- ) ; + +: do-overflow ( -- ) + pre do-overflow post ; + +: recurse ( -- ? ) + [ do-overflow f ] [ ] recover + second ERROR-CALLSTACK-OVERFLOW = ; + +os windows? [ + { t } [ + 10 [ recurse ] replicate [ ] all? + ] unit-test +] unless + : don't-compile-me ( -- ) ; : foo ( -- ) callstack "c" set don't-compile-me ; : bar ( -- a b ) 1 foo 2 ; diff --git a/vm/contexts.hpp b/vm/contexts.hpp index c13f3a0444..20d773dea9 100644 --- a/vm/contexts.hpp +++ b/vm/contexts.hpp @@ -12,7 +12,11 @@ enum context_object { OBJ_IN_CALLBACK_P, }; -static const cell stack_reserved = 1024; +/* When the callstack fills up (e.g by to deep recursion), a callstack + overflow error is triggered. So before continuing executing on it + in general_error(), we chop of this many bytes to have some space + to work with. */ +static const cell stack_reserved = 4096; struct context { diff --git a/vm/cpu-x86.cpp b/vm/cpu-x86.cpp index 88419b1dab..5ea316169b 100644 --- a/vm/cpu-x86.cpp +++ b/vm/cpu-x86.cpp @@ -3,8 +3,9 @@ namespace factor { void factor_vm::dispatch_signal_handler(cell* sp, cell* pc, cell handler) { - if (!code->seg->in_segment_p(*pc) || - *sp < ctx->callstack_seg->start + stack_reserved) { + + cell callstack_limit = ctx->callstack_seg->start + stack_reserved; + if (!code->seg->in_segment_p(*pc) || *sp < callstack_limit) { /* Fault came from the VM, foreign code, a callstack overflow, or we don't have enough callstack room to try the resumable handler. Cut the callstack down to the shallowest Factor stack @@ -15,8 +16,7 @@ void factor_vm::dispatch_signal_handler(cell* sp, cell* pc, cell handler) { cell frame_top = ctx->callstack_top; - while (frame_top < ctx->callstack_bottom && - frame_top < ctx->callstack_seg->start + stack_reserved) { + while (frame_top < ctx->callstack_bottom && frame_top < callstack_limit) { frame_top = frame_predecessor(frame_top); }