ruby-changes:47387
From: nagachika <ko1@a...>
Date: Sat, 5 Aug 2017 00:06:29 +0900 (JST)
Subject: [ruby-changes:47387] nagachika:r59503 (ruby_2_4): merge revision(s) 59063: [Backport #13605]
nagachika 2017-08-05 00:06:22 +0900 (Sat, 05 Aug 2017) New Revision: 59503 https://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=59503 Log: merge revision(s) 59063: [Backport #13605] * 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. Modified directories: branches/ruby_2_4/ Modified files: branches/ruby_2_4/proc.c branches/ruby_2_4/test/ruby/test_proc.rb branches/ruby_2_4/version.h Index: ruby_2_4/proc.c =================================================================== --- ruby_2_4/proc.c (revision 59502) +++ ruby_2_4/proc.c (revision 59503) @@ -392,8 +392,9 @@ bind_eval(int argc, VALUE *argv, VALUE b https://github.com/ruby/ruby/blob/trunk/ruby_2_4/proc.c#L392 } 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; @@ -403,15 +404,18 @@ get_local_variable_ptr(const rb_env_t *e https://github.com/ruby/ruby/blob/trunk/ruby_2_4/proc.c#L404 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; } @@ -494,12 +498,14 @@ bind_local_variable_get(VALUE bindval, V https://github.com/ruby/ruby/blob/trunk/ruby_2_4/proc.c#L498 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", @@ -546,7 +552,7 @@ bind_local_variable_set(VALUE bindval, V https://github.com/ruby/ruby/blob/trunk/ruby_2_4/proc.c#L552 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(bind, 1, &lid); env = VM_ENV_ENVVAL_PTR(vm_block_ep(&bind->block)); @@ -579,11 +585,13 @@ bind_local_variable_defined_p(VALUE bind https://github.com/ruby/ruby/blob/trunk/ruby_2_4/proc.c#L585 { 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; } /* Index: ruby_2_4/version.h =================================================================== --- ruby_2_4/version.h (revision 59502) +++ ruby_2_4/version.h (revision 59503) @@ -1,6 +1,6 @@ https://github.com/ruby/ruby/blob/trunk/ruby_2_4/version.h#L1 #define RUBY_VERSION "2.4.2" #define RUBY_RELEASE_DATE "2017-08-04" -#define RUBY_PATCHLEVEL 169 +#define RUBY_PATCHLEVEL 170 #define RUBY_RELEASE_YEAR 2017 #define RUBY_RELEASE_MONTH 8 Index: ruby_2_4/test/ruby/test_proc.rb =================================================================== --- ruby_2_4/test/ruby/test_proc.rb (revision 59502) +++ ruby_2_4/test/ruby/test_proc.rb (revision 59503) @@ -1322,6 +1322,20 @@ class TestProc < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/ruby_2_4/test/ruby/test_proc.rb#L1322 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)) Index: ruby_2_4 =================================================================== --- ruby_2_4 (revision 59502) +++ ruby_2_4 (revision 59503) Property changes on: ruby_2_4 ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /trunk:r59063 -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/