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);".
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.
Saves a few hundred bytes of footprint:
* duk_dup_0() = duk_dup(ctx, 0), duk_dup_1() = duk_dup(ctx, 1), etc.
* duk_dup_m2() = duk_dup(ctx, -2), etc.
* duk_dup_m1() is not added, because duk_dup_top() is the same thing
This allows a native thread to suspend its Duktape thread while for
example calling out to an external blocking API, allowing other native
threads to cooperatively run code on the same heap in the meantime.
It is left up to the application to synchronize its native threads so
only a single native thread executes code at a time, each taking care to
use distinct Duktape threads while doing so.
Related to #834.
Also remove the NULL check for refcounts: call sites where a NULL target value
(duk_tval * or duk_heaphdr *) may occur must use a NULL-tolerant variant
explicitly. This is for performance and to reduce call site size when the
refcount operations are inlined.
Using inline macros is basically the same as a forced inline when using a
good compiler and the single source file model. Macros make this more
portable, and will allow refcount updates to happen even directly from
Duktape API macros later.
- Avoid warning for unreferenced variables
- Fix incorrect (non-existent) macro name (DUK_NEVER_HERE)
- Fix built-in missing prototype
- Fix C++ static variable issue
- Avoid pc2line lookup when not enabled
- Change combine_src.py order to match C++ static var requirements
- Use volatile in cause segfault to avoid clang warning
Add a C API binding for Object.defineProperty(): duk_def_prop().
In addition to Object.defineProperty() features, the API call provides a
"force" flag which allows properties to be added to non-extensible objects
and non-configurable properties to be changed (except virtual properties
which are immutable).
Because the name duk_def_prop() conflicts with internal calls, rename them
from duk_def_prop*() to duk_xdef_prop*(). This rename also makes it clearer
that the internal duk_xdef_prop*() calls have non-compliant, internal
semantics.
Also reimplement Object.defineProperty() and Object.defineProperties() (and
duk_def_prop()) so that they share the same internal helpers, and there is
no need for a temporary property descriptor object which is unnecessary churn.
Detailed changes:
- New helper to prepare (validate and normalize) property descriptors
- New helper to implement Object.defineProperty() internals, leaving
out validation of the property descriptor
- Reimplement Object.defineProperty() using the new helpers
- Reimplement Object.defineProperties() using the new helpers
- Reimplement duk_define_property() using the new helpers, so that a
temporary property descriptor object is no longer created
- Add support for "force" flag to Object.defineProperty()
Must create a new scope instead of just setting _target of the existing one:
if just _target is set, it will affect other threads which share the same
(initial) built-ins. Instead, we must create a new scope object and replace
it entirely.