root/eaccelerator/tags/0.9.1/loader.c

Revision 21, 34.6 kB (checked in by reinerj, 4 years ago)

Change the address from dmitry to the SF account

  • 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 eAccelerator                                      |
6    | http://eaccelerator.sourceforge.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    +----------------------------------------------------------------------+
27    $Id$
28 */
29
30 #include "eaccelerator.h"
31 #include "eaccelerator_version.h"
32
33 #ifdef HAVE_EACCELERATOR
34 #ifdef WITH_EACCELERATOR_LOADER
35
36 #include "opcodes.h"
37
38 #include "zend.h"
39 #include "zend_API.h"
40 #include "php.h"
41
42 #include <math.h>
43
44 #define MMC_ENCODER_VERSION   0x00000002
45
46 #define MMC_ENCODER_END       0x00
47 #define MMC_ENCODER_NAMESPACE 0x01
48 #define MMC_ENCODER_CLASS     0x02
49 #define MMC_ENCODER_FUNCTION  0x03
50
51 typedef struct loader_data {
52   long  version;
53   char* filename;
54   uint  lineno;
55 } loader_data;
56
57 static inline unsigned char decode(char** p, unsigned int* l) {
58   unsigned char c;
59   if (*l == 0) {
60     zend_bailout();
61   }
62   c = **p;
63   (*p)++;
64   (*l)--;
65   return c;
66 }
67
68 static inline unsigned int decode32(char** p, unsigned int* l) {
69   unsigned int i = decode(p, l);
70   i += ((unsigned int)decode(p, l)) << 8;
71   i += ((unsigned int)decode(p, l)) << 16;
72   i += ((unsigned int)decode(p, l)) << 24;
73   return i;
74 }
75
76 static inline unsigned short decode16(char** p, unsigned int* l) {
77   unsigned short i = decode(p, l);
78   i += ((unsigned short)decode(p, l)) << 8;
79   return i;
80 }
81
82 static unsigned int decode_var(unsigned int count, char** p, unsigned int* l) {
83   unsigned int var;
84   if (count < 0xff) {
85     var = decode(p, l);
86   } else if (count < 0xffff) {
87     var = decode16(p, l);
88   } else {
89     var = decode32(p, l);
90   }
91   if (var >= count) {
92     zend_bailout();
93   }
94 #ifdef ZEND_ENGINE_2
95   return (unsigned int)(((temp_variable*)NULL) + var);
96 #else
97   return var;
98 #endif
99 }
100
101 static unsigned int decode_opline(unsigned int last, char** p, unsigned int* l) {
102   unsigned int opline;
103   if (last < 0xff-1) {
104     opline = decode(p, l);
105     if (opline == 0xff) return (unsigned int)-1;
106   } else if (last < 0xffff-1) {
107     opline = decode16(p, l);
108     if (opline == 0xffff) return (unsigned int)-1;
109   } else {
110     opline = decode32(p, l);
111   }
112   if (opline >= last) {
113     zend_bailout();
114   }
115   return opline;
116 }
117
118 static char* decode_zstr(char** p, unsigned int* l) {
119   char *s = *p;
120   unsigned int len = 0;
121   while (s[len] != '\0') {
122     len++;
123     if (len > (*l)) {
124       zend_bailout();
125     }
126   }
127   if (len == 0) {
128     (*p)++;
129     (*l)--;
130     return NULL;
131   } else {
132     char *str = emalloc(len+1);
133     memcpy(str, *p, len+1);
134     *p += len+1;
135     *l -= len+1;
136     return str;
137   }
138 }
139
140 static char* decode_zstr_noalloc(char** p, unsigned int* l) {
141   char *s = *p;
142   unsigned int len = 0;
143   while (s[len] != '\0') {
144     len++;
145     if (len > (*l)) {
146       zend_bailout();
147     }
148   }
149   if (len == 0) {
150     (*p)++;
151     (*l)--;
152     return NULL;
153   } else {
154     *p += len+1;
155     *l -= len+1;
156     return s;
157   }
158 }
159
160 #if MMC_ENCODER_VERSION < 2
161 static char* decode_filename(char** p, unsigned int* l TSRMLS_DC) {
162   char *s = *p;
163   unsigned int len = 0;
164   while (s[len] != '\0') {
165     len++;
166     if (len > (*l)) {
167       zend_bailout();
168     }
169   }
170   if (len == 0) {
171     (*p)++;
172     (*l)--;
173     return NULL;
174   } else {
175     if (((loader_data*)MMCG(mem))->filename == NULL ||
176         strcmp(((loader_data*)MMCG(mem))->filename,*p) != 0) {
177       char* old = CG(compiled_filename);
178       ((loader_data*)MMCG(mem))->filename = zend_set_compiled_filename(*p TSRMLS_CC);
179       CG(compiled_filename) = old;
180     }
181     *p += len+1;
182     *l -= len+1;
183     return ((loader_data*)MMCG(mem))->filename;
184   }
185 }
186 #endif
187
188 static char* decode_lstr(unsigned int* len, char** p, unsigned int* l) {
189   *len = decode32(p, l);
190   if (*len == 0) {
191     return NULL;
192   } else {
193     char* str;
194     if (*len > *l) {
195       zend_bailout();
196     }
197     str = emalloc((*len)+1);
198     memcpy(str, *p, *len);
199     str[(*len)] = '\0';
200     *p += *len;
201     *l -= *len;
202     return str;
203   }
204 }
205
206 static char* decode_lstr_noalloc(unsigned int* len, char** p, unsigned int* l) {
207   *len = decode32(p, l);
208   if (*len == 0) {
209     return NULL;
210   } else {
211     char* str = *p;
212     if (*len > *l) {
213       zend_bailout();
214     }
215     *p += *len;
216     *l -= *len;
217     return str;
218   }
219 }
220
221 static unsigned char* decode_pstr(char** p, unsigned int* l) {
222   unsigned char c = decode(p, l);
223   if (c == 0) {
224     return NULL;
225   } else {
226     unsigned char *str;
227     if (c > *l) {
228       zend_bailout();
229     }
230     str = emalloc(c+1);
231     str[0] = c;
232     memcpy(&str[1], *p, c);
233     *p += c;
234     *l -= c;
235     return str;
236   }
237 }
238
239 static double decode_double(char** p, unsigned int* l) {
240   unsigned char sign;
241   int exp;
242   unsigned int i1, i2;
243   double d;
244
245   sign = decode(p, l);
246   exp = decode32(p, l);
247   i1 = decode32(p, l);
248   i2 = decode32(p, l);
249   d = ldexp((((double)i2 / 4294967296.0) + (double)i1) / 4294967296.0, exp);
250   if (sign) {
251     d = -d;
252   }
253   return d;
254 }
255
256 typedef void* (*decode_bucket_t)(void* to, char**, unsigned int* TSRMLS_DC);
257
258 #define decode_zval_hash(to, p, l) decode_hash(to, sizeof(zval*), (decode_bucket_t)decode_zval_ptr, p, l TSRMLS_CC)
259 #define decode_zval_hash_noref(to, p, l) decode_hash(to, sizeof(zval*), (decode_bucket_t)decode_zval_ptr_noref, p, l TSRMLS_CC)
260
261 static HashTable* decode_hash(HashTable* to, int size, decode_bucket_t decode_bucket, char**p, unsigned int* l TSRMLS_DC);
262 static zval* decode_zval_ptr(zval* to, char** p, unsigned int* l TSRMLS_DC);
263
264 static zval* decode_zval(zval* to, int refs, char** p, unsigned int* l TSRMLS_DC) {
265   to->type     = decode(p ,l);
266   if (refs) {
267     to->is_ref = decode(p, l);
268     to->refcount = decode32(p, l);
269   } else {
270     to->is_ref   = 1;
271     to->refcount = 2;
272   }
273   switch (to->type & ~IS_CONSTANT_INDEX) {
274     case IS_NULL:
275       break;
276     case IS_BOOL:
277       to->value.lval = decode(p, l);
278       break;
279     case IS_LONG:
280       {
281   int x = decode32(p,l);
282         to->value.lval = x;
283       }
284       break;
285     case IS_DOUBLE:
286       to->value.dval = decode_double(p, l);
287       break;
288     case IS_CONSTANT:
289     case IS_STRING:
290 /*???    case FLAG_IS_BC:*/
291       to->value.str.val = decode_lstr((unsigned int*)&to->value.str.len, p, l);
292       if (to->value.str.val == NULL) {
293         to->value.str.val = empty_string;
294       }
295       break;
296     case IS_ARRAY:
297     case IS_CONSTANT_ARRAY:
298       to->value.ht = decode_zval_hash(NULL, p ,l);
299       if (to->value.ht) {
300         to->value.ht->pDestructor = ZVAL_PTR_DTOR;
301       } else {
302         ALLOC_HASHTABLE(to->value.ht);
303         zend_hash_init(to->value.ht, 0, NULL, ZVAL_PTR_DTOR, 0);
304       }
305       break;
306     case IS_OBJECT:
307     case IS_RESOURCE:
308       /*???*/
309     default:
310       zend_bailout();
311       break;
312   }
313   return to;
314 }
315
316 static zval* decode_zval_ptr(zval* to, char** p, unsigned int* l TSRMLS_DC) {
317   if (to == NULL) {
318     ALLOC_ZVAL(to);
319   }
320   decode_zval(to, 1, p, l TSRMLS_CC);
321   return to;
322 }
323
324 static zval* decode_zval_ptr_noref(zval* to, char** p, unsigned int* l TSRMLS_DC) {
325   if (to == NULL) {
326     ALLOC_ZVAL(to);
327   }
328   decode_zval(to, 1, p, l TSRMLS_CC);
329   to->is_ref   = 0;
330   to->refcount = 1;
331   return to;
332 }
333
334 static void decode_znode(znode* to, unsigned int vars_count, char** p, unsigned int* l TSRMLS_DC) {
335   to->op_type = decode(p, l);
336   if (to->op_type == IS_CONST) {
337     decode_zval(&to->u.constant, 0, p, l TSRMLS_CC);
338     to->u.constant.is_ref = 1;
339     to->u.constant.refcount = 2;
340   } else if (to->op_type == IS_VAR ||
341              to->op_type == IS_TMP_VAR) {
342     to->u.var = decode_var(vars_count, p, l);
343   } else if (to->op_type != IS_UNUSED) {
344     zend_bailout();
345   }
346 }
347
348 static HashTable* decode_hash(HashTable* to, int size, decode_bucket_t decode_bucket, char** p, unsigned int* l TSRMLS_DC) {
349   unsigned int n;
350   void *data = NULL;
351
352   if (size != sizeof(void*)) {
353     data = do_alloca(size);
354   }
355   n = decode32(p, l);
356   if (to == NULL) {
357     if (n == 0 ) return NULL;
358     ALLOC_HASHTABLE(to);
359     zend_hash_init(to, 0, NULL, NULL, 0);
360   }
361   while (n > 0) {
362     void* x;
363     char* s;
364     unsigned int len;
365
366     s = decode_lstr_noalloc(&len, p, l);
367     if (s == NULL) {
368       len = decode32(p, l);
369     }
370     if (size == sizeof(void*)) {
371       x = decode_bucket(NULL, p, l TSRMLS_CC);
372       if (s != NULL) {
373         zend_hash_add(to, s, len, &x, size, NULL);
374       } else {
375         zend_hash_index_update(to, len, &x, size, NULL);
376       }
377     } else {
378       decode_bucket(data, p, l TSRMLS_CC);
379       if (s != NULL) {
380         zend_hash_add(to, s, len, data, size, NULL);
381       } else {
382         zend_hash_index_update(to, len, data, size, NULL);
383       }
384     }
385     --n;
386   }
387   if (size != sizeof(void*)) {
388     free_alloca(data);
389   }
390   return to;
391 }
392
393 static void call_op_array_ctor_handler(zend_extension *extension, zend_op_array *op_array TSRMLS_DC) {
394   if (extension->op_array_ctor) {
395     extension->op_array_ctor(op_array);
396   }
397 }
398
399 static zend_op_array* decode_op_array(zend_op_array *to, char** p, unsigned int* l TSRMLS_DC) {
400   char c;
401   zend_op *opline;
402   zend_op *end;
403 #ifdef ZEND_ENGINE_2
404   char* scope_name;
405   int   scope_name_len;
406 #endif
407
408   c = decode(p, l);
409   if (c == ZEND_INTERNAL_FUNCTION) {
410     if (to == NULL) {
411       to = (zend_op_array*)emalloc(sizeof(zend_internal_function));
412     }
413     memset(to, 0, sizeof(zend_internal_function));
414   } else if (c == ZEND_USER_FUNCTION) {
415     if (to == NULL) {
416       to = (zend_op_array*)emalloc(sizeof(zend_op_array));
417     }
418     memset(to, 0, sizeof(zend_op_array));
419     zend_llist_apply_with_argument(&zend_extensions, (llist_apply_with_arg_func_t) call_op_array_ctor_handler, to TSRMLS_CC);
420   } else {
421     zend_bailout();
422   }
423   to->type = c;
424 #ifdef ZEND_ENGINE_2
425   to->num_args = decode32(p, l);
426   if (to->num_args > 0) {
427     zend_uint i;
428     to->arg_info = (zend_arg_info*)emalloc(to->num_args * sizeof(zend_arg_info));
429     for (i = 0; i < to->num_args; i++) {
430       to->arg_info[i].name = decode_lstr(&to->arg_info[i].name_len, p ,l);
431       to->arg_info[i].class_name = decode_lstr(&to->arg_info[i].class_name_len, p ,l);
432       to->arg_info[i].allow_null = decode(p, l);
433       to->arg_info[i].pass_by_reference = decode(p, l);
434     }
435   } else {
436     to->arg_info = NULL;
437   }
438   to->pass_rest_by_reference = decode(p, l);
439 #else
440   to->arg_types     = decode_pstr(p, l);
441 #endif
442   to->function_name = decode_zstr(p, l);
443 #ifdef ZEND_ENGINE_2
444         to->scope            = MMCG(class_entry);
445         to->fn_flags         = decode32(p, l);
446         scope_name = decode_lstr((unsigned int*)&scope_name_len, p, l);
447         if (to->scope == NULL && scope_name != NULL)
448         {
449                 if (zend_hash_find(CG(class_table),
450                         (void *)scope_name, scope_name_len,
451                         (void **)&to->scope) == SUCCESS)
452                 {
453                         to->scope = *(zend_class_entry**)to->scope;
454                 }
455                 else
456                 {
457 /*???
458                         debug_printf("[%d] EACCELERATOR can't restore parent class "
459                                 "\"%s\" of function \"%s\"\n", getpid(),
460                                 (char*)scope_name, to->function_name);
461 */
462                                 to->scope = NULL;
463                 }
464         }
465         if (to->scope != NULL)
466         {
467                 unsigned int len = strlen(to->function_name);
468                 char *lcname = zend_str_tolower_dup(to->function_name, len);
469                 /*
470                  * HOESH: As explained in restore_op_array()!
471                  */
472                 if  (
473                                 to->scope->name_length == len &&
474                                 memcmp(to->scope->name, lcname, len) == 0 &&
475                                 (
476                                         to->scope->constructor == NULL || // case 0)
477                                         to->scope->constructor->type == ZEND_INTERNAL_FUNCTION || // case A)
478                                         to->scope->constructor->op_array.scope->name_length != len || // case B)
479                                         memcmp(to->scope->constructor->op_array.scope->name, lcname, len) != 0
480                                 )
481                         )
482                 {
483                         to->scope->constructor = (zend_function*)to;
484                 }
485                 else if (*lcname == '_' && *(lcname+1) == '_')
486                 {
487                         if (len == sizeof(ZEND_CONSTRUCTOR_FUNC_NAME)-1 &&
488                                 memcmp(lcname, ZEND_CONSTRUCTOR_FUNC_NAME, sizeof(ZEND_CONSTRUCTOR_FUNC_NAME)) == 0)
489                         {
490                                 to->scope->constructor = (zend_function*)to;
491                         }
492                         else if (len == sizeof(ZEND_DESTRUCTOR_FUNC_NAME)-1 &&
493                                 memcmp(lcname, ZEND_DESTRUCTOR_FUNC_NAME, sizeof(ZEND_DESTRUCTOR_FUNC_NAME)) == 0)
494                         {
495                                 to->scope->destructor = (zend_function*)to;
496                         }
497                         else if (len == sizeof(ZEND_CLONE_FUNC_NAME)-1 &&
498                                 memcmp(lcname, ZEND_CLONE_FUNC_NAME, sizeof(ZEND_CLONE_FUNC_NAME)) == 0)
499                         {
500                                 to->scope->clone = (zend_function*)to;
501                         }
502                         else if (len == sizeof(ZEND_GET_FUNC_NAME)-1 &&
503                                 memcmp(lcname, ZEND_GET_FUNC_NAME, sizeof(ZEND_GET_FUNC_NAME)) == 0)
504                         {
505                                 to->scope->__get = (zend_function*)to;
506                         }
507                         else if (len == sizeof(ZEND_SET_FUNC_NAME)-1 &&
508                                 memcmp(lcname, ZEND_SET_FUNC_NAME, sizeof(ZEND_SET_FUNC_NAME)) == 0)
509                         {
510                                 to->scope->__set = (zend_function*)to;
511                         }
512                         else if (len == sizeof(ZEND_CALL_FUNC_NAME)-1 &&
513                                 memcmp(lcname, ZEND_CALL_FUNC_NAME, sizeof(ZEND_CALL_FUNC_NAME)) == 0)
514                         {
515                                 to->scope->__call = (zend_function*)to;
516                         }
517                 }
518                 efree(lcname);
519         }
520 #endif
521   if (to->type == ZEND_INTERNAL_FUNCTION) {
522     return to;
523   }
524   to->T = decode32(p, l);
525 #ifdef ZEND_ENGINE_2
526   to->uses_this = decode(p, l);
527 #else
528   to->uses_globals = decode(p, l);
529 #endif
530   to->return_reference = decode(p, l);
531
532   to->last = decode32(p, l);
533   to->size = to->last;
534   if (to->last > 0) {
535     to->last_brk_cont = decode32(p, l);
536     if (to->last_brk_cont > 0) {
537       zend_uint i;
538       to->brk_cont_array = emalloc(sizeof(zend_brk_cont_element)*to->last_brk_cont);
539       for (i = 0; i < to->last_brk_cont; i++) {
540         to->brk_cont_array[i].brk = decode_opline(to->last, p, l);
541         to->brk_cont_array[i].cont = decode_opline(to->last, p, l);
542         to->brk_cont_array[i].parent = decode_opline(to->last_brk_cont, p, l);
543       }
544     } else {
545       to->brk_cont_array = NULL;
546     }
547 #ifdef ZEND_ENGINE_2
548         to->last_try_catch = decode32(p, l);
549         if (to->last_try_catch > 0)
550         {
551                 zend_uint i;
552                 to->try_catch_array = emalloc(sizeof(zend_try_catch_element)*to->last_try_catch);
553                 for (i = 0; i < to->last_try_catch; i++)
554                 {
555                         to->try_catch_array[i].try_op = decode_opline(to->last, p, l);
556                         to->try_catch_array[i].catch_op = decode_opline(to->last, p, l);
557 //                      to->try_catch_array[i].parent = decode_opline(to->last_brk_cont, p, l);
558                 }
559         }
560         else
561         {
562                 to->try_catch_array = NULL;
563 }
564 #endif
565     to->opcodes = emalloc(sizeof(zend_op)*to->last);
566     memset(to->opcodes, 0, sizeof(zend_op)*to->last);
567     opline = to->opcodes;
568     end = opline + to->last;
569     for (;opline < end; opline++) {
570       const opcode_dsc* op_dsc;
571       opline->opcode = decode(p, l);
572       op_dsc = get_opcode_dsc(opline->opcode);
573       if (op_dsc == NULL) {
574         zend_bailout();
575       } else {
576         unsigned int ops = op_dsc->ops;
577 #ifdef ZEND_ENGINE_2
578 /*??? FIXME
579         opline->handler = zend_opcode_handlers[opline->opcode];
580 */
581         opline->handler = get_opcode_handler(opline->opcode TSRMLS_CC);
582 #endif
583 #if MMC_ENCODER_VERSION < 2
584         opline->lineno = decode32(p, l);
585 #else
586         if (((loader_data*)MMCG(mem))->version < 2) {
587           opline->lineno = decode32(p, l);
588         }
589         opline->lineno = ((loader_data*)MMCG(mem))->lineno;
590 #endif
591         opline->extended_value = 0;
592         opline->result.op_type = IS_UNUSED;
593         opline->op1.op_type    = IS_UNUSED;
594         opline->op2.op_type    = IS_UNUSED;
595
596         switch (ops & EXT_MASK) {
597           case EXT_UNUSED:
598             break;
599           case EXT_STD:
600           case EXT_FCALL:
601           case EXT_ARG:
602           case EXT_IFACE:
603             opline->extended_value = decode32(p, l);
604             break;
605           case EXT_SEND:
606           case EXT_SEND_NOREF:
607           case EXT_INIT_FCALL:
608           case EXT_FETCH:
609           case EXT_CAST:
610           case EXT_DECLARE:
611           case EXT_FCLASS:
612           case EXT_BIT:
613           case EXT_ISSET:
614           case EXT_ASSIGN:
615             opline->extended_value = decode(p, l);
616             break;
617           case EXT_OPLINE:
618             opline->extended_value = decode_opline(to->last, p, l);
619             break;
620           case EXT_CLASS:
621             opline->extended_value = decode_var(to->T, p, l);
622             break;
623           default:
624             zend_bailout();
625             break;
626         }
627         switch (ops & RES_MASK) {
628           case RES_UNUSED:
629             break;
630           case RES_TMP:
631             opline->result.op_type = IS_TMP_VAR;
632             opline->result.u.var = decode_var(to->T, p, l);
633             break;
634           case RES_CLASS:
635             opline->result.u.var = decode_var(to->T, p, l);
636             break;
637           case RES_VAR:
638             opline->result.op_type = IS_VAR;
639             opline->result.u.var = decode_var(to->T, p, l);
640             opline->result.u.EA.type = 0;
641             if (decode(p, l)) {
642               opline->result.u.EA.type |= EXT_TYPE_UNUSED;
643             }
644             break;
645           case RES_STD:
646             decode_znode(&opline->result, to->T, p, l TSRMLS_CC);
647             if (opline->result.op_type == IS_VAR) {
648               opline->result.u.EA.type = 0;
649               if (decode(p, l)) {
650                 opline->result.u.EA.type |= EXT_TYPE_UNUSED;
651               }
652             }
653             break;
654           default:
655             zend_bailout();
656             break;
657         }
658         switch (ops & OP1_MASK) {
659           case OP1_UNUSED:
660             break;
661           case OP1_OPLINE:
662             opline->op1.u.opline_num = decode_opline(to->last, p, l);
663             break;
664           case OP1_BRK:
665           case OP1_CONT:
666             opline->op1.u.opline_num = decode_opline(to->last_brk_cont, p, l);
667             break;
668           case OP1_CLASS:
669             opline->op1.u.var = decode_var(to->T, p, l);
670             break;
671           case OP1_UCLASS:
672             opline->op1.op_type = decode(p, l);
673             if (opline->op1.op_type != IS_UNUSED) {
674               opline->op1.u.var = decode_var(to->T, p, l);
675             }
676             break;
677           case OP1_TMP:
678             opline->op1.op_type = IS_TMP_VAR;
679             opline->op1.u.var = decode_var(to->T, p, l);
680             break;
681           case OP1_VAR:
682             opline->op1.op_type = IS_VAR;
683             opline->op1.u.var = decode_var(to->T, p, l);
684             break;
685           case OP1_ARG:
686             opline->op1.op_type = IS_CONST;
687             opline->op1.u.constant.type = IS_LONG;
688             opline->op1.u.constant.value.lval = decode32(p, l);
689             break;
690 #ifdef ZEND_ENGINE_2
691           case OP1_JMPADDR:
692             opline->op1.u.jmp_addr = to->opcodes + decode_opline(to->last, p, l);
693             break;
694 #endif
695           case OP1_STD:
696             decode_znode(&opline->op1, to->T, p, l TSRMLS_CC);
697             break;
698           default:
699             zend_bailout();
700             break;
701         }
702         switch (ops & OP2_MASK) {
703           case OP2_UNUSED:
704             break;
705           case OP2_OPLINE:
706             opline->op2.u.opline_num = decode_opline(to->last, p, l);
707             break;
708           case OP2_ARG:
709             opline->op2.u.opline_num = decode32(p, l);
710             break;
711           case OP2_ISSET:
712           case OP2_INCLUDE:
713             opline->op2.op_type = IS_CONST;
714             opline->op2.u.constant.type = IS_LONG;
715             opline->op2.u.constant.value.lval = decode(p, l);
716             break;
717           case OP2_FETCH:
718 #ifdef ZEND_ENGINE_2
719             opline->op2.u.EA.type = decode(p, l);
720             if (opline->op2.u.EA.type == ZEND_FETCH_STATIC_MEMBER) {
721               opline->op2.u.var = decode_var(to->T, p, l);
722             }
723 #else
724             opline->op2.u.fetch_type = decode(p, l);
725 #endif
726             break;
727           case OP2_CLASS:
728             opline->op2.u.var = decode_var(to->T, p, l);
729             break;
730           case OP2_TMP:
731             opline->op2.op_type = IS_TMP_VAR;
732             opline->op2.u.var = decode_var(to->T, p, l);
733             break;
734           case OP2_VAR:
735             opline->op2.op_type = IS_VAR;
736             opline->op2.u.var = decode_var(to->T, p, l);
737             break;
738 #ifdef ZEND_ENGINE_2
739           case OP2_JMPADDR:
740             opline->op2.u.jmp_addr = to->opcodes + decode_opline(to->last, p, l);
741             break;
742 #endif
743           case OP2_STD:
744             decode_znode(&opline->op2, to->T, p, l TSRMLS_CC);
745             break;
746           default:
747             zend_bailout();
748             break;
749         }
750       }
751     }
752   } else {
753     to->opcodes = NULL;
754   }
755
756 #ifdef ZEND_ENGINE_2
757   to->static_variables = decode_zval_hash(NULL, p, l);
758 #else
759   to->static_variables = decode_zval_hash_noref(NULL, p, l);
760 #endif
761   if (to->static_variables) {
762     to->static_variables->pDestructor = ZVAL_PTR_DTOR;
763   }
764 #if MMC_ENCODER_VERSION < 2
765   to->filename = decode_filename(p, l TSRMLS_CC);
766 #else
767   if (((loader_data*)MMCG(mem))->version < 2) {
768     to->filename = decode_zstr(p, l);
769     efree(to->filename);
770   }
771   to->filename = ((loader_data*)MMCG(mem))->filename;
772 #endif
773 #ifdef ZEND_ENGINE_2
774   to->line_start = decode32(p, l);
775   to->line_end = decode32(p, l);
776   to->doc_comment = decode_lstr(&to->doc_comment_len, p, l);
777 #endif
778   to->start_op = to->opcodes;
779   to->current_brk_cont = 0xffffffff;
780   to->backpatch_count  = 0;
781   to->done_pass_two    = 1;
782   to->refcount = emalloc(sizeof(*to->refcount));
783    *to->refcount=1;
784   return to;
785 }
786
787
788 #ifdef ZEND_ENGINE_2
789 static zend_property_info* decode_property_info(zend_property_info* to, char** p, unsigned int* l TSRMLS_DC) {
790   if (to == NULL) {
791     to = emalloc(sizeof(zend_property_info));
792   }
793   to->flags = decode32(p, l);
794   to->name = decode_lstr((unsigned int*)&to->name_length, p, l);
795   return to;
796 }
797 #endif
798
799 static zend_class_entry* decode_class_entry(zend_class_entry* to, char** p, unsigned int* l TSRMLS_DC) {
800   char c;
801   zend_class_entry* old;
802   char*             s;
803   unsigned int      len;
804
805   c = decode(p, l);
806   if (c == ZEND_USER_CLASS) {
807     if (to == NULL) {
808       to = emalloc(sizeof(zend_class_entry));
809     }
810     memset(to, 0, sizeof(zend_class_entry));
811   } else {
812     zend_bailout();
813   }
814   to->type = c;
815   to->name = decode_lstr(&to->name_length, p ,l);
816 #ifdef ZEND_ENGINE_2
817   to->ce_flags = decode32(p ,l);
818   to->num_interfaces = decode32(p, l);
819   if (to->num_interfaces > 0) {
820     to->interfaces = (zend_class_entry **) emalloc(sizeof(zend_class_entry *)*to->num_interfaces);
821   } else {
822     to->interfaces = NULL;
823   }
824   to->create_object = NULL;
825 #endif
826
827   to->parent      = NULL;
828   s = decode_lstr(&len, p, l);
829   if (s != NULL) {
830     if (zend_hash_find(CG(class_table), s, len+1, (void **)&to->parent) != SUCCESS) {
831 /*???
832       debug_printf("[%d] EACCELERATOR can't restore parent class "
833           "\"%s\" of class \"%s\"\n", getpid(), s, to->name);
834 */
835       to->parent = NULL;
836     } else {
837 #ifdef ZEND_ENGINE_2
838           /*
839            * HOESH: See restore_class_entry() on details.
840            */
841           to->parent = *(zend_class_entry**)to->parent;
842           to->constructor  = to->parent->constructor;
843           to->destructor  = to->parent->destructor;
844           to->clone  = to->parent->clone;
845           to->__get  = to->parent->__get;
846       to->__set  = to->parent->__set;
847       to->__call = to->parent->__call;
848           to->create_object = to->parent->create_object;
849 #else
850           to->handle_property_get  = to->parent->handle_property_get;
851       to->handle_property_set  = to->parent->handle_property_set;
852       to->handle_function_call = to->parent->handle_function_call;
853 #endif
854     }
855     efree(s);
856   }
857
858   old = MMCG(class_entry);
859   MMCG(class_entry) = to;
860
861 #ifdef ZEND_ENGINE_2
862   to->refcount = 1;
863
864 #if MMC_ENCODER_VERSION < 2
865   to->line_start = decode32(p, l);
866   to->line_end = decode32(p, l);
867   to->filename = decode_filename(p, l TSRMLS_CC);
868 #else
869   if (((loader_data*)MMCG(mem))->version < 2) {
870     to->line_start = decode32(p, l);
871     to->line_end = decode32(p, l);
872     to->filename = decode_zstr(p, l);
873     efree(to->filename);
874   }
875   to->line_start = ((loader_data*)MMCG(mem))->lineno;
876   to->line_end = ((loader_data*)MMCG(mem))->lineno;
877   to->filename = ((loader_data*)MMCG(mem))->filename;
878 #endif
879   to->doc_comment = decode_lstr(&to->doc_comment_len, p, l);
880
881   zend_hash_init(&to->constants_table, 0, NULL, ZVAL_PTR_DTOR, 0);
882   decode_zval_hash(&to->constants_table, p, l);
883
884   zend_hash_init(&to->default_properties, 0, NULL, ZVAL_PTR_DTOR, 0);
885   decode_zval_hash(&to->default_properties, p, l);
886
887 /*???FIXME
888   zend_hash_init_ex(&to->properties_info, 0, NULL, (dtor_func_t)zend_destroy_property_info, 0, 0);
889 */
890   zend_hash_init_ex(&to->properties_info, 0, NULL, (dtor_func_t)NULL, 0, 0);
891   decode_hash(&to->properties_info, sizeof(zend_property_info), (decode_bucket_t)decode_property_info, p, l TSRMLS_CC);
892
893   ALLOC_HASHTABLE(to->static_members);
894   zend_hash_init_ex(to->static_members, 0, NULL, ZVAL_PTR_DTOR, 0, 0);
895   decode_zval_hash(to->static_members, p, l);
896
897   {
898     Bucket *q = to->properties_info.pListHead;
899     while (q != NULL) {
900       zend_property_info* x = (zend_property_info*)q->pData;
901       Bucket * y = NULL;
902       if ((x->flags & ZEND_ACC_STATIC) && to->static_members != NULL && to->static_members->nNumOfElements > 0) {
903         y = to->static_members->pListHead;
904       } else if ((x->flags & ZEND_ACC_STATIC) == 0 && to->default_properties.nNumOfElements > 0) {
905         y = to->default_properties.pListHead;
906       }
907       while (y != NULL) {
908         if ((int)y->nKeyLength == x->name_length+1 &&
909              memcmp(y->arKey, x->name, x->name_length+1) == 0) {
910           x->h = y->h;
911           break;
912         }
913         y = y->pListNext;
914       }
915       q = q->pListNext;
916     }
917   }
918
919 #else
920   to->refcount = emalloc(sizeof(*to->refcount));
921   *to->refcount = 1;
922
923   zend_hash_init(&to->default_properties, 0, NULL, ZVAL_PTR_DTOR, 0);
924   decode_zval_hash_noref(&to->default_properties, p, l);
925 #endif
926   zend_hash_init(&to->function_table, 0, NULL, ZEND_FUNCTION_DTOR, 0);
927   decode_hash(&to->function_table, sizeof(zend_op_array), (decode_bucket_t)decode_op_array, p, l TSRMLS_CC);
928   to->constants_updated = 0;
929
930   MMCG(class_entry) = old;
931
932   return to;
933 }
934
935 zend_op_array* eaccelerator_load(char* src, int src_len TSRMLS_DC) {
936   zval func;
937   zval gzstring;
938   zval retval;
939   zval param;
940   zval *params[1];
941   zend_op_array* to = NULL;
942   zend_bool error_reported = 0;
943
944   if (!zend_hash_exists(EG(function_table), "gzuncompress", sizeof("gzuncompress"))) {
945     zend_error(E_ERROR, "Turck MMCache Loader requires php_zlib extension\n");
946     return NULL;
947   }
948
949   ZVAL_STRING(&func, "base64_decode", 0);
950   INIT_ZVAL(param);
951   params[0] = &param;
952   ZVAL_STRINGL(params[0], src, src_len, 0);
953   if (call_user_function(CG(function_table), (zval**)NULL, &func, &gzstring, 1, params TSRMLS_CC) == SUCCESS &&
954       gzstring.type == IS_STRING) {
955     ZVAL_STRING(&func, "gzuncompress", 0);
956     params[0] = &gzstring;
957     if (call_user_function(CG(function_table), (zval**)NULL, &func, &retval, 1, params TSRMLS_CC) == SUCCESS &&
958         retval.type == IS_STRING) {
959       zend_bool old_in_compilation = CG(in_compilation);
960       zend_bool old_in_execution   = EG(in_execution);
961       zval_dtor(&gzstring);
962       zend_try {
963         char*        p = retval.value.str.val;
964         unsigned int l = retval.value.str.len;
965         char *s;
966         unsigned char c;
967         unsigned int  v;
968
969         s = decode_zstr_noalloc(&p, &l);
970         if (s != NULL && strcmp(s,"EACCELERATOR") == 0) {
971           v = decode32(&p, &l);
972           if (v <= MMC_ENCODER_VERSION) {
973             loader_data data;
974             data.version  = v;
975             data.filename = NULL;
976             data.lineno = 0;
977             MMCG(mem) = (char*)&data;
978             c = decode(&p, &l);
979 #ifdef ZEND_ENGINE_2
980             if (c == 2) {
981 #else
982             if (c == 1) {
983 #endif
984               MMCG(class_entry) = NULL;
985 #if MMC_ENCODER_VERSION > 1
986               if (CG(in_compilation)) {
987                 data.filename = CG(compiled_filename);
988                 data.lineno = 0;
989               } else {
990                 char* old = CG(compiled_filename);
991                 if (EG(active_op_array && EG(active_op_array)->filename)) {
992                   data.filename = zend_set_compiled_filename(EG(active_op_array)->filename TSRMLS_CC);
993                 }
994                 CG(compiled_filename) = old;
995                 data.lineno = zend_get_executed_lineno(TSRMLS_C);
996               }
997 #endif
998               while (1) {
999                 c = decode(&p, &l);
1000                 if (c == MMC_ENCODER_CLASS) {
1001 #ifdef ZEND_ENGINE_2
1002                   zend_class_entry* x;
1003                   s = decode_lstr_noalloc(&v, &p, &l);
1004                   x = decode_class_entry(NULL, &p, &l TSRMLS_CC);
1005 #else
1006                   zend_class_entry x;
1007                   s = decode_lstr_noalloc(&v, &p, &l);
1008                   decode_class_entry(&x, &p, &l TSRMLS_CC);
1009 #endif
1010                   if ((s[0] == '\000') &&
1011                       zend_hash_exists(CG(class_table), s, v)) {
1012 #ifdef ZEND_ENGINE_2
1013                   } else if (zend_hash_add(CG(class_table), s, v,
1014                       &x, sizeof(zend_class_entry*), NULL) == FAILURE) {
1015 #else
1016                   } else if (zend_hash_add(CG(class_table), s, v,
1017                       &x, sizeof(zend_class_entry), NULL) == FAILURE) {
1018 #endif
1019                     error_reported = 1;
1020                     zend_error(E_ERROR, "Cannot redeclare class %s", s);
1021                   }
1022                 } else if (c == MMC_ENCODER_END) {
1023                   break;
1024                 } else {
1025                   zend_bailout();
1026                 }
1027               }
1028               while (1) {
1029                 c = decode(&p, &l);
1030                 if (c == MMC_ENCODER_FUNCTION) {
1031                   zend_op_array x;
1032                   s = decode_lstr_noalloc(&v, &p, &l);
1033                   decode_op_array(&x, &p, &l TSRMLS_CC);
1034                   if ((s[0] == '\000') &&
1035                       zend_hash_exists(CG(function_table), s, v)) {
1036                   } else if (zend_hash_add(CG(function_table), s, v,
1037                              &x, sizeof(zend_op_array), NULL) == FAILURE) {
1038                     error_reported = 1;
1039                     zend_error(E_ERROR, "Cannot redeclare %s()", s);
1040                   }
1041                 } else if (c == MMC_ENCODER_END) {
1042                   break;
1043                 } else {
1044                   zend_bailout();
1045                 }
1046               }
1047               to = decode_op_array(NULL, &p, &l TSRMLS_CC);
1048               if (l != 0) {
1049                 zend_bailout();
1050               }
1051             } else {
1052               error_reported = 1;
1053               zend_error(E_ERROR, "MMCache Loader can't load code. Icorrect Zend Engine version");
1054             }
1055           } else {
1056             error_reported = 1;
1057             zend_error(E_ERROR, "MMCache Loader can't load code. Icorrect MMCache encoder version (%u)", v);
1058           }
1059         } else {
1060           error_reported = 1;
1061           zend_error(E_ERROR, "MMCache Loader can't load code. Icorrect code");
1062         }
1063       } zend_catch {
1064         CG(in_compilation) = old_in_compilation;
1065         EG(in_execution)   = old_in_execution;
1066         to = NULL;
1067       } zend_end_try();
1068       zval_dtor(&retval);
1069     }
1070   }
1071   if (to == NULL) {
1072     if (error_reported) {
1073       zend_bailout();
1074     } else {
1075       zend_error(E_ERROR, "MMCache Loader can't load code. Icorrect code");
1076     }
1077   }
1078   return to;
1079 }
1080
1081 PHP_FUNCTION(eaccelerator_load) {
1082   char *src;
1083   int   src_len;
1084   zend_op_array* op_array;
1085
1086   if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
1087     "s", &src, &src_len) == FAILURE) {
1088     RETURN_FALSE;
1089   }
1090   if ((op_array = eaccelerator_load(src, src_len TSRMLS_CC)) != NULL) {
1091     zval *local_retval_ptr=NULL;
1092     zend_function_state *original_function_state_ptr = EG(function_state_ptr);
1093     zval **original_return_value = EG(return_value_ptr_ptr);
1094     zend_op_array *original_op_array = EG(active_op_array);
1095     zend_op **original_opline_ptr = EG(opline_ptr);
1096
1097     EG(return_value_ptr_ptr) = &local_retval_ptr;
1098     EG(active_op_array) = op_array;
1099
1100     zend_execute(op_array TSRMLS_CC);
1101
1102     if (local_retval_ptr) {
1103       if (return_value != NULL) {
1104         COPY_PZVAL_TO_ZVAL(*return_value, local_retval_ptr);
1105       } else {
1106         zval_ptr_dtor(&local_retval_ptr);
1107       }
1108     } else if (return_value) {
1109       INIT_ZVAL(*return_value);
1110     }
1111
1112 #ifdef ZEND_ENGINE_2
1113     destroy_op_array(op_array TSRMLS_CC);
1114 #else
1115     destroy_op_array(op_array);
1116 #endif
1117     efree(op_array);
1118
1119     EG(active_op_array) = original_op_array;
1120     EG(return_value_ptr_ptr)=original_return_value;
1121     EG(opline_ptr) = original_opline_ptr;
1122     EG(function_state_ptr) = original_function_state_ptr;
1123
1124     return;
1125   }
1126   RETURN_FALSE;
1127 }
1128
1129 PHP_FUNCTION(_eaccelerator_loader_file) {
1130   if (EG(active_op_array) && EG(active_op_array)->filename) {
1131     RETURN_STRING(EG(active_op_array)->filename, 1);
1132   } else {
1133   &n