ruby-changes:38030
From: nobu <ko1@a...>
Date: Sun, 29 Mar 2015 11:51:40 +0900 (JST)
Subject: [ruby-changes:38030] nobu:r50111 (trunk): proc.c: replicate method env
nobu 2015-03-29 11:51:34 +0900 (Sun, 29 Mar 2015) New Revision: 50111 http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=50111 Log: proc.c: replicate method env * proc.c (proc_binding): replicate env from method object, and allocate the local variable area for the iseq local table. [ruby-core:68673] [Bug #11012] Modified files: trunk/ChangeLog trunk/proc.c trunk/test/ruby/test_method.rb Index: ChangeLog =================================================================== --- ChangeLog (revision 50110) +++ ChangeLog (revision 50111) @@ -1,3 +1,9 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1 +Sun Mar 29 11:51:32 2015 Nobuyoshi Nakada <nobu@r...> + + * proc.c (proc_binding): replicate env from method object, and + allocate the local variable area for the iseq local table. + [ruby-core:68673] [Bug #11012] + Sat Mar 28 09:19:41 2015 NARUSE, Yui <naruse@r...> * ext/date/extconf.rb: try_cflags("-std=iso9899:1999") [Bug #10906] Index: proc.c =================================================================== --- proc.c (revision 50110) +++ proc.c (revision 50111) @@ -2493,22 +2493,40 @@ static VALUE https://github.com/ruby/ruby/blob/trunk/proc.c#L2493 proc_binding(VALUE self) { rb_proc_t *proc; - VALUE bindval; + VALUE bindval, envval; rb_binding_t *bind; rb_iseq_t *iseq; GetProcPtr(self, proc); + envval = proc->envval; iseq = proc->block.iseq; if (RUBY_VM_IFUNC_P(iseq)) { + rb_env_t *env; if (!IS_METHOD_PROC_ISEQ(iseq)) { rb_raise(rb_eArgError, "Can't create Binding from C level Proc"); } iseq = rb_method_get_iseq((VALUE)((struct vm_ifunc *)iseq)->data); + GetEnvPtr(envval, env); + if (env->local_size < iseq->local_size) { + int prev_local_size = env->local_size; + int local_size = iseq->local_size; + VALUE newenvval = TypedData_Wrap_Struct(RBASIC_CLASS(envval), RTYPEDDATA_TYPE(envval), 0); + rb_env_t *newenv = xmalloc(sizeof(rb_env_t) + ((local_size + 1) * sizeof(VALUE))); + RTYPEDDATA_DATA(newenvval) = newenv; + newenv->env_size = local_size + 2; + newenv->local_size = local_size; + newenv->prev_envval = env->prev_envval; + newenv->block = env->block; + MEMCPY(newenv->env, env->env, VALUE, prev_local_size + 1); + rb_mem_clear(newenv->env + prev_local_size + 1, local_size - prev_local_size); + newenv->env[local_size + 1] = newenvval; + envval = newenvval; + } } bindval = rb_binding_alloc(rb_cBinding); GetBindingPtr(bindval, bind); - bind->env = proc->envval; + bind->env = envval; bind->blockprocval = proc->blockprocval; if (RUBY_VM_NORMAL_ISEQ_P(iseq)) { bind->path = iseq->location.path; Index: test/ruby/test_method.rb =================================================================== --- test/ruby/test_method.rb (revision 50110) +++ test/ruby/test_method.rb (revision 50111) @@ -886,4 +886,18 @@ class TestMethod < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_method.rb#L886 obj.bar end end + + def test_to_proc_binding + bug11012 = '[ruby-core:68673] [Bug #11012]' + class << (obj = Object.new) + src = 1000.times.map {|i|"v#{i} = nil"}.join("\n") + eval("def foo()\n""#{src}\n""end") + end + + b = obj.method(:foo).to_proc.binding + b.local_variables.each_with_index {|n, i| + b.local_variable_set(n, i) + } + assert_equal([998, 999], %w[v998 v999].map {|n| b.local_variable_get(n)}, bug11012) + end end -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/