Skip to content

Commit 5807bf6

Browse files
author
Noah Gibbs
authored
Port SETLOCAL opcodes (ruby#154)
1 parent cbcc27d commit 5807bf6

File tree

2 files changed

+104
-118
lines changed

2 files changed

+104
-118
lines changed

yjit/src/codegen.rs

Lines changed: 102 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -1361,7 +1361,7 @@ fn gen_newarray(jit: &mut JITState, ctx: &mut Context, cb: &mut CodeBlock, ocb:
13611361
// Save the PC and SP because we are allocating
13621362
jit_prepare_routine_call(jit, ctx, REG0);
13631363
1364-
x86opnd_t values_ptr = ctx_sp_opnd(ctx, -(sizeof(VALUE) * (uint32_t)n));
1364+
x86opnd_t values_ptr = ctx_sp_opnd(ctx, -(SIZEOF_VALUE * (uint32_t)n));
13651365
13661366
// call rb_ec_ary_new_from_values(struct rb_execution_context_struct *ec, long n, const VALUE *elts);
13671367
mov(cb, C_ARG_REGS[0], REG_EC);
@@ -1650,6 +1650,91 @@ fn gen_getlocal_wc1(jit: &mut JITState, ctx: &mut Context, cb: &mut CodeBlock, o
16501650
gen_getlocal_generic(ctx, cb, idx.as_u32(), 1)
16511651
}
16521652

1653+
fn gen_setlocal_wc0(jit: &mut JITState, ctx: &mut Context, cb: &mut CodeBlock, ocb: &mut OutlinedCb) -> CodegenStatus
1654+
{
1655+
/*
1656+
vm_env_write(const VALUE *ep, int index, VALUE v)
1657+
{
1658+
VALUE flags = ep[VM_ENV_DATA_INDEX_FLAGS];
1659+
if (LIKELY((flags & VM_ENV_FLAG_WB_REQUIRED) == 0)) {
1660+
VM_STACK_ENV_WRITE(ep, index, v);
1661+
}
1662+
else {
1663+
vm_env_write_slowpath(ep, index, v);
1664+
}
1665+
}
1666+
*/
1667+
1668+
let slot_idx = jit_get_arg(jit, 0).as_i32();
1669+
let local_idx = slot_to_local_idx(jit.get_iseq(), slot_idx) as usize;
1670+
1671+
// Load environment pointer EP (level 0) from CFP
1672+
gen_get_ep(cb, REG0, 0);
1673+
1674+
// flags & VM_ENV_FLAG_WB_REQUIRED
1675+
let flags_opnd = mem_opnd(64, REG0, SIZEOF_VALUE as i32 * VM_ENV_DATA_INDEX_FLAGS as i32);
1676+
test(cb, flags_opnd, imm_opnd(VM_ENV_FLAG_WB_REQUIRED as i64));
1677+
1678+
// Create a side-exit to fall back to the interpreter
1679+
let side_exit = get_side_exit(jit, ocb, ctx);
1680+
1681+
// if (flags & VM_ENV_FLAG_WB_REQUIRED) != 0
1682+
jnz_ptr(cb, side_exit);
1683+
1684+
// Set the type of the local variable in the context
1685+
let temp_type = ctx.get_opnd_type(InsnOpnd::StackOpnd(0));
1686+
ctx.set_local_type(local_idx, temp_type);
1687+
1688+
// Pop the value to write from the stack
1689+
let stack_top = ctx.stack_pop(1);
1690+
mov(cb, REG1, stack_top);
1691+
1692+
// Write the value at the environment pointer
1693+
let offs:i32 = -8 * slot_idx;
1694+
mov(cb, mem_opnd(64, REG0, offs), REG1);
1695+
1696+
KeepCompiling
1697+
}
1698+
1699+
fn gen_setlocal_generic(jit:&mut JITState, ctx: &mut Context, cb: &mut CodeBlock, ocb: &mut OutlinedCb, local_idx:i32, level:u32) -> CodegenStatus
1700+
{
1701+
// Load environment pointer EP at level
1702+
gen_get_ep(cb, REG0, level);
1703+
1704+
// flags & VM_ENV_FLAG_WB_REQUIRED
1705+
let flags_opnd = mem_opnd(64, REG0, SIZEOF_VALUE as i32 * VM_ENV_DATA_INDEX_FLAGS as i32);
1706+
test(cb, flags_opnd, imm_opnd(VM_ENV_FLAG_WB_REQUIRED as i64));
1707+
1708+
// Create a side-exit to fall back to the interpreter
1709+
let side_exit = get_side_exit(jit, ocb, ctx);
1710+
1711+
// if (flags & VM_ENV_FLAG_WB_REQUIRED) != 0
1712+
jnz_ptr(cb, side_exit);
1713+
1714+
// Pop the value to write from the stack
1715+
let stack_top = ctx.stack_pop(1);
1716+
mov(cb, REG1, stack_top);
1717+
1718+
// Write the value at the environment pointer
1719+
let offs = -(SIZEOF_VALUE as i32 * local_idx);
1720+
mov(cb, mem_opnd(64, REG0, offs), REG1);
1721+
1722+
KeepCompiling
1723+
}
1724+
1725+
fn gen_setlocal(jit: &mut JITState, ctx: &mut Context, cb: &mut CodeBlock, ocb: &mut OutlinedCb) -> CodegenStatus
1726+
{
1727+
let idx = jit_get_arg(jit, 0).as_i32();
1728+
let level = jit_get_arg(jit, 1).as_u32();
1729+
gen_setlocal_generic(jit, ctx, cb, ocb, idx, level)
1730+
}
1731+
1732+
fn gen_setlocal_wc1(jit: &mut JITState, ctx: &mut Context, cb: &mut CodeBlock, ocb: &mut OutlinedCb) -> CodegenStatus
1733+
{
1734+
let idx = jit_get_arg(jit, 0).as_i32();
1735+
gen_setlocal_generic(jit, ctx, cb, ocb, idx, 1)
1736+
}
1737+
16531738
/*
16541739
// new hash initialized from top N values
16551740
fn gen_newhash(jit: &mut JITState, ctx: &mut Context, cb: &mut CodeBlock, ocb: &mut OutlinedCb) -> CodegenStatus
@@ -1709,68 +1794,6 @@ fn gen_putstring(jit: &mut JITState, ctx: &mut Context, cb: &mut CodeBlock, ocb:
17091794
return YJIT_KEEP_COMPILING;
17101795
}
17111796
1712-
// Get EP at level from CFP
1713-
static void
1714-
gen_get_ep(codeblock_t *cb, x86opnd_t reg, uint32_t level)
1715-
{
1716-
// Load environment pointer EP from CFP
1717-
mov(cb, reg, member_opnd(REG_CFP, rb_control_frame_t, ep));
1718-
1719-
while (level--) {
1720-
// Get the previous EP from the current EP
1721-
// See GET_PREV_EP(ep) macro
1722-
// VALUE *prev_ep = ((VALUE *)((ep)[VM_ENV_DATA_INDEX_SPECVAL] & ~0x03))
1723-
mov(cb, reg, mem_opnd(64, REG0, SIZEOF_VALUE * VM_ENV_DATA_INDEX_SPECVAL));
1724-
and(cb, reg, imm_opnd(~0x03));
1725-
}
1726-
}
1727-
1728-
fn gen_setlocal_wc0(jit: &mut JITState, ctx: &mut Context, cb: &mut CodeBlock, ocb: &mut OutlinedCb) -> CodegenStatus
1729-
{
1730-
/*
1731-
vm_env_write(const VALUE *ep, int index, VALUE v)
1732-
{
1733-
VALUE flags = ep[VM_ENV_DATA_INDEX_FLAGS];
1734-
if (LIKELY((flags & VM_ENV_FLAG_WB_REQUIRED) == 0)) {
1735-
VM_STACK_ENV_WRITE(ep, index, v);
1736-
}
1737-
else {
1738-
vm_env_write_slowpath(ep, index, v);
1739-
}
1740-
}
1741-
*/
1742-
1743-
int32_t slot_idx = (int32_t)jit_get_arg(jit, 0);
1744-
uint32_t local_idx = slot_to_local_idx(jit->iseq, slot_idx);
1745-
1746-
// Load environment pointer EP (level 0) from CFP
1747-
gen_get_ep(cb, REG0, 0);
1748-
1749-
// flags & VM_ENV_FLAG_WB_REQUIRED
1750-
x86opnd_t flags_opnd = mem_opnd(64, REG0, sizeof(VALUE) * VM_ENV_DATA_INDEX_FLAGS);
1751-
test(cb, flags_opnd, imm_opnd(VM_ENV_FLAG_WB_REQUIRED));
1752-
1753-
// Create a side-exit to fall back to the interpreter
1754-
uint8_t *side_exit = get_side_exit(jit, ocb, ctx);
1755-
1756-
// if (flags & VM_ENV_FLAG_WB_REQUIRED) != 0
1757-
jnz_ptr(cb, side_exit);
1758-
1759-
// Set the type of the local variable in the context
1760-
val_type_t temp_type = ctx_get_opnd_type(ctx, OPND_STACK(0));
1761-
ctx_set_local_type(ctx, local_idx, temp_type);
1762-
1763-
// Pop the value to write from the stack
1764-
x86opnd_t stack_top = ctx_stack_pop(ctx, 1);
1765-
mov(cb, REG1, stack_top);
1766-
1767-
// Write the value at the environment pointer
1768-
const int32_t offs = -8 * slot_idx;
1769-
mov(cb, mem_opnd(64, REG0, offs), REG1);
1770-
1771-
return YJIT_KEEP_COMPILING;
1772-
}
1773-
17741797
// Push Qtrue or Qfalse depending on whether the given keyword was supplied by
17751798
// the caller
17761799
fn gen_checkkeyword(jit: &mut JITState, ctx: &mut Context, cb: &mut CodeBlock, ocb: &mut OutlinedCb) -> CodegenStatus
@@ -1791,7 +1814,7 @@ fn gen_checkkeyword(jit: &mut JITState, ctx: &mut Context, cb: &mut CodeBlock, o
17911814
gen_get_ep(cb, REG0, 0);
17921815
17931816
// VALUE kw_bits = *(ep - bits);
1794-
x86opnd_t bits_opnd = mem_opnd(64, REG0, sizeof(VALUE) * -bits_offset);
1817+
x86opnd_t bits_opnd = mem_opnd(64, REG0, SIZEOF_VALUE * -bits_offset);
17951818
17961819
// unsigned int b = (unsigned int)FIX2ULONG(kw_bits);
17971820
// if ((b & (0x01 << idx))) {
@@ -1809,45 +1832,6 @@ fn gen_checkkeyword(jit: &mut JITState, ctx: &mut Context, cb: &mut CodeBlock, o
18091832
return YJIT_KEEP_COMPILING;
18101833
}
18111834
1812-
fn gen_setlocal_generic(jitstate_t *jit, ctx_t *ctx, uint32_t local_idx, uint32_t level)
1813-
{
1814-
// Load environment pointer EP at level
1815-
gen_get_ep(cb, REG0, level);
1816-
1817-
// flags & VM_ENV_FLAG_WB_REQUIRED
1818-
x86opnd_t flags_opnd = mem_opnd(64, REG0, sizeof(VALUE) * VM_ENV_DATA_INDEX_FLAGS);
1819-
test(cb, flags_opnd, imm_opnd(VM_ENV_FLAG_WB_REQUIRED));
1820-
1821-
// Create a side-exit to fall back to the interpreter
1822-
uint8_t *side_exit = get_side_exit(jit, ocb, ctx);
1823-
1824-
// if (flags & VM_ENV_FLAG_WB_REQUIRED) != 0
1825-
jnz_ptr(cb, side_exit);
1826-
1827-
// Pop the value to write from the stack
1828-
x86opnd_t stack_top = ctx_stack_pop(ctx, 1);
1829-
mov(cb, REG1, stack_top);
1830-
1831-
// Write the value at the environment pointer
1832-
const int32_t offs = -(SIZEOF_VALUE * local_idx);
1833-
mov(cb, mem_opnd(64, REG0, offs), REG1);
1834-
1835-
return YJIT_KEEP_COMPILING;
1836-
}
1837-
1838-
fn gen_setlocal(jit: &mut JITState, ctx: &mut Context, cb: &mut CodeBlock, ocb: &mut OutlinedCb) -> CodegenStatus
1839-
{
1840-
int32_t idx = (int32_t)jit_get_arg(jit, 0);
1841-
int32_t level = (int32_t)jit_get_arg(jit, 1);
1842-
return gen_setlocal_generic(jit, ctx, idx, level);
1843-
}
1844-
1845-
fn gen_setlocal_wc1(jit: &mut JITState, ctx: &mut Context, cb: &mut CodeBlock, ocb: &mut OutlinedCb) -> CodegenStatus
1846-
{
1847-
int32_t idx = (int32_t)jit_get_arg(jit, 0);
1848-
return gen_setlocal_generic(jit, ctx, idx, 1);
1849-
}
1850-
18511835
static void
18521836
gen_jnz_to_target0(codeblock_t *cb, uint8_t *target0, uint8_t *target1, uint8_t shape)
18531837
{
@@ -2098,7 +2082,7 @@ fn gen_get_ivar(jitstate_t *jit, ctx_t *ctx, const int max_chain_depth, VALUE co
20982082
mov(cb, REG0, tbl_opnd);
20992083
21002084
// Read the ivar from the extended table
2101-
x86opnd_t ivar_opnd = mem_opnd(64, REG0, sizeof(VALUE) * ivar_index);
2085+
x86opnd_t ivar_opnd = mem_opnd(64, REG0, SIZEOF_VALUE * ivar_index);
21022086
mov(cb, REG0, ivar_opnd);
21032087
21042088
// Check that the ivar is not Qundef
@@ -2271,7 +2255,7 @@ fn gen_concatstrings(jit: &mut JITState, ctx: &mut Context, cb: &mut CodeBlock,
22712255
// Save the PC and SP because we are allocating
22722256
jit_prepare_routine_call(jit, ctx, REG0);
22732257
2274-
x86opnd_t values_ptr = ctx_sp_opnd(ctx, -(sizeof(VALUE) * (uint32_t)n));
2258+
x86opnd_t values_ptr = ctx_sp_opnd(ctx, SIZEOF_VALUE * (uint32_t)n));
22752259
22762260
// call rb_str_concat_literals(long n, const VALUE *strings);
22772261
mov(cb, C_ARG_REGS[0], imm_opnd(n));
@@ -3586,8 +3570,8 @@ fn gen_send_cfunc(jitstate_t *jit, ctx_t *ctx, const struct rb_callinfo *ci, con
35863570
35873571
// Stack overflow check
35883572
// #define CHECK_VM_STACK_OVERFLOW0(cfp, sp, margin)
3589-
// REG_CFP <= REG_SP + 4 * sizeof(VALUE) + sizeof(rb_control_frame_t)
3590-
lea(cb, REG0, ctx_sp_opnd(ctx, sizeof(VALUE) * 4 + 2 * sizeof(rb_control_frame_t)));
3573+
// REG_CFP <= REG_SP + 4 * SIZEOF_VALUE + sizeof(rb_control_frame_t)
3574+
lea(cb, REG0, ctx_sp_opnd(ctx, SIZEOF_VALUE * 4 + 2 * sizeof(rb_control_frame_t)));
35913575
cmp(cb, REG_CFP, REG0);
35923576
jle_ptr(cb, counted_exit!(ocb, side_exit, send_se_cf_overflow));
35933577
@@ -3607,7 +3591,7 @@ fn gen_send_cfunc(jitstate_t *jit, ctx_t *ctx, const struct rb_callinfo *ci, con
36073591
36083592
// Increment the stack pointer by 3 (in the callee)
36093593
// sp += 3
3610-
lea(cb, REG0, ctx_sp_opnd(ctx, sizeof(VALUE) * 3));
3594+
lea(cb, REG0, ctx_sp_opnd(ctx, SIZEOF_VALUE * 3));
36113595
36123596
// Write method entry at sp[-3]
36133597
// sp[-3] = me;
@@ -3656,7 +3640,7 @@ fn gen_send_cfunc(jitstate_t *jit, ctx_t *ctx, const struct rb_callinfo *ci, con
36563640
mov(cb, member_opnd(REG1, rb_control_frame_t, iseq), imm_opnd(0));
36573641
mov(cb, member_opnd(REG1, rb_control_frame_t, block_code), imm_opnd(0));
36583642
mov(cb, member_opnd(REG1, rb_control_frame_t, __bp__), REG0);
3659-
sub(cb, REG0, imm_opnd(sizeof(VALUE)));
3643+
sub(cb, REG0, imm_opnd(SIZEOF_VALUE));
36603644
mov(cb, member_opnd(REG1, rb_control_frame_t, ep), REG0);
36613645
mov(cb, REG0, recv);
36623646
mov(cb, member_opnd(REG1, rb_control_frame_t, self), REG0);
@@ -3986,7 +3970,7 @@ fn gen_send_iseq(jitstate_t *jit, ctx_t *ctx, const struct rb_callinfo *ci, cons
39863970
// Note that vm_push_frame checks it against a decremented cfp, hence the multiply by 2.
39873971
// #define CHECK_VM_STACK_OVERFLOW0(cfp, sp, margin)
39883972
add_comment(cb, "stack overflow check");
3989-
lea(cb, REG0, ctx_sp_opnd(ctx, sizeof(VALUE) * (num_locals + iseq->body->stack_max) + 2 * sizeof(rb_control_frame_t)));
3973+
lea(cb, REG0, ctx_sp_opnd(ctx, SIZEOF_VALUE * (num_locals + iseq->body->stack_max) + 2 * sizeof(rb_control_frame_t)));
39903974
cmp(cb, REG_CFP, REG0);
39913975
jle_ptr(cb, counted_exit!(ocb, side_exit, send_se_cf_overflow));
39923976
@@ -4106,7 +4090,7 @@ fn gen_send_iseq(jitstate_t *jit, ctx_t *ctx, const struct rb_callinfo *ci, cons
41064090
41074091
// Store the updated SP on the current frame (pop arguments and receiver)
41084092
add_comment(cb, "store caller sp");
4109-
lea(cb, REG0, ctx_sp_opnd(ctx, sizeof(VALUE) * -(argc + 1)));
4093+
lea(cb, REG0, ctx_sp_opnd(ctx, SIZEOF_VALUE * -(argc + 1)));
41104094
mov(cb, member_opnd(REG_CFP, rb_control_frame_t, sp), REG0);
41114095
41124096
// Store the next PC in the current frame
@@ -4121,11 +4105,11 @@ fn gen_send_iseq(jitstate_t *jit, ctx_t *ctx, const struct rb_callinfo *ci, cons
41214105
}
41224106
41234107
// Adjust the callee's stack pointer
4124-
lea(cb, REG0, ctx_sp_opnd(ctx, sizeof(VALUE) * (3 + num_locals + doing_kw_call)));
4108+
lea(cb, REG0, ctx_sp_opnd(ctx, SIZEOF_VALUE * (3 + num_locals + doing_kw_call)));
41254109
41264110
// Initialize local variables to Qnil
41274111
for (int i = 0; i < num_locals; i++) {
4128-
mov(cb, mem_opnd(64, REG0, sizeof(VALUE) * (i - num_locals - 3)), imm_opnd(Qnil));
4112+
mov(cb, mem_opnd(64, REG0, SIZEOF_VALUE * (i - num_locals - 3)), imm_opnd(Qnil));
41294113
}
41304114
41314115
add_comment(cb, "push env");
@@ -4173,7 +4157,7 @@ fn gen_send_iseq(jitstate_t *jit, ctx_t *ctx, const struct rb_callinfo *ci, cons
41734157
mov(cb, REG_SP, REG0); // Switch to the callee's REG_SP
41744158
mov(cb, member_opnd(REG_CFP, rb_control_frame_t, sp), REG0);
41754159
mov(cb, member_opnd(REG_CFP, rb_control_frame_t, __bp__), REG0);
4176-
sub(cb, REG0, imm_opnd(sizeof(VALUE)));
4160+
sub(cb, REG0, imm_opnd(SIZEOF_VALUE));
41774161
mov(cb, member_opnd(REG_CFP, rb_control_frame_t, ep), REG0);
41784162
jit_mov_gc_ptr(jit, cb, REG0, (VALUE)iseq);
41794163
mov(cb, member_opnd(REG_CFP, rb_control_frame_t, iseq), REG0);
@@ -4778,7 +4762,7 @@ fn gen_toregexp(jit: &mut JITState, ctx: &mut Context, cb: &mut CodeBlock, ocb:
47784762
// raise an exception.
47794763
jit_prepare_routine_call(jit, ctx, REG0);
47804764
4781-
x86opnd_t values_ptr = ctx_sp_opnd(ctx, -(sizeof(VALUE) * (uint32_t)cnt));
4765+
x86opnd_t values_ptr = ctx_sp_opnd(ctx, -(SIZEOF_VALUE * (uint32_t)cnt));
47824766
ctx_stack_pop(ctx, cnt);
47834767
47844768
mov(cb, C_ARG_REGS[0], imm_opnd(0));
@@ -5238,6 +5222,9 @@ fn get_gen_fn(opcode: VALUE) -> Option<CodeGenFn>
52385222
OP_GETLOCAL => Some(gen_getlocal),
52395223
OP_GETLOCAL_WC_0 => Some(gen_getlocal_wc0),
52405224
OP_GETLOCAL_WC_1 => Some(gen_getlocal_wc1),
5225+
OP_SETLOCAL => Some(gen_setlocal),
5226+
OP_SETLOCAL_WC_0 => Some(gen_setlocal_wc0),
5227+
OP_SETLOCAL_WC_1 => Some(gen_setlocal_wc1),
52415228

52425229
/*
52435230
yjit_reg_op(BIN(newarray), gen_newarray);
@@ -5249,9 +5236,6 @@ fn get_gen_fn(opcode: VALUE) -> Option<CodeGenFn>
52495236
yjit_reg_op(BIN(newrange), gen_newrange);
52505237
yjit_reg_op(BIN(concatstrings), gen_concatstrings);
52515238
yjit_reg_op(BIN(putstring), gen_putstring);
5252-
yjit_reg_op(BIN(setlocal), gen_setlocal);
5253-
yjit_reg_op(BIN(setlocal_WC_0), gen_setlocal_wc0);
5254-
yjit_reg_op(BIN(setlocal_WC_1), gen_setlocal_wc1);
52555239
yjit_reg_op(BIN(getinstancevariable), gen_getinstancevariable);
52565240
yjit_reg_op(BIN(setinstancevariable), gen_setinstancevariable);
52575241
yjit_reg_op(BIN(defined), gen_defined);

yjit/src/cruby.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -309,7 +309,9 @@ pub const RUBY_IMMEDIATE_MASK:usize = 0x7;
309309
// Constants from vm_core.h
310310
pub const VM_SPECIAL_OBJECT_VMCORE:usize = 0x1;
311311
pub const VM_ENV_DATA_INDEX_SPECVAL:isize = -1;
312+
pub const VM_ENV_DATA_INDEX_FLAGS:isize = 0;
312313
pub const VM_ENV_DATA_SIZE:usize = 3;
314+
pub const VM_ENV_FLAG_WB_REQUIRED:usize = 0x008;
313315

314316
pub const SIZEOF_VALUE: usize = 8;
315317

0 commit comments

Comments
 (0)