JavaScript-Duktape-XS
view release on metacpan or search on metacpan
#if defined(DUK_USE_LIGHTFUNC_BUILTINS)
lightfunc_skip:
#endif
defprop_flags = (duk_small_uint_t) duk_bd_decode_flagged(bd,
DUK__PROP_FLAGS_BITS,
(duk_uint32_t) DUK_PROPDESC_FLAGS_WC);
defprop_flags |= DUK_DEFPROP_FORCE | DUK_DEFPROP_HAVE_VALUE | DUK_DEFPROP_HAVE_WRITABLE |
DUK_DEFPROP_HAVE_ENUMERABLE | DUK_DEFPROP_HAVE_CONFIGURABLE;
DUK_ASSERT(DUK_PROPDESC_FLAG_WRITABLE == DUK_DEFPROP_WRITABLE);
DUK_ASSERT(DUK_PROPDESC_FLAG_ENUMERABLE == DUK_DEFPROP_ENUMERABLE);
DUK_ASSERT(DUK_PROPDESC_FLAG_CONFIGURABLE == DUK_DEFPROP_CONFIGURABLE);
duk_def_prop(thr, (duk_idx_t) i, defprop_flags);
/* [ (builtin objects) ] */
}
}
/*
* Special post-tweaks, for cases not covered by the init data format.
*
* - Set Date.prototype.toGMTString to Date.prototype.toUTCString.
* toGMTString is required to have the same Function object as
* toUTCString in E5 Section B.2.6. Note that while Smjs respects
* this, V8 does not (the Function objects are distinct).
*
* - Make DoubleError non-extensible.
*
* - Add info about most important effective compile options to Duktape.
*
* - Possibly remove some properties (values or methods) which are not
* desirable with current feature options but are not currently
* conditional in init data.
*/
#if defined(DUK_USE_DATE_BUILTIN)
duk_get_prop_stridx_short(thr, DUK_BIDX_DATE_PROTOTYPE, DUK_STRIDX_TO_UTC_STRING);
duk_xdef_prop_stridx_short(thr, DUK_BIDX_DATE_PROTOTYPE, DUK_STRIDX_TO_GMT_STRING, DUK_PROPDESC_FLAGS_WC);
#endif
h = duk_known_hobject(thr, DUK_BIDX_DOUBLE_ERROR);
DUK_HOBJECT_CLEAR_EXTENSIBLE(h);
#if !defined(DUK_USE_ES6_OBJECT_PROTO_PROPERTY)
DUK_DD(DUK_DDPRINT("delete Object.prototype.__proto__ built-in which is not enabled in features"));
(void) duk_hobject_delprop_raw(thr,
thr->builtins[DUK_BIDX_OBJECT_PROTOTYPE],
DUK_HTHREAD_STRING___PROTO__(thr),
DUK_DELPROP_FLAG_THROW);
#endif
#if !defined(DUK_USE_ES6_OBJECT_SETPROTOTYPEOF)
DUK_DD(DUK_DDPRINT("delete Object.setPrototypeOf built-in which is not enabled in features"));
(void) duk_hobject_delprop_raw(thr,
thr->builtins[DUK_BIDX_OBJECT_CONSTRUCTOR],
DUK_HTHREAD_STRING_SET_PROTOTYPE_OF(thr),
DUK_DELPROP_FLAG_THROW);
#endif
/* XXX: relocate */
duk_push_string(thr,
/* Endianness indicator */
#if defined(DUK_USE_INTEGER_LE)
"l"
#elif defined(DUK_USE_INTEGER_BE)
"b"
#elif defined(DUK_USE_INTEGER_ME) /* integer mixed endian not really used now */
"m"
#else
"?"
#endif
#if defined(DUK_USE_DOUBLE_LE)
"l"
#elif defined(DUK_USE_DOUBLE_BE)
"b"
#elif defined(DUK_USE_DOUBLE_ME)
"m"
#else
"?"
#endif
" "
/* Packed or unpacked tval */
#if defined(DUK_USE_PACKED_TVAL)
"p"
#else
"u"
#endif
#if defined(DUK_USE_FASTINT)
"f"
#endif
" "
/* Low memory/performance options */
#if defined(DUK_USE_STRTAB_PTRCOMP)
"s"
#endif
#if !defined(DUK_USE_HEAPPTR16) && !defined(DUK_DATAPTR16) && !defined(DUK_FUNCPTR16)
"n"
#endif
#if defined(DUK_USE_HEAPPTR16)
"h"
#endif
#if defined(DUK_USE_DATAPTR16)
"d"
#endif
#if defined(DUK_USE_FUNCPTR16)
"f"
#endif
#if defined(DUK_USE_REFCOUNT16)
"R"
#endif
#if defined(DUK_USE_STRHASH16)
"H"
#endif
#if defined(DUK_USE_STRLEN16)
"S"
#endif
#if defined(DUK_USE_BUFLEN16)
"B"
#endif
#if defined(DUK_USE_OBJSIZES16)
/* Inner executor, performance critical. */
DUK_LOCAL DUK_NOINLINE DUK_HOT void duk__js_execute_bytecode_inner(duk_hthread *entry_thread, duk_activation *entry_act) {
/* Current PC, accessed by other functions through thr->ptr_to_curr_pc.
* Critical for performance. It would be safest to make this volatile,
* but that eliminates performance benefits; aliasing guarantees
* should be enough though.
*/
duk_instr_t *curr_pc; /* bytecode has a stable pointer */
/* Hot variables for interpretation. Critical for performance,
* but must add sparingly to minimize register shuffling.
*/
duk_hthread *thr; /* stable */
duk_tval *consts; /* stable */
duk_uint_fast32_t ins;
/* 'funcs' is quite rarely used, so no local for it */
#if defined(DUK_USE_EXEC_FUN_LOCAL)
duk_hcompfunc *fun;
#else
/* 'fun' is quite rarely used, so no local for it */
#endif
#if defined(DUK_USE_INTERRUPT_COUNTER)
duk_int_t int_ctr;
#endif
#if defined(DUK_USE_ASSERTIONS)
duk_size_t valstack_top_base; /* valstack top, should match before interpreting each op (no leftovers) */
#endif
/* Optimized reg/const access macros assume sizeof(duk_tval) to be
* either 8 or 16. Heap allocation checks this even without asserts
* enabled now because it can't be autodetected in duk_config.h.
*/
#if 1
#if defined(DUK_USE_PACKED_TVAL)
DUK_ASSERT(sizeof(duk_tval) == 8);
#else
DUK_ASSERT(sizeof(duk_tval) == 16);
#endif
#endif
DUK_GC_TORTURE(entry_thread->heap);
/*
* Restart execution by reloading thread state.
*
* Note that 'thr' and any thread configuration may have changed,
* so all local variables are suspect and we need to reinitialize.
*
* The number of local variables should be kept to a minimum: if
* the variables are spilled, they will need to be loaded from
* memory anyway.
*
* Any 'goto restart_execution;' code path in opcode dispatch must
* ensure 'curr_pc' is synced back to act->curr_pc before the goto
* takes place.
*
* The interpreter must be very careful with memory pointers, as
* many pointers are not guaranteed to be 'stable' and may be
* reallocated and relocated on-the-fly quite easily (e.g. by a
* memory allocation or a property access).
*
* The following are assumed to have stable pointers:
* - the current thread
* - the current function
* - the bytecode, constant table, inner function table of the
* current function (as they are a part of the function allocation)
*
* The following are assumed to have semi-stable pointers:
* - the current activation entry: stable as long as callstack
* is not changed (reallocated by growing or shrinking), or
* by any garbage collection invocation (through finalizers)
* - Note in particular that ANY DECREF can invalidate the
* activation pointer, so for the most part a fresh lookup
* is required
*
* The following are not assumed to have stable pointers at all:
* - the value stack (registers) of the current thread
*
* See execution.rst for discussion.
*/
restart_execution:
/* Lookup current thread; use the stable 'entry_thread' for this to
* avoid clobber warnings. Any valid, reachable 'thr' value would be
* fine for this, so using 'entry_thread' is just to silence warnings.
*/
thr = entry_thread->heap->curr_thread;
DUK_ASSERT(thr != NULL);
DUK_ASSERT(thr->callstack_top >= 1);
DUK_ASSERT(thr->callstack_curr != NULL);
DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack_curr) != NULL);
DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->callstack_curr)));
DUK_GC_TORTURE(thr->heap);
thr->ptr_curr_pc = &curr_pc;
/* Relookup and initialize dispatch loop variables. Debugger check. */
{
duk_activation *act;
#if !defined(DUK_USE_EXEC_FUN_LOCAL)
duk_hcompfunc *fun;
#endif
/* Assume interrupt init/counter are properly initialized here. */
/* Assume that thr->valstack_bottom has been set-up before getting here. */
act = thr->callstack_curr;
DUK_ASSERT(act != NULL);
fun = (duk_hcompfunc *) DUK_ACT_GET_FUNC(act);
DUK_ASSERT(fun != NULL);
DUK_ASSERT(thr->valstack_top - thr->valstack_bottom == fun->nregs);
consts = DUK_HCOMPFUNC_GET_CONSTS_BASE(thr->heap, fun);
DUK_ASSERT(consts != NULL);
#if defined(DUK_USE_DEBUGGER_SUPPORT)
if (DUK_UNLIKELY(duk_debug_is_attached(thr->heap) && !thr->heap->dbg_processing)) {
duk__executor_recheck_debugger(thr, act, fun);
duk_uint_t error_count = 0;
duk_double_t d1, d2;
duk_small_uint_t u;
duk_double_t d1v, d2v;
duk_small_uint_t uv;
/* Test without volatiles */
d1 = 1.0;
u = (duk_small_uint_t) d1;
d2 = (duk_double_t) u;
if (!(duk_double_equals(d1, 1.0) && u == 1 && duk_double_equals(d2, 1.0) && duk_double_equals(d1, d2))) {
DUK__FAILED("double to duk_small_uint_t cast failed");
}
/* Same test with volatiles */
d1v = 1.0;
uv = (duk_small_uint_t) d1v;
d2v = (duk_double_t) uv;
if (!(duk_double_equals(d1v, 1.0) && uv == 1 && duk_double_equals(d2v, 1.0) && duk_double_equals(d1v, d2v))) {
DUK__FAILED("double to duk_small_uint_t cast failed");
}
return error_count;
}
DUK_LOCAL duk_uint_t duk__selftest_cast_double_to_uint32(void) {
/*
* This test fails on an exotic ARM target; double-to-uint
* cast is incorrectly clamped to -signed- int highest value.
*
* https://github.com/svaarala/duktape/issues/336
*/
duk_uint_t error_count = 0;
duk_double_t dv;
duk_uint32_t uv;
dv = 3735928559.0; /* 0xdeadbeef in decimal */
uv = (duk_uint32_t) dv;
if (uv != 0xdeadbeefUL) {
DUK__FAILED("double to duk_uint32_t cast failed");
}
return error_count;
}
/*
* Minimal test of user supplied allocation functions
*
* - Basic alloc + realloc + free cycle
*
* - Realloc to significantly larger size to (hopefully) trigger a
* relocation and check that relocation copying works
*/
DUK_LOCAL duk_uint_t duk__selftest_alloc_funcs(duk_alloc_function alloc_func,
duk_realloc_function realloc_func,
duk_free_function free_func,
void *udata) {
duk_uint_t error_count = 0;
void *ptr;
void *new_ptr;
duk_small_int_t i, j;
unsigned char x;
if (alloc_func == NULL || realloc_func == NULL || free_func == NULL) {
return 0;
}
for (i = 1; i <= 256; i++) {
ptr = alloc_func(udata, (duk_size_t) i);
if (ptr == NULL) {
DUK_D(DUK_DPRINT("alloc failed, ignore"));
continue; /* alloc failed, ignore */
}
for (j = 0; j < i; j++) {
((unsigned char *) ptr)[j] = (unsigned char) (0x80 + j);
}
new_ptr = realloc_func(udata, ptr, 1024);
if (new_ptr == NULL) {
DUK_D(DUK_DPRINT("realloc failed, ignore"));
free_func(udata, ptr);
continue; /* realloc failed, ignore */
}
ptr = new_ptr;
for (j = 0; j < i; j++) {
x = ((unsigned char *) ptr)[j];
if (x != (unsigned char) (0x80 + j)) {
DUK_D(DUK_DPRINT("byte at index %ld doesn't match after realloc: %02lx",
(long) j,
(unsigned long) x));
DUK__FAILED("byte compare after realloc");
break;
}
}
free_func(udata, ptr);
}
return error_count;
}
/*
* Self test main
*/
DUK_INTERNAL duk_uint_t duk_selftest_run_tests(duk_alloc_function alloc_func,
duk_realloc_function realloc_func,
duk_free_function free_func,
void *udata) {
duk_uint_t error_count = 0;
DUK_D(DUK_DPRINT("self test starting"));
( run in 2.006 seconds using v1.01-cache-2.11-cpan-71847e10f99 )