/* Shared helper to implement ES6 Object.setPrototypeOf and * Object.prototype.__proto__ setter. * * https://people.mozilla.org/~jorendorff/es6-draft.html#sec-get-object.prototype.__proto__ * https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.setprototypeof */ duk_ret_t duk_bi_object_setprototype_shared(duk_context *ctx) { duk_hthread *thr = (duk_hthread *) ctx; duk_hobject *h_obj; duk_hobject *h_new_proto; duk_hobject *h_curr; duk_ret_t ret_success = 1; /* retval for success path */ /* Preliminaries for __proto__ and setPrototypeOf (E6 19.1.2.18 steps 1-4); * magic: 0=setter call, 1=Object.setPrototypeOf */ if (duk_get_current_magic(ctx) == 0) { duk_push_this_check_object_coercible(ctx); duk_insert(ctx, 0); if (!duk_check_type_mask(ctx, 1, DUK_TYPE_MASK_NULL | DUK_TYPE_MASK_OBJECT)) { return 0; } /* __proto__ setter returns 'undefined' on success unlike the * setPrototypeOf() call which returns the target object. */ ret_success = 0; } else { duk_require_object_coercible(ctx, 0); duk_require_type_mask(ctx, 1, DUK_TYPE_MASK_NULL | DUK_TYPE_MASK_OBJECT); } h_obj = duk_get_hobject(ctx, 0); if (!h_obj) { goto skip; } h_new_proto = duk_get_hobject(ctx, 1); DUK_ASSERT(h_obj != NULL); /* h_new_proto may be NULL */ /* [[SetPrototypeOf]] standard behavior, E6 9.1.2 */ /* NOTE: steps 7-8 seem to be a cut-paste bug in the E6 draft */ /* TODO: implement Proxy object support here */ if (h_new_proto == h_obj->prototype) { goto skip; } if (!DUK_HOBJECT_HAS_EXTENSIBLE(h_obj)) { goto fail_nonextensible; } for (h_curr = h_new_proto; h_curr != NULL; h_curr = h_curr->prototype) { /* Loop prevention */ if (h_curr == h_obj) { goto fail_loop; } } DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, h_obj, h_new_proto); /* fall thru */ skip: duk_set_top(ctx, 1); return ret_success; fail_nonextensible: fail_loop: return DUK_RET_TYPE_ERROR; }
duk_ret_t duk_bi_object_constructor_is_extensible(duk_context *ctx) { duk_hobject *h; h = duk_require_hobject(ctx, 0); DUK_ASSERT(h != NULL); duk_push_boolean(ctx, DUK_HOBJECT_HAS_EXTENSIBLE(h)); return 1; }
DUK_INTERNAL duk_ret_t duk_bi_object_constructor_is_extensible(duk_context *ctx) { duk_hobject *h; h = duk_require_hobject_or_lfunc(ctx, 0); if (!h) { duk_push_false(ctx); } else { duk_push_boolean(ctx, DUK_HOBJECT_HAS_EXTENSIBLE(h)); } return 1; }
duk_ret_t duk_bi_number_constructor(duk_context *ctx) { duk_idx_t nargs; duk_hobject *h_this; /* * The Number constructor uses ToNumber(arg) for number coercion * (coercing an undefined argument to NaN). However, if the * argument is not given at all, +0 must be used instead. To do * this, a vararg function is used. */ nargs = duk_get_top(ctx); if (nargs == 0) { duk_push_int(ctx, 0); } duk_to_number(ctx, 0); duk_set_top(ctx, 1); DUK_ASSERT_TOP(ctx, 1); if (!duk_is_constructor_call(ctx)) { return 1; } /* * E5 Section 15.7.2.1 requires that the constructed object * must have the original Number.prototype as its internal * prototype. However, since Number.prototype is non-writable * and non-configurable, this doesn't have to be enforced here: * The default object (bound to 'this') is OK, though we have * to change its class. * * Internal value set to ToNumber(arg) or +0; if no arg given, * ToNumber(undefined) = NaN, so special treatment is needed * (above). String internal value is immutable. */ /* XXX: helper */ duk_push_this(ctx); h_this = duk_get_hobject(ctx, -1); DUK_ASSERT(h_this != NULL); DUK_HOBJECT_SET_CLASS_NUMBER(h_this, DUK_HOBJECT_CLASS_NUMBER); DUK_ASSERT(h_this->prototype == ((duk_hthread *) ctx)->builtins[DUK_BIDX_NUMBER_PROTOTYPE]); DUK_ASSERT(DUK_HOBJECT_GET_CLASS_NUMBER(h_this) == DUK_HOBJECT_CLASS_NUMBER); DUK_ASSERT(DUK_HOBJECT_HAS_EXTENSIBLE(h_this)); duk_dup(ctx, 0); /* -> [ val obj val ] */ duk_def_prop_stridx(ctx, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_NONE); return 0; /* no return value -> don't replace created value */ }
DUK_INTERNAL void duk_err_augment_error_create(duk_hthread *thr, duk_hthread *thr_callstack, const char *c_filename, duk_int_t c_line, duk_bool_t noblame_fileline) { duk_context *ctx = (duk_context *) thr; duk_hobject *obj; DUK_ASSERT(thr != NULL); DUK_ASSERT(thr_callstack != NULL); DUK_ASSERT(ctx != NULL); /* [ ... error ] */ /* * Criteria for augmenting: * * - augmentation enabled in build (naturally) * - error value internal prototype chain contains the built-in * Error prototype object (i.e. 'val instanceof Error') * * Additional criteria for built-in augmenting: * * - error value is an extensible object */ obj = duk_get_hobject(ctx, -1); if (!obj) { DUK_DDD(DUK_DDDPRINT("value is not an object, skip both built-in and user augment")); return; } if (!duk_hobject_prototype_chain_contains(thr, obj, thr->builtins[DUK_BIDX_ERROR_PROTOTYPE], 1 /*ignore_loop*/)) { /* If the value has a prototype loop, it's critical not to * throw here. Instead, assume the value is not to be * augmented. */ DUK_DDD(DUK_DDDPRINT("value is not an error instance, skip both built-in and user augment")); return; } if (DUK_HOBJECT_HAS_EXTENSIBLE(obj)) { DUK_DDD(DUK_DDDPRINT("error meets criteria, built-in augment")); duk__err_augment_builtin_create(thr, thr_callstack, c_filename, c_line, noblame_fileline, obj); } else { DUK_DDD(DUK_DDDPRINT("error does not meet criteria, no built-in augment")); } /* [ ... error ] */ #if defined(DUK_USE_ERRCREATE) duk__err_augment_user(thr, DUK_STRIDX_ERR_CREATE); #endif }
DUK_INTERNAL duk_ret_t duk_bi_object_constructor_is_extensible(duk_hthread *thr) { /* * magic = 0: Object.isExtensible() * magic = 1: Reflect.isExtensible() */ duk_hobject *h; if (duk_get_current_magic(thr) == 0) { h = duk_get_hobject(thr, 0); } else { /* Reflect.isExtensible(): throw if non-object, but we accept lightfuncs * and plain buffers here because they pretend to be objects. */ h = duk_require_hobject_accept_mask(thr, 0, DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER); } duk_push_boolean(thr, (h != NULL) && DUK_HOBJECT_HAS_EXTENSIBLE(h)); return 1; }
void duk_debug_dump_hobject(duk_hobject *obj) { duk_uint_fast32_t i; const char *str_empty = ""; const char *str_excl = "!"; DUK_D(DUK_DPRINT("=== hobject %p ===", (void *) obj)); if (!obj) { return; } DUK_D(DUK_DPRINT(" %sextensible", DUK_HOBJECT_HAS_EXTENSIBLE(obj) ? str_empty : str_excl)); DUK_D(DUK_DPRINT(" %sconstructable", DUK_HOBJECT_HAS_CONSTRUCTABLE(obj) ? str_empty : str_excl)); DUK_D(DUK_DPRINT(" %sbound", DUK_HOBJECT_HAS_BOUND(obj) ? str_empty : str_excl)); DUK_D(DUK_DPRINT(" %scompiledfunction", DUK_HOBJECT_HAS_COMPILEDFUNCTION(obj) ? str_empty : str_excl)); DUK_D(DUK_DPRINT(" %snativefunction", DUK_HOBJECT_HAS_NATIVEFUNCTION(obj) ? str_empty : str_excl)); DUK_D(DUK_DPRINT(" %sthread", DUK_HOBJECT_HAS_THREAD(obj) ? str_empty : str_excl)); DUK_D(DUK_DPRINT(" %sarray_part", DUK_HOBJECT_HAS_ARRAY_PART(obj) ? str_empty : str_excl)); DUK_D(DUK_DPRINT(" %sstrict", DUK_HOBJECT_HAS_STRICT(obj) ? str_empty : str_excl)); DUK_D(DUK_DPRINT(" %snewenv", DUK_HOBJECT_HAS_NEWENV(obj) ? str_empty : str_excl)); DUK_D(DUK_DPRINT(" %snamebinding", DUK_HOBJECT_HAS_NAMEBINDING(obj) ? str_empty : str_excl)); DUK_D(DUK_DPRINT(" %screateargs", DUK_HOBJECT_HAS_CREATEARGS(obj) ? str_empty : str_excl)); DUK_D(DUK_DPRINT(" %senvrecclosed", DUK_HOBJECT_HAS_ENVRECCLOSED(obj) ? str_empty : str_excl)); DUK_D(DUK_DPRINT(" %sexotic_array", DUK_HOBJECT_HAS_EXOTIC_ARRAY(obj) ? str_empty : str_excl)); DUK_D(DUK_DPRINT(" %sexotic_stringobj", DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ(obj) ? str_empty : str_excl)); DUK_D(DUK_DPRINT(" %sexotic_arguments", DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(obj) ? str_empty : str_excl)); DUK_D(DUK_DPRINT(" %sexotic_dukfunc", DUK_HOBJECT_HAS_EXOTIC_DUKFUNC(obj) ? str_empty : str_excl)); DUK_D(DUK_DPRINT(" %sexotic_bufferobj", DUK_HOBJECT_HAS_EXOTIC_BUFFEROBJ(obj) ? str_empty : str_excl)); DUK_D(DUK_DPRINT(" %sexotic_proxyobj", DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(obj) ? str_empty : str_excl)); DUK_D(DUK_DPRINT(" class: number %d -> %s", (int) DUK_HOBJECT_GET_CLASS_NUMBER(obj), duk__class_names[(DUK_HOBJECT_GET_CLASS_NUMBER(obj)) & ((1 << DUK_HOBJECT_FLAG_CLASS_BITS) - 1)])); DUK_D(DUK_DPRINT(" prototype: %p -> %!O", (void *) obj->prototype, (duk_heaphdr *) obj->prototype)); DUK_D(DUK_DPRINT(" props: p=%p, e_size=%d, e_used=%d, a_size=%d, h_size=%d", (void *) obj->p, (int) obj->e_size, (int) obj->e_used, (int) obj->a_size, (int) obj->h_size)); /* * Object (struct layout) specific dumping. Inline code here * instead of helpers, to ensure debug line prefix is identical. */ if (DUK_HOBJECT_IS_COMPILEDFUNCTION(obj)) { duk_hcompiledfunction *h = (duk_hcompiledfunction *) obj; DUK_D(DUK_DPRINT(" hcompiledfunction")); DUK_D(DUK_DPRINT(" data: %!O", h->data)); DUK_D(DUK_DPRINT(" nregs: %d", (int) h->nregs)); DUK_D(DUK_DPRINT(" nargs: %d", (int) h->nargs)); if (h->data && DUK_HBUFFER_HAS_DYNAMIC(h->data) && DUK_HBUFFER_GET_DATA_PTR(h->data)) { DUK_D(DUK_DPRINT(" consts: %p (%d, %d bytes)", (void *) DUK_HCOMPILEDFUNCTION_GET_CONSTS_BASE(h), (int) DUK_HCOMPILEDFUNCTION_GET_CONSTS_COUNT(h), (int) DUK_HCOMPILEDFUNCTION_GET_CONSTS_SIZE(h))); DUK_D(DUK_DPRINT(" funcs: %p (%d, %d bytes)", (void *) DUK_HCOMPILEDFUNCTION_GET_FUNCS_BASE(h), (int) DUK_HCOMPILEDFUNCTION_GET_FUNCS_COUNT(h), (int) DUK_HCOMPILEDFUNCTION_GET_FUNCS_SIZE(h))); DUK_D(DUK_DPRINT(" bytecode: %p (%d, %d bytes)", (void *) DUK_HCOMPILEDFUNCTION_GET_CODE_BASE(h), (int) DUK_HCOMPILEDFUNCTION_GET_CODE_COUNT(h), (int) DUK_HCOMPILEDFUNCTION_GET_CODE_SIZE(h))); } else { DUK_D(DUK_DPRINT(" consts: ???")); DUK_D(DUK_DPRINT(" funcs: ???")); DUK_D(DUK_DPRINT(" bytecode: ???")); } } else if (DUK_HOBJECT_IS_NATIVEFUNCTION(obj)) { duk_hnativefunction *h = (duk_hnativefunction *) obj; DUK_D(DUK_DPRINT(" hnativefunction")); /* XXX: h->func, cannot print function pointers portably */ DUK_D(DUK_DPRINT(" nargs: %d", (int) h->nargs)); } else if (DUK_HOBJECT_IS_THREAD(obj)) { duk_hthread *thr = (duk_hthread *) obj; duk_tval *p; DUK_D(DUK_DPRINT(" hthread")); DUK_D(DUK_DPRINT(" strict: %d", (int) thr->strict)); DUK_D(DUK_DPRINT(" state: %d", (int) thr->state)); DUK_D(DUK_DPRINT(" valstack_max: %d, callstack_max:%d, catchstack_max: %d", thr->valstack_max, thr->callstack_max, thr->catchstack_max)); DUK_D(DUK_DPRINT(" callstack: ptr %p, size %d, top %d, preventcount %d, used size %d entries (%d bytes), alloc size %d entries (%d bytes)", (void *) thr->callstack, thr->callstack_size, thr->callstack_top, thr->callstack_preventcount, thr->callstack_top, thr->callstack_top * sizeof(duk_activation), thr->callstack_size, thr->callstack_size * sizeof(duk_activation))); DUK_DEBUG_SUMMARY_INIT(); DUK_DEBUG_SUMMARY_CHAR('['); for (i = 0; i <= thr->callstack_size; i++) { if (i == thr->callstack_top) { DUK_DEBUG_SUMMARY_CHAR('|'); } if (!thr->callstack) { DUK_DEBUG_SUMMARY_CHAR('@'); } else if (i < thr->callstack_size) { if (i < thr->callstack_top) { /* tailcalling is nice to see immediately; other flags (e.g. strict) * not that important. */ if (thr->callstack[i].flags & DUK_ACT_FLAG_TAILCALLED) { DUK_DEBUG_SUMMARY_CHAR('/'); } DUK_DEBUG_SUMMARY_CHAR(duk__get_act_summary_char(&thr->callstack[i])); } else { DUK_DEBUG_SUMMARY_CHAR('.'); } } } DUK_DEBUG_SUMMARY_CHAR(']'); DUK_DEBUG_SUMMARY_FINISH(); DUK_D(DUK_DPRINT(" valstack: ptr %p, end %p (%d), bottom %p (%d), top %p (%d), used size %d entries (%d bytes), alloc size %d entries (%d bytes)", (void *) thr->valstack, (void *) thr->valstack_end, (int) (thr->valstack_end - thr->valstack), (void *) thr->valstack_bottom, (int) (thr->valstack_bottom - thr->valstack), (void *) thr->valstack_top, (int) (thr->valstack_top - thr->valstack), (int) (thr->valstack_top - thr->valstack), (int) (thr->valstack_top - thr->valstack) * sizeof(duk_tval), (int) (thr->valstack_end - thr->valstack), (int) (thr->valstack_end - thr->valstack) * sizeof(duk_tval))); DUK_DEBUG_SUMMARY_INIT(); DUK_DEBUG_SUMMARY_CHAR('['); p = thr->valstack; while (p <= thr->valstack_end) { i = (duk_uint_fast32_t) (p - thr->valstack); if (thr->callstack && thr->callstack_top > 0 && i == (duk_size_t) (thr->callstack + thr->callstack_top - 1)->idx_bottom) { DUK_DEBUG_SUMMARY_CHAR('>'); } if (p == thr->valstack_top) { DUK_DEBUG_SUMMARY_CHAR('|'); } if (p < thr->valstack_end) { if (p < thr->valstack_top) { DUK_DEBUG_SUMMARY_CHAR(duk__get_tval_summary_char(p)); } else { /* XXX: safe printer for these? would be nice, because * we could visualize whether the values are in proper * state. */ DUK_DEBUG_SUMMARY_CHAR('.'); } } p++; } DUK_DEBUG_SUMMARY_CHAR(']'); DUK_DEBUG_SUMMARY_FINISH(); DUK_D(DUK_DPRINT(" catchstack: ptr %p, size %d, top %d, used size %d entries (%d bytes), alloc size %d entries (%d bytes)", (void *) thr->catchstack, thr->catchstack_size, thr->catchstack_top, thr->catchstack_top, thr->catchstack_top * sizeof(duk_catcher), thr->catchstack_size, thr->catchstack_size * sizeof(duk_catcher))); DUK_DEBUG_SUMMARY_INIT(); DUK_DEBUG_SUMMARY_CHAR('['); for (i = 0; i <= thr->catchstack_size; i++) { if (i == thr->catchstack_top) { DUK_DEBUG_SUMMARY_CHAR('|'); } if (!thr->catchstack) { DUK_DEBUG_SUMMARY_CHAR('@'); } else if (i < thr->catchstack_size) { if (i < thr->catchstack_top) { DUK_DEBUG_SUMMARY_CHAR(duk__get_cat_summary_char(&thr->catchstack[i])); } else { DUK_DEBUG_SUMMARY_CHAR('.'); } } } DUK_DEBUG_SUMMARY_CHAR(']'); DUK_DEBUG_SUMMARY_FINISH(); DUK_D(DUK_DPRINT(" resumer: ptr %p", (void *) thr->resumer)); #if 0 /* worth dumping? */ for (i = 0; i < DUK_NUM_BUILTINS; i++) { DUK_D(DUK_DPRINT(" builtins[%d] -> %!@O", i, thr->builtins[i])); } #endif } if (obj->p) { DUK_D(DUK_DPRINT(" props alloc size: %d", (int) DUK_HOBJECT_P_COMPUTE_SIZE(obj->e_size, obj->a_size, obj->h_size))); } else { DUK_D(DUK_DPRINT(" props alloc size: n/a")); } DUK_D(DUK_DPRINT(" prop entries:")); for (i = 0; i < obj->e_size; i++) { duk_hstring *k; duk_propvalue *v; k = DUK_HOBJECT_E_GET_KEY(obj, i); v = DUK_HOBJECT_E_GET_VALUE_PTR(obj, i); if (i >= obj->e_used) { DUK_D(DUK_DPRINT(" [%d]: UNUSED", i)); continue; } if (!k) { DUK_D(DUK_DPRINT(" [%d]: NULL", i)); continue; } if (DUK_HOBJECT_E_SLOT_IS_ACCESSOR(obj, i)) { DUK_D(DUK_DPRINT(" [%d]: [w=%d e=%d c=%d a=%d] %!O -> get:%p set:%p; get %!O; set %!O", i, DUK_HOBJECT_E_SLOT_IS_WRITABLE(obj, i), DUK_HOBJECT_E_SLOT_IS_ENUMERABLE(obj, i), DUK_HOBJECT_E_SLOT_IS_CONFIGURABLE(obj, i), DUK_HOBJECT_E_SLOT_IS_ACCESSOR(obj, i), k, (void *) v->a.get, (void *) v->a.set, (duk_heaphdr *) v->a.get, (duk_heaphdr *) v->a.set)); } else { DUK_D(DUK_DPRINT(" [%d]: [w=%d e=%d c=%d a=%d] %!O -> %!T", i, DUK_HOBJECT_E_SLOT_IS_WRITABLE(obj, i), DUK_HOBJECT_E_SLOT_IS_ENUMERABLE(obj, i), DUK_HOBJECT_E_SLOT_IS_CONFIGURABLE(obj, i), DUK_HOBJECT_E_SLOT_IS_ACCESSOR(obj, i), k, &v->v)); } } DUK_D(DUK_DPRINT(" array entries:")); for (i = 0; i < obj->a_size; i++) { DUK_D(DUK_DPRINT(" [%d]: [w=%d e=%d c=%d a=%d] %d -> %!T", i, 1, /* implicit attributes */ 1, 1, 0, i, DUK_HOBJECT_A_GET_VALUE_PTR(obj, i))); } DUK_D(DUK_DPRINT(" hash entries:")); for (i = 0; i < obj->h_size; i++) { duk_uint32_t t = DUK_HOBJECT_H_GET_INDEX(obj, i); if (t == DUK_HOBJECT_HASHIDX_UNUSED) { DUK_D(DUK_DPRINT(" [%d]: unused", i)); } else if (t == DUK_HOBJECT_HASHIDX_DELETED) { DUK_D(DUK_DPRINT(" [%d]: deleted", i)); } else { DUK_D(DUK_DPRINT(" [%d]: %d", i, (int) t)); } } }
void duk_err_augment_error(duk_hthread *thr, duk_hthread *thr_callstack, int err_index, const char *filename, int line, int noblame_fileline) { duk_context *ctx = (duk_context *) thr; duk_hobject *obj; DUK_ASSERT(thr != NULL); DUK_ASSERT(thr_callstack != NULL); DUK_ASSERT(ctx != NULL); err_index = duk_require_normalize_index(ctx, err_index); /* * Criteria for augmenting: * * - augmentation enabled in build (naturally) * - error value is an extensible object * - error value internal prototype chain contains the built-in * Error prototype object (i.e. 'val instanceof Error') */ obj = duk_require_hobject(ctx, err_index); if (!obj) { DUK_DDDPRINT("error value not an object, not augmented"); return; } if (!DUK_HOBJECT_HAS_EXTENSIBLE(obj)) { DUK_DDDPRINT("error value not extensible, not augmented"); return; } if (!duk_hobject_prototype_chain_contains(thr, obj, thr->builtins[DUK_BIDX_ERROR_PROTOTYPE])) { DUK_DDDPRINT("error value not inherited from Error, not augmented"); return; } /* Yes, augment error. */ #ifdef DUK_USE_TRACEBACKS /* * If tracebacks are enabled, the 'tracedata' property is the only * thing we need: 'fileName' and 'lineNumber' are virtual properties * which use 'tracedata'. */ if (duk_hobject_hasprop_raw(thr, obj, DUK_HTHREAD_STRING_TRACEDATA(thr))) { DUK_DDDPRINT("error value already has a 'traceback' property, not modifying it"); } else { add_traceback(thr, thr_callstack, obj, err_index, filename, line, noblame_fileline); } #else /* * If tracebacks are disabled, 'fileName' and 'lineNumber' are added * as plain own properties. Since Error.prototype has accessors of * the same name, we need to define own properties directly (cannot * just use e.g. duk_put_prop_stridx). Existing properties are not * overwritten in case they already exist. */ if (filename && !noblame_fileline) { /* FIXME: file/line is disabled in minimal builds, so disable this too * when appropriate. */ duk_push_string(ctx, filename); duk_def_prop_stridx(ctx, err_index, DUK_STRIDX_FILE_NAME, DUK_PROPDESC_FLAGS_WC | DUK_PROPDESC_FLAG_NO_OVERWRITE); duk_push_int(ctx, line); duk_def_prop_stridx(ctx, err_index, DUK_STRIDX_LINE_NUMBER, DUK_PROPDESC_FLAGS_WC | DUK_PROPDESC_FLAG_NO_OVERWRITE); } else if (thr_callstack->callstack_top > 0) { duk_activation *act; duk_hobject *func; duk_hbuffer *pc2line; act = thr_callstack->callstack + thr_callstack->callstack_top - 1; DUK_ASSERT(act >= thr_callstack->callstack && act < thr_callstack->callstack + thr_callstack->callstack_size); func = act->func; if (func) { int pc; duk_uint32_t line; /* PC points to next instruction, find offending PC. Note that * PC == 0 for native code. */ pc = act->pc; if (pc > 0) { pc--; } DUK_ASSERT(pc >= 0 && (double) pc < DUK_DOUBLE_2TO32); /* assume PC is at most 32 bits and non-negative */ act = NULL; /* invalidated by pushes, so get out of the way */ duk_push_hobject(ctx, func); duk_get_prop_stridx(ctx, -1, DUK_STRIDX_FILE_NAME); duk_def_prop_stridx(ctx, err_index, DUK_STRIDX_FILE_NAME, DUK_PROPDESC_FLAGS_WC | DUK_PROPDESC_FLAG_NO_OVERWRITE); if (DUK_HOBJECT_IS_COMPILEDFUNCTION(func)) { #if 0 duk_push_number(ctx, pc); duk_def_prop_stridx(ctx, err_index, DUK_STRIDX_PC, DUK_PROPDESC_FLAGS_WC | DUK_PROPDESC_FLAGS_NO_OVERWRITE); #endif duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_PC2LINE); if (duk_is_buffer(ctx, -1)) { pc2line = duk_get_hbuffer(ctx, -1); DUK_ASSERT(pc2line != NULL); DUK_ASSERT(!DUK_HBUFFER_HAS_DYNAMIC(pc2line)); line = duk_hobject_pc2line_query((duk_hbuffer_fixed *) pc2line, (duk_uint_fast32_t) pc); duk_push_number(ctx, (double) line); /* FIXME: u32 */ duk_def_prop_stridx(ctx, err_index, DUK_STRIDX_LINE_NUMBER, DUK_PROPDESC_FLAGS_WC | DUK_PROPDESC_FLAG_NO_OVERWRITE); } duk_pop(ctx); } else { /* Native function, no relevant lineNumber. */ } duk_pop(ctx); } } #endif /* DUK_USE_TRACEBACKS */ }
DUK_INTERNAL void duk_hthread_create_builtin_objects(duk_hthread *thr) { duk_context *ctx = (duk_context *) thr; duk_bitdecoder_ctx bd_ctx; duk_bitdecoder_ctx *bd = &bd_ctx; /* convenience */ duk_hobject *h; duk_small_uint_t i, j; DUK_D(DUK_DPRINT("INITBUILTINS BEGIN")); DUK_MEMZERO(&bd_ctx, sizeof(bd_ctx)); bd->data = (const duk_uint8_t *) duk_builtins_data; bd->length = (duk_size_t) DUK_BUILTINS_DATA_LENGTH; /* * First create all built-in bare objects on the empty valstack. * During init, their indices will correspond to built-in indices. * * Built-ins will be reachable from both valstack and thr->builtins. */ /* XXX: there is no need to resize valstack because builtin count * is much less than the default space; assert for it. */ DUK_DD(DUK_DDPRINT("create empty built-ins")); DUK_ASSERT_TOP(ctx, 0); for (i = 0; i < DUK_NUM_BUILTINS; i++) { duk_small_uint_t class_num; duk_small_int_t len = -1; /* must be signed */ class_num = (duk_small_uint_t) duk_bd_decode(bd, DUK__CLASS_BITS); len = (duk_small_int_t) duk_bd_decode_flagged(bd, DUK__LENGTH_PROP_BITS, (duk_int32_t) -1 /*def_value*/); if (class_num == DUK_HOBJECT_CLASS_FUNCTION) { duk_small_uint_t natidx; duk_small_uint_t stridx; duk_int_t c_nargs; /* must hold DUK_VARARGS */ duk_c_function c_func; duk_int16_t magic; DUK_DDD(DUK_DDDPRINT("len=%ld", (long) len)); DUK_ASSERT(len >= 0); natidx = (duk_small_uint_t) duk_bd_decode(bd, DUK__NATIDX_BITS); stridx = (duk_small_uint_t) duk_bd_decode(bd, DUK__STRIDX_BITS); c_func = duk_bi_native_functions[natidx]; c_nargs = (duk_small_uint_t) duk_bd_decode_flagged(bd, DUK__NARGS_BITS, len /*def_value*/); if (c_nargs == DUK__NARGS_VARARGS_MARKER) { c_nargs = DUK_VARARGS; } /* XXX: set magic directly here? (it could share the c_nargs arg) */ duk_push_c_function_noexotic(ctx, c_func, c_nargs); h = duk_require_hobject(ctx, -1); DUK_ASSERT(h != NULL); /* Currently all built-in native functions are strict. * duk_push_c_function() now sets strict flag, so * assert for it. */ DUK_ASSERT(DUK_HOBJECT_HAS_STRICT(h)); /* XXX: function properties */ duk_push_hstring_stridx(ctx, stridx); duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_NONE); /* Almost all global level Function objects are constructable * but not all: Function.prototype is a non-constructable, * callable Function. */ if (duk_bd_decode_flag(bd)) { DUK_ASSERT(DUK_HOBJECT_HAS_CONSTRUCTABLE(h)); } else { DUK_HOBJECT_CLEAR_CONSTRUCTABLE(h); } /* Cast converts magic to 16-bit signed value */ magic = (duk_int16_t) duk_bd_decode_flagged(bd, DUK__MAGIC_BITS, 0 /*def_value*/); ((duk_hnativefunction *) h)->magic = magic; } else { /* XXX: ARRAY_PART for Array prototype? */ duk_push_object_helper(ctx, DUK_HOBJECT_FLAG_EXTENSIBLE, -1); /* no prototype or class yet */ h = duk_require_hobject(ctx, -1); DUK_ASSERT(h != NULL); } DUK_HOBJECT_SET_CLASS_NUMBER(h, class_num); thr->builtins[i] = h; DUK_HOBJECT_INCREF(thr, &h->hdr); if (len >= 0) { /* * For top-level objects, 'length' property has the following * default attributes: non-writable, non-enumerable, non-configurable * (E5 Section 15). * * However, 'length' property for Array.prototype has attributes * expected of an Array instance which are different: writable, * non-enumerable, non-configurable (E5 Section 15.4.5.2). * * This is currently determined implicitly based on class; there are * no attribute flags in the init data. */ duk_push_int(ctx, len); duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH, (class_num == DUK_HOBJECT_CLASS_ARRAY ? /* only Array.prototype matches */ DUK_PROPDESC_FLAGS_W : DUK_PROPDESC_FLAGS_NONE)); } /* enable exotic behaviors last */ if (class_num == DUK_HOBJECT_CLASS_ARRAY) { DUK_HOBJECT_SET_EXOTIC_ARRAY(h); } if (class_num == DUK_HOBJECT_CLASS_STRING) { DUK_HOBJECT_SET_EXOTIC_STRINGOBJ(h); } /* some assertions */ DUK_ASSERT(DUK_HOBJECT_HAS_EXTENSIBLE(h)); /* DUK_HOBJECT_FLAG_CONSTRUCTABLE varies */ DUK_ASSERT(!DUK_HOBJECT_HAS_BOUND(h)); DUK_ASSERT(!DUK_HOBJECT_HAS_COMPILEDFUNCTION(h)); /* DUK_HOBJECT_FLAG_NATIVEFUNCTION varies */ DUK_ASSERT(!DUK_HOBJECT_HAS_THREAD(h)); DUK_ASSERT(!DUK_HOBJECT_HAS_ARRAY_PART(h)); /* currently, even for Array.prototype */ /* DUK_HOBJECT_FLAG_STRICT varies */ DUK_ASSERT(!DUK_HOBJECT_HAS_NATIVEFUNCTION(h) || /* all native functions have NEWENV */ DUK_HOBJECT_HAS_NEWENV(h)); DUK_ASSERT(!DUK_HOBJECT_HAS_NAMEBINDING(h)); DUK_ASSERT(!DUK_HOBJECT_HAS_CREATEARGS(h)); DUK_ASSERT(!DUK_HOBJECT_HAS_ENVRECCLOSED(h)); /* DUK_HOBJECT_FLAG_EXOTIC_ARRAY varies */ /* DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ varies */ DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(h)); DUK_DDD(DUK_DDDPRINT("created built-in %ld, class=%ld, length=%ld", (long) i, (long) class_num, (long) len)); } /* * Then decode the builtins init data (see genbuiltins.py) to * init objects */ DUK_DD(DUK_DDPRINT("initialize built-in object properties")); for (i = 0; i < DUK_NUM_BUILTINS; i++) { duk_small_uint_t t; duk_small_uint_t num; DUK_DDD(DUK_DDDPRINT("initializing built-in object at index %ld", (long) i)); h = thr->builtins[i]; t = (duk_small_uint_t) duk_bd_decode(bd, DUK__BIDX_BITS); if (t != DUK__NO_BIDX_MARKER) { DUK_DDD(DUK_DDDPRINT("set internal prototype: built-in %ld", (long) t)); DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, h, thr->builtins[t]); } t = (duk_small_uint_t) duk_bd_decode(bd, DUK__BIDX_BITS); if (t != DUK__NO_BIDX_MARKER) { /* 'prototype' property for all built-in objects (which have it) has attributes: * [[Writable]] = false, * [[Enumerable]] = false, * [[Configurable]] = false */ DUK_DDD(DUK_DDDPRINT("set external prototype: built-in %ld", (long) t)); duk_xdef_prop_stridx_builtin(ctx, i, DUK_STRIDX_PROTOTYPE, t, DUK_PROPDESC_FLAGS_NONE); } t = (duk_small_uint_t) duk_bd_decode(bd, DUK__BIDX_BITS); if (t != DUK__NO_BIDX_MARKER) { /* 'constructor' property for all built-in objects (which have it) has attributes: * [[Writable]] = true, * [[Enumerable]] = false, * [[Configurable]] = true */ DUK_DDD(DUK_DDDPRINT("set external constructor: built-in %ld", (long) t)); duk_xdef_prop_stridx_builtin(ctx, i, DUK_STRIDX_CONSTRUCTOR, t, DUK_PROPDESC_FLAGS_WC); } /* normal valued properties */ num = (duk_small_uint_t) duk_bd_decode(bd, DUK__NUM_NORMAL_PROPS_BITS); DUK_DDD(DUK_DDDPRINT("built-in object %ld, %ld normal valued properties", (long) i, (long) num)); for (j = 0; j < num; j++) { duk_small_uint_t stridx; duk_small_uint_t prop_flags; stridx = (duk_small_uint_t) duk_bd_decode(bd, DUK__STRIDX_BITS); /* * Property attribute defaults are defined in E5 Section 15 (first * few pages); there is a default for all properties and a special * default for 'length' properties. Variation from the defaults is * signaled using a single flag bit in the bitstream. */ if (duk_bd_decode_flag(bd)) { prop_flags = (duk_small_uint_t) duk_bd_decode(bd, DUK__PROP_FLAGS_BITS); } else { if (stridx == DUK_STRIDX_LENGTH) { prop_flags = DUK_PROPDESC_FLAGS_NONE; } else { prop_flags = DUK_PROPDESC_FLAGS_WC; } } t = (duk_small_uint_t) duk_bd_decode(bd, DUK__PROP_TYPE_BITS); DUK_DDD(DUK_DDDPRINT("built-in %ld, normal-valued property %ld, stridx %ld, flags 0x%02lx, type %ld", (long) i, (long) j, (long) stridx, (unsigned long) prop_flags, (long) t)); switch (t) { case DUK__PROP_TYPE_DOUBLE: { duk_double_union du; duk_small_uint_t k; for (k = 0; k < 8; k++) { /* Encoding endianness must match target memory layout, * build scripts and genbuiltins.py must ensure this. */ du.uc[k] = (duk_uint8_t) duk_bd_decode(bd, 8); } duk_push_number(ctx, du.d); /* push operation normalizes NaNs */ break; } case DUK__PROP_TYPE_STRING: { duk_small_uint_t n; duk_small_uint_t k; duk_uint8_t *p; n = (duk_small_uint_t) duk_bd_decode(bd, DUK__STRING_LENGTH_BITS); p = (duk_uint8_t *) duk_push_fixed_buffer(ctx, n); for (k = 0; k < n; k++) { *p++ = (duk_uint8_t) duk_bd_decode(bd, DUK__STRING_CHAR_BITS); } duk_to_string(ctx, -1); break; } case DUK__PROP_TYPE_STRIDX: { duk_small_uint_t n; n = (duk_small_uint_t) duk_bd_decode(bd, DUK__STRIDX_BITS); DUK_ASSERT_DISABLE(n >= 0); /* unsigned */ DUK_ASSERT(n < DUK_HEAP_NUM_STRINGS); duk_push_hstring_stridx(ctx, n); break; } case DUK__PROP_TYPE_BUILTIN: { duk_small_uint_t bidx; bidx = (duk_small_uint_t) duk_bd_decode(bd, DUK__BIDX_BITS); DUK_ASSERT(bidx != DUK__NO_BIDX_MARKER); duk_dup(ctx, (duk_idx_t) bidx); break; } case DUK__PROP_TYPE_UNDEFINED: { duk_push_undefined(ctx); break; } case DUK__PROP_TYPE_BOOLEAN_TRUE: { duk_push_true(ctx); break; } case DUK__PROP_TYPE_BOOLEAN_FALSE: { duk_push_false(ctx); break; } case DUK__PROP_TYPE_ACCESSOR: { duk_small_uint_t natidx_getter = (duk_small_uint_t) duk_bd_decode(bd, DUK__NATIDX_BITS); duk_small_uint_t natidx_setter = (duk_small_uint_t) duk_bd_decode(bd, DUK__NATIDX_BITS); duk_c_function c_func_getter; duk_c_function c_func_setter; /* XXX: this is a bit awkward because there is no exposed helper * in the API style, only this internal helper. */ DUK_DDD(DUK_DDDPRINT("built-in accessor property: objidx=%ld, stridx=%ld, getteridx=%ld, setteridx=%ld, flags=0x%04lx", (long) i, (long) stridx, (long) natidx_getter, (long) natidx_setter, (unsigned long) prop_flags)); c_func_getter = duk_bi_native_functions[natidx_getter]; c_func_setter = duk_bi_native_functions[natidx_setter]; duk_push_c_function_noconstruct_noexotic(ctx, c_func_getter, 0); /* always 0 args */ duk_push_c_function_noconstruct_noexotic(ctx, c_func_setter, 1); /* always 1 arg */ /* XXX: magic for getter/setter? */ prop_flags |= DUK_PROPDESC_FLAG_ACCESSOR; /* accessor flag not encoded explicitly */ duk_hobject_define_accessor_internal(thr, duk_require_hobject(ctx, i), DUK_HTHREAD_GET_STRING(thr, stridx), duk_require_hobject(ctx, -2), duk_require_hobject(ctx, -1), prop_flags); duk_pop_2(ctx); /* getter and setter, now reachable through object */ goto skip_value; } default: { /* exhaustive */ DUK_UNREACHABLE(); } } DUK_ASSERT((prop_flags & DUK_PROPDESC_FLAG_ACCESSOR) == 0); duk_xdef_prop_stridx(ctx, i, stridx, prop_flags); skip_value: continue; /* avoid empty label at the end of a compound statement */ } /* native function properties */ num = (duk_small_uint_t) duk_bd_decode(bd, DUK__NUM_FUNC_PROPS_BITS); DUK_DDD(DUK_DDDPRINT("built-in object %ld, %ld function valued properties", (long) i, (long) num)); for (j = 0; j < num; j++) { duk_small_uint_t stridx; duk_small_uint_t natidx; duk_int_t c_nargs; /* must hold DUK_VARARGS */ duk_small_uint_t c_length; duk_int16_t magic; duk_c_function c_func; duk_hnativefunction *h_func; #if defined(DUK_USE_LIGHTFUNC_BUILTINS) duk_small_int_t lightfunc_eligible; #endif stridx = (duk_small_uint_t) duk_bd_decode(bd, DUK__STRIDX_BITS); natidx = (duk_small_uint_t) duk_bd_decode(bd, DUK__NATIDX_BITS); c_length = (duk_small_uint_t) duk_bd_decode(bd, DUK__LENGTH_PROP_BITS); c_nargs = (duk_int_t) duk_bd_decode_flagged(bd, DUK__NARGS_BITS, (duk_int32_t) c_length /*def_value*/); if (c_nargs == DUK__NARGS_VARARGS_MARKER) { c_nargs = DUK_VARARGS; } c_func = duk_bi_native_functions[natidx]; DUK_DDD(DUK_DDDPRINT("built-in %ld, function-valued property %ld, stridx %ld, natidx %ld, length %ld, nargs %ld", (long) i, (long) j, (long) stridx, (long) natidx, (long) c_length, (c_nargs == DUK_VARARGS ? (long) -1 : (long) c_nargs))); /* Cast converts magic to 16-bit signed value */ magic = (duk_int16_t) duk_bd_decode_flagged(bd, DUK__MAGIC_BITS, 0); #if defined(DUK_USE_LIGHTFUNC_BUILTINS) lightfunc_eligible = ((c_nargs >= DUK_LFUNC_NARGS_MIN && c_nargs <= DUK_LFUNC_NARGS_MAX) || (c_nargs == DUK_VARARGS)) && (c_length <= DUK_LFUNC_LENGTH_MAX) && (magic >= DUK_LFUNC_MAGIC_MIN && magic <= DUK_LFUNC_MAGIC_MAX); if (stridx == DUK_STRIDX_EVAL || stridx == DUK_STRIDX_YIELD || stridx == DUK_STRIDX_RESUME || stridx == DUK_STRIDX_REQUIRE) { /* These functions have trouble working as lightfuncs. * Some of them have specific asserts and some may have * additional properties (e.g. 'require.id' may be written). */ DUK_D(DUK_DPRINT("reject as lightfunc: stridx=%d, i=%d, j=%d", (int) stridx, (int) i, (int) j)); lightfunc_eligible = 0; } if (lightfunc_eligible) { duk_tval tv_lfunc; duk_small_uint_t lf_nargs = (c_nargs == DUK_VARARGS ? DUK_LFUNC_NARGS_VARARGS : c_nargs); duk_small_uint_t lf_flags = DUK_LFUNC_FLAGS_PACK(magic, c_length, lf_nargs); DUK_TVAL_SET_LIGHTFUNC(&tv_lfunc, c_func, lf_flags); duk_push_tval(ctx, &tv_lfunc); DUK_D(DUK_DPRINT("built-in function eligible as light function: i=%d, j=%d c_length=%ld, c_nargs=%ld, magic=%ld -> %!iT", (int) i, (int) j, (long) c_length, (long) c_nargs, (long) magic, duk_get_tval(ctx, -1))); goto lightfunc_skip; } DUK_D(DUK_DPRINT("built-in function NOT ELIGIBLE as light function: i=%d, j=%d c_length=%ld, c_nargs=%ld, magic=%ld", (int) i, (int) j, (long) c_length, (long) c_nargs, (long) magic)); #endif /* DUK_USE_LIGHTFUNC_BUILTINS */ /* [ (builtin objects) ] */ duk_push_c_function_noconstruct_noexotic(ctx, c_func, c_nargs); h_func = duk_require_hnativefunction(ctx, -1); DUK_UNREF(h_func); /* Currently all built-in native functions are strict. * This doesn't matter for many functions, but e.g. * String.prototype.charAt (and other string functions) * rely on being strict so that their 'this' binding is * not automatically coerced. */ DUK_HOBJECT_SET_STRICT((duk_hobject *) h_func); /* No built-in functions are constructable except the top * level ones (Number, etc). */ DUK_ASSERT(!DUK_HOBJECT_HAS_CONSTRUCTABLE((duk_hobject *) h_func)); /* XXX: any way to avoid decoding magic bit; there are quite * many function properties and relatively few with magic values. */ h_func->magic = magic; /* [ (builtin objects) func ] */ duk_push_int(ctx, c_length); duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_NONE); duk_push_hstring_stridx(ctx, stridx); duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_NONE); /* XXX: other properties of function instances; 'arguments', 'caller'. */ DUK_DD(DUK_DDPRINT("built-in object %ld, function property %ld -> %!T", (long) i, (long) j, (duk_tval *) duk_get_tval(ctx, -1))); /* [ (builtin objects) func ] */ /* * The default property attributes are correct for all * function valued properties of built-in objects now. */ #if defined(DUK_USE_LIGHTFUNC_BUILTINS) lightfunc_skip: #endif duk_xdef_prop_stridx(ctx, i, stridx, DUK_PROPDESC_FLAGS_WC); /* [ (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. */ duk_get_prop_stridx(ctx, DUK_BIDX_DATE_PROTOTYPE, DUK_STRIDX_TO_UTC_STRING); duk_xdef_prop_stridx(ctx, DUK_BIDX_DATE_PROTOTYPE, DUK_STRIDX_TO_GMT_STRING, DUK_PROPDESC_FLAGS_WC); h = duk_require_hobject(ctx, DUK_BIDX_DOUBLE_ERROR); DUK_ASSERT(h != NULL); 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 duk_push_string(ctx, /* 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 #if defined(DUK_USE_BYTEORDER_FORCED) "f" #endif " " /* Packed or unpacked tval */ #if defined(DUK_USE_PACKED_TVAL) "p" #else "u" #endif #if defined(DUK_USE_FASTINT) "f" #endif " " /* Low memory options */ #if defined(DUK_USE_STRTAB_CHAIN) "c" /* chain */ #elif defined(DUK_USE_STRTAB_PROBE) "p" /* probe */ #else "?" #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) "O" #endif #if defined(DUK_USE_LIGHTFUNC_BUILTINS) "L" #endif " " /* Object property allocation layout */ #if defined(DUK_USE_HOBJECT_LAYOUT_1) "p1" #elif defined(DUK_USE_HOBJECT_LAYOUT_2) "p2" #elif defined(DUK_USE_HOBJECT_LAYOUT_3) "p3" #else "p?" #endif " " /* Alignment guarantee */ #if defined(DUK_USE_ALIGN_4) "a4" #elif defined(DUK_USE_ALIGN_8) "a8" #else "a1" #endif " " /* Architecture, OS, and compiler strings */ DUK_USE_ARCH_STRING " " DUK_USE_OS_STRING " " DUK_USE_COMPILER_STRING); duk_xdef_prop_stridx(ctx, DUK_BIDX_DUKTAPE, DUK_STRIDX_ENV, DUK_PROPDESC_FLAGS_WC); /* * InitJS code - Ecmascript code evaluated from a built-in source * which provides e.g. backward compatibility. User can also provide * JS code to be evaluated at startup. */ #ifdef DUK_USE_BUILTIN_INITJS /* XXX: compression */ DUK_DD(DUK_DDPRINT("running built-in initjs")); duk_eval_string(ctx, (const char *) duk_initjs_data); /* initjs data is NUL terminated */ duk_pop(ctx); #endif /* DUK_USE_BUILTIN_INITJS */ #ifdef DUK_USE_USER_INITJS /* XXX: compression (as an option) */ DUK_DD(DUK_DDPRINT("running user initjs")); duk_eval_string_noresult(ctx, (const char *) DUK_USE_USER_INITJS); #endif /* DUK_USE_USER_INITJS */ /* * Since built-ins are not often extended, compact them. */ DUK_DD(DUK_DDPRINT("compact built-ins")); for (i = 0; i < DUK_NUM_BUILTINS; i++) { duk_hobject_compact_props(thr, thr->builtins[i]); } DUK_D(DUK_DPRINT("INITBUILTINS END")); #ifdef DUK_USE_DDPRINT for (i = 0; i < DUK_NUM_BUILTINS; i++) { DUK_DD(DUK_DDPRINT("built-in object %ld after initialization and compacting: %!@iO", (long) i, (duk_heaphdr *) thr->builtins[i])); } #endif /* * Pop built-ins from stack: they are now INCREF'd and * reachable from the builtins[] array. */ duk_pop_n(ctx, DUK_NUM_BUILTINS); DUK_ASSERT_TOP(ctx, 0); }
void duk_hthread_create_builtin_objects(duk_hthread *thr) { duk_context *ctx = (duk_context *) thr; duk_bitdecoder_ctx bd_ctx; duk_bitdecoder_ctx *bd = &bd_ctx; /* convenience */ duk_hobject *h; int i, j; DUK_DPRINT("INITBUILTINS BEGIN"); DUK_MEMZERO(&bd_ctx, sizeof(bd_ctx)); bd->data = (const duk_uint8_t *) duk_builtins_data; bd->length = (duk_size_t) DUK_BUILTINS_DATA_LENGTH; /* * First create all built-in bare objects on the empty valstack. * During init, their indices will correspond to built-in indices. * * Built-ins will be reachable from both valstack and thr->builtins. */ /* XXX: there is no need to resize valstack because builtin count * is much less than the default space; assert for it. */ DUK_DDPRINT("create empty built-ins"); DUK_ASSERT_TOP(ctx, 0); for (i = 0; i < DUK_NUM_BUILTINS; i++) { int class_num; int len = -1; class_num = duk_bd_decode(bd, DUK__CLASS_BITS); len = duk_bd_decode_flagged(bd, DUK__LENGTH_PROP_BITS, (duk_int32_t) -1 /*def_value*/); if (class_num == DUK_HOBJECT_CLASS_FUNCTION) { int natidx; int stridx; int c_nargs; duk_c_function c_func; duk_int16_t magic; DUK_DDDPRINT("len=%d", len); DUK_ASSERT(len >= 0); natidx = duk_bd_decode(bd, DUK__NATIDX_BITS); stridx = duk_bd_decode(bd, DUK__STRIDX_BITS); c_func = duk_bi_native_functions[natidx]; c_nargs = duk_bd_decode_flagged(bd, DUK__NARGS_BITS, len /*def_value*/); if (c_nargs == DUK__NARGS_VARARGS_MARKER) { c_nargs = DUK_VARARGS; } /* FIXME: set magic directly here? (it could share the c_nargs arg) */ duk_push_c_function_nospecial(ctx, c_func, c_nargs); h = duk_require_hobject(ctx, -1); DUK_ASSERT(h != NULL); /* Currently all built-in native functions are strict. * duk_push_c_function() now sets strict flag, so * assert for it. */ DUK_ASSERT(DUK_HOBJECT_HAS_STRICT(h)); /* FIXME: function properties */ duk_push_hstring_stridx(ctx, stridx); duk_def_prop_stridx(ctx, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_NONE); /* Almost all global level Function objects are constructable * but not all: Function.prototype is a non-constructable, * callable Function. */ if (duk_bd_decode_flag(bd)) { DUK_ASSERT(DUK_HOBJECT_HAS_CONSTRUCTABLE(h)); } else { DUK_HOBJECT_CLEAR_CONSTRUCTABLE(h); } /* Cast converts magic to 16-bit signed value */ magic = (duk_int16_t) duk_bd_decode_flagged(bd, DUK__MAGIC_BITS, 0 /*def_value*/); ((duk_hnativefunction *) h)->magic = magic; } else { /* FIXME: ARRAY_PART for Array prototype? */ duk_push_object_helper(ctx, DUK_HOBJECT_FLAG_EXTENSIBLE, -1); /* no prototype or class yet */ h = duk_require_hobject(ctx, -1); DUK_ASSERT(h != NULL); } DUK_HOBJECT_SET_CLASS_NUMBER(h, class_num); thr->builtins[i] = h; DUK_HOBJECT_INCREF(thr, &h->hdr); if (len >= 0) { /* * For top-level objects, 'length' property has the following * default attributes: non-writable, non-enumerable, non-configurable * (E5 Section 15). * * However, 'length' property for Array.prototype has attributes * expected of an Array instance which are different: writable, * non-enumerable, non-configurable (E5 Section 15.4.5.2). * * This is currently determined implicitly based on class; there are * no attribute flags in the init data. */ duk_push_int(ctx, len); duk_def_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH, (class_num == DUK_HOBJECT_CLASS_ARRAY ? /* only Array.prototype matches */ DUK_PROPDESC_FLAGS_W : DUK_PROPDESC_FLAGS_NONE)); } /* enable special behaviors last */ if (class_num == DUK_HOBJECT_CLASS_ARRAY) { DUK_HOBJECT_SET_SPECIAL_ARRAY(h); } if (class_num == DUK_HOBJECT_CLASS_STRING) { DUK_HOBJECT_SET_SPECIAL_STRINGOBJ(h); } /* some assertions */ DUK_ASSERT(DUK_HOBJECT_HAS_EXTENSIBLE(h)); /* DUK_HOBJECT_FLAG_CONSTRUCTABLE varies */ DUK_ASSERT(!DUK_HOBJECT_HAS_BOUND(h)); DUK_ASSERT(!DUK_HOBJECT_HAS_COMPILEDFUNCTION(h)); /* DUK_HOBJECT_FLAG_NATIVEFUNCTION varies */ DUK_ASSERT(!DUK_HOBJECT_HAS_THREAD(h)); DUK_ASSERT(!DUK_HOBJECT_HAS_ARRAY_PART(h)); /* currently, even for Array.prototype */ /* DUK_HOBJECT_FLAG_STRICT varies */ DUK_ASSERT(!DUK_HOBJECT_HAS_NATIVEFUNCTION(h) || /* all native functions have NEWENV */ DUK_HOBJECT_HAS_NEWENV(h)); DUK_ASSERT(!DUK_HOBJECT_HAS_NAMEBINDING(h)); DUK_ASSERT(!DUK_HOBJECT_HAS_CREATEARGS(h)); DUK_ASSERT(!DUK_HOBJECT_HAS_ENVRECCLOSED(h)); /* DUK_HOBJECT_FLAG_SPECIAL_ARRAY varies */ /* DUK_HOBJECT_FLAG_SPECIAL_STRINGOBJ varies */ DUK_ASSERT(!DUK_HOBJECT_HAS_SPECIAL_ARGUMENTS(h)); DUK_DDDPRINT("created built-in %d, class=%d, length=%d", i, class_num, len); } /* * Then decode the builtins init data (see genbuiltins.py) to * init objects */ DUK_DDPRINT("initialize built-in object properties"); for (i = 0; i < DUK_NUM_BUILTINS; i++) { unsigned char t; int num; DUK_DDDPRINT("initializing built-in object at index %d", i); h = thr->builtins[i]; t = duk_bd_decode(bd, DUK__BIDX_BITS); if (t != DUK__NO_BIDX_MARKER) { DUK_DDDPRINT("set internal prototype: built-in %d", (int) t); DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, h, thr->builtins[t]); } t = duk_bd_decode(bd, DUK__BIDX_BITS); if (t != DUK__NO_BIDX_MARKER) { /* 'prototype' property for all built-in objects (which have it) has attributes: * [[Writable]] = false, * [[Enumerable]] = false, * [[Configurable]] = false */ DUK_DDDPRINT("set external prototype: built-in %d", (int) t); duk_def_prop_stridx_builtin(ctx, i, DUK_STRIDX_PROTOTYPE, t, DUK_PROPDESC_FLAGS_NONE); } t = duk_bd_decode(bd, DUK__BIDX_BITS); if (t != DUK__NO_BIDX_MARKER) { /* 'constructor' property for all built-in objects (which have it) has attributes: * [[Writable]] = true, * [[Enumerable]] = false, * [[Configurable]] = true */ DUK_DDDPRINT("set external constructor: built-in %d", (int) t); duk_def_prop_stridx_builtin(ctx, i, DUK_STRIDX_CONSTRUCTOR, t, DUK_PROPDESC_FLAGS_WC); } /* normal valued properties */ num = duk_bd_decode(bd, DUK__NUM_NORMAL_PROPS_BITS); DUK_DDDPRINT("built-in object %d, %d normal valued properties", i, num); for (j = 0; j < num; j++) { int stridx; int prop_flags; stridx = duk_bd_decode(bd, DUK__STRIDX_BITS); /* * Property attribute defaults are defined in E5 Section 15 (first * few pages); there is a default for all properties and a special * default for 'length' properties. Variation from the defaults is * signaled using a single flag bit in the bitstream. */ if (duk_bd_decode_flag(bd)) { prop_flags = duk_bd_decode(bd, DUK__PROP_FLAGS_BITS); } else { if (stridx == DUK_STRIDX_LENGTH) { prop_flags = DUK_PROPDESC_FLAGS_NONE; } else { prop_flags = DUK_PROPDESC_FLAGS_WC; } } t = duk_bd_decode(bd, DUK__PROP_TYPE_BITS); DUK_DDDPRINT("built-in %d, normal-valued property %d, stridx %d, flags 0x%02x, type %d", i, j, stridx, prop_flags, (int) t); switch (t) { case DUK__PROP_TYPE_DOUBLE: { duk_double_union du; int k; for (k = 0; k < 8; k++) { /* Encoding endianness must match target memory layout, * build scripts and genbuiltins.py must ensure this. */ du.uc[k] = (duk_uint8_t) duk_bd_decode(bd, 8); } duk_push_number(ctx, du.d); /* push operation normalizes NaNs */ break; } case DUK__PROP_TYPE_STRING: { int n; int k; char *p; n = duk_bd_decode(bd, DUK__STRING_LENGTH_BITS); p = (char *) duk_push_fixed_buffer(ctx, n); for (k = 0; k < n; k++) { *p++ = duk_bd_decode(bd, DUK__STRING_CHAR_BITS); } duk_to_string(ctx, -1); break; } case DUK__PROP_TYPE_STRIDX: { int n; n = duk_bd_decode(bd, DUK__STRIDX_BITS); DUK_ASSERT(n >= 0 && n < DUK_HEAP_NUM_STRINGS); duk_push_hstring_stridx(ctx, n); break; } case DUK__PROP_TYPE_BUILTIN: { int bidx; bidx = duk_bd_decode(bd, DUK__BIDX_BITS); DUK_ASSERT(bidx != DUK__NO_BIDX_MARKER); duk_dup(ctx, bidx); break; } case DUK__PROP_TYPE_UNDEFINED: { duk_push_undefined(ctx); break; } case DUK__PROP_TYPE_BOOLEAN_TRUE: { duk_push_true(ctx); break; } case DUK__PROP_TYPE_BOOLEAN_FALSE: { duk_push_false(ctx); break; } case DUK__PROP_TYPE_ACCESSOR: { int natidx_getter = duk_bd_decode(bd, DUK__NATIDX_BITS); int natidx_setter = duk_bd_decode(bd, DUK__NATIDX_BITS); duk_c_function c_func_getter; duk_c_function c_func_setter; /* XXX: this is a bit awkward because there is no exposed helper * in the API style, only this internal helper. */ DUK_DDDPRINT("built-in accessor property: objidx=%d, stridx=%d, getteridx=%d, setteridx=%d, flags=0x%04x", i, stridx, natidx_getter, natidx_setter, prop_flags); c_func_getter = duk_bi_native_functions[natidx_getter]; c_func_setter = duk_bi_native_functions[natidx_setter]; duk_push_c_function_noconstruct_nospecial(ctx, c_func_getter, 0); /* always 0 args */ duk_push_c_function_noconstruct_nospecial(ctx, c_func_setter, 1); /* always 1 arg */ /* FIXME: magic for getter/setter? */ prop_flags |= DUK_PROPDESC_FLAG_ACCESSOR; /* accessor flag not encoded explicitly */ duk_hobject_define_accessor_internal(thr, duk_require_hobject(ctx, i), DUK_HTHREAD_GET_STRING(thr, stridx), duk_require_hobject(ctx, -2), duk_require_hobject(ctx, -1), prop_flags); duk_pop_2(ctx); /* getter and setter, now reachable through object */ goto skip_value; } default: { /* exhaustive */ DUK_UNREACHABLE(); } } DUK_ASSERT((prop_flags & DUK_PROPDESC_FLAG_ACCESSOR) == 0); duk_def_prop_stridx(ctx, i, stridx, prop_flags); skip_value: continue; /* avoid empty label at the end of a compound statement */ } /* native function properties */ num = duk_bd_decode(bd, DUK__NUM_FUNC_PROPS_BITS); DUK_DDDPRINT("built-in object %d, %d function valued properties", i, num); for (j = 0; j < num; j++) { int stridx; int natidx; int c_nargs; int c_length; duk_int16_t magic; duk_c_function c_func; duk_hnativefunction *h_func; stridx = duk_bd_decode(bd, DUK__STRIDX_BITS); natidx = duk_bd_decode(bd, DUK__NATIDX_BITS); c_length = duk_bd_decode(bd, DUK__LENGTH_PROP_BITS); c_nargs = duk_bd_decode_flagged(bd, DUK__NARGS_BITS, (duk_int32_t) c_length /*def_value*/); if (c_nargs == DUK__NARGS_VARARGS_MARKER) { c_nargs = DUK_VARARGS; } c_func = duk_bi_native_functions[natidx]; DUK_DDDPRINT("built-in %d, function-valued property %d, stridx %d, natidx %d, length %d, nargs %d", i, j, stridx, natidx, c_length, (c_nargs == DUK_VARARGS ? -1 : c_nargs)); /* [ (builtin objects) ] */ duk_push_c_function_noconstruct_nospecial(ctx, c_func, c_nargs); h_func = duk_require_hnativefunction(ctx, -1); DUK_UNREF(h_func); /* Currently all built-in native functions are strict. * This doesn't matter for many functions, but e.g. * String.prototype.charAt (and other string functions) * rely on being strict so that their 'this' binding is * not automatically coerced. */ DUK_HOBJECT_SET_STRICT((duk_hobject *) h_func); /* No built-in functions are constructable except the top * level ones (Number, etc). */ DUK_ASSERT(!DUK_HOBJECT_HAS_CONSTRUCTABLE((duk_hobject *) h_func)); /* FIXME: any way to avoid decoding magic bit; there are quite * many function properties and relatively few with magic values. */ /* Cast converts magic to 16-bit signed value */ magic = (duk_int16_t) duk_bd_decode_flagged(bd, DUK__MAGIC_BITS, 0); h_func->magic = magic; /* [ (builtin objects) func ] */ duk_push_int(ctx, c_length); duk_def_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_NONE); duk_push_hstring_stridx(ctx, stridx); duk_def_prop_stridx(ctx, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_NONE); /* FIXME: other properties of function instances; 'arguments', 'caller'. */ DUK_DDPRINT("built-in object %d, function property %d -> %!T", i, j, duk_get_tval(ctx, -1)); /* [ (builtin objects) func ] */ /* * The default property attributes are correct for all * function valued properties of built-in objects now. */ duk_def_prop_stridx(ctx, i, stridx, DUK_PROPDESC_FLAGS_WC); /* [ (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. */ duk_get_prop_stridx(ctx, DUK_BIDX_DATE_PROTOTYPE, DUK_STRIDX_TO_UTC_STRING); duk_def_prop_stridx(ctx, DUK_BIDX_DATE_PROTOTYPE, DUK_STRIDX_TO_GMT_STRING, DUK_PROPDESC_FLAGS_WC); h = duk_require_hobject(ctx, DUK_BIDX_DOUBLE_ERROR); DUK_ASSERT(h != NULL); DUK_HOBJECT_CLEAR_EXTENSIBLE(h); duk_push_string(ctx, #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 #if defined(DUK_USE_BYTEORDER_FORCED) "f" #endif " " #if defined(DUK_USE_PACKED_TVAL) "p" #else "u" #endif " " #if defined(DUK_USE_HOBJECT_LAYOUT_1) "p1" #elif defined(DUK_USE_HOBJECT_LAYOUT_2) "p2" #elif defined(DUK_USE_HOBJECT_LAYOUT_3) "p3" #else "p?" #endif " " #if defined(DUK_USE_ALIGN_4) "a4" #elif defined(DUK_USE_ALIGN_8) "a8" #else "a1" #endif " " DUK_USE_ARCH_STRING); duk_def_prop_stridx(ctx, DUK_BIDX_DUKTAPE, DUK_STRIDX_ENV, DUK_PROPDESC_FLAGS_WC); /* * InitJS code - Ecmascript code evaluated from a built-in source * which provides e.g. backward compatibility. User can also provide * JS code to be evaluated at startup. */ #ifdef DUK_USE_INITJS /* FIXME: compression */ duk_eval_string(ctx, (const char *) duk_initjs_data); /* initjs data is NUL terminated */ duk_pop(ctx); #endif /* DUK_USE_INITJS */ #ifdef DUK_USE_USER_INITJS /* FIXME: compression, at least as an option? */ /* FIXME: unused now */ duk_eval_string(ctx, (const char *) DUK_USE_USER_INITJS); duk_pop(ctx); #endif /* DUK_USE_USER_INITJS */ /* * Since built-ins are not often extended, compact them. */ DUK_DDPRINT("compact built-ins"); for (i = 0; i < DUK_NUM_BUILTINS; i++) { duk_hobject_compact_props(thr, thr->builtins[i]); } DUK_DPRINT("INITBUILTINS END"); #ifdef DUK_USE_DDEBUG for (i = 0; i < DUK_NUM_BUILTINS; i++) { DUK_DDPRINT("built-in object %d after initialization and compacting: %!@iO", i, thr->builtins[i]); } #endif #ifdef DUK_USE_DDDEBUG for (i = 0; i < DUK_NUM_BUILTINS; i++) { DUK_DDDPRINT("built-in object %d after initialization and compacting", i); DUK_DEBUG_DUMP_HOBJECT(thr->builtins[i]); } #endif /* * Pop built-ins from stack: they are now INCREF'd and * reachable from the builtins[] array. */ duk_pop_n(ctx, DUK_NUM_BUILTINS); DUK_ASSERT_TOP(ctx, 0); }
/* Shared helper to implement ES2015 Object.setPrototypeOf, * Object.prototype.__proto__ setter, and Reflect.setPrototypeOf. * * http://www.ecma-international.org/ecma-262/6.0/index.html#sec-get-object.prototype.__proto__ * http://www.ecma-international.org/ecma-262/6.0/index.html#sec-object.setprototypeof */ DUK_INTERNAL duk_ret_t duk_bi_object_setprototype_shared(duk_hthread *thr) { /* * magic = 0: __proto__ setter * magic = 1: Object.setPrototypeOf() * magic = 2: Reflect.setPrototypeOf() */ duk_hobject *h_obj; duk_hobject *h_new_proto; duk_hobject *h_curr; duk_ret_t ret_success = 1; /* retval for success path */ duk_uint_t mask; duk_int_t magic; /* Preliminaries for __proto__ and setPrototypeOf (E6 19.1.2.18 steps 1-4). */ magic = duk_get_current_magic(thr); if (magic == 0) { duk_push_this_check_object_coercible(thr); duk_insert(thr, 0); if (!duk_check_type_mask(thr, 1, DUK_TYPE_MASK_NULL | DUK_TYPE_MASK_OBJECT)) { return 0; } /* __proto__ setter returns 'undefined' on success unlike the * setPrototypeOf() call which returns the target object. */ ret_success = 0; } else { if (magic == 1) { duk_require_object_coercible(thr, 0); } else { duk_require_hobject_accept_mask(thr, 0, DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER); } duk_require_type_mask(thr, 1, DUK_TYPE_MASK_NULL | DUK_TYPE_MASK_OBJECT); } h_new_proto = duk_get_hobject(thr, 1); /* h_new_proto may be NULL */ mask = duk_get_type_mask(thr, 0); if (mask & (DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER)) { duk_hobject *curr_proto; curr_proto = thr->builtins[(mask & DUK_TYPE_MASK_LIGHTFUNC) ? DUK_BIDX_FUNCTION_PROTOTYPE : DUK_BIDX_UINT8ARRAY_PROTOTYPE]; if (h_new_proto == curr_proto) { goto skip; } goto fail_nonextensible; } h_obj = duk_get_hobject(thr, 0); if (h_obj == NULL) { goto skip; } DUK_ASSERT(h_obj != NULL); /* [[SetPrototypeOf]] standard behavior, E6 9.1.2. */ /* TODO: implement Proxy object support here */ if (h_new_proto == DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h_obj)) { goto skip; } if (!DUK_HOBJECT_HAS_EXTENSIBLE(h_obj)) { goto fail_nonextensible; } for (h_curr = h_new_proto; h_curr != NULL; h_curr = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h_curr)) { /* Loop prevention. */ if (h_curr == h_obj) { goto fail_loop; } } DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, h_obj, h_new_proto); /* fall thru */ skip: duk_set_top(thr, 1); if (magic == 2) { duk_push_true(thr); } return ret_success; fail_nonextensible: fail_loop: if (magic != 2) { DUK_DCERROR_TYPE_INVALID_ARGS(thr); } else { duk_push_false(thr); return 1; } }
DUK_LOCAL void duk__print_hobject(duk__dprint_state *st, duk_hobject *h) { duk_fixedbuffer *fb = st->fb; duk_uint_fast32_t i; duk_tval *tv; duk_hstring *key; duk_bool_t first = 1; const char *brace1 = "{"; const char *brace2 = "}"; duk_bool_t pushed_loopstack = 0; if (duk_fb_is_full(fb)) { return; } duk__print_shared_heaphdr(st, &h->hdr); if (h && DUK_HOBJECT_HAS_ARRAY_PART(h)) { brace1 = "["; brace2 = "]"; } if (!h) { duk_fb_put_cstring(fb, "NULL"); goto finished; } if (st->depth >= st->depth_limit) { const char *subtype = "generic"; if (DUK_HOBJECT_IS_COMPFUNC(h)) { subtype = "compfunc"; } else if (DUK_HOBJECT_IS_NATFUNC(h)) { subtype = "natfunc"; } else if (DUK_HOBJECT_IS_THREAD(h)) { subtype = "thread"; } else if (DUK_HOBJECT_IS_BUFOBJ(h)) { subtype = "bufobj"; } else if (DUK_HOBJECT_IS_ARRAY(h)) { subtype = "array"; } duk_fb_sprintf(fb, "%sobject/%s %p%s", (const char *) brace1, subtype, (void *) h, (const char *) brace2); return; } for (i = 0; i < (duk_uint_fast32_t) st->loop_stack_index; i++) { if (st->loop_stack[i] == h) { duk_fb_sprintf(fb, "%sLOOP:%p%s", (const char *) brace1, (void *) h, (const char *) brace2); return; } } /* after this, return paths should 'goto finished' for decrement */ st->depth++; if (st->loop_stack_index >= st->loop_stack_limit) { duk_fb_sprintf(fb, "%sOUT-OF-LOOP-STACK%s", (const char *) brace1, (const char *) brace2); goto finished; } st->loop_stack[st->loop_stack_index++] = h; pushed_loopstack = 1; /* * Notation: double underscore used for internal properties which are not * stored in the property allocation (e.g. '__valstack'). */ duk_fb_put_cstring(fb, brace1); if (DUK_HOBJECT_GET_PROPS(NULL, h)) { duk_uint32_t a_limit; a_limit = DUK_HOBJECT_GET_ASIZE(h); if (st->internal) { /* dump all allocated entries, unused entries print as 'unused', * note that these may extend beyond current 'length' and look * a bit funny. */ } else { /* leave out trailing 'unused' elements */ while (a_limit > 0) { tv = DUK_HOBJECT_A_GET_VALUE_PTR(NULL, h, a_limit - 1); if (!DUK_TVAL_IS_UNUSED(tv)) { break; } a_limit--; } } for (i = 0; i < a_limit; i++) { tv = DUK_HOBJECT_A_GET_VALUE_PTR(NULL, h, i); DUK__COMMA(); duk__print_tval(st, tv); } for (i = 0; i < DUK_HOBJECT_GET_ENEXT(h); i++) { key = DUK_HOBJECT_E_GET_KEY(NULL, h, i); if (!key) { continue; } if (!st->internal && DUK_HSTRING_HAS_HIDDEN(key)) { continue; } DUK__COMMA(); duk__print_hstring(st, key, 0); duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_COLON); if (DUK_HOBJECT_E_SLOT_IS_ACCESSOR(NULL, h, i)) { duk_fb_sprintf(fb, "[get:%p,set:%p]", (void *) DUK_HOBJECT_E_GET_VALUE(NULL, h, i).a.get, (void *) DUK_HOBJECT_E_GET_VALUE(NULL, h, i).a.set); } else { tv = &DUK_HOBJECT_E_GET_VALUE(NULL, h, i).v; duk__print_tval(st, tv); } if (st->heavy) { duk_fb_sprintf(fb, "<%02lx>", (unsigned long) DUK_HOBJECT_E_GET_FLAGS(NULL, h, i)); } } } if (st->internal) { if (DUK_HOBJECT_HAS_EXTENSIBLE(h)) { DUK__COMMA(); duk_fb_sprintf(fb, "__extensible:true"); } if (DUK_HOBJECT_HAS_CONSTRUCTABLE(h)) { DUK__COMMA(); duk_fb_sprintf(fb, "__constructable:true"); } if (DUK_HOBJECT_HAS_BOUNDFUNC(h)) { DUK__COMMA(); duk_fb_sprintf(fb, "__boundfunc:true"); } if (DUK_HOBJECT_HAS_COMPFUNC(h)) { DUK__COMMA(); duk_fb_sprintf(fb, "__compfunc:true"); } if (DUK_HOBJECT_HAS_NATFUNC(h)) { DUK__COMMA(); duk_fb_sprintf(fb, "__natfunc:true"); } if (DUK_HOBJECT_HAS_BUFOBJ(h)) { DUK__COMMA(); duk_fb_sprintf(fb, "__bufobj:true"); } if (DUK_HOBJECT_HAS_THREAD(h)) { DUK__COMMA(); duk_fb_sprintf(fb, "__thread:true"); } if (DUK_HOBJECT_HAS_ARRAY_PART(h)) { DUK__COMMA(); duk_fb_sprintf(fb, "__array_part:true"); } if (DUK_HOBJECT_HAS_STRICT(h)) { DUK__COMMA(); duk_fb_sprintf(fb, "__strict:true"); } if (DUK_HOBJECT_HAS_NOTAIL(h)) { DUK__COMMA(); duk_fb_sprintf(fb, "__notail:true"); } if (DUK_HOBJECT_HAS_NEWENV(h)) { DUK__COMMA(); duk_fb_sprintf(fb, "__newenv:true"); } if (DUK_HOBJECT_HAS_NAMEBINDING(h)) { DUK__COMMA(); duk_fb_sprintf(fb, "__namebinding:true"); } if (DUK_HOBJECT_HAS_CREATEARGS(h)) { DUK__COMMA(); duk_fb_sprintf(fb, "__createargs:true"); } if (DUK_HOBJECT_HAS_ENVRECCLOSED(h)) { DUK__COMMA(); duk_fb_sprintf(fb, "__envrecclosed:true"); } if (DUK_HOBJECT_HAS_EXOTIC_ARRAY(h)) { DUK__COMMA(); duk_fb_sprintf(fb, "__exotic_array:true"); } if (DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ(h)) { DUK__COMMA(); duk_fb_sprintf(fb, "__exotic_stringobj:true"); } if (DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(h)) { DUK__COMMA(); duk_fb_sprintf(fb, "__exotic_arguments:true"); } if (DUK_HOBJECT_HAS_EXOTIC_DUKFUNC(h)) { DUK__COMMA(); duk_fb_sprintf(fb, "__exotic_dukfunc:true"); } if (DUK_HOBJECT_IS_BUFOBJ(h)) { DUK__COMMA(); duk_fb_sprintf(fb, "__exotic_bufobj:true"); } if (DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(h)) { DUK__COMMA(); duk_fb_sprintf(fb, "__exotic_proxyobj:true"); } } if (st->internal && DUK_HOBJECT_IS_ARRAY(h)) { duk_harray *a = (duk_harray *) h; DUK__COMMA(); duk_fb_sprintf(fb, "__length:%ld", (long) a->length); DUK__COMMA(); duk_fb_sprintf(fb, "__length_nonwritable:%ld", (long) a->length_nonwritable); } else if (st->internal && DUK_HOBJECT_IS_COMPFUNC(h)) { duk_hcompfunc *f = (duk_hcompfunc *) h; DUK__COMMA(); duk_fb_put_cstring(fb, "__data:"); duk__print_hbuffer(st, (duk_hbuffer *) DUK_HCOMPFUNC_GET_DATA(NULL, f)); DUK__COMMA(); duk_fb_put_cstring(fb, "__lexenv:"); duk__print_hobject(st, DUK_HCOMPFUNC_GET_LEXENV(NULL, f)); DUK__COMMA(); duk_fb_put_cstring(fb, "__varenv:"); duk__print_hobject(st, DUK_HCOMPFUNC_GET_VARENV(NULL, f)); DUK__COMMA(); duk_fb_sprintf(fb, "__nregs:%ld", (long) f->nregs); DUK__COMMA(); duk_fb_sprintf(fb, "__nargs:%ld", (long) f->nargs); #if defined(DUK_USE_DEBUGGER_SUPPORT) DUK__COMMA(); duk_fb_sprintf(fb, "__start_line:%ld", (long) f->start_line); DUK__COMMA(); duk_fb_sprintf(fb, "__end_line:%ld", (long) f->end_line); #endif DUK__COMMA(); duk_fb_put_cstring(fb, "__data:"); duk__print_hbuffer(st, (duk_hbuffer *) DUK_HCOMPFUNC_GET_DATA(NULL, f)); } else if (st->internal && DUK_HOBJECT_IS_NATFUNC(h)) { duk_hnatfunc *f = (duk_hnatfunc *) h; DUK__COMMA(); duk_fb_sprintf(fb, "__func:"); duk_fb_put_funcptr(fb, (duk_uint8_t *) &f->func, sizeof(f->func)); DUK__COMMA(); duk_fb_sprintf(fb, "__nargs:%ld", (long) f->nargs); DUK__COMMA(); duk_fb_sprintf(fb, "__magic:%ld", (long) f->magic); #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) } else if (st->internal && DUK_HOBJECT_IS_BUFOBJ(h)) { duk_hbufobj *b = (duk_hbufobj *) h; DUK__COMMA(); duk_fb_sprintf(fb, "__buf:"); duk__print_hbuffer(st, (duk_hbuffer *) b->buf); DUK__COMMA(); duk_fb_sprintf(fb, "__buf_prop:"); duk__print_hobject(st, (duk_hobject *) b->buf_prop); DUK__COMMA(); duk_fb_sprintf(fb, "__offset:%ld", (long) b->offset); DUK__COMMA(); duk_fb_sprintf(fb, "__length:%ld", (long) b->length); DUK__COMMA(); duk_fb_sprintf(fb, "__shift:%ld", (long) b->shift); DUK__COMMA(); duk_fb_sprintf(fb, "__elemtype:%ld", (long) b->elem_type); #endif } else if (st->internal && DUK_HOBJECT_IS_THREAD(h)) { duk_hthread *t = (duk_hthread *) h; DUK__COMMA(); duk_fb_sprintf(fb, "__strict:%ld", (long) t->strict); DUK__COMMA(); duk_fb_sprintf(fb, "__state:%ld", (long) t->state); DUK__COMMA(); duk_fb_sprintf(fb, "__unused1:%ld", (long) t->unused1); DUK__COMMA(); duk_fb_sprintf(fb, "__unused2:%ld", (long) t->unused2); DUK__COMMA(); duk_fb_sprintf(fb, "__valstack_max:%ld", (long) t->valstack_max); DUK__COMMA(); duk_fb_sprintf(fb, "__callstack_max:%ld", (long) t->callstack_max); DUK__COMMA(); duk_fb_sprintf(fb, "__catchstack_max:%ld", (long) t->catchstack_max); DUK__COMMA(); duk_fb_sprintf(fb, "__valstack:%p", (void *) t->valstack); DUK__COMMA(); duk_fb_sprintf(fb, "__valstack_end:%p/%ld", (void *) t->valstack_end, (long) (t->valstack_end - t->valstack)); DUK__COMMA(); duk_fb_sprintf(fb, "__valstack_bottom:%p/%ld", (void *) t->valstack_bottom, (long) (t->valstack_bottom - t->valstack)); DUK__COMMA(); duk_fb_sprintf(fb, "__valstack_top:%p/%ld", (void *) t->valstack_top, (long) (t->valstack_top - t->valstack)); DUK__COMMA(); duk_fb_sprintf(fb, "__catchstack:%p", (void *) t->catchstack); DUK__COMMA(); duk_fb_sprintf(fb, "__catchstack_size:%ld", (long) t->catchstack_size); DUK__COMMA(); duk_fb_sprintf(fb, "__catchstack_top:%ld", (long) t->catchstack_top); DUK__COMMA(); duk_fb_sprintf(fb, "__resumer:"); duk__print_hobject(st, (duk_hobject *) t->resumer); /* XXX: print built-ins array? */ } #if defined(DUK_USE_REFERENCE_COUNTING) if (st->internal) { DUK__COMMA(); duk_fb_sprintf(fb, "__refcount:%lu", (unsigned long) DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) h)); } #endif if (st->internal) { DUK__COMMA(); duk_fb_sprintf(fb, "__class:%ld", (long) DUK_HOBJECT_GET_CLASS_NUMBER(h)); } DUK__COMMA(); duk_fb_sprintf(fb, "__heapptr:%p", (void *) h); /* own pointer */ /* prototype should be last, for readability */ if (DUK_HOBJECT_GET_PROTOTYPE(NULL, h)) { if (st->follow_proto) { DUK__COMMA(); duk_fb_put_cstring(fb, "__prototype:"); duk__print_hobject(st, DUK_HOBJECT_GET_PROTOTYPE(NULL, h)); } else { DUK__COMMA(); duk_fb_sprintf(fb, "__prototype:%p", (void *) DUK_HOBJECT_GET_PROTOTYPE(NULL, h)); } } duk_fb_put_cstring(fb, brace2); #if defined(DUK_USE_HOBJECT_HASH_PART) if (st->heavy && DUK_HOBJECT_GET_HSIZE(h) > 0) { duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_LANGLE); for (i = 0; i < DUK_HOBJECT_GET_HSIZE(h); i++) { duk_uint_t h_idx = DUK_HOBJECT_H_GET_INDEX(NULL, h, i); if (i > 0) { duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_COMMA); } if (h_idx == DUK_HOBJECT_HASHIDX_UNUSED) { duk_fb_sprintf(fb, "u"); } else if (h_idx == DUK_HOBJECT_HASHIDX_DELETED) { duk_fb_sprintf(fb, "d"); } else { duk_fb_sprintf(fb, "%ld", (long) h_idx); } } duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_RANGLE); } #endif finished: st->depth--; if (pushed_loopstack) { st->loop_stack_index--; st->loop_stack[st->loop_stack_index] = NULL; } }