-
Notifications
You must be signed in to change notification settings - Fork 8k
Implement JIT for ZEND_FETCH_STATIC_PROP_* and improve interpretation #16157
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
Changes from 1 commit
c4995fa
cb4390d
8965fe6
8a05272
b6f7f9a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3532,7 +3532,8 @@ static zend_never_inline void zend_assign_to_property_reference_var_var(zval *co | |
OPLINE_CC EXECUTE_DATA_CC); | ||
} | ||
|
||
static zend_never_inline zend_result zend_fetch_static_property_address_ex(zval **retval, zend_property_info **prop_info, uint32_t cache_slot, int fetch_type OPLINE_DC EXECUTE_DATA_DC) { | ||
static zend_never_inline zval* zend_fetch_static_property_address_ex(zend_property_info **prop_info, uint32_t cache_slot, int fetch_type OPLINE_DC EXECUTE_DATA_DC) { | ||
zval *result; | ||
zend_string *name; | ||
zend_class_entry *ce; | ||
zend_property_info *property_info; | ||
|
@@ -3548,7 +3549,7 @@ static zend_never_inline zend_result zend_fetch_static_property_address_ex(zval | |
ce = zend_fetch_class_by_name(Z_STR_P(class_name), Z_STR_P(class_name + 1), ZEND_FETCH_CLASS_DEFAULT | ZEND_FETCH_CLASS_EXCEPTION); | ||
if (UNEXPECTED(ce == NULL)) { | ||
FREE_OP(op1_type, opline->op1.var); | ||
return FAILURE; | ||
return NULL; | ||
} | ||
if (UNEXPECTED(op1_type != IS_CONST)) { | ||
CACHE_PTR(cache_slot, ce); | ||
|
@@ -3559,21 +3560,21 @@ static zend_never_inline zend_result zend_fetch_static_property_address_ex(zval | |
ce = zend_fetch_class(NULL, opline->op2.num); | ||
if (UNEXPECTED(ce == NULL)) { | ||
FREE_OP(op1_type, opline->op1.var); | ||
return FAILURE; | ||
return NULL; | ||
} | ||
} else { | ||
ce = Z_CE_P(EX_VAR(opline->op2.var)); | ||
} | ||
if (EXPECTED(op1_type == IS_CONST) && EXPECTED(CACHED_PTR(cache_slot) == ce)) { | ||
*retval = CACHED_PTR(cache_slot + sizeof(void *)); | ||
if (EXPECTED(op1_type == IS_CONST) && EXPECTED(CACHED_PTR(cache_slot + sizeof(void *)) == ce)) { | ||
result = CACHED_PTR(cache_slot + sizeof(void *)); | ||
*prop_info = CACHED_PTR(cache_slot + sizeof(void *) * 2); | ||
return SUCCESS; | ||
return result; | ||
} | ||
} | ||
|
||
if (EXPECTED(op1_type == IS_CONST)) { | ||
name = Z_STR_P(RT_CONSTANT(opline, opline->op1)); | ||
*retval = zend_std_get_static_property_with_info(ce, name, fetch_type, &property_info); | ||
result = zend_std_get_static_property_with_info(ce, name, fetch_type, &property_info); | ||
} else { | ||
zend_string *tmp_name; | ||
zval *varname = get_zval_ptr_undef(opline->op1_type, opline->op1, BP_VAR_R); | ||
|
@@ -3586,62 +3587,109 @@ static zend_never_inline zend_result zend_fetch_static_property_address_ex(zval | |
} | ||
name = zval_get_tmp_string(varname, &tmp_name); | ||
} | ||
*retval = zend_std_get_static_property_with_info(ce, name, fetch_type, &property_info); | ||
result = zend_std_get_static_property_with_info(ce, name, fetch_type, &property_info); | ||
|
||
zend_tmp_string_release(tmp_name); | ||
|
||
FREE_OP(op1_type, opline->op1.var); | ||
} | ||
|
||
if (UNEXPECTED(*retval == NULL)) { | ||
return FAILURE; | ||
if (UNEXPECTED(result == NULL)) { | ||
return NULL; | ||
} | ||
|
||
*prop_info = property_info; | ||
|
||
if (EXPECTED(op1_type == IS_CONST) | ||
&& EXPECTED(!(property_info->ce->ce_flags & ZEND_ACC_TRAIT))) { | ||
CACHE_POLYMORPHIC_PTR(cache_slot, ce, *retval); | ||
CACHE_POLYMORPHIC_PTR(cache_slot, ce, result); | ||
CACHE_PTR(cache_slot + sizeof(void *) * 2, property_info); | ||
} | ||
|
||
return SUCCESS; | ||
return result; | ||
} | ||
|
||
|
||
static zend_always_inline zend_result zend_fetch_static_property_address(zval **retval, zend_property_info **prop_info, uint32_t cache_slot, int fetch_type, int flags OPLINE_DC EXECUTE_DATA_DC) { | ||
static zend_always_inline zval* zend_fetch_static_property_address(zend_property_info **prop_info, uint32_t cache_slot, int fetch_type, int flags OPLINE_DC EXECUTE_DATA_DC) { | ||
zval *result; | ||
zend_property_info *property_info; | ||
|
||
if (opline->op1_type == IS_CONST && (opline->op2_type == IS_CONST || (opline->op2_type == IS_UNUSED && (opline->op2.num == ZEND_FETCH_CLASS_SELF || opline->op2.num == ZEND_FETCH_CLASS_PARENT))) && EXPECTED(CACHED_PTR(cache_slot) != NULL)) { | ||
*retval = CACHED_PTR(cache_slot + sizeof(void *)); | ||
if (opline->op1_type == IS_CONST | ||
&& (opline->op2_type == IS_CONST | ||
|| (opline->op2_type == IS_UNUSED | ||
&& (opline->op2.num == ZEND_FETCH_CLASS_SELF | ||
|| opline->op2.num == ZEND_FETCH_CLASS_PARENT))) | ||
&& EXPECTED(CACHED_PTR(cache_slot + sizeof(void *)) != NULL)) { | ||
result = CACHED_PTR(cache_slot + sizeof(void *)); | ||
property_info = CACHED_PTR(cache_slot + sizeof(void *) * 2); | ||
|
||
if ((fetch_type == BP_VAR_R || fetch_type == BP_VAR_RW) | ||
&& UNEXPECTED(Z_TYPE_P(*retval) == IS_UNDEF) | ||
&& UNEXPECTED(Z_TYPE_P(result) == IS_UNDEF) | ||
&& ZEND_TYPE_IS_SET(property_info->type)) { | ||
zend_throw_error(NULL, "Typed static property %s::$%s must not be accessed before initialization", | ||
ZSTR_VAL(property_info->ce->name), | ||
zend_get_unmangled_property_name(property_info->name)); | ||
return FAILURE; | ||
return NULL; | ||
} | ||
} else { | ||
zend_result success; | ||
success = zend_fetch_static_property_address_ex(retval, &property_info, cache_slot, fetch_type OPLINE_CC EXECUTE_DATA_CC); | ||
if (UNEXPECTED(success != SUCCESS)) { | ||
return FAILURE; | ||
result = zend_fetch_static_property_address_ex(&property_info, cache_slot, fetch_type OPLINE_CC EXECUTE_DATA_CC); | ||
if (UNEXPECTED(!result)) { | ||
return NULL; | ||
} | ||
} | ||
|
||
flags &= ZEND_FETCH_OBJ_FLAGS; | ||
if (flags && ZEND_TYPE_IS_SET(property_info->type)) { | ||
zend_handle_fetch_obj_flags(NULL, *retval, NULL, property_info, flags); | ||
zend_handle_fetch_obj_flags(NULL, result, NULL, property_info, flags); | ||
} | ||
|
||
if (prop_info) { | ||
*prop_info = property_info; | ||
} | ||
|
||
return SUCCESS; | ||
return result; | ||
} | ||
|
||
ZEND_API zval* zend_fetch_static_property(zend_execute_data *ex, int fetch_type) { | ||
|
||
zval *result; | ||
zend_property_info *property_info; | ||
#if defined(ZEND_VM_FP_GLOBAL_REG) && ((ZEND_VM_KIND == ZEND_VM_KIND_CALL) || (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID)) | ||
zend_execute_data *orig_execute_data = execute_data; | ||
#else | ||
zend_execute_data *execute_data; | ||
#endif | ||
execute_data = ex; | ||
#if defined(ZEND_VM_IP_GLOBAL_REG) && ((ZEND_VM_KIND == ZEND_VM_KIND_CALL) || (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID)) | ||
const zend_op *orig_opline = opline; | ||
#else | ||
const zend_op *opline; | ||
#endif | ||
opline = execute_data->opline; | ||
|
||
uint32_t cache_slot = opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS; | ||
uint32_t flags = 0; | ||
|
||
if (fetch_type == BP_VAR_W) { | ||
flags = opline->extended_value & ZEND_FETCH_OBJ_FLAGS; | ||
} | ||
result = zend_fetch_static_property_address_ex(&property_info, cache_slot, fetch_type OPLINE_CC EXECUTE_DATA_CC); | ||
if (EXPECTED(result)) { | ||
if (flags && ZEND_TYPE_IS_SET(property_info->type)) { | ||
zend_handle_fetch_obj_flags(NULL, result, NULL, property_info, flags); | ||
} | ||
} else { | ||
result = &EG(uninitialized_zval); | ||
} | ||
|
||
#if defined(ZEND_VM_IP_GLOBAL_REG) && ((ZEND_VM_KIND == ZEND_VM_KIND_CALL) || (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID)) | ||
EX(opline) = opline; | ||
opline = orig_opline; | ||
#endif | ||
#if defined(ZEND_VM_FP_GLOBAL_REG) && ((ZEND_VM_KIND == ZEND_VM_KIND_CALL) || (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID)) | ||
execute_data = orig_execute_data; | ||
#endif | ||
|
||
return result; | ||
} | ||
|
||
ZEND_API ZEND_COLD void zend_throw_ref_type_error_type(const zend_property_info *prop1, const zend_property_info *prop2, const zval *zv) { | ||
|
Uh oh!
There was an error while loading. Please reload this page.
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.
It doesn't seem right that you add
sizeof(void *)
here.CACHE_POLYMORPHIC_PTR
takes offset 0 to thecache_slot
for ce. Theresult
is stored in offsetsizeof(void *)
instead ofce
.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.
You are right! Thanks!