Skip to content

Commit e015918

Browse files
author
Fabrice Bellard
committed
Much faster destructuring at the expense of a slight incompatibility
with the spec when direct evals are present (v8 behaves the same way).
1 parent a6816be commit e015918

File tree

3 files changed

+103
-41
lines changed

3 files changed

+103
-41
lines changed

TODO

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,4 +63,4 @@ Test262o: 0/11262 errors, 463 excluded
6363
Test262o commit: 7da91bceb9ce7613f87db47ddd1292a2dda58b42 (es5-tests branch)
6464

6565
Test262:
66-
Result: 56/83147 errors, 1646 excluded, 5538 skipped
66+
Result: 66/83147 errors, 1646 excluded, 5538 skipped

quickjs.c

Lines changed: 89 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -25143,18 +25143,19 @@ static __exception int js_parse_array_literal(JSParseState *s)
2514325143
return js_parse_expect(s, ']');
2514425144
}
2514525145

25146-
/* XXX: remove */
25146+
/* check if scope chain contains a with statement */
2514725147
static BOOL has_with_scope(JSFunctionDef *s, int scope_level)
2514825148
{
25149-
/* check if scope chain contains a with statement */
2515025149
while (s) {
25151-
int scope_idx = s->scopes[scope_level].first;
25152-
while (scope_idx >= 0) {
25153-
JSVarDef *vd = &s->vars[scope_idx];
25154-
25155-
if (vd->var_name == JS_ATOM__with_)
25156-
return TRUE;
25157-
scope_idx = vd->scope_next;
25150+
/* no with in strict mode */
25151+
if (!(s->js_mode & JS_MODE_STRICT)) {
25152+
int scope_idx = s->scopes[scope_level].first;
25153+
while (scope_idx >= 0) {
25154+
JSVarDef *vd = &s->vars[scope_idx];
25155+
if (vd->var_name == JS_ATOM__with_)
25156+
return TRUE;
25157+
scope_idx = vd->scope_next;
25158+
}
2515825159
}
2515925160
/* check parent scopes */
2516025161
scope_level = s->parent_scope_level;
@@ -25187,7 +25188,11 @@ static __exception int get_lvalue(JSParseState *s, int *popcode, int *pscope,
2518725188
}
2518825189
if (name == JS_ATOM_this || name == JS_ATOM_new_target)
2518925190
goto invalid_lvalue;
25190-
depth = 2; /* will generate OP_get_ref_value */
25191+
if (has_with_scope(fd, scope)) {
25192+
depth = 2; /* will generate OP_get_ref_value */
25193+
} else {
25194+
depth = 0;
25195+
}
2519125196
break;
2519225197
case OP_get_field:
2519325198
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,
2522425229
/* get the value but keep the object/fields on the stack */
2522525230
switch(opcode) {
2522625231
case OP_scope_get_var:
25227-
label = new_label(s);
25228-
if (label < 0)
25229-
return -1;
25230-
emit_op(s, OP_scope_make_ref);
25231-
emit_atom(s, name);
25232-
emit_u32(s, label);
25233-
emit_u16(s, scope);
25234-
update_label(fd, label, 1);
25235-
emit_op(s, OP_get_ref_value);
25236-
opcode = OP_get_ref_value;
25232+
if (depth != 0) {
25233+
label = new_label(s);
25234+
if (label < 0)
25235+
return -1;
25236+
emit_op(s, OP_scope_make_ref);
25237+
emit_atom(s, name);
25238+
emit_u32(s, label);
25239+
emit_u16(s, scope);
25240+
update_label(fd, label, 1);
25241+
emit_op(s, OP_get_ref_value);
25242+
opcode = OP_get_ref_value;
25243+
} else {
25244+
emit_op(s, OP_scope_get_var);
25245+
emit_atom(s, name);
25246+
emit_u16(s, scope);
25247+
}
2523725248
break;
2523825249
case OP_get_field:
2523925250
emit_op(s, OP_get_field2);
@@ -25258,15 +25269,17 @@ static __exception int get_lvalue(JSParseState *s, int *popcode, int *pscope,
2525825269
} else {
2525925270
switch(opcode) {
2526025271
case OP_scope_get_var:
25261-
label = new_label(s);
25262-
if (label < 0)
25263-
return -1;
25264-
emit_op(s, OP_scope_make_ref);
25265-
emit_atom(s, name);
25266-
emit_u32(s, label);
25267-
emit_u16(s, scope);
25268-
update_label(fd, label, 1);
25269-
opcode = OP_get_ref_value;
25272+
if (depth != 0) {
25273+
label = new_label(s);
25274+
if (label < 0)
25275+
return -1;
25276+
emit_op(s, OP_scope_make_ref);
25277+
emit_atom(s, name);
25278+
emit_u32(s, label);
25279+
emit_u16(s, scope);
25280+
update_label(fd, label, 1);
25281+
opcode = OP_get_ref_value;
25282+
}
2527025283
break;
2527125284
default:
2527225285
break;
@@ -25300,6 +25313,21 @@ static void put_lvalue(JSParseState *s, int opcode, int scope,
2530025313
BOOL is_let)
2530125314
{
2530225315
switch(opcode) {
25316+
case OP_scope_get_var:
25317+
/* depth = 0 */
25318+
switch(special) {
25319+
case PUT_LVALUE_NOKEEP:
25320+
case PUT_LVALUE_NOKEEP_DEPTH:
25321+
case PUT_LVALUE_KEEP_SECOND:
25322+
case PUT_LVALUE_NOKEEP_BOTTOM:
25323+
break;
25324+
case PUT_LVALUE_KEEP_TOP:
25325+
emit_op(s, OP_dup);
25326+
break;
25327+
default:
25328+
abort();
25329+
}
25330+
break;
2530325331
case OP_get_field:
2530425332
case OP_scope_get_private_field:
2530525333
/* depth = 1 */
@@ -25371,8 +25399,6 @@ static void put_lvalue(JSParseState *s, int opcode, int scope,
2537125399

2537225400
switch(opcode) {
2537325401
case OP_scope_get_var: /* val -- */
25374-
assert(special == PUT_LVALUE_NOKEEP ||
25375-
special == PUT_LVALUE_NOKEEP_DEPTH);
2537625402
emit_op(s, is_let ? OP_scope_put_var_init : OP_scope_put_var);
2537725403
emit_u32(s, name); /* has refcount */
2537825404
emit_u16(s, scope);
@@ -25726,6 +25752,8 @@ static int js_parse_destructuring_element(JSParseState *s, int tok, int is_arg,
2572625752
/* swap ref and lvalue object if any */
2572725753
if (prop_name == JS_ATOM_NULL) {
2572825754
switch(depth_lvalue) {
25755+
case 0:
25756+
break;
2572925757
case 1:
2573025758
/* source prop x -> x source prop */
2573125759
emit_op(s, OP_rot3r);
@@ -25739,9 +25767,13 @@ static int js_parse_destructuring_element(JSParseState *s, int tok, int is_arg,
2573925767
emit_op(s, OP_rot5l);
2574025768
emit_op(s, OP_rot5l);
2574125769
break;
25770+
default:
25771+
abort();
2574225772
}
2574325773
} else {
2574425774
switch(depth_lvalue) {
25775+
case 0:
25776+
break;
2574525777
case 1:
2574625778
/* source x -> x source */
2574725779
emit_op(s, OP_swap);
@@ -25754,6 +25786,8 @@ static int js_parse_destructuring_element(JSParseState *s, int tok, int is_arg,
2575425786
/* source x y z -> x y z source */
2575525787
emit_op(s, OP_rot4l);
2575625788
break;
25789+
default:
25790+
abort();
2575725791
}
2575825792
}
2575925793
}
@@ -27405,7 +27439,7 @@ static __exception int js_parse_assign_expr2(JSParseState *s, int parse_flags)
2740527439
}
2740627440

2740727441
if (op == '=') {
27408-
if (opcode == OP_get_ref_value && name == name0) {
27442+
if ((opcode == OP_get_ref_value || opcode == OP_scope_get_var) && name == name0) {
2740927443
set_object_name(s, name);
2741027444
}
2741127445
} else {
@@ -27440,11 +27474,14 @@ static __exception int js_parse_assign_expr2(JSParseState *s, int parse_flags)
2744027474
return -1;
2744127475
}
2744227476

27443-
if (opcode == OP_get_ref_value && name == name0) {
27477+
if ((opcode == OP_get_ref_value || opcode == OP_scope_get_var) && name == name0) {
2744427478
set_object_name(s, name);
2744527479
}
2744627480

2744727481
switch(depth_lvalue) {
27482+
case 0:
27483+
emit_op(s, OP_dup);
27484+
break;
2744827485
case 1:
2744927486
emit_op(s, OP_insert2);
2745027487
break;
@@ -32202,14 +32239,22 @@ static int resolve_scope_var(JSContext *ctx, JSFunctionDef *s,
3220232239
}
3220332240
}
3220432241
break;
32242+
case OP_scope_put_var:
32243+
if (!(var_idx & ARGUMENT_VAR_OFFSET) &&
32244+
s->vars[var_idx].var_kind == JS_VAR_FUNCTION_NAME) {
32245+
/* in non strict mode, modifying the function name is ignored */
32246+
dbuf_putc(bc, OP_drop);
32247+
goto done;
32248+
}
32249+
goto local_scope_var;
3220532250
case OP_scope_get_ref:
3220632251
dbuf_putc(bc, OP_undefined);
32207-
/* fall thru */
32252+
goto local_scope_var;
3220832253
case OP_scope_get_var_checkthis:
3220932254
case OP_scope_get_var_undef:
3221032255
case OP_scope_get_var:
32211-
case OP_scope_put_var:
3221232256
case OP_scope_put_var_init:
32257+
local_scope_var:
3221332258
is_put = (op == OP_scope_put_var || op == OP_scope_put_var_init);
3221432259
if (var_idx & ARGUMENT_VAR_OFFSET) {
3221532260
dbuf_putc(bc, OP_get_arg + is_put);
@@ -32497,15 +32542,22 @@ static int resolve_scope_var(JSContext *ctx, JSFunctionDef *s,
3249732542
dbuf_put_u16(bc, idx);
3249832543
}
3249932544
break;
32545+
case OP_scope_put_var:
32546+
if (s->closure_var[idx].var_kind == JS_VAR_FUNCTION_NAME) {
32547+
/* in non strict mode, modifying the function name is ignored */
32548+
dbuf_putc(bc, OP_drop);
32549+
goto done;
32550+
}
32551+
goto closure_scope_var;
3250032552
case OP_scope_get_ref:
3250132553
/* XXX: should create a dummy object with a named slot that is
3250232554
a reference to the closure variable */
3250332555
dbuf_putc(bc, OP_undefined);
32504-
/* fall thru */
32556+
goto closure_scope_var;
3250532557
case OP_scope_get_var_undef:
3250632558
case OP_scope_get_var:
32507-
case OP_scope_put_var:
3250832559
case OP_scope_put_var_init:
32560+
closure_scope_var:
3250932561
is_put = (op == OP_scope_put_var ||
3251032562
op == OP_scope_put_var_init);
3251132563
if (is_put) {

test262_errors.txt

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,19 @@ test262/test/annexB/language/expressions/assignmenttargettype/callexpression-in-
55
test262/test/annexB/language/expressions/assignmenttargettype/callexpression-in-prefix-update.js:27: SyntaxError: invalid increment/decrement operand
66
test262/test/annexB/language/expressions/assignmenttargettype/callexpression.js:33: SyntaxError: invalid assignment left-hand side
77
test262/test/annexB/language/expressions/assignmenttargettype/cover-callexpression-and-asyncarrowhead.js:20: SyntaxError: invalid assignment left-hand side
8+
test262/test/language/expressions/assignment/S11.13.1_A6_T1.js:23: Test262Error: #1: innerX === undefined. Actual: 1
9+
test262/test/language/expressions/assignment/S11.13.1_A6_T2.js:23: Test262Error: #1: innerX === 2. Actual: 1
10+
test262/test/language/expressions/compound-assignment/S11.13.2_A6.1_T1.js:24: Test262Error: #1: innerX === 2. Actual: 12
11+
test262/test/language/expressions/compound-assignment/S11.13.2_A6.2_T1.js:24: Test262Error: #1: innerX === 2. Actual: 5
12+
test262/test/language/expressions/compound-assignment/S11.13.2_A6.3_T1.js:24: Test262Error: #1: innerX === 2. Actual: 3
13+
test262/test/language/expressions/compound-assignment/S11.13.2_A6.4_T1.js:24: Test262Error: #1: innerX === 2. Actual: 4
14+
test262/test/language/expressions/compound-assignment/S11.13.2_A6.5_T1.js:24: Test262Error: #1: innerX === 2. Actual: 4
15+
test262/test/language/expressions/compound-assignment/S11.13.2_A6.6_T1.js:24: Test262Error: #1: innerX === 2. Actual: 8
16+
test262/test/language/expressions/compound-assignment/S11.13.2_A6.7_T1.js:24: Test262Error: #1: innerX === 2. Actual: 4
17+
test262/test/language/expressions/compound-assignment/S11.13.2_A6.8_T1.js:24: Test262Error: #1: innerX === 2. Actual: 4
18+
test262/test/language/expressions/compound-assignment/S11.13.2_A6.9_T1.js:24: Test262Error: #1: innerX === 2. Actual: 1
19+
test262/test/language/expressions/compound-assignment/S11.13.2_A6.10_T1.js:24: Test262Error: #1: innerX === 2. Actual: 5
20+
test262/test/language/expressions/compound-assignment/S11.13.2_A6.11_T1.js:24: Test262Error: #1: innerX === 2. Actual: 5
821
test262/test/language/identifier-resolution/assign-to-global-undefined.js:20: strict mode: expected error
922
test262/test/staging/sm/Function/arguments-parameter-shadowing.js:14: Test262Error: Expected SameValue(«true», «false») to be true
1023
test262/test/staging/sm/Function/constructor-binding.js:11: Test262Error: Expected SameValue(«"function"», «"undefined"») to be true
@@ -35,9 +48,6 @@ test262/test/staging/sm/class/boundFunctionSubclassing.js:9: strict mode: Test26
3548
test262/test/staging/sm/class/strictExecution.js:13: Test262Error: Expected a TypeError to be thrown but no exception was thrown at all
3649
test262/test/staging/sm/class/superPropOrdering.js:17: Test262Error: Expected a TypeError to be thrown but no exception was thrown at all
3750
test262/test/staging/sm/class/superPropOrdering.js:17: strict mode: Test262Error: Expected a TypeError to be thrown but no exception was thrown at all
38-
test262/test/staging/sm/expressions/short-circuit-compound-assignment-const.js:96: TypeError: 'a' is read-only
39-
test262/test/staging/sm/expressions/short-circuit-compound-assignment-tdz.js:18: Test262Error: Expected a ReferenceError but got a TypeError
40-
test262/test/staging/sm/expressions/short-circuit-compound-assignment-tdz.js:18: strict mode: Test262Error: Expected a ReferenceError but got a TypeError
4151
test262/test/staging/sm/generators/syntax.js:50: Test262Error: Expected a SyntaxError to be thrown but no exception was thrown at all
4252
test262/test/staging/sm/lexical-environment/block-scoped-functions-annex-b-arguments.js:13: Test262Error: Expected SameValue(«"object"», «"function"») to be true
4353
test262/test/staging/sm/lexical-environment/block-scoped-functions-annex-b-eval.js:11: Test262Error: Expected SameValue(«"outer-gouter-geval-gtruefalseq"», «"outer-geval-gwith-gtruefalseq"») to be true

0 commit comments

Comments
 (0)