From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on dcvr.yhbt.net X-Spam-Level: X-Spam-ASN: X-Spam-Status: No, score=-3.0 required=3.0 tests=ALL_TRUSTED,AWL,BAYES_00 shortcircuit=no autolearn=unavailable version=3.3.2 X-Original-To: spew@80x24.org Received: from localhost (dcvr.yhbt.net [127.0.0.1]) by dcvr.yhbt.net (Postfix) with ESMTP id 80BA31FB84 for ; Sat, 15 Nov 2014 22:16:12 +0000 (UTC) From: Eric Wong To: spew@80x24.org Subject: [PATCH 1/2] compile.c: hide "literal" optimizations behind peephole optimize Date: Sat, 15 Nov 2014 22:16:11 +0000 Message-Id: X-Mailer: git-send-email 2.2.0.rc2.1.g1758c97.dirty List-Id: This allows us to disable/enable optimizations at runtime. --- compile.c | 47 ++++++++++++++++++++++++++---------------- test/-ext-/symbol/test_type.rb | 1 + test/lib/envutil.rb | 10 +++++++++ test/objspace/test_objspace.rb | 1 + test/ruby/test_hash.rb | 2 ++ test/ruby/test_iseq.rb | 1 + test/ruby/test_optimization.rb | 11 +++++++++- 7 files changed, 54 insertions(+), 19 deletions(-) diff --git a/compile.c b/compile.c index 4e4101f..9936647 100644 --- a/compile.c +++ b/compile.c @@ -1913,6 +1913,33 @@ iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcal } } } + + /* string literal optimizations */ + if (iobj->insn_id == BIN(putstring)) { + INSN *niobj = (INSN *)get_next_insn((INSN *)list); + + if (niobj && niobj->insn_id == BIN(send)) { + rb_call_info_t *ci = (rb_call_info_t *)niobj->operands[0]; + + if (!ci->blockiseq && !(ci->flag & ~VM_CALL_ARGS_SIMPLE)) { + /* obj["literal"] -> opt_aref_with(obj, "literal") */ + if (ci->mid == idAREF && ci->orig_argc == 1) { + VALUE *old_operands = iobj->operands; + + iobj->insn_id = BIN(opt_aref_with); + iobj->operand_size = insn_len(iobj->insn_id) - 1; + + iobj->operands = (VALUE *)compile_data_alloc(iseq, + iobj->operand_size * sizeof(VALUE)); + iobj->operands[0] = (VALUE)ci; + iobj->operands[1] = old_operands[0]; + + REMOVE_ELEM((LINK_ELEMENT *)niobj); + } + } + } + } + return COMPILE_OK; } @@ -4376,7 +4403,8 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node, int poped) /* optimization shortcut * "literal".freeze -> opt_str_freeze("literal") */ - if (node->nd_recv && nd_type(node->nd_recv) == NODE_STR && + if (iseq->compile_data->option->peephole_optimization && + node->nd_recv && nd_type(node->nd_recv) == NODE_STR && node->nd_mid == idFreeze && node->nd_args == NULL) { VALUE str = rb_fstring(node->nd_recv->nd_lit); @@ -4387,23 +4415,6 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node, int poped) } break; } - /* optimization shortcut - * obj["literal"] -> opt_aref_with(obj, "literal") - */ - if (node->nd_mid == idAREF && !private_recv_p(node) && node->nd_args && - nd_type(node->nd_args) == NODE_ARRAY && node->nd_args->nd_alen == 1 && - nd_type(node->nd_args->nd_head) == NODE_STR) - { - VALUE str = rb_fstring(node->nd_args->nd_head->nd_lit); - node->nd_args->nd_head->nd_lit = str; - COMPILE(ret, "recv", node->nd_recv); - ADD_INSN2(ret, line, opt_aref_with, - new_callinfo(iseq, idAREF, 1, 0, 0, NULL), str); - if (poped) { - ADD_INSN(ret, line, pop); - } - break; - } case NODE_FCALL: case NODE_VCALL:{ /* VCALL: variable or call */ /* diff --git a/test/-ext-/symbol/test_type.rb b/test/-ext-/symbol/test_type.rb index f1749f5..5bd79b8 100644 --- a/test/-ext-/symbol/test_type.rb +++ b/test/-ext-/symbol/test_type.rb @@ -4,6 +4,7 @@ require "-test-/symbol" module Test_Symbol class TestType < Test::Unit::TestCase def test_id2str_fstring_bug9171 + require_compile_option(:peephole_optimization) fstr = eval("# encoding: us-ascii 'foobar'.freeze") assert_same fstr, Bug::Symbol.id2str(:foobar) diff --git a/test/lib/envutil.rb b/test/lib/envutil.rb index 001753a..852cfe1 100644 --- a/test/lib/envutil.rb +++ b/test/lib/envutil.rb @@ -551,6 +551,16 @@ eom values end + def require_compile_option(opt) + case RubyVM::InstructionSequence.compile_option[opt] + when true + when false + skip(":#{opt} disabled") + else + raise ArgumentError, "unrecognized compile option: #{opt.inspect}" + end + end + class << (AssertFile = Struct.new(:failure_message).new) include Assertions def assert_file_predicate(predicate, *args) diff --git a/test/objspace/test_objspace.rb b/test/objspace/test_objspace.rb index f507562..cfdb908 100644 --- a/test/objspace/test_objspace.rb +++ b/test/objspace/test_objspace.rb @@ -194,6 +194,7 @@ class TestObjSpace < Test::Unit::TestCase end def test_dump_flags + require_compile_option(:peephole_optimization) info = ObjectSpace.dump("foo".freeze) assert_match /"wb_protected":true, "old":true, "long_lived":true, "marked":true/, info assert_match /"fstring":true/, info diff --git a/test/ruby/test_hash.rb b/test/ruby/test_hash.rb index da07df9..370e8be 100644 --- a/test/ruby/test_hash.rb +++ b/test/ruby/test_hash.rb @@ -215,6 +215,7 @@ class TestHash < Test::Unit::TestCase end def test_AREF_fstring_key + require_compile_option(:peephole_optimization) h = {"abc" => 1} before = GC.stat(:total_allocated_objects) 5.times{ h["abc"] } @@ -229,6 +230,7 @@ class TestHash < Test::Unit::TestCase end def test_NEWHASH_fstring_key + require_compile_option(:peephole_optimization) a = {"ABC" => :t} b = {"ABC" => :t} assert_same a.keys[0], b.keys[0] diff --git a/test/ruby/test_iseq.rb b/test/ruby/test_iseq.rb index 79c41bb..e3a28fa 100644 --- a/test/ruby/test_iseq.rb +++ b/test/ruby/test_iseq.rb @@ -117,6 +117,7 @@ class TestISeq < Test::Unit::TestCase end def test_label_fstring + require_compile_option(:peephole_optimization) c = Class.new{ def foobar() end } a, b = eval("# encoding: us-ascii\n'foobar'.freeze"), diff --git a/test/ruby/test_optimization.rb b/test/ruby/test_optimization.rb index 129f62a..79cfa1c 100644 --- a/test/ruby/test_optimization.rb +++ b/test/ruby/test_optimization.rb @@ -28,6 +28,13 @@ class TestRubyOptimization < Test::Unit::TestCase end; end + def assert_no_allocation(mesg = "", adjust = 0) + before = GC.stat(:total_allocated_objects) + yield + after = GC.stat(:total_allocated_objects) + assert_equal before, after - adjust, mesg + end + def test_fixnum_plus a, b = 1, 2 assert_equal 3, a + b @@ -117,8 +124,10 @@ class TestRubyOptimization < Test::Unit::TestCase end def test_string_freeze - assert_equal "foo", "foo".freeze assert_redefine_method('String', 'freeze', 'assert_nil "foo".freeze') + require_compile_option(:peephole_optimization) + assert_no_allocation { 5.times { "".freeze } } + assert_equal "foo", "foo".freeze end def test_string_eq_neq -- EW