Direct comparison may have portability concerns because a constant may
have more precision than its counterpart. Even a direct cast before
a comparison may not work (e.g. Math.atan2() assert with gcc -m32 still
fails even when both sides have an explicit double cast). So use an
internal always-inline helper for float/double comparisons, which also
allows -Wfloat-equal warning to be suppressed in a single helper; add
a clang pragma option so that both gcc and clang suppress the warning.
Other changes:
* Add -Wfloat-equal warning back to the Makefile.
* Fix all internal float comparison call sites to use the helper.
* Add code policy check for probable floating point comparison
(not very important with -Wfloat-equal enabled).
* Add minimal CBOR config options.
* Add 'CBOR' built-in YAML metadata.
* Add a public C API for CBOR.
* Remove examples/cmdline support for extras/cbor, use built-in CBOR
instead.
* Makefile, dist/tools changes.
* Rewrite CBOR extra to use Duktape internal helpers, also some related
refactoring.
* Rework duk_heaphdr and subclass assertions into functions to
reduce debug build size.
* Add explicit object validity assert passes to mark-and-sweep.
This allows detection of invalid internal structures especially
when used with GC torture.
* Rename assertion macros for consistency, e.g. from
DUK_ASSERT_HSTRING_VALID to DUK_HSTRING_ASSERT_VALID.
* Automatically pin C literals interned into heap strings. Or if the
literal maps to an already interned string, pin it too. Pinning is
implemented using a duk_hstring flag and a one-off refcount bump.
Mark-and-sweep avoids sweeping pinned strings based on the flag.
* Add a lookup cache for quickly mapping a C literal address (which is
assumed stable) into a duk_hstring pointer. Once a mapping has been
formed, it never needs to be invalidated because the duk_hstring is
always pinned if the cache is used. Only heap destruction will free
the pinned duk_hstrings.
* More internal call site conversion for literals.
* Wording trivia.
* Convert memory helpers like duk_memcmp() to macros where possible: for some
reason automatic inlining with -Os doesn't do the right thing and the
footprint impact is over 1kB. The duk_memcmp() helper is an inlined
function because it returns a value and assertions would otherwise lead
to multiple evaluation of arguments.
* Differentiate between C99+ and "unsafe" call sites. For example, use
duk_memcpy() when the call site obeys C99+ restrictions, and
duk_memcpy_unsafe() when either pointer may be NULL when the size is zero.
Same for all helpers.
* 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.
Add internal helpers to deal with undefined behavior cases explicitly.
When DUK_USE_ALLOW_UNDEFINED_BEHAVIOR is set, skip the (almost always
unnecessary) explicit checks to improve footprint and performance.
Also split duk_util_misc.c into a few better scoped files.
* 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);".
Make the hash algorithm simpler by using a bit mask rather than a modulus for
probing the hash.
Make the hash part load factor lower than before to reduce clustering. Low
memory environments disable hash part support anyway, so this doesn't impact
them.
* Replace the two alternative algorithms with a single one which works for
both desktop and low memory cases.
* Basic algorithm is a hash table with size 2^N, hash mask is simply
(size - 1), e.g. if size is 0x100, mask is 0xFF. duk_hstring has a 'next'
pointer (single linked list) for chaining strings mapping to the same
slot.
- Faster hex decode invalid input check for duk_hex_decode() fast path
- Faster JX/JC hex encode
- Slightly faster JX/JC hex decode (avoid string intern for temp value)
- Relocate decode tables, they may be useful in other files later
- Loop typing changes
- DUK_BSWAP32() and DUK_BSWAP16() in duk_features.h so that platform specific
macros, intrinsics, or inline assembly can be used if necessary
- DUK_DBLUNION_BSWAP() for byte swapping doubles (needed by debugger)
- duk_byteswap_bytes() helper for byte swapping arbitrary data (needed by
debugger for pointers)
When doing a single file build, drop DUK_INTERNAL_DECL declarations which
would otherwise be mapped to "static". This avoids the problem with C++
where a static data symbol is both forward declared and defined.
With this change static definitions must appear before their first use in
the single file build. This requires a change in combine_src.py which is
done in a separate commit.