diff options
author | nobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2016-03-14 07:53:39 +0000 |
---|---|---|
committer | nobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2016-03-14 07:53:39 +0000 |
commit | ea5e885a958967c999e15512c6e72defab232de4 (patch) | |
tree | 35b1713bacf79e68f79ec0f5a361e8ac1acae2ba /compile.c | |
parent | a4e6f7d707293a71727ad18e75aae9639ba423f3 (diff) | |
download | ruby-ea5e885a958967c999e15512c6e72defab232de4.tar.gz |
optimize named capture assignment
* compile.c (compile_named_capture_assign): optimize named capture
assignments, by replacing repeating global variable accesses
with `dup`, and by returning the matched result instead of
re-getting it from the MatchData.
* parse.y (reg_named_capture_assign_gen): build just assignment
nodes for the optimization.
ex. `/(?<x>.)/ =~ "bar"`
- old
```
0000 putstring "bar"
0002 opt_regexpmatch1 /(?<x>.)/
0004 pop
0005 getglobal $~
0007 branchunless 25
0009 getglobal $~
0011 putobject :x
0013 opt_aref <callinfo!mid:[], argc:1, ARGS_SIMPLE>
0016 setlocal_OP__WC__0 2
0018 getglobal $~
0020 putobject_OP_INT2FIX_O_0_C_
0021 opt_send_without_block <callinfo!mid:begin, argc:1, ARGS_SIMPLE>
0024 leave
0025 putobject nil
0027 setlocal_OP__WC__0 2
0029 putobject nil
0031 leave
```
- new
```
0000 putstring "bar"
0002 opt_regexpmatch1 /(?<x>.)/
0004 getglobal $~
0006 dup
0007 branchunless 14
0009 putobject :x
0011 opt_aref <callinfo!mid:[], argc:1, ARGS_SIMPLE>
0014 setlocal_OP__WC__0 2
0016 leave
```
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@54100 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'compile.c')
-rw-r--r-- | compile.c | 63 |
1 files changed, 63 insertions, 0 deletions
@@ -3648,6 +3648,65 @@ build_postexe_iseq(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE *body) return Qnil; } +static void +compile_named_capture_assign(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE *node) +{ + NODE *vars; + LINK_ELEMENT *last; + int line = nd_line(node); + LABEL *fail_label = NEW_LABEL(line), *end_label = NEW_LABEL(line); + +#if !(defined(NAMED_CAPTURE_BY_SVAR) && NAMED_CAPTURE_BY_SVAR-0) + ADD_INSN1(ret, line, getglobal, ((VALUE)rb_global_entry(idBACKREF) | 1)); +#else + ADD_INSN2(ret, line, getspecial, INT2FIX(1) /* '~' */, INT2FIX(0)); +#endif + ADD_INSN(ret, line, dup); + ADD_INSNL(ret, line, branchunless, fail_label); + + for (vars = node; vars; vars = vars->nd_next) { + INSN *cap; + if (vars->nd_next) { + ADD_INSN(ret, line, dup); + } + last = ret->last; + COMPILE_POPED(ret, "capture", vars->nd_head); + last = last->next; /* putobject :var */ + cap = new_insn_send(iseq, line, idAREF, INT2FIX(1), + NULL, INT2FIX(0), NULL); + INSERT_ELEM_PREV(last->next, (LINK_ELEMENT *)cap); +#if !defined(NAMED_CAPTURE_SINGLE_OPT) || NAMED_CAPTURE_SINGLE_OPT-0 + if (!vars->nd_next && vars == node) { + /* only one name */ + DECL_ANCHOR(nom); + + INIT_ANCHOR(nom); + ADD_INSNL(nom, line, jump, end_label); + ADD_LABEL(nom, fail_label); +# if 0 /* $~ must be MatchData or nil */ + ADD_INSN(nom, line, pop); + ADD_INSN(nom, line, putnil); +# endif + ADD_LABEL(nom, end_label); + (nom->last->next = cap->link.next)->prev = nom->last; + (cap->link.next = nom->anchor.next)->prev = &cap->link; + return; + } +#endif + } + ADD_INSNL(ret, line, jump, end_label); + ADD_LABEL(ret, fail_label); + ADD_INSN(ret, line, pop); + for (vars = node; vars; vars = vars->nd_next) { + last = ret->last; + COMPILE_POPED(ret, "capture", vars->nd_head); + last = last->next; /* putobject :var */ + ((INSN*)last)->insn_id = BIN(putnil); + ((INSN*)last)->operand_size = 0; + } + ADD_LABEL(ret, end_label); +} + /** compile each node @@ -5351,6 +5410,10 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node, int poped) ADD_SEND(ret, line, idEqTilde, INT2FIX(1)); } + if (node->nd_args) { + compile_named_capture_assign(iseq, ret, node->nd_args); + } + if (poped) { ADD_INSN(ret, line, pop); } |