* proc.c: fix issues caused by binding created from Method#to_proc.
[Bug #11163] * vm.c (vm_cref_new_toplevel): export as rb_vm_cref_new_toplevel(). * test/ruby/test_method.rb: add some assersions. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@50592 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
e398e64ad7
commit
928d89c77b
@ -1,3 +1,12 @@
|
|||||||
|
Thu May 21 17:44:53 2015 Koichi Sasada <ko1@atdot.net>
|
||||||
|
|
||||||
|
* proc.c: fix issues caused by binding created from Method#to_proc.
|
||||||
|
[Bug #11163]
|
||||||
|
|
||||||
|
* vm.c (vm_cref_new_toplevel): export as rb_vm_cref_new_toplevel().
|
||||||
|
|
||||||
|
* test/ruby/test_method.rb: add some assersions.
|
||||||
|
|
||||||
Thu May 21 17:29:26 2015 SHIBATA Hiroshi <hsbt@ruby-lang.org>
|
Thu May 21 17:29:26 2015 SHIBATA Hiroshi <hsbt@ruby-lang.org>
|
||||||
|
|
||||||
* lib/matrix.rb: added documentation for Matrix#empty and Matrix#/
|
* lib/matrix.rb: added documentation for Matrix#empty and Matrix#/
|
||||||
|
81
proc.c
81
proc.c
@ -33,6 +33,7 @@ VALUE rb_cProc;
|
|||||||
static VALUE bmcall(VALUE, VALUE, int, VALUE *, VALUE);
|
static VALUE bmcall(VALUE, VALUE, int, VALUE *, VALUE);
|
||||||
static int method_arity(VALUE);
|
static int method_arity(VALUE);
|
||||||
static int method_min_max_arity(VALUE, int *max);
|
static int method_min_max_arity(VALUE, int *max);
|
||||||
|
|
||||||
#define attached id__attached__
|
#define attached id__attached__
|
||||||
|
|
||||||
/* Proc */
|
/* Proc */
|
||||||
@ -369,14 +370,19 @@ get_local_variable_ptr(VALUE envval, ID lid)
|
|||||||
GetEnvPtr(envval, env);
|
GetEnvPtr(envval, env);
|
||||||
iseq = env->block.iseq;
|
iseq = env->block.iseq;
|
||||||
|
|
||||||
|
if (RUBY_VM_NORMAL_ISEQ_P(iseq)) {
|
||||||
for (i=0; i<iseq->local_table_size; i++) {
|
for (i=0; i<iseq->local_table_size; i++) {
|
||||||
if (iseq->local_table[i] == lid) {
|
if (iseq->local_table[i] == lid) {
|
||||||
return &env->env[i];
|
return &env->env[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
} while ((envval = env->prev_envval) != 0);
|
} while ((envval = env->prev_envval) != 0);
|
||||||
|
|
||||||
return 0;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -2401,30 +2407,20 @@ static VALUE
|
|||||||
method_to_proc(VALUE method)
|
method_to_proc(VALUE method)
|
||||||
{
|
{
|
||||||
VALUE procval;
|
VALUE procval;
|
||||||
struct METHOD *meth;
|
|
||||||
rb_proc_t *proc;
|
rb_proc_t *proc;
|
||||||
rb_env_t *env;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* class Method
|
* class Method
|
||||||
* def to_proc
|
* def to_proc
|
||||||
* proc{|*args|
|
* lambda{|*args|
|
||||||
* self.call(*args)
|
* self.call(*args)
|
||||||
* }
|
* }
|
||||||
* end
|
* end
|
||||||
* end
|
* end
|
||||||
*/
|
*/
|
||||||
TypedData_Get_Struct(method, struct METHOD, &method_data_type, meth);
|
|
||||||
procval = rb_iterate(mlambda, 0, bmcall, method);
|
procval = rb_iterate(mlambda, 0, bmcall, method);
|
||||||
GetProcPtr(procval, proc);
|
GetProcPtr(procval, proc);
|
||||||
proc->is_from_method = 1;
|
proc->is_from_method = 1;
|
||||||
proc->block.self = meth->recv;
|
|
||||||
proc->block.klass = meth->defined_class;
|
|
||||||
GetEnvPtr(proc->envval, env);
|
|
||||||
env->block.self = meth->recv;
|
|
||||||
env->block.klass = meth->defined_class;
|
|
||||||
env->block.iseq = method_def_iseq(meth->me->def);
|
|
||||||
env->block.ep[-1] = (VALUE)method_cref(method);
|
|
||||||
return procval;
|
return procval;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2476,6 +2472,29 @@ localjump_reason(VALUE exc)
|
|||||||
return rb_iv_get(exc, "@reason");
|
return rb_iv_get(exc, "@reason");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rb_cref_t *rb_vm_cref_new_toplevel(void); /* vm.c */
|
||||||
|
|
||||||
|
static VALUE
|
||||||
|
env_clone(VALUE envval, VALUE receiver, const rb_cref_t *cref)
|
||||||
|
{
|
||||||
|
VALUE newenvval = TypedData_Wrap_Struct(RBASIC_CLASS(envval), RTYPEDDATA_TYPE(envval), 0);
|
||||||
|
rb_env_t *env, *newenv;
|
||||||
|
int envsize;
|
||||||
|
|
||||||
|
if (cref == NULL) {
|
||||||
|
cref = rb_vm_cref_new_toplevel();
|
||||||
|
}
|
||||||
|
|
||||||
|
GetEnvPtr(envval, env);
|
||||||
|
envsize = sizeof(rb_env_t) + (env->local_size + 1) * sizeof(VALUE);
|
||||||
|
newenv = xmalloc(envsize);
|
||||||
|
memcpy(newenv, env, envsize);
|
||||||
|
RTYPEDDATA_DATA(newenvval) = newenv;
|
||||||
|
newenv->block.self = receiver;
|
||||||
|
newenv->block.ep[-1] = (VALUE)cref;
|
||||||
|
return newenvval;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* call-seq:
|
* call-seq:
|
||||||
* prc.binding -> binding
|
* prc.binding -> binding
|
||||||
@ -2503,26 +2522,12 @@ proc_binding(VALUE self)
|
|||||||
envval = proc->envval;
|
envval = proc->envval;
|
||||||
iseq = proc->block.iseq;
|
iseq = proc->block.iseq;
|
||||||
if (RUBY_VM_IFUNC_P(iseq)) {
|
if (RUBY_VM_IFUNC_P(iseq)) {
|
||||||
rb_env_t *env;
|
if (IS_METHOD_PROC_ISEQ(iseq)) {
|
||||||
if (!IS_METHOD_PROC_ISEQ(iseq)) {
|
VALUE method = (VALUE)((struct vm_ifunc *)iseq)->data;
|
||||||
rb_raise(rb_eArgError, "Can't create Binding from C level Proc");
|
envval = env_clone(envval, method_receiver(method), method_cref(method));
|
||||||
}
|
}
|
||||||
iseq = rb_method_iseq((VALUE)((struct vm_ifunc *)iseq)->data);
|
else {
|
||||||
GetEnvPtr(envval, env);
|
rb_raise(rb_eArgError, "Can't create Binding from C level Proc");
|
||||||
if (iseq && 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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2530,7 +2535,18 @@ proc_binding(VALUE self)
|
|||||||
GetBindingPtr(bindval, bind);
|
GetBindingPtr(bindval, bind);
|
||||||
bind->env = envval;
|
bind->env = envval;
|
||||||
bind->blockprocval = proc->blockprocval;
|
bind->blockprocval = proc->blockprocval;
|
||||||
if (RUBY_VM_NORMAL_ISEQ_P(iseq)) {
|
|
||||||
|
if (!RUBY_VM_NORMAL_ISEQ_P(iseq)) {
|
||||||
|
if (RUBY_VM_IFUNC_P(iseq) && IS_METHOD_PROC_ISEQ(iseq)) {
|
||||||
|
VALUE method = (VALUE)((struct vm_ifunc *)iseq)->data;
|
||||||
|
iseq = rb_method_iseq(method);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
iseq = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (iseq) {
|
||||||
bind->path = iseq->location.path;
|
bind->path = iseq->location.path;
|
||||||
bind->first_lineno = FIX2INT(rb_iseq_first_lineno(iseq->self));
|
bind->first_lineno = FIX2INT(rb_iseq_first_lineno(iseq->self));
|
||||||
}
|
}
|
||||||
@ -2538,6 +2554,7 @@ proc_binding(VALUE self)
|
|||||||
bind->path = Qnil;
|
bind->path = Qnil;
|
||||||
bind->first_lineno = 0;
|
bind->first_lineno = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return bindval;
|
return bindval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -887,17 +887,25 @@ class TestMethod < Test::Unit::TestCase
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_to_proc_binding
|
class C
|
||||||
bug11012 = '[ruby-core:68673] [Bug #11012]'
|
D = "Const_D"
|
||||||
class << (obj = Object.new)
|
def foo
|
||||||
src = 1000.times.map {|i|"v#{i} = nil"}.join("\n")
|
a = b = c = 12345
|
||||||
eval("def foo()\n""#{src}\n""end")
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
b = obj.method(:foo).to_proc.binding
|
def test_to_proc_binding
|
||||||
b.local_variables.each_with_index {|n, i|
|
bug11012 = '[ruby-core:68673] [Bug #11012]'
|
||||||
b.local_variable_set(n, i)
|
|
||||||
}
|
b = C.new.method(:foo).to_proc.binding
|
||||||
assert_equal([998, 999], %w[v998 v999].map {|n| b.local_variable_get(n)}, bug11012)
|
assert_equal([], b.local_variables)
|
||||||
|
assert_equal("Const_D", b.eval("D")) # Check CREF
|
||||||
|
|
||||||
|
assert_raise(NameError){ b.local_variable_get(:foo) }
|
||||||
|
assert_equal(123, b.local_variable_set(:foo, 123))
|
||||||
|
assert_equal(123, b.local_variable_get(:foo))
|
||||||
|
assert_equal(456, b.local_variable_set(:bar, 456))
|
||||||
|
assert_equal(123, b.local_variable_get(:foo))
|
||||||
|
assert_equal(456, b.local_variable_get(:bar))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
12
vm.c
12
vm.c
@ -98,6 +98,12 @@ vm_cref_new_toplevel(rb_thread_t *th)
|
|||||||
return cref;
|
return cref;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rb_cref_t *
|
||||||
|
rb_vm_cref_new_toplevel(void)
|
||||||
|
{
|
||||||
|
return vm_cref_new_toplevel(GET_THREAD());
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
vm_cref_dump(const char *mesg, const rb_cref_t *cref)
|
vm_cref_dump(const char *mesg, const rb_cref_t *cref)
|
||||||
{
|
{
|
||||||
@ -772,8 +778,14 @@ rb_binding_add_dynavars(rb_binding_t *bind, int dyncount, const ID *dynvars)
|
|||||||
MEMCPY(dyns + 1, dynvars, ID, dyncount);
|
MEMCPY(dyns + 1, dynvars, ID, dyncount);
|
||||||
node = NEW_NODE(NODE_SCOPE, dyns, 0, 0);
|
node = NEW_NODE(NODE_SCOPE, dyns, 0, 0);
|
||||||
|
|
||||||
|
if (base_iseq) {
|
||||||
iseqval = rb_iseq_new(node, base_iseq->location.label, path, path,
|
iseqval = rb_iseq_new(node, base_iseq->location.label, path, path,
|
||||||
base_iseq->self, ISEQ_TYPE_EVAL);
|
base_iseq->self, ISEQ_TYPE_EVAL);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
VALUE tempstr = rb_str_new2("<temp>");
|
||||||
|
iseqval = rb_iseq_new_top(node, tempstr, tempstr, tempstr, Qfalse);
|
||||||
|
}
|
||||||
node->u1.tbl = 0; /* reset table */
|
node->u1.tbl = 0; /* reset table */
|
||||||
ALLOCV_END(idtmp);
|
ALLOCV_END(idtmp);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user