diff options
| -rw-r--r-- | mrbgems/mruby-compiler/core/codegen.c | 44 | ||||
| -rw-r--r-- | test/t/syntax.rb | 38 |
2 files changed, 67 insertions, 15 deletions
diff --git a/mrbgems/mruby-compiler/core/codegen.c b/mrbgems/mruby-compiler/core/codegen.c index 5b779b63d..f3d6d2d25 100644 --- a/mrbgems/mruby-compiler/core/codegen.c +++ b/mrbgems/mruby-compiler/core/codegen.c @@ -398,17 +398,15 @@ gen_jmpdst(codegen_scope *s, uint32_t pc) { if (pc == JMPLINK_START) { - gen_S(s, 0); + pc = 0; } - else { - uint32_t pos2 = s->pc+2; - int32_t off = pc - pos2; + uint32_t pos2 = s->pc+2; + int32_t off = pc - pos2; - if (off > INT16_MAX || INT16_MIN > off) { - codegen_error(s, "too big jump offset"); - } - gen_S(s, (uint16_t)off); + if (off > INT16_MAX || INT16_MIN > off) { + codegen_error(s, "too big jump offset"); } + gen_S(s, (uint16_t)off); } static uint32_t @@ -490,12 +488,33 @@ gen_move(codegen_scope *s, uint16_t dst, uint16_t src, int nopeep) s->pc = s->lastpc; genop_2(s, data.insn, dst, data.b); break; + case OP_GETUPVAR: + if (nopeep || data.a != src || data.a < s->nlocals) goto normal; + s->pc = s->lastpc; + genop_3(s, data.insn, dst, data.b, data.c); + break; default: goto normal; } } } +static int search_upvar(codegen_scope *s, mrb_sym id, int *idx); + +static void +gen_getupvar(codegen_scope *s, uint16_t dst, mrb_sym id) +{ + int idx; + int lv = search_upvar(s, id, &idx); + + struct mrb_insn_data data = mrb_last_insn(s); + if (!no_peephole(s) && data.insn == OP_SETUPVAR && data.a == dst && data.b == idx && data.c == lv) { + /* skip GETUPVAR right after SETUPVAR */ + return; + } + genop_3(s, OP_GETUPVAR, dst, idx, lv); +} + static void gen_return(codegen_scope *s, uint8_t op, uint16_t src) { @@ -968,8 +987,7 @@ lambda_body(codegen_scope *s, node *tree, int blk) gen_move(s, idx, cursp(), 0); } else { - int lv = search_upvar(s, id, &idx); - genop_3(s, OP_GETUPVAR, cursp(), idx, lv); + gen_getupvar(s, cursp(), id); } i++; opt = opt->cdr; @@ -1007,8 +1025,7 @@ lambda_body(codegen_scope *s, node *tree, int blk) gen_move(s, idx, cursp(), 0); } else { - int lv = search_upvar(s, kwd_sym, &idx); - genop_3(s, OP_GETUPVAR, cursp(), idx, lv); + gen_getupvar(s, cursp(), kwd_sym); } jmp_def_set = genjmp_0(s, OP_JMP); dispatch(s, jmpif_key_p); @@ -2463,8 +2480,7 @@ codegen(codegen_scope *s, node *tree, int val) gen_move(s, cursp(), idx, val); } else { - int lv = search_upvar(s, nsym(tree), &idx); - genop_3(s, OP_GETUPVAR, cursp(), idx, lv); + gen_getupvar(s, cursp(), nsym(tree)); } push(); } diff --git a/test/t/syntax.rb b/test/t/syntax.rb index c4c99242b..515c8f361 100644 --- a/test/t/syntax.rb +++ b/test/t/syntax.rb @@ -48,7 +48,32 @@ assert('yield', '11.3.5') do end end -assert('redo in a for loop (#3275)') do +assert('break', '11.5.2.4.3') do + n = 0 + a = [] + while true + n += 1 + a.push(n) + if n > 3 + break + end + end + + assert_equal [1,2,3,4], a + + n = 0 + a = [] + 6.times do + n += 1 + a.push(n) + if n > 3 + break + end + end + assert_equal [1,2,3,4], a +end + +assert('redo', '11.5.2.4.5') do sum = 0 for i in 1..10 sum += i @@ -59,6 +84,17 @@ assert('redo in a for loop (#3275)') do end assert_equal 220, sum + + n = 0 + a = [] + 3.times do + n += 1 + if n == 2 + redo + end + a.push(n) + end + assert_equal [1,3,4], a end assert('Abbreviated variable assignment', '11.4.2.3.2') do |
