root/eaccelerator/tags/0.9.5-rc1/ea_restore.c

Revision 241, 30.1 kB (checked in by bart, 2 years ago)

Fix restoring of opcode handler for php 5.0.5 when files are loaded

from disk cache. This fixes bug #147

Some update in the release notes for the upcoming rc1

  • Property svn:eol-style set to native
  • Property svn:keywords set to svn:eol-style
Line 
1 /*
2    +----------------------------------------------------------------------+
3    | eAccelerator project                                                 |
4    +----------------------------------------------------------------------+
5    | Copyright (c) 2004 - 2006 eAccelerator                               |
6    | http://eaccelerator.net                                              |
7    +----------------------------------------------------------------------+
8    | This program is free software; you can redistribute it and/or        |
9    | modify it under the terms of the GNU General Public License          |
10    | as published by the Free Software Foundation; either version 2       |
11    | of the License, or (at your option) any later version.               |
12    |                                                                      |
13    | This program is distributed in the hope that it will be useful,      |
14    | but WITHOUT ANY WARRANTY; without even the implied warranty of       |
15    | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        |
16    | GNU General Public License for more details.                         |
17    |                                                                      |
18    | You should have received a copy of the GNU General Public License    |
19    | along with this program; if not, write to the Free Software          |
20    | Foundation, Inc., 59 Temple Place - Suite 330, Boston,               |
21    | MA  02111-1307, USA.                                                 |
22    |                                                                      |
23    | A copy is availble at http://www.gnu.org/copyleft/gpl.txt            |
24    +----------------------------------------------------------------------+
25    $Id: ea_restore.c 176 2006-03-05 12:18:54Z bart $
26 */
27
28 #include "eaccelerator.h"
29
30 #ifdef HAVE_EACCELERATOR
31
32 #include "debug.h"
33 #include "ea_restore.h"
34 #include "opcodes.h"
35 #include "zend.h"
36 #include "zend_API.h"
37 #include "zend_extensions.h"
38 #ifdef ZEND_ENGINE_2_1
39 #include "zend_vm.h"
40 #endif
41
42 #ifndef INCOMPLETE_CLASS
43 #  define INCOMPLETE_CLASS "__PHP_Incomplete_Class"
44 #endif
45 #ifndef MAGIC_MEMBER
46 #  define MAGIC_MEMBER "__PHP_Incomplete_Class_Name"
47 #endif
48
49 extern zend_extension *ZendOptimizer;
50 #if HARDENING_PATCH_HASH_PROTECT
51 extern unsigned int zend_hash_canary;
52 #endif
53
54 #ifdef ZEND_ENGINE_2
55 /* pointer to the properties_info hashtable destructor */
56 dtor_func_t properties_info_dtor = NULL;
57
58 /* This function creates a dummy class entry to steal the pointer to the
59  * properties_info hashtable destructor because it's declared static */
60 dtor_func_t get_zend_destroy_property_info(TSRMLS_D)
61 {
62         dtor_func_t property_dtor;
63         zend_class_entry dummy_class_entry;
64         dummy_class_entry.type = ZEND_USER_CLASS;
65
66         zend_initialize_class_data(&dummy_class_entry, 1 TSRMLS_CC);
67
68         property_dtor = dummy_class_entry.properties_info.pDestructor;
69
70         zend_hash_destroy(&dummy_class_entry.default_properties);
71         zend_hash_destroy(&dummy_class_entry.function_table);
72         zend_hash_destroy(&dummy_class_entry.constants_table);
73         zend_hash_destroy(&dummy_class_entry.properties_info);
74 #  ifdef ZEND_ENGINE_2_1
75         zend_hash_destroy(&dummy_class_entry.default_static_members);
76 #  endif
77 #  if defined(ZEND_ENGINE_2) && !defined(ZEND_ENGINE_2_1)
78         zend_hash_destroy(dummy_class_entry.static_members);
79         FREE_HASHTABLE(dummy_class_entry.static_members);
80 #  endif
81         return property_dtor;
82 }
83 #endif
84
85 /******************************************************************************/
86 /* Functions to restore a cached script from file cache                       */
87 /******************************************************************************/
88
89 typedef void (*fixup_bucket_t) (void *TSRMLS_DC);
90
91 #define fixup_zval_hash(from) \
92     fixup_hash(from, (fixup_bucket_t)fixup_zval TSRMLS_CC)
93
94 #ifdef ZEND_ENGINE_2
95 static void fixup_property_info(zend_property_info * from TSRMLS_DC)
96 {
97         FIXUP(from->name);
98 #ifdef ZEND_ENGINE_2_1
99         FIXUP(from->doc_comment);
100 #endif
101 }
102 #endif
103
104 static void fixup_hash(HashTable * source,
105                                            fixup_bucket_t fixup_bucket TSRMLS_DC)
106 {
107         unsigned int i;
108         Bucket *p;
109
110         if (source->nNumOfElements > 0) {
111                 if (!EAG(compress)) {
112                         if (source->arBuckets != NULL) {
113                                 FIXUP(source->arBuckets);
114                                 for (i = 0; i < source->nTableSize; i++) {
115                                         FIXUP(source->arBuckets[i]);
116                                 }
117                         }
118                 }
119                 FIXUP(source->pListHead);
120                 FIXUP(source->pListTail);
121
122                 p = source->pListHead;
123                 while (p) {
124                         FIXUP(p->pNext);
125                         FIXUP(p->pLast);
126                         FIXUP(p->pData);
127                         FIXUP(p->pDataPtr);
128                         FIXUP(p->pListLast);
129                         FIXUP(p->pListNext);
130                         if (p->pDataPtr) {
131                                 fixup_bucket(p->pDataPtr TSRMLS_CC);
132                                 p->pData = &p->pDataPtr;
133                         } else {
134                                 fixup_bucket(p->pData TSRMLS_CC);
135                         }
136                         p = p->pListNext;
137                 }
138                 source->pInternalPointer = source->pListHead;
139         }
140 }
141
142 void fixup_zval(zval * zv TSRMLS_DC)
143 {
144         switch (Z_TYPE_P(zv) & ~IS_CONSTANT_INDEX) {
145         case IS_CONSTANT:                       /* fallthrough */
146         case IS_STRING:
147                 FIXUP(Z_STRVAL_P(zv));
148                 break;
149         case IS_ARRAY:                          /* fallthrough */
150         case IS_CONSTANT_ARRAY:
151                 FIXUP(Z_ARRVAL_P(zv));
152                 fixup_zval_hash(Z_ARRVAL_P(zv));
153                 break;
154         case IS_OBJECT:
155                 if (!EAG(compress)) {
156                         return;
157                 }
158 #ifndef ZEND_ENGINE_2
159                 FIXUP(Z_OBJCE_P(zv));
160                 if (Z_OBJPROP_P(zv) != NULL) {
161                         FIXUP(Z_OBJPROP_P(zv));
162                         fixup_zval_hash(Z_OBJPROP_P(zv));
163                 }
164 #endif
165         default:
166                 break;
167         }
168 }
169
170 void fixup_op_array(eaccelerator_op_array * from TSRMLS_DC)
171 {
172         zend_op *opline;
173         zend_op *end;
174
175 #ifdef ZEND_ENGINE_2
176         if (from->num_args > 0) {
177                 zend_uint i;
178                 FIXUP(from->arg_info);
179                 for (i = 0; i < from->num_args; i++) {
180                         FIXUP(from->arg_info[i].name);
181                         FIXUP(from->arg_info[i].class_name);
182                 }
183         }
184 #else
185         FIXUP(from->arg_types);
186 #endif
187         FIXUP(from->function_name);
188 #ifdef ZEND_ENGINE_2
189         FIXUP(from->scope_name);
190 #endif
191         if (from->type == ZEND_INTERNAL_FUNCTION) {
192                 return;
193         }
194
195         if (from->opcodes != NULL) {
196                 FIXUP(from->opcodes);
197
198                 opline = from->opcodes;
199                 end = opline + from->last;
200                 EAG(compress) = 0;
201                 for (; opline < end; opline++) {
202                         /*
203                            if (opline->result.op_type == IS_CONST)
204                            fixup_zval(&opline->result.u.constant TSRMLS_CC);
205                          */
206                         if (opline->op1.op_type == IS_CONST)
207                                 fixup_zval(&opline->op1.u.constant TSRMLS_CC);
208                         if (opline->op2.op_type == IS_CONST)
209                                 fixup_zval(&opline->op2.u.constant TSRMLS_CC);
210 #ifdef ZEND_ENGINE_2
211                         switch (opline->opcode) {
212                         case ZEND_JMP:
213                                 FIXUP(opline->op1.u.jmp_addr);
214                                 break;
215                         case ZEND_JMPZ: /* fallthrough */
216                         case ZEND_JMPNZ:
217                         case ZEND_JMPZ_EX:
218                         case ZEND_JMPNZ_EX:
219                                 FIXUP(opline->op2.u.jmp_addr);
220                                 break;
221                         }
222 #  ifdef ZEND_ENGINE_2_1
223                         ZEND_VM_SET_OPCODE_HANDLER(opline);
224 #  elif defined(ZEND_ENGINE_2)
225             opline->handler = zend_opcode_handlers[opline->opcode];
226 #  else
227                         opline->handler = get_opcode_handler(opline->opcode TSRMLS_CC);
228 #  endif
229
230 #endif
231                 }
232                 EAG(compress) = 1;
233         }
234         FIXUP(from->brk_cont_array);
235 #ifdef ZEND_ENGINE_2
236         FIXUP(from->try_catch_array);
237 #endif
238         if (from->static_variables != NULL) {
239                 FIXUP(from->static_variables);
240                 fixup_zval_hash(from->static_variables);
241         }
242 #ifdef ZEND_ENGINE_2_1
243         if (from->vars != NULL) {
244                 int i;
245                 FIXUP(from->vars);
246                 for (i = 0; i < from->last_var; i++) {
247                         FIXUP(from->vars[i].name);
248                 }
249         }
250 #endif
251         FIXUP(from->filename);
252 }
253
254 void fixup_class_entry(eaccelerator_class_entry * from TSRMLS_DC)
255 {
256         FIXUP(from->name);
257         FIXUP(from->parent);
258 #ifdef ZEND_ENGINE_2
259         FIXUP(from->filename);
260         fixup_zval_hash(&from->constants_table);
261         fixup_zval_hash(&from->default_properties);
262         fixup_hash(&from->properties_info,
263                            (fixup_bucket_t) fixup_property_info TSRMLS_CC);
264 #  ifdef ZEND_ENGINE_2_1
265         fixup_zval_hash(&from->default_static_members);
266         if (from->static_members != NULL) {
267                 FIXUP(from->static_members);
268                 if (from->static_members != &from->default_static_members) {
269                         fixup_zval_hash(from->static_members);
270                 }
271         }
272 #  else
273         if (from->static_members != NULL) {
274                 FIXUP(from->static_members);
275                 fixup_zval_hash(from->static_members);
276         }
277 #  endif
278 #else
279         fixup_zval_hash(&from->default_properties);
280 #endif
281         fixup_hash(&from->function_table,
282                            (fixup_bucket_t) fixup_op_array TSRMLS_CC);
283 }
284
285 /******************************************************************************/
286 /* Functions to restore a php script from shared memory                       */
287 /******************************************************************************/
288
289 typedef void *(*restore_bucket_t) (void *TSRMLS_DC);
290
291 #define restore_zval_hash(target, source) \
292     restore_hash(target, source, (restore_bucket_t)restore_zval_ptr TSRMLS_CC)
293
294 static zval *restore_zval_ptr(zval * from TSRMLS_DC)
295 {
296         zval *p;
297         ALLOC_ZVAL(p);
298         memcpy(p, from, sizeof(zval));
299         restore_zval(p TSRMLS_CC);
300         /* hrak: reset refcount to make sure there is one reference to this val, and prevent memleaks */
301         p->refcount = 1;
302         return p;
303 }
304
305 static HashTable *restore_hash(HashTable * target, HashTable * source,
306                                                            restore_bucket_t copy_bucket TSRMLS_DC)
307 {
308         Bucket *p, *np, *prev_p;
309         int nIndex;
310
311         if (target == NULL) {
312                 ALLOC_HASHTABLE(target);
313         }
314         memcpy(target, source, sizeof(HashTable));
315         target->arBuckets =
316                 (Bucket **) emalloc(target->nTableSize * sizeof(Bucket *));
317         memset(target->arBuckets, 0, target->nTableSize * sizeof(Bucket *));
318         target->pDestructor = NULL;
319         target->persistent = 0;
320         target->pListHead = NULL;
321         target->pListTail = NULL;
322 #if HARDENING_PATCH_HASH_PROTECT
323     target->canary = zend_hash_canary;
324 #endif
325
326         p = source->pListHead;
327         prev_p = NULL;
328         np = NULL;
329         while (p) {
330                 np = (Bucket *) emalloc(offsetof(Bucket, arKey) + p->nKeyLength);
331                 /*    np = (Bucket *) emalloc(sizeof(Bucket) + p->nKeyLength); */
332                 nIndex = p->h % source->nTableSize;
333                 if (target->arBuckets[nIndex]) {
334                         np->pNext = target->arBuckets[nIndex];
335                         np->pLast = NULL;
336                         np->pNext->pLast = np;
337                 } else {
338                         np->pNext = NULL;
339                         np->pLast = NULL;
340                 }
341                 target->arBuckets[nIndex] = np;
342                 np->h = p->h;
343                 np->nKeyLength = p->nKeyLength;
344
345                 if (p->pDataPtr == NULL) {
346                         np->pData = copy_bucket(p->pData TSRMLS_CC);
347                         np->pDataPtr = NULL;
348                 } else {
349                         np->pDataPtr = copy_bucket(p->pDataPtr TSRMLS_CC);
350                         np->pData = &np->pDataPtr;
351                 }
352                 np->pListLast = prev_p;
353                 np->pListNext = NULL;
354
355                 memcpy(np->arKey, p->arKey, p->nKeyLength);
356
357                 if (prev_p) {
358                         prev_p->pListNext = np;
359                 } else {
360                         target->pListHead = np;
361                 }
362                 prev_p = np;
363                 p = p->pListNext;
364         }
365         target->pListTail = np;
366         target->pInternalPointer = target->pListHead;
367         return target;
368 }
369
370 void restore_zval(zval * zv TSRMLS_DC)
371 {
372         switch (zv->type & ~IS_CONSTANT_INDEX) {
373         case IS_CONSTANT:
374         case IS_STRING:
375                 if (Z_STRVAL_P(zv) == NULL || Z_STRVAL_P(zv) == "" || Z_STRLEN_P(zv) == 0) {
376                         Z_STRLEN_P(zv) = 0;
377                         Z_STRVAL_P(zv) = empty_string;
378                         return;
379                 } else {
380                         char *p = emalloc(Z_STRLEN_P(zv) + 1);
381                         memcpy(p, Z_STRVAL_P(zv), Z_STRLEN_P(zv) + 1);
382                         Z_STRVAL_P(zv) = p;
383                 }
384                 return;
385
386         case IS_ARRAY:
387         case IS_CONSTANT_ARRAY:
388                 if (Z_ARRVAL_P(zv) != NULL && Z_ARRVAL_P(zv) != &EG(symbol_table)) {
389                         Z_ARRVAL_P(zv) = restore_zval_hash(NULL, Z_ARRVAL_P(zv));
390                         Z_ARRVAL_P(zv)->pDestructor = ZVAL_PTR_DTOR;
391                 }
392                 return;
393
394         case IS_OBJECT:
395     {
396 #ifndef ZEND_ENGINE_2
397         zend_bool incomplete_class = 0;
398         char *class_name = (char *) Z_OBJCE_P(zv);
399         int name_len = 0;
400         if (!EAG(compress)) {
401             return;
402         }
403         if (class_name != NULL) {
404             zend_class_entry *ce = NULL;
405             name_len = strlen(class_name);
406             if (zend_hash_find(CG(class_table), (void *) class_name, name_len + 1, (void **) &ce) != SUCCESS) {
407                 char *lowercase_name = estrndup(INCOMPLETE_CLASS, sizeof(INCOMPLETE_CLASS));
408                 zend_str_tolower(lowercase_name, sizeof(INCOMPLETE_CLASS));
409                 if (zend_hash_find(CG(class_table), lowercase_name, sizeof(INCOMPLETE_CLASS), (void **) &ce) != SUCCESS) {
410                     efree(lowercase_name);
411                     zend_error(E_ERROR, "EACCELERATOR can't restore object's class \"%s\"", class_name);
412                 } else {
413                     efree(lowercase_name);
414                     Z_OBJCE_P(zv) = ce;
415                     incomplete_class = 1;
416                 }
417             } else {
418                 Z_OBJCE_P(zv) = ce;
419             }
420         }
421         if (Z_OBJPROP_P(zv) != NULL) {
422             Z_OBJPROP_P(zv) = restore_zval_hash(NULL, Z_OBJPROP_P(zv));
423             Z_OBJPROP_P(zv)->pDestructor = ZVAL_PTR_DTOR;
424             /* Clearing references */
425             {
426                 Bucket *p = Z_OBJPROP_P(zv)->pListHead;
427                 while (p != NULL) {
428                     ((zval *) (p->pDataPtr))->refcount = 1;
429                     p = p->pListNext;
430                 }
431             }
432         }
433         if (incomplete_class && class_name != NULL) {
434             zval *val;
435             MAKE_STD_ZVAL(val);
436             Z_TYPE_P(val) = IS_STRING;
437             Z_STRVAL_P(val) = estrndup(class_name, name_len);
438             Z_STRLEN_P(val) = name_len;
439             zend_hash_update(Z_OBJPROP_P(zv), MAGIC_MEMBER, sizeof(MAGIC_MEMBER), &val, sizeof(val), NULL);
440         }
441 #endif
442         return;
443     }
444         }
445 }
446
447 static void call_op_array_ctor_handler(zend_extension * extension,
448                                                                            zend_op_array * op_array TSRMLS_DC)
449 {
450         if (extension->op_array_ctor) {
451                 extension->op_array_ctor(op_array);
452         }
453 }
454
455 zend_op_array *restore_op_array(zend_op_array * to,
456                                                                 eaccelerator_op_array * from TSRMLS_DC)
457 {
458     union {
459         zend_function *v;
460         void *ptr;
461     } function;
462 #ifdef ZEND_ENGINE_2
463         int fname_len = 0;
464         char *fname_lc = NULL;
465 #endif
466
467         DBG(ea_debug_pad, (EA_DEBUG TSRMLS_CC));
468         DBG(ea_debug_printf, (EA_DEBUG, "[%d] restore_op_array: %s type=%x\n", getpid(),
469                                         from->function_name ? from->function_name : "(top)", from->type));
470
471         if (from->type == ZEND_INTERNAL_FUNCTION) {
472                 if (to == NULL) {
473                         to = emalloc(sizeof(zend_internal_function));
474                 }
475                 memset(to, 0, sizeof(zend_internal_function));
476         } else {
477                 if (to == NULL) {
478                         to = emalloc(sizeof(zend_op_array));
479                 }
480                 memset(to, 0, sizeof(zend_op_array));
481                 if (ZendOptimizer) {
482                         zend_llist_apply_with_argument(&zend_extensions,
483                     (llist_apply_with_arg_func_t) call_op_array_ctor_handler, to TSRMLS_CC);
484                 }
485         }
486         to->type = from->type;
487 #ifdef ZEND_ENGINE_2
488         to->num_args = from->num_args;
489         to->required_num_args = from->required_num_args;
490         to->arg_info = from->arg_info;
491         to->pass_rest_by_reference = from->pass_rest_by_reference;
492 #else
493         to->arg_types = from->arg_types;
494 #endif
495         to->function_name = from->function_name;
496
497 #ifdef ZEND_ENGINE_2
498         if (to->function_name) {
499                 fname_len = strlen(to->function_name);
500                 fname_lc = zend_str_tolower_dup(to->function_name, fname_len);
501         }
502
503         to->fn_flags = from->fn_flags;
504
505         /* segv74:
506          * to->scope = EAG(class_entry)
507          *
508          * if  from->scope_name == NULL,
509          *     ; EAG(class) == NULL  : we are in function or outside function.
510          *     ; EAG(class) != NULL  : inherited method not defined in current file, should have to find.
511          *                              just LINK (zend_op_array *) to to original entry in parent,
512          *                              but, with what? !!! I don't know PARENT CLASS NAME !!!!
513          *
514          *
515          * if  from->scope_name != NULL,
516          *     ; we are in class member function
517          *
518          *     ; we have to find appropriate (zend_class_entry*) to->scope for name from->scope_name
519          *     ; if we find in CG(class_table), link to it.
520          *     ; if fail, it should be EAG(class_entry)
521          *   
522          * am I right here ? ;-(
523          */
524         if (from->scope_name != NULL) {
525         union {
526             zend_class_entry *v;
527             void *ptr;
528         } scope;
529                 char *from_scope_lc = zend_str_tolower_dup(from->scope_name, from->scope_name_len);
530         scope.v = to->scope;
531                 if (zend_hash_find (CG(class_table), (void *) from_scope_lc, from->scope_name_len + 1, &scope.ptr) != SUCCESS) {
532                         DBG(ea_debug_pad, (EA_DEBUG TSRMLS_CC));
533                         DBG(ea_debug_printf, (EA_DEBUG, "[%d]                   can't find '%s' in class_table. use EAG(class_entry).\n", getpid(), from->scope_name));
534                         to->scope = EAG(class_entry);
535                 } else {
536                         DBG(ea_debug_pad, (EA_DEBUG TSRMLS_CC));
537                         DBG(ea_debug_printf, (EA_DEBUG, "[%d]                   found '%s' in hash\n", getpid(), from->scope_name));
538                         to->scope = *(zend_class_entry **) to->scope;
539                 }
540                 efree(from_scope_lc);
541         } else {                                        // zoeloelip: is this needed? scope is always stored -> hra: no its not :P only if from->scope!=null in ea_store
542                 DBG(ea_debug_pad, (EA_DEBUG TSRMLS_CC));
543                 DBG(ea_debug_printf, (EA_DEBUG, "[%d]                   from is NULL\n", getpid()));
544                 if (EAG(class_entry)) {
545                         zend_class_entry *p;
546                         for (p = EAG(class_entry)->parent; p; p = p->parent) {
547                                 DBG(ea_debug_pad, (EA_DEBUG TSRMLS_CC));
548                                 DBG(ea_debug_printf, (EA_DEBUG, "[%d]                   checking parent '%s' have '%s'\n", getpid(), p->name, fname_lc));
549                                 if (zend_hash_find(&p->function_table, fname_lc, fname_len + 1, &function.ptr) == SUCCESS) {
550                                         DBG(ea_debug_pad, (EA_DEBUG TSRMLS_CC));
551                                         DBG(ea_debug_printf, (EA_DEBUG, "[%d]                                   '%s' has '%s' of scope '%s'\n",
552                             getpid(), p->name, fname_lc, function.v->common.scope->name));
553                                         to->scope = function.v->common.scope;
554                                         break;
555                                 }
556                         }
557                 } else {
558                         to->scope = NULL;
559                 }
560         }
561
562         DBG(ea_debug_pad, (EA_DEBUG TSRMLS_CC));
563         DBG(ea_debug_printf, (EA_DEBUG, "[%d]                   %s's scope is '%s'\n", getpid(),
564             from->function_name ? from->function_name : "(top)", to->scope ? to->scope->name : "NULL"));
565 #endif
566         if (from->type == ZEND_INTERNAL_FUNCTION) {
567                 zend_class_entry *class_entry = EAG(class_entry);
568                 DBG(ea_debug_pad, (EA_DEBUG TSRMLS_CC));
569                 DBG(ea_debug_printf, (EA_DEBUG, "[%d]                   [internal function from=%08x,to=%08x] class_entry='%s' [%08x]\n",
570                 getpid(), from, to, class_entry->name, class_entry));
571                 if (class_entry) {
572                         DBG(ea_debug_pad, (EA_DEBUG TSRMLS_CC));
573                         DBG(ea_debug_printf, (EA_DEBUG, "[%d]                                       class_entry->parent='%s' [%08x]\n",
574                     getpid(), class_entry->parent->name, class_entry->parent));
575                 }
576                 if (class_entry != NULL && class_entry->parent != NULL &&
577                 zend_hash_find(&class_entry->parent->function_table,
578 #ifdef ZEND_ENGINE_2
579                 fname_lc, fname_len + 1,
580 #else
581                 to->function_name, strlen(to->function_name) + 1,
582 #endif
583                                 &function.ptr) == SUCCESS && function.v->type == ZEND_INTERNAL_FUNCTION) {
584                         DBG(ea_debug_pad, (EA_DEBUG TSRMLS_CC));
585                         DBG(ea_debug_printf, (EA_DEBUG, "[%d]                                       found in function table\n", getpid()));
586                         ((zend_internal_function *) (to))->handler = ((zend_internal_function *) function.v)->handler;
587                 } else {
588                         /* FIXME. I don't know how to fix handler.
589                          * TODO: must solve this somehow, to avoid returning damaged structure...
590                          */
591                         DBG(ea_debug_pad, (EA_DEBUG TSRMLS_CC));
592                         DBG(ea_debug_printf, (EA_DEBUG, "[%d]                                       can't find\n", getpid()));
593                 }               
594 #ifdef ZEND_ENGINE_2
595                 /* hrak: slight memleak here. dont forget to free the lowercase function name! */
596                 if (fname_lc != NULL) {
597                         efree(fname_lc);
598                 }
599                 /* zend_internal_function also contains return_reference in ZE2 */
600                 to->return_reference = from->return_reference;
601                 /* this gets set by zend_do_inheritance */
602                 to->prototype = NULL;
603 #endif
604                 return to;
605         }
606 #ifdef ZEND_ENGINE_2
607         /* hrak: slight memleak here. dont forget to free the lowercase function name! */
608         if (fname_lc != NULL) {
609                 efree(fname_lc);
610         }
611 #endif
612         to->opcodes = from->opcodes;
613         to->last = to->size = from->last;
614         to->T = from->T;
615         to->brk_cont_array = from->brk_cont_array;
616         to->last_brk_cont = from->last_brk_cont;
617        
618            to->current_brk_cont = -1;
619            to->static_variables = from->static_variables;
620 /*         to->start_op         = to->opcodes; */
621            to->backpatch_count  = 0;
622        
623         to->return_reference = from->return_reference;
624         to->done_pass_two = 1;
625         to->filename = from->filename;
626 /*      if (from->filename != NULL) {
627                 size_t len = strlen(from->filename) + 1;
628                 to->filename = emalloc(len);
629                 memcpy(to->filename, from->filename, len);
630         }*/
631
632 #ifdef ZEND_ENGINE_2
633         /* HOESH: try & catch support */
634         to->try_catch_array = from->try_catch_array;
635         to->last_try_catch = from->last_try_catch;
636         to->uses_this = from->uses_this;
637
638         to->line_start = from->line_start;
639         to->line_end = from->line_end;
640         to->doc_comment_len = 0;
641         to->doc_comment = NULL;
642 #else
643         to->uses_globals = from->uses_globals;
644 #endif
645         if (from->static_variables) {
646                 to->static_variables = restore_zval_hash(NULL, from->static_variables);
647                 to->static_variables->pDestructor = ZVAL_PTR_DTOR;
648 #ifndef ZEND_ENGINE_2
649                 if (EAG(class_entry) != NULL) {
650                         Bucket *p = to->static_variables->pListHead;
651                         while (p != NULL) {
652                                 ((zval *) (p->pDataPtr))->refcount = 1;
653                                 p = p->pListNext;
654                         }
655                 }
656 #endif
657         }
658
659 #ifdef ZEND_ENGINE_2_1
660         to->vars             = from->vars;
661         to->last_var         = from->last_var;
662         to->size_var         = 0;
663 /*      if (from->vars) {
664                 zend_uint i;
665                 to->vars = (zend_compiled_variable*)emalloc(from->last_var*sizeof(zend_compiled_variable));             
666                 memcpy(to->vars, from->vars, sizeof(zend_compiled_variable) * from->last_var);
667                 for (i = 0; i < from->last_var; i ++) {
668                         to->vars[i].name = estrndup(from->vars[i].name, from->vars[i].name_len);
669                 }
670         }*/
671 #endif
672
673         /* disable deletion in destroy_op_array */
674         ++EAG(refcount_helper);
675         to->refcount = &EAG(refcount_helper);
676
677         return to;
678 }
679
680 static zend_op_array *restore_op_array_ptr(eaccelerator_op_array *
681                                                                                    from TSRMLS_DC)
682 {
683         return restore_op_array(NULL, from TSRMLS_CC);
684 }
685
686 #ifdef ZEND_ENGINE_2
687 static zend_property_info *restore_property_info(zend_property_info *
688                                                                                                  from TSRMLS_DC)
689 {
690         zend_property_info *to = emalloc(sizeof(zend_property_info));
691         memcpy(to, from, sizeof(zend_property_info));
692         to->name = emalloc(from->name_length + 1);
693         memcpy(to->name, from->name, from->name_length + 1);
694 #ifdef ZEND_ENGINE_2_1
695     to->doc_comment_len = 0;
696     to->doc_comment = NULL;
697 #endif
698         return to;
699 }
700 #endif
701
702 /* restore the parent class with the given name for the given class */
703 void restore_class_parent(char *parent, int len,
704                                                   zend_class_entry * to TSRMLS_DC)
705 {
706 #ifdef ZEND_ENGINE_2
707         zend_class_entry** parent_ptr = NULL;
708         if (zend_lookup_class(parent, len, &parent_ptr TSRMLS_CC) != SUCCESS)
709 #else
710         char *name_lc = estrndup(parent, len);
711         zend_str_tolower(name_lc, len);
712         if (zend_hash_find(CG(class_table), (void *) name_lc, len + 1, (void **) &to->parent) != SUCCESS)
713 #endif
714         {
715                 DBG(ea_debug_error, ("[%d] EACCELERATOR can't restore parent class \"%s\" of class \"%s\"\n",
716                 getpid(), (char *) parent, to->name));
717                 to->parent = NULL;
718         } else {
719                 /* parent found */
720 #ifdef ZEND_ENGINE_2
721                 to->parent = *parent_ptr;
722 #endif
723                 DBG(ea_debug_printf, (EA_DEBUG, "restore_class_parent: found parent %s..\n", to->parent->name));
724                 DBG(ea_debug_printf, (EA_DEBUG, "restore_class_parent: parent type=%d child type=%d\n", to->parent->type, to->type));
725         }
726 #ifndef ZEND_ENGINE_2
727         efree(name_lc);
728 #endif
729 }
730
731 #ifdef ZEND_ENGINE_2
732 void restore_class_methods(zend_class_entry * to TSRMLS_DC)
733 {
734         int cname_len = to->name_length;
735         char *cname_lc = zend_str_tolower_dup(to->name, cname_len);
736         int fname_len = 0;
737         char *fname_lc = NULL;
738         zend_function *f = NULL;
739         Bucket *p = to->function_table.pListHead;
740
741         while (p != NULL) {
742                 f = p->pData;
743                 fname_len = strlen(f->common.function_name);
744                 fname_lc = zend_str_tolower_dup(f->common.function_name, fname_len);
745                
746                 if (fname_len == cname_len && !memcmp(fname_lc, cname_lc, fname_len) && f->common.scope != to->parent) {
747                         to->constructor = f;
748                 } else if (fname_lc[0] == '_' && fname_lc[1] == '_' && f->common.scope != to->parent) {
749                         if (fname_len == sizeof(ZEND_CONSTRUCTOR_FUNC_NAME) - 1 &&
750                     memcmp(fname_lc, ZEND_CONSTRUCTOR_FUNC_NAME, sizeof(ZEND_CONSTRUCTOR_FUNC_NAME)) == 0)
751                                 to->constructor = f;
752                         else if (fname_len == sizeof(ZEND_DESTRUCTOR_FUNC_NAME) - 1 &&
753                                          memcmp(fname_lc, ZEND_DESTRUCTOR_FUNC_NAME, sizeof(ZEND_DESTRUCTOR_FUNC_NAME)) == 0)
754                                 to->destructor = f;
755                         else if (fname_len == sizeof(ZEND_CLONE_FUNC_NAME) - 1 &&
756                                          memcmp(fname_lc, ZEND_CLONE_FUNC_NAME, sizeof(ZEND_CLONE_FUNC_NAME)) == 0)
757                                 to->clone = f;
758                         else if (fname_len == sizeof(ZEND_GET_FUNC_NAME) - 1 &&
759                                          memcmp(fname_lc, ZEND_GET_FUNC_NAME, sizeof(ZEND_GET_FUNC_NAME)) == 0)
760                                 to->__get = f;
761                         else if (fname_len == sizeof(ZEND_SET_FUNC_NAME) - 1 &&
762                                          memcmp(fname_lc, ZEND_SET_FUNC_NAME, sizeof(ZEND_SET_FUNC_NAME)) == 0)
763                                 to->__set = f;
764 #  ifdef ZEND_ENGINE_2_1
765                         else if (fname_len == sizeof(ZEND_UNSET_FUNC_NAME) - 1 &&
766                                         memcmp(fname_lc, ZEND_UNSET_FUNC_NAME, sizeof(ZEND_UNSET_FUNC_NAME)) == 0)
767                                 to->__unset = f;
768                         else if (fname_len == sizeof(ZEND_ISSET_FUNC_NAME) - 1 &&
769                                         memcmp(fname_lc, ZEND_ISSET_FUNC_NAME, sizeof(ZEND_ISSET_FUNC_NAME)) == 0)
770                                 to->__isset = f;
771 #  endif
772                         else if (fname_len == sizeof(ZEND_CALL_FUNC_NAME) - 1 &&
773                                          memcmp(fname_lc, ZEND_CALL_FUNC_NAME, sizeof(ZEND_CALL_FUNC_NAME)) == 0)
774                                 to->__call = f;
775                 }
776                 if (to->parent) {
777                         /* clear the child's prototype and IMPLEMENTED_ABSTRACT flag,
778                            these are properly restored by zend_do_inheritance() (see do_inherit_method_check) */
779                         f->common.prototype = NULL;
780                         f->common.fn_flags = f->common.fn_flags & (~ZEND_ACC_IMPLEMENTED_ABSTRACT);
781                 }
782                 efree(fname_lc);
783                 p = p->pListNext;
784         }
785         efree(cname_lc);
786 }
787 #endif
788
789 zend_class_entry *restore_class_entry(zend_class_entry * to,
790                                                                           eaccelerator_class_entry * from TSRMLS_DC)
791 {
792         zend_class_entry *old;
793
794         DBG(ea_debug_pad, (EA_DEBUG TSRMLS_CC));
795         DBG(ea_debug_printf, (EA_DEBUG, "[%d] restore_class_entry: %s\n", getpid(), from->name ? from->name : "(top)"));
796 #ifdef DEBUG
797         EAG(xpad)++;
798 #endif
799         if (to == NULL) {
800                 to = emalloc(sizeof(zend_class_entry));
801         }
802         memset(to, 0, sizeof(zend_class_entry));
803         to->type = from->type;
804         /*
805            to->name        = NULL;
806            to->name_length = from->name_length;
807            to->constants_updated = 0;
808            to->parent      = NULL;
809          */
810 #ifdef ZEND_ENGINE_2
811         to->ce_flags = from->ce_flags;
812         to->num_interfaces = from->num_interfaces;
813         to->interfaces = NULL;
814
815         if (to->num_interfaces > 0) {
816                 /* hrak: Allocate the slots which will later be populated by ZEND_ADD_INTERFACE */
817                 to->interfaces = (zend_class_entry **) emalloc(sizeof(zend_class_entry *) * to->num_interfaces);
818                 memset(to->interfaces, 0, sizeof(zend_class_entry *) * to->num_interfaces);
819         }
820 #endif
821
822         if (from->name != NULL) {
823                 to->name_length = from->name_length;
824                 to->name = emalloc(from->name_length + 1);
825                 memcpy(to->name, from->name, from->name_length + 1);
826         }
827
828         old = EAG(class_entry);
829         EAG(class_entry) = to;
830
831 #ifdef ZEND_ENGINE_2
832         to->refcount = 1;
833
834         to->line_start = from->line_start;
835         to->line_end = from->line_end;
836         to->doc_comment_len = 0;
837     to->doc_comment = NULL;
838 /*      if (from->filename != NULL) {
839                 size_t len = strlen(from->filename) + 1;
840                 to->filename = emalloc(len);
841                 memcpy(to->filename, from->filename, len);
842         }*/
843         to->filename = from->filename;
844
845         /* restore constants table */
846         restore_zval_hash(&to->constants_table, &from->constants_table);
847         to->constants_table.pDestructor = ZVAL_PTR_DTOR;
848         /* restore default properties */
849         restore_zval_hash(&to->default_properties, &from->default_properties);
850         to->default_properties.pDestructor = ZVAL_PTR_DTOR;
851         /* restore properties */
852         restore_hash(&to->properties_info, &from->properties_info,
853             (restore_bucket_t) restore_property_info TSRMLS_CC);
854         to->properties_info.pDestructor = properties_info_dtor;
855
856 #  ifdef ZEND_ENGINE_2_1
857         /* restore default_static_members */
858         restore_zval_hash(&to->default_static_members, &from->default_static_members);
859         to->default_static_members.pDestructor = ZVAL_PTR_DTOR;
860        
861         if (from->static_members != &(from->default_static_members)) {
862                 ALLOC_HASHTABLE(to->static_members);
863                 restore_zval_hash(to->static_members, from->static_members);
864                 to->static_members->pDestructor = ZVAL_PTR_DTOR;
865         } else {
866                 to->static_members = &(to->default_static_members);
867         }
868 #  else
869         if (from->static_members != NULL) {
870                 ALLOC_HASHTABLE(to->static_members);
871                 restore_zval_hash(to->static_members, from->static_members);
872                 to->static_members->pDestructor = ZVAL_PTR_DTOR;
873         }
874 #  endif
875 #else
876         to->refcount = emalloc(sizeof(*to->refcount));
877         *to->refcount = 1;
878
879         restore_zval_hash(&to->default_properties, &from->default_properties);
880         to->default_properties.pDestructor = ZVAL_PTR_DTOR;
881         /* Clearing references */
882         {
883                 Bucket *p = to->default_properties.pListHead;
884                 while (p != NULL) {
885                         ((zval *) (p->pDataPtr))->refcount = 1;
886                         p = p->pListNext;
887                 }
888         }
889 #endif
890         if (from->parent != NULL) {
891                 restore_class_parent(from->parent, strlen(from->parent), to TSRMLS_CC);
892         } else {
893                 DBG(ea_debug_pad, (EA_DEBUG TSRMLS_CC));
894                 DBG(ea_debug_printf, (EA_DEBUG, "[%d] parent = NULL\n", getpid()));
895                 to->parent = NULL;
896         }
897
898         restore_hash(&to->function_table, &from->function_table,
899                                  (restore_bucket_t) restore_op_array_ptr TSRMLS_CC);
900         to->function_table.pDestructor = ZEND_FUNCTION_DTOR;
901
902 #ifdef ZEND_ENGINE_2
903         restore_class_methods(to TSRMLS_CC);
904 #endif
905         if (to->parent)
906                 zend_do_inheritance(to, to->parent TSRMLS_CC);
907         EAG(class_entry) = old;
908
909 #ifdef DEBUG
910         EAG(xpad)--;
911 #endif
912
913         return to;
914 }
915
916 void restore_function(mm_fc_entry * p TSRMLS_DC)
917 {
918         zend_op_array op_array;
919
920         if ((p->htabkey[0] == '\000') && zend_hash_exists(CG(function_table), p->htabkey, p->htablen)) {
921                 return;
922         }
923         if (restore_op_array(&op_array, (eaccelerator_op_array *) p->fc TSRMLS_CC) != NULL) {
924                 if (zend_hash_add(CG(function_table), p->htabkey, p->htablen, &op_array, sizeof(zend_op_array), NULL) == FAILURE) {
925                         CG(in_compilation) = 1;
926                         CG(compiled_filename) = EAG(mem);
927 #ifdef ZEND_ENGINE_2
928                         CG(zend_lineno) = op_array.line_start;
929 #else
930                         CG(zend_lineno) = op_array.opcodes[0].lineno;
931 #endif
932                         zend_error(E_ERROR, "Cannot redeclare %s()", p->htabkey);
933                 }
934         }
935 }
936
937 /*
938  * Class handling.
939  */
940 void restore_class(mm_fc_entry * p TSRMLS_DC)
941 {
942 #ifdef ZEND_ENGINE_2
943         zend_class_entry *ce;
944 #else