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