]> granicus.if.org Git - php/commitdiff
Added Inheritance Cache.
authorDmitry Stogov <dmitry@zend.com>
Tue, 9 Feb 2021 19:53:57 +0000 (22:53 +0300)
committerDmitry Stogov <dmitry@zend.com>
Tue, 9 Feb 2021 19:53:57 +0000 (22:53 +0300)
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.

41 files changed:
NEWS
Zend/tests/anon/015.phpt [new file with mode: 0644]
Zend/tests/anon/016.phpt [new file with mode: 0644]
Zend/zend.c
Zend/zend.h
Zend/zend_API.c
Zend/zend_API.h
Zend/zend_builtin_functions.c
Zend/zend_compile.c
Zend/zend_compile.h
Zend/zend_constants.c
Zend/zend_execute.c
Zend/zend_execute_API.c
Zend/zend_globals.h
Zend/zend_inheritance.c
Zend/zend_inheritance.h
Zend/zend_map_ptr.h
Zend/zend_opcode.c
Zend/zend_types.h
Zend/zend_vm_def.h
Zend/zend_vm_execute.h
ext/opcache/ZendAccelerator.c
ext/opcache/ZendAccelerator.h
ext/opcache/jit/zend_jit_x86.dasc
ext/opcache/tests/bug78014.phpt
ext/opcache/tests/preload_004.phpt
ext/opcache/tests/preload_009.phpt
ext/opcache/tests/preload_012.phpt
ext/opcache/tests/preload_ind.phpt
ext/opcache/tests/preload_loadable_classes_2.phpt
ext/opcache/tests/preload_loadable_classes_3.phpt
ext/opcache/tests/preload_unresolved_prop_type.phpt
ext/opcache/zend_accelerator_util_funcs.c
ext/opcache/zend_file_cache.c
ext/opcache/zend_persist.c
ext/opcache/zend_persist.h
ext/opcache/zend_persist_calc.c
ext/opcache/zend_shared_alloc.c
ext/opcache/zend_shared_alloc.h
ext/reflection/php_reflection.c
main/main.c

diff --git a/NEWS b/NEWS
index 14b189c1a114fbe3eb849206f2be1edf044fbc74..5d6db8eb520e823607812e5f99422430560ef419 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -21,6 +21,9 @@ PHP                                                                        NEWS
   . Fixed bug #80330 (Replace language in APIs and source code/docs).
     (Darek Ćšlusarczyk)
 
+- Opcache:
+  . Added inheritance cache. (Dmitry)
+
 - OpenSSL:
   . Bump minimal OpenSSL version to 1.0.2. (Jakub Zelenka)
 
diff --git a/Zend/tests/anon/015.phpt b/Zend/tests/anon/015.phpt
new file mode 100644 (file)
index 0000000..324ebe8
--- /dev/null
@@ -0,0 +1,33 @@
+--TEST--
+static variables in methods inherited from parent class
+--FILE--
+<?php
+class C {
+    function foo ($y = null) {
+        static $x = null;
+        if (!is_null($y)) {
+            $x = [$y];
+        }
+        return $x;
+    }
+}
+$c = new C();
+$c->foo(42);
+$d = new class extends C {};
+var_dump($d->foo());
+var_dump($d->foo(24));
+var_dump($c->foo());
+?>
+--EXPECT--
+array(1) {
+  [0]=>
+  int(42)
+}
+array(1) {
+  [0]=>
+  int(24)
+}
+array(1) {
+  [0]=>
+  int(42)
+}
diff --git a/Zend/tests/anon/016.phpt b/Zend/tests/anon/016.phpt
new file mode 100644 (file)
index 0000000..4cde6df
--- /dev/null
@@ -0,0 +1,35 @@
+--TEST--
+static variables in methods inherited from parent class (can't cache objects)
+--FILE--
+<?php
+class C {
+    function foo ($y = null) {
+        static $x = null;
+        if (!is_null($y)) {
+            $x = [$y];
+        }
+        return $x;
+    }
+}
+$c = new C();
+$c->foo(new stdClass);
+$d = new class extends C {};
+var_dump($d->foo());
+var_dump($d->foo(24));
+var_dump($c->foo());
+?>
+--EXPECT--
+array(1) {
+  [0]=>
+  object(stdClass)#2 (0) {
+  }
+}
+array(1) {
+  [0]=>
+  int(24)
+}
+array(1) {
+  [0]=>
+  object(stdClass)#2 (0) {
+  }
+}
index 4da7991db6d3b46120b881e6e2aad711ab11580f..45183226227bef1a439602f737624bca16c7b767 100644 (file)
@@ -660,6 +660,7 @@ static void compiler_globals_ctor(zend_compiler_globals *compiler_globals) /* {{
        zend_hash_copy(compiler_globals->auto_globals, global_auto_globals_table, auto_global_copy_ctor);
 
        compiler_globals->script_encoding_list = NULL;
+       compiler_globals->current_linking_class = NULL;
 
 #if ZEND_MAP_PTR_KIND == ZEND_MAP_PTR_KIND_PTR_OR_OFFSET
        /* Map region is going to be created and resized at run-time. */
index 6a2a834d93c0a1982a945cc3d3e4244173866c15..44f3baac46ed3cb9d62986d9ac4f8330e1982a51 100644 (file)
@@ -107,6 +107,28 @@ typedef struct _zend_trait_alias {
        uint32_t modifiers;
 } zend_trait_alias;
 
+typedef struct _zend_class_mutable_data {
+       zval      *default_properties_table;
+       HashTable *constants_table;
+       uint32_t   ce_flags;
+} zend_class_mutable_data;
+
+typedef struct _zend_class_dependency {
+       zend_string      *name;
+       zend_class_entry *ce;
+} zend_class_dependency;
+
+typedef struct _zend_inheritance_cache_entry zend_inheritance_cache_entry;
+
+struct _zend_inheritance_cache_entry {
+       zend_inheritance_cache_entry *next;
+       zend_class_entry             *ce;
+       zend_class_entry             *parent;
+       zend_class_dependency        *dependencies;
+       uint32_t                      dependencies_count;
+       zend_class_entry             *traits_and_interfaces[1];
+};
+
 struct _zend_class_entry {
        char type;
        zend_string *name;
@@ -127,6 +149,9 @@ struct _zend_class_entry {
        HashTable properties_info;
        HashTable constants_table;
 
+       ZEND_MAP_PTR_DEF(zend_class_mutable_data*, mutable_data);
+       zend_inheritance_cache_entry *inheritance_cache;
+
        struct _zend_property_info **properties_info_table;
 
        zend_function *constructor;
index 5f558c493031d071ab7118f37b1276f39a640721..abfbb411a53dbb6c678874e20e302419714224a2 100644 (file)
@@ -1213,39 +1213,147 @@ ZEND_API void zend_merge_properties(zval *obj, HashTable *properties) /* {{{ */
 }
 /* }}} */
 
+static zend_class_mutable_data *zend_allocate_mutable_data(zend_class_entry *class_type) /* {{{ */
+{
+       zend_class_mutable_data *mutable_data;
+
+       ZEND_ASSERT(class_type->ce_flags & ZEND_ACC_IMMUTABLE);
+       ZEND_ASSERT(ZEND_MAP_PTR(class_type->mutable_data) != NULL);
+       ZEND_ASSERT(ZEND_MAP_PTR_GET_IMM(class_type->mutable_data) == NULL);
+
+       mutable_data = zend_arena_alloc(&CG(arena), sizeof(zend_class_mutable_data));
+       memset(mutable_data, 0, sizeof(zend_class_mutable_data));
+       mutable_data->ce_flags = class_type->ce_flags;
+       ZEND_MAP_PTR_SET_IMM(class_type->mutable_data, mutable_data);
+
+       return mutable_data;
+}
+/* }}} */
+
+ZEND_API HashTable *zend_separate_class_constants_table(zend_class_entry *class_type) /* {{{ */
+{
+       zend_class_mutable_data *mutable_data;
+       HashTable *constants_table;
+       zend_string *key;
+       zend_class_constant *new_c, *c;
+
+       constants_table = zend_arena_alloc(&CG(arena), sizeof(HashTable));
+       zend_hash_init(constants_table, zend_hash_num_elements(&class_type->constants_table), NULL, NULL, 0);
+       zend_hash_extend(constants_table, zend_hash_num_elements(&class_type->constants_table), 0);
+
+       ZEND_HASH_FOREACH_STR_KEY_PTR(&class_type->constants_table, key, c) {
+               if (Z_TYPE(c->value) == IS_CONSTANT_AST) {
+                       new_c = zend_arena_alloc(&CG(arena), sizeof(zend_class_constant));
+                       memcpy(new_c, c, sizeof(zend_class_constant));
+                       c = new_c;
+               }
+               _zend_hash_append_ptr(constants_table, key, c);
+       } ZEND_HASH_FOREACH_END();
+
+       ZEND_ASSERT(class_type->ce_flags & ZEND_ACC_IMMUTABLE);
+       ZEND_ASSERT(ZEND_MAP_PTR(class_type->mutable_data) != NULL);
+
+       mutable_data = ZEND_MAP_PTR_GET_IMM(class_type->mutable_data);
+       if (!mutable_data) {
+               mutable_data = zend_allocate_mutable_data(class_type);
+       }
+
+       mutable_data->constants_table = constants_table;
+
+       return constants_table;
+}
+
 ZEND_API zend_result zend_update_class_constants(zend_class_entry *class_type) /* {{{ */
 {
-       if (!(class_type->ce_flags & ZEND_ACC_CONSTANTS_UPDATED)) {
-               zend_class_constant *c;
-               zval *val;
-               zend_property_info *prop_info;
+       zend_class_mutable_data *mutable_data = NULL;
+       zval *default_properties_table = NULL;
+       zval *static_members_table = NULL;
+       zend_class_constant *c;
+       zval *val;
+       zend_property_info *prop_info;
+       uint32_t ce_flags;
 
-               if (class_type->parent) {
-                       if (UNEXPECTED(zend_update_class_constants(class_type->parent) != SUCCESS)) {
-                               return FAILURE;
+       ce_flags = class_type->ce_flags;
+
+       if (ce_flags & ZEND_ACC_CONSTANTS_UPDATED) {
+               return SUCCESS;
+       }
+
+       if (ce_flags & ZEND_ACC_IMMUTABLE) {
+               mutable_data = ZEND_MAP_PTR_GET_IMM(class_type->mutable_data);
+               if (mutable_data) {
+                       ce_flags = mutable_data->ce_flags;
+                       if (ce_flags & ZEND_ACC_CONSTANTS_UPDATED) {
+                               return SUCCESS;
                        }
+               } else {
+                       mutable_data = zend_allocate_mutable_data(class_type);
                }
+       }
 
-               ZEND_HASH_FOREACH_PTR(&class_type->constants_table, c) {
-                       val = &c->value;
-                       if (Z_TYPE_P(val) == IS_CONSTANT_AST) {
+       if (class_type->parent) {
+               if (UNEXPECTED(zend_update_class_constants(class_type->parent) != SUCCESS)) {
+                       return FAILURE;
+               }
+       }
+
+       if (ce_flags & ZEND_ACC_HAS_AST_CONSTANTS) {
+               HashTable *constants_table;
+
+               if (ce_flags & ZEND_ACC_IMMUTABLE) {
+                       constants_table = mutable_data->constants_table;
+                       if (!constants_table) {
+                               constants_table = zend_separate_class_constants_table(class_type);
+                       }
+               } else {
+                       constants_table = &class_type->constants_table;
+               }
+               ZEND_HASH_FOREACH_PTR(constants_table, c) {
+                       if (Z_TYPE(c->value) == IS_CONSTANT_AST) {
+                               val = &c->value;
                                if (UNEXPECTED(zval_update_constant_ex(val, c->ce) != SUCCESS)) {
                                        return FAILURE;
                                }
                        }
                } ZEND_HASH_FOREACH_END();
+       }
 
-               if (class_type->default_static_members_count && !CE_STATIC_MEMBERS(class_type)) {
-                       if (class_type->type == ZEND_INTERNAL_CLASS || (class_type->ce_flags & (ZEND_ACC_IMMUTABLE|ZEND_ACC_PRELOADED))) {
+       if (class_type->default_static_members_count) {
+               static_members_table = CE_STATIC_MEMBERS(class_type);
+               if (!static_members_table) {
+                       if (class_type->type == ZEND_INTERNAL_CLASS || (ce_flags & (ZEND_ACC_IMMUTABLE|ZEND_ACC_PRELOADED))) {
                                zend_class_init_statics(class_type);
+                               static_members_table = CE_STATIC_MEMBERS(class_type);
                        }
                }
+       }
+
+       default_properties_table = class_type->default_properties_table;
+       if ((ce_flags & ZEND_ACC_IMMUTABLE)
+        && (ce_flags & ZEND_ACC_HAS_AST_PROPERTIES)) {
+               zval *src, *dst, *end;
+
+               default_properties_table = mutable_data->default_properties_table;
+               if (!default_properties_table) {
+                       default_properties_table = zend_arena_alloc(&CG(arena), sizeof(zval) * class_type->default_properties_count);
+                       src = class_type->default_properties_table;
+                       dst = default_properties_table;
+                       end = dst + class_type->default_properties_count;
+                       do {
+                               ZVAL_COPY_VALUE_PROP(dst, src);
+                               src++;
+                               dst++;
+                       } while (dst != end);
+                       mutable_data->default_properties_table = default_properties_table;
+               }
+       }
 
+       if (ce_flags & (ZEND_ACC_HAS_AST_PROPERTIES|ZEND_ACC_HAS_AST_STATICS)) {
                ZEND_HASH_FOREACH_PTR(&class_type->properties_info, prop_info) {
                        if (prop_info->flags & ZEND_ACC_STATIC) {
-                               val = CE_STATIC_MEMBERS(class_type) + prop_info->offset;
+                               val = static_members_table + prop_info->offset;
                        } else {
-                               val = (zval*)((char*)class_type->default_properties_table + prop_info->offset - OBJ_PROP_TO_OFFSET(0));
+                               val = (zval*)((char*)default_properties_table + prop_info->offset - OBJ_PROP_TO_OFFSET(0));
                        }
                        if (Z_TYPE_P(val) == IS_CONSTANT_AST) {
                                if (ZEND_TYPE_IS_SET(prop_info->type)) {
@@ -1268,8 +1376,21 @@ ZEND_API zend_result zend_update_class_constants(zend_class_entry *class_type) /
                                }
                        }
                } ZEND_HASH_FOREACH_END();
+       }
 
-               class_type->ce_flags |= ZEND_ACC_CONSTANTS_UPDATED;
+       ce_flags |= ZEND_ACC_CONSTANTS_UPDATED;
+       ce_flags &= ~ZEND_ACC_HAS_AST_CONSTANTS;
+       ce_flags &= ~ZEND_ACC_HAS_AST_PROPERTIES;
+       if (class_type->ce_flags & ZEND_ACC_IMMUTABLE) {
+               ce_flags &= ~ZEND_ACC_HAS_AST_STATICS;
+               if (mutable_data) {
+                       mutable_data->ce_flags = ce_flags;
+               }
+       } else {
+               if (!(ce_flags & ZEND_ACC_PRELOADED)) {
+                       ce_flags &= ~ZEND_ACC_HAS_AST_STATICS;
+               }
+               class_type->ce_flags = ce_flags;
        }
 
        return SUCCESS;
@@ -1279,7 +1400,7 @@ ZEND_API zend_result zend_update_class_constants(zend_class_entry *class_type) /
 static zend_always_inline void _object_properties_init(zend_object *object, zend_class_entry *class_type) /* {{{ */
 {
        if (class_type->default_properties_count) {
-               zval *src = class_type->default_properties_table;
+               zval *src = CE_DEFAULT_PROPERTIES_TABLE(class_type);
                zval *dst = object->properties_table;
                zval *end = src + class_type->default_properties_count;
 
@@ -3809,6 +3930,11 @@ ZEND_API zend_property_info *zend_declare_typed_property(zend_class_entry *ce, z
                property_info = zend_arena_alloc(&CG(arena), sizeof(zend_property_info));
                if (Z_TYPE_P(property) == IS_CONSTANT_AST) {
                        ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
+                       if (access_type & ZEND_ACC_STATIC) {
+                               ce->ce_flags |= ZEND_ACC_HAS_AST_STATICS;
+                       } else {
+                               ce->ce_flags |= ZEND_ACC_HAS_AST_PROPERTIES;
+                       }
                }
        }
 
@@ -4124,6 +4250,7 @@ ZEND_API zend_class_constant *zend_declare_class_constant_ex(zend_class_entry *c
        c->ce = ce;
        if (Z_TYPE_P(value) == IS_CONSTANT_AST) {
                ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
+               ce->ce_flags |= ZEND_ACC_HAS_AST_CONSTANTS;
        }
 
        if (!zend_hash_add_ptr(&ce->constants_table, name, c)) {
index 89eb6312d697c407d25f51913480ca2a20b84bff..6c867b2869f578a844ff84626fde276fd651de79 100644 (file)
@@ -278,6 +278,12 @@ typedef struct _zend_fcall_info_cache {
 #define CE_STATIC_MEMBERS(ce) \
        ((zval*)ZEND_MAP_PTR_GET((ce)->static_members_table))
 
+#define CE_CONSTANTS_TABLE(ce) \
+       zend_class_constants_table(ce)
+
+#define CE_DEFAULT_PROPERTIES_TABLE(ce) \
+       zend_class_default_properties_table(ce)
+
 #define ZEND_FCI_INITIALIZED(fci) ((fci).size != 0)
 
 ZEND_API int zend_next_free_module(void);
@@ -382,6 +388,33 @@ ZEND_API void zend_declare_class_constant_stringl(zend_class_entry *ce, const ch
 ZEND_API void zend_declare_class_constant_string(zend_class_entry *ce, const char *name, size_t name_length, const char *value);
 
 ZEND_API zend_result zend_update_class_constants(zend_class_entry *class_type);
+ZEND_API HashTable *zend_separate_class_constants_table(zend_class_entry *class_type);
+
+static zend_always_inline HashTable *zend_class_constants_table(zend_class_entry *ce) {
+       if ((ce->ce_flags & ZEND_ACC_HAS_AST_CONSTANTS)
+        && (ce->ce_flags & ZEND_ACC_IMMUTABLE)) {
+               zend_class_mutable_data *mutable_data =
+                       (zend_class_mutable_data*)ZEND_MAP_PTR_GET_IMM(ce->mutable_data);
+               if (mutable_data && mutable_data->constants_table) {
+                       return mutable_data->constants_table;
+               } else {
+                       return zend_separate_class_constants_table(ce);
+               }
+       } else {
+               return &ce->constants_table;
+       }
+}
+
+static zend_always_inline zval *zend_class_default_properties_table(zend_class_entry *ce) {
+       if ((ce->ce_flags & ZEND_ACC_HAS_AST_PROPERTIES)
+        && (ce->ce_flags & ZEND_ACC_IMMUTABLE)) {
+               zend_class_mutable_data *mutable_data =
+                       (zend_class_mutable_data*)ZEND_MAP_PTR_GET_IMM(ce->mutable_data);
+               return mutable_data->default_properties_table;
+       } else {
+               return ce->default_properties_table;
+       }
+}
 
 ZEND_API void zend_update_property_ex(zend_class_entry *scope, zend_object *object, zend_string *name, zval *value);
 ZEND_API void zend_update_property(zend_class_entry *scope, zend_object *object, const char *name, size_t name_length, zval *value);
index fa65d1ca074254974f1351a9e1f99683783bb3cc..afabfa97f32c8792d9f3762aa56e9ed1e3319d98 100644 (file)
@@ -703,6 +703,7 @@ static void add_class_vars(zend_class_entry *scope, zend_class_entry *ce, bool s
        zend_property_info *prop_info;
        zval *prop, prop_copy;
        zend_string *key;
+       zval *default_properties_table = CE_DEFAULT_PROPERTIES_TABLE(ce);
 
        ZEND_HASH_FOREACH_STR_KEY_PTR(&ce->properties_info, key, prop_info) {
                if (((prop_info->flags & ZEND_ACC_PROTECTED) &&
@@ -716,7 +717,7 @@ static void add_class_vars(zend_class_entry *scope, zend_class_entry *ce, bool s
                        prop = &ce->default_static_members_table[prop_info->offset];
                        ZVAL_DEINDIRECT(prop);
                } else if (!statics && (prop_info->flags & ZEND_ACC_STATIC) == 0) {
-                       prop = &ce->default_properties_table[OBJ_PROP_TO_NUM(prop_info->offset)];
+                       prop = &default_properties_table[OBJ_PROP_TO_NUM(prop_info->offset)];
                }
                if (!prop) {
                        continue;
@@ -734,7 +735,7 @@ static void add_class_vars(zend_class_entry *scope, zend_class_entry *ce, bool s
                /* this is necessary to make it able to work with default array
                 * properties, returned to user */
                if (Z_OPT_TYPE_P(prop) == IS_CONSTANT_AST) {
-                       if (UNEXPECTED(zval_update_constant_ex(prop, NULL) != SUCCESS)) {
+                       if (UNEXPECTED(zval_update_constant_ex(prop, ce) != SUCCESS)) {
                                return;
                        }
                }
index 65fa1862344e0692d03bd4f956768e7b83733e26..d617547f81ef6f0706fdc6c951f1d059499579af 100644 (file)
@@ -417,6 +417,8 @@ void init_compiler(void) /* {{{ */
 
        CG(delayed_variance_obligations) = NULL;
        CG(delayed_autoloads) = NULL;
+       CG(unlinked_uses) = NULL;
+       CG(current_linking_class) = NULL;
 }
 /* }}} */
 
@@ -428,7 +430,6 @@ void shutdown_compiler(void) /* {{{ */
        zend_stack_destroy(&CG(loop_var_stack));
        zend_stack_destroy(&CG(delayed_oplines_stack));
        zend_stack_destroy(&CG(short_circuiting_opnums));
-       zend_arena_destroy(CG(arena));
 
        if (CG(delayed_variance_obligations)) {
                zend_hash_destroy(CG(delayed_variance_obligations));
@@ -440,6 +441,12 @@ void shutdown_compiler(void) /* {{{ */
                FREE_HASHTABLE(CG(delayed_autoloads));
                CG(delayed_autoloads) = NULL;
        }
+       if (CG(unlinked_uses)) {
+               zend_hash_destroy(CG(unlinked_uses));
+               FREE_HASHTABLE(CG(unlinked_uses));
+               CG(unlinked_uses) = NULL;
+       }
+       CG(current_linking_class) = NULL;
 }
 /* }}} */
 
@@ -1136,7 +1143,8 @@ ZEND_API zend_result do_bind_class(zval *lcname, zend_string *lc_parent_name) /*
                return FAILURE;
        }
 
-       if (zend_do_link_class(ce, lc_parent_name) == FAILURE) {
+       ce = zend_do_link_class(ce, lc_parent_name, Z_STR_P(lcname));
+       if (!ce) {
                /* Reload bucket pointer, the hash table may have been reallocated */
                zv = zend_hash_find(EG(class_table), Z_STR_P(lcname));
                zend_hash_set_bucket_key(EG(class_table), (Bucket *) zv, Z_STR_P(rtd_key));
@@ -1187,13 +1195,23 @@ zend_string *zend_type_to_string_resolved(zend_type type, zend_class_entry *scop
                        if (ZEND_TYPE_HAS_CE(*list_type)) {
                                str = add_type_string(str, ZEND_TYPE_CE(*list_type)->name);
                        } else {
-                               zend_string *resolved = resolve_class_name(ZEND_TYPE_NAME(*list_type), scope);
-                               str = add_type_string(str, resolved);
-                               zend_string_release(resolved);
+                               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);
+                               } else {
+                                       zend_string *resolved = resolve_class_name(ZEND_TYPE_NAME(*list_type), scope);
+                                       str = add_type_string(str, resolved);
+                                       zend_string_release(resolved);
+                               }
                        }
                } ZEND_TYPE_LIST_FOREACH_END();
        } else if (ZEND_TYPE_HAS_NAME(type)) {
-               str = resolve_class_name(ZEND_TYPE_NAME(type), scope);
+               if (ZEND_TYPE_HAS_CE_CACHE(type)
+                && ZEND_TYPE_CE_CACHE(type)) {
+                       str = zend_string_copy(ZEND_TYPE_CE_CACHE(type)->name);
+               } else {
+                       str = resolve_class_name(ZEND_TYPE_NAME(type), scope);
+               }
        } else if (ZEND_TYPE_HAS_CE(type)) {
                str = zend_string_copy(ZEND_TYPE_CE(type)->name);
        }
@@ -1354,7 +1372,8 @@ ZEND_API void zend_do_delayed_early_binding(zend_op_array *op_array, uint32_t fi
                                zend_class_entry *parent_ce = zend_hash_find_ex_ptr(EG(class_table), lc_parent_name, 1);
 
                                if (parent_ce) {
-                                       if (zend_try_early_bind(ce, parent_ce, Z_STR_P(lcname), zv)) {
+                                       ce = zend_try_early_bind(ce, parent_ce, Z_STR_P(lcname), zv);
+                                       if (ce) {
                                                /* Store in run-time cache */
                                                ((void**)((char*)run_time_cache + opline->extended_value))[0] = ce;
                                        }
@@ -1831,6 +1850,7 @@ ZEND_API void zend_initialize_class_data(zend_class_entry *ce, bool nullify_hand
                ZEND_MAP_PTR_INIT(ce->static_members_table, &ce->default_static_members_table);
                ce->info.user.doc_comment = NULL;
        }
+       ZEND_MAP_PTR_INIT(ce->mutable_data, NULL);
 
        ce->default_properties_count = 0;
        ce->default_static_members_count = 0;
index ffc2f7baa4528604fbf0bbf4ea78e2a26b65ab68..fbab084b2b4171fbd45c091e13c77129b960440c 100644 (file)
@@ -233,7 +233,7 @@ typedef struct _zend_oparray_context {
 /* op_array or class is preloaded                         |     |     |     */
 #define ZEND_ACC_PRELOADED               (1 << 10) /*  X  |  X  |     |     */
 /*                                                        |     |     |     */
-/* Class Flags (unused: 23...)                            |     |     |     */
+/* Class Flags (unused: 28...)                            |     |     |     */
 /* ===========                                            |     |     |     */
 /*                                                        |     |     |     */
 /* Special class types                                    |     |     |     */
@@ -285,6 +285,16 @@ typedef struct _zend_oparray_context {
 /* stored in opcache (may be partially)                   |     |     |     */
 #define ZEND_ACC_CACHED                  (1 << 22) /*  X  |     |     |     */
 /*                                                        |     |     |     */
+/* temporary flag used during delayed variance checks     |     |     |     */
+#define ZEND_ACC_CACHEABLE               (1 << 23) /*  X  |     |     |     */
+/*                                                        |     |     |     */
+#define ZEND_ACC_HAS_AST_CONSTANTS       (1 << 24) /*  X  |     |     |     */
+#define ZEND_ACC_HAS_AST_PROPERTIES      (1 << 25) /*  X  |     |     |     */
+#define ZEND_ACC_HAS_AST_STATICS         (1 << 26) /*  X  |     |     |     */
+/*                                                        |     |     |     */
+/* loaded from file cache to process memory               |     |     |     */
+#define ZEND_ACC_FILE_CACHED             (1 << 27) /*  X  |     |     |     */
+/*                                                        |     |     |     */
 /* Function Flags (unused: 27-30)                         |     |     |     */
 /* ==============                                         |     |     |     */
 /*                                                        |     |     |     */
@@ -802,6 +812,7 @@ ZEND_API int open_file_for_scanning(zend_file_handle *file_handle);
 ZEND_API void init_op_array(zend_op_array *op_array, zend_uchar type, int initial_ops_size);
 ZEND_API void destroy_op_array(zend_op_array *op_array);
 ZEND_API void zend_destroy_file_handle(zend_file_handle *file_handle);
+ZEND_API void zend_cleanup_mutable_class_data(zend_class_entry *ce);
 ZEND_API void zend_cleanup_internal_class_data(zend_class_entry *ce);
 ZEND_API void zend_cleanup_internal_classes(void);
 ZEND_API void zend_type_release(zend_type type, bool persistent);
index 03ab10b5232cba2cf65c370249c6cfe7ca8e983e..9534190f8dfced23f492b7c9d2f06cd9fbdd1034 100644 (file)
@@ -374,7 +374,7 @@ ZEND_API zval *zend_get_constant_ex(zend_string *cname, zend_class_entry *scope,
                        ce = zend_fetch_class(class_name, flags);
                }
                if (ce) {
-                       c = zend_hash_find_ptr(&ce->constants_table, constant_name);
+                       c = zend_hash_find_ptr(CE_CONSTANTS_TABLE(ce), constant_name);
                        if (c == NULL) {
                                if ((flags & ZEND_FETCH_CLASS_SILENT) == 0) {
                                        zend_throw_error(NULL, "Undefined constant %s::%s", ZSTR_VAL(class_name), ZSTR_VAL(constant_name));
index 93cee93dbd36c1b245f8f1bed90bfbca1110791e..5338a0ae43bd3213923865d757f216da79a02dfd 100644 (file)
@@ -857,7 +857,17 @@ 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_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 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) {
@@ -874,7 +884,17 @@ static bool zend_check_and_resolve_property_class_type(
                } ZEND_TYPE_LIST_FOREACH_END();
                return 0;
        } else {
-               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 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)) {
index 4a6ff1bdbc573360eb7e5798266bba54545667d1..7c32f3a7fbf559165051db10c3ebb87031be6baa 100644 (file)
@@ -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;
index 6d67325fe1068ae848918f6d280273785565de2b..73dac228cceb85358372126c90b69b929862e952 100644 (file)
@@ -126,6 +126,8 @@ struct _zend_compiler_globals {
 
        HashTable *delayed_variance_obligations;
        HashTable *delayed_autoloads;
+       HashTable *unlinked_uses;
+       zend_class_entry *current_linking_class;
 
        uint32_t rtd_key_counter;
 
index 16e31a10d8744160967cdffdea83774e7f31c444..32d03acb4aef59b56bc419422a64432af73bb35d 100644 (file)
@@ -27,6 +27,9 @@
 #include "zend_operators.h"
 #include "zend_exceptions.h"
 
+ZEND_API zend_class_entry* (*zend_inheritance_cache_get)(zend_class_entry *ce, zend_class_entry *parent, zend_class_entry **traits_and_interfaces) = NULL;
+ZEND_API zend_class_entry* (*zend_inheritance_cache_add)(zend_class_entry *ce, zend_class_entry *proto, zend_class_entry *parent, zend_class_entry **traits_and_interfaces, HashTable *dependencies) = NULL;
+
 static void add_dependency_obligation(zend_class_entry *ce, zend_class_entry *dependency_ce);
 static void add_compatibility_obligation(
                zend_class_entry *ce, const zend_function *child_fn, zend_class_entry *child_scope,
@@ -368,6 +371,47 @@ typedef enum {
        INHERITANCE_SUCCESS = 1,
 } inheritance_status;
 
+
+static void track_class_dependency(zend_class_entry *ce, zend_string *class_name)
+{
+       HashTable *ht;
+
+       if (!CG(current_linking_class) || ce == CG(current_linking_class)) {
+               return;
+       } else if (!class_name) {
+               class_name = ce->name;
+       } else if (zend_string_equals_literal_ci(class_name, "self")
+               || zend_string_equals_literal_ci(class_name, "parent")) {
+               return;
+       }
+
+       ht = (HashTable*)CG(current_linking_class)->inheritance_cache;
+
+#ifndef ZEND_WIN32
+       if (ce->type == ZEND_USER_CLASS && !(ce->ce_flags & ZEND_ACC_IMMUTABLE)) {
+#else
+       if (!(ce->ce_flags & ZEND_ACC_IMMUTABLE)) {
+#endif
+               // TODO: dependency on not-immutable class ???
+               if (ht) {
+                       zend_hash_destroy(ht);
+                       FREE_HASHTABLE(ht);
+                       CG(current_linking_class)->inheritance_cache = NULL;
+               }
+               CG(current_linking_class)->ce_flags &= ~ZEND_ACC_CACHEABLE;
+               CG(current_linking_class) = NULL;
+               return;
+       }
+
+       /* Record dependency */
+       if (!ht) {
+               ALLOC_HASHTABLE(ht);
+               zend_hash_init(ht, 0, NULL, NULL, 0);
+               CG(current_linking_class)->inheritance_cache = (zend_inheritance_cache_entry*)ht;
+       }
+       zend_hash_add_ptr(ht, class_name, ce);
+}
+
 static inheritance_status zend_perform_covariant_class_type_check(
                zend_class_entry *fe_scope, zend_string *fe_class_name, zend_class_entry *fe_ce,
                zend_class_entry *proto_scope, zend_type proto_type,
@@ -381,6 +425,7 @@ static inheritance_status zend_perform_covariant_class_type_check(
                if (!fe_ce) {
                        have_unresolved = 1;
                } else {
+                       track_class_dependency(fe_ce, fe_class_name);
                        return INHERITANCE_SUCCESS;
                }
        }
@@ -389,6 +434,7 @@ static inheritance_status zend_perform_covariant_class_type_check(
                if (!fe_ce) {
                        have_unresolved = 1;
                } else if (unlinked_instanceof(fe_ce, zend_ce_traversable)) {
+                       track_class_dependency(fe_ce, fe_class_name);
                        return INHERITANCE_SUCCESS;
                }
        }
@@ -396,8 +442,9 @@ static inheritance_status zend_perform_covariant_class_type_check(
        zend_type *single_type;
        ZEND_TYPE_FOREACH(proto_type, single_type) {
                zend_class_entry *proto_ce;
+               zend_string *proto_class_name = NULL;
                if (ZEND_TYPE_HAS_NAME(*single_type)) {
-                       zend_string *proto_class_name =
+                       proto_class_name =
                                resolve_class_name(proto_scope, ZEND_TYPE_NAME(*single_type));
                        if (zend_string_equals_ci(fe_class_name, proto_class_name)) {
                                return INHERITANCE_SUCCESS;
@@ -416,6 +463,8 @@ static inheritance_status zend_perform_covariant_class_type_check(
                if (!fe_ce || !proto_ce) {
                        have_unresolved = 1;
                } else if (unlinked_instanceof(fe_ce, proto_ce)) {
+                       track_class_dependency(fe_ce, fe_class_name);
+                       track_class_dependency(proto_ce, proto_class_name);
                        return INHERITANCE_SUCCESS;
                }
        } ZEND_TYPE_FOREACH_END();
@@ -1139,6 +1188,12 @@ static void do_inherit_class_constant(zend_string *name, zend_class_constant *pa
        } else if (!(Z_ACCESS_FLAGS(parent_const->value) & ZEND_ACC_PRIVATE)) {
                if (Z_TYPE(parent_const->value) == IS_CONSTANT_AST) {
                        ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
+                       ce->ce_flags |= ZEND_ACC_HAS_AST_CONSTANTS;
+                       if (ce->parent->ce_flags & ZEND_ACC_IMMUTABLE) {
+                               c = zend_arena_alloc(&CG(arena), sizeof(zend_class_constant));
+                               memcpy(c, parent_const, sizeof(zend_class_constant));
+                               parent_const = c;
+                       }
                }
                if (ce->type & ZEND_INTERNAL_CLASS) {
                        c = pemalloc(sizeof(zend_class_constant), 1);
@@ -1251,6 +1306,7 @@ ZEND_API void zend_do_inheritance_ex(zend_class_entry *ce, zend_class_entry *par
                                ZVAL_COPY_OR_DUP_PROP(dst, src);
                                if (Z_OPT_TYPE_P(dst) == IS_CONSTANT_AST) {
                                        ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
+                                       ce->ce_flags |= ZEND_ACC_HAS_AST_PROPERTIES;
                                }
                                continue;
                        } while (dst != end);
@@ -1261,6 +1317,7 @@ ZEND_API void zend_do_inheritance_ex(zend_class_entry *ce, zend_class_entry *par
                                ZVAL_COPY_PROP(dst, src);
                                if (Z_OPT_TYPE_P(dst) == IS_CONSTANT_AST) {
                                        ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
+                                       ce->ce_flags |= ZEND_ACC_HAS_AST_PROPERTIES;
                                }
                                continue;
                        } while (dst != end);
@@ -1323,6 +1380,7 @@ ZEND_API void zend_do_inheritance_ex(zend_class_entry *ce, zend_class_entry *par
                                }
                                if (Z_TYPE_P(Z_INDIRECT_P(dst)) == IS_CONSTANT_AST) {
                                        ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
+                                       ce->ce_flags |= ZEND_ACC_HAS_AST_STATICS;
                                }
                        } while (dst != end);
                } else {
@@ -1434,6 +1492,12 @@ static void do_inherit_iface_constant(zend_string *name, zend_class_constant *c,
                zend_class_constant *ct;
                if (Z_TYPE(c->value) == IS_CONSTANT_AST) {
                        ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
+                       ce->ce_flags |= ZEND_ACC_HAS_AST_CONSTANTS;
+                       if (iface->ce_flags & ZEND_ACC_IMMUTABLE) {
+                               ct = zend_arena_alloc(&CG(arena), sizeof(zend_class_constant));
+                               memcpy(ct, c, sizeof(zend_class_constant));
+                               c = ct;
+                       }
                }
                if (ce->type & ZEND_INTERNAL_CLASS) {
                        ct = pemalloc(sizeof(zend_class_constant), 1);
@@ -2073,37 +2137,13 @@ static void zend_do_traits_property_binding(zend_class_entry *ce, zend_class_ent
 }
 /* }}} */
 
-static void zend_do_bind_traits(zend_class_entry *ce) /* {{{ */
+static void zend_do_bind_traits(zend_class_entry *ce, zend_class_entry **traits) /* {{{ */
 {
        HashTable **exclude_tables;
        zend_class_entry **aliases;
-       zend_class_entry **traits, *trait;
-       uint32_t i, j;
 
        ZEND_ASSERT(ce->num_traits > 0);
 
-       traits = emalloc(sizeof(zend_class_entry*) * ce->num_traits);
-
-       for (i = 0; i < ce->num_traits; i++) {
-               trait = zend_fetch_class_by_name(ce->trait_names[i].name,
-                       ce->trait_names[i].lc_name, ZEND_FETCH_CLASS_TRAIT);
-               if (UNEXPECTED(trait == NULL)) {
-                       return;
-               }
-               if (UNEXPECTED(!(trait->ce_flags & ZEND_ACC_TRAIT))) {
-                       zend_error_noreturn(E_ERROR, "%s cannot use %s - it is not a trait", ZSTR_VAL(ce->name), ZSTR_VAL(trait->name));
-                       return;
-               }
-               for (j = 0; j < i; j++) {
-                       if (traits[j] == trait) {
-                               /* skip duplications */
-                               trait = NULL;
-                               break;
-                       }
-               }
-               traits[i] = trait;
-       }
-
        /* complete initialization of trait strutures in ce */
        zend_traits_init_trait_structures(ce, traits, &exclude_tables, &aliases);
 
@@ -2120,8 +2160,6 @@ static void zend_do_bind_traits(zend_class_entry *ce) /* {{{ */
 
        /* then flatten the properties into it, to, mostly to notfiy developer about problems */
        zend_do_traits_property_binding(ce, traits);
-
-       efree(traits);
 }
 /* }}} */
 
@@ -2293,7 +2331,12 @@ static int check_variance_obligation(zval *zv) {
        if (obligation->type == OBLIGATION_DEPENDENCY) {
                zend_class_entry *dependency_ce = obligation->dependency_ce;
                if (dependency_ce->ce_flags & ZEND_ACC_UNRESOLVED_VARIANCE) {
+                       zend_class_entry *orig_linking_class = CG(current_linking_class);
+
+                       CG(current_linking_class) =
+                               (dependency_ce->ce_flags & ZEND_ACC_CACHEABLE) ? dependency_ce : NULL;
                        resolve_delayed_variance_obligations(dependency_ce);
+                       CG(current_linking_class) = orig_linking_class;
                }
                if (!(dependency_ce->ce_flags & ZEND_ACC_LINKED)) {
                        return ZEND_HASH_APPLY_KEEP;
@@ -2401,7 +2444,10 @@ static void check_unrecoverable_load_failure(zend_class_entry *ce) {
         * to remove the class from the class table and throw an exception, because there is already
         * a dependence on the inheritance hierarchy of this specific class. Instead we fall back to
         * a fatal error, as would happen if we did not allow exceptions in the first place. */
-       if (ce->ce_flags & ZEND_ACC_HAS_UNLINKED_USES) {
+       if ((ce->ce_flags & ZEND_ACC_HAS_UNLINKED_USES)
+        || ((ce->ce_flags & ZEND_ACC_IMMUTABLE)
+         && CG(unlinked_uses)
+         && zend_hash_index_del(CG(unlinked_uses), (zend_long)(zend_uintptr_t)ce) == SUCCESS)) {
                zend_string *exception_str;
                zval exception_zv;
                ZEND_ASSERT(EG(exception) && "Exception must have been thrown");
@@ -2413,13 +2459,167 @@ static void check_unrecoverable_load_failure(zend_class_entry *ce) {
        }
 }
 
-ZEND_API zend_result zend_do_link_class(zend_class_entry *ce, zend_string *lc_parent_name) /* {{{ */
+#define zend_update_inherited_handler(handler) do { \
+               if (ce->handler == (zend_function*)op_array) { \
+                       ce->handler = (zend_function*)new_op_array; \
+               } \
+       } while (0)
+
+static zend_class_entry *zend_lazy_class_load(zend_class_entry *pce)
+{
+       zend_class_entry *ce;
+       Bucket *p, *end;
+
+       ce = zend_arena_alloc(&CG(arena), sizeof(zend_class_entry));
+       memcpy(ce, pce, sizeof(zend_class_entry));
+       ce->ce_flags &= ~ZEND_ACC_IMMUTABLE;
+       ce->refcount = 1;
+       ce->inheritance_cache = NULL;
+       ZEND_MAP_PTR_INIT(ce->mutable_data, NULL);
+
+       /* properties */
+       if (ce->default_properties_table) {
+               zval *dst = emalloc(sizeof(zval) * ce->default_properties_count);
+               zval *src = ce->default_properties_table;
+               zval *end = src + ce->default_properties_count;
+
+               ce->default_properties_table = dst;
+               for (; src != end; src++, dst++) {
+                       ZVAL_COPY_VALUE_PROP(dst, src);
+               }
+       }
+
+       /* methods */
+       ce->function_table.pDestructor = ZEND_FUNCTION_DTOR;
+       if (!(HT_FLAGS(&ce->function_table) & HASH_FLAG_UNINITIALIZED)) {
+               p = emalloc(HT_SIZE(&ce->function_table));
+               memcpy(p, HT_GET_DATA_ADDR(&ce->function_table), HT_USED_SIZE(&ce->function_table));
+               HT_SET_DATA_ADDR(&ce->function_table, p);
+               p = ce->function_table.arData;
+               end = p + ce->function_table.nNumUsed;
+               for (; p != end; p++) {
+                       zend_op_array *op_array, *new_op_array;
+                       void ***run_time_cache_ptr;
+
+                       op_array = Z_PTR(p->val);
+                       ZEND_ASSERT(op_array->type == ZEND_USER_FUNCTION);
+                       ZEND_ASSERT(op_array->scope == pce);
+                       ZEND_ASSERT(op_array->prototype == NULL);
+                       new_op_array = zend_arena_alloc(&CG(arena), sizeof(zend_op_array) + sizeof(void*));
+                       Z_PTR(p->val) = new_op_array;
+                       memcpy(new_op_array, op_array, sizeof(zend_op_array));
+                       run_time_cache_ptr = (void***)(new_op_array + 1);
+                       *run_time_cache_ptr = NULL;
+                       new_op_array->fn_flags &= ~ZEND_ACC_IMMUTABLE;
+                       new_op_array->scope = ce;
+                       ZEND_MAP_PTR_INIT(new_op_array->run_time_cache, run_time_cache_ptr);
+                       ZEND_MAP_PTR_INIT(new_op_array->static_variables_ptr, &new_op_array->static_variables);
+
+                       zend_update_inherited_handler(constructor);
+                       zend_update_inherited_handler(destructor);
+                       zend_update_inherited_handler(clone);
+                       zend_update_inherited_handler(__get);
+                       zend_update_inherited_handler(__set);
+                       zend_update_inherited_handler(__call);
+                       zend_update_inherited_handler(__isset);
+                       zend_update_inherited_handler(__unset);
+                       zend_update_inherited_handler(__tostring);
+                       zend_update_inherited_handler(__callstatic);
+                       zend_update_inherited_handler(__debugInfo);
+                       zend_update_inherited_handler(__serialize);
+                       zend_update_inherited_handler(__unserialize);
+               }
+       }
+
+       /* static members */
+       if (ce->default_static_members_table) {
+               zval *dst = emalloc(sizeof(zval) * ce->default_static_members_count);
+               zval *src = ce->default_static_members_table;
+               zval *end = src + ce->default_static_members_count;
+
+               ce->default_static_members_table = dst;
+               for (; src != end; src++, dst++) {
+                       ZVAL_COPY_VALUE(dst, src);
+               }
+       }
+       ZEND_MAP_PTR_INIT(ce->static_members_table, &ce->default_static_members_table);
+
+       /* properties_info */
+       if (!(HT_FLAGS(&ce->properties_info) & HASH_FLAG_UNINITIALIZED)) {
+               p = emalloc(HT_SIZE(&ce->properties_info));
+               memcpy(p, HT_GET_DATA_ADDR(&ce->properties_info), HT_USED_SIZE(&ce->properties_info));
+               HT_SET_DATA_ADDR(&ce->properties_info, p);
+               p = ce->properties_info.arData;
+               end = p + ce->properties_info.nNumUsed;
+               for (; p != end; p++) {
+                       zend_property_info *prop_info, *new_prop_info;
+
+                       prop_info = Z_PTR(p->val);
+                       ZEND_ASSERT(prop_info->ce == pce);
+                       new_prop_info= zend_arena_alloc(&CG(arena), sizeof(zend_property_info));
+                       Z_PTR(p->val) = new_prop_info;
+                       memcpy(new_prop_info, prop_info, sizeof(zend_property_info));
+                       new_prop_info->ce = ce;
+                       if (ZEND_TYPE_HAS_LIST(new_prop_info->type)) {
+                               zend_type_list *new_list;
+                               zend_type_list *list = ZEND_TYPE_LIST(new_prop_info->type);
+
+                               new_list = zend_arena_alloc(&CG(arena), ZEND_TYPE_LIST_SIZE(list->num_types));
+                               memcpy(new_list, list, ZEND_TYPE_LIST_SIZE(list->num_types));
+                               ZEND_TYPE_SET_PTR(new_prop_info->type, list);
+                               ZEND_TYPE_FULL_MASK(new_prop_info->type) |= _ZEND_TYPE_ARENA_BIT;
+                       }
+               }
+       }
+
+       /* constants table */
+       if (!(HT_FLAGS(&ce->constants_table) & HASH_FLAG_UNINITIALIZED)) {
+               p = emalloc(HT_SIZE(&ce->constants_table));
+               memcpy(p, HT_GET_DATA_ADDR(&ce->constants_table), HT_USED_SIZE(&ce->constants_table));
+               HT_SET_DATA_ADDR(&ce->constants_table, p);
+               p = ce->constants_table.arData;
+               end = p + ce->constants_table.nNumUsed;
+               for (; p != end; p++) {
+                       zend_class_constant *c, *new_c;
+
+                       c = Z_PTR(p->val);
+                       ZEND_ASSERT(c->ce == pce);
+                       new_c = zend_arena_alloc(&CG(arena), sizeof(zend_class_constant));
+                       Z_PTR(p->val) = new_c;
+                       memcpy(new_c, c, sizeof(zend_class_constant));
+                       new_c->ce = ce;
+               }
+       }
+
+       return ce;
+}
+
+#ifndef ZEND_WIN32
+# define UPDATE_IS_CACHEABLE(ce) do { \
+                       if ((ce)->type == ZEND_USER_CLASS) { \
+                               is_cacheable &= (ce)->ce_flags; \
+                       } \
+               } while (0)
+#else
+// TODO: ASLR may cause different addresses in different workers ???
+# define UPDATE_IS_CACHEABLE(ce) do { \
+                       is_cacheable &= (ce)->ce_flags; \
+               } while (0)
+#endif
+
+ZEND_API zend_class_entry *zend_do_link_class(zend_class_entry *ce, zend_string *lc_parent_name, zend_string *key) /* {{{ */
 {
        /* Load parent/interface dependencies first, so we can still gracefully abort linking
         * with an exception and remove the class from the class table. This is only possible
         * if no variance obligations on the current class have been added during autoloading. */
        zend_class_entry *parent = NULL;
        zend_class_entry **interfaces = NULL;
+       zend_class_entry **traits_and_interfaces = NULL;
+       zend_class_entry *proto = NULL;
+       zend_class_entry *orig_linking_class;
+       uint32_t is_cacheable = ce->ce_flags & ZEND_ACC_IMMUTABLE;
+       uint32_t i, j;
+       zval *zv;
 
        if (ce->parent_name) {
                parent = zend_fetch_class_by_name(
@@ -2427,13 +2627,43 @@ ZEND_API zend_result zend_do_link_class(zend_class_entry *ce, zend_string *lc_pa
                        ZEND_FETCH_CLASS_ALLOW_NEARLY_LINKED | ZEND_FETCH_CLASS_EXCEPTION);
                if (!parent) {
                        check_unrecoverable_load_failure(ce);
-                       return FAILURE;
+                       return NULL;
+               }
+               UPDATE_IS_CACHEABLE(parent);
+       }
+
+       if (ce->num_traits || ce->num_interfaces) {
+               traits_and_interfaces = emalloc(sizeof(zend_class_entry*) * (ce->num_traits + ce->num_interfaces));
+
+               for (i = 0; i < ce->num_traits; i++) {
+                       zend_class_entry *trait = zend_fetch_class_by_name(ce->trait_names[i].name,
+                               ce->trait_names[i].lc_name, ZEND_FETCH_CLASS_TRAIT);
+                       if (UNEXPECTED(trait == NULL)) {
+                               efree(traits_and_interfaces);
+                               return NULL;
+                       }
+                       if (UNEXPECTED(!(trait->ce_flags & ZEND_ACC_TRAIT))) {
+                               zend_error_noreturn(E_ERROR, "%s cannot use %s - it is not a trait", ZSTR_VAL(ce->name), ZSTR_VAL(trait->name));
+                               efree(traits_and_interfaces);
+                               return NULL;
+                       }
+                       for (j = 0; j < i; j++) {
+                               if (traits_and_interfaces[j] == trait) {
+                                       /* skip duplications */
+                                       trait = NULL;
+                                       break;
+                               }
+                       }
+                       traits_and_interfaces[i] = trait;
+                       if (trait) {
+                               UPDATE_IS_CACHEABLE(trait);
+                       }
                }
        }
 
        if (ce->num_interfaces) {
                /* Also copy the parent interfaces here, so we don't need to reallocate later. */
-               uint32_t i, num_parent_interfaces = parent ? parent->num_interfaces : 0;
+               uint32_t num_parent_interfaces = parent ? parent->num_interfaces : 0;
                interfaces = emalloc(
                        sizeof(zend_class_entry *) * (ce->num_interfaces + num_parent_interfaces));
                if (num_parent_interfaces) {
@@ -2448,12 +2678,61 @@ ZEND_API zend_result zend_do_link_class(zend_class_entry *ce, zend_string *lc_pa
                        if (!iface) {
                                check_unrecoverable_load_failure(ce);
                                efree(interfaces);
-                               return FAILURE;
+                               efree(traits_and_interfaces);
+                               return NULL;
                        }
                        interfaces[num_parent_interfaces + i] = iface;
+                       traits_and_interfaces[ce->num_traits + i] = iface;
+                       if (iface) {
+                               UPDATE_IS_CACHEABLE(iface);
+                       }
                }
        }
 
+
+       if (ce->ce_flags & ZEND_ACC_IMMUTABLE) {
+               if (is_cacheable) {
+                       if (zend_inheritance_cache_get && zend_inheritance_cache_add) {
+                               zend_class_entry *ret = zend_inheritance_cache_get(ce, parent, traits_and_interfaces);
+                               if (ret) {
+                                       if (traits_and_interfaces) {
+                                               efree(traits_and_interfaces);
+                                       }
+                                       if (traits_and_interfaces) {
+                                               efree(interfaces);
+                                       }
+                                       zv = zend_hash_find_ex(CG(class_table), key, 1);
+                                       Z_CE_P(zv) = ret;
+                                       return ret;
+                               }
+                       } else {
+                               is_cacheable = 0;
+                       }
+                       proto = ce;
+               }
+               /* Lazy class loading */
+               ce = zend_lazy_class_load(ce);
+               zv = zend_hash_find_ex(CG(class_table), key, 1);
+               Z_CE_P(zv) = ce;
+               if (CG(unlinked_uses)
+                && zend_hash_index_del(CG(unlinked_uses), (zend_long)(zend_uintptr_t)proto) == SUCCESS) {
+                       ce->ce_flags |= ZEND_ACC_HAS_UNLINKED_USES;
+               }
+       } else if (ce->ce_flags & ZEND_ACC_FILE_CACHED) {
+               /* Lazy class loading */
+               ce = zend_lazy_class_load(ce);
+               ce->ce_flags &= ~ZEND_ACC_FILE_CACHED;
+               zv = zend_hash_find_ex(CG(class_table), key, 1);
+               Z_CE_P(zv) = ce;
+               if (CG(unlinked_uses)
+                && zend_hash_index_del(CG(unlinked_uses), (zend_long)(zend_uintptr_t)proto) == SUCCESS) {
+                       ce->ce_flags |= ZEND_ACC_HAS_UNLINKED_USES;
+               }
+       }
+
+       orig_linking_class = CG(current_linking_class);
+       CG(current_linking_class) = is_cacheable ? ce : NULL;
+
        if (parent) {
                if (!(parent->ce_flags & ZEND_ACC_LINKED)) {
                        add_dependency_obligation(ce, parent);
@@ -2461,7 +2740,7 @@ ZEND_API zend_result zend_do_link_class(zend_class_entry *ce, zend_string *lc_pa
                zend_do_inheritance(ce, parent);
        }
        if (ce->num_traits) {
-               zend_do_bind_traits(ce);
+               zend_do_bind_traits(ce, traits_and_interfaces);
        }
        if (interfaces) {
                zend_do_implement_interfaces(ce, interfaces);
@@ -2478,19 +2757,53 @@ ZEND_API zend_result zend_do_link_class(zend_class_entry *ce, zend_string *lc_pa
 
        if (!(ce->ce_flags & ZEND_ACC_UNRESOLVED_VARIANCE)) {
                ce->ce_flags |= ZEND_ACC_LINKED;
-               return SUCCESS;
+       } else {
+               ce->ce_flags |= ZEND_ACC_NEARLY_LINKED;
+               if (CG(current_linking_class)) {
+                       ce->ce_flags |= ZEND_ACC_CACHEABLE;
+               }
+               load_delayed_classes();
+               if (ce->ce_flags & ZEND_ACC_UNRESOLVED_VARIANCE) {
+                       resolve_delayed_variance_obligations(ce);
+                       if (!(ce->ce_flags & ZEND_ACC_LINKED)) {
+                               CG(current_linking_class) = orig_linking_class;
+                               report_variance_errors(ce);
+                       }
+               }
+               if (ce->ce_flags & ZEND_ACC_CACHEABLE) {
+                       ce->ce_flags &= ~ZEND_ACC_CACHEABLE;
+               } else {
+                       CG(current_linking_class) = NULL;
+               }
+       }
+
+       if (!CG(current_linking_class)) {
+               is_cacheable = 0;
        }
+       CG(current_linking_class) = orig_linking_class;
 
-       ce->ce_flags |= ZEND_ACC_NEARLY_LINKED;
-       load_delayed_classes();
-       if (ce->ce_flags & ZEND_ACC_UNRESOLVED_VARIANCE) {
-               resolve_delayed_variance_obligations(ce);
-               if (!(ce->ce_flags & ZEND_ACC_LINKED)) {
-                       report_variance_errors(ce);
+       if (is_cacheable) {
+               HashTable *ht = (HashTable*)ce->inheritance_cache;
+               zend_class_entry *new_ce;
+
+               ce->inheritance_cache = NULL;
+               new_ce = zend_inheritance_cache_add(ce, proto, parent, traits_and_interfaces, ht);
+               if (new_ce) {
+                       zv = zend_hash_find_ex(CG(class_table), key, 1);
+                       ce = new_ce;
+                       Z_CE_P(zv) = ce;
+               }
+               if (ht) {
+                       zend_hash_destroy(ht);
+                       FREE_HASHTABLE(ht);
                }
        }
 
-       return SUCCESS;
+       if (traits_and_interfaces) {
+               efree(traits_and_interfaces);
+       }
+
+       return ce;
 }
 /* }}} */
 
@@ -2539,21 +2852,66 @@ static inheritance_status zend_can_early_bind(zend_class_entry *ce, zend_class_e
 }
 /* }}} */
 
-bool zend_try_early_bind(zend_class_entry *ce, zend_class_entry *parent_ce, zend_string *lcname, zval *delayed_early_binding) /* {{{ */
+zend_class_entry *zend_try_early_bind(zend_class_entry *ce, zend_class_entry *parent_ce, zend_string *lcname, zval *delayed_early_binding) /* {{{ */
 {
-       inheritance_status status = zend_can_early_bind(ce, parent_ce);
+       inheritance_status status;
+       zend_class_entry *proto = NULL;
+       zend_class_entry *orig_linking_class;
+       uint32_t is_cacheable = ce->ce_flags & ZEND_ACC_IMMUTABLE;
+
+       UPDATE_IS_CACHEABLE(parent_ce);
+       if (is_cacheable) {
+               if (zend_inheritance_cache_get && zend_inheritance_cache_add) {
+                       zend_class_entry *ret = zend_inheritance_cache_get(ce, parent_ce, NULL);
+                       if (ret) {
+                               if (delayed_early_binding) {
+                                       if (UNEXPECTED(zend_hash_set_bucket_key(EG(class_table), (Bucket*)delayed_early_binding, lcname) == NULL)) {
+                                               zend_error_noreturn(E_COMPILE_ERROR, "Cannot declare %s %s, because the name is already in use", zend_get_object_type(ce), ZSTR_VAL(ce->name));
+                                               return NULL;
+                                       }
+                                       Z_CE_P(delayed_early_binding) = ret;
+                               } else {
+                                       if (UNEXPECTED(zend_hash_add_ptr(CG(class_table), lcname, ret) == NULL)) {
+                                               return NULL;
+                                       }
+                               }
+                               return ret;
+                       }
+               } else {
+                       is_cacheable = 0;
+               }
+               proto = ce;
+       }
 
+       orig_linking_class = CG(current_linking_class);
+       CG(current_linking_class) = NULL;
+       status = zend_can_early_bind(ce, parent_ce);
+       CG(current_linking_class) = orig_linking_class;
        if (EXPECTED(status != INHERITANCE_UNRESOLVED)) {
+               if (ce->ce_flags & ZEND_ACC_IMMUTABLE) {
+                       /* Lazy class loading */
+                       ce = zend_lazy_class_load(ce);
+               } else if (ce->ce_flags & ZEND_ACC_FILE_CACHED) {
+                       /* Lazy class loading */
+                       ce = zend_lazy_class_load(ce);
+                       ce->ce_flags &= ~ZEND_ACC_FILE_CACHED;
+               }
+
                if (delayed_early_binding) {
                        if (UNEXPECTED(zend_hash_set_bucket_key(EG(class_table), (Bucket*)delayed_early_binding, lcname) == NULL)) {
                                zend_error_noreturn(E_COMPILE_ERROR, "Cannot declare %s %s, because the name is already in use", zend_get_object_type(ce), ZSTR_VAL(ce->name));
-                               return 0;
+                               return NULL;
                        }
+                       Z_CE_P(delayed_early_binding) = ce;
                } else {
                        if (UNEXPECTED(zend_hash_add_ptr(CG(class_table), lcname, ce) == NULL)) {
-                               return 0;
+                               return NULL;
                        }
                }
+
+               orig_linking_class = CG(current_linking_class);
+               CG(current_linking_class) = is_cacheable ? ce : NULL;
+
                zend_do_inheritance_ex(ce, parent_ce, status == INHERITANCE_SUCCESS);
                if (parent_ce && parent_ce->num_interfaces) {
                        zend_do_inherit_interfaces(ce, parent_ce);
@@ -2564,8 +2922,28 @@ bool zend_try_early_bind(zend_class_entry *ce, zend_class_entry *parent_ce, zend
                }
                ZEND_ASSERT(!(ce->ce_flags & ZEND_ACC_UNRESOLVED_VARIANCE));
                ce->ce_flags |= ZEND_ACC_LINKED;
-               return 1;
+
+               CG(current_linking_class) = orig_linking_class;
+
+               if (is_cacheable) {
+                       HashTable *ht = (HashTable*)ce->inheritance_cache;
+                       zend_class_entry *new_ce;
+
+                       ce->inheritance_cache = NULL;
+                       new_ce = zend_inheritance_cache_add(ce, proto, parent_ce, NULL, ht);
+                       if (new_ce) {
+                               zval *zv = zend_hash_find_ex(CG(class_table), lcname, 1);
+                               ce = new_ce;
+                               Z_CE_P(zv) = ce;
+                       }
+                       if (ht) {
+                               zend_hash_destroy(ht);
+                               FREE_HASHTABLE(ht);
+                       }
+               }
+
+               return ce;
        }
-       return 0;
+       return NULL;
 }
 /* }}} */
index e82910f052141ac4de2b5ca07ade2398096b47c8..c67032f1295f389edbdd846986a56b96aaa328f2 100644 (file)
@@ -30,11 +30,14 @@ ZEND_API void zend_do_inheritance_ex(zend_class_entry *ce, zend_class_entry *par
 #define zend_do_inheritance(ce, parent_ce) \
        zend_do_inheritance_ex(ce, parent_ce, 0)
 
-ZEND_API zend_result zend_do_link_class(zend_class_entry *ce, zend_string *lc_parent_name);
+ZEND_API zend_class_entry *zend_do_link_class(zend_class_entry *ce, zend_string *lc_parent_name, zend_string *key);
 
 void zend_verify_abstract_class(zend_class_entry *ce);
 void zend_build_properties_info_table(zend_class_entry *ce);
-bool zend_try_early_bind(zend_class_entry *ce, zend_class_entry *parent_ce, zend_string *lcname, zval *delayed_early_binding);
+zend_class_entry *zend_try_early_bind(zend_class_entry *ce, zend_class_entry *parent_ce, zend_string *lcname, zval *delayed_early_binding);
+
+ZEND_API extern zend_class_entry* (*zend_inheritance_cache_get)(zend_class_entry *ce, zend_class_entry *parent, zend_class_entry **traits_and_interfaces);
+ZEND_API extern zend_class_entry* (*zend_inheritance_cache_add)(zend_class_entry *ce, zend_class_entry *proto, zend_class_entry *parent, zend_class_entry **traits_and_interfaces, HashTable *dependencies);
 
 END_EXTERN_C()
 
index c6930473cf724d5c1433468c67f17fc71411aa53..c014f225a3a8a62212e51e54083944a2323f0714 100644 (file)
        type * ZEND_MAP_PTR(name)
 # define ZEND_MAP_PTR_GET(ptr) \
        (*(ZEND_MAP_PTR(ptr)))
+# define ZEND_MAP_PTR_GET_IMM(ptr) \
+       ZEND_MAP_PTR_GET(ptr)
 # define ZEND_MAP_PTR_SET(ptr, val) do { \
                (*(ZEND_MAP_PTR(ptr))) = (val); \
        } while (0)
+# define ZEND_MAP_PTR_SET_IMM(ptr, val) \
+       ZEND_MAP_PTR_SET(ptr, val)
 # define ZEND_MAP_PTR_INIT(ptr, val) do { \
                ZEND_MAP_PTR(ptr) = (val); \
        } while (0)
@@ -51,6 +55,8 @@
 # define ZEND_MAP_PTR_SET_REAL_BASE(base, ptr) do { \
                base = (ptr); \
        } while (0)
+# define ZEND_MAP_PTR_OFFSET2PTR(ptr) \
+       ((void**)((char*)CG(map_ptr_base) + (uintptr_t)ZEND_MAP_PTR(ptr)))
 #elif ZEND_MAP_PTR_KIND == ZEND_MAP_PTR_KIND_PTR_OR_OFFSET
 # define ZEND_MAP_PTR(ptr) \
        ptr ## __ptr
@@ -66,6 +72,8 @@
        (*(ZEND_MAP_PTR_IS_OFFSET(ptr) ? \
                ZEND_MAP_PTR_OFFSET2PTR(ptr) : \
                ((void**)(ZEND_MAP_PTR(ptr)))))
+# define ZEND_MAP_PTR_GET_IMM(ptr) \
+       (*ZEND_MAP_PTR_OFFSET2PTR(ptr))
 # define ZEND_MAP_PTR_SET(ptr, val) do { \
                void **__p = (void**)(ZEND_MAP_PTR(ptr)); \
                if (ZEND_MAP_PTR_IS_OFFSET(ptr)) { \
                } \
                *__p = (val); \
        } while (0)
+# define ZEND_MAP_PTR_SET_IMM(ptr, val) do { \
+               void **__p = ZEND_MAP_PTR_OFFSET2PTR(ptr); \
+               *__p = (val); \
+       } while (0)
 # define ZEND_MAP_PTR_INIT(ptr, val) do { \
                ZEND_MAP_PTR(ptr) = (val); \
        } while (0)
index ae9bf2d74d4ed8785773318de310dc80e6aee6bf..abb75b8026c51eb61d9262fae27c326af62ce860 100644 (file)
@@ -163,7 +163,7 @@ ZEND_API void zend_function_dtor(zval *zv)
 
 ZEND_API void zend_cleanup_internal_class_data(zend_class_entry *ce)
 {
-       if (CE_STATIC_MEMBERS(ce)) {
+       if (ZEND_MAP_PTR(ce->static_members_table) && CE_STATIC_MEMBERS(ce)) {
                zval *static_members = CE_STATIC_MEMBERS(ce);
                zval *p = static_members;
                zval *end = p + ce->default_static_members_count;
@@ -255,18 +255,76 @@ static void _destroy_zend_class_traits_info(zend_class_entry *ce)
        }
 }
 
+ZEND_API void zend_cleanup_mutable_class_data(zend_class_entry *ce)
+{
+       zend_class_mutable_data *mutable_data = ZEND_MAP_PTR_GET_IMM(ce->mutable_data);
+
+       if (mutable_data) {
+               HashTable *constants_table;
+               zval *p;
+
+               constants_table = mutable_data->constants_table;
+               if (constants_table && constants_table != &ce->constants_table) {
+                       zend_class_constant *c;
+
+                       ZEND_HASH_FOREACH_PTR(constants_table, c) {
+                               zval_ptr_dtor_nogc(&c->value);
+                       } ZEND_HASH_FOREACH_END();
+                       zend_hash_destroy(constants_table);
+                       mutable_data->constants_table = NULL;
+               }
+
+               p = mutable_data->default_properties_table;
+               if (p && p != ce->default_properties_table) {
+                       zval *end = p + ce->default_properties_count;
+
+                       while (p < end) {
+                               zval_ptr_dtor_nogc(p);
+                               p++;
+                       }
+                       mutable_data->default_properties_table = NULL;
+               }
+
+               ZEND_MAP_PTR_SET_IMM(ce->mutable_data, NULL);
+       }
+}
+
 ZEND_API void destroy_zend_class(zval *zv)
 {
        zend_property_info *prop_info;
        zend_class_entry *ce = Z_PTR_P(zv);
        zend_function *fn;
 
-       if (ce->ce_flags & (ZEND_ACC_IMMUTABLE|ZEND_ACC_PRELOADED)) {
+       if (ce->ce_flags & (ZEND_ACC_IMMUTABLE|ZEND_ACC_PRELOADED|ZEND_ACC_FILE_CACHED)) {
                zend_op_array *op_array;
 
                if (ce->default_static_members_count) {
                        zend_cleanup_internal_class_data(ce);
                }
+
+               if (!(ce->ce_flags & ZEND_ACC_FILE_CACHED)) {
+                       if (ZEND_MAP_PTR(ce->mutable_data) && ZEND_MAP_PTR_GET_IMM(ce->mutable_data)) {
+                               zend_cleanup_mutable_class_data(ce);
+                       }
+               } else {
+                       zend_class_constant *c;
+                       zval *p, *end;
+
+                       ZEND_HASH_FOREACH_PTR(&ce->constants_table, c) {
+                               if (c->ce == ce) {
+                                       zval_ptr_dtor_nogc(&c->value);
+                               }
+                       } ZEND_HASH_FOREACH_END();
+
+                       p = ce->default_properties_table;
+                       end = p + ce->default_properties_count;
+
+                       while (p < end) {
+                               zval_ptr_dtor_nogc(p);
+                               p++;
+                       }
+               }
+
                if (ce->ce_flags & ZEND_HAS_STATIC_IN_METHODS) {
                        ZEND_HASH_FOREACH_PTR(&ce->function_table, op_array) {
                                if (op_array->type == ZEND_USER_FUNCTION) {
index da6792ba7bb2549db3e0e1c2bab60ebb13bfba4f..bb8073e1d50dc845720087727afe18c84528f020 100644 (file)
@@ -130,7 +130,7 @@ typedef struct {
         * are only supported since C++20). */
        void *ptr;
        uint32_t type_mask;
-       /* TODO: We could use the extra 32-bit of padding on 64-bit systems. */
+       uint32_t ce_cache__ptr; /* map_ptr offset */
 } zend_type;
 
 typedef struct {
@@ -138,13 +138,15 @@ typedef struct {
        zend_type types[1];
 } zend_type_list;
 
-#define _ZEND_TYPE_EXTRA_FLAGS_SHIFT 24
-#define _ZEND_TYPE_MASK ((1u << 24) - 1)
+#define _ZEND_TYPE_EXTRA_FLAGS_SHIFT 25
+#define _ZEND_TYPE_MASK ((1u << 25) - 1)
 /* Only one of these bits may be set. */
-#define _ZEND_TYPE_NAME_BIT (1u << 23)
-#define _ZEND_TYPE_CE_BIT   (1u << 22)
-#define _ZEND_TYPE_LIST_BIT (1u << 21)
+#define _ZEND_TYPE_NAME_BIT (1u << 24)
+#define _ZEND_TYPE_CE_BIT   (1u << 23)
+#define _ZEND_TYPE_LIST_BIT (1u << 22)
 #define _ZEND_TYPE_KIND_MASK (_ZEND_TYPE_LIST_BIT|_ZEND_TYPE_CE_BIT|_ZEND_TYPE_NAME_BIT)
+/* CE cached in map_ptr area */
+#define _ZEND_TYPE_CACHE_BIT (1u << 21)
 /* Whether the type list is arena allocated */
 #define _ZEND_TYPE_ARENA_BIT (1u << 20)
 /* Type mask excluding the flags above. */
@@ -167,6 +169,9 @@ typedef struct {
 #define ZEND_TYPE_HAS_LIST(t) \
        ((((t).type_mask) & _ZEND_TYPE_LIST_BIT) != 0)
 
+#define ZEND_TYPE_HAS_CE_CACHE(t) \
+       ((((t).type_mask) & _ZEND_TYPE_CACHE_BIT) != 0)
+
 #define ZEND_TYPE_USES_ARENA(t) \
        ((((t).type_mask) & _ZEND_TYPE_ARENA_BIT) != 0)
 
@@ -185,6 +190,13 @@ typedef struct {
 #define ZEND_TYPE_LIST(t) \
        ((zend_type_list *) (t).ptr)
 
+#define ZEND_TYPE_CE_CACHE(t) \
+       (*(zend_class_entry **)ZEND_MAP_PTR_OFFSET2PTR((t).ce_cache))
+
+#define ZEND_TYPE_SET_CE_CACHE(t, ce) do { \
+               *((zend_class_entry **)ZEND_MAP_PTR_OFFSET2PTR((t).ce_cache)) = ce; \
+       } while (0)
+
 #define ZEND_TYPE_LIST_SIZE(num_types) \
        (sizeof(zend_type_list) + ((num_types) - 1) * sizeof(zend_type))
 
@@ -254,10 +266,10 @@ typedef struct {
        (((t).type_mask & _ZEND_TYPE_NULLABLE_BIT) != 0)
 
 #define ZEND_TYPE_INIT_NONE(extra_flags) \
-       { NULL, (extra_flags) }
+       { NULL, (extra_flags), 0 }
 
 #define ZEND_TYPE_INIT_MASK(_type_mask) \
-       { NULL, (_type_mask) }
+       { NULL, (_type_mask), 0 }
 
 #define ZEND_TYPE_INIT_CODE(code, allow_null, extra_flags) \
        ZEND_TYPE_INIT_MASK(((code) == _IS_BOOL ? MAY_BE_BOOL : ((code) == IS_MIXED ? MAY_BE_ANY : (1 << (code)))) \
@@ -265,10 +277,10 @@ typedef struct {
 
 #define ZEND_TYPE_INIT_PTR(ptr, type_kind, allow_null, extra_flags) \
        { (void *) (ptr), \
-               (type_kind) | ((allow_null) ? _ZEND_TYPE_NULLABLE_BIT : 0) | (extra_flags) }
+               (type_kind) | ((allow_null) ? _ZEND_TYPE_NULLABLE_BIT : 0) | (extra_flags), 0 }
 
 #define ZEND_TYPE_INIT_PTR_MASK(ptr, type_mask) \
-       { (void *) (ptr), (type_mask) }
+       { (void *) (ptr), (type_mask), 0 }
 
 #define ZEND_TYPE_INIT_CE(_ce, allow_null, extra_flags) \
        ZEND_TYPE_INIT_PTR(_ce, _ZEND_TYPE_CE_BIT, allow_null, extra_flags)
index 4b927461a2085388199a84efa52c2caa3bc3b8aa..d09fcd39b84abd02a012113a401e0e4a74222e96 100644 (file)
@@ -5821,7 +5821,7 @@ ZEND_VM_HANDLER(181, ZEND_FETCH_CLASS_CONSTANT, VAR|CONST|UNUSED|CLASS_FETCH, CO
                        }
                }
 
-               zv = zend_hash_find_ex(&ce->constants_table, Z_STR_P(RT_CONSTANT(opline, opline->op2)), 1);
+               zv = zend_hash_find_ex(CE_CONSTANTS_TABLE(ce), Z_STR_P(RT_CONSTANT(opline, opline->op2)), 1);
                if (EXPECTED(zv != NULL)) {
                        c = Z_PTR_P(zv);
                        scope = EX(func)->op_array.scope;
@@ -7526,7 +7526,8 @@ ZEND_VM_HANDLER(145, ZEND_DECLARE_CLASS_DELAYED, CONST, CONST)
                        if (UNEXPECTED(!zv)) {
                                zend_error_noreturn(E_COMPILE_ERROR, "Cannot declare %s %s, because the name is already in use", zend_get_object_type(ce), ZSTR_VAL(ce->name));
                        } else {
-                               if (zend_do_link_class(ce, Z_STR_P(RT_CONSTANT(opline, opline->op2))) == FAILURE) {
+                               ce = zend_do_link_class(ce, Z_STR_P(RT_CONSTANT(opline, opline->op2)), Z_STR_P(lcname));
+                               if (!ce) {
                                        /* Reload bucket pointer, the hash table may have been reallocated */
                                        zv = zend_hash_find(EG(class_table), Z_STR_P(lcname));
                                        zend_hash_set_bucket_key(EG(class_table), (Bucket *) zv, Z_STR_P(lcname + 1));
@@ -7567,7 +7568,8 @@ ZEND_VM_HANDLER(146, ZEND_DECLARE_ANON_CLASS, ANY, ANY, CACHE_SLOT)
                ce = Z_CE_P(zv);
                if (!(ce->ce_flags & ZEND_ACC_LINKED)) {
                        SAVE_OPLINE();
-                       if (zend_do_link_class(ce, (OP2_TYPE == IS_CONST) ? Z_STR_P(RT_CONSTANT(opline, opline->op2)) : NULL) == FAILURE) {
+                       ce = zend_do_link_class(ce, (OP2_TYPE == IS_CONST) ? Z_STR_P(RT_CONSTANT(opline, opline->op2)) : NULL, rtd_key);
+                       if (!ce) {
                                HANDLE_EXCEPTION();
                        }
                }
index 2f1f6fc298dfcdbda18cddf96de1ce77017c2fe5..f27f3fd5e12017894edf68d9b3ee40e714c552a9 100644 (file)
@@ -2813,7 +2813,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DECLARE_ANON_CLASS_SPEC_HANDLE
                ce = Z_CE_P(zv);
                if (!(ce->ce_flags & ZEND_ACC_LINKED)) {
                        SAVE_OPLINE();
-                       if (zend_do_link_class(ce, (opline->op2_type == IS_CONST) ? Z_STR_P(RT_CONSTANT(opline, opline->op2)) : NULL) == FAILURE) {
+                       ce = zend_do_link_class(ce, (opline->op2_type == IS_CONST) ? Z_STR_P(RT_CONSTANT(opline, opline->op2)) : NULL, rtd_key);
+                       if (!ce) {
                                HANDLE_EXCEPTION();
                        }
                }
@@ -6848,7 +6849,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_CLASS_CONSTANT_SPEC_CONS
                        }
                }
 
-               zv = zend_hash_find_ex(&ce->constants_table, Z_STR_P(RT_CONSTANT(opline, opline->op2)), 1);
+               zv = zend_hash_find_ex(CE_CONSTANTS_TABLE(ce), Z_STR_P(RT_CONSTANT(opline, opline->op2)), 1);
                if (EXPECTED(zv != NULL)) {
                        c = Z_PTR_P(zv);
                        scope = EX(func)->op_array.scope;
@@ -7175,7 +7176,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DECLARE_CLASS_DELAYED_SPEC_CON
                        if (UNEXPECTED(!zv)) {
                                zend_error_noreturn(E_COMPILE_ERROR, "Cannot declare %s %s, because the name is already in use", zend_get_object_type(ce), ZSTR_VAL(ce->name));
                        } else {
-                               if (zend_do_link_class(ce, Z_STR_P(RT_CONSTANT(opline, opline->op2))) == FAILURE) {
+                               ce = zend_do_link_class(ce, Z_STR_P(RT_CONSTANT(opline, opline->op2)), Z_STR_P(lcname));
+                               if (!ce) {
                                        /* Reload bucket pointer, the hash table may have been reallocated */
                                        zv = zend_hash_find(EG(class_table), Z_STR_P(lcname));
                                        zend_hash_set_bucket_key(EG(class_table), (Bucket *) zv, Z_STR_P(lcname + 1));
@@ -24194,7 +24196,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_CLASS_CONSTANT_SPEC_VAR_
                        }
                }
 
-               zv = zend_hash_find_ex(&ce->constants_table, Z_STR_P(RT_CONSTANT(opline, opline->op2)), 1);
+               zv = zend_hash_find_ex(CE_CONSTANTS_TABLE(ce), Z_STR_P(RT_CONSTANT(opline, opline->op2)), 1);
                if (EXPECTED(zv != NULL)) {
                        c = Z_PTR_P(zv);
                        scope = EX(func)->op_array.scope;
@@ -32617,7 +32619,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_CLASS_CONSTANT_SPEC_UNUS
                        }
                }
 
-               zv = zend_hash_find_ex(&ce->constants_table, Z_STR_P(RT_CONSTANT(opline, opline->op2)), 1);
+               zv = zend_hash_find_ex(CE_CONSTANTS_TABLE(ce), Z_STR_P(RT_CONSTANT(opline, opline->op2)), 1);
                if (EXPECTED(zv != NULL)) {
                        c = Z_PTR_P(zv);
                        scope = EX(func)->op_array.scope;
index 088bca6ebf6aefcbb6d70495327f4e94d5aae463..9819e7acdd26f56b14826c7463bc2b63f5fd0cfb 100644 (file)
@@ -118,6 +118,8 @@ bool fallback_process = 0; /* process uses file cache fallback */
 #endif
 
 static zend_op_array *(*accelerator_orig_compile_file)(zend_file_handle *file_handle, int type);
+static zend_class_entry* (*accelerator_orig_inheritance_cache_get)(zend_class_entry *ce, zend_class_entry *parent, zend_class_entry **traits_and_interfaces);
+static zend_class_entry* (*accelerator_orig_inheritance_cache_add)(zend_class_entry *ce, zend_class_entry *proto, zend_class_entry *parent, zend_class_entry **traits_and_interfaces, HashTable *dependencies);
 static zend_result (*accelerator_orig_zend_stream_open_function)(const char *filename, zend_file_handle *handle );
 static zend_string *(*accelerator_orig_zend_resolve_path)(const char *filename, size_t filename_len);
 static void (*accelerator_orig_zend_error_cb)(int type, const char *error_filename, const uint32_t error_lineno, zend_string *message);
@@ -2249,6 +2251,269 @@ zend_op_array *persistent_compile_file(zend_file_handle *file_handle, int type)
        return zend_accel_load_script(persistent_script, from_shared_memory);
 }
 
+static zend_inheritance_cache_entry* zend_accel_inheritance_cache_find(zend_inheritance_cache_entry *entry, zend_class_entry *ce, zend_class_entry *parent, zend_class_entry **traits_and_interfaces, bool *needs_autoload_ptr)
+{
+       uint32_t i;
+
+       ZEND_ASSERT(ce->ce_flags & ZEND_ACC_IMMUTABLE);
+       ZEND_ASSERT(!(ce->ce_flags & ZEND_ACC_LINKED));
+
+       while (entry) {
+               bool found = 1;
+               bool needs_autoload = 0;
+
+               if (entry->parent != parent) {
+                       found = 0;
+               } else {
+                       for (i = 0; i < ce->num_traits + ce->num_interfaces; i++) {
+                               if (entry->traits_and_interfaces[i] != traits_and_interfaces[i]) {
+                                       found = 0;
+                                       break;
+                               }
+                       }
+                       if (found && entry->dependencies) {
+                               for (i = 0; i < entry->dependencies_count; i++) {
+                                       zend_class_entry *ce = zend_lookup_class_ex(entry->dependencies[i].name, NULL, ZEND_FETCH_CLASS_NO_AUTOLOAD);
+
+                                       if (ce != entry->dependencies[i].ce) {
+                                               if (!ce) {
+                                                       needs_autoload = 1;
+                                               } else {
+                                                       found = 0;
+                                                       break;
+                                               }
+                                       }
+                               }
+                       }
+               }
+               if (found) {
+                       *needs_autoload_ptr = needs_autoload;
+                       return entry;
+               }
+               entry = entry->next;
+       }
+
+       return NULL;
+}
+
+static zend_class_entry* zend_accel_inheritance_cache_get(zend_class_entry *ce, zend_class_entry *parent, zend_class_entry **traits_and_interfaces)
+{
+       uint32_t i;
+       bool needs_autoload;
+       zend_inheritance_cache_entry *entry = ce->inheritance_cache;
+
+       while (entry) {
+               entry = zend_accel_inheritance_cache_find(entry, ce, parent, traits_and_interfaces, &needs_autoload);
+               if (entry) {
+                       if (!needs_autoload) {
+                               zend_map_ptr_extend(ZCSG(map_ptr_last));
+                               return entry->ce;
+                       }
+
+                       for (i = 0; i < entry->dependencies_count; i++) {
+                               zend_class_entry *ce = zend_lookup_class_ex(entry->dependencies[i].name, NULL, 0);
+
+                               if (ce == NULL) {
+                                       return NULL;
+                               }
+                       }
+               }
+       }
+
+       return NULL;
+}
+
+static bool is_array_cacheable(zval *zv)
+{
+       zval *p;
+
+       ZEND_HASH_FOREACH_VAL(Z_ARR_P(zv), p) {
+               if (Z_REFCOUNTED_P(p)) {
+                       if (Z_TYPE_P(p) == IS_ARRAY) {
+                               if (!is_array_cacheable(p)) {
+                                       /* Can't cache */
+                                       return 0;
+                               }
+                       } else if (Z_TYPE_P(p) == IS_OBJECT || Z_TYPE_P(p) == IS_RESOURCE || Z_TYPE_P(p) == IS_REFERENCE) {
+                               /* Can't cache */
+                               return 0;
+                       }
+               }
+       } ZEND_HASH_FOREACH_END();
+
+       return 1;
+}
+
+static zend_class_entry* zend_accel_inheritance_cache_add(zend_class_entry *ce, zend_class_entry *proto, zend_class_entry *parent, zend_class_entry **traits_and_interfaces, HashTable *dependencies)
+{
+       zend_persistent_script dummy;
+       size_t size;
+       uint32_t i;
+       bool needs_autoload;
+       zend_class_entry *new_ce;
+       zend_inheritance_cache_entry *entry;
+
+       ZEND_ASSERT(!(ce->ce_flags & ZEND_ACC_IMMUTABLE));
+       ZEND_ASSERT(ce->ce_flags & ZEND_ACC_LINKED);
+
+       if (!ZCG(accelerator_enabled) ||
+        (ZCSG(restart_in_progress) && accel_restart_is_active())) {
+               return NULL;
+       }
+
+       if (traits_and_interfaces && dependencies) {
+               for (i = 0; i < proto->num_traits + proto->num_interfaces; i++) {
+                       if (traits_and_interfaces[i]) {
+                               zend_hash_del(dependencies, traits_and_interfaces[i]->name);
+                       }
+               }
+       }
+
+       if (ce->ce_flags & ZEND_HAS_STATIC_IN_METHODS) {
+               zend_op_array *op_array;
+               zval *zv;
+
+               ZEND_HASH_FOREACH_PTR(&ce->function_table, op_array) {
+                       if (op_array->type == ZEND_USER_FUNCTION
+                        && op_array->static_variables
+                        && !(GC_FLAGS(op_array->static_variables) & IS_ARRAY_IMMUTABLE)) {
+                               if (UNEXPECTED(GC_REFCOUNT(op_array->static_variables) > 1)) {
+                                       GC_DELREF(op_array->static_variables);
+                                       op_array->static_variables = zend_array_dup(op_array->static_variables);
+                               }
+                               ZEND_HASH_FOREACH_VAL(op_array->static_variables, zv) {
+                                       if (Z_ISREF_P(zv)) {
+                                               zend_reference *ref = Z_REF_P(zv);
+
+                                               ZVAL_COPY_VALUE(zv, &ref->val);
+                                               if (GC_DELREF(ref) == 0) {
+                                                       efree_size(ref, sizeof(zend_reference));
+                                               }
+                                       }
+                                       if (Z_REFCOUNTED_P(zv)) {
+                                               if (Z_TYPE_P(zv) == IS_ARRAY) {
+                                                       if (!is_array_cacheable(zv)) {
+                                                               /* Can't cache */
+                                                               return NULL;
+                                                       }
+                                                       SEPARATE_ARRAY(zv);
+                                               } else if (Z_TYPE_P(zv) == IS_OBJECT || Z_TYPE_P(zv) == IS_RESOURCE) {
+                                                       /* Can't cache */
+                                                       return NULL;
+                                               }
+                                       }
+                               } ZEND_HASH_FOREACH_END();
+                       }
+               } ZEND_HASH_FOREACH_END();
+       }
+
+       SHM_UNPROTECT();
+       zend_shared_alloc_lock();
+
+       entry = ce->inheritance_cache;
+       while (entry) {
+               entry = zend_accel_inheritance_cache_find(entry, ce, parent, traits_and_interfaces, &needs_autoload);
+               if (entry) {
+                       if (!needs_autoload) {
+                               zend_shared_alloc_unlock();
+                               SHM_PROTECT();
+
+                               zend_map_ptr_extend(ZCSG(map_ptr_last));
+                               return entry->ce;
+                       }
+                       ZEND_ASSERT(0); // entry = entry->next; // This shouldn't be posible ???
+               }
+       }
+
+       zend_shared_alloc_init_xlat_table();
+
+       memset(&dummy, 0, sizeof(dummy));
+       dummy.size = ZEND_ALIGNED_SIZE(
+               sizeof(zend_inheritance_cache_entry) -
+               sizeof(void*) +
+               (sizeof(void*) * (proto->num_traits + proto->num_interfaces)));
+       if (dependencies) {
+               dummy.size += ZEND_ALIGNED_SIZE(zend_hash_num_elements(dependencies) * sizeof(zend_class_dependency));
+       }
+       ZCG(current_persistent_script) = &dummy;
+       zend_persist_class_entry_calc(ce);
+       size = dummy.size;
+
+       zend_shared_alloc_clear_xlat_table();
+
+#if ZEND_MM_ALIGNMENT < 8
+       /* Align to 8-byte boundary */
+       ZCG(mem) = zend_shared_alloc(size + 8);
+#else
+       ZCG(mem) = zend_shared_alloc(size);
+#endif
+
+       if (!ZCG(mem)) {
+               zend_shared_alloc_destroy_xlat_table();
+               zend_shared_alloc_unlock();
+               SHM_PROTECT();
+               return NULL;
+       }
+
+#if ZEND_MM_ALIGNMENT < 8
+       /* Align to 8-byte boundary */
+       ZCG(mem) = (void*)(((zend_uintptr_t)ZCG(mem) + 7L) & ~7L);
+#endif
+
+       memset(ZCG(mem), 0, size);
+       entry = (zend_inheritance_cache_entry*)ZCG(mem);
+       ZCG(mem) = (char*)ZCG(mem) +
+               ZEND_ALIGNED_SIZE(
+                       (sizeof(zend_inheritance_cache_entry) -
+                        sizeof(void*) +
+                        (sizeof(void*) * (proto->num_traits + proto->num_interfaces))));
+       entry->parent = parent;
+       for (i = 0; i < proto->num_traits + proto->num_interfaces; i++) {
+               entry->traits_and_interfaces[i] = traits_and_interfaces[i];
+       }
+       if (dependencies && zend_hash_num_elements(dependencies)) {
+               zend_string *dep_name;
+               zend_class_entry *dep_ce;
+
+               i = 0;
+               entry->dependencies_count = zend_hash_num_elements(dependencies);
+               entry->dependencies = (zend_class_dependency*)ZCG(mem);
+               ZEND_HASH_FOREACH_STR_KEY_PTR(dependencies, dep_name, dep_ce) {
+#if ZEND_DEBUG
+                       ZEND_ASSERT(zend_accel_in_shm(dep_name));
+#endif
+                       entry->dependencies[i].name = dep_name;
+                       entry->dependencies[i].ce = dep_ce;
+                       i++;
+               } ZEND_HASH_FOREACH_END();
+               ZCG(mem) = (char*)ZCG(mem) + zend_hash_num_elements(dependencies) * sizeof(zend_class_dependency);
+       }
+       entry->ce = new_ce = zend_persist_class_entry(ce);
+       zend_update_parent_ce(new_ce);
+       entry->next = proto->inheritance_cache;
+       proto->inheritance_cache = entry;
+
+       zend_shared_alloc_destroy_xlat_table();
+
+       zend_shared_alloc_unlock();
+       SHM_PROTECT();
+
+       /* Consistency check */
+       if ((char*)entry + size != (char*)ZCG(mem)) {
+               zend_accel_error(
+                       ((char*)entry + size < (char*)ZCG(mem)) ? ACCEL_LOG_ERROR : ACCEL_LOG_WARNING,
+                       "Internal error: wrong class size calculation: %s start=" ZEND_ADDR_FMT ", end=" ZEND_ADDR_FMT ", real=" ZEND_ADDR_FMT "\n",
+                       ZSTR_VAL(ce->name),
+                       (size_t)entry,
+                       (size_t)((char *)entry + size),
+                       (size_t)ZCG(mem));
+       }
+
+       zend_map_ptr_extend(ZCSG(map_ptr_last));
+
+       return new_ce;
+}
+
 #ifdef ZEND_WIN32
 static int accel_gen_uname_id(void)
 {
@@ -3123,7 +3388,19 @@ file_cache_fallback:
                accel_use_shm_interned_strings();
        }
 
-       return accel_finish_startup();
+       if (accel_finish_startup() != SUCCESS) {
+               return FAILURE;
+       }
+
+       if (ZCG(enabled) && accel_startup_ok) {
+               /* Override inheritance cache callbaks */
+               accelerator_orig_inheritance_cache_get = zend_inheritance_cache_get;
+               accelerator_orig_inheritance_cache_add = zend_inheritance_cache_add;
+               zend_inheritance_cache_get = zend_accel_inheritance_cache_get;
+               zend_inheritance_cache_add = zend_accel_inheritance_cache_add;
+       }
+
+       return SUCCESS;
 }
 
 static void (*orig_post_shutdown_cb)(void);
@@ -3170,6 +3447,8 @@ void accel_shutdown(void)
        }
 
        zend_compile_file = accelerator_orig_compile_file;
+       zend_inheritance_cache_get = accelerator_orig_inheritance_cache_get;
+       zend_inheritance_cache_add = accelerator_orig_inheritance_cache_add;
 
        if ((ini_entry = zend_hash_str_find_ptr(EG(ini_directives), "include_path", sizeof("include_path")-1)) != NULL) {
                ini_entry->on_modify = orig_include_path_on_modify;
@@ -3472,34 +3751,6 @@ try_again:
        }
 }
 
-static void get_unresolved_initializer(zend_class_entry *ce, const char **kind, const char **name) {
-       zend_string *key;
-       zend_class_constant *c;
-       zend_property_info *prop;
-
-       *kind = "unknown";
-       *name = "";
-
-       ZEND_HASH_FOREACH_STR_KEY_PTR(&ce->constants_table, key, c) {
-               if (Z_TYPE(c->value) == IS_CONSTANT_AST) {
-                       *kind = "constant ";
-                       *name = ZSTR_VAL(key);
-               }
-       } ZEND_HASH_FOREACH_END();
-       ZEND_HASH_FOREACH_STR_KEY_PTR(&ce->properties_info, key, prop) {
-               zval *val;
-               if (prop->flags & ZEND_ACC_STATIC) {
-                       val = &ce->default_static_members_table[prop->offset];
-               } else {
-                       val = &ce->default_properties_table[OBJ_PROP_TO_NUM(prop->offset)];
-               }
-               if (Z_TYPE_P(val) == IS_CONSTANT_AST) {
-                       *kind = (prop->flags & ZEND_ACC_STATIC) ? "static property $" : "property $";
-                       *name = ZSTR_VAL(key);
-               }
-       } ZEND_HASH_FOREACH_END();
-}
-
 static bool preload_needed_types_known(zend_class_entry *ce);
 static void get_unlinked_dependency(zend_class_entry *ce, const char **kind, const char **name) {
        zend_class_entry *p;
@@ -3515,16 +3766,6 @@ static void get_unlinked_dependency(zend_class_entry *ce, const char **kind, con
                        *name = ZSTR_VAL(ce->parent_name);
                        return;
                }
-               if (!(p->ce_flags & ZEND_ACC_CONSTANTS_UPDATED)) {
-                       *kind = "Parent with unresolved initializers ";
-                       *name = ZSTR_VAL(ce->parent_name);
-                       return;
-               }
-               if (!(p->ce_flags & ZEND_ACC_PROPERTY_TYPES_RESOLVED)) {
-                       *kind = "Parent with unresolved property types ";
-                       *name = ZSTR_VAL(ce->parent_name);
-                       return;
-               }
        }
 
        if (ce->num_interfaces) {
@@ -3559,12 +3800,11 @@ static void get_unlinked_dependency(zend_class_entry *ce, const char **kind, con
 
 static bool preload_try_resolve_constants(zend_class_entry *ce)
 {
-       bool ok, changed;
+       bool ok, changed, was_changed = 0;
        zend_class_constant *c;
        zval *val;
 
        EG(exception) = (void*)(uintptr_t)-1; /* prevent error reporting */
-       CG(in_compilation) = 1; /* prevent autoloading */
        do {
                ok = 1;
                changed = 0;
@@ -3572,62 +3812,65 @@ static bool preload_try_resolve_constants(zend_class_entry *ce)
                        val = &c->value;
                        if (Z_TYPE_P(val) == IS_CONSTANT_AST) {
                                if (EXPECTED(zval_update_constant_ex(val, c->ce) == SUCCESS)) {
-                                       changed = 1;
+                                       was_changed = changed = 1;
                                } else {
                                        ok = 0;
                                }
                        }
                } ZEND_HASH_FOREACH_END();
+               if (ok) {
+                       ce->ce_flags &= ~ZEND_ACC_HAS_AST_CONSTANTS;
+               }
                if (ce->default_properties_count) {
                        uint32_t i;
+                       bool resolved = 1;
+
                        for (i = 0; i < ce->default_properties_count; i++) {
                                val = &ce->default_properties_table[i];
                                if (Z_TYPE_P(val) == IS_CONSTANT_AST) {
                                        zend_property_info *prop = ce->properties_info_table[i];
                                        if (UNEXPECTED(zval_update_constant_ex(val, prop->ce) != SUCCESS)) {
-                                               ok = 0;
+                                               resolved = ok = 0;
                                        }
                                }
                        }
+                       if (resolved) {
+                               ce->ce_flags &= ~ZEND_ACC_HAS_AST_PROPERTIES;
+                       }
                }
                if (ce->default_static_members_count) {
                        uint32_t count = ce->parent ? ce->default_static_members_count - ce->parent->default_static_members_count : ce->default_static_members_count;
+                       bool resolved = 1;
 
                        val = ce->default_static_members_table + ce->default_static_members_count - 1;
                        while (count) {
                                if (Z_TYPE_P(val) == IS_CONSTANT_AST) {
                                        if (UNEXPECTED(zval_update_constant_ex(val, ce) != SUCCESS)) {
-                                               ok = 0;
+                                               resolved = ok = 0;
                                        }
                                }
                                val--;
                                count--;
                        }
+                       if (resolved) {
+                               ce->ce_flags &= ~ZEND_ACC_HAS_AST_STATICS;
+                       }
                }
        } while (changed && !ok);
        EG(exception) = NULL;
        CG(in_compilation) = 0;
 
-       return ok;
+       if (ok) {
+               ce->ce_flags |= ZEND_ACC_CONSTANTS_UPDATED;
+       }
+
+       return ok || was_changed;
 }
 
-static zend_class_entry *preload_fetch_resolved_ce(zend_string *name, zend_class_entry *self_ce) {
+static zend_class_entry *preload_fetch_resolved_ce(zend_string *name) {
        zend_string *lcname = zend_string_tolower(name);
        zend_class_entry *ce = zend_hash_find_ptr(EG(class_table), lcname);
        zend_string_release(lcname);
-       if (!ce) {
-               return NULL;
-       }
-       if (ce == self_ce) {
-               /* Ignore the following requirements if this is the class referring to itself */
-               return ce;
-       }
-       if (!(ce->ce_flags & ZEND_ACC_CONSTANTS_UPDATED)) {
-               return NULL;
-       }
-       if (!(ce->ce_flags & ZEND_ACC_PROPERTY_TYPES_RESOLVED)) {
-               return NULL;
-       }
        return ce;
 }
 
@@ -3641,7 +3884,7 @@ static bool preload_try_resolve_property_types(zend_class_entry *ce)
                        ZEND_TYPE_FOREACH(prop->type, single_type) {
                                if (ZEND_TYPE_HAS_NAME(*single_type)) {
                                        zend_class_entry *p =
-                                               preload_fetch_resolved_ce(ZEND_TYPE_NAME(*single_type), ce);
+                                               preload_fetch_resolved_ce(ZEND_TYPE_NAME(*single_type));
                                        if (!p) {
                                                ok = 0;
                                                continue;
@@ -3650,6 +3893,9 @@ static bool preload_try_resolve_property_types(zend_class_entry *ce)
                                }
                        } ZEND_TYPE_FOREACH_END();
                } ZEND_HASH_FOREACH_END();
+               if (ok) {
+                       ce->ce_flags |= ZEND_ACC_PROPERTY_TYPES_RESOLVED;
+               }
        }
 
        return ok;
@@ -3778,12 +4024,6 @@ static void preload_link(void)
                                        parent = zend_hash_find_ptr(EG(class_table), key);
                                        zend_string_release(key);
                                        if (!parent) continue;
-                                       if (!(parent->ce_flags & ZEND_ACC_CONSTANTS_UPDATED)) {
-                                               continue;
-                                       }
-                                       if (!(parent->ce_flags & ZEND_ACC_PROPERTY_TYPES_RESOLVED)) {
-                                               continue;
-                                       }
                                }
 
                                if (ce->num_interfaces) {
@@ -3794,10 +4034,6 @@ static void preload_link(void)
                                                        found = 0;
                                                        break;
                                                }
-                                               if (!(p->ce_flags & ZEND_ACC_CONSTANTS_UPDATED)) {
-                                                       found = 0;
-                                                       break;
-                                               }
                                        }
                                        if (!found) continue;
                                }
@@ -3822,11 +4058,8 @@ static void preload_link(void)
                                        continue;
                                }
 
-                               {
-                                       zend_string *key = zend_string_tolower(ce->name);
-                                       zv = zend_hash_set_bucket_key(EG(class_table), (Bucket*)zv, key);
-                                       zend_string_release(key);
-                               }
+                               key = zend_string_tolower(ce->name);
+                               zv = zend_hash_set_bucket_key(EG(class_table), (Bucket*)zv, key);
 
                                if (EXPECTED(zv)) {
                                        /* Set filename & lineno information for inheritance errors */
@@ -3842,7 +4075,8 @@ static void preload_link(void)
                                        } else {
                                                CG(zend_lineno) = ce->info.user.line_start;
                                        }
-                                       if (zend_do_link_class(ce, NULL) == FAILURE) {
+                                       ce = zend_do_link_class(ce, NULL, key);
+                                       if (!ce) {
                                                ZEND_ASSERT(0 && "Class linking failed?");
                                        }
                                        CG(in_compilation) = 0;
@@ -3850,22 +4084,41 @@ static void preload_link(void)
 
                                        changed = 1;
                                }
+
+                               zend_string_release(key);
                        }
-                       if (ce->ce_flags & ZEND_ACC_LINKED) {
-                               if (!(ce->ce_flags & ZEND_ACC_CONSTANTS_UPDATED)) {
-                                       if ((ce->ce_flags & ZEND_ACC_TRAIT) /* don't update traits */
-                                        || preload_try_resolve_constants(ce)) {
-                                               ce->ce_flags |= ZEND_ACC_CONSTANTS_UPDATED;
-                                               changed = 1;
-                                       }
-                               }
+               } ZEND_HASH_FOREACH_END();
+       } while (changed);
+
+       /* Resolve property types */
+       ZEND_HASH_REVERSE_FOREACH_VAL(EG(class_table), zv) {
+               ce = Z_PTR_P(zv);
+               if (ce->type == ZEND_INTERNAL_CLASS) {
+                       break;
+               }
+               if (!(ce->ce_flags & ZEND_ACC_PROPERTY_TYPES_RESOLVED)) {
+                       if (!(ce->ce_flags & ZEND_ACC_TRAIT)) {
+                               preload_try_resolve_property_types(ce);
+                       }
+               }
+       } ZEND_HASH_FOREACH_END();
+
 
-                               if (!(ce->ce_flags & ZEND_ACC_PROPERTY_TYPES_RESOLVED)) {
-                                       if ((ce->ce_flags & ZEND_ACC_TRAIT) /* don't update traits */
-                                        || preload_try_resolve_property_types(ce)) {
-                                               ce->ce_flags |= ZEND_ACC_PROPERTY_TYPES_RESOLVED;
+       do {
+               changed = 0;
+
+               ZEND_HASH_REVERSE_FOREACH_VAL(EG(class_table), zv) {
+                       ce = Z_PTR_P(zv);
+                       if (ce->type == ZEND_INTERNAL_CLASS) {
+                               break;
+                       }
+                       if (!(ce->ce_flags & ZEND_ACC_CONSTANTS_UPDATED)) {
+                               if (!(ce->ce_flags & ZEND_ACC_TRAIT)) { /* don't update traits */
+                                       CG(in_compilation) = 1; /* prevent autoloading */
+                                       if (preload_try_resolve_constants(ce)) {
                                                changed = 1;
                                        }
+                                       CG(in_compilation) = 0;
                                }
                        }
                } ZEND_HASH_FOREACH_END();
@@ -3895,18 +4148,6 @@ static void preload_link(void)
                                        ZSTR_VAL(ce->name), kind, name);
                        }
                        zend_string_release(key);
-               } else if (!(ce->ce_flags & ZEND_ACC_CONSTANTS_UPDATED)) {
-                       const char *kind, *name;
-                       get_unresolved_initializer(ce, &kind, &name);
-                       zend_error_at(
-                               E_WARNING, ZSTR_VAL(ce->info.user.filename), ce->info.user.line_start,
-                               "Can't preload class %s with unresolved initializer for %s%s",
-                               ZSTR_VAL(ce->name), kind, name);
-               } else if (!(ce->ce_flags & ZEND_ACC_PROPERTY_TYPES_RESOLVED)) {
-                       zend_error_at(
-                               E_WARNING, ZSTR_VAL(ce->info.user.filename), ce->info.user.line_start,
-                               "Can't preload class %s with unresolved property types",
-                               ZSTR_VAL(ce->name));
                } else {
                        continue;
                }
@@ -3960,7 +4201,7 @@ static inline int preload_update_class_constants(zend_class_entry *ce) {
         * maybe-uninitialized analysis. */
        int result;
        zend_try {
-               result = zend_update_class_constants(ce);
+               result = preload_try_resolve_constants(ce) ? SUCCESS : FAILURE;
        } zend_catch {
                result = FAILURE;
        } zend_end_try();
@@ -3976,13 +4217,6 @@ static zend_class_entry *preload_load_prop_type(zend_property_info *prop, zend_s
        } else {
                ce = zend_lookup_class(name);
        }
-       if (ce) {
-               return ce;
-       }
-
-       zend_error_noreturn(E_ERROR,
-               "Failed to load class %s used by typed property %s::$%s during preloading",
-               ZSTR_VAL(name), ZSTR_VAL(prop->ce->name), zend_get_unmangled_property_name(prop->name));
        return ce;
 }
 
@@ -4008,12 +4242,7 @@ static void preload_ensure_classes_loadable() {
                        }
 
                        if (!(ce->ce_flags & ZEND_ACC_CONSTANTS_UPDATED)) {
-                               if (preload_update_class_constants(ce) == FAILURE) {
-                                       zend_error_noreturn(E_ERROR,
-                                               "Failed to resolve initializers of class %s during preloading",
-                                               ZSTR_VAL(ce->name));
-                               }
-                               ZEND_ASSERT(ce->ce_flags & ZEND_ACC_CONSTANTS_UPDATED);
+                               preload_update_class_constants(ce);
                        }
 
                        if (!(ce->ce_flags & ZEND_ACC_PROPERTY_TYPES_RESOLVED)) {
@@ -4025,7 +4254,9 @@ static void preload_ensure_classes_loadable() {
                                                        if (ZEND_TYPE_HAS_NAME(*single_type)) {
                                                                zend_class_entry *ce = preload_load_prop_type(
                                                                        prop, ZEND_TYPE_NAME(*single_type));
-                                                               ZEND_TYPE_SET_CE(*single_type, ce);
+                                                               if (ce) {
+                                                                       ZEND_TYPE_SET_CE(*single_type, ce);
+                                                               }
                                                        }
                                                } ZEND_TYPE_FOREACH_END();
                                        } ZEND_HASH_FOREACH_END();
@@ -4558,15 +4789,8 @@ static int accel_preload(const char *config, bool in_child)
                        ZEND_ASSERT(ce->ce_flags & ZEND_ACC_PRELOADED);
                        if (ce->default_static_members_count) {
                                zend_cleanup_internal_class_data(ce);
-                               if (ce->ce_flags & ZEND_ACC_CONSTANTS_UPDATED) {
-                                       int i;
-
-                                       for (i = 0; i < ce->default_static_members_count; i++) {
-                                               if (Z_TYPE(ce->default_static_members_table[i]) == IS_CONSTANT_AST) {
-                                                       ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
-                                                       break;
-                                               }
-                                       }
+                               if (ce->ce_flags & ZEND_ACC_HAS_AST_STATICS) {
+                                       ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
                                }
                        }
                        if (ce->ce_flags & ZEND_HAS_STATIC_IN_METHODS) {
@@ -4701,8 +4925,6 @@ static int accel_preload(const char *config, bool in_child)
                SHM_PROTECT();
                HANDLE_UNBLOCK_INTERRUPTIONS();
 
-               ZEND_ASSERT(ZCSG(preload_script)->arena_size == 0);
-
                preload_load();
 
                /* Store individual scripts with unlinked classes */
index 1d151b982e524ee5c3e8880efa84e9abbfb4e026..d8cf261ed2bd7457c4dffe025d231f3765dae407 100644 (file)
@@ -129,8 +129,6 @@ typedef struct _zend_persistent_script {
 
        void          *mem;                    /* shared memory area used by script structures */
        size_t         size;                   /* size of used shared memory */
-       void          *arena_mem;              /* part that should be copied into process */
-       size_t         arena_size;
 
        /* All entries that shouldn't be counted in the ADLER32
         * checksum must be declared in this struct
@@ -227,9 +225,7 @@ typedef struct _zend_accel_globals {
 #endif
        /* preallocated shared-memory block to save current script */
        void                   *mem;
-       void                   *arena_mem;
        zend_persistent_script *current_persistent_script;
-       bool               is_immutable_class;
        /* Temporary storage for warnings before they are moved into persistent_script. */
        bool               record_warnings;
        uint32_t                num_warnings;
index 5700a92ff1c44934c37d7ee65e9dde93c2ea84de..df496cc1a45a36575417bd6625eed394fb455782 100644 (file)
@@ -9878,7 +9878,10 @@ static int zend_jit_do_fcall(dasm_State **Dst, const zend_op *opline, const zend
                                if (func && !(func->op_array.fn_flags & ZEND_ACC_CLOSURE)) {
                                        if (ZEND_MAP_PTR_IS_OFFSET(func->op_array.run_time_cache)) {
                                                |       MEM_OP2_2_ZTS add, r2, aword, compiler_globals, map_ptr_base, r1
-                                       } else if (!zend_accel_in_shm(func->op_array.opcodes)) {
+                                       } else if ((func->op_array.fn_flags & ZEND_ACC_IMMUTABLE)
+                                               && (!func->op_array.scope || (func->op_array.scope->ce_flags & ZEND_ACC_LINKED))) {
+                                               |       MEM_OP2_2_ZTS add, r2, aword, compiler_globals, map_ptr_base, r1
+                                       } else {
                                                /* the called op_array may be not persisted yet */
                                                |       test r2, 1
                                                |       jz >1
@@ -12611,11 +12614,12 @@ static int zend_jit_recv_init(dasm_State **Dst, const zend_op *opline, const zen
        return 1;
 }
 
-static zend_property_info* zend_get_known_property_info(zend_class_entry *ce, zend_string *member, bool on_this, zend_string *filename)
+static zend_property_info* zend_get_known_property_info(const zend_op_array *op_array, zend_class_entry *ce, zend_string *member, bool on_this, zend_string *filename)
 {
        zend_property_info *info = NULL;
 
-       if (!ce ||
+       if ((on_this && (op_array->fn_flags & ZEND_ACC_TRAIT_CLONE)) ||
+           !ce ||
            !(ce->ce_flags & ZEND_ACC_LINKED) ||
            (ce->ce_flags & ZEND_ACC_TRAIT) ||
            ce->create_object) {
@@ -12745,7 +12749,7 @@ static int zend_jit_fetch_obj(dasm_State          **Dst,
 
        member = RT_CONSTANT(opline, opline->op2);
        ZEND_ASSERT(Z_TYPE_P(member) == IS_STRING && Z_STRVAL_P(member)[0] != '\0');
-       prop_info = zend_get_known_property_info(ce, Z_STR_P(member), opline->op1_type == IS_UNUSED, op_array->filename);
+       prop_info = zend_get_known_property_info(op_array, ce, Z_STR_P(member), opline->op1_type == IS_UNUSED, op_array->filename);
 
        if (opline->op1_type == IS_UNUSED || use_this) {
                |       GET_ZVAL_PTR FCARG1a, this_addr
@@ -12784,7 +12788,7 @@ static int zend_jit_fetch_obj(dasm_State          **Dst,
        }
 
        if (!prop_info && trace_ce && (trace_ce->ce_flags & ZEND_ACC_IMMUTABLE)) {
-               prop_info = zend_get_known_property_info(trace_ce, Z_STR_P(member), opline->op1_type == IS_UNUSED, op_array->filename);
+               prop_info = zend_get_known_property_info(op_array, trace_ce, Z_STR_P(member), opline->op1_type == IS_UNUSED, op_array->filename);
                if (prop_info) {
                        ce = trace_ce;
                        ce_is_instanceof = 0;
@@ -13140,7 +13144,7 @@ static int zend_jit_incdec_obj(dasm_State          **Dst,
        member = RT_CONSTANT(opline, opline->op2);
        ZEND_ASSERT(Z_TYPE_P(member) == IS_STRING && Z_STRVAL_P(member)[0] != '\0');
        name = Z_STR_P(member);
-       prop_info = zend_get_known_property_info(ce, name, opline->op1_type == IS_UNUSED, op_array->filename);
+       prop_info = zend_get_known_property_info(op_array, ce, name, opline->op1_type == IS_UNUSED, op_array->filename);
 
        if (opline->op1_type == IS_UNUSED || use_this) {
                |       GET_ZVAL_PTR FCARG1a, this_addr
@@ -13188,7 +13192,7 @@ static int zend_jit_incdec_obj(dasm_State          **Dst,
        }
 
        if (!prop_info && trace_ce && (trace_ce->ce_flags & ZEND_ACC_IMMUTABLE)) {
-               prop_info = zend_get_known_property_info(trace_ce, name, opline->op1_type == IS_UNUSED, op_array->filename);
+               prop_info = zend_get_known_property_info(op_array, trace_ce, name, opline->op1_type == IS_UNUSED, op_array->filename);
                if (prop_info) {
                        ce = trace_ce;
                        ce_is_instanceof = 0;
@@ -13514,7 +13518,7 @@ static int zend_jit_assign_obj_op(dasm_State          **Dst,
        member = RT_CONSTANT(opline, opline->op2);
        ZEND_ASSERT(Z_TYPE_P(member) == IS_STRING && Z_STRVAL_P(member)[0] != '\0');
        name = Z_STR_P(member);
-       prop_info = zend_get_known_property_info(ce, name, opline->op1_type == IS_UNUSED, op_array->filename);
+       prop_info = zend_get_known_property_info(op_array, ce, name, opline->op1_type == IS_UNUSED, op_array->filename);
 
        if (opline->op1_type == IS_UNUSED || use_this) {
                |       GET_ZVAL_PTR FCARG1a, this_addr
@@ -13571,7 +13575,7 @@ static int zend_jit_assign_obj_op(dasm_State          **Dst,
        }
 
        if (!prop_info && trace_ce && (trace_ce->ce_flags & ZEND_ACC_IMMUTABLE)) {
-               prop_info = zend_get_known_property_info(trace_ce, name, opline->op1_type == IS_UNUSED, op_array->filename);
+               prop_info = zend_get_known_property_info(op_array, trace_ce, name, opline->op1_type == IS_UNUSED, op_array->filename);
                if (prop_info) {
                        ce = trace_ce;
                        ce_is_instanceof = 0;
@@ -13847,7 +13851,7 @@ static int zend_jit_assign_obj(dasm_State          **Dst,
        member = RT_CONSTANT(opline, opline->op2);
        ZEND_ASSERT(Z_TYPE_P(member) == IS_STRING && Z_STRVAL_P(member)[0] != '\0');
        name = Z_STR_P(member);
-       prop_info = zend_get_known_property_info(ce, name, opline->op1_type == IS_UNUSED, op_array->filename);
+       prop_info = zend_get_known_property_info(op_array, ce, name, opline->op1_type == IS_UNUSED, op_array->filename);
 
        if (opline->op1_type == IS_UNUSED || use_this) {
                |       GET_ZVAL_PTR FCARG1a, this_addr
@@ -13903,7 +13907,7 @@ static int zend_jit_assign_obj(dasm_State          **Dst,
        }
 
        if (!prop_info && trace_ce && (trace_ce->ce_flags & ZEND_ACC_IMMUTABLE)) {
-               prop_info = zend_get_known_property_info(trace_ce, name, opline->op1_type == IS_UNUSED, op_array->filename);
+               prop_info = zend_get_known_property_info(op_array, trace_ce, name, opline->op1_type == IS_UNUSED, op_array->filename);
                if (prop_info) {
                        ce = trace_ce;
                        ce_is_instanceof = 0;
index 3b4d332828ae9a88b89d95e6e3a44fca6bea7a29..63fc1b6db1be8806502b5287c4266bc9653a34b6 100644 (file)
@@ -12,18 +12,8 @@ if (PHP_OS_FAMILY == 'Windows') die('skip Preloading is not supported on Windows
 ?>
 --FILE--
 <?php
-class B extends A {
-    function foo(): int { return 24; }
-}
 $c = new C;
 var_dump($c->foo());
 ?>
---EXPECTF--
-Warning: Can't preload unlinked class C: Parent with unresolved initializers B in %s on line %d
-
-Warning: Can't preload class B with unresolved initializer for constant X in %s on line %d
-
-Fatal error: Uncaught Error: Class "C" not found in %sbug78014.php:5
-Stack trace:
-#0 {main}
-  thrown in %sbug78014.php on line 5
+--EXPECT--
+int(42)
index f4dd45a062ecfa37825cd742d7c657d76b7b3df6..c8006dae1c1cb1de24703f8e4fe042926bed1dcf 100644 (file)
@@ -9,13 +9,16 @@ opcache.preload={PWD}/preload_undef_const.inc
 <?php
 require_once('skipif.inc');
 if (PHP_OS_FAMILY == 'Windows') die('skip Preloading is not supported on Windows');
-if (getenv('SKIP_ASAN')) die('xfail Startup failure leak');
 ?>
 --FILE--
 <?php
 var_dump(class_exists('Foo'));
+try {
+   new Foo();
+} catch (Throwable $ex) {
+       echo $ex->getMessage() . "\n";
+}
 ?>
 --EXPECT--
-Fatal error: Undefined constant self::DOES_NOT_EXIST in Unknown on line 0
-
-Fatal error: Failed to resolve initializers of class Foo during preloading in Unknown on line 0
+bool(true)
+Undefined constant self::DOES_NOT_EXIST
index a13b504cd14b48263ad63e17976b63f8e83f8351..88d0df5fddc82b10ffb66c12f42455b00e5c69fa 100644 (file)
@@ -9,14 +9,18 @@ opcache.preload={PWD}/preload_undef_const_2.inc
 <?php
 require_once('skipif.inc');
 if (PHP_OS_FAMILY == 'Windows') die('skip Preloading is not supported on Windows');
-if (getenv('SKIP_ASAN')) die('xfail Startup failure leak');
 ?>
 --FILE--
 <?php
 var_dump(trait_exists('T'));
 var_dump(class_exists('Foo'));
+try {
+    new Foo();
+} catch (Throwable $ex) {
+    echo $ex->getMessage() . "\n";
+}
 ?>
 --EXPECT--
-Fatal error: Undefined constant "UNDEF" in Unknown on line 0
-
-Fatal error: Failed to resolve initializers of class Foo during preloading in Unknown on line 0
+bool(true)
+bool(true)
+Undefined constant "UNDEF"
index 7c5ad9aa1a75499dcd4a3e8e6dc16f749a2afb1c..0ca2ae15b9ba72573cd7129a4d83a66aad1cc904 100644 (file)
@@ -11,5 +11,16 @@ require_once('skipif.inc');
 if (PHP_OS_FAMILY == 'Windows') die('skip Preloading is not supported on Windows');
 ?>
 --FILE--
---EXPECTF--
-Warning: Can't preload class Test with unresolved initializer for constant C in %s on line %d
+<?php
+class Foo {
+}
+var_dump(class_exists('Test'));
+try {
+    new Test();
+} catch (Throwable $ex) {
+    echo $ex->getMessage() . "\n";
+}
+?>
+--EXPECT--
+bool(true)
+Undefined constant Foo::BAR
index 158fc15ab6b16d739b376dd38bc3478611f2c53e..4f0c625b08d3441e2431dcd374a3af9820135412 100644 (file)
@@ -12,6 +12,5 @@ if (PHP_OS_FAMILY == 'Windows') die('skip Preloading is not supported on Windows
 ?>
 --FILE--
 OK
---EXPECTF--
-Warning: Can't preload class C with unresolved property types in %s on line %d
+--EXPECT--
 OK
index 665f3157e201fa5911c41fce7054568baa49a5ec..8d4e8e3712c8666c324422737698c4fac0817a24 100644 (file)
@@ -9,11 +9,17 @@ opcache.preload={PWD}/preload_loadable_classes_2.inc
 <?php
 require_once('skipif.inc');
 if (PHP_OS_FAMILY == 'Windows') die('skip Preloading is not supported on Windows');
-if (getenv('SKIP_ASAN')) die('xfail Startup failure leak');
 ?>
 --FILE--
-Unreachable
+<?php
+const UNDEF = 1;
+class Foo {
+    const UNDEF = 2;
+}
+var_dump(class_exists("Test"));
+var_dump(Test::X);
+var_dump(Test::Y);
 --EXPECT--
-Fatal error: Undefined constant "UNDEF" in Unknown on line 0
-
-Fatal error: Failed to resolve initializers of class Test during preloading in Unknown on line 0
+bool(true)
+int(1)
+int(2)
index 97309a6fccfe2082dbf5dd9f494765107b29695e..b12cc9d3cd4d69d2bb96cb5bb085d8ec49c1df99 100644 (file)
@@ -9,9 +9,15 @@ opcache.preload={PWD}/preload_loadable_classes_3.inc
 <?php
 require_once('skipif.inc');
 if (PHP_OS_FAMILY == 'Windows') die('skip Preloading is not supported on Windows');
-if (getenv('SKIP_ASAN')) die('xfail Startup failure leak');
 ?>
 --FILE--
-Unreachable
+<?php
+class Foo {
+}
+var_dump(new Test);
+?>
 --EXPECT--
-Fatal error: Failed to load class Foo used by typed property Test::$prop during preloading in Unknown on line 0
+object(Test)#1 (0) {
+  ["prop":protected]=>
+  uninitialized(Foo)
+}
index 3e2accd19ecdc128c00d2d964d6dfeed1462a93c..9e0b3570ee45fb5b6bf80ee6a23e53e5396105a0 100644 (file)
@@ -11,7 +11,12 @@ require_once('skipif.inc');
 if (PHP_OS_FAMILY == 'Windows') die('skip Preloading is not supported on Windows');
 ?>
 --FILE--
+<?php
+class Unknown {
+}
+$x = new Test;
+$x->prop = new Unknown;
+?>
 ===DONE===
---EXPECTF--
-Warning: Can't preload class Test with unresolved property types in %s on line %d
+--EXPECT--
 ===DONE===
index d3011da941e02a79563276c72a8b03cdf5fd199e..f17f7e80768aa5980615eaed8845b53a27048c4b 100644 (file)
 #include "zend_persist.h"
 #include "zend_shared_alloc.h"
 
-#define IN_ARENA(ptr) \
-       ((void*)(ptr) >= ZCG(current_persistent_script)->arena_mem && \
-        (void*)(ptr) < (void*)((char*)ZCG(current_persistent_script)->arena_mem + ZCG(current_persistent_script)->arena_size))
-
-#define ARENA_REALLOC(ptr) \
-       (void*)(((char*)(ptr)) + ((char*)ZCG(arena_mem) - (char*)ZCG(current_persistent_script)->arena_mem))
-
 typedef int (*id_function_t)(void *, void *);
 typedef void (*unique_copy_ctor_func_t)(void *pElement);
 
@@ -131,238 +124,6 @@ void zend_accel_move_user_classes(HashTable *src, uint32_t count, zend_script *s
        src->pDestructor = orig_dtor;
 }
 
-static void zend_hash_clone_constants(HashTable *ht)
-{
-       Bucket *p, *end;
-       zend_class_constant *c;
-
-       if (HT_FLAGS(ht) & HASH_FLAG_UNINITIALIZED) {
-               return;
-       }
-
-       p = emalloc(HT_SIZE(ht));
-       memcpy(p, HT_GET_DATA_ADDR(ht), HT_USED_SIZE(ht));
-       HT_SET_DATA_ADDR(ht, p);
-
-       p = ht->arData;
-       end = p + ht->nNumUsed;
-       for (; p != end; p++) {
-               ZEND_ASSERT(Z_TYPE(p->val) != IS_UNDEF);
-               c = Z_PTR(p->val);
-               if (IN_ARENA(c)) {
-                       c = ARENA_REALLOC(c);
-                       Z_PTR(p->val) = c;
-
-                       if (IN_ARENA(c->ce)) {
-                               c->ce = ARENA_REALLOC(c->ce);
-                       }
-               }
-       }
-}
-
-static void zend_hash_clone_methods(HashTable *ht)
-{
-       Bucket *p, *end;
-       zend_op_array *new_entry;
-
-       ht->pDestructor = ZEND_FUNCTION_DTOR;
-
-       if (HT_FLAGS(ht) & HASH_FLAG_UNINITIALIZED) {
-               return;
-       }
-
-       p = emalloc(HT_SIZE(ht));
-       memcpy(p, HT_GET_DATA_ADDR(ht), HT_USED_SIZE(ht));
-       HT_SET_DATA_ADDR(ht, p);
-
-       p = ht->arData;
-       end = p + ht->nNumUsed;
-       for (; p != end; p++) {
-               ZEND_ASSERT(Z_TYPE(p->val) != IS_UNDEF);
-               new_entry = Z_PTR(p->val);
-               if (IN_ARENA(new_entry)) {
-                       new_entry = ARENA_REALLOC(new_entry);
-                       Z_PTR(p->val) = new_entry;
-
-                       if (IN_ARENA(new_entry->scope)) {
-                               new_entry->scope = ARENA_REALLOC(new_entry->scope);
-
-                               /* update prototype */
-                               if (IN_ARENA(new_entry->prototype)) {
-                                       new_entry->prototype = ARENA_REALLOC(new_entry->prototype);
-                               }
-                       }
-                       if (IN_ARENA(ZEND_MAP_PTR(new_entry->run_time_cache))) {
-                               ZEND_MAP_PTR_INIT(new_entry->run_time_cache, ARENA_REALLOC(ZEND_MAP_PTR(new_entry->run_time_cache)));
-                       }
-                       ZEND_MAP_PTR_INIT(new_entry->static_variables_ptr, &new_entry->static_variables);
-               }
-       }
-}
-
-static void zend_hash_clone_prop_info(HashTable *ht)
-{
-       Bucket *p, *end;
-       zend_property_info *prop_info;
-
-       if (HT_FLAGS(ht) & HASH_FLAG_UNINITIALIZED) {
-               return;
-       }
-
-       p = emalloc(HT_SIZE(ht));
-       memcpy(p, HT_GET_DATA_ADDR(ht), HT_USED_SIZE(ht));
-       HT_SET_DATA_ADDR(ht, p);
-
-       p = ht->arData;
-       end = p + ht->nNumUsed;
-       for (; p != end; p++) {
-               ZEND_ASSERT(Z_TYPE(p->val) != IS_UNDEF);
-               prop_info = Z_PTR(p->val);
-               if (IN_ARENA(prop_info)) {
-                       prop_info = ARENA_REALLOC(prop_info);
-                       Z_PTR(p->val) = prop_info;
-
-                       if (IN_ARENA(prop_info->ce)) {
-                               prop_info->ce = ARENA_REALLOC(prop_info->ce);
-                       }
-
-                       if (ZEND_TYPE_HAS_LIST(prop_info->type)) {
-                               zend_type_list *list = ZEND_TYPE_LIST(prop_info->type);
-                               if (IN_ARENA(list)) {
-                                       list = ARENA_REALLOC(list);
-                                       ZEND_TYPE_SET_PTR(prop_info->type, list);
-
-                                       zend_type *list_type;
-                                       ZEND_TYPE_LIST_FOREACH(ZEND_TYPE_LIST(prop_info->type), list_type) {
-                                               if (ZEND_TYPE_HAS_CE(*list_type)) {
-                                                       zend_class_entry *ce = ZEND_TYPE_CE(*list_type);
-                                                       if (IN_ARENA(ce)) {
-                                                               ce = ARENA_REALLOC(ce);
-                                                               ZEND_TYPE_SET_PTR(*list_type, ce);
-                                                       }
-                                               }
-                                       } ZEND_TYPE_LIST_FOREACH_END();
-                               }
-                       } else if (ZEND_TYPE_HAS_CE(prop_info->type)) {
-                               zend_class_entry *ce = ZEND_TYPE_CE(prop_info->type);
-                               if (IN_ARENA(ce)) {
-                                       ce = ARENA_REALLOC(ce);
-                                       ZEND_TYPE_SET_PTR(prop_info->type, ce);
-                               }
-                       }
-               }
-       }
-}
-
-#define zend_update_inherited_handler(handler) \
-{ \
-       if (ce->handler != NULL && IN_ARENA(ce->handler)) { \
-               ce->handler = ARENA_REALLOC(ce->handler); \
-       } \
-}
-
-/* Protects class' refcount, copies default properties, functions and class name */
-static void zend_class_copy_ctor(zend_class_entry **pce)
-{
-       zend_class_entry *ce = *pce;
-       zval *src, *dst, *end;
-
-       *pce = ce = ARENA_REALLOC(ce);
-       ce->refcount = 1;
-
-       if ((ce->ce_flags & ZEND_ACC_LINKED) && IN_ARENA(ce->parent)) {
-               ce->parent = ARENA_REALLOC(ce->parent);
-       }
-
-       if (ce->default_properties_table) {
-               dst = emalloc(sizeof(zval) * ce->default_properties_count);
-               src = ce->default_properties_table;
-               end = src + ce->default_properties_count;
-               ce->default_properties_table = dst;
-               for (; src != end; src++, dst++) {
-                       ZVAL_COPY_VALUE_PROP(dst, src);
-               }
-       }
-
-       zend_hash_clone_methods(&ce->function_table);
-
-       /* static members */
-       if (ce->default_static_members_table) {
-               int i, end;
-               zend_class_entry *parent = !(ce->ce_flags & ZEND_ACC_LINKED) ? NULL : ce->parent;
-
-               dst = emalloc(sizeof(zval) * ce->default_static_members_count);
-               src = ce->default_static_members_table;
-               ce->default_static_members_table = dst;
-               i = ce->default_static_members_count - 1;
-
-               /* Copy static properties in this class */
-               end = parent ? parent->default_static_members_count : 0;
-               for (; i >= end; i--) {
-                       zval *p = &dst[i];
-                       ZVAL_COPY_VALUE(p, &src[i]);
-               }
-
-               /* Create indirections to static properties from parent classes */
-               while (parent && parent->default_static_members_table) {
-                       end = parent->parent ? parent->parent->default_static_members_count : 0;
-                       for (; i >= end; i--) {
-                               zval *p = &dst[i];
-                               ZVAL_INDIRECT(p, &parent->default_static_members_table[i]);
-                       }
-
-                       parent = parent->parent;
-               }
-       }
-       ZEND_MAP_PTR_INIT(ce->static_members_table, &ce->default_static_members_table);
-
-       /* properties_info */
-       zend_hash_clone_prop_info(&ce->properties_info);
-
-       /* constants table */
-       zend_hash_clone_constants(&ce->constants_table);
-
-       if (ce->properties_info_table) {
-               int i;
-               ce->properties_info_table = ARENA_REALLOC(ce->properties_info_table);
-               for (i = 0; i < ce->default_properties_count; i++) {
-                       if (IN_ARENA(ce->properties_info_table[i])) {
-                               ce->properties_info_table[i] = ARENA_REALLOC(ce->properties_info_table[i]);
-                       }
-               }
-       }
-
-       if (ce->num_interfaces) {
-               if (ce->ce_flags & ZEND_ACC_LINKED) {
-                       zend_class_entry **interfaces = emalloc(sizeof(zend_class_entry*) * ce->num_interfaces);
-                       uint32_t i;
-
-                       for (i = 0; i < ce->num_interfaces; i++) {
-                               if (IN_ARENA(ce->interfaces[i])) {
-                                       interfaces[i] = ARENA_REALLOC(ce->interfaces[i]);
-                               } else {
-                                       interfaces[i] = ce->interfaces[i];
-                               }
-                       }
-                       ce->interfaces = interfaces;
-               }
-       }
-
-       zend_update_inherited_handler(constructor);
-       zend_update_inherited_handler(destructor);
-       zend_update_inherited_handler(clone);
-       zend_update_inherited_handler(__get);
-       zend_update_inherited_handler(__set);
-       zend_update_inherited_handler(__call);
-       zend_update_inherited_handler(__isset);
-       zend_update_inherited_handler(__unset);
-       zend_update_inherited_handler(__tostring);
-       zend_update_inherited_handler(__callstatic);
-       zend_update_inherited_handler(__debugInfo);
-       zend_update_inherited_handler(__serialize);
-       zend_update_inherited_handler(__unserialize);
-}
-
 static void zend_accel_function_hash_copy(HashTable *target, HashTable *source)
 {
        zend_function *function1, *function2;
@@ -452,196 +213,6 @@ static void zend_accel_class_hash_copy(HashTable *target, HashTable *source)
        return;
 }
 
-static void zend_accel_class_hash_copy_from_shm(HashTable *target, HashTable *source)
-{
-       Bucket *p, *end;
-       zval *t;
-
-       zend_hash_extend(target, target->nNumUsed + source->nNumUsed, 0);
-       p = source->arData;
-       end = p + source->nNumUsed;
-       for (; p != end; p++) {
-               ZEND_ASSERT(Z_TYPE(p->val) != IS_UNDEF);
-               ZEND_ASSERT(p->key);
-               t = zend_hash_find_ex(target, p->key, 1);
-               if (UNEXPECTED(t != NULL)) {
-                       if (EXPECTED(ZSTR_LEN(p->key) > 0) && EXPECTED(ZSTR_VAL(p->key)[0] == 0)) {
-                               /* See comment in zend_accel_function_hash_copy(). */
-                               continue;
-                       } else if (UNEXPECTED(!ZCG(accel_directives).ignore_dups)) {
-                               zend_class_entry *ce1 = Z_PTR(p->val);
-                               if (!(ce1->ce_flags & ZEND_ACC_ANON_CLASS)) {
-                                       CG(in_compilation) = 1;
-                                       zend_set_compiled_filename(ce1->info.user.filename);
-                                       CG(zend_lineno) = ce1->info.user.line_start;
-                                       zend_error(E_ERROR,
-                                                       "Cannot declare %s %s, because the name is already in use",
-                                                       zend_get_object_type(ce1), ZSTR_VAL(ce1->name));
-                                       return;
-                               }
-                               continue;
-                       }
-               } else {
-                       t = _zend_hash_append_ptr_ex(target, p->key, Z_PTR(p->val), 1);
-                       if (!(((zend_class_entry*)Z_PTR_P(t))->ce_flags & ZEND_ACC_IMMUTABLE)) {
-                               zend_class_copy_ctor((zend_class_entry**)&Z_PTR_P(t));
-                       }
-               }
-       }
-       target->nInternalPointer = 0;
-       return;
-}
-
-#if __has_feature(memory_sanitizer)
-# define fast_memcpy memcpy
-#elif defined(__AVX__)
-# include <nmmintrin.h>
-# if defined(__GNUC__) && defined(__i386__)
-static zend_always_inline void fast_memcpy(void *dest, const void *src, size_t size)
-{
-       size_t delta = (char*)dest - (char*)src;
-
-       __asm__ volatile (
-               ".align 16\n\t"
-               ".LL0%=:\n\t"
-               "prefetchnta 0x40(%1)\n\t"
-               "vmovaps (%1), %%ymm0\n\t"
-               "vmovaps 0x20(%1), %%ymm1\n\t"
-               "vmovaps %%ymm0, (%1,%2)\n\t"
-               "vmovaps %%ymm1, 0x20(%1,%2)\n\t"
-               "addl $0x40, %1\n\t"
-               "subl $0x40, %0\n\t"
-               "ja .LL0%="
-               : "+r"(size),
-               "+r"(src)
-               : "r"(delta)
-               : "cc", "memory", "%ymm0", "%ymm1");
-}
-# elif defined(__GNUC__) && defined(__x86_64__)
-static zend_always_inline void fast_memcpy(void *dest, const void *src, size_t size)
-{
-       size_t delta = (char*)dest - (char*)src;
-
-       __asm__ volatile (
-               ".align 16\n\t"
-               ".LL0%=:\n\t"
-               "prefetchnta 0x40(%1)\n\t"
-               "vmovaps (%1), %%ymm0\n\t"
-               "vmovaps 0x20(%1), %%ymm1\n\t"
-               "vmovaps %%ymm0, (%1,%2)\n\t"
-               "vmovaps %%ymm1, 0x20(%1,%2)\n\t"
-               "addq $0x40, %1\n\t"
-               "subq $0x40, %0\n\t"
-               "ja .LL0%="
-               : "+r"(size),
-               "+r"(src)
-               : "r"(delta)
-               : "cc", "memory", "%ymm0", "%ymm1");
-}
-# else
-static zend_always_inline void fast_memcpy(void *dest, const void *src, size_t size)
-{
-       __m256 *dqdest = (__m256*)dest;
-       const __m256 *dqsrc  = (const __m256*)src;
-       const __m256 *end  = (const __m256*)((const char*)src + size);
-
-       do {
-#ifdef PHP_WIN32
-               _mm_prefetch((const char *)(dqsrc + 2), _MM_HINT_NTA);
-#else
-               _mm_prefetch(dqsrc + 2, _MM_HINT_NTA);
-#endif
-
-               __m256 ymm0 = _mm256_load_ps((const float *)(dqsrc + 0));
-               __m256 ymm1 = _mm256_load_ps((const float *)(dqsrc + 1));
-               dqsrc  += 2;
-               _mm256_store_ps((float *)(dqdest + 0), ymm0);
-               _mm256_store_ps((float *)(dqdest + 1), ymm1);
-               dqdest += 2;
-       } while (dqsrc != end);
-}
-# endif
-#elif defined(__SSE2__)
-# include <emmintrin.h>
-# if defined(__GNUC__) && defined(__i386__)
-static zend_always_inline void fast_memcpy(void *dest, const void *src, size_t size)
-{
-       size_t delta = (char*)dest - (char*)src;
-
-       __asm__ volatile (
-               ".align 16\n\t"
-               ".LL0%=:\n\t"
-               "prefetchnta 0x40(%1)\n\t"
-               "movdqa (%1), %%xmm0\n\t"
-               "movdqa 0x10(%1), %%xmm1\n\t"
-               "movdqa 0x20(%1), %%xmm2\n\t"
-               "movdqa 0x30(%1), %%xmm3\n\t"
-               "movdqa %%xmm0, (%1,%2)\n\t"
-               "movdqa %%xmm1, 0x10(%1,%2)\n\t"
-               "movdqa %%xmm2, 0x20(%1,%2)\n\t"
-               "movdqa %%xmm3, 0x30(%1,%2)\n\t"
-               "addl $0x40, %1\n\t"
-               "subl $0x40, %0\n\t"
-               "ja .LL0%="
-               : "+r"(size),
-                 "+r"(src)
-               : "r"(delta)
-               : "cc", "memory", "%xmm0", "%xmm1", "%xmm1", "%xmm2");
-}
-# elif defined(__GNUC__) && defined(__x86_64__) && !defined(__ILP32__)
-static zend_always_inline void fast_memcpy(void *dest, const void *src, size_t size)
-{
-       size_t delta = (char*)dest - (char*)src;
-
-       __asm__ volatile (
-               ".align 16\n\t"
-               ".LL0%=:\n\t"
-               "prefetchnta 0x40(%1)\n\t"
-               "movdqa (%1), %%xmm0\n\t"
-               "movdqa 0x10(%1), %%xmm1\n\t"
-               "movdqa 0x20(%1), %%xmm2\n\t"
-               "movdqa 0x30(%1), %%xmm3\n\t"
-               "movdqa %%xmm0, (%1,%2)\n\t"
-               "movdqa %%xmm1, 0x10(%1,%2)\n\t"
-               "movdqa %%xmm2, 0x20(%1,%2)\n\t"
-               "movdqa %%xmm3, 0x30(%1,%2)\n\t"
-               "addq $0x40, %1\n\t"
-               "subq $0x40, %0\n\t"
-               "ja .LL0%="
-               : "+r"(size),
-                 "+r"(src)
-               : "r"(delta)
-               : "cc", "memory", "%xmm0", "%xmm1", "%xmm1", "%xmm2");
-}
-# else
-static zend_always_inline void fast_memcpy(void *dest, const void *src, size_t size)
-{
-       __m128i *dqdest = (__m128i*)dest;
-       const __m128i *dqsrc  = (const __m128i*)src;
-       const __m128i *end  = (const __m128i*)((const char*)src + size);
-
-       do {
-#ifdef PHP_WIN32
-               _mm_prefetch((const char *)(dqsrc + 4), _MM_HINT_NTA);
-#else
-               _mm_prefetch(dqsrc + 4, _MM_HINT_NTA);
-#endif
-
-               __m128i xmm0 = _mm_load_si128(dqsrc + 0);
-               __m128i xmm1 = _mm_load_si128(dqsrc + 1);
-               __m128i xmm2 = _mm_load_si128(dqsrc + 2);
-               __m128i xmm3 = _mm_load_si128(dqsrc + 3);
-               dqsrc  += 4;
-               _mm_store_si128(dqdest + 0, xmm0);
-               _mm_store_si128(dqdest + 1, xmm1);
-               _mm_store_si128(dqdest + 2, xmm2);
-               _mm_store_si128(dqdest + 3, xmm3);
-               dqdest += 4;
-       } while (dqsrc != end);
-}
-# endif
-#endif
-
 zend_op_array* zend_accel_load_script(zend_persistent_script *persistent_script, int from_shared_memory)
 {
        zend_op_array *op_array;
@@ -654,27 +225,11 @@ zend_op_array* zend_accel_load_script(zend_persistent_script *persistent_script,
                zend_accel_function_hash_copy(CG(function_table), &persistent_script->script.function_table);
        }
 
-       if (EXPECTED(from_shared_memory)) {
-               ZCG(current_persistent_script) = persistent_script;
-               ZCG(arena_mem) = NULL;
-               if (EXPECTED(persistent_script->arena_size)) {
-#if defined(__AVX__) || defined(__SSE2__)
-                       /* Target address must be aligned to 64-byte boundary */
-                       _mm_prefetch(persistent_script->arena_mem, _MM_HINT_NTA);
-                       ZCG(arena_mem) = zend_arena_alloc(&CG(arena), persistent_script->arena_size + 64);
-                       ZCG(arena_mem) = (void*)(((zend_uintptr_t)ZCG(arena_mem) + 63L) & ~63L);
-                       fast_memcpy(ZCG(arena_mem), persistent_script->arena_mem, persistent_script->arena_size);
-#else
-                       ZCG(arena_mem) = zend_arena_alloc(&CG(arena), persistent_script->arena_size);
-                       memcpy(ZCG(arena_mem), persistent_script->arena_mem, persistent_script->arena_size);
-#endif
-               }
-
-               /* Copy all the necessary stuff from shared memory to regular memory, and protect the shared script */
-               if (zend_hash_num_elements(&persistent_script->script.class_table) > 0) {
-                       zend_accel_class_hash_copy_from_shm(CG(class_table), &persistent_script->script.class_table);
-               }
+       if (zend_hash_num_elements(&persistent_script->script.class_table) > 0) {
+               zend_accel_class_hash_copy(CG(class_table), &persistent_script->script.class_table);
+       }
 
+       if (EXPECTED(from_shared_memory)) {
                /* Register __COMPILER_HALT_OFFSET__ constant */
                if (persistent_script->compiler_halt_offset != 0 &&
                    persistent_script->script.filename) {
@@ -688,12 +243,7 @@ zend_op_array* zend_accel_load_script(zend_persistent_script *persistent_script,
                        zend_string_release_ex(name, 0);
                }
 
-               ZCG(current_persistent_script) = NULL;
                zend_map_ptr_extend(ZCSG(map_ptr_last));
-       } else /* if (!from_shared_memory) */ {
-               if (zend_hash_num_elements(&persistent_script->script.class_table) > 0) {
-                       zend_accel_class_hash_copy(CG(class_table), &persistent_script->script.class_table);
-               }
        }
 
        if (persistent_script->script.first_early_binding_opline != (uint32_t)-1) {
index 62a2d261ff27b69336bea2b7940380b004e74e59..56a26eec5d8c8d9616f740d7c2d7abd19401c1fa 100644 (file)
@@ -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)
index 9bdba91639a6bbdca6a9574ca00d4537e9fbf99e..a95c614f2a273dffb666837faf18d17db3f87ae8 100644 (file)
@@ -115,7 +115,11 @@ static void zend_hash_persist(HashTable *ht)
        }
        if (HT_FLAGS(ht) & HASH_FLAG_PACKED) {
                void *data = HT_GET_DATA_ADDR(ht);
-               data = zend_shared_memdup_free(data, HT_USED_SIZE(ht));
+               if (GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE) {
+                       data = zend_shared_memdup(data, HT_USED_SIZE(ht));
+               } else {
+                       data = zend_shared_memdup_free(data, HT_USED_SIZE(ht));
+               }
                HT_SET_DATA_ADDR(ht, data);
        } else if (ht->nNumUsed > HT_MIN_SIZE && ht->nNumUsed < (uint32_t)(-(int32_t)ht->nTableMask) / 4) {
                /* compact table */
@@ -133,7 +137,9 @@ static void zend_hash_persist(HashTable *ht)
                ZCG(mem) = (void*)((char*)ZCG(mem) + ZEND_ALIGNED_SIZE((hash_size * sizeof(uint32_t)) + (ht->nNumUsed * sizeof(Bucket))));
                HT_HASH_RESET(ht);
                memcpy(ht->arData, old_buckets, ht->nNumUsed * sizeof(Bucket));
-               efree(old_data);
+               if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE)) {
+                       efree(old_data);
+               }
 
                /* rehash */
                for (idx = 0; idx < ht->nNumUsed; idx++) {
@@ -150,7 +156,9 @@ static void zend_hash_persist(HashTable *ht)
                ZEND_ASSERT(((zend_uintptr_t)ZCG(mem) & 0x7) == 0); /* should be 8 byte aligned */
                ZCG(mem) = (void*)((char*)data + ZEND_ALIGNED_SIZE(HT_USED_SIZE(ht)));
                memcpy(data, old_data, HT_USED_SIZE(ht));
-               efree(old_data);
+               if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE)) {
+                       efree(old_data);
+               }
                HT_SET_DATA_ADDR(ht, data);
        }
 }
@@ -206,28 +214,21 @@ static void zend_persist_zval(zval *z)
 
                                if (!Z_REFCOUNTED_P(z)) {
                                        Z_ARR_P(z) = zend_shared_memdup_put(Z_ARR_P(z), sizeof(zend_array));
-                                       zend_hash_persist(Z_ARRVAL_P(z));
-                                       ZEND_HASH_FOREACH_BUCKET(Z_ARRVAL_P(z), p) {
-                                               if (p->key) {
-                                                       zend_accel_memdup_interned_string(p->key);
-                                               }
-                                               zend_persist_zval(&p->val);
-                                       } ZEND_HASH_FOREACH_END();
                                } else {
                                        GC_REMOVE_FROM_BUFFER(Z_ARR_P(z));
                                        Z_ARR_P(z) = zend_shared_memdup_put_free(Z_ARR_P(z), sizeof(zend_array));
-                                       zend_hash_persist(Z_ARRVAL_P(z));
-                                       ZEND_HASH_FOREACH_BUCKET(Z_ARRVAL_P(z), p) {
-                                               if (p->key) {
-                                                       zend_accel_store_interned_string(p->key);
-                                               }
-                                               zend_persist_zval(&p->val);
-                                       } ZEND_HASH_FOREACH_END();
-                                       /* make immutable array */
-                                       Z_TYPE_FLAGS_P(z) = 0;
-                                       GC_SET_REFCOUNT(Z_COUNTED_P(z), 2);
-                                       GC_ADD_FLAGS(Z_COUNTED_P(z), IS_ARRAY_IMMUTABLE);
                                }
+                               zend_hash_persist(Z_ARRVAL_P(z));
+                               ZEND_HASH_FOREACH_BUCKET(Z_ARRVAL_P(z), p) {
+                                       if (p->key) {
+                                               zend_accel_store_interned_string(p->key);
+                                       }
+                                       zend_persist_zval(&p->val);
+                               } ZEND_HASH_FOREACH_END();
+                               /* make immutable array */
+                               Z_TYPE_FLAGS_P(z) = 0;
+                               GC_SET_REFCOUNT(Z_COUNTED_P(z), 2);
+                               GC_ADD_FLAGS(Z_COUNTED_P(z), IS_ARRAY_IMMUTABLE);
                        }
                        break;
                case IS_CONSTANT_AST:
@@ -235,7 +236,7 @@ static void zend_persist_zval(zval *z)
                        if (new_ptr) {
                                Z_AST_P(z) = new_ptr;
                                Z_TYPE_FLAGS_P(z) = 0;
-                       } else {
+                       } else if (!zend_accel_in_shm(Z_AST_P(z))) {
                                zend_ast_ref *old_ref = Z_AST_P(z);
                                Z_AST_P(z) = zend_shared_memdup_put(Z_AST_P(z), sizeof(zend_ast_ref));
                                zend_persist_ast(GC_AST(old_ref));
@@ -258,6 +259,10 @@ static HashTable *zend_persist_attributes(HashTable *attributes)
                uint32_t i;
                zval *v;
 
+               if (zend_accel_in_shm(attributes)) {
+                       return attributes;
+               }
+
                zend_hash_persist(attributes);
 
                ZEND_HASH_FOREACH_VAL(attributes, v) {
@@ -285,17 +290,12 @@ static HashTable *zend_persist_attributes(HashTable *attributes)
        return ptr;
 }
 
-static void zend_persist_type(zend_type *type, bool use_arena) {
+static void zend_persist_type(zend_type *type) {
        if (ZEND_TYPE_HAS_LIST(*type)) {
                zend_type_list *list = ZEND_TYPE_LIST(*type);
                if (ZEND_TYPE_USES_ARENA(*type)) {
-                       if (!ZCG(is_immutable_class) && use_arena) {
-                               list = zend_shared_memdup_arena_put(list, ZEND_TYPE_LIST_SIZE(list->num_types));
-                       } else {
-                               /* Moved from arena to SHM because type list was fully resolved. */
-                               list = zend_shared_memdup_put(list, ZEND_TYPE_LIST_SIZE(list->num_types));
-                               ZEND_TYPE_FULL_MASK(*type) &= ~_ZEND_TYPE_ARENA_BIT;
-                       }
+                       list = zend_shared_memdup_put(list, ZEND_TYPE_LIST_SIZE(list->num_types));
+                       ZEND_TYPE_FULL_MASK(*type) &= ~_ZEND_TYPE_ARENA_BIT;
                } else {
                        list = zend_shared_memdup_put_free(list, ZEND_TYPE_LIST_SIZE(list->num_types));
                }
@@ -308,6 +308,11 @@ static void zend_persist_type(zend_type *type, bool use_arena) {
                        zend_string *type_name = ZEND_TYPE_NAME(*single_type);
                        zend_accel_store_interned_string(type_name);
                        ZEND_TYPE_SET_PTR(*single_type, type_name);
+                       if (!ZCG(current_persistent_script)->corrupted) {
+                               // TODO: we may use single map_ptr slot for each class name ???
+                               single_type->type_mask |= _ZEND_TYPE_CACHE_BIT;
+                               single_type->ce_cache__ptr = (uint32_t)(uintptr_t)zend_map_ptr_new();
+                       }
                }
        } ZEND_TYPE_FOREACH_END();
 }
@@ -352,6 +357,7 @@ static void zend_persist_op_array_ex(zend_op_array *op_array, zend_persistent_sc
                if (scope) {
                        op_array->scope = scope;
                }
+
                if (op_array->prototype) {
                        zend_function *ptr = zend_shared_alloc_get_xlat_entry(op_array->prototype);
 
@@ -367,7 +373,6 @@ static void zend_persist_op_array_ex(zend_op_array *op_array, zend_persistent_sc
                                op_array->static_variables = zend_shared_alloc_get_xlat_entry(op_array->static_variables);
                                ZEND_ASSERT(op_array->static_variables != NULL);
                        }
-                       ZEND_MAP_PTR_INIT(op_array->static_variables_ptr, &op_array->static_variables);
                        if (op_array->literals) {
                                op_array->literals = zend_shared_alloc_get_xlat_entry(op_array->literals);
                                ZEND_ASSERT(op_array->literals != NULL);
@@ -435,7 +440,7 @@ static void zend_persist_op_array_ex(zend_op_array *op_array, zend_persistent_sc
                op_array->prototype = NULL;
        }
 
-       if (op_array->static_variables) {
+       if (op_array->static_variables && !zend_accel_in_shm(op_array->static_variables)) {
                Bucket *p;
 
                zend_hash_persist(op_array->static_variables);
@@ -449,7 +454,12 @@ static void zend_persist_op_array_ex(zend_op_array *op_array, zend_persistent_sc
                GC_SET_REFCOUNT(op_array->static_variables, 2);
                GC_TYPE_INFO(op_array->static_variables) = GC_ARRAY | ((IS_ARRAY_IMMUTABLE|GC_NOT_COLLECTABLE) << GC_FLAGS_SHIFT);
        }
-       ZEND_MAP_PTR_INIT(op_array->static_variables_ptr, &op_array->static_variables);
+
+       if (op_array->scope
+        && !(op_array->fn_flags & ZEND_ACC_CLOSURE)
+        && (op_array->scope->ce_flags & ZEND_ACC_CACHED)) {
+               return;
+       }
 
        if (op_array->literals) {
                zval *p, *end;
@@ -551,7 +561,6 @@ static void zend_persist_op_array_ex(zend_op_array *op_array, zend_persistent_sc
 
                efree(op_array->opcodes);
                op_array->opcodes = new_opcodes;
-               ZEND_MAP_PTR_INIT(op_array->run_time_cache, NULL);
        }
 
        if (op_array->filename) {
@@ -575,7 +584,7 @@ static void zend_persist_op_array_ex(zend_op_array *op_array, zend_persistent_sc
                        if (arg_info[i].name) {
                                zend_accel_store_interned_string(arg_info[i].name);
                        }
-                       zend_persist_type(&arg_info[i].type, 0);
+                       zend_persist_type(&arg_info[i].type);
                }
                if (op_array->fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
                        arg_info++;
@@ -636,13 +645,11 @@ static void zend_persist_op_array(zval *zv)
                        ZEND_MAP_PTR_NEW(op_array->static_variables_ptr);
                }
        } else {
-               ZEND_MAP_PTR_INIT(op_array->run_time_cache, ZCG(arena_mem));
-               ZCG(arena_mem) = (void*)(((char*)ZCG(arena_mem)) + ZEND_ALIGNED_SIZE(sizeof(void*)));
-               ZEND_MAP_PTR_SET(op_array->run_time_cache, NULL);
+               ZEND_MAP_PTR_INIT(op_array->static_variables_ptr, &op_array->static_variables);
        }
 }
 
-static void zend_persist_class_method(zval *zv)
+static void zend_persist_class_method(zval *zv, zend_class_entry *ce)
 {
        zend_op_array *op_array = Z_PTR_P(zv);
        zend_op_array *old_op_array;
@@ -654,11 +661,7 @@ static void zend_persist_class_method(zval *zv)
                        if (old_op_array) {
                                Z_PTR_P(zv) = old_op_array;
                        } else {
-                               if (ZCG(is_immutable_class)) {
-                                       op_array = Z_PTR_P(zv) = zend_shared_memdup_put(op_array, sizeof(zend_internal_function));
-                               } else {
-                                       op_array = Z_PTR_P(zv) = zend_shared_memdup_arena_put(op_array, sizeof(zend_internal_function));
-                               }
+                               op_array = Z_PTR_P(zv) = zend_shared_memdup_put(op_array, sizeof(zend_internal_function));
                                if (op_array->scope) {
                                        void *persist_ptr;
 
@@ -676,6 +679,14 @@ static void zend_persist_class_method(zval *zv)
                return;
        }
 
+       if ((op_array->fn_flags & ZEND_ACC_IMMUTABLE)
+        && !op_array->static_variables
+        && !ZCG(current_persistent_script)->corrupted
+        && zend_accel_in_shm(op_array)) {
+               zend_shared_alloc_register_xlat_entry(op_array, op_array);
+               return;
+       }
+
        old_op_array = zend_shared_alloc_get_xlat_entry(op_array);
        if (old_op_array) {
                Z_PTR_P(zv) = old_op_array;
@@ -692,33 +703,27 @@ static void zend_persist_class_method(zval *zv)
                }
                return;
        }
-       if (ZCG(is_immutable_class)) {
-               op_array = Z_PTR_P(zv) = zend_shared_memdup_put(op_array, sizeof(zend_op_array));
-       } else {
-               op_array = Z_PTR_P(zv) = zend_shared_memdup_arena_put(op_array, sizeof(zend_op_array));
-       }
+       op_array = Z_PTR_P(zv) = zend_shared_memdup_put(op_array, sizeof(zend_op_array));
        zend_persist_op_array_ex(op_array, NULL);
-       if (ZCG(is_immutable_class)) {
+       if ((ce->ce_flags & ZEND_ACC_LINKED)
+        && (ce->ce_flags & ZEND_ACC_IMMUTABLE)) {
                op_array->fn_flags |= ZEND_ACC_IMMUTABLE;
                ZEND_MAP_PTR_NEW(op_array->run_time_cache);
                if (op_array->static_variables) {
                        ZEND_MAP_PTR_NEW(op_array->static_variables_ptr);
                }
        } else {
-               ZEND_MAP_PTR_INIT(op_array->run_time_cache, ZCG(arena_mem));
-               ZCG(arena_mem) = (void*)(((char*)ZCG(arena_mem)) + ZEND_ALIGNED_SIZE(sizeof(void*)));
-               ZEND_MAP_PTR_SET(op_array->run_time_cache, NULL);
+               if (ce->ce_flags & ZEND_ACC_IMMUTABLE) {
+                       ZEND_MAP_PTR_INIT(op_array->run_time_cache, NULL);
+               }
+               ZEND_MAP_PTR_INIT(op_array->static_variables_ptr, &op_array->static_variables);
        }
 }
 
 static zend_property_info *zend_persist_property_info(zend_property_info *prop)
 {
        zend_class_entry *ce;
-       if (ZCG(is_immutable_class)) {
-               prop = zend_shared_memdup_put(prop, sizeof(zend_property_info));
-       } else {
-               prop = zend_shared_memdup_arena_put(prop, sizeof(zend_property_info));
-       }
+       prop = zend_shared_memdup_put(prop, sizeof(zend_property_info));
        ce = zend_shared_alloc_get_xlat_entry(prop->ce);
        if (ce) {
                prop->ce = ce;
@@ -738,7 +743,7 @@ static zend_property_info *zend_persist_property_info(zend_property_info *prop)
        if (prop->attributes) {
                prop->attributes = zend_persist_attributes(prop->attributes);
        }
-       zend_persist_type(&prop->type, 1);
+       zend_persist_type(&prop->type);
        return prop;
 }
 
@@ -751,11 +756,7 @@ static void zend_persist_class_constant(zval *zv)
                Z_PTR_P(zv) = c;
                return;
        }
-       if (ZCG(is_immutable_class)) {
-               c = Z_PTR_P(zv) = zend_shared_memdup_put(Z_PTR_P(zv), sizeof(zend_class_constant));
-       } else {
-               c = Z_PTR_P(zv) = zend_shared_memdup_arena_put(Z_PTR_P(zv), sizeof(zend_class_constant));
-       }
+       c = Z_PTR_P(zv) = zend_shared_memdup_put(Z_PTR_P(zv), sizeof(zend_class_constant));
        zend_persist_zval(&c->value);
        ce = zend_shared_alloc_get_xlat_entry(c->ce);
        if (ce) {
@@ -783,39 +784,28 @@ static void zend_persist_class_constant(zval *zv)
        }
 }
 
-static void zend_persist_class_entry(zval *zv)
+zend_class_entry *zend_persist_class_entry(zend_class_entry *orig_ce)
 {
        Bucket *p;
-       zend_class_entry *orig_ce = Z_PTR_P(zv), *ce = orig_ce;
+       zend_class_entry *ce = orig_ce;
 
        if (ce->type == ZEND_USER_CLASS) {
                /* The same zend_class_entry may be reused by class_alias */
                zend_class_entry *new_ce = zend_shared_alloc_get_xlat_entry(ce);
                if (new_ce) {
-                       Z_PTR_P(zv) = new_ce;
-                       return;
+                       return new_ce;
                }
-               if ((ce->ce_flags & ZEND_ACC_LINKED)
-                && (ce->ce_flags & ZEND_ACC_CONSTANTS_UPDATED)
-                && (ce->ce_flags & ZEND_ACC_PROPERTY_TYPES_RESOLVED)
-                && !ZCG(current_persistent_script)->corrupted) {
-                       ZCG(is_immutable_class) = 1;
-                       ce = Z_PTR_P(zv) = zend_shared_memdup_put(ce, sizeof(zend_class_entry));
+               ce = zend_shared_memdup_put(ce, sizeof(zend_class_entry));
+               if (EXPECTED(!ZCG(current_persistent_script)->corrupted)) {
                        ce->ce_flags |= ZEND_ACC_IMMUTABLE;
-               } else {
-                       ZCG(is_immutable_class) = 0;
-                       ce = Z_PTR_P(zv) = zend_shared_memdup_arena_put(ce, sizeof(zend_class_entry));
-               }
-               ce->ce_flags |= ZEND_ACC_CACHED;
-               zend_accel_store_interned_string(ce->name);
-               if (ce->parent_name && !(ce->ce_flags & ZEND_ACC_LINKED)) {
-                       zend_accel_store_interned_string(ce->parent_name);
                }
+               ce->inheritance_cache = NULL;
+
                zend_hash_persist(&ce->function_table);
                ZEND_HASH_FOREACH_BUCKET(&ce->function_table, p) {
                        ZEND_ASSERT(p->key != NULL);
                        zend_accel_store_interned_string(p->key);
-                       zend_persist_class_method(&p->val);
+                       zend_persist_class_method(&p->val, ce);
                } ZEND_HASH_FOREACH_END();
                HT_FLAGS(&ce->function_table) &= (HASH_FLAG_UNINITIALIZED | HASH_FLAG_STATIC_KEYS);
                if (ce->default_properties_table) {
@@ -826,6 +816,15 @@ static void zend_persist_class_entry(zval *zv)
                                zend_persist_zval(&ce->default_properties_table[i]);
                        }
                }
+               if ((ce->ce_flags & ZEND_ACC_IMMUTABLE)
+                && (ce->ce_flags & ZEND_ACC_LINKED)
+                && !(ce->ce_flags & ZEND_ACC_CONSTANTS_UPDATED)) {
+                       ZEND_MAP_PTR_NEW(ce->mutable_data);
+               } else if (ce->ce_flags & ZEND_ACC_IMMUTABLE) {
+                       ZEND_MAP_PTR_INIT(ce->mutable_data, NULL);
+               } else {
+                       ce->ce_flags |= ZEND_ACC_FILE_CACHED;
+               }
                if (ce->default_static_members_table) {
                        int i;
                        ce->default_static_members_table = zend_shared_memdup_free(ce->default_static_members_table, sizeof(zval) * ce->default_static_members_count);
@@ -837,7 +836,11 @@ static void zend_persist_class_entry(zval *zv)
                                zend_persist_zval(&ce->default_static_members_table[i]);
                        }
                        if (ce->ce_flags & ZEND_ACC_IMMUTABLE) {
-                               ZEND_MAP_PTR_NEW(ce->static_members_table);
+                               if (ce->ce_flags & ZEND_ACC_LINKED) {
+                                       ZEND_MAP_PTR_NEW(ce->static_members_table);
+                               } else {
+                                       ZEND_MAP_PTR_INIT(ce->static_members_table, NULL);
+                               }
                        } else {
                                ZEND_MAP_PTR_INIT(ce->static_members_table, &ce->default_static_members_table);
                        }
@@ -853,23 +856,6 @@ static void zend_persist_class_entry(zval *zv)
                } ZEND_HASH_FOREACH_END();
                HT_FLAGS(&ce->constants_table) &= (HASH_FLAG_UNINITIALIZED | HASH_FLAG_STATIC_KEYS);
 
-               if (ce->info.user.filename) {
-                       zend_accel_store_string(ce->info.user.filename);
-               }
-               if (ce->info.user.doc_comment) {
-                       if (ZCG(accel_directives).save_comments) {
-                               zend_accel_store_interned_string(ce->info.user.doc_comment);
-                       } else {
-                               if (!zend_shared_alloc_get_xlat_entry(ce->info.user.doc_comment)) {
-                                       zend_shared_alloc_register_xlat_entry(ce->info.user.doc_comment, ce->info.user.doc_comment);
-                                       zend_string_release_ex(ce->info.user.doc_comment, 0);
-                               }
-                               ce->info.user.doc_comment = NULL;
-                       }
-               }
-               if (ce->attributes) {
-                       ce->attributes = zend_persist_attributes(ce->attributes);
-               }
                zend_hash_persist(&ce->properties_info);
                ZEND_HASH_FOREACH_BUCKET(&ce->properties_info, p) {
                        zend_property_info *prop = Z_PTR(p->val);
@@ -895,13 +881,8 @@ static void zend_persist_class_entry(zval *zv)
 
                        size_t size = sizeof(zend_property_info *) * ce->default_properties_count;
                        ZEND_ASSERT(ce->ce_flags & ZEND_ACC_LINKED);
-                       if (ZCG(is_immutable_class)) {
-                               ce->properties_info_table = zend_shared_memdup(
-                                       ce->properties_info_table, size);
-                       } else {
-                               ce->properties_info_table = zend_shared_memdup_arena(
-                                       ce->properties_info_table, size);
-                       }
+                       ce->properties_info_table = zend_shared_memdup(
+                               ce->properties_info_table, size);
 
                        for (i = 0; i < ce->default_properties_count; i++) {
                                if (ce->properties_info_table[i]) {
@@ -914,6 +895,41 @@ static void zend_persist_class_entry(zval *zv)
                        }
                }
 
+               if (ce->iterator_funcs_ptr) {
+                       ce->iterator_funcs_ptr = zend_shared_memdup(ce->iterator_funcs_ptr, sizeof(zend_class_iterator_funcs));
+               }
+
+               if (ce->ce_flags & ZEND_ACC_CACHED) {
+                       return ce;
+               }
+
+               ce->ce_flags |= ZEND_ACC_CACHED;
+
+               zend_accel_store_interned_string(ce->name);
+               if (ce->parent_name && !(ce->ce_flags & ZEND_ACC_LINKED)) {
+                       zend_accel_store_interned_string(ce->parent_name);
+               }
+
+               if (ce->info.user.filename) {
+                       zend_accel_store_string(ce->info.user.filename);
+               }
+
+               if (ce->info.user.doc_comment) {
+                       if (ZCG(accel_directives).save_comments) {
+                               zend_accel_store_interned_string(ce->info.user.doc_comment);
+                       } else {
+                               if (!zend_shared_alloc_get_xlat_entry(ce->info.user.doc_comment)) {
+                                       zend_shared_alloc_register_xlat_entry(ce->info.user.doc_comment, ce->info.user.doc_comment);
+                                       zend_string_release_ex(ce->info.user.doc_comment, 0);
+                               }
+                               ce->info.user.doc_comment = NULL;
+                       }
+               }
+
+               if (ce->attributes) {
+                       ce->attributes = zend_persist_attributes(ce->attributes);
+               }
+
                if (ce->num_interfaces && !(ce->ce_flags & ZEND_ACC_LINKED)) {
                        uint32_t i = 0;
 
@@ -973,14 +989,12 @@ static void zend_persist_class_entry(zval *zv)
                                        ce->trait_precedences, sizeof(zend_trait_precedence*) * (i + 1));
                        }
                }
-
-               if (ce->iterator_funcs_ptr) {
-                       ce->iterator_funcs_ptr = zend_shared_memdup(ce->iterator_funcs_ptr, sizeof(zend_class_iterator_funcs));
-               }
        }
+
+       return ce;
 }
 
-static void zend_update_parent_ce(zend_class_entry *ce)
+void zend_update_parent_ce(zend_class_entry *ce)
 {
        if (ce->ce_flags & ZEND_ACC_LINKED) {
                if (ce->parent) {
@@ -1145,7 +1159,7 @@ static void zend_accel_persist_class_table(HashTable *class_table)
        ZEND_HASH_FOREACH_BUCKET(class_table, p) {
                ZEND_ASSERT(p->key != NULL);
                zend_accel_store_interned_string(p->key);
-               zend_persist_class_entry(&p->val);
+               Z_CE(p->val) = zend_persist_class_entry(Z_CE(p->val));
        } ZEND_HASH_FOREACH_END();
     ZEND_HASH_FOREACH_BUCKET(class_table, p) {
                if (EXPECTED(Z_TYPE(p->val) != IS_ALIAS_PTR)) {
@@ -1198,9 +1212,6 @@ zend_persistent_script *zend_accel_script_persist(zend_persistent_script *script
        ZEND_ASSERT(((zend_uintptr_t)ZCG(mem) & 0x7) == 0); /* should be 8 byte aligned */
 #endif
 
-       script->arena_mem = ZCG(arena_mem) = ZCG(mem);
-       ZCG(mem) = (void*)((char*)ZCG(mem) + script->arena_size);
-
 #ifdef HAVE_JIT
        if (JIT_G(on) && for_shm) {
                zend_jit_unprotect();
@@ -1217,6 +1228,11 @@ zend_persistent_script *zend_accel_script_persist(zend_persistent_script *script
                zend_persist_op_array(&p->val);
        } ZEND_HASH_FOREACH_END();
        zend_persist_op_array_ex(&script->script.main_op_array, script);
+       if (!script->corrupted) {
+               ZEND_MAP_PTR_INIT(script->script.main_op_array.run_time_cache, NULL);
+       }
+       ZEND_MAP_PTR_INIT(script->script.main_op_array.static_variables_ptr,
+               &script->script.main_op_array.static_variables);
        zend_persist_warnings(script);
 
        if (for_shm) {
index d5eca3f19570a1a096cf7d643e8418be7ab34f0d..38afac39d9366394fd8b6b8d100bb103fb054999 100644 (file)
@@ -25,4 +25,8 @@
 uint32_t zend_accel_script_persist_calc(zend_persistent_script *script, const char *key, unsigned int key_length, int for_shm);
 zend_persistent_script *zend_accel_script_persist(zend_persistent_script *script, const char **key, unsigned int key_length, int for_shm);
 
+void zend_persist_class_entry_calc(zend_class_entry *ce);
+zend_class_entry *zend_persist_class_entry(zend_class_entry *ce);
+void zend_update_parent_ce(zend_class_entry *ce);
+
 #endif /* ZEND_PERSIST_H */
index 7731b9a97050b2fb45431f17a57d65067ed8fa81..5728414eec55e1a98445d6b9c6c0a1086bbc7ba6 100644 (file)
 
 #define ADD_DUP_SIZE(m,s)  ZCG(current_persistent_script)->size += zend_shared_memdup_size((void*)m, s)
 #define ADD_SIZE(m)        ZCG(current_persistent_script)->size += ZEND_ALIGNED_SIZE(m)
-#define ADD_ARENA_SIZE(m)  ZCG(current_persistent_script)->arena_size += ZEND_ALIGNED_SIZE(m)
-
-#define ADD_SIZE_EX(m) do { \
-               if (ZCG(is_immutable_class)) { \
-                       ADD_SIZE(m); \
-               } else { \
-                       ADD_ARENA_SIZE(m); \
-               } \
-       } while (0)
 
 # define ADD_STRING(str) ADD_DUP_SIZE((str), _ZSTR_STRUCT_SIZE(ZSTR_LEN(str)))
 
@@ -129,10 +120,12 @@ static void zend_persist_zval_calc(zval *z)
                        }
                        break;
                case IS_CONSTANT_AST:
-                       size = zend_shared_memdup_size(Z_AST_P(z), sizeof(zend_ast_ref));
-                       if (size) {
-                               ADD_SIZE(size);
-                               zend_persist_ast_calc(Z_ASTVAL_P(z));
+                       if (!zend_accel_in_shm(Z_AST_P(z))) {
+                               size = zend_shared_memdup_size(Z_AST_P(z), sizeof(zend_ast_ref));
+                               if (size) {
+                                       ADD_SIZE(size);
+                                       zend_persist_ast_calc(Z_ASTVAL_P(z));
+                               }
                        }
                        break;
                default:
@@ -143,7 +136,8 @@ static void zend_persist_zval_calc(zval *z)
 
 static void zend_persist_attributes_calc(HashTable *attributes)
 {
-       if (!zend_shared_alloc_get_xlat_entry(attributes)) {
+       if (!zend_shared_alloc_get_xlat_entry(attributes)
+        && !zend_accel_in_shm(attributes)) {
                zend_attribute *attr;
                uint32_t i;
 
@@ -166,14 +160,10 @@ static void zend_persist_attributes_calc(HashTable *attributes)
        }
 }
 
-static void zend_persist_type_calc(zend_type *type, bool use_arena)
+static void zend_persist_type_calc(zend_type *type)
 {
        if (ZEND_TYPE_HAS_LIST(*type)) {
-               if (ZEND_TYPE_USES_ARENA(*type) && !ZCG(is_immutable_class) && use_arena) {
-                       ADD_ARENA_SIZE(ZEND_TYPE_LIST_SIZE(ZEND_TYPE_LIST(*type)->num_types));
-               } else {
-                       ADD_SIZE(ZEND_TYPE_LIST_SIZE(ZEND_TYPE_LIST(*type)->num_types));
-               }
+               ADD_SIZE(ZEND_TYPE_LIST_SIZE(ZEND_TYPE_LIST(*type)->num_types));
        }
 
        zend_type *single_type;
@@ -198,13 +188,15 @@ static void zend_persist_op_array_calc_ex(zend_op_array *op_array)
                }
     }
 
-       if (op_array->scope && zend_shared_alloc_get_xlat_entry(op_array->opcodes)) {
-               /* already stored */
-               ADD_SIZE(ZEND_ALIGNED_SIZE(zend_extensions_op_array_persist_calc(op_array)));
-               return;
+       if (op_array->scope) {
+               if (zend_shared_alloc_get_xlat_entry(op_array->opcodes)) {
+                       /* already stored */
+                       ADD_SIZE(ZEND_ALIGNED_SIZE(zend_extensions_op_array_persist_calc(op_array)));
+                       return;
+               }
        }
 
-       if (op_array->static_variables) {
+       if (op_array->static_variables && !zend_accel_in_shm(op_array->static_variables)) {
                if (!zend_shared_alloc_get_xlat_entry(op_array->static_variables)) {
                        Bucket *p;
 
@@ -219,6 +211,12 @@ static void zend_persist_op_array_calc_ex(zend_op_array *op_array)
                }
        }
 
+       if (op_array->scope
+        && !(op_array->fn_flags & ZEND_ACC_CLOSURE)
+        && (op_array->scope->ce_flags & ZEND_ACC_CACHED)) {
+               return;
+       }
+
        if (op_array->literals) {
                zval *p = op_array->literals;
                zval *end = p + op_array->last_literal;
@@ -254,7 +252,7 @@ static void zend_persist_op_array_calc_ex(zend_op_array *op_array)
                        if (arg_info[i].name) {
                                ADD_INTERNED_STRING(arg_info[i].name);
                        }
-                       zend_persist_type_calc(&arg_info[i].type, 0);
+                       zend_persist_type_calc(&arg_info[i].type);
                }
        }
 
@@ -293,9 +291,6 @@ static void zend_persist_op_array_calc(zval *zv)
        ZEND_ASSERT(op_array->type == ZEND_USER_FUNCTION);
        ADD_SIZE(sizeof(zend_op_array));
        zend_persist_op_array_calc_ex(Z_PTR_P(zv));
-       if (ZCG(current_persistent_script)->corrupted) {
-               ADD_ARENA_SIZE(sizeof(void*));
-       }
 }
 
 static void zend_persist_class_method_calc(zval *zv)
@@ -308,21 +303,26 @@ static void zend_persist_class_method_calc(zval *zv)
                if (op_array->fn_flags & ZEND_ACC_ARENA_ALLOCATED) {
                        old_op_array = zend_shared_alloc_get_xlat_entry(op_array);
                        if (!old_op_array) {
-                               ADD_SIZE_EX(sizeof(zend_internal_function));
+                               ADD_SIZE(sizeof(zend_internal_function));
                                zend_shared_alloc_register_xlat_entry(op_array, Z_PTR_P(zv));
                        }
                }
                return;
        }
 
+       if ((op_array->fn_flags & ZEND_ACC_IMMUTABLE)
+        && !op_array->static_variables
+        && !ZCG(current_persistent_script)->corrupted
+        && zend_accel_in_shm(op_array)) {
+               zend_shared_alloc_register_xlat_entry(op_array, op_array);
+               return;
+       }
+
        old_op_array = zend_shared_alloc_get_xlat_entry(op_array);
        if (!old_op_array) {
-               ADD_SIZE_EX(sizeof(zend_op_array));
+               ADD_SIZE(sizeof(zend_op_array));
                zend_persist_op_array_calc_ex(Z_PTR_P(zv));
                zend_shared_alloc_register_xlat_entry(op_array, Z_PTR_P(zv));
-               if (!ZCG(is_immutable_class)) {
-                       ADD_ARENA_SIZE(sizeof(void*));
-               }
        } else {
                /* If op_array is shared, the function name refcount is still incremented for each use,
                 * so we need to release it here. We remembered the original function name in xlat. */
@@ -336,9 +336,9 @@ static void zend_persist_class_method_calc(zval *zv)
 
 static void zend_persist_property_info_calc(zend_property_info *prop)
 {
-       ADD_SIZE_EX(sizeof(zend_property_info));
+       ADD_SIZE(sizeof(zend_property_info));
        ADD_INTERNED_STRING(prop->name);
-       zend_persist_type_calc(&prop->type, 1);
+       zend_persist_type_calc(&prop->type);
        if (ZCG(accel_directives).save_comments && prop->doc_comment) {
                ADD_STRING(prop->doc_comment);
        }
@@ -353,7 +353,7 @@ static void zend_persist_class_constant_calc(zval *zv)
 
        if (!zend_shared_alloc_get_xlat_entry(c)) {
                zend_shared_alloc_register_xlat_entry(c, c);
-               ADD_SIZE_EX(sizeof(zend_class_constant));
+               ADD_SIZE(sizeof(zend_class_constant));
                zend_persist_zval_calc(&c->value);
                if (ZCG(accel_directives).save_comments && c->doc_comment) {
                        ADD_STRING(c->doc_comment);
@@ -364,29 +364,8 @@ static void zend_persist_class_constant_calc(zval *zv)
        }
 }
 
-static void check_property_type_resolution(zend_class_entry *ce) {
-       zend_property_info *prop;
-       if (ce->ce_flags & ZEND_ACC_PROPERTY_TYPES_RESOLVED) {
-               /* Preloading might have computed this already. */
-               return;
-       }
-
-       if (ce->ce_flags & ZEND_ACC_HAS_TYPE_HINTS) {
-               ZEND_HASH_FOREACH_PTR(&ce->properties_info, prop) {
-                       zend_type *single_type;
-                       ZEND_TYPE_FOREACH(prop->type, single_type) {
-                               if (ZEND_TYPE_HAS_NAME(*single_type)) {
-                                       return;
-                               }
-                       } ZEND_TYPE_FOREACH_END();
-               } ZEND_HASH_FOREACH_END();
-       }
-       ce->ce_flags |= ZEND_ACC_PROPERTY_TYPES_RESOLVED;
-}
-
-static void zend_persist_class_entry_calc(zval *zv)
+void zend_persist_class_entry_calc(zend_class_entry *ce)
 {
-       zend_class_entry *ce = Z_PTR_P(zv);
        Bucket *p;
 
        if (ce->type == ZEND_USER_CLASS) {
@@ -396,19 +375,8 @@ static void zend_persist_class_entry_calc(zval *zv)
                }
                zend_shared_alloc_register_xlat_entry(ce, ce);
 
-               check_property_type_resolution(ce);
-
-               ZCG(is_immutable_class) =
-                       (ce->ce_flags & ZEND_ACC_LINKED) &&
-                       (ce->ce_flags & ZEND_ACC_CONSTANTS_UPDATED) &&
-                       (ce->ce_flags & ZEND_ACC_PROPERTY_TYPES_RESOLVED) &&
-                       !ZCG(current_persistent_script)->corrupted;
+               ADD_SIZE(sizeof(zend_class_entry));
 
-               ADD_SIZE_EX(sizeof(zend_class_entry));
-               ADD_INTERNED_STRING(ce->name);
-               if (ce->parent_name && !(ce->ce_flags & ZEND_ACC_LINKED)) {
-                       ADD_INTERNED_STRING(ce->parent_name);
-               }
                zend_hash_persist_calc(&ce->function_table);
                ZEND_HASH_FOREACH_BUCKET(&ce->function_table, p) {
                        ZEND_ASSERT(p->key != NULL);
@@ -440,16 +408,6 @@ static void zend_persist_class_entry_calc(zval *zv)
                        zend_persist_class_constant_calc(&p->val);
                } ZEND_HASH_FOREACH_END();
 
-               if (ce->info.user.filename) {
-                       ADD_STRING(ce->info.user.filename);
-               }
-               if (ZCG(accel_directives).save_comments && ce->info.user.doc_comment) {
-                       ADD_STRING(ce->info.user.doc_comment);
-               }
-               if (ce->attributes) {
-                       zend_persist_attributes_calc(ce->attributes);
-               }
-
                zend_hash_persist_calc(&ce->properties_info);
                ZEND_HASH_FOREACH_BUCKET(&ce->properties_info, p) {
                        zend_property_info *prop = Z_PTR(p->val);
@@ -461,7 +419,36 @@ static void zend_persist_class_entry_calc(zval *zv)
                } ZEND_HASH_FOREACH_END();
 
                if (ce->properties_info_table) {
-                       ADD_SIZE_EX(sizeof(zend_property_info *) * ce->default_properties_count);
+                       ADD_SIZE(sizeof(zend_property_info *) * ce->default_properties_count);
+               }
+
+               if (ce->num_interfaces && (ce->ce_flags & ZEND_ACC_LINKED)) {
+                       ADD_SIZE(sizeof(zend_class_entry*) * ce->num_interfaces);
+               }
+
+               if (ce->iterator_funcs_ptr) {
+                       ADD_SIZE(sizeof(zend_class_iterator_funcs));
+               }
+
+               if (ce->ce_flags & ZEND_ACC_CACHED) {
+                       return;
+               }
+
+               ADD_INTERNED_STRING(ce->name);
+               if (ce->parent_name && !(ce->ce_flags & ZEND_ACC_LINKED)) {
+                       ADD_INTERNED_STRING(ce->parent_name);
+               }
+
+               if (ce->info.user.filename) {
+                       ADD_STRING(ce->info.user.filename);
+               }
+
+               if (ZCG(accel_directives).save_comments && ce->info.user.doc_comment) {
+                       ADD_STRING(ce->info.user.doc_comment);
+               }
+
+               if (ce->attributes) {
+                       zend_persist_attributes_calc(ce->attributes);
                }
 
                if (ce->num_interfaces) {
@@ -473,8 +460,6 @@ static void zend_persist_class_entry_calc(zval *zv)
                                        ADD_INTERNED_STRING(ce->interface_names[i].lc_name);
                                }
                                ADD_SIZE(sizeof(zend_class_name) * ce->num_interfaces);
-                       } else {
-                               ADD_SIZE(sizeof(zend_class_entry*) * ce->num_interfaces);
                        }
                }
 
@@ -523,10 +508,6 @@ static void zend_persist_class_entry_calc(zval *zv)
                                ADD_SIZE(sizeof(zend_trait_precedence*) * (i + 1));
                        }
                }
-
-               if (ce->iterator_funcs_ptr) {
-                       ADD_SIZE(sizeof(zend_class_iterator_funcs));
-               }
        }
 }
 
@@ -538,7 +519,7 @@ static void zend_accel_persist_class_table_calc(HashTable *class_table)
        ZEND_HASH_FOREACH_BUCKET(class_table, p) {
                ZEND_ASSERT(p->key != NULL);
                ADD_INTERNED_STRING(p->key);
-               zend_persist_class_entry_calc(&p->val);
+               zend_persist_class_entry_calc(Z_CE(p->val));
        } ZEND_HASH_FOREACH_END();
 }
 
@@ -557,8 +538,6 @@ uint32_t zend_accel_script_persist_calc(zend_persistent_script *new_persistent_s
 
        new_persistent_script->mem = NULL;
        new_persistent_script->size = 0;
-       new_persistent_script->arena_mem = NULL;
-       new_persistent_script->arena_size = 0;
        new_persistent_script->corrupted = 0;
        ZCG(current_persistent_script) = new_persistent_script;
 
@@ -595,12 +574,6 @@ uint32_t zend_accel_script_persist_calc(zend_persistent_script *new_persistent_s
        zend_persist_op_array_calc_ex(&new_persistent_script->script.main_op_array);
        zend_persist_warnings_calc(new_persistent_script);
 
-#if defined(__AVX__) || defined(__SSE2__)
-       /* Align size to 64-byte boundary */
-       new_persistent_script->arena_size = (new_persistent_script->arena_size + 63) & ~63;
-#endif
-
-       new_persistent_script->size += new_persistent_script->arena_size;
        new_persistent_script->corrupted = 0;
 
        ZCG(current_persistent_script) = NULL;
index 698c2884ca629fbb159ce74a576aa5b7f866b43a..a078a31c0f6e9ca5b2252ac3ca385eac520e4612 100644 (file)
@@ -375,7 +375,7 @@ int zend_shared_memdup_size(void *source, size_t size)
        return ZEND_ALIGNED_SIZE(size);
 }
 
-static zend_always_inline void *_zend_shared_memdup(void *source, size_t size, bool arena, bool get_xlat, bool set_xlat, bool free_source)
+static zend_always_inline void *_zend_shared_memdup(void *source, size_t size, bool get_xlat, bool set_xlat, bool free_source)
 {
        void *old_p, *retval;
        zend_ulong key;
@@ -388,13 +388,8 @@ static zend_always_inline void *_zend_shared_memdup(void *source, size_t size, b
                        return old_p;
                }
        }
-       if (arena) {
-               retval = ZCG(arena_mem);
-               ZCG(arena_mem) = (void*)(((char*)ZCG(arena_mem)) + ZEND_ALIGNED_SIZE(size));
-       } else {
-               retval = ZCG(mem);
-               ZCG(mem) = (void*)(((char*)ZCG(mem)) + ZEND_ALIGNED_SIZE(size));
-       }
+       retval = ZCG(mem);
+       ZCG(mem) = (void*)(((char*)ZCG(mem)) + ZEND_ALIGNED_SIZE(size));
        memcpy(retval, source, size);
        if (set_xlat) {
                if (!get_xlat) {
@@ -411,42 +406,32 @@ static zend_always_inline void *_zend_shared_memdup(void *source, size_t size, b
 
 void *zend_shared_memdup_get_put_free(void *source, size_t size)
 {
-       return _zend_shared_memdup(source, size, 0, 1, 1, 1);
+       return _zend_shared_memdup(source, size, 1, 1, 1);
 }
 
 void *zend_shared_memdup_put_free(void *source, size_t size)
 {
-       return _zend_shared_memdup(source, size, 0, 0, 1, 1);
+       return _zend_shared_memdup(source, size, 0, 1, 1);
 }
 
 void *zend_shared_memdup_free(void *source, size_t size)
 {
-       return _zend_shared_memdup(source, size, 0, 0, 0, 1);
+       return _zend_shared_memdup(source, size, 0, 0, 1);
 }
 
 void *zend_shared_memdup_get_put(void *source, size_t size)
 {
-       return _zend_shared_memdup(source, size, 0, 1, 1, 0);
+       return _zend_shared_memdup(source, size, 1, 1, 0);
 }
 
 void *zend_shared_memdup_put(void *source, size_t size)
 {
-       return _zend_shared_memdup(source, size, 0, 0, 1, 0);
+       return _zend_shared_memdup(source, size, 0, 1, 0);
 }
 
 void *zend_shared_memdup(void *source, size_t size)
 {
-       return _zend_shared_memdup(source, size, 0, 0, 0, 0);
-}
-
-void *zend_shared_memdup_arena_put(void *source, size_t size)
-{
-       return _zend_shared_memdup(source, size, 1, 0, 1, 0);
-}
-
-void *zend_shared_memdup_arena(void *source, size_t size)
-{
-       return _zend_shared_memdup(source, size, 1, 0, 0, 0);
+       return _zend_shared_memdup(source, size, 0, 0, 0);
 }
 
 void zend_shared_alloc_safe_unlock(void)
index 8d37376570a0e9cec5993760e18d72365e1ca6c5..7b67c3c454ea30c5576dfae886f7538d9a1f87c6 100644 (file)
@@ -139,8 +139,6 @@ void *zend_shared_memdup_free(void *source, size_t size);
 void *zend_shared_memdup_get_put(void *source, size_t size);
 void *zend_shared_memdup_put(void *source, size_t size);
 void *zend_shared_memdup(void *source, size_t size);
-void *zend_shared_memdup_arena_put(void *source, size_t size);
-void *zend_shared_memdup_arena(void *source, size_t size);
 
 int  zend_shared_memdup_size(void *p, size_t size);
 
index b0c1067474102db4eabc0f6098a35dea77d38d82..73c6926b0df3b80f19dd6bbe4e4c17e44dc27bef 100644 (file)
@@ -386,7 +386,7 @@ static void _class_string(smart_str *str, zend_class_entry *ce, zval *obj, char
                zend_string *key;
                zend_class_constant *c;
 
-               ZEND_HASH_FOREACH_STR_KEY_PTR(&ce->constants_table, key, c) {
+               ZEND_HASH_FOREACH_STR_KEY_PTR(CE_CONSTANTS_TABLE(ce), key, c) {
                        _class_const_string(str, ZSTR_VAL(key), c, ZSTR_VAL(sub_indent));
                        if (UNEXPECTED(EG(exception))) {
                                zend_string_release(sub_indent);
@@ -2948,8 +2948,14 @@ ZEND_METHOD(ReflectionUnionType, getTypes)
                        append_type(return_value, *list_type);
                } ZEND_TYPE_LIST_FOREACH_END();
        } else if (ZEND_TYPE_HAS_NAME(param->type)) {
-               append_type(return_value,
-                       (zend_type) ZEND_TYPE_INIT_CLASS(ZEND_TYPE_NAME(param->type), 0, 0));
+               if (ZEND_TYPE_HAS_CE_CACHE(param->type)
+                && ZEND_TYPE_CE_CACHE(param->type)) {
+                       append_type(return_value,
+                               (zend_type) ZEND_TYPE_INIT_CE(ZEND_TYPE_CE_CACHE(param->type), 0, 0));
+               } else {
+                       append_type(return_value,
+                               (zend_type) ZEND_TYPE_INIT_CLASS(ZEND_TYPE_NAME(param->type), 0, 0));
+               }
        } else if (ZEND_TYPE_HAS_CE(param->type)) {
                append_type(return_value,
                        (zend_type) ZEND_TYPE_INIT_CE(ZEND_TYPE_CE(param->type), 0, 0));
@@ -3548,7 +3554,7 @@ ZEND_METHOD(ReflectionClassConstant, __construct)
        object = ZEND_THIS;
        intern = Z_REFLECTION_P(object);
 
-       if ((constant = zend_hash_find_ptr(&ce->constants_table, constname)) == NULL) {
+       if ((constant = zend_hash_find_ptr(CE_CONSTANTS_TABLE(ce), constname)) == NULL) {
                zend_throw_exception_ex(reflection_exception_ptr, 0, "Constant %s::%s does not exist", ZSTR_VAL(ce->name), ZSTR_VAL(constname));
                RETURN_THROWS();
        }
@@ -4444,7 +4450,7 @@ ZEND_METHOD(ReflectionClass, getConstants)
        GET_REFLECTION_OBJECT_PTR(ce);
 
        array_init(return_value);
-       ZEND_HASH_FOREACH_STR_KEY_PTR(&ce->constants_table, key, constant) {
+       ZEND_HASH_FOREACH_STR_KEY_PTR(CE_CONSTANTS_TABLE(ce), key, constant) {
                if (UNEXPECTED(zval_update_constant_ex(&constant->value, ce) != SUCCESS)) {
                        RETURN_THROWS();
                }
@@ -4478,7 +4484,7 @@ ZEND_METHOD(ReflectionClass, getReflectionConstants)
        GET_REFLECTION_OBJECT_PTR(ce);
 
        array_init(return_value);
-       ZEND_HASH_FOREACH_STR_KEY_PTR(&ce->constants_table, name, constant) {
+       ZEND_HASH_FOREACH_STR_KEY_PTR(CE_CONSTANTS_TABLE(ce), name, constant) {
                if (Z_ACCESS_FLAGS(constant->value) & filter) {
                        zval class_const;
                        reflection_class_constant_factory(name, constant, &class_const);
@@ -4493,6 +4499,7 @@ ZEND_METHOD(ReflectionClass, getConstant)
 {
        reflection_object *intern;
        zend_class_entry *ce;
+       HashTable *constants_table;
        zend_class_constant *c;
        zend_string *name;
 
@@ -4501,12 +4508,13 @@ ZEND_METHOD(ReflectionClass, getConstant)
        }
 
        GET_REFLECTION_OBJECT_PTR(ce);
-       ZEND_HASH_FOREACH_PTR(&ce->constants_table, c) {
+       constants_table = CE_CONSTANTS_TABLE(ce);
+       ZEND_HASH_FOREACH_PTR(constants_table, c) {
                if (UNEXPECTED(zval_update_constant_ex(&c->value, ce) != SUCCESS)) {
                        RETURN_THROWS();
                }
        } ZEND_HASH_FOREACH_END();
-       if ((c = zend_hash_find_ptr(&ce->constants_table, name)) == NULL) {
+       if ((c = zend_hash_find_ptr(constants_table, name)) == NULL) {
                RETURN_FALSE;
        }
        ZVAL_COPY_OR_DUP(return_value, &c->value);
@@ -4526,7 +4534,7 @@ ZEND_METHOD(ReflectionClass, getReflectionConstant)
                RETURN_THROWS();
        }
 
-       if ((constant = zend_hash_find_ptr(&ce->constants_table, name)) == NULL) {
+       if ((constant = zend_hash_find_ptr(CE_CONSTANTS_TABLE(ce), name)) == NULL) {
                RETURN_FALSE;
        }
        reflection_class_constant_factory(name, constant, return_value);
index b5115663b83a9e176a95b4e5342148772125fc31..ac7170c88aacd667ddb36287431a574e9ff73f84 100644 (file)
@@ -1826,6 +1826,7 @@ void php_request_shutdown(void *dummy)
        } zend_end_try();
 
        /* 15. Free Willy (here be crashes) */
+       zend_arena_destroy(CG(arena));
        zend_interned_strings_deactivate();
        zend_try {
                shutdown_memory_manager(CG(unclean_shutdown) || !report_memleaks, 0);