int duk_builtin_number_prototype_to_exponential(duk_context *ctx) { int frac_undefined; int frac_digits; double d; int c; int n2s_flags; d = push_this_number_plain(ctx); frac_undefined = duk_is_undefined(ctx, 0); duk_to_int(ctx, 0); /* for side effects */ c = DUK_FPCLASSIFY(d); if (c == DUK_FP_NAN || c == DUK_FP_INFINITE) { goto use_to_string; } frac_digits = duk_to_int_check_range(ctx, 0, 0, 20); n2s_flags = DUK_N2S_FLAG_FORCE_EXP | (frac_undefined ? 0 : DUK_N2S_FLAG_FIXED_FORMAT); duk_numconv_stringify(ctx, 10 /*radix*/, frac_digits + 1 /*leading digit + fractions*/, n2s_flags /*flags*/); return 1; use_to_string: DUK_ASSERT_TOP(ctx, 2); duk_to_string(ctx, -1); return 1; }
DUK_INTERNAL duk_ret_t duk_bi_object_constructor_create(duk_hthread *thr) { duk_hobject *proto; DUK_ASSERT_TOP(thr, 2); #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) duk_hbufobj_promote_plain(thr, 0); #endif proto = duk_require_hobject_accept_mask(thr, 0, DUK_TYPE_MASK_NULL); DUK_ASSERT(proto != NULL || duk_is_null(thr, 0)); (void) duk_push_object_helper_proto(thr, DUK_HOBJECT_FLAG_EXTENSIBLE | DUK_HOBJECT_FLAG_FASTREFS | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT), proto); if (!duk_is_undefined(thr, 1)) { /* [ O Properties obj ] */ duk_replace(thr, 0); /* [ obj Properties ] */ /* Just call the "original" Object.defineProperties() to * finish up. */ return duk_bi_object_constructor_define_properties(thr); } /* [ O Properties obj ] */ return 1; }
duk_ret_t duk_bi_number_prototype_to_fixed(duk_context *ctx) { duk_small_int_t frac_digits; duk_double_t d; duk_small_int_t c; duk_small_uint_t n2s_flags; frac_digits = (duk_small_int_t) duk_to_int_check_range(ctx, 0, 0, 20); d = duk__push_this_number_plain(ctx); c = (duk_small_int_t) DUK_FPCLASSIFY(d); if (c == DUK_FP_NAN || c == DUK_FP_INFINITE) { goto use_to_string; } if (d >= 1.0e21 || d <= -1.0e21) { goto use_to_string; } n2s_flags = DUK_N2S_FLAG_FIXED_FORMAT | DUK_N2S_FLAG_FRACTION_DIGITS; duk_numconv_stringify(ctx, 10 /*radix*/, frac_digits /*digits*/, n2s_flags /*flags*/); return 1; use_to_string: DUK_ASSERT_TOP(ctx, 2); duk_to_string(ctx, -1); return 1; }
DUK_LOCAL duk_ret_t duk__error_setter_helper(duk_context *ctx, duk_small_uint_t stridx_key) { /* Attempt to write 'stack', 'fileName', 'lineNumber' works as if * user code called Object.defineProperty() to create an overriding * own property. This allows user code to overwrite .fileName etc * intuitively as e.g. "err.fileName = 'dummy'" as one might expect. * See https://github.com/svaarala/duktape/issues/387. */ DUK_ASSERT_TOP(ctx, 1); /* fixed arg count: value */ duk_push_this(ctx); duk_push_hstring_stridx(ctx, (duk_small_int_t) stridx_key); duk_dup_0(ctx); /* [ ... obj key value ] */ DUK_DD(DUK_DDPRINT("error setter: %!T %!T %!T", duk_get_tval(ctx, -3), duk_get_tval(ctx, -2), duk_get_tval(ctx, -1))); duk_def_prop(ctx, -3, DUK_DEFPROP_HAVE_VALUE | DUK_DEFPROP_HAVE_WRITABLE | DUK_DEFPROP_WRITABLE | DUK_DEFPROP_HAVE_ENUMERABLE | /*not enumerable*/ DUK_DEFPROP_HAVE_CONFIGURABLE | DUK_DEFPROP_CONFIGURABLE); return 0; }
int duk_bi_error_prototype_nop_setter(duk_context *ctx) { /* Attempt to write 'stack', 'fileName', 'lineNumber' is a silent no-op. * User can use Object.defineProperty() to override this behavior. */ DUK_ASSERT_TOP(ctx, 1); /* fixed arg count */ DUK_UNREF(ctx); return 0; }
DUK_INTERNAL duk_ret_t duk_bi_array_prototype_reverse(duk_context *ctx) { duk_uint32_t len; duk_uint32_t middle; duk_uint32_t lower, upper; duk_bool_t have_lower, have_upper; len = duk__push_this_obj_len_u32(ctx); middle = len / 2; /* If len <= 1, middle will be 0 and for-loop bails out * immediately (0 < 0 -> false). */ for (lower = 0; lower < middle; lower++) { DUK_ASSERT(len >= 2); DUK_ASSERT_TOP(ctx, 2); DUK_ASSERT(len >= lower + 1); upper = len - lower - 1; have_lower = duk_get_prop_index(ctx, -2, (duk_uarridx_t) lower); have_upper = duk_get_prop_index(ctx, -3, (duk_uarridx_t) upper); /* [ ToObject(this) ToUint32(length) lowerValue upperValue ] */ if (have_upper) { duk_put_prop_index(ctx, -4, (duk_uarridx_t) lower); } else { duk_del_prop_index(ctx, -4, (duk_uarridx_t) lower); duk_pop(ctx); } if (have_lower) { duk_put_prop_index(ctx, -3, (duk_uarridx_t) upper); } else { duk_del_prop_index(ctx, -3, (duk_uarridx_t) upper); duk_pop(ctx); } DUK_ASSERT_TOP(ctx, 2); } DUK_ASSERT_TOP(ctx, 2); duk_pop(ctx); /* -> [ ToObject(this) ] */ return 1; }
DUK_INTERNAL duk_ret_t duk_bi_duktape_object_enc(duk_context *ctx) { duk_hthread *thr = (duk_hthread *) ctx; duk_hstring *h_str; DUK_UNREF(thr); /* Vararg function: must be careful to check/require arguments. * The JSON helpers accept invalid indices and treat them like * non-existent optional parameters. */ h_str = duk_require_hstring(ctx, 0); duk_require_valid_index(ctx, 1); if (h_str == DUK_HTHREAD_STRING_HEX(thr)) { duk_set_top(ctx, 2); duk_hex_encode(ctx, 1); DUK_ASSERT_TOP(ctx, 2); } else if (h_str == DUK_HTHREAD_STRING_BASE64(thr)) { duk_set_top(ctx, 2); duk_base64_encode(ctx, 1); DUK_ASSERT_TOP(ctx, 2); #ifdef DUK_USE_JX } else if (h_str == DUK_HTHREAD_STRING_JX(thr)) { duk_bi_json_stringify_helper(ctx, 1 /*idx_value*/, 2 /*idx_replacer*/, 3 /*idx_space*/, DUK_JSON_FLAG_EXT_CUSTOM | DUK_JSON_FLAG_ASCII_ONLY | DUK_JSON_FLAG_AVOID_KEY_QUOTES /*flags*/); #endif #ifdef DUK_USE_JC } else if (h_str == DUK_HTHREAD_STRING_JC(thr)) { duk_bi_json_stringify_helper(ctx, 1 /*idx_value*/, 2 /*idx_replacer*/, 3 /*idx_space*/, DUK_JSON_FLAG_EXT_COMPATIBLE | DUK_JSON_FLAG_ASCII_ONLY /*flags*/); #endif } else { return DUK_RET_TYPE_ERROR; } return 1; }
duk_ret_t duk_bi_number_prototype_to_precision(duk_context *ctx) { /* The specification has quite awkward order of coercion and * checks for toPrecision(). The operations below are a bit * reordered, within constraints of observable side effects. */ duk_double_t d; duk_small_int_t prec; duk_small_int_t c; duk_small_uint_t n2s_flags; DUK_ASSERT_TOP(ctx, 1); d = duk__push_this_number_plain(ctx); if (duk_is_undefined(ctx, 0)) { goto use_to_string; } DUK_ASSERT_TOP(ctx, 2); duk_to_int(ctx, 0); /* for side effects */ c = (duk_small_int_t) DUK_FPCLASSIFY(d); if (c == DUK_FP_NAN || c == DUK_FP_INFINITE) { goto use_to_string; } prec = (duk_small_int_t) duk_to_int_check_range(ctx, 0, 1, 21); n2s_flags = DUK_N2S_FLAG_FIXED_FORMAT | DUK_N2S_FLAG_NO_ZERO_PAD; duk_numconv_stringify(ctx, 10 /*radix*/, prec /*digits*/, n2s_flags /*flags*/); return 1; use_to_string: /* Used when precision is undefined; also used for NaN (-> "NaN"), * and +/- infinity (-> "Infinity", "-Infinity"). */ DUK_ASSERT_TOP(ctx, 2); duk_to_string(ctx, -1); return 1; }
int duk_builtin_duk_object_dec(duk_context *ctx) { duk_hthread *thr = (duk_hthread *) ctx; duk_hstring *h_str; h_str = duk_to_hstring(ctx, 0); if (h_str == DUK_HTHREAD_STRING_HEX(thr)) { duk_hex_decode(ctx, 1); DUK_ASSERT_TOP(ctx, 2); return 1; } else if (h_str == DUK_HTHREAD_STRING_BASE64(thr)) { duk_base64_decode(ctx, 1); DUK_ASSERT_TOP(ctx, 2); return 1; } else { return DUK_RET_TYPE_ERROR; } }
void duk_hobject_run_finalizer(duk_hthread *thr, duk_hobject *obj) { duk_context *ctx = (duk_context *) thr; int rc; #ifdef DUK_USE_ASSERTIONS int entry_top; #endif DUK_DDDPRINT("running object finalizer for object: %p", (void *) obj); DUK_ASSERT(thr != NULL); DUK_ASSERT(ctx != NULL); DUK_ASSERT(obj != NULL); /* FIXME: assert stack space */ #ifdef DUK_USE_ASSERTIONS entry_top = duk_get_top(ctx); #endif /* * Get and call the finalizer. All of this must be wrapped * in a protected call, because even getting the finalizer * may trigger an error (getter may throw one, for instance). */ /* FIXME: use a NULL error handler for the finalizer call? */ DUK_DDDPRINT("-> finalizer found, calling wrapped finalize helper"); duk_push_hobject(ctx, obj); /* this also increases refcount by one */ rc = duk_safe_call(ctx, _finalize_helper, 0 /*nargs*/, 1 /*nrets*/, DUK_INVALID_INDEX); /* -> [... obj retval/error] */ DUK_ASSERT_TOP(ctx, entry_top + 2); /* duk_safe_call discipline */ if (rc != DUK_ERR_EXEC_SUCCESS) { /* Note: we ask for one return value from duk_safe_call to get this * error debugging here. */ DUK_DPRINT("wrapped finalizer call failed for object %p (ignored); error: %!T", (void *) obj, duk_get_tval(ctx, -1)); } duk_pop_2(ctx); /* -> [...] */ DUK_ASSERT_TOP(ctx, entry_top); }
DUK_INTERNAL duk_ret_t duk_bi_regexp_prototype_tostring(duk_hthread *thr) { /* This must be generic in ES2015 and later. */ DUK_ASSERT_TOP(thr, 0); duk_push_this(thr); duk_push_literal(thr, "/"); duk_get_prop_stridx(thr, 0, DUK_STRIDX_SOURCE); duk_dup_m2(thr); /* another "/" */ duk_get_prop_stridx(thr, 0, DUK_STRIDX_FLAGS); duk_concat(thr, 4); return 1; }
DUK_INTERNAL duk_ret_t duk_bi_object_constructor_seal_freeze_shared(duk_context *ctx) { duk_hthread *thr = (duk_hthread *) ctx; duk_hobject *h; duk_bool_t is_freeze; DUK_ASSERT_TOP(ctx, 1); is_freeze = (duk_bool_t) duk_get_current_magic(ctx); if (duk_is_buffer(ctx, 0)) { /* Plain buffer: already sealed, but not frozen (and can't be frozen * because index properties can't be made non-writable. */ if (is_freeze) { goto fail_cannot_freeze; } return 1; } else if (duk_is_lightfunc(ctx, 0)) { /* Lightfunc: already sealed and frozen, success. */ return 1; } #if 0 /* Seal/freeze are quite rare in practice so it'd be nice to get the * correct behavior simply via automatic promotion (at the cost of some * memory churn). However, the promoted objects don't behave the same, * e.g. promoted lightfuncs are extensible. */ h = duk_require_hobject_promote_mask(ctx, 0, DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER); #endif h = duk_get_hobject(ctx, 0); if (h == NULL) { /* ES2015 Sections 19.1.2.5, 19.1.2.17 */ return 1; } if (is_freeze && DUK_HOBJECT_IS_BUFOBJ(h)) { /* Buffer objects cannot be frozen because there's no internal * support for making virtual array indices non-writable. */ DUK_DD(DUK_DDPRINT("cannot freeze a buffer object")); goto fail_cannot_freeze; } duk_hobject_object_seal_freeze_helper(thr, h, is_freeze); /* Sealed and frozen objects cannot gain any more properties, * so this is a good time to compact them. */ duk_hobject_compact_props(thr, h); return 1; fail_cannot_freeze: DUK_DCERROR_TYPE_INVALID_ARGS(thr); /* XXX: proper error message */ }
DUK_INTERNAL duk_ret_t duk_bi_object_prototype_to_locale_string(duk_context *ctx) { DUK_ASSERT_TOP(ctx, 0); (void) duk_push_this_coercible_to_object(ctx); duk_get_prop_stridx(ctx, 0, DUK_STRIDX_TO_STRING); if (!duk_is_callable(ctx, 1)) { return DUK_RET_TYPE_ERROR; } duk_dup(ctx, 0); /* -> [ O toString O ] */ duk_call_method(ctx, 0); /* XXX: call method tailcall? */ return 1; }
DUK_INTERNAL duk_ret_t duk_bi_object_prototype_to_locale_string(duk_hthread *thr) { DUK_ASSERT_TOP(thr, 0); (void) duk_push_this_coercible_to_object(thr); duk_get_prop_stridx_short(thr, 0, DUK_STRIDX_TO_STRING); #if 0 /* This is mentioned explicitly in the E5.1 spec, but duk_call_method() checks for it in practice. */ duk_require_callable(thr, 1); #endif duk_dup_0(thr); /* -> [ O toString O ] */ duk_call_method(thr, 0); /* XXX: call method tail call? */ return 1; }
DUK_INTERNAL duk_ret_t duk_bi_proxy_constructor(duk_context *ctx) { duk_hobject *h_target; duk_hobject *h_handler; if (!duk_is_constructor_call(ctx)) { return DUK_RET_TYPE_ERROR; } /* Reject a proxy object as the target because it would need * special handler in property lookups. (ES6 has no such restriction) */ h_target = duk_require_hobject_or_lfunc_coerce(ctx, 0); DUK_ASSERT(h_target != NULL); if (DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(h_target)) { return DUK_RET_TYPE_ERROR; } /* Reject a proxy object as the handler because it would cause * potentially unbounded recursion. (ES6 has no such restriction) */ h_handler = duk_require_hobject_or_lfunc_coerce(ctx, 1); DUK_ASSERT(h_handler != NULL); if (DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(h_handler)) { return DUK_RET_TYPE_ERROR; } /* XXX: the returned value is exotic in ES6, but we use a * simple object here with no prototype. Without a prototype, * [[DefaultValue]] coercion fails which is abit confusing. * No callable check/handling in the current Proxy subset. */ (void) duk_push_object_helper_proto(ctx, DUK_HOBJECT_FLAG_EXTENSIBLE | DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT), NULL); DUK_ASSERT_TOP(ctx, 3); /* Make _Target and _Handler non-configurable and non-writable. * They can still be forcibly changed by C code (both user and * Duktape internal), but not by Ecmascript code. */ /* Proxy target */ duk_dup(ctx, 0); duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_TARGET, DUK_PROPDESC_FLAGS_NONE); /* Proxy handler */ duk_dup(ctx, 1); duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_HANDLER, DUK_PROPDESC_FLAGS_NONE); return 1; /* replacement handler */ }
int duk_bi_array_prototype_reverse(duk_context *ctx) { unsigned int len; unsigned int middle; unsigned int lower, upper; int have_lower, have_upper; len = duk__push_this_obj_len_u32(ctx); middle = len / 2; for (lower = 0; lower < middle; lower++) { DUK_ASSERT_TOP(ctx, 2); upper = len - lower - 1; have_lower = duk_get_prop_index(ctx, -2, lower); have_upper = duk_get_prop_index(ctx, -3, upper); /* [ ToObject(this) ToUint32(length) lowerValue upperValue ] */ if (have_upper) { duk_put_prop_index(ctx, -4, lower); /* FIXME: Throw */ } else { duk_del_prop_index(ctx, -4, lower); duk_pop(ctx); } if (have_lower) { duk_put_prop_index(ctx, -3, upper); } else { duk_del_prop_index(ctx, -3, upper); duk_pop(ctx); } DUK_ASSERT_TOP(ctx, 2); } DUK_ASSERT_TOP(ctx, 2); duk_pop(ctx); /* -> [ ToObject(this) ] */ return 1; }
duk_ret_t duk_bi_duk_object_dec(duk_context *ctx) { duk_hthread *thr = (duk_hthread *) ctx; duk_hstring *h_str; /* Vararg function: must be careful to check/require arguments. * The JSON helpers accept invalid indices and treat them like * non-existent optional parameters. */ h_str = duk_require_hstring(ctx, 0); duk_require_valid_index(ctx, 1); if (h_str == DUK_HTHREAD_STRING_HEX(thr)) { duk_set_top(ctx, 2); duk_hex_decode(ctx, 1); DUK_ASSERT_TOP(ctx, 2); } else if (h_str == DUK_HTHREAD_STRING_BASE64(thr)) { duk_set_top(ctx, 2); duk_base64_decode(ctx, 1); DUK_ASSERT_TOP(ctx, 2); #ifdef DUK_USE_JSONX } else if (h_str == DUK_HTHREAD_STRING_JSONX(thr)) { duk_bi_json_parse_helper(ctx, 1 /*idx_value*/, 2 /*idx_replacer*/, DUK_JSON_FLAG_EXT_CUSTOM /*flags*/); #endif #ifdef DUK_USE_JSONC } else if (h_str == DUK_HTHREAD_STRING_JSONC(thr)) { duk_bi_json_parse_helper(ctx, 1 /*idx_value*/, 2 /*idx_replacer*/, DUK_JSON_FLAG_EXT_COMPATIBLE /*flags*/); #endif } else { return DUK_RET_TYPE_ERROR; } return 1; }
DUK_INTERNAL duk_ret_t duk_bi_object_constructor_get_own_property_descriptor(duk_hthread *thr) { DUK_ASSERT_TOP(thr, 2); /* ES2015 Section 19.1.2.6, step 1 */ if (duk_get_current_magic(thr) == 0) { duk_to_object(thr, 0); } /* [ obj key ] */ duk_hobject_object_get_own_property_descriptor(thr, -2); 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 */ }
/* Shared helper to implement Object.getPrototypeOf, * Object.prototype.__proto__ getter, and Reflect.getPrototypeOf. * * http://www.ecma-international.org/ecma-262/6.0/index.html#sec-get-object.prototype.__proto__ */ DUK_INTERNAL duk_ret_t duk_bi_object_getprototype_shared(duk_context *ctx) { /* * magic = 0: __proto__ getter * magic = 1: Object.getPrototypeOf() * magic = 2: Reflect.getPrototypeOf() */ duk_hthread *thr = (duk_hthread *) ctx; duk_hobject *h; duk_hobject *proto; duk_tval *tv; duk_int_t magic; magic = duk_get_current_magic(ctx); if (magic == 0) { DUK_ASSERT_TOP(ctx, 0); duk_push_this_coercible_to_object(ctx); } DUK_ASSERT(duk_get_top(ctx) >= 1); if (magic < 2) { /* ES2015 Section 19.1.2.9, step 1 */ duk_to_object(ctx, 0); } tv = DUK_GET_TVAL_POSIDX(ctx, 0); switch (DUK_TVAL_GET_TAG(tv)) { case DUK_TAG_BUFFER: proto = thr->builtins[DUK_BIDX_UINT8ARRAY_PROTOTYPE]; break; case DUK_TAG_LIGHTFUNC: proto = thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]; break; case DUK_TAG_OBJECT: h = DUK_TVAL_GET_OBJECT(tv); proto = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h); break; default: /* This implicitly handles CheckObjectCoercible() caused * TypeError. */ DUK_DCERROR_TYPE_INVALID_ARGS(thr); } if (proto != NULL) { duk_push_hobject(ctx, proto); } else { duk_push_null(ctx); } return 1; }
DUK_INTERNAL duk_ret_t duk_bi_array_prototype_shift(duk_context *ctx) { duk_uint32_t len; duk_uint32_t i; len = duk__push_this_obj_len_u32(ctx); if (len == 0) { duk_push_int(ctx, 0); duk_put_prop_stridx(ctx, 0, DUK_STRIDX_LENGTH); return 0; } duk_get_prop_index(ctx, 0, 0); /* stack[0] = object (this) * stack[1] = ToUint32(length) * stack[2] = elem at index 0 (retval) */ for (i = 1; i < len; i++) { DUK_ASSERT_TOP(ctx, 3); if (duk_get_prop_index(ctx, 0, (duk_uarridx_t) i)) { /* fromPresent = true */ duk_put_prop_index(ctx, 0, (duk_uarridx_t) (i - 1)); } else { /* fromPresent = false */ duk_del_prop_index(ctx, 0, (duk_uarridx_t) (i - 1)); duk_pop(ctx); } } duk_del_prop_index(ctx, 0, (duk_uarridx_t) (len - 1)); duk_push_u32(ctx, (duk_uint32_t) (len - 1)); duk_put_prop_stridx(ctx, 0, DUK_STRIDX_LENGTH); DUK_ASSERT_TOP(ctx, 3); return 1; }
int duk_bi_array_prototype_shift(duk_context *ctx) { unsigned int len; unsigned int i; len = duk__push_this_obj_len_u32(ctx); if (len == 0) { duk_push_int(ctx, 0); duk_put_prop_stridx(ctx, 0, DUK_STRIDX_LENGTH); /* FIXME: Throw */ return 0; } duk_get_prop_index(ctx, 0, 0); /* stack[0] = object (this) * stack[1] = ToUint32(length) * stack[2] = elem at index 0 (retval) */ for (i = 1; i < len; i++) { DUK_ASSERT_TOP(ctx, 3); if (duk_get_prop_index(ctx, 0, i)) { /* fromPresent = true */ duk_put_prop_index(ctx, 0, i - 1); /* FIXME: Throw */ } else { /* fromPresent = false */ duk_del_prop_index(ctx, 0, i - 1); duk_pop(ctx); } } duk_del_prop_index(ctx, 0, len - 1); /* FIXME: Throw */ duk_push_number(ctx, (double) (len - 1)); /* FIXME: push uint */ duk_put_prop_stridx(ctx, 0, DUK_STRIDX_LENGTH); DUK_ASSERT_TOP(ctx, 3); return 1; }
DUK_INTERNAL duk_ret_t duk_bi_array_prototype_unshift(duk_context *ctx) { duk_idx_t nargs; duk_uint32_t len; duk_uint32_t i; nargs = duk_get_top(ctx); len = duk__push_this_obj_len_u32(ctx); /* stack[0...nargs-1] = unshift args (vararg) * stack[nargs] = ToObject(this) * stack[nargs+1] = ToUint32(length) */ DUK_ASSERT_TOP(ctx, nargs + 2); /* Note: unshift() may operate on indices above unsigned 32-bit range * and the final length may be >= 2**32. However, we restrict the * final result to 32-bit range for practicality. */ if (len + (duk_uint32_t) nargs < len) { DUK_D(DUK_DPRINT("Array.prototype.unshift() would go beyond 32-bit length, throw")); return DUK_RET_RANGE_ERROR; } i = len; while (i > 0) { DUK_ASSERT_TOP(ctx, nargs + 2); i--; /* k+argCount-1; note that may be above 32-bit range */ if (duk_get_prop_index(ctx, -2, (duk_uarridx_t) i)) { /* fromPresent = true */ /* [ ... ToObject(this) ToUint32(length) val ] */ duk_put_prop_index(ctx, -3, (duk_uarridx_t) (i + nargs)); /* -> [ ... ToObject(this) ToUint32(length) ] */ } else { /* fromPresent = false */ /* [ ... ToObject(this) ToUint32(length) val ] */ duk_pop(ctx); duk_del_prop_index(ctx, -2, (duk_uarridx_t) (i + nargs)); /* -> [ ... ToObject(this) ToUint32(length) ] */ } DUK_ASSERT_TOP(ctx, nargs + 2); } for (i = 0; i < (duk_uint32_t) nargs; i++) { DUK_ASSERT_TOP(ctx, nargs + 2); duk_dup(ctx, i); /* -> [ ... ToObject(this) ToUint32(length) arg[i] ] */ duk_put_prop_index(ctx, -3, (duk_uarridx_t) i); DUK_ASSERT_TOP(ctx, nargs + 2); } DUK_ASSERT_TOP(ctx, nargs + 2); duk_push_u32(ctx, len + nargs); duk_dup_top(ctx); /* -> [ ... ToObject(this) ToUint32(length) final_len final_len ] */ duk_put_prop_stridx(ctx, -4, DUK_STRIDX_LENGTH); return 1; }
int duk_bi_array_prototype_sort(duk_context *ctx) { unsigned int len; len = duk__push_this_obj_len_u32(ctx); /* stack[0] = compareFn * stack[1] = ToObject(this) * stack[2] = ToUint32(length) */ duk__array_qsort(ctx, 0, len - 1); DUK_ASSERT_TOP(ctx, 3); duk_pop(ctx); return 1; /* return ToObject(this) */ }
int duk_builtin_object_constructor_create(duk_context *ctx) { duk_hthread *thr = (duk_hthread *) ctx; duk_tval *tv; duk_hobject *proto = NULL; duk_hobject *h; DUK_ASSERT_TOP(ctx, 2); tv = duk_get_tval(ctx, 0); DUK_ASSERT(tv != NULL); if (DUK_TVAL_IS_NULL(tv)) { ; } else if (DUK_TVAL_IS_OBJECT(tv)) { proto = DUK_TVAL_GET_OBJECT(tv); DUK_ASSERT(proto != NULL); } else { return DUK_RET_TYPE_ERROR; } /* FIXME: direct helper to create with specific prototype */ (void) duk_push_object_helper(ctx, DUK_HOBJECT_FLAG_EXTENSIBLE | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT), -1); h = duk_get_hobject(ctx, -1); DUK_ASSERT(h != NULL); DUK_ASSERT(h->prototype == NULL); DUK_HOBJECT_SET_PROTOTYPE(thr, h, proto); if (!duk_is_undefined(ctx, 1)) { /* [ O Properties obj ] */ /* Use original function. No need to get it explicitly, * just call the helper. */ duk_replace(ctx, 0); /* [ obj Properties ] */ return duk_hobject_object_define_properties(ctx); } /* [ O Properties obj ] */ return 1; }
int duk_bi_array_prototype_unshift(duk_context *ctx) { unsigned int nargs; unsigned int len; unsigned int i; double final_len; /* FIXME: duk_get_top return type */ nargs = (unsigned int) duk_get_top(ctx); len = duk__push_this_obj_len_u32(ctx); /* stack[0...nargs-1] = unshift args (vararg) * stack[nargs] = ToObject(this) * stack[nargs+1] = ToUint32(length) */ DUK_ASSERT_TOP(ctx, nargs + 2); /* Note: unshift() may operate on indices above unsigned 32-bit range * and the final length may be >= 2**32. Hence we use 'double' vars * here, when appropriate. */ i = len; while (i > 0) { DUK_ASSERT_TOP(ctx, nargs + 2); i--; duk_push_number(ctx, ((double) i) + ((double) nargs)); /* k+argCount-1; note that may be above 32-bit range */ if (duk_get_prop_index(ctx, -3, i)) { /* fromPresent = true */ /* [ ... ToObject(this) ToUint32(length) to val ] */ duk_put_prop(ctx, -4); /* -> [ ... ToObject(this) ToUint32(length) ] */ /* FIXME: Throw */ } else { /* fromPresent = false */ /* [ ... ToObject(this) ToUint32(length) to val ] */ duk_pop(ctx); duk_del_prop(ctx, -3); /* -> [ ... ToObject(this) ToUint32(length) ] */ /* FIXME: Throw */ } DUK_ASSERT_TOP(ctx, nargs + 2); } for (i = 0; i < nargs; i++) { DUK_ASSERT_TOP(ctx, nargs + 2); duk_dup(ctx, i); /* -> [ ... ToObject(this) ToUint32(length) arg[i] ] */ duk_put_prop_index(ctx, -3, i); /* FIXME: Throw */ DUK_ASSERT_TOP(ctx, nargs + 2); } DUK_ASSERT_TOP(ctx, nargs + 2); final_len = ((double) len) + ((double) nargs); duk_push_number(ctx, final_len); duk_dup_top(ctx); /* -> [ ... ToObject(this) ToUint32(length) final_len final_len ] */ duk_put_prop_stridx(ctx, -4, DUK_STRIDX_LENGTH); /* FIXME: Throw */ return 1; }
DUK_INTERNAL duk_ret_t duk_bi_array_prototype_pop(duk_context *ctx) { duk_uint32_t len; duk_uint32_t idx; DUK_ASSERT_TOP(ctx, 0); len = duk__push_this_obj_len_u32(ctx); if (len == 0) { duk_push_int(ctx, 0); duk_put_prop_stridx(ctx, 0, DUK_STRIDX_LENGTH); return 0; } idx = len - 1; duk_get_prop_index(ctx, 0, (duk_uarridx_t) idx); duk_del_prop_index(ctx, 0, (duk_uarridx_t) idx); duk_push_u32(ctx, idx); duk_put_prop_stridx(ctx, 0, DUK_STRIDX_LENGTH); return 1; }
int duk_bi_array_prototype_pop(duk_context *ctx) { unsigned int len; unsigned int idx; DUK_ASSERT_TOP(ctx, 0); len = duk__push_this_obj_len_u32(ctx); if (len == 0) { duk_push_int(ctx, 0); duk_put_prop_stridx(ctx, 0, DUK_STRIDX_LENGTH); /* FIXME: Throw */ return 0; } idx = len - 1; duk_get_prop_index(ctx, 0, idx); duk_del_prop_index(ctx, 0, idx); /* FIXME: Throw */ duk_push_int(ctx, idx); /* FIXME: unsigned */ duk_put_prop_stridx(ctx, 0, DUK_STRIDX_LENGTH); /* FIXME: Throw */ return 1; }
duk_ret_t duk_bi_object_prototype_is_prototype_of(duk_context *ctx) { duk_hthread *thr = (duk_hthread *) ctx; duk_hobject *h_v; duk_hobject *h_obj; DUK_ASSERT_TOP(ctx, 1); h_v = duk_get_hobject(ctx, 0); if (!h_v) { duk_push_false(ctx); /* XXX: tail call: return duk_push_false(ctx) */ return 1; } h_obj = duk_push_this_coercible_to_object(ctx); DUK_ASSERT(h_obj != NULL); /* E5.1 Section 15.2.4.6, step 3.a, lookup proto once before compare */ duk_push_boolean(ctx, duk_hobject_prototype_chain_contains(thr, h_v->prototype, h_obj)); return 1; }
DUK_INTERNAL duk_ret_t duk_bi_object_prototype_is_prototype_of(duk_hthread *thr) { duk_hobject *h_v; duk_hobject *h_obj; DUK_ASSERT_TOP(thr, 1); h_v = duk_get_hobject(thr, 0); if (!h_v) { duk_push_false(thr); /* XXX: tail call: return duk_push_false(thr) */ return 1; } h_obj = duk_push_this_coercible_to_object(thr); DUK_ASSERT(h_obj != NULL); /* E5.1 Section 15.2.4.6, step 3.a, lookup proto once before compare. * Prototype loops should cause an error to be thrown. */ duk_push_boolean(thr, duk_hobject_prototype_chain_contains(thr, DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h_v), h_obj, 0 /*ignore_loop*/)); return 1; }