* Wrap checks to duk_require_stack() and variants.
* Wrap check to value stack grow.
* Add internal helper duk_set_top_and_wipe(); for now it's just two
duk_set_top() calls but can be optimized later.
* Make value stack and call stack limits configurable via DUK_USE_xxx
options. Also make value stack grow/shrink constants configurable.
* Rewrite value stack grow/shrink check primitives for better hot/cold path
handling.
* Use a proportional spare for grow and shrink sizes so that applications
needing a large value stack have fewer value stack resizes.
* Grow value stack allocation when entering a call or when explicitly requested
via e.g. duk_require_stack().
* Never shrink the value stack when entering a call, so that the unwind path
is guaranteed to have value stack to handle a protected call return. This
guarantee is only needed for protected call but is now applied to all calls
for simplicity.
* Don't perform a value stack shrink check at all in function return anymore.
It would be OK from protected call semantics perspective to do a shrink
attempt without throwing if it fails.
* Perform a value stack shrink check in mark-and-sweep only for now. When
emergency GC is running, shrink to a minimal size respecting current value
stack reserve.
The distinction matters when loading back: if _Formals was omitted, we don't
want to load back an empty _Formals array for a function template because it
then breaks function instance .length computation.
Move handling of the following opcodes into NOINLINE helpers to make the
main dispatch function smaller and a bit better performing:
* INITSET and INITGET
* TRYCATCH
* ENDTRY
* ENDCATCH
* ENDFIN
* INITENUM and NEXTENUM
duk_hbufobj validity assertions require that if the buf pointer is NULL,
the buffer length and offset are zero. This is violated by the shared
slice code because it sets ->length before allocating a buffer, and since an
allocation may trigger side effects, the assert may trigger in mark-and-sweep.
I don't think this causes issues besides an assert failure.
With ROM objects having REACHABLE always set, mark-and-sweep doesn't need a
specific ROM object check when deciding whether to mark an object or not:
the REACHABLE check causes the object not to be marked.
Remove thr->callstack as a monolithic array and replace it with a linked list
of duk_activations. thr->callstack_curr is the current call (or NULL if no
call is in progress), and act->parent chains to a previous call or NULL.
thr->callstack_top is kept because it's needed by some internals at present;
it may be removed in the future.
* Merge duk_api_public.h.in to duktape.h.in.
* Adjust define order so that duk_config.h sees DUK_VERSION which allows
user config fixups to react to it.
Tweak mark-and-sweep so that if finalizers are present (heap->finalize_list
is not NULL), rescue decisions are postponed (free decisions are not).
In concrete terms this means that objects normally rescued keep their
FINALIZED flag so that their finalizer won't be called again if the object
turns out to be unreachable in a later run.
This wasn't necessary before: finalize_list only contained unreachable
objects so nothing could point to them while we marked heap_allocated.
But when duk_push_heapptr() is allowed to push unreachable pointers
(which are pending finalization), it's possible for an object in
heap_allocated to point to an object on finalize_list, which also means
that the latter object can get a TEMPROOT flag.
A pointer to the value stack was obtained before duk_push_bare_object()
and used after the push. If value stack resize happens as a side effect
of the push (mark-and-sweep, finalizers, etc) the 'tv' pointer could be
stale. Found using torture tests.