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

Revision 231, 29.2 kB (checked in by bart, 2 years ago)

Some zval macro's differ for php4 and 5, this fixes #146.

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