Make sure that there is always an index table entry for getivars
This commit is contained in:
parent
7f2828d1c8
commit
b3e993a64b
149
yjit_codegen.c
149
yjit_codegen.c
@ -1442,82 +1442,83 @@ gen_get_ivar(jitstate_t *jit, ctx_t *ctx, const int max_chain_depth, VALUE compt
|
|||||||
struct rb_iv_index_tbl_entry *ent;
|
struct rb_iv_index_tbl_entry *ent;
|
||||||
struct st_table *iv_index_tbl = ROBJECT_IV_INDEX_TBL(comptime_receiver);
|
struct st_table *iv_index_tbl = ROBJECT_IV_INDEX_TBL(comptime_receiver);
|
||||||
|
|
||||||
// Lookup index for the ivar the instruction loads
|
// Make sure there is a mapping for this ivar in the index table
|
||||||
if (iv_index_tbl && rb_iv_index_tbl_lookup(iv_index_tbl, id, &ent)) {
|
if (!iv_index_tbl || !rb_iv_index_tbl_lookup(iv_index_tbl, id, &ent)) {
|
||||||
uint32_t ivar_index = ent->index;
|
rb_ivar_set(comptime_receiver, id, Qundef);
|
||||||
|
iv_index_tbl = ROBJECT_IV_INDEX_TBL(comptime_receiver);
|
||||||
// Pop receiver if it's on the temp stack
|
RUBY_ASSERT(iv_index_tbl && rb_iv_index_tbl_lookup(iv_index_tbl, id, &ent));
|
||||||
if (!reg0_opnd.is_self) {
|
|
||||||
(void)ctx_stack_pop(ctx, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Compile time self is embedded and the ivar index lands within the object
|
|
||||||
if (RB_FL_TEST_RAW(comptime_receiver, ROBJECT_EMBED) && ivar_index < ROBJECT_EMBED_LEN_MAX) {
|
|
||||||
// See ROBJECT_IVPTR() from include/ruby/internal/core/robject.h
|
|
||||||
|
|
||||||
// Guard that self is embedded
|
|
||||||
// TODO: BT and JC is shorter
|
|
||||||
ADD_COMMENT(cb, "guard embedded getivar");
|
|
||||||
x86opnd_t flags_opnd = member_opnd(REG0, struct RBasic, flags);
|
|
||||||
test(cb, flags_opnd, imm_opnd(ROBJECT_EMBED));
|
|
||||||
jit_chain_guard(JCC_JZ, jit, &starting_context, max_chain_depth, side_exit);
|
|
||||||
|
|
||||||
// Load the variable
|
|
||||||
x86opnd_t ivar_opnd = mem_opnd(64, REG0, offsetof(struct RObject, as.ary) + ivar_index * SIZEOF_VALUE);
|
|
||||||
mov(cb, REG1, ivar_opnd);
|
|
||||||
|
|
||||||
// Guard that the variable is not Qundef
|
|
||||||
cmp(cb, REG1, imm_opnd(Qundef));
|
|
||||||
mov(cb, REG0, imm_opnd(Qnil));
|
|
||||||
cmove(cb, REG1, REG0);
|
|
||||||
|
|
||||||
// Push the ivar on the stack
|
|
||||||
x86opnd_t out_opnd = ctx_stack_push(ctx, TYPE_UNKNOWN);
|
|
||||||
mov(cb, out_opnd, REG1);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// Compile time value is *not* embeded.
|
|
||||||
|
|
||||||
// Guard that value is *not* embedded
|
|
||||||
// See ROBJECT_IVPTR() from include/ruby/internal/core/robject.h
|
|
||||||
ADD_COMMENT(cb, "guard extended getivar");
|
|
||||||
x86opnd_t flags_opnd = member_opnd(REG0, struct RBasic, flags);
|
|
||||||
test(cb, flags_opnd, imm_opnd(ROBJECT_EMBED));
|
|
||||||
jit_chain_guard(JCC_JNZ, jit, &starting_context, max_chain_depth, side_exit);
|
|
||||||
|
|
||||||
// check that the extended table is big enough
|
|
||||||
if (ivar_index >= ROBJECT_EMBED_LEN_MAX + 1) {
|
|
||||||
// Check that the slot is inside the extended table (num_slots > index)
|
|
||||||
x86opnd_t num_slots = mem_opnd(32, REG0, offsetof(struct RObject, as.heap.numiv));
|
|
||||||
cmp(cb, num_slots, imm_opnd(ivar_index));
|
|
||||||
jle_ptr(cb, COUNTED_EXIT(side_exit, getivar_idx_out_of_range));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get a pointer to the extended table
|
|
||||||
x86opnd_t tbl_opnd = mem_opnd(64, REG0, offsetof(struct RObject, as.heap.ivptr));
|
|
||||||
mov(cb, REG0, tbl_opnd);
|
|
||||||
|
|
||||||
// Read the ivar from the extended table
|
|
||||||
x86opnd_t ivar_opnd = mem_opnd(64, REG0, sizeof(VALUE) * ivar_index);
|
|
||||||
mov(cb, REG0, ivar_opnd);
|
|
||||||
|
|
||||||
// Check that the ivar is not Qundef
|
|
||||||
cmp(cb, REG0, imm_opnd(Qundef));
|
|
||||||
mov(cb, REG1, imm_opnd(Qnil));
|
|
||||||
cmove(cb, REG0, REG1);
|
|
||||||
|
|
||||||
// Push the ivar on the stack
|
|
||||||
x86opnd_t out_opnd = ctx_stack_push(ctx, TYPE_UNKNOWN);
|
|
||||||
mov(cb, out_opnd, REG0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Jump to next instruction. This allows guard chains to share the same successor.
|
|
||||||
jit_jump_to_next_insn(jit, ctx);
|
|
||||||
return YJIT_END_BLOCK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
GEN_COUNTER_INC(cb, getivar_name_not_mapped);
|
uint32_t ivar_index = ent->index;
|
||||||
return YJIT_CANT_COMPILE;
|
|
||||||
|
// Pop receiver if it's on the temp stack
|
||||||
|
if (!reg0_opnd.is_self) {
|
||||||
|
(void)ctx_stack_pop(ctx, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compile time self is embedded and the ivar index lands within the object
|
||||||
|
if (RB_FL_TEST_RAW(comptime_receiver, ROBJECT_EMBED) && ivar_index < ROBJECT_EMBED_LEN_MAX) {
|
||||||
|
// See ROBJECT_IVPTR() from include/ruby/internal/core/robject.h
|
||||||
|
|
||||||
|
// Guard that self is embedded
|
||||||
|
// TODO: BT and JC is shorter
|
||||||
|
ADD_COMMENT(cb, "guard embedded getivar");
|
||||||
|
x86opnd_t flags_opnd = member_opnd(REG0, struct RBasic, flags);
|
||||||
|
test(cb, flags_opnd, imm_opnd(ROBJECT_EMBED));
|
||||||
|
jit_chain_guard(JCC_JZ, jit, &starting_context, max_chain_depth, side_exit);
|
||||||
|
|
||||||
|
// Load the variable
|
||||||
|
x86opnd_t ivar_opnd = mem_opnd(64, REG0, offsetof(struct RObject, as.ary) + ivar_index * SIZEOF_VALUE);
|
||||||
|
mov(cb, REG1, ivar_opnd);
|
||||||
|
|
||||||
|
// Guard that the variable is not Qundef
|
||||||
|
cmp(cb, REG1, imm_opnd(Qundef));
|
||||||
|
mov(cb, REG0, imm_opnd(Qnil));
|
||||||
|
cmove(cb, REG1, REG0);
|
||||||
|
|
||||||
|
// Push the ivar on the stack
|
||||||
|
x86opnd_t out_opnd = ctx_stack_push(ctx, TYPE_UNKNOWN);
|
||||||
|
mov(cb, out_opnd, REG1);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Compile time value is *not* embeded.
|
||||||
|
|
||||||
|
// Guard that value is *not* embedded
|
||||||
|
// See ROBJECT_IVPTR() from include/ruby/internal/core/robject.h
|
||||||
|
ADD_COMMENT(cb, "guard extended getivar");
|
||||||
|
x86opnd_t flags_opnd = member_opnd(REG0, struct RBasic, flags);
|
||||||
|
test(cb, flags_opnd, imm_opnd(ROBJECT_EMBED));
|
||||||
|
jit_chain_guard(JCC_JNZ, jit, &starting_context, max_chain_depth, side_exit);
|
||||||
|
|
||||||
|
// check that the extended table is big enough
|
||||||
|
if (ivar_index >= ROBJECT_EMBED_LEN_MAX + 1) {
|
||||||
|
// Check that the slot is inside the extended table (num_slots > index)
|
||||||
|
x86opnd_t num_slots = mem_opnd(32, REG0, offsetof(struct RObject, as.heap.numiv));
|
||||||
|
cmp(cb, num_slots, imm_opnd(ivar_index));
|
||||||
|
jle_ptr(cb, COUNTED_EXIT(side_exit, getivar_idx_out_of_range));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get a pointer to the extended table
|
||||||
|
x86opnd_t tbl_opnd = mem_opnd(64, REG0, offsetof(struct RObject, as.heap.ivptr));
|
||||||
|
mov(cb, REG0, tbl_opnd);
|
||||||
|
|
||||||
|
// Read the ivar from the extended table
|
||||||
|
x86opnd_t ivar_opnd = mem_opnd(64, REG0, sizeof(VALUE) * ivar_index);
|
||||||
|
mov(cb, REG0, ivar_opnd);
|
||||||
|
|
||||||
|
// Check that the ivar is not Qundef
|
||||||
|
cmp(cb, REG0, imm_opnd(Qundef));
|
||||||
|
mov(cb, REG1, imm_opnd(Qnil));
|
||||||
|
cmove(cb, REG0, REG1);
|
||||||
|
|
||||||
|
// Push the ivar on the stack
|
||||||
|
x86opnd_t out_opnd = ctx_stack_push(ctx, TYPE_UNKNOWN);
|
||||||
|
mov(cb, out_opnd, REG0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Jump to next instruction. This allows guard chains to share the same successor.
|
||||||
|
jit_jump_to_next_insn(jit, ctx);
|
||||||
|
return YJIT_END_BLOCK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static codegen_status_t
|
static codegen_status_t
|
||||||
|
@ -69,7 +69,6 @@ YJIT_DECLARE_COUNTERS(
|
|||||||
|
|
||||||
getivar_se_self_not_heap,
|
getivar_se_self_not_heap,
|
||||||
getivar_idx_out_of_range,
|
getivar_idx_out_of_range,
|
||||||
getivar_name_not_mapped,
|
|
||||||
|
|
||||||
setivar_se_self_not_heap,
|
setivar_se_self_not_heap,
|
||||||
setivar_idx_out_of_range,
|
setivar_idx_out_of_range,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user