Index: /eaccelerator/trunk/eaccelerator.php
===================================================================
--- /eaccelerator/trunk/eaccelerator.php	(revision 4)
+++ /eaccelerator/trunk/eaccelerator.php	(revision 4)
@@ -0,0 +1,7 @@
+<?php
+if (function_exists("eaccelerator")) {
+  eaccelerator();
+} else {
+  echo "<html><head><title>eAccelerator</title></head><body><h1 align=\"center\">eAccelerator is not installed</h1></body></html>";
+}
+?>
Index: /eaccelerator/trunk/eaccelerator.h
===================================================================
--- /eaccelerator/trunk/eaccelerator.h	(revision 4)
+++ /eaccelerator/trunk/eaccelerator.h	(revision 4)
@@ -0,0 +1,187 @@
+/*
+   +----------------------------------------------------------------------+
+   | Turck MMCache for PHP Version 4                                      |
+   +----------------------------------------------------------------------+
+   | Copyright (c) 2002-2003 TurckSoft, St. Petersburg                    |
+   | http://www.turcksoft.com                                             |
+   +----------------------------------------------------------------------+
+   | This program is free software; you can redistribute it and/or        |
+   | modify it under the terms of the GNU General Public License          |
+   | as published by the Free Software Foundation; either version 2       |
+   | of the License, or (at your option) any later version.               |
+   |                                                                      |
+   | This program is distributed in the hope that it will be useful,      |
+   | but WITHOUT ANY WARRANTY; without even the implied warranty of       |
+   | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        |
+   | GNU General Public License for more details.                         |
+   |                                                                      |
+   | You should have received a copy of the GNU General Public License    |
+   | along with this program; if not, write to the Free Software          |
+   | Foundation, Inc., 59 Temple Place - Suite 330, Boston,               |
+   | MA  02111-1307, USA.                                                 |
+   |                                                                      |
+   | A copy is availble at http://www.gnu.org/copyleft/gpl.txt            |
+   +----------------------------------------------------------------------+
+   | Author: Dmitry Stogov <mmcache@turckware.ru>                         |
+   +----------------------------------------------------------------------+
+   $Id$
+*/
+
+#ifndef INCLUDED_EACCELERATOR_H
+#define INCLUDED_EACCELERATOR_H
+
+#include "php.h"
+#include "zend.h"
+#include "zend_API.h"
+#include "zend_extensions.h"
+
+#ifndef ZEND_WIN32
+#  if ZEND_MODULE_API_NO >= 20001222
+#    include "config.h"
+#  else
+#    include "php_config.h"
+#  endif
+#endif
+
+#ifndef ZEND_WIN32
+/* UnDefine if your filesystem doesn't support inodes */
+#  define EACCELERATOR_USE_INODE
+#endif
+
+/* Define some of the following macros if you like to debug eAccelerator */
+/*#define DEBUG*/
+/*#define TEST_PERFORMANCE*/
+/*#define PROFILE_OPCODES*/
+
+#ifdef WITH_EACCELERATOR_CRASH_DETECTION
+#  include <signal.h>
+#endif
+
+#if defined(DEBUG) || defined(TEST_PERFORMANCE)  || defined(PROFILE_OPCODES)
+/* Here you can chage debuging log filename */
+#define DEBUG_LOGFILE     "/var/log/httpd/eaccelerator_log"
+#define DEBUG_LOGFILE_CGI "/tmp/eaccelerator_log"
+#endif
+
+#define EACCELERATOR_MM_FILE "/tmp/eaccelerator"
+
+#ifdef HAVE_EACCELERATOR
+/*
+ * Where to cache
+ */
+typedef enum _eaccelerator_cache_place {
+  eaccelerator_shm_and_disk, /* in shm and in disk */
+  eaccelerator_shm,          /* in shm, but if it is not possible then on disk */
+  eaccelerator_shm_only,     /* in shm only  */
+  eaccelerator_disk_only,    /* on disk only */
+  eaccelerator_none          /* don't cache  */
+} eaccelerator_cache_place;
+
+extern eaccelerator_cache_place eaccelerator_content_cache_place;
+
+unsigned int eaccelerator_crc32(const char *p, size_t n);
+int eaccelerator_put(const char* key, int key_len, zval* val, time_t ttl, eaccelerator_cache_place where TSRMLS_DC);
+int eaccelerator_get(const char* key, int key_len, zval* return_value, eaccelerator_cache_place where  TSRMLS_DC);
+int eaccelerator_rm(const char* key, int key_len, eaccelerator_cache_place where  TSRMLS_DC);
+size_t eaccelerator_gc(TSRMLS_D);
+#  ifdef WITH_EACCELERATOR_EXECUTOR
+ZEND_DLEXPORT void eaccelerator_execute(zend_op_array *op_array TSRMLS_DC);
+#  endif
+#  ifdef WITH_EACCELERATOR_OPTIMIZER
+void eaccelerator_optimize(zend_op_array *op_array);
+#  endif
+#ifdef WITH_EACCELERATOR_ENCODER
+PHP_FUNCTION(eaccelerator_encode);
+#endif
+#ifdef WITH_EACCELERATOR_LOADER
+zend_op_array* eaccelerator_load(char* src, int src_len TSRMLS_DC);
+PHP_FUNCTION(eaccelerator_load);
+PHP_FUNCTION(_eaccelerator_loader_file);
+PHP_FUNCTION(_eaccelerator_loader_line);
+#endif
+#ifdef WITH_EACCELERATOR_CONTENT_CACHING
+void eaccelerator_content_cache_startup();
+void eaccelerator_content_cache_shutdown();
+
+PHP_FUNCTION(_eaccelerator_output_handler);
+PHP_FUNCTION(eaccelerator_cache_page);
+PHP_FUNCTION(eaccelerator_rm_page);
+PHP_FUNCTION(eaccelerator_cache_output);
+PHP_FUNCTION(eaccelerator_cache_result);
+#endif
+#endif
+
+/*
+ * conditional filter
+ */
+typedef struct _mm_cond_entry {
+  char     *str;
+  int       len;
+  zend_bool not;
+  struct  _mm_cond_entry  *next;
+} mm_cond_entry;
+
+/*
+ * Globals (different for each process/thread)
+ */
+ZEND_BEGIN_MODULE_GLOBALS(eaccelerator)
+  void          *used_entries;     /* list of files which are used     */
+                                   /* by process/thread                */
+  zend_bool     enabled;
+  zend_bool     optimizer_enabled;
+  zend_bool     compression_enabled;
+  zend_bool     compiler;
+  zend_bool     encoder;
+  zend_bool     compress;
+  zend_bool     compress_content;
+  zend_bool     in_request;
+  zend_llist*   content_headers;
+  long          compress_level;
+  char          *cache_dir;
+  char          *mem;
+  HashTable     strings;
+  zend_class_entry *class_entry;
+  mm_cond_entry *cond_list;
+  zend_uint      refcount_helper;
+  char          hostname[32];
+#ifdef WITH_EACCELERATOR_CRASH_DETECTION
+#ifdef SIGSEGV
+  void (*original_sigsegv_handler)(int);
+#endif
+#ifdef SIGFPE
+  void (*original_sigfpe_handler)(int);
+#endif
+#ifdef SIGBUS
+  void (*original_sigbus_handler)(int);
+#endif
+#ifdef SIGILL
+  void (*original_sigill_handler)(int);
+#endif
+#ifdef SIGABRT
+  void (*original_sigabrt_handler)(int);
+#endif
+#endif
+#if defined(DEBUG) || defined(TEST_PERFORMANCE)  || defined(PROFILE_OPCODES)
+  int  xpad;
+#endif
+#ifdef WITH_EACCELERATOR_SESSIONS
+  char *session;
+#endif
+#ifdef PROFILE_OPCODES
+  int  profile_level;
+  long self_time[256];
+#endif
+ZEND_END_MODULE_GLOBALS(eaccelerator)
+
+ZEND_EXTERN_MODULE_GLOBALS(eaccelerator)
+
+#ifdef ZTS
+#  define MMCG(v) TSRMG(eaccelerator_globals_id, zend_eaccelerator_globals*, v)
+#else
+#  define MMCG(v) (eaccelerator_globals.v)
+#endif
+
+#define EACCELERATOR_EXTENSION_NAME "eAccelerator"
+#define EACCELERATOR_LOADER_EXTENSION_NAME "Turck Loader"
+
+#endif /*#ifndef INCLUDED_EACCELERATOR_H*/
Index: /eaccelerator/trunk/optimize.c
===================================================================
--- /eaccelerator/trunk/optimize.c	(revision 4)
+++ /eaccelerator/trunk/optimize.c	(revision 4)
@@ -0,0 +1,3273 @@
+/*
+   +----------------------------------------------------------------------+
+   | Turck MMCache for PHP Version 4                                      |
+   +----------------------------------------------------------------------+
+   | Copyright (c) 2002-2003 TurckSoft, St. Petersburg                    |
+   | http://www.turcksoft.com                                             |
+   +----------------------------------------------------------------------+
+   | This program is free software; you can redistribute it and/or        |
+   | modify it under the terms of the GNU General Public License          |
+   | as published by the Free Software Foundation; either version 2       |
+   | of the License, or (at your option) any later version.               |
+   |                                                                      |
+   | This program is distributed in the hope that it will be useful,      |
+   | but WITHOUT ANY WARRANTY; without even the implied warranty of       |
+   | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        |
+   | GNU General Public License for more details.                         |
+   |                                                                      |
+   | You should have received a copy of the GNU General Public License    |
+   | along with this program; if not, write to the Free Software          |
+   | Foundation, Inc., 59 Temple Place - Suite 330, Boston,               |
+   | MA  02111-1307, USA.                                                 |
+   |                                                                      |
+   | A copy is availble at http://www.gnu.org/copyleft/gpl.txt            |
+   +----------------------------------------------------------------------+
+   | Author: Dmitry Stogov <mmcache@turckware.ru>                         |
+   +----------------------------------------------------------------------+
+   $Id$
+*/
+
+#include "eaccelerator.h"
+
+#ifdef HAVE_EACCELERATOR
+#ifdef WITH_EACCELERATOR_OPTIMIZER
+
+#include "zend.h"
+#include "zend_API.h"
+#include "zend_constants.h"
+#include "opcodes.h"
+
+typedef unsigned int* set;
+
+struct _BBlink;
+
+typedef struct _BB {
+  zend_op*        start;
+  int             len;
+  int             used;
+  /*
+   * HOESH: To protect merging. Primary
+   * it abblies to try & catch blocks.
+   * ZEND_ENGINE_2 specific, but can take place
+   */
+  int             protect_merge;
+  struct _BB*     jmp_1;
+  struct _BB*     jmp_2;
+  struct _BB*     jmp_ext;
+  struct _BB*     follow;
+  struct _BBlink* pred;  // Gonna be a chain of BBs
+  struct _BB*     next;
+} BB;
+
+typedef struct _BBlink {
+  struct _BB*     bb;
+  struct _BBlink* next;
+} BBlink;
+
+#if 0
+static void dump_bb(BB* bb, zend_op_array *op_array) {
+  BB* p = bb;
+  BBlink *q;
+  zend_printf("<pre>%s:%s\n", op_array->filename, op_array->function_name);
+  while (p != NULL) {
+    zend_printf("  bb%u start=%u len=%d used=%d\n",
+                 (unsigned int)(p-bb),
+                 (unsigned int)(p->start-op_array->opcodes),
+                 p->len,
+                 p->used);
+    if (p->jmp_1) {
+      zend_printf("    jmp_1 bb%u start=%u  len=%d used=%d\n",
+                  (unsigned int)(p->jmp_1-bb),
+                  (unsigned int)(p->jmp_1->start-op_array->opcodes),
+                  p->jmp_1->len,
+                  p->jmp_1->used);
+    }
+    if (p->jmp_2) {
+      zend_printf("    jmp_2 bb%u start=%u  len=%d used=%d\n",
+                  (unsigned int)(p->jmp_2-bb),
+                  (unsigned int)(p->jmp_2->start-op_array->opcodes),
+                  p->jmp_2->len,
+                  p->jmp_2->used);
+    }
+    if (p->jmp_ext) {
+      zend_printf("    jmp_ext bb%u start=%u  len=%d used=%d\n",
+                  (unsigned int)(p->jmp_ext-bb),
+                  (unsigned int)(p->jmp_ext->start-op_array->opcodes),
+                  p->jmp_ext->len,
+                  p->jmp_ext->used);
+    }
+    if (p->follow) {
+      zend_printf("    follow bb%u start=%u  len=%d used=%d\n",
+                  (unsigned int)(p->follow-bb),
+                  (unsigned int)(p->follow->start-op_array->opcodes),
+                  p->follow->len,
+                  p->follow->used);
+    }
+    q = p->pred;
+    while (q != NULL) {
+      zend_printf("    pred bb%u start=%u  len=%d used=%d (",
+                  (unsigned int)(q->bb-bb),
+                  (unsigned int)(q->bb->start-op_array->opcodes),
+                  q->bb->len,
+                  q->bb->used);
+      if (q->bb->jmp_1 == p) {
+        zend_printf("jmp_1 ");
+      }
+      if (q->bb->jmp_2 == p) {
+        zend_printf("jmp_2 ");
+      }
+      if (q->bb->jmp_ext == p) {
+        zend_printf("jmp_ext ");
+      }
+      if (q->bb->follow == p) {
+        zend_printf("follow ");
+      }
+      zend_printf(")\n");
+      q = q->next;
+    }
+    p = p->next;
+  }
+  zend_printf("</pre><hr>\n");
+  fflush(stdout);
+}
+#endif
+
+#define SET_TO_NOP(op) \
+  (op)->opcode = ZEND_NOP; \
+  (op)->op1.op_type = IS_UNUSED; \
+  (op)->op2.op_type = IS_UNUSED; \
+  (op)->result.op_type = IS_UNUSED;
+
+static void compute_live_var(BB* bb, zend_op_array* op_array, char* global)
+{
+  BB* p = bb;
+  memset(global, 0, op_array->T * sizeof(char));
+  if (p != NULL && p->next != NULL) {
+    int bb_count = 0;
+    char *def     = do_alloca(op_array->T * sizeof(char));
+#if 0
+    zend_printf("<hr>%s::%s<br>", op_array->filename, op_array->function_name);
+#endif
+    while (p != NULL) {
+      zend_op* op = p->start;
+      zend_op* end = op + p->len;
+      memset(def, 0, op_array->T * sizeof(char));
+      while (op < end) {
+        if ((op->op1.op_type == IS_VAR || op->op1.op_type == IS_TMP_VAR) &&
+            !def[VAR_NUM(op->op1.u.var)] && !global[VAR_NUM(op->op1.u.var)]) {
+          global[VAR_NUM(op->op1.u.var)] = 1;
+        }
+        if ((op->op2.op_type == IS_VAR || op->op2.op_type == IS_TMP_VAR) &&
+            !def[VAR_NUM(op->op2.u.var)] && !global[VAR_NUM(op->op2.u.var)]) {
+#ifdef ZEND_ENGINE_2
+          if (op->opcode != ZEND_OP_DATA) {
+            global[VAR_NUM(op->op2.u.var)] = 1;
+          }
+#else
+          global[VAR_NUM(op->op2.u.var)] = 1;
+#endif
+        }
+#ifdef ZEND_ENGINE_2
+        if (op->opcode == ZEND_DECLARE_INHERITED_CLASS &&
+            !def[VAR_NUM(op->extended_value)] &&
+            !global[VAR_NUM(op->extended_value)]) {
+          global[VAR_NUM(op->extended_value)] = 1;
+        }
+#endif
+        if ((op->result.op_type == IS_VAR &&
+#ifdef ZEND_ENGINE_2
+             (op->opcode == ZEND_RECV || op->opcode == ZEND_RECV_INIT ||
+              (op->result.u.EA.type & EXT_TYPE_UNUSED) == 0)) ||
+#else
+             (op->result.u.EA.type & EXT_TYPE_UNUSED) == 0) ||
+#endif
+            (op->result.op_type == IS_TMP_VAR)) {
+          if (!def[VAR_NUM(op->result.u.var)] && !global[VAR_NUM(op->result.u.var)]) {
+            switch (op->opcode) {
+              case ZEND_RECV:
+              case ZEND_RECV_INIT:
+              case ZEND_ADD_ARRAY_ELEMENT:
+                global[VAR_NUM(op->result.u.var)] = 1;
+             }
+          }
+          def[VAR_NUM(op->result.u.var)] = 1;
+        }
+        op++;
+      }
+      p = p->next;
+      bb_count++;
+    }
+    free_alloca(def);
+  }
+  {
+    char *used = do_alloca(op_array->T * sizeof(char));
+    p = bb;
+    while (p != NULL) {
+      zend_op* op = p->start;
+      zend_op* end = op + p->len;
+      memset(used, 0, op_array->T * sizeof(char));
+      while (op < end) {
+        end--;
+        if (((end->result.op_type == IS_VAR &&
+#ifdef ZEND_ENGINE_2
+             (end->opcode == ZEND_RECV || end->opcode == ZEND_RECV_INIT ||
+              (end->result.u.EA.type & EXT_TYPE_UNUSED) == 0)) ||
+#else
+             (end->result.u.EA.type & EXT_TYPE_UNUSED) == 0) ||
+#endif
+             (end->result.op_type == IS_TMP_VAR)) &&
+            !global[VAR_NUM(end->result.u.var)] && !used[VAR_NUM(end->result.u.var)]) {
+           switch(end->opcode) {
+             case ZEND_JMPZ_EX:
+               end->opcode = ZEND_JMPZ;
+               end->result.op_type = IS_UNUSED;
+               break;
+             case ZEND_JMPNZ_EX:
+               end->opcode = ZEND_JMPNZ;
+               end->result.op_type = IS_UNUSED;
+               break;
+             case ZEND_ASSIGN_ADD:
+             case ZEND_ASSIGN_SUB:
+             case ZEND_ASSIGN_MUL:
+             case ZEND_ASSIGN_DIV:
+             case ZEND_ASSIGN_MOD:
+             case ZEND_ASSIGN_SL:
+             case ZEND_ASSIGN_SR:
+             case ZEND_ASSIGN_CONCAT:
+             case ZEND_ASSIGN_BW_OR:
+             case ZEND_ASSIGN_BW_AND:
+             case ZEND_ASSIGN_BW_XOR:
+             case ZEND_PRE_INC:
+             case ZEND_PRE_DEC:
+             case ZEND_POST_INC:
+             case ZEND_POST_DEC:
+             case ZEND_ASSIGN:
+             case ZEND_ASSIGN_REF:
+             case ZEND_DO_FCALL:
+             case ZEND_DO_FCALL_BY_NAME:
+               if (end->result.op_type == IS_VAR) {
+                 end->result.u.EA.type |= EXT_TYPE_UNUSED;
+               }
+               break;
+             case ZEND_UNSET_VAR:
+             case ZEND_UNSET_DIM_OBJ:
+               end->result.op_type = IS_UNUSED;
+               break;
+             case ZEND_RECV:
+             case ZEND_RECV_INIT:
+             /*case ZEND_ADD_ARRAY_ELEMENT:*/
+             case ZEND_INCLUDE_OR_EVAL:
+             case ZEND_JMP_NO_CTOR:
+             case ZEND_FE_FETCH:
+#ifdef ZEND_ENGINE_2
+             case ZEND_DECLARE_CLASS:
+             case ZEND_DECLARE_INHERITED_CLASS:
+#endif
+              break;
+            default:
+              if (end->op1.op_type == IS_CONST) {
+                zval_dtor(&end->op1.u.constant);
+              }
+              if (end->op2.op_type == IS_CONST) {
+                zval_dtor(&end->op2.u.constant);
+              }
+              SET_TO_NOP(end);
+          }
+        } else if (end->result.op_type == IS_VAR &&
+                   (end->result.u.EA.type & EXT_TYPE_UNUSED) != 0 &&
+#ifdef ZEND_ENGINE_2
+                   end->opcode != ZEND_RECV && end->opcode != ZEND_RECV_INIT &&
+#endif
+                   used[VAR_NUM(end->result.u.var)]) {
+          end->result.u.EA.type &= ~EXT_TYPE_UNUSED;
+        }
+        if ((end->result.op_type == IS_VAR &&
+#ifdef ZEND_ENGINE_2
+            (end->opcode == ZEND_RECV || end->opcode == ZEND_RECV_INIT ||
+             (end->result.u.EA.type & EXT_TYPE_UNUSED) == 0)) ||
+#else
+            (end->result.u.EA.type & EXT_TYPE_UNUSED) == 0) ||
+#endif
+            (end->result.op_type == IS_TMP_VAR)) {
+          switch (end->opcode) {
+            case ZEND_RECV:
+            case ZEND_RECV_INIT:
+            case ZEND_ADD_ARRAY_ELEMENT:
+              used[VAR_NUM(end->result.u.var)] = 1;
+              break;
+            default:
+              used[VAR_NUM(end->result.u.var)] = 0;
+           }
+        }
+        if (end->op1.op_type == IS_VAR || end->op1.op_type == IS_TMP_VAR) {
+          used[VAR_NUM(end->op1.u.var)] = 1;
+        }
+        if (end->op2.op_type == IS_VAR || end->op2.op_type == IS_TMP_VAR) {
+          used[VAR_NUM(end->op2.u.var)] = 1;
+        }
+#ifdef ZEND_ENGINE_2
+        if (end->opcode == ZEND_DECLARE_INHERITED_CLASS) {
+          used[VAR_NUM(end->extended_value)] = 1;
+        }
+#endif
+      }
+      p = p->next;
+    }
+    free_alloca(used);
+  }
+/*
+  while (1) {
+    int change = 0;
+    p = bb;
+    while (p != NULL) {
+      int n = SET_SIZE(op_array->T);
+      while (n-- > 0) {
+        unsigned int old_in = p->in[n];
+        p->out[n] = 0;
+        if (p->jmp_1   != NULL) p->out[n] |= p->jmp_1->in[n];
+        if (p->jmp_2   != NULL) p->out[n] |= p->jmp_2->in[n];
+        if (p->jmp_ext != NULL) p->out[n] |= p->jmp_ext->in[n];
+        if (p->follow  != NULL) p->out[n] |= p->follow->in[n];
+        p->in[n] = p->use[n] | (p->out[n] & ~p->def[n]);
+        if (old_in != p->in[n]) change = 1;
+      }
+      p = p->next;
+    }
+    if (!change) break;
+  }
+*/
+}
+
+/* Adds FROM as predcessor of TO */
+#define BB_ADD_PRED(TO,FROM) { \
+                               BBlink *q = (TO)->pred; \
+                               while (q != NULL) { \
+                                 if (q->bb == (FROM)) break; \
+                                 q = q->next; \
+                               } \
+                               if (q == NULL) { \
+                                 q = emalloc(sizeof(*q)); \
+                                 q->bb = (FROM); \
+                                 q->next = (TO)->pred; \
+                                 (TO)->pred = q; \
+                               } \
+                             }
+
+/* Removes FROM from predcessors of TO */
+#define BB_DEL_PRED(TO,FROM) { \
+                               BBlink *q = (TO)->pred; \
+                               if (q != NULL) { \
+                                 if (q->bb == (FROM)) { \
+                                   (TO)->pred = q->next; \
+                                   efree(q); \
+                                 } else { \
+                                   while (q->next != NULL) { \
+                                     if (q->next->bb == (FROM)) { \
+                                       BBlink *r = q->next; \
+                                       q->next = q->next->next; \
+                                       efree(r); \
+                                       break; \
+                                     } \
+                                     q = q->next; \
+                                   } \
+                                 } \
+                               } \
+                             }
+
+#define RM_BB(p) do {if (p->pred == NULL && p != bb) rm_bb(p);} while (0)
+
+static void mark_used_bb(BB* bb)
+{
+  if (bb->used) return;
+  bb->used = 1;
+  if (bb->jmp_1 != NULL) {
+    mark_used_bb(bb->jmp_1);
+    BB_ADD_PRED(bb->jmp_1, bb);
+  }
+  if (bb->jmp_2 != NULL) {
+    mark_used_bb(bb->jmp_2);
+    BB_ADD_PRED(bb->jmp_2, bb);
+  }
+  if (bb->jmp_ext != NULL) {
+    mark_used_bb(bb->jmp_ext);
+    BB_ADD_PRED(bb->jmp_ext, bb);
+  }
+  if (bb->follow != NULL) {
+    mark_used_bb(bb->follow);
+    BB_ADD_PRED(bb->follow, bb);
+  }
+}
+
+static void mark_used_bb2(BB* bb)
+{
+  if (bb->used) return;
+  bb->used = 1;
+  if (bb->jmp_1 != NULL) {
+    mark_used_bb2(bb->jmp_1);
+  }
+  if (bb->jmp_2 != NULL) {
+    mark_used_bb2(bb->jmp_2);
+  }
+  if (bb->jmp_ext != NULL) {
+    mark_used_bb2(bb->jmp_ext);
+  }
+  if (bb->follow != NULL) {
+    mark_used_bb2(bb->follow);
+  }
+}
+
+static void rm_bb(BB* bb)
+{
+  if (bb->used == 0) {
+    return;
+  }
+  bb->used = 0;
+  if (bb->jmp_1 != NULL) {
+    BB_DEL_PRED(bb->jmp_1, bb);
+  }
+  if (bb->jmp_2 != NULL) {
+    BB_DEL_PRED(bb->jmp_2, bb);
+  }
+  if (bb->jmp_ext != NULL) {
+    BB_DEL_PRED(bb->jmp_ext, bb);
+  }
+  if (bb->follow != NULL) {
+    BB_DEL_PRED(bb->follow, bb);
+  }
+}
+
+static void del_bb(BB* bb)
+{
+  zend_op* op = bb->start;
+  zend_op* end = op + bb->len;
+
+  rm_bb(bb);
+  while (op < end) {
+    --end;
+    if (end->op1.op_type == IS_CONST) {
+      zval_dtor(&end->op1.u.constant);
+    }
+    if (end->op2.op_type == IS_CONST) {
+      zval_dtor(&end->op2.u.constant);
+    }
+    SET_TO_NOP(end);
+  }
+  bb->len  = 0;
+  bb->used = 0;
+}
+
+static void replace_bb(BB* src, BB* dst)
+{
+  BBlink* p = src->pred;
+  while (p != NULL) {
+    BBlink* q = p->next;
+    if (p->bb->jmp_1   == src) {
+      p->bb->jmp_1 = dst;
+      BB_ADD_PRED(dst,p->bb);
+    }
+    if (p->bb->jmp_2   == src) {
+      p->bb->jmp_2 = dst;
+      BB_ADD_PRED(dst,p->bb);
+    }
+    if (p->bb->jmp_ext == src) {
+      p->bb->jmp_ext = dst;
+      BB_ADD_PRED(dst,p->bb);
+    }
+    if (p->bb->follow  == src) {
+      p->bb->follow = dst;
+      BB_ADD_PRED(dst,p->bb);
+    }
+    efree(p);
+    p = q;
+  }
+  src->pred = NULL;
+}
+
+static void optimize_jmp(BB* bb, zend_op_array* op_array)
+{
+  BB* p;
+
+  while(1) {
+    int ok = 1;
+
+    /* Remove Unused Basic Blocks */
+    p = bb;
+    while (p->next != NULL) {
+      if (p->next->used && p->next->pred) {
+        p = p->next;
+      } else {
+        del_bb(p->next);
+        p->next = p->next->next;
+        ok = 0;
+      }
+    }
+
+    /* Clear leading NOP(s) */
+    p = bb;
+    while (p != NULL) {
+      if (p->used) {
+        while (p->len > 0 && p->start->opcode ==ZEND_NOP) {
+          p->start++;
+          p->len--;
+        }
+        if (p->len == 0 && p != bb) {
+          if (p->follow) {
+            replace_bb(p, p->follow);
+          }
+          rm_bb(p);
+          p->used = 0;
+          ok = 0;
+        }
+      }
+      p = p->next;
+    }
+
+    /* JMP optimization */
+    p = bb;
+    while (p != NULL) {
+      while (p->next != NULL && (!p->next->used || p->next->pred == NULL)) {
+        del_bb(p->next);
+        p->next = p->next->next;
+        ok = 0;
+      }
+      if (p->used && p->len > 0) {
+        zend_op* op = &p->start[p->len-1];
+
+        switch (op->opcode) {
+          case ZEND_JMP:
+jmp:
+            /* L1: JMP L1+1  => NOP
+            */
+            if (p->jmp_1 == p->next) {
+              p->follow = p->jmp_1;
+              p->jmp_1   = NULL;
+              SET_TO_NOP(op);
+              --(p->len);
+              ok = 0;
+              break;
+            }
+            /*     JMP L1  =>  JMP L2
+                   ...         ...
+               L1: JMP L2      JMP L2
+            */
+            while (p->jmp_1->len == 1 &&
+                p->jmp_1->start->opcode == ZEND_JMP &&
+                p->jmp_1 != p) {
+              BB* x_p = p->jmp_1;
+              BB_DEL_PRED(p->jmp_1, p);
+              RM_BB(x_p);
+              p->jmp_1 = x_p->jmp_1;
+              BB_ADD_PRED(p->jmp_1, p);
+              ok = 0;
+            }
+            break;
+          case ZEND_JMPZNZ:
+jmp_znz:
+            /* JMPZNZ  ?,L1,L1  =>  JMP L1
+            */
+            if (p->jmp_ext == p->jmp_2) {
+              op->opcode = ZEND_JMP;
+              op->extended_value = 0;
+              op->op1.op_type = IS_UNUSED;
+              op->op2.op_type = IS_UNUSED;
+              p->jmp_1 = p->jmp_2;
+              p->jmp_2 = NULL;
+              p->jmp_ext = NULL;
+              ok = 0;
+              goto jmp;
+            } else if (op->op1.op_type == IS_CONST) {
+              /* JMPZNZ  0,L1,L2  =>  JMP L1
+              */
+              if (!zend_is_true(&op->op1.u.constant)) {
+                op->opcode = ZEND_JMP;
+                op->extended_value = 0;
+                op->op1.op_type = IS_UNUSED;
+                op->op2.op_type = IS_UNUSED;
+                if (p->jmp_ext != p->jmp_2) {
+                  BB_DEL_PRED(p->jmp_ext, p);
+                  RM_BB(p->jmp_ext);
+                }
+                p->jmp_1   = p->jmp_2;
+                p->jmp_2   = NULL;
+                p->jmp_ext = NULL;
+                p->follow  = NULL;
+                ok = 0;
+                goto jmp;
+              /* JMPZNZ  1,L1,L2  =>  JMP L2
+              */
+              } else {
+                op->opcode = ZEND_JMP;
+                op->extended_value = 0;
+                op->op1.op_type = IS_UNUSED;
+                op->op2.op_type = IS_UNUSED;
+                if (p->jmp_ext != p->jmp_2) {
+                  BB_DEL_PRED(p->jmp_2, p);
+                  RM_BB(p->jmp_2);
+                }
+                p->jmp_1   = p->jmp_ext;
+                p->jmp_2   = NULL;
+                p->jmp_ext = NULL;
+                p->follow  = NULL;
+                ok = 0;
+                goto jmp;
+              }
+            /* L1: JMPZNZ ?,L2,L1+1  => JMPZ ?,L2
+            */
+            } else if (p->jmp_ext == p->next) {
+              op->opcode = ZEND_JMPZ;
+              op->extended_value = 0;
+              p->follow = p->jmp_ext;
+              p->jmp_ext = NULL;
+              ok = 0;
+              goto jmp_z;
+            /* L1: JMPZNZ ?,L1+1,L2  => JMPNZ ?,L2
+            */
+            } else if (p->jmp_2 == p->next) {
+              op->opcode = ZEND_JMPNZ;
+              op->extended_value = 0;
+              p->follow = p->jmp_2;
+              p->jmp_2  = p->jmp_ext;
+              p->jmp_ext = NULL;
+              ok = 0;
+              goto jmp_nz;
+            } else if (p->jmp_2->len == 1 &&
+                       op->op1.op_type == IS_TMP_VAR) {
+            /*     JMPZNZ $x,L1,L2  =>  JMPZNZ $x,L3,L2
+                   ...                  ...
+               L1: JMPZ   $x,L3         JMPZ   $x,L3
+            */
+            /*     JMPZNZ $x,L1,L2  =>  JMPZNZ $x,L3,L2
+                   ...                  ...
+               L1: JMPZNZ $x,L3,L4      JMPZNZ $x,L3,L4
+            */
+            if        ((p->jmp_2->start->opcode == ZEND_JMPZ ||
+                        p->jmp_2->start->opcode == ZEND_JMPZNZ) &&
+                       p->jmp_2->start->op1.op_type == IS_TMP_VAR &&
+                       op->op1.u.var == p->jmp_2->start->op1.u.var) {
+              if (p->jmp_2 != p->jmp_ext) {
+                BB_DEL_PRED(p->jmp_2, p);
+                RM_BB(p->jmp_2);
+              }
+              p->jmp_2 = p->jmp_2->jmp_2;
+              BB_ADD_PRED(p->jmp_2, p);
+              ok = 0;
+              goto jmp_znz;
+            /*     JMPZNZ $x,L1,L2  =>  JMPZNZ $x,L1+1,L2
+                   ...                  ...
+               L1: JMPNZ  $x,L3         JMPNZ  $x,L3
+            */
+            } else if (p->jmp_2->start->opcode == ZEND_JMPNZ &&
+                       p->jmp_2->start->op1.op_type == IS_TMP_VAR &&
+                       op->op1.u.var == p->jmp_2->start->op1.u.var) {
+              if (p->jmp_2 != p->jmp_ext) {
+                BB_DEL_PRED(p->jmp_2, p);
+                RM_BB(p->jmp_2);
+              }
+              p->jmp_2 = p->jmp_2->follow;
+              BB_ADD_PRED(p->jmp_2, p);
+              ok = 0;
+              goto jmp_znz;
+            /*     JMPZNZ $x,L1,L2  =>  JMPZNZ $x,L1,L3
+                   ...                  ...
+               L2: JMPNZ  $x,L3         JMPNZ  $x,L3
+            */
+            } else if (p->jmp_ext->start->opcode == ZEND_JMPNZ &&
+                       p->jmp_ext->start->op1.op_type == IS_TMP_VAR &&
+                       op->op1.u.var == p->jmp_ext->start->op1.u.var) {
+              if (p->jmp_2 != p->jmp_ext) {
+                BB_DEL_PRED(p->jmp_ext, p);
+                RM_BB(p->jmp_ext);
+              }
+              p->jmp_ext = p->jmp_ext->jmp_2;
+              BB_ADD_PRED(p->jmp_ext, p);
+              ok = 0;
+              goto jmp_znz;
+            /*     JMPZNZ $x,L1,L2  =>  JMPZNZ $x,L1,L4
+                   ...                  ...
+               L2: JMPZNZ $x,L3,L4      JMPZNZ $x,L3,L4
+            */
+            } else if (p->jmp_ext->start->opcode == ZEND_JMPZNZ &&
+                       p->jmp_ext->start->op1.op_type == IS_TMP_VAR &&
+                       op->op1.u.var == p->jmp_ext->start->op1.u.var) {
+              if (p->jmp_2 != p->jmp_ext) {
+                BB_DEL_PRED(p->jmp_ext, p);
+                RM_BB(p->jmp_ext);
+              }
+              p->jmp_ext = p->jmp_ext->jmp_ext;
+              BB_ADD_PRED(p->jmp_ext, p);
+              ok = 0;
+              goto jmp_znz;
+            /*     JMPZNZ $x,L1,L2  =>  JMPZNZ $x,L1,L2+1
+                   ...                  ...
+               L2: JMPZ   $x,L3         JMPZ   $x,L3
+            */
+            } else if (p->jmp_ext->start->opcode == ZEND_JMPZ &&
+                       p->jmp_ext->start->op1.op_type == IS_TMP_VAR &&
+                       op->op1.u.var == p->jmp_ext->start->op1.u.var) {
+              if (p->jmp_2 != p->jmp_ext) {
+                BB_DEL_PRED(p->jmp_ext, p);
+                RM_BB(p->jmp_ext);
+              }
+              p->jmp_ext = p->jmp_ext->follow;
+              BB_ADD_PRED(p->jmp_ext, p);
+              ok = 0;
+              goto jmp_znz;
+            }
+            }
+            while (p->jmp_2->len == 1 && p->jmp_2->start->opcode == ZEND_JMP) {
+              BB* x_p = p->jmp_2;
+              if (p->jmp_2 != p->jmp_ext) {
+                BB_DEL_PRED(p->jmp_2, p);
+                RM_BB(x_p);
+              }
+              p->jmp_2 = x_p->jmp_1;
+              BB_ADD_PRED(p->jmp_2, p);
+              ok = 0;
+            }
+            while (p->jmp_ext->len == 1 && p->jmp_ext->start->opcode == ZEND_JMP) {
+              BB* x_p = p->jmp_ext;
+              if (p->jmp_2 != p->jmp_ext) {
+                BB_DEL_PRED(p->jmp_ext, p);
+                RM_BB(x_p);
+              }
+              p->jmp_ext = x_p->jmp_1;
+              BB_ADD_PRED(p->jmp_ext, p);
+              ok = 0;
+            }
+            break;
+          case ZEND_JMPZ:
+jmp_z:
+            /* L1: JMPZ  ?,L1+1  =>  NOP
+            */
+            if (p->follow == p->jmp_2) {
+              p->jmp_2   = NULL;
+              SET_TO_NOP(op);
+              --(p->len);
+              ok = 0;
+              break;
+            } else if (op->op1.op_type == IS_CONST) {
+              /* JMPZ  0,L1  =>  JMP L1
+              */
+              if (!zend_is_true(&op->op1.u.constant)) {
+                op->opcode = ZEND_JMP;
+                op->op1.op_type = IS_UNUSED;
+                op->op2.op_type = IS_UNUSED;
+                if (p->follow != p->jmp_2) {
+                  BB_DEL_PRED(p->follow, p);
+                  RM_BB(p->follow);
+                }
+                p->jmp_1  = p->jmp_2;
+                p->jmp_2  = NULL;
+                p->follow = NULL;
+                ok = 0;
+                goto jmp;
+              /* JMPZ  1,L1  =>  NOP
+              */
+              } else {
+                if (p->follow != p->jmp_2) {
+                  BB_DEL_PRED(p->jmp_2, p);
+                  RM_BB(p->jmp_2);
+                }
+                p->jmp_2   = NULL;
+                SET_TO_NOP(op);
+                --(p->len);
+                ok = 0;
+                break;
+              }
+            /* JMPZ ?,L1  =>  JMPZNZ  ?,L1,L2
+               JMP  L2        JMP     L2
+            */
+            } else if (p->follow->len == 1 && p->follow->start->opcode == ZEND_JMP) {
+              BB* x_p = p->follow;
+              op->opcode = ZEND_JMPZNZ;
+              if (p->jmp_2 != p->follow) {
+                BB_DEL_PRED(p->follow, p);
+                RM_BB(x_p);
+              }
+              p->follow = NULL;
+              p->jmp_ext = x_p->jmp_1;
+              BB_ADD_PRED(p->jmp_ext, p);
+              ok = 0;
+              goto jmp_znz;
+            } else if (p->jmp_2->len == 1 &&
+                       op->op1.op_type == IS_TMP_VAR) {
+            /*     JMPZ $x,L1  =>  JMPZ $x,L2
+                   ...             ...
+               L1: JMPZ $x,L2      JMPZ $x,L2
+               ----------------------------------------
+                   JMPZ   $x,L1     =>  JMPZ  $x,L2
+                   ...                   ...
+               L1: JMPZNZ $x,L2,L3      JMPZNZ $x,L2,L3
+            */
+            if       ((p->jmp_2->start->opcode == ZEND_JMPZ ||
+                       p->jmp_2->start->opcode == ZEND_JMPZNZ) &&
+                      p->jmp_2->start->op1.op_type == IS_TMP_VAR &&
+                      op->op1.u.var == p->jmp_2->start->op1.u.var) {
+              if (p->jmp_2 != p->follow) {
+                BB_DEL_PRED(p->jmp_2, p);
+                RM_BB(p->jmp_2);
+              }
+              p->jmp_2 = p->jmp_2->jmp_2;
+              BB_ADD_PRED(p->jmp_2, p);
+              ok = 0;
+              goto jmp_z;
+            /*     JMPZ  $x,L1  =>  JMPZ  $x,L1+1
+                   ...              ...
+               L1: JMPNZ $x,L2      JMPNZ $x,L2
+            */
+            } else if (p->jmp_2->start->opcode == ZEND_JMPNZ &&
+                       p->jmp_2->start->op1.op_type == IS_TMP_VAR &&
+                       op->op1.u.var == p->jmp_2->start->op1.u.var) {
+              if (p->jmp_2 != p->follow) {
+                BB_DEL_PRED(p->jmp_2, p);
+                RM_BB(p->jmp_2);
+              }
+              p->jmp_2 = p->jmp_2->follow;
+              BB_ADD_PRED(p->jmp_2, p);
+              ok = 0;
+              goto jmp_z;
+            }
+            }
+            goto jmp_2;
+          case ZEND_JMPNZ:
+jmp_nz:
+            /* L1: JMPNZ  ?,L1+1  =>  NOP
+            */
+            if (p->follow == p->jmp_2) {
+              p->jmp_2   = NULL;
+              SET_TO_NOP(op);
+              --(p->len);
+              ok = 0;
+              break;
+            } else if (op->op1.op_type == IS_CONST) {
+              /* JMPNZ  1,L1  =>  JMP L1
+              */
+              if (zend_is_true(&op->op1.u.constant)) {
+                op->opcode = ZEND_JMP;
+                op->op1.op_type = IS_UNUSED;
+                op->op2.op_type = IS_UNUSED;
+                if (p->follow != p->jmp_2) {
+                  BB_DEL_PRED(p->follow, p);
+                  RM_BB(p->follow);
+                }
+                p->jmp_1  = p->jmp_2;
+                p->jmp_2  = NULL;
+                p->follow = NULL;
+                ok = 0;
+                goto jmp;
+              /* JMPNZ  0,L1  =>  NOP
+              */
+              } else {
+                if (p->follow != p->jmp_2) {
+                  BB_DEL_PRED(p->jmp_2, p);
+                  RM_BB(p->jmp_2);
+                }
+                p->jmp_2   = NULL;
+                SET_TO_NOP(op);
+                --(p->len);
+                ok = 0;
+                break;
+              }
+            /* JMPNZ ?,L1  =>  JMPZNZ  ?,L2,L1
+               JMP   L2        JMP     L2
+            */
+            } else if (p->follow->len == 1 && p->follow->start->opcode == ZEND_JMP) {
+              BB* x_p = p->follow;
+              op->opcode = ZEND_JMPZNZ;
+              if (p->jmp_2 != p->follow) {
+                BB_DEL_PRED(p->follow, p);
+                RM_BB(p->follow);
+              }
+              p->follow = NULL;
+              p->jmp_ext = p->jmp_2;
+              p->jmp_2 = x_p->jmp_1;
+              BB_ADD_PRED(p->jmp_2, p);
+              ok = 0;
+              goto jmp_znz;
+            /*     JMPNZ $x,L1  =>  JMPNZ $x,L2
+                   ...              ...
+               L1: JMPNZ $x,L2      JMPNZ $x,L2
+            */
+            } else if (p->jmp_2->len == 1 &&
+                       op->op1.op_type == IS_TMP_VAR) {
+            if        (p->jmp_2->start->opcode == ZEND_JMPNZ &&
+                       p->jmp_2->start->op1.op_type == IS_TMP_VAR &&
+                       op->op1.u.var == p->jmp_2->start->op1.u.var) {
+              if (p->jmp_2 != p->follow) {
+                BB_DEL_PRED(p->jmp_2, p);
+                RM_BB(p->jmp_2);
+              }
+              p->jmp_2 = p->jmp_2->jmp_2;
+              BB_ADD_PRED(p->jmp_2, p);
+              ok = 0;
+              goto jmp_nz;
+            /*     JMPNZ  $x,L1  =>  JMPNZ  $x,L1+1
+                   ...               ...
+               L1: JMPZ   $x,L2      JMPZ $x,L2
+            */
+            } else if (p->jmp_2->start->opcode == ZEND_JMPZ &&
+                       p->jmp_2->start->op1.op_type == IS_TMP_VAR &&
+                       op->op1.u.var == p->jmp_2->start->op1.u.var) {
+              if (p->jmp_2 != p->follow) {
+                BB_DEL_PRED(p->jmp_2, p);
+                RM_BB(p->jmp_2);
+              }
+              p->jmp_2 = p->jmp_2->follow;
+              BB_ADD_PRED(p->jmp_2, p);
+              ok = 0;
+              goto jmp_nz;
+            /*     JMPNZ  $x,L1     =>  JMPNZ  $x,L3
+                   ...                   ...
+               L1: JMPZNZ $x,L2,L3      JMPZNZ $x,L2,L3
+            */
+            } else if (p->jmp_2->start->opcode == ZEND_JMPZNZ &&
+                       p->jmp_2->start->op1.op_type == IS_TMP_VAR &&
+                       op->op1.u.var == p->jmp_2->start->op1.u.var) {
+              if (p->jmp_2 != p->follow) {
+                BB_DEL_PRED(p->jmp_2, p);
+                RM_BB(p->jmp_2);
+              }
+              p->jmp_2 = p->jmp_2->jmp_ext;
+              BB_ADD_PRED(p->jmp_2, p);
+              ok = 0;
+              goto jmp_nz;
+            }
+            }
+            goto jmp_2;
+          case ZEND_JMPZ_EX:
+jmp_z_ex:
+            /* L1: JMPZ_EX  $x,L1+1,$x  =>  NOP
+            */
+            if (p->follow == p->jmp_2 &&
+                op->op1.op_type == IS_TMP_VAR &&
+                op->result.op_type == IS_TMP_VAR &&
+                op->op1.u.var == op->result.u.var) {
+              p->jmp_2   = NULL;
+              SET_TO_NOP(op);
+              --(p->len);
+              ok = 0;
+              break;
+            /* L1: JMPZ_EX  $x,L1+1,$y  =>  BOOL $x,$y
+            */
+            } else if (p->follow == p->jmp_2) {
+              p->jmp_2   = NULL;
+              op->opcode = ZEND_BOOL;
+              op->op2.op_type = IS_UNUSED;
+              ok = 0;
+              break;
+            } else if (p->jmp_2->len == 1 &&
+                       op->result.op_type == IS_TMP_VAR) {
+            /*     JMPZ_EX ?,L1,$x  =>  JMPZ_EX ?,L2,$x
+                   ...                  ...
+               L1: JMPZ    $x,L2        JMPZ    $x,L2
+               ------------------------------------------
+                   JMPZ_EX ?,L1,$x  =>  JMPZ_EX ?,L2,$x
+                   ...                  ...
+               L1: JMPZNZ  $x,L2,L3     JMPZNZ  $x,L2,L3
+               ------------------------------------------
+                   JMPZ_EX ?,L1,$x  =>  JMPZ_EX ?,L2,$x
+                   ...                  ...
+               L1: JMPZ_EX $x,L2,$x     JMPZ_EX $x,L2,$x
+            */
+            if       (((p->jmp_2->start->opcode == ZEND_JMPZ ||
+                         p->jmp_2->start->opcode == ZEND_JMPZNZ) &&
+                        p->jmp_2->start->op1.op_type == IS_TMP_VAR &&
+                        op->result.u.var == p->jmp_2->start->op1.u.var) ||
+                       (p->jmp_2->start->opcode == ZEND_JMPZ_EX &&
+                        p->jmp_2->start->op1.op_type == IS_TMP_VAR &&
+                        p->jmp_2->start->result.op_type == IS_TMP_VAR &&
+                        op->result.u.var == p->jmp_2->start->op1.u.var &&
+                        op->result.u.var == p->jmp_2->start->result.u.var)) {
+              if (p->jmp_2 != p->follow) {
+                BB_DEL_PRED(p->jmp_2, p);
+                RM_BB(p->jmp_2);
+              }
+              p->jmp_2 = p->jmp_2->jmp_2;
+              BB_ADD_PRED(p->jmp_2, p);
+              ok = 0;
+              goto jmp_z_ex;
+            /*     JMPZ_EX ?,L1,$x   =>  JMPZ_EX ?,L2+1,$x
+                   ...                   ...
+               L1: JMPNZ    $x,L2        JMPNZ    $x,L2
+               ------------------------------------------
+                   JMPZ_EX ?,L1,$x   =>  JMPZ_EX  ?,L2+1,$x
+                   ...                   ...
+               L1: JMPNZ_EX $x,L2,$x     JMPNZ_EX $x,L2,$x
+            */
+            } else if ((p->jmp_2->start->opcode == ZEND_JMPNZ &&
+                        p->jmp_2->start->op1.op_type == IS_TMP_VAR &&
+                        op->result.u.var == p->jmp_2->start->op1.u.var) ||
+                       (p->jmp_2->start->opcode == ZEND_JMPNZ_EX &&
+                        p->jmp_2->start->op1.op_type == IS_TMP_VAR &&
+                        p->jmp_2->start->result.op_type == IS_TMP_VAR &&
+                        op->result.u.var == p->jmp_2->start->op1.u.var &&
+                        op->result.u.var == p->jmp_2->start->result.u.var)) {
+              if (p->jmp_2 != p->follow) {
+                BB_DEL_PRED(p->jmp_2, p);
+                RM_BB(p->jmp_2);
+              }
+              p->jmp_2 = p->jmp_2->follow;
+              BB_ADD_PRED(p->jmp_2, p);
+              ok = 0;
+              goto jmp_z_ex;
+            /*     JMPZ_EX ?,L1,$x   =>  JMPZ_EX ?,L1+1,$y
+                   ...                   ...
+               L1: BOOL    $x,$y         BOOL    $x,$y
+            */
+            } else if (p->jmp_2->start->opcode == ZEND_BOOL &&
+                       p->jmp_2->start->op1.op_type == IS_TMP_VAR &&
+                       op->result.u.var == p->jmp_2->start->op1.u.var) {
+              memcpy(&op->result, &p->jmp_2->start->result, sizeof(zval));
+              if (p->jmp_2 != p->follow) {
+                BB_DEL_PRED(p->jmp_2, p);
+                RM_BB(p->jmp_2);
+              }
+              p->jmp_2 = p->jmp_2->follow;
+              BB_ADD_PRED(p->jmp_2, p);
+              ok = 0;
+              goto jmp_z_ex;
+            /*     JMPZ_EX ?,L1,$x   =>  JMPZ    ?,L1+1
+                   ...                   ...
+               L1: FREE    $x            FREE    $x
+            */
+            } else if (p->jmp_2->start->opcode == ZEND_FREE &&
+                       p->jmp_2->start->op1.op_type == IS_TMP_VAR &&
+                       op->result.u.var == p->jmp_2->start->op1.u.var) {
+              op->opcode = ZEND_JMPZ;
+              op->result.op_type = IS_UNUSED;
+              if (p->jmp_2 != p->follow) {
+                BB_DEL_PRED(p->jmp_2, p);
+                RM_BB(p->jmp_2);
+              }
+              p->jmp_2 = p->jmp_2->follow;
+              BB_ADD_PRED(p->jmp_2, p);
+              ok = 0;
+              goto jmp_z;
+            }
+            /*     JMPZ_EX ?,L1,$x   =>  JMPZ ?,L1+1
+                   ...                   ...
+               L1: FREE    $x            FREE $x
+            */
+            } else if (op->result.op_type == IS_TMP_VAR &&
+                       p->jmp_2->start->opcode == ZEND_FREE &&
+                       p->jmp_2->start->op1.op_type == IS_TMP_VAR &&
+                       op->result.u.var == p->jmp_2->start->op1.u.var) {
+              if (p->jmp_2->len > 1) {
+                /* splitting */
+                BB* new_bb = (p->jmp_2+1);
+                new_bb->used   = 1;
+                new_bb->start  = p->jmp_2->start+1;
+                new_bb->len    = p->jmp_2->len-1;
+                p->jmp_2->len  = 1;
+                new_bb->next   = p->jmp_2->next;
+                p->jmp_2->next = new_bb;
+                new_bb->pred   = NULL;
+                if (p->jmp_2->jmp_1) {
+                  new_bb->jmp_1     = p->jmp_2->jmp_1;
+                  BB_ADD_PRED(new_bb->jmp_1, new_bb);
+                  BB_DEL_PRED(new_bb->jmp_1, p->jmp_2);
+                  p->jmp_2->jmp_1   = NULL;
+                }
+                if (p->jmp_2->jmp_2) {
+                  new_bb->jmp_2     = p->jmp_2->jmp_2;
+                  BB_ADD_PRED(new_bb->jmp_2, new_bb);
+                  BB_DEL_PRED(new_bb->jmp_2, p->jmp_2);
+                  p->jmp_2->jmp_2   = NULL;
+                }
+                if (p->jmp_2->jmp_ext) {
+                  new_bb->jmp_ext     = p->jmp_2->jmp_ext;
+                  BB_ADD_PRED(new_bb->jmp_ext, new_bb);
+                  BB_DEL_PRED(new_bb->jmp_ext, p->jmp_2);
+                  p->jmp_2->jmp_ext   = NULL;
+                }
+                op->opcode = ZEND_JMPZ;
+                op->result.op_type = IS_UNUSED;
+                if (p->jmp_2->follow) {
+                  new_bb->follow     = p->jmp_2->follow;
+                  BB_ADD_PRED(new_bb->follow, new_bb);
+                  BB_DEL_PRED(new_bb->follow, p->jmp_2);
+                  p->jmp_2->follow   = NULL;
+                }
+                p->jmp_2->follow = new_bb;
+                BB_ADD_PRED(p->jmp_2->follow, p->jmp_2);
+              }
+              if (p->jmp_2 != p->follow) {
+                BB_DEL_PRED(p->jmp_2, p);
+                RM_BB(p->jmp_2);
+              }
+              p->jmp_2 = p->jmp_2->follow;
+              BB_ADD_PRED(p->jmp_2, p);
+              ok = 0;
+              goto jmp_z;
+            }
+            goto jmp_2;
+          case ZEND_JMPNZ_EX:
+jmp_nz_ex:
+            /* L1: JMPNZ_EX  $x,L1+1,$x  =>  NOP
+            */
+            if (p->follow == p->jmp_2 &&
+                op->op1.op_type == IS_TMP_VAR &&
+                op->result.op_type == IS_TMP_VAR &&
+                op->op1.u.var == op->result.u.var) {
+              p->jmp_2   = NULL;
+              SET_TO_NOP(op);
+              --(p->len);
+              ok = 0;
+              break;
+            /* L1: JMPNZ_EX  $x,L1+1,$y  =>  BOOL $x,$y
+            */
+            } else if (p->follow == p->jmp_2) {
+              p->jmp_2   = NULL;
+              op->opcode = ZEND_BOOL;
+              op->op2.op_type = IS_UNUSED;
+              ok = 0;
+              break;
+            } else if (p->jmp_2->len == 1 &&
+                       op->result.op_type == IS_TMP_VAR) {
+            /*     JMPNZ_EX ?,L1,$x  =>  JMPNZ_EX ?,L2,$x
+                   ...                   ...
+               L1: JMPNZ    $x,L2        JMPNZ    $x,L2
+               ------------------------------------------
+                   JMPNZ_EX ?,L1,$x  =>  JMPNZ_EX ?,L2,$x
+                   ...                   ...
+               L1: JMPNZ_EX $x,L2,$x     JMPNZ_EX $x,L2,$x
+            */
+            if        ((p->jmp_2->start->opcode == ZEND_JMPNZ &&
+                        p->jmp_2->start->op1.op_type == IS_TMP_VAR &&
+                        op->result.u.var == p->jmp_2->start->op1.u.var) ||
+                       (p->jmp_2->start->opcode == ZEND_JMPNZ_EX &&
+                        p->jmp_2->start->op1.op_type == IS_TMP_VAR &&
+                        p->jmp_2->start->result.op_type == IS_TMP_VAR &&
+                        op->result.u.var == p->jmp_2->start->op1.u.var &&
+                        op->result.u.var == p->jmp_2->start->result.u.var)) {
+              if (p->jmp_2 != p->follow) {
+                BB_DEL_PRED(p->jmp_2, p);
+                RM_BB(p->jmp_2);
+              }
+              p->jmp_2 = p->jmp_2->jmp_2;
+              BB_ADD_PRED(p->jmp_2, p);
+              ok = 0;
+              goto jmp_nz_ex;
+            /*     JMPNZ_EX ?,L1,$x   =>  JMPNZ_EX ?,L3,$x
+                   ...                    ...
+               L1: JMPZNZ   $x,L2,L3      JMPZNZ   $x,L2,L3
+            */
+            } else if (p->jmp_2->start->opcode == ZEND_JMPZNZ &&
+                       p->jmp_2->start->op1.op_type == IS_TMP_VAR &&
+                       op->result.u.var == p->jmp_2->start->op1.u.var) {
+              if (p->jmp_2 != p->follow) {
+                BB_DEL_PRED(p->jmp_2, p);
+                RM_BB(p->jmp_2);
+              }
+              p->jmp_2 = p->jmp_2->jmp_ext;
+              BB_ADD_PRED(p->jmp_2, p);
+              ok = 0;
+              goto jmp_nz_ex;
+            /*     JMPNZ_EX ?,L1,$x   =>  JMPNZ_EX ?,L1+1,$x
+                   ...                    ...
+               L1: JMPZ    $x,L2          JMPZ    $x,L2
+               ------------------------------------------
+                   JMPNZ_EX ?,L1,$x   =>  JMPNZ_EX  ?,L1+1,$x
+                   ...                    ...
+               L1: JMPZ_EX $x,L2,$x      JMPZ_EX $x,L2,$x
+            */
+            } else if ((p->jmp_2->start->opcode == ZEND_JMPZ &&
+                        p->jmp_2->start->op1.op_type == IS_TMP_VAR &&
+                        op->result.u.var == p->jmp_2->start->op1.u.var) ||
+                       (p->jmp_2->start->opcode == ZEND_JMPZ_EX &&
+                        p->jmp_2->start->op1.op_type == IS_TMP_VAR &&
+                        p->jmp_2->start->result.op_type == IS_TMP_VAR &&
+                        op->result.u.var == p->jmp_2->start->op1.u.var &&
+                        op->result.u.var == p->jmp_2->start->result.u.var)) {
+              if (p->jmp_2 != p->follow) {
+                BB_DEL_PRED(p->jmp_2, p);
+                RM_BB(p->jmp_2);
+              }
+              p->jmp_2 = p->jmp_2->follow;
+              BB_ADD_PRED(p->jmp_2, p);
+              ok = 0;
+              goto jmp_nz_ex;
+            /*     JMPNZ_EX ?,L1,$x   =>  JMPNZ_EX ?,L1+1,$y
+                   ...                   ...
+               L1: BOOL    $x,$y         BOOL    $x,$y
+            */
+            } else if (p->jmp_2->start->opcode == ZEND_BOOL &&
+                       p->jmp_2->start->op1.op_type == IS_TMP_VAR &&
+                       op->result.u.var == p->jmp_2->start->op1.u.var) {
+              memcpy(&op->result, &p->jmp_2->start->result, sizeof(zval));
+              if (p->jmp_2 != p->follow) {
+                BB_DEL_PRED(p->jmp_2, p);
+                RM_BB(p->jmp_2);
+              }
+              p->jmp_2 = p->jmp_2->follow;
+              BB_ADD_PRED(p->jmp_2, p);
+              ok = 0;
+              goto jmp_nz_ex;
+            /*     JMPNZ_EX ?,L1,$x   =>  JMPNZ ?,L1+1
+                   ...                    ...
+               L1: FREE    $x             FREE    $x
+            */
+            } else if (p->jmp_2->start->opcode == ZEND_FREE &&
+                       p->jmp_2->start->op1.op_type == IS_TMP_VAR &&
+                       op->result.u.var == p->jmp_2->start->op1.u.var) {
+              op->opcode = ZEND_JMPNZ;
+              op->result.op_type = IS_UNUSED;
+              if (p->jmp_2 != p->follow) {
+                BB_DEL_PRED(p->jmp_2, p);
+                RM_BB(p->jmp_2);
+              }
+              p->jmp_2 = p->jmp_2->follow;
+              BB_ADD_PRED(p->jmp_2, p);
+              ok = 0;
+              goto jmp_nz;
+            }
+            /*     JMPNZ_EX ?,L1,$x   =>  JMPNZ_EX ?,L1+1,$x
+                   ...                    ...
+               L1: FREE    $x             FREE    $x
+            */
+            } else if (op->result.op_type == IS_TMP_VAR &&
+                       p->jmp_2->start->opcode == ZEND_FREE &&
+                       p->jmp_2->start->op1.op_type == IS_TMP_VAR &&
+                       op->result.u.var == p->jmp_2->start->op1.u.var) {
+              if (p->jmp_2->len > 1) {
+                /* splitting */
+                BB* new_bb = (p->jmp_2+1);
+                new_bb->used   = 1;
+                new_bb->start  = p->jmp_2->start+1;
+                new_bb->len    = p->jmp_2->len-1;
+                p->jmp_2->len  = 1;
+                new_bb->next   = p->jmp_2->next;
+                p->jmp_2->next = new_bb;
+                new_bb->pred   = NULL;
+                if (p->jmp_2->jmp_1) {
+                  new_bb->jmp_1     = p->jmp_2->jmp_1;
+                  BB_ADD_PRED(new_bb->jmp_1, new_bb);
+                  BB_DEL_PRED(new_bb->jmp_1, p->jmp_2);
+                  p->jmp_2->jmp_1   = NULL;
+                }
+                if (p->jmp_2->jmp_2) {
+                  new_bb->jmp_2     = p->jmp_2->jmp_2;
+                  BB_ADD_PRED(new_bb->jmp_2, new_bb);
+                  BB_DEL_PRED(new_bb->jmp_2, p->jmp_2);
+                  p->jmp_2->jmp_2   = NULL;
+                }
+                if (p->jmp_2->jmp_ext) {
+                  new_bb->jmp_ext     = p->jmp_2->jmp_ext;
+                  BB_ADD_PRED(new_bb->jmp_ext, new_bb);
+                  BB_DEL_PRED(new_bb->jmp_ext, p->jmp_2);
+                  p->jmp_2->jmp_ext   = NULL;
+                }
+                if (p->jmp_2->follow) {
+                  new_bb->follow     = p->jmp_2->follow;
+                  BB_ADD_PRED(new_bb->follow, new_bb);
+                  BB_DEL_PRED(new_bb->follow, p->jmp_2);
+                  p->jmp_2->follow   = NULL;
+                }
+                p->jmp_2->follow = new_bb;
+                BB_ADD_PRED(p->jmp_2->follow, p->jmp_2);
+              }
+              op->opcode = ZEND_JMPNZ;
+              op->result.op_type = IS_UNUSED;
+              if (p->jmp_2 != p->follow) {
+                BB_DEL_PRED(p->jmp_2, p);
+                RM_BB(p->jmp_2);
+              }
+              p->jmp_2 = p->jmp_2->follow;
+              BB_ADD_PRED(p->jmp_2, p);
+              ok = 0;
+              goto jmp_nz;
+            }
+            goto jmp_2;
+          case ZEND_JMP_NO_CTOR:
+          case ZEND_FE_FETCH:
+jmp_2:
+            while (p->jmp_2->len == 1 && p->jmp_2->start->opcode == ZEND_JMP) {
+              BB* x_p = p->jmp_2;
+              if (p->jmp_2 != p->follow) {
+                BB_DEL_PRED(p->jmp_2, p);
+                RM_BB(x_p);
+              }
+              p->jmp_2 = x_p->jmp_1;
+              BB_ADD_PRED(p->jmp_2, p);
+              ok = 0;
+            }
+        }
+      }
+
+      /* Merging Basic Blocks */
+      if (p->used && p->pred != NULL && p->pred->bb->used && p->pred->next == NULL &&
+          p->pred->bb->follow == p &&
+          p->pred->bb->next == p &&
+          p->pred->bb->jmp_1 == NULL &&
+          p->pred->bb->jmp_2 == NULL &&
+          p->pred->bb->jmp_ext == NULL &&
+		  /* HOESH: See structure declaration */
+		  p->protect_merge == 0)
+	  {
+        BB* x = p->pred->bb;
+        BB_DEL_PRED(p, x);
+        x->len = &p->start[p->len] - x->start;
+        if (p->jmp_1 != NULL) {
+          x->jmp_1 = p->jmp_1;
+          BB_DEL_PRED(p->jmp_1, p);
+          BB_ADD_PRED(p->jmp_1, x);
+        }
+        if (p->jmp_2 != NULL) {
+          x->jmp_2   = p->jmp_2;
+          BB_DEL_PRED(p->jmp_2, p);
+          BB_ADD_PRED(p->jmp_2, x);
+        }
+        if (p->jmp_ext != NULL) {
+          x->jmp_ext   = p->jmp_ext;
+          BB_DEL_PRED(p->jmp_ext, p);
+          BB_ADD_PRED(p->jmp_ext, x);
+        }
+        x->follow  = p->follow;
+        if (p->follow != NULL) {
+          BB_DEL_PRED(p->follow, p);
+          BB_ADD_PRED(p->follow, x);
+        }
+        p->used  = 0;
+        p->len   = 0;
+        ok = 0;
+/*???
+      } else if (p != bb && p->used && p->pred != NULL && p->pred->bb->used && p->pred->next == NULL &&
+          p->follow == NULL &&
+          p->pred->bb->follow == NULL &&
+          p->pred->bb->jmp_1 == p &&
+          p->pred->bb->jmp_2 == NULL &&
+          p->pred->bb->jmp_ext == NULL &&
+          p->pred->bb != p &&
+          p->pred->bb->start[p->pred->bb->len-1].opcode == ZEND_JMP) {
+        BB* x = p->pred->bb;
+        int offset = p->len;
+        zend_op* save = emalloc(sizeof(zend_op)*offset);
+        memcpy(save, p->start, sizeof(zend_op)*offset);
+        if (x->start < p->start) {
+          if (offset > 1) {
+            BB* q = x->next;
+            while (q != p) {
+              if (q->len > 0) {
+                memcpy(q->start + (offset-1), q->start, sizeof(zend_op)*q->len);
+              }
+              q->start += offset - 1;
+              q = q->next;
+            }
+          }
+        } else {
+          BB* q = p->next;
+          while (q != x->next) {
+            if (q->len > 0) {
+              memcpy(q->start - offset, q->start, sizeof(zend_op)*q->len);
+              q->start -= offset;
+            }
+            q = q->next;
+          }
+        }
+        memcpy(x->start+(x->len-1),save, sizeof(zend_op)*offset);
+        efree(save);
+        x->len += offset-1;
+        if (x->start < p->start) {
+          SET_TO_NOP(&p->start[p->len-1]);
+        } else {
+          SET_TO_NOP(&x->start[x->len]);
+        }
+
+        BB_DEL_PRED(p, x);
+        x->jmp_1 = p->jmp_1;
+        if (p->jmp_1 != NULL) {
+          BB_DEL_PRED(p->jmp_1, p);
+          BB_ADD_PRED(p->jmp_1, x);
+        }
+        if (p->jmp_2 != NULL) {
+          x->jmp_2   = p->jmp_2;
+          BB_DEL_PRED(p->jmp_2, p);
+          BB_ADD_PRED(p->jmp_2, x);
+        }
+        if (p->jmp_ext != NULL) {
+          x->jmp_ext   = p->jmp_ext;
+          BB_DEL_PRED(p->jmp_ext, p);
+          BB_ADD_PRED(p->jmp_ext, x);
+        }
+        if (p->follow != NULL) {
+          x->follow  = p->follow;
+          BB_DEL_PRED(p->follow, p);
+          BB_ADD_PRED(p->follow, x);
+        }
+        p->start = NULL;
+        p->used  = 0;
+        p->len   = 0;
+        ok = 0;
+*/
+      }
+
+      p = p->next;
+    }
+
+    if (ok) {
+      /* Eliminate JMP to RETURN or EXIT */
+      p = bb;
+      while (p != NULL) {
+        if (p->used && p->len > 0) {
+          zend_op* op = &p->start[p->len-1];
+          if (op->opcode == ZEND_JMP &&
+              p->jmp_1->len == 1 &&
+              (p->jmp_1->start->opcode == ZEND_RETURN ||
+               p->jmp_1->start->opcode == ZEND_EXIT))
+		  {
+            BB_DEL_PRED(p->jmp_1, p);
+            RM_BB(p->jmp_1);
+            memcpy(op, p->jmp_1->start, sizeof(zend_op));
+            if (op->op1.op_type == IS_CONST)
+			{
+              zval_copy_ctor(&op->op1.u.constant);
+            }
+            p->jmp_1 = NULL;
+            ok = 0;
+          }
+        }
+        p = p->next;
+      }
+    }
+    if (ok) {
+      break;
+    }
+  }
+}
+
+static int opt_get_constant(const char* name, int name_len, zend_constant** result TSRMLS_DC) {
+  if (!MMCG(encoder) ||
+      (name_len == sizeof("false")-1 && strcmp(name,"false") == 0) ||
+      (name_len == sizeof("true")-1 && strcmp(name,"true") == 0)) {
+    zend_constant *c;
+    int retval;
+    char *lookup_name = do_alloca(name_len+1);
+    memcpy(lookup_name, name, name_len);
+    lookup_name[name_len] = '\0';
+
+    if (zend_hash_find(EG(zend_constants), lookup_name, name_len+1, (void **) &c)==SUCCESS) {
+      *result = c;
+      retval=1;
+    } else {
+      zend_str_tolower(lookup_name, name_len);
+
+      if (zend_hash_find(EG(zend_constants), lookup_name, name_len+1, (void **) &c)==SUCCESS) {
+        if ((c->flags & CONST_CS) && (memcmp(c->name, name, name_len)!=0)) {
+          retval=0;
+        } else {
+          *result = c;
+          retval=1;
+        }
+      } else {
+        retval=0;
+      }
+    }
+    free_alloca(lookup_name);
+    return retval;
+  } else {
+    return 0;
+  }
+}
+
+static int opt_function_exists(const char* name, int name_len TSRMLS_DC) {
+  if (!MMCG(encoder)) {
+    char *lcname;
+    char *lcfname;
+    Bucket *p;
+
+    lcname = estrndup(name,name_len+1);
+    zend_str_tolower(lcname, name_len);
+    p = module_registry.pListHead;
+    while (p != NULL) {
+      zend_module_entry *m = (zend_module_entry*)p->pData;
+      if (m->type == MODULE_PERSISTENT) {
+        zend_function_entry* f = m->functions;
+        if (f != NULL) {
+          while (f->fname) {
+            lcfname = estrdup(f->fname);
+            zend_str_tolower(lcfname, strlen(lcfname));
+            if (strcmp(lcname,lcfname) == 0) {
+              efree(lcfname);
+              efree(lcname);
+              return 1;
+            }
+            efree(lcfname);
+            f++;
+          }
+        }
+      }
+      p = p->pListNext;
+    }
+    efree(lcname);
+  }
+  return 0;
+}
+
+static int opt_extension_loaded(const char* name, int name_len TSRMLS_DC) {
+  if (!MMCG(encoder)) {
+    Bucket *p = module_registry.pListHead;
+    while (p != NULL) {
+      zend_module_entry *m = (zend_module_entry*)p->pData;
+      if (m->type == MODULE_PERSISTENT && strcmp(m->name,name) == 0) {
+        return 1;
+      }
+      p = p->pListNext;
+    }
+  }
+  return 0;
+}
+
+static int opt_result_is_numeric(zend_op* x) {
+  switch (x->opcode) {
+    case ZEND_ADD:
+    case ZEND_SUB:
+    case ZEND_MUL:
+    case ZEND_DIV:
+    case ZEND_MOD:
+    case ZEND_SL:
+    case ZEND_SR:
+    case ZEND_BOOL_NOT:
+    case ZEND_BOOL_XOR:
+    case ZEND_IS_IDENTICAL:
+    case ZEND_IS_NOT_IDENTICAL:
+    case ZEND_IS_EQUAL:
+    case ZEND_IS_NOT_EQUAL:
+    case ZEND_IS_SMALLER:
+    case ZEND_IS_SMALLER_OR_EQUAL:
+    case ZEND_PRE_DEC:
+    case ZEND_PRE_INC:
+    case ZEND_ASSIGN_ADD:
+    case ZEND_ASSIGN_SUB:
+    case ZEND_ASSIGN_MUL:
+    case ZEND_ASSIGN_DIV:
+    case ZEND_ASSIGN_MOD:
+    case ZEND_ASSIGN_SL:
+    case ZEND_ASSIGN_SR:
+    case ZEND_BOOL:
+      return 1;
+    case ZEND_CAST:
+      if (x->extended_value == IS_BOOL ||
+          x->extended_value == IS_LONG ||
+          x->extended_value == IS_DOUBLE) {
+        return 1;
+      }
+      return 0;
+    case ZEND_DO_FCALL:
+      if (x->op1.op_type == IS_CONST &&
+          x->op1.u.constant.type == IS_STRING &&
+          (strcmp(x->op1.u.constant.value.str.val,"count") == 0 ||
+           strcmp(x->op1.u.constant.value.str.val,"sizeof") == 0 ||
+           strcmp(x->op1.u.constant.value.str.val,"strcmp") == 0 ||
+           strcmp(x->op1.u.constant.value.str.val,"strlen") == 0 ||
+           strcmp(x->op1.u.constant.value.str.val,"strpos") == 0 ||
+           strcmp(x->op1.u.constant.value.str.val,"strncmp") == 0 ||
+           strcmp(x->op1.u.constant.value.str.val,"strcoll") == 0 ||
+           strcmp(x->op1.u.constant.value.str.val,"strcasecmp") == 0)) {
+        return 1;
+      }
+      return 0;
+    default:
+      return 0;
+  }
+  return 0;
+}
+
+#ifndef ZEND_ENGINE_2
+#define FETCH_TYPE(op) ((op)->op2.u.fetch_type)
+#else
+#define FETCH_TYPE(op) ((op)->op2.u.EA.type)
+#endif
+
+#define SET_UNDEFINED(op) Ts[VAR_NUM((op).u.var)] = NULL;
+#define SET_DEFINED(op)   Ts[VAR_NUM((op)->result.u.var)] = (op);
+#define IS_DEFINED(op)    (Ts[VAR_NUM((op).u.var)] != NULL)
+#define DEFINED_OP(op)    (Ts[VAR_NUM((op).u.var)])
+
+static void optimize_bb(BB* bb, zend_op_array* op_array, char* global, int pass TSRMLS_DC)
+{
+  zend_op* prev = NULL;
+  zend_op* op = bb->start;
+  zend_op* end = op + bb->len;
+
+  HashTable assigns;
+  HashTable fetch_dim;
+
+  zend_op** Ts = do_alloca(sizeof(zend_op*)*op_array->T);
+  memset(Ts, 0, sizeof(zend_op*)*op_array->T);
+
+  zend_hash_init(&assigns, 0, NULL, NULL, 0);
+  zend_hash_init(&fetch_dim, 0, NULL, NULL, 0);
+
+  while (op < end) {
+    /* Constant Folding */
+    if (op->op1.op_type == IS_TMP_VAR &&
+        IS_DEFINED(op->op1) &&
+        DEFINED_OP(op->op1)->opcode == ZEND_QM_ASSIGN &&
+        DEFINED_OP(op->op1)->op1.op_type == IS_CONST) {
+      zend_op *x = DEFINED_OP(op->op1);
+      if (op->opcode != ZEND_CASE) {
+        SET_UNDEFINED(op->op1);
+        memcpy(&op->op1, &x->op1, sizeof(znode));
+        SET_TO_NOP(x);
+      }
+    }
+    if (op->op2.op_type == IS_TMP_VAR &&
+        IS_DEFINED(op->op2) &&
+        DEFINED_OP(op->op2)->opcode == ZEND_QM_ASSIGN &&
+        DEFINED_OP(op->op2)->op1.op_type == IS_CONST) {
+      zend_op *x = DEFINED_OP(op->op2);
+      SET_UNDEFINED(op->op2);
+      memcpy(&op->op2, &x->op1, sizeof(znode));
+      SET_TO_NOP(x);
+    }
+/*
+    if (op->result.op_type == IS_TMP_VAR &&
+        Ts[VAR_NUM(op->result.u.var)].op_type == IS_CONST &&
+        op->opcode != ZEND_ADD_CHAR &&
+        op->opcode != ZEND_ADD_STRING &&
+        op->opcode != ZEND_ADD_VAR &&
+        op->opcode != ZEND_ADD_ARRAY_ELEMENT) {
+      Ts[VAR_NUM(op->result.u.var)].op_type = IS_UNUSED;
+    }
+*/
+    if (op->opcode == ZEND_IS_EQUAL) {
+      if (op->op1.op_type == IS_CONST &&
+          (op->op1.u.constant.type == IS_BOOL &&
+           op->op1.u.constant.value.lval == 0)) {
+        op->opcode = ZEND_BOOL_NOT;
+        memcpy(&op->op1, &op->op2, sizeof(znode));
+        op->op2.op_type = IS_UNUSED;
+      } else if (op->op1.op_type == IS_CONST &&
+                 op->op1.u.constant.type == IS_BOOL &&
+                 op->op1.u.constant.value.lval == 1) {
+        op->opcode = ZEND_BOOL;
+        memcpy(&op->op1, &op->op2, sizeof(znode));
+        op->op2.op_type = IS_UNUSED;
+      } else if (op->op2.op_type == IS_CONST &&
+                 op->op2.u.constant.type == IS_BOOL &&
+                 op->op2.u.constant.value.lval == 0) {
+        op->opcode = ZEND_BOOL_NOT;
+        op->op2.op_type = IS_UNUSED;
+      } else if (op->op2.op_type == IS_CONST &&
+          op->op2.u.constant.type == IS_BOOL &&
+          op->op2.u.constant.value.lval == 1) {
+        op->opcode = ZEND_BOOL;
+        op->op2.op_type = IS_UNUSED;
+      } else if (op->op2.op_type == IS_CONST &&
+          op->op2.u.constant.type == IS_LONG &&
+          op->op2.u.constant.value.lval == 0 &&
+          (op->op1.op_type == IS_TMP_VAR || op->op1.op_type == IS_VAR) &&
+          IS_DEFINED(op->op1) &&
+          opt_result_is_numeric(DEFINED_OP(op->op1))) {
+        op->opcode = ZEND_BOOL_NOT;
+        op->op2.op_type = IS_UNUSED;
+      }
+    } else if (op->opcode == ZEND_IS_NOT_EQUAL) {
+      if (op->op1.op_type == IS_CONST &&
+          op->op1.u.constant.type == IS_BOOL &&
+          op->op1.u.constant.value.lval == 0) {
+        op->opcode = ZEND_BOOL;
+        memcpy(&op->op1, &op->op2, sizeof(znode));
+        op->op2.op_type = IS_UNUSED;
+      } else if (op->op1.op_type == IS_CONST &&
+                 op->op1.u.constant.type == IS_BOOL &&
+                 op->op1.u.constant.value.lval == 1) {
+        op->opcode = ZEND_BOOL_NOT;
+        memcpy(&op->op1, &op->op2, sizeof(znode));
+        op->op2.op_type = IS_UNUSED;
+      } else if (op->op2.op_type == IS_CONST &&
+                 op->op2.u.constant.type == IS_BOOL &&
+                 op->op2.u.constant.value.lval == 0) {
+        op->opcode = ZEND_BOOL;
+        op->op2.op_type = IS_UNUSED;
+      } else if (op->op2.op_type == IS_CONST &&
+          op->op2.u.constant.type == IS_BOOL &&
+          op->op2.u.constant.value.lval == 1) {
+        op->opcode = ZEND_BOOL_NOT;
+        op->op2.op_type = IS_UNUSED;
+      } else if (op->op2.op_type == IS_CONST &&
+          op->op2.u.constant.type == IS_LONG &&
+          op->op2.u.constant.value.lval == 0 &&
+          (op->op1.op_type == IS_TMP_VAR || op->op1.op_type == IS_VAR) &&
+          IS_DEFINED(op->op1) &&
+          opt_result_is_numeric(DEFINED_OP(op->op1))) {
+        op->opcode = ZEND_BOOL;
+        op->op2.op_type = IS_UNUSED;
+      }
+    }
+    if (op->opcode == ZEND_FETCH_CONSTANT &&
+        op->result.op_type == IS_TMP_VAR) {
+      zend_constant *c = NULL;
+      if (opt_get_constant(op->op1.u.constant.value.str.val, op->op1.u.constant.value.str.len, &c TSRMLS_CC) && c != NULL && ((c->flags & CONST_PERSISTENT) != 0)) {
+        STR_FREE(op->op1.u.constant.value.str.val);
+        memcpy(&op->op1.u.constant, &c->value, sizeof(zval));
+        zval_copy_ctor(&op->op1.u.constant);
+        op->opcode = ZEND_QM_ASSIGN;
+        op->extended_value = 0;
+        op->op1.op_type = IS_CONST;
+        op->op2.op_type = IS_UNUSED;
+      }
+    } else if ((op->opcode == ZEND_ADD ||
+                op->opcode == ZEND_SUB ||
+                op->opcode == ZEND_MUL ||
+                op->opcode == ZEND_DIV ||
+                op->opcode == ZEND_MOD ||
+                op->opcode == ZEND_SL ||
+                op->opcode == ZEND_SR ||
+                op->opcode == ZEND_CONCAT ||
+                op->opcode == ZEND_BW_OR ||
+                op->opcode == ZEND_BW_AND ||
+                op->opcode == ZEND_BW_XOR ||
+                op->opcode == ZEND_BOOL_XOR ||
+                op->opcode == ZEND_IS_IDENTICAL ||
+                op->opcode == ZEND_IS_NOT_IDENTICAL ||
+                op->opcode == ZEND_IS_EQUAL ||
+                op->opcode == ZEND_IS_NOT_EQUAL ||
+                op->opcode == ZEND_IS_SMALLER ||
+                op->opcode == ZEND_IS_SMALLER_OR_EQUAL) &&
+               op->op1.op_type == IS_CONST &&
+               op->op2.op_type == IS_CONST &&
+               op->result.op_type == IS_TMP_VAR) {
+
+      typedef int (*binary_op_type)(zval *, zval *, zval*  TSRMLS_DC);
+
+      binary_op_type binary_op = (binary_op_type)get_binary_op(op->opcode);
+
+      if (binary_op != NULL) {
+        int old = EG(error_reporting);
+        zval res;
+        EG(error_reporting) = 0;
+        if (binary_op(&res, &op->op1.u.constant, &op->op2.u.constant TSRMLS_CC) != FAILURE) {
+          zval_dtor(&op->op1.u.constant);
+          zval_dtor(&op->op2.u.constant);
+          op->opcode = ZEND_QM_ASSIGN;
+          op->extended_value = 0;
+          op->op1.op_type = IS_CONST;
+          memcpy(&op->op1.u.constant, &res, sizeof(zval));
+          op->op2.op_type = IS_UNUSED;
+        }
+        EG(error_reporting) = old;
+      }
+    } else if ((op->opcode == ZEND_BW_NOT ||
+                op->opcode == ZEND_BOOL_NOT) &&
+               op->op1.op_type == IS_CONST &&
+               op->result.op_type == IS_TMP_VAR) {
+      int (*unary_op)(zval *result, zval *op1) =
+        unary_op = get_unary_op(op->opcode);
+      if (unary_op != NULL) {
+        int old = EG(error_reporting);
+        zval res;
+        EG(error_reporting) = 0;
+        if (unary_op(&res, &op->op1.u.constant) != FAILURE) {
+          zval_dtor(&op->op1.u.constant);
+          op->opcode = ZEND_QM_ASSIGN;
+          op->extended_value = 0;
+          op->op1.op_type = IS_CONST;
+          memcpy(&op->op1.u.constant, &res, sizeof(zval));
+          op->op2.op_type = IS_UNUSED;
+        }
+        EG(error_reporting) = old;
+      }
+    } else if ((op->opcode == ZEND_BOOL) &&
+               op->op1.op_type == IS_CONST &&
+               op->result.op_type == IS_TMP_VAR) {
+      zval res;
+      res.type = IS_BOOL;
+      res.value.lval = zend_is_true(&op->op1.u.constant);
+      zval_dtor(&op->op1.u.constant);
+      op->opcode = ZEND_QM_ASSIGN;
+      op->extended_value = 0;
+      op->op1.op_type = IS_CONST;
+      memcpy(&op->op1.u.constant, &res, sizeof(zval));
+      op->op2.op_type = IS_UNUSED;
+    } else if ((op->opcode == ZEND_CAST) &&
+               op->op1.op_type == IS_CONST &&
+               op->result.op_type == IS_TMP_VAR &&
+               op->extended_value != IS_ARRAY &&
+               op->extended_value != IS_OBJECT &&
+               op->extended_value != IS_RESOURCE) {
+      zval res;
+      memcpy(&res,&op->op1.u.constant,sizeof(zval));
+      zval_copy_ctor(&res);
+      switch (op->extended_value) {
+        case IS_NULL:
+          convert_to_null(&res);
+          break;
+        case IS_BOOL:
+          convert_to_boolean(&res);
+          break;
+        case IS_LONG:
+          convert_to_long(&res);
+          break;
+        case IS_DOUBLE:
+          convert_to_double(&res);
+          break;
+        case IS_STRING:
+          convert_to_string(&res);
+          break;
+        case IS_ARRAY:
+          convert_to_array(&res);
+          break;
+        case IS_OBJECT:
+          convert_to_object(&res);
+          break;
+      }
+      zval_dtor(&op->op1.u.constant);
+      op->opcode = ZEND_QM_ASSIGN;
+      op->extended_value = 0;
+      op->op1.op_type = IS_CONST;
+      memcpy(&op->op1.u.constant, &res, sizeof(zval));
+      op->op2.op_type = IS_UNUSED;
+
+    /* FREE(CONST) => NOP
+    */
+    } else if (op->opcode == ZEND_FREE &&
+               op->op1.op_type == IS_CONST) {
+      zval_dtor(&op->op1.u.constant);
+      SET_TO_NOP(op);
+
+    /* INIT_STRING ADD_CAHR ADD_STRIN ADD_VAR folding */
+
+    /* INIT_STRING($y) => QM_ASSIGN('',$y)
+    */
+    } else if (op->opcode == ZEND_INIT_STRING) {
+      op->opcode = ZEND_QM_ASSIGN;
+      op->op1.op_type = IS_CONST;
+      op->op2.op_type = IS_UNUSED;
+      op->op1.u.constant.type = IS_STRING;
+      op->op1.u.constant.value.str.len = 0;
+      op->op1.u.constant.value.str.val = empty_string;
+    /* ADD_CHAR(CONST,CONST,$y) => QM_ASSIGN(CONST,$y)
+    */
+    } else if (op->opcode == ZEND_ADD_CHAR &&
+               op->op1.op_type == IS_CONST) {
+      size_t len;
+      op->opcode = ZEND_QM_ASSIGN;
+      op->op1.op_type = IS_CONST;
+      op->op2.op_type = IS_UNUSED;
+      convert_to_string(&op->op1.u.constant);
+      len = op->op1.u.constant.value.str.len + 1;
+      STR_REALLOC(op->op1.u.constant.value.str.val,len+1);
+      op->op1.u.constant.value.str.val[len-1] = (char) op->op2.u.constant.value.lval;
+      op->op1.u.constant.value.str.val[len] = 0;
+      op->op1.u.constant.value.str.len = len;
+    /* ADD_STRING(CONST,CONST,$y) => QM_ASSIGN(CONST,$y)
+    */
+    } else if (op->opcode == ZEND_ADD_STRING &&
+               op->op1.op_type == IS_CONST) {
+      size_t len;
+      op->opcode = ZEND_QM_ASSIGN;
+      op->op1.op_type = IS_CONST;
+      op->op2.op_type = IS_UNUSED;
+      convert_to_string(&op->op1.u.constant);
+      convert_to_string(&op->op2.u.constant);
+      len = op->op1.u.constant.value.str.len + op->op2.u.constant.value.str.len;
+      STR_REALLOC(op->op1.u.constant.value.str.val,len+1);
+      memcpy(op->op1.u.constant.value.str.val+op->op1.u.constant.value.str.len,
+             op->op2.u.constant.value.str.val, op->op2.u.constant.value.str.len);
+      op->op1.u.constant.value.str.val[len] = 0;
+      op->op1.u.constant.value.str.len = len;
+      STR_FREE(op->op2.u.constant.value.str.val);
+    /* ADD_VAR(CONST,VAR,$y) => CONCAT(CONST,$y)
+    */
+    } else if (op->opcode == ZEND_ADD_VAR &&
+               op->op1.op_type == IS_CONST) {
+      op->opcode = ZEND_CONCAT;
+    /* CONCAT('',$x,$y) + ADD_CHAR($y,CHAR,$z) => CONCAT($x, CONST, $z)
+    */
+    } else if (op->opcode == ZEND_ADD_CHAR &&
+               op->op1.op_type == IS_TMP_VAR &&
+               IS_DEFINED(op->op1) &&
+               DEFINED_OP(op->op1)->opcode == ZEND_CONCAT &&
+               DEFINED_OP(op->op1)->op1.op_type == IS_CONST &&
+               DEFINED_OP(op->op1)->op1.u.constant.type == IS_STRING &&
+               DEFINED_OP(op->op1)->op1.u.constant.value.str.len == 0) {
+      char ch = (char) op->op2.u.constant.value.lval;
+      zend_op *x = DEFINED_OP(op->op1);
+      SET_UNDEFINED(op->op1);
+      memcpy(&op->op1, &x->op2, sizeof(op->op2));
+      op->opcode = ZEND_CONCAT;
+      op->op2.u.constant.type = IS_STRING;
+      op->op2.u.constant.value.str.val = emalloc(2);
+      op->op2.u.constant.value.str.val[0] = ch;
+      op->op2.u.constant.value.str.val[1] = '\000';
+      op->op2.u.constant.value.str.len = 1;
+      STR_FREE(x->op1.u.constant.value.str.val);
+      SET_TO_NOP(x);
+    /*
+       CONCAT('',$x,$y) + ADD_STRING($y,$v,$z) => CONCAT($x, $v, $z)
+       CONCAT('',$x,$y) + CONCAT($y,$v,$z)     => CONCAT($x, $v, $z)
+       CONCAT('',$x,$y) + ADD_VAR($y,$v,$z)    => CONCAT($x, $v, $z)
+    */
+    } else if ((op->opcode == ZEND_ADD_STRING ||
+                op->opcode == ZEND_CONCAT ||
+                op->opcode == ZEND_ADD_VAR) &&
+               op->op1.op_type == IS_TMP_VAR &&
+               IS_DEFINED(op->op1) &&
+               DEFINED_OP(op->op1)->opcode == ZEND_CONCAT &&
+               DEFINED_OP(op->op1)->op1.op_type == IS_CONST &&
+               DEFINED_OP(op->op1)->op1.u.constant.type == IS_STRING &&
+               DEFINED_OP(op->op1)->op1.u.constant.value.str.len == 0) {
+      zend_op *x = DEFINED_OP(op->op1);
+      SET_UNDEFINED(op->op1);
+      op->opcode = ZEND_CONCAT;
+      memcpy(&op->op1, &x->op2, sizeof(op->op2));
+      STR_FREE(x->op1.u.constant.value.str.val);
+      SET_TO_NOP(x);
+    /* ADD_CHAR($x,CONST,$y) + ADD_CHAR($y,CHAR,$z) => ADD_STRING($x, CONST, $z)
+    */
+    } else if (op->opcode == ZEND_ADD_CHAR &&
+               op->op1.op_type == IS_TMP_VAR &&
+               IS_DEFINED(op->op1) &&
+               DEFINED_OP(op->op1)->opcode == ZEND_ADD_CHAR) {
+      char ch1 = (char) DEFINED_OP(op->op1)->op2.u.constant.value.lval;
+      char ch2 = (char) op->op2.u.constant.value.lval;
+      DEFINED_OP(op->op1)->op2.u.constant.type = IS_STRING;
+      DEFINED_OP(op->op1)->op2.u.constant.value.str.val = emalloc(3);
+      DEFINED_OP(op->op1)->op2.u.constant.value.str.val[0] = ch1;
+      DEFINED_OP(op->op1)->op2.u.constant.value.str.val[1] = ch2;
+      DEFINED_OP(op->op1)->op2.u.constant.value.str.val[2] = '\000';
+      DEFINED_OP(op->op1)->op2.u.constant.value.str.len = 2;
+      memcpy(&DEFINED_OP(op->op1)->result, &op->result, sizeof(op->result));
+      DEFINED_OP(op->op1)->opcode = ZEND_ADD_STRING;
+      SET_DEFINED(DEFINED_OP(op->op1));
+      SET_TO_NOP(op);
+    /* CONCAT($x,CONST,$y) + ADD_CHAR($y,CONST,$z) => CONCAT($x, CONST, $z)
+       ADD_STRING($x,CONST,$y) + ADD_CHAR($y,CONST,$z) => ADD_STRING($x, CONST, $z)
+    */
+    } else if (op->opcode == ZEND_ADD_CHAR &&
+               op->op1.op_type == IS_TMP_VAR &&
+               IS_DEFINED(op->op1) &&
+               (DEFINED_OP(op->op1)->opcode == ZEND_CONCAT ||
+                DEFINED_OP(op->op1)->opcode == ZEND_ADD_STRING) &&
+               DEFINED_OP(op->op1)->op2.op_type == IS_CONST) {
+      size_t len;
+      convert_to_string(&DEFINED_OP(op->op1)->op2.u.constant);
+      len = DEFINED_OP(op->op1)->op2.u.constant.value.str.len + 1;
+      STR_REALLOC(DEFINED_OP(op->op1)->op2.u.constant.value.str.val,len+1);
+      DEFINED_OP(op->op1)->op2.u.constant.value.str.val[len-1] = (char) op->op2.u.constant.value.lval;
+      DEFINED_OP(op->op1)->op2.u.constant.value.str.val[len] = 0;
+      DEFINED_OP(op->op1)->op2.u.constant.value.str.len = len;
+      memcpy(&DEFINED_OP(op->op1)->result, &op->result, sizeof(op->result));
+      if (DEFINED_OP(op->op1)->op1.op_type == DEFINED_OP(op->op1)->result.op_type &&
+          DEFINED_OP(op->op1)->op1.u.var == DEFINED_OP(op->op1)->result.u.var) {
+        DEFINED_OP(op->op1)->opcode = ZEND_ADD_STRING;
+      }
+      SET_DEFINED(DEFINED_OP(op->op1));
+      SET_TO_NOP(op);
+    /* ADD_CHAR($x,CONST,$y) + ADD_STRING($y,CONST,$z) => ADD_STRING($x, CONST, $z)
+       ADD_CHAR($x,CONST,$y) + CONCAT($y,CONST,$z) => CONCAT($x, CONST, $z)
+    */
+    } else if ((op->opcode == ZEND_ADD_STRING ||
+                op->opcode == ZEND_CONCAT) &&
+               op->op2.op_type == IS_CONST &&
+               op->op1.op_type == IS_TMP_VAR &&
+               IS_DEFINED(op->op1) &&
+               DEFINED_OP(op->op1)->opcode == ZEND_ADD_CHAR) {
+      char ch = (char) DEFINED_OP(op->op1)->op2.u.constant.value.lval;
+      size_t len;
+      convert_to_string(&op->op2.u.constant);
+      len = op->op2.u.constant.value.str.len + 1;
+      DEFINED_OP(op->op1)->op2.u.constant.type = IS_STRING;
+      DEFINED_OP(op->op1)->op2.u.constant.value.str.val = emalloc(len+1);
+      DEFINED_OP(op->op1)->op2.u.constant.value.str.val[0] = ch;
+      memcpy(DEFINED_OP(op->op1)->op2.u.constant.value.str.val+1,
+             op->op2.u.constant.value.str.val, op->op2.u.constant.value.str.len);
+      DEFINED_OP(op->op1)->op2.u.constant.value.str.val[len] = 0;
+      DEFINED_OP(op->op1)->op2.u.constant.value.str.len = len;
+      STR_FREE(op->op2.u.constant.value.str.val);
+      memcpy(&DEFINED_OP(op->op1)->result, &op->result, sizeof(op->result));
+      DEFINED_OP(op->op1)->opcode = op->opcode;
+      if (DEFINED_OP(op->op1)->op1.op_type == DEFINED_OP(op->op1)->result.op_type &&
+          DEFINED_OP(op->op1)->op1.u.var == DEFINED_OP(op->op1)->result.u.var) {
+        DEFINED_OP(op->op1)->opcode = ZEND_ADD_STRING;
+      }
+      SET_DEFINED(DEFINED_OP(op->op1));
+      SET_TO_NOP(op);
+    /* ADD_STRING($x,CONST,$y) + ADD_STRING($y,CONST,$z) => ADD_STRING($x, CONST, $z)
+       ADD_STRING($x,CONST,$y) + CONCAT($y,CONST,$z) => CONCAT($x, CONST, $z)
+       CONCAT($x,CONST,$y) + ADD_STRING($y,CONST,$z) => CONCAT($x, CONST, $z)
+       CONCAT($x,CONST,$y) + CONCAT($y,CONST,$z) => CONCAT($x, CONST, $z)
+    */
+    } else if ((op->opcode == ZEND_ADD_STRING ||
+                op->opcode == ZEND_CONCAT) &&
+               op->op2.op_type == IS_CONST &&
+               op->op1.op_type == IS_TMP_VAR &&
+               IS_DEFINED(op->op1) &&
+               (DEFINED_OP(op->op1)->opcode == ZEND_CONCAT ||
+                DEFINED_OP(op->op1)->opcode == ZEND_ADD_STRING) &&
+               DEFINED_OP(op->op1)->op2.op_type == IS_CONST) {
+      size_t len;
+      convert_to_string(&DEFINED_OP(op->op1)->op2.u.constant);
+      convert_to_string(&op->op2.u.constant);
+      len = DEFINED_OP(op->op1)->op2.u.constant.value.str.len + op->op2.u.constant.value.str.len;
+      STR_REALLOC(DEFINED_OP(op->op1)->op2.u.constant.value.str.val,len+1);
+      memcpy(DEFINED_OP(op->op1)->op2.u.constant.value.str.val+DEFINED_OP(op->op1)->op2.u.constant.value.str.len,
+             op->op2.u.constant.value.str.val, op->op2.u.constant.value.str.len);
+      DEFINED_OP(op->op1)->op2.u.constant.value.str.val[len] = 0;
+      DEFINED_OP(op->op1)->op2.u.constant.value.str.len = len;
+      STR_FREE(op->op2.u.constant.value.str.val);
+      memcpy(&DEFINED_OP(op->op1)->result, &op->result, sizeof(op->result));
+      if (op->opcode == ZEND_CONCAT) {
+        DEFINED_OP(op->op1)->opcode = ZEND_CONCAT;
+      }
+      if (DEFINED_OP(op->op1)->op1.op_type == DEFINED_OP(op->op1)->result.op_type &&
+          DEFINED_OP(op->op1)->op1.u.var == DEFINED_OP(op->op1)->result.u.var) {
+        DEFINED_OP(op->op1)->opcode = ZEND_ADD_STRING;
+      }
+      SET_DEFINED(DEFINED_OP(op->op1));
+      SET_TO_NOP(op);
+    /* FETCH_X      local("GLOBALS"),$x => FETCH_X global($y),$z
+       FETCH_DIM_X  $x,$y,$z               NOP
+    */
+    } else if (
+#ifndef ZEND_ENGINE_2
+               op_array->uses_globals &&
+#endif
+               ((op->opcode == ZEND_FETCH_DIM_R &&
+                op->op1.op_type == IS_VAR &&
+/*???               op->extended_value == ZEND_FETCH_STANDARD &&*/
+                IS_DEFINED(op->op1) &&
+                DEFINED_OP(op->op1)->opcode == ZEND_FETCH_R) ||
+               (op->opcode == ZEND_FETCH_DIM_W &&
+                op->op1.op_type == IS_VAR &&
+                IS_DEFINED(op->op1) &&
+                DEFINED_OP(op->op1)->opcode == ZEND_FETCH_W) ||
+               (op->opcode == ZEND_FETCH_DIM_RW &&
+                op->op1.op_type == IS_VAR &&
+                IS_DEFINED(op->op1) &&
+                DEFINED_OP(op->op1)->opcode == ZEND_FETCH_RW) ||
+               (op->opcode == ZEND_FETCH_DIM_IS &&
+                op->op1.op_type == IS_VAR &&
+                IS_DEFINED(op->op1) &&
+                DEFINED_OP(op->op1)->opcode == ZEND_FETCH_IS) ||
+               (op->opcode == ZEND_FETCH_DIM_FUNC_ARG &&
+                op->op1.op_type == IS_VAR &&
+                IS_DEFINED(op->op1) &&
+                DEFINED_OP(op->op1)->opcode == ZEND_FETCH_FUNC_ARG) ||
+               (op->opcode == ZEND_FETCH_DIM_UNSET &&
+                op->op1.op_type == IS_VAR &&
+                IS_DEFINED(op->op1) &&
+                DEFINED_OP(op->op1)->opcode == ZEND_FETCH_UNSET)) &&
+#ifdef ZEND_ENGINE_2
+                FETCH_TYPE(DEFINED_OP(op->op1)) == ZEND_FETCH_GLOBAL &&
+#else
+                FETCH_TYPE(DEFINED_OP(op->op1)) == ZEND_FETCH_LOCAL &&
+#endif
+                DEFINED_OP(op->op1)->op1.op_type == IS_CONST &&
+                DEFINED_OP(op->op1)->op1.u.constant.type == IS_STRING &&
+                DEFINED_OP(op->op1)->op1.u.constant.value.str.len == (sizeof("GLOBALS")-1) &&
+                memcmp(DEFINED_OP(op->op1)->op1.u.constant.value.str.val, "GLOBALS", sizeof("GLOBALS")-1) == 0) {
+      zend_op *x = DEFINED_OP(op->op1);
+      SET_UNDEFINED(op->op1);
+      STR_FREE(x->op1.u.constant.value.str.val);
+      FETCH_TYPE(x) = ZEND_FETCH_GLOBAL;
+      memcpy(&x->op1,&op->op2,sizeof(znode));
+      memcpy(&x->result,&op->result,sizeof(znode));
+      SET_DEFINED(x);
+      SET_TO_NOP(op);
+#ifndef ZEND_ENGINE_2
+      if (x->op1.op_type == IS_VAR) {
+        memcpy(&op->op1,&x->op1,sizeof(znode));
+        op->opcode = ZEND_SWITCH_FREE;
+        op->extended_value = 0;
+      }
+#endif
+#ifdef ZEND_ENGINE_2
+    /* FETCH_IS               local("GLOBALS"),$x    ISSET_ISEMPTY_VAR $y(global),res
+       ISSET_ISEMPTY_DIM_OBJ  $x,$y,$res          => NOP
+    */
+    } else if (op->opcode == ZEND_ISSET_ISEMPTY_DIM_OBJ &&
+               op->op1.op_type == IS_VAR &&
+              IS_DEFINED(op->op1) &&
+              DEFINED_OP(op->op1)->opcode == ZEND_FETCH_IS &&
+              FETCH_TYPE(DEFINED_OP(op->op1)) == ZEND_FETCH_GLOBAL &&
+              DEFINED_OP(op->op1)->op1.op_type == IS_CONST &&
+              DEFINED_OP(op->op1)->op1.u.constant.type == IS_STRING &&
+              DEFINED_OP(op->op1)->op1.u.constant.value.str.len == (sizeof("GLOBALS")-1) &&
+              memcmp(DEFINED_OP(op->op1)->op1.u.constant.value.str.val, "GLOBALS", sizeof("GLOBALS")-1) == 0) {
+      zend_op* x = DEFINED_OP(op->op1);
+      STR_FREE(x->op1.u.constant.value.str.val);
+      x->opcode = ZEND_ISSET_ISEMPTY_VAR;
+      x->extended_value = op->extended_value;
+      FETCH_TYPE(x) = ZEND_FETCH_GLOBAL;
+      memcpy(&x->op1,&op->op2,sizeof(znode));
+      memcpy(&x->result,&op->result,sizeof(znode));
+      SET_DEFINED(x);
+      SET_TO_NOP(op);
+#endif
+    } else if (op->opcode == ZEND_FREE &&
+               op->op1.op_type == IS_TMP_VAR &&
+               IS_DEFINED(op->op1)) {
+      /* POST_INC + FREE => PRE_INC */
+      if (DEFINED_OP(op->op1)->opcode == ZEND_POST_INC) {
+        DEFINED_OP(op->op1)->opcode = ZEND_PRE_INC;
+        DEFINED_OP(op->op1)->result.op_type = IS_VAR;
+        DEFINED_OP(op->op1)->result.u.EA.type |= EXT_TYPE_UNUSED;
+        SET_UNDEFINED(op->op1);
+        SET_TO_NOP(op);
+      /* POST_DEC + FREE => PRE_DEC */
+      } else if (DEFINED_OP(op->op1)->opcode == ZEND_POST_DEC) {
+        DEFINED_OP(op->op1)->opcode = ZEND_PRE_DEC;
+        DEFINED_OP(op->op1)->result.op_type = IS_VAR;
+        DEFINED_OP(op->op1)->result.u.EA.type |= EXT_TYPE_UNUSED;
+        SET_UNDEFINED(op->op1);
+        SET_TO_NOP(op);
+      /* PRINT + FREE => ECHO */
+      } else if (DEFINED_OP(op->op1)->opcode == ZEND_PRINT) {
+        DEFINED_OP(op->op1)->opcode = ZEND_ECHO;
+        DEFINED_OP(op->op1)->result.op_type = IS_UNUSED;
+        SET_UNDEFINED(op->op1);
+        SET_TO_NOP(op);
+      /* BOOL + FREE => NOP + NOP */
+      } else if (DEFINED_OP(op->op1)->opcode == ZEND_BOOL) {
+        SET_TO_NOP(DEFINED_OP(op->op1));
+        SET_UNDEFINED(op->op1);
+        SET_TO_NOP(op);
+      }
+    /* CMP + BOOL     => CMP + NOP */
+    } else if (op->opcode == ZEND_BOOL &&
+               op->op1.op_type == IS_TMP_VAR &&
+               (!global[VAR_NUM(op->op1.u.var)] ||
+                (op->result.op_type == IS_TMP_VAR &&
+                 op->op1.u.var == op->result.u.var)) &&
+               IS_DEFINED(op->op1) &&
+               (DEFINED_OP(op->op1)->opcode == ZEND_IS_IDENTICAL ||
+                DEFINED_OP(op->op1)->opcode == ZEND_IS_NOT_IDENTICAL ||
+                DEFINED_OP(op->op1)->opcode == ZEND_IS_EQUAL ||
+                DEFINED_OP(op->op1)->opcode == ZEND_IS_NOT_EQUAL ||
+                DEFINED_OP(op->op1)->opcode == ZEND_IS_SMALLER ||
+                DEFINED_OP(op->op1)->opcode == ZEND_IS_SMALLER_OR_EQUAL)) {
+      memcpy(&DEFINED_OP(op->op1)->result, &op->result, sizeof(op->result));
+      SET_DEFINED(DEFINED_OP(op->op1));
+      SET_TO_NOP(op);
+    /* BOOL + BOOL     => NOP + BOOL
+       BOOL + BOOL_NOT => NOP + BOOL_NOT
+       BOOL + JMP...   => NOP + JMP...
+    */
+    } else if ((op->opcode == ZEND_BOOL ||
+                op->opcode == ZEND_BOOL_NOT ||
+                op->opcode == ZEND_JMPZ||
+                op->opcode == ZEND_JMPNZ ||
+                op->opcode == ZEND_JMPZNZ ||
+                op->opcode == ZEND_JMPZ_EX ||
+                op->opcode == ZEND_JMPNZ_EX) &&
+                op->op1.op_type == IS_TMP_VAR &&
+                (!global[VAR_NUM(op->op1.u.var)] ||
+                 (op->result.op_type == IS_TMP_VAR &&
+                  op->op1.u.var == op->result.u.var)) &&
+                IS_DEFINED(op->op1) &&
+                DEFINED_OP(op->op1)->opcode == ZEND_BOOL) {
+      zend_op *x = DEFINED_OP(op->op1);
+      SET_UNDEFINED(op->op1);
+      memcpy(&op->op1, &x->op1, sizeof(op->op1));
+      SET_TO_NOP(x);
+    /* BOOL_NOT + BOOL     => NOP + BOOL_NOT
+       BOOL_NOT + BOOL_NOT => NOP + BOOL
+       BOOL_NOT + JMP...   => NOP + JMP[n]...
+    */
+    } else if ((op->opcode == ZEND_BOOL ||
+                op->opcode == ZEND_BOOL_NOT ||
+                op->opcode == ZEND_JMPZ||
+                op->opcode == ZEND_JMPNZ) &&
+                op->op1.op_type == IS_TMP_VAR &&
+                (!global[VAR_NUM(op->op1.u.var)] ||
+                 (op->result.op_type == IS_TMP_VAR &&
+                  op->op1.u.var == op->result.u.var)) &&
+                IS_DEFINED(op->op1) &&
+                DEFINED_OP(op->op1)->opcode == ZEND_BOOL_NOT) {
+      zend_op *x = DEFINED_OP(op->op1);
+      switch (op->opcode) {
+        case ZEND_BOOL:     op->opcode = ZEND_BOOL_NOT; break;
+        case ZEND_BOOL_NOT: op->opcode = ZEND_BOOL;     break;
+        case ZEND_JMPZ:     op->opcode = ZEND_JMPNZ;    break;
+        case ZEND_JMPNZ:    op->opcode = ZEND_JMPZ;     break;
+      }
+      SET_UNDEFINED(op->op1);
+      memcpy(&op->op1, &x->op1, sizeof(op->op1));
+      SET_TO_NOP(x);
+    /* function_exists(STR) or is_callable(STR) */
+    } else if ((op->opcode == ZEND_BOOL ||
+                op->opcode == ZEND_BOOL_NOT ||
+                op->opcode == ZEND_JMPZ||
+                op->opcode == ZEND_JMPNZ ||
+                op->opcode == ZEND_JMPZNZ ||
+                op->opcode == ZEND_JMPZ_EX ||
+                op->opcode == ZEND_JMPNZ_EX) &&
+                op->op1.op_type == IS_VAR &&
+                !global[VAR_NUM(op->op1.u.var)] &&
+                IS_DEFINED(op->op1) &&
+                DEFINED_OP(op->op1)->opcode == ZEND_DO_FCALL &&
+                DEFINED_OP(op->op1)->extended_value == 1 &&
+                DEFINED_OP(op->op1)->op1.op_type == IS_CONST &&
+                DEFINED_OP(op->op1)->op1.u.constant.type == IS_STRING) {
+      zend_op* call = DEFINED_OP(op->op1);
+      zend_op* send = call-1;
+      if (send->opcode == ZEND_SEND_VAL &&
+          send->extended_value == ZEND_DO_FCALL &&
+          send->op1.op_type == IS_CONST &&
+          send->op1.u.constant.type == IS_STRING &&
+          (strcmp(call->op1.u.constant.value.str.val,"function_exists") == 0 ||
+           strcmp(call->op1.u.constant.value.str.val,"is_callable") == 0)) {
+        if (opt_function_exists(send->op1.u.constant.value.str.val, send->op1.u.constant.value.str.len  TSRMLS_CC)) {
+          SET_UNDEFINED(op->op1);
+          zval_dtor(&send->op1.u.constant);
+          SET_TO_NOP(send);
+          zval_dtor(&call->op1.u.constant);
+          SET_TO_NOP(call);
+          op->op1.op_type = IS_CONST;
+          op->op1.u.constant.type = IS_BOOL;
+          op->op1.u.constant.value.lval = 1;
+        }
+      } else if (send->opcode == ZEND_SEND_VAL &&
+          send->extended_value == ZEND_DO_FCALL &&
+          send->op1.op_type == IS_CONST &&
+          send->op1.u.constant.type == IS_STRING &&
+          strcmp(call->op1.u.constant.value.str.val,"extension_loaded") == 0) {
+        if (opt_extension_loaded(send->op1.u.constant.value.str.val, send->op1.u.constant.value.str.len  TSRMLS_CC)) {
+          SET_UNDEFINED(op->op1);
+          zval_dtor(&send->op1.u.constant);
+          SET_TO_NOP(send);
+          zval_dtor(&call->op1.u.constant);
+          SET_TO_NOP(call);
+          op->op1.op_type = IS_CONST;
+          op->op1.u.constant.type = IS_BOOL;
+          op->op1.u.constant.value.lval = 1;
+        }
+      } else if (send->opcode == ZEND_SEND_VAL &&
+          send->extended_value == ZEND_DO_FCALL &&
+          send->op1.op_type == IS_CONST &&
+          send->op1.u.constant.type == IS_STRING &&
+          strcmp(call->op1.u.constant.value.str.val,"defined") == 0) {
+        zend_constant *c = NULL;
+        if (opt_get_constant(send->op1.u.constant.value.str.val, send->op1.u.constant.value.str.len, &c TSRMLS_CC) && c != NULL && ((c->flags & CONST_PERSISTENT) != 0)) {
+          SET_UNDEFINED(op->op1);
+          zval_dtor(&send->op1.u.constant);
+          SET_TO_NOP(send);
+          zval_dtor(&call->op1.u.constant);
+          SET_TO_NOP(call);
+          op->op1.op_type = IS_CONST;
+          op->op1.u.constant.type = IS_BOOL;
+          op->op1.u.constant.value.lval = 1;
+        }
+      }
+    /* QM_ASSIGN($x,$x) => NOP */
+    } else if (op->opcode == ZEND_QM_ASSIGN &&
+               op->op1.op_type == IS_TMP_VAR &&
+               op->result.op_type == IS_TMP_VAR &&
+               op->op1.u.var == op->result.u.var) {
+      SET_TO_NOP(op);
+    /* ?(,,$tmp_x) +QM_ASSIGN($tmp_x,$tmp_y) => ?(,,$tmp_y) + NOP */
+    } else if (op->opcode == ZEND_QM_ASSIGN &&
+               op->op1.op_type == IS_TMP_VAR &&
+               !global[VAR_NUM(op->op1.u.var)] &&
+               op->op1.u.var != op->result.u.var &&
+               IS_DEFINED(op->op1)) {
+      zend_op *x = DEFINED_OP(op->op1);
+      if (x->opcode != ZEND_ADD_ARRAY_ELEMENT &&
+          x->opcode != ZEND_ADD_STRING &&
+          x->opcode != ZEND_ADD_CHAR &&
+          x->opcode != ZEND_ADD_VAR) {
+        SET_UNDEFINED(op->op1);
+        memcpy(&x->result, &op->result, sizeof(op->result));
+        SET_DEFINED(x);
+        SET_TO_NOP(op);
+      }
+    /* ECHO(const) + ECHO(const) => ECHO(const) */
+    } else if (prev != NULL &&
+               op->opcode == ZEND_ECHO &&
+               op->op1.op_type == IS_CONST &&
+               prev->opcode == ZEND_ECHO &&
+               prev->op1.op_type == IS_CONST) {
+      int len;
+      convert_to_string(&prev->op1.u.constant);
+      convert_to_string(&op->op1.u.constant);
+      len = prev->op1.u.constant.value.str.len + op->op1.u.constant.value.str.len;
+      STR_REALLOC(prev->op1.u.constant.value.str.val,len+1);
+      memcpy(prev->op1.u.constant.value.str.val+prev->op1.u.constant.value.str.len,
+             op->op1.u.constant.value.str.val, op->op1.u.constant.value.str.len);
+      prev->op1.u.constant.value.str.val[len] = 0;
+      prev->op1.u.constant.value.str.len = len;
+      STR_FREE(op->op1.u.constant.value.str.val);
+      SET_TO_NOP(op);
+    /* END_SILENCE + BEGIN_SILENCE => NOP + NOP */
+    } else if (prev != NULL &&
+               prev->opcode == ZEND_END_SILENCE &&
+               op->opcode == ZEND_BEGIN_SILENCE) {
+      zend_op *x = op+1;
+      while (x < end) {
+        if (x->opcode == ZEND_END_SILENCE &&
+            x->op1.u.var == op->result.u.var) {
+          x->op1.u.var = prev->op1.u.var;
+          SET_TO_NOP(prev);
+          SET_TO_NOP(op);
+          break;
+        }
+        x++;
+      }
+    /* BEGIN_SILENCE + END_SILENCE => NOP + NOP */
+    } else if (prev != NULL &&
+               prev->opcode == ZEND_BEGIN_SILENCE &&
+               op->opcode == ZEND_END_SILENCE &&
+               prev->result.u.var == op->op1.u.var) {
+      SET_TO_NOP(prev);
+      SET_TO_NOP(op);
+    /* SEND_VAR_NO_REF => SEND_VAR (cond) */
+    } else if (op->opcode == ZEND_SEND_VAR_NO_REF &&
+               (op->extended_value & ZEND_ARG_COMPILE_TIME_BOUND) &&
+               !(op->extended_value & ZEND_ARG_SEND_BY_REF)) {
+      op->opcode = ZEND_SEND_VAR;
+      op->extended_value = ZEND_DO_FCALL;
+    /* INIT_FCALL_BY_NAME + DO_FCALL_BY_NAME => DO_FCALL $x */
+    } else if (prev != NULL &&
+               op->opcode == ZEND_DO_FCALL_BY_NAME &&
+               op->extended_value == 0 &&
+               op->op1.op_type == IS_CONST &&
+               op->op1.u.constant.type == IS_STRING &&
+               prev->opcode == ZEND_INIT_FCALL_BY_NAME &&
+               prev->op1.op_type == IS_UNUSED &&
+               prev->op2.op_type == IS_CONST &&
+               prev->op2.u.constant.type == IS_STRING &&
+               op->op1.u.constant.value.str.len == prev->op2.u.constant.value.str.len &&
+               (memcmp(op->op1.u.constant.value.str.val,prev->op2.u.constant.value.str.val,op->op1.u.constant.value.str.len) == 0)) {
+       op->opcode = ZEND_DO_FCALL;
+       STR_FREE(prev->op2.u.constant.value.str.val);
+       SET_TO_NOP(prev);
+    /* SEND_REF $x + FCALL "reset" => FE_RESET $x */
+    } else if (prev != NULL &&
+               prev->opcode == ZEND_SEND_REF &&
+               prev->extended_value == ZEND_DO_FCALL &&
+               prev->op1.op_type == IS_VAR &&
+               prev->op2.u.opline_num == 1 &&
+               op->opcode == ZEND_DO_FCALL &&
+               op->extended_value == 1 &&
+               op->op1.op_type == IS_CONST &&
+               op->op1.u.constant.type == IS_STRING &&
+               op->op1.u.constant.value.str.len == (sizeof("reset")-1) &&
+               (memcmp(op->op1.u.constant.value.str.val, "reset", sizeof("reset")-1) == 0) &&
+               op->result.op_type == IS_VAR &&
+               ((op->result.u.EA.type & EXT_TYPE_UNUSED) != 0)) {
+      STR_FREE(op->op1.u.constant.value.str.val);
+      prev->opcode = ZEND_FE_RESET;
+      prev->extended_value = 1;
+      prev->op2.op_type = IS_UNUSED;
+      memcpy(&prev->result, &op->result, sizeof(op->result));
+      if (op->result.op_type == IS_VAR &&
+          (op->result.u.EA.type & EXT_TYPE_UNUSED) == 0) {
+        SET_DEFINED(prev);
+        SET_TO_NOP(op);
+      } else {
+        prev->result.u.EA.type &= ~EXT_TYPE_UNUSED;
+        op->opcode = ZEND_SWITCH_FREE;
+        op->extended_value = 1;
+        memcpy(&op->op1,&prev->result,sizeof(prev->result));
+        op->op2.op_type = IS_UNUSED;
+        op->result.op_type = IS_UNUSED;
+      }
+    }
+
+    /* $a = $a + ? => $a+= ? */
+    if (op->opcode == ZEND_ASSIGN &&
+        op->op1.op_type == IS_VAR &&
+        op->op2.op_type == IS_TMP_VAR &&
+        IS_DEFINED(op->op1) &&
+        IS_DEFINED(op->op2)) {
+      zend_op* l = DEFINED_OP(op->op1);
+      zend_op* r = DEFINED_OP(op->op2);
+      if (l->opcode == ZEND_FETCH_W &&
+          l->op1.op_type == IS_CONST &&
+          l->op1.u.constant.type == IS_STRING &&
+          (r->opcode  == ZEND_ADD ||
+           r->opcode  == ZEND_SUB ||
+           r->opcode  == ZEND_MUL ||
+           r->opcode  == ZEND_DIV ||
+           r->opcode  == ZEND_MOD ||
+           r->opcode  == ZEND_SL ||
+           r->opcode  == ZEND_SR ||
+           r->opcode  == ZEND_CONCAT ||
+           r->opcode  == ZEND_BW_OR ||
+           r->opcode  == ZEND_BW_AND ||
+           r->opcode  == ZEND_BW_XOR) &&
+         r->op1.op_type == IS_VAR &&
+         IS_DEFINED(r->op1)) {
+        zend_op* rl = DEFINED_OP(r->op1);
+        if (rl->opcode == ZEND_FETCH_R &&
+            rl->op1.op_type == IS_CONST &&
+            rl->op1.u.constant.type == IS_STRING &&
+            FETCH_TYPE(rl) == FETCH_TYPE(l) &&
+            l->op1.u.constant.value.str.len ==
+              rl->op1.u.constant.value.str.len &&
+            memcmp(l->op1.u.constant.value.str.val,
+              rl->op1.u.constant.value.str.val,
+              l->op1.u.constant.value.str.len) == 0) {
+          switch (r->opcode) {
+            case ZEND_ADD:    op->opcode = ZEND_ASSIGN_ADD; break;
+            case ZEND_SUB:    op->opcode = ZEND_ASSIGN_SUB; break;
+            case ZEND_MUL:    op->opcode = ZEND_ASSIGN_MUL; break;
+            case ZEND_DIV:    op->opcode = ZEND_ASSIGN_DIV; break;
+            case ZEND_MOD:    op->opcode = ZEND_ASSIGN_MOD; break;
+            case ZEND_SL:     op->opcode = ZEND_ASSIGN_SL;  break;
+            case ZEND_SR:     op->opcode = ZEND_ASSIGN_SR;  break;
+            case ZEND_CONCAT: op->opcode = ZEND_ASSIGN_CONCAT; break;
+            case ZEND_BW_OR:  op->opcode = ZEND_ASSIGN_BW_OR;  break;
+            case ZEND_BW_AND: op->opcode = ZEND_ASSIGN_BW_AND; break;
+            case ZEND_BW_XOR: op->opcode = ZEND_ASSIGN_BW_XOR; break;
+            default:
+              break;
+          }
+          memcpy(&op->op2, &r->op2, sizeof(op->op2));
+          l->opcode = ZEND_FETCH_RW;
+          SET_TO_NOP(r);
+          STR_FREE(rl->op1.u.constant.value.str.val);
+          SET_TO_NOP(rl);
+        }
+      }
+    }
+
+    if (pass == 1) {
+      /* FETCH_W var,$x + ASSIGN $x,?,_  + FETCH_R var,$y =>
+         FETCH_W var,$x + ASSIGN $x,?,$y */
+      if (op->opcode == ZEND_UNSET_VAR ||
+          op->opcode == ZEND_DO_FCALL ||
+          op->opcode == ZEND_DO_FCALL_BY_NAME ||
+          op->opcode == ZEND_POST_INC ||
+          op->opcode == ZEND_POST_DEC ||
+          op->opcode == ZEND_UNSET_DIM_OBJ ||
+          op->opcode == ZEND_INCLUDE_OR_EVAL
+#ifdef ZEND_ENGINE_2
+          || op->opcode == ZEND_ASSIGN_DIM
+          || op->opcode == ZEND_ASSIGN_OBJ
+#endif
+          ) {
+        zend_hash_clean(&assigns);
+        zend_hash_clean(&fetch_dim);
+      } else if (op->opcode == ZEND_ASSIGN_REF ||
+                 op->opcode == ZEND_ASSIGN ||
+                 op->opcode == ZEND_PRE_INC ||
+                 op->opcode == ZEND_PRE_DEC ||
+                 op->opcode == ZEND_ASSIGN_ADD ||
+                 op->opcode == ZEND_ASSIGN_SUB ||
+                 op->opcode == ZEND_ASSIGN_MUL ||
+                 op->opcode == ZEND_ASSIGN_DIV ||
+                 op->opcode == ZEND_ASSIGN_MOD ||
+                 op->opcode == ZEND_ASSIGN_SL ||
+                 op->opcode == ZEND_ASSIGN_SR ||
+                 op->opcode == ZEND_ASSIGN_CONCAT ||
+                 op->opcode == ZEND_ASSIGN_BW_OR ||
+                 op->opcode == ZEND_ASSIGN_BW_AND ||
+                 op->opcode == ZEND_ASSIGN_BW_XOR) {
+        zend_hash_clean(&assigns);
+        zend_hash_clean(&fetch_dim);
+        if ((op->result.u.EA.type & EXT_TYPE_UNUSED) != 0 &&
+            op->op1.op_type == IS_VAR &&
+            IS_DEFINED(op->op1)) {
+          zend_op *x = DEFINED_OP(op->op1);
+          if ((x->opcode == ZEND_FETCH_W || x->opcode == ZEND_FETCH_RW) &&
+              x->op1.op_type == IS_CONST &&
+              x->op1.u.constant.type == IS_STRING) {
+            char *s = emalloc(x->op1.u.constant.value.str.len+2);
+            memcpy(s,x->op1.u.constant.value.str.val,x->op1.u.constant.value.str.len);
+            s[x->op1.u.constant.value.str.len] = (char)FETCH_TYPE(x);
+            s[x->op1.u.constant.value.str.len+1] = '\0';
+            zend_hash_update(&assigns,
+                             s, x->op1.u.constant.value.str.len+2,
+                             (void**)&op, sizeof(void*), NULL);
+            efree(s);
+          }
+        }
+      } else if ((op->opcode == ZEND_FETCH_R ||
+                  op->opcode == ZEND_FETCH_IS) &&
+                 !global[VAR_NUM(op->result.u.var)] &&
+                 op->op1.op_type == IS_CONST &&
+                 op->op1.u.constant.type == IS_STRING) {
+        zend_op *x;
+        char *s = emalloc(op->op1.u.constant.value.str.len+2);
+        memcpy(s,op->op1.u.constant.value.str.val,op->op1.u.constant.value.str.len);
+        s[op->op1.u.constant.value.str.len] = (char)FETCH_TYPE(op);
+        s[op->op1.u.constant.value.str.len+1] = '\0';
+
+        if (zend_hash_find(&assigns,
+                           s, op->op1.u.constant.value.str.len+2,
+                           (void**)&x) == SUCCESS) {
+          x = *(zend_op**)x;
+/*
+          if (x->opcode == ZEND_ASSIGN && x->op2.op_type == IS_CONST) {
+            zend_printf("possible const propogation in %s:%s (%s,%u:%u)<br>\n",op_array->filename, op_array->function_name, op->op1.u.constant.value.str.val, x-op_array->opcodes, op-op_array->opcodes);
+          }
+*/
+          memcpy(&x->result, &op->result, sizeof(op->result));
+          x->result.u.EA.type = 0;
+          SET_DEFINED(x);
+          zend_hash_del(&assigns,
+                        s, op->op1.u.constant.value.str.len+2);
+          STR_FREE(op->op1.u.constant.value.str.val);
+          SET_TO_NOP(op);
+        }
+        efree(s);
+      } else if (op->opcode == ZEND_FETCH_DIM_R &&
+                 op->extended_value != ZEND_FETCH_ADD_LOCK &&
+                 op->op1.op_type == IS_VAR &&
+                 IS_DEFINED(op->op1)) {
+        zend_op *x = DEFINED_OP(op->op1);
+        while ((x->opcode == ZEND_ASSIGN_REF ||
+                x->opcode == ZEND_ASSIGN ||
+                x->opcode == ZEND_PRE_INC ||
+                x->opcode == ZEND_PRE_DEC ||
+                x->opcode == ZEND_ASSIGN_ADD ||
+                x->opcode == ZEND_ASSIGN_SUB ||
+                x->opcode == ZEND_ASSIGN_MUL ||
+                x->opcode == ZEND_ASSIGN_DIV ||
+                x->opcode == ZEND_ASSIGN_MOD ||
+                x->opcode == ZEND_ASSIGN_SL ||
+                x->opcode == ZEND_ASSIGN_SR ||
+                x->opcode == ZEND_ASSIGN_CONCAT ||
+                x->opcode == ZEND_ASSIGN_BW_OR ||
+                x->opcode == ZEND_ASSIGN_BW_AND ||
+                x->opcode == ZEND_ASSIGN_BW_XOR) &&
+                x->op1.op_type == IS_VAR &&
+                IS_DEFINED(x->op1)) {
+          x = DEFINED_OP(x->op1);
+        }
+        if ((x->opcode == ZEND_FETCH_R ||
+             x->opcode == ZEND_FETCH_W ||
+             x->opcode == ZEND_FETCH_RW) &&
+             x->op1.op_type == IS_CONST &&
+             x->op1.u.constant.type == IS_STRING) {
+          zend_op *y;
+          char *s = emalloc(x->op1.u.constant.value.str.len+2);
+          memcpy(s,x->op1.u.constant.value.str.val,x->op1.u.constant.value.str.len);
+          s[x->op1.u.constant.value.str.len] = (char)FETCH_TYPE(x);
+          s[x->op1.u.constant.value.str.len+1] = '\0';
+          if (zend_hash_find(&fetch_dim,
+                             s, x->op1.u.constant.value.str.len+2,
+                             (void**)&y) == SUCCESS) {
+            y = *(zend_op**)y;
+            y->extended_value = ZEND_FETCH_ADD_LOCK;
+            zend_hash_update(&fetch_dim,
+                             s, x->op1.u.constant.value.str.len+2,
+                             (void**)&op, sizeof(void*), NULL);
+            SET_UNDEFINED(x->result);
+            STR_FREE(x->op1.u.constant.value.str.val);
+            SET_TO_NOP(x);
+            memcpy(&op->op1,&y->op1,sizeof(op->op1));
+          } else {
+            zend_hash_update(&fetch_dim,
+                             s, x->op1.u.constant.value.str.len+2,
+                             (void**)&op, sizeof(void*), NULL);
+          }
+          efree(s);
+        }
+      }
+    }
+
+    if (op->opcode != ZEND_NOP) {
+      prev = op;
+    }
+    if ((op->result.op_type == IS_VAR &&
+#ifdef ZEND_ENGINE_2
+        (op->opcode == ZEND_RECV || op->opcode == ZEND_RECV_INIT ||
+         (op->result.u.EA.type & EXT_TYPE_UNUSED) == 0)) ||
+#else
+        (op->result.u.EA.type & EXT_TYPE_UNUSED) == 0) ||
+#endif
+        (op->result.op_type == IS_TMP_VAR)) {
+      if (op->opcode == ZEND_RECV ||
+          op->opcode == ZEND_RECV_INIT) {
+        SET_UNDEFINED(op->result);
+      } else {
+        SET_DEFINED(op);
+      }
+    }
+    ++op;
+  }
+
+  /* NOP Removing */
+  op = bb->start;
+  end = op + bb->len;
+  while (op < end) {
+    if (op->opcode == ZEND_NOP) {
+      zend_op *next = op+1;
+      while (next < end && next->opcode == ZEND_NOP) next++;
+      if (next < end) {
+        memcpy(op,next,(end-next) * sizeof(zend_op));
+        while (next > op) {
+          --end;
+          SET_TO_NOP(end);
+          --next;
+        }
+      } else {
+        end -= (next-op);
+      }
+    } else {
+      ++op;
+    }
+  }
+  bb->len = end - bb->start;
+  zend_hash_destroy(&fetch_dim);
+  zend_hash_destroy(&assigns);
+  free_alloca(Ts);
+}
+
+/*
+ * Find All Basic Blocks in op_array and build Control Flow Graph (CFG)
+ */
+static int build_cfg(zend_op_array *op_array, BB* bb)
+{
+	zend_op* op = op_array->opcodes;
+	int len = op_array->last;
+	int line_num;
+	BB* p;
+	int remove_brk_cont_array = 1;
+#ifndef ZEND_ENGINE_2
+	int* overload_var = do_alloca(op_array->T * sizeof(int));
+	memset(overload_var,-1,op_array->T * sizeof(int));
+#else
+	/* HOESH: Just to use later... */
+	zend_uint innermost_ketchup;
+
+	/* HOESH: Mark try & catch blocks */
+	if (op_array->last_try_catch > 0)
+	{
+		int i;
+		zend_try_catch_element* tc_element = op_array->try_catch_array;
+		for (i=0; i<op_array->last_try_catch; i++, tc_element++)
+		{
+			bb[tc_element->try_op].start = &op_array->opcodes[tc_element->try_op];
+			bb[tc_element->try_op].protect_merge = 1;
+
+			bb[tc_element->catch_op].start = &op_array->opcodes[tc_element->catch_op];
+			bb[tc_element->catch_op].protect_merge = 1;
+		}
+	}
+#endif
+	/* Find Starts of Basic Blocks */
+	bb[0].start = op;
+	for (line_num=0; line_num < len; op++,line_num++)
+	{
+#ifdef ZEND_ENGINE_2
+		const opcode_dsc* dsc = get_opcode_dsc(op->opcode);
+		if (dsc != NULL)
+		{
+			if ((dsc->ops & OP1_MASK) == OP1_UCLASS)
+			{
+				if (op->op1.op_type != IS_UNUSED)
+				{
+					op->op1.op_type = IS_VAR;
+				}
+			}
+			else if ((dsc->ops & OP1_MASK) == OP1_CLASS)
+			{
+				op->op1.op_type = IS_VAR;
+			}
+			else if ((dsc->ops & OP1_MASK) == OP1_UNUSED)
+			{
+				op->op1.op_type = IS_UNUSED;
+			}
+			if ((dsc->ops & OP2_MASK) == OP2_CLASS)
+			{
+				op->op2.op_type = IS_VAR;
+			}
+			else if ((dsc->ops & OP2_MASK) == OP2_UNUSED)
+			{
+				op->op2.op_type = IS_UNUSED;
+			}
+			else if ((dsc->ops & OP2_MASK) == OP2_FETCH &&
+					op->op2.u.EA.type == ZEND_FETCH_STATIC_MEMBER)
+			{
+				op->op2.op_type = IS_VAR;
+			}
+			if ((dsc->ops & RES_MASK) == RES_CLASS)
+			{
+				op->result.op_type = IS_VAR;
+				op->result.u.EA.type &= ~EXT_TYPE_UNUSED;
+			}
+			else if ((dsc->ops & RES_MASK) == RES_UNUSED)
+			{
+				op->result.op_type = IS_UNUSED;
+			}
+		}
+#endif
+		switch(op->opcode)
+		{
+			case ZEND_RETURN:
+			case ZEND_EXIT:
+				bb[line_num+1].start = op+1;
+				break;
+			case ZEND_JMP:
+				bb[op->op1.u.opline_num].start = &op_array->opcodes[op->op1.u.opline_num];
+				bb[line_num+1].start = op+1;
+				break;
+			case ZEND_JMPZNZ:
+				bb[op->extended_value].start = &op_array->opcodes[op->extended_value];
+				bb[op->op2.u.opline_num].start = &op_array->opcodes[op->op2.u.opline_num];
+				bb[line_num+1].start = op+1;
+				break;
+			case ZEND_JMPZ:
+			case ZEND_JMPNZ:
+			case ZEND_JMPZ_EX:
+			case ZEND_JMPNZ_EX:
+			case ZEND_JMP_NO_CTOR:
+			case ZEND_FE_FETCH:
+				bb[line_num+1].start = op+1;
+				bb[op->op2.u.opline_num].start = &op_array->opcodes[op->op2.u.opline_num];
+				break;
+			case ZEND_BRK:
+				/* Replace BRK by JMP */
+				if (op->op1.u.opline_num == -1)
+				{
+				}
+				else if (op->op2.op_type == IS_CONST &&
+						op->op2.u.constant.type == IS_LONG)
+				{
+					int level  = op->op2.u.constant.value.lval;
+					zend_uint offset = op->op1.u.opline_num;
+					zend_brk_cont_element *jmp_to;
+					do
+					{
+						if (offset < 0 || offset >= op_array->last_brk_cont)
+						{
+							goto brk_failed;
+						}
+						jmp_to = &op_array->brk_cont_array[offset];
+						if (level>1 &&
+							(op_array->opcodes[jmp_to->brk].opcode == ZEND_SWITCH_FREE ||
+							op_array->opcodes[jmp_to->brk].opcode == ZEND_FREE))
+						{
+							goto brk_failed;
+						}
+						offset = jmp_to->parent;
+					}
+					while (--level > 0);
+					op->opcode = ZEND_JMP;
+					op->op1.u.opline_num = jmp_to->brk;
+					op->op2.op_type = IS_UNUSED;
+					bb[op->op1.u.opline_num].start = &op_array->opcodes[jmp_to->brk];
+				}
+				else
+				{
+brk_failed:
+				  remove_brk_cont_array = 0;
+				}
+				bb[line_num+1].start = op+1;
+				break;
+			case ZEND_CONT:
+				/* Replace CONT by JMP */
+				if (op->op1.u.opline_num == -1)
+				{
+				}
+				else if (op->op2.op_type == IS_CONST &&
+						op->op2.u.constant.type == IS_LONG)
+				{
+				int level  = op->op2.u.constant.value.lval;
+				zend_uint offset = op->op1.u.opline_num;
+				zend_brk_cont_element *jmp_to;
+				do
+				{
+					if (offset < 0 || offset >= op_array->last_brk_cont)
+					{
+						goto cont_failed;
+					}
+					jmp_to = &op_array->brk_cont_array[offset];
+					if (level>1 &&
+						(op_array->opcodes[jmp_to->brk].opcode == ZEND_SWITCH_FREE ||
+						op_array->opcodes[jmp_to->brk].opcode == ZEND_FREE))
+					{
+						goto cont_failed;
+					}
+					offset = jmp_to->parent;
+				}
+				while (--level > 0);
+				op->opcode = ZEND_JMP;
+				op->op1.u.opline_num = jmp_to->cont;
+				op->op2.op_type = IS_UNUSED;
+				bb[op->op1.u.opline_num].start = &op_array->opcodes[jmp_to->cont];
+				}
+				else
+				{
+cont_failed:
+					remove_brk_cont_array = 0;
+				}
+				bb[line_num+1].start = op+1;
+				break;
+#ifdef ZEND_ENGINE_2
+			case ZEND_CATCH:
+				bb[op->extended_value].start = &op_array->opcodes[op->extended_value];
+				bb[line_num+1].start = op+1;
+				break;
+			case ZEND_THROW:
+				if (op->op2.u.opline_num != -1)
+				{
+					bb[op->op2.u.opline_num].start = &op_array->opcodes[op->op2.u.opline_num];
+				}
+				bb[line_num+1].start = op+1;
+				break;
+			case ZEND_DO_FCALL:
+			case ZEND_DO_FCALL_BY_NAME:
+				if (op->op2.u.opline_num != -1)
+				{
+					bb[op->op2.u.opline_num].start = &op_array->opcodes[op->op2.u.opline_num];
+					bb[line_num+1].start = op+1;
+				}
+				break;
+#else
+			case ZEND_INIT_FCALL_BY_NAME:
+				if (op->op1.op_type == IS_VAR && op->result.op_type == IS_VAR)
+				{
+					overload_var[op->result.u.var] = op->op1.u.var;
+					op->result.u.var = op->op1.u.var;
+				}
+				break;
+			case ZEND_DO_FCALL_BY_NAME:
+				if (op->op1.op_type == IS_VAR && overload_var[op->op1.u.var] >= 0)
+				{
+					op->op1.u.var = overload_var[op->op1.u.var];
+				}
+				break;
+#endif
+			case ZEND_UNSET_VAR:
+			case ZEND_UNSET_DIM_OBJ:
+				op->result.op_type = IS_UNUSED;
+				break;
+			default:
+				break;
+		}
+	}
+
+#ifndef ZEND_ENGINE_2
+	free_alloca(overload_var);
+#endif
+
+	/* Find Lengths of Basic Blocks and build CFG */
+	p = bb;
+	for (line_num=1; line_num < len; line_num++)
+	{
+#ifdef ZEND_ENGINE_2
+		/* Calculate innermost CATCH op */
+		innermost_ketchup = 0;
+		if (op_array->last_try_catch > 0)
+		{
+			int i;
+			zend_try_catch_element* tc_element = op_array->try_catch_array;
+			for (i=0; i<op_array->last_try_catch; i++, tc_element++)
+			{
+				if (tc_element->try_op <= line_num-1 &&
+					line_num-1 < tc_element->catch_op &&
+						(innermost_ketchup == 0 ||
+						innermost_ketchup > tc_element->catch_op)
+					)
+				{
+					innermost_ketchup = tc_element->catch_op;
+				}
+			}
+		}
+#endif
+		if (bb[line_num].start != NULL)
+		{
+			p->len  = bb[line_num].start - p->start;
+			p->next = &bb[line_num];
+			op = &p->start[p->len-1];
+			switch (op->opcode)
+			{
+				case ZEND_JMP:
+					p->jmp_1 = &bb[op->op1.u.opline_num];
+					break;
+				case ZEND_JMPZNZ:
+					p->jmp_2 = &bb[op->op2.u.opline_num];
+					p->jmp_ext = &bb[op->extended_value];
+					break;
+				case ZEND_JMPZ:
+				case ZEND_JMPNZ:
+				case ZEND_JMPZ_EX:
+				case ZEND_JMPNZ_EX:
+				case ZEND_JMP_NO_CTOR:
+				case ZEND_FE_FETCH:
+					p->jmp_2 = &bb[op->op2.u.opline_num];
+					p->follow = &bb[line_num];
+					break;
+				case ZEND_RETURN:
+				case ZEND_EXIT:
+				case ZEND_BRK:
+				case ZEND_CONT:
+#ifdef ZEND_ENGINE_2
+					/* HOESH: The control might flow to the innermost CATCH
+					 * op if an exception thrown earlier. We can follow to CATCH
+					 * to protect it against unnecessary K.O. In that case,
+					 * the last RETURN will hold HANDLE_EXCEPTION.
+					 * If no CATCH op toward, then glue it to the last opcode,
+					 * that is HANDLE_EXCEPTION.
+					 */
+					p->follow = (innermost_ketchup > 0) ? &bb[innermost_ketchup] : &bb[len-1];
+					break;
+				case ZEND_DO_FCALL:
+				case ZEND_DO_FCALL_BY_NAME:
+					if (op->op2.u.opline_num != -1)
+					{
+						p->jmp_2 = &bb[op->op2.u.opline_num];
+					}
+					p->follow = &bb[line_num];
+					break;
+				case ZEND_CATCH:
+					p->jmp_ext = &bb[op->extended_value];
+					p->follow = &bb[line_num];
+					break;
+				case ZEND_THROW:
+					if (op->op2.u.opline_num != -1)
+					{
+						p->jmp_2 = &bb[op->op2.u.opline_num];
+					}
+					p->follow = &bb[line_num];
+#endif
+					break;
+				default:
+					p->follow = &bb[line_num];
+			}
+			p = &bb[line_num];
+		}
+	}
+	p->len = (op_array->opcodes + op_array->last) - p->start;
+
+	/* Remove Unused brk_cont_array (BRK and COND instructions replaced by JMP)*/
+	if (remove_brk_cont_array)
+	{
+		if (op_array->brk_cont_array != NULL)
+		{
+			efree(op_array->brk_cont_array);
+			op_array->brk_cont_array = NULL;
+		}
+		op_array->last_brk_cont = 0;
+	}
+	return remove_brk_cont_array;
+}
+
+/*
+ * Emits Optimized Code
+ */
+static void emit_cfg(zend_op_array *op_array, BB* bb)
+{
+  /* Compacting Optimized Code */
+  BB* p = bb;
+  zend_op* start = op_array->opcodes;
+  zend_op* op = start;
+  zend_op* end = op + op_array->last;
+  while (p != NULL)
+  {
+    if (p->used)
+	{
+      if (p->len > 0 && op != p->start)
+	  {
+        memcpy(op, p->start, p->len * sizeof(zend_op));
+      }
+      p->start = op;
+      op += p->len;
+    }
+    p = p->next;
+  }
+  op_array->last = op - start;
+  op_array->start_op = NULL;
+  while (op < end)
+  {
+    SET_TO_NOP(op);
+    op++;
+  }
+
+  /* Set Branch Targets */
+  p = bb;
+  while (p != NULL) {
+    if (p->used)
+	{
+      if (p->jmp_1 != NULL)
+	  {
+        p->start[p->len-1].op1.u.opline_num = p->jmp_1->start - start;
+      }
+      if (p->jmp_2 != NULL)
+	  {
+        p->start[p->len-1].op2.u.opline_num = p->jmp_2->start - start;
+      }
+      if (p->jmp_ext != NULL)
+	  {
+        p->start[p->len-1].extended_value = p->jmp_ext->start - start;
+      }
+    }
+    p = p->next;
+  }
+
+#ifdef ZEND_ENGINE_2
+	/*
+	 * HOESH: Reassign try & catch blocks
+	 */
+	if (op_array->last_try_catch>0)
+	{
+		int i;
+		int last_try_catch = op_array->last_try_catch;
+		zend_try_catch_element* old_tc_element = op_array->try_catch_array;
+		for (i=0; i<op_array->last_try_catch; i++, old_tc_element++)
+		{
+			if (bb[old_tc_element->try_op].used &&
+				bb[old_tc_element->catch_op].used)
+			{
+				old_tc_element->try_op = bb[old_tc_element->try_op].start - start;
+				old_tc_element->catch_op = bb[old_tc_element->catch_op].start - start;
+			}
+			else
+			{
+				old_tc_element->try_op = 0;
+				old_tc_element->catch_op = 0;
+				last_try_catch--;
+			}
+		}
+		if (op_array->last_try_catch > last_try_catch)
+		{
+			zend_try_catch_element* new_tc_array = NULL;
+			if (last_try_catch > 0)
+			{
+				/* Lost some try & catch blocks */
+				zend_try_catch_element* new_tc_element = emalloc(sizeof(zend_try_catch_element)*last_try_catch);
+				new_tc_array = new_tc_element;
+				old_tc_element = op_array->try_catch_array;
+				for (i=0; i<op_array->last_try_catch; i++, old_tc_element++)
+				{
+					if (old_tc_element->try_op != old_tc_element->catch_op)
+					{
+						new_tc_element->try_op = old_tc_element->try_op;
+						new_tc_element->catch_op = old_tc_element->catch_op;
+						new_tc_element++;
+					}
+				}
+			}
+			/* Otherwise lost all try & catch blocks */
+			efree(op_array->try_catch_array);
+			op_array->try_catch_array = new_tc_array;
+			op_array->last_try_catch = last_try_catch;
+		}
+	}
+#endif
+}
+
+#define GET_REG(R) {\
+                     if (assigned[(R)] < 0) {\
+                       zend_uint j = 0;\
+                       while (j < op_array->T) {\
+                         if (reg_pool[j] == 0 &&\
+                             (global[(R)] == 0 || used[j] == 0)) {\
+                           reg_pool[j] = 1;\
+                           assigned[(R)] = j;\
+                           if (j+1 > n) {n = j+1;}\
+                           break;\
+                         }\
+                         j++;\
+                       }\
+                     }\
+                     used[assigned[(R)]] = 1;\
+                   }
+
+#define FREE_REG(R) reg_pool[(R)] = 0;
+
+
+void reassign_registers(zend_op_array *op_array, BB* p, char *global) {
+  zend_uint i;
+  zend_uint n = 0;
+  int uses_globals = 0;
+  int* assigned = do_alloca(op_array->T * sizeof(int));
+  char* reg_pool = do_alloca(op_array->T * sizeof(char));
+  char* used     = do_alloca(op_array->T * sizeof(char));
+
+  for (i = 0; i < op_array->T; i++) {
+    assigned[i] = -1;
+    reg_pool[i] = 0;
+    used[i] = 0;
+  }
+
+  while (p != NULL) {
+    if (p->used && p->len > 0) {
+      zend_op* start = p->start;
+      zend_op* op    = start + p->len;
+#ifdef ZEND_ENGINE_2
+      zend_op* op_data;
+#endif
+
+      for (i = 0; i < op_array->T; i++) {
+        if (!global[i]) {
+          if (assigned[i] >= 0) {reg_pool[assigned[i]] = 0;}
+          assigned[i] = -1;
+        }
+      }
+
+      while (start < op) {
+        --op;
+#ifdef ZEND_ENGINE_2
+        op_data = NULL;
+#else
+        if (op_array->uses_globals &&
+            (op->opcode == ZEND_FETCH_R ||
+             op->opcode == ZEND_FETCH_W ||
+             op->opcode == ZEND_FETCH_RW ||
+             op->opcode == ZEND_FETCH_IS ||
+             op->opcode == ZEND_FETCH_FUNC_ARG ||
+             op->opcode == ZEND_FETCH_UNSET) &&
+             op->op1.op_type == IS_CONST &&
+             op->op1.u.constant.type == IS_STRING &&
+             op->op1.u.constant.value.str.len == (sizeof("GLOBALS")-1) &&
+             memcmp(op->op1.u.constant.value.str.val, "GLOBALS", sizeof("GLOBALS")-1) == 0) {
+          uses_globals = 1;
+        }
+#endif
+        if (op->opcode == ZEND_DO_FCALL_BY_NAME &&
+            op->op1.op_type == IS_CONST) {
+          zval_dtor(&op->op1.u.constant);
+          op->op1.op_type = IS_UNUSED;
+        }
+        if (op->op1.op_type == IS_VAR || op->op1.op_type == IS_TMP_VAR) {
+          int r = VAR_NUM(op->op1.u.var);
+          GET_REG(r);
+          if (op->opcode == ZEND_DO_FCALL_BY_NAME) {
+            op->op1.op_type = IS_UNUSED;
+          } else {
+            op->op1.u.var = VAR_VAL(assigned[r]);
+          }
+        }
+        if (op->op2.op_type == IS_VAR || op->op2.op_type == IS_TMP_VAR) {
+          int r = VAR_NUM(op->op2.u.var);
+          GET_REG(r);
+          op->op2.u.var = VAR_VAL(assigned[r]);
+        }
+#ifdef ZEND_ENGINE_2
+        if (op->opcode == ZEND_DECLARE_INHERITED_CLASS) {
+          int r = VAR_NUM(op->extended_value);
+          GET_REG(r);
+          op->extended_value = VAR_VAL(assigned[r]);
+        }
+        if (op->opcode == ZEND_OP_DATA) {
+          op_data = op;
+          --op;
+          if (op->op1.op_type == IS_VAR || op->op1.op_type == IS_TMP_VAR) {
+            int r = VAR_NUM(op->op1.u.var);
+            GET_REG(r);
+            op->op1.u.var = VAR_VAL(assigned[r]);
+          }
+          if (op->op2.op_type == IS_VAR || op->op2.op_type == IS_TMP_VAR) {
+            int r = VAR_NUM(op->op2.u.var);
+            GET_REG(r);
+            op->op2.u.var = VAR_VAL(assigned[r]);
+          }
+        }
+#endif
+        if (op->result.op_type == IS_VAR ||
+            op->result.op_type == IS_TMP_VAR) {
+          int r = VAR_NUM(op->result.u.var);
+          GET_REG(r);
+          op->result.u.var = VAR_VAL(assigned[r]);
+          if (op->result.op_type == IS_VAR &&
+#ifdef ZEND_ENGINE_2
+              op->opcode != ZEND_RECV && op->opcode != ZEND_RECV_INIT &&
+#endif
+              ((op->result.u.EA.type & EXT_TYPE_UNUSED) != 0)) {
+            FREE_REG(VAR_NUM(op->result.u.var))
+          } else if (!(op->op1.op_type == op->result.op_type &&
+              op->op1.u.var == op->result.u.var) &&
+              !(op->op2.op_type == op->result.op_type &&
+              op->op2.u.var == op->result.u.var) &&
+              !global[r]) {
+            switch (op->opcode) {
+              case ZEND_RECV:
+              case ZEND_RECV_INIT:
+              case ZEND_ADD_ARRAY_ELEMENT:
+                break;
+              default:
+                FREE_REG(VAR_NUM(op->result.u.var));
+            }
+          }
+        }
+#ifdef ZEND_ENGINE_2
+        if (op_data != NULL && op_data->op2.op_type == IS_VAR) {
+          FREE_REG(VAR_NUM(op_data->op2.u.var));
+        }
+#endif
+      }
+    }
+    p = p->next;
+  }
+  op_array->T = n;
+#ifndef ZEND_ENGINE_2
+  if (op_array->uses_globals && !uses_globals) {
+    op_array->uses_globals = 0;
+  }
+#endif
+  free_alloca(used);
+  free_alloca(reg_pool);
+  free_alloca(assigned);
+}
+
+/*
+ * Main Optimization Routine
+ */
+void eaccelerator_optimize(zend_op_array *op_array)
+{
+  BB* p;
+  int i;
+  BB* bb;
+
+  TSRMLS_FETCH();
+/*???
+#ifdef ZEND_ENGINE_2
+  return;
+#endif
+*/
+  if (!MMCG(compiler) || op_array->type != ZEND_USER_FUNCTION) {
+    return;
+  }
+
+  /* Allocate memory for CFG */
+  if ((bb = do_alloca(sizeof(BB)*(op_array->last+1))) == NULL) return;
+  memset(bb, 0, sizeof(BB)*(op_array->last+1));
+
+  /* Find All Basic Blocks and build CFG */
+  if (build_cfg(op_array, bb)) {
+    char *global = do_alloca(op_array->T * sizeof(char));
+    if (global == NULL) return;
+
+    for (i=0; i<2; i++) {
+      /* Determine Used Blocks and its Predcessors */
+      mark_used_bb(bb);
+
+      /* JMP Optimization */
+      optimize_jmp(bb, op_array);
+      compute_live_var(bb, op_array, global);
+
+      /* Optimize Each Basic Block */
+      p = bb;
+      while (p != NULL) {
+        optimize_bb(p, op_array, global, i TSRMLS_CC);
+        p = p->next;
+      }
+
+      /* Mark All Basik Blocks as Unused. Free Predcessors Links. */
+      p = bb;
+      while (p != NULL) {
+        rm_bb(p);
+        p = p->next;
+      }
+    }
+    /* Mark Used Blocks */
+    mark_used_bb2(bb);
+
+    /* Remove Unused Basic Blocks */
+    p = bb;
+    while (p->next != NULL) {
+      if (p->next->used) {
+        p = p->next;
+      } else {
+        del_bb(p->next);
+        p->next = p->next->next;
+      }
+    }
+
+    /* Store Optimized Code */
+    emit_cfg(op_array, bb);
+    reassign_registers(op_array, bb, global);
+
+    free_alloca(global);
+  }
+  free_alloca(bb);
+}
+#endif
+#endif /* #ifdef HAVE_EACCELERATOR */
Index: /eaccelerator/trunk/Makefile.in
===================================================================
--- /eaccelerator/trunk/Makefile.in	(revision 4)
+++ /eaccelerator/trunk/Makefile.in	(revision 4)
@@ -0,0 +1,7 @@
+LTLIBRARY_NAME        = libeaccelerator.la
+LTLIBRARY_SOURCES     = eaccelerator.c optimize.c execute.c encoder.c loader.c opcodes.c content.c mm.c
+LTLIBRARY_SHARED_NAME = eaccelerator.la
+
+EXTRA_CFLAGS = -O3
+
+include $(top_srcdir)/build/dynlib.mk
Index: /eaccelerator/trunk/opcodes.h
===================================================================
--- /eaccelerator/trunk/opcodes.h	(revision 4)
+++ /eaccelerator/trunk/opcodes.h	(revision 4)
@@ -0,0 +1,109 @@
+/*
+   +----------------------------------------------------------------------+
+   | Turck MMCache for PHP Version 4                                      |
+   +----------------------------------------------------------------------+
+   | Copyright (c) 2002-2003 TurckSoft, St. Petersburg                    |
+   | http://www.turcksoft.com                                             |
+   +----------------------------------------------------------------------+
+   | This program is free software; you can redistribute it and/or        |
+   | modify it under the terms of the GNU General Public License          |
+   | as published by the Free Software Foundation; either version 2       |
+   | of the License, or (at your option) any later version.               |
+   |                                                                      |
+   | This program is distributed in the hope that it will be useful,      |
+   | but WITHOUT ANY WARRANTY; without even the implied warranty of       |
+   | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        |
+   | GNU General Public License for more details.                         |
+   |                                                                      |
+   | You should have received a copy of the GNU General Public License    |
+   | along with this program; if not, write to the Free Software          |
+   | Foundation, Inc., 59 Temple Place - Suite 330, Boston,               |
+   | MA  02111-1307, USA.                                                 |
+   |                                                                      |
+   | A copy is availble at http://www.gnu.org/copyleft/gpl.txt            |
+   +----------------------------------------------------------------------+
+   | Author: Dmitry Stogov <mmcache@turckware.ru>                         |
+   +----------------------------------------------------------------------+
+   $Id$
+*/
+
+#include "eaccelerator.h"
+
+#ifdef HAVE_EACCELERATOR
+
+#define EXT_MASK       0x0ff00
+#define EXT_UNUSED     0x0ff00
+#define EXT_STD        0x00000
+#define EXT_OPLINE     0x00100
+#define EXT_FCALL      0x00200
+#define EXT_ARG        0x00300
+#define EXT_SEND       0x00400
+#define EXT_CAST       0x00500
+#define EXT_INIT_FCALL 0x00600
+#define EXT_FETCH      0x00700
+#define EXT_DECLARE    0x00800
+#define EXT_SEND_NOREF 0x00900
+#define EXT_FCLASS     0x00a00
+#define EXT_IFACE      0x00b00
+#define EXT_ISSET      0x00c00
+#define EXT_BIT        0x00d00
+#define EXT_CLASS      0x00e00
+#define EXT_ASSIGN     0x00f00
+
+#define OP1_MASK       0x000f0
+#define OP1_UNUSED     0x000f0
+#define OP1_STD        0x00000
+#define OP1_OPLINE     0x00010
+#define OP1_ARG        0x00020
+#define OP1_BRK        0x00030
+#define OP1_CONT       0x00040
+#define OP1_JMPADDR    0x00050
+#define OP1_CLASS      0x00060
+#define OP1_VAR        0x00070
+#define OP1_TMP        0x00080
+#define OP1_UCLASS     0x00090
+
+#define OP2_MASK       0x0000f
+#define OP2_UNUSED     0x0000f
+#define OP2_STD        0x00000
+#define OP2_OPLINE     0x00001
+#define OP2_FETCH      0x00002
+#define OP2_INCLUDE    0x00003
+#define OP2_ARG        0x00004
+#define OP2_ISSET      0x00005
+#define OP2_JMPADDR    0x00006
+#define OP2_CLASS      0x00007
+#define OP2_VAR        0x00008
+#define OP2_TMP        0x00009
+
+#define RES_MASK       0xf0000
+#define RES_UNUSED     0xf0000
+#define RES_STD        0x00000
+#define RES_CLASS      0x10000
+#define RES_TMP        0x20000
+#define RES_VAR        0x30000
+
+#define OPS_STD       EXT_STD | OP1_STD | OP2_STD | RES_STD
+
+#ifdef ZEND_ENGINE_2
+#  define VAR_NUM(var) ((unsigned int)(((temp_variable *)(var))-((temp_variable *)NULL)))
+#  define VAR_VAL(var) ((unsigned int)((var)*sizeof(temp_variable)))
+#else
+#  define VAR_NUM(var) ((unsigned int)(var))
+#  define VAR_VAL(var) ((unsigned int)(var))
+#endif
+
+typedef struct {
+#ifdef WITH_EACCELERATOR_DISASSEMBLER
+  const char*  opname;
+#endif
+  unsigned int ops;
+} opcode_dsc;
+
+const opcode_dsc* get_opcode_dsc(unsigned int n);
+
+#ifdef ZEND_ENGINE_2
+opcode_handler_t get_opcode_handler(zend_uchar opcode TSRMLS_DC);
+#endif
+
+#endif
Index: /eaccelerator/trunk/execute.c
===================================================================
--- /eaccelerator/trunk/execute.c	(revision 4)
+++ /eaccelerator/trunk/execute.c	(revision 4)
@@ -0,0 +1,42 @@
+/*
+   +----------------------------------------------------------------------+
+   | Turck MMCache for PHP Version 4                                      |
+   +----------------------------------------------------------------------+
+   | Copyright (c) 2002-2003 TurckSoft, St. Petersburg                    |
+   | http://www.turcksoft.com                                             |
+   +----------------------------------------------------------------------+
+   | This program is free software; you can redistribute it and/or        |
+   | modify it under the terms of the GNU General Public License          |
+   | as published by the Free Software Foundation; either version 2       |
+   | of the License, or (at your option) any later version.               |
+   |                                                                      |
+   | This program is distributed in the hope that it will be useful,      |
+   | but WITHOUT ANY WARRANTY; without even the implied warranty of       |
+   | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        |
+   | GNU General Public License for more details.                         |
+   |                                                                      |
+   | You should have received a copy of the GNU General Public License    |
+   | along with this program; if not, write to the Free Software          |
+   | Foundation, Inc., 59 Temple Place - Suite 330, Boston,               |
+   | MA  02111-1307, USA.                                                 |
+   |                                                                      |
+   | A copy is availble at http://www.gnu.org/copyleft/gpl.txt            |
+   +----------------------------------------------------------------------+
+   | Author: Dmitry Stogov <mmcache@turckware.ru>                         |
+   +----------------------------------------------------------------------+
+   $Id$
+*/
+
+#include "eaccelerator.h"
+
+#ifdef HAVE_EACCELERATOR
+#ifdef WITH_EACCELERATOR_EXECUTOR
+#include "zend.h"
+
+ZEND_DLEXPORT void eaccelerator_execute(zend_op_array *op_array TSRMLS_DC)
+{
+  zend_error(E_CORE_ERROR, "eaccelerator_execute() is not implemented");
+}
+
+#endif
+#endif /* #ifdef HAVE_EACCELERATOR */
Index: /eaccelerator/trunk/eaccelerator_version.h
===================================================================
--- /eaccelerator/trunk/eaccelerator_version.h	(revision 4)
+++ /eaccelerator/trunk/eaccelerator_version.h	(revision 4)
@@ -0,0 +1,3 @@
+#ifndef EACCELERATOR_VERSION
+#define EACCELERATOR_VERSION "0.9.0"
+#endif
Index: /eaccelerator/trunk/config.m4
===================================================================
--- /eaccelerator/trunk/config.m4	(revision 4)
+++ /eaccelerator/trunk/config.m4	(revision 4)
@@ -0,0 +1,289 @@
+AC_ARG_WITH(eaccelerator,[],[enable_eaccelerator=$withval])
+
+PHP_ARG_ENABLE(eaccelerator, whether to enable eaccelerator support,
+[  --enable-eaccelerator        Enable eaccelerator support])
+
+AC_ARG_WITH(eaccelerator-crash-detection,
+[  --without-eaccelerator-crash-detection  Do not include eaccelerator crash detection],[
+  eaccelerator_crash_detection=$withval
+],[
+  eaccelerator_crash_detection=yes
+])
+
+AC_ARG_WITH(eaccelerator-optimizer,
+[  --without-eaccelerator-optimizer        Do not include eaccelerator optimizer],[
+  eaccelerator_optimizer=$withval
+],[
+  eaccelerator_optimizer=yes
+])
+
+AC_ARG_WITH(eaccelerator-encoder,
+[  --without-eaccelerator-encoder          Do not include eaccelerator encoder],[
+  eaccelerator_encoder=$withval
+],[
+  eaccelerator_encoder=yes
+])
+
+AC_ARG_WITH(eaccelerator-loader,
+[  --without-eaccelerator-loader           Do not include eaccelerator loader],[
+  eaccelerator_loader=$withval
+],[
+  eaccelerator_loader=yes
+])
+
+AC_ARG_WITH(eaccelerator-sessions,
+[  --without-eaccelerator-sessions         Do not include eaccelerator sessions],[
+  eaccelerator_sessions=$withval
+],[
+  eaccelerator_sessions=yes
+])
+
+AC_ARG_WITH(eaccelerator-content-caching,
+[  --without-eaccelerator-content-caching  Do not include eaccelerator content caching],[
+  eaccelerator_content_caching=$withval
+],[
+  eaccelerator_content_caching=yes
+])
+
+AC_ARG_WITH(eaccelerator-disassembler,
+[  --with-eaccelerator-disassembler        Include disassembler],[
+  eaccelerator_disassembler=$withval
+],[
+  eaccelerator_disassemmbler=no
+])
+
+AC_ARG_WITH(eaccelerator-executor,
+[  --with-eaccelerator-executor            Include optimized executor (not implemented yet)],[
+  eaccelerator_executor=$withval
+],[
+  eaccelerator_executor=no
+])
+
+dnl PHP_BUILD_SHARED
+if test "$PHP_EACCELERATOR" != "no"; then
+  PHP_EXTENSION(eaccelerator, $ext_shared)
+  AC_DEFINE(HAVE_EACCELERATOR, 1, [Define if you like to use eAccelerator])
+
+  if test "$eaccelerator_crash_detection" = "yes"; then
+    AC_DEFINE(WITH_EACCELERATOR_CRASH_DETECTION, 1, [Define if you like to release eAccelerator resources on PHP crash])
+  fi
+  if test "$eaccelerator_optimizer" = "yes"; then
+    AC_DEFINE(WITH_EACCELERATOR_OPTIMIZER, 1, [Define if you like to use peephole opcode optimization])
+  fi
+  if test "$eaccelerator_encoder" = "yes"; then
+    AC_DEFINE(WITH_EACCELERATOR_ENCODER, 1, [Define if you like to use eAccelerator enoder])
+  fi
+  if test "$eaccelerator_loader" = "yes"; then
+    AC_DEFINE(WITH_EACCELERATOR_LOADER, 1, [Define if you like to load files encoded by eAccelerator encoder])
+  fi
+  if test "$eaccelerator_sessions" = "yes"; then
+    AC_DEFINE(WITH_EACCELERATOR_SESSIONS, 1, [Define if you like to use eAccelerator session handlers to store session's information in shared memory])
+  fi
+  if test "$eaccelerator_content_caching" = "yes"; then
+    AC_DEFINE(WITH_EACCELERATOR_CONTENT_CACHING, 1, [Define if you like to use eAccelerator content cachin API])
+  fi
+  if test "$eaccelerator_disassembler" = "yes"; then
+    AC_DEFINE(WITH_EACCELERATOR_DISASSEMBLER, 1, [Define if you like to explore Zend bytecode])
+  fi
+  if test "$eaccelerator_executor" = "yes"; then
+    AC_DEFINE(WITH_EACCELERATOR_EXECUTOR, 1, [Define if you like use optimized executor (not implemented yet)])
+  fi
+
+  AC_REQUIRE_CPP()
+
+  AC_HAVE_HEADERS(unistd.h limits.h sys/param.h sched.h)
+
+  AC_MSG_CHECKING(mandatory system headers)
+  AC_TRY_CPP([#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <malloc.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>],msg=yes,msg=no)
+  AC_MSG_RESULT([$msg])
+
+  AC_MSG_CHECKING(whether union semun is defined in sys/sem.h)
+  AC_TRY_COMPILE([
+  #include <sys/types.h>
+  #include <sys/ipc.h>
+  #include <sys/sem.h>
+  ],[
+  union semun arg;
+  semctl(0, 0, 0, arg);
+  ],
+  AC_DEFINE(HAVE_UNION_SEMUN, 1, [Define if you have semun union in sys/sem.h])
+  msg=yes,msg=no)
+  AC_MSG_RESULT([$msg])
+
+  mm_shm_ipc=no
+  mm_shm_mmap_anon=no
+  mm_shm_mmap_zero=no
+  mm_shm_mmap_file=no
+  mm_shm_mmap_posix=no
+
+  AC_MSG_CHECKING(for sysvipc shared memory support)
+  AC_TRY_RUN([#define MM_SEM_NONE
+#define MM_SHM_IPC
+#define MM_TEST_SHM
+#include "mm.c"
+],dnl
+    mm_shm_ipc=yes
+    msg=yes,msg=no,msg=no)
+  AC_MSG_RESULT([$msg])
+
+  AC_MSG_CHECKING(for mmap shared memory support)
+  AC_TRY_RUN([#define MM_SEM_NONE
+#define MM_SHM_MMAP_FILE
+#define MM_TEST_SHM
+#include "mm.c"
+],dnl
+    mm_shm_mmap_file=yes
+    msg=yes,msg=no,msg=no)
+  AC_MSG_RESULT([$msg])
+
+  AC_MSG_CHECKING(for mmap on /dev/zero shared memory support)
+  AC_TRY_RUN([#define MM_SEM_NONE
+#define MM_SHM_MMAP_ZERO
+#define MM_TEST_SHM
+#include "mm.c"
+],dnl
+    mm_shm_mmap_zero=yes
+    msg=yes,msg=no,msg=no)
+  AC_MSG_RESULT([$msg])
+
+  AC_MSG_CHECKING(for anonymous mmap shared memory support)
+  AC_TRY_RUN([#define MM_SEM_NONE
+#define MM_SHM_MMAP_ANON
+#define MM_TEST_SHM
+#include "mm.c"
+],dnl
+    mm_shm_mmap_anon=yes
+    msg=yes,msg=no,msg=no)
+  AC_MSG_RESULT([$msg])
+
+  AC_MSG_CHECKING(for posix mmap shared memory support)
+  AC_TRY_RUN([#define MM_SEM_NONE
+#define MM_SHM_MMAP_POSIX
+#define MM_TEST_SHM
+#include "mm.c"
+],dnl
+    mm_shm_mmap_posix=yes
+    msg=yes,msg=no,msg=no)
+  AC_MSG_RESULT([$msg])
+
+  AC_MSG_CHECKING(for best shared memory type)
+  if test "$mm_shm_ipc" = "yes"; then
+    AC_DEFINE(MM_SHM_IPC, 1, [Define if you like to use sysvipc based shared memory])
+    msg="sysvipc"
+  elif test "$mm_shm_mmap_anon" = "yes"; then
+    AC_DEFINE(MM_SHM_MMAP_ANON, 1, [Define if you like to use anonymous mmap based shared memory])
+    msg="anonymous mmap"
+  elif test "$mm_shm_mmap_zero" = "yes"; then
+    AC_DEFINE(MM_SHM_MMAP_ZERO, 1, [Define if you like to use mmap on /dev/zero based shared memory])
+    msg="mmap on /dev/zero"
+  elif test "$mm_shm_mmap_posix" = "yes"; then
+    AC_DEFINE(MM_SHM_MMAP_POSIX, 1, [Define if you like to use posix mmap based shared memory])
+    msg="posix mmap"
+  elif test "$mm_shm_mmap_file" = "yes"; then
+    AC_DEFINE(MM_SHM_MMAP_FILE, 1, [Define if you like to use mmap on temporary file shared memory])
+    msg="mmap"
+  fi
+  AC_MSG_RESULT([$msg])
+
+  AC_MSG_CHECKING(for spinlock semaphores support)
+  AC_TRY_RUN([#define MM_SEM_SPINLOCK
+#define MM_TEST_SEM
+#include "mm.c"
+],dnl
+    mm_sem_spinlock=yes
+    msg=yes,msg=no,msg=no)
+  AC_MSG_RESULT([$msg])
+
+  AC_MSG_CHECKING(for pthread semaphores support)
+  AC_TRY_RUN([#define MM_SEM_PTHREAD
+#define MM_TEST_SEM
+#include "mm.c"
+],dnl
+    mm_sem_pthread=yes
+    msg=yes,msg=no,msg=no)
+  AC_MSG_RESULT([$msg])
+
+  AC_MSG_CHECKING(for posix semaphores support)
+  AC_TRY_RUN([#define MM_SEM_POSIX
+#define MM_TEST_SEM
+#include "mm.c"
+],dnl
+    mm_sem_posix=yes
+    msg=yes,msg=no,msg=no)
+  AC_MSG_RESULT([$msg])
+
+  AC_MSG_CHECKING(for sysvipc semaphores support)
+  AC_TRY_RUN([#define MM_SEM_IPC
+#define MM_TEST_SEM
+#include "mm.c"
+],dnl
+    mm_sem_ipc=yes
+    msg=yes,msg=no,msg=no)
+  AC_MSG_RESULT([$msg])
+
+  AC_MSG_CHECKING(for fcntl semaphores support)
+  AC_TRY_RUN([#define MM_SEM_FCNTL
+#define MM_TEST_SEM
+#include "mm.c"
+],dnl
+    mm_sem_fcntl=yes
+    msg=yes,msg=no,msg=no)
+  AC_MSG_RESULT([$msg])
+
+  AC_MSG_CHECKING(for flock semaphores support)
+  AC_TRY_RUN([#define MM_SEM_FLOCK
+#define MM_TEST_SEM
+#include "mm.c"
+],dnl
+    mm_sem_flock=yes
+    msg=yes,msg=no,msg=no)
+  AC_MSG_RESULT([$msg])
+
+  AC_MSG_CHECKING(for best semaphores type)
+  if test "$mm_sem_spinlock" = "yes"; then
+    AC_DEFINE(MM_SEM_SPINLOCK, 1, [Define if you like to use spinlock based semaphores])
+    msg="spinlock"
+  elif test "$mm_sem_ipc" = "yes"; then
+    AC_DEFINE(MM_SEM_IPC, 1, [Define if you like to use sysvipc based semaphores])
+    msg="sysvipc"
+  elif test "$mm_sem_fcntl" = "yes"; then
+    AC_DEFINE(MM_SEM_FCNTL, 1, [Define if you like to use fcntl based semaphores])
+    msg="fcntl"
+  elif test "$mm_sem_flock" = "yes"; then
+    AC_DEFINE(MM_SEM_FLOCK, 1, [Define if you like to use flock based semaphores])
+    msg="flock"
+  elif test "$mm_sem_pthread" = "yes"; then
+    AC_DEFINE(MM_SEM_PTHREAD, 1, [Define if you like to use pthread based semaphores])
+    msg="pthread"
+  elif test "$mm_sem_posix" = "yes"; then
+    AC_DEFINE(MM_SEM_POSIX, 1, [Define if you like to use posix based semaphores])
+    msg="posix"
+  fi
+  AC_MSG_RESULT([$msg])
+
+  AC_CHECK_FUNC(sched_yield,[
+      AC_DEFINE(HAVE_SCHED_YIELD, 1, [Define if ou have sched_yield function])
+    ])
+
+  AC_CHECK_FUNC(mprotect,[
+      AC_DEFINE(HAVE_MPROTECT, 1, [Define if ou have mprotect function])
+    ])
+
+  old_cppflags="$CPPFLAGS"
+  CPPFLAGS="$CPPFLAGS $INCLUDES"
+  AC_MSG_CHECKING(for ext/session/php_session.h)
+  AC_TRY_CPP([#include "ext/session/php_session.h"],msg="yes",msg="no")
+  if test "$msg" = "yes"; then
+    AC_DEFINE(HAVE_EXT_SESSION_PHP_SESSION_H, 1, [Define if you have the <ext/session/php_session.h> header file.])
+  fi
+  AC_MSG_RESULT([$msg])
+  CPPFLAGS="$old_cppflags"
+
+fi
Index: /eaccelerator/trunk/AUTHORS
===================================================================
--- /eaccelerator/trunk/AUTHORS	(revision 4)
+++ /eaccelerator/trunk/AUTHORS	(revision 4)
@@ -0,0 +1,6 @@
+Frank Alcantara  <frankalcantara@users.sourceforge.net>
+Reiner Jung  <reinerj@users.sourceforge.net>
+Everaldo Canuto <everaldo_canuto@users.sourceforge.net>
+
+eAccelerator is based on Turck MMCache whiten by:
+  Dmitry Stogov <mmcache@turckware.ru>
Index: /eaccelerator/trunk/ChangeLog
===================================================================
--- /eaccelerator/trunk/ChangeLog	(revision 4)
+++ /eaccelerator/trunk/ChangeLog	(revision 4)
@@ -0,0 +1,3 @@
+2004-12-09  Everaldo Canuto <everaldo_canuto@yahoo.com.br>
+
+        * first public release 0.9.0 based on Turck MMCache.
Index: /eaccelerator/trunk/loader.c
===================================================================
--- /eaccelerator/trunk/loader.c	(revision 4)
+++ /eaccelerator/trunk/loader.c	(revision 4)
@@ -0,0 +1,1187 @@
+/*
+   +----------------------------------------------------------------------+
+   | Turck MMCache for PHP Version 4                                      |
+   +----------------------------------------------------------------------+
+   | Copyright (c) 2002-2003 TurckSoft, St. Petersburg                    |
+   | http://www.turcksoft.com                                             |
+   +----------------------------------------------------------------------+
+   | This program is free software; you can redistribute it and/or        |
+   | modify it under the terms of the GNU General Public License          |
+   | as published by the Free Software Foundation; either version 2       |
+   | of the License, or (at your option) any later version.               |
+   |                                                                      |
+   | This program is distributed in the hope that it will be useful,      |
+   | but WITHOUT ANY WARRANTY; without even the implied warranty of       |
+   | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        |
+   | GNU General Public License for more details.                         |
+   |                                                                      |
+   | You should have received a copy of the GNU General Public License    |
+   | along with this program; if not, write to the Free Software          |
+   | Foundation, Inc., 59 Temple Place - Suite 330, Boston,               |
+   | MA  02111-1307, USA.                                                 |
+   |                                                                      |
+   | A copy is availble at http://www.gnu.org/copyleft/gpl.txt            |
+   +----------------------------------------------------------------------+
+   | Author: Dmitry Stogov <mmcache@turckware.ru>                         |
+   +----------------------------------------------------------------------+
+   $Id$
+*/
+
+#include "eaccelerator.h"
+#include "eaccelerator_version.h"
+
+#ifdef HAVE_EACCELERATOR
+#ifdef WITH_EACCELERATOR_LOADER
+
+#include "opcodes.h"
+
+#include "zend.h"
+#include "zend_API.h"
+#include "php.h"
+
+#include <math.h>
+
+#define MMC_ENCODER_VERSION   0x00000002
+
+#define MMC_ENCODER_END       0x00
+#define MMC_ENCODER_NAMESPACE 0x01
+#define MMC_ENCODER_CLASS     0x02
+#define MMC_ENCODER_FUNCTION  0x03
+
+typedef struct loader_data {
+  long  version;
+  char* filename;
+  uint  lineno;
+} loader_data;
+
+static inline unsigned char decode(char** p, unsigned int* l) {
+  unsigned char c;
+  if (*l == 0) {
+    zend_bailout();
+  }
+  c = **p;
+  (*p)++;
+  (*l)--;
+  return c;
+}
+
+static inline unsigned int decode32(char** p, unsigned int* l) {
+  unsigned int i = decode(p, l);
+  i += ((unsigned int)decode(p, l)) << 8;
+  i += ((unsigned int)decode(p, l)) << 16;
+  i += ((unsigned int)decode(p, l)) << 24;
+  return i;
+}
+
+static inline unsigned short decode16(char** p, unsigned int* l) {
+  unsigned short i = decode(p, l);
+  i += ((unsigned short)decode(p, l)) << 8;
+  return i;
+}
+
+static unsigned int decode_var(unsigned int count, char** p, unsigned int* l) {
+  unsigned int var;
+  if (count < 0xff) {
+    var = decode(p, l);
+  } else if (count < 0xffff) {
+    var = decode16(p, l);
+  } else {
+    var = decode32(p, l);
+  }
+  if (var >= count) {
+    zend_bailout();
+  }
+#ifdef ZEND_ENGINE_2
+  return (unsigned int)(((temp_variable*)NULL) + var);
+#else
+  return var;
+#endif
+}
+
+static unsigned int decode_opline(unsigned int last, char** p, unsigned int* l) {
+  unsigned int opline;
+  if (last < 0xff-1) {
+    opline = decode(p, l);
+    if (opline == 0xff) return (unsigned int)-1;
+  } else if (last < 0xffff-1) {
+    opline = decode16(p, l);
+    if (opline == 0xffff) return (unsigned int)-1;
+  } else {
+    opline = decode32(p, l);
+  }
+  if (opline >= last) {
+    zend_bailout();
+  }
+  return opline;
+}
+
+static char* decode_zstr(char** p, unsigned int* l) {
+  char *s = *p;
+  unsigned int len = 0;
+  while (s[len] != '\0') {
+    len++;
+    if (len > (*l)) {
+      zend_bailout();
+    }
+  }
+  if (len == 0) {
+    (*p)++;
+    (*l)--;
+    return NULL;
+  } else {
+    char *str = emalloc(len+1);
+    memcpy(str, *p, len+1);
+    *p += len+1;
+    *l -= len+1;
+    return str;
+  }
+}
+
+static char* decode_zstr_noalloc(char** p, unsigned int* l) {
+  char *s = *p;
+  unsigned int len = 0;
+  while (s[len] != '\0') {
+    len++;
+    if (len > (*l)) {
+      zend_bailout();
+    }
+  }
+  if (len == 0) {
+    (*p)++;
+    (*l)--;
+    return NULL;
+  } else {
+    *p += len+1;
+    *l -= len+1;
+    return s;
+  }
+}
+
+#if MMC_ENCODER_VERSION < 2
+static char* decode_filename(char** p, unsigned int* l TSRMLS_DC) {
+  char *s = *p;
+  unsigned int len = 0;
+  while (s[len] != '\0') {
+    len++;
+    if (len > (*l)) {
+      zend_bailout();
+    }
+  }
+  if (len == 0) {
+    (*p)++;
+    (*l)--;
+    return NULL;
+  } else {
+    if (((loader_data*)MMCG(mem))->filename == NULL ||
+        strcmp(((loader_data*)MMCG(mem))->filename,*p) != 0) {
+      char* old = CG(compiled_filename);
+      ((loader_data*)MMCG(mem))->filename = zend_set_compiled_filename(*p TSRMLS_CC);
+      CG(compiled_filename) = old;
+    }
+    *p += len+1;
+    *l -= len+1;
+    return ((loader_data*)MMCG(mem))->filename;
+  }
+}
+#endif
+
+static char* decode_lstr(unsigned int* len, char** p, unsigned int* l) {
+  *len = decode32(p, l);
+  if (*len == 0) {
+    return NULL;
+  } else {
+    char* str;
+    if (*len > *l) {
+      zend_bailout();
+    }
+    str = emalloc((*len)+1);
+    memcpy(str, *p, *len);
+    str[(*len)] = '\0';
+    *p += *len;
+    *l -= *len;
+    return str;
+  }
+}
+
+static char* decode_lstr_noalloc(unsigned int* len, char** p, unsigned int* l) {
+  *len = decode32(p, l);
+  if (*len == 0) {
+    return NULL;
+  } else {
+    char* str = *p;
+    if (*len > *l) {
+      zend_bailout();
+    }
+    *p += *len;
+    *l -= *len;
+    return str;
+  }
+}
+
+static unsigned char* decode_pstr(char** p, unsigned int* l) {
+  unsigned char c = decode(p, l);
+  if (c == 0) {
+    return NULL;
+  } else {
+    unsigned char *str;
+    if (c > *l) {
+      zend_bailout();
+    }
+    str = emalloc(c+1);
+    str[0] = c;
+    memcpy(&str[1], *p, c);
+    *p += c;
+    *l -= c;
+    return str;
+  }
+}
+
+static double decode_double(char** p, unsigned int* l) {
+  unsigned char sign;
+  int exp;
+  unsigned int i1, i2;
+  double d;
+
+  sign = decode(p, l);
+  exp = decode32(p, l);
+  i1 = decode32(p, l);
+  i2 = decode32(p, l);
+  d = ldexp((((double)i2 / 4294967296.0) + (double)i1) / 4294967296.0, exp);
+  if (sign) {
+    d = -d;
+  }
+  return d;
+}
+
+typedef void* (*decode_bucket_t)(void* to, char**, unsigned int* TSRMLS_DC);
+
+#define decode_zval_hash(to, p, l) decode_hash(to, sizeof(zval*), (decode_bucket_t)decode_zval_ptr, p, l TSRMLS_CC)
+#define decode_zval_hash_noref(to, p, l) decode_hash(to, sizeof(zval*), (decode_bucket_t)decode_zval_ptr_noref, p, l TSRMLS_CC)
+
+static HashTable* decode_hash(HashTable* to, int size, decode_bucket_t decode_bucket, char**p, unsigned int* l TSRMLS_DC);
+static zval* decode_zval_ptr(zval* to, char** p, unsigned int* l TSRMLS_DC);
+
+static zval* decode_zval(zval* to, int refs, char** p, unsigned int* l TSRMLS_DC) {
+  to->type     = decode(p ,l);
+  if (refs) {
+    to->is_ref = decode(p, l);
+    to->refcount = decode32(p, l);
+  } else {
+    to->is_ref   = 1;
+    to->refcount = 2;
+  }
+  switch (to->type & ~IS_CONSTANT_INDEX) {
+    case IS_NULL:
+      break;
+    case IS_BOOL:
+      to->value.lval = decode(p, l);
+      break;
+    case IS_LONG:
+      {
+  int x = decode32(p,l);
+        to->value.lval = x;
+      }
+      break;
+    case IS_DOUBLE:
+      to->value.dval = decode_double(p, l);
+      break;
+    case IS_CONSTANT:
+    case IS_STRING:
+/*???    case FLAG_IS_BC:*/
+      to->value.str.val = decode_lstr((unsigned int*)&to->value.str.len, p, l);
+      if (to->value.str.val == NULL) {
+        to->value.str.val = empty_string;
+      }
+      break;
+    case IS_ARRAY:
+    case IS_CONSTANT_ARRAY:
+      to->value.ht = decode_zval_hash(NULL, p ,l);
+      if (to->value.ht) {
+        to->value.ht->pDestructor = ZVAL_PTR_DTOR;
+      } else {
+        ALLOC_HASHTABLE(to->value.ht);
+        zend_hash_init(to->value.ht, 0, NULL, ZVAL_PTR_DTOR, 0);
+      }
+      break;
+    case IS_OBJECT:
+    case IS_RESOURCE:
+      /*???*/
+    default:
+      zend_bailout();
+      break;
+  }
+  return to;
+}
+
+static zval* decode_zval_ptr(zval* to, char** p, unsigned int* l TSRMLS_DC) {
+  if (to == NULL) {
+    ALLOC_ZVAL(to);
+  }
+  decode_zval(to, 1, p, l TSRMLS_CC);
+  return to;
+}
+
+static zval* decode_zval_ptr_noref(zval* to, char** p, unsigned int* l TSRMLS_DC) {
+  if (to == NULL) {
+    ALLOC_ZVAL(to);
+  }
+  decode_zval(to, 1, p, l TSRMLS_CC);
+  to->is_ref   = 0;
+  to->refcount = 1;
+  return to;
+}
+
+static void decode_znode(znode* to, unsigned int vars_count, char** p, unsigned int* l TSRMLS_DC) {
+  to->op_type = decode(p, l);
+  if (to->op_type == IS_CONST) {
+    decode_zval(&to->u.constant, 0, p, l TSRMLS_CC);
+    to->u.constant.is_ref = 1;
+    to->u.constant.refcount = 2;
+  } else if (to->op_type == IS_VAR ||
+             to->op_type == IS_TMP_VAR) {
+    to->u.var = decode_var(vars_count, p, l);
+  } else if (to->op_type != IS_UNUSED) {
+    zend_bailout();
+  }
+}
+
+static HashTable* decode_hash(HashTable* to, int size, decode_bucket_t decode_bucket, char** p, unsigned int* l TSRMLS_DC) {
+  unsigned int n;
+  void *data = NULL;
+
+  if (size != sizeof(void*)) {
+    data = do_alloca(size);
+  }
+  n = decode32(p, l);
+  if (to == NULL) {
+    if (n == 0 ) return NULL;
+    ALLOC_HASHTABLE(to);
+    zend_hash_init(to, 0, NULL, NULL, 0);
+  }
+  while (n > 0) {
+    void* x;
+    char* s;
+    unsigned int len;
+
+    s = decode_lstr_noalloc(&len, p, l);
+    if (s == NULL) {
+      len = decode32(p, l);
+    }
+    if (size == sizeof(void*)) {
+      x = decode_bucket(NULL, p, l TSRMLS_CC);
+      if (s != NULL) {
+        zend_hash_add(to, s, len, &x, size, NULL);
+      } else {
+        zend_hash_index_update(to, len, &x, size, NULL);
+      }
+    } else {
+      decode_bucket(data, p, l TSRMLS_CC);
+      if (s != NULL) {
+        zend_hash_add(to, s, len, data, size, NULL);
+      } else {
+        zend_hash_index_update(to, len, data, size, NULL);
+      }
+    }
+    --n;
+  }
+  if (size != sizeof(void*)) {
+    free_alloca(data);
+  }
+  return to;
+}
+
+static void call_op_array_ctor_handler(zend_extension *extension, zend_op_array *op_array TSRMLS_DC) {
+  if (extension->op_array_ctor) {
+    extension->op_array_ctor(op_array);
+  }
+}
+
+static zend_op_array* decode_op_array(zend_op_array *to, char** p, unsigned int* l TSRMLS_DC) {
+  char c;
+  zend_op *opline;
+  zend_op *end;
+#ifdef ZEND_ENGINE_2
+  char* scope_name;
+  int   scope_name_len;
+#endif
+
+  c = decode(p, l);
+  if (c == ZEND_INTERNAL_FUNCTION) {
+    if (to == NULL) {
+      to = (zend_op_array*)emalloc(sizeof(zend_internal_function));
+    }
+    memset(to, 0, sizeof(zend_internal_function));
+  } else if (c == ZEND_USER_FUNCTION) {
+    if (to == NULL) {
+      to = (zend_op_array*)emalloc(sizeof(zend_op_array));
+    }
+    memset(to, 0, sizeof(zend_op_array));
+    zend_llist_apply_with_argument(&zend_extensions, (llist_apply_with_arg_func_t) call_op_array_ctor_handler, to TSRMLS_CC);
+  } else {
+    zend_bailout();
+  }
+  to->type = c;
+#ifdef ZEND_ENGINE_2
+  to->num_args = decode32(p, l);
+  if (to->num_args > 0) {
+    zend_uint i;
+    to->arg_info = (zend_arg_info*)emalloc(to->num_args * sizeof(zend_arg_info));
+    for (i = 0; i < to->num_args; i++) {
+      to->arg_info[i].name = decode_lstr(&to->arg_info[i].name_len, p ,l);
+      to->arg_info[i].class_name = decode_lstr(&to->arg_info[i].class_name_len, p ,l);
+      to->arg_info[i].allow_null = decode(p, l);
+      to->arg_info[i].pass_by_reference = decode(p, l);
+    }
+  } else {
+    to->arg_info = NULL;
+  }
+  to->pass_rest_by_reference = decode(p, l);
+#else
+  to->arg_types     = decode_pstr(p, l);
+#endif
+  to->function_name = decode_zstr(p, l);
+#ifdef ZEND_ENGINE_2
+	to->scope            = MMCG(class_entry);
+	to->fn_flags         = decode32(p, l);
+	scope_name = decode_lstr((unsigned int*)&scope_name_len, p, l);
+	if (to->scope == NULL && scope_name != NULL)
+	{
+		if (zend_hash_find(CG(class_table),
+			(void *)scope_name, scope_name_len,
+			(void **)&to->scope) == SUCCESS)
+		{
+			to->scope = *(zend_class_entry**)to->scope;
+		}
+		else
+		{
+/*???
+			debug_printf("[%d] EACCELERATOR can't restore parent class "
+				"\"%s\" of function \"%s\"\n", getpid(),
+				(char*)scope_name, to->function_name);
+*/
+				to->scope = NULL;
+		}
+	}
+	if (to->scope != NULL)
+	{
+		unsigned int len = strlen(to->function_name);
+		char *lcname = zend_str_tolower_dup(to->function_name, len);
+		/*
+		 * HOESH: As explained in restore_op_array()!
+		 */
+		if  (
+				to->scope->name_length == len &&
+				memcmp(to->scope->name, lcname, len) == 0 &&
+				(
+					to->scope->constructor == NULL || // case 0)
+					to->scope->constructor->type == ZEND_INTERNAL_FUNCTION || // case A)
+					to->scope->constructor->op_array.scope->name_length != len || // case B)
+					memcmp(to->scope->constructor->op_array.scope->name, lcname, len) != 0
+				)
+			)
+		{
+			to->scope->constructor = (zend_function*)to;
+		}
+		else if (*lcname == '_' && *(lcname+1) == '_')
+		{
+			if (len == sizeof(ZEND_CONSTRUCTOR_FUNC_NAME)-1 &&
+				memcmp(lcname, ZEND_CONSTRUCTOR_FUNC_NAME, sizeof(ZEND_CONSTRUCTOR_FUNC_NAME)) == 0)
+			{
+				to->scope->constructor = (zend_function*)to;
+			}
+			else if (len == sizeof(ZEND_DESTRUCTOR_FUNC_NAME)-1 &&
+				memcmp(lcname, ZEND_DESTRUCTOR_FUNC_NAME, sizeof(ZEND_DESTRUCTOR_FUNC_NAME)) == 0)
+			{
+				to->scope->destructor = (zend_function*)to;
+			}
+			else if (len == sizeof(ZEND_CLONE_FUNC_NAME)-1 &&
+				memcmp(lcname, ZEND_CLONE_FUNC_NAME, sizeof(ZEND_CLONE_FUNC_NAME)) == 0)
+			{
+				to->scope->clone = (zend_function*)to;
+			}
+			else if (len == sizeof(ZEND_GET_FUNC_NAME)-1 &&
+				memcmp(lcname, ZEND_GET_FUNC_NAME, sizeof(ZEND_GET_FUNC_NAME)) == 0)
+			{
+				to->scope->__get = (zend_function*)to;
+			}
+			else if (len == sizeof(ZEND_SET_FUNC_NAME)-1 &&
+				memcmp(lcname, ZEND_SET_FUNC_NAME, sizeof(ZEND_SET_FUNC_NAME)) == 0)
+			{
+				to->scope->__set = (zend_function*)to;
+			}
+			else if (len == sizeof(ZEND_CALL_FUNC_NAME)-1 &&
+				memcmp(lcname, ZEND_CALL_FUNC_NAME, sizeof(ZEND_CALL_FUNC_NAME)) == 0)
+			{
+				to->scope->__call = (zend_function*)to;
+			}
+		}
+		efree(lcname);
+	}
+#endif
+  if (to->type == ZEND_INTERNAL_FUNCTION) {
+    return to;
+  }
+  to->T = decode32(p, l);
+#ifdef ZEND_ENGINE_2
+  to->uses_this = decode(p, l);
+#else
+  to->uses_globals = decode(p, l);
+#endif
+  to->return_reference = decode(p, l);
+
+  to->last = decode32(p, l);
+  to->size = to->last;
+  if (to->last > 0) {
+    to->last_brk_cont = decode32(p, l);
+    if (to->last_brk_cont > 0) {
+      zend_uint i;
+      to->brk_cont_array = emalloc(sizeof(zend_brk_cont_element)*to->last_brk_cont);
+      for (i = 0; i < to->last_brk_cont; i++) {
+        to->brk_cont_array[i].brk = decode_opline(to->last, p, l);
+        to->brk_cont_array[i].cont = decode_opline(to->last, p, l);
+        to->brk_cont_array[i].parent = decode_opline(to->last_brk_cont, p, l);
+      }
+    } else {
+      to->brk_cont_array = NULL;
+    }
+#ifdef ZEND_ENGINE_2
+	to->last_try_catch = decode32(p, l);
+	if (to->last_try_catch > 0)
+	{
+		zend_uint i;
+		to->try_catch_array = emalloc(sizeof(zend_try_catch_element)*to->last_try_catch);
+		for (i = 0; i < to->last_try_catch; i++)
+		{
+			to->try_catch_array[i].try_op = decode_opline(to->last, p, l);
+			to->try_catch_array[i].catch_op = decode_opline(to->last, p, l);
+//			to->try_catch_array[i].parent = decode_opline(to->last_brk_cont, p, l);
+		}
+	}
+	else
+	{
+		to->try_catch_array = NULL;
+}
+#endif
+    to->opcodes = emalloc(sizeof(zend_op)*to->last);
+    memset(to->opcodes, 0, sizeof(zend_op)*to->last);
+    opline = to->opcodes;
+    end = opline + to->last;
+    for (;opline < end; opline++) {
+      const opcode_dsc* op_dsc;
+      opline->opcode = decode(p, l);
+      op_dsc = get_opcode_dsc(opline->opcode);
+      if (op_dsc == NULL) {
+        zend_bailout();
+      } else {
+        unsigned int ops = op_dsc->ops;
+#ifdef ZEND_ENGINE_2
+/*??? FIXME
+        opline->handler = zend_opcode_handlers[opline->opcode];
+*/
+        opline->handler = get_opcode_handler(opline->opcode TSRMLS_CC);
+#endif
+#if MMC_ENCODER_VERSION < 2
+        opline->lineno = decode32(p, l);
+#else
+        if (((loader_data*)MMCG(mem))->version < 2) {
+          opline->lineno = decode32(p, l);
+        }
+        opline->lineno = ((loader_data*)MMCG(mem))->lineno;
+#endif
+        opline->extended_value = 0;
+        opline->result.op_type = IS_UNUSED;
+        opline->op1.op_type    = IS_UNUSED;
+        opline->op2.op_type    = IS_UNUSED;
+
+        switch (ops & EXT_MASK) {
+          case EXT_UNUSED:
+            break;
+          case EXT_STD:
+          case EXT_FCALL:
+          case EXT_ARG:
+          case EXT_IFACE:
+            opline->extended_value = decode32(p, l);
+            break;
+          case EXT_SEND:
+          case EXT_SEND_NOREF:
+          case EXT_INIT_FCALL:
+          case EXT_FETCH:
+          case EXT_CAST:
+          case EXT_DECLARE:
+          case EXT_FCLASS:
+          case EXT_BIT:
+          case EXT_ISSET:
+          case EXT_ASSIGN:
+            opline->extended_value = decode(p, l);
+            break;
+          case EXT_OPLINE:
+            opline->extended_value = decode_opline(to->last, p, l);
+            break;
+          case EXT_CLASS:
+            opline->extended_value = decode_var(to->T, p, l);
+            break;
+          default:
+            zend_bailout();
+            break;
+        }
+        switch (ops & RES_MASK) {
+          case RES_UNUSED:
+            break;
+          case RES_TMP:
+            opline->result.op_type = IS_TMP_VAR;
+            opline->result.u.var = decode_var(to->T, p, l);
+            break;
+          case RES_CLASS:
+            opline->result.u.var = decode_var(to->T, p, l);
+            break;
+          case RES_VAR:
+            opline->result.op_type = IS_VAR;
+            opline->result.u.var = decode_var(to->T, p, l);
+            opline->result.u.EA.type = 0;
+            if (decode(p, l)) {
+              opline->result.u.EA.type |= EXT_TYPE_UNUSED;
+            }
+            break;
+          case RES_STD:
+            decode_znode(&opline->result, to->T, p, l TSRMLS_CC);
+            if (opline->result.op_type == IS_VAR) {
+              opline->result.u.EA.type = 0;
+              if (decode(p, l)) {
+                opline->result.u.EA.type |= EXT_TYPE_UNUSED;
+              }
+            }
+            break;
+          default:
+            zend_bailout();
+            break;
+        }
+        switch (ops & OP1_MASK) {
+          case OP1_UNUSED:
+            break;
+          case OP1_OPLINE:
+            opline->op1.u.opline_num = decode_opline(to->last, p, l);
+            break;
+          case OP1_BRK:
+          case OP1_CONT:
+            opline->op1.u.opline_num = decode_opline(to->last_brk_cont, p, l);
+            break;
+          case OP1_CLASS:
+            opline->op1.u.var = decode_var(to->T, p, l);
+            break;
+          case OP1_UCLASS:
+            opline->op1.op_type = decode(p, l);
+            if (opline->op1.op_type != IS_UNUSED) {
+              opline->op1.u.var = decode_var(to->T, p, l);
+            }
+            break;
+          case OP1_TMP:
+            opline->op1.op_type = IS_TMP_VAR;
+            opline->op1.u.var = decode_var(to->T, p, l);
+            break;
+          case OP1_VAR:
+            opline->op1.op_type = IS_VAR;
+            opline->op1.u.var = decode_var(to->T, p, l);
+            break;
+          case OP1_ARG:
+            opline->op1.op_type = IS_CONST;
+            opline->op1.u.constant.type = IS_LONG;
+            opline->op1.u.constant.value.lval = decode32(p, l);
+            break;
+#ifdef ZEND_ENGINE_2
+          case OP1_JMPADDR:
+            opline->op1.u.jmp_addr = to->opcodes + decode_opline(to->last, p, l);
+            break;
+#endif
+          case OP1_STD:
+            decode_znode(&opline->op1, to->T, p, l TSRMLS_CC);
+            break;
+          default:
+            zend_bailout();
+            break;
+        }
+        switch (ops & OP2_MASK) {
+          case OP2_UNUSED:
+            break;
+          case OP2_OPLINE:
+            opline->op2.u.opline_num = decode_opline(to->last, p, l);
+            break;
+          case OP2_ARG:
+            opline->op2.u.opline_num = decode32(p, l);
+            break;
+          case OP2_ISSET:
+          case OP2_INCLUDE:
+            opline->op2.op_type = IS_CONST;
+            opline->op2.u.constant.type = IS_LONG;
+            opline->op2.u.constant.value.lval = decode(p, l);
+            break;
+          case OP2_FETCH:
+#ifdef ZEND_ENGINE_2
+            opline->op2.u.EA.type = decode(p, l);
+            if (opline->op2.u.EA.type == ZEND_FETCH_STATIC_MEMBER) {
+              opline->op2.u.var = decode_var(to->T, p, l);
+            }
+#else
+            opline->op2.u.fetch_type = decode(p, l);
+#endif
+            break;
+          case OP2_CLASS:
+            opline->op2.u.var = decode_var(to->T, p, l);
+            break;
+          case OP2_TMP:
+            opline->op2.op_type = IS_TMP_VAR;
+            opline->op2.u.var = decode_var(to->T, p, l);
+            break;
+          case OP2_VAR:
+            opline->op2.op_type = IS_VAR;
+            opline->op2.u.var = decode_var(to->T, p, l);
+            break;
+#ifdef ZEND_ENGINE_2
+          case OP2_JMPADDR:
+            opline->op2.u.jmp_addr = to->opcodes + decode_opline(to->last, p, l);
+            break;
+#endif
+          case OP2_STD:
+            decode_znode(&opline->op2, to->T, p, l TSRMLS_CC);
+            break;
+          default:
+            zend_bailout();
+            break;
+        }
+      }
+    }
+  } else {
+    to->opcodes = NULL;
+  }
+
+#ifdef ZEND_ENGINE_2
+  to->static_variables = decode_zval_hash(NULL, p, l);
+#else
+  to->static_variables = decode_zval_hash_noref(NULL, p, l);
+#endif
+  if (to->static_variables) {
+    to->static_variables->pDestructor = ZVAL_PTR_DTOR;
+  }
+#if MMC_ENCODER_VERSION < 2
+  to->filename = decode_filename(p, l TSRMLS_CC);
+#else
+  if (((loader_data*)MMCG(mem))->version < 2) {
+    to->filename = decode_zstr(p, l);
+    efree(to->filename);
+  }
+  to->filename = ((loader_data*)MMCG(mem))->filename;
+#endif
+#ifdef ZEND_ENGINE_2
+  to->line_start = decode32(p, l);
+  to->line_end = decode32(p, l);
+  to->doc_comment = decode_lstr(&to->doc_comment_len, p, l);
+#endif
+  to->start_op = to->opcodes;
+  to->current_brk_cont = 0xffffffff;
+  to->backpatch_count  = 0;
+  to->done_pass_two    = 1;
+  to->refcount = emalloc(sizeof(*to->refcount));
+   *to->refcount=1;
+  return to;
+}
+
+
+#ifdef ZEND_ENGINE_2
+static zend_property_info* decode_property_info(zend_property_info* to, char** p, unsigned int* l TSRMLS_DC) {
+  if (to == NULL) {
+    to = emalloc(sizeof(zend_property_info));
+  }
+  to->flags = decode32(p, l);
+  to->name = decode_lstr((unsigned int*)&to->name_length, p, l);
+  return to;
+}
+#endif
+
+static zend_class_entry* decode_class_entry(zend_class_entry* to, char** p, unsigned int* l TSRMLS_DC) {
+  char c;
+  zend_class_entry* old;
+  char*             s;
+  unsigned int      len;
+
+  c = decode(p, l);
+  if (c == ZEND_USER_CLASS) {
+    if (to == NULL) {
+      to = emalloc(sizeof(zend_class_entry));
+    }
+    memset(to, 0, sizeof(zend_class_entry));
+  } else {
+    zend_bailout();
+  }
+  to->type = c;
+  to->name = decode_lstr(&to->name_length, p ,l);
+#ifdef ZEND_ENGINE_2
+  to->ce_flags = decode32(p ,l);
+  to->num_interfaces = decode32(p, l);
+  if (to->num_interfaces > 0) {
+    to->interfaces = (zend_class_entry **) emalloc(sizeof(zend_class_entry *)*to->num_interfaces);
+  } else {
+    to->interfaces = NULL;
+  }
+  to->create_object = NULL;
+#endif
+
+  to->parent      = NULL;
+  s = decode_lstr(&len, p, l);
+  if (s != NULL) {
+    if (zend_hash_find(CG(class_table), s, len+1, (void **)&to->parent) != SUCCESS) {
+/*???
+      debug_printf("[%d] EACCELERATOR can't restore parent class "
+          "\"%s\" of class \"%s\"\n", getpid(), s, to->name);
+*/
+      to->parent = NULL;
+    } else {
+#ifdef ZEND_ENGINE_2
+	  /*
+	   * HOESH: See restore_class_entry() on details.
+	   */
+	  to->parent = *(zend_class_entry**)to->parent;
+	  to->constructor  = to->parent->constructor;
+	  to->destructor  = to->parent->destructor;
+	  to->clone  = to->parent->clone;
+	  to->__get  = to->parent->__get;
+      to->__set  = to->parent->__set;
+      to->__call = to->parent->__call;
+	  to->create_object = to->parent->create_object;
+#else
+	  to->handle_property_get  = to->parent->handle_property_get;
+      to->handle_property_set  = to->parent->handle_property_set;
+      to->handle_function_call = to->parent->handle_function_call;
+#endif
+    }
+    efree(s);
+  }
+
+  old = MMCG(class_entry);
+  MMCG(class_entry) = to;
+
+#ifdef ZEND_ENGINE_2
+  to->refcount = 1;
+
+#if MMC_ENCODER_VERSION < 2
+  to->line_start = decode32(p, l);
+  to->line_end = decode32(p, l);
+  to->filename = decode_filename(p, l TSRMLS_CC);
+#else
+  if (((loader_data*)MMCG(mem))->version < 2) {
+    to->line_start = decode32(p, l);
+    to->line_end = decode32(p, l);
+    to->filename = decode_zstr(p, l);
+    efree(to->filename);
+  }
+  to->line_start = ((loader_data*)MMCG(mem))->lineno;
+  to->line_end = ((loader_data*)MMCG(mem))->lineno;
+  to->filename = ((loader_data*)MMCG(mem))->filename;
+#endif
+  to->doc_comment = decode_lstr(&to->doc_comment_len, p, l);
+
+  zend_hash_init(&to->constants_table, 0, NULL, ZVAL_PTR_DTOR, 0);
+  decode_zval_hash(&to->constants_table, p, l);
+
+  zend_hash_init(&to->default_properties, 0, NULL, ZVAL_PTR_DTOR, 0);
+  decode_zval_hash(&to->default_properties, p, l);
+
+/*???FIXME
+  zend_hash_init_ex(&to->properties_info, 0, NULL, (dtor_func_t)zend_destroy_property_info, 0, 0);
+*/
+  zend_hash_init_ex(&to->properties_info, 0, NULL, (dtor_func_t)NULL, 0, 0);
+  decode_hash(&to->properties_info, sizeof(zend_property_info), (decode_bucket_t)decode_property_info, p, l TSRMLS_CC);
+
+  ALLOC_HASHTABLE(to->static_members);
+  zend_hash_init_ex(to->static_members, 0, NULL, ZVAL_PTR_DTOR, 0, 0);
+  decode_zval_hash(to->static_members, p, l);
+
+  {
+    Bucket *q = to->properties_info.pListHead;
+    while (q != NULL) {
+      zend_property_info* x = (zend_property_info*)q->pData;
+      Bucket * y = NULL;
+      if ((x->flags & ZEND_ACC_STATIC) && to->static_members != NULL && to->static_members->nNumOfElements > 0) {
+        y = to->static_members->pListHead;
+      } else if ((x->flags & ZEND_ACC_STATIC) == 0 && to->default_properties.nNumOfElements > 0) {
+        y = to->default_properties.pListHead;
+      }
+      while (y != NULL) {
+        if ((int)y->nKeyLength == x->name_length+1 &&
+             memcmp(y->arKey, x->name, x->name_length+1) == 0) {
+          x->h = y->h;
+          break;
+        }
+        y = y->pListNext;
+      }
+      q = q->pListNext;
+    }
+  }
+
+#else
+  to->refcount = emalloc(sizeof(*to->refcount));
+  *to->refcount = 1;
+
+  zend_hash_init(&to->default_properties, 0, NULL, ZVAL_PTR_DTOR, 0);
+  decode_zval_hash_noref(&to->default_properties, p, l);
+#endif
+  zend_hash_init(&to->function_table, 0, NULL, ZEND_FUNCTION_DTOR, 0);
+  decode_hash(&to->function_table, sizeof(zend_op_array), (decode_bucket_t)decode_op_array, p, l TSRMLS_CC);
+  to->constants_updated = 0;
+
+  MMCG(class_entry) = old;
+
+  return to;
+}
+
+zend_op_array* eaccelerator_load(char* src, int src_len TSRMLS_DC) {
+  zval func;
+  zval gzstring;
+  zval retval;
+  zval param;
+  zval *params[1];
+  zend_op_array* to = NULL;
+  zend_bool error_reported = 0;
+
+  if (!zend_hash_exists(EG(function_table), "gzuncompress", sizeof("gzuncompress"))) {
+    zend_error(E_ERROR, "Turck MMCache Loader requires php_zlib extension\n");
+    return NULL;
+  }
+
+  ZVAL_STRING(&func, "base64_decode", 0);
+  INIT_ZVAL(param);
+  params[0] = &param;
+  ZVAL_STRINGL(params[0], src, src_len, 0);
+  if (call_user_function(CG(function_table), (zval**)NULL, &func, &gzstring, 1, params TSRMLS_CC) == SUCCESS &&
+      gzstring.type == IS_STRING) {
+    ZVAL_STRING(&func, "gzuncompress", 0);
+    params[0] = &gzstring;
+    if (call_user_function(CG(function_table), (zval**)NULL, &func, &retval, 1, params TSRMLS_CC) == SUCCESS &&
+        retval.type == IS_STRING) {
+      zend_bool old_in_compilation = CG(in_compilation);
+      zend_bool old_in_execution   = EG(in_execution);
+      zval_dtor(&gzstring);
+      zend_try {
+        char*        p = retval.value.str.val;
+        unsigned int l = retval.value.str.len;
+        char *s;
+        unsigned char c;
+        unsigned int  v;
+
+        s = decode_zstr_noalloc(&p, &l);
+        if (s != NULL && strcmp(s,"EACCELERATOR") == 0) {
+          v = decode32(&p, &l);
+          if (v <= MMC_ENCODER_VERSION) {
+            loader_data data;
+            data.version  = v;
+            data.filename = NULL;
+            data.lineno = 0;
+            MMCG(mem) = (char*)&data;
+            c = decode(&p, &l);
+#ifdef ZEND_ENGINE_2
+            if (c == 2) {
+#else
+            if (c == 1) {
+#endif
+              MMCG(class_entry) = NULL;
+#if MMC_ENCODER_VERSION > 1
+              if (CG(in_compilation)) {
+                data.filename = CG(compiled_filename);
+                data.lineno = 0;
+              } else {
+                char* old = CG(compiled_filename);
+                if (EG(active_op_array && EG(active_op_array)->filename)) {
+                  data.filename = zend_set_compiled_filename(EG(active_op_array)->filename TSRMLS_CC);
+                }
+                CG(compiled_filename) = old;
+                data.lineno = zend_get_executed_lineno(TSRMLS_C);
+              }
+#endif
+              while (1) {
+                c = decode(&p, &l);
+                if (c == MMC_ENCODER_CLASS) {
+#ifdef ZEND_ENGINE_2
+                  zend_class_entry* x;
+                  s = decode_lstr_noalloc(&v, &p, &l);
+                  x = decode_class_entry(NULL, &p, &l TSRMLS_CC);
+#else
+                  zend_class_entry x;
+                  s = decode_lstr_noalloc(&v, &p, &l);
+                  decode_class_entry(&x, &p, &l TSRMLS_CC);
+#endif
+                  if ((s[0] == '\000') &&
+                      zend_hash_exists(CG(class_table), s, v)) {
+#ifdef ZEND_ENGINE_2
+                  } else if (zend_hash_add(CG(class_table), s, v,
+                      &x, sizeof(zend_class_entry*), NULL) == FAILURE) {
+#else
+                  } else if (zend_hash_add(CG(class_table), s, v,
+                      &x, sizeof(zend_class_entry), NULL) == FAILURE) {
+#endif
+                    error_reported = 1;
+                    zend_error(E_ERROR, "Cannot redeclare class %s", s);
+                  }
+                } else if (c == MMC_ENCODER_END) {
+                  break;
+                } else {
+                  zend_bailout();
+                }
+              }
+              while (1) {
+                c = decode(&p, &l);
+                if (c == MMC_ENCODER_FUNCTION) {
+                  zend_op_array x;
+                  s = decode_lstr_noalloc(&v, &p, &l);
+                  decode_op_array(&x, &p, &l TSRMLS_CC);
+                  if ((s[0] == '\000') &&
+                      zend_hash_exists(CG(function_table), s, v)) {
+                  } else if (zend_hash_add(CG(function_table), s, v,
+                             &x, sizeof(zend_op_array), NULL) == FAILURE) {
+                    error_reported = 1;
+                    zend_error(E_ERROR, "Cannot redeclare %s()", s);
+                  }
+                } else if (c == MMC_ENCODER_END) {
+                  break;
+                } else {
+                  zend_bailout();
+                }
+              }
+              to = decode_op_array(NULL, &p, &l TSRMLS_CC);
+              if (l != 0) {
+                zend_bailout();
+              }
+            } else {
+              error_reported = 1;
+              zend_error(E_ERROR, "MMCache Loader can't load code. Icorrect Zend Engine version");
+            }
+          } else {
+            error_reported = 1;
+            zend_error(E_ERROR, "MMCache Loader can't load code. Icorrect MMCache encoder version (%u)", v);
+          }
+        } else {
+          error_reported = 1;
+          zend_error(E_ERROR, "MMCache Loader can't load code. Icorrect code");
+        }
+      } zend_catch {
+        CG(in_compilation) = old_in_compilation;
+        EG(in_execution)   = old_in_execution;
+        to = NULL;
+      } zend_end_try();
+      zval_dtor(&retval);
+    }
+  }
+  if (to == NULL) {
+    if (error_reported) {
+      zend_bailout();
+    } else {
+      zend_error(E_ERROR, "MMCache Loader can't load code. Icorrect code");
+    }
+  }
+  return to;
+}
+
+PHP_FUNCTION(eaccelerator_load) {
+  char *src;
+  int   src_len;
+  zend_op_array* op_array;
+
+  if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
+    "s", &src, &src_len) == FAILURE) {
+    RETURN_FALSE;
+  }
+  if ((op_array = eaccelerator_load(src, src_len TSRMLS_CC)) != NULL) {
+    zval *local_retval_ptr=NULL;
+    zend_function_state *original_function_state_ptr = EG(function_state_ptr);
+    zval **original_return_value = EG(return_value_ptr_ptr);
+    zend_op_array *original_op_array = EG(active_op_array);
+    zend_op **original_opline_ptr = EG(opline_ptr);
+
+    EG(return_value_ptr_ptr) = &local_retval_ptr;
+    EG(active_op_array) = op_array;
+
+    zend_execute(op_array TSRMLS_CC);
+
+    if (local_retval_ptr) {
+      if (return_value != NULL) {
+        COPY_PZVAL_TO_ZVAL(*return_value, local_retval_ptr);
+      } else {
+        zval_ptr_dtor(&local_retval_ptr);
+      }
+    } else if (return_value) {
+      INIT_ZVAL(*return_value);
+    }
+
+#ifdef ZEND_ENGINE_2
+    destroy_op_array(op_array TSRMLS_CC);
+#else
+    destroy_op_array(op_array);
+#endif
+    efree(op_array);
+
+    EG(active_op_array) = original_op_array;
+    EG(return_value_ptr_ptr)=original_return_value;
+    EG(opline_ptr) = original_opline_ptr;
+    EG(function_state_ptr) = original_function_state_ptr;
+
+    return;
+  }
+  RETURN_FALSE;
+}
+
+PHP_FUNCTION(_eaccelerator_loader_file) {
+  if (EG(active_op_array) && EG(active_op_array)->filename) {
+    RETURN_STRING(EG(active_op_array)->filename, 1);
+  } else {
+    RETURN_EMPTY_STRING();
+  }
+}
+
+PHP_FUNCTION(_eaccelerator_loader_line) {
+  RETURN_LONG(zend_get_executed_lineno(TSRMLS_C));
+}
+
+#ifdef HAVE_EACCELERATOR_STANDALONE_LOADER
+ZEND_DECLARE_MODULE_GLOBALS(eaccelerator)
+
+function_entry eaccelerator_loader_functions[] = {
+  PHP_FE(eaccelerator_load, NULL)
+  PHP_FE(_eaccelerator_loader_file, NULL)
+  PHP_FE(_eaccelerator_loader_line, NULL)
+  {NULL, NULL, NULL}
+};
+
+static void eaccelerator_init_globals(zend_eaccelerator_globals *eaccelerator_globals) {
+}
+
+PHP_MINIT_FUNCTION(eaccelerator_loader) {
+  if (zend_hash_exists(&module_registry, EACCELERATOR_EXTENSION_NAME, sizeof(EACCELERATOR_EXTENSION_NAME)) &&
+      zend_hash_exists(CG(function_table), "eaccelerator_load", sizeof("eaccelerator_load"))) {
+    zend_error(E_CORE_WARNING,"Extension \"%s\" is not need with \"%s\". Remove it from php.ini\n", EACCELERATOR_LOADER_EXTENSION_NAME, EACCELERATOR_EXTENSION_NAME);
+    return FAILURE;
+  }
+  ZEND_INIT_MODULE_GLOBALS(eaccelerator, eaccelerator_init_globals, NULL);
+  return SUCCESS;
+}
+
+zend_module_entry eaccelerator_loader_module_entry = {
+#if ZEND_MODULE_API_NO >= 20010901
+  STANDARD_MODULE_HEADER,
+#endif
+  EACCELERATOR_LOADER_EXTENSION_NAME,
+  eaccelerator_loader_functions,
+  PHP_MINIT(eaccelerator_loader),
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+#if ZEND_MODULE_API_NO >= 20010901
+  EACCELERATOR_VERSION,          /* extension version number (string) */
+#endif
+  STANDARD_MODULE_PROPERTIES
+};
+
+#if defined(COMPILE_DL_TURCKLOADER)
+ZEND_GET_MODULE(eaccelerator_loader)
+#endif
+#endif
+
+#endif
+#endif
Index: /eaccelerator/trunk/mm.c
===================================================================
--- /eaccelerator/trunk/mm.c	(revision 4)
+++ /eaccelerator/trunk/mm.c	(revision 4)
@@ -0,0 +1,1263 @@
+/* libmm replacement */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#ifdef WIN32
+#  if 1
+#    define MM_SHM_WIN32
+#    define MM_SEM_WIN32
+#  else
+#    define MM_SHM_MALLOC
+#    define MM_SEM_NONE
+#  endif
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+
+#ifdef WIN32
+#  include <limits.h>
+#else
+#  ifdef HAVE_UNISTD_H
+#    include <unistd.h>
+#  endif
+#  ifdef HAVE_SYS_PARAM_H
+#    include <sys/param.h>
+#  endif
+#  ifdef HAVE_LIMITS_H
+#    include <limits.h>
+#  endif
+#endif
+
+#if defined(MM_SHM_MMAP_FILE) || defined(MM_SHM_MMAP_ZERO) || defined(MM_SHM_MMAP_ANON) || defined(MM_SHM_MMAP_POSIX) || defined(HAVE_MPROTECT)
+#  include <sys/mman.h>
+#endif
+#if defined(MM_SHM_IPC) || defined(MM_SEM_IPC)
+#  include <sys/ipc.h>
+#endif
+#ifdef MM_SHM_IPC
+#  include <sys/shm.h>
+#endif
+#if defined(MM_SHM_WIN32) || defined(MM_SEM_WIN32)
+#  include <windows.h>
+#endif
+#ifdef MM_SHM_MALLOC
+#  include <malloc.h>
+#endif
+#ifdef MM_SEM_IPC
+#  include <sys/sem.h>
+#endif
+#ifdef MM_SEM_FLOCK
+#  include <sys/file.h>
+#endif
+#ifdef MM_SEM_POSIX
+#  include <semaphore.h>
+#endif
+#ifdef MM_SEM_PTHREAD
+#  include <pthread.h>
+#endif
+
+struct mm_mutex;
+
+typedef struct mm_free_bucket {
+  size_t                 size;
+  struct mm_free_bucket* next;
+} mm_free_bucket;
+
+typedef struct mm_core {
+  size_t           size;
+  void*            start;
+  size_t           available;
+  void*            attach_addr;
+  struct mm_mutex* lock;
+  mm_free_bucket*  free_list;
+} mm_core;
+
+typedef union mm_mem_head {
+  size_t size;
+  double a1;
+  int (*a2)(int);
+  void *a3;
+} mm_mem_head;
+
+#define MM_SIZE(sz)       (sizeof(mm_mem_head)+(sz))
+#define PTR_TO_HEAD(p)    (((mm_mem_head *)(p)) - 1)
+#define HEAD_TO_PTR(p)    ((void *)(((mm_mem_head *)(p)) + 1))
+
+#define MM mm_core
+#define MM_PRIVATE
+#include "mm.h"
+
+typedef union mm_word {
+  size_t size;
+  void*  ptr;
+  double d;
+  int (*func)(int);
+} mm_word;
+
+#if (defined (__GNUC__) && __GNUC__ >= 2)
+#define MM_PLATFORM_ALIGNMENT (__alignof__ (mm_word))
+#else
+#define MM_PLATFORM_ALIGNMENT (sizeof(mm_word))
+#endif
+
+#define MM_ALIGN(n) (void*)((((size_t)(n)-1) & ~(MM_PLATFORM_ALIGNMENT-1)) + MM_PLATFORM_ALIGNMENT)
+/*#define MM_ALIGN(n) (void*)((1+(((size_t)(n)-1) / sizeof(mm_word))) * sizeof(mm_word))*/
+
+#ifndef MAXPATHLEN
+#  ifdef PATH_MAX
+#    define MAXPATHLEN PATH_MAX
+#  elif defined(_POSIX_PATH_MAX)
+#    define MAXPATHLEN _POSIX_PATH_MAX
+#  else
+#    define MAXPATHLEN 256
+#  endif
+#endif
+
+#undef MM_SHM_CAN_ATTACH
+
+static int strxcat(char* dst, const char* src, int size) {
+  int dst_len = strlen(dst);
+  int src_len = strlen(src);
+  if (dst_len + src_len < size) {
+    memcpy(dst+dst_len, src, src_len+1);
+    return 1;
+  } else {
+    memcpy(dst+dst_len, src, (size-1)-dst_len);
+    dst[size-1] = '\000';
+    return 0;
+  }
+}
+
+#if defined(MM_SEM_SPINLOCK)
+
+#if defined(__GNUC__) && defined(i386)
+#  include "x86_spinlocks.h"
+#else
+#  error "spinlocks are not implemented for your system"
+#endif
+
+#define MM_SEM_TYPE "spinlock"
+#define MM_SEM_CAN_ATTACH
+
+typedef struct mm_mutex {
+  spinlock_t spinlock;
+} mm_mutex;
+
+static int mm_attach_lock(const char* key, mm_mutex* lock) {
+  return 1;
+}
+
+static int mm_init_lock(const char* key, mm_mutex* lock) {
+  spinlock_init(&lock->spinlock);
+  return 1;
+}
+
+static int mm_do_lock(mm_mutex* lock, int kind) {
+  spinlock_lock(&lock->spinlock);
+  return 1;
+}
+
+static int mm_do_unlock(mm_mutex* lock) {
+  spinlock_unlock(&lock->spinlock);
+  return 1;
+}
+
+static void mm_destroy_lock(mm_mutex* lock) {
+}
+
+#elif defined(MM_SEM_PTHREAD)
+
+#define MM_SEM_TYPE "pthread"
+
+typedef struct mm_mutex {
+  pthread_mutex_t mutex;
+} mm_mutex;
+
+static int mm_init_lock(const char* key, mm_mutex* lock) {
+  pthread_mutexattr_t mattr;
+
+  if (pthread_mutexattr_init(&mattr) != 0) {
+    return 0;
+  }
+  if (pthread_mutexattr_setpshared(&mattr, PTHREAD_PROCESS_SHARED) != 0) {
+    return 0;
+  }
+  if (pthread_mutex_init(&lock->mutex, &mattr) != 0) {
+    return 0;
+  }
+  pthread_mutexattr_destroy(&mattr);
+  return 1;
+}
+
+static int mm_do_lock(mm_mutex* lock, int kind) {
+  if (pthread_mutex_lock(&lock->mutex) != 0) {
+    return 0;
+  }
+  return 1;
+}
+
+static int mm_do_unlock(mm_mutex* lock) {
+  if (pthread_mutex_unlock(&lock->mutex) != 0) {
+    return 0;
+  }
+  return 1;
+}
+
+static void mm_destroy_lock(mm_mutex* lock) {
+  pthread_mutex_destroy(&lock->mutex);
+}
+
+#elif defined(MM_SEM_POSIX)
+
+/* not tested */
+
+#define MM_SEM_TYPE "posix"
+
+typedef struct mm_mutex {
+  sem_t* sem;
+} mm_mutex;
+
+static int mm_init_lock(const char* key, mm_mutex* lock) {
+#ifdef SEM_NAME_LEN
+  char s[SEM_NAME_LEN];
+
+  strncpy(s,key,SEM_NAME_LEN-1);
+  strxcat(s,".sem.XXXXXX",SEM_NAME_LEN);
+#else
+  char s[MAXPATHLEN];
+
+  strncpy(s,key,MAXPATHLEN-1);
+  strxcat(s,".sem.XXXXXX",MAXPATHLEN);
+#endif
+  if (mktemp(s) == NULL) return 0;
+  if ((lock->sem = sem_open(s, O_CREAT, S_IRUSR | S_IWUSR, 1)) == (sem_t*)SEM_FAILED) {
+    return 0;
+  }
+  sem_unlink(s);
+  return 1;
+}
+
+static int mm_do_lock(mm_mutex* lock, int kind) {
+  return (sem_wait(lock->sem) == 0);
+}
+
+static int mm_do_unlock(mm_mutex* lock) {
+  return (sem_post(lock->sem) == 0);
+}
+
+static void mm_destroy_lock(mm_mutex* lock) {
+  sem_close(lock->sem);
+}
+
+#elif defined(MM_SEM_IPC)
+
+#define MM_SEM_TYPE "sysvipc"
+
+#ifndef HAVE_SEMUN
+union semun {
+    int val;
+    struct semid_ds *buf;
+    unsigned short *array;
+    struct seminfo *__buf;
+};
+#endif
+
+typedef struct mm_mutex {
+  int semid;
+} mm_mutex;
+
+static int mm_init_lock(const char* key, mm_mutex* lock) {
+  int rc;
+  union semun arg;
+
+  if ((lock->semid = semget(IPC_PRIVATE, 1, IPC_CREAT | IPC_EXCL | S_IRUSR | S_IWUSR)) < 0) {
+    return 0;
+  }
+  arg.val = 1;
+  do {
+    rc = semctl(lock->semid, 0, SETVAL, arg);
+  } while (rc < 0 && errno == EINTR);
+  if (rc < 0) {
+    do {
+      semctl(lock->semid, 0, IPC_RMID, 0);
+    } while (rc < 0 && errno == EINTR);
+    return 0;
+  }
+  return 1;
+}
+
+static int mm_do_lock(mm_mutex* lock, int kind) {
+  int rc;
+  struct sembuf op;
+
+  op.sem_num = 0;
+  op.sem_op  = -1;
+  op.sem_flg = SEM_UNDO;
+  do {
+    rc = semop(lock->semid, &op, 1);
+  } while (rc < 0 && errno == EINTR);
+  return (rc == 0);
+}
+
+static int mm_do_unlock(mm_mutex* lock) {
+  int rc;
+  struct sembuf op;
+
+  op.sem_num = 0;
+  op.sem_op  = 1;
+  op.sem_flg = SEM_UNDO;
+  do {
+    rc = semop(lock->semid, &op, 1);
+  } while (rc < 0 && errno == EINTR);
+  return (rc == 0);
+}
+
+static void mm_destroy_lock(mm_mutex* lock) {
+  int rc;
+  do {
+    rc = semctl(lock->semid, 0, IPC_RMID, 0);
+  } while (rc < 0 && errno == EINTR);
+}
+
+#elif defined(MM_SEM_FCNTL)
+
+#define MM_SEM_TYPE "fcntl"
+
+typedef struct mm_mutex {
+  int fd;
+} mm_mutex;
+
+static int mm_init_lock(const char* key, mm_mutex* lock) {
+  char s[MAXPATHLEN];
+
+  strncpy(s,key,MAXPATHLEN-1);
+  strxcat(s,".sem.XXXXXX",MAXPATHLEN);
+  lock->fd =mkstemp(s);
+  if (lock->fd != -1) {
+    unlink(s);
+  }
+  return (lock->fd != -1);
+}
+
+static int mm_do_lock(mm_mutex* lock, int kind) {
+  int rc;
+  struct flock l;
+  l.l_whence   = SEEK_SET;
+  l.l_start    = 0;
+  l.l_len      = 0;
+  l.l_pid      = 0;
+  if (kind == MM_LOCK_RD) {
+    l.l_type     = F_RDLCK;
+  } else {
+    l.l_type     = F_WRLCK;
+  }
+  do {
+    rc = fcntl(lock->fd, F_SETLKW, &l);
+  } while (rc < 0 && errno == EINTR);
+  return (rc == 0);
+}
+
+static int mm_do_unlock(mm_mutex* lock) {
+  int rc;
+  struct flock l;
+  l.l_whence   = SEEK_SET;
+  l.l_start    = 0;
+  l.l_len      = 0;
+  l.l_pid      = 0;
+  l.l_type     = F_UNLCK;
+  do {
+    rc = fcntl(lock->fd, F_SETLKW, &l);
+  } while (rc < 0 && errno == EINTR);
+  return (rc == 0);
+}
+
+static void mm_destroy_lock(mm_mutex* lock) {
+  close(lock->fd);
+}
+
+#elif defined(MM_SEM_FLOCK)
+
+/* this method is not thread safe */
+
+#define MM_SEM_TYPE "flock"
+
+static int   mm_flock_fd  = -1;
+static pid_t mm_flock_pid = -1;
+
+typedef struct mm_mutex {
+  char filename[MAXPATHLEN];
+} mm_mutex;
+
+static int mm_init_lock(const char* key, mm_mutex* lock) {
+  strncpy(lock->filename,key,MAXPATHLEN-1);
+  strxcat(lock->filename,".sem.XXXXXX",MAXPATHLEN);
+  mm_flock_fd =mkstemp(lock->filename);
+  if (mm_flock_fd != -1) {
+#if defined(F_SETFD) && defined(FD_CLOEXEC)
+    fcntl(mm_flock_fd, F_SETFD, FD_CLOEXEC);
+#endif
+    mm_flock_pid = getpid();
+    return 1;
+  }
+  return 0;
+}
+
+static int mm_do_lock(mm_mutex* lock, int kind) {
+  pid_t pid = getpid();
+  int rc;
+  if (kind == MM_LOCK_RD) {
+    kind = LOCK_SH;
+  } else {
+    kind = LOCK_EX;
+  }
+
+  if (mm_flock_fd == -1 || mm_flock_pid != pid) {
+    mm_flock_fd = open(lock->filename, O_RDWR, S_IRUSR | S_IWUSR);
+    if (mm_flock_fd == -1) {
+      return 0;
+    }
+#if defined(F_SETFD) && defined(FD_CLOEXEC)
+    fcntl(mm_flock_fd, F_SETFD, FD_CLOEXEC);
+#endif
+    mm_flock_pid = pid;
+  }
+  do {
+    rc = flock(mm_flock_fd, kind);
+  } while (rc < 0 && errno == EINTR);
+  return (rc == 0);
+}
+
+static int mm_do_unlock(mm_mutex* lock) {
+  int rc;
+  if (mm_flock_fd == -1) {
+    mm_flock_fd = open(lock->filename, O_RDWR, S_IRUSR | S_IWUSR);
+    if (mm_flock_fd == -1) {
+      return 0;
+    }
+  }
+  do {
+    rc = flock(mm_flock_fd, LOCK_UN);
+  } while (rc < 0 && errno == EINTR);
+  return (rc == 0);
+}
+
+static void mm_destroy_lock(mm_mutex* lock) {
+  close(mm_flock_fd);
+  unlink(lock->filename);
+}
+
+#elif defined(MM_SEM_BEOS)
+
+#define MM_SEM_TYPE "beos"
+#error "Semophore type (MM_SEM_BEOS) is not implemented"
+
+#elif defined(MM_SEM_OS2)
+
+#define MM_SEM_TYPE "os2"
+#error "Semophore type (MM_SEM_OS2) is not implemented"
+
+#elif defined(MM_SEM_WIN32)
+
+#define MM_SEM_TYPE "win32"
+#define MM_SEM_CAN_ATTACH
+
+typedef struct mm_mutex {
+  HANDLE hMutex;
+} mm_mutex;
+
+static mm_mutex g_lock;
+
+static int mm_attach_lock(const char* key, mm_mutex* lock) {
+  char* ch;
+  char name[256];
+  HANDLE hMutex;
+
+  strncpy(name, key, 255);
+  strxcat(name, ".sem", 255);
+  for (ch = name; *ch; ++ch) {
+    if (*ch == ':' || *ch == '/' || *ch == '\\') {
+      *ch = '_';
+    }
+  }
+  g_lock.hMutex = hMutex = OpenMutex(MUTEX_ALL_ACCESS, FALSE, name);
+  if (!g_lock.hMutex) {
+    return 0;
+  }
+  return 1;
+}
+
+static int mm_init_lock(const char* key, mm_mutex* lock) {
+  char* ch;
+  char name[256];
+  strncpy(name, key, 255);
+  strxcat(name, ".sem", 255);
+  for (ch = name; *ch; ++ch) {
+    if (*ch == ':' || *ch == '/' || *ch == '\\') {
+      *ch = '_';
+    }
+  }
+  g_lock.hMutex = CreateMutex(NULL, FALSE, name);
+  if (!g_lock.hMutex) {
+    return 0;
+  }
+  return 1;
+}
+
+static void mm_destroy_lock(mm_mutex* lock) {
+  CloseHandle(g_lock.hMutex);
+}
+
+static int mm_do_lock(mm_mutex* lock, int kind) {
+  DWORD rv;
+
+  rv = WaitForSingleObject(g_lock.hMutex, INFINITE);
+
+  if (rv == WAIT_OBJECT_0 || rv == WAIT_ABANDONED) {
+    return 1;
+  }
+  return 0;
+}
+
+static int mm_do_unlock(mm_mutex* lock) {
+  if (ReleaseMutex(g_lock.hMutex) == 0) {
+    return 0;
+  }
+  return 1;
+}
+
+#elif defined(MM_SEM_NONE)
+
+#define MM_SEM_TYPE "none"
+#define MM_SEM_CAN_ATTACH
+
+
+typedef struct mm_mutex {
+  int semid;
+} mm_mutex;
+
+static int mm_attach_lock(const char* key, mm_mutex* lock) {
+  return 1;
+}
+
+static int mm_init_lock(const char* key, mm_mutex* lock) {
+  return 1;
+}
+
+static void mm_destroy_lock(mm_mutex* lock) {
+}
+
+static int mm_do_lock(mm_mutex* lock, int kind) {
+  return 1;
+}
+
+static int mm_do_unlock(mm_mutex* lock) {
+  return 1;
+}
+
+#else
+#  error "Semaohore type is not selected. Define one of the following: MM_SEM_SPINLOCK, MM_SEM_PTHREAD, MM_SEM_POSIX, MM_SEM_IPC, MM_SEM_FCNTL, MM_SEM_FLOCK, MM_SEM_BEOS, MM_SEM_OS2, MM_SEM_WIN32"
+#endif
+
+int mm_lock(MM* mm, int kind) {
+  return mm_do_lock(mm->lock, kind);
+}
+
+int mm_unlock(MM* mm) {
+  return mm_do_unlock(mm->lock);
+}
+
+/* Shared Memory Implementations */
+
+#if defined(MM_SHM_IPC)
+
+#define MM_SHM_TYPE "sysvipc"
+
+static MM* mm_create_shm(const char* key, size_t size) {
+  int fd;
+  void** segment = NULL;
+  if ((fd = shmget(IPC_PRIVATE, size, (IPC_CREAT | SHM_R | SHM_W))) != -1) {
+    MM* p;
+    if ((p = (MM*)shmat(fd, NULL, 0)) != ((void *)-1)) {
+      struct shmid_ds shmbuf;
+      if (shmctl(fd, IPC_STAT, &shmbuf) == 0) {
+        shmbuf.shm_perm.uid = getuid();
+        shmbuf.shm_perm.gid = getgid();
+        if (shmctl(fd, IPC_SET, &shmbuf) == 0) {
+          shmctl(fd, IPC_RMID, NULL);
+          p->size = size;
+          segment = (void**)((char*)p+sizeof(MM));
+          *segment = (void*)-1;
+          segment++;
+          p->start = segment;
+          return p;
+        }
+      }
+      shmdt(p);
+    }
+    shmctl(fd, IPC_RMID, NULL);
+  } else {
+    /* can't get one shared memory segment, trying to get several */
+    size_t seg_size = 1024*1024;
+    size_t orig_size = size;
+    void*  p;
+    MM*    root = NULL;
+    char*  prev = NULL;
+
+    while (seg_size <= size/2) {
+      seg_size *= 2;
+    }
+    while ((fd = shmget(IPC_PRIVATE, seg_size, (IPC_CREAT | SHM_R | SHM_W))) == -1) {
+      if (seg_size <= 1024*1024) {
+        return (MM*)-1;
+      }
+      seg_size /= 2;
+    }
+    while (size > 0) {
+      if (fd != -1 ||
+          (fd = shmget(IPC_PRIVATE, (size > seg_size)?seg_size:size, (IPC_CREAT | SHM_R | SHM_W))) != -1) {
+        if ((p = (void *)shmat(fd, prev?(prev+seg_size):NULL, 0)) != ((void *)-1) &&
+            (prev == NULL || prev + seg_size == p)) {
+          struct shmid_ds shmbuf;
+/*???
+          memset(p, 0, (size > seg_size)?seg_size:size);
+*/
+          if (shmctl(fd, IPC_STAT, &shmbuf) == 0) {
+            shmbuf.shm_perm.uid = getuid();
+            shmbuf.shm_perm.gid = getgid();
+            if (shmctl(fd, IPC_SET, &shmbuf) == 0) {
+              shmctl(fd, IPC_RMID, NULL);
+              if (root == NULL) {
+                root = (MM*)p;
+                segment = (void**)((char*)p+sizeof(MM));
+              } else {
+                *segment = p;
+                segment++;
+              }
+              prev = (char*)p;
+              fd = -1;
+              if (size > seg_size) {
+                size -= seg_size;
+              } else {
+                size = 0;
+              }
+              continue;
+            }
+          }
+          shmdt(p);
+        }
+        shmctl(fd, IPC_RMID, NULL);
+      }
+      if (root != NULL) {
+        while (segment > (void**)((char*)root+sizeof(MM))) {
+          segment--;
+          shmdt(*segment);
+        }
+      }
+      shmdt(root);
+      return (MM*)-1;
+    }
+    *segment = (void*)-1;
+    segment++;
+    root->size  = orig_size;
+    root->start = (void*)segment;
+    return root;
+  }
+  return (MM*)-1;
+}
+
+static void mm_destroy_shm(MM* mm) {
+  void** segment = (void**)((char*)mm+sizeof(MM));
+  while (*segment != (void*)-1) {
+    shmdt(*segment);
+    ++segment;
+  }
+  shmdt(mm);
+}
+
+#elif defined(MM_SHM_MMAP_ANON)
+
+#define MM_SHM_TYPE "mmap_anon"
+
+#ifndef MAP_ANON
+#  ifdef MAP_ANONYMOUS
+#    define MAP_ANON MAP_ANONYMOUS
+#  endif
+#endif
+
+static MM* mm_create_shm(const char* key, size_t size) {
+  MM* p;
+  p = (MM*)mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
+  if (p != (MM*)-1) {
+    p->size = size;
+    p->start = (char*)p+sizeof(MM);
+  }
+  return p;
+}
+
+static void mm_destroy_shm(MM* mm) {
+  munmap(mm,mm->size);
+}
+
+#elif defined(MM_SHM_MMAP_ZERO)
+
+#define MM_SHM_TYPE "mmap_zero"
+
+static MM* mm_create_shm(const char* key, size_t size) {
+  MM* p;
+  int fd = open("/dev/zero", O_RDWR, S_IRUSR | S_IWUSR);
+  if (fd == -1) {
+    return (MM*)-1;
+  }
+  p = (MM*)mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+  close(fd);
+  if (p != (MM*)-1) {
+    p->size = size;
+    p->start = (char*)p+sizeof(MM);
+  }
+  return p;
+}
+
+static void mm_destroy_shm(MM* mm) {
+  munmap(mm,mm->size);
+}
+
+#elif defined(MM_SHM_MMAP_POSIX)
+
+#define MM_SHM_TYPE "mmap_posix"
+
+/* Not Tested */
+
+static MM* mm_create_shm(const char* key, size_t size) {
+  MM* p;
+  int fd;
+  char s[MAXPATHLEN];
+
+  strncpy(s,key,MAXPATHLEN-1);
+  strxcat(s,".shm.XXXXXX",MAXPATHLEN);
+  if (mktemp(s) == NULL) {
+    return (MM*)-1;
+  }
+  if ((fd = shm_open(s, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR)) == -1) {
+    return (MM*)-1;
+  }
+  if (ftruncate(fd, size) < 0) {
+    close(fd);
+    shm_unlink(s);
+    return (MM*)-1;
+  }
+  p = (MM*)mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+  shm_unlink(s);
+  close(fd);
+  if (p != (MM*)-1) {
+    p->size = size;
+    p->start = (char*)p+sizeof(MM);
+  }
+  return p;
+}
+
+static void mm_destroy_shm(MM* mm) {
+  munmap(mm,mm->size);
+}
+
+#elif defined(MM_SHM_MMAP_FILE)
+
+#define MM_SHM_TYPE "mmap_file"
+
+static MM* mm_create_shm(const char* key, size_t size) {
+  MM* p;
+  int fd;
+  char s[MAXPATHLEN];
+
+  strncpy(s,key,MAXPATHLEN-1);
+  strxcat(s,".shm.XXXXXX",MAXPATHLEN);
+  fd = mkstemp(s);
+  if (fd < 0) {
+    return (MM*)-1;
+  }
+  if (ftruncate(fd, size) < 0) {
+    return (MM*)-1;
+  }
+  p = (MM*)mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+  close(fd);
+  unlink(s);
+  if (p != (MM*)-1) {
+    p->size = size;
+    p->start = (char*)p+sizeof(MM);
+  }
+  return p;
+}
+
+static void mm_destroy_shm(MM* mm) {
+  munmap(mm,mm->size);
+}
+
+#elif defined(MM_SHM_BEOS)
+
+#define MM_SHM_TYPE "beos"
+#error "Shared memeory type (MM_SHM_BEOS) is not implemented"
+
+#elif defined(MM_SHM_OS2)
+
+#define MM_SHM_TYPE "os2"
+#error "Shared memeory type (MM_SHM_OS2) is not implemented"
+
+#elif defined(MM_SHM_WIN32)
+
+#define MM_SHM_TYPE "win32"
+#define MM_SHM_CAN_ATTACH
+
+static MM* mm_attach_shm(const char* key, size_t size) {
+  HANDLE  shm_handle;
+  MM*     mm;
+  MM*     addr;
+  MM**    addr_ptr;
+  char    s[MAXPATHLEN];
+  char*   ch;
+
+
+  strcpy(s,key);
+  for (ch = s; *ch; ++ch) {
+    if (*ch == ':' || *ch == '/' || *ch == '\\') {
+      *ch = '_';
+    }
+  }
+
+  shm_handle = OpenFileMapping(FILE_MAP_READ | FILE_MAP_WRITE, FALSE, s);
+  if (shm_handle) {
+    mm = (MM*)MapViewOfFile(shm_handle, FILE_MAP_ALL_ACCESS, 0, 0, 0);
+    if (mm == NULL) {
+      return (MM*)-1;
+    }
+/*
+    if (mm->size != size) {
+      UnmapViewOfFile(mm);
+      CloseHandle(shm_handle);
+      return (MM*)-1;
+    }
+*/
+    addr_ptr = (MM**)(((char*)mm)+sizeof(MM));
+    addr = *addr_ptr;
+    if (addr != mm) {
+      UnmapViewOfFile(mm);
+      mm = (MM*)MapViewOfFileEx(shm_handle, FILE_MAP_ALL_ACCESS, 0, 0, 0, addr);
+      if (mm == NULL) {
+        return (MM*)-1;
+      }
+    }
+/*  CloseHandle(shm_handle);*/
+    return mm;
+  }
+  return (MM*)-1;
+}
+
+static MM* mm_create_shm(const char* key, size_t size) {
+  HANDLE  shm_handle;
+  MM*     mm;
+  MM**    addr_ptr;
+  char    s[MAXPATHLEN];
+  char*   ch;
+
+
+  strcpy(s,key);
+  for (ch = s; *ch; ++ch) {
+    if (*ch == ':' || *ch == '/' || *ch == '\\') {
+      *ch = '_';
+    }
+  }
+
+  shm_handle = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, size, s);
+  if (!shm_handle) {
+    return (MM*)-1;
+  }
+  mm = (MM*)MapViewOfFileEx(shm_handle, FILE_MAP_ALL_ACCESS, 0, 0, 0, NULL);
+  if (mm == NULL) {
+    return (MM*)-1;
+  }
+  addr_ptr = (MM**)(((char*)mm)+sizeof(MM));
+  *addr_ptr = mm;
+  mm->size = size;
+  mm->start = ((char*)mm)+sizeof(MM)+sizeof(void*);
+
+/*  CloseHandle(shm_handle);*/
+  return mm;
+}
+
+static void mm_destroy_shm(MM* mm) {
+  UnmapViewOfFile(mm);
+}
+
+#elif defined(MM_SHM_MALLOC)
+
+#define MM_SHM_TYPE "malloc"
+
+static void* mm_create_shm(const char* key, size_t size) {
+  MM* p = (MM*)malloc(sizeof(MM));
+  if (p == NULL) {
+    return (MM*)-1;
+  }
+  p->size  = size;
+  p->start = NULL;
+  return p;
+}
+
+static void mm_destroy_shm(MM* mm) {
+  free(mm);
+}
+
+#else
+#define MM_SHM_TYPE "none"
+#  error "Shared memeory type is not selected. Define one of the following: MM_SHM_IPC, MM_SHM_MMAP_ANON, MM_SHM_MMAP_ZERO, MM_SHM_MMAP_FILE, MM_SHM_MALLOC, MM_SHM_BEOS, MM_SHM_OS2, MM_SHM_WIN32"
+#endif
+
+#ifdef MM_SHM_MALLOC
+static void mm_init(MM* mm) {
+  mm->available = mm->size - sizeof(MM);
+  mm->lock = malloc(sizeof(mm_mutex));
+}
+
+void* mm_malloc_nolock(MM* mm, size_t size) {
+  if (size > 0) {
+    mm_mem_head *p = NULL;
+    if (mm->available >= MM_SIZE(size)) {
+      p = malloc(MM_SIZE(size));
+      if (p != NULL) {
+        p->size = MM_SIZE(size);
+        mm->available -= MM_SIZE(size);
+      }
+    }
+    if (p != NULL) {
+      return HEAD_TO_PTR(p);
+    }
+  }
+  return NULL;
+}
+
+void mm_free_nolock(MM* mm, void* x) {
+  if (x != NULL) {
+    mm_mem_head *p;
+    p = PTR_TO_HEAD(x);
+    mm->available += p->size;
+    free(p);
+  }
+}
+
+size_t mm_maxsize(MM* mm) {
+  size_t ret;
+  mm_lock(mm, MM_LOCK_RD);
+  ret = mm->available - MM_SIZE(0);
+  mm_unlock(mm);
+  return ret;
+}
+
+#else
+static void mm_init(MM* mm) {
+  mm->start = MM_ALIGN(mm->start);
+  mm->attach_addr = (void*)mm;
+  mm->lock = mm->start;
+  mm->start = MM_ALIGN((void*)(((char*)(mm->start)) + sizeof(mm_mutex)));
+  mm->available = mm->size - (((char*)(mm->start))-(char*)mm);
+  mm->free_list = (mm_free_bucket*)mm->start;
+  mm->free_list->size = mm->available;
+  mm->free_list->next = NULL;
+}
+
+void* mm_malloc_nolock(MM* mm, size_t size) {
+  if (size > 0) {
+    mm_mem_head* x = NULL;
+    size_t realsize = (size_t)MM_ALIGN(MM_SIZE(size));
+    if (realsize <= mm->available) {
+      /* Search for free bucket */
+      mm_free_bucket* p = mm->free_list;
+      mm_free_bucket* q = NULL;
+      mm_free_bucket* best = NULL;
+      mm_free_bucket* best_prev = NULL;
+      while (p != NULL) {
+        if (p->size == realsize) {
+          /* Found free bucket with the same size */
+          if (q == NULL) {
+            mm->free_list = p->next;
+            x = (mm_mem_head*)p;
+          } else {
+            q->next = p->next;
+            x = (mm_mem_head*)p;
+          }
+          break;
+        } else if (p->size > realsize && (best == NULL || best->size > p->size)) {
+          /* Found best bucket (smallest bucket with the grater size) */
+          best = p;
+          best_prev = q;
+        }
+        q = p;
+        p = p->next;
+      }
+      if (x == NULL && best != NULL) {
+        if (best->size-realsize < sizeof(mm_free_bucket)) {
+          realsize = best->size;
+          x = (mm_mem_head*)best;
+          if (best_prev == NULL) {
+            mm->free_list = best->next;
+          } else {
+            best_prev->next = best->next;
+          }
+        } else {
+          if (best_prev == NULL) {
+            mm->free_list = (mm_free_bucket*)((char*)best + realsize);
+            mm->free_list->size = best->size-realsize;
+            mm->free_list->next = best->next;
+          } else {
+            best_prev->next = (mm_free_bucket*)((char*)best + realsize);
+            best_prev->next->size = best->size-realsize;
+            best_prev->next->next = best->next;
+          }
+          best->size = realsize;
+          x = (mm_mem_head*)best;
+        }
+      }
+      if (x != NULL) {
+        mm->available -= realsize;
+      }
+    }
+    if (x != NULL) {
+      return HEAD_TO_PTR(x);
+    }
+  }
+  return NULL;
+}
+
+void mm_free_nolock(MM* mm, void* x) {
+  if (x != NULL) {
+    if (x >= mm->start && x < (void*)((char*)mm + mm->size)) {
+      mm_mem_head *p = PTR_TO_HEAD(x);
+      size_t size = p->size;
+      if ((char*)p+size <= (char*)mm + mm->size) {
+        mm_free_bucket* b = (mm_free_bucket*)p;
+        b->next = NULL;
+        if (mm->free_list == NULL) {
+          mm->free_list = b;
+        } else {
+          mm_free_bucket* q = mm->free_list;
+          mm_free_bucket* prev = NULL;
+          mm_free_bucket* next = NULL;
+          while (q != NULL) {
+            if (b < q) {
+              next = q;
+              break;
+            }
+            prev = q;
+            q = q->next;
+          }
+          if (prev != NULL && (char*)prev+prev->size == (char*)b) {
+            if ((char*)next == (char*)b+size) {
+              /* merging with prev and next */
+              prev->size += size + next->size;
+              prev->next = next->next;
+            } else {
+              /* merging with prev */
+              prev->size += size;
+            }
+          } else {
+            if ((char*)next == (char*)b+size) {
+              /* merging with next */
+              b->size += next->size;
+              b->next = next->next;
+            } else {
+              /* don't merge */
+              b->next = next;
+            }
+            if (prev != NULL) {
+              prev->next = b;
+            } else {
+              mm->free_list = b;
+            }
+          }
+        }
+        mm->available += size;
+      }
+    }
+  }
+}
+
+size_t mm_maxsize(MM* mm) {
+  size_t ret = MM_SIZE(0);
+  mm_free_bucket* p;
+  mm_lock(mm, MM_LOCK_RD);
+  p = mm->free_list;
+  while (p != NULL) {
+    if (p->size > ret) {
+      ret = p->size;
+    }
+    p = p->next;
+  }
+  mm_unlock(mm);
+  return ret - MM_SIZE(0);
+}
+#endif
+
+void* mm_malloc(MM* mm, size_t size) {
+  void *ret;
+  mm_lock(mm, MM_LOCK_RW);
+  ret = mm_malloc_nolock(mm,size);
+  mm_unlock(mm);
+  return ret;
+}
+
+void mm_free(MM* mm, void* x) {
+  mm_lock(mm, MM_LOCK_RW);
+  mm_free_nolock(mm,x);
+  mm_unlock(mm);
+}
+
+void mm_set_attach(MM* mm, void* attach_addr) {
+  mm->attach_addr = attach_addr;
+}
+
+void* mm_attach(size_t size, const char* key) {
+#ifdef MM_SHM_CAN_ATTACH
+  MM* mm = mm_attach_shm(key, size);
+  if (mm == (MM*)-1) {
+    return NULL;
+  }
+#ifdef MM_SEM_CAN_ATTACH
+  if (!mm_attach_lock(key, mm->lock)) {
+    mm_destroy_shm(mm);
+    return NULL;
+  }
+#endif
+  return mm->attach_addr;
+#else
+  return NULL;
+#endif
+}
+
+MM* mm_create(size_t size, const char* key) {
+  MM* p;
+  if (size == 0) {
+    size = 32 * 1024 * 1024;
+  }
+  p = mm_create_shm(key, size);
+  if (p == (MM*)-1) {
+    return NULL;
+  }
+  mm_init(p);
+  if (p->lock == NULL) {
+    mm_destroy_shm(p);
+    return NULL;
+  }
+  if (!mm_init_lock(key, p->lock)) {
+    mm_destroy_shm(p);
+    return NULL;
+  }
+  return p;
+}
+
+void mm_destroy(MM* mm) {
+  if (mm != NULL) {
+    mm_destroy_lock(mm->lock);
+    mm_destroy_shm(mm);
+  }
+}
+
+size_t mm_size(MM* mm) {
+  if (mm != NULL) {
+    return mm->size;
+  }
+  return 0;
+}
+
+size_t mm_sizeof(MM* mm, void* x) {
+  mm_mem_head *p;
+  size_t ret;
+  if (mm == NULL) return 0;
+  if (x == NULL) return 0;
+  mm_lock(mm, MM_LOCK_RD);
+  p = PTR_TO_HEAD(x);
+  ret = p->size;
+  mm_unlock(mm);
+  return ret;
+}
+
+size_t mm_available(MM* mm) {
+  size_t available;
+  if (mm != NULL) {
+    mm_lock(mm, MM_LOCK_RD);
+    available = mm->available;
+    mm_unlock(mm);
+    return available;
+  }
+  return 0;
+}
+
+const char* mm_shm_type() {
+  return MM_SHM_TYPE;
+}
+
+const char* mm_sem_type() {
+  return MM_SEM_TYPE;
+}
+
+int mm_protect(MM* mm, int mode) {
+#ifdef HAVE_MPROTECT
+  int pmode = 0;
+  if (mode & MM_PROT_NONE) {
+    pmode |= PROT_NONE;
+  }
+  if (mode & MM_PROT_READ) {
+    pmode |= PROT_READ;
+  }
+  if (mode & MM_PROT_WRITE) {
+    pmode |= PROT_WRITE;
+  }
+  if (mode & MM_PROT_EXEC) {
+    pmode |= PROT_EXEC;
+  }
+  return (mprotect(mm, mm->size, pmode) == 0);
+#endif
+  return 0;
+}
+
+#ifdef MM_TEST_SHM
+int main() {
+  char key[] = "/tmp/mm";
+  size_t size = 64*1024*1024;
+  MM *mm = mm_create(size, key);
+  if (mm == NULL) {
+    return 1;
+  }
+  mm_destroy(mm);
+  return 0;
+}
+#endif
+
+#ifdef MM_TEST_SEM
+int main() {
+  int ret = 0;
+  char key[] = "/tmp/mm";
+  size_t size = 1*1024*1024;
+  MM *mm = mm_create(size, key);
+  if (mm == NULL) {
+    return 1;
+  }
+  if (!mm_lock(mm, MM_LOCK_RW)) {
+    ret = 1;
+  }
+  if (!mm_unlock(mm)) {
+    ret = 1;
+  }
+  if (!mm_lock(mm, MM_LOCK_RD)) {
+    ret = 1;
+  }
+  if (!mm_unlock(mm)) {
+    ret = 1;
+  }
+  mm_destroy(mm);
+  return ret;
+}
+#endif
Index: /eaccelerator/trunk/content.c
===================================================================
--- /eaccelerator/trunk/content.c	(revision 4)
+++ /eaccelerator/trunk/content.c	(revision 4)
@@ -0,0 +1,575 @@
+/*
+   +----------------------------------------------------------------------+
+   | Turck MMCache for PHP Version 4                                      |
+   +----------------------------------------------------------------------+
+   | Copyright (c) 2002-2003 TurckSoft, St. Petersburg                    |
+   | http://www.turcksoft.com                                             |
+   +----------------------------------------------------------------------+
+   | This program is free software; you can redistribute it and/or        |
+   | modify it under the terms of the GNU General Public License          |
+   | as published by the Free Software Foundation; either version 2       |
+   | of the License, or (at your option) any later version.               |
+   |                                                                      |
+   | This program is distributed in the hope that it will be useful,      |
+   | but WITHOUT ANY WARRANTY; without even the implied warranty of       |
+   | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        |
+   | GNU General Public License for more details.                         |
+   |                                                                      |
+   | You should have received a copy of the GNU General Public License    |
+   | along with this program; if not, write to the Free Software          |
+   | Foundation, Inc., 59 Temple Place - Suite 330, Boston,               |
+   | MA  02111-1307, USA.                                                 |
+   |                                                                      |
+   | A copy is availble at http://www.gnu.org/copyleft/gpl.txt            |
+   +----------------------------------------------------------------------+
+   | Author: Dmitry Stogov <mmcache@turckware.ru>                         |
+   +----------------------------------------------------------------------+
+   $Id$
+*/
+
+#include "eaccelerator.h"
+
+#ifdef HAVE_EACCELERATOR
+#ifdef WITH_EACCELERATOR_CONTENT_CACHING
+
+#include "SAPI.h"
+
+#define EACCELERATOR_COMPRESS_MIN 128
+
+static int (*eaccelerator_old_header_handler)(sapi_header_struct *sapi_header, sapi_headers_struct *sapi_headers TSRMLS_DC);
+
+static int eaccelerator_check_compression(sapi_header_struct *sapi_header TSRMLS_DC) {
+  if (strstr(sapi_header->header, "Content-Type") == sapi_header->header) {
+    char *ch = sapi_header->header + sizeof("Content-Type") - 1;
+    while (*ch != '\0' && *ch != ':') {ch++;}
+    if (*ch == ':') {ch++;}
+    while (*ch == ' ') {ch++;}
+    if (strstr(ch, "text") != ch) {
+      MMCG(compress_content) = 0;
+      return 0;
+    }
+  } else if (strstr(sapi_header->header, "Content-Encoding") == sapi_header->header) {
+    MMCG(compress_content) = 0;
+    return 0;
+  }
+  return 1;
+}
+
+static void eaccelerator_free_header(sapi_header_struct *sapi_header) {
+  efree(sapi_header->header);
+}
+
+static int eaccelerator_header_handler(sapi_header_struct *sapi_header, sapi_headers_struct *sapi_headers TSRMLS_DC) {
+  if (MMCG(content_headers) != NULL) {
+    sapi_header_struct x;
+    memcpy(&x, sapi_header, sizeof(sapi_header_struct));
+    x.header = estrndup(sapi_header->header, sapi_header->header_len);
+    zend_llist_add_element(MMCG(content_headers), &x);
+  }
+  eaccelerator_check_compression(sapi_header TSRMLS_CC);
+  if (eaccelerator_old_header_handler) {
+    return eaccelerator_old_header_handler(sapi_header, sapi_headers TSRMLS_CC);
+  } else {
+    return SAPI_HEADER_ADD;
+  }
+}
+
+void eaccelerator_content_cache_startup() {
+  if (eaccelerator_content_cache_place != eaccelerator_none) {
+    eaccelerator_old_header_handler = sapi_module.header_handler;
+    sapi_module.header_handler = eaccelerator_header_handler;
+  }
+}
+
+void eaccelerator_content_cache_shutdown() {
+  if (eaccelerator_content_cache_place != eaccelerator_none) {
+    sapi_module.header_handler = eaccelerator_old_header_handler;
+  }
+}
+
+static int eaccelerator_is_not_modified(zval* return_value TSRMLS_DC) {
+  char  etag[256];
+  zval  **server_vars, **match;
+
+  if (!SG(headers_sent)) {
+    sprintf(etag,"ETag: eaccelerator-%u",eaccelerator_crc32(Z_STRVAL_P(return_value),Z_STRLEN_P(return_value)));
+    sapi_add_header(etag, strlen(etag), 1);
+    if (zend_hash_find(&EG(symbol_table), "_SERVER", sizeof("_SERVER"), (void **) &server_vars) == SUCCESS &&
+        Z_TYPE_PP(server_vars) == IS_ARRAY &&
+        zend_hash_find(Z_ARRVAL_PP(server_vars), "HTTP_IF_NONE_MATCH", sizeof("HTTP_IF_NONE_MATCH"), (void **) &match)==SUCCESS &&
+        Z_TYPE_PP(match) == IS_STRING) {
+      if (strcmp(etag+6,Z_STRVAL_PP(match)) == 0 &&
+          sapi_add_header("HTTP/1.0 304", sizeof("HTTP/1.0 304") - 1, 1) == SUCCESS &&
+          sapi_add_header("Status: 304 Not Modified", sizeof("Status: 304 Not Modified") - 1, 1) == SUCCESS) {
+        zval_dtor(return_value);
+        return_value->value.str.val = empty_string;
+        return_value->value.str.len = 0;
+        /*fprintf(stderr,"\nnot-modified\n");*/
+        return 1;
+      }
+    }
+  }
+  return 0;
+}
+
+static void eaccelerator_put_page(const char* key, int key_len, zval* content, time_t ttl  TSRMLS_DC) {
+  zval cache_array;
+  zval *cache_content;
+  INIT_ZVAL(cache_array);
+  array_init(&cache_array);
+  MAKE_STD_ZVAL(cache_content);
+  if (MMCG(content_headers) && (MMCG(content_headers)->count > 0)) {
+    zend_llist_element *p = MMCG(content_headers)->head;
+    zval *headers;
+    MAKE_STD_ZVAL(headers);
+    array_init(headers);
+    while (p != NULL) {
+      sapi_header_struct* h = (sapi_header_struct*)&p->data;
+      char* s = emalloc(h->header_len+2);
+      s[0] = h->replace?'1':'0';
+      memcpy(s+1, h->header, h->header_len+1);
+      add_next_index_stringl(headers, s, h->header_len+1, 0);
+      p = p->next;
+    }
+    add_assoc_zval(&cache_array, "headers", headers);
+  }
+  memcpy(cache_content, content, sizeof(zval));
+  zval_copy_ctor(cache_content);
+  cache_content->is_ref = 0;
+  cache_content->refcount = 1;
+  add_assoc_zval(&cache_array, "content", cache_content);
+  eaccelerator_put(key, key_len , &cache_array, ttl, eaccelerator_content_cache_place TSRMLS_CC);
+  zval_dtor(&cache_array);
+}
+
+static int eaccelerator_send_header(zval **header TSRMLS_DC) {
+  sapi_add_header_ex(Z_STRVAL_PP(header)+1, Z_STRLEN_PP(header)-1, 1,
+                     (zend_bool)((Z_STRVAL_PP(header)[0] == '0')?0:1) TSRMLS_CC);
+  return SUCCESS;
+}
+
+static int eaccelerator_get_page(const char* key, int key_len, zval* return_value TSRMLS_DC) {
+  int   ret = 0;
+  zval cache_array;
+  zval **headers;
+  zval **content;
+  if (eaccelerator_get(key, key_len, &cache_array, eaccelerator_content_cache_place TSRMLS_CC)) {
+    if (Z_TYPE(cache_array) == IS_ARRAY) {
+      if (zend_hash_find(Z_ARRVAL(cache_array),"content",sizeof("content"),(void**)&content) == SUCCESS &&
+         Z_TYPE_PP(content) == IS_STRING) {
+        if (zend_hash_find(Z_ARRVAL(cache_array),"headers",sizeof("headers"),(void**)&headers) == SUCCESS &&
+           Z_TYPE_PP(headers) == IS_ARRAY) {
+          zend_hash_apply(Z_ARRVAL_PP(headers), (apply_func_t)eaccelerator_send_header TSRMLS_CC);
+        }
+        memcpy(return_value,*content, sizeof(zval));
+        zval_copy_ctor(return_value);
+        ret = 1;
+      }
+    }
+    zval_dtor(&cache_array);
+  }
+  return ret;
+}
+
+static void eaccelerator_compress(char* key, int key_len, zval* return_value, time_t ttl TSRMLS_DC) {
+  zval  **server_vars, **encoding;
+
+  if (MMCG(compression_enabled) &&
+      MMCG(compress_content) &&
+      !SG(headers_sent) &&
+      zend_hash_find(&EG(symbol_table), "_SERVER", sizeof("_SERVER"), (void **) &server_vars) == SUCCESS &&
+      Z_TYPE_PP(server_vars) == IS_ARRAY &&
+      zend_hash_find(Z_ARRVAL_PP(server_vars), "HTTP_ACCEPT_ENCODING", sizeof("HTTP_ACCEPT_ENCODING"), (void **) &encoding)==SUCCESS &&
+      Z_TYPE_PP(encoding) == IS_STRING &&
+      Z_TYPE_P(return_value) == IS_STRING &&
+      Z_STRLEN_P(return_value) >= EACCELERATOR_COMPRESS_MIN) {
+    char* zkey = NULL;
+    int   zkey_len;
+    char* enc;
+    zval  func;
+    zval* params[2];
+    zval  gzstring;
+    int   gzip = 0;
+    zval  level;
+
+    zend_llist_element *p = SG(sapi_headers).headers.head;
+    while (p != NULL) {
+      sapi_header_struct* h = (sapi_header_struct*)&p->data;
+      if (!eaccelerator_check_compression(h TSRMLS_CC)) {
+        eaccelerator_is_not_modified(return_value TSRMLS_CC);
+        return;
+      }
+      p = p->next;
+    }
+
+    if (strstr(Z_STRVAL_PP(encoding),"x-gzip")) {
+      zkey_len = sizeof("gzip_") + key_len - 1;
+      zkey = emalloc(zkey_len+1);
+      memcpy(zkey,"gzip_",sizeof("gzip_")-1);
+      memcpy(zkey+sizeof("gzip_")-1,key,key_len+1);
+      ZVAL_STRING(&func, "gzcompress", 0);
+      enc = "Content-Encoding: x-gzip";
+      params[0] = return_value;
+      gzip = 1;
+    } else if (strstr(Z_STRVAL_PP(encoding),"gzip")) {
+      zkey_len = sizeof("gzip_") + key_len - 1;
+      zkey = emalloc(zkey_len+1);
+      memcpy(zkey,"gzip_",sizeof("gzip_")-1);
+      memcpy(zkey+sizeof("gzip_")-1,key,key_len+1);
+      ZVAL_STRING(&func, "gzcompress", 0);
+      enc = "Content-Encoding: gzip";
+      params[0] = return_value;
+      gzip = 1;
+    } else if (strstr(Z_STRVAL_PP(encoding),"deflate")) {
+      zkey_len = sizeof("deflate_") + key_len - 1;
+      zkey = emalloc(zkey_len+1);
+      memcpy(zkey,"deflate_",sizeof("deflate_")-1);
+      memcpy(zkey+sizeof("deflate_")-1,key,key_len+1);
+      ZVAL_STRING(&func, "gzdeflate", 0);
+      enc = "Content-Encoding: deflate";
+      params[0] = return_value;
+    } else {
+      eaccelerator_is_not_modified(return_value TSRMLS_CC);
+      return;
+    }
+    INIT_ZVAL(level);
+    ZVAL_LONG(&level,MMCG(compress_level));
+    params[1] = &level;
+    if (zkey != NULL &&
+        zend_hash_exists(EG(function_table), Z_STRVAL(func), Z_STRLEN(func)+1) &&
+        call_user_function(CG(function_table), (zval**)NULL, &func, &gzstring, 2, params TSRMLS_CC) == SUCCESS &&
+        gzstring.type == IS_STRING) {
+      if (gzip) {
+        char* ret = emalloc(gzstring.value.str.len+13);
+        unsigned long crc32 = eaccelerator_crc32(Z_STRVAL_P(return_value),Z_STRLEN_P(return_value));
+        ret[0] = '\x1f';
+        ret[1] = '\x8b';
+        ret[2] = '\x08';
+        ret[3] = '\x00';
+        ret[4] = '\x00';
+        ret[5] = '\x00';
+        ret[6] = '\x00';
+        ret[7] = '\x00';
+        ret[8] = '\x00';
+        ret[9] = '\x03';
+        memcpy(ret+10,gzstring.value.str.val+2,gzstring.value.str.len-6);
+        ret[gzstring.value.str.len+4]  = (char)(crc32 & 0xff);
+        ret[gzstring.value.str.len+5]  = (char)((crc32 >> 8) & 0xff);
+        ret[gzstring.value.str.len+6]  = (char)((crc32 >> 16) & 0xff);
+        ret[gzstring.value.str.len+7]  = (char)((crc32 >> 24) & 0xff);
+        ret[gzstring.value.str.len+8]  = (char)(return_value->value.str.len & 0xff);
+        ret[gzstring.value.str.len+9]  = (char)((return_value->value.str.len >> 8) & 0xff);
+        ret[gzstring.value.str.len+10] = (char)((return_value->value.str.len >> 16) & 0xff);
+        ret[gzstring.value.str.len+11] = (char)((return_value->value.str.len >> 24) & 0xff);
+        ret[gzstring.value.str.len+12] = '\x00';
+        STR_FREE(gzstring.value.str.val);
+        gzstring.value.str.val = ret;
+        gzstring.value.str.len += 12;
+      }
+      eaccelerator_put_page(zkey, zkey_len, &gzstring, ttl TSRMLS_CC);
+      if (!eaccelerator_is_not_modified(&gzstring TSRMLS_CC) &&
+          sapi_add_header(enc, strlen(enc), 1) == SUCCESS &&
+          sapi_add_header("Vary: Accept-Encoding", sizeof("Vary: Accept-Encoding") - 1, 1) == SUCCESS) {
+      }
+      efree(zkey);
+      zval_dtor(return_value);
+      memcpy(return_value,&gzstring,sizeof(zval));
+      return;
+    }
+    if (zkey != NULL) {
+      efree(zkey);
+    }
+  }
+  eaccelerator_is_not_modified(return_value TSRMLS_CC);
+}
+
+static void eaccelerator_destroy_headers(TSRMLS_D) {
+  if (MMCG(content_headers) != NULL) {
+    zend_llist_destroy(MMCG(content_headers));
+    efree(MMCG(content_headers));
+    MMCG(content_headers) = NULL;
+  }
+}
+
+PHP_FUNCTION(_eaccelerator_output_handler) {
+  zval* content;
+  long  status;
+  char* s;
+  char* key;
+  int   key_len = 0;
+  time_t ttl = 0;
+
+  if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
+                            "z|l", &content, &status) == FAILURE) {
+    eaccelerator_destroy_headers(TSRMLS_C);
+    return;
+  }
+  memcpy(return_value, content, sizeof(zval));
+  s = key = return_value->value.str.val;
+  if ((status & PHP_OUTPUT_HANDLER_START) != 0) {
+    while (*s) {++s;}
+    ttl = atoi(key);
+    s = key = s+1;
+    if (s - return_value->value.str.val > return_value->value.str.len) {
+      zval_copy_ctor(return_value);
+      eaccelerator_destroy_headers(TSRMLS_C);
+      return;
+    }
+    while (*s) {++s;}
+    key_len = atoi(key);
+    s = key = s+1;
+    if (s - return_value->value.str.val > return_value->value.str.len) {
+      zval_copy_ctor(return_value);
+      eaccelerator_destroy_headers(TSRMLS_C);
+      return;
+    }
+    while (*s) {++s;}
+    ++s;
+    if (s - return_value->value.str.val > return_value->value.str.len) {
+      zval_copy_ctor(return_value);
+      eaccelerator_destroy_headers(TSRMLS_C);
+      return;
+    }
+  }
+  return_value->value.str.len -= (s-return_value->value.str.val);
+  return_value->value.str.val = s;
+  zval_copy_ctor(return_value);
+  if ((status & PHP_OUTPUT_HANDLER_START) != 0 &&
+      (status & PHP_OUTPUT_HANDLER_END) != 0 &&
+      !(PG(connection_status) & PHP_CONNECTION_ABORTED) != 0) {
+    eaccelerator_put_page(key, key_len , return_value, ttl TSRMLS_CC);
+    eaccelerator_compress(key, key_len, return_value, ttl TSRMLS_CC);
+  }
+  eaccelerator_destroy_headers(TSRMLS_C);
+}
+
+PHP_FUNCTION(eaccelerator_cache_page) {
+  char* key;
+  int   key_len;
+  long  ttl = 0;
+  zval  **server_vars, **encoding;
+
+  if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
+                          "s|l", &key, &key_len, &ttl) == FAILURE) {
+    RETURN_FALSE;
+  }
+  if (eaccelerator_content_cache_place == eaccelerator_none) {
+    RETURN_FALSE;
+  }
+  if (MMCG(content_headers) != NULL) {
+    RETURN_FALSE;
+  }
+  if (MMCG(compression_enabled) &&
+      MMCG(compress_content) &&
+      !SG(headers_sent) &&
+      zend_hash_find(&EG(symbol_table), "_SERVER", sizeof("_SERVER"), (void **) &server_vars) == SUCCESS &&
+      Z_TYPE_PP(server_vars) == IS_ARRAY &&
+      zend_hash_find(Z_ARRVAL_PP(server_vars), "HTTP_ACCEPT_ENCODING", sizeof("HTTP_ACCEPT_ENCODING"), (void **) &encoding)==SUCCESS &&
+      Z_TYPE_PP(encoding) == IS_STRING) {
+    char* zkey = NULL;
+    char* enc = NULL;
+    int   zkey_len = 0;
+    if (strstr(Z_STRVAL_PP(encoding),"x-gzip")) {
+      zkey_len = sizeof("gzip_") + key_len - 1;
+      zkey = emalloc(zkey_len+1);
+      memcpy(zkey,"gzip_",sizeof("gzip_")-1);
+      memcpy(zkey+sizeof("gzip_")-1,key,key_len+1);
+      enc = "Content-Encoding: x-gzip";
+    } else if (strstr(Z_STRVAL_PP(encoding),"gzip")) {
+      zkey_len = sizeof("gzip_") + key_len - 1;
+      zkey = emalloc(zkey_len+1);
+      memcpy(zkey,"gzip_",sizeof("gzip_")-1);
+      memcpy(zkey+sizeof("gzip_")-1,key,key_len+1);
+      enc = "Content-Encoding: gzip";
+    } else if (strstr(Z_STRVAL_PP(encoding),"deflate")) {
+      zkey_len = sizeof("deflate_") + key_len - 1;
+      zkey = emalloc(zkey_len+1);
+      memcpy(zkey,"deflate_",sizeof("deflate_")-1);
+      memcpy(zkey+sizeof("deflate_")-1,key,key_len+1);
+      enc = "Content-Encoding: deflate";
+    }
+    if (zkey != NULL &&
+        eaccelerator_get_page(zkey, zkey_len, return_value TSRMLS_CC) &&
+        return_value->type == IS_STRING) {
+      if (!eaccelerator_is_not_modified(return_value TSRMLS_CC) &&
+          sapi_add_header(enc, strlen(enc), 1) == SUCCESS &&
+          sapi_add_header("Vary: Accept-Encoding", sizeof("Vary: Accept-Encoding") - 1, 1) == SUCCESS) {
+        ZEND_WRITE(return_value->value.str.val, return_value->value.str.len);
+      }
+      efree(zkey);
+      zend_bailout();
+      RETURN_TRUE;
+    }
+    if (zkey != NULL) {
+      efree(zkey);
+    }
+  }
+  if (eaccelerator_get_page(key, key_len, return_value TSRMLS_CC) &&
+      return_value->type == IS_STRING) {
+    /*  Output is cached. Print it. */
+    if (!(PG(connection_status) & PHP_CONNECTION_ABORTED)) {
+      eaccelerator_compress(key, key_len, return_value, ttl TSRMLS_CC);
+    }
+    ZEND_WRITE(return_value->value.str.val, return_value->value.str.len);
+    zend_bailout();
+    RETURN_TRUE;
+  } else {
+    /* Output is not cached. Install Handler. */
+    char ch = '\000';
+#ifdef PHP_OUTPUT_HANDLER_USER
+#if defined(PHP_MAJOR_VERSION) && defined(PHP_MINOR_VERSION) && \
+    ((PHP_MAJOR_VERSION == 4 && PHP_MINOR_VERSION >= 3) || \
+     (PHP_MAJOR_VERSION > 4))
+    /* PHP 4.3.0 and above */
+    zval handler;
+    ZVAL_STRING(&handler, "_eaccelerator_output_handler", 0);
+    php_start_ob_buffer(&handler, 0, 0 TSRMLS_CC);
+    if (OG(active_ob_buffer).handler_name == NULL ||
+        strcmp(OG(active_ob_buffer).handler_name,"_eaccelerator_output_handler") != 0) {
+#else
+    /* PHP 4.2.* */
+    zval *handler;
+    ALLOC_INIT_ZVAL(handler);
+    ZVAL_STRING(handler, "_eaccelerator_output_handler", 1);
+    php_start_ob_buffer(handler, 0, 0 TSRMLS_CC);
+    if (OG(active_ob_buffer).handler_name == NULL ||
+        strcmp(OG(active_ob_buffer).handler_name,"_eaccelerator_output_handler") != 0) {
+#endif
+#else
+    /* PHP 4.1.2 and before */
+    zval *handler;
+    ALLOC_INIT_ZVAL(handler);
+    ZVAL_STRING(handler, "_eaccelerator_output_handler", 1);
+    if (php_start_ob_buffer(handler, 0 TSRMLS_CC) == FAILURE) {
+#endif
+      RETURN_FALSE;
+    }
+    zend_printf("%ld",ttl);
+    ZEND_PUTC(ch);
+    zend_printf("%d",key_len);
+    ZEND_PUTC(ch);
+    zend_printf("%s",key);
+    ZEND_PUTC(ch);
+    /* Init headers cache */
+    MMCG(content_headers) = emalloc(sizeof(zend_llist));
+    zend_llist_init(MMCG(content_headers), sizeof(sapi_header_struct), (void (*)(void *))eaccelerator_free_header, 0);
+    RETURN_TRUE;
+  }
+  RETURN_FALSE;
+}
+
+PHP_FUNCTION(eaccelerator_rm_page) {
+  char* key;
+  int   key_len;
+  char* zkey;
+  int   zkey_len;
+
+  if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
+                          "s", &key, &key_len) == FAILURE) {
+    return;
+  }
+  if (eaccelerator_content_cache_place == eaccelerator_none) {
+    RETURN_NULL();
+  }
+  zkey = do_alloca(key_len+16);
+  eaccelerator_rm(key, key_len, eaccelerator_content_cache_place TSRMLS_CC);
+  zkey_len = sizeof("gzip_") + key_len - 1;
+  memcpy(zkey,"gzip_",sizeof("gzip_")-1);
+  memcpy(zkey+sizeof("gzip_")-1,key,key_len+1);
+  eaccelerator_rm(zkey, zkey_len, eaccelerator_content_cache_place TSRMLS_CC);
+  zkey_len = sizeof("deflate_") + key_len - 1;
+  memcpy(zkey,"deflate_",sizeof("deflate_")-1);
+  memcpy(zkey+sizeof("deflate_")-1,key,key_len+1);
+  eaccelerator_rm(zkey, zkey_len, eaccelerator_content_cache_place TSRMLS_CC);
+  RETURN_NULL();
+}
+
+PHP_FUNCTION(eaccelerator_cache_output) {
+  char* key;
+  int   key_len;
+  char* code;
+  int   code_len;
+  long  ttl = 0;
+  char* eval_name;
+  int ret = 0;
+
+  if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
+                          "ss|l", &key, &key_len, &code, &code_len, &ttl) == FAILURE) {
+    return;
+  }
+  if (eaccelerator_content_cache_place == eaccelerator_none) {
+    eval_name = zend_make_compiled_string_description("eval()'d code" TSRMLS_CC);
+    zend_eval_string(code, NULL, eval_name TSRMLS_CC);
+    efree(eval_name);
+    RETURN_FALSE;
+  } else if (eaccelerator_get(key, key_len, return_value, eaccelerator_content_cache_place TSRMLS_CC) &&
+      return_value->type == IS_STRING) {
+    /*  Output is cached. Print it. */
+    ZEND_WRITE(return_value->value.str.val, return_value->value.str.len);
+    zval_dtor(return_value);
+    RETURN_TRUE;
+  } else {
+    /* Output is not cached. Generate it and print. */
+    eval_name = zend_make_compiled_string_description("eval()'d code" TSRMLS_CC);
+#ifdef PHP_OUTPUT_HANDLER_USER
+    /* PHP 4.2.0 and above */
+    if (php_start_ob_buffer(NULL, 0, 0 TSRMLS_CC) == FAILURE) {
+#else
+    /* PHP 4.1.2 and before */
+    if (php_start_ob_buffer(NULL, 0 TSRMLS_CC) == FAILURE) {
+#endif
+      zend_eval_string(code, NULL, eval_name TSRMLS_CC);
+      efree(eval_name);
+      RETURN_FALSE;
+    }
+    if (zend_eval_string(code, NULL, eval_name TSRMLS_CC) == SUCCESS) {
+      if (php_ob_get_buffer(return_value TSRMLS_CC) == SUCCESS) {
+        ret = eaccelerator_put(key, key_len, return_value, ttl, eaccelerator_content_cache_place TSRMLS_CC);
+        zval_dtor(return_value);
+      }
+    }
+    efree(eval_name);
+    php_end_ob_buffer(1, 0 TSRMLS_CC);
+    if (ret) {
+      RETURN_TRUE;
+    }
+  }
+  RETURN_FALSE;
+}
+
+PHP_FUNCTION(eaccelerator_cache_result) {
+  char* key;
+  int   key_len;
+  char* code;
+  int   code_len;
+  long  ttl = 0;
+  char* eval_name;
+
+  if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
+                          "ss|l", &key, &key_len, &code, &code_len, &ttl) == FAILURE) {
+    return;
+  }
+  if ((eaccelerator_content_cache_place != eaccelerator_none) &&
+      eaccelerator_get(key, key_len, return_value, eaccelerator_content_cache_place TSRMLS_CC)) {
+    /*  Return value is cached. Return it. */
+    return;
+  } else {
+    /* Return value is not cached. Generate it and return. */
+    eval_name = zend_make_compiled_string_description("eval()'d code" TSRMLS_CC);
+    if (zend_eval_string(code, return_value, eval_name TSRMLS_CC) == SUCCESS &&
+        eaccelerator_content_cache_place != eaccelerator_none) {
+
+      /* clean garbage */
+      while (EG(garbage_ptr)) {
+        zval_ptr_dtor(&EG(garbage)[--EG(garbage_ptr)]);
+      }
+
+      eaccelerator_put(key, key_len, return_value, ttl, eaccelerator_content_cache_place TSRMLS_CC);
+    }
+    efree(eval_name);
+    return;
+  }
+}
+
+#endif
+#endif
Index: /eaccelerator/trunk/README
===================================================================
--- /eaccelerator/trunk/README	(revision 4)
+++ /eaccelerator/trunk/README	(revision 4)
@@ -0,0 +1,315 @@
+eAccelerator for PHP
+=====================
+
+What is eAccelerator?
+----------------------
+eAccelerator is a free open source PHP accelerator, optimizer, encoder and
+dynamic content cache for PHP. It increases performance of PHP scripts
+by caching them in compiled state, so that the overhead of compiling is almost
+completely eliminated. Also it uses some optimizations to speed up execution
+of PHP scripts. eAccelerator typically reduces server load and increases
+the speed of your PHP code by 1-10 times.
+
+eAccelerator stores compiled PHP scripts in shared memory and executes code
+directly from it. It creates locks only for short time, while searching
+compiled PHP script in the cache, so one script can be executed simultaneously
+by several engines. MM shared memory library (http://www.engelschall.com/sw/mm/)
+was used by eAccelerator before version 2.3.13 for management of the shared
+memory and locking. Files that can't fit in shared memory are cached on disk only.
+
+eAccelerator was first launched in 2001 to speed up the www.guestbooks4all.com
+service. It has been tested with PHP 4.1.0 - 4.3.3 under GNU/Linux and Windows
+with Apache 1.3 and 2.0.
+Patches for ports to other OSs and PHP versions are welcome.
+
+Since version 2.3.10, eAccelerator contains a PHP encoder and loader.
+You can encode PHP scripts using encoder.php in order to distribute them without
+sources. Encoded files can be run on any site which runs PHP with eAccelerator
+2.3.10 or above. The sources of encoded scripts can't be restored because
+they are stored in a compiled form and the encoded version doesn't contain
+the source. Of course, some internals of the scripts can be restored with
+different reverse engineering tools (disassemblers, debuggers, etc), but it is
+not trivial.
+
+Since version 2.3.15, eAccelerator is compatible with Zend Optimizer's
+loader. Zend Optimizer must be installed after eAccelerator in php.ini.
+If you don't use scripts encoded with Zend Encoder then we do not recommend
+you install Zend Optimizer with eAccelerator.
+
+eAccelerator does not work in CGI mode.
+
+Here are some other products that provide the same functionality:
+
+ - Zend Performance Suite (http://www.zend.com/)
+ - PHP Accelerator (http://www.php-accelerator.co.uk/)
+ - Alternative PHP Cache (http://apc.communityconnect.com/)
+ - AfterBurner Cache (http://www.bwcache.bware.it/)
+
+
+Where is eAccelerator already used?
+-----------------------------------
+The following you will find a list of sites that use eAccelerator
+If you want to be added, please send e-mail to frankalcantara@users.sourceforge.net
+
+ - HomePage Title (http://www.xxx.com)
+   homepage description
+
+
+Download
+--------
+Latest eAccelerator versions can be downloaded at the sourceforge page:
+http://sourceforge.net/projects/eaccelerator/
+
+
+Requirements
+------------
+apache 1.3, mod_php 4.1, autoconf, automake, libtool, m4
+
+
+Compatibility
+-------------
+This version of the eAccelerator has been successfully tested on PHP
+4.1.0-4.3.3 under RedHat Linux 7.0, 7.3, 8.0 and Windows
+with Apache 1.3 and 2.0.
+
+
+Quick install
+-------------
+Step 1. Compiling eAccelerator
+
+  export PHP_PREFIX="/usr"
+  $PHP_PREFIX/bin/phpize
+  ./configure --enable-eaccelerator=shared --with-php-config=$PHP_PREFIX/bin/php-config
+  make
+
+  You must specify the real prefix where PHP is installed in the "export"
+  command. It may be "/usr" "/usr/local", or something else.
+
+Step 2. Installing eAccelerator
+
+  make install
+
+Step 3. Configuring eAccelerator
+
+eAccelerator can be installed both as Zend or PHP extension, so you need
+to edit your php.ini file (usually /etc/php.ini).
+
+To install as Zend extension:
+
+  zend_extension="/usr/lib/php4/eaccelerator.so"
+  eaccelerator.shm_size="16"
+  eaccelerator.cache_dir="/tmp/eaccelerator"
+  eaccelerator.enable="1"
+  eaccelerator.optimizer="1"
+  eaccelerator.check_mtime="1"
+  eaccelerator.debug="0"
+  eaccelerator.filter=""
+  eaccelerator.shm_max="0"
+  eaccelerator.shm_ttl="0"
+  eaccelerator.shm_prune_period="0"
+  eaccelerator.shm_only="0"
+  eaccelerator.compress="1"
+  eaccelerator.compress_level="9"
+
+  If you use thread safe build of PHP you must use "zend_extension_ts" instead
+  of "zend_extension".
+
+To install as PHP extension:
+
+  extension="eaccelerator.so"
+  eaccelerator.shm_size="16"
+  eaccelerator.cache_dir="/tmp/eaccelerator"
+  eaccelerator.enable="1"
+  eaccelerator.optimizer="1"
+  eaccelerator.check_mtime="1"
+  eaccelerator.debug="0"
+  eaccelerator.filter=""
+  eaccelerator.shm_max="0"
+  eaccelerator.shm_ttl="0"
+  eaccelerator.shm_prune_period="0"
+  eaccelerator.shm_only="0"
+  eaccelerator.compress="1"
+  eaccelerator.compress_level="9"  
+
+Step 4. Creating cache directory
+
+  mkdir /tmp/eaccelerator
+  chmod 0777 /tmp/eaccelerator
+
+
+Configuration Options
+---------------------
+
+eaccelerator.shm_size
+    The amount of shared memory (in megabytes) that eAccelerator will use.
+    "0" means OS default. Default value is "0".
+
+eaccelerator.cache_dir
+    The directory that is used for disk cache. eAccelerator stores precompiled
+    code, session data, content and user entries  here. The same data can be
+    stored in shared memory also (for more quick access). Default value is
+    "/tmp/eaccelerator".
+
+eaccelerator.enable
+    Enables or disables eAccelerator. Should be "1" for enabling or
+    "0" for disabling. Default value is "1".
+
+eaccelerator.optimizer
+    Enables or disables internal peephole optimizer which may speed up code
+    execution. Should be "1" for enabling or "0" for disabling.
+    Default value is "1".
+
+eaccelerator.debug
+    Enables or disables debug logging. Should be "1" for enabling or
+    "0" for disabling. Default value is "0".
+
+eaccelerator.check_mtime
+    Enables or disables PHP file modification checking. Should be "1"
+    for enabling or "0" for disabling. You should set it to "1" if you want
+    to recompile PHP files after modification. Default value is "1".
+
+eaccelerator.filter
+    Determine which PHP files must be cached. You may specify the number of
+    patterns (for example "*.php *.phtml") which specifies to cache or
+    not to cache. If pattern starts with the character "!", it means to ignore
+    files which are matched by the following pattern. Default value is "" that
+    means - all PHP scripts will be cached.
+
+eaccelerator.shm_max
+    Disables putting large values into shared memory by "eaccelerator_put()"
+    function.
+    It indicates the largest allowed size in bytes (10240, 10K, 1M). The "0"
+    disables the limit. Default value is "0".
+
+eaccelerator.shm_ttl
+    When eaccelerator fails to get shared memory for new script it removes all
+    scripts which were not accessed at last "shm_ttl" seconds from shared
+    memory. Default value is "0" that means - don't remove any files from
+    shared memory.
+
+eaccelerator.shm_prune_period
+    When eaccelerator fails to get shared memory for new script it tryes to 
+    remove old script if the previous try was made more then "shm_prune_period"
+    seconds ago. Default value is "0" that means - don't try to remove any
+    files from shared memory.
+
+eaccelerator.shm_only
+    Enables or disables caching of compiled scripts on disk. It has no effect
+    on session data and content caching. Default value is "0" that means -
+    use disk and shared memory for caching.
+
+eaccelerator.compress
+    Enables or disables cached content compression. Default value is "1" that
+    means enable compression.
+
+eaccelerator.compress_level
+    Compression level used for content caching.  Default value is "9" which
+    is the maximum value
+    
+eaccelerator.keys
+eaccelerator.sessions
+eaccelerator.content
+    Determine where keys, session data and content will be cached. The possible
+    values are:
+    "shm_and_disk" - cache data in shared memory and on disk (default value)
+    "shm"          - cache data in shared memory or on disk if shared memory
+                     is full or data size greater then "eaccelerator.shm_max"
+    "shm_only"     - cache data in shared memory
+    "disk_only"    - cache data on disk
+    "none"         - don't cache data
+
+
+eAccelerator API
+----------------
+
+eaccelerator_put($key, $value, $ttl=0)
+  puts the $value into shard memory for $ttl seconds.
+
+eaccelerator_get($key)
+  returns the value from shared memory which was stored by eaccelerator_put() or
+  null if it is not exists or was expired.
+
+eaccelerator_rm($key)
+  removres the $key from shared memory
+
+eaccelerator_gc()
+  removes all expired keys from shared memory
+
+eaccelerator_lock($lock)
+  creates a lock with specified name. The lock can be released by function
+  eaccelerator_unlock() or automatic on the end of request.
+  For Example:
+  <?php
+    eaccelerator_lock("count");
+    eaccelerator_put("count",eaccelerator_get("count")+1));
+  ?>
+
+eaccelerator_unlock($lock)
+  release lock with specified name
+
+eaccelerator_set_session_handlers()
+  install the eaccelerator session handlers.
+  Since PHP 4.2.0 you can install eaccelerator session handlers
+  in "php.ini" by "session.save_handler=eaccelerator".
+
+eaccelerator_cache_output($key, $eval_code, $ttl=0)
+  caches the output of $eval_code in shared memory for $ttl seconds.
+  Output can be removed from cache by calling mmcach_rm() with the same $key.
+  For Example:
+  <?php eaccelerator_cache_output('test', 'echo time(); phpinfo();', 30); ?>
+
+eaccelerator_cache_result($key, $eval_code, $ttl=0)
+  caches the result of $eval_code in shared memory for $ttl seconds.
+  Result can be removed from cache by calling mmcach_rm() with the same $key.
+  For Example:
+  <?php eaccelerator_cache_output('test', 'time()." Hello";', 30); ?>
+
+eaccelerator_cache_page($key, $ttl=0)
+  caches the full page for $ttl seconds.
+  For Example:
+  <?php
+    eaccelerator_cache_page($_SERVER['PHP_SELF'].'?GET='.serialize($_GET), 30);
+    echo time();
+    phpinfo();
+  ?>
+
+eaccelerator_rm_page($key)
+  removes the page which was cached by eaccelerator_cache_page() with the same 
+  $key from cache
+
+eaccelerator_encode($filename)
+  returns the encoded bytecode of compiled file $filename
+
+eaccelerator_load($code)
+  loads script which was encoded by eaccelerator_encode()
+
+WEB interface
+-------------
+eAccelerator can be managed through web interface script eaccelerator.php.
+So you need to put this file on your web site. For security reasons it is
+recommended to restrict the usage of this script by your local IP.
+
+Since version 2.3.18 admin interface may be protected by password.
+To generate password run the eaccelerator_password.php from command line and
+follow the instruction.
+
+  $ php -q eaccelerator_password.php
+  Changing password for eAccelerator Web Interface (eaccelerator.php)
+
+  Enter admin name: admin
+  New admin password: eaccelerator
+  Retype new admin password: eaccelerator
+
+  Add the following lines into your php.ini and restart HTTPD
+
+  eaccelerator.admin.name="admin"
+  eaccelerator.admin.password="$1$0ScD9gkb$nOEmFerNMvQ576hELeLrG0"
+
+If you use eaccelerator.php in directory that is password-protected by HTTPD 
+then eaccelerator's admin name and password must be the same.
+
+
+Contact us
+----------
+To contact us with questions, patches or bugs, please send e-mail to
+Frank Alcantara <frankalcantara@users.sourceforge.net>
Index: /eaccelerator/trunk/mm.h
===================================================================
--- /eaccelerator/trunk/mm.h	(revision 4)
+++ /eaccelerator/trunk/mm.h	(revision 4)
@@ -0,0 +1,71 @@
+/* libmm replacement */
+
+#ifndef INCLUDED_MM_H
+#define INCLUDED_MM_H
+
+#include <sys/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef MM_PRIVATE
+#  ifdef MM
+#    undef MM
+#  endif
+#  define MM void
+#endif
+
+#define MM_LOCK_RW 1
+#define MM_LOCK_RD 0
+
+#if (_MSC_VER < 1300)
+MM*    _mm_create(size_t size, const char* key);
+void   _mm_set_attach(MM* mm, void* attach_addr);
+void*  _mm_attach(size_t size, const char* key);
+size_t _mm_size(MM* mm);
+void   _mm_destroy(MM* mm);
+int    _mm_lock(MM* mm, int kind);
+int    _mm_unlock(MM* mm);
+size_t _mm_available(MM* mm);
+size_t _mm_maxsize(MM* mm);
+void*  _mm_malloc(MM* mm, size_t size);
+void   _mm_free(MM* mm, void* p);
+void*  _mm_malloc_nolock(MM* mm, size_t size);
+void   _mm_free_nolock(MM* mm, void* p);
+size_t _mm_sizeof(MM* mm, void* x);
+#endif
+
+
+const char* mm_shm_type();
+const char* mm_sem_type();
+
+#define MM_PROT_NONE  1
+#define MM_PROT_READ  2
+#define MM_PROT_WRITE 4
+#define MM_PROT_EXEC  8
+
+int mm_protect(MM* mm, int mode);
+
+#if (_MSC_VER < 1300)
+#define mm_create(A, B)        _mm_create(A, B)
+#define mm_set_attach(A, B)    _mm_set_attach(A, B)
+#define mm_attach(A, B)        _mm_attach(A, B)
+#define mm_size(A)             _mm_size(A)
+#define mm_destroy(A)          _mm_destroy(A)
+#define mm_lock(A, B)          _mm_lock(A, B)
+#define mm_unlock(A)           _mm_unlock(A)
+#define mm_available(A)        _mm_available(A)
+#define mm_maxsize(A)          _mm_maxsize(A)
+#define mm_malloc(A, B)        _mm_malloc(A, B)
+#define mm_free(A, B)          _mm_free(A, B)
+#define mm_malloc_nolock(A, B) _mm_malloc_nolock(A, B)
+#define mm_free_nolock(A, B)   _mm_free_nolock(A, B)
+#define mm_sizeof(A, B)        _mm_sizeof(A, B)
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
Index: /eaccelerator/trunk/encoder.c
===================================================================
--- /eaccelerator/trunk/encoder.c	(revision 4)
+++ /eaccelerator/trunk/encoder.c	(revision 4)
@@ -0,0 +1,1343 @@
+/*
+   +----------------------------------------------------------------------+
+   | Turck MMCache for PHP Version 4                                      |
+   +----------------------------------------------------------------------+
+   | Copyright (c) 2002-2003 TurckSoft, St. Petersburg                    |
+   | http://www.turcksoft.com                                             |
+   +----------------------------------------------------------------------+
+   | This program is free software; you can redistribute it and/or        |
+   | modify it under the terms of the GNU General Public License          |
+   | as published by the Free Software Foundation; either version 2       |
+   | of the License, or (at your option) any later version.               |
+   |                                                                      |
+   | This program is distributed in the hope that it will be useful,      |
+   | but WITHOUT ANY WARRANTY; without even the implied warranty of       |
+   | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        |
+   | GNU General Public License for more details.                         |
+   |                                                                      |
+   | You should have received a copy of the GNU General Public License    |
+   | along with this program; if not, write to the Free Software          |
+   | Foundation, Inc., 59 Temple Place - Suite 330, Boston,               |
+   | MA  02111-1307, USA.                                                 |
+   |                                                                      |
+   | A copy is availble at http://www.gnu.org/copyleft/gpl.txt            |
+   +----------------------------------------------------------------------+
+   | Author: Dmitry Stogov <mmcache@turckware.ru>                         |
+   +----------------------------------------------------------------------+
+   $Id$
+*/
+
+#include "eaccelerator.h"
+#include "eaccelerator_version.h"
+
+#ifdef HAVE_EACCELERATOR
+#ifdef WITH_EACCELERATOR_ENCODER
+
+#include "opcodes.h"
+
+#include "zend.h"
+#include "zend_API.h"
+#include "php.h"
+
+#include <math.h>
+
+#define MMC_ENCODER_VERSION   0x00000002
+
+#define MMC_ENCODER_END       0x00
+#define MMC_ENCODER_NAMESPACE 0x01
+#define MMC_ENCODER_CLASS     0x02
+#define MMC_ENCODER_FUNCTION  0x03
+
+#ifndef WITHOUT_FILE_FILTER
+#define IEQ(need)  (ch == (need) || \
+                    ((need) >= 'a' && (need) <= 'z' && ch == ((need)-'a'+'A')))
+
+#define SKIP_WHITESPACES() do {\
+                             ch = fgetc(yyin);\
+                             while (ch == ' ' || ch == '\t' ||\
+                                    ch == '\r' || ch == '\n') {\
+                               fputc(ch,yyout);\
+                               ch = fgetc(yyin);\
+                             }\
+                           } while(0)
+
+static void filter_script(FILE *yyin, FILE *yyout TSRMLS_DC) {
+  register int ch = EOF;
+  int repeat = 0;
+  int allow = 1;
+
+  int label_len, pos;
+  char label[256];
+
+  while (1) {
+    if (!repeat) {
+      ch = fgetc(yyin);
+    } else {
+      repeat = 0;
+    }
+    if (ch == EOF) break;
+    fputc(ch,yyout);
+    if (ch == '\'' || ch == '"' || ch == '`') {
+      /* skip strings */
+      register int start = ch;
+      do {
+        ch = fgetc(yyin);
+        if (ch == EOF) break;
+        fputc(ch,yyout);
+        if (ch == '\\') {
+          ch = fgetc(yyin);
+          if (ch == EOF) break;
+          fputc(ch,yyout);
+          ch = fgetc(yyin);
+          if (ch == EOF) break;
+          fputc(ch,yyout);
+        }
+      } while (ch != start);
+      allow = 1;
+    } else if (ch == '#') {
+      /* skip one line comments */
+one_line_comment:
+      do {
+        ch = fgetc(yyin);
+        if (ch == EOF) break;
+        fputc(ch,yyout);
+      } while (ch != '\r' && ch != '\n');
+      allow = 1;
+    } else if (ch == '/') {
+      ch = fgetc(yyin);
+      if (ch == EOF) break;
+      if (ch == '/') {
+        fputc(ch,yyout);
+        /* skip one line comments */
+        goto one_line_comment;
+      } else if (ch == '*') {
+        fputc(ch,yyout);
+        /* skip multiline comments */
+        while (1) {
+          do {
+            ch = fgetc(yyin);
+            if (ch == EOF) break;
+            fputc(ch,yyout);
+          } while (ch != '*');
+          if (ch == EOF) break;
+          while (ch == '*') {
+            ch = fgetc(yyin);
+            if (ch == EOF) break;
+            fputc(ch,yyout);
+          }
+          if (ch == EOF || ch == '/') break;
+        }
+      } else {
+        repeat = 1;
+      }
+      allow = 1;
+    } else if (ch == '?' || (ch == '%' && CG(asp_tags))) {
+      /* end of script */
+      ch = fgetc(yyin);
+      if (ch == EOF) break;
+      if (ch == '>') {
+        fputc(ch,yyout);
+        return;
+      } else {
+        repeat = 1;
+      }
+      allow = 1;
+    } else if (ch == '<') {
+      repeat = 1;
+      /* </script> */
+      ch = fgetc(yyin);
+      if (ch == EOF) break;
+      if (ch == '/') {
+        fputc(ch,yyout);
+        ch = fgetc(yyin);
+        if (ch == EOF) break;
+        if (IEQ('s')) {
+          fputc(ch,yyout);
+          ch = fgetc(yyin);
+          if (ch == EOF) break;
+          if (IEQ('c')) {
+            fputc(ch,yyout);
+            ch = fgetc(yyin);
+            if (ch == EOF) break;
+            if (IEQ('r')) {
+              fputc(ch,yyout);
+              ch = fgetc(yyin);
+              if (ch == EOF) break;
+              if (IEQ('i')) {
+                fputc(ch,yyout);
+                ch = fgetc(yyin);
+                if (ch == EOF) break;
+                if (IEQ('p')) {
+                  fputc(ch,yyout);
+                  ch = fgetc(yyin);
+                  if (ch == EOF) break;
+                  if (IEQ('t')) {
+                    fputc(ch,yyout);
+                    SKIP_WHITESPACES();
+                    if (ch == '>') {
+                      fputc(ch,yyout);
+                      return;
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+      } else if (ch == '<') {
+        repeat = 1;
+        fputc(ch,yyout);
+        ch = fgetc(yyin);
+        if (ch == EOF) break;
+        if (ch == '<') {
+          /* heredoc */
+          fputc(ch,yyout);
+          do {
+            ch = fgetc(yyin);
+            if (ch == EOF) break;
+            fputc(ch,yyout);
+          } while (ch == '\t' || ch == ' ');
+          if ((ch >= 'a' && ch <= 'z') ||
+              (ch >= 'A' && ch <= 'Z') ||
+              ch == '_' ||
+              (ch >= '\x7f' && ch <= '\xff')) {
+            label[0] = ch;
+            label_len = 1;
+            while(1) {
+              ch = fgetc(yyin);
+              if (ch == EOF) break;
+              fputc(ch,yyout);
+              if ((ch >= 'a' && ch <= 'z') ||
+                  (ch >= 'A' && ch <= 'Z') ||
+                  (ch >= '0' && ch <= '9') ||
+                  ch == '_' ||
+                  (ch >= '\x7f' && ch <= '\xff')) {
+                label[label_len] = ch;
+                label_len++;
+                if (label_len >= sizeof(label)-1) break;
+              } else {
+                break;
+              }
+            }
+            if (ch == '\r' || ch =='\n') {
+              label[label_len] = '\000';
+              while (1) {
+                if (ch == '\r' || ch == '\n') {
+                  ch = fgetc(yyin);
+                  if (ch == EOF) break;
+                  fputc(ch,yyout);
+                  pos = 0;
+                  while (1) {
+                    if (pos == label_len && ch == ';') {
+                      ch = fgetc(yyin);
+                      if (ch == EOF) break;
+                      fputc(ch,yyout);
+                    }
+                    if (pos == label_len && (ch == '\r' || ch == '\n')) {
+                      break;
+                    }
+                    if (pos > label_len || label[pos] != ch) {
+                      break;
+                    }
+                    pos++;
+                    ch = fgetc(yyin);
+                    if (ch == EOF) break;
+                    fputc(ch,yyout);
+                  }
+                  if (pos == label_len && (ch == '\r' || ch == '\n')) {
+                    break;
+                  }
+                } else {
+                  ch = fgetc(yyin);
+                  if (ch == EOF) break;
+                  fputc(ch,yyout);
+                }
+              }
+            }
+          }
+          repeat = 0;
+        }
+      }
+      allow = 1;
+    } else if (allow && ch == '_') {
+      label[0] = ch = fgetc(yyin);
+      if (ch == EOF) {break;}
+      if (ch == '_') {
+        label[1] = ch = fgetc(yyin);
+        if (ch == EOF) {fwrite(label,1,1,yyout); break;}
+        if (IEQ('f')) {
+          label[2] = ch = fgetc(yyin);
+          if (ch == EOF) {fwrite(label,2,1,yyout); break;}
+          if (IEQ('i')) {
+            label[3] = ch = fgetc(yyin);
+            if (ch == EOF) {fwrite(label,3,1,yyout); break;}
+            if (IEQ('l')) {
+              label[4] = ch = fgetc(yyin);
+              if (ch == EOF) {fwrite(label,4,1,yyout); break;}
+              if (IEQ('e')) {
+                label[5] = ch = fgetc(yyin);
+                if (ch == EOF) {fwrite(label,5,1,yyout); break;}
+                if (ch == '_') {
+                  label[6] = ch = fgetc(yyin);
+                  if (ch == EOF) {fwrite(label,6,1,yyout); break;}
+                  if (ch == '_') {
+                    ch = fgetc(yyin);
+                    repeat = 1;
+                    if ((ch >= 'a' && ch <= 'z') ||
+                        (ch >= 'A' && ch <= 'Z') ||
+                        (ch >= '0' && ch <= '9') ||
+                        (ch >= '\x7f' && ch <= '\xff') ||
+                        ch == '_') {
+                      fwrite(label,7,1,yyout);
+                    } else {
+                      fputs("eaccelerator_loader_file()",yyout);
+                    }
+                  } else {
+                    fwrite(label,7,1,yyout);
+                  }
+                } else {
+                  fwrite(label,6,1,yyout);
+                }
+              } else {
+                fwrite(label,5,1,yyout);
+              }
+            } else {
+              fwrite(label,4,1,yyout);
+            }
+          } else {
+            fwrite(label,3,1,yyout);
+          }
+        } else if (IEQ('l')) {
+          label[2] = ch = fgetc(yyin);
+          if (ch == EOF) {fwrite(label,2,1,yyout); break;}
+          if (IEQ('i')) {
+            label[3] = ch = fgetc(yyin);
+            if (ch == EOF) {fwrite(label,3,1,yyout); break;}
+            if (IEQ('n')) {
+              label[4] = ch = fgetc(yyin);
+              if (ch == EOF) {fwrite(label,4,1,yyout); break;}
+              if (IEQ('e')) {
+                label[5] = ch = fgetc(yyin);
+                if (ch == EOF) {fwrite(label,5,1,yyout); break;}
+                if (ch == '_') {
+                  label[6] = ch = fgetc(yyin);
+                  if (ch == EOF) {fwrite(label,6,1,yyout); break;}
+                  if (ch == '_') {
+                    ch = fgetc(yyin);
+                    repeat = 1;
+                    if ((ch >= 'a' && ch <= 'z') ||
+                        (ch >= 'A' && ch <= 'Z') ||
+                        (ch >= '0' && ch <= '9') ||
+                        (ch >= '\x7f' && ch <= '\xff') ||
+                        ch == '_') {
+                      fwrite(label,7,1,yyout);
+                    } else {
+                      fputs("eaccelerator_loader_line()",yyout);
+                    }
+                  } else {
+                    fwrite(label,7,1,yyout);
+                  }
+                } else {
+                  fwrite(label,6,1,yyout);
+                }
+              } else {
+                fwrite(label,5,1,yyout);
+              }
+            } else {
+              fwrite(label,4,1,yyout);
+            }
+          } else {
+            fwrite(label,3,1,yyout);
+          }
+        } else {
+          fwrite(label,2,1,yyout);
+        }
+      } else {
+        fwrite(label,1,1,yyout);
+      }
+      allow = 0;
+    } else if ((ch >= 'a' && ch <= 'z') ||
+               (ch >= 'A' && ch <= 'Z') ||
+               (ch >= '\x7f' && ch <= '\xff') ||
+               ch == '_' || ch == '$') {
+      allow = 0;
+    } else if (ch == '-') {
+      ch = fgetc(yyin);
+      if (ch == EOF) break;
+      if (ch == '>') {
+        fputc(ch,yyout);
+        allow = 0;
+      } else {
+        repeat = 1;
+        allow = 1;
+      }
+    } else {
+      allow = 1;
+    }
+  }
+}
+
+static void filter_file(FILE *yyin, FILE *yyout TSRMLS_DC) {
+  register int ch = EOF;
+  int repeat = 0;
+
+  while (1) {
+    if (!repeat) {
+      ch = fgetc(yyin);
+    } else {
+      repeat = 0;
+    }
+    if (ch == EOF) break;
+    fputc(ch,yyout);
+    if (ch == '<') {
+      ch = fgetc(yyin);
+      if (ch == EOF) break;
+      if (ch == '?') {
+        fputc(ch,yyout);
+        if (CG(short_tags)) {
+          filter_script(yyin, yyout TSRMLS_CC);
+        } else {
+          repeat = 1;
+          ch = fgetc(yyin);
+          if (ch == EOF) break;
+          if (IEQ('p')) {
+            fputc(ch,yyout);
+            ch = fgetc(yyin);
+            if (ch == EOF) break;
+            if (IEQ('h')) {
+              fputc(ch,yyout);
+              ch = fgetc(yyin);
+              if (ch == EOF) break;
+              if (IEQ('p')) {
+                fputc(ch,yyout);
+                ch = fgetc(yyin);
+                if (ch == EOF) break;
+                if (ch == '\r' || ch == '\n' || ch == ' ' || ch == '\t') {
+                  fputc(ch,yyout);
+                  filter_script(yyin, yyout TSRMLS_CC);
+                  repeat = 0;
+                }
+              }
+            }
+          }
+        }
+      } else if (ch == '%' && CG(asp_tags)) {
+        fputc(ch,yyout);
+        filter_script(yyin, yyout TSRMLS_CC);
+      } else if (IEQ('s')) {
+        repeat = 1;
+        fputc(ch,yyout);
+        ch = fgetc(yyin);
+        if (ch == EOF) break;
+        if (IEQ('c')) {
+          fputc(ch,yyout);
+          ch = fgetc(yyin);
+          if (ch == EOF) break;
+          if (IEQ('r')) {
+            fputc(ch,yyout);
+            ch = fgetc(yyin);
+            if (ch == EOF) break;
+            if (IEQ('i')) {
+              fputc(ch,yyout);
+              ch = fgetc(yyin);
+              if (ch == EOF) break;
+              if (IEQ('p')) {
+                fputc(ch,yyout);
+                ch = fgetc(yyin);
+                if (ch == EOF) break;
+                if (IEQ('t')) {
+                  fputc(ch,yyout);
+                  SKIP_WHITESPACES();
+                  if (ch == EOF) break;
+                  if (IEQ('l')) {
+                    fputc(ch,yyout);
+                    ch = fgetc(yyin);
+                    if (ch == EOF) break;
+                    if (IEQ('a')) {
+                      fputc(ch,yyout);
+                      ch = fgetc(yyin);
+                      if (ch == EOF) break;
+                      if (IEQ('n')) {
+                        fputc(ch,yyout);
+                        ch = fgetc(yyin);
+                        if (ch == EOF) break;
+                        if (IEQ('g')) {
+                          fputc(ch,yyout);
+                          ch = fgetc(yyin);
+                          if (ch == EOF) break;
+                          if (IEQ('u')) {
+                            fputc(ch,yyout);
+                            ch = fgetc(yyin);
+                            if (ch == EOF) break;
+                            if (IEQ('a')) {
+                              fputc(ch,yyout);
+                              ch = fgetc(yyin);
+                              if (ch == EOF) break;
+                              if (IEQ('g')) {
+                                fputc(ch,yyout);
+                                ch = fgetc(yyin);
+                                if (ch == EOF) break;
+                                if (IEQ('e')) {
+                                  register int start = '\000';
+                                  fputc(ch,yyout);
+                                  SKIP_WHITESPACES();
+                                  if (ch == EOF) break;
+                                  if (ch == '=') {
+                                    fputc(ch,yyout);
+                                    SKIP_WHITESPACES();
+                                    if (ch == EOF) break;
+                                    if (ch == '\'' || ch == '"') {
+                                      fputc(ch,yyout);
+                                      start = ch;
+                                      ch = fgetc(yyin);
+                                      if (ch == EOF) break;
+                                    }
+                                    if (IEQ('p')) {
+                                      fputc(ch,yyout);
+                                      ch = fgetc(yyin);
+                                      if (ch == EOF) break;
+                                      if (IEQ('h')) {
+                                        fputc(ch,yyout);
+                                        ch = fgetc(yyin);
+                                        if (ch == EOF) break;
+                                        if (IEQ('p')) {
+                                          fputc(ch,yyout);
+                                          if (start != '\000') {
+                                            ch = fgetc(yyin);
+                                            if (ch == EOF) break;
+                                            if (ch == start) {
+                                              fputc(ch,yyout);
+                                              start = '\000';
+                                            }
+                                          }
+                                          if (start == '\000') {
+                                            SKIP_WHITESPACES();
+                                            if (ch == '>') {
+                                              fputc(ch,yyout);
+                                              filter_script(yyin, yyout TSRMLS_CC);
+                                              repeat = 0;
+                                            }
+                                          }
+                                        }
+                                      }
+                                    }
+                                  }
+                                }
+                              }
+                            }
+                          }
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+      } else {
+        repeat = 1;
+      }
+    }
+  }
+}
+#endif
+
+static inline void encode(unsigned char c) {
+  zend_write((char*)&c, 1);
+}
+
+static inline void encode32(unsigned int i) {
+  encode((unsigned char)(i & 0xff));
+  encode((unsigned char)((i >> 8) & 0xff));
+  encode((unsigned char)((i >> 16) & 0xff));
+  encode((unsigned char)((i >> 24) & 0xff));
+}
+
+static inline void encode16(unsigned short i) {
+  encode((unsigned char)(i & 0xff));
+  encode((unsigned char)((i >> 8) & 0xff));
+}
+
+static void encode_var(unsigned int var, unsigned int count) {
+  unsigned int v = VAR_NUM(var);
+  if (v >= count) {
+    zend_bailout();
+  }
+  if (count < 0xff) {
+    encode((unsigned char)v);
+  } else if (count < 0xffff) {
+    encode16((unsigned short)v);
+  } else {
+    encode32(v);
+  }
+}
+
+static void encode_opline(unsigned int opline, unsigned int last) {
+  if (opline >= last && opline != (unsigned int)-1) {
+    zend_bailout();
+  }
+  if (last < 0xff-1) {
+    encode((unsigned char)opline);
+  } else if (last < 0xffff-1) {
+    encode16((unsigned short)opline);
+  } else {
+    encode32(opline);
+  }
+}
+
+static void encode_zstr(const char* str) {
+  if (str != NULL) {
+    int len = strlen(str);
+    ZEND_WRITE(str,len+1);
+  } else {
+    encode(0);
+  }
+}
+
+static void encode_lstr(const char* str, unsigned int len) {
+  if (str != NULL && len > 0) {
+    encode32(len);
+    ZEND_WRITE(str,len);
+  } else {
+    encode32(0);
+  }
+}
+
+static inline void encode_pstr(const unsigned char* str) {
+  if (str != NULL) {
+    unsigned int len = str[0];
+    ZEND_WRITE((const char*)str,len+1);
+  } else {
+    encode(0);
+  }
+}
+
+static void encode_double(double d) {
+  char sign = 0;
+  int  exp;
+  unsigned long i1, i2;
+
+  if (d < 0.0) {
+    sign = 1;
+    d = -d;
+  }
+  d = frexp(d, &exp);
+  d = d * 4294967296.0;
+  i1 = (unsigned long)floor(d);
+  d = (d - i1) * 4294967296.0;
+  i2 = (unsigned long)floor(d);
+
+  encode(sign);
+  encode32(exp);
+  encode32(i1);
+  encode32(i2);
+}
+
+typedef void (*encode_bucket_t)(void*);
+
+#define encode_zval_hash(from) encode_hash(from, (encode_bucket_t)encode_zval_ptr)
+
+static void encode_zval_ptr(zval** from);
+static void encode_hash(HashTable* from, encode_bucket_t encode_bucket);
+
+static void encode_zval(zval* from, int refs) {
+  encode(from->type);
+  if (refs) {
+    encode(from->is_ref);
+    encode32(from->refcount);
+  } else if (!from->is_ref || from->refcount != 2) {
+    zend_bailout();
+  }
+
+  switch (from->type & ~IS_CONSTANT_INDEX) {
+    case IS_NULL:
+      break;
+    case IS_BOOL:
+      encode((unsigned char)from->value.lval);
+      break;
+    case IS_LONG:
+      encode32(from->value.lval);
+      break;
+    case IS_DOUBLE:
+      encode_double(from->value.dval);
+      break;
+    case IS_CONSTANT:
+    case IS_STRING:
+/*???    case FLAG_IS_BC:*/
+      encode_lstr(from->value.str.val, from->value.str.len);
+      break;
+    case IS_ARRAY:
+    case IS_CONSTANT_ARRAY:
+      encode_zval_hash(from->value.ht);
+      break;
+    case IS_OBJECT:
+    case IS_RESOURCE:
+      /*???*/
+    default:
+      zend_bailout();
+      break;
+  }
+}
+
+static void encode_znode(znode* from, unsigned int vars_count) {
+  encode((unsigned char)from->op_type);
+  if (from->op_type == IS_CONST) {
+    encode_zval(&from->u.constant, 0);
+  } else if (from->op_type == IS_VAR ||
+             from->op_type == IS_TMP_VAR) {
+    encode_var(from->u.var, vars_count);
+  } else if (from->op_type != IS_UNUSED) {
+    zend_bailout();
+  }
+}
+
+
+static void encode_zval_ptr(zval** from) {
+  encode_zval(*from, 1);
+}
+
+#ifdef ZEND_ENGINE_2
+static void encode_property_info(zend_property_info* from) {
+  encode32(from->flags);
+  encode_lstr(from->name, from->name_length);
+}
+
+static void encode_class_entry(zend_class_entry* from);
+
+static void encode_class_entry_ptr(zend_class_entry** from) {
+  encode_class_entry(*from);
+}
+#endif
+
+static void encode_hash(HashTable* from, encode_bucket_t encode_bucket) {
+  if (from != NULL &&
+      from->nNumOfElements > 0) {
+    Bucket* p;
+    encode32(from->nNumOfElements);
+    p = from->pListHead;
+    while (p != NULL) {
+      encode_lstr(p->arKey, p->nKeyLength);
+      if (p->nKeyLength == 0) {
+        encode32(p->h);
+      }
+      encode_bucket(p->pData);
+      p = p->pListNext;
+    }
+  } else {
+    encode32(0);
+  }
+}
+
+#ifdef ZEND_ENGINE_2
+#define encode_zval_hash_ex(from,p) encode_hash_ex(from, p, (encode_bucket_t)encode_zval_ptr)
+
+static void encode_hash_ex(HashTable* from, Bucket* p, encode_bucket_t encode_bucket) {
+  if (from != NULL &&
+      from->nNumOfElements > 0) {
+    unsigned int n = 0;
+    Bucket* q = p;
+    while (q != NULL) {
+      ++n;
+      q = q->pListNext;
+    }
+    encode32(n);
+    while (p != NULL) {
+      encode_lstr(p->arKey, p->nKeyLength);
+      if (p->nKeyLength == 0) {
+        encode32(p->h);
+      }
+      encode_bucket(p->pData);
+      p = p->pListNext;
+    }
+  } else {
+    encode32(0);
+  }
+}
+#endif
+
+static void encode_op_array(zend_op_array* from) {
+  zend_op *opline;
+  zend_op *end;
+
+  if (from->type == ZEND_INTERNAL_FUNCTION) {
+  } else if (from->type == ZEND_USER_FUNCTION) {
+  } else {
+    zend_bailout();
+  }
+  encode(from->type);
+#ifdef ZEND_ENGINE_2
+  encode32(from->num_args);
+  if (from->num_args > 0) {
+    zend_uint i;
+    for (i = 0; i < from->num_args; i++) {
+      encode_lstr(from->arg_info[i].name,from->arg_info[i].name_len);
+      encode_lstr(from->arg_info[i].class_name,from->arg_info[i].class_name_len);
+      encode(from->arg_info[i].allow_null);
+      encode(from->arg_info[i].pass_by_reference);
+    }
+  }
+  encode(from->pass_rest_by_reference);
+#else
+  encode_pstr(from->arg_types);
+#endif
+  encode_zstr(from->function_name);
+#ifdef ZEND_ENGINE_2
+  encode32(from->fn_flags);
+  if (from->scope != NULL) {
+    TSRMLS_FETCH();
+    {
+      Bucket* q = CG(class_table)->pListHead;
+      while (q != NULL) {
+        if (*(zend_class_entry**)q->pData == from->scope) {
+          encode_lstr(q->arKey, q->nKeyLength);
+          goto scope_stored;
+        }
+        q = q->pListNext;
+      }
+    }
+  }
+  encode32(0);
+scope_stored:
+#endif
+  if (from->type == ZEND_INTERNAL_FUNCTION) {
+    return;
+  }
+  encode32(from->T);
+#ifdef ZEND_ENGINE_2
+  encode(from->uses_this);
+#else
+  encode(from->uses_globals);
+#endif
+  encode(from->return_reference);
+
+  if (from->opcodes != NULL && from->last > 0) {
+    encode32(from->last);
+    if (from->brk_cont_array != NULL && from->last_brk_cont > 0) {
+      zend_uint i;
+      encode32(from->last_brk_cont);
+      for (i = 0; i < from->last_brk_cont; i++) {
+        encode_opline(from->brk_cont_array[i].brk, from->last);
+        encode_opline(from->brk_cont_array[i].cont, from->last);
+        encode_opline(from->brk_cont_array[i].parent, from->last_brk_cont);
+      }
+    } else {
+      encode32(0);
+    }
+#ifdef ZEND_ENGINE_2
+	if (from->try_catch_array != NULL && from->last_try_catch > 0)
+	{
+		zend_uint i;
+		encode32(from->last_try_catch);
+		for (i = 0; i < from->last_try_catch; i++)
+		{
+			encode_opline(from->try_catch_array[i].try_op, from->last);
+			encode_opline(from->try_catch_array[i].catch_op, from->last);
+//			encode_opline(from->try_catch_array[i].parent, from->last_try_catch);
+		}
+	}
+	else
+	{
+		encode32(0);
+	}
+#endif
+	opline = from->opcodes;
+    end = opline + from->last;
+    for (;opline < end; opline++) {
+      const opcode_dsc* op_dsc = get_opcode_dsc(opline->opcode);
+      if (op_dsc == NULL) {
+        zend_bailout();
+      } else {
+        unsigned int ops = op_dsc->ops;
+        encode(opline->opcode);
+#if MMC_ENCODER_VERSION < 2
+        encode32(opline->lineno);
+#endif
+        switch (ops & EXT_MASK) {
+          case EXT_UNUSED:
+            break;
+          case EXT_STD:
+          case EXT_FCALL:
+          case EXT_ARG:
+          case EXT_IFACE:
+            encode32(opline->extended_value);
+            break;
+          case EXT_SEND:
+          case EXT_SEND_NOREF:
+          case EXT_INIT_FCALL:
+          case EXT_FETCH:
+          case EXT_CAST:
+          case EXT_DECLARE:
+          case EXT_FCLASS:
+          case EXT_BIT:
+          case EXT_ISSET:
+          case EXT_ASSIGN:
+            encode((unsigned char)opline->extended_value);
+            break;
+          case EXT_OPLINE:
+            encode_opline(opline->extended_value, from->last);
+            break;
+          case EXT_CLASS:
+            encode_var(opline->extended_value, from->T);
+            break;
+          default:
+            zend_bailout();
+            break;
+        }
+        switch (ops & RES_MASK) {
+          case RES_UNUSED:
+            break;
+          case RES_TMP:
+          case RES_CLASS:
+            encode_var(opline->result.u.var, from->T);
+            break;
+          case RES_VAR:
+            encode_var(opline->result.u.var, from->T);
+            if ((opline->result.u.EA.type & EXT_TYPE_UNUSED) != 0) {
+              encode(1);
+            } else {
+              encode(0);
+            }
+            break;
+          case RES_STD:
+            encode_znode(&opline->result, from->T);
+            if (opline->result.op_type == IS_VAR) {
+              if ((opline->result.u.EA.type & EXT_TYPE_UNUSED) != 0) {
+                encode(1);
+              } else {
+                encode(0);
+              }
+            }
+            break;
+          default:
+            zend_bailout();
+            break;
+        }
+        switch (ops & OP1_MASK) {
+          case OP1_UNUSED:
+            break;
+          case OP1_OPLINE:
+            encode_opline(opline->op1.u.opline_num,from->last);
+            break;
+          case OP1_BRK:
+          case OP1_CONT:
+            encode_opline(opline->op1.u.opline_num, from->last_brk_cont);
+            break;
+          case OP1_CLASS:
+          case OP1_TMP:
+          case OP1_VAR:
+            encode_var(opline->op1.u.var, from->T);
+            break;
+          case OP1_UCLASS:
+            encode((unsigned char)opline->op1.op_type);
+            if (opline->op1.op_type != IS_UNUSED) {
+              encode_var(opline->op1.u.var, from->T);
+            }
+            break;
+          case OP1_ARG:
+            encode32(opline->op1.u.constant.value.lval);
+            break;
+#ifdef ZEND_ENGINE_2
+          case OP1_JMPADDR:
+            encode_opline(opline->op1.u.jmp_addr - from->opcodes, from->last);
+            break;
+#endif
+          case OP1_STD:
+            encode_znode(&opline->op1, from->T);
+            break;
+          default:
+            zend_bailout();
+            break;
+        }
+        switch (ops & OP2_MASK) {
+          case OP2_UNUSED:
+            break;
+          case OP2_OPLINE:
+            encode_opline(opline->op2.u.opline_num, from->last);
+            break;
+          case OP2_ARG:
+            encode32(opline->op2.u.opline_num);
+            break;
+          case OP2_ISSET:
+          case OP2_INCLUDE:
+            encode((unsigned char)opline->op2.u.constant.value.lval);
+            break;
+          case OP2_FETCH:
+#ifdef ZEND_ENGINE_2
+            encode((unsigned char)opline->op2.u.EA.type);
+            if (opline->op2.u.EA.type == ZEND_FETCH_STATIC_MEMBER) {
+              encode_var(opline->op2.u.var, from->T);
+            }
+#else
+            encode((unsigned char)opline->op2.u.fetch_type);
+#endif
+            break;
+          case OP2_CLASS:
+          case OP2_TMP:
+          case OP2_VAR:
+            encode_var(opline->op2.u.var, from->T);
+            break;
+#ifdef ZEND_ENGINE_2
+          case OP2_JMPADDR:
+            encode_opline(opline->op2.u.jmp_addr - from->opcodes, from->last);
+            break;
+#endif
+          case OP2_STD:
+            encode_znode(&opline->op2, from->T);
+            break;
+          default:
+            zend_bailout();
+            break;
+        }
+      }
+    }
+  } else {
+    encode32(0);
+  }
+  encode_zval_hash(from->static_variables);
+#if MMC_ENCODER_VERSION < 2
+  encode_zstr(from->filename);
+#endif
+#ifdef ZEND_ENGINE_2
+  encode32(from->line_start);
+  encode32(from->line_end);
+  encode_lstr(from->doc_comment, from->doc_comment_len);
+#endif
+}
+
+static void encode_class_entry(zend_class_entry* from) {
+  encode(from->type);
+  encode_lstr(from->name,from->name_length);
+#ifdef ZEND_ENGINE_2
+  encode32(from->ce_flags);
+  encode32(from->num_interfaces);
+#endif
+
+  if (from->parent != NULL && from->parent->name) {
+    encode_lstr(from->parent->name, from->parent->name_length);
+  } else {
+    encode32(0);
+  }
+
+#ifdef ZEND_ENGINE_2
+#if MMC_ENCODER_VERSION < 2
+  encode32(from->line_start);
+  encode32(from->line_end);
+  encode_zstr(from->filename);
+#endif
+  encode_lstr(from->doc_comment, from->doc_comment_len);
+
+  encode_zval_hash(&from->constants_table);
+  encode_zval_hash(&from->default_properties);
+  encode_hash(&from->properties_info, (encode_bucket_t)encode_property_info);
+  encode_zval_hash(from->static_members);
+#else
+  encode_zval_hash(&from->default_properties);
+#endif
+  encode_hash(&from->function_table, (encode_bucket_t)encode_op_array);
+}
+
+static int eaccelerator_encode(char* key, zend_op_array* op_array,
+                          Bucket* f, Bucket *c) {
+  encode_zstr("EACCELERATOR");
+  encode32(MMC_ENCODER_VERSION);
+#ifdef ZEND_ENGINE_2
+  encode(2);
+#else
+  encode(1);
+#endif
+  while (c != NULL) {
+    zend_class_entry *ce;
+#ifdef ZEND_ENGINE_2
+    ce = *(zend_class_entry**)c->pData;
+    encode(MMC_ENCODER_CLASS);
+    encode_lstr(c->arKey, c->nKeyLength);
+    encode_class_entry(ce);
+#else
+    encode(MMC_ENCODER_CLASS);
+    encode_lstr(c->arKey, c->nKeyLength);
+    ce = (zend_class_entry*)c->pData;
+    encode_class_entry(ce);
+#endif
+    c = c->pListNext;
+  }
+  encode(MMC_ENCODER_END);
+
+  while (f != NULL) {
+    encode(MMC_ENCODER_FUNCTION);
+    encode_lstr(f->arKey, f->nKeyLength);
+    encode_op_array((zend_op_array*)f->pData);
+    f = f->pListNext;
+  }
+  encode(MMC_ENCODER_END);
+  encode_op_array(op_array);
+  return 1;
+}
+
+#ifdef ZEND_ENGINE_2
+
+ZEND_DLIMPORT int isatty(int fd);
+
+static size_t eaccelerator_stream_stdio_reader(void *handle, char *buf, size_t len TSRMLS_DC)
+{
+	return fread(buf, 1, len, (FILE*)handle);
+}
+
+static void eaccelerator_stream_stdio_closer(void *handle TSRMLS_DC)
+{
+	if ((FILE*)handle != stdin)
+		fclose((FILE*)handle);
+}
+
+#endif
+
+PHP_FUNCTION(eaccelerator_encode)
+{
+	zend_op_array *t;
+	Bucket        *f;
+	Bucket        *c;
+	zval          *src;
+	zval          *prefix = NULL;
+	char          *pre_content = NULL;
+	int           pre_content_len = 0;
+	char          *post_content = NULL;
+	int           post_content_len = 0;
+	int welldone = 0;
+	char *opened_path=NULL;
+	zend_file_handle file_handle;
+	zend_bool old_enabled;
+
+	FILE* src_fp;
+
+	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
+		"z|zss", &src, &prefix,
+		&pre_content, &pre_content_len,
+		&post_content, &post_content_len) == FAILURE)
+	{
+		return;
+	}
+	if (Z_TYPE_P(src) == IS_STRING)
+	{
+#ifndef ZEND_ENGINE_2
+		file_handle.handle.fp = NULL;
+		file_handle.type = ZEND_HANDLE_FILENAME;
+		file_handle.filename = Z_STRVAL_P(src);
+		file_handle.opened_path = NULL;
+		file_handle.free_filename = 0;
+#endif
+	}
+	else
+	{
+		zend_error(E_WARNING, "eaccelerator_encode() expects parameter 1 to be string\n");
+		RETURN_FALSE;
+	}
+	if (!zend_hash_exists(EG(function_table), "gzcompress", sizeof("gzcompress")))
+	{
+		zend_error(E_ERROR, "eAccelerator Encoder requires php_zlib extension.\n");
+		RETURN_FALSE;
+	}
+	if (prefix != NULL)
+	{
+		ZVAL_EMPTY_STRING(prefix);
+	}
+
+	/* Storing global pre-compiled functions and classes */
+	f = CG(function_table)->pListTail;
+	c = CG(class_table)->pListTail;
+	MMCG(compiler) = 1;
+	MMCG(encoder) = 1;
+	old_enabled = MMCG(enabled);
+	MMCG(enabled) = 0;
+	zend_try
+	{
+		char *opened_path;
+
+#ifdef ZEND_ENGINE_2
+		zend_stream_open(Z_STRVAL_P(src), &file_handle TSRMLS_CC);
+		src_fp = fopen(file_handle.opened_path, "r");
+		opened_path = file_handle.opened_path;
+#else
+		file_handle.handle.fp = zend_fopen(file_handle.filename, &opened_path);
+		src_fp = file_handle.handle.fp;
+#endif
+
+		if (src_fp)
+		{
+			/* #!php support */
+			long pos = 0;
+			char c;
+
+			c = fgetc(src_fp);
+			pos++;
+			if (c == '#')
+			{
+				while (c != 10 && c != 13)
+				{
+					c = fgetc(src_fp); /* skip to end of line */
+					pos++;
+				}
+				/* handle situations where line is terminated by \r\n */
+				/* HOESH: easy rider.. tricky half sised */
+				if (c == 13 || c == 10)
+				{
+					if (fgetc(src_fp)+c != 10 + 13)
+					{
+						if (prefix == NULL) fseek(src_fp, pos, SEEK_SET);
+					}
+					else pos++;
+				}
+				if (prefix != NULL)
+				{
+					prefix->type = IS_STRING;
+					prefix->value.str.len = pos;
+					prefix->value.str.val = emalloc(pos+1);
+					rewind(src_fp);
+					fread(prefix->value.str.val, pos, 1, src_fp);
+					prefix->value.str.val[prefix->value.str.len] = '\000';
+				}
+			}
+			else
+			{
+				rewind(src_fp);
+			}
+#ifndef ZEND_ENGINE_2
+			file_handle.type = ZEND_HANDLE_FP;
+			file_handle.opened_path = opened_path;
+#endif
+		    if (1)
+			{
+				FILE *tmp_fp = tmpfile();
+				if (tmp_fp)
+				{
+					if (pre_content_len > 0)
+					{
+						fwrite(pre_content, pre_content_len, 1, tmp_fp);
+					}
+#ifndef WITHOUT_FILE_FILTER
+					filter_file(src_fp, tmp_fp TSRMLS_CC);
+#else
+					while (1)
+					{
+						int c = fgetc(src_fp);
+						if (c == EOF) break;
+						fputc(c, tmp_fp);
+					}
+#endif
+					if (post_content_len > 0)
+					{
+						fwrite(post_content, post_content_len, 1, tmp_fp);
+					}
+					rewind(tmp_fp);
+					fclose(src_fp);
+#ifndef ZEND_ENGINE_2
+					file_handle.handle.fp = tmp_fp;
+#else
+					/* HOESH: change stream */
+					file_handle.handle.stream.closer(file_handle.handle.stream.handle TSRMLS_CC);
+					file_handle.handle.stream.handle = tmp_fp;
+					file_handle.handle.stream.reader = eaccelerator_stream_stdio_reader;
+					file_handle.handle.stream.closer = eaccelerator_stream_stdio_closer;
+					file_handle.type = ZEND_HANDLE_STREAM;
+					file_handle.handle.stream.interactive = isatty(fileno((FILE *)file_handle.handle.stream.handle));
+#endif
+				}
+			}
+		}
+		t = zend_compile_file(&file_handle, ZEND_INCLUDE TSRMLS_CC);
+	}
+	zend_catch
+	{
+		t = NULL;
+		/* restoring some globals to default values */
+		CG(active_class_entry) = NULL;
+	}
+	zend_end_try();
+
+	MMCG(encoder) = 0;
+	MMCG(compiler) = 0;
+	MMCG(enabled) = old_enabled;
+
+	f = f ? f->pListNext : CG(function_table)->pListHead;
+	c = c ? c->pListNext : CG(class_table)->pListHead;
+
+	if (t != NULL)
+	{
+		opened_path = file_handle.opened_path;
+#ifdef PHP_OUTPUT_HANDLER_USER
+		/* PHP 4.2.0 and above */
+		if (php_start_ob_buffer(NULL, 0, 0 TSRMLS_CC) != FAILURE)
+		{
+#else
+		/* PHP 4.1.2 and before */
+		if (php_start_ob_buffer(NULL, 0 TSRMLS_CC) != FAILURE)
+		{
+#endif
+/*???
+			zend_error(E_ERROR, "Cann't encode %s\n", opened_path);
+*/
+			zend_try
+			{
+				if (eaccelerator_encode(opened_path, t, f, c) &&
+					php_ob_get_buffer(return_value TSRMLS_CC) != FAILURE)
+				{
+					zval func;
+					zval gzstring;
+					zval *params[1];
+
+					php_end_ob_buffer(0, 0 TSRMLS_CC);
+					ZVAL_STRING(&func, "gzcompress", 0);
+					params[0] = return_value;
+					if (call_user_function(CG(function_table), (zval**)NULL, &func, &gzstring, 1, params TSRMLS_CC) == SUCCESS &&
+						gzstring.type == IS_STRING)
+					{
+						zval_dtor(return_value);
+						ZVAL_STRING(&func, "base64_encode", 0);
+						params[0] = &gzstring;
+						if (call_user_function(CG(function_table), (zval**)NULL, &func, return_value, 1, params TSRMLS_CC) == SUCCESS &&
+							return_value->type == IS_STRING)
+						{
+							zval_dtor(&gzstring);
+							welldone = 1;
+						}
+					}
+				}
+			}
+			zend_catch
+			{
+				php_end_ob_buffer(0, 0 TSRMLS_CC);
+			}
+			zend_end_try();
+		}
+	}
+	/* Clear compiled code */
+	if (t != NULL)
+	{
+#ifdef ZEND_ENGINE_2
+		destroy_op_array(t TSRMLS_CC);
+#else
+		destroy_op_array(t);
+#endif
+		efree(t);
+	}
+	while (f != NULL)
+	{
+		Bucket* q = f->pListNext;
+		zend_hash_del(CG(function_table), f->arKey, f->nKeyLength);
+		f = q;
+	}
+	while (c != NULL)
+	{
+		Bucket* q = c->pListNext;
+		zend_hash_del(CG(class_table), c->arKey, c->nKeyLength);
+		c = q;
+	}
+	zend_destroy_file_handle(&file_handle TSRMLS_CC);
+	if (welldone)
+	{
+		return;
+	}
+	else RETURN_FALSE;
+}
+
+#endif
+#endif
Index: /eaccelerator/trunk/x86_spinlocks.h
===================================================================
--- /eaccelerator/trunk/x86_spinlocks.h	(revision 4)
+++ /eaccelerator/trunk/x86_spinlocks.h	(revision 4)
@@ -0,0 +1,54 @@
+/*???
+#ifdef HAVE_SCHED_H
+#  include <sched.h>
+#endif
+*/
+
+typedef struct { volatile unsigned int lock;
+                 volatile pid_t pid;
+                 volatile int locked;
+               } spinlock_t;
+
+#define spinlock_init(rw)  do { (rw)->lock = 0x00000001; (rw)->pid=-1; (rw)->locked=0;} while(0)
+
+#define spinlock_try_lock(rw)  asm volatile("lock ; decl %0" :"=m" ((rw)->lock) : : "memory")
+#define _spinlock_unlock(rw)   asm volatile("lock ; incl %0" :"=m" ((rw)->lock) : : "memory")
+
+
+/*???
+#ifdef HAVE_SCHED_YIELD
+#  define yield sched_yield
+#else
+*/
+static inline void yield()
+{
+  struct timeval t;
+
+  t.tv_sec = 0;
+  t.tv_usec = 100;
+  select(0, NULL, NULL, NULL, &t);
+}
+/*???
+#endif
+*/
+static inline void spinlock_unlock(spinlock_t* rw) {
+  if (rw->locked && (rw->pid == getpid())) {
+    rw->pid = 0;
+    rw->locked = 0;
+    _spinlock_unlock(rw);
+  }
+}
+
+static inline void spinlock_lock(spinlock_t* rw)
+{
+  while (1) {
+    spinlock_try_lock(rw);
+    if (rw->lock == 0) {
+      rw->pid = getpid();
+      rw->locked = 1;
+      return;
+    }
+    _spinlock_unlock(rw);
+    yield();
+  }
+}
Index: /eaccelerator/trunk/eaccelerator_password.php
===================================================================
--- /eaccelerator/trunk/eaccelerator_password.php	(revision 4)
+++ /eaccelerator/trunk/eaccelerator_password.php	(revision 4)
@@ -0,0 +1,105 @@
+<?php
+
+function main_cli() {
+  echo "Changing password for eAccelerator Web Interface (eaccelerator.php)\n\n";
+  $stdin = fopen("php://stdin","r");
+  while (1) {
+    echo "Enter admin name: ";
+    $name = fgets($stdin,1024);
+    if (feof($stdin)) {echo("\n"); exit;}
+    $name = str_replace(array("\n","\r"),"",$name);
+    if ($name == "") {
+      echo "\nSorry, admin name can't be empty\n";
+    } else {
+      break;
+    }
+  }
+  while (1) {
+    echo "New admin password: ";
+    $p1 = fgets($stdin,1024);
+    if (feof($stdin)) {echo("\n"); exit;}
+    $p1 = str_replace(array("\n","\r"),"",$p1);
+    if ($p1 == "") {
+      echo "\nSorry, new admin password can't be empty\n";
+    } else {
+      break;
+    }
+  }
+  echo "Retype new admin password: ";
+  $p2 = fgets($stdin,1024);
+  if (feof($stdin)) {echo("\n"); exit;}
+  $p2 = str_replace(array("\n","\r"),"",$p2);
+  if ($p1 != $p2) {
+    echo "\nSorry, passwords do not match\n";
+    exit;
+  }
+  $password = crypt($p1);
+  echo "\nAdd the following lines into your php.ini and restart HTTPD\n\n".
+       "eaccelerator.admin.name=\"$name\"\n".
+       "eaccelerator.admin.password=\"$password\"\n";
+}
+
+function main_web() {
+  $admin_name      = "";
+  $admin_password  = "";
+  $admin_password2 = "";
+  $error = "";
+  if (isset($_POST["submit"])) {
+    if (isset($_POST["admin_name"])) {
+      $admin_name = $_POST["admin_name"];
+    }
+    if (isset($_POST["admin_password"])) {
+      $admin_password = $_POST["admin_password"];
+    }
+    if (isset($_POST["admin_password2"])) {
+      $admin_password2 = $_POST["admin_password2"];
+    }
+    if (empty($admin_name)) {
+      $error = "Sorry, admin name can't be empty";
+    } else if (empty($admin_password)) {
+      $error = "Sorry, new admin password can't be empty";
+    } else if ($admin_password != $admin_password2) {
+      $error = "Sorry, passwords do not match";
+    } else {
+      $password = crypt($admin_password);
+      echo "<html><head><title>Changing password for eAccelerator Web Interface (eaccelerator.php)</title></head>".
+           "<body><h1 align=\"center\">Changing password for eAccelerator Web Interface (eaccelerator.php)</h1>".
+           "Add the following lines into your php.ini and restart HTTPD<br><pre><b>".
+           "eaccelerator.admin.name=\"$admin_name\"\n".
+           "eaccelerator.admin.password=\"$password\"\n</b></pre></body></html>";
+      return;
+    }
+  }
+  echo "<html><head><title>Changing password for eAccelerator Web Interface (eaccelerator.php)</title></head>".
+       "<body><h1 align=\"center\">Changing password for eAccelerator Web Interface (eaccelerator.php)</h1>".
+       "<h3 align=\"center\"><font color=\"#ff0000\">$error</font></h3>".
+       "<form method=\"POST\">".
+       "<table border=\"0\" cellpadding=\"3\" cellspacing=\"1\" width=\"600\" bgcolor=\"#000000\" align=\"center\">".
+       "<tr valign=\"baseline\" bgcolor=\"#cccccc\"><td width=\"50%\" bgcolor=\"#ccccff\"><b>Admin name:</b></td><td width=\"50%\"><input type=\"text\" name=\"admin_name\" size=\"32\" value=\"$admin_name\" style=\"width:100%\"></td></tr>".
+       "<tr valign=\"baseline\" bgcolor=\"#cccccc\"><td width=\"50%\" bgcolor=\"#ccccff\"><b>New admin password:</b></td><td width=\"50%\"><input type=\"text\" name=\"admin_password\" size=\"32\" value=\"$admin_password\" style=\"width:100%\"></td></tr>".
+       "<tr valign=\"baseline\" bgcolor=\"#cccccc\"><td width=\"50%\" bgcolor=\"#ccccff\"><b>Retype new admin password:</b></td><td width=\"50%\"><input type=\"text\" name=\"admin_password2\" size=\"32\" value=\"$admin_password2\" style=\"width:100%\"></td></tr>".
+       "<tr><td colspan=\"2\" align=\"center\" bgcolor=\"#cccccc\"><input type=\"submit\" name=\"submit\" value=\"OK\" style=\"width:100px\"></td></tr>".
+       "</form></body></html>";
+}
+
+function is_cli() {
+  if (php_sapi_name() == "cli" || empty($_SERVER['PHP_SELF'])) {
+    return 1;
+  } else {
+    return 0;
+  }
+}
+
+if (is_cli()) {
+  if (function_exists("ob_end_flush")) {
+    ob_end_flush();
+  }
+  if (function_exists("ob_implicit_flush")) {
+    ob_implicit_flush(1);
+  }
+  main_cli();
+} else {
+  main_web();
+}
+
+?>
Index: /eaccelerator/trunk/encoder.php
===================================================================
--- /eaccelerator/trunk/encoder.php	(revision 4)
+++ /eaccelerator/trunk/encoder.php	(revision 4)
@@ -0,0 +1,439 @@
+<?php
+$web_error = "";
+
+function eaccelerator_encoder_usage() {
+  echo "Usage:\tphp -q encoder.php [options] source_file_name\n";
+  echo       "\tphp -q encoder.php [options] source_file_name...\n";
+  echo       "\tphp -q encoder.php [options] source_directory_name...\n\n";
+  echo "Options:\n";
+  echo "\t-s suffix\n\t\tencode files only with following suffix (default is \"php\")\n";
+  echo "\t-a\n\t\tencode all files (no by default)\n";
+  echo "\t-l\n\t\tfollow symbolic links (no by default)\n";
+  echo "\t-r\n\t\tencode directories recursively (no by default)\n";
+  echo "\t-c\n\t\tcopy files those shouldn't be encoded (no by default)\n";
+  echo "\t-f\n\t\toverwrite existing files (no by default)\n";
+  echo "\t-o target\n\t\tIf you encode only one script then 'target' specifyes an output\n";
+  echo               "\t\tfile name. If you encode directory or several files at once\n";
+  echo               "\t\tthen 'target' specifyes an output directory name.\n";
+  echo "\nExamples:\n";
+  echo "\tphp -q encoder.php some_file.php\n";
+  echo "\tphp -q encoder.php some_file.php -o some_encoded_file.php\n";
+  echo "\tphp -q encoder.php *.php -o some_dir\n";
+  echo "\tphp -q encoder.php ~/public_html/x -rcf -sphp -sinc -o ~/public_html/y\n";
+  echo "\n";
+  exit();
+}
+
+function eaccelerator_error($str, $web) {
+  if ($web) {
+    global $web_error;
+    $web_error = "ERROR: $str";
+  } else {
+    echo "eAccelerator Encoder ERROR: $str\n";
+  }
+}
+
+function eaccelerator_encode_file($src, $out, $f, $c, $web) {
+  if (empty($out)) {
+    echo "\n// $src\n";
+  }
+  $prefix = "";
+  $cmp = eaccelerator_encode($src, $prefix);
+  if (empty($cmp)) {
+    eaccelerator_error("Can't compile file \"$src\"",$web);
+    if ($f) {
+      if ($c && !empty($out)) {
+        if ($web) {
+          global $web_error;
+          if (!empty($web_error)) {
+            echo "<font color=\"#ff0000\">$web_error</font><br>\n"; flush();
+            $web_error = "";
+          }
+        }
+        eaccelerator_copy_file($src, $out, $f, $web);
+      }
+    } else {
+      if (!$web) {
+        exit();
+      }
+    }
+  } else {
+    $cmp = $prefix.'<?php if (!is_callable("eaccelerator_load") && !@dl((PHP_OS=="WINNT"||PHP_OS=="WIN32")?"TurckLoader.dll":"TurckLoader.so")) { die("This PHP script has been encoded with eAccelerator, to run it you must install <a href=\"http://eaccelerator.sourceforge.net/\">eAccelerator or Turck Loader</a>");} return eaccelerator_load(\''.$cmp."');?>\n";
+    if (!empty($out)) {
+      if (!$f && file_exists($out)) {
+        eaccelerator_error("Can't create output file \"$out\" (already exists)",$web);
+      } else {
+        $file = @fopen($out,"wb");
+        if (!$file) {
+          eaccelerator_error("Can't open output file \"$out\"",$web);
+        } else {
+          fwrite($file,$cmp);
+          unset($cmp);
+          fclose($file);
+          $stat = stat($src);
+          chmod($out, $stat['mode']);
+          if ($web) {
+            echo "<font color=\"#00aa00\">Encoding: \"$src\" -> \"$out\"</font><br>\n";
+          }
+        }
+      }
+    } else {
+      if ($web) {
+        echo "<pre>".htmlspecialchars($cmp)."</pre>\n";
+      } else {
+        echo $cmp;
+      }
+      unset($cmp);
+    }
+  }
+}
+
+function eaccelerator_mkdir($dir, $f, $web) {
+  if (!empty($dir)) {
+    if (!@mkdir($dir,0777)) {
+      if (!$f) {
+        $error = "Can't create destination directory \"$dir\"";
+        if (file_exists($dir)) {
+          $error .= " (already exists)";
+        }
+        eaccelerator_error($error, $web);
+        return 0;
+      }
+    }
+  }
+  return 1;
+}
+
+function eaccelerator_copy_dir($src, $dir, $f, $web) {
+  $stat = stat($src);
+  $old = umask(0);
+  $ret = eaccelerator_mkdir($dir, $f, $web);
+  umask($old);
+  return $ret;
+}
+
+function eaccelerator_copy_file($src, $out, $f, $web) {
+  $i = @fopen($src, "rb");
+  if (!$i) {
+    eaccelerator_error("Can't open file \"$src\" for copying",$web);
+    return;
+  }
+  if (!$f && file_exists($out)) {
+    eaccelerator_error("Can't create output file \"$out\" (already exists)");
+  } else {
+    $o = @fopen($out, "wb");
+    if (!$o) {
+      eaccelerator_error("Can't copy file into \"$out\"");
+      return;
+    }
+    while ($tmp = fread($i, 1024*32)) {
+      fwrite($o, $tmp);
+    }
+    fclose($i);
+    fclose($o);
+    $stat = stat($src);
+    chmod($out, $stat['mode']);
+    if ($web) {
+      echo "<font color=\"#00aa00\">Copying: \"$src\" -> \"$out\"</font><br>\n";
+    }
+  }
+}
+
+function eaccelerator_copy_link($src, $out, $f, $web) {
+  $link = readlink($src);
+  if (!@symlink($link,$out)) {
+    if ($f && file_exists($out)) {
+      unlink($out);
+      eaccelerator_copy_link($src, $out, false, $web);
+    } else if ($f && is_array(lstat($out))) {
+      unlink($out);
+      eaccelerator_copy_link($src, $out, false, $web);
+    } else {
+      eaccelerator_error("Can't create symlink \"$out\" -> \"$link\"");
+      return;
+    }
+  }
+}
+
+function eaccelerator_encode_dir($src, $out, $s, $r, $l, $c, $f, $web) {
+  if ($dir = @opendir($src)) {
+    while (($file = readdir($dir)) !== false) {
+      if ($file == "." || $file == "..") continue;
+      $i = "$src/$file";
+      $o = empty($out)?$out:"$out/$file";
+      if (is_link($i)) {
+        if ($c && !empty($o)) {
+          eaccelerator_copy_link($i, $o, $f, $web);
+          if ($web) {
+            global $web_error;
+            if (!empty($web_error)) {
+              echo "<font color=\"#ff0000\">$web_error</font><br>\n"; flush();
+              $web_error = "";
+            }
+          }
+          continue;
+        } else if (!$l) {
+          continue;
+        }
+      }
+      if (is_dir($i)) {
+        if ($r) {
+          if (eaccelerator_copy_dir($i, $o, $f, $web)) {
+            eaccelerator_encode_dir($i, $o, $s, $r, $l, $c, $f, $web);
+          }
+        }
+      } else if (is_file($i)) {
+        if (empty($s)) {
+          eaccelerator_encode_file($i, $o, $f, $c, $web);
+        } else if (is_string($s)) {
+          if (preg_match("/".preg_quote(".$s")."\$/i", $file)) {
+            eaccelerator_encode_file($i, $o, $f, $c, $web);
+          } else if (!empty($o) && $c) {
+            eaccelerator_copy_file($i, $o, $f, $web);
+          }
+        } else if (is_array($s)) {
+          $encoded = false;
+          foreach($s as $z) {
+            if (preg_match("/".preg_quote(".$z")."\$/i", $file)) {
+              eaccelerator_encode_file($i, $o, $f, $c, $web);
+              $encoded = true;
+              break;
+            }
+          }
+          if (!$encoded && !empty($o) && $c) {
+            eaccelerator_copy_file($i, $o, $f, $web);
+          }
+        }
+      }
+      if ($web) {
+        global $web_error;
+        if (!empty($web_error)) {
+          echo "<font color=\"#ff0000\">$web_error</font><br>\n"; flush();
+          $web_error = "";
+        }
+      }
+    }
+    closedir($dir);
+  } else {
+    eaccelerator_error("Can't open source directory \"$src\"", $web);
+  }
+}
+
+function eaccelerator_encoder_main() {
+  $argc = $_SERVER['argc'];
+  $argv = $_SERVER['argv'];
+
+  $src = array();
+  $out = null;
+  unset($s);
+  $r = false;
+  $l = false;
+  $a = false;
+  $c = false;
+  $f = false;
+
+  for ($i = 1; $i < $argc; $i++) {
+    $arg = $argv[$i];
+    if (!empty($arg)) {
+      if ($arg[0] == '-') {
+        if ($arg[1] == "o") {
+          if (!empty($out)) {
+            eaccelerator_encoder_usage();
+          }
+          if (strlen($arg) == 2) {
+            if ($argc <= $i || empty($argv[$i+1]) || $argv[$i+1][0] == "-") {
+              eaccelerator_encoder_usage();
+            }
+            $out = $argv[++$i];
+          } else {
+            $out = substr($arg,2);
+          }
+
+        } else if ($arg[1] == "s") {
+          if (strlen($arg) == 2) {
+            $s[] = $argv[++$i];
+          } else {
+            $s[] = substr($arg,2);
+          }
+        } else if (strlen($arg) == 2 && $arg[1] == "r") {
+          $r = true;
+        } else if (strlen($arg) == 2 && $arg[1] == "l") {
+          $l = true;
+        } else if (strlen($arg) == 2 && $arg[1] == "a") {
+          $a = true;
+        } else if (strlen($arg) == 2 && $arg[1] == "c") {
+          $c = true;
+        } else if (strlen($arg) == 2 && $arg[1] == "f") {
+          $f = true;
+        } else {
+          $len = strlen($arg);
+          if ($len > 1) {
+            $n   = 1;
+            while ($n < $len) {
+              if ($arg[$n] == "r") {
+                $r = true;
+              } else if ($arg[$n] == "l") {
+                $l = true;
+              } else if ($arg[$n] == "a") {
+                $a = true;
+              } else if ($arg[$n] == "c") {
+                $c = true;
+              } else if ($arg[$n] == "f") {
+                $f = true;
+              } else {
+                if ($arg[$n] != "o" && $arg[$n] != "s") {
+                  echo("eAccelerator Encoder ERROR: Unknown option \"-".$arg[$n]."\"\n\n");
+                }
+                eaccelerator_encoder_usage();
+              }
+              ++$n;
+            }
+          } else {
+            echo("eAccelerator Encoder ERROR: Unknown option \"$arg\"\n\n");
+            eaccelerator_encoder_usage();
+          }
+        }
+      } else {
+        $src[] = $arg;
+      }
+    }
+  }
+  if (isset($src) && is_array($src) && count($src) > 0) {
+    $cnt = count($src);
+    if ($a) {
+      $s = "";
+    } else if (!isset($s)) {
+      $s = "php";
+    }
+    if ($cnt > 1) {
+      if (!eaccelerator_mkdir($out, $f, 0)) {
+        return;
+      }
+    }
+    foreach($src as $file) {
+      if (!file_exists($file)) {
+        echo("eAccelerator Encoder ERROR: Source file \"$file\" doesn't exist.\n");
+      } else {
+        if (is_dir($file)) {
+          if ($cnt == 1) {
+            if (eaccelerator_mkdir($out, $f, 0)) {
+              eaccelerator_encode_dir($file, $out, $s, $r, $l, $c, $f, 0);
+            }
+          } else {
+            if (eaccelerator_copy_dir($file, $out."/".basename($file), $f, 0)) {
+              eaccelerator_encode_dir($file, $out."/".basename($file), $s, $r, $l, $c, $f, 0);
+            }
+          }
+        } else {
+          if ($cnt == 1) {
+            eaccelerator_encode_file($file, $out, $f, $c, 0);
+          } else {
+            if (empty($out)) {
+              eaccelerator_encode_file($file, $out, $f, $c, 0);
+            } else {
+              eaccelerator_encode_file($file, $out."/".basename($file), $f, $c, 0);
+            }
+          }
+        }
+      }
+    }
+  } else {
+    eaccelerator_encoder_usage();
+  }
+}
+
+function eaccelerator_encoder_web() {
+  echo "<html><head><title>eAccelerator Encoder</title></head>".
+       "<body><h1 align=\"center\">eAccelerator Encoder ".EACCELERATOR_VERSION."</h1>";
+  $error = "";
+  $source = "";
+  $target = "";
+  $s = "php";
+  $suffixies = "php";
+  if (isset($_POST["submit"])) {
+    if (isset($_POST["source"])) {
+      $source = $_POST["source"];
+    }
+    if (isset($_POST["target"])) {
+      $target = $_POST["target"];
+    }
+    if (isset($_POST["suffixies"])) {
+      $suffixies = $_POST["suffixies"];
+      if (strpos($suffixies,",") !== false) {
+        $s = explode(",",$suffixies);
+      } else {
+        $s = $suffixies;
+      }
+    }
+    $all = isset($_POST["all"])?$_POST["all"]:false;
+    $links = isset($_POST["links"])?$_POST["links"]:false;
+    $recursive = isset($_POST["recursive"])?$_POST["recursive"]:false;
+    $copy = isset($_POST["copy"])?$_POST["copy"]:false;
+    $force = isset($_POST["force"])?$_POST["force"]:false;
+    if (empty($source)) {
+      $error = "ERROR: Source is not specified!";
+    } else if (!file_exists($source)) {
+      $error = "ERROR: Source file \"$source\" doesn't exist.\n";
+    } else {
+      if (is_dir($source)) {
+        if (eaccelerator_mkdir($target, $force, 1)) {
+          if ($all) {
+            $s = "";
+          }
+          eaccelerator_encode_dir($source, $target, $s, $recursive, $links, $copy, $force, 1);
+        }
+      } else {
+        eaccelerator_encode_file($source, $target, $force, $copy, 1);
+      }
+      global $web_error;
+      if (empty($web_error)) {
+        echo "<br><b>DONE</b></html>";
+        return;
+      } else {
+        $error = $web_error;
+      }
+    }
+  }
+  echo "<h3 align=\"center\"><font color=\"#ff0000\">$error</font></h3>".
+       "<form method=\"POST\">".
+       "<table border=\"0\" cellpadding=\"3\" cellspacing=\"1\" width=\"600\" bgcolor=\"#000000\" align=\"center\">".
+       "<tr valign=\"baseline\" bgcolor=\"#cccccc\"><td width=\"50%\" bgcolor=\"#ccccff\"><b>Souce file or directory name:</b></td><td width=\"50%\"><input type=\"text\" name=\"source\" size=\"32\" value=\"$source\" style=\"width:100%\"></td></tr>".
+       "<tr valign=\"baseline\" bgcolor=\"#cccccc\"><td width=\"50%\" bgcolor=\"#ccccff\"><b>Target file or directory name:</b></td><td width=\"50%\"><input type=\"text\" name=\"target\" size=\"32\" value=\"$target\" style=\"width:100%\"></td></tr>".
+       "<tr valign=\"baseline\" bgcolor=\"#cccccc\"><td width=\"50%\" bgcolor=\"#ccccff\"><b>PHP suffixies <small>(comma separated list)</small>:</b></td><td width=\"50%\"><input type=\"text\" name=\"suffixies\" size=\"32\" value=\"$suffixies\" style=\"width:100%\"></td></tr>".
+
+       "<tr valign=\"baseline\" bgcolor=\"#cccccc\"><td width=\"50%\" bgcolor=\"#ccccff\"><b>Options:</b></td><td width=\"50%\">".
+       "<input type=\"checkbox\" id=\"all\" name=\"all\"".(empty($all)?"":" checked")."> - <label for=\"all\">encode all files</label><br>".
+       "<input type=\"checkbox\" id=\"links\" name=\"links\"".(empty($links)?"":" checked")."> - <label for=\"links\">follow symbolic links</label><br>".
+       "<input type=\"checkbox\" id=\"recursive\" name=\"recursive\"".(empty($recursive)?"":" checked")."> - <label for=\"recursive\">encode directories recursively</label><br>".
+       "<input type=\"checkbox\" id=\"copy\" name=\"copy\"".(empty($copy)?"":" checked")."> - <label for=\"copy\">copy files those shouldn't be encoded</label><br>".
+       "<input type=\"checkbox\" id=\"force\" name=\"force\"".(empty($force)?"":" checked")."> - <label for=\"force\">overwrite existing files</label><br>".
+       "</td></tr>".
+       "<tr><td colspan=\"2\" align=\"center\" bgcolor=\"#cccccc\"><input type=\"submit\" name=\"submit\" value=\"OK\" style=\"width:100px\"></td></tr>".
+       "</form></body></html>";
+}
+
+set_time_limit(0);
+
+function is_cli() {
+  if (php_sapi_name() == "cli" || empty($_SERVER['PHP_SELF'])) {
+    return 1;
+  } else {
+    return 0;
+  }
+}
+
+if (is_cli()) {
+  if (!is_callable("eaccelerator_encode") && !(!extension_loaded("eAccelerator") && @dl((PHP_OS=="WINNT"||PHP_OS=="WIN32")?"eaccelerator.dll":"eaccelerator.so") && is_callable("eaccelerator_encode"))) {
+    die("ERROR: eAccelerator Encoder is not installed\n");
+  }
+  if (!isset($_SERVER['argc'])) {
+    die("ERROR: Set \"register_argc_argv = On\" in your php.ini or use a CLI version of PHP to run encoder.\n");
+  }
+  eaccelerator_encoder_main();
+} else {
+  if (!is_callable("eaccelerator_encode") && !(!extension_loaded("eAccelerator") && @dl((PHP_OS=="WINNT"||PHP_OS=="WIN32")?"eaccelerator.dll":"eaccelerator.so") && is_callable("eaccelerator_encode"))) {
+    die("<html><head><title>eAccelerator Encoder</title></head><body><h1 align=\"center\">eAccelerator Encoder is not installed</h1></body></html>");
+  }
+  eaccelerator_encoder_web();
+}
+?>
Index: /eaccelerator/trunk/eaccelerator.ini
===================================================================
--- /eaccelerator/trunk/eaccelerator.ini	(revision 4)
+++ /eaccelerator/trunk/eaccelerator.ini	(revision 4)
@@ -0,0 +1,96 @@
+[eaccelerator]
+
+; eAccelerator is compatible with Zend Optimizer's loader. Zend Optimizer
+; must be installed after eAccelerator in php.ini. If you don't use scripts
+; encoded with Zend Encoder then we do not recommend you install Zend Optimizer
+; with eAccelerator.
+
+; eAccelerator.
+
+; You must uncomment one (and only one) line from the following to load
+; eAccelerator extension.
+
+;extension="eaccelerator.so"
+;zend_extension="/usr/lib/php4/eaccelerator.so"
+;zend_extension_ts="/usr/lib/php4/eaccelerator.so"
+;extension="eaccelerator.dll"
+;zend_extension_ts="c:\php4\eaccelerator.dll"
+;zend_extension="c:\php4\eaccelerator.dll"
+
+eaccelerator.shm_size = "16"
+; The amount of shared memory (in megabytes) that eAccelerator will use.
+; "0" means OS default. Default value is "0".
+
+eaccelerator.cache_dir = "/tmp/eaccelerator"
+; The directory that is used for disk cache. eAccelerator stores precompiled
+; code, session data, content and user entries  here. The same data can be
+; stored in shared memory also (for more quick access). Default value is
+; "/tmp/eaccelerator".
+
+eaccelerator.enable = "1"
+; Enables or disables eAccelerator. Should be "1" for enabling or
+; "0" for disabling. Default value is "1".
+
+eaccelerator.optimizer = "1"
+; Enables or disables internal peephole optimizer which may speed up code
+; execution. Should be "1" for enabling or "0" for disabling.
+; Default value is "1".
+
+eaccelerator.debug = "0"
+; Enables or disables debug logging. Should be "1" for enabling or
+; "0" for disabling. Default value is "0".
+
+eaccelerator.check_mtime = "1"
+; Enables or disables PHP file modification checking. Should be "1"
+; for enabling or "0" for disabling. You should set it to "1" if you want
+; to recompile PHP files after modification. Default value is "1".
+
+eaccelerator.filter = ""
+; Determine which PHP files must be cached. You may specify the number of
+; patterns (for example "*.php *.phtml") which specifies to cache or
+; not to cache. If pattern starts with the character "!", it means to ignore
+; files which are matched by the following pattern. Default value is "" that
+; means - all PHP scripts will be cached.
+
+eaccelerator.shm_max = "0"
+; Disables putting large values into shared memory by "eaccelerator_put()"
+; function.
+; It indicates the largest allowed size in bytes (10240, 10K, 1M). The "0"
+; disables the limit. Default value is "0".
+
+eaccelerator.shm_ttl = "0"
+; When MMCache fails to get shared memory for new script it removes all
+; scripts which were not accessed at last "shm_ttl" seconds from shared
+; memory. Default value is "0" that means - don't remove any files from
+; shared memory.
+
+eaccelerator.shm_prune_period = "0"
+; When MMCache fails to get shared memory for new script it tryes to remove
+; old script if the previous try was made more then "shm_prune_period"
+; seconds ago. Default value is "0" that means - don't try to remove any
+; files from shared memory.
+
+eaccelerator.shm_only = "0"
+; Enables or disables caching of compiled scripts on disk. It has no effect
+; on session data and content caching.
+; Default value is "0" that means - use disk and shared memory for caching.
+
+eaccelerator.compress = "1"
+; Enables or disables cached content compression. Default value is "1" that
+; means enable compression.
+
+eaccelerator.compress_level = "9"
+; Compression level used for content caching.  Default value is "9" which i
+; is the maximum compression level
+
+eaccelerator.keys     = "shm_and_disk"
+eaccelerator.sessions = "shm_and_disk"
+eaccelerator.content  = "shm_and_disk"
+; Determine where keys, session data and content will be cached. The possible
+; values are:
+; "shm_and_disk" - cache data in shared memory and on disk (default value)
+; "shm"          - cache data in shared memory or on disk if shared memory
+;                  is full or data size greater then "eaccelerator.shm_max"
+; "shm_only"     - cache data in shared memory
+; "disk_only"    - cache data on disk
+; "none"         - don't cache data
Index: /eaccelerator/trunk/COPYING
===================================================================
--- /eaccelerator/trunk/COPYING	(revision 4)
+++ /eaccelerator/trunk/COPYING	(revision 4)
@@ -0,0 +1,502 @@
+		  GNU LESSER GENERAL PUBLIC LICENSE
+		       Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+     59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL.  It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it.  You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+  When we speak of free software, we are referring to freedom of use,
+not price.  Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+  To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights.  These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  To protect each distributor, we want to make it very clear that
+there is no warranty for the free library.  Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+  Finally, software patents pose a constant threat to the existence of
+any free program.  We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder.  Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+  Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License.  This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License.  We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+  When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library.  The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom.  The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+  We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License.  It also provides other free software developers Less
+of an advantage over competing non-free programs.  These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries.  However, the Lesser license provides advantages in certain
+special circumstances.
+
+  For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard.  To achieve this, non-free programs must be
+allowed to use the library.  A more frequent case is that a free
+library does the same job as widely used non-free libraries.  In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+  In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software.  For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+  Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+		  GNU LESSER GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+  6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Use a suitable shared library mechanism for linking with the
+    Library.  A suitable mechanism is one that (1) uses at run time a
+    copy of the library already present on the user's computer system,
+    rather than copying library functions into the executable, and (2)
+    will operate properly with a modified version of the library, if
+    the user installs one, as long as the modified version is
+    interface-compatible with the version that the work was made with.
+
+    c) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    d) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    e) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+			    NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+           How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
Index: /eaccelerator/trunk/eaccelerator.c
===================================================================
--- /eaccelerator/trunk/eaccelerator.c	(revision 4)
+++ /eaccelerator/trunk/eaccelerator.c	(revision 4)
@@ -0,0 +1,6720 @@
+/*
+   +----------------------------------------------------------------------+
+   | Turck MMCache for PHP Version 4                                      |
+   +----------------------------------------------------------------------+
+   | Copyright (c) 2002-2003 TurckSoft, St. Petersburg                    |
+   | http://www.turcksoft.com                                             |
+   +----------------------------------------------------------------------+
+   | This program is free software; you can redistribute it and/or        |
+   | modify it under the terms of the GNU General Public License          |
+   | as published by the Free Software Foundation; either version 2       |
+   | of the License, or (at your option) any later version.               |
+   |                                                                      |
+   | This program is distributed in the hope that it will be useful,      |
+   | but WITHOUT ANY WARRANTY; without even the implied warranty of       |
+   | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        |
+   | GNU General Public License for more details.                         |
+   |                                                                      |
+   | You should have received a copy of the GNU General Public License    |
+   | along with this program; if not, write to the Free Software          |
+   | Foundation, Inc., 59 Temple Place - Suite 330, Boston,               |
+   | MA  02111-1307, USA.                                                 |
+   |                                                                      |
+   | A copy is availble at http://www.gnu.org/copyleft/gpl.txt            |
+   +----------------------------------------------------------------------+
+   | Author: Dmitry Stogov <mmcache@turckware.ru>                         |
+   +----------------------------------------------------------------------+
+   $Id$
+*/
+
+#include "eaccelerator.h"
+#include "eaccelerator_version.h"
+
+#ifdef HAVE_EACCELERATOR
+
+#include "opcodes.h"
+
+#include "zend.h"
+#include "zend_API.h"
+#include "zend_extensions.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef ZEND_WIN32
+#  include "win32/time.h"
+#  include <time.h>
+#  include <sys/utime.h>
+#else
+#  include <sys/file.h>
+#  include <sys/time.h>
+#  include <utime.h>
+#endif
+#include <fcntl.h>
+
+#ifndef O_BINARY
+#  define O_BINARY 0
+#endif
+
+/*???
+#ifdef HAVE_SCHED_H
+#  include <sched.h>
+#endif
+*/
+
+#ifdef ZEND_WIN32
+#  include <process.h>
+#  ifndef S_ISREG
+#    define S_ISREG(mode) (((mode)&S_IFMT) & S_IFREG)
+#  endif
+#  ifndef S_IRUSR
+#    define S_IRUSR S_IREAD
+#  endif
+#  ifndef S_IWUSR
+#    define S_IWUSR S_IWRITE
+#  endif
+#else
+#  include <dirent.h>
+#endif
+
+#include "php.h"
+#include "php_ini.h"
+#include "php_logos.h"
+#include "main/fopen_wrappers.h"
+#include "ext/standard/info.h"
+#include "ext/standard/php_incomplete_class.h"
+#include "ext/standard/md5.h"
+
+#ifndef INCOMPLETE_CLASS
+#  define INCOMPLETE_CLASS "__PHP_Incomplete_Class"
+#endif
+#ifndef MAGIC_MEMBER
+#  define MAGIC_MEMBER "__PHP_Incomplete_Class_Name"
+#endif
+
+#include "SAPI.h"
+
+#undef HAVE_PHP_SESSIONS_SUPPORT
+#ifdef HAVE_EXT_SESSION_PHP_SESSION_H
+#  include "ext/session/php_session.h"
+#   ifdef PHP_SESSION_API
+#     if PHP_SESSION_API >= 20020306
+#       define HAVE_PHP_SESSIONS_SUPPORT
+static int eaccelerator_sessions_registered = 0;
+#       ifdef PS_CREATE_SID_ARGS
+#         include "ext/standard/php_lcg.h"
+#       endif
+#     endif
+#   endif
+#endif
+
+#define MAX_DUP_STR_LEN 256
+
+#define offsetof(str,fld) ((size_t)&(((str*)NULL)->fld))
+
+#ifdef EACCELERATOR_WITHOUT_FILE_LOCKING
+#  ifndef LOCK_SH
+#    define LOCK_SH 1
+#    define LOCK_EX 2
+#    define LOCK_UN 8
+#  endif
+#  define EACCELERATOR_FLOCK(FILE,OP)
+#else
+#  ifndef ZEND_WIN32
+#    ifdef HAVE_FLOCK
+#      define EACCELERATOR_FLOCK(FILE,OP) flock((FILE),(OP))
+#    else
+#      ifndef LOCK_SH
+#        define LOCK_SH 1
+#        define LOCK_EX 2
+#        define LOCK_UN 8
+#      endif
+#      define EACCELERATOR_FLOCK(FILE,OP)
+#    endif
+#  else
+#    define LOCK_SH 0
+#    define LOCK_EX 1
+#    define LOCK_UN 2
+#    define EACCELERATOR_FLOCK(FILE,OP) {OVERLAPPED offset = {0,0,0,0,NULL};\
+                                   if ((OP) == LOCK_EX) {\
+                                     LockFileEx((HANDLE)_get_osfhandle(FILE), \
+                                       LOCKFILE_EXCLUSIVE_LOCK, 0,\
+                                       1, 0, &offset);\
+                                   } else if ((OP) == LOCK_SH) {\
+                                     LockFileEx((HANDLE)_get_osfhandle(FILE), \
+                                       0, 0,\
+                                       1, 0, &offset);\
+                                   } else if ((OP) == LOCK_UN) {\
+                                     UnlockFileEx((HANDLE)_get_osfhandle(FILE), \
+                                       0,\
+                                       1, 0, &offset);\
+                                   }}
+#  endif
+#endif
+
+
+typedef struct _eaccelerator_op_array {
+  zend_uchar type;
+#ifdef ZEND_ENGINE_2
+  zend_bool uses_this;
+#else
+  zend_bool uses_globals;
+#endif
+  zend_bool return_reference;
+#ifdef ZEND_ENGINE_2
+  zend_uint num_args;
+  zend_arg_info *arg_info;
+  zend_bool pass_rest_by_reference;
+#else
+  zend_uchar *arg_types;
+#endif
+  char *function_name;
+#ifdef ZEND_ENGINE_2
+  char* scope_name;
+  int   scope_name_len;
+  zend_uint fn_flags;
+#endif
+  zend_op *opcodes;
+  zend_uint last;
+  zend_uint T;
+  zend_brk_cont_element *brk_cont_array;
+  zend_uint last_brk_cont;
+#ifdef ZEND_ENGINE_2
+	/* HOESH: try & catch support */
+	zend_try_catch_element* try_catch_array;
+	int last_try_catch;
+#endif
+  HashTable *static_variables;
+  char *filename;
+#ifdef ZEND_ENGINE_2
+  zend_uint line_start;
+  zend_uint line_end;
+  char *doc_comment;
+  zend_uint doc_comment_len;
+#endif
+} eaccelerator_op_array;
+
+typedef struct _eaccelerator_class_entry {
+  char type;
+  char *name;
+  uint name_length;
+  char *parent;
+  HashTable function_table;
+  HashTable default_properties;
+#ifdef ZEND_ENGINE_2
+  zend_uint ce_flags;
+  HashTable *static_members;
+  HashTable properties_info;
+  HashTable constants_table;
+  zend_uint num_interfaces;
+
+  char *filename;
+  zend_uint line_start;
+  zend_uint line_end;
+  char *doc_comment;
+  zend_uint doc_comment_len;
+#endif
+} eaccelerator_class_entry;
+
+/*
+ * To cache functions and classes.
+ */
+typedef struct _mm_fc_entry {
+  void   *fc;
+  struct _mm_fc_entry *next;
+  int    htablen;
+  char   htabkey[1];         /* must be last element */
+} mm_fc_entry;
+
+/*
+ * A mm_cache_entry is a bucket for one PHP script file.
+ * Nested  functions and classes which defined in the file goes
+ * into the list of mm_fc_entry.
+ */
+typedef struct _mm_cache_entry {
+  struct _mm_cache_entry *next;
+#ifdef EACCELERATOR_USE_INODE
+  dev_t                  st_dev;         /* file's device                     */
+  ino_t                  st_ino;         /* file's inode                      */
+#else
+  unsigned int           hv;             /* hash value                        */
+#endif
+  off_t                  filesize;       /* file size */
+  time_t                 mtime;          /* file last modification time       */
+  time_t                 ttl;            /* expiration time                   */
+  int                    size;           /* entry size (bytes)                */
+  int                    nhits;          /* hits count                        */
+  int                    nreloads;       /* count of reloads                  */
+  int                    use_cnt;        /* how many processes uses the entry */
+  eaccelerator_op_array       *op_array;      /* script's global scope code        */
+  mm_fc_entry            *f_head;        /* list of nested functions          */
+  mm_fc_entry            *c_head;        /* list of nested classes            */
+  zend_bool              removed;        /* the entry is scheduled to remove  */
+  char                   realfilename[1];/* real file name (must be last el.) */
+} mm_cache_entry;
+
+/*
+ * bucket for user's cache
+ */
+typedef struct _mm_user_cache_entry {
+  struct _mm_user_cache_entry *next;
+  unsigned int           hv;            /* hash value                  */
+  long                   ttl;           /* expiration time             */
+  int                    size;
+  zval                   value;         /* value                       */
+  char                   key[1];        /* key value (must be last el) */
+} mm_user_cache_entry;
+
+/*
+ * Linked list of mm_cache_entry which are used by process/thread
+ */
+typedef struct _mm_used_entry {
+  struct _mm_used_entry *next;
+  mm_cache_entry        *entry;
+} mm_used_entry;
+
+/*
+ * Linked list of locks
+ */
+typedef struct _mm_lock_entry {
+  struct _mm_lock_entry *next;
+  pid_t  pid;
+#ifdef ZTS
+  THREAD_T thread;
+#endif
+  char                  key[1];
+} mm_lock_entry;
+
+typedef struct _mm_file_header {
+  char   magic[8];        /* "EACCELERATOR" */
+  int    eaccelerator_version;
+  int    zend_version;
+  int    php_version;
+  int    size;
+  time_t mtime;
+  unsigned int crc32;
+} mm_file_header;
+
+#ifdef ZTS
+#  define ZTS_LOCK()    tsrm_mutex_lock(mm_mutex)
+#  define ZTS_UNLOCK()  tsrm_mutex_unlock(mm_mutex)
+#else
+#  define ZTS_LOCK()
+#  define ZTS_UNLOCK()
+#endif
+
+#include "mm.h"
+
+#if defined(EACCELERATOR_PROTECT_SHM)
+#  define EACCELERATOR_PROTECT()    do {mm_protect(eaccelerator_mm_instance->mm, MM_PROT_READ);} while(0)
+#  define EACCELERATOR_UNPROTECT()  do {mm_protect(eaccelerator_mm_instance->mm, MM_PROT_READ|MM_PROT_WRITE);} while(0)
+#else
+#  define EACCELERATOR_PROTECT()
+#  define EACCELERATOR_UNPROTECT()
+#endif
+
+#define EACCELERATOR_LOCK_RW()    do {ZTS_LOCK(); mm_lock(eaccelerator_mm_instance->mm, MM_LOCK_RW);} while(0)
+#define EACCELERATOR_LOCK_RD()    do {ZTS_LOCK(); mm_lock(eaccelerator_mm_instance->mm, MM_LOCK_RD);} while(0)
+#define EACCELERATOR_UNLOCK()     do {mm_unlock(eaccelerator_mm_instance->mm); ZTS_UNLOCK();} while(0)
+#define EACCELERATOR_UNLOCK_RW()  EACCELERATOR_UNLOCK()
+#define EACCELERATOR_UNLOCK_RD()  EACCELERATOR_UNLOCK()
+
+#define EACCELERATOR_BLOCK_INTERRUPTIONS()   HANDLE_BLOCK_INTERRUPTIONS()
+#define EACCELERATOR_UNBLOCK_INTERRUPTIONS() HANDLE_UNBLOCK_INTERRUPTIONS()
+
+#define MM_HASH_SIZE      256
+#define MM_USER_HASH_SIZE 256
+#define MM_HASH_MAX       (MM_HASH_SIZE-1)
+#define MM_USER_HASH_MAX  (MM_USER_HASH_SIZE-1)
+
+#define eaccelerator_malloc(size)        mm_malloc(eaccelerator_mm_instance->mm, size)
+#define eaccelerator_free(x)             mm_free(eaccelerator_mm_instance->mm, x)
+#define eaccelerator_malloc_nolock(size) mm_malloc_nolock(eaccelerator_mm_instance->mm, size)
+#define eaccelerator_free_nolock(x)      mm_free_nolock(eaccelerator_mm_instance->mm, x)
+
+typedef struct {
+  MM             *mm;
+  pid_t          owner;
+  size_t         total;
+  unsigned int   hash_cnt;
+  unsigned int   user_hash_cnt;
+  zend_bool      enabled;
+  zend_bool      optimizer_enabled;
+  unsigned int   rem_cnt;
+  time_t         last_prune;
+  mm_cache_entry *removed;
+  mm_lock_entry  *locks;
+
+  mm_cache_entry      *hash[MM_HASH_SIZE];
+  mm_user_cache_entry *user_hash[MM_USER_HASH_SIZE];
+} eaccelerator_mm;
+
+/*
+ * Globals (different for each process/thread)
+ */
+ZEND_DECLARE_MODULE_GLOBALS(eaccelerator)
+
+/*
+ * Globals (common for each process/thread)
+ */
+static long eaccelerator_shm_size = 0;
+static long eaccelerator_shm_max = 0;
+static long eaccelerator_shm_ttl = 0;
+static long eaccelerator_shm_prune_period = 0;
+static long eaccelerator_debug = 0;
+static zend_bool eaccelerator_check_mtime = 1;
+static zend_bool eaccelerator_scripts_shm_only = 0;
+static eaccelerator_cache_place eaccelerator_keys_cache_place     = eaccelerator_shm_and_disk;
+static eaccelerator_cache_place eaccelerator_sessions_cache_place = eaccelerator_shm_and_disk;
+       eaccelerator_cache_place eaccelerator_content_cache_place  = eaccelerator_shm_and_disk;
+
+static eaccelerator_mm* eaccelerator_mm_instance = NULL;
+static int eaccelerator_is_zend_extension = 0;
+static int eaccelerator_is_extension      = 0;
+static zend_extension* ZendOptimizer = NULL;
+#ifdef ZTS
+static MUTEX_T mm_mutex;
+#endif
+
+static HashTable eaccelerator_global_function_table;
+static HashTable eaccelerator_global_class_table;
+
+static int binary_eaccelerator_version;
+static int binary_php_version;
+static int binary_zend_version;
+
+/* saved original functions */
+static zend_op_array *(*mm_saved_zend_compile_file)(zend_file_handle *file_handle, int type TSRMLS_DC);
+
+#if defined(PROFILE_OPCODES) || defined(WITH_EACCELERATOR_EXECUTOR)
+static void (*mm_saved_zend_execute)(zend_op_array *op_array TSRMLS_DC);
+#endif
+
+/* external declarations */
+PHPAPI void php_stripslashes(char *str, int *len TSRMLS_DC);
+PHPAPI char *php_get_uname();
+
+ZEND_DLEXPORT zend_op_array* eaccelerator_compile_file(zend_file_handle *file_handle, int type TSRMLS_DC);
+
+
+#if defined(DEBUG) || defined(TEST_PERFORMANCE)  || defined(PROFILE_OPCODES)
+#include <ctype.h>
+#include <stdio.h>
+static FILE *F_fp;
+
+static void pad(TSRMLS_D) {
+  int i = MMCG(xpad);
+  while (i-- > 0) {
+    fputc('\t', F_fp);
+  }
+}
+
+static void start_time(struct timeval *tvstart) {
+  gettimeofday(tvstart, NULL);
+}
+
+static long elapsed_time(struct timeval *tvstart) {
+  struct timeval tvend;
+  int sec, usec;
+  gettimeofday(&tvend, NULL);
+  sec = tvend.tv_sec - tvstart->tv_sec;
+  usec = tvend.tv_usec - tvstart->tv_usec;
+  return sec * 1000000 + usec;
+}
+#endif  /* #if defined(DEBUG) || defined(TEST_PERFORMANCE)  || defined(PROFILE_OPCODES) */
+
+static inline unsigned int hash_mm(const char *data, int len) {
+  unsigned int h;
+  const char *e = data + len;
+  for (h = 2166136261U; data < e; ) {
+    h *= 16777619;
+    h ^= *data++;
+  }
+  return h;
+}
+
+static mm_cache_entry* hash_find_mm(const char  *key,
+                                    struct stat *buf,
+                                    int         *nreloads,
+                                    time_t      ttl) {
+  unsigned int hv, slot;
+  mm_cache_entry *p, *q;
+
+#ifdef EACCELERATOR_USE_INODE
+  hv = buf->st_dev + buf->st_ino;
+#else
+  hv = hash_mm(key, strlen(key));
+#endif
+  slot = hv & MM_HASH_MAX;
+
+  EACCELERATOR_LOCK_RW();
+  q = NULL;
+  p = eaccelerator_mm_instance->hash[slot];
+  while (p != NULL) {
+#ifdef EACCELERATOR_USE_INODE
+    if (p->st_dev == buf->st_dev && p->st_ino == buf->st_ino) {
+      struct stat buf2;
+      if ((eaccelerator_check_mtime &&
+          (buf->st_mtime != p->mtime || buf->st_size != p->filesize)) ||
+          (strcmp(p->realfilename, key) != 0 &&
+           (stat(p->realfilename,&buf2) != 0 ||
+           buf2.st_dev != buf->st_dev ||
+           buf2.st_ino != buf->st_ino))) {
+#else
+    if ((p->hv == hv) && (strcmp(p->realfilename, key) == 0)) {
+      if (eaccelerator_check_mtime &&
+          (buf->st_mtime != p->mtime || buf->st_size != p->filesize)) {
+#endif
+        /* key is invalid. Remove it. */
+        *nreloads = p->nreloads+1;
+        if (q == NULL) {
+          eaccelerator_mm_instance->hash[slot] = p->next;
+        } else {
+          q->next = p->next;
+        }
+        eaccelerator_mm_instance->hash_cnt--;
+        if (p->use_cnt > 0) {
+          /* key is used by other process/thred. Shedule it to remove */
+          p->removed = 1;
+          p->next = eaccelerator_mm_instance->removed;
+          eaccelerator_mm_instance->removed = p;
+          eaccelerator_mm_instance->rem_cnt++;
+          EACCELERATOR_UNLOCK_RW();
+          return NULL;
+        } else {
+          /* key is unused. Remove it. */
+          eaccelerator_free_nolock(p);
+          EACCELERATOR_UNLOCK_RW();
+          return NULL;
+        }
+      } else {
+        /* key is valid */
+        p->nhits++;
+        p->use_cnt++;
+        p->ttl = ttl;
+        EACCELERATOR_UNLOCK_RW();
+        return p;
+      }
+    }
+    q = p;
+    p = p->next;
+  }
+  EACCELERATOR_UNLOCK_RW();
+  return NULL;
+}
+
+static void hash_add_mm(mm_cache_entry *x) {
+  mm_cache_entry *p,*q;
+  unsigned int slot;
+#ifdef EACCELERATOR_USE_INODE
+  slot = (x->st_dev + x->st_ino) & MM_HASH_MAX;
+#else
+  x->hv = hash_mm(x->realfilename, strlen(x->realfilename));
+  slot = x->hv & MM_HASH_MAX;
+#endif
+
+  EACCELERATOR_LOCK_RW();
+  x->next = eaccelerator_mm_instance->hash[slot];
+  eaccelerator_mm_instance->hash[slot] = x;
+  eaccelerator_mm_instance->hash_cnt++;
+  q = x;
+  p = x->next;
+  while (p != NULL) {
+#ifdef EACCELERATOR_USE_INODE
+    if ((p->st_dev == x->st_dev) && (p->st_ino == x->st_ino)) {
+#else
+    if ((p->hv == x->hv) &&
+        (strcmp(p->realfilename, x->realfilename) == 0)) {
+#endif
+      q->next = p->next;
+      eaccelerator_mm_instance->hash_cnt--;
+      eaccelerator_mm_instance->hash[slot]->nreloads += p->nreloads;
+      if (p->use_cnt > 0) {
+        /* key is used by other process/thred. Shedule it to remove */
+        p->removed = 1;
+        p->next = eaccelerator_mm_instance->removed;
+        eaccelerator_mm_instance->removed = p;
+        eaccelerator_mm_instance->rem_cnt++;
+        EACCELERATOR_UNLOCK_RW();
+        return;
+      } else {
+        /* key is unused. Remove it. */
+        eaccelerator_free_nolock(p);
+        EACCELERATOR_UNLOCK_RW();
+        return;
+      }
+    }
+    q = p;
+    p = p->next;
+  }
+  EACCELERATOR_UNLOCK_RW();
+}
+
+static int init_mm(TSRMLS_D) {
+  pid_t  owner = getpid();
+  MM     *mm;
+  size_t total;
+  char   mm_path[MAXPATHLEN];
+
+/*  if (getppid() != 1) return SUCCESS; */ /*???*/
+#ifdef ZEND_WIN32
+    snprintf(mm_path, MAXPATHLEN, "%s.%s", EACCELERATOR_MM_FILE, sapi_module.name);
+#else
+    snprintf(mm_path, MAXPATHLEN, "%s.%s%d", EACCELERATOR_MM_FILE, sapi_module.name, getpid());
+#endif
+/*  snprintf(mm_path, MAXPATHLEN, "%s.%s%d", EACCELERATOR_MM_FILE, sapi_module.name, geteuid());*/
+  if ((eaccelerator_mm_instance = (eaccelerator_mm*)mm_attach(eaccelerator_shm_size*1024*1024, mm_path)) != NULL) {
+#ifdef ZTS
+    mm_mutex = tsrm_mutex_alloc();
+#endif
+    return SUCCESS;
+  }
+  mm = mm_create(eaccelerator_shm_size*1024*1024, mm_path);
+  if (!mm) {
+    return FAILURE;
+  }
+#ifdef DEBUG
+#ifdef ZEND_WIN32
+  fprintf(F_fp, "init_mm [%d]\n", getpid());
+#else
+  fprintf(F_fp, "init_mm [%d,%d]\n", getpid(), getppid());
+#endif
+  fflush(F_fp);
+#endif
+#ifdef ZTS
+  mm_mutex = tsrm_mutex_alloc();
+#endif
+  total = mm_available(mm);
+  eaccelerator_mm_instance = mm_malloc(mm, sizeof(*eaccelerator_mm_instance));
+  if (!eaccelerator_mm_instance) {
+    return FAILURE;
+  }
+  mm_set_attach(mm, eaccelerator_mm_instance);
+  memset(eaccelerator_mm_instance, 0, sizeof(*eaccelerator_mm_instance));
+  eaccelerator_mm_instance->owner = owner;
+  eaccelerator_mm_instance->mm    = mm;
+  eaccelerator_mm_instance->total = total;
+  eaccelerator_mm_instance->hash_cnt = 0;
+  eaccelerator_mm_instance->rem_cnt  = 0;
+  eaccelerator_mm_instance->enabled = 1;
+  eaccelerator_mm_instance->optimizer_enabled = 1;
+  eaccelerator_mm_instance->removed = NULL;
+  eaccelerator_mm_instance->locks = NULL;
+  eaccelerator_mm_instance->user_hash_cnt = 0;
+  eaccelerator_mm_instance->last_prune = time(0);
+  EACCELERATOR_PROTECT();
+  return SUCCESS;
+}
+
+static void shutdown_mm(TSRMLS_D) {
+  if (eaccelerator_mm_instance) {
+#ifdef ZEND_WIN32
+    if (eaccelerator_mm_instance->owner == getpid()) {
+#else
+    if (getpgrp() == getpid()) {
+#endif
+      MM *mm = eaccelerator_mm_instance->mm;
+#ifdef DEBUG
+#ifdef ZEND_WIN32
+      fprintf(F_fp, "shutdown_mm [%d]\n", getpid());
+#else
+      fprintf(F_fp, "shutdown_mm [%d,%d]\n", getpid(), getppid());
+#endif
+      fflush(F_fp);
+#endif
+#ifdef ZTS
+      tsrm_mutex_free(mm_mutex);
+#endif
+      if (mm) {
+        mm_destroy(mm);
+      }
+      eaccelerator_mm_instance = NULL;
+    }
+  }
+}
+
+static void debug_printf(char *format, ...) {
+  char output_buf[512];
+  va_list args;
+
+  va_start(args, format);
+  vsnprintf(output_buf, sizeof(output_buf), format, args);
+  va_end(args);
+
+#ifdef ZEND_WIN32
+  OutputDebugString(output_buf);
+/*  zend_printf("EACCELERATOR: %s<br>\n",output_buf);*/
+#else
+  fputs(output_buf, stderr);
+#endif
+}
+
+/******************************************************************************/
+
+#define FIXUP(x) if((x)!=NULL) {(x) = (void*)(((char*)(x)) + ((long)(MMCG(mem))));}
+
+static void fixup_zval(zval* z TSRMLS_DC);
+
+typedef void (*fixup_bucket_t)(void* TSRMLS_DC);
+
+#define fixup_zval_hash(from) \
+  fixup_hash(from, (fixup_bucket_t)fixup_zval TSRMLS_CC)
+
+#ifdef ZEND_ENGINE_2
+static void fixup_property_info(zend_property_info* from TSRMLS_DC) {
+  FIXUP(from->name);
+}
+#endif
+
+static void fixup_hash(HashTable* source, fixup_bucket_t fixup_bucket TSRMLS_DC) {
+  unsigned int i;
+  Bucket *p;
+
+  if (source->nNumOfElements > 0) {
+    if (!MMCG(compress)) {
+      if (source->arBuckets != NULL) {
+        FIXUP(source->arBuckets);
+        for (i = 0; i < source->nTableSize; i++) {
+          FIXUP(source->arBuckets[i]);
+        }
+      }
+    }
+    FIXUP(source->pListHead);
+    FIXUP(source->pListTail);
+
+    p = source->pListHead;
+    while (p) {
+      FIXUP(p->pNext);
+      FIXUP(p->pLast);
+      FIXUP(p->pData);
+      FIXUP(p->pDataPtr);
+      FIXUP(p->pListLast);
+      FIXUP(p->pListNext);
+      if (p->pDataPtr) {
+        fixup_bucket(p->pDataPtr TSRMLS_CC);
+        p->pData = &p->pDataPtr;
+      } else {
+        fixup_bucket(p->pData TSRMLS_CC);
+      }
+      p = p->pListNext;
+    }
+    source->pInternalPointer = source->pListHead;
+  }
+}
+
+static void fixup_zval(zval* zv TSRMLS_DC) {
+  switch (zv->type) {
+    case IS_CONSTANT:
+    case IS_STRING:
+      if (zv->value.str.val == NULL ||
+         zv->value.str.len == 0) {
+        zv->value.str.val = empty_string;
+        zv->value.str.len = 0;
+      } else {
+        FIXUP(zv->value.str.val);
+      }
+      break;
+    case IS_ARRAY:
+    case IS_CONSTANT_ARRAY:
+      if (zv->value.ht == NULL || zv->value.ht == &EG(symbol_table)) {
+      } else {
+        FIXUP(zv->value.ht);
+        fixup_zval_hash(zv->value.ht);
+      }
+      break;
+    case IS_OBJECT:
+      if (!MMCG(compress)) {
+        return;
+      }
+#ifndef ZEND_ENGINE_2
+      FIXUP(zv->value.obj.ce);
+      if (zv->value.obj.properties != NULL) {
+        FIXUP(zv->value.obj.properties);
+        fixup_zval_hash(zv->value.obj.properties);
+      }
+#endif
+    default:
+      break;
+  }
+}
+
+static void fixup_op_array(eaccelerator_op_array* from TSRMLS_DC) {
+  zend_op *opline;
+  zend_op *end;
+
+#ifdef ZEND_ENGINE_2
+  if (from->num_args > 0) {
+    zend_uint i;
+    FIXUP(from->arg_info);
+    for (i = 0; i < from->num_args; i++) {
+      FIXUP(from->arg_info[i].name);
+      FIXUP(from->arg_info[i].class_name);
+    }
+  }
+#else
+  FIXUP(from->arg_types);
+#endif
+  FIXUP(from->function_name);
+#ifdef ZEND_ENGINE_2
+  FIXUP(from->scope_name);
+#endif
+  if (from->type == ZEND_INTERNAL_FUNCTION) {
+    return;
+  }
+
+  if (from->opcodes != NULL) {
+    FIXUP(from->opcodes);
+
+    opline = from->opcodes;
+    end = opline + from->last;
+    MMCG(compress) = 0;
+    for (;opline < end; opline++) {
+/*
+      if (opline->result.op_type == IS_CONST) fixup_zval(&opline->result.u.constant  TSRMLS_CC);
+*/
+      if (opline->op1.op_type    == IS_CONST) fixup_zval(&opline->op1.u.constant TSRMLS_CC);
+      if (opline->op2.op_type    == IS_CONST) fixup_zval(&opline->op2.u.constant TSRMLS_CC);
+#ifdef ZEND_ENGINE_2
+      switch (opline->opcode) {
+        case ZEND_JMP:
+          FIXUP(opline->op1.u.jmp_addr);
+          break;
+        case ZEND_JMPZ:
+        case ZEND_JMPNZ:
+        case ZEND_JMPZ_EX:
+        case ZEND_JMPNZ_EX:
+          FIXUP(opline->op2.u.jmp_addr);
+          break;
+      }
+      opline->handler = get_opcode_handler(opline->opcode TSRMLS_CC);
+#endif
+    }
+    MMCG(compress) = 1;
+  }
+  FIXUP(from->brk_cont_array);
+#ifdef ZEND_ENGINE_2
+	/* HOESH: try & catch support */
+	FIXUP(from->try_catch_array);
+#endif
+  if (from->static_variables != NULL) {
+    FIXUP(from->static_variables);
+    fixup_zval_hash(from->static_variables);
+  }
+  FIXUP(from->filename);
+#ifdef ZEND_ENGINE_2
+  FIXUP(from->doc_comment);
+#endif
+}
+
+static void fixup_class_entry(eaccelerator_class_entry* from TSRMLS_DC) {
+  FIXUP(from->name);
+  FIXUP(from->parent);
+#ifdef ZEND_ENGINE_2
+  FIXUP(from->filename);
+  FIXUP(from->doc_comment);
+  fixup_zval_hash(&from->constants_table);
+  fixup_zval_hash(&from->default_properties);
+  fixup_hash(&from->properties_info, (fixup_bucket_t)fixup_property_info TSRMLS_CC);
+  if (from->static_members != NULL) {
+    FIXUP(from->static_members);
+    fixup_zval_hash(from->static_members);
+  }
+#else
+  fixup_zval_hash(&from->default_properties);
+#endif
+  fixup_hash(&from->function_table, (fixup_bucket_t)fixup_op_array TSRMLS_CC);
+}
+
+static void eaccelerator_fixup(mm_cache_entry *p TSRMLS_DC) {
+  mm_fc_entry* q;
+
+  MMCG(mem) = (char*)((long)p - (long)p->next);
+  MMCG(compress) = 1;
+  p->next        = NULL;
+  FIXUP(p->op_array);
+  FIXUP(p->f_head);
+  FIXUP(p->c_head);
+  fixup_op_array(p->op_array TSRMLS_CC);
+  q = p->f_head;
+  while (q != NULL) {
+    FIXUP(q->fc);
+    fixup_op_array((eaccelerator_op_array*)q->fc TSRMLS_CC);
+    FIXUP(q->next);
+    q = q->next;
+  }
+  q = p->c_head;
+  while (q != NULL) {
+    FIXUP(q->fc);
+    fixup_class_entry((eaccelerator_class_entry*)q->fc TSRMLS_CC);
+    FIXUP(q->next);
+    q = q->next;
+  }
+}
+
+/******************************************************************************/
+
+static int encode_version(const char *s) {
+  unsigned int v1 = 0;
+  unsigned int v2 = 0;
+  unsigned int v3 = 0;
+  unsigned int c;
+  char m = '.';
+  sscanf(s, "%u.%u%c%u",&v1,&v2,&m,&v3);
+  switch (m) {
+    case  'a': c = 0; break;
+    case  'b': c = 1; break;
+    case  '.': c = 2; break;
+    case  's': c = 15; break;
+    default: c = 2;
+  }
+  return ((v1 & 0xf) << 20) |
+         ((v2 & 0xff) << 12) |
+         ((c & 0xf) << 8) |
+         (v3 & 0xff);
+}
+
+static void decode_version(char *version, int v) {
+  int t = (v & 0x000f00) >> 8;
+  char c;
+  switch (t) {
+    case  0: c = 'a'; break;
+    case  1: c = 'b'; break;
+    case  2: c = '.'; break;
+    case 15: c = 's'; break;
+    default: c = '.';
+  }
+  snprintf(version, 16, "%d.%d%c%d", (v & 0xf00000) >> 20,
+                                     (v & 0x0ff000) >> 12,
+                                     c,
+                                     (v & 0x0000ff));
+}
+
+#ifdef EACCELERATOR_USE_INODE
+static int eaccelerator_inode_key(char* s, dev_t dev, ino_t ino TSRMLS_DC) {
+  int n;
+  strncpy(s, MMCG(cache_dir), MAXPATHLEN-1);
+  strlcat(s, "/eaccelerator-", MAXPATHLEN-1);
+  n = strlen(s);
+  while (dev > 0) {
+    if (n >= MAXPATHLEN) return 0;
+    s[n++] = (dev % 10) +'0';
+    dev /= 10;
+  }
+  if (n >= MAXPATHLEN) return 0;
+  s[n++] = '.';
+  while (ino > 0) {
+    if (n >= MAXPATHLEN) return 0;
+    s[n++] = (ino % 10) +'0';
+    ino /= 10;
+  }
+  if (n >= MAXPATHLEN) return 0;
+  s[n++] = '\000';
+  return 1;
+}
+#endif
+
+static int eaccelerator_md5(char* s, const char* prefix, const char* key TSRMLS_DC) {
+#if defined(PHP_MAJOR_VERSION) && defined(PHP_MINOR_VERSION) && \
+    ((PHP_MAJOR_VERSION > 4) || (PHP_MAJOR_VERSION == 4 && PHP_MINOR_VERSION > 1))
+  char md5str[33];
+  PHP_MD5_CTX context;
+  unsigned char digest[16];
+
+  md5str[0] = '\0';
+  PHP_MD5Init(&context);
+  PHP_MD5Update(&context, key, strlen(key));
+  PHP_MD5Final(digest, &context);
+  make_digest(md5str, digest);
+  snprintf(s, MAXPATHLEN-1, "%s%s%s", MMCG(cache_dir), prefix, md5str);
+  return 1;
+#else
+  zval retval;
+  zval md5;
+  zval param;
+  zval *params[1];
+
+  ZVAL_STRING(&md5, "md5", 0);
+  INIT_ZVAL(param);
+  params[0] = &param;
+  ZVAL_STRING(params[0], (char*)key, 0);
+  if (call_user_function(CG(function_table), (zval**)NULL, &md5, &retval, 1, params TSRMLS_CC) == SUCCESS &&
+      retval.type == IS_STRING &&
+      retval.value.str.len == 32) {
+    strncpy(s, MMCG(cache_dir), MAXPATHLEN-1);
+    strlcat(s, prefix, MAXPATHLEN);
+    strlcat(s, retval.value.str.val, MAXPATHLEN);
+    zval_dtor(&retval);
+    return 1;
+  }
+  s[0] ='\0';
+#endif
+  return 0;
+}
+
+static void eaccelerator_prune(time_t t) {
+  unsigned int i;
+
+  EACCELERATOR_LOCK_RW();
+  eaccelerator_mm_instance->last_prune = t;
+  for (i = 0; i < MM_HASH_SIZE; i++) {
+    mm_cache_entry **p = &eaccelerator_mm_instance->hash[i];
+    while (*p != NULL) {
+      struct stat buf;
+      if (((*p)->ttl != 0 && (*p)->ttl < t && (*p)->use_cnt <= 0) ||
+          stat((*p)->realfilename,&buf) != 0 ||
+#ifdef EACCELERATOR_USE_INODE
+          (*p)->st_dev != buf.st_dev ||
+          (*p)->st_ino != buf.st_ino ||
+#endif
+          (*p)->mtime != buf.st_mtime ||
+          (*p)->filesize != buf.st_size) {
+        mm_cache_entry *r = *p;
+        *p = (*p)->next;
+        eaccelerator_mm_instance->hash_cnt--;
+        eaccelerator_free_nolock(r);
+      } else {
+        p = &(*p)->next;
+      }
+    }
+  }
+  EACCELERATOR_UNLOCK_RW();
+}
+
+static void* eaccelerator_malloc2(size_t size TSRMLS_DC) {
+  void *p = NULL;
+  time_t t;
+
+  if (eaccelerator_gc(TSRMLS_C) > 0) {
+    p = eaccelerator_malloc(size);
+    if (p != NULL) {
+      return p;
+    }
+  }
+  if (eaccelerator_shm_prune_period > 0) {
+    t = time(0);
+    if (t - eaccelerator_mm_instance->last_prune > eaccelerator_shm_prune_period) {
+      eaccelerator_prune(t);
+      p = eaccelerator_malloc(size);
+    }
+  }
+  return p;
+}
+
+#define EACCELERATOR_CRC32(crc, ch)   (crc = (crc >> 8) ^ crc32tab[(crc ^ (ch)) & 0xff])
+
+static const unsigned int crc32tab[256] = {
+  0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
+  0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
+  0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
+  0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
+  0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
+  0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
+  0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
+  0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
+  0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
+  0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
+  0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
+  0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
+  0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
+  0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
+  0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+  0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
+  0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
+  0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
+  0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
+  0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
+  0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
+  0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
+  0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
+  0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
+  0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
+  0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
+  0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
+  0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
+  0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
+  0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+  0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
+  0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
+  0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
+  0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
+  0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
+  0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
+  0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
+  0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
+  0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
+  0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
+  0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
+  0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
+  0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
+  0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
+  0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+  0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
+  0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
+  0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
+  0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
+  0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
+  0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
+  0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
+  0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
+  0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
+  0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
+  0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
+  0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
+  0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
+  0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
+  0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+  0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
+  0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
+  0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
+  0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
+};
+
+unsigned int eaccelerator_crc32(const char *p, size_t n) {
+  unsigned int crc = ~0;
+  for (; n--; ++p) {
+    EACCELERATOR_CRC32(crc, *p);
+  }
+  return ~crc;
+}
+
+static mm_cache_entry* hash_find_file(const char  *key,
+                                      struct stat *buf TSRMLS_DC) {
+  int f;
+  char s[MAXPATHLEN];
+  mm_file_header hdr;
+  mm_cache_entry *p;
+  int use_shm = 1;
+
+#ifdef EACCELERATOR_USE_INODE
+  struct stat buf2;
+
+  if (!eaccelerator_inode_key(s, buf->st_dev, buf->st_ino TSRMLS_CC)) {
+    return NULL;
+  }
+#else
+  if (!eaccelerator_md5(s, "/eaccelerator-", key TSRMLS_CC)) {
+    return NULL;
+  }
+#endif
+
+  if ((f = open(s, O_RDONLY | O_BINARY)) > 0) {
+    EACCELERATOR_FLOCK(f, LOCK_SH);
+    if (read(f, &hdr, sizeof(hdr)) != sizeof(hdr)) {
+      EACCELERATOR_FLOCK(f, LOCK_UN);
+      close(f);
+      return NULL;
+    }
+    if (strncmp(hdr.magic,"EACCELERATOR",8) != 0 ||
+        hdr.eaccelerator_version != binary_eaccelerator_version ||
+        hdr.zend_version != binary_zend_version ||
+        hdr.php_version != binary_php_version) {
+      EACCELERATOR_FLOCK(f, LOCK_UN);
+      close(f);
+      unlink(s);
+      return NULL;
+    }
+    p = eaccelerator_malloc(hdr.size);
+    if (p == NULL) {
+      p = eaccelerator_malloc2(hdr.size TSRMLS_CC);
+    }
+    if (p == NULL) {
+      p = emalloc(hdr.size);
+      use_shm = 0;
+    }
+    if (p == NULL) {
+      EACCELERATOR_FLOCK(f, LOCK_UN);
+      close(f);
+      return NULL;
+    }
+    if (read(f, p, hdr.size) != hdr.size ||
+        p->size != hdr.size ||
+        hdr.crc32 != eaccelerator_crc32((const char*)p,p->size)) {
+      EACCELERATOR_FLOCK(f, LOCK_UN);
+      close(f);
+      unlink(s);
+      if (use_shm) eaccelerator_free(p); else efree(p);
+      return NULL;
+    }
+    EACCELERATOR_FLOCK(f, LOCK_UN);
+    close(f);
+#ifdef EACCELERATOR_USE_INODE
+    if (p->st_dev != buf->st_dev || p->st_ino != buf->st_ino) {
+#else
+    if (strcmp(key,p->realfilename) != 0) {
+#endif
+      if (use_shm) eaccelerator_free(p); else efree(p);
+      return NULL;
+    }
+    if ((eaccelerator_check_mtime &&
+        (buf->st_mtime != p->mtime || buf->st_size != p->filesize))
+#ifdef EACCELERATOR_USE_INODE
+        ||
+        (strcmp(p->realfilename, key) != 0 &&
+         (stat(p->realfilename,&buf2) != 0 ||
+         buf2.st_dev != buf->st_dev ||
+         buf2.st_ino != buf->st_ino))
+#endif
+       ) {
+      /* key is invalid. Remove it. */
+      if (use_shm) eaccelerator_free(p); else efree(p);
+      unlink(s);
+      return NULL;
+    }
+    eaccelerator_fixup(p TSRMLS_CC);
+    if (use_shm) {
+      p->nhits    = 1;
+      p->nreloads = 1;
+      p->use_cnt  = 1;
+      p->removed  = 0;
+      if (eaccelerator_shm_ttl > 0) {
+        p->ttl = time(0) + eaccelerator_shm_ttl;
+      } else {
+        p->ttl = 0;
+      }
+      hash_add_mm(p);
+    } else {
+      p->use_cnt  = 0;
+      p->removed  = 1;
+    }
+    return p;
+  }
+  return NULL;
+}
+
+static int hash_add_file(mm_cache_entry *p TSRMLS_DC) {
+  int f;
+  int ret = 0;
+  char s[MAXPATHLEN];
+  mm_file_header hdr;
+
+#ifdef EACCELERATOR_USE_INODE
+  if (!eaccelerator_inode_key(s, p->st_dev, p->st_ino TSRMLS_CC)) {
+    return 0;
+  }
+#else
+  if (!eaccelerator_md5(s, "/eaccelerator-", p->realfilename TSRMLS_CC)) {
+    return 0;
+  }
+#endif
+
+  unlink(s);
+  f = open(s, O_CREAT | O_WRONLY | O_EXCL | O_BINARY, S_IRUSR | S_IWUSR);
+  if (f > 0) {
+    EACCELERATOR_FLOCK(f, LOCK_EX);
+    strcpy(hdr.magic,"EACCELERATOR");
+    hdr.eaccelerator_version = binary_eaccelerator_version;
+    hdr.zend_version    = binary_zend_version;
+    hdr.php_version     = binary_php_version;
+    hdr.size  = p->size;
+    hdr.mtime = p->mtime;
+    p->next = p;
+    hdr.crc32 = eaccelerator_crc32((const char*)p,p->size);
+    ret = (write(f, &hdr, sizeof(hdr)) == sizeof(hdr));
+    if (ret) ret = (write(f, p, p->size) == p->size);
+    EACCELERATOR_FLOCK(f, LOCK_UN);
+    close(f);
+  }
+  return ret;
+}
+
+typedef union align_union {
+  double d;
+  void *v;
+  int (*func)(int);
+  long l;
+} align_union;
+
+#if (defined (__GNUC__) && __GNUC__ >= 2)
+#define EACCELERATOR_PLATFORM_ALIGNMENT (__alignof__ (align_test))
+#else
+#define EACCELERATOR_PLATFORM_ALIGNMENT (sizeof(align_union))
+#endif
+
+#define EACCELERATOR_ALIGN(n) (n) = (void*)((((size_t)(n)-1) & ~(EACCELERATOR_PLATFORM_ALIGNMENT-1)) + EACCELERATOR_PLATFORM_ALIGNMENT)
+
+/******************************************************************************/
+
+static inline void calc_string(char* str, int len TSRMLS_DC) {
+  if (len > MAX_DUP_STR_LEN || zend_hash_add(&MMCG(strings), str, len, &str, sizeof(char*), NULL) == SUCCESS) {
+    EACCELERATOR_ALIGN(MMCG(mem));
+    MMCG(mem) += len;
+  }
+}
+
+static void calc_zval(zval* z TSRMLS_DC);
+static void calc_class_entry(zend_class_entry* from TSRMLS_DC);
+
+typedef void (*calc_bucket_t)(void* TSRMLS_DC);
+
+#define calc_hash_ex(from, start, calc_bucket) \
+  calc_hash_int(from, start, calc_bucket TSRMLS_CC)
+
+#define calc_hash(from, calc_bucket) \
+  calc_hash_ex(from, (from)->pListHead, calc_bucket)
+
+#define calc_zval_hash(from) \
+  calc_hash(from, (calc_bucket_t)calc_zval_ptr)
+
+#define calc_zval_hash_ex(from, start) \
+  calc_hash_ex(from, start, (calc_bucket_t)calc_zval_ptr)
+
+
+static void calc_zval_ptr(zval** from TSRMLS_DC) {
+  EACCELERATOR_ALIGN(MMCG(mem));
+  MMCG(mem) += sizeof(zval);
+  calc_zval(*from TSRMLS_CC);
+}
+
+#ifdef ZEND_ENGINE_2
+static void calc_property_info(zend_property_info* from TSRMLS_DC) {
+  EACCELERATOR_ALIGN(MMCG(mem));
+  MMCG(mem) += sizeof(zend_property_info);
+  calc_string(from->name, from->name_length+1 TSRMLS_CC);
+}
+
+static void calc_class_entry_ptr(zend_class_entry** from TSRMLS_DC) {
+  calc_class_entry(*from TSRMLS_CC);
+}
+#endif
+
+static void calc_hash_int(HashTable* source, Bucket* start, calc_bucket_t calc_bucket TSRMLS_DC) {
+  Bucket* p;
+
+  if (source->nNumOfElements > 0) {
+    if (!MMCG(compress)) {
+      EACCELERATOR_ALIGN(MMCG(mem));
+      MMCG(mem) += source->nTableSize * sizeof(Bucket*);
+    }
+    p = start;
+    while (p) {
+      EACCELERATOR_ALIGN(MMCG(mem));
+      MMCG(mem) += offsetof(Bucket,arKey)+p->nKeyLength;
+      calc_bucket(p->pData TSRMLS_CC);
+      p = p->pListNext;
+    }
+  }
+}
+
+static void calc_zval(zval* zv TSRMLS_DC) {
+  switch (zv->type & ~IS_CONSTANT_INDEX) {
+    case IS_CONSTANT:
+    case IS_STRING:
+      if (zv->value.str.val == NULL ||
+          zv->value.str.val == empty_string ||
+          zv->value.str.len == 0) {
+      } else {
+        calc_string(zv->value.str.val, zv->value.str.len+1 TSRMLS_CC);
+      }
+      break;
+    case IS_ARRAY:
+    case IS_CONSTANT_ARRAY:
+      if (zv->value.ht == NULL || zv->value.ht == &EG(symbol_table)) {
+      } else {
+        EACCELERATOR_ALIGN(MMCG(mem));
+        MMCG(mem) += sizeof(HashTable);
+        calc_zval_hash(zv->value.ht);
+      }
+      break;
+    case IS_OBJECT:
+#ifndef ZEND_ENGINE_2
+      if (zv->value.obj.ce != NULL) {
+        zend_class_entry *ce = zv->value.obj.ce;
+        if (!MMCG(compress)) {
+          debug_printf("[%d] EACCELERATOR can't cache objects\n", getpid());
+          zend_bailout();
+        }
+        while (ce != NULL) {
+          if (ce->type !=  ZEND_USER_CLASS && strcmp(ce->name,"stdClass") != 0) {
+            debug_printf("[%d] EACCELERATOR can't cache objects\n", getpid());
+            zend_bailout();
+          }
+          ce = ce->parent;
+        }
+        calc_string(zv->value.obj.ce->name, zv->value.obj.ce->name_length+1 TSRMLS_CC);
+      }
+      if (zv->value.obj.properties != NULL) {
+        EACCELERATOR_ALIGN(MMCG(mem));
+        MMCG(mem) += sizeof(HashTable);
+        calc_zval_hash(zv->value.obj.properties);
+      }
+#endif
+      return;
+    case IS_RESOURCE:
+      debug_printf("[%d] EACCELERATOR can't cache resources\n", getpid());
+      zend_bailout();
+    default:
+      break;
+  }
+}
+
+static void calc_op_array(zend_op_array* from TSRMLS_DC) {
+  zend_op *opline;
+  zend_op *end;
+
+  if (from->type == ZEND_INTERNAL_FUNCTION) {
+    EACCELERATOR_ALIGN(MMCG(mem));
+    MMCG(mem) += sizeof(zend_internal_function);
+  } else if (from->type == ZEND_USER_FUNCTION) {
+    EACCELERATOR_ALIGN(MMCG(mem));
+    MMCG(mem) += sizeof(eaccelerator_op_array);
+  } else {
+    debug_printf("[%d] EACCELERATOR can't cache function \"%s\"\n", getpid(), from->function_name);
+    zend_bailout();
+  }
+#ifdef ZEND_ENGINE_2
+  if (from->num_args > 0) {
+    zend_uint i;
+    EACCELERATOR_ALIGN(MMCG(mem));
+    MMCG(mem) += from->num_args * sizeof(zend_arg_info);
+    for (i = 0; i < from->num_args; i++) {
+      if (from->arg_info[i].name) {
+        calc_string(from->arg_info[i].name,from->arg_info[i].name_len TSRMLS_CC);
+      }
+      if (from->arg_info[i].class_name) {
+        calc_string(from->arg_info[i].class_name,from->arg_info[i].class_name_len TSRMLS_CC);
+      }
+    }
+  }
+#else
+  if (from->arg_types != NULL) {
+    calc_string((char*)from->arg_types, (from->arg_types[0]+1) * sizeof(zend_uchar) TSRMLS_CC);
+  }
+#endif
+  if (from->function_name != NULL) {
+    calc_string(from->function_name, strlen(from->function_name)+1 TSRMLS_CC);
+  }
+#ifdef ZEND_ENGINE_2
+  if (from->scope != NULL)
+  {
+    // HOESH: the same problem?
+    Bucket* q = CG(class_table)->pListHead;
+    while (q != NULL)
+	{
+      if (*(zend_class_entry**)q->pData == from->scope)
+	  {
+        calc_string(q->arKey, q->nKeyLength TSRMLS_CC);
+        break;
+      }
+      q = q->pListNext;
+    }
+  }
+#endif
+  if (from->type == ZEND_INTERNAL_FUNCTION) {
+    return;
+  }
+
+  if (from->opcodes != NULL) {
+    EACCELERATOR_ALIGN(MMCG(mem));
+    MMCG(mem) += from->last * sizeof(zend_op);
+
+    opline = from->opcodes;
+    end = opline + from->last;
+    MMCG(compress) = 0;
+    for (;opline < end; opline++) {
+/*
+      if (opline->result.op_type == IS_CONST) calc_zval(&opline->result.u.constant  TSRMLS_CC);
+*/
+      if (opline->op1.op_type    == IS_CONST) calc_zval(&opline->op1.u.constant TSRMLS_CC);
+      if (opline->op2.op_type    == IS_CONST) calc_zval(&opline->op2.u.constant TSRMLS_CC);
+    }
+    MMCG(compress) = 1;
+  }
+  if (from->brk_cont_array != NULL) {
+    EACCELERATOR_ALIGN(MMCG(mem));
+    MMCG(mem) += sizeof(zend_brk_cont_element) * from->last_brk_cont;
+  }
+#ifdef ZEND_ENGINE_2
+	/* HOESH: try & catch support */
+	if (from->try_catch_array != NULL)
+	{
+		EACCELERATOR_ALIGN(MMCG(mem));
+		MMCG(mem) += sizeof(zend_try_catch_element) * from->last_try_catch;
+	}
+#endif
+  if (from->static_variables != NULL) {
+    EACCELERATOR_ALIGN(MMCG(mem));
+    MMCG(mem) += sizeof(HashTable);
+    calc_zval_hash(from->static_variables);
+  }
+  if (from->filename != NULL) {
+    calc_string(from->filename, strlen(from->filename)+1 TSRMLS_CC);
+  }
+#ifdef ZEND_ENGINE_2
+  if (from->doc_comment != NULL) {
+    calc_string(from->doc_comment, from->doc_comment_len+1 TSRMLS_CC);
+  }
+#endif
+}
+
+static void calc_class_entry(zend_class_entry* from TSRMLS_DC) {
+  if (from->type != ZEND_USER_CLASS) {
+    debug_printf("[%d] EACCELERATOR can't cache internal class \"%s\"\n", getpid(), from->name);
+    zend_bailout();
+  }
+/*
+  if (from->builtin_functions) {
+    debug_printf("[%d] EACCELERATOR can't cache class \"%s\" because of it has "
+        "some builtin_functions\n", getpid(), from->name);
+    zend_bailout();
+  }
+*/
+  EACCELERATOR_ALIGN(MMCG(mem));
+  MMCG(mem) += sizeof(eaccelerator_class_entry);
+
+  if (from->name != NULL) {
+    calc_string(from->name, from->name_length+1 TSRMLS_CC);
+  }
+  if (from->parent != NULL && from->parent->name) {
+    calc_string(from->parent->name, from->parent->name_length + 1  TSRMLS_CC);
+  }
+
+#ifdef ZEND_ENGINE_2
+  if (from->filename != NULL) {
+    calc_string(from->filename, strlen(from->filename)+1 TSRMLS_CC);
+  }
+  if (from->doc_comment != NULL) {
+    calc_string(from->doc_comment, from->doc_comment_len+1 TSRMLS_CC);
+  }
+
+  calc_zval_hash(&from->constants_table);
+  calc_zval_hash(&from->default_properties);
+  calc_hash(&from->properties_info, (calc_bucket_t)calc_property_info);
+  if (from->static_members != NULL) {
+    EACCELERATOR_ALIGN(MMCG(mem));
+    MMCG(mem) += sizeof(HashTable);
+    calc_zval_hash(from->static_members);
+  }
+#else
+  calc_zval_hash(&from->default_properties);
+#endif
+  calc_hash(&from->function_table, (calc_bucket_t)calc_op_array);
+}
+
+static int calc_size(char* key, zend_op_array* op_array,
+                     Bucket* f, Bucket *c TSRMLS_DC) {
+  Bucket *b;
+  char   *x;
+  int len = strlen(key);
+  MMCG(compress) = 1;
+  MMCG(mem) = NULL;
+
+  zend_hash_init(&MMCG(strings), 0, NULL, NULL, 0);
+  MMCG(mem) += offsetof(mm_cache_entry,realfilename)+len+1;
+  zend_hash_add(&MMCG(strings), key, len+1, &key, sizeof(char*), NULL);
+  b = c;
+  while (b != NULL) {
+    EACCELERATOR_ALIGN(MMCG(mem));
+    MMCG(mem) += offsetof(mm_fc_entry,htabkey)+b->nKeyLength;
+    x = b->arKey;
+    zend_hash_add(&MMCG(strings), b->arKey, b->nKeyLength, &x, sizeof(char*), NULL);
+    b = b->pListNext;
+  }
+  b = f;
+  while (b != NULL) {
+    EACCELERATOR_ALIGN(MMCG(mem));
+    MMCG(mem) += offsetof(mm_fc_entry,htabkey)+b->nKeyLength;
+    x = b->arKey;
+    zend_hash_add(&MMCG(strings), b->arKey, b->nKeyLength, &x, sizeof(char*), NULL);
+    b = b->pListNext;
+  }
+  while (c != NULL) {
+#ifdef ZEND_ENGINE_2
+    calc_class_entry(*(zend_class_entry**)c->pData TSRMLS_CC);
+#else
+    calc_class_entry((zend_class_entry*)c->pData TSRMLS_CC);
+#endif
+    c = c->pListNext;
+  }
+  while (f != NULL) {
+    calc_op_array((zend_op_array*)f->pData TSRMLS_CC);
+    f = f->pListNext;
+  }
+  calc_op_array(op_array TSRMLS_CC);
+  EACCELERATOR_ALIGN(MMCG(mem));
+  zend_hash_destroy(&MMCG(strings));
+  return (long)MMCG(mem);
+}
+
+/******************************************************************************/
+
+static inline char* store_string(char* str, int len TSRMLS_DC) {
+  char *p;
+  if (len > MAX_DUP_STR_LEN) {
+    EACCELERATOR_ALIGN(MMCG(mem));
+    p = (char*)MMCG(mem);
+    MMCG(mem) += len;
+    memcpy(p, str, len);
+  } else if (zend_hash_find(&MMCG(strings), str, len, (void*)&p) == SUCCESS) {
+    p = *(char**)p;
+  } else {
+    EACCELERATOR_ALIGN(MMCG(mem));
+    p = (char*)MMCG(mem);
+    MMCG(mem) += len;
+    memcpy(p, str, len);
+    zend_hash_add(&MMCG(strings), str, len, (void*)&p, sizeof(char*), NULL);
+  }
+  return p;
+}
+
+static void store_zval(zval* z TSRMLS_DC);
+static eaccelerator_class_entry* store_class_entry(zend_class_entry* from TSRMLS_DC);
+
+typedef void* (*store_bucket_t)(void* TSRMLS_DC);
+
+#define store_hash_ex(to, from, start, store_bucket) \
+  store_hash_int(to, from, start, store_bucket TSRMLS_CC)
+
+#define store_hash(to, from, store_bucket) \
+  store_hash_ex(to, from, (from)->pListHead, store_bucket)
+
+#define store_zval_hash(to, from) \
+  store_hash(to, from, (store_bucket_t)store_zval_ptr)
+
+#define store_zval_hash_ex(to, from, start) \
+  store_hash_ex(to, from, start, (store_bucket_t)store_zval_ptr)
+
+static zval* store_zval_ptr(zval* from TSRMLS_DC) {
+  zval* to;
+  EACCELERATOR_ALIGN(MMCG(mem));
+  to = (zval*)MMCG(mem);
+  MMCG(mem) += sizeof(zval);
+  memcpy(to, from, sizeof(zval));
+  store_zval(to TSRMLS_CC);
+  return to;
+}
+
+#ifdef ZEND_ENGINE_2
+static zend_property_info* store_property_info(zend_property_info* from TSRMLS_DC) {
+  zend_property_info* to;
+  EACCELERATOR_ALIGN(MMCG(mem));
+  to = (zend_property_info*)MMCG(mem);
+  MMCG(mem) += sizeof(zend_property_info);
+  memcpy(to, from, sizeof(zend_property_info));
+  to->name = store_string(from->name, from->name_length+1 TSRMLS_CC);
+  return to;
+}
+
+static eaccelerator_class_entry* store_class_entry_ptr(zend_class_entry** from TSRMLS_DC) {
+  return store_class_entry(*from TSRMLS_CC);
+}
+#endif
+
+static void store_hash_int(HashTable* target, HashTable* source, Bucket* start, store_bucket_t copy_bucket TSRMLS_DC) {
+  Bucket *p, *np, *prev_p;
+
+  memcpy(target, source, sizeof(HashTable));
+
+  if (source->nNumOfElements > 0) {
+    if (!MMCG(compress)) {
+      EACCELERATOR_ALIGN(MMCG(mem));
+      target->arBuckets = (Bucket **)MMCG(mem);
+      MMCG(mem) += target->nTableSize * sizeof(Bucket*);
+      memset(target->arBuckets, 0, target->nTableSize * sizeof(Bucket*));
+    }
+
+    target->pDestructor = NULL;
+    target->persistent  = 1;
+    target->pListHead   = NULL;
+    target->pListTail   = NULL;
+
+    p = start;
+    prev_p = NULL;
+    np = NULL;
+    while (p) {
+      EACCELERATOR_ALIGN(MMCG(mem));
+      np = (Bucket*)MMCG(mem);
+      MMCG(mem) += offsetof(Bucket,arKey)+p->nKeyLength;
+
+      if (!MMCG(compress)) {
+        int nIndex = p->h % source->nTableSize;
+        if(target->arBuckets[nIndex]) {
+          np->pNext = target->arBuckets[nIndex];
+          np->pLast = NULL;
+          np->pNext->pLast = np;
+        } else {
+          np->pNext = NULL;
+          np->pLast = NULL;
+        }
+        target->arBuckets[nIndex] = np;
+      }
+      np->h = p->h;
+      np->nKeyLength = p->nKeyLength;
+
+      if (p->pDataPtr == NULL) {
+        np->pData    = copy_bucket(p->pData TSRMLS_CC);
+        np->pDataPtr = NULL;
+      } else {
+        np->pDataPtr = copy_bucket(p->pDataPtr TSRMLS_CC);
+        np->pData    = &np->pDataPtr;
+      }
+
+      np->pListLast = prev_p;
+      np->pListNext = NULL;
+
+      memcpy(np->arKey, p->arKey, p->nKeyLength);
+
+      if (prev_p) {
+        prev_p->pListNext = np;
+      } else {
+        target->pListHead = np;
+      }
+      prev_p = np;
+      p = p->pListNext;
+    }
+    target->pListTail = np;
+    target->pInternalPointer = target->pListHead;
+  }
+}
+
+static void store_zval(zval* zv TSRMLS_DC) {
+  switch (zv->type & ~IS_CONSTANT_INDEX) {
+    case IS_CONSTANT:
+    case IS_STRING:
+      if (zv->value.str.val == NULL ||
+          zv->value.str.val == empty_string ||
+          zv->value.str.len == 0) {
+        zv->value.str.val = empty_string;
+        zv->value.str.len = 0;
+      } else {
+        zv->value.str.val = store_string(zv->value.str.val, zv->value.str.len+1 TSRMLS_CC);
+      }
+      break;
+    case IS_ARRAY:
+    case IS_CONSTANT_ARRAY:
+      if (zv->value.ht == NULL || zv->value.ht == &EG(symbol_table)) {
+      } else {
+        HashTable* p;
+        EACCELERATOR_ALIGN(MMCG(mem));
+        p = (HashTable*)MMCG(mem);
+        MMCG(mem) += sizeof(HashTable);
+        store_zval_hash(p, zv->value.ht);
+        zv->value.ht = p;
+      }
+      break;
+    case IS_OBJECT:
+      if (!MMCG(compress)) {
+        return;
+      }
+#ifndef ZEND_ENGINE_2
+      if (zv->value.obj.ce != NULL) {
+        char *s = store_string(zv->value.obj.ce->name, zv->value.obj.ce->name_length+1 TSRMLS_CC);
+        zend_str_tolower(s, zv->value.obj.ce->name_length);
+        zv->value.obj.ce = (zend_class_entry*)s;
+      }
+      if (zv->value.obj.properties != NULL) {
+        HashTable* p;
+        EACCELERATOR_ALIGN(MMCG(mem));
+        p = (HashTable*)MMCG(mem);
+        MMCG(mem) += sizeof(HashTable);
+        store_zval_hash(p, zv->value.obj.properties);
+        zv->value.obj.properties = p;
+      }
+#endif
+    default:
+      break;
+  }
+}
+
+static eaccelerator_op_array* store_op_array(zend_op_array* from TSRMLS_DC) {
+  eaccelerator_op_array *to;
+  zend_op *opline;
+  zend_op *end;
+
+#ifdef DEBUG
+  pad(TSRMLS_C);
+  fprintf(F_fp, "[%d] store_op_array: %s\n", getpid(),
+    from->function_name ? from->function_name : "(top)");
+  fflush(F_fp);
+#endif
+
+  if (from->type == ZEND_INTERNAL_FUNCTION) {
+    EACCELERATOR_ALIGN(MMCG(mem));
+    to = (eaccelerator_op_array*)MMCG(mem);
+    MMCG(mem) += offsetof(eaccelerator_op_array,opcodes);
+  } else if (from->type == ZEND_USER_FUNCTION) {
+    EACCELERATOR_ALIGN(MMCG(mem));
+    to = (eaccelerator_op_array*)MMCG(mem);
+    MMCG(mem) += sizeof(eaccelerator_op_array);
+  } else {
+    return NULL;
+  }
+
+  to->type = from->type;
+#ifdef ZEND_ENGINE_2
+  to->num_args = from->num_args;
+  if (from->num_args > 0) {
+    zend_uint i;
+    EACCELERATOR_ALIGN(MMCG(mem));
+    to->arg_info = (zend_arg_info*)MMCG(mem);
+    MMCG(mem) += from->num_args * sizeof(zend_arg_info);
+    for (i = 0; i < from->num_args; i++) {
+      if (from->arg_info[i].name) {
+        to->arg_info[i].name = store_string(from->arg_info[i].name,from->arg_info[i].name_len TSRMLS_CC);
+        to->arg_info[i].name_len = from->arg_info[i].name_len;
+      }
+      if (from->arg_info[i].class_name) {
+        to->arg_info[i].class_name = store_string(from->arg_info[i].class_name,from->arg_info[i].class_name_len TSRMLS_CC);
+        to->arg_info[i].class_name_len = from->arg_info[i].class_name_len;
+      }
+      to->arg_info[i].allow_null        = from->arg_info[i].allow_null;
+      to->arg_info[i].pass_by_reference = from->arg_info[i].pass_by_reference;
+    }
+  }
+  to->pass_rest_by_reference = from->pass_rest_by_reference;
+#else
+  if (from->arg_types != NULL) {
+    to->arg_types = (unsigned char*)
+      store_string((char*)from->arg_types, (from->arg_types[0]+1) * sizeof(zend_uchar) TSRMLS_CC);
+  }
+#endif
+  if (from->function_name != NULL)
+  {
+	/*
+	 * HOESH: converting to lowercase. this helps to find 
+	 * class methods in function_table without each time tolower...
+	 */
+	to->function_name = store_string(from->function_name, strlen(from->function_name)+1  TSRMLS_CC);
+	zend_str_tolower(to->function_name, strlen(from->function_name));
+  }
+#ifdef ZEND_ENGINE_2
+  to->fn_flags         = from->fn_flags;
+  to->scope_name = NULL;
+  to->scope_name_len = 0;
+  if (from->scope != NULL)
+  {
+	// HOESH: why? use from->scope->name & from->scope->name_len instead.
+	// Keep internal class behavior on mind!
+    Bucket* q = CG(class_table)->pListHead;
+    while (q != NULL)
+	{
+      if (*(zend_class_entry**)q->pData == from->scope)
+	  {
+        to->scope_name = store_string(q->arKey, q->nKeyLength TSRMLS_CC);
+        to->scope_name_len = q->nKeyLength;
+        break;
+      }
+      q = q->pListNext;
+    }
+  }
+#endif
+  if (from->type == ZEND_INTERNAL_FUNCTION) {
+    return to;
+  }
+  to->opcodes          = from->opcodes;
+  to->last             = from->last;
+  to->T                = from->T;
+  to->brk_cont_array   = from->brk_cont_array;
+  to->last_brk_cont    = from->last_brk_cont;
+#ifdef ZEND_ENGINE_2
+	/* HOESH: try & catch support */
+	to->try_catch_array   = from->try_catch_array;
+	to->last_try_catch    = from->last_try_catch;
+  to->uses_this        = from->uses_this;
+#else
+  to->uses_globals     = from->uses_globals;
+#endif
+  to->static_variables = from->static_variables;
+  to->return_reference = from->return_reference;
+  to->filename         = from->filename;
+
+  if (from->opcodes != NULL) {
+    EACCELERATOR_ALIGN(MMCG(mem));
+    to->opcodes = (zend_op*)MMCG(mem);
+    MMCG(mem) += from->last * sizeof(zend_op);
+    memcpy(to->opcodes, from->opcodes, from->last * sizeof(zend_op));
+
+    opline = to->opcodes;
+    end = opline + to->last;
+    MMCG(compress) = 0;
+    for (;opline < end; opline++) {
+/*
+      if (opline->result.op_type == IS_CONST) store_zval(&opline->result.u.constant  TSRMLS_CC);
+*/
+      if (opline->op1.op_type    == IS_CONST) store_zval(&opline->op1.u.constant TSRMLS_CC);
+      if (opline->op2.op_type    == IS_CONST) store_zval(&opline->op2.u.constant TSRMLS_CC);
+#ifdef ZEND_ENGINE_2
+      switch (opline->opcode) {
+        case ZEND_JMP:
+          opline->op1.u.jmp_addr = to->opcodes + (opline->op1.u.jmp_addr - from->opcodes);
+          break;
+        case ZEND_JMPZ:
+        case ZEND_JMPNZ:
+        case ZEND_JMPZ_EX:
+        case ZEND_JMPNZ_EX:
+          opline->op2.u.jmp_addr = to->opcodes + (opline->op2.u.jmp_addr - from->opcodes);
+          break;
+      }
+#endif
+    }
+    MMCG(compress) = 1;
+  }
+  if (from->brk_cont_array != NULL) {
+    EACCELERATOR_ALIGN(MMCG(mem));
+    to->brk_cont_array = (zend_brk_cont_element*)MMCG(mem);
+    MMCG(mem) += sizeof(zend_brk_cont_element) * from->last_brk_cont;
+    memcpy(to->brk_cont_array, from->brk_cont_array,
+           sizeof(zend_brk_cont_element) * from->last_brk_cont);
+  } else {
+    to->last_brk_cont  = 0;
+  }
+#ifdef ZEND_ENGINE_2
+	/* HOESH: try & catch support */
+	if (from->try_catch_array != NULL)
+	{
+		EACCELERATOR_ALIGN(MMCG(mem));
+		to->try_catch_array = (zend_try_catch_element*)MMCG(mem);
+		MMCG(mem) += sizeof(zend_try_catch_element) * from->last_try_catch;
+		memcpy(to->try_catch_array, from->try_catch_array,
+			sizeof(zend_try_catch_element) * from->last_try_catch);
+	}
+	else
+	{
+		to->last_try_catch  = 0;
+	}
+#endif
+  if (from->static_variables != NULL) {
+    EACCELERATOR_ALIGN(MMCG(mem));
+    to->static_variables = (HashTable*)MMCG(mem);
+    MMCG(mem) += sizeof(HashTable);
+    store_zval_hash(to->static_variables, from->static_variables);
+  }
+  if (from->filename != NULL) {
+    to->filename =
+      store_string(to->filename, strlen(from->filename)+1 TSRMLS_CC);
+  }
+#ifdef ZEND_ENGINE_2
+  to->line_start      = from->line_start;
+  to->line_end        = from->line_end;
+  to->doc_comment_len = from->doc_comment_len;
+  if (from->doc_comment != NULL) {
+    to->doc_comment = store_string(from->doc_comment, from->doc_comment_len+1 TSRMLS_CC);
+  }
+#endif
+  return to;
+}
+
+static eaccelerator_class_entry* store_class_entry(zend_class_entry* from TSRMLS_DC) {
+  eaccelerator_class_entry *to;
+
+  EACCELERATOR_ALIGN(MMCG(mem));
+  to = (eaccelerator_class_entry*)MMCG(mem);
+  MMCG(mem) += sizeof(eaccelerator_class_entry);
+  to->type        = from->type;
+  to->name        = NULL;
+  to->name_length = from->name_length;
+  to->parent      = NULL;
+#ifdef ZEND_ENGINE_2
+  to->ce_flags    = from->ce_flags;
+  to->static_members = NULL;
+  to->num_interfaces = from->num_interfaces;
+#endif
+
+#ifdef DEBUG
+  pad(TSRMLS_C);
+  fprintf(F_fp, "[%d] store_class_entry: %s\n", getpid(), from->name? from->name : "(top)");
+  fflush(F_fp);
+  MMCG(xpad)++;
+#endif
+
+  if (from->name != NULL) {
+    to->name = store_string(from->name, from->name_length+1 TSRMLS_CC);
+	zend_str_tolower(to->name, from->name_length);
+  }
+  if (from->parent != NULL && from->parent->name) {
+    to->parent = store_string(from->parent->name, from->parent->name_length+1 TSRMLS_CC);
+    zend_str_tolower(to->parent, from->parent->name_length);
+  }
+
+/*
+  if (!from->constants_updated) {
+    zend_hash_apply_with_argument(&from->default_properties, (apply_func_arg_t) zval_update_constant, (void *) 1 TSRMLS_CC);
+    to->constants_updated = 1;
+  }
+*/
+#ifdef ZEND_ENGINE_2
+  to->line_start      = from->line_start;
+  to->line_end        = from->line_end;
+  to->doc_comment_len = from->doc_comment_len;
+  if (from->filename != NULL) {
+    to->filename = store_string(from->filename, strlen(from->filename)+1 TSRMLS_CC);
+  }
+  if (from->doc_comment != NULL) {
+    to->doc_comment = store_string(from->doc_comment, from->doc_comment_len+1 TSRMLS_CC);
+  }
+
+  store_zval_hash(&to->constants_table, &from->constants_table);
+  store_zval_hash(&to->default_properties, &from->default_properties);
+  store_hash(&to->properties_info, &from->properties_info, (store_bucket_t)store_property_info);
+  if (from->static_members != NULL) {
+    EACCELERATOR_ALIGN(MMCG(mem));
+    to->static_members = (HashTable*)MMCG(mem);
+    MMCG(mem) += sizeof(HashTable);
+    store_zval_hash(to->static_members, from->static_members);
+  }
+#else
+  store_zval_hash(&to->default_properties, &from->default_properties);
+#endif
+  store_hash(&to->function_table, &from->function_table, (store_bucket_t)store_op_array);
+
+#ifdef DEBUG
+  MMCG(xpad)--;
+#endif
+
+  return to;
+}
+
+static mm_cache_entry* eaccelerator_store_int(
+                         char* key, int len,
+                         zend_op_array* op_array,
+                         Bucket* f, Bucket *c TSRMLS_DC) {
+  mm_cache_entry *p;
+  mm_fc_entry    *fc;
+  mm_fc_entry    *q;
+  char *x;
+
+  MMCG(compress) = 1;
+  zend_hash_init(&MMCG(strings), 0, NULL, NULL, 0);
+  p = (mm_cache_entry*)MMCG(mem);
+  MMCG(mem) += offsetof(mm_cache_entry,realfilename)+len+1;
+
+  p->nhits    = 0;
+  p->use_cnt  = 0;
+  p->removed  = 0;
+  p->f_head   = NULL;
+  p->c_head   = NULL;
+  memcpy(p->realfilename, key, len+1);
+  x = p->realfilename;
+  zend_hash_add(&MMCG(strings), key, len+1, &x, sizeof(char*), NULL);
+
+  q = NULL;
+  while (c != NULL) {
+    EACCELERATOR_ALIGN(MMCG(mem));
+    fc = (mm_fc_entry*)MMCG(mem);
+    MMCG(mem) += offsetof(mm_fc_entry,htabkey)+c->nKeyLength;
+    memcpy(fc->htabkey, c->arKey, c->nKeyLength);
+    fc->htablen = c->nKeyLength;
+    fc->next = NULL;
+#ifdef ZEND_ENGINE_2
+    fc->fc = *(zend_class_entry**)c->pData;
+#else
+    fc->fc = c->pData;
+#endif
+    c = c->pListNext;
+    x = fc->htabkey;
+    zend_hash_add(&MMCG(strings), fc->htabkey, fc->htablen, &x, sizeof(char*), NULL);
+    if (q == NULL) {
+      p->c_head = fc;
+    } else {
+      q->next = fc;
+    }
+    q = fc;
+  }
+
+  q = NULL;
+  while (f != NULL) {
+    EACCELERATOR_ALIGN(MMCG(mem));
+    fc = (mm_fc_entry*)MMCG(mem);
+    MMCG(mem) += offsetof(mm_fc_entry,htabkey)+f->nKeyLength;
+    memcpy(fc->htabkey, f->arKey, f->nKeyLength);
+    fc->htablen = f->nKeyLength;
+    fc->next = NULL;
+    fc->fc = f->pData;
+    f = f->pListNext;
+    x = fc->htabkey;
+    zend_hash_add(&MMCG(strings), fc->htabkey, fc->htablen, &x, sizeof(char*), NULL);
+    if (q == NULL) {
+      p->f_head = fc;
+    } else {
+      q->next = fc;
+    }
+    q = fc;
+  }
+
+  q = p->c_head;
+  while (q != NULL) {
+#ifdef ZEND_ENGINE_2
+    q->fc = store_class_entry((zend_class_entry*)q->fc TSRMLS_CC);
+#else
+    q->fc = store_class_entry((zend_class_entry*)q->fc TSRMLS_CC);
+#endif
+    q = q->next;
+  }
+
+  q = p->f_head;
+  while (q != NULL) {
+    q->fc = store_op_array((zend_op_array*)q->fc TSRMLS_CC);
+    q = q->next;
+  }
+  p->op_array = store_op_array(op_array TSRMLS_CC);
+
+  zend_hash_destroy(&MMCG(strings));
+  return p;
+}
+
+/* called after succesful compilation, from eaccelerator_compile file */
+static int eaccelerator_store(char* key, struct stat *buf, int nreloads,
+                         zend_op_array* op_array,
+                         Bucket* f, Bucket *c TSRMLS_DC) {
+  mm_cache_entry *p;
+  int len = strlen(key);
+  int use_shm = 1;
+  int ret = 0;
+  int size = 0;
+
+  zend_try {
+    size = calc_size(key, op_array, f, c TSRMLS_CC);
+  } zend_catch {
+    size =  0;
+  } zend_end_try();
+  if (size == 0) {
+    return 0;
+  }
+  EACCELERATOR_UNPROTECT();
+  MMCG(mem) = eaccelerator_malloc(size);
+  if (MMCG(mem) == NULL) {
+    MMCG(mem) = eaccelerator_malloc2(size TSRMLS_CC);
+  }
+  if (!MMCG(mem) && !eaccelerator_scripts_shm_only) {
+    EACCELERATOR_PROTECT();
+    MMCG(mem) = emalloc(size);
+    use_shm = 0;
+  }
+  if (MMCG(mem)) {
+    memset(MMCG(mem), 0, size);
+    p = eaccelerator_store_int(key, len, op_array, f, c TSRMLS_CC);
+    p->mtime    = buf->st_mtime;
+    p->filesize = buf->st_size;
+    p->size     = size;
+    p->nreloads = nreloads;
+#ifdef EACCELERATOR_USE_INODE
+    p->st_dev   = buf->st_dev;
+    p->st_ino   = buf->st_ino;
+#endif
+    if (use_shm) {
+      if (eaccelerator_shm_ttl > 0) {
+        p->ttl = time(0) + eaccelerator_shm_ttl;
+      } else {
+        p->ttl = 0;
+      }
+      if (!eaccelerator_scripts_shm_only) {
+        hash_add_file(p TSRMLS_CC);
+      }
+      hash_add_mm(p);
+      EACCELERATOR_PROTECT();
+      ret = 1;
+    } else {
+      ret =  hash_add_file(p TSRMLS_CC);
+      efree(p);
+    }
+  }
+  return ret;
+}
+
+/******************************************************************************/
+
+static void restore_zval(zval * TSRMLS_DC);
+static zend_class_entry* restore_class_entry(zend_class_entry* to, eaccelerator_class_entry *from TSRMLS_DC);
+
+typedef void* (*restore_bucket_t)(void* TSRMLS_DC);
+
+#define restore_zval_hash(target, source) \
+  restore_hash(target, source, (restore_bucket_t)restore_zval_ptr TSRMLS_CC)
+
+static zval* restore_zval_ptr(zval* from TSRMLS_DC) {
+  zval* p;
+  ALLOC_ZVAL(p);
+  memcpy(p, from, sizeof(zval));
+  restore_zval(p TSRMLS_CC);
+  return p;
+}
+
+#ifdef ZEND_ENGINE_2
+static zend_property_info* restore_property_info(zend_property_info* from TSRMLS_DC) {
+  zend_property_info* to = emalloc(sizeof(zend_property_info));
+  memcpy(to, from, sizeof(zend_property_info));
+  to->name = emalloc(from->name_length+1);
+  memcpy(to->name, from->name, from->name_length+1);
+  return to;
+}
+
+static zend_class_entry* restore_class_entry_ptr(eaccelerator_class_entry *from TSRMLS_DC) {
+  return restore_class_entry(NULL, from TSRMLS_CC);
+}
+#endif
+
+static HashTable* restore_hash(HashTable *target, HashTable *source, restore_bucket_t copy_bucket TSRMLS_DC)
+{
+  Bucket *p, *np, *prev_p;
+  int nIndex;
+
+  if (target == NULL) {
+    ALLOC_HASHTABLE(target);
+  }
+  memcpy(target, source, sizeof(HashTable));
+  target->arBuckets = (Bucket **) emalloc(target->nTableSize * sizeof(Bucket*));
+  memset(target->arBuckets, 0, target->nTableSize * sizeof(Bucket*));
+  target->pDestructor = NULL;
+  target->persistent  = 0;
+  target->pListHead   = NULL;
+  target->pListTail   = NULL;
+
+  p = source->pListHead;
+  prev_p = NULL;
+  np = NULL;
+  while (p) {
+    np = (Bucket *) emalloc(offsetof(Bucket,arKey) + p->nKeyLength);
+/*    np = (Bucket *) emalloc(sizeof(Bucket) + p->nKeyLength);*/
+    nIndex = p->h % source->nTableSize;
+    if(target->arBuckets[nIndex]) {
+      np->pNext = target->arBuckets[nIndex];
+      np->pLast = NULL;
+      np->pNext->pLast = np;
+    } else {
+      np->pNext = NULL;
+      np->pLast = NULL;
+    }
+    target->arBuckets[nIndex] = np;
+    np->h = p->h;
+    np->nKeyLength = p->nKeyLength;
+
+    if (p->pDataPtr == NULL) {
+      np->pData    = copy_bucket(p->pData TSRMLS_CC);
+      np->pDataPtr = NULL;
+    } else {
+      np->pDataPtr = copy_bucket(p->pDataPtr TSRMLS_CC);
+      np->pData    = &np->pDataPtr;
+    }
+    np->pListLast = prev_p;
+    np->pListNext = NULL;
+
+    memcpy(np->arKey, p->arKey, p->nKeyLength);
+
+    if (prev_p) {
+      prev_p->pListNext = np;
+    } else {
+      target->pListHead = np;
+    }
+    prev_p = np;
+    p = p->pListNext;
+  }
+  target->pListTail = np;
+  target->pInternalPointer = target->pListHead;
+  return target;
+}
+
+static void restore_zval(zval *zv TSRMLS_DC)
+{
+  switch (zv->type & ~IS_CONSTANT_INDEX) {
+    case IS_CONSTANT:
+    case IS_STRING:
+      if (zv->value.str.val == NULL || zv->value.str.val == empty_string || zv->value.str.len == 0) {
+        zv->value.str.val = empty_string;
+        return;
+      } else {
+        char *p = emalloc(zv->value.str.len+1);
+        memcpy(p, zv->value.str.val, zv->value.str.len+1);
+        zv->value.str.val = p;
+      }
+      return;
+
+    case IS_ARRAY:
+    case IS_CONSTANT_ARRAY:
+      if (zv->value.ht != NULL && zv->value.ht != &EG(symbol_table)) {
+        zv->value.ht = restore_zval_hash(NULL, zv->value.ht);
+        zv->value.ht->pDestructor = ZVAL_PTR_DTOR;
+      }
+      return;
+    case IS_OBJECT: {
+#ifndef ZEND_ENGINE_2
+      zend_bool incomplete_class = 0;
+      char* class_name = (char*)zv->value.obj.ce;
+      int   name_len = 0;
+      if (!MMCG(compress)) {
+        return;
+      }
+      if (class_name != NULL) {
+        zend_class_entry *ce = NULL;
+        name_len = strlen(class_name);
+        if (zend_hash_find(CG(class_table), (void*)class_name, name_len+1,
+            (void **)&ce) != SUCCESS) {
+          char *lowercase_name = estrndup(INCOMPLETE_CLASS, sizeof(INCOMPLETE_CLASS));
+          zend_str_tolower(lowercase_name, sizeof(INCOMPLETE_CLASS));
+          if (zend_hash_find(CG(class_table),lowercase_name, sizeof(INCOMPLETE_CLASS),
+            (void **)&ce) != SUCCESS) {
+            efree(lowercase_name);
+            zend_error(E_ERROR, "EACCELERATOR can't restore object's class \"%s\"", class_name);
+          } else {
+            efree(lowercase_name);
+            zv->value.obj.ce = ce;
+            incomplete_class = 1;
+          }
+        } else {
+          zv->value.obj.ce = ce;
+        }
+      }
+      if (zv->value.obj.properties != NULL) {
+        zv->value.obj.properties = restore_zval_hash(NULL, zv->value.obj.properties);
+        zv->value.obj.properties->pDestructor = ZVAL_PTR_DTOR;
+        /* Clearing references */
+        {
+          Bucket* p = zv->value.obj.properties->pListHead;
+          while (p != NULL) {
+            ((zval*)(p->pDataPtr))->refcount = 1;
+            p = p->pListNext;
+          }
+        }
+      }
+      if (incomplete_class && class_name != NULL) {
+        zval *val;
+        MAKE_STD_ZVAL(val);
+        Z_TYPE_P(val)   = IS_STRING;
+        Z_STRVAL_P(val) = estrndup(class_name, name_len);
+        Z_STRLEN_P(val) = name_len;
+        zend_hash_update(Z_OBJPROP_P(zv), MAGIC_MEMBER, sizeof(MAGIC_MEMBER), &val, sizeof(val), NULL);
+      }
+#endif
+      return;
+    }
+  }
+}
+
+static void call_op_array_ctor_handler(zend_extension *extension, zend_op_array *op_array TSRMLS_DC) {
+  if (extension->op_array_ctor) {
+    extension->op_array_ctor(op_array);
+  }
+}
+
+static zend_op_array* restore_op_array(zend_op_array *to, eaccelerator_op_array *from TSRMLS_DC) {
+  zend_internal_function* function;
+
+#ifdef DEBUG
+  pad(TSRMLS_C);
+  fprintf(F_fp, "[%d] restore_op_array: %s\n", getpid(),
+    from->function_name? from->function_name : "(top)");
+  fflush(F_fp);
+#endif
+
+  if (from->type == ZEND_INTERNAL_FUNCTION) {
+    if (to == NULL) {
+      to = emalloc(sizeof(zend_internal_function));
+    }
+    memset(to, 0, sizeof(zend_internal_function));
+  } else {
+    if (to == NULL) {
+      to = emalloc(sizeof(zend_op_array));
+    }
+    memset(to, 0, sizeof(zend_op_array));
+    if (ZendOptimizer) {
+      zend_llist_apply_with_argument(&zend_extensions, (llist_apply_with_arg_func_t) call_op_array_ctor_handler, to TSRMLS_CC);
+    }
+  }
+  to->type             = from->type;
+#ifdef ZEND_ENGINE_2
+  to->num_args = from->num_args;
+  to->arg_info = from->arg_info;
+  to->pass_rest_by_reference = from->pass_rest_by_reference;
+#else
+  to->arg_types        = from->arg_types;
+#endif
+  to->function_name    = from->function_name;
+#ifdef ZEND_ENGINE_2
+	to->scope            = MMCG(class_entry);
+	to->fn_flags         = from->fn_flags;
+	if (to->scope == NULL && from->scope_name != NULL)
+	{
+		if (zend_hash_find(CG(class_table),
+			(void *)from->scope_name, from->scope_name_len,
+			(void **)&to->scope) == SUCCESS)
+		{
+			to->scope = *(zend_class_entry**)to->scope;
+		}
+		else
+		{
+			debug_printf("[%d] EACCELERATOR can't restore parent class "
+				"\"%s\" of function \"%s\"\n", getpid(),
+				(char*)from->scope_name, to->function_name);
+			to->scope = NULL;
+		}
+	}
+	if (to->scope != NULL)
+	{
+		unsigned int len = strlen(to->function_name);
+		char *lcname = zend_str_tolower_dup(to->function_name, len);
+		/*
+		 * HOESH: this one probably the old style constructor,
+		 * so we set this as the constructor for the scope if
+		 * 0) it doesn't exists yet,
+		 * or, if the constructor is inherited from the parent:
+		 * A) the constructor is internal function
+		 * B) the constructor's scope name doesn't match the oparray's scope name
+		 *
+		 * remember lcname & len can be used as scope name info after the match!
+		 */
+
+		if  (
+				to->scope->name_length == len &&
+				memcmp(to->scope->name, lcname, len) == 0 &&
+				(
+					to->scope->constructor == NULL || // case 0)
+					to->scope->constructor->type == ZEND_INTERNAL_FUNCTION || // case A)
+					to->scope->constructor->op_array.scope->name_length != len || // case B)
+					memcmp(to->scope->constructor->op_array.scope->name, lcname, len) != 0
+				)
+			)
+		{
+			to->scope->constructor = (zend_function*)to;
+		}
+		/* HOESH: To avoid unnecessary lookups */
+		else if (*lcname == '_' && *(lcname+1) == '_')
+		{
+			if (len == sizeof(ZEND_CONSTRUCTOR_FUNC_NAME)-1 &&
+				memcmp(lcname, ZEND_CONSTRUCTOR_FUNC_NAME, sizeof(ZEND_CONSTRUCTOR_FUNC_NAME)) == 0)
+			{
+				to->scope->constructor = (zend_function*)to;
+			}
+			else if (len == sizeof(ZEND_DESTRUCTOR_FUNC_NAME)-1 &&
+				memcmp(lcname, ZEND_DESTRUCTOR_FUNC_NAME, sizeof(ZEND_DESTRUCTOR_FUNC_NAME)) == 0)
+			{
+				to->scope->destructor = (zend_function*)to;
+			}
+			else if (len == sizeof(ZEND_CLONE_FUNC_NAME)-1 &&
+				memcmp(lcname, ZEND_CLONE_FUNC_NAME, sizeof(ZEND_CLONE_FUNC_NAME)) == 0)
+			{
+				to->scope->clone = (zend_function*)to;
+			}
+			else if (len == sizeof(ZEND_GET_FUNC_NAME)-1 &&
+				memcmp(lcname, ZEND_GET_FUNC_NAME, sizeof(ZEND_GET_FUNC_NAME)) == 0)
+			{
+				to->scope->__get = (zend_function*)to;
+			}
+			else if (len == sizeof(ZEND_SET_FUNC_NAME)-1 &&
+				memcmp(lcname, ZEND_SET_FUNC_NAME, sizeof(ZEND_SET_FUNC_NAME)) == 0)
+			{
+				to->scope->__set = (zend_function*)to;
+			}
+			else if (len == sizeof(ZEND_CALL_FUNC_NAME)-1 &&
+				memcmp(lcname, ZEND_CALL_FUNC_NAME, sizeof(ZEND_CALL_FUNC_NAME)) == 0)
+			{
+				to->scope->__call = (zend_function*)to;
+			}
+		}
+		efree(lcname);
+	}
+#endif
+  if (from->type == ZEND_INTERNAL_FUNCTION)
+  {
+	zend_class_entry* ce = MMCG(class_entry);
+    if (ce != NULL &&
+		ce->parent != NULL &&
+		zend_hash_find(&ce->parent->function_table,
+			to->function_name, strlen(to->function_name)+1,
+			(void **) &function)==SUCCESS &&
+		function->type == ZEND_INTERNAL_FUNCTION)
+	{
+#ifdef ZEND_ENGINE_2
+		efree(to);
+		to = (zend_op_array*)function;
+#else
+		((zend_internal_function*)(to))->handler = function->handler;
+#endif
+    }
+	else
+	{
+      /*??? FIXME. I don't know how to fix handler. */
+		/*
+		 * HOESH TODO: must solve this somehow, to avoid returnin
+		 * damaged structure...
+		 */
+    }
+    return to;
+  }
+  to->opcodes          = from->opcodes;
+  to->last = to->size  = from->last;
+  to->T                = from->T;
+  to->brk_cont_array   = from->brk_cont_array;
+  to->last_brk_cont    = from->last_brk_cont;
+/*
+  to->current_brk_cont = -1;
+  to->static_variables = from->static_variables;
+  to->start_op         = to->opcodes;
+  to->backpatch_count  = 0;
+*/
+  to->return_reference = from->return_reference;
+  to->done_pass_two    = 1;
+  to->filename         = from->filename;
+#ifdef ZEND_ENGINE_2
+	/* HOESH: try & catch support */
+	to->try_catch_array   = from->try_catch_array;
+	to->last_try_catch    = from->last_try_catch;
+  to->uses_this        = from->uses_this;
+
+  to->line_start      = from->line_start;
+  to->line_end        = from->line_end;
+  to->doc_comment_len = from->doc_comment_len;
+  to->doc_comment     = from->doc_comment;
+/*???
+  if (from->doc_comment != NULL) {
+    to->doc_comment = emalloc(from->doc_comment_len+1);
+    memcpy(to->doc_comment, from->doc_comment, from->doc_comment_len+1);
+  }
+*/
+#else
+  to->uses_globals     = from->uses_globals;
+#endif
+  if (from->static_variables) {
+    to->static_variables = restore_zval_hash(NULL, from->static_variables);
+    to->static_variables->pDestructor = ZVAL_PTR_DTOR;
+#ifndef ZEND_ENGINE_2
+    if (MMCG(class_entry) != NULL) {
+      Bucket* p = to->static_variables->pListHead;
+      while (p != NULL) {
+        ((zval*)(p->pDataPtr))->refcount = 1;
+        p = p->pListNext;
+      }
+    }
+#endif
+  }
+
+  /* disable deletion in destroy_op_array */
+  ++MMCG(refcount_helper);
+  to->refcount = &MMCG(refcount_helper);
+
+  return to;
+}
+
+static zend_op_array* restore_op_array_ptr(eaccelerator_op_array *from TSRMLS_DC) {
+  return restore_op_array(NULL, from TSRMLS_CC);
+}
+
+static zend_class_entry* restore_class_entry(zend_class_entry* to, eaccelerator_class_entry *from TSRMLS_DC)
+{
+  zend_class_entry *old;
+
+#ifdef DEBUG
+  pad(TSRMLS_C);
+  fprintf(F_fp, "[%d] retore_class_entry: %s\n", getpid(), from->name? from->name : "(top)");
+  fflush(F_fp);
+  MMCG(xpad)++;
+#endif
+  if (to == NULL) {
+    to = emalloc(sizeof(zend_class_entry));
+  }
+  memset(to, 0, sizeof(zend_class_entry));
+  to->type        = from->type;
+/*
+  to->name        = NULL;
+  to->name_length = from->name_length;
+  to->constants_updated = 0;
+  to->parent      = NULL;
+*/
+#ifdef ZEND_ENGINE_2
+  to->ce_flags    = from->ce_flags;
+/*
+  to->static_members = NULL;
+*/
+  to->num_interfaces = from->num_interfaces;
+  if (to->num_interfaces > 0) {
+    to->interfaces = (zend_class_entry **) emalloc(sizeof(zend_class_entry *)*to->num_interfaces);
+/*
+  } else {
+    to->interfaces = NULL;
+*/
+  }
+/*
+  to->create_object = NULL;
+*/
+#endif
+
+  if (from->name != NULL) {
+    to->name_length = from->name_length;
+    to->name = emalloc(from->name_length+1);
+    memcpy(to->name, from->name, from->name_length+1);
+  }
+
+  if (from->parent != NULL)
+  {
+    int name_len = strlen(from->parent);
+    if (zend_hash_find(CG(class_table), (void *)from->parent, name_len+1, (void **)&to->parent) != SUCCESS)
+	{
+      debug_printf("[%d] EACCELERATOR can't restore parent class "
+          "\"%s\" of class \"%s\"\n", getpid(), (char*)from->parent, to->name);
+      to->parent = NULL;
+    }
+	else
+	{
+#ifdef ZEND_ENGINE_2
+	  /*
+	   * HOESH: not sure this is a clean solution on kwestlake's
+	   * problem... Fact: zend_hash_find returned **, but we
+	   * expected * - I've tested this against autoload and
+	   * everything seems to be oK.
+	   */
+	  to->parent = *(zend_class_entry**)to->parent;
+	  /*
+	   * HOESH: ahh, this is really needed. ;)
+	   */
+	  to->constructor  = to->parent->constructor;
+	  to->destructor  = to->parent->destructor;
+	  to->clone  = to->parent->clone;
+	  to->__get  = to->parent->__get;
+      to->__set  = to->parent->__set;
+      to->__call = to->parent->__call;
+	  to->create_object = to->parent->create_object;
+#else
+	  to->handle_property_get  = to->parent->handle_property_get;
+      to->handle_property_set  = to->parent->handle_property_set;
+      to->handle_function_call = to->parent->handle_function_call;
+#endif
+    }
+  }
+  old = MMCG(class_entry);
+  MMCG(class_entry) = to;
+
+#ifdef ZEND_ENGINE_2
+  to->refcount = 1;
+
+  to->line_start      = from->line_start;
+  to->line_end        = from->line_end;
+  to->doc_comment_len = from->doc_comment_len;
+  if (from->filename != NULL) {
+    size_t len = strlen(from->filename)+1;
+    to->filename = emalloc(len);
+    memcpy(to->filename, from->filename, len);
+  }
+  if (from->doc_comment != NULL) {
+    to->doc_comment = emalloc(from->doc_comment_len+1);
+    memcpy(to->doc_comment, from->doc_comment, from->doc_comment_len+1);
+  }
+
+  restore_zval_hash(&to->constants_table, &from->constants_table);
+  to->constants_table.pDestructor = ZVAL_PTR_DTOR;
+  restore_zval_hash(&to->default_properties, &from->default_properties);
+  to->default_properties.pDestructor = ZVAL_PTR_DTOR;
+  restore_hash(&to->properties_info, &from->properties_info, (restore_bucket_t)restore_property_info TSRMLS_CC);
+  if (from->static_members != NULL) {
+    ALLOC_HASHTABLE(to->static_members);
+    restore_zval_hash(to->static_members, from->static_members);
+    to->static_members->pDestructor = ZVAL_PTR_DTOR;
+/*
+  } else {
+    ALLOC_HASHTABLE(to->static_members);
+    zend_hash_init_ex(to->static_members, 0, NULL, ZVAL_PTR_DTOR, 0, 0);
+*/
+  }
+/*??? FIXME
+    to->properties_info.pDestructor = (dtor_func_t) zend_destroy_property_info;
+*/
+#else
+  to->refcount = emalloc(sizeof(*to->refcount));
+  *to->refcount = 1;
+
+  restore_zval_hash(&to->default_properties, &from->default_properties);
+  to->default_properties.pDestructor = ZVAL_PTR_DTOR;
+  /* Clearing references */
+  {
+    Bucket* p = to->default_properties.pListHead;
+    while (p != NULL) {
+      ((zval*)(p->pDataPtr))->refcount = 1;
+      p = p->pListNext;
+    }
+  }
+#endif
+  restore_hash(&to->function_table, &from->function_table, (restore_bucket_t)restore_op_array_ptr TSRMLS_CC);
+  to->function_table.pDestructor = ZEND_FUNCTION_DTOR;
+
+  MMCG(class_entry) = old;
+
+#ifdef DEBUG
+  MMCG(xpad)--;
+#endif
+
+  return to;
+}
+
+static void restore_function(mm_fc_entry *p TSRMLS_DC) {
+  zend_op_array op_array;
+
+  if ((p->htabkey[0] == '\000') &&
+      zend_hash_exists(CG(function_table), p->htabkey, p->htablen)) {
+    return;
+  }
+  if (restore_op_array(&op_array, (eaccelerator_op_array *)p->fc TSRMLS_CC) != NULL) {
+    if (zend_hash_add(CG(function_table), p->htabkey, p->htablen,
+        &op_array, sizeof(zend_op_array), NULL) == FAILURE) {
+      CG(in_compilation) = 1;
+      CG(compiled_filename) = MMCG(mem);
+#ifdef ZEND_ENGINE_2
+      CG(zend_lineno) = op_array.line_start;
+#else
+      CG(zend_lineno) = op_array.opcodes[0].lineno;
+#endif
+      zend_error(E_ERROR, "Cannot redeclare %s()", p->htabkey);
+    }
+  }
+}
+
+/*
+ * Class handling.
+ */
+static void restore_class(mm_fc_entry *p TSRMLS_DC) {
+#ifdef ZEND_ENGINE_2
+  zend_class_entry *ce;
+#else
+  zend_class_entry ce;
+#endif
+
+  if ((p->htabkey[0] == '\000') &&
+      zend_hash_exists(CG(class_table), p->htabkey, p->htablen)) {
+    return;
+  }
+#ifdef ZEND_ENGINE_2
+  ce = restore_class_entry(NULL, (eaccelerator_class_entry *)p->fc TSRMLS_CC);
+  if (ce != NULL) {
+    if (zend_hash_add(CG(class_table), p->htabkey, p->htablen,
+                      &ce, sizeof(zend_class_entry*), NULL) == FAILURE) {
+#else
+  if (restore_class_entry(&ce, (eaccelerator_class_entry *)p->fc TSRMLS_CC) != NULL) {
+    if (zend_hash_add(CG(class_table), p->htabkey, p->htablen,
+                      &ce, sizeof(zend_class_entry), NULL) == FAILURE) {
+#endif
+      CG(in_compilation) = 1;
+      CG(compiled_filename) = MMCG(mem);
+#ifdef ZEND_ENGINE_2
+      CG(zend_lineno) = ce->line_start;
+#else
+      CG(zend_lineno) = 0;
+#endif
+      zend_error(E_ERROR, "Cannot redeclare class %s", p->htabkey);
+    }
+  }
+}
+
+/*
+ * Try to restore a file from the cache.
+ */
+static zend_op_array* eaccelerator_restore(char *realname, struct stat *buf,
+                                      int *nreloads, time_t compile_time TSRMLS_DC) {
+  mm_cache_entry *p;
+  zend_op_array *op_array = NULL;
+
+  *nreloads = 1;
+  EACCELERATOR_UNPROTECT();
+  p = hash_find_mm(realname, buf, nreloads,
+                   ((eaccelerator_shm_ttl > 0)?(compile_time + eaccelerator_shm_ttl):0));
+  if (p == NULL && !eaccelerator_scripts_shm_only) {
+    p = hash_find_file(realname, buf TSRMLS_CC);
+  }
+  EACCELERATOR_PROTECT();
+  if (p != NULL && p->op_array != NULL) {
+    MMCG(class_entry) = NULL;
+    op_array = restore_op_array(NULL, p->op_array TSRMLS_CC);
+    if (op_array != NULL) {
+      mm_fc_entry *e;
+      mm_used_entry *used = emalloc(sizeof(mm_used_entry));
+      used->entry  = p;
+      used->next   = (mm_used_entry*)MMCG(used_entries);
+      MMCG(used_entries) = (void*)used;
+      MMCG(mem) = op_array->filename;
+      for (e = p->c_head; e!=NULL; e = e->next) {
+        restore_class(e TSRMLS_CC);
+      }
+      for (e = p->f_head; e!=NULL; e = e->next) {
+        restore_function(e TSRMLS_CC);
+      }
+      MMCG(mem) = p->realfilename;
+    }
+  }
+  return op_array;
+}
+
+/*
+ * Only files matching user specified conditions should be cached.
+ *
+ * TODO - check the algorithm (fl)
+ */
+
+static int match(const char* name, const char* pat) {
+  char p,k;
+  int ok, neg;
+
+  while (1) {
+    p = *pat++;
+    if (p == '\0') {
+      return (*name == '\0');
+    } else if (p == '*') {
+      if (*pat == '\0') {
+        return 1;
+      }
+      do {
+        if (match(name, pat)) {
+          return 1;
+        }
+      } while (*name++ != '\0');
+      return 0;
+    } else if (p == '?') {
+      if (*name++ == '\0') {
+        return 0;
+      }
+    } else if (p == '[') {
+      ok = 0;
+      if ((k = *name++) == '\0') {
+        return 0;
+      }
+      if ((neg = (*pat == '!')) != '\0') {
+        ++pat;
+      }
+      while ((p = *pat++) != ']') {
+        if (*pat == '-') {
+          if (p <= k && k <= pat[1]) {
+            ok = 1;
+          }
+          pat += 2;
+        } else {
+          if (p == '\\') {
+            p = *pat++;
+            if (p == '\0') {
+              p ='\\';
+              pat--;
+            }
+          }
+          if (p == k) {
+            ok = 1;
+          }
+        }
+      }
+      if (ok == neg) {
+        return 0;
+      }
+    } else {
+      if (p == '\\') {
+        p = *pat++;
+        if (p == '\0') {
+          p ='\\';
+          pat--;
+        }
+      }
+      if (*name++ != p) {
+        return 0;
+      }
+    }
+  }
+  return (*name == '\0');
+}
+
+static int eaccelerator_ok_to_cache(char *realname TSRMLS_DC) {
+  mm_cond_entry *p;
+  int ok;
+
+  if (MMCG(cond_list) == NULL) {
+    return 1;
+  }
+
+  /* if "realname" matches to any pattern started with "!" then ignore it */
+  for (p = MMCG(cond_list); p != NULL; p = p->next) {
+    if (p->not && match(realname, p->str)) {
+      return 0;
+    }
+  }
+
+  /* else if it matches to any pattern not started with "!" then accept it */
+  ok = 1;
+  for (p = MMCG(cond_list); p != NULL; p = p->next) {
+    if (!p->not) {
+      ok = 0;
+      if (match(realname, p->str)) {
+        return 1;
+      }
+    }
+  }
+  return ok;
+}
+
+/******************************************************************************/
+static char* eaccelerator_realpath(const char* name, char* realname TSRMLS_DC) {
+/* ???TODO it is possibe to cache name->realname mapping to avoid lstat() calls */
+#if ZEND_MODULE_API_NO >= 20001222
+  return VCWD_REALPATH(name, realname);
+#else
+  return V_REALPATH(name, realname);
+#endif
+}
+
+static int eaccelerator_stat(zend_file_handle *file_handle,
+                        char* realname, struct stat* buf TSRMLS_DC) {
+#ifdef EACCELERATOR_USE_INODE
+#ifndef ZEND_WIN32
+  if (file_handle->type == ZEND_HANDLE_FP && file_handle->handle.fp != NULL) {
+    if (fstat(fileno(file_handle->handle.fp), buf) == 0 &&
+       S_ISREG(buf->st_mode)) {
+      if (file_handle->opened_path != NULL) {
+        strcpy(realname,file_handle->opened_path);
+      }
+      return 0;
+    }
+  } else
+#endif
+  if (file_handle->opened_path != NULL) {
+    if (stat(file_handle->opened_path, buf) == 0 &&
+        S_ISREG(buf->st_mode)) {
+       strcpy(realname,file_handle->opened_path);
+       return 0;
+    }
+  } else if (PG(include_path) == NULL ||
+             file_handle->filename[0] == '.' ||
+             IS_SLASH(file_handle->filename[0]) ||
+             IS_ABSOLUTE_PATH(file_handle->filename,strlen(file_handle->filename))) {
+    if (stat(file_handle->filename, buf) == 0 &&
+        S_ISREG(buf->st_mode)) {
+       return 0;
+    }
+  } else {
+    char* ptr = PG(include_path);
+    char* end;
+    int   len;
+    char  tryname[MAXPATHLEN];
+    int   filename_len = strlen(file_handle->filename);
+
+    while (ptr && *ptr) {
+      end = strchr(ptr, DEFAULT_DIR_SEPARATOR);
+      if (end != NULL) {
+        len = end-ptr;
+        end++;
+      } else {
+        len = strlen(ptr);
+        end = ptr+len;
+      }
+      if (len+filename_len+2 < MAXPATHLEN) {
+        memcpy(tryname, ptr, len);
+        tryname[len] = '/';
+        memcpy(tryname+len+1, file_handle->filename, filename_len);
+        tryname[len+filename_len+1] = '\0';
+        if (stat(tryname, buf) == 0 &&
+            S_ISREG(buf->st_mode)) {
+          return 0;
+        }
+      }
+      ptr = end;
+    }
+  }
+  return -1;
+#else
+  if (file_handle->opened_path != NULL) {
+    strcpy(realname,file_handle->opened_path);
+#ifndef ZEND_WIN32
+    if (file_handle->type == ZEND_HANDLE_FP && file_handle->handle.fp != NULL) {
+      if (!eaccelerator_check_mtime) {
+        return 0;
+      } else if (fstat(fileno(file_handle->handle.fp), buf) == 0 &&
+                 S_ISREG(buf->st_mode)) {
+        return 0;
+      } else {
+        return -1;
+      }
+    } else {
+      if (!eaccelerator_check_mtime) {
+        return 0;
+      } else if (stat(realname, buf) == 0 &&
+                 S_ISREG(buf->st_mode)) {
+        return 0;
+      } else {
+        return -1;
+      }
+    }
+#else
+    if (!eaccelerator_check_mtime) {
+      return 0;
+    } else if (stat(realname, buf) == 0 &&
+               S_ISREG(buf->st_mode)) {
+      return 0;
+    } else {
+      return -1;
+    }
+#endif
+  } else if (file_handle->filename == NULL) {
+    return -1;
+  } else if (PG(include_path) == NULL ||
+             file_handle->filename[0] == '.' ||
+             IS_SLASH(file_handle->filename[0]) ||
+             IS_ABSOLUTE_PATH(file_handle->filename,strlen(file_handle->filename))) {
+    if (eaccelerator_realpath(file_handle->filename, realname TSRMLS_CC)) {
+      if (!eaccelerator_check_mtime) {
+        return 0;
+      } else if (stat(realname, buf) == 0 &&
+                 S_ISREG(buf->st_mode)) {
+        return 0;
+      } else {
+        return -1;
+      }
+    }
+  } else {
+    char* ptr = PG(include_path);
+    char* end;
+    int   len;
+    char  tryname[MAXPATHLEN];
+    int   filename_len = strlen(file_handle->filename);
+
+    while (ptr && *ptr) {
+      end = strchr(ptr, DEFAULT_DIR_SEPARATOR);
+      if (end != NULL) {
+        len = end-ptr;
+        end++;
+      } else {
+        len = strlen(ptr);
+        end = ptr+len;
+      }
+      if (len+filename_len+2 < MAXPATHLEN) {
+        memcpy(tryname, ptr, len);
+        tryname[len] = '/';
+        memcpy(tryname+len+1, file_handle->filename, filename_len);
+        tryname[len+filename_len+1] = '\0';
+        if (eaccelerator_realpath(tryname, realname TSRMLS_CC)) {
+#ifdef ZEND_WIN32
+          if (stat(realname, buf) == 0 &&
+              S_ISREG(buf->st_mode)) {
+            return 0;
+          }
+#else
+          if (!eaccelerator_check_mtime) {
+            return 0;
+          } else if (stat(realname, buf) == 0 &&
+                     S_ISREG(buf->st_mode)) {
+            return 0;
+          } else {
+            return -1;
+          }
+#endif
+        }
+      }
+      ptr = end;
+    }
+  }
+  return -1;
+#endif
+}
+
+/*
+ * Intercept compilation of PHP file.  If we already have the file in
+ * our cache, restore it.  Otherwise call the original Zend compilation
+ * function and store the compiled zend_op_array in out cache.
+ * This function is called again for each PHP file included in the
+ * main PHP file.
+ */
+ZEND_DLEXPORT zend_op_array* eaccelerator_compile_file(zend_file_handle *file_handle, int type TSRMLS_DC) {
+  zend_op_array *t;
+  struct stat buf;
+  char  realname[MAXPATHLEN];
+  int   nreloads;
+  time_t compile_time;
+
+#ifdef EACCELERATOR_USE_INODE
+  realname[0] = '\000';
+#endif
+#if defined(DEBUG) || defined(TEST_PERFORMANCE)
+#ifdef TEST_PERFORMANCE
+  struct timeval tv_start;
+  fprintf(F_fp, "[%d] Enter COMPILE\n",getpid()); fflush(F_fp);
+  start_time(&tv_start);
+#endif
+  fprintf(F_fp, "[%d] Enter COMPILE\n",getpid()); fflush(F_fp);
+  fprintf(F_fp, "[%d] compile_file: \"%s\"\n",getpid(), file_handle->filename); fflush(F_fp);
+  MMCG(xpad)+=2;
+#endif
+  if (!MMCG(enabled) ||
+      (eaccelerator_mm_instance == NULL) ||
+      !eaccelerator_mm_instance->enabled ||
+      file_handle == NULL ||
+      file_handle->filename == NULL ||
+      eaccelerator_stat(file_handle, realname, &buf TSRMLS_CC) != 0 ||
+      buf.st_mtime >= (compile_time = time(0)) ||
+#ifdef EACCELERATOR_USE_INODE
+      0) {
+#else
+      !eaccelerator_ok_to_cache(realname TSRMLS_CC)) {
+#endif
+#if defined(DEBUG) || defined(TEST_PERFORMANCE)
+    fprintf(F_fp, "\t[%d] compile_file: compiling\n",getpid()); fflush(F_fp);
+#endif
+    t = mm_saved_zend_compile_file(file_handle, type TSRMLS_CC);
+#if defined(DEBUG) || defined(TEST_PERFORMANCE)
+#ifdef TEST_PERFORMANCE
+    fprintf(F_fp, "\t[%d] compile_file: end (%ld)\n",getpid(),elapsed_time(&tv_start)); fflush(F_fp);
+#else
+    fprintf(F_fp, "\t[%d] compile_file: end\n",getpid()); fflush(F_fp);
+#endif
+    MMCG(xpad)-=2;
+#endif
+#if defined(DEBUG)
+    fprintf(F_fp, "[%d] Leave COMPILE\n",getpid()); fflush(F_fp);
+#endif
+    return t;
+  }
+
+  t = eaccelerator_restore(realname, &buf, &nreloads, compile_time TSRMLS_CC);
+
+  if (t != NULL) {
+    if (eaccelerator_debug > 0) {
+      debug_printf("[%d] EACCELERATOR hit: \"%s\"\n", getpid(), t->filename);
+    }
+    /* restored from cache */
+
+    zend_llist_add_element(&CG(open_files), file_handle);
+#ifdef ZEND_ENGINE_2
+    if (file_handle->opened_path == NULL && file_handle->type != ZEND_HANDLE_STREAM) {
+      file_handle->handle.stream.handle = (void*)1;
+#else
+    if (file_handle->opened_path == NULL && file_handle->type != ZEND_HANDLE_FP) {
+      int dummy = 1;
+      file_handle->opened_path = MMCG(mem);
+      zend_hash_add(&EG(included_files), file_handle->opened_path, strlen(file_handle->opened_path)+1, (void *)&dummy, sizeof(int), NULL);
+      file_handle->handle.fp = NULL;
+#endif
+/*??? I don't understud way estrdup is not need
+      file_handle->opened_path = estrdup(MMCG(mem));
+*/
+    }
+#if defined(DEBUG) || defined(TEST_PERFORMANCE)
+#ifdef TEST_PERFORMANCE
+    fprintf(F_fp, "\t[%d] compile_file: restored (%ld)\n",getpid(),elapsed_time(&tv_start)); fflush(F_fp);
+#else
+    fprintf(F_fp, "\t[%d] compile_file: restored\n",getpid()); fflush(F_fp);
+#endif
+    MMCG(xpad)-=2;
+#endif
+#if defined(DEBUG)
+    fprintf(F_fp, "[%d] Leave COMPILE\n",getpid()); fflush(F_fp);
+#endif
+    return t;
+  } else {
+    /* not in cache or must be recompiled */
+    Bucket *function_table_tail;
+    Bucket *class_table_tail;
+    HashTable* orig_function_table;
+    HashTable* orig_class_table;
+    HashTable tmp_function_table;
+    HashTable tmp_class_table;
+    zend_function tmp_func;
+    zend_class_entry tmp_class;
+    int bailout;
+
+#if defined(DEBUG) || defined(TEST_PERFORMANCE)
+    fprintf(F_fp, "\t[%d] compile_file: marking\n",getpid()); fflush(F_fp);
+#endif
+
+    zend_hash_init_ex(&tmp_function_table, 100, NULL, ZEND_FUNCTION_DTOR, 1, 0);
+    zend_hash_copy(&tmp_function_table, &eaccelerator_global_function_table, NULL, &tmp_func, sizeof(zend_function));
+    orig_function_table = CG(function_table);
+    CG(function_table) = &tmp_function_table;
+
+    zend_hash_init_ex(&tmp_class_table, 10, NULL, ZEND_CLASS_DTOR, 1, 0);
+    zend_hash_copy(&tmp_class_table, &eaccelerator_global_class_table, NULL, &tmp_class, sizeof(zend_class_entry));
+    orig_class_table = CG(class_table);;
+    CG(class_table) = &tmp_class_table;
+
+    /* Storing global pre-compiled functions and classes */
+    function_table_tail = CG(function_table)->pListTail;
+    class_table_tail = CG(class_table)->pListTail;
+
+#if defined(DEBUG) || defined(TEST_PERFORMANCE)
+#ifdef TEST_PERFORMANCE
+    fprintf(F_fp, "\t[%d] compile_file: compiling (%ld)\n",getpid(),elapsed_time(&tv_start)); fflush(F_fp);
+#else
+    fprintf(F_fp, "\t[%d] compile_file: compiling\n",getpid()); fflush(F_fp);
+#endif
+#endif
+    if (MMCG(optimizer_enabled) && eaccelerator_mm_instance->optimizer_enabled) {
+      MMCG(compiler) = 1;
+    }
+
+    bailout = 0;
+    zend_try {
+      t = mm_saved_zend_compile_file(file_handle, type TSRMLS_CC);
+    } zend_catch {
+      CG(function_table) = orig_function_table;
+      CG(class_table) = orig_class_table;
+      bailout = 1;
+    } zend_end_try();
+    if (bailout) {
+      zend_bailout();
+    }
+
+/*???
+    if (file_handle->opened_path == NULL && t != NULL) {
+      file_handle->opened_path = t->filename;
+    }
+*/
+    MMCG(compiler) = 0;
+    if (t != NULL &&
+        file_handle->opened_path != NULL &&
+#ifdef EACCELERATOR_USE_INODE
+        eaccelerator_ok_to_cache(file_handle->opened_path TSRMLS_CC)) {
+#else
+        (eaccelerator_check_mtime ||
+         ((stat(file_handle->opened_path, &buf) == 0) && S_ISREG(buf.st_mode)))) {
+#endif
+#if defined(DEBUG) || defined(TEST_PERFORMANCE)
+#ifdef TEST_PERFORMANCE
+      fprintf(F_fp, "\t[%d] compile_file: storing in cache (%ld)\n",getpid(),elapsed_time(&tv_start)); fflush(F_fp);
+#else
+      fprintf(F_fp, "\t[%d] compile_file: storing in cache\n",getpid()); fflush(F_fp);
+#endif
+#endif
+#ifdef WITH_EACCELERATOR_LOADER
+      if (t->last >= 3 &&
+          t->opcodes[0].opcode == ZEND_SEND_VAL &&
+          t->opcodes[1].opcode == ZEND_DO_FCALL &&
+          t->opcodes[2].opcode == ZEND_RETURN &&
+          t->opcodes[1].op1.op_type == IS_CONST &&
+          t->opcodes[1].op1.u.constant.type == IS_STRING &&
+          t->opcodes[1].op1.u.constant.value.str.len == sizeof("eaccelerator_load")-1 &&
+          (memcmp(t->opcodes[1].op1.u.constant.value.str.val, "eaccelerator_load", sizeof("eaccelerator_load")-1) == 0) &&
+          t->opcodes[0].op1.op_type == IS_CONST &&
+          t->opcodes[0].op1.u.constant.type == IS_STRING) {
+        zend_op_array* new_t;
+        zend_bool old_in_compilation = CG(in_compilation);
+        char* old_filename = CG(compiled_filename);
+        int old_lineno = CG(zend_lineno);
+
+        CG(in_compilation) = 1;
+        zend_set_compiled_filename(t->filename TSRMLS_CC);
+        CG(zend_lineno) = t->opcodes[1].lineno;
+        new_t = eaccelerator_load(
+          t->opcodes[0].op1.u.constant.value.str.val,
+          t->opcodes[0].op1.u.constant.value.str.len TSRMLS_CC);
+        CG(in_compilation) = old_in_compilation;
+        CG(compiled_filename) = old_filename;
+        CG(zend_lineno) = old_lineno;
+        if (new_t != NULL) {
+#ifdef ZEND_ENGINE_2
+          destroy_op_array(t TSRMLS_CC);
+#else
+          destroy_op_array(t);
+#endif
+          efree(t);
+          t = new_t;
+        }
+      }
+#endif
+      function_table_tail = function_table_tail?function_table_tail->pListNext:
+                                                CG(function_table)->pListHead;
+      class_table_tail = class_table_tail?class_table_tail->pListNext:
+                                          CG(class_table)->pListHead;
+      if (eaccelerator_store(file_handle->opened_path, &buf, nreloads, t,
+                        function_table_tail, class_table_tail TSRMLS_CC)) {
+        if (eaccelerator_debug > 0) {
+          debug_printf("[%d] EACCELERATOR %s: \"%s\"\n", getpid(),
+              (nreloads == 1) ? "cached" : "re-cached", file_handle->opened_path);
+        }
+      } else {
+        if (eaccelerator_debug > 0) {
+          debug_printf("[%d] EACCELERATOR cann't cache: \"%s\"\n", getpid(), file_handle->opened_path);
+        }
+      }
+    } else {
+      function_table_tail = function_table_tail?function_table_tail->pListNext:
+                                                CG(function_table)->pListHead;
+      class_table_tail = class_table_tail?class_table_tail->pListNext:
+                                          CG(class_table)->pListHead;
+    }
+    CG(function_table) = orig_function_table;
+    CG(class_table) = orig_class_table;
+    while (function_table_tail != NULL) {
+      zend_op_array *op_array = (zend_op_array*)function_table_tail->pData;
+      if (op_array->type == ZEND_USER_FUNCTION) {
+        if (zend_hash_add(CG(function_table),
+                          function_table_tail->arKey,
+                          function_table_tail->nKeyLength,
+                          op_array, sizeof(zend_op_array), NULL) == FAILURE &&
+            function_table_tail->arKey[0] != '\000') {
+          CG(in_compilation) = 1;
+          CG(compiled_filename) = file_handle->opened_path;
+#ifdef ZEND_ENGINE_2
+          CG(zend_lineno) = op_array->line_start;
+#else
+          CG(zend_lineno) = op_array->opcodes[0].lineno;
+#endif
+          zend_error(E_ERROR, "Cannot redeclare %s()", function_table_tail->arKey);
+        }
+      }
+      function_table_tail = function_table_tail->pListNext;
+    }
+    while (class_table_tail != NULL) {
+#ifdef ZEND_ENGINE_2
+      zend_class_entry **ce = (zend_class_entry**)class_table_tail->pData;
+      if ((*ce)->type == ZEND_USER_CLASS) {
+        if (zend_hash_add(CG(class_table),
+                          class_table_tail->arKey,
+                          class_table_tail->nKeyLength,
+                          ce, sizeof(zend_class_entry*), NULL) == FAILURE &&
+            class_table_tail->arKey[0] != '\000') {
+          CG(in_compilation) = 1;
+          CG(compiled_filename) = file_handle->opened_path;
+          CG(zend_lineno) = (*ce)->line_start;
+#else
+      zend_class_entry *ce = (zend_class_entry*)class_table_tail->pData;
+      if (ce->type == ZEND_USER_CLASS) {
+        if (ce->parent != NULL) {
+          if (zend_hash_find(CG(class_table), (void*)ce->parent->name, ce->parent->name_length+1, (void **)&ce->parent) != SUCCESS)
+		  {
+            ce->parent = NULL;
+          }
+        }
+        if (zend_hash_add(CG(class_table),
+                          class_table_tail->arKey,
+                          class_table_tail->nKeyLength,
+                          ce, sizeof(zend_class_entry), NULL) == FAILURE &&
+            class_table_tail->arKey[0] != '\000') {
+          CG(in_compilation) = 1;
+          CG(compiled_filename) = file_handle->opened_path;
+          CG(zend_lineno) = 0;
+#endif
+          zend_error(E_ERROR, "Cannot redeclare class %s", class_table_tail->arKey);
+        }
+      }
+      class_table_tail = class_table_tail->pListNext;
+    }
+    tmp_function_table.pDestructor = NULL;
+    tmp_class_table.pDestructor = NULL;
+    zend_hash_destroy(&tmp_function_table);
+    zend_hash_destroy(&tmp_class_table);
+  }
+#if defined(DEBUG) || defined(TEST_PERFORMANCE)
+#ifdef TEST_PERFORMANCE
+  fprintf(F_fp, "\t[%d] compile_file: end (%ld)\n",getpid(),elapsed_time(&tv_start)); fflush(F_fp);
+#else
+  fprintf(F_fp, "\t[%d] compile_file: end\n",getpid()); fflush(F_fp);
+#endif
+  MMCG(xpad)-=2;
+  fflush(F_fp);
+#endif
+#if defined(DEBUG)
+  fprintf(F_fp, "[%d] Leave COMPILE\n",getpid()); fflush(F_fp);
+#endif
+  return t;
+}
+
+#ifdef PROFILE_OPCODES
+static void profile_execute(zend_op_array *op_array TSRMLS_DC)
+{
+  int i;
+  struct timeval tv_start;
+  long usec;
+
+  for (i=0;i<MMCG(profile_level);i++)
+    fputs("  ", F_fp);
+  fprintf(F_fp,"enter: %s:%s\n", op_array->filename, op_array->function_name);
+  fflush(F_fp);
+  start_time(&tv_start);
+  MMCG(self_time)[MMCG(profile_level)] = 0;
+  MMCG(profile_level)++;
+#ifdef WITH_EACCELERATOR_EXECUTOR
+  eaccelerator_execute(op_array TSRMLS_CC);
+#else
+  mm_saved_zend_execute(op_array TSRMLS_CC);
+#endif
+  usec = elapsed_time(&tv_start);
+  MMCG(profile_level)--;
+  if (MMCG(profile_level) > 0)
+    MMCG(self_time)[MMCG(profile_level)-1] += usec;
+  for (i=0;i<MMCG(profile_level);i++)
+    fputs("  ", F_fp);
+  fprintf(F_fp,"leave: %s:%s (%ld,%ld)\n", op_array->filename, op_array->function_name, usec, usec-MMCG(self_time)[MMCG(profile_level)]);
+  fflush(F_fp);
+}
+
+ZEND_DLEXPORT zend_op_array* profile_compile_file(zend_file_handle *file_handle, int type TSRMLS_DC) {
+  zend_op_array *t;
+  int i;
+  struct timeval tv_start;
+  long usec;
+
+  start_time(&tv_start);
+  MMCG(self_time)[MMCG(profile_level)] = 0;
+  t = eaccelerator_compile_file(file_handle, type TSRMLS_CC);
+  usec = elapsed_time(&tv_start);
+  if (MMCG(profile_level) > 0)
+    MMCG(self_time)[MMCG(profile_level)-1] += usec;
+  for (i=0;i<MMCG(profile_level);i++)
+    fputs("  ", F_fp);
+  fprintf(F_fp,"compile: %s (%ld)\n", file_handle->filename, usec);
+  fflush(F_fp);
+  return t;
+}
+
+#endif  /* #ifdef PROFILE_OPCODES */
+
+/* Format Bytes */
+static void format_size(char* s, unsigned int size, int legend) {
+  unsigned int i = 0;
+  unsigned int n = 0;
+  char ch;
+  do {
+    if ((n != 0) && (n % 3 == 0)) {
+      s[i++] = ',';
+    }
+    s[i++] = (char)((int)'0' + (size % 10));
+    n++;
+    size = size / 10;
+  } while (size != 0);
+  s[i] = '\0';
+  n = 0; i--;
+  while (n < i) {
+    ch = s[n];
+    s[n] = s[i];
+    s[i] = ch;
+    n++, i--;
+  }
+  if (legend) {
+    strcat(s, " Bytes");
+  }
+}
+
+PHP_MINFO_FUNCTION(eaccelerator) {
+  char s[32];
+
+  php_info_print_table_start();
+  php_info_print_table_header(2, "eAccelerator support", "enabled");
+  php_info_print_table_row(2, "Version", EACCELERATOR_VERSION);
+  php_info_print_table_row(2, "Caching Enabled", (MMCG(enabled) && (eaccelerator_mm_instance != NULL) && eaccelerator_mm_instance->enabled)?"true":"false");
+  php_info_print_table_row(2, "Optimizer Enabled", (MMCG(optimizer_enabled) && (eaccelerator_mm_instance != NULL) && eaccelerator_mm_instance->optimizer_enabled)?"true":"false");
+  if (eaccelerator_mm_instance != NULL) {
+    size_t available;
+    EACCELERATOR_UNPROTECT();
+    available = mm_available(eaccelerator_mm_instance->mm);
+    EACCELERATOR_LOCK_RD();
+    EACCELERATOR_PROTECT();
+    format_size(s, eaccelerator_mm_instance->total, 1);
+    php_info_print_table_row(2, "Memory Size", s);
+    format_size(s, available, 1);
+    php_info_print_table_row(2, "Memory Available", s);
+    format_size(s, eaccelerator_mm_instance->total - available, 1);
+    php_info_print_table_row(2, "Memory Allocated", s);
+    snprintf(s, 32, "%u", eaccelerator_mm_instance->hash_cnt);
+    php_info_print_table_row(2, "Cached Scripts", s);
+    snprintf(s, 32, "%u", eaccelerator_mm_instance->rem_cnt);
+    php_info_print_table_row(2, "Removed Scripts", s);
+    snprintf(s, 32, "%u", eaccelerator_mm_instance->user_hash_cnt);
+    php_info_print_table_row(2, "Cached Keys", s);
+    EACCELERATOR_UNPROTECT();
+    EACCELERATOR_UNLOCK_RD();
+    EACCELERATOR_PROTECT();
+  }
+  php_info_print_table_end();
+
+  DISPLAY_INI_ENTRIES();
+}
+
+/* User Cache Routines (put, get, rm, gc) */
+
+static char* build_key(const char* key, int key_len, int *xlen TSRMLS_DC) {
+  int len = strlen(MMCG(hostname));
+  if (len > 0) {
+    char* xkey;
+    *xlen = len + key_len + 1;
+    xkey = emalloc((*xlen)+1);
+    memcpy(xkey, MMCG(hostname), len);
+    xkey[len] = ':';
+    memcpy(xkey+len+1, key, key_len+1);
+    return xkey;
+  } else {
+    *xlen = key_len;
+    return (char*)key;
+  }
+}
+
+static int eaccelerator_lock(const char* key, int key_len TSRMLS_DC) {
+  int xlen;
+  char* xkey;
+  mm_lock_entry* x;
+  mm_lock_entry** p;
+  int ok = 0;
+
+  if (eaccelerator_mm_instance == NULL) {
+    return 0;
+  }
+  xkey = build_key(key, key_len, &xlen TSRMLS_CC);
+  EACCELERATOR_UNPROTECT();
+  x = eaccelerator_malloc(offsetof(mm_lock_entry,key)+xlen+1);
+  if (x == NULL) {
+    EACCELERATOR_PROTECT();
+    if (xlen != key_len) {efree(xkey);}
+    return 0;
+  }
+  x->pid = getpid();
+#ifdef ZTS
+  x->thread = tsrm_thread_id();
+#endif
+  x->next = NULL;
+  memcpy(x->key, xkey, xlen+1);
+  while (1) {
+    EACCELERATOR_LOCK_RW();
+    p = &eaccelerator_mm_instance->locks;
+    while ((*p) != NULL) {
+      if (strcmp((*p)->key,x->key) == 0) {
+#ifdef ZTS
+        if (x->pid == (*p)->pid && x->thread == (*p)->thread) {
+#else
+        if (x->pid == (*p)->pid) {
+#endif
+          ok = 1;
+          eaccelerator_free_nolock(x);
+        }
+        break;
+      }
+      p = &(*p)->next;
+    }
+    if ((*p) == NULL) {
+      *p = x;
+      ok = 1;
+    }
+    EACCELERATOR_UNLOCK_RW();
+    if (ok) {
+      break;
+    } else {
+#ifdef ZEND_WIN32
+      Sleep(100);
+/*???
+#elif defined(HAVE_SCHED_YIELD)
+      sched_yield();
+*/
+#else
+      struct timeval t;
+      t.tv_sec = 0;
+      t.tv_usec = 100;
+      select(0, NULL, NULL, NULL, &t);
+#endif
+    }
+  }
+  EACCELERATOR_PROTECT();
+  if (xlen != key_len) {efree(xkey);}
+  return 1;
+}
+
+static int eaccelerator_unlock(const char* key, int key_len TSRMLS_DC) {
+  int xlen;
+  char* xkey;
+  mm_lock_entry** p;
+
+  if (eaccelerator_mm_instance == NULL) {
+    return 0;
+  }
+  xkey = build_key(key, key_len, &xlen TSRMLS_CC);
+  EACCELERATOR_UNPROTECT();
+  EACCELERATOR_LOCK_RW();
+  p = &eaccelerator_mm_instance->locks;
+  while ((*p) != NULL) {
+    if (strcmp((*p)->key,xkey) == 0) {
+#ifdef ZTS
+      if ((*p)->pid == getpid() && (*p)->thread == tsrm_thread_id()) {
+#else
+      if ((*p)->pid == getpid()) {
+#endif
+         mm_lock_entry *x = (*p);
+        *p = (*p)->next;
+        eaccelerator_free_nolock(x);
+      } else {
+        EACCELERATOR_UNLOCK_RW();
+        EACCELERATOR_PROTECT();
+        if (xlen != key_len) {efree(xkey);}
+        return 0;
+      }
+      break;
+    }
+    p = &(*p)->next;
+  }
+  EACCELERATOR_UNLOCK_RW();
+  EACCELERATOR_PROTECT();
+  if (xlen != key_len) {efree(xkey);}
+  return 1;
+}
+
+int eaccelerator_put(const char* key, int key_len, zval* val, time_t ttl, eaccelerator_cache_place where TSRMLS_DC) {
+  mm_user_cache_entry *p, *q;
+  unsigned int slot;
+  long size;
+  int use_shm = 1;
+  int ret = 0;
+  char s[MAXPATHLEN];
+  int xlen;
+  char* xkey;
+
+  xkey = build_key(key, key_len, &xlen TSRMLS_CC);
+  MMCG(compress) = 1;
+  MMCG(mem) = NULL;
+  zend_hash_init(&MMCG(strings), 0, NULL, NULL, 0);
+  EACCELERATOR_ALIGN(MMCG(mem));
+  MMCG(mem) += offsetof(mm_user_cache_entry, key)+xlen+1;
+  calc_zval(val TSRMLS_CC);
+  zend_hash_destroy(&MMCG(strings));
+
+  size = (long)MMCG(mem);
+
+  MMCG(mem) = NULL;
+  if (eaccelerator_mm_instance != NULL &&
+      (where == eaccelerator_shm_and_disk ||
+       where == eaccelerator_shm ||
+       where == eaccelerator_shm_only)) {
+    EACCELERATOR_UNPROTECT();
+    if (eaccelerator_shm_max == 0 || size <= eaccelerator_shm_max) {
+      MMCG(mem) = eaccelerator_malloc(size);
+      if (MMCG(mem) == NULL) {
+        MMCG(mem) = eaccelerator_malloc2(size TSRMLS_CC);
+      }
+    }
+    if (MMCG(mem) == NULL) {
+      EACCELERATOR_PROTECT();
+    }
+  }
+  if (MMCG(mem) == NULL &&
+      (where == eaccelerator_shm_and_disk ||
+       where == eaccelerator_shm ||
+       where == eaccelerator_disk_only)) {
+    use_shm = 0;
+    MMCG(mem) = emalloc(size);
+  }
+  if (MMCG(mem)) {
+    zend_hash_init(&MMCG(strings), 0, NULL, NULL, 0);
+    EACCELERATOR_ALIGN(MMCG(mem));
+    q = (mm_user_cache_entry*)MMCG(mem);
+    q->size = size;
+    MMCG(mem) += offsetof(mm_user_cache_entry,key)+xlen+1;
+    q->hv = hash_mm(xkey, xlen);;
+    memcpy(q->key, xkey, xlen+1);
+    memcpy(&q->value, val, sizeof(zval));
+    q->ttl = ttl?time(0)+ttl:0;
+    store_zval(&q->value TSRMLS_CC);
+    zend_hash_destroy(&MMCG(strings));
+
+    /* storing to file */
+    if ((where == eaccelerator_shm_and_disk ||
+         ((where == eaccelerator_shm) && !use_shm) ||
+         where == eaccelerator_disk_only) &&
+        eaccelerator_md5(s, "/eaccelerator-user-", q->key TSRMLS_CC)) {
+      int f;
+      unlink(s);
+      f = open(s, O_CREAT | O_WRONLY | O_EXCL | O_BINARY, S_IRUSR | S_IWUSR);
+      if (f > 0) {
+        mm_file_header hdr;
+        EACCELERATOR_FLOCK(f, LOCK_EX);
+        strcpy(hdr.magic,"EACCELERATOR");
+        hdr.eaccelerator_version = binary_eaccelerator_version;
+        hdr.zend_version    = binary_zend_version;
+        hdr.php_version     = binary_php_version;
+        hdr.size  = q->size;
+        hdr.mtime = q->ttl;
+        q->next = q;
+        hdr.crc32 = eaccelerator_crc32((const char*)q,q->size);
+        if (write(f, &hdr, sizeof(hdr)) == sizeof(hdr)) {
+          write(f, q, q->size);
+          EACCELERATOR_FLOCK(f, LOCK_UN);
+          close(f);
+          ret = 1;
+        } else {
+          EACCELERATOR_FLOCK(f, LOCK_UN);
+          close(f);
+          unlink(s);
+        }
+      }
+      if (!use_shm) {
+        efree(q);
+      }
+    }
+
+    if ((where == eaccelerator_shm_and_disk ||
+         where == eaccelerator_shm ||
+         where == eaccelerator_shm_only) && use_shm) {
+      /* storing to shared memory */
+      slot = q->hv & MM_USER_HASH_MAX;
+      EACCELERATOR_LOCK_RW();
+      eaccelerator_mm_instance->user_hash_cnt++;
+      q->next = eaccelerator_mm_instance->user_hash[slot];
+      eaccelerator_mm_instance->user_hash[slot] = q;
+      p = q->next;
+      while (p != NULL) {
+        if ((p->hv == q->hv) && (strcmp(p->key, xkey) == 0)) {
+          eaccelerator_mm_instance->user_hash_cnt--;
+          q->next = p->next;
+          eaccelerator_free_nolock(p);
+          break;
+        }
+        q = p;
+        p = p->next;
+      }
+      EACCELERATOR_UNLOCK_RW();
+      EACCELERATOR_PROTECT();
+      ret = 1;
+    }
+  }
+  if (xlen != key_len) {efree(xkey);}
+  return ret;
+}
+
+int eaccelerator_get(const char* key, int key_len, zval* return_value, eaccelerator_cache_place where  TSRMLS_DC) {
+  unsigned int hv, slot;
+  char s[MAXPATHLEN];
+  int xlen;
+  char* xkey;
+
+  xkey = build_key(key, key_len, &xlen TSRMLS_CC);
+  hv = hash_mm(xkey,xlen);
+  slot = hv & MM_USER_HASH_MAX;
+
+  if (eaccelerator_mm_instance != NULL &&
+      (where == eaccelerator_shm_and_disk ||
+       where == eaccelerator_shm ||
+       where == eaccelerator_shm_only)) {
+    mm_user_cache_entry *p, *q;
+    mm_user_cache_entry *x = NULL;
+    EACCELERATOR_UNPROTECT();
+    EACCELERATOR_LOCK_RW();
+    q = NULL;
+    p = eaccelerator_mm_instance->user_hash[slot];
+    while (p != NULL) {
+      if ((p->hv == hv) && (strcmp(p->key, xkey) == 0)) {
+        x = p;
+        if (p->ttl != 0 && p->ttl < time(0)) {
+          if (q == NULL) {
+            eaccelerator_mm_instance->user_hash[slot] = p->next;
+          } else {
+            q->next = p->next;
+          }
+          eaccelerator_mm_instance->user_hash_cnt--;
+          eaccelerator_free_nolock(x);
+          x = NULL;
+        }
+        break;
+      }
+      q = p;
+      p = p->next;
+    }
+    EACCELERATOR_UNLOCK_RW();
+    EACCELERATOR_PROTECT();
+    if (x) {
+      memcpy(return_value, &x->value, sizeof(zval));
+      restore_zval(return_value TSRMLS_CC);
+      if (xlen != key_len) {efree(xkey);}
+      return 1;
+    }
+  }
+
+  /* key is not found in shared memory try to load it from file */
+  if ((where == eaccelerator_shm_and_disk ||
+       where == eaccelerator_shm ||
+       where == eaccelerator_disk_only) &&
+      eaccelerator_md5(s, "/eaccelerator-user-", xkey TSRMLS_CC)) {
+    time_t t = time(0);
+    int use_shm = 1;
+    int ret = 0;
+    int f;
+
+    if ((f = open(s, O_RDONLY | O_BINARY)) > 0) {
+      mm_file_header hdr;
+
+      EACCELERATOR_FLOCK(f, LOCK_SH);
+      if (read(f, &hdr, sizeof(hdr)) != sizeof(hdr) ||
+          strncmp(hdr.magic,"EACCELERATOR",8) != 0 ||
+          hdr.eaccelerator_version != binary_eaccelerator_version ||
+          hdr.zend_version != binary_zend_version ||
+          hdr.php_version != binary_php_version) {
+        EACCELERATOR_FLOCK(f, LOCK_UN);
+        close(f);
+        unlink(s);
+        if (xlen != key_len) {efree(xkey);}
+        return 0;
+      }
+      if (hdr.mtime == 0 || hdr.mtime > t) {
+        /* try to put it into shared memory */
+        mm_user_cache_entry *p = NULL;
+        if (eaccelerator_mm_instance != NULL &&
+            (where == eaccelerator_shm_and_disk ||
+             where == eaccelerator_shm)) {
+          if (eaccelerator_shm_max == 0 || hdr.size <= eaccelerator_shm_max) {
+            EACCELERATOR_UNPROTECT();
+            p = eaccelerator_malloc(hdr.size);
+            if (p == NULL) {
+              p = eaccelerator_malloc2(hdr.size TSRMLS_CC);
+            }
+            if (p == NULL) {
+              EACCELERATOR_PROTECT();
+            }
+          }
+        }
+        if (p == NULL) {
+          p = emalloc(hdr.size);
+          use_shm = 0;
+        }
+        if (p != NULL) {
+          if (read(f, p, hdr.size) == hdr.size &&
+              hdr.size == p->size &&
+              hdr.crc32 == eaccelerator_crc32((const char*)p,p->size)) {
+            MMCG(mem) = (char*)((long)p - (long)p->next);
+            MMCG(compress) = 1;
+            fixup_zval(&p->value TSRMLS_CC);
+
+            if (strcmp(xkey,p->key) != 0) {
+              if (use_shm) {
+                eaccelerator_free(p);
+              } else {
+                efree(p);
+              }
+              EACCELERATOR_FLOCK(f, LOCK_UN);
+              close(f);
+              unlink(s);
+              if (use_shm) EACCELERATOR_PROTECT();
+              if (xlen != key_len) {efree(xkey);}
+              return 0;
+            }
+
+            memcpy(return_value, &p->value, sizeof(zval));
+            restore_zval(return_value TSRMLS_CC);
+            ret = 1;
+            if (use_shm) {
+              /* put it into shared memory */
+              mm_user_cache_entry *q,*prev;
+
+              p->hv = hv;
+              EACCELERATOR_LOCK_RW();
+              p->next = eaccelerator_mm_instance->user_hash[slot];
+              eaccelerator_mm_instance->user_hash[slot] = p;
+              eaccelerator_mm_instance->user_hash_cnt++;
+              prev = p;
+              q = p->next;
+              while (q != NULL) {
+                if ((q->hv == hv) && (strcmp(q->key, xkey) == 0)) {
+                  prev->next = q->next;
+                  eaccelerator_mm_instance->user_hash_cnt--;
+                  eaccelerator_free_nolock(q);
+                  break;
+                }
+                prev = q;
+                q = q->next;
+              }
+              EACCELERATOR_UNLOCK_RW();
+            } else {
+              efree(p);
+            }
+            EACCELERATOR_FLOCK(f, LOCK_UN);
+            close(f);
+          } else {
+            if (use_shm) {
+              eaccelerator_free(p);
+            } else {
+              efree(p);
+            }
+            EACCELERATOR_FLOCK(f, LOCK_UN);
+            close(f);
+            unlink(s);
+          }
+        }
+        if (use_shm) EACCELERATOR_PROTECT();
+      } else {
+        EACCELERATOR_FLOCK(f, LOCK_UN);
+        close(f);
+        unlink(s);
+      }
+      if (xlen != key_len) {efree(xkey);}
+      return ret;
+    }
+  }
+  if (xlen != key_len) {efree(xkey);}
+  return 0;
+}
+
+int eaccelerator_rm(const char* key, int key_len, eaccelerator_cache_place where  TSRMLS_DC) {
+  unsigned int hv, slot;
+  mm_user_cache_entry *p, *q;
+  char s[MAXPATHLEN];
+  int xlen;
+  char* xkey;
+
+  xkey = build_key(key, key_len, &xlen TSRMLS_CC);
+  /* removing file */
+  if ((where == eaccelerator_shm_and_disk ||
+       where == eaccelerator_shm ||
+       where == eaccelerator_disk_only) &&
+      eaccelerator_md5(s, "/eaccelerator-user-", xkey TSRMLS_CC)) {
+    unlink(s);
+  }
+
+  /* removing from shared memory */
+  if (eaccelerator_mm_instance != NULL &&
+      (where == eaccelerator_shm_and_disk ||
+       where == eaccelerator_shm ||
+       where == eaccelerator_shm_only)) {
+    hv = hash_mm(xkey, xlen);
+    slot = hv & MM_USER_HASH_MAX;
+
+    EACCELERATOR_UNPROTECT();
+    EACCELERATOR_LOCK_RW();
+    q = NULL;
+    p = eaccelerator_mm_instance->user_hash[slot];
+    while (p != NULL) {
+      if ((p->hv == hv) && (strcmp(p->key, xkey) == 0)) {
+        if (q == NULL) {
+          eaccelerator_mm_instance->user_hash[slot] = p->next;
+        } else {
+          q->next = p->next;
+        }
+        eaccelerator_mm_instance->user_hash_cnt--;
+        eaccelerator_free_nolock(p);
+        break;
+      }
+      q = p;
+      p = p->next;
+    }
+    EACCELERATOR_UNLOCK_RW();
+    EACCELERATOR_PROTECT();
+  }
+  if (xlen != key_len) {efree(xkey);}
+  return 1;
+}
+
+size_t eaccelerator_gc(TSRMLS_D) {
+  size_t size = 0;
+  unsigned int i;
+  time_t t = time(0);
+
+  if (eaccelerator_mm_instance == NULL) {
+    return 0;
+  }
+  EACCELERATOR_UNPROTECT();
+  EACCELERATOR_LOCK_RW();
+  for (i = 0; i < MM_USER_HASH_SIZE; i++) {
+    mm_user_cache_entry** p = &eaccelerator_mm_instance->user_hash[i];
+    while (*p != NULL) {
+      if ((*p)->ttl != 0 && (*p)->ttl < t) {
+        mm_user_cache_entry *r = *p;
+        *p = (*p)->next;
+        eaccelerator_mm_instance->user_hash_cnt--;
+        size += r->size;
+        eaccelerator_free_nolock(r);
+      } else {
+        p = &(*p)->next;
+      }
+    }
+  }
+  EACCELERATOR_UNLOCK_RW();
+  EACCELERATOR_PROTECT();
+  return size;
+}
+
+PHP_FUNCTION(eaccelerator_lock) {
+  char *key;
+  int  key_len;
+
+  if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
+                          "s", &key, &key_len) == FAILURE) {
+    return;
+  }
+  if (eaccelerator_lock(key, key_len TSRMLS_CC)) {
+    RETURN_TRUE;
+  } else {
+    RETURN_FALSE;
+  }
+}
+
+PHP_FUNCTION(eaccelerator_unlock) {
+  char *key;
+  int  key_len;
+
+  if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
+                          "s", &key, &key_len) == FAILURE) {
+    return;
+  }
+  if (eaccelerator_unlock(key, key_len TSRMLS_CC)) {
+    RETURN_TRUE;
+  } else {
+    RETURN_FALSE;
+  }
+}
+
+PHP_FUNCTION(eaccelerator_put) {
+  char   *key;
+  int    key_len;
+  zval   *val;
+  time_t ttl = 0;
+  long   where = eaccelerator_keys_cache_place;
+
+  if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
+                          "sz|ll", &key, &key_len, &val, &ttl, &where) == FAILURE) {
+    return;
+  }
+  if (eaccelerator_put(key, key_len, val, ttl, where TSRMLS_CC)) {
+    RETURN_TRUE;
+  } else {
+    RETURN_FALSE;
+  }
+}
+
+PHP_FUNCTION(eaccelerator_get) {
+  char *key;
+  int  key_len;
+  long where = eaccelerator_keys_cache_place;
+
+  if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
+                          "s|l", &key, &key_len, &where) == FAILURE) {
+    return;
+  }
+  if (eaccelerator_get(key, key_len, return_value, where TSRMLS_CC)) {
+    return;
+  } else {
+    RETURN_NULL();
+  }
+}
+
+PHP_FUNCTION(eaccelerator_rm) {
+  char *key;
+  int  key_len;
+  long where = eaccelerator_keys_cache_place;
+
+  if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
+                          "s|l", &key, &key_len, &where) == FAILURE) {
+    return;
+  }
+  if (eaccelerator_rm(key, key_len, where TSRMLS_CC)) {
+    RETURN_TRUE;
+  } else {
+    RETURN_FALSE;
+  }
+}
+
+PHP_FUNCTION(eaccelerator_gc) {
+  if(ZEND_NUM_ARGS() != 0) {
+    WRONG_PARAM_COUNT;
+  }
+  eaccelerator_gc(TSRMLS_C);
+  RETURN_TRUE;
+}
+
+#ifdef WITH_EACCELERATOR_SESSIONS
+
+static int do_session_unlock(TSRMLS_D) {
+  if (MMCG(session) != NULL) {
+    eaccelerator_unlock(MMCG(session),strlen(MMCG(session)) TSRMLS_CC);
+    efree(MMCG(session));
+    MMCG(session) = NULL;
+  }
+  return 1;
+}
+
+static int do_session_lock(const char* sess_name TSRMLS_DC) {
+  if (MMCG(session) != NULL) {
+    if (strcmp(MMCG(session),sess_name) == 0) {
+      return 1;
+    } else {
+      do_session_unlock(TSRMLS_C);
+    }
+  }
+  if (eaccelerator_lock(sess_name, strlen(sess_name) TSRMLS_CC)) {
+    MMCG(session) = estrdup(sess_name);
+    return 1;
+  } else {
+    return 0;
+  }
+}
+
+#ifdef HAVE_PHP_SESSIONS_SUPPORT
+
+PS_OPEN_FUNC(eaccelerator) {
+  if (eaccelerator_mm_instance == NULL) {
+    return FAILURE;
+  }
+  PS_SET_MOD_DATA((void *)1);
+  return SUCCESS;
+}
+
+PS_CLOSE_FUNC(eaccelerator) {
+  if (eaccelerator_mm_instance == NULL) {
+    return FAILURE;
+  }
+  do_session_unlock(TSRMLS_C);
+  return SUCCESS;
+}
+
+PS_READ_FUNC(eaccelerator) {
+  char *skey;
+  int  len;
+  zval ret;
+
+  len = sizeof("sess_") + strlen(key);
+  skey = do_alloca(len + 1);
+  strcpy(skey,"sess_");
+  strcat(skey,key);
+  do_session_lock(skey TSRMLS_CC);
+  if (eaccelerator_get(skey, len, &ret, eaccelerator_sessions_cache_place TSRMLS_CC) &&
+      ret.type == IS_STRING) {
+    *val = estrdup(ret.value.str.val);
+    *vallen = ret.value.str.len;
+    zval_dtor(&ret);
+  } else {
+    *val = emalloc(1);
+    (*val)[0] = '\0';
+    *vallen = 0;
+  }
+  free_alloca(skey);
+  return SUCCESS;
+}
+
+PS_WRITE_FUNC(eaccelerator) {
+  char *skey;
+  int  len;
+  char *tmp;
+  time_t ttl;
+  zval sval;
+
+  len = sizeof("sess_") + strlen(key);
+  skey = do_alloca(len + 1);
+  strcpy(skey,"sess_");
+  strcat(skey,key);
+  if (cfg_get_string("session.gc_maxlifetime", &tmp)==FAILURE) {
+    ttl = 1440;
+  } else {
+    ttl = atoi(tmp);
+  }
+  sval.type = IS_STRING;
+  sval.value.str.val = (char*)val;
+  sval.value.str.len = vallen;
+
+  do_session_lock(skey TSRMLS_CC);
+  if (eaccelerator_put(skey, len, &sval, ttl, eaccelerator_sessions_cache_place TSRMLS_CC)) {
+    free_alloca(skey);
+    return SUCCESS;
+  } else {
+    free_alloca(skey);
+    return FAILURE;
+  }
+}
+
+PS_DESTROY_FUNC(eaccelerator) {
+  char *skey;
+  int  len;
+
+  len = sizeof("sess_") + strlen(key);
+  skey = do_alloca(len + 1);
+  strcpy(skey,"sess_");
+  strcat(skey,key);
+  if (eaccelerator_rm(skey, len, eaccelerator_sessions_cache_place TSRMLS_CC)) {
+    free_alloca(skey);
+    return SUCCESS;
+  } else {
+    free_alloca(skey);
+    return FAILURE;
+  }
+}
+
+PS_GC_FUNC(eaccelerator) {
+  if (eaccelerator_mm_instance == NULL) {
+    return FAILURE;
+  }
+  eaccelerator_gc(TSRMLS_C);
+  return SUCCESS;
+}
+
+#ifdef PS_CREATE_SID_ARGS
+PS_CREATE_SID_FUNC(eaccelerator) {
+  static char hexconvtab[] = "0123456789abcdef";
+  PHP_MD5_CTX context;
+  unsigned char digest[16];
+  char buf[256];
+  struct timeval tv;
+  int i;
+  int j = 0;
+  unsigned char c;
+
+  long entropy_length;
+  char *entropy_file;
+
+  if (cfg_get_string("session.entropy_length", &entropy_file)==FAILURE) {
+    entropy_length = 0;
+  } else {
+    entropy_length = atoi(entropy_file);
+  }
+  if (cfg_get_string("session.entropy_file", &entropy_file)==FAILURE) {
+    entropy_file = empty_string;
+  }
+
+  gettimeofday(&tv, NULL);
+  PHP_MD5Init(&context);
+
+  sprintf(buf, "%ld%ld%0.8f", tv.tv_sec, tv.tv_usec, php_combined_lcg(TSRMLS_C) * 10);
+  PHP_MD5Update(&context, buf, strlen(buf));
+
+  if (entropy_length > 0) {
+    int fd;
+
+    fd = VCWD_OPEN(entropy_file, O_RDONLY);
+    if (fd >= 0) {
+      unsigned char buf[2048];
+      int n;
+      int to_read = entropy_length;
+
+      while (to_read > 0) {
+        n = read(fd, buf, MIN(to_read, sizeof(buf)));
+        if (n <= 0) break;
+        PHP_MD5Update(&context, buf, n);
+        to_read -= n;
+      }
+      close(fd);
+    }
+  }
+
+  PHP_MD5Final(digest, &context);
+
+  for (i = 0; i < 16; i++) {
+    c = digest[i];
+    buf[j++] = hexconvtab[c >> 4];
+    buf[j++] = hexconvtab[c & 15];
+  }
+  buf[j] = '\0';
+
+  if (newlen)
+    *newlen = j;
+  return estrdup(buf);
+}
+#endif
+
+static ps_module ps_mod_eaccelerator = {
+#ifdef PS_CREATE_SID_ARGS
+  PS_MOD_SID(eaccelerator)
+#else
+  PS_MOD(eaccelerator)
+#endif
+};
+
+#else
+
+PHP_FUNCTION(_eaccelerator_session_open) {
+  if (eaccelerator_mm_instance == NULL) {
+    RETURN_FALSE;
+  }
+  RETURN_TRUE;
+}
+
+PHP_FUNCTION(_eaccelerator_session_close) {
+  if (eaccelerator_mm_instance == NULL) {
+    RETURN_FALSE;
+  }
+  do_session_unlock(TSRMLS_C);
+  RETURN_TRUE;
+}
+
+PHP_FUNCTION(_eaccelerator_session_read) {
+  zval **arg_key;
+  char *key;
+  int  len;
+
+  if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &arg_key) == FAILURE) {
+    WRONG_PARAM_COUNT;
+  }
+  len = sizeof("sess_") + (*arg_key)->value.str.len;
+  key = do_alloca(len + 1);
+  strcpy(key,"sess_");
+  strcat(key,(*arg_key)->value.str.val);
+  do_session_lock(key TSRMLS_CC);
+  if (eaccelerator_get(key, len, return_value, eaccelerator_sessions_cache_place TSRMLS_CC)) {
+    free_alloca(key);
+    return;
+  } else {
+    free_alloca(key);
+    RETURN_EMPTY_STRING();
+  }
+}
+
+PHP_FUNCTION(_eaccelerator_session_write) {
+  zval **arg_key, **arg_val;
+  char *key;
+  int  len;
+  char *tmp;
+  time_t ttl;
+
+  if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &arg_key, &arg_val) == FAILURE) {
+    WRONG_PARAM_COUNT;
+  }
+  len = sizeof("sess_") + (*arg_key)->value.str.len;
+  key = do_alloca(len + 1);
+  strcpy(key,"sess_");
+  strcat(key,(*arg_key)->value.str.val);
+  if (cfg_get_string("session.gc_maxlifetime", &tmp)==FAILURE) {
+    ttl = 1440;
+  } else {
+    ttl = atoi(tmp);
+  }
+  do_session_lock(key TSRMLS_CC);
+  if (eaccelerator_put(key, len, *arg_val, ttl, eaccelerator_sessions_cache_place TSRMLS_CC)) {
+    free_alloca(key);
+    RETURN_TRUE;
+  } else {
+    free_alloca(key);
+    RETURN_FALSE;
+  }
+}
+
+PHP_FUNCTION(_eaccelerator_session_destroy) {
+  zval **arg_key;
+  char *key;
+  int  len;
+
+  if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &arg_key) == FAILURE) {
+    WRONG_PARAM_COUNT;
+  }
+  len = sizeof("sess_") + (*arg_key)->value.str.len;
+  key = do_alloca(len + 1);
+  strcpy(key,"sess_");
+  strcat(key,(*arg_key)->value.str.val);
+  if (eaccelerator_rm(key, len, eaccelerator_sessions_cache_place TSRMLS_CC)) {
+    free_alloca(key);
+    RETURN_TRUE;
+  } else {
+    free_alloca(key);
+    RETURN_FALSE;
+  }
+}
+
+PHP_FUNCTION(_eaccelerator_session_gc) {
+  if (eaccelerator_mm_instance == NULL) {
+    RETURN_FALSE;
+  }
+  eaccelerator_gc(TSRMLS_C);
+  RETURN_TRUE;
+}
+#endif /* HAVE_PHP_SESSIONS_SUPPORT */
+
+
+static int eaccelerator_set_session_handlers(TSRMLS_D) {
+  zval func;
+  zval retval;
+  int ret = 1;
+#ifdef HAVE_PHP_SESSIONS_SUPPORT
+  zval param;
+  zval *params[1];
+/*
+  if (php_session_register_module(&ps_mod_eaccelerator) != 0) {
+    return 0;
+  }
+*/
+  if (eaccelerator_sessions_cache_place == eaccelerator_none) {
+    return 0;
+  }
+  ZVAL_STRING(&func, "session_module_name", 0);
+  INIT_ZVAL(param);
+  params[0] = &param;
+  ZVAL_STRING(params[0], "eaccelerator", 0);
+  if (call_user_function(EG(function_table), NULL, &func, &retval,
+        1, params TSRMLS_CC) == FAILURE) {
+    ret = 0;
+  }
+  zval_dtor(&retval);
+  return ret;
+#else
+  zval *params[6];
+  int i;
+
+  if (eaccelerator_sessions_cache_place == eaccelerator_none) {
+    return 0;
+  }
+  if (eaccelerator_mm_instance == NULL) {
+    return 0;
+  }
+  if (!zend_hash_exists(EG(function_table), "session_set_save_handler", sizeof("session_set_save_handler"))) {
+    return 0;
+  }
+
+  ZVAL_STRING(&func, "session_set_save_handler", 0);
+  MAKE_STD_ZVAL(params[0]);
+  ZVAL_STRING(params[0], "_eaccelerator_session_open", 1);
+  MAKE_STD_ZVAL(params[1]);
+  ZVAL_STRING(params[1], "_eaccelerator_session_close", 1);
+  MAKE_STD_ZVAL(params[2]);
+  ZVAL_STRING(params[2], "_eaccelerator_session_read", 1);
+  MAKE_STD_ZVAL(params[3]);
+  ZVAL_STRING(params[3], "_eaccelerator_session_write", 1);
+  MAKE_STD_ZVAL(params[4]);
+  ZVAL_STRING(params[4], "_eaccelerator_session_destroy", 1);
+  MAKE_STD_ZVAL(params[5]);
+  ZVAL_STRING(params[5], "_eaccelerator_session_gc", 1);
+  if (call_user_function(EG(function_table), NULL, &func, &retval,
+        6, params TSRMLS_CC) == FAILURE) {
+    ret = 0;
+  }
+  zval_dtor(&retval);
+  for (i = 0; i < 6; i++) zval_ptr_dtor(&params[i]);
+  return ret;
+#endif
+}
+
+PHP_FUNCTION(eaccelerator_set_session_handlers) {
+  if (eaccelerator_set_session_handlers(TSRMLS_C)) {
+    RETURN_TRUE;
+  } else {
+    RETURN_FALSE;
+  }
+}
+
+#endif
+
+#ifdef WITH_EACCELERATOR_CRASH
+PHP_FUNCTION(eaccelerator_crash) {
+  char *x = NULL;
+  strcpy(x,"Hello");
+}
+#endif
+
+PHP_FUNCTION(eaccelerator);
+
+/******************************************************************************/
+/*
+ * Begin of dynamic loadable module interfaces.
+ * There are two interfaces:
+ *  - standard php module,
+ *  - zend extension.
+ */
+PHP_INI_MH(eaccelerator_filter) {
+  mm_cond_entry *p, *q;
+  char *s = new_value;
+  char *ss;
+  int  not;
+  for (p = MMCG(cond_list); p != NULL; p = q) {
+    q = p->next;
+    if (p->str) {
+      free(p->str);
+    }
+    free(p);
+  }
+  MMCG(cond_list) = NULL;
+  while (*s) {
+    for (; *s == ' ' || *s == '\t'; s++)
+      ;
+    if (*s == 0)
+      break;
+    if (*s == '!') {
+      s++;
+      not = 1;
+    } else {
+      not = 0;
+    }
+    ss = s;
+    for (; *s && *s != ' ' && *s != '\t'; s++)
+      ;
+    if ((s > ss) && *ss) {
+      p = (mm_cond_entry *)malloc(sizeof(mm_cond_entry));
+      if (p == NULL)
+        break;
+      p->not = not;
+      p->len = s-ss;
+      p->str = malloc(p->len+1);
+      memcpy(p->str, ss, p->len);
+      p->str[p->len] = 0;
+      p->next = MMCG(cond_list);
+      MMCG(cond_list) = p;
+    }
+  }
+  return SUCCESS;
+}
+
+static PHP_INI_MH(eaccelerator_OnUpdateLong) {
+  long *p = (long*)mh_arg1;
+  *p = zend_atoi(new_value, new_value_length);
+  return SUCCESS;
+}
+
+static PHP_INI_MH(eaccelerator_OnUpdateBool) {
+  zend_bool *p = (zend_bool*)mh_arg1;
+  if (strncasecmp("on", new_value, sizeof("on"))) {
+    *p = (zend_bool) atoi(new_value);
+  } else {
+    *p = (zend_bool) 1;
+  }
+  return SUCCESS;
+}
+
+static PHP_INI_MH(eaccelerator_OnUpdateCachePlace) {
+  eaccelerator_cache_place *p = (eaccelerator_cache_place*)mh_arg1;
+  if (strncasecmp("shm_and_disk", new_value, sizeof("shm_and_disk")) == 0) {
+    *p = eaccelerator_shm_and_disk;
+  } else if (strncasecmp("shm", new_value, sizeof("shm")) == 0) {
+    *p = eaccelerator_shm;
+  } else if (strncasecmp("shm_only", new_value, sizeof("shm_only")) == 0) {
+    *p = eaccelerator_shm_only;
+  } else if (strncasecmp("disk_only", new_value, sizeof("disk_only")) == 0) {
+    *p = eaccelerator_disk_only;
+  } else if (strncasecmp("none", new_value, sizeof("none")) == 0) {
+    *p = eaccelerator_none;
+  }
+  return SUCCESS;
+}
+
+#ifndef ZEND_ENGINE_2
+#define OnUpdateLong OnUpdateInt
+#endif
+
+PHP_INI_BEGIN()
+STD_PHP_INI_ENTRY("eaccelerator.enable",         "1", PHP_INI_ALL, OnUpdateBool, enabled, zend_eaccelerator_globals, eaccelerator_globals)
+STD_PHP_INI_ENTRY("eaccelerator.optimizer",      "1", PHP_INI_ALL, OnUpdateBool, optimizer_enabled, zend_eaccelerator_globals, eaccelerator_globals)
+STD_PHP_INI_ENTRY("eaccelerator.compress",       "1", PHP_INI_ALL, OnUpdateBool, compression_enabled, zend_eaccelerator_globals, eaccelerator_globals)
+STD_PHP_INI_ENTRY("eaccelerator.compress_level", "9", PHP_INI_ALL, OnUpdateLong, compress_level, zend_eaccelerator_globals, eaccelerator_globals)                  
+ZEND_INI_ENTRY1("eaccelerator.shm_size",         "0", PHP_INI_SYSTEM, eaccelerator_OnUpdateLong, &eaccelerator_shm_size)
+ZEND_INI_ENTRY1("eaccelerator.shm_max",          "0", PHP_INI_SYSTEM, eaccelerator_OnUpdateLong, &eaccelerator_shm_max)
+ZEND_INI_ENTRY1("eaccelerator.shm_ttl",          "0", PHP_INI_SYSTEM, eaccelerator_OnUpdateLong, &eaccelerator_shm_ttl)
+ZEND_INI_ENTRY1("eaccelerator.shm_prune_period", "0", PHP_INI_SYSTEM, eaccelerator_OnUpdateLong, &eaccelerator_shm_prune_period)
+ZEND_INI_ENTRY1("eaccelerator.debug",            "0", PHP_INI_SYSTEM, eaccelerator_OnUpdateLong, &eaccelerator_debug)
+ZEND_INI_ENTRY1("eaccelerator.check_mtime",      "1", PHP_INI_SYSTEM, eaccelerator_OnUpdateBool, &eaccelerator_check_mtime)
+ZEND_INI_ENTRY1("eaccelerator.shm_only",         "0", PHP_INI_SYSTEM, eaccelerator_OnUpdateBool, &eaccelerator_scripts_shm_only)
+ZEND_INI_ENTRY1("eaccelerator.keys",             "shm_and_disk", PHP_INI_SYSTEM, eaccelerator_OnUpdateCachePlace, &eaccelerator_keys_cache_place)
+ZEND_INI_ENTRY1("eaccelerator.sessions",         "shm_and_disk", PHP_INI_SYSTEM, eaccelerator_OnUpdateCachePlace, &eaccelerator_sessions_cache_place)
+ZEND_INI_ENTRY1("eaccelerator.content",          "shm_and_disk", PHP_INI_SYSTEM, eaccelerator_OnUpdateCachePlace, &eaccelerator_content_cache_place)
+STD_PHP_INI_ENTRY("eaccelerator.cache_dir",      "/tmp/eaccelerator", PHP_INI_SYSTEM, OnUpdateString,
+                  cache_dir, zend_eaccelerator_globals, eaccelerator_globals)
+PHP_INI_ENTRY("eaccelerator.filter",             "",  PHP_INI_ALL, eaccelerator_filter)
+PHP_INI_END()
+
+static void eaccelerator_clean_request(TSRMLS_D) {
+  mm_used_entry  *p = (mm_used_entry*)MMCG(used_entries);
+  if (eaccelerator_mm_instance != NULL) {
+    EACCELERATOR_UNPROTECT();
+    mm_unlock(eaccelerator_mm_instance->mm);
+    if (p != NULL || eaccelerator_mm_instance->locks != NULL) {
+      EACCELERATOR_LOCK_RW();
+      while (p != NULL) {
+        p->entry->use_cnt--;
+        if (p->entry->removed && p->entry->use_cnt <= 0) {
+          if (eaccelerator_mm_instance->removed == p->entry) {
+            eaccelerator_mm_instance->removed = p->entry->next;
+            eaccelerator_mm_instance->rem_cnt--;
+            eaccelerator_free_nolock(p->entry);
+            p->entry = NULL;
+          } else {
+            mm_cache_entry *q = eaccelerator_mm_instance->removed;
+            while (q != NULL && q->next != p->entry) {
+              q = q->next;
+            }
+            if (q != NULL) {
+              q->next = p->entry->next;
+              eaccelerator_mm_instance->rem_cnt--;
+              eaccelerator_free_nolock(p->entry);
+              p->entry = NULL;
+            }
+          }
+        }
+        p = p->next;
+      }
+      if (eaccelerator_mm_instance->locks != NULL) {
+        pid_t    pid    = getpid();
+#ifdef ZTS
+        THREAD_T thread = tsrm_thread_id();
+#endif
+        mm_lock_entry** p = &eaccelerator_mm_instance->locks;
+        while ((*p) != NULL) {
+#ifdef ZTS
+          if ((*p)->pid == pid && (*p)->thread == thread) {
+#else
+          if ((*p)->pid == pid) {
+#endif
+            mm_lock_entry* x = *p;
+            *p = (*p)->next;
+            eaccelerator_free_nolock(x);
+          } else {
+            p = &(*p)->next;
+          }
+        }
+      }
+      EACCELERATOR_UNLOCK_RW();
+    }
+    EACCELERATOR_PROTECT();
+    p = (mm_used_entry*)MMCG(used_entries);
+    while (p != NULL) {
+      mm_used_entry* r = p;
+      p = p->next;
+      if (r->entry != NULL && r->entry->use_cnt < 0) {
+        efree(r->entry);
+      }
+      efree(r);
+    }
+  }
+  MMCG(used_entries) = NULL;
+  MMCG(in_request) = 0;
+}
+
+static void eaccelerator_clean_shutdown(void) {
+  if (eaccelerator_mm_instance != NULL) {
+    TSRMLS_FETCH();
+    if (MMCG(in_request)) {
+      fflush(stdout);
+      fflush(stderr);
+      eaccelerator_clean_request(TSRMLS_C);
+      if (eaccelerator_debug > 0) {
+        if (EG(active_op_array)) {
+          fprintf(stderr, "[%d] EACCELERATOR: PHP unclean shutdown on opline %ld of %s() at %s:%u\n\n",
+            getpid(),
+            (long)(active_opline-EG(active_op_array)->opcodes),
+            get_active_function_name(TSRMLS_C),
+            zend_get_executed_filename(TSRMLS_C),
+            zend_get_executed_lineno(TSRMLS_C));
+        }  else {
+          fprintf(stderr, "[%d] EACCELERATOR: PHP unclean shutdown\n\n",getpid());
+        }
+      }
+    }
+  }
+}
+
+#ifdef WITH_EACCELERATOR_CRASH_DETECTION
+static void eaccelerator_crash_handler(int dummy) {
+  TSRMLS_FETCH();
+  fflush(stdout);
+  fflush(stderr);
+#ifdef SIGSEGV
+  if (MMCG(original_sigsegv_handler) != eaccelerator_crash_handler) {
+    signal(SIGSEGV, MMCG(original_sigsegv_handler));
+  } else {
+    signal(SIGSEGV, SIG_DFL);
+  }
+#endif
+#ifdef SIGFPE
+  if (MMCG(original_sigfpe_handler) != eaccelerator_crash_handler) {
+    signal(SIGFPE, MMCG(original_sigfpe_handler));
+  } else {
+    signal(SIGFPE, SIG_DFL);
+  }
+#endif
+#ifdef SIGBUS
+  if (MMCG(original_sigbus_handler) != eaccelerator_crash_handler) {
+    signal(SIGBUS, MMCG(original_sigbus_handler));
+  } else {
+    signal(SIGBUS, SIG_DFL);
+  }
+#endif
+#ifdef SIGILL
+  if (MMCG(original_sigill_handler) != eaccelerator_crash_handler) {
+    signal(SIGILL, MMCG(original_sigill_handler));
+  } else {
+    signal(SIGILL, SIG_DFL);
+  }
+#endif
+#ifdef SIGABRT
+  if (MMCG(original_sigabrt_handler) != eaccelerator_crash_handler) {
+    signal(SIGABRT, MMCG(original_sigabrt_handler));
+  } else {
+    signal(SIGABRT, SIG_DFL);
+  }
+#endif
+  eaccelerator_clean_request(TSRMLS_C);
+  if (EG(active_op_array)) {
+    fprintf(stderr, "[%d] EACCELERATOR: PHP crashed on opline %ld of %s() at %s:%u\n\n",
+      getpid(),
+      (long)(active_opline-EG(active_op_array)->opcodes),
+      get_active_function_name(TSRMLS_C),
+      zend_get_executed_filename(TSRMLS_C),
+      zend_get_executed_lineno(TSRMLS_C));
+  } else {
+    fprintf(stderr, "[%d] EACCELERATOR: PHP crashed\n\n",getpid());
+  }
+#if !defined(WIN32) && !defined(NETWARE)
+  kill(getpid(), dummy);
+#else
+  raise(dummy);
+#endif
+}
+#endif
+
+static void eaccelerator_init_globals(zend_eaccelerator_globals *eaccelerator_globals)
+{
+  eaccelerator_globals->used_entries      = NULL;
+  eaccelerator_globals->enabled           = 1;
+  eaccelerator_globals->cache_dir         = NULL;
+  eaccelerator_globals->optimizer_enabled = 1;
+  eaccelerator_globals->compiler          = 0;
+  eaccelerator_globals->encoder           = 0;
+  eaccelerator_globals->cond_list         = NULL;
+  eaccelerator_globals->content_headers   = NULL;
+#ifdef WITH_EACCELERATOR_SESSIONS
+  eaccelerator_globals->session           = NULL;
+#endif
+  eaccelerator_globals->hostname[0]       = '\000';
+  eaccelerator_globals->in_request        = 0;
+}
+
+static void eaccelerator_globals_dtor(zend_eaccelerator_globals *eaccelerator_globals)
+{
+  mm_cond_entry *p, *q;
+
+  for (p = eaccelerator_globals->cond_list; p != NULL; p = q) {
+    q = p->next;
+    if (p->str) {
+      free(p->str);
+    }
+    free(p);
+  }
+  eaccelerator_globals->cond_list = NULL;
+}
+
+static void register_eaccelerator_as_zend_extension();
+static int eaccelerator_set_session_handlers();
+
+static int eaccelerator_check_php_version(TSRMLS_D) {
+  zval v;
+  int ret = 0;
+  if (zend_get_constant("PHP_VERSION", sizeof("PHP_VERSION")-1, &v TSRMLS_CC)) {
+    if (Z_TYPE(v) == IS_STRING &&
+        Z_STRLEN(v) == sizeof(PHP_VERSION)-1 &&
+        strcmp(Z_STRVAL(v),PHP_VERSION) == 0) {
+      ret = 1;
+    } else {
+      zend_error(E_CORE_WARNING,"[%s] This build of \"%s\" was compiled for PHP version %s. Rebuild it for your PHP version (%s) or download precompiled binaries.\n", EACCELERATOR_EXTENSION_NAME,EACCELERATOR_EXTENSION_NAME,PHP_VERSION,Z_STRVAL(v));
+    }
+    zval_dtor(&v);
+  } else {
+    zend_error(E_CORE_WARNING,"[%s] This build of \"%s\" was compiled for PHP version %s. Rebuild it for your PHP version.\n", EACCELERATOR_EXTENSION_NAME,EACCELERATOR_EXTENSION_NAME,PHP_VERSION);
+  }
+  return ret;
+}
+
+PHP_MINIT_FUNCTION(eaccelerator) {
+  if (type == MODULE_PERSISTENT) {
+#ifndef ZEND_WIN32
+    if (strcmp(sapi_module.name,"apache") == 0) {
+      /* Is the parent process - init */
+/*
+      sleep(1);
+      if (getppid() != 1) {
+*/
+      if (getpid() != getpgrp()) {
+        return SUCCESS;
+      }
+    }
+#endif
+#ifdef WITH_EACCELERATOR_LOADER
+    if (zend_hash_exists(&module_registry, EACCELERATOR_LOADER_EXTENSION_NAME, sizeof(EACCELERATOR_LOADER_EXTENSION_NAME))) {
+      zend_error(E_CORE_WARNING,"Extension \"%s\" is not need with \"%s\". Remove it from php.ini\n", EACCELERATOR_LOADER_EXTENSION_NAME, EACCELERATOR_EXTENSION_NAME);
+      zend_hash_del(&module_registry, EACCELERATOR_LOADER_EXTENSION_NAME, sizeof(EACCELERATOR_LOADER_EXTENSION_NAME));
+    }
+#endif
+  }
+  if (!eaccelerator_check_php_version(TSRMLS_C)) {
+    return FAILURE;
+  }
+/*??? FIXME
+  ZEND_INIT_MODULE_GLOBALS(eaccelerator, eaccelerator_init_globals, eaccelerator_globals_dtor);
+*/
+  ZEND_INIT_MODULE_GLOBALS(eaccelerator, eaccelerator_init_globals, NULL);
+  REGISTER_INI_ENTRIES();
+  REGISTER_STRING_CONSTANT("EACCELERATOR_VERSION", EACCELERATOR_VERSION, CONST_CS | CONST_PERSISTENT);
+  REGISTER_LONG_CONSTANT("EACCELERATOR_SHM_AND_DISK", eaccelerator_shm_and_disk, CONST_CS | CONST_PERSISTENT);
+  REGISTER_LONG_CONSTANT("EACCELERATOR_SHM", eaccelerator_shm, CONST_CS | CONST_PERSISTENT);
+  REGISTER_LONG_CONSTANT("EACCELERATOR_SHM_ONLY", eaccelerator_shm_only, CONST_CS | CONST_PERSISTENT);
+  REGISTER_LONG_CONSTANT("EACCELERATOR_DISK_ONLY", eaccelerator_disk_only, CONST_CS | CONST_PERSISTENT);
+  REGISTER_LONG_CONSTANT("EACCELERATOR_NONE", eaccelerator_none, CONST_CS | CONST_PERSISTENT);
+  binary_eaccelerator_version = encode_version(EACCELERATOR_VERSION);
+  binary_php_version = encode_version(PHP_VERSION);
+  binary_zend_version = encode_version(ZEND_VERSION);
+  eaccelerator_is_extension = 1;
+  if (type == MODULE_PERSISTENT &&
+      strcmp(sapi_module.name, "cgi") != 0 &&
+      strcmp(sapi_module.name, "cli") != 0) {
+#if defined(DEBUG) || defined(TEST_PERFORMANCE) || defined(PROFILE_OPCODES)
+    F_fp = fopen(DEBUG_LOGFILE, "a");
+    if (!F_fp) {
+      F_fp = fopen(DEBUG_LOGFILE_CGI, "a");
+      if (!F_fp) {
+        fprintf(stderr, "Cann't open log file '%s'.", DEBUG_LOGFILE);
+      }
+      chmod(DEBUG_LOGFILE_CGI, 0777);
+    }
+    fputs("\n=======================================\n", F_fp);
+    fprintf(F_fp, "[%d] EACCELERATOR STARTED\n", getpid());
+    fputs("=======================================\n", F_fp);
+    fflush(F_fp);
+#endif
+
+    if (init_mm(TSRMLS_C) == FAILURE) {
+      zend_error(E_CORE_WARNING,"[%s] Can not create shared memory area\n", EACCELERATOR_EXTENSION_NAME);
+    }
+
+    mm_saved_zend_compile_file = zend_compile_file;
+#ifdef PROFILE_OPCODES
+    zend_compile_file = profile_compile_file;
+    mm_saved_zend_execute = zend_execute;
+    zend_execute = profile_execute;
+#else
+    zend_compile_file = eaccelerator_compile_file;
+#ifdef WITH_EACCELERATOR_EXECUTOR
+    mm_saved_zend_execute = zend_execute;
+    zend_execute = eaccelerator_execute;
+#endif
+#endif
+    atexit(eaccelerator_clean_shutdown);
+  }
+#if defined(WITH_EACCELERATOR_SESSIONS) && defined(HAVE_PHP_SESSIONS_SUPPORT)
+    if (eaccelerator_sessions_cache_place != eaccelerator_none &&
+        eaccelerator_sessions_registered == 0) {
+      php_session_register_module(&ps_mod_eaccelerator);
+      eaccelerator_sessions_registered = 1;
+    }
+#endif
+#ifdef WITH_EACCELERATOR_CONTENT_CACHING
+    eaccelerator_content_cache_startup();
+#endif
+  if (!eaccelerator_is_zend_extension) {
+    register_eaccelerator_as_zend_extension();
+  }
+  return SUCCESS;
+}
+
+PHP_MSHUTDOWN_FUNCTION(eaccelerator) {
+  if (eaccelerator_mm_instance == NULL || !eaccelerator_is_extension) {
+    return SUCCESS;
+  }
+  zend_compile_file = mm_saved_zend_compile_file;
+#if defined(PROFILE_OPCODES) || defined(WITH_EACCELERATOR_EXECUTOR)
+  zend_execute = mm_saved_zend_execute;
+#endif
+#ifdef WITH_EACCELERATOR_CONTENT_CACHING
+  eaccelerator_content_cache_shutdown();
+#endif
+  shutdown_mm(TSRMLS_C);
+#if defined(DEBUG) || defined(TEST_PERFORMANCE) || defined(PROFILE_OPCODES)
+  fputs("========================================\n", F_fp);
+  fprintf(F_fp, "[%d] EACCELERATOR STOPPED\n", getpid());
+  fputs("========================================\n\n", F_fp);
+  fclose(F_fp);
+  F_fp = NULL;
+#endif
+  UNREGISTER_INI_ENTRIES();
+#ifndef ZTS
+  eaccelerator_globals_dtor(&eaccelerator_globals TSRMLS_CC);
+#endif
+  eaccelerator_is_zend_extension = 0;
+  eaccelerator_is_extension = 0;
+  return SUCCESS;
+}
+
+PHP_RINIT_FUNCTION(eaccelerator)
+{
+	if (eaccelerator_mm_instance == NULL)
+	{
+		return SUCCESS;
+	}
+	/*
+	 * HOESH: Initialization on first call,
+	 * came from eaccelerator_zend_startup().
+	 */
+	if (eaccelerator_global_function_table.nTableSize == 0)
+	{
+		zend_function tmp_func;
+		zend_class_entry tmp_class;
+
+		// Don't need this, as the context given by function argument.
+		// TSRMLS_FETCH();
+
+		zend_hash_init_ex(&eaccelerator_global_function_table, 100, NULL, NULL, 1, 0);
+		zend_hash_copy(&eaccelerator_global_function_table, CG(function_table), NULL, &tmp_func, sizeof(zend_function));
+		
+		zend_hash_init_ex(&eaccelerator_global_class_table, 10, NULL, NULL, 1, 0);
+		zend_hash_copy(&eaccelerator_global_class_table, CG(class_table), NULL, &tmp_class, sizeof(zend_class_entry));
+	}
+#if defined(DEBUG)
+	fprintf(F_fp, "[%d] Enter RINIT\n",getpid()); fflush(F_fp);
+#endif
+#ifdef PROFILE_OPCODES
+	fputs("\n========================================\n", F_fp);
+	fflush(F_fp);
+#endif
+	MMCG(in_request) = 1;
+	MMCG(used_entries) = NULL;
+	MMCG(compiler) = 0;
+	MMCG(encoder) = 0;
+	MMCG(refcount_helper) = 1;
+	MMCG(compress_content) = 1;
+	MMCG(content_headers) = NULL;
+	/* Storing Host Name */
+	MMCG(hostname)[0] = '\000';
+	{
+		zval  **server_vars, **hostname;
+
+		if (zend_hash_find(&EG(symbol_table), "_SERVER", sizeof("_SERVER"), (void **) &server_vars) == SUCCESS &&
+			Z_TYPE_PP(server_vars) == IS_ARRAY &&
+			zend_hash_find(Z_ARRVAL_PP(server_vars), "SERVER_NAME", sizeof("SERVER_NAME"), (void **) &hostname)==SUCCESS &&
+			Z_TYPE_PP(hostname) == IS_STRING &&
+			Z_STRLEN_PP(hostname) > 0)
+		{
+			if (sizeof(MMCG(hostname)) > Z_STRLEN_PP(hostname))
+			{
+				memcpy(MMCG(hostname),Z_STRVAL_PP(hostname),Z_STRLEN_PP(hostname)+1);
+			}
+			else
+			{
+				memcpy(MMCG(hostname),Z_STRVAL_PP(hostname),sizeof(MMCG(hostname))-1);
+				MMCG(hostname)[sizeof(MMCG(hostname))-1] = '\000';
+			}
+		}
+	}
+#if defined(DEBUG)
+	fprintf(F_fp, "[%d] Leave RINIT\n",getpid()); fflush(F_fp);
+#endif
+#if defined(DEBUG) || defined(TEST_PERFORMANCE)  || defined(PROFILE_OPCODES)
+	MMCG(xpad) = 0;
+#endif
+#ifdef PROFILE_OPCODES
+	MMCG(profile_level) = 0;
+#endif
+#ifdef WITH_EACCELERATOR_CRASH_DETECTION
+#ifdef SIGSEGV
+	MMCG(original_sigsegv_handler) = signal(SIGSEGV, eaccelerator_crash_handler);
+#endif
+#ifdef SIGFPE
+	MMCG(original_sigfpe_handler) = signal(SIGFPE, eaccelerator_crash_handler);
+#endif
+#ifdef SIGBUS
+	MMCG(original_sigbus_handler) = signal(SIGBUS, eaccelerator_crash_handler);
+#endif
+#ifdef SIGILL
+	MMCG(original_sigill_handler) = signal(SIGILL, eaccelerator_crash_handler);
+#endif
+#ifdef SIGABRT
+	MMCG(original_sigabrt_handler) = signal(SIGABRT, eaccelerator_crash_handler);
+#endif
+#endif
+	return SUCCESS;
+}
+
+PHP_RSHUTDOWN_FUNCTION(eaccelerator)
+{
+	if (eaccelerator_mm_instance == NULL)
+	{
+		return SUCCESS;
+	}
+#ifdef WITH_EACCELERATOR_CRASH_DETECTION
+#ifdef SIGSEGV
+	if (MMCG(original_sigsegv_handler) != eaccelerator_crash_handler)
+	{
+		signal(SIGSEGV, MMCG(original_sigsegv_handler));
+	}
+	else
+	{
+		signal(SIGSEGV, SIG_DFL);
+	}
+#endif
+#ifdef SIGFPE
+	if (MMCG(original_sigfpe_handler) != eaccelerator_crash_handler)
+	{
+		signal(SIGFPE, MMCG(original_sigfpe_handler));
+	}
+	else
+	{
+		signal(SIGFPE, SIG_DFL);
+	}
+#endif
+#ifdef SIGBUS
+	if (MMCG(original_sigbus_handler) != eaccelerator_crash_handler)
+	{
+		signal(SIGBUS, MMCG(original_sigbus_handler));
+	}
+	else
+	{
+		signal(SIGBUS, SIG_DFL);
+	}
+#endif
+#ifdef SIGILL
+	if (MMCG(original_sigill_handler) != eaccelerator_crash_handler)
+	{
+		signal(SIGILL, MMCG(original_sigill_handler));
+	}
+	else
+	{
+		signal(SIGILL, SIG_DFL);
+	}
+#endif
+#ifdef SIGABRT
+	if (MMCG(original_sigabrt_handler) != eaccelerator_crash_handler)
+	{
+		signal(SIGABRT, MMCG(original_sigabrt_handler));
+	}
+	else
+	{
+		signal(SIGABRT, SIG_DFL);
+	}
+#endif
+#endif
+#if defined(DEBUG)
+	fprintf(F_fp, "[%d] Enter RSHUTDOWN\n",getpid()); fflush(F_fp);
+#endif
+	eaccelerator_clean_request(TSRMLS_C);
+#if defined(DEBUG)
+	fprintf(F_fp, "[%d] Leave RSHUTDOWN\n",getpid()); fflush(F_fp);
+#endif
+	return SUCCESS;
+}
+
+#ifdef ZEND_ENGINE_2
+ZEND_BEGIN_ARG_INFO(eaccelerator_second_arg_force_ref, 0)
+  ZEND_ARG_PASS_INFO(0)
+  ZEND_ARG_PASS_INFO(1)
+ZEND_END_ARG_INFO();
+#else
+static unsigned char eaccelerator_second_arg_force_ref[] = {2, BYREF_NONE, BYREF_FORCE};
+#endif
+
+function_entry eaccelerator_functions[] = {
+  PHP_FE(eaccelerator, NULL)
+  PHP_FE(eaccelerator_put, NULL)
+  PHP_FE(eaccelerator_get, NULL)
+  PHP_FE(eaccelerator_rm, NULL)
+  PHP_FE(eaccelerator_gc, NULL)
+  PHP_FE(eaccelerator_lock, NULL)
+  PHP_FE(eaccelerator_unlock, NULL)
+#ifdef WITH_EACCELERATOR_ENCODER
+  PHP_FE(eaccelerator_encode, eaccelerator_second_arg_force_ref)
+#endif
+#ifdef WITH_EACCELERATOR_LOADER
+  PHP_FE(eaccelerator_load, NULL)
+  PHP_FE(_eaccelerator_loader_file, NULL)
+  PHP_FE(_eaccelerator_loader_line, NULL)
+#endif
+#ifdef WITH_EACCELERATOR_SESSIONS
+#ifndef HAVE_PHP_SESSIONS_SUPPORT
+  PHP_FE(_eaccelerator_session_open, NULL)
+  PHP_FE(_eaccelerator_session_close, NULL)
+  PHP_FE(_eaccelerator_session_read, NULL)
+  PHP_FE(_eaccelerator_session_write, NULL)
+  PHP_FE(_eaccelerator_session_destroy, NULL)
+  PHP_FE(_eaccelerator_session_gc, NULL)
+#endif
+  PHP_FE(eaccelerator_set_session_handlers, NULL)
+#endif
+#ifdef WITH_EACCELERATOR_CONTENT_CACHING
+  PHP_FE(_eaccelerator_output_handler, NULL)
+  PHP_FE(eaccelerator_cache_page, NULL)
+  PHP_FE(eaccelerator_rm_page, NULL)
+  PHP_FE(eaccelerator_cache_output, NULL)
+  PHP_FE(eaccelerator_cache_result, NULL)
+#endif
+#ifdef WITH_EACCELERATOR_CRASH
+  PHP_FE(eaccelerator_crash, NULL)
+#endif
+  {NULL, NULL, NULL}
+};
+
+zend_module_entry eaccelerator_module_entry = {
+#if ZEND_MODULE_API_NO >= 20010901
+  STANDARD_MODULE_HEADER,
+#endif
+  EACCELERATOR_EXTENSION_NAME,
+  eaccelerator_functions,
+  PHP_MINIT(eaccelerator),
+  PHP_MSHUTDOWN(eaccelerator),
+  PHP_RINIT(eaccelerator),
+  PHP_RSHUTDOWN(eaccelerator),
+  PHP_MINFO(eaccelerator),
+#if ZEND_MODULE_API_NO >= 20010901
+  EACCELERATOR_VERSION,          /* extension version number (string) */
+#endif
+  STANDARD_MODULE_PROPERTIES
+};
+
+#if defined(COMPILE_DL_EACCELERATOR)
+ZEND_GET_MODULE(eaccelerator)
+#endif
+
+static startup_func_t last_startup;
+static zend_llist_element *eaccelerator_el;
+
+#define EACCELERATOR_VERSION_GUID   "PHPE8EDA1B6-806A-4851-B1C8-A6B4712F44FB"
+#define EACCELERATOR_LOGO_GUID      "PHPE6F78DE9-13E4-4dee-8518-5FA2DACEA803"
+
+#define EACCELERATOR_VERSION_STRING ("eAccelerator " EACCELERATOR_VERSION " (PHP " PHP_VERSION ")")
+
+static const unsigned char eaccelerator_logo[] = {
+      71, 73, 70, 56, 57, 97, 88,  0, 31,  0,247,  0,  0,255,255,255,141,
+     144,192,219,  2, 17,125,128,172,  0,  0,  0,194,196,216,245,188,192,
+     229, 69, 80,250,221,223,238,137,144,220,221,233,248,204,207,238,238,
+     244,253,238,239, 43, 44, 54,233,103,112,162,165,204,160,162,194,154,
+     156,185,172,173,192,134,136,178, 86, 88,109,156,159,201,224, 36, 49,
+     241,154,160,174,176,194,229,230,238,151,153,189,134,137,183,152,155,
+     198,213,213,222,246,247,249,118,121,161,171,173,208,233,233,233,251,
+     251,251,137,139,186,212,213,227,140,143,190,226, 53, 65,140,143,177,
+      97, 99,122,138,141,188,187,188,217,122,124,165,146,148,188,155,158,
+     200,119,121,150,117,119,158,177,179,205,203,204,222,176,177,196,129,
+     131,163, 76, 77, 95,142,145,183,164,165,183,236,120,128,145,146,151,
+     166,168,197,148,151,196,254,254,254,169,169,171,151,154,198,142,145,
+     188,186,187,211,149,152,197, 65, 66, 82,178,178,178,153,156,199,130,
+     133,178,144,147,194, 54, 55, 68,140,141,164,186,187,205,154,157,199,
+     221, 19, 33,142,145,193,167,169,206,209,209,209,135,138,184, 11, 11,
+      14,108,110,136, 32, 33, 41,139,140,157, 22, 22, 27,147,150,195,231,
+      86, 96,214,215,224,190,192,218,124,127,169,161,164,203,145,148,194,
+     142,145,185,115,117,157,171,173,205,252,252,253,139,142,190,139,141,
+     170,247,247,247,193,194,211,151,154,190,200,201,225,180,181,201,229,
+     229,229,223,223,223,216,217,226,109,112,149,158,161,202,125,128,170,
+     159,162,202,114,116,155,143,146,193,146,149,195,224,224,224,150,153,
+     193,138,141,187,103,105,140,183,185,215,236,237,241,168,170,200,243,
+     171,176,219,220,230,145,146,173,227,227,227,128,131,175,109,111,148,
+     107,109,145,190,190,190,133,136,181,195,196,222,100,102,136,224,225,
+     238,161,161,162,178,180,200,242,242,242,174,176,210,222,222,234,168,
+     171,207,184,186,213,234,234,239,180,182,209,110,112,150,192,194,220,
+     245,245,245,137,139,178,151,154,197,165,167,201,241,241,247,207,207,
+     207,141,143,183,105,107,143,163,164,185,186,186,189,158,160,201,229,
+     229,240,150,153,179,144,145,165,247,247,250,112,115,153,235,236,241,
+     224,224,231,217,217,228,151,153,188,201,202,218,127,129,172,207,208,
+     220,124,126,154,160,161,188,156,156,156,152,152,152,245,245,248,148,
+     150,177,156,158,200,111,114,151,210,210,223,157,160,201,163,165,204,
+     132,135,180,236,236,236,149,149,154,175,176,200,166,167,188,132,134,
+     179,190,191,210,223,224,230,149,152,187,155,158,198,144,146,181,165,
+     167,199,198,200,222,143,144,170,224,225,232,177,179,199,179,181,207,
+     153,153,157,234,234,243,235,235,244,237,194,197,252,252,254,160,162,
+     202,158,160,189,168,169,189,211,211,225,122,124,142,149,151,170,207,
+     208,227,167,168,190,154,156,193,167,169,193,168,170,199,170,172,194,
+     171,172,198,192,192,192,199,200,214,183,183,183,254,254,255,214,215,
+     232,106,108,142,173,175,200,201,203,223,197,199,223,206,207,220,210,
+     211,230,187,189,212,189,190,213,129,130,150,198,199,202,159,161,195,
+     150,153,197,181,183,213,176,178,208,176,178,212,181,182,207,232,174,
+     178,124,126,146,163,164,188,212,213,228,144,145,171,134,136,165,148,
+     149,172,132,134,168,239,239,244,129,132,176,162,163,193,139,142,189,
+     162,164,204,155,156,171,166,168,204,147,149,177,108,110,146,206,206,
+     218,135,137,172,145,147,176,126,128,159,245,245,247,192,193,218, 33,
+     249,  4,  0,  0,  0,  0,  0, 44,  0,  0,  0,  0, 88,  0, 31,  0, 64,
+       8,255,  0,  3,  8, 28, 72,176,160,193,131,  8, 19, 42, 92,200,144,
+     225,191, 60,125,104,  0, 80,  5, 76, 77,171, 80,165,  0,116,  1, 96,
+      39,137,178, 81,  0, 38,100,168,181, 17, 88,  6,  0,206,  0,204,200,
+     144,161, 21,128, 62,125,186,149,202, 50,  7,145,171, 12, 87,244, 73,
+       3, 16,207,149, 30, 51, 94, 10, 90,112, 64,192, 65,141,162, 22, 42,
+      16,160, 82,  3, 10,  1, 20, 16,  8, 16, 16,114,132, 64,  5, 31,  2,
+     199,209, 58, 36, 16,128,215,175, 96,195,138, 29, 75,182,236,216, 47,
+     143,246,136, 75,118,234,  5, 10, 56, 10,141,160,120, 65,134,137, 64,
+      20, 83,132,253,137, 35,134,  7,128,174, 10,  6, 40,240, 58,  0,  8,
+     128,192, 50,  2,151,144, 81, 24, 64,129,  1, 31,  0,  0,177,193, 32,
+       2,133, 15, 27, 32,123, 53, 32,224,129,128,  4, 23, 14, 28,  0,144,
+     160,179,104,207,  9,188, 30, 16, 32,246,  1,134,  5,  2, 14, 32,136,
+     221,192, 10, 14,  0,  2, 46, 52, 56,193, 26,195,103,216, 15,254,  6,
+      48, 75,188,184,241,178,195, 86, 40, 65,184, 69,137, 11,184,  7, 89,
+     173, 32, 22,118,160, 10, 91,242, 72,  4,  0,  3, 40, 11,  8, 16,164,
+      56, 20,255,201, 82,132,  3, 27, 54,242, 88,192,128,193,130, 15, 31,
+      14, 28,  6,176,  0,177,158,133,247, 46, 32,178,112, 48, 65, 98,  0,
+     125, 16, 69,252,208,130, 40, 94, 56,194,213, 64, 62, 40, 69, 69, 20,
+      66, 16, 16,197, 11,  4,212,208,  1,132, 53, 12, 85,212, 11, 82, 64,
+     129,130, 17,  2,185,195,  9, 47,  2, 49,160,192,  6, 27, 40,160,193,
+      99, 12,  0, 16,195,  0,  0, 68, 96,131,  2, 37, 80, 16,  1,  0, 27,
+      80, 80,194, 99,  5, 32,182,162, 97,  0, 52, 96,128,  1, 13,  0,176,
+     128,  1, 11,  0,128,192,143,155, 25,128,  0, 88, 71, 22,201,195,  8,
+      98, 24, 34,203, 25,123,196,129,198,149,113,156, 33, 66, 58,197,136,
+     241,133, 95, 99,117,117,220,152, 96,249,216,192,145, 66, 22,137,230,
+       2, 69, 42,201, 36,145, 95,249,136,192,144, 94, 29,185, 36,  0,112,
+     210,233,213,144,119,138, 73,230,159,128,134,117,205, 36,131,148, 81,
+      71, 34,175,236, 64,208, 14,175, 36, 82, 71, 25,131, 76, 82, 86, 67,
+     148, 86,106,208, 27, 85,116,208, 70, 34, 88,120, 19, 72, 36,  4, 85,
+     225,195, 14, 46, 60, 23, 64, 84, 14, 88, 96, 65, 16,  2,  5, 49,170,
+       5, 29,112,255, 72,206, 10,129,148,147,200, 64, 88,132, 66,135, 31,
+     173,204,  0, 64, 40, 26,  0,128,207, 37, 33,209,161,138, 63,130,  0,
+     112,133,  7, 87,108,100, 73, 59,  0, 16,187,236, 21,155,  0,144, 70,
+     176,171,184, 17, 11, 34,159,120,176,200, 34,249, 36,145,135, 41,167,
+     108,179,  5, 65,114, 77,165,132,133, 16, 72, 65,  0,  4,107,184, 11,
+      65, 10,  4,164, 16,  4,170, 22,  8,244,  3, 51,209, 88,234,111,165,
+     152,250,176, 70, 19,135,160, 51,141, 28,  2,105,  1,  5, 21,109,104,
+     161, 69,  7, 76, 16,  1,  1, 17, 17, 79, 76,131,186, 16,180,  1,106,
+       0,144,168,131,196, 60,247,  8,164, 64,  1, 36,147,204, 64,  1, 41,
+     142, 44, 98,201, 37,124,117,114,142, 94,193,252,  1,201,129,122,245,
+     164, 33,123, 56,129, 73, 15,246,188,195,207, 46, 92,252, 96,130,  9,
+      63, 84,130, 66, 24, 72, 76,145,  3, 33,214, 56,113,198, 35, 95,128,
+      37,230,  0,  5,120, 21,193,  6, 94,201,  8,192,  0, 50, 14, 32,216,
+      99,193,126,245,152,215, 50,124,197,153,  0, 56, 52, 32, 64,108,164,
+     173,141,  7, 30,107,167,  6,128,111, 39, 24,224, 89,112, 66,194, 89,
+     167,155,184,201,255,102,  0, 88, 72,122,213, 21, 16, 44,122,181,162,
+     215,134, 61,102,248,  0, 37, 96,230, 53,  5,193, 82, 13,128,  6,  3,
+      96,141,167,  0,  6, 92, 32,  0,  6,162,181, 61,155,  0,179,201, 77,
+     183,  1, 86,116,198,217,  3,176,201, 70,219,  5, 39,244, 13,192,106,
+     115,127,214, 64,  2, 69,254,107,251,237,184, 51, 84,243,238,188,247,
+     238,103,239,192,139,245,133, 38,142, 52,113,110, 67,112, 52,225,136,
+      38,198,136,149,251,243,  3,189,177, 69, 16,172,192,114, 78, 32,216,
+     112,115,140, 66, 74, 80,229,130, 66,107, 96, 81,198, 10,135,192, 50,
+     144, 35, 46, 51,146,126, 39,128, 52,  3,128, 45,138,116,  2, 86, 17,
+      96,181,  0, 86, 48,245,147, 96,194, 32, 95,125,  3,192, 51,114,  0,
+       0, 59,192,209,139,229, 12,100,  7, 47,168, 64, 20,142,112,  4, 20,
+      32,208, 42, 21,112, 64, 10,136, 64,132, 20, 40,208, 40,117,  9, 64,
+       7, 24, 81,135,  3,  5,  0, 11, 95, 73,  2,  0,144,160,  6, 22,140,
+      34, 13,160,248,197, 39,124,225,149,126,  0,192,  3, 30, 24,131, 27,
+     148,  5,  0, 92, 36, 11,134, 87,112, 73, 62,186, 48,134, 52,116,  1,
+      16,220,242, 22, 40,255,178, 81, 13, 59,152, 66, 15,183,232, 64, 65,
+      20,198,176,120,189,171, 65, 41,112, 65, 85,104,112, 49, 33, 40,129,
+      12, 72, 17, 72, 11, 46, 17, 20,129,200,  1, 25,158,104, 15, 41,246,
+       1,140, 66,168,161, 17, 48, 40,132, 37,186,128, 12, 61,248,193, 12,
+      51, 16,137, 39,180,225,  6, 16, 72, 96, 21,208,200,192,  4, 38, 64,
+       3, 56,206,128,  6, 37, 36,129, 36, 10,177, 71, 65,184, 33, 23,208,
+       8, 67, 52,202,144,137, 69, 69,193, 42, 62,192,162, 20,240,133,175,
+     163,188, 32,  8,143,148,144, 64, 42,193,  9, 29, 12,196,  4, 96,160,
+     135,  9,  4, 98,  2, 21, 60,129,  4, 96,216,206, 28,192, 80, 74, 21,
+     168,128,  4,240, 33,129, 43,135,246,202, 39,192,231,148,182,124,130,
+      10, 70,105,130, 57,216,146,  4, 76,200,212, 26, 66,160,  8, 69,232,
+      98, 32, 22,170,  0, 20,160, 48, 65,165,164, 32, 65,245,138,138, 20,
+     142, 66,  5, 26, 40,145, 99,225,216,132, 36,160,  7, 61,233,  5, 65,
+       9,245,  8,129, 57,104,177, 14, 81,164,235,  8,223, 75, 72, 16,232,
+     117, 21,130,192, 99, 25, 83, 56,197, 61,234,241,187,224,  1,143,  7,
+      98, 16,129,206,110, 32,255,129, 22, 44,196,  8, 85, 96, 66, 37,194,
+      48,133, 89, 12,193,  9, 34,232,  4,152,  4, 50, 54,175,217,160,  4,
+     130,113, 12,100, 26, 58,128, 24, 76,142,  2, 94,139,168,228, 50, 83,
+      54,222, 61,233, 17, 34, 64,  3, 37,254, 48,132, 30, 16,  2, 21,169,
+      72, 41, 42,  8,209,131, 33, 80,131, 18,113,144,133,151,156, 55, 28,
+       0,104, 77, 69,133,139,192,140, 54, 48,163, 15, 80,224, 14,148,171,
+     154, 99, 24,  0,209, 59, 84,212,108,107,195,  0,  0, 52, 55,154,210,
+     128,238,115,114,  3,  0, 14,214, 38,128, 19,  4,169, 56,108, 51, 75,
+      87,130,234, 21, 27,204,104,107, 40, 27,128, 13, 48,218, 50,197,129,
+     133,112,153,185,  3, 82, 67,195,153,208,180,237,  2,  9,  0,205,103,
+     188, 82,186, 59,209, 78,170, 84, 77,141,103,214,118, 27,  1, 44, 97,
+     109,163,217,205,218,150,176,164,174,128,141, 48, 15,205, 12,  3, 24,
+     163,  0,159, 82, 64,162, 49,120,204,140,188, 42, 81,161,114,198, 55,
+     166,105,234,230,146, 58, 87,  0,212,181, 71, 86,192,131, 84,151,240,
+     215,  3,112, 38,170,174,131,157, 83,  1, 43,156,201, 13,230, 43, 55,
+      10,155,136,188, 34,162, 20, 50,125, 64,  6, 50,136,204, 97, 82,116,
+     152,215,114,198,110,160,235, 92,105,150,122,  1,220, 68,117,170,107,
+     179, 42,  2,254,234,215,214,237,117,174,108,131,157, 96,147,218, 90,
+     123, 90,247,186, 82, 11,  8,  0, 59};
+
+static int eaccelerator_last_startup(zend_extension *extension) {
+  int ret;
+  extension->startup = last_startup;
+  ret = extension->startup(extension);
+  zend_extensions.count++;
+  eaccelerator_el->next = zend_extensions.head;
+  eaccelerator_el->prev = NULL;
+  zend_extensions.head->prev = eaccelerator_el;
+  zend_extensions.head = eaccelerator_el;
+  if (ZendOptimizer) {
+    if ((ZendOptimizer = zend_get_extension("Zend Optimizer")) != NULL) {
+      ZendOptimizer->op_array_handler = NULL;
+    }
+  }
+  return ret;
+}
+
+/*
+static int eaccelerator_ioncube_startup(zend_extension *extension) {
+  int ret;
+  zend_extension* last_ext = (zend_extension*)zend_extensions.tail->data;
+  extension->startup = last_startup;
+  ret = extension->startup(extension);
+  last_startup = last_ext->startup;
+  last_ext->startup = eaccelerator_last_startup;
+  return ret;
+}
+*/
+
+ZEND_DLEXPORT int eaccelerator_zend_startup(zend_extension *extension) {
+ eaccelerator_is_zend_extension = 1;
+  eaccelerator_el   = NULL;
+  last_startup = NULL;
+
+  if (!eaccelerator_is_extension) {
+    if (zend_startup_module(&eaccelerator_module_entry) != SUCCESS) {
+      return FAILURE;
+    }
+  }
+
+  if (zend_llist_count(&zend_extensions) > 1) {
+    zend_llist_element *p = zend_extensions.head;
+    while (p != NULL) {
+      zend_extension* ext = (zend_extension*)(p->data);
+      if (strcmp(ext->name, EACCELERATOR_EXTENSION_NAME) == 0) {
+        /* temporary removing eAccelerator extension */
+        zend_extension* last_ext = (zend_extension*)zend_extensions.tail->data;
+        if (eaccelerator_el != NULL) {
+          zend_error(E_CORE_ERROR,"[%s] %s %s can not be loaded twich",
+                   EACCELERATOR_EXTENSION_NAME,
+                   EACCELERATOR_EXTENSION_NAME,
+                   EACCELERATOR_VERSION);
+          exit(1);
+        }
+        if (last_ext != ext) {
+          eaccelerator_el = p;
+          last_startup = las