Don't create a stack frame for Hash#key?
This commit is contained in:
parent
5413d0918b
commit
0c52371c47
132
ujit_compile.c
132
ujit_compile.c
@ -483,6 +483,21 @@ gen_opt_minus(codeblock_t* cb, codeblock_t* ocb, ctx_t* ctx)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MJIT_FUNC_EXPORTED VALUE rb_hash_has_key(VALUE hash, VALUE key);
|
||||||
|
|
||||||
|
bool
|
||||||
|
cfunc_needs_frame(const rb_method_cfunc_t *cfunc)
|
||||||
|
{
|
||||||
|
void* fptr = (void*)cfunc->func;
|
||||||
|
|
||||||
|
// Leaf C functions do not need a stack frame
|
||||||
|
// or a stack overflow check
|
||||||
|
return !(
|
||||||
|
// Hash#key?
|
||||||
|
fptr == (void*)rb_hash_has_key
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
gen_opt_send_without_block(codeblock_t* cb, codeblock_t* ocb, ctx_t* ctx)
|
gen_opt_send_without_block(codeblock_t* cb, codeblock_t* ocb, ctx_t* ctx)
|
||||||
{
|
{
|
||||||
@ -590,64 +605,61 @@ gen_opt_send_without_block(codeblock_t* cb, codeblock_t* ocb, ctx_t* ctx)
|
|||||||
test(cb, flags_opnd, imm_opnd(IMEMO_FL_USER5));
|
test(cb, flags_opnd, imm_opnd(IMEMO_FL_USER5));
|
||||||
jnz_ptr(cb, side_exit);
|
jnz_ptr(cb, side_exit);
|
||||||
|
|
||||||
// IDEA: stack frame setup may not be needed for some C functions
|
// If this function needs a Ruby stack frame
|
||||||
// We could profile the most called C functions and identify which are safe
|
if (cfunc_needs_frame(cfunc))
|
||||||
// This may help us eliminate stack overflow checks as well
|
{
|
||||||
|
// Stack overflow check
|
||||||
|
// #define CHECK_VM_STACK_OVERFLOW0(cfp, sp, margin)
|
||||||
|
// REG_CFP <= REG_SP + 4 * sizeof(VALUE) + sizeof(rb_control_frame_t)
|
||||||
|
lea(cb, REG0, ctx_sp_opnd(ctx, sizeof(VALUE) * 4 + sizeof(rb_control_frame_t)));
|
||||||
|
cmp(cb, REG_CFP, REG0);
|
||||||
|
jle_ptr(cb, side_exit);
|
||||||
|
|
||||||
|
// Increment the stack pointer by 3 (in the callee)
|
||||||
|
// sp += 3
|
||||||
|
lea(cb, REG0, ctx_sp_opnd(ctx, sizeof(VALUE) * 3));
|
||||||
|
|
||||||
|
// Write method entry at sp[-3]
|
||||||
|
// sp[-3] = me;
|
||||||
|
mov(cb, mem_opnd(64, REG0, 8 * -3), REG1);
|
||||||
|
|
||||||
|
// Write block handler at sp[-2]
|
||||||
|
// sp[-2] = block_handler;
|
||||||
|
mov(cb, mem_opnd(64, REG0, 8 * -2), imm_opnd(VM_BLOCK_HANDLER_NONE));
|
||||||
|
|
||||||
// Stack overflow check
|
// Write env flags at sp[-1]
|
||||||
// #define CHECK_VM_STACK_OVERFLOW0(cfp, sp, margin)
|
// sp[-1] = frame_type;
|
||||||
// REG_CFP <= REG_SP + 4 * sizeof(VALUE) + sizeof(rb_control_frame_t)
|
uint64_t frame_type = VM_FRAME_MAGIC_CFUNC | VM_FRAME_FLAG_CFRAME | VM_ENV_FLAG_LOCAL;
|
||||||
lea(cb, REG0, ctx_sp_opnd(ctx, sizeof(VALUE) * 4 + sizeof(rb_control_frame_t)));
|
mov(cb, mem_opnd(64, REG0, 8 * -1), imm_opnd(frame_type));
|
||||||
cmp(cb, REG_CFP, REG0);
|
|
||||||
jle_ptr(cb, side_exit);
|
|
||||||
|
|
||||||
// Increment the stack pointer by 3 (in the callee)
|
// Allocate a new CFP (ec->cfp--)
|
||||||
// sp += 3
|
sub(
|
||||||
lea(cb, REG0, ctx_sp_opnd(ctx, sizeof(VALUE) * 3));
|
cb,
|
||||||
|
member_opnd(REG_EC, rb_execution_context_t, cfp),
|
||||||
|
imm_opnd(sizeof(rb_control_frame_t))
|
||||||
|
);
|
||||||
|
|
||||||
// Write method entry at sp[-3]
|
// Setup the new frame
|
||||||
// sp[-3] = me;
|
// *cfp = (const struct rb_control_frame_struct) {
|
||||||
mov(cb, mem_opnd(64, REG0, 8 * -3), REG1);
|
// .pc = 0,
|
||||||
|
// .sp = sp,
|
||||||
// Write block handler at sp[-2]
|
// .iseq = 0,
|
||||||
// sp[-2] = block_handler;
|
// .self = recv,
|
||||||
mov(cb, mem_opnd(64, REG0, 8 * -2), imm_opnd(VM_BLOCK_HANDLER_NONE));
|
// .ep = sp - 1,
|
||||||
|
// .block_code = 0,
|
||||||
// Write env flags at sp[-1]
|
// .__bp__ = sp,
|
||||||
// sp[-1] = frame_type;
|
// };
|
||||||
uint64_t frame_type = VM_FRAME_MAGIC_CFUNC | VM_FRAME_FLAG_CFRAME | VM_ENV_FLAG_LOCAL;
|
mov(cb, REG1, member_opnd(REG_EC, rb_execution_context_t, cfp));
|
||||||
mov(cb, mem_opnd(64, REG0, 8 * -1), imm_opnd(frame_type));
|
mov(cb, member_opnd(REG1, rb_control_frame_t, pc), imm_opnd(0));
|
||||||
|
mov(cb, member_opnd(REG1, rb_control_frame_t, sp), REG0);
|
||||||
// Allocate a new CFP (ec->cfp--)
|
mov(cb, member_opnd(REG1, rb_control_frame_t, iseq), imm_opnd(0));
|
||||||
sub(
|
mov(cb, member_opnd(REG1, rb_control_frame_t, block_code), imm_opnd(0));
|
||||||
cb,
|
mov(cb, member_opnd(REG1, rb_control_frame_t, __bp__), REG0);
|
||||||
member_opnd(REG_EC, rb_execution_context_t, cfp),
|
sub(cb, REG0, imm_opnd(sizeof(VALUE)));
|
||||||
imm_opnd(sizeof(rb_control_frame_t))
|
mov(cb, member_opnd(REG1, rb_control_frame_t, ep), REG0);
|
||||||
);
|
mov(cb, REG0, recv);
|
||||||
|
mov(cb, member_opnd(REG1, rb_control_frame_t, self), REG0);
|
||||||
// Setup the new frame
|
}
|
||||||
// *cfp = (const struct rb_control_frame_struct) {
|
|
||||||
// .pc = 0,
|
|
||||||
// .sp = sp,
|
|
||||||
// .iseq = 0,
|
|
||||||
// .self = recv,
|
|
||||||
// .ep = sp - 1,
|
|
||||||
// .block_code = 0,
|
|
||||||
// .__bp__ = sp,
|
|
||||||
// };
|
|
||||||
mov(cb, REG1, member_opnd(REG_EC, rb_execution_context_t, cfp));
|
|
||||||
mov(cb, member_opnd(REG1, rb_control_frame_t, pc), imm_opnd(0));
|
|
||||||
mov(cb, member_opnd(REG1, rb_control_frame_t, sp), REG0);
|
|
||||||
mov(cb, member_opnd(REG1, rb_control_frame_t, iseq), imm_opnd(0));
|
|
||||||
mov(cb, member_opnd(REG1, rb_control_frame_t, block_code), imm_opnd(0));
|
|
||||||
mov(cb, member_opnd(REG1, rb_control_frame_t, __bp__), REG0);
|
|
||||||
sub(cb, REG0, imm_opnd(sizeof(VALUE)));
|
|
||||||
mov(cb, member_opnd(REG1, rb_control_frame_t, ep), REG0);
|
|
||||||
mov(cb, REG0, recv);
|
|
||||||
mov(cb, member_opnd(REG1, rb_control_frame_t, self), REG0);
|
|
||||||
|
|
||||||
// Save the MicroJIT registers
|
// Save the MicroJIT registers
|
||||||
push(cb, REG_CFP);
|
push(cb, REG_CFP);
|
||||||
@ -693,12 +705,16 @@ gen_opt_send_without_block(codeblock_t* cb, codeblock_t* ocb, ctx_t* ctx)
|
|||||||
x86opnd_t stack_ret = ctx_stack_push(ctx, 1);
|
x86opnd_t stack_ret = ctx_stack_push(ctx, 1);
|
||||||
mov(cb, stack_ret, RAX);
|
mov(cb, stack_ret, RAX);
|
||||||
|
|
||||||
// Pop the stack frame (ec->cfp++)
|
// If this function needs a Ruby stack frame
|
||||||
add(
|
if (cfunc_needs_frame(cfunc))
|
||||||
cb,
|
{
|
||||||
member_opnd(REG_EC, rb_execution_context_t, cfp),
|
// Pop the stack frame (ec->cfp++)
|
||||||
imm_opnd(sizeof(rb_control_frame_t))
|
add(
|
||||||
);
|
cb,
|
||||||
|
member_opnd(REG_EC, rb_execution_context_t, cfp),
|
||||||
|
imm_opnd(sizeof(rb_control_frame_t))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user