* Add internal wrappers also to DUK_MEMMOVE(), DUK_MEMSET(), and
DUK_MEMZERO().
* Use the wrappers everywhere for consistency: the zero-size cases will then
always be safe, and if the target is fine with invalid pointers in the zero
size case, the whole check can be omitted easily.
* Remove a few zero size checks as they're no longer necessary.
* 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.
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.
Reorder tags to accommodate a separate 'unused' tag so that 'undefined' can
become a single tag write (instead of tag + value like booleans). This is
good because 'undefined' values are involved in e.g. value stack resizes and
are performance relevant.
Also reorder tags so that "is heap allocated" check can be a single bit test
instead of a comparison when using non-packed duk_tval. This makes every
DECREF potentially faster because an "is heap allocated" test appears in
every DECREF.
Because "unused" is not intended to appear anywhere in actual use (e.g. as
a value stack value, as a property value, etc), "unused" values will fall
into the default clause of DUK_TAG_xxx switch case statements. Add an assert
to every such default clause that the value is not intended to be "unused".
Remove duk_push_unused() as it should no longer be used. It was only used
by the debugger protocol; refuse an inbound "unused" value in the debugger.
This is not breaking compatibility because there was no legitimate usage for
the debug client sending requests with "unused" values.
'Leave as undefined' seems to be the best overall value stack initialization
policy. While 'leave as garbage' is marginally better in a few cases (mostly
when refcounting is disabled) it's probably not worth keeping two policies
around.
Change the current value stack policy from "unused above top" to either
"undefined above top" or "garbage above top", depending on a config
option. Change mark-and-sweep and debug print code to only process
entries between [0,top[ in either case.
Both policies have potential upsides and downsides based on performance
measurement. This commit provides both policies; "undefined above top"
will probably be the only policy left however, because "garbage above
top" is only better in a few cases and mostly without refcounts.
Other minor improvements:
- Rework index validation to use duk_uidx_t and more shared code.
- Add cached thr->valstack_size value
Also remove mostly unused old debug code.
Debug code doesn't have access to 'heap' so it cannot decode pointers.
Cause an #error for now if both debug prints and pointer compression
are enabled at the same time.
Remove duk_debug_hobject.c from make and dist. It was out of date and
not used in practice anymore.