xref: /PHP-5.6/ext/opcache/zend_persist.c (revision 49493a2d)
1 /*
2    +----------------------------------------------------------------------+
3    | Zend OPcache                                                         |
4    +----------------------------------------------------------------------+
5    | Copyright (c) 1998-2016 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@zend.com>                                |
16    |          Zeev Suraski <zeev@zend.com>                                |
17    |          Stanislav Malyshev <stas@zend.com>                          |
18    |          Dmitry Stogov <dmitry@zend.com>                             |
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 
31 #define zend_accel_store(p, size) \
32 	    (p = _zend_shared_memdup((void*)p, size, 1 TSRMLS_CC))
33 #define zend_accel_memdup(p, size) \
34 	    _zend_shared_memdup((void*)p, size, 0 TSRMLS_CC)
35 
36 #if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
37 # define zend_accel_memdup_interned_string(str, len) \
38 	IS_INTERNED(str) ? str : zend_accel_memdup(str, len)
39 
40 # define zend_accel_store_interned_string(str, len) do { \
41 		if (!IS_INTERNED(str)) { zend_accel_store(str, len); } \
42 	} while (0)
43 #else
44 # define zend_accel_memdup_interned_string(str, len) \
45 	zend_accel_memdup(str, len)
46 
47 # define zend_accel_store_interned_string(str, len) \
48 	zend_accel_store(str, len)
49 #endif
50 
51 typedef void (*zend_persist_func_t)(void * TSRMLS_DC);
52 
53 static void zend_persist_zval_ptr(zval **zp TSRMLS_DC);
54 static void zend_persist_zval(zval *z TSRMLS_DC);
55 
56 #if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
57 static const Bucket *uninitialized_bucket = NULL;
58 #endif
59 
zend_hash_persist(HashTable * ht,void (* pPersistElement)(void * pElement TSRMLS_DC),size_t el_size TSRMLS_DC)60 static void zend_hash_persist(HashTable *ht, void (*pPersistElement)(void *pElement TSRMLS_DC), size_t el_size TSRMLS_DC)
61 {
62 	Bucket *p = ht->pListHead;
63 	uint i;
64 
65 	while (p) {
66 		Bucket *q = p;
67 
68 		/* persist bucket and key */
69 #if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
70 		p = zend_accel_memdup(p, sizeof(Bucket));
71 		if (p->nKeyLength) {
72 			p->arKey = zend_accel_memdup_interned_string(p->arKey, p->nKeyLength);
73 		}
74 #else
75 		p = zend_accel_memdup(p, sizeof(Bucket) - 1 + p->nKeyLength);
76 #endif
77 
78 		/* persist data pointer in bucket */
79 		if (!p->pDataPtr) {
80 			zend_accel_store(p->pData, el_size);
81 		} else {
82 			/* Update p->pData to point to the new p->pDataPtr address, after the bucket relocation */
83 			p->pData = &p->pDataPtr;
84 		}
85 
86 		/* persist the data itself */
87 		if (pPersistElement) {
88 			pPersistElement(p->pData TSRMLS_CC);
89 		}
90 
91 		/* update linked lists */
92 		if (p->pLast) {
93 			p->pLast->pNext = p;
94 		}
95 		if (p->pNext) {
96 			p->pNext->pLast = p;
97 		}
98 		if (p->pListLast) {
99 			p->pListLast->pListNext = p;
100 		}
101 		if (p->pListNext) {
102 			p->pListNext->pListLast = p;
103 		}
104 
105 		p = p->pListNext;
106 
107 		/* delete the old non-persistent bucket */
108 		efree(q);
109 	}
110 
111 	/* update linked lists */
112 	if (ht->pListHead) {
113 		ht->pListHead = zend_shared_alloc_get_xlat_entry(ht->pListHead);
114 	}
115 	if (ht->pListTail) {
116 		ht->pListTail = zend_shared_alloc_get_xlat_entry(ht->pListTail);
117 	}
118 	if (ht->pInternalPointer) {
119 		ht->pInternalPointer = zend_shared_alloc_get_xlat_entry(ht->pInternalPointer);
120 	}
121 
122 #if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
123 	/* Check if HastTable is initialized */
124 	if (ht->nTableMask) {
125 #endif
126 		if (ht->nNumOfElements) {
127 			/* update hash table */
128 			for (i = 0; i < ht->nTableSize; i++) {
129 				if (ht->arBuckets[i]) {
130 					ht->arBuckets[i] = zend_shared_alloc_get_xlat_entry(ht->arBuckets[i]);
131 				}
132 			}
133 		}
134 		zend_accel_store(ht->arBuckets, sizeof(Bucket*) * ht->nTableSize);
135 #if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
136 	} else {
137 		ht->arBuckets = (Bucket**)&uninitialized_bucket;
138 	}
139 #endif
140 }
141 
142 #if ZEND_EXTENSION_API_NO > PHP_5_5_X_API_NO
zend_persist_ast(zend_ast * ast TSRMLS_DC)143 static zend_ast *zend_persist_ast(zend_ast *ast TSRMLS_DC)
144 {
145 	int i;
146 	zend_ast *node;
147 
148 	if (ast->kind == ZEND_CONST) {
149 		node = zend_accel_memdup(ast, sizeof(zend_ast) + sizeof(zval));
150 		node->u.val = (zval*)(node + 1);
151 		zend_persist_zval(node->u.val TSRMLS_CC);
152 	} else {
153 		node = zend_accel_memdup(ast, sizeof(zend_ast) + sizeof(zend_ast*) * (ast->children - 1));
154 		for (i = 0; i < ast->children; i++) {
155 			if ((&node->u.child)[i]) {
156 				(&node->u.child)[i] = zend_persist_ast((&node->u.child)[i] TSRMLS_CC);
157 			}
158 		}
159 	}
160 	efree(ast);
161 	return node;
162 }
163 #endif
164 
zend_persist_zval(zval * z TSRMLS_DC)165 static void zend_persist_zval(zval *z TSRMLS_DC)
166 {
167 #if ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO
168 	switch (z->type & IS_CONSTANT_TYPE_MASK) {
169 #else
170 	switch (z->type & ~IS_CONSTANT_INDEX) {
171 #endif
172 		case IS_STRING:
173 		case IS_CONSTANT:
174 			zend_accel_store_interned_string(z->value.str.val, z->value.str.len + 1);
175 			break;
176 		case IS_ARRAY:
177 #if ZEND_EXTENSION_API_NO <= PHP_5_5_API_NO
178 		case IS_CONSTANT_ARRAY:
179 #endif
180 			zend_accel_store(z->value.ht, sizeof(HashTable));
181 			zend_hash_persist(z->value.ht, (zend_persist_func_t) zend_persist_zval_ptr, sizeof(zval**) TSRMLS_CC);
182 			break;
183 #if ZEND_EXTENSION_API_NO > PHP_5_5_X_API_NO
184 		case IS_CONSTANT_AST:
185 			Z_AST_P(z) = zend_persist_ast(Z_AST_P(z) TSRMLS_CC);
186 			break;
187 #endif
188 	}
189 }
190 
191 static void zend_persist_zval_ptr(zval **zp TSRMLS_DC)
192 {
193 	zval *new_ptr = zend_shared_alloc_get_xlat_entry(*zp);
194 
195 	if (new_ptr) {
196 		*zp = new_ptr;
197 	} else {
198 		/* Attempt to store only if we didn't store this zval_ptr yet */
199 		zend_accel_store(*zp, sizeof(zval));
200 		zend_persist_zval(*zp TSRMLS_CC);
201 	}
202 }
203 
204 static void zend_protect_zval(zval *z TSRMLS_DC)
205 {
206 	PZ_SET_ISREF_P(z);
207 	PZ_SET_REFCOUNT_P(z, 2);
208 }
209 
210 static void zend_persist_op_array_ex(zend_op_array *op_array, zend_persistent_script* main_persistent_script TSRMLS_DC)
211 {
212 	zend_op *persist_ptr;
213 #if ZEND_EXTENSION_API_NO < PHP_5_3_X_API_NO
214 	int has_jmp = 0;
215 #endif
216 #if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
217 	zend_literal *orig_literals = NULL;
218 #endif
219 
220 	if (op_array->type != ZEND_USER_FUNCTION) {
221 		return;
222 	}
223 
224 #if ZEND_EXTENSION_API_NO <= PHP_5_3_X_API_NO
225 	op_array->size = op_array->last;
226 #endif
227 
228 	if (--(*op_array->refcount) == 0) {
229 		efree(op_array->refcount);
230 	}
231 	op_array->refcount = NULL;
232 
233 	if (op_array->filename) {
234 		/* do not free! PHP has centralized filename storage, compiler will free it */
235 		op_array->filename = zend_accel_memdup(op_array->filename, strlen(op_array->filename) + 1);
236 	}
237 
238 	if (main_persistent_script) {
239 		zend_bool orig_in_execution = EG(in_execution);
240 		zend_op_array *orig_op_array = EG(active_op_array);
241 		zval offset;
242 
243 #if ZEND_EXTENSION_API_NO < PHP_5_3_X_API_NO
244 		main_persistent_script->early_binding = -1;
245 #endif
246 		EG(in_execution) = 1;
247 		EG(active_op_array) = op_array;
248 		if (zend_get_constant("__COMPILER_HALT_OFFSET__", sizeof("__COMPILER_HALT_OFFSET__") - 1, &offset TSRMLS_CC)) {
249 			main_persistent_script->compiler_halt_offset = Z_LVAL(offset);
250 		}
251 		EG(active_op_array) = orig_op_array;
252 		EG(in_execution) = orig_in_execution;
253 	}
254 
255 #if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
256 	if (op_array->literals) {
257 		orig_literals = zend_shared_alloc_get_xlat_entry(op_array->literals);
258 		if (orig_literals) {
259 			op_array->literals = orig_literals;
260 		} else {
261 			zend_literal *p = zend_accel_memdup(op_array->literals, sizeof(zend_literal) * op_array->last_literal);
262 			zend_literal *end = p + op_array->last_literal;
263 			orig_literals = op_array->literals;
264 			op_array->literals = p;
265 			while (p < end) {
266 				zend_persist_zval(&p->constant TSRMLS_CC);
267 				zend_protect_zval(&p->constant TSRMLS_CC);
268 				p++;
269 			}
270 			efree(orig_literals);
271 		}
272 	}
273 #endif
274 
275 	if ((persist_ptr = zend_shared_alloc_get_xlat_entry(op_array->opcodes))) {
276 		op_array->opcodes = persist_ptr;
277 	} else {
278 		zend_op *new_opcodes = zend_accel_memdup(op_array->opcodes, sizeof(zend_op) * op_array->last);
279 		zend_op *opline = new_opcodes;
280 		zend_op *end = new_opcodes + op_array->last;
281 		int offset = 0;
282 
283 		for (; opline < end ; opline++, offset++) {
284 			if (ZEND_OP1_TYPE(opline) == IS_CONST) {
285 #if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
286 				opline->op1.zv = (zval*)((char*)opline->op1.zv + ((char*)op_array->literals - (char*)orig_literals));
287 #else
288 				zend_persist_zval(&opline->op1.u.constant TSRMLS_CC);
289 				zend_protect_zval(&opline->op1.u.constant TSRMLS_CC);
290 #endif
291 			}
292 			if (ZEND_OP2_TYPE(opline) == IS_CONST) {
293 #if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
294 				opline->op2.zv = (zval*)((char*)opline->op2.zv + ((char*)op_array->literals - (char*)orig_literals));
295 #else
296 				zend_persist_zval(&opline->op2.u.constant TSRMLS_CC);
297 				zend_protect_zval(&opline->op2.u.constant TSRMLS_CC);
298 #endif
299 			}
300 
301 #if ZEND_EXTENSION_API_NO < PHP_5_3_X_API_NO
302 			switch (opline->opcode) {
303 				case ZEND_JMP:
304 					has_jmp = 1;
305 					if (ZEND_DONE_PASS_TWO(op_array)) {
306 						ZEND_OP1(opline).jmp_addr = &new_opcodes[ZEND_OP1(opline).jmp_addr - op_array->opcodes];
307 					}
308 					break;
309 				case ZEND_JMPZ:
310 				case ZEND_JMPNZ:
311 				case ZEND_JMPZ_EX:
312 				case ZEND_JMPNZ_EX:
313 					has_jmp = 1;
314 					if (ZEND_DONE_PASS_TWO(op_array)) {
315 						ZEND_OP2(opline).jmp_addr = &new_opcodes[ZEND_OP2(opline).jmp_addr - op_array->opcodes];
316 					}
317 					break;
318 				case ZEND_JMPZNZ:
319 				case ZEND_BRK:
320 				case ZEND_CONT:
321 					has_jmp = 1;
322 					break;
323 				case ZEND_DECLARE_INHERITED_CLASS:
324 					if (main_persistent_script && ZCG(accel_directives).inherited_hack) {
325 					if (!has_jmp &&
326 					   ((opline + 2) >= end ||
327 					    (opline + 1)->opcode != ZEND_FETCH_CLASS ||
328 					    (opline + 2)->opcode != ZEND_ADD_INTERFACE)) {
329 
330 						zend_uint *opline_num = &main_persistent_script->early_binding;
331 
332 						while ((int)*opline_num != -1) {
333 							opline_num = &new_opcodes[*opline_num].result.u.opline_num;
334 						}
335 						*opline_num = opline - new_opcodes;
336 						opline->result.op_type = IS_UNUSED;
337 						opline->result.u.opline_num = -1;
338 						opline->opcode = ZEND_DECLARE_INHERITED_CLASS_DELAYED;
339 						ZEND_VM_SET_OPCODE_HANDLER(opline);
340 					}
341 					break;
342 				}
343 			}
344 
345 #else /* if ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO */
346 
347 			if (ZEND_DONE_PASS_TWO(op_array)) {
348 				/* fix jumps to point to new array */
349 				switch (opline->opcode) {
350 					case ZEND_JMP:
351 					case ZEND_GOTO:
352 #if ZEND_EXTENSION_API_NO > PHP_5_4_X_API_NO
353 					case ZEND_FAST_CALL:
354 #endif
355 						ZEND_OP1(opline).jmp_addr = &new_opcodes[ZEND_OP1(opline).jmp_addr - op_array->opcodes];
356 						break;
357 					case ZEND_JMPZ:
358 					case ZEND_JMPNZ:
359 					case ZEND_JMPZ_EX:
360 					case ZEND_JMPNZ_EX:
361 					case ZEND_JMP_SET:
362 #if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
363 					case ZEND_JMP_SET_VAR:
364 #endif
365 						ZEND_OP2(opline).jmp_addr = &new_opcodes[ZEND_OP2(opline).jmp_addr - op_array->opcodes];
366 						break;
367 				}
368 			}
369 #endif /* if ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO */
370 		}
371 
372 		efree(op_array->opcodes);
373 		op_array->opcodes = new_opcodes;
374 
375 #if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
376 		if (op_array->run_time_cache) {
377 			efree(op_array->run_time_cache);
378 			op_array->run_time_cache = NULL;
379 		}
380 #endif
381 	}
382 
383 	if (op_array->function_name) {
384 		char *new_name;
385 		if ((new_name = zend_shared_alloc_get_xlat_entry(op_array->function_name))) {
386 			op_array->function_name = new_name;
387 		} else {
388 			zend_accel_store(op_array->function_name, strlen(op_array->function_name) + 1);
389 		}
390 	}
391 
392 	if (op_array->arg_info) {
393 		zend_arg_info *new_ptr;
394 		if ((new_ptr = zend_shared_alloc_get_xlat_entry(op_array->arg_info))) {
395 			op_array->arg_info = new_ptr;
396 		} else {
397 			zend_uint i;
398 
399 			zend_accel_store(op_array->arg_info, sizeof(zend_arg_info) * op_array->num_args);
400 			for (i = 0; i < op_array->num_args; i++) {
401 				if (op_array->arg_info[i].name) {
402 					zend_accel_store_interned_string(op_array->arg_info[i].name, op_array->arg_info[i].name_len + 1);
403 				}
404 				if (op_array->arg_info[i].class_name) {
405 					zend_accel_store_interned_string(op_array->arg_info[i].class_name, op_array->arg_info[i].class_name_len + 1);
406 				}
407 			}
408 		}
409 	}
410 
411 	if (op_array->brk_cont_array) {
412 		zend_accel_store(op_array->brk_cont_array, sizeof(zend_brk_cont_element) * op_array->last_brk_cont);
413 	}
414 
415 	if (op_array->static_variables) {
416 		zend_hash_persist(op_array->static_variables, (zend_persist_func_t) zend_persist_zval_ptr, sizeof(zval**) TSRMLS_CC);
417 		zend_accel_store(op_array->static_variables, sizeof(HashTable));
418 	}
419 
420 	if (op_array->scope) {
421 		op_array->scope = zend_shared_alloc_get_xlat_entry(op_array->scope);
422 	}
423 
424 	if (op_array->doc_comment) {
425 		if (ZCG(accel_directives).save_comments) {
426 			zend_accel_store(op_array->doc_comment, op_array->doc_comment_len + 1);
427 		} else {
428 			if (!zend_shared_alloc_get_xlat_entry(op_array->doc_comment)) {
429 				zend_shared_alloc_register_xlat_entry(op_array->doc_comment, op_array->doc_comment);
430 				efree((char*)op_array->doc_comment);
431 			}
432 			op_array->doc_comment = NULL;
433 			op_array->doc_comment_len = 0;
434 		}
435 	}
436 
437 	if (op_array->try_catch_array) {
438 		zend_accel_store(op_array->try_catch_array, sizeof(zend_try_catch_element) * op_array->last_try_catch);
439 	}
440 
441 	if (op_array->vars) {
442 		if ((persist_ptr = zend_shared_alloc_get_xlat_entry(op_array->vars))) {
443 			op_array->vars = (zend_compiled_variable*)persist_ptr;
444 		} else {
445 			int i;
446 			zend_accel_store(op_array->vars, sizeof(zend_compiled_variable) * op_array->last_var);
447 			for (i = 0; i < op_array->last_var; i++) {
448 				zend_accel_store_interned_string(op_array->vars[i].name, op_array->vars[i].name_len + 1);
449 			}
450 		}
451 	}
452 
453 	/* "prototype" may be undefined if "scope" isn't set */
454 	if (op_array->scope && op_array->prototype) {
455 		if ((persist_ptr = zend_shared_alloc_get_xlat_entry(op_array->prototype))) {
456 			op_array->prototype = (union _zend_function*)persist_ptr;
457 			/* we use refcount to show that op_array is referenced from several places */
458 			op_array->prototype->op_array.refcount++;
459 		}
460 	} else {
461 		op_array->prototype = NULL;
462 	}
463 }
464 
465 static void zend_persist_op_array(zend_op_array *op_array TSRMLS_DC)
466 {
467 	zend_persist_op_array_ex(op_array, NULL TSRMLS_CC);
468 }
469 
470 static void zend_persist_property_info(zend_property_info *prop TSRMLS_DC)
471 {
472 	zend_accel_store_interned_string(prop->name, prop->name_length + 1);
473 	if (prop->doc_comment) {
474 		if (ZCG(accel_directives).save_comments) {
475 			zend_accel_store(prop->doc_comment, prop->doc_comment_len + 1);
476 		} else {
477 			if (!zend_shared_alloc_get_xlat_entry(prop->doc_comment)) {
478 				zend_shared_alloc_register_xlat_entry(prop->doc_comment, prop->doc_comment);
479 				efree((char*)prop->doc_comment);
480 			}
481 			prop->doc_comment = NULL;
482 			prop->doc_comment_len = 0;
483 		}
484 	}
485 }
486 
487 static void zend_persist_class_entry(zend_class_entry **pce TSRMLS_DC)
488 {
489 	zend_class_entry *ce = *pce;
490 
491 	if (ce->type == ZEND_USER_CLASS) {
492 		*pce = zend_accel_store(ce, sizeof(zend_class_entry));
493 		zend_accel_store_interned_string(ce->name, ce->name_length + 1);
494 		zend_hash_persist(&ce->function_table, (zend_persist_func_t) zend_persist_op_array, sizeof(zend_op_array) TSRMLS_CC);
495 #if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
496 		if (ce->default_properties_table) {
497 		    int i;
498 
499 			zend_accel_store(ce->default_properties_table, sizeof(zval*) * ce->default_properties_count);
500 			for (i = 0; i < ce->default_properties_count; i++) {
501 				if (ce->default_properties_table[i]) {
502 					zend_persist_zval_ptr(&ce->default_properties_table[i] TSRMLS_CC);
503 				}
504 			}
505 		}
506 		if (ce->default_static_members_table) {
507 		    int i;
508 
509 			zend_accel_store(ce->default_static_members_table, sizeof(zval*) * ce->default_static_members_count);
510 			for (i = 0; i < ce->default_static_members_count; i++) {
511 				if (ce->default_static_members_table[i]) {
512 					zend_persist_zval_ptr(&ce->default_static_members_table[i] TSRMLS_CC);
513 				}
514 			}
515 		}
516 		ce->static_members_table = NULL;
517 #else
518 		zend_hash_persist(&ce->default_properties, (zend_persist_func_t) zend_persist_zval_ptr, sizeof(zval**) TSRMLS_CC);
519 		zend_hash_persist(&ce->default_static_members, (zend_persist_func_t) zend_persist_zval_ptr, sizeof(zval**) TSRMLS_CC);
520 		ce->static_members = NULL;
521 #endif
522 		zend_hash_persist(&ce->constants_table, (zend_persist_func_t) zend_persist_zval_ptr, sizeof(zval**) TSRMLS_CC);
523 
524 		if (ZEND_CE_FILENAME(ce)) {
525 			/* do not free! PHP has centralized filename storage, compiler will free it */
526 			ZEND_CE_FILENAME(ce) = zend_accel_memdup(ZEND_CE_FILENAME(ce), strlen(ZEND_CE_FILENAME(ce)) + 1);
527 		}
528 		if (ZEND_CE_DOC_COMMENT(ce)) {
529 			if (ZCG(accel_directives).save_comments) {
530 				zend_accel_store(ZEND_CE_DOC_COMMENT(ce), ZEND_CE_DOC_COMMENT_LEN(ce) + 1);
531 			} else {
532 				if (!zend_shared_alloc_get_xlat_entry(ZEND_CE_DOC_COMMENT(ce))) {
533 					zend_shared_alloc_register_xlat_entry(ZEND_CE_DOC_COMMENT(ce), ZEND_CE_DOC_COMMENT(ce));
534 					efree((char*)ZEND_CE_DOC_COMMENT(ce));
535 				}
536 				ZEND_CE_DOC_COMMENT(ce) = NULL;
537 				ZEND_CE_DOC_COMMENT_LEN(ce) = 0;
538 			}
539 		}
540 		zend_hash_persist(&ce->properties_info, (zend_persist_func_t) zend_persist_property_info, sizeof(zend_property_info) TSRMLS_CC);
541 		if (ce->num_interfaces && ce->interfaces) {
542 			efree(ce->interfaces);
543 		}
544 		ce->interfaces = NULL; /* will be filled in on fetch */
545 
546 #if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
547 		if (ce->num_traits && ce->traits) {
548 			efree(ce->traits);
549 		}
550 		ce->traits = NULL;
551 
552 		if (ce->trait_aliases) {
553 			int i = 0;
554 			while (ce->trait_aliases[i]) {
555 				if (ce->trait_aliases[i]->trait_method) {
556 					if (ce->trait_aliases[i]->trait_method->method_name) {
557 						zend_accel_store(ce->trait_aliases[i]->trait_method->method_name,
558 							ce->trait_aliases[i]->trait_method->mname_len + 1);
559 					}
560 					if (ce->trait_aliases[i]->trait_method->class_name) {
561 						zend_accel_store(ce->trait_aliases[i]->trait_method->class_name,
562 							ce->trait_aliases[i]->trait_method->cname_len + 1);
563 					}
564 					ce->trait_aliases[i]->trait_method->ce = NULL;
565 					zend_accel_store(ce->trait_aliases[i]->trait_method,
566 						sizeof(zend_trait_method_reference));
567 				}
568 
569 				if (ce->trait_aliases[i]->alias) {
570 					zend_accel_store(ce->trait_aliases[i]->alias,
571 						ce->trait_aliases[i]->alias_len + 1);
572 				}
573 
574 #if ZEND_EXTENSION_API_NO <= PHP_5_4_X_API_NO
575                 ce->trait_aliases[i]->function = NULL;
576 #endif
577 				zend_accel_store(ce->trait_aliases[i], sizeof(zend_trait_alias));
578 				i++;
579 			}
580 
581 			zend_accel_store(ce->trait_aliases, sizeof(zend_trait_alias*) * (i + 1));
582 		}
583 
584 		if (ce->trait_precedences) {
585 			int i = 0;
586 
587 			while (ce->trait_precedences[i]) {
588 				zend_accel_store(ce->trait_precedences[i]->trait_method->method_name,
589 					ce->trait_precedences[i]->trait_method->mname_len + 1);
590 				zend_accel_store(ce->trait_precedences[i]->trait_method->class_name,
591 					ce->trait_precedences[i]->trait_method->cname_len + 1);
592 				ce->trait_precedences[i]->trait_method->ce = NULL;
593 				zend_accel_store(ce->trait_precedences[i]->trait_method,
594 					sizeof(zend_trait_method_reference));
595 
596 				if (ce->trait_precedences[i]->exclude_from_classes) {
597 					int j = 0;
598 
599 					while (ce->trait_precedences[i]->exclude_from_classes[j]) {
600 						zend_accel_store(ce->trait_precedences[i]->exclude_from_classes[j],
601 							strlen((char*)ce->trait_precedences[i]->exclude_from_classes[j]) + 1);
602 						j++;
603 					}
604 					zend_accel_store(ce->trait_precedences[i]->exclude_from_classes,
605 						sizeof(zend_class_entry*) * (j + 1));
606 				}
607 
608 #if ZEND_EXTENSION_API_NO <= PHP_5_4_X_API_NO
609                 ce->trait_precedences[i]->function = NULL;
610 #endif
611 				zend_accel_store(ce->trait_precedences[i], sizeof(zend_trait_precedence));
612 				i++;
613 			}
614 			zend_accel_store(
615 				ce->trait_precedences, sizeof(zend_trait_precedence*) * (i + 1));
616 		}
617 #endif
618 	}
619 }
620 
621 static int zend_update_property_info_ce(zend_property_info *prop TSRMLS_DC)
622 {
623 	prop->ce = zend_shared_alloc_get_xlat_entry(prop->ce);
624 	return 0;
625 }
626 
627 static int zend_update_parent_ce(zend_class_entry **pce TSRMLS_DC)
628 {
629 	zend_class_entry *ce = *pce;
630 
631 	if (ce->parent) {
632 		ce->parent = zend_shared_alloc_get_xlat_entry(ce->parent);
633 		/* We use refcount to show if the class is used as a parent */
634 		ce->parent->refcount++;
635 	}
636 
637 	/* update methods */
638 	if (ce->constructor) {
639 		ce->constructor = zend_shared_alloc_get_xlat_entry(ce->constructor);
640 		/* we use refcount to show that op_array is referenced from several places */
641 		ce->constructor->op_array.refcount++;
642 	}
643 	if (ce->destructor) {
644 		ce->destructor = zend_shared_alloc_get_xlat_entry(ce->destructor);
645 		ce->destructor->op_array.refcount++;
646 	}
647 	if (ce->clone) {
648 		ce->clone = zend_shared_alloc_get_xlat_entry(ce->clone);
649 		ce->clone->op_array.refcount++;
650 	}
651 	if (ce->__get) {
652 		ce->__get = zend_shared_alloc_get_xlat_entry(ce->__get);
653 		ce->__get->op_array.refcount++;
654 	}
655 	if (ce->__set) {
656 		ce->__set = zend_shared_alloc_get_xlat_entry(ce->__set);
657 		ce->__set->op_array.refcount++;
658 	}
659 	if (ce->__call) {
660 		ce->__call = zend_shared_alloc_get_xlat_entry(ce->__call);
661 		ce->__call->op_array.refcount++;
662 	}
663 	if (ce->serialize_func) {
664 		ce->serialize_func = zend_shared_alloc_get_xlat_entry(ce->serialize_func);
665 		ce->serialize_func->op_array.refcount++;
666 	}
667 	if (ce->unserialize_func) {
668 		ce->unserialize_func = zend_shared_alloc_get_xlat_entry(ce->unserialize_func);
669 		ce->unserialize_func->op_array.refcount++;
670 	}
671 	if (ce->__isset) {
672 		ce->__isset = zend_shared_alloc_get_xlat_entry(ce->__isset);
673 		ce->__isset->op_array.refcount++;
674 	}
675 	if (ce->__unset) {
676 		ce->__unset = zend_shared_alloc_get_xlat_entry(ce->__unset);
677 		ce->__unset->op_array.refcount++;
678 	}
679 	if (ce->__tostring) {
680 		ce->__tostring = zend_shared_alloc_get_xlat_entry(ce->__tostring);
681 		ce->__tostring->op_array.refcount++;
682 	}
683 #if ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO
684 	if (ce->__callstatic) {
685 		ce->__callstatic = zend_shared_alloc_get_xlat_entry(ce->__callstatic);
686 		ce->__callstatic->op_array.refcount++;
687 	}
688 #endif
689 #if ZEND_EXTENSION_API_NO >= PHP_5_6_X_API_NO
690 	if (ce->__debugInfo) {
691 		ce->__debugInfo = zend_shared_alloc_get_xlat_entry(ce->__debugInfo);
692 		ce->__debugInfo->op_array.refcount++;
693 	}
694 #endif
695 	zend_hash_apply(&ce->properties_info, (apply_func_t) zend_update_property_info_ce TSRMLS_CC);
696 	return 0;
697 }
698 
699 static void zend_accel_persist_class_table(HashTable *class_table TSRMLS_DC)
700 {
701     zend_hash_persist(class_table, (zend_persist_func_t) zend_persist_class_entry, sizeof(zend_class_entry*) TSRMLS_CC);
702 	zend_hash_apply(class_table, (apply_func_t) zend_update_parent_ce TSRMLS_CC);
703 }
704 
705 zend_persistent_script *zend_accel_script_persist(zend_persistent_script *script, char **key, unsigned int key_length TSRMLS_DC)
706 {
707 	zend_shared_alloc_clear_xlat_table();
708 	zend_hash_persist(&script->function_table, (zend_persist_func_t) zend_persist_op_array, sizeof(zend_op_array) TSRMLS_CC);
709 	zend_accel_persist_class_table(&script->class_table TSRMLS_CC);
710 	zend_persist_op_array_ex(&script->main_op_array, script TSRMLS_CC);
711 	*key = zend_accel_memdup(*key, key_length + 1);
712 	zend_accel_store(script->full_path, script->full_path_len + 1);
713 	zend_accel_store(script, sizeof(zend_persistent_script));
714 
715 	return script;
716 }
717 
718 int zend_accel_script_persistable(zend_persistent_script *script)
719 {
720 	return 1;
721 }
722