Browse Source

Avoid value stack churn for array .length coercion

pull/862/head
Sami Vaarala 8 years ago
parent
commit
72a6f8d54f
  1. 62
      src/duk_hobject_props.c
  2. 3
      src/duk_js_ops.c

62
src/duk_hobject_props.c

@ -2925,25 +2925,56 @@ DUK_INTERNAL duk_bool_t duk_hobject_hasprop_raw(duk_hthread *thr, duk_hobject *o
* Used by duk_hobject_putprop(). * Used by duk_hobject_putprop().
*/ */
DUK_LOCAL duk_uint32_t duk__to_new_array_length_checked(duk_hthread *thr) { /* Coerce a new .length candidate to a number and check that it's a valid
duk_context *ctx = (duk_context *) thr; * .length.
*/
DUK_LOCAL duk_uint32_t duk__to_new_array_length_checked(duk_hthread *thr, duk_tval *tv) {
duk_uint32_t res; duk_uint32_t res;
duk_double_t d; duk_double_t d;
/* Input value should be on stack top and will be coerced and #if !defined(DUK_USE_PREFER_SIZE)
* popped. Refuse to update an Array's 'length' to a value #if defined(DUK_USE_FASTINT)
* outside the 32-bit range. Negative zero is accepted as zero. /* When fastints are enabled, the most interesting case is assigning
* a fastint to .length (e.g. arr.length = 0).
*/ */
if (DUK_TVAL_IS_FASTINT(tv)) {
/* Very common case. */
duk_int64_t fi;
fi = DUK_TVAL_GET_FASTINT(tv);
if (fi < 0 || fi > 0xffffffffLL) {
goto fail_range;
}
return (duk_uint32_t) fi;
}
#else /* DUK_USE_FASTINT */
/* When fastints are not enabled, the most interesting case is any
* number.
*/
if (DUK_TVAL_IS_DOUBLE(tv)) {
d = DUK_TVAL_GET_NUMBER(tv);
}
#endif /* DUK_USE_FASTINT */
else
#endif /* !DUK_USE_PREFER_SIZE */
{
/* In all other cases, and when doing a size optimized build,
* fall back to the comprehensive handler.
*/
d = duk_js_tonumber(thr, tv);
}
/* XXX: fastint; avoid value stack! */ /* Refuse to update an Array's 'length' to a value outside the
* 32-bit range. Negative zero is accepted as zero.
d = duk_to_number(ctx, -1); */
res = (duk_uint32_t) d; res = (duk_uint32_t) d;
if ((duk_double_t) res != d) { if ((duk_double_t) res != d) {
DUK_ERROR_RANGE(thr, DUK_STR_INVALID_ARRAY_LENGTH); goto fail_range;
} }
duk_pop(ctx);
return res; return res;
fail_range:
DUK_ERROR_RANGE(thr, DUK_STR_INVALID_ARRAY_LENGTH);
} }
/* Delete elements required by a smaller length, taking into account /* Delete elements required by a smaller length, taking into account
@ -3170,8 +3201,7 @@ DUK_LOCAL duk_bool_t duk__handle_put_array_length(duk_hthread *thr, duk_hobject
*/ */
old_len = a->length; old_len = a->length;
duk_dup(ctx, -1); /* [in_val in_val] */ new_len = duk__to_new_array_length_checked(thr, DUK_GET_TVAL_NEGIDX(ctx, -1));
new_len = duk__to_new_array_length_checked(thr); /* -> [in_val] */
DUK_DDD(DUK_DDDPRINT("old_len=%ld, new_len=%ld", (long) old_len, (long) new_len)); DUK_DDD(DUK_DDDPRINT("old_len=%ld, new_len=%ld", (long) old_len, (long) new_len));
/* /*
@ -4572,11 +4602,11 @@ DUK_INTERNAL void duk_hobject_define_property_internal(duk_hthread *thr, duk_hob
duk_uint32_t prev_len; duk_uint32_t prev_len;
prev_len = ((duk_harray *) obj)->length; prev_len = ((duk_harray *) obj)->length;
#endif #endif
new_len = duk__to_new_array_length_checked(thr); /* pops length */ new_len = duk__to_new_array_length_checked(thr, DUK_GET_TVAL_NEGIDX(ctx, -1));
((duk_harray *) obj)->length = new_len; ((duk_harray *) obj)->length = new_len;
DUK_D(DUK_DPRINT("internal define property for array .length: %ld -> %ld", DUK_D(DUK_DPRINT("internal define property for array .length: %ld -> %ld",
(long) prev_len, (long) ((duk_harray *) obj)->length)); (long) prev_len, (long) ((duk_harray *) obj)->length));
goto no_pop_exit; goto pop_exit;
} }
DUK_DD(DUK_DDPRINT("property already exists but is virtual -> failure")); DUK_DD(DUK_DDPRINT("property already exists but is virtual -> failure"));
goto error_virtual; goto error_virtual;
@ -4622,7 +4652,6 @@ DUK_INTERNAL void duk_hobject_define_property_internal(duk_hthread *thr, duk_hob
pop_exit: pop_exit:
duk_pop(ctx); /* remove in_val */ duk_pop(ctx); /* remove in_val */
no_pop_exit:
return; return;
error_virtual: /* share error message */ error_virtual: /* share error message */
@ -5124,8 +5153,7 @@ void duk_hobject_define_property_helper(duk_context *ctx,
arrlen_old_len = a->length; arrlen_old_len = a->length;
DUK_ASSERT(idx_value >= 0); DUK_ASSERT(idx_value >= 0);
duk_dup(ctx, idx_value); arrlen_new_len = duk__to_new_array_length_checked(thr, DUK_GET_TVAL_POSIDX(ctx, idx_value));
arrlen_new_len = duk__to_new_array_length_checked(thr);
duk_push_u32(ctx, arrlen_new_len); duk_push_u32(ctx, arrlen_new_len);
duk_replace(ctx, idx_value); /* step 3.e: replace 'Desc.[[Value]]' */ duk_replace(ctx, idx_value); /* step 3.e: replace 'Desc.[[Value]]' */

3
src/duk_js_ops.c

@ -213,7 +213,8 @@ DUK_INTERNAL duk_double_t duk_js_tonumber(duk_hthread *thr, duk_tval *tv) {
/* recursive call for a primitive value (guaranteed not to cause second /* recursive call for a primitive value (guaranteed not to cause second
* recursion). * recursion).
*/ */
d = duk_js_tonumber(thr, duk_require_tval(ctx, -1)); DUK_ASSERT(duk_get_tval(ctx, -1) != NULL);
d = duk_js_tonumber(thr, duk_get_tval(ctx, -1));
duk_pop(ctx); duk_pop(ctx);
return d; return d;

Loading…
Cancel
Save