Skip to content

Commit 85803f5

Browse files
authored
Merge pull request #222 from jhawthorn/opt_aset
Specialize opt_aset based on received types
2 parents 6b820c1 + f92e09e commit 85803f5

File tree

3 files changed

+75
-27
lines changed

3 files changed

+75
-27
lines changed

test/ruby/test_yjit.rb

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,13 @@ def test_compile_tostring
158158
assert_no_exits('"i am a string #{true}"')
159159
end
160160

161+
def test_compile_opt_aset
162+
assert_compiles('[1,2,3][2] = 4', insns: %i[opt_aset])
163+
assert_compiles('{}[:foo] = :bar', insns: %i[opt_aset])
164+
assert_compiles('[1,2,3][0..-1] = []', insns: %i[opt_aset])
165+
assert_compiles('"foo"[3] = "d"', insns: %i[opt_aset])
166+
end
167+
161168
def test_compile_attr_set
162169
assert_no_exits(<<~EORB)
163170
class Foo

vm_insnhelper.c

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5238,12 +5238,6 @@ vm_opt_aset(VALUE recv, VALUE obj, VALUE set)
52385238
}
52395239
}
52405240

5241-
VALUE
5242-
rb_vm_opt_aset(VALUE recv, VALUE obj, VALUE set)
5243-
{
5244-
return vm_opt_aset(recv, obj, set);
5245-
}
5246-
52475241
static VALUE
52485242
vm_opt_aref_with(VALUE recv, VALUE key)
52495243
{

yjit_codegen.c

Lines changed: 68 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2175,37 +2175,84 @@ gen_opt_aref(jitstate_t *jit, ctx_t *ctx)
21752175
}
21762176
}
21772177

2178-
VALUE rb_vm_opt_aset(VALUE recv, VALUE obj, VALUE set);
2179-
21802178
static codegen_status_t
21812179
gen_opt_aset(jitstate_t *jit, ctx_t *ctx)
21822180
{
2183-
// Save the PC and SP because the callee may allocate
2184-
// Note that this modifies REG_SP, which is why we do it first
2185-
jit_prepare_routine_call(jit, ctx, REG0);
2181+
// Defer compilation so we can specialize on a runtime `self`
2182+
if (!jit_at_current_insn(jit)) {
2183+
defer_compilation(jit->block, jit->insn_idx, ctx);
2184+
return YJIT_END_BLOCK;
2185+
}
21862186

2187-
uint8_t* side_exit = yjit_side_exit(jit, ctx);
2187+
VALUE comptime_recv = jit_peek_at_stack(jit, ctx, 2);
2188+
VALUE comptime_key = jit_peek_at_stack(jit, ctx, 1);
2189+
VALUE comptime_val = jit_peek_at_stack(jit, ctx, 0);
21882190

21892191
// Get the operands from the stack
2190-
x86opnd_t arg2 = ctx_stack_pop(ctx, 1);
2191-
x86opnd_t arg1 = ctx_stack_pop(ctx, 1);
2192-
x86opnd_t arg0 = ctx_stack_pop(ctx, 1);
2192+
x86opnd_t recv = ctx_stack_opnd(ctx, 2);
2193+
x86opnd_t key = ctx_stack_opnd(ctx, 1);
2194+
x86opnd_t val = ctx_stack_opnd(ctx, 0);
21932195

2194-
// Call rb_vm_opt_aset(VALUE recv, VALUE obj)
2195-
mov(cb, C_ARG_REGS[0], arg0);
2196-
mov(cb, C_ARG_REGS[1], arg1);
2197-
mov(cb, C_ARG_REGS[2], arg2);
2198-
call_ptr(cb, REG0, (void *)rb_vm_opt_aset);
2196+
if (CLASS_OF(comptime_recv) == rb_cArray && FIXNUM_P(comptime_val)) {
2197+
uint8_t* side_exit = yjit_side_exit(jit, ctx);
21992198

2200-
// If val == Qundef, bail to do a method call
2201-
cmp(cb, RAX, imm_opnd(Qundef));
2202-
je_ptr(cb, side_exit);
2199+
// Guard receiver is an Array
2200+
mov(cb, REG0, recv);
2201+
jit_guard_known_klass(jit, ctx, rb_cArray, OPND_STACK(2), comptime_recv, SEND_MAX_DEPTH, side_exit);
22032202

2204-
// Push the return value onto the stack
2205-
x86opnd_t stack_ret = ctx_stack_push(ctx, TYPE_UNKNOWN);
2206-
mov(cb, stack_ret, RAX);
2203+
// Guard key is a fixnum
2204+
mov(cb, REG0, key);
2205+
jit_guard_known_klass(jit, ctx, rb_cInteger, OPND_STACK(1), comptime_key, SEND_MAX_DEPTH, side_exit);
22072206

2208-
return YJIT_KEEP_COMPILING;
2207+
// Call rb_ary_store
2208+
mov(cb, C_ARG_REGS[0], recv);
2209+
mov(cb, C_ARG_REGS[1], key);
2210+
sar(cb, C_ARG_REGS[1], imm_opnd(1)); // FIX2LONG(key)
2211+
mov(cb, C_ARG_REGS[2], val);
2212+
2213+
// We might allocate or raise
2214+
jit_prepare_routine_call(jit, ctx, REG0);
2215+
2216+
call_ptr(cb, REG0, (void *)rb_ary_store);
2217+
2218+
// rb_ary_store returns void
2219+
// stored value should still be on stack
2220+
mov(cb, REG0, ctx_stack_opnd(ctx, 0));
2221+
2222+
// Push the return value onto the stack
2223+
ctx_stack_pop(ctx, 3);
2224+
x86opnd_t stack_ret = ctx_stack_push(ctx, TYPE_UNKNOWN);
2225+
mov(cb, stack_ret, REG0);
2226+
2227+
jit_jump_to_next_insn(jit, ctx);
2228+
return YJIT_END_BLOCK;
2229+
} else if (CLASS_OF(comptime_recv) == rb_cHash) {
2230+
uint8_t* side_exit = yjit_side_exit(jit, ctx);
2231+
2232+
// Guard receiver is a Hash
2233+
mov(cb, REG0, recv);
2234+
jit_guard_known_klass(jit, ctx, rb_cHash, OPND_STACK(2), comptime_recv, SEND_MAX_DEPTH, side_exit);
2235+
2236+
// Call rb_hash_aset
2237+
mov(cb, C_ARG_REGS[0], recv);
2238+
mov(cb, C_ARG_REGS[1], key);
2239+
mov(cb, C_ARG_REGS[2], val);
2240+
2241+
// We might allocate or raise
2242+
jit_prepare_routine_call(jit, ctx, REG0);
2243+
2244+
call_ptr(cb, REG0, (void *)rb_hash_aset);
2245+
2246+
// Push the return value onto the stack
2247+
ctx_stack_pop(ctx, 3);
2248+
x86opnd_t stack_ret = ctx_stack_push(ctx, TYPE_UNKNOWN);
2249+
mov(cb, stack_ret, RAX);
2250+
2251+
jit_jump_to_next_insn(jit, ctx);
2252+
return YJIT_END_BLOCK;
2253+
} else {
2254+
return gen_opt_send_without_block(jit, ctx);
2255+
}
22092256
}
22102257

22112258
static codegen_status_t

0 commit comments

Comments
 (0)