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