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