From 5ee9513a7104078d9d2f51aecc354ae67f1ba002 Mon Sep 17 00:00:00 2001 From: ko1 Date: Tue, 24 Oct 2017 11:13:49 +0000 Subject: Lazy Proc allocation for block parameters [Feature #14045] * insns.def (getblockparam, setblockparam): add special access instructions for block parameters. getblockparam checks VM_FRAME_FLAG_MODIFIED_BLOCK_PARAM and if it is not set this instruction creates a Proc object from a given blcok and set VM_FRAME_FLAG_MODIFIED_BLOCK_PARAM. setblockparam is similar to setlocal, but set VM_FRAME_FLAG_MODIFIED_BLOCK_PARAM. * compile.c: use get/setblockparm instead get/setlocal instructions. Note that they are used for method local block parameters (def m(&b)), not for block local method parameters (iter{|&b|). * proc.c (get_local_variable_ptr): creates Proc object for Binding#local_variable_get/set. * safe.c (safe_setter): we need to create Proc objects for postponed block parameters when $SAFE is changed. * vm_args.c (args_setup_block_parameter): used only for block local blcok parameters. * vm_args.c (vm_caller_setup_arg_block): if called with VM_CALL_ARGS_BLOCKARG_BLOCKPARAM flag then passed block values should be a block handler. * test/ruby/test_optimization.rb: add tests. * benchmark/bm_vm1_blockparam*: added. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@60397 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- test/ruby/test_optimization.rb | 65 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) (limited to 'test/ruby') diff --git a/test/ruby/test_optimization.rb b/test/ruby/test_optimization.rb index 2d0eec02fd..ed16ad9fe2 100644 --- a/test/ruby/test_optimization.rb +++ b/test/ruby/test_optimization.rb @@ -575,4 +575,69 @@ class TestRubyOptimization < Test::Unit::TestCase def t; if false; case 42; when s {}; end; end; end end; end + + def bptest_yield &b + yield + end + + def bptest_yield_pass &b + bptest_yield(&b) + end + + def bptest_bp_value &b + b + end + + def bptest_bp_pass_bp_value &b + bptest_bp_value(&b) + end + + def bptest_binding &b + binding + end + + def bptest_set &b + b = Proc.new{2} + end + + def test_block_parameter + assert_equal(1, bptest_yield{1}) + assert_equal(1, bptest_yield_pass{1}) + assert_equal(1, send(:bptest_yield){1}) + + assert_equal(Proc, bptest_bp_value{}.class) + assert_equal nil, bptest_bp_value + assert_equal(Proc, bptest_bp_pass_bp_value{}.class) + assert_equal nil, bptest_bp_pass_bp_value + + assert_equal Proc, bptest_binding{}.local_variable_get(:b).class + + assert_equal 2, bptest_set{1}.call + end + + def test_block_parameter_should_not_create_objects + assert_separately [], <<-END + # + def foo &b + end + h1 = {}; h2 = {} + ObjectSpace.count_objects(h1) # reharsal + ObjectSpace.count_objects(h1) + foo{} + ObjectSpace.count_objects(h2) + + assert_equal 0, h2[:TOTAL] - h1[:TOTAL] + END + end + + def test_block_parameter_should_restore_safe_level + assert_separately [], <<-END + # + def foo &b + $SAFE = 1 + b.call + end + assert_equal 0, foo{$SAFE} + END + end end -- cgit v1.2.3