int duk_bi_buffer_prototype_tostring_shared(duk_context *ctx) { duk_tval *tv; int to_string = duk_get_magic(ctx); duk_push_this(ctx); tv = duk_require_tval(ctx, -1); DUK_ASSERT(tv != NULL); if (DUK_TVAL_IS_BUFFER(tv)) { /* nop */ } else if (DUK_TVAL_IS_OBJECT(tv)) { duk_hobject *h = DUK_TVAL_GET_OBJECT(tv); DUK_ASSERT(h != NULL); /* Must be a "buffer object", i.e. class "Buffer" */ if (DUK_HOBJECT_GET_CLASS_NUMBER(h) != DUK_HOBJECT_CLASS_BUFFER) { goto type_error; } duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_VALUE); } else { goto type_error; } if (to_string) { duk_to_string(ctx, -1); } return 1; type_error: return DUK_RET_TYPE_ERROR; }
/* 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; int ret_success = 1; /* Preliminaries for __proto__ and setPrototypeOf (E6 19.1.2.18 steps 1-4); * magic: 0=setter call, 1=Object.setPrototypeOf */ if (duk_get_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; }
void * es_get_native_obj(duk_context *ctx, int obj_idx, es_native_type_t wanted_type) { duk_get_finalizer(ctx, obj_idx); if(!duk_is_function(ctx, -1)) { duk_error(ctx, DUK_ERR_ERROR, "Object is not of type %s (no finalizer)", native_type_to_str(wanted_type)); } es_native_type_t current_type = duk_get_magic(ctx, -1); duk_pop(ctx); if(current_type != wanted_type) duk_error(ctx, DUK_ERR_ERROR, "Object is %s, expected %s", native_type_to_str(current_type), native_type_to_str(wanted_type)); duk_get_prop_string(ctx, obj_idx, PTRNAME); if(!duk_is_pointer(ctx, -1)) duk_error(ctx, DUK_ERR_ERROR, "Object missing ptr"); void *r = duk_get_pointer(ctx, -1); duk_pop(ctx); return r; }
/* Shared helper to implement Object.getPrototypeOf and the ES6 * Object.prototype.__proto__ getter. * * https://people.mozilla.org/~jorendorff/es6-draft.html#sec-get-object.prototype.__proto__ */ duk_ret_t duk_bi_object_getprototype_shared(duk_context *ctx) { duk_hobject *h; /* magic: 0=getter call, 1=Object.getPrototypeOf */ if (duk_get_magic(ctx) == 0) { duk_push_this_coercible_to_object(ctx); duk_insert(ctx, 0); } h = duk_require_hobject(ctx, 0); DUK_ASSERT(h != NULL); /* XXX: should the API call handle this directly, i.e. attempt * to duk_push_hobject(ctx, null) would push a null instead? * (On the other hand 'undefined' would be just as logical, but * not wanted here.) */ if (h->prototype) { duk_push_hobject(ctx, h->prototype); } else { duk_push_null(ctx); } return 1; }
/* Shared helper to provide toString() and valueOf(). Checks 'this', gets * the primitive value to stack top, and optionally coerces with ToString(). */ duk_ret_t duk_bi_boolean_prototype_tostring_shared(duk_context *ctx) { duk_tval *tv; duk_hobject *h; duk_small_int_t coerce_tostring = duk_get_magic(ctx); /* FIXME: there is room to use a shared helper here, many built-ins * check the 'this' type, and if it's an object, check its class, * then get its internal value, etc. */ duk_push_this(ctx); tv = duk_get_tval(ctx, -1); DUK_ASSERT(tv != NULL); if (DUK_TVAL_IS_BOOLEAN(tv)) { goto type_ok; } else if (DUK_TVAL_IS_OBJECT(tv)) { h = DUK_TVAL_GET_OBJECT(tv); DUK_ASSERT(h != NULL); if (DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_BOOLEAN) { duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_VALUE); DUK_ASSERT(duk_is_boolean(ctx, -1)); goto type_ok; } } return DUK_RET_TYPE_ERROR; type_ok: if (coerce_tostring) { duk_to_string(ctx, -1); } return 1; }
duk_ret_t duk_bi_string_prototype_caseconv_shared(duk_context *ctx) { duk_hthread *thr = (duk_hthread *) ctx; duk_small_int_t uppercase = duk_get_magic(ctx); (void) duk_push_this_coercible_to_string(ctx); duk_unicode_case_convert_string(thr, uppercase); return 1; }
int duk_builtin_math_object_twoarg_shared(duk_context *ctx) { int fun_idx = duk_get_magic(ctx); two_arg_func fun; DUK_ASSERT(fun_idx >= 0 && fun_idx < sizeof(two_arg_funcs) / sizeof(two_arg_func)); fun = two_arg_funcs[fun_idx]; duk_push_number(ctx, fun(duk_to_number(ctx, 0), duk_to_number(ctx, 1))); return 1; }
duk_ret_t duk_bi_math_object_twoarg_shared(duk_context *ctx) { duk_small_int_t fun_idx = duk_get_magic(ctx); duk__two_arg_func fun; DUK_ASSERT(fun_idx >= 0); DUK_ASSERT(fun_idx < (duk_small_int_t) (sizeof(duk__two_arg_funcs) / sizeof(duk__two_arg_func))); fun = duk__two_arg_funcs[fun_idx]; /* FIXME: double typing here: double or duk_double_t? */ duk_push_number(ctx, fun((double) duk_to_number(ctx, 0), (double) duk_to_number(ctx, 1))); return 1; }
duk_ret_t duk_bi_object_constructor_is_sealed_frozen_shared(duk_context *ctx) { duk_hobject *h; int is_frozen; int rc; h = duk_require_hobject(ctx, 0); DUK_ASSERT(h != NULL); is_frozen = duk_get_magic(ctx); rc = duk_hobject_object_is_sealed_frozen_helper(h, is_frozen /*is_frozen*/); duk_push_boolean(ctx ,rc); return 1; }
duk_ret_t duk_bi_object_constructor_seal_freeze_shared(duk_context *ctx) { duk_hthread *thr = (duk_hthread *) ctx; duk_hobject *h; int is_freeze; h = duk_require_hobject(ctx, 0); DUK_ASSERT(h != NULL); is_freeze = duk_get_magic(ctx); duk_hobject_object_seal_freeze_helper(thr, h, is_freeze /*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; }
int duk_bi_error_constructor_shared(duk_context *ctx) { /* Behavior for constructor and non-constructor call is * the same except for augmenting the created error. When * called as a constructor, the caller (duk_new()) will handle * augmentation; when called as normal function, we need to do * it here. */ duk_hthread *thr = (duk_hthread *) ctx; int bidx_prototype = duk_get_magic(ctx); /* same for both error and each subclass like TypeError */ int flags_and_class = DUK_HOBJECT_FLAG_EXTENSIBLE | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ERROR); DUK_UNREF(thr); duk_push_object_helper(ctx, flags_and_class, bidx_prototype); /* If message is undefined, the own property 'message' is not set at * all to save property space. An empty message is inherited anyway. */ if (!duk_is_undefined(ctx, 0)) { duk_to_string(ctx, 0); duk_dup(ctx, 0); /* [ message error message ] */ duk_def_prop_stridx(ctx, -2, DUK_STRIDX_MESSAGE, DUK_PROPDESC_FLAGS_WC); } /* Augment the error if called as a normal function. __FILE__ and __LINE__ * are not desirable in this case. */ #ifdef DUK_USE_AUGMENT_ERROR_CREATE if (!duk_is_constructor_call(ctx)) { duk_err_augment_error_create(thr, thr, NULL, 0, 1 /*noblame_fileline*/); } #endif return 1; }
static duk_ret_t test_func(duk_context *ctx, void *udata) { (void) udata; if (ctx) { printf("dummy - return here\n"); fflush(stdout); return 0; } /* Up-to-date for Duktape 1.3.0, alphabetical order: * $ cd website/api; ls *.yaml */ (void) duk_alloc_raw(ctx, 0); (void) duk_alloc(ctx, 0); (void) duk_base64_decode(ctx, 0); (void) duk_base64_encode(ctx, 0); (void) duk_buffer_to_string(ctx, 0); (void) duk_call_method(ctx, 0); (void) duk_call_prop(ctx, 0, 0); (void) duk_call(ctx, 0); (void) duk_char_code_at(ctx, 0, 0); (void) duk_check_stack_top(ctx, 0); (void) duk_check_stack(ctx, 0); (void) duk_check_type_mask(ctx, 0, 0); (void) duk_check_type(ctx, 0, 0); (void) duk_compact(ctx, 0); (void) duk_compile_lstring_filename(ctx, 0, "dummy", 0); (void) duk_compile_lstring(ctx, 0, "dummy", 0); (void) duk_compile_string_filename(ctx, 0, "dummy"); (void) duk_compile_string(ctx, 0, "dummy"); (void) duk_compile(ctx, 0); (void) duk_concat(ctx, 0); (void) duk_config_buffer(ctx, 0, NULL, 0); (void) duk_copy(ctx, 0, 0); (void) duk_create_heap_default(); (void) duk_create_heap(NULL, NULL, NULL, NULL, NULL); (void) duk_debugger_attach(ctx, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); (void) duk_debugger_cooperate(ctx); (void) duk_debugger_detach(ctx); (void) duk_debugger_notify(ctx, 0); (void) duk_debugger_pause(ctx); (void) duk_decode_string(ctx, 0, NULL, NULL); (void) duk_def_prop(ctx, 0, 0); (void) duk_del_prop_index(ctx, 0, 0); (void) duk_del_prop_string(ctx, 0, "dummy"); (void) duk_del_prop(ctx, 0); (void) duk_destroy_heap(ctx); (void) duk_dump_function(ctx); (void) duk_dup_top(ctx); (void) duk_dup(ctx, 0); (void) duk_enum(ctx, 0, 0); (void) duk_equals(ctx, 0, 0); duk_error_va(ctx, 0, NULL, NULL); duk_error(ctx, 0, "dummy"); /* (void) cast won't work without variadic macros */ (void) duk_eval_lstring_noresult(ctx, "dummy", 0); (void) duk_eval_lstring(ctx, "dummy", 0); (void) duk_eval_noresult(ctx); (void) duk_eval_string_noresult(ctx, "dummy"); (void) duk_eval_string(ctx, "dummy"); (void) duk_eval(ctx); (void) duk_fatal(ctx, "dummy"); (void) duk_free_raw(ctx, NULL); (void) duk_free(ctx, NULL); (void) duk_gc(ctx, 0); (void) duk_get_boolean(ctx, 0); (void) duk_get_buffer_data(ctx, 0, NULL); (void) duk_get_buffer(ctx, 0, NULL); (void) duk_get_c_function(ctx, 0); (void) duk_get_context(ctx, 0); (void) duk_get_current_magic(ctx); (void) duk_get_error_code(ctx, 0); (void) duk_get_finalizer(ctx, 0); (void) duk_get_global_string(ctx, 0); (void) duk_get_heapptr(ctx, 0); (void) duk_get_int(ctx, 0); (void) duk_get_length(ctx, 0); (void) duk_get_lstring(ctx, 0, NULL); (void) duk_get_magic(ctx, 0); (void) duk_get_memory_functions(ctx, NULL); (void) duk_get_number(ctx, 0); (void) duk_get_pointer(ctx, 0); (void) duk_get_prop_index(ctx, 0, 0); (void) duk_get_prop_string(ctx, 0, "dummy"); (void) duk_get_prop(ctx, 0); (void) duk_get_prototype(ctx, 0); (void) duk_get_string(ctx, 0); (void) duk_get_top_index(ctx); (void) duk_get_top(ctx); (void) duk_get_type_mask(ctx, 0); (void) duk_get_type(ctx, 0); (void) duk_get_uint(ctx, 0); (void) duk_has_prop_index(ctx, 0, 0); (void) duk_has_prop_string(ctx, 0, "dummy"); (void) duk_has_prop(ctx, 0); (void) duk_hex_decode(ctx, 0); (void) duk_hex_encode(ctx, 0); (void) duk_insert(ctx, 0); (void) duk_instanceof(ctx, 0, 0); (void) duk_is_array(ctx, 0); (void) duk_is_boolean(ctx, 0); (void) duk_is_bound_function(ctx, 0); (void) duk_is_buffer(ctx, 0); (void) duk_is_callable(ctx, 0); (void) duk_is_c_function(ctx, 0); (void) duk_is_constructor_call(ctx); (void) duk_is_dynamic_buffer(ctx, 0); (void) duk_is_ecmascript_function(ctx, 0); (void) duk_is_error(ctx, 0); (void) duk_is_eval_error(ctx, 0); (void) duk_is_fixed_buffer(ctx, 0); (void) duk_is_function(ctx, 0); (void) duk_is_lightfunc(ctx, 0); (void) duk_is_nan(ctx, 0); (void) duk_is_null_or_undefined(ctx, 0); (void) duk_is_null(ctx, 0); (void) duk_is_number(ctx, 0); (void) duk_is_object_coercible(ctx, 0); (void) duk_is_object(ctx, 0); (void) duk_is_pointer(ctx, 0); (void) duk_is_primitive(ctx, 0); (void) duk_is_range_error(ctx, 0); (void) duk_is_reference_error(ctx, 0); (void) duk_is_strict_call(ctx); (void) duk_is_string(ctx, 0); (void) duk_is_syntax_error(ctx, 0); (void) duk_is_thread(ctx, 0); (void) duk_is_type_error(ctx, 0); (void) duk_is_undefined(ctx, 0); (void) duk_is_uri_error(ctx, 0); (void) duk_is_valid_index(ctx, 0); (void) duk_join(ctx, 0); (void) duk_json_decode(ctx, 0); (void) duk_json_encode(ctx, 0); (void) duk_load_function(ctx); (void) duk_map_string(ctx, 0, NULL, NULL); (void) duk_new(ctx, 0); (void) duk_next(ctx, 0, 0); (void) duk_normalize_index(ctx, 0); (void) duk_pcall_method(ctx, 0); (void) duk_pcall_prop(ctx, 0, 0); (void) duk_pcall(ctx, 0); (void) duk_pcompile_lstring_filename(ctx, 0, "dummy", 0); (void) duk_pcompile_lstring(ctx, 0, "dummy", 0); (void) duk_pcompile_string_filename(ctx, 0, "dummy"); (void) duk_pcompile_string(ctx, 0, "dummy"); (void) duk_pcompile(ctx, 0); (void) duk_peval_lstring_noresult(ctx, "dummy", 0); (void) duk_peval_lstring(ctx, "dummy", 0); (void) duk_peval_noresult(ctx); (void) duk_peval_string_noresult(ctx, "dummy"); (void) duk_peval_string(ctx, "dummy"); (void) duk_peval(ctx); (void) duk_pnew(ctx, 0); (void) duk_pop_2(ctx); (void) duk_pop_3(ctx); (void) duk_pop_n(ctx, 0); (void) duk_pop(ctx); (void) duk_push_array(ctx); (void) duk_push_boolean(ctx, 0); (void) duk_push_buffer_object(ctx, 0, 0, 0, 0); (void) duk_push_buffer(ctx, 0, 0); (void) duk_push_c_function(ctx, NULL, 0); (void) duk_push_c_lightfunc(ctx, NULL, 0, 0, 0); (void) duk_push_context_dump(ctx); (void) duk_push_current_function(ctx); (void) duk_push_current_thread(ctx); (void) duk_push_dynamic_buffer(ctx, 0); (void) duk_push_error_object_va(ctx, 0, NULL, NULL); (void) duk_push_error_object(ctx, 0, "dummy"); (void) duk_push_external_buffer(ctx); (void) duk_push_false(ctx); (void) duk_push_fixed_buffer(ctx, 0); (void) duk_push_global_object(ctx); (void) duk_push_global_stash(ctx); (void) duk_push_heap_stash(ctx); (void) duk_push_heapptr(ctx, NULL); (void) duk_push_int(ctx, 0); (void) duk_push_lstring(ctx, "dummy", 0); (void) duk_push_nan(ctx); (void) duk_push_null(ctx); (void) duk_push_number(ctx, 0.0); (void) duk_push_object(ctx); (void) duk_push_pointer(ctx, NULL); (void) duk_push_sprintf(ctx, "dummy"); (void) duk_push_string(ctx, "dummy"); (void) duk_push_this(ctx); (void) duk_push_thread_new_globalenv(ctx); (void) duk_push_thread_stash(ctx, NULL); (void) duk_push_thread(ctx); (void) duk_push_true(ctx); (void) duk_push_uint(ctx, 0); (void) duk_push_undefined(ctx); (void) duk_push_vsprintf(ctx, "dummy", NULL); (void) duk_put_function_list(ctx, 0, NULL); (void) duk_put_global_string(ctx, NULL); (void) duk_put_number_list(ctx, 0, NULL); (void) duk_put_prop_index(ctx, 0, 0); (void) duk_put_prop_string(ctx, 0, "dummy"); (void) duk_put_prop(ctx, 0); (void) duk_realloc_raw(ctx, NULL, 0); (void) duk_realloc(ctx, NULL, 0); (void) duk_remove(ctx, 0); (void) duk_replace(ctx, 0); (void) duk_require_boolean(ctx, 0); (void) duk_require_buffer_data(ctx, 0, NULL); (void) duk_require_buffer(ctx, 0, NULL); (void) duk_require_c_function(ctx, 0); (void) duk_require_callable(ctx, 0); (void) duk_require_context(ctx, 0); (void) duk_require_function(ctx, 0); (void) duk_require_heapptr(ctx, 0); (void) duk_require_int(ctx, 0); (void) duk_require_lstring(ctx, 0, NULL); (void) duk_require_normalize_index(ctx, 0); (void) duk_require_null(ctx, 0); (void) duk_require_number(ctx, 0); (void) duk_require_object_coercible(ctx, 0); (void) duk_require_pointer(ctx, 0); (void) duk_require_stack_top(ctx, 0); (void) duk_require_stack(ctx, 0); (void) duk_require_string(ctx, 0); (void) duk_require_top_index(ctx); (void) duk_require_type_mask(ctx, 0, 0); (void) duk_require_uint(ctx, 0); (void) duk_require_undefined(ctx, 0); (void) duk_require_valid_index(ctx, 0); (void) duk_resize_buffer(ctx, 0, 0); (void) duk_safe_call(ctx, NULL, NULL, 0, 0); (void) duk_safe_to_lstring(ctx, 0, NULL); (void) duk_safe_to_string(ctx, 0); (void) duk_set_finalizer(ctx, 0); (void) duk_set_global_object(ctx); (void) duk_set_magic(ctx, 0, 0); (void) duk_set_prototype(ctx, 0); (void) duk_set_top(ctx, 0); (void) duk_steal_buffer(ctx, 0, NULL); (void) duk_strict_equals(ctx, 0, 0); (void) duk_substring(ctx, 0, 0, 0); (void) duk_swap_top(ctx, 0); (void) duk_swap(ctx, 0, 0); (void) duk_throw(ctx); (void) duk_to_boolean(ctx, 0); (void) duk_to_buffer(ctx, 0, NULL); (void) duk_to_defaultvalue(ctx, 0, 0); (void) duk_to_dynamic_buffer(ctx, 0, NULL); (void) duk_to_fixed_buffer(ctx, 0, NULL); (void) duk_to_int32(ctx, 0); (void) duk_to_int(ctx, 0); (void) duk_to_lstring(ctx, 0, NULL); (void) duk_to_null(ctx, 0); (void) duk_to_number(ctx, 0); (void) duk_to_object(ctx, 0); (void) duk_to_pointer(ctx, 0); (void) duk_to_primitive(ctx, 0, 0); (void) duk_to_string(ctx, 0); (void) duk_to_uint16(ctx, 0); (void) duk_to_uint32(ctx, 0); (void) duk_to_uint(ctx, 0); (void) duk_to_undefined(ctx, 0); (void) duk_trim(ctx, 0); (void) duk_xcopy_top(ctx, NULL, 0); (void) duk_xmove_top(ctx, NULL, 0); printf("never here\n"); fflush(stdout); return 0; }
/* Shared helper for Object.getOwnPropertyNames() and Object.keys(). * Magic: 0=getOwnPropertyNames, 1=Object.keys. */ duk_ret_t duk_bi_object_constructor_keys_shared(duk_context *ctx) { duk_hthread *thr = (duk_hthread *) ctx; duk_hobject *obj; #if defined(DUK_USE_ES6_PROXY) duk_hobject *h_proxy_target; duk_hobject *h_proxy_handler; duk_hobject *h_trap_result; duk_uint32_t i, len, idx; #endif duk_small_int_t enum_flags; DUK_ASSERT_TOP(ctx, 1); obj = duk_require_hobject(ctx, 0); DUK_ASSERT(obj != NULL); DUK_UNREF(obj); #if defined(DUK_USE_ES6_PROXY) if (DUK_LIKELY(!duk_hobject_proxy_check(thr, obj, &h_proxy_target, &h_proxy_handler))) { goto skip_proxy; } duk_push_hobject(ctx, h_proxy_handler); if (!duk_get_prop_stridx(ctx, -1, DUK_STRIDX_OWN_KEYS)) { /* Careful with reachability here: don't pop 'obj' before pushing * proxy target. */ DUK_DDD(DUK_DDDPRINT("no ownKeys trap, get keys of target instead")); duk_pop_2(ctx); duk_push_hobject(ctx, h_proxy_target); duk_replace(ctx, 0); DUK_ASSERT_TOP(ctx, 1); goto skip_proxy; } /* [ obj handler trap ] */ duk_insert(ctx, -2); duk_push_hobject(ctx, h_proxy_target); /* -> [ obj trap handler target ] */ duk_call_method(ctx, 1 /*nargs*/); /* -> [ obj trap_result ] */ h_trap_result = duk_require_hobject(ctx, -1); DUK_UNREF(h_trap_result); len = (duk_uint32_t) duk_get_length(ctx, -1); idx = 0; duk_push_array(ctx); for (i = 0; i < len; i++) { /* [ obj trap_result res_arr ] */ if (duk_get_prop_index(ctx, -2, i) && duk_is_string(ctx, -1)) { /* XXX: for Object.keys() we should check enumerability of key */ /* [ obj trap_result res_arr propname ] */ duk_put_prop_index(ctx, -2, idx); idx++; } else { duk_pop(ctx); } } /* XXX: for Object.keys() the [[OwnPropertyKeys]] result (trap result) * should be filtered so that only enumerable keys remain. Enumerability * should be checked with [[GetOwnProperty]] on the original object * (i.e., the proxy in this case). If the proxy has a getOwnPropertyDescriptor * trap, it should be triggered for every property. If the proxy doesn't have * the trap, enumerability should be checked against the target object instead. * We don't do any of this now, so Object.keys() and Object.getOwnPropertyNames() * return the same result now for proxy traps. We still do clean up the trap * result, so that Object.keys() and Object.getOwnPropertyNames() will return a * clean array of strings without gaps. */ return 1; skip_proxy: #endif /* DUK_USE_ES6_PROXY */ DUK_ASSERT_TOP(ctx, 1); if (duk_get_magic(ctx)) { /* Object.keys */ enum_flags = DUK_ENUM_OWN_PROPERTIES_ONLY | DUK_ENUM_NO_PROXY_BEHAVIOR; } else { /* Object.getOwnPropertyNames */ enum_flags = DUK_ENUM_INCLUDE_NONENUMERABLE | DUK_ENUM_OWN_PROPERTIES_ONLY | DUK_ENUM_NO_PROXY_BEHAVIOR; } return duk_hobject_get_enumerated_keys(ctx, enum_flags); }
duk_ret_t duk_bi_string_prototype_indexof_shared(duk_context *ctx) { duk_hthread *thr = (duk_hthread *) ctx; duk_hstring *h_this; duk_hstring *h_search; duk_int_t clen_this; duk_int_t cpos; duk_int_t bpos; duk_uint8_t *p_start, *p_end, *p; duk_uint8_t *q_start; duk_size_t q_blen; /* FIXME: type inconsistency (clen_this is duk_int_t) */ duk_uint8_t firstbyte; duk_uint8_t t; duk_small_int_t is_lastindexof = duk_get_magic(ctx); /* 0=indexOf, 1=lastIndexOf */ h_this = duk_push_this_coercible_to_string(ctx); DUK_ASSERT(h_this != NULL); clen_this = (duk_int_t) DUK_HSTRING_GET_CHARLEN(h_this); h_search = duk_to_hstring(ctx, 0); DUK_ASSERT(h_search != NULL); q_start = DUK_HSTRING_GET_DATA(h_search); q_blen = (size_t) DUK_HSTRING_GET_BYTELEN(h_search); duk_to_number(ctx, 1); if (duk_is_nan(ctx, 1) && is_lastindexof) { /* indexOf: NaN should cause pos to be zero. * lastIndexOf: NaN should cause pos to be +Infinity * (and later be clamped to len). */ cpos = clen_this; } else { cpos = duk_to_int_clamped(ctx, 1, 0, clen_this); } /* Empty searchstring always matches; cpos must be clamped here. */ if (q_blen == 0) { duk_push_int(ctx, cpos); return 1; } bpos = (duk_int_t) duk_heap_strcache_offset_char2byte(thr, h_this, (duk_uint32_t) cpos); p_start = DUK_HSTRING_GET_DATA(h_this); p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_this); p = p_start + bpos; /* This loop is optimized for size. For speed, there should be * two separate loops, and we should ensure that memcmp() can be * used without an extra "will searchstring fit" check. Doing * the preconditioning for 'p' and 'p_end' is easy but cpos * must be updated if 'p' is wound back (backward scanning). */ firstbyte = q_start[0]; /* leading byte of match string */ while (p <= p_end && p >= p_start) { t = *p; /* For Ecmascript strings, this check can only match for * initial UTF-8 bytes (not continuation bytes). For other * strings all bets are off. */ if ((t == firstbyte) && ((duk_size_t) (p_end - p) >= q_blen)) { DUK_ASSERT(q_blen > 0); /* no issues with memcmp() zero size, even if broken */ if (DUK_MEMCMP(p, q_start, q_blen) == 0) { duk_push_int(ctx, cpos); return 1; } } /* track cpos while scanning */ if (is_lastindexof) { /* when going backwards, we decrement cpos 'early'; * 'p' may point to a continuation byte of the char * at offset 'cpos', but that's OK because we'll * backtrack all the way to the initial byte. */ if ((t & 0xc0) != 0x80) { cpos--; } p--; } else { if ((t & 0xc0) != 0x80) { cpos++; } p++; } } /* Not found. Empty string case is handled specially above. */ duk_push_int(ctx, -1); return 1; }
int duk_builtin_date_prototype_set_shared(duk_context *ctx) { int flags_and_maxnargs = duk_get_magic(ctx); return set_part_helper(ctx, flags_and_maxnargs); }
int duk_builtin_date_prototype_get_shared(duk_context *ctx) { int flags_and_idx = duk_get_magic(ctx); return get_part_helper(ctx, flags_and_idx); }
int duk_builtin_date_prototype_tostring_shared(duk_context *ctx) { int flags = duk_get_magic(ctx); return to_string_helper(ctx, flags); }
int duk_bi_array_prototype_indexof_shared(duk_context *ctx) { /* FIXME: types, ensure loop below works when fixed (i must be able to go negative right now) */ int nargs; int i, len; int fromIndex; int idx_step = duk_get_magic(ctx); /* idx_step is +1 for indexOf, -1 for lastIndexOf */ /* lastIndexOf() needs to be a vararg function because we must distinguish * between an undefined fromIndex and a "not given" fromIndex; indexOf() is * made vararg for symmetry although it doesn't strictly need to be. */ nargs = duk_get_top(ctx); duk_set_top(ctx, 2); len = duk__push_this_obj_len_u32(ctx); if (len == 0) { goto not_found; } /* Index clamping is a bit tricky, we must ensure that we'll only iterate * through elements that exist and that the specific requirements from E5.1 * Sections 15.4.4.14 and 15.4.4.15 are fulfilled; especially: * * - indexOf: clamp to [-len,len], negative handling -> [0,len], * if clamped result is len, for-loop bails out immediately * * - lastIndexOf: clamp to [-len-1, len-1], negative handling -> [-1, len-1], * if clamped result is -1, for-loop bails out immediately * * If fromIndex is not given, ToInteger(undefined) = 0, which is correct * for indexOf() but incorrect for lastIndexOf(). Hence special handling, * and why lastIndexOf() needs to be a vararg function. */ if (nargs >= 2) { /* indexOf: clamp fromIndex to [-len, len] * (if fromIndex == len, for-loop terminates directly) * * lastIndexOf: clamp fromIndex to [-len - 1, len - 1] * (if clamped to -len-1 -> fromIndex becomes -1, terminates for-loop directly) */ fromIndex = duk_to_int_clamped(ctx, 1, (idx_step > 0 ? -len : -len - 1), (idx_step > 0 ? len : len - 1)); if (fromIndex < 0) { /* for lastIndexOf, result may be -1 (mark immediate termination) */ fromIndex = len + fromIndex; } } else { /* for indexOf, ToInteger(undefined) would be 0, i.e. correct, but * handle both indexOf and lastIndexOf specially here. */ if (idx_step > 0) { fromIndex = 0; } else { fromIndex = len - 1; } } /* stack[0] = searchElement * stack[1] = fromIndex * stack[2] = object * stack[3] = length (not needed, but not popped above) */ for (i = fromIndex; i >= 0 && i < len; i += idx_step) { DUK_ASSERT_TOP(ctx, 4); if (duk_get_prop_index(ctx, 2, i)) { DUK_ASSERT_TOP(ctx, 5); if (duk_strict_equals(ctx, 0, 4)) { duk_push_int(ctx, i); return 1; } } duk_pop(ctx); } not_found: duk_push_int(ctx, -1); return 1; }
int duk_bi_array_prototype_iter_shared(duk_context *ctx) { int len; int i; int k; int bval; int iter_type = duk_get_magic(ctx); duk_uint32_t res_length = 0; /* each call this helper serves has nargs==2 */ DUK_ASSERT_TOP(ctx, 2); len = duk__push_this_obj_len_u32(ctx); if (!duk_is_callable(ctx, 0)) { goto type_error; } /* if thisArg not supplied, behave as if undefined was supplied */ if (iter_type == DUK__ITER_MAP || iter_type == DUK__ITER_FILTER) { duk_push_array(ctx); } else { duk_push_undefined(ctx); } /* stack[0] = callback * stack[1] = thisArg * stack[2] = object * stack[3] = ToUint32(length) (unused, but avoid unnecessary pop) * stack[4] = result array (or undefined) */ k = 0; /* result index for filter() */ for (i = 0; i < len; i++) { DUK_ASSERT_TOP(ctx, 5); if (!duk_get_prop_index(ctx, 2, i)) { duk_pop(ctx); continue; } /* The original value needs to be preserved for filter(), hence * this funny order. We can't re-get the value because of side * effects. */ duk_dup(ctx, 0); duk_dup(ctx, 1); duk_dup(ctx, -3); duk_push_int(ctx, i); duk_dup(ctx, 2); /* [ ... val callback thisArg val i obj ] */ duk_call_method(ctx, 3); /* -> [ ... val retval ] */ switch (iter_type) { case DUK__ITER_EVERY: bval = duk_to_boolean(ctx, -1); if (!bval) { /* stack top contains 'false' */ return 1; } break; case DUK__ITER_SOME: bval = duk_to_boolean(ctx, -1); if (bval) { /* stack top contains 'true' */ return 1; } break; case DUK__ITER_FOREACH: /* nop */ break; case DUK__ITER_MAP: duk_dup(ctx, -1); duk_def_prop_index(ctx, 4, i, DUK_PROPDESC_FLAGS_WEC); /* retval to result[i] */ res_length = i + 1; break; case DUK__ITER_FILTER: bval = duk_to_boolean(ctx, -1); if (bval) { duk_dup(ctx, -2); /* orig value */ duk_def_prop_index(ctx, 4, k, DUK_PROPDESC_FLAGS_WEC); k++; res_length = k; } break; default: DUK_UNREACHABLE(); break; } duk_pop_2(ctx); DUK_ASSERT_TOP(ctx, 5); } switch (iter_type) { case DUK__ITER_EVERY: duk_push_true(ctx); break; case DUK__ITER_SOME: duk_push_false(ctx); break; case DUK__ITER_FOREACH: duk_push_undefined(ctx); break; case DUK__ITER_MAP: case DUK__ITER_FILTER: DUK_ASSERT_TOP(ctx, 5); DUK_ASSERT(duk_is_array(ctx, -1)); /* topmost element is the result array already */ duk_push_number(ctx, (double) res_length); /* FIXME */ duk_def_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_W); break; default: DUK_UNREACHABLE(); break; } return 1; type_error: return DUK_RET_TYPE_ERROR; }
//duk_int_t duk_get_magic(duk_context *ctx, duk_idx_t index); duk_int_t aperl_duk_get_magic(duk_context *ctx, duk_idx_t index) { duk_int_t ret = duk_get_magic(ctx, index); return ret; }
int duk_bi_array_prototype_reduce_shared(duk_context *ctx) { int nargs; int have_acc; int i, len; int idx_step = duk_get_magic(ctx); /* idx_step is +1 for reduce, -1 for reduceRight */ /* We're a varargs function because we need to detect whether * initialValue was given or not. */ nargs = duk_get_top(ctx); DUK_DDD(DUK_DDDPRINT("nargs=%d", nargs)); duk_set_top(ctx, 2); len = duk__push_this_obj_len_u32(ctx); if (!duk_is_callable(ctx, 0)) { goto type_error; } /* stack[0] = callback fn * stack[1] = initialValue * stack[2] = object (coerced this) * stack[3] = length (not needed, but not popped above) * stack[4] = accumulator */ have_acc = 0; if (nargs >= 2) { duk_dup(ctx, 1); have_acc = 1; } DUK_DDD(DUK_DDDPRINT("have_acc=%d, acc=%!T", have_acc, duk_get_tval(ctx, 3))); for (i = (idx_step >= 0 ? 0 : len - 1); i >= 0 && i < len; i += idx_step) { DUK_DDD(DUK_DDDPRINT("i=%d, len=%d, have_acc=%d, top=%d, acc=%!T", i, len, have_acc, duk_get_top(ctx), duk_get_tval(ctx, 4))); DUK_ASSERT((have_acc && duk_get_top(ctx) == 5) || (!have_acc && duk_get_top(ctx) == 4)); if (!duk_has_prop_index(ctx, 2, i)) { continue; } if (!have_acc) { DUK_ASSERT_TOP(ctx, 4); duk_get_prop_index(ctx, 2, i); have_acc = 1; DUK_ASSERT_TOP(ctx, 5); } else { DUK_ASSERT_TOP(ctx, 5); duk_dup(ctx, 0); duk_dup(ctx, 4); duk_get_prop_index(ctx, 2, i); duk_push_int(ctx, i); /* FIXME: type */ duk_dup(ctx, 2); DUK_DDD(DUK_DDDPRINT("calling reduce function: func=%!T, prev=%!T, curr=%!T, idx=%!T, obj=%!T", duk_get_tval(ctx, -5), duk_get_tval(ctx, -4), duk_get_tval(ctx, -3), duk_get_tval(ctx, -2), duk_get_tval(ctx, -1))); duk_call(ctx, 4); DUK_DDD(DUK_DDDPRINT("-> result: %!T", duk_get_tval(ctx, -1))); duk_replace(ctx, 4); DUK_ASSERT_TOP(ctx, 5); } } if (!have_acc) { goto type_error; } DUK_ASSERT_TOP(ctx, 5); return 1; type_error: return DUK_RET_TYPE_ERROR; }
int duk_bi_array_prototype_join_shared(duk_context *ctx) { duk_uint32_t len, count; duk_uint32_t idx; duk_small_int_t to_locale_string = duk_get_magic(ctx); duk_int_t valstack_required; /* For join(), nargs is 1. For toLocaleString(), nargs is 0 and * setting the top essentially pushes an undefined to the stack, * thus defaulting to a comma separator. */ duk_set_top(ctx, 1); if (duk_is_undefined(ctx, 0)) { duk_pop(ctx); duk_push_hstring_stridx(ctx, DUK_STRIDX_COMMA); } else { duk_to_string(ctx, 0); } len = duk__push_this_obj_len_u32(ctx); /* [ sep ToObject(this) len ] */ DUK_DDD(DUK_DDDPRINT("sep=%!T, this=%!T, len=%d", duk_get_tval(ctx, 0), duk_get_tval(ctx, 1), (int) len)); valstack_required = (len >= DUK__ARRAY_MID_JOIN_LIMIT ? DUK__ARRAY_MID_JOIN_LIMIT : len); valstack_required++; duk_require_stack(ctx, valstack_required); duk_dup(ctx, 0); /* [ sep ToObject(this) len sep ] */ count = 0; idx = 0; for (;;) { if (count >= DUK__ARRAY_MID_JOIN_LIMIT || /* intermediate join to avoid valstack overflow */ idx >= len) { /* end of loop (careful with len==0) */ /* [ sep ToObject(this) len sep str0 ... str(count-1) ] */ DUK_DDD(DUK_DDDPRINT("mid/final join, count=%d, idx=%d, len=%d", (int) count, (int) idx, (int) len)); duk_join(ctx, count); /* -> [ sep ToObject(this) len str ] */ duk_dup(ctx, 0); /* -> [ sep ToObject(this) len str sep ] */ duk_insert(ctx, -2); /* -> [ sep ToObject(this) len sep str ] */ count = 1; } if (idx >= len) { /* if true, the stack already contains the final result */ break; } duk_get_prop_index(ctx, 1, idx); if (duk_is_null_or_undefined(ctx, -1)) { duk_pop(ctx); duk_push_hstring_stridx(ctx, DUK_STRIDX_EMPTY_STRING); } else { if (to_locale_string) { duk_to_object(ctx, -1); duk_get_prop_stridx(ctx, -1, DUK_STRIDX_TO_LOCALE_STRING); duk_insert(ctx, -2); /* -> [ ... toLocaleString ToObject(val) ] */ duk_call_method(ctx, 0); duk_to_string(ctx, -1); } else { duk_to_string(ctx, -1); } } count++; idx++; } /* [ sep ToObject(this) len sep result ] */ return 1; }