8000 Merge pull request #72 from Shopify/bop-dependencies · jamatthews/ruby@ec0e606 · GitHub
[go: up one dir, main page]

Skip to content

Commit ec0e606

Browse files
authored
Merge pull request ruby#72 from Shopify/bop-dependencies
Make Blocks depend on BOPS
2 parents faef554 + 737a163 commit ec0e606

File tree

5 files changed

+89
-71
lines changed

5 files changed

+89
-71
lines changed

bootstraptest/test_yjit.rb

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,38 @@
1+
# BOP redefined methods work when JIT compiled
2+
assert_equal 'false', %q{
3+
def less_than x
4+
x < 10
5+
end
6+
7+
class Integer
8+
def < x
9+
false
10+
end
11+
end
12+
13+
less_than 2
14+
less_than 2
15+
less_than 2
16+
}
17+
18+
# BOP redefinition works on Integer#<
19+
assert_equal 'false', %q{
20+
def less_than x
21+
x < 10
22+
end
23+
24+
less_than 2
25+
less_than 2
26+
27+
class Integer
28+
def < x
29+
false
30+
end
31+
end
32+
33+
less_than 2
34+
}
35+
136
# Putobject, less-than operator, fixnums
237
assert_equal '2', %q{
338
def check_index(index)

yjit_codegen.c

Lines changed: 15 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -870,15 +870,9 @@ gen_fixnum_cmp(jitstate_t* jit, ctx_t* ctx, cmov_fn cmov_op)
870870
// Note: we generate the side-exit before popping operands from the stack
871871
uint8_t* side_exit = yjit_side_exit(jit, ctx);
872872

873-
// TODO: make a helper function for guarding on op-not-redefined
874-
// Make sure that minus isn't redefined for integers
875-
mov(cb, RAX, const_ptr_opnd(ruby_current_vm_ptr));
876-
test(
877-
cb,
878-
member_opnd_idx(RAX, rb_vm_t, redefined_flag, BOP_LT),
879-
imm_opnd(INTEGER_REDEFINED_OP_FLAG)
880-
);
881-
jnz_ptr(cb, side_exit);
873+
if (!assume_bop_not_redefined(jit->block, INTEGER_REDEFINED_OP_FLAG, BOP_LT)) {
874+
return YJIT_CANT_COMPILE;
875+
}
882876

883877
// Get the operands and destination from the stack
884878
int arg1_type = ctx_get_top_type(ctx);
@@ -951,15 +945,9 @@ gen_opt_aref(jitstate_t* jit, ctx_t* ctx)
951945
// Create a size-exit to fall back to the interpreter
952946
uint8_t* side_exit = yjit_side_exit(jit, ctx);
953947

954-
// TODO: make a helper function for guarding on op-not-redefined
955-
// Make sure that aref isn't redefined for arrays.
956-
mov(cb, RAX, const_ptr_opnd(ruby_current_vm_ptr));
957-
test(
958-
cb,
959-
member_opnd_idx(RAX, rb_vm_t, redefined_flag, BOP_AREF),
960-
imm_opnd(ARRAY_REDEFINED_OP_FLAG)
961-
);
962-
jnz_ptr(cb, side_exit);
948+
if (!assume_bop_not_redefined(jit->block, ARRAY_REDEFINED_OP_FLAG, BOP_AREF)) {
949+
return YJIT_CANT_COMPILE;
950+
}
963951

964952
// Pop the stack operands
965953
x86opnd_t idx_opnd = ctx_stack_pop(ctx, 1);
@@ -1011,15 +999,9 @@ gen_opt_and(jitstate_t* jit, ctx_t* ctx)
1011999
// Note: we generate the side-exit before popping operands from the stack
10121000
uint8_t* side_exit = yjit_side_exit(jit, ctx);
10131001

1014-
// TODO: make a helper function for guarding on op-not-redefined
1015-
// Make sure that plus isn't redefined for integers
1016-
mov(cb, RAX, const_ptr_opnd(ruby_current_vm_ptr));
1017-
test(
1018-
cb,
1019-
member_opnd_idx(RAX, rb_vm_t, redefined_flag, BOP_AND),
1020-
imm_opnd(INTEGER_REDEFINED_OP_FLAG)
1021-
);
1022-
jnz_ptr(cb, side_exit);
1002+
if (!assume_bop_not_redefined(jit->block, INTEGER_REDEFINED_OP_FLAG, BOP_AND)) {
1003+
return YJIT_CANT_COMPILE;
1004+
}
10231005

10241006
// Get the operands and destination from the stack
10251007
int arg1_type = ctx_get_top_type(ctx);
@@ -1055,15 +1037,9 @@ gen_opt_minus(jitstate_t* jit, ctx_t* ctx)
10551037
// Note: we generate the side-exit before popping operands from the stack
10561038
uint8_t* side_exit = yjit_side_exit(jit, ctx);
10571039

1058-
// TODO: make a helper function for guarding on op-not-redefined
1059-
// Make sure that minus isn't redefined for integers
1060-
mov(cb, RAX, const_ptr_opnd(ruby_current_vm_ptr));
1061-
test(
1062-
cb,
1063-
member_opnd_idx(RAX, rb_vm_t, redefined_flag, BOP_MINUS),
1064-
imm_opnd(INTEGER_REDEFINED_OP_FLAG)
1065-
);
1066-
jnz_ptr(cb, side_exit);
1040+
if (!assume_bop_not_redefined(jit->block, INTEGER_REDEFINED_OP_FLAG, BOP_MINUS)) {
1041+
return YJIT_CANT_COMPILE;
1042+
}
10671043

10681044
// Get the operands and destination from the stack
10691045
x86opnd_t arg1 = ctx_stack_pop(ctx, 1);
@@ -1095,15 +1071,9 @@ gen_opt_plus(jitstate_t* jit, ctx_t* ctx)
10951071
// Note: we generate the side-exit before popping operands from the stack
10961072
uint8_t* side_exit = yjit_side_exit(jit, ctx);
10971073

1098-
// TODO: make a helper function for guarding on op-not-redefined
1099-
// Make sure that plus isn't redefined for integers
1100-
mov(cb, RAX, const_ptr_opnd(ruby_current_vm_ptr));
1101-
test(
1102-
cb,
1103-
member_opnd_idx(RAX, rb_vm_t, redefined_flag, BOP_PLUS),
1104-
imm_opnd(INTEGER_REDEFINED_OP_FLAG)
1105-
);
1106-
jnz_ptr(cb, side_exit);
1074+
if (!assume_bop_not_redefined(jit->block, INTEGER_REDEFINED_OP_FLAG, BOP_PLUS)) {
1075+
return YJIT_CANT_COMPILE;
1076+
}
11071077

11081078
// Get the operands and destination from the stack
11091079
int arg1_type = ctx_get_top_type(ctx);

yjit_core.c

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
1-
#include "vm_core.h"
2-
#include "vm_callinfo.h"
3-
#include "builtin.h"
4-
#include "insns.inc"
5-
#include "insns_info.inc"
1+
#include "ruby/ruby.h"
2+
#include "internal.h"
63
#include "vm_sync.h"
4+
#include "builtin.h"
5+
76
#include "yjit_asm.h"
87
#include "yjit_utils.h"
98
#include "yjit_iface.h"

yjit_iface.c

Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
#include <assert.h>
1+
#include "ruby/ruby.h"
2+
#include "vm_core.h"
23
#include "insns.inc"
34
#include "internal.h"
4-
#include "vm_core.h"
55
#include "vm_sync.h"
66
#include "vm_callinfo.h"
77
#include "builtin.h"
@@ -174,6 +174,23 @@ add_lookup_dependency_i(st_data_t *key, st_data_t *value, st_data_t data, int ex
174174
return ST_CONTINUE;
175175
}
176176

177+
// Hash table of BOP blocks
178+
static st_table *blocks_assuming_bops;
179+
180+
bool
181+
assume_bop_not_redefined(block_t *block, int redefined_flag, enum ruby_basic_operators bop)
182+
{
183+
if (BASIC_OP_UNREDEFINED_P(bop, redefined_flag)) {
184+
if (blocks_assuming_bops) {
185+
st_insert(blocks_assuming_bops, (st_data_t)block, 0);
186+
}
187+
return true;
188+
}
189+
else {
190+
return false;
191+
}
192+
}
193+
177194
// Remember that the currently compiling block is only valid while cme and cc are valid
178195
void
179196
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)
341358
if (blocks_assuming_single_ractor_mode) {
342359
st_delete(blocks_assuming_single_ractor_mode, &as_st_data, NULL);
343360
}
361+
362+
if (blocks_assuming_bops) {
363+
st_delete(blocks_assuming_bops, &as_st_data, NULL);
364+
}
344365
}
345366

346367
void
@@ -440,20 +461,22 @@ iseq_end_index(VALUE self)
440461
return INT2NUM(block->end_idx);
441462
}
442463

443-
/* Called when a basic operation is redefined */
444-
void
445-
rb_yjit_bop_redefined(VALUE klass, const rb_method_entry_t *me, enum ruby_basic_operators bop)
446-
{
447-
//fprintf(stderr, "bop redefined\n");
448-
}
449-
450464
static int
451465
block_invalidation_iterator(st_data_t key, st_data_t value, st_data_t data) {
452466
block_t *block = (block_t *)key;
453467
invalidate_block_version(block); // Thankfully, st_table supports deleteing while iterating
454468
return ST_CONTINUE;
455469
}
456470

471+
/* Called when a basic operation is redefined */
472+
void
473+
rb_yjit_bop_redefined(VALUE klass, const rb_method_entry_t *me, enum ruby_basic_operators bop)
474+
{
475+
if (blocks_assuming_bops) {
476+
st_foreach(blocks_assuming_bops, block_invalidation_iterator, 0);
477+
}
478+
}
479+
457480
/* Called when the constant state changes */
458481
void
459482
rb_yjit_constant_state_changed(void)
@@ -787,6 +810,7 @@ rb_yjit_init(struct rb_yjit_options *options)
787810

788811
blocks_assuming_stable_global_constant_state = st_init_numtable();
789812
blocks_assuming_single_ractor_mode = st_init_numtable();
813+
blocks_assuming_bops = st_init_numtable();
790814

791815
yjit_init_core();
792816
yjit_init_codegen();

yjit_iface.h

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,10 @@
66
#ifndef YJIT_IFACE_H
77
#define YJIT_IFACE_H 1
88

9-
#include "stddef.h"
10-
#include "stdint.h"
11-
#include "stdbool.h"
12-
#include "internal.h"
13-
#include "ruby/internal/attr/nodiscard.h"
9+
#include "ruby/ruby.h"
1410
#include "vm_core.h"
15-
#include "vm_callinfo.h"
16-
#include "builtin.h"
1711
#include "yjit_core.h"
1812

19-
#ifndef rb_callcache
20-
struct rb_callcache;
21-
#define rb_callcache rb_callcache
22-
#endif
23-
2413
#define YJIT_DECLARE_COUNTERS(...) struct rb_yjit_runtime_counters { \
2514
int64_t __VA_ARGS__; \
2615
}; \
@@ -82,6 +71,7 @@ int opcode_at_pc(const rb_iseq_t *iseq, const VALUE *pc);
8271
void check_cfunc_dispatch(VALUE receiver, struct rb_call_data *cd, void *callee, rb_callable_method_entry_t *compile_time_cme);
8372
bool cfunc_needs_frame(const rb_method_cfunc_t *cfunc);
8473

74+
RBIMPL_ATTR_NODISCARD() bool assume_bop_not_redefined(block_t *block, int redefined_flag, enum ruby_basic_operators bop);
8575
void assume_method_lookup_stable(const struct rb_callcache *cc, const rb_callable_method_entry_t *cme, block_t* block);
8676
RBIMPL_ATTR_NODISCARD() bool assume_single_ractor_mode(block_t *block);
8777
RBIMPL_ATTR_NODISCARD() bool assume_stable_global_constant_state(block_t *block);

0 commit comments

Comments
 (0)
0