diff options
| author | Yukihiro "Matz" Matsumoto <[email protected]> | 2016-03-30 20:43:57 +0900 |
|---|---|---|
| committer | Yukihiro "Matz" Matsumoto <[email protected]> | 2016-03-30 20:43:57 +0900 |
| commit | d098d823de6db6e312c5acc73325eb2b0491fd95 (patch) | |
| tree | 10fb8ebcda24f4fae775d2394cf3e2cf31ed1625 | |
| parent | 4979b52d613f867b8fa7fdcc969c939a085e315f (diff) | |
| download | mruby-d098d823de6db6e312c5acc73325eb2b0491fd95.tar.gz mruby-d098d823de6db6e312c5acc73325eb2b0491fd95.zip | |
fix duplicated eval in op_asgn
`a` in `a.m += c` or `a[b] += c` should be evaluated only once.
| -rw-r--r-- | mrbgems/mruby-compiler/core/codegen.c | 49 |
1 files changed, 47 insertions, 2 deletions
diff --git a/mrbgems/mruby-compiler/core/codegen.c b/mrbgems/mruby-compiler/core/codegen.c index e417bddd4..de21f05b5 100644 --- a/mrbgems/mruby-compiler/core/codegen.c +++ b/mrbgems/mruby-compiler/core/codegen.c @@ -1716,7 +1716,7 @@ codegen(codegen_scope *s, node *tree, int val) mrb_sym sym = sym(tree->cdr->car); mrb_int len; const char *name = mrb_sym2name_len(s->mrb, sym, &len); - int idx; + int idx, callargs = -1, vsp = -1; if ((len == 2 && name[0] == '|' && name[1] == '|') && ((intptr_t)tree->car->car == NODE_CONST || @@ -1737,6 +1737,34 @@ codegen(codegen_scope *s, node *tree, int val) genop(s, MKOP_A(OP_LOADF, exc)); dispatch(s, noexc); } + else if ((intptr_t)tree->car->car == NODE_CALL) { + node *n = tree->car->cdr; + + if (val) { + vsp = cursp(); + push(); + } + codegen(s, n->car, VAL); /* receiver */ + idx = new_msym(s, sym(n->cdr->car)); + if (n->cdr->cdr->car) { + int i = gen_values(s, n->cdr->cdr->car->car, VAL); + if (i >= 0) { + pop_n(i); + genop(s, MKOP_ABC(OP_ARRAY, cursp(), cursp(), i)); + } + genop(s, MKOP_AB(OP_MOVE, cursp()+1, cursp()-1)); + genop(s, MKOP_AB(OP_MOVE, cursp()+2, cursp())); + push(); + genop(s, MKOP_ABC(OP_SEND, cursp(), idx, CALL_MAXARGS)); + callargs = CALL_MAXARGS; + } + else { + genop(s, MKOP_AB(OP_MOVE, cursp(), cursp()-1)); + genop(s, MKOP_ABC(OP_SEND, cursp(), idx, 0)); + callargs = 1; + } + push(); + } else { codegen(s, tree->car, VAL); } @@ -1785,8 +1813,25 @@ codegen(codegen_scope *s, node *tree, int val) else { genop(s, MKOP_ABC(OP_SEND, cursp(), idx, 1)); } + if (callargs < 0) { + gen_assignment(s, tree->car, cursp(), val); + } + else { + if (callargs == CALL_MAXARGS) { + genop(s, MKOP_AB(OP_ARYPUSH, cursp()-1, cursp())); + if (val) { + genop(s, MKOP_AB(OP_MOVE, vsp, cursp())); + } + pop(); + } + else if (val) { + genop(s, MKOP_AB(OP_MOVE, vsp, cursp())); + } + pop(); + idx = new_msym(s, attrsym(s,sym(tree->car->cdr->cdr->car))); + genop(s, MKOP_ABC(OP_SEND, cursp(), idx, callargs)); + } } - gen_assignment(s, tree->car, cursp(), val); break; case NODE_SUPER: |
