summaryrefslogtreecommitdiff
path: root/yjit_codegen.c
diff options
authorAlan Wu <[email protected]>2021-09-27 14:54:09 -0400
committerAlan Wu <[email protected]>2021-10-20 18:19:41 -0400
commit5c15850ea622d8ad86fa14cb5b9ba6f03abb232e (patch)
tree73f43455c66579d555509c9d96c9868400bca19e /yjit_codegen.c
parent9dce2d51326c7db947507f32a9d33a0d22bbafbd (diff)
Use jit_guard_known_klass() for hashes in opt_aref
The old heap object check is not as efficient as the one in jit_guard_known_klass(). Also, the old code saves cfp->sp after popping the operands off the stack, which might cause the operands to be not marked by the GC in some circumstances.
Diffstat (limited to 'yjit_codegen.c')
-rw-r--r--yjit_codegen.c47
1 files changed, 16 insertions, 31 deletions
diff --git a/yjit_codegen.c b/yjit_codegen.c
index 5bf0905541..e788ac2797 100644
--- a/yjit_codegen.c
+++ b/yjit_codegen.c
@@ -2167,43 +2167,28 @@ gen_opt_aref(jitstate_t* jit, ctx_t* ctx, codeblock_t* cb)
return YJIT_CANT_COMPILE;
}
- // Pop the stack operands
- x86opnd_t idx_opnd = ctx_stack_pop(ctx, 1);
- x86opnd_t recv_opnd = ctx_stack_pop(ctx, 1);
- mov(cb, REG0, recv_opnd);
+ x86opnd_t key_opnd = ctx_stack_opnd(ctx, 0);
+ x86opnd_t recv_opnd = ctx_stack_opnd(ctx, 1);
- // if (SPECIAL_CONST_P(recv)) {
- // Bail if receiver is not a heap object
- test(cb, REG0, imm_opnd(RUBY_IMMEDIATE_MASK));
- jnz_ptr(cb, side_exit);
- cmp(cb, REG0, imm_opnd(Qfalse));
- je_ptr(cb, side_exit);
- cmp(cb, REG0, imm_opnd(Qnil));
- je_ptr(cb, side_exit);
+ // Guard that the receiver is a hash
+ mov(cb, REG0, recv_opnd);
+ jit_guard_known_klass(jit, ctx, rb_cHash, OPND_STACK(1), comptime_recv, OPT_AREF_MAX_CHAIN_DEPTH, side_exit);
- // Bail if recv has a class other than ::Hash.
- // BOP_AREF check above is only good for ::Hash.
- mov(cb, REG1, mem_opnd(64, REG0, offsetof(struct RBasic, klass)));
- mov(cb, REG0, const_ptr_opnd((void *)rb_cHash));
- cmp(cb, REG0, REG1);
- jit_chain_guard(JCC_JNE, jit, &starting_context, OPT_AREF_MAX_CHAIN_DEPTH, side_exit);
+ // Setup arguments for rb_hash_aref().
+ mov(cb, C_ARG_REGS[0], REG0);
+ mov(cb, C_ARG_REGS[1], key_opnd);
- // Call VALUE rb_hash_aref(VALUE hash, VALUE key).
- {
- // About to change REG_SP which these operands depend on. Yikes.
- mov(cb, C_ARG_REGS[0], recv_opnd);
- mov(cb, C_ARG_REGS[1], idx_opnd);
+ // Prepare to call rb_hash_aref(). It might call #hash on the key.
+ jit_prepare_routine_call(jit, ctx, REG0);
- // Write incremented pc to cfp->pc as the routine can raise and allocate
- // Write sp to cfp->sp since rb_hash_aref might need to call #hash on the key
- jit_prepare_routine_call(jit, ctx, REG0);
+ call_ptr(cb, REG0, (void *)rb_hash_aref);
- call_ptr(cb, REG0, (void *)rb_hash_aref);
+ // Pop the key and the reciever
+ (void)ctx_stack_pop(ctx, 2);
- // Push the return value onto the stack
- x86opnd_t stack_ret = ctx_stack_push(ctx, TYPE_UNKNOWN);
- mov(cb, stack_ret, RAX);
- }
+ // Push the return value onto the stack
+ x86opnd_t stack_ret = ctx_stack_push(ctx, TYPE_UNKNOWN);
+ mov(cb, stack_ret, RAX);
// Jump to next instruction. This allows guard chains to share the same successor.
jit_jump_to_next_insn(jit, ctx);