Browse Source

Merge pull request #582 from svaarala/perf-raw-duk-get-tval-accessors

Use raw value stack accessors internally when it's safe to do so
pull/589/head
Sami Vaarala 9 years ago
parent
commit
f8376441f9
  1. 3
      RELEASES.rst
  2. 18
      src/duk_api_internal.h
  3. 12
      src/duk_hobject_props.c
  4. 2
      src/duk_js_call.c
  5. 36
      src/duk_js_compiler.c
  6. 18
      src/duk_js_executor.c
  7. 18
      src/duk_js_ops.c

3
RELEASES.rst

@ -1405,6 +1405,9 @@ Planned
* Change OS string (visible in Duktape.env) from "ios" to "osx" for non-phone
targets (GH-570, GH-571)
* Internal performance improvement: use raw value stack accessors internally
when it's safe to do so (GH-582)
2.0.0 (XXXX-XX-XX)
------------------

18
src/duk_api_internal.h

@ -173,4 +173,22 @@ DUK_INTERNAL_DECL void duk_xdef_prop_stridx_thrower(duk_context *ctx, duk_idx_t
/* Set object 'length'. */
DUK_INTERNAL_DECL void duk_set_length(duk_context *ctx, duk_idx_t index, duk_size_t length);
/* Raw internal valstack access macros: access is unsafe so call site
* must have a guarantee that the index is valid. When that is the case,
* using these macro results in faster and smaller code than duk_get_tval().
* Both 'ctx' and 'idx' are evaluted multiple times, but only for asserts.
*/
#define DUK_ASSERT_VALID_NEGIDX(ctx,idx) \
(DUK_ASSERT_EXPR((idx) < 0), DUK_ASSERT_EXPR(duk_is_valid_index((ctx), (idx))))
#define DUK_ASSERT_VALID_POSIDX(ctx,idx) \
(DUK_ASSERT_EXPR((idx) >= 0), DUK_ASSERT_EXPR(duk_is_valid_index((ctx), (idx))))
#define DUK_GET_TVAL_NEGIDX(ctx,idx) \
(DUK_ASSERT_VALID_NEGIDX((ctx),(idx)), ((duk_hthread *) (ctx))->valstack_top + (idx))
#define DUK_GET_TVAL_POSIDX(ctx,idx) \
(DUK_ASSERT_VALID_POSIDX((ctx),(idx)), ((duk_hthread *) (ctx))->valstack_bottom + (idx))
#define DUK_GET_HOBJECT_NEGIDX(ctx,idx) \
(DUK_ASSERT_VALID_NEGIDX((ctx),(idx)), DUK_TVAL_GET_OBJECT(((duk_hthread *) (ctx))->valstack_top + (idx)))
#define DUK_GET_HOBJECT_POSIDX(ctx,idx) \
(DUK_ASSERT_VALID_POSIDX((ctx),(idx)), DUK_TVAL_GET_OBJECT(((duk_hthread *) (ctx))->valstack_bottom + (idx)))
#endif /* DUK_API_INTERNAL_H_INCLUDED */

12
src/duk_hobject_props.c

@ -4353,7 +4353,7 @@ DUK_INTERNAL duk_bool_t duk_hobject_delprop(duk_hthread *thr, duk_tval *tv_obj,
duk_push_tval(ctx, tv_obj);
duk_push_tval(ctx, tv_key);
tv_obj = duk_get_tval(ctx, -2);
tv_obj = DUK_GET_TVAL_NEGIDX(ctx, -2);
if (DUK_TVAL_IS_OBJECT(tv_obj)) {
duk_hobject *obj = DUK_TVAL_GET_OBJECT(tv_obj);
DUK_ASSERT(obj != NULL);
@ -4745,7 +4745,11 @@ DUK_INTERNAL void duk_hobject_set_length(duk_hthread *thr, duk_hobject *obj, duk
duk_push_hobject(ctx, obj);
duk_push_hstring_stridx(ctx, DUK_STRIDX_LENGTH);
duk_push_u32(ctx, length);
(void) duk_hobject_putprop(thr, duk_get_tval(ctx, -3), duk_get_tval(ctx, -2), duk_get_tval(ctx, -1), 0);
(void) duk_hobject_putprop(thr,
DUK_GET_TVAL_NEGIDX(ctx, -3),
DUK_GET_TVAL_NEGIDX(ctx, -2),
DUK_GET_TVAL_NEGIDX(ctx, -1),
0);
duk_pop_n(ctx, 3);
}
@ -4758,7 +4762,9 @@ DUK_INTERNAL duk_uint32_t duk_hobject_get_length(duk_hthread *thr, duk_hobject *
duk_double_t val;
duk_push_hobject(ctx, obj);
duk_push_hstring_stridx(ctx, DUK_STRIDX_LENGTH);
(void) duk_hobject_getprop(thr, duk_get_tval(ctx, -2), duk_get_tval(ctx, -1));
(void) duk_hobject_getprop(thr,
DUK_GET_TVAL_NEGIDX(ctx, -2),
DUK_GET_TVAL_NEGIDX(ctx, -1));
val = duk_to_number(ctx, -1);
duk_pop_n(ctx, 3);
if (val >= 0.0 && val < DUK_DOUBLE_2TO32) {

2
src/duk_js_call.c

@ -731,7 +731,7 @@ DUK_LOCAL duk_hobject *duk__nonbound_func_lookup(duk_context *ctx,
for (;;) {
/* Use loop to minimize code size of relookup after bound function case */
tv_func = duk_get_tval(ctx, idx_func);
tv_func = DUK_GET_TVAL_POSIDX(ctx, idx_func);
DUK_ASSERT(tv_func != NULL);
if (DUK_TVAL_IS_OBJECT(tv_func)) {

36
src/duk_js_compiler.c

@ -512,23 +512,23 @@ DUK_LOCAL void duk__init_func_valstack_slots(duk_compiler_ctx *comp_ctx) {
duk_push_array(ctx);
func->consts_idx = entry_top + 1;
func->h_consts = duk_get_hobject(ctx, entry_top + 1);
func->h_consts = DUK_GET_HOBJECT_POSIDX(ctx, entry_top + 1);
DUK_ASSERT(func->h_consts != NULL);
duk_push_array(ctx);
func->funcs_idx = entry_top + 2;
func->h_funcs = duk_get_hobject(ctx, entry_top + 2);
func->h_funcs = DUK_GET_HOBJECT_POSIDX(ctx, entry_top + 2);
DUK_ASSERT(func->h_funcs != NULL);
DUK_ASSERT(func->fnum_next == 0);
duk_push_array(ctx);
func->decls_idx = entry_top + 3;
func->h_decls = duk_get_hobject(ctx, entry_top + 3);
func->h_decls = DUK_GET_HOBJECT_POSIDX(ctx, entry_top + 3);
DUK_ASSERT(func->h_decls != NULL);
duk_push_array(ctx);
func->labelnames_idx = entry_top + 4;
func->h_labelnames = duk_get_hobject(ctx, entry_top + 4);
func->h_labelnames = DUK_GET_HOBJECT_POSIDX(ctx, entry_top + 4);
DUK_ASSERT(func->h_labelnames != NULL);
duk_push_dynamic_buffer(ctx, 0);
@ -539,12 +539,12 @@ DUK_LOCAL void duk__init_func_valstack_slots(duk_compiler_ctx *comp_ctx) {
duk_push_array(ctx);
func->argnames_idx = entry_top + 6;
func->h_argnames = duk_get_hobject(ctx, entry_top + 6);
func->h_argnames = DUK_GET_HOBJECT_POSIDX(ctx, entry_top + 6);
DUK_ASSERT(func->h_argnames != NULL);
duk_push_object_internal(ctx);
func->varmap_idx = entry_top + 7;
func->h_varmap = duk_get_hobject(ctx, entry_top + 7);
func->h_varmap = DUK_GET_HOBJECT_POSIDX(ctx, entry_top + 7);
DUK_ASSERT(func->h_varmap != NULL);
}
@ -570,7 +570,7 @@ DUK_LOCAL void duk__reset_func_for_pass2(duk_compiler_ctx *comp_ctx) {
/* truncated in case pass 3 needed */
duk_push_object_internal(ctx);
duk_replace(ctx, func->varmap_idx);
func->h_varmap = duk_get_hobject(ctx, func->varmap_idx);
func->h_varmap = DUK_GET_HOBJECT_POSIDX(ctx, func->varmap_idx);
DUK_ASSERT(func->h_varmap != NULL);
}
@ -588,7 +588,7 @@ DUK_LOCAL duk_int_t duk__cleanup_varmap(duk_compiler_ctx *comp_ctx) {
/* [ ... varmap ] */
h_varmap = duk_get_hobject(ctx, -1);
h_varmap = DUK_GET_HOBJECT_NEGIDX(ctx, -1);
DUK_ASSERT(h_varmap != NULL);
ret = 0;
@ -655,7 +655,7 @@ DUK_LOCAL void duk__convert_to_func_template(duk_compiler_ctx *comp_ctx, duk_boo
/* Valstack should suffice here, required on function valstack init */
(void) duk_push_compiledfunction(ctx);
h_res = (duk_hcompiledfunction *) duk_get_hobject(ctx, -1); /* XXX: specific getter */
h_res = (duk_hcompiledfunction *) DUK_GET_HOBJECT_NEGIDX(ctx, -1); /* XXX: specific getter */
DUK_ASSERT(h_res != NULL);
if (func->is_function) {
@ -1892,7 +1892,7 @@ DUK_LOCAL duk_regconst_t duk__getconst(duk_compiler_ctx *comp_ctx) {
n = (duk_int_t) duk_get_length(ctx, f->consts_idx);
tv1 = duk_get_tval(ctx, -1);
tv1 = DUK_GET_TVAL_NEGIDX(ctx, -1);
DUK_ASSERT(tv1 != NULL);
#if defined(DUK_USE_FASTINT)
@ -1968,7 +1968,7 @@ duk_regconst_t duk__ispec_toregconst_raw(duk_compiler_ctx *comp_ctx,
case DUK_ISPEC_VALUE: {
duk_tval *tv;
tv = duk_get_tval(ctx, x->valstack_idx);
tv = DUK_GET_TVAL_POSIDX(ctx, x->valstack_idx);
DUK_ASSERT(tv != NULL);
switch (DUK_TVAL_GET_TAG(tv)) {
@ -2158,8 +2158,8 @@ DUK_LOCAL void duk__ivalue_toplain_raw(duk_compiler_ctx *comp_ctx, duk_ivalue *x
/* inline arithmetic check for constant values */
/* XXX: use the exactly same arithmetic function here as in executor */
if (x->x1.t == DUK_ISPEC_VALUE && x->x2.t == DUK_ISPEC_VALUE && x->t == DUK_IVAL_ARITH) {
tv1 = duk_get_tval(ctx, x->x1.valstack_idx);
tv2 = duk_get_tval(ctx, x->x2.valstack_idx);
tv1 = DUK_GET_TVAL_POSIDX(ctx, x->x1.valstack_idx);
tv2 = DUK_GET_TVAL_POSIDX(ctx, x->x2.valstack_idx);
DUK_ASSERT(tv1 != NULL);
DUK_ASSERT(tv2 != NULL);
@ -3593,12 +3593,13 @@ DUK_LOCAL void duk__expr_nud(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
duk__expr(comp_ctx, res, DUK__BP_MULTIPLICATIVE /*rbp_flags*/); /* UnaryExpression */
if (res->t == DUK_IVAL_PLAIN && res->x1.t == DUK_ISPEC_VALUE &&
duk_is_number(ctx, res->x1.valstack_idx)) {
/* this optimization is important to handle negative literals (which are not directly
* provided by the lexical grammar
/* this optimization is important to handle negative literals
* (which are not directly provided by the lexical grammar)
*/
duk_tval *tv_num = duk_get_tval(ctx, res->x1.valstack_idx);
duk_tval *tv_num;
duk_double_union du;
tv_num = DUK_GET_TVAL_POSIDX(ctx, res->x1.valstack_idx);
DUK_ASSERT(tv_num != NULL);
DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_num));
du.d = DUK_TVAL_GET_NUMBER(tv_num);
@ -3621,8 +3622,9 @@ DUK_LOCAL void duk__expr_nud(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
/* Very minimal inlining to handle common idioms '!0' and '!1',
* and also boolean arguments like '!false' and '!true'.
*/
duk_tval *tv_val = duk_get_tval(ctx, res->x1.valstack_idx);
duk_tval *tv_val;
tv_val = DUK_GET_TVAL_POSIDX(ctx, res->x1.valstack_idx);
DUK_ASSERT(tv_val != NULL);
if (DUK_TVAL_IS_NUMBER(tv_val)) {
duk_double_t d;

18
src/duk_js_executor.c

@ -422,6 +422,8 @@ DUK_LOCAL void duk__vm_arith_unary_op(duk_hthread *thr, duk_tval *tv_x, duk_idx_
DUK_ASSERT(thr != NULL);
DUK_ASSERT(ctx != NULL);
DUK_ASSERT(opcode == DUK_EXTRAOP_UNM || opcode == DUK_EXTRAOP_UNP);
DUK_ASSERT(tv_x != NULL);
DUK_ASSERT(idx_x >= 0);
#if defined(DUK_USE_FASTINT)
if (DUK_TVAL_IS_FASTINT(tv_x)) {
@ -449,7 +451,7 @@ DUK_LOCAL void duk__vm_arith_unary_op(duk_hthread *thr, duk_tval *tv_x, duk_idx_
if (!DUK_TVAL_IS_NUMBER(tv_x)) {
duk_to_number(ctx, idx_x); /* side effects, perform in-place */
tv_x = duk_get_tval(ctx, idx_x);
tv_x = DUK_GET_TVAL_POSIDX(ctx, idx_x);
DUK_ASSERT(tv_x != NULL);
DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_x));
}
@ -726,7 +728,7 @@ DUK_LOCAL void duk__handle_catch(duk_hthread *thr, duk_size_t cat_idx, duk_tval
DUK_HOBJECT_FLAG_EXTENSIBLE |
DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DECENV),
act_lex_env);
new_env = duk_get_hobject(ctx, -1);
new_env = DUK_GET_HOBJECT_NEGIDX(ctx, -1);
DUK_ASSERT(new_env != NULL);
DUK_DDD(DUK_DDDPRINT("new_env allocated: %!iO", (duk_heaphdr *) new_env));
@ -2797,12 +2799,12 @@ DUK_LOCAL DUK_NOINLINE void duk__js_execute_bytecode_inner(duk_hthread *entry_th
} else {
duk_push_tval(ctx, DUK__REGCONSTP(c));
}
tv1 = duk_get_tval(ctx, -1);
tv1 = DUK_GET_TVAL_NEGIDX(ctx, -1);
act = thr->callstack + thr->callstack_top - 1;
if (duk_js_declvar_activation(thr, act, name, tv1, prop_flags, is_func_decl)) {
/* already declared, must update binding value */
tv1 = duk_get_tval(ctx, -1);
tv1 = DUK_GET_TVAL_NEGIDX(ctx, -1);
duk_js_putvar_activation(thr, act, name, tv1, DUK__STRICT());
}
@ -3591,7 +3593,7 @@ DUK_LOCAL DUK_NOINLINE void duk__js_execute_bytecode_inner(duk_hthread *entry_th
DUK_DDD(DUK_DDDPRINT("activating object env: %!iT",
(duk_tval *) duk_get_tval(ctx, -1)));
DUK_ASSERT(act->lex_env != NULL);
new_env = duk_get_hobject(ctx, -1);
new_env = DUK_GET_HOBJECT_NEGIDX(ctx, -1);
DUK_ASSERT(new_env != NULL);
act = thr->callstack + thr->callstack_top - 1; /* relookup (side effects) */
@ -3750,7 +3752,7 @@ DUK_LOCAL DUK_NOINLINE void duk__js_execute_bytecode_inner(duk_hthread *entry_th
}
duk_push_number(ctx, y);
tv1 = duk_get_tval(ctx, -1);
tv1 = DUK_GET_TVAL_NEGIDX(ctx, -1);
DUK_ASSERT(tv1 != NULL);
duk_js_putvar_activation(thr, act, name, tv1, DUK__STRICT());
duk_pop(ctx);
@ -3804,7 +3806,7 @@ DUK_LOCAL DUK_NOINLINE void duk__js_execute_bytecode_inner(duk_hthread *entry_th
}
duk_push_number(ctx, y);
tv_val = duk_get_tval(ctx, -1);
tv_val = DUK_GET_TVAL_NEGIDX(ctx, -1);
DUK_ASSERT(tv_val != NULL);
tv_obj = DUK__REGCONSTP(b);
tv_key = DUK__REGCONSTP(c);
@ -3944,7 +3946,7 @@ DUK_LOCAL DUK_NOINLINE void duk__js_execute_bytecode_inner(duk_hthread *entry_th
act = thr->callstack + thr->callstack_top - 1;
if (duk_js_getvar_activation(thr, act, name, 0 /*throw*/)) {
/* -> [... val this] */
tv = duk_get_tval(ctx, -2);
tv = DUK_GET_TVAL_NEGIDX(ctx, -2);
duk_push_hstring(ctx, duk_js_typeof(thr, tv));
duk_replace(ctx, (duk_idx_t) b);
duk_pop_2(ctx);

18
src/duk_js_ops.c

@ -730,7 +730,10 @@ DUK_INTERNAL duk_bool_t duk_js_equals_helper(duk_hthread *thr, duk_tval *tv_x, d
DUK_ASSERT(DUK_TVAL_GET_BOOLEAN(tv_y) == 0 || DUK_TVAL_GET_BOOLEAN(tv_y) == 1);
duk_push_tval(ctx, tv_x);
duk_push_int(ctx, DUK_TVAL_GET_BOOLEAN(tv_y));
rc = duk_js_equals_helper(thr, duk_get_tval(ctx, -2), duk_get_tval(ctx, -1), 0 /*flags:nonstrict*/);
rc = duk_js_equals_helper(thr,
DUK_GET_TVAL_NEGIDX(ctx, -2),
DUK_GET_TVAL_NEGIDX(ctx, -1),
0 /*flags:nonstrict*/);
duk_pop_2(ctx);
return rc;
}
@ -748,7 +751,10 @@ DUK_INTERNAL duk_bool_t duk_js_equals_helper(duk_hthread *thr, duk_tval *tv_x, d
duk_push_tval(ctx, tv_x);
duk_push_tval(ctx, tv_y);
duk_to_primitive(ctx, -2, DUK_HINT_NONE); /* apparently no hint? */
rc = duk_js_equals_helper(thr, duk_get_tval(ctx, -2), duk_get_tval(ctx, -1), 0 /*flags:nonstrict*/);
rc = duk_js_equals_helper(thr,
DUK_GET_TVAL_NEGIDX(ctx, -2),
DUK_GET_TVAL_NEGIDX(ctx, -1),
0 /*flags:nonstrict*/);
duk_pop_2(ctx);
return rc;
}
@ -903,8 +909,8 @@ DUK_INTERNAL duk_bool_t duk_js_compare_helper(duk_hthread *thr, duk_tval *tv_x,
}
/* Note: reuse variables */
tv_x = duk_get_tval(ctx, -2);
tv_y = duk_get_tval(ctx, -1);
tv_x = DUK_GET_TVAL_NEGIDX(ctx, -2);
tv_y = DUK_GET_TVAL_NEGIDX(ctx, -1);
if (DUK_TVAL_IS_STRING(tv_x) && DUK_TVAL_IS_STRING(tv_y)) {
duk_hstring *h1 = DUK_TVAL_GET_STRING(tv_x);
@ -1213,7 +1219,9 @@ DUK_INTERNAL duk_bool_t duk_js_in(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv
duk_require_type_mask(ctx, -1, DUK_TYPE_MASK_OBJECT | DUK_TYPE_MASK_LIGHTFUNC);
duk_to_string(ctx, -2); /* coerce lval with ToString() */
retval = duk_hobject_hasprop(thr, duk_get_tval(ctx, -1), duk_get_tval(ctx, -2));
retval = duk_hobject_hasprop(thr,
DUK_GET_TVAL_NEGIDX(ctx, -1),
DUK_GET_TVAL_NEGIDX(ctx, -2));
duk_pop_2(ctx);
return retval;

Loading…
Cancel
Save