xref: /PHP-7.4/ext/opcache/zend_persist.c (revision e576d342)
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(&copy->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