Skip to content

Commit 3f913c1

Browse files
authored
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()
1 parent 83bbf4b commit 3f913c1

File tree

8 files changed

+354
-55
lines changed

8 files changed

+354
-55
lines changed

Zend/zend_execute.c

Lines changed: 70 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3532,7 +3532,8 @@ static zend_never_inline void zend_assign_to_property_reference_var_var(zval *co
35323532
OPLINE_CC EXECUTE_DATA_CC);
35333533
}
35343534

3535-
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) {
3535+
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) {
3536+
zval *result;
35363537
zend_string *name;
35373538
zend_class_entry *ce;
35383539
zend_property_info *property_info;
@@ -3548,7 +3549,7 @@ static zend_never_inline zend_result zend_fetch_static_property_address_ex(zval
35483549
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);
35493550
if (UNEXPECTED(ce == NULL)) {
35503551
FREE_OP(op1_type, opline->op1.var);
3551-
return FAILURE;
3552+
return NULL;
35523553
}
35533554
if (UNEXPECTED(op1_type != IS_CONST)) {
35543555
CACHE_PTR(cache_slot, ce);
@@ -3559,21 +3560,21 @@ static zend_never_inline zend_result zend_fetch_static_property_address_ex(zval
35593560
ce = zend_fetch_class(NULL, opline->op2.num);
35603561
if (UNEXPECTED(ce == NULL)) {
35613562
FREE_OP(op1_type, opline->op1.var);
3562-
return FAILURE;
3563+
return NULL;
35633564
}
35643565
} else {
35653566
ce = Z_CE_P(EX_VAR(opline->op2.var));
35663567
}
35673568
if (EXPECTED(op1_type == IS_CONST) && EXPECTED(CACHED_PTR(cache_slot) == ce)) {
3568-
*retval = CACHED_PTR(cache_slot + sizeof(void *));
3569+
result = CACHED_PTR(cache_slot + sizeof(void *));
35693570
*prop_info = CACHED_PTR(cache_slot + sizeof(void *) * 2);
3570-
return SUCCESS;
3571+
return result;
35713572
}
35723573
}
35733574

35743575
if (EXPECTED(op1_type == IS_CONST)) {
35753576
name = Z_STR_P(RT_CONSTANT(opline, opline->op1));
3576-
*retval = zend_std_get_static_property_with_info(ce, name, fetch_type, &property_info);
3577+
result = zend_std_get_static_property_with_info(ce, name, fetch_type, &property_info);
35773578
} else {
35783579
zend_string *tmp_name;
35793580
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
35863587
}
35873588
name = zval_get_tmp_string(varname, &tmp_name);
35883589
}
3589-
*retval = zend_std_get_static_property_with_info(ce, name, fetch_type, &property_info);
3590+
result = zend_std_get_static_property_with_info(ce, name, fetch_type, &property_info);
35903591

35913592
zend_tmp_string_release(tmp_name);
35923593

35933594
FREE_OP(op1_type, opline->op1.var);
35943595
}
35953596

3596-
if (UNEXPECTED(*retval == NULL)) {
3597-
return FAILURE;
3597+
if (UNEXPECTED(result == NULL)) {
3598+
return NULL;
35983599
}
35993600

36003601
*prop_info = property_info;
36013602

36023603
if (EXPECTED(op1_type == IS_CONST)
36033604
&& EXPECTED(!(property_info->ce->ce_flags & ZEND_ACC_TRAIT))) {
3604-
CACHE_POLYMORPHIC_PTR(cache_slot, ce, *retval);
3605+
CACHE_POLYMORPHIC_PTR(cache_slot, ce, result);
36053606
CACHE_PTR(cache_slot + sizeof(void *) * 2, property_info);
36063607
}
36073608

3608-
return SUCCESS;
3609+
return result;
36093610
}
36103611

36113612

3612-
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) {
3613+
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) {
3614+
zval *result;
36133615
zend_property_info *property_info;
36143616

3615-
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)) {
3616-
*retval = CACHED_PTR(cache_slot + sizeof(void *));
3617+
if (opline->op1_type == IS_CONST
3618+
&& (opline->op2_type == IS_CONST
3619+
|| (opline->op2_type == IS_UNUSED
3620+
&& (opline->op2.num == ZEND_FETCH_CLASS_SELF
3621+
|| opline->op2.num == ZEND_FETCH_CLASS_PARENT)))
3622+
&& EXPECTED(CACHED_PTR(cache_slot + sizeof(void *)) != NULL)) {
3623+
result = CACHED_PTR(cache_slot + sizeof(void *));
36173624
property_info = CACHED_PTR(cache_slot + sizeof(void *) * 2);
36183625

36193626
if ((fetch_type == BP_VAR_R || fetch_type == BP_VAR_RW)
3620-
&& UNEXPECTED(Z_TYPE_P(*retval) == IS_UNDEF)
3627+
&& UNEXPECTED(Z_TYPE_P(result) == IS_UNDEF)
36213628
&& ZEND_TYPE_IS_SET(property_info->type)) {
36223629
zend_throw_error(NULL, "Typed static property %s::$%s must not be accessed before initialization",
36233630
ZSTR_VAL(property_info->ce->name),
36243631
zend_get_unmangled_property_name(property_info->name));
3625-
return FAILURE;
3632+
return NULL;
36263633
}
36273634
} else {
3628-
zend_result success;
3629-
success = zend_fetch_static_property_address_ex(retval, &property_info, cache_slot, fetch_type OPLINE_CC EXECUTE_DATA_CC);
3630-
if (UNEXPECTED(success != SUCCESS)) {
3631-
return FAILURE;
3635+
result = zend_fetch_static_property_address_ex(&property_info, cache_slot, fetch_type OPLINE_CC EXECUTE_DATA_CC);
3636+
if (UNEXPECTED(!result)) {
3637+
return NULL;
36323638
}
36333639
}
36343640

36353641
flags &= ZEND_FETCH_OBJ_FLAGS;
36363642
if (flags && ZEND_TYPE_IS_SET(property_info->type)) {
3637-
zend_handle_fetch_obj_flags(NULL, *retval, NULL, property_info, flags);
3643+
zend_handle_fetch_obj_flags(NULL, result, NULL, property_info, flags);
36383644
}
36393645

36403646
if (prop_info) {
36413647
*prop_info = property_info;
36423648
}
36433649

3644-
return SUCCESS;
3650+
return result;
3651+
}
3652+
3653+
ZEND_API zval* ZEND_FASTCALL zend_fetch_static_property(zend_execute_data *ex, int fetch_type) {
3654+
zval *result;
3655+
zend_property_info *property_info;
3656+
#if defined(ZEND_VM_FP_GLOBAL_REG) && ((ZEND_VM_KIND == ZEND_VM_KIND_CALL) || (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID))
3657+
zend_execute_data *orig_execute_data = execute_data;
3658+
#else
3659+
zend_execute_data *execute_data;
3660+
#endif
3661+
execute_data = ex;
3662+
#if defined(ZEND_VM_IP_GLOBAL_REG) && ((ZEND_VM_KIND == ZEND_VM_KIND_CALL) || (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID))
3663+
const zend_op *orig_opline = opline;
3664+
#else
3665+
const zend_op *opline;
3666+
#endif
3667+
opline = execute_data->opline;
3668+
3669+
uint32_t cache_slot = opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS;
3670+
uint32_t flags = 0;
3671+
3672+
if (fetch_type == BP_VAR_W) {
3673+
flags = opline->extended_value & ZEND_FETCH_OBJ_FLAGS;
3674+
}
3675+
result = zend_fetch_static_property_address_ex(&property_info, cache_slot, fetch_type OPLINE_CC EXECUTE_DATA_CC);
3676+
if (EXPECTED(result)) {
3677+
if (flags && ZEND_TYPE_IS_SET(property_info->type)) {
3678+
zend_handle_fetch_obj_flags(NULL, result, NULL, property_info, flags);
3679+
}
3680+
} else {
3681+
result = &EG(uninitialized_zval);
3682+
}
3683+
3684+
#if defined(ZEND_VM_IP_GLOBAL_REG) && ((ZEND_VM_KIND == ZEND_VM_KIND_CALL) || (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID))
3685+
EX(opline) = opline;
3686+
opline = orig_opline;
3687+
#endif
3688+
#if defined(ZEND_VM_FP_GLOBAL_REG) && ((ZEND_VM_KIND == ZEND_VM_KIND_CALL) || (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID))
3689+
execute_data = orig_execute_data;
3690+
#endif
3691+
3692+
return result;
36453693
}
36463694

36473695
ZEND_API ZEND_COLD void zend_throw_ref_type_error_type(const zend_property_info *prop1, const zend_property_info *prop2, const zval *zv) {

Zend/zend_execute.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -434,6 +434,7 @@ ZEND_API void zend_unfinished_calls_gc(zend_execute_data *execute_data, zend_exe
434434
ZEND_API void zend_cleanup_unfinished_execution(zend_execute_data *execute_data, uint32_t op_num, uint32_t catch_op_num);
435435
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);
436436
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);
437+
ZEND_API zval* ZEND_FASTCALL zend_fetch_static_property(zend_execute_data *ex, int fetch_type);
437438

438439
ZEND_API void zend_frameless_observed_call(zend_execute_data *execute_data);
439440

Zend/zend_vm_def.h

Lines changed: 23 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1109,7 +1109,8 @@ ZEND_VM_HANDLER(29, ZEND_ASSIGN_STATIC_PROP_OP, ANY, ANY, OP)
11091109

11101110
SAVE_OPLINE();
11111111

1112-
if (UNEXPECTED(zend_fetch_static_property_address(&prop, &prop_info, (opline+1)->extended_value, BP_VAR_RW, 0 OPLINE_CC EXECUTE_DATA_CC) != SUCCESS)) {
1112+
prop = zend_fetch_static_property_address(&prop_info, (opline+1)->extended_value, BP_VAR_RW, 0 OPLINE_CC EXECUTE_DATA_CC);
1113+
if (UNEXPECTED(!prop)) {
11131114
UNDEF_RESULT();
11141115
FREE_OP_DATA();
11151116
HANDLE_EXCEPTION();
@@ -1423,7 +1424,8 @@ ZEND_VM_HANDLER(38, ZEND_PRE_INC_STATIC_PROP, ANY, ANY, CACHE_SLOT)
14231424

14241425
SAVE_OPLINE();
14251426

1426-
if (zend_fetch_static_property_address(&prop, &prop_info, opline->extended_value, BP_VAR_RW, 0 OPLINE_CC EXECUTE_DATA_CC) != SUCCESS) {
1427+
prop = zend_fetch_static_property_address(&prop_info, opline->extended_value, BP_VAR_RW, 0 OPLINE_CC EXECUTE_DATA_CC);
1428+
if (UNEXPECTED(!prop)) {
14271429
UNDEF_RESULT();
14281430
HANDLE_EXCEPTION();
14291431
}
@@ -1449,7 +1451,8 @@ ZEND_VM_HANDLER(40, ZEND_POST_INC_STATIC_PROP, ANY, ANY, CACHE_SLOT)
14491451

14501452
SAVE_OPLINE();
14511453

1452-
if (zend_fetch_static_property_address(&prop, &prop_info, opline->extended_value, BP_VAR_RW, 0 OPLINE_CC EXECUTE_DATA_CC) != SUCCESS) {
1454+
prop = zend_fetch_static_property_address(&prop_info, opline->extended_value, BP_VAR_RW, 0 OPLINE_CC EXECUTE_DATA_CC);
1455+
if (UNEXPECTED(!prop)) {
14531456
UNDEF_RESULT();
14541457
HANDLE_EXCEPTION();
14551458
}
@@ -1829,14 +1832,17 @@ ZEND_VM_HANDLER(89, ZEND_FETCH_IS, CONST|TMPVAR|CV, UNUSED, VAR_FETCH)
18291832
}
18301833

18311834
/* No specialization for op_types (CONST|TMPVAR|CV, UNUSED|CONST|VAR) */
1832-
ZEND_VM_HELPER(zend_fetch_static_prop_helper, ANY, ANY, int type)
1835+
ZEND_VM_INLINE_HELPER(zend_fetch_static_prop_helper, ANY, ANY, int type)
18331836
{
18341837
USE_OPLINE
18351838
zval *prop;
18361839

18371840
SAVE_OPLINE();
18381841

1839-
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)) {
1842+
prop = zend_fetch_static_property_address(
1843+
NULL, opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS, type,
1844+
type == BP_VAR_W ? opline->extended_value : 0 OPLINE_CC EXECUTE_DATA_CC);
1845+
if (UNEXPECTED(!prop)) {
18401846
ZEND_ASSERT(EG(exception) || (type == BP_VAR_IS));
18411847
prop = &EG(uninitialized_zval);
18421848
}
@@ -1870,10 +1876,11 @@ ZEND_VM_HANDLER(175, ZEND_FETCH_STATIC_PROP_RW, ANY, CLASS_FETCH, CACHE_SLOT)
18701876
/* No specialization for op_types (CONST|TMPVAR|CV, UNUSED|CLASS_FETCH|CONST|VAR) */
18711877
ZEND_VM_HANDLER(177, ZEND_FETCH_STATIC_PROP_FUNC_ARG, ANY, CLASS_FETCH, FETCH_REF|CACHE_SLOT)
18721878
{
1873-
int fetch_type =
1874-
(UNEXPECTED(ZEND_CALL_INFO(EX(call)) & ZEND_CALL_SEND_ARG_BY_REF)) ?
1875-
BP_VAR_W : BP_VAR_R;
1876-
ZEND_VM_DISPATCH_TO_HELPER(zend_fetch_static_prop_helper, type, fetch_type);
1879+
if (UNEXPECTED(ZEND_CALL_INFO(EX(call)) & ZEND_CALL_SEND_ARG_BY_REF)) {
1880+
ZEND_VM_DISPATCH_TO_HANDLER(ZEND_FETCH_STATIC_PROP_W);
1881+
} else {
1882+
ZEND_VM_DISPATCH_TO_HANDLER(ZEND_FETCH_STATIC_PROP_R);
1883+
}
18771884
}
18781885

18791886
/* 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=
25842591

25852592
SAVE_OPLINE();
25862593

2587-
if (zend_fetch_static_property_address(&prop, &prop_info, opline->extended_value, BP_VAR_W, 0 OPLINE_CC EXECUTE_DATA_CC) != SUCCESS) {
2594+
prop = zend_fetch_static_property_address(&prop_info, opline->extended_value, BP_VAR_W, 0 OPLINE_CC EXECUTE_DATA_CC);
2595+
if (UNEXPECTED(!prop)) {
25882596
FREE_OP_DATA();
25892597
UNDEF_RESULT();
25902598
HANDLE_EXCEPTION();
@@ -2878,7 +2886,8 @@ ZEND_VM_HANDLER(33, ZEND_ASSIGN_STATIC_PROP_REF, ANY, ANY, CACHE_SLOT|SRC)
28782886

28792887
SAVE_OPLINE();
28802888

2881-
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) {
2889+
prop = zend_fetch_static_property_address(&prop_info, opline->extended_value & ~ZEND_RETURNS_FUNCTION, BP_VAR_W, 0 OPLINE_CC EXECUTE_DATA_CC);
2890+
if (UNEXPECTED(!prop)) {
28822891
FREE_OP_DATA();
28832892
UNDEF_RESULT();
28842893
HANDLE_EXCEPTION();
@@ -7430,18 +7439,17 @@ ZEND_VM_HANDLER(180, ZEND_ISSET_ISEMPTY_STATIC_PROP, ANY, CLASS_FETCH, ISSET|CAC
74307439
{
74317440
USE_OPLINE
74327441
zval *value;
7433-
zend_result fetch_result;
74347442
bool result;
74357443

74367444
SAVE_OPLINE();
74377445

7438-
fetch_result = zend_fetch_static_property_address(&value, NULL, opline->extended_value & ~ZEND_ISEMPTY, BP_VAR_IS, 0 OPLINE_CC EXECUTE_DATA_CC);
7446+
value = zend_fetch_static_property_address(NULL, opline->extended_value & ~ZEND_ISEMPTY, BP_VAR_IS, 0 OPLINE_CC EXECUTE_DATA_CC);
74397447

74407448
if (!(opline->extended_value & ZEND_ISEMPTY)) {
7441-
result = fetch_result == SUCCESS && Z_TYPE_P(value) > IS_NULL &&
7449+
result = value != NULL && Z_TYPE_P(value) > IS_NULL &&
74427450
(!Z_ISREF_P(value) || Z_TYPE_P(Z_REFVAL_P(value)) != IS_NULL);
74437451
} else {
7444-
result = fetch_result != SUCCESS || !i_zend_is_true(value);
7452+
result = value == NULL || !i_zend_is_true(value);
74457453
}
74467454

74477455
ZEND_VM_SMART_BRANCH(result, 1);

0 commit comments

Comments
 (0)