root/eaccelerator/tags/0.9.5-beta2/ea_store.c

Revision 195, 30.1 kB (checked in by hans, 3 years ago)

Fixed handling of interfaces. This fixes sf.net bug #1440575

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