clean up var ref
This commit is contained in:
@@ -114,9 +114,6 @@ DEF( put_var, 5, 1, 0, key) /* resolved by linker to set_global_slot */
|
||||
DEF( put_var_init, 5, 1, 0, key) /* resolved by linker to set_global_slot */
|
||||
DEF( put_var_strict, 5, 2, 0, key) /* resolved by linker to set_global_slot */
|
||||
|
||||
DEF( get_ref_value, 1, 2, 3, none)
|
||||
DEF( put_ref_value, 1, 3, 0, none)
|
||||
|
||||
/* Global variable opcodes - resolved by linker to get/set_global_slot */
|
||||
DEF( define_var, 6, 0, 0, key_u8)
|
||||
DEF(check_define_var, 6, 0, 0, key_u8)
|
||||
@@ -144,19 +141,11 @@ DEF( set_loc, 3, 1, 1, loc) /* must come after put_loc */
|
||||
DEF( get_arg, 3, 0, 1, arg)
|
||||
DEF( put_arg, 3, 1, 0, arg) /* must come after get_arg */
|
||||
DEF( set_arg, 3, 1, 1, arg) /* must come after put_arg */
|
||||
/* Var ref opcodes - deprecated, resolved to get_up/set_up during scope resolution */
|
||||
DEF( get_var_ref, 3, 0, 1, loc) /* deprecated - use get_up */
|
||||
DEF( put_var_ref, 3, 1, 0, loc) /* deprecated - use set_up */
|
||||
DEF( set_var_ref, 3, 1, 1, loc) /* deprecated - use set_up */
|
||||
DEF(set_loc_uninitialized, 3, 0, 0, loc)
|
||||
DEF( get_loc_check, 3, 0, 1, loc)
|
||||
DEF( put_loc_check, 3, 1, 0, loc) /* must come after get_loc_check */
|
||||
DEF( put_loc_check_init, 3, 1, 0, loc)
|
||||
DEF(get_loc_checkthis, 3, 0, 1, loc)
|
||||
DEF(get_var_ref_check, 3, 0, 1, loc) /* deprecated - use get_up */
|
||||
DEF(put_var_ref_check, 3, 1, 0, loc) /* deprecated - use set_up */
|
||||
DEF(put_var_ref_check_init, 3, 1, 0, loc) /* deprecated - use set_up */
|
||||
DEF( close_loc, 3, 0, 0, loc) /* deprecated - no longer needed */
|
||||
DEF( if_false, 5, 1, 0, label)
|
||||
DEF( if_true, 5, 1, 0, label) /* must come after if_false */
|
||||
DEF( goto, 5, 0, 0, label) /* must come after if_true */
|
||||
@@ -167,12 +156,6 @@ DEF( nip_catch, 1, 2, 1, none) /* catch ... a -> a */
|
||||
|
||||
DEF( to_propkey, 1, 1, 1, none)
|
||||
|
||||
/* Deprecated make_*_ref opcodes - no longer needed with outer_frame model */
|
||||
DEF( make_loc_ref, 7, 0, 2, key_u16) /* deprecated */
|
||||
DEF( make_arg_ref, 7, 0, 2, key_u16) /* deprecated */
|
||||
DEF(make_var_ref_ref, 7, 0, 2, key_u16) /* deprecated */
|
||||
DEF( make_var_ref, 5, 0, 2, key) /* deprecated */
|
||||
|
||||
/* arithmetic/logic operations */
|
||||
DEF( neg, 1, 1, 1, none)
|
||||
DEF( plus, 1, 1, 1, none)
|
||||
@@ -240,8 +223,6 @@ def(scope_get_var_undef, 7, 0, 1, key_u16) /* emitted in phase 1, removed in pha
|
||||
def( scope_get_var, 7, 0, 1, key_u16) /* emitted in phase 1, removed in phase 2 */
|
||||
def( scope_put_var, 7, 1, 0, key_u16) /* emitted in phase 1, removed in phase 2 */
|
||||
def(scope_delete_var, 7, 0, 1, key_u16) /* emitted in phase 1, removed in phase 2 */
|
||||
def( scope_make_ref, 11, 0, 2, key_label_u16) /* emitted in phase 1, removed in phase 2 */
|
||||
def( scope_get_ref, 7, 0, 2, key_u16) /* emitted in phase 1, removed in phase 2 */
|
||||
def(scope_put_var_init, 7, 0, 2, key_u16) /* emitted in phase 1, removed in phase 2 */
|
||||
def(scope_get_var_checkthis, 7, 0, 1, key_u16) /* emitted in phase 1, removed in phase 2, only used to return 'this' in derived class constructors */
|
||||
def(get_field_opt_chain, 5, 1, 1, key) /* emitted in phase 1, removed in phase 2 */
|
||||
|
||||
640
source/quickjs.c
640
source/quickjs.c
@@ -5060,175 +5060,6 @@ static JSValue JS_ThrowSyntaxErrorVarRedeclaration (JSContext *ctx,
|
||||
return JS_ThrowSyntaxError (ctx, "redeclaration of '%s'", JS_KeyGetStr (ctx, buf, sizeof (buf), prop));
|
||||
}
|
||||
|
||||
/* GC-SAFE: Only calls rec_find_slot (no allocations).
|
||||
flags is 0, DEFINE_GLOBAL_LEX_VAR or DEFINE_GLOBAL_FUNC_VAR */
|
||||
static int JS_CheckDefineGlobalVar (JSContext *ctx, JSValue prop, int flags) {
|
||||
JSRecord *rec;
|
||||
int slot;
|
||||
|
||||
rec = (JSRecord *)JS_VALUE_GET_OBJ (ctx->global_obj);
|
||||
slot = rec_find_slot (rec, prop);
|
||||
if (flags & DEFINE_GLOBAL_LEX_VAR) {
|
||||
if (slot > 0) goto fail_redeclaration;
|
||||
} else {
|
||||
if (slot <= 0 && obj_is_stone (rec)) {
|
||||
char buf[KEY_GET_STR_BUF_SIZE];
|
||||
JS_ThrowTypeError (ctx, "cannot define variable '%s'", JS_KeyGetStr (ctx, buf, sizeof (buf), prop));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
/* check if there already is a lexical declaration */
|
||||
rec = (JSRecord *)JS_VALUE_GET_OBJ (ctx->global_var_obj);
|
||||
slot = rec_find_slot (rec, prop);
|
||||
if (slot > 0) {
|
||||
fail_redeclaration:
|
||||
JS_ThrowSyntaxErrorVarRedeclaration (ctx, prop);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* CAUTION: rec_set_own is NOT GC-safe if rec_resize is implemented.
|
||||
Currently safe because rec_resize always fails.
|
||||
def_flags is (0, DEFINE_GLOBAL_LEX_VAR) */
|
||||
static int JS_DefineGlobalVar (JSContext *ctx, JSValue prop, int def_flags) {
|
||||
JSValue *pobj;
|
||||
JSValue val;
|
||||
JSRecord *rec;
|
||||
int slot;
|
||||
|
||||
if (def_flags & DEFINE_GLOBAL_LEX_VAR) {
|
||||
pobj = &ctx->global_var_obj;
|
||||
val = JS_UNINITIALIZED;
|
||||
} else {
|
||||
pobj = &ctx->global_obj;
|
||||
val = JS_NULL;
|
||||
}
|
||||
rec = (JSRecord *)JS_VALUE_GET_OBJ (*pobj);
|
||||
slot = rec_find_slot (rec, prop);
|
||||
if (slot > 0) return 0; /* already defined */
|
||||
if (obj_is_stone (rec)) return 0;
|
||||
return rec_set_own (ctx, pobj, prop, val);
|
||||
}
|
||||
|
||||
/* Simplified global function definition */
|
||||
static int JS_DefineGlobalFunction (JSContext *ctx, JSValue prop, JSValue func, int def_flags) {
|
||||
(void)def_flags;
|
||||
/* JS_SetPropertyInternal consumes the value, so we must dup it */
|
||||
if (JS_SetPropertyInternal (ctx, ctx->global_obj, prop, func)
|
||||
< 0)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* GC-SAFE: Only calls rec_find_slot and rec_get (no allocations) */
|
||||
static JSValue JS_GetGlobalVar (JSContext *ctx, JSValue prop, BOOL throw_ref_error) {
|
||||
JSRecord *rec;
|
||||
int slot;
|
||||
|
||||
rec = (JSRecord *)JS_VALUE_GET_OBJ (ctx->global_var_obj);
|
||||
slot = rec_find_slot (rec, prop);
|
||||
if (slot > 0) {
|
||||
JSValue val = rec->slots[slot].val;
|
||||
if (unlikely (JS_IsUninitialized (val)))
|
||||
return JS_ThrowReferenceErrorUninitialized (ctx, prop);
|
||||
return val;
|
||||
}
|
||||
/* Fall back to global object */
|
||||
JSValue val
|
||||
= rec_get (ctx, (JSRecord *)JS_VALUE_GET_OBJ (ctx->global_obj), prop);
|
||||
if (JS_IsNull (val) && throw_ref_error)
|
||||
return JS_ThrowReferenceErrorNotDefined (ctx, prop);
|
||||
return val;
|
||||
}
|
||||
|
||||
/* GC-SAFE: Only calls rec_find_slot and JS_HasProperty (no allocations).
|
||||
Construct a reference to a global variable */
|
||||
static int JS_GetGlobalVarRef (JSContext *ctx, JSValue prop, JSValue *sp) {
|
||||
JSRecord *rec;
|
||||
int slot;
|
||||
|
||||
rec = (JSRecord *)JS_VALUE_GET_OBJ (ctx->global_var_obj);
|
||||
slot = rec_find_slot (rec, prop);
|
||||
if (slot > 0) {
|
||||
JSValue val = rec->slots[slot].val;
|
||||
if (unlikely (JS_IsUninitialized (val))) {
|
||||
JS_ThrowReferenceErrorUninitialized (ctx, prop);
|
||||
return -1;
|
||||
}
|
||||
sp[0] = ctx->global_var_obj;
|
||||
} else {
|
||||
int ret = JS_HasProperty (ctx, ctx->global_obj, prop);
|
||||
if (ret < 0) return -1;
|
||||
if (ret) {
|
||||
sp[0] = ctx->global_obj;
|
||||
} else {
|
||||
sp[0] = JS_NULL;
|
||||
}
|
||||
}
|
||||
sp[1] = prop;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* GC-SAFE: Only calls rec_find_slot and JS_HasProperty (no allocations).
|
||||
Use for strict variable access: test if the variable exists */
|
||||
static int JS_CheckGlobalVar (JSContext *ctx, JSValue prop) {
|
||||
JSRecord *rec;
|
||||
int slot, ret;
|
||||
|
||||
rec = (JSRecord *)JS_VALUE_GET_OBJ (ctx->global_var_obj);
|
||||
slot = rec_find_slot (rec, prop);
|
||||
if (slot > 0) {
|
||||
ret = TRUE;
|
||||
} else {
|
||||
ret = JS_HasProperty (ctx, ctx->global_obj, prop);
|
||||
if (ret < 0) return -1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* flag = 0: normal variable write
|
||||
flag = 1: initialize lexical variable
|
||||
flag = 2: normal variable write, strict check was done before
|
||||
*/
|
||||
static int JS_SetGlobalVar (JSContext *ctx, JSValue prop, JSValue val, int flag) {
|
||||
JSRecord *rec;
|
||||
int slot;
|
||||
|
||||
rec = (JSRecord *)JS_VALUE_GET_OBJ (ctx->global_var_obj);
|
||||
slot = rec_find_slot (rec, prop);
|
||||
if (slot > 0) {
|
||||
if (flag != 1) {
|
||||
if (unlikely (JS_IsUninitialized (rec->slots[slot].val))) {
|
||||
JS_ThrowReferenceErrorUninitialized (ctx, prop);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
rec->slots[slot].val = val;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return JS_SetPropertyInternal (ctx, ctx->global_obj, prop, val);
|
||||
}
|
||||
|
||||
/* return -1, FALSE or TRUE */
|
||||
static int JS_DeleteGlobalVar (JSContext *ctx, JSValue prop) {
|
||||
JSRecord *rec;
|
||||
int slot, ret;
|
||||
|
||||
/* 9.1.1.4.7 DeleteBinding ( N ) */
|
||||
rec = (JSRecord *)JS_VALUE_GET_OBJ (ctx->global_var_obj);
|
||||
slot = rec_find_slot (rec, prop);
|
||||
if (slot > 0) return FALSE; /* lexical variables cannot be deleted */
|
||||
ret = JS_HasProperty (ctx, ctx->global_obj, prop);
|
||||
if (ret < 0) return -1;
|
||||
if (ret) {
|
||||
return JS_DeleteProperty (ctx, ctx->global_obj, prop);
|
||||
} else {
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
int JS_DeleteProperty (JSContext *ctx, JSValue obj, JSValue prop) {
|
||||
JSRecord *rec;
|
||||
int slot;
|
||||
@@ -5359,25 +5190,6 @@ int JS_ToBool (JSContext *ctx, JSValue val) {
|
||||
}
|
||||
}
|
||||
|
||||
static int skip_spaces (const char *pc) {
|
||||
const uint8_t *p, *p_next, *p_start;
|
||||
uint32_t c;
|
||||
|
||||
p = p_start = (const uint8_t *)pc;
|
||||
for (;;) {
|
||||
c = *p;
|
||||
if (c < 128) {
|
||||
if (!((c >= 0x09 && c <= 0x0d) || (c == 0x20))) break;
|
||||
p++;
|
||||
} else {
|
||||
c = unicode_from_utf8 (p, UTF8_CHAR_LEN_MAX, &p_next);
|
||||
if (!lre_is_space (c)) break;
|
||||
p = p_next;
|
||||
}
|
||||
}
|
||||
return p - p_start;
|
||||
}
|
||||
|
||||
static inline int to_digit (int c) {
|
||||
if (c >= '0' && c <= '9')
|
||||
return c - '0';
|
||||
@@ -7641,24 +7453,6 @@ restart:
|
||||
}
|
||||
BREAK;
|
||||
|
||||
/* Deprecated var_ref opcodes - should be resolved to get_up/set_up during scope resolution */
|
||||
CASE (OP_get_var_ref) :
|
||||
CASE (OP_put_var_ref) :
|
||||
CASE (OP_set_var_ref) :
|
||||
CASE (OP_get_var_ref_check) :
|
||||
CASE (OP_put_var_ref_check) :
|
||||
CASE (OP_put_var_ref_check_init) :
|
||||
pc += 2; /* skip the index */
|
||||
JS_ThrowInternalError(ctx, "deprecated var_ref opcode (use OP_get_up/OP_set_up)");
|
||||
goto exception;
|
||||
BREAK;
|
||||
|
||||
CASE (OP_close_loc) :
|
||||
pc += 2;
|
||||
JS_ThrowInternalError(ctx, "deprecated close_loc opcode");
|
||||
goto exception;
|
||||
BREAK;
|
||||
|
||||
CASE (OP_goto) : pc += (int32_t)get_u32 (pc);
|
||||
if (unlikely (js_poll_interrupts (ctx))) goto exception;
|
||||
BREAK;
|
||||
@@ -8013,32 +7807,6 @@ restart:
|
||||
}
|
||||
BREAK;
|
||||
|
||||
CASE (OP_get_ref_value) : {
|
||||
JSValue val;
|
||||
JSValue key = sp[-1];
|
||||
JSValue ref_obj = sp[-2];
|
||||
|
||||
sf->cur_pc = pc;
|
||||
|
||||
if (JS_IsText (key)) { key = js_key_from_string (ctx, key); }
|
||||
if (unlikely (JS_IsNull (ref_obj))) {
|
||||
JS_ThrowReferenceErrorNotDefined (ctx, key);
|
||||
goto exception;
|
||||
}
|
||||
int ret = JS_HasProperty (ctx, ref_obj, key);
|
||||
if (unlikely (ret <= 0)) {
|
||||
if (ret < 0) { goto exception; }
|
||||
JS_ThrowReferenceErrorNotDefined (ctx, key);
|
||||
goto exception;
|
||||
} else {
|
||||
val = JS_GetProperty (ctx, ref_obj, key);
|
||||
}
|
||||
if (unlikely (JS_IsException (val))) goto exception;
|
||||
sp[0] = val;
|
||||
sp++;
|
||||
}
|
||||
BREAK;
|
||||
|
||||
CASE (OP_put_array_el) : {
|
||||
int ret;
|
||||
|
||||
@@ -8055,30 +7823,6 @@ restart:
|
||||
}
|
||||
BREAK;
|
||||
|
||||
CASE (OP_put_ref_value) : {
|
||||
JSValue key = sp[-2];
|
||||
JSValue ref_obj = sp[-3];
|
||||
JSValue val = sp[-1];
|
||||
|
||||
sf->cur_pc = pc;
|
||||
|
||||
if (JS_IsText (key)) { key = js_key_from_string (ctx, key); }
|
||||
if (unlikely (JS_IsNull (ref_obj))) {
|
||||
JS_ThrowReferenceErrorNotDefined (ctx, key);
|
||||
goto exception;
|
||||
}
|
||||
int ret = JS_HasProperty (ctx, ref_obj, key);
|
||||
if (unlikely (ret <= 0)) {
|
||||
if (unlikely (ret < 0)) { goto exception; }
|
||||
JS_ThrowReferenceErrorNotDefined (ctx, key);
|
||||
goto exception;
|
||||
}
|
||||
ret = JS_SetPropertyInternal (ctx, ref_obj, key, val);
|
||||
sp -= 3;
|
||||
if (unlikely (ret < 0)) goto exception;
|
||||
}
|
||||
BREAK;
|
||||
|
||||
CASE (OP_define_array_el) : {
|
||||
int ret;
|
||||
ret = JS_SetPropertyValue (ctx, sp[-3], sp[-2], sp[-1]);
|
||||
@@ -8647,20 +8391,6 @@ restart:
|
||||
}
|
||||
BREAK;
|
||||
|
||||
/* Deprecated make_*_ref opcodes - no longer needed with outer_frame model */
|
||||
CASE (OP_make_loc_ref) :
|
||||
CASE (OP_make_arg_ref) :
|
||||
CASE (OP_make_var_ref_ref) :
|
||||
pc += 6;
|
||||
JS_ThrowInternalError(ctx, "deprecated make_*_ref opcode");
|
||||
goto exception;
|
||||
BREAK;
|
||||
CASE (OP_make_var_ref) :
|
||||
pc += 4;
|
||||
JS_ThrowInternalError(ctx, "deprecated make_var_ref opcode");
|
||||
goto exception;
|
||||
BREAK;
|
||||
|
||||
CASE (OP_template_concat) : {
|
||||
int n, i;
|
||||
JSValue out;
|
||||
@@ -12408,7 +12138,7 @@ static int js_parse_destructuring_element (JSParseState *s, int tok, int is_arg,
|
||||
if (next_token (s)) goto var_error;
|
||||
emit_op (s, OP_drop);
|
||||
if (js_parse_assign_expr (s)) goto var_error;
|
||||
if (opcode == OP_scope_get_var || opcode == OP_get_ref_value)
|
||||
if (opcode == OP_scope_get_var)
|
||||
set_object_name (s, var_name);
|
||||
emit_label (s, label_hasval);
|
||||
}
|
||||
@@ -12692,13 +12422,6 @@ static __exception int js_parse_postfix_expr (JSParseState *s,
|
||||
statement can resolve to a method call of the
|
||||
`with` context object
|
||||
*/
|
||||
/* XXX: always generate the OP_scope_get_ref
|
||||
and remove it in variable resolution
|
||||
pass ? */
|
||||
if (has_with_scope (fd, scope)) {
|
||||
opcode = OP_scope_get_ref;
|
||||
fd->byte_code.buf[fd->last_opcode_pos] = opcode;
|
||||
}
|
||||
}
|
||||
drop_count = 1;
|
||||
} break;
|
||||
@@ -12737,7 +12460,6 @@ static __exception int js_parse_postfix_expr (JSParseState *s,
|
||||
switch (opcode) {
|
||||
case OP_get_field:
|
||||
case OP_get_array_el:
|
||||
case OP_scope_get_ref:
|
||||
emit_op (s, OP_call_method);
|
||||
emit_u16 (s, arg_count);
|
||||
break;
|
||||
@@ -14744,112 +14466,6 @@ static int compute_closure_depth_slot(JSFunctionDef *s, int closure_idx, int *ou
|
||||
return depth;
|
||||
}
|
||||
|
||||
static BOOL can_opt_put_ref_value (const uint8_t *bc_buf, int pos) {
|
||||
int opcode = bc_buf[pos];
|
||||
return (bc_buf[pos + 1] == OP_put_ref_value
|
||||
&& (opcode == OP_insert3 || opcode == OP_perm4 || opcode == OP_nop
|
||||
|| opcode == OP_rot3l));
|
||||
}
|
||||
|
||||
static BOOL can_opt_put_global_ref_value (const uint8_t *bc_buf, int pos) {
|
||||
int opcode = bc_buf[pos];
|
||||
return (bc_buf[pos + 1] == OP_put_ref_value
|
||||
&& (opcode == OP_insert3 || opcode == OP_perm4 || opcode == OP_nop
|
||||
|| opcode == OP_rot3l));
|
||||
}
|
||||
|
||||
static int optimize_scope_make_ref (JSContext *ctx, JSFunctionDef *s, DynBuf *bc, uint8_t *bc_buf, LabelSlot *ls, int pos_next, int get_op, int var_idx) {
|
||||
int label_pos, end_pos, pos;
|
||||
|
||||
/* XXX: should optimize `loc(a) += expr` as `expr add_loc(a)`
|
||||
but only if expr does not modify `a`.
|
||||
should scan the code between pos_next and label_pos
|
||||
for operations that can potentially change `a`:
|
||||
OP_scope_make_ref(a), function calls, jumps and gosub.
|
||||
*/
|
||||
/* replace the reference get/put with normal variable
|
||||
accesses */
|
||||
if (bc_buf[pos_next] == OP_get_ref_value) {
|
||||
dbuf_putc (bc, get_op);
|
||||
dbuf_put_u16 (bc, var_idx);
|
||||
pos_next++;
|
||||
}
|
||||
/* remove the OP_label to make room for replacement */
|
||||
/* label should have a refcount of 0 anyway */
|
||||
/* XXX: should avoid this patch by inserting nops in phase 1 */
|
||||
label_pos = ls->pos;
|
||||
pos = label_pos - 5;
|
||||
assert (bc_buf[pos] == OP_label);
|
||||
/* label points to an instruction pair:
|
||||
- insert3 / put_ref_value
|
||||
- perm4 / put_ref_value
|
||||
- rot3l / put_ref_value
|
||||
- nop / put_ref_value
|
||||
*/
|
||||
end_pos = label_pos + 2;
|
||||
if (bc_buf[label_pos] == OP_insert3) bc_buf[pos++] = OP_dup;
|
||||
bc_buf[pos] = get_op + 1;
|
||||
put_u16 (bc_buf + pos + 1, var_idx);
|
||||
pos += 3;
|
||||
/* pad with OP_nop */
|
||||
while (pos < end_pos)
|
||||
bc_buf[pos++] = OP_nop;
|
||||
return pos_next;
|
||||
}
|
||||
|
||||
static int optimize_scope_make_global_ref (JSContext *ctx, JSFunctionDef *s, DynBuf *bc, uint8_t *bc_buf, LabelSlot *ls, int pos_next, JSValue var_name) {
|
||||
int label_pos, end_pos, pos, op;
|
||||
int cpool_idx = fd_cpool_add (ctx, s, var_name);
|
||||
|
||||
/* replace the reference get/put with normal variable
|
||||
accesses */
|
||||
/* need to check if the variable exists before evaluating the right
|
||||
expression */
|
||||
/* XXX: need an extra OP_true if destructuring an array */
|
||||
dbuf_putc (bc, OP_check_var);
|
||||
dbuf_put_u32 (bc, cpool_idx);
|
||||
|
||||
if (bc_buf[pos_next] == OP_get_ref_value) {
|
||||
dbuf_putc (bc, OP_get_var);
|
||||
dbuf_put_u32 (bc, cpool_idx);
|
||||
pos_next++;
|
||||
}
|
||||
/* remove the OP_label to make room for replacement */
|
||||
/* label should have a refcount of 0 anyway */
|
||||
/* XXX: should have emitted several OP_nop to avoid this kludge */
|
||||
label_pos = ls->pos;
|
||||
pos = label_pos - 5;
|
||||
assert (bc_buf[pos] == OP_label);
|
||||
end_pos = label_pos + 2;
|
||||
op = bc_buf[label_pos];
|
||||
if (op != OP_nop) {
|
||||
switch (op) {
|
||||
case OP_insert3:
|
||||
op = OP_insert2;
|
||||
break;
|
||||
case OP_perm4:
|
||||
op = OP_perm3;
|
||||
break;
|
||||
case OP_rot3l:
|
||||
op = OP_swap;
|
||||
break;
|
||||
default:
|
||||
abort ();
|
||||
}
|
||||
bc_buf[pos++] = op;
|
||||
}
|
||||
|
||||
bc_buf[pos] = OP_put_var_strict;
|
||||
/* XXX: need 1 extra OP_drop if destructuring an array */
|
||||
|
||||
put_u32 (bc_buf + pos + 1, cpool_idx);
|
||||
pos += 5;
|
||||
/* pad with OP_nop */
|
||||
while (pos < end_pos)
|
||||
bc_buf[pos++] = OP_nop;
|
||||
return pos_next;
|
||||
}
|
||||
|
||||
static int add_var_this (JSContext *ctx, JSFunctionDef *fd) {
|
||||
return add_var (ctx, fd, JS_KEY_this);
|
||||
}
|
||||
@@ -14907,7 +14523,7 @@ static int resolve_scope_var (JSContext *ctx, JSFunctionDef *s, JSValue var_name
|
||||
for (idx = s->scopes[scope_level].first; idx >= 0;) {
|
||||
vd = &s->vars[idx];
|
||||
if (js_key_equal (vd->var_name, var_name)) {
|
||||
if (op == OP_scope_put_var || op == OP_scope_make_ref) {
|
||||
if (op == OP_scope_put_var) {
|
||||
if (vd->is_const) {
|
||||
int cpool_idx = fd_cpool_add (ctx, s, var_name);
|
||||
dbuf_putc (bc, OP_throw_error);
|
||||
@@ -14937,7 +14553,7 @@ static int resolve_scope_var (JSContext *ctx, JSFunctionDef *s, JSValue var_name
|
||||
}
|
||||
}
|
||||
if (var_idx >= 0) {
|
||||
if ((op == OP_scope_put_var || op == OP_scope_make_ref)
|
||||
if (op == OP_scope_put_var
|
||||
&& !(var_idx & ARGUMENT_VAR_OFFSET) && s->vars[var_idx].is_const) {
|
||||
/* only happens when assigning a function expression name
|
||||
in strict mode */
|
||||
@@ -14951,49 +14567,6 @@ static int resolve_scope_var (JSContext *ctx, JSFunctionDef *s, JSValue var_name
|
||||
lexical variable, so it is never used in a with or var object. It
|
||||
can be used with a closure (module global variable case). */
|
||||
switch (op) {
|
||||
case OP_scope_make_ref:
|
||||
if (!(var_idx & ARGUMENT_VAR_OFFSET)
|
||||
&& s->vars[var_idx].var_kind == JS_VAR_FUNCTION_NAME) {
|
||||
/* Create a dummy object reference for the func_var */
|
||||
int cpool_idx = fd_cpool_add (ctx, s, var_name);
|
||||
if (cpool_idx < 0) return -1;
|
||||
dbuf_putc (bc, OP_object);
|
||||
dbuf_putc (bc, OP_get_loc);
|
||||
dbuf_put_u16 (bc, var_idx);
|
||||
dbuf_putc (bc, OP_define_field);
|
||||
dbuf_put_u32 (bc, cpool_idx);
|
||||
dbuf_putc (bc, OP_push_const);
|
||||
dbuf_put_u32 (bc, cpool_idx);
|
||||
} else if (label_done == -1 && can_opt_put_ref_value (bc_buf, ls->pos)) {
|
||||
int get_op;
|
||||
if (var_idx & ARGUMENT_VAR_OFFSET) {
|
||||
get_op = OP_get_arg;
|
||||
var_idx -= ARGUMENT_VAR_OFFSET;
|
||||
} else {
|
||||
if (s->vars[var_idx].is_lexical)
|
||||
get_op = OP_get_loc_check;
|
||||
else
|
||||
get_op = OP_get_loc;
|
||||
}
|
||||
pos_next = optimize_scope_make_ref (ctx, s, bc, bc_buf, ls, pos_next, get_op, var_idx);
|
||||
} else {
|
||||
/* Create a dummy object with a named slot that is
|
||||
a reference to the local variable */
|
||||
int cpool_idx = fd_cpool_add (ctx, s, var_name);
|
||||
if (var_idx & ARGUMENT_VAR_OFFSET) {
|
||||
dbuf_putc (bc, OP_make_arg_ref);
|
||||
dbuf_put_u32 (bc, cpool_idx);
|
||||
dbuf_put_u16 (bc, var_idx - ARGUMENT_VAR_OFFSET);
|
||||
} else {
|
||||
dbuf_putc (bc, OP_make_loc_ref);
|
||||
dbuf_put_u32 (bc, cpool_idx);
|
||||
dbuf_put_u16 (bc, var_idx);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case OP_scope_get_ref:
|
||||
dbuf_putc (bc, OP_null);
|
||||
/* fall thru */
|
||||
case OP_scope_get_var_checkthis:
|
||||
case OP_scope_get_var_undef:
|
||||
case OP_scope_get_var:
|
||||
@@ -15059,7 +14632,7 @@ static int resolve_scope_var (JSContext *ctx, JSFunctionDef *s, JSValue var_name
|
||||
for (idx = fd->scopes[scope_level].first; idx >= 0;) {
|
||||
vd = &fd->vars[idx];
|
||||
if (js_key_equal (vd->var_name, var_name)) {
|
||||
if (op == OP_scope_put_var || op == OP_scope_make_ref) {
|
||||
if (op == OP_scope_put_var) {
|
||||
if (vd->is_const) {
|
||||
int cpool_idx = fd_cpool_add (ctx, s, var_name);
|
||||
dbuf_putc (bc, OP_throw_error);
|
||||
@@ -15092,21 +14665,27 @@ static int resolve_scope_var (JSContext *ctx, JSFunctionDef *s, JSValue var_name
|
||||
|
||||
/* check eval object */
|
||||
if (!is_arg_scope && fd->var_object_idx >= 0 && !is_pseudo_var) {
|
||||
int slot, depth;
|
||||
vd = &fd->vars[fd->var_object_idx];
|
||||
vd->is_captured = 1;
|
||||
idx = get_closure_var (ctx, s, fd, FALSE, fd->var_object_idx, vd->var_name, FALSE, FALSE, JS_VAR_NORMAL);
|
||||
dbuf_putc (bc, OP_get_var_ref);
|
||||
dbuf_put_u16 (bc, idx);
|
||||
depth = compute_closure_depth_slot(s, idx, &slot);
|
||||
dbuf_putc (bc, OP_get_up);
|
||||
dbuf_putc (bc, (uint8_t)depth);
|
||||
dbuf_put_u16 (bc, (uint16_t)slot);
|
||||
var_object_test (ctx, s, var_name, op, bc, &label_done, 0);
|
||||
}
|
||||
|
||||
/* check eval object in argument scope */
|
||||
if (fd->arg_var_object_idx >= 0 && !is_pseudo_var) {
|
||||
int slot, depth;
|
||||
vd = &fd->vars[fd->arg_var_object_idx];
|
||||
vd->is_captured = 1;
|
||||
idx = get_closure_var (ctx, s, fd, FALSE, fd->arg_var_object_idx, vd->var_name, FALSE, FALSE, JS_VAR_NORMAL);
|
||||
dbuf_putc (bc, OP_get_var_ref);
|
||||
dbuf_put_u16 (bc, idx);
|
||||
depth = compute_closure_depth_slot(s, idx, &slot);
|
||||
dbuf_putc (bc, OP_get_up);
|
||||
dbuf_putc (bc, (uint8_t)depth);
|
||||
dbuf_put_u16 (bc, (uint16_t)slot);
|
||||
var_object_test (ctx, s, var_name, op, bc, &label_done, 0);
|
||||
}
|
||||
|
||||
@@ -15130,13 +14709,16 @@ static int resolve_scope_var (JSContext *ctx, JSFunctionDef *s, JSValue var_name
|
||||
} else if ((js_key_equal_str (cv->var_name, "_var_")
|
||||
|| js_key_equal_str (cv->var_name, "_arg_var_"))
|
||||
&& !is_pseudo_var) {
|
||||
int slot, depth;
|
||||
if (fd != s) {
|
||||
idx = get_closure_var2 (ctx, s, fd, FALSE, cv->is_arg, idx1, cv->var_name, FALSE, FALSE, JS_VAR_NORMAL);
|
||||
} else {
|
||||
idx = idx1;
|
||||
}
|
||||
dbuf_putc (bc, OP_get_var_ref);
|
||||
dbuf_put_u16 (bc, idx);
|
||||
depth = compute_closure_depth_slot(s, idx, &slot);
|
||||
dbuf_putc (bc, OP_get_up);
|
||||
dbuf_putc (bc, (uint8_t)depth);
|
||||
dbuf_put_u16 (bc, (uint16_t)slot);
|
||||
var_object_test (ctx, s, var_name, op, bc, &label_done, 0);
|
||||
}
|
||||
}
|
||||
@@ -15154,8 +14736,7 @@ static int resolve_scope_var (JSContext *ctx, JSFunctionDef *s, JSValue var_name
|
||||
}
|
||||
if (idx >= 0) {
|
||||
has_idx:
|
||||
if ((op == OP_scope_put_var || op == OP_scope_make_ref)
|
||||
&& s->closure_var[idx].is_const) {
|
||||
if (op == OP_scope_put_var && s->closure_var[idx].is_const) {
|
||||
int cpool_idx = fd_cpool_add (ctx, s, var_name);
|
||||
dbuf_putc (bc, OP_throw_error);
|
||||
dbuf_put_u32 (bc, cpool_idx);
|
||||
@@ -15163,69 +14744,6 @@ static int resolve_scope_var (JSContext *ctx, JSFunctionDef *s, JSValue var_name
|
||||
goto done;
|
||||
}
|
||||
switch (op) {
|
||||
case OP_scope_make_ref:
|
||||
if (s->closure_var[idx].var_kind == JS_VAR_FUNCTION_NAME) {
|
||||
/* Create a dummy object reference for the func_var */
|
||||
int cpool_idx = fd_cpool_add (ctx, s, var_name);
|
||||
if (cpool_idx < 0) return -1;
|
||||
dbuf_putc (bc, OP_object);
|
||||
dbuf_putc (bc, OP_get_var_ref);
|
||||
dbuf_put_u16 (bc, idx);
|
||||
dbuf_putc (bc, OP_define_field);
|
||||
dbuf_put_u32 (bc, cpool_idx);
|
||||
dbuf_putc (bc, OP_push_const);
|
||||
dbuf_put_u32 (bc, cpool_idx);
|
||||
} else if (label_done == -1
|
||||
&& can_opt_put_ref_value (bc_buf, ls->pos)) {
|
||||
/* Check if we can use new OP_set_up model for closure variables */
|
||||
int slot;
|
||||
int depth = compute_closure_depth_slot(s, idx, &slot);
|
||||
if (depth > 0 && depth <= 255 && slot <= 65535) {
|
||||
/* Use OP_get_up/OP_set_up for the make_ref optimization */
|
||||
int label_pos = ls->pos;
|
||||
int pos = label_pos - 5;
|
||||
int end_pos = label_pos + 2;
|
||||
if (bc_buf[pos_next] == OP_get_ref_value) {
|
||||
/* Get part - emit to bc output buffer */
|
||||
dbuf_putc (bc, OP_get_up);
|
||||
dbuf_putc (bc, (uint8_t)depth);
|
||||
dbuf_put_u16 (bc, (uint16_t)slot);
|
||||
pos_next++;
|
||||
}
|
||||
/* Put part - patch in-place in bc_buf */
|
||||
if (bc_buf[label_pos] == OP_insert3) {
|
||||
bc_buf[pos++] = OP_dup;
|
||||
}
|
||||
bc_buf[pos] = OP_set_up;
|
||||
bc_buf[pos + 1] = (uint8_t)depth;
|
||||
put_u16(bc_buf + pos + 2, (uint16_t)slot);
|
||||
pos += 4;
|
||||
/* Pad with nops */
|
||||
while (pos < end_pos)
|
||||
bc_buf[pos++] = OP_nop;
|
||||
} else {
|
||||
/* Fall back to old var_ref model */
|
||||
int get_op;
|
||||
if (s->closure_var[idx].is_lexical)
|
||||
get_op = OP_get_var_ref_check;
|
||||
else
|
||||
get_op = OP_get_var_ref;
|
||||
pos_next = optimize_scope_make_ref (ctx, s, bc, bc_buf, ls, pos_next, get_op, idx);
|
||||
}
|
||||
} else {
|
||||
/* Create a dummy object with a named slot that is
|
||||
a reference to the closure variable */
|
||||
int cpool_idx = fd_cpool_add (ctx, s, var_name);
|
||||
dbuf_putc (bc, OP_make_var_ref_ref);
|
||||
dbuf_put_u32 (bc, cpool_idx);
|
||||
dbuf_put_u16 (bc, idx);
|
||||
}
|
||||
break;
|
||||
case OP_scope_get_ref:
|
||||
/* XXX: should create a dummy object with a named slot that is
|
||||
a reference to the closure variable */
|
||||
dbuf_putc (bc, OP_null);
|
||||
/* fall thru */
|
||||
case OP_scope_get_var_undef:
|
||||
case OP_scope_get_var:
|
||||
case OP_scope_put_var:
|
||||
@@ -15235,39 +14753,14 @@ static int resolve_scope_var (JSContext *ctx, JSFunctionDef *s, JSValue var_name
|
||||
/* Use OP_get_up/OP_set_up with (depth, slot) encoding */
|
||||
int slot;
|
||||
int depth = compute_closure_depth_slot(s, idx, &slot);
|
||||
if (depth > 0 && depth <= 255 && slot <= 65535) {
|
||||
/* Can use the new outer_frame model */
|
||||
if (is_put) {
|
||||
dbuf_putc(bc, OP_set_up);
|
||||
} else {
|
||||
dbuf_putc(bc, OP_get_up);
|
||||
}
|
||||
dbuf_putc(bc, (uint8_t)depth);
|
||||
dbuf_put_u16(bc, (uint16_t)slot);
|
||||
assert(depth > 0 && depth <= 255 && slot <= 65535);
|
||||
if (is_put) {
|
||||
dbuf_putc(bc, OP_set_up);
|
||||
} else {
|
||||
/* Fall back to old var_ref model */
|
||||
if (is_put) {
|
||||
if (s->closure_var[idx].is_lexical) {
|
||||
if (op == OP_scope_put_var_init) {
|
||||
if (js_key_equal (var_name, JS_KEY_this))
|
||||
dbuf_putc (bc, OP_put_var_ref_check_init);
|
||||
else
|
||||
dbuf_putc (bc, OP_put_var_ref);
|
||||
} else {
|
||||
dbuf_putc (bc, OP_put_var_ref_check);
|
||||
}
|
||||
} else {
|
||||
dbuf_putc (bc, OP_put_var_ref);
|
||||
}
|
||||
} else {
|
||||
if (s->closure_var[idx].is_lexical) {
|
||||
dbuf_putc (bc, OP_get_var_ref_check);
|
||||
} else {
|
||||
dbuf_putc (bc, OP_get_var_ref);
|
||||
}
|
||||
}
|
||||
dbuf_put_u16 (bc, idx);
|
||||
dbuf_putc(bc, OP_get_up);
|
||||
}
|
||||
dbuf_putc(bc, (uint8_t)depth);
|
||||
dbuf_put_u16(bc, (uint16_t)slot);
|
||||
}
|
||||
break;
|
||||
case OP_scope_delete_var:
|
||||
@@ -15283,21 +14776,6 @@ static int resolve_scope_var (JSContext *ctx, JSFunctionDef *s, JSValue var_name
|
||||
int cpool_idx = fd_cpool_add (ctx, s, var_name);
|
||||
|
||||
switch (op) {
|
||||
case OP_scope_make_ref:
|
||||
if (label_done == -1 && can_opt_put_global_ref_value (bc_buf, ls->pos)) {
|
||||
pos_next = optimize_scope_make_global_ref (ctx, s, bc, bc_buf, ls, pos_next, var_name);
|
||||
} else {
|
||||
dbuf_putc (bc, OP_make_var_ref);
|
||||
dbuf_put_u32 (bc, cpool_idx);
|
||||
}
|
||||
break;
|
||||
case OP_scope_get_ref:
|
||||
/* XXX: should create a dummy object with a named slot that is
|
||||
a reference to the global variable */
|
||||
dbuf_putc (bc, OP_null);
|
||||
dbuf_putc (bc, OP_get_var);
|
||||
dbuf_put_u32 (bc, cpool_idx);
|
||||
break;
|
||||
case OP_scope_get_var_undef:
|
||||
case OP_scope_get_var:
|
||||
case OP_scope_put_var:
|
||||
@@ -15670,8 +15148,10 @@ static void instantiate_hoisted_definitions (JSContext *ctx, JSFunctionDef *s, D
|
||||
}
|
||||
if (js_key_equal_str (cv->var_name, "_var_")
|
||||
|| js_key_equal_str (cv->var_name, "_arg_var_")) {
|
||||
dbuf_putc (bc, OP_get_var_ref);
|
||||
dbuf_put_u16 (bc, idx);
|
||||
int slot, depth = compute_closure_depth_slot(s, idx, &slot);
|
||||
dbuf_putc (bc, OP_get_up);
|
||||
dbuf_putc (bc, (uint8_t)depth);
|
||||
dbuf_put_u16 (bc, (uint16_t)slot);
|
||||
has_closure = 1;
|
||||
force_init = TRUE;
|
||||
break;
|
||||
@@ -15716,8 +15196,10 @@ static void instantiate_hoisted_definitions (JSContext *ctx, JSFunctionDef *s, D
|
||||
dbuf_putc (bc, OP_null);
|
||||
}
|
||||
if (has_closure == 2) {
|
||||
dbuf_putc (bc, OP_put_var_ref);
|
||||
dbuf_put_u16 (bc, idx);
|
||||
int slot, depth = compute_closure_depth_slot(s, idx, &slot);
|
||||
dbuf_putc (bc, OP_set_up);
|
||||
dbuf_putc (bc, (uint8_t)depth);
|
||||
dbuf_put_u16 (bc, (uint16_t)slot);
|
||||
} else if (has_closure == 1) {
|
||||
int key_idx = fd_cpool_add (ctx, s, hf->var_name);
|
||||
dbuf_putc (bc, OP_define_field);
|
||||
@@ -15878,24 +15360,12 @@ static __exception int resolve_variables (JSContext *ctx, JSFunctionDef *s) {
|
||||
case OP_scope_get_var:
|
||||
case OP_scope_put_var:
|
||||
case OP_scope_delete_var:
|
||||
case OP_scope_get_ref:
|
||||
case OP_scope_put_var_init:
|
||||
cpool_idx = get_u32 (bc_buf + pos + 1);
|
||||
var_name = s->cpool[cpool_idx];
|
||||
scope = get_u16 (bc_buf + pos + 5);
|
||||
pos_next = resolve_scope_var (ctx, s, var_name, scope, op, &bc_out, NULL, NULL, pos_next);
|
||||
break;
|
||||
case OP_scope_make_ref: {
|
||||
int label;
|
||||
LabelSlot *ls;
|
||||
cpool_idx = get_u32 (bc_buf + pos + 1);
|
||||
var_name = s->cpool[cpool_idx];
|
||||
label = get_u32 (bc_buf + pos + 5);
|
||||
scope = get_u16 (bc_buf + pos + 9);
|
||||
ls = &s->label_slots[label];
|
||||
ls->ref_count--; /* always remove label reference */
|
||||
pos_next = resolve_scope_var (ctx, s, var_name, scope, op, &bc_out, bc_buf, ls, pos_next);
|
||||
} break;
|
||||
case OP_gosub:
|
||||
s->jump_size++;
|
||||
if (OPTIMIZE) {
|
||||
@@ -15937,9 +15407,8 @@ static __exception int resolve_variables (JSContext *ctx, JSFunctionDef *s) {
|
||||
goto no_change;
|
||||
case OP_insert3:
|
||||
if (OPTIMIZE) {
|
||||
/* Transformation: insert3 put_array_el|put_ref_value drop ->
|
||||
* put_array_el|put_ref_value */
|
||||
if (code_match (&cc, pos_next, M2 (OP_put_array_el, OP_put_ref_value), OP_drop, -1)) {
|
||||
/* Transformation: insert3 put_array_el drop -> put_array_el */
|
||||
if (code_match (&cc, pos_next, OP_put_array_el, OP_drop, -1)) {
|
||||
dbuf_putc (&bc_out, cc.op);
|
||||
pos_next = cc.pos;
|
||||
if (cc.line_num != -1 && cc.line_num != line_num) {
|
||||
@@ -16019,22 +15488,9 @@ static __exception int resolve_variables (JSContext *ctx, JSFunctionDef *s) {
|
||||
}
|
||||
} break;
|
||||
|
||||
case OP_leave_scope: {
|
||||
int scope_idx, scope = get_u16 (bc_buf + pos + 1);
|
||||
|
||||
for (scope_idx = s->scopes[scope].first; scope_idx >= 0;) {
|
||||
JSVarDef *vd = &s->vars[scope_idx];
|
||||
if (vd->scope_level == scope) {
|
||||
if (vd->is_captured) {
|
||||
dbuf_putc (&bc_out, OP_close_loc);
|
||||
dbuf_put_u16 (&bc_out, scope_idx);
|
||||
}
|
||||
scope_idx = vd->scope_next;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} break;
|
||||
case OP_leave_scope:
|
||||
/* With outer_frame model, captured variables don't need closing */
|
||||
break;
|
||||
|
||||
case OP_set_name: {
|
||||
/* remove dummy set_name opcodes */
|
||||
@@ -16740,7 +16196,7 @@ static __exception int resolve_labels (JSContext *ctx, JSFunctionDef *s) {
|
||||
case OP_to_propkey:
|
||||
if (OPTIMIZE) {
|
||||
/* remove redundant to_propkey opcodes when storing simple data */
|
||||
if (code_match (&cc, pos_next, M3 (OP_get_loc, OP_get_arg, OP_get_var_ref), -1, OP_put_array_el, -1)
|
||||
if (code_match (&cc, pos_next, M2 (OP_get_loc, OP_get_arg), -1, OP_put_array_el, -1)
|
||||
|| code_match (&cc, pos_next, M2 (OP_push_i32, OP_push_const), OP_put_array_el, -1)
|
||||
|| code_match (&cc, pos_next, M4 (OP_null, OP_null, OP_push_true, OP_push_false), OP_put_array_el, -1)) {
|
||||
break;
|
||||
@@ -16769,7 +16225,7 @@ static __exception int resolve_labels (JSContext *ctx, JSFunctionDef *s) {
|
||||
/* Transformation: dup put_x(n) drop -> put_x(n) */
|
||||
int op1, line2 = -1;
|
||||
/* Transformation: dup put_x(n) -> set_x(n) */
|
||||
if (code_match (&cc, pos_next, M3 (OP_put_loc, OP_put_arg, OP_put_var_ref), -1, -1)) {
|
||||
if (code_match (&cc, pos_next, M2 (OP_put_loc, OP_put_arg), -1, -1)) {
|
||||
if (cc.line_num >= 0) line_num = cc.line_num;
|
||||
op1 = cc.op + 1; /* put_x -> set_x */
|
||||
pos_next = cc.pos;
|
||||
@@ -16824,13 +16280,11 @@ static __exception int resolve_labels (JSContext *ctx, JSFunctionDef *s) {
|
||||
pos_next = cc.pos;
|
||||
break;
|
||||
}
|
||||
/* transformation: XXX: also do these:
|
||||
get_loc(n) get_loc(x) add dup put_loc(n) drop -> get_loc(x)
|
||||
add_loc(n) get_loc(n) get_arg(x) add dup put_loc(n) drop ->
|
||||
get_arg(x) add_loc(n) get_loc(n) get_var_ref(x) add dup put_loc(n)
|
||||
drop -> get_var_ref(x) add_loc(n)
|
||||
/* transformation:
|
||||
get_loc(n) get_loc(x) add dup put_loc(n) drop -> get_loc(x) add_loc(n)
|
||||
get_loc(n) get_arg(x) add dup put_loc(n) drop -> get_arg(x) add_loc(n)
|
||||
*/
|
||||
if (code_match (&cc, pos_next, M3 (OP_get_loc, OP_get_arg, OP_get_var_ref), -1, OP_add, OP_dup, OP_put_loc, idx, OP_drop, -1)) {
|
||||
if (code_match (&cc, pos_next, M2 (OP_get_loc, OP_get_arg), -1, OP_add, OP_dup, OP_put_loc, idx, OP_drop, -1)) {
|
||||
if (cc.line_num >= 0) line_num = cc.line_num;
|
||||
add_pc2line_info (s, bc_out.size, line_num);
|
||||
put_short_code (&bc_out, cc.op, cc.idx);
|
||||
@@ -16846,7 +16300,6 @@ static __exception int resolve_labels (JSContext *ctx, JSFunctionDef *s) {
|
||||
goto no_change;
|
||||
#if SHORT_OPCODES
|
||||
case OP_get_arg:
|
||||
case OP_get_var_ref:
|
||||
if (OPTIMIZE) {
|
||||
int idx;
|
||||
idx = get_u16 (bc_buf + pos + 1);
|
||||
@@ -16858,7 +16311,6 @@ static __exception int resolve_labels (JSContext *ctx, JSFunctionDef *s) {
|
||||
#endif
|
||||
case OP_put_loc:
|
||||
case OP_put_arg:
|
||||
case OP_put_var_ref:
|
||||
if (OPTIMIZE) {
|
||||
/* transformation: put_x(n) get_x(n) -> set_x(n) */
|
||||
int idx;
|
||||
@@ -16886,7 +16338,7 @@ static __exception int resolve_labels (JSContext *ctx, JSFunctionDef *s) {
|
||||
post_inc perm4 put_array_el drop -> inc put_array_el
|
||||
*/
|
||||
int op1, idx;
|
||||
if (code_match (&cc, pos_next, M3 (OP_put_loc, OP_put_arg, OP_put_var_ref), -1, OP_drop, -1)) {
|
||||
if (code_match (&cc, pos_next, M2 (OP_put_loc, OP_put_arg), -1, OP_drop, -1)) {
|
||||
if (cc.line_num >= 0) line_num = cc.line_num;
|
||||
op1 = cc.op;
|
||||
idx = cc.idx;
|
||||
|
||||
Reference in New Issue
Block a user