mirror of
https://github.com/bellard/quickjs.git
synced 2025-11-15 18:22:15 +03:00
Much faster destructuring at the expense of a slight incompatibility
with the spec when direct evals are present (v8 behaves the same way).
This commit is contained in:
126
quickjs.c
126
quickjs.c
@@ -25143,18 +25143,19 @@ done:
|
||||
return js_parse_expect(s, ']');
|
||||
}
|
||||
|
||||
/* XXX: remove */
|
||||
/* check if scope chain contains a with statement */
|
||||
static BOOL has_with_scope(JSFunctionDef *s, int scope_level)
|
||||
{
|
||||
/* check if scope chain contains a with statement */
|
||||
while (s) {
|
||||
int scope_idx = s->scopes[scope_level].first;
|
||||
while (scope_idx >= 0) {
|
||||
JSVarDef *vd = &s->vars[scope_idx];
|
||||
|
||||
if (vd->var_name == JS_ATOM__with_)
|
||||
return TRUE;
|
||||
scope_idx = vd->scope_next;
|
||||
/* no with in strict mode */
|
||||
if (!(s->js_mode & JS_MODE_STRICT)) {
|
||||
int scope_idx = s->scopes[scope_level].first;
|
||||
while (scope_idx >= 0) {
|
||||
JSVarDef *vd = &s->vars[scope_idx];
|
||||
if (vd->var_name == JS_ATOM__with_)
|
||||
return TRUE;
|
||||
scope_idx = vd->scope_next;
|
||||
}
|
||||
}
|
||||
/* check parent scopes */
|
||||
scope_level = s->parent_scope_level;
|
||||
@@ -25187,7 +25188,11 @@ static __exception int get_lvalue(JSParseState *s, int *popcode, int *pscope,
|
||||
}
|
||||
if (name == JS_ATOM_this || name == JS_ATOM_new_target)
|
||||
goto invalid_lvalue;
|
||||
depth = 2; /* will generate OP_get_ref_value */
|
||||
if (has_with_scope(fd, scope)) {
|
||||
depth = 2; /* will generate OP_get_ref_value */
|
||||
} else {
|
||||
depth = 0;
|
||||
}
|
||||
break;
|
||||
case OP_get_field:
|
||||
name = get_u32(fd->byte_code.buf + fd->last_opcode_pos + 1);
|
||||
@@ -25224,16 +25229,22 @@ static __exception int get_lvalue(JSParseState *s, int *popcode, int *pscope,
|
||||
/* get the value but keep the object/fields on the stack */
|
||||
switch(opcode) {
|
||||
case OP_scope_get_var:
|
||||
label = new_label(s);
|
||||
if (label < 0)
|
||||
return -1;
|
||||
emit_op(s, OP_scope_make_ref);
|
||||
emit_atom(s, name);
|
||||
emit_u32(s, label);
|
||||
emit_u16(s, scope);
|
||||
update_label(fd, label, 1);
|
||||
emit_op(s, OP_get_ref_value);
|
||||
opcode = OP_get_ref_value;
|
||||
if (depth != 0) {
|
||||
label = new_label(s);
|
||||
if (label < 0)
|
||||
return -1;
|
||||
emit_op(s, OP_scope_make_ref);
|
||||
emit_atom(s, name);
|
||||
emit_u32(s, label);
|
||||
emit_u16(s, scope);
|
||||
update_label(fd, label, 1);
|
||||
emit_op(s, OP_get_ref_value);
|
||||
opcode = OP_get_ref_value;
|
||||
} else {
|
||||
emit_op(s, OP_scope_get_var);
|
||||
emit_atom(s, name);
|
||||
emit_u16(s, scope);
|
||||
}
|
||||
break;
|
||||
case OP_get_field:
|
||||
emit_op(s, OP_get_field2);
|
||||
@@ -25258,15 +25269,17 @@ static __exception int get_lvalue(JSParseState *s, int *popcode, int *pscope,
|
||||
} else {
|
||||
switch(opcode) {
|
||||
case OP_scope_get_var:
|
||||
label = new_label(s);
|
||||
if (label < 0)
|
||||
return -1;
|
||||
emit_op(s, OP_scope_make_ref);
|
||||
emit_atom(s, name);
|
||||
emit_u32(s, label);
|
||||
emit_u16(s, scope);
|
||||
update_label(fd, label, 1);
|
||||
opcode = OP_get_ref_value;
|
||||
if (depth != 0) {
|
||||
label = new_label(s);
|
||||
if (label < 0)
|
||||
return -1;
|
||||
emit_op(s, OP_scope_make_ref);
|
||||
emit_atom(s, name);
|
||||
emit_u32(s, label);
|
||||
emit_u16(s, scope);
|
||||
update_label(fd, label, 1);
|
||||
opcode = OP_get_ref_value;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -25300,6 +25313,21 @@ static void put_lvalue(JSParseState *s, int opcode, int scope,
|
||||
BOOL is_let)
|
||||
{
|
||||
switch(opcode) {
|
||||
case OP_scope_get_var:
|
||||
/* depth = 0 */
|
||||
switch(special) {
|
||||
case PUT_LVALUE_NOKEEP:
|
||||
case PUT_LVALUE_NOKEEP_DEPTH:
|
||||
case PUT_LVALUE_KEEP_SECOND:
|
||||
case PUT_LVALUE_NOKEEP_BOTTOM:
|
||||
break;
|
||||
case PUT_LVALUE_KEEP_TOP:
|
||||
emit_op(s, OP_dup);
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
break;
|
||||
case OP_get_field:
|
||||
case OP_scope_get_private_field:
|
||||
/* depth = 1 */
|
||||
@@ -25371,8 +25399,6 @@ static void put_lvalue(JSParseState *s, int opcode, int scope,
|
||||
|
||||
switch(opcode) {
|
||||
case OP_scope_get_var: /* val -- */
|
||||
assert(special == PUT_LVALUE_NOKEEP ||
|
||||
special == PUT_LVALUE_NOKEEP_DEPTH);
|
||||
emit_op(s, is_let ? OP_scope_put_var_init : OP_scope_put_var);
|
||||
emit_u32(s, name); /* has refcount */
|
||||
emit_u16(s, scope);
|
||||
@@ -25726,6 +25752,8 @@ static int js_parse_destructuring_element(JSParseState *s, int tok, int is_arg,
|
||||
/* swap ref and lvalue object if any */
|
||||
if (prop_name == JS_ATOM_NULL) {
|
||||
switch(depth_lvalue) {
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
/* source prop x -> x source prop */
|
||||
emit_op(s, OP_rot3r);
|
||||
@@ -25739,9 +25767,13 @@ static int js_parse_destructuring_element(JSParseState *s, int tok, int is_arg,
|
||||
emit_op(s, OP_rot5l);
|
||||
emit_op(s, OP_rot5l);
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
} else {
|
||||
switch(depth_lvalue) {
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
/* source x -> x source */
|
||||
emit_op(s, OP_swap);
|
||||
@@ -25754,6 +25786,8 @@ static int js_parse_destructuring_element(JSParseState *s, int tok, int is_arg,
|
||||
/* source x y z -> x y z source */
|
||||
emit_op(s, OP_rot4l);
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -27405,7 +27439,7 @@ static __exception int js_parse_assign_expr2(JSParseState *s, int parse_flags)
|
||||
}
|
||||
|
||||
if (op == '=') {
|
||||
if (opcode == OP_get_ref_value && name == name0) {
|
||||
if ((opcode == OP_get_ref_value || opcode == OP_scope_get_var) && name == name0) {
|
||||
set_object_name(s, name);
|
||||
}
|
||||
} else {
|
||||
@@ -27440,11 +27474,14 @@ static __exception int js_parse_assign_expr2(JSParseState *s, int parse_flags)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (opcode == OP_get_ref_value && name == name0) {
|
||||
if ((opcode == OP_get_ref_value || opcode == OP_scope_get_var) && name == name0) {
|
||||
set_object_name(s, name);
|
||||
}
|
||||
|
||||
switch(depth_lvalue) {
|
||||
case 0:
|
||||
emit_op(s, OP_dup);
|
||||
break;
|
||||
case 1:
|
||||
emit_op(s, OP_insert2);
|
||||
break;
|
||||
@@ -32202,14 +32239,22 @@ static int resolve_scope_var(JSContext *ctx, JSFunctionDef *s,
|
||||
}
|
||||
}
|
||||
break;
|
||||
case OP_scope_put_var:
|
||||
if (!(var_idx & ARGUMENT_VAR_OFFSET) &&
|
||||
s->vars[var_idx].var_kind == JS_VAR_FUNCTION_NAME) {
|
||||
/* in non strict mode, modifying the function name is ignored */
|
||||
dbuf_putc(bc, OP_drop);
|
||||
goto done;
|
||||
}
|
||||
goto local_scope_var;
|
||||
case OP_scope_get_ref:
|
||||
dbuf_putc(bc, OP_undefined);
|
||||
/* fall thru */
|
||||
goto local_scope_var;
|
||||
case OP_scope_get_var_checkthis:
|
||||
case OP_scope_get_var_undef:
|
||||
case OP_scope_get_var:
|
||||
case OP_scope_put_var:
|
||||
case OP_scope_put_var_init:
|
||||
local_scope_var:
|
||||
is_put = (op == OP_scope_put_var || op == OP_scope_put_var_init);
|
||||
if (var_idx & ARGUMENT_VAR_OFFSET) {
|
||||
dbuf_putc(bc, OP_get_arg + is_put);
|
||||
@@ -32497,15 +32542,22 @@ static int resolve_scope_var(JSContext *ctx, JSFunctionDef *s,
|
||||
dbuf_put_u16(bc, idx);
|
||||
}
|
||||
break;
|
||||
case OP_scope_put_var:
|
||||
if (s->closure_var[idx].var_kind == JS_VAR_FUNCTION_NAME) {
|
||||
/* in non strict mode, modifying the function name is ignored */
|
||||
dbuf_putc(bc, OP_drop);
|
||||
goto done;
|
||||
}
|
||||
goto closure_scope_var;
|
||||
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_undefined);
|
||||
/* fall thru */
|
||||
goto closure_scope_var;
|
||||
case OP_scope_get_var_undef:
|
||||
case OP_scope_get_var:
|
||||
case OP_scope_put_var:
|
||||
case OP_scope_put_var_init:
|
||||
closure_scope_var:
|
||||
is_put = (op == OP_scope_put_var ||
|
||||
op == OP_scope_put_var_init);
|
||||
if (is_put) {
|
||||
|
||||
Reference in New Issue
Block a user