]> granicus.if.org Git - php/commitdiff
Use ZEND_HASH_FOREACH with direct callback, instead of callbacks
authorDmitry Stogov <dmitry@zend.com>
Tue, 30 Apr 2019 11:50:01 +0000 (14:50 +0300)
committerDmitry Stogov <dmitry@zend.com>
Tue, 30 Apr 2019 11:50:01 +0000 (14:50 +0300)
ext/opcache/zend_persist.c
ext/opcache/zend_persist_calc.c

index ed0587299369083dfc7af4a23ee2403288f88941..f32644f4c60b21f8639938e5fe2f619a45960d4d 100644 (file)
@@ -79,7 +79,7 @@ static void zend_persist_zval(zval *z);
 static const uint32_t uninitialized_bucket[-HT_MIN_MASK] =
        {HT_INVALID_IDX, HT_INVALID_IDX};
 
-static void zend_hash_persist(HashTable *ht, zend_persist_func_t pPersistElement)
+static void zend_hash_persist(HashTable *ht)
 {
        uint32_t idx, nIndex;
        Bucket *p;
@@ -111,19 +111,15 @@ static void zend_hash_persist(HashTable *ht, zend_persist_func_t pPersistElement
                void *data = HT_GET_DATA_ADDR(ht);
                data = zend_shared_memdup_free(data, HT_USED_SIZE(ht));
                HT_SET_DATA_ADDR(ht, data);
-       } else if (ht->nNumUsed < (uint32_t)(-(int32_t)ht->nTableMask) / 4) {
+       } else if (ht->nNumUsed > HT_MIN_SIZE && ht->nNumUsed < (uint32_t)(-(int32_t)ht->nTableMask) / 4) {
                /* compact table */
                void *old_data = HT_GET_DATA_ADDR(ht);
                Bucket *old_buckets = ht->arData;
                uint32_t hash_size;
 
-               if (ht->nNumUsed <= HT_MIN_SIZE) {
-                       hash_size = HT_MIN_SIZE * 2;
-               } else {
-                       hash_size = (uint32_t)(-(int32_t)ht->nTableMask);
-                       while (hash_size >> 2 > ht->nNumUsed) {
-                               hash_size >>= 1;
-                       }
+               hash_size = (uint32_t)(-(int32_t)ht->nTableMask);
+               while (hash_size >> 2 > ht->nNumUsed) {
+                       hash_size >>= 1;
                }
                ht->nTableMask = (uint32_t)(-(int32_t)hash_size);
                ZEND_ASSERT(((zend_uintptr_t)ZCG(mem) & 0x7) == 0); /* should be 8 byte aligned */
@@ -133,23 +129,14 @@ static void zend_hash_persist(HashTable *ht, zend_persist_func_t pPersistElement
                memcpy(ht->arData, old_buckets, ht->nNumUsed * sizeof(Bucket));
                efree(old_data);
 
+               /* rehash */
                for (idx = 0; idx < ht->nNumUsed; idx++) {
                        p = ht->arData + idx;
                        if (Z_TYPE(p->val) == IS_UNDEF) continue;
-
-                       /* persist bucket and key */
-                       if (p->key) {
-                               zend_accel_store_interned_string(p->key);
-                       }
-
-                       /* persist the data itself */
-                       pPersistElement(&p->val);
-
                        nIndex = p->h | ht->nTableMask;
                        Z_NEXT(p->val) = HT_HASH(ht, nIndex);
                        HT_HASH(ht, nIndex) = HT_IDX_TO_HASH(idx);
                }
-               return;
        } else {
                void *data = ZCG(mem);
                void *old_data = HT_GET_DATA_ADDR(ht);
@@ -160,107 +147,6 @@ static void zend_hash_persist(HashTable *ht, zend_persist_func_t pPersistElement
                efree(old_data);
                HT_SET_DATA_ADDR(ht, data);
        }
-
-       for (idx = 0; idx < ht->nNumUsed; idx++) {
-               p = ht->arData + idx;
-               if (Z_TYPE(p->val) == IS_UNDEF) continue;
-
-               /* persist bucket and key */
-               if (p->key) {
-                       zend_accel_store_interned_string(p->key);
-               }
-
-               /* persist the data itself */
-               pPersistElement(&p->val);
-       }
-}
-
-static void zend_hash_persist_immutable(HashTable *ht)
-{
-       uint32_t idx, nIndex;
-       Bucket *p;
-
-       HT_FLAGS(ht) |= HASH_FLAG_STATIC_KEYS;
-       ht->pDestructor = NULL;
-
-       if (HT_FLAGS(ht) & HASH_FLAG_UNINITIALIZED) {
-               if (EXPECTED(!ZCG(current_persistent_script)->corrupted)) {
-                       HT_SET_DATA_ADDR(ht, &ZCSG(uninitialized_bucket));
-               } else {
-                       HT_SET_DATA_ADDR(ht, &uninitialized_bucket);
-               }
-               return;
-       }
-       if (ht->nNumUsed == 0) {
-               efree(HT_GET_DATA_ADDR(ht));
-               ht->nTableMask = HT_MIN_MASK;
-               if (EXPECTED(!ZCG(current_persistent_script)->corrupted)) {
-                       HT_SET_DATA_ADDR(ht, &ZCSG(uninitialized_bucket));
-               } else {
-                       HT_SET_DATA_ADDR(ht, &uninitialized_bucket);
-               }
-               HT_FLAGS(ht) |= HASH_FLAG_UNINITIALIZED;
-               return;
-       }
-       if (HT_FLAGS(ht) & HASH_FLAG_PACKED) {
-               HT_SET_DATA_ADDR(ht, zend_shared_memdup(HT_GET_DATA_ADDR(ht), HT_USED_SIZE(ht)));
-       } else if (ht->nNumUsed < (uint32_t)(-(int32_t)ht->nTableMask) / 4) {
-               /* compact table */
-               Bucket *old_buckets = ht->arData;
-               uint32_t hash_size;
-
-               if (ht->nNumUsed <= HT_MIN_SIZE) {
-                       hash_size = HT_MIN_SIZE * 2;
-               } else {
-                       hash_size = (uint32_t)(-(int32_t)ht->nTableMask);
-                       while (hash_size >> 2 > ht->nNumUsed) {
-                               hash_size >>= 1;
-                       }
-               }
-               ht->nTableMask = (uint32_t)(-(int32_t)hash_size);
-               ZEND_ASSERT(((zend_uintptr_t)ZCG(mem) & 0x7) == 0); /* should be 8 byte aligned */
-               HT_SET_DATA_ADDR(ht, ZCG(mem));
-               ZCG(mem) = (void*)((char*)ZCG(mem) + (hash_size * sizeof(uint32_t)) + (ht->nNumUsed * sizeof(Bucket)));
-               HT_HASH_RESET(ht);
-               memcpy(ht->arData, old_buckets, ht->nNumUsed * sizeof(Bucket));
-
-               for (idx = 0; idx < ht->nNumUsed; idx++) {
-                       p = ht->arData + idx;
-                       if (Z_TYPE(p->val) == IS_UNDEF) continue;
-
-                       /* persist bucket and key */
-                       if (p->key) {
-                               zend_accel_memdup_interned_string(p->key);
-                       }
-
-                       /* persist the data itself */
-                       zend_persist_zval(&p->val);
-
-                       nIndex = p->h | ht->nTableMask;
-                       Z_NEXT(p->val) = HT_HASH(ht, nIndex);
-                       HT_HASH(ht, nIndex) = HT_IDX_TO_HASH(idx);
-               }
-               return;
-       } else {
-               void *data = ZCG(mem);
-
-               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, HT_GET_DATA_ADDR(ht), HT_USED_SIZE(ht));
-               HT_SET_DATA_ADDR(ht, data);
-       }
-       for (idx = 0; idx < ht->nNumUsed; idx++) {
-               p = ht->arData + idx;
-               if (Z_TYPE(p->val) == IS_UNDEF) continue;
-
-               /* persist bucket and key */
-               if (p->key) {
-                       zend_accel_memdup_interned_string(p->key);
-               }
-
-               /* persist the data itself */
-               zend_persist_zval(&p->val);
-       }
 }
 
 static zend_ast *zend_persist_ast(zend_ast *ast)
@@ -310,13 +196,27 @@ static void zend_persist_zval(zval *z)
                                Z_ARR_P(z) = new_ptr;
                                Z_TYPE_FLAGS_P(z) = 0;
                        } else {
+                               Bucket *p;
+
                                if (!Z_REFCOUNTED_P(z)) {
                                        Z_ARR_P(z) = zend_shared_memdup_put(Z_ARR_P(z), sizeof(zend_array));
-                                       zend_hash_persist_immutable(Z_ARRVAL_P(z));
+                                       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_persist_zval);
+                                       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);
@@ -374,21 +274,6 @@ static void zend_persist_op_array_ex(zend_op_array *op_array, zend_persistent_sc
                EG(current_execute_data) = orig_execute_data;
        }
 
-       if (op_array->static_variables) {
-               HashTable *stored = zend_shared_alloc_get_xlat_entry(op_array->static_variables);
-
-               if (stored) {
-                       op_array->static_variables = stored;
-               } else {
-                       zend_hash_persist(op_array->static_variables, zend_persist_zval);
-                       op_array->static_variables = zend_shared_memdup_put_free(op_array->static_variables, sizeof(HashTable));
-                       /* make immutable array */
-                       GC_SET_REFCOUNT(op_array->static_variables, 2);
-                       GC_TYPE_INFO(op_array->static_variables) = IS_ARRAY | (IS_ARRAY_IMMUTABLE << GC_FLAGS_SHIFT);
-               }
-       }
-       ZEND_MAP_PTR_INIT(op_array->static_variables_ptr, &op_array->static_variables);
-
        if (op_array->scope) {
                zend_class_entry *scope = zend_shared_alloc_get_xlat_entry(op_array->scope);
 
@@ -402,61 +287,82 @@ static void zend_persist_op_array_ex(zend_op_array *op_array, zend_persistent_sc
                                op_array->prototype = ptr;
                        }
                }
-       } else {
-               /* "prototype" may be undefined if "scope" isn't set */
-               op_array->prototype = NULL;
-       }
 
-       persist_ptr = zend_shared_alloc_get_xlat_entry(op_array->opcodes);
-       if (persist_ptr) {
-               op_array->opcodes = persist_ptr;
-               if (op_array->literals) {
-                       op_array->literals = zend_shared_alloc_get_xlat_entry(op_array->literals);
-                       ZEND_ASSERT(op_array->literals != NULL);
-               }
-               if (op_array->function_name && !IS_ACCEL_INTERNED(op_array->function_name)) {
-                       op_array->function_name = zend_shared_alloc_get_xlat_entry(op_array->function_name);
-                       ZEND_ASSERT(op_array->function_name != NULL);
-               }
-               if (op_array->filename) {
-                       op_array->filename = zend_shared_alloc_get_xlat_entry(op_array->filename);
-                       ZEND_ASSERT(op_array->filename != NULL);
-               }
-               if (op_array->arg_info) {
-                       zend_arg_info *arg_info = op_array->arg_info;
-                       if (op_array->fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
-                               arg_info--;
+               persist_ptr = zend_shared_alloc_get_xlat_entry(op_array->opcodes);
+               if (persist_ptr) {
+                       op_array->opcodes = persist_ptr;
+                       if (op_array->static_variables) {
+                               op_array->static_variables = zend_shared_alloc_get_xlat_entry(op_array->static_variables);
+                               ZEND_ASSERT(op_array->static_variables != NULL);
                        }
-                       arg_info = zend_shared_alloc_get_xlat_entry(arg_info);
-                       ZEND_ASSERT(arg_info != NULL);
-                       if (op_array->fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
-                               arg_info++;
+                       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);
                        }
-                       op_array->arg_info = arg_info;
-               }
-               if (op_array->live_range) {
-                       op_array->live_range = zend_shared_alloc_get_xlat_entry(op_array->live_range);
-                       ZEND_ASSERT(op_array->live_range != NULL);
-               }
-               if (op_array->doc_comment) {
-                       if (ZCG(accel_directives).save_comments) {
-                               op_array->doc_comment = zend_shared_alloc_get_xlat_entry(op_array->doc_comment);
-                               ZEND_ASSERT(op_array->doc_comment != NULL);
-                       } else {
-                               op_array->doc_comment = NULL;
+                       if (op_array->function_name && !IS_ACCEL_INTERNED(op_array->function_name)) {
+                               op_array->function_name = zend_shared_alloc_get_xlat_entry(op_array->function_name);
+                               ZEND_ASSERT(op_array->function_name != NULL);
                        }
+                       if (op_array->filename) {
+                               op_array->filename = zend_shared_alloc_get_xlat_entry(op_array->filename);
+                               ZEND_ASSERT(op_array->filename != NULL);
+                       }
+                       if (op_array->arg_info) {
+                               zend_arg_info *arg_info = op_array->arg_info;
+                               if (op_array->fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
+                                       arg_info--;
+                               }
+                               arg_info = zend_shared_alloc_get_xlat_entry(arg_info);
+                               ZEND_ASSERT(arg_info != NULL);
+                               if (op_array->fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
+                                       arg_info++;
+                               }
+                               op_array->arg_info = arg_info;
+                       }
+                       if (op_array->live_range) {
+                               op_array->live_range = zend_shared_alloc_get_xlat_entry(op_array->live_range);
+                               ZEND_ASSERT(op_array->live_range != NULL);
+                       }
+                       if (op_array->doc_comment) {
+                               if (ZCG(accel_directives).save_comments) {
+                                       op_array->doc_comment = zend_shared_alloc_get_xlat_entry(op_array->doc_comment);
+                                       ZEND_ASSERT(op_array->doc_comment != NULL);
+                               } else {
+                                       op_array->doc_comment = NULL;
+                               }
+                       }
+                       if (op_array->try_catch_array) {
+                               op_array->try_catch_array = zend_shared_alloc_get_xlat_entry(op_array->try_catch_array);
+                               ZEND_ASSERT(op_array->try_catch_array != NULL);
+                       }
+                       if (op_array->vars) {
+                               op_array->vars = zend_shared_alloc_get_xlat_entry(op_array->vars);
+                               ZEND_ASSERT(op_array->vars != NULL);
+                       }
+                       ZCG(mem) = (void*)((char*)ZCG(mem) + ZEND_ALIGNED_SIZE(zend_extensions_op_array_persist(op_array, ZCG(mem))));
+                       return;
                }
-               if (op_array->try_catch_array) {
-                       op_array->try_catch_array = zend_shared_alloc_get_xlat_entry(op_array->try_catch_array);
-                       ZEND_ASSERT(op_array->try_catch_array != NULL);
-               }
-               if (op_array->vars) {
-                       op_array->vars = zend_shared_alloc_get_xlat_entry(op_array->vars);
-                       ZEND_ASSERT(op_array->vars != NULL);
-               }
-               ZCG(mem) = (void*)((char*)ZCG(mem) + ZEND_ALIGNED_SIZE(zend_extensions_op_array_persist(op_array, ZCG(mem))));
-               return;
+       } else {
+               /* "prototype" may be undefined if "scope" isn't set */
+               op_array->prototype = NULL;
+       }
+
+       if (op_array->static_variables) {
+               Bucket *p;
+
+               zend_hash_persist(op_array->static_variables);
+               ZEND_HASH_FOREACH_BUCKET(op_array->static_variables, p) {
+                       ZEND_ASSERT(p->key != NULL);
+                       zend_accel_store_interned_string(p->key);
+                       zend_persist_zval(&p->val);
+               } ZEND_HASH_FOREACH_END();
+               op_array->static_variables = zend_shared_memdup_put_free(op_array->static_variables, sizeof(HashTable));
+               /* make immutable array */
+               GC_SET_REFCOUNT(op_array->static_variables, 2);
+               GC_TYPE_INFO(op_array->static_variables) = IS_ARRAY | (IS_ARRAY_IMMUTABLE << GC_FLAGS_SHIFT);
        }
+       ZEND_MAP_PTR_INIT(op_array->static_variables_ptr, &op_array->static_variables);
 
        if (op_array->literals) {
                zval *p, *end;
@@ -788,6 +694,7 @@ static void zend_persist_class_constant(zval *zv)
 
 static void zend_persist_class_entry(zval *zv)
 {
+       Bucket *p;
        zend_class_entry *ce = Z_PTR_P(zv);
 
        if (ce->type == ZEND_USER_CLASS) {
@@ -806,7 +713,12 @@ static void zend_persist_class_entry(zval *zv)
                if (ce->parent_name && !(ce->ce_flags & ZEND_ACC_LINKED)) {
                        zend_accel_store_interned_string(ce->parent_name);
                }
-               zend_hash_persist(&ce->function_table, zend_persist_class_method);
+               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_HASH_FOREACH_END();
                HT_FLAGS(&ce->function_table) &= (HASH_FLAG_UNINITIALIZED | HASH_FLAG_STATIC_KEYS);
                if (ce->default_properties_table) {
                    int i;
@@ -835,7 +747,12 @@ static void zend_persist_class_entry(zval *zv)
                        ZEND_MAP_PTR_INIT(ce->static_members_table, &ce->default_static_members_table);
                }
 
-               zend_hash_persist(&ce->constants_table, zend_persist_class_constant);
+               zend_hash_persist(&ce->constants_table);
+               ZEND_HASH_FOREACH_BUCKET(&ce->constants_table, p) {
+                       ZEND_ASSERT(p->key != NULL);
+                       zend_accel_store_interned_string(p->key);
+                       zend_persist_class_constant(&p->val);
+               } ZEND_HASH_FOREACH_END();
                HT_FLAGS(&ce->constants_table) &= (HASH_FLAG_UNINITIALIZED | HASH_FLAG_STATIC_KEYS);
 
                if (ce->info.user.filename) {
@@ -853,7 +770,12 @@ static void zend_persist_class_entry(zval *zv)
                                ce->info.user.doc_comment = NULL;
                        }
                }
-               zend_hash_persist(&ce->properties_info, zend_persist_property_info);
+               zend_hash_persist(&ce->properties_info);
+               ZEND_HASH_FOREACH_BUCKET(&ce->properties_info, p) {
+                       ZEND_ASSERT(p->key != NULL);
+                       zend_accel_store_interned_string(p->key);
+                       zend_persist_property_info(&p->val);
+               } ZEND_HASH_FOREACH_END();
                HT_FLAGS(&ce->properties_info) &= (HASH_FLAG_UNINITIALIZED | HASH_FLAG_STATIC_KEYS);
 
                if (ce->properties_info_table) {
@@ -1097,9 +1019,15 @@ static void zend_update_parent_ce(zend_class_entry *ce)
 
 static void zend_accel_persist_class_table(HashTable *class_table)
 {
+       Bucket *p;
        zend_class_entry *ce;
 
-    zend_hash_persist(class_table, zend_persist_class_entry);
+    zend_hash_persist(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);
+       } ZEND_HASH_FOREACH_END();
     ZEND_HASH_FOREACH_PTR(class_table, ce) {
                zend_update_parent_ce(ce);
        } ZEND_HASH_FOREACH_END();
@@ -1107,6 +1035,8 @@ static void zend_accel_persist_class_table(HashTable *class_table)
 
 zend_persistent_script *zend_accel_script_persist(zend_persistent_script *script, const char **key, unsigned int key_length, int for_shm)
 {
+       Bucket *p;
+
        script->mem = ZCG(mem);
 
        ZEND_ASSERT(((zend_uintptr_t)ZCG(mem) & 0x7) == 0); /* should be 8 byte aligned */
@@ -1139,7 +1069,12 @@ zend_persistent_script *zend_accel_script_persist(zend_persistent_script *script
        zend_map_ptr_extend(ZCSG(map_ptr_last));
 
        zend_accel_persist_class_table(&script->script.class_table);
-       zend_hash_persist(&script->script.function_table, zend_persist_op_array);
+       zend_hash_persist(&script->script.function_table);
+       ZEND_HASH_FOREACH_BUCKET(&script->script.function_table, p) {
+               ZEND_ASSERT(p->key != NULL);
+               zend_accel_store_interned_string(p->key);
+               zend_persist_op_array(&p->val);
+       } ZEND_HASH_FOREACH_END();
        zend_persist_op_array_ex(&script->script.main_op_array, script);
 
        ZCSG(map_ptr_last) = CG(map_ptr_last);
index 774f42185f1379667a8a2c0ef62fc3c4585b4575..ca96da7ffa8ee99bcabbfe79a8a6dfa831b8166d 100644 (file)
 
 static void zend_persist_zval_calc(zval *z);
 
-static void zend_hash_persist_calc(HashTable *ht, void (*pPersistElement)(zval *pElement))
+static void zend_hash_persist_calc(HashTable *ht)
 {
-       uint32_t idx;
-       Bucket *p;
-
        if ((HT_FLAGS(ht) & HASH_FLAG_UNINITIALIZED) || ht->nNumUsed == 0) {
                return;
        }
 
-       if (!(HT_FLAGS(ht) & HASH_FLAG_PACKED) && ht->nNumUsed < (uint32_t)(-(int32_t)ht->nTableMask) / 4) {
+       if (!(HT_FLAGS(ht) & HASH_FLAG_PACKED) && ht->nNumUsed > HT_MIN_SIZE && ht->nNumUsed < (uint32_t)(-(int32_t)ht->nTableMask) / 4) {
                /* compact table */
                uint32_t hash_size;
 
-               if (ht->nNumUsed <= HT_MIN_SIZE) {
-                       hash_size = HT_MIN_SIZE * 2;
-               } else {
-                       hash_size = (uint32_t)(-(int32_t)ht->nTableMask);
-                       while (hash_size >> 2 > ht->nNumUsed) {
-                               hash_size >>= 1;
-                       }
+               hash_size = (uint32_t)(-(int32_t)ht->nTableMask);
+               while (hash_size >> 2 > ht->nNumUsed) {
+                       hash_size >>= 1;
                }
                ADD_SIZE(hash_size * sizeof(uint32_t) + ht->nNumUsed * sizeof(Bucket));
        } else {
                ADD_SIZE(HT_USED_SIZE(ht));
        }
-
-       for (idx = 0; idx < ht->nNumUsed; idx++) {
-               p = ht->arData + idx;
-               if (Z_TYPE(p->val) == IS_UNDEF) continue;
-
-               /* persist bucket and key */
-               if (p->key) {
-                       ADD_INTERNED_STRING(p->key);
-               }
-
-               pPersistElement(&p->val);
-       }
 }
 
 static void zend_persist_ast_calc(zend_ast *ast)
@@ -134,8 +115,16 @@ static void zend_persist_zval_calc(zval *z)
                case IS_ARRAY:
                        size = zend_shared_memdup_size(Z_ARR_P(z), sizeof(zend_array));
                        if (size) {
+                               Bucket *p;
+
                                ADD_SIZE(size);
-                               zend_hash_persist_calc(Z_ARRVAL_P(z), zend_persist_zval_calc);
+                               zend_hash_persist_calc(Z_ARRVAL_P(z));
+                               ZEND_HASH_FOREACH_BUCKET(Z_ARRVAL_P(z), p) {
+                                       if (p->key) {
+                                               ADD_INTERNED_STRING(p->key);
+                                       }
+                                       zend_persist_zval_calc(&p->val);
+                               } ZEND_HASH_FOREACH_END();
                        }
                        break;
                case IS_REFERENCE:
@@ -157,15 +146,7 @@ static void zend_persist_zval_calc(zval *z)
 
 static void zend_persist_op_array_calc_ex(zend_op_array *op_array)
 {
-       if (op_array->static_variables) {
-               if (!zend_shared_alloc_get_xlat_entry(op_array->static_variables)) {
-                       zend_shared_alloc_register_xlat_entry(op_array->static_variables, op_array->static_variables);
-                       ADD_SIZE(sizeof(HashTable));
-                       zend_hash_persist_calc(op_array->static_variables, zend_persist_zval_calc);
-               }
-       }
-
-       if (zend_shared_alloc_get_xlat_entry(op_array->opcodes)) {
+       if (op_array->scope && zend_shared_alloc_get_xlat_entry(op_array->opcodes)) {
                /* already stored */
                if (op_array->function_name) {
                        zend_string *new_name = zend_shared_alloc_get_xlat_entry(op_array->function_name);
@@ -177,6 +158,21 @@ static void zend_persist_op_array_calc_ex(zend_op_array *op_array)
                return;
        }
 
+       if (op_array->static_variables) {
+               if (!zend_shared_alloc_get_xlat_entry(op_array->static_variables)) {
+                       Bucket *p;
+
+                       zend_shared_alloc_register_xlat_entry(op_array->static_variables, op_array->static_variables);
+                       ADD_SIZE(sizeof(HashTable));
+                       zend_hash_persist_calc(op_array->static_variables);
+                       ZEND_HASH_FOREACH_BUCKET(op_array->static_variables, p) {
+                               ZEND_ASSERT(p->key != NULL);
+                               ADD_INTERNED_STRING(p->key);
+                               zend_persist_zval_calc(&p->val);
+                       } ZEND_HASH_FOREACH_END();
+               }
+       }
+
        if (op_array->literals) {
                zval *p = op_array->literals;
                zval *end = p + op_array->last_literal;
@@ -351,6 +347,7 @@ static void check_property_type_resolution(zend_class_entry *ce) {
 static void zend_persist_class_entry_calc(zval *zv)
 {
        zend_class_entry *ce = Z_PTR_P(zv);
+       Bucket *p;
 
        if (ce->type == ZEND_USER_CLASS) {
                check_property_type_resolution(ce);
@@ -366,7 +363,12 @@ static void zend_persist_class_entry_calc(zval *zv)
                if (ce->parent_name && !(ce->ce_flags & ZEND_ACC_LINKED)) {
                        ADD_INTERNED_STRING(ce->parent_name);
                }
-               zend_hash_persist_calc(&ce->function_table, zend_persist_class_method_calc);
+               zend_hash_persist_calc(&ce->function_table);
+               ZEND_HASH_FOREACH_BUCKET(&ce->function_table, p) {
+                       ZEND_ASSERT(p->key != NULL);
+                       ADD_INTERNED_STRING(p->key);
+                       zend_persist_class_method_calc(&p->val);
+               } ZEND_HASH_FOREACH_END();
                if (ce->default_properties_table) {
                    int i;
 
@@ -385,7 +387,12 @@ static void zend_persist_class_entry_calc(zval *zv)
                                }
                        }
                }
-               zend_hash_persist_calc(&ce->constants_table, zend_persist_class_constant_calc);
+               zend_hash_persist_calc(&ce->constants_table);
+               ZEND_HASH_FOREACH_BUCKET(&ce->constants_table, p) {
+                       ZEND_ASSERT(p->key != NULL);
+                       ADD_INTERNED_STRING(p->key);
+                       zend_persist_class_constant_calc(&p->val);
+               } ZEND_HASH_FOREACH_END();
 
                if (ce->info.user.filename) {
                        ADD_STRING(ce->info.user.filename);
@@ -394,7 +401,12 @@ static void zend_persist_class_entry_calc(zval *zv)
                        ADD_STRING(ce->info.user.doc_comment);
                }
 
-               zend_hash_persist_calc(&ce->properties_info, zend_persist_property_info_calc);
+               zend_hash_persist_calc(&ce->properties_info);
+               ZEND_HASH_FOREACH_BUCKET(&ce->properties_info, p) {
+                       ZEND_ASSERT(p->key != NULL);
+                       ADD_INTERNED_STRING(p->key);
+                       zend_persist_property_info_calc(&p->val);
+               } ZEND_HASH_FOREACH_END();
 
                if (ce->properties_info_table) {
                        ADD_SIZE_EX(sizeof(zend_property_info *) * ce->default_properties_count);
@@ -468,11 +480,20 @@ static void zend_persist_class_entry_calc(zval *zv)
 
 static void zend_accel_persist_class_table_calc(HashTable *class_table)
 {
-       zend_hash_persist_calc(class_table, zend_persist_class_entry_calc);
+       Bucket *p;
+
+       zend_hash_persist_calc(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_HASH_FOREACH_END();
 }
 
 uint32_t zend_accel_script_persist_calc(zend_persistent_script *new_persistent_script, const char *key, unsigned int key_length, int for_shm)
 {
+       Bucket *p;
+
        new_persistent_script->mem = NULL;
        new_persistent_script->size = 0;
        new_persistent_script->arena_mem = NULL;
@@ -504,7 +525,12 @@ uint32_t zend_accel_script_persist_calc(zend_persistent_script *new_persistent_s
        if (new_persistent_script->script.function_table.nNumUsed != new_persistent_script->script.function_table.nNumOfElements) {
                zend_hash_rehash(&new_persistent_script->script.function_table);
        }
-       zend_hash_persist_calc(&new_persistent_script->script.function_table, zend_persist_op_array_calc);
+       zend_hash_persist_calc(&new_persistent_script->script.function_table);
+       ZEND_HASH_FOREACH_BUCKET(&new_persistent_script->script.function_table, p) {
+               ZEND_ASSERT(p->key != NULL);
+               ADD_INTERNED_STRING(p->key);
+               zend_persist_op_array_calc(&p->val);
+       } ZEND_HASH_FOREACH_END();
        zend_persist_op_array_calc_ex(&new_persistent_script->script.main_op_array);
 
 #if defined(__AVX__) || defined(__SSE2__)