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