Coverage Report

Created: 2026-07-25 06:39

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