2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2008 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.8 2008/05/11 18:57:00 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*, const 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*, const zend_arg_info*, uint, apc_malloc_t, apc_free_t);
112 static zend_arg_info* my_copy_arg_info(zend_arg_info*, const 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 #ifdef ZEND_ENGINE_2_3
296 if(!(dst[0] = (zval*) allocate(sizeof(zval_gc_info)))) {
297 if(local_dst_alloc) deallocate(dst);
301 if(allocate == apc_php_malloc) {
302 GC_ZVAL_INIT(dst[0]);
305 if(!(dst[0] = (zval*) allocate(sizeof(zval)))) {
306 if(local_dst_alloc) deallocate(dst);
310 if(!(dst_new = my_copy_zval(*dst, *src, allocate, deallocate))) {
311 if(local_dst_alloc) deallocate(dst);
314 if(dst_new != *dst) {
319 Z_SET_REFCOUNT_PP(dst, Z_REFCOUNT_PP((zval**)src));
320 Z_SET_ISREF_TO_PP(dst, Z_ISREF_PP((zval**)src));
326 /* {{{ my_copy_zval */
327 static zval* my_copy_zval(zval* dst, const zval* src, apc_malloc_t allocate, apc_free_t deallocate)
335 memcpy(dst, src, sizeof(src[0]));
337 switch (src->type & ~IS_CONSTANT_INDEX) {
347 #ifndef ZEND_ENGINE_2
350 if (src->value.str.val) {
351 CHECK(dst->value.str.val = apc_xmemcpy(src->value.str.val,
352 src->value.str.len+1,
359 if(APCG(copied_zvals)) {
360 if(zend_hash_index_find(APCG(copied_zvals), (ulong)src, (void**)&tmp) == SUCCESS) {
365 zend_hash_index_update(APCG(copied_zvals), (ulong)src, (void**)&dst, sizeof(zval*), NULL);
369 case IS_CONSTANT_ARRAY:
371 CHECK(dst->value.ht =
372 my_copy_hashtable(NULL,
374 (ht_copy_fun_t) my_copy_zval_ptr,
375 (ht_free_fun_t) my_free_zval_ptr,
377 allocate, deallocate));
381 #ifndef ZEND_ENGINE_2
382 CHECK(dst->value.obj.ce =
383 my_copy_class_entry(NULL, src->value.obj.ce, allocate, deallocate));
385 if(!(dst->value.obj.properties = my_copy_hashtable(NULL,
386 src->value.obj.properties,
387 (ht_copy_fun_t) my_copy_zval_ptr,
388 (ht_free_fun_t) my_free_zval_ptr,
390 allocate, deallocate))) {
391 my_destroy_class_entry(dst->value.obj.ce, deallocate);
408 /* {{{ my_copy_znode */
409 static znode* my_copy_znode(znode* dst, znode* src, apc_malloc_t allocate, apc_free_t deallocate)
414 memcpy(dst, src, sizeof(src[0]));
417 assert(dst ->op_type == IS_CONST ||
418 dst ->op_type == IS_VAR ||
419 dst ->op_type == IS_CV ||
420 dst ->op_type == IS_TMP_VAR ||
421 dst ->op_type == IS_UNUSED);
423 assert(dst ->op_type == IS_CONST ||
424 dst ->op_type == IS_VAR ||
425 dst ->op_type == IS_TMP_VAR ||
426 dst ->op_type == IS_UNUSED);
429 if (src->op_type == IS_CONST) {
430 if(!my_copy_zval(&dst->u.constant, &src->u.constant, allocate, deallocate)) {
439 /* {{{ my_copy_zend_op */
440 static zend_op* my_copy_zend_op(zend_op* dst, zend_op* src, apc_malloc_t allocate, apc_free_t deallocate)
445 memcpy(dst, src, sizeof(src[0]));
447 if( my_copy_znode(&dst->result, &src->result, allocate, deallocate) == NULL
448 || my_copy_znode(&dst->op1, &src->op1, allocate, deallocate) == NULL
449 || my_copy_znode(&dst->op2, &src->op2, allocate, deallocate) == NULL)
458 /* {{{ my_copy_function */
459 static zend_function* my_copy_function(zend_function* dst, zend_function* src, apc_malloc_t allocate, apc_free_t deallocate)
461 int local_dst_alloc = 0;
466 if(!dst) local_dst_alloc = 1;
467 CHECK(dst = my_bitwise_copy_function(dst, src, allocate));
470 case ZEND_INTERNAL_FUNCTION:
471 case ZEND_OVERLOADED_FUNCTION:
472 /* shallow copy because op_array is internal */
473 dst->op_array = src->op_array;
476 case ZEND_USER_FUNCTION:
478 if(!apc_copy_op_array(&dst->op_array,
480 allocate, deallocate TSRMLS_CC)) {
481 if(local_dst_alloc) deallocate(dst);
491 * op_array bitwise copying overwrites what ever you modified
492 * before apc_copy_op_array - which is why this code is outside
493 * my_bitwise_copy_function.
496 /* zend_do_inheritance will re-look this up, because the pointers
497 * in prototype are from a function table of another class. It just
498 * helps if that one is from EG(class_table).
500 dst->common.prototype = NULL;
502 /* once a method is marked as ZEND_ACC_IMPLEMENTED_ABSTRACT then you
503 * have to carry around a prototype. Thankfully zend_do_inheritance
504 * sets this properly as well
506 dst->common.fn_flags = src->common.fn_flags & (~ZEND_ACC_IMPLEMENTED_ABSTRACT);
514 /* {{{ my_copy_function_entry */
515 static zend_function_entry* my_copy_function_entry(zend_function_entry* dst, const zend_function_entry* src, apc_malloc_t allocate, apc_free_t deallocate)
517 int local_dst_alloc = 0;
521 CHECK(dst = (zend_function_entry*) allocate(sizeof(src[0])));
525 /* Start with a bitwise copy */
526 memcpy(dst, src, sizeof(src[0]));
530 dst->arg_info = NULL;
532 dst->func_arg_types = NULL;
536 if(!(dst->fname = apc_xstrdup(src->fname, allocate))) {
543 if(!(dst->arg_info = my_copy_arg_info_array(NULL,
552 if (src->func_arg_types) {
553 if(!(dst->func_arg_types = apc_xmemcpy(src->func_arg_types,
554 src->func_arg_types[0]+1,
564 if(dst->fname) deallocate((char*)dst->fname);
565 if(local_dst_alloc) deallocate(dst);
571 /* {{{ my_copy_property_info */
572 static zend_property_info* my_copy_property_info(zend_property_info* dst, zend_property_info* src, apc_malloc_t allocate, apc_free_t deallocate)
574 int local_dst_alloc = 0;
579 CHECK(dst = (zend_property_info*) allocate(sizeof(*src)));
583 /* Start with a bitwise copy */
584 memcpy(dst, src, sizeof(*src));
587 #if defined(ZEND_ENGINE_2) && PHP_MINOR_VERSION > 0
588 dst->doc_comment = NULL;
592 /* private members are stored inside property_info as a mangled
593 * string of the form:
594 * \0<classname>\0<membername>\0
597 apc_xmemcpy(src->name, src->name_length+1, allocate))) {
602 #if defined(ZEND_ENGINE_2) && PHP_MINOR_VERSION > 0
603 if (src->doc_comment) {
604 if( !(dst->doc_comment =
605 apc_xmemcpy(src->doc_comment, src->doc_comment_len+1, allocate))) {
614 if(dst->name) deallocate(dst->name);
615 #if defined(ZEND_ENGINE_2) && PHP_MINOR_VERSION > 0
616 if(dst->doc_comment) deallocate(dst->doc_comment);
618 if(local_dst_alloc) deallocate(dst);
623 /* {{{ my_copy_property_info_for_execution */
624 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)
626 int local_dst_alloc = 0;
631 CHECK(dst = (zend_property_info*) allocate(sizeof(*src)));
635 /* We need only a shallow copy */
636 memcpy(dst, src, sizeof(*src));
642 /* {{{ my_copy_arg_info_array */
643 static zend_arg_info* my_copy_arg_info_array(zend_arg_info* dst, const zend_arg_info* src, uint num_args, apc_malloc_t allocate, apc_free_t deallocate)
645 int local_dst_alloc = 0;
650 CHECK(dst = (zend_arg_info*) allocate(sizeof(*src)*num_args));
654 /* Start with a bitwise copy */
655 memcpy(dst, src, sizeof(*src)*num_args);
657 for(i=0; i < num_args; i++) {
658 if(!(my_copy_arg_info( &dst[i], &src[i], allocate, deallocate))) {
659 if(i) my_destroy_arg_info_array(dst, i-1, deallocate);
660 if(local_dst_alloc) deallocate(dst);
669 /* {{{ my_copy_arg_info */
670 static zend_arg_info* my_copy_arg_info(zend_arg_info* dst, const zend_arg_info* src, apc_malloc_t allocate, apc_free_t deallocate)
672 int local_dst_alloc = 0;
677 CHECK(dst = (zend_arg_info*) allocate(sizeof(*src)));
681 /* Start with a bitwise copy */
682 memcpy(dst, src, sizeof(*src));
685 dst->class_name = NULL;
689 apc_xmemcpy(src->name, src->name_len+1, allocate))) {
694 if (src->class_name) {
695 if(!(dst->class_name =
696 apc_xmemcpy(src->class_name, src->class_name_len+1, allocate))) {
704 if(dst->name) deallocate((char*)dst->name);
705 if(dst->class_name) deallocate((char*)dst->class_name);
706 if(local_dst_alloc) deallocate(dst);
712 /* {{{ my_copy_class_entry */
713 static zend_class_entry* my_copy_class_entry(zend_class_entry* dst, zend_class_entry* src, apc_malloc_t allocate, apc_free_t deallocate)
715 int local_dst_alloc = 0;
721 CHECK(dst = (zend_class_entry*) allocate(sizeof(*src)));
725 /* Start with a bitwise copy */
726 memcpy(dst, src, sizeof(*src));
729 dst->builtin_functions = NULL;
730 memset(&dst->function_table, 0, sizeof(dst->function_table));
731 memset(&dst->default_properties, 0, sizeof(dst->default_properties));
732 #ifndef ZEND_ENGINE_2
733 dst->refcount = NULL;
735 dst->static_members = NULL;
736 dst->doc_comment = NULL;
737 dst->filename = NULL;
738 memset(&dst->properties_info, 0, sizeof(dst->properties_info));
739 memset(&dst->constants_table, 0, sizeof(dst->constants_table));
740 memset(&dst->default_static_members, 0, sizeof(dst->default_static_members));
744 if(!(dst->name = apc_xstrdup(src->name, allocate))) {
749 #ifndef ZEND_ENGINE_2
750 if(!(dst->refcount = apc_xmemcpy(src->refcount,
751 sizeof(src->refcount[0]),
757 if(!(my_copy_hashtable_ex(&dst->function_table,
758 &src->function_table,
759 (ht_copy_fun_t) my_copy_function,
760 (ht_free_fun_t) my_free_function,
762 allocate, deallocate,
763 (ht_check_copy_fun_t) my_check_copy_function,
770 /* the interfaces are populated at runtime using ADD_INTERFACE */
771 dst->interfaces = NULL;
773 /* the current count includes inherited interfaces as well,
774 the real dynamic ones are the first <n> which are zero'd
775 out in zend_do_end_class_declaration */
776 for(i = 0 ; i < src->num_interfaces ; i++) {
777 if(src->interfaces[i])
779 dst->num_interfaces = i;
784 /* these will either be set inside my_fixup_hashtable or
785 * they will be copied out from parent inside zend_do_inheritance
787 dst->constructor = NULL;
788 dst->destructor = NULL;
795 #ifdef ZEND_ENGINE_2_2
796 dst->__tostring = NULL;
799 /* unset function proxies */
800 dst->serialize_func = NULL;
801 dst->unserialize_func = NULL;
803 my_fixup_hashtable(&dst->function_table, (ht_fixup_fun_t)my_fixup_function, src, dst);
806 if(!(my_copy_hashtable_ex(&dst->default_properties,
807 &src->default_properties,
808 (ht_copy_fun_t) my_copy_zval_ptr,
809 (ht_free_fun_t) my_free_zval_ptr,
812 (ht_check_copy_fun_t) my_check_copy_default_property,
819 if(!(my_copy_hashtable_ex(&dst->properties_info,
820 &src->properties_info,
821 (ht_copy_fun_t) my_copy_property_info,
822 (ht_free_fun_t) my_free_property_info,
824 allocate, deallocate,
825 (ht_check_copy_fun_t) my_check_copy_property_info,
830 #ifdef ZEND_ENGINE_2_2
831 /* php5.2 introduced a scope attribute for property info */
832 my_fixup_hashtable(&dst->properties_info, (ht_fixup_fun_t)my_fixup_property_info_for_execution, src, dst);
835 if(!my_copy_hashtable_ex(&dst->default_static_members,
836 &src->default_static_members,
837 (ht_copy_fun_t) my_copy_zval_ptr,
838 (ht_free_fun_t) my_free_zval_ptr,
840 allocate, deallocate,
841 (ht_check_copy_fun_t) my_check_copy_static_member,
843 &src->default_static_members)) {
846 if(src->static_members != &src->default_static_members)
848 if(!(dst->static_members = my_copy_hashtable_ex(NULL,
850 (ht_copy_fun_t) my_copy_zval_ptr,
851 (ht_free_fun_t) my_free_zval_ptr,
853 allocate, deallocate,
854 (ht_check_copy_fun_t) my_check_copy_static_member,
856 src->static_members))) {
862 dst->static_members = &dst->default_static_members;
865 if(!(my_copy_hashtable(&dst->constants_table,
866 &src->constants_table,
867 (ht_copy_fun_t) my_copy_zval_ptr,
868 (ht_free_fun_t) my_free_zval_ptr,
870 allocate, deallocate))) {
874 if (src->doc_comment) {
875 if(!(dst->doc_comment =
876 apc_xmemcpy(src->doc_comment, src->doc_comment_len+1, allocate))) {
882 if (src->builtin_functions) {
885 for (n = 0; src->type == ZEND_INTERNAL_CLASS && src->builtin_functions[n].fname != NULL; n++) {}
887 if(!(dst->builtin_functions =
888 (zend_function_entry*)
889 allocate((n + 1) * sizeof(zend_function_entry)))) {
894 for (i = 0; i < n; i++) {
895 if(!my_copy_function_entry((zend_function_entry*)(&dst->builtin_functions[i]),
896 &src->builtin_functions[i],
897 allocate, deallocate)) {
900 for(ii=i-1; ii>=0; ii--) my_destroy_function_entry((zend_function_entry*)(&dst->builtin_functions[ii]), deallocate);
904 *(char**)&(dst->builtin_functions[n].fname) = NULL;
909 if(!(dst->filename = apc_xstrdup(src->filename, allocate))) {
919 if(dst->name) deallocate(dst->name);
921 if(dst->doc_comment) deallocate(dst->doc_comment);
922 if(dst->filename) deallocate(dst->filename);
924 if(dst->refcount) deallocate(dst->refcount);
927 if(dst->builtin_functions) deallocate((zend_function_entry*)dst->builtin_functions);
928 if(dst->function_table.arBuckets) my_destroy_hashtable(&dst->function_table, (ht_free_fun_t) my_free_function, deallocate);
929 if(dst->default_properties.arBuckets) my_destroy_hashtable(&dst->default_properties, (ht_free_fun_t) my_free_zval_ptr, deallocate);
932 if(dst->properties_info.arBuckets) my_destroy_hashtable(&dst->properties_info, (ht_free_fun_t) my_free_property_info, deallocate);
933 if(dst->default_static_members.arBuckets)
935 my_destroy_hashtable(&dst->default_static_members, (ht_free_fun_t) my_free_zval_ptr, deallocate);
937 if(dst->static_members && dst->static_members != &(dst->default_static_members))
939 my_destroy_hashtable(dst->static_members, (ht_free_fun_t) my_free_zval_ptr, deallocate);
940 deallocate(dst->static_members);
942 if(dst->constants_table.arBuckets) my_destroy_hashtable(&dst->constants_table, (ht_free_fun_t) my_free_zval_ptr, deallocate);
944 if(local_dst_alloc) deallocate(dst);
950 /* {{{ my_copy_hashtable */
951 static HashTable* my_copy_hashtable_ex(HashTable* dst,
953 ht_copy_fun_t copy_fn,
954 ht_free_fun_t free_fn,
956 apc_malloc_t allocate,
957 apc_free_t deallocate,
958 ht_check_copy_fun_t check_fn,
965 int local_dst_alloc = 0;
971 CHECK(dst = (HashTable*) allocate(sizeof(src[0])));
975 memcpy(dst, src, sizeof(src[0]));
977 /* allocate buckets for the new hashtable */
978 if(!(dst->arBuckets = allocate(dst->nTableSize * sizeof(Bucket*)))) {
979 if(local_dst_alloc) deallocate(dst);
983 memset(dst->arBuckets, 0, dst->nTableSize * sizeof(Bucket*));
984 dst->pInternalPointer = NULL;
985 dst->pListHead = NULL;
987 for (curr = src->pListHead; curr != NULL; curr = curr->pListNext) {
988 int n = curr->h % dst->nTableSize;
992 va_start(args, check_fn);
994 /* Call the check_fn to see if the current bucket
995 * needs to be copied out
997 if(!check_fn(curr, args)) {
998 dst->nNumOfElements--;
1005 /* create a copy of the bucket 'curr' */
1007 (Bucket*) apc_xmemcpy(curr,
1008 sizeof(Bucket) + curr->nKeyLength - 1,
1013 /* insert 'newp' into the linked list at its hashed index */
1014 if (dst->arBuckets[n]) {
1015 newp->pNext = dst->arBuckets[n];
1017 newp->pNext->pLast = newp;
1020 newp->pNext = newp->pLast = NULL;
1023 dst->arBuckets[n] = newp;
1025 /* copy the bucket data using our 'copy_fn' callback function */
1026 if(!(newp->pData = copy_fn(NULL, curr->pData, allocate, deallocate))) {
1031 memcpy(&newp->pDataPtr, newp->pData, sizeof(void*));
1034 newp->pDataPtr = NULL;
1037 /* insert 'newp' into the table-thread linked list */
1038 newp->pListLast = prev;
1039 newp->pListNext = NULL;
1042 prev->pListNext = newp;
1046 dst->pListHead = newp;
1053 dst->pListTail = newp;
1058 for(index = 0; index < dst->nTableSize; index++)
1060 curr = dst->arBuckets[index];
1063 Bucket * tmp = curr;
1064 if(curr->pData && free_fn)
1066 free_fn(curr->pData, deallocate);
1072 deallocate(dst->arBuckets);
1073 if(local_dst_alloc) deallocate(dst);
1074 else dst->arBuckets = NULL;
1080 /* {{{ my_copy_static_variables */
1081 static HashTable* my_copy_static_variables(zend_op_array* src, apc_malloc_t allocate, apc_free_t deallocate)
1083 if (src->static_variables == NULL) {
1087 return my_copy_hashtable(NULL,
1088 src->static_variables,
1089 (ht_copy_fun_t) my_copy_zval_ptr,
1090 (ht_free_fun_t) my_free_zval_ptr,
1092 allocate, deallocate);
1096 /* {{{ apc_copy_zval */
1097 zval* apc_copy_zval(zval* dst, const zval* src, apc_malloc_t allocate, apc_free_t deallocate)
1099 int local_dst_alloc = 0;
1100 assert(src != NULL);
1103 #ifdef ZEND_ENGINE_2_3
1104 CHECK(dst = (zval*) allocate(sizeof(zval_gc_info)));
1106 if(allocate == apc_php_malloc) {
1110 CHECK(dst = (zval*) allocate(sizeof(zval)));
1112 local_dst_alloc = 1;
1115 dst = my_copy_zval(dst, src, allocate, deallocate);
1117 if(local_dst_alloc) deallocate(dst);
1124 #ifdef ZEND_ENGINE_2
1125 /* {{{ apc_fixup_op_array_jumps */
1126 static void apc_fixup_op_array_jumps(zend_op_array *dst, zend_op_array *src )
1130 for (i=0; i < dst->last; ++i) {
1131 zend_op *zo = &(dst->opcodes[i]);
1132 /*convert opline number to jump address*/
1133 switch (zo->opcode) {
1135 /*Note: if src->opcodes != dst->opcodes then we need to the opline according to src*/
1136 zo->op1.u.jmp_addr = dst->opcodes + (zo->op1.u.jmp_addr - src->opcodes);
1142 zo->op2.u.jmp_addr = dst->opcodes + (zo->op2.u.jmp_addr - src->opcodes);
1152 /* {{{ apc_copy_op_array */
1153 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)
1156 int local_dst_alloc = 0;
1157 apc_fileinfo_t fileinfo;
1158 char canon_path[MAXPATHLEN];
1159 char *fullpath = NULL;
1160 #ifdef ZEND_ENGINE_2
1161 apc_opflags_t * flags = NULL;
1164 assert(src != NULL);
1167 CHECK(dst = (zend_op_array*) allocate(sizeof(src[0])));
1168 local_dst_alloc = 1;
1171 if(APCG(apc_optimize_function)) {
1172 APCG(apc_optimize_function)(src TSRMLS_CC);
1175 /* start with a bitwise copy of the array */
1176 memcpy(dst, src, sizeof(src[0]));
1178 dst->function_name = NULL;
1179 dst->filename = NULL;
1180 dst->refcount = NULL;
1181 dst->opcodes = NULL;
1182 dst->brk_cont_array = NULL;
1183 dst->static_variables = NULL;
1184 #ifdef ZEND_ENGINE_2
1185 dst->try_catch_array = NULL;
1186 dst->arg_info = NULL;
1187 dst->doc_comment = NULL;
1189 dst->arg_types = NULL;
1191 #ifdef ZEND_ENGINE_2_1
1195 /* copy the arg types array (if set) */
1196 #ifdef ZEND_ENGINE_2
1197 if (src->arg_info) {
1198 if(!(dst->arg_info = my_copy_arg_info_array(NULL,
1207 if (src->arg_types) {
1208 if(!(dst->arg_types = apc_xmemcpy(src->arg_types,
1209 sizeof(src->arg_types[0]) * (src->arg_types[0]+1),
1216 if (src->function_name) {
1217 if(!(dst->function_name = apc_xstrdup(src->function_name, allocate))) {
1221 if (src->filename) {
1222 if(!(dst->filename = apc_xstrdup(src->filename, allocate))) {
1227 if(!(dst->refcount = apc_xmemcpy(src->refcount,
1228 sizeof(src->refcount[0]),
1233 /* deep-copy the opcodes */
1234 if(!(dst->opcodes = (zend_op*) allocate(sizeof(zend_op) * src->last))) {
1238 #ifdef ZEND_ENGINE_2
1239 if(APCG(reserved_offset) != -1) {
1240 /* Insanity alert: the void* pointer is cast into an apc_opflags_t
1241 * struct. apc_zend_init() checks to ensure that it fits in a void* */
1242 flags = (apc_opflags_t*) & (dst->reserved[APCG(reserved_offset)]);
1243 memset(flags, 0, sizeof(apc_opflags_t));
1244 /* assert(sizeof(apc_opflags_t) < sizeof(dst->reserved)); */
1248 for (i = 0; i < src->last; i++) {
1249 #ifdef ZEND_ENGINE_2
1250 zend_op *zo = &(src->opcodes[i]);
1251 /* a lot of files are merely constant arrays with no jumps */
1252 switch (zo->opcode) {
1259 flags->has_jumps = 1;
1262 #ifdef ZEND_ENGINE_2
1263 /* auto_globals_jit was not in php-4.3.* */
1267 case ZEND_FETCH_FUNC_ARG:
1268 if(PG(auto_globals_jit) && flags != NULL)
1270 /* The fetch is only required if auto_globals_jit=1 */
1271 if(zo->op2.u.EA.type == ZEND_FETCH_GLOBAL &&
1272 zo->op1.op_type == IS_CONST &&
1273 zo->op1.u.constant.type == IS_STRING) {
1274 znode * varname = &zo->op1;
1275 if (varname->u.constant.value.str.val[0] == '_') {
1276 #define SET_IF_AUTOGLOBAL(member) \
1277 if(!strcmp(varname->u.constant.value.str.val, #member)) \
1278 flags->member = 1 /* no ';' here */
1279 SET_IF_AUTOGLOBAL(_GET);
1280 else SET_IF_AUTOGLOBAL(_POST);
1281 else SET_IF_AUTOGLOBAL(_COOKIE);
1282 else SET_IF_AUTOGLOBAL(_SERVER);
1283 else SET_IF_AUTOGLOBAL(_ENV);
1284 else SET_IF_AUTOGLOBAL(_FILES);
1285 else SET_IF_AUTOGLOBAL(_REQUEST);
1286 else if(zend_is_auto_global(
1287 varname->u.constant.value.str.val,
1288 varname->u.constant.value.str.len
1291 flags->unknown_global = 1;
1298 case ZEND_RECV_INIT:
1299 if(zo->op2.op_type == IS_CONST &&
1300 zo->op2.u.constant.type == IS_CONSTANT_ARRAY) {
1302 flags->deep_copy = 1;
1307 if((zo->op1.op_type == IS_CONST &&
1308 zo->op1.u.constant.type == IS_CONSTANT_ARRAY) ||
1309 (zo->op2.op_type == IS_CONST &&
1310 zo->op2.u.constant.type == IS_CONSTANT_ARRAY)) {
1312 flags->deep_copy = 1;
1318 if(!(my_copy_zend_op(dst->opcodes+i, src->opcodes+i, allocate, deallocate))) {
1320 for(ii = i-1; ii>=0; ii--) {
1321 my_destroy_zend_op(dst->opcodes+ii, deallocate);
1325 #ifdef ZEND_ENGINE_2
1326 /* This code breaks apc's rule#1 - cache what you compile */
1327 if(APCG(fpstat)==0) {
1328 if((zo->opcode == ZEND_INCLUDE_OR_EVAL) &&
1329 (zo->op1.op_type == IS_CONST && zo->op1.u.constant.type == IS_STRING)) {
1330 /* constant includes */
1331 if(!IS_ABSOLUTE_PATH(Z_STRVAL_P(&zo->op1.u.constant),Z_STRLEN_P(&zo->op1.u.constant))) {
1332 if (apc_search_paths(Z_STRVAL_P(&zo->op1.u.constant), PG(include_path), &fileinfo) == 0) {
1333 if((fullpath = realpath(fileinfo.fullpath, canon_path))) {
1334 /* everything has to go through a realpath() */
1335 zend_op *dzo = &(dst->opcodes[i]);
1336 deallocate(dzo->op1.u.constant.value.str.val);
1337 dzo->op1.u.constant.value.str.len = strlen(fullpath);
1338 dzo->op1.u.constant.value.str.val = apc_xstrdup(fullpath, allocate);
1347 #ifdef ZEND_ENGINE_2
1348 if(flags == NULL || flags->has_jumps) {
1349 apc_fixup_op_array_jumps(dst,src);
1353 /* copy the break-continue array */
1354 if (src->brk_cont_array) {
1355 if(!(dst->brk_cont_array =
1356 apc_xmemcpy(src->brk_cont_array,
1357 sizeof(src->brk_cont_array[0]) * src->last_brk_cont,
1359 goto cleanup_opcodes;
1363 /* copy the table of static variables */
1364 if (src->static_variables) {
1365 if(!(dst->static_variables = my_copy_static_variables(src, allocate, deallocate))) {
1366 goto cleanup_opcodes;
1370 #ifdef ZEND_ENGINE_2
1371 if (src->try_catch_array) {
1372 if(!(dst->try_catch_array =
1373 apc_xmemcpy(src->try_catch_array,
1374 sizeof(src->try_catch_array[0]) * src->last_try_catch,
1376 goto cleanup_opcodes;
1381 #ifdef ZEND_ENGINE_2_1 /* PHP 5.1 */
1383 if(!(dst->vars = apc_xmemcpy(src->vars,
1384 sizeof(src->vars[0]) * src->last_var,
1386 goto cleanup_opcodes;
1389 for(i = 0; i < src->last_var; i++) dst->vars[i].name = NULL;
1391 for(i = 0; i < src->last_var; i++) {
1392 if(!(dst->vars[i].name = apc_xmemcpy(src->vars[i].name,
1393 src->vars[i].name_len + 1,
1396 goto cleanup_opcodes;
1402 #ifdef ZEND_ENGINE_2
1403 if (src->doc_comment) {
1404 if (!(dst->doc_comment
1405 = apc_xmemcpy(src->doc_comment, src->doc_comment_len+1, allocate))) {
1406 goto cleanup_opcodes;
1415 for(i=0; i < src->last; i++) my_destroy_zend_op(dst->opcodes+i, deallocate);
1418 if(dst->function_name) deallocate(dst->function_name);
1419 if(dst->refcount) deallocate(dst->refcount);
1420 if(dst->filename) deallocate(dst->filename);
1421 #ifdef ZEND_ENGINE_2
1422 if(dst->arg_info) my_free_arg_info_array(dst->arg_info, dst->num_args, deallocate);
1423 if(dst->try_catch_array) deallocate(dst->try_catch_array);
1424 if(dst->doc_comment) deallocate(dst->doc_comment);
1426 if(dst->arg_types) deallocate(dst->arg_types);
1428 if(dst->opcodes) deallocate(dst->opcodes);
1429 if(dst->brk_cont_array) deallocate(dst->brk_cont_array);
1430 if(dst->static_variables) my_free_hashtable(dst->static_variables, (ht_free_fun_t)my_free_zval_ptr, (apc_free_t)deallocate);
1431 #ifdef ZEND_ENGINE_2_1
1433 for(i=0; i < dst->last_var; i++) {
1434 if(dst->vars[i].name) deallocate(dst->vars[i].name);
1436 deallocate(dst->vars);
1439 if(local_dst_alloc) deallocate(dst);
1444 /* {{{ apc_copy_new_functions */
1445 apc_function_t* apc_copy_new_functions(int old_count, apc_malloc_t allocate, apc_free_t deallocate TSRMLS_DC)
1447 apc_function_t* array;
1448 int new_count; /* number of new functions in table */
1451 new_count = zend_hash_num_elements(CG(function_table)) - old_count;
1452 assert(new_count >= 0);
1456 allocate(sizeof(apc_function_t) * (new_count+1)));
1458 if (new_count == 0) {
1459 array[0].function = NULL;
1463 /* Skip the first `old_count` functions in the table */
1464 zend_hash_internal_pointer_reset(CG(function_table));
1465 for (i = 0; i < old_count; i++) {
1466 zend_hash_move_forward(CG(function_table));
1469 /* Add the next `new_count` functions to our array */
1470 for (i = 0; i < new_count; i++) {
1475 zend_hash_get_current_key_ex(CG(function_table),
1482 zend_hash_get_current_data(CG(function_table), (void**) &fun);
1484 if(!(array[i].name = apc_xmemcpy(key, (int) key_size, allocate))) {
1486 for(ii=i-1; ii>=0; ii--) {
1487 deallocate(array[ii].name);
1488 my_free_function(array[ii].function, deallocate);
1493 array[i].name_len = (int) key_size-1;
1494 if(!(array[i].function = my_copy_function(NULL, fun, allocate, deallocate))) {
1496 deallocate(array[i].name);
1497 for(ii=i-1; ii>=0; ii--) {
1498 deallocate(array[ii].name);
1499 my_free_function(array[ii].function, deallocate);
1504 zend_hash_move_forward(CG(function_table));
1507 array[i].function = NULL;
1512 /* {{{ apc_copy_new_classes */
1513 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)
1516 int new_count; /* number of new classes in table */
1519 new_count = zend_hash_num_elements(CG(class_table)) - old_count;
1520 assert(new_count >= 0);
1524 allocate(sizeof(apc_class_t)*(new_count+1)));
1526 if (new_count == 0) {
1527 array[0].class_entry = NULL;
1531 /* Skip the first `old_count` classes in the table */
1532 zend_hash_internal_pointer_reset(CG(class_table));
1533 for (i = 0; i < old_count; i++) {
1534 zend_hash_move_forward(CG(class_table));
1537 /* Add the next `new_count` classes to our array */
1538 for (i = 0; i < new_count; i++) {
1541 zend_class_entry* elem = NULL;
1543 array[i].class_entry = NULL;
1545 zend_hash_get_current_key_ex(CG(class_table),
1552 zend_hash_get_current_data(CG(class_table), (void**) &elem);
1555 #ifdef ZEND_ENGINE_2
1556 elem = *((zend_class_entry**)elem);
1559 if(!(array[i].name = apc_xmemcpy(key, (int) key_size, allocate))) {
1562 for(ii=i-1; ii>=0; ii--) {
1563 deallocate(array[ii].name);
1564 my_destroy_class_entry(array[ii].class_entry, deallocate);
1565 deallocate(array[ii].class_entry);
1570 array[i].name_len = (int) key_size-1;
1571 if(!(array[i].class_entry = my_copy_class_entry(NULL, elem, allocate, deallocate))) {
1574 deallocate(array[i].name);
1575 for(ii=i-1; ii>=0; ii--) {
1576 deallocate(array[ii].name);
1577 my_destroy_class_entry(array[ii].class_entry, deallocate);
1578 deallocate(array[ii].class_entry);
1585 * If the class has a pointer to its parent class, save the parent
1586 * name so that we can enable compile-time inheritance when we reload
1587 * the child class; otherwise, set the parent name to null and scan
1588 * the op_array to determine if this class inherits from some base
1589 * class at execution-time.
1593 if(!(array[i].parent_name =
1594 apc_xstrdup(elem->parent->name, allocate))) {
1597 for(ii=i; ii>=0; ii--) {
1598 deallocate(array[ii].name);
1599 my_destroy_class_entry(array[ii].class_entry, deallocate);
1600 deallocate(array[ii].class_entry);
1602 if(array[ii].parent_name) deallocate(array[ii].parent_name);
1607 array[i].is_derived = 1;
1610 array[i].parent_name = NULL;
1611 array[i].is_derived = is_derived_class(op_array, key, key_size);
1614 zend_hash_move_forward(CG(class_table));
1617 array[i].class_entry = NULL;
1622 /* {{{ my_destroy_zval_ptr */
1623 static void my_destroy_zval_ptr(zval** src, apc_free_t deallocate)
1625 assert(src != NULL);
1626 if(my_destroy_zval(src[0], deallocate) == SUCCESS) {
1632 /* {{{ my_destroy_zval */
1633 static int my_destroy_zval(zval* src, apc_free_t deallocate)
1638 switch (src->type & ~IS_CONSTANT_INDEX) {
1648 #ifndef ZEND_ENGINE_2
1651 deallocate(src->value.str.val);
1656 /* Maintain a list of zvals we've copied to properly handle recursive structures */
1657 if(APCG(copied_zvals)) {
1658 if(zend_hash_index_find(APCG(copied_zvals), (ulong)src, (void**)&tmp) == SUCCESS) {
1662 zend_hash_index_update(APCG(copied_zvals), (ulong)src, (void**)&src, sizeof(zval*), NULL);
1666 case IS_CONSTANT_ARRAY:
1667 my_free_hashtable(src->value.ht,
1668 (ht_free_fun_t) my_free_zval_ptr,
1673 #ifndef ZEND_ENGINE_2
1674 my_destroy_class_entry(src->value.obj.ce, deallocate);
1675 deallocate(src->value.obj.ce);
1676 my_free_hashtable(src->value.obj.properties,
1677 (ht_free_fun_t) my_free_zval_ptr,
1690 /* {{{ my_destroy_znode */
1691 static void my_destroy_znode(znode* src, apc_free_t deallocate)
1693 if (src->op_type == IS_CONST) {
1694 my_destroy_zval(&src->u.constant, deallocate);
1699 /* {{{ my_destroy_zend_op */
1700 static void my_destroy_zend_op(zend_op* src, apc_free_t deallocate)
1702 my_destroy_znode(&src->result, deallocate);
1703 my_destroy_znode(&src->op1, deallocate);
1704 my_destroy_znode(&src->op2, deallocate);
1708 /* {{{ my_destroy_function */
1709 static void my_destroy_function(zend_function* src, apc_free_t deallocate)
1711 assert(src != NULL);
1713 switch (src->type) {
1714 case ZEND_INTERNAL_FUNCTION:
1715 case ZEND_OVERLOADED_FUNCTION:
1718 case ZEND_USER_FUNCTION:
1719 case ZEND_EVAL_CODE:
1720 my_destroy_op_array(&src->op_array, deallocate);
1729 /* {{{ my_destroy_function_entry */
1730 static void my_destroy_function_entry(zend_function_entry* src, apc_free_t deallocate)
1732 assert(src != NULL);
1734 deallocate((char*)src->fname);
1735 #ifdef ZEND_ENGINE_2
1736 if (src->arg_info) {
1737 my_free_arg_info_array((zend_arg_info*)src->arg_info, src->num_args, deallocate);
1740 if (src->func_arg_types) {
1741 deallocate(src->func_arg_types);
1747 #ifdef ZEND_ENGINE_2
1748 /* {{{ my_destroy_property_info*/
1749 static void my_destroy_property_info(zend_property_info* src, apc_free_t deallocate)
1751 assert(src != NULL);
1753 deallocate(src->name);
1754 #if defined(ZEND_ENGINE_2) && PHP_MINOR_VERSION > 0
1755 if(src->doc_comment) deallocate(src->doc_comment);
1760 /* {{{ my_destroy_arg_info_array */
1761 static void my_destroy_arg_info_array(zend_arg_info* src, uint num_args, apc_free_t deallocate)
1765 assert(src != NULL);
1767 for(i=0; i < num_args; i++) {
1768 my_destroy_arg_info(&src[i], deallocate);
1773 /* {{{ my_destroy_arg_info */
1774 static void my_destroy_arg_info(zend_arg_info* src, apc_free_t deallocate)
1776 assert(src != NULL);
1778 deallocate((char*)src->name);
1779 deallocate((char*)src->class_name);
1784 /* {{{ my_destroy_class_entry */
1785 static void my_destroy_class_entry(zend_class_entry* src, apc_free_t deallocate)
1789 assert(src != NULL);
1791 deallocate(src->name);
1792 #ifndef ZEND_ENGINE_2
1793 deallocate(src->refcount);
1795 if(src->doc_comment) deallocate(src->doc_comment);
1796 if(src->filename) deallocate(src->filename);
1799 my_destroy_hashtable(&src->function_table,
1800 (ht_free_fun_t) my_free_function,
1803 my_destroy_hashtable(&src->default_properties,
1804 (ht_free_fun_t) my_free_zval_ptr,
1807 #ifdef ZEND_ENGINE_2
1808 my_destroy_hashtable(&src->properties_info,
1809 (ht_free_fun_t) my_free_property_info,
1811 if(src->static_members)
1813 my_destroy_hashtable(src->static_members,
1814 (ht_free_fun_t) my_free_zval_ptr,
1816 if(src->static_members != &(src->default_static_members))
1818 deallocate(src->static_members);
1822 my_destroy_hashtable(&src->constants_table,
1823 (ht_free_fun_t) my_free_zval_ptr,
1827 if (src->builtin_functions) {
1828 for (i = 0; src->builtin_functions[i].fname != NULL; i++) {
1829 my_destroy_function_entry((zend_function_entry*)(&src->builtin_functions[i]), deallocate);
1831 deallocate((zend_function_entry*)src->builtin_functions);
1836 /* {{{ my_destroy_hashtable */
1837 static void my_destroy_hashtable(HashTable* src, ht_free_fun_t free_fn, apc_free_t deallocate)
1841 assert(src != NULL);
1843 for (i = 0; i < src->nTableSize; i++) {
1844 Bucket* p = src->arBuckets[i];
1848 free_fn(q->pData, deallocate);
1853 deallocate(src->arBuckets);
1857 /* {{{ my_destroy_op_array */
1858 static void my_destroy_op_array(zend_op_array* src, apc_free_t deallocate)
1862 assert(src != NULL);
1864 #ifdef ZEND_ENGINE_2
1865 if (src->arg_info) {
1866 my_free_arg_info_array(src->arg_info, src->num_args, deallocate);
1869 if (src->arg_types) {
1870 deallocate(src->arg_types);
1874 deallocate(src->function_name);
1875 deallocate(src->filename);
1876 deallocate(src->refcount);
1878 for (i = 0; i < src->last; i++) {
1879 my_destroy_zend_op(src->opcodes + i, deallocate);
1881 deallocate(src->opcodes);
1883 if (src->brk_cont_array) {
1884 deallocate(src->brk_cont_array);
1887 if (src->static_variables) {
1888 my_free_hashtable(src->static_variables,
1889 (ht_free_fun_t) my_free_zval_ptr,
1893 #ifdef ZEND_ENGINE_2_1
1895 for(i=0; i < src->last_var; i++) {
1896 if(src->vars[i].name) deallocate(src->vars[i].name);
1898 deallocate(src->vars);
1901 #ifdef ZEND_ENGINE_2
1902 if(src->try_catch_array) {
1903 deallocate(src->try_catch_array);
1905 if (src->doc_comment) {
1906 deallocate(src->doc_comment);
1912 /* {{{ my_free_zval_ptr */
1913 static void my_free_zval_ptr(zval** src, apc_free_t deallocate)
1915 my_destroy_zval_ptr(src, deallocate);
1920 #ifdef ZEND_ENGINE_2
1921 /* {{{ my_free_property_info */
1922 static void my_free_property_info(zend_property_info* src, apc_free_t deallocate)
1924 my_destroy_property_info(src, deallocate);
1929 /* {{{ my_free_arg_info_array */
1930 static void my_free_arg_info_array(zend_arg_info* src, uint num_args, apc_free_t deallocate)
1932 my_destroy_arg_info_array(src, num_args, deallocate);
1937 /* {{{ my_free_arg_info */
1938 static void my_free_arg_info(zend_arg_info* src, apc_free_t deallocate)
1940 my_destroy_arg_info(src, deallocate);
1946 /* {{{ my_free_function */
1947 static void my_free_function(zend_function* src, apc_free_t deallocate)
1949 my_destroy_function(src, deallocate);
1954 /* {{{ my_free_hashtable */
1955 static void my_free_hashtable(HashTable* src, ht_free_fun_t free_fn, apc_free_t deallocate)
1957 my_destroy_hashtable(src, free_fn, deallocate);
1962 /* {{{ apc_free_op_array */
1963 void apc_free_op_array(zend_op_array* src, apc_free_t deallocate)
1966 my_destroy_op_array(src, deallocate);
1972 /* {{{ apc_free_functions */
1973 void apc_free_functions(apc_function_t* src, apc_free_t deallocate)
1978 for (i = 0; src[i].function != NULL; i++) {
1979 deallocate(src[i].name);
1980 my_destroy_function(src[i].function, deallocate);
1981 deallocate(src[i].function);
1988 /* {{{ apc_free_classes */
1989 void apc_free_classes(apc_class_t* src, apc_free_t deallocate)
1994 for (i = 0; src[i].class_entry != NULL; i++) {
1995 deallocate(src[i].name);
1996 deallocate(src[i].parent_name);
1997 my_destroy_class_entry(src[i].class_entry, deallocate);
1998 deallocate(src[i].class_entry);
2005 /* {{{ apc_free_zval */
2006 void apc_free_zval(zval* src, apc_free_t deallocate)
2009 if(my_destroy_zval(src, deallocate) == SUCCESS) {
2017 /* Used only by my_prepare_op_array_for_execution */
2018 #define APC_PREPARE_FETCH_GLOBAL_FOR_EXECUTION() \
2019 /* The fetch is only required if auto_globals_jit=1 */ \
2020 if(zo->op2.u.EA.type == ZEND_FETCH_GLOBAL && \
2021 zo->op1.op_type == IS_CONST && \
2022 zo->op1.u.constant.type == IS_STRING && \
2023 zo->op1.u.constant.value.str.val[0] == '_') { \
2025 znode* varname = &zo->op1; \
2026 (void)zend_is_auto_global(varname->u.constant.value.str.val, \
2027 varname->u.constant.value.str.len \
2031 /* {{{ my_prepare_op_array_for_execution */
2032 static int my_prepare_op_array_for_execution(zend_op_array* dst, zend_op_array* src TSRMLS_DC)
2034 /* combine my_fetch_global_vars and my_copy_data_exceptions.
2035 * - Pre-fetch superglobals which would've been pre-fetched in parse phase.
2036 * - If the opcode stream contain mutable data, ensure a copy.
2037 * - Fixup array jumps in the same loop.
2042 #ifdef ZEND_ENGINE_2
2043 apc_opflags_t * flags = APCG(reserved_offset) != -1 ?
2044 (apc_opflags_t*) & (src->reserved[APCG(reserved_offset)]) : NULL;
2045 int needcopy = flags ? flags->deep_copy : 1;
2046 /* auto_globals_jit was not in php4 */
2047 int do_prepare_fetch_global = PG(auto_globals_jit) && (flags == NULL || flags->unknown_global);
2049 #define FETCH_AUTOGLOBAL(member) do { \
2050 if(flags && flags->member == 1) { \
2051 zend_is_auto_global(#member,\
2052 (sizeof(#member) - 1)\
2057 FETCH_AUTOGLOBAL(_GET);
2058 FETCH_AUTOGLOBAL(_POST);
2059 FETCH_AUTOGLOBAL(_COOKIE);
2060 FETCH_AUTOGLOBAL(_SERVER);
2061 FETCH_AUTOGLOBAL(_ENV);
2062 FETCH_AUTOGLOBAL(_FILES);
2063 FETCH_AUTOGLOBAL(_REQUEST);
2067 int do_prepare_fetch_global = 0;
2070 for(j = 0; j < src->last; j++) {
2071 zo = &src->opcodes[j];
2073 if( ((zo->op1.op_type == IS_CONST &&
2074 zo->op1.u.constant.type == IS_CONSTANT_ARRAY)) ||
2075 ((zo->op2.op_type == IS_CONST &&
2076 zo->op2.u.constant.type == IS_CONSTANT_ARRAY))) {
2084 dst->opcodes = (zend_op*) apc_xmemcpy(src->opcodes,
2085 sizeof(zend_op) * src->last,
2091 if( ((zo->op1.op_type == IS_CONST &&
2092 zo->op1.u.constant.type == IS_CONSTANT_ARRAY)) ||
2093 ((zo->op2.op_type == IS_CONST &&
2094 zo->op2.u.constant.type == IS_CONSTANT_ARRAY))) {
2096 if(!(my_copy_zend_op(dzo, zo, apc_php_malloc, apc_php_free))) {
2097 assert(0); /* emalloc failed or a bad constant array */
2101 #ifdef ZEND_ENGINE_2
2102 switch(zo->opcode) {
2104 dzo->op1.u.jmp_addr = dst->opcodes +
2105 (zo->op1.u.jmp_addr - src->opcodes);
2111 dzo->op2.u.jmp_addr = dst->opcodes +
2112 (zo->op2.u.jmp_addr - src->opcodes);
2117 case ZEND_FETCH_FUNC_ARG:
2118 if(do_prepare_fetch_global)
2120 APC_PREPARE_FETCH_GLOBAL_FOR_EXECUTION();
2131 #ifdef ZEND_ENGINE_2
2132 } else { /* !needcopy */
2133 /* The fetch is only required if auto_globals_jit=1 */
2134 if(do_prepare_fetch_global)
2139 if(zo->opcode == ZEND_FETCH_R ||
2140 zo->opcode == ZEND_FETCH_W ||
2141 zo->opcode == ZEND_FETCH_IS ||
2142 zo->opcode == ZEND_FETCH_FUNC_ARG
2144 APC_PREPARE_FETCH_GLOBAL_FOR_EXECUTION();
2157 /* {{{ apc_copy_op_array_for_execution */
2158 zend_op_array* apc_copy_op_array_for_execution(zend_op_array* dst, zend_op_array* src TSRMLS_DC)
2161 dst = (zend_op_array*) emalloc(sizeof(src[0]));
2163 memcpy(dst, src, sizeof(src[0]));
2164 dst->static_variables = my_copy_static_variables(src, apc_php_malloc, apc_php_free);
2166 dst->refcount = apc_xmemcpy(src->refcount,
2167 sizeof(src->refcount[0]),
2170 my_prepare_op_array_for_execution(dst,src TSRMLS_CC);
2176 /* {{{ apc_copy_function_for_execution */
2177 zend_function* apc_copy_function_for_execution(zend_function* src)
2182 dst = (zend_function*) emalloc(sizeof(src[0]));
2183 memcpy(dst, src, sizeof(src[0]));
2184 apc_copy_op_array_for_execution(&(dst->op_array), &(src->op_array) TSRMLS_CC);
2189 /* {{{ apc_copy_function_for_execution_ex */
2190 zend_function* apc_copy_function_for_execution_ex(void *dummy, zend_function* src, apc_malloc_t allocate, apc_free_t deallocate)
2192 if(src->type==ZEND_INTERNAL_FUNCTION || src->type==ZEND_OVERLOADED_FUNCTION) return src;
2193 return apc_copy_function_for_execution(src);
2197 /* {{{ apc_copy_class_entry_for_execution */
2198 zend_class_entry* apc_copy_class_entry_for_execution(zend_class_entry* src, int is_derived)
2200 zend_class_entry* dst = (zend_class_entry*) emalloc(sizeof(src[0]));
2201 memcpy(dst, src, sizeof(src[0]));
2203 #ifdef ZEND_ENGINE_2
2204 if(src->num_interfaces)
2206 /* These are slots to be populated later by ADD_INTERFACE insns */
2207 dst->interfaces = apc_php_malloc(
2208 sizeof(zend_class_entry*) * src->num_interfaces);
2209 memset(dst->interfaces, 0,
2210 sizeof(zend_class_entry*) * src->num_interfaces);
2214 /* assert(dst->interfaces == NULL); */
2218 #ifndef ZEND_ENGINE_2
2219 dst->refcount = apc_xmemcpy(src->refcount,
2220 sizeof(src->refcount[0]),
2224 /* Deep-copy the class properties, because they will be modified */
2226 my_copy_hashtable(&dst->default_properties,
2227 &src->default_properties,
2228 (ht_copy_fun_t) my_copy_zval_ptr,
2229 (ht_free_fun_t) my_free_zval_ptr,
2231 apc_php_malloc, apc_php_free);
2233 /* For derived classes, we must also copy the function hashtable (although
2234 * we can merely bitwise copy the functions it contains) */
2236 my_copy_hashtable(&dst->function_table,
2237 &src->function_table,
2238 (ht_copy_fun_t) apc_copy_function_for_execution_ex,
2241 apc_php_malloc, apc_php_free);
2242 #ifdef ZEND_ENGINE_2
2243 my_fixup_hashtable(&dst->function_table, (ht_fixup_fun_t)my_fixup_function_for_execution, src, dst);
2245 /* zend_do_inheritance merges properties_info.
2246 * Need only shallow copying as it doesn't hold the pointers.
2248 my_copy_hashtable(&dst->properties_info,
2249 &src->properties_info,
2250 (ht_copy_fun_t) my_copy_property_info_for_execution,
2253 apc_php_malloc, apc_php_free);
2255 #ifdef ZEND_ENGINE_2_2
2256 /* php5.2 introduced a scope attribute for property info */
2257 my_fixup_hashtable(&dst->properties_info, (ht_fixup_fun_t)my_fixup_property_info_for_execution, src, dst);
2260 /* if inheritance results in a hash_del, it might result in
2261 * a pefree() of the pointers here. Deep copying required.
2264 my_copy_hashtable(&dst->constants_table,
2265 &src->constants_table,
2266 (ht_copy_fun_t) my_copy_zval_ptr,
2269 apc_php_malloc, apc_php_free);
2271 my_copy_hashtable(&dst->default_static_members,
2272 &src->default_static_members,
2273 (ht_copy_fun_t) my_copy_zval_ptr,
2274 (ht_free_fun_t) my_free_zval_ptr,
2276 apc_php_malloc, apc_php_free);
2278 if(src->static_members != &(src->default_static_members))
2280 dst->static_members = my_copy_hashtable(NULL,
2281 src->static_members,
2282 (ht_copy_fun_t) my_copy_zval_ptr,
2283 (ht_free_fun_t) my_free_zval_ptr,
2285 apc_php_malloc, apc_php_free);
2289 dst->static_members = &(dst->default_static_members);
2298 /* {{{ apc_free_class_entry_after_execution */
2299 void apc_free_class_entry_after_execution(zend_class_entry* src)
2301 #ifdef ZEND_ENGINE_2
2302 if(src->num_interfaces > 0 && src->interfaces) {
2303 apc_php_free(src->interfaces);
2304 src->interfaces = NULL;
2305 src->num_interfaces = 0;
2307 /* my_destroy_hashtable() does not play nice with refcounts */
2309 zend_hash_clean(&src->default_static_members);
2310 if(src->static_members != &(src->default_static_members))
2312 zend_hash_destroy(src->static_members);
2313 apc_php_free(src->static_members);
2314 src->static_members = NULL;
2318 src->static_members = NULL;
2320 zend_hash_clean(&src->default_properties);
2321 zend_hash_clean(&src->constants_table);
2324 /* TODO: more cleanup */
2328 #ifdef ZEND_ENGINE_2
2330 /* {{{ my_fixup_function */
2331 static void my_fixup_function(Bucket *p, zend_class_entry *src, zend_class_entry *dst)
2333 zend_function* zf = p->pData;
2335 #define SET_IF_SAME_NAME(member) \
2337 if(src->member && !strcmp(zf->common.function_name, src->member->common.function_name)) { \
2343 if(zf->common.scope == src)
2346 /* Fixing up the default functions for objects here since
2347 * we need to compare with the newly allocated functions
2349 * caveat: a sub-class method can have the same name as the
2350 * parent's constructor and create problems.
2353 if(zf->common.fn_flags & ZEND_ACC_CTOR) dst->constructor = zf;
2354 else if(zf->common.fn_flags & ZEND_ACC_DTOR) dst->destructor = zf;
2355 else if(zf->common.fn_flags & ZEND_ACC_CLONE) dst->clone = zf;
2358 SET_IF_SAME_NAME(__get);
2359 SET_IF_SAME_NAME(__set);
2360 SET_IF_SAME_NAME(__unset);
2361 SET_IF_SAME_NAME(__isset);
2362 SET_IF_SAME_NAME(__call);
2363 #ifdef ZEND_ENGINE_2_2
2364 SET_IF_SAME_NAME(__tostring);
2367 zf->common.scope = dst;
2371 /* no other function should reach here */
2375 #undef SET_IF_SAME_NAME
2379 #ifdef ZEND_ENGINE_2_2
2380 /* {{{ my_fixup_property_info */
2381 static void my_fixup_property_info(Bucket *p, zend_class_entry *src, zend_class_entry *dst)
2383 zend_property_info* property_info = (zend_property_info*)p->pData;
2385 if(property_info->ce == src)
2387 property_info->ce = dst;
2391 assert(0); /* should never happen */
2397 /* {{{ my_fixup_hashtable */
2398 static void my_fixup_hashtable(HashTable *ht, ht_fixup_fun_t fixup, zend_class_entry *src, zend_class_entry *dst)
2404 for (i = 0; i < ht->nTableSize; i++) {
2405 if(!ht->arBuckets) break;
2406 p = ht->arBuckets[i];
2417 /* {{{ my_check_copy_function */
2418 static int my_check_copy_function(Bucket* p, va_list args)
2420 zend_class_entry* src = va_arg(args, zend_class_entry*);
2421 zend_function* zf = (zend_function*)p->pData;
2422 #ifndef ZEND_ENGINE_2
2423 zend_class_entry* parent = src->parent;
2424 zend_function* parent_fn = NULL;
2427 #ifdef ZEND_ENGINE_2
2428 return (zf->common.scope == src);
2431 zend_hash_quick_find(&parent->function_table, p->arKey,
2432 p->nKeyLength, p->h, (void **) &parent_fn)==SUCCESS) {
2434 if((parent_fn && zf) &&
2435 (parent_fn->op_array.refcount == zf->op_array.refcount))
2445 /* {{{ my_check_copy_default_property */
2446 static int my_check_copy_default_property(Bucket* p, va_list args)
2448 zend_class_entry* src = va_arg(args, zend_class_entry*);
2449 zend_class_entry* parent = src->parent;
2450 zval ** child_prop = (zval**)p->pData;
2451 zval ** parent_prop = NULL;
2454 zend_hash_quick_find(&parent->default_properties, p->arKey,
2455 p->nKeyLength, p->h, (void **) &parent_prop)==SUCCESS) {
2457 if((parent_prop && child_prop) && (*parent_prop) == (*child_prop))
2463 /* possibly not in the parent */
2468 #ifdef ZEND_ENGINE_2
2470 /* {{{ my_check_copy_property_info */
2471 static int my_check_copy_property_info(Bucket* p, va_list args)
2473 zend_class_entry* src = va_arg(args, zend_class_entry*);
2474 zend_class_entry* parent = src->parent;
2475 zend_property_info* child_info = (zend_property_info*)p->pData;
2476 zend_property_info* parent_info = NULL;
2478 #ifdef ZEND_ENGINE_2_2
2479 /* so much easier */
2480 return (child_info->ce == src);
2484 zend_hash_quick_find(&parent->properties_info, p->arKey, p->nKeyLength,
2485 p->h, (void **) &parent_info)==SUCCESS) {
2486 if(parent_info->flags & ZEND_ACC_PRIVATE)
2490 if((parent_info->flags & ZEND_ACC_PPP_MASK) !=
2491 (child_info->flags & ZEND_ACC_PPP_MASK))
2493 /* TODO: figure out whether ACC_CHANGED is more appropriate
2500 /* property doesn't exist in parent, copy into cached child */
2505 /* {{{ my_check_copy_static_member */
2506 static int my_check_copy_static_member(Bucket* p, va_list args)
2508 zend_class_entry* src = va_arg(args, zend_class_entry*);
2509 HashTable * ht = va_arg(args, HashTable*);
2510 zend_class_entry* parent = src->parent;
2511 HashTable * parent_ht = NULL;
2513 char * class_name = NULL;
2515 zend_property_info *parent_info = NULL;
2516 zend_property_info *child_info = NULL;
2517 zval ** parent_prop = NULL;
2518 zval ** child_prop = (zval**)(p->pData);
2524 /* these do not need free'ing */
2525 #ifdef ZEND_ENGINE_2_2
2526 zend_unmangle_property_name(p->arKey, p->nKeyLength-1, &class_name, &member_name);
2528 zend_unmangle_property_name(p->arKey, &class_name, &member_name);
2531 /* please refer do_inherit_property_access_check in zend_compile.c
2532 * to understand why we lookup in properties_info.
2534 if((zend_hash_find(&parent->properties_info, member_name,
2535 strlen(member_name)+1, (void**)&parent_info) == SUCCESS)
2537 (zend_hash_find(&src->properties_info, member_name,
2538 strlen(member_name)+1, (void**)&child_info) == SUCCESS))
2540 if(child_info->flags & ZEND_ACC_STATIC &&
2541 (parent_info->flags & ZEND_ACC_PROTECTED &&
2542 child_info->flags & ZEND_ACC_PUBLIC))
2544 /* Do not copy into static_members. zend_do_inheritance
2545 * will automatically insert a NULL value.
2546 * TODO: decrement refcount or fixup when copying out for exec ?
2550 if(ht == &(src->default_static_members))
2552 parent_ht = &parent->default_static_members;
2556 parent_ht = parent->static_members;
2559 if(zend_hash_quick_find(parent_ht, p->arKey,
2560 p->nKeyLength, p->h, (void**)&parent_prop) == SUCCESS)
2562 /* they point to the same zval */
2563 if(*parent_prop == *child_prop)
2575 /* {{{ apc_register_optimizer(apc_optimize_function_t optimizer)
2576 * register a optimizer callback function, returns the previous callback
2578 apc_optimize_function_t apc_register_optimizer(apc_optimize_function_t optimizer TSRMLS_DC) {
2579 apc_optimize_function_t old_optimizer = APCG(apc_optimize_function);
2580 APCG(apc_optimize_function) = optimizer;
2581 return old_optimizer;
2589 * vim600: expandtab sw=4 ts=4 sts=4 fdm=marker
2590 * vim<600: expandtab sw=4 ts=4 sts=4