* [PATCH 4/4] opt_str_lit_yoda: account for method redefinition in arg
@ 2014-11-05 23:18 Eric Wong
0 siblings, 0 replies; only message in thread
From: Eric Wong @ 2014-11-05 23:18 UTC (permalink / raw)
To: spew
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset=y, Size: 5902 bytes --]
Strange arguments may redefine methods at run-time. This commit
may not be necessary, as (hopefully) nobody writes such strange code.
[ruby-core:66097]
---
compile.c | 63 ++++++++++++++++++++++++++++++++++++------
insns.def | 27 ++++++++++++++++++
test/ruby/test_optimization.rb | 28 +++++++++++++++++++
3 files changed, 110 insertions(+), 8 deletions(-)
diff --git a/compile.c b/compile.c
index 7498bca..cd1d43f 100644
--- a/compile.c
+++ b/compile.c
@@ -1812,6 +1812,18 @@ new_recvinfo_for_recv_(rb_iseq_t *iseq, VALUE str,
return ri;
}
+static VALUE
+new_recvinfo_for_yoda(rb_iseq_t *iseq, VALUE str,
+ enum ruby_optimized_method om, int recv_off)
+{
+ VALUE ri = rb_ary_new_from_args(3, str, INT2FIX(om), INT2FIX(recv_off));
+
+ hide_obj(ri);
+ iseq_add_mark_object(iseq, ri);
+
+ return ri;
+}
+
#define new_recvinfo_for_arg(iseq,str,mid,klass,off) \
new_recvinfo_for_arg_((iseq),(str),(OM_##mid##__##klass),\
(OM_TMASK_##klass),(off))
@@ -4596,6 +4608,7 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node, int poped)
unsigned int flag = 0;
rb_call_info_kw_arg_t *keywords = NULL;
VALUE parent_block = iseq->compile_data->current_block;
+ INSN *yoda_insn = 0;
iseq->compile_data->current_block = Qfalse;
INIT_ANCHOR(recv);
@@ -4669,13 +4682,23 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node, int poped)
enum ruby_optimized_method om;
/*
* optimize:
- * "string literal".method(...)
- * "yoda" == other -> opt_str_lit("yoda").send(:==, other)
- * "yoda" != other -> opt_str_lit("yoda").send(:!=, other)
- * "str" + other -> opt_str_lit("str").send(:+, other)
- * "str" * other -> opt_str_lit("str").send(:*, other)
- * "fmt" % args -> opt_str_lit("str").send(:%, other)
+ * "string literal".method(arg)
+ * "yoda" == other
+ * "yoda" != other
+ * "str" + other
+ * "str" * other
+ * "fmt" % args
* ...
+ * result A:
+ * putobject str
+ * <setup_args>
+ * opt_str_lit_yoda([str, om, off])
+ * send mid ...
+ *
+ * result B:
+ * opt_str_lit_recv([str, om]) => str
+ * <setup_args (putobject|putstring|putspecial)>
+ * send mid ...
*/
if (iseq->compile_data->option->peephole_optimization &&
((om = opt_str_lit_recv_om(mid)) != OM_LAST_) &&
@@ -4685,10 +4708,12 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node, int poped)
node->nd_args->nd_alen == 1)
{
VALUE yoda = rb_fstring(node->nd_recv->nd_lit);
- VALUE recv_info = new_recvinfo_for_recv_(iseq, yoda, om);
+ int off = node->nd_args->nd_alen;
+ VALUE yoda_info = new_recvinfo_for_yoda(iseq, yoda, om, off);
node->nd_recv->nd_lit = yoda;
- ADD_INSN1(recv, line, opt_str_lit_recv, recv_info);
+ ADD_INSN1(recv, line, putobject, yoda_info /* temporary */);
+ yoda_insn = (INSN *)recv->last;
} else {
COMPILE(recv, "recv", node->nd_recv);
}
@@ -4719,6 +4744,28 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node, int poped)
flag |= VM_CALL_FCALL;
}
+ if (yoda_insn) {
+ INSN *last = (INSN *)ret->last;
+ VALUE yoda_info = yoda_insn->operands[0];
+
+ assert(yoda_insn->insn_id == BIN(putobject));
+ switch (last->insn_id) {
+ case BIN(putstring):
+ case BIN(putobject):
+ case BIN(getlocal):
+ /*
+ * [putobject, yoda_info] => [opt_str_lit_recv, recv_info]
+ * n.b.: opt_str_lit_recv ignores 3rd element of recv_info
+ */
+ yoda_insn->insn_id = BIN(opt_str_lit_recv);
+ break;
+ default:
+ /* [putobject, yoda_info] => [putobject, "str lit"] */
+ yoda_insn->operands[0] = RARRAY_AREF(yoda_info, 0); /* str */
+
+ ADD_INSN1(ret, line, opt_str_lit_yoda, yoda_info);
+ }
+ }
ADD_SEND_R(ret, line, mid, argc, parent_block, INT2FIX(flag), keywords);
if (poped) {
diff --git a/insns.def b/insns.def
index ba86863..9728405 100644
--- a/insns.def
+++ b/insns.def
@@ -462,6 +462,33 @@ opt_str_lit_recv
}
/**
+ @c optimize
+ @e put string val. string may be dup-ed depending on recv_info conditions
+ */
+DEFINE_INSN
+opt_str_lit_yoda
+(VALUE recv_info)
+()
+()
+{
+ /*
+ * recv_info:
+ * 0 - str (only for assert)
+ * 1 - tmask (optimized receiver classes)
+ * 2 - stack offset (Fixint)
+ */
+ const VALUE *ri = RARRAY_CONST_PTR(recv_info);
+ enum ruby_optimized_method om = FIX2UINT(ri[1]);
+ int off = FIX2INT(ri[2]);
+ VALUE recv = TOPN(off);
+
+ assert(ri[0] == recv);
+ if (!rb_basic_op_unredefined_p(om)) {
+ TOPN(off) = rb_str_resurrect(recv);
+ }
+}
+
+/**
@c put
@e put concatenate strings
@j スタックトップの文字列を n 個連結し,結果をスタックにプッシュする。
diff --git a/test/ruby/test_optimization.rb b/test/ruby/test_optimization.rb
index 63ed22b..709b5cc 100644
--- a/test/ruby/test_optimization.rb
+++ b/test/ruby/test_optimization.rb
@@ -148,6 +148,34 @@ class TestRubyOptimization < Test::Unit::TestCase
end
end
+ def test_opt_str_lit_lazy
+ require_compile_option(:peephole_optimization)
+ assert_separately([], <<-"end;")# do
+ def bar
+ String.class_eval %q{
+ def ==(other)
+ self.upcase! # modify operation
+ true
+ end
+ }
+ 'bar'
+ end
+ assert('foo' == bar, "[ruby-core:66097]")
+
+ def break_gsub
+ String.class_eval %q{
+ def gsub(a, b)
+ self.dup.gsub!(a.upcase!, b.upcase)
+ true
+ end
+ }
+ 'a'
+ end
+ str = 'A'
+ assert_equal('a', str.gsub(break_gsub, 'a'))
+ end;
+ end
+
def test_string_ltlt
assert_equal "", "" << ""
assert_equal "x", "x" << ""
--
EW
^ permalink raw reply related [flat|nested] only message in thread
only message in thread, other threads:[~2014-11-05 23:18 UTC | newest]
Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-11-05 23:18 [PATCH 4/4] opt_str_lit_yoda: account for method redefinition in arg Eric Wong
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).