diff options
| author | Yukihiro "Matz" Matsumoto <[email protected]> | 2017-08-24 14:38:03 +0900 |
|---|---|---|
| committer | GitHub <[email protected]> | 2017-08-24 14:38:03 +0900 |
| commit | 63f10a1ee59743c086afc339f25da4f6e100e765 (patch) | |
| tree | 7694adf91bfc6ca0ebc26be50b3935d6c3deb3fc | |
| parent | 4c9a60487799b923ff905def46cb2497bcc1e4dd (diff) | |
| parent | 3366894a4084c9f44a38410daf6abad9e2da5b33 (diff) | |
| download | mruby-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.c | 88 | ||||
| -rw-r--r-- | src/vm.c | 6 | ||||
| -rw-r--r-- | test/t/codegen.rb | 122 |
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); @@ -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 |
