Skip to content

Commit ff89d56

Browse files
authored
Pass reg_cfp instead of iseq to vm_search_method and related functions (ruby#16541)
Change vm_search_method_fastpath, vm_search_method, vm_method_cfunc_is, opt_equality, vm_opt_neq, vm_opt_nil_p, vm_opt_not, and vm_objtostring to take a CFP instead of an iseq. The iseq is now read lazily from reg_cfp->iseq only when the slowpath is actually needed. This is a preparatory refactoring for lightweight JIT frames where the iseq may not always be written eagerly to the CFP. ZJIT's rb_zjit_vm_search_method and rb_vm_method_cfunc_is, which are called with a compile-time iseq rather than a live CFP, now call the slowpath directly.
1 parent a3eca0c commit ff89d56

File tree

4 files changed

+45
-36
lines changed

4 files changed

+45
-36
lines changed

insns.def

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -926,7 +926,7 @@ opt_new
926926
// The bookkeeping slot should be empty.
927927
RUBY_ASSERT(TOPN(argc + 1) == Qnil);
928928

929-
if (vm_method_cfunc_is(GET_ISEQ(), cd, val, rb_class_new_instance_pass_kw)) {
929+
if (vm_method_cfunc_is(GET_CFP(), cd, val, rb_class_new_instance_pass_kw)) {
930930
RB_DEBUG_COUNTER_INC(opt_new_hit);
931931
val = rb_obj_alloc(val);
932932
TOPN(argc) = val;
@@ -947,7 +947,7 @@ objtostring
947947
// attr bool leaf = false;
948948
// attr bool zjit_profile = true;
949949
{
950-
val = vm_objtostring(GET_ISEQ(), recv, cd);
950+
val = vm_objtostring(GET_CFP(), recv, cd);
951951

952952
if (UNDEF_P(val)) {
953953
CALL_SIMPLE_METHOD();
@@ -1006,7 +1006,7 @@ opt_nil_p
10061006
(VALUE val)
10071007
// attr bool zjit_profile = true;
10081008
{
1009-
val = vm_opt_nil_p(GET_ISEQ(), cd, recv);
1009+
val = vm_opt_nil_p(GET_CFP(), cd, recv);
10101010

10111011
if (UNDEF_P(val)) {
10121012
CALL_SIMPLE_METHOD();
@@ -1435,7 +1435,7 @@ opt_eq
14351435
(VALUE val)
14361436
// attr bool zjit_profile = true;
14371437
{
1438-
val = opt_equality(GET_ISEQ(), recv, obj, cd);
1438+
val = opt_equality(GET_CFP(), recv, obj, cd);
14391439

14401440
if (UNDEF_P(val)) {
14411441
CALL_SIMPLE_METHOD();
@@ -1450,7 +1450,7 @@ opt_neq
14501450
(VALUE val)
14511451
// attr bool zjit_profile = true;
14521452
{
1453-
val = vm_opt_neq(GET_ISEQ(), cd, cd_eq, recv, obj);
1453+
val = vm_opt_neq(GET_CFP(), cd, cd_eq, recv, obj);
14541454

14551455
if (UNDEF_P(val)) {
14561456
CALL_SIMPLE_METHOD();
@@ -1672,7 +1672,7 @@ opt_not
16721672
(VALUE val)
16731673
// attr bool zjit_profile = true;
16741674
{
1675-
val = vm_opt_not(GET_ISEQ(), cd, recv);
1675+
val = vm_opt_not(GET_CFP(), cd, recv);
16761676

16771677
if (UNDEF_P(val)) {
16781678
CALL_SIMPLE_METHOD();

vm_insnhelper.c

Lines changed: 36 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -2352,9 +2352,9 @@ vm_search_method_slowpath0(VALUE cd_owner, struct rb_call_data *cd, VALUE klass)
23522352
return cc;
23532353
}
23542354

2355-
ALWAYS_INLINE(static const struct rb_callcache *vm_search_method_fastpath(VALUE cd_owner, struct rb_call_data *cd, VALUE klass));
2355+
ALWAYS_INLINE(static const struct rb_callcache *vm_search_method_fastpath(const struct rb_control_frame_struct *reg_cfp, struct rb_call_data *cd, VALUE klass));
23562356
static const struct rb_callcache *
2357-
vm_search_method_fastpath(VALUE cd_owner, struct rb_call_data *cd, VALUE klass)
2357+
vm_search_method_fastpath(const struct rb_control_frame_struct *reg_cfp, struct rb_call_data *cd, VALUE klass)
23582358
{
23592359
const struct rb_callcache *cc = cd->cc;
23602360

@@ -2376,24 +2376,28 @@ vm_search_method_fastpath(VALUE cd_owner, struct rb_call_data *cd, VALUE klass)
23762376
}
23772377
#endif
23782378

2379-
return vm_search_method_slowpath0(cd_owner, cd, klass);
2379+
return vm_search_method_slowpath0((VALUE)reg_cfp->iseq, cd, klass);
23802380
}
23812381

23822382
static const struct rb_callable_method_entry_struct *
2383-
vm_search_method(VALUE cd_owner, struct rb_call_data *cd, VALUE recv)
2383+
vm_search_method(struct rb_control_frame_struct *reg_cfp, struct rb_call_data *cd, VALUE recv)
23842384
{
23852385
VALUE klass = CLASS_OF(recv);
23862386
VM_ASSERT(klass != Qfalse);
23872387
VM_ASSERT(RBASIC_CLASS(klass) == 0 || rb_obj_is_kind_of(klass, rb_cClass));
23882388

2389-
const struct rb_callcache *cc = vm_search_method_fastpath(cd_owner, cd, klass);
2389+
const struct rb_callcache *cc = vm_search_method_fastpath(reg_cfp, cd, klass);
23902390
return vm_cc_cme(cc);
23912391
}
23922392

23932393
const struct rb_callable_method_entry_struct *
23942394
rb_zjit_vm_search_method(VALUE cd_owner, struct rb_call_data *cd, VALUE recv)
23952395
{
2396-
return vm_search_method(cd_owner, cd, recv);
2396+
// Called from ZJIT with the compile-time iseq, which may differ from
2397+
// the iseq on the current CFP. Use the slowpath to avoid stale caches.
2398+
VALUE klass = CLASS_OF(recv);
2399+
const struct rb_callcache *cc = vm_search_method_slowpath0(cd_owner, cd, klass);
2400+
return vm_cc_cme(cc);
23972401
}
23982402

23992403
#if __has_attribute(transparent_union)
@@ -2453,10 +2457,10 @@ check_method_basic_definition(const rb_callable_method_entry_t *me)
24532457
}
24542458

24552459
static inline int
2456-
vm_method_cfunc_is(const rb_iseq_t *iseq, CALL_DATA cd, VALUE recv, cfunc_type func)
2460+
vm_method_cfunc_is(struct rb_control_frame_struct *reg_cfp, CALL_DATA cd, VALUE recv, cfunc_type func)
24572461
{
2458-
VM_ASSERT(iseq != NULL);
2459-
const struct rb_callable_method_entry_struct *cme = vm_search_method((VALUE)iseq, cd, recv);
2462+
VM_ASSERT(reg_cfp != NULL);
2463+
const struct rb_callable_method_entry_struct *cme = vm_search_method(reg_cfp, cd, recv);
24602464
return check_cfunc(cme, func);
24612465
}
24622466

@@ -2469,11 +2473,16 @@ rb_zjit_cme_is_cfunc(const rb_callable_method_entry_t *me, const cfunc_type func
24692473
int
24702474
rb_vm_method_cfunc_is(const rb_iseq_t *iseq, CALL_DATA cd, VALUE recv, cfunc_type func)
24712475
{
2472-
return vm_method_cfunc_is(iseq, cd, recv, func);
2476+
// Called from ZJIT with the compile-time iseq, which may differ from
2477+
// the iseq on the current CFP. Use the slowpath to avoid stale caches.
2478+
VALUE klass = CLASS_OF(recv);
2479+
const struct rb_callcache *cc = vm_search_method_slowpath0((VALUE)iseq, cd, klass);
2480+
const struct rb_callable_method_entry_struct *cme = vm_cc_cme(cc);
2481+
return check_cfunc(cme, func);
24732482
}
24742483

24752484
#define check_cfunc(me, func) check_cfunc(me, make_cfunc_type(func))
2476-
#define vm_method_cfunc_is(iseq, cd, recv, func) vm_method_cfunc_is(iseq, cd, recv, make_cfunc_type(func))
2485+
#define vm_method_cfunc_is(reg_cfp, cd, recv, func) vm_method_cfunc_is(reg_cfp, cd, recv, make_cfunc_type(func))
24772486

24782487
#define EQ_UNREDEFINED_P(t) BASIC_OP_UNREDEFINED_P(BOP_EQ, t##_REDEFINED_OP_FLAG)
24792488

@@ -2542,14 +2551,14 @@ opt_equality_specialized(VALUE recv, VALUE obj)
25422551
}
25432552

25442553
static VALUE
2545-
opt_equality(const rb_iseq_t *cd_owner, VALUE recv, VALUE obj, CALL_DATA cd)
2554+
opt_equality(struct rb_control_frame_struct *reg_cfp, VALUE recv, VALUE obj, CALL_DATA cd)
25462555
{
2547-
VM_ASSERT(cd_owner != NULL);
2556+
VM_ASSERT(reg_cfp != NULL);
25482557

25492558
VALUE val = opt_equality_specialized(recv, obj);
25502559
if (!UNDEF_P(val)) return val;
25512560

2552-
if (!vm_method_cfunc_is(cd_owner, cd, recv, rb_obj_equal)) {
2561+
if (!vm_method_cfunc_is(reg_cfp, cd, recv, rb_obj_equal)) {
25532562
return Qundef;
25542563
}
25552564
else {
@@ -5171,7 +5180,7 @@ vm_search_super_method(const rb_control_frame_t *reg_cfp, struct rb_call_data *c
51715180
RB_OBJ_WRITE(reg_cfp->iseq, &cd->cc, cc);
51725181
}
51735182
else {
5174-
cc = vm_search_method_fastpath((VALUE)reg_cfp->iseq, cd, klass);
5183+
cc = vm_search_method_fastpath(reg_cfp, cd, klass);
51755184
const rb_callable_method_entry_t *cached_cme = vm_cc_cme(cc);
51765185

51775186
// define_method can cache for different method id
@@ -6123,7 +6132,7 @@ vm_sendish(
61236132

61246133
switch (method_explorer) {
61256134
case mexp_search_method:
6126-
calling.cc = cc = vm_search_method_fastpath((VALUE)reg_cfp->iseq, cd, CLASS_OF(recv));
6135+
calling.cc = cc = vm_search_method_fastpath(reg_cfp, cd, CLASS_OF(recv));
61276136
val = vm_cc_call(cc)(ec, GET_CFP(), &calling);
61286137
break;
61296138
case mexp_search_super:
@@ -6230,14 +6239,14 @@ VALUE rb_mod_to_s(VALUE);
62306239
VALUE rb_mod_name(VALUE);
62316240

62326241
static VALUE
6233-
vm_objtostring(const rb_iseq_t *iseq, VALUE recv, CALL_DATA cd)
6242+
vm_objtostring(struct rb_control_frame_struct *reg_cfp, VALUE recv, CALL_DATA cd)
62346243
{
62356244
int type = TYPE(recv);
62366245
if (type == T_STRING) {
62376246
return recv;
62386247
}
62396248

6240-
const struct rb_callable_method_entry_struct *cme = vm_search_method((VALUE)iseq, cd, recv);
6249+
const struct rb_callable_method_entry_struct *cme = vm_search_method(reg_cfp, cd, recv);
62416250

62426251
switch (type) {
62436252
case T_SYMBOL:
@@ -6288,9 +6297,9 @@ vm_objtostring(const rb_iseq_t *iseq, VALUE recv, CALL_DATA cd)
62886297
// ZJIT implementation is using the C function
62896298
// and needs to call a non-static function
62906299
VALUE
6291-
rb_vm_objtostring(const rb_iseq_t *iseq, VALUE recv, CALL_DATA cd)
6300+
rb_vm_objtostring(struct rb_control_frame_struct *reg_cfp, VALUE recv, CALL_DATA cd)
62926301
{
6293-
return vm_objtostring(iseq, recv, cd);
6302+
return vm_objtostring(reg_cfp, recv, cd);
62946303
}
62956304

62966305
static VALUE
@@ -6841,10 +6850,10 @@ vm_opt_mod(VALUE recv, VALUE obj)
68416850
}
68426851

68436852
static VALUE
6844-
vm_opt_neq(const rb_iseq_t *iseq, CALL_DATA cd, CALL_DATA cd_eq, VALUE recv, VALUE obj)
6853+
vm_opt_neq(struct rb_control_frame_struct *reg_cfp, CALL_DATA cd, CALL_DATA cd_eq, VALUE recv, VALUE obj)
68456854
{
6846-
if (vm_method_cfunc_is(iseq, cd, recv, rb_obj_not_equal)) {
6847-
VALUE val = opt_equality(iseq, recv, obj, cd_eq);
6855+
if (vm_method_cfunc_is(reg_cfp, cd, recv, rb_obj_not_equal)) {
6856+
VALUE val = opt_equality(reg_cfp, recv, obj, cd_eq);
68486857

68496858
if (!UNDEF_P(val)) {
68506859
return RBOOL(!RTEST(val));
@@ -7096,13 +7105,13 @@ vm_opt_empty_p(VALUE recv)
70967105
VALUE rb_false(VALUE obj);
70977106

70987107
static VALUE
7099-
vm_opt_nil_p(const rb_iseq_t *iseq, CALL_DATA cd, VALUE recv)
7108+
vm_opt_nil_p(struct rb_control_frame_struct *reg_cfp, CALL_DATA cd, VALUE recv)
71007109
{
71017110
if (NIL_P(recv) &&
71027111
BASIC_OP_UNREDEFINED_P(BOP_NIL_P, NIL_REDEFINED_OP_FLAG)) {
71037112
return Qtrue;
71047113
}
7105-
else if (vm_method_cfunc_is(iseq, cd, recv, rb_false)) {
7114+
else if (vm_method_cfunc_is(reg_cfp, cd, recv, rb_false)) {
71067115
return Qfalse;
71077116
}
71087117
else {
@@ -7158,9 +7167,9 @@ vm_opt_succ(VALUE recv)
71587167
}
71597168

71607169
static VALUE
7161-
vm_opt_not(const rb_iseq_t *iseq, CALL_DATA cd, VALUE recv)
7170+
vm_opt_not(struct rb_control_frame_struct *reg_cfp, CALL_DATA cd, VALUE recv)
71627171
{
7163-
if (vm_method_cfunc_is(iseq, cd, recv, rb_obj_not)) {
7172+
if (vm_method_cfunc_is(reg_cfp, cd, recv, rb_obj_not)) {
71647173
return RBOOL(!RTEST(recv));
71657174
}
71667175
else {

zjit/src/codegen.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -742,8 +742,8 @@ fn gen_get_ep(asm: &mut Assembler, level: u32) -> Opnd {
742742
fn gen_objtostring(jit: &mut JITState, asm: &mut Assembler, val: Opnd, cd: *const rb_call_data, state: &FrameState) -> Opnd {
743743
gen_prepare_non_leaf_call(jit, asm, state);
744744
// TODO: Specialize for immediate types
745-
// Call rb_vm_objtostring(iseq, recv, cd)
746-
let ret = asm_ccall!(asm, rb_vm_objtostring, VALUE::from(jit.iseq).into(), val, Opnd::const_ptr(cd));
745+
// Call rb_vm_objtostring(cfp, recv, cd)
746+
let ret = asm_ccall!(asm, rb_vm_objtostring, CFP, val, Opnd::const_ptr(cd));
747747

748748
// TODO: Call `to_s` on the receiver if rb_vm_objtostring returns Qundef
749749
// Need to replicate what CALL_SIMPLE_METHOD does

zjit/src/cruby.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ unsafe extern "C" {
165165
pub fn rb_vm_stack_canary() -> VALUE;
166166
pub fn rb_vm_push_cfunc_frame(cme: *const rb_callable_method_entry_t, recv_idx: c_int);
167167
pub fn rb_obj_class(klass: VALUE) -> VALUE;
168-
pub fn rb_vm_objtostring(iseq: IseqPtr, recv: VALUE, cd: *const rb_call_data) -> VALUE;
168+
pub fn rb_vm_objtostring(reg_cfp: CfpPtr, recv: VALUE, cd: *const rb_call_data) -> VALUE;
169169
}
170170

171171
// Renames

0 commit comments

Comments
 (0)