Coverage Report

Created: 2026-06-02 06:40

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/php-src/ext/opcache/zend_persist.c
Line
Count
Source
1
/*
2
   +----------------------------------------------------------------------+
3
   | Zend OPcache                                                         |
4
   +----------------------------------------------------------------------+
5
   | Copyright © The PHP Group and Contributors.                          |
6
   +----------------------------------------------------------------------+
7
   | This source file is subject to the Modified BSD License that is      |
8
   | bundled with this package in the file LICENSE, and is available      |
9
   | through the World Wide Web at <https://www.php.net/license/>.        |
10
   |                                                                      |
11
   | SPDX-License-Identifier: BSD-3-Clause                                |
12
   +----------------------------------------------------------------------+
13
   | Authors: Andi Gutmans <andi@php.net>                                 |
14
   |          Zeev Suraski <zeev@php.net>                                 |
15
   |          Stanislav Malyshev <stas@zend.com>                          |
16
   |          Dmitry Stogov <dmitry@php.net>                              |
17
   +----------------------------------------------------------------------+
18
*/
19
20
#include "zend.h"
21
#include "ZendAccelerator.h"
22
#include "zend_persist.h"
23
#include "zend_extensions.h"
24
#include "zend_shared_alloc.h"
25
#include "zend_vm.h"
26
#include "zend_constants.h"
27
#include "zend_operators.h"
28
#include "zend_interfaces.h"
29
#include "zend_attributes.h"
30
31
#ifdef HAVE_JIT
32
# include "Optimizer/zend_func_info.h"
33
# include "jit/zend_jit.h"
34
#endif
35
36
96.1k
#define zend_set_str_gc_flags(str) do { \
37
96.1k
  GC_SET_REFCOUNT(str, 2); \
38
96.1k
  uint32_t flags = GC_STRING | (ZSTR_IS_VALID_UTF8(str) ? IS_STR_VALID_UTF8 : 0); \
39
96.1k
  if (file_cache_only \
40
96.1k
   || (ZCG(current_persistent_script) && ZCG(current_persistent_script)->corrupted)) { \
41
0
    GC_TYPE_INFO(str) = GC_STRING | (IS_STR_INTERNED << GC_FLAGS_SHIFT); \
42
0
    flags |= (IS_STR_INTERNED << GC_FLAGS_SHIFT); \
43
96.1k
  } else { \
44
96.1k
    flags |= ((IS_STR_INTERNED | IS_STR_PERMANENT) << GC_FLAGS_SHIFT); \
45
96.1k
  } \
46
96.1k
  GC_TYPE_INFO(str) = flags; \
47
96.1k
} while (0)
48
49
169k
#define zend_accel_store_string(str) do { \
50
169k
    zend_string *new_str = zend_shared_alloc_get_xlat_entry(str); \
51
169k
    if (new_str) { \
52
73.3k
      zend_string_release_ex(str, 0); \
53
73.3k
      str = new_str; \
54
96.1k
    } else { \
55
96.1k
      new_str = zend_shared_memdup_put((void*)str, _ZSTR_STRUCT_SIZE(ZSTR_LEN(str))); \
56
96.1k
      zend_string_release_ex(str, 0); \
57
96.1k
      str = new_str; \
58
96.1k
      zend_string_hash_val(str); \
59
96.1k
      zend_set_str_gc_flags(str); \
60
96.1k
    } \
61
169k
  } while (0)
62
#define zend_accel_memdup_string(str) do { \
63
    zend_string *new_str = zend_shared_alloc_get_xlat_entry(str); \
64
    if (new_str) { \
65
      str = new_str; \
66
    } else { \
67
      new_str = zend_shared_memdup_put((void*)str, _ZSTR_STRUCT_SIZE(ZSTR_LEN(str))); \
68
      str = new_str; \
69
      zend_string_hash_val(str); \
70
      zend_set_str_gc_flags(str); \
71
    } \
72
  } while (0)
73
1.24M
#define zend_accel_store_interned_string(str) do { \
74
1.24M
    if (!IS_ACCEL_INTERNED(str)) { \
75
52.1k
      zend_accel_store_string(str); \
76
52.1k
    } \
77
1.24M
  } while (0)
78
#define zend_accel_memdup_interned_string(str) do { \
79
    if (!IS_ACCEL_INTERNED(str)) { \
80
      zend_accel_memdup_string(str); \
81
    } \
82
  } while (0)
83
84
typedef void (*zend_persist_func_t)(zval*);
85
86
static void zend_persist_zval(zval *z);
87
static void zend_persist_op_array(zval *zv);
88
89
static const uint32_t uninitialized_bucket[-HT_MIN_MASK] =
90
  {HT_INVALID_IDX, HT_INVALID_IDX};
91
92
static void zend_hash_persist(HashTable *ht)
93
204k
{
94
204k
  uint32_t idx, nIndex;
95
204k
  Bucket *p;
96
97
204k
  HT_FLAGS(ht) |= HASH_FLAG_STATIC_KEYS;
98
204k
  ht->pDestructor = NULL;
99
204k
  ht->nInternalPointer = 0;
100
101
204k
  if (HT_FLAGS(ht) & HASH_FLAG_UNINITIALIZED) {
102
129k
    if (EXPECTED(!ZCG(current_persistent_script)->corrupted)) {
103
129k
      HT_SET_DATA_ADDR(ht, &ZCSG(uninitialized_bucket));
104
129k
    } else {
105
0
      HT_SET_DATA_ADDR(ht, &uninitialized_bucket);
106
0
    }
107
129k
    return;
108
129k
  }
109
75.7k
  if (ht->nNumUsed == 0) {
110
2
    efree(HT_GET_DATA_ADDR(ht));
111
2
    ht->nTableMask = HT_MIN_MASK;
112
2
    if (EXPECTED(!ZCG(current_persistent_script)->corrupted)) {
113
2
      HT_SET_DATA_ADDR(ht, &ZCSG(uninitialized_bucket));
114
2
    } else {
115
0
      HT_SET_DATA_ADDR(ht, &uninitialized_bucket);
116
0
    }
117
2
    HT_FLAGS(ht) |= HASH_FLAG_UNINITIALIZED;
118
2
    return;
119
2
  }
120
75.7k
  if (HT_IS_PACKED(ht)) {
121
18.4k
    void *data = HT_GET_DATA_ADDR(ht);
122
18.4k
    if (GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE) {
123
0
      data = zend_shared_memdup(data, HT_PACKED_USED_SIZE(ht));
124
18.4k
    } else {
125
18.4k
      data = zend_shared_memdup_free(data, HT_PACKED_USED_SIZE(ht));
126
18.4k
    }
127
18.4k
    HT_SET_DATA_ADDR(ht, data);
128
57.2k
  } else if (ht->nNumUsed > HT_MIN_SIZE && ht->nNumUsed < (uint32_t)(-(int32_t)ht->nTableMask) / 4) {
129
    /* compact table */
130
12
    void *old_data = HT_GET_DATA_ADDR(ht);
131
12
    Bucket *old_buckets = ht->arData;
132
12
    uint32_t hash_size;
133
134
12
    hash_size = (uint32_t)(-(int32_t)ht->nTableMask);
135
24
    while (hash_size >> 2 > ht->nNumUsed) {
136
12
      hash_size >>= 1;
137
12
    }
138
12
    ht->nTableMask = (uint32_t)(-(int32_t)hash_size);
139
12
    ZEND_ASSERT(((uintptr_t)ZCG(mem) & 0x7) == 0); /* should be 8 byte aligned */
140
12
    HT_SET_DATA_ADDR(ht, ZCG(mem));
141
12
    ZCG(mem) = (void*)((char*)ZCG(mem) + ZEND_ALIGNED_SIZE((hash_size * sizeof(uint32_t)) + (ht->nNumUsed * sizeof(Bucket))));
142
12
    HT_HASH_RESET(ht);
143
12
    memcpy(ht->arData, old_buckets, ht->nNumUsed * sizeof(Bucket));
144
12
    if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE)) {
145
12
      efree(old_data);
146
12
    }
147
148
    /* rehash */
149
192
    for (idx = 0; idx < ht->nNumUsed; idx++) {
150
180
      p = ht->arData + idx;
151
180
      if (Z_TYPE(p->val) == IS_UNDEF) continue;
152
180
      nIndex = p->h | ht->nTableMask;
153
180
      Z_NEXT(p->val) = HT_HASH(ht, nIndex);
154
180
      HT_HASH(ht, nIndex) = HT_IDX_TO_HASH(idx);
155
180
    }
156
57.2k
  } else {
157
57.2k
    void *data = ZCG(mem);
158
57.2k
    void *old_data = HT_GET_DATA_ADDR(ht);
159
160
57.2k
    ZEND_ASSERT(((uintptr_t)ZCG(mem) & 0x7) == 0); /* should be 8 byte aligned */
161
57.2k
    ZCG(mem) = (void*)((char*)data + ZEND_ALIGNED_SIZE(HT_USED_SIZE(ht)));
162
57.2k
    memcpy(data, old_data, HT_USED_SIZE(ht));
163
57.2k
    if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE)) {
164
57.2k
      efree(old_data);
165
57.2k
    }
166
57.2k
    HT_SET_DATA_ADDR(ht, data);
167
57.2k
  }
168
75.7k
}
169
170
static zend_ast *zend_persist_ast(zend_ast *ast)
171
17.8k
{
172
17.8k
  uint32_t i;
173
17.8k
  zend_ast *node;
174
175
17.8k
  if (ast->kind == ZEND_AST_ZVAL || ast->kind == ZEND_AST_CONSTANT) {
176
10.8k
    zend_ast_zval *copy = zend_shared_memdup(ast, sizeof(zend_ast_zval));
177
10.8k
    zend_persist_zval(&copy->val);
178
10.8k
    node = (zend_ast *) copy;
179
10.8k
  } else if (zend_ast_is_list(ast)) {
180
1.08k
    zend_ast_list *list = zend_ast_get_list(ast);
181
1.08k
    zend_ast_list *copy = zend_shared_memdup(ast,
182
1.08k
      sizeof(zend_ast_list) - sizeof(zend_ast *) + sizeof(zend_ast *) * list->children);
183
2.32k
    for (i = 0; i < list->children; i++) {
184
1.24k
      if (copy->child[i]) {
185
1.24k
        copy->child[i] = zend_persist_ast(copy->child[i]);
186
1.24k
      }
187
1.24k
    }
188
1.08k
    node = (zend_ast *) copy;
189
5.83k
  } else if (ast->kind == ZEND_AST_OP_ARRAY) {
190
70
    zend_ast_op_array *copy = zend_shared_memdup(ast, sizeof(zend_ast_op_array));
191
70
    zval z;
192
70
    ZVAL_PTR(&z, copy->op_array);
193
70
    zend_persist_op_array(&z);
194
70
    copy->op_array = Z_PTR(z);
195
70
    node = (zend_ast *) copy;
196
5.76k
  } else if (ast->kind == ZEND_AST_CALLABLE_CONVERT) {
197
192
    zend_ast_fcc *copy = zend_shared_memdup(ast, sizeof(zend_ast_fcc));
198
192
    copy->args = zend_persist_ast(copy->args);
199
192
    node = (zend_ast *) copy;
200
5.57k
  } else if (zend_ast_is_decl(ast)) {
201
    /* Not implemented. */
202
0
    ZEND_UNREACHABLE();
203
5.57k
  } else {
204
5.57k
    uint32_t children = zend_ast_get_num_children(ast);
205
5.57k
    node = zend_shared_memdup(ast, zend_ast_size(children));
206
18.9k
    for (i = 0; i < children; i++) {
207
13.3k
      if (node->child[i]) {
208
12.0k
        node->child[i] = zend_persist_ast(node->child[i]);
209
12.0k
      }
210
13.3k
    }
211
5.57k
  }
212
213
17.8k
  return node;
214
17.8k
}
215
216
static void zend_persist_zval(zval *z)
217
1.01M
{
218
1.01M
  void *new_ptr;
219
220
1.01M
  switch (Z_TYPE_P(z)) {
221
612k
    case IS_STRING:
222
612k
      zend_accel_store_interned_string(Z_STR_P(z));
223
612k
      Z_TYPE_FLAGS_P(z) = 0;
224
612k
      break;
225
22.2k
    case IS_ARRAY:
226
22.2k
      new_ptr = zend_shared_alloc_get_xlat_entry(Z_ARR_P(z));
227
22.2k
      if (new_ptr) {
228
513
        Z_ARR_P(z) = new_ptr;
229
513
        Z_TYPE_FLAGS_P(z) = 0;
230
21.6k
      } else if (!ZCG(current_persistent_script)->corrupted
231
21.6k
       && zend_accel_in_shm(Z_ARR_P(z))) {
232
        /* pass */
233
21.5k
      } else {
234
21.5k
        HashTable *ht;
235
236
21.5k
        if (!Z_REFCOUNTED_P(z)) {
237
3.38k
          ht = zend_shared_memdup_put(Z_ARR_P(z), sizeof(zend_array));
238
18.2k
        } else {
239
18.2k
          GC_REMOVE_FROM_BUFFER(Z_ARR_P(z));
240
18.2k
          ht = zend_shared_memdup_put_free(Z_ARR_P(z), sizeof(zend_array));
241
18.2k
        }
242
21.5k
        Z_ARR_P(z) = ht;
243
21.5k
        zend_hash_persist(ht);
244
21.5k
        if (HT_IS_PACKED(ht)) {
245
15.7k
          zval *zv;
246
247
474k
          ZEND_HASH_PACKED_FOREACH_VAL(ht, zv) {
248
474k
            zend_persist_zval(zv);
249
474k
          } ZEND_HASH_FOREACH_END();
250
15.7k
        } else {
251
5.81k
          Bucket *p;
252
253
28.4k
          ZEND_HASH_MAP_FOREACH_BUCKET(ht, p) {
254
28.4k
            if (p->key) {
255
3.52k
              zend_accel_store_interned_string(p->key);
256
3.52k
            }
257
28.4k
            zend_persist_zval(&p->val);
258
28.4k
          } ZEND_HASH_FOREACH_END();
259
5.81k
        }
260
        /* make immutable array */
261
21.5k
        Z_TYPE_FLAGS_P(z) = 0;
262
21.5k
        GC_SET_REFCOUNT(Z_COUNTED_P(z), 2);
263
21.5k
        GC_ADD_FLAGS(Z_COUNTED_P(z), IS_ARRAY_IMMUTABLE);
264
21.5k
      }
265
22.2k
      break;
266
22.2k
    case IS_CONSTANT_AST:
267
4.49k
      new_ptr = zend_shared_alloc_get_xlat_entry(Z_AST_P(z));
268
4.49k
      if (new_ptr) {
269
36
        Z_AST_P(z) = new_ptr;
270
36
        Z_TYPE_FLAGS_P(z) = 0;
271
4.45k
      } else if (ZCG(current_persistent_script)->corrupted
272
4.45k
       || !zend_accel_in_shm(Z_AST_P(z))) {
273
4.34k
        zend_ast_ref *old_ref = Z_AST_P(z);
274
4.34k
        Z_AST_P(z) = zend_shared_memdup_put(Z_AST_P(z), sizeof(zend_ast_ref));
275
4.34k
        zend_persist_ast(GC_AST(old_ref));
276
4.34k
        Z_TYPE_FLAGS_P(z) = 0;
277
4.34k
        GC_SET_REFCOUNT(Z_COUNTED_P(z), 1);
278
4.34k
        GC_ADD_FLAGS(Z_COUNTED_P(z), GC_IMMUTABLE);
279
4.34k
        efree(old_ref);
280
4.34k
      }
281
4.49k
      break;
282
192
    case IS_PTR:
283
192
      break;
284
373k
    default:
285
373k
      ZEND_ASSERT(Z_TYPE_P(z) < IS_STRING);
286
373k
      break;
287
1.01M
  }
288
1.01M
}
289
290
static HashTable *zend_persist_attributes(HashTable *attributes)
291
2.71k
{
292
2.71k
  uint32_t i;
293
2.71k
  zval *v;
294
295
2.71k
  if (!ZCG(current_persistent_script)->corrupted && zend_accel_in_shm(attributes)) {
296
34
    return attributes;
297
34
  }
298
299
  /* Attributes for trait properties may be shared if preloading is used. */
300
2.68k
  HashTable *xlat = zend_shared_alloc_get_xlat_entry(attributes);
301
2.68k
  if (xlat) {
302
0
    return xlat;
303
0
  }
304
305
2.68k
  zend_hash_persist(attributes);
306
307
12.6k
  ZEND_HASH_PACKED_FOREACH_VAL(attributes, v) {
308
12.6k
    zend_attribute *attr = Z_PTR_P(v);
309
12.6k
    zend_attribute *copy = zend_shared_memdup_put_free(attr, ZEND_ATTRIBUTE_SIZE(attr->argc));
310
311
12.6k
    zend_accel_store_interned_string(copy->name);
312
12.6k
    zend_accel_store_interned_string(copy->lcname);
313
12.6k
    if (copy->validation_error) {
314
90
      zend_accel_store_interned_string(copy->validation_error);
315
90
    }
316
317
12.6k
    for (i = 0; i < copy->argc; i++) {
318
1.25k
      if (copy->args[i].name) {
319
168
        zend_accel_store_interned_string(copy->args[i].name);
320
168
      }
321
1.25k
      zend_persist_zval(&copy->args[i].value);
322
1.25k
    }
323
324
12.6k
    ZVAL_PTR(v, copy);
325
12.6k
  } ZEND_HASH_FOREACH_END();
326
327
2.68k
  HashTable *ptr = zend_shared_memdup_put_free(attributes, sizeof(HashTable));
328
2.68k
  GC_SET_REFCOUNT(ptr, 2);
329
2.68k
  GC_TYPE_INFO(ptr) = GC_ARRAY | ((IS_ARRAY_IMMUTABLE|GC_NOT_COLLECTABLE) << GC_FLAGS_SHIFT);
330
331
2.68k
  return ptr;
332
2.68k
}
333
334
uint32_t zend_accel_get_class_name_map_ptr(zend_string *type_name)
335
29.7k
{
336
29.7k
  uint32_t ret;
337
338
29.7k
  if (zend_string_equals_ci(type_name, ZSTR_KNOWN(ZEND_STR_SELF)) ||
339
29.6k
      zend_string_equals_ci(type_name, ZSTR_KNOWN(ZEND_STR_PARENT))) {
340
122
    return 0;
341
122
  }
342
343
  /* We use type.name.gc.refcount to keep map_ptr of corresponding type */
344
29.6k
  if (ZSTR_HAS_CE_CACHE(type_name)) {
345
27.7k
    return GC_REFCOUNT(type_name);
346
27.7k
  }
347
348
1.87k
  if ((GC_FLAGS(type_name) & GC_IMMUTABLE)
349
1.87k
   && (GC_FLAGS(type_name) & IS_STR_PERMANENT)) {
350
1.87k
    do {
351
1.87k
      ret = ZEND_MAP_PTR_NEW_OFFSET();
352
1.87k
    } while (ret <= 2);
353
1.87k
    GC_SET_REFCOUNT(type_name, ret);
354
1.87k
    GC_ADD_FLAGS(type_name, IS_STR_CLASS_NAME_MAP_PTR);
355
1.87k
    return ret;
356
1.87k
  }
357
358
0
  return 0;
359
1.87k
}
360
361
55.0k
static void zend_persist_type(zend_type *type) {
362
55.0k
  if (ZEND_TYPE_HAS_LIST(*type)) {
363
1.76k
    zend_type_list *list = ZEND_TYPE_LIST(*type);
364
1.76k
    if (ZEND_TYPE_USES_ARENA(*type) || zend_accel_in_shm(list)) {
365
1.76k
      list = zend_shared_memdup_put(list, ZEND_TYPE_LIST_SIZE(list->num_types));
366
1.76k
      ZEND_TYPE_FULL_MASK(*type) &= ~_ZEND_TYPE_ARENA_BIT;
367
1.76k
    } else {
368
0
      list = zend_shared_memdup_put_free(list, ZEND_TYPE_LIST_SIZE(list->num_types));
369
0
    }
370
1.76k
    ZEND_TYPE_SET_PTR(*type, list);
371
1.76k
  }
372
373
55.0k
  zend_type *single_type;
374
111k
  ZEND_TYPE_FOREACH_MUTABLE(*type, single_type) {
375
111k
    if (ZEND_TYPE_HAS_LIST(*single_type)) {
376
508
      zend_persist_type(single_type);
377
508
      continue;
378
508
    }
379
56.2k
    if (ZEND_TYPE_HAS_NAME(*single_type)) {
380
7.04k
      zend_string *type_name = ZEND_TYPE_NAME(*single_type);
381
7.04k
      zend_accel_store_interned_string(type_name);
382
7.04k
      ZEND_TYPE_SET_PTR(*single_type, type_name);
383
7.04k
      if (!ZCG(current_persistent_script)->corrupted) {
384
7.04k
        zend_accel_get_class_name_map_ptr(type_name);
385
7.04k
      }
386
7.04k
    }
387
56.2k
  } ZEND_TYPE_FOREACH_END();
388
55.0k
}
389
390
static void zend_persist_op_array_ex(zend_op_array *op_array, zend_persistent_script* main_persistent_script)
391
98.5k
{
392
98.5k
  zend_op *persist_ptr;
393
98.5k
  zval *orig_literals = NULL;
394
395
98.5k
  if (op_array->refcount && --(*op_array->refcount) == 0) {
396
92.2k
    efree(op_array->refcount);
397
92.2k
  }
398
98.5k
  op_array->refcount = NULL;
399
400
98.5k
  if (main_persistent_script) {
401
49.4k
    zend_execute_data *orig_execute_data = EG(current_execute_data);
402
49.4k
    zend_execute_data fake_execute_data;
403
49.4k
    zval *offset;
404
405
49.4k
    memset(&fake_execute_data, 0, sizeof(fake_execute_data));
406
49.4k
    fake_execute_data.func = (zend_function*)op_array;
407
49.4k
    EG(current_execute_data) = &fake_execute_data;
408
49.4k
    if ((offset = zend_get_constant_str("__COMPILER_HALT_OFFSET__", sizeof("__COMPILER_HALT_OFFSET__") - 1)) != NULL) {
409
50
      main_persistent_script->compiler_halt_offset = Z_LVAL_P(offset);
410
50
    }
411
49.4k
    EG(current_execute_data) = orig_execute_data;
412
49.4k
  }
413
414
98.5k
  if (op_array->function_name) {
415
49.0k
    zend_string *old_name = op_array->function_name;
416
49.0k
    zend_accel_store_interned_string(op_array->function_name);
417
    /* Remember old function name, so it can be released multiple times if shared. */
418
49.0k
    if (op_array->function_name != old_name
419
878
        && !zend_shared_alloc_get_xlat_entry(&op_array->function_name)) {
420
878
      zend_shared_alloc_register_xlat_entry(&op_array->function_name, old_name);
421
878
    }
422
49.0k
  }
423
424
98.5k
  if (op_array->scope) {
425
27.5k
    zend_class_entry *scope = zend_shared_alloc_get_xlat_entry(op_array->scope);
426
427
27.5k
    if (scope) {
428
27.5k
      op_array->scope = scope;
429
27.5k
    }
430
431
27.5k
    if (op_array->prototype) {
432
3.61k
      zend_function *ptr = zend_shared_alloc_get_xlat_entry(op_array->prototype);
433
434
3.61k
      if (ptr) {
435
867
        op_array->prototype = ptr;
436
867
      }
437
3.61k
    }
438
439
27.5k
    persist_ptr = zend_shared_alloc_get_xlat_entry(op_array->opcodes);
440
27.5k
    if (persist_ptr) {
441
0
      op_array->opcodes = persist_ptr;
442
0
      if (op_array->static_variables) {
443
0
        op_array->static_variables = zend_shared_alloc_get_xlat_entry(op_array->static_variables);
444
0
        ZEND_ASSERT(op_array->static_variables != NULL);
445
0
      }
446
0
      if (op_array->literals) {
447
0
        op_array->literals = zend_shared_alloc_get_xlat_entry(op_array->literals);
448
0
        ZEND_ASSERT(op_array->literals != NULL);
449
0
      }
450
0
      if (op_array->filename) {
451
0
        op_array->filename = zend_shared_alloc_get_xlat_entry(op_array->filename);
452
0
        ZEND_ASSERT(op_array->filename != NULL);
453
0
      }
454
0
      if (op_array->arg_info) {
455
0
        zend_arg_info *arg_info = op_array->arg_info;
456
0
        if (op_array->fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
457
0
          arg_info--;
458
0
        }
459
0
        arg_info = zend_shared_alloc_get_xlat_entry(arg_info);
460
0
        ZEND_ASSERT(arg_info != NULL);
461
0
        if (op_array->fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
462
0
          arg_info++;
463
0
        }
464
0
        op_array->arg_info = arg_info;
465
0
      }
466
0
      if (op_array->live_range) {
467
0
        op_array->live_range = zend_shared_alloc_get_xlat_entry(op_array->live_range);
468
0
        ZEND_ASSERT(op_array->live_range != NULL);
469
0
      }
470
0
      if (op_array->doc_comment) {
471
0
        if (ZCG(accel_directives).save_comments) {
472
0
          op_array->doc_comment = zend_shared_alloc_get_xlat_entry(op_array->doc_comment);
473
0
          ZEND_ASSERT(op_array->doc_comment != NULL);
474
0
        } else {
475
0
          op_array->doc_comment = NULL;
476
0
        }
477
0
      }
478
0
      if (op_array->attributes) {
479
0
        op_array->attributes = zend_shared_alloc_get_xlat_entry(op_array->attributes);
480
0
        ZEND_ASSERT(op_array->attributes != NULL);
481
0
      }
482
483
0
      if (op_array->try_catch_array) {
484
0
        op_array->try_catch_array = zend_shared_alloc_get_xlat_entry(op_array->try_catch_array);
485
0
        ZEND_ASSERT(op_array->try_catch_array != NULL);
486
0
      }
487
0
      if (op_array->vars) {
488
0
        op_array->vars = zend_shared_alloc_get_xlat_entry(op_array->vars);
489
0
        ZEND_ASSERT(op_array->vars != NULL);
490
0
      }
491
0
      if (op_array->dynamic_func_defs) {
492
0
        op_array->dynamic_func_defs = zend_shared_alloc_get_xlat_entry(op_array->dynamic_func_defs);
493
0
        ZEND_ASSERT(op_array->dynamic_func_defs != NULL);
494
0
      }
495
0
      ZCG(mem) = (void*)((char*)ZCG(mem) + ZEND_ALIGNED_SIZE(zend_extensions_op_array_persist(op_array, ZCG(mem))));
496
0
      return;
497
0
    }
498
70.9k
  } else {
499
    /* "prototype" may be undefined if "scope" isn't set */
500
70.9k
    op_array->prototype = NULL;
501
70.9k
  }
502
503
98.5k
  if (op_array->scope
504
27.5k
   && !(op_array->fn_flags & ZEND_ACC_CLOSURE)
505
27.5k
   && (op_array->scope->ce_flags & ZEND_ACC_CACHED)) {
506
4.66k
    return;
507
4.66k
  }
508
509
93.8k
  if (op_array->static_variables && !zend_accel_in_shm(op_array->static_variables)) {
510
2.40k
    Bucket *p;
511
512
2.40k
    zend_hash_persist(op_array->static_variables);
513
21.5k
    ZEND_HASH_MAP_FOREACH_BUCKET(op_array->static_variables, p) {
514
21.5k
      ZEND_ASSERT(p->key != NULL);
515
21.5k
      zend_accel_store_interned_string(p->key);
516
8.36k
      zend_persist_zval(&p->val);
517
8.36k
    } ZEND_HASH_FOREACH_END();
518
2.40k
    op_array->static_variables = zend_shared_memdup_put_free(op_array->static_variables, sizeof(HashTable));
519
    /* make immutable array */
520
2.40k
    GC_SET_REFCOUNT(op_array->static_variables, 2);
521
2.40k
    GC_TYPE_INFO(op_array->static_variables) = GC_ARRAY | ((IS_ARRAY_IMMUTABLE|GC_NOT_COLLECTABLE) << GC_FLAGS_SHIFT);
522
2.40k
  }
523
524
93.8k
  if (op_array->literals) {
525
92.0k
    zval *p, *end;
526
527
92.0k
    orig_literals = op_array->literals;
528
#if ZEND_USE_ABS_CONST_ADDR
529
    p = zend_shared_memdup_put_free(op_array->literals, sizeof(zval) * op_array->last_literal);
530
#else
531
92.0k
    p = zend_shared_memdup_put(op_array->literals, sizeof(zval) * op_array->last_literal);
532
92.0k
#endif
533
92.0k
    end = p + op_array->last_literal;
534
92.0k
    op_array->literals = p;
535
833k
    while (p < end) {
536
741k
      zend_persist_zval(p);
537
741k
      p++;
538
741k
    }
539
92.0k
  }
540
541
93.8k
  {
542
93.8k
    zend_op *new_opcodes = zend_shared_memdup_put(op_array->opcodes, sizeof(zend_op) * op_array->last);
543
93.8k
    zend_op *opline = new_opcodes;
544
93.8k
    zend_op *end = new_opcodes + op_array->last;
545
546
2.31M
    for (; opline < end ; opline++) {
547
#if ZEND_USE_ABS_CONST_ADDR
548
      if (opline->op1_type == IS_CONST) {
549
        opline->op1.zv = (zval*)((char*)opline->op1.zv + ((char*)op_array->literals - (char*)orig_literals));
550
        if (opline->opcode == ZEND_SEND_VAL
551
         || opline->opcode == ZEND_SEND_VAL_EX
552
         || opline->opcode == ZEND_QM_ASSIGN) {
553
          /* Update handlers to eliminate REFCOUNTED check */
554
          zend_vm_set_opcode_handler_ex(opline, 1 << Z_TYPE_P(opline->op1.zv), 0, 0);
555
        }
556
      }
557
      if (opline->op2_type == IS_CONST) {
558
        opline->op2.zv = (zval*)((char*)opline->op2.zv + ((char*)op_array->literals - (char*)orig_literals));
559
      }
560
#else
561
2.21M
      if (opline->op1_type == IS_CONST) {
562
391k
        opline->op1.constant =
563
391k
          (char*)(op_array->literals +
564
391k
            ((zval*)((char*)(op_array->opcodes + (opline - new_opcodes)) +
565
391k
            (int32_t)opline->op1.constant) - orig_literals)) -
566
391k
          (char*)opline;
567
391k
        if (opline->opcode == ZEND_SEND_VAL
568
342k
         || opline->opcode == ZEND_SEND_VAL_EX
569
333k
         || opline->opcode == ZEND_QM_ASSIGN) {
570
66.6k
          zend_vm_set_opcode_handler_ex(opline, 0, 0, 0);
571
66.6k
        }
572
391k
      }
573
2.21M
      if (opline->op2_type == IS_CONST) {
574
570k
        opline->op2.constant =
575
570k
          (char*)(op_array->literals +
576
570k
            ((zval*)((char*)(op_array->opcodes + (opline - new_opcodes)) +
577
570k
            (int32_t)opline->op2.constant) - orig_literals)) -
578
570k
          (char*)opline;
579
570k
      }
580
2.21M
#endif
581
#if ZEND_USE_ABS_JMP_ADDR
582
      if (op_array->fn_flags & ZEND_ACC_DONE_PASS_TWO) {
583
        /* fix jumps to point to new array */
584
        switch (opline->opcode) {
585
          case ZEND_JMP:
586
          case ZEND_FAST_CALL:
587
            opline->op1.jmp_addr = &new_opcodes[opline->op1.jmp_addr - op_array->opcodes];
588
            break;
589
          case ZEND_JMPZ:
590
          case ZEND_JMPNZ:
591
          case ZEND_JMPZ_EX:
592
          case ZEND_JMPNZ_EX:
593
          case ZEND_JMP_SET:
594
          case ZEND_COALESCE:
595
          case ZEND_FE_RESET_R:
596
          case ZEND_FE_RESET_RW:
597
          case ZEND_ASSERT_CHECK:
598
          case ZEND_JMP_NULL:
599
          case ZEND_BIND_INIT_STATIC_OR_JMP:
600
          case ZEND_JMP_FRAMELESS:
601
            opline->op2.jmp_addr = &new_opcodes[opline->op2.jmp_addr - op_array->opcodes];
602
            break;
603
          case ZEND_CATCH:
604
            if (!(opline->extended_value & ZEND_LAST_CATCH)) {
605
              opline->op2.jmp_addr = &new_opcodes[opline->op2.jmp_addr - op_array->opcodes];
606
            }
607
            break;
608
          case ZEND_FE_FETCH_R:
609
          case ZEND_FE_FETCH_RW:
610
          case ZEND_SWITCH_LONG:
611
          case ZEND_SWITCH_STRING:
612
          case ZEND_MATCH:
613
            /* relative extended_value don't have to be changed */
614
            break;
615
        }
616
      }
617
#endif
618
2.21M
      if (opline->opcode == ZEND_OP_DATA && (opline-1)->opcode == ZEND_DECLARE_ATTRIBUTED_CONST) {
619
192
        zval *literal = RT_CONSTANT(opline, opline->op1);
620
192
        HashTable *attributes = Z_PTR_P(literal);
621
192
        attributes = zend_persist_attributes(attributes);
622
192
        ZVAL_PTR(literal, attributes);
623
192
      }
624
2.21M
    }
625
626
93.8k
    efree(op_array->opcodes);
627
93.8k
    op_array->opcodes = new_opcodes;
628
93.8k
  }
629
630
93.8k
  if (op_array->filename) {
631
93.8k
    zend_accel_store_string(op_array->filename);
632
93.8k
  }
633
634
93.8k
  if (op_array->arg_info) {
635
23.1k
    zend_arg_info *arg_info = op_array->arg_info;
636
23.1k
    uint32_t num_args = op_array->num_args;
637
23.1k
    uint32_t i;
638
639
23.1k
    if (op_array->fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
640
7.53k
      arg_info--;
641
7.53k
      num_args++;
642
7.53k
    }
643
23.1k
    if (op_array->fn_flags & ZEND_ACC_VARIADIC) {
644
406
      num_args++;
645
406
    }
646
23.1k
    arg_info = zend_shared_memdup_put_free(arg_info, sizeof(zend_arg_info) * num_args);
647
57.5k
    for (i = 0; i < num_args; i++) {
648
34.4k
      if (arg_info[i].name) {
649
26.8k
        zend_accel_store_interned_string(arg_info[i].name);
650
26.8k
      }
651
34.4k
      zend_persist_type(&arg_info[i].type);
652
34.4k
      if (arg_info[i].doc_comment) {
653
0
        zend_accel_store_interned_string(arg_info[i].doc_comment);
654
0
      }
655
34.4k
    }
656
23.1k
    if (op_array->fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
657
7.53k
      arg_info++;
658
7.53k
    }
659
23.1k
    op_array->arg_info = arg_info;
660
23.1k
  }
661
662
93.8k
  if (op_array->live_range) {
663
45.9k
    op_array->live_range = zend_shared_memdup_put_free(op_array->live_range, sizeof(zend_live_range) * op_array->last_live_range);
664
45.9k
  }
665
666
93.8k
  if (op_array->doc_comment) {
667
42
    if (ZCG(accel_directives).save_comments) {
668
42
      zend_accel_store_interned_string(op_array->doc_comment);
669
42
    } else {
670
0
      zend_string_release_ex(op_array->doc_comment, 0);
671
0
      op_array->doc_comment = NULL;
672
0
    }
673
42
  }
674
675
93.8k
  if (op_array->attributes) {
676
968
    op_array->attributes = zend_persist_attributes(op_array->attributes);
677
968
  }
678
679
93.8k
  if (op_array->try_catch_array) {
680
18.6k
    op_array->try_catch_array = zend_shared_memdup_put_free(op_array->try_catch_array, sizeof(zend_try_catch_element) * op_array->last_try_catch);
681
18.6k
  }
682
683
93.8k
  if (op_array->vars) {
684
63.5k
    int i;
685
63.5k
    op_array->vars = zend_shared_memdup_put_free(op_array->vars, sizeof(zend_string*) * op_array->last_var);
686
392k
    for (i = 0; i < op_array->last_var; i++) {
687
329k
      zend_accel_store_interned_string(op_array->vars[i]);
688
329k
    }
689
63.5k
  }
690
691
93.8k
  if (op_array->num_dynamic_func_defs) {
692
5.00k
    op_array->dynamic_func_defs = zend_shared_memdup_put_free(
693
5.00k
      op_array->dynamic_func_defs, sizeof(zend_function *) * op_array->num_dynamic_func_defs);
694
12.6k
    for (uint32_t i = 0; i < op_array->num_dynamic_func_defs; i++) {
695
7.60k
      zval tmp;
696
7.60k
      ZVAL_PTR(&tmp, op_array->dynamic_func_defs[i]);
697
7.60k
      zend_persist_op_array(&tmp);
698
7.60k
      op_array->dynamic_func_defs[i] = Z_PTR(tmp);
699
7.60k
    }
700
5.00k
  }
701
702
93.8k
  ZCG(mem) = (void*)((char*)ZCG(mem) + ZEND_ALIGNED_SIZE(zend_extensions_op_array_persist(op_array, ZCG(mem))));
703
93.8k
}
704
705
static void zend_persist_op_array(zval *zv)
706
21.4k
{
707
21.4k
  zend_op_array *op_array = Z_PTR_P(zv);
708
21.4k
  zend_op_array *old_op_array;
709
21.4k
  ZEND_ASSERT(op_array->type == ZEND_USER_FUNCTION);
710
711
21.4k
  old_op_array = zend_shared_alloc_get_xlat_entry(op_array);
712
21.4k
  if (!old_op_array) {
713
21.4k
    op_array = Z_PTR_P(zv) = zend_shared_memdup_put(Z_PTR_P(zv), sizeof(zend_op_array));
714
21.4k
    zend_persist_op_array_ex(op_array, NULL);
715
21.4k
    if (!ZCG(current_persistent_script)->corrupted) {
716
21.4k
      op_array->fn_flags |= ZEND_ACC_IMMUTABLE;
717
21.4k
      ZEND_MAP_PTR_NEW(op_array->run_time_cache);
718
21.4k
      if (op_array->static_variables) {
719
2.20k
        ZEND_MAP_PTR_NEW(op_array->static_variables_ptr);
720
2.20k
      }
721
21.4k
    }
722
21.4k
#ifdef HAVE_JIT
723
21.4k
    if (JIT_G(on)
724
0
     && JIT_G(opt_level) <= ZEND_JIT_LEVEL_OPT_FUNCS
725
0
     && (!ZCG(current_persistent_script)
726
0
      || !ZCG(current_persistent_script)->corrupted)) {
727
0
      zend_jit_op_array(op_array, ZCG(current_persistent_script) ? &ZCG(current_persistent_script)->script : NULL);
728
0
    }
729
21.4k
#endif
730
21.4k
  } else {
731
    /* This can happen during preloading, if a dynamic function definition is declared. */
732
0
    Z_PTR_P(zv) = old_op_array;
733
0
  }
734
21.4k
}
735
736
static zend_op_array *zend_persist_class_method(zend_op_array *op_array, const zend_class_entry *ce)
737
34.1k
{
738
34.1k
  zend_op_array *old_op_array;
739
740
34.1k
  if (op_array->type != ZEND_USER_FUNCTION) {
741
4.21k
    ZEND_ASSERT(op_array->type == ZEND_INTERNAL_FUNCTION);
742
4.21k
    if (op_array->fn_flags & ZEND_ACC_ARENA_ALLOCATED) {
743
4.21k
      old_op_array = zend_shared_alloc_get_xlat_entry(op_array);
744
4.21k
      if (old_op_array) {
745
0
        return old_op_array;
746
4.21k
      } else {
747
4.21k
        op_array = zend_shared_memdup_put(op_array, sizeof(zend_internal_function));
748
4.21k
        if (op_array->scope) {
749
4.21k
          void *persist_ptr;
750
751
4.21k
          if ((persist_ptr = zend_shared_alloc_get_xlat_entry(op_array->scope))) {
752
0
            op_array->scope = (zend_class_entry*)persist_ptr;
753
0
          }
754
4.21k
          if (op_array->prototype) {
755
1.82k
            if ((persist_ptr = zend_shared_alloc_get_xlat_entry(op_array->prototype))) {
756
0
              op_array->prototype = (zend_function*)persist_ptr;
757
0
            }
758
1.82k
          }
759
4.21k
        }
760
        // Real dynamically created internal functions like enum methods must have their own run_time_cache pointer. They're always on the same scope as their defining class.
761
        // However, copies - as caused by inheritance of internal methods - must retain the original run_time_cache pointer, shared with the source function.
762
4.21k
        if (!op_array->scope || (op_array->scope == ce && !(op_array->fn_flags & ZEND_ACC_TRAIT_CLONE))) {
763
0
          if (op_array->fn_flags & ZEND_ACC_PRELOADED) {
764
0
            ZEND_MAP_PTR_NEW_STATIC(op_array->run_time_cache);
765
0
          } else {
766
0
            ZEND_MAP_PTR_NEW(op_array->run_time_cache);
767
0
          }
768
0
        }
769
4.21k
      }
770
4.21k
    }
771
4.21k
    return op_array;
772
4.21k
  }
773
774
29.8k
  if ((op_array->fn_flags & ZEND_ACC_IMMUTABLE)
775
460
   && !ZCG(current_persistent_script)->corrupted
776
460
   && zend_accel_in_shm(op_array)) {
777
452
    zend_shared_alloc_register_xlat_entry(op_array, op_array);
778
452
    return op_array;
779
452
  }
780
781
29.4k
  old_op_array = zend_shared_alloc_get_xlat_entry(op_array);
782
29.4k
  if (old_op_array) {
783
1.85k
    if (op_array->refcount && --(*op_array->refcount) == 0) {
784
1.58k
      efree(op_array->refcount);
785
1.58k
    }
786
787
    /* If op_array is shared, the function name refcount is still incremented for each use,
788
     * so we need to release it here. We remembered the original function name in xlat. */
789
1.85k
    zend_string *old_function_name =
790
1.85k
      zend_shared_alloc_get_xlat_entry(&old_op_array->function_name);
791
1.85k
    if (old_function_name) {
792
0
      zend_string_release_ex(old_function_name, 0);
793
0
    }
794
1.85k
    return old_op_array;
795
1.85k
  }
796
797
27.5k
  op_array = zend_shared_memdup_put(op_array, sizeof(zend_op_array));
798
27.5k
  zend_persist_op_array_ex(op_array, NULL);
799
27.5k
  if (ce->ce_flags & ZEND_ACC_IMMUTABLE) {
800
27.5k
    op_array->fn_flags |= ZEND_ACC_IMMUTABLE;
801
27.5k
    if (ce->ce_flags & ZEND_ACC_LINKED) {
802
23.3k
      ZEND_MAP_PTR_NEW(op_array->run_time_cache);
803
23.3k
      if (op_array->static_variables) {
804
211
        ZEND_MAP_PTR_NEW(op_array->static_variables_ptr);
805
211
      }
806
23.3k
    } else {
807
4.25k
      ZEND_MAP_PTR_INIT(op_array->run_time_cache, NULL);
808
4.25k
      ZEND_MAP_PTR_INIT(op_array->static_variables_ptr, NULL);
809
4.25k
    }
810
27.5k
  }
811
27.5k
  return op_array;
812
29.4k
}
813
814
static zend_property_info *zend_persist_property_info(zend_property_info *prop)
815
15.8k
{
816
15.8k
  zend_class_entry *ce;
817
15.8k
  prop = zend_shared_memdup_put(prop, sizeof(zend_property_info));
818
15.8k
  ce = zend_shared_alloc_get_xlat_entry(prop->ce);
819
15.8k
  if (ce) {
820
15.8k
    prop->ce = ce;
821
15.8k
  }
822
15.8k
  zend_accel_store_interned_string(prop->name);
823
15.8k
  if (prop->doc_comment) {
824
284
    if (ZCG(accel_directives).save_comments) {
825
284
      zend_accel_store_interned_string(prop->doc_comment);
826
284
    } else {
827
0
      if (!zend_shared_alloc_get_xlat_entry(prop->doc_comment)) {
828
0
        zend_shared_alloc_register_xlat_entry(prop->doc_comment, prop->doc_comment);
829
0
      }
830
0
      zend_string_release_ex(prop->doc_comment, 0);
831
0
      prop->doc_comment = NULL;
832
0
    }
833
284
  }
834
15.8k
  if (prop->attributes) {
835
192
    prop->attributes = zend_persist_attributes(prop->attributes);
836
192
  }
837
15.8k
  if (prop->prototype) {
838
15.8k
    const zend_property_info *new_prototype = (const zend_property_info *) zend_shared_alloc_get_xlat_entry(prop->prototype);
839
15.8k
    if (new_prototype) {
840
15.7k
      prop->prototype = new_prototype;
841
15.7k
    }
842
15.8k
  }
843
15.8k
  if (prop->hooks) {
844
1.63k
    prop->hooks = zend_shared_memdup_put(prop->hooks, ZEND_PROPERTY_HOOK_STRUCT_SIZE);
845
4.89k
    for (uint32_t i = 0; i < ZEND_PROPERTY_HOOK_COUNT; i++) {
846
3.26k
      if (prop->hooks[i]) {
847
2.14k
        zend_op_array *hook = zend_persist_class_method(&prop->hooks[i]->op_array, ce);
848
2.14k
#ifdef HAVE_JIT
849
2.14k
        if (JIT_G(on)
850
0
         && JIT_G(opt_level) <= ZEND_JIT_LEVEL_OPT_FUNCS
851
0
         && (!ZCG(current_persistent_script)
852
0
          || !ZCG(current_persistent_script)->corrupted)) {
853
0
          if (hook->scope == ce && !(hook->fn_flags & ZEND_ACC_TRAIT_CLONE)) {
854
0
            zend_jit_op_array(hook, ZCG(current_persistent_script) ? &ZCG(current_persistent_script)->script : NULL);
855
0
          }
856
0
        }
857
2.14k
#endif
858
2.14k
        const zend_property_info *new_prop_info = (const zend_property_info *) zend_shared_alloc_get_xlat_entry(hook->prop_info);
859
2.14k
        if (new_prop_info) {
860
2.09k
          hook->prop_info = new_prop_info;
861
2.09k
        }
862
2.14k
        prop->hooks[i] = (zend_function *) hook;
863
2.14k
      }
864
3.26k
    }
865
1.63k
  }
866
15.8k
  zend_persist_type(&prop->type);
867
15.8k
  return prop;
868
15.8k
}
869
870
static void zend_persist_class_constant(zval *zv)
871
5.43k
{
872
5.43k
  const zend_class_constant *orig_c = Z_PTR_P(zv);
873
5.43k
  zend_class_constant *c = zend_shared_alloc_get_xlat_entry(orig_c);
874
5.43k
  zend_class_entry *ce;
875
876
5.43k
  if (c) {
877
174
    Z_PTR_P(zv) = c;
878
174
    return;
879
5.25k
  } else if (((orig_c->ce->ce_flags & ZEND_ACC_IMMUTABLE) && !(Z_CONSTANT_FLAGS(orig_c->value) & CONST_OWNED))
880
5.12k
   || orig_c->ce->type == ZEND_INTERNAL_CLASS) {
881
    /* Class constant comes from a different file in shm or internal class, keep existing pointer. */
882
966
    return;
883
4.29k
  } else if (!ZCG(current_persistent_script)->corrupted
884
4.29k
   && zend_accel_in_shm(Z_PTR_P(zv))) {
885
0
    return;
886
0
  }
887
4.29k
  c = Z_PTR_P(zv) = zend_shared_memdup_put(Z_PTR_P(zv), sizeof(zend_class_constant));
888
4.29k
  zend_persist_zval(&c->value);
889
4.29k
  ce = zend_shared_alloc_get_xlat_entry(c->ce);
890
4.29k
  if (ce) {
891
4.27k
    c->ce = ce;
892
4.27k
  }
893
4.29k
  if (c->doc_comment) {
894
28
    if (ZCG(accel_directives).save_comments) {
895
28
      zend_string *doc_comment = zend_shared_alloc_get_xlat_entry(c->doc_comment);
896
28
      if (doc_comment) {
897
0
        c->doc_comment = doc_comment;
898
28
      } else {
899
28
        zend_accel_store_interned_string(c->doc_comment);
900
28
      }
901
28
    } else {
902
0
      zend_string *doc_comment = zend_shared_alloc_get_xlat_entry(c->doc_comment);
903
0
      if (!doc_comment) {
904
0
        zend_shared_alloc_register_xlat_entry(c->doc_comment, c->doc_comment);
905
0
        zend_string_release_ex(c->doc_comment, 0);
906
0
      }
907
0
      c->doc_comment = NULL;
908
0
    }
909
28
  }
910
4.29k
  if (c->attributes) {
911
168
    c->attributes = zend_persist_attributes(c->attributes);
912
168
  }
913
4.29k
  zend_persist_type(&c->type);
914
4.29k
}
915
916
zend_class_entry *zend_persist_class_entry(zend_class_entry *orig_ce)
917
26.3k
{
918
26.3k
  Bucket *p;
919
26.3k
  zend_class_entry *ce = orig_ce;
920
921
26.3k
  if (ce->type == ZEND_USER_CLASS) {
922
    /* The same zend_class_entry may be reused by class_alias */
923
26.3k
    zend_class_entry *new_ce = zend_shared_alloc_get_xlat_entry(ce);
924
26.3k
    if (new_ce) {
925
0
      return new_ce;
926
0
    }
927
26.3k
    ce = zend_shared_memdup_put(ce, sizeof(zend_class_entry));
928
26.3k
    if (EXPECTED(!ZCG(current_persistent_script)->corrupted)) {
929
26.3k
      ce->ce_flags |= ZEND_ACC_IMMUTABLE;
930
26.3k
      if ((ce->ce_flags & ZEND_ACC_LINKED)
931
21.4k
       && !(ce->ce_flags & ZEND_ACC_CONSTANTS_UPDATED)) {
932
654
        ZEND_MAP_PTR_NEW(ce->mutable_data);
933
25.7k
      } else {
934
25.7k
        ZEND_MAP_PTR_INIT(ce->mutable_data, NULL);
935
25.7k
      }
936
26.3k
    } else {
937
0
      ce->ce_flags |= ZEND_ACC_FILE_CACHED;
938
0
    }
939
26.3k
    ce->inheritance_cache = NULL;
940
941
26.3k
    if (!(ce->ce_flags & ZEND_ACC_CACHED)) {
942
23.3k
      if (ZSTR_HAS_CE_CACHE(ce->name)) {
943
21.2k
        ZSTR_SET_CE_CACHE_EX(ce->name, NULL, 0);
944
21.2k
      }
945
23.3k
      zend_accel_store_interned_string(ce->name);
946
23.3k
      if (!(ce->ce_flags & ZEND_ACC_ANON_CLASS)
947
22.6k
       && !ZCG(current_persistent_script)->corrupted) {
948
22.6k
        zend_accel_get_class_name_map_ptr(ce->name);
949
22.6k
      }
950
23.3k
      if (ce->parent_name && !(ce->ce_flags & ZEND_ACC_LINKED)) {
951
1.17k
        zend_accel_store_interned_string(ce->parent_name);
952
1.17k
      }
953
23.3k
    }
954
955
26.3k
    zend_hash_persist(&ce->function_table);
956
116k
    ZEND_HASH_MAP_FOREACH_BUCKET(&ce->function_table, p) {
957
116k
      ZEND_ASSERT(p->key != NULL);
958
116k
      zend_accel_store_interned_string(p->key);
959
31.9k
      Z_PTR(p->val) = zend_persist_class_method(Z_PTR(p->val), ce);
960
31.9k
    } ZEND_HASH_FOREACH_END();
961
26.3k
    HT_FLAGS(&ce->function_table) &= (HASH_FLAG_UNINITIALIZED | HASH_FLAG_STATIC_KEYS);
962
26.3k
    if (ce->default_properties_table) {
963
9.10k
        int i;
964
965
9.10k
      ce->default_properties_table = zend_shared_memdup_free(ce->default_properties_table, sizeof(zval) * ce->default_properties_count);
966
24.0k
      for (i = 0; i < ce->default_properties_count; i++) {
967
14.9k
        zend_persist_zval(&ce->default_properties_table[i]);
968
14.9k
      }
969
9.10k
    }
970
26.3k
    if (ce->default_static_members_table) {
971
1.61k
      ce->default_static_members_table = zend_shared_memdup_free(ce->default_static_members_table, sizeof(zval) * ce->default_static_members_count);
972
973
      /* Persist only static properties in this class.
974
       * Static properties from parent classes will be handled in class_copy_ctor and are marked with IS_INDIRECT */
975
4.59k
      for (uint32_t i = 0; i < ce->default_static_members_count; i++) {
976
2.97k
        if (Z_TYPE(ce->default_static_members_table[i]) != IS_INDIRECT) {
977
2.61k
          zend_persist_zval(&ce->default_static_members_table[i]);
978
2.61k
        }
979
2.97k
      }
980
1.61k
      if (ce->ce_flags & ZEND_ACC_IMMUTABLE) {
981
1.61k
        if (ce->ce_flags & ZEND_ACC_LINKED) {
982
1.57k
          ZEND_MAP_PTR_NEW(ce->static_members_table);
983
1.57k
        } else {
984
48
          ZEND_MAP_PTR_INIT(ce->static_members_table, NULL);
985
48
        }
986
1.61k
      }
987
1.61k
    }
988
989
26.3k
    zend_hash_persist(&ce->constants_table);
990
63.5k
    ZEND_HASH_MAP_FOREACH_BUCKET(&ce->constants_table, p) {
991
63.5k
      ZEND_ASSERT(p->key != NULL);
992
63.5k
      zend_accel_store_interned_string(p->key);
993
5.43k
      zend_persist_class_constant(&p->val);
994
5.43k
    } ZEND_HASH_FOREACH_END();
995
26.3k
    HT_FLAGS(&ce->constants_table) &= (HASH_FLAG_UNINITIALIZED | HASH_FLAG_STATIC_KEYS);
996
997
26.3k
    zend_hash_persist(&ce->properties_info);
998
89.6k
    ZEND_HASH_MAP_FOREACH_BUCKET(&ce->properties_info, p) {
999
89.6k
      zend_property_info *prop = Z_PTR(p->val);
1000
89.6k
      ZEND_ASSERT(p->key != NULL);
1001
89.6k
      zend_accel_store_interned_string(p->key);
1002
18.4k
      if (prop->ce == orig_ce) {
1003
15.8k
        Z_PTR(p->val) = zend_persist_property_info(prop);
1004
15.8k
      } else {
1005
2.62k
        prop = zend_shared_alloc_get_xlat_entry(prop);
1006
2.62k
        if (prop) {
1007
1.20k
          Z_PTR(p->val) = prop;
1008
1.42k
        } else {
1009
          /* This can happen if preloading is used and we inherit a property from an
1010
           * internal class. In that case we should keep pointing to the internal
1011
           * property, without any adjustments. */
1012
1.42k
        }
1013
2.62k
      }
1014
18.4k
    } ZEND_HASH_FOREACH_END();
1015
26.3k
    HT_FLAGS(&ce->properties_info) &= (HASH_FLAG_UNINITIALIZED | HASH_FLAG_STATIC_KEYS);
1016
1017
26.3k
    if (ce->properties_info_table) {
1018
7.71k
      int i;
1019
1020
7.71k
      size_t size = sizeof(zend_property_info *) * ce->default_properties_count;
1021
7.71k
      ZEND_ASSERT(ce->ce_flags & ZEND_ACC_LINKED);
1022
7.71k
      ce->properties_info_table = zend_shared_memdup(
1023
7.71k
        ce->properties_info_table, size);
1024
1025
20.7k
      for (i = 0; i < ce->default_properties_count; i++) {
1026
13.0k
        if (ce->properties_info_table[i]) {
1027
12.6k
          zend_property_info *prop_info = zend_shared_alloc_get_xlat_entry(
1028
12.6k
            ce->properties_info_table[i]);
1029
12.6k
          if (prop_info) {
1030
11.4k
            ce->properties_info_table[i] = prop_info;
1031
11.4k
          }
1032
12.6k
        }
1033
13.0k
      }
1034
7.71k
    }
1035
1036
26.3k
    if (ce->iterator_funcs_ptr) {
1037
269
      ce->iterator_funcs_ptr = zend_shared_memdup(ce->iterator_funcs_ptr, sizeof(zend_class_iterator_funcs));
1038
269
    }
1039
26.3k
    if (ce->arrayaccess_funcs_ptr) {
1040
326
      ce->arrayaccess_funcs_ptr = zend_shared_memdup(ce->arrayaccess_funcs_ptr, sizeof(zend_class_arrayaccess_funcs));
1041
326
    }
1042
1043
26.3k
    if (ce->ce_flags & ZEND_ACC_CACHED) {
1044
2.97k
      return ce;
1045
2.97k
    }
1046
1047
23.3k
    ce->ce_flags |= ZEND_ACC_CACHED;
1048
1049
23.3k
    if (ce->info.user.filename) {
1050
23.3k
      zend_accel_store_string(ce->info.user.filename);
1051
23.3k
    }
1052
1053
23.3k
    if (ce->doc_comment) {
1054
30
      if (ZCG(accel_directives).save_comments) {
1055
30
        zend_accel_store_interned_string(ce->doc_comment);
1056
30
      } else {
1057
0
        if (!zend_shared_alloc_get_xlat_entry(ce->doc_comment)) {
1058
0
          zend_shared_alloc_register_xlat_entry(ce->doc_comment, ce->doc_comment);
1059
0
          zend_string_release_ex(ce->doc_comment, 0);
1060
0
        }
1061
0
        ce->doc_comment = NULL;
1062
0
      }
1063
30
    }
1064
1065
23.3k
    if (ce->attributes) {
1066
1.19k
      ce->attributes = zend_persist_attributes(ce->attributes);
1067
1.19k
    }
1068
1069
23.3k
    if (ce->num_interfaces && !(ce->ce_flags & ZEND_ACC_LINKED)) {
1070
2.89k
      uint32_t i = 0;
1071
1072
6.46k
      for (i = 0; i < ce->num_interfaces; i++) {
1073
3.56k
        zend_accel_store_interned_string(ce->interface_names[i].name);
1074
3.56k
        zend_accel_store_interned_string(ce->interface_names[i].lc_name);
1075
3.56k
      }
1076
2.89k
      ce->interface_names = zend_shared_memdup_free(ce->interface_names, sizeof(zend_class_name) * ce->num_interfaces);
1077
2.89k
    }
1078
1079
23.3k
    if (ce->num_traits) {
1080
1.33k
      uint32_t i = 0;
1081
1082
3.01k
      for (i = 0; i < ce->num_traits; i++) {
1083
1.67k
        zend_accel_store_interned_string(ce->trait_names[i].name);
1084
1.67k
        zend_accel_store_interned_string(ce->trait_names[i].lc_name);
1085
1.67k
      }
1086
1.33k
      ce->trait_names = zend_shared_memdup_free(ce->trait_names, sizeof(zend_class_name) * ce->num_traits);
1087
1088
1.33k
      i = 0;
1089
1.33k
      if (ce->trait_aliases) {
1090
576
        while (ce->trait_aliases[i]) {
1091
378
          if (ce->trait_aliases[i]->trait_method.method_name) {
1092
378
            zend_accel_store_interned_string(ce->trait_aliases[i]->trait_method.method_name);
1093
378
          }
1094
378
          if (ce->trait_aliases[i]->trait_method.class_name) {
1095
158
            zend_accel_store_interned_string(ce->trait_aliases[i]->trait_method.class_name);
1096
158
          }
1097
1098
378
          if (ce->trait_aliases[i]->alias) {
1099
258
            zend_accel_store_interned_string(ce->trait_aliases[i]->alias);
1100
258
          }
1101
1102
378
          ce->trait_aliases[i] = zend_shared_memdup_free(ce->trait_aliases[i], sizeof(zend_trait_alias));
1103
378
          i++;
1104
378
        }
1105
1106
198
        ce->trait_aliases = zend_shared_memdup_free(ce->trait_aliases, sizeof(zend_trait_alias*) * (i + 1));
1107
198
      }
1108
1109
1.33k
      if (ce->trait_precedences) {
1110
82
        uint32_t j;
1111
1112
82
        i = 0;
1113
186
        while (ce->trait_precedences[i]) {
1114
104
          zend_accel_store_interned_string(ce->trait_precedences[i]->trait_method.method_name);
1115
104
          zend_accel_store_interned_string(ce->trait_precedences[i]->trait_method.class_name);
1116
1117
214
          for (j = 0; j < ce->trait_precedences[i]->num_excludes; j++) {
1118
110
            zend_accel_store_interned_string(ce->trait_precedences[i]->exclude_class_names[j]);
1119
110
          }
1120
1121
104
          ce->trait_precedences[i] = zend_shared_memdup_free(ce->trait_precedences[i], sizeof(zend_trait_precedence) + (ce->trait_precedences[i]->num_excludes - 1) * sizeof(zend_string*));
1122
104
          i++;
1123
104
        }
1124
82
        ce->trait_precedences = zend_shared_memdup_free(
1125
82
          ce->trait_precedences, sizeof(zend_trait_precedence*) * (i + 1));
1126
82
      }
1127
1.33k
    }
1128
1129
23.3k
    ZEND_ASSERT(ce->backed_enum_table == NULL);
1130
23.3k
  }
1131
1132
23.3k
  return ce;
1133
26.3k
}
1134
1135
void zend_update_parent_ce(zend_class_entry *ce)
1136
26.3k
{
1137
26.3k
  if (ce->ce_flags & ZEND_ACC_LINKED) {
1138
21.4k
    if (ce->parent) {
1139
3.29k
      int i, end;
1140
3.29k
      zend_class_entry *parent = ce->parent;
1141
1142
3.29k
      if (parent->type == ZEND_USER_CLASS) {
1143
2.91k
        zend_class_entry *p = zend_shared_alloc_get_xlat_entry(parent);
1144
1145
2.91k
        if (p) {
1146
2.31k
          ce->parent = parent = p;
1147
2.31k
        }
1148
2.91k
      }
1149
1150
      /* Create indirections to static properties from parent classes */
1151
3.29k
      i = parent->default_static_members_count - 1;
1152
3.53k
      while (parent && parent->default_static_members_table) {
1153
241
        end = parent->parent ? parent->parent->default_static_members_count : 0;
1154
596
        for (; i >= end; i--) {
1155
355
          zval *p = &ce->default_static_members_table[i];
1156
          /* The static property may have been overridden by a trait
1157
           * during inheritance. In that case, the property default
1158
           * value is replaced by zend_declare_typed_property() at the
1159
           * property index of the parent property. Make sure we only
1160
           * point to the parent property value if the child value was
1161
           * already indirect. */
1162
355
          if (Z_TYPE_P(p) == IS_INDIRECT) {
1163
355
            ZVAL_INDIRECT(p, &parent->default_static_members_table[i]);
1164
355
          }
1165
355
        }
1166
1167
241
        parent = parent->parent;
1168
241
      }
1169
3.29k
    }
1170
1171
21.4k
    if (ce->num_interfaces) {
1172
2.05k
      uint32_t i = 0;
1173
1174
2.05k
      ce->interfaces = zend_shared_memdup_free(ce->interfaces, sizeof(zend_class_entry*) * ce->num_interfaces);
1175
4.96k
      for (i = 0; i < ce->num_interfaces; i++) {
1176
2.91k
        if (ce->interfaces[i]->type == ZEND_USER_CLASS) {
1177
1.05k
          zend_class_entry *tmp = zend_shared_alloc_get_xlat_entry(ce->interfaces[i]);
1178
1.05k
          if (tmp != NULL) {
1179
0
            ce->interfaces[i] = tmp;
1180
0
          }
1181
1.05k
        }
1182
2.91k
      }
1183
2.05k
    }
1184
1185
21.4k
    if (ce->iterator_funcs_ptr) {
1186
269
      memset(ce->iterator_funcs_ptr, 0, sizeof(zend_class_iterator_funcs));
1187
269
      if (zend_class_implements_interface(ce, zend_ce_aggregate)) {
1188
178
        ce->iterator_funcs_ptr->zf_new_iterator = zend_hash_str_find_ptr(&ce->function_table, "getiterator", sizeof("getiterator") - 1);
1189
178
      }
1190
269
      if (zend_class_implements_interface(ce, zend_ce_iterator)) {
1191
91
        ce->iterator_funcs_ptr->zf_rewind = zend_hash_str_find_ptr(&ce->function_table, "rewind", sizeof("rewind") - 1);
1192
91
        ce->iterator_funcs_ptr->zf_valid = zend_hash_str_find_ptr(&ce->function_table, "valid", sizeof("valid") - 1);
1193
91
        ce->iterator_funcs_ptr->zf_key = zend_hash_find_ptr(&ce->function_table, ZSTR_KNOWN(ZEND_STR_KEY));
1194
91
        ce->iterator_funcs_ptr->zf_current = zend_hash_str_find_ptr(&ce->function_table, "current", sizeof("current") - 1);
1195
91
        ce->iterator_funcs_ptr->zf_next = zend_hash_str_find_ptr(&ce->function_table, "next", sizeof("next") - 1);
1196
91
      }
1197
269
    }
1198
1199
21.4k
    if (ce->arrayaccess_funcs_ptr) {
1200
326
      ZEND_ASSERT(zend_class_implements_interface(ce, zend_ce_arrayaccess));
1201
326
      ce->arrayaccess_funcs_ptr->zf_offsetget = zend_hash_str_find_ptr(&ce->function_table, "offsetget", sizeof("offsetget") - 1);
1202
326
      ce->arrayaccess_funcs_ptr->zf_offsetexists = zend_hash_str_find_ptr(&ce->function_table, "offsetexists", sizeof("offsetexists") - 1);
1203
326
      ce->arrayaccess_funcs_ptr->zf_offsetset = zend_hash_str_find_ptr(&ce->function_table, "offsetset", sizeof("offsetset") - 1);
1204
326
      ce->arrayaccess_funcs_ptr->zf_offsetunset = zend_hash_str_find_ptr(&ce->function_table, "offsetunset", sizeof("offsetunset") - 1);
1205
326
    }
1206
21.4k
  }
1207
1208
  /* update methods */
1209
26.3k
  if (ce->constructor) {
1210
3.74k
    zend_function *tmp = zend_shared_alloc_get_xlat_entry(ce->constructor);
1211
3.74k
    if (tmp != NULL) {
1212
3.57k
      ce->constructor = tmp;
1213
3.57k
    }
1214
3.74k
  }
1215
26.3k
  if (ce->destructor) {
1216
1.66k
    zend_function *tmp = zend_shared_alloc_get_xlat_entry(ce->destructor);
1217
1.66k
    if (tmp != NULL) {
1218
1.66k
      ce->destructor = tmp;
1219
1.66k
    }
1220
1.66k
  }
1221
26.3k
  if (ce->clone) {
1222
364
    zend_function *tmp = zend_shared_alloc_get_xlat_entry(ce->clone);
1223
364
    if (tmp != NULL) {
1224
236
      ce->clone = tmp;
1225
236
    }
1226
364
  }
1227
26.3k
  if (ce->__get) {
1228
957
    zend_function *tmp = zend_shared_alloc_get_xlat_entry(ce->__get);
1229
957
    if (tmp != NULL) {
1230
957
      ce->__get = tmp;
1231
957
    }
1232
957
  }
1233
26.3k
  if (ce->__set) {
1234
680
    zend_function *tmp = zend_shared_alloc_get_xlat_entry(ce->__set);
1235
680
    if (tmp != NULL) {
1236
680
      ce->__set = tmp;
1237
680
    }
1238
680
  }
1239
26.3k
  if (ce->__call) {
1240
620
    zend_function *tmp = zend_shared_alloc_get_xlat_entry(ce->__call);
1241
620
    if (tmp != NULL) {
1242
620
      ce->__call = tmp;
1243
620
    }
1244
620
  }
1245
26.3k
  if (ce->__serialize) {
1246
186
    zend_function *tmp = zend_shared_alloc_get_xlat_entry(ce->__serialize);
1247
186
    if (tmp != NULL) {
1248
60
      ce->__serialize = tmp;
1249
60
    }
1250
186
  }
1251
26.3k
  if (ce->__unserialize) {
1252
174
    zend_function *tmp = zend_shared_alloc_get_xlat_entry(ce->__unserialize);
1253
174
    if (tmp != NULL) {
1254
48
      ce->__unserialize = tmp;
1255
48
    }
1256
174
  }
1257
26.3k
  if (ce->__isset) {
1258
338
    zend_function *tmp = zend_shared_alloc_get_xlat_entry(ce->__isset);
1259
338
    if (tmp != NULL) {
1260
338
      ce->__isset = tmp;
1261
338
    }
1262
338
  }
1263
26.3k
  if (ce->__unset) {
1264
148
    zend_function *tmp = zend_shared_alloc_get_xlat_entry(ce->__unset);
1265
148
    if (tmp != NULL) {
1266
148
      ce->__unset = tmp;
1267
148
    }
1268
148
  }
1269
26.3k
  if (ce->__tostring) {
1270
1.09k
    zend_function *tmp = zend_shared_alloc_get_xlat_entry(ce->__tostring);
1271
1.09k
    if (tmp != NULL) {
1272
972
      ce->__tostring = tmp;
1273
972
    }
1274
1.09k
  }
1275
26.3k
  if (ce->__callstatic) {
1276
370
    zend_function *tmp = zend_shared_alloc_get_xlat_entry(ce->__callstatic);
1277
370
    if (tmp != NULL) {
1278
370
      ce->__callstatic = tmp;
1279
370
    }
1280
370
  }
1281
26.3k
  if (ce->__debugInfo) {
1282
156
    zend_function *tmp = zend_shared_alloc_get_xlat_entry(ce->__debugInfo);
1283
156
    if (tmp != NULL) {
1284
110
      ce->__debugInfo = tmp;
1285
110
    }
1286
156
  }
1287
26.3k
}
1288
1289
#ifdef HAVE_JIT
1290
static void zend_accel_persist_jit_op_array(zend_op_array *op_array, const zend_class_entry *ce)
1291
0
{
1292
0
  if (op_array->type == ZEND_USER_FUNCTION) {
1293
0
    if (op_array->scope == ce
1294
0
     && !(op_array->fn_flags & ZEND_ACC_ABSTRACT)
1295
0
     && !(op_array->fn_flags & ZEND_ACC_TRAIT_CLONE)) {
1296
0
      zend_jit_op_array(op_array, ZCG(current_persistent_script) ? &ZCG(current_persistent_script)->script : NULL);
1297
0
      for (uint32_t i = 0; i < op_array->num_dynamic_func_defs; i++) {
1298
0
        zend_jit_op_array(op_array->dynamic_func_defs[i], ZCG(current_persistent_script) ? &ZCG(current_persistent_script)->script : NULL);
1299
0
      }
1300
0
    }
1301
0
  }
1302
0
}
1303
1304
static void zend_accel_persist_link_func_info(zend_op_array *op_array, const zend_class_entry *ce)
1305
0
{
1306
0
  if (op_array->type == ZEND_USER_FUNCTION
1307
0
   && !(op_array->fn_flags & ZEND_ACC_ABSTRACT)) {
1308
0
    if ((op_array->scope != ce
1309
0
     || (op_array->fn_flags & ZEND_ACC_TRAIT_CLONE))
1310
0
      && (JIT_G(trigger) == ZEND_JIT_ON_FIRST_EXEC
1311
0
      || JIT_G(trigger) == ZEND_JIT_ON_PROF_REQUEST
1312
0
      || JIT_G(trigger) == ZEND_JIT_ON_HOT_COUNTERS
1313
0
      || JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE)) {
1314
0
      void *jit_extension = zend_shared_alloc_get_xlat_entry(op_array->opcodes);
1315
1316
0
      if (jit_extension) {
1317
0
        ZEND_SET_FUNC_INFO(op_array, jit_extension);
1318
0
      }
1319
0
    }
1320
0
  }
1321
0
}
1322
#endif
1323
1324
static void zend_accel_persist_class_table(HashTable *class_table)
1325
49.4k
{
1326
49.4k
  Bucket *p;
1327
49.4k
  zend_class_entry *ce;
1328
49.4k
#ifdef HAVE_JIT
1329
49.4k
  bool orig_jit_on = JIT_G(on);
1330
1331
49.4k
  JIT_G(on) = 0;
1332
49.4k
#endif
1333
49.4k
  zend_hash_persist(class_table);
1334
145k
  ZEND_HASH_MAP_FOREACH_BUCKET(class_table, p) {
1335
145k
    ZEND_ASSERT(p->key != NULL);
1336
145k
    zend_accel_store_interned_string(p->key);
1337
23.3k
    Z_CE(p->val) = zend_persist_class_entry(Z_CE(p->val));
1338
23.3k
  } ZEND_HASH_FOREACH_END();
1339
145k
  ZEND_HASH_MAP_FOREACH_BUCKET(class_table, p) {
1340
145k
    if (EXPECTED(Z_TYPE(p->val) != IS_ALIAS_PTR)) {
1341
23.3k
      ce = Z_PTR(p->val);
1342
23.3k
      zend_update_parent_ce(ce);
1343
23.3k
    }
1344
145k
  } ZEND_HASH_FOREACH_END();
1345
49.4k
#ifdef HAVE_JIT
1346
49.4k
  JIT_G(on) = orig_jit_on;
1347
49.4k
  if (JIT_G(on) && JIT_G(opt_level) <= ZEND_JIT_LEVEL_OPT_FUNCS &&
1348
0
      !ZCG(current_persistent_script)->corrupted) {
1349
0
      zend_op_array *op_array;
1350
0
    zend_property_info *prop;
1351
1352
0
      ZEND_HASH_MAP_FOREACH_BUCKET(class_table, p) {
1353
0
      if (EXPECTED(Z_TYPE(p->val) != IS_ALIAS_PTR)) {
1354
0
        ce = Z_PTR(p->val);
1355
0
        ZEND_HASH_MAP_FOREACH_PTR(&ce->function_table, op_array) {
1356
0
          zend_accel_persist_jit_op_array(op_array, ce);
1357
0
        } ZEND_HASH_FOREACH_END();
1358
1359
0
        if (ce->num_hooked_props > 0) {
1360
0
          ZEND_HASH_MAP_FOREACH_PTR(&ce->properties_info, prop) {
1361
0
            if (prop->hooks) {
1362
0
              for (uint32_t i = 0; i < ZEND_PROPERTY_HOOK_COUNT; i++) {
1363
0
                if (prop->hooks[i]) {
1364
0
                  op_array = &prop->hooks[i]->op_array;
1365
0
                  zend_accel_persist_jit_op_array(op_array, ce);
1366
0
                }
1367
0
              }
1368
0
            }
1369
0
          } ZEND_HASH_FOREACH_END();
1370
0
        }
1371
0
      }
1372
0
    } ZEND_HASH_FOREACH_END();
1373
0
      ZEND_HASH_MAP_FOREACH_BUCKET(class_table, p) {
1374
0
      if (EXPECTED(Z_TYPE(p->val) != IS_ALIAS_PTR)) {
1375
0
        ce = Z_PTR(p->val);
1376
0
        ZEND_HASH_MAP_FOREACH_PTR(&ce->function_table, op_array) {
1377
0
          zend_accel_persist_link_func_info(op_array, ce);
1378
0
        } ZEND_HASH_FOREACH_END();
1379
1380
0
        if (ce->num_hooked_props > 0) {
1381
0
          ZEND_HASH_MAP_FOREACH_PTR(&ce->properties_info, prop) {
1382
0
            if (prop->hooks) {
1383
0
              for (uint32_t i = 0; i < ZEND_PROPERTY_HOOK_COUNT; i++) {
1384
0
                if (prop->hooks[i]) {
1385
0
                  op_array = &prop->hooks[i]->op_array;
1386
0
                  zend_accel_persist_link_func_info(op_array, ce);
1387
0
                }
1388
0
              }
1389
0
            }
1390
0
          } ZEND_HASH_FOREACH_END();
1391
0
        }
1392
0
      }
1393
0
    } ZEND_HASH_FOREACH_END();
1394
0
  }
1395
49.4k
#endif
1396
49.4k
}
1397
1398
52.4k
zend_error_info **zend_persist_warnings(uint32_t num_warnings, zend_error_info **warnings) {
1399
52.4k
  if (warnings) {
1400
52
    warnings = zend_shared_memdup(warnings, num_warnings * sizeof(zend_error_info *));
1401
106
    for (uint32_t i = 0; i < num_warnings; i++) {
1402
54
      zend_accel_store_string(warnings[i]->filename);
1403
54
      zend_accel_store_string(warnings[i]->message);
1404
54
      warnings[i] = zend_shared_memdup(warnings[i], sizeof(zend_error_info));
1405
54
    }
1406
52
  }
1407
52.4k
  return warnings;
1408
52.4k
}
1409
1410
static zend_early_binding *zend_persist_early_bindings(
1411
49.4k
    uint32_t num_early_bindings, zend_early_binding *early_bindings) {
1412
49.4k
  if (early_bindings) {
1413
459
    early_bindings = zend_shared_memdup_free(
1414
459
      early_bindings, num_early_bindings * sizeof(zend_early_binding));
1415
1.76k
    for (uint32_t i = 0; i < num_early_bindings; i++) {
1416
1.30k
      zend_accel_store_interned_string(early_bindings[i].lcname);
1417
1.30k
      zend_accel_store_interned_string(early_bindings[i].rtd_key);
1418
1.30k
      zend_accel_store_interned_string(early_bindings[i].lc_parent_name);
1419
1.30k
    }
1420
459
  }
1421
49.4k
  return early_bindings;
1422
49.4k
}
1423
1424
zend_persistent_script *zend_accel_script_persist(zend_persistent_script *script, bool for_shm)
1425
49.4k
{
1426
49.4k
  Bucket *p;
1427
1428
49.4k
  script->mem = ZCG(mem);
1429
1430
49.4k
  ZEND_ASSERT(((uintptr_t)ZCG(mem) & 0x7) == 0); /* should be 8 byte aligned */
1431
1432
49.4k
  script = zend_shared_memdup_free(script, sizeof(zend_persistent_script));
1433
49.4k
  script->corrupted = false;
1434
49.4k
  ZCG(current_persistent_script) = script;
1435
1436
49.4k
  if (!for_shm) {
1437
    /* script is not going to be saved in SHM */
1438
0
    script->corrupted = true;
1439
0
  }
1440
1441
49.4k
  zend_accel_store_interned_string(script->script.filename);
1442
1443
49.4k
#if defined(__AVX__) || defined(__SSE2__)
1444
  /* Align to 64-byte boundary */
1445
49.4k
  ZCG(mem) = (void*)(((uintptr_t)ZCG(mem) + 63L) & ~63L);
1446
#else
1447
  ZEND_ASSERT(((uintptr_t)ZCG(mem) & 0x7) == 0); /* should be 8 byte aligned */
1448
#endif
1449
1450
49.4k
#ifdef HAVE_JIT
1451
49.4k
  if (JIT_G(on) && for_shm) {
1452
0
    zend_jit_unprotect();
1453
0
  }
1454
49.4k
#endif
1455
1456
49.4k
  zend_map_ptr_extend(ZCSG(map_ptr_last));
1457
1458
49.4k
  zend_accel_persist_class_table(&script->script.class_table);
1459
49.4k
  zend_hash_persist(&script->script.function_table);
1460
126k
  ZEND_HASH_MAP_FOREACH_BUCKET(&script->script.function_table, p) {
1461
126k
    ZEND_ASSERT(p->key != NULL);
1462
126k
    zend_accel_store_interned_string(p->key);
1463
13.7k
    zend_persist_op_array(&p->val);
1464
13.7k
  } ZEND_HASH_FOREACH_END();
1465
49.4k
  zend_persist_op_array_ex(&script->script.main_op_array, script);
1466
49.4k
  if (!script->corrupted) {
1467
49.4k
    ZEND_MAP_PTR_INIT(script->script.main_op_array.run_time_cache, NULL);
1468
49.4k
    if (script->script.main_op_array.static_variables) {
1469
44
      ZEND_MAP_PTR_NEW(script->script.main_op_array.static_variables_ptr);
1470
44
    }
1471
49.4k
#ifdef HAVE_JIT
1472
49.4k
    if (JIT_G(on) && JIT_G(opt_level) <= ZEND_JIT_LEVEL_OPT_FUNCS) {
1473
0
      zend_jit_op_array(&script->script.main_op_array, &script->script);
1474
0
    }
1475
49.4k
#endif
1476
49.4k
  }
1477
49.4k
  script->warnings = zend_persist_warnings(script->num_warnings, script->warnings);
1478
49.4k
  script->early_bindings = zend_persist_early_bindings(
1479
49.4k
    script->num_early_bindings, script->early_bindings);
1480
1481
49.4k
  if (for_shm) {
1482
49.4k
    ZCSG(map_ptr_last) = CG(map_ptr_last);
1483
49.4k
    ZCSG(map_ptr_static_last) = zend_map_ptr_static_last;
1484
49.4k
  }
1485
1486
49.4k
#ifdef HAVE_JIT
1487
49.4k
  if (JIT_G(on) && for_shm) {
1488
0
    if (JIT_G(opt_level) >= ZEND_JIT_LEVEL_OPT_SCRIPT) {
1489
0
      zend_jit_script(&script->script);
1490
0
    }
1491
0
    zend_jit_protect();
1492
0
  }
1493
49.4k
#endif
1494
1495
49.4k
  script->corrupted = false;
1496
49.4k
  ZCG(current_persistent_script) = NULL;
1497
1498
49.4k
  return script;
1499
49.4k
}