YJIT: Cancel on-stack jit_return on invalidation (#9086)

* YJIT: Cancel on-stack jit_return on invalidation

Co-authored-by: Alan Wu <alansi.xingwu@shopify.com>

* Use RUBY_VM_CONTROL_FRAME_STACK_OVERFLOW_P

---------

Co-authored-by: Alan Wu <alansi.xingwu@shopify.com>
This commit is contained in:
Takashi Kokubun 2023-11-30 18:35:55 -08:00 committed by GitHub
parent 5888a16a12
commit ba1cdadfc8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 69 additions and 8 deletions

35
cont.c
View file

@ -1290,19 +1290,38 @@ rb_jit_cont_each_iseq(rb_iseq_callback callback, void *data)
if (cont->ec->vm_stack == NULL)
continue;
const rb_control_frame_t *cfp;
for (cfp = RUBY_VM_END_CONTROL_FRAME(cont->ec) - 1; ; cfp = RUBY_VM_NEXT_CONTROL_FRAME(cfp)) {
const rb_iseq_t *iseq;
if (cfp->pc && (iseq = cfp->iseq) != NULL && imemo_type((VALUE)iseq) == imemo_iseq) {
callback(iseq, data);
const rb_control_frame_t *cfp = cont->ec->cfp;
while (!RUBY_VM_CONTROL_FRAME_STACK_OVERFLOW_P(cont->ec, cfp)) {
if (cfp->pc && cfp->iseq && imemo_type((VALUE)cfp->iseq) == imemo_iseq) {
callback(cfp->iseq, data);
}
if (cfp == cont->ec->cfp)
break; // reached the most recent cfp
cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
}
}
}
#if USE_YJIT
// Update the jit_return of all CFPs to leave_exit unless it's leave_exception or not set.
// This prevents jit_exec_exception from jumping to the caller after invalidation.
void
rb_yjit_cancel_jit_return(void *leave_exit, void *leave_exception)
{
struct rb_jit_cont *cont;
for (cont = first_jit_cont; cont != NULL; cont = cont->next) {
if (cont->ec->vm_stack == NULL)
continue;
const rb_control_frame_t *cfp = cont->ec->cfp;
while (!RUBY_VM_CONTROL_FRAME_STACK_OVERFLOW_P(cont->ec, cfp)) {
if (cfp->jit_return && cfp->jit_return != leave_exception) {
((rb_control_frame_t *)cfp)->jit_return = leave_exit;
}
cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
}
}
}
#endif
// Finish working with jit_cont.
void
rb_jit_cont_finish(void)