зеркало из https://github.com/github/ruby.git
Make Blocks depend on BOPS
When a BOP is redefined, the BOP redefinition callback will invalidate any blocks that depend on BOPS. This allows us to eliminate runtime checks for BOP redefinition.
This commit is contained in:
Родитель
46874b8fb9
Коммит
c15a577eda
|
@ -1,3 +1,38 @@
|
|||
# BOP redefined methods work when JIT compiled
|
||||
assert_equal 'false', %q{
|
||||
def less_than x
|
||||
x < 10
|
||||
end
|
||||
|
||||
class Integer
|
||||
def < x
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
less_than 2
|
||||
less_than 2
|
||||
less_than 2
|
||||
}
|
||||
|
||||
# BOP redefinition works on Integer#<
|
||||
assert_equal 'false', %q{
|
||||
def less_than x
|
||||
x < 10
|
||||
end
|
||||
|
||||
less_than 2
|
||||
less_than 2
|
||||
|
||||
class Integer
|
||||
def < x
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
less_than 2
|
||||
}
|
||||
|
||||
# Putobject, less-than operator, fixnums
|
||||
assert_equal '2', %q{
|
||||
def check_index(index)
|
||||
|
|
|
@ -740,15 +740,9 @@ gen_fixnum_cmp(jitstate_t* jit, ctx_t* ctx, cmov_fn cmov_op)
|
|||
// Note: we generate the side-exit before popping operands from the stack
|
||||
uint8_t* side_exit = yjit_side_exit(jit, ctx);
|
||||
|
||||
// TODO: make a helper function for guarding on op-not-redefined
|
||||
// Make sure that minus isn't redefined for integers
|
||||
mov(cb, RAX, const_ptr_opnd(ruby_current_vm_ptr));
|
||||
test(
|
||||
cb,
|
||||
member_opnd_idx(RAX, rb_vm_t, redefined_flag, BOP_LT),
|
||||
imm_opnd(INTEGER_REDEFINED_OP_FLAG)
|
||||
);
|
||||
jnz_ptr(cb, side_exit);
|
||||
if (!assume_bop_not_redefined(jit->block, INTEGER_REDEFINED_OP_FLAG, BOP_LT)) {
|
||||
return YJIT_CANT_COMPILE;
|
||||
}
|
||||
|
||||
// Get the operands and destination from the stack
|
||||
int arg1_type = ctx_get_top_type(ctx);
|
||||
|
@ -821,15 +815,9 @@ gen_opt_aref(jitstate_t* jit, ctx_t* ctx)
|
|||
// Create a size-exit to fall back to the interpreter
|
||||
uint8_t* side_exit = yjit_side_exit(jit, ctx);
|
||||
|
||||
// TODO: make a helper function for guarding on op-not-redefined
|
||||
// Make sure that aref isn't redefined for arrays.
|
||||
mov(cb, RAX, const_ptr_opnd(ruby_current_vm_ptr));
|
||||
test(
|
||||
cb,
|
||||
member_opnd_idx(RAX, rb_vm_t, redefined_flag, BOP_AREF),
|
||||
imm_opnd(ARRAY_REDEFINED_OP_FLAG)
|
||||
);
|
||||
jnz_ptr(cb, side_exit);
|
||||
if (!assume_bop_not_redefined(jit->block, ARRAY_REDEFINED_OP_FLAG, BOP_AREF)) {
|
||||
return YJIT_CANT_COMPILE;
|
||||
}
|
||||
|
||||
// Pop the stack operands
|
||||
x86opnd_t idx_opnd = ctx_stack_pop(ctx, 1);
|
||||
|
@ -881,15 +869,9 @@ gen_opt_and(jitstate_t* jit, ctx_t* ctx)
|
|||
// Note: we generate the side-exit before popping operands from the stack
|
||||
uint8_t* side_exit = yjit_side_exit(jit, ctx);
|
||||
|
||||
// TODO: make a helper function for guarding on op-not-redefined
|
||||
// Make sure that plus isn't redefined for integers
|
||||
mov(cb, RAX, const_ptr_opnd(ruby_current_vm_ptr));
|
||||
test(
|
||||
cb,
|
||||
member_opnd_idx(RAX, rb_vm_t, redefined_flag, BOP_AND),
|
||||
imm_opnd(INTEGER_REDEFINED_OP_FLAG)
|
||||
);
|
||||
jnz_ptr(cb, side_exit);
|
||||
if (!assume_bop_not_redefined(jit->block, INTEGER_REDEFINED_OP_FLAG, BOP_AND)) {
|
||||
return YJIT_CANT_COMPILE;
|
||||
}
|
||||
|
||||
// Get the operands and destination from the stack
|
||||
int arg1_type = ctx_get_top_type(ctx);
|
||||
|
@ -925,15 +907,9 @@ gen_opt_minus(jitstate_t* jit, ctx_t* ctx)
|
|||
// Note: we generate the side-exit before popping operands from the stack
|
||||
uint8_t* side_exit = yjit_side_exit(jit, ctx);
|
||||
|
||||
// TODO: make a helper function for guarding on op-not-redefined
|
||||
// Make sure that minus isn't redefined for integers
|
||||
mov(cb, RAX, const_ptr_opnd(ruby_current_vm_ptr));
|
||||
test(
|
||||
cb,
|
||||
member_opnd_idx(RAX, rb_vm_t, redefined_flag, BOP_MINUS),
|
||||
imm_opnd(INTEGER_REDEFINED_OP_FLAG)
|
||||
);
|
||||
jnz_ptr(cb, side_exit);
|
||||
if (!assume_bop_not_redefined(jit->block, INTEGER_REDEFINED_OP_FLAG, BOP_MINUS)) {
|
||||
return YJIT_CANT_COMPILE;
|
||||
}
|
||||
|
||||
// Get the operands and destination from the stack
|
||||
x86opnd_t arg1 = ctx_stack_pop(ctx, 1);
|
||||
|
@ -965,15 +941,9 @@ gen_opt_plus(jitstate_t* jit, ctx_t* ctx)
|
|||
// Note: we generate the side-exit before popping operands from the stack
|
||||
uint8_t* side_exit = yjit_side_exit(jit, ctx);
|
||||
|
||||
// TODO: make a helper function for guarding on op-not-redefined
|
||||
// Make sure that plus isn't redefined for integers
|
||||
mov(cb, RAX, const_ptr_opnd(ruby_current_vm_ptr));
|
||||
test(
|
||||
cb,
|
||||
member_opnd_idx(RAX, rb_vm_t, redefined_flag, BOP_PLUS),
|
||||
imm_opnd(INTEGER_REDEFINED_OP_FLAG)
|
||||
);
|
||||
jnz_ptr(cb, side_exit);
|
||||
if (!assume_bop_not_redefined(jit->block, INTEGER_REDEFINED_OP_FLAG, BOP_PLUS)) {
|
||||
return YJIT_CANT_COMPILE;
|
||||
}
|
||||
|
||||
// Get the operands and destination from the stack
|
||||
int arg1_type = ctx_get_top_type(ctx);
|
||||
|
|
36
yjit_iface.c
36
yjit_iface.c
|
@ -174,6 +174,23 @@ add_lookup_dependency_i(st_data_t *key, st_data_t *value, st_data_t data, int ex
|
|||
return ST_CONTINUE;
|
||||
}
|
||||
|
||||
// Hash table of BOP blocks
|
||||
static st_table *blocks_assuming_bops;
|
||||
|
||||
bool
|
||||
assume_bop_not_redefined(block_t *block, int redefined_flag, enum ruby_basic_operators bop)
|
||||
{
|
||||
if (BASIC_OP_UNREDEFINED_P(bop, redefined_flag)) {
|
||||
if (blocks_assuming_bops) {
|
||||
st_insert(blocks_assuming_bops, (st_data_t)block, 0);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Remember that the currently compiling block is only valid while cme and cc are valid
|
||||
void
|
||||
assume_method_lookup_stable(const struct rb_callcache *cc, const rb_callable_method_entry_t *cme, block_t *block)
|
||||
|
@ -341,6 +358,10 @@ yjit_block_assumptions_free(block_t *block)
|
|||
if (blocks_assuming_single_ractor_mode) {
|
||||
st_delete(blocks_assuming_single_ractor_mode, &as_st_data, NULL);
|
||||
}
|
||||
|
||||
if (blocks_assuming_bops) {
|
||||
st_delete(blocks_assuming_bops, &as_st_data, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -440,13 +461,6 @@ iseq_end_index(VALUE self)
|
|||
return INT2NUM(block->end_idx);
|
||||
}
|
||||
|
||||
/* Called when a basic operation is redefined */
|
||||
void
|
||||
rb_yjit_bop_redefined(VALUE klass, const rb_method_entry_t *me, enum ruby_basic_operators bop)
|
||||
{
|
||||
//fprintf(stderr, "bop redefined\n");
|
||||
}
|
||||
|
||||
static int
|
||||
block_invalidation_iterator(st_data_t key, st_data_t value, st_data_t data) {
|
||||
block_t *block = (block_t *)key;
|
||||
|
@ -454,6 +468,13 @@ block_invalidation_iterator(st_data_t key, st_data_t value, st_data_t data) {
|
|||
return ST_CONTINUE;
|
||||
}
|
||||
|
||||
/* Called when a basic operation is redefined */
|
||||
void
|
||||
rb_yjit_bop_redefined(VALUE klass, const rb_method_entry_t *me, enum ruby_basic_operators bop)
|
||||
{
|
||||
st_foreach(blocks_assuming_bops, block_invalidation_iterator, 0);
|
||||
}
|
||||
|
||||
/* Called when the constant state changes */
|
||||
void
|
||||
rb_yjit_constant_state_changed(void)
|
||||
|
@ -782,6 +803,7 @@ rb_yjit_init(struct rb_yjit_options *options)
|
|||
|
||||
blocks_assuming_stable_global_constant_state = st_init_numtable();
|
||||
blocks_assuming_single_ractor_mode = st_init_numtable();
|
||||
blocks_assuming_bops = st_init_numtable();
|
||||
|
||||
yjit_init_core();
|
||||
yjit_init_codegen();
|
||||
|
|
|
@ -78,6 +78,7 @@ int opcode_at_pc(const rb_iseq_t *iseq, const VALUE *pc);
|
|||
void check_cfunc_dispatch(VALUE receiver, struct rb_call_data *cd, void *callee, rb_callable_method_entry_t *compile_time_cme);
|
||||
bool cfunc_needs_frame(const rb_method_cfunc_t *cfunc);
|
||||
|
||||
RBIMPL_ATTR_NODISCARD() bool assume_bop_not_redefined(block_t *block, int redefined_flag, enum ruby_basic_operators bop);
|
||||
void assume_method_lookup_stable(const struct rb_callcache *cc, const rb_callable_method_entry_t *cme, block_t* block);
|
||||
RBIMPL_ATTR_NODISCARD() bool assume_single_ractor_mode(block_t *block);
|
||||
RBIMPL_ATTR_NODISCARD() bool assume_stable_global_constant_state(block_t *block);
|
||||
|
|
Загрузка…
Ссылка в новой задаче