mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
* proc.c (get_local_variable_ptr): return found env ptr. Returned env
will be used by write barrier at `bind_local_variable_set()'. [Bug #13605] * test/ruby/test_proc.rb: add a test for this issue. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@59063 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
b25237fb5d
commit
fccbc2d278
2 changed files with 26 additions and 4 deletions
16
proc.c
16
proc.c
|
@ -386,8 +386,9 @@ bind_eval(int argc, VALUE *argv, VALUE bindval)
|
|||
}
|
||||
|
||||
static const VALUE *
|
||||
get_local_variable_ptr(const rb_env_t *env, ID lid)
|
||||
get_local_variable_ptr(const rb_env_t **envp, ID lid)
|
||||
{
|
||||
const rb_env_t *env = *envp;
|
||||
do {
|
||||
if (!VM_ENV_FLAGS(env->ep, VM_FRAME_FLAG_CFRAME)) {
|
||||
const rb_iseq_t *iseq = env->iseq;
|
||||
|
@ -397,15 +398,18 @@ get_local_variable_ptr(const rb_env_t *env, ID lid)
|
|||
|
||||
for (i=0; i<iseq->body->local_table_size; i++) {
|
||||
if (iseq->body->local_table[i] == lid) {
|
||||
*envp = env;
|
||||
return &env->env[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
*envp = NULL;
|
||||
return NULL;
|
||||
}
|
||||
} while ((env = rb_vm_env_prev_env(env)) != NULL);
|
||||
|
||||
*envp = NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -488,12 +492,14 @@ bind_local_variable_get(VALUE bindval, VALUE sym)
|
|||
ID lid = check_local_id(bindval, &sym);
|
||||
const rb_binding_t *bind;
|
||||
const VALUE *ptr;
|
||||
const rb_env_t *env;
|
||||
|
||||
if (!lid) goto undefined;
|
||||
|
||||
GetBindingPtr(bindval, bind);
|
||||
|
||||
if ((ptr = get_local_variable_ptr(VM_ENV_ENVVAL_PTR(vm_block_ep(&bind->block)), lid)) == NULL) {
|
||||
env = VM_ENV_ENVVAL_PTR(vm_block_ep(&bind->block));
|
||||
if ((ptr = get_local_variable_ptr(&env, lid)) == NULL) {
|
||||
sym = ID2SYM(lid);
|
||||
undefined:
|
||||
rb_name_err_raise("local variable `%1$s' not defined for %2$s",
|
||||
|
@ -540,7 +546,7 @@ bind_local_variable_set(VALUE bindval, VALUE sym, VALUE val)
|
|||
|
||||
GetBindingPtr(bindval, bind);
|
||||
env = VM_ENV_ENVVAL_PTR(vm_block_ep(&bind->block));
|
||||
if ((ptr = get_local_variable_ptr(env, lid)) == NULL) {
|
||||
if ((ptr = get_local_variable_ptr(&env, lid)) == NULL) {
|
||||
/* not found. create new env */
|
||||
ptr = rb_binding_add_dynavars(bindval, bind, 1, &lid);
|
||||
env = VM_ENV_ENVVAL_PTR(vm_block_ep(&bind->block));
|
||||
|
@ -573,11 +579,13 @@ bind_local_variable_defined_p(VALUE bindval, VALUE sym)
|
|||
{
|
||||
ID lid = check_local_id(bindval, &sym);
|
||||
const rb_binding_t *bind;
|
||||
const rb_env_t *env;
|
||||
|
||||
if (!lid) return Qfalse;
|
||||
|
||||
GetBindingPtr(bindval, bind);
|
||||
return get_local_variable_ptr(VM_ENV_ENVVAL_PTR(vm_block_ep(&bind->block)), lid) ? Qtrue : Qfalse;
|
||||
env = VM_ENV_ENVVAL_PTR(vm_block_ep(&bind->block));
|
||||
return get_local_variable_ptr(&env, lid) ? Qtrue : Qfalse;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -1324,6 +1324,20 @@ class TestProc < Test::Unit::TestCase
|
|||
assert_equal(20, b.eval("b"))
|
||||
end
|
||||
|
||||
def test_local_variable_set_wb
|
||||
assert_ruby_status([], <<-'end;', '[Bug #13605]')
|
||||
b = binding
|
||||
n = 20_000
|
||||
|
||||
n.times do |i|
|
||||
v = rand(2_000)
|
||||
name = "n#{v}"
|
||||
value = Object.new
|
||||
b.local_variable_set name, value
|
||||
end
|
||||
end;
|
||||
end
|
||||
|
||||
def test_local_variable_defined?
|
||||
b = get_binding
|
||||
assert_equal(true, b.local_variable_defined?(:a))
|
||||
|
|
Loading…
Add table
Reference in a new issue