-
Notifications
You must be signed in to change notification settings - Fork 7.8k
JIT: Check exception on exit #18297
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: PHP-8.4
Are you sure you want to change the base?
JIT: Check exception on exit #18297
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes sense to me. Please see my 2 minor remarks.
@@ -14476,7 +14476,7 @@ static int zend_jit_fetch_obj(zend_jit_ctx *jit, | |||
ZEND_ASSERT(end_inputs == IR_UNUSED); | |||
if ((res_info & MAY_BE_GUARD) && JIT_G(current_frame)) { | |||
uint8_t type = concrete_type(res_info); | |||
uint32_t flags = 0; | |||
uint32_t flags = ZEND_JIT_EXIT_CHECK_EXCEPTION; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can't comment on the line, but maybe it's better to change line 14484 to flags |= ZEND_JIT_EXIT_FREE_OP1;
. It doesn't matter here because you also check exceptions when OP1 needs to be freed, but it would be more "future-proof"/"semantically right".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh right, that's actually a mistake. Thank you for spotting this.
#define ZEND_JIT_EXIT_CLOSURE_CALL (1<<8) /* exit because of polymorphic INIT_DYNAMIC_CALL call */ | ||
#define ZEND_JIT_EXIT_METHOD_CALL (1<<9) /* exit because of polymorphic INIT_METHOD_CALL call */ | ||
#define ZEND_JIT_EXIT_INVALIDATE (1<<10) /* invalidate current trace */ | ||
#define ZEND_JIT_EXIT_CHECK_EXCEPTION (1<<11) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe also make sure this gets printed out in zend_jit_dump_exit_info
?
The patch looks good and I suppose it's completely right. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Everything is fine!
Fixes GH-18262. See #18262 (comment).
In
zend_jit_fetch_obj()
, we may emit a type guard (inzend_jit_guard_fetch_result_type()
) before the exception check. When an exception is throw while fetching a property and the guard fails, we ignore the exception and start side tracing. In GH-18262 an assertion fails during tracing becauseEG(exception)
is set.Here I add a new exit flag
ZEND_JIT_EXIT_CHECK_EXCEPTION
, that enables exception checking during exit/deoptimization. This seems ideal because this ensures that house keeping is done before exception handling (freeing op1), and avoids duplicating the exception check inzend_jit_fetch_obj()
. Also, it is my understanding that deoptimization is required before handling the exception in this case.We already checked for exceptions during exit/deoptimization, but only when
ZEND_JIT_EXIT_FREE_OP1
orZEND_JIT_EXIT_FREE_OP2
were set (presumably to handle exceptions thrown during dtor). Here I make it possible to request it explicitly withZEND_JIT_EXIT_CHECK_EXCEPTION
.I had to change exception checking in
zend_jit_trace_exit()
to handle two issues:1
, we were telling the caller (zend_jit_trace_exit_stub()
) to execute the original op handler ofEG(current_execute_data)->opline
, but in reality we want to executeEX(opline)
, which should beEG(exception_op)
.EX(opline)
is set to%r15
inzend_jit_trace_exit_stub()
before callingzend_jit_trace_exit()
, but this may be the address of azend_execute_data
when IP is being reused to cacheEX(call)
(which was the case here). This is usually not an issue because we overrideEX(opline)
again inzend_jit_trace_exit_stub()
, in most cases, except when checking exceptions.BTW, I think it may be possible to stop reusing IP / %r15 for holding the value of
EX(opline)
(edit: I meantEX(call)
) in the new JIT? From my understanding this was very convenient in the old JIT, but it seems unnecessary now.