From b4a02502c2125cebd034967027d65ee975987f73 Mon Sep 17 00:00:00 2001 From: eileencodes Date: Tue, 23 Jul 2024 14:44:46 -0400 Subject: [PATCH] [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: #@test2.rb:1 (1,0)-(3,3)> 0000 definemethod :foo, foo ( 1)[Li] 0003 putobject :foo 0005 leave == disasm: # local table (size: 1, argc: 0 [opts: 0, rest: -1, post: 0, block: 0, kw: -1@-1, kwrest: -1]) [ 1] blk@0 0000 getblockparam blk@0, 0 ( 2)[LiCa] 0003 opt_send_without_block 0005 leave ( 3)[Re] ``` After: ``` == disasm: #@test2.rb:1 (1,0)-(3,3)> 0000 definemethod :foo, foo ( 1)[Li] 0003 putobject :foo 0005 leave == disasm: # local table (size: 1, argc: 0 [opts: 0, rest: -1, post: 0, block: 0, kw: -1@-1, kwrest: -1]) [ 1] blk@0 0000 getblockparamproxy blk@0, 0 ( 2)[LiCa] 0003 opt_send_without_block 0005 leave ( 3)[Re] ``` Fixes `test_getblockparamproxy` and `test_ifunc_getblockparamproxy` in test_yjit.rb. Related to ruby/prism#2935. --- prism_compile.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/prism_compile.c b/prism_compile.c index 5983489dd0..6768e00718 100644 --- a/prism_compile.c +++ b/prism_compile.c @@ -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);