aboutsummaryrefslogtreecommitdiffstats
path: root/compile.c
diff options
context:
space:
mode:
authornormal <normal@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2017-04-01 21:38:25 +0000
committernormal <normal@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2017-04-01 21:38:25 +0000
commit120976b9f973f667c6eeb246b2d311949ecdf1f3 (patch)
treee5d29dce6988259d8c4b9a04f11f5f574278fd3a /compile.c
parent48bc5004c00de3ed2b0ca353ec7508cef10eaca6 (diff)
downloadruby-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.c31
1 files changed, 31 insertions, 0 deletions
diff --git a/compile.c b/compile.c
index 317475b525..81cbb9ff5a 100644
--- a/compile.c
+++ b/compile.c
@@ -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);
}