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