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@php.net> |
16 | Zeev Suraski <zeev@php.net> |
17 | Stanislav Malyshev <stas@zend.com> |
18 | Dmitry Stogov <dmitry@php.net> |
19 +----------------------------------------------------------------------+
20 */
21
22 #include "zend_API.h"
23 #include "zend_constants.h"
24 #include "zend_accelerator_util_funcs.h"
25 #include "zend_persist.h"
26 #include "zend_shared_alloc.h"
27
28 #if SIZEOF_SIZE_T <= SIZEOF_ZEND_LONG
29 /* If sizeof(void*) == sizeof(ulong) we can use zend_hash index functions */
30 # define accel_xlat_set(old, new) zend_hash_index_add_new_ptr(&ZCG(bind_hash), (zend_ulong)(zend_uintptr_t)(old), (new))
31 # define accel_xlat_get(old) zend_hash_index_find_ptr(&ZCG(bind_hash), (zend_ulong)(zend_uintptr_t)(old))
32 #else
33 # define accel_xlat_set(old, new) zend_hash_str_add_new_ptr(&ZCG(bind_hash), (char*)&(old), sizeof(void*), (new))
34 # define accel_xlat_get(old) zend_hash_str_find_ptr(&ZCG(bind_hash), (char*)&(old), sizeof(void*))
35 #endif
36
37 #define ARENA_REALLOC(ptr) \
38 (void*)(((char*)(ptr)) + ((char*)ZCG(arena_mem) - (char*)ZCG(current_persistent_script)->arena_mem))
39
40 typedef int (*id_function_t)(void *, void *);
41 typedef void (*unique_copy_ctor_func_t)(void *pElement);
42
zend_accel_destroy_zend_function(zval * zv)43 static void zend_accel_destroy_zend_function(zval *zv)
44 {
45 zend_function *function = Z_PTR_P(zv);
46
47 if (function->type == ZEND_USER_FUNCTION) {
48 if (function->op_array.static_variables) {
49 if (!(GC_FLAGS(function->op_array.static_variables) & IS_ARRAY_IMMUTABLE)) {
50 if (GC_DELREF(function->op_array.static_variables) == 0) {
51 FREE_HASHTABLE(function->op_array.static_variables);
52 }
53 }
54 function->op_array.static_variables = NULL;
55 }
56 }
57
58 zend_function_dtor(zv);
59 }
60
zend_accel_destroy_zend_class(zval * zv)61 static void zend_accel_destroy_zend_class(zval *zv)
62 {
63 zend_class_entry *ce = Z_PTR_P(zv);
64 ce->function_table.pDestructor = zend_accel_destroy_zend_function;
65 destroy_zend_class(zv);
66 }
67
create_persistent_script(void)68 zend_persistent_script* create_persistent_script(void)
69 {
70 zend_persistent_script *persistent_script = (zend_persistent_script *) emalloc(sizeof(zend_persistent_script));
71 memset(persistent_script, 0, sizeof(zend_persistent_script));
72
73 zend_hash_init(&persistent_script->script.function_table, 128, NULL, ZEND_FUNCTION_DTOR, 0);
74 /* class_table is usually destroyed by free_persistent_script() that
75 * overrides destructor. ZEND_CLASS_DTOR may be used by standard
76 * PHP compiler
77 */
78 zend_hash_init(&persistent_script->script.class_table, 16, NULL, ZEND_CLASS_DTOR, 0);
79
80 return persistent_script;
81 }
82
free_persistent_script(zend_persistent_script * persistent_script,int destroy_elements)83 void free_persistent_script(zend_persistent_script *persistent_script, int destroy_elements)
84 {
85 if (destroy_elements) {
86 persistent_script->script.function_table.pDestructor = zend_accel_destroy_zend_function;
87 persistent_script->script.class_table.pDestructor = zend_accel_destroy_zend_class;
88 } else {
89 persistent_script->script.function_table.pDestructor = NULL;
90 persistent_script->script.class_table.pDestructor = NULL;
91 }
92
93 zend_hash_destroy(&persistent_script->script.function_table);
94 zend_hash_destroy(&persistent_script->script.class_table);
95
96 if (persistent_script->script.filename) {
97 zend_string_release_ex(persistent_script->script.filename, 0);
98 }
99
100 efree(persistent_script);
101 }
102
is_not_internal_function(zval * zv)103 static int is_not_internal_function(zval *zv)
104 {
105 zend_function *function = Z_PTR_P(zv);
106 return(function->type != ZEND_INTERNAL_FUNCTION);
107 }
108
zend_accel_free_user_functions(HashTable * ht)109 void zend_accel_free_user_functions(HashTable *ht)
110 {
111 dtor_func_t orig_dtor = ht->pDestructor;
112
113 ht->pDestructor = NULL;
114 zend_hash_apply(ht, (apply_func_t) is_not_internal_function);
115 ht->pDestructor = orig_dtor;
116 }
117
zend_accel_move_user_functions(HashTable * src,HashTable * dst)118 void zend_accel_move_user_functions(HashTable *src, HashTable *dst)
119 {
120 Bucket *p;
121 dtor_func_t orig_dtor = src->pDestructor;
122
123 src->pDestructor = NULL;
124 zend_hash_extend(dst, dst->nNumUsed + src->nNumUsed, 0);
125 ZEND_HASH_REVERSE_FOREACH_BUCKET(src, p) {
126 zend_function *function = Z_PTR(p->val);
127
128 if (EXPECTED(function->type == ZEND_USER_FUNCTION)) {
129 _zend_hash_append_ptr(dst, p->key, function);
130 zend_hash_del_bucket(src, p);
131 } else {
132 break;
133 }
134 } ZEND_HASH_FOREACH_END();
135 src->pDestructor = orig_dtor;
136 }
137
zend_accel_copy_internal_functions(void)138 void zend_accel_copy_internal_functions(void)
139 {
140 zend_string *key;
141 zval *val;
142
143 ZEND_HASH_FOREACH_STR_KEY_VAL(CG(function_table), key, val) {
144 zend_internal_function *function = Z_PTR_P(val);
145 if (function->type == ZEND_INTERNAL_FUNCTION) {
146 zend_hash_add_new_ptr(&ZCG(function_table), key, function);
147 }
148 } ZEND_HASH_FOREACH_END();
149 ZCG(internal_functions_count) = zend_hash_num_elements(&ZCG(function_table));
150 }
151
zend_clone_zval(zval * src)152 static inline void zend_clone_zval(zval *src)
153 {
154 void *ptr;
155
156 if (Z_TYPE_P(src) == IS_REFERENCE) {
157 ptr = accel_xlat_get(Z_REF_P(src));
158 if (ptr != NULL) {
159 Z_REF_P(src) = ptr;
160 return;
161 } else {
162 zend_reference *old = Z_REF_P(src);
163 ZVAL_NEW_REF(src, &old->val);
164 Z_REF_P(src)->gc = old->gc;
165 accel_xlat_set(old, Z_REF_P(src));
166 src = Z_REFVAL_P(src);
167 }
168 }
169 }
170
zend_hash_clone_constants(HashTable * ht,HashTable * source)171 static void zend_hash_clone_constants(HashTable *ht, HashTable *source)
172 {
173 Bucket *p, *q, *end;
174 zend_ulong nIndex;
175 zend_class_constant *c;
176
177 ht->nTableSize = source->nTableSize;
178 ht->nTableMask = source->nTableMask;
179 ht->nNumUsed = 0;
180 ht->nNumOfElements = source->nNumOfElements;
181 ht->nNextFreeElement = source->nNextFreeElement;
182 ht->pDestructor = NULL;
183 HT_FLAGS(ht) = (HT_FLAGS(source) & (HASH_FLAG_INITIALIZED | HASH_FLAG_STATIC_KEYS));
184 ht->nInternalPointer = 0;
185
186 if (!(HT_FLAGS(ht) & HASH_FLAG_INITIALIZED)) {
187 ht->arData = source->arData;
188 return;
189 }
190
191 ZEND_ASSERT((HT_FLAGS(source) & HASH_FLAG_PACKED) == 0);
192 HT_SET_DATA_ADDR(ht, emalloc(HT_SIZE(ht)));
193 HT_HASH_RESET(ht);
194
195 p = source->arData;
196 end = p + source->nNumUsed;
197 for (; p != end; p++) {
198 ZEND_ASSERT(Z_TYPE(p->val) != IS_UNDEF);
199 nIndex = p->h | ht->nTableMask;
200
201 /* Insert into hash collision list */
202 q = ht->arData + ht->nNumUsed;
203 Z_NEXT(q->val) = HT_HASH(ht, nIndex);
204 HT_HASH(ht, nIndex) = HT_IDX_TO_HASH(ht->nNumUsed++);
205
206 /* Initialize key */
207 q->h = p->h;
208 q->key = p->key;
209
210 /* Copy data */
211 c = ARENA_REALLOC(Z_PTR(p->val));
212 ZVAL_PTR(&q->val, c);
213
214 zend_clone_zval(&c->value);
215 if ((void*)c->ce >= ZCG(current_persistent_script)->arena_mem &&
216 (void*)c->ce < (void*)((char*)ZCG(current_persistent_script)->arena_mem + ZCG(current_persistent_script)->arena_size)) {
217 c->ce = ARENA_REALLOC(c->ce);
218 }
219 }
220 }
221
zend_hash_clone_methods(HashTable * ht,HashTable * source,zend_class_entry * old_ce,zend_class_entry * ce)222 static void zend_hash_clone_methods(HashTable *ht, HashTable *source, zend_class_entry *old_ce, zend_class_entry *ce)
223 {
224 Bucket *p, *q, *end;
225 zend_ulong nIndex;
226 zend_op_array *new_entry;
227
228 ht->nTableSize = source->nTableSize;
229 ht->nTableMask = source->nTableMask;
230 ht->nNumUsed = 0;
231 ht->nNumOfElements = source->nNumOfElements;
232 ht->nNextFreeElement = source->nNextFreeElement;
233 ht->pDestructor = ZEND_FUNCTION_DTOR;
234 HT_FLAGS(ht) = (HT_FLAGS(source) & (HASH_FLAG_INITIALIZED | HASH_FLAG_STATIC_KEYS));
235 ht->nInternalPointer = 0;
236
237 if (!(HT_FLAGS(ht) & HASH_FLAG_INITIALIZED)) {
238 ht->arData = source->arData;
239 return;
240 }
241
242 ZEND_ASSERT(!(HT_FLAGS(source) & HASH_FLAG_PACKED));
243 HT_SET_DATA_ADDR(ht, emalloc(HT_SIZE(ht)));
244 HT_HASH_RESET(ht);
245
246 p = source->arData;
247 end = p + source->nNumUsed;
248 for (; p != end; p++) {
249 ZEND_ASSERT(Z_TYPE(p->val) != IS_UNDEF);
250
251 nIndex = p->h | ht->nTableMask;
252
253 /* Insert into hash collision list */
254 q = ht->arData + ht->nNumUsed;
255 Z_NEXT(q->val) = HT_HASH(ht, nIndex);
256 HT_HASH(ht, nIndex) = HT_IDX_TO_HASH(ht->nNumUsed++);
257
258 /* Initialize key */
259 q->h = p->h;
260 ZEND_ASSERT(p->key != NULL);
261 q->key = p->key;
262
263 /* Copy data */
264 ZVAL_PTR(&q->val, ARENA_REALLOC(Z_PTR(p->val)));
265 new_entry = (zend_op_array*)Z_PTR(q->val);
266
267 if ((void*)new_entry->scope >= ZCG(current_persistent_script)->arena_mem &&
268 (void*)new_entry->scope < (void*)((char*)ZCG(current_persistent_script)->arena_mem + ZCG(current_persistent_script)->arena_size)) {
269
270 new_entry->scope = ARENA_REALLOC(new_entry->scope);
271
272 /* update prototype */
273 if (new_entry->prototype) {
274 new_entry->prototype = ARENA_REALLOC(new_entry->prototype);
275 }
276 }
277 }
278 }
279
zend_hash_clone_prop_info(HashTable * ht,HashTable * source,zend_class_entry * old_ce)280 static void zend_hash_clone_prop_info(HashTable *ht, HashTable *source, zend_class_entry *old_ce)
281 {
282 Bucket *p, *q, *end;
283 zend_ulong nIndex;
284 zend_property_info *prop_info;
285
286 ht->nTableSize = source->nTableSize;
287 ht->nTableMask = source->nTableMask;
288 ht->nNumUsed = 0;
289 ht->nNumOfElements = source->nNumOfElements;
290 ht->nNextFreeElement = source->nNextFreeElement;
291 ht->pDestructor = NULL;
292 HT_FLAGS(ht) = (HT_FLAGS(source) & (HASH_FLAG_INITIALIZED | HASH_FLAG_STATIC_KEYS));
293 ht->nInternalPointer = 0;
294
295 if (!(HT_FLAGS(ht) & HASH_FLAG_INITIALIZED)) {
296 ht->arData = source->arData;
297 return;
298 }
299
300 ZEND_ASSERT(!(HT_FLAGS(source) & HASH_FLAG_PACKED));
301 HT_SET_DATA_ADDR(ht, emalloc(HT_SIZE(ht)));
302 HT_HASH_RESET(ht);
303
304 p = source->arData;
305 end = p + source->nNumUsed;
306 for (; p != end; p++) {
307 ZEND_ASSERT(Z_TYPE(p->val) != IS_UNDEF);
308
309 nIndex = p->h | ht->nTableMask;
310
311 /* Insert into hash collision list */
312 q = ht->arData + ht->nNumUsed;
313 Z_NEXT(q->val) = HT_HASH(ht, nIndex);
314 HT_HASH(ht, nIndex) = HT_IDX_TO_HASH(ht->nNumUsed++);
315
316 /* Initialize key */
317 q->h = p->h;
318 ZEND_ASSERT(p->key != NULL);
319 q->key = p->key;
320
321 /* Copy data */
322 prop_info = ARENA_REALLOC(Z_PTR(p->val));
323 ZVAL_PTR(&q->val, prop_info);
324
325 if ((void*)prop_info->ce >= ZCG(current_persistent_script)->arena_mem &&
326 (void*)prop_info->ce < (void*)((char*)ZCG(current_persistent_script)->arena_mem + ZCG(current_persistent_script)->arena_size)) {
327 prop_info->ce = ARENA_REALLOC(prop_info->ce);
328 }
329 }
330 }
331
332 #define zend_update_inherited_handler(handler) \
333 { \
334 if (ce->handler != NULL) { \
335 ce->handler = ARENA_REALLOC(ce->handler); \
336 } \
337 }
338
339 /* Protects class' refcount, copies default properties, functions and class name */
zend_class_copy_ctor(zend_class_entry ** pce)340 static void zend_class_copy_ctor(zend_class_entry **pce)
341 {
342 zend_class_entry *ce = *pce;
343 zend_class_entry *old_ce = ce;
344 zval *src, *dst, *end;
345
346 *pce = ce = ARENA_REALLOC(old_ce);
347 ce->refcount = 1;
348
349 if (ce->parent) {
350 ce->parent = ARENA_REALLOC(ce->parent);
351 }
352
353 if (old_ce->default_properties_table) {
354 ce->default_properties_table = emalloc(sizeof(zval) * old_ce->default_properties_count);
355 src = old_ce->default_properties_table;
356 end = src + old_ce->default_properties_count;
357 dst = ce->default_properties_table;
358 for (; src != end; src++, dst++) {
359 ZVAL_COPY_VALUE(dst, src);
360 zend_clone_zval(dst);
361 }
362 }
363
364 zend_hash_clone_methods(&ce->function_table, &old_ce->function_table, old_ce, ce);
365
366 /* static members */
367 if (old_ce->default_static_members_table) {
368 int i, end;
369 zend_class_entry *parent = ce->parent;
370
371 ce->default_static_members_table = emalloc(sizeof(zval) * old_ce->default_static_members_count);
372 i = ce->default_static_members_count - 1;
373
374 /* Copy static properties in this class */
375 end = parent ? parent->default_static_members_count : 0;
376 for (; i >= end; i--) {
377 zval *p = &ce->default_static_members_table[i];
378 ZVAL_COPY_VALUE(p, &old_ce->default_static_members_table[i]);
379 zend_clone_zval(p);
380 }
381
382 /* Create indirections to static properties from parent classes */
383 while (parent && parent->default_static_members_table) {
384 end = parent->parent ? parent->parent->default_static_members_count : 0;
385 for (; i >= end; i--) {
386 zval *p = &ce->default_static_members_table[i];
387 ZVAL_INDIRECT(p, &parent->default_static_members_table[i]);
388 }
389
390 parent = parent->parent;
391 }
392 }
393 ce->static_members_table = ce->default_static_members_table;
394
395 /* properties_info */
396 zend_hash_clone_prop_info(&ce->properties_info, &old_ce->properties_info, old_ce);
397
398 /* constants table */
399 zend_hash_clone_constants(&ce->constants_table, &old_ce->constants_table);
400
401 /* interfaces aren't really implemented, so we create a new table */
402 if (ce->num_interfaces) {
403 ce->interfaces = emalloc(sizeof(zend_class_entry *) * ce->num_interfaces);
404 memset(ce->interfaces, 0, sizeof(zend_class_entry *) * ce->num_interfaces);
405 } else {
406 ce->interfaces = NULL;
407 }
408
409 zend_update_inherited_handler(constructor);
410 zend_update_inherited_handler(destructor);
411 zend_update_inherited_handler(clone);
412 zend_update_inherited_handler(__get);
413 zend_update_inherited_handler(__set);
414 zend_update_inherited_handler(__call);
415 /* 5.1 stuff */
416 zend_update_inherited_handler(serialize_func);
417 zend_update_inherited_handler(unserialize_func);
418 zend_update_inherited_handler(__isset);
419 zend_update_inherited_handler(__unset);
420 /* 5.2 stuff */
421 zend_update_inherited_handler(__tostring);
422
423 /* 5.3 stuff */
424 zend_update_inherited_handler(__callstatic);
425 zend_update_inherited_handler(__debugInfo);
426
427 /* 5.4 traits */
428 if (ce->trait_aliases) {
429 zend_trait_alias **trait_aliases;
430 int i = 0;
431
432 while (ce->trait_aliases[i]) {
433 i++;
434 }
435 trait_aliases = emalloc(sizeof(zend_trait_alias*) * (i + 1));
436 i = 0;
437 while (ce->trait_aliases[i]) {
438 trait_aliases[i] = emalloc(sizeof(zend_trait_alias));
439 memcpy(trait_aliases[i], ce->trait_aliases[i], sizeof(zend_trait_alias));
440 i++;
441 }
442 trait_aliases[i] = NULL;
443 ce->trait_aliases = trait_aliases;
444 }
445
446 if (ce->trait_precedences) {
447 zend_trait_precedence **trait_precedences;
448 int i = 0;
449
450 while (ce->trait_precedences[i]) {
451 i++;
452 }
453 trait_precedences = emalloc(sizeof(zend_trait_precedence*) * (i + 1));
454 i = 0;
455 while (ce->trait_precedences[i]) {
456 trait_precedences[i] = emalloc(sizeof(zend_trait_precedence) + (ce->trait_precedences[i]->num_excludes - 1) * sizeof(zend_string*));
457 memcpy(trait_precedences[i], ce->trait_precedences[i], sizeof(zend_trait_precedence) + (ce->trait_precedences[i]->num_excludes - 1) * sizeof(zend_string*));
458 i++;
459 }
460 trait_precedences[i] = NULL;
461 ce->trait_precedences = trait_precedences;
462 }
463 }
464
zend_accel_function_hash_copy(HashTable * target,HashTable * source)465 static void zend_accel_function_hash_copy(HashTable *target, HashTable *source)
466 {
467 zend_function *function1, *function2;
468 Bucket *p, *end;
469 zval *t;
470
471 zend_hash_extend(target, target->nNumUsed + source->nNumUsed, 0);
472 p = source->arData;
473 end = p + source->nNumUsed;
474 for (; p != end; p++) {
475 ZEND_ASSERT(Z_TYPE(p->val) != IS_UNDEF);
476 ZEND_ASSERT(p->key);
477 t = zend_hash_find_ex(target, p->key, 1);
478 if (UNEXPECTED(t != NULL)) {
479 if (EXPECTED(ZSTR_LEN(p->key) > 0) && EXPECTED(ZSTR_VAL(p->key)[0] == 0)) {
480 /* Mangled key */
481 t = zend_hash_update(target, p->key, &p->val);
482 } else {
483 goto failure;
484 }
485 } else {
486 _zend_hash_append_ptr(target, p->key, Z_PTR(p->val));
487 }
488 }
489 target->nInternalPointer = 0;
490 return;
491
492 failure:
493 function1 = Z_PTR(p->val);
494 function2 = Z_PTR_P(t);
495 CG(in_compilation) = 1;
496 zend_set_compiled_filename(function1->op_array.filename);
497 CG(zend_lineno) = function1->op_array.opcodes[0].lineno;
498 if (function2->type == ZEND_USER_FUNCTION
499 && function2->op_array.last > 0) {
500 zend_error(E_ERROR, "Cannot redeclare %s() (previously declared in %s:%d)",
501 ZSTR_VAL(function1->common.function_name),
502 ZSTR_VAL(function2->op_array.filename),
503 (int)function2->op_array.opcodes[0].lineno);
504 } else {
505 zend_error(E_ERROR, "Cannot redeclare %s()", ZSTR_VAL(function1->common.function_name));
506 }
507 }
508
zend_accel_function_hash_copy_from_shm(HashTable * target,HashTable * source)509 static void zend_accel_function_hash_copy_from_shm(HashTable *target, HashTable *source)
510 {
511 zend_function *function1, *function2;
512 Bucket *p, *end;
513 zval *t;
514
515 zend_hash_extend(target, target->nNumUsed + source->nNumUsed, 0);
516 p = source->arData;
517 end = p + source->nNumUsed;
518 for (; p != end; p++) {
519 ZEND_ASSERT(Z_TYPE(p->val) != IS_UNDEF);
520 ZEND_ASSERT(p->key);
521 t = zend_hash_find_ex(target, p->key, 1);
522 if (UNEXPECTED(t != NULL)) {
523 if (EXPECTED(ZSTR_LEN(p->key) > 0) && EXPECTED(ZSTR_VAL(p->key)[0] == 0)) {
524 /* Mangled key */
525 zend_hash_update_ptr(target, p->key, Z_PTR(p->val));
526 } else {
527 goto failure;
528 }
529 } else {
530 _zend_hash_append_ptr_ex(target, p->key, Z_PTR(p->val), 1);
531 }
532 }
533 target->nInternalPointer = 0;
534 return;
535
536 failure:
537 function1 = Z_PTR(p->val);
538 function2 = Z_PTR_P(t);
539 CG(in_compilation) = 1;
540 zend_set_compiled_filename(function1->op_array.filename);
541 CG(zend_lineno) = function1->op_array.opcodes[0].lineno;
542 if (function2->type == ZEND_USER_FUNCTION
543 && function2->op_array.last > 0) {
544 zend_error(E_ERROR, "Cannot redeclare %s() (previously declared in %s:%d)",
545 ZSTR_VAL(function1->common.function_name),
546 ZSTR_VAL(function2->op_array.filename),
547 (int)function2->op_array.opcodes[0].lineno);
548 } else {
549 zend_error(E_ERROR, "Cannot redeclare %s()", ZSTR_VAL(function1->common.function_name));
550 }
551 }
552
zend_accel_class_hash_copy(HashTable * target,HashTable * source)553 static void zend_accel_class_hash_copy(HashTable *target, HashTable *source)
554 {
555 Bucket *p, *end;
556 zval *t;
557
558 zend_hash_extend(target, target->nNumUsed + source->nNumUsed, 0);
559 p = source->arData;
560 end = p + source->nNumUsed;
561 for (; p != end; p++) {
562 if (UNEXPECTED(Z_TYPE(p->val) == IS_UNDEF)) continue;
563 ZEND_ASSERT(p->key);
564 t = zend_hash_find_ex(target, p->key, 1);
565 if (UNEXPECTED(t != NULL)) {
566 if (EXPECTED(ZSTR_LEN(p->key) > 0) && EXPECTED(ZSTR_VAL(p->key)[0] == 0)) {
567 /* Mangled key - ignore and wait for runtime */
568 continue;
569 } else if (UNEXPECTED(!ZCG(accel_directives).ignore_dups)) {
570 zend_class_entry *ce1 = Z_PTR(p->val);
571 if (!(ce1->ce_flags & ZEND_ACC_ANON_CLASS)) {
572 CG(in_compilation) = 1;
573 zend_set_compiled_filename(ce1->info.user.filename);
574 CG(zend_lineno) = ce1->info.user.line_start;
575 zend_error(E_ERROR,
576 "Cannot declare %s %s, because the name is already in use",
577 zend_get_object_type(ce1), ZSTR_VAL(ce1->name));
578 return;
579 }
580 continue;
581 }
582 } else {
583 t = _zend_hash_append_ptr(target, p->key, Z_PTR(p->val));
584 }
585 }
586 target->nInternalPointer = 0;
587 return;
588 }
589
zend_accel_class_hash_copy_from_shm(HashTable * target,HashTable * source)590 static void zend_accel_class_hash_copy_from_shm(HashTable *target, HashTable *source)
591 {
592 Bucket *p, *end;
593 zval *t;
594
595 zend_hash_extend(target, target->nNumUsed + source->nNumUsed, 0);
596 p = source->arData;
597 end = p + source->nNumUsed;
598 for (; p != end; p++) {
599 ZEND_ASSERT(Z_TYPE(p->val) != IS_UNDEF);
600 ZEND_ASSERT(p->key);
601 t = zend_hash_find_ex(target, p->key, 1);
602 if (UNEXPECTED(t != NULL)) {
603 if (EXPECTED(ZSTR_LEN(p->key) > 0) && EXPECTED(ZSTR_VAL(p->key)[0] == 0)) {
604 /* Mangled key - ignore and wait for runtime */
605 continue;
606 } else if (UNEXPECTED(!ZCG(accel_directives).ignore_dups)) {
607 zend_class_entry *ce1 = Z_PTR(p->val);
608 if (!(ce1->ce_flags & ZEND_ACC_ANON_CLASS)) {
609 CG(in_compilation) = 1;
610 zend_set_compiled_filename(ce1->info.user.filename);
611 CG(zend_lineno) = ce1->info.user.line_start;
612 zend_error(E_ERROR,
613 "Cannot declare %s %s, because the name is already in use",
614 zend_get_object_type(ce1), ZSTR_VAL(ce1->name));
615 return;
616 }
617 continue;
618 }
619 } else {
620 t = _zend_hash_append_ptr_ex(target, p->key, Z_PTR(p->val), 1);
621 zend_class_copy_ctor((zend_class_entry**)&Z_PTR_P(t));
622 }
623 }
624 target->nInternalPointer = 0;
625 return;
626 }
627
628 #if defined(__AVX__)
629 # include <nmmintrin.h>
630 # if defined(__GNUC__) && defined(__i386__)
fast_memcpy(void * dest,const void * src,size_t size)631 static zend_always_inline void fast_memcpy(void *dest, const void *src, size_t size)
632 {
633 size_t delta = (char*)dest - (char*)src;
634
635 __asm__ volatile (
636 ".align 16\n\t"
637 ".LL0%=:\n\t"
638 "prefetchnta 0x40(%1)\n\t"
639 "vmovaps (%1), %%ymm0\n\t"
640 "vmovaps 0x20(%1), %%ymm1\n\t"
641 "vmovaps %%ymm0, (%1,%2)\n\t"
642 "vmovaps %%ymm1, 0x20(%1,%2)\n\t"
643 "addl $0x40, %1\n\t"
644 "subl $0x40, %0\n\t"
645 "ja .LL0%="
646 : "+r"(size),
647 "+r"(src)
648 : "r"(delta)
649 : "cc", "memory", "%ymm0", "%ymm1");
650 }
651 # elif defined(__GNUC__) && defined(__x86_64__)
fast_memcpy(void * dest,const void * src,size_t size)652 static zend_always_inline void fast_memcpy(void *dest, const void *src, size_t size)
653 {
654 size_t delta = (char*)dest - (char*)src;
655
656 __asm__ volatile (
657 ".align 16\n\t"
658 ".LL0%=:\n\t"
659 "prefetchnta 0x40(%1)\n\t"
660 "vmovaps (%1), %%ymm0\n\t"
661 "vmovaps 0x20(%1), %%ymm1\n\t"
662 "vmovaps %%ymm0, (%1,%2)\n\t"
663 "vmovaps %%ymm1, 0x20(%1,%2)\n\t"
664 "addq $0x40, %1\n\t"
665 "subq $0x40, %0\n\t"
666 "ja .LL0%="
667 : "+r"(size),
668 "+r"(src)
669 : "r"(delta)
670 : "cc", "memory", "%ymm0", "%ymm1");
671 }
672 # else
fast_memcpy(void * dest,const void * src,size_t size)673 static zend_always_inline void fast_memcpy(void *dest, const void *src, size_t size)
674 {
675 __m256 *dqdest = (__m256*)dest;
676 const __m256 *dqsrc = (const __m256*)src;
677 const __m256 *end = (const __m256*)((const char*)src + size);
678
679 do {
680 #ifdef PHP_WIN32
681 _mm_prefetch((const char *)(dqsrc + 2), _MM_HINT_NTA);
682 #else
683 _mm_prefetch(dqsrc + 2, _MM_HINT_NTA);
684 #endif
685
686 __m256 ymm0 = _mm256_load_ps((const float *)(dqsrc + 0));
687 __m256 ymm1 = _mm256_load_ps((const float *)(dqsrc + 1));
688 dqsrc += 2;
689 _mm256_store_ps((float *)(dqdest + 0), ymm0);
690 _mm256_store_ps((float *)(dqdest + 1), ymm1);
691 dqdest += 2;
692 } while (dqsrc != end);
693 }
694 # endif
695 #elif defined(__SSE2__)
696 # include <emmintrin.h>
697 # if defined(__GNUC__) && defined(__i386__)
fast_memcpy(void * dest,const void * src,size_t size)698 static zend_always_inline void fast_memcpy(void *dest, const void *src, size_t size)
699 {
700 size_t delta = (char*)dest - (char*)src;
701
702 __asm__ volatile (
703 ".align 16\n\t"
704 ".LL0%=:\n\t"
705 "prefetchnta 0x40(%1)\n\t"
706 "movdqa (%1), %%xmm0\n\t"
707 "movdqa 0x10(%1), %%xmm1\n\t"
708 "movdqa 0x20(%1), %%xmm2\n\t"
709 "movdqa 0x30(%1), %%xmm3\n\t"
710 "movdqa %%xmm0, (%1,%2)\n\t"
711 "movdqa %%xmm1, 0x10(%1,%2)\n\t"
712 "movdqa %%xmm2, 0x20(%1,%2)\n\t"
713 "movdqa %%xmm3, 0x30(%1,%2)\n\t"
714 "addl $0x40, %1\n\t"
715 "subl $0x40, %0\n\t"
716 "ja .LL0%="
717 : "+r"(size),
718 "+r"(src)
719 : "r"(delta)
720 : "cc", "memory", "%xmm0", "%xmm1", "%xmm1", "%xmm2");
721 }
722 # elif defined(__GNUC__) && defined(__x86_64__) && !defined(__ILP32__)
fast_memcpy(void * dest,const void * src,size_t size)723 static zend_always_inline void fast_memcpy(void *dest, const void *src, size_t size)
724 {
725 size_t delta = (char*)dest - (char*)src;
726
727 __asm__ volatile (
728 ".align 16\n\t"
729 ".LL0%=:\n\t"
730 "prefetchnta 0x40(%1)\n\t"
731 "movdqa (%1), %%xmm0\n\t"
732 "movdqa 0x10(%1), %%xmm1\n\t"
733 "movdqa 0x20(%1), %%xmm2\n\t"
734 "movdqa 0x30(%1), %%xmm3\n\t"
735 "movdqa %%xmm0, (%1,%2)\n\t"
736 "movdqa %%xmm1, 0x10(%1,%2)\n\t"
737 "movdqa %%xmm2, 0x20(%1,%2)\n\t"
738 "movdqa %%xmm3, 0x30(%1,%2)\n\t"
739 "addq $0x40, %1\n\t"
740 "subq $0x40, %0\n\t"
741 "ja .LL0%="
742 : "+r"(size),
743 "+r"(src)
744 : "r"(delta)
745 : "cc", "memory", "%xmm0", "%xmm1", "%xmm1", "%xmm2");
746 }
747 # else
fast_memcpy(void * dest,const void * src,size_t size)748 static zend_always_inline void fast_memcpy(void *dest, const void *src, size_t size)
749 {
750 __m128i *dqdest = (__m128i*)dest;
751 const __m128i *dqsrc = (const __m128i*)src;
752 const __m128i *end = (const __m128i*)((const char*)src + size);
753
754 do {
755 #ifdef PHP_WIN32
756 _mm_prefetch((const char *)(dqsrc + 4), _MM_HINT_NTA);
757 #else
758 _mm_prefetch(dqsrc + 4, _MM_HINT_NTA);
759 #endif
760
761 __m128i xmm0 = _mm_load_si128(dqsrc + 0);
762 __m128i xmm1 = _mm_load_si128(dqsrc + 1);
763 __m128i xmm2 = _mm_load_si128(dqsrc + 2);
764 __m128i xmm3 = _mm_load_si128(dqsrc + 3);
765 dqsrc += 4;
766 _mm_store_si128(dqdest + 0, xmm0);
767 _mm_store_si128(dqdest + 1, xmm1);
768 _mm_store_si128(dqdest + 2, xmm2);
769 _mm_store_si128(dqdest + 3, xmm3);
770 dqdest += 4;
771 } while (dqsrc != end);
772 }
773 # endif
774 #endif
775
zend_accel_load_script(zend_persistent_script * persistent_script,int from_shared_memory)776 zend_op_array* zend_accel_load_script(zend_persistent_script *persistent_script, int from_shared_memory)
777 {
778 zend_op_array *op_array;
779
780 op_array = (zend_op_array *) emalloc(sizeof(zend_op_array));
781 *op_array = persistent_script->script.main_op_array;
782
783 if (EXPECTED(from_shared_memory)) {
784 zend_hash_init(&ZCG(bind_hash), 10, NULL, NULL, 0);
785
786 ZCG(current_persistent_script) = persistent_script;
787 ZCG(arena_mem) = NULL;
788 if (EXPECTED(persistent_script->arena_size)) {
789 #if defined(__AVX__) || defined(__SSE2__)
790 /* Target address must be aligned to 64-byte boundary */
791 _mm_prefetch(persistent_script->arena_mem, _MM_HINT_NTA);
792 ZCG(arena_mem) = zend_arena_alloc(&CG(arena), persistent_script->arena_size + 64);
793 ZCG(arena_mem) = (void*)(((zend_uintptr_t)ZCG(arena_mem) + 63L) & ~63L);
794 fast_memcpy(ZCG(arena_mem), persistent_script->arena_mem, persistent_script->arena_size);
795 #else
796 ZCG(arena_mem) = zend_arena_alloc(&CG(arena), persistent_script->arena_size);
797 memcpy(ZCG(arena_mem), persistent_script->arena_mem, persistent_script->arena_size);
798 #endif
799 }
800
801 /* Copy all the necessary stuff from shared memory to regular memory, and protect the shared script */
802 if (zend_hash_num_elements(&persistent_script->script.class_table) > 0) {
803 zend_accel_class_hash_copy_from_shm(CG(class_table), &persistent_script->script.class_table);
804 }
805 /* we must first to copy all classes and then prepare functions, since functions may try to bind
806 classes - which depend on pre-bind class entries existent in the class table */
807 if (zend_hash_num_elements(&persistent_script->script.function_table) > 0) {
808 zend_accel_function_hash_copy_from_shm(CG(function_table), &persistent_script->script.function_table);
809 }
810
811 /* Register __COMPILER_HALT_OFFSET__ constant */
812 if (persistent_script->compiler_halt_offset != 0 &&
813 persistent_script->script.filename) {
814 zend_string *name;
815 static const char haltoff[] = "__COMPILER_HALT_OFFSET__";
816
817 name = zend_mangle_property_name(haltoff, sizeof(haltoff) - 1, ZSTR_VAL(persistent_script->script.filename), ZSTR_LEN(persistent_script->script.filename), 0);
818 if (!zend_hash_exists(EG(zend_constants), name)) {
819 zend_register_long_constant(ZSTR_VAL(name), ZSTR_LEN(name), persistent_script->compiler_halt_offset, CONST_CS, 0);
820 }
821 zend_string_release_ex(name, 0);
822 }
823
824 zend_hash_destroy(&ZCG(bind_hash));
825 ZCG(current_persistent_script) = NULL;
826 } else /* if (!from_shared_memory) */ {
827 if (zend_hash_num_elements(&persistent_script->script.function_table) > 0) {
828 zend_accel_function_hash_copy(CG(function_table), &persistent_script->script.function_table);
829 }
830 if (zend_hash_num_elements(&persistent_script->script.class_table) > 0) {
831 zend_accel_class_hash_copy(CG(class_table), &persistent_script->script.class_table);
832 }
833 }
834
835 if (persistent_script->script.first_early_binding_opline != (uint32_t)-1) {
836 zend_string *orig_compiled_filename = CG(compiled_filename);
837 CG(compiled_filename) = persistent_script->script.filename;
838 zend_do_delayed_early_binding(op_array, persistent_script->script.first_early_binding_opline);
839 CG(compiled_filename) = orig_compiled_filename;
840 }
841
842 if (UNEXPECTED(!from_shared_memory)) {
843 free_persistent_script(persistent_script, 0); /* free only hashes */
844 }
845
846 return op_array;
847 }
848
849 /*
850 * zend_adler32() is based on zlib implementation
851 * Computes the Adler-32 checksum of a data stream
852 *
853 * Copyright (C) 1995-2005 Mark Adler
854 * For conditions of distribution and use, see copyright notice in zlib.h
855 *
856 * Copyright (C) 1995-2005 Jean-loup Gailly and Mark Adler
857 *
858 * This software is provided 'as-is', without any express or implied
859 * warranty. In no event will the authors be held liable for any damages
860 * arising from the use of this software.
861 *
862 * Permission is granted to anyone to use this software for any purpose,
863 * including commercial applications, and to alter it and redistribute it
864 * freely, subject to the following restrictions:
865 *
866 * 1. The origin of this software must not be misrepresented; you must not
867 * claim that you wrote the original software. If you use this software
868 * in a product, an acknowledgment in the product documentation would be
869 * appreciated but is not required.
870 * 2. Altered source versions must be plainly marked as such, and must not be
871 * misrepresented as being the original software.
872 * 3. This notice may not be removed or altered from any source distribution.
873 *
874 */
875
876 #define ADLER32_BASE 65521 /* largest prime smaller than 65536 */
877 #define ADLER32_NMAX 5552
878 /* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
879
880 #define ADLER32_DO1(buf) {s1 += *(buf); s2 += s1;}
881 #define ADLER32_DO2(buf, i) ADLER32_DO1(buf + i); ADLER32_DO1(buf + i + 1);
882 #define ADLER32_DO4(buf, i) ADLER32_DO2(buf, i); ADLER32_DO2(buf, i + 2);
883 #define ADLER32_DO8(buf, i) ADLER32_DO4(buf, i); ADLER32_DO4(buf, i + 4);
884 #define ADLER32_DO16(buf) ADLER32_DO8(buf, 0); ADLER32_DO8(buf, 8);
885
zend_adler32(unsigned int checksum,unsigned char * buf,uint32_t len)886 unsigned int zend_adler32(unsigned int checksum, unsigned char *buf, uint32_t len)
887 {
888 unsigned int s1 = checksum & 0xffff;
889 unsigned int s2 = (checksum >> 16) & 0xffff;
890 unsigned char *end;
891
892 while (len >= ADLER32_NMAX) {
893 len -= ADLER32_NMAX;
894 end = buf + ADLER32_NMAX;
895 do {
896 ADLER32_DO16(buf);
897 buf += 16;
898 } while (buf != end);
899 s1 %= ADLER32_BASE;
900 s2 %= ADLER32_BASE;
901 }
902
903 if (len) {
904 if (len >= 16) {
905 end = buf + (len & 0xfff0);
906 len &= 0xf;
907 do {
908 ADLER32_DO16(buf);
909 buf += 16;
910 } while (buf != end);
911 }
912 if (len) {
913 end = buf + len;
914 do {
915 ADLER32_DO1(buf);
916 buf++;
917 } while (buf != end);
918 }
919 s1 %= ADLER32_BASE;
920 s2 %= ADLER32_BASE;
921 }
922
923 return (s2 << 16) | s1;
924 }
925
zend_accel_script_checksum(zend_persistent_script * persistent_script)926 unsigned int zend_accel_script_checksum(zend_persistent_script *persistent_script)
927 {
928 unsigned char *mem = (unsigned char*)persistent_script->mem;
929 size_t size = persistent_script->size;
930 size_t persistent_script_check_block_size = ((char *)&(persistent_script->dynamic_members)) - (char *)persistent_script;
931 unsigned int checksum = ADLER32_INIT;
932
933 if (mem < (unsigned char*)persistent_script) {
934 checksum = zend_adler32(checksum, mem, (unsigned char*)persistent_script - mem);
935 size -= (unsigned char*)persistent_script - mem;
936 mem += (unsigned char*)persistent_script - mem;
937 }
938
939 zend_adler32(checksum, mem, persistent_script_check_block_size);
940 mem += sizeof(*persistent_script);
941 size -= sizeof(*persistent_script);
942
943 if (size > 0) {
944 checksum = zend_adler32(checksum, mem, size);
945 }
946 return checksum;
947 }
948