root/eaccelerator/tags/0.9.3/eaccelerator.c

Revision 94, 141.2 kB (checked in by zoeloelip, 3 years ago)

VC compile fix

  • 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 - 2005 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    | Author(s): Dmitry Stogov <dstogov@users.sourceforge.net>             |
26    |            Seung Woo <segv@sayclub.com>                              |
27    |            Everaldo Canuto <everaldo_canuto@yahoo.com.br>            |
28    +----------------------------------------------------------------------+
29    $Id$
30 */
31
32 #include "eaccelerator.h"
33 #include "eaccelerator_version.h"
34
35 #ifdef HAVE_EACCELERATOR
36
37 #include "opcodes.h"
38
39 #include "zend.h"
40 #include "zend_API.h"
41 #include "zend_extensions.h"
42
43 #include "webui.h"
44 #include "debug.h"
45 #include "shm.h"
46 #include "session.h"
47 #include "content.h"
48 #include "cache.h"
49
50 #include <sys/types.h>
51 #include <sys/stat.h>
52 #ifdef ZEND_WIN32
53 #  include "win32/time.h"
54 #  include <time.h>
55 #  include <sys/utime.h>
56 #else
57 #  include <sys/file.h>
58 #  include <sys/time.h>
59 #  include <utime.h>
60 #endif
61 #include <fcntl.h>
62
63 #ifndef O_BINARY
64 #  define O_BINARY 0
65 #endif
66
67 /*???
68 #ifdef HAVE_SCHED_H
69 #  include <sched.h>
70 #endif
71 */
72
73 #include "php.h"
74 #include "php_ini.h"
75 #include "php_logos.h"
76 #include "main/fopen_wrappers.h"
77 #include "ext/standard/info.h"
78 #include "ext/standard/php_incomplete_class.h"
79 #include "ext/standard/md5.h"
80
81 #ifndef INCOMPLETE_CLASS
82 #  define INCOMPLETE_CLASS "__PHP_Incomplete_Class"
83 #endif
84 #ifndef MAGIC_MEMBER
85 #  define MAGIC_MEMBER "__PHP_Incomplete_Class_Name"
86 #endif
87
88 #include "SAPI.h"
89
90 #define MAX_DUP_STR_LEN 256
91
92 /* Globals (different for each process/thread) */
93 ZEND_DECLARE_MODULE_GLOBALS(eaccelerator)
94
95 /* Globals (common for each process/thread) */
96 static long eaccelerator_shm_size = 0;
97 long eaccelerator_shm_max = 0;
98 static long eaccelerator_shm_ttl = 0;
99 static long eaccelerator_shm_prune_period = 0;
100 static long eaccelerator_debug = 0;
101 static zend_bool eaccelerator_check_mtime = 1;
102 static zend_bool eaccelerator_scripts_shm_only = 0;
103
104 eaccelerator_mm* eaccelerator_mm_instance = NULL;
105 static int eaccelerator_is_zend_extension = 0;
106 static int eaccelerator_is_extension      = 0;
107 static zend_extension* ZendOptimizer = NULL;
108
109 static HashTable eaccelerator_global_function_table;
110 static HashTable eaccelerator_global_class_table;
111
112 int binary_eaccelerator_version;
113 int binary_php_version;
114 int binary_zend_version;
115
116 FILE *F_fp;
117
118 #ifdef ZEND_ENGINE_2
119 /* pointer to the properties_info hashtable destructor */
120 static dtor_func_t properties_info_dtor = NULL;
121 #endif
122
123 /* saved original functions */
124 static zend_op_array *(*mm_saved_zend_compile_file)(zend_file_handle *file_handle, int type TSRMLS_DC);
125
126 #if defined(PROFILE_OPCODES) || defined(WITH_EACCELERATOR_EXECUTOR)
127 static void (*mm_saved_zend_execute)(zend_op_array *op_array TSRMLS_DC);
128 #endif
129
130 /* external declarations */
131 PHPAPI void php_stripslashes(char *str, int *len TSRMLS_DC);
132
133 ZEND_DLEXPORT zend_op_array* eaccelerator_compile_file(zend_file_handle *file_handle, int type TSRMLS_DC);
134
135 /******************************************************************************/
136 /* hash mm functions                                                                                                              */
137 /* TODO: insert items sorted in buckets, so searching in buckets goes from        */
138 /*                      O(n) to O(log n)
139 /******************************************************************************/
140
141 /* Create a key for the scripts hashtable. This is only used when eA can't use
142    inodes. */
143 inline unsigned int hash_mm(const char *data, int len) {
144   unsigned int h;
145   const char *e = data + len;
146   for (h = 2166136261U; data < e; ) {
147     h *= 16777619;
148     h ^= *data++;
149   }
150   return h;
151 }
152
153 /* Find a script entry with the given hash key */
154 static mm_cache_entry* hash_find_mm(const char  *key,
155                                     struct stat *buf,
156                                     int         *nreloads,
157                                     time_t      ttl) {
158   unsigned int hv, slot;
159   mm_cache_entry *p, *q;
160
161 #ifdef EACCELERATOR_USE_INODE
162   hv = buf->st_dev + buf->st_ino;
163 #else
164   hv = hash_mm(key, strlen(key));
165 #endif
166   slot = hv & MM_HASH_MAX;
167
168   EACCELERATOR_LOCK_RW();
169   q = NULL;
170   p = eaccelerator_mm_instance->hash[slot];
171   while (p != NULL) {
172 #ifdef EACCELERATOR_USE_INODE
173     if (p->st_dev == buf->st_dev && p->st_ino == buf->st_ino) {
174       struct stat buf2;
175       if ((eaccelerator_check_mtime &&
176           (buf->st_mtime != p->mtime || buf->st_size != p->filesize)) ||
177           (strcmp(p->realfilename, key) != 0 &&
178            (stat(p->realfilename,&buf2) != 0 ||
179            buf2.st_dev != buf->st_dev ||
180            buf2.st_ino != buf->st_ino))) {
181 #else
182     if ((p->hv == hv) && (strcmp(p->realfilename, key) == 0)) {
183       if (eaccelerator_check_mtime &&
184           (buf->st_mtime != p->mtime || buf->st_size != p->filesize)) {
185 #endif
186         /* key is invalid. Remove it. */
187         *nreloads = p->nreloads+1;
188         if (q == NULL) {
189           eaccelerator_mm_instance->hash[slot] = p->next;
190         } else {
191           q->next = p->next;
192         }
193         eaccelerator_mm_instance->hash_cnt--;
194         if (p->use_cnt > 0) {
195           /* key is used by other process/thred. Shedule it to remove */
196           p->removed = 1;
197           p->next = eaccelerator_mm_instance->removed;
198           eaccelerator_mm_instance->removed = p;
199           eaccelerator_mm_instance->rem_cnt++;
200           EACCELERATOR_UNLOCK_RW();
201           return NULL;
202         } else {
203           /* key is unused. Remove it. */
204           eaccelerator_free_nolock(p);
205           EACCELERATOR_UNLOCK_RW();
206           return NULL;
207         }
208       } else {
209         /* key is valid */
210         p->nhits++;
211         p->use_cnt++;
212         p->ttl = ttl;
213         EACCELERATOR_UNLOCK_RW();
214         return p;
215       }
216     }
217     q = p;
218     p = p->next;
219   }
220   EACCELERATOR_UNLOCK_RW();
221   return NULL;
222 }
223
224 /* Add a new entry to the hashtable */
225 static void hash_add_mm(mm_cache_entry *x) {
226   mm_cache_entry *p,*q;
227   unsigned int slot;
228 #ifdef EACCELERATOR_USE_INODE
229   slot = (x->st_dev + x->st_ino) & MM_HASH_MAX;
230 #else
231   x->hv = hash_mm(x->realfilename, strlen(x->realfilename));
232   slot = x->hv & MM_HASH_MAX;
233 #endif
234
235   EACCELERATOR_LOCK_RW();
236   x->next = eaccelerator_mm_instance->hash[slot];
237   eaccelerator_mm_instance->hash[slot] = x;
238   eaccelerator_mm_instance->hash_cnt++;
239   q = x;
240   p = x->next;
241   while (p != NULL) {
242 #ifdef EACCELERATOR_USE_INODE
243     if ((p->st_dev == x->st_dev) && (p->st_ino == x->st_ino)) {
244 #else
245     if ((p->hv == x->hv) &&
246         (strcmp(p->realfilename, x->realfilename) == 0)) {
247 #endif
248       q->next = p->next;
249       eaccelerator_mm_instance->hash_cnt--;
250       eaccelerator_mm_instance->hash[slot]->nreloads += p->nreloads;
251       if (p->use_cnt > 0) {
252         /* key is used by other process/thred. Shedule it to remove */
253         p->removed = 1;
254         p->next = eaccelerator_mm_instance->removed;
255         eaccelerator_mm_instance->removed = p;
256         eaccelerator_mm_instance->rem_cnt++;
257         EACCELERATOR_UNLOCK_RW();
258         return;
259       } else {
260         /* key is unused. Remove it. */
261         eaccelerator_free_nolock(p);
262         EACCELERATOR_UNLOCK_RW();
263         return;
264       }
265     }
266     q = p;
267     p = p->next;
268   }
269   EACCELERATOR_UNLOCK_RW();
270 }
271
272 /* Initialise the shared memory */
273 static int init_mm(TSRMLS_D) {
274   pid_t  owner = getpid();
275   MM     *mm;
276   size_t total;
277   char   mm_path[MAXPATHLEN];
278
279 /*  if (getppid() != 1) return SUCCESS; */ /*???*/
280 #ifdef ZEND_WIN32
281     snprintf(mm_path, MAXPATHLEN, "%s.%s", EACCELERATOR_MM_FILE, sapi_module.name);
282 #else
283     snprintf(mm_path, MAXPATHLEN, "%s.%s%d", EACCELERATOR_MM_FILE, sapi_module.name, getpid());
284 #endif
285 /*  snprintf(mm_path, MAXPATHLEN, "%s.%s%d", EACCELERATOR_MM_FILE, sapi_module.name, geteuid());*/
286   if ((eaccelerator_mm_instance = (eaccelerator_mm*)mm_attach(eaccelerator_shm_size*1024*1024, mm_path)) != NULL) {
287 #ifdef ZTS
288     mm_mutex = tsrm_mutex_alloc();
289 #endif
290     return SUCCESS;
291   }
292   mm = mm_create(eaccelerator_shm_size*1024*1024, mm_path);
293   if (!mm) {
294     return FAILURE;
295   }
296 #ifdef DEBUG
297 #ifdef ZEND_WIN32
298   fprintf(F_fp, "init_mm [%d]\n", getpid());
299 #else
300   fprintf(F_fp, "init_mm [%d,%d]\n", getpid(), getppid());
301 #endif
302   fflush(F_fp);
303 #endif
304 #ifdef ZTS
305   mm_mutex = tsrm_mutex_alloc();
306 #endif
307   total = mm_available(mm);
308   eaccelerator_mm_instance = mm_malloc_lock(mm, sizeof(*eaccelerator_mm_instance));
309   if (!eaccelerator_mm_instance) {
310     return FAILURE;
311   }
312   mm_set_attach(mm, eaccelerator_mm_instance);
313   memset(eaccelerator_mm_instance, 0, sizeof(*eaccelerator_mm_instance));
314   eaccelerator_mm_instance->owner = owner;
315   eaccelerator_mm_instance->mm    = mm;
316   eaccelerator_mm_instance->total = total;
317   eaccelerator_mm_instance->hash_cnt = 0;
318   eaccelerator_mm_instance->rem_cnt  = 0;
319   eaccelerator_mm_instance->enabled = 1;
320   eaccelerator_mm_instance->optimizer_enabled = 1;
321   eaccelerator_mm_instance->removed = NULL;
322   eaccelerator_mm_instance->locks = NULL;
323   eaccelerator_mm_instance->user_hash_cnt = 0;
324   eaccelerator_mm_instance->last_prune = time(0);
325   EACCELERATOR_PROTECT();
326   return SUCCESS;
327 }
328
329 /* Clean up the shared memory */
330 static void shutdown_mm(TSRMLS_D) {
331   if (eaccelerator_mm_instance) {
332 #ifdef ZEND_WIN32
333     if (eaccelerator_mm_instance->owner == getpid()) {
334 #else
335     if (getpgrp() == getpid()) {
336 #endif
337       MM *mm = eaccelerator_mm_instance->mm;
338 #ifdef DEBUG
339 #ifdef ZEND_WIN32
340       fprintf(F_fp, "shutdown_mm [%d]\n", getpid());
341 #else
342       fprintf(F_fp, "shutdown_mm [%d,%d]\n", getpid(), getppid());
343 #endif
344       fflush(F_fp);
345 #endif
346 #ifdef ZTS
347       tsrm_mutex_free(mm_mutex);
348 #endif
349       if (mm) {
350         mm_destroy(mm);
351       }
352       eaccelerator_mm_instance = NULL;
353     }
354   }
355 }
356
357 /******************************************************************************/
358 /* Prepare values to cache them                                                                                           */
359 /******************************************************************************/
360
361 #define FIXUP(x) if((x)!=NULL) {(x) = (void*)(((char*)(x)) + ((long)(MMCG(mem))));}
362
363 typedef void (*fixup_bucket_t)(void* TSRMLS_DC);
364
365 #define fixup_zval_hash(from) \
366   fixup_hash(from, (fixup_bucket_t)fixup_zval TSRMLS_CC)
367
368 #ifdef ZEND_ENGINE_2
369 static void fixup_property_info(zend_property_info* from TSRMLS_DC) {
370   FIXUP(from->name);
371 }
372 #endif
373
374 /* Prepare a zend HashTable for caching */
375 static void fixup_hash(HashTable* source, fixup_bucket_t fixup_bucket TSRMLS_DC)
376 {
377   unsigned int i;
378   Bucket *p;
379
380   if (source->nNumOfElements > 0) {
381     if (!MMCG(compress)) {
382       if (source->arBuckets != NULL) {
383         FIXUP(source->arBuckets);
384         for (i = 0; i < source->nTableSize; i++) {
385           FIXUP(source->arBuckets[i]);
386         }
387       }
388     }
389     FIXUP(source->pListHead);
390     FIXUP(source->pListTail);
391
392     p = source->pListHead;
393     while (p) {
394       FIXUP(p->pNext);
395       FIXUP(p->pLast);
396       FIXUP(p->pData);
397       FIXUP(p->pDataPtr);
398       FIXUP(p->pListLast);
399       FIXUP(p->pListNext);
400       if (p->pDataPtr) {
401         fixup_bucket(p->pDataPtr TSRMLS_CC);
402         p->pData = &p->pDataPtr;
403       } else {
404         fixup_bucket(p->pData TSRMLS_CC);
405       }
406       p = p->pListNext;
407     }
408     source->pInternalPointer = source->pListHead;
409   }
410 }
411
412 /* Prepare a zval for caching */
413 void fixup_zval(zval* zv TSRMLS_DC) {
414   switch (zv->type & ~IS_CONSTANT_INDEX) {
415     case IS_CONSTANT:
416     case IS_STRING:
417       if (zv->value.str.val == NULL ||
418          zv->value.str.len == 0) {
419         zv->value.str.val = empty_string;
420         zv->value.str.len = 0;
421       } else {
422         FIXUP(zv->value.str.val);
423       }
424       break;
425     case IS_ARRAY:
426     case IS_CONSTANT_ARRAY:
427       if (zv->value.ht == NULL || zv->value.ht == &EG(symbol_table)) {
428       } else {
429         FIXUP(zv->value.ht);
430         fixup_zval_hash(zv->value.ht);
431       }
432       break;
433     case IS_OBJECT:
434       if (!MMCG(compress)) {
435         return;
436       }
437 #ifndef ZEND_ENGINE_2
438       FIXUP(zv->value.obj.ce);
439       if (zv->value.obj.properties != NULL) {
440         FIXUP(zv->value.obj.properties);
441         fixup_zval_hash(zv->value.obj.properties);
442       }
443 #endif
444     default:
445       break;
446   }
447 }
448
449 /* Prepare an opcode array for caching */
450 static void fixup_op_array(eaccelerator_op_array* from TSRMLS_DC) {
451   zend_op *opline;
452   zend_op *end;
453
454 #ifdef ZEND_ENGINE_2
455   if (from->num_args > 0) {
456     zend_uint i;
457     FIXUP(from->arg_info);
458     for (i = 0; i < from->num_args; i++) {
459       FIXUP(from->arg_info[i].name);
460       FIXUP(from->arg_info[i].class_name);
461     }
462   }
463 #else
464   FIXUP(from->arg_types);
465 #endif
466   FIXUP(from->function_name);
467 #ifdef ZEND_ENGINE_2
468   FIXUP(from->scope_name);
469 #endif
470   if (from->type == ZEND_INTERNAL_FUNCTION) {
471     return;
472   }
473
474   if (from->opcodes != NULL) {
475     FIXUP(from->opcodes);
476
477     opline = from->opcodes;
478     end = opline + from->last;
479     MMCG(compress) = 0;
480     for (;opline < end; opline++) {
481 /*
482       if (opline->result.op_type == IS_CONST) fixup_zval(&opline->result.u.constant  TSRMLS_CC);
483 */
484       if (opline->op1.op_type    == IS_CONST) fixup_zval(&opline->op1.u.constant TSRMLS_CC);
485       if (opline->op2.op_type    == IS_CONST) fixup_zval(&opline->op2.u.constant TSRMLS_CC);
486 #ifdef ZEND_ENGINE_2
487       switch (opline->opcode) {
488         case ZEND_JMP:
489           FIXUP(opline->op1.u.jmp_addr);
490           break;
491         case ZEND_JMPZ:
492         case ZEND_JMPNZ:
493         case ZEND_JMPZ_EX:
494         case ZEND_JMPNZ_EX:
495           FIXUP(opline->op2.u.jmp_addr);
496           break;
497       }
498       opline->handler = get_opcode_handler(opline->opcode TSRMLS_CC);
499 #endif
500     }
501     MMCG(compress) = 1;
502   }
503   FIXUP(from->brk_cont_array);
504 #ifdef ZEND_ENGINE_2
505   FIXUP(from->try_catch_array);
506 #endif
507   if (from->static_variables != NULL) {
508     FIXUP(from->static_variables);
509     fixup_zval_hash(from->static_variables);
510   }
511   FIXUP(from->filename);
512 #ifdef ZEND_ENGINE_2
513   FIXUP(from->doc_comment);
514 #endif
515 }
516
517 /* Prepare a class entry for caching */
518 static void fixup_class_entry(eaccelerator_class_entry* from TSRMLS_DC) {
519   FIXUP(from->name);
520   FIXUP(from->parent);
521 #ifdef ZEND_ENGINE_2
522   FIXUP(from->filename);
523   FIXUP(from->doc_comment);
524   fixup_zval_hash(&from->constants_table);
525   fixup_zval_hash(&from->default_properties);
526   fixup_hash(&from->properties_info, (fixup_bucket_t)fixup_property_info TSRMLS_CC);
527   if (from->static_members != NULL) {
528     FIXUP(from->static_members);
529     fixup_zval_hash(from->static_members);
530   }
531 #else
532   fixup_zval_hash(&from->default_properties);
533 #endif
534   fixup_hash(&from->function_table, (fixup_bucket_t)fixup_op_array TSRMLS_CC);
535 }
536
537 /* Prepare a cache entry for caching */
538 static void eaccelerator_fixup(mm_cache_entry *p TSRMLS_DC) {
539   mm_fc_entry* q;
540
541   MMCG(mem) = (char*)((long)p - (long)p->next);
542   MMCG(compress) = 1;
543   p->next        = NULL;
544   FIXUP(p->op_array);
545   FIXUP(p->f_head);
546   FIXUP(p->c_head);
547   fixup_op_array(p->op_array TSRMLS_CC);
548   q = p->f_head;
549   while (q != NULL) {
550     FIXUP(q->fc);
551     fixup_op_array((eaccelerator_op_array*)q->fc TSRMLS_CC);
552     FIXUP(q->next);
553     q = q->next;
554   }
555   q = p->c_head;
556   while (q != NULL) {
557     FIXUP(q->fc);
558     fixup_class_entry((eaccelerator_class_entry*)q->fc TSRMLS_CC);
559     FIXUP(q->next);
560     q = q->next;
561   }
562 }
563
564 /******************************************************************************/
565
566 static int encode_version(const char *s) {
567   unsigned int v1 = 0;
568   unsigned int v2 = 0;
569   unsigned int v3 = 0;
570   unsigned int c;
571   char m = '.';
572   sscanf(s, "%u.%u%c%u",&v1,&v2,&m,&v3);
573   switch (m) {
574     case  'a': c = 0; break;
575     case  'b': c = 1; break;
576     case  '.': c = 2; break;
577     case  's': c = 15; break;
578     default: c = 2;
579   }
580   return ((v1 & 0xf) << 20) |
581          ((v2 & 0xff) << 12) |
582          ((c & 0xf) << 8) |
583          (v3 & 0xff);
584 }
585
586 static void decode_version(char *version, int v) {
587   int t = (v & 0x000f00) >> 8;
588   char c;
589   switch (t) {
590     case  0: c = 'a'; break;
591     case  1: c = 'b'; break;
592     case  2: c = '.'; break;
593     case 15: c = 's'; break;
594     default: c = '.';
595   }
596   snprintf(version, 16, "%d.%d%c%d", (v & 0xf00000) >> 20,
597                                      (v & 0x0ff000) >> 12,
598                                      c,
599                                      (v & 0x0000ff));
600 }
601
602 #ifdef EACCELERATOR_USE_INODE
603 static int eaccelerator_inode_key(char* s, dev_t dev, ino_t ino TSRMLS_DC) {
604   int n;
605   strncpy(s, MMCG(cache_dir), MAXPATHLEN-1);
606   strlcat(s, "/eaccelerator-", MAXPATHLEN-1);
607   n = strlen(s);
608   while (dev > 0) {
609     if (n >= MAXPATHLEN) return 0;
610     s[n++] = (dev % 10) +'0';
611     dev /= 10;
612   }
613   if (n >= MAXPATHLEN) return 0;
614   s[n++] = '.';
615   while (ino > 0) {
616     if (n >= MAXPATHLEN) return 0;
617     s[n++] = (ino % 10) +'0';
618     ino /= 10;
619   }
620   if (n >= MAXPATHLEN) return 0;
621   s[n++] = '\000';
622   return 1;
623 }
624 #endif
625
626 /* Function to create a hash key when filenames are used */
627 int eaccelerator_md5(char* s, const char* prefix, const char* key TSRMLS_DC) {
628 #if defined(PHP_MAJOR_VERSION) && defined(PHP_MINOR_VERSION) && \
629     ((PHP_MAJOR_VERSION > 4) || (PHP_MAJOR_VERSION == 4 && PHP_MINOR_VERSION > 1))
630   char md5str[33];
631   PHP_MD5_CTX context;
632   unsigned char digest[16];
633
634   md5str[0] = '\0';
635   PHP_MD5Init(&context);
636   PHP_MD5Update(&context, (unsigned char*)key, strlen(key));
637   PHP_MD5Final(digest, &context);
638   make_digest(md5str, digest);
639   snprintf(s, MAXPATHLEN-1, "%s%s%s", MMCG(cache_dir), prefix, md5str);
640   return 1;
641 #else
642   zval retval;
643   zval md5;
644   zval param;
645   zval *params[1];
646
647   ZVAL_STRING(&md5, "md5", 0);
648   INIT_ZVAL(param);
649   params[0] = &param;
650   ZVAL_STRING(params[0], (char*)key, 0);
651   if (call_user_function(CG(function_table), (zval**)NULL, &md5, &retval, 1, params TSRMLS_CC) == SUCCESS &&
652       retval.type == IS_STRING &&
653       retval.value.str.len == 32) {
654     strncpy(s, MMCG(cache_dir), MAXPATHLEN-1);
655     strlcat(s, prefix, MAXPATHLEN);
656     strlcat(s, retval.value.str.val, MAXPATHLEN);
657     zval_dtor(&retval);
658     return 1;
659   }
660   s[0] ='\0';
661 #endif
662   return 0;
663 }
664
665 /* Remove expired keys, content and scripts from the cache */
666 void eaccelerator_prune(time_t t) {
667   unsigned int i;
668
669   EACCELERATOR_LOCK_RW();
670   eaccelerator_mm_instance->last_prune = t;
671   for (i = 0; i < MM_HASH_SIZE; i++) {
672     mm_cache_entry **p = &eaccelerator_mm_instance->hash[i];
673     while (*p != NULL) {
674       struct stat buf;
675       if (((*p)->ttl != 0 && (*p)->ttl < t && (*p)->use_cnt <= 0) ||
676           stat((*p)->realfilename,&buf) != 0 ||
677 #ifdef EACCELERATOR_USE_INODE
678           (*p)->st_dev != buf.st_dev ||
679           (*p)->st_ino != buf.st_ino ||
680 #endif
681           (*p)->mtime != buf.st_mtime ||
682           (*p)->filesize != buf.st_size) {
683         mm_cache_entry *r = *p;
684         *p = (*p)->next;
685         eaccelerator_mm_instance->hash_cnt--;
686         eaccelerator_free_nolock(r);
687       } else {
688         p = &(*p)->next;
689       }
690     }
691   }
692   EACCELERATOR_UNLOCK_RW();
693 }
694
695 /* Allocate a new cache chunk */
696 void* eaccelerator_malloc2(size_t size TSRMLS_DC) {
697   void *p = NULL;
698   time_t t;
699
700   if (eaccelerator_gc(TSRMLS_C) > 0) {
701     p = eaccelerator_malloc(size);
702     if (p != NULL) {
703       return p;
704     }
705   }
706   if (eaccelerator_shm_prune_period > 0) {
707     t = time(0);
708     if (t - eaccelerator_mm_instance->last_prune > eaccelerator_shm_prune_period) {
709       eaccelerator_prune(t);
710       p = eaccelerator_malloc(size);
711     }
712   }
713   return p;
714 }
715
716 #define EACCELERATOR_CRC32(crc, ch)   (crc = (crc >> 8) ^ crc32tab[(crc ^ (ch)) & 0xff])
717
718 static const unsigned int crc32tab[256] = {
719   0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
720   0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
721   0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
722   0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
723   0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
724   0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
725   0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
726   0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
727   0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
728   0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
729   0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
730   0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
731   0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
732   0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
733   0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
734   0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
735   0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
736   0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
737   0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
738   0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
739   0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
740   0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
741   0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
742   0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
743   0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
744   0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
745   0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
746   0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
747   0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
748   0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
749   0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
750   0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
751   0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
752   0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
753   0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
754   0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
755   0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
756   0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
757   0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
758   0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
759   0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
760   0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
761   0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
762   0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
763   0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
764   0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
765   0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
766   0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
767   0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
768   0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
769   0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
770   0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
771   0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
772   0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
773   0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
774   0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
775   0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
776   0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
777   0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
778   0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
779   0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
780   0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
781   0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
782   0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
783 };
784
785 unsigned int eaccelerator_crc32(const char *p, size_t n) {
786   unsigned int crc = ~0;
787   for (; n--; ++p) {
788     EACCELERATOR_CRC32(crc, *p);
789   }
790   return ~crc;
791 }
792
793 /******************************************************************************/
794 /* Cache file functions.                                                                                                          */
795 /* TODO: create cache subdirectories -> speed improvement highly used servers */
796 /******************************************************************************/
797
798 /* Retrieve a cache entry from the cache directory */
799 static mm_cache_entry* hash_find_file(const char  *key,
800                                       struct stat *buf TSRMLS_DC) {
801   int f;
802   char s[MAXPATHLEN];
803   mm_file_header hdr;
804   mm_cache_entry *p;
805   int use_shm = 1;
806
807 #ifdef EACCELERATOR_USE_INODE
808   struct stat buf2;
809
810   if (!eaccelerator_inode_key(s, buf->st_dev, buf->st_ino TSRMLS_CC)) {
811     return NULL;
812   }
813 #else
814   if (!eaccelerator_md5(s, "/eaccelerator-", key TSRMLS_CC)) {
815     return NULL;
816   }
817 #endif
818
819   if ((f = open(s, O_RDONLY | O_BINARY)) > 0) {
820     EACCELERATOR_FLOCK(f, LOCK_SH);
821     if (read(f, &hdr, sizeof(hdr)) != sizeof(hdr)) {
822       EACCELERATOR_FLOCK(f, LOCK_UN);
823       close(f);
824       return NULL;
825     }
826     if (strncmp(hdr.magic,"EACCELERATOR",8) != 0 ||
827         hdr.eaccelerator_version != binary_eaccelerator_version ||
828         hdr.zend_version != binary_zend_version ||
829         hdr.php_version != binary_php_version) {
830       EACCELERATOR_FLOCK(f, LOCK_UN);
831       close(f);
832       unlink(s);
833       return NULL;
834     }
835     p = eaccelerator_malloc(hdr.size);
836     if (p == NULL) {
837       p = eaccelerator_malloc2(hdr.size TSRMLS_CC);
838     }
839     if (p == NULL) {
840       p = emalloc(hdr.size);
841       use_shm = 0;
842     }
843     if (p == NULL) {
844       EACCELERATOR_FLOCK(f, LOCK_UN);
845       close(f);
846       return NULL;
847     }
848     if (read(f, p, hdr.size) != hdr.size ||
849         p->size != hdr.size ||
850         hdr.crc32 != eaccelerator_crc32((const char*)p,p->size)) {
851       EACCELERATOR_FLOCK(f, LOCK_UN);
852       close(f);
853       unlink(s);
854       if (use_shm) eaccelerator_free(p); else efree(p);
855       return NULL;
856     }
857     EACCELERATOR_FLOCK(f, LOCK_UN);
858     close(f);
859 #ifdef EACCELERATOR_USE_INODE
860     if (p->st_dev != buf->st_dev || p->st_ino != buf->st_ino) {
861 #else
862     if (strcmp(key,p->realfilename) != 0) {
863 #endif
864       if (use_shm) eaccelerator_free(p); else efree(p);
865       return NULL;
866     }
867     if ((eaccelerator_check_mtime &&
868         (buf->st_mtime != p->mtime || buf->st_size != p->filesize))
869 #ifdef EACCELERATOR_USE_INODE
870         ||
871         (strcmp(p->realfilename, key) != 0 &&
872          (stat(p->realfilename,&buf2) != 0 ||
873          buf2.st_dev != buf->st_dev ||
874          buf2.st_ino != buf->st_ino))
875 #endif
876        ) {
877       /* key is invalid. Remove it. */
878       if (use_shm) eaccelerator_free(p); else efree(p);
879       unlink(s);
880       return NULL;
881     }
882     eaccelerator_fixup(p TSRMLS_CC);
883     if (use_shm) {
884       p->nhits    = 1;
885       p->nreloads = 1;
886       p->use_cnt  = 1;
887       p->removed  = 0;
888       if (eaccelerator_shm_ttl > 0) {
889         p->ttl = time(0) + eaccelerator_shm_ttl;
890       } else {
891         p->ttl = 0;
892       }
893       hash_add_mm(p);
894     } else {
895       p->use_cnt  = 0;
896       p->removed  = 1;
897     }
898     return p;
899   }
900   return NULL;
901 }
902
903 /* Add a cache entry to the cache directory */
904 static int hash_add_file(mm_cache_entry *p TSRMLS_DC) {
905   int f;
906   int ret = 0;
907   char s[MAXPATHLEN];
908   mm_file_header hdr;
909
910 #ifdef EACCELERATOR_USE_INODE
911   if (!eaccelerator_inode_key(s, p->st_dev, p->st_ino TSRMLS_CC)) {
912     return 0;
913   }
914 #else
915   if (!eaccelerator_md5(s, "/eaccelerator-", p->realfilename TSRMLS_CC)) {
916     return 0;
917   }
918 #endif
919
920   unlink(s);
921   f = open(s, O_CREAT | O_WRONLY | O_EXCL | O_BINARY, S_IRUSR | S_IWUSR);
922   if (f > 0) {
923     EACCELERATOR_FLOCK(f, LOCK_EX);
924     strcpy(hdr.magic,"EACCELERATOR");
925     hdr.eaccelerator_version = binary_eaccelerator_version;
926     hdr.zend_version    = binary_zend_version;
927     hdr.php_version     = binary_php_version;
928     hdr.size  = p->size;
929     hdr.mtime = p->mtime;
930     p->next = p;
931     hdr.crc32 = eaccelerator_crc32((const char*)p,p->size);
932     ret = (write(f, &hdr, sizeof(hdr)) == sizeof(hdr));
933     if (ret) ret = (write(f, p, p->size) == p->size);
934     EACCELERATOR_FLOCK(f, LOCK_UN);
935     close(f);
936   }
937   return ret;
938 }
939
940 /******************************************************************************/
941 /* Functions to calculate the size of different structure that a compiled php */
942 /* script contains.                                                                                                                       */
943 /******************************************************************************/
944
945 #ifndef DEBUG
946 inline
947 #endif
948 static
949 void calc_string(char* str, int len TSRMLS_DC) {
950   if (len > MAX_DUP_STR_LEN || zend_hash_add(&MMCG(strings), str, len, &str, sizeof(char*), NULL) == SUCCESS) {
951     EACCELERATOR_ALIGN(MMCG(mem));
952     MMCG(mem) += len;
953   }
954 }
955
956 static void calc_class_entry(zend_class_entry* from TSRMLS_DC);
957
958 typedef void (*calc_bucket_t)(void* TSRMLS_DC);
959
960 #define calc_hash_ex(from, start, calc_bucket) \
961   calc_hash_int(from, start, calc_bucket TSRMLS_CC)
962
963 #define calc_hash(from, calc_bucket) \
964   calc_hash_ex(from, (from)->pListHead, calc_bucket)
965
966 #define calc_zval_hash(from) \
967   calc_hash(from, (calc_bucket_t)calc_zval_ptr)
968
969 #define calc_zval_hash_ex(from, start) \
970   calc_hash_ex(from, start, (calc_bucket_t)calc_zval_ptr)
971
972
973 static void calc_zval_ptr(zval** from TSRMLS_DC) {
974   EACCELERATOR_ALIGN(MMCG(mem));
975   MMCG(mem) += sizeof(zval);
976   calc_zval(*from TSRMLS_CC);
977 }
978
979 #ifdef ZEND_ENGINE_2
980 static void calc_property_info(zend_property_info* from TSRMLS_DC) {
981   EACCELERATOR_ALIGN(MMCG(mem));
982   MMCG(mem) += sizeof(zend_property_info);
983   calc_string(from->name, from->name_length+1 TSRMLS_CC);
984 }
985
986 /* Calculate the size of a point to a class entry */
987 static void calc_class_entry_ptr(zend_class_entry** from TSRMLS_DC) {
988   calc_class_entry(*from TSRMLS_CC);
989 }
990 #endif
991
992 /* Calculate the size of an HashTable */
993 static void calc_hash_int(HashTable* source, Bucket* start, calc_bucket_t calc_bucket TSRMLS_DC) {
994   Bucket* p;
995
996   if (source->nNumOfElements > 0) {
997     if (!MMCG(compress)) {
998       EACCELERATOR_ALIGN(MMCG(mem));
999       MMCG(mem) += source->nTableSize * sizeof(Bucket*);
1000     }
1001     p = start;
1002     while (p) {
1003       EACCELERATOR_ALIGN(MMCG(mem));
1004       MMCG(mem) += offsetof(Bucket,arKey)+p->nKeyLength;
1005       calc_bucket(p->pData TSRMLS_CC);
1006       p = p->pListNext;
1007     }
1008   }
1009 }
1010
1011 void calc_zval(zval* zv TSRMLS_DC) {
1012   switch (zv->type & ~IS_CONSTANT_INDEX) {
1013     case IS_CONSTANT:
1014     case IS_STRING:
1015       if (zv->value.str.val == NULL ||
1016           zv->value.str.val == empty_string ||
1017           zv->value.str.len == 0) {
1018       } else {
1019         calc_string(zv->value.str.val, zv->value.str.len+1 TSRMLS_CC);
1020       }
1021       break;
1022     case IS_ARRAY:
1023     case IS_CONSTANT_ARRAY:
1024       if (zv->value.ht == NULL || zv->value.ht == &EG(symbol_table)) {
1025       } else {
1026         EACCELERATOR_ALIGN(MMCG(mem));
1027         MMCG(mem) += sizeof(HashTable);
1028         calc_zval_hash(zv->value.ht);
1029       }
1030       break;
1031     case IS_OBJECT:
1032 #ifndef ZEND_ENGINE_2
1033       if (zv->value.obj.ce != NULL) {
1034         zend_class_entry *ce = zv->value.obj.ce;
1035         if (!MMCG(compress)) {
1036           debug_printf("[%d] EACCELERATOR can't cache objects\n", getpid());
1037           zend_bailout();
1038         }
1039         while (ce != NULL) {
1040           if (ce->type !=  ZEND_USER_CLASS && strcmp(ce->name,"stdClass") != 0) {
1041             debug_printf("[%d] EACCELERATOR can't cache objects\n", getpid());
1042             zend_bailout();
1043           }
1044           ce = ce->parent;
1045         }
1046         calc_string(zv->value.obj.ce->name, zv->value.obj.ce->name_length+1 TSRMLS_CC);
1047       }
1048       if (zv->value.obj.properties != NULL) {
1049         EACCELERATOR_ALIGN(MMCG(mem));
1050         MMCG(mem) += sizeof(HashTable);
1051         calc_zval_hash(zv->value.obj.properties);
1052       }
1053 #endif
1054       return;
1055     case IS_RESOURCE:
1056       debug_printf("[%d] EACCELERATOR can't cache resources\n", getpid());
1057       zend_bailout();
1058     default:
1059       break;
1060   }
1061 }
1062
1063 /* Calculate the size of an op_array */
1064 static void calc_op_array(zend_op_array* from TSRMLS_DC) {
1065   zend_op *opline;
1066   zend_op *end;
1067
1068   if (from->type == ZEND_INTERNAL_FUNCTION) {
1069     EACCELERATOR_ALIGN(MMCG(mem));
1070     MMCG(mem) += sizeof(zend_internal_function);
1071   } else if (from->type == ZEND_USER_FUNCTION) {
1072     EACCELERATOR_ALIGN(MMCG(mem));
1073     MMCG(mem) += sizeof(eaccelerator_op_array);
1074   } else {
1075     debug_printf("[%d] EACCELERATOR can't cache function \"%s\"\n", getpid(), from->function_name);
1076     zend_bailout();
1077   }
1078 #ifdef ZEND_ENGINE_2
1079   if (from->num_args > 0) {
1080     zend_uint i;
1081     EACCELERATOR_ALIGN(MMCG(mem));
1082     MMCG(mem) += from->num_args * sizeof(zend_arg_info);
1083     for (i = 0; i < from->num_args; i++) {
1084       if (from->arg_info[i].name) {
1085         calc_string(from->arg_info[i].name,from->arg_info[i].name_len+1 TSRMLS_CC);
1086       }
1087       if (from->arg_info[i].class_name) {
1088         calc_string(from->arg_info[i].class_name,from->arg_info[i].class_name_len+1 TSRMLS_CC);
1089       }
1090     }
1091   }
1092 #else
1093   if (from->arg_types != NULL) {
1094     calc_string((char*)from->arg_types, (from->arg_types[0]+1) * sizeof(zend_uchar) TSRMLS_CC);
1095   }
1096 #endif
1097   if (from->function_name != NULL) {
1098     calc_string(from->function_name, strlen(from->function_name)+1 TSRMLS_CC);
1099   }
1100 #ifdef ZEND_ENGINE_2
1101   if (from->scope != NULL)
1102   {
1103     // HOESH: the same problem?
1104     Bucket* q = CG(class_table)->pListHead;
1105     while (q != NULL)
1106         {
1107       if (*(zend_class_entry**)q->pData == from->scope)
1108           {
1109         calc_string(q->arKey, q->nKeyLength TSRMLS_CC);
1110         break;
1111       }
1112       q = q->pListNext;
1113     }
1114   }
1115 #endif
1116   if (from->type == ZEND_INTERNAL_FUNCTION) {
1117     return;
1118   }
1119
1120   if (from->opcodes != NULL) {
1121     EACCELERATOR_ALIGN(MMCG(mem));
1122     MMCG(mem) += from->last * sizeof(zend_op);
1123
1124     opline = from->opcodes;
1125     end = opline + from->last;
1126     MMCG(compress) = 0;
1127     for (;opline < end; opline++) {
1128 /*
1129       if (opline->result.op_type == IS_CONST) calc_zval(&opline->result.u.constant  TSRMLS_CC);
1130 */
1131       if (opline->op1.op_type    == IS_CONST) calc_zval(&opline->op1.u.constant TSRMLS_CC);
1132       if (opline->op2.op_type    == IS_CONST) calc_zval(&opline->op2.u.constant TSRMLS_CC);
1133     }
1134     MMCG(compress) = 1;
1135   }
1136   if (from->brk_cont_array != NULL) {
1137     EACCELERATOR_ALIGN(MMCG(mem));
1138     MMCG(mem) += sizeof(zend_brk_cont_element) * from->last_brk_cont;
1139   }
1140 #ifdef ZEND_ENGINE_2
1141         /* HOESH: try & catch support */
1142         if (from->try_catch_array != NULL)
1143         {
1144                 EACCELERATOR_ALIGN(MMCG(mem));
1145                 MMCG(mem) += sizeof(zend_try_catch_element) * from->last_try_catch;
1146         }
1147 #endif
1148   if (from->static_variables != NULL) {
1149     EACCELERATOR_ALIGN(MMCG(mem));
1150     MMCG(mem) += sizeof(HashTable);
1151     calc_zval_hash(from->static_variables);
1152   }
1153   if (from->filename != NULL) {
1154     calc_string(from->filename, strlen(from->filename)+1 TSRMLS_CC);
1155   }
1156 #ifdef ZEND_ENGINE_2
1157   if (from->doc_comment != NULL) {
1158     calc_string(from->doc_comment, from->doc_comment_len+1 TSRMLS_CC);
1159   }
1160 #endif
1161 }
1162
1163 /* Calculate the size of a class entry */
1164 static void calc_class_entry(zend_class_entry* from TSRMLS_DC) {
1165   int i;
1166
1167   if (from->type != ZEND_USER_CLASS) {
1168     debug_printf("[%d] EACCELERATOR can't cache internal class \"%s\"\n", getpid(), from->name);
1169     zend_bailout();
1170   }
1171 /*
1172   if (from->builtin_functions) {
1173     debug_printf("[%d] EACCELERATOR can't cache class \"%s\" because of it has "
1174         "some builtin_functions\n", getpid(), from->name);
1175     zend_bailout();
1176   }
1177 */
1178   EACCELERATOR_ALIGN(MMCG(mem));
1179   MMCG(mem) += sizeof(eaccelerator_class_entry);
1180
1181   if (from->name != NULL) {
1182     calc_string(from->name, from->name_length+1 TSRMLS_CC);
1183   }
1184   if (from->parent != NULL && from->parent->name) {
1185     calc_string(from->parent->name, from->parent->name_length + 1  TSRMLS_CC);
1186   }
1187 #ifdef ZEND_ENGINE_2
1188 #if 0
1189   // what's problem. why from->interfaces[i] == 0x5a5a5a5a ?
1190   for (i=0; i<from->num_interfaces; i++) {
1191     if (from->interfaces[i]) {
1192       calc_string(from->interfaces[i]->name, from->interfaces[i]->name_length);
1193     }
1194   }
1195 #endif
1196   if (from->filename != NULL) {
1197     calc_string(from->filename, strlen(from->filename)+1 TSRMLS_CC);
1198   }
1199   if (from->doc_comment != NULL) {
1200     calc_string(from->doc_comment, from->doc_comment_len+1 TSRMLS_CC);
1201   }
1202
1203   calc_zval_hash(&from->constants_table);
1204   calc_zval_hash(&from->default_properties);
1205   calc_hash(&from->properties_info, (calc_bucket_t)calc_property_info);
1206   if (from->static_members != NULL) {
1207     EACCELERATOR_ALIGN(MMCG(mem));
1208     MMCG(mem) += sizeof(HashTable);
1209     calc_zval_hash(from->static_members);
1210   }
1211 #else
1212   calc_zval_hash(&from->default_properties);
1213 #endif
1214   calc_hash(&from->function_table, (calc_bucket_t)calc_op_array);
1215 }
1216
1217 /* Calculate the size of a cache entry with its given op_array and function and
1218    class bucket */