Skip to content

Commit db02a6b

Browse files
committed
[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.
1 parent 71f402c commit db02a6b

File tree

2 files changed

+105
-3
lines changed

2 files changed

+105
-3
lines changed

proc.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -414,11 +414,11 @@ get_local_variable_ptr(const rb_env_t **envp, ID lid)
414414
}
415415

416416
const rb_iseq_t *iseq = env->iseq;
417-
unsigned int i;
418417

419418
VM_ASSERT(rb_obj_is_iseq((VALUE)iseq));
420419

421-
for (i=0; i<ISEQ_BODY(iseq)->local_table_size; i++) {
420+
const unsigned int local_table_size = ISEQ_BODY(iseq)->local_table_size;
421+
for (unsigned int i=0; i<local_table_size; i++) {
422422
if (ISEQ_BODY(iseq)->local_table[i] == lid) {
423423
if (ISEQ_BODY(iseq)->local_iseq == iseq &&
424424
ISEQ_BODY(iseq)->param.flags.has_block &&
@@ -431,7 +431,9 @@ get_local_variable_ptr(const rb_env_t **envp, ID lid)
431431
}
432432

433433
*envp = env;
434-
return &env->env[i];
434+
unsigned int last_lvar = env->env_size+VM_ENV_INDEX_LAST_LVAR
435+
- 1 /* errinfo */;
436+
return &env->env[last_lvar - (local_table_size - i)];
435437
}
436438
}
437439
}

test/ruby/test_method.rb

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1439,6 +1439,46 @@ class C
14391439
def foo
14401440
a = b = c = a = b = c = 12345
14411441
end
1442+
1443+
def binding_noarg
1444+
a = a = 12345
1445+
binding
1446+
end
1447+
1448+
def binding_one_arg(x)
1449+
a = a = 12345
1450+
binding
1451+
end
1452+
1453+
def binding_optargs(x, y=42)
1454+
a = a = 12345
1455+
binding
1456+
end
1457+
1458+
def binding_anyargs(*x)
1459+
a = a = 12345
1460+
binding
1461+
end
1462+
1463+
def binding_keywords(x: 42)
1464+
a = a = 12345
1465+
binding
1466+
end
1467+
1468+
def binding_anykeywords(**x)
1469+
a = a = 12345
1470+
binding
1471+
end
1472+
1473+
def binding_forwarding(...)
1474+
a = a = 12345
1475+
binding
1476+
end
1477+
1478+
def binding_forwarding1(x, ...)
1479+
a = a = 12345
1480+
binding
1481+
end
14421482
end
14431483

14441484
def test_to_proc_binding
@@ -1457,6 +1497,66 @@ def test_to_proc_binding
14571497
assert_equal([:bar, :foo], b.local_variables.sort, bug11012)
14581498
end
14591499

1500+
def test_method_binding
1501+
c = C.new
1502+
1503+
b = c.binding_noarg
1504+
assert_equal(12345, b.local_variable_get(:a))
1505+
1506+
b = c.binding_one_arg(0)
1507+
assert_equal(12345, b.local_variable_get(:a))
1508+
assert_equal(0, b.local_variable_get(:x))
1509+
1510+
b = c.binding_anyargs()
1511+
assert_equal(12345, b.local_variable_get(:a))
1512+
assert_equal([], b.local_variable_get(:x))
1513+
b = c.binding_anyargs(0)
1514+
assert_equal(12345, b.local_variable_get(:a))
1515+
assert_equal([0], b.local_variable_get(:x))
1516+
b = c.binding_anyargs(0, 1)
1517+
assert_equal(12345, b.local_variable_get(:a))
1518+
assert_equal([0, 1], b.local_variable_get(:x))
1519+
1520+
b = c.binding_optargs(0)
1521+
assert_equal(12345, b.local_variable_get(:a))
1522+
assert_equal(0, b.local_variable_get(:x))
1523+
assert_equal(42, b.local_variable_get(:y))
1524+
b = c.binding_optargs(0, 1)
1525+
assert_equal(12345, b.local_variable_get(:a))
1526+
assert_equal(0, b.local_variable_get(:x))
1527+
assert_equal(1, b.local_variable_get(:y))
1528+
1529+
b = c.binding_keywords()
1530+
assert_equal(12345, b.local_variable_get(:a))
1531+
assert_equal(42, b.local_variable_get(:x))
1532+
b = c.binding_keywords(x: 102)
1533+
assert_equal(12345, b.local_variable_get(:a))
1534+
assert_equal(102, b.local_variable_get(:x))
1535+
1536+
b = c.binding_anykeywords()
1537+
assert_equal(12345, b.local_variable_get(:a))
1538+
assert_equal({}, b.local_variable_get(:x))
1539+
b = c.binding_anykeywords(foo: 999)
1540+
assert_equal(12345, b.local_variable_get(:a))
1541+
assert_equal({foo: 999}, b.local_variable_get(:x))
1542+
1543+
b = c.binding_forwarding()
1544+
assert_equal(12345, b.local_variable_get(:a))
1545+
b = c.binding_forwarding(0)
1546+
assert_equal(12345, b.local_variable_get(:a))
1547+
b = c.binding_forwarding(0, 1)
1548+
assert_equal(12345, b.local_variable_get(:a))
1549+
b = c.binding_forwarding(foo: 42)
1550+
assert_equal(12345, b.local_variable_get(:a))
1551+
1552+
b = c.binding_forwarding1(987)
1553+
assert_equal(12345, b.local_variable_get(:a))
1554+
assert_equal(987, b.local_variable_get(:x))
1555+
b = c.binding_forwarding1(987, 654)
1556+
assert_equal(12345, b.local_variable_get(:a))
1557+
assert_equal(987, b.local_variable_get(:x))
1558+
end
1559+
14601560
MethodInMethodClass_Setup = -> do
14611561
remove_const :MethodInMethodClass if defined? MethodInMethodClass
14621562

0 commit comments

Comments
 (0)