70
70
8: dump stdlib functions
71
71
16: dump bytecode in hex
72
72
32: dump line number table
73
- 64: dump executed bytecode
73
+ 64: dump compute_stack_size
74
+ 128: dump executed bytecode
74
75
*/
75
76
//#define DUMP_BYTECODE (1)
76
77
/* dump the occurence of the automatic GC */
@@ -14330,7 +14331,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValue func_obj,
14330
14331
size_t alloca_size;
14331
14332
JSInlineCache *ic;
14332
14333
14333
- #if defined(DUMP_BYTECODE) && (DUMP_BYTECODE & 64 )
14334
+ #if defined(DUMP_BYTECODE) && (DUMP_BYTECODE & 128 )
14334
14335
#define DUMP_BYTECODE_OR_DONT(pc) dump_single_byte_code(ctx, pc, b);
14335
14336
#else
14336
14337
#define DUMP_BYTECODE_OR_DONT(pc)
@@ -14439,7 +14440,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValue func_obj,
14439
14440
ctx = b->realm; /* set the current realm */
14440
14441
ic = b->ic;
14441
14442
14442
- #if defined(DUMP_BYTECODE) && (DUMP_BYTECODE & 64 )
14443
+ #if defined(DUMP_BYTECODE) && (DUMP_BYTECODE & 128 )
14443
14444
print_func_name(b);
14444
14445
#endif
14445
14446
@@ -15575,26 +15576,21 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValue func_obj,
15575
15576
}
15576
15577
sp--;
15577
15578
BREAK;
15578
- CASE(OP_iterator_close_return ):
15579
+ CASE(OP_nip_catch ):
15579
15580
{
15580
15581
JSValue ret_val;
15581
- /* iter_obj next catch_offset ... ret_val ->
15582
- ret_eval iter_obj next catch_offset */
15582
+ /* catch_offset ... ret_val -> ret_eval */
15583
15583
ret_val = *--sp;
15584
15584
while (sp > stack_buf &&
15585
15585
JS_VALUE_GET_TAG(sp[-1]) != JS_TAG_CATCH_OFFSET) {
15586
15586
JS_FreeValue(ctx, *--sp);
15587
15587
}
15588
- if (unlikely(sp < stack_buf + 3 )) {
15589
- JS_ThrowInternalError(ctx, "iterator_close_return ");
15588
+ if (unlikely(sp == stack_buf)) {
15589
+ JS_ThrowInternalError(ctx, "nip_catch ");
15590
15590
JS_FreeValue(ctx, ret_val);
15591
15591
goto exception;
15592
15592
}
15593
- sp[0] = sp[-1];
15594
- sp[-1] = sp[-2];
15595
- sp[-2] = sp[-3];
15596
- sp[-3] = ret_val;
15597
- sp++;
15593
+ sp[-1] = ret_val;
15598
15594
}
15599
15595
BREAK;
15600
15596
@@ -23852,7 +23848,6 @@ static __exception int emit_break(JSParseState *s, JSAtom name, int is_cont)
23852
23848
static void emit_return(JSParseState *s, BOOL hasval)
23853
23849
{
23854
23850
BlockEnv *top;
23855
- int drop_count;
23856
23851
23857
23852
if (s->cur_func->func_kind != JS_FUNC_NORMAL) {
23858
23853
if (!hasval) {
@@ -23866,60 +23861,49 @@ static void emit_return(JSParseState *s, BOOL hasval)
23866
23861
}
23867
23862
}
23868
23863
23869
- drop_count = 0;
23870
23864
top = s->cur_func->top_break;
23871
23865
while (top != NULL) {
23872
- /* XXX: emit the appropriate OP_leave_scope opcodes? Probably not
23873
- required as all local variables will be closed upon returning
23874
- from JS_CallInternal, but not in the same order. */
23875
- if (top->has_iterator) {
23876
- /* with 'yield', the exact number of OP_drop to emit is
23877
- unknown, so we use a specific operation to look for
23878
- the catch offset */
23866
+ if (top->has_iterator || top->label_finally != -1) {
23879
23867
if (!hasval) {
23880
23868
emit_op(s, OP_undefined);
23881
23869
hasval = TRUE;
23882
23870
}
23883
- emit_op(s, OP_iterator_close_return);
23884
- if (s->cur_func->func_kind == JS_FUNC_ASYNC_GENERATOR) {
23885
- int label_next, label_next2;
23886
-
23887
- emit_op(s, OP_drop); /* catch offset */
23888
- emit_op(s, OP_drop); /* next */
23889
- emit_op(s, OP_get_field2);
23890
- emit_atom(s, JS_ATOM_return);
23891
- emit_ic(s, JS_ATOM_return);
23892
- /* stack: iter_obj return_func */
23893
- emit_op(s, OP_dup);
23894
- emit_op(s, OP_is_undefined_or_null);
23895
- label_next = emit_goto(s, OP_if_true, -1);
23896
- emit_op(s, OP_call_method);
23897
- emit_u16(s, 0);
23898
- emit_op(s, OP_iterator_check_object);
23899
- emit_op(s, OP_await);
23900
- label_next2 = emit_goto(s, OP_goto, -1);
23901
- emit_label(s, label_next);
23902
- emit_op(s, OP_drop);
23903
- emit_label(s, label_next2);
23904
- emit_op(s, OP_drop);
23871
+ /* Remove the stack elements up to and including the catch
23872
+ offset. When 'yield' is used in an expression we have
23873
+ no easy way to count them, so we use this specific
23874
+ instruction instead. */
23875
+ emit_op(s, OP_nip_catch);
23876
+ /* stack: iter_obj next ret_val */
23877
+ if (top->has_iterator) {
23878
+ if (s->cur_func->func_kind == JS_FUNC_ASYNC_GENERATOR) {
23879
+ int label_next, label_next2;
23880
+ emit_op(s, OP_nip); /* next */
23881
+ emit_op(s, OP_swap);
23882
+ emit_op(s, OP_get_field2);
23883
+ emit_atom(s, JS_ATOM_return);
23884
+ emit_ic(s, JS_ATOM_return);
23885
+ /* stack: iter_obj return_func */
23886
+ emit_op(s, OP_dup);
23887
+ emit_op(s, OP_is_undefined_or_null);
23888
+ label_next = emit_goto(s, OP_if_true, -1);
23889
+ emit_op(s, OP_call_method);
23890
+ emit_u16(s, 0);
23891
+ emit_op(s, OP_iterator_check_object);
23892
+ emit_op(s, OP_await);
23893
+ label_next2 = emit_goto(s, OP_goto, -1);
23894
+ emit_label(s, label_next);
23895
+ emit_op(s, OP_drop);
23896
+ emit_label(s, label_next2);
23897
+ emit_op(s, OP_drop);
23898
+ } else {
23899
+ emit_op(s, OP_rot3r);
23900
+ emit_op(s, OP_undefined); /* dummy catch offset */
23901
+ emit_op(s, OP_iterator_close);
23902
+ }
23905
23903
} else {
23906
- emit_op(s, OP_iterator_close);
23907
- }
23908
- drop_count = -3;
23909
- }
23910
- drop_count += top->drop_count;
23911
- if (top->label_finally != -1) {
23912
- while(drop_count) {
23913
- /* must keep the stack top if hasval */
23914
- emit_op(s, hasval ? OP_nip : OP_drop);
23915
- drop_count--;
23904
+ /* execute the "finally" block */
23905
+ emit_goto(s, OP_gosub, top->label_finally);
23916
23906
}
23917
- if (!hasval) {
23918
- /* must push return value to keep same stack size */
23919
- emit_op(s, OP_undefined);
23920
- hasval = TRUE;
23921
- }
23922
- emit_goto(s, OP_gosub, top->label_finally);
23923
23907
}
23924
23908
top = top->prev;
23925
23909
}
@@ -30431,14 +30415,15 @@ typedef struct StackSizeState {
30431
30415
int bc_len;
30432
30416
int stack_len_max;
30433
30417
uint16_t *stack_level_tab;
30418
+ int32_t *catch_pos_tab;
30434
30419
int *pc_stack;
30435
30420
int pc_stack_len;
30436
30421
int pc_stack_size;
30437
30422
} StackSizeState;
30438
30423
30439
30424
/* 'op' is only used for error indication */
30440
30425
static __exception int ss_check(JSContext *ctx, StackSizeState *s,
30441
- int pos, int op, int stack_len)
30426
+ int pos, int op, int stack_len, int catch_pos )
30442
30427
{
30443
30428
if ((unsigned)pos >= s->bc_len) {
30444
30429
JS_ThrowInternalError(ctx, "bytecode buffer overflow (op=%d, pc=%d)", op, pos);
@@ -30457,13 +30442,18 @@ static __exception int ss_check(JSContext *ctx, StackSizeState *s,
30457
30442
JS_ThrowInternalError(ctx, "inconsistent stack size: %d %d (pc=%d)",
30458
30443
s->stack_level_tab[pos], stack_len, pos);
30459
30444
return -1;
30445
+ } else if (s->catch_pos_tab[pos] != catch_pos) {
30446
+ JS_ThrowInternalError(ctx, "inconsistent catch position: %d %d (pc=%d)",
30447
+ s->catch_pos_tab[pos], catch_pos, pos);
30448
+ return -1;
30460
30449
} else {
30461
30450
return 0;
30462
30451
}
30463
30452
}
30464
30453
30465
30454
/* mark as explored and store the stack size */
30466
30455
s->stack_level_tab[pos] = stack_len;
30456
+ s->catch_pos_tab[pos] = catch_pos;
30467
30457
30468
30458
/* queue the new PC to explore */
30469
30459
if (js_resize_array(ctx, (void **)&s->pc_stack, sizeof(s->pc_stack[0]),
@@ -30478,7 +30468,7 @@ static __exception int compute_stack_size(JSContext *ctx,
30478
30468
int *pstack_size)
30479
30469
{
30480
30470
StackSizeState s_s, *s = &s_s;
30481
- int i, diff, n_pop, pos_next, stack_len, pos, op;
30471
+ int i, diff, n_pop, pos_next, stack_len, pos, op, catch_pos, catch_level ;
30482
30472
const JSOpCode *oi;
30483
30473
const uint8_t *bc_buf;
30484
30474
@@ -30491,24 +30481,32 @@ static __exception int compute_stack_size(JSContext *ctx,
30491
30481
return -1;
30492
30482
for(i = 0; i < s->bc_len; i++)
30493
30483
s->stack_level_tab[i] = 0xffff;
30494
- s->stack_len_max = 0;
30495
30484
s->pc_stack = NULL;
30485
+ s->catch_pos_tab = js_malloc(ctx, sizeof(s->catch_pos_tab[0]) * s->bc_len);
30486
+ if (!s->catch_pos_tab)
30487
+ goto fail;
30488
+
30489
+ s->stack_len_max = 0;
30496
30490
s->pc_stack_len = 0;
30497
30491
s->pc_stack_size = 0;
30498
30492
30499
30493
/* breadth-first graph exploration */
30500
- if (ss_check(ctx, s, 0, OP_invalid, 0))
30494
+ if (ss_check(ctx, s, 0, OP_invalid, 0, -1 ))
30501
30495
goto fail;
30502
30496
30503
30497
while (s->pc_stack_len > 0) {
30504
30498
pos = s->pc_stack[--s->pc_stack_len];
30505
30499
stack_len = s->stack_level_tab[pos];
30500
+ catch_pos = s->catch_pos_tab[pos];
30506
30501
op = bc_buf[pos];
30507
30502
if (op == 0 || op >= OP_COUNT) {
30508
30503
JS_ThrowInternalError(ctx, "invalid opcode (op=%d, pc=%d)", op, pos);
30509
30504
goto fail;
30510
30505
}
30511
30506
oi = &short_opcode_info(op);
30507
+ #if defined(DUMP_BYTECODE) && (DUMP_BYTECODE & 64)
30508
+ printf("%5d: %10s %5d %5d\n", pos, oi->name, stack_len, catch_pos);
30509
+ #endif
30512
30510
pos_next = pos + oi->size;
30513
30511
if (pos_next > s->bc_len) {
30514
30512
JS_ThrowInternalError(ctx, "bytecode buffer overflow (op=%d, pc=%d)", op, pos);
@@ -30559,54 +30557,103 @@ static __exception int compute_stack_size(JSContext *ctx,
30559
30557
case OP_if_true8:
30560
30558
case OP_if_false8:
30561
30559
diff = (int8_t)bc_buf[pos + 1];
30562
- if (ss_check(ctx, s, pos + 1 + diff, op, stack_len))
30560
+ if (ss_check(ctx, s, pos + 1 + diff, op, stack_len, catch_pos ))
30563
30561
goto fail;
30564
30562
break;
30565
30563
case OP_if_true:
30566
30564
case OP_if_false:
30567
- case OP_catch:
30568
30565
diff = get_u32(bc_buf + pos + 1);
30569
- if (ss_check(ctx, s, pos + 1 + diff, op, stack_len))
30566
+ if (ss_check(ctx, s, pos + 1 + diff, op, stack_len, catch_pos ))
30570
30567
goto fail;
30571
30568
break;
30572
30569
case OP_gosub:
30573
30570
diff = get_u32(bc_buf + pos + 1);
30574
- if (ss_check(ctx, s, pos + 1 + diff, op, stack_len + 1))
30571
+ if (ss_check(ctx, s, pos + 1 + diff, op, stack_len + 1, catch_pos ))
30575
30572
goto fail;
30576
30573
break;
30577
30574
case OP_with_get_var:
30578
30575
case OP_with_delete_var:
30579
30576
diff = get_u32(bc_buf + pos + 5);
30580
- if (ss_check(ctx, s, pos + 5 + diff, op, stack_len + 1))
30577
+ if (ss_check(ctx, s, pos + 5 + diff, op, stack_len + 1, catch_pos ))
30581
30578
goto fail;
30582
30579
break;
30583
30580
case OP_with_make_ref:
30584
30581
case OP_with_get_ref:
30585
30582
case OP_with_get_ref_undef:
30586
30583
diff = get_u32(bc_buf + pos + 5);
30587
- if (ss_check(ctx, s, pos + 5 + diff, op, stack_len + 2))
30584
+ if (ss_check(ctx, s, pos + 5 + diff, op, stack_len + 2, catch_pos ))
30588
30585
goto fail;
30589
30586
break;
30590
30587
case OP_with_put_var:
30591
30588
diff = get_u32(bc_buf + pos + 5);
30592
- if (ss_check(ctx, s, pos + 5 + diff, op, stack_len - 1))
30589
+ if (ss_check(ctx, s, pos + 5 + diff, op, stack_len - 1, catch_pos ))
30593
30590
goto fail;
30594
30591
break;
30595
-
30592
+ case OP_catch:
30593
+ diff = get_u32(bc_buf + pos + 1);
30594
+ if (ss_check(ctx, s, pos + 1 + diff, op, stack_len, catch_pos))
30595
+ goto fail;
30596
+ catch_pos = pos;
30597
+ break;
30598
+ case OP_for_of_start:
30599
+ case OP_for_await_of_start:
30600
+ catch_pos = pos;
30601
+ break;
30602
+ /* we assume the catch offset entry is only removed with
30603
+ some op codes */
30604
+ case OP_drop:
30605
+ catch_level = stack_len;
30606
+ goto check_catch;
30607
+ case OP_nip:
30608
+ catch_level = stack_len - 1;
30609
+ goto check_catch;
30610
+ case OP_nip1:
30611
+ catch_level = stack_len - 1;
30612
+ goto check_catch;
30613
+ case OP_iterator_close:
30614
+ catch_level = stack_len + 2;
30615
+ check_catch:
30616
+ /* Note: for for_of_start/for_await_of_start we consider
30617
+ the catch offset is on the first stack entry instead of
30618
+ the thirst */
30619
+ if (catch_pos >= 0) {
30620
+ int level;
30621
+ level = s->stack_level_tab[catch_pos];
30622
+ if (bc_buf[catch_pos] != OP_catch)
30623
+ level++; /* for_of_start, for_wait_of_start */
30624
+ /* catch_level = stack_level before op_catch is executed ? */
30625
+ if (catch_level == level) {
30626
+ catch_pos = s->catch_pos_tab[catch_pos];
30627
+ }
30628
+ }
30629
+ break;
30630
+ case OP_nip_catch:
30631
+ if (catch_pos < 0) {
30632
+ JS_ThrowInternalError(ctx, "nip_catch: no catch op (pc=%d)", pos);
30633
+ goto fail;
30634
+ }
30635
+ stack_len = s->stack_level_tab[catch_pos];
30636
+ if (bc_buf[catch_pos] != OP_catch)
30637
+ stack_len++; /* for_of_start, for_wait_of_start */
30638
+ stack_len++; /* no stack overflow is possible by construction */
30639
+ catch_pos = s->catch_pos_tab[catch_pos];
30640
+ break;
30596
30641
default:
30597
30642
break;
30598
30643
}
30599
- if (ss_check(ctx, s, pos_next, op, stack_len))
30644
+ if (ss_check(ctx, s, pos_next, op, stack_len, catch_pos ))
30600
30645
goto fail;
30601
30646
done_insn: ;
30602
30647
}
30603
- js_free(ctx, s->stack_level_tab);
30604
30648
js_free(ctx, s->pc_stack);
30649
+ js_free(ctx, s->catch_pos_tab);
30650
+ js_free(ctx, s->stack_level_tab);
30605
30651
*pstack_size = s->stack_len_max;
30606
30652
return 0;
30607
30653
fail:
30608
- js_free(ctx, s->stack_level_tab);
30609
30654
js_free(ctx, s->pc_stack);
30655
+ js_free(ctx, s->catch_pos_tab);
30656
+ js_free(ctx, s->stack_level_tab);
30610
30657
*pstack_size = 0;
30611
30658
return -1;
30612
30659
}
0 commit comments