From: Dmitry Stogov Date: Wed, 10 Feb 2021 15:00:00 +0000 (+0300) Subject: Use zend_type.ce_cache__ptr for caching class resulution during argument/result type... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=ef5164818576d75929834d9f0c15cdfc095f7139;p=php Use zend_type.ce_cache__ptr for caching class resulution during argument/result type checks --- diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index d617547f81..069acae0c1 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -1197,7 +1197,13 @@ zend_string *zend_type_to_string_resolved(zend_type type, zend_class_entry *scop } else { if (ZEND_TYPE_HAS_CE_CACHE(*list_type) && ZEND_TYPE_CE_CACHE(*list_type)) { - str = add_type_string(str, ZEND_TYPE_CE_CACHE(*list_type)->name); + zend_class_entry *ce = ZEND_TYPE_CE_CACHE(*list_type); + if (ce->ce_flags & ZEND_ACC_ANON_CLASS) { + zend_string *tmp = zend_string_init(ZSTR_VAL(ce->name), strlen(ZSTR_VAL(ce->name)), 0); + str = add_type_string(str, tmp); + } else { + str = add_type_string(str, ce->name); + } } else { zend_string *resolved = resolve_class_name(ZEND_TYPE_NAME(*list_type), scope); str = add_type_string(str, resolved); @@ -1208,7 +1214,12 @@ zend_string *zend_type_to_string_resolved(zend_type type, zend_class_entry *scop } else if (ZEND_TYPE_HAS_NAME(type)) { if (ZEND_TYPE_HAS_CE_CACHE(type) && ZEND_TYPE_CE_CACHE(type)) { - str = zend_string_copy(ZEND_TYPE_CE_CACHE(type)->name); + zend_class_entry *ce = ZEND_TYPE_CE_CACHE(type); + if (ce->ce_flags & ZEND_ACC_ANON_CLASS) { + str = zend_string_init(ZSTR_VAL(ce->name), strlen(ZSTR_VAL(ce->name)), 0); + } else { + str = zend_string_copy(ce->name); + } } else { str = resolve_class_name(ZEND_TYPE_NAME(type), scope); } diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index 5338a0ae43..02912c2009 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -857,24 +857,26 @@ static bool zend_check_and_resolve_property_class_type( if (ZEND_TYPE_HAS_LIST(info->type)) { zend_type *list_type; ZEND_TYPE_LIST_FOREACH(ZEND_TYPE_LIST(info->type), list_type) { - if (ZEND_TYPE_HAS_CE_CACHE(*list_type)) { - ce = ZEND_TYPE_CE_CACHE(*list_type); - if (!ce) { + if (ZEND_TYPE_HAS_NAME(*list_type)) { + if (ZEND_TYPE_HAS_CE_CACHE(*list_type)) { + ce = ZEND_TYPE_CE_CACHE(*list_type); + if (!ce) { + zend_string *name = ZEND_TYPE_NAME(*list_type); + ce = resolve_single_class_type(name, info->ce); + if (UNEXPECTED(!ce)) { + continue; + } + ZEND_TYPE_SET_CE_CACHE(*list_type, ce); + } + } else { zend_string *name = ZEND_TYPE_NAME(*list_type); ce = resolve_single_class_type(name, info->ce); - if (UNEXPECTED(!ce)) { + if (!ce) { continue; } - ZEND_TYPE_SET_CE_CACHE(*list_type, ce); - } - } else if (ZEND_TYPE_HAS_NAME(*list_type)) { - zend_string *name = ZEND_TYPE_NAME(*list_type); - ce = resolve_single_class_type(name, info->ce); - if (!ce) { - continue; + zend_string_release(name); + ZEND_TYPE_SET_CE(*list_type, ce); } - zend_string_release(name); - ZEND_TYPE_SET_CE(*list_type, ce); } else { ce = ZEND_TYPE_CE(*list_type); } @@ -884,25 +886,27 @@ static bool zend_check_and_resolve_property_class_type( } ZEND_TYPE_LIST_FOREACH_END(); return 0; } else { - if (ZEND_TYPE_HAS_CE_CACHE(info->type)) { - ce = ZEND_TYPE_CE_CACHE(info->type); - if (!ce) { + if (UNEXPECTED(ZEND_TYPE_HAS_NAME(info->type))) { + if (ZEND_TYPE_HAS_CE_CACHE(info->type)) { + ce = ZEND_TYPE_CE_CACHE(info->type); + if (!ce) { + zend_string *name = ZEND_TYPE_NAME(info->type); + ce = resolve_single_class_type(name, info->ce); + if (UNEXPECTED(!ce)) { + return 0; + } + ZEND_TYPE_SET_CE_CACHE(info->type, ce); + } + } else { zend_string *name = ZEND_TYPE_NAME(info->type); ce = resolve_single_class_type(name, info->ce); if (UNEXPECTED(!ce)) { return 0; } - ZEND_TYPE_SET_CE_CACHE(info->type, ce); - } - } else if (UNEXPECTED(ZEND_TYPE_HAS_NAME(info->type))) { - zend_string *name = ZEND_TYPE_NAME(info->type); - ce = resolve_single_class_type(name, info->ce); - if (UNEXPECTED(!ce)) { - return 0; - } - zend_string_release(name); - ZEND_TYPE_SET_CE(info->type, ce); + zend_string_release(name); + ZEND_TYPE_SET_CE(info->type, ce); + } } else { ce = ZEND_TYPE_CE(info->type); } @@ -980,17 +984,22 @@ ZEND_API bool zend_value_instanceof_static(zval *zv) { #endif static zend_always_inline bool zend_check_type_slow( - zend_type type, zval *arg, zend_reference *ref, void **cache_slot, zend_class_entry *scope, + zend_type *type, zval *arg, zend_reference *ref, void **cache_slot, zend_class_entry *scope, bool is_return_type, bool is_internal) { uint32_t type_mask; - if (ZEND_TYPE_HAS_CLASS(type) && Z_TYPE_P(arg) == IS_OBJECT) { + if (ZEND_TYPE_HAS_CLASS(*type) && Z_TYPE_P(arg) == IS_OBJECT) { zend_class_entry *ce; - if (ZEND_TYPE_HAS_LIST(type)) { + if (ZEND_TYPE_HAS_LIST(*type)) { zend_type *list_type; - ZEND_TYPE_LIST_FOREACH(ZEND_TYPE_LIST(type), list_type) { + ZEND_TYPE_LIST_FOREACH(ZEND_TYPE_LIST(*type), list_type) { if (HAVE_CACHE_SLOT && *cache_slot) { ce = *cache_slot; + } else if (ZEND_TYPE_HAS_CE_CACHE(*list_type) && ZEND_TYPE_CE_CACHE(*list_type)) { + ce = ZEND_TYPE_CE_CACHE(*list_type); + if (HAVE_CACHE_SLOT) { + *cache_slot = ce; + } } else { ce = zend_fetch_class(ZEND_TYPE_NAME(*list_type), (ZEND_FETCH_CLASS_AUTO | ZEND_FETCH_CLASS_NO_AUTOLOAD)); @@ -1003,6 +1012,9 @@ static zend_always_inline bool zend_check_type_slow( if (HAVE_CACHE_SLOT) { *cache_slot = ce; } + if (ZEND_TYPE_HAS_CE_CACHE(*list_type)) { + ZEND_TYPE_SET_CE_CACHE(*list_type, ce); + } } if (instanceof_function(Z_OBJCE_P(arg), ce)) { return 1; @@ -1014,14 +1026,22 @@ static zend_always_inline bool zend_check_type_slow( } else { if (EXPECTED(HAVE_CACHE_SLOT && *cache_slot)) { ce = (zend_class_entry *) *cache_slot; + } else if (ZEND_TYPE_HAS_CE_CACHE(*type) && ZEND_TYPE_CE_CACHE(*type)) { + ce = ZEND_TYPE_CE_CACHE(*type); + if (HAVE_CACHE_SLOT) { + *cache_slot = ce; + } } else { - ce = zend_fetch_class(ZEND_TYPE_NAME(type), (ZEND_FETCH_CLASS_AUTO | ZEND_FETCH_CLASS_NO_AUTOLOAD)); + ce = zend_fetch_class(ZEND_TYPE_NAME(*type), (ZEND_FETCH_CLASS_AUTO | ZEND_FETCH_CLASS_NO_AUTOLOAD)); if (UNEXPECTED(!ce)) { goto builtin_types; } if (HAVE_CACHE_SLOT) { *cache_slot = (void *) ce; } + if (ZEND_TYPE_HAS_CE_CACHE(*type)) { + ZEND_TYPE_SET_CE_CACHE(*type, ce); + } } if (instanceof_function(Z_OBJCE_P(arg), ce)) { return 1; @@ -1030,7 +1050,7 @@ static zend_always_inline bool zend_check_type_slow( } builtin_types: - type_mask = ZEND_TYPE_FULL_MASK(type); + type_mask = ZEND_TYPE_FULL_MASK(*type); if ((type_mask & MAY_BE_CALLABLE) && zend_is_callable(arg, 0, NULL)) { return 1; } @@ -1060,18 +1080,18 @@ builtin_types: } static zend_always_inline bool zend_check_type( - zend_type type, zval *arg, void **cache_slot, zend_class_entry *scope, + zend_type *type, zval *arg, void **cache_slot, zend_class_entry *scope, bool is_return_type, bool is_internal) { zend_reference *ref = NULL; - ZEND_ASSERT(ZEND_TYPE_IS_SET(type)); + ZEND_ASSERT(ZEND_TYPE_IS_SET(*type)); if (UNEXPECTED(Z_ISREF_P(arg))) { ref = Z_REF_P(arg); arg = Z_REFVAL_P(arg); } - if (EXPECTED(ZEND_TYPE_CONTAINS_CODE(type, Z_TYPE_P(arg)))) { + if (EXPECTED(ZEND_TYPE_CONTAINS_CODE(*type, Z_TYPE_P(arg)))) { return 1; } @@ -1086,7 +1106,7 @@ static zend_always_inline bool zend_verify_recv_arg_type(zend_function *zf, uint cur_arg_info = &zf->common.arg_info[arg_num-1]; if (ZEND_TYPE_IS_SET(cur_arg_info->type) - && UNEXPECTED(!zend_check_type(cur_arg_info->type, arg, cache_slot, zf->common.scope, 0, 0))) { + && UNEXPECTED(!zend_check_type(&cur_arg_info->type, arg, cache_slot, zf->common.scope, 0, 0))) { zend_verify_arg_error(zf, cur_arg_info, arg_num, arg); return 0; } @@ -1098,7 +1118,7 @@ static zend_always_inline bool zend_verify_variadic_arg_type( zend_function *zf, zend_arg_info *arg_info, uint32_t arg_num, zval *arg, void **cache_slot) { ZEND_ASSERT(ZEND_TYPE_IS_SET(arg_info->type)); - if (UNEXPECTED(!zend_check_type(arg_info->type, arg, cache_slot, zf->common.scope, 0, 0))) { + if (UNEXPECTED(!zend_check_type(&arg_info->type, arg, cache_slot, zf->common.scope, 0, 0))) { zend_verify_arg_error(zf, arg_info, arg_num, arg); return 0; } @@ -1123,7 +1143,7 @@ static zend_never_inline ZEND_ATTRIBUTE_UNUSED bool zend_verify_internal_arg_typ } if (ZEND_TYPE_IS_SET(cur_arg_info->type) - && UNEXPECTED(!zend_check_type(cur_arg_info->type, arg, /* cache_slot */ NULL, fbc->common.scope, 0, /* is_internal */ 1))) { + && UNEXPECTED(!zend_check_type(&cur_arg_info->type, arg, /* cache_slot */ NULL, fbc->common.scope, 0, /* is_internal */ 1))) { return 0; } arg++; @@ -1256,7 +1276,7 @@ static bool zend_verify_internal_return_type(zend_function *zf, zval *ret) return 1; } - if (UNEXPECTED(!zend_check_type(ret_info->type, ret, /* cache_slot */ NULL, NULL, 1, /* is_internal */ 1))) { + if (UNEXPECTED(!zend_check_type(&ret_info->type, ret, /* cache_slot */ NULL, NULL, 1, /* is_internal */ 1))) { zend_verify_internal_return_error(zf, ret); return 0; } diff --git a/Zend/zend_inheritance.c b/Zend/zend_inheritance.c index 32d03acb4a..9266aa74d2 100644 --- a/Zend/zend_inheritance.c +++ b/Zend/zend_inheritance.c @@ -712,8 +712,12 @@ static ZEND_COLD zend_string *zend_get_function_declaration( } if (fptr->common.scope) { - /* cut off on NULL byte ... class@anonymous */ - smart_str_appendl(&str, ZSTR_VAL(fptr->common.scope->name), strlen(ZSTR_VAL(fptr->common.scope->name))); + if (fptr->common.scope->ce_flags & ZEND_ACC_ANON_CLASS) { + /* cut off on NULL byte ... class@anonymous */ + smart_str_appends(&str, ZSTR_VAL(fptr->common.scope->name)); + } else { + smart_str_appendl(&str, ZSTR_VAL(fptr->common.scope->name), ZSTR_LEN(fptr->common.scope->name)); + } smart_str_appends(&str, "::"); } diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index d09fcd39b8..98b8b51d7f 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -4227,7 +4227,7 @@ ZEND_VM_COLD_CONST_HANDLER(124, ZEND_VERIFY_RETURN_TYPE, CONST|TMP|VAR|UNUSED|CV } SAVE_OPLINE(); - if (UNEXPECTED(!zend_check_type_slow(ret_info->type, retval_ptr, ref, cache_slot, NULL, 1, 0))) { + if (UNEXPECTED(!zend_check_type_slow(&ret_info->type, retval_ptr, ref, cache_slot, NULL, 1, 0))) { zend_verify_return_error(EX(func), retval_ptr); HANDLE_EXCEPTION(); } diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index f27f3fd5e1..d680541f03 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -9777,7 +9777,7 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_VERIFY_RETURN_TYP } SAVE_OPLINE(); - if (UNEXPECTED(!zend_check_type_slow(ret_info->type, retval_ptr, ref, cache_slot, NULL, 1, 0))) { + if (UNEXPECTED(!zend_check_type_slow(&ret_info->type, retval_ptr, ref, cache_slot, NULL, 1, 0))) { zend_verify_return_error(EX(func), retval_ptr); HANDLE_EXCEPTION(); } @@ -20133,7 +20133,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_VERIFY_RETURN_TYPE_SPEC_TMP_UN } SAVE_OPLINE(); - if (UNEXPECTED(!zend_check_type_slow(ret_info->type, retval_ptr, ref, cache_slot, NULL, 1, 0))) { + if (UNEXPECTED(!zend_check_type_slow(&ret_info->type, retval_ptr, ref, cache_slot, NULL, 1, 0))) { zend_verify_return_error(EX(func), retval_ptr); HANDLE_EXCEPTION(); } @@ -27730,7 +27730,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_VERIFY_RETURN_TYPE_SPEC_VAR_UN } SAVE_OPLINE(); - if (UNEXPECTED(!zend_check_type_slow(ret_info->type, retval_ptr, ref, cache_slot, NULL, 1, 0))) { + if (UNEXPECTED(!zend_check_type_slow(&ret_info->type, retval_ptr, ref, cache_slot, NULL, 1, 0))) { zend_verify_return_error(EX(func), retval_ptr); HANDLE_EXCEPTION(); } @@ -34914,7 +34914,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_VERIFY_RETURN_TYPE_SPEC_UNUSED } SAVE_OPLINE(); - if (UNEXPECTED(!zend_check_type_slow(ret_info->type, retval_ptr, ref, cache_slot, NULL, 1, 0))) { + if (UNEXPECTED(!zend_check_type_slow(&ret_info->type, retval_ptr, ref, cache_slot, NULL, 1, 0))) { zend_verify_return_error(EX(func), retval_ptr); HANDLE_EXCEPTION(); } @@ -46624,7 +46624,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_VERIFY_RETURN_TYPE_SPEC_CV_UNU } SAVE_OPLINE(); - if (UNEXPECTED(!zend_check_type_slow(ret_info->type, retval_ptr, ref, cache_slot, NULL, 1, 0))) { + if (UNEXPECTED(!zend_check_type_slow(&ret_info->type, retval_ptr, ref, cache_slot, NULL, 1, 0))) { zend_verify_return_error(EX(func), retval_ptr); HANDLE_EXCEPTION(); } diff --git a/ext/opcache/jit/zend_jit_helpers.c b/ext/opcache/jit/zend_jit_helpers.c index 696013f60f..d46ddcd920 100644 --- a/ext/opcache/jit/zend_jit_helpers.c +++ b/ext/opcache/jit/zend_jit_helpers.c @@ -1384,6 +1384,9 @@ static zend_always_inline bool zend_jit_verify_type_common(zval *arg, zend_arg_i ZEND_TYPE_LIST_FOREACH(ZEND_TYPE_LIST(arg_info->type), list_type) { if (*cache_slot) { ce = *cache_slot; + } else if (ZEND_TYPE_HAS_CE_CACHE(*list_type) && ZEND_TYPE_CE_CACHE(*list_type)) { + ce = ZEND_TYPE_CE_CACHE(*list_type); + *cache_slot = ce; } else { ce = zend_fetch_class(ZEND_TYPE_NAME(*list_type), (ZEND_FETCH_CLASS_AUTO | ZEND_FETCH_CLASS_NO_AUTOLOAD)); @@ -1392,6 +1395,9 @@ static zend_always_inline bool zend_jit_verify_type_common(zval *arg, zend_arg_i continue; } *cache_slot = ce; + if (ZEND_TYPE_HAS_CE_CACHE(*list_type)) { + ZEND_TYPE_SET_CE_CACHE(*list_type, ce); + } } if (instanceof_function(Z_OBJCE_P(arg), ce)) { return 1; @@ -1401,12 +1407,18 @@ static zend_always_inline bool zend_jit_verify_type_common(zval *arg, zend_arg_i } else { if (EXPECTED(*cache_slot)) { ce = (zend_class_entry *) *cache_slot; + } else if (ZEND_TYPE_HAS_CE_CACHE(arg_info->type) && ZEND_TYPE_CE_CACHE(arg_info->type)) { + ce = ZEND_TYPE_CE_CACHE(arg_info->type); + *cache_slot = ce; } else { ce = zend_fetch_class(ZEND_TYPE_NAME(arg_info->type), (ZEND_FETCH_CLASS_AUTO | ZEND_FETCH_CLASS_NO_AUTOLOAD)); if (UNEXPECTED(!ce)) { goto builtin_types; } *cache_slot = (void *) ce; + if (ZEND_TYPE_HAS_CE_CACHE(arg_info->type)) { + ZEND_TYPE_SET_CE_CACHE(arg_info->type, ce); + } } if (instanceof_function(Z_OBJCE_P(arg), ce)) { return 1;