1 /*
2 +----------------------------------------------------------------------+
3 | Zend OPcache |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 1998-2018 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))
33 #define zend_accel_memdup(p, size) \
34 _zend_shared_memdup((void*)p, size, 0)
35
36 #ifdef HAVE_OPCACHE_FILE_CACHE
37 #define zend_set_str_gc_flags(str) do { \
38 if (file_cache_only) { \
39 GC_FLAGS(str) = IS_STR_INTERNED; \
40 } else { \
41 GC_FLAGS(str) = IS_STR_INTERNED | IS_STR_PERMANENT; \
42 } \
43 } while (0)
44 #else
45 #define zend_set_str_gc_flags(str) GC_FLAGS(str) = IS_STR_INTERNED | IS_STR_PERMANENT
46 #endif
47
48 #define zend_accel_store_string(str) do { \
49 zend_string *new_str = zend_shared_alloc_get_xlat_entry(str); \
50 if (new_str) { \
51 zend_string_release(str); \
52 str = new_str; \
53 } else { \
54 new_str = zend_accel_memdup((void*)str, _ZSTR_STRUCT_SIZE(ZSTR_LEN(str))); \
55 zend_string_release(str); \
56 str = new_str; \
57 zend_string_hash_val(str); \
58 zend_set_str_gc_flags(str); \
59 } \
60 } while (0)
61 #define zend_accel_memdup_string(str) do { \
62 str = zend_accel_memdup(str, _ZSTR_STRUCT_SIZE(ZSTR_LEN(str))); \
63 zend_string_hash_val(str); \
64 zend_set_str_gc_flags(str); \
65 } while (0)
66 #define zend_accel_store_interned_string(str) do { \
67 if (!IS_ACCEL_INTERNED(str)) { \
68 zend_accel_store_string(str); \
69 } \
70 } while (0)
71 #define zend_accel_memdup_interned_string(str) do { \
72 if (!IS_ACCEL_INTERNED(str)) { \
73 zend_accel_memdup_string(str); \
74 } \
75 } while (0)
76
77 typedef void (*zend_persist_func_t)(zval*);
78
79 static void zend_persist_zval(zval *z);
80
81 static const uint32_t uninitialized_bucket[-HT_MIN_MASK] =
82 {HT_INVALID_IDX, HT_INVALID_IDX};
83
zend_hash_persist(HashTable * ht,zend_persist_func_t pPersistElement)84 static void zend_hash_persist(HashTable *ht, zend_persist_func_t pPersistElement)
85 {
86 uint32_t idx, nIndex;
87 Bucket *p;
88
89 ht->pDestructor = NULL;
90
91 if (!(ht->u.flags & HASH_FLAG_INITIALIZED)) {
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->u.flags &= ~HASH_FLAG_INITIALIZED;
108 return;
109 }
110 if (ht->u.flags & HASH_FLAG_PACKED) {
111 void *data = HT_GET_DATA_ADDR(ht);
112 zend_accel_store(data, HT_USED_SIZE(ht));
113 HT_SET_DATA_ADDR(ht, data);
114 } else if (ht->nNumUsed < (uint32_t)(-(int32_t)ht->nTableMask) / 2) {
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 if (ht->nNumUsed <= HT_MIN_SIZE) {
121 hash_size = HT_MIN_SIZE;
122 } else {
123 hash_size = (uint32_t)(-(int32_t)ht->nTableMask);
124 while (hash_size >> 1 > ht->nNumUsed) {
125 hash_size >>= 1;
126 }
127 }
128 ht->nTableMask = (uint32_t)(-(int32_t)hash_size);
129 ZEND_ASSERT(((zend_uintptr_t)ZCG(mem) & 0x7) == 0); /* should be 8 byte aligned */
130 HT_SET_DATA_ADDR(ht, ZCG(mem));
131 ZCG(mem) = (void*)((char*)ZCG(mem) + ZEND_ALIGNED_SIZE((hash_size * sizeof(uint32_t)) + (ht->nNumUsed * sizeof(Bucket))));
132 HT_HASH_RESET(ht);
133 memcpy(ht->arData, old_buckets, ht->nNumUsed * sizeof(Bucket));
134 efree(old_data);
135
136 for (idx = 0; idx < ht->nNumUsed; idx++) {
137 p = ht->arData + idx;
138 if (Z_TYPE(p->val) == IS_UNDEF) continue;
139
140 /* persist bucket and key */
141 if (p->key) {
142 zend_accel_store_interned_string(p->key);
143 }
144
145 /* persist the data itself */
146 pPersistElement(&p->val);
147
148 nIndex = p->h | ht->nTableMask;
149 Z_NEXT(p->val) = HT_HASH(ht, nIndex);
150 HT_HASH(ht, nIndex) = HT_IDX_TO_HASH(idx);
151 }
152 return;
153 } else {
154 void *data = ZCG(mem);
155 void *old_data = HT_GET_DATA_ADDR(ht);
156
157 ZEND_ASSERT(((zend_uintptr_t)ZCG(mem) & 0x7) == 0); /* should be 8 byte aligned */
158 ZCG(mem) = (void*)((char*)data + ZEND_ALIGNED_SIZE(HT_USED_SIZE(ht)));
159 memcpy(data, old_data, HT_USED_SIZE(ht));
160 efree(old_data);
161 HT_SET_DATA_ADDR(ht, data);
162 }
163
164 for (idx = 0; idx < ht->nNumUsed; idx++) {
165 p = ht->arData + idx;
166 if (Z_TYPE(p->val) == IS_UNDEF) continue;
167
168 /* persist bucket and key */
169 if (p->key) {
170 zend_accel_store_interned_string(p->key);
171 }
172
173 /* persist the data itself */
174 pPersistElement(&p->val);
175 }
176 }
177
zend_hash_persist_immutable(HashTable * ht)178 static void zend_hash_persist_immutable(HashTable *ht)
179 {
180 uint32_t idx, nIndex;
181 Bucket *p;
182
183 ht->pDestructor = NULL;
184
185 if (!(ht->u.flags & HASH_FLAG_INITIALIZED)) {
186 if (EXPECTED(!ZCG(current_persistent_script)->corrupted)) {
187 HT_SET_DATA_ADDR(ht, &ZCSG(uninitialized_bucket));
188 } else {
189 HT_SET_DATA_ADDR(ht, &uninitialized_bucket);
190 }
191 return;
192 }
193 if (ht->nNumUsed == 0) {
194 efree(HT_GET_DATA_ADDR(ht));
195 ht->nTableMask = HT_MIN_MASK;
196 if (EXPECTED(!ZCG(current_persistent_script)->corrupted)) {
197 HT_SET_DATA_ADDR(ht, &ZCSG(uninitialized_bucket));
198 } else {
199 HT_SET_DATA_ADDR(ht, &uninitialized_bucket);
200 }
201 ht->u.flags &= ~HASH_FLAG_INITIALIZED;
202 return;
203 }
204 if (ht->u.flags & HASH_FLAG_PACKED) {
205 HT_SET_DATA_ADDR(ht, zend_accel_memdup(HT_GET_DATA_ADDR(ht), HT_USED_SIZE(ht)));
206 } else if (ht->nNumUsed < (uint32_t)(-(int32_t)ht->nTableMask) / 2) {
207 /* compact table */
208 void *old_data = HT_GET_DATA_ADDR(ht);
209 Bucket *old_buckets = ht->arData;
210 uint32_t hash_size;
211
212 if (ht->nNumUsed <= HT_MIN_SIZE) {
213 hash_size = HT_MIN_SIZE;
214 } else {
215 hash_size = (uint32_t)(-(int32_t)ht->nTableMask);
216 while (hash_size >> 1 > ht->nNumUsed) {
217 hash_size >>= 1;
218 }
219 }
220 ht->nTableMask = (uint32_t)(-(int32_t)hash_size);
221 ZEND_ASSERT(((zend_uintptr_t)ZCG(mem) & 0x7) == 0); /* should be 8 byte aligned */
222 HT_SET_DATA_ADDR(ht, ZCG(mem));
223 ZCG(mem) = (void*)((char*)ZCG(mem) + (hash_size * sizeof(uint32_t)) + (ht->nNumUsed * sizeof(Bucket)));
224 HT_HASH_RESET(ht);
225 memcpy(ht->arData, old_buckets, ht->nNumUsed * sizeof(Bucket));
226 efree(old_data);
227
228 for (idx = 0; idx < ht->nNumUsed; idx++) {
229 p = ht->arData + idx;
230 if (Z_TYPE(p->val) == IS_UNDEF) continue;
231
232 /* persist bucket and key */
233 if (p->key) {
234 zend_accel_memdup_interned_string(p->key);
235 }
236
237 /* persist the data itself */
238 zend_persist_zval(&p->val);
239
240 nIndex = p->h | ht->nTableMask;
241 Z_NEXT(p->val) = HT_HASH(ht, nIndex);
242 HT_HASH(ht, nIndex) = HT_IDX_TO_HASH(idx);
243 }
244 return;
245 } else {
246 void *data = ZCG(mem);
247
248 ZEND_ASSERT(((zend_uintptr_t)ZCG(mem) & 0x7) == 0); /* should be 8 byte aligned */
249 ZCG(mem) = (void*)((char*)data + ZEND_ALIGNED_SIZE(HT_USED_SIZE(ht)));
250 memcpy(data, HT_GET_DATA_ADDR(ht), HT_USED_SIZE(ht));
251 HT_SET_DATA_ADDR(ht, data);
252 }
253 for (idx = 0; idx < ht->nNumUsed; idx++) {
254 p = ht->arData + idx;
255 if (Z_TYPE(p->val) == IS_UNDEF) continue;
256
257 /* persist bucket and key */
258 if (p->key) {
259 zend_accel_memdup_interned_string(p->key);
260 }
261
262 /* persist the data itself */
263 zend_persist_zval(&p->val);
264 }
265 }
266
zend_persist_ast(zend_ast * ast)267 static zend_ast *zend_persist_ast(zend_ast *ast)
268 {
269 uint32_t i;
270 zend_ast *node;
271
272 if (ast->kind == ZEND_AST_ZVAL) {
273 zend_ast_zval *copy = zend_accel_memdup(ast, sizeof(zend_ast_zval));
274 zend_persist_zval(©->val);
275 node = (zend_ast *) copy;
276 } else if (zend_ast_is_list(ast)) {
277 zend_ast_list *list = zend_ast_get_list(ast);
278 zend_ast_list *copy = zend_accel_memdup(ast,
279 sizeof(zend_ast_list) - sizeof(zend_ast *) + sizeof(zend_ast *) * list->children);
280 for (i = 0; i < list->children; i++) {
281 if (copy->child[i]) {
282 copy->child[i] = zend_persist_ast(copy->child[i]);
283 }
284 }
285 node = (zend_ast *) copy;
286 } else {
287 uint32_t children = zend_ast_get_num_children(ast);
288 node = zend_accel_memdup(ast, sizeof(zend_ast) - sizeof(zend_ast *) + sizeof(zend_ast *) * children);
289 for (i = 0; i < children; i++) {
290 if (node->child[i]) {
291 node->child[i] = zend_persist_ast(node->child[i]);
292 }
293 }
294 }
295
296 efree(ast);
297 return node;
298 }
299
zend_persist_zval(zval * z)300 static void zend_persist_zval(zval *z)
301 {
302 void *new_ptr;
303
304 switch (Z_TYPE_P(z)) {
305 case IS_STRING:
306 case IS_CONSTANT:
307 zend_accel_store_interned_string(Z_STR_P(z));
308 Z_TYPE_FLAGS_P(z) &= ~ (IS_TYPE_REFCOUNTED | IS_TYPE_COPYABLE);
309 break;
310 case IS_ARRAY:
311 new_ptr = zend_shared_alloc_get_xlat_entry(Z_ARR_P(z));
312 if (new_ptr) {
313 Z_ARR_P(z) = new_ptr;
314 Z_TYPE_FLAGS_P(z) = IS_TYPE_COPYABLE;
315 } else {
316 if (!Z_REFCOUNTED_P(z)) {
317 Z_ARR_P(z) = zend_accel_memdup(Z_ARR_P(z), sizeof(zend_array));
318 zend_hash_persist_immutable(Z_ARRVAL_P(z));
319 } else {
320 GC_REMOVE_FROM_BUFFER(Z_ARR_P(z));
321 zend_accel_store(Z_ARR_P(z), sizeof(zend_array));
322 zend_hash_persist(Z_ARRVAL_P(z), zend_persist_zval);
323 /* make immutable array */
324 Z_TYPE_FLAGS_P(z) = IS_TYPE_COPYABLE;
325 GC_REFCOUNT(Z_COUNTED_P(z)) = 2;
326 GC_FLAGS(Z_COUNTED_P(z)) |= IS_ARRAY_IMMUTABLE;
327 Z_ARRVAL_P(z)->u.flags |= HASH_FLAG_STATIC_KEYS;
328 Z_ARRVAL_P(z)->u.flags &= ~HASH_FLAG_APPLY_PROTECTION;
329 }
330 }
331 break;
332 case IS_REFERENCE:
333 new_ptr = zend_shared_alloc_get_xlat_entry(Z_REF_P(z));
334 if (new_ptr) {
335 Z_REF_P(z) = new_ptr;
336 } else {
337 zend_accel_store(Z_REF_P(z), sizeof(zend_reference));
338 zend_persist_zval(Z_REFVAL_P(z));
339 }
340 break;
341 case IS_CONSTANT_AST:
342 new_ptr = zend_shared_alloc_get_xlat_entry(Z_AST_P(z));
343 if (new_ptr) {
344 Z_AST_P(z) = new_ptr;
345 Z_TYPE_FLAGS_P(z) = IS_TYPE_CONSTANT | IS_TYPE_COPYABLE;
346 } else {
347 zend_accel_store(Z_AST_P(z), sizeof(zend_ast_ref));
348 Z_ASTVAL_P(z) = zend_persist_ast(Z_ASTVAL_P(z));
349 Z_TYPE_FLAGS_P(z) = IS_TYPE_CONSTANT | IS_TYPE_COPYABLE;
350 GC_REFCOUNT(Z_COUNTED_P(z)) = 2;
351 }
352 break;
353 }
354 }
355
zend_persist_op_array_ex(zend_op_array * op_array,zend_persistent_script * main_persistent_script)356 static void zend_persist_op_array_ex(zend_op_array *op_array, zend_persistent_script* main_persistent_script)
357 {
358 int already_stored = 0;
359 zend_op *persist_ptr;
360 zval *orig_literals = NULL;
361
362 if (op_array->type != ZEND_USER_FUNCTION) {
363 return;
364 }
365
366 if (op_array->refcount && --(*op_array->refcount) == 0) {
367 efree(op_array->refcount);
368 }
369 op_array->refcount = NULL;
370
371 if (main_persistent_script) {
372 zend_execute_data *orig_execute_data = EG(current_execute_data);
373 zend_execute_data fake_execute_data;
374 zval *offset;
375
376 memset(&fake_execute_data, 0, sizeof(fake_execute_data));
377 fake_execute_data.func = (zend_function*)op_array;
378 EG(current_execute_data) = &fake_execute_data;
379 if ((offset = zend_get_constant_str("__COMPILER_HALT_OFFSET__", sizeof("__COMPILER_HALT_OFFSET__") - 1)) != NULL) {
380 main_persistent_script->compiler_halt_offset = Z_LVAL_P(offset);
381 }
382 EG(current_execute_data) = orig_execute_data;
383 }
384
385 if (op_array->static_variables) {
386 HashTable *stored = zend_shared_alloc_get_xlat_entry(op_array->static_variables);
387
388 if (stored) {
389 op_array->static_variables = stored;
390 } else {
391 zend_hash_persist(op_array->static_variables, zend_persist_zval);
392 zend_accel_store(op_array->static_variables, sizeof(HashTable));
393 /* make immutable array */
394 GC_REFCOUNT(op_array->static_variables) = 2;
395 GC_TYPE_INFO(op_array->static_variables) = IS_ARRAY | (IS_ARRAY_IMMUTABLE << 8);
396 op_array->static_variables->u.flags |= HASH_FLAG_STATIC_KEYS;
397 op_array->static_variables->u.flags &= ~HASH_FLAG_APPLY_PROTECTION;
398 }
399 }
400
401 if (zend_shared_alloc_get_xlat_entry(op_array->opcodes)) {
402 already_stored = 1;
403 }
404
405 if (op_array->literals) {
406 if (already_stored) {
407 orig_literals = zend_shared_alloc_get_xlat_entry(op_array->literals);
408 ZEND_ASSERT(orig_literals != NULL);
409 op_array->literals = orig_literals;
410 } else {
411 zval *p = zend_accel_memdup(op_array->literals, sizeof(zval) * op_array->last_literal);
412 zval *end = p + op_array->last_literal;
413 orig_literals = op_array->literals;
414 op_array->literals = p;
415 while (p < end) {
416 zend_persist_zval(p);
417 p++;
418 }
419 efree(orig_literals);
420 }
421 }
422
423 if (already_stored) {
424 persist_ptr = zend_shared_alloc_get_xlat_entry(op_array->opcodes);
425 ZEND_ASSERT(persist_ptr != NULL);
426 op_array->opcodes = persist_ptr;
427 } else {
428 zend_op *new_opcodes = zend_accel_memdup(op_array->opcodes, sizeof(zend_op) * op_array->last);
429 #if ZEND_USE_ABS_CONST_ADDR || ZEND_USE_ABS_JMP_ADDR
430 zend_op *opline = new_opcodes;
431 zend_op *end = new_opcodes + op_array->last;
432 int offset = 0;
433
434 for (; opline < end ; opline++, offset++) {
435 # if ZEND_USE_ABS_CONST_ADDR
436 if (opline->op1_type == IS_CONST) {
437 opline->op1.zv = (zval*)((char*)opline->op1.zv + ((char*)op_array->literals - (char*)orig_literals));
438 }
439 if (opline->op2_type == IS_CONST) {
440 opline->op2.zv = (zval*)((char*)opline->op2.zv + ((char*)op_array->literals - (char*)orig_literals));
441 }
442 # endif
443 # if ZEND_USE_ABS_JMP_ADDR
444 if (op_array->fn_flags & ZEND_ACC_DONE_PASS_TWO) {
445 /* fix jumps to point to new array */
446 switch (opline->opcode) {
447 case ZEND_JMP:
448 case ZEND_FAST_CALL:
449 opline->op1.jmp_addr = &new_opcodes[opline->op1.jmp_addr - op_array->opcodes];
450 break;
451 case ZEND_JMPZNZ:
452 /* relative extended_value don't have to be changed */
453 /* break omitted intentionally */
454 case ZEND_JMPZ:
455 case ZEND_JMPNZ:
456 case ZEND_JMPZ_EX:
457 case ZEND_JMPNZ_EX:
458 case ZEND_JMP_SET:
459 case ZEND_COALESCE:
460 case ZEND_FE_RESET_R:
461 case ZEND_FE_RESET_RW:
462 case ZEND_ASSERT_CHECK:
463 opline->op2.jmp_addr = &new_opcodes[opline->op2.jmp_addr - op_array->opcodes];
464 break;
465 case ZEND_DECLARE_ANON_CLASS:
466 case ZEND_DECLARE_ANON_INHERITED_CLASS:
467 case ZEND_FE_FETCH_R:
468 case ZEND_FE_FETCH_RW:
469 case ZEND_SWITCH_LONG:
470 case ZEND_SWITCH_STRING:
471 /* relative extended_value don't have to be changed */
472 break;
473 }
474 }
475 # endif
476 }
477 #endif
478
479 efree(op_array->opcodes);
480 op_array->opcodes = new_opcodes;
481
482 if (op_array->run_time_cache) {
483 efree(op_array->run_time_cache);
484 op_array->run_time_cache = NULL;
485 }
486 }
487
488 if (op_array->function_name && !IS_ACCEL_INTERNED(op_array->function_name)) {
489 zend_string *new_name;
490 if (already_stored) {
491 new_name = zend_shared_alloc_get_xlat_entry(op_array->function_name);
492 ZEND_ASSERT(new_name != NULL);
493 op_array->function_name = new_name;
494 } else {
495 zend_accel_store_interned_string(op_array->function_name);
496 }
497 }
498
499 if (op_array->filename) {
500 /* do not free! PHP has centralized filename storage, compiler will free it */
501 zend_accel_memdup_string(op_array->filename);
502 }
503
504 if (op_array->arg_info) {
505 zend_arg_info *arg_info = op_array->arg_info;
506 uint32_t num_args = op_array->num_args;
507
508 if (op_array->fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
509 arg_info--;
510 num_args++;
511 }
512 if (already_stored) {
513 arg_info = zend_shared_alloc_get_xlat_entry(arg_info);
514 ZEND_ASSERT(arg_info != NULL);
515 } else {
516 uint32_t i;
517
518 if (op_array->fn_flags & ZEND_ACC_VARIADIC) {
519 num_args++;
520 }
521 zend_accel_store(arg_info, sizeof(zend_arg_info) * num_args);
522 for (i = 0; i < num_args; i++) {
523 if (arg_info[i].name) {
524 zend_accel_store_interned_string(arg_info[i].name);
525 }
526 if (ZEND_TYPE_IS_CLASS(arg_info[i].type)) {
527 zend_string *type_name = ZEND_TYPE_NAME(arg_info[i].type);
528 zend_bool allow_null = ZEND_TYPE_ALLOW_NULL(arg_info[i].type);
529
530 zend_accel_store_interned_string(type_name);
531 arg_info[i].type = ZEND_TYPE_ENCODE_CLASS(type_name, allow_null);
532 }
533 }
534 }
535 if (op_array->fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
536 arg_info++;
537 }
538 op_array->arg_info = arg_info;
539 }
540
541 if (op_array->live_range) {
542 zend_accel_store(op_array->live_range, sizeof(zend_live_range) * op_array->last_live_range);
543 }
544
545 if (op_array->scope) {
546 op_array->scope = zend_shared_alloc_get_xlat_entry(op_array->scope);
547 }
548
549 if (op_array->doc_comment) {
550 if (ZCG(accel_directives).save_comments) {
551 if (already_stored) {
552 op_array->doc_comment = zend_shared_alloc_get_xlat_entry(op_array->doc_comment);
553 ZEND_ASSERT(op_array->doc_comment != NULL);
554 } else {
555 zend_accel_store_interned_string(op_array->doc_comment);
556 }
557 } else {
558 if (!already_stored) {
559 zend_string_release(op_array->doc_comment);
560 }
561 op_array->doc_comment = NULL;
562 }
563 }
564
565 if (op_array->try_catch_array) {
566 zend_accel_store(op_array->try_catch_array, sizeof(zend_try_catch_element) * op_array->last_try_catch);
567 }
568
569 if (op_array->vars) {
570 if (already_stored) {
571 persist_ptr = zend_shared_alloc_get_xlat_entry(op_array->vars);
572 ZEND_ASSERT(persist_ptr != NULL);
573 op_array->vars = (zend_string**)persist_ptr;
574 } else {
575 int i;
576 zend_accel_store(op_array->vars, sizeof(zend_string*) * op_array->last_var);
577 for (i = 0; i < op_array->last_var; i++) {
578 zend_accel_store_interned_string(op_array->vars[i]);
579 }
580 }
581 }
582
583 /* "prototype" may be undefined if "scope" isn't set */
584 if (op_array->scope && op_array->prototype) {
585 if ((persist_ptr = zend_shared_alloc_get_xlat_entry(op_array->prototype))) {
586 op_array->prototype = (union _zend_function*)persist_ptr;
587 }
588 } else {
589 op_array->prototype = NULL;
590 }
591
592 ZCG(mem) = (void*)((char*)ZCG(mem) + ZEND_ALIGNED_SIZE(zend_extensions_op_array_persist(op_array, ZCG(mem))));
593 }
594
zend_persist_op_array(zval * zv)595 static void zend_persist_op_array(zval *zv)
596 {
597 zend_op_array *op_array = Z_PTR_P(zv);
598 zend_op_array *old_op_array = zend_shared_alloc_get_xlat_entry(op_array);
599 if (old_op_array) {
600 Z_PTR_P(zv) = old_op_array;
601 if (op_array->refcount && --(*op_array->refcount) == 0) {
602 efree(op_array->refcount);
603 }
604 return;
605 }
606 memcpy(ZCG(arena_mem), Z_PTR_P(zv), sizeof(zend_op_array));
607 zend_shared_alloc_register_xlat_entry(Z_PTR_P(zv), ZCG(arena_mem));
608 Z_PTR_P(zv) = ZCG(arena_mem);
609 ZCG(arena_mem) = (void*)((char*)ZCG(arena_mem) + ZEND_ALIGNED_SIZE(sizeof(zend_op_array)));
610 zend_persist_op_array_ex(Z_PTR_P(zv), NULL);
611 }
612
zend_persist_property_info(zval * zv)613 static void zend_persist_property_info(zval *zv)
614 {
615 zend_property_info *prop = zend_shared_alloc_get_xlat_entry(Z_PTR_P(zv));
616
617 if (prop) {
618 Z_PTR_P(zv) = prop;
619 return;
620 }
621 memcpy(ZCG(arena_mem), Z_PTR_P(zv), sizeof(zend_property_info));
622 zend_shared_alloc_register_xlat_entry(Z_PTR_P(zv), ZCG(arena_mem));
623 prop = Z_PTR_P(zv) = ZCG(arena_mem);
624 ZCG(arena_mem) = (void*)((char*)ZCG(arena_mem) + ZEND_ALIGNED_SIZE(sizeof(zend_property_info)));
625 prop->ce = zend_shared_alloc_get_xlat_entry(prop->ce);
626 zend_accel_store_interned_string(prop->name);
627 if (prop->doc_comment) {
628 if (ZCG(accel_directives).save_comments) {
629 zend_accel_store_interned_string(prop->doc_comment);
630 } else {
631 if (!zend_shared_alloc_get_xlat_entry(prop->doc_comment)) {
632 zend_shared_alloc_register_xlat_entry(prop->doc_comment, prop->doc_comment);
633 }
634 zend_string_release(prop->doc_comment);
635 prop->doc_comment = NULL;
636 }
637 }
638 }
639
zend_persist_class_constant(zval * zv)640 static void zend_persist_class_constant(zval *zv)
641 {
642 zend_class_constant *c = zend_shared_alloc_get_xlat_entry(Z_PTR_P(zv));
643
644 if (c) {
645 Z_PTR_P(zv) = c;
646 return;
647 }
648 memcpy(ZCG(arena_mem), Z_PTR_P(zv), sizeof(zend_class_constant));
649 zend_shared_alloc_register_xlat_entry(Z_PTR_P(zv), ZCG(arena_mem));
650 c = Z_PTR_P(zv) = ZCG(arena_mem);
651 ZCG(arena_mem) = (void*)((char*)ZCG(arena_mem) + ZEND_ALIGNED_SIZE(sizeof(zend_class_constant)));
652 zend_persist_zval(&c->value);
653 c->ce = zend_shared_alloc_get_xlat_entry(c->ce);
654 if (c->doc_comment) {
655 if (ZCG(accel_directives).save_comments) {
656 zend_string *doc_comment = zend_shared_alloc_get_xlat_entry(c->doc_comment);
657 if (doc_comment) {
658 c->doc_comment = doc_comment;
659 } else {
660 zend_accel_store_interned_string(c->doc_comment);
661 }
662 } else {
663 zend_string *doc_comment = zend_shared_alloc_get_xlat_entry(c->doc_comment);
664 if (!doc_comment) {
665 zend_shared_alloc_register_xlat_entry(c->doc_comment, c->doc_comment);
666 zend_string_release(c->doc_comment);
667 }
668 c->doc_comment = NULL;
669 }
670 }
671 }
672
zend_persist_class_entry(zval * zv)673 static void zend_persist_class_entry(zval *zv)
674 {
675 zend_class_entry *ce = Z_PTR_P(zv);
676
677 if (ce->type == ZEND_USER_CLASS) {
678 memcpy(ZCG(arena_mem), Z_PTR_P(zv), sizeof(zend_class_entry));
679 zend_shared_alloc_register_xlat_entry(Z_PTR_P(zv), ZCG(arena_mem));
680 ce = Z_PTR_P(zv) = ZCG(arena_mem);
681 ZCG(arena_mem) = (void*)((char*)ZCG(arena_mem) + ZEND_ALIGNED_SIZE(sizeof(zend_class_entry)));
682 zend_accel_store_interned_string(ce->name);
683 zend_hash_persist(&ce->function_table, zend_persist_op_array);
684 if (ce->default_properties_table) {
685 int i;
686
687 zend_accel_store(ce->default_properties_table, sizeof(zval) * ce->default_properties_count);
688 for (i = 0; i < ce->default_properties_count; i++) {
689 zend_persist_zval(&ce->default_properties_table[i]);
690 }
691 }
692 if (ce->default_static_members_table) {
693 int i;
694
695 zend_accel_store(ce->default_static_members_table, sizeof(zval) * ce->default_static_members_count);
696 for (i = 0; i < ce->default_static_members_count; i++) {
697 zend_persist_zval(&ce->default_static_members_table[i]);
698 }
699 }
700 ce->static_members_table = NULL;
701
702 zend_hash_persist(&ce->constants_table, zend_persist_class_constant);
703
704 if (ce->info.user.filename) {
705 /* do not free! PHP has centralized filename storage, compiler will free it */
706 zend_accel_memdup_string(ce->info.user.filename);
707 }
708 if (ce->info.user.doc_comment) {
709 if (ZCG(accel_directives).save_comments) {
710 zend_accel_store_interned_string(ce->info.user.doc_comment);
711 } else {
712 if (!zend_shared_alloc_get_xlat_entry(ce->info.user.doc_comment)) {
713 zend_shared_alloc_register_xlat_entry(ce->info.user.doc_comment, ce->info.user.doc_comment);
714 zend_string_release(ce->info.user.doc_comment);
715 }
716 ce->info.user.doc_comment = NULL;
717 }
718 }
719 zend_hash_persist(&ce->properties_info, zend_persist_property_info);
720 if (ce->num_interfaces && ce->interfaces) {
721 efree(ce->interfaces);
722 }
723 ce->interfaces = NULL; /* will be filled in on fetch */
724
725 if (ce->num_traits && ce->traits) {
726 efree(ce->traits);
727 }
728 ce->traits = NULL;
729
730 if (ce->trait_aliases) {
731 int i = 0;
732 while (ce->trait_aliases[i]) {
733 if (ce->trait_aliases[i]->trait_method) {
734 if (ce->trait_aliases[i]->trait_method->method_name) {
735 zend_accel_store_interned_string(ce->trait_aliases[i]->trait_method->method_name);
736 }
737 if (ce->trait_aliases[i]->trait_method->class_name) {
738 zend_accel_store_interned_string(ce->trait_aliases[i]->trait_method->class_name);
739 }
740 ce->trait_aliases[i]->trait_method->ce = NULL;
741 zend_accel_store(ce->trait_aliases[i]->trait_method,
742 sizeof(zend_trait_method_reference));
743 }
744
745 if (ce->trait_aliases[i]->alias) {
746 zend_accel_store_interned_string(ce->trait_aliases[i]->alias);
747 }
748
749 zend_accel_store(ce->trait_aliases[i], sizeof(zend_trait_alias));
750 i++;
751 }
752
753 zend_accel_store(ce->trait_aliases, sizeof(zend_trait_alias*) * (i + 1));
754 }
755
756 if (ce->trait_precedences) {
757 int i = 0;
758
759 while (ce->trait_precedences[i]) {
760 zend_accel_store_interned_string(ce->trait_precedences[i]->trait_method->method_name);
761 zend_accel_store_interned_string(ce->trait_precedences[i]->trait_method->class_name);
762 ce->trait_precedences[i]->trait_method->ce = NULL;
763 zend_accel_store(ce->trait_precedences[i]->trait_method,
764 sizeof(zend_trait_method_reference));
765
766 if (ce->trait_precedences[i]->exclude_from_classes) {
767 int j = 0;
768
769 while (ce->trait_precedences[i]->exclude_from_classes[j].class_name) {
770 zend_accel_store_interned_string(ce->trait_precedences[i]->exclude_from_classes[j].class_name);
771 j++;
772 }
773 zend_accel_store(ce->trait_precedences[i]->exclude_from_classes,
774 sizeof(zend_class_entry*) * (j + 1));
775 }
776
777 zend_accel_store(ce->trait_precedences[i], sizeof(zend_trait_precedence));
778 i++;
779 }
780 zend_accel_store(
781 ce->trait_precedences, sizeof(zend_trait_precedence*) * (i + 1));
782 }
783 }
784 }
785
786 //static int zend_update_property_info_ce(zval *zv)
787 //{
788 // zend_property_info *prop = Z_PTR_P(zv);
789 //
790 // prop->ce = zend_shared_alloc_get_xlat_entry(prop->ce);
791 // return 0;
792 //}
793
zend_update_parent_ce(zval * zv)794 static int zend_update_parent_ce(zval *zv)
795 {
796 zend_class_entry *ce = Z_PTR_P(zv);
797
798 if (ce->parent) {
799 ce->parent = zend_shared_alloc_get_xlat_entry(ce->parent);
800 }
801
802 /* update methods */
803 if (ce->constructor) {
804 ce->constructor = zend_shared_alloc_get_xlat_entry(ce->constructor);
805 }
806 if (ce->destructor) {
807 ce->destructor = zend_shared_alloc_get_xlat_entry(ce->destructor);
808 }
809 if (ce->clone) {
810 ce->clone = zend_shared_alloc_get_xlat_entry(ce->clone);
811 }
812 if (ce->__get) {
813 ce->__get = zend_shared_alloc_get_xlat_entry(ce->__get);
814 }
815 if (ce->__set) {
816 ce->__set = zend_shared_alloc_get_xlat_entry(ce->__set);
817 }
818 if (ce->__call) {
819 ce->__call = zend_shared_alloc_get_xlat_entry(ce->__call);
820 }
821 if (ce->serialize_func) {
822 ce->serialize_func = zend_shared_alloc_get_xlat_entry(ce->serialize_func);
823 }
824 if (ce->unserialize_func) {
825 ce->unserialize_func = zend_shared_alloc_get_xlat_entry(ce->unserialize_func);
826 }
827 if (ce->__isset) {
828 ce->__isset = zend_shared_alloc_get_xlat_entry(ce->__isset);
829 }
830 if (ce->__unset) {
831 ce->__unset = zend_shared_alloc_get_xlat_entry(ce->__unset);
832 }
833 if (ce->__tostring) {
834 ce->__tostring = zend_shared_alloc_get_xlat_entry(ce->__tostring);
835 }
836 if (ce->__callstatic) {
837 ce->__callstatic = zend_shared_alloc_get_xlat_entry(ce->__callstatic);
838 }
839 if (ce->__debugInfo) {
840 ce->__debugInfo = zend_shared_alloc_get_xlat_entry(ce->__debugInfo);
841 }
842 // zend_hash_apply(&ce->properties_info, (apply_func_t) zend_update_property_info_ce);
843 return 0;
844 }
845
zend_accel_persist_class_table(HashTable * class_table)846 static void zend_accel_persist_class_table(HashTable *class_table)
847 {
848 zend_hash_persist(class_table, zend_persist_class_entry);
849 zend_hash_apply(class_table, (apply_func_t) zend_update_parent_ce);
850 }
851
zend_accel_script_persist(zend_persistent_script * script,char ** key,unsigned int key_length,int for_shm)852 zend_persistent_script *zend_accel_script_persist(zend_persistent_script *script, char **key, unsigned int key_length, int for_shm)
853 {
854 script->mem = ZCG(mem);
855
856 ZEND_ASSERT(((zend_uintptr_t)ZCG(mem) & 0x7) == 0); /* should be 8 byte aligned */
857 zend_shared_alloc_clear_xlat_table();
858
859 zend_accel_store(script, sizeof(zend_persistent_script));
860 if (key && *key) {
861 *key = zend_accel_memdup(*key, key_length + 1);
862 }
863
864 script->corrupted = 0;
865 ZCG(current_persistent_script) = script;
866
867 if (!for_shm) {
868 /* script is not going to be saved in SHM */
869 script->corrupted = 1;
870 }
871
872 zend_accel_store_interned_string(script->script.filename);
873
874 #ifdef __SSE2__
875 /* Align to 64-byte boundary */
876 ZCG(mem) = (void*)(((zend_uintptr_t)ZCG(mem) + 63L) & ~63L);
877 #else
878 ZEND_ASSERT(((zend_uintptr_t)ZCG(mem) & 0x7) == 0); /* should be 8 byte aligned */
879 #endif
880
881 script->arena_mem = ZCG(arena_mem) = ZCG(mem);
882 ZCG(mem) = (void*)((char*)ZCG(mem) + script->arena_size);
883
884 zend_accel_persist_class_table(&script->script.class_table);
885 zend_hash_persist(&script->script.function_table, zend_persist_op_array);
886 zend_persist_op_array_ex(&script->script.main_op_array, script);
887
888 script->corrupted = 0;
889 ZCG(current_persistent_script) = NULL;
890
891 return script;
892 }
893
zend_accel_script_persistable(zend_persistent_script * script)894 int zend_accel_script_persistable(zend_persistent_script *script)
895 {
896 return 1;
897 }
898