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:
//.........这里部分代码省略.........
/* Shared helper for Object.getOwnPropertyNames() and Object.keys().
* Magic: 0=getOwnPropertyNames, 1=Object.keys.
*/
DUK_INTERNAL 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_uarridx_t i, len, idx;
#endif
duk_small_uint_t enum_flags;
DUK_ASSERT_TOP(ctx, 1);
DUK_UNREF(thr);
obj = duk_require_hobject_or_lfunc_coerce(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_uarridx_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: missing trap result validation for non-configurable target keys
* (must be present), for non-extensible target all target keys must be
* present and no extra keys can be present.
* http://www.ecma-international.org/ecma-262/6.0/#sec-proxy-object-internal-methods-and-internal-slots-ownpropertykeys
*/
/* 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_current_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_INTERNAL duk_ret_t duk_bi_array_prototype_splice(duk_context *ctx) {
duk_idx_t nargs;
duk_uint32_t len;
duk_bool_t have_delcount;
duk_int_t item_count;
duk_int_t act_start;
duk_int_t del_count;
duk_int_t i, n;
DUK_UNREF(have_delcount);
nargs = duk_get_top(ctx);
if (nargs < 2) {
duk_set_top(ctx, 2);
nargs = 2;
have_delcount = 0;
} else {
have_delcount = 1;
}
/* XXX: len >= 0x80000000 won't work below because we need to be
* able to represent -len.
*/
len = duk__push_this_obj_len_u32_limited(ctx);
act_start = duk_to_int_clamped(ctx, 0, -((duk_int_t) len), (duk_int_t) len);
if (act_start < 0) {
act_start = len + act_start;
}
DUK_ASSERT(act_start >= 0 && act_start <= (duk_int_t) len);
#ifdef DUK_USE_NONSTD_ARRAY_SPLICE_DELCOUNT
if (have_delcount) {
#endif
del_count = duk_to_int_clamped(ctx, 1, 0, len - act_start);
#ifdef DUK_USE_NONSTD_ARRAY_SPLICE_DELCOUNT
} else {
/* E5.1 standard behavior when deleteCount is not given would be
* to treat it just like if 'undefined' was given, which coerces
* ultimately to 0. Real world behavior is to splice to the end
* of array, see test-bi-array-proto-splice-no-delcount.js.
*/
del_count = len - act_start;
}
#endif
DUK_ASSERT(nargs >= 2);
item_count = (duk_int_t) (nargs - 2);
DUK_ASSERT(del_count >= 0 && del_count <= (duk_int_t) len - act_start);
DUK_ASSERT(del_count + act_start <= (duk_int_t) len);
/* For now, restrict result array into 32-bit length range. */
if (((duk_double_t) len) - ((duk_double_t) del_count) + ((duk_double_t) item_count) > (duk_double_t) DUK_UINT32_MAX) {
DUK_D(DUK_DPRINT("Array.prototype.splice() would go beyond 32-bit length, throw"));
return DUK_RET_RANGE_ERROR;
}
duk_push_array(ctx);
/* stack[0] = start
* stack[1] = deleteCount
* stack[2...nargs-1] = items
* stack[nargs] = ToObject(this) -3
* stack[nargs+1] = ToUint32(length) -2
* stack[nargs+2] = result array -1
*/
DUK_ASSERT_TOP(ctx, nargs + 3);
/* Step 9: copy elements-to-be-deleted into the result array */
for (i = 0; i < del_count; i++) {
if (duk_get_prop_index(ctx, -3, (duk_uarridx_t) (act_start + i))) {
duk_xdef_prop_index_wec(ctx, -2, i); /* throw flag irrelevant (false in std alg) */
} else {
duk_pop(ctx);
}
}
duk_push_u32(ctx, (duk_uint32_t) del_count);
duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_W);
/* Steps 12 and 13: reorganize elements to make room for itemCount elements */
if (item_count < del_count) {
/* [ A B C D E F G H ] rel_index = 2, del_count 3, item count 1
* -> [ A B F G H ] (conceptual intermediate step)
* -> [ A B . F G H ] (placeholder marked)
* [ A B C F G H ] (actual result at this point, C will be replaced)
*/
DUK_ASSERT_TOP(ctx, nargs + 3);
n = len - del_count;
for (i = act_start; i < n; i++) {
if (duk_get_prop_index(ctx, -3, (duk_uarridx_t) (i + del_count))) {
duk_put_prop_index(ctx, -4, (duk_uarridx_t) (i + item_count));
} else {
duk_pop(ctx);
duk_del_prop_index(ctx, -3, (duk_uarridx_t) (i + item_count));
//.........这里部分代码省略.........
int duk_bi_array_prototype_splice(duk_context *ctx) {
int nargs;
int have_delcount;
int item_count;
int len;
int act_start;
int del_count;
int i;
DUK_UNREF(have_delcount);
nargs = duk_get_top(ctx);
if (nargs < 2) {
duk_set_top(ctx, 2);
nargs = 2;
have_delcount = 0;
} else {
have_delcount = 1;
}
len = duk__push_this_obj_len_u32(ctx);
act_start = duk_to_int_clamped(ctx, 0, -len, len);
if (act_start < 0) {
act_start = len + act_start;
}
DUK_ASSERT(act_start >= 0 && act_start <= len);
#ifdef DUK_USE_NONSTD_ARRAY_SPLICE_DELCOUNT
if (have_delcount) {
#endif
del_count = duk_to_int_clamped(ctx, 1, 0, len - act_start);
#ifdef DUK_USE_NONSTD_ARRAY_SPLICE_DELCOUNT
} else {
/* E5.1 standard behavior when deleteCount is not given would be
* to treat it just like if 'undefined' was given, which coerces
* ultimately to 0. Real world behavior is to splice to the end
* of array, see test-bi-array-proto-splice-no-delcount.js.
*/
del_count = len - act_start;
}
#endif
DUK_ASSERT(del_count >= 0 && del_count <= len - act_start);
DUK_ASSERT(del_count + act_start <= len);
duk_push_array(ctx);
/* stack[0] = start
* stack[1] = deleteCount
* stack[2...nargs-1] = items
* stack[nargs] = ToObject(this) -3
* stack[nargs+1] = ToUint32(length) -2
* stack[nargs+2] = result array -1
*/
DUK_ASSERT_TOP(ctx, nargs + 3);
/* Step 9: copy elements-to-be-deleted into the result array */
for (i = 0; i < del_count; i++) {
if (duk_get_prop_index(ctx, -3, act_start + i)) {
duk_def_prop_index(ctx, -2, i, DUK_PROPDESC_FLAGS_WEC); /* throw flag irrelevant (false in std alg) */
} else {
duk_pop(ctx);
}
}
duk_push_int(ctx, del_count); /* FIXME: typing */
duk_def_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_W);
/* Steps 12 and 13: reorganize elements to make room for itemCount elements */
DUK_ASSERT(nargs >= 2);
item_count = nargs - 2;
if (item_count < del_count) {
/* [ A B C D E F G H ] rel_index = 2, del_count 3, item count 1
* -> [ A B F G H ] (conceptual intermediate step)
* -> [ A B . F G H ] (placeholder marked)
* [ A B C F G H ] (actual result at this point, C will be replaced)
*/
DUK_ASSERT_TOP(ctx, nargs + 3);
for (i = act_start; i < len - del_count; i++) {
if (duk_get_prop_index(ctx, -3, i + del_count)) {
duk_put_prop_index(ctx, -4, i + item_count); /* FIXME: Throw */
} else {
duk_pop(ctx);
duk_del_prop_index(ctx, -3, i + item_count); /* FIXME: Throw */
}
}
DUK_ASSERT_TOP(ctx, nargs + 3);
/* loop iterator init and limit changed from standard algorithm */
for (i = len - 1; i >= len - del_count + item_count; i--) {
duk_del_prop_index(ctx, -3, i); /* FIXME: Throw */
}
DUK_ASSERT_TOP(ctx, nargs + 3);
//.........这里部分代码省略.........
int duk_bi_array_prototype_concat(duk_context *ctx) {
int i, n;
int j, len;
int idx, idx_last;
duk_hobject *h;
/* XXX: the insert here is a bit expensive if there are a lot of items.
* It could also be special cased in the outermost for loop quite easily
* (as the element is dup()'d anyway).
*/
(void) duk_push_this_coercible_to_object(ctx);
duk_insert(ctx, 0);
n = duk_get_top(ctx);
duk_push_array(ctx); /* -> [ ToObject(this) item1 ... itemN arr ] */
/* NOTE: The Array special behaviors are NOT invoked by duk_def_prop_index()
* (which differs from the official algorithm). If no error is thrown, this
* doesn't matter as the length is updated at the end. However, if an error
* is thrown, the length will be unset. That shouldn't matter because the
* caller won't get a reference to the intermediate value.
*/
idx = 0;
idx_last = 0;
for (i = 0; i < n; i++) {
DUK_ASSERT_TOP(ctx, n + 1);
/* [ ToObject(this) item1 ... itemN arr ] */
duk_dup(ctx, i);
h = duk_get_hobject_with_class(ctx, -1, DUK_HOBJECT_CLASS_ARRAY);
if (!h) {
duk_def_prop_index(ctx, -2, idx++, DUK_PROPDESC_FLAGS_WEC);
idx_last = idx;
continue;
}
/* [ ToObject(this) item1 ... itemN arr item(i) ] */
/* FIXME: an array can have length higher than 32 bits; this is not handled
* correctly now (also len is signed so length above 2**31-1 will have trouble.
*/
len = duk_get_length(ctx, -1);
for (j = 0; j < len; j++) {
if (duk_get_prop_index(ctx, -1, j)) {
/* [ ToObject(this) item1 ... itemN arr item(i) item(i)[j] ] */
duk_def_prop_index(ctx, -3, idx++, DUK_PROPDESC_FLAGS_WEC);
idx_last = idx;
} else {
/* XXX: according to E5.1 Section 15.4.4.4 nonexistent trailing
* elements do not affect 'length' but test262 disagrees. Work
* as E5.1 mandates for now and don't touch idx_last.
*/
idx++;
duk_pop(ctx);
}
}
duk_pop(ctx);
}
duk_push_number(ctx, (double) idx_last);
duk_def_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_W);
DUK_ASSERT_TOP(ctx, n + 1);
return 1;
}
请发表评论