Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 70 additions & 22 deletions Zend/zend_execute.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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);
Expand All @@ -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);
Expand All @@ -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) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be marked with ZEND_FASTCALL since it is called from JIT?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah. It makes sense to switch to FASTCALL. This will allow to pass parameters in register in 32-bit x86 build.
I don't care about 32-bit x86 a lot.

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) {
Expand Down
1 change: 1 addition & 0 deletions Zend/zend_execute.h
Original file line number Diff line number Diff line change
Expand Up @@ -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_fetch_static_property(zend_execute_data *ex, int fetch_type);

ZEND_API void zend_frameless_observed_call(zend_execute_data *execute_data);

Expand Down
38 changes: 23 additions & 15 deletions Zend/zend_vm_def.h
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -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();
}
Expand All @@ -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();
}
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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) */
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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);
Expand Down
Loading
Loading