root/eaccelerator/tags/0.9.2a/loader.c

Revision 50, 34.4 kB (checked in by everaldo_canuto, 4 years ago)

Some updates mmcache -> eaccelerator.

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