Skip to content

Commit 00c9a4e

Browse files
committed
Write JITFrame pointer for C frames, skip iseq/block_code writes
Instead of writing 3 fields to C frames (jit_return=0, iseq=0, block_code=0), write a single JITFrame pointer with {pc=NULL, iseq=NULL, materialize_block_code=true}. This eliminates 2 memory writes per C method call. Add rb_zjit_cfp_has_iseq() and rb_zjit_cfp_has_pc() helpers that check JITFrame first when present, since cfp->iseq and cfp->pc may be stale for frames with JITFrame. Replace all cfp->iseq || CFP_JIT_RETURN(cfp) and cfp->pc || CFP_JIT_RETURN(cfp) patterns with the new helpers.
1 parent 1ec5c20 commit 00c9a4e

File tree

7 files changed

+37
-18
lines changed

7 files changed

+37
-18
lines changed

cont.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1348,7 +1348,7 @@ rb_jit_cont_each_iseq(rb_iseq_callback callback, void *data)
13481348

13491349
const rb_control_frame_t *cfp = cont->ec->cfp;
13501350
while (!RUBY_VM_CONTROL_FRAME_STACK_OVERFLOW_P(cont->ec, cfp)) {
1351-
if ((cfp->pc || CFP_JIT_RETURN(cfp)) && (cfp->iseq || CFP_JIT_RETURN(cfp))) {
1351+
if (rb_zjit_cfp_has_pc(cfp) && rb_zjit_cfp_has_iseq(cfp)) {
13521352
const rb_iseq_t *iseq = rb_zjit_cfp_iseq(cfp);
13531353
if (iseq && imemo_type((VALUE)iseq) == imemo_iseq) {
13541354
callback(iseq, data);

gc.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1000,7 +1000,7 @@ gc_validate_pc(VALUE obj)
10001000

10011001
rb_execution_context_t *ec = GET_EC();
10021002
const rb_control_frame_t *cfp = ec->cfp;
1003-
if (cfp && VM_FRAME_RUBYFRAME_P(cfp) && (cfp->pc || CFP_JIT_RETURN(cfp))) {
1003+
if (cfp && VM_FRAME_RUBYFRAME_P(cfp) && rb_zjit_cfp_has_pc(cfp)) {
10041004
const VALUE *iseq_encoded = ISEQ_BODY(rb_zjit_cfp_iseq(cfp))->iseq_encoded;
10051005
const VALUE *iseq_encoded_end = iseq_encoded + ISEQ_BODY(rb_zjit_cfp_iseq(cfp))->iseq_size;
10061006
RUBY_ASSERT(rb_zjit_cfp_pc(cfp) >= iseq_encoded, "PC not set when allocating, breaking tracing");

vm.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -941,7 +941,7 @@ rb_control_frame_t *
941941
rb_vm_get_binding_creatable_next_cfp(const rb_execution_context_t *ec, const rb_control_frame_t *cfp)
942942
{
943943
while (!RUBY_VM_CONTROL_FRAME_STACK_OVERFLOW_P(ec, cfp)) {
944-
if (cfp->iseq || CFP_JIT_RETURN(cfp)) {
944+
if (rb_zjit_cfp_has_iseq(cfp)) {
945945
return (rb_control_frame_t *)cfp;
946946
}
947947
cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
@@ -1997,7 +1997,7 @@ rb_vm_invoke_proc_with_self(rb_execution_context_t *ec, rb_proc_t *proc, VALUE s
19971997
VALUE *
19981998
rb_vm_svar_lep(const rb_execution_context_t *ec, const rb_control_frame_t *cfp)
19991999
{
2000-
while ((cfp->pc == 0 && !CFP_JIT_RETURN(cfp)) || (cfp->iseq == 0 && !CFP_JIT_RETURN(cfp))) {
2000+
while (!rb_zjit_cfp_has_pc(cfp) || !rb_zjit_cfp_has_iseq(cfp)) {
20012001
if (VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_IFUNC) {
20022002
struct vm_ifunc *ifunc = (struct vm_ifunc *)rb_zjit_cfp_iseq(cfp);
20032003
return ifunc->svar_lep;

vm_backtrace.c

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ calc_node_id(const rb_iseq_t *iseq, const VALUE *pc)
102102
int
103103
rb_vm_get_sourceline(const rb_control_frame_t *cfp)
104104
{
105-
if (VM_FRAME_RUBYFRAME_P(cfp) && (cfp->iseq || CFP_JIT_RETURN(cfp))) {
105+
if (VM_FRAME_RUBYFRAME_P(cfp) && rb_zjit_cfp_has_iseq(cfp)) {
106106
const rb_iseq_t *iseq = rb_zjit_cfp_iseq(cfp);
107107
int line = calc_lineno(iseq, rb_zjit_cfp_pc(cfp));
108108
if (line != 0) {
@@ -688,8 +688,8 @@ rb_ec_partial_backtrace_object(const rb_execution_context_t *ec, long start_fram
688688
}
689689

690690
for (; cfp != end_cfp && (bt->backtrace_size < num_frames); cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp)) {
691-
if (cfp->iseq || CFP_JIT_RETURN(cfp)) {
692-
if (cfp->pc || CFP_JIT_RETURN(cfp)) {
691+
if (rb_zjit_cfp_has_iseq(cfp)) {
692+
if (rb_zjit_cfp_has_pc(cfp)) {
693693
if (start_frame > 0) {
694694
start_frame--;
695695
}
@@ -753,7 +753,7 @@ rb_ec_partial_backtrace_object(const rb_execution_context_t *ec, long start_fram
753753
// is the one of the caller Ruby frame, so if the last entry is a C frame we find the caller Ruby frame here.
754754
if (backpatch_counter > 0) {
755755
for (; cfp != end_cfp; cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp)) {
756-
if ((cfp->iseq || CFP_JIT_RETURN(cfp)) && (cfp->pc || CFP_JIT_RETURN(cfp)) && !(skip_internal && is_internal_location(rb_zjit_cfp_iseq(cfp)))) {
756+
if (rb_zjit_cfp_has_iseq(cfp) && rb_zjit_cfp_has_pc(cfp) && !(skip_internal && is_internal_location(rb_zjit_cfp_iseq(cfp)))) {
757757
VM_ASSERT(!skip_next_frame); // ISEQ_TYPE_RESCUE/ISEQ_TYPE_ENSURE should have a caller Ruby ISEQ, not a cfunc
758758
bt_backpatch_loc(backpatch_counter, loc, rb_zjit_cfp_iseq(cfp), rb_zjit_cfp_pc(cfp));
759759
RB_OBJ_WRITTEN(btobj, Qundef, rb_zjit_cfp_iseq(cfp));
@@ -1020,8 +1020,8 @@ backtrace_each(const rb_execution_context_t *ec,
10201020
/* SDR(); */
10211021
for (i=0, cfp = start_cfp; i<size; i++, cfp = RUBY_VM_NEXT_CONTROL_FRAME(cfp)) {
10221022
/* fprintf(stderr, "cfp: %d\n", (rb_control_frame_t *)(ec->vm_stack + ec->vm_stack_size) - cfp); */
1023-
if (cfp->iseq || CFP_JIT_RETURN(cfp)) {
1024-
if (cfp->pc || CFP_JIT_RETURN(cfp)) {
1023+
if (rb_zjit_cfp_has_iseq(cfp)) {
1024+
if (rb_zjit_cfp_has_pc(cfp)) {
10251025
iter_iseq(arg, cfp);
10261026
}
10271027
}
@@ -1747,7 +1747,7 @@ thread_profile_frames(rb_execution_context_t *ec, int start, int limit, VALUE *b
17471747
end_cfp = RUBY_VM_NEXT_CONTROL_FRAME(end_cfp);
17481748

17491749
for (i=0; i<limit && cfp != end_cfp; cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp)) {
1750-
if (VM_FRAME_RUBYFRAME_P_UNCHECKED(cfp) && (cfp->pc != 0 || CFP_JIT_RETURN(cfp))) {
1750+
if (VM_FRAME_RUBYFRAME_P_UNCHECKED(cfp) && rb_zjit_cfp_has_pc(cfp)) {
17511751
if (start > 0) {
17521752
start--;
17531753
continue;

vm_dump.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ control_frame_dump(const rb_execution_context_t *ec, const rb_control_frame_t *c
119119
selfstr = "";
120120
}
121121

122-
if (cfp->iseq || CFP_JIT_RETURN(cfp)) {
122+
if (rb_zjit_cfp_has_iseq(cfp)) {
123123
iseq = rb_zjit_cfp_iseq(cfp);
124124
#define RUBY_VM_IFUNC_P(ptr) IMEMO_TYPE_P(ptr, imemo_ifunc)
125125
if (RUBY_VM_IFUNC_P(iseq)) {
@@ -132,7 +132,7 @@ control_frame_dump(const rb_execution_context_t *ec, const rb_control_frame_t *c
132132
line = -1;
133133
}
134134
else {
135-
if (cfp->pc || CFP_JIT_RETURN(cfp)) {
135+
if (rb_zjit_cfp_has_pc(cfp)) {
136136
pc = rb_zjit_cfp_pc(cfp) - ISEQ_BODY(iseq)->iseq_encoded;
137137
iseq_name = RSTRING_PTR(ISEQ_BODY(iseq)->location.label);
138138
if (pc >= 0 && (size_t)pc <= ISEQ_BODY(iseq)->iseq_size) {
@@ -341,7 +341,7 @@ box_env_dump(const rb_execution_context_t *ec, const VALUE *env, const rb_contro
341341
break;
342342
}
343343

344-
if (cfp && (cfp->iseq != 0 || CFP_JIT_RETURN(cfp))) {
344+
if (cfp && rb_zjit_cfp_has_iseq(cfp)) {
345345
#define RUBY_VM_IFUNC_P(ptr) IMEMO_TYPE_P(ptr, imemo_ifunc)
346346
const rb_iseq_t *resolved_iseq = rb_zjit_cfp_iseq(cfp);
347347
if (RUBY_VM_IFUNC_P(resolved_iseq)) {
@@ -354,7 +354,7 @@ box_env_dump(const rb_execution_context_t *ec, const VALUE *env, const rb_contro
354354
line = -1;
355355
}
356356
else {
357-
if (cfp->pc || CFP_JIT_RETURN(cfp)) {
357+
if (rb_zjit_cfp_has_pc(cfp)) {
358358
iseq = resolved_iseq;
359359
pc = rb_zjit_cfp_pc(cfp) - ISEQ_BODY(iseq)->iseq_encoded;
360360
iseq_name = RSTRING_PTR(ISEQ_BODY(iseq)->location.label);

zjit.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,26 @@ CFP_JIT_RETURN(const rb_control_frame_t *cfp)
6767
return !!cfp->jit_return;
6868
}
6969

70+
// Returns true if cfp has an ISEQ, either directly or via JITFrame.
71+
// When JITFrame is present, it is authoritative (cfp->iseq may be stale).
72+
// C frames with JITFrame have iseq=NULL, so this returns false for them.
73+
static inline bool
74+
rb_zjit_cfp_has_iseq(const rb_control_frame_t *cfp)
75+
{
76+
if (CFP_JIT_RETURN(cfp)) return rb_zjit_jit_return_iseq(cfp->jit_return) != NULL;
77+
return !!cfp->iseq;
78+
}
79+
80+
// Returns true if cfp has a PC, either directly or via JITFrame.
81+
// When JITFrame is present, it is authoritative (cfp->pc may be stale/poisoned).
82+
// C frames with JITFrame have pc=NULL, so this returns false for them.
83+
static inline bool
84+
rb_zjit_cfp_has_pc(const rb_control_frame_t *cfp)
85+
{
86+
if (CFP_JIT_RETURN(cfp)) return rb_zjit_jit_return_pc(cfp->jit_return) != NULL;
87+
return !!cfp->pc;
88+
}
89+
7090
static inline const VALUE*
7191
rb_zjit_cfp_pc(const rb_control_frame_t *cfp)
7292
{

zjit/src/codegen.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2755,9 +2755,8 @@ fn gen_push_frame(asm: &mut Assembler, argc: usize, state: &FrameState, frame: C
27552755
}
27562756
let new_sp = asm.lea(Opnd::mem(64, SP, (ep_offset + 1) * SIZEOF_VALUE_I32));
27572757
asm.mov(cfp_opnd(RUBY_OFFSET_CFP_SP), new_sp);
2758-
asm.mov(cfp_opnd(RUBY_OFFSET_CFP_JIT_RETURN), 0.into()); // just clear a leftover on stack. TODO: make JIT frame for it
2759-
asm.mov(cfp_opnd(RUBY_OFFSET_CFP_ISEQ), 0.into()); // TODO: optimize this with JITFrame
2760-
asm.mov(cfp_opnd(RUBY_OFFSET_CFP_BLOCK_CODE), 0.into()); // TODO: optimize this with JITFrame
2758+
let jit_frame = JITFrame::new(std::ptr::null(), std::ptr::null(), true);
2759+
asm.mov(cfp_opnd(RUBY_OFFSET_CFP_JIT_RETURN), Opnd::const_ptr(jit_frame));
27612760
}
27622761

27632762
asm.mov(cfp_opnd(RUBY_OFFSET_CFP_SELF), frame.recv);

0 commit comments

Comments
 (0)