Index: /tags/1.0/disassembler.h
===================================================================
--- /tags/1.0/disassembler.h	(revision 1)
+++ /tags/1.0/disassembler.h	(revision 1)
@@ -0,0 +1,4 @@
+#include "php.h"
+
+void xc_dasm_string(zval *return_value, zval *code TSRMLS_DC);
+void xc_dasm_file(zval *return_value, const char *filename TSRMLS_DC);
Index: /tags/1.0/coverager.h
===================================================================
--- /tags/1.0/coverager.h	(revision 27)
+++ /tags/1.0/coverager.h	(revision 27)
@@ -0,0 +1,11 @@
+#include "php.h"
+#include "xcache.h"
+
+extern char *xc_coveragedump_dir;
+
+void xc_coverager_handle_ext_stmt(zend_op_array *op_array, zend_uchar op);
+int xc_coverager_init(int module_number TSRMLS_DC);
+void xc_coverager_destroy();
+void xc_coverager_request_init(TSRMLS_D);
+void xc_coverager_request_shutdown(TSRMLS_D);
+PHP_FUNCTION(xcache_coverager_decode);
Index: /tags/1.0/optimizer.c
===================================================================
--- /tags/1.0/optimizer.c	(revision 1)
+++ /tags/1.0/optimizer.c	(revision 1)
@@ -0,0 +1,27 @@
+#include "optimizer.h"
+#include "utils.h"
+
+static int xc_optimize_op_array(zend_op_array *op_array TSRMLS_DC) /* {{{ */
+{
+	if (op_array->type != ZEND_USER_FUNCTION) {
+		return 0;
+	}
+	//xc_undo_pass_two(op_array TSRMLS_CC);
+	//xc_redo_pass_two(op_array TSRMLS_CC);
+	//xc_dprint_zend_op_array(op_array, 0);
+	return 0;
+}
+/* }}} */
+void xc_optimize(zend_op_array *op_array TSRMLS_DC) /* {{{ */
+{
+	xc_compile_result_t cr;
+
+	xc_compile_result_init_cur(&cr, op_array TSRMLS_CC);
+
+	xc_apply_op_array(&cr, (apply_func_t) xc_undo_pass_two TSRMLS_CC);
+	xc_apply_op_array(&cr, (apply_func_t) xc_optimize_op_array TSRMLS_CC);
+	xc_apply_op_array(&cr, (apply_func_t) xc_redo_pass_two TSRMLS_CC);
+
+	xc_compile_result_free(&cr);
+}
+/* }}} */
Index: /tags/1.0/opcode_spec.c
===================================================================
--- /tags/1.0/opcode_spec.c	(revision 20)
+++ /tags/1.0/opcode_spec.c	(revision 20)
@@ -0,0 +1,43 @@
+#include "xcache.h"
+#include "opcode_spec.h"
+#include "const_string.h"
+
+#ifdef HAVE_XCACHE_OPCODE_SPEC_DEF
+/* {{{ opcode_spec */
+#define OPSPEC(ext, op1, op2, res) { OPSPEC_##ext, OPSPEC_##op1, OPSPEC_##op2, OPSPEC_##res },
+#ifdef ZEND_ENGINE_2
+#	define OPSPEC_VAR_2 OPSPEC_STD
+#else
+#	define OPSPEC_VAR_2 OPSPEC_VAR
+#endif
+#include "opcode_spec_def.h"
+
+zend_uchar xc_get_opcode_spec_count()
+{
+	return sizeof(xc_opcode_spec) / sizeof(xc_opcode_spec[0]);
+}
+
+const xc_opcode_spec_t *xc_get_opcode_spec(zend_uchar opcode)
+{
+	assert(xc_get_opcode_count() == xc_get_opcode_spec_count());
+	assert(opcode < xc_get_opcode_spec_count());
+	return &xc_opcode_spec[opcode];
+}
+/* }}} */
+#endif
+/* {{{ op_spec */
+
+#define OPSPECS_DEF_NAME(name) #name,
+static const char *xc_op_spec[] = { OPSPECS(OPSPECS_DEF_NAME) };
+
+zend_uchar xc_get_op_spec_count()
+{
+	return sizeof(xc_op_spec) / sizeof(xc_op_spec[0]);
+}
+
+const char *xc_get_op_spec(zend_uchar spec)
+{
+	assert(spec < xc_get_op_spec_count());
+	return xc_op_spec[spec];
+}
+/* }}} */
Index: /tags/1.0/INSTALL
===================================================================
--- /tags/1.0/INSTALL	(revision 1)
+++ /tags/1.0/INSTALL	(revision 1)
@@ -0,0 +1,26 @@
+# vim:ts=4:sw=4
+Installtion:
+
+    $ phpize --clean && phpize
+    $ ./configure --help
+    $ CFLAGS='your cflags' ./configure --enable-xcache --enable...
+    $ make
+    $ su
+    # make install
+	(update php.ini, restart php)
+
+Reinstall:
+
+	$ mv config.nice conf
+	$ make distclean && phpize --clean && phpize
+	$ mv conf config.nice
+	$ ./config.nice
+	$ make
+	$ su
+	# make install
+	(update php.ini, restart php)
+
+Update php.ini:
+	$ su
+	# cat xcache.ini >> /etc/php.ini
+	# $EDITOR /etc/php.ini
Index: /tags/1.0/phpdc.phpr
===================================================================
--- /tags/1.0/phpdc.phpr	(revision 52)
+++ /tags/1.0/phpdc.phpr	(revision 52)
@@ -0,0 +1,30 @@
+#! /usr/bin/php -dopen_basedir=
+<?php
+
+$srcdir = dirname(__FILE__);
+require_once("$srcdir/Decompiler.class.php");
+if (file_exists("$srcdir/phpdc.debug.php")) {
+	include("$srcdir/phpdc.debug.php");
+}
+
+if (!isset($argv)) {
+	$argv = $_SERVER['argv'];
+	$argc = $_SERVER['argc'];
+}
+
+$dc = &new Decompiler();
+if (isset($argv[1])) {
+	$dc->decompileFile($argv[1]);
+}
+else {
+	$phpcode = '';
+	if (!defined('stdin')) {
+		define('stdin', fopen('php://stdin', 'rb'));
+	}
+	while (!feof(stdin)) {
+		$phpcode .= fgets(stdin);
+	}
+	$dc->decompileFile($phpcode);
+}
+$dc->output();
+
Index: /tags/1.0/COPYING
===================================================================
--- /tags/1.0/COPYING	(revision 45)
+++ /tags/1.0/COPYING	(revision 45)
@@ -0,0 +1,31 @@
+
+
+Copyright (c) 2005-2006, mOo, phpxcache@gmail.com, XCache
+ All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+- Redistributions of source code must retain the above copyright notice, this
+  list of conditions and the following disclaimer.
+
+- Redistributions in binary form must reproduce the above copyright notice,
+  this list of conditions and the following disclaimer in the documentation
+  and/or other materials provided with the distribution.
+
+- Neither the name of the 'XCache' nor the names of its contributors may
+  be used to endorse or promote products derived from this software without
+  specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+THE POSSIBILITY OF SUCH DAMAGE.
+
Index: /tags/1.0/optimizer.h
===================================================================
--- /tags/1.0/optimizer.h	(revision 1)
+++ /tags/1.0/optimizer.h	(revision 1)
@@ -0,0 +1,4 @@
+#include "php.h"
+#include "xcache.h"
+
+void xc_optimize(zend_op_array *op_array TSRMLS_DC);
Index: /tags/1.0/lock.c
===================================================================
--- /tags/1.0/lock.c	(revision 62)
+++ /tags/1.0/lock.c	(revision 62)
@@ -0,0 +1,157 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <php.h>
+#ifndef ZEND_WIN32
+typedef int HANDLE;
+#	ifndef INVALID_HANDLE_VALUE
+#		define INVALID_HANDLE_VALUE -1
+#	endif
+#	define CloseHandle(h) close(h)
+#endif
+#include "lock.h"
+
+struct _xc_lock_t {
+	HANDLE fd;
+	char *pathname;
+};
+
+#ifndef ZEND_WIN32
+#	include <unistd.h>
+#	include <fcntl.h>
+#	include <errno.h>
+#	define LCK_WR F_WRLCK
+#	define LCK_RD F_RDLCK
+#	define LCK_UN F_UNLCK
+#	define LCK_NB 0
+static inline int dolock(xc_lock_t *lck, int type) /* {{{ */
+{ 
+	int ret;
+	struct flock lock;
+
+	lock.l_type = type;
+	lock.l_start = 0;
+	lock.l_whence = SEEK_SET;
+	lock.l_len = 1;
+	lock.l_pid = 0;
+
+	do {
+		ret = fcntl(lck->fd, F_SETLKW, &lock);
+	} while (ret < 0 && errno == EINTR);
+	return ret;
+}
+/* }}} */
+#else
+
+#	include <win32/flock.h>
+#	include <io.h>
+#	include <fcntl.h>
+#	include <sys/types.h>
+#	include <sys/stat.h>
+#	ifndef errno
+#		define errno GetLastError()
+#	endif
+#	define getuid() 0
+#	define LCK_WR LOCKFILE_EXCLUSIVE_LOCK
+#	define LCK_RD 0
+#	define LCK_UN 0
+#	define LCK_NB LOCKFILE_FAIL_IMMEDIATELY
+static inline int dolock(xc_lock_t *lck, int type) /* {{{ */
+{ 
+	static OVERLAPPED offset = {0, 0, 0, 0, NULL};
+
+	if (type == LCK_UN) {
+		return UnlockFileEx((HANDLE)lck->fd, 0, 1, 0, &offset);
+	}
+	else {
+		return LockFileEx((HANDLE)lck->fd, type, 0, 1, 0, &offset);
+	}
+}
+/* }}} */
+#endif
+
+xc_lock_t *xc_fcntl_init(const char *pathname) /* {{{ */
+{
+	HANDLE fd;
+	xc_lock_t *lck;
+	int size;
+	char *myname;
+
+	if (pathname == NULL) {
+		static int i = 0;
+		const char default_tmpdir[] = { DEFAULT_SLASH, 't', 'm', 'p', '\0' };
+		const char *tmpdir;
+
+		tmpdir = getenv("TEMP");
+		if (!tmpdir) {
+			tmpdir = getenv("TMP");
+			if (!tmpdir) {
+				tmpdir = default_tmpdir;
+			}
+		}
+		size = strlen(tmpdir) + sizeof("/.xcache.lock") - 1 + 3 * 10 + 100;
+		myname = do_alloca(size);
+		snprintf(myname, size - 1, "%s%c.xcache.%d.%d.%d.lock", tmpdir, DEFAULT_SLASH, (int) getuid(), i ++, rand());
+		pathname = myname;
+	}
+	else {
+		myname = NULL;
+	}
+
+	fd = (HANDLE) open(pathname, O_RDWR|O_CREAT, 0666);
+
+	if (fd != INVALID_HANDLE_VALUE) {
+		lck = malloc(sizeof(lck[0]));
+
+#ifndef __CYGWIN__
+		unlink(pathname);
+#endif
+		lck->fd = fd;
+		size = strlen(pathname) + 1;
+		lck->pathname = malloc(size);
+		memcpy(lck->pathname, pathname, size);
+	}
+	else {
+		fprintf(stderr, "xc_fcntl_create: open(%s, O_RDWR|O_CREAT, 0666) failed:", pathname);
+		lck = NULL;
+	}
+
+	if (myname) {
+		free_alloca(myname);
+	}
+
+	return lck;
+}
+/* }}} */
+void xc_fcntl_destroy(xc_lock_t *lck) /* {{{ */
+{   
+	CloseHandle(lck->fd);
+#ifdef __CYGWIN__
+	unlink(lck->pathname);
+#endif
+	free(lck->pathname);
+	free(lck);
+}
+/* }}} */
+void xc_fcntl_lock(xc_lock_t *lck) /* {{{ */
+{   
+	if (dolock(lck, LCK_WR) < 0) {
+		fprintf(stderr, "xc_fcntl_lock failed errno:%d", errno);
+	}
+}
+/* }}} */
+void xc_fcntl_rdlock(xc_lock_t *lck) /* {{{ */
+{   
+	if (dolock(lck, LCK_RD) < 0) {
+		fprintf(stderr, "xc_fcntl_lock failed errno:%d", errno);
+	}
+}
+/* }}} */
+void xc_fcntl_unlock(xc_lock_t *lck) /* {{{ */
+{   
+	if (dolock(lck, LCK_UN) < 0) {
+		fprintf(stderr, "xc_fcntl_unlock failed errno:%d", errno);
+	}
+}
+/* }}} */
Index: /tags/1.0/opcode_spec.h
===================================================================
--- /tags/1.0/opcode_spec.h	(revision 20)
+++ /tags/1.0/opcode_spec.h	(revision 20)
@@ -0,0 +1,43 @@
+#include "php.h"
+
+#define OPSPECS(OPSPEC) \
+	OPSPEC(STD) \
+	OPSPEC(UNUSED) \
+	OPSPEC(OPLINE) \
+	OPSPEC(FCALL) \
+	OPSPEC(INIT_FCALL) \
+	OPSPEC(ARG) \
+	OPSPEC(CAST) \
+	OPSPEC(FETCH) \
+	OPSPEC(DECLARE) \
+	OPSPEC(SEND) \
+	OPSPEC(SEND_NOREF) \
+	OPSPEC(FCLASS) \
+	OPSPEC(UCLASS) \
+	OPSPEC(CLASS) \
+	OPSPEC(FE) \
+	OPSPEC(IFACE) \
+	OPSPEC(ISSET) \
+	OPSPEC(BIT) \
+	OPSPEC(VAR) \
+	OPSPEC(TMP) \
+	OPSPEC(JMPADDR) \
+	OPSPEC(BRK) \
+	OPSPEC(CONT) \
+	OPSPEC(INCLUDE) \
+	OPSPEC(ASSIGN)
+
+#define OPSPECS_DEF_ENUM(name) OPSPEC_##name,
+typedef enum { OPSPECS(OPSPECS_DEF_ENUM) } xc_op_spec_t;
+
+typedef struct {
+	xc_op_spec_t ext;
+	xc_op_spec_t op1;
+	xc_op_spec_t op2;
+	xc_op_spec_t res;
+} xc_opcode_spec_t;
+
+const xc_opcode_spec_t *xc_get_opcode_spec(zend_uchar opcode);
+zend_uchar xc_get_opcode_spec_count();
+zend_uchar xc_get_op_spec_count();
+const char *xc_get_op_spec(zend_uchar spec);
Index: /tags/1.0/xcache.c
===================================================================
--- /tags/1.0/xcache.c	(revision 65)
+++ /tags/1.0/xcache.c	(revision 65)
@@ -0,0 +1,2075 @@
+
+#undef DEBUG
+
+/* {{{ macros */
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <signal.h>
+
+#include "php.h"
+#include "ext/standard/info.h"
+#include "ext/standard/md5.h"
+#include "zend_extensions.h"
+#include "SAPI.h"
+
+#include "xcache.h"
+#include "optimizer.h"
+#include "coverager.h"
+#include "disassembler.h"
+#include "align.h"
+#include "stack.h"
+#include "xcache_globals.h"
+#include "processor.h"
+#include "utils.h"
+#include "const_string.h"
+#include "opcode_spec.h"
+
+#ifdef DEBUG
+#	undef NDEBUG
+#	undef inline
+#	define inline
+#else
+#	ifndef NDEBUG
+#		define NDEBUG
+#	endif
+#endif
+#include <assert.h>
+
+#define CHECK(x, e) do { if ((x) == NULL) { zend_error(E_ERROR, "XCache: " e); goto err; } } while (0)
+#define LOCK(x) xc_lock(x->lck)
+#define UNLOCK(x) xc_unlock(x->lck)
+#define ENTER_LOCK(x) do { \
+	int catched = 0; \
+	xc_lock(x->lck); \
+	zend_try { \
+		do
+#define LEAVE_LOCK(x) \
+		while (0); \
+	} zend_catch { \
+		catched = 1; \
+	} zend_end_try(); \
+	xc_unlock(x->lck); \
+} while(0)
+/* }}} */
+
+/* {{{ globals */
+static char *xc_mmap_path = NULL;
+static char *xc_coredump_dir = NULL;
+
+static xc_hash_t xc_php_hcache = {0};
+static xc_hash_t xc_php_hentry = {0};
+static xc_hash_t xc_var_hcache = {0};
+static xc_hash_t xc_var_hentry = {0};
+
+/* total size */
+static zend_ulong xc_php_size  = 0;
+static zend_ulong xc_var_size  = 0;
+
+static xc_cache_t **xc_php_caches = NULL;
+static xc_cache_t **xc_var_caches = NULL;
+
+static zend_bool xc_initized = 0;
+static zend_compile_file_t *origin_compile_file;
+
+static zend_bool xc_test = 0;
+static zend_bool xc_readonly_protection = 0;
+
+static zend_bool xc_module_gotup = 0;
+static zend_bool xc_zend_extension_gotup = 0;
+#if !COMPILE_DL_XCACHE
+#	define zend_extension_entry xcache_zend_extension_entry
+#endif
+ZEND_DLEXPORT zend_extension zend_extension_entry;
+ZEND_DECLARE_MODULE_GLOBALS(xcache);
+/* }}} */
+
+/* any function in *_dmz is only safe be called within locked(single thread) area */
+
+static inline int xc_entry_equal_dmz(xc_entry_t *a, xc_entry_t *b) /* {{{ */
+{
+	/* this function isn't required but can be in dmz */
+
+	if (a->type != b->type) {
+		return 0;
+	}
+	switch (a->type) {
+		case XC_TYPE_PHP:
+#ifdef HAVE_INODE
+			do {
+				xc_entry_data_php_t *ap = a->data.php;
+				xc_entry_data_php_t *bp = b->data.php;
+				return ap->inode == bp->inode
+					&& ap->device == bp->device;
+			} while(0);
+#endif
+			/* fall */
+
+		case XC_TYPE_VAR:
+			do {
+#ifdef IS_UNICODE
+				if (a->name_type == IS_UNICODE) {
+					if (a->name.ustr.len != b->name.ustr.len) {
+						return 0;
+					}
+					return memcmp(a->name.ustr.val, b->name.ustr.val, (a->name.ustr.len + 1) * sizeof(UChar)) == 0;
+				}
+				else {
+					return memcmp(a->name.str.val, b->name.str.val, a->name.str.len + 1) == 0;
+				}
+#else
+				return memcmp(a->name.str.val, b->name.str.val, a->name.str.len + 1) == 0;
+#endif
+
+			} while(0);
+		default:
+			assert(0);
+	}
+	return 0;
+}
+/* }}} */
+static void xc_entry_free_dmz(volatile xc_entry_t *xce) /* {{{ */
+{
+	xc_mem_free(xce->cache->mem, (xc_entry_t *)xce);
+}
+/* }}} */
+static void xc_entry_add_dmz(xc_entry_t *xce) /* {{{ */
+{
+	xc_entry_t **head = &(xce->cache->entries[xce->hvalue]);
+	xce->next = *head;
+	*head = xce;
+	xce->cache->entries_count ++;
+}
+/* }}} */
+static xc_entry_t *xc_entry_store_dmz(xc_entry_t *xce TSRMLS_DC) /* {{{ */
+{
+	xc_entry_t *stored_xce;
+
+	xce->hits  = 0;
+	xce->ctime = XG(request_time);
+	xce->atime = XG(request_time);
+	stored_xce = xc_processor_store_xc_entry_t(xce TSRMLS_CC);
+	if (stored_xce) {
+		xc_entry_add_dmz(stored_xce);
+		return stored_xce;
+	}
+	else {
+		xce->cache->ooms ++;
+		return NULL;
+	}
+}
+/* }}} */
+static void xc_entry_remove_dmz(xc_entry_t *xce TSRMLS_DC) /* {{{ */
+{
+	xc_entry_t **last = &(xce->cache->entries[xce->hvalue]);
+	xc_entry_t *p;
+	for (p = *last; p; last = &(p->next), p = p->next) {
+		if (xc_entry_equal_dmz(xce, p)) {
+			*last = p->next;
+			xce->cache->entries_count ++;
+			if (p->refcount == 0) {
+				xc_entry_free_dmz(p);
+			}
+			else {
+				p->next = p->cache->deletes;
+				p->cache->deletes = p;
+				p->dtime = XG(request_time);
+				xce->cache->deletes_count ++;
+			}
+			return;
+		}
+	}
+	assert(0);
+}
+/* }}} */
+static xc_entry_t *xc_entry_find_dmz(xc_entry_t *xce TSRMLS_DC) /* {{{ */
+{
+	xc_entry_t *p;
+	for (p = xce->cache->entries[xce->hvalue]; p; p = p->next) {
+		if (xc_entry_equal_dmz(xce, p)) {
+			if (p->type == XC_TYPE_VAR || /* PHP */ p->data.php->mtime == xce->data.php->mtime) {
+				p->hits ++;
+				p->atime = XG(request_time);
+				return p;
+			}
+			else {
+				xc_entry_remove_dmz(p TSRMLS_CC);
+				return NULL;
+			}
+		}
+	}
+	return NULL;
+}
+/* }}} */
+static void xc_entry_hold_php_dmz(xc_entry_t *xce TSRMLS_DC) /* {{{ */
+{
+	xce->refcount ++;
+	xc_stack_push(&XG(php_holds)[xce->cache->cacheid], (void *)xce);
+}
+/* }}} */
+#if 0
+static void xc_entry_hold_var_dmz(xc_entry_t *xce TSRMLS_DC) /* {{{ */
+{
+	xce->refcount ++;
+	xc_stack_push(&XG(var_holds)[xce->cache->cacheid], (void *)xce);
+}
+/* }}} */
+#endif
+
+/* helper functions for user functions */
+static void xc_fillinfo_dmz(xc_cache_t *cache, zval *return_value TSRMLS_DC) /* {{{ */
+{
+	zval *blocks;
+	const xc_block_t *b;
+#ifndef NDEBUG
+	xc_memsize_t avail = 0;
+#endif
+	xc_mem_t *mem = cache->mem;
+
+	add_assoc_long_ex(return_value, ZEND_STRS("slots"),     cache->hentry->size);
+	add_assoc_long_ex(return_value, ZEND_STRS("compiling"), cache->compiling);
+	add_assoc_long_ex(return_value, ZEND_STRS("misses"),    cache->misses);
+	add_assoc_long_ex(return_value, ZEND_STRS("hits"),      cache->hits);
+	add_assoc_long_ex(return_value, ZEND_STRS("clogs"),     cache->clogs);
+	add_assoc_long_ex(return_value, ZEND_STRS("ooms"),      cache->ooms);
+
+	add_assoc_long_ex(return_value, ZEND_STRS("cached"), cache->entries_count);
+	add_assoc_long_ex(return_value, ZEND_STRS("deleted"), cache->deletes_count);
+
+	MAKE_STD_ZVAL(blocks);
+	array_init(blocks);
+
+	add_assoc_long_ex(return_value, ZEND_STRS("size"),  xc_mem_size(mem));
+	add_assoc_long_ex(return_value, ZEND_STRS("avail"), xc_mem_avail(mem));
+	add_assoc_bool_ex(return_value, ZEND_STRS("can_readonly"), xc_readonly_protection);
+
+	for (b = xc_mem_freeblock_first(mem); b; b = xc_mem_freeblock_next(b)) {
+		zval *bi;
+
+		MAKE_STD_ZVAL(bi);
+		array_init(bi);
+
+		add_assoc_long_ex(bi, ZEND_STRS("size"),   xc_mem_block_size(b));
+		add_assoc_long_ex(bi, ZEND_STRS("offset"), xc_mem_block_offset(mem, b));
+		add_next_index_zval(blocks, bi);
+#ifndef NDEBUG
+		avail += b->size;
+#endif
+	}
+	add_assoc_zval_ex(return_value, ZEND_STRS("free_blocks"), blocks);
+	assert(avail == xc_mem_avail(mem));
+}
+/* }}} */
+static void xc_fillentry_dmz(xc_entry_t *entry, int del, zval *list TSRMLS_DC) /* {{{ */
+{
+	zval* ei;
+	xc_entry_data_php_t *php;
+	xc_entry_data_var_t *var;
+
+	ALLOC_INIT_ZVAL(ei);
+	array_init(ei);
+
+	add_assoc_long_ex(ei, ZEND_STRS("size"),     entry->size);
+	add_assoc_long_ex(ei, ZEND_STRS("refcount"), entry->refcount);
+	add_assoc_long_ex(ei, ZEND_STRS("hits"),     entry->hits);
+	add_assoc_long_ex(ei, ZEND_STRS("ctime"),    entry->ctime);
+	add_assoc_long_ex(ei, ZEND_STRS("atime"),    entry->atime);
+	add_assoc_long_ex(ei, ZEND_STRS("dtime"),    entry->dtime);
+#ifdef IS_UNICODE
+	do {
+		zval *zv;
+		ALLOC_INIT_ZVAL(zv);
+		switch (entry->name_type) {
+			case IS_UNICODE:
+					ZVAL_UNICODEL(zv, entry->name.ustr.val, entry->name.ustr.len, 1);
+				break;
+			case IS_STRING:
+				ZVAL_STRINGL(zv, entry->name.str.val, entry->name.str.len, 1);
+				break;
+			default:
+				assert(0);
+		}
+		zv->type = entry->name_type;
+		add_assoc_zval_ex(ei, ZEND_STRS("name"), zv);
+	} while (0);
+#else
+	add_assoc_stringl_ex(ei, ZEND_STRS("name"), entry->name.str.val, entry->name.str.len + 1, 1);
+#endif
+	switch (entry->type) {
+		case XC_TYPE_PHP:
+			php = entry->data.php;
+			add_assoc_long_ex(ei, ZEND_STRS("sourcesize"),   php->sourcesize);
+#ifdef HAVE_INODE
+			add_assoc_long_ex(ei, ZEND_STRS("device"),       php->device);
+			add_assoc_long_ex(ei, ZEND_STRS("inode"),        php->inode);
+#endif
+			add_assoc_long_ex(ei, ZEND_STRS("mtime"),        php->mtime);
+
+			add_assoc_long_ex(ei, ZEND_STRS("function_cnt"), php->funcinfo_cnt);
+			add_assoc_long_ex(ei, ZEND_STRS("class_cnt"),    php->classinfo_cnt);
+			break;
+		case XC_TYPE_VAR:
+			var = entry->data.var;
+			break;
+
+		default:
+			assert(0);
+	}
+
+	add_next_index_zval(list, ei);
+}
+/* }}} */
+static void xc_filllist_dmz(xc_cache_t *cache, zval *return_value TSRMLS_DC) /* {{{ */
+{
+	zval* list;
+	int i, c;
+	xc_entry_t *e;
+
+	ALLOC_INIT_ZVAL(list);
+	array_init(list);
+
+	for (i = 0, c = cache->hentry->size; i < c; i ++) {
+		for (e = cache->entries[i]; e; e = e->next) {
+			xc_fillentry_dmz(e, 0, list TSRMLS_CC);
+		}
+	}
+	add_assoc_zval(return_value, "cache_list", list);
+
+	ALLOC_INIT_ZVAL(list);
+	array_init(list);
+	for (e = cache->deletes; e; e = e->next) {
+		xc_fillentry_dmz(e, 1, list TSRMLS_CC);
+	}
+	add_assoc_zval(return_value, "deleted_list", list);
+}
+/* }}} */
+
+static zend_op_array *xc_entry_install(xc_entry_t *xce, zend_file_handle *h TSRMLS_DC) /* {{{ */
+{
+	zend_uint i;
+	xc_entry_data_php_t *p = xce->data.php;
+#ifndef ZEND_ENGINE_2
+	/* new ptr which is stored inside CG(class_table) */
+	xc_cest_t **new_cest_ptrs = (xc_cest_t **)do_alloca(sizeof(xc_cest_t*) * p->classinfo_cnt);
+#endif
+
+	/* install function */
+	for (i = 0; i < p->funcinfo_cnt; i ++) {
+		xc_funcinfo_t  *fi = &p->funcinfos[i];
+		xc_install_function(xce->name.str.val, &fi->func,
+				UNISW(0, fi->type), fi->key, fi->key_size TSRMLS_CC);
+	}
+
+	/* install class */
+	for (i = 0; i < p->classinfo_cnt; i ++) {
+		xc_classinfo_t *ci = &p->classinfos[i];
+#ifndef ZEND_ENGINE_2
+		zend_class_entry *ce = CestToCePtr(ci->cest);
+		/* fix pointer to the be which inside class_table */
+		if (ce->parent) {
+			zend_uint class_idx = (/* class_num */ (int) ce->parent) - 1;
+			assert(class_idx < i);
+			ci->cest.parent = new_cest_ptrs[class_idx];
+		}
+		new_cest_ptrs[i] =
+#endif
+		xc_install_class(xce->name.str.val, &ci->cest,
+				UNISW(0, ci->type), ci->key, ci->key_size TSRMLS_CC);
+	}
+
+	i = 1;
+	zend_hash_add(&EG(included_files), xce->name.str.val, xce->name.str.len+1, (void *)&i, sizeof(int), NULL);
+	zend_llist_add_element(&CG(open_files), h);
+
+#ifndef ZEND_ENGINE_2
+	free_alloca(new_cest_ptrs);
+#endif
+	return p->op_array;
+}
+/* }}} */
+static void xc_entry_gc_real(xc_cache_t **caches, int size TSRMLS_DC) /* {{{ */
+{
+	time_t t = XG(request_time);
+	int i;
+	xc_cache_t *cache;
+	typedef xc_entry_t *xc_delete_t;
+	xc_delete_t p, *last;
+
+	for (i = 0; i < size; i ++) {
+		cache = caches[i];
+		ENTER_LOCK(cache) {
+			if (cache->deletes) {
+				last = (xc_delete_t *) &cache->deletes;
+				for (p = *last; p; p = p->next) {
+					if (t - p->dtime > 3600) {
+						p->refcount = 0;
+						/* issue warning here */
+					}
+					if (p->refcount == 0) {
+						*last = p->next;
+						cache->deletes_count --;
+						xc_entry_free_dmz(p);
+					}
+					else {
+						last = &(p->next);
+					}
+				}
+			}
+		} LEAVE_LOCK(cache);
+	}
+}
+/* }}} */
+static void xc_entry_gc(TSRMLS_D) /* {{{ */
+{
+	xc_entry_gc_real(xc_php_caches, xc_php_hcache.size TSRMLS_CC);
+	xc_entry_gc_real(xc_var_caches, xc_var_hcache.size TSRMLS_CC);
+}
+/* }}} */
+static inline void xc_entry_unholds_real(xc_stack_t *holds, xc_cache_t **caches, int cachecount TSRMLS_DC) /* {{{ */
+{
+	int i;
+	xc_stack_t *s;
+	xc_cache_t *cache;
+	xc_entry_t *xce;
+
+	for (i = 0; i < cachecount; i ++) {
+		s = &holds[i];
+		if (xc_stack_size(s)) {
+			cache = ((xc_entry_t *)xc_stack_top(s))->cache;
+			ENTER_LOCK(cache) {
+				while (xc_stack_size(holds)) {
+					xce = (xc_entry_t*) xc_stack_pop(holds);
+					xce->refcount --;
+					assert(xce->refcount >= 0);
+				}
+			} LEAVE_LOCK(cache);
+		}
+	}
+}
+/* }}} */
+static void xc_entry_unholds(TSRMLS_D) /* {{{ */
+{
+	xc_entry_unholds_real(XG(php_holds), xc_php_caches, xc_php_hcache.size TSRMLS_CC);
+	xc_entry_unholds_real(XG(var_holds), xc_var_caches, xc_var_hcache.size TSRMLS_CC);
+}
+/* }}} */
+static int xc_stat(const char *filename, const char *include_path, struct stat *pbuf TSRMLS_DC) /* {{{ */
+{
+	char filepath[1024];
+	char *paths, *path;
+	char *tokbuf;
+	int size = strlen(include_path) + 1;
+	char tokens[] = { DEFAULT_DIR_SEPARATOR, '\0' };
+
+	paths = (char *)do_alloca(size);
+	memcpy(paths, include_path, size);
+
+	for (path = php_strtok_r(paths, tokens, &tokbuf); path; path = php_strtok_r(NULL, tokens, &tokbuf)) {
+		if (strlen(path) + strlen(filename) + 1 > 1024) {
+			continue;
+		}
+		snprintf(filepath, sizeof(filepath), "%s/%s", path, filename);
+		if (VCWD_STAT(filepath, pbuf) == 0) {
+			free_alloca(paths);
+			return 0;
+		}
+	}
+
+	free_alloca(paths);
+
+	return 1;
+}
+/* }}} */
+
+#define HASH(i) (i)
+#define HASH_USTR_L(t, s, l) HASH(zend_u_inline_hash_func(t, s, (l + 1) * sizeof(UChar)))
+#define HASH_STR_L(s, l) HASH(zend_inline_hash_func(s, l + 1))
+#define HASH_STR(s) HASH_STR_L(s, strlen(s) + 1)
+#define HASH_NUM(n) HASH(n)
+static inline xc_hash_value_t xc_entry_hash_var(xc_entry_t *xce) /* {{{ */
+{
+	return UNISW(NOTHING, UG(unicode) ? HASH_USTR_L(xce->name_type, (char *)xce->name.ustr.val, xce->name.ustr.len) :)
+		HASH_STR_L(xce->name.str.val, xce->name.str.len);
+}
+/* }}} */
+static inline xc_hash_value_t xc_entry_hash_php(xc_entry_t *xce) /* {{{ */
+{
+#ifdef HAVE_INODE
+	return HASH(xce->data.php->device + xce->data.php->inode);
+#else
+	return xc_entry_hash_var(xce);
+#endif
+}
+/* }}} */
+static int xc_entry_init_key_php(xc_entry_t *xce, char *filename TSRMLS_DC) /* {{{ */
+{
+	struct stat buf, *pbuf;
+	xc_hash_value_t hv;
+	int cacheid;
+	xc_entry_data_php_t *php;
+
+	if (!filename || !SG(request_info).path_translated) {
+		return 0;
+	}
+
+	do {
+		if (strcmp(SG(request_info).path_translated, filename) == 0) {
+			/* sapi has already done this stat() for us */
+			pbuf = sapi_get_stat(TSRMLS_C);
+			if (pbuf) {
+				break;
+			}
+		}
+
+		pbuf = &buf;
+		if (IS_ABSOLUTE_PATH(filename, strlen(filename))) {
+			if (VCWD_STAT(filename, pbuf) != 0) {
+				return 0;
+			}
+		}
+		else {
+			if (xc_stat(filename, PG(include_path), pbuf TSRMLS_CC) != 0) {   
+				return 0;
+			}
+		}
+	} while (0);
+
+	if (XG(request_time) - pbuf->st_mtime < 2) {
+		return 0;
+	}
+
+	UNISW(NOTHING, xce->name_type = IS_STRING;)
+	xce->name.str.val = filename;
+	xce->name.str.len = strlen(filename);
+
+	php = xce->data.php;
+	php->mtime        = pbuf->st_mtime;
+#ifdef HAVE_INODE
+	php->device       = pbuf->st_dev;
+	php->inode        = pbuf->st_ino;
+#endif
+	php->sourcesize   = pbuf->st_size;
+
+
+	hv = xc_entry_hash_php(xce);
+	cacheid = (hv & xc_php_hcache.mask);
+	xce->cache = xc_php_caches[cacheid];
+	hv >>= xc_php_hcache.bits;
+	xce->hvalue = (hv & xc_php_hentry.mask);
+
+	xce->type = XC_TYPE_PHP;
+	return 1;
+}
+/* }}} */
+static zend_op_array *xc_compile_file(zend_file_handle *h, int type TSRMLS_DC) /* {{{ */
+{
+	xc_sandbox_t sandbox;
+	zend_op_array *op_array;
+	xc_entry_t xce, *stored_xce;
+	xc_entry_data_php_t php;
+	xc_cache_t *cache;
+	zend_bool clogged = 0;
+	zend_bool catched = 0;
+	char *filename;
+
+	if (!xc_initized) {
+		assert(0);
+	}
+
+	if (!XG(cacher)) {
+		op_array = origin_compile_file(h, type TSRMLS_CC);
+#ifdef HAVE_XCACHE_OPTIMIZER
+		if (XG(optimizer)) {
+			xc_optimize(op_array TSRMLS_CC);
+		}
+#endif
+		return op_array;
+	}
+
+	/* {{{ prepare key
+	 * include_once() and require_once() gives us opened_path
+	 * however, include() and require() non-absolute path which break
+	 * included_files, and may confuse with (include|require)_once
+	 * -- Xuefer
+	 */
+
+	filename = h->opened_path ? h->opened_path : h->filename;
+	xce.data.php = &php;
+	if (!xc_entry_init_key_php(&xce, filename TSRMLS_CC)) {
+		return origin_compile_file(h, type TSRMLS_CC);
+	}
+	cache = xce.cache;
+	/* }}} */
+	/* {{{ restore */
+	/* stale precheck */
+	if (cache->compiling) {
+		cache->clogs ++; /* is it safe here? */
+		return origin_compile_file(h, type TSRMLS_CC);
+	}
+
+	stored_xce = NULL;
+	op_array = NULL;
+	ENTER_LOCK(cache) {
+		/* clogged */
+		if (cache->compiling) {
+			cache->clogs ++;
+			op_array = NULL;
+			clogged = 1;
+			break;
+		}
+
+		stored_xce = xc_entry_find_dmz(&xce TSRMLS_CC);
+		/* found */
+		if (stored_xce) {
+#ifdef DEBUG
+			fprintf(stderr, "found %s, catch it\n", stored_xce->name.str.val);
+#endif
+			xc_entry_hold_php_dmz(stored_xce TSRMLS_CC);
+			cache->hits ++;
+			break;
+		}
+
+		cache->compiling = XG(request_time);
+		cache->misses ++;
+	} LEAVE_LOCK(cache);
+
+	/* found */
+	if (stored_xce) {
+		goto restore;
+	}
+
+	/* clogged */
+	if (clogged) {
+		return origin_compile_file(h, type TSRMLS_CC);
+	}
+	/* }}} */
+
+	/* {{{ compile */
+#ifdef DEBUG
+	fprintf(stderr, "compiling %s\n", filename);
+#endif
+
+	/* make compile inside sandbox */
+	xc_sandbox_init(&sandbox, filename TSRMLS_CC);
+
+	zend_try {
+		op_array = origin_compile_file(h, type TSRMLS_CC);
+	} zend_catch {
+		catched = 1;
+	} zend_end_try();
+
+	if (catched) {
+		goto err_bailout;
+	}
+
+	if (op_array == NULL) {
+		goto err_oparray;
+	}
+
+#ifdef HAVE_XCACHE_OPTIMIZER
+	if (XG(optimizer)) {
+		xc_optimize(op_array TSRMLS_CC);
+	}
+#endif
+
+	php.op_array      = op_array;
+
+	php.funcinfo_cnt  = zend_hash_num_elements(CG(function_table));
+	php.classinfo_cnt = zend_hash_num_elements(CG(class_table));
+
+	php.funcinfos     = ECALLOC_N(php.funcinfos, php.funcinfo_cnt);
+	if (!php.funcinfos) {
+		goto err_func;
+	}
+	php.classinfos    = ECALLOC_N(php.classinfos, php.classinfo_cnt);
+	if (!php.classinfos) {
+		goto err_class;
+	}
+	/* }}} */
+	/* {{{ shallow copy, pointers only */ {
+		Bucket *b;
+		unsigned int i;
+
+		b = CG(function_table)->pListHead;
+		for (i = 0; b; i ++, b = b->pListNext) {
+			xc_funcinfo_t *fi = &php.funcinfos[i];
+
+			assert(i < php.funcinfo_cnt);
+			assert(b->pData);
+			memcpy(&fi->func, b->pData, sizeof(zend_function));
+			UNISW(NOTHING, fi->type = b->key.type;)
+			fi->key        = BUCKET_KEY(b);
+			fi->key_size   = b->nKeyLength;
+		}
+
+		b = CG(class_table)->pListHead;
+		for (i = 0; b; i ++, b = b->pListNext) {
+			xc_classinfo_t *ci = &php.classinfos[i];
+
+			assert(i < php.classinfo_cnt);
+			assert(b->pData);
+			memcpy(&ci->cest, b->pData, sizeof(xc_cest_t));
+			UNISW(NOTHING, ci->type = b->key.type;)
+			ci->key        = BUCKET_KEY(b);
+			ci->key_size   = b->nKeyLength;
+			/* need to fix inside store */
+		}
+	}
+	/* }}} */
+	xc_entry_gc(TSRMLS_C);
+	ENTER_LOCK(cache) { /* {{{ store/add entry */
+		stored_xce = xc_entry_store_dmz(&xce TSRMLS_CC);
+	} LEAVE_LOCK(cache);
+	/* }}} */
+#ifdef DEBUG
+	fprintf(stderr, "stored\n");
+#endif
+
+	efree(xce.data.php->classinfos);
+err_class:
+	efree(xce.data.php->funcinfos);
+err_func:
+err_oparray:
+err_bailout:
+
+	if (xc_test && stored_xce) {
+		/* no install, keep open_files too for h */
+		xc_sandbox_free(&sandbox, 0 TSRMLS_CC);
+		sandbox.tmp_open_files->dtor = NULL;
+	}
+	else {
+		xc_sandbox_free(&sandbox, 1 TSRMLS_CC);
+	}
+
+	ENTER_LOCK(cache) {
+		cache->compiling = 0;
+	} LEAVE_LOCK(cache);
+	if (catched) {
+		zend_bailout();
+	}
+	if (xc_test && stored_xce) {
+		goto restore;
+	}
+	return op_array;
+
+restore:
+#ifdef DEBUG
+	fprintf(stderr, "restoring\n");
+#endif
+	xc_processor_restore_xc_entry_t(&xce, stored_xce, xc_readonly_protection TSRMLS_CC);
+	op_array = xc_entry_install(&xce, h TSRMLS_CC);
+
+	efree(xce.data.php->funcinfos);
+	efree(xce.data.php->classinfos);
+	efree(xce.data.php);
+#ifdef DEBUG
+	fprintf(stderr, "restored\n");
+#endif
+	return op_array;
+}
+/* }}} */
+
+/* gdb helper functions, but N/A for coredump */
+int xc_is_rw(const void *p) /* {{{ */
+{
+	int i;
+	if (!xc_initized) {
+		return 0;
+	}
+	for (i = 0; i < xc_php_hcache.size; i ++) {
+		if (xc_shm_is_readwrite(xc_php_caches[i]->shm, p)) {
+			return 1;
+		}
+	}
+	for (i = 0; i < xc_var_hcache.size; i ++) {
+		if (xc_shm_is_readwrite(xc_var_caches[i]->shm, p)) {
+			return 1;
+		}
+	}
+	return 0;
+}
+/* }}} */
+int xc_is_ro(const void *p) /* {{{ */
+{
+	int i;
+	if (!xc_initized) {
+		return 0;
+	}
+	for (i = 0; i < xc_php_hcache.size; i ++) {
+		if (xc_shm_is_readonly(xc_php_caches[i]->shm, p)) {
+			return 1;
+		}
+	}
+	for (i = 0; i < xc_var_hcache.size; i ++) {
+		if (xc_shm_is_readonly(xc_var_caches[i]->shm, p)) {
+			return 1;
+		}
+	}
+	return 0;
+}
+/* }}} */
+int xc_is_shm(const void *p) /* {{{ */
+{
+	return xc_is_ro(p) || xc_is_rw(p);
+}
+/* }}} */
+
+/* module helper function */
+static int xc_init_constant(int module_number TSRMLS_DC) /* {{{ */
+{
+	typedef struct {
+		const char *prefix;
+		zend_uchar (*getsize)();
+		const char *(*get)(zend_uchar i);
+	} xc_meminfo_t;
+	xc_meminfo_t nameinfos[] = {
+		{ "",        xc_get_op_type_count,   xc_get_op_type   },
+		{ "",        xc_get_data_type_count, xc_get_data_type },
+		{ "",        xc_get_opcode_count,    xc_get_opcode    },
+		{ "OPSPEC_", xc_get_op_spec_count,   xc_get_op_spec   },
+		{ NULL, NULL, NULL }
+	};
+	xc_meminfo_t* p;
+	zend_uchar i, count;
+	char const_name[96];
+	int const_name_len;
+	int undefdone = 0;
+
+	for (p = nameinfos; p->getsize; p ++) {
+		count = p->getsize();
+		for (i = 0; i < count; i ++) {
+			const char *name = p->get(i);
+			if (!name) continue;
+			if (strcmp(name, "UNDEF") == 0) {
+				if (undefdone) continue;
+				undefdone = 1;
+			}
+			const_name_len = snprintf(const_name, sizeof(const_name), "XC_%s%s", p->prefix, name);
+			zend_register_long_constant(const_name, const_name_len+1, i, CONST_CS | CONST_PERSISTENT, module_number TSRMLS_CC);
+		}
+	}
+
+	zend_register_long_constant(ZEND_STRS("XC_SIZEOF_TEMP_VARIABLE"), sizeof(temp_variable), CONST_CS | CONST_PERSISTENT, module_number TSRMLS_CC);
+	zend_register_long_constant(ZEND_STRS("XC_TYPE_PHP"), XC_TYPE_PHP, CONST_CS | CONST_PERSISTENT, module_number TSRMLS_CC);
+	zend_register_long_constant(ZEND_STRS("XC_TYPE_VAR"), XC_TYPE_VAR, CONST_CS | CONST_PERSISTENT, module_number TSRMLS_CC);
+	return 0;
+}
+/* }}} */
+static xc_shm_t *xc_cache_destroy(xc_cache_t **caches, xc_hash_t *hcache) /* {{{ */
+{
+	int i;
+	xc_cache_t *cache;
+	xc_shm_t *shm;
+
+	if (!caches) {
+		return NULL;
+	}
+	shm = NULL;
+	for (i = 0; i < hcache->size; i ++) {
+		cache = caches[i];
+		if (cache) {
+			if (cache->lck) {
+				xc_lock_destroy(cache->lck);
+			}
+			/* do NOT free
+			if (cache->entries) {
+				xc_mem_free(cache->mem, cache->entries);
+			}
+			xc_mem_free(cache->mem, cache);
+			*/
+			xc_mem_destroy(cache->mem);
+			shm = cache->shm;
+		}
+	}
+	free(caches);
+	return shm;
+}
+/* }}} */
+static xc_cache_t **xc_cache_init(xc_shm_t *shm, char *ptr, xc_hash_t *hcache, xc_hash_t *hentry, xc_shmsize_t shmsize) /* {{{ */
+{
+	xc_cache_t **caches = NULL, *cache;
+	xc_mem_t *mem;
+	int i;
+	xc_memsize_t memsize;
+
+	memsize = shmsize / hcache->size;
+
+	/* Don't let it break out of mem after ALIGNed
+	 * This is important for 
+	 * Simply loop until it fit our need
+	 */
+	while (ALIGN(memsize) * hcache->size > shmsize && ALIGN(memsize) != memsize) {
+		if (memsize < ALIGN(1)) {
+			CHECK(NULL, "cache too small");
+		}
+		memsize --;
+	}
+
+	CHECK(caches = calloc(hcache->size, sizeof(xc_cache_t *)), "caches OOM");
+
+	for (i = 0; i < hcache->size; i ++) {
+		CHECK(mem            = xc_mem_init(ptr, memsize), "Failed init memory allocator");
+		ptr += memsize;
+		CHECK(cache          = xc_mem_calloc(mem, 1, sizeof(xc_cache_t)), "cache OOM");
+		CHECK(cache->entries = xc_mem_calloc(mem, hentry->size, sizeof(xc_entry_t*)), "entries OOM");
+		CHECK(cache->lck     = xc_lock_init(NULL), "can't create lock");
+
+		cache->hcache  = hcache;
+		cache->hentry  = hentry;
+		cache->shm     = shm;
+		cache->mem     = mem;
+		cache->cacheid = i;
+		caches[i] = cache;
+	}
+	assert(ptr <= (char*)xc_shm_ptr(shm) + shmsize);
+	return caches;
+
+err:
+	if (caches) {
+		xc_cache_destroy(caches, hcache);
+	}
+	return NULL;
+}
+/* }}} */
+static void xc_destroy() /* {{{ */
+{
+	xc_shm_t *shm = NULL;
+
+	if (origin_compile_file) {
+		zend_compile_file = origin_compile_file;
+		origin_compile_file = NULL;
+	}
+
+	if (xc_php_caches) {
+		shm = xc_cache_destroy(xc_php_caches, &xc_php_hcache);
+		xc_php_caches = NULL;
+	}
+	if (xc_var_caches) {
+		shm = xc_cache_destroy(xc_var_caches, &xc_var_hcache);
+		xc_var_caches = NULL;
+	}
+	if (shm) {
+		xc_shm_destroy(shm);
+	}
+}
+/* }}} */
+static int xc_init(int module_number TSRMLS_DC) /* {{{ */
+{
+	xc_shm_t *shm;
+	char *ptr;
+
+	xc_php_caches = xc_var_caches = NULL;
+
+	if (xc_php_size || xc_var_size) {
+		CHECK(shm = xc_shm_init(xc_mmap_path, ALIGN(xc_php_size) + ALIGN(xc_var_size), xc_readonly_protection), "Cannot create shm");
+		if (!xc_shm_can_readonly(shm)) {
+			xc_readonly_protection = 0;
+		}
+
+		ptr = (char *)xc_shm_ptr(shm);
+		if (xc_php_size) {
+			origin_compile_file = zend_compile_file;
+			zend_compile_file = xc_compile_file;
+
+			CHECK(xc_php_caches = xc_cache_init(shm, ptr, &xc_php_hcache, &xc_php_hentry, xc_php_size), "failed init opcode cache");
+			ptr += ALIGN(xc_php_size);
+		}
+
+		if (xc_var_size) {
+			CHECK(xc_var_caches = xc_cache_init(shm, ptr, &xc_var_hcache, &xc_var_hentry, xc_var_size), "failed init variable cache");
+		}
+	}
+	return 1;
+
+err:
+	if (xc_php_caches || xc_var_caches) {
+		xc_destroy();
+		/* shm destroied */
+	}
+	else if (shm) {
+		xc_shm_destroy(shm);
+	}
+	return 0;
+}
+/* }}} */
+static void xc_request_init(TSRMLS_D) /* {{{ */
+{
+	int i;
+
+	if (xc_php_hcache.size && !XG(php_holds)) {
+		XG(php_holds) = calloc(xc_php_hcache.size, sizeof(xc_stack_t));
+		for (i = 0; i < xc_php_hcache.size; i ++) {
+			xc_stack_init(&XG(php_holds[i]));
+		}
+	}
+
+	if (xc_var_hcache.size && !XG(var_holds)) {
+		XG(var_holds) = calloc(xc_var_hcache.size, sizeof(xc_stack_t));
+		for (i = 0; i < xc_var_hcache.size; i ++) {
+			xc_stack_init(&XG(var_holds[i]));
+		}
+	}
+
+	if (XG(cacher)) {
+#if PHP_API_VERSION <= 20041225
+		XG(request_time) = time(NULL);
+#else
+		XG(request_time) = sapi_get_request_time(TSRMLS_C);
+#endif
+	}
+#ifdef HAVE_XCACHE_COVERAGER
+	xc_coverager_request_init(TSRMLS_C);
+#endif
+}
+/* }}} */
+static void xc_request_shutdown(TSRMLS_D) /* {{{ */
+{
+	xc_entry_unholds(TSRMLS_C);
+#ifdef HAVE_XCACHE_COVERAGER
+	xc_coverager_request_shutdown(TSRMLS_C);
+#endif
+}
+/* }}} */
+static void xc_init_globals(zend_xcache_globals* xc_globals TSRMLS_DC) /* {{{ */
+{
+	memset(xc_globals, 0, sizeof(zend_xcache_globals));
+}
+/* }}} */
+static void xc_shutdown_globals(zend_xcache_globals* xc_globals TSRMLS_DC) /* {{{ */
+{
+	int i;
+
+	if (xc_globals->php_holds != NULL) {
+		for (i = 0; i < xc_php_hcache.size; i ++) {
+			xc_stack_destroy(&xc_globals->php_holds[i]);
+		}
+		free(xc_globals->php_holds);
+		xc_globals->php_holds = NULL;
+	}
+
+	if (xc_globals->var_holds != NULL) {
+		for (i = 0; i < xc_var_hcache.size; i ++) {
+			xc_stack_destroy(&xc_globals->var_holds[i]);
+		}
+		free(xc_globals->var_holds);
+		xc_globals->var_holds = NULL;
+	}
+}
+/* }}} */
+
+/* user functions */
+static int xcache_admin_auth_check(TSRMLS_D) /* {{{ */
+{
+	zval **server = NULL;
+	zval **user = NULL;
+	zval **pass = NULL;
+	char *admin_user = NULL;
+	char *admin_pass = NULL;
+	HashTable *ht;
+
+	if (cfg_get_string("xcache.admin.user", &admin_user) == FAILURE || !admin_user[0]) {
+		admin_user = NULL;
+	}
+	if (cfg_get_string("xcache.admin.pass", &admin_pass) == FAILURE || !admin_pass[0]) {
+		admin_pass = NULL;
+	}
+
+	if (admin_user == NULL || admin_pass == NULL) {
+		php_error_docref(NULL TSRMLS_CC, E_ERROR, "xcache.admin.user and xcache.admin.pass is required");
+		zend_bailout();
+	}
+	if (strlen(admin_pass) != 32) {
+		php_error_docref(NULL TSRMLS_CC, E_ERROR, "unexpect %d bytes of xcache.admin.pass, expected 32 bytes, the password after md5()", strlen(admin_pass));
+		zend_bailout();
+	}
+
+	if (zend_hash_find(&EG(symbol_table), "_SERVER", sizeof("_SERVER"), (void **) &server) != SUCCESS || Z_TYPE_PP(server) != IS_ARRAY) {
+		php_error_docref(NULL TSRMLS_CC, E_ERROR, "_SERVER is corrupted");
+		zend_bailout();
+	}
+	ht = HASH_OF((*server));
+
+	if (zend_hash_find(ht, "PHP_AUTH_USER", sizeof("PHP_AUTH_USER"), (void **) &user) == FAILURE) {
+	 	user = NULL;
+	}
+	else if (Z_TYPE_PP(user) != IS_STRING) {
+		user = NULL;
+	}
+
+	if (zend_hash_find(ht, "PHP_AUTH_PW", sizeof("PHP_AUTH_PW"), (void **) &pass) == FAILURE) {
+	 	pass = NULL;
+	}
+	else if (Z_TYPE_PP(pass) != IS_STRING) {
+		pass = NULL;
+	}
+
+	if (user != NULL && pass != NULL && strcmp(admin_user, Z_STRVAL_PP(user)) == 0) {
+		PHP_MD5_CTX context;
+		char md5str[33];
+		unsigned char digest[16];
+
+		PHP_MD5Init(&context);
+		PHP_MD5Update(&context, Z_STRVAL_PP(pass), Z_STRLEN_PP(pass));
+		PHP_MD5Final(digest, &context);
+
+		md5str[0] = '\0';
+		make_digest(md5str, digest);
+		if (strcmp(admin_pass, md5str) == 0) {
+			return 1;
+		}
+	}
+
+#define STR "WWW-authenticate: basic realm='XCache Administration'"
+	sapi_add_header_ex(STR, sizeof(STR) - 1, 1, 1 TSRMLS_CC);
+#undef STR
+#define STR "HTTP/1.0 401 Unauthorized"
+	sapi_add_header_ex(STR, sizeof(STR) - 1, 1, 1 TSRMLS_CC);
+#undef STR
+	ZEND_PUTS("XCache Auth Failed. User and Password is case sense\n");
+
+	zend_bailout();
+	return 0;
+}
+/* }}} */
+/* {{{ xcache_admin_operate */
+typedef enum { XC_OP_COUNT, XC_OP_INFO, XC_OP_LIST, XC_OP_CLEAR } xcache_op_type;
+static void xcache_admin_operate(xcache_op_type optype, INTERNAL_FUNCTION_PARAMETERS)
+{
+	long type;
+	int size;
+	xc_cache_t **caches, *cache;
+	long id = 0;
+
+	if (!xc_initized) {
+		php_error_docref(NULL TSRMLS_CC, E_WARNING, "XCache is not initized");
+		RETURN_FALSE;
+	}
+
+	xcache_admin_auth_check(TSRMLS_C);
+
+	if (optype == XC_OP_COUNT) {
+		if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &type) == FAILURE) {
+			return;
+		}
+	}
+	else if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ll", &type, &id) == FAILURE) {
+		return;
+	}
+
+	switch (type) {
+		case XC_TYPE_PHP:
+			size = xc_php_hcache.size;
+			caches = xc_php_caches;
+			break;
+
+		case XC_TYPE_VAR:
+			size = xc_var_hcache.size;
+			caches = xc_var_caches;
+			break;
+
+		default:
+			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown type %ld", type);
+			RETURN_FALSE;
+	}
+
+	switch (optype) {
+		case XC_OP_COUNT:
+			RETURN_LONG(size)
+			break;
+
+		case XC_OP_INFO:
+		case XC_OP_LIST:
+			if (id < 0 || id >= size) {
+				php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cache not exists");
+				RETURN_FALSE;
+			}
+
+			array_init(return_value);
+
+			cache = caches[id];
+			ENTER_LOCK(cache) {
+				if (optype == XC_OP_INFO) {
+					xc_fillinfo_dmz(cache, return_value TSRMLS_CC);
+				}
+				else {
+					xc_filllist_dmz(cache, return_value TSRMLS_CC);
+				}
+			} LEAVE_LOCK(cache);
+			break;
+		case XC_OP_CLEAR:
+			{
+				xc_entry_t *e;
+				int i, c;
+
+				if (id < 0 || id >= size) {
+					php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cache not exists");
+					RETURN_FALSE;
+				}
+
+				cache = caches[id];
+				ENTER_LOCK(cache) {
+					for (i = 0, c = cache->hentry->size; i < c; i ++) {
+						for (e = cache->entries[i]; e; e = e->next) {
+							xc_entry_remove_dmz(e TSRMLS_CC);
+						}
+						cache->entries[i] = NULL;
+					}
+				} LEAVE_LOCK(cache);
+				xc_entry_gc(TSRMLS_C);
+			}
+			break;
+
+		default:
+			assert(0);
+	}
+}
+/* }}} */
+/* {{{ proto int xcache_count(int type)
+   Return count of cache on specified cache type */
+PHP_FUNCTION(xcache_count)
+{
+	xcache_admin_operate(XC_OP_COUNT, INTERNAL_FUNCTION_PARAM_PASSTHRU);
+}
+/* }}} */
+/* {{{ proto array xcache_info(int type, int id)
+   Get cache info by id on specified cache type */
+PHP_FUNCTION(xcache_info)
+{
+	xcache_admin_operate(XC_OP_INFO, INTERNAL_FUNCTION_PARAM_PASSTHRU);
+}
+/* }}} */
+/* {{{ proto array xcache_list(int type, int id)
+   Get cache entries list by id on specified cache type */
+PHP_FUNCTION(xcache_list)
+{
+	xcache_admin_operate(XC_OP_LIST, INTERNAL_FUNCTION_PARAM_PASSTHRU);
+}
+/* }}} */
+/* {{{ proto array xcache_clear_cache(int type, int id)
+   Clear cache by id on specified cache type */
+PHP_FUNCTION(xcache_clear_cache)
+{
+	xcache_admin_operate(XC_OP_CLEAR, INTERNAL_FUNCTION_PARAM_PASSTHRU);
+}
+/* }}} */
+
+static int xc_entry_init_key_var(xc_entry_t *xce, zval *name TSRMLS_DC) /* {{{ */
+{
+	xc_hash_value_t hv;
+	int cacheid;
+
+	switch (Z_TYPE_P(name)) {
+#ifdef IS_UNICODE
+		case IS_UNICODE:
+#endif
+		case IS_STRING:
+			break;
+		default:
+#ifdef IS_UNICODE
+			convert_to_text(name);
+#else
+			convert_to_string(name);
+#endif
+	}
+#ifdef IS_UNICODE
+	xce->name_type = name->type;
+#endif
+	xce->name = name->value;
+
+	hv = xc_entry_hash_var(xce);
+
+	cacheid = (hv & xc_var_hcache.mask);
+	xce->cache = xc_var_caches[cacheid];
+	hv >>= xc_var_hcache.bits;
+	xce->hvalue = (hv & xc_var_hentry.mask);
+
+	xce->type = XC_TYPE_VAR;
+	return SUCCESS;
+}
+/* }}} */
+#define TIME_MAX (sizeof(time_t) == sizeof(long) ? LONG_MAX : INT_MAX)
+/* {{{ proto mixed xcache_get(string name)
+   Get cached data by specified name */
+PHP_FUNCTION(xcache_get)
+{
+	xc_entry_t xce, *stored_xce;
+	xc_entry_data_var_t var;
+	zval *name;
+
+	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &name) == FAILURE) {
+		return;
+	}
+	xce.data.var = &var;
+	xc_entry_init_key_var(&xce, name TSRMLS_CC);
+
+	ENTER_LOCK(xce.cache) {
+		stored_xce = xc_entry_find_dmz(&xce TSRMLS_CC);
+		if (stored_xce) {
+			if (XG(request_time) <= stored_xce->data.var->etime) {
+				xc_processor_restore_zval(return_value, stored_xce->data.var->value TSRMLS_CC);
+				/* return */
+				break;
+			}
+			else {
+				xc_entry_remove_dmz(stored_xce TSRMLS_CC);
+			}
+		}
+
+		RETVAL_NULL();
+	} LEAVE_LOCK(xce.cache);
+}
+/* }}} */
+/* {{{ proto bool  xcache_set(string name, mixed value [, int ttl])
+   Store data to cache by specified name */
+PHP_FUNCTION(xcache_set)
+{
+	xc_entry_t xce, *stored_xce;
+	xc_entry_data_var_t var;
+	zval *name;
+	zval *value;
+	long ttl = 0;
+
+	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz|l", &name, &value, &ttl) == FAILURE) {
+		return;
+	}
+	xce.data.var = &var;
+	xc_entry_init_key_var(&xce, name TSRMLS_CC);
+
+	ENTER_LOCK(xce.cache) {
+		stored_xce = xc_entry_find_dmz(&xce TSRMLS_CC);
+		if (stored_xce) {
+			xc_entry_remove_dmz(stored_xce TSRMLS_CC);
+		}
+		var.value = value;
+		var.etime = ttl ? XG(request_time) + ttl : TIME_MAX;
+		RETVAL_BOOL(xc_entry_store_dmz(&xce TSRMLS_CC) != NULL ? 1 : 0);
+	} LEAVE_LOCK(xce.cache);
+}
+/* }}} */
+/* {{{ proto bool  xcache_isset(string name)
+   Check if an entry exists in cache by specified name */
+PHP_FUNCTION(xcache_isset)
+{
+	xc_entry_t xce, *stored_xce;
+	xc_entry_data_var_t var;
+	zval *name;
+
+	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &name) == FAILURE) {
+		return;
+	}
+	xce.data.var = &var;
+	xc_entry_init_key_var(&xce, name TSRMLS_CC);
+
+	ENTER_LOCK(xce.cache) {
+		stored_xce = xc_entry_find_dmz(&xce TSRMLS_CC);
+		if (stored_xce) {
+			if (XG(request_time) <= stored_xce->data.var->etime) {
+				RETVAL_TRUE;
+				/* return */
+				break;
+			}
+			else {
+				xc_entry_remove_dmz(stored_xce TSRMLS_CC);
+			}
+		}
+
+		RETVAL_FALSE;
+	} LEAVE_LOCK(xce.cache);
+}
+/* }}} */
+/* {{{ proto bool  xcache_unset(string name)
+   Unset existing data in cache by specified name */
+PHP_FUNCTION(xcache_unset)
+{
+	xc_entry_t xce, *stored_xce;
+	xc_entry_data_var_t var;
+	zval *name;
+
+	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &name) == FAILURE) {
+		return;
+	}
+	xce.data.var = &var;
+	xc_entry_init_key_var(&xce, name TSRMLS_CC);
+
+	ENTER_LOCK(xce.cache) {
+		stored_xce = xc_entry_find_dmz(&xce TSRMLS_CC);
+		if (stored_xce) {
+			xc_entry_remove_dmz(stored_xce TSRMLS_CC);
+			RETVAL_TRUE;
+		}
+		else {
+			RETVAL_FALSE;
+		}
+	} LEAVE_LOCK(xce.cache);
+}
+/* }}} */
+static inline void xc_var_inc_dec(int inc, INTERNAL_FUNCTION_PARAMETERS) /* {{{ */
+{
+	xc_entry_t xce, *stored_xce;
+	xc_entry_data_var_t var, *stored_var;
+	zval *name;
+	long count = 1;
+	long ttl = 0;
+	long value = 0;
+	zval oldzval;
+
+	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|ll", &name, &count, &ttl) == FAILURE) {
+		return;
+	}
+	xce.data.var = &var;
+	xc_entry_init_key_var(&xce, name TSRMLS_CC);
+
+	ENTER_LOCK(xce.cache) {
+		stored_xce = xc_entry_find_dmz(&xce TSRMLS_CC);
+		if (stored_xce) {
+#ifdef DEBUG
+			fprintf(stderr, "incdec: gotxce %s\n", xce.name.str.val);
+#endif
+			stored_var = stored_xce->data.var;
+			/* timeout */
+			if (XG(request_time) > stored_var->etime) {
+#ifdef DEBUG
+				fprintf(stderr, "incdec: expired\n");
+#endif
+				xc_entry_remove_dmz(stored_xce TSRMLS_CC);
+				stored_xce = NULL;
+			}
+			else {
+				/* do it in place */
+				if (Z_TYPE_P(stored_var->value) == IS_LONG) {
+#ifdef DEBUG
+					fprintf(stderr, "incdec: islong\n");
+#endif
+					value = Z_LVAL_P(stored_var->value);
+					value += (inc == 1 ? count : - count);
+					RETVAL_LONG(value);
+					Z_LVAL_P(stored_var->value) = value;
+					break;
+				}
+				else {
+#ifdef DEBUG
+					fprintf(stderr, "incdec: notlong\n");
+#endif
+					xc_processor_restore_zval(&oldzval, stored_xce->data.var->value TSRMLS_CC);
+					convert_to_long(&oldzval);
+					value = Z_LVAL(oldzval);
+					zval_dtor(&oldzval);
+				}
+			}
+		}
+#ifdef DEBUG
+		else {
+			fprintf(stderr, "incdec: %s not found\n", xce.name.str.val);
+		}
+#endif
+
+		value += (inc == 1 ? count : - count);
+		RETVAL_LONG(value);
+		var.value = return_value;
+		var.etime = ttl ? XG(request_time) + ttl : TIME_MAX;
+		if (stored_xce) {
+			xce.atime = stored_xce->atime;
+			xce.ctime = stored_xce->ctime;
+			xce.hits  = stored_xce->hits;
+			xc_entry_remove_dmz(stored_xce TSRMLS_CC);
+		}
+		xc_entry_store_dmz(&xce TSRMLS_CC);
+
+	} LEAVE_LOCK(xce.cache);
+}
+/* }}} */
+/* {{{ proto int xcache_inc(string name [, int value [, int ttl]])
+   Increase an int counter in cache by specified name, create it if not exists */
+PHP_FUNCTION(xcache_inc)
+{
+	xc_var_inc_dec(1, INTERNAL_FUNCTION_PARAM_PASSTHRU);
+}
+/* }}} */
+/* {{{ proto int xcache_dec(string name [, int value [, int ttl]])
+   Decrease an int counter in cache by specified name, create it if not exists */
+PHP_FUNCTION(xcache_dec)
+{
+	xc_var_inc_dec(-1, INTERNAL_FUNCTION_PARAM_PASSTHRU);
+}
+/* }}} */
+/* {{{ proto string xcache_asm(string filename)
+ */
+#ifdef HAVE_XCACHE_ASSEMBLER
+PHP_FUNCTION(xcache_asm)
+{
+}
+#endif
+/* }}} */
+#ifdef HAVE_XCACHE_DISASSEMBLER
+/* {{{ proto array  xcache_dasm_file(string filename)
+   Disassemble file into opcode array by filename */
+PHP_FUNCTION(xcache_dasm_file)
+{
+	char *filename;
+	long filename_len;
+
+	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &filename, &filename_len) == FAILURE) {
+		return;
+	}
+	if (!filename_len) RETURN_FALSE;
+
+	xc_dasm_file(return_value, filename TSRMLS_CC);
+}
+/* }}} */
+/* {{{ proto array  xcache_dasm_string(string code)
+   Disassemble php code into opcode array */
+PHP_FUNCTION(xcache_dasm_string)
+{
+	zval *code;
+
+	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &code) == FAILURE) {
+		return;
+	}
+	xc_dasm_string(return_value, code TSRMLS_CC);
+}
+/* }}} */
+#endif
+/* {{{ proto string xcache_encode(string filename)
+   Encode php file into XCache opcode encoded format */
+#ifdef HAVE_XCACHE_ENCODER
+PHP_FUNCTION(xcache_encode)
+{
+}
+#endif
+/* }}} */
+/* {{{ proto bool xcache_decode_file(string filename)
+   Decode(load) opcode from XCache encoded format file */
+#ifdef HAVE_XCACHE_DECODER
+PHP_FUNCTION(xcache_decode_file)
+{
+}
+#endif
+/* }}} */
+/* {{{ proto bool xcache_decode_string(string data)
+   Decode(load) opcode from XCache encoded format data */
+#ifdef HAVE_XCACHE_DECODER
+PHP_FUNCTION(xcache_decode_string)
+{
+}
+#endif
+/* }}} */
+/* {{{ xc_call_getter */
+typedef const char *(xc_name_getter_t)(zend_uchar type);
+static void xc_call_getter(xc_name_getter_t getter, int count, INTERNAL_FUNCTION_PARAMETERS)
+{
+	long spec;
+	const char *name;
+
+	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &spec) == FAILURE) {
+		return;
+	}
+	if (spec >= 0 && spec < count) {
+		name = getter((zend_uchar) spec);
+		if (name) {
+			/* RETURN_STRING */
+			int len = strlen(name);
+			return_value->value.str.len = len;
+			return_value->value.str.val = estrndup(name, len);
+			return_value->type = IS_STRING; 
+			return;
+		}
+	}
+	RETURN_NULL();
+}
+/* }}} */
+/* {{{ proto string xcache_get_op_type(int op_type) */
+PHP_FUNCTION(xcache_get_op_type)
+{
+	xc_call_getter(xc_get_op_type, xc_get_op_type_count(), INTERNAL_FUNCTION_PARAM_PASSTHRU);
+}
+/* }}} */
+/* {{{ proto string xcache_get_data_type(int type) */
+PHP_FUNCTION(xcache_get_data_type)
+{
+	xc_call_getter(xc_get_data_type, xc_get_data_type_count(), INTERNAL_FUNCTION_PARAM_PASSTHRU);
+}
+/* }}} */
+/* {{{ proto string xcache_get_opcode(int opcode) */
+PHP_FUNCTION(xcache_get_opcode)
+{
+	xc_call_getter(xc_get_opcode, xc_get_opcode_count(), INTERNAL_FUNCTION_PARAM_PASSTHRU);
+}
+/* }}} */
+/* {{{ proto string xcache_get_op_spec(int op_type) */
+PHP_FUNCTION(xcache_get_op_spec)
+{
+	xc_call_getter(xc_get_op_spec, xc_get_op_spec_count(), INTERNAL_FUNCTION_PARAM_PASSTHRU);
+}
+/* }}} */
+#ifdef HAVE_XCACHE_OPCODE_SPEC_DEF
+/* {{{ proto string xcache_get_opcode_spec(int opcode) */
+PHP_FUNCTION(xcache_get_opcode_spec)
+{
+	long spec;
+	const xc_opcode_spec_t *opspec;
+
+	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &spec) == FAILURE) {
+		return;
+	}
+	if ((zend_uchar) spec <= xc_get_opcode_spec_count()) {
+		opspec = xc_get_opcode_spec((zend_uchar) spec);
+		if (opspec) {
+			array_init(return_value);
+			add_assoc_long_ex(return_value, ZEND_STRS("ext"), opspec->ext);
+			add_assoc_long_ex(return_value, ZEND_STRS("op1"), opspec->op1);
+			add_assoc_long_ex(return_value, ZEND_STRS("op2"), opspec->op2);
+			add_assoc_long_ex(return_value, ZEND_STRS("res"), opspec->res);
+			return;
+		}
+	}
+	RETURN_NULL();
+}
+/* }}} */
+#endif
+/* {{{ proto mixed xcache_get_special_value(zval value) */
+PHP_FUNCTION(xcache_get_special_value)
+{
+	zval *value;
+
+	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &value) == FAILURE) {
+		return;
+	}
+
+	if (value->type == IS_CONSTANT) {
+		*return_value = *value;
+		zval_copy_ctor(return_value);
+		return_value->type = UNISW(IS_STRING, UG(unicode) ? IS_UNICODE : IS_STRING);
+		return;
+	}
+
+	if (value->type == IS_CONSTANT_ARRAY) {
+		*return_value = *value;
+		zval_copy_ctor(return_value);
+		return_value->type = IS_ARRAY;
+		return;
+	}
+
+	RETURN_NULL();
+}
+/* }}} */
+/* {{{ proto string xcache_coredump(int op_type) */
+PHP_FUNCTION(xcache_coredump)
+{
+	if (xc_test) {
+		raise(SIGSEGV);
+	}
+	else {
+		php_error_docref(NULL TSRMLS_CC, E_WARNING, "xcache.test must be enabled to test xcache_coredump()");
+	}
+}
+/* }}} */
+/* {{{ proto string xcache_is_autoglobal(string name) */
+PHP_FUNCTION(xcache_is_autoglobal)
+{
+	char *name;
+	long name_len;
+
+	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &name, &name_len) == FAILURE) {
+		return;
+	}
+
+	RETURN_BOOL(zend_hash_exists(CG(auto_globals), name, name_len + 1));
+}
+/* }}} */
+static function_entry xcache_functions[] = /* {{{ */
+{
+	PHP_FE(xcache_count,             NULL)
+	PHP_FE(xcache_info,              NULL)
+	PHP_FE(xcache_list,              NULL)
+	PHP_FE(xcache_clear_cache,       NULL)
+	PHP_FE(xcache_coredump,          NULL)
+#ifdef HAVE_XCACHE_ASSEMBLER
+	PHP_FE(xcache_asm,               NULL)
+#endif
+#ifdef HAVE_XCACHE_DISASSEMBLER
+	PHP_FE(xcache_dasm_file,         NULL)
+	PHP_FE(xcache_dasm_string,       NULL)
+#endif
+#ifdef HAVE_XCACHE_ENCODER
+	PHP_FE(xcache_encode,            NULL)
+#endif
+#ifdef HAVE_XCACHE_DECODER
+	PHP_FE(xcache_decode_file,       NULL)
+	PHP_FE(xcache_decode_string,     NULL)
+#endif
+#ifdef HAVE_XCACHE_COVERAGER
+	PHP_FE(xcache_coverager_decode,  NULL)
+#endif
+	PHP_FE(xcache_get_special_value, NULL)
+	PHP_FE(xcache_get_op_type,       NULL)
+	PHP_FE(xcache_get_data_type,     NULL)
+	PHP_FE(xcache_get_opcode,        NULL)
+#ifdef HAVE_XCACHE_OPCODE_SPEC_DEF
+	PHP_FE(xcache_get_opcode_spec,   NULL)
+#endif
+	PHP_FE(xcache_is_autoglobal,     NULL)
+	PHP_FE(xcache_inc,               NULL)
+	PHP_FE(xcache_dec,               NULL)
+	PHP_FE(xcache_get,               NULL)
+	PHP_FE(xcache_set,               NULL)
+	PHP_FE(xcache_isset,             NULL)
+	PHP_FE(xcache_unset,             NULL)
+	{NULL, NULL,                     NULL}
+};
+/* }}} */
+
+/* signal handler */
+static void (*original_sigsegv_handler)(int) = NULL;
+static void xcache_sigsegv_handler(int sig) /* {{{ */
+{
+	if (original_sigsegv_handler != xcache_sigsegv_handler) {
+		signal(SIGSEGV, original_sigsegv_handler);
+	}
+	else {
+		signal(SIGSEGV, SIG_DFL);
+	}
+	if (xc_coredump_dir && xc_coredump_dir[0]) {
+		chdir(xc_coredump_dir);
+	}
+	raise(sig);
+}
+/* }}} */
+
+/* {{{ PHP_INI */
+static PHP_INI_MH(xc_OnUpdateLong)
+{
+	long *p = (long *)mh_arg1;
+	*p = zend_atoi(new_value, new_value_length);
+	return SUCCESS;
+}
+
+static PHP_INI_MH(xc_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(xc_OnUpdateHashInfo)
+{
+	xc_hash_t *p = (xc_hash_t *)mh_arg1;
+	int bits, size;
+
+	p->size = zend_atoi(new_value, new_value_length);
+	for (size = 1, bits = 1; size < p->size; bits ++, size <<= 1) {
+		/* empty body */
+	}
+	p->size = size;
+	p->bits = bits;
+	p->mask = size - 1;
+
+	return SUCCESS;
+}
+
+static PHP_INI_MH(xc_OnUpdateString)
+{
+	char **p = (char**)mh_arg1;
+	if (*p) {
+		pefree(*p, 1);
+	}
+	*p = pemalloc(strlen(new_value) + 1, 1);
+	strcpy(*p, new_value);
+	return SUCCESS;
+}
+#ifdef ZEND_ENGINE_2
+#define OnUpdateInt OnUpdateLong
+#endif
+
+#ifdef ZEND_WIN32
+#	define DEFAULT_PATH "xcache"
+#else
+#	define DEFAULT_PATH "/dev/zero"
+#endif
+PHP_INI_BEGIN()
+	PHP_INI_ENTRY1     ("xcache.size",                   "0", PHP_INI_SYSTEM, xc_OnUpdateLong,     &xc_php_size)
+	PHP_INI_ENTRY1     ("xcache.count",                  "1", PHP_INI_SYSTEM, xc_OnUpdateHashInfo, &xc_php_hcache)
+	PHP_INI_ENTRY1     ("xcache.slots",                 "8K", PHP_INI_SYSTEM, xc_OnUpdateHashInfo, &xc_php_hentry)
+
+	PHP_INI_ENTRY1     ("xcache.var_size",               "0", PHP_INI_SYSTEM, xc_OnUpdateLong,     &xc_var_size)
+	PHP_INI_ENTRY1     ("xcache.var_count",              "1", PHP_INI_SYSTEM, xc_OnUpdateHashInfo, &xc_var_hcache)
+	PHP_INI_ENTRY1     ("xcache.var_slots",             "8K", PHP_INI_SYSTEM, xc_OnUpdateHashInfo, &xc_var_hentry)
+
+	PHP_INI_ENTRY1     ("xcache.mmap_path",     DEFAULT_PATH, PHP_INI_SYSTEM, xc_OnUpdateString,   &xc_mmap_path)
+	PHP_INI_ENTRY1     ("xcache.coredump_directory",      "", PHP_INI_SYSTEM, xc_OnUpdateString,   &xc_coredump_dir)
+	PHP_INI_ENTRY1     ("xcache.test",                   "0", PHP_INI_SYSTEM, xc_OnUpdateBool,     &xc_test)
+	PHP_INI_ENTRY1     ("xcache.readonly_protection",    "0", PHP_INI_SYSTEM, xc_OnUpdateBool,     &xc_readonly_protection)
+
+	STD_PHP_INI_BOOLEAN("xcache.cacher",                 "1", PHP_INI_ALL,    OnUpdateBool,        cacher,            zend_xcache_globals, xcache_globals)
+#ifdef HAVE_XCACHE_OPTIMIZER
+	STD_PHP_INI_BOOLEAN("xcache.optimizer",              "0", PHP_INI_ALL,    OnUpdateBool,        optimizer,         zend_xcache_globals, xcache_globals)
+#endif
+#ifdef HAVE_XCACHE_COVERAGER
+	PHP_INI_ENTRY1     ("xcache.coveragedump_directory", "/tmp/pcov/", PHP_INI_SYSTEM, xc_OnUpdateString,   &xc_coveragedump_dir)
+	STD_PHP_INI_BOOLEAN("xcache.coveragedumper" ,                 "0", PHP_INI_ALL,    OnUpdateBool,        coveragedumper,    zend_xcache_globals, xcache_globals)
+#endif
+PHP_INI_END()
+/* }}} */
+/* {{{ PHP_MINFO_FUNCTION(xcache) */
+static PHP_MINFO_FUNCTION(xcache)
+{
+	php_info_print_table_start();
+	php_info_print_table_header(2, "XCache Support", (xc_php_size || xc_var_size) ? "enabled" : "disabled");
+	php_info_print_table_row(2, "Version", XCACHE_VERSION);
+	php_info_print_table_row(2, "Modules Built", XCACHE_MODULES);
+	php_info_print_table_row(2, "Readonly Protection", xc_readonly_protection ? "enabled" : "N/A");
+	php_info_print_table_row(2, "Opcode Cache", xc_php_size ? "enabled" : "disabled");
+	php_info_print_table_row(2, "Variable Cache", xc_var_size ? "enabled" : "disabled");
+#ifdef HAVE_XCACHE_COVERAGER
+	php_info_print_table_row(2, "Coverage Dumper", XG(coveragedumper) && xc_coveragedump_dir && xc_coveragedump_dir[0] ? "enabled" : "disabled");
+#endif
+	php_info_print_table_end();
+	DISPLAY_INI_ENTRIES();
+}
+/* }}} */
+/* {{{ extension startup */
+static void xc_zend_extension_register(zend_extension *new_extension, DL_HANDLE handle)
+{
+    zend_extension extension;
+
+    extension = *new_extension;
+    extension.handle = handle;
+
+    zend_extension_dispatch_message(ZEND_EXTMSG_NEW_EXTENSION, &extension);
+
+    zend_llist_add_element(&zend_extensions, &extension);
+#ifdef DEBUG
+	fprintf(stderr, "registered\n");
+#endif
+}
+
+/* dirty check */
+#if defined(COMPILE_DL_XCACHE) && (defined(ZEND_WIN32) || defined(__CYGWIN__) || defined(__MINGW32__))
+#	define zend_append_version_info(x) do { } while (0)
+#else
+extern void zend_append_version_info(zend_extension *extension);
+#endif
+static int xc_zend_extension_startup(zend_extension *extension)
+{
+    if (extension->startup) {
+        if (extension->startup(extension) != SUCCESS) {
+			return FAILURE;
+        }
+        zend_append_version_info(extension);
+    }
+	return SUCCESS;
+}
+/* }}} */
+/* {{{ PHP_MINIT_FUNCTION(xcache) */
+static PHP_MINIT_FUNCTION(xcache)
+{
+	char *env;
+
+	xc_module_gotup = 1;
+	if (!xc_zend_extension_gotup) {
+		if (zend_get_extension(XCACHE_NAME) == NULL) {
+			xc_zend_extension_register(&zend_extension_entry, 0);
+			xc_zend_extension_startup(&zend_extension_entry);
+		}
+	}
+
+	ZEND_INIT_MODULE_GLOBALS(xcache, xc_init_globals, xc_shutdown_globals);
+	REGISTER_INI_ENTRIES();
+
+	if (strcmp(sapi_module.name, "cli") == 0) {
+		if ((env = getenv("XCACHE_TEST")) != NULL) {
+			zend_alter_ini_entry("xcache.test", sizeof("xcache.test"), env, strlen(env) + 1, PHP_INI_SYSTEM, PHP_INI_STAGE_STARTUP);
+		}
+		if (!xc_test) {
+			/* disable cache for cli except for test */
+			xc_php_size = xc_var_size = 0;
+		}
+	}
+
+	if (xc_php_size <= 0) {
+		xc_php_size = xc_php_hcache.size = 0;
+	}
+	if (xc_var_size <= 0) {
+		xc_var_size = xc_var_hcache.size = 0;
+	}
+
+	if (xc_coredump_dir && xc_coredump_dir[0]) {
+		original_sigsegv_handler = signal(SIGSEGV, xcache_sigsegv_handler);
+	}
+
+	xc_init_constant(module_number TSRMLS_CC);
+
+	if ((xc_php_size || xc_var_size) && xc_mmap_path && xc_mmap_path[0]) {
+		if (!xc_init(module_number TSRMLS_CC)) {
+			zend_error(E_ERROR, "XCache: Cannot init");
+			goto err_init;
+		}
+		xc_initized = 1;
+	}
+
+#ifdef HAVE_XCACHE_COVERAGER
+	xc_coverager_init(module_number TSRMLS_CC);
+#endif
+
+	return SUCCESS;
+
+err_init:
+	return FAILURE;
+}
+/* }}} */
+/* {{{ PHP_MSHUTDOWN_FUNCTION(xcache) */
+static PHP_MSHUTDOWN_FUNCTION(xcache)
+{
+	if (xc_initized) {
+		xc_destroy();
+		xc_initized = 0;
+	}
+	if (xc_mmap_path) {
+		pefree(xc_mmap_path, 1);
+		xc_mmap_path = NULL;
+	}
+
+#ifdef HAVE_XCACHE_COVERAGER
+	xc_coverager_destroy();
+#endif
+
+	if (xc_coredump_dir && xc_coredump_dir[0]) {
+		signal(SIGSEGV, original_sigsegv_handler);
+	}
+	if (xc_coredump_dir) {
+		pefree(xc_coredump_dir, 1);
+		xc_coredump_dir = NULL;
+	}
+#ifdef ZTS
+	ts_free_id(xcache_globals_id);
+#else
+	xc_shutdown_globals(&xcache_globals TSRMLS_CC);
+#endif
+
+	UNREGISTER_INI_ENTRIES();
+	return SUCCESS;
+}
+/* }}} */
+/* {{{ PHP_RINIT_FUNCTION(xcache) */
+static PHP_RINIT_FUNCTION(xcache)
+{
+	xc_request_init(TSRMLS_C);
+	return SUCCESS;
+}
+/* }}} */
+/* {{{ PHP_RSHUTDOWN_FUNCTION(xcache) */
+#ifndef ZEND_ENGINE_2
+static PHP_RSHUTDOWN_FUNCTION(xcache)
+#else
+static ZEND_MODULE_POST_ZEND_DEACTIVATE_D(xcache)
+#endif
+{
+#ifdef ZEND_ENGINE_2
+	TSRMLS_FETCH();
+#endif
+
+	xc_request_shutdown(TSRMLS_C);
+	return SUCCESS;
+}
+/* }}} */
+/* {{{ module definition structure */
+
+zend_module_entry xcache_module_entry = {
+	STANDARD_MODULE_HEADER,
+	"XCache",
+	xcache_functions,
+	PHP_MINIT(xcache),
+	PHP_MSHUTDOWN(xcache),
+	PHP_RINIT(xcache),
+#ifndef ZEND_ENGINE_2
+	PHP_RSHUTDOWN(xcache),
+#else
+	NULL,
+#endif
+	PHP_MINFO(xcache),
+	XCACHE_VERSION,
+#ifdef ZEND_ENGINE_2
+	ZEND_MODULE_POST_ZEND_DEACTIVATE_N(xcache),
+#else
+	NULL,
+	NULL,
+#endif
+	STANDARD_MODULE_PROPERTIES_EX
+};
+
+#ifdef COMPILE_DL_XCACHE
+ZEND_GET_MODULE(xcache)
+#endif
+/* }}} */
+ZEND_DLEXPORT int xcache_zend_startup(zend_extension *extension) /* {{{ */
+{
+	if (xc_zend_extension_gotup) {
+		return FAILURE;
+	}
+	xc_zend_extension_gotup = 1;
+	if (!xc_module_gotup) {
+		return zend_startup_module(&xcache_module_entry);
+	}
+	return SUCCESS;
+}
+/* }}} */
+ZEND_DLEXPORT void xcache_zend_shutdown(zend_extension *extension) /* {{{ */
+{
+	/* empty */
+}
+/* }}} */
+ZEND_DLEXPORT void xcache_statement_handler(zend_op_array *op_array) /* {{{ */
+{
+#ifdef HAVE_XCACHE_COVERAGER
+	xc_coverager_handle_ext_stmt(op_array, ZEND_EXT_STMT);
+#endif
+}
+/* }}} */
+ZEND_DLEXPORT void xcache_fcall_begin_handler(zend_op_array *op_array) /* {{{ */
+{
+#if 0
+	xc_coverager_handle_ext_stmt(op_array, ZEND_EXT_FCALL_BEGIN);
+#endif
+}
+/* }}} */
+ZEND_DLEXPORT void xcache_fcall_end_handler(zend_op_array *op_array) /* {{{ */
+{
+#if 0
+	xc_coverager_handle_ext_stmt(op_array, ZEND_EXT_FCALL_END);
+#endif
+}
+/* }}} */
+/* {{{ zend extension definition structure */
+ZEND_DLEXPORT zend_extension zend_extension_entry = {
+	XCACHE_NAME,
+	XCACHE_VERSION,
+	XCACHE_AUTHOR,
+	XCACHE_URL,
+	XCACHE_COPYRIGHT,
+	xcache_zend_startup,
+	xcache_zend_shutdown,
+	NULL,           /* activate_func_t */
+	NULL,           /* deactivate_func_t */
+	NULL,           /* message_handler_func_t */
+	NULL,           /* op_array_handler_func_t */
+	xcache_statement_handler,
+	xcache_fcall_begin_handler,
+	xcache_fcall_end_handler,
+	NULL,           /* op_array_ctor_func_t */
+	NULL,           /* op_array_dtor_func_t */
+	STANDARD_ZEND_EXTENSION_PROPERTIES
+};
+
+#ifndef ZEND_EXT_API
+#	define ZEND_EXT_API ZEND_DLEXPORT
+#endif
+#if COMPILE_DL_XCACHE
+ZEND_EXTENSION();
+#endif
+/* }}} */
Index: /tags/1.0/.cvsignore
===================================================================
--- /tags/1.0/.cvsignore	(revision 10)
+++ /tags/1.0/.cvsignore	(revision 10)
@@ -0,0 +1,33 @@
+acinclude.m4
+aclocal.m4
+build
+config.cache
+config.guess
+config.h
+config.h.in
+config.log
+config.nice
+config.status
+config.sub
+configure
+configure.in
+conftest
+conftest.c
+.deps
+include
+includes.i
+install-sh
+libtool
+ltmain.sh
+Makefile
+Makefile.fragments
+Makefile.global
+Makefile.objects
+missing
+mkinstalldirs
+modules
+processor.h
+processor.out
+processor_real.c
+run-tests.php
+structinfo.m4
Index: /tags/1.0/Decompiler.class.php
===================================================================
--- /tags/1.0/Decompiler.class.php	(revision 1)
+++ /tags/1.0/Decompiler.class.php	(revision 1)
@@ -0,0 +1,1886 @@
+<?php
+
+define('INDENT', "\t");
+ini_set('error_reporting', E_ALL);
+
+function color($str, $color = 33)
+{
+	return "\x1B[{$color}m$str\x1B[0m";
+}
+
+function str($src, $indent = '') // {{{
+{
+	if (is_array($indent)) {
+		$indent = $indent['indent'];
+	}
+
+	/*
+	$e = xcache_get_special_value($src);
+	if (isset($e)) {
+		if (is_array($e)) {
+			$src = $e;
+		}
+		else {
+			return $e;
+		}
+	}
+	*/
+
+	if (is_array($src)) {
+		die_error('array str');
+		$src = new Decompiler_Array($src);
+		return $src->__toString($indent);
+	}
+
+	if (is_object($src)) {
+		if (!method_exists($src, '__toString')) {
+			var_dump($src);
+			die_error('no __toString');
+		}
+		return $src->__toString($indent);
+	}
+
+	return $src;
+}
+// }}}
+function value($value) // {{{
+{
+	$spec = xcache_get_special_value($value);
+	if (isset($spec)) {
+		$value = $spec;
+		if (!is_array($value)) {
+			// constant
+			return $value;
+		}
+	}
+
+	if (is_array($value)) {
+		$value = new Decompiler_Array($value, true);
+	}
+	else {
+		$value = new Decompiler_Value($value, true);
+	}
+	return $value;
+}
+// }}}
+class Decompiler_Object // {{{
+{
+}
+// }}}
+class Decompiler_Value extends Decompiler_Object // {{{
+{
+	var $value;
+
+	function Decompiler_Value($value = null)
+	{
+		$this->value = $value;
+	}
+
+	function __toString()
+	{
+		return var_export($this->value, true);
+	}
+}
+// }}}
+class Decompiler_Code extends Decompiler_Object // {{{
+{
+	var $src;
+
+	function Decompiler_Code($src)
+	{
+		$this->src = $src;
+	}
+
+	function __toString()
+	{
+		return $this->src;
+	}
+}
+// }}}
+class Decompiler_Binop extends Decompiler_Code // {{{
+{
+	var $opc;
+	var $op1;
+	var $op2;
+	var $parent;
+
+	function Decompiler_Binop($parent, $op1, $opc, $op2)
+	{
+		$this->parent = &$parent;
+		$this->opc = $opc;
+		$this->op1 = $op1;
+		$this->op2 = $op2;
+	}
+
+	function __toString()
+	{
+		$op1 = str($this->op1);
+		if (is_a($this->op1, 'Decompiler_Binop') && $this->op1->opc != $this->opc) {
+			$op1 = "($op1)";
+		}
+		$opstr = $this->parent->binops[$this->opc];
+		if ($op1 == '0' && $this->opc == XC_SUB) {
+			return $opstr . str($this->op2);
+		}
+		return $op1 . ' ' . $opstr . ' ' . str($this->op2);
+	}
+}
+// }}}
+class Decompiler_Fetch extends Decompiler_Code // {{{
+{
+	var $src;
+	var $fetchType;
+
+	function Decompiler_Fetch($src, $type, $globalsrc)
+	{
+		$this->src = $src;
+		$this->fetchType = $type;
+		$this->globalsrc = $globalsrc;
+	}
+
+	function __toString()
+	{
+		switch ($this->fetchType) {
+		case ZEND_FETCH_LOCAL:
+			return '$' . substr($this->src, 1, -1);
+		case ZEND_FETCH_STATIC:
+			die('static fetch cant to string');
+		case ZEND_FETCH_GLOBAL:
+		case ZEND_FETCH_GLOBAL_LOCK:
+			return $this->globalsrc;
+		default:
+			var_dump($this->fetchType);
+			assert(0);
+		}
+	}
+}
+// }}}
+class Decompiler_Box // {{{
+{
+	var $obj;
+
+	function Decompiler_Box(&$obj)
+	{
+		$this->obj = &$obj;
+	}
+
+	function __toString($indent)
+	{
+		return $this->obj->__toString($indent);
+	}
+}
+// }}}
+class Decompiler_Dim extends Decompiler_Value // {{{
+{
+	var $offsets = array();
+	var $isLast = false;
+	var $assign = null;
+
+	function __toString()
+	{
+		if (is_a($this->value, 'Decompiler_ListBox')) {
+			$exp = str($this->value->obj->src);
+		}
+		else {
+			$exp = str($this->value);
+		}
+		foreach ($this->offsets as $dim) {
+			$exp .= '[' . str($dim) . ']';
+		}
+		return $exp;
+	}
+}
+// }}}
+class Decompiler_DimBox extends Decompiler_Box // {{{
+{
+}
+// }}}
+class Decompiler_List extends Decompiler_Code // {{{
+{
+	var $src;
+	var $dims = array();
+	var $everLocked = false;
+
+	function __toString()
+	{
+		if (count($this->dims) == 1 && !$this->everLocked) {
+			$dim = $this->dims[0];
+			unset($dim->value);
+			$dim->value = $this->src;
+			if (!isset($dim->assign)) {
+				return str($dim);
+			}
+			return str($this->dims[0]->assign) . ' = ' . str($dim);
+		}
+		/* flatten dims */
+		$assigns = array();
+		foreach ($this->dims as $dim) {
+			$assign = &$assigns;
+			foreach ($dim->offsets as $offset) {
+				$assign = &$assign[$offset];
+			}
+			$assign = str($dim->assign);
+		}
+		return $this->toList($assigns) . ' = ' . str($this->src);
+	}
+
+	function toList($assigns)
+	{
+		$keys = array_keys($assigns);
+		if (count($keys) < 2) {
+			$keys[] = 0;
+		}
+		$max = call_user_func_array('max', $keys);
+		$list = 'list(';
+		for ($i = 0; $i <= $max; $i ++) {
+			if ($i) {
+				$list .= ', ';
+			}
+			if (!isset($assigns[$i])) {
+				continue;
+			}
+			if (is_array($assigns[$i])) {
+				$list .= $this->toList($assigns[$i]);
+			}
+			else {
+				$list .= $assigns[$i];
+			}
+		}
+		return $list . ')';
+	}
+}
+// }}}
+class Decompiler_ListBox extends Decompiler_Box // {{{
+{
+}
+// }}}
+class Decompiler_Array extends Decompiler_Value // {{{
+{
+	var $needExport = false;
+
+	function Decompiler_Array($value = array(), $needexport = false)
+	{
+		$this->value = $value;
+		$this->needExport = $needexport;
+	}
+
+	function __toString($indent)
+	{
+		$exp = "array(";
+		$indent .= INDENT;
+		$assoclen = 0;
+		$multiline = 0;
+		$i = 0;
+		foreach ($this->value as $k => $v) {
+			if ($i !== $k) {
+				$len = strlen($k);
+				if ($assoclen < $len) {
+					$assoclen = $len;
+				}
+			}
+			if (is_array($v)) {
+				$multiline ++;
+			}
+			++ $i;
+		}
+		if ($assoclen && $this->needExport) {
+			$assoclen += 2;
+		}
+
+		$i = 0;
+		$subindent = $indent . INDENT;
+		foreach ($this->value as $k => $v) {
+			if ($multiline) {
+				if ($i) {
+					$exp .= ",";
+				}
+				$exp .= "\n";
+				$exp .= $indent;
+			}
+			else {
+				if ($i) {
+					$exp .= ", ";
+				}
+			}
+
+			if ($this->needExport) {
+				$k = var_export($k, true);
+			}
+			if ($multiline) {
+				$exp .= sprintf("%{$assoclen}s => ", $k);
+			}
+			else if ($assoclen) {
+				$exp .= $k . ' => ';
+			}
+
+			if (is_array($v)) {
+				$v = new Decompiler_Array($v, $this->needExport);
+			}
+			$exp .= str($v, $subindent);
+
+			$i ++;
+		}
+		if ($multiline) {
+			$exp .= "$indent);";
+		}
+		else {
+			$exp .= ")";
+		}
+		return $exp;
+	}
+}
+// }}}
+class Decompiler_ForeachBox extends Decompiler_Box // {{{
+{
+	var $iskey;
+
+	function __toString($indent)
+	{
+		return 'foreach (' . '';
+	}
+}
+// }}}
+
+class Decompiler
+{
+	var $rName = '!^[\\w_][\\w\\d_]*$!';
+	var $rQuotedName = "!^'[\\w_][\\w\\d_]*'\$!";
+
+	function Decompiler()
+	{
+		// {{{ opinfo
+		$this->unaryops = array(
+				XC_BW_NOT   => '~',
+				XC_BOOL_NOT => '!',
+				);
+		$this->binops = array(
+				XC_ADD                 => "+",
+				XC_ASSIGN_ADD          => "+=",
+				XC_SUB                 => "-",
+				XC_ASSIGN_SUB          => "-=",
+				XC_MUL                 => "*",
+				XC_ASSIGN_MUL          => "*=",
+				XC_DIV                 => "/",
+				XC_ASSIGN_DIV          => "/=",
+				XC_MOD                 => "%",
+				XC_ASSIGN_MOD          => "%=",
+				XC_SL                  => "<<",
+				XC_ASSIGN_SL           => "<<=",
+				XC_SR                  => ">>",
+				XC_ASSIGN_SR           => ">>=",
+				XC_CONCAT              => ".",
+				XC_ASSIGN_CONCAT       => ".=",
+				XC_IS_IDENTICAL        => "===",
+				XC_IS_NOT_IDENTICAL    => "!==",
+				XC_IS_EQUAL            => "==",
+				XC_IS_NOT_EQUAL        => "!=",
+				XC_IS_SMALLER          => "<",
+				XC_IS_SMALLER_OR_EQUAL => "<=",
+				XC_BW_OR               => "|",
+				XC_ASSIGN_BW_OR        => "|=",
+				XC_BW_AND              => "&",
+				XC_ASSIGN_BW_AND       => "&=",
+				XC_BW_XOR              => "^",
+				XC_ASSIGN_BW_XOR       => "^=",
+				XC_BOOL_XOR            => "xor",
+				);
+		// }}}
+		$this->includeTypes = array( // {{{
+				ZEND_EVAL         => 'eval',
+				ZEND_INCLUDE      => 'include',
+				ZEND_INCLUDE_ONCE => 'include_once',
+				ZEND_REQUIRE      => 'require',
+				ZEND_REQUIRE_ONCE => 'require_once',
+				);
+				// }}}
+	}
+	function outputPhp(&$opcodes, $opline, $last, $indent) // {{{
+	{
+		$origindent = $indent;
+		$curticks = 0;
+		for ($i = $opline; $i <= $last; $i ++) {
+			$op = $opcodes[$i];
+			if (isset($op['php'])) {
+				$toticks = isset($op['ticks']) ? $op['ticks'] : 0;
+				if ($curticks != $toticks) {
+					if (!$toticks) {
+						echo $origindent, "}\n";
+						$indent = $origindent;
+					}
+					else {
+						if ($curticks) {
+							echo $origindent, "}\n";
+						}
+						else if (!$curticks) {
+							$indent .= INDENT;
+						}
+						echo $origindent, "declare(ticks=$curticks) {\n";
+					}
+					$curticks = $toticks;
+				}
+				echo $indent, str($op['php']), ";\n";
+			}
+		}
+		if ($curticks) {
+			echo $origindent, "}\n";
+		}
+	}
+	// }}}
+	function getOpVal($op, &$EX, $tostr = true, $free = false) // {{{
+	{
+		switch ($op['op_type']) {
+		case XC_IS_CONST:
+			return str(value($op['u.constant']));
+
+		case XC_IS_VAR:
+		case XC_IS_TMP_VAR:
+			$T = &$EX['Ts'];
+			$ret = $T[$op['u.var']];
+			if ($tostr) {
+				$ret = str($ret, $EX);
+			}
+			if ($free) {
+				unset($T[$op['u.var']]);
+			}
+			return $ret;
+
+		case XC_IS_CV:
+			$var = $op['u.var'];
+			$var = $EX['op_array']['vars'][$var];
+			return '$' . $var['name'];
+
+		case XC_IS_UNUSED:
+			return null;
+		}
+	}
+	// }}}
+	function &dop_array($op_array, $indent = '') // {{{
+	{
+		$opcodes = &$op_array['opcodes'];
+		$last = count($opcodes) - 1;
+		if ($opcodes[$last]['opcode'] == XC_HANDLE_EXCEPTION) {
+			unset($opcodes[$last]);
+		}
+		$EX['indent'] = '';
+		//for ($i = 0, $cnt = count($opcodes); $i < $cnt; $i ++) {
+		//	$opcodes[$i]['opcode'] = xcache_get_fixed_opcode($opcodes[$i]['opcode'], $i);
+		//}
+		// {{{ build jmp array
+		for ($i = 0, $cnt = count($opcodes); $i < $cnt; $i ++) {
+			$op = &$opcodes[$i];
+			/*
+			if ($op['opcode'] == XC_JMPZ) {
+				$this->dumpop($op, $EX);
+				var_dump($op);
+			}
+			continue;
+			*/
+			$op['line'] = $i;
+			switch ($op['opcode']) {
+			case XC_JMP:
+				$target = $op['op1']['u.var'];
+				$op['jmpouts'] = array($target);
+				$opcodes[$target]['jmpins'][] = $i;
+				break;
+
+			case XC_JMPZNZ:
+				$jmpz = $op['op2']['u.opline_num'];
+				$jmpnz = $op['extended_value'];
+				$op['jmpouts'] = array($jmpz, $jmpnz);
+				$opcodes[$jmpz]['jmpins'][] = $i;
+				$opcodes[$jmpnz]['jmpins'][] = $i;
+				break;
+
+			case XC_JMPZ:
+			case XC_JMPNZ:
+			case XC_JMPZ_EX:
+			case XC_JMPNZ_EX:
+			// case XC_FE_RESET:
+			case XC_FE_FETCH:
+			// case XC_JMP_NO_CTOR:
+				$target = $op['op2']['u.opline_num'];
+				//if (!isset($target)) {
+				//	$this->dumpop($op, $EX);
+				//	var_dump($op); exit;
+				//}
+				$op['jmpouts'] = array($target);
+				$opcodes[$target]['jmpins'][] = $i;
+				break;
+
+			/*
+			case XC_RETURN:
+				$op['jmpouts'] = array();
+				break;
+			*/
+			}
+		}
+		unset($op);
+		// }}}
+		// build semi-basic blocks
+		$nextbbs = array();
+		$starti = 0;
+		for ($i = 1, $cnt = count($opcodes); $i < $cnt; $i ++) {
+			if (isset($opcodes[$i]['jmpins'])
+			 || isset($opcodes[$i - 1]['jmpouts'])) {
+				$nextbbs[$starti] = $i;
+				$starti = $i;
+			}
+		}
+		$nextbbs[$starti] = $cnt;
+
+		$EX = array();
+		$EX['Ts'] = array();
+		$EX['indent'] = $indent;
+		$EX['nextbbs'] = $nextbbs;
+		$EX['op_array'] = &$op_array;
+		$EX['opcodes'] = &$opcodes;
+		// func call
+		$EX['object'] = null;
+		$EX['fbc'] = null;
+		$EX['argstack'] = array();
+		$EX['arg_types_stack'] = array();
+		$EX['last'] = count($opcodes) - 1;
+		$EX['silence'] = 0;
+
+		for ($next = 0, $last = $EX['last'];
+				$loop = $this->outputCode($EX, $next, $last, $indent, true);
+				list($next, $last) = $loop) {
+			// empty
+		}
+		return $EX;
+	}
+	// }}}
+	function outputCode(&$EX, $opline, $last, $indent, $loop = false) // {{{
+	{
+		$op = &$EX['opcodes'][$opline];
+		$next = $EX['nextbbs'][$opline];
+
+		$end = $next - 1;
+		if ($end > $last) {
+			$end = $last;
+		}
+
+		if (isset($op['jmpins'])) {
+			echo "\nline", $op['line'], ":\n";
+		}
+		else {
+			// echo ";;;\n";
+		}
+		$this->dasmBasicBlock($EX, $opline, $end);
+		$this->outputPhp($EX['opcodes'], $opline, $end, $indent);
+		// jmpout op
+		$op = &$EX['opcodes'][$end];
+		$op1 = $op['op1'];
+		$op2 = $op['op2'];
+		$ext = $op['extended_value'];
+		$line = $op['line'];
+
+		if (isset($EX['opcodes'][$next])) {
+			if (isset($last) && $next > $last) {
+				$next = null;
+			}
+		}
+		else {
+			$next = null;
+		}
+		if ($op['opcode'] == XC_FE_FETCH) {
+			$opline = $next;
+			$next = $op['op2']['u.opline_num'];
+			$end = $next - 1;
+
+			ob_start();
+			$this->outputCode($EX, $opline, $end /* - 1 skip last jmp */, $indent . INDENT);
+			$body = ob_get_clean();
+
+			$as = str($op['fe_as']);
+			if (isset($op['fe_key'])) {
+				$as = str($op['fe_key']) . ' => ' . $as;
+			}
+			echo "{$indent}foreach (" . str($op['fe_src']) . " as $as) {\n";
+			echo $body;
+			echo "{$indent}}";
+			// $this->outputCode($EX, $next, $last, $indent);
+			// return;
+		}
+		/*
+		if ($op['opcode'] == XC_JMPZ) {
+			$target = $op2['u.opline_num'];
+			if ($line + 1) {
+				$nextblock = $EX['nextbbs'][$next];
+				$jmpop = end($nextblock);
+				if ($jmpop['opcode'] == XC_JMP) {
+					$ifendline = $op2['u.opline_num'];
+					if ($ifendline >= $line) {
+						$cond = $op['cond'];
+						echo "{$indent}if ($cond) {\n";
+						$this->outputCode($EX, $next, $last, INDENT . $indent);
+						echo "$indent}\n";
+						$this->outputCode($EX, $target, $last, $indent);
+						return;
+					}
+				}
+			}
+		}
+		*/
+		if (!isset($next)) {
+			return;
+		}
+		if (!empty($op['jmpouts']) && isset($op['isjmp'])) {
+			if (isset($op['cond'])) {
+				echo "{$indent}check ($op[cond]) {\n";
+				echo INDENT;
+			}
+			echo $indent;
+			echo xcache_get_opcode($op['opcode']), ' line', $op['jmpouts'][0];
+			if (isset($op['jmpouts'][1])) {
+				echo ', line', $op['jmpouts'][1];
+			}
+			echo ";";
+			// echo ' // <- line', $op['line'];
+			echo "\n";
+			if (isset($op['cond'])) echo "$indent}\n";
+		}
+
+		// proces JMPZ_EX/JMPNZ_EX for AND,OR
+		$op = &$EX['opcodes'][$next];
+		/*
+		if (isset($op['jmpins'])) {
+			foreach (array_reverse($op['jmpins']) as $fromline) {
+				$fromop = $EX['opcodes'][$fromline];
+				switch ($fromop['opcode']) {
+				case XC_JMPZ_EX: $opstr = 'and'; break;
+				case XC_JMPNZ_EX: $opstr = 'or'; break;
+				case XC_JMPZNZ: var_dump($fromop); exit;
+				default: continue 2;
+				}
+
+				$var = $fromop['result']['u.var'];
+				var_dump($EX['Ts'][$var]);
+				$EX['Ts'][$var] = '(' . $fromop['and_or'] . " $opstr " . $EX['Ts'][$var] . ')';
+			}
+			#$this->outputCode($EX, $next, $last, $indent);
+			#return;
+		}
+		*/
+		if (isset($op['cond_false'])) {
+			// $this->dumpop($op, $EX);
+			// any true comes here, so it's a "or"
+			$cond = implode(' and ', $op['cond_false']);
+			// var_dump($op['cond'] = $cond);
+			/*
+			$rvalue = implode(' or ', $op['cond_true']) . ' or ' . $rvalue;
+			unset($op['cond_true']);
+			*/
+		}
+
+		if ($loop) {
+			return array($next, $last);
+		}
+		$this->outputCode($EX, $next, $last, $indent);
+	}
+	// }}}
+	function unquoteName($str) // {{{
+	{
+		if (preg_match($this->rQuotedName, $str)) {
+			$str = substr($str, 1, -1);
+		}
+		return $str;
+	}
+	// }}}
+	function dasmBasicBlock(&$EX, $opline, $last) // {{{
+	{
+		$T = &$EX['Ts'];
+		$opcodes = &$EX['opcodes'];
+		$lastphpop = null;
+
+		for ($i = $opline, $ic = $last + 1; $i < $ic; $i ++) {
+			// {{{ prepair
+			$op = &$opcodes[$i];
+			$opc = $op['opcode'];
+			if ($opc == XC_NOP) {
+				continue;
+			}
+
+			$op1 = $op['op1'];
+			$op2 = $op['op2'];
+			$res = $op['result'];
+			$ext = $op['extended_value'];
+
+			$opname = xcache_get_opcode($opc);
+
+			if ($opname == 'UNDEF' || !isset($opname)) {
+				echo 'UNDEF OP:';
+				$this->dumpop($op, $EX);
+				continue;
+			}
+			// $this->dumpop($op, $EX); //var_dump($op);
+
+			$resvar = null;
+			if (($res['u.EA.type'] & EXT_TYPE_UNUSED) || $res['op_type'] == XC_IS_UNUSED) {
+				$istmpres = false;
+			}
+			else {
+				$istmpres = true;
+			}
+			// }}}
+			// echo $opname, "\n";
+
+			$call = array(&$this, $opname);
+			if (is_callable($call)) {
+				$this->{$opname}($op, $EX);
+			}
+			else if (isset($this->binops[$opc])) { // {{{
+				$op1val = $this->getOpVal($op1, $EX, false);
+				$op2val = $this->getOpVal($op2, $EX, false);
+				$rvalue = new Decompiler_Binop($this, $op1val, $opc, $op2val);
+				$resvar = $rvalue;
+				// }}}
+			}
+			else if (isset($this->unaryops[$opc])) { // {{{
+				$op1val = $this->getOpVal($op1, $EX);
+				$myop = $this->unaryops[$opc];
+				$rvalue = "$myop$op1val";
+				$resvar = $rvalue;
+				// }}}
+			}
+			else {
+				switch ($opc) {
+				case XC_NEW: // {{{
+					array_push($EX['arg_types_stack'], array($EX['object'], $EX['fbc']));
+					$EX['object'] = (int) $res['u.var'];
+					$EX['fbc'] = 'new ' . $this->unquoteName($this->getOpVal($op1, $EX));
+					if (PHP_VERSION < 5) {
+						$resvar = '$new object$';
+					}
+					break;
+					// }}}
+				case XC_FETCH_CLASS: // {{{
+					if ($op2['op_type'] == XC_IS_UNUSED) {
+						switch ($ext) {
+						case ZEND_FETCH_CLASS_SELF:
+							$class = 'self';
+							break;
+						case ZEND_FETCH_CLASS_PARENT:
+							$class = 'parent';
+						}
+					}
+					else {
+						$class = $op2['u.constant'];
+						if (is_object($class)) {
+							$class = get_class($class);
+						}
+					}
+					$resvar = $class;
+					break;
+					// }}}
+				case XC_FETCH_CONSTANT: // {{{
+					if ($op1['op_type'] == XC_IS_CONST) {
+						$resvar = $op1['u.constant'];
+					}
+					else if ($op1['op_type'] == XC_IS_UNUSED) {
+						$resvar = $op2['u.constant'];
+					}
+					else {
+						$class = $T[$op1['u.var']];
+						assert($class[0] == 'class');
+						$resvar = $class[1] . '::' . $op2['u.constant'];
+					}
+					break;
+					// }}}
+					// {{{ case XC_FETCH_*
+				case XC_FETCH_R:
+				case XC_FETCH_W:
+				case XC_FETCH_RW:
+				case XC_FETCH_FUNC_ARG:
+				case XC_FETCH_UNSET:
+				case XC_FETCH_IS:
+				case XC_UNSET_VAR:
+					$rvalue = $this->getOpVal($op1, $EX);
+					$fetchtype = $op2[PHP_VERSION < 5 ? 'u.fetch_type' : 'u.EA.type'];
+					switch ($fetchtype) {
+					case ZEND_FETCH_STATIC_MEMBER:
+						$class = $this->getOpVal($op2, $EX);
+						$rvalue = $class . '::$' . $this->unquoteName($rvalue);
+						break;
+					default:
+						$name = $this->unquoteName($rvalue);
+						$globalname = xcache_is_autoglobal($name) ? "\$$name" : "\$GLOBALS[$rvalue]";
+						$rvalue = new Decompiler_Fetch($rvalue, $fetchtype, $globalname);
+						break;
+					}
+					if ($opc == XC_UNSET_VAR) {
+						$op['php'] = "unset(" . str($rvalue) . ")";
+						$lastphpop = &$op;
+					}
+					else if ($res['op_type'] != XC_IS_UNUSED) {
+						$resvar = $rvalue;
+					}
+					break;
+					// }}}
+					// {{{ case XC_FETCH_DIM_*
+				case XC_FETCH_DIM_TMP_VAR:
+				case XC_FETCH_DIM_R:
+				case XC_FETCH_DIM_W:
+				case XC_FETCH_DIM_RW:
+				case XC_FETCH_DIM_FUNC_ARG:
+				case XC_FETCH_DIM_UNSET:
+				case XC_FETCH_DIM_IS:
+				case XC_ASSIGN_DIM:
+				case XC_UNSET_DIM:
+				case XC_UNSET_DIM_OBJ:
+					$src = $this->getOpVal($op1, $EX, false);
+					if (is_a($src, "Decompiler_ForeachBox")) {
+						$src->iskey = $this->getOpVal($op2, $EX);
+						$resvar = $src;
+						break;
+					}
+					else if (is_a($src, "Decompiler_DimBox")) {
+						$dimbox = $src;
+					}
+					else {
+						if (!is_a($src, "Decompiler_ListBox")) {
+							$list = new Decompiler_List($this->getOpVal($op1, $EX, false));
+
+							$src = new Decompiler_ListBox($list);
+							if (!isset($op1['u.var'])) {
+								$this->dumpop($op, $EX);
+								var_dump($op);
+								die('missing u.var');
+							}
+							$T[$op1['u.var']] = $src;
+							unset($list);
+						}
+						$dim = new Decompiler_Dim($src);
+						$src->obj->dims[] = &$dim;
+
+						$dimbox = new Decompiler_DimBox($dim);
+					}
+					$dim = &$dimbox->obj;
+					$dim->offsets[] = $this->getOpVal($op2, $EX);
+					if ($ext == ZEND_FETCH_ADD_LOCK) {
+						$src->obj->everLocked = true;
+					}
+					else if ($ext == ZEND_FETCH_STANDARD) {
+						$dim->isLast = true;
+					}
+					unset($dim);
+					$rvalue = $dimbox;
+
+					if ($opc == XC_ASSIGN_DIM) {
+						$lvalue = $rvalue;
+						++ $i;
+						$rvalue = $this->getOpVal($opcodes[$i]['op1'], $EX);
+						$resvar = str($lvalue) . ' = ' . $rvalue;
+					}
+					else if ($opc == XC_UNSET_DIM) {
+						$op['php'] = "unset(" . str($rvalue) . ")";
+						$lastphpop = &$op;
+					}
+					else if ($res['op_type'] != XC_IS_UNUSED) {
+						$resvar = $rvalue;
+					}
+					break;
+					// }}}
+				case XC_ASSIGN: // {{{
+					$lvalue = $this->getOpVal($op1, $EX);
+					$rvalue = $this->getOpVal($op2, $EX, false);
+					if (is_a($rvalue, 'Decompiler_ForeachBox')) {
+						$type = $rvalue->iskey ? 'fe_key' : 'fe_as';
+						$rvalue->obj[$type] = $lvalue;
+						unset($T[$op2['u.var']]);
+						break;
+					}
+					if (is_a($rvalue, "Decompiler_DimBox")) {
+						$dim = &$rvalue->obj;
+						$dim->assign = $lvalue;
+						if ($dim->isLast) {
+							$resvar = str($dim->value);
+						}
+						unset($dim);
+						break;
+					}
+					$resvar = "$lvalue = " . str($rvalue, $EX);
+					break;
+					// }}}
+				case XC_ASSIGN_REF: // {{{
+					$lvalue = $this->getOpVal($op1, $EX);
+					$rvalue = $this->getOpVal($op2, $EX, false);
+					if (is_a($rvalue, 'Decompiler_Fetch')) {
+						$src = str($rvalue->src);
+						if (substr($src, 1, -1) == substr($lvalue, 1)) {
+							switch ($rvalue->fetchType) {
+							case ZEND_FETCH_GLOBAL:
+								$resvar = 'global ' . $lvalue;
+								break 2;
+							case ZEND_FETCH_STATIC:
+								$statics = &$EX['op_array']['static_variables'];
+								$resvar = 'static ' . $lvalue;
+								$name = substr($src, 1, -1);
+								if (isset($statics[$name])) {
+									$var = $statics[$name];
+									$resvar .= ' = ';
+									$resvar .= str(value($var), $EX);
+								}
+								unset($statics);
+								break 2;
+							}
+						}
+					}
+					$rvalue = str($rvalue);
+					$resvar = "$lvalue = &$rvalue";
+					break;
+					// }}}
+				// {{{ case XC_FETCH_OBJ_*
+				case XC_FETCH_OBJ_R:
+				case XC_FETCH_OBJ_W:
+				case XC_FETCH_OBJ_RW:
+				case XC_FETCH_OBJ_FUNC_ARG:
+				case XC_FETCH_OBJ_UNSET:
+				case XC_FETCH_OBJ_IS:
+				case XC_ASSIGN_OBJ:
+					$obj = $this->getOpVal($op1, $EX);
+					if (!isset($obj)) {
+						$obj = '$this';
+					}
+					$prop = $this->getOpVal($op2, $EX);
+					if (preg_match($this->rQuotedName, $prop)) {
+						$prop = substr($prop, 1, -1);;
+						$rvalue = "{$obj}->$prop";
+					}
+					else {
+						$rvalue = "{$obj}->{" . "$prop}";
+					}
+					if ($res['op_type'] != XC_IS_UNUSED) {
+						$resvar = $rvalue;
+					}
+					if ($opc == XC_ASSIGN_OBJ) {
+						++ $i;
+						$lvalue = $rvalue;
+						$rvalue = $this->getOpVal($opcodes[$i]['op1'], $EX);
+						$resvar = "$lvalue = $rvalue";
+					}
+					break;
+					// }}}
+				case XC_ISSET_ISEMPTY_DIM_OBJ:
+				case XC_ISSET_ISEMPTY_PROP_OBJ:
+				case XC_ISSET_ISEMPTY:
+				case XC_ISSET_ISEMPTY_VAR: // {{{
+					if ($opc == XC_ISSET_ISEMPTY_VAR) {
+						$rvalue = $this->getOpVal($op1, $EX);;
+						if (preg_match($this->rQuotedName, $rvalue)) {
+							$rvalue = '$' . substr($rvalue, 1, -1);
+						}
+						else {
+							$rvalue = "${" . $rvalue . "}";
+						}
+						if ($op2['u.EA.type'] == ZEND_FETCH_STATIC_MEMBER) {
+							$class = $this->getOpVal($op2, $EX);
+							$rvalue = $class . '::' . $rvalue;
+						}
+					}
+					else if ($opc == XC_ISSET_ISEMPTY) {
+						$rvalue = $this->getOpVal($op1, $EX);
+					}
+					else {
+						$container = $this->getOpVal($op1, $EX);
+						$dim = $this->getOpVal($op2, $EX);
+						$rvalue = $container . "[$dim]";
+					}
+
+					switch (PHP_VERSION < 5 ? $op['op2']['u.var'] /* u.constant */ : $ext) {
+					case ZEND_ISSET:
+						$rvalue = "isset($rvalue)";
+						break;
+					case ZEND_ISEMPTY:
+						$rvalue = "empty($rvalue)";
+						break;
+					default:
+						$this->dumpop($op, $EX);
+						die_error('1');
+					}
+					$resvar = $rvalue;
+					break;
+					// }}}
+				case XC_SEND_VAR_NO_REF:
+				case XC_SEND_VAL:
+				case XC_SEND_REF:
+				case XC_SEND_VAR: // {{{
+					$ref = ($opc == XC_SEND_REF ? '&' : '');
+					$EX['argstack'][] = $ref . $this->getOpVal($op1, $EX);
+					break;
+					// }}}
+				case XC_INIT_METHOD_CALL:
+				case XC_INIT_FCALL_BY_FUNC:
+				case XC_INIT_FCALL_BY_NAME: // {{{
+					if (($ext & ZEND_CTOR_CALL)) {
+						break;
+					}
+					array_push($EX['arg_types_stack'], array($EX['object'], $EX['fbc']));
+					if ($opc == XC_INIT_METHOD_CALL || $op1['op_type'] != XC_IS_UNUSED) {
+						$obj = $this->getOpVal($op1, $EX);
+						if (!isset($obj)) {
+							$obj = '$this';
+						}
+						$EX['object'] = $obj;
+						if ($res['op_type'] != XC_IS_UNUSED) {
+							$resvar = '$obj call$';
+						}
+					}
+					else {
+						$EX['object'] = null;
+					}
+
+					if ($opc == XC_INIT_FCALL_BY_FUNC) {
+						$which = $op1['u.var'];
+						$EX['fbc'] = $EX['op_array']['funcs'][$which]['name'];
+					}
+					else {
+						$EX['fbc'] = $this->getOpVal($op2, $EX, false);
+					}
+					break;
+					// }}}
+				case XC_DO_FCALL_BY_FUNC:
+					$which = $op1['u.var'];
+					$fname = $EX['op_array']['funcs'][$which]['name'];
+					$args = $this->popargs($EX, $ext);
+					$resvar = $fname . "($args)";
+					break;
+				case XC_DO_FCALL:
+					$fname = $this->unquoteName($this->getOpVal($op1, $EX, false));
+					$args = $this->popargs($EX, $ext);
+					$resvar = $fname . "($args)";
+					break;
+				case XC_DO_FCALL_BY_NAME: // {{{
+					$object = null;
+
+					$fname = $this->unquoteName($EX['fbc']);
+					if (!is_int($EX['object'])) {
+						$object = $EX['object'];
+					}
+
+					$args = $this->popargs($EX, $ext);
+
+					$resvar =
+						(isset($object) ? $object . '->' : '' )
+						. $fname . "($args)";
+					unset($args);
+
+					if (is_int($EX['object'])) {
+						$T[$EX['object']] = $resvar;
+						$resvar = null;
+					}
+					list($EX['object'], $EX['fbc']) = array_pop($EX['arg_types_stack']);
+					break;
+					// }}}
+				case XC_VERIFY_ABSTRACT_CLASS: // {{{
+					//unset($T[$op1['u.var']]);
+					break;
+					// }}}
+				case XC_DECLARE_CLASS: 
+				case XC_DECLARE_INHERITED_CLASS: // {{{
+					$key = $op1['u.constant'];
+					$class = &$this->dc['class_table'][$key];
+					if (!isset($class)) {
+						echo 'class not found: ' . $key;
+						exit;
+					}
+					$class['name'] = $this->unquoteName($this->getOpVal($op2, $EX));
+					if ($opc == XC_DECLARE_INHERITED_CLASS) {
+						$ext /= XC_SIZEOF_TEMP_VARIABLE;
+						$class['parent'] = $T[$ext];
+						unset($T[$ext]);
+					}
+					else {
+						$class['parent'] = null;
+					}
+
+					while ($i + 2 < $ic
+					 && $opcodes[$i + 2]['opcode'] == XC_ADD_INTERFACE
+					 && $opcodes[$i + 2]['op1']['u.var'] == $res['u.var']
+					 && $opcodes[$i + 1]['opcode'] == XC_FETCH_CLASS) {
+						$fetchop = &$opcodes[$i + 1];
+						$impl = $this->unquoteName($this->getOpVal($fetchop['op2'], $EX));
+						$addop = &$opcodes[$i + 2];
+						$class['interfaces'][$addop['extended_value']] = $impl;
+						unset($fetchop, $addop);
+						$i += 2;
+					}
+					$this->dclass($class);
+					unset($class);
+					break;
+					// }}}
+				case XC_INIT_STRING: // {{{
+					$resvar = "''";
+					break;
+					// }}}
+				case XC_ADD_CHAR:
+				case XC_ADD_STRING:
+				case XC_ADD_VAR: // {{{
+					$op1val = $this->getOpVal($op1, $EX);
+					$op2val = $this->getOpVal($op2, $EX);
+					switch ($opc) {
+					case XC_ADD_CHAR:
+						$op2val = str(chr($op2val), $EX);
+						break;
+					case XC_ADD_STRING:
+						$op2val = str($op2val, $EX);
+						break;
+					case XC_ADD_VAR:
+						break;
+					}
+					if ($op1val == "''") {
+						$rvalue = $op2val;
+					}
+					else if ($op2val == "''") {
+						$rvalue = $op1val;
+					}
+					else {
+						$rvalue = $op1val . ' . ' . $op2val;
+					}
+					$resvar = $rvalue;
+					// }}}
+					break;
+				case XC_PRINT: // {{{
+					$op1val = $this->getOpVal($op1, $EX);
+					$resvar = "print($op1val)";
+					break;
+					// }}}
+				case XC_ECHO: // {{{
+					$op1val = $this->getOpVal($op1, $EX);
+					$resvar = "echo $op1val";
+					break;
+					// }}}
+				case XC_EXIT: // {{{
+					$op1val = $this->getOpVal($op1, $EX);
+					$resvar = "exit($op1val)";
+					break;
+					// }}}
+				case XC_INIT_ARRAY:
+				case XC_ADD_ARRAY_ELEMENT: // {{{
+					$rvalue = $this->getOpVal($op1, $EX, false, true);
+
+					if ($opc == XC_ADD_ARRAY_ELEMENT) {
+						$offset = $this->getOpVal($op2, $EX);
+						if (isset($offset)) {
+							$T[$res['u.var']]->value[$offset] = $rvalue;
+						}
+						else {
+							$T[$res['u.var']]->value[] = $rvalue;
+						}
+					}
+					else {
+						if ($opc == XC_INIT_ARRAY) {
+							$resvar = new Decompiler_Array();
+							if (!isset($rvalue)) {
+								continue;
+							}
+						}
+
+						$offset = $this->getOpVal($op2, $EX);
+						if (isset($offset)) {
+							$resvar->value[$offset] = $rvalue;
+						}
+						else {
+							$resvar->value[] = $rvalue;
+						}
+					}
+					break;
+					// }}}
+				case XC_QM_ASSIGN: // {{{
+					$resvar = $this->getOpVal($op1, $EX);
+					break;
+					// }}}
+				case XC_BOOL: // {{{
+					$resvar = /*'(bool) ' .*/ $this->getOpVal($op1, $EX);
+					break;
+					// }}}
+				case XC_RETURN: // {{{
+					$resvar = "return " . $this->getOpVal($op1, $EX);
+					break;
+					// }}}
+				case XC_INCLUDE_OR_EVAL: // {{{
+					$type = $op2['u.var']; // hack
+					$keyword = $this->includeTypes[$type];
+					$resvar = "$keyword(" . $this->getOpVal($op1, $EX) . ")";
+					break;
+					// }}}
+				case XC_FE_RESET: // {{{
+					$resvar = $this->getOpVal($op1, $EX);
+					break;
+					// }}}
+				case XC_FE_FETCH: // {{{
+					$op['fe_src'] = $this->getOpVal($op1, $EX);
+					$fe = new Decompiler_ForeachBox($op);
+					$fe->iskey = false;
+					$T[$res['u.var']] = $fe;
+
+					++ $i;
+					if (($ext & ZEND_FE_FETCH_WITH_KEY)) {
+						$fe = new Decompiler_ForeachBox($op);
+						$fe->iskey = true;
+
+						$res = $opcodes[$i]['result'];
+						$T[$res['u.var']] = $fe;
+					}
+					break;
+					// }}}
+				case XC_SWITCH_FREE: // {{{
+					// unset($T[$op1['u.var']]);
+					break;
+					// }}}
+				case XC_FREE: // {{{
+					$free = $T[$op1['u.var']];
+					if (!is_a($free, 'Decompiler_Array') && !is_a($free, 'Decompiler_Box')) {
+						$op['php'] = is_object($free) ? $free : $this->unquote($free, '(', ')');
+						$lastphpop = &$op;
+					}
+					unset($T[$op1['u.var']], $free);
+					break;
+					// }}}
+				case XC_JMP_NO_CTOR:
+					break;
+				case XC_JMPNZ: // while
+				case XC_JMPZNZ: // for
+				case XC_JMPZ_EX: // and
+				case XC_JMPNZ_EX: // or
+				case XC_JMPZ: // {{{
+					if ($opc == XC_JMP_NO_CTOR && $EX['object']) {
+						$rvalue = $EX['object'];
+					}
+					else {
+						$rvalue = $this->getOpVal($op1, $EX);
+					}
+
+					if (isset($op['cond_true'])) {
+						// any true comes here, so it's a "or"
+						$rvalue = implode(' or ', $op['cond_true']) . ' or ' . $rvalue;
+						unset($op['cond_true']);
+					}
+					if (isset($op['cond_false'])) {
+						var_dump($op);// exit;
+					}
+					if ($opc == XC_JMPZ_EX || $opc == XC_JMPNZ_EX || $opc == XC_JMPZ) {
+						$targetop = &$EX['opcodes'][$op2['u.opline_num']];
+						if ($opc == XC_JMPNZ_EX) {
+							$targetop['cond_true'][] = str($rvalue);
+						}
+						else {
+							$targetop['cond_false'][] = str($rvalue);
+						}
+						unset($targetop);
+					}
+					else {
+						$op['cond'] = $rvalue; 
+						$op['isjmp'] = true;
+					}
+					break;
+					// }}}
+				case XC_JMP: // {{{
+					$op['cond'] = null;
+					$op['isjmp'] = true;
+					break;
+					// }}}
+				case XC_CASE:
+				case XC_BRK:
+					break;
+				case XC_RECV_INIT:
+				case XC_RECV:
+					$offset = $this->getOpVal($op1, $EX);
+					$lvalue = $this->getOpVal($op['result'], $EX);
+					if ($opc == XC_RECV_INIT) {
+						$default = value($op['op2']['u.constant']);
+					}
+					else {
+						$default = null;
+					}
+					$EX['recvs'][$offset] = array($lvalue, $default);
+					break;
+				case XC_POST_DEC:
+				case XC_POST_INC:
+				case XC_POST_DEC_OBJ:
+				case XC_POST_INC_OBJ:
+				case XC_PRE_DEC:
+				case XC_PRE_INC:
+				case XC_PRE_DEC_OBJ:
+				case XC_PRE_INC_OBJ: // {{{
+					$flags = array_flip(explode('_', $opname));
+					if (isset($flags['OBJ'])) {
+						$resvar = $this->getOpVal($op1, $EX);
+						$prop = $this->unquoteName($this->getOpVal($op2, $EX));
+						if ($prop{0} == '$') {
+							$resvar = $resvar . "{" . $prop . "}";
+						}
+						else {
+							$resvar = $resvar . "->" . $prop;
+						}
+					}
+					else {
+						$resvar = $this->getOpVal($op1, $EX);
+					}
+					$opstr = isset($flags['DEC']) ? '--' : '++';
+					if (isset($flags['POST'])) {
+						$resvar .= ' ' . $opstr;
+					}
+					else {
+						$resvar = "$opstr $resvar";
+					}
+					break;
+					// }}}
+
+				case XC_BEGIN_SILENCE: // {{{
+					$EX['silence'] ++;
+					break;
+					// }}}
+				case XC_END_SILENCE: // {{{
+					$EX['silence'] --;
+					$lastresvar = '@' . str($lastresvar);
+					break;
+					// }}}
+				case XC_CONT: // {{{
+					break;
+					// }}}
+				case XC_CAST: // {{{
+					$type = $ext;
+					static $type2cast = array(
+							IS_LONG   => '(int)',
+							IS_DOUBLE => '(double)',
+							IS_STRING => '(string)',
+							IS_ARRAY  => '(array)',
+							IS_OBJECT => '(object)',
+							IS_BOOL   => '(bool)',
+							IS_NULL   => '(unset)',
+							);
+					assert(isset($type2cast[$type]));
+					$cast = $type2cast[$type];
+					$resvar = $cast . ' ' . $this->getOpVal($op1, $EX);
+					break;
+					// }}}
+				case XC_EXT_STMT:
+				case XC_EXT_FCALL_BEGIN:
+				case XC_EXT_FCALL_END:
+				case XC_EXT_NOP:
+					break;
+				case XC_DECLARE_FUNCTION_OR_CLASS:
+					/* always removed by compiler */
+					break;
+				case XC_TICKS:
+					$lastphpop['ticks'] = $this->getOpVal($op1, $EX);
+					// $EX['tickschanged'] = true;
+					break;
+				default: // {{{
+					echo "\x1B[31m * TODO ", $opname, "\x1B[0m\n";
+					// }}}
+				}
+			}
+			if (isset($resvar)) {
+				if ($istmpres) {
+					$T[$res['u.var']] = $resvar;
+					$lastresvar = &$T[$res['u.var']];
+				}
+				else {
+					$op['php'] = $resvar;
+					$lastphpop = &$op;
+					$lastresvar = &$op['php'];
+				}
+			}
+		}
+		return $T;
+	}
+	// }}}
+	function unquote($str, $st, $ed) // {{{
+	{
+		$l1 = strlen($st);
+		$l2 = strlen($ed);
+		if (substr($str, 0, $l1) === $st && substr($str, -$l2) === $ed) {
+			$str = substr($str, $l1, -$l2);
+		}
+		return $str;
+	}
+	// }}}
+	function popargs(&$EX, $n) // {{{
+	{
+		$args = array();
+		for ($i = 0; $i < $n; $i ++) {
+			$a = array_pop($EX['argstack']);
+			if (is_array($a)) {
+				array_unshift($args, str($a, $EX));
+			}
+			else {
+				array_unshift($args, $a);
+			}
+		}
+		return implode(', ', $args);
+	}
+	// }}}
+	function dumpop($op, &$EX) // {{{
+	{
+		$op1 = $op['op1'];
+		$op2 = $op['op2'];
+		$d = array('opname' => xcache_get_opcode($op['opcode']), 'opcode' => $op['opcode']);
+
+		foreach (array('op1' => 'op1', 'op2' => 'op2', 'result' => 'res') as $k => $kk) {
+			switch ($op[$k]['op_type']) {
+			case XC_IS_UNUSED:
+				$d[$kk] = '*UNUSED* ' . $op[$k]['u.opline_num'];
+				break;
+
+			case XC_IS_VAR:
+				$d[$kk] = '$' . $op[$k]['u.var'];
+				if ($kk != 'res') {
+					$d[$kk] .= ':' . $this->getOpVal($op[$k], $EX);
+				}
+				break;
+
+			case XC_IS_TMP_VAR:
+				$d[$kk] = '#' . $op[$k]['u.var'];
+				if ($kk != 'res') {
+					$d[$kk] .= ':' . $this->getOpVal($op[$k], $EX);
+				}
+				break;
+
+			case XC_IS_CV:
+				$d[$kk] = $this->getOpVal($op[$k], $EX);
+				break;
+
+			default:
+				if ($kk == 'res') {
+					assert(0);
+				}
+				else {
+					$d[$kk] = $this->getOpVal($op[$k], $EX);
+				}
+			}
+		}
+		$d['ext'] = $op['extended_value'];
+
+		var_dump($d);
+	}
+	// }}}
+	function dargs(&$EX, $indent) // {{{
+	{
+		$EX['indent'] = $indent;
+		$op_array = &$EX['op_array'];
+
+		if (isset($op_array['num_args'])) {
+			$c = $op_array['num_args'];
+		}
+		else if ($op_array['arg_types']) {
+			$c = count($op_array['arg_types']);
+		}
+		else {
+			// php4
+			$c = count($EX['recvs']);
+		}
+
+		$refrest = false;
+		for ($i = 0; $i < $c; $i ++) {
+			if ($i) {
+				echo ', ';
+			}
+			if (isset($op_array['arg_info'])) {
+				$ai = $op_array['arg_info'][$i];
+				if (!empty($ai['class_name'])) {
+					echo $ai['class_name'], ' ';
+					if ($ai['allow_null']) {
+						echo 'or NULL ';
+					}
+				}
+				else if (!empty($ai['array_type_hint'])) {
+					echo 'array ';
+					if ($ai['allow_null']) {
+						echo 'or NULL ';
+					}
+				}
+				if ($ai['pass_by_reference']) {
+					echo '&';
+				}
+				printf("\$%s", $ai['name']);
+			}
+			else {
+				if ($refrest) {
+					echo '&';
+				}
+				else if (isset($op_array['arg_types'][$i])) {
+					switch ($op_array['arg_types'][$i]) {
+					case BYREF_FORCE_REST:
+						$refrest = true;
+						/* fall */
+					case BYREF_FORCE:
+						echo '&';
+						break;
+
+					case BYREF_NONE:
+					case BYREF_ALLOW:
+						break;
+					default:
+						assert(0);
+					}
+				}
+				$arg = $EX['recvs'][$i + 1];
+				echo str($arg[0]);
+				if (isset($arg[1])) {
+					echo ' = ', str($arg[1]);
+				}
+			}
+		}
+	}
+	// }}}
+	function dfunction($func, $indent = '', $nobody = false) // {{{
+	{
+		if ($nobody) {
+			$body = ";\n";
+			$EX = array();
+			$EX['op_array'] = &$func['op_array'];
+			$EX['recvs'] = array();
+		}
+		else {
+			ob_start();
+			$newindent = INDENT . $indent;
+			$EX = &$this->dop_array($func['op_array'], $newindent);
+			$body = ob_get_clean();
+			if (!isset($EX['recvs'])) {
+				$EX['recvs'] = array();
+			}
+		}
+
+		echo 'function ', $func['op_array']['function_name'], '(';
+		$this->dargs($EX, $indent);
+		echo ")\n";
+		echo $indent, "{\n";
+		echo $body;
+		echo "$indent}\n";
+	}
+	// }}}
+	function dclass($class, $indent = '') // {{{
+	{
+		// {{{ class decl
+		if (!empty($class['doc_comment'])) {
+			echo $indent;
+			echo $class['doc_comment'];
+			echo "\n";
+		}
+		$isinterface = false;
+		if (!empty($class['ce_flags'])) {
+			if ($class['ce_flags'] & ZEND_ACC_INTERFACE) {
+				echo 'interface ';
+				$isinterface = true;
+			}
+			else {
+				if ($class['ce_flags'] & ZEND_ACC_IMPLICIT_ABSTRACT) {
+					echo "abstract ";
+				}
+				if ($class['ce_flags'] & ZEND_ACC_FINAL) {
+					echo "final ";
+				}
+			}
+		}
+		echo 'class ', $class['name'];
+		if ($class['parent']) {
+			echo ' extends ', $class['parent'];
+		}
+		/* TODO */
+		if (!empty($class['interfaces'])) {
+			echo ' implements ';
+			echo implode(', ', $class['interfaces']);
+		}
+		echo "\n";
+		echo $indent, "{";
+		// }}}
+		$newindent = INDENT . $indent;
+		// {{{ const, static
+		foreach (array('constants_table' => 'const '
+					, 'static_members' => 'static $') as $type => $prefix) {
+			if (!empty($class[$type])) {
+				echo "\n";
+				// TODO: skip shadow?
+				foreach ($class[$type] as $name => $v) {
+					echo $newindent;
+					echo $prefix, $name, ' = ';
+					echo str(value($v), $EX);
+					echo ";\n";
+				}
+			}
+		}
+		// }}}
+		// {{{ properties
+		if (!empty($class['default_properties'])) {
+			echo "\n";
+			$infos = empty($class['properties_info']) ? null : $class['properties_info'];
+			foreach ($class['default_properties'] as $name => $v) {
+				$info = (isset($infos) && isset($infos[$name])) ? $infos[$name] : null;
+				if (isset($info)) {
+					if (!empty($info['doc_comment'])) {
+						echo $newindent;
+						echo $info['doc_comment'];
+						echo "\n";
+					}
+				}
+
+				echo $newindent;
+				if (PHP_VERSION < 5) {
+					echo 'var ';
+				}
+				else if (!isset($info)) {
+					echo 'public ';
+				}
+				else {
+					if ($info['flags'] & ZEND_ACC_SHADOW) {
+						continue;
+					}
+					switch ($info['flags'] & ZEND_ACC_PPP_MASK) {
+					case ZEND_ACC_PUBLIC:
+						echo "public ";
+						break;
+					case ZEND_ACC_PRIVATE:
+						echo "private ";
+						break;
+					case ZEND_ACC_PROTECTED:
+						echo "protected ";
+						break;
+					}
+					if ($info['flags'] & ZEND_ACC_STATIC) {
+						echo "static ";
+					}
+				}
+
+				echo '$', $name;
+				if (isset($v)) {
+					echo ' = ';
+					echo str(value($v));
+				}
+				echo ";\n";
+			}
+		}
+		// }}}
+		// {{{ function_table
+		if (isset($class['function_table'])) {
+			foreach ($class['function_table'] as $func) {
+				if (!isset($func['scope']) || $func['scope'] == $class['name']) {
+					// TODO: skip shadow here
+					echo "\n";
+					$opa = $func['op_array'];
+					if (!empty($opa['doc_comment'])) {
+						echo $newindent;
+						echo $opa['doc_comment'];
+						echo "\n";
+					}
+					echo $newindent;
+					if (isset($opa['fn_flags'])) {
+						if ($opa['fn_flags'] & ZEND_ACC_ABSTRACT) {
+							echo "abstract ";
+						}
+						if ($opa['fn_flags'] & ZEND_ACC_FINAL) {
+							echo "final ";
+						}
+						if ($opa['fn_flags'] & ZEND_ACC_STATIC) {
+							echo "static ";
+						}
+
+						switch ($opa['fn_flags'] & ZEND_ACC_PPP_MASK) {
+							case ZEND_ACC_PUBLIC:
+								echo "public ";
+								break;
+							case ZEND_ACC_PRIVATE:
+								echo "private ";
+								break;
+							case ZEND_ACC_PROTECTED:
+								echo "protected ";
+								break;
+							default:
+								echo "<visibility error> ";
+								break;
+						}
+					}
+					$this->dfunction($func, $newindent, $isinterface);
+					if ($opa['function_name'] == 'Decompiler') {
+						//exit;
+					}
+				}
+			}
+		}
+		// }}}
+		echo $indent, "}\n";
+	}
+	// }}}
+	function decompileString($string) // {{{
+	{
+		$this->dc = xcache_dasm_string($string);
+		if ($this->dc === false) {
+			echo "error compling string\n";
+			return false;
+		}
+	}
+	// }}}
+	function decompileFile($file) // {{{
+	{
+		$this->dc = xcache_dasm_file($file);
+		if ($this->dc === false) {
+			echo "error compling $file\n";
+			return false;
+		}
+	}
+	// }}}
+	function output() // {{{
+	{
+		echo "<?". "php\n";
+		foreach ($this->dc['class_table'] as $key => $class) {
+			if ($key{0} != "\0") {
+				echo "\n";
+				$this->dclass($class);
+			}
+		}
+
+		foreach ($this->dc['function_table'] as $key => $func) {
+			if ($key{0} != "\0") {
+				echo "\n";
+				$this->dfunction($func);
+			}
+		}
+
+		echo "\n";
+		$this->dop_array($this->dc['op_array']);
+		echo "\n?" . ">\n";
+		return true;
+	}
+	// }}}
+}
+
+// {{{ defines
+define('ZEND_ACC_STATIC',         0x01);
+define('ZEND_ACC_ABSTRACT',       0x02);
+define('ZEND_ACC_FINAL',          0x04);
+define('ZEND_ACC_IMPLEMENTED_ABSTRACT',       0x08);
+
+define('ZEND_ACC_IMPLICIT_ABSTRACT_CLASS',    0x10);
+define('ZEND_ACC_EXPLICIT_ABSTRACT_CLASS',    0x20);
+define('ZEND_ACC_FINAL_CLASS',                0x40);
+define('ZEND_ACC_INTERFACE',                  0x80);
+define('ZEND_ACC_PUBLIC',     0x100);
+define('ZEND_ACC_PROTECTED',  0x200);
+define('ZEND_ACC_PRIVATE',    0x400);
+define('ZEND_ACC_PPP_MASK',  (ZEND_ACC_PUBLIC | ZEND_ACC_PROTECTED | ZEND_ACC_PRIVATE));
+
+define('ZEND_ACC_CHANGED',    0x800);
+define('ZEND_ACC_IMPLICIT_PUBLIC',    0x1000);
+
+define('ZEND_ACC_CTOR',       0x2000);
+define('ZEND_ACC_DTOR',       0x4000);
+define('ZEND_ACC_CLONE',      0x8000);
+
+define('ZEND_ACC_ALLOW_STATIC',   0x10000);
+
+define('ZEND_ACC_SHADOW', 0x2000);
+
+define('ZEND_FETCH_GLOBAL',           0);
+define('ZEND_FETCH_LOCAL',            1);
+define('ZEND_FETCH_STATIC',           2);
+define('ZEND_FETCH_STATIC_MEMBER',    3);
+define('ZEND_FETCH_GLOBAL_LOCK',      4);
+
+define('ZEND_FETCH_CLASS_DEFAULT',    0);
+define('ZEND_FETCH_CLASS_SELF',       1);
+define('ZEND_FETCH_CLASS_PARENT',     2);
+define('ZEND_FETCH_CLASS_MAIN',       3);
+define('ZEND_FETCH_CLASS_GLOBAL',     4);
+define('ZEND_FETCH_CLASS_AUTO',       5);
+define('ZEND_FETCH_CLASS_INTERFACE',  6);
+
+define('ZEND_EVAL',               (1<<0));
+define('ZEND_INCLUDE',            (1<<1));
+define('ZEND_INCLUDE_ONCE',       (1<<2));
+define('ZEND_REQUIRE',            (1<<3));
+define('ZEND_REQUIRE_ONCE',       (1<<4));
+
+define('ZEND_ISSET',              (1<<0));
+define('ZEND_ISEMPTY',            (1<<1));
+define('EXT_TYPE_UNUSED',         (1<<0));
+
+define('ZEND_FETCH_STANDARD',     0);
+define('ZEND_FETCH_ADD_LOCK',     1);
+
+define('ZEND_FE_FETCH_BYREF',     1);
+define('ZEND_FE_FETCH_WITH_KEY',  2);
+
+define('ZEND_MEMBER_FUNC_CALL',   1<<0);
+define('ZEND_CTOR_CALL',          1<<1);
+
+define('ZEND_ARG_SEND_BY_REF',        (1<<0));
+define('ZEND_ARG_COMPILE_TIME_BOUND', (1<<1));
+define('ZEND_ARG_SEND_FUNCTION',      (1<<2));
+
+define('BYREF_NONE',       0);
+define('BYREF_FORCE',      1);
+define('BYREF_ALLOW',      2);
+define('BYREF_FORCE_REST', 3);
+define('IS_NULL',     0);
+define('IS_LONG',     1);
+define('IS_DOUBLE',   2);
+define('IS_STRING',   3);
+define('IS_ARRAY',    4);
+define('IS_OBJECT',   5);
+define('IS_BOOL',     6);
+define('IS_RESOURCE', 7);
+define('IS_CONSTANT', 8);
+define('IS_CONSTANT_ARRAY',   9);
+
+@define('XC_IS_CV', 16);
+
+/*
+if (preg_match_all('!XC_[A-Z_]+!', file_get_contents(__FILE__), $ms)) {
+	$verdiff = array();
+	foreach ($ms[0] as $k) {
+		if (!defined($k)) {
+			$verdiff[$k] = -1;
+			define($k, -1);
+		}
+	}
+	var_export($verdiff);
+}
+/*/
+foreach (array (
+	'XC_HANDLE_EXCEPTION' => -1,
+	'XC_FETCH_CLASS' => -1,
+	'XC_FETCH_' => -1,
+	'XC_FETCH_DIM_' => -1,
+	'XC_ASSIGN_DIM' => -1,
+	'XC_UNSET_DIM' => -1,
+	'XC_FETCH_OBJ_' => -1,
+	'XC_ASSIGN_OBJ' => -1,
+	'XC_ISSET_ISEMPTY_DIM_OBJ' => -1,
+	'XC_ISSET_ISEMPTY_PROP_OBJ' => -1,
+	'XC_ISSET_ISEMPTY_VAR' => -1,
+	'XC_INIT_METHOD_CALL' => -1,
+	'XC_VERIFY_ABSTRACT_CLASS' => -1,
+	'XC_DECLARE_CLASS' => -1,
+	'XC_DECLARE_INHERITED_CLASS' => -1,
+	'XC_ADD_INTERFACE' => -1,
+	'XC_POST_DEC_OBJ' => -1,
+	'XC_POST_INC_OBJ' => -1,
+	'XC_PRE_DEC_OBJ' => -1,
+	'XC_PRE_INC_OBJ' => -1,
+	'XC_UNSET_OBJ' => -1,
+	'XC_JMP_NO_CTOR' => -1,
+	'XC_FETCH_' => -1,
+	'XC_FETCH_DIM_' => -1,
+	'XC_UNSET_DIM_OBJ' => -1,
+	'XC_FETCH_OBJ_' => -1,
+	'XC_ISSET_ISEMPTY' => -1,
+	'XC_INIT_FCALL_BY_FUNC' => -1,
+	'XC_DO_FCALL_BY_FUNC' => -1,
+	'XC_DECLARE_FUNCTION_OR_CLASS' => -1,
+) as $k => $v) {
+	if (!defined($k)) {
+		define($k, $v);
+	}
+}
+
+/* XC_UNDEF XC_OP_DATA
+$content = file_get_contents(__FILE__);
+for ($i = 0; $opname = xcache_get_opcode($i); $i ++) {
+	if (!preg_match("/\\bXC_" . $opname . "\\b(?!')/", $content)) {
+		echo "not done ", $opname, "\n";
+	}
+}
+// */
+// }}}
+
Index: /tags/1.0/lock.h
===================================================================
--- /tags/1.0/lock.h	(revision 1)
+++ /tags/1.0/lock.h	(revision 1)
@@ -0,0 +1,11 @@
+typedef struct _xc_lock_t xc_lock_t;
+
+xc_lock_t *xc_fcntl_init(const char *pathname);
+void xc_fcntl_destroy(xc_lock_t *lck);
+void xc_fcntl_lock(xc_lock_t *lck);
+void xc_fcntl_unlock(xc_lock_t *lck);
+
+#define xc_lock_init(name)  xc_fcntl_init(name)
+#define xc_lock_destroy(fd) xc_fcntl_destroy(fd)
+#define xc_lock(fd)         xc_fcntl_lock(fd)
+#define xc_unlock(fd)       xc_fcntl_unlock(fd)
Index: /tags/1.0/config.w32
===================================================================
--- /tags/1.0/config.w32	(revision 37)
+++ /tags/1.0/config.w32	(revision 37)
@@ -0,0 +1,135 @@
+// vim:ft=javascript
+
+
+ARG_ENABLE("xcache", "Include XCache support", "yes,shared");
+
+if (PHP_XCACHE != "no") {
+	var xcache_sources = "processor.c \
+	                      xcache.c \
+	                      mmap.c \
+	                      mem.c \
+	                      const_string.c \
+	                      opcode_spec.c \
+	                      stack.c \
+	                      utils.c \
+	                      lock.c \
+	                      ";
+	// {{{ add sources on enabled
+	ARG_ENABLE("xcache-optimizer",    "(N/A)", "no");
+	ARG_ENABLE("xcache-coverager",    "Enable code coverage dumper, useful for testing php scripts", "no");
+	ARG_ENABLE("xcache-assembler",    "(N/A)", "no");
+	ARG_ENABLE("xcache-disassembler", "Enable opcode to php variable dumper, NOT for production server", "no");
+	ARG_ENABLE("xcache-encoder",      "(N/A)", "no");
+	ARG_ENABLE("xcache-decoder",      "(N/A)", "no");
+
+	var XCACHE_MODULES = "cacher";
+	var options = ["optimizer",
+	               "coverager",
+	               "assembler", "disassembler",
+	               "encoder", "decoder"];
+	for (var i in options) {
+		var name = options[i];
+		var uname = name.toUpperCase();
+		var withval = eval("PHP_XCACHE_" + uname);
+		if (withval != "no") {
+			xcache_sources += " " + name + ".c";
+			XCACHE_MODULES += " " + name;
+			STDOUT.WriteLine("Enabling XCache Module: " + name);
+			AC_DEFINE("HAVE_XCACHE_" + uname, 1, "Define for XCache: " + name)
+		}
+	}
+	AC_DEFINE("XCACHE_MODULES", XCACHE_MODULES);
+	// }}}
+	// {{{ check for programs needed
+	var apps = ["m4", "grep", "sed"];
+	for (var i in apps) {
+		if (!PATH_PROG(apps[i])) {
+			ERROR(apps[i] + " is currently required to build XCache");
+		}
+	}
+	PATH_PROG("gawk", null, "AWK") || PATH_PROG("awk", null, "AWK");
+
+	// the cygwin indent is known broken on our output
+	var indent = false; // PATH_PROG("indent");
+	if (indent) {
+		indent += " -kr --use-tabs --tab-size 4 -sob -nce";
+	}
+	else {
+		indent = PATH_PROG("cat");
+		if (!indent) {
+			indent = '';
+		}
+	}
+	DEFINE("XCACHE_INDENT", indent);
+	// }}}
+	// {{{ create extension
+	EXTENSION("xcache", xcache_sources);
+	var srcdir = configure_module_dirname;
+	// it's a bit harder to get builddir
+	var mfofile = "Makefile.objects";
+	MFO.Close();
+
+	var mfo = file_get_contents(mfofile);
+	mfo.match(/(.*\\xcache)\\xcache.obj/);
+	var builddir = RegExp.$1;
+	mfo.match(/(.*\$\(CC\).* )\/c.*\\xcache\\xcache.c.*/i);
+	var ccrule = RegExp.$1;
+
+	MFO = FSO.OpenTextFile(mfofile, 8);
+	mfo = null;
+	// }}}
+	// {{{ add make fragments
+	var file = srcdir + "\\Makefile.frag";
+	STDOUT.WriteLine("Adding Makefile.frag: " + file);
+	var frag = file_get_contents(file);
+	frag = frag.replace(/\$\(srcdir\)\//g,   srcdir + '\\');
+	frag = frag.replace(/\$\(srcdir\)/g,     srcdir);
+	frag = frag.replace(/\$\(builddir\)\//g, builddir + '\\');
+	frag = frag.replace(/\$\(builddir\)/g,   builddir);
+	frag = frag.replace(/processor\//g,      "processor\\");
+	frag = frag.replace(/\.lo:/g, ".obj:");
+	frag = frag.replace(/.*\$\(CC\).* -E (.*) -o (.*)/, ccrule + " /E $1 > $2");
+	frag = frag.replace(/ -o /g, " /Fo");
+	frag = frag.replace(/mv -f /g, "move ");
+	frag = frag.replace(/ \|\| /g, "\r\n\tif errorlevel 1 ");
+	frag = frag.replace(/ && /g, "\r\n\tif not errorlevel 1 ");
+	if (indent == '') {
+		frag = frag.replace(/\| +\$\(XCACHE_INDENT\)/, '');
+		frag = frag.replace(/\$\(XCACHE_INDENT\) < /, 'type ');
+	}
+	MFO.WriteLine(frag);
+	ADD_FLAG("CFLAGS_XCACHE", "/I " + builddir);
+	/// }}}
+	// {{{ check for xcache-test
+	ARG_ENABLE("xcache-test", "XCache: Enable self test - FOR DEVELOPERS ONLY!!", "no");
+	if (PHP_XCACHE_TEST != "no") {
+		ADD_FLAG("XCACHE_ENABLE_TEST", "-DXCACHE_ENABLE_TEST");
+		AC_DEFINE("HAVE_XCACHE_TEST", 1, "Define to enable XCache self test");
+	}
+	else {
+		ADD_FLAG("XCACHE_ENABLE_TEST", "");
+	}
+
+	XCACHE_PROC_SOURCES=glob(srcdir + "\\processor\\*.m4").join(' ');
+	ADD_FLAG("XCACHE_PROC_SOURCES", XCACHE_PROC_SOURCES);
+	// }}}
+	// {{{ check for opcode_spec_def.h
+	STDOUT.Write("Checking if you have opcode_spec_def.h for XCache ... ");
+	var file = srcdir + "\\opcode_spec_def.h";
+	if (FSO.FileExists(file)) {
+		STDOUT.WriteLine("yes");
+		AC_DEFINE("HAVE_XCACHE_OPCODE_SPEC_DEF", 1, "Define if you have opcode_spec_def.h for XCache");
+	}
+	else {
+		STDOUT.WriteLine("no");
+
+		// check for features depend on opcode_spec_def.h
+		var xcache_require_opcode_spec_def = function(withval, name) {
+			if (withval != "no") {
+				ERROR(file + " is required to enable XCache " + name);
+			}
+		}
+		xcache_require_opcode_spec_def(PHP_XCACHE_DISASSEMBLER, "disassembler");
+	}
+	// }}}
+}
Index: /tags/1.0/xcache.h
===================================================================
--- /tags/1.0/xcache.h	(revision 32)
+++ /tags/1.0/xcache.h	(revision 32)
@@ -0,0 +1,219 @@
+#ifndef __XCACHE_H
+#define __XCACHE_H
+#define XCACHE_NAME       "XCache"
+#define XCACHE_VERSION    "1.0"
+#define XCACHE_AUTHOR     "mOo"
+#define XCACHE_COPYRIGHT  "Copyright (c) 2005-2006"
+#define XCACHE_URL        "http://xcache.lighttpd.net"
+
+#include <php.h>
+#include <zend_compile.h>
+#include <zend_API.h>
+#include "php_ini.h"
+#include "zend_hash.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include "myshm.h"
+#include "mem.h"
+#include "lock.h"
+
+#ifndef ZEND_WIN32
+/* UnDefine if your filesystem doesn't support inodes */
+#	define HAVE_INODE
+#endif
+#if !defined(ZEND_ENGINE_2_1) && (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 1 || PHP_MAJOR_VERSION > 5)
+#	define ZEND_ENGINE_2_1
+#endif
+
+#define NOTHING
+/* ZendEngine code Switcher */
+#ifndef ZEND_ENGINE_2
+#	define ZESW(v1, v2) v1
+#else
+#	define ZESW(v1, v2) v2
+#endif
+
+/* unicode */
+#ifdef IS_UNICODE
+#	define UNISW(text, unicode) unicode
+#else
+#	define UNISW(text, unicode) text
+#endif
+#define BUCKET_KEY_SIZE(b) \
+		(UNISW( \
+			(b)->nKeyLength, \
+				((b)->key.type == IS_UNICODE) \
+				? UBYTES(b->nKeyLength) \
+				: b->nKeyLength \
+				))
+#define BUCKET_KEY(b) (UNISW((b)->arKey, (b)->key.u.string))
+#define BUCKET_UKEY(b) (UNISW((b)->arKey, (b)->key.u.unicode))
+#define BUCKET_KEY_TYPE(b) (UNISW(0, (b)->key.type))
+#ifdef IS_UNICODE
+#	define BUCKET_HEAD_SIZE(b) XtOffsetOf(Bucket, key)
+#else
+#	define BUCKET_HEAD_SIZE(b) XtOffsetOf(Bucket, arKey)
+#endif
+#define BUCKET_SIZE(b) (BUCKET_HEAD_SIZE(b) + BUCKET_KEY_SIZE(b))
+
+#ifndef IS_UNICODE
+typedef char *zstr;
+#	define ZSTR_S(s) (s)
+#	define ZSTR_U(s) (s)
+#	define ZSTR_V(s) (s)
+#else
+#	define ZSTR_S(s) ((s)->s)
+#	define ZSTR_U(s) ((s)->u)
+#	define ZSTR_V(s) ((s)->v)
+#endif
+
+/* {{{ u hash wrapper */
+#ifndef IS_UNICODE
+#	define zend_u_hash_add(ht, type, arKey, nKeyLength, pData, nDataSize, pDest) \
+ 	   zend_hash_add(ht, arKey, nKeyLength, pData, nDataSize, pDest)
+
+#	define zend_u_hash_find(ht, type, arKey, nKeyLength, pData) \
+ 	   zend_hash_find(ht, arKey, nKeyLength, pData)
+
+#	define add_u_assoc_zval_ex(arg, type, key, key_len, value) \
+		add_assoc_zval_ex(arg, key, key_len, value)
+
+#endif
+/* }}} */
+
+
+#define ECALLOC_N(x, n) ((x) = ecalloc(n, sizeof((x)[0])))
+#define ECALLOC_ONE(x) ECALLOC_N(x, 1)
+
+
+
+typedef ulong xc_hash_value_t;
+typedef struct {
+	int bits;
+	int size;
+	int mask;
+} xc_hash_t;
+
+/* the class entry type to be stored in class_table */
+typedef ZESW(zend_class_entry, zend_class_entry*) xc_cest_t;
+
+/* xc_cest_t to (zend_class_entry*) */
+#define CestToCePtr(st) (ZESW(\
+			&(st), \
+			st \
+			) )
+
+/* ZCEP=zend class entry ptr */
+#define ZCEP_REFCOUNT_PTR(pce) (ZESW( \
+			(pce)->refcount, \
+			&((pce)->refcount) \
+			))
+
+#define ZCE_REFCOUNT_PTR(ce) ZCE_REFCOUNT_PTR(&ce)
+
+typedef zend_op_array *(zend_compile_file_t)(zend_file_handle *h, int type TSRMLS_DC);
+
+/* {{{ xc_cache_t */
+typedef struct _xc_entry_t xc_entry_t;
+typedef struct {
+	int cacheid;
+	xc_hash_t  *hcache; /* hash to cacheid */
+
+	time_t     compiling;
+	zend_ulong misses;
+	zend_ulong hits;
+	zend_ulong clogs;
+	zend_ulong ooms;
+	xc_lock_t  *lck;
+	xc_shm_t   *shm; /* to which shm contains us */
+	xc_mem_t   *mem; /* to which mem contains us */
+
+	xc_entry_t **entries;
+	int entries_count;
+	xc_entry_t *deletes;
+	int deletes_count;
+	xc_hash_t  *hentry; /* hash to entry */
+} xc_cache_t;
+/* }}} */
+/* {{{ xc_classinfo_t */
+typedef struct {
+#ifdef IS_UNICODE
+	zend_uchar type;
+#endif
+	char *key;
+	zend_uint key_size;
+	xc_cest_t cest;
+} xc_classinfo_t;
+/* }}} */
+/* {{{ xc_funcinfo_t */
+typedef struct {
+#ifdef IS_UNICODE
+	zend_uchar type;
+#endif
+	char *key;
+	zend_uint key_size;
+	zend_function func;
+} xc_funcinfo_t;
+/* }}} */
+typedef enum { XC_TYPE_PHP, XC_TYPE_VAR } xc_entry_type_t;
+/* {{{ xc_entry_data_php_t */
+typedef struct {
+	size_t sourcesize;
+#ifdef HAVE_INODE
+	int device;             /* the filesystem device */
+	int inode;              /* the filesystem inode */
+#endif
+	time_t mtime;           /* the mtime of origin source file */
+
+	zend_op_array *op_array;
+
+	zend_uint funcinfo_cnt;
+	xc_funcinfo_t *funcinfos;
+
+	zend_uint classinfo_cnt;
+	xc_classinfo_t *classinfos;
+} xc_entry_data_php_t;
+/* }}} */
+/* {{{ xc_entry_data_var_t */
+typedef struct {
+	zval   *value;
+	time_t etime;
+} xc_entry_data_var_t;
+/* }}} */
+typedef zvalue_value xc_entry_name_t;
+/* {{{ xc_entry_t */
+struct _xc_entry_t {
+	xc_entry_type_t type;
+	xc_hash_value_t hvalue;
+	xc_entry_t *next;
+	xc_cache_t *cache;      /* which cache it's on */
+
+	size_t     size;
+	zend_ulong refcount;
+	zend_ulong hits;
+	time_t     ctime;           /* the ctime of this entry */
+	time_t     atime;           /* the atime of this entry */
+	time_t     dtime;           /* the deletion time of this entry */
+
+#ifdef IS_UNICODE
+	zend_uchar name_type;
+#endif
+	xc_entry_name_t name;
+
+	union {
+		xc_entry_data_php_t *php;
+		xc_entry_data_var_t *var;
+	} data;
+};
+/* }}} */
+
+extern zend_module_entry xcache_module_entry;
+#define phpext_xcache_ptr &xcache_module_entry
+
+int xc_is_rw(const void *p);
+int xc_is_ro(const void *p);
+int xc_is_shm(const void *p);
+
+#endif /* __XCACHE_H */
Index: /tags/1.0/myshm.h
===================================================================
--- /tags/1.0/myshm.h	(revision 11)
+++ /tags/1.0/myshm.h	(revision 11)
@@ -0,0 +1,13 @@
+typedef struct _xc_shm_t xc_shm_t;
+typedef size_t xc_shmsize_t;
+
+int xc_shm_can_readonly(xc_shm_t *shm);
+int xc_shm_is_readwrite(xc_shm_t *shm, const void *p);
+int xc_shm_is_readonly(xc_shm_t *shm, const void *p);
+void *xc_shm_to_readwrite(xc_shm_t *shm, void *p);
+void *xc_shm_to_readonly(xc_shm_t *shm, void *p);
+
+void *xc_shm_ptr(xc_shm_t *shm);
+
+xc_shm_t *xc_shm_init(const char *path, xc_shmsize_t size, zend_bool readonly_protection);
+void xc_shm_destroy(xc_shm_t *shm);
Index: /tags/1.0/config.m4
===================================================================
--- /tags/1.0/config.m4	(revision 37)
+++ /tags/1.0/config.m4	(revision 37)
@@ -0,0 +1,103 @@
+dnl vim:ts=2:sw=2:expandtab
+
+AC_DEFUN([XCACHE_OPTION], [
+  PHP_ARG_ENABLE(xcache-$1, for XCache $1,
+  [  --enable-xcache-$2    XCache: $4], no, no)
+  if test "$PHP_$3" != "no"; then
+    xcache_sources="$xcache_sources $1.c"
+    XCACHE_MODULES="$XCACHE_MODULES $1"
+    HAVE_$3=1
+    AC_DEFINE([HAVE_$3], 1, [Define for XCache: $4])
+  else
+    HAVE_$3=
+  fi
+])dnl
+
+PHP_ARG_ENABLE(xcache, for XCache support,
+[  --enable-xcache         Include XCache support.])
+
+if test "$PHP_XCACHE" != "no"; then
+  xcache_sources="processor.c \
+                  xcache.c \
+                  mmap.c \
+                  mem.c \
+                  const_string.c \
+                  opcode_spec.c \
+                  stack.c \
+                  utils.c \
+                  lock.c \
+                  "
+  XCACHE_MODULES="cacher"
+  XCACHE_OPTION([optimizer],    [optimizer   ], [XCACHE_OPTIMIZER],    [(N/A)])
+  XCACHE_OPTION([coverager],    [coverager   ], [XCACHE_COVERAGER],    [Enable code coverage dumper, useful for testing php scripts])
+  XCACHE_OPTION([assembler],    [assembler   ], [XCACHE_ASSEMBLER],    [(N/A)])
+  XCACHE_OPTION([disassembler], [disassembler], [XCACHE_DISASSEMBLER], [Enable opcode to php variable dumper, NOT for production server])
+  XCACHE_OPTION([encoder],      [encoder     ], [XCACHE_ENCODER],      [(N/A)])
+  XCACHE_OPTION([decoder],      [decoder     ], [XCACHE_DECODER],      [(N/A)])
+  AC_DEFINE_UNQUOTED([XCACHE_MODULES], "$XCACHE_MODULES", [Define what modules is built with XCache])
+
+  PHP_NEW_EXTENSION(xcache, $xcache_sources, $ext_shared)
+  PHP_ADD_MAKEFILE_FRAGMENT()
+
+  PHP_ARG_ENABLE(xcache-test, for XCache self test,
+  [  --enable-xcache-test            XCache: Enable self test - FOR DEVELOPERS ONLY!!], no, no)
+  if test "$PHP_XCACHE_TEST" != "no"; then
+    XCACHE_ENABLE_TEST=-DXCACHE_ENABLE_TEST
+    AC_DEFINE([HAVE_XCACHE_TEST], 1, [Define to enable XCache self test])
+  else
+    XCACHE_ENABLE_TEST=
+  fi
+  PHP_SUBST([XCACHE_ENABLE_TEST])
+
+  AC_PATH_PROGS([AWK], [gawk awk])
+  PHP_SUBST([AWK])
+  AC_PATH_PROGS([M4], [m4])
+  PHP_SUBST([M4])
+  AC_PATH_PROGS([GREP], [grep])
+  PHP_SUBST([GREP])
+  AC_PATH_PROGS([SED], [sed])
+  PHP_SUBST([SED])
+
+  AC_PATH_PROGS([INDENT], [indent cat])
+  case $INDENT in
+  */indent[)]
+    opts="-kr --use-tabs --tab-size 4 -sob -nce"
+    if echo | $INDENT $opts > /dev/null 2>&1 ; then
+      XCACHE_INDENT="$INDENT $opts"
+    else
+      opts="-sob -nce"
+      if echo | $INDENT $opts > /dev/null 2>&1 ; then
+        XCACHE_INDENT="$INDENT $opts"
+      else
+        if echo | $INDENT > /dev/null 2>&1 ; then
+          XCACHE_INDENT="$INDENT"
+        fi
+      fi
+    fi
+    ;;
+  *[)]
+    XCACHE_INDENT=cat
+    ;;
+  esac
+  PHP_SUBST([XCACHE_INDENT])
+
+  dnl $ac_srcdir etc require PHP_NEW_EXTENSION
+  XCACHE_PROC_SOURCES=`ls $ac_srcdir/processor/*.m4`
+  PHP_SUBST([XCACHE_PROC_SOURCES])
+
+  AC_MSG_CHECKING(if you have opcode_spec_def.h for XCache)
+  if test -e "$ac_srcdir/opcode_spec_def.h" ; then
+    AC_DEFINE([HAVE_XCACHE_OPCODE_SPEC_DEF], 1, [Define if you have opcode_spec_def.h for XCache])
+    AC_MSG_RESULT(yes)
+  else
+    dnl check for features depend on opcode_spec_def.h
+    AC_MSG_RESULT(no)
+    define([ERROR], [
+      AC_MSG_ERROR([cannot build with $1, $ac_srcdir/opcode_spec_def.h required])
+    ])
+    if test "$PHP_XCACHE_DISASSEMBLER" != "no" ; then
+      ERROR(disassembler)
+    fi
+    undefine([ERROR])
+  fi
+fi
Index: /tags/1.0/test.mak
===================================================================
--- /tags/1.0/test.mak	(revision 52)
+++ /tags/1.0/test.mak	(revision 52)
@@ -0,0 +1,18 @@
+#! /usr/bin/make -f
+
+EXES=mem_test
+OBJS=mem.o
+CC=gcc
+CFLAGS=-g -O0 -D TEST -Wall
+TEST=valgrind
+
+all: mem
+
+mem_test: mem.c
+	$(CC) $(CFLAGS) -o mem_test mem.c
+	
+mem: mem_test
+	$(TEST) ./mem_test
+
+clean:
+	rm -f $(OBJS) $(EXES)
Index: /tags/1.0/includes.c
===================================================================
--- /tags/1.0/includes.c	(revision 1)
+++ /tags/1.0/includes.c	(revision 1)
@@ -0,0 +1,2 @@
+#include "xcache.h"
+#include "zend_compile.h"
Index: /tags/1.0/admin/xcache.php
===================================================================
--- /tags/1.0/admin/xcache.php	(revision 60)
+++ /tags/1.0/admin/xcache.php	(revision 60)
@@ -0,0 +1,189 @@
+<?php
+
+error_reporting(E_ALL);
+define('REQUEST_TIME', time());
+
+class Cycle
+{
+	var $values;
+	var $i;
+	var $count;
+
+	function Cycle($v)
+	{
+		$this->values = func_get_args();
+		$this->i = -1;
+		$this->count = count($this->values);
+	}
+
+	function next()
+	{
+		$this->i = ($this->i + 1) % $this->count;
+		return $this->values[$this->i];
+	}
+
+	function cur()
+	{
+		return $this->values[$this->i];
+	}
+
+	function reset()
+	{
+		$this->i = -1;
+	}
+}
+
+function number_formats($a, $keys)
+{
+	foreach ($keys as $k) {
+		$a[$k] = number_format($a[$k]);
+	}
+	return $a;
+}
+
+function size($size, $suffix = '', $precision = 2)
+{
+	$size = (int) $size;
+	if ($size < 1024)
+		return number_format($size, $precision) . ' ' . $suffix;
+
+	if ($size < 1048576)
+		return number_format($size / 1024, $precision) . ' K' . $suffix;
+
+	return number_format($size / 1048576, $precision) . ' M' . $suffix;
+}
+
+function age($time)
+{
+	if (!$time) return '';
+	$delta = REQUEST_TIME - $time;
+
+	if ($delta < 0) {
+		$delta = -$delta;
+	}
+	
+  	static $seconds = array(1, 60, 3600, 86400, 604800, 2678400, 31536000);
+	static $name = array('s', 'm', 'h', 'd', 'w', 'M', 'Y');
+
+	for ($i = 6; $i >= 0; $i --) {
+		if ($delta >= $seconds[$i]) {
+			$ret = (int) ($delta / $seconds[$i]);
+			return $ret . ' ' . $name[$i];
+		}
+	}
+}
+
+function switcher($name, $options)
+{
+	$n = isset($_GET[$name]) ? $_GET[$name] : null;
+	$html = array();
+	foreach ($options as $k => $v) {
+		$html[] = sprintf('<a href="?%s=%s"%s>%s</a>', $name, $k, $k == $n ? 'class="active"' : '', $v);
+	}
+	return implode(' ', $html);
+}
+
+$charset = "UTF-8";
+
+if (file_exists("config.php")) {
+	include("config.php");
+}
+
+$pcnt = xcache_count(XC_TYPE_PHP);
+$vcnt = xcache_count(XC_TYPE_VAR);
+
+$type_none = -1;
+if (!isset($_GET['type'])) {
+	$_GET['type'] = $type_none;
+}
+$_GET['type'] = $type = (int) $_GET['type'];
+
+// {{{ process clear
+function processClear()
+{
+	$type = isset($_POST['type']) ? $_POST['type'] : null;
+	if ($type != XC_TYPE_PHP && $type != XC_TYPE_VAR) {
+		$type = null;
+	}
+	if (isset($type)) {
+		$cacheid = (int) (isset($_POST['cacheid']) ? $_POST['cacheid'] : 0);
+		if (isset($_POST['clearcache'])) {
+			xcache_clear_cache($type, $cacheid);
+		}
+	}
+}
+processClear();
+// }}}
+// {{{ load info/list
+$cacheinfos = array();
+for ($i = 0; $i < $pcnt; $i ++) {
+	$data = xcache_info(XC_TYPE_PHP, $i);
+	if ($type === XC_TYPE_PHP) {
+		$data += xcache_list(XC_TYPE_PHP, $i);
+	}
+	$data['type'] = XC_TYPE_PHP;
+	$data['cache_name'] = "php#$i";
+	$data['cacheid'] = $i;
+	$cacheinfos[] = $data;
+}
+for ($i = 0; $i < $vcnt; $i ++) {
+	$data = xcache_info(XC_TYPE_VAR, $i);
+	if ($type === XC_TYPE_VAR) {
+		$data += xcache_list(XC_TYPE_VAR, $i);
+	}
+	$data['type'] = XC_TYPE_VAR;
+	$data['cache_name'] = "var#$i";
+	$data['cacheid'] = $i;
+	$cacheinfos[] = $data;
+}
+// }}}
+// {{{ merge the list
+switch ($type) {
+case XC_TYPE_PHP:
+case XC_TYPE_VAR:
+	$cachelist = array('type' => $type, 'cache_list' => array(), 'deleted_list' => array());
+	if ($type == XC_TYPE_VAR) {
+		$cachelist['type_name'] = 'var';
+	}
+	else {
+		$cachelist['type_name'] = 'php';
+	}
+	foreach ($cacheinfos as $i => $c) {
+		if ($c['type'] == $type && isset($c['cache_list'])) {
+			foreach ($c['cache_list'] as $e) {
+				$e['cache_name'] = $c['cache_name'];
+				$cachelist['cache_list'][] = $e;
+			}
+			foreach ($c['deleted_list'] as $e) {
+				$e['cache_name'] = $c['cache_name'];
+				$cachelist['deleted_list'][] = $e;
+			}
+		}
+	}
+	if ($type == XC_TYPE_PHP) {
+		$inodes = array();
+		foreach ($cachelist['cache_list'] as $e) {
+			$i = &$inodes[$e['inode']];
+			if (isset($i) && $i == 1) {
+				set_error("duplicate inode $e[inode]");
+			}
+			$i ++;
+		}
+	}
+	unset($data);
+	break;
+
+default:
+	$_GET['type'] = $type_none;
+	$cachelist = array();
+	break;
+}
+// }}}
+
+$type_php = XC_TYPE_PHP;
+$type_var = XC_TYPE_VAR;
+$types = array($type_none => 'Statistics', $type_php =>'List PHP', $type_var =>'List Var Data');
+
+include("xcache.tpl.php");
+
+?>
Index: /tags/1.0/admin/xcache.css
===================================================================
--- /tags/1.0/admin/xcache.css	(revision 60)
+++ /tags/1.0/admin/xcache.css	(revision 60)
@@ -0,0 +1,17 @@
+input, table { font-family: monospace; font-size: 11px; }
+table.cycles { border: 1px solid black; background: white; margin-top: 5px; margin-bottom: 5px; }
+table.cycles .col1 { background-color: #f5f5f5; }
+table.cycles .col2 { background-color: #e0e0e0; }
+table.cycles th, table.cycles td { border-top: 1px solid white; border-left: 1px solid white; }
+table.cycles th { background-color: #707090; color: white; font-weight: bold; height: 20px; line-height: 16px; font-family: serif; }
+th a { color: white; font-weight: bold; display: block; width: 100%; height: 100%; }
+.button { }
+span.sortarrow { color: white; text-decoration: none; }
+.freeblocks { float: left; margin-right: 4px;}
+form {margin: 0; padding: 0}
+.percent { border: 1px solid gray; width: 90%; }
+.percent .v { background: black; font-size: 1px; line-height: 11px;}
+.switcher, h1 { text-align: center; display: block; }
+.switcher * { color: blue; }
+.switcher a.active { font-weight: bold; font-size: 130%; color: black; }
+#help { display: block; float: right; }
Index: /tags/1.0/admin/config.php.example
===================================================================
--- /tags/1.0/admin/config.php.example	(revision 34)
+++ /tags/1.0/admin/config.php.example	(revision 34)
@@ -0,0 +1,47 @@
+<?php
+
+// this is an example only
+// write your own config and name it as config.php
+
+$charset = "UTF-8";
+
+// this function is detected by xcache.tpl.php, and enabled if function_exists
+// this ob filter is applied for the cache list, not the whole page
+function ob_filter_path_nicer($o)
+{
+	$o = str_replace("/home/", "{H}/", $o);
+	return $o;
+}
+
+// you can simply let xcache to do the http auth
+// but if you have your home made login/permission system, you can implement the following
+// {{{ home made login example
+// this is an example only, it's won't work for you without your implemention.
+function check_admin_and_by_pass_xcache_http_auth()
+{
+	require("/path/to/user-login-and-permission-lib.php");
+	session_start();
+
+	if (!user_logined()) {
+		if (!ask_the_user_to_login()) {
+			exit;
+		}
+	}
+
+	user_load_permissions();
+	if (!user_is_admin()) {
+		die("Permission denied");
+	}
+
+	// user is trusted after permission checks above.
+	// tell XCache about it (the only way to by pass XCache http auth)
+	$_SERVER["PHP_AUTH_USER"] = "moo";
+	$_SERVER["PHP_AUTH_PW"] = "your-xcache-password";
+	return true;
+}
+
+// uncomment:
+// check_admin_and_by_pass_xcache_http_auth();
+// }}}
+
+?>
Index: /tags/1.0/admin/tablesort.js
===================================================================
--- /tags/1.0/admin/tablesort.js	(revision 34)
+++ /tags/1.0/admin/tablesort.js	(revision 34)
@@ -0,0 +1,58 @@
+var sort_column;
+var prev_span = null;
+function get_inner_text(el) {
+ if((typeof el == 'string')||(typeof el == 'undefined'))
+  return el;
+ if(el.innerText)
+  return el.innerText;
+ else {
+  var str = "";
+  var cs = el.childNodes;
+  var l = cs.length;
+  for (i=0;i<l;i++) {
+   if (cs[i].nodeType==1) str += get_inner_text(cs[i]);
+   else if (cs[i].nodeType==3) str += cs[i].nodeValue;
+  }
+ }
+ return str;
+}
+function sortfn(a,b) {
+ var i = a.cells[sort_column].getAttribute('int');
+ if (i != null) {
+  return parseInt(i)-parseInt(b.cells[sort_column].getAttribute('int'));
+ } else {
+  var at = get_inner_text(a.cells[sort_column]);
+  var bt = get_inner_text(b.cells[sort_column]);
+  aa = at.toLowerCase();
+  bb = bt.toLowerCase();
+  if (aa==bb) return 0;
+  else if (aa<bb) return -1;
+  else return 1;
+ }
+}
+function resort(lnk) {
+ var span = lnk.childNodes[1];
+ if (!span) {
+ 	 var span = document.createElement("span")
+ 	 span.className = "sortarrow";
+ 	 lnk.appendChild(span);
+ }
+ var table = lnk.parentNode.parentNode.parentNode.parentNode;
+ var rows = new Array();
+ for (j=1;j<table.rows.length;j++)
+  rows[j-1] = table.rows[j];
+ sort_column = lnk.parentNode.cellIndex;
+ rows.sort(sortfn);
+ if (prev_span != null) prev_span.innerHTML = '';
+ if (span.getAttribute('sortdir')=='down') {
+  span.innerHTML = '&uarr;';
+  span.setAttribute('sortdir','up');
+  rows.reverse();
+ } else {
+  span.innerHTML = '&darr;';
+  span.setAttribute('sortdir','down');
+ }
+ for (i=0;i<rows.length;i++)
+  table.tBodies[0].appendChild(rows[i]);
+ prev_span = span;
+}
Index: /tags/1.0/admin/index.php
===================================================================
--- /tags/1.0/admin/index.php	(revision 34)
+++ /tags/1.0/admin/index.php	(revision 34)
@@ -0,0 +1,3 @@
+<?php
+
+include("xcache.php");
Index: /tags/1.0/admin/help.php
===================================================================
--- /tags/1.0/admin/help.php	(revision 60)
+++ /tags/1.0/admin/help.php	(revision 60)
@@ -0,0 +1,69 @@
+<?php
+$charset = "UTF-8";
+if (file_exists("./config.php")) {
+	include("./config.php");
+}
+?>
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+	<meta http-equiv="Content-Language" content="en-us" />
+<?php
+echo <<<HEAD
+	<meta http-equiv="Content-Type" content="text/html; charset=$charset" />
+	<script type="text/javascript" src="tablesort.js" charset="$charset"></script>
+HEAD;
+?>
+
+	<link rel="stylesheet" type="text/css" href="xcache.css" />
+	<title>XCache Administration Help</title>
+	<script>
+	function toggle(o)
+	{
+		o.style.display = o.style.display != 'block' ? 'block' : 'none';
+	}
+	</script>
+</head>
+
+<body>
+<h1>XCache Administration Help</h1>
+<a href="javascript:" onclick="toggle(document.getElementById('help'));return false" style="display:block; float: right">Help</a>
+<div id1="help">
+<h2>Cache Legends</h2>
+<pre>
+<b>Slots:      </b>Number of hash slots. the setting from your php.ini
+<b>Size:       </b>Cache Size, Size of the cache (or cache chunk), in bytes
+<b>Avail:      </b>Available Memory, free memory in bytes of this cache
+<b>Used:       </b>Used Percent, A bar shows how much memory used in percent
+<b>Clear:      </b>Clear Button, Press the button to clean this cache
+<b>Compiling:  </b>Compiling flag, "yes" if the cache is busy compiling php script
+<b>Hits:       </b>Cache Hits, hit=a var/php is loaded from this cache
+<b>Misses:     </b>Cache Misses, miss=a var/php is requested but not in the cache
+<b>CLogs:      </b>Compiling Clogs, clog=compiling is needed but avoided to wait(be blocked)
+            for the cache busy compiling
+<b>OOMs:       </b>Out Of Memory, how many times a new item should be stored but there isn't
+            enough memory in the cache, think of increasing the xcache.size or xcache.var_size
+<b>Protected:  </b>Whether readonly_protection is available and enable on this cache
+<b>Cached:     </b>Number of entries stored in this cache
+<b>Deleted:    </b>Number of entries is pending in delete list (expired but referenced)
+<b>Free Blocks:</b>Free blocks list in the specified cache
+</pre>
+
+<h2>List Legends</h2>
+<pre>
+<b>entry:      </b>The entry name or filename
+<b>Hits:       </b>Times this entry is hit (loaded from this cache)
+<b>Refcount:   </b>Reference count this entry is holded by a php request
+<b>Size:       </b>Size in bytes of this entry in the cache
+<b>SrcSize:    </b>Size of the source file
+<b>Modify:     </b>Last modified time of the source file
+<b>device:     </b>device number of the source file
+<b>inode:      </b>inode number of the source file
+<b>Access:     </b>Last access time of the cached entry
+<b>Create:     </b>The time when this entry is stored
+</pre>
+</div>
+
+See also: <a href="http://trac.lighttpd.net/xcache/wiki/PhpIni">setting php.ini for XCache</a> in the <a href="http://trac.lighttpd.net/xcache/">XCache wiki</a>
+</body>
+</html>
Index: /tags/1.0/admin/xcache.tpl.php
===================================================================
--- /tags/1.0/admin/xcache.tpl.php	(revision 60)
+++ /tags/1.0/admin/xcache.tpl.php	(revision 60)
@@ -0,0 +1,234 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+	<meta http-equiv="Content-Language" content="en-us" />
+<?php
+echo <<<HEAD
+	<meta http-equiv="Content-Type" content="text/html; charset=$charset" />
+	<script type="text/javascript" src="tablesort.js" charset="$charset"></script>
+HEAD;
+?>
+
+	<link rel="stylesheet" type="text/css" href="xcache.css" />
+	<title>XCache Administration</title>
+</head>
+
+<body>
+<h1>XCache Administration</h1>
+<a href="help.php" target="_blank" id="help">Help &raquo;</a>
+<span class="switcher"><?php echo switcher("type", $types); ?></span>
+<?php
+$a = new Cycle('class="col1"', 'class="col2"');
+$b = new Cycle('class="col1"', 'class="col2"');
+?>
+Caches:
+<table cellspacing="0" cellpadding="4" class="cycles">
+	<col />
+	<col align="right" />
+	<col align="right" />
+	<col align="right" />
+	<col />
+	<col />
+	<col align="right" />
+	<col align="right" />
+	<col align="right" />
+	<col align="right" />
+	<col align="right" />
+	<col align="right" />
+	<col align="right" />
+	<col align="right" />
+	<col />
+	<tr <?php echo $a->next(); ?>>
+		<th>-</th>
+		<th>Slots</th>
+		<th>Size</th>
+		<th>Avail</th>
+		<th>Used</th>
+		<th>Clear</th>
+		<th>Compiling</th>
+		<th>Hits</th>
+		<th>Misses</th>
+		<th>Clogs</th>
+		<th>OOMs</th>
+		<th>Protected</th>
+		<th>Cached</th>
+		<th>Deleted</th>
+	</tr>
+	<?php
+	$numkeys = explode(',', 'slots,size,avail,hits,misses,clogs,ooms,cached,deleted');
+	foreach ($cacheinfos as $i => $ci) {
+		echo "
+		<tr ", $a->next(), ">";
+		$ci = number_formats($ci, $numkeys);
+		$ci['compiling']    = $ci['type'] == $type_php ? ($ci['compiling'] ? 'yes' : 'no') : '-';
+		$ci['can_readonly'] = $ci['can_readonly'] ? 'yes' : 'no';
+
+		$percent = (int) (($ci['size'] - $ci['avail']) / $ci['size'] * 100);
+		echo <<<EOS
+		<th>{$ci['cache_name']}</th>
+		<td>{$ci['slots']}</td>
+		<td>{$ci['size']}</td>
+		<td>{$ci['avail']}</td>
+		<td><div class="percent"><div style="width: $percent%" class="v">&nbsp;</div></div></td>
+		<td>
+			<form method="post">
+				<div>
+					<input type="hidden" name="type" value="{$ci['type']}">
+					<input type="hidden" name="cacheid" value="{$ci['cacheid']}">
+					<input type="submit" name="clearcache" value="Clear" class="submit" onclick="return confirm('Sure to clear?');" />
+				</div>
+			</form>
+		</td>
+		<td>{$ci['compiling']}</td>
+		<td>{$ci['hits']}</td>
+		<td>{$ci['misses']}</td>
+		<td>{$ci['clogs']}</td>
+		<td>{$ci['ooms']}</td>
+		<td>{$ci['can_readonly']}</td>
+		<td>{$ci['cached']}</td>
+		<td>{$ci['deleted']}</td>
+EOS;
+
+			$b->reset();
+			?>
+	</tr>
+	<?php } ?>
+</table>
+Free Blocks:
+<?php
+foreach ($cacheinfos as $i => $ci) {
+	$b->reset();
+?>
+<table cellspacing="0" cellpadding="4" class="cycles freeblocks">
+	<tr>
+		<th><?php echo $ci['cache_name']; ?> size<br>offset</th>
+	<?php
+	foreach ($ci['free_blocks'] as $block) {
+		$size   = number_format($block['size']);
+		$offset = number_format($block['offset']);
+
+		$c = $b->next();
+		echo "
+		<td $c><nobr>$size<br>$offset</nobr></td>";
+	}
+	?>
+
+	</tr>
+</table>
+<?php
+}
+?>
+<div style="clear: both">&nbsp;</div>
+<?php
+
+if ($cachelist) {
+	$isphp = $cachelist['type'] == $type_php;
+	if (function_exists("ob_filter_path_nicer")) {
+		ob_start("ob_filter_path_nicer");
+	}
+	foreach (array('Cached' => $cachelist['cache_list'], 'Deleted' => $cachelist['deleted_list']) as $listname => $entries) {
+		$a->reset();
+		echo "
+		<caption>{$cachelist['type_name']} $listname</caption>";
+		?>
+
+	<table cellspacing="0" cellpadding="4" class="cycles entrys" width="100%">
+		<col />
+		<col />
+		<col align="right" />
+		<col align="right" />
+		<col align="right" />
+		<col align="right" />
+		<col align="right" />
+		<col align="right" />
+		<?php
+		if ($listname == 'Deleted') {
+			echo '<col align="right" />';
+		}
+		if ($isphp) {
+			echo '<col align="right" />';
+			echo '<col align="right" />';
+			echo '<col align="right" />';
+		}
+
+		echo "
+		<tr ", $a->next(), ">";
+		?>
+
+			<th><a href="javascript:" onclick="resort(this); return false">Cache</a></th>
+			<th><a href="javascript:" onclick="resort(this); return false">entry</a></th>
+			<th><a href="javascript:" onclick="resort(this); return false">Hits</a></th>
+			<th><a href="javascript:" onclick="resort(this); return false">Ref count</a></th>
+			<th><a href="javascript:" onclick="resort(this); return false">Size</a></th>
+			<?php if ($isphp) { ?>
+			<th><a href="javascript:" onclick="resort(this); return false">SrcSize</a></th>
+			<th><a href="javascript:" onclick="resort(this); return false">Modify</a></th>
+			<th><a href="javascript:" onclick="resort(this); return false">device</a></th>
+			<th><a href="javascript:" onclick="resort(this); return false">inode</a></th>
+			<?php } ?>
+			<th><a href="javascript:" onclick="resort(this); return false">Access</a></th>
+			<th><a href="javascript:" onclick="resort(this); return false">Create</a></th>
+			<?php if ($listname == 'Deleted') { ?>
+			<th><a href="javascript:" onclick="resort(this); return false">Delete</a></th>
+			<?php } ?>
+		</tr>
+		<?php
+		foreach ($entries as $i => $entry) {
+			echo "
+			<tr ", $a->next(), ">";
+			$name     = htmlspecialchars($entry['name']);
+			$hits     = number_format($entry['hits']);
+			$refcount = number_format($entry['refcount']);
+			$size     = size($entry['size']);
+			if ($isphp) {
+				$sourcesize = size($entry['sourcesize']);
+			}
+
+			if ($isphp) {
+				$mtime = age($entry['mtime']);
+			}
+			$ctime = age($entry['ctime']);
+			$atime = age($entry['atime']);
+			$dtime = age($entry['dtime']);
+
+			echo <<<ENTRY
+			<td>{$entry['cache_name']} {$i}</td>
+			<td>{$name}</td>
+			<td int="{$entry['hits']}">{$entry['hits']}</td>
+			<td int="{$entry['refcount']}">{$entry['refcount']}</td>
+			<td int="{$entry['size']}">{$size}</td>
+ENTRY;
+			if ($isphp) {
+				echo <<<ENTRY
+				<td int="{$entry['sourcesize']}">{$sourcesize}</td>
+				<td int="{$entry['mtime']}">{$mtime}</td>
+				<td int="{$entry['device']}">{$entry['device']}</td>
+				<td int="{$entry['inode']}">{$entry['inode']}</td>
+ENTRY;
+			}
+			echo <<<ENTRY
+			<td int="{$entry['atime']}">{$atime}</td>
+			<td int="{$entry['ctime']}">{$ctime}</td>
+ENTRY;
+			if ($listname == 'Deleted') {
+			echo <<<ENTRY
+				<td int="{$entry['dtime']}">{$dtime}</td>
+ENTRY;
+			}
+
+			echo "
+		</tr>
+			";
+		}
+		?>
+
+	</table>
+<?php
+	}
+	if (function_exists("ob_filter_path_nicer")) {
+		ob_end_flush();
+	}
+}
+?>
+</body>
+</html>
Index: /tags/1.0/prepare.devel
===================================================================
--- /tags/1.0/prepare.devel	(revision 52)
+++ /tags/1.0/prepare.devel	(revision 52)
@@ -0,0 +1,100 @@
+#! /bin/bash
+SELF="$0"
+
+if test -e prepare.devel.inc ; then
+	. prepare.devel.inc
+else
+	echo prepare.devel.inc is required, see prepare.devel.inc.example >&2
+	exit
+fi
+
+CTAGS=`which ctags 2>/dev/null || which exuberant-ctags 2>/dev/null `
+AWK=`which gawk 2>/dev/null || which awk 2>/dev/null `
+
+make_all() {
+	make_opcode_spec_def.h
+	make_const_string
+	test -e tags && echo tags exists, skipping. use \""$0" tags\" to rebuild || make_tags
+}
+
+make_clean() {
+ 	make_clean_const_string
+	echo "*" rm -f tags opcode_spec_def.h
+	rm -f tags opcode_spec_def.h
+}
+
+make_const_string() {
+	make_const_string_opcodes_php4.x.h
+	make_const_string_opcodes_php5.0.h
+	make_const_string_opcodes_php5.1.h
+	make_const_string_opcodes_php6.x.h
+}
+
+make_clean_const_string() {
+	echo "*" rm -f const_string_opcodes_php*.h{,.tmp}
+	rm -f const_string_opcodes_php*.h
+}
+
+make_const_string_opcodes_php4.x.h() {
+	precheck const_string_opcodes_php4.x.h "${PHP4_x_DIR}/Zend/zend_compile.h" && "$AWK" -f ./mkopcode.awk < "$I" > "$O.tmp" && mv "$O.tmp" "$O"
+}
+
+make_const_string_opcodes_php5.0.h() {
+	precheck const_string_opcodes_php5.0.h "${PHP5_0_DIR}/Zend/zend_compile.h" && "$AWK" -f ./mkopcode.awk < "$I" > "$O.tmp" && mv "$O.tmp" "$O"
+}
+
+make_const_string_opcodes_php5.1.h() {
+	precheck const_string_opcodes_php5.1.h "${PHP5_1_DIR}/Zend/zend_vm_def.h"  && "$AWK" -f ./mkopcode.awk < "$I" > "$O.tmp" && mv "$O.tmp" "$O"
+}
+
+make_const_string_opcodes_php6.x.h() {
+	precheck const_string_opcodes_php6.x.h "${PHP6_x_DIR}/Zend/zend_vm_def.h"  && "$AWK" -f ./mkopcode.awk < "$I" > "$O.tmp" && mv "$O.tmp" "$O"
+}
+
+make_opcode_spec_def.h() {
+	precheck "opcode_spec_def.h" "${EA_DIR}/opcodes.c" && "$AWK" -f ./mkopcode_spec.awk < "$I" > "$O"
+}
+
+make_tags() {
+	if test -z "$CTAGS" ; then
+		echo tool ctags not found, skip building tags >&2
+		return
+	fi
+
+	if test -d "${PHP_DEVEL_DIR}" ; then
+		echo "* Making tags with ${PHP_DEVEL_DIR}"
+		"$CTAGS" -R . "${PHP_DEVEL_DIR}/main" "${PHP_DEVEL_DIR}/Zend" "${PHP_DEVEL_DIR}/TSRM" "${PHP_DEVEL_DIR}/ext/standard"
+	else
+		echo "* Making tags without php source files"
+		"$CTAGS" -R .
+	fi
+}
+
+error() {
+	echo "$@" >&2
+}
+
+precheck() {
+	if test -e "$2" ; then :; else
+		error X skipping "$1" because "$2" not found
+		return 1
+	fi
+	if test "$1" -ot "$2" ; then :; else
+		echo O "$1" is up to date.
+		return 1
+	fi
+	O="$1"
+	I="$2"
+	echo "* Making $1 from $2"
+	return 0
+}
+
+if test -z "$1" ; then
+	make_all
+else
+	while ! test -z "$1" ; do
+		eval "make_$1"
+		shift
+	done
+fi
+
Index: /tags/1.0/const_string.c
===================================================================
--- /tags/1.0/const_string.c	(revision 51)
+++ /tags/1.0/const_string.c	(revision 51)
@@ -0,0 +1,114 @@
+#include "xcache.h"
+#include "const_string.h"
+
+/* {{{ xc_get_op_type */
+static const char *const op_type_names[] = {
+	/* 0 */ "NULL?",
+	/* 1 */ "IS_CONST",
+	/* 2 */ "IS_TMP_VAR",
+	/* 3 */ NULL,
+	/* 4 */ "IS_VAR",
+	/* 5 */ NULL,
+	/* 6 */ NULL,
+	/* 7 */ NULL,
+	/* 8 */ "IS_UNUSED",
+#ifdef IS_CV
+	/* 9  */ NULL,
+	/* 10 */ NULL,
+	/* 11 */ NULL,
+	/* 12 */ NULL,
+	/* 13 */ NULL,
+	/* 14 */ NULL,
+	/* 15 */ NULL,
+	/* 16 */ "IS_CV"
+#endif
+};
+
+zend_uchar xc_get_op_type_count()
+{
+	return sizeof(op_type_names) / sizeof(op_type_names[0]);
+}
+
+const char *xc_get_op_type(zend_uchar op_type)
+{
+	assert(op_type < xc_get_op_type_count());
+	return op_type_names[op_type];
+}
+/* }}} */
+/* {{{ xc_get_data_type */
+static const char *const data_type_names[] = {
+	/* 0 */ "IS_NULL",
+	/* 1 */ "IS_LONG",
+	/* 2 */ "IS_DOUBLE",
+	/* 3 */ "IS_BOOL",
+	/* 4 */ "IS_ARRAY",
+	/* 5 */ "IS_OBJECT",
+	/* 6 */ "IS_STRING",
+	/* 7 */ "IS_RESOURCE",
+	/* 8 */ "IS_CONSTANT",
+	/* 9 */ "IS_CONSTANT_ARRAY",
+	/* 10 */ "IS_UNICODE",
+#if 0
+	/* 11 */ "",
+	/* 12 */ "",
+	/* 13 */ "",
+	/* 14 */ "",
+	/* 15 */ "", "", "", "", "",
+
+/* IS_CONSTANT_INDEX */
+	/* 20 */ "CIDX IS_NULL",
+	/* 21 */ "CIDX IS_LONG",
+	/* 22 */ "CIDX IS_DOUBLE",
+	/* 23 */ "CIDX IS_BOOL",
+	/* 24 */ "CIDX IS_ARRAY",
+	/* 25 */ "CIDX IS_OBJECT",
+	/* 26 */ "CIDX IS_STRING",
+	/* 27 */ "CIDX IS_RESOURCE",
+	/* 28 */ "CIDX IS_CONSTANT",
+	/* 29 */ "CIDX IS_CONSTANT_ARRAY"
+	/* 20 */ "CIDX IS_UNICODE",
+#endif
+};
+
+zend_uchar xc_get_data_type_count()
+{
+	return sizeof(data_type_names) / sizeof(data_type_names[0]);
+}
+
+const char *xc_get_data_type(zend_uchar data_type)
+{
+#if 0
+	if (data_type & IS_CONSTANT_INDEX) {
+		data_type = (data_type & ~IS_CONSTANT_INDEX) + 20;
+	}
+#endif
+	data_type &= ~IS_CONSTANT_INDEX;
+	return data_type_names[data_type];
+}
+/* }}} */
+/* {{{ xc_get_opcode */
+#if PHP_MAJOR_VERSION >= 6
+#	include     "const_string_opcodes_php6.x.h"
+#else
+#	ifdef ZEND_ENGINE_2_1
+#		include     "const_string_opcodes_php5.1.h"
+#	else
+#		ifdef ZEND_ENGINE_2
+#			include "const_string_opcodes_php5.0.h"
+#		else
+#			include "const_string_opcodes_php4.x.h"
+#		endif
+#	endif
+#endif
+
+zend_uchar xc_get_opcode_count()
+{
+	return sizeof(xc_opcode_names) / sizeof(xc_opcode_names[0]);
+}
+
+const char *xc_get_opcode(zend_uchar opcode)
+{
+	assert(opcode < xc_get_opcode_count());
+	return xc_opcode_names[opcode];
+}
+/* }}} */
Index: /tags/1.0/README
===================================================================
--- /tags/1.0/README	(revision 64)
+++ /tags/1.0/README	(revision 64)
@@ -0,0 +1,1 @@
+Please check http://trac.lighttpd.net/xcache/ and http://forum.lighttpd.net/forum/4 for help
Index: /tags/1.0/.vimrc
===================================================================
--- /tags/1.0/.vimrc	(revision 1)
+++ /tags/1.0/.vimrc	(revision 1)
@@ -0,0 +1,2 @@
+
+au FileType m4 setlocal ts=2 sw=2 fdm=marker
Index: /tags/1.0/mem.c
===================================================================
--- /tags/1.0/mem.c	(revision 54)
+++ /tags/1.0/mem.c	(revision 54)
@@ -0,0 +1,376 @@
+#ifdef TEST
+#include <limits.h>
+#include <stdio.h>
+#else
+#include <php.h>
+#endif
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include "mem.h"
+#include "align.h"
+
+#ifdef TEST
+#	define ALLOC_DEBUG
+#endif
+#ifdef ALLOC_DEBUG
+#	define ALLOC_DEBUG_BLOCK_CHECK
+#endif
+
+#if 0
+#undef ALLOC_DEBUG_BLOCK_CHECK
+#endif
+
+#define CHAR_PTR(p) ((char *) (p))
+#define PADD(p, a) (CHAR_PTR(p) + a)
+#define PSUB(p1, p2) (CHAR_PTR(p1) - CHAR_PTR(p2))
+
+// {{{ mem
+struct _xc_block_t {
+#ifdef ALLOC_DEBUG_BLOCK_CHECK
+	unsigned int magic;
+#endif
+	xc_memsize_t size; /* reserved even after alloc */
+	xc_block_t *next;  /* not used after alloc */
+};
+
+struct _xc_mem_t {
+	xc_memsize_t size;
+	xc_memsize_t avail;       /* total free */
+	xc_block_t headblock[1];  /* just as a pointer to first block*/
+};
+
+#ifndef XtOffsetOf
+#	include <linux/stddef.h>
+#	define XtOffsetOf(s_type, field) offsetof(s_type, field)
+#endif
+
+#define SizeOf(type, field) sizeof( ((type *) 0)->field )
+#define BLOCK_HEADER_SIZE() (ALIGN( XtOffsetOf(xc_block_t, size) + SizeOf(xc_block_t, size) ))
+
+#define BLOCK_MAGIC ((unsigned int) 0x87655678)
+
+/* }}} */
+static inline void xc_block_setup(xc_block_t *b, xc_memsize_t size, xc_block_t *next) /* {{{ */
+{
+#ifdef ALLOC_DEBUG_BLOCK_CHECK
+	b->magic = BLOCK_MAGIC;
+#endif
+	b->size = size;
+	b->next = next;
+}
+/* }}} */
+#ifdef ALLOC_DEBUG_BLOCK_CHECK
+static void xc_block_check(xc_block_t *b) /* {{{ */
+{
+	if (b->magic != BLOCK_MAGIC) {
+		fprintf(stderr, "0x%X != 0x%X magic wrong \n", b->magic, BLOCK_MAGIC);
+	}
+}
+/* }}} */
+#else
+#	define xc_block_check(b) do { } while(0)
+#endif
+
+
+void *xc_mem_malloc(xc_mem_t *mem, xc_memsize_t size) /* {{{ */
+{
+	xc_block_t *prev, *cur;
+	xc_block_t *newb, *b;
+	xc_memsize_t realsize;
+	xc_memsize_t minsize;
+	void *p;
+	/* [xc_block_t:size|size] */
+	realsize = BLOCK_HEADER_SIZE() + size;
+	/* realsize is ALIGNed so next block start at ALIGNed address */
+	realsize = ALIGN(realsize);
+
+#ifdef ALLOC_DEBUG
+	fprintf(stderr, "avail: %d (%dKB). Allocate size: %d realsize: %d (%dKB)"
+			, mem->avail, mem->avail / 1024
+			, size
+			, realsize, realsize / 1024
+			);
+#endif
+	do {
+		p = NULL;
+		if (mem->avail < realsize) {
+#ifdef ALLOC_DEBUG
+			fprintf(stderr, " oom\n");
+#endif
+			break;
+		}
+
+		b = NULL;
+		minsize = INT_MAX;
+
+		/* prev|cur */
+
+		for (prev = mem->headblock; prev->next; prev = cur) {
+			/* while (prev->next != 0) { */
+			cur = prev->next;
+			xc_block_check(cur);
+			if (cur->size == realsize) {
+				/* found a perfect fit, stop searching */
+				b = prev;
+				break;
+			}
+			/* make sure we can split on the block */
+			else if (cur->size > (sizeof(xc_block_t) + realsize) &&
+					cur->size < minsize) {
+				/* cur is acceptable and memller */
+				b = prev;
+				minsize = cur->size;
+			}
+			prev = cur;
+		}
+
+		if (b == NULL) {
+#ifdef ALLOC_DEBUG
+			fprintf(stderr, " no fit chunk\n");
+#endif
+			break;
+		}
+
+		prev = b;
+
+		cur = prev->next;
+		p = PADD(cur, BLOCK_HEADER_SIZE());
+
+		/* update the block header */
+		mem->avail -= realsize;
+
+		/* perfect fit, just unlink */
+		if (cur->size == realsize) {
+			prev->next = cur->next;
+#ifdef ALLOC_DEBUG
+			fprintf(stderr, " perfect fit. Got: %p\n", p);
+#endif
+			break;
+		}
+
+		/* make new free block after alloced space */
+
+		/* save, as it might be overwrited by newb (cur->size is ok) */
+		b = cur->next;
+
+		/* prev|cur     |next=b */
+
+		newb = (xc_block_t *)PADD(cur, realsize);
+		xc_block_setup(newb, cur->size - realsize, b);
+		cur->size = realsize;
+		/* prev|cur|newb|next
+		 *            `--^
+		 */
+
+#ifdef ALLOC_DEBUG
+		fprintf(stderr, " -> avail: %d (%dKB). new next: %p offset: %d %dKB. Got: %p\n"
+				, mem->avail, mem->avail / 1024
+				, newb
+				, PSUB(newb, mem), PSUB(newb, mem) / 1024
+				, p
+				);
+#endif
+		prev->next = newb;
+		/* prev|cur|newb|next
+		 *    `-----^
+		 */
+
+	} while (0);
+
+	return p;
+}
+/* }}} */
+int xc_mem_free(xc_mem_t *mem, const void *p) /* {{{ return block size freed */
+{
+	xc_block_t *cur, *b;
+	int size;
+
+	cur = (xc_block_t *) (CHAR_PTR(p) - BLOCK_HEADER_SIZE());
+#ifdef ALLOC_DEBUG
+	fprintf(stderr, "freeing: %p", p);
+	fprintf(stderr, ", size=%d", cur->size);
+#endif
+	xc_block_check(cur);
+	assert((char*)mem < (char*)cur && (char*)cur < (char*)mem + mem->size);
+
+	/* find free block right before the p */
+	b = mem->headblock;
+	while (b->next != 0 && b->next < cur) {
+		b = b->next;
+	}
+
+	/* restore block */
+	cur->next = b->next;
+	b->next = cur;
+	size = cur->size;
+
+#ifdef ALLOC_DEBUG
+	fprintf(stderr, ", avail %d (%dKB)", mem->avail, mem->avail / 1024);
+#endif
+	mem->avail += size;
+
+	/* combine prev|cur */
+	if (PADD(b, b->size) == (char *)cur) {
+		b->size += cur->size;
+		b->next = cur->next;
+		cur = b;
+#ifdef ALLOC_DEBUG
+		fprintf(stderr, ", combine prev");
+#endif
+	}
+
+	/* combine cur|next */
+	b = cur->next;
+	if (PADD(cur, cur->size) == (char *)b) {
+		cur->size += b->size;
+		cur->next = b->next;
+#ifdef ALLOC_DEBUG
+		fprintf(stderr, ", combine next");
+#endif
+	}
+#ifdef ALLOC_DEBUG
+	fprintf(stderr, " -> avail %d (%dKB)\n", mem->avail, mem->avail / 1024);
+#endif
+	return size;
+}
+/* }}} */
+void *xc_mem_calloc(xc_mem_t *mem, xc_memsize_t memb, xc_memsize_t size) /* {{{ */
+{
+	xc_memsize_t realsize = memb * size;
+	void *p = xc_mem_malloc(mem, realsize);
+
+	memset(p, 0, realsize);
+	return p;
+}
+/* }}} */
+void *xc_mem_realloc(xc_mem_t *mem, const void *p, xc_memsize_t size) /* {{{ */
+{
+	void *newp = xc_mem_malloc(mem, size);
+	memcpy(newp, p, size);
+	xc_mem_free(mem, p);
+	return newp;
+}
+/* }}} */
+char *xc_mem_strndup(xc_mem_t *mem, const char *str, xc_memsize_t len) /* {{{ */
+{
+	void *p = xc_mem_malloc(mem, len + 1);
+	memcpy(p, str, len + 1);
+	return p;
+}
+/* }}} */
+char *xc_mem_strdup(xc_mem_t *mem, const char *str) /* {{{ */
+{
+	return xc_mem_strndup(mem, str, strlen(str));
+}
+/* }}} */
+
+xc_memsize_t xc_mem_avail(xc_mem_t *mem) /* {{{ */
+{
+	return mem->avail;
+}
+/* }}} */
+xc_memsize_t xc_mem_size(xc_mem_t *mem) /* {{{ */
+{
+	return mem->size;
+}
+/* }}} */
+
+const xc_block_t *xc_mem_freeblock_first(xc_mem_t *mem) /* {{{ */
+{
+	return mem->headblock->next;
+}
+/* }}} */
+const xc_block_t *xc_mem_freeblock_next(const xc_block_t *block) /* {{{ */
+{
+	return block->next;
+}
+/* }}} */
+xc_memsize_t xc_mem_block_size(const xc_block_t *block) /* {{{ */
+{
+	return block->size;
+}
+/* }}} */
+xc_memsize_t xc_mem_block_offset(const xc_mem_t *mem, const xc_block_t *block) /* {{{ */
+{
+	return ((char *) block) - ((char *) mem);
+}
+/* }}} */
+
+xc_mem_t *xc_mem_init(void *ptr, xc_memsize_t size) /* {{{ */
+{
+	xc_mem_t   *mem;
+	xc_block_t *b;
+
+#define MINSIZE (ALIGN(sizeof(xc_mem_t)) + sizeof(xc_block_t))
+	/* requires at least the header and 1 tail block */
+	if (size < MINSIZE) {
+		fprintf(stderr, "xc_mem_init requires %d bytes at least\n", MINSIZE);
+		return NULL;
+	}
+	mem = (xc_mem_t *) ptr;
+	mem->size = size;
+	mem->avail = size - MINSIZE;
+
+	/* pointer to first block, right after ALIGNed header */
+	b = mem->headblock;
+	xc_block_setup(b, 0, (xc_block_t *) PADD(mem, ALIGN(sizeof(xc_mem_t))));
+
+	/* first block*/
+	b = b->next;
+	xc_block_setup(b, mem->avail, 0);
+#undef MINSIZE
+
+	return mem;
+}
+/* }}} */
+void xc_mem_destroy(xc_mem_t *mem) /* {{{ */
+{
+}
+/* }}} */
+
+#ifdef TEST
+/* {{{ */
+#undef CHECK
+#define CHECK(a, msg) do { if ((a) == NULL) { puts(msg); return -1; } } while (0)
+#include <time.h>
+
+int main()
+{
+	int count = 0;
+	void *p;
+	void *memory;
+	xc_mem_t *mem;
+	void **ptrs;
+	int size, i;
+
+#if 0
+	fprintf(stderr, "%s", "Input test size: ");
+	scanf("%d", &size);
+#else
+	size = 100;
+#endif
+	CHECK(memory = malloc(size), "OOM");
+	CHECK(ptrs   = malloc(size * sizeof(void*)), "OOM");
+	CHECK(mem    = xc_mem_init(memory, size), "Failed init memory allocator");
+
+	while ((p = xc_mem_malloc(mem, 1))) {
+		ptrs[count ++] = p;
+	}
+	fprintf(stderr, "count=%d, random freeing\n", count);
+	srandom(time(NULL));
+	while (count) {
+		i = (random() % count);
+		fprintf(stderr, "freeing %d: ", i);
+		xc_mem_free(mem, ptrs[i]);
+		ptrs[i] = ptrs[count - 1];
+		count --;
+	}
+
+	free(ptrs);
+	free(memory);
+	return 0;
+}
+/* }}} */
+#endif
Index: /tags/1.0/phpdop.phpr
===================================================================
--- /tags/1.0/phpdop.phpr	(revision 52)
+++ /tags/1.0/phpdop.phpr	(revision 52)
@@ -0,0 +1,118 @@
+#! /usr/bin/php
+<?php
+
+$srcdir = dirname(__FILE__);
+if (file_exists("$srcdir/phpdc.debug.php")) {
+	include("$srcdir/phpdc.debug.php");
+}
+
+function get_op($op)
+{
+	switch ($op['op_type']) {
+	case 1: // CONST
+		return var_export($op['u.constant'], true);
+
+	case 2: // IS_TMP_VAR
+		return 't@' . $op['u.var'];
+
+	case 4:
+		return 'v$' . $op['u.var'];
+
+	case 8: // UNUSED
+		if (isset($op['u.opline_num'])) {
+			return 'l#' . $op['u.opline_num'];
+		}
+		else {
+			return '-';
+		}
+
+	default:
+		return $op['op_type'] . $op['u.var'];
+	}
+}
+
+function dump_opcodes($op_array, $indent = '')
+{
+	$types = array('result' => 5, 'op1' => 20, 'op2' => 20);
+	foreach ($op_array as $line => $op) {
+		echo $indent;
+		echo sprintf("%3d ", $op['lineno']);
+		echo sprintf("%3x ", $line);
+		$name = xcache_get_opcode($op['opcode']);
+
+		if (substr($name, 0, 5) == 'ZEND_') {
+			$name = substr($name, 5);
+		}
+		echo str_pad($name, 25);
+
+		foreach ($types as $t => $len) {
+			echo str_pad(isset($op[$t]) ? get_op($op[$t]) : "", $len);
+		}
+		printf("%5s", isset($op['extended_value']) ?  $op['extended_value'] : "");
+
+		echo "\n";
+	}
+}
+
+function dump_function($name, $func, $indent = '')
+{
+	if (isset($func['op_array'])) {
+		$op_array = $func['op_array'];
+		unset($func['op_array']);
+	}
+	else {
+		$op_array = null;
+	}
+	var_dump($func);
+	echo $indent, 'function ', $name, "\n";
+	if (isset($op_array)) {
+		dump_opcodes($op_array['opcodes'], "  " . $indent);
+	}
+}
+
+function dump_class($name, $class, $indent = '')
+{
+	if (isset($class['function_table'])) {
+		$funcs = $class['function_table'];
+		unset($class['function_table']);
+	}
+	else {
+		$funcs = null;
+	}
+	echo $indent, 'class ', $name, "\n";
+	if (isset($funcs)) {
+		foreach ($funcs as $name => $func) {
+			dump_function($name, $func, "  " . $indent);
+		}
+	}
+}
+
+$pk = xcache_dasm_file($argv[1]);
+$op_array = $funcs = $classes = null;
+if (isset($pk['op_array'])) {
+	$op_array = $pk['op_array'];
+	unset($pk['op_array']);
+}
+if (isset($pk['function_table'])) {
+	$funcs = $pk['function_table'];
+	unset($pk['function_table']);
+}
+if (isset($pk['class_table'])) {
+	$classes = $pk['class_table'];
+	unset($pk['class_table']);
+}
+var_dump($pk);
+if (isset($op_array)) {
+	dump_opcodes($op_array['opcodes']);
+}
+if (isset($funcs)) {
+	foreach ($funcs as $name => $func) {
+		dump_function($name, $func);
+	}
+}
+if (isset($classes)) {
+	foreach ($classes as $name => $class) {
+		dump_class($name, $class);
+	}
+}
+
Index: /tags/1.0/const_string.h
===================================================================
--- /tags/1.0/const_string.h	(revision 20)
+++ /tags/1.0/const_string.h	(revision 20)
@@ -0,0 +1,8 @@
+#include "php.h"
+
+zend_uchar xc_get_op_type_count();
+const char *xc_get_op_type(zend_uchar op_type);
+zend_uchar xc_get_data_type_count();
+const char *xc_get_data_type(zend_uchar data_type);
+zend_uchar xc_get_opcode_count();
+const char *xc_get_opcode(zend_uchar opcode);
Index: /tags/1.0/mem.h
===================================================================
--- /tags/1.0/mem.h	(revision 1)
+++ /tags/1.0/mem.h	(revision 1)
@@ -0,0 +1,20 @@
+typedef struct _xc_mem_t xc_mem_t;
+typedef struct _xc_block_t xc_block_t;
+typedef unsigned int xc_memsize_t;
+
+void *xc_mem_malloc(xc_mem_t *mem, xc_memsize_t size);
+int xc_mem_free(xc_mem_t *mem, const void *p);
+void *xc_mem_calloc(xc_mem_t *mem, xc_memsize_t memb, xc_memsize_t size);
+void *xc_mem_realloc(xc_mem_t *mem, const void *p, xc_memsize_t size);
+char *xc_mem_strndup(xc_mem_t *mem, const char *str, xc_memsize_t len);
+char *xc_mem_strdup(xc_mem_t *mem, const char *str);
+const xc_block_t *xc_mem_freeblock_first(xc_mem_t *mem);
+const xc_block_t *xc_mem_freeblock_next(const xc_block_t *block);
+xc_memsize_t xc_mem_block_size(const xc_block_t *block);
+xc_memsize_t xc_mem_block_offset(const xc_mem_t *mem, const xc_block_t *block);
+
+xc_memsize_t xc_mem_avail(xc_mem_t *mem);
+xc_memsize_t xc_mem_size(xc_mem_t *mem);
+
+xc_mem_t *xc_mem_init(void *ptr, xc_memsize_t size);
+void xc_mem_destroy(xc_mem_t *mem);
Index: /tags/1.0/const_string_opcodes_php5.0.h
===================================================================
--- /tags/1.0/const_string_opcodes_php5.0.h	(revision 56)
+++ /tags/1.0/const_string_opcodes_php5.0.h	(revision 56)
@@ -0,0 +1,153 @@
+/* size = 149 */
+static const char *const xc_opcode_names[] = {
+/* 0 */	"NOP",
+/* 1 */	"ADD",
+/* 2 */	"SUB",
+/* 3 */	"MUL",
+/* 4 */	"DIV",
+/* 5 */	"MOD",
+/* 6 */	"SL",
+/* 7 */	"SR",
+/* 8 */	"CONCAT",
+/* 9 */	"BW_OR",
+/* 10 */	"BW_AND",
+/* 11 */	"BW_XOR",
+/* 12 */	"BW_NOT",
+/* 13 */	"BOOL_NOT",
+/* 14 */	"BOOL_XOR",
+/* 15 */	"IS_IDENTICAL",
+/* 16 */	"IS_NOT_IDENTICAL",
+/* 17 */	"IS_EQUAL",
+/* 18 */	"IS_NOT_EQUAL",
+/* 19 */	"IS_SMALLER",
+/* 20 */	"IS_SMALLER_OR_EQUAL",
+/* 21 */	"CAST",
+/* 22 */	"QM_ASSIGN",
+/* 23 */	"ASSIGN_ADD",
+/* 24 */	"ASSIGN_SUB",
+/* 25 */	"ASSIGN_MUL",
+/* 26 */	"ASSIGN_DIV",
+/* 27 */	"ASSIGN_MOD",
+/* 28 */	"ASSIGN_SL",
+/* 29 */	"ASSIGN_SR",
+/* 30 */	"ASSIGN_CONCAT",
+/* 31 */	"ASSIGN_BW_OR",
+/* 32 */	"ASSIGN_BW_AND",
+/* 33 */	"ASSIGN_BW_XOR",
+/* 34 */	"PRE_INC",
+/* 35 */	"PRE_DEC",
+/* 36 */	"POST_INC",
+/* 37 */	"POST_DEC",
+/* 38 */	"ASSIGN",
+/* 39 */	"ASSIGN_REF",
+/* 40 */	"ECHO",
+/* 41 */	"PRINT",
+/* 42 */	"JMP",
+/* 43 */	"JMPZ",
+/* 44 */	"JMPNZ",
+/* 45 */	"JMPZNZ",
+/* 46 */	"JMPZ_EX",
+/* 47 */	"JMPNZ_EX",
+/* 48 */	"CASE",
+/* 49 */	"SWITCH_FREE",
+/* 50 */	"BRK",
+/* 51 */	"CONT",
+/* 52 */	"BOOL",
+/* 53 */	"INIT_STRING",
+/* 54 */	"ADD_CHAR",
+/* 55 */	"ADD_STRING",
+/* 56 */	"ADD_VAR",
+/* 57 */	"BEGIN_SILENCE",
+/* 58 */	"END_SILENCE",
+/* 59 */	"INIT_FCALL_BY_NAME",
+/* 60 */	"DO_FCALL",
+/* 61 */	"DO_FCALL_BY_NAME",
+/* 62 */	"RETURN",
+/* 63 */	"RECV",
+/* 64 */	"RECV_INIT",
+/* 65 */	"SEND_VAL",
+/* 66 */	"SEND_VAR",
+/* 67 */	"SEND_REF",
+/* 68 */	"NEW",
+/* 69 */	"JMP_NO_CTOR",
+/* 70 */	"FREE",
+/* 71 */	"INIT_ARRAY",
+/* 72 */	"ADD_ARRAY_ELEMENT",
+/* 73 */	"INCLUDE_OR_EVAL",
+/* 74 */	"UNSET_VAR",
+/* 75 */	"UNSET_DIM_OBJ",
+/* 76 */	"UNDEF",
+/* 77 */	"FE_RESET",
+/* 78 */	"FE_FETCH",
+/* 79 */	"EXIT",
+/* 80 */	"FETCH_R",
+/* 81 */	"FETCH_DIM_R",
+/* 82 */	"FETCH_OBJ_R",
+/* 83 */	"FETCH_W",
+/* 84 */	"FETCH_DIM_W",
+/* 85 */	"FETCH_OBJ_W",
+/* 86 */	"FETCH_RW",
+/* 87 */	"FETCH_DIM_RW",
+/* 88 */	"FETCH_OBJ_RW",
+/* 89 */	"FETCH_IS",
+/* 90 */	"FETCH_DIM_IS",
+/* 91 */	"FETCH_OBJ_IS",
+/* 92 */	"FETCH_FUNC_ARG",
+/* 93 */	"FETCH_DIM_FUNC_ARG",
+/* 94 */	"FETCH_OBJ_FUNC_ARG",
+/* 95 */	"FETCH_UNSET",
+/* 96 */	"FETCH_DIM_UNSET",
+/* 97 */	"FETCH_OBJ_UNSET",
+/* 98 */	"FETCH_DIM_TMP_VAR",
+/* 99 */	"FETCH_CONSTANT",
+/* 100 */	"UNDEF",
+/* 101 */	"EXT_STMT",
+/* 102 */	"EXT_FCALL_BEGIN",
+/* 103 */	"EXT_FCALL_END",
+/* 104 */	"EXT_NOP",
+/* 105 */	"TICKS",
+/* 106 */	"SEND_VAR_NO_REF",
+/* 107 */	"CATCH",
+/* 108 */	"THROW",
+/* 109 */	"FETCH_CLASS",
+/* 110 */	"CLONE",
+/* 111 */	"INIT_CTOR_CALL",
+/* 112 */	"INIT_METHOD_CALL",
+/* 113 */	"INIT_STATIC_METHOD_CALL",
+/* 114 */	"ISSET_ISEMPTY_VAR",
+/* 115 */	"ISSET_ISEMPTY_DIM_OBJ",
+/* 116 */	"UNDEF",
+/* 117 */	"UNDEF",
+/* 118 */	"UNDEF",
+/* 119 */	"UNDEF",
+/* 120 */	"UNDEF",
+/* 121 */	"UNDEF",
+/* 122 */	"UNDEF",
+/* 123 */	"UNDEF",
+/* 124 */	"UNDEF",
+/* 125 */	"UNDEF",
+/* 126 */	"UNDEF",
+/* 127 */	"UNDEF",
+/* 128 */	"UNDEF",
+/* 129 */	"UNDEF",
+/* 130 */	"UNDEF",
+/* 131 */	"UNDEF",
+/* 132 */	"PRE_INC_OBJ",
+/* 133 */	"PRE_DEC_OBJ",
+/* 134 */	"POST_INC_OBJ",
+/* 135 */	"POST_DEC_OBJ",
+/* 136 */	"ASSIGN_OBJ",
+/* 137 */	"OP_DATA",
+/* 138 */	"INSTANCEOF",
+/* 139 */	"DECLARE_CLASS",
+/* 140 */	"DECLARE_INHERITED_CLASS",
+/* 141 */	"DECLARE_FUNCTION",
+/* 142 */	"RAISE_ABSTRACT_ERROR",
+/* 143 */	"UNDEF",
+/* 144 */	"ADD_INTERFACE",
+/* 145 */	"UNDEF",
+/* 146 */	"VERIFY_ABSTRACT_CLASS",
+/* 147 */	"ASSIGN_DIM",
+/* 148 */	"ISSET_ISEMPTY_PROP_OBJ",
+/* 149 */	"HANDLE_EXCEPTION"
+};
Index: /tags/1.0/const_string_opcodes_php5.1.h
===================================================================
--- /tags/1.0/const_string_opcodes_php5.1.h	(revision 1)
+++ /tags/1.0/const_string_opcodes_php5.1.h	(revision 1)
@@ -0,0 +1,154 @@
+/* size = 150 */
+static const char *const xc_opcode_names[] = {
+/* 0 */	"NOP",
+/* 1 */	"ADD",
+/* 2 */	"SUB",
+/* 3 */	"MUL",
+/* 4 */	"DIV",
+/* 5 */	"MOD",
+/* 6 */	"SL",
+/* 7 */	"SR",
+/* 8 */	"CONCAT",
+/* 9 */	"BW_OR",
+/* 10 */	"BW_AND",
+/* 11 */	"BW_XOR",
+/* 12 */	"BW_NOT",
+/* 13 */	"BOOL_NOT",
+/* 14 */	"BOOL_XOR",
+/* 15 */	"IS_IDENTICAL",
+/* 16 */	"IS_NOT_IDENTICAL",
+/* 17 */	"IS_EQUAL",
+/* 18 */	"IS_NOT_EQUAL",
+/* 19 */	"IS_SMALLER",
+/* 20 */	"IS_SMALLER_OR_EQUAL",
+/* 21 */	"CAST",
+/* 22 */	"QM_ASSIGN",
+/* 23 */	"ASSIGN_ADD",
+/* 24 */	"ASSIGN_SUB",
+/* 25 */	"ASSIGN_MUL",
+/* 26 */	"ASSIGN_DIV",
+/* 27 */	"ASSIGN_MOD",
+/* 28 */	"ASSIGN_SL",
+/* 29 */	"ASSIGN_SR",
+/* 30 */	"ASSIGN_CONCAT",
+/* 31 */	"ASSIGN_BW_OR",
+/* 32 */	"ASSIGN_BW_AND",
+/* 33 */	"ASSIGN_BW_XOR",
+/* 34 */	"PRE_INC",
+/* 35 */	"PRE_DEC",
+/* 36 */	"POST_INC",
+/* 37 */	"POST_DEC",
+/* 38 */	"ASSIGN",
+/* 39 */	"ASSIGN_REF",
+/* 40 */	"ECHO",
+/* 41 */	"PRINT",
+/* 42 */	"JMP",
+/* 43 */	"JMPZ",
+/* 44 */	"JMPNZ",
+/* 45 */	"JMPZNZ",
+/* 46 */	"JMPZ_EX",
+/* 47 */	"JMPNZ_EX",
+/* 48 */	"CASE",
+/* 49 */	"SWITCH_FREE",
+/* 50 */	"BRK",
+/* 51 */	"CONT",
+/* 52 */	"BOOL",
+/* 53 */	"INIT_STRING",
+/* 54 */	"ADD_CHAR",
+/* 55 */	"ADD_STRING",
+/* 56 */	"ADD_VAR",
+/* 57 */	"BEGIN_SILENCE",
+/* 58 */	"END_SILENCE",
+/* 59 */	"INIT_FCALL_BY_NAME",
+/* 60 */	"DO_FCALL",
+/* 61 */	"DO_FCALL_BY_NAME",
+/* 62 */	"RETURN",
+/* 63 */	"RECV",
+/* 64 */	"RECV_INIT",
+/* 65 */	"SEND_VAL",
+/* 66 */	"SEND_VAR",
+/* 67 */	"SEND_REF",
+/* 68 */	"NEW",
+/* 69 */	"UNDEF",
+/* 70 */	"FREE",
+/* 71 */	"INIT_ARRAY",
+/* 72 */	"ADD_ARRAY_ELEMENT",
+/* 73 */	"INCLUDE_OR_EVAL",
+/* 74 */	"UNSET_VAR",
+/* 75 */	"UNSET_DIM",
+/* 76 */	"UNSET_OBJ",
+/* 77 */	"FE_RESET",
+/* 78 */	"FE_FETCH",
+/* 79 */	"EXIT",
+/* 80 */	"FETCH_R",
+/* 81 */	"FETCH_DIM_R",
+/* 82 */	"FETCH_OBJ_R",
+/* 83 */	"FETCH_W",
+/* 84 */	"FETCH_DIM_W",
+/* 85 */	"FETCH_OBJ_W",
+/* 86 */	"FETCH_RW",
+/* 87 */	"FETCH_DIM_RW",
+/* 88 */	"FETCH_OBJ_RW",
+/* 89 */	"FETCH_IS",
+/* 90 */	"FETCH_DIM_IS",
+/* 91 */	"FETCH_OBJ_IS",
+/* 92 */	"FETCH_FUNC_ARG",
+/* 93 */	"FETCH_DIM_FUNC_ARG",
+/* 94 */	"FETCH_OBJ_FUNC_ARG",
+/* 95 */	"FETCH_UNSET",
+/* 96 */	"FETCH_DIM_UNSET",
+/* 97 */	"FETCH_OBJ_UNSET",
+/* 98 */	"FETCH_DIM_TMP_VAR",
+/* 99 */	"FETCH_CONSTANT",
+/* 100 */	"UNDEF",
+/* 101 */	"EXT_STMT",
+/* 102 */	"EXT_FCALL_BEGIN",
+/* 103 */	"EXT_FCALL_END",
+/* 104 */	"EXT_NOP",
+/* 105 */	"TICKS",
+/* 106 */	"SEND_VAR_NO_REF",
+/* 107 */	"CATCH",
+/* 108 */	"THROW",
+/* 109 */	"FETCH_CLASS",
+/* 110 */	"CLONE",
+/* 111 */	"UNDEF",
+/* 112 */	"INIT_METHOD_CALL",
+/* 113 */	"INIT_STATIC_METHOD_CALL",
+/* 114 */	"ISSET_ISEMPTY_VAR",
+/* 115 */	"ISSET_ISEMPTY_DIM_OBJ",
+/* 116 */	"UNDEF",
+/* 117 */	"UNDEF",
+/* 118 */	"UNDEF",
+/* 119 */	"UNDEF",
+/* 120 */	"UNDEF",
+/* 121 */	"UNDEF",
+/* 122 */	"UNDEF",
+/* 123 */	"UNDEF",
+/* 124 */	"UNDEF",
+/* 125 */	"UNDEF",
+/* 126 */	"UNDEF",
+/* 127 */	"UNDEF",
+/* 128 */	"UNDEF",
+/* 129 */	"UNDEF",
+/* 130 */	"UNDEF",
+/* 131 */	"UNDEF",
+/* 132 */	"PRE_INC_OBJ",
+/* 133 */	"PRE_DEC_OBJ",
+/* 134 */	"POST_INC_OBJ",
+/* 135 */	"POST_DEC_OBJ",
+/* 136 */	"ASSIGN_OBJ",
+/* 137 */	"OP_DATA",
+/* 138 */	"INSTANCEOF",
+/* 139 */	"DECLARE_CLASS",
+/* 140 */	"DECLARE_INHERITED_CLASS",
+/* 141 */	"DECLARE_FUNCTION",
+/* 142 */	"RAISE_ABSTRACT_ERROR",
+/* 143 */	"UNDEF",
+/* 144 */	"ADD_INTERFACE",
+/* 145 */	"UNDEF",
+/* 146 */	"VERIFY_ABSTRACT_CLASS",
+/* 147 */	"ASSIGN_DIM",
+/* 148 */	"ISSET_ISEMPTY_PROP_OBJ",
+/* 149 */	"HANDLE_EXCEPTION",
+/* 150 */	"USER_OPCODE"
+};
Index: /tags/1.0/mkstructinfo.awk
===================================================================
--- /tags/1.0/mkstructinfo.awk	(revision 52)
+++ /tags/1.0/mkstructinfo.awk	(revision 52)
@@ -0,0 +1,117 @@
+#! /usr/bin/awk -f
+# vim:ts=4:sw=4
+BEGIN {
+	brace = 0;
+	buffer_len = 0;
+}
+/^}.*;/ {
+	if (instruct) {
+		sub(";", "");
+		if (instruct == 1 && $2) {
+			instruct = $2;
+		}
+		if (instruct in typedefs) {
+			instruct = typedefs[instruct];
+		}
+		sizeinfo = "";
+		elms = "";
+		for (i = 0; i in buffer; i ++) {
+			if (i) {
+				sizeinfo = sizeinfo " + ";
+			}
+			sizeinfo = sizeinfo "sizeof(((" instruct "*)NULL)->" buffer[i] ")";
+
+			if (i == 0) {
+				elms = buffer[i];
+			}
+			else {
+				elms = elms "," buffer[i];
+			}
+		}
+		printf "define(`ELEMENTSOF_%s', `%s')\n", instruct, elms;
+		printf "define(`COUNTOF_%s', `%s')\n", instruct, i;
+		printf "define(`SIZEOF_%s', `(  %s  )')\n", instruct, sizeinfo;
+		print "\n";
+		for (i in buffer) {
+			delete buffer[i];
+		}
+		buffer_len = 0;
+		instruct = 0;
+	}
+	next;
+}
+
+/.\{/ {
+	brace = brace + 1;
+}
+/.}/ {
+	brace = brace - 1;
+}
+
+{
+	if (brace == 1 && instruct) {
+		sub(/.*[{}]/, "");
+		gsub(/\[[^\]]+\]/, ""); # ignore [...]
+		gsub(/:[0-9]+/, ""); # ignore struct bit
+		if (match($0, /^[^(]*\([ ]*\*([^)]+)\)/)) {
+			sub(/ +/, "")
+			sub(/^[^(]*\(\*/, "");
+			sub(/\).*/, "");
+			# function pointer
+			buffer[buffer_len] = $0;
+			buffer_len ++;
+		}
+		else {
+			# ignore any ()s
+			while (gsub(/(\([^)]*\))/, "")) {
+			}
+			if (match($0, /[()]/)) {
+				next;
+			}
+			gsub(/[*]/, " ");
+			gsub(/ +/, " ");
+			gsub(/ *[,;]/, ";");
+			if (!match($0, /;/)) {
+				next;
+			}
+			split($0, chunks, ";");
+			# get var of "int *var, var;" etc
+			for (i in chunks) {
+				if (chunks[i] == "") {
+					delete chunks[i];
+					continue;
+				}
+				split(chunks[i], pieces, " ");
+
+				for (j in pieces) {
+					last_piece = pieces[j];
+					delete pieces[i];
+				}
+				if (last_piece == "") {
+					print "=====" chunks[i];
+				}
+				buffer[buffer_len] = last_piece;
+				buffer_len ++;
+				delete chunks[i];
+			}
+		}
+		next;
+	}
+}
+
+/^typedef struct [^{]*;/ {
+	sub(";", "");
+	typedefs[$3] = $4;
+	next;
+}
+/^typedef struct .*\{/ {
+	brace = 1;
+	instruct = 1;
+	next;
+}
+
+/^struct .*\{/ {
+	instruct = $2;
+	brace = 1;
+	next;
+}
Index: /tags/1.0/xcache.ini
===================================================================
--- /tags/1.0/xcache.ini	(revision 44)
+++ /tags/1.0/xcache.ini	(revision 44)
@@ -0,0 +1,57 @@
+[xcache-common]
+;; install as zend extension (recommended), normally "$extension_dir/xcache.so"
+zend_extension = /usr/local/lib/php/extensions/non-debug-non-zts-xxx/xcache.so
+;; For windows users, replace xcache.so with php_xcache.dll
+zend_extension_ts = c:/php/extensions/php_xcache.dll
+;; or install as extension, make sure your extension_dir setting is correct
+; extension = xcache.so
+;; or win32:
+; extension = php_xcache.dll
+
+; required for >=php5.1 if you turn XCache on
+auto_globals_jit = Off
+
+[xcache.admin]
+xcache.admin.user = "mOo"
+; xcache.admin.pass = md5($your_password)
+xcache.admin.pass = ""
+
+[xcache]
+; ini only settings, all the values here is default unless explained
+; to disable: xcache.size=0
+; to enable : xcache.size=any size > 0 and your system mmap allows
+xcache.size =                  0
+; uncomment and set to cpu count (cat /proc/cpuinfo |grep -c processor)
+xcache.count =                 1
+; just a hash hints, you can always store count(items) > slots
+xcache.slots =                8K
+
+; same as aboves but for variable cache
+xcache.var_size =              0
+xcache.var_count =             1
+xcache.var_slots =            8K
+
+xcache.test =                Off
+; N/A for /dev/zero
+xcache.readonly_protection = Off
+; for win32, xcache.mmap_path=anonymous map name, not file path
+; uncomment and change to "/tmp/xcache" for readonly protection
+; 2 group of php won't share the same /tmp/xcache
+xcache.mmap_path =    "/dev/zero"
+
+
+; leave it blank(disabled) or "/tmp/phpcore/"
+; make sure it's writable by php (without checking open_basedir)
+xcache.coredump_directory =   ""
+
+; per request settings
+xcache.cacher =               On
+xcache.optimizer =           Off
+
+[xcache.coverager]
+; ini only settings
+; make sure it's readable (care open_basedir) coverage viewer script
+xcache.coveragedump_directory = "/tmp/pcov/"
+
+; per request settings, will be auto disabled if xcache.coveragedump_directory is not set
+xcache.coveragedumper         = Off
Index: /tags/1.0/mmap.c
===================================================================
--- /tags/1.0/mmap.c	(revision 61)
+++ /tags/1.0/mmap.c	(revision 61)
@@ -0,0 +1,258 @@
+
+#undef ALLOC_DEBUG
+
+#include <stdio.h>
+#include <assert.h>
+#include <limits.h>
+#include <string.h>
+#include <stdlib.h>
+
+/* mmap */
+#ifdef ZEND_WIN32
+#	define ftruncate chsize
+#	define getuid() 0
+#	define XCacheCreateFileMapping(size, perm, name) \
+		CreateFileMapping(INVALID_HANDLE_VALUE, NULL, perm, (sizeof(xc_shmsize_t) > 4) ? size >> 32 : 0, size & 0xffffffff, name)
+#	define XCACHE_MAP_FAILED NULL
+#	define munmap(p, s) UnmapViewOfFile(p)
+#else
+#	include <unistd.h>
+#	define XCACHE_MAP_FAILED MAP_FAILED
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#ifndef ZEND_WIN32
+#include <sys/mman.h>
+#endif
+
+#include "php.h"
+#include "myshm.h"
+
+#ifndef max
+#define max(a, b) ((a) < (b) ? (b) : (a))
+#endif
+
+// {{{ xc_shm_t
+struct _xc_shm_t {
+	void *ptr;
+	void *ptr_ro;
+	long  diff;
+	xc_shmsize_t size;
+	char *name;
+	int newfile;
+#ifdef ZEND_WIN32
+	HANDLE hmap;
+	HANDLE hmap_ro;
+#endif
+};
+
+#undef NDEBUG
+#ifdef ALLOC_DEBUG
+#	define inline
+#else
+#	define NDEBUG
+#endif
+#include <assert.h>
+/* }}} */
+#define CHECK(x, e) do { if ((x) == NULL) { zend_error(E_ERROR, "XCache: " e); goto err; } } while (0)
+#define PTR_ADD(ptr, v) (((char *) (ptr)) + (v))
+#define PTR_SUB(ptr, v) (((char *) (ptr)) - (v))
+
+int xc_shm_can_readonly(xc_shm_t *shm) /* {{{ */
+{
+	return shm->ptr_ro != NULL;
+}
+/* }}} */
+int xc_shm_is_readwrite(xc_shm_t *shm, const void *p) /* {{{ */
+{
+	return p >= shm->ptr && (char *)p < (char *)shm->ptr + shm->size;
+}
+/* }}} */
+int xc_shm_is_readonly(xc_shm_t *shm, const void *p) /* {{{ */
+{
+	return xc_shm_can_readonly(shm) && p >= shm->ptr_ro && (char *)p < (char *)shm->ptr_ro + shm->size;
+}
+/* }}} */
+void *xc_shm_to_readwrite(xc_shm_t *shm, void *p) /* {{{ */
+{
+	if (shm->diff) {
+		assert(xc_shm_is_readonly(p));
+		p = PTR_SUB(p, shm->diff);
+	}
+	assert(xc_shm_is_readwrite(p));
+	return p;
+}
+/* }}} */
+void *xc_shm_to_readonly(xc_shm_t *shm, void *p) /* {{{ */
+{
+	assert(xc_shm_is_readwrite(p));
+	if (shm->diff) {
+		p = PTR_ADD(p, shm->diff);
+		assert(xc_shm_is_readonly(p));
+	}
+	return p;
+}
+/* }}} */
+
+void xc_shm_destroy(xc_shm_t *shm) /* {{{ */
+{
+	if (shm->ptr_ro) {
+		munmap(shm->ptr_ro, shm->size);
+		/*
+		shm->ptr_ro = NULL;
+		*/
+	}
+	if (shm->ptr) {
+		/* shm->size depends on shm->ptr */
+		munmap(shm->ptr, shm->size);
+		/*
+		shm->ptr = NULL;
+		*/
+	}
+#ifdef ZEND_WIN32
+	if (shm->hmap) {
+		CloseHandle(shm->hmap);
+	}
+	if (shm->hmap_ro) {
+		CloseHandle(shm->hmap_ro);
+	}
+#endif
+
+	if (shm->name) {
+#ifdef __CYGWIN__
+		if (shm->newfile) {
+			unlink(shm->name);
+		}
+#endif
+		free(shm->name);
+	}
+	/*
+	shm->size = NULL;
+	shm->diff = 0;
+	*/
+
+	free(shm);
+	return;
+}
+/* }}} */
+xc_shm_t *xc_shm_init(const char *path, xc_shmsize_t size, zend_bool readonly_protection) /* {{{ */
+{
+#ifdef ZEND_WIN32
+#	define TMP_PATH "XCache"
+#else
+#	define TMP_PATH "/tmp/XCache"
+#endif
+	xc_shm_t *shm = NULL;
+	int fd = -1;
+	int ro_ok;
+	volatile void *romem;
+	char tmpname[sizeof(TMP_PATH) - 1 + 100];
+
+	CHECK(shm = calloc(1, sizeof(xc_shm_t)), "shm OOM");
+	shm->size = size;
+
+	if (path == NULL || !path[0]) {
+		static int inc = 0;
+		snprintf(tmpname, sizeof(tmpname) - 1, "%s.%d.%d.%d", TMP_PATH, (int) getuid(), inc ++, rand());
+		path = tmpname;
+	}
+
+	shm->name = strdup(path);
+
+#ifndef ZEND_WIN32
+#	define XCACHE_MMAP_PERMISSION (S_IRUSR | S_IWUSR)
+	fd = open(shm->name, O_RDWR, XCACHE_MMAP_PERMISSION);
+	if (fd == -1) {
+		/* do not create file in /dev */
+		if (strncmp(shm->name, "/dev", 4) == 0) {
+			goto err;
+		}
+		fd = open(shm->name, O_CREAT | O_RDWR, XCACHE_MMAP_PERMISSION);
+		shm->newfile = 1;
+		if (fd == -1) {
+			goto err;
+		}
+	}
+	ftruncate(fd, size);
+#endif
+
+#ifdef ZEND_WIN32
+	shm->hmap = XCacheCreateFileMapping(size, PAGE_READWRITE, shm->name);
+	shm->ptr = (LPSTR) MapViewOfFile(shm->hmap, FILE_MAP_WRITE, 0, 0, 0);
+#else
+	shm->ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+#endif
+
+	if (shm->ptr == XCACHE_MAP_FAILED) {
+		shm->ptr = NULL;
+		goto err;
+	}
+
+	ro_ok = 0;
+	if (readonly_protection) {
+#ifdef ZEND_WIN32
+		shm->hmap_ro = XCacheCreateFileMapping(size, PAGE_READONLY, shm->name);
+		shm->ptr_ro = (LPSTR) MapViewOfFile(shm->hmap_ro, FILE_MAP_READ, 0, 0, 0);
+#else
+		shm->ptr_ro = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
+#endif
+		romem = shm->ptr_ro;
+
+		/* {{{ check if ptr_ro works */
+		do {
+			if (shm->ptr_ro == XCACHE_MAP_FAILED || shm->ptr_ro == shm->ptr) {
+				break;
+			}
+			*(char *)shm->ptr = 1;
+			if (*(char *)romem != 1) {
+				break;
+			}
+			*(char *)shm->ptr = 2;
+			if (*(char *)romem != 2) {
+				break;
+			}
+			ro_ok = 1;
+		} while (0);
+	}
+
+	if (ro_ok) {
+		shm->diff = PTR_SUB(shm->ptr_ro, (char *) shm->ptr);
+		assert(abs(shm->diff) >= size);
+	}
+	else {
+		if (shm->ptr_ro != XCACHE_MAP_FAILED) {
+			munmap(shm->ptr_ro, size);
+		}
+		shm->ptr_ro = NULL;
+		shm->diff = 0;
+	}
+	/* }}} */
+
+	close(fd);
+#ifndef __CYGWIN__
+	if (shm->newfile) {
+		unlink(shm->name);
+	}
+#endif
+
+	return shm;
+
+err:
+	if (fd != -1) {
+		close(fd);
+	}
+	if (shm) {
+		xc_shm_destroy(shm);
+	}
+	return NULL;
+}
+/* }}} */
+
+void *xc_shm_ptr(xc_shm_t *shm) /* {{{ */
+{
+	return shm->ptr;
+}
+/* }}} */
Index: /tags/1.0/coverager/coverager.php
===================================================================
--- /tags/1.0/coverager/coverager.php	(revision 33)
+++ /tags/1.0/coverager/coverager.php	(revision 33)
@@ -0,0 +1,313 @@
+<?php
+
+error_reporting(E_ALL);
+define('REQUEST_TIME', time());
+
+class Cycle
+{
+	var $values;
+	var $i;
+	var $count;
+
+	function Cycle($v)
+	{
+		$this->values = func_get_args();
+		$this->i = -1;
+		$this->count = count($this->values);
+	}
+
+	function next()
+	{
+		$this->i = ($this->i + 1) % $this->count;
+		return $this->values[$this->i];
+	}
+
+	function cur()
+	{
+		return $this->values[$this->i];
+	}
+
+	function reset()
+	{
+		$this->i = -1;
+	}
+}
+
+class XcacheCoverageViewer
+{
+	var $syntaxhiglight = true;
+	var $usecache = false;
+	var $include_paths = array();
+	var $exclude_paths = array();
+	var $charset = 'UTF-8';
+
+	function XcacheCoverageViewer()
+	{
+		$this->datadir = ini_get('xcache.coveragedump_directory');
+
+		// copy config
+		foreach (array('charset', 'include_paths', 'exclude_paths', 'syntaxhiglight', 'usecache', 'datadir') as $k) {
+			if (isset($GLOBALS['usecache'])) {
+				$this->{$k} = $GLOBALS['usecache'];
+			}
+		}
+
+		$this->datadir = preg_replace('!/$!', '', $this->datadir);
+		$this->datadir_len =  strlen($this->datadir);
+
+		$this->path = isset($_GET['path']) ? $_GET['path'] : '';
+		$this->path = preg_replace('!\.{2,}!', '.', $this->path);
+		$this->path = preg_replace('![\\\\/]{2,}!', '/', $this->path);
+		if ($this->path == '/') {
+			$this->path = '';
+		}
+		$this->outpath = $this->datadir . $this->path;
+	}
+
+	function main()
+	{
+		$path = $this->path;
+
+		if (is_dir($this->outpath)) {
+			$action = 'dir';
+			$prefix_len = strlen($path) + 1;
+			$dirinfo = $this->loadDir($this->outpath);
+			if (!$this->usecache) {
+				ksort($dirinfo['subdirs']);
+				ksort($dirinfo['files']);
+			}
+		}
+		else if (is_file($this->outpath . ".pcov")) {
+			$action = 'file';
+
+			$dir = dirname($path);
+			$filename = basename($path);
+
+			$fileinfo = $this->loadCov($this->outpath . ".pcov");
+
+			$lines = file($path);
+			// fix the tabs not in the middle
+			foreach ($lines as $l => $line) {
+				if (preg_match('!^(\\t*)([^\\t]+\\t.*)$!s', $line, $m)) {
+					$lines[$l] = $m[1];
+					$chunks = explode("\t", $m[2]);
+					for ($i = 0, $c = count($chunks) - 1; $i < $c; $i ++) {
+						$lines[$l] .= $chunks[$i] . str_repeat(" ", 4 - (strlen($chunks[$i]) % 4));
+					}
+					$lines[$l] .= $chunks[$c];
+				}
+			}
+			if ($this->syntaxhiglight) {
+				$source = implode('', $lines);
+				ob_start();
+				highlight_string($source);
+				$lines = explode('<br />', str_replace("\n", "", ob_get_clean()));
+				$last = array_pop($lines);
+				$filecov = sprint_cov($fileinfo['cov'], $lines, false);
+				$filecov .= $last;
+				unset($source);
+			}
+			else {
+				$filecov = sprint_cov($fileinfo['cov'], $lines);
+			}
+
+			list($tplfile, $tpllines, $tplcov) = $this->loadTplCov($fileinfo['cov'], substr($this->outpath, $this->datadir_len));
+			if ($tplfile) {
+				$tplcov = sprint_cov($tplinfo['tplcov'], $tpllines);
+				unset($tpllines);
+			}
+		}
+		else if (!$this->datadir) {
+			$action = 'require xcache.coveragedump_directory';
+		}
+		else {
+			$action = "no data";
+		}
+
+		include("coverager.tpl.php");
+	}
+
+	function loadDir($outdir, $addtodo = null)
+	{
+		if ($this->usecache) {
+			$cachefile = $outdir . "/.pcovcache";
+			if (file_exists($cachefile)) {
+				return unserialize(file_get_contents($cachefile));
+			}
+		}
+		$srcdir = substr($outdir, $this->datadir_len);
+
+		$total = $hits = $todos = 0;
+		$files = array();
+		$subdirs = array();
+		if (!isset($addtodo)) {
+			if ($this->include_paths) {
+				foreach ($this->include_paths as $p) {
+					if (strncmp($p, $srcdir, strlen($p)) == 0) {
+						$addtodo = true;
+						break;
+					}
+				}
+			}
+		}
+		if ($addtodo) {
+			if ($this->exclude_paths) {
+				foreach ($this->exclude_paths as $p) {
+					if (strncmp($p, $srcdir, strlen($p)) == 0) {
+						$addtodo = false;
+						break;
+					}
+				}
+			}
+		}
+		foreach (glob($outdir . "/*") as $outfile) {
+			if (is_dir($outfile)) {
+				$info = $this->loadDir($outfile, $addtodo);
+				$srcfile = substr($outfile, $this->datadir_len);
+				$subdirs += $info['subdirs'];
+				$total   += $info['total'];
+				$hits    += $info['hits'];
+				$todos   += $info['todos'];
+				unset($info['subdirs']);
+				$subdirs[$srcfile] = $info;
+			}
+			else if (substr($outfile, -5) == ".pcov") {
+				// pass
+				$info = $this->loadFile($outfile);
+				$total += $info['total'];
+				$hits  += $info['hits'];
+				$srcfile = substr($outfile, $this->datadir_len, -5);
+				$files[$srcfile] = $info;
+			}
+			else {
+				continue;
+			}
+		}
+		if ($addtodo === true) {
+			foreach (glob($srcdir . "/*") as $srcfile) {
+				if (!isset($files[$srcfile]) && is_file($srcfile)) {
+					$files[$srcfile] = array('total' => 0, 'hits' => 0);
+					$todos ++;
+				}
+				else if (!isset($subdirs[$srcfile]) && is_dir($srcfile)) {
+					$subdirs[$srcfile] = array('total' => 0, 'hits' => 0, 'todos' => 1, 'files' => 0, 'subdirs' => array());
+					$todos ++;
+				}
+			}
+		}
+
+		if ($this->usecache) {
+			ksort($subdirs);
+			ksort($files);
+		}
+
+		$info = array(
+				'total'   => $total,
+				'hits'    => $hits,
+				'todos'   => $todos,
+				'files'   => $files,
+				'subdirs' => $subdirs,
+				);
+
+		if ($this->usecache) {
+			$fp = fopen($cachefile, "wb");
+			fwrite($fp, serialize($info));
+			fclose($fp);
+		}
+		return $info;
+	}
+
+	function loadFile($file)
+	{
+		if ($this->usecache) {
+			$cachefile = $file . "cache";
+			if (file_exists($cachefile)) {
+				return unserialize(file_get_contents($cachefile));
+			}
+		}
+
+		$info = $this->loadCov($file); //, $lines);
+		unset($info['cov']);
+
+		if ($this->usecache) {
+			$fp = fopen($cachefile, "wb");
+			fwrite($fp, serialize($info));
+			fclose($fp);
+		}
+		return $info;
+	}
+
+	function loadCov($file)//, $lines)
+	{
+		$total = $hits = 0;
+
+		$cov = xcache_coverager_decode(file_get_contents($file));
+
+		return array('total' => count($cov) - 1, 'hits' => $cov[0], 'cov' => $cov);
+	}
+
+	function loadTplCov($cov, $ctpl)
+	{
+		$tplinfofile = $ctpl . '.phpinfo';
+
+		if (!file_exists($tplinfofile)) {
+			return;
+		}
+
+		$tplinfo = unserialize(file_get_contents($tplinfofile));
+
+		if (!isset($tplinfo['sourceFile'])) {
+			return;
+		}
+		$tplfile = $tplinfo['sourceFile'];
+		if (!isset($tplinfo['lineMap']) || !count($tplinfo['lineMap'])) {
+			return;
+		}
+
+		$tpllines = file($tplfile);
+
+		$dline = 0;
+		$sline = 0;
+		$tplcov = array();
+		foreach ($cov as $line => $times) {
+			// find nearest line
+			while ($dline < $line) {
+				if ((list($dline, $sline) = each($tplinfo['lineMap'])) === false) {
+					break 2;
+				}
+			}
+
+			$tplcov[$sline] = $times;
+		}
+		return array($tplfile, $tpllines, $tplcov);
+	}
+}
+
+function sprint_cov($cov, $lines, $encode = true)
+{
+	foreach ($lines as $l => $line) {
+		$offs = $l + 1;
+		if ($encode) {
+			$line = str_replace("\n", "", htmlspecialchars($line));
+		}
+		if (isset($cov[$offs])) {
+			$lines[$l] = sprintf("<li class=\"line%sCov\"> %s\t%s</li>\n"
+					, $cov[$offs] ? '' : 'No'
+					, $cov[$offs]
+					, $line);
+		}
+		else {
+			$lines[$l] = "<li>\t$line</li>\n";
+		}
+	}
+	return implode('', $lines);
+}
+
+if (file_exists("config.php")) {
+	include("config.php");
+}
+
+$app = new XcacheCoverageViewer();
+$app->main();
+
+?>
Index: /tags/1.0/coverager/coverager.css
===================================================================
--- /tags/1.0/coverager/coverager.css	(revision 33)
+++ /tags/1.0/coverager/coverager.css	(revision 33)
@@ -0,0 +1,57 @@
+input, table { font-family: monospace; font-size: 11px; }
+table.cycles { border: 1px solid black; background: white; margin-top: 5px; margin-bottom: 5px; }
+table.cycles .col1 { background-color: #f5f5f5; }
+table.cycles .col2 { background-color: #e0e0e0; }
+table.cycles th { background-color: #707090; color: white; font-weight: bold; height: 20px; line-height: 16px; font-family: serif; }
+th a { color: white; font-weight: bold; display: block; width: 100%; height: 100%; }
+
+.coverFile {
+	text-align:       left;
+	color:            gray;
+	padding-left:     10px;
+	padding-right:    10px;
+}
+
+.coverBar {
+	padding-left:     10px;
+	padding-right:    10px;
+}
+
+.coverBarOutline {
+	border: 1px solid black;
+	background-color: #ffffff;
+	width: 100px;
+	font-size: 11px; line-height: 11px;
+	font-family: tahoma;
+	position: relative;
+}
+
+.coverPerHi, .coverPerMed, .coverPerLo {
+	text-align:       center;
+	font-weight:      bold;
+	left: 0px; top: 2px;
+	position: absolute;
+	width: 100%;
+}
+.coverBarHi, .coverBarMed, .coverBarLo { left: 1px; top: 1px; }
+.coverBarHi  { background-color: #A7FC9D; }
+.coverBarMed { background-color: #FFEA20; }
+.coverBarLo  { background-color: #FF0000; }
+
+
+.coverNumHi, .coverNumMed, .coverNumLo {
+	text-align:       right;
+	padding-left:     10px;
+	padding-right:    10px;
+}
+.coverNumHi  { /*background-color: #A7FC9D;*/ }
+.coverNumMed { /*background-color: #FFEA20;*/ }
+.coverNumLo  { background-color: #FF0000; }
+
+.lineCov   { background-color: #F0F0F0; }
+.lineNoCov { background-color: #ffe0e0; }
+pre.code {
+	font-family: monospace;
+	white-space: pre;
+	border: 1px solid gray;
+}
Index: /tags/1.0/coverager/config.php.example
===================================================================
--- /tags/1.0/coverager/config.php.example	(revision 33)
+++ /tags/1.0/coverager/config.php.example	(revision 33)
@@ -0,0 +1,19 @@
+<?php
+
+// should be named as config.php
+
+$charset = "UTF-8";
+// $include_paths = array("/www/my-php-project/");
+// $exclude_paths = array("/www/my-php-project/tmp/");
+$syntaxhiglight = true;
+$usecache = false;
+//// $datadir is default to ini_get("xcache.coveragedump_directory")
+// $datadir = '';
+
+function ob_filter_path_nicer($o)
+{
+	$o = str_replace("/home/", "{H}/", $o);
+	return $o;
+}
+
+?>
Index: /tags/1.0/coverager/index.php
===================================================================
--- /tags/1.0/coverager/index.php	(revision 33)
+++ /tags/1.0/coverager/index.php	(revision 33)
@@ -0,0 +1,3 @@
+<?php
+
+include("coverager.php");
Index: /tags/1.0/coverager/coverager.tpl.php
===================================================================
--- /tags/1.0/coverager/coverager.tpl.php	(revision 33)
+++ /tags/1.0/coverager/coverager.tpl.php	(revision 33)
@@ -0,0 +1,212 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+	<meta http-equiv="Content-Language" content="en-us" />
+<?php
+echo <<<HEAD
+	<meta http-equiv="Content-Type" content="text/html; charset=$this->charset" />
+	<script type="text/javascript" src="tablesort.js" charset="$this->charset"></script>
+HEAD;
+?>
+
+	<link rel="stylesheet" type="text/css" href="coverager.css" />
+	<title>XCache Coverage Viewer</title>
+</head>
+<body>
+
+<?php
+function calc_percent($info, &$percent, &$class)
+{
+	if (!$info['total']) {
+		$percent = 0;
+	}
+	else {
+		$percent = (int) ($info['hits'] / $info['total'] * 100);
+	}
+	if ($percent < 15) {
+		$class = "Lo";
+	}
+	else if ($percent < 50) {
+		$class = "Med";
+	}
+	else {
+		$class = "Hi";
+	}
+}
+
+function bar($percent, $class)
+{
+	return <<<EOS
+	<div class="coverBarOutline">
+		<div class="coverBar{$class}" style="width:{$percent}%"></div>
+		<div class="coverPer{$class}">{$percent}</div>
+	</div>
+EOS;
+}
+
+function dir_head()
+{
+	global $cycle;
+	$cycle = new Cycle('class="col1"', 'class="col2"');
+	return <<<EOS
+	<table align="center" cellpadding="2" cellspacing="1" border="0" class="cycles">
+	<tr>
+		<th>Directory</th><th>Percent</th><th>Hits</th><th>Lines</th><th>TODO</th>
+	</tr>
+EOS;
+}
+
+function dir_row($info, $srcdir)
+{
+	global $cycle;
+	if ($info['files'] || $info['todos']) {
+		$c = $cycle->next();
+		$srcdir_html = htmlspecialchars($srcdir);
+		$todos = number_format($info['todos']);
+		if ($info['total']) {
+			$srcdir_url = urlencode($srcdir);
+			$hits  = number_format($info['hits']);
+			$total = number_format($info['total']);
+			calc_percent($info, $percent, $class);
+			$bar = bar($percent, $class);
+			return <<<EOS
+			<tr $c>
+				<td class="coverFile"><a href="?path={$srcdir_url}">{$srcdir_html}</a></td>
+				<td class="coverBar">$bar</td>
+				<td class="coverNum{$class}">{$hits}</td>
+				<td class="coverNum{$class}">{$total}</td>
+				<td class="coverNum{$class}">{$todos}</td>
+			</tr>
+EOS;
+		}
+		else {
+			return <<<EOS
+			<tr $c>
+				<td class="coverFile">{$srcdir_html}</td>
+				<td class="coverBar"></td>
+				<td class="coverNumLo"></td>
+				<td class="coverNumLo"></td>
+				<td class="coverNumLo">{$todos}</td>
+			</tr>
+EOS;
+		}
+	}
+}
+
+function dir_foot()
+{
+	return <<<EOS
+	</table>
+EOS;
+}
+
+function file_head()
+{
+	global $cycle;
+	$cycle = new Cycle('class="col1"', 'class="col2"');
+	return <<<EOS
+	<br>
+	<table align="center" cellpadding="2" cellspacing="1" border="0" class="cycles">
+	<tr>
+		<th>File</th><th>Percent</th><th>Hits</th><th>Lines</th>
+	</tr>
+EOS;
+}
+
+function file_row($info, $srcfile)
+{
+	global $cycle;
+
+	$c = $cycle->next();
+	$srcfile_html = htmlspecialchars($srcfile);
+	$total = number_format($info['total']);
+	if ($info['total']) {
+		$hits = number_format($info['hits']);
+		$srcfile_url = urlencode($srcfile);
+		calc_percent($info, $percent, $class);
+		$bar = bar($percent, $class);
+		return <<<EOS
+			<tr $c>
+					<td class="coverFile"><a href="?path={$srcfile_url}">{$srcfile_html}</a></td>
+					<td class="coverBar">$bar</td>
+					<td class="coverNum{$class}">{$hits}</td>
+					<td class="coverNum{$class}">{$total}</td>
+			</tr>
+EOS;
+	}
+	else {
+		return <<<EOS
+			<tr $c>
+					<td class="coverFile">{$srcfile_html}</a></td>
+					<td class="coverBar"></td>
+					<td class="coverNumLo"></td>
+					<td class="coverNumLo">{$total}</td>
+			</tr>
+EOS;
+	}
+}
+
+function file_foot()
+{
+	return <<<EOS
+    </table>
+EOS;
+}
+
+if ($action == 'dir') {
+	$path_html = htmlspecialchars($path);
+	echo <<<EOS
+	<a href="?">root</a> $path<br />
+EOS;
+	echo dir_head($dirinfo);
+	echo dir_row($dirinfo, $path);
+	echo dir_foot($dirinfo);
+	if ($dirinfo['subdirs']) {
+		echo dir_head();
+		foreach ($dirinfo['subdirs'] as $srcdir => $info) {
+			echo dir_row($info, $srcdir);
+		}
+		echo dir_foot();
+	}
+	if ($dirinfo['files']) {
+		echo file_head();
+		foreach ($dirinfo['files'] as $srcfile => $info) {
+			echo file_row($info, $srcfile);
+		}
+		echo file_foot();
+	}
+}
+else if ($action == 'file') {
+	$dir_url = urlencode($dir);
+	$dir_html = htmlspecialchars($dir);
+	echo <<<EOS
+	<a href="?">root</a> <a href="?path={$dir_url}">{$dir_html}</a>/<b>{$filename}</b><br />
+EOS;
+
+	echo file_head();
+	echo file_row($fileinfo, $path);
+	echo file_foot();
+
+	if ($tplfile) {
+		$tplfile_html = htmlspecialchars($tplfile);
+		echo <<<EOS
+		<a href="#tpl">{$tplfile_html}</a><br />
+EOS;
+	}
+	echo <<<EOS
+	<pre class="code"><ol>{$filecov}</ol></pre>
+EOS;
+	if ($tplfile) {
+		echo <<<EOS
+	<a name="tpl">{$tplfile}</a>
+	<pre class="code"><ol>{$tplcov}</ol></pre>
+EOS;
+	}
+}
+else {
+	echo htmlspecialchars($action);
+}
+?>
+
+</body>
+</html>
Index: /tags/1.0/const_string_opcodes_php4.x.h
===================================================================
--- /tags/1.0/const_string_opcodes_php4.x.h	(revision 1)
+++ /tags/1.0/const_string_opcodes_php4.x.h	(revision 1)
@@ -0,0 +1,116 @@
+/* size = 112 */
+static const char *const xc_opcode_names[] = {
+/* 0 */	"NOP",
+/* 1 */	"ADD",
+/* 2 */	"SUB",
+/* 3 */	"MUL",
+/* 4 */	"DIV",
+/* 5 */	"MOD",
+/* 6 */	"SL",
+/* 7 */	"SR",
+/* 8 */	"CONCAT",
+/* 9 */	"BW_OR",
+/* 10 */	"BW_AND",
+/* 11 */	"BW_XOR",
+/* 12 */	"BW_NOT",
+/* 13 */	"BOOL_NOT",
+/* 14 */	"BOOL_XOR",
+/* 15 */	"IS_IDENTICAL",
+/* 16 */	"IS_NOT_IDENTICAL",
+/* 17 */	"IS_EQUAL",
+/* 18 */	"IS_NOT_EQUAL",
+/* 19 */	"IS_SMALLER",
+/* 20 */	"IS_SMALLER_OR_EQUAL",
+/* 21 */	"CAST",
+/* 22 */	"QM_ASSIGN",
+/* 23 */	"ASSIGN_ADD",
+/* 24 */	"ASSIGN_SUB",
+/* 25 */	"ASSIGN_MUL",
+/* 26 */	"ASSIGN_DIV",
+/* 27 */	"ASSIGN_MOD",
+/* 28 */	"ASSIGN_SL",
+/* 29 */	"ASSIGN_SR",
+/* 30 */	"ASSIGN_CONCAT",
+/* 31 */	"ASSIGN_BW_OR",
+/* 32 */	"ASSIGN_BW_AND",
+/* 33 */	"ASSIGN_BW_XOR",
+/* 34 */	"PRE_INC",
+/* 35 */	"PRE_DEC",
+/* 36 */	"POST_INC",
+/* 37 */	"POST_DEC",
+/* 38 */	"ASSIGN",
+/* 39 */	"ASSIGN_REF",
+/* 40 */	"ECHO",
+/* 41 */	"PRINT",
+/* 42 */	"JMP",
+/* 43 */	"JMPZ",
+/* 44 */	"JMPNZ",
+/* 45 */	"JMPZNZ",
+/* 46 */	"JMPZ_EX",
+/* 47 */	"JMPNZ_EX",
+/* 48 */	"CASE",
+/* 49 */	"SWITCH_FREE",
+/* 50 */	"BRK",
+/* 51 */	"CONT",
+/* 52 */	"BOOL",
+/* 53 */	"INIT_STRING",
+/* 54 */	"ADD_CHAR",
+/* 55 */	"ADD_STRING",
+/* 56 */	"ADD_VAR",
+/* 57 */	"BEGIN_SILENCE",
+/* 58 */	"END_SILENCE",
+/* 59 */	"INIT_FCALL_BY_NAME",
+/* 60 */	"DO_FCALL",
+/* 61 */	"DO_FCALL_BY_NAME",
+/* 62 */	"RETURN",
+/* 63 */	"RECV",
+/* 64 */	"RECV_INIT",
+/* 65 */	"SEND_VAL",
+/* 66 */	"SEND_VAR",
+/* 67 */	"SEND_REF",
+/* 68 */	"NEW",
+/* 69 */	"JMP_NO_CTOR",
+/* 70 */	"FREE",
+/* 71 */	"INIT_ARRAY",
+/* 72 */	"ADD_ARRAY_ELEMENT",
+/* 73 */	"INCLUDE_OR_EVAL",
+/* 74 */	"UNSET_VAR",
+/* 75 */	"UNSET_DIM_OBJ",
+/* 76 */	"ISSET_ISEMPTY",
+/* 77 */	"FE_RESET",
+/* 78 */	"FE_FETCH",
+/* 79 */	"EXIT",
+/* 80 */	"FETCH_R",
+/* 81 */	"FETCH_DIM_R",
+/* 82 */	"FETCH_OBJ_R",
+/* 83 */	"FETCH_W",
+/* 84 */	"FETCH_DIM_W",
+/* 85 */	"FETCH_OBJ_W",
+/* 86 */	"FETCH_RW",
+/* 87 */	"FETCH_DIM_RW",
+/* 88 */	"FETCH_OBJ_RW",
+/* 89 */	"FETCH_IS",
+/* 90 */	"FETCH_DIM_IS",
+/* 91 */	"FETCH_OBJ_IS",
+/* 92 */	"FETCH_FUNC_ARG",
+/* 93 */	"FETCH_DIM_FUNC_ARG",
+/* 94 */	"FETCH_OBJ_FUNC_ARG",
+/* 95 */	"FETCH_UNSET",
+/* 96 */	"FETCH_DIM_UNSET",
+/* 97 */	"FETCH_OBJ_UNSET",
+/* 98 */	"FETCH_DIM_TMP_VAR",
+/* 99 */	"FETCH_CONSTANT",
+/* 100 */	"DECLARE_FUNCTION_OR_CLASS",
+/* 101 */	"EXT_STMT",
+/* 102 */	"EXT_FCALL_BEGIN",
+/* 103 */	"EXT_FCALL_END",
+/* 104 */	"EXT_NOP",
+/* 105 */	"TICKS",
+/* 106 */	"SEND_VAR_NO_REF",
+/* 107 */	"UNDEF",
+/* 108 */	"UNDEF",
+/* 109 */	"UNDEF",
+/* 110 */	"DO_FCALL_BY_FUNC",
+/* 111 */	"INIT_FCALL_BY_FUNC",
+/* 112 */	"UNDEF"
+};
Index: /tags/1.0/processor/dispatch.m4
===================================================================
--- /tags/1.0/processor/dispatch.m4	(revision 1)
+++ /tags/1.0/processor/dispatch.m4	(revision 1)
@@ -0,0 +1,27 @@
+dnl DISPATCH(1:type, 2:elm)
+define(`DISPATCH', `
+	DBG(`$0($*)')
+	ifelse(
+		`$1', `zend_bool',        `PROC_INT(`$2', `u',  `$1')'
+	, `$1', `zend_uchar',       `PROC_INT(`$2', `u',  `$1')'
+	, `$1', `char',             `PROC_INT(`$2', `d',  `$1')'
+	, `$1', `int32_t',          `PROC_INT(`$2', `d',  `$1')'
+	, `$1', `unsigned char',    `PROC_INT(`$2', `u',  `$1')'
+	, `$1', `zend_uint',        `PROC_INT(`$2', `u',  `$1')'
+	, `$1', `uint',             `PROC_INT(`$2', `u',  `$1')'
+	, `$1', `unsigned int',     `PROC_INT(`$2', `u',  `$1')'
+	, `$1', `zend_ulong',       `PROC_INT(`$2', `lu', `$1')'
+	, `$1', `ulong',            `PROC_INT(`$2', `lu', `$1')'
+	, `$1', `size_t',           `PROC_INT(`$2', `u', `$1')'
+	, `$1', `long',             `PROC_INT(`$2', `ld', `$1')'
+	, `$1', `time_t',           `PROC_INT(`$2', `ld', `$1')'
+	, `$1', `zend_ushort',      `PROC_INT(`$2', `hu', `$1')'
+	, `$1', `int',              `PROC_INT(`$2', `d',  `$1')'
+	, `$1', `double',           `PROC_INT(`$2', `f',  `$1')'
+	, `$1', `opcode_handler_t', `/* is copying enough? */COPY(`$2')'
+	, `$1', `zval_data_type',   `PROC_INT(`$2', `u',  `$1')'
+	, `$1', `xc_entry_type_t',  `PROC_INT(`$2', `d',  `$1')'
+	, `$1', `xc_hash_value_t',  `PROC_INT(`$2', `lu', `$1')'
+	, `', `', `m4_errprint(`Unknown type "$1"')'
+	)
+')
Index: /tags/1.0/processor/processor.m4
===================================================================
--- /tags/1.0/processor/processor.m4	(revision 56)
+++ /tags/1.0/processor/processor.m4	(revision 56)
@@ -0,0 +1,723 @@
+dnl ================
+/* {{{ Pre-declare */
+DECL_STRUCT_P_FUNC(`zval')
+DECL_STRUCT_P_FUNC(`zval_ptr')
+DECL_STRUCT_P_FUNC(`zend_op_array')
+DECL_STRUCT_P_FUNC(`zend_class_entry')
+DECL_STRUCT_P_FUNC(`zend_function')
+DECL_STRUCT_P_FUNC(`xc_entry_t')
+#ifdef ZEND_ENGINE_2
+DECL_STRUCT_P_FUNC(`zend_property_info')
+#endif
+/* }}} */
+dnl ====================================================
+dnl {{{ zend_compiled_variable
+#ifdef IS_CV
+DEF_STRUCT_P_FUNC(`zend_compiled_variable', , `
+	DISPATCH(int, name_len)
+	PROC_USTRING_L(, name, name_len)
+	DISPATCH(ulong, hash_value)
+')
+#endif
+dnl }}}
+dnl {{{ zend_uint
+DEF_STRUCT_P_FUNC(`zend_uint', , `
+	IFCOPY(`dst[0] = src[0];')
+	IFDPRINT(`
+		INDENT()
+		fprintf(stderr, "%u\n", src[0]);
+	')
+	DONE_SIZE(sizeof(src[0]))
+')
+dnl }}}
+dnl {{{ int
+#ifndef ZEND_ENGINE_2
+DEF_STRUCT_P_FUNC(`int', , `
+	IFCOPY(`*dst = *src;')
+	IFDPRINT(`
+		INDENT()
+		fprintf(stderr, "%d\n", src[0]);
+	')
+	DONE_SIZE(sizeof(src[0]))
+')
+#endif
+dnl }}}
+dnl {{{ zend_try_catch_element
+#ifdef ZEND_ENGINE_2
+DEF_STRUCT_P_FUNC(`zend_try_catch_element', , `
+	DISPATCH(zend_uint, try_op)
+	DISPATCH(zend_uint, catch_op)
+')
+#endif /* ifdef ZEND_ENGINE_2 */
+dnl }}}
+dnl {{{ zend_brk_cont_element
+DEF_STRUCT_P_FUNC(`zend_brk_cont_element', , `
+	DISPATCH(int, cont)
+	DISPATCH(int, brk)
+	DISPATCH(int, parent)
+')
+dnl }}}
+DEF_HASH_TABLE_FUNC(`HashTable_zval_ptr',           `zval_ptr')
+DEF_HASH_TABLE_FUNC(`HashTable_zend_function',      `zend_function')
+#ifdef ZEND_ENGINE_2
+DEF_HASH_TABLE_FUNC(`HashTable_zend_property_info', `zend_property_info')
+#endif
+DEF_STRUCT_P_FUNC(`zval', , `dnl {{{
+	IFDASM(`do {
+		zval_dtor(dst);
+		*dst = *src;
+		zval_copy_ctor(dst);
+		ZVAL_REFCOUNT(dst) = 1;
+		DONE(value)
+		DONE(refcount)
+		DONE(type)
+		DONE(is_ref)
+	} while(0);
+	return;
+	', `
+		dnl IFDASM else
+		/* Variable information */
+dnl {{{ zvalue_value
+		DISABLECHECK(`
+		switch (src->type & ~IS_CONSTANT_INDEX) {
+			case IS_LONG:
+			case IS_RESOURCE:
+			case IS_BOOL:
+				DISPATCH(long, value.lval)
+				break;
+			case IS_DOUBLE:
+				DISPATCH(double, value.dval)
+				break;
+			case IS_NULL:
+				IFDPRINT(`INDENT()`'fprintf(stderr, "\tNULL\n");')
+				break;
+
+			case IS_CONSTANT:
+#ifdef IS_UNICODE
+				if (UG(unicode)) {
+					goto proc_unicode;
+				}
+#endif
+			case IS_STRING:
+#ifdef FLAG_IS_BC
+			case FLAG_IS_BC:
+#endif
+				DISPATCH(int, value.str.len)
+				PROC_STRING_L(value.str.val, value.str.len)
+				break;
+#ifdef IS_UNICODE
+			case IS_UNICODE:
+proc_unicode:
+				DISPATCH(int32_t, value.ustr.len)
+				PROC_USTRING_L(1, value.ustr.val, value.ustr.len)
+				break;
+#endif
+
+			case IS_ARRAY:
+			case IS_CONSTANT_ARRAY:
+				STRUCT_P(HashTable, value.ht, HashTable_zval_ptr)
+				break;
+
+			case IS_OBJECT:
+				IFNOTMEMCPY(`IFCOPY(`memcpy(dst, src, sizeof(src[0]));')')
+				dnl STRUCT(value.obj)
+#ifndef ZEND_ENGINE_2
+				STRUCT_P(zend_class_entry, value.obj.ce)
+				STRUCT_P(HashTable, value.obj.properties, HashTable_zval_ptr)
+#endif
+				break;
+
+			default:
+				assert(0);
+		}
+		')
+dnl }}}
+		DONE(value)
+		DISPATCH(zval_data_type, type)
+		DISPATCH(zend_uchar, is_ref)
+		DISPATCH(zend_ushort, refcount)
+	')dnl IFDASM
+')
+dnl }}}
+DEF_STRUCT_P_FUNC(`zval_ptr', , `dnl {{{
+	IFDASM(`
+		pushdefFUNC_NAME(`zval')
+		FUNC_NAME (dst, src[0] TSRMLS_CC);
+		popdef(`FUNC_NAME')
+	', `
+		do {
+			IFCALCCOPY(`
+				if (processor->reference) {
+					zval_ptr *ppzv;
+					if (zend_hash_find(&processor->zvalptrs, (char *)src[0], sizeof(src[0]), (void**)&ppzv) == SUCCESS) {
+						IFCOPY(`
+							dst[0] = *ppzv;
+							/* *dst is updated */
+							dnl fprintf(stderr, "*dst is set to %p\n", dst[0]);
+						')
+						IFSTORE(`assert(xc_is_shm(dst[0]));')
+						IFRESTORE(`assert(!xc_is_shm(dst[0]));')
+						break;
+					}
+				}
+			')
+			
+			ALLOC(dst[0], zval)
+			IFCALCCOPY(`
+				if (processor->reference) {
+					IFCALC(`
+						/* make dummy */
+						zval_ptr pzv = (zval_ptr)-1;
+					', `
+						zval_ptr pzv = dst[0];
+					')
+					if (zend_hash_add(&processor->zvalptrs, (char *)src[0], sizeof(src[0]), (void*)&pzv, sizeof(pzv), NULL) == SUCCESS) {
+						/* first add, go on */
+						dnl fprintf(stderr, "mark[%p] = %p\n", src[0], pzv);
+					}
+					else {
+						assert(0);
+					}
+				}
+			')
+			IFCOPY(`
+				dnl fprintf(stderr, "copy from %p to %p\n", src[0], dst[0]);
+			')
+			STRUCT_P_EX(zval, dst[0], src[0], `[0]', `', ` ')
+		} while (0);
+	')
+	DONE_SIZE(sizeof(zval_ptr))
+')
+dnl }}}
+dnl {{{ zend_arg_info
+#ifdef ZEND_ENGINE_2
+DEF_STRUCT_P_FUNC(`zend_arg_info', , `
+	DISPATCH(zend_uint, name_len)
+	PROC_USTRING_L(, name, name_len)
+	DISPATCH(zend_uint, class_name_len)
+	PROC_USTRING_L(, class_name, class_name_len)
+	DISPATCH(zend_bool, array_type_hint)
+	DISPATCH(zend_bool, allow_null)
+	DISPATCH(zend_bool, pass_by_reference)
+	DISPATCH(zend_bool, return_reference)
+	DISPATCH(int, required_num_args)
+')
+#endif
+dnl }}}
+DEF_STRUCT_P_FUNC(`zend_function', , `dnl {{{
+	DISABLECHECK(`
+	switch (src->type) {
+	case ZEND_INTERNAL_FUNCTION:
+	case ZEND_OVERLOADED_FUNCTION:
+		IFNOTMEMCPY(`IFCOPY(`memcpy(dst, src, sizeof(src[0]));')')
+		break;
+
+	case ZEND_USER_FUNCTION:
+	case ZEND_EVAL_CODE:
+		DONE(type)
+		STRUCT(zend_op_array, op_array)
+		break;
+
+	default:
+		assert(0);
+	}
+	')
+	DONE_SIZE(sizeof(src[0]))
+')
+dnl }}}
+dnl {{{ zend_property_info
+#ifdef ZEND_ENGINE_2
+DEF_STRUCT_P_FUNC(`zend_property_info', , `
+	DISPATCH(zend_uint, flags)
+	DISPATCH(int, name_length)
+	PROC_USTRING_L(, name, name_length)
+	DISPATCH(ulong, h)
+#ifdef ZEND_ENGINE_2_1
+	DISPATCH(int, doc_comment_len)
+	PROC_USTRING_L(, doc_comment, doc_comment_len)
+#endif
+')
+#endif
+dnl }}}
+DEF_STRUCT_P_FUNC(`zend_class_entry', , `dnl {{{
+	IFCOPY(`
+		processor->active_class_entry_src = src;
+		processor->active_class_entry_dst = dst;
+	')
+	DISPATCH(char, type)
+	DISPATCH(zend_uint, name_length)
+	PROC_USTRING_L(, name, name_length)
+	IFRESTORE(`
+#ifndef ZEND_ENGINE_2
+		/* just copy parent and resolve on install_class */
+		COPY(parent)
+#else
+		PROC_CLASS_ENTRY_P(parent)
+#endif
+	', `
+		PROC_CLASS_ENTRY_P(parent)
+	')
+#ifdef ZEND_ENGINE_2
+	DISPATCH(int, refcount)
+#else
+	STRUCT_P(int, refcount)
+#endif
+	DISPATCH(zend_bool, constants_updated)
+#ifdef ZEND_ENGINE_2
+	DISPATCH(zend_uint, ce_flags)
+#endif
+
+	STRUCT(HashTable, default_properties, HashTable_zval_ptr)
+	IFCOPY(`dst->builtin_functions = src->builtin_functions;')
+	DONE(builtin_functions)
+#ifdef ZEND_ENGINE_2
+	STRUCT(HashTable, properties_info, HashTable_zend_property_info)
+#	ifdef ZEND_ENGINE_2_1
+	STRUCT(HashTable, default_static_members, HashTable_zval_ptr)
+	IFCOPY(`dst->static_members = &dst->default_static_members;')
+	DONE(static_members)
+#	else
+	STRUCT_P(HashTable, static_members, HashTable_zval_ptr)
+#	endif
+	STRUCT(HashTable, constants_table, HashTable_zval_ptr)
+
+	dnl runtime binding: ADD_INTERFACE will deal with it
+	IFRESTORE(`
+		if (src->num_interfaces) {
+			CALLOC(dst->interfaces, zend_class_entry*, src->num_interfaces)
+			DONE(`interfaces')
+		}
+		else {
+			COPYNULL(interfaces)
+		}
+	')
+	IFDASM(`
+		if (src->num_interfaces) {
+			/*
+			zval *arr;
+			ALLOC_INIT_ZVAL(arr);
+			array_init(arr);
+			for (i = 0; i < src->num_interfaces; i ++) {
+				zval *zv;
+				ALLOC_INIT_ZVAL(zv);
+				ZVAL_STRING(src->num_interfaces);
+			}
+			add_assoc_zval_ex(dst, ZEND_STRS("interfaces"), arr);
+			*/
+			DONE(`interfaces')
+		}
+		else {
+			COPYNULL(interfaces)
+		}
+	')
+	IFRESTORE(`', `
+		IFDASM(`', `
+			DONE(`interfaces')
+		')
+	')
+	DISPATCH(zend_uint, num_interfaces)
+
+	IFRESTORE(`COPY(filename)', `PROC_STRING(filename)')
+	DISPATCH(zend_uint, line_start)
+	DISPATCH(zend_uint, line_end)
+#ifdef ZEND_ENGINE_2_1
+	DISPATCH(zend_uint, doc_comment_len)
+	PROC_USTRING_L(, doc_comment, doc_comment_len)
+#endif
+	/* # NOT DONE */
+	COPY(serialize_func)
+	COPY(unserialize_func)
+	COPY(iterator_funcs)
+	COPY(create_object)
+	COPY(get_iterator)
+	COPY(interface_gets_implemented)
+	COPY(serialize)
+	COPY(unserialize)
+	/* deal with it inside xc_fix_method */
+	SETNULL(constructor)
+	COPY(destructor)
+	COPY(clone)
+	COPY(__get)
+	COPY(__set)
+/* should be >5.1 */
+#ifdef ZEND_ENGINE_2_1
+	COPY(__unset)
+	COPY(__isset)
+# if PHP_MAJOR_VERSION >= 6
+	COPY(__tostring)
+# endif
+#endif
+	COPY(__call)
+#ifdef IS_UNICODE
+	SETNULL(u_twin)
+#endif
+	/* # NOT DONE */
+	COPY(module)
+#else
+	COPY(handle_function_call)
+	COPY(handle_property_get)
+	COPY(handle_property_set)
+#endif
+	dnl must after SETNULL(constructor)
+	STRUCT(HashTable, function_table, HashTable_zend_function)
+	IFRESTORE(`dst->function_table.pDestructor = (dtor_func_t) destroy_zend_function;')
+')
+dnl }}}
+DEF_STRUCT_P_FUNC(`znode', , `dnl {{{
+	DISPATCH(int, op_type)
+
+#ifdef IS_CV
+#	define XCACHE_IS_CV IS_CV
+#else
+/* compatible with zend optimizer */
+#	define XCACHE_IS_CV 16
+#endif
+	assert(src->op_type == IS_CONST ||
+		src->op_type == IS_VAR ||
+		src->op_type == XCACHE_IS_CV ||
+		src->op_type == IS_TMP_VAR ||
+		src->op_type == IS_UNUSED);
+#undef XCACHE_IS_CV
+	dnl dirty dispatch
+	DISABLECHECK(`
+	switch (src->op_type) {
+		case IS_CONST:
+			STRUCT(zval, u.constant)
+			break;
+		IFCOPY(`
+			IFNOTMEMCPY(`
+				default:
+					memcpy(&dst->u, &src->u, sizeof(src->u));
+			')
+		', `
+		case IS_VAR:
+		case IS_TMP_VAR:
+#ifdef IS_CV
+		case IS_CV:
+#else
+		case 16:
+#endif
+			DISPATCH(zend_uint, u.var)
+			DISPATCH(zend_uint, u.EA.type)
+			break;
+		case IS_UNUSED:
+			IFDASM(`DISPATCH(zend_uint, u.var)')
+			DISPATCH(zend_uint, u.opline_num)
+#ifndef ZEND_ENGINE_2
+			DISPATCH(zend_uint, u.fetch_type)
+#endif
+			DISPATCH(zend_uint, u.EA.type)
+			break;
+		')
+	}
+	')
+	DONE(u)
+')
+dnl }}}
+DEF_STRUCT_P_FUNC(`zend_op', , `dnl {{{
+	DISPATCH(zend_uchar, opcode)
+	STRUCT(znode, result)
+	STRUCT(znode, op1)
+	STRUCT(znode, op2)
+	DISPATCH(ulong, extended_value)
+	DISPATCH(uint, lineno)
+#ifdef ZEND_ENGINE_2_1
+	IFCOPY(`
+		switch (src->opcode) {
+			case ZEND_JMP:
+				dst->op1.u.jmp_addr = processor->active_opcodes_dst + (src->op1.u.jmp_addr - processor->active_opcodes_src);
+				break;
+
+			case ZEND_JMPZ:
+			case ZEND_JMPNZ:
+			case ZEND_JMPZ_EX:
+			case ZEND_JMPNZ_EX:
+				dst->op2.u.jmp_addr = processor->active_opcodes_dst + (src->op2.u.jmp_addr - processor->active_opcodes_src);
+				break;
+
+			default:
+				break;
+		}
+	')
+	DISPATCH(opcode_handler_t, handler)
+#endif
+')
+dnl }}}
+DEF_STRUCT_P_FUNC(`zend_op_array', , `dnl {{{
+	IFRESTORE(`
+	if (!processor->readonly_protection) {
+		/* really fast shallow copy */
+		memcpy(dst, src, sizeof(src[0]));
+		dst->refcount[0] = 1000;
+		/* deep */
+		STRUCT_P(HashTable, static_variables, HashTable_zval_ptr)
+		define(`SKIPASSERT_ONCE')
+
+	IFRESTORE(`
+#ifdef ZEND_ENGINE_2
+		if (dst->scope) {
+			dst->scope = xc_get_class(processor, (int) dst->scope);
+			xc_fix_method(processor, dst);
+		}
+#endif
+	')
+
+	}
+	else
+	')
+	do {
+	dnl RESTORE is done above!
+	zend_uint ii;
+	int i;
+
+	/* Common elements */
+	DISPATCH(zend_uchar, type)
+	PROC_USTRING(, function_name)
+#ifdef ZEND_ENGINE_2
+	IFRESTORE(`
+		if (dst->scope) {
+			dst->scope = xc_get_class(processor, (int) dst->scope);
+			xc_fix_method(processor, dst);
+		}
+		DONE(scope)
+	', `
+		PROC_CLASS_ENTRY_P(scope)
+	')
+	DISPATCH(zend_uint, fn_flags)
+	/* useless */
+	COPY(prototype)
+	STRUCT_ARRAY_I(num_args, zend_arg_info, arg_info)
+	DISPATCH(zend_uint, num_args)
+	DISPATCH(zend_uint, required_num_args)
+	DISPATCH(zend_bool, pass_rest_by_reference)
+#else
+	if (src->arg_types) {
+		ALLOC(dst->arg_types, zend_uchar, src->arg_types[0] + 1)
+		IFCOPY(`memcpy(dst->arg_types, src->arg_types, sizeof(src->arg_types[0]) * (src->arg_types[0]+1));')
+		IFDASM(`do {
+			zend_uint ii;
+			int i;
+			zval *zv;
+			ALLOC_INIT_ZVAL(zv);
+			array_init(zv);
+			for (i = 0; i < src->arg_types[0]; i ++) {
+				add_next_index_long(zv, src->arg_types[i + 1]);
+			}
+			add_assoc_zval_ex(dst, ZEND_STRS("arg_types"), zv);
+		} while (0);')
+		DONE(arg_types)
+	}
+	else {
+		IFDASM(`do {
+			/* empty array */
+			zval *zv;
+			ALLOC_INIT_ZVAL(zv);
+			array_init(zv);
+			add_assoc_zval_ex(dst, ZEND_STRS("arg_types"), zv);
+		} while (0);
+		DONE(arg_types)
+		', `
+		COPYNULL(arg_types)
+		')
+	}
+#endif
+	DISPATCH(unsigned char, return_reference)
+	/* END of common elements */
+#ifdef IS_UNICODE
+	SETNULL(u_twin)
+#endif
+
+	STRUCT_P(zend_uint, refcount)
+	UNFIXPOINTER(zend_uint, refcount)
+
+	pushdef(`AFTER_ALLOC', `IFCOPY(`
+		processor->active_opcodes_dst = dst->opcodes;
+		processor->active_opcodes_src = src->opcodes;
+	')')
+	STRUCT_ARRAY_I(last, zend_op, opcodes)
+	popdef(`AFTER_ALLOC')
+	DISPATCH(zend_uint, last)
+	IFCOPY(`dst->size = src->last;DONE(size)', `DISPATCH(zend_uint, size)')
+
+#ifdef IS_CV
+	STRUCT_ARRAY(last_var, zend_compiled_variable, vars)
+	DISPATCH(int, last_var)
+	IFCOPY(`dst->size_var = src->last_var;DONE(size_var)', `DISPATCH(zend_uint, size_var)')
+#else
+	dnl zend_cv.m4 is illegal to be made public, don not ask me for it
+	IFDASM(`
+		sinclude(srcdir`/processor/zend_cv.m4')
+		')
+#endif
+
+	DISPATCH(zend_uint, T)
+
+	STRUCT_ARRAY_I(last_brk_cont, zend_brk_cont_element, brk_cont_array)
+	DISPATCH(zend_uint, last_brk_cont)
+	DISPATCH(zend_uint, current_brk_cont)
+#ifndef ZEND_ENGINE_2
+	DISPATCH(zend_bool, uses_globals)
+#endif
+
+#ifdef ZEND_ENGINE_2
+	STRUCT_ARRAY(last_try_catch, zend_try_catch_element, try_catch_array)
+	DISPATCH(int, last_try_catch)
+#endif
+
+	STRUCT_P(HashTable, static_variables, HashTable_zval_ptr)
+
+	IFCOPY(`dst->start_op = src->start_op;')
+	DONE(start_op)
+	DISPATCH(int, backpatch_count)
+
+	DISPATCH(zend_bool, done_pass_two)
+#ifdef ZEND_ENGINE_2
+	DISPATCH(zend_bool, uses_this)
+#endif
+
+	IFRESTORE(`COPY(filename)', `PROC_STRING(filename)')
+#ifdef IS_UNICODE
+	PROC_STRING(script_encoding)
+#endif
+#ifdef ZEND_ENGINE_2
+	DISPATCH(zend_uint, line_start)
+	DISPATCH(zend_uint, line_end)
+	DISPATCH(int, doc_comment_len)
+	PROC_USTRING_L(, doc_comment, doc_comment_len)
+#endif
+
+	/* reserved */
+	DONE(reserved)
+#if defined(HARDENING_PATCH) && HARDENING_PATCH
+	DISPATCH(zend_bool, created_by_eval)
+#endif
+	} while (0);
+')
+dnl }}}
+
+DEF_STRUCT_P_FUNC(`xc_funcinfo_t', , `dnl {{{
+	DISPATCH(zend_uint, key_size)
+#ifdef IS_UNICODE
+	DISPATCH(zend_uchar, type)
+#endif
+	IFRESTORE(`COPY(key)', `
+		PROC_USTRING_N(type, key, key_size)
+	')
+	STRUCT(zend_function, func)
+')
+dnl }}}
+DEF_STRUCT_P_FUNC(`xc_classinfo_t', , `dnl {{{
+	DISPATCH(zend_uint, key_size)
+#ifdef IS_UNICODE
+	DISPATCH(zend_uchar, type)
+#endif
+	IFRESTORE(`COPY(key)', `
+		PROC_USTRING_N(type, key, key_size)
+	')
+#ifdef ZEND_ENGINE_2
+	STRUCT_P(zend_class_entry, cest)
+#else
+	STRUCT(zend_class_entry, cest)
+#endif
+')
+dnl }}}
+DEF_STRUCT_P_FUNC(`xc_entry_data_php_t', , `dnl {{{
+	zend_uint i;
+
+#ifdef HAVE_INODE
+	DISPATCH(int, device)
+	DISPATCH(int, inode)
+#endif
+	DISPATCH(size_t, sourcesize)
+
+	DISPATCH(time_t, mtime)
+
+	STRUCT_P(zend_op_array, op_array)
+
+	DISPATCH(zend_uint, funcinfo_cnt)
+	STRUCT_ARRAY(funcinfo_cnt, xc_funcinfo_t, funcinfos)
+
+	DISPATCH(zend_uint, classinfo_cnt)
+	pushdef(`BEFORE_LOOP', `
+		IFCOPY(`
+			processor->active_class_num = i + 1;
+		')
+	')
+	STRUCT_ARRAY(classinfo_cnt, xc_classinfo_t, classinfos)
+	popdef(`BEFORE_LOOP')
+')
+dnl }}}
+DEF_STRUCT_P_FUNC(`xc_entry_data_var_t', , `dnl {{{
+	DISPATCH(time_t, etime)
+	IFSTORE(`
+		if (processor->reference) {
+			if (zend_hash_add(&processor->zvalptrs, (char *)&src->value, sizeof(&src->value), (void*)&src->value, sizeof(src->value), NULL) == SUCCESS) {
+				dnl fprintf(stderr, "mark[%p] = %p\n", &src->value, &dst->value);
+			}
+			else {
+				assert(0);
+			}
+		}
+	')
+	STRUCT_P_EX(zval_ptr, dst->value, src->value, `value', `', `&')
+	DONE(value)
+')
+dnl }}}
+dnl {{{ xc_entry_t
+DEF_STRUCT_P_FUNC(`xc_entry_t', , `
+	IFCOPY(`
+		processor->xce_dst = dst;
+		processor->xce_src = src;
+	')
+	DISPATCH(xc_entry_type_t, type)
+	DISPATCH(size_t, size)
+
+	DISPATCH(xc_hash_value_t, hvalue)
+	COPY(cache)
+	/* skip */
+	DONE(next)
+
+	IFSTORE(`dst->refcount = 0; DONE(refcount)', `DISPATCH(long, refcount)')
+
+	DISPATCH(time_t, ctime)
+	DISPATCH(time_t, atime)
+	DISPATCH(time_t, dtime)
+	DISPATCH(zend_ulong, hits)
+#ifdef IS_UNICODE
+	DISPATCH(zend_uchar, name_type)
+#endif
+	dnl {{{ name
+	DISABLECHECK(`
+#ifdef IS_UNICODE
+		if (src->name_type == IS_UNICODE) {
+			DISPATCH(int32_t, name.ustr.len)
+		}
+		else {
+			DISPATCH(int, name.str.len)
+		}
+#else
+		DISPATCH(int, name.str.len)
+#endif
+		IFRESTORE(`COPY(name.str.val)', `PROC_USTRING_L(name_type, name.str.val, name.str.len)')
+	')
+	DONE(name)
+	dnl }}}
+
+	dnl {{{ data
+	DISABLECHECK(`
+		switch (src->type) {
+		case XC_TYPE_PHP:
+			STRUCT_P(xc_entry_data_php_t, data.php)
+			break;
+		case XC_TYPE_VAR:
+			STRUCT_P(xc_entry_data_var_t, data.var)
+			break;
+		default:
+			assert(0);
+		}
+	')
+	DONE(data)
+	dnl }}}
+')
+dnl }}}
+dnl ====================================================
Index: /tags/1.0/processor/head.m4
===================================================================
--- /tags/1.0/processor/head.m4	(revision 58)
+++ /tags/1.0/processor/head.m4	(revision 58)
@@ -0,0 +1,322 @@
+dnl {{{ === program start ========================================
+divert(0)
+#include <string.h>
+#include <stdio.h>
+
+#include "php.h"
+#include "zend_compile.h"
+#include "zend_API.h"
+#include "zend_ini.h"
+
+#include "xcache.h"
+#include "align.h"
+#include "const_string.h"
+#include "processor.h"
+#include "stack.h"
+#include "xcache_globals.h"
+
+#if defined(HARDENING_PATCH_HASH_PROTECT) && HARDENING_PATCH_HASH_PROTECT
+extern unsigned int zend_hash_canary;
+#endif
+
+define(`SIZEOF_zend_uint', `sizeof(zend_uint)')
+define(`COUNTOF_zend_uint', `1')
+define(`SIZEOF_int', `sizeof(int)')
+define(`COUNTOF_int', `1')
+define(`SIZEOF_zend_function', `sizeof(zend_function)')
+define(`COUNTOF_zend_function', `1')
+define(`SIZEOF_zval_ptr', `sizeof(zval_ptr)')
+define(`COUNTOF_zval_ptr', `1')
+define(`SIZEOF_xc_entry_name_t', `sizeof(xc_entry_name_t)')
+define(`COUNTOF_xc_entry_name_t', `1')
+
+ifdef(`XCACHE_ENABLE_TEST', `
+#undef NDEBUG
+#include <assert.h>
+m4_errprint(`AUTOCHECK INFO: runtime autocheck Enabled (debug build)')
+', `
+m4_errprint(`AUTOCHECK INFO: runtime autocheck Disabled (optimized build)')
+')
+sinclude(builddir`/structinfo.m4')
+
+#ifndef NDEBUG
+#	undef inline
+#define inline
+#endif
+
+typedef zval *zval_ptr;
+typedef zend_uchar zval_data_type;
+
+#define MAX_DUP_STR_LEN 256
+dnl }}}
+/* export: typedef struct _processor_t processor_t; :export {{{ */
+struct _processor_t {
+	char *p;
+	zend_uint size;
+	HashTable strings;
+	HashTable zvalptrs;
+	zend_bool reference; /* enable if to deal with reference */
+	const xc_entry_t *xce_src;
+	const xc_entry_t *xce_dst;
+	const zend_class_entry *cache_ce;
+	zend_uint cache_class_num;
+
+	const zend_op          *active_opcodes_src;
+	zend_op                *active_opcodes_dst;
+	const zend_class_entry *active_class_entry_src;
+	zend_class_entry       *active_class_entry_dst;
+	zend_uint               active_class_num;
+
+	zend_bool readonly_protection; /* wheather it's present */
+IFASSERT(xc_stack_t allocsizes;)
+};
+/* }}} */
+#ifdef XCACHE_HAVE_DPRINT
+static void xc_dprint_indent(int indent) /* {{{ */
+{
+	int i;
+	for (i = 0; i < indent; i ++) {
+		fprintf(stderr, "  ");
+	}
+}
+#endif
+/* }}} */
+/* {{{ xc_calc_string_n */
+REDEF(`KIND', `calc')
+static inline void xc_calc_string_n(processor_t *processor, zend_uchar type, char *str, long size IFASSERT(`, int relayline')) {
+	pushdef(`__LINE__', `relayline')
+	int realsize = UNISW(size, (type == IS_UNICODE) ? UBYTES(size) : size);
+
+	if (realsize > MAX_DUP_STR_LEN) {
+		ALLOC(, char, realsize)
+	}
+	else if (zend_u_hash_add(&processor->strings, type, str, size, (void*)&str, sizeof(char*), NULL) == SUCCESS) {
+		/* new string */
+		ALLOC(, char, realsize)
+	} 
+	IFASSERT(`
+		else {
+			dnl fprintf(stderr, "dupstr %s\n", str);
+		}
+	')
+	popdef(`__LINE__')
+}
+/* }}} */
+/* {{{ xc_store_string_n */
+REDEF(`KIND', `store')
+static inline char *xc_store_string_n(processor_t *processor, zend_uchar type, char *str, long size IFASSERT(`, int relayline')) {
+	pushdef(`__LINE__', `relayline')
+	int realsize = UNISW(size, (type == IS_UNICODE) ? UBYTES(size) : size);
+	char *s;
+
+	if (realsize > MAX_DUP_STR_LEN) {
+		ALLOC(s, char, realsize)
+		memcpy(s, str, realsize);
+	}
+	else if (zend_u_hash_find(&processor->strings, type, str, size, (void*)&s) != SUCCESS) {
+		/* new string */
+		ALLOC(s, char, realsize)
+		memcpy(s, str, realsize);
+		zend_u_hash_add(&processor->strings, type, str, size, (void*)&s, sizeof(char*), NULL);
+	}
+	else {
+		s = *(char**)s;
+	}
+	return s;
+	popdef(`__LINE__')
+}
+/* }}} */
+/* {{{ xc_get_class_num
+ * return class_index + 1
+ */
+static zend_uint xc_get_class_num(processor_t *processor, zend_class_entry *ce) {
+	zend_uint i;
+	const xc_entry_t *xce = processor->xce_src;
+	zend_class_entry *ceptr;
+
+	if (processor->cache_ce == ce) {
+		return processor->cache_class_num;
+	}
+	for (i = 0; i < xce->data.php->classinfo_cnt; i ++) {
+		ceptr = CestToCePtr(xce->data.php->classinfos[i].cest);
+		if (ZCEP_REFCOUNT_PTR(ceptr) == ZCEP_REFCOUNT_PTR(ce)) {
+			processor->cache_ce = ceptr;
+			processor->cache_class_num = i + 1;
+			return i + 1;
+		}
+	}
+	assert(0);
+	return (zend_uint) -1;
+}
+/* }}} */
+/* {{{ xc_get_class */
+#ifdef ZEND_ENGINE_2
+static zend_class_entry *xc_get_class(processor_t *processor, zend_uint class_num) {
+	/* must be parent or currrent class */
+	assert(class_num <= processor->active_class_num);
+	return CestToCePtr(processor->xce_dst->data.php->classinfos[class_num - 1].cest);
+}
+#endif
+/* }}} */
+#ifdef ZEND_ENGINE_2
+/* fix method on store */
+static void xc_fix_method(processor_t *processor, zend_op_array *dst) /* {{{ */
+{
+	zend_function *zf = (zend_function *) dst;
+	zend_class_entry *ce = processor->active_class_entry_dst;
+
+	/* Fixing up the default functions for objects here since
+	 * we need to compare with the newly allocated functions
+	 *
+	 * caveat: a sub-class method can have the same name as the
+	 * parent~s constructor and create problems.
+	 */
+
+	if (zf->common.fn_flags & ZEND_ACC_CTOR) {
+		if (!ce->constructor) {
+			ce->constructor = zf;
+		}
+	}
+	else if (zf->common.fn_flags & ZEND_ACC_DTOR) {
+		ce->destructor = zf;
+	}
+	else if (zf->common.fn_flags & ZEND_ACC_CLONE) {
+		ce->clone = zf;
+	}
+	else {
+#define SET_IF_SAME_NAME(member) \
+		do { \
+			if(!strcasecmp(zf->common.function_name, #member)) { \
+				ce->member = zf; \
+			} \
+		} \
+		while(0)
+		/* if(ce->member && !strcmp(zf->common.function_name, ce->member->common.function_name)) { \ */
+
+		SET_IF_SAME_NAME(__get);
+		SET_IF_SAME_NAME(__set);
+#ifdef ZEND_ENGINE_2_1
+		SET_IF_SAME_NAME(__unset);
+		SET_IF_SAME_NAME(__isset);
+#endif
+		SET_IF_SAME_NAME(__call);
+#if PHP_MAJOR_VERSION >= 6
+		SET_IF_SAME_NAME(__tostring);
+#endif
+
+#undef SET_IF_SAME_NAME
+	}
+}
+/* }}} */
+#endif
+dnl ================ export API
+/* export: xc_entry_t *xc_processor_store_xc_entry_t(xc_entry_t *src TSRMLS_DC); :export {{{ */
+xc_entry_t *xc_processor_store_xc_entry_t(xc_entry_t *src TSRMLS_DC) {
+	xc_entry_t *dst;
+	processor_t processor;
+
+	memset(&processor, 0, sizeof(processor));
+	if (src->type == XC_TYPE_VAR) {
+		processor.reference = 1;
+	}
+
+	IFASSERT(`xc_stack_init(&processor.allocsizes);')
+
+	/* calc size */ {
+		zend_hash_init(&processor.strings, 0, NULL, NULL, 0);
+		if (processor.reference) {
+			zend_hash_init(&processor.zvalptrs, 0, NULL, NULL, 0);
+		}
+
+		processor.size = 0;
+		/* allocate */
+		processor.size = ALIGN(processor.size + sizeof(src[0]));
+
+		xc_calc_xc_entry_t(&processor, src TSRMLS_CC);
+		if (processor.reference) {
+			zend_hash_destroy(&processor.zvalptrs);
+		}
+		zend_hash_destroy(&processor.strings);
+	}
+	src->size = processor.size;
+
+	IFASSERT(`xc_stack_reverse(&processor.allocsizes);')
+	/* store {{{ */
+	{
+		IFASSERT(`char *oldp;')
+		zend_hash_init(&processor.strings, 0, NULL, NULL, 0);
+		if (processor.reference) {
+			zend_hash_init(&processor.zvalptrs, 0, NULL, NULL, 0);
+		}
+
+		/* mem :) */
+		processor.p = (char *)xc_mem_malloc(src->cache->mem, processor.size);
+		if (processor.p == NULL) {
+			dst = NULL;
+			goto err_alloc;
+			return NULL;
+		}
+		IFASSERT(`oldp = processor.p;')
+		assert(processor.p == (char *) ALIGN(processor.p));
+
+		/* allocate */
+		dst = (xc_entry_t *) processor.p;
+		processor.p = (char *) ALIGN(processor.p + sizeof(dst[0]));
+
+		xc_store_xc_entry_t(&processor, dst, src TSRMLS_CC);
+		IFASSERT(` {
+			int real = processor.p - oldp;
+			int should = processor.size;
+			if (real != processor.size) {
+				fprintf(stderr, "real %d - should %d = %d\n", real, should, real - should);
+				abort();
+			}
+		}')
+err_alloc:
+		if (processor.reference) {
+			zend_hash_destroy(&processor.zvalptrs);
+		}
+		zend_hash_destroy(&processor.strings);
+	}
+	/* }}} */
+
+	IFASSERT(`xc_stack_destroy(&processor.allocsizes);')
+
+	return dst;
+}
+/* }}} */
+/* export: xc_entry_t *xc_processor_restore_xc_entry_t(xc_entry_t *dst, const xc_entry_t *src, zend_bool readonly_protection TSRMLS_DC); :export {{{ */
+xc_entry_t *xc_processor_restore_xc_entry_t(xc_entry_t *dst, const xc_entry_t *src, zend_bool readonly_protection TSRMLS_DC) {
+	processor_t processor;
+
+	memset(&processor, 0, sizeof(processor));
+	processor.readonly_protection = readonly_protection;
+
+	xc_restore_xc_entry_t(&processor, dst, src TSRMLS_CC);
+	return dst;
+}
+/* }}} */
+/* export: zval *xc_processor_restore_zval(zval *dst, const zval *src TSRMLS_DC); :export {{{ */
+zval *xc_processor_restore_zval(zval *dst, const zval *src TSRMLS_DC) {
+	processor_t processor;
+
+	memset(&processor, 0, sizeof(processor));
+	processor.reference = 1;
+
+	zend_hash_init(&processor.zvalptrs, 0, NULL, NULL, 0);
+	dnl fprintf(stderr, "mark[%p] = %p\n", src, dst);
+	zend_hash_add(&processor.zvalptrs, (char *)src, sizeof(src), (void*)&dst, sizeof(dst), NULL);
+	xc_restore_zval(&processor, dst, src TSRMLS_CC);
+	zend_hash_destroy(&processor.zvalptrs);
+
+	return dst;
+}
+/* }}} */
+/* export: void xc_dprint(xc_entry_t *src, int indent TSRMLS_DC); :export {{{ */
+#ifdef XCACHE_HAVE_DPRINT
+void xc_dprint(xc_entry_t *src, int indent TSRMLS_DC) {
+	IFDPRINT(`INDENT()`'fprintf(stderr, "xc_entry_t:src");')
+	xc_dprint_xc_entry_t(src, indent TSRMLS_CC);
+}
+#endif
+/* }}} */
Index: /tags/1.0/processor/main.m4
===================================================================
--- /tags/1.0/processor/main.m4	(revision 12)
+++ /tags/1.0/processor/main.m4	(revision 12)
@@ -0,0 +1,237 @@
+divert(-1)
+dnl ================ start ======================
+dnl define(`XCACHE_ENABLE_TEST')
+define(`USEMEMCPY')
+
+dnl ================ main
+
+dnl {{{ basic
+define(`REDEF', `undefine(`$1') define(`$1', `$2')')
+define(`ONCE', `ifdef(`ONCE $1', `', `define(`ONCE $1')$1')')
+define(`m4_errprint', `ONCE(`errprint(`$1
+')')')
+dnl ============
+define(`INDENT', `xc_dprint_indent(indent);')
+dnl }}}
+dnl {{{ ALLOC(1:dst, 2:type, 3:count=1, 4:clean=false, 5:forcetype=$2)
+define(`ALLOC', `
+	pushdef(`COUNT', `ifelse(`$3', `', `1', `$3')')
+	pushdef(`SIZE', `sizeof($2)ifelse(`$3', `', `', ` * $3')')
+	pushdef(`FORCETYPE', `ifelse(`$5', , `$2', `$5')')
+	/* allocate */
+	IFCALC(`
+		IFASSERT(`
+			xc_stack_push(&processor->allocsizes, (void*)(SIZE));
+			xc_stack_push(&processor->allocsizes, (void*)(__LINE__));
+		')
+		processor->size = (size_t) ALIGN(processor->size);
+		processor->size += SIZE;
+	')
+	IFSTORE(`
+		IFASSERT(`{
+			if (!xc_stack_size(&processor->allocsizes)) {
+				fprintf(stderr, "mismatch `$@' at line %d\n", __LINE__);
+			}
+			else {
+				int expect = (int)xc_stack_pop(&processor->allocsizes);
+				int atline = (int)xc_stack_pop(&processor->allocsizes);
+				int real = SIZE;
+				if (expect != real) {
+					fprintf(stderr, "mismatch `$@' at line %d(was %d): real %d - expect %d = %d\n", __LINE__, atline, real, expect, real - expect);
+				}
+			}
+		}')
+		$1 = (FORCETYPE *) (processor->p = (char *) ALIGN(processor->p));
+		ifelse(`$4', `', `
+				IFASSERT(`memset($1, -1, SIZE);')
+			', `
+				memset($1, 0, SIZE);
+		')
+		processor->p += SIZE;
+	')
+	IFRESTORE(`ifelse(`$4', `', `
+			ifelse(
+				FORCETYPE*COUNT, `zval*1', `ALLOC_ZVAL($1);',
+				FORCETYPE*COUNT, `HashTable*1', `ALLOC_HASHTABLE($1);',
+				`', `', `$1 = (FORCETYPE *) emalloc(SIZE);')
+			IFASSERT(`memset($1, -1, SIZE);')
+		', `
+			$1 = (FORCETYPE *) ecalloc(COUNT, sizeof($2));
+		')
+	')
+	popdef(`COUNT')
+	popdef(`SIZE')
+')
+dnl CALLOC(1:dst, 2:type [, 3:count=1 ])
+define(`CALLOC', `ALLOC(`$1', `$2', `$3', `1')')
+dnl }}}
+dnl {{{ PROC_INT(1:elm, 2:format=%d, 3:type=, 4:spec=)
+define(`PROC_INT', `
+	IFNOTMEMCPY(`IFCOPY(`dst->$1 = src->$1;')')
+	IFDPRINT(`
+		INDENT()
+		ifelse(
+			`$3 $1', `zval_data_type type', `fprintf(stderr, "$3:$1:\t%d %s\n", src->$1, xc_get_data_type(src->$1));'
+		, `$3 $1', `int op_type', `fprintf(stderr, "$3:$1:\t%d %s\n", src->$1, xc_get_op_type(src->$1));'
+		, `$3 $1', `zend_uchar opcode', `fprintf(stderr, "$3:$1:\t%d %s\n", src->$1, xc_get_opcode(src->$1));'
+		, `', `', `fprintf(stderr, "$3:$1:\t%ifelse(`$2',`',`d',`$2')\n", src->$1);')
+	')
+	IFDASM(`
+		ifelse(
+			`$3', `zend_bool', `add_assoc_bool_ex(dst, ZEND_STRS("$1"), src->$1 ? 1 : 0);'
+		, `', `', `add_assoc_long_ex(dst, ZEND_STRS("$1"), src->$1);'
+		)
+	')
+	DONE(`$1')
+')
+dnl }}}
+dnl {{{ PROC_CLASS_ENTRY_P(1:elm)
+define(`PROC_CLASS_ENTRY_P', `PROC_CLASS_ENTRY_P_EX(`dst->$1', `src->$1', `$1')`'DONE(`$1')')
+dnl PROC_CLASS_ENTRY_P_EX(1:dst, 2:src, 3:elm-name)
+define(`PROC_CLASS_ENTRY_P_EX', `
+	if ($2) {
+		IFSTORE(`$1 = (zend_class_entry *) xc_get_class_num(processor, $2);')
+		IFRESTORE(`$1 = xc_get_class(processor, (zend_uint) $2);')
+		IFDASM(`add_assoc_stringl_ex(dst, ZEND_STRS("$3"), $2->name, strlen($2->name), 1);')
+	}
+	else {
+		COPYNULL_EX(`$1', `$3')
+	}
+')
+dnl }}}
+dnl {{{ IFASSERT
+define(`IFASSERT', `ifdef(`XCACHE_ENABLE_TEST', `
+#ifndef NDEBUG
+		$1
+#endif
+')')
+dnl }}}
+dnl {{{ DBG
+define(`DBG', `ifdef(`XCACHE_ENABLE_TEST', `
+	/* `$1' */
+')')
+dnl }}}
+dnl {{{ EXPORT
+define(`EXPORT', `define(`EXPORT_$1')')
+dnl }}}
+dnl {{{ FIXPOINTER
+define(`FIXPOINTER', `FIXPOINTER_EX(`$1', `dst->$2')')
+define(`FIXPOINTER_EX', `IFSTORE(`
+	$2 = ($1 *) xc_shm_to_readonly(processor->xce_src->cache->shm, (char *)$2);
+')')
+define(`UNFIXPOINTER', `UNFIXPOINTER_EX(`$1', `dst->$2')')
+define(`UNFIXPOINTER_EX', `IFSTORE(`
+	$2 = ($1 *) xc_shm_to_readwrite(processor->xce_src->cache->shm, (char *)$2);
+')')
+dnl }}}
+dnl {{{ COPY
+define(`COPY', `IFNOTMEMCPY(`IFCOPY(`dst->$1 = src->$1;')')DONE(`$1')')
+dnl }}}
+dnl {{{ SETNULL_EX
+define(`SETNULL_EX', `IFCOPY(`$1 = NULL;')')
+define(`SETNULL', `SETNULL_EX(`dst->$1')DONE(`$1')')
+dnl }}}
+dnl {{{ COPYNULL_EX(1:dst, 2:elm-name)
+define(`COPYNULL_EX', `
+	IFDASM(`add_assoc_null_ex(dst, ZEND_STRS("$2"));')
+	IFNOTMEMCPY(`IFCOPY(`$1 = NULL;')')
+')
+dnl }}}
+dnl {{{ COPYNULL(1:elm)
+# foreach(VAR, (LIST), STMT)
+m4_define([foreach],
+       [m4_pushdef([$1])_foreach([$1], [$2], [$3])m4_popdef([$1])])
+m4_define([_arg1], [$1])
+m4_define([_foreach],
+       [ifelse([$2], [()], ,
+       [m4_define([$1], _arg1$2)$3[]_foreach([$1],
+                                                       (shift$2),
+                                                       [$3])])])
+define(`COPYNULL', `
+	COPYNULL_EX(`dst->$1', `$2')DONE(`$1')
+')
+dnl }}}
+dnl {{{ LIST_DIFF(1:left-list, 2:right-list)
+define(`foreach',
+       `pushdef(`$1')_foreach(`$1', `$2', `$3')popdef(`$1')')
+define(`_arg1', `$1')
+define(`_foreach',                             
+       `ifelse(`$2', `()', ,                       
+       `define(`$1', _arg1$2)$3`'_foreach(`$1',
+                                                       (shift$2),
+                                                       `$3')')')
+define(`LIST_DIFF', `dnl
+foreach(`i', `($1)', `pushdef(`item_'defn(`i'))')dnl allocate variable for items in $1 
+foreach(`i', `($2)', `pushdef(`item_'defn(`i'))undefine(`item_'defn(`i'))')dnl allocate variable for items in $2, and undefine it 
+foreach(`i', `($1)', `ifdef(`item_'defn(`i'), `defn(`i') ')')dnl see what is still defined
+foreach(`i', `($2)', `popdef(`item_'defn(`i'))')dnl
+foreach(`i', `($1)', `popdef(`item_'defn(`i'))')dnl
+')
+dnl }}}
+dnl {{{ DONE_*
+define(`DONE_SIZE', `IFASSERT(`
+	done_size += $1`';
+	done_count ++;
+')')
+define(`DONE', `
+	define(`ELEMENTS_DONE', defn(`ELEMENTS_DONE')`,$1')
+	DONE_SIZE(`sizeof(src->$1)')
+')
+define(`DISABLECHECK', `
+	pushdef(`DONE_SIZE')
+	pushdef(`DONE')
+$1
+	popdef(`DONE_SIZE')
+	popdef(`DONE')
+')
+dnl }}}
+dnl {{{ IF**
+define(`IFCALC', `ifelse(KIND, `calc', `$1', `$2')')
+define(`IFSTORE', `ifelse(KIND, `store', `$1', `$2')')
+define(`IFCALCSTORE', `IFSTORE(`$1', `
+	IFCALC(`$1', `$2')
+')')
+define(`IFRESTORE', `ifelse(KIND, `restore', `$1', `$2')')
+define(`IFCOPY', `IFSTORE(`$1', `
+	IFRESTORE(`$1', `$2')
+')')
+define(`IFCALCCOPY', `IFCALC(`$1', `
+	IFCOPY(`$1', `$2')
+')')
+define(`IFDPRINT', `ifelse(KIND, `dprint', `$1', `$2')')
+define(`IFASM', `ifelse(KIND, `asm', `$1', `$2')')
+define(`IFDASM', `ifelse(KIND, `dasm', `$1', `$2')')
+dnl }}}
+EXPORT(`zend_op')
+EXPORT(`zend_op_array')
+EXPORT(`zend_function')
+EXPORT(`HashTable_zend_function')
+EXPORT(`zend_class_entry')
+EXPORT(`xc_classinfo_t')
+EXPORT(`xc_funcinfo_t')
+EXPORT(`xc_entry_t')
+EXPORT(`zval')
+
+include(srcdir`/processor/hashtable.m4')
+include(srcdir`/processor/string.m4')
+include(srcdir`/processor/struct.m4')
+include(srcdir`/processor/dispatch.m4')
+include(srcdir`/processor/head.m4')
+
+define(`IFNOTMEMCPY', `ifdef(`USEMEMCPY', `', `$1')')
+REDEF(`KIND', `calc') include(srcdir`/processor/processor.m4')
+REDEF(`KIND', `store') include(srcdir`/processor/processor.m4')
+REDEF(`KIND', `restore') include(srcdir`/processor/processor.m4')
+
+REDEF(`IFNOTMEMCPY', `$1')
+#ifdef HAVE_XCACHE_DPRINT
+REDEF(`KIND', `dprint') include(srcdir`/processor/processor.m4')
+#endif /* HAVE_XCACHE_DPRINT */
+#ifdef HAVE_XCACHE_DISASSEMBLER
+REDEF(`KIND', `dasm') include(srcdir`/processor/processor.m4')
+#endif /* HAVE_XCACHE_DISASSEMBLER */
+#ifdef HAVE_XCACHE_ASSEMBLER
+REDEF(`KIND', `asm') include(srcdir`/processor/processor.m4')
+#endif /* HAVE_XCACHE_ASSEMBLER */
+
+ifdef(`EXIT_PENDING', `m4exit(EXIT_PENDING)')
Index: /tags/1.0/processor/struct.m4
===================================================================
--- /tags/1.0/processor/struct.m4	(revision 29)
+++ /tags/1.0/processor/struct.m4	(revision 29)
@@ -0,0 +1,208 @@
+define(`pushdefFUNC_NAME', `
+	pushdef(`FUNC_NAME', `xc_`'KIND`'_`'ifelse(`$2', `', `$1', `$2')')
+')
+dnl {{{ DECL_STRUCT_P_FUNC(1:type, 2:name, 3:comma=;)
+define(`DECL_STRUCT_P_FUNC', `translit(
+	pushdefFUNC_NAME(`$1', `$2')
+	define(`DEFINED_'ifelse(`$2', `', `$1', `$2'), `')
+	ifdef(`EXPORT_'ifelse(`$2', `', `$1', `$2'), `void', `static void inline')
+	FUNC_NAME`'(
+		IFDPRINT( `const $1 * const src, int indent')
+		IFCALC(   `processor_t *processor, const $1 * const src')
+		IFSTORE(  `processor_t *processor, $1 *dst, const $1 * const src')
+		IFRESTORE(`processor_t *processor, $1 *dst, const $1 * const src')
+		IFDASM(   `zval *dst, const $1 * const src')
+		IFASM(    `$1 *dst, const $1 * const src')
+		TSRMLS_DC
+	)ifelse(`$3', `', `;')
+	popdef(`FUNC_NAME')dnl
+, `
+', ` ')')
+dnl }}}
+dnl {{{ DEF_STRUCT_P_FUNC(1:type, 2:name, 3:body)
+define(`DEF_STRUCT_P_FUNC', `
+	pushdefFUNC_NAME(`$1', `$2')
+/* {`{'{ FUNC_NAME */
+	ifdef(`EXPORT_'ifelse(`$2', `', `$1', `$2'), `
+		/* export: DECL_STRUCT_P_FUNC(`$1', `$2') :export */
+	')
+DECL_STRUCT_P_FUNC(`$1', `$2', 1)
+	{
+		pushdef(`ELEMENTS_DONE')
+		ifdef(`SIZEOF_$1', , `m4_errprint(`AUTOCHECK WARN: $1: missing structinfo, dont panic')define(`SIZEOF_$1', 0)')
+		IFASSERT(`
+			/* {{{ init assert */
+			ifdef(`SIZEOF_$1', , `m4_errprint(`missing SIZEOF_$1, safe to ignore')define(`SIZEOF_$1', 0)')
+			ifdef(`COUNTOF_$1', , `m4_errprint(`missing COUNTOF_$1, safe to ignore')define(`COUNTOF_$1', 0)')
+			dnl SIZEOF_x COUNTOF_x can be both defined or both not
+			ifdef(`SIZEOF_$1', `
+				ifdef(`COUNTOF_$1', , `m4_errprint(`AUTOCHECK WARN: missing COUNTOF_$1')')
+			', `
+				define(`SIZEOF_$1', 0)
+			')
+			ifdef(`COUNTOF_$1', `
+				ifdef(`SIZEOF_$1', , `m4_errprint(`AUTOCHECK WARN: missing SIZEOF_$1')')
+			', `
+				define(`COUNTOF_$1', 0)
+			')
+			int assert_size = SIZEOF_$1, assert_count = COUNTOF_$1;
+			int done_size = 0, done_count = 0;
+			/* }}} */
+			IFRESTORE(`assert(xc_is_shm(src));')
+			IFCALCSTORE(`assert(!xc_is_shm(src));')
+			do {
+		')
+
+		ifdef(`USEMEMCPY', `IFCOPY(`
+			memcpy(dst, src, sizeof($1));
+			do {
+		')')
+
+		IFDPRINT(`
+			fprintf(stderr, "%s", " {\n");
+			indent ++;
+		')
+		$3`'
+		IFDPRINT(`
+			indent --;
+			INDENT()fprintf(stderr, "}\n");
+		')
+		ifdef(`SKIPASSERT_ONCE', `undefine(`SKIPASSERT_ONCE')', `
+			IFASSERT(`
+				/* {{{ check assert */
+				if (done_count != assert_count) {
+					fprintf(stderr
+						, "count assertion failed at %s `#'%d FUNC_NAME`' : unexpected %d - expected %d = %d != 0\n"
+						, __FILE__, __LINE__
+						, done_count, assert_count, done_count - assert_count
+						);
+					abort();
+				}
+				if (done_size != assert_size) {
+					fprintf(stderr
+						, "size assertion failed at %s `#'%d FUNC_NAME`' : %d - %d = %d != 0\n"
+						, __FILE__, __LINE__
+						, done_size, assert_size, done_size - assert_size
+						);
+					abort();
+				}
+				/* }}} */
+			')
+			ifdef(`ELEMENTSOF_$1', `
+				pushdef(`ELEMENTS_UNDONE', LIST_DIFF(defn(`ELEMENTSOF_$1'), defn(`ELEMENTS_DONE')))
+				ifelse(defn(`ELEMENTS_UNDONE'), , `m4_errprint(`AUTOCHECK INFO: $1: processor looks good')', `
+					m4_errprint(`AUTOCHECK ERROR: ====' KIND `$1 =================')
+					m4_errprint(`AUTOCHECK expected:' defn(`ELEMENTSOF_$1'))
+					m4_errprint(`AUTOCHECK missing :' defn(`ELEMENTS_UNDONE'))
+					define(`EXIT_PENDING', 1)
+				')
+				popdef(`ELEMENTS_UNDONE')
+			')
+		')
+		ifdef(`USEMEMCPY', `IFCOPY(`
+			} while (0);
+		')')
+		IFASSERT(`
+			} while (0);
+		')
+		popdef(`ELEMENTS_DONE')
+	}
+/* }`}'} */
+	popdef(`FUNC_NAME')
+')
+dnl }}}
+dnl {{{ STRUCT_P_EX(1:type, 2:dst, 3:src, 4:elm-name, 5:name=type, 6:&)
+define(`STRUCT_P_EX', `
+	DBG(`$0($*)')
+	pushdefFUNC_NAME(`$1', `$5')
+	ifdef(`DEFINED_'ifelse(`$5', `', `$1', `$5'), `', `m4_errprint(`Unknown struct "'ifelse(`$5', `', `$1', `$5')`"')')
+	assert(sizeof($1) == sizeof(($6 $3)[0]));
+	ifelse(`$6', `', `ALLOC(`$2', `$1')')
+	IFDASM(`do {
+		zval *zv;
+		ALLOC_INIT_ZVAL(zv);
+		array_init(zv);
+	')
+	FUNC_NAME`'(
+		IFDPRINT( `           $6 $3, indent')
+		IFCALC(   `processor, $6 $3')
+		IFSTORE(  `processor, $6 $2, $6 $3')
+		IFRESTORE(`processor, $6 $2, $6 $3')
+		IFDASM(   `zv, $6 $3')
+		IFASM(    `$6 $2, $6 $3')
+		TSRMLS_CC
+	);
+	IFDASM(`
+		add_assoc_zval_ex(dst, ZEND_STRS("$4"), zv);
+	} while (0);
+	')
+	popdef(`FUNC_NAME')
+	ifelse(`$6', , `FIXPOINTER_EX(`$1', `$2')')
+')
+dnl }}}
+dnl {{{ STRUCT_P(1:type, 2:elm, 3:name=type)
+define(`STRUCT_P', `
+	DBG(`$0($*)')
+	if (src->$2) {
+		STRUCT_P_EX(`$1', `dst->$2', `src->$2', `$2', `$3')
+		IFDPRINT(`INDENT()`'fprintf(stderr, "$1:$2");')
+	}
+	else {
+		COPYNULL_EX(`dst->$2', `$2')
+		IFDPRINT(`INDENT()`'fprintf(stderr, "$1:$2:\tNULL\n");')
+	}
+	DONE(`$2')
+')
+dnl }}}
+dnl {{{ STRUCT(1:type, 2:elm, 3:name=type)
+define(`STRUCT', `
+	DBG(`$0($*)')
+	assert(sizeof($1) == sizeof(src->$2));
+	IFDPRINT(`INDENT()`'fprintf(stderr, "$1:$2");')
+	STRUCT_P_EX(`$1', `dst->$2', `src->$2', `$2', `$3', `&')
+	DONE(`$2')
+')
+dnl }}}
+dnl {{{ STRUCT_ARRAY_I(1:count, 2:type, 3:elm, 4:name=type)
+define(`STRUCT_ARRAY_I', `
+pushdef(`i', `ii')
+STRUCT_ARRAY(`$1', `$2', `$3', `$4')
+popdef(`i')
+')
+dnl }}}
+dnl {{{ STRUCT_ARRAY(1:count, 2:type, 3:elm, 4:name=type)
+define(`STRUCT_ARRAY', `
+	if (src->$3) {
+		pushdefFUNC_NAME(`$2', `$4')
+		IFDASM(`
+			zval *arr;
+			ALLOC_INIT_ZVAL(arr);
+			array_init(arr);
+			for (i = 0; i < src->$1; i ++) {
+				zval *zv;
+
+				ALLOC_INIT_ZVAL(zv);
+				array_init(zv);
+				FUNC_NAME (zv, &(src->$3[i]) TSRMLS_CC);
+				add_next_index_zval(arr, zv);
+			}
+			add_assoc_zval_ex(dst, ZEND_STRS("$3"), arr);
+		', `
+			ALLOC(`dst->$3', `$2', `src->$1')
+			ifdef(`AFTER_ALLOC', AFTER_ALLOC)
+			for (i = 0; i < src->$1; i ++) {
+				DISABLECHECK(`
+					ifdef(`BEFORE_LOOP', `BEFORE_LOOP')
+					STRUCT(`$2', `$3[i]', `$4')
+				')
+			}
+		')dnl IFDASM
+		DONE(`$3')
+		popdef(`FUNC_NAME')
+	}
+	else {
+		COPYNULL(`$3')
+		ifdef(`AFTER_ALLOC', AFTER_ALLOC)
+	}
+')
+dnl }}}
Index: /tags/1.0/processor/string.m4
===================================================================
--- /tags/1.0/processor/string.m4	(revision 11)
+++ /tags/1.0/processor/string.m4	(revision 11)
@@ -0,0 +1,88 @@
+
+dnl {{{ PROC_STRING_N_EX(1:dst, 2:src, 3:size, 4:name, 5:type=char)
+define(`PROC_STRING_N_EX', `
+	pushdef(`STRTYPE', `ifelse(`$5',,`char',`$5')')
+	pushdef(`ISTYPE', ifelse(STRTYPE,`char',IS_STRING,IS_UNICODE))
+	if ($2 == NULL) {
+		IFNOTMEMCPY(`IFCOPY(`
+			$1 = NULL;
+		')')
+		IFDASM(`
+			add_assoc_null_ex(dst, ZEND_STRS("$4"));
+		')
+	}
+	else {
+		IFDPRINT(`INDENT()
+			ifelse(STRTYPE, `UChar', `
+#ifdef IS_UNICODE
+			do {
+				zval zv;
+				zval reszv;
+				int usecopy;
+
+				INIT_ZVAL(zv);
+				ZVAL_UNICODEL(&zv, (UChar *) ($2), $3 - 1, 1);
+				zend_make_printable_zval(&zv, &reszv, &usecopy);
+				fprintf(stderr, "string:%s:\t\"%s\" len=%d\n", "$1", reszv.value.str.val, $3 - 1);
+				if (usecopy) {
+					zval_dtor(&reszv);
+				}
+				zval_dtor(&zv);
+			} while (0);
+#endif
+			', `
+			fprintf(stderr, "string:%s:\t\"%s\" len=%d\n", "$1", $2, $3 - 1);
+			')
+		')
+		IFCALC(`xc_calc_string_n(processor, ISTYPE, (void *) $2, `$3' IFASSERT(`, __LINE__'));')
+		IFSTORE(`$1 = (STRTYPE *) xc_store_string_n(processor, ISTYPE, (char *) $2, `$3' IFASSERT(`, __LINE__'));')
+		IFRESTORE(`
+			ALLOC(`$1', `STRTYPE', `sizeof(STRTYPE) * ($3)')
+			memcpy($1, $2, sizeof(STRTYPE) * ($3));
+		')
+		FIXPOINTER_EX(`STRTYPE', `$1')
+		IFDASM(`
+				ifelse(STRTYPE,UChar, `
+					add_assoc_unicodel_ex(dst, ZEND_STRS("$4"), $2, $3-1, 1);
+					', ` dnl else
+					add_assoc_stringl_ex(dst, ZEND_STRS("$4"), $2, $3-1, 1);')
+				')
+	}
+	popdef(`STRTYPE')
+	popdef(`ISTYPE')
+')
+dnl }}}
+dnl PROC_STRING_N(1:name, 2:size, 3:type)
+define(`PROC_STRING_N', `DBG(`$0($*)') DONE(`$1')`'PROC_STRING_N_EX(`dst->$1', `src->$1', `src->$2', `$1', `char')')
+
+define(`PROC_STRING_L', `DBG(`$0($*)') PROC_STRING_N(`$1', `$2 + 1')')
+define(`PROC_STRING',   `DBG(`$0($*)') DONE(`$1')`'PROC_STRING_N_EX(`dst->$1', `src->$1', `strlen(src->$1) + 1', `$1', `char')')
+
+dnl {{{ PROC_USTRING_N(1:type, 2:name, 3:size, 4:size_type)
+define(`PROC_USTRING_N', `
+	DBG(`$0($*)')
+#ifdef IS_UNICODE
+	pushdef(`NSIZE', ifelse(
+			`$4', `strlen', `strlen(src->$2) + 1',
+			`$4', `len',    `src->$3 + 1',
+			`',   `',       `src->$3',
+			))
+	DONE(`$2')
+	ifelse(`$1', `1', `PROC_STRING_N_EX(`dst->$2', `src->$2', NSIZE, `$2', `UChar')
+	', `
+		if (ifelse(`$1', `', `UG(unicode)', `src->$1')) {
+			PROC_STRING_N_EX(`dst->$2', `src->$2', NSIZE, `$2', `UChar')
+		}
+		else {
+			PROC_STRING_N_EX(`dst->$2', `src->$2', NSIZE, `$2', `char')
+		}
+	')
+#else
+	DONE(`$2')
+	PROC_STRING_N_EX(`dst->$2', `src->$2', NSIZE, `$2', `char')
+#endif
+	popdef(`NSIZE')
+')
+// }}}
+define(`PROC_USTRING_L', `DBG(`$0($*)') PROC_USTRING_N(`$1', `$2', `$3', `len')')
+define(`PROC_USTRING', `DBG(`$0($*)') PROC_USTRING_N(`$1', `$2', , `strlen')')
Index: /tags/1.0/processor/hashtable.m4
===================================================================
--- /tags/1.0/processor/hashtable.m4	(revision 58)
+++ /tags/1.0/processor/hashtable.m4	(revision 58)
@@ -0,0 +1,152 @@
+dnl DEF_HASH_TABLE_FUNC(1:name, 2:datatype [, 3:dataname])
+define(`DEF_HASH_TABLE_FUNC', `
+	DEF_STRUCT_P_FUNC(`HashTable', `$1', `
+		pushdefFUNC_NAME(`$2', `$3')
+		dnl {{{ dasm
+		IFDASM(`
+			Bucket *b;
+			zval *zv;
+			int bufsize = 2;
+			char *buf = emalloc(bufsize);
+			int keysize;
+
+#if defined(HARDENING_PATCH_HASH_PROTECT) && HARDENING_PATCH_HASH_PROTECT
+			DONE(canary)
+#endif
+			DONE(nTableSize)
+			DONE(nTableMask)
+			DONE(nNumOfElements)
+			DONE(nNextFreeElement)
+			DONE(pInternalPointer)
+			DONE(pListHead)
+			DONE(pListTail)
+			DONE(arBuckets)
+			DONE(pDestructor)
+			DONE(persistent)
+			DONE(nApplyCount)
+			DONE(bApplyProtection)
+#if ZEND_DEBUG
+			DONE(inconsistent)
+#endif
+#ifdef IS_UNICODE
+			DONE(unicode)
+#endif
+
+			DISABLECHECK(`
+			for (b = src->pListHead; b != NULL; b = b->pListNext) {
+				ALLOC_INIT_ZVAL(zv);
+				array_init(zv);
+				FUNC_NAME (zv, (($2*)b->pData) TSRMLS_CC);
+				keysize = BUCKET_KEY_SIZE(b) + 2;
+				if (keysize > bufsize) {
+					do {
+						bufsize *= 2;
+					} while (keysize > bufsize);
+					buf = erealloc(buf, bufsize);
+				}
+				memcpy(buf, BUCKET_KEY(b), keysize);
+				buf[keysize - 2] = buf[keysize - 1] = ""[0];
+				keysize = b->nKeyLength;
+#ifdef IS_UNICODE
+				if (BUCKET_KEY_TYPE(b) == IS_UNICODE) {
+					if (buf[0] == ""[0] && buf[1] == ""[0]) {
+						keysize ++;
+					}
+				} else
+#endif
+				{
+					if (buf[0] == ""[0]) {
+						keysize ++;
+					}
+				}
+				add_u_assoc_zval_ex(dst, BUCKET_KEY_TYPE(b), buf, keysize, zv);
+			}
+			')
+
+			efree(buf);
+			return; /* no check size */
+		', `
+		dnl }}}
+		Bucket *b, *pnew = NULL, *prev = NULL;
+		zend_bool first = 1;
+		dnl only used for copy
+		IFCOPY(`uint n;')
+		IFCALCCOPY(`int bucketsize;')
+
+#if defined(HARDENING_PATCH_HASH_PROTECT) && HARDENING_PATCH_HASH_PROTECT
+		IFASM(`dst->canary = zend_hash_canary; DONE(canary)', `
+		dnl elseif
+			IFRESTORE(`dst->canary = zend_hash_canary; DONE(canary)', `
+				dnl else
+				DISPATCH(unsigned int, canary)
+			')
+		')
+#endif
+		DISPATCH(uint, nTableSize)
+		DISPATCH(uint, nTableMask)
+		DISPATCH(uint, nNumOfElements)
+		DISPATCH(ulong, nNextFreeElement)
+		IFCOPY(`dst->pInternalPointer = NULL;	/* Used for element traversal */') DONE(pInternalPointer)
+		IFCOPY(`dst->pListHead = NULL;') DONE(pListHead)
+		CALLOC(dst->arBuckets, Bucket*, src->nTableSize)
+		DONE(arBuckets)
+		DISABLECHECK(`
+
+		for (b = src->pListHead; b != NULL; b = b->pListNext) {
+			IFCALCCOPY(`bucketsize = BUCKET_SIZE(b);')
+			ALLOC(pnew, char, bucketsize, , Bucket)
+			IFCOPY(`memcpy(pnew, b, bucketsize);')
+			IFCOPY(`
+				n = b->h & src->nTableMask;
+				/* pnew into hash node chain */
+				pnew->pLast = NULL;
+				if (dst->arBuckets[n]) {
+					pnew->pNext = dst->arBuckets[n];
+					pnew->pNext->pLast = pnew;
+				}
+				else {
+					pnew->pNext = NULL;
+				}
+				dst->arBuckets[n] = pnew;
+			')
+			if (sizeof(void *) == sizeof($2)) {
+				IFCOPY(`pnew->pData = &pnew->pDataPtr;')
+				dnl no alloc
+				STRUCT_P_EX(`$2', pnew->pData, (($2*)b->pData), `', `$3', ` ')
+			}
+			else {
+				STRUCT_P_EX(`$2', pnew->pData, (($2*)b->pData), `', `$3')
+				IFCOPY(`pnew->pDataPtr = NULL;')
+			}
+
+			if (first) {
+				IFCOPY(`dst->pListHead = pnew;')
+				first = 0;
+			}
+
+			IFCOPY(`
+				/* flat link */
+				pnew->pListLast = prev;
+				pnew->pListNext = NULL;
+				if (prev) {
+					prev->pListNext = pnew;
+				}
+			')
+			prev = pnew;
+		}
+		')
+		IFCOPY(`dst->pListTail = pnew;') DONE(pListTail)
+		IFCOPY(`dst->pDestructor = src->pDestructor;') DONE(pDestructor)
+		DISPATCH(zend_bool, persistent)
+#ifdef IS_UNICODE
+		DISPATCH(zend_bool, unicode)
+#endif
+		DISPATCH(unsigned char, nApplyCount)
+		DISPATCH(zend_bool, bApplyProtection)
+#if ZEND_DEBUG
+		DISPATCH(int, inconsistent)
+#endif
+		')dnl IFDASM
+		popdef(`FUNC_NAME')
+	')
+')
Index: /tags/1.0/align.h
===================================================================
--- /tags/1.0/align.h	(revision 36)
+++ /tags/1.0/align.h	(revision 36)
@@ -0,0 +1,19 @@
+#ifndef __ALIGN_H
+#define __ALIGN_H
+#ifndef ALIGN
+typedef union align_union {
+	double d;
+	void *v;
+	int (*func)(int);
+	long l;
+} align_union;
+
+#if (defined (__GNUC__) && __GNUC__ >= 2)
+#define XCACHE_PLATFORM_ALIGNMENT (__alignof__ (align_union))
+#else
+#define XCACHE_PLATFORM_ALIGNMENT (sizeof(align_union))
+#endif
+
+#define ALIGN(n) ((((size_t)(n)-1) & ~(XCACHE_PLATFORM_ALIGNMENT-1)) + XCACHE_PLATFORM_ALIGNMENT)
+#endif
+#endif /* __ALIGN_H */
Index: /tags/1.0/const_string_opcodes_php6.x.h
===================================================================
--- /tags/1.0/const_string_opcodes_php6.x.h	(revision 1)
+++ /tags/1.0/const_string_opcodes_php6.x.h	(revision 1)
@@ -0,0 +1,155 @@
+/* size = 151 */
+static const char *const xc_opcode_names[] = {
+/* 0 */	"NOP",
+/* 1 */	"ADD",
+/* 2 */	"SUB",
+/* 3 */	"MUL",
+/* 4 */	"DIV",
+/* 5 */	"MOD",
+/* 6 */	"SL",
+/* 7 */	"SR",
+/* 8 */	"CONCAT",
+/* 9 */	"BW_OR",
+/* 10 */	"BW_AND",
+/* 11 */	"BW_XOR",
+/* 12 */	"BW_NOT",
+/* 13 */	"BOOL_NOT",
+/* 14 */	"BOOL_XOR",
+/* 15 */	"IS_IDENTICAL",
+/* 16 */	"IS_NOT_IDENTICAL",
+/* 17 */	"IS_EQUAL",
+/* 18 */	"IS_NOT_EQUAL",
+/* 19 */	"IS_SMALLER",
+/* 20 */	"IS_SMALLER_OR_EQUAL",
+/* 21 */	"CAST",
+/* 22 */	"QM_ASSIGN",
+/* 23 */	"ASSIGN_ADD",
+/* 24 */	"ASSIGN_SUB",
+/* 25 */	"ASSIGN_MUL",
+/* 26 */	"ASSIGN_DIV",
+/* 27 */	"ASSIGN_MOD",
+/* 28 */	"ASSIGN_SL",
+/* 29 */	"ASSIGN_SR",
+/* 30 */	"ASSIGN_CONCAT",
+/* 31 */	"ASSIGN_BW_OR",
+/* 32 */	"ASSIGN_BW_AND",
+/* 33 */	"ASSIGN_BW_XOR",
+/* 34 */	"PRE_INC",
+/* 35 */	"PRE_DEC",
+/* 36 */	"POST_INC",
+/* 37 */	"POST_DEC",
+/* 38 */	"ASSIGN",
+/* 39 */	"ASSIGN_REF",
+/* 40 */	"ECHO",
+/* 41 */	"PRINT",
+/* 42 */	"JMP",
+/* 43 */	"JMPZ",
+/* 44 */	"JMPNZ",
+/* 45 */	"JMPZNZ",
+/* 46 */	"JMPZ_EX",
+/* 47 */	"JMPNZ_EX",
+/* 48 */	"CASE",
+/* 49 */	"SWITCH_FREE",
+/* 50 */	"BRK",
+/* 51 */	"CONT",
+/* 52 */	"BOOL",
+/* 53 */	"INIT_STRING",
+/* 54 */	"ADD_CHAR",
+/* 55 */	"ADD_STRING",
+/* 56 */	"ADD_VAR",
+/* 57 */	"BEGIN_SILENCE",
+/* 58 */	"END_SILENCE",
+/* 59 */	"INIT_FCALL_BY_NAME",
+/* 60 */	"DO_FCALL",
+/* 61 */	"DO_FCALL_BY_NAME",
+/* 62 */	"RETURN",
+/* 63 */	"RECV",
+/* 64 */	"RECV_INIT",
+/* 65 */	"SEND_VAL",
+/* 66 */	"SEND_VAR",
+/* 67 */	"SEND_REF",
+/* 68 */	"NEW",
+/* 69 */	"UNDEF",
+/* 70 */	"FREE",
+/* 71 */	"INIT_ARRAY",
+/* 72 */	"ADD_ARRAY_ELEMENT",
+/* 73 */	"INCLUDE_OR_EVAL",
+/* 74 */	"UNSET_VAR",
+/* 75 */	"UNSET_DIM",
+/* 76 */	"UNSET_OBJ",
+/* 77 */	"FE_RESET",
+/* 78 */	"FE_FETCH",
+/* 79 */	"EXIT",
+/* 80 */	"FETCH_R",
+/* 81 */	"FETCH_DIM_R",
+/* 82 */	"FETCH_OBJ_R",
+/* 83 */	"FETCH_W",
+/* 84 */	"FETCH_DIM_W",
+/* 85 */	"FETCH_OBJ_W",
+/* 86 */	"FETCH_RW",
+/* 87 */	"FETCH_DIM_RW",
+/* 88 */	"FETCH_OBJ_RW",
+/* 89 */	"FETCH_IS",
+/* 90 */	"FETCH_DIM_IS",
+/* 91 */	"FETCH_OBJ_IS",
+/* 92 */	"FETCH_FUNC_ARG",
+/* 93 */	"FETCH_DIM_FUNC_ARG",
+/* 94 */	"FETCH_OBJ_FUNC_ARG",
+/* 95 */	"FETCH_UNSET",
+/* 96 */	"FETCH_DIM_UNSET",
+/* 97 */	"FETCH_OBJ_UNSET",
+/* 98 */	"FETCH_DIM_TMP_VAR",
+/* 99 */	"FETCH_CONSTANT",
+/* 100 */	"UNDEF",
+/* 101 */	"EXT_STMT",
+/* 102 */	"EXT_FCALL_BEGIN",
+/* 103 */	"EXT_FCALL_END",
+/* 104 */	"EXT_NOP",
+/* 105 */	"TICKS",
+/* 106 */	"SEND_VAR_NO_REF",
+/* 107 */	"CATCH",
+/* 108 */	"THROW",
+/* 109 */	"FETCH_CLASS",
+/* 110 */	"CLONE",
+/* 111 */	"UNDEF",
+/* 112 */	"INIT_METHOD_CALL",
+/* 113 */	"INIT_STATIC_METHOD_CALL",
+/* 114 */	"ISSET_ISEMPTY_VAR",
+/* 115 */	"ISSET_ISEMPTY_DIM_OBJ",
+/* 116 */	"UNDEF",
+/* 117 */	"UNDEF",
+/* 118 */	"UNDEF",
+/* 119 */	"UNDEF",
+/* 120 */	"UNDEF",
+/* 121 */	"UNDEF",
+/* 122 */	"UNDEF",
+/* 123 */	"UNDEF",
+/* 124 */	"UNDEF",
+/* 125 */	"UNDEF",
+/* 126 */	"UNDEF",
+/* 127 */	"UNDEF",
+/* 128 */	"UNDEF",
+/* 129 */	"UNDEF",
+/* 130 */	"UNDEF",
+/* 131 */	"UNDEF",
+/* 132 */	"PRE_INC_OBJ",
+/* 133 */	"PRE_DEC_OBJ",
+/* 134 */	"POST_INC_OBJ",
+/* 135 */	"POST_DEC_OBJ",
+/* 136 */	"ASSIGN_OBJ",
+/* 137 */	"OP_DATA",
+/* 138 */	"INSTANCEOF",
+/* 139 */	"DECLARE_CLASS",
+/* 140 */	"DECLARE_INHERITED_CLASS",
+/* 141 */	"DECLARE_FUNCTION",
+/* 142 */	"RAISE_ABSTRACT_ERROR",
+/* 143 */	"UNDEF",
+/* 144 */	"ADD_INTERFACE",
+/* 145 */	"UNDEF",
+/* 146 */	"VERIFY_ABSTRACT_CLASS",
+/* 147 */	"ASSIGN_DIM",
+/* 148 */	"ISSET_ISEMPTY_PROP_OBJ",
+/* 149 */	"HANDLE_EXCEPTION",
+/* 150 */	"USER_OPCODE",
+/* 151 */	"U_NORMALIZE"
+};
Index: /tags/1.0/utils.c
===================================================================
--- /tags/1.0/utils.c	(revision 19)
+++ /tags/1.0/utils.c	(revision 19)
@@ -0,0 +1,403 @@
+#include "php.h"
+#include "xcache.h"
+#include "utils.h"
+#ifdef ZEND_ENGINE_2_1
+#include "zend_vm.h"
+#endif
+#include "opcode_spec.h"
+#undef NDEBUG
+#include "assert.h"
+
+xc_compile_result_t *xc_compile_result_init(xc_compile_result_t *cr, /* {{{ */
+		zend_op_array *op_array,
+		HashTable *function_table,
+		HashTable *class_table)
+{
+	if (cr) {
+		cr->alloc = 0;
+	}
+	else {
+		cr = emalloc(sizeof(xc_compile_result_t));
+		cr->alloc = 1;
+	}
+	cr->op_array       = op_array;
+	cr->function_table = function_table;
+	cr->class_table    = class_table;
+	return cr;
+}
+/* }}} */
+xc_compile_result_t *xc_compile_result_init_cur(xc_compile_result_t *cr, zend_op_array *op_array TSRMLS_DC) /* {{{ */
+{
+	return xc_compile_result_init(cr, op_array, CG(function_table), CG(class_table));
+}
+/* }}} */
+void xc_compile_result_free(xc_compile_result_t *cr) /* {{{ */
+{
+	if (cr->alloc) {
+		efree(cr);
+	}
+}
+/* }}} */
+
+int xc_apply_function(zend_function *zf, apply_func_t applyer TSRMLS_DC) /* {{{ */
+{
+	switch (zf->type) {
+	case ZEND_USER_FUNCTION:
+	case ZEND_EVAL_CODE:
+		return applyer(&zf->op_array TSRMLS_CC);
+		break;
+
+	case ZEND_INTERNAL_FUNCTION:
+	case ZEND_OVERLOADED_FUNCTION:
+		break;
+
+	EMPTY_SWITCH_DEFAULT_CASE();
+	}
+	return 0;
+}
+/* }}} */
+typedef struct {
+	apply_func_t applyer;
+	zend_class_entry *ce;
+} xc_apply_method_info;
+int xc_apply_method(zend_function *zf, xc_apply_method_info *mi TSRMLS_DC) /* {{{ */
+{
+	/* avoid duplicate apply for shadowed method */
+#ifdef ZEND_ENGINE_2
+	if (mi->ce != zf->common.scope) {
+		/* fprintf(stderr, "avoided duplicate %s\n", zf->common.function_name); */
+		return 0;
+	}
+#else
+	char *name = zf->common.function_name;
+	int name_s = strlen(name) + 1;
+	zend_class_entry *ce;
+	zend_function *ptr;
+
+	for (ce = mi->ce->parent; ce; ce = ce->parent) {
+		if (zend_hash_find(&ce->function_table, name, name_s, (void **) &ptr) == SUCCESS) {
+			if (ptr->op_array.refcount == zf->op_array.refcount) {
+				return 0;
+			}
+		}
+	}
+#endif
+	return xc_apply_function(zf, mi->applyer TSRMLS_CC);
+}
+/* }}} */
+#if 0
+int xc_apply_class(zend_class_entry *ce, apply_func_t applyer TSRMLS_DC) /* {{{ */
+{
+	xc_apply_method_info mi;
+
+	mi.applyer = applyer;
+	mi.ce      = ce;
+	zend_hash_apply_with_argument(&(ce->function_table), (apply_func_arg_t) xc_apply_method, &mi TSRMLS_CC);
+	return 0;
+}
+/* }}} */
+#endif
+static int xc_apply_cest(xc_cest_t *cest, apply_func_t applyer TSRMLS_DC) /* {{{ */
+{
+	xc_apply_method_info mi;
+
+	mi.applyer = applyer;
+	mi.ce      = CestToCePtr(*cest);
+	zend_hash_apply_with_argument(&(CestToCePtr(*cest)->function_table), (apply_func_arg_t) xc_apply_method, &mi TSRMLS_CC);
+	return 0;
+}
+/* }}} */
+int xc_apply_op_array(xc_compile_result_t *cr, apply_func_t applyer TSRMLS_DC) /* {{{ */
+{
+	zend_hash_apply_with_argument(cr->function_table, (apply_func_arg_t) xc_apply_function, applyer TSRMLS_CC);
+	zend_hash_apply_with_argument(cr->class_table, (apply_func_arg_t) xc_apply_cest, applyer TSRMLS_CC);
+
+	return applyer(cr->op_array TSRMLS_CC);
+}
+/* }}} */
+
+int xc_undo_pass_two(zend_op_array *op_array TSRMLS_DC) /* {{{ */
+{
+	zend_op *opline, *end;
+
+	if (!op_array->done_pass_two) {
+		return 0;
+	}
+
+	opline = op_array->opcodes;
+	end = opline + op_array->last;
+	while (opline < end) {
+#ifdef ZEND_ENGINE_2_1
+		switch (opline->opcode) {
+			case ZEND_JMP:
+				opline->op1.u.opline_num = opline->op1.u.jmp_addr - op_array->opcodes;
+				assert(opline->op1.u.opline_num < op_array->last);
+				break;
+			case ZEND_JMPZ:
+			case ZEND_JMPNZ:
+			case ZEND_JMPZ_EX:
+			case ZEND_JMPNZ_EX:
+				opline->op2.u.opline_num = opline->op2.u.jmp_addr - op_array->opcodes;
+				assert(opline->op2.u.opline_num < op_array->last);
+				break;
+		}
+#endif
+		opline++;
+	}
+	op_array->done_pass_two = 0;
+
+	return 0;
+}
+/* }}} */
+int xc_redo_pass_two(zend_op_array *op_array TSRMLS_DC) /* {{{ */
+{
+	zend_op *opline, *end;
+
+	if (op_array->done_pass_two) {
+		return 0;
+	}
+
+	/*
+	op_array->opcodes = (zend_op *) erealloc(op_array->opcodes, sizeof(zend_op)*op_array->last);
+	op_array->size = op_array->last;
+	*/
+
+	opline = op_array->opcodes;
+	end = opline + op_array->last;
+	while (opline < end) {
+		if (opline->op1.op_type == IS_CONST) {
+			opline->op1.u.constant.is_ref = 1;
+			opline->op1.u.constant.refcount = 2; /* Make sure is_ref won't be reset */
+		}
+		if (opline->op2.op_type == IS_CONST) {
+			opline->op2.u.constant.is_ref = 1;
+			opline->op2.u.constant.refcount = 2;
+		}
+#ifdef ZEND_ENGINE_2_1
+		switch (opline->opcode) {
+			case ZEND_JMP:
+				assert(opline->op1.u.opline_num < op_array->last);
+				opline->op1.u.jmp_addr = op_array->opcodes + opline->op1.u.opline_num;
+				break;
+			case ZEND_JMPZ:
+			case ZEND_JMPNZ:
+			case ZEND_JMPZ_EX:
+			case ZEND_JMPNZ_EX:
+				assert(opline->op2.u.opline_num < op_array->last);
+				opline->op2.u.jmp_addr = op_array->opcodes + opline->op2.u.opline_num;
+				break;
+		}
+		ZEND_VM_SET_OPCODE_HANDLER(opline);
+#endif
+		opline++;
+	}
+
+	op_array->done_pass_two = 1;
+	return 0;
+}
+/* }}} */
+
+#ifdef HAVE_XCACHE_OPCODE_SPEC_DEF
+static void xc_fix_opcode_ex_znode(int tofix, xc_op_spec_t spec, znode *znode, int type TSRMLS_DC) /* {{{ */
+{
+#ifdef ZEND_ENGINE_2
+	if ((znode->op_type != IS_UNUSED && (spec == OPSPEC_UCLASS || spec == OPSPEC_CLASS)) ||
+			spec == OPSPEC_FETCH) {
+		if (tofix) {
+			switch (znode->op_type) {
+			case IS_VAR:
+			case IS_TMP_VAR:
+				break;
+
+			default:
+				/* TODO: data lost, find a way to keep it */
+				/* assert(znode->op_type == IS_CONST); */
+				znode->op_type = IS_TMP_VAR;
+			}
+		}
+	}
+	switch (znode->op_type) {
+	case IS_TMP_VAR:
+	case IS_VAR:
+		if (tofix) {
+			znode->u.var /= sizeof(temp_variable);
+		}
+		else {
+			znode->u.var *= sizeof(temp_variable);
+		}
+	}
+#endif
+}
+/* }}} */
+
+static void xc_fix_opcode_ex(zend_op_array *op_array, int tofix TSRMLS_DC) /* {{{ */
+{
+	zend_op *opline;
+	zend_uint i;
+
+	opline = op_array->opcodes;
+	for (i = 0; i < op_array->last; i ++, opline ++) {
+		/* 3rd optimizer may have ... */
+		if (opline->opcode < xc_get_opcode_spec_count()) {
+			const xc_opcode_spec_t *spec;
+			spec = xc_get_opcode_spec(opline->opcode);
+
+			xc_fix_opcode_ex_znode(tofix, spec->op1, &opline->op1, 0 TSRMLS_CC);
+			xc_fix_opcode_ex_znode(tofix, spec->op2, &opline->op2, 1 TSRMLS_CC);
+			xc_fix_opcode_ex_znode(tofix, spec->res, &opline->result, 2 TSRMLS_CC);
+		}
+	}
+}
+/* }}} */
+int xc_fix_opcode(zend_op_array *op_array TSRMLS_DC) /* {{{ */
+{
+	xc_fix_opcode_ex(op_array, 1 TSRMLS_CC);
+	return 0;
+}
+/* }}} */
+int xc_undo_fix_opcode(zend_op_array *op_array TSRMLS_DC) /* {{{ */
+{
+	xc_fix_opcode_ex(op_array, 0 TSRMLS_CC);
+
+	return 0;
+}
+/* }}} */
+#endif
+
+void xc_install_function(char *filename, zend_function *func, zend_uchar type, char *key, uint len TSRMLS_DC) /* {{{ */
+{
+	if (func->type == ZEND_USER_FUNCTION) {
+		if (zend_u_hash_add(CG(function_table), type, key, len,
+					func, sizeof(zend_op_array),
+					NULL
+					) == FAILURE) {
+			CG(in_compilation) = 1;
+			CG(compiled_filename) = filename;
+			CG(zend_lineno) = ZESW(func->op_array.opcodes[0].lineno, func->op_array.line_start);
+			zend_error(E_ERROR, "Cannot redeclare %s()", key);
+		}
+	}
+}
+/* }}} */
+ZESW(xc_cest_t *, void) xc_install_class(char *filename, xc_cest_t *cest, zend_uchar type, void *key, uint len TSRMLS_DC) /* {{{ */
+{
+	zend_class_entry *cep = CestToCePtr(*cest);
+	ZESW(void *stored_ce_ptr, NOTHING);
+
+	if (zend_u_hash_add(CG(class_table), type, key, len,
+				cest, sizeof(xc_cest_t),
+				ZESW(&stored_ce_ptr, NULL)
+				) == FAILURE) {
+		CG(in_compilation) = 1;
+		CG(compiled_filename) = filename;
+		CG(zend_lineno) = ZESW(0, cep->line_start);
+		zend_error(E_ERROR, "Cannot redeclare class %s", (char *) cep->name);
+	}
+	ZESW(return (xc_cest_t *) stored_ce_ptr, NOTHING);
+}
+/* }}} */
+
+/* sandbox {{{ */
+#undef TG
+#undef OG
+#define TG(x) (sandbox->tmp_##x)
+#define OG(x) (sandbox->orig_##x)
+/* }}} */
+xc_sandbox_t *xc_sandbox_init(xc_sandbox_t *sandbox, char *filename TSRMLS_DC) /* {{{ */
+{
+	if (sandbox) {
+		memset(sandbox, 0, sizeof(sandbox[0]));
+	}
+	else {
+		ECALLOC_ONE(sandbox);
+		sandbox->alloc = 1;
+	}
+	memcpy(&OG(included_files), &EG(included_files), sizeof(EG(included_files)));
+	memcpy(&OG(open_files), &CG(open_files), sizeof(CG(open_files)));
+
+	OG(function_table) = CG(function_table);
+	CG(function_table) = &TG(function_table);
+
+	assert(EG(class_table) == CG(class_table));
+
+	OG(class_table) = CG(class_table);
+	CG(class_table) = &TG(class_table);
+	EG(class_table) = CG(class_table);
+
+	TG(included_files) = &EG(included_files);
+	TG(open_files)     = &CG(open_files);
+
+	zend_llist_init(TG(open_files), sizeof(zend_file_handle), (void (*)(void *)) zend_file_handle_dtor, 0);
+	zend_hash_init_ex(TG(included_files), 5, NULL, NULL, 0, 1);
+	zend_hash_init_ex(&TG(function_table), 128, NULL, ZEND_FUNCTION_DTOR, 0, 0);
+	zend_hash_init_ex(&TG(class_table), 16, NULL, ZEND_CLASS_DTOR, 0, 0);
+
+	sandbox->filename = filename;
+
+	return sandbox;
+}
+/* }}} */
+static void xc_sandbox_install(xc_sandbox_t *sandbox TSRMLS_DC) /* {{{ */
+{
+	int i;
+	Bucket *b;
+	zend_llist_position lpos;
+	zend_file_handle *handle;
+
+	b = TG(function_table).pListHead;
+	/* install function */
+	while (b != NULL) {
+		zend_function *func = (zend_function*) b->pData;
+		xc_install_function(sandbox->filename, func,
+				BUCKET_KEY_TYPE(b), BUCKET_KEY(b), b->nKeyLength TSRMLS_CC);
+		b = b->pListNext;
+	}
+
+	b = TG(class_table).pListHead;
+	/* install class */
+	while (b != NULL) {
+		xc_install_class(sandbox->filename, (xc_cest_t*)b->pData,
+				BUCKET_KEY_TYPE(b), BUCKET_KEY(b), b->nKeyLength TSRMLS_CC);
+		b = b->pListNext;
+	}
+
+	i = 1;
+	zend_hash_add(&OG(included_files), sandbox->filename, strlen(sandbox->filename) + 1, (void *)&i, sizeof(int), NULL);
+	for (handle = zend_llist_get_first_ex(TG(open_files), &lpos);
+			handle;
+			handle = zend_llist_get_next_ex(TG(open_files), &lpos)) {
+		zend_llist_add_element(&OG(open_files), handle);
+	}
+}
+/* }}} */
+void xc_sandbox_free(xc_sandbox_t *sandbox, int install TSRMLS_DC) /* {{{ */
+{
+	/* restore first first install function/class */
+	CG(function_table) = OG(function_table);
+	CG(class_table)    = OG(class_table);
+	EG(class_table)    = CG(class_table);
+
+	if (install) {
+		xc_sandbox_install(sandbox TSRMLS_CC);
+
+		/* no free as it's installed */
+		TG(function_table).pDestructor = NULL;
+		TG(class_table).pDestructor = NULL;
+		TG(open_files)->dtor = NULL;
+	}
+
+	/* destroy all the tmp */
+	zend_hash_destroy(&TG(function_table));
+	zend_hash_destroy(&TG(class_table));
+	zend_hash_destroy(TG(included_files));
+	zend_llist_destroy(TG(open_files));
+
+	/* restore orig here, as EG/CG holded tmp before */
+	memcpy(&EG(included_files), &OG(included_files), sizeof(EG(included_files)));
+	memcpy(&CG(open_files),     &OG(open_files),     sizeof(CG(open_files)));
+
+	if (sandbox->alloc) {
+		efree(sandbox);
+	}
+}
+/* }}} */
Index: /tags/1.0/mkopcode.awk
===================================================================
--- /tags/1.0/mkopcode.awk	(revision 52)
+++ /tags/1.0/mkopcode.awk	(revision 52)
@@ -0,0 +1,77 @@
+#! /usr/bin/awk -f
+# vim:ts=4:sw=4
+# process zend_vm_def.h or zend_compile.h
+BEGIN {
+	FS=" "
+	max = 0;
+}
+
+/^ZEND_VM_HANDLER\(/ {
+	# regex from php5.1+/Zend/zend_vm_gen.php
+	gsub(/ +/, "");
+	if (!match($0, /^ZEND_VM_HANDLER\(([0-9]+),([A-Z_]+),([A-Z|]+),([A-Z|]+)\)/)) {
+		print "error unmatch $0";
+		exit;
+	}
+	# life is hard without 3rd argument of match()
+	sub(/^ZEND_VM_HANDLER\(/, "");
+	id = $0;
+	sub(/,.*/, "", id); # chop
+	id = 0 + id;
+	sub(/^([0-9]+),/, "");
+	sub(/,.*/, ""); # chop
+	name = $0;
+	if (max < id) {
+		max = id;
+	}
+	opcodes[id] = name;
+	next;
+}
+
+/^#define +ZEND_[A-Z_]+[\t ]+[[:digit:]]+$/ {
+	id = 0 + $3;
+	name = $2;
+	if (max < id) {
+		max = id;
+	}
+	opcodes[id] = name;
+	next;
+}
+
+/end of block/ {
+	exit;
+}
+
+END {
+	mymax = 112;
+	if (max < mymax) {
+		for (i = max + 1; i <= mymax; i ++) {
+			opcodes[i] = "UNDEF";
+		}
+		max = mymax;
+		opcodes[110] = "ZEND_DO_FCALL_BY_FUNC";
+		opcodes[111] = "ZEND_INIT_FCALL_BY_FUNC";
+		opcodes[112] = "UNDEF";
+	}
+	printf "/* size = %d */\n", max;
+	print "static const char *const xc_opcode_names[] = {";
+	for (i = 0; i <= max; i ++) {
+		if (i != 0) {
+			print ",";
+		}
+		printf "/* %d */\t", i
+		if (i in opcodes) {
+			name = opcodes[i];
+			sub(/^ZEND_/, "", name);
+			printf "\"%s\"", name;
+		}
+		else if (i == 137) {
+			printf "\"%s\"", "OP_DATA";
+		}
+		else {
+			printf "\"UNDEF\"";
+		}
+	}
+	print "";
+	print "};";
+}
Index: /tags/1.0/xcache_globals.h
===================================================================
--- /tags/1.0/xcache_globals.h	(revision 28)
+++ /tags/1.0/xcache_globals.h	(revision 28)
@@ -0,0 +1,22 @@
+
+ZEND_BEGIN_MODULE_GLOBALS(xcache)
+	zend_bool cacher;      /* true if enabled */
+#ifdef HAVE_XCACHE_OPTIMIZER
+	zend_bool optimizer;   /* true if enabled */
+#endif
+#ifdef HAVE_XCACHE_COVERAGER
+	zend_bool coveragedumper;
+	HashTable *coverages;  /* coverages[file][line] = times */
+#endif
+	xc_stack_t *php_holds;
+	xc_stack_t *var_holds;
+	time_t request_time;
+ZEND_END_MODULE_GLOBALS(xcache)
+
+ZEND_EXTERN_MODULE_GLOBALS(xcache)
+
+#ifdef ZTS
+# define XG(v) TSRMG(xcache_globals_id, zend_xcache_globals *, v)
+#else
+# define XG(v) (xcache_globals.v)
+#endif
Index: /tags/1.0/AUTHORS
===================================================================
--- /tags/1.0/AUTHORS	(revision 45)
+++ /tags/1.0/AUTHORS	(revision 45)
@@ -0,0 +1,1 @@
+mOo <phpxcache@gmail.com>
Index: /tags/1.0/stack.c
===================================================================
--- /tags/1.0/stack.c	(revision 11)
+++ /tags/1.0/stack.c	(revision 11)
@@ -0,0 +1,62 @@
+#include <stdlib.h>
+#include <assert.h>
+#include "stack.h"
+typedef xc_stack_t* S;
+
+void xc_stack_init(S stack)
+{
+	stack->cnt = 0;
+	stack->size = 8;
+	stack->data = malloc(sizeof(void *) * stack->size);
+}
+
+void xc_stack_destroy(S stack)
+{
+	free(stack->data);
+}
+
+void xc_stack_push(S stack, void *item)
+{
+	if (stack->cnt == stack->size) {
+		stack->size <<= 1;
+		stack->data = realloc(stack->data, sizeof(void *) * stack->size);
+	}
+	stack->data[stack->cnt++] = item;
+}
+
+void* xc_stack_pop(S stack)
+{
+	assert(stack != NULL && stack->size > 0);
+	return stack->data[--stack->cnt];
+}
+
+void* xc_stack_top(S stack)
+{
+	assert(stack != NULL && stack->cnt > 0);
+	return stack->data[stack->cnt-1];
+}
+
+void* xc_stack_get(S stack, int n)
+{
+	assert(stack != NULL && stack->cnt > 0);
+	return stack->data[n];
+}
+
+int xc_stack_size(S stack)
+{
+	assert(stack != NULL);
+	return stack->cnt;
+}
+
+void xc_stack_reverse(S stack)
+{
+	int i, j;
+	void *tmp;
+
+	assert(stack != NULL);
+	for (i = 0, j = stack->cnt - 1; i < j; i ++, j --) {
+		tmp = stack->data[i];
+		stack->data[i] = stack->data[j];
+		stack->data[j] = tmp;
+	}
+}
Index: /tags/1.0/utils.h
===================================================================
--- /tags/1.0/utils.h	(revision 1)
+++ /tags/1.0/utils.h	(revision 1)
@@ -0,0 +1,48 @@
+#include "php.h"
+
+typedef struct {
+	int alloc;
+	zend_op_array *op_array;
+	HashTable *function_table;
+	HashTable *class_table;
+} xc_compile_result_t;
+
+xc_compile_result_t *xc_compile_result_init(xc_compile_result_t *cr,
+		zend_op_array *op_array,
+		HashTable *function_table,
+		HashTable *class_table);
+void xc_compile_result_free(xc_compile_result_t *cr);
+xc_compile_result_t *xc_compile_result_init_cur(xc_compile_result_t *cr, zend_op_array *op_array TSRMLS_DC);
+/* apply func */
+int xc_apply_function(zend_function *zf, apply_func_t applyer TSRMLS_DC);
+int xc_apply_class(zend_class_entry *ce, apply_func_t applyer TSRMLS_DC);
+int xc_apply_op_array(xc_compile_result_t *cr, apply_func_t applyer TSRMLS_DC);
+
+int xc_undo_pass_two(zend_op_array *op_array TSRMLS_DC);
+int xc_redo_pass_two(zend_op_array *op_array TSRMLS_DC);
+int xc_fix_opcode(zend_op_array *op_array TSRMLS_DC);
+int xc_undo_fix_opcode(zend_op_array *op_array TSRMLS_DC);
+zend_uchar xc_get_fixed_opcode(zend_uchar opcode, int line);
+
+/* installer */
+void xc_install_function(char *filename, zend_function *func, zend_uchar type, char *key, uint len TSRMLS_DC);
+ZESW(xc_cest_t *, void) xc_install_class(char *filename, xc_cest_t *cest, zend_uchar type, void *key, uint len TSRMLS_DC);
+
+/* sandbox */
+typedef struct {
+	int alloc;
+	char *filename;
+
+	HashTable orig_included_files;
+	zend_llist orig_open_files;
+	HashTable *tmp_included_files;
+	zend_llist *tmp_open_files;
+
+	HashTable *orig_function_table;
+	HashTable *orig_class_table;
+	HashTable tmp_function_table;
+	HashTable tmp_class_table;
+} xc_sandbox_t;
+
+xc_sandbox_t *xc_sandbox_init(xc_sandbox_t *sandbox, char *filename TSRMLS_DC);
+void xc_sandbox_free(xc_sandbox_t *sandbox, int install TSRMLS_DC);
Index: /tags/1.0/THANKS
===================================================================
--- /tags/1.0/THANKS	(revision 63)
+++ /tags/1.0/THANKS	(revision 63)
@@ -0,0 +1,7 @@
+
+Jan <jan@kneschke.de>, host XCache website
+Alex <ale@freebsd.org>, redist to FreeBSD
+darix <darix@irssi.org>, redist to opensuse
+
+There is also many ppl on IRC or forum helped me a lot testing XCache.
+Without them, XCache may not even be released.
Index: /tags/1.0/Makefile.frag
===================================================================
--- /tags/1.0/Makefile.frag	(revision 53)
+++ /tags/1.0/Makefile.frag	(revision 53)
@@ -0,0 +1,35 @@
+XCACHE_PROC_SRC=$(srcdir)/processor/main.m4
+XCACHE_PROC_OUT=$(builddir)/processor.out
+XCACHE_PROC_C=$(builddir)/processor_real.c
+XCACHE_PROC_H=$(builddir)/processor.h
+XCACHE_INCLUDES_SRC=$(srcdir)/includes.c
+XCACHE_INCLUDES_I=$(builddir)/includes.i
+XCACHE_STRUCTINFO_OUT=$(builddir)/structinfo.m4
+
+$(XCACHE_INCLUDES_I): $(XCACHE_INCLUDES_SRC) $(srcdir)/xcache.h
+	$(CC) -I. -I$(srcdir) $(COMMON_FLAGS) $(CFLAGS_CLEAN) $(EXTRA_CFLAGS) -E $(XCACHE_INCLUDES_SRC) -o $(XCACHE_INCLUDES_I)
+
+$(XCACHE_STRUCTINFO_OUT): $(XCACHE_INCLUDES_I) $(srcdir)/mkstructinfo.awk
+	@echo $(XCACHE_STRUCTINFO_OUT) is optional if XCache test is not enabled, feel free if it awk failed to produce it
+	-$(AWK) -f $(srcdir)/mkstructinfo.awk < $(XCACHE_INCLUDES_I) > $(XCACHE_STRUCTINFO_OUT).tmp && mv -f $(XCACHE_STRUCTINFO_OUT).tmp $(XCACHE_STRUCTINFO_OUT)
+
+$(XCACHE_PROC_OUT): $(XCACHE_PROC_SRC) $(XCACHE_STRUCTINFO_OUT) $(XCACHE_PROC_SOURCES)
+	$(M4) -D srcdir="$(srcdir)" -D builddir="$(builddir)" $(XCACHE_ENABLE_TEST) $(XCACHE_PROC_SRC) > $(XCACHE_PROC_OUT).tmp
+	mv -f $(XCACHE_PROC_OUT).tmp $(XCACHE_PROC_OUT)
+
+$(XCACHE_PROC_H): $(XCACHE_PROC_OUT)
+	$(GREP) 'export: ' $(XCACHE_PROC_OUT) | $(SED) 's/.*export:\(.*\):export.*/\1/g' | $(XCACHE_INDENT) > $(XCACHE_PROC_H).tmp
+	mv -f $(XCACHE_PROC_H).tmp $(XCACHE_PROC_H)
+
+$(XCACHE_PROC_C): $(XCACHE_PROC_OUT) $(XCACHE_PROC_H)
+	$(XCACHE_INDENT) < $(XCACHE_PROC_OUT) > $(XCACHE_PROC_C).tmp
+	mv -f $(XCACHE_PROC_C).tmp $(XCACHE_PROC_C)
+
+$(builddir)/processor.lo: $(XCACHE_PROC_C) $(XCACHE_PROC_H) $(srcdir)/processor.c
+processor.lo: $(XCACHE_PROC_C) $(XCACHE_PROC_H) $(srcdir)/processor.c
+
+$(builddir)/disassembler.lo: $(XCACHE_PROC_H) $(srcdir)/processor.c
+disassembler.lo: $(XCACHE_PROC_H) $(srcdir)/processor.c
+
+$(builddir)/xcache.lo: $(XCACHE_PROC_H) $(srcdir)/myshm.h $(srcdir)/stack.h $(srcdir)/xcache_globals.h $(srcdir)/xcache.c
+xcache.lo: $(XCACHE_PROC_H) $(srcdir)/myshm.h $(srcdir)/stack.h $(srcdir)/xcache_globals.h $(srcdir)/xcache.c
Index: /tags/1.0/stack.h
===================================================================
--- /tags/1.0/stack.h	(revision 1)
+++ /tags/1.0/stack.h	(revision 1)
@@ -0,0 +1,17 @@
+
+typedef struct {
+	void **data;
+	int cnt;
+	int size;
+} xc_stack_t;
+
+#define S xc_stack_t*
+void xc_stack_init(S stack);
+void xc_stack_destroy(S stack);
+void xc_stack_push(S stack, void *item);
+void *xc_stack_pop(S stack);
+void *xc_stack_top(S stack);
+void *xc_stack_get(S stack, int n);
+int xc_stack_size(S stack);
+void xc_stack_reverse(S stack);
+#undef S
Index: /tags/1.0/mkopcode_spec.awk
===================================================================
--- /tags/1.0/mkopcode_spec.awk	(revision 52)
+++ /tags/1.0/mkopcode_spec.awk	(revision 52)
@@ -0,0 +1,38 @@
+#! /usr/bin/awk -f
+# vim:ts=4:sw=4
+# process eaccelerator/opcodes.c
+BEGIN {
+	FS=" "
+	max = 0;
+	started = 0
+}
+
+/OPDEF/ {
+	if (started) {
+		sub(/".*"/, "")
+		if (!match($0, /EXT_([^ |]+).*OP[1S]_([^ |]+).*OP2_([^ |]+).*RES_([^ |)]+).*/, array)) {
+			print "error" $0
+			exit
+		}
+		printf "\tOPSPEC(%10s, %10s, %10s, %10s)\n", array[1], array[2], array[3], array[4]
+		next
+	}
+}
+/^}/ {
+	print $0
+	exit;
+}
+/^[ ]*,[ ]*$/ {
+	next
+}
+{
+	if (started) {
+		print $0
+		next
+	}
+}
+
+/^static/ {
+	started = 1;
+	print "static const xc_opcode_spec_t xc_opcode_spec[] = {"
+}
Index: /tags/1.0/disassembler.c
===================================================================
--- /tags/1.0/disassembler.c	(revision 8)
+++ /tags/1.0/disassembler.c	(revision 8)
@@ -0,0 +1,157 @@
+#include "disassembler.h"
+#include "xcache.h"
+#include "utils.h"
+#include "processor.h"
+
+#define return_value dst
+
+#ifndef HAVE_XCACHE_OPCODE_SPEC_DEF
+#error disassembler cannot be built without xcache/opcode_spec_def.h
+#endif
+static void xc_dasm(zval *dst, zend_op_array *op_array TSRMLS_DC) /* {{{ */
+{
+	Bucket *b;
+	zval *zv, *list;
+	xc_compile_result_t cr;
+	int bufsize = 2;
+	char *buf;
+	int keysize;
+
+	xc_compile_result_init_cur(&cr, op_array TSRMLS_CC);
+
+	xc_apply_op_array(&cr, (apply_func_t) xc_undo_pass_two TSRMLS_CC);
+	xc_apply_op_array(&cr, (apply_func_t) xc_fix_opcode TSRMLS_CC);
+
+	/* go */
+	array_init(dst);
+
+	ALLOC_INIT_ZVAL(zv);
+	array_init(zv);
+	xc_dasm_zend_op_array(zv, op_array TSRMLS_CC);
+	add_assoc_zval_ex(dst, ZEND_STRS("op_array"), zv);
+
+	ALLOC_INIT_ZVAL(list);
+	array_init(list);
+	xc_dasm_HashTable_zend_function(list, CG(function_table) TSRMLS_CC);
+	add_assoc_zval_ex(dst, ZEND_STRS("function_table"), list);
+	
+	buf = emalloc(bufsize);
+	ALLOC_INIT_ZVAL(list);
+	array_init(list);
+	for (b = CG(class_table)->pListHead; b; b = b->pListNext) {
+		ALLOC_INIT_ZVAL(zv);
+		array_init(zv);
+		xc_dasm_zend_class_entry(zv, CestToCePtr(*(xc_cest_t *)b->pData) TSRMLS_CC);
+
+		keysize = BUCKET_KEY_SIZE(b) + 2;
+		if (keysize > bufsize) {
+			do {
+				bufsize *= 2;
+			} while (keysize > bufsize);
+			buf = erealloc(buf, bufsize);
+		}
+		memcpy(buf, BUCKET_KEY(b), keysize);
+		buf[keysize - 2] = buf[keysize - 1] = ""[0];
+		keysize = b->nKeyLength;
+#ifdef IS_UNICODE
+		if (BUCKET_KEY_TYPE(b) == IS_UNICODE) {
+			if (buf[0] == ""[0] && buf[1] == ""[0]) {
+				keysize ++;
+			}
+		} else
+#endif
+		{
+			if (buf[0] == ""[0]) {
+				keysize ++;
+			}
+		}
+		add_u_assoc_zval_ex(list, BUCKET_KEY_TYPE(b), buf, b->nKeyLength, zv);
+	}
+	efree(buf);
+	add_assoc_zval_ex(dst, ZEND_STRS("class_table"), list);
+
+	/*xc_apply_op_array(&cr, (apply_func_t) xc_redo_pass_two TSRMLS_CC);*/
+	xc_compile_result_free(&cr);
+
+	return;
+}
+/* }}} */
+void xc_dasm_string(zval *dst, zval *source TSRMLS_DC) /* {{{ */
+{
+	int catched;
+	zend_op_array *op_array = NULL;
+	xc_sandbox_t sandbox;
+	char *eval_name = zend_make_compiled_string_description("runtime-created function" TSRMLS_CC);
+
+	xc_sandbox_init(&sandbox, eval_name TSRMLS_CC);
+
+	catched = 0;
+	zend_try {
+		op_array = compile_string(source, eval_name TSRMLS_CC);
+	} zend_catch {
+		catched = 1;
+	} zend_end_try();
+
+	if (catched || !op_array) {
+		goto err_compile;
+	}
+
+	xc_dasm(dst, op_array TSRMLS_CC);
+
+	/* free */
+	efree(eval_name);
+	destroy_op_array(op_array TSRMLS_CC);
+	efree(op_array);
+	xc_sandbox_free(&sandbox, 0 TSRMLS_CC);
+	return;
+
+err_compile:
+	efree(eval_name);
+	xc_sandbox_free(&sandbox, 0 TSRMLS_CC);
+
+	RETURN_FALSE;
+}
+/* }}} */
+void xc_dasm_file(zval *dst, const char *filename TSRMLS_DC) /* {{{ */
+{
+	int catched;
+	zend_op_array *op_array = NULL;
+	xc_sandbox_t sandbox;
+	zval *zfilename;
+
+	MAKE_STD_ZVAL(zfilename);
+	zfilename->value.str.val = estrdup(filename);
+	zfilename->value.str.len = strlen(filename);
+	zfilename->type = IS_STRING;
+
+	xc_sandbox_init(&sandbox, zfilename->value.str.val TSRMLS_CC);
+
+	catched = 0;
+	zend_try {
+		op_array = compile_filename(ZEND_REQUIRE, zfilename TSRMLS_CC);
+	} zend_catch {
+		catched = 1;
+	} zend_end_try();
+
+	if (catched || !op_array) {
+		goto err_compile;
+	}
+
+	xc_dasm(dst, op_array TSRMLS_CC);
+
+	/* free */
+	destroy_op_array(op_array TSRMLS_CC);
+	efree(op_array);
+	xc_sandbox_free(&sandbox, 0 TSRMLS_CC);
+	zval_dtor(zfilename);
+	FREE_ZVAL(zfilename);
+	return;
+
+err_compile:
+	xc_sandbox_free(&sandbox, 0 TSRMLS_CC);
+
+	zval_dtor(zfilename);
+	FREE_ZVAL(zfilename);
+	RETURN_FALSE;
+}
+/* }}} */
Index: /tags/1.0/coverager.c
===================================================================
--- /tags/1.0/coverager.c	(revision 51)
+++ /tags/1.0/coverager.c	(revision 51)
@@ -0,0 +1,434 @@
+#include <stdio.h>
+#include "xcache.h"
+#include "ext/standard/flock_compat.h"
+#ifdef HAVE_SYS_FILE_H
+#	include <sys/file.h>
+#endif
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include "stack.h"
+#include "xcache_globals.h"
+#include "coverager.h"
+#include "utils.h"
+typedef HashTable *coverager_t;
+#define PCOV_HEADER_MAGIC 0x564f4350
+
+char *xc_coveragedump_dir = NULL;
+static zend_compile_file_t *origin_compile_file;
+
+#undef DEBUG
+/* dumper */
+static void xc_destroy_coverage(void *pDest) /* {{{ */
+{
+	coverager_t cov = *(coverager_t*) pDest;
+#ifdef DEBUG
+	fprintf(stderr, "destroy %p\n", cov);
+#endif
+	zend_hash_destroy(cov);
+	efree(cov);
+}
+/* }}} */
+void xcache_mkdirs_ex(char *root, int rootlen, char *path, int pathlen TSRMLS_DC) /* {{{ */
+{
+	char *fullpath;
+	struct stat st;
+
+#ifdef DEBUG
+	fprintf(stderr, "mkdirs %s %d %s %d\n", root, rootlen, path, pathlen);
+#endif
+	fullpath = do_alloca(rootlen + pathlen + 1);
+	memcpy(fullpath, root, rootlen);
+	memcpy(fullpath + rootlen, path, pathlen);
+	fullpath[rootlen + pathlen] = '\0';
+
+	if (stat(fullpath, &st) != 0) {
+		char *chr;
+
+		chr = strrchr(path, PHP_DIR_SEPARATOR);
+		if (chr && chr != path) {
+			*chr = '\0';
+			xcache_mkdirs_ex(root, rootlen, path, chr - path TSRMLS_CC);
+			*chr = PHP_DIR_SEPARATOR;
+		}
+#ifdef DEBUG
+		fprintf(stderr, "mkdir %s\n", fullpath);
+#endif
+#if PHP_MAJOR_VERSION > 5
+		php_stream_mkdir(fullpath, 0700, REPORT_ERRORS, NULL);
+#else
+		mkdir(fullpath, 0700);
+#endif
+	}
+	free_alloca(fullpath);
+}
+/* }}} */
+static void xc_coverager_save_cov(char *srcfile, char *outfilename, coverager_t cov TSRMLS_DC) /* {{{ */
+{
+	long *buf = NULL, *p;
+	long covlines, *phits;
+	int fd = -1;
+	int size;
+	int newfile;
+	struct stat srcstat, outstat;
+	HashPosition pos;
+	char *contents = NULL;
+	long len;
+
+	if (stat(srcfile, &srcstat) != 0) {
+		return;
+	}
+
+	newfile = 0;
+	if (stat(outfilename, &outstat) != 0) {
+		newfile = 1;
+	}
+	else {
+		if (srcstat.st_mtime > outstat.st_mtime) {
+			newfile = 1;
+		}
+	}
+
+	fd = open(outfilename, O_RDWR | O_CREAT, 0600);
+	if (fd < 0) {
+		char *chr;
+		chr = strrchr(srcfile, PHP_DIR_SEPARATOR);
+		if (chr) {
+			*chr = '\0';
+			xcache_mkdirs_ex(xc_coveragedump_dir, strlen(xc_coveragedump_dir), srcfile, chr - srcfile TSRMLS_CC);
+			*chr = PHP_DIR_SEPARATOR;
+		}
+		fd = open(outfilename, O_RDWR | O_CREAT, 0600);
+		if (fd < 0) {
+			goto bailout;
+		}
+	}
+	if (flock(fd, LOCK_EX) != SUCCESS) {
+		goto bailout;
+	}
+
+	if (newfile) {
+#ifdef DEBUG
+		fprintf(stderr, "new file\n");
+#endif
+	}
+	else if (outstat.st_size) {
+		len = outstat.st_size;
+		contents = emalloc(len);
+		if (read(fd, (void *) contents, len) != len) {
+			goto bailout;
+		}
+#ifdef DEBUG
+		fprintf(stderr, "oldsize %d\n", (int) len);
+#endif
+		do {
+			p = (long *) contents;
+			len -= sizeof(long);
+			if (len < 0) {
+				break;
+			}
+			if (*p++ != PCOV_HEADER_MAGIC) {
+#ifdef DEBUG
+				fprintf(stderr, "wrong magic in file %s\n", outfilename);
+#endif
+				break;
+			}
+
+			p += 2; /* skip covliens */
+			len -= sizeof(long) * 2;
+			if (len < 0) {
+				break;
+			}
+
+			for (; len >= sizeof(long) * 2; len -= sizeof(long) * 2, p += 2) {
+				if (zend_hash_index_find(cov, p[0], (void**)&phits) == SUCCESS) {
+					if (p[1] <= 0) {
+						/* already marked */
+						continue;
+					}
+					if (*phits > 0) {
+						p[1] += *phits;
+					}
+				}
+				zend_hash_index_update(cov, p[0], &p[1], sizeof(p[1]), NULL);
+			}
+		} while (0);
+		efree(contents);
+		contents = NULL;
+	}
+
+
+	/* serialize */
+	size = (zend_hash_num_elements(cov) + 1) * sizeof(long) * 2 + sizeof(long);
+	p = buf = emalloc(size);
+	*p++ = PCOV_HEADER_MAGIC;
+	p += 2; /* for covlines */
+	covlines = 0;
+
+	zend_hash_internal_pointer_reset_ex(cov, &pos);
+	while (zend_hash_get_current_data_ex(cov, (void**)&phits, &pos) == SUCCESS) {
+		*p++ = pos->h;
+		if (*phits <= 0) {
+			*p++ = 0;
+		}
+		else {
+			*p++ = *phits;
+			covlines ++;
+		}
+		zend_hash_move_forward_ex(cov, &pos);
+	}
+	p = buf + 1;
+	p[0] = 0;
+	p[1] = covlines;
+
+	ftruncate(fd, 0);
+	lseek(fd, 0, SEEK_SET);
+	write(fd, (char *) buf, size);
+
+bailout:
+	if (contents) efree(contents);
+	if (fd >= 0) close(fd);
+	if (buf) efree(buf);
+}
+/* }}} */
+void xc_coverager_request_init(TSRMLS_D) /* {{{ */
+{
+	if (XG(coveragedumper)) {
+		XG(coverages) = emalloc(sizeof(HashTable));
+		zend_hash_init(XG(coverages), 0, NULL, xc_destroy_coverage, 0);
+	}
+}
+/* }}} */
+void xc_coverager_request_shutdown(TSRMLS_D) /* {{{ */
+{
+	coverager_t *pcov;
+	zstr s;
+	char *outfilename;
+	int dumpdir_len, outfilelen, size, alloc_len = 0;
+
+	if (!XG(coverages)) {
+		return;
+	}
+	if (XG(coveragedumper)) {	
+		dumpdir_len = strlen(xc_coveragedump_dir);
+		alloc_len = dumpdir_len + 1 + 128;
+		outfilename = emalloc(alloc_len);
+		strcpy(outfilename, xc_coveragedump_dir);
+
+		zend_hash_internal_pointer_reset(XG(coverages));
+		while (zend_hash_get_current_data(XG(coverages), (void **) &pcov) == SUCCESS) {
+			zend_hash_get_current_key_ex(XG(coverages), &s, &size, NULL, 0, NULL);
+			outfilelen = dumpdir_len + size + 5;
+			if (alloc_len < outfilelen) {
+				alloc_len = outfilelen + 128;
+				outfilename = erealloc(outfilename, alloc_len);
+			}
+			strcpy(outfilename + dumpdir_len, ZSTR_S(s));
+			strcpy(outfilename + dumpdir_len + size - 1, ".pcov");
+
+#ifdef DEBUG
+			fprintf(stderr, "outfilename %s\n", outfilename);
+#endif
+			xc_coverager_save_cov(ZSTR_S(s), outfilename, *pcov TSRMLS_CC);
+			zend_hash_move_forward(XG(coverages));
+		}
+	}
+
+	zend_hash_destroy(XG(coverages));
+	efree(XG(coverages));
+	XG(coverages) = NULL;
+}
+/* }}} */
+
+/* helper func to store hits into coverages */
+static coverager_t xc_coverager_get(char *filename TSRMLS_DC) /* {{{ */
+{
+	int len = strlen(filename) + 1;
+	coverager_t cov, *pcov;
+
+	if (zend_hash_find(XG(coverages), filename, len, (void **) &pcov) == SUCCESS) {
+#ifdef DEBUG
+		fprintf(stderr, "got coverage %s %p\n", filename, *pcov);
+#endif
+		return *pcov;
+	}
+	else {
+		cov = emalloc(sizeof(HashTable));
+		zend_hash_init(cov, 0, NULL, NULL, 0);
+		zend_hash_add(XG(coverages), filename, len, (void **) &cov, sizeof(cov), NULL);
+#ifdef DEBUG
+		fprintf(stderr, "new coverage %s %p\n", filename, cov);
+#endif
+		return cov;
+	}
+}
+/* }}} */
+static void xc_coverager_add_hits(HashTable *cov, long line, long hits TSRMLS_DC) /* {{{ */
+{
+	long *poldhits;
+
+	if (line == 0) {
+		return;
+	}
+	if (zend_hash_index_find(cov, line, (void**)&poldhits) == SUCCESS) {
+		if (hits == -1) {
+			/* already marked */
+			return;
+		}
+		if (*poldhits != -1) {
+			hits += *poldhits;
+		}
+	}
+	zend_hash_index_update(cov, line, &hits, sizeof(hits), NULL);
+}
+/* }}} */
+
+static int xc_coverager_get_op_array_size_no_tail(zend_op_array *op_array) /* {{{ */
+{
+	zend_uint size;
+
+	size = op_array->size;
+#ifdef ZEND_ENGINE_2
+	if (op_array->opcodes[size - 1].opcode == ZEND_HANDLE_EXCEPTION) {
+		size --;
+#endif
+		if (op_array->opcodes[size - 1].opcode == ZEND_RETURN) {
+			size --;
+			/* it's not real php statement */
+			if (op_array->opcodes[size - 1].opcode == ZEND_EXT_STMT) {
+				size --;
+			}
+		}   
+#ifdef ZEND_ENGINE_2
+	}
+#endif
+	return size;
+}
+/* }}} */
+
+/* prefill */
+static int xc_coverager_init_op_array(zend_op_array *op_array TSRMLS_DC) /* {{{ */
+{
+	zend_uint size;
+	coverager_t cov;
+	zend_uint i;
+
+	if (op_array->type != ZEND_USER_FUNCTION) {
+		return 0;
+	}
+
+	size = xc_coverager_get_op_array_size_no_tail(op_array);
+	cov = xc_coverager_get(op_array->filename TSRMLS_CC);
+	for (i = 0; i < size; i ++) {
+		switch (op_array->opcodes[i].opcode) {
+			case ZEND_EXT_STMT:
+#if 0
+			case ZEND_EXT_FCALL_BEGIN:
+			case ZEND_EXT_FCALL_END:
+#endif
+				xc_coverager_add_hits(cov, op_array->opcodes[i].lineno, -1 TSRMLS_CC);
+				break;
+		}
+	}
+	return 0;
+}
+/* }}} */
+static void xc_coverager_init_compile_result(zend_op_array *op_array TSRMLS_DC) /* {{{ */
+{
+	xc_compile_result_t cr;
+
+	xc_compile_result_init_cur(&cr, op_array TSRMLS_CC);
+	xc_apply_op_array(&cr, (apply_func_t) xc_coverager_init_op_array TSRMLS_CC);
+	xc_compile_result_free(&cr);
+}
+/* }}} */
+static zend_op_array *xc_compile_file_for_coverage(zend_file_handle *h, int type TSRMLS_DC) /* {{{ */
+{
+	zend_op_array *op_array;
+
+	op_array = origin_compile_file(h, type TSRMLS_CC);
+	if (XG(coveragedumper) && XG(coverages)) {
+		xc_coverager_init_compile_result(op_array TSRMLS_CC);
+	}
+	return op_array;
+}
+/* }}} */
+
+/* hits */
+void xc_coverager_handle_ext_stmt(zend_op_array *op_array, zend_uchar op) /* {{{ */
+{
+	TSRMLS_FETCH();
+
+	if (XG(coveragedumper) && XG(coverages)) {
+		int size = xc_coverager_get_op_array_size_no_tail(op_array);
+		int oplineno = (*EG(opline_ptr)) - op_array->opcodes;
+		if (oplineno < size) {
+			xc_coverager_add_hits(xc_coverager_get(op_array->filename TSRMLS_CC), (*EG(opline_ptr))->lineno, 1 TSRMLS_CC);
+		}
+	}
+}
+/* }}} */
+
+/* init/destroy */
+int xc_coverager_init(int module_number TSRMLS_DC) /* {{{ */
+{
+	if (xc_coveragedump_dir) {
+		int len = strlen(xc_coveragedump_dir);
+		if (len) {
+			if (xc_coveragedump_dir[len - 1] == '/') {
+				xc_coveragedump_dir[len - 1] = '\0';
+			}
+		}
+	}
+	if (xc_coveragedump_dir && xc_coveragedump_dir[0]) {
+		origin_compile_file = zend_compile_file;
+		zend_compile_file = xc_compile_file_for_coverage;
+		CG(extended_info) = 1;
+	}
+	return SUCCESS;
+}
+/* }}} */
+void xc_coverager_destroy() /* {{{ */
+{
+	if (origin_compile_file == xc_compile_file_for_coverage) {
+		zend_compile_file = origin_compile_file;
+	}
+	if (xc_coveragedump_dir) {
+		pefree(xc_coveragedump_dir, 1);
+		xc_coveragedump_dir = NULL;
+	}
+}
+/* }}} */
+
+/* user api */
+PHP_FUNCTION(xcache_coverager_decode) /* {{{ */
+{
+	char *str;
+	int len;
+	long *p;
+
+	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &len) == FAILURE) {
+		return;
+	}
+
+	array_init(return_value);
+
+	p = (long*) str;
+	len -= sizeof(long);
+	if (len < 0) {
+		return;
+	}
+	if (*p++ != PCOV_HEADER_MAGIC) {
+#ifdef DEBUG
+		fprintf(stderr, "wrong magic in xcache_coverager_decode");
+#endif
+		return;
+	}
+
+	for (; len >= sizeof(long) * 2; len -= sizeof(long) * 2, p += 2) {
+		add_index_long(return_value, p[0], p[1]);
+	}
+}
+/* }}} */
+
Index: /tags/1.0/prepare.devel.inc.example
===================================================================
--- /tags/1.0/prepare.devel.inc.example	(revision 43)
+++ /tags/1.0/prepare.devel.inc.example	(revision 43)
@@ -0,0 +1,7 @@
+# copy this file to devel.prepare.inc before modifying
+PHP4_x_DIR=
+PHP5_0_DIR=
+PHP5_1_DIR=
+PHP6_x_DIR=
+
+PHP_DEVEL_DIR=
Index: /tags/1.0/processor.c
===================================================================
--- /tags/1.0/processor.c	(revision 1)
+++ /tags/1.0/processor.c	(revision 1)
@@ -0,0 +1,1 @@
+#include "processor_real.c"
