Skip to content

Commit 205d29a

Browse files
Add two new instructions for forwarding calls
This commit adds `sendforward` and `invokesuperforward` for forwarding parameters to calls Co-authored-by: Matt Valentine-House <matt@eightbitraptor.com>
1 parent e62bdae commit 205d29a

7 files changed

Lines changed: 301 additions & 206 deletions

File tree

compile.c

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1465,7 +1465,16 @@ new_insn_send(rb_iseq_t *iseq, int line_no, int node_id, ID id, VALUE argc, cons
14651465
if (blockiseq) {
14661466
RB_OBJ_WRITTEN(iseq, Qundef, blockiseq);
14671467
}
1468-
INSN *insn = new_insn_core(iseq, line_no, node_id, BIN(send), 2, operands);
1468+
1469+
INSN *insn;
1470+
1471+
if (vm_ci_flag((struct rb_callinfo *)ci) & VM_CALL_FORWARDING) {
1472+
insn = new_insn_core(iseq, line_no, node_id, BIN(sendforward), 2, operands);
1473+
}
1474+
else {
1475+
insn = new_insn_core(iseq, line_no, node_id, BIN(send), 2, operands);
1476+
}
1477+
14691478
RB_OBJ_WRITTEN(iseq, Qundef, ci);
14701479
RB_GC_GUARD(ci);
14711480
return insn;
@@ -8009,7 +8018,7 @@ compile_iter(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, in
80098018
INSN *iobj;
80108019
LINK_ELEMENT *last_elem = LAST_ELEMENT(ret);
80118020
iobj = IS_INSN(last_elem) ? (INSN*) last_elem : (INSN*) get_prev_insn((INSN*) last_elem);
8012-
while (INSN_OF(iobj) != BIN(send) && INSN_OF(iobj) != BIN(invokesuper)) {
8021+
while (!IS_INSN_ID(iobj, send) && !IS_INSN_ID(iobj, invokesuper) && !IS_INSN_ID(iobj, sendforward) && !IS_INSN_ID(iobj, invokesuperforward)) {
80138022
iobj = (INSN*) get_prev_insn(iobj);
80148023
}
80158024
ELEM_INSERT_NEXT(&iobj->link, (LINK_ELEMENT*) retry_end_l);
@@ -9607,9 +9616,15 @@ compile_super(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, i
96079616
if (type == NODE_ZSUPER) flag |= VM_CALL_ZSUPER;
96089617
ADD_INSN(ret, node, putself);
96099618
ADD_SEQ(ret, args);
9610-
ADD_INSN2(ret, node, invokesuper,
9611-
new_callinfo(iseq, 0, argc, flag, keywords, parent_block != NULL),
9612-
parent_block);
9619+
9620+
const struct rb_callinfo * ci = new_callinfo(iseq, 0, argc, flag, keywords, parent_block != NULL);
9621+
9622+
if (vm_ci_flag(ci) & VM_CALL_FORWARDING) {
9623+
ADD_INSN2(ret, node, invokesuperforward, ci, parent_block);
9624+
}
9625+
else {
9626+
ADD_INSN2(ret, node, invokesuper, ci, parent_block);
9627+
}
96139628

96149629
if (popped) {
96159630
ADD_INSN(ret, node, pop);

insns.def

Lines changed: 44 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -866,21 +866,38 @@ send
866866
(VALUE val)
867867
// attr rb_snum_t sp_inc = sp_inc_of_sendish(cd->ci);
868868
// attr rb_snum_t comptime_sp_inc = sp_inc_of_sendish(ci);
869+
{
870+
VALUE bh = vm_caller_setup_arg_block(ec, GET_CFP(), cd->ci, blockiseq, false);
871+
val = vm_sendish(ec, GET_CFP(), cd, bh, mexp_search_method);
872+
JIT_EXEC(ec, val);
873+
874+
if (UNDEF_P(val)) {
875+
RESTORE_REGS();
876+
NEXT_INSN();
877+
}
878+
}
879+
880+
/* invoke forward method. */
881+
DEFINE_INSN
882+
sendforward
883+
(CALL_DATA cd, ISEQ blockiseq)
884+
(...)
885+
(VALUE val)
886+
// attr rb_snum_t sp_inc = sp_inc_of_sendish(cd->ci);
887+
// attr rb_snum_t comptime_sp_inc = sp_inc_of_sendish(ci);
869888
{
870889
struct rb_forwarding_call_data adjusted_cd;
871890
struct rb_callinfo adjusted_ci;
872891

873892
CALL_DATA _cd = cd;
874893

875-
VALUE bh = vm_caller_setup_args(GET_EC(), GET_CFP(), &cd, blockiseq, 0, &adjusted_cd, &adjusted_ci);
894+
VALUE bh = vm_caller_setup_fwd_args(GET_EC(), GET_CFP(), &cd, blockiseq, 0, &adjusted_cd, &adjusted_ci);
876895

877896
val = vm_sendish(ec, GET_CFP(), cd, bh, mexp_search_method);
878897
JIT_EXEC(ec, val);
879898

880-
if (vm_ci_flag(_cd->ci) & VM_CALL_FORWARDING) {
881-
if (_cd->cc != cd->cc && vm_cc_markable(cd->cc)) {
882-
RB_OBJ_WRITE(GET_ISEQ(), &_cd->cc, cd->cc);
883-
}
899+
if (_cd->cc != cd->cc && vm_cc_markable(cd->cc)) {
900+
RB_OBJ_WRITE(GET_ISEQ(), &_cd->cc, cd->cc);
884901
}
885902

886903
if (UNDEF_P(val)) {
@@ -1005,20 +1022,37 @@ invokesuper
10051022
(VALUE val)
10061023
// attr rb_snum_t sp_inc = sp_inc_of_sendish(cd->ci);
10071024
// attr rb_snum_t comptime_sp_inc = sp_inc_of_sendish(ci);
1025+
{
1026+
VALUE bh = vm_caller_setup_arg_block(ec, GET_CFP(), cd->ci, blockiseq, true);
1027+
val = vm_sendish(ec, GET_CFP(), cd, bh, mexp_search_super);
1028+
JIT_EXEC(ec, val);
1029+
1030+
if (UNDEF_P(val)) {
1031+
RESTORE_REGS();
1032+
NEXT_INSN();
1033+
}
1034+
}
1035+
1036+
/* super(args) # args.size => num */
1037+
DEFINE_INSN
1038+
invokesuperforward
1039+
(CALL_DATA cd, ISEQ blockiseq)
1040+
(...)
1041+
(VALUE val)
1042+
// attr rb_snum_t sp_inc = sp_inc_of_sendish(cd->ci);
1043+
// attr rb_snum_t comptime_sp_inc = sp_inc_of_sendish(ci);
10081044
{
10091045
CALL_DATA _cd = cd;
10101046
struct rb_forwarding_call_data adjusted_cd;
10111047
struct rb_callinfo adjusted_ci;
10121048

1013-
VALUE bh = vm_caller_setup_args(GET_EC(), GET_CFP(), &cd, blockiseq, 1, &adjusted_cd, &adjusted_ci);
1049+
VALUE bh = vm_caller_setup_fwd_args(GET_EC(), GET_CFP(), &cd, blockiseq, 1, &adjusted_cd, &adjusted_ci);
10141050

10151051
val = vm_sendish(ec, GET_CFP(), cd, bh, mexp_search_super);
10161052
JIT_EXEC(ec, val);
10171053

1018-
if (vm_ci_flag(_cd->ci) & VM_CALL_FORWARDING) {
1019-
if (_cd->cc != cd->cc && vm_cc_markable(cd->cc)) {
1020-
RB_OBJ_WRITE(GET_ISEQ(), &_cd->cc, cd->cc);
1021-
}
1054+
if (_cd->cc != cd->cc && vm_cc_markable(cd->cc)) {
1055+
RB_OBJ_WRITE(GET_ISEQ(), &_cd->cc, cd->cc);
10221056
}
10231057

10241058
if (UNDEF_P(val)) {

prism_compile.c

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2990,7 +2990,7 @@ pm_compile_retry_end_label(rb_iseq_t *iseq, LINK_ANCHOR *const ret, LABEL *retry
29902990
INSN *iobj;
29912991
LINK_ELEMENT *last_elem = LAST_ELEMENT(ret);
29922992
iobj = IS_INSN(last_elem) ? (INSN*) last_elem : (INSN*) get_prev_insn((INSN*) last_elem);
2993-
while (INSN_OF(iobj) != BIN(send) && INSN_OF(iobj) != BIN(invokesuper)) {
2993+
while (!IS_INSN_ID(iobj, send) && !IS_INSN_ID(iobj, invokesuper) && !IS_INSN_ID(iobj, sendforward) && !IS_INSN_ID(iobj, invokesuperforward)) {
29942994
iobj = (INSN*) get_prev_insn(iobj);
29952995
}
29962996
ELEM_INSERT_NEXT(&iobj->link, (LINK_ELEMENT*) retry_end_l);
@@ -6707,7 +6707,7 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
67076707
flag |= VM_CALL_FORWARDING;
67086708
pm_local_index_t mult_local = pm_lookup_local_index(iseq, scope_node, PM_CONSTANT_DOT3, 0);
67096709
PUSH_GETLOCAL(ret, location, mult_local.index, mult_local.level);
6710-
PUSH_INSN2(ret, location, invokesuper, new_callinfo(iseq, 0, 0, flag, NULL, block != NULL), block);
6710+
PUSH_INSN2(ret, location, invokesuperforward, new_callinfo(iseq, 0, 0, flag, NULL, block != NULL), block);
67116711
if (popped) PUSH_INSN(ret, location, pop);
67126712
return;
67136713
}
@@ -9277,8 +9277,14 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
92779277
}
92789278

92799279
PUSH_SEQ(ret, args);
9280-
PUSH_INSN2(ret, location, invokesuper, new_callinfo(iseq, 0, argc, flags, keywords, current_block != NULL), current_block);
9281-
pm_compile_retry_end_label(iseq, ret, retry_end_l);
9280+
if (ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->param.flags.forwardable) {
9281+
flags |= VM_CALL_FORWARDING;
9282+
PUSH_INSN2(ret, location, invokesuperforward, new_callinfo(iseq, 0, argc, flags, keywords, current_block != NULL), current_block);
9283+
}
9284+
else {
9285+
PUSH_INSN2(ret, location, invokesuper, new_callinfo(iseq, 0, argc, flags, keywords, current_block != NULL), current_block);
9286+
pm_compile_retry_end_label(iseq, ret, retry_end_l);
9287+
}
92829288

92839289
if (popped) PUSH_INSN(ret, location, pop);
92849290
ISEQ_COMPILE_DATA(iseq)->current_block = previous_block;

vm_args.c

Lines changed: 31 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1061,52 +1061,54 @@ vm_caller_setup_arg_block(const rb_execution_context_t *ec, rb_control_frame_t *
10611061
static void vm_adjust_stack_forwarding(const struct rb_execution_context_struct *ec, struct rb_control_frame_struct *cfp, CALL_INFO callers_info, VALUE splat);
10621062

10631063
static VALUE
1064-
vm_caller_setup_args(const rb_execution_context_t *ec, rb_control_frame_t *reg_cfp,
1064+
vm_caller_setup_fwd_args(const rb_execution_context_t *ec, rb_control_frame_t *reg_cfp,
10651065
CALL_DATA *cd, const rb_iseq_t *blockiseq, const int is_super,
10661066
struct rb_forwarding_call_data *adjusted_cd, struct rb_callinfo *adjusted_ci)
10671067
{
10681068
CALL_INFO site_ci = (*cd)->ci;
10691069
VALUE bh = Qundef;
10701070

1071-
if (vm_ci_flag(site_ci) & VM_CALL_FORWARDING) {
1072-
RUBY_ASSERT(ISEQ_BODY(ISEQ_BODY(GET_ISEQ())->local_iseq)->param.flags.forwardable);
1073-
CALL_INFO caller_ci = (CALL_INFO)TOPN(0);
1071+
RUBY_ASSERT(ISEQ_BODY(ISEQ_BODY(GET_ISEQ())->local_iseq)->param.flags.forwardable);
1072+
CALL_INFO caller_ci = (CALL_INFO)TOPN(0);
10741073

1075-
unsigned int forwarding_argc = vm_ci_argc(site_ci);
1076-
VALUE splat = Qfalse;
1074+
unsigned int forwarding_argc = vm_ci_argc(site_ci);
1075+
VALUE splat = Qfalse;
10771076

1078-
if (vm_ci_flag(site_ci) & VM_CALL_ARGS_SPLAT) {
1079-
// If we're called with args_splat, the top 1 should be an array
1080-
splat = TOPN(1);
1081-
forwarding_argc += (RARRAY_LEN(splat) - 1);
1082-
}
1077+
if (vm_ci_flag(site_ci) & VM_CALL_ARGS_SPLAT) {
1078+
// If we're called with args_splat, the top 1 should be an array
1079+
splat = TOPN(1);
1080+
forwarding_argc += (RARRAY_LEN(splat) - 1);
1081+
}
10831082

1084-
// Need to setup the block in case of e.g. `super { :block }`
1085-
if (is_super && blockiseq) {
1086-
bh = vm_caller_setup_arg_block(ec, GET_CFP(), site_ci, blockiseq, is_super);
1087-
}
1088-
else {
1089-
bh = VM_ENV_BLOCK_HANDLER(GET_LEP());
1090-
}
1083+
// Need to setup the block in case of e.g. `super { :block }`
1084+
if (is_super && blockiseq) {
1085+
bh = vm_caller_setup_arg_block(ec, GET_CFP(), site_ci, blockiseq, is_super);
1086+
}
1087+
else {
1088+
bh = VM_ENV_BLOCK_HANDLER(GET_LEP());
1089+
}
10911090

1092-
vm_adjust_stack_forwarding(ec, GET_CFP(), caller_ci, splat);
1091+
vm_adjust_stack_forwarding(ec, GET_CFP(), caller_ci, splat);
10931092

1094-
*adjusted_ci = VM_CI_ON_STACK(
1093+
*adjusted_ci = VM_CI_ON_STACK(
10951094
vm_ci_mid(site_ci),
10961095
(vm_ci_flag(caller_ci) | (vm_ci_flag(site_ci) & (VM_CALL_FCALL | VM_CALL_FORWARDING))),
10971096
forwarding_argc + vm_ci_argc(caller_ci),
10981097
vm_ci_kwarg(caller_ci)
1099-
);
1098+
);
11001099

1101-
adjusted_cd->cd.ci = adjusted_ci;
1102-
adjusted_cd->cd.cc = (*cd)->cc;
1103-
adjusted_cd->caller_ci = caller_ci;
1100+
adjusted_cd->cd.ci = adjusted_ci;
1101+
adjusted_cd->cd.cc = (*cd)->cc;
1102+
adjusted_cd->caller_ci = caller_ci;
11041103

1105-
*cd = &adjusted_cd->cd;
1106-
}
1107-
else {
1108-
bh = vm_caller_setup_arg_block(ec, GET_CFP(), site_ci, blockiseq, is_super);
1109-
}
1104+
*cd = &adjusted_cd->cd;
11101105

11111106
return bh;
11121107
}
1108+
1109+
static VALUE
1110+
vm_caller_setup_args(const rb_execution_context_t *ec, rb_control_frame_t *reg_cfp,
1111+
CALL_DATA *cd, const rb_iseq_t *blockiseq, const int is_super)
1112+
{
1113+
return vm_caller_setup_arg_block(ec, GET_CFP(), (*cd)->ci, blockiseq, is_super);
1114+
}

vm_insnhelper.c

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5929,7 +5929,15 @@ rb_vm_send(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp, CALL_DATA cd
59295929
struct rb_callinfo adjusted_ci;
59305930
CALL_DATA _cd = cd;
59315931

5932-
VALUE bh = vm_caller_setup_args(ec, GET_CFP(), &cd, blockiseq, false, &adjusted_cd, &adjusted_ci);
5932+
VALUE bh;
5933+
5934+
if (vm_ci_flag(_cd->ci) & VM_CALL_FORWARDING) {
5935+
bh = vm_caller_setup_fwd_args(GET_EC(), GET_CFP(), &cd, blockiseq, false, &adjusted_cd, &adjusted_ci);
5936+
}
5937+
else {
5938+
bh = vm_caller_setup_args(ec, GET_CFP(), &cd, blockiseq, false);
5939+
}
5940+
59335941
VALUE val = vm_sendish(ec, GET_CFP(), cd, bh, mexp_search_method);
59345942

59355943
if (vm_ci_flag(_cd->ci) & VM_CALL_FORWARDING) {
@@ -5960,7 +5968,15 @@ rb_vm_invokesuper(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp, CALL_
59605968
struct rb_callinfo adjusted_ci;
59615969
CALL_DATA _cd = cd;
59625970

5963-
VALUE bh = vm_caller_setup_args(ec, GET_CFP(), &cd, blockiseq, true, &adjusted_cd, &adjusted_ci);
5971+
VALUE bh;
5972+
5973+
if (vm_ci_flag(_cd->ci) & VM_CALL_FORWARDING) {
5974+
bh = vm_caller_setup_fwd_args(ec, GET_CFP(), &cd, blockiseq, true, &adjusted_cd, &adjusted_ci);
5975+
}
5976+
else {
5977+
bh = vm_caller_setup_args(ec, GET_CFP(), &cd, blockiseq, true);
5978+
}
5979+
59645980
VALUE val = vm_sendish(ec, GET_CFP(), cd, bh, mexp_search_super);
59655981

59665982
if (vm_ci_flag(_cd->ci) & VM_CALL_FORWARDING) {

yjit/src/codegen.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9070,6 +9070,14 @@ fn gen_send(
90709070
})
90719071
}
90729072

9073+
fn gen_sendforward(
9074+
jit: &mut JITState,
9075+
asm: &mut Assembler,
9076+
ocb: &mut OutlinedCb,
9077+
) -> Option<CodegenStatus> {
9078+
return gen_send(jit, asm, ocb);
9079+
}
9080+
90739081
fn gen_invokeblock(
90749082
jit: &mut JITState,
90759083
asm: &mut Assembler,
@@ -9253,6 +9261,14 @@ fn gen_invokesuper(
92539261
})
92549262
}
92559263

9264+
fn gen_invokesuperforward(
9265+
jit: &mut JITState,
9266+
asm: &mut Assembler,
9267+
ocb: &mut OutlinedCb,
9268+
) -> Option<CodegenStatus> {
9269+
return gen_invokesuper(jit, asm, ocb);
9270+
}
9271+
92569272
fn gen_invokesuper_specialized(
92579273
jit: &mut JITState,
92589274
asm: &mut Assembler,
@@ -10232,8 +10248,10 @@ fn get_gen_fn(opcode: VALUE) -> Option<InsnGenFn> {
1023210248
YARVINSN_getblockparam => Some(gen_getblockparam),
1023310249
YARVINSN_opt_send_without_block => Some(gen_opt_send_without_block),
1023410250
YARVINSN_send => Some(gen_send),
10251+
YARVINSN_sendforward => Some(gen_sendforward),
1023510252
YARVINSN_invokeblock => Some(gen_invokeblock),
1023610253
YARVINSN_invokesuper => Some(gen_invokesuper),
10254+
YARVINSN_invokesuperforward => Some(gen_invokesuperforward),
1023710255
YARVINSN_leave => Some(gen_leave),
1023810256

1023910257
YARVINSN_getglobal => Some(gen_getglobal),

0 commit comments

Comments
 (0)