Skip to content

Commit 5807bf6

Browse files
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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy