[PRISM] Fix block param instructions when it has a recevier

In the following code:

```ruby
def foo(&blk)
  blk.call
end
```

Prism was using the `getblockparam` instruction but it should be
`getblockparamproxy`. In this case we have a receiver, if it's a local
variable read node, then it needs to go through the path to use
`getblockparamproxy`.

Before:

```
== disasm: #<ISeq:<main>@test2.rb:1 (1,0)-(3,3)>
0000 definemethod                           :foo, foo                 (   1)[Li]
0003 putobject                              :foo
0005 leave

== disasm: #<ISeq:foo@test2.rb:1 (1,0)-(3,3)>
local table (size: 1, argc: 0 [opts: 0, rest: -1, post: 0, block: 0, kw: -1@-1, kwrest: -1])
[ 1] blk@0<Block>
0000 getblockparam                          blk@0, 0                  (   2)[LiCa]
0003 opt_send_without_block                 <calldata!mid:call, argc:0, ARGS_SIMPLE>
0005 leave                                                            (   3)[Re]
```

After:

```
== disasm: #<ISeq:<main>@test2.rb:1 (1,0)-(3,3)>
0000 definemethod                           :foo, foo                 (   1)[Li]
0003 putobject                              :foo
0005 leave

== disasm: #<ISeq:foo@test2.rb:1 (1,0)-(3,3)>
local table (size: 1, argc: 0 [opts: 0, rest: -1, post: 0, block: 0, kw: -1@-1, kwrest: -1])
[ 1] blk@0<Block>
0000 getblockparamproxy                     blk@0, 0                  (   2)[LiCa]
0003 opt_send_without_block                 <calldata!mid:call, argc:0, ARGS_SIMPLE>
0005 leave                                                            (   3)[Re]
```

Fixes `test_getblockparamproxy` and `test_ifunc_getblockparamproxy` in
test_yjit.rb. Related to ruby/prism#2935.
This commit is contained in:
eileencodes 2024-07-23 14:44:46 -04:00 коммит произвёл Kevin Newton
Родитель 70d4dcb76c
Коммит b4a02502c2
1 изменённых файлов: 15 добавлений и 1 удалений

Просмотреть файл

@ -6049,7 +6049,21 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
PUSH_INSN(ret, location, putself);
}
else {
PM_COMPILE_NOT_POPPED(cast->receiver);
if (method_id == idCall && PM_NODE_TYPE_P(cast->receiver, PM_LOCAL_VARIABLE_READ_NODE)) {
const pm_local_variable_read_node_t *read_node_cast = (const pm_local_variable_read_node_t *) cast->receiver;
uint32_t node_id = cast->receiver->node_id;
int idx, level;
if (iseq_block_param_id_p(iseq, pm_constant_id_lookup(scope_node, read_node_cast->name), &idx, &level)) {
ADD_ELEM(ret, (LINK_ELEMENT *) new_insn_body(iseq, location.line, node_id, BIN(getblockparamproxy), 2, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level)));
}
else {
PM_COMPILE_NOT_POPPED(cast->receiver);
}
}
else {
PM_COMPILE_NOT_POPPED(cast->receiver);
}
}
pm_compile_call(iseq, cast, ret, popped, scope_node, method_id, start);