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