merge revision(s) db02a6b3ab: [Backport #21103]

[Bug #21103] Fix local variable index calculation with forwarding

	Forwarding argument is optimized not to packed when no other arguments
	and an internal object refers values before it.  This size is decided
	at called time, calculate the local variable index from the fixed end
	point.
This commit is contained in:
Takashi Kokubun 2025-02-13 21:12:33 -08:00
parent feb4a688a2
commit e5403bd137
3 changed files with 106 additions and 4 deletions

8
proc.c
View file

@ -414,11 +414,11 @@ get_local_variable_ptr(const rb_env_t **envp, ID lid)
}
const rb_iseq_t *iseq = env->iseq;
unsigned int i;
VM_ASSERT(rb_obj_is_iseq((VALUE)iseq));
for (i=0; i<ISEQ_BODY(iseq)->local_table_size; i++) {
const unsigned int local_table_size = ISEQ_BODY(iseq)->local_table_size;
for (unsigned int i=0; i<local_table_size; i++) {
if (ISEQ_BODY(iseq)->local_table[i] == lid) {
if (ISEQ_BODY(iseq)->local_iseq == iseq &&
ISEQ_BODY(iseq)->param.flags.has_block &&
@ -431,7 +431,9 @@ get_local_variable_ptr(const rb_env_t **envp, ID lid)
}
*envp = env;
return &env->env[i];
unsigned int last_lvar = env->env_size+VM_ENV_INDEX_LAST_LVAR
- 1 /* errinfo */;
return &env->env[last_lvar - (local_table_size - i)];
}
}
}

View file

@ -1439,6 +1439,46 @@ class TestMethod < Test::Unit::TestCase
def foo
a = b = c = a = b = c = 12345
end
def binding_noarg
a = a = 12345
binding
end
def binding_one_arg(x)
a = a = 12345
binding
end
def binding_optargs(x, y=42)
a = a = 12345
binding
end
def binding_anyargs(*x)
a = a = 12345
binding
end
def binding_keywords(x: 42)
a = a = 12345
binding
end
def binding_anykeywords(**x)
a = a = 12345
binding
end
def binding_forwarding(...)
a = a = 12345
binding
end
def binding_forwarding1(x, ...)
a = a = 12345
binding
end
end
def test_to_proc_binding
@ -1457,6 +1497,66 @@ class TestMethod < Test::Unit::TestCase
assert_equal([:bar, :foo], b.local_variables.sort, bug11012)
end
def test_method_binding
c = C.new
b = c.binding_noarg
assert_equal(12345, b.local_variable_get(:a))
b = c.binding_one_arg(0)
assert_equal(12345, b.local_variable_get(:a))
assert_equal(0, b.local_variable_get(:x))
b = c.binding_anyargs()
assert_equal(12345, b.local_variable_get(:a))
assert_equal([], b.local_variable_get(:x))
b = c.binding_anyargs(0)
assert_equal(12345, b.local_variable_get(:a))
assert_equal([0], b.local_variable_get(:x))
b = c.binding_anyargs(0, 1)
assert_equal(12345, b.local_variable_get(:a))
assert_equal([0, 1], b.local_variable_get(:x))
b = c.binding_optargs(0)
assert_equal(12345, b.local_variable_get(:a))
assert_equal(0, b.local_variable_get(:x))
assert_equal(42, b.local_variable_get(:y))
b = c.binding_optargs(0, 1)
assert_equal(12345, b.local_variable_get(:a))
assert_equal(0, b.local_variable_get(:x))
assert_equal(1, b.local_variable_get(:y))
b = c.binding_keywords()
assert_equal(12345, b.local_variable_get(:a))
assert_equal(42, b.local_variable_get(:x))
b = c.binding_keywords(x: 102)
assert_equal(12345, b.local_variable_get(:a))
assert_equal(102, b.local_variable_get(:x))
b = c.binding_anykeywords()
assert_equal(12345, b.local_variable_get(:a))
assert_equal({}, b.local_variable_get(:x))
b = c.binding_anykeywords(foo: 999)
assert_equal(12345, b.local_variable_get(:a))
assert_equal({foo: 999}, b.local_variable_get(:x))
b = c.binding_forwarding()
assert_equal(12345, b.local_variable_get(:a))
b = c.binding_forwarding(0)
assert_equal(12345, b.local_variable_get(:a))
b = c.binding_forwarding(0, 1)
assert_equal(12345, b.local_variable_get(:a))
b = c.binding_forwarding(foo: 42)
assert_equal(12345, b.local_variable_get(:a))
b = c.binding_forwarding1(987)
assert_equal(12345, b.local_variable_get(:a))
assert_equal(987, b.local_variable_get(:x))
b = c.binding_forwarding1(987, 654)
assert_equal(12345, b.local_variable_get(:a))
assert_equal(987, b.local_variable_get(:x))
end
MethodInMethodClass_Setup = -> do
remove_const :MethodInMethodClass if defined? MethodInMethodClass

View file

@ -11,7 +11,7 @@
# define RUBY_VERSION_MINOR RUBY_API_VERSION_MINOR
#define RUBY_VERSION_TEENY 1
#define RUBY_RELEASE_DATE RUBY_RELEASE_YEAR_STR"-"RUBY_RELEASE_MONTH_STR"-"RUBY_RELEASE_DAY_STR
#define RUBY_PATCHLEVEL 22
#define RUBY_PATCHLEVEL 23
#include "ruby/version.h"
#include "ruby/internal/abi.h"