mirror of
https://github.com/php/php-src.git
synced 2026-03-24 00:02:20 +01:00
Implement JIT for ZEND_FETCH_STATIC_PROP_* and improve interpretation (#16157)
* Implement JIT for ZEND_FETCH_STATIC_PROP_* and improve interpretation * Revert incorrect change * Use FASTCALL calling convention * Use EMPTY_SWITCH_DEFAULT_CASE * Move the loading of the property info into zend_jit_uninit_static_prop()
This commit is contained in:
@@ -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 *));
|
||||
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_FASTCALL 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) {
|
||||
|
||||
@@ -434,6 +434,7 @@ ZEND_API void zend_unfinished_calls_gc(zend_execute_data *execute_data, zend_exe
|
||||
ZEND_API void zend_cleanup_unfinished_execution(zend_execute_data *execute_data, uint32_t op_num, uint32_t catch_op_num);
|
||||
ZEND_API ZEND_ATTRIBUTE_DEPRECATED HashTable *zend_unfinished_execution_gc(zend_execute_data *execute_data, zend_execute_data *call, zend_get_gc_buffer *gc_buffer);
|
||||
ZEND_API HashTable *zend_unfinished_execution_gc_ex(zend_execute_data *execute_data, zend_execute_data *call, zend_get_gc_buffer *gc_buffer, bool suspended_by_yield);
|
||||
ZEND_API zval* ZEND_FASTCALL zend_fetch_static_property(zend_execute_data *ex, int fetch_type);
|
||||
|
||||
ZEND_API void zend_frameless_observed_call(zend_execute_data *execute_data);
|
||||
|
||||
|
||||
@@ -1109,7 +1109,8 @@ ZEND_VM_HANDLER(29, ZEND_ASSIGN_STATIC_PROP_OP, ANY, ANY, OP)
|
||||
|
||||
SAVE_OPLINE();
|
||||
|
||||
if (UNEXPECTED(zend_fetch_static_property_address(&prop, &prop_info, (opline+1)->extended_value, BP_VAR_RW, 0 OPLINE_CC EXECUTE_DATA_CC) != SUCCESS)) {
|
||||
prop = zend_fetch_static_property_address(&prop_info, (opline+1)->extended_value, BP_VAR_RW, 0 OPLINE_CC EXECUTE_DATA_CC);
|
||||
if (UNEXPECTED(!prop)) {
|
||||
UNDEF_RESULT();
|
||||
FREE_OP_DATA();
|
||||
HANDLE_EXCEPTION();
|
||||
@@ -1423,7 +1424,8 @@ ZEND_VM_HANDLER(38, ZEND_PRE_INC_STATIC_PROP, ANY, ANY, CACHE_SLOT)
|
||||
|
||||
SAVE_OPLINE();
|
||||
|
||||
if (zend_fetch_static_property_address(&prop, &prop_info, opline->extended_value, BP_VAR_RW, 0 OPLINE_CC EXECUTE_DATA_CC) != SUCCESS) {
|
||||
prop = zend_fetch_static_property_address(&prop_info, opline->extended_value, BP_VAR_RW, 0 OPLINE_CC EXECUTE_DATA_CC);
|
||||
if (UNEXPECTED(!prop)) {
|
||||
UNDEF_RESULT();
|
||||
HANDLE_EXCEPTION();
|
||||
}
|
||||
@@ -1449,7 +1451,8 @@ ZEND_VM_HANDLER(40, ZEND_POST_INC_STATIC_PROP, ANY, ANY, CACHE_SLOT)
|
||||
|
||||
SAVE_OPLINE();
|
||||
|
||||
if (zend_fetch_static_property_address(&prop, &prop_info, opline->extended_value, BP_VAR_RW, 0 OPLINE_CC EXECUTE_DATA_CC) != SUCCESS) {
|
||||
prop = zend_fetch_static_property_address(&prop_info, opline->extended_value, BP_VAR_RW, 0 OPLINE_CC EXECUTE_DATA_CC);
|
||||
if (UNEXPECTED(!prop)) {
|
||||
UNDEF_RESULT();
|
||||
HANDLE_EXCEPTION();
|
||||
}
|
||||
@@ -1829,14 +1832,17 @@ ZEND_VM_HANDLER(89, ZEND_FETCH_IS, CONST|TMPVAR|CV, UNUSED, VAR_FETCH)
|
||||
}
|
||||
|
||||
/* No specialization for op_types (CONST|TMPVAR|CV, UNUSED|CONST|VAR) */
|
||||
ZEND_VM_HELPER(zend_fetch_static_prop_helper, ANY, ANY, int type)
|
||||
ZEND_VM_INLINE_HELPER(zend_fetch_static_prop_helper, ANY, ANY, int type)
|
||||
{
|
||||
USE_OPLINE
|
||||
zval *prop;
|
||||
|
||||
SAVE_OPLINE();
|
||||
|
||||
if (UNEXPECTED(zend_fetch_static_property_address(&prop, NULL, opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS, type, opline->extended_value OPLINE_CC EXECUTE_DATA_CC) != SUCCESS)) {
|
||||
prop = zend_fetch_static_property_address(
|
||||
NULL, opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS, type,
|
||||
type == BP_VAR_W ? opline->extended_value : 0 OPLINE_CC EXECUTE_DATA_CC);
|
||||
if (UNEXPECTED(!prop)) {
|
||||
ZEND_ASSERT(EG(exception) || (type == BP_VAR_IS));
|
||||
prop = &EG(uninitialized_zval);
|
||||
}
|
||||
@@ -1870,10 +1876,11 @@ ZEND_VM_HANDLER(175, ZEND_FETCH_STATIC_PROP_RW, ANY, CLASS_FETCH, CACHE_SLOT)
|
||||
/* No specialization for op_types (CONST|TMPVAR|CV, UNUSED|CLASS_FETCH|CONST|VAR) */
|
||||
ZEND_VM_HANDLER(177, ZEND_FETCH_STATIC_PROP_FUNC_ARG, ANY, CLASS_FETCH, FETCH_REF|CACHE_SLOT)
|
||||
{
|
||||
int fetch_type =
|
||||
(UNEXPECTED(ZEND_CALL_INFO(EX(call)) & ZEND_CALL_SEND_ARG_BY_REF)) ?
|
||||
BP_VAR_W : BP_VAR_R;
|
||||
ZEND_VM_DISPATCH_TO_HELPER(zend_fetch_static_prop_helper, type, fetch_type);
|
||||
if (UNEXPECTED(ZEND_CALL_INFO(EX(call)) & ZEND_CALL_SEND_ARG_BY_REF)) {
|
||||
ZEND_VM_DISPATCH_TO_HANDLER(ZEND_FETCH_STATIC_PROP_W);
|
||||
} else {
|
||||
ZEND_VM_DISPATCH_TO_HANDLER(ZEND_FETCH_STATIC_PROP_R);
|
||||
}
|
||||
}
|
||||
|
||||
/* No specialization for op_types (CONST|TMPVAR|CV, UNUSED|CLASS_FETCH|CONST|VAR) */
|
||||
@@ -2584,7 +2591,8 @@ ZEND_VM_HANDLER(25, ZEND_ASSIGN_STATIC_PROP, ANY, ANY, CACHE_SLOT, SPEC(OP_DATA=
|
||||
|
||||
SAVE_OPLINE();
|
||||
|
||||
if (zend_fetch_static_property_address(&prop, &prop_info, opline->extended_value, BP_VAR_W, 0 OPLINE_CC EXECUTE_DATA_CC) != SUCCESS) {
|
||||
prop = zend_fetch_static_property_address(&prop_info, opline->extended_value, BP_VAR_W, 0 OPLINE_CC EXECUTE_DATA_CC);
|
||||
if (UNEXPECTED(!prop)) {
|
||||
FREE_OP_DATA();
|
||||
UNDEF_RESULT();
|
||||
HANDLE_EXCEPTION();
|
||||
@@ -2878,7 +2886,8 @@ ZEND_VM_HANDLER(33, ZEND_ASSIGN_STATIC_PROP_REF, ANY, ANY, CACHE_SLOT|SRC)
|
||||
|
||||
SAVE_OPLINE();
|
||||
|
||||
if (zend_fetch_static_property_address(&prop, &prop_info, opline->extended_value & ~ZEND_RETURNS_FUNCTION, BP_VAR_W, 0 OPLINE_CC EXECUTE_DATA_CC) != SUCCESS) {
|
||||
prop = zend_fetch_static_property_address(&prop_info, opline->extended_value & ~ZEND_RETURNS_FUNCTION, BP_VAR_W, 0 OPLINE_CC EXECUTE_DATA_CC);
|
||||
if (UNEXPECTED(!prop)) {
|
||||
FREE_OP_DATA();
|
||||
UNDEF_RESULT();
|
||||
HANDLE_EXCEPTION();
|
||||
@@ -7430,18 +7439,17 @@ ZEND_VM_HANDLER(180, ZEND_ISSET_ISEMPTY_STATIC_PROP, ANY, CLASS_FETCH, ISSET|CAC
|
||||
{
|
||||
USE_OPLINE
|
||||
zval *value;
|
||||
zend_result fetch_result;
|
||||
bool result;
|
||||
|
||||
SAVE_OPLINE();
|
||||
|
||||
fetch_result = zend_fetch_static_property_address(&value, NULL, opline->extended_value & ~ZEND_ISEMPTY, BP_VAR_IS, 0 OPLINE_CC EXECUTE_DATA_CC);
|
||||
value = zend_fetch_static_property_address(NULL, opline->extended_value & ~ZEND_ISEMPTY, BP_VAR_IS, 0 OPLINE_CC EXECUTE_DATA_CC);
|
||||
|
||||
if (!(opline->extended_value & ZEND_ISEMPTY)) {
|
||||
result = fetch_result == SUCCESS && Z_TYPE_P(value) > IS_NULL &&
|
||||
result = value != NULL && Z_TYPE_P(value) > IS_NULL &&
|
||||
(!Z_ISREF_P(value) || Z_TYPE_P(Z_REFVAL_P(value)) != IS_NULL);
|
||||
} else {
|
||||
result = fetch_result != SUCCESS || !i_zend_is_true(value);
|
||||
result = value == NULL || !i_zend_is_true(value);
|
||||
}
|
||||
|
||||
ZEND_VM_SMART_BRANCH(result, 1);
|
||||
|
||||
47
Zend/zend_vm_execute.h
generated
47
Zend/zend_vm_execute.h
generated
@@ -776,7 +776,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_STATIC_PROP_OP_SPEC_HAN
|
||||
|
||||
SAVE_OPLINE();
|
||||
|
||||
if (UNEXPECTED(zend_fetch_static_property_address(&prop, &prop_info, (opline+1)->extended_value, BP_VAR_RW, 0 OPLINE_CC EXECUTE_DATA_CC) != SUCCESS)) {
|
||||
prop = zend_fetch_static_property_address(&prop_info, (opline+1)->extended_value, BP_VAR_RW, 0 OPLINE_CC EXECUTE_DATA_CC);
|
||||
if (UNEXPECTED(!prop)) {
|
||||
UNDEF_RESULT();
|
||||
FREE_OP((opline+1)->op1_type, (opline+1)->op1.var);
|
||||
HANDLE_EXCEPTION();
|
||||
@@ -819,7 +820,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_PRE_INC_STATIC_PROP_SPEC_HANDL
|
||||
|
||||
SAVE_OPLINE();
|
||||
|
||||
if (zend_fetch_static_property_address(&prop, &prop_info, opline->extended_value, BP_VAR_RW, 0 OPLINE_CC EXECUTE_DATA_CC) != SUCCESS) {
|
||||
prop = zend_fetch_static_property_address(&prop_info, opline->extended_value, BP_VAR_RW, 0 OPLINE_CC EXECUTE_DATA_CC);
|
||||
if (UNEXPECTED(!prop)) {
|
||||
UNDEF_RESULT();
|
||||
HANDLE_EXCEPTION();
|
||||
}
|
||||
@@ -839,7 +841,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_POST_INC_STATIC_PROP_SPEC_HAND
|
||||
|
||||
SAVE_OPLINE();
|
||||
|
||||
if (zend_fetch_static_property_address(&prop, &prop_info, opline->extended_value, BP_VAR_RW, 0 OPLINE_CC EXECUTE_DATA_CC) != SUCCESS) {
|
||||
prop = zend_fetch_static_property_address(&prop_info, opline->extended_value, BP_VAR_RW, 0 OPLINE_CC EXECUTE_DATA_CC);
|
||||
if (UNEXPECTED(!prop)) {
|
||||
UNDEF_RESULT();
|
||||
HANDLE_EXCEPTION();
|
||||
}
|
||||
@@ -851,14 +854,17 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_POST_INC_STATIC_PROP_SPEC_HAND
|
||||
}
|
||||
|
||||
/* No specialization for op_types (CONST|TMPVAR|CV, UNUSED|CONST|VAR) */
|
||||
static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_fetch_static_prop_helper_SPEC(int type ZEND_OPCODE_HANDLER_ARGS_DC)
|
||||
static zend_always_inline ZEND_OPCODE_HANDLER_RET zend_fetch_static_prop_helper_SPEC(int type ZEND_OPCODE_HANDLER_ARGS_DC)
|
||||
{
|
||||
USE_OPLINE
|
||||
zval *prop;
|
||||
|
||||
SAVE_OPLINE();
|
||||
|
||||
if (UNEXPECTED(zend_fetch_static_property_address(&prop, NULL, opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS, type, opline->extended_value OPLINE_CC EXECUTE_DATA_CC) != SUCCESS)) {
|
||||
prop = zend_fetch_static_property_address(
|
||||
NULL, opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS, type,
|
||||
type == BP_VAR_W ? opline->extended_value : 0 OPLINE_CC EXECUTE_DATA_CC);
|
||||
if (UNEXPECTED(!prop)) {
|
||||
ZEND_ASSERT(EG(exception) || (type == BP_VAR_IS));
|
||||
prop = &EG(uninitialized_zval);
|
||||
}
|
||||
@@ -892,10 +898,11 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_STATIC_PROP_RW_SPEC_HAND
|
||||
/* No specialization for op_types (CONST|TMPVAR|CV, UNUSED|CLASS_FETCH|CONST|VAR) */
|
||||
static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_STATIC_PROP_FUNC_ARG_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
|
||||
{
|
||||
int fetch_type =
|
||||
(UNEXPECTED(ZEND_CALL_INFO(EX(call)) & ZEND_CALL_SEND_ARG_BY_REF)) ?
|
||||
BP_VAR_W : BP_VAR_R;
|
||||
ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC(fetch_type ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC));
|
||||
if (UNEXPECTED(ZEND_CALL_INFO(EX(call)) & ZEND_CALL_SEND_ARG_BY_REF)) {
|
||||
ZEND_VM_TAIL_CALL(ZEND_FETCH_STATIC_PROP_W_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU));
|
||||
} else {
|
||||
ZEND_VM_TAIL_CALL(ZEND_FETCH_STATIC_PROP_R_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU));
|
||||
}
|
||||
}
|
||||
|
||||
/* No specialization for op_types (CONST|TMPVAR|CV, UNUSED|CLASS_FETCH|CONST|VAR) */
|
||||
@@ -943,7 +950,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_STATIC_PROP_SPEC_OP_DAT
|
||||
|
||||
SAVE_OPLINE();
|
||||
|
||||
if (zend_fetch_static_property_address(&prop, &prop_info, opline->extended_value, BP_VAR_W, 0 OPLINE_CC EXECUTE_DATA_CC) != SUCCESS) {
|
||||
prop = zend_fetch_static_property_address(&prop_info, opline->extended_value, BP_VAR_W, 0 OPLINE_CC EXECUTE_DATA_CC);
|
||||
if (UNEXPECTED(!prop)) {
|
||||
|
||||
UNDEF_RESULT();
|
||||
HANDLE_EXCEPTION();
|
||||
@@ -979,7 +987,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_STATIC_PROP_SPEC_OP_DAT
|
||||
|
||||
SAVE_OPLINE();
|
||||
|
||||
if (zend_fetch_static_property_address(&prop, &prop_info, opline->extended_value, BP_VAR_W, 0 OPLINE_CC EXECUTE_DATA_CC) != SUCCESS) {
|
||||
prop = zend_fetch_static_property_address(&prop_info, opline->extended_value, BP_VAR_W, 0 OPLINE_CC EXECUTE_DATA_CC);
|
||||
if (UNEXPECTED(!prop)) {
|
||||
zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var));
|
||||
UNDEF_RESULT();
|
||||
HANDLE_EXCEPTION();
|
||||
@@ -1015,7 +1024,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_STATIC_PROP_SPEC_OP_DAT
|
||||
|
||||
SAVE_OPLINE();
|
||||
|
||||
if (zend_fetch_static_property_address(&prop, &prop_info, opline->extended_value, BP_VAR_W, 0 OPLINE_CC EXECUTE_DATA_CC) != SUCCESS) {
|
||||
prop = zend_fetch_static_property_address(&prop_info, opline->extended_value, BP_VAR_W, 0 OPLINE_CC EXECUTE_DATA_CC);
|
||||
if (UNEXPECTED(!prop)) {
|
||||
zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var));
|
||||
UNDEF_RESULT();
|
||||
HANDLE_EXCEPTION();
|
||||
@@ -1051,7 +1061,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_STATIC_PROP_SPEC_OP_DAT
|
||||
|
||||
SAVE_OPLINE();
|
||||
|
||||
if (zend_fetch_static_property_address(&prop, &prop_info, opline->extended_value, BP_VAR_W, 0 OPLINE_CC EXECUTE_DATA_CC) != SUCCESS) {
|
||||
prop = zend_fetch_static_property_address(&prop_info, opline->extended_value, BP_VAR_W, 0 OPLINE_CC EXECUTE_DATA_CC);
|
||||
if (UNEXPECTED(!prop)) {
|
||||
|
||||
UNDEF_RESULT();
|
||||
HANDLE_EXCEPTION();
|
||||
@@ -1087,7 +1098,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_STATIC_PROP_REF_SPEC_HA
|
||||
|
||||
SAVE_OPLINE();
|
||||
|
||||
if (zend_fetch_static_property_address(&prop, &prop_info, opline->extended_value & ~ZEND_RETURNS_FUNCTION, BP_VAR_W, 0 OPLINE_CC EXECUTE_DATA_CC) != SUCCESS) {
|
||||
prop = zend_fetch_static_property_address(&prop_info, opline->extended_value & ~ZEND_RETURNS_FUNCTION, BP_VAR_W, 0 OPLINE_CC EXECUTE_DATA_CC);
|
||||
if (UNEXPECTED(!prop)) {
|
||||
FREE_OP((opline+1)->op1_type, (opline+1)->op1.var);
|
||||
UNDEF_RESULT();
|
||||
HANDLE_EXCEPTION();
|
||||
@@ -3008,18 +3020,17 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ISSET_ISEMPTY_STATIC_PROP_SPEC
|
||||
{
|
||||
USE_OPLINE
|
||||
zval *value;
|
||||
zend_result fetch_result;
|
||||
bool result;
|
||||
|
||||
SAVE_OPLINE();
|
||||
|
||||
fetch_result = zend_fetch_static_property_address(&value, NULL, opline->extended_value & ~ZEND_ISEMPTY, BP_VAR_IS, 0 OPLINE_CC EXECUTE_DATA_CC);
|
||||
value = zend_fetch_static_property_address(NULL, opline->extended_value & ~ZEND_ISEMPTY, BP_VAR_IS, 0 OPLINE_CC EXECUTE_DATA_CC);
|
||||
|
||||
if (!(opline->extended_value & ZEND_ISEMPTY)) {
|
||||
result = fetch_result == SUCCESS && Z_TYPE_P(value) > IS_NULL &&
|
||||
result = value != NULL && Z_TYPE_P(value) > IS_NULL &&
|
||||
(!Z_ISREF_P(value) || Z_TYPE_P(Z_REFVAL_P(value)) != IS_NULL);
|
||||
} else {
|
||||
result = fetch_result != SUCCESS || !i_zend_is_true(value);
|
||||
result = value == NULL || !i_zend_is_true(value);
|
||||
}
|
||||
|
||||
ZEND_VM_SMART_BRANCH(result, 1);
|
||||
|
||||
@@ -2349,6 +2349,22 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op
|
||||
goto jit_failure;
|
||||
}
|
||||
goto done;
|
||||
case ZEND_FETCH_STATIC_PROP_R:
|
||||
case ZEND_FETCH_STATIC_PROP_IS:
|
||||
case ZEND_FETCH_STATIC_PROP_W:
|
||||
case ZEND_FETCH_STATIC_PROP_RW:
|
||||
case ZEND_FETCH_STATIC_PROP_UNSET:
|
||||
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))))) {
|
||||
break;
|
||||
}
|
||||
if (!zend_jit_fetch_static_prop(&ctx, opline, op_array)) {
|
||||
goto jit_failure;
|
||||
}
|
||||
goto done;
|
||||
case ZEND_BIND_GLOBAL:
|
||||
if (!ssa->ops || !ssa->var_info) {
|
||||
op1_info = MAY_BE_ANY|MAY_BE_REF;
|
||||
|
||||
@@ -3212,6 +3212,18 @@ static void ZEND_FASTCALL zend_jit_post_dec_obj_helper(zend_object *zobj, zend_s
|
||||
}
|
||||
}
|
||||
|
||||
static void ZEND_FASTCALL zend_jit_uninit_static_prop(void)
|
||||
{
|
||||
zend_execute_data *execute_data = EG(current_execute_data);
|
||||
const zend_op *opline = EX(opline);
|
||||
uint32_t cache_slot = opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS;
|
||||
const zend_property_info *property_info = CACHED_PTR(cache_slot + sizeof(void *) * 2);
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
static void ZEND_FASTCALL zend_jit_free_trampoline_helper(zend_function *func)
|
||||
{
|
||||
ZEND_ASSERT(func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE);
|
||||
|
||||
@@ -3093,6 +3093,7 @@ static void zend_jit_setup_disasm(void)
|
||||
REGISTER_HELPER(zend_jit_post_inc_obj_helper);
|
||||
REGISTER_HELPER(zend_jit_pre_dec_obj_helper);
|
||||
REGISTER_HELPER(zend_jit_post_dec_obj_helper);
|
||||
REGISTER_HELPER(zend_jit_uninit_static_prop);
|
||||
REGISTER_HELPER(zend_jit_rope_end);
|
||||
REGISTER_HELPER(zend_fcall_interrupt);
|
||||
|
||||
@@ -15609,6 +15610,185 @@ static int zend_jit_incdec_obj(zend_jit_ctx *jit,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int zend_jit_fetch_static_prop(zend_jit_ctx *jit, const zend_op *opline, const zend_op_array *op_array)
|
||||
{
|
||||
zend_jit_addr res_addr = RES_ADDR();
|
||||
uint32_t cache_slot = opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS;
|
||||
uint32_t flags;
|
||||
ir_ref ref, ref2, if_cached, fast_path, cold_path, prop_info_ref, if_typed, if_def;
|
||||
int fetch_type;
|
||||
zend_property_info *known_prop_info = NULL;
|
||||
zend_class_entry *ce = NULL;
|
||||
|
||||
if (opline->op2_type == IS_CONST) {
|
||||
zval *zv = RT_CONSTANT(opline, opline->op2);
|
||||
zend_string *class_name;
|
||||
|
||||
ZEND_ASSERT(Z_TYPE_P(zv) == IS_STRING);
|
||||
class_name = Z_STR_P(zv);
|
||||
ce = zend_lookup_class_ex(class_name, NULL, ZEND_FETCH_CLASS_NO_AUTOLOAD);
|
||||
if (ce && (ce->type == ZEND_INTERNAL_CLASS || ce->info.user.filename != op_array->filename)) {
|
||||
ce = NULL;
|
||||
}
|
||||
} else {
|
||||
ZEND_ASSERT(opline->op2_type == IS_UNUSED);
|
||||
if (opline->op2.num == ZEND_FETCH_CLASS_SELF) {
|
||||
ce = op_array->scope;
|
||||
} else {
|
||||
ZEND_ASSERT(opline->op2.num == ZEND_FETCH_CLASS_PARENT);
|
||||
ce = op_array->scope;
|
||||
if (ce) {
|
||||
if (ce->parent) {
|
||||
ce = ce->parent;
|
||||
if (ce->type == ZEND_INTERNAL_CLASS || ce->info.user.filename != op_array->filename) {
|
||||
ce = NULL;
|
||||
}
|
||||
} else {
|
||||
ce = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ce) {
|
||||
zval *zv = RT_CONSTANT(opline, opline->op1);
|
||||
zend_string *prop_name;
|
||||
|
||||
ZEND_ASSERT(Z_TYPE_P(zv) == IS_STRING);
|
||||
prop_name = Z_STR_P(zv);
|
||||
zv = zend_hash_find(&ce->properties_info, prop_name);
|
||||
if (zv) {
|
||||
zend_property_info *prop_info = Z_PTR_P(zv);
|
||||
|
||||
if (prop_info->flags & ZEND_ACC_STATIC) {
|
||||
if (prop_info->ce == op_array->scope
|
||||
|| (prop_info->flags & ZEND_ACC_PUBLIC)
|
||||
|| ((prop_info->flags & ZEND_ACC_PROTECTED)
|
||||
&& instanceof_function_slow(op_array->scope, prop_info->ce))) {
|
||||
known_prop_info = prop_info;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch (opline->opcode) {
|
||||
case ZEND_FETCH_STATIC_PROP_R:
|
||||
case ZEND_FETCH_STATIC_PROP_FUNC_ARG:
|
||||
fetch_type = BP_VAR_R;
|
||||
break;
|
||||
case ZEND_FETCH_STATIC_PROP_IS:
|
||||
fetch_type = BP_VAR_IS;
|
||||
break;
|
||||
case ZEND_FETCH_STATIC_PROP_W:
|
||||
fetch_type = BP_VAR_W;
|
||||
break;
|
||||
case ZEND_FETCH_STATIC_PROP_RW:
|
||||
fetch_type = BP_VAR_RW;
|
||||
break;
|
||||
case ZEND_FETCH_STATIC_PROP_UNSET:
|
||||
fetch_type = BP_VAR_UNSET;
|
||||
break;
|
||||
EMPTY_SWITCH_DEFAULT_CASE();
|
||||
}
|
||||
|
||||
// JIT: result = CACHED_PTR(cache_slot + sizeof(void *));
|
||||
ref = ir_LOAD_A(
|
||||
ir_ADD_OFFSET(ir_LOAD_A(jit_EX(run_time_cache)), cache_slot + sizeof(void*)));
|
||||
|
||||
// JIT: if (result)
|
||||
if_cached = ir_IF(ref);
|
||||
ir_IF_TRUE(if_cached);
|
||||
|
||||
if (fetch_type == BP_VAR_R || fetch_type == BP_VAR_RW) {
|
||||
if (!known_prop_info || ZEND_TYPE_IS_SET(known_prop_info->type)) {
|
||||
ir_ref merge = IR_UNUSED;
|
||||
|
||||
// JIT: if (UNEXPECTED(Z_TYPE_P(result) == IS_UNDEF)
|
||||
if_typed = IR_UNUSED;
|
||||
if_def = ir_IF(jit_Z_TYPE_ref(jit, ref));
|
||||
ir_IF_FALSE_cold(if_def);
|
||||
if (!known_prop_info) {
|
||||
// JIT: if (ZEND_TYPE_IS_SET(property_info->type))
|
||||
prop_info_ref = ir_LOAD_L(
|
||||
ir_ADD_OFFSET(ir_LOAD_A(jit_EX(run_time_cache)), cache_slot + sizeof(void*) * 2));
|
||||
if_typed = ir_IF(ir_AND_U32(
|
||||
ir_LOAD_U32(ir_ADD_OFFSET(prop_info_ref, offsetof(zend_property_info, type.type_mask))),
|
||||
ir_CONST_U32(_ZEND_TYPE_MASK)));
|
||||
ir_IF_FALSE(if_typed);
|
||||
ir_END_list(merge);
|
||||
ir_IF_TRUE(if_typed);
|
||||
}
|
||||
// JIT: 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));
|
||||
jit_SET_EX_OPLINE(jit, opline);
|
||||
ir_CALL(IR_VOID, ir_CONST_FC_FUNC(zend_jit_uninit_static_prop));
|
||||
ir_IJMP(jit_STUB_ADDR(jit, jit_stub_exception_handler_undef));
|
||||
|
||||
ir_IF_TRUE(if_def);
|
||||
if (!known_prop_info) {
|
||||
ir_END_list(merge);
|
||||
ir_MERGE_list(merge);
|
||||
}
|
||||
}
|
||||
} else if (fetch_type == BP_VAR_W) {
|
||||
flags = opline->extended_value & ZEND_FETCH_OBJ_FLAGS;
|
||||
if (flags && (!known_prop_info || ZEND_TYPE_IS_SET(known_prop_info->type))) {
|
||||
ir_ref merge = IR_UNUSED;
|
||||
|
||||
if (!known_prop_info) {
|
||||
// JIT: if (ZEND_TYPE_IS_SET(property_info->type))
|
||||
prop_info_ref = ir_LOAD_L(
|
||||
ir_ADD_OFFSET(ir_LOAD_A(jit_EX(run_time_cache)), cache_slot + sizeof(void*) * 2));
|
||||
if_typed = ir_IF(ir_AND_U32(
|
||||
ir_LOAD_U32(ir_ADD_OFFSET(prop_info_ref, offsetof(zend_property_info, type.type_mask))),
|
||||
ir_CONST_U32(_ZEND_TYPE_MASK)));
|
||||
ir_IF_FALSE(if_typed);
|
||||
ir_END_list(merge);
|
||||
ir_IF_TRUE(if_typed);
|
||||
} else {
|
||||
prop_info_ref = ir_CONST_ADDR(known_prop_info);
|
||||
}
|
||||
|
||||
// JIT: zend_handle_fetch_obj_flags(NULL, *retval, NULL, property_info, flags);
|
||||
ir_ref if_ok = ir_IF(ir_CALL_5(IR_BOOL, ir_CONST_FUNC(zend_handle_fetch_obj_flags),
|
||||
IR_NULL, ref, IR_NULL, prop_info_ref, ir_CONST_U32(flags)));
|
||||
ir_IF_FALSE_cold(if_ok);
|
||||
ir_IJMP(jit_STUB_ADDR(jit, jit_stub_exception_handler_undef));
|
||||
ir_IF_TRUE(if_ok);
|
||||
if (!known_prop_info) {
|
||||
ir_END_list(merge);
|
||||
ir_MERGE_list(merge);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fast_path = ir_END();
|
||||
|
||||
ir_IF_FALSE_cold(if_cached);
|
||||
jit_SET_EX_OPLINE(jit, opline);
|
||||
ref2 = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_fetch_static_property), jit_FP(jit), ir_CONST_I32(fetch_type));
|
||||
zend_jit_check_exception_undef_result(jit, opline);
|
||||
cold_path = ir_END();
|
||||
|
||||
ir_MERGE_2(fast_path, cold_path);
|
||||
ref = ir_PHI_2(IR_ADDR, ref, ref2);
|
||||
|
||||
if (fetch_type == BP_VAR_R || fetch_type == BP_VAR_IS) {
|
||||
// JIT: ZVAL_COPY_DEREF(EX_VAR(opline->result.var), result);
|
||||
if (!zend_jit_zval_copy_deref(jit, res_addr, ZEND_ADDR_REF_ZVAL(ref),
|
||||
jit_Z_TYPE_INFO_ref(jit, ref))) {
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
// JIT: ZVAL_INDIRECT(EX_VAR(opline->result.var), result);
|
||||
jit_set_Z_PTR(jit, res_addr, ref);
|
||||
jit_set_Z_TYPE_INFO(jit, res_addr, IS_INDIRECT);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int zend_jit_switch(zend_jit_ctx *jit, const zend_op *opline, const zend_op_array *op_array, zend_ssa *ssa, zend_jit_trace_rec *trace, zend_jit_trace_info *trace_info)
|
||||
{
|
||||
HashTable *jumptable = Z_ARRVAL_P(RT_CONSTANT(opline, opline->op2));
|
||||
|
||||
@@ -6071,6 +6071,29 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
|
||||
goto jit_failure;
|
||||
}
|
||||
goto done;
|
||||
case ZEND_FETCH_STATIC_PROP_FUNC_ARG:
|
||||
if (!JIT_G(current_frame)
|
||||
|| !JIT_G(current_frame)->call
|
||||
|| !TRACE_FRAME_IS_LAST_SEND_BY_VAL(JIT_G(current_frame)->call)) {
|
||||
break;
|
||||
}
|
||||
ZEND_FALLTHROUGH;
|
||||
case ZEND_FETCH_STATIC_PROP_R:
|
||||
case ZEND_FETCH_STATIC_PROP_IS:
|
||||
case ZEND_FETCH_STATIC_PROP_W:
|
||||
case ZEND_FETCH_STATIC_PROP_RW:
|
||||
case ZEND_FETCH_STATIC_PROP_UNSET:
|
||||
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))))) {
|
||||
break;
|
||||
}
|
||||
if (!zend_jit_fetch_static_prop(&ctx, opline, op_array)) {
|
||||
goto jit_failure;
|
||||
}
|
||||
goto done;
|
||||
case ZEND_BIND_GLOBAL:
|
||||
orig_opline = opline;
|
||||
orig_ssa_op = ssa_op;
|
||||
|
||||
Reference in New Issue
Block a user