Skip to content

Commit 217583e

Browse files
authored
Merge pull request #229 from jhawthorn/setlocal_generic
Implement generic setlocal
2 parents 76c97c7 + 3298ef9 commit 217583e

File tree

2 files changed

+79
-14
lines changed

2 files changed

+79
-14
lines changed

test/ruby/test_yjit.rb

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,20 @@ def foo(foo, bar)
197197
RUBY
198198
end
199199

200+
def test_setlocal_with_level
201+
assert_no_exits(<<~RUBY)
202+
def sum(arr)
203+
sum = 0
204+
arr.each do |x|
205+
sum += x
206+
end
207+
sum
208+
end
209+
210+
sum([1,2,3])
211+
RUBY
212+
end
213+
200214
def test_string_then_nil
201215
assert_compiles(<<~RUBY, insns: %i[opt_nil_p], result: true)
202216
def foo(val)

yjit_codegen.c

Lines changed: 65 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1193,6 +1193,22 @@ gen_putspecialobject(jitstate_t* jit, ctx_t* ctx)
11931193
}
11941194
}
11951195

1196+
// Get EP at level from CFP
1197+
static void
1198+
gen_get_ep(codeblock_t *cb, x86opnd_t reg, uint32_t level)
1199+
{
1200+
// Load environment pointer EP from CFP
1201+
mov(cb, reg, member_opnd(REG_CFP, rb_control_frame_t, ep));
1202+
1203+
while (level--) {
1204+
// Get the previous EP from the current EP
1205+
// See GET_PREV_EP(ep) macro
1206+
// VALUE* prev_ep = ((VALUE *)((ep)[VM_ENV_DATA_INDEX_SPECVAL] & ~0x03))
1207+
mov(cb, reg, mem_opnd(64, REG0, SIZEOF_VALUE * VM_ENV_DATA_INDEX_SPECVAL));
1208+
and(cb, reg, imm_opnd(~0x03));
1209+
}
1210+
}
1211+
11961212
// Compute the index of a local variable from its slot index
11971213
static uint32_t
11981214
slot_to_local_idx(const rb_iseq_t *iseq, int32_t slot_idx)
@@ -1213,8 +1229,8 @@ gen_getlocal_wc0(jitstate_t* jit, ctx_t* ctx)
12131229
const int32_t offs = -(SIZEOF_VALUE * slot_idx);
12141230
uint32_t local_idx = slot_to_local_idx(jit->iseq, slot_idx);
12151231

1216-
// Load environment pointer EP from CFP
1217-
mov(cb, REG0, member_opnd(REG_CFP, rb_control_frame_t, ep));
1232+
// Load environment pointer EP (level 0) from CFP
1233+
gen_get_ep(cb, REG0, 0);
12181234

12191235
// Load the local from the EP
12201236
mov(cb, REG0, mem_opnd(64, REG0, offs));
@@ -1229,16 +1245,7 @@ gen_getlocal_wc0(jitstate_t* jit, ctx_t* ctx)
12291245
static codegen_status_t
12301246
gen_getlocal_generic(ctx_t* ctx, uint32_t local_idx, uint32_t level)
12311247
{
1232-
// Load environment pointer EP from CFP
1233-
mov(cb, REG0, member_opnd(REG_CFP, rb_control_frame_t, ep));
1234-
1235-
while (level--) {
1236-
// Get the previous EP from the current EP
1237-
// See GET_PREV_EP(ep) macro
1238-
// VALUE* prev_ep = ((VALUE *)((ep)[VM_ENV_DATA_INDEX_SPECVAL] & ~0x03))
1239-
mov(cb, REG0, mem_opnd(64, REG0, SIZEOF_VALUE * VM_ENV_DATA_INDEX_SPECVAL));
1240-
and(cb, REG0, imm_opnd(~0x03));
1241-
}
1248+
gen_get_ep(cb, REG0, level);
12421249

12431250
// Load the local from the block
12441251
// val = *(vm_get_ep(GET_EP(), level) - idx);
@@ -1286,8 +1293,8 @@ gen_setlocal_wc0(jitstate_t* jit, ctx_t* ctx)
12861293
int32_t slot_idx = (int32_t)jit_get_arg(jit, 0);
12871294
uint32_t local_idx = slot_to_local_idx(jit->iseq, slot_idx);
12881295

1289-
// Load environment pointer EP from CFP
1290-
mov(cb, REG0, member_opnd(REG_CFP, rb_control_frame_t, ep));
1296+
// Load environment pointer EP (level 0) from CFP
1297+
gen_get_ep(cb, REG0, 0);
12911298

12921299
// flags & VM_ENV_FLAG_WB_REQUIRED
12931300
x86opnd_t flags_opnd = mem_opnd(64, REG0, sizeof(VALUE) * VM_ENV_DATA_INDEX_FLAGS);
@@ -1314,6 +1321,48 @@ gen_setlocal_wc0(jitstate_t* jit, ctx_t* ctx)
13141321
return YJIT_KEEP_COMPILING;
13151322
}
13161323

1324+
static codegen_status_t
1325+
gen_setlocal_generic(jitstate_t *jit, ctx_t* ctx, uint32_t local_idx, uint32_t level)
1326+
{
1327+
// Load environment pointer EP at level
1328+
gen_get_ep(cb, REG0, level);
1329+
1330+
// flags & VM_ENV_FLAG_WB_REQUIRED
1331+
x86opnd_t flags_opnd = mem_opnd(64, REG0, sizeof(VALUE) * VM_ENV_DATA_INDEX_FLAGS);
1332+
test(cb, flags_opnd, imm_opnd(VM_ENV_FLAG_WB_REQUIRED));
1333+
1334+
// Create a size-exit to fall back to the interpreter
1335+
uint8_t *side_exit = yjit_side_exit(jit, ctx);
1336+
1337+
// if (flags & VM_ENV_FLAG_WB_REQUIRED) != 0
1338+
jnz_ptr(cb, side_exit);
1339+
1340+
// Pop the value to write from the stack
1341+
x86opnd_t stack_top = ctx_stack_pop(ctx, 1);
1342+
mov(cb, REG1, stack_top);
1343+
1344+
// Write the value at the environment pointer
1345+
const int32_t offs = -(SIZEOF_VALUE * local_idx);
1346+
mov(cb, mem_opnd(64, REG0, offs), REG1);
1347+
1348+
return YJIT_KEEP_COMPILING;
1349+
}
1350+
1351+
static codegen_status_t
1352+
gen_setlocal(jitstate_t* jit, ctx_t* ctx)
1353+
{
1354+
int32_t idx = (int32_t)jit_get_arg(jit, 0);
1355+
int32_t level = (int32_t)jit_get_arg(jit, 1);
1356+
return gen_setlocal_generic(jit, ctx, idx, level);
1357+
}
1358+
1359+
static codegen_status_t
1360+
gen_setlocal_wc1(jitstate_t* jit, ctx_t* ctx)
1361+
{
1362+
int32_t idx = (int32_t)jit_get_arg(jit, 0);
1363+
return gen_setlocal_generic(jit, ctx, idx, 1);
1364+
}
1365+
13171366
// Check that `self` is a pointer to an object on the GC heap
13181367
static void
13191368
guard_self_is_heap(codeblock_t *cb, x86opnd_t self_opnd, uint8_t *side_exit, ctx_t *ctx)
@@ -4305,7 +4354,9 @@ yjit_init_codegen(void)
43054354
yjit_reg_op(BIN(getlocal), gen_getlocal);
43064355
yjit_reg_op(BIN(getlocal_WC_0), gen_getlocal_wc0);
43074356
yjit_reg_op(BIN(getlocal_WC_1), gen_getlocal_wc1);
4357+
yjit_reg_op(BIN(setlocal), gen_setlocal);
43084358
yjit_reg_op(BIN(setlocal_WC_0), gen_setlocal_wc0);
4359+
yjit_reg_op(BIN(setlocal_WC_1), gen_setlocal_wc1);
43094360
yjit_reg_op(BIN(getinstancevariable), gen_getinstancevariable);
43104361
yjit_reg_op(BIN(setinstancevariable), gen_setinstancevariable);
43114362
yjit_reg_op(BIN(defined), gen_defined);

0 commit comments

Comments
 (0)