From 4b79dba93202ed5640dff317046ce2fdd42e1d82 Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Tue, 9 Feb 2021 22:53:57 +0300 Subject: Added Inheritance Cache. This is a new transparent technology that eliminates overhead of PHP class inheritance. PHP classes are compiled and cached (by opcahce) separately, however their "linking" was done at run-time - on each request. The process of "linking" may involve a number of compatibility checks and borrowing methods/properties/constants form parent and traits. This takes significant time, but the result is the same on each request. Inheritance Cache performs "linking" for unique set of all the depending classes (parent, interfaces, traits, property types, method types involved into compatibility checks) once and stores result in opcache shared memory. As a part of the this patch, I removed limitations for immutable classes (unresolved constants, typed properties and covariant type checks). So now all classes stored in opcache are "immutable". They may be lazily loaded into process memory, if necessary, but this usually occurs just once (on first linking). The patch shows 8% improvement on Symphony "Hello World" app. --- Zend/zend_execute_API.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) (limited to 'Zend/zend_execute_API.c') diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index 4a6ff1bdbc..7c32f3a7fb 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -295,9 +295,15 @@ void shutdown_executor(void) /* {{{ */ } ZEND_HASH_FOREACH_END(); ZEND_HASH_REVERSE_FOREACH_VAL(EG(class_table), zv) { zend_class_entry *ce = Z_PTR_P(zv); + if (ce->default_static_members_count) { zend_cleanup_internal_class_data(ce); } + + if (ZEND_MAP_PTR(ce->mutable_data) && ZEND_MAP_PTR_GET_IMM(ce->mutable_data)) { + zend_cleanup_mutable_class_data(ce); + } + if (ce->ce_flags & ZEND_HAS_STATIC_IN_METHODS) { zend_op_array *op_array; ZEND_HASH_FOREACH_PTR(&ce->function_table, op_array) { @@ -1059,7 +1065,15 @@ ZEND_API zend_class_entry *zend_lookup_class_ex(zend_string *name, zend_string * if ((flags & ZEND_FETCH_CLASS_ALLOW_UNLINKED) || ((flags & ZEND_FETCH_CLASS_ALLOW_NEARLY_LINKED) && (ce->ce_flags & ZEND_ACC_NEARLY_LINKED))) { - ce->ce_flags |= ZEND_ACC_HAS_UNLINKED_USES; + if (ce->ce_flags & ZEND_ACC_IMMUTABLE) { + if (!CG(unlinked_uses)) { + ALLOC_HASHTABLE(CG(unlinked_uses)); + zend_hash_init(CG(unlinked_uses), 0, NULL, NULL, 0); + } + zend_hash_index_add_empty_element(CG(unlinked_uses), (zend_long)(zend_uintptr_t)ce); + } else { + ce->ce_flags |= ZEND_ACC_HAS_UNLINKED_USES; + } return ce; } return NULL; -- cgit v1.2.1