summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--mrbgems/mruby-compiler/core/codegen.c44
-rw-r--r--test/t/syntax.rb38
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