summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorYukihiro "Matz" Matsumoto <[email protected]>2017-08-24 14:38:03 +0900
committerGitHub <[email protected]>2017-08-24 14:38:03 +0900
commit63f10a1ee59743c086afc339f25da4f6e100e765 (patch)
tree7694adf91bfc6ca0ebc26be50b3935d6c3deb3fc
parent4c9a60487799b923ff905def46cb2497bcc1e4dd (diff)
parent3366894a4084c9f44a38410daf6abad9e2da5b33 (diff)
downloadmruby-63f10a1ee59743c086afc339f25da4f6e100e765.tar.gz
mruby-63f10a1ee59743c086afc339f25da4f6e100e765.zip
Merge pull request #3788 from christopheraue/fix_codegen_op_send_nregs
Fixed register windows of OP_SENDs generated during codegen
-rw-r--r--mrbgems/mruby-compiler/core/codegen.c88
-rw-r--r--src/vm.c6
-rw-r--r--test/t/codegen.rb122
3 files changed, 168 insertions, 48 deletions
diff --git a/mrbgems/mruby-compiler/core/codegen.c b/mrbgems/mruby-compiler/core/codegen.c
index c63533fef..8f15a9b18 100644
--- a/mrbgems/mruby-compiler/core/codegen.c
+++ b/mrbgems/mruby-compiler/core/codegen.c
@@ -631,6 +631,7 @@ for_body(codegen_scope *s, node *tree)
scope_finish(s);
s = prev;
genop(s, MKOP_Abc(OP_LAMBDA, cursp(), s->irep->rlen-1, OP_L_BLOCK));
+ push();pop(); /* space for a block */
pop();
idx = new_msym(s, mrb_intern_lit(s->mrb, "each"));
genop(s, MKOP_ABC(OP_SENDB, cursp(), idx, 0));
@@ -870,7 +871,7 @@ gen_call(codegen_scope *s, node *tree, mrb_sym name, int sp, int val, int safe)
genop(s, MKOP_A(OP_LOADNIL, cursp()));
push();
genop(s, MKOP_AB(OP_MOVE, cursp(), recv));
- push(); pop(); /* space for a block */
+ push_n(2); pop_n(2); /* space for one arg and a block */
pop();
idx = new_msym(s, mrb_intern_lit(s->mrb, "=="));
genop(s, MKOP_ABC(OP_EQ, cursp(), idx, 1));
@@ -1095,6 +1096,7 @@ gen_vmassignment(codegen_scope *s, node *tree, int rhs, int val)
static void
gen_send_intern(codegen_scope *s)
{
+ push();pop(); /* space for a block */
pop();
genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "intern")), 0));
push();
@@ -1320,7 +1322,8 @@ codegen(codegen_scope *s, node *tree, int val)
if (n4 && n4->car && nint(n4->car->car) == NODE_SPLAT) {
codegen(s, n4->car, VAL);
genop(s, MKOP_AB(OP_MOVE, cursp(), exc));
- push_n(2); pop_n(3);
+ push_n(2); pop_n(2); /* space for one arg and a block */
+ pop();
genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "__case_eqq")), 1));
}
else {
@@ -1542,6 +1545,7 @@ codegen(codegen_scope *s, node *tree, int val)
codegen(s, n->car, VAL);
if (head) {
genop(s, MKOP_AB(OP_MOVE, cursp(), head));
+ push_n(2); pop_n(2); /* space for one arg and a block */
pop();
if (nint(n->car->car) == NODE_SPLAT) {
genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "__case_eqq")), 1));
@@ -1811,6 +1815,8 @@ codegen(codegen_scope *s, node *tree, int val)
}
else if (nint(tree->car->car) == NODE_CALL) {
node *n = tree->car->cdr;
+ int base, i, nargs = 0;
+ callargs = 0;
if (val) {
vsp = cursp();
@@ -1818,36 +1824,25 @@ codegen(codegen_scope *s, node *tree, int val)
}
codegen(s, n->car, VAL); /* receiver */
idx = new_msym(s, nsym(n->cdr->car));
+ base = cursp()-1;
if (n->cdr->cdr->car) {
- int base = cursp()-1;
- int nargs = gen_values(s, n->cdr->cdr->car->car, VAL, 1);
-
- /* copy receiver and arguments */
+ nargs = gen_values(s, n->cdr->cdr->car->car, VAL, 1);
if (nargs >= 0) {
- int i;
-
- genop(s, MKOP_AB(OP_MOVE, cursp(), base));
- for (i=0; i<nargs; i++) {
- genop(s, MKOP_AB(OP_MOVE, cursp()+i+1, base+i+1));
- }
- push_n(nargs+1);
- pop_n(nargs+1);
callargs = nargs;
}
- else {
- /* varargs */
+ else { /* varargs */
push();
- genop(s, MKOP_AB(OP_MOVE, cursp(), base));
- genop(s, MKOP_AB(OP_MOVE, cursp()+1, base+1));
+ nargs = 1;
callargs = CALL_MAXARGS;
}
- genop(s, MKOP_ABC(OP_SEND, cursp(), idx, callargs));
}
- else {
- genop(s, MKOP_AB(OP_MOVE, cursp(), cursp()-1));
- genop(s, MKOP_ABC(OP_SEND, cursp(), idx, 0));
- callargs = 0;
+ /* copy receiver and arguments */
+ genop(s, MKOP_AB(OP_MOVE, cursp(), base));
+ for (i=0; i<nargs; i++) {
+ genop(s, MKOP_AB(OP_MOVE, cursp()+i+1, base+i+1));
}
+ push_n(nargs+2);pop_n(nargs+2); /* space for receiver, arguments and a block */
+ genop(s, MKOP_ABC(OP_SEND, cursp(), idx, callargs));
push();
}
else {
@@ -1874,20 +1869,17 @@ codegen(codegen_scope *s, node *tree, int val)
genop(s, MKOP_AB(OP_MOVE, vsp, cursp()));
}
if (nint(tree->car->car) == NODE_CALL) {
- mrb_sym m = nsym(tree->car->cdr->cdr->car);
- mrb_sym m2 = attrsym(s, m);
-
- idx = new_msym(s, m2);
- pop();
if (callargs == CALL_MAXARGS) {
- genop(s, MKOP_AB(OP_ARYPUSH, cursp(), cursp()+1));
pop();
- genop(s, MKOP_ABC(OP_SEND, cursp(), idx, callargs));
+ genop(s, MKOP_AB(OP_ARYPUSH, cursp(), cursp()+1));
}
else {
pop_n(callargs);
- genop(s, MKOP_ABC(OP_SEND, cursp(), idx, callargs+1));
+ callargs++;
}
+ pop();
+ idx = new_msym(s, attrsym(s, nsym(tree->car->cdr->cdr->car)));
+ genop(s, MKOP_ABC(OP_SEND, cursp(), idx, callargs));
}
else {
gen_assignment(s, tree->car, cursp(), val);
@@ -2049,6 +2041,7 @@ codegen(codegen_scope *s, node *tree, int val)
push();
}
}
+ push();pop(); /* space for a block */
pop_n(n+1);
genop(s, MKOP_ABx(OP_BLKPUSH, cursp(), (ainfo<<4)|(lv & 0xf)));
if (sendv) n = CALL_MAXARGS;
@@ -2457,26 +2450,26 @@ codegen(codegen_scope *s, node *tree, int val)
genop(s, MKOP_ABx(OP_GETMCNST, cursp(), sym));
push();
genop(s, MKOP_ABx(OP_STRING, cursp(), off));
+ push();
if (p2 || p3) {
- push();
- if (p2) {
+ if (p2) { /* opt */
off = new_lit(s, mrb_str_new_cstr(s->mrb, p2));
genop(s, MKOP_ABx(OP_STRING, cursp(), off));
}
else {
genop(s, MKOP_A(OP_LOADNIL, cursp()));
}
+ push();
argc++;
- if (p3) {
- push();
+ if (p3) { /* enc */
off = new_lit(s, mrb_str_new(s->mrb, p3, 1));
genop(s, MKOP_ABx(OP_STRING, cursp(), off));
+ push();
argc++;
- pop();
}
- pop();
}
- pop();
+ push(); /* space for a block */
+ pop_n(argc+2);
sym = new_sym(s, mrb_intern_lit(s->mrb, "compile"));
genop(s, MKOP_ABC(OP_SEND, cursp(), sym, argc));
mrb_gc_arena_restore(s->mrb, ai);
@@ -2506,31 +2499,31 @@ codegen(codegen_scope *s, node *tree, int val)
n = n->cdr;
}
n = tree->cdr->cdr;
- if (n->car) {
+ if (n->car) { /* tail */
p = (char*)n->car;
off = new_lit(s, mrb_str_new_cstr(s->mrb, p));
codegen(s, tree->car, VAL);
genop(s, MKOP_ABx(OP_STRING, cursp(), off));
pop();
genop_peep(s, MKOP_AB(OP_STRCAT, cursp(), cursp()+1), VAL);
+ push();
}
- if (n->cdr->car) {
+ if (n->cdr->car) { /* opt */
char *p2 = (char*)n->cdr->car;
-
- push();
off = new_lit(s, mrb_str_new_cstr(s->mrb, p2));
genop(s, MKOP_ABx(OP_STRING, cursp(), off));
+ push();
argc++;
}
- if (n->cdr->cdr) {
+ if (n->cdr->cdr) { /* enc */
char *p2 = (char*)n->cdr->cdr;
-
- push();
off = new_lit(s, mrb_str_new_cstr(s->mrb, p2));
genop(s, MKOP_ABx(OP_STRING, cursp(), off));
+ push();
argc++;
}
- pop_n(argc);
+ push(); /* space for a block */
+ pop_n(argc+2);
sym = new_sym(s, mrb_intern_lit(s->mrb, "compile"));
genop(s, MKOP_ABC(OP_SEND, cursp(), sym, argc));
mrb_gc_arena_restore(s->mrb, ai);
@@ -2605,7 +2598,7 @@ codegen(codegen_scope *s, node *tree, int val)
genop(s, MKOP_ABx(OP_LOADSYM, cursp(), b));
push();
genop(s, MKOP_A(OP_LOADNIL, cursp()));
- push();
+ push(); /* space for a block */
pop_n(4);
genop(s, MKOP_ABC(OP_SEND, cursp(), c, 2));
if (val) {
@@ -2644,6 +2637,7 @@ codegen(codegen_scope *s, node *tree, int val)
t = t->cdr;
num++;
}
+ push();pop(); /* space for a block */
pop();
if (num < CALL_MAXARGS) {
pop_n(num);
diff --git a/src/vm.c b/src/vm.c
index 715c3db6b..ba320d962 100644
--- a/src/vm.c
+++ b/src/vm.c
@@ -1333,10 +1333,12 @@ RETRY_TRY_BLOCK:
int bidx = (argc < 0) ? a+2 : a+n+1;
struct RProc *m;
struct RClass *c;
- mrb_callinfo *ci;
+ mrb_callinfo *ci = mrb->c->ci;
mrb_value recv, blk;
mrb_sym mid = syms[GETARG_B(i)];
+ mrb_assert(bidx < ci->nregs);
+
recv = regs[a];
if (GET_OPCODE(i) != OP_SENDB) {
SET_NIL_VALUE(regs[bidx]);
@@ -1523,6 +1525,8 @@ RETRY_TRY_BLOCK:
mrb_value recv, blk;
mrb_sym mid = ci->mid;
+ mrb_assert(bidx < ci->nregs);
+
if (mid == 0 || !ci->target_class) {
mrb_value exc = mrb_exc_new_str_lit(mrb, E_NOMETHOD_ERROR, "super called outside of method");
mrb_exc_set(mrb, exc);
diff --git a/test/t/codegen.rb b/test/t/codegen.rb
index 29f5ad525..4c9e2c594 100644
--- a/test/t/codegen.rb
+++ b/test/t/codegen.rb
@@ -73,3 +73,125 @@ assert('negate literal register alignment') do
assert_equal [2], a
end
+
+assert('register window of calls (#3783)') do
+ # NODE_FOR
+ assert_nothing_raised do
+ for i in []; end
+ end
+
+ # NODE_SYMBOLS
+ assert_nothing_raised do
+ %i(sym)
+ end
+
+ # NODE_SCALL
+ assert_nothing_raised do
+ Object.new&.__id__
+ end
+
+ # NODE_RESCUE with splat
+ assert_nothing_raised do
+ begin
+ raise
+ rescue *[Exception]
+ end
+ end
+
+ # NODE_CASE
+ assert_nothing_raised do
+ case 1
+ when nil
+ end
+ end
+
+ # NODE_CASE with splat
+ assert_nothing_raised do
+ case 1
+ when *nil
+ end
+ end
+
+ # NODE_HASH
+ assert_nothing_raised do
+ {}.merge(
+ 0=>0, 1=>1, 2=>2, 3=>3, 4=>4, 5=>5, 6=>6, 7=>7, 8=>8, 9=>9,
+ 10=>10, 11=>11, 12=>12, 13=>13, 14=>14, 15=>15, 16=>16, 17=>17, 18=>18, 19=>19,
+ 20=>20, 21=>21, 22=>22, 23=>23, 24=>24, 25=>25, 26=>26, 27=>27, 28=>28, 29=>29,
+ 30=>30, 31=>31, 32=>32, 33=>33, 34=>34, 35=>35, 36=>36, 37=>37, 38=>38, 39=>39,
+ 40=>40, 41=>41, 42=>42, 43=>43, 44=>44, 45=>45, 46=>46, 47=>47, 48=>48, 49=>49,
+ 50=>50, 51=>51, 52=>52, 53=>53, 54=>54, 55=>55, 56=>56, 57=>57, 58=>58, 59=>59,
+ 60=>60, 61=>61, 62=>62, 63=>63, 64=>64, 65=>65, 66=>66, 67=>67, 68=>68, 69=>69,
+ 70=>70, 71=>71, 72=>72, 73=>73, 74=>74, 75=>75, 76=>76, 77=>77, 78=>78, 79=>79,
+ 80=>80, 81=>81, 82=>82, 83=>83, 84=>84, 85=>85, 86=>86, 87=>87, 88=>88, 89=>89,
+ 90=>90, 91=>91, 92=>92, 93=>93, 94=>94, 95=>95, 96=>96, 97=>97, 98=>98, 99=>99,
+ 100=>100, 101=>101, 102=>102, 103=>103, 104=>104, 105=>105, 106=>106, 107=>107, 108=>108, 109=>109,
+ 110=>110, 111=>111, 112=>112, 113=>113, 114=>114, 115=>115, 116=>116, 117=>117, 118=>118, 119=>119,
+ 120=>120, 121=>121, 122=>122, 123=>123, 124=>124, 125=>125, 126=>126)
+ end
+
+ # NODE_OP_ASGN
+ o = Object.new
+ class << o
+ attr_accessor :a
+ end
+
+ o.a = 1
+ assert_nothing_raised{ o.a += 1 }
+ o.a = 1
+ assert_nothing_raised{ o.a <<= 1 }
+ o.a = 1
+ assert_nothing_raised{ o.a &&= 1 }
+
+ o = { k: 1 }
+ assert_nothing_raised{ o[:k] += 1 }
+ o = { k: 1 }
+ assert_nothing_raised{ o[:k] <<= 1 }
+ o = { k: 1 }
+ assert_nothing_raised{ o[:k] &&= 1 }
+
+ o = { k: 1 }
+ assert_nothing_raised{ o[*[:k]] += 1 }
+ o = { k: 1 }
+ assert_nothing_raised{ o[*[:k]] <<= 1 }
+ o = { k: 1 }
+ assert_nothing_raised{ o[*[:k]] &&= 1 }
+
+ # NODE_YIELD
+ def check_node_yield
+ yield
+ end
+ assert_nothing_raised do
+ check_node_yield{}
+ end
+
+ # NODE_DXSTR
+ assert_raise(NotImplementedError){ `#{:dynamic}` }
+
+ # NODE_XSTR
+ assert_raise(NotImplementedError){ `static` }
+
+ # NODE_DREGX
+ class Regexp; end
+ assert_raise(NoMethodError){ /#{'dynamic'}tail/ }
+ assert_raise(NoMethodError){ /#{'dynamic'}tail/iu }
+
+ # NODE_REGX
+ assert_raise(NoMethodError){ /static/ }
+ assert_raise(NoMethodError){ /static/iu }
+ Object.remove_const :Regexp
+
+ # NODE_UNDEF
+ assert_nothing_raised do
+ class << Object.new
+ undef send
+ end
+ end
+
+ # NODE_ALIAS
+ assert_nothing_raised do
+ class << Object.new
+ alias send2 send
+ end
+ end
+end \ No newline at end of file