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)
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