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_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( 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 */
|
/* Global variable opcodes - resolved by linker to get/set_global_slot */
|
||||||
DEF( define_var, 6, 0, 0, key_u8)
|
DEF( define_var, 6, 0, 0, key_u8)
|
||||||
DEF(check_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( get_arg, 3, 0, 1, arg)
|
||||||
DEF( put_arg, 3, 1, 0, arg) /* must come after get_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 */
|
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(set_loc_uninitialized, 3, 0, 0, loc)
|
||||||
DEF( get_loc_check, 3, 0, 1, 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, 3, 1, 0, loc) /* must come after get_loc_check */
|
||||||
DEF( put_loc_check_init, 3, 1, 0, loc)
|
DEF( put_loc_check_init, 3, 1, 0, loc)
|
||||||
DEF(get_loc_checkthis, 3, 0, 1, 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_false, 5, 1, 0, label)
|
||||||
DEF( if_true, 5, 1, 0, label) /* must come after if_false */
|
DEF( if_true, 5, 1, 0, label) /* must come after if_false */
|
||||||
DEF( goto, 5, 0, 0, label) /* must come after if_true */
|
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)
|
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 */
|
/* arithmetic/logic operations */
|
||||||
DEF( neg, 1, 1, 1, none)
|
DEF( neg, 1, 1, 1, none)
|
||||||
DEF( plus, 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_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_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_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_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(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 */
|
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));
|
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) {
|
int JS_DeleteProperty (JSContext *ctx, JSValue obj, JSValue prop) {
|
||||||
JSRecord *rec;
|
JSRecord *rec;
|
||||||
int slot;
|
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) {
|
static inline int to_digit (int c) {
|
||||||
if (c >= '0' && c <= '9')
|
if (c >= '0' && c <= '9')
|
||||||
return c - '0';
|
return c - '0';
|
||||||
@@ -7641,24 +7453,6 @@ restart:
|
|||||||
}
|
}
|
||||||
BREAK;
|
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);
|
CASE (OP_goto) : pc += (int32_t)get_u32 (pc);
|
||||||
if (unlikely (js_poll_interrupts (ctx))) goto exception;
|
if (unlikely (js_poll_interrupts (ctx))) goto exception;
|
||||||
BREAK;
|
BREAK;
|
||||||
@@ -8013,32 +7807,6 @@ restart:
|
|||||||
}
|
}
|
||||||
BREAK;
|
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) : {
|
CASE (OP_put_array_el) : {
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
@@ -8055,30 +7823,6 @@ restart:
|
|||||||
}
|
}
|
||||||
BREAK;
|
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) : {
|
CASE (OP_define_array_el) : {
|
||||||
int ret;
|
int ret;
|
||||||
ret = JS_SetPropertyValue (ctx, sp[-3], sp[-2], sp[-1]);
|
ret = JS_SetPropertyValue (ctx, sp[-3], sp[-2], sp[-1]);
|
||||||
@@ -8647,20 +8391,6 @@ restart:
|
|||||||
}
|
}
|
||||||
BREAK;
|
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) : {
|
CASE (OP_template_concat) : {
|
||||||
int n, i;
|
int n, i;
|
||||||
JSValue out;
|
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;
|
if (next_token (s)) goto var_error;
|
||||||
emit_op (s, OP_drop);
|
emit_op (s, OP_drop);
|
||||||
if (js_parse_assign_expr (s)) goto var_error;
|
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);
|
set_object_name (s, var_name);
|
||||||
emit_label (s, label_hasval);
|
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
|
statement can resolve to a method call of the
|
||||||
`with` context object
|
`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;
|
drop_count = 1;
|
||||||
} break;
|
} break;
|
||||||
@@ -12737,7 +12460,6 @@ static __exception int js_parse_postfix_expr (JSParseState *s,
|
|||||||
switch (opcode) {
|
switch (opcode) {
|
||||||
case OP_get_field:
|
case OP_get_field:
|
||||||
case OP_get_array_el:
|
case OP_get_array_el:
|
||||||
case OP_scope_get_ref:
|
|
||||||
emit_op (s, OP_call_method);
|
emit_op (s, OP_call_method);
|
||||||
emit_u16 (s, arg_count);
|
emit_u16 (s, arg_count);
|
||||||
break;
|
break;
|
||||||
@@ -14744,112 +14466,6 @@ static int compute_closure_depth_slot(JSFunctionDef *s, int closure_idx, int *ou
|
|||||||
return depth;
|
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) {
|
static int add_var_this (JSContext *ctx, JSFunctionDef *fd) {
|
||||||
return add_var (ctx, fd, JS_KEY_this);
|
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;) {
|
for (idx = s->scopes[scope_level].first; idx >= 0;) {
|
||||||
vd = &s->vars[idx];
|
vd = &s->vars[idx];
|
||||||
if (js_key_equal (vd->var_name, var_name)) {
|
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) {
|
if (vd->is_const) {
|
||||||
int cpool_idx = fd_cpool_add (ctx, s, var_name);
|
int cpool_idx = fd_cpool_add (ctx, s, var_name);
|
||||||
dbuf_putc (bc, OP_throw_error);
|
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 (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) {
|
&& !(var_idx & ARGUMENT_VAR_OFFSET) && s->vars[var_idx].is_const) {
|
||||||
/* only happens when assigning a function expression name
|
/* only happens when assigning a function expression name
|
||||||
in strict mode */
|
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
|
lexical variable, so it is never used in a with or var object. It
|
||||||
can be used with a closure (module global variable case). */
|
can be used with a closure (module global variable case). */
|
||||||
switch (op) {
|
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_checkthis:
|
||||||
case OP_scope_get_var_undef:
|
case OP_scope_get_var_undef:
|
||||||
case OP_scope_get_var:
|
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;) {
|
for (idx = fd->scopes[scope_level].first; idx >= 0;) {
|
||||||
vd = &fd->vars[idx];
|
vd = &fd->vars[idx];
|
||||||
if (js_key_equal (vd->var_name, var_name)) {
|
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) {
|
if (vd->is_const) {
|
||||||
int cpool_idx = fd_cpool_add (ctx, s, var_name);
|
int cpool_idx = fd_cpool_add (ctx, s, var_name);
|
||||||
dbuf_putc (bc, OP_throw_error);
|
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 */
|
/* check eval object */
|
||||||
if (!is_arg_scope && fd->var_object_idx >= 0 && !is_pseudo_var) {
|
if (!is_arg_scope && fd->var_object_idx >= 0 && !is_pseudo_var) {
|
||||||
|
int slot, depth;
|
||||||
vd = &fd->vars[fd->var_object_idx];
|
vd = &fd->vars[fd->var_object_idx];
|
||||||
vd->is_captured = 1;
|
vd->is_captured = 1;
|
||||||
idx = get_closure_var (ctx, s, fd, FALSE, fd->var_object_idx, vd->var_name, FALSE, FALSE, JS_VAR_NORMAL);
|
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);
|
depth = compute_closure_depth_slot(s, idx, &slot);
|
||||||
dbuf_put_u16 (bc, idx);
|
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);
|
var_object_test (ctx, s, var_name, op, bc, &label_done, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* check eval object in argument scope */
|
/* check eval object in argument scope */
|
||||||
if (fd->arg_var_object_idx >= 0 && !is_pseudo_var) {
|
if (fd->arg_var_object_idx >= 0 && !is_pseudo_var) {
|
||||||
|
int slot, depth;
|
||||||
vd = &fd->vars[fd->arg_var_object_idx];
|
vd = &fd->vars[fd->arg_var_object_idx];
|
||||||
vd->is_captured = 1;
|
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);
|
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);
|
depth = compute_closure_depth_slot(s, idx, &slot);
|
||||||
dbuf_put_u16 (bc, idx);
|
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);
|
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_")
|
} else if ((js_key_equal_str (cv->var_name, "_var_")
|
||||||
|| js_key_equal_str (cv->var_name, "_arg_var_"))
|
|| js_key_equal_str (cv->var_name, "_arg_var_"))
|
||||||
&& !is_pseudo_var) {
|
&& !is_pseudo_var) {
|
||||||
|
int slot, depth;
|
||||||
if (fd != s) {
|
if (fd != s) {
|
||||||
idx = get_closure_var2 (ctx, s, fd, FALSE, cv->is_arg, idx1, cv->var_name, FALSE, FALSE, JS_VAR_NORMAL);
|
idx = get_closure_var2 (ctx, s, fd, FALSE, cv->is_arg, idx1, cv->var_name, FALSE, FALSE, JS_VAR_NORMAL);
|
||||||
} else {
|
} else {
|
||||||
idx = idx1;
|
idx = idx1;
|
||||||
}
|
}
|
||||||
dbuf_putc (bc, OP_get_var_ref);
|
depth = compute_closure_depth_slot(s, idx, &slot);
|
||||||
dbuf_put_u16 (bc, idx);
|
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);
|
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) {
|
if (idx >= 0) {
|
||||||
has_idx:
|
has_idx:
|
||||||
if ((op == OP_scope_put_var || op == OP_scope_make_ref)
|
if (op == OP_scope_put_var && s->closure_var[idx].is_const) {
|
||||||
&& s->closure_var[idx].is_const) {
|
|
||||||
int cpool_idx = fd_cpool_add (ctx, s, var_name);
|
int cpool_idx = fd_cpool_add (ctx, s, var_name);
|
||||||
dbuf_putc (bc, OP_throw_error);
|
dbuf_putc (bc, OP_throw_error);
|
||||||
dbuf_put_u32 (bc, cpool_idx);
|
dbuf_put_u32 (bc, cpool_idx);
|
||||||
@@ -15163,69 +14744,6 @@ static int resolve_scope_var (JSContext *ctx, JSFunctionDef *s, JSValue var_name
|
|||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
switch (op) {
|
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_undef:
|
||||||
case OP_scope_get_var:
|
case OP_scope_get_var:
|
||||||
case OP_scope_put_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 */
|
/* Use OP_get_up/OP_set_up with (depth, slot) encoding */
|
||||||
int slot;
|
int slot;
|
||||||
int depth = compute_closure_depth_slot(s, idx, &slot);
|
int depth = compute_closure_depth_slot(s, idx, &slot);
|
||||||
if (depth > 0 && depth <= 255 && slot <= 65535) {
|
assert(depth > 0 && depth <= 255 && slot <= 65535);
|
||||||
/* Can use the new outer_frame model */
|
if (is_put) {
|
||||||
if (is_put) {
|
dbuf_putc(bc, OP_set_up);
|
||||||
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);
|
|
||||||
} else {
|
} else {
|
||||||
/* Fall back to old var_ref model */
|
dbuf_putc(bc, OP_get_up);
|
||||||
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, (uint8_t)depth);
|
||||||
|
dbuf_put_u16(bc, (uint16_t)slot);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case OP_scope_delete_var:
|
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);
|
int cpool_idx = fd_cpool_add (ctx, s, var_name);
|
||||||
|
|
||||||
switch (op) {
|
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_undef:
|
||||||
case OP_scope_get_var:
|
case OP_scope_get_var:
|
||||||
case OP_scope_put_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_")
|
if (js_key_equal_str (cv->var_name, "_var_")
|
||||||
|| js_key_equal_str (cv->var_name, "_arg_var_")) {
|
|| js_key_equal_str (cv->var_name, "_arg_var_")) {
|
||||||
dbuf_putc (bc, OP_get_var_ref);
|
int slot, depth = compute_closure_depth_slot(s, idx, &slot);
|
||||||
dbuf_put_u16 (bc, idx);
|
dbuf_putc (bc, OP_get_up);
|
||||||
|
dbuf_putc (bc, (uint8_t)depth);
|
||||||
|
dbuf_put_u16 (bc, (uint16_t)slot);
|
||||||
has_closure = 1;
|
has_closure = 1;
|
||||||
force_init = TRUE;
|
force_init = TRUE;
|
||||||
break;
|
break;
|
||||||
@@ -15716,8 +15196,10 @@ static void instantiate_hoisted_definitions (JSContext *ctx, JSFunctionDef *s, D
|
|||||||
dbuf_putc (bc, OP_null);
|
dbuf_putc (bc, OP_null);
|
||||||
}
|
}
|
||||||
if (has_closure == 2) {
|
if (has_closure == 2) {
|
||||||
dbuf_putc (bc, OP_put_var_ref);
|
int slot, depth = compute_closure_depth_slot(s, idx, &slot);
|
||||||
dbuf_put_u16 (bc, idx);
|
dbuf_putc (bc, OP_set_up);
|
||||||
|
dbuf_putc (bc, (uint8_t)depth);
|
||||||
|
dbuf_put_u16 (bc, (uint16_t)slot);
|
||||||
} else if (has_closure == 1) {
|
} else if (has_closure == 1) {
|
||||||
int key_idx = fd_cpool_add (ctx, s, hf->var_name);
|
int key_idx = fd_cpool_add (ctx, s, hf->var_name);
|
||||||
dbuf_putc (bc, OP_define_field);
|
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_get_var:
|
||||||
case OP_scope_put_var:
|
case OP_scope_put_var:
|
||||||
case OP_scope_delete_var:
|
case OP_scope_delete_var:
|
||||||
case OP_scope_get_ref:
|
|
||||||
case OP_scope_put_var_init:
|
case OP_scope_put_var_init:
|
||||||
cpool_idx = get_u32 (bc_buf + pos + 1);
|
cpool_idx = get_u32 (bc_buf + pos + 1);
|
||||||
var_name = s->cpool[cpool_idx];
|
var_name = s->cpool[cpool_idx];
|
||||||
scope = get_u16 (bc_buf + pos + 5);
|
scope = get_u16 (bc_buf + pos + 5);
|
||||||
pos_next = resolve_scope_var (ctx, s, var_name, scope, op, &bc_out, NULL, NULL, pos_next);
|
pos_next = resolve_scope_var (ctx, s, var_name, scope, op, &bc_out, NULL, NULL, pos_next);
|
||||||
break;
|
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:
|
case OP_gosub:
|
||||||
s->jump_size++;
|
s->jump_size++;
|
||||||
if (OPTIMIZE) {
|
if (OPTIMIZE) {
|
||||||
@@ -15937,9 +15407,8 @@ static __exception int resolve_variables (JSContext *ctx, JSFunctionDef *s) {
|
|||||||
goto no_change;
|
goto no_change;
|
||||||
case OP_insert3:
|
case OP_insert3:
|
||||||
if (OPTIMIZE) {
|
if (OPTIMIZE) {
|
||||||
/* Transformation: insert3 put_array_el|put_ref_value drop ->
|
/* Transformation: insert3 put_array_el drop -> put_array_el */
|
||||||
* put_array_el|put_ref_value */
|
if (code_match (&cc, pos_next, OP_put_array_el, OP_drop, -1)) {
|
||||||
if (code_match (&cc, pos_next, M2 (OP_put_array_el, OP_put_ref_value), OP_drop, -1)) {
|
|
||||||
dbuf_putc (&bc_out, cc.op);
|
dbuf_putc (&bc_out, cc.op);
|
||||||
pos_next = cc.pos;
|
pos_next = cc.pos;
|
||||||
if (cc.line_num != -1 && cc.line_num != line_num) {
|
if (cc.line_num != -1 && cc.line_num != line_num) {
|
||||||
@@ -16019,22 +15488,9 @@ static __exception int resolve_variables (JSContext *ctx, JSFunctionDef *s) {
|
|||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case OP_leave_scope: {
|
case OP_leave_scope:
|
||||||
int scope_idx, scope = get_u16 (bc_buf + pos + 1);
|
/* With outer_frame model, captured variables don't need closing */
|
||||||
|
break;
|
||||||
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_set_name: {
|
case OP_set_name: {
|
||||||
/* remove dummy set_name opcodes */
|
/* remove dummy set_name opcodes */
|
||||||
@@ -16740,7 +16196,7 @@ static __exception int resolve_labels (JSContext *ctx, JSFunctionDef *s) {
|
|||||||
case OP_to_propkey:
|
case OP_to_propkey:
|
||||||
if (OPTIMIZE) {
|
if (OPTIMIZE) {
|
||||||
/* remove redundant to_propkey opcodes when storing simple data */
|
/* 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, 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)) {
|
|| code_match (&cc, pos_next, M4 (OP_null, OP_null, OP_push_true, OP_push_false), OP_put_array_el, -1)) {
|
||||||
break;
|
break;
|
||||||
@@ -16769,7 +16225,7 @@ static __exception int resolve_labels (JSContext *ctx, JSFunctionDef *s) {
|
|||||||
/* Transformation: dup put_x(n) drop -> put_x(n) */
|
/* Transformation: dup put_x(n) drop -> put_x(n) */
|
||||||
int op1, line2 = -1;
|
int op1, line2 = -1;
|
||||||
/* Transformation: dup put_x(n) -> set_x(n) */
|
/* 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;
|
if (cc.line_num >= 0) line_num = cc.line_num;
|
||||||
op1 = cc.op + 1; /* put_x -> set_x */
|
op1 = cc.op + 1; /* put_x -> set_x */
|
||||||
pos_next = cc.pos;
|
pos_next = cc.pos;
|
||||||
@@ -16824,13 +16280,11 @@ static __exception int resolve_labels (JSContext *ctx, JSFunctionDef *s) {
|
|||||||
pos_next = cc.pos;
|
pos_next = cc.pos;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/* transformation: XXX: also do these:
|
/* transformation:
|
||||||
get_loc(n) get_loc(x) add dup put_loc(n) drop -> get_loc(x)
|
get_loc(n) get_loc(x) add dup put_loc(n) drop -> get_loc(x) add_loc(n)
|
||||||
add_loc(n) get_loc(n) get_arg(x) add dup put_loc(n) drop ->
|
get_loc(n) get_arg(x) add dup put_loc(n) drop -> get_arg(x) add_loc(n)
|
||||||
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)
|
|
||||||
*/
|
*/
|
||||||
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;
|
if (cc.line_num >= 0) line_num = cc.line_num;
|
||||||
add_pc2line_info (s, bc_out.size, line_num);
|
add_pc2line_info (s, bc_out.size, line_num);
|
||||||
put_short_code (&bc_out, cc.op, cc.idx);
|
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;
|
goto no_change;
|
||||||
#if SHORT_OPCODES
|
#if SHORT_OPCODES
|
||||||
case OP_get_arg:
|
case OP_get_arg:
|
||||||
case OP_get_var_ref:
|
|
||||||
if (OPTIMIZE) {
|
if (OPTIMIZE) {
|
||||||
int idx;
|
int idx;
|
||||||
idx = get_u16 (bc_buf + pos + 1);
|
idx = get_u16 (bc_buf + pos + 1);
|
||||||
@@ -16858,7 +16311,6 @@ static __exception int resolve_labels (JSContext *ctx, JSFunctionDef *s) {
|
|||||||
#endif
|
#endif
|
||||||
case OP_put_loc:
|
case OP_put_loc:
|
||||||
case OP_put_arg:
|
case OP_put_arg:
|
||||||
case OP_put_var_ref:
|
|
||||||
if (OPTIMIZE) {
|
if (OPTIMIZE) {
|
||||||
/* transformation: put_x(n) get_x(n) -> set_x(n) */
|
/* transformation: put_x(n) get_x(n) -> set_x(n) */
|
||||||
int idx;
|
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
|
post_inc perm4 put_array_el drop -> inc put_array_el
|
||||||
*/
|
*/
|
||||||
int op1, idx;
|
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;
|
if (cc.line_num >= 0) line_num = cc.line_num;
|
||||||
op1 = cc.op;
|
op1 = cc.op;
|
||||||
idx = cc.idx;
|
idx = cc.idx;
|
||||||
|
|||||||
Reference in New Issue
Block a user