Coverage Report

Created: 2026-10-28 06:20

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