diff --git a/quickjs-opcode.h b/quickjs-opcode.h index f08b94c..8063c53 100644 --- a/quickjs-opcode.h +++ b/quickjs-opcode.h @@ -302,6 +302,7 @@ DEF( get_loc8, 2, 0, 1, loc8) DEF( put_loc8, 2, 1, 0, loc8) DEF( set_loc8, 2, 1, 1, loc8) +DEF( get_loc0_loc1, 1, 0, 2, none_loc) DEF( get_loc0, 1, 0, 1, none_loc) DEF( get_loc1, 1, 0, 1, none_loc) DEF( get_loc2, 1, 0, 1, none_loc) diff --git a/quickjs.c b/quickjs.c index 9ace208..0f41cef 100644 --- a/quickjs.c +++ b/quickjs.c @@ -14976,6 +14976,14 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, CASE(OP_put_loc8): set_value(ctx, &var_buf[*pc++], *--sp); BREAK; CASE(OP_set_loc8): set_value(ctx, &var_buf[*pc++], JS_DupValue(ctx, sp[-1])); BREAK; + // Observation: get_loc0 and get_loc1 are individually very + // frequent opcodes _and_ they are very often paired together, + // making them ideal candidates for opcode fusion. + CASE(OP_get_loc0_loc1): + *sp++ = JS_DupValue(ctx, var_buf[0]); + *sp++ = JS_DupValue(ctx, var_buf[1]); + BREAK; + CASE(OP_get_loc0): *sp++ = JS_DupValue(ctx, var_buf[0]); BREAK; CASE(OP_get_loc1): *sp++ = JS_DupValue(ctx, var_buf[1]); BREAK; CASE(OP_get_loc2): *sp++ = JS_DupValue(ctx, var_buf[2]); BREAK; @@ -29661,6 +29669,14 @@ static __exception int resolve_labels(JSContext *ctx, JSFunctionDef *s) pos_next = cc.pos; break; } + /* transformation: get_loc(0) get_loc(1) -> get_loc0_loc1 */ + if (idx == 0 && code_match(&cc, pos_next, OP_get_loc, 1, -1)) { + if (cc.line_num >= 0) line_num = cc.line_num; + add_pc2line_info(s, bc_out.size, line_num); + dbuf_putc(&bc_out, OP_get_loc0_loc1); + pos_next = cc.pos; + break; + } add_pc2line_info(s, bc_out.size, line_num); put_short_code(&bc_out, op, idx); }