From 6b2ed7d833ce7e160ec20bbe880b48f9c4500134 Mon Sep 17 00:00:00 2001 From: Sami Vaarala Date: Tue, 25 Mar 2014 22:47:25 +0200 Subject: [PATCH] rework shuffling to support switched source/target roles for each of A, B, C, add role flags to EXTRAOPs for shuffling --- src/duk_js_compiler.c | 303 ++++++++++++++++++++++++++++++------------ 1 file changed, 219 insertions(+), 84 deletions(-) diff --git a/src/duk_js_compiler.c b/src/duk_js_compiler.c index 62b8ca35..b5ba542f 100644 --- a/src/duk_js_compiler.c +++ b/src/duk_js_compiler.c @@ -96,10 +96,10 @@ static void duk__emit_a(duk_compiler_ctx *comp_ctx, int op_flags, int a); #endif static void duk__emit_a_bc(duk_compiler_ctx *comp_ctx, int op, int a, int bc); static void duk__emit_abc(duk_compiler_ctx *comp_ctx, int op, int abc); -static void duk__emit_extraop_b_c(duk_compiler_ctx *comp_ctx, int extraop, int b, int c); -static void duk__emit_extraop_b(duk_compiler_ctx *comp_ctx, int extraop, int b); +static void duk__emit_extraop_b_c(duk_compiler_ctx *comp_ctx, int extraop_flags, int b, int c); +static void duk__emit_extraop_b(duk_compiler_ctx *comp_ctx, int extraop_flags, int b); static void duk__emit_extraop_bc(duk_compiler_ctx *comp_ctx, int extraop, int bc); -static void duk__emit_extraop_only(duk_compiler_ctx *comp_ctx, int extraop); +static void duk__emit_extraop_only(duk_compiler_ctx *comp_ctx, int extraop_flags); static void duk__emit_loadint(duk_compiler_ctx *comp_ctx, int reg, int val); static void duk__emit_jump(duk_compiler_ctx *comp_ctx, int target_pc); static int duk__emit_jump_empty(duk_compiler_ctx *comp_ctx); @@ -928,9 +928,18 @@ static void duk__convert_to_func_template(duk_compiler_ctx *comp_ctx) { * case when the slot in question (A, B, C) is used in the standard way and * for opcodes the emission helpers explicitly understand (like DUK_OP_CALL). * - * If a slot is used in a non-standard way the caller must ensure that the - * raw value fits into the corresponding slot so as to not trigger shuffling. - * The caller must set a "no shuffle" flag to ensure compilation fails if + * The standard way is that: + * - slot A is a target register + * - slot B is a source register/constant + * - slot C is a source register/constant + * + * If a slot is used in a non-standard way the caller must indicate this + * somehow. If a slot is used as a target instead of a source (or vice + * versa), this can be indicated with a flag to trigger proper shuffling + * (e.g. DUK__EMIT_FLAG_B_IS_TARGET). If the value in the slot is not + * register/const related at all, the caller must ensure that the raw value + * fits into the corresponding slot so as to not trigger shuffling. The + * caller must set a "no shuffle" flag to ensure compilation fails if * shuffling were to be triggered because of an internal error. * * For slots B and C the raw slot size is 9 bits but one bit is reserved for @@ -946,6 +955,9 @@ static void duk__convert_to_func_template(duk_compiler_ctx *comp_ctx) { #define DUK__EMIT_FLAG_NO_SHUFFLE_A (1 << 8) #define DUK__EMIT_FLAG_NO_SHUFFLE_B (1 << 9) #define DUK__EMIT_FLAG_NO_SHUFFLE_C (1 << 10) +#define DUK__EMIT_FLAG_A_IS_SOURCE (1 << 11) /* slot A is a source (default: target) */ +#define DUK__EMIT_FLAG_B_IS_TARGET (1 << 12) /* slot B is a target (default: source) */ +#define DUK__EMIT_FLAG_C_IS_TARGET (1 << 13) /* slot C is a target (default: source) */ /* FIXME: clarify on when and where DUK__CONST_MARKER is allowed */ /* FIXME: opcode specific assertions on when consts are allowed */ @@ -999,18 +1011,66 @@ static void duk__emit_op_only(duk_compiler_ctx *comp_ctx, int op) { static void duk__emit_a_b_c(duk_compiler_ctx *comp_ctx, int op_flags, int a, int b, int c) { duk_instr ins = 0; + duk_int_t a_out = 0; + duk_int_t b_out = 0; + duk_int_t c_out = 0; duk_int_t tmp; - /* FIXME: rely on max temp/const checks; if they don't exceed BC - * limit, then nothing here can too (i.e. just assert for it)? + /* We could rely on max temp/const checks: if they don't exceed BC + * limit, nothing here can either (just asserts would be enough). + * Currently we check for the limits, which provides additional + * protection against creating invalid bytecode due to compiler + * bugs. */ DUK_ASSERT((op_flags & 0xff) >= DUK_BC_OP_MIN && (op_flags & 0xff) <= DUK_BC_OP_MAX); + /* Input shuffling happens before the actual operation, while output + * shuffling happens afterwards. Output shuffling decisions are still + * made at the same time to reduce branch clutter; output shuffle decisions + * are recorded into X_out variables. + */ + + /* Slot A */ + + if (a <= DUK_BC_A_MAX) { + ; + } else if (op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_A) { + DUK_DPRINT("out of regs: 'a' (reg) needs shuffling but shuffle prohibited, a: %d", (int) a); + goto error_outofregs; + } else if (a <= DUK_BC_BC_MAX) { + comp_ctx->curr_func.needs_shuffle = 1; + tmp = comp_ctx->curr_func.shuffle1; + if (op_flags & DUK__EMIT_FLAG_A_IS_SOURCE) { + duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_LDREG, tmp, a)); + } else { + duk_small_int_t op = op_flags & 0xff; + if (op == DUK_OP_CSVAR || op == DUK_OP_CSREG || op == DUK_OP_CSPROP) { + /* Special handling for call setup instructions. The target + * is expressed indirectly, but there is no output shuffling. + */ + DUK_ASSERT((op_flags & DUK__EMIT_FLAG_A_IS_SOURCE) == 0); + duk__emit_loadint(comp_ctx, tmp, a); + DUK_ASSERT(DUK_OP_CSVARI == DUK_OP_CSVAR + 1); + DUK_ASSERT(DUK_OP_CSREGI == DUK_OP_CSREG + 1); + DUK_ASSERT(DUK_OP_CSPROPI == DUK_OP_CSPROP + 1); + op_flags++; /* indirect opcode follows direct */ + } else { + /* Output shuffle needed after main operation */ + a_out = a; + } + } + a = tmp; + } else { + DUK_DPRINT("out of regs: 'a' (reg) needs shuffling but does not fit into BC, a: %d", (int) a); + goto error_outofregs; + } + /* Slot B */ if (b & DUK__CONST_MARKER) { DUK_ASSERT((op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_B) == 0); + DUK_ASSERT((op_flags & DUK__EMIT_FLAG_B_IS_TARGET) == 0); DUK_ASSERT((op_flags & 0xff) != DUK_OP_CALL); DUK_ASSERT((op_flags & 0xff) != DUK_OP_NEW); b = b & ~DUK__CONST_MARKER; @@ -1018,36 +1078,44 @@ static void duk__emit_a_b_c(duk_compiler_ctx *comp_ctx, int op_flags, int a, int ins |= DUK_ENC_OP_A_B_C(0, 0, 0x100, 0); /* const flag for B */ } else if (b <= DUK_BC_BC_MAX) { comp_ctx->curr_func.needs_shuffle = 1; - tmp = comp_ctx->curr_func.shuffle1; + tmp = comp_ctx->curr_func.shuffle2; duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_LDCONST, tmp, b)); b = tmp; } else { + DUK_DPRINT("out of regs: 'b' (const) needs shuffling but does not fit into BC, b: %d", (int) b); goto error_outofregs; } } else { - if (op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_B) { + if (b <= 0xff) { + ; + } else if (op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_B) { if (b > DUK_BC_B_MAX) { + /* Note: 0xff != DUK_BC_B_MAX */ + DUK_DPRINT("out of regs: 'b' (reg) needs shuffling but shuffle prohibited, b: %d", (int) b); goto error_outofregs; } - } else if (b <= 0xff) { - ; } else if (b <= DUK_BC_BC_MAX) { - duk_small_int_t op = op_flags & 0xff; - comp_ctx->curr_func.needs_shuffle = 1; - tmp = comp_ctx->curr_func.shuffle1; - - if (op == DUK_OP_CALL || op == DUK_OP_NEW) { - /* Special handling for CALL/NEW shuffling. */ - duk__emit_loadint(comp_ctx, tmp, b); - DUK_ASSERT(DUK_OP_CALLI == DUK_OP_CALL + 1); - DUK_ASSERT(DUK_OP_NEWI == DUK_OP_NEW + 1); - op_flags++; /* indirect opcode follows direct */ + tmp = comp_ctx->curr_func.shuffle2; + if (op_flags & DUK__EMIT_FLAG_B_IS_TARGET) { + /* Output shuffle needed after main operation */ + b_out = b; } else { - duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_LDREG, tmp, b)); + duk_small_int_t op = op_flags & 0xff; + if (op == DUK_OP_CALL || op == DUK_OP_NEW) { + /* Special handling for CALL/NEW shuffling. */ + DUK_ASSERT((op_flags & DUK__EMIT_FLAG_B_IS_TARGET) == 0); + duk__emit_loadint(comp_ctx, tmp, b); + DUK_ASSERT(DUK_OP_CALLI == DUK_OP_CALL + 1); + DUK_ASSERT(DUK_OP_NEWI == DUK_OP_NEW + 1); + op_flags++; /* indirect opcode follows direct */ + } else { + duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_LDREG, tmp, b)); + } } b = tmp; } else { + DUK_DPRINT("out of regs: 'b' (reg) needs shuffling but does not fit into BC, b: %d", (int) b); goto error_outofregs; } } @@ -1056,66 +1124,74 @@ static void duk__emit_a_b_c(duk_compiler_ctx *comp_ctx, int op_flags, int a, int if (c & DUK__CONST_MARKER) { DUK_ASSERT((op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_C) == 0); + DUK_ASSERT((op_flags & DUK__EMIT_FLAG_C_IS_TARGET) == 0); c = c & ~DUK__CONST_MARKER; if (c <= 0xff) { ins |= DUK_ENC_OP_A_B_C(0, 0, 0, 0x100); /* const flag for C */ } else if (c <= DUK_BC_BC_MAX) { comp_ctx->curr_func.needs_shuffle = 1; - tmp = comp_ctx->curr_func.shuffle2; + tmp = comp_ctx->curr_func.shuffle3; duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_LDCONST, tmp, c)); c = tmp; } else { + DUK_DPRINT("out of regs: 'c' (const) needs shuffling but does not fit into BC, c: %d", (int) c); goto error_outofregs; } } else { - if (op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_C) { + if (c <= 0xff) { + ; + } else if (op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_C) { if (c > DUK_BC_C_MAX) { + /* Note: 0xff != DUK_BC_C_MAX */ + DUK_DPRINT("out of regs: 'c' (reg) needs shuffling but shuffle prohibited, c: %d", (int) c); goto error_outofregs; } - } else if (c <= 0xff) { - ; - } else if (b <= DUK_BC_BC_MAX) { + } else if (c <= DUK_BC_BC_MAX) { comp_ctx->curr_func.needs_shuffle = 1; - tmp = comp_ctx->curr_func.shuffle2; - duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_LDREG, tmp, c)); + tmp = comp_ctx->curr_func.shuffle3; + if (op_flags & DUK__EMIT_FLAG_C_IS_TARGET) { + /* Output shuffle needed after main operation */ + c_out = c; + } else { + duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_LDREG, tmp, c)); + } c = tmp; } else { + DUK_DPRINT("out of regs: 'c' (reg) needs shuffling but does not fit into BC, c: %d", (int) c); goto error_outofregs; } } - /* Slot A */ + /* Main operation */ - if (a <= DUK_BC_A_MAX) { - ins |= DUK_ENC_OP_A_B_C(op_flags & 0xff, a, b, c); - duk__emit(comp_ctx, ins); - } else if (op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_A) { - goto error_outofregs; - } else if (a <= DUK_BC_BC_MAX) { - duk_small_int_t op = op_flags & 0xff; + DUK_ASSERT(a >= DUK_BC_A_MIN && a <= DUK_BC_A_MAX); + DUK_ASSERT(b >= DUK_BC_B_MIN && b <= DUK_BC_B_MAX); + DUK_ASSERT(c >= DUK_BC_C_MIN && c <= DUK_BC_C_MAX); - comp_ctx->curr_func.needs_shuffle = 1; - tmp = comp_ctx->curr_func.shuffle3; + ins |= DUK_ENC_OP_A_B_C(op_flags & 0xff, a, b, c); + duk__emit(comp_ctx, ins); - if (op == DUK_OP_CSVAR || op == DUK_OP_CSREG || op == DUK_OP_CSPROP) { - /* Special handling for call setup instructions. */ - comp_ctx->curr_func.needs_shuffle = 1; - tmp = comp_ctx->curr_func.shuffle3; + if (a_out || b_out || c_out) { + DUK_DPRINT("output shuffled: op_flags=%04x, a=%d, b=%d, c=%d, a_out=%d, b_out=%d, c_out=%d", + (int) op_flags, (int) a, (int) b, (int) c, (int) a_out, (int) b_out, (int) c_out); + } - duk__emit_loadint(comp_ctx, tmp, a); - DUK_ASSERT(DUK_OP_CSVARI == DUK_OP_CSVAR + 1); - DUK_ASSERT(DUK_OP_CSREGI == DUK_OP_CSREG + 1); - DUK_ASSERT(DUK_OP_CSPROPI == DUK_OP_CSPROP + 1); - ins |= DUK_ENC_OP_A_B_C(op + 1, tmp, b, c); /* indirect opcode follows direct */ - duk__emit(comp_ctx, ins); - } else { - ins |= DUK_ENC_OP_A_B_C(op, tmp, b, c); - duk__emit(comp_ctx, ins); - duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_STREG, tmp, a)); - } - } else { - goto error_outofregs; + /* Output shuffling: only one output register is realistically possible. */ + + if (a_out != 0) { + DUK_ASSERT(b_out == 0); + DUK_ASSERT(c_out == 0); + duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_STREG, a, a_out)); + } else if (b_out != 0) { + DUK_ASSERT(a_out == 0); + DUK_ASSERT(c_out == 0); + duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_STREG, b, b_out)); + } else if (c_out != 0) { + DUK_ASSERT(b_out == 0); + DUK_ASSERT(c_out == 0); + duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_STREG, c, c_out)); } + return; error_outofregs: @@ -1143,7 +1219,12 @@ static void duk__emit_a_bc(duk_compiler_ctx *comp_ctx, int op, int a, int bc) { DUK_ASSERT(bc >= DUK_BC_BC_MIN && bc <= DUK_BC_BC_MAX); DUK_ASSERT((bc & DUK__CONST_MARKER) == 0); - /* FIXME: no check for 'bc' range now, inconsistent with duk__emit_a_b_c */ + if (bc <= DUK_BC_BC_MAX) { + ; + } else { + /* No BC shuffling now. */ + goto error_outofregs; + } if (a <= DUK_BC_A_MAX) { ins = DUK_ENC_OP_A_BC(op, a, bc); @@ -1176,24 +1257,45 @@ static void duk__emit_abc(duk_compiler_ctx *comp_ctx, int op, int abc) { duk__emit(comp_ctx, ins); } -static void duk__emit_extraop_b_c(duk_compiler_ctx *comp_ctx, int extraop, int b, int c) { - DUK_ASSERT(extraop >= DUK_BC_EXTRAOP_MIN && extraop <= DUK_BC_EXTRAOP_MAX); - duk__emit_a_b_c(comp_ctx, DUK_OP_EXTRA, extraop, b, c); +static void duk__emit_extraop_b_c(duk_compiler_ctx *comp_ctx, int extraop_flags, int b, int c) { + DUK_ASSERT((extraop_flags & 0xff) >= DUK_BC_EXTRAOP_MIN && + (extraop_flags & 0xff) <= DUK_BC_EXTRAOP_MAX); + /* Setting "no shuffle A" would be prudent but not necessary, assert covers it. */ + duk__emit_a_b_c(comp_ctx, + DUK_OP_EXTRA | (extraop_flags & ~0xff), /* transfer flags */ + extraop_flags & 0xff, + b, + c); } -static void duk__emit_extraop_b(duk_compiler_ctx *comp_ctx, int extraop, int b) { - DUK_ASSERT(extraop >= DUK_BC_EXTRAOP_MIN && extraop <= DUK_BC_EXTRAOP_MAX); - duk__emit_a_b_c(comp_ctx, DUK_OP_EXTRA, extraop, b, 0); +static void duk__emit_extraop_b(duk_compiler_ctx *comp_ctx, int extraop_flags, int b) { + DUK_ASSERT((extraop_flags & 0xff) >= DUK_BC_EXTRAOP_MIN && + (extraop_flags & 0xff) <= DUK_BC_EXTRAOP_MAX); + /* Setting "no shuffle A" would be prudent but not necessary, assert covers it. */ + duk__emit_a_b_c(comp_ctx, + DUK_OP_EXTRA | (extraop_flags & ~0xff), /* transfer flags */ + extraop_flags & 0xff, + b, + 0); } static void duk__emit_extraop_bc(duk_compiler_ctx *comp_ctx, int extraop, int bc) { DUK_ASSERT(extraop >= DUK_BC_EXTRAOP_MIN && extraop <= DUK_BC_EXTRAOP_MAX); - duk__emit_a_bc(comp_ctx, DUK_OP_EXTRA, extraop, bc); + duk__emit_a_bc(comp_ctx, + DUK_OP_EXTRA, + extraop, + bc); } -static void duk__emit_extraop_only(duk_compiler_ctx *comp_ctx, int extraop) { - DUK_ASSERT(extraop >= DUK_BC_EXTRAOP_MIN && extraop <= DUK_BC_EXTRAOP_MAX); - duk__emit_a_b_c(comp_ctx, DUK_OP_EXTRA, extraop, 0, 0); +static void duk__emit_extraop_only(duk_compiler_ctx *comp_ctx, int extraop_flags) { + DUK_ASSERT((extraop_flags & 0xff) >= DUK_BC_EXTRAOP_MIN && + (extraop_flags & 0xff) <= DUK_BC_EXTRAOP_MAX); + /* Setting "no shuffle A" would be prudent but not necessary, assert covers it. */ + duk__emit_a_b_c(comp_ctx, + DUK_OP_EXTRA | (extraop_flags & ~0xff), /* transfer flags */ + extraop_flags & 0xff, + 0, + 0); } static void duk__emit_loadint(duk_compiler_ctx *comp_ctx, int reg, duk_int32_t val) { @@ -2232,7 +2334,10 @@ static void duk__nud_array_literal(duk_compiler_ctx *comp_ctx, duk_ivalue *res) max_init_values = DUK__MAX_ARRAY_INIT_VALUES; /* XXX: depend on available temps? */ reg_obj = DUK__ALLOCTEMP(comp_ctx); - duk__emit_extraop_b_c(comp_ctx, DUK_EXTRAOP_NEWARR, reg_obj, 0); /* XXX: patch initial size afterwards? */ + duk__emit_extraop_b_c(comp_ctx, + DUK_EXTRAOP_NEWARR | DUK__EMIT_FLAG_B_IS_TARGET, + reg_obj, + 0); /* XXX: patch initial size afterwards? */ temp_start = DUK__GETTEMP(comp_ctx); /* @@ -2311,14 +2416,16 @@ static void duk__nud_array_literal(duk_compiler_ctx *comp_ctx, duk_ivalue *res) if (num_values > 0) { /* B and C have a non-register/const meaning, so shuffling - * is not allowed. Also A has non-standard meaning. + * is not allowed. Also A has non-standard meaning, is is + * a source (object is read from it). */ /* FIXME: indirect MPUTARR */ duk__emit_a_b_c(comp_ctx, DUK_OP_MPUTARR | DUK__EMIT_FLAG_NO_SHUFFLE_A | DUK__EMIT_FLAG_NO_SHUFFLE_B | - DUK__EMIT_FLAG_NO_SHUFFLE_C, + DUK__EMIT_FLAG_NO_SHUFFLE_C | + DUK__EMIT_FLAG_A_IS_SOURCE, reg_obj, temp_start, num_values); @@ -2429,7 +2536,10 @@ static void duk__nud_object_literal(duk_compiler_ctx *comp_ctx, duk_ivalue *res) max_init_pairs = DUK__MAX_OBJECT_INIT_PAIRS; /* XXX: depend on available temps? */ reg_obj = DUK__ALLOCTEMP(comp_ctx); - duk__emit_extraop_b_c(comp_ctx, DUK_EXTRAOP_NEWOBJ, reg_obj, 0); /* XXX: patch initial size afterwards? */ + duk__emit_extraop_b_c(comp_ctx, + DUK_EXTRAOP_NEWOBJ | DUK__EMIT_FLAG_B_IS_TARGET, + reg_obj, + 0); /* XXX: patch initial size afterwards? */ temp_start = DUK__GETTEMP(comp_ctx); /* temp object for tracking / detecting duplicate keys */ @@ -2548,7 +2658,8 @@ static void duk__nud_object_literal(duk_compiler_ctx *comp_ctx, duk_ivalue *res) DUK_OP_MPUTOBJ | DUK__EMIT_FLAG_NO_SHUFFLE_A | DUK__EMIT_FLAG_NO_SHUFFLE_B | - DUK__EMIT_FLAG_NO_SHUFFLE_C, + DUK__EMIT_FLAG_NO_SHUFFLE_C | + DUK__EMIT_FLAG_A_IS_SOURCE, reg_obj, temp_start, num_pairs); @@ -2612,7 +2723,8 @@ static void duk__nud_object_literal(duk_compiler_ctx *comp_ctx, duk_ivalue *res) DUK_OP_MPUTOBJ | DUK__EMIT_FLAG_NO_SHUFFLE_A | DUK__EMIT_FLAG_NO_SHUFFLE_B | - DUK__EMIT_FLAG_NO_SHUFFLE_C, + DUK__EMIT_FLAG_NO_SHUFFLE_C | + DUK__EMIT_FLAG_A_IS_SOURCE, reg_obj, temp_start, num_pairs); @@ -2727,7 +2839,9 @@ static void duk__expr_nud(duk_compiler_ctx *comp_ctx, duk_ivalue *res) { case DUK_TOK_THIS: { int reg_temp; reg_temp = DUK__ALLOCTEMP(comp_ctx); - duk__emit_extraop_b(comp_ctx, DUK_EXTRAOP_LDTHIS, reg_temp); + duk__emit_extraop_b(comp_ctx, + DUK_EXTRAOP_LDTHIS | DUK__EMIT_FLAG_B_IS_TARGET, + reg_temp); res->t = DUK_IVAL_PLAIN; res->x1.t = DUK_ISPEC_REGCONST; res->x1.regconst = reg_temp; @@ -2939,7 +3053,8 @@ static void duk__expr_nud(duk_compiler_ctx *comp_ctx, duk_ivalue *res) { duk_dup(ctx, res->x1.valstack_idx); if (duk__lookup_lhs(comp_ctx, ®_varbind, ®_varname)) { /* register bound variables are non-configurable -> always false */ - duk__emit_extraop_bc(comp_ctx, DUK_EXTRAOP_LDFALSE, reg_temp); + duk__emit_extraop_bc(comp_ctx, + DUK_EXTRAOP_LDFALSE, reg_temp); } else { duk_dup(ctx, res->x1.valstack_idx); reg_varname = duk__getconst(comp_ctx); @@ -2992,8 +3107,10 @@ static void duk__expr_nud(duk_compiler_ctx *comp_ctx, duk_ivalue *res) { DUK_DDDPRINT("typeof for an identifier name which could not be resolved " "at compile time, need to use special run-time handling"); tr = DUK__ALLOCTEMP(comp_ctx); - duk__emit_extraop_b_c(comp_ctx, DUK_EXTRAOP_TYPEOFID, tr, reg_varname); - + duk__emit_extraop_b_c(comp_ctx, + DUK_EXTRAOP_TYPEOFID | DUK__EMIT_FLAG_B_IS_TARGET, + tr, + reg_varname); res->t = DUK_IVAL_PLAIN; res->x1.t = DUK_ISPEC_REGCONST; res->x1.regconst = tr; @@ -3082,7 +3199,10 @@ static void duk__expr_nud(duk_compiler_ctx *comp_ctx, duk_ivalue *res) { /* FIXME: refactor into unary2: above? */ int tr; tr = duk__ivalue_toregconst_raw(comp_ctx, res, -1 /*forced_reg*/, DUK__IVAL_FLAG_REQUIRE_TEMP /*flags*/); - duk__emit_extraop_b_c(comp_ctx, args >> 8, tr, tr); + duk__emit_extraop_b_c(comp_ctx, + (args >> 8) | DUK__EMIT_FLAG_B_IS_TARGET, + tr, + tr); res->t = DUK_IVAL_PLAIN; res->x1.t = DUK_ISPEC_REGCONST; res->x1.regconst = tr; @@ -3136,7 +3256,10 @@ static void duk__expr_nud(duk_compiler_ctx *comp_ctx, duk_ivalue *res) { * for proper semantics (consider ToNumber() called for an object). */ duk__ivalue_toforcedreg(comp_ctx, res, reg_res); - duk__emit_extraop_b_c(comp_ctx, DUK_EXTRAOP_TONUM, reg_res, reg_res); /* for side effects */ + duk__emit_extraop_b_c(comp_ctx, + DUK_EXTRAOP_TONUM | DUK__EMIT_FLAG_B_IS_TARGET, + reg_res, + reg_res); /* for side effects */ duk__emit_extraop_only(comp_ctx, DUK_EXTRAOP_INVLHS); } res->t = DUK_IVAL_PLAIN; @@ -3845,12 +3968,18 @@ static void duk__expr_led(duk_compiler_ctx *comp_ctx, duk_ivalue *left, duk_ival duk_dup(ctx, left->x1.valstack_idx); if (duk__lookup_lhs(comp_ctx, ®_varbind, ®_varname)) { duk__emit_a_bc(comp_ctx, DUK_OP_LDREG, reg_res, reg_varbind); - duk__emit_extraop_b_c(comp_ctx, DUK_EXTRAOP_TONUM, reg_res, reg_res); + duk__emit_extraop_b_c(comp_ctx, + DUK_EXTRAOP_TONUM | DUK__EMIT_FLAG_B_IS_TARGET, + reg_res, + reg_res); duk__emit_a_b(comp_ctx, args_op, reg_varbind, reg_res); } else { int reg_temp = DUK__ALLOCTEMP(comp_ctx); duk__emit_a_bc(comp_ctx, DUK_OP_GETVAR, reg_res, reg_varname); - duk__emit_extraop_b_c(comp_ctx, DUK_EXTRAOP_TONUM, reg_res, reg_res); + duk__emit_extraop_b_c(comp_ctx, + DUK_EXTRAOP_TONUM | DUK__EMIT_FLAG_B_IS_TARGET, + reg_res, + reg_res); duk__emit_a_b(comp_ctx, args_op, reg_temp, reg_res); duk__emit_a_bc(comp_ctx, DUK_OP_PUTVAR, reg_temp, reg_varname); } @@ -3864,7 +3993,10 @@ static void duk__expr_led(duk_compiler_ctx *comp_ctx, duk_ivalue *left, duk_ival reg_obj = duk__ispec_toregconst_raw(comp_ctx, &left->x1, -1 /*forced_reg*/, 0 /*flags*/); /* don't allow const */ reg_key = duk__ispec_toregconst_raw(comp_ctx, &left->x2, -1 /*forced_reg*/, DUK__IVAL_FLAG_ALLOW_CONST /*flags*/); duk__emit_a_b_c(comp_ctx, DUK_OP_GETPROP, reg_res, reg_obj, reg_key); - duk__emit_extraop_b_c(comp_ctx, DUK_EXTRAOP_TONUM, reg_res, reg_res); + duk__emit_extraop_b_c(comp_ctx, + DUK_EXTRAOP_TONUM | DUK__EMIT_FLAG_B_IS_TARGET, + reg_res, + reg_res); duk__emit_a_b(comp_ctx, args_op, reg_temp, reg_res); duk__emit_a_b_c(comp_ctx, DUK_OP_PUTPROP, reg_obj, reg_key, reg_temp); } else { @@ -3873,7 +4005,10 @@ static void duk__expr_led(duk_compiler_ctx *comp_ctx, duk_ivalue *left, duk_ival * for proper semantics (consider ToNumber() called for an object). */ duk__ivalue_toforcedreg(comp_ctx, left, reg_res); - duk__emit_extraop_b_c(comp_ctx, DUK_EXTRAOP_TONUM, reg_res, reg_res); /* for side effects */ + duk__emit_extraop_b_c(comp_ctx, + DUK_EXTRAOP_TONUM | DUK__EMIT_FLAG_B_IS_TARGET, + reg_res, + reg_res); /* for side effects */ duk__emit_extraop_only(comp_ctx, DUK_EXTRAOP_INVLHS); }