Skip to content

Commit ded23b6

Browse files
authored
Implement opt_mod as call to interpreter function (ruby#29)
1 parent 9ab9e63 commit ded23b6

File tree

3 files changed

+80
-15
lines changed

3 files changed

+80
-15
lines changed

bootstraptest/test_yjit.rb

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,13 @@
1+
# Test for opt_mod
2+
assert_equal '2', %q{
3+
def mod(a, b)
4+
a % b
5+
end
6+
7+
mod(7, 5)
8+
mod(7, 5)
9+
}
10+
111
# BOP redefined methods work when JIT compiled
212
assert_equal 'false', %q{
313
def less_than x

vm_insnhelper.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4905,6 +4905,12 @@ vm_opt_mod(VALUE recv, VALUE obj)
49054905
}
49064906
}
49074907

4908+
VALUE
4909+
rb_vm_opt_mod(VALUE recv, VALUE obj)
4910+
{
4911+
return vm_opt_mod(recv, obj);
4912+
}
4913+
49084914
static VALUE
49094915
vm_opt_neq(const rb_iseq_t *iseq, CALL_DATA cd, CALL_DATA cd_eq, VALUE recv, VALUE obj)
49104916
{

yjit_codegen.c

Lines changed: 64 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,30 @@ jit_peek_at_self(jitstate_t *jit, ctx_t *ctx)
113113
return jit->ec->cfp->self;
114114
}
115115

116+
// Save the incremented PC on the CFP
117+
// This is necessary when calleees can raise or allocate
118+
void
119+
jit_save_pc(jitstate_t* jit, x86opnd_t scratch_reg)
120+
{
121+
mov(cb, scratch_reg, const_ptr_opnd(jit->pc + insn_len(jit->opcode)));
122+
mov(cb, mem_opnd(64, REG_CFP, offsetof(rb_control_frame_t, pc)), scratch_reg);
123+
}
124+
125+
// Save the current SP on the CFP
126+
// This realigns the interpreter SP with the JIT SP
127+
// Note: this will change the current value of REG_SP,
128+
// which could invalidate memory operands
129+
void
130+
jit_save_sp(jitstate_t* jit, ctx_t* ctx)
131+
{
132+
if (ctx->sp_offset != 0) {
133+
x86opnd_t stack_pointer = ctx_sp_opnd(ctx, 0);
134+
lea(cb, REG_SP, stack_pointer);
135+
mov(cb, member_opnd(REG_CFP, rb_control_frame_t, sp), REG_SP);
136+
ctx->sp_offset = 0;
137+
}
138+
}
139+
116140
static bool jit_guard_known_klass(jitstate_t *jit, ctx_t* ctx, VALUE known_klass, insn_opnd_t insn_opnd, const int max_chain_depth, uint8_t *side_exit);
117141

118142
#if RUBY_DEBUG
@@ -1344,20 +1368,14 @@ gen_opt_aref(jitstate_t *jit, ctx_t *ctx)
13441368
// Call VALUE rb_hash_aref(VALUE hash, VALUE key).
13451369
{
13461370
// Write incremented pc to cfp->pc as the routine can raise and allocate
1347-
mov(cb, REG0, const_ptr_opnd(jit->pc + insn_len(BIN(opt_aref))));
1348-
mov(cb, member_opnd(REG_CFP, rb_control_frame_t, pc), REG0);
1371+
jit_save_pc(jit, REG0);
13491372

13501373
// About to change REG_SP which these operands depend on. Yikes.
13511374
mov(cb, R8, recv_opnd);
13521375
mov(cb, R9, idx_opnd);
13531376

13541377
// Write sp to cfp->sp since rb_hash_aref might need to call #hash on the key
1355-
if (ctx->sp_offset != 0) {
1356-
x86opnd_t stack_pointer = ctx_sp_opnd(ctx, 0);
1357-
lea(cb, REG_SP, stack_pointer);
1358-
mov(cb, member_opnd(REG_CFP, rb_control_frame_t, sp), REG_SP);
1359-
ctx->sp_offset = 0; // REG_SP now equals cfp->sp
1360-
}
1378+
jit_save_sp(jit, ctx);
13611379

13621380
yjit_save_regs(cb);
13631381

@@ -1502,6 +1520,40 @@ gen_opt_plus(jitstate_t* jit, ctx_t* ctx)
15021520
return YJIT_KEEP_COMPILING;
15031521
}
15041522

1523+
VALUE rb_vm_opt_mod(VALUE recv, VALUE obj);
1524+
1525+
static codegen_status_t
1526+
gen_opt_mod(jitstate_t* jit, ctx_t* ctx)
1527+
{
1528+
// Save the PC and SP because the callee may allocate bignums
1529+
// Note that this modifies REG_SP, which is why we do it first
1530+
jit_save_pc(jit, REG0);
1531+
jit_save_sp(jit, ctx);
1532+
1533+
uint8_t* side_exit = yjit_side_exit(jit, ctx);
1534+
1535+
// Get the operands from the stack
1536+
x86opnd_t arg1 = ctx_stack_pop(ctx, 1);
1537+
x86opnd_t arg0 = ctx_stack_pop(ctx, 1);
1538+
1539+
// Call rb_vm_opt_mod(VALUE recv, VALUE obj)
1540+
yjit_save_regs(cb);
1541+
mov(cb, C_ARG_REGS[0], arg0);
1542+
mov(cb, C_ARG_REGS[1], arg1);
1543+
call_ptr(cb, REG0, (void *)rb_vm_opt_mod);
1544+
yjit_load_regs(cb);
1545+
1546+
// If val == Qundef, bail to do a method call
1547+
cmp(cb, RAX, imm_opnd(Qundef));
1548+
je_ptr(cb, side_exit);
1549+
1550+
// Push the return value onto the stack
1551+
x86opnd_t stack_ret = ctx_stack_push(ctx, TYPE_UNKNOWN);
1552+
mov(cb, stack_ret, RAX);
1553+
1554+
return YJIT_KEEP_COMPILING;
1555+
}
1556+
15051557
void
15061558
gen_branchif_branch(codeblock_t* cb, uint8_t* target0, uint8_t* target1, uint8_t shape)
15071559
{
@@ -1802,8 +1854,7 @@ gen_send_cfunc(jitstate_t *jit, ctx_t *ctx, const struct rb_callinfo *ci, const
18021854
x86opnd_t recv = ctx_stack_opnd(ctx, argc);
18031855

18041856
// Store incremented PC into current control frame in case callee raises.
1805-
mov(cb, REG0, const_ptr_opnd(jit->pc + insn_len(jit->opcode)));
1806-
mov(cb, mem_opnd(64, REG_CFP, offsetof(rb_control_frame_t, pc)), REG0);
1857+
jit_save_pc(jit, REG0);
18071858

18081859
if (push_frame) {
18091860
if (block) {
@@ -1896,9 +1947,7 @@ gen_send_cfunc(jitstate_t *jit, ctx_t *ctx, const struct rb_callinfo *ci, const
18961947
if (block) {
18971948
// Write interpreter SP into CFP.
18981949
// Needed in case the callee yields to the block.
1899-
lea(cb, REG_SP, ctx_sp_opnd(ctx, 0));
1900-
mov(cb, member_opnd(REG_CFP, rb_control_frame_t, sp), REG_SP);
1901-
ctx->sp_offset = 0;
1950+
jit_save_sp(jit, ctx);
19021951
}
19031952

19041953
// Save YJIT registers
@@ -2074,8 +2123,7 @@ gen_send_iseq(jitstate_t *jit, ctx_t *ctx, const struct rb_callinfo *ci, const r
20742123
mov(cb, member_opnd(REG_CFP, rb_control_frame_t, sp), REG0);
20752124

20762125
// Store the next PC in the current frame
2077-
mov(cb, REG0, const_ptr_opnd(jit->pc + insn_len(jit->opcode)));
2078-
mov(cb, mem_opnd(64, REG_CFP, offsetof(rb_control_frame_t, pc)), REG0);
2126+
jit_save_pc(jit, REG0);
20792127

20802128
if (block) {
20812129
// Change cfp->block_code in the current frame. See vm_caller_setup_arg_block().
@@ -2488,6 +2536,7 @@ yjit_init_codegen(void)
24882536
yjit_reg_op(BIN(opt_or), gen_opt_or);
24892537
yjit_reg_op(BIN(opt_minus), gen_opt_minus);
24902538
yjit_reg_op(BIN(opt_plus), gen_opt_plus);
2539+
yjit_reg_op(BIN(opt_mod), gen_opt_mod);
24912540
yjit_reg_op(BIN(opt_getinlinecache), gen_opt_getinlinecache);
24922541
yjit_reg_op(BIN(branchif), gen_branchif);
24932542
yjit_reg_op(BIN(branchunless), gen_branchunless);

0 commit comments

Comments
 (0)