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