root/eaccelerator/tags/0.9.5/ea_store.c

Revision 270, 30.5 kB (checked in by bart, 2 years ago)

Add php 5.2 support. These are minimal changes so they shouldn't affect stability.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
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$
26 */
27
28 #include "eaccelerator.h"
29
30 #ifdef HAVE_EACCELERATOR
31
32 #include "ea_store.h"
33 #include "debug.h"
34
35 /******************************************************************************/
36 /* Functions to calculate the size of different structure that a compiled php */
37 /* script contains.                                                           */
38 /******************************************************************************/
39
40 #ifndef DEBUG
41 inline
42 #endif
43 static void calc_string(char *str, int len TSRMLS_DC)
44 {
45         if (len > MAX_DUP_STR_LEN || zend_hash_add(&EAG(strings), str, len,
46                                                                                            &str, sizeof(char *),
47                                                                                            NULL) == SUCCESS) {
48                 EACCELERATOR_ALIGN(EAG(mem));
49                 EAG(mem) += len;
50         }
51 }
52
53 typedef void (*calc_bucket_t) (void *TSRMLS_DC);
54
55 #define calc_hash_ex(from, start, calc_bucket) \
56   calc_hash_int(from, start, calc_bucket TSRMLS_CC)
57
58 #define calc_hash(from, calc_bucket) \
59   calc_hash_ex(from, (from)->pListHead, calc_bucket)
60
61 #define calc_zval_hash(from) \
62   calc_hash(from, (calc_bucket_t)calc_zval_ptr)
63
64 #define calc_zval_hash_ex(from, start) \
65   calc_hash_ex(from, start, (calc_bucket_t)calc_zval_ptr)
66
67
68 static void calc_zval_ptr(zval ** from TSRMLS_DC)
69 {
70         EACCELERATOR_ALIGN(EAG(mem));
71         EAG(mem) += sizeof(zval);
72         calc_zval(*from TSRMLS_CC);
73 }
74
75 #ifdef ZEND_ENGINE_2
76 static void calc_property_info(zend_property_info * from TSRMLS_DC)
77 {
78         EACCELERATOR_ALIGN(EAG(mem));
79         EAG(mem) += sizeof(zend_property_info);
80         calc_string(from->name, from->name_length + 1 TSRMLS_CC);
81 #ifdef INCLUDE_DOC_COMMENTS
82 #ifdef ZEND_ENGINE_2_1
83      if (from->doc_comment != NULL) {
84         calc_string(from->doc_comment, from->doc_comment_len + 1 TSRMLS_CC);
85      }
86 #endif
87 #endif
88 }
89
90
91 /* Calculate the size of a point to a class entry */
92 /* not used
93 static void calc_class_entry_ptr(zend_class_entry ** from TSRMLS_DC)
94 {
95         calc_class_entry(*from TSRMLS_CC);
96 }
97 */
98 #endif
99
100 /* Calculate the size of an HashTable */
101 static void calc_hash_int(HashTable * source, Bucket * start,
102                                                   calc_bucket_t calc_bucket TSRMLS_DC)
103 {
104         Bucket *p;
105
106         if (source->nNumOfElements > 0) {
107                 if (!EAG(compress)) {
108                         EACCELERATOR_ALIGN(EAG(mem));
109                         EAG(mem) += source->nTableSize * sizeof(Bucket *);
110                 }
111                 p = start;
112                 while (p) {
113                         EACCELERATOR_ALIGN(EAG(mem));
114                         EAG(mem) += offsetof(Bucket, arKey) + p->nKeyLength;
115                         calc_bucket(p->pData TSRMLS_CC);
116                         p = p->pListNext;
117                 }
118         }
119 }
120
121 void calc_zval(zval * zv TSRMLS_DC)
122 {
123         switch (Z_TYPE_P(zv) & ~IS_CONSTANT_INDEX) {
124         case IS_CONSTANT:
125         case IS_STRING:
126                 calc_string(Z_STRVAL_P(zv), Z_STRLEN_P(zv) + 1 TSRMLS_CC);
127                 break;
128         case IS_ARRAY:
129         case IS_CONSTANT_ARRAY:
130                 if (Z_ARRVAL_P(zv) != NULL && Z_ARRVAL_P(zv) != &EG(symbol_table)) {
131                         EACCELERATOR_ALIGN(EAG(mem));
132                         EAG(mem) += sizeof(HashTable);
133                         calc_zval_hash(Z_ARRVAL_P(zv));
134                 }
135                 break;
136         case IS_OBJECT:
137 #ifndef ZEND_ENGINE_2
138                 if (Z_OBJCE_P(zv) != NULL) {
139                         zend_class_entry *ce = Z_OBJCE_P(zv);
140                         if (!EAG(compress)) {
141                                 DBG(ea_debug_error, ("[%d] EACCELERATOR can't cache objects\n", getpid()));
142                                 zend_bailout();
143                         }
144                         while (ce != NULL) {
145                                 if (ce->type != ZEND_USER_CLASS && strcmp(ce->name, "stdClass") != 0) {
146                                         DBG(ea_debug_error, ("[%d] EACCELERATOR can't cache objects\n", getpid()));
147                                         zend_bailout();
148                                 }
149                                 ce = ce->parent;
150                         }
151                         calc_string(Z_OBJCE_P(zv)->name, Z_OBJCE_P(zv)->name_length + 1 TSRMLS_CC);
152                 }
153                 if (Z_OBJPROP_P(zv) != NULL) {
154                         EACCELERATOR_ALIGN(EAG(mem));
155                         EAG(mem) += sizeof(HashTable);
156                         calc_zval_hash(Z_OBJPROP_P(zv));
157                 }
158 #endif
159                 return;
160         case IS_RESOURCE:
161                 DBG(ea_debug_error, ("[%d] EACCELERATOR can't cache resources\n", getpid()));
162                 zend_bailout();
163         default:
164                 break;
165         }
166 }
167
168 /* Calculate the size of an op_array */
169 void calc_op_array(zend_op_array * from TSRMLS_DC)
170 {
171         zend_op *opline;
172         zend_op *end;
173
174         if (from->type == ZEND_INTERNAL_FUNCTION) {
175                 EACCELERATOR_ALIGN(EAG(mem));
176                 EAG(mem) += sizeof(zend_internal_function);
177         } else if (from->type == ZEND_USER_FUNCTION) {
178                 EACCELERATOR_ALIGN(EAG(mem));
179                 EAG(mem) += sizeof(eaccelerator_op_array);
180         } else {
181                 DBG(ea_debug_error, ("[%d] EACCELERATOR can't cache function \"%s\"\n", getpid(), from->function_name));
182                 zend_bailout();
183         }
184 #ifdef ZEND_ENGINE_2
185         if (from->num_args > 0) {
186                 zend_uint i;
187                 EACCELERATOR_ALIGN(EAG(mem));
188                 EAG(mem) += from->num_args * sizeof(zend_arg_info);
189                 for (i = 0; i < from->num_args; i++) {
190                         if (from->arg_info[i].name)
191                                 calc_string(from->arg_info[i].name, from->arg_info[i].name_len + 1 TSRMLS_CC);
192                         if (from->arg_info[i].class_name)
193                                 calc_string(from->arg_info[i].class_name, from->arg_info[i].class_name_len + 1 TSRMLS_CC);
194                 }
195         }
196 #else
197         if (from->arg_types != NULL)
198                 calc_string((char *) from->arg_types, (from->arg_types[0] + 1) * sizeof(zend_uchar) TSRMLS_CC);
199 #endif
200         if (from->function_name != NULL)
201                 calc_string(from->function_name, strlen(from->function_name) + 1 TSRMLS_CC);
202 #ifdef ZEND_ENGINE_2
203         if (from->scope != NULL) {
204                 // HOESH: the same problem?
205                 Bucket *q = CG(class_table)->pListHead;
206                 while (q != NULL) {
207                         if (*(zend_class_entry **) q->pData == from->scope) {
208                                 calc_string(q->arKey, q->nKeyLength TSRMLS_CC);
209                                 break;
210                         }
211                         q = q->pListNext;
212                 }
213         }
214 #endif
215         if (from->type == ZEND_INTERNAL_FUNCTION)
216                 return;
217
218         if (from->opcodes != NULL) {
219                 EACCELERATOR_ALIGN(EAG(mem));
220                 EAG(mem) += from->last * sizeof(zend_op);
221
222                 opline = from->opcodes;
223                 end = opline + from->last;
224                 EAG(compress) = 0;
225                 for (; opline < end; opline++) {
226 /*
227       if (opline->result.op_type == IS_CONST) calc_zval(&opline->result.u.constant  TSRMLS_CC);
228 */
229                         if (opline->op1.op_type == IS_CONST)
230                                 calc_zval(&opline->op1.u.constant TSRMLS_CC);
231                         if (opline->op2.op_type == IS_CONST)
232                                 calc_zval(&opline->op2.u.constant TSRMLS_CC);
233                 }
234                 EAG(compress) = 1;
235         }
236         if (from->brk_cont_array != NULL) {
237                 EACCELERATOR_ALIGN(EAG(mem));
238                 EAG(mem) += sizeof(zend_brk_cont_element) * from->last_brk_cont;
239         }
240 #ifdef ZEND_ENGINE_2
241         /* HOESH: try & catch support */
242         if (from->try_catch_array != NULL) {
243                 EACCELERATOR_ALIGN(EAG(mem));
244                 EAG(mem) += sizeof(zend_try_catch_element) * from->last_try_catch;
245         }
246 #endif
247         if (from->static_variables != NULL) {
248                 EACCELERATOR_ALIGN(EAG(mem));
249                 EAG(mem) += sizeof(HashTable);
250                 calc_zval_hash(from->static_variables);
251         }
252 #ifdef ZEND_ENGINE_2_1
253         if (from->vars != NULL) {
254                 int i;
255                 EACCELERATOR_ALIGN(EAG(mem));
256                 EAG(mem) += sizeof(zend_compiled_variable) * from->last_var;
257                 for (i = 0; i < from->last_var; i ++) {
258                         calc_string(from->vars[i].name, from->vars[i].name_len+1 TSRMLS_CC);
259                 }
260         }
261 #endif
262         if (from->filename != NULL)
263                 calc_string(from->filename, strlen(from->filename) + 1 TSRMLS_CC);
264 #ifdef INCLUDE_DOC_COMMENTS
265 #ifdef ZEND_ENGINE_2
266     if (from->doc_comment != NULL)
267         calc_string(from->doc_comment, from->doc_comment_len + 1 TSRMLS_CC);
268 #endif
269 #endif
270 }
271
272 /* Calculate the size of a class entry */
273 void calc_class_entry(zend_class_entry * from TSRMLS_DC)
274 {
275         if (from->type != ZEND_USER_CLASS) {
276                 DBG(ea_debug_error, ("[%d] EACCELERATOR can't cache internal class \"%s\"\n", getpid(), from->name));
277                 zend_bailout();
278         }
279         EACCELERATOR_ALIGN(EAG(mem));
280         EAG(mem) += sizeof(eaccelerator_class_entry);
281
282         if (from->name != NULL)
283                 calc_string(from->name, from->name_length + 1 TSRMLS_CC);
284         if (from->parent != NULL && from->parent->name)
285                 calc_string(from->parent->name, from->parent->name_length + 1 TSRMLS_CC);
286 #ifdef ZEND_ENGINE_2
287         if (from->filename != NULL)
288                 calc_string(from->filename, strlen(from->filename) + 1 TSRMLS_CC);
289 #ifdef INCLUDE_DOC_COMMENTS
290      if (from->doc_comment != NULL)
291         calc_string(from->doc_comment, from->doc_comment_len + 1 TSRMLS_CC);
292 #endif
293        
294     calc_zval_hash(&from->constants_table);
295         calc_zval_hash(&from->default_properties);
296
297         calc_hash(&from->properties_info, (calc_bucket_t) calc_property_info);
298
299 #  ifdef ZEND_ENGINE_2_1
300         calc_zval_hash(&from->default_static_members);
301         if ((from->static_members != NULL) && (from->static_members != &from->default_static_members)) {
302 #  else
303         if (from->static_members != NULL) {
304 #  endif
305                 EACCELERATOR_ALIGN(EAG(mem));
306                 EAG(mem) += sizeof(HashTable);
307                 calc_zval_hash(from->static_members);
308         }
309 #else
310         calc_zval_hash(&from->default_properties);
311 #endif
312         calc_hash(&from->function_table, (calc_bucket_t) calc_op_array);
313 }
314
315 /* Calculate the size of a cache entry with its given op_array and function and
316    class bucket */
317 int calc_size(char *key, zend_op_array * op_array,
318                           Bucket * f, Bucket * c TSRMLS_DC)
319 {
320         Bucket *b;
321         char *x;
322         int len = strlen(key);
323         EAG(compress) = 1;
324         EAG(mem) = NULL;
325
326         zend_hash_init(&EAG(strings), 0, NULL, NULL, 0);
327         EAG(mem) += offsetof(mm_cache_entry, realfilename) + len + 1;
328         zend_hash_add(&EAG(strings), key, len + 1, &key, sizeof(char *), NULL);
329         b = c;
330         while (b != NULL) {
331                 EACCELERATOR_ALIGN(EAG(mem));
332                 EAG(mem) += offsetof(mm_fc_entry, htabkey) + b->nKeyLength;
333                 x = b->arKey;
334                 zend_hash_add(&EAG(strings), b->arKey, b->nKeyLength, &x, sizeof(char *), NULL);
335                 b = b->pListNext;
336         }
337         b = f;
338         while (b != NULL) {
339                 EACCELERATOR_ALIGN(EAG(mem));
340                 EAG(mem) += offsetof(mm_fc_entry, htabkey) + b->nKeyLength;
341                 x = b->arKey;
342                 zend_hash_add(&EAG(strings), b->arKey, b->nKeyLength, &x, sizeof(char *), NULL);
343                 b = b->pListNext;
344         }
345         while (c != NULL) {
346 #ifdef ZEND_ENGINE_2
347                 calc_class_entry(*(zend_class_entry **) c->pData TSRMLS_CC);
348 #else
349                 calc_class_entry((zend_class_entry *) c->pData TSRMLS_CC);
350 #endif
351                 c = c->pListNext;
352         }
353         while (f != NULL) {
354                 calc_op_array((zend_op_array *) f->pData TSRMLS_CC);
355                 f = f->pListNext;
356         }
357         calc_op_array(op_array TSRMLS_CC);
358         EACCELERATOR_ALIGN(EAG(mem));
359         zend_hash_destroy(&EAG(strings));
360         return (size_t) EAG(mem);
361 }
362
363 /** Functions to store a script **/
364 static inline char *store_string(char *str, int len TSRMLS_DC)
365 {
366         char *p;
367         if (len > MAX_DUP_STR_LEN) {
368                 EACCELERATOR_ALIGN(EAG(mem));
369                 p = (char *) EAG(mem);
370                 EAG(mem) += len;
371                 memcpy(p, str, len);
372         } else if (zend_hash_find(&EAG(strings), str, len, (void *) &p) == SUCCESS) {
373                 p = *(char **) p;
374         } else {
375                 EACCELERATOR_ALIGN(EAG(mem));
376                 p = (char *) EAG(mem);
377                 EAG(mem) += len;
378                 memcpy(p, str, len);
379                 zend_hash_add(&EAG(strings), str, len, (void *) &p, sizeof(char *), NULL);
380         }
381         return p;
382 }
383
384 typedef void *(*store_bucket_t) (void *TSRMLS_DC);
385 typedef void *(*check_bucket_t) (Bucket*, zend_class_entry*);
386
387 #define store_hash_ex(to, from, start, store_bucket, check_bucket, from_ce) \
388   store_hash_int(to, from, start, store_bucket, check_bucket, from_ce)
389
390 #define store_hash(to, from, store_bucket, check_bucket, from_ce) \
391   store_hash_ex(to, from, (from)->pListHead, store_bucket, check_bucket, from_ce)
392
393 #define store_zval_hash(to, from) \
394   store_hash(to, from, (store_bucket_t)store_zval_ptr, NULL, NULL)
395
396 #define store_zval_hash_ex(to, from, start) \
397   store_hash_ex(to, from, start, (store_bucket_t)store_zval_ptr, NULL)
398
399 static zval *store_zval_ptr(zval * from TSRMLS_DC)
400 {
401         zval *to;
402         EACCELERATOR_ALIGN(EAG(mem));
403         to = (zval *) EAG(mem);
404         EAG(mem) += sizeof(zval);
405         memcpy(to, from, sizeof(zval));
406         store_zval(to TSRMLS_CC);
407         return to;
408 }
409
410 static void store_hash_int(HashTable * target, HashTable * source,
411                                                    Bucket * start, store_bucket_t copy_bucket,
412                                                                    check_bucket_t check_bucket,
413                                                                    zend_class_entry * from_ce)
414 {
415         Bucket *p, *np, *prev_p;
416         TSRMLS_FETCH();
417
418         memcpy(target, source, sizeof(HashTable));
419
420         if (source->nNumOfElements > 0) {
421                 if (!EAG(compress)) {
422                         EACCELERATOR_ALIGN(EAG(mem));
423                         target->arBuckets = (Bucket **) EAG(mem);
424                         EAG(mem) += target->nTableSize * sizeof(Bucket *);
425                         memset(target->arBuckets, 0, target->nTableSize * sizeof(Bucket *));
426                 }
427
428                 target->pDestructor = NULL;
429                 target->persistent = 1;
430                 target->pListHead = NULL;
431                 target->pListTail = NULL;
432
433                 p = start;
434                 prev_p = NULL;
435                 np = NULL;
436                 while (p) {
437                         /* If a check function has been defined, run it */
438                         if (check_bucket) {
439                                 /* If the check function returns ZEND_HASH_APPLY_REMOVE, don't store this record, skip over it */
440                                 if(check_bucket(p, from_ce)) {
441                                         p = p->pListNext;
442                                         target->nNumOfElements--;
443                                         /* skip to next itteration */
444                                         continue;
445                                 }
446                         }
447
448                         EACCELERATOR_ALIGN(EAG(mem));
449                         np = (Bucket *) EAG(mem);
450                         EAG(mem) += offsetof(Bucket, arKey) + p->nKeyLength;
451
452                         if (!EAG(compress)) {
453                                 int nIndex = p->h % source->nTableSize;
454                                 if (target->arBuckets[nIndex]) {
455                                         np->pNext = target->arBuckets[nIndex];
456                                         np->pLast = NULL;
457                                         np->pNext->pLast = np;
458                                 } else {
459                                         np->pNext = NULL;
460                                         np->pLast = NULL;
461                                 }
462                                 target->arBuckets[nIndex] = np;
463                         }
464                         np->h = p->h;
465                         np->nKeyLength = p->nKeyLength;
466
467                         if (p->pDataPtr == NULL) {
468                                 np->pData = copy_bucket(p->pData TSRMLS_CC);
469                                 np->pDataPtr = NULL;
470                         } else {
471                                 np->pDataPtr = copy_bucket(p->pDataPtr TSRMLS_CC);
472                                 np->pData = &np->pDataPtr;
473                         }
474
475                         np->pListLast = prev_p;
476                         np->pListNext = NULL;
477
478                         memcpy(np->arKey, p->arKey, p->nKeyLength);
479
480                         if (prev_p) {
481                                 prev_p->pListNext = np;
482                         } else {
483                                 target->pListHead = np;
484                         }
485                         prev_p = np;
486                         p = p->pListNext;
487                 }
488                 target->pListTail = np;
489                 target->pInternalPointer = target->pListHead;
490         }
491 }
492
493 void store_zval(zval * zv TSRMLS_DC)
494 {
495         switch (Z_TYPE_P(zv) & ~IS_CONSTANT_INDEX) {
496         case IS_CONSTANT:
497         case IS_STRING:
498                 Z_STRVAL_P(zv) = store_string(Z_STRVAL_P(zv), Z_STRLEN_P(zv) + 1 TSRMLS_CC);
499                 break;
500         case IS_ARRAY:
501         case IS_CONSTANT_ARRAY:
502                 if (Z_ARRVAL_P(zv) != NULL && Z_ARRVAL_P(zv) != &EG(symbol_table)) {
503                         HashTable *p;
504                         EACCELERATOR_ALIGN(EAG(mem));
505                         p = (HashTable *) EAG(mem);
506                         EAG(mem) += sizeof(HashTable);
507                         store_zval_hash(p, Z_ARRVAL_P(zv));
508                         Z_ARRVAL_P(zv) = p;
509                 }
510                 break;
511         case IS_OBJECT:
512                 if (!EAG(compress)) {
513                         return;
514                 }
515 #ifndef ZEND_ENGINE_2
516                 if (Z_OBJCE_P(zv) != NULL) {
517                         char *s = store_string(Z_OBJCE_P(zv)->name, Z_OBJCE_P(zv)->name_length + 1 TSRMLS_CC);
518                         zend_str_tolower(s, Z_OBJCE_P(zv)->name_length);
519                         Z_OBJCE_P(zv) = (zend_class_entry *) s;
520                 }
521                 if (Z_OBJPROP_P(zv) != NULL) {
522                         HashTable *p;
523                         EACCELERATOR_ALIGN(EAG(mem));
524                         p = (HashTable *) EAG(mem);
525                         EAG(mem) += sizeof(HashTable);
526                         store_zval_hash(p, Z_OBJPROP_P(zv));
527                         Z_OBJPROP_P(zv) = p;
528                 }
529 #endif
530         default:
531                 break;
532         }
533 }
534
535 eaccelerator_op_array *store_op_array(zend_op_array * from TSRMLS_DC)
536 {
537         eaccelerator_op_array *to;
538         zend_op *opline;
539         zend_op *end;
540
541         DBG(ea_debug_pad, (EA_DEBUG TSRMLS_CC));
542 #ifdef ZEND_ENGINE_2
543         DBG(ea_debug_printf, (EA_DEBUG, "[%d] store_op_array: %s [scope=%s type=%x]\n",
544             getpid(), from->function_name ? from->function_name : "(top)",
545                         from->scope ? from->scope->name : "NULL"
546                         , from->type
547                 ));
548 #else
549         DBG(ea_debug_printf, (EA_DEBUG, "[%d] store_op_array: %s [scope=%s type=%x]\n",
550             getpid(), from->function_name ? from->function_name : "(top)",
551                         "NULL"
552                         , from->type
553                 ));
554 #endif
555
556         if (from->type == ZEND_INTERNAL_FUNCTION) {
557                 EACCELERATOR_ALIGN(EAG(mem));
558                 to = (eaccelerator_op_array *) EAG(mem);
559                 EAG(mem) += offsetof(eaccelerator_op_array, opcodes);
560         } else if (from->type == ZEND_USER_FUNCTION) {
561                 EACCELERATOR_ALIGN(EAG(mem));
562                 to = (eaccelerator_op_array *) EAG(mem);
563                 EAG(mem) += sizeof(eaccelerator_op_array);
564         } else {
565                 return NULL;
566         }
567
568         to->type = from->type;
569 #ifdef ZEND_ENGINE_2
570         to->num_args = from->num_args;
571         to->required_num_args = from->required_num_args;
572         if (from->num_args > 0) {
573                 zend_uint i;
574                 EACCELERATOR_ALIGN(EAG(mem));
575                 to->arg_info = (zend_arg_info *) EAG(mem);
576                 EAG(mem) += from->num_args * sizeof(zend_arg_info);
577                 for (i = 0; i < from->num_args; i++) {
578                         if (from->arg_info[i].name) {
579                                 to->arg_info[i].name = store_string(from->arg_info[i].name, from->arg_info[i].name_len + 1 TSRMLS_CC);
580                                 to->arg_info[i].name_len = from->arg_info[i].name_len;
581                         }
582                         if (from->arg_info[i].class_name) {
583                                 to->arg_info[i].class_name = store_string(from->arg_info[i].class_name, from->arg_info[i].class_name_len + 1 TSRMLS_CC);
584                                 to->arg_info[i].class_name_len = from->arg_info[i].class_name_len;
585                         }
586 #  ifdef ZEND_ENGINE_2_1
587                         /* php 5.1 introduces this in zend_arg_info for array type hinting */
588                         to->arg_info[i].array_type_hint = from->arg_info[i].array_type_hint;
589 #  endif
590                         to->arg_info[i].allow_null = from->arg_info[i].allow_null;
591                         to->arg_info[i].pass_by_reference = from->arg_info[i].pass_by_reference;
592                         to->arg_info[i].return_reference = from->arg_info[i].return_reference;
593                 }
594         }
595         to->pass_rest_by_reference = from->pass_rest_by_reference;
596 #else
597         if (from->arg_types != NULL)
598                 to->arg_types = (unsigned char *) store_string((char *) from->arg_types, (from->arg_types[0] + 1) * sizeof(zend_uchar) TSRMLS_CC);
599 #endif
600         if (from->function_name != NULL)
601                 to->function_name = store_string(from->function_name, strlen(from->function_name) + 1 TSRMLS_CC);
602 #ifdef ZEND_ENGINE_2
603         to->fn_flags = from->fn_flags;
604         to->scope_name = NULL;
605         to->scope_name_len = 0;
606         if (from->scope != NULL) {
607                 Bucket *q = CG(class_table)->pListHead;
608                 while (q != NULL) {
609                         if (*(zend_class_entry **) q->pData == from->scope) {
610                                 to->scope_name = store_string(q->arKey, q->nKeyLength TSRMLS_CC);
611                                 to->scope_name_len = q->nKeyLength - 1;
612
613                                 DBG(ea_debug_pad, (EA_DEBUG TSRMLS_CC));
614                                 DBG(ea_debug_printf, (EA_DEBUG,
615                         "[%d]                 find scope '%s' in CG(class_table) save hashkey '%s' [%08x] as to->scope_name\n",
616                                                 getpid(), from->scope->name ? from->scope->name : "NULL", q->arKey, to->scope_name));
617                                 break;
618                         }
619                         q = q->pListNext;
620                 }
621             if (to->scope_name == NULL) {
622                     DBG(ea_debug_pad, (EA_DEBUG TSRMLS_CC));
623                     DBG(ea_debug_printf, (EA_DEBUG,
624                                                 "[%d]                 could not find scope '%s' in CG(class_table), saving it to NULL\n",
625                                                 getpid(), from->scope->name ? from->scope->name : "NULL"));
626             }
627     }
628 #endif
629
630         if (from->type == ZEND_INTERNAL_FUNCTION) {
631 #ifdef ZEND_ENGINE_2
632                 /* zend_internal_function also contains return_reference in ZE2 */
633                 to->return_reference = from->return_reference;
634 #endif         
635                 return to;
636         }
637    
638         to->opcodes = from->opcodes;
639         to->last = from->last;
640         to->T = from->T;
641         to->brk_cont_array = from->brk_cont_array;
642         to->last_brk_cont = from->last_brk_cont;
643 #ifdef ZEND_ENGINE_2
644         to->try_catch_array = from->try_catch_array;
645         to->last_try_catch = from->last_try_catch;
646         to->uses_this = from->uses_this;
647 #else
648         to->uses_globals = from->uses_globals;
649 #endif
650         to->static_variables = from->static_variables;
651         to->return_reference = from->return_reference;
652         to->filename = from->filename;
653
654         if (from->opcodes != NULL) {
655                 EACCELERATOR_ALIGN(EAG(mem));
656                 to->opcodes = (zend_op *) EAG(mem);
657                 EAG(mem) += from->last * sizeof(zend_op);
658                 memcpy(to->opcodes, from->opcodes, from->last * sizeof(zend_op));
659
660                 opline = to->opcodes;
661                 end = opline + to->last;
662                 EAG(compress) = 0;
663                 for (; opline < end; opline++) {
664                         /*
665                            if (opline->result.op_type == IS_CONST)
666                            store_zval(&opline->result.u.constant TSRMLS_CC);
667                          */
668                         if (opline->op1.op_type == IS_CONST)
669                                 store_zval(&opline->op1.u.constant TSRMLS_CC);
670                         if (opline->op2.op_type == IS_CONST)
671                                 store_zval(&opline->op2.u.constant TSRMLS_CC);
672 #ifdef ZEND_ENGINE_2
673                         switch (opline->opcode) {
674                         case ZEND_JMP:
675                                 opline->op1.u.jmp_addr = to->opcodes + (opline->op1.u.jmp_addr - from->opcodes);
676                                 break;
677                         case ZEND_JMPZ:
678                         case ZEND_JMPNZ:
679                         case ZEND_JMPZ_EX:
680                         case ZEND_JMPNZ_EX:
681                                 opline->op2.u.jmp_addr = to->opcodes + (opline->op2.u.jmp_addr - from->opcodes);
682                                 break;
683                         }
684 #endif
685                 }
686                 EAG(compress) = 1;
687         }
688         if (from->brk_cont_array != NULL) {
689                 EACCELERATOR_ALIGN(EAG(mem));
690                 to->brk_cont_array = (zend_brk_cont_element *) EAG(mem);
691                 EAG(mem) += sizeof(zend_brk_cont_element) * from->last_brk_cont;
692                 memcpy(to->brk_cont_array, from->brk_cont_array, sizeof(zend_brk_cont_element) * from->last_brk_cont);
693         } else {
694                 to->last_brk_cont = 0;
695         }
696 #ifdef ZEND_ENGINE_2
697         if (from->try_catch_array != NULL) {
698                 EACCELERATOR_ALIGN(EAG(mem));
699                 to->try_catch_array = (zend_try_catch_element *) EAG(mem);
700                 EAG(mem) += sizeof(zend_try_catch_element) * from->last_try_catch;
701                 memcpy(to->try_catch_array, from->try_catch_array, sizeof(zend_try_catch_element) * from->last_try_catch);
702         } else {
703                 to->last_try_catch = 0;
704         }
705 #endif
706         if (from->static_variables != NULL) {
707                 EACCELERATOR_ALIGN(EAG(mem));
708                 to->static_variables = (HashTable *) EAG(mem);
709                 EAG(mem) += sizeof(HashTable);
710                 store_zval_hash(to->static_variables, from->static_variables);
711         }
712 #ifdef ZEND_ENGINE_2_1
713         if (from->vars != NULL) {
714                 int i;
715                 EACCELERATOR_ALIGN(EAG(mem));
716                 to->last_var = from->last_var;
717                 to->vars = (zend_compiled_variable*)EAG(mem);
718                 EAG(mem) += sizeof(zend_compiled_variable) * from->last_var;
719                         memcpy(to->vars, from->vars, sizeof(zend_compiled_variable) * from->last_var);
720                 for (i = 0; i < from->last_var; i ++) {
721                         to->vars[i].name = store_string(from->vars[i].name, from->vars[i].name_len+1 TSRMLS_CC);
722                 }
723         } else {
724                 to->last_var = 0;
725                 to->vars = NULL;
726         }
727 #endif
728         if (from->filename != NULL) {
729                 to->filename = store_string(from->filename, strlen(from->filename) + 1 TSRMLS_CC);
730         }
731 #ifdef ZEND_ENGINE_2
732         to->line_start = from->line_start;
733         to->line_end = from->line_end;
734 #ifdef INCLUDE_DOC_COMMENTS
735     to->doc_comment_len = from->doc_comment_len;
736     if (from->doc_comment != NULL)
737         to->doc_comment = store_string(from->doc_comment, from->doc_comment_len + 1 TSRMLS_CC);
738 #endif
739 #endif
740         return to;
741 }
742
743 #ifdef ZEND_ENGINE_2
744 static zend_property_info *store_property_info(zend_property_info * from TSRMLS_DC)
745 {
746         zend_property_info *to;
747         EACCELERATOR_ALIGN(EAG(mem));
748         to = (zend_property_info *) EAG(mem);
749         EAG(mem) += sizeof(zend_property_info);
750         memcpy(to, from, sizeof(zend_property_info));
751         to->name = store_string(from->name, from->name_length + 1 TSRMLS_CC);
752 #ifdef ZEND_ENGINE_2_1
753 #ifdef INCLUDE_DOC_COMMENTS
754 to->doc_comment_len = from->doc_comment_len;
755 if (from->doc_comment != NULL) {
756        to->doc_comment = store_string(from->doc_comment, from->doc_comment_len + 1 TSRMLS_CC);
757 }
758 #else
759         to->doc_comment_len = 0;
760         to->doc_comment = NULL;
761 #endif
762 #endif
763         return to;
764 }
765
766 /*
767  * The following two functions handle access checking of properties (public/private/protected)
768  * and control proper inheritance during copying of the properties_info and (default_)static_members hashes
769  *
770  * Both functions return ZEND_HASH_APPLY_REMOVE if the property to be copied needs to be skipped, or
771  * ZEND_HASH_APPLY_KEEP if the property needs to be copied over into the cache.
772  * 
773  * If the property is skipped due to access restrictions, or it needs inheritance of its value from the
774  * parent, the restore phase will take care of that.
775  *
776  * Most of the logic behind all this can be found in zend_compile.c, functions zend_do_inheritance and
777  * zend_do_inherit_property_access_check
778 */
779 static int store_property_access_check(Bucket * p, zend_class_entry * from_ce)
780 {
781         zend_class_entry *from = from_ce;
782         zend_class_entry *parent = from->parent;
783        
784         if (parent) {
785                 // hra: TODO - do some usefull stuff :)
786                 // check for ACC_PRIVATE etc.
787                 // for now, just return keep
788         }
789         return ZEND_HASH_APPLY_KEEP;
790 }
791
792 static int store_static_member_access_check(Bucket * p, zend_class_entry * from_ce)
793 {
794         zend_class_entry *from = from_ce;
795         zend_class_entry *parent = from->parent;
796     union {
797         zend_property_info *v;
798         void *ptr;
799     } pinfo, cinfo;
800     union {
801         zval **v;
802         void *ptr;
803     } pprop, cprop;
804         char *mname, *cname = NULL;
805
806     cprop.v = p->pData;
807         /* Check if this is a parent class. If so, copy unconditionally */
808         if (parent) {
809                 /* unpack the \0classname\0membername\0 style property name to seperate vars */
810 #ifdef ZEND_ENGINE_2_2
811                 zend_unmangle_property_name(p->arKey, p->nKeyLength, &cname, &mname);
812 #else
813                 zend_unmangle_property_name(p->arKey, &cname, &mname);
814 #endif
815        
816                 /* lookup the member's info in parent and child */
817                 if((zend_hash_find(&parent->properties_info, mname, strlen(mname)+1, &pinfo.ptr) == SUCCESS) &&
818                         (zend_hash_find(&from->properties_info, mname, strlen(mname)+1, &cinfo.ptr) == SUCCESS)) {
819                         /* don't copy this static property if protected in parent and static public in child.
820                            inheritance will handle this properly on restore */
821                         if(cinfo.v->flags & ZEND_ACC_STATIC && (pinfo.v->flags & ZEND_ACC_PROTECTED && cinfo.v->flags & ZEND_ACC_PUBLIC)) {
822                                 return ZEND_HASH_APPLY_REMOVE;
823                         }
824                         /* If the static member points to the same value in parent and child, remove for proper inheritance during restore */
825 #  ifdef ZEND_ENGINE_2_1
826                         if(zend_hash_quick_find(&parent->default_static_members, p->arKey, p->nKeyLength, p->h, &pprop.ptr) == SUCCESS) {
827 #  else
828                         if(zend_hash_quick_find(parent->static_members, p->arKey, p->nKeyLength, p->h, &pprop.ptr) == SUCCESS) {
829 #  endif
830                                 if(*pprop.v == *cprop.v) {
831                                         return ZEND_HASH_APPLY_REMOVE;
832                                 }
833                         }
834                 }
835         }
836         return ZEND_HASH_APPLY_KEEP;
837 }
838
839 /*
840  * This function makes sure that functions/methods that are not in the scope of the current
841  * class being stored, do not get copied to the function_table hash. This makes sure they
842  * get properly inherited on restore by zend_do_inheritance
843  *
844  * If we dont do this, it will result in broken inheritance, problems with final methods
845  * (e.g. "Cannot override final method") and the like.
846  */
847 static int store_function_inheritance_check(Bucket * p, zend_class_entry * from_ce)
848 {
849         zend_class_entry *from = from_ce;
850         zend_function *zf = p->pData;
851        
852         if (zf->common.scope == from) {
853                 return ZEND_HASH_APPLY_KEEP;
854         }
855         return ZEND_HASH_APPLY_REMOVE;
856 }
857 #endif
858
859 eaccelerator_class_entry *store_class_entry(zend_class_entry * from TSRMLS_DC)
860 {
861         eaccelerator_class_entry *to;
862         unsigned int i;
863
864         EACCELERATOR_ALIGN(EAG(mem));
865         to = (eaccelerator_class_entry *) EAG(mem);
866         EAG(mem) += sizeof(eaccelerator_class_entry);
867         to->type = from->type;
868         to->name = NULL;
869         to->name_length = from->name_length;
870         to->parent = NULL;
871 #ifdef ZEND_ENGINE_2
872         to->ce_flags = from->ce_flags;
873         to->static_members = NULL;
874
875         /*
876          * Scan the interfaces looking for the first one which isn't 0
877          * This is the first inherited interface and should not be counted in the stored object
878          */
879         for (i = 0 ; i < from->num_interfaces ; i++) {
880                 if (from->interfaces[i] != 0) {
881                         break;
882                 }
883         }
884         to->num_interfaces = i;
885         DBG(ea_debug_printf, (EA_DEBUG, "from->num_interfaces=%d, to->num_interfaces=%d\n", from->num_interfaces, to->num_interfaces));
886
887         /*
888          * hrak: no need to really store the interfaces since these get populated
889          * at/after restore by zend_do_inheritance and ZEND_ADD_INTERFACE
890          */
891 #endif
892
893         DBG(ea_debug_pad, (EA_DEBUG TSRMLS_CC));
894         DBG(ea_debug_printf, (EA_DEBUG, "[%d] store_class_entry: %s parent was '%s'\n",
895                                         getpid(), from->name ? from->name : "(top)",
896                                         from->parent ? from->parent->name : "NULL"));
897 #ifdef DEBUG
898         EAG(xpad)++;
899 #endif
900
901         if (from->name != NULL)
902                 to->name = store_string(from->name, from->name_length + 1 TSRMLS_CC);
903         if (from->parent != NULL && from->parent->name)
904                 to->parent = store_string(from->parent->name, from->parent->name_length + 1 TSRMLS_CC);
905
906 #ifdef ZEND_ENGINE_2
907         to->line_start = from->line_start;
908         to->line_end = from->line_end;
909 #ifdef INCLUDE_DOC_COMMENTS
910     to->doc_comment_len = from->doc_comment_len;
911 #endif
912
913         if (from->filename != NULL)
914                 to->filename = store_string(from->filename, strlen(from->filename) + 1 TSRMLS_CC);
915 #ifdef INCLUDE_DOC_COMMENTS
916     if (from->doc_comment != NULL)
917         to->doc_comment = store_string(from->doc_comment, from->doc_comment_len + 1 TSRMLS_CC);
918 #endif
919
920         store_zval_hash(&to->constants_table, &from->constants_table);
921         store_zval_hash(&to->default_properties, &from->default_properties);
922         //store_hash(&to->properties_info, &from->properties_info, (store_bucket_t) store_property_info, NULL, NULL);
923         store_hash(&to->properties_info, &from->properties_info, (store_bucket_t) store_property_info, (check_bucket_t) store_property_access_check, from);
924 #  ifdef ZEND_ENGINE_2_1
925         if((from->static_members != NULL) && (from->static_members != &from->default_static_members)) {
926                 store_zval_hash(&to->default_static_members, &from->default_static_members);
927                 EACCELERATOR_ALIGN(EAG(mem));
928                 to->static_members = (HashTable *) EAG(mem);
929                 EAG(mem) += sizeof(HashTable);
930                 store_hash(to->static_members, from->static_members, (store_bucket_t) store_zval_ptr, (check_bucket_t) store_static_member_access_check, from);
931         } else {
932                 /*EACCELERATOR_ALIGN(EAG(mem));
933                 to->static_members = (HashTable *) EAG(mem);
934                 EAG(mem) += sizeof(HashTable);*/
935                 store_hash(&to->default_static_members, &from->default_static_members, (store_bucket_t) store_zval_ptr, (check_bucket_t) store_static_member_access_check, from);
936                 to->static_members = &to->default_static_members;
937         }
938 #  elif defined(ZEND_ENGINE_2) && !defined(ZEND_ENGINE_2_1)
939         /* for php-5.0 */
940         if(f