2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2006 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: Daniel Cowgill <dcowgill@communityconnect.com> |
16 | Rasmus Lerdorf <rasmus@php.net> |
17 | Arun C. Murthy <arunc@yahoo-inc.com> |
18 | Gopal Vijayaraghavan <gopalv@yahoo-inc.com> |
19 +----------------------------------------------------------------------+
21 This software was contributed to PHP by Community Connect Inc. in 2002
22 and revised in 2005 by Yahoo! Inc. to add support for PHP 5.1.
23 Future revisions and derivatives of this source code must acknowledge
24 Community Connect Inc. as the original contributor of this module by
25 leaving this note intact in the source code.
27 All other licensing and usage conditions are those of the PHP Group.
31 /* $Id: apc_compile.c,v 3.87.2.4 2008/03/28 21:05:14 rasmus Exp $ */
33 #include "apc_compile.h"
34 #include "apc_globals.h"
38 #define Z_REFCOUNT_P(pz) (pz)->refcount
39 #define Z_REFCOUNT_PP(ppz) Z_REFCOUNT_P(*(ppz))
42 #ifndef Z_SET_REFCOUNT_P
43 #define Z_SET_REFCOUNT_P(pz, rc) (pz)->refcount = rc
44 #define Z_SET_REFCOUNT_PP(ppz, rc) Z_SET_REFCOUNT_P(*(ppz), rc)
48 #define Z_ADDREF_P(pz) (pz)->refcount++
49 #define Z_ADDREF_PP(ppz) Z_ADDREF_P(*(ppz))
53 #define Z_DELREF_P(pz) (pz)->refcount--
54 #define Z_DELREF_PP(ppz) Z_DELREF_P(*(ppz))
58 #define Z_ISREF_P(pz) (pz)->is_ref
59 #define Z_ISREF_PP(ppz) Z_ISREF_P(*(ppz))
63 #define Z_SET_ISREF_P(pz) (pz)->is_ref = 1
64 #define Z_SET_ISREF_PP(ppz) Z_SET_ISREF_P(*(ppz))
67 #ifndef Z_UNSET_ISREF_P
68 #define Z_UNSET_ISREF_P(pz) (pz)->is_ref = 0
69 #define Z_UNSET_ISREF_PP(ppz) Z_UNSET_ISREF_P(*(ppz))
72 #ifndef Z_SET_ISREF_TO_P
73 #define Z_SET_ISREF_TO_P(pz, isref) (pz)->is_ref = isref
74 #define Z_SET_ISREF_TO_PP(ppz, isref) Z_SET_ISREF_TO_P(*(ppz), isref)
77 typedef void* (*ht_copy_fun_t)(void*, void*, apc_malloc_t, apc_free_t);
78 typedef void (*ht_free_fun_t)(void*, apc_free_t);
79 typedef int (*ht_check_copy_fun_t)(Bucket*, va_list);
82 typedef void (*ht_fixup_fun_t)(Bucket*, zend_class_entry*, zend_class_entry*);
85 #define CHECK(p) { if ((p) == NULL) return NULL; }
87 /* {{{ internal function declarations */
89 static int is_derived_class(zend_op_array* op_array, const char* key, int key_size);
91 static zend_function* my_bitwise_copy_function(zend_function*, zend_function*, apc_malloc_t);
94 * The "copy" functions perform deep-copies on a particular data structure
95 * (passed as the second argument). They also optionally allocate space for
96 * the destination data structure if the first argument is null.
98 static zval** my_copy_zval_ptr(zval**, const zval**, apc_malloc_t, apc_free_t);
99 static zval* my_copy_zval(zval*, const zval*, apc_malloc_t, apc_free_t);
100 static znode* my_copy_znode(znode*, znode*, apc_malloc_t, apc_free_t);
101 static zend_op* my_copy_zend_op(zend_op*, zend_op*, apc_malloc_t, apc_free_t);
102 static zend_function* my_copy_function(zend_function*, zend_function*, apc_malloc_t, apc_free_t);
103 static zend_function_entry* my_copy_function_entry(zend_function_entry*, zend_function_entry*, apc_malloc_t, apc_free_t);
104 static zend_class_entry* my_copy_class_entry(zend_class_entry*, zend_class_entry*, apc_malloc_t, apc_free_t);
105 static HashTable* my_copy_hashtable_ex(HashTable*, HashTable*, ht_copy_fun_t, ht_free_fun_t, int, apc_malloc_t, apc_free_t, ht_check_copy_fun_t, ...);
106 #define my_copy_hashtable( dst, src, copy_fn, free_fn, holds_ptr, allocate, deallocate) \
107 my_copy_hashtable_ex(dst, src, copy_fn, free_fn, holds_ptr, allocate, deallocate, NULL)
108 static HashTable* my_copy_static_variables(zend_op_array* src, apc_malloc_t allocate, apc_free_t deallocate);
110 static zend_property_info* my_copy_property_info(zend_property_info* dst, zend_property_info* src, apc_malloc_t allocate, apc_free_t deallocate);
111 static zend_arg_info* my_copy_arg_info_array(zend_arg_info*, zend_arg_info*, uint, apc_malloc_t, apc_free_t);
112 static zend_arg_info* my_copy_arg_info(zend_arg_info*, zend_arg_info*, apc_malloc_t, apc_free_t);
115 * The "destroy" functions free the memory associated with a particular data
116 * structure but do not free the pointer to the data structure.
118 * my_destroy_zval() returns SUCCESS or FAILURE, FAILURE means that
119 * the zval* has other references elsewhere
121 static int my_destroy_zval(zval*, apc_free_t);
122 static void my_destroy_zval_ptr(zval**, apc_free_t);
123 static void my_destroy_zend_op(zend_op*, apc_free_t);
124 static void my_destroy_znode(znode*, apc_free_t);
125 static void my_destroy_function(zend_function*, apc_free_t);
126 static void my_destroy_function_entry(zend_function_entry*, apc_free_t);
127 static void my_destroy_class_entry(zend_class_entry*, apc_free_t);
128 static void my_destroy_hashtable(HashTable*, ht_free_fun_t, apc_free_t);
129 static void my_destroy_op_array(zend_op_array*, apc_free_t);
131 static void my_destroy_property_info(zend_property_info*, apc_free_t);
132 static void my_destroy_arg_info_array(zend_arg_info* src, uint, apc_free_t);
133 static void my_destroy_arg_info(zend_arg_info*, apc_free_t);
137 * The "free" functions work exactly like their "destroy" counterparts (see
138 * above) but also free the pointer to the data structure.
140 static void my_free_zval_ptr(zval**, apc_free_t);
141 static void my_free_function(zend_function*, apc_free_t);
142 static void my_free_hashtable(HashTable*, ht_free_fun_t, apc_free_t);
144 static void my_free_property_info(zend_property_info* src, apc_free_t);
145 static void my_free_arg_info_array(zend_arg_info*, uint, apc_free_t);
146 static void my_free_arg_info(zend_arg_info*, apc_free_t);
150 * The "fixup" functions need for ZEND_ENGINE_2
153 static void my_fixup_function( Bucket *p, zend_class_entry *src, zend_class_entry *dst );
154 static void my_fixup_hashtable( HashTable *ht, ht_fixup_fun_t fixup, zend_class_entry *src, zend_class_entry *dst );
155 /* my_fixup_function_for_execution is the same as my_fixup_function
156 * but named differently for clarity
158 #define my_fixup_function_for_execution my_fixup_function
160 #ifdef ZEND_ENGINE_2_2
161 static void my_fixup_property_info( Bucket *p, zend_class_entry *src, zend_class_entry *dst );
162 #define my_fixup_property_info_for_execution my_fixup_property_info
168 * These functions return "1" if the member/function is
169 * defined/overridden in the 'current' class and not inherited.
171 static int my_check_copy_function(Bucket* src, va_list args);
172 static int my_check_copy_default_property(Bucket* p, va_list args);
174 static int my_check_copy_property_info(Bucket* src, va_list args);
175 static int my_check_copy_static_member(Bucket* src, va_list args);
180 /* {{{ check_op_array_integrity */
182 static void check_op_array_integrity(zend_op_array* src)
186 /* These sorts of checks really aren't particularly effective, but they
187 * can provide a welcome sanity check when debugging. Just don't enable
188 * for production use! */
190 assert(src->refcount != NULL);
191 assert(src->opcodes != NULL);
192 assert(src->last > 0);
194 for (i = 0; i < src->last; i++) {
195 zend_op* op = &src->opcodes[i];
196 znode* nodes[] = { &op->result, &op->op1, &op->op2 };
197 for (j = 0; j < 3; j++) {
198 assert(nodes[j]->op_type == IS_CONST ||
199 nodes[j]->op_type == IS_VAR ||
200 nodes[j]->op_type == IS_TMP_VAR ||
201 nodes[j]->op_type == IS_UNUSED);
203 if (nodes[j]->op_type == IS_CONST) {
204 int type = nodes[j]->u.constant.type;
205 assert(type == IS_RESOURCE ||
210 type == IS_CONSTANT ||
212 type == FLAG_IS_BC ||
214 type == IS_CONSTANT_ARRAY ||
223 /* {{{ is_derived_class */
224 static int is_derived_class(zend_op_array* op_array, const char* key, int key_size)
229 * Scan the op_array for execution-time class declarations of derived
230 * classes. If we find one whose key matches our current class key, we
231 * know the current class is a derived class.
233 * This check is exceedingly inefficient (fortunately it only has to occur
234 * once, when the source file is first compiled and cached), but the
235 * compiler should save this information for us -- definitely a candidate
236 * for a Zend Engine patch.
238 * XXX checking for derived classes provides a minimal (albeit measurable)
239 * speed up. It may not be worth the added complexity -- considere
240 * removing this optimization.
243 for (i = 0; i < op_array->last; i++) {
244 zend_op* op = &op_array->opcodes[i];
247 if (op->opcode == ZEND_DECLARE_CLASS &&
248 op->extended_value == ZEND_DECLARE_INHERITED_CLASS)
250 if (op->opcode == ZEND_DECLARE_FUNCTION_OR_CLASS &&
251 op->extended_value == ZEND_DECLARE_INHERITED_CLASS)
254 if (op->op1.u.constant.value.str.len == key_size &&
255 !memcmp(op->op1.u.constant.value.str.val, key, key_size))
266 /* {{{ my_bitwise_copy_function */
267 static zend_function* my_bitwise_copy_function(zend_function* dst, zend_function* src, apc_malloc_t allocate)
272 CHECK(dst = (zend_function*) allocate(sizeof(src[0])));
275 /* We only need to do a bitwise copy */
276 memcpy(dst, src, sizeof(src[0]));
282 /* {{{ my_copy_zval_ptr */
283 static zval** my_copy_zval_ptr(zval** dst, const zval** src, apc_malloc_t allocate, apc_free_t deallocate)
285 int local_dst_alloc = 0;
291 CHECK(dst = (zval**) allocate(sizeof(zval*)));
295 if(!(dst[0] = (zval*) allocate(sizeof(zval)))) {
296 if(local_dst_alloc) deallocate(dst);
299 if(!(dst_new = my_copy_zval(*dst, *src, allocate, deallocate))) {
300 if(local_dst_alloc) deallocate(dst);
303 if(dst_new != *dst) {
308 Z_SET_REFCOUNT_PP(dst, Z_REFCOUNT_PP(src));
309 Z_SET_ISREF_TO_PP(dst, Z_ISREF_PP(src));
315 /* {{{ my_copy_zval */
316 static zval* my_copy_zval(zval* dst, const zval* src, apc_malloc_t allocate, apc_free_t deallocate)
324 memcpy(dst, src, sizeof(src[0]));
326 switch (src->type & ~IS_CONSTANT_INDEX) {
336 #ifndef ZEND_ENGINE_2
339 if (src->value.str.val) {
340 CHECK(dst->value.str.val = apc_xmemcpy(src->value.str.val,
341 src->value.str.len+1,
348 if(APCG(copied_zvals)) {
349 if(zend_hash_index_find(APCG(copied_zvals), (ulong)src, (void**)&tmp) == SUCCESS) {
354 zend_hash_index_update(APCG(copied_zvals), (ulong)src, (void**)&dst, sizeof(zval*), NULL);
358 case IS_CONSTANT_ARRAY:
360 CHECK(dst->value.ht =
361 my_copy_hashtable(NULL,
363 (ht_copy_fun_t) my_copy_zval_ptr,
364 (ht_free_fun_t) my_free_zval_ptr,
366 allocate, deallocate));
370 #ifndef ZEND_ENGINE_2
371 CHECK(dst->value.obj.ce =
372 my_copy_class_entry(NULL, src->value.obj.ce, allocate, deallocate));
374 if(!(dst->value.obj.properties = my_copy_hashtable(NULL,
375 src->value.obj.properties,
376 (ht_copy_fun_t) my_copy_zval_ptr,
377 (ht_free_fun_t) my_free_zval_ptr,
379 allocate, deallocate))) {
380 my_destroy_class_entry(dst->value.obj.ce, deallocate);
397 /* {{{ my_copy_znode */
398 static znode* my_copy_znode(znode* dst, znode* src, apc_malloc_t allocate, apc_free_t deallocate)
403 memcpy(dst, src, sizeof(src[0]));
406 assert(dst ->op_type == IS_CONST ||
407 dst ->op_type == IS_VAR ||
408 dst ->op_type == IS_CV ||
409 dst ->op_type == IS_TMP_VAR ||
410 dst ->op_type == IS_UNUSED);
412 assert(dst ->op_type == IS_CONST ||
413 dst ->op_type == IS_VAR ||
414 dst ->op_type == IS_TMP_VAR ||
415 dst ->op_type == IS_UNUSED);
418 if (src->op_type == IS_CONST) {
419 if(!my_copy_zval(&dst->u.constant, &src->u.constant, allocate, deallocate)) {
428 /* {{{ my_copy_zend_op */
429 static zend_op* my_copy_zend_op(zend_op* dst, zend_op* src, apc_malloc_t allocate, apc_free_t deallocate)
434 memcpy(dst, src, sizeof(src[0]));
436 if( my_copy_znode(&dst->result, &src->result, allocate, deallocate) == NULL
437 || my_copy_znode(&dst->op1, &src->op1, allocate, deallocate) == NULL
438 || my_copy_znode(&dst->op2, &src->op2, allocate, deallocate) == NULL)
447 /* {{{ my_copy_function */
448 static zend_function* my_copy_function(zend_function* dst, zend_function* src, apc_malloc_t allocate, apc_free_t deallocate)
450 int local_dst_alloc = 0;
455 if(!dst) local_dst_alloc = 1;
456 CHECK(dst = my_bitwise_copy_function(dst, src, allocate));
459 case ZEND_INTERNAL_FUNCTION:
460 case ZEND_OVERLOADED_FUNCTION:
461 /* shallow copy because op_array is internal */
462 dst->op_array = src->op_array;
465 case ZEND_USER_FUNCTION:
467 if(!apc_copy_op_array(&dst->op_array,
469 allocate, deallocate TSRMLS_CC)) {
470 if(local_dst_alloc) deallocate(dst);
480 * op_array bitwise copying overwrites what ever you modified
481 * before apc_copy_op_array - which is why this code is outside
482 * my_bitwise_copy_function.
485 /* zend_do_inheritance will re-look this up, because the pointers
486 * in prototype are from a function table of another class. It just
487 * helps if that one is from EG(class_table).
489 dst->common.prototype = NULL;
491 /* once a method is marked as ZEND_ACC_IMPLEMENTED_ABSTRACT then you
492 * have to carry around a prototype. Thankfully zend_do_inheritance
493 * sets this properly as well
495 dst->common.fn_flags = src->common.fn_flags & (~ZEND_ACC_IMPLEMENTED_ABSTRACT);
503 /* {{{ my_copy_function_entry */
504 static zend_function_entry* my_copy_function_entry(zend_function_entry* dst, zend_function_entry* src, apc_malloc_t allocate, apc_free_t deallocate)
506 int local_dst_alloc = 0;
510 CHECK(dst = (zend_function_entry*) allocate(sizeof(src[0])));
514 /* Start with a bitwise copy */
515 memcpy(dst, src, sizeof(src[0]));
519 dst->arg_info = NULL;
521 dst->func_arg_types = NULL;
525 if(!(dst->fname = apc_xstrdup(src->fname, allocate))) {
532 if(!(dst->arg_info = my_copy_arg_info_array(NULL,
541 if (src->func_arg_types) {
542 if(!(dst->func_arg_types = apc_xmemcpy(src->func_arg_types,
543 src->func_arg_types[0]+1,
553 if(dst->fname) deallocate(dst->fname);
554 if(local_dst_alloc) deallocate(dst);
560 /* {{{ my_copy_property_info */
561 static zend_property_info* my_copy_property_info(zend_property_info* dst, zend_property_info* src, apc_malloc_t allocate, apc_free_t deallocate)
563 int local_dst_alloc = 0;
568 CHECK(dst = (zend_property_info*) allocate(sizeof(*src)));
572 /* Start with a bitwise copy */
573 memcpy(dst, src, sizeof(*src));
576 #if defined(ZEND_ENGINE_2) && PHP_MINOR_VERSION > 0
577 dst->doc_comment = NULL;
581 /* private members are stored inside property_info as a mangled
582 * string of the form:
583 * \0<classname>\0<membername>\0
586 apc_xmemcpy(src->name, src->name_length+1, allocate))) {
591 #if defined(ZEND_ENGINE_2) && PHP_MINOR_VERSION > 0
592 if (src->doc_comment) {
593 if( !(dst->doc_comment =
594 apc_xmemcpy(src->doc_comment, src->doc_comment_len+1, allocate))) {
603 if(dst->name) deallocate(dst->name);
604 #if defined(ZEND_ENGINE_2) && PHP_MINOR_VERSION > 0
605 if(dst->doc_comment) deallocate(dst->doc_comment);
607 if(local_dst_alloc) deallocate(dst);
612 /* {{{ my_copy_property_info_for_execution */
613 static zend_property_info* my_copy_property_info_for_execution(zend_property_info* dst, zend_property_info* src, apc_malloc_t allocate, apc_free_t deallocate)
615 int local_dst_alloc = 0;
620 CHECK(dst = (zend_property_info*) allocate(sizeof(*src)));
624 /* We need only a shallow copy */
625 memcpy(dst, src, sizeof(*src));
631 /* {{{ my_copy_arg_info_array */
632 static zend_arg_info* my_copy_arg_info_array(zend_arg_info* dst, zend_arg_info* src, uint num_args, apc_malloc_t allocate, apc_free_t deallocate)
634 int local_dst_alloc = 0;
639 CHECK(dst = (zend_arg_info*) allocate(sizeof(*src)*num_args));
643 /* Start with a bitwise copy */
644 memcpy(dst, src, sizeof(*src)*num_args);
646 for(i=0; i < num_args; i++) {
647 if(!(my_copy_arg_info( &dst[i], &src[i], allocate, deallocate))) {
648 if(i) my_destroy_arg_info_array(dst, i-1, deallocate);
649 if(local_dst_alloc) deallocate(dst);
658 /* {{{ my_copy_arg_info */
659 static zend_arg_info* my_copy_arg_info(zend_arg_info* dst, zend_arg_info* src, apc_malloc_t allocate, apc_free_t deallocate)
661 int local_dst_alloc = 0;
666 CHECK(dst = (zend_arg_info*) allocate(sizeof(*src)));
670 /* Start with a bitwise copy */
671 memcpy(dst, src, sizeof(*src));
674 dst->class_name = NULL;
678 apc_xmemcpy(src->name, src->name_len+1, allocate))) {
683 if (src->class_name) {
684 if(!(dst->class_name =
685 apc_xmemcpy(src->class_name, src->class_name_len+1, allocate))) {
693 if(dst->name) deallocate(dst->name);
694 if(dst->class_name) deallocate(dst->name);
695 if(local_dst_alloc) deallocate(dst);
701 /* {{{ my_copy_class_entry */
702 static zend_class_entry* my_copy_class_entry(zend_class_entry* dst, zend_class_entry* src, apc_malloc_t allocate, apc_free_t deallocate)
704 int local_dst_alloc = 0;
710 CHECK(dst = (zend_class_entry*) allocate(sizeof(*src)));
714 /* Start with a bitwise copy */
715 memcpy(dst, src, sizeof(*src));
718 dst->builtin_functions = NULL;
719 memset(&dst->function_table, 0, sizeof(dst->function_table));
720 memset(&dst->default_properties, 0, sizeof(dst->default_properties));
721 #ifndef ZEND_ENGINE_2
722 dst->refcount = NULL;
724 dst->static_members = NULL;
725 dst->doc_comment = NULL;
726 dst->filename = NULL;
727 memset(&dst->properties_info, 0, sizeof(dst->properties_info));
728 memset(&dst->constants_table, 0, sizeof(dst->constants_table));
729 memset(&dst->default_static_members, 0, sizeof(dst->default_static_members));
733 if(!(dst->name = apc_xstrdup(src->name, allocate))) {
738 #ifndef ZEND_ENGINE_2
739 if(!(dst->refcount = apc_xmemcpy(src->refcount,
740 sizeof(src->refcount[0]),
746 if(!(my_copy_hashtable_ex(&dst->function_table,
747 &src->function_table,
748 (ht_copy_fun_t) my_copy_function,
749 (ht_free_fun_t) my_free_function,
751 allocate, deallocate,
752 (ht_check_copy_fun_t) my_check_copy_function,
759 /* the interfaces are populated at runtime using ADD_INTERFACE */
760 dst->interfaces = NULL;
762 /* the current count includes inherited interfaces as well,
763 the real dynamic ones are the first <n> which are zero'd
764 out in zend_do_end_class_declaration */
765 for(i = 0 ; i < src->num_interfaces ; i++) {
766 if(src->interfaces[i])
768 dst->num_interfaces = i;
773 /* these will either be set inside my_fixup_hashtable or
774 * they will be copied out from parent inside zend_do_inheritance
776 dst->constructor = NULL;
777 dst->destructor = NULL;
784 #ifdef ZEND_ENGINE_2_2
785 dst->__tostring = NULL;
788 /* unset function proxies */
789 dst->serialize_func = NULL;
790 dst->unserialize_func = NULL;
792 my_fixup_hashtable(&dst->function_table, (ht_fixup_fun_t)my_fixup_function, src, dst);
795 if(!(my_copy_hashtable_ex(&dst->default_properties,
796 &src->default_properties,
797 (ht_copy_fun_t) my_copy_zval_ptr,
798 (ht_free_fun_t) my_free_zval_ptr,
801 (ht_check_copy_fun_t) my_check_copy_default_property,
808 if(!(my_copy_hashtable_ex(&dst->properties_info,
809 &src->properties_info,
810 (ht_copy_fun_t) my_copy_property_info,
811 (ht_free_fun_t) my_free_property_info,
813 allocate, deallocate,
814 (ht_check_copy_fun_t) my_check_copy_property_info,
819 #ifdef ZEND_ENGINE_2_2
820 /* php5.2 introduced a scope attribute for property info */
821 my_fixup_hashtable(&dst->properties_info, (ht_fixup_fun_t)my_fixup_property_info_for_execution, src, dst);
824 if(!my_copy_hashtable_ex(&dst->default_static_members,
825 &src->default_static_members,
826 (ht_copy_fun_t) my_copy_zval_ptr,
827 (ht_free_fun_t) my_free_zval_ptr,
829 allocate, deallocate,
830 (ht_check_copy_fun_t) my_check_copy_static_member,
832 &src->default_static_members)) {
835 if(src->static_members != &src->default_static_members)
837 if(!(dst->static_members = my_copy_hashtable_ex(NULL,
839 (ht_copy_fun_t) my_copy_zval_ptr,
840 (ht_free_fun_t) my_free_zval_ptr,
842 allocate, deallocate,
843 (ht_check_copy_fun_t) my_check_copy_static_member,
845 src->static_members))) {
851 dst->static_members = &dst->default_static_members;
854 if(!(my_copy_hashtable(&dst->constants_table,
855 &src->constants_table,
856 (ht_copy_fun_t) my_copy_zval_ptr,
857 (ht_free_fun_t) my_free_zval_ptr,
859 allocate, deallocate))) {
863 if (src->doc_comment) {
864 if(!(dst->doc_comment =
865 apc_xmemcpy(src->doc_comment, src->doc_comment_len+1, allocate))) {
871 if (src->builtin_functions) {
874 for (n = 0; src->type == ZEND_INTERNAL_CLASS && src->builtin_functions[n].fname != NULL; n++) {}
876 if(!(dst->builtin_functions =
877 (zend_function_entry*)
878 allocate((n + 1) * sizeof(zend_function_entry)))) {
883 for (i = 0; i < n; i++) {
884 if(!my_copy_function_entry(&dst->builtin_functions[i],
885 &src->builtin_functions[i],
886 allocate, deallocate)) {
889 for(ii=i-1; i>=0; i--) my_destroy_function_entry(&dst->builtin_functions[ii], deallocate);
893 *(char**)&(dst->builtin_functions[n].fname) = NULL;
898 if(!(dst->filename = apc_xstrdup(src->filename, allocate))) {
908 if(dst->name) deallocate(dst->name);
910 if(dst->doc_comment) deallocate(dst->doc_comment);
911 if(dst->filename) deallocate(dst->filename);
913 if(dst->refcount) deallocate(dst->refcount);
916 if(dst->builtin_functions) deallocate(dst->builtin_functions);
917 if(dst->function_table.arBuckets) my_destroy_hashtable(&dst->function_table, (ht_free_fun_t) my_free_function, deallocate);
918 if(dst->default_properties.arBuckets) my_destroy_hashtable(&dst->default_properties, (ht_free_fun_t) my_free_zval_ptr, deallocate);
921 if(dst->properties_info.arBuckets) my_destroy_hashtable(&dst->properties_info, (ht_free_fun_t) my_free_property_info, deallocate);
922 if(dst->default_static_members.arBuckets)
924 my_destroy_hashtable(&dst->default_static_members, (ht_free_fun_t) my_free_zval_ptr, deallocate);
926 if(dst->static_members && dst->static_members != &(dst->default_static_members))
928 my_destroy_hashtable(dst->static_members, (ht_free_fun_t) my_free_zval_ptr, deallocate);
929 deallocate(dst->static_members);
931 if(dst->constants_table.arBuckets) my_destroy_hashtable(&dst->constants_table, (ht_free_fun_t) my_free_zval_ptr, deallocate);
933 if(local_dst_alloc) deallocate(dst);
939 /* {{{ my_copy_hashtable */
940 static HashTable* my_copy_hashtable_ex(HashTable* dst,
942 ht_copy_fun_t copy_fn,
943 ht_free_fun_t free_fn,
945 apc_malloc_t allocate,
946 apc_free_t deallocate,
947 ht_check_copy_fun_t check_fn,
954 int local_dst_alloc = 0;
960 CHECK(dst = (HashTable*) allocate(sizeof(src[0])));
964 memcpy(dst, src, sizeof(src[0]));
966 /* allocate buckets for the new hashtable */
967 if(!(dst->arBuckets = allocate(dst->nTableSize * sizeof(Bucket*)))) {
968 if(local_dst_alloc) deallocate(dst);
972 memset(dst->arBuckets, 0, dst->nTableSize * sizeof(Bucket*));
973 dst->pInternalPointer = NULL;
974 dst->pListHead = NULL;
976 for (curr = src->pListHead; curr != NULL; curr = curr->pListNext) {
977 int n = curr->h % dst->nTableSize;
981 va_start(args, check_fn);
983 /* Call the check_fn to see if the current bucket
984 * needs to be copied out
986 if(!check_fn(curr, args)) {
987 dst->nNumOfElements--;
994 /* create a copy of the bucket 'curr' */
996 (Bucket*) apc_xmemcpy(curr,
997 sizeof(Bucket) + curr->nKeyLength - 1,
1002 /* insert 'newp' into the linked list at its hashed index */
1003 if (dst->arBuckets[n]) {
1004 newp->pNext = dst->arBuckets[n];
1006 newp->pNext->pLast = newp;
1009 newp->pNext = newp->pLast = NULL;
1012 dst->arBuckets[n] = newp;
1014 /* copy the bucket data using our 'copy_fn' callback function */
1015 if(!(newp->pData = copy_fn(NULL, curr->pData, allocate, deallocate))) {
1020 memcpy(&newp->pDataPtr, newp->pData, sizeof(void*));
1023 newp->pDataPtr = NULL;
1026 /* insert 'newp' into the table-thread linked list */
1027 newp->pListLast = prev;
1028 newp->pListNext = NULL;
1031 prev->pListNext = newp;
1035 dst->pListHead = newp;
1042 dst->pListTail = newp;
1047 for(index = 0; index < dst->nTableSize; index++)
1049 curr = dst->arBuckets[index];
1052 Bucket * tmp = curr;
1053 if(curr->pData && free_fn)
1055 free_fn(curr->pData, deallocate);
1061 deallocate(dst->arBuckets);
1062 if(local_dst_alloc) deallocate(dst);
1063 else dst->arBuckets = NULL;
1069 /* {{{ my_copy_static_variables */
1070 static HashTable* my_copy_static_variables(zend_op_array* src, apc_malloc_t allocate, apc_free_t deallocate)
1072 if (src->static_variables == NULL) {
1076 return my_copy_hashtable(NULL,
1077 src->static_variables,
1078 (ht_copy_fun_t) my_copy_zval_ptr,
1079 (ht_free_fun_t) my_free_zval_ptr,
1081 allocate, deallocate);
1085 /* {{{ apc_copy_zval */
1086 zval* apc_copy_zval(zval* dst, const zval* src, apc_malloc_t allocate, apc_free_t deallocate)
1088 int local_dst_alloc = 0;
1089 assert(src != NULL);
1092 CHECK(dst = (zval*) allocate(sizeof(zval)));
1093 local_dst_alloc = 1;
1096 dst = my_copy_zval(dst, src, allocate, deallocate);
1098 if(local_dst_alloc) deallocate(dst);
1105 #ifdef ZEND_ENGINE_2
1106 /* {{{ apc_fixup_op_array_jumps */
1107 static void apc_fixup_op_array_jumps(zend_op_array *dst, zend_op_array *src )
1111 for (i=0; i < dst->last; ++i) {
1112 zend_op *zo = &(dst->opcodes[i]);
1113 /*convert opline number to jump address*/
1114 switch (zo->opcode) {
1116 /*Note: if src->opcodes != dst->opcodes then we need to the opline according to src*/
1117 zo->op1.u.jmp_addr = dst->opcodes + (zo->op1.u.jmp_addr - src->opcodes);
1123 zo->op2.u.jmp_addr = dst->opcodes + (zo->op2.u.jmp_addr - src->opcodes);
1133 /* {{{ apc_copy_op_array */
1134 zend_op_array* apc_copy_op_array(zend_op_array* dst, zend_op_array* src, apc_malloc_t allocate, apc_free_t deallocate TSRMLS_DC)
1137 int local_dst_alloc = 0;
1138 apc_fileinfo_t fileinfo;
1139 char canon_path[MAXPATHLEN];
1140 char *fullpath = NULL;
1141 #ifdef ZEND_ENGINE_2
1142 apc_opflags_t * flags = NULL;
1145 assert(src != NULL);
1148 CHECK(dst = (zend_op_array*) allocate(sizeof(src[0])));
1149 local_dst_alloc = 1;
1152 if(APCG(apc_optimize_function)) {
1153 APCG(apc_optimize_function)(src TSRMLS_CC);
1156 /* start with a bitwise copy of the array */
1157 memcpy(dst, src, sizeof(src[0]));
1159 dst->function_name = NULL;
1160 dst->filename = NULL;
1161 dst->refcount = NULL;
1162 dst->opcodes = NULL;
1163 dst->brk_cont_array = NULL;
1164 dst->static_variables = NULL;
1165 #ifdef ZEND_ENGINE_2
1166 dst->try_catch_array = NULL;
1167 dst->arg_info = NULL;
1168 dst->doc_comment = NULL;
1170 dst->arg_types = NULL;
1172 #ifdef ZEND_ENGINE_2_1
1176 /* copy the arg types array (if set) */
1177 #ifdef ZEND_ENGINE_2
1178 if (src->arg_info) {
1179 if(!(dst->arg_info = my_copy_arg_info_array(NULL,
1188 if (src->arg_types) {
1189 if(!(dst->arg_types = apc_xmemcpy(src->arg_types,
1190 sizeof(src->arg_types[0]) * (src->arg_types[0]+1),
1197 if (src->function_name) {
1198 if(!(dst->function_name = apc_xstrdup(src->function_name, allocate))) {
1202 if (src->filename) {
1203 if(!(dst->filename = apc_xstrdup(src->filename, allocate))) {
1208 if(!(dst->refcount = apc_xmemcpy(src->refcount,
1209 sizeof(src->refcount[0]),
1214 /* deep-copy the opcodes */
1215 if(!(dst->opcodes = (zend_op*) allocate(sizeof(zend_op) * src->last))) {
1219 #ifdef ZEND_ENGINE_2
1220 if(APCG(reserved_offset) != -1) {
1221 /* Insanity alert: the void* pointer is cast into an apc_opflags_t
1222 * struct. apc_zend_init() checks to ensure that it fits in a void* */
1223 flags = (apc_opflags_t*) & (dst->reserved[APCG(reserved_offset)]);
1224 memset(flags, 0, sizeof(apc_opflags_t));
1225 /* assert(sizeof(apc_opflags_t) < sizeof(dst->reserved)); */
1229 for (i = 0; i < src->last; i++) {
1230 #ifdef ZEND_ENGINE_2
1231 zend_op *zo = &(src->opcodes[i]);
1232 /* a lot of files are merely constant arrays with no jumps */
1233 switch (zo->opcode) {
1240 flags->has_jumps = 1;
1243 #ifdef ZEND_ENGINE_2
1244 /* auto_globals_jit was not in php-4.3.* */
1248 case ZEND_FETCH_FUNC_ARG:
1249 if(PG(auto_globals_jit) && flags != NULL)
1251 /* The fetch is only required if auto_globals_jit=1 */
1252 if(zo->op2.u.EA.type == ZEND_FETCH_GLOBAL &&
1253 zo->op1.op_type == IS_CONST &&
1254 zo->op1.u.constant.type == IS_STRING) {
1255 znode * varname = &zo->op1;
1256 if (varname->u.constant.value.str.val[0] == '_') {
1257 #define SET_IF_AUTOGLOBAL(member) \
1258 if(!strcmp(varname->u.constant.value.str.val, #member)) \
1259 flags->member = 1 /* no ';' here */
1260 SET_IF_AUTOGLOBAL(_GET);
1261 else SET_IF_AUTOGLOBAL(_POST);
1262 else SET_IF_AUTOGLOBAL(_COOKIE);
1263 else SET_IF_AUTOGLOBAL(_SERVER);
1264 else SET_IF_AUTOGLOBAL(_ENV);
1265 else SET_IF_AUTOGLOBAL(_FILES);
1266 else SET_IF_AUTOGLOBAL(_REQUEST);
1267 else if(zend_is_auto_global(
1268 varname->u.constant.value.str.val,
1269 varname->u.constant.value.str.len
1272 flags->unknown_global = 1;
1279 case ZEND_RECV_INIT:
1280 if(zo->op2.op_type == IS_CONST &&
1281 zo->op2.u.constant.type == IS_CONSTANT_ARRAY) {
1283 flags->deep_copy = 1;
1288 if((zo->op1.op_type == IS_CONST &&
1289 zo->op1.u.constant.type == IS_CONSTANT_ARRAY) ||
1290 (zo->op2.op_type == IS_CONST &&
1291 zo->op2.u.constant.type == IS_CONSTANT_ARRAY)) {
1293 flags->deep_copy = 1;
1299 if(!(my_copy_zend_op(dst->opcodes+i, src->opcodes+i, allocate, deallocate))) {
1301 for(ii = i-1; ii>=0; ii--) {
1302 my_destroy_zend_op(dst->opcodes+ii, deallocate);
1306 #ifdef ZEND_ENGINE_2
1307 /* This code breaks apc's rule#1 - cache what you compile */
1308 if(APCG(fpstat)==0) {
1309 if((zo->opcode == ZEND_INCLUDE_OR_EVAL) &&
1310 (zo->op1.op_type == IS_CONST && zo->op1.u.constant.type == IS_STRING)) {
1311 /* constant includes */
1312 if(!IS_ABSOLUTE_PATH(Z_STRVAL_P(&zo->op1.u.constant),Z_STRLEN_P(&zo->op1.u.constant))) {
1313 if (apc_search_paths(Z_STRVAL_P(&zo->op1.u.constant), PG(include_path), &fileinfo) == 0) {
1314 if((fullpath = realpath(fileinfo.fullpath, canon_path))) {
1315 /* everything has to go through a realpath() */
1316 zend_op *dzo = &(dst->opcodes[i]);
1317 deallocate(dzo->op1.u.constant.value.str.val);
1318 dzo->op1.u.constant.value.str.len = strlen(fullpath);
1319 dzo->op1.u.constant.value.str.val = apc_xstrdup(fullpath, allocate);
1328 #ifdef ZEND_ENGINE_2
1329 if(flags == NULL || flags->has_jumps) {
1330 apc_fixup_op_array_jumps(dst,src);
1334 /* copy the break-continue array */
1335 if (src->brk_cont_array) {
1336 if(!(dst->brk_cont_array =
1337 apc_xmemcpy(src->brk_cont_array,
1338 sizeof(src->brk_cont_array[0]) * src->last_brk_cont,
1340 goto cleanup_opcodes;
1344 /* copy the table of static variables */
1345 if (src->static_variables) {
1346 if(!(dst->static_variables = my_copy_static_variables(src, allocate, deallocate))) {
1347 goto cleanup_opcodes;
1351 #ifdef ZEND_ENGINE_2
1352 if (src->try_catch_array) {
1353 if(!(dst->try_catch_array =
1354 apc_xmemcpy(src->try_catch_array,
1355 sizeof(src->try_catch_array[0]) * src->last_try_catch,
1357 goto cleanup_opcodes;
1362 #ifdef ZEND_ENGINE_2_1 /* PHP 5.1 */
1364 if(!(dst->vars = apc_xmemcpy(src->vars,
1365 sizeof(src->vars[0]) * src->last_var,
1367 goto cleanup_opcodes;
1370 for(i = 0; i < src->last_var; i++) dst->vars[i].name = NULL;
1372 for(i = 0; i < src->last_var; i++) {
1373 if(!(dst->vars[i].name = apc_xmemcpy(src->vars[i].name,
1374 src->vars[i].name_len + 1,
1377 goto cleanup_opcodes;
1383 #ifdef ZEND_ENGINE_2
1384 if (src->doc_comment) {
1385 if (!(dst->doc_comment
1386 = apc_xmemcpy(src->doc_comment, src->doc_comment_len+1, allocate))) {
1387 goto cleanup_opcodes;
1396 for(i=0; i < src->last; i++) my_destroy_zend_op(dst->opcodes+i, deallocate);
1399 if(dst->function_name) deallocate(dst->function_name);
1400 if(dst->refcount) deallocate(dst->refcount);
1401 if(dst->filename) deallocate(dst->filename);
1402 #ifdef ZEND_ENGINE_2
1403 if(dst->arg_info) my_free_arg_info_array(dst->arg_info, dst->num_args, deallocate);
1404 if(dst->try_catch_array) deallocate(dst->try_catch_array);
1405 if(dst->doc_comment) deallocate(dst->doc_comment);
1407 if(dst->arg_types) deallocate(dst->arg_types);
1409 if(dst->opcodes) deallocate(dst->opcodes);
1410 if(dst->brk_cont_array) deallocate(dst->brk_cont_array);
1411 if(dst->static_variables) my_free_hashtable(dst->static_variables, (ht_free_fun_t)my_free_zval_ptr, (apc_free_t)deallocate);
1412 #ifdef ZEND_ENGINE_2_1
1414 for(i=0; i < dst->last_var; i++) {
1415 if(dst->vars[i].name) deallocate(dst->vars[i].name);
1417 deallocate(dst->vars);
1420 if(local_dst_alloc) deallocate(dst);
1425 /* {{{ apc_copy_new_functions */
1426 apc_function_t* apc_copy_new_functions(int old_count, apc_malloc_t allocate, apc_free_t deallocate TSRMLS_DC)
1428 apc_function_t* array;
1429 int new_count; /* number of new functions in table */
1432 new_count = zend_hash_num_elements(CG(function_table)) - old_count;
1433 assert(new_count >= 0);
1437 allocate(sizeof(apc_function_t) * (new_count+1)));
1439 if (new_count == 0) {
1440 array[0].function = NULL;
1444 /* Skip the first `old_count` functions in the table */
1445 zend_hash_internal_pointer_reset(CG(function_table));
1446 for (i = 0; i < old_count; i++) {
1447 zend_hash_move_forward(CG(function_table));
1450 /* Add the next `new_count` functions to our array */
1451 for (i = 0; i < new_count; i++) {
1456 zend_hash_get_current_key_ex(CG(function_table),
1463 zend_hash_get_current_data(CG(function_table), (void**) &fun);
1465 if(!(array[i].name = apc_xmemcpy(key, (int) key_size, allocate))) {
1467 for(ii=i-1; ii>=0; ii--) {
1468 deallocate(array[ii].name);
1469 my_free_function(array[ii].function, deallocate);
1474 array[i].name_len = (int) key_size-1;
1475 if(!(array[i].function = my_copy_function(NULL, fun, allocate, deallocate))) {
1477 deallocate(array[i].name);
1478 for(ii=i-1; ii>=0; ii--) {
1479 deallocate(array[ii].name);
1480 my_free_function(array[ii].function, deallocate);
1485 zend_hash_move_forward(CG(function_table));
1488 array[i].function = NULL;
1493 /* {{{ apc_copy_new_classes */
1494 apc_class_t* apc_copy_new_classes(zend_op_array* op_array, int old_count, apc_malloc_t allocate, apc_free_t deallocate TSRMLS_DC)
1497 int new_count; /* number of new classes in table */
1500 new_count = zend_hash_num_elements(CG(class_table)) - old_count;
1501 assert(new_count >= 0);
1505 allocate(sizeof(apc_class_t)*(new_count+1)));
1507 if (new_count == 0) {
1508 array[0].class_entry = NULL;
1512 /* Skip the first `old_count` classes in the table */
1513 zend_hash_internal_pointer_reset(CG(class_table));
1514 for (i = 0; i < old_count; i++) {
1515 zend_hash_move_forward(CG(class_table));
1518 /* Add the next `new_count` classes to our array */
1519 for (i = 0; i < new_count; i++) {
1522 zend_class_entry* elem = NULL;
1524 array[i].class_entry = NULL;
1526 zend_hash_get_current_key_ex(CG(class_table),
1533 zend_hash_get_current_data(CG(class_table), (void**) &elem);
1536 #ifdef ZEND_ENGINE_2
1537 elem = *((zend_class_entry**)elem);
1540 if(!(array[i].name = apc_xmemcpy(key, (int) key_size, allocate))) {
1543 for(ii=i-1; ii>=0; ii--) {
1544 deallocate(array[ii].name);
1545 my_destroy_class_entry(array[ii].class_entry, deallocate);
1546 deallocate(array[ii].class_entry);
1551 array[i].name_len = (int) key_size-1;
1552 if(!(array[i].class_entry = my_copy_class_entry(NULL, elem, allocate, deallocate))) {
1555 deallocate(array[i].name);
1556 for(ii=i-1; ii>=0; ii--) {
1557 deallocate(array[ii].name);
1558 my_destroy_class_entry(array[ii].class_entry, deallocate);
1559 deallocate(array[ii].class_entry);
1566 * If the class has a pointer to its parent class, save the parent
1567 * name so that we can enable compile-time inheritance when we reload
1568 * the child class; otherwise, set the parent name to null and scan
1569 * the op_array to determine if this class inherits from some base
1570 * class at execution-time.
1574 if(!(array[i].parent_name =
1575 apc_xstrdup(elem->parent->name, allocate))) {
1578 for(ii=i; ii>=0; ii--) {
1579 deallocate(array[ii].name);
1580 my_destroy_class_entry(array[ii].class_entry, deallocate);
1581 deallocate(array[ii].class_entry);
1583 if(array[ii].parent_name) deallocate(array[ii].parent_name);
1588 array[i].is_derived = 1;
1591 array[i].parent_name = NULL;
1592 array[i].is_derived = is_derived_class(op_array, key, key_size);
1595 zend_hash_move_forward(CG(class_table));
1598 array[i].class_entry = NULL;
1603 /* {{{ my_destroy_zval_ptr */
1604 static void my_destroy_zval_ptr(zval** src, apc_free_t deallocate)
1606 assert(src != NULL);
1607 if(my_destroy_zval(src[0], deallocate) == SUCCESS) {
1613 /* {{{ my_destroy_zval */
1614 static int my_destroy_zval(zval* src, apc_free_t deallocate)
1619 switch (src->type & ~IS_CONSTANT_INDEX) {
1629 #ifndef ZEND_ENGINE_2
1632 deallocate(src->value.str.val);
1637 /* Maintain a list of zvals we've copied to properly handle recursive structures */
1638 if(APCG(copied_zvals)) {
1639 if(zend_hash_index_find(APCG(copied_zvals), (ulong)src, (void**)&tmp) == SUCCESS) {
1643 zend_hash_index_update(APCG(copied_zvals), (ulong)src, (void**)&src, sizeof(zval*), NULL);
1647 case IS_CONSTANT_ARRAY:
1648 my_free_hashtable(src->value.ht,
1649 (ht_free_fun_t) my_free_zval_ptr,
1654 #ifndef ZEND_ENGINE_2
1655 my_destroy_class_entry(src->value.obj.ce, deallocate);
1656 deallocate(src->value.obj.ce);
1657 my_free_hashtable(src->value.obj.properties,
1658 (ht_free_fun_t) my_free_zval_ptr,
1671 /* {{{ my_destroy_znode */
1672 static void my_destroy_znode(znode* src, apc_free_t deallocate)
1674 if (src->op_type == IS_CONST) {
1675 my_destroy_zval(&src->u.constant, deallocate);
1680 /* {{{ my_destroy_zend_op */
1681 static void my_destroy_zend_op(zend_op* src, apc_free_t deallocate)
1683 my_destroy_znode(&src->result, deallocate);
1684 my_destroy_znode(&src->op1, deallocate);
1685 my_destroy_znode(&src->op2, deallocate);
1689 /* {{{ my_destroy_function */
1690 static void my_destroy_function(zend_function* src, apc_free_t deallocate)
1692 assert(src != NULL);
1694 switch (src->type) {
1695 case ZEND_INTERNAL_FUNCTION:
1696 case ZEND_OVERLOADED_FUNCTION:
1699 case ZEND_USER_FUNCTION:
1700 case ZEND_EVAL_CODE:
1701 my_destroy_op_array(&src->op_array, deallocate);
1710 /* {{{ my_destroy_function_entry */
1711 static void my_destroy_function_entry(zend_function_entry* src, apc_free_t deallocate)
1713 assert(src != NULL);
1715 deallocate(src->fname);
1716 #ifdef ZEND_ENGINE_2
1717 if (src->arg_info) {
1718 my_free_arg_info_array(src->arg_info, src->num_args, deallocate);
1721 if (src->func_arg_types) {
1722 deallocate(src->func_arg_types);
1728 #ifdef ZEND_ENGINE_2
1729 /* {{{ my_destroy_property_info*/
1730 static void my_destroy_property_info(zend_property_info* src, apc_free_t deallocate)
1732 assert(src != NULL);
1734 deallocate(src->name);
1735 #if defined(ZEND_ENGINE_2) && PHP_MINOR_VERSION > 0
1736 if(src->doc_comment) deallocate(src->doc_comment);
1741 /* {{{ my_destroy_arg_info_array */
1742 static void my_destroy_arg_info_array(zend_arg_info* src, uint num_args, apc_free_t deallocate)
1746 assert(src != NULL);
1748 for(i=0; i < num_args; i++) {
1749 my_destroy_arg_info(&src[i], deallocate);
1754 /* {{{ my_destroy_arg_info */
1755 static void my_destroy_arg_info(zend_arg_info* src, apc_free_t deallocate)
1757 assert(src != NULL);
1759 deallocate(src->name);
1760 deallocate(src->class_name);
1765 /* {{{ my_destroy_class_entry */
1766 static void my_destroy_class_entry(zend_class_entry* src, apc_free_t deallocate)
1770 assert(src != NULL);
1772 deallocate(src->name);
1773 #ifndef ZEND_ENGINE_2
1774 deallocate(src->refcount);
1776 if(src->doc_comment) deallocate(src->doc_comment);
1777 if(src->filename) deallocate(src->filename);
1780 my_destroy_hashtable(&src->function_table,
1781 (ht_free_fun_t) my_free_function,
1784 my_destroy_hashtable(&src->default_properties,
1785 (ht_free_fun_t) my_free_zval_ptr,
1788 #ifdef ZEND_ENGINE_2
1789 my_destroy_hashtable(&src->properties_info,
1790 (ht_free_fun_t) my_free_property_info,
1792 if(src->static_members)
1794 my_destroy_hashtable(src->static_members,
1795 (ht_free_fun_t) my_free_zval_ptr,
1797 if(src->static_members != &(src->default_static_members))
1799 deallocate(src->static_members);
1803 my_destroy_hashtable(&src->constants_table,
1804 (ht_free_fun_t) my_free_zval_ptr,
1808 if (src->builtin_functions) {
1809 for (i = 0; src->builtin_functions[i].fname != NULL; i++) {
1810 my_destroy_function_entry(&src->builtin_functions[i], deallocate);
1812 deallocate(src->builtin_functions);
1817 /* {{{ my_destroy_hashtable */
1818 static void my_destroy_hashtable(HashTable* src, ht_free_fun_t free_fn, apc_free_t deallocate)
1822 assert(src != NULL);
1824 for (i = 0; i < src->nTableSize; i++) {
1825 Bucket* p = src->arBuckets[i];
1829 free_fn(q->pData, deallocate);
1834 deallocate(src->arBuckets);
1838 /* {{{ my_destroy_op_array */
1839 static void my_destroy_op_array(zend_op_array* src, apc_free_t deallocate)
1843 assert(src != NULL);
1845 #ifdef ZEND_ENGINE_2
1846 if (src->arg_info) {
1847 my_free_arg_info_array(src->arg_info, src->num_args, deallocate);
1850 if (src->arg_types) {
1851 deallocate(src->arg_types);
1855 deallocate(src->function_name);
1856 deallocate(src->filename);
1857 deallocate(src->refcount);
1859 for (i = 0; i < src->last; i++) {
1860 my_destroy_zend_op(src->opcodes + i, deallocate);
1862 deallocate(src->opcodes);
1864 if (src->brk_cont_array) {
1865 deallocate(src->brk_cont_array);
1868 if (src->static_variables) {
1869 my_free_hashtable(src->static_variables,
1870 (ht_free_fun_t) my_free_zval_ptr,
1874 #ifdef ZEND_ENGINE_2_1
1876 for(i=0; i < src->last_var; i++) {
1877 if(src->vars[i].name) deallocate(src->vars[i].name);
1879 deallocate(src->vars);
1882 #ifdef ZEND_ENGINE_2
1883 if(src->try_catch_array) {
1884 deallocate(src->try_catch_array);
1886 if (src->doc_comment) {
1887 deallocate(src->doc_comment);
1893 /* {{{ my_free_zval_ptr */
1894 static void my_free_zval_ptr(zval** src, apc_free_t deallocate)
1896 my_destroy_zval_ptr(src, deallocate);
1901 #ifdef ZEND_ENGINE_2
1902 /* {{{ my_free_property_info */
1903 static void my_free_property_info(zend_property_info* src, apc_free_t deallocate)
1905 my_destroy_property_info(src, deallocate);
1910 /* {{{ my_free_arg_info_array */
1911 static void my_free_arg_info_array(zend_arg_info* src, uint num_args, apc_free_t deallocate)
1913 my_destroy_arg_info_array(src, num_args, deallocate);
1918 /* {{{ my_free_arg_info */
1919 static void my_free_arg_info(zend_arg_info* src, apc_free_t deallocate)
1921 my_destroy_arg_info(src, deallocate);
1927 /* {{{ my_free_function */
1928 static void my_free_function(zend_function* src, apc_free_t deallocate)
1930 my_destroy_function(src, deallocate);
1935 /* {{{ my_free_hashtable */
1936 static void my_free_hashtable(HashTable* src, ht_free_fun_t free_fn, apc_free_t deallocate)
1938 my_destroy_hashtable(src, free_fn, deallocate);
1943 /* {{{ apc_free_op_array */
1944 void apc_free_op_array(zend_op_array* src, apc_free_t deallocate)
1947 my_destroy_op_array(src, deallocate);
1953 /* {{{ apc_free_functions */
1954 void apc_free_functions(apc_function_t* src, apc_free_t deallocate)
1959 for (i = 0; src[i].function != NULL; i++) {
1960 deallocate(src[i].name);
1961 my_destroy_function(src[i].function, deallocate);
1962 deallocate(src[i].function);
1969 /* {{{ apc_free_classes */
1970 void apc_free_classes(apc_class_t* src, apc_free_t deallocate)
1975 for (i = 0; src[i].class_entry != NULL; i++) {
1976 deallocate(src[i].name);
1977 deallocate(src[i].parent_name);
1978 my_destroy_class_entry(src[i].class_entry, deallocate);
1979 deallocate(src[i].class_entry);
1986 /* {{{ apc_free_zval */
1987 void apc_free_zval(zval* src, apc_free_t deallocate)
1990 if(my_destroy_zval(src, deallocate) == SUCCESS) {
1998 /* Used only by my_prepare_op_array_for_execution */
1999 #define APC_PREPARE_FETCH_GLOBAL_FOR_EXECUTION() \
2000 /* The fetch is only required if auto_globals_jit=1 */ \
2001 if(zo->op2.u.EA.type == ZEND_FETCH_GLOBAL && \
2002 zo->op1.op_type == IS_CONST && \
2003 zo->op1.u.constant.type == IS_STRING && \
2004 zo->op1.u.constant.value.str.val[0] == '_') { \
2006 znode* varname = &zo->op1; \
2007 (void)zend_is_auto_global(varname->u.constant.value.str.val, \
2008 varname->u.constant.value.str.len \
2012 /* {{{ my_prepare_op_array_for_execution */
2013 static int my_prepare_op_array_for_execution(zend_op_array* dst, zend_op_array* src TSRMLS_DC)
2015 /* combine my_fetch_global_vars and my_copy_data_exceptions.
2016 * - Pre-fetch superglobals which would've been pre-fetched in parse phase.
2017 * - If the opcode stream contain mutable data, ensure a copy.
2018 * - Fixup array jumps in the same loop.
2023 #ifdef ZEND_ENGINE_2
2024 apc_opflags_t * flags = APCG(reserved_offset) != -1 ?
2025 (apc_opflags_t*) & (src->reserved[APCG(reserved_offset)]) : NULL;
2026 int needcopy = flags ? flags->deep_copy : 1;
2027 /* auto_globals_jit was not in php4 */
2028 int do_prepare_fetch_global = PG(auto_globals_jit) && (flags == NULL || flags->unknown_global);
2030 #define FETCH_AUTOGLOBAL(member) do { \
2031 if(flags && flags->member == 1) { \
2032 zend_is_auto_global(#member,\
2033 (sizeof(#member) - 1)\
2038 FETCH_AUTOGLOBAL(_GET);
2039 FETCH_AUTOGLOBAL(_POST);
2040 FETCH_AUTOGLOBAL(_COOKIE);
2041 FETCH_AUTOGLOBAL(_SERVER);
2042 FETCH_AUTOGLOBAL(_ENV);
2043 FETCH_AUTOGLOBAL(_FILES);
2044 FETCH_AUTOGLOBAL(_REQUEST);
2048 int do_prepare_fetch_global = 0;
2051 for(j = 0; j < src->last; j++) {
2052 zo = &src->opcodes[j];
2054 if( ((zo->op1.op_type == IS_CONST &&
2055 zo->op1.u.constant.type == IS_CONSTANT_ARRAY)) ||
2056 ((zo->op2.op_type == IS_CONST &&
2057 zo->op2.u.constant.type == IS_CONSTANT_ARRAY))) {
2065 dst->opcodes = (zend_op*) apc_xmemcpy(src->opcodes,
2066 sizeof(zend_op) * src->last,
2072 if( ((zo->op1.op_type == IS_CONST &&
2073 zo->op1.u.constant.type == IS_CONSTANT_ARRAY)) ||
2074 ((zo->op2.op_type == IS_CONST &&
2075 zo->op2.u.constant.type == IS_CONSTANT_ARRAY))) {
2077 if(!(my_copy_zend_op(dzo, zo, apc_php_malloc, apc_php_free))) {
2078 assert(0); /* emalloc failed or a bad constant array */
2082 #ifdef ZEND_ENGINE_2
2083 switch(zo->opcode) {
2085 dzo->op1.u.jmp_addr = dst->opcodes +
2086 (zo->op1.u.jmp_addr - src->opcodes);
2092 dzo->op2.u.jmp_addr = dst->opcodes +
2093 (zo->op2.u.jmp_addr - src->opcodes);
2098 case ZEND_FETCH_FUNC_ARG:
2099 if(do_prepare_fetch_global)
2101 APC_PREPARE_FETCH_GLOBAL_FOR_EXECUTION();
2112 #ifdef ZEND_ENGINE_2
2113 } else { /* !needcopy */
2114 /* The fetch is only required if auto_globals_jit=1 */
2115 if(do_prepare_fetch_global)
2120 if(zo->opcode == ZEND_FETCH_R ||
2121 zo->opcode == ZEND_FETCH_W ||
2122 zo->opcode == ZEND_FETCH_IS ||
2123 zo->opcode == ZEND_FETCH_FUNC_ARG
2125 APC_PREPARE_FETCH_GLOBAL_FOR_EXECUTION();
2138 /* {{{ apc_copy_op_array_for_execution */
2139 zend_op_array* apc_copy_op_array_for_execution(zend_op_array* dst, zend_op_array* src TSRMLS_DC)
2142 dst = (zend_op_array*) emalloc(sizeof(src[0]));
2144 memcpy(dst, src, sizeof(src[0]));
2145 dst->static_variables = my_copy_static_variables(src, apc_php_malloc, apc_php_free);
2147 dst->refcount = apc_xmemcpy(src->refcount,
2148 sizeof(src->refcount[0]),
2151 my_prepare_op_array_for_execution(dst,src TSRMLS_CC);
2157 /* {{{ apc_copy_function_for_execution */
2158 zend_function* apc_copy_function_for_execution(zend_function* src)
2163 dst = (zend_function*) emalloc(sizeof(src[0]));
2164 memcpy(dst, src, sizeof(src[0]));
2165 apc_copy_op_array_for_execution(&(dst->op_array), &(src->op_array) TSRMLS_CC);
2170 /* {{{ apc_copy_function_for_execution_ex */
2171 zend_function* apc_copy_function_for_execution_ex(void *dummy, zend_function* src, apc_malloc_t allocate, apc_free_t deallocate)
2173 if(src->type==ZEND_INTERNAL_FUNCTION || src->type==ZEND_OVERLOADED_FUNCTION) return src;
2174 return apc_copy_function_for_execution(src);
2178 /* {{{ apc_copy_class_entry_for_execution */
2179 zend_class_entry* apc_copy_class_entry_for_execution(zend_class_entry* src, int is_derived)
2181 zend_class_entry* dst = (zend_class_entry*) emalloc(sizeof(src[0]));
2182 memcpy(dst, src, sizeof(src[0]));
2184 #ifdef ZEND_ENGINE_2
2185 if(src->num_interfaces)
2187 /* These are slots to be populated later by ADD_INTERFACE insns */
2188 dst->interfaces = apc_php_malloc(
2189 sizeof(zend_class_entry*) * src->num_interfaces);
2190 memset(dst->interfaces, 0,
2191 sizeof(zend_class_entry*) * src->num_interfaces);
2195 /* assert(dst->interfaces == NULL); */
2199 #ifndef ZEND_ENGINE_2
2200 dst->refcount = apc_xmemcpy(src->refcount,
2201 sizeof(src->refcount[0]),
2205 /* Deep-copy the class properties, because they will be modified */
2207 my_copy_hashtable(&dst->default_properties,
2208 &src->default_properties,
2209 (ht_copy_fun_t) my_copy_zval_ptr,
2210 (ht_free_fun_t) my_free_zval_ptr,
2212 apc_php_malloc, apc_php_free);
2214 /* For derived classes, we must also copy the function hashtable (although
2215 * we can merely bitwise copy the functions it contains) */
2217 my_copy_hashtable(&dst->function_table,
2218 &src->function_table,
2219 (ht_copy_fun_t) apc_copy_function_for_execution_ex,
2222 apc_php_malloc, apc_php_free);
2223 #ifdef ZEND_ENGINE_2
2224 my_fixup_hashtable(&dst->function_table, (ht_fixup_fun_t)my_fixup_function_for_execution, src, dst);
2226 /* zend_do_inheritance merges properties_info.
2227 * Need only shallow copying as it doesn't hold the pointers.
2229 my_copy_hashtable(&dst->properties_info,
2230 &src->properties_info,
2231 (ht_copy_fun_t) my_copy_property_info_for_execution,
2234 apc_php_malloc, apc_php_free);
2236 #ifdef ZEND_ENGINE_2_2
2237 /* php5.2 introduced a scope attribute for property info */
2238 my_fixup_hashtable(&dst->properties_info, (ht_fixup_fun_t)my_fixup_property_info_for_execution, src, dst);
2241 /* if inheritance results in a hash_del, it might result in
2242 * a pefree() of the pointers here. Deep copying required.
2245 my_copy_hashtable(&dst->constants_table,
2246 &src->constants_table,
2247 (ht_copy_fun_t) my_copy_zval_ptr,
2250 apc_php_malloc, apc_php_free);
2252 my_copy_hashtable(&dst->default_static_members,
2253 &src->default_static_members,
2254 (ht_copy_fun_t) my_copy_zval_ptr,
2255 (ht_free_fun_t) my_free_zval_ptr,
2257 apc_php_malloc, apc_php_free);
2259 if(src->static_members != &(src->default_static_members))
2261 dst->static_members = my_copy_hashtable(NULL,
2262 src->static_members,
2263 (ht_copy_fun_t) my_copy_zval_ptr,
2264 (ht_free_fun_t) my_free_zval_ptr,
2266 apc_php_malloc, apc_php_free);
2270 dst->static_members = &(dst->default_static_members);
2279 /* {{{ apc_free_class_entry_after_execution */
2280 void apc_free_class_entry_after_execution(zend_class_entry* src)
2282 #ifdef ZEND_ENGINE_2
2283 if(src->num_interfaces > 0 && src->interfaces) {
2284 apc_php_free(src->interfaces);
2285 src->interfaces = NULL;
2286 src->num_interfaces = 0;
2288 /* my_destroy_hashtable() does not play nice with refcounts */
2290 zend_hash_clean(&src->default_static_members);
2291 if(src->static_members != &(src->default_static_members))
2293 zend_hash_destroy(src->static_members);
2294 apc_php_free(src->static_members);
2295 src->static_members = NULL;
2299 src->static_members = NULL;
2301 zend_hash_clean(&src->default_properties);
2302 zend_hash_clean(&src->constants_table);
2305 /* TODO: more cleanup */
2309 #ifdef ZEND_ENGINE_2
2311 /* {{{ my_fixup_function */
2312 static void my_fixup_function(Bucket *p, zend_class_entry *src, zend_class_entry *dst)
2314 zend_function* zf = p->pData;
2316 #define SET_IF_SAME_NAME(member) \
2318 if(src->member && !strcmp(zf->common.function_name, src->member->common.function_name)) { \
2324 if(zf->common.scope == src)
2327 /* Fixing up the default functions for objects here since
2328 * we need to compare with the newly allocated functions
2330 * caveat: a sub-class method can have the same name as the
2331 * parent's constructor and create problems.
2334 if(zf->common.fn_flags & ZEND_ACC_CTOR) dst->constructor = zf;
2335 else if(zf->common.fn_flags & ZEND_ACC_DTOR) dst->destructor = zf;
2336 else if(zf->common.fn_flags & ZEND_ACC_CLONE) dst->clone = zf;
2339 SET_IF_SAME_NAME(__get);
2340 SET_IF_SAME_NAME(__set);
2341 SET_IF_SAME_NAME(__unset);
2342 SET_IF_SAME_NAME(__isset);
2343 SET_IF_SAME_NAME(__call);
2344 #ifdef ZEND_ENGINE_2_2
2345 SET_IF_SAME_NAME(__tostring);
2348 zf->common.scope = dst;
2352 /* no other function should reach here */
2356 #undef SET_IF_SAME_NAME
2360 #ifdef ZEND_ENGINE_2_2
2361 /* {{{ my_fixup_property_info */
2362 static void my_fixup_property_info(Bucket *p, zend_class_entry *src, zend_class_entry *dst)
2364 zend_property_info* property_info = (zend_property_info*)p->pData;
2366 if(property_info->ce == src)
2368 property_info->ce = dst;
2372 assert(0); /* should never happen */
2378 /* {{{ my_fixup_hashtable */
2379 static void my_fixup_hashtable(HashTable *ht, ht_fixup_fun_t fixup, zend_class_entry *src, zend_class_entry *dst)
2385 for (i = 0; i < ht->nTableSize; i++) {
2386 if(!ht->arBuckets) break;
2387 p = ht->arBuckets[i];
2398 /* {{{ my_check_copy_function */
2399 static int my_check_copy_function(Bucket* p, va_list args)
2401 zend_class_entry* src = va_arg(args, zend_class_entry*);
2402 zend_function* zf = (zend_function*)p->pData;
2403 #ifndef ZEND_ENGINE_2
2404 zend_class_entry* parent = src->parent;
2405 zend_function* parent_fn = NULL;
2408 #ifdef ZEND_ENGINE_2
2409 return (zf->common.scope == src);
2412 zend_hash_quick_find(&parent->function_table, p->arKey,
2413 p->nKeyLength, p->h, (void **) &parent_fn)==SUCCESS) {
2415 if((parent_fn && zf) &&
2416 (parent_fn->op_array.refcount == zf->op_array.refcount))
2426 /* {{{ my_check_copy_default_property */
2427 static int my_check_copy_default_property(Bucket* p, va_list args)
2429 zend_class_entry* src = va_arg(args, zend_class_entry*);
2430 zend_class_entry* parent = src->parent;
2431 zval ** child_prop = (zval**)p->pData;
2432 zval ** parent_prop = NULL;
2435 zend_hash_quick_find(&parent->default_properties, p->arKey,
2436 p->nKeyLength, p->h, (void **) &parent_prop)==SUCCESS) {
2438 if((parent_prop && child_prop) && (*parent_prop) == (*child_prop))
2444 /* possibly not in the parent */
2449 #ifdef ZEND_ENGINE_2
2451 /* {{{ my_check_copy_property_info */
2452 static int my_check_copy_property_info(Bucket* p, va_list args)
2454 zend_class_entry* src = va_arg(args, zend_class_entry*);
2455 zend_class_entry* parent = src->parent;
2456 zend_property_info* child_info = (zend_property_info*)p->pData;
2457 zend_property_info* parent_info = NULL;
2459 #ifdef ZEND_ENGINE_2_2
2460 /* so much easier */
2461 return (child_info->ce == src);
2465 zend_hash_quick_find(&parent->properties_info, p->arKey, p->nKeyLength,
2466 p->h, (void **) &parent_info)==SUCCESS) {
2467 if(parent_info->flags & ZEND_ACC_PRIVATE)
2471 if((parent_info->flags & ZEND_ACC_PPP_MASK) !=
2472 (child_info->flags & ZEND_ACC_PPP_MASK))
2474 /* TODO: figure out whether ACC_CHANGED is more appropriate
2481 /* property doesn't exist in parent, copy into cached child */
2486 /* {{{ my_check_copy_static_member */
2487 static int my_check_copy_static_member(Bucket* p, va_list args)
2489 zend_class_entry* src = va_arg(args, zend_class_entry*);
2490 HashTable * ht = va_arg(args, HashTable*);
2491 zend_class_entry* parent = src->parent;
2492 HashTable * parent_ht = NULL;
2494 char * class_name = NULL;
2496 zend_property_info *parent_info = NULL;
2497 zend_property_info *child_info = NULL;
2498 zval ** parent_prop = NULL;
2499 zval ** child_prop = (zval**)(p->pData);
2505 /* these do not need free'ing */
2506 #ifdef ZEND_ENGINE_2_2
2507 zend_unmangle_property_name(p->arKey, p->nKeyLength-1, &class_name, &member_name);
2509 zend_unmangle_property_name(p->arKey, &class_name, &member_name);
2512 /* please refer do_inherit_property_access_check in zend_compile.c
2513 * to understand why we lookup in properties_info.
2515 if((zend_hash_find(&parent->properties_info, member_name,
2516 strlen(member_name)+1, (void**)&parent_info) == SUCCESS)
2518 (zend_hash_find(&src->properties_info, member_name,
2519 strlen(member_name)+1, (void**)&child_info) == SUCCESS))
2521 if(child_info->flags & ZEND_ACC_STATIC &&
2522 (parent_info->flags & ZEND_ACC_PROTECTED &&
2523 child_info->flags & ZEND_ACC_PUBLIC))
2525 /* Do not copy into static_members. zend_do_inheritance
2526 * will automatically insert a NULL value.
2527 * TODO: decrement refcount or fixup when copying out for exec ?
2531 if(ht == &(src->default_static_members))
2533 parent_ht = &parent->default_static_members;
2537 parent_ht = parent->static_members;
2540 if(zend_hash_quick_find(parent_ht, p->arKey,
2541 p->nKeyLength, p->h, (void**)&parent_prop) == SUCCESS)
2543 /* they point to the same zval */
2544 if(*parent_prop == *child_prop)
2556 /* {{{ apc_register_optimizer(apc_optimize_function_t optimizer)
2557 * register a optimizer callback function, returns the previous callback
2559 apc_optimize_function_t apc_register_optimizer(apc_optimize_function_t optimizer TSRMLS_DC) {
2560 apc_optimize_function_t old_optimizer = APCG(apc_optimize_function);
2561 APCG(apc_optimize_function) = optimizer;
2562 return old_optimizer;
2570 * vim600: expandtab sw=4 ts=4 sts=4 fdm=marker
2571 * vim<600: expandtab sw=4 ts=4 sts=4