зеркало из https://github.com/github/ruby.git
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] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@50111 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
Родитель
4bc9b1d29a
Коммит
509089e9b1
|
@ -1,3 +1,9 @@
|
|||
Sun Mar 29 11:51:32 2015 Nobuyoshi Nakada <nobu@ruby-lang.org>
|
||||
|
||||
* 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@ruby-lang.org>
|
||||
|
||||
* ext/date/extconf.rb: try_cflags("-std=iso9899:1999") [Bug #10906]
|
||||
|
|
22
proc.c
22
proc.c
|
@ -2493,22 +2493,40 @@ static VALUE
|
|||
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;
|
||||
|
|
|
@ -886,4 +886,18 @@ class TestMethod < Test::Unit::TestCase
|
|||
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
|
||||
|
|
Загрузка…
Ссылка в новой задаче