* Change duk_bool_to to duk_small_uint_t from duk_small_int_t. This may
cause some sign warnings in calling code.
* Reject attempt to unpack an array-like value whose length is 2G or over;
previously was not checked explicitly, and the length was cast to duk_idx_t
with a sign change and the unpack would then later fail. Now it fails with
a clean RangeError.
* Add wrap check for Node.js Buffer.concat().
* API DUK_TYPE_xxx, DUK_TYPE_MASK_xxx, flag constants etc are now unsigned.
Both duk_hthread and duk_context typedefs resolve to struct duk_hthread
internally. In external API duk_context resolves to struct duk_hthread
which is intentionally left undefined as the struct itself is not
dereferenced. Change internal code to use duk_hthread exclusively which
removes unnecessary and awkward thr <-> ctx casts from internals.
The basic guidelines are:
* Public API uses duk_context in prototype declarations. The intent is to
hide the internal type, and there's already a wide dependency on the
type name.
* All internal code, both declarations and definitions, use duk_hthread
exclusively. This is done even for API functions, i.e. an API function
declared as "void duk_foo(duk_context *ctx);" is then defined as
"void duk_foo(duk_hthread *thr);".
Remove the special ecma-to-ecma call setup code and just use the normal
unprotected call setup code for that instead. Most of the code is the
same; just before calling into the bytecode executor check if the current
executor can be reused, and if so, indicate the situation using a special
return code.
Also remove internal duk_handle_call_protected() and implement all
protected API calls via duk_safe_call(). This reduces footprint and code
duplication further.
Rework call handling to use helpers more to make the call handling code
easier to follow.
Various other minor changer, e.g. DUK_OP_NEW is now DUK_OP_CONSCALL and
bytecode sets up the initial default instance.
Add support for 'new.target' expression without yet adding support for an
explicit newTarget which may differ from the constructor function being
called.
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.
Previously a fastint lost its fastint status in duk_to_(u)int() coercion
which caused a _Varmap index to be a non-fastint for a redeclared global
variable. This further caused an assertion error.
* Strings with 0xFF byte prefix are considered special symbols: they have
typeof "symbol" but still mostly behave as strings (e.g. allow ToString)
so that existing code dealing with internal keys, especially inside
Duktape, can work with fewer changes.
* Strings with 0x80 byte prefix are global symbols, e.g. Symbol.for('foo')
creates the byte representatio: 0x80 "foo"
* Strings with 0x81 byte prefix are unique symbols; the 0x81 byte is followed
by the Symbol description, and an internal string component ensuring
uniqueness is separated by a 0xFF byte (which can never appear anywhere in
an extended UTF-8 string). The unique suffix is up to Duktape internals,
currently two 32-bit counters are used. For example:
0x81 "mySymbol" 0xFF "0-17".
* Well-known symbols use the 0x81 prefix but lack a unique suffix, so their
format is 0x81 <description> 0xFF.
* ES6 distinguishes between an undefined symbol description and an empty
string symbol description. This distinction is not currently visible via
Ecmascript bindings but may be visible in the future. Append an extra
0xFF to the unique suffix when the description is undefined, i.e.
0x81 0xFF <unique suffix> 0xFF.
* Allow duplicates keys, even in strict mode (ES6).
* Add identifier reference shorthand: { Math }.
* Add method definition shorthand: { foo(a,b) { return a + b; } }.
* Eval/program code no longer has the CONSTRUCTABLE flag which was
previously set. Calling an eval/program function as a constructor
makes no sense and wasn't really supported previously. This change
has no compliance impact because eval/program code doesn't exist as
an unexecuted function in Ecmascript.
* Eval/program code no longer has a NAMEBINDING flag which was previously
set. The revised behavior is cleaner because eval/program code must
not have a name binding. However, the flag is only consulted if NEWENV
is also set, and NEWENV is never set for eval/program code. So this
change has no other effect other than affecting dumped bytecode.
* Anonymous functions don't have an own '.name' property but inherit
an empty string .name from Function.prototype.
* new Function() returns a function whose name is 'anonymous'.
Previously _Varmap was kept if any slow path accesses were made. Improve this
behavior so that, in the absence of eval() etc, safe slow path accesses are
allowed while still dropping the _Varmap. A safe slow path access is one that
doesn't match any of the statically declared variables in the function so that
(again assuming no new variables are declared by e.g. eval()) the varmap won't
be needed at runtime.
Allow dropping of _Formals even in presence of eval() or a potentially
dangerous slow path access if _Formals is empty *and* _Formals.length matches
nargs so that .length computation works out even without _Formals.
Also reduce initial bytecode allocation from 2kB to 256 bytes when
DUK_USE_PREFER_SIZE is defined (in absence of a more specific define).
Rename and reuse a previously internal duk_push_object_internal() which just
pushes a bare object (= object without an internal prototype) which is useful
for various dict / tracking map purposes.
Also provide explicit fast / slow (small) variants for fastint downgrade
check: it doesn't make sense to inline the very large check except in the
hot paths of executor and call handling. Elsewhere it's better to save
footprint and thus code cache.
These can be used whenever we're 100% certain that the value stack index
exists and the type matches expected type. When these are true, a
duk_hstring, duk_hbuffer, or duk_hobject pointer fetch can be inlined to
small code.
This avoids the need for a function call and up to two property lookups
for a `Math.pow()` invocation, as well as allowing expressions like
`2 ** 16` to be inlined at compile time.
Exponentiation uses the same internal handler as `Math.pow()`, per the
ES7 specification.
Usage:
x = base ** exp;
x **= 2;
Optimization to avoid a temporary for x <op>= y works for any RHS
which doesn't emit code when evaluated to an ivalue, e.g.:
* A plain constant or any expression which constant folds to a
constant, e.g.: x += 4 and x += 'foo' + 'bar'.
* A register-bound variable, e.g. x += y.
The optimization doesn't have enough state to detect safe cases
such as register bound 'y' in: x += y + 1.