Coverage Report

Created: 2025-11-16 06:23

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