root/eaccelerator/branches/new-cache/ea_store.c

Revision 335, 34.5 kB (checked in by bart, 1 year ago)

Branch trunk for new caching code

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