root/eaccelerator/trunk/ea_store.c

Revision 348, 32.6 kB (checked in by bart, 1 month ago)

First stab at php 5.3 support. Only fixes the script cache. phpMyAdmin seems to work with these changes.

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