diff --git a/RELEASES.rst b/RELEASES.rst index 1dd69fd5..5ed1fd35 100644 --- a/RELEASES.rst +++ b/RELEASES.rst @@ -1959,6 +1959,8 @@ Planned ES6 and other engines; "\078" is now accepted and is the same as "\u00078", "\8" and "\9" are accepted as literal "8" and "9" (GH-1057) +* Add a fastint check for duk_put_number_list() values (GH-1086) + * Fix Object.prototype.__proto__ handling to use ToObject() coercion rather than requiring an object; this matches ES6 requirements and allows e.g. the expression (123).__proto__ to work (GH-1080) diff --git a/src-input/duk_api_bytecode.c b/src-input/duk_api_bytecode.c index 4daf1eae..1f4b7b64 100644 --- a/src-input/duk_api_bytecode.c +++ b/src-input/duk_api_bytecode.c @@ -487,7 +487,7 @@ static duk_uint8_t *duk__load_func(duk_context *ctx, duk_uint8_t *p, duk_uint8_t duk_double_t val; DUK__ASSERT_LEFT(8); val = DUK_RAW_READ_DOUBLE_BE(p); - DUK_TVAL_SET_NUMBER_CHKFAST(&tv_tmp, val); + DUK_TVAL_SET_NUMBER_CHKFAST_SLOW(&tv_tmp, val); duk_push_tval(ctx, &tv_tmp); break; } diff --git a/src-input/duk_api_object.c b/src-input/duk_api_object.c index a97249b3..a55cc630 100644 --- a/src-input/duk_api_object.c +++ b/src-input/duk_api_object.c @@ -528,13 +528,16 @@ DUK_EXTERNAL void duk_put_function_list(duk_context *ctx, duk_idx_t obj_idx, con DUK_EXTERNAL void duk_put_number_list(duk_context *ctx, duk_idx_t obj_idx, const duk_number_list_entry *numbers) { const duk_number_list_entry *ent = numbers; + duk_tval *tv; DUK_ASSERT_CTX_VALID(ctx); obj_idx = duk_require_normalize_index(ctx, obj_idx); if (ent != NULL) { while (ent->key != NULL) { - duk_push_number(ctx, ent->value); + tv = ((duk_hthread *) ctx)->valstack_top++; + DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(tv)); /* value stack init policy */ + DUK_TVAL_SET_NUMBER_CHKFAST_SLOW(tv, ent->value); /* no need for decref/incref */ duk_put_prop_string(ctx, obj_idx, ent->key); ent++; } diff --git a/src-input/duk_bi_thread.c b/src-input/duk_bi_thread.c index e8106dcc..bef4493e 100644 --- a/src-input/duk_bi_thread.c +++ b/src-input/duk_bi_thread.c @@ -169,7 +169,7 @@ DUK_INTERNAL duk_ret_t duk_bi_thread_resume(duk_context *ctx) { /* lj value1: value */ DUK_ASSERT(thr->valstack_bottom + 1 < thr->valstack_top); DUK_TVAL_SET_TVAL_UPDREF(thr, &thr->heap->lj.value1, &thr->valstack_bottom[1]); /* side effects */ - DUK_TVAL_CHKFAST_INPLACE(&thr->heap->lj.value1); + DUK_TVAL_CHKFAST_INPLACE_SLOW(&thr->heap->lj.value1); thr->heap->lj.iserror = is_error; @@ -288,7 +288,7 @@ DUK_INTERNAL duk_ret_t duk_bi_thread_yield(duk_context *ctx) { /* lj value1: value */ DUK_ASSERT(thr->valstack_bottom < thr->valstack_top); DUK_TVAL_SET_TVAL_UPDREF(thr, &thr->heap->lj.value1, &thr->valstack_bottom[0]); /* side effects */ - DUK_TVAL_CHKFAST_INPLACE(&thr->heap->lj.value1); + DUK_TVAL_CHKFAST_INPLACE_SLOW(&thr->heap->lj.value1); thr->heap->lj.iserror = is_error; diff --git a/src-input/duk_heaphdr.h b/src-input/duk_heaphdr.h index 8d78e755..ca79122b 100644 --- a/src-input/duk_heaphdr.h +++ b/src-input/duk_heaphdr.h @@ -574,7 +574,7 @@ struct duk_heaphdr_string { #define DUK_TVAL_SET_NUMBER_CHKFAST_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ - DUK_TVAL_SET_NUMBER_CHKFAST(tv__dst, (newval)); \ + DUK_TVAL_SET_NUMBER_CHKFAST_FAST(tv__dst, (newval)); \ DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ } while (0) #define DUK_TVAL_SET_DOUBLE_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ @@ -800,7 +800,7 @@ struct duk_heaphdr_string { } while (0) #define DUK_TVAL_SET_NUMBER_CHKFAST_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ duk_tval *tv__dst; tv__dst = (tvptr_dst); \ - DUK_TVAL_SET_NUMBER_CHKFAST(tv__dst, (newval)); \ + DUK_TVAL_SET_NUMBER_CHKFAST_FAST(tv__dst, (newval)); \ DUK_UNREF((thr)); \ } while (0) #define DUK_TVAL_SET_DOUBLE_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ diff --git a/src-input/duk_js_call.c b/src-input/duk_js_call.c index 84e58ed6..f016843f 100644 --- a/src-input/duk_js_call.c +++ b/src-input/duk_js_call.c @@ -1598,7 +1598,7 @@ DUK_LOCAL void duk__handle_call_inner(duk_hthread *thr, tv_funret = thr->valstack_top - 1; #if defined(DUK_USE_FASTINT) /* Explicit check for fastint downgrade. */ - DUK_TVAL_CHKFAST_INPLACE(tv_funret); + DUK_TVAL_CHKFAST_INPLACE_FAST(tv_funret); #endif DUK_TVAL_SET_TVAL_UPDREF(thr, tv_ret, tv_funret); /* side effects */ } else { @@ -1663,7 +1663,7 @@ DUK_LOCAL void duk__handle_call_inner(duk_hthread *thr, tv_funret = thr->valstack_top - 1; #if defined(DUK_USE_FASTINT) /* Explicit check for fastint downgrade. */ - DUK_TVAL_CHKFAST_INPLACE(tv_funret); + DUK_TVAL_CHKFAST_INPLACE_FAST(tv_funret); #endif DUK_TVAL_SET_TVAL_UPDREF(thr, tv_ret, tv_funret); /* side effects */ } @@ -1787,7 +1787,7 @@ DUK_LOCAL void duk__handle_call_error(duk_hthread *thr, DUK_TVAL_SET_TVAL_UPDREF(thr, tv_ret, &thr->heap->lj.value1); /* side effects */ #if defined(DUK_USE_FASTINT) /* Explicit check for fastint downgrade. */ - DUK_TVAL_CHKFAST_INPLACE(tv_ret); + DUK_TVAL_CHKFAST_INPLACE_FAST(tv_ret); #endif duk_set_top(ctx, idx_func + 1); /* XXX: could be eliminated with valstack adjust */ diff --git a/src-input/duk_js_compiler.c b/src-input/duk_js_compiler.c index 1bf553aa..d6521504 100644 --- a/src-input/duk_js_compiler.c +++ b/src-input/duk_js_compiler.c @@ -1861,7 +1861,7 @@ DUK_LOCAL duk_regconst_t duk__getconst(duk_compiler_ctx *comp_ctx) { #if defined(DUK_USE_FASTINT) /* Explicit check for fastint downgrade. */ - DUK_TVAL_CHKFAST_INPLACE(tv1); + DUK_TVAL_CHKFAST_INPLACE_SLOW(tv1); #endif /* Sanity workaround for handling functions with a large number of diff --git a/src-input/duk_js_executor.c b/src-input/duk_js_executor.c index 0314952f..fdb41360 100644 --- a/src-input/duk_js_executor.c +++ b/src-input/duk_js_executor.c @@ -547,7 +547,7 @@ DUK_LOCAL DUK__INLINE_PERF void duk__vm_arith_unary_op(duk_hthread *thr, duk_idx DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&du)); #if defined(DUK_USE_FASTINT) tv = DUK_GET_TVAL_POSIDX(ctx, idx_dst); - DUK_TVAL_SET_NUMBER_CHKFAST_UPDREF(thr, tv, du.d); + DUK_TVAL_SET_NUMBER_CHKFAST_UPDREF(thr, tv, du.d); /* always 'fast', i.e. inlined */ return; #endif } else { @@ -1531,7 +1531,7 @@ DUK_LOCAL duk_small_uint_t duk__handle_return(duk_hthread *thr, DUK_ASSERT(entry_thread != NULL); DUK_ASSERT(thr->valstack_top - 1 >= thr->valstack_bottom); tv1 = thr->valstack_top - 1; - DUK_TVAL_CHKFAST_INPLACE(tv1); /* fastint downgrade check for return values */ + DUK_TVAL_CHKFAST_INPLACE_FAST(tv1); /* fastint downgrade check for return values */ /* * Four possible outcomes: diff --git a/src-input/duk_tval.c b/src-input/duk_tval.c index 964eb526..1d324ec7 100644 --- a/src-input/duk_tval.c +++ b/src-input/duk_tval.c @@ -19,7 +19,7 @@ * See doc/fastint.rst for details. */ -DUK_INTERNAL DUK_ALWAYS_INLINE void duk_tval_set_number_chkfast(duk_tval *tv, duk_double_t x) { +DUK_INTERNAL DUK_ALWAYS_INLINE void duk_tval_set_number_chkfast_fast(duk_tval *tv, duk_double_t x) { duk_double_union du; duk_int64_t i; duk_small_int_t expt; @@ -62,6 +62,10 @@ DUK_INTERNAL DUK_ALWAYS_INLINE void duk_tval_set_number_chkfast(duk_tval *tv, du return; } +DUK_INTERNAL DUK_NOINLINE void duk_tval_set_number_chkfast_slow(duk_tval *tv, duk_double_t x) { + duk_tval_set_number_chkfast_fast(tv, x); +} + /* * Manually optimized number-to-double conversion */ diff --git a/src-input/duk_tval.h b/src-input/duk_tval.h index 6de86bcf..c3d8f385 100644 --- a/src-input/duk_tval.h +++ b/src-input/duk_tval.h @@ -176,15 +176,25 @@ typedef struct { #define DUK_TVAL_SET_I48(tv,i) DUK__TVAL_SET_I48((tv), (i)) #define DUK_TVAL_SET_I32(tv,i) DUK__TVAL_SET_I32((tv), (i)) #define DUK_TVAL_SET_U32(tv,i) DUK__TVAL_SET_U32((tv), (i)) -#define DUK_TVAL_SET_NUMBER_CHKFAST(tv,d) duk_tval_set_number_chkfast((tv), (d)) +#define DUK_TVAL_SET_NUMBER_CHKFAST_FAST(tv,d) duk_tval_set_number_chkfast_fast((tv), (d)) +#define DUK_TVAL_SET_NUMBER_CHKFAST_SLOW(tv,d) duk_tval_set_number_chkfast_slow((tv), (d)) #define DUK_TVAL_SET_NUMBER(tv,d) DUK_TVAL_SET_DOUBLE((tv), (d)) -#define DUK_TVAL_CHKFAST_INPLACE(tv) do { \ +#define DUK_TVAL_CHKFAST_INPLACE_FAST(tv) do { \ duk_tval *duk__tv; \ duk_double_t duk__d; \ duk__tv = (tv); \ if (DUK_TVAL_IS_DOUBLE(duk__tv)) { \ duk__d = DUK_TVAL_GET_DOUBLE(duk__tv); \ - DUK_TVAL_SET_NUMBER_CHKFAST(duk__tv, duk__d); \ + DUK_TVAL_SET_NUMBER_CHKFAST_FAST(duk__tv, duk__d); \ + } \ + } while (0) +#define DUK_TVAL_CHKFAST_INPLACE_SLOW(tv) do { \ + duk_tval *duk__tv; \ + duk_double_t duk__d; \ + duk__tv = (tv); \ + if (DUK_TVAL_IS_DOUBLE(duk__tv)) { \ + duk__d = DUK_TVAL_GET_DOUBLE(duk__tv); \ + DUK_TVAL_SET_NUMBER_CHKFAST_SLOW(duk__tv, duk__d); \ } \ } while (0) #else /* DUK_USE_FASTINT */ @@ -197,9 +207,11 @@ typedef struct { #define DUK_TVAL_SET_I48(tv,i) DUK_TVAL_SET_DOUBLE((tv), (duk_double_t) (i)) /* XXX: fast int-to-double */ #define DUK_TVAL_SET_I32(tv,i) DUK_TVAL_SET_DOUBLE((tv), (duk_double_t) (i)) #define DUK_TVAL_SET_U32(tv,i) DUK_TVAL_SET_DOUBLE((tv), (duk_double_t) (i)) -#define DUK_TVAL_SET_NUMBER_CHKFAST(tv,d) DUK_TVAL_SET_DOUBLE((tv), (d)) +#define DUK_TVAL_SET_NUMBER_CHKFAST_FAST(tv,d) DUK_TVAL_SET_DOUBLE((tv), (d)) +#define DUK_TVAL_SET_NUMBER_CHKFAST_SLOW(tv,d) DUK_TVAL_SET_DOUBLE((tv), (d)) #define DUK_TVAL_SET_NUMBER(tv,d) DUK_TVAL_SET_DOUBLE((tv), (d)) -#define DUK_TVAL_CHKFAST_INPLACE(tv) do { } while (0) +#define DUK_TVAL_CHKFAST_INPLACE_FAST(tv) do { } while (0) +#define DUK_TVAL_CHKFAST_INPLACE_SLOW(tv) do { } while (0) #endif /* DUK_USE_FASTINT */ #define DUK_TVAL_SET_FASTINT(tv,i) DUK_TVAL_SET_I48((tv), (i)) /* alias */ @@ -395,17 +407,28 @@ typedef struct { duk__tv->t = DUK_TAG_FASTINT; \ duk__tv->v.fi = (duk_int64_t) (val); \ } while (0) -#define DUK_TVAL_SET_NUMBER_CHKFAST(tv,d) \ - duk_tval_set_number_chkfast((tv), (d)) +#define DUK_TVAL_SET_NUMBER_CHKFAST_FAST(tv,d) \ + duk_tval_set_number_chkfast_fast((tv), (d)) +#define DUK_TVAL_SET_NUMBER_CHKFAST_SLOW(tv,d) \ + duk_tval_set_number_chkfast_slow((tv), (d)) #define DUK_TVAL_SET_NUMBER(tv,val) \ DUK_TVAL_SET_DOUBLE((tv), (val)) -#define DUK_TVAL_CHKFAST_INPLACE(tv) do { \ +#define DUK_TVAL_CHKFAST_INPLACE_FAST(tv) do { \ duk_tval *duk__tv; \ duk_double_t duk__d; \ duk__tv = (tv); \ if (DUK_TVAL_IS_DOUBLE(duk__tv)) { \ duk__d = DUK_TVAL_GET_DOUBLE(duk__tv); \ - DUK_TVAL_SET_NUMBER_CHKFAST(duk__tv, duk__d); \ + DUK_TVAL_SET_NUMBER_CHKFAST_FAST(duk__tv, duk__d); \ + } \ + } while (0) +#define DUK_TVAL_CHKFAST_INPLACE_SLOW(tv) do { \ + duk_tval *duk__tv; \ + duk_double_t duk__d; \ + duk__tv = (tv); \ + if (DUK_TVAL_IS_DOUBLE(duk__tv)) { \ + duk__d = DUK_TVAL_GET_DOUBLE(duk__tv); \ + DUK_TVAL_SET_NUMBER_CHKFAST_SLOW(duk__tv, duk__d); \ } \ } while (0) #else /* DUK_USE_FASTINT */ @@ -426,9 +449,12 @@ typedef struct { duk__tv->t = DUK_TAG_NUMBER; \ duk__tv->v.d = duk__dblval; \ } while (0) -#define DUK_TVAL_SET_NUMBER_CHKFAST(tv,d) \ +#define DUK_TVAL_SET_NUMBER_CHKFAST_FAST(tv,d) \ + DUK_TVAL_SET_NUMBER((tv), (d)) +#define DUK_TVAL_SET_NUMBER_CHKFAST_SLOW(tv,d) \ DUK_TVAL_SET_NUMBER((tv), (d)) -#define DUK_TVAL_CHKFAST_INPLACE(tv) do { } while (0) +#define DUK_TVAL_CHKFAST_INPLACE_FAST(tv) do { } while (0) +#define DUK_TVAL_CHKFAST_INPLACE_SLOW(tv) do { } while (0) #endif /* DUK_USE_FASTINT */ #define DUK_TVAL_SET_FASTINT(tv,i) \ @@ -588,7 +614,8 @@ DUK_INTERNAL_DECL duk_double_t duk_tval_get_number_unpacked_fastint(duk_tval *tv #define DUK_FASTINT_MAX 0x7fffffffffffLL #define DUK_FASTINT_BITS 48 -DUK_INTERNAL_DECL void duk_tval_set_number_chkfast(duk_tval *tv, duk_double_t x); +DUK_INTERNAL_DECL void duk_tval_set_number_chkfast_fast(duk_tval *tv, duk_double_t x); +DUK_INTERNAL_DECL void duk_tval_set_number_chkfast_slow(duk_tval *tv, duk_double_t x); #endif #endif /* DUK_TVAL_H_INCLUDED */ diff --git a/tests/api/test-put-func-num-list.c b/tests/api/test-put-func-num-list.c index 4e4565ad..35691aa8 100644 --- a/tests/api/test-put-func-num-list.c +++ b/tests/api/test-put-func-num-list.c @@ -2,7 +2,7 @@ *** test_1 (duk_safe_call) after definition, top=0 object -tweak,adjust,frobnicate,FLAG_FOO,FLAG_BAR,FLAG_QUUX,meaning +tweak,adjust,frobnicate,FLAG_FOO,FLAG_BAR,FLAG_QUUX,meaning,nonFast 1 2 4 @@ -13,6 +13,8 @@ adjust, top=3 4 frobnicate, top=6 5 +true +true final top: 0 ==> rc=0, result='undefined' ===*/ @@ -50,6 +52,7 @@ static const duk_number_list_entry my_consts[] = { { "FLAG_BAR", (duk_double_t) (1 << 1) }, { "FLAG_QUUX", (duk_double_t) (1 << 2) }, { "meaning", (duk_double_t) 42.0 }, + { "nonFast", (duk_double_t) 42.1 }, { NULL, 0.0 } }; @@ -85,6 +88,12 @@ static duk_ret_t test_1(duk_context *ctx, void *udata) { "print(MyModule.frobnicate(1, 2, 3, 4, 5, 6));\n" ); + /* Fastint compatible values are fastint downgraded. */ + duk_eval_string_noresult(ctx, + "print(Duktape.info(MyModule.meaning)[1] === Duktape.info(MyModule.FLAG_FOO)[1])\n" /* match: both are fastints */ + "print(Duktape.info(MyModule.meaning)[1] !== Duktape.info(MyModule.nonFast)[1])\n" /* no match: nonFast is not fastint */ + ); + printf("final top: %ld\n", (long) duk_get_top(ctx)); return 0; }