diff options
author | normal <normal@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2017-04-01 21:38:25 +0000 |
---|---|---|
committer | normal <normal@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2017-04-01 21:38:25 +0000 |
commit | 120976b9f973f667c6eeb246b2d311949ecdf1f3 (patch) | |
tree | e5d29dce6988259d8c4b9a04f11f5f574278fd3a /compile.c | |
parent | 48bc5004c00de3ed2b0ca353ec7508cef10eaca6 (diff) | |
download | ruby-120976b9f973f667c6eeb246b2d311949ecdf1f3.tar.gz |
compile.c: optimize literal String range in case/when dispatch
This is similar in spirit to opt_case_dispatch as the literal
Range here is guaranteed to be immutable when used for
checkmatch.
Normal range literals with non-frozen strings are actually
mutable, as Range#begin and Range#end exposes the strings to
modification. So those Range objects cannot be frozen without
breaking compatibility, but Ranges in case/when dispatch can be
frozen at compile time.
* compile.c (iseq_peephole_optimize): persistent Range creation
when String literals are used as beginning and end of range
when used for case/when dispatch.
[ruby-core:80290] [Feature #13355]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@58233 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'compile.c')
-rw-r--r-- | compile.c | 31 |
1 files changed, 31 insertions, 0 deletions
@@ -2144,6 +2144,37 @@ iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcal } } + /* + * putstring "beg" + * putstring "end" + * newrange excl + * + * ==> + * + * putobject "beg".."end" + */ + if (IS_INSN_ID(iobj, checkmatch)) { + INSN *range = (INSN *)get_prev_insn(iobj); + INSN *beg, *end; + + if (range && IS_INSN_ID(range, newrange) && + (end = (INSN *)get_prev_insn(range)) != 0 && + IS_INSN_ID(end, putstring) && + (beg = (INSN *)get_prev_insn(end)) != 0 && + IS_INSN_ID(beg, putstring)) { + VALUE str_beg = OPERAND_AT(beg, 0); + VALUE str_end = OPERAND_AT(end, 0); + int excl = FIX2INT(OPERAND_AT(range, 0)); + VALUE lit_range = rb_range_new(str_beg, str_end, excl); + + iseq_add_mark_object(iseq, lit_range); + REMOVE_ELEM(&beg->link); + REMOVE_ELEM(&end->link); + range->insn_id = BIN(putobject); + OPERAND_AT(range, 0) = lit_range; + } + } + if (IS_INSN_ID(iobj, leave)) { remove_unreachable_chunk(iseq, iobj->link.next); } |