* Use shared error macros and shared error handler to reduce the size of call
sites of common errors.
* Make zero argument DUK_ERROR() calls non-vararg calls to reduce call site
footprint. Non-vararg calls have smaller call sites and because there are
a lot of call sites, this turns out to be significant.
* Remove variadic macros from internal DUK_ERROR() macro set and add separate
macros for argument counts 0 to 4; this is more portable and requires less
conditional code, and works well when a non-vararg call is used for most
error call sites.
* Rework macro / function argument order for the error path, try to keep 'thr'
in the same argument slot to avoid unnecessary register moves.
* Pack linenumber and error code into a single 32-bit argument when possible,
removes one more constant load from the call site.
* Convert some internal errors to RangeErrors when the underlying cause is an
implementation limit (such as a compiler temp limit) rather than an actual
unexpected internal situation.
* Simplify and share a few error messages to reduce string count.
Separate call handling into three functions: unprotected call wrapper,
protected call wrapper, and a shared inner call handler. Having setjmp
only in a smaller wrapper reduces problems with compiler, including:
* Spurious volatile warnings
* Performance impact on compilers where optimizations must be disabled for
any function involving a setjmp
Also make every DUK_SETJMP() call site compatible with a later refactoring
to supporting C++ exceptions by handling the success case in the then-block
and the error in the else-block. This allows a try-catch structure to
trivially replace the setjmp construct.
Split call error handling to separate function which makes it easier to
share for C++ exception handling which may need a catch (xxx) for Duktape
errors and a separate catch (...) for other errors accidentally thrown by
user code.
Other minor cleanups in call handling.
* Fix outstanding FIXME issues for lightfunc semantics.
* Improve API and Ecmascript testcases to match.
* Clarify lightfunc limitations, e.g. finalizer limitations.
* Guide and API documentation changes for lightfuncs.
* Fix compile warning: duk_str_not_object unused.
A lot of changes to add preliminary lightfunc support:
* Add LIGHTFUNC tagged type to duk_tval.h and API.
* Internal changes for preliminary to support lightfuncs in call handling
and other operations (FIXMEs left in obvious places where support is
still missing after this commit)
* Preliminary Ecmascript and API testcases for lightfuncs
Detailed notes:
* Because magic is signed, reading it back involves sign extension which is
quite verbose to do in C. Use macros for reading the magic value and other
bit fields encoded in the flags.
* Function.prototype.bind(): the 'length' property of a bound function now
comes out wrong. We could simply look up the virtual 'length' property
even if h_target is NULL: no extra code and binding is relatively rare in
hot paths. Rewrite more cleanly in any case.
* The use flag DUK_USE_LIGHTFUNC_BUILTINS controls the forced lightfunc
conversion of built-ins. This results in non-compliant built-ins but
significant memory savings in very memory poor environments.
* Reject eval(), Thread.yield/resume as lightfuncs. These functions have
current assertions that they must be called as fully fledged functions.
* Lightfuncs are serialized like ordinary functions for JSON, JX, and JC
by this diff.
* Add 'magic' to activation for lightfuncs. It will be needed for lightweight
functions: we don't have the duk_tval related to the lightfunc, so we must
copy the magic value to the activation when a call is made.
* When lightfuncs are used as property lookup base values, continue property
lookup from the Function.prototype object. This is necessary to allow e.g.
``func.call()`` and ``func.apply()`` to be used.
* Call handling had to be reworked for lightfuncs, especially how bound
function chains are handled. This is a relatively large change but is
necessary to support lightweight functions properly in bound function
resolution.
The current solution is not ideal. The bytecode executor will first try an
ecma-to-ecma call setup which resolves the bound function chain first. If
the final, unbound function is not viable (a native function) the call setup
returns with an error code. The caller will then perform a normal call.
Although bound function resolution has already been done, the normal call
handling code will re-do it (and detect there is nothing to do).
This situation could be avoided by decoupling bound function handling and
effective this binding computation from the actual call setup. The caller
could then to do this prestep first, and only then decide whether to use an
ecma-to-ecma call or an ordinary heavyweight call.
Remove duk__find_nonbound_function as unused.
* Use indirect magic to allow LIGHTFUNCs for Date. Most of the built-in
functions not directly eligible as lightfuncs are the Date built-in methods,
whose magic values contain too much information to fit into the 8-bit magic
of a LIGHTFUNC value.
To work around this, add an array (duk__date_magics[]) containing the
actual control flags needed by the built-ins, and make the Date built-in
magic value an index into this table. With this change Date built-ins are
successfully converted to lightfuncs.
Testcase fixes:
- Whitespace fixes
- Print error for indirect eval error to make diagnosis easier
- Fix error string to match errmsg updated in this branch
The duk_idx_t type is appropriate for stack sizes and counts because
it will necessarily have enough bits to express sizes/counts nicely.
Negative values are clamped to zero or cause an error to be thrown.
This is nice for calling code, because calculation errors or simple
failures to clamp will not cause a negative value to be treated like
a large unsigned value which would be incorrect and lead to confusing
behavior.
Note: use duk_ret_t for function/method/safe call returns, and use
duk_bool_t for "C boolean" returns, where the return value range would
be the same as e.g. a comparison (a > b).