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