summaryrefslogtreecommitdiff
path: root/ext/opcache/zend_file_cache.c
diff options
context:
space:
mode:
authorDmitry Stogov <dmitry@zend.com>2021-02-09 22:53:57 +0300
committerDmitry Stogov <dmitry@zend.com>2021-02-09 22:53:57 +0300
commit4b79dba93202ed5640dff317046ce2fdd42e1d82 (patch)
treec9d35bb7fba407405d14e1fb8c1dd1df3e0f8da7 /ext/opcache/zend_file_cache.c
parent550aee0be3bf256fc1dec5409ad1262c96b23147 (diff)
downloadphp-git-4b79dba93202ed5640dff317046ce2fdd42e1d82.tar.gz
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.
Diffstat (limited to 'ext/opcache/zend_file_cache.c')
-rw-r--r--ext/opcache/zend_file_cache.c77
1 files changed, 44 insertions, 33 deletions
diff --git a/ext/opcache/zend_file_cache.c b/ext/opcache/zend_file_cache.c
index 62a2d261ff..56a26eec5d 100644
--- a/ext/opcache/zend_file_cache.c
+++ b/ext/opcache/zend_file_cache.c
@@ -450,6 +450,9 @@ static void zend_file_cache_serialize_op_array(zend_op_array *op_arra
zend_file_cache_metainfo *info,
void *buf)
{
+ ZEND_MAP_PTR_INIT(op_array->static_variables_ptr, NULL);
+ ZEND_MAP_PTR_INIT(op_array->run_time_cache, NULL);
+
/* Check whether this op_array has already been serialized. */
if (IS_SERIALIZED(op_array->opcodes)) {
ZEND_ASSERT(op_array->scope && "Only method op_arrays should be shared");
@@ -465,13 +468,6 @@ static void zend_file_cache_serialize_op_array(zend_op_array *op_arra
zend_file_cache_serialize_hash(ht, script, info, buf, zend_file_cache_serialize_zval);
}
- ZEND_MAP_PTR_INIT(op_array->static_variables_ptr, &op_array->static_variables);
- if (op_array->fn_flags & ZEND_ACC_IMMUTABLE) {
- ZEND_MAP_PTR_INIT(op_array->run_time_cache, NULL);
- } else {
- SERIALIZE_PTR(ZEND_MAP_PTR(op_array->run_time_cache));
- }
-
if (op_array->scope) {
if (UNEXPECTED(zend_shared_alloc_get_xlat_entry(op_array->opcodes))) {
op_array->refcount = (uint32_t*)(intptr_t)-1;
@@ -855,7 +851,8 @@ static void zend_file_cache_serialize_class(zval *zv,
SERIALIZE_PTR(ce->iterator_funcs_ptr);
}
- ZEND_MAP_PTR_INIT(ce->static_members_table, &ce->default_static_members_table);
+ ZEND_MAP_PTR_INIT(ce->static_members_table, NULL);
+ ZEND_MAP_PTR_INIT(ce->mutable_data, NULL);
}
static void zend_file_cache_serialize_warnings(
@@ -901,7 +898,6 @@ static void zend_file_cache_serialize(zend_persistent_script *script,
zend_file_cache_serialize_op_array(&new_script->script.main_op_array, script, info, buf);
zend_file_cache_serialize_warnings(new_script, info, buf);
- SERIALIZE_PTR(new_script->arena_mem);
new_script->mem = NULL;
}
@@ -1209,6 +1205,13 @@ static void zend_file_cache_unserialize_type(
zend_string *type_name = ZEND_TYPE_NAME(*type);
UNSERIALIZE_STR(type_name);
ZEND_TYPE_SET_PTR(*type, type_name);
+ if (!(script->corrupted)) {
+ // TODO: we may use single map_ptr slot for each class name ???
+ type->type_mask |= _ZEND_TYPE_CACHE_BIT;
+ type->ce_cache__ptr = (uint32_t)(uintptr_t)zend_map_ptr_new();
+ } else {
+ type->type_mask &= ~_ZEND_TYPE_CACHE_BIT;
+ }
} else if (ZEND_TYPE_HAS_CE(*type)) {
zend_class_entry *ce = ZEND_TYPE_CE(*type);
UNSERIALIZE_PTR(ce);
@@ -1220,6 +1223,26 @@ static void zend_file_cache_unserialize_op_array(zend_op_array *op_arr
zend_persistent_script *script,
void *buf)
{
+ if (!(script->corrupted)
+ && op_array != &script->script.main_op_array) {
+ op_array->fn_flags |= ZEND_ACC_IMMUTABLE;
+ if (op_array->static_variables) {
+ ZEND_MAP_PTR_NEW(op_array->static_variables_ptr);
+ } else {
+ ZEND_MAP_PTR_INIT(op_array->static_variables_ptr, &op_array->static_variables);
+ }
+ ZEND_MAP_PTR_NEW(op_array->run_time_cache);
+ } else {
+ op_array->fn_flags &= ~ZEND_ACC_IMMUTABLE;
+ ZEND_MAP_PTR_INIT(op_array->static_variables_ptr, &op_array->static_variables);
+ if (op_array != &script->script.main_op_array) {
+ ZEND_MAP_PTR_INIT(op_array->run_time_cache, zend_arena_alloc(&CG(arena), sizeof(void*)));
+ ZEND_MAP_PTR_SET(op_array->run_time_cache, NULL);
+ } else {
+ ZEND_MAP_PTR_INIT(op_array->run_time_cache, NULL);
+ }
+ }
+
/* Check whether this op_array has already been unserialized. */
if (IS_UNSERIALIZED(op_array->opcodes)) {
ZEND_ASSERT(op_array->scope && "Only method op_arrays should be shared");
@@ -1235,26 +1258,6 @@ static void zend_file_cache_unserialize_op_array(zend_op_array *op_arr
script, buf, zend_file_cache_unserialize_zval, ZVAL_PTR_DTOR);
}
- if (op_array->fn_flags & ZEND_ACC_IMMUTABLE) {
- if (op_array->static_variables) {
- ZEND_MAP_PTR_NEW(op_array->static_variables_ptr);
- } else {
- ZEND_MAP_PTR_INIT(op_array->static_variables_ptr, &op_array->static_variables);
- }
- ZEND_MAP_PTR_NEW(op_array->run_time_cache);
- } else {
- ZEND_MAP_PTR_INIT(op_array->static_variables_ptr, &op_array->static_variables);
- if (ZEND_MAP_PTR(op_array->run_time_cache)) {
- if (script->corrupted) {
- /* Not in SHM: Use serialized arena pointer. */
- UNSERIALIZE_PTR(ZEND_MAP_PTR(op_array->run_time_cache));
- } else {
- /* In SHM: Allocate new pointer. */
- ZEND_MAP_PTR_NEW(op_array->run_time_cache);
- }
- }
- }
-
if (op_array->refcount) {
op_array->refcount = NULL;
UNSERIALIZE_PTR(op_array->literals);
@@ -1605,10 +1608,20 @@ static void zend_file_cache_unserialize_class(zval *zv,
UNSERIALIZE_PTR(ce->iterator_funcs_ptr->zf_next);
}
- if (ce->ce_flags & ZEND_ACC_IMMUTABLE && ce->default_static_members_table) {
- ZEND_MAP_PTR_NEW(ce->static_members_table);
+ if (!(script->corrupted)) {
+ ce->ce_flags |= ZEND_ACC_IMMUTABLE;
+ ce->ce_flags &= ~ZEND_ACC_FILE_CACHED;
+ if (ce->ce_flags & ZEND_ACC_IMMUTABLE && ce->default_static_members_table) {
+ ZEND_MAP_PTR_NEW(ce->static_members_table);
+ } else {
+ ZEND_MAP_PTR_INIT(ce->static_members_table, &ce->default_static_members_table);
+ }
+ ZEND_MAP_PTR_NEW(ce->mutable_data);
} else {
+ ce->ce_flags &= ~ZEND_ACC_IMMUTABLE;
+ ce->ce_flags |= ZEND_ACC_FILE_CACHED;
ZEND_MAP_PTR_INIT(ce->static_members_table, &ce->default_static_members_table);
+ ZEND_MAP_PTR_INIT(ce->mutable_data, NULL);
}
}
@@ -1637,8 +1650,6 @@ static void zend_file_cache_unserialize(zend_persistent_script *script,
script, buf, zend_file_cache_unserialize_func, ZEND_FUNCTION_DTOR);
zend_file_cache_unserialize_op_array(&script->script.main_op_array, script, buf);
zend_file_cache_unserialize_warnings(script, buf);
-
- UNSERIALIZE_PTR(script->arena_mem);
}
zend_persistent_script *zend_file_cache_script_load(zend_file_handle *file_handle)