Index: /tags/3.0.0-rc1/mod_coverager/xc_coverager.c
===================================================================
--- /tags/3.0.0-rc1/mod_coverager/xc_coverager.c	(revision 1118)
+++ /tags/3.0.0-rc1/mod_coverager/xc_coverager.c	(revision 1118)
@@ -0,0 +1,718 @@
+#if 0
+#define XCACHE_DEBUG
+#endif
+
+#include "xc_coverager.h"
+
+#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 "xcache/xc_extension.h"
+#include "xcache/xc_ini.h"
+#include "xcache/xc_utils.h"
+#include "util/xc_stack.h"
+#include "util/xc_trace.h"
+#include "xcache_globals.h"
+
+#include "ext/standard/info.h"
+#include "zend_compile.h"
+
+typedef HashTable *coverager_t;
+#define PCOV_HEADER_MAGIC 0x564f4350
+
+static char *xc_coveragedump_dir = NULL;
+static zend_compile_file_t *old_compile_file = NULL;
+
+/* dumper */
+static void xc_destroy_coverage(void *pDest) /* {{{ */
+{
+	coverager_t cov = *(coverager_t*) pDest;
+	TRACE("destroy %p", cov);
+	zend_hash_destroy(cov);
+	efree(cov);
+}
+/* }}} */
+static void xcache_mkdirs_ex(char *root, int rootlen, char *path, int pathlen TSRMLS_DC) /* {{{ */
+{
+	char *fullpath;
+	struct stat st;
+	ALLOCA_FLAG(use_heap)
+
+	TRACE("mkdirs %s %d %s %d", root, rootlen, path, pathlen);
+	fullpath = my_do_alloca(rootlen + pathlen + 1, use_heap);
+	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;
+		}
+		TRACE("mkdir %s", fullpath);
+#if PHP_MAJOR_VERSION > 5
+		php_stream_mkdir(fullpath, 0700, REPORT_ERRORS, NULL);
+#else
+		mkdir(fullpath, 0700);
+#endif
+	}
+	my_free_alloca(fullpath, use_heap);
+}
+/* }}} */
+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) {
+		TRACE("%s", "new file");
+	}
+	else if (outstat.st_size) {
+		len = outstat.st_size;
+		contents = emalloc(len);
+		if (read(fd, (void *) contents, len) != len) {
+			goto bailout;
+		}
+		TRACE("oldsize %d", (int) len);
+		do {
+			p = (long *) contents;
+			len -= sizeof(long);
+			if (len < 0) {
+				break;
+			}
+			if (*p++ != PCOV_HEADER_MAGIC) {
+				TRACE("wrong magic in file %s", outfilename);
+				break;
+			}
+
+			p += 2; /* skip covliens */
+			len -= sizeof(long) * 2;
+			if (len < 0) {
+				break;
+			}
+
+			for (; len >= (int) sizeof(long) * 2; len -= sizeof(long) * 2, p += 2) {
+				if (zend_hash_index_find(cov, p[0], (void**)&phits) == SUCCESS) {
+					if (p[1] == -1) {
+						/* OPTIMIZE: already marked */
+						continue;
+					}
+					if (*phits != -1) {
+						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;
+		*p++ = *phits;
+		if (*phits > 0) {
+			covlines ++;
+		}
+		zend_hash_move_forward_ex(cov, &pos);
+	}
+	p = buf + 1;
+	p[0] = 0;
+	p[1] = covlines;
+
+	if (ftruncate(fd, 0) != 0) {
+		goto bailout;
+	}
+	lseek(fd, 0, SEEK_SET);
+	if (write(fd, (char *) buf, size) != size) {
+		goto bailout;
+	}
+
+bailout:
+	if (contents) efree(contents);
+	if (fd >= 0) close(fd);
+	if (buf) efree(buf);
+}
+/* }}} */
+
+static void xc_coverager_initenv(TSRMLS_D) /* {{{ */
+{
+	if (!XG(coverages)) {
+		XG(coverages) = emalloc(sizeof(HashTable));
+		zend_hash_init(XG(coverages), 0, NULL, xc_destroy_coverage, 0);
+	}
+}
+/* }}} */
+static void xc_coverager_clean(TSRMLS_D) /* {{{ */
+{
+	if (XG(coverages)) {
+		HashPosition pos;
+		coverager_t *pcov;
+
+		zend_hash_internal_pointer_reset_ex(XG(coverages), &pos);
+		while (zend_hash_get_current_data_ex(XG(coverages), (void **) &pcov, &pos) == SUCCESS) {
+			long *phits;
+			coverager_t cov;
+			HashPosition pos2;
+
+			cov = *pcov;
+
+			zend_hash_internal_pointer_reset_ex(cov, &pos2);
+			while (zend_hash_get_current_data_ex(cov, (void**)&phits, &pos2) == SUCCESS) {
+				long hits = *phits;
+
+				if (hits != -1) {
+					hits = -1;
+					zend_hash_index_update(cov, pos2->h, &hits, sizeof(hits), NULL);
+				}
+				zend_hash_move_forward_ex(cov, &pos2);
+			}
+
+			zend_hash_move_forward_ex(XG(coverages), &pos);
+		}
+	}
+}
+/* }}} */
+static void xc_coverager_cleanup(TSRMLS_D) /* {{{ */
+{
+	if (XG(coverages)) {
+		zend_hash_destroy(XG(coverages));
+		efree(XG(coverages));
+		XG(coverages) = NULL;
+	}
+}
+/* }}} */
+
+static void xc_coverager_start(TSRMLS_D) /* {{{ */
+{
+	XG(coverager_started) = 1;
+}
+/* }}} */
+static void xc_coverager_stop(TSRMLS_D) /* {{{ */
+{
+	XG(coverager_started) = 0;
+}
+/* }}} */
+
+static PHP_RINIT_FUNCTION(xcache_coverager) /* {{{ */
+{
+	if (XG(coverager)) {
+		if (XG(coverager_autostart)) {
+			xc_coverager_start(TSRMLS_C);
+		}
+#ifdef ZEND_COMPILE_EXTENDED_INFO
+		CG(compiler_options) |= ZEND_COMPILE_EXTENDED_INFO;
+#else
+		CG(extended_info) = 1;
+#endif
+	}
+	else {
+		XG(coverager_started) = 0;
+	}
+	return SUCCESS;
+}
+/* }}} */
+static void xc_coverager_autodump(TSRMLS_D) /* {{{ */
+{
+	coverager_t *pcov;
+	zstr s;
+	char *outfilename;
+	int dumpdir_len, outfilelen, alloc_len = 0;
+	uint size;
+	HashPosition pos;
+
+	if (XG(coverages) && xc_coveragedump_dir) {	
+		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_ex(XG(coverages), &pos);
+		while (zend_hash_get_current_data_ex(XG(coverages), (void **) &pcov, &pos) == SUCCESS) {
+			zend_hash_get_current_key_ex(XG(coverages), &s, &size, NULL, 0, &pos);
+			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");
+
+			TRACE("outfilename %s", outfilename);
+			xc_coverager_save_cov(ZSTR_S(s), outfilename, *pcov TSRMLS_CC);
+			zend_hash_move_forward_ex(XG(coverages), &pos);
+		}
+		efree(outfilename);
+	}
+}
+/* }}} */
+static void xc_coverager_dump(zval *return_value TSRMLS_DC) /* {{{ */
+{
+	coverager_t *pcov;
+	HashPosition pos;
+
+	if (XG(coverages)) {
+		array_init(return_value);
+
+		zend_hash_internal_pointer_reset_ex(XG(coverages), &pos);
+		while (zend_hash_get_current_data_ex(XG(coverages), (void **) &pcov, &pos) == SUCCESS) {
+			zval *lines;
+			long *phits;
+			coverager_t cov;
+			HashPosition pos2;
+			zstr filename;
+			uint size;
+
+			cov = *pcov;
+			zend_hash_get_current_key_ex(XG(coverages), &filename, &size, NULL, 0, &pos);
+
+			MAKE_STD_ZVAL(lines);
+			array_init(lines);
+			zend_hash_internal_pointer_reset_ex(cov, &pos2);
+			while (zend_hash_get_current_data_ex(cov, (void**)&phits, &pos2) == SUCCESS) {
+				long hits = *phits;
+				add_index_long(lines, pos2->h, hits >= 0 ? hits : 0);
+				zend_hash_move_forward_ex(cov, &pos2);
+			}
+			add_assoc_zval_ex(return_value, ZSTR_S(filename), strlen(ZSTR_S(filename)) + 1, lines);
+
+			zend_hash_move_forward_ex(XG(coverages), &pos);
+		}
+	}
+	else {
+		RETVAL_NULL();
+	}
+}
+/* }}} */
+static PHP_RSHUTDOWN_FUNCTION(xcache_coverager) /* {{{ */
+{
+	if (XG(coverager)) {
+		xc_coverager_autodump(TSRMLS_C);
+		xc_coverager_cleanup(TSRMLS_C);
+	}
+	return SUCCESS;
+}
+/* }}} */
+
+/* helper func to store hits into coverages */
+static coverager_t xc_coverager_get(const char *filename TSRMLS_DC) /* {{{ */
+{
+	int len = strlen(filename) + 1;
+	coverager_t cov, *pcov;
+
+	if (zend_u_hash_find(XG(coverages), IS_STRING, filename, len, (void **) &pcov) == SUCCESS) {
+		TRACE("got coverage %s %p", filename, *pcov);
+		return *pcov;
+	}
+	else {
+		cov = emalloc(sizeof(HashTable));
+		zend_hash_init(cov, 0, NULL, NULL, 0);
+		zend_u_hash_add(XG(coverages), IS_STRING, filename, len, (void **) &cov, sizeof(cov), NULL);
+		TRACE("new coverage %s %p", filename, cov);
+		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) {
+			/* OPTIMIZE: -1 == init-ing, but it's already initized */
+			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 last = op_array->last;
+	do {
+next_op:
+		if (last == 0) {
+			break;
+		}
+		switch (op_array->opcodes[last - 1].opcode) {
+#ifdef ZEND_HANDLE_EXCEPTION
+			case ZEND_HANDLE_EXCEPTION:
+#endif
+			case ZEND_RETURN:
+			case ZEND_EXT_STMT:
+				--last;
+				goto next_op;
+		}
+	} while (0);
+	return last;
+}
+/* }}} */
+
+/* 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 = old_compile_file(h, type TSRMLS_CC);
+	if (op_array) {
+		if (XG(coverager)) {
+			xc_coverager_initenv(TSRMLS_C);
+			xc_coverager_init_compile_result(op_array TSRMLS_CC);
+		}
+	}
+	return op_array;
+}
+/* }}} */
+
+/* hits */
+static void xc_coverager_handle_ext_stmt(zend_op_array *op_array, zend_uchar op) /* {{{ */
+{
+	TSRMLS_FETCH();
+
+	if (XG(coverages) && XG(coverager_started)) {
+		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);
+		}
+	}
+}
+/* }}} */
+
+/* user api */
+/* {{{ proto array xcache_coverager_decode(string data)
+ * decode specified data which is saved by auto dumper to array
+ */
+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) {
+		TRACE("%s", "wrong magic in xcache_coverager_decode");
+		return;
+	}
+
+	for (; len >= (int) sizeof(long) * 2; len -= sizeof(long) * 2, p += 2) {
+		add_index_long(return_value, p[0], p[1] < 0 ? 0 : p[1]);
+	}
+}
+/* }}} */
+/* {{{ proto void xcache_coverager_start([bool clean = true])
+ * starts coverager data collecting
+ */
+PHP_FUNCTION(xcache_coverager_start)
+{
+	zend_bool clean = 1;
+
+	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &clean) == FAILURE) {
+		return;
+	}
+
+	if (clean) {
+		xc_coverager_clean(TSRMLS_C);
+	}
+
+	if (XG(coverager)) {
+		xc_coverager_start(TSRMLS_C);
+	}
+	else {
+		php_error(E_WARNING, "You can only start coverager after you set 'xcache.coverager' to 'On' in ini");
+	}
+}
+/* }}} */
+/* {{{ proto void xcache_coverager_stop([bool clean = false])
+ * stop coverager data collecting
+ */
+PHP_FUNCTION(xcache_coverager_stop)
+{
+	zend_bool clean = 0;
+
+	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &clean) == FAILURE) {
+		return;
+	}
+
+	xc_coverager_stop(TSRMLS_C);
+	if (clean) {
+		xc_coverager_clean(TSRMLS_C);
+	}
+}
+/* }}} */
+/* {{{ proto array xcache_coverager_get([bool clean = false])
+ * get coverager data collected
+ */
+PHP_FUNCTION(xcache_coverager_get)
+{
+	zend_bool clean = 0;
+	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &clean) == FAILURE) {
+		return;
+	}
+
+	xc_coverager_dump(return_value TSRMLS_CC);
+	if (clean) {
+		xc_coverager_clean(TSRMLS_C);
+	}
+}
+/* }}} */
+static zend_function_entry xcache_coverager_functions[] = /* {{{ */
+{
+	PHP_FE(xcache_coverager_decode,  NULL)
+	PHP_FE(xcache_coverager_start,   NULL)
+	PHP_FE(xcache_coverager_stop,    NULL)
+	PHP_FE(xcache_coverager_get,     NULL)
+	PHP_FE_END
+};
+/* }}} */
+
+static int xc_coverager_zend_startup(zend_extension *extension) /* {{{ */
+{
+	old_compile_file = zend_compile_file;
+	zend_compile_file = xc_compile_file_for_coverage;
+
+	return SUCCESS;
+}
+/* }}} */
+static void xc_coverager_zend_shutdown(zend_extension *extension) /* {{{ */
+{
+	/* empty */
+}
+/* }}} */
+static void xc_statement_handler(zend_op_array *op_array) /* {{{ */
+{
+	xc_coverager_handle_ext_stmt(op_array, ZEND_EXT_STMT);
+}
+/* }}} */
+static void xc_fcall_begin_handler(zend_op_array *op_array) /* {{{ */
+{
+#if 0
+	xc_coverager_handle_ext_stmt(op_array, ZEND_EXT_FCALL_BEGIN);
+#endif
+}
+/* }}} */
+static void xc_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 */
+static zend_extension xc_coverager_zend_extension_entry = {
+	XCACHE_NAME " Coverager",
+	XCACHE_VERSION,
+	XCACHE_AUTHOR,
+	XCACHE_URL,
+	XCACHE_COPYRIGHT,
+	xc_coverager_zend_startup,
+	xc_coverager_zend_shutdown,
+	NULL,           /* activate_func_t */
+	NULL,           /* deactivate_func_t */
+	NULL,           /* message_handler_func_t */
+	NULL,           /* statement_handler_func_t */
+	xc_statement_handler,
+	xc_fcall_begin_handler,
+	xc_fcall_end_handler,
+	NULL,           /* op_array_ctor_func_t */
+	NULL,           /* op_array_dtor_func_t */
+	STANDARD_ZEND_EXTENSION_PROPERTIES
+};
+/* }}} */
+/* {{{ PHP_INI */
+PHP_INI_BEGIN()
+	STD_PHP_INI_BOOLEAN("xcache.coverager",              "0", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateBool, coverager,           zend_xcache_globals, xcache_globals)
+	STD_PHP_INI_BOOLEAN("xcache.coverager_autostart",    "1", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateBool, coverager_autostart, zend_xcache_globals, xcache_globals)
+	PHP_INI_ENTRY1     ("xcache.coveragedump_directory",  "", PHP_INI_SYSTEM, xcache_OnUpdateDummy, NULL)
+PHP_INI_END()
+/* }}} */
+static PHP_MINFO_FUNCTION(xcache_coverager) /* {{{ */
+{
+	char *covdumpdir;
+
+	php_info_print_table_start();
+	php_info_print_table_row(2, "XCache Coverager Module", "enabled");
+	if (cfg_get_string("xcache.coveragedump_directory", &covdumpdir) != SUCCESS || !covdumpdir[0]) {
+		covdumpdir = NULL;
+	}
+	php_info_print_table_row(2, "Coverage Started", XG(coverager_started) && covdumpdir ? "On" : "Off");
+	php_info_print_table_end();
+
+	DISPLAY_INI_ENTRIES();
+}
+/* }}} */
+static PHP_MINIT_FUNCTION(xcache_coverager) /* {{{ */
+{
+	REGISTER_INI_ENTRIES();
+
+	if (cfg_get_string("xcache.coveragedump_directory", &xc_coveragedump_dir) == SUCCESS && xc_coveragedump_dir) {
+		int len;
+		xc_coveragedump_dir = pestrdup(xc_coveragedump_dir, 1);
+		len = strlen(xc_coveragedump_dir);
+		if (len) {
+			if (xc_coveragedump_dir[len - 1] == '/') {
+				xc_coveragedump_dir[len - 1] = '\0';
+			}
+		}
+		if (!strlen(xc_coveragedump_dir)) {
+			pefree(xc_coveragedump_dir, 1);
+			xc_coveragedump_dir = NULL;
+		}
+	}
+
+	return xcache_zend_extension_add(&xc_coverager_zend_extension_entry, 0);
+}
+/* }}} */
+static PHP_MSHUTDOWN_FUNCTION(xcache_coverager) /* {{{ */
+{
+	if (old_compile_file && zend_compile_file == xc_compile_file_for_coverage) {
+		zend_compile_file = old_compile_file;
+		old_compile_file = NULL;
+	}
+	if (xc_coveragedump_dir) {
+		pefree(xc_coveragedump_dir, 1);
+		xc_coveragedump_dir = NULL;
+	}
+	UNREGISTER_INI_ENTRIES();
+	return xcache_zend_extension_remove(&xc_coverager_zend_extension_entry);
+}
+/* }}} */
+
+static zend_module_entry xcache_coverager_module_entry = { /* {{{ */
+	STANDARD_MODULE_HEADER,
+	XCACHE_NAME " Coverager",
+	xcache_coverager_functions,
+	PHP_MINIT(xcache_coverager),
+	PHP_MSHUTDOWN(xcache_coverager),
+	PHP_RINIT(xcache_coverager),
+	PHP_RSHUTDOWN(xcache_coverager),
+	PHP_MINFO(xcache_coverager),
+	XCACHE_VERSION,
+#ifdef PHP_GINIT
+	NO_MODULE_GLOBALS,
+#endif
+#ifdef ZEND_ENGINE_2
+	NULL,
+#else
+	NULL,
+	NULL,
+#endif
+	STANDARD_MODULE_PROPERTIES_EX
+};
+/* }}} */
+int xc_coverager_startup_module() /* {{{ */
+{
+	return zend_startup_module(&xcache_coverager_module_entry);
+}
+/* }}} */
Index: /tags/3.0.0-rc1/mod_coverager/xc_coverager.h
===================================================================
--- /tags/3.0.0-rc1/mod_coverager/xc_coverager.h	(revision 1044)
+++ /tags/3.0.0-rc1/mod_coverager/xc_coverager.h	(revision 1044)
@@ -0,0 +1,12 @@
+#ifndef XC_COVERAGER_H_D5BB29AAB992B932E91C70A8C2F5D2B1
+#define XC_COVERAGER_H_D5BB29AAB992B932E91C70A8C2F5D2B1
+
+#if _MSC_VER > 1000
+#pragma once
+#endif /* _MSC_VER > 1000 */
+
+#include "php.h"
+
+int xc_coverager_startup_module();
+
+#endif /* XC_COVERAGER_H_D5BB29AAB992B932E91C70A8C2F5D2B1 */
Index: /tags/3.0.0-rc1/NEWS
===================================================================
--- /tags/3.0.0-rc1/NEWS	(revision 1146)
+++ /tags/3.0.0-rc1/NEWS	(revision 1146)
@@ -0,0 +1,84 @@
+3.0.0 2012-??-??
+========
+ * lots of improvements
+ * bug fixes
+ * updates api, adds a few ini
+ * uses extension= to load XCache. loading via zend_extension= is unsupported
+ * updates XCache admin page
+ * namespace support
+ * professional helpers
+   * adds an diagnosis module to give advise @ htdocs
+   * auto disable caching on crash @ runtime
+
+2.0.1 2012-07-14
+========
+ * improve stability
+ * admin/ config changed. please update accordingly
+ * PHP 5.3.14 is unstable. Please upgrade to new version. You have been warned
+ * fixed __FILE__ __DIR__ handling for moved/hardlinked files (set "xcache.experimental = on" to eanble this fix)
+
+2.0.0 2012-04-20
+========
+ * support for PHP_5_4
+ * reduce memory usage by caching 1 for multiple same content files
+ * correct __FILE__ __DIR__ supported for hardlinked files
+
+1.3.2 2011-06-04
+========
+ * admin page security fix
+ * adds 30 seconds timeout to "compiling" flag
+ * improves decompiling
+ * memory leak on recompile
+ * disassembler fixes and updates for new PHP
+ * win32 build fix
+ * improve compatibility with ionCube Loader
+
+1.3.1 2010-11-27
+========
+ * 2G/4G limitation on 64bit arch
+ * xcache_unset matching e.g. prefixed_ values
+
+1.3.0 2009-08-04
+========
+ * PHP 5.3 support
+ * many cacher/coverager bug fixes
+ * improved admin pages
+ * admin page is now magic quote gpc aware
+
+1.2.2 2007-12-29
+========
+ * live with wrong system time: allow caching files with mtime in further
+ * bug fix for compatibility with Zend Optimizer and other non-cachable
+ * a rare segv bug with token_get_all
+ * minor bug fixes
+
+1.2.1 2007-07-01
+========
+ * compatibility fix for apache 1.x, which init XCache module correctly
+ * full Zend Optimizer compatibility
+ * ini settings changed
+ * other bug fixes
+
+1.2.0 2006-12-10
+========
+ * full 5.2 support
+ * minor admin/coverage-viewer page improves
+ * compatible with suhosin/ZendOptimizer
+ * xcache_get reference handling
+ * new apis for coverager
+ * some ini settings changed
+
+1.1.0 2006-11-11
+========
+ * fix xcache_get issue on ttl 0 data
+ * avoid crash when php failed to compile file when coverager enabled
+ * gc expired items, new ini
+ * Partial php 5.2 support
+ * "Cannot redeclare ()" bug
+ * bug fixes
+ * Chinese Simplified/Traditional translations
+ * admin page fixes and applied phpinfo style
+ * coverage viewer page use phpinfo style
+ * fix build on rare arch and Mac OS X
+ * zts build
+ * includes all fixes from <=1.0.2
Index: /tags/3.0.0-rc1/xcache.c
===================================================================
--- /tags/3.0.0-rc1/xcache.c	(revision 1134)
+++ /tags/3.0.0-rc1/xcache.c	(revision 1134)
@@ -0,0 +1,794 @@
+/* {{{ macros */
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <signal.h>
+
+#include "xcache.h"
+
+#ifdef HAVE_XCACHE_OPTIMIZER
+#	include "mod_optimizer/xc_optimizer.h"
+#endif
+#ifdef HAVE_XCACHE_CACHER
+#	include "mod_cacher/xc_cacher.h"
+#endif
+#ifdef HAVE_XCACHE_COVERAGER
+#	include "mod_coverager/xc_coverager.h"
+#endif
+#ifdef HAVE_XCACHE_DISASSEMBLER
+#	include "mod_disassembler/xc_disassembler.h"
+#endif
+
+#include "xcache_globals.h"
+#include "xcache/xc_extension.h"
+#include "xcache/xc_ini.h"
+#include "xcache/xc_const_string.h"
+#include "xcache/xc_opcode_spec.h"
+#include "xcache/xc_utils.h"
+#include "util/xc_stack.h"
+
+#include "php.h"
+#include "ext/standard/info.h"
+#include "ext/standard/php_string.h"
+#include "SAPI.h"
+/* }}} */
+
+/* {{{ globals */
+static char *xc_coredump_dir = NULL;
+static zend_bool xc_disable_on_crash = 0;
+
+static zend_compile_file_t *old_compile_file = NULL;
+
+zend_bool xc_test = 0;
+
+ZEND_DECLARE_MODULE_GLOBALS(xcache)
+
+/* }}} */
+
+static zend_op_array *xc_check_initial_compile_file(zend_file_handle *h, int type TSRMLS_DC) /* {{{ */
+{
+	XG(initial_compile_file_called) = 1;
+	return old_compile_file(h, type TSRMLS_CC);
+}
+/* }}} */
+
+/* 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_nameinfo_t;
+	xc_nameinfo_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 }
+	};
+	int undefdone = 0;
+	xc_nameinfo_t *p;
+
+	for (p = nameinfos; p->getsize; p ++) {
+		zend_uchar i, count;
+		char const_name[96];
+		int const_name_len;
+
+		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_stringl_constant(ZEND_STRS("XCACHE_VERSION"), ZEND_STRL(XCACHE_VERSION), CONST_CS | CONST_PERSISTENT, module_number TSRMLS_CC);
+	zend_register_stringl_constant(ZEND_STRS("XCACHE_MODULES"), ZEND_STRL(XCACHE_MODULES), CONST_CS | CONST_PERSISTENT, module_number TSRMLS_CC);
+	return 0;
+}
+/* }}} */
+/* {{{ PHP_GINIT_FUNCTION(xcache) */
+#pragma GCC push_options
+#pragma GCC diagnostic ignored "-Wshadow"
+
+#ifdef PHP_GINIT_FUNCTION
+static PHP_GINIT_FUNCTION(xcache)
+#else
+static void xc_init_globals(zend_xcache_globals* xcache_globals TSRMLS_DC)
+#endif
+{
+#pragma GCC pop_options
+
+	memset(xcache_globals, 0, sizeof(zend_xcache_globals));
+
+#ifdef HAVE_XCACHE_CONSTANT
+	zend_hash_init_ex(&xcache_globals->internal_constant_table, 1, NULL, (dtor_func_t) xc_zend_constant_dtor, 1, 0);
+#endif
+	zend_hash_init_ex(&xcache_globals->internal_function_table, 1, NULL, NULL, 1, 0);
+	zend_hash_init_ex(&xcache_globals->internal_class_table,    1, NULL, NULL, 1, 0);
+}
+/* }}} */
+/* {{{ PHP_GSHUTDOWN_FUNCTION(xcache) */
+static
+#ifdef PHP_GSHUTDOWN_FUNCTION
+PHP_GSHUTDOWN_FUNCTION(xcache)
+#else
+void xc_shutdown_globals(zend_xcache_globals* xcache_globals TSRMLS_DC)
+#endif
+{
+	size_t i;
+
+	if (xcache_globals->php_holds != NULL) {
+		for (i = 0; i < xcache_globals->php_holds_size; i ++) {
+			xc_stack_destroy(&xcache_globals->php_holds[i]);
+		}
+		free(xcache_globals->php_holds);
+		xcache_globals->php_holds = NULL;
+		xcache_globals->php_holds_size = 0;
+	}
+
+	if (xcache_globals->var_holds != NULL) {
+		for (i = 0; i < xcache_globals->var_holds_size; i ++) {
+			xc_stack_destroy(&xcache_globals->var_holds[i]);
+		}
+		free(xcache_globals->var_holds);
+		xcache_globals->var_holds = NULL;
+		xcache_globals->var_holds_size = 0;
+	}
+
+	if (xcache_globals->internal_table_copied) {
+#ifdef HAVE_XCACHE_CONSTANT
+		zend_hash_destroy(&xcache_globals->internal_constant_table);
+#endif
+		zend_hash_destroy(&xcache_globals->internal_function_table);
+		zend_hash_destroy(&xcache_globals->internal_class_table);
+	}
+}
+/* }}} */
+
+/* {{{ proto int xcache_get_refcount(mixed variable)
+   XCache internal uses only: Get reference count of variable */
+PHP_FUNCTION(xcache_get_refcount)
+{
+	zval *variable;
+	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &variable) == FAILURE) {
+		RETURN_NULL();
+	}
+
+	RETURN_LONG(Z_REFCOUNT(*variable));
+}
+/* }}} */
+/* {{{ proto bool xcache_get_isref(mixed variable)
+   XCache internal uses only: Check if variable data is marked referenced */
+#ifdef ZEND_BEGIN_ARG_INFO_EX
+ZEND_BEGIN_ARG_INFO_EX(arginfo_xcache_get_isref, 0, 0, 1)
+	ZEND_ARG_INFO(1, variable)
+ZEND_END_ARG_INFO()
+#else
+static unsigned char arginfo_xcache_get_isref[] = { 1, BYREF_FORCE };
+#endif
+
+PHP_FUNCTION(xcache_get_isref)
+{
+	zval *variable;
+	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &variable) == FAILURE) {
+		RETURN_NULL();
+	}
+
+	RETURN_BOOL(Z_ISREF(*variable) && Z_REFCOUNT(*variable) >= 3);
+}
+/* }}} */
+#ifdef HAVE_XCACHE_DPRINT
+/* {{{ proto bool  xcache_dprint(mixed value)
+   Prints variable (or value) internal struct (debug only) */
+PHP_FUNCTION(xcache_dprint)
+{
+	zval *value;
+
+	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &value) == FAILURE) {
+		return;
+	}
+	xc_dprint_zval(value, 0 TSRMLS_CC);
+}
+/* }}} */
+#endif
+/* {{{ proto string xcache_asm(string filename)
+ */
+#ifdef HAVE_XCACHE_ASSEMBLER
+PHP_FUNCTION(xcache_asm)
+{
+}
+#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);
+}
+/* }}} */
+/* {{{ 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();
+}
+/* }}} */
+/* {{{ proto mixed xcache_get_special_value(zval value)
+   XCache internal use only: For decompiler to get static value with type fixed */
+PHP_FUNCTION(xcache_get_special_value)
+{
+	zval *value;
+
+	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &value) == FAILURE) {
+		return;
+	}
+
+	switch ((Z_TYPE_P(value) & IS_CONSTANT_TYPE_MASK)) {
+	case IS_CONSTANT:
+		*return_value = *value;
+		zval_copy_ctor(return_value);
+		return_value->type = UNISW(IS_STRING, UG(unicode) ? IS_UNICODE : IS_STRING);
+		break;
+
+	case IS_CONSTANT_ARRAY:
+		*return_value = *value;
+		zval_copy_ctor(return_value);
+		return_value->type = IS_ARRAY;
+		break;
+
+	default:
+		RETURN_NULL();
+	}
+}
+/* }}} */
+/* {{{ proto int xcache_get_type(zval value)
+   XCache internal use only for disassembler to get variable type in engine level */
+PHP_FUNCTION(xcache_get_type)
+{
+	zval *value;
+
+	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &value) == FAILURE) {
+		return;
+	}
+
+	RETURN_LONG(Z_TYPE_P(value));
+}
+/* }}} */
+/* {{{ 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)
+{
+	zval *name;
+
+	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &name) == FAILURE) {
+		return;
+	}
+
+#ifdef IS_UNICODE
+	convert_to_unicode(name);
+#else
+	convert_to_string(name);
+#endif
+
+	RETURN_BOOL(zend_u_hash_exists(CG(auto_globals), UG(unicode), Z_STRVAL_P(name), Z_STRLEN_P(name) + 1));
+}
+/* }}} */
+static zend_function_entry xcache_functions[] = /* {{{ */
+{
+	PHP_FE(xcache_coredump,          NULL)
+#ifdef HAVE_XCACHE_ASSEMBLER
+	PHP_FE(xcache_asm,               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
+	PHP_FE(xcache_get_special_value, NULL)
+	PHP_FE(xcache_get_type,          NULL)
+	PHP_FE(xcache_get_op_type,       NULL)
+	PHP_FE(xcache_get_data_type,     NULL)
+	PHP_FE(xcache_get_opcode,        NULL)
+	PHP_FE(xcache_get_opcode_spec,   NULL)
+	PHP_FE(xcache_is_autoglobal,     NULL)
+	PHP_FE(xcache_get_refcount,      NULL)
+	PHP_FE(xcache_get_isref,         arginfo_xcache_get_isref)
+#ifdef HAVE_XCACHE_DPRINT
+	PHP_FE(xcache_dprint,            NULL)
+#endif
+	PHP_FE_END
+};
+/* }}} */
+
+#ifdef ZEND_WIN32
+#include "dbghelp.h"
+typedef BOOL (WINAPI *MINIDUMPWRITEDUMP)(HANDLE hProcess, DWORD dwPid, HANDLE hFile, MINIDUMP_TYPE DumpType,
+		CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
+		CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
+		CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam
+		);
+
+static PTOP_LEVEL_EXCEPTION_FILTER oldFilter = NULL;
+static HMODULE dbghelpModule = NULL;
+static char crash_dumpPath[_MAX_PATH] = { 0 };
+static MINIDUMPWRITEDUMP dbghelp_MiniDumpWriteDump = NULL;
+
+static LONG WINAPI miniDumperFilter(struct _EXCEPTION_POINTERS *pExceptionInfo) /* {{{ */
+{
+	HANDLE fileHandle;
+	LONG ret = EXCEPTION_CONTINUE_SEARCH;
+
+	SetUnhandledExceptionFilter(oldFilter);
+
+	/* create the file */
+	fileHandle = CreateFile(crash_dumpPath, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+
+	if (fileHandle != INVALID_HANDLE_VALUE) {
+		MINIDUMP_EXCEPTION_INFORMATION exceptionInformation;
+		BOOL ok;
+
+		exceptionInformation.ThreadId = GetCurrentThreadId();
+		exceptionInformation.ExceptionPointers = pExceptionInfo;
+		exceptionInformation.ClientPointers = FALSE;
+
+		/* write the dump */
+		ok = dbghelp_MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), fileHandle, MiniDumpNormal|MiniDumpWithDataSegs|MiniDumpWithIndirectlyReferencedMemory, &exceptionInformation, NULL, NULL);
+		CloseHandle(fileHandle);
+		if (ok) {
+			zend_error(E_ERROR, "Saved dump file to '%s'", crash_dumpPath);
+			ret = EXCEPTION_EXECUTE_HANDLER;
+		}
+		else {
+			zend_error(E_ERROR, "Failed to save dump file to '%s' (error %d)", crash_dumpPath, GetLastError());
+		}
+	}
+	else {
+		zend_error(E_ERROR, "Failed to create dump file '%s' (error %d)", crash_dumpPath, GetLastError());
+	}
+
+	if (xc_disable_on_crash) {
+		xc_disable_on_crash = 0;
+		xc_cacher_disable();
+	}
+
+	return ret;
+}
+/* }}} */
+
+static void xcache_restore_crash_handler() /* {{{ */
+{
+	if (oldFilter) {
+		SetUnhandledExceptionFilter(oldFilter);
+		oldFilter = NULL;
+	}
+}
+/* }}} */
+static void xcache_init_crash_handler() /* {{{ */
+{
+	/* firstly see if dbghelp.dll is around and has the function we need
+	   look next to the EXE first, as the one in System32 might be old
+	   (e.g. Windows 2000) */
+	char dbghelpPath[_MAX_PATH];
+
+	if (GetModuleFileName(NULL, dbghelpPath, _MAX_PATH)) {
+		char *slash = strchr(dbghelpPath, '\\');
+		if (slash) {
+			strcpy(slash + 1, "DBGHELP.DLL");
+			dbghelpModule = LoadLibrary(dbghelpPath);
+		}
+	}
+
+	if (!dbghelpModule) {
+		/* load any version we can */
+		dbghelpModule = LoadLibrary("DBGHELP.DLL");
+		if (!dbghelpModule) {
+			zend_error(E_ERROR, "Unable to enable crash dump saver: %s", "DBGHELP.DLL not found");
+			return;
+		}
+	}
+
+	dbghelp_MiniDumpWriteDump = (MINIDUMPWRITEDUMP)GetProcAddress(dbghelpModule, "MiniDumpWriteDump");
+	if (!dbghelp_MiniDumpWriteDump) {
+		zend_error(E_ERROR, "Unable to enable crash dump saver: %s", "DBGHELP.DLL too old. Get updated dll and put it aside of php_xcache.dll");
+		return;
+	}
+
+#ifdef XCACHE_VERSION_REVISION
+#define REVISION "r" XCACHE_VERSION_REVISION
+#else
+#define REVISION ""
+#endif
+	sprintf(crash_dumpPath, "%s\\php-%s-xcache-%s%s-%lu-%lu.dmp", xc_coredump_dir, zend_get_module_version("standard"), XCACHE_VERSION, REVISION, (unsigned long) time(NULL), (unsigned long) GetCurrentProcessId());
+#undef REVISION
+
+	oldFilter = SetUnhandledExceptionFilter(&miniDumperFilter);
+}
+/* }}} */
+#else
+/* old signal handlers {{{ */
+typedef void (*xc_sighandler_t)(int);
+#define FOREACH_SIG(sig) static xc_sighandler_t old_##sig##_handler = NULL
+#include "util/xc_foreachcoresig.h"
+#undef FOREACH_SIG
+/* }}} */
+static void xcache_signal_handler(int sig);
+static void xcache_restore_crash_handler() /* {{{ */
+{
+#define FOREACH_SIG(sig) do { \
+	if (old_##sig##_handler != xcache_signal_handler) { \
+		signal(sig, old_##sig##_handler); \
+	} \
+	else { \
+		signal(sig, SIG_DFL); \
+	} \
+} while (0)
+#include "util/xc_foreachcoresig.h"
+#undef FOREACH_SIG
+}
+/* }}} */
+static void xcache_init_crash_handler() /* {{{ */
+{
+#define FOREACH_SIG(sig) \
+	old_##sig##_handler = signal(sig, xcache_signal_handler)
+#include "util/xc_foreachcoresig.h"
+#undef FOREACH_SIG
+}
+/* }}} */
+static void xcache_signal_handler(int sig) /* {{{ */
+{
+	xcache_restore_crash_handler();
+	if (xc_coredump_dir && xc_coredump_dir[0]) {
+		if (chdir(xc_coredump_dir) != 0) {
+			/* error, but nothing can do about it
+			 * and should'nt print anything which might SEGV again */
+		}
+	}
+	if (xc_disable_on_crash) {
+		xc_disable_on_crash = 0;
+		xc_cacher_disable();
+	}
+	raise(sig);
+}
+/* }}} */
+#endif
+
+/* {{{ incompatible zend extensions handling */
+typedef struct {
+	const char *name;
+	startup_func_t old_startup;
+} xc_incompatible_zend_extension_info_t;
+static xc_incompatible_zend_extension_info_t xc_incompatible_zend_extensions[] = {
+	{ "Zend Optimizer", NULL }
+};
+
+static xc_incompatible_zend_extension_info_t *xc_get_incompatible_zend_extension_info(const char *name)
+{
+	size_t i;
+
+	for (i = 0; i < sizeof(xc_incompatible_zend_extensions) / sizeof(xc_incompatible_zend_extensions[0]); ++i) {
+		xc_incompatible_zend_extension_info_t *incompatible_zend_extension_info = &xc_incompatible_zend_extensions[i];
+		if (strcmp(incompatible_zend_extension_info->name, name) == 0) {
+			return incompatible_zend_extension_info;
+		}
+	}
+
+	return NULL;
+}
+/* }}} */
+static int xc_incompatible_zend_extension_startup_hook(zend_extension *extension) /* {{{ */
+{
+	xc_incompatible_zend_extension_info_t *incompatible_zend_extension_info = xc_get_incompatible_zend_extension_info(extension->name);
+	int status;
+	zend_bool catched = 0;
+	zend_llist old_zend_extensions = zend_extensions;
+	TSRMLS_FETCH();
+
+	/* hide all extensions from it */
+	zend_extensions.head = NULL;
+	zend_extensions.count = 0;
+
+	/* restore */
+	extension->startup = incompatible_zend_extension_info->old_startup;
+	incompatible_zend_extension_info->old_startup = NULL;
+	assert(extension->startup);
+
+	zend_try {
+		status = extension->startup(extension);
+	} zend_catch {
+		catched = 1;
+	} zend_end_try();
+
+	zend_extensions = old_zend_extensions;
+	if (catched) {
+		zend_bailout();
+	}
+	return status;
+}
+/* }}} */
+static int xc_zend_startup(zend_extension *extension) /* {{{ */
+{
+	zend_llist_position lpos;
+	zend_extension *ext;
+
+	ext = (zend_extension *) zend_extensions.head->data;
+	if (strcmp(ext->name, XCACHE_NAME) != 0) {
+		zend_error(E_WARNING, "XCache failed to load itself as the before \"%s\". compatibility downgraded", ext->name);
+	}
+
+	old_compile_file = zend_compile_file;
+	zend_compile_file = xc_check_initial_compile_file;
+
+	for (ext = (zend_extension *) zend_llist_get_first_ex(&zend_extensions, &lpos);
+			ext;
+			ext = (zend_extension *) zend_llist_get_next_ex(&zend_extensions, &lpos)) {
+		xc_incompatible_zend_extension_info_t *incompatible_zend_extension_info = xc_get_incompatible_zend_extension_info(ext->name);
+		if (incompatible_zend_extension_info) {
+			assert(!incompatible_zend_extension_info->old_startup);
+			incompatible_zend_extension_info->old_startup = ext->startup;
+			ext->startup = xc_incompatible_zend_extension_startup_hook;
+		}
+	}
+	return SUCCESS;
+}
+/* }}} */
+static void xc_zend_shutdown(zend_extension *extension) /* {{{ */
+{
+}
+/* }}} */
+/* {{{ zend extension definition structure */
+static zend_extension xc_zend_extension_entry = {
+	XCACHE_NAME,
+	XCACHE_VERSION,
+	XCACHE_AUTHOR,
+	XCACHE_URL,
+	XCACHE_COPYRIGHT,
+	xc_zend_startup,
+	xc_zend_shutdown,
+	NULL,           /* activate_func_t */
+	NULL,           /* deactivate_func_t */
+	NULL,           /* message_handler_func_t */
+	NULL,           /* op_array_handler_func_t */
+	NULL,           /* statement_handler_func_t */
+	NULL,           /* fcall_begin_handler_func_t */
+	NULL,           /* fcall_end_handler_func_t */
+	NULL,           /* op_array_ctor_func_t */
+	NULL,           /* op_array_dtor_func_t */
+	STANDARD_ZEND_EXTENSION_PROPERTIES
+};
+/* }}} */
+
+/* {{{ PHP_INI */
+PHP_INI_BEGIN()
+	PHP_INI_ENTRY1     ("xcache.coredump_directory",      "", PHP_INI_SYSTEM, xcache_OnUpdateString,   &xc_coredump_dir)
+	PHP_INI_ENTRY1_EX  ("xcache.disable_on_crash",       "0", PHP_INI_SYSTEM, xcache_OnUpdateBool,     &xc_disable_on_crash, zend_ini_boolean_displayer_cb)
+	PHP_INI_ENTRY1_EX  ("xcache.test",                   "0", PHP_INI_SYSTEM, xcache_OnUpdateBool,     &xc_test,             zend_ini_boolean_displayer_cb)
+	STD_PHP_INI_BOOLEAN("xcache.experimental",           "0", PHP_INI_ALL,    OnUpdateBool,        experimental,      zend_xcache_globals, xcache_globals)
+PHP_INI_END()
+/* }}} */
+static PHP_MINFO_FUNCTION(xcache) /* {{{ */
+{
+	php_info_print_table_start();
+	php_info_print_table_row(2, "XCache Version", XCACHE_VERSION);
+#ifdef XCACHE_VERSION_REVISION
+	php_info_print_table_row(2, "Revision", "r" XCACHE_VERSION_REVISION);
+#endif
+	php_info_print_table_row(2, "Modules Built", XCACHE_MODULES);
+	php_info_print_table_end();
+
+	DISPLAY_INI_ENTRIES();
+}
+/* }}} */
+static PHP_MINIT_FUNCTION(xcache) /* {{{ */
+{
+#ifndef PHP_GINIT
+	ZEND_INIT_MODULE_GLOBALS(xcache, xc_init_globals, xc_shutdown_globals);
+#endif
+	REGISTER_INI_ENTRIES();
+
+	if (xc_coredump_dir && xc_coredump_dir[0]) {
+		xcache_init_crash_handler();
+	}
+
+	if (strcmp(sapi_module.name, "cli") == 0) {
+		char *env;
+		if ((env = getenv("XCACHE_TEST")) != NULL) {
+			xc_test = atoi(env);
+		}
+	}
+
+	xc_init_constant(module_number TSRMLS_CC);
+	xc_shm_init_modules();
+
+	/* must be the first */
+	xcache_zend_extension_add(&xc_zend_extension_entry, 1);
+#ifdef HAVE_XCACHE_OPTIMIZER
+	xc_optimizer_startup_module();
+#endif
+#ifdef HAVE_XCACHE_CACHER
+	xc_cacher_startup_module();
+#endif
+#ifdef HAVE_XCACHE_COVERAGER
+	xc_coverager_startup_module();
+#endif
+#ifdef HAVE_XCACHE_DISASSEMBLER
+	xc_disassembler_startup_module();
+#endif
+
+	return SUCCESS;
+}
+/* }}} */
+static PHP_MSHUTDOWN_FUNCTION(xcache) /* {{{ */
+{
+	if (old_compile_file && zend_compile_file == xc_check_initial_compile_file) {
+		zend_compile_file = old_compile_file;
+		old_compile_file = NULL;
+	}
+
+	if (xc_coredump_dir && xc_coredump_dir[0]) {
+		xcache_restore_crash_handler();
+	}
+	if (xc_coredump_dir) {
+		pefree(xc_coredump_dir, 1);
+		xc_coredump_dir = NULL;
+	}
+#ifndef PHP_GINIT
+#	ifdef ZTS
+	ts_free_id(xcache_globals_id);
+#	else
+	xc_shutdown_globals(&xcache_globals TSRMLS_CC);
+#	endif
+#endif
+
+	UNREGISTER_INI_ENTRIES();
+	xcache_zend_extension_remove(&xc_zend_extension_entry);
+	return SUCCESS;
+}
+/* }}} */
+/* {{{ module dependencies */
+#ifdef STANDARD_MODULE_HEADER_EX
+static zend_module_dep xcache_module_deps[] = {
+	ZEND_MOD_REQUIRED("standard")
+	ZEND_MOD_CONFLICTS("apc")
+	ZEND_MOD_CONFLICTS("eAccelerator")
+	ZEND_MOD_CONFLICTS("Turck MMCache")
+	ZEND_MOD_END
+};
+#endif
+/* }}} */ 
+/* {{{ module definition structure */
+zend_module_entry xcache_module_entry = {
+#ifdef STANDARD_MODULE_HEADER_EX
+	STANDARD_MODULE_HEADER_EX,
+	NULL,
+	xcache_module_deps,
+#else
+	STANDARD_MODULE_HEADER,
+#endif
+	XCACHE_NAME,
+	xcache_functions,
+	PHP_MINIT(xcache),
+	PHP_MSHUTDOWN(xcache),
+	NULL, /* RINIT */
+	NULL, /* RSHUTDOWN */
+	PHP_MINFO(xcache),
+	XCACHE_VERSION,
+#ifdef PHP_GINIT
+	PHP_MODULE_GLOBALS(xcache),
+	PHP_GINIT(xcache),
+	PHP_GSHUTDOWN(xcache),
+#endif
+#ifdef ZEND_ENGINE_2
+	NULL /* ZEND_MODULE_POST_ZEND_DEACTIVATE_N */,
+#else
+	NULL,
+	NULL,
+#endif
+	STANDARD_MODULE_PROPERTIES_EX
+};
+
+#ifdef COMPILE_DL_XCACHE
+ZEND_GET_MODULE(xcache)
+#endif
+/* }}} */
Index: /tags/3.0.0-rc1/config.w32
===================================================================
--- /tags/3.0.0-rc1/config.w32	(revision 1135)
+++ /tags/3.0.0-rc1/config.w32	(revision 1135)
@@ -0,0 +1,148 @@
+// vim:ft=javascript
+
+
+ARG_ENABLE("xcache", "Include XCache support", "yes,shared");
+
+if (PHP_XCACHE != "no") {
+	EXTENSION("xcache", "xcache.c", null, "/I " + configure_module_dirname);
+	// {{{ check for xcache-constant 
+	ARG_ENABLE("xcache-constant", "XCache: Handle new constants made by php compiler (e.g.: for __halt_compiler)", "yes");
+	if (PHP_XCACHE_CONSTANT != "no") {
+		AC_DEFINE("HAVE_XCACHE_CONSTANT", 1, "Define to enable XCache handling of compile time constants");
+	}
+	// }}}
+
+	ADD_SOURCES(configure_module_dirname + "/util", " \
+xc_stack.c \
+xc_trace.c \
+", "xcache");
+
+	ADD_SOURCES(configure_module_dirname + "/xcache", " \
+xc_allocator.c \
+xc_allocator_bestfit.c \
+xc_compatibility.c \
+xc_const_string.c \
+xc_extension.c \
+xc_ini.c \
+xc_lock.c \
+xc_opcode_spec.c \
+xc_processor.c \
+xc_sandbox.c \
+xc_shm.c \
+xc_shm_mmap.c \
+xc_utils.c \
+", "xcache");
+	ADD_SOURCES(configure_module_dirname + "/mod_cacher", " \
+xc_cacher.c \
+", "xcache");
+
+	// {{{ 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 server usage", "no");
+	ARG_ENABLE("xcache-encoder",      "(N/A)", "no");
+	ARG_ENABLE("xcache-decoder",      "(N/A)", "no");
+
+	var XCACHE_MODULES = "cacher";
+	AC_DEFINE("HAVE_XCACHE_CACHER", 1, "Define for XCache: 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") {
+			ADD_SOURCES(configure_module_dirname + "/mod_" + name, "xc_" + name + ".c", "xcache");
+			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");
+		}
+	}
+	DEFINE("XCACHE_BACKTICK", "`")
+	PATH_PROG("gawk", null, "XCACHE_AWK") || PATH_PROG("awk", null, "XCACHE_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);
+	// }}}
+	// {{{ 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");
+		ADD_SOURCES(configure_module_dirname + "/xcache", "xc_malloc.c", "xcache");
+		AC_DEFINE("HAVE_XCACHE_TEST", 1, "Define to enable XCache self test");
+	}
+	else {
+		ADD_FLAG("XCACHE_ENABLE_TEST", "");
+	}
+	// }}}
+	// {{{ check for xcache-test
+	ARG_ENABLE("xcache-dprint", "XCache: Enable self debug print functions - FOR DEVELOPERS ONLY!!", "no");
+	if (PHP_XCACHE_DPRINT != "no") {
+		AC_DEFINE("HAVE_XCACHE_DPRINT", 1, "Define to enable XCache debug print functions");
+	}
+	// }}}
+	// {{{ get ccrule
+	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.obj:/);
+	var builddir = RegExp.$1;
+	mfo.match(/(.*\$\(CC\).* )\/c.*\\xcache.c.*/i);
+	var ccrule = RegExp.$1;
+
+	MFO = FSO.OpenTextFile(mfofile, 8);
+	mfo = null;
+	// }}}
+	// {{{ add make fragments
+	var makefileFrag = srcdir + "\\Makefile.frag";
+	var makefileFragDeps = srcdir + "\\Makefile.frag.deps";
+	STDOUT.WriteLine("Adding Makefile.frag: " + makefileFrag);
+	STDOUT.WriteLine("Adding Makefile.frag.deps: " + makefileFragDeps);
+	var frag = file_get_contents(makefileFrag) + "\r\n" + file_get_contents(makefileFragDeps);
+	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(/cp /g, "copy ");
+	frag = frag.replace(/mv /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);
+	/// }}}
+	XCACHE_PROC_SOURCES=glob(srcdir + "\\processor\\*.m4").join(' ');
+	ADD_FLAG("XCACHE_PROC_SOURCES", XCACHE_PROC_SOURCES);
+}
Index: /tags/3.0.0-rc1/mod_optimizer/xc_optimizer.c
===================================================================
--- /tags/3.0.0-rc1/mod_optimizer/xc_optimizer.c	(revision 1112)
+++ /tags/3.0.0-rc1/mod_optimizer/xc_optimizer.c	(revision 1112)
@@ -0,0 +1,704 @@
+#if 0
+#	define XCACHE_DEBUG
+#endif
+
+#include "xc_optimizer.h"
+#include "xcache/xc_extension.h"
+#include "xcache/xc_ini.h"
+#include "xcache/xc_utils.h"
+#include "util/xc_stack.h"
+#include "util/xc_trace.h"
+#include "xcache_globals.h"
+
+#include "ext/standard/info.h"
+
+#ifdef XCACHE_DEBUG
+#error 1
+#	include "xc_processor.h"
+#	include "xcache/xc_const_string.h"
+#	include "ext/standard/php_var.h"
+#endif
+
+#ifdef IS_CV
+#	define XCACHE_IS_CV IS_CV
+#else
+#	define XCACHE_IS_CV 16
+#endif
+
+#ifdef ZEND_ENGINE_2_4
+#	undef Z_OP_CONSTANT
+/* Z_OP_CONSTANT is used before pass_two is applied */
+#	define Z_OP_CONSTANT(op) op_array->literals[op.constant].constant
+#endif
+
+typedef zend_uint bbid_t;
+#define BBID_INVALID ((bbid_t) -1)
+/* {{{ basic block */
+typedef struct _bb_t {
+	bbid_t     id;
+	zend_bool  used;
+
+	zend_bool  alloc;
+	zend_op   *opcodes;
+	int        count;
+	int        size;
+
+	bbid_t     fall;
+#ifdef ZEND_ENGINE_2
+	bbid_t     catch;
+#endif
+
+	zend_uint  opnum; /* opnum after joining basic block */
+} bb_t;
+/* }}} */
+
+/* basic blocks */
+typedef xc_stack_t bbs_t;
+
+/* op array helper functions */
+static int op_array_convert_switch(zend_op_array *op_array) /* {{{ */
+{
+	zend_uint i;
+
+	if (op_array->brk_cont_array == NULL) {
+		return SUCCESS;
+	}
+
+	for (i = 0; i < op_array->last; i ++) {
+		zend_op *opline = &op_array->opcodes[i];
+		zend_brk_cont_element *jmp_to;
+		zend_bool can_convert = 1;
+		int array_offset, nest_levels, original_nest_levels;
+
+		switch (opline->opcode) {
+		case ZEND_BRK:
+		case ZEND_CONT:
+			break;
+
+#ifdef ZEND_GOTO
+		case ZEND_GOTO:
+#endif
+			continue;
+
+		default:
+			continue;
+		}
+
+		if (Z_OP_TYPE(opline->op2) != IS_CONST
+		 || Z_OP_CONSTANT(opline->op2).type != IS_LONG) {
+			return FAILURE;
+		}
+
+		nest_levels = Z_OP_CONSTANT(opline->op2).value.lval;
+		original_nest_levels = nest_levels;
+
+		array_offset = Z_OP(opline->op1).opline_num;
+		do {
+			if (array_offset == -1) {
+				/* this is a runtime error in ZE
+				zend_error(E_ERROR, "Cannot break/continue %d level%s", original_nest_levels, (original_nest_levels == 1) ? "" : "s");
+				*/
+				return FAILURE;
+			}
+			jmp_to = &op_array->brk_cont_array[array_offset];
+			if (nest_levels > 1) {
+				zend_op *brk_opline = &op_array->opcodes[jmp_to->brk];
+
+				switch (brk_opline->opcode) {
+				case ZEND_SWITCH_FREE:
+				case ZEND_FREE:
+#ifdef EXT_TYPE_FREE_ON_RETURN
+					if (!(brk_opline->extended_value & EXT_TYPE_FREE_ON_RETURN))
+#endif
+					{
+						can_convert = 0;
+					}
+					break;
+				}
+			}
+			array_offset = jmp_to->parent;
+		} while (--nest_levels > 0);
+
+		if (can_convert) {
+			/* rewrite to jmp */
+			switch (opline->opcode) {
+			case ZEND_BRK:
+				Z_OP(opline->op1).opline_num = jmp_to->brk;
+				break;
+
+			case ZEND_CONT:
+				Z_OP(opline->op1).opline_num = jmp_to->cont;
+				break;
+			}
+			Z_OP_TYPE(opline->op2) = IS_UNUSED;
+			opline->opcode = ZEND_JMP;
+		}
+	}
+
+	return SUCCESS;
+}
+/* }}} */
+/* {{{ op_flowinfo helper func */
+enum {
+	XC_OPNUM_INVALID = -1
+};
+typedef struct {
+	int       jmpout_op1;
+	int       jmpout_op2;
+	int       jmpout_ext;
+	zend_bool fall;
+} op_flowinfo_t;
+static void op_flowinfo_init(op_flowinfo_t *fi)
+{
+	fi->jmpout_op1 = fi->jmpout_op2 = fi->jmpout_ext = XC_OPNUM_INVALID;
+	fi->fall = 0;
+}
+/* }}} */
+static int op_get_flowinfo(op_flowinfo_t *fi, zend_op *opline) /* {{{ */
+{
+	op_flowinfo_init(fi);
+
+	/* break=will fall */
+	switch (opline->opcode) {
+#ifdef ZEND_HANDLE_EXCEPTION
+	case ZEND_HANDLE_EXCEPTION:
+#endif
+	case ZEND_RETURN:
+	case ZEND_EXIT:
+		return SUCCESS; /* no fall */
+
+	case ZEND_JMP:
+		fi->jmpout_op1 = Z_OP(opline->op1).opline_num;
+		return SUCCESS; /* no fall */
+
+	case ZEND_JMPZNZ:
+		fi->jmpout_op2 = Z_OP(opline->op2).opline_num;
+		fi->jmpout_ext = (int) opline->extended_value;
+		return SUCCESS; /* no fall */
+
+	case ZEND_JMPZ:
+	case ZEND_JMPNZ:
+	case ZEND_JMPZ_EX:
+	case ZEND_JMPNZ_EX:
+#ifdef ZEND_JMP_SET
+	case ZEND_JMP_SET:
+#endif
+#ifdef ZEND_JMP_NO_CTOR
+	case ZEND_JMP_NO_CTOR:
+#endif
+#ifdef ZEND_NEW
+	case ZEND_NEW:
+#endif
+#ifdef ZEND_FE_RESET
+	case ZEND_FE_RESET:
+#endif      
+	case ZEND_FE_FETCH:
+		fi->jmpout_op2 = Z_OP(opline->op2).opline_num;
+		break;
+
+#ifdef ZEND_CATCH
+	case ZEND_CATCH:
+		fi->jmpout_ext = (int) opline->extended_value;
+		break;
+#endif
+
+	default:
+		return FAILURE;
+	}
+
+	fi->fall = 1;
+	return SUCCESS;
+}
+/* }}} */
+#ifdef XCACHE_DEBUG
+static void op_snprint(char *buf, int size, zend_uchar op_type, znode_op *op) /* {{{ */
+{
+	switch (op_type) {
+	case IS_CONST:
+		{
+			zval result;
+			zval *zv = &Z_OP_CONSTANT(*op);
+			TSRMLS_FETCH();
+
+			/* TODO: update for PHP 6 */
+			php_start_ob_buffer(NULL, 0, 1 TSRMLS_CC);
+			php_var_export(&zv, 1 TSRMLS_CC);
+
+			php_ob_get_buffer(&result TSRMLS_CC); 
+			php_end_ob_buffer(0, 0 TSRMLS_CC);
+			snprintf(buf, size, Z_STRVAL(result));
+			zval_dtor(&result);
+		}
+		break;
+
+	case IS_TMP_VAR:
+		snprintf(buf, size, "t@%d", Z_OP(*op).var);
+		break;
+
+	case XCACHE_IS_CV:
+	case IS_VAR:
+		snprintf(buf, size, "v@%d", Z_OP(*op).var);
+		break;
+
+	case IS_UNUSED:
+		if (Z_OP(*op).opline_num) {
+			snprintf(buf, size, "u#%d", Z_OP(op).opline_num);
+		}
+		else {
+			snprintf(buf, size, "-");
+		}
+		break;
+
+	default:
+		snprintf(buf, size, "%d %d", op->op_type, Z_OP(op).var);
+	}
+}
+/* }}} */
+static void op_print(int line, zend_op *first, zend_op *end) /* {{{ */
+{
+	zend_op *opline;
+	for (opline = first; opline < end; opline ++) {
+		char buf_r[20];
+		char buf_1[20];
+		char buf_2[20];
+		op_snprint(buf_r, sizeof(buf_r), Z_OP_TYPE(opline->result), &opline->result);
+		op_snprint(buf_1, sizeof(buf_1), Z_OP_TYPE(opline->op1),    &opline->op1);
+		op_snprint(buf_2, sizeof(buf_2), Z_OP_TYPE(opline->op2),    &opline->op2);
+		fprintf(stderr,
+				"%3d %3d"
+				" %-25s%-5s%-20s%-20s%5lu\r\n"
+				, opline->lineno, opline - first + line
+				, xc_get_opcode(opline->opcode), buf_r, buf_1, buf_2, opline->extended_value);
+	}
+}
+/* }}} */
+#endif
+
+/*
+ * basic block functions
+ */
+
+static bb_t *bb_new_ex(zend_op *opcodes, int count) /* {{{ */
+{
+	bb_t *bb = (bb_t *) ecalloc(sizeof(bb_t), 1);
+
+	bb->fall       = BBID_INVALID;
+#ifdef ZEND_ENGINE_2
+	bb->catch      = BBID_INVALID;
+#endif
+
+	if (opcodes) {
+		bb->alloc   = 0;
+		bb->size    = bb->count = count;
+		bb->opcodes = opcodes;
+	}
+	else {
+		bb->alloc   = 1;
+		bb->size    = bb->count = 8;
+		bb->opcodes = ecalloc(sizeof(zend_op), bb->size);
+	}
+
+	return bb;
+}
+/* }}} */
+#define bb_new() bb_new_ex(NULL, 0)
+static void bb_destroy(bb_t *bb) /* {{{ */
+{
+	if (bb->alloc) {
+		efree(bb->opcodes);
+	}
+	efree(bb);
+}
+/* }}} */
+#ifdef XCACHE_DEBUG
+static void bb_print(bb_t *bb, zend_op *opcodes) /* {{{ */
+{
+	int line = bb->opcodes - opcodes;
+	op_flowinfo_t fi;
+	zend_op *last = bb->opcodes + bb->count - 1;
+	bbid_t catchbbid;
+#ifdef ZEND_ENGINE_2
+	catchbbid = BBID_INVALID;
+#else
+	catchbbid = bb->catch;
+#endif
+
+	op_get_flowinfo(&fi, last);
+
+	fprintf(stderr,
+			"\r\n==== #%-3d cnt:%-3d lno:%-3d"
+			" %c%c"
+			" op1:%-3d op2:%-3d ext:%-3d fal:%-3d cat:%-3d %s ====\r\n"
+			, bb->id, bb->count, bb->alloc ? -1 : line
+			, bb->used ? 'U' : ' ', bb->alloc ? 'A' : ' '
+			, fi.jmpout_op1, fi.jmpout_op2, fi.jmpout_ext, bb->fall, catchbbid, xc_get_opcode(last->opcode)
+			);
+	op_print(line, bb->opcodes, last + 1);
+}
+/* }}} */
+#endif
+
+static bb_t *bbs_get(bbs_t *bbs, int n) /* {{{ */
+{
+	return (bb_t *) xc_stack_get(bbs, n);
+}
+/* }}} */
+static int bbs_count(bbs_t *bbs) /* {{{ */
+{
+	return xc_stack_count(bbs);
+}
+/* }}} */
+static void bbs_destroy(bbs_t *bbs) /* {{{ */
+{
+	bb_t *bb;
+	while (bbs_count(bbs)) {
+		bb = (bb_t *) xc_stack_pop(bbs);
+		bb_destroy(bb);
+	}
+	xc_stack_destroy(bbs);
+}
+/* }}} */
+#ifdef XCACHE_DEBUG
+static void bbs_print(bbs_t *bbs, zend_op *opcodes) /* {{{ */
+{
+	int i;
+	for (i = 0; i < xc_stack_count(bbs); i ++) {
+		bb_print(bbs_get(bbs, i), opcodes);
+	}
+}
+/* }}} */
+#endif
+#define bbs_init(bbs) xc_stack_init_ex(bbs, 16)
+static bb_t *bbs_add_bb(bbs_t *bbs, bb_t *bb) /* {{{ */
+{
+	bb->id = (bbid_t) xc_stack_count(bbs);
+	xc_stack_push(bbs, (void *) bb);
+	return bb;
+}
+/* }}} */
+static bb_t *bbs_new_bb_ex(bbs_t *bbs, zend_op *opcodes, int count) /* {{{ */
+{
+	return bbs_add_bb(bbs, bb_new_ex(opcodes, count));
+}
+/* }}} */
+static int bbs_build_from(bbs_t *bbs, zend_op_array *op_array, int count) /* {{{ */
+{
+	int i, start;
+	bb_t *pbb;
+	bbid_t id;
+	op_flowinfo_t fi;
+	zend_op *opline;
+	ALLOCA_FLAG(use_heap_bbids)
+	ALLOCA_FLAG(use_heap_catchbbids)
+	ALLOCA_FLAG(use_heap_markbbhead)
+	bbid_t *bbids          = my_do_alloca(count * sizeof(bbid_t),    use_heap_bbids);
+#ifdef ZEND_ENGINE_2
+	bbid_t *catchbbids     = my_do_alloca(count * sizeof(bbid_t),    use_heap_catchbbids);
+#endif
+	zend_bool *markbbhead  = my_do_alloca(count * sizeof(zend_bool), use_heap_markbbhead);
+
+	/* {{{ mark jmpin/jumpout */
+	memset(markbbhead,  0, count * sizeof(zend_bool));
+
+	markbbhead[0] = 1;
+	for (i = 0; i < count; i ++) {
+		if (op_get_flowinfo(&fi, &op_array->opcodes[i]) == SUCCESS) {
+			if (fi.jmpout_op1 != XC_OPNUM_INVALID) {
+				markbbhead[fi.jmpout_op1] = 1;
+			}
+			if (fi.jmpout_op2 != XC_OPNUM_INVALID) {
+				markbbhead[fi.jmpout_op2] = 1;
+			}
+			if (fi.jmpout_ext != XC_OPNUM_INVALID) {
+				markbbhead[fi.jmpout_ext] = 1;
+			}
+			if (i + 1 < count) {
+				markbbhead[i + 1] = 1;
+			}
+		}
+	}
+#ifdef ZEND_ENGINE_2
+	/* mark try start */
+	for (i = 0; i < op_array->last_try_catch; i ++) {
+		markbbhead[op_array->try_catch_array[i].try_op] = 1;
+	}
+#endif
+	/* }}} */
+	/* {{{ fill op lines with newly allocated id */
+	for (i = 0; i < count; i ++) {
+		bbids[i] = BBID_INVALID;
+	}
+
+	id = -1;
+	for (i = 0; i < count; i ++) {
+		if (markbbhead[i]) {
+			id ++;
+		}
+		bbids[i] = id;
+		TRACE("bbids[%d] = %d", i, id);
+	}
+	/* }}} */
+#ifdef ZEND_ENGINE_2
+	/* {{{ fill op lines with catch id */
+	for (i = 0; i < count; i ++) {
+		catchbbids[i] = BBID_INVALID;
+	}
+
+	for (i = 0; i < op_array->last_try_catch; i ++) {
+		zend_uint j;
+		zend_try_catch_element *e = &op_array->try_catch_array[i];
+		for (j = e->try_op; j < e->catch_op; j ++) {
+			catchbbids[j] = bbids[e->catch_op];
+		}
+	}
+#ifdef XCACHE_DEBUG
+	for (i = 0; i < count; i ++) {
+		TRACE("catchbbids[%d] = %d", i, catchbbids[i]);
+	}
+#endif
+	/* }}} */
+#endif
+	/* {{{ create basic blocks */
+	start = 0;
+	id = 0;
+	/* loop over to deal with the last block */
+	for (i = 1; i <= count; i ++) {
+		if (i < count && id == bbids[i]) {
+			continue;
+		}
+
+		opline = op_array->opcodes + start;
+		pbb = bbs_new_bb_ex(bbs, opline, i - start);
+#ifdef ZEND_ENGINE_2
+		pbb->catch = catchbbids[start];
+#endif
+
+		/* last */
+		opline = pbb->opcodes + pbb->count - 1;
+		if (op_get_flowinfo(&fi, opline) == SUCCESS) {
+			if (fi.jmpout_op1 != XC_OPNUM_INVALID) {
+				Z_OP(opline->op1).opline_num = bbids[fi.jmpout_op1];
+				assert(Z_OP(opline->op1).opline_num != BBID_INVALID);
+			}
+			if (fi.jmpout_op2 != XC_OPNUM_INVALID) {
+				Z_OP(opline->op2).opline_num = bbids[fi.jmpout_op2];
+				assert(Z_OP(opline->op2).opline_num != BBID_INVALID);
+			}
+			if (fi.jmpout_ext != XC_OPNUM_INVALID) {
+				opline->extended_value = bbids[fi.jmpout_ext];
+				assert(opline->extended_value != BBID_INVALID);
+			}
+			if (fi.fall && i + 1 < count) {
+				pbb->fall = bbids[i + 1];
+				TRACE("fall %d", pbb->fall);
+				assert(pbb->fall != BBID_INVALID);
+			}
+		}
+		if (i >= count) {
+			break;
+		}
+		start = i;
+		id = bbids[i];
+	}
+	/* }}} */
+
+	my_free_alloca(markbbhead, use_heap_markbbhead);
+#ifdef ZEND_ENGINE_2
+	my_free_alloca(catchbbids, use_heap_catchbbids);
+#endif
+	my_free_alloca(bbids,      use_heap_bbids);
+	return SUCCESS;
+}
+/* }}} */
+static void bbs_restore_opnum(bbs_t *bbs, zend_op_array *op_array) /* {{{ */
+{
+	int i;
+#ifdef ZEND_ENGINE_2
+	bbid_t lasttrybbid;
+	bbid_t lastcatchbbid;
+#endif
+
+	for (i = 0; i < bbs_count(bbs); i ++) {
+		op_flowinfo_t fi;
+		bb_t *bb = bbs_get(bbs, i);
+		zend_op *last = bb->opcodes + bb->count - 1;
+
+		if (op_get_flowinfo(&fi, last) == SUCCESS) {
+			if (fi.jmpout_op1 != XC_OPNUM_INVALID) {
+				Z_OP(last->op1).opline_num = bbs_get(bbs, fi.jmpout_op1)->opnum;
+				assert(Z_OP(last->op1).opline_num != BBID_INVALID);
+			}
+			if (fi.jmpout_op2 != XC_OPNUM_INVALID) {
+				Z_OP(last->op2).opline_num = bbs_get(bbs, fi.jmpout_op2)->opnum;
+				assert(Z_OP(last->op2).opline_num != BBID_INVALID);
+			}
+			if (fi.jmpout_ext != XC_OPNUM_INVALID) {
+				last->extended_value = bbs_get(bbs, fi.jmpout_ext)->opnum;
+				assert(last->extended_value != BBID_INVALID);
+			}
+		}
+	}
+
+#ifdef ZEND_ENGINE_2
+	lasttrybbid   = BBID_INVALID;
+	lastcatchbbid = BBID_INVALID;
+	op_array->last_try_catch = 0;
+	for (i = 0; i < bbs_count(bbs); i ++) {
+		bb_t *bb = bbs_get(bbs, i);
+
+		if (lastcatchbbid != bb->catch) {
+			if (lasttrybbid != BBID_INVALID && lastcatchbbid != BBID_INVALID) {
+				int try_catch_offset = op_array->last_try_catch ++;
+
+				op_array->try_catch_array = erealloc(op_array->try_catch_array, sizeof(zend_try_catch_element) * op_array->last_try_catch);
+				op_array->try_catch_array[try_catch_offset].try_op = bbs_get(bbs, lasttrybbid)->opnum;
+				op_array->try_catch_array[try_catch_offset].catch_op = bbs_get(bbs, lastcatchbbid)->opnum;
+			}
+			lasttrybbid   = i;
+			lastcatchbbid = bb->catch;
+		}
+	}
+	/* it is impossible to have last bb catched */
+#endif
+}
+/* }}} */
+
+/*
+ * optimize
+ */
+static int xc_optimize_op_array(zend_op_array *op_array TSRMLS_DC) /* {{{ */
+{
+	bbs_t bbs;
+
+	if (op_array->type != ZEND_USER_FUNCTION) {
+		return 0;
+	}
+
+#ifdef XCACHE_DEBUG
+#	if 0
+	TRACE("optimize file: %s", op_array->filename);
+	xc_dprint_zend_op_array(op_array, 0 TSRMLS_CC);
+#	endif
+	op_print(0, op_array->opcodes, op_array->opcodes + op_array->last);
+#endif
+
+	if (op_array_convert_switch(op_array) == SUCCESS) {
+		bbs_init(&bbs);
+		if (bbs_build_from(&bbs, op_array, op_array->last) == SUCCESS) {
+			int i;
+#ifdef XCACHE_DEBUG
+			bbs_print(&bbs, op_array->opcodes);
+#endif
+			/* TODO: calc opnum after basic block move */
+			for (i = 0; i < bbs_count(&bbs); i ++) {
+				bb_t *bb = bbs_get(&bbs, i);
+				bb->opnum = bb->opcodes - op_array->opcodes;
+			}
+			bbs_restore_opnum(&bbs, op_array);
+		}
+		bbs_destroy(&bbs);
+	}
+
+#ifdef XCACHE_DEBUG
+#	if 0
+	TRACE("%s", "after compiles");
+	xc_dprint_zend_op_array(op_array, 0 TSRMLS_CC);
+#	endif
+	op_print(0, op_array->opcodes, op_array->opcodes + op_array->last);
+#endif
+	return 0;
+}
+/* }}} */
+static void xc_optimizer_op_array_handler(zend_op_array *op_array) /* {{{ */
+{
+	TSRMLS_FETCH();
+	if (XG(optimizer)) {
+		xc_optimize_op_array(op_array TSRMLS_CC);
+	}
+}
+/* }}} */
+
+static int xc_coverager_zend_startup(zend_extension *extension) /* {{{ */
+{
+	return SUCCESS;
+}
+/* }}} */
+static void xc_coverager_zend_shutdown(zend_extension *extension) /* {{{ */
+{
+}
+/* }}} */
+/* {{{ zend extension definition structure */
+static zend_extension xc_optimizer_zend_extension_entry = {
+	XCACHE_NAME " Optimizer",
+	XCACHE_VERSION,
+	XCACHE_AUTHOR,
+	XCACHE_URL,
+	XCACHE_COPYRIGHT,
+	xc_coverager_zend_startup,
+	xc_coverager_zend_shutdown,
+	NULL,           /* activate_func_t */
+	NULL,           /* deactivate_func_t */
+	NULL,           /* message_handler_func_t */
+	xc_optimizer_op_array_handler,
+	NULL,           /* statement_handler_func_t */
+	NULL,           /* fcall_begin_handler_func_t */
+	NULL,           /* fcall_end_handler_func_t */
+	NULL,           /* op_array_ctor_func_t */
+	NULL,           /* op_array_dtor_func_t */
+	STANDARD_ZEND_EXTENSION_PROPERTIES
+};
+/* }}} */
+
+/* {{{ ini */
+PHP_INI_BEGIN()
+	STD_PHP_INI_BOOLEAN("xcache.optimizer",              "0", PHP_INI_ALL,    OnUpdateBool,        optimizer,         zend_xcache_globals, xcache_globals)
+PHP_INI_END()
+/* }}} */
+static PHP_MINFO_FUNCTION(xcache_optimizer) /* {{{ */
+{
+	php_info_print_table_start();
+	php_info_print_table_row(2, "XCache Optimizer Module", "enabled");
+	php_info_print_table_end();
+
+	DISPLAY_INI_ENTRIES();
+}
+/* }}} */
+static PHP_MINIT_FUNCTION(xcache_optimizer) /* {{{ */
+{
+	REGISTER_INI_ENTRIES();
+	return xcache_zend_extension_add(&xc_optimizer_zend_extension_entry, 0);
+}
+/* }}} */
+static PHP_MSHUTDOWN_FUNCTION(xcache_optimizer) /* {{{ */
+{
+	UNREGISTER_INI_ENTRIES();
+	return xcache_zend_extension_remove(&xc_optimizer_zend_extension_entry);
+}
+/* }}} */
+static zend_module_entry xcache_optimizer_module_entry = { /* {{{ */
+	STANDARD_MODULE_HEADER,
+	XCACHE_NAME " Optimizer",
+	NULL,
+	PHP_MINIT(xcache_optimizer),
+	PHP_MSHUTDOWN(xcache_optimizer),
+	NULL,
+	NULL,
+	PHP_MINFO(xcache_optimizer),
+	XCACHE_VERSION,
+#ifdef PHP_GINIT
+	NO_MODULE_GLOBALS,
+#endif
+#ifdef ZEND_ENGINE_2
+	NULL,
+#else
+	NULL,
+	NULL,
+#endif
+	STANDARD_MODULE_PROPERTIES_EX
+};
+/* }}} */
+int xc_optimizer_startup_module() /* {{{ */
+{
+	return zend_startup_module(&xcache_optimizer_module_entry);
+}
+/* }}} */
Index: /tags/3.0.0-rc1/mod_optimizer/xc_optimizer.h
===================================================================
--- /tags/3.0.0-rc1/mod_optimizer/xc_optimizer.h	(revision 1044)
+++ /tags/3.0.0-rc1/mod_optimizer/xc_optimizer.h	(revision 1044)
@@ -0,0 +1,12 @@
+#ifndef XC_OPTIMIZER_H_6614228F428A266C39CDAC30269D9857
+#define XC_OPTIMIZER_H_6614228F428A266C39CDAC30269D9857
+
+#if _MSC_VER > 1000
+#pragma once
+#endif /* _MSC_VER > 1000 */
+
+#include "php.h"
+
+int xc_optimizer_startup_module();
+
+#endif /* XC_OPTIMIZER_H_6614228F428A266C39CDAC30269D9857 */
Index: /tags/3.0.0-rc1/xcache.h
===================================================================
--- /tags/3.0.0-rc1/xcache.h	(revision 1051)
+++ /tags/3.0.0-rc1/xcache.h	(revision 1051)
@@ -0,0 +1,30 @@
+#ifndef __XCACHE_H
+#define __XCACHE_H
+#define XCACHE_NAME       "XCache"
+#ifndef XCACHE_VERSION
+#	define XCACHE_VERSION "3.0.0-dev"
+#endif
+#define XCACHE_AUTHOR     "mOo"
+#define XCACHE_COPYRIGHT  "Copyright (c) 2005-2012"
+#define XCACHE_URL        "http://xcache.lighttpd.net"
+#define XCACHE_WIKI_URL   XCACHE_URL "/wiki"
+
+#include "php.h"
+
+#if defined(E_STRICT) || defined(E_DEPRECATED)
+#define XCACHE_ERROR_CACHING
+#endif
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include "xcache/xc_shm.h"
+#include "xcache/xc_lock.h"
+#include "xcache/xc_compatibility.h"
+
+extern zend_module_entry xcache_module_entry;
+#define phpext_xcache_ptr &xcache_module_entry
+
+extern zend_bool xc_test;
+
+#endif /* __XCACHE_H */
Index: /tags/3.0.0-rc1/config.m4
===================================================================
--- /tags/3.0.0-rc1/config.m4	(revision 1135)
+++ /tags/3.0.0-rc1/config.m4	(revision 1135)
@@ -0,0 +1,141 @@
+dnl vim:ts=2:sw=2:expandtab
+
+AC_DEFUN([XCACHE_MODULE], [
+  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 mod_$1/xc_$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
+  PHP_ARG_ENABLE(xcache-constant, for XCache handle of compile time constant,
+  [  --enable-xcache-constant        XCache: Handle new constants made by php compiler (e.g.: for __halt_compiler)], yes, no)
+  if test "$PHP_XCACHE_CONSTANT" != "no"; then
+    AC_DEFINE([HAVE_XCACHE_CONSTANT], 1, [Define to enable XCache handling of compile time constants])
+  fi
+
+  xcache_sources="xcache.c"
+  for i in \
+xc_stack.c \
+xc_trace.c \
+; do
+  xcache_sources="$xcache_sources util/$i"
+done
+  for i in \
+xc_allocator.c \
+xc_allocator_bestfit.c \
+xc_compatibility.c \
+xc_const_string.c \
+xc_extension.c \
+xc_ini.c \
+xc_lock.c \
+xc_opcode_spec.c \
+xc_processor.c \
+xc_sandbox.c \
+xc_shm.c \
+xc_shm_mmap.c \
+xc_utils.c \
+; do
+  xcache_sources="$xcache_sources xcache/$i"
+done
+  for i in \
+xc_cacher.c \
+; do
+  xcache_sources="$xcache_sources mod_cacher/$i"
+done
+  XCACHE_MODULES="cacher"
+  AC_DEFINE([HAVE_XCACHE_CACHER], 1, [Define to enable XCache cacher])
+  XCACHE_MODULE([optimizer],    [optimizer   ], [XCACHE_OPTIMIZER],    [(N/A)])
+  XCACHE_MODULE([coverager],    [coverager   ], [XCACHE_COVERAGER],    [Enable code coverage dumper, useful for testing php scripts])
+  XCACHE_MODULE([assembler],    [assembler   ], [XCACHE_ASSEMBLER],    [(N/A)])
+  XCACHE_MODULE([disassembler], [disassembler], [XCACHE_DISASSEMBLER], [Enable opcode to php variable dumper, not for server usage])
+  XCACHE_MODULE([encoder],      [encoder     ], [XCACHE_ENCODER],      [(N/A)])
+  XCACHE_MODULE([decoder],      [decoder     ], [XCACHE_DECODER],      [(N/A)])
+  AC_DEFINE_UNQUOTED([XCACHE_MODULES], "$XCACHE_MODULES", [Define what modules is built with XCache])
+
+  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
+    xcache_sources="$xcache_sources xcache/xc_malloc.c"
+    AC_DEFINE([HAVE_XCACHE_TEST], 1, [Define to enable XCache self test])
+  else
+    XCACHE_ENABLE_TEST=
+  fi
+  PHP_SUBST([XCACHE_ENABLE_TEST])
+
+  PHP_ARG_ENABLE(xcache-dprint, for XCache self test,
+  [  --enable-xcache-dprint          XCache: Enable debug print functions - FOR DEVELOPERS ONLY!!], no, no)
+  if test "$PHP_XCACHE_DPRINT" != "no"; then
+    AC_DEFINE([HAVE_XCACHE_DPRINT], 1, [Define to enable XCache debug print functions])
+  fi
+
+  PHP_NEW_EXTENSION(xcache, $xcache_sources, $ext_shared)
+  PHP_ADD_BUILD_DIR($ext_builddir/util)
+  PHP_ADD_BUILD_DIR($ext_builddir/xcache)
+  PHP_ADD_BUILD_DIR($ext_builddir/submodules)
+  PHP_ADD_MAKEFILE_FRAGMENT()
+  PHP_ADD_MAKEFILE_FRAGMENT($ext_srcdir/Makefile.frag.deps)
+
+  AC_PATH_PROGS([XCACHE_AWK], [gawk awk])
+  dnl clean locale for gawk 3.1.5 assertion bug
+  if echo | LANG=C "$XCACHE_AWK" -- '' > /dev/null 2>&1 ; then
+    XCACHE_AWK="LANG=C $XCACHE_AWK"
+  else
+    if echo | /usr/bin/env - "$XCACHE_AWK" -- '' > /dev/null 2>&1 ; then
+      XCACHE_AWK="/usr/bin/env - $XCACHE_AWK"
+    fi
+  fi
+  PHP_SUBST([XCACHE_AWK])
+  AC_PATH_PROGS([M4], [m4])
+  if test "$PHP_XCACHE_TEST" != "no"; then
+    if echo | "$M4" -E > /dev/null 2>&1 ; then
+      M4="$M4 -E"
+    fi
+  fi
+   dnl fix for solaris m4: size of the push-back and argument
+  if echo | "$M4" -B 102400 > /dev/null 2>&1 ; then
+    M4="$M4 -B 102400"
+  fi
+  PHP_SUBST([M4])
+  XCACHE_BACKTICK="'"'`'"'"
+  PHP_SUBST([XCACHE_BACKTICK])
+  AC_PATH_PROGS([GREP], [grep])
+  PHP_SUBST([GREP])
+  AC_PATH_PROGS([SED], [sed])
+  PHP_SUBST([SED])
+
+  AC_PATH_PROGS([INDENT], [indent cat])
+  XCACHE_INDENT=cat
+  case $INDENT in
+  */indent[)]
+    XCACHE_INDENT="$INDENT"
+    opts="-kr --use-tabs --tab-size 4"
+    if echo | $INDENT $opts > /dev/null 2>&1 ; then
+      XCACHE_INDENT="$XCACHE_INDENT $opts"
+    fi
+    opts="-sob -nce"
+    if echo | $INDENT $opts > /dev/null 2>&1 ; then
+      XCACHE_INDENT="$XCACHE_INDENT $opts"
+    fi
+    opts="-l 160"
+    if echo | $INDENT $opts > /dev/null 2>&1 ; then
+      XCACHE_INDENT="$XCACHE_INDENT $opts"
+    fi
+    ;;
+  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])
+fi
Index: /tags/3.0.0-rc1/htdocs/cacher/lang/zh-traditional.po
===================================================================
--- /tags/3.0.0-rc1/htdocs/cacher/lang/zh-traditional.po	(revision 1148)
+++ /tags/3.0.0-rc1/htdocs/cacher/lang/zh-traditional.po	(revision 1148)
@@ -0,0 +1,266 @@
+msgid ""
+msgstr ""
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2012-09-02 00:52+0800\n"
+"Language: zh_TW\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: edit.tpl.php:8
+#, php-format
+msgid "Editing Variable %s"
+msgstr "正在编辑变量 %s"
+
+#: edit.tpl.php:13
+#, php-format
+msgid "Set %s in config to enable"
+msgstr "請在配置文件中設置 %s 啟用本功能"
+
+#: index.php:187 index.php:213
+msgid "Total"
+msgstr "总共"
+
+#: index.php:263
+msgid "Summary"
+msgstr "簡要訊息"
+
+#: index.php:264
+msgid "List PHP"
+msgstr "列出PHP"
+
+#: index.php:265
+msgid "List Var Data"
+msgstr "列變數資料"
+
+#: listentries.tpl.php:11
+msgid "php Cached"
+msgstr "快取的 PHP 指令"
+
+#: listentries.tpl.php:11
+msgid "var Cached"
+msgstr "快取的變數"
+
+#: listentries.tpl.php:15
+msgid "php Deleted"
+msgstr "待刪 PHP 指令快取"
+
+#: listentries.tpl.php:15
+msgid "var Deleted"
+msgstr "待刪變數快取"
+
+#: sub/entrylist.tpl.php:14
+msgid "entry.id"
+msgstr "Id|"
+
+#: sub/entrylist.tpl.php:19
+msgid "entry.remove"
+msgstr "移除|"
+
+#: sub/entrylist.tpl.php:24
+msgid "entry.name"
+msgstr "項目名稱/檔案名稱|項目名稱或者檔案名稱"
+
+#: sub/entrylist.tpl.php:25
+msgid "entry.hits"
+msgstr "命中|該項目被命中的次數 (從共享記憶體區載入)"
+
+#: sub/entrylist.tpl.php:26
+msgid "entry.size"
+msgstr "大小|項目在共享記憶體裡佔用位元數"
+
+#: sub/entrylist.tpl.php:31
+msgid "entry.refcount"
+msgstr "引用數|項目依然被其他程序佔用的引用次數"
+
+#: sub/entrylist.tpl.php:32
+msgid "entry.phprefcount"
+msgstr "共享|與本項目相同 PHP 內容的个數"
+
+#: sub/entrylist.tpl.php:33
+msgid "entry.class_cnt"
+msgstr "类|类个数"
+
+#: sub/entrylist.tpl.php:34
+msgid "entry.function_cnt"
+msgstr "函数|函数个数"
+
+#: sub/entrylist.tpl.php:35
+msgid "entry.file_size"
+msgstr "源大小|原始檔案大小"
+
+#: sub/entrylist.tpl.php:36
+msgid "entry.file_mtime"
+msgstr "修改|原始檔案最後修改時間"
+
+#: sub/entrylist.tpl.php:39
+msgid "entry.file_device"
+msgstr "dev|原始檔案所在設備ID"
+
+#: sub/entrylist.tpl.php:40
+msgid "entry.file_inode"
+msgstr "ino|原始檔案的inode"
+
+#: sub/entrylist.tpl.php:44
+msgid "entry.hash"
+msgstr "Hash|Hash"
+
+#: sub/entrylist.tpl.php:45
+msgid "entry.atime"
+msgstr "存取|最後存取該項目的時間"
+
+#: sub/entrylist.tpl.php:46
+msgid "entry.ctime"
+msgstr "建立|該項目被建立於共享內的時間"
+
+#: sub/entrylist.tpl.php:51
+msgid "entry.delete"
+msgstr "移除|該項目被移除於共享內的時間"
+
+#: sub/entrylist.tpl.php:149
+msgid "Remove Selected"
+msgstr "移除所选"
+
+#: sub/moduleinfo.tpl.php:1
+msgid "Module Info"
+msgstr "組元訊息"
+
+#: sub/summary.tpl.php:3
+msgid "Caches"
+msgstr "快取"
+
+#: sub/summary.tpl.php:6
+msgid "cache.cache"
+msgstr "快取|"
+
+#: sub/summary.tpl.php:7
+msgid "cache.slots"
+msgstr "槽|Hash 槽個數，對應 php.ini 裡的設置"
+
+#: sub/summary.tpl.php:8
+msgid "cache.size"
+msgstr "大小|共享記憶體區大小，單位：位元"
+
+#: sub/summary.tpl.php:9
+msgid "cache.avail"
+msgstr "剩餘|可用記憶體，對應共享記憶體區的剩餘記憶體位元數"
+
+#: sub/summary.tpl.php:10
+msgid "cache.blocksgraph"
+msgstr "百分比图|條狀顯示可用記憶體的比例"
+
+#: sub/summary.tpl.php:11
+msgid "cache.operations"
+msgstr "操作|點擊按鈕清除對應共享記憶體區的資料"
+
+#: sub/summary.tpl.php:12
+msgid "cache.status"
+msgstr ""
+"狀態|狀態標記. 當共享內存區正在編譯 PHP 腳本時標記為 \"編譯中\". 當共享內存區"
+"暫停使用時標記為 \"禁用\""
+
+#: sub/summary.tpl.php:13
+msgid "cache.hits"
+msgstr "命中|共享記憶體命中次數，命中=從該共享記憶體載入 PHP 或者變數"
+
+#: sub/summary.tpl.php:14
+msgid "cache.hits_graph"
+msgstr "24H 分布|24 小时命中分布图. 图表现是最后 24 小时的命中次数"
+
+#: sub/summary.tpl.php:15
+msgid "cache.hits_avg_h"
+msgstr "命中/H|每小时命中次数. 只统计最后 24 小时"
+
+#: sub/summary.tpl.php:16
+msgid "cache.hits_avg_s"
+msgstr "命中/S|每秒命中次数. 只统计最后 5 秒"
+
+#: sub/summary.tpl.php:17
+msgid "cache.updates"
+msgstr "更新|共享記憶更新過次數"
+
+#: sub/summary.tpl.php:18
+msgid "cache.skips"
+msgstr ""
+"跳過|跳過更新次數，跳過=XCache 自動判斷阻塞的共享記憶體區自動跳過阻塞等待，直"
+"接使用编译不存储方式繼續處理請求"
+
+#: sub/summary.tpl.php:19
+msgid "cache.ooms"
+msgstr ""
+"記憶體不足|記憶體不足次數，顯示需要儲存新資料但是共享記憶體區記憶體不足的次"
+"數. 如果出現太頻繁請考慮加大配置中的 xcache.size 或者 xcache.var_size"
+
+#: sub/summary.tpl.php:20
+msgid "cache.errors"
+msgstr ""
+"错误|编译错误, 显示您的脚本被编译时出错的次数. 如果您发现这个数字不断增长, 您"
+"应该检查什么脚本产生错误. 参考 說明 获取更多信息"
+
+#: sub/summary.tpl.php:21
+msgid "cache.readonly_protected"
+msgstr "保护|顯示該 Cache 是否支援並啟用 readonly_protection. 参考 說明"
+
+#: sub/summary.tpl.php:22
+msgid "cache.cached"
+msgstr "快取|共享記憶體於該共享記憶體區的項目個數"
+
+#: sub/summary.tpl.php:23
+msgid "cache.deleted"
+msgstr "待刪|共享記憶體區內將要刪除的項目 (已經刪除但是還被某些程序佔用)"
+
+#: sub/summary.tpl.php:24
+msgid "cache.gc_timer"
+msgstr "GC|垃圾回收的倒數計時"
+
+#: sub/summary.tpl.php:30
+msgid "Clear"
+msgstr "清除"
+
+#: sub/summary.tpl.php:31
+msgid "Disabled"
+msgstr "禁用"
+
+#: sub/summary.tpl.php:32
+msgid "Disable"
+msgstr "禁用"
+
+#: sub/summary.tpl.php:33
+msgid "Enable"
+msgstr "啟用"
+
+#: sub/summary.tpl.php:34
+msgid "Compiling"
+msgstr "編譯中"
+
+#: sub/summary.tpl.php:35
+msgid "Normal"
+msgstr "正常"
+
+#: sub/summary.tpl.php:36 sub/testcoredump.tpl.php:3
+msgid "Sure?"
+msgstr "確認?"
+
+#: sub/summary.tpl.php:132
+msgid "Legends:"
+msgstr "图例:"
+
+#: sub/summary.tpl.php:134
+msgid "% Free"
+msgstr "% 剩余"
+
+#: sub/summary.tpl.php:134
+msgid "% Used"
+msgstr "% 已用"
+
+#: sub/summary.tpl.php:136
+msgid "Free Blocks"
+msgstr "未用块"
+
+#: sub/summary.tpl.php:136
+msgid "Used Blocks"
+msgstr "已用块"
+
+#: sub/summary.tpl.php:138
+msgid "Hits"
+msgstr "命中"
Index: /tags/3.0.0-rc1/htdocs/cacher/lang/en.php
===================================================================
--- /tags/3.0.0-rc1/htdocs/cacher/lang/en.php	(revision 1148)
+++ /tags/3.0.0-rc1/htdocs/cacher/lang/en.php	(revision 1148)
@@ -0,0 +1,87 @@
+<?php
+// auto generated, do not modify
+$strings += array(
+		"php Cached"
+		=> "PHP Cached",
+		"var Cached"
+		=> "Variable Cached",
+		"php Deleted"
+		=> "PHP Deleted",
+		"var Deleted"
+		=> "Variable Deleted",
+		"entry.id"
+		=> "Id|",
+		"entry.remove"
+		=> "Remove|",
+		"entry.name"
+		=> "Entry name|The entry name or filename",
+		"entry.hits"
+		=> "Hits|Hit times of this entry (loaded from this cache)",
+		"entry.size"
+		=> "Size|Size in bytes of this entry in the cache",
+		"entry.refcount"
+		=> "Refs|Reference count of this entry is holded by a php request",
+		"entry.phprefcount"
+		=> "Shares|Count of entry sharing this php data",
+		"entry.class_cnt"
+		=> "Cls.|Count of classes",
+		"entry.function_cnt"
+		=> "Funcs|Count of functions",
+		"entry.file_size"
+		=> "Src Size|Size of the source file",
+		"entry.file_mtime"
+		=> "Modified|Last modified time of the source file",
+		"entry.file_device"
+		=> "dev|device number of the source file",
+		"entry.file_inode"
+		=> "ino|inode number of the source file",
+		"entry.hash"
+		=> "Hash|Hash value of this entry",
+		"entry.atime"
+		=> "Access|Last time when this entry is accessed",
+		"entry.ctime"
+		=> "Create|The time when this entry is stored",
+		"entry.delete"
+		=> "Delete|The time when this entry is deleted",
+		"Caches"
+		=> "Caches",
+		"cache.cache"
+		=> "Cache|",
+		"cache.slots"
+		=> "Slots|Number of hash slots. the setting from your php.ini",
+		"cache.size"
+		=> "Size|Cache Size, Size of the cache (or cache chunk), in bytes",
+		"cache.avail"
+		=> "Avail|Available Memory, free memory in bytes of this cache",
+		"cache.blocksgraph"
+		=> "Percent Graph|Shows how much memory available in percent, and memory blocks status in graph",
+		"cache.operations"
+		=> "Operations|Press the clear button to clean this cache",
+		"cache.status"
+		=> "Status|Compiling flag, \"Compiling\" if the cache is busy compiling php script. \"Disabled\" if cache is disabled",
+		"cache.hits"
+		=> "Hits|Cache Hits, hit=a var/php is loaded from this cache",
+		"cache.hits_graph"
+		=> "Hits*24H|Hits graph of last 24 hours",
+		"cache.hits_avg_h"
+		=> "Hits/H|Average Hits per Hour. Only last 24 hours is logged",
+		"cache.hits_avg_s"
+		=> "Hits/S|Average Hits per Second. Only last 5 seconds is logged",
+		"cache.updates"
+		=> "Updates|Cache Updates",
+		"cache.skips"
+		=> "Skips|Skips. Skip=updates are needed but skipped for some reason. e.g.: other process/thread is busy compiling on this cache",
+		"cache.ooms"
+		=> "OOMs|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",
+		"cache.errors"
+		=> "Errs|Compiler errors, how many times your script(s) failed to be compiled by PHP. You should really check what is happening if you see this value increase. (See Help for more information)",
+		"cache.readonly_protected"
+		=> "Protected|Whether readonly_protection is available and enable on this cache (See help for more information)",
+		"cache.cached"
+		=> "Cached|Number of entries stored in this cache",
+		"cache.deleted"
+		=> "Deleted|Number of entries is pending in delete list (expired but referenced)",
+		"cache.gc_timer"
+		=> "GC|Seconds count down of Garbage Collection",
+		);
+
Index: /tags/3.0.0-rc1/htdocs/cacher/lang/zh-simplified.php
===================================================================
--- /tags/3.0.0-rc1/htdocs/cacher/lang/zh-simplified.php	(revision 1121)
+++ /tags/3.0.0-rc1/htdocs/cacher/lang/zh-simplified.php	(revision 1121)
@@ -0,0 +1,129 @@
+<?php
+// auto generated, do not modify
+$strings += array(
+		"Editing Variable %s"
+		=> "正在编辑变量 %s",
+		"Set %s in config to enable"
+		=> "请在配置文件中设置 %s 启用本功能",
+		"Total"
+		=> "总共",
+		"Summary"
+		=> "摘要信息",
+		"List PHP"
+		=> "列出PHP",
+		"List Var Data"
+		=> "列变量数据",
+		"php Cached"
+		=> "缓存的 PHP 脚本",
+		"var Cached"
+		=> "缓存的变量",
+		"php Deleted"
+		=> "待删 PHP 脚本缓存",
+		"var Deleted"
+		=> "待删变量缓存",
+		"entry.id"
+		=> "Id|",
+		"entry.remove"
+		=> "删除|",
+		"entry.name"
+		=> "项目名/文件名|项目名或者文件名",
+		"entry.hits"
+		=> "命中|该项目被命中的次数 (从缓存区载入)",
+		"entry.size"
+		=> "大小|项目在缓存里占用字节数",
+		"entry.refcount"
+		=> "引用数|项目依然被其他进程占据的引用次数",
+		"entry.phprefcount"
+		=> "共享数|与本项目相同 PHP 代码的个数",
+		"entry.class_cnt"
+		=> "类|类个数",
+		"entry.function_cnt"
+		=> "函数|函数个数",
+		"entry.file_size"
+		=> "源大小|源文件大小",
+		"entry.file_mtime"
+		=> "修改|源文件最后修改时间",
+		"entry.file_device"
+		=> "dev|源文件所在设备ID",
+		"entry.file_inode"
+		=> "ino|源文件的 inode",
+		"entry.hash"
+		=> "哈希|该项目的哈希值",
+		"entry.atime"
+		=> "访问|最后访问该项目的时间",
+		"entry.ctime"
+		=> "创建|该项目被创建于缓存区内的时间",
+		"entry.delete"
+		=> "删除|该项目被决定删除的时间",
+		"Remove Selected"
+		=> "删除所选",
+		"Module Info"
+		=> "模块信息",
+		"Caches"
+		=> "缓存区",
+		"cache.cache"
+		=> "缓存|",
+		"cache.slots"
+		=> "槽|Hash 槽个数, 对应 php.ini 里的设置",
+		"cache.size"
+		=> "大小|共享内存区大小, 单位: 字节",
+		"cache.avail"
+		=> "剩余|可用内存, 对应缓存区的剩余内存字节数",
+		"cache.blocksgraph"
+		=> "百分比图|条状显示可用内存的比例, 以及显示分配块状态",
+		"cache.operations"
+		=> "操作|点击按钮清除对应缓存区的数据",
+		"cache.status"
+		=> "状态|状态标记. 当缓存区正在编译 PHP 脚本时标记为 \"编译中\". 当缓存区暂停使用时标记为 \"禁用\"",
+		"cache.hits"
+		=> "命中|缓存命中次数, 命中=从该缓存载入 PHP 或者变量",
+		"cache.hits_graph"
+		=> "24H 分布|24 小时命中分布图. 图表现是最后 24 小时的命中次数",
+		"cache.hits_avg_h"
+		=> "命中/H|每小时命中次数. 只统计最后 24 小时",
+		"cache.hits_avg_s"
+		=> "命中/S|每秒命中次数. 只统计最后 5 秒",
+		"cache.updates"
+		=> "更新|缓存更新次数",
+		"cache.skips"
+		=> "跳过|跳过更新次数, 跳过=XCache 自动判断阻塞的缓存区自动跳过阻塞等待, 直接使用编译不缓存方式继续处理请求",
+		"cache.ooms"
+		=> "内存不足|内存不足次数, 显示需要存储新数据但是缓存区内存不足的次数. 如果出现太频繁请考虑加大配置中的 xcache.size 或者 xcache.var_size",
+		"cache.errors"
+		=> "错误|编译错误, 显示您的脚本被编译时出错的次数. 如果您发现这个数字不断增长, 您应该检查什么脚本产生错误. 参考 帮助 获取更多信息",
+		"cache.readonly_protected"
+		=> "保护|显示该 Cache 是否支持并启用 readonly_protection. 参考 帮助 获取更多信息",
+		"cache.cached"
+		=> "缓存|缓存于该缓存区的项目条数",
+		"cache.deleted"
+		=> "待删|缓存区内将要删除的项目 (已经删除但是还被某些进程占用)",
+		"cache.gc_timer"
+		=> "GC|垃圾回收的倒计时",
+		"Clear"
+		=> "清除",
+		"Disabled"
+		=> "禁用",
+		"Disable"
+		=> "禁用",
+		"Enable"
+		=> "启用",
+		"Compiling"
+		=> "编译中",
+		"Normal"
+		=> "正常",
+		"Sure?"
+		=> "确认?",
+		"Legends:"
+		=> "图例:",
+		"% Free"
+		=> "% 剩余",
+		"% Used"
+		=> "% 已用",
+		"Free Blocks"
+		=> "未用块",
+		"Used Blocks"
+		=> "已用块",
+		"Hits"
+		=> "命中",
+		);
+
Index: /tags/3.0.0-rc1/htdocs/cacher/lang/en.po
===================================================================
--- /tags/3.0.0-rc1/htdocs/cacher/lang/en.po	(revision 1148)
+++ /tags/3.0.0-rc1/htdocs/cacher/lang/en.po	(revision 1148)
@@ -0,0 +1,273 @@
+msgid ""
+msgstr ""
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2012-09-02 00:52+0800\n"
+"Language: en\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: edit.tpl.php:8
+#, php-format
+msgid "Editing Variable %s"
+msgstr ""
+
+#: edit.tpl.php:13
+#, php-format
+msgid "Set %s in config to enable"
+msgstr ""
+
+#: index.php:187 index.php:213
+msgid "Total"
+msgstr ""
+
+#: index.php:263
+msgid "Summary"
+msgstr ""
+
+#: index.php:264
+msgid "List PHP"
+msgstr ""
+
+#: index.php:265
+msgid "List Var Data"
+msgstr ""
+
+#: listentries.tpl.php:11
+msgid "php Cached"
+msgstr "PHP Cached"
+
+#: listentries.tpl.php:11
+msgid "var Cached"
+msgstr "Variable Cached"
+
+#: listentries.tpl.php:15
+msgid "php Deleted"
+msgstr "PHP Deleted"
+
+#: listentries.tpl.php:15
+msgid "var Deleted"
+msgstr "Variable Deleted"
+
+#: sub/entrylist.tpl.php:14
+msgid "entry.id"
+msgstr "Id|"
+
+#: sub/entrylist.tpl.php:19
+msgid "entry.remove"
+msgstr "Remove|"
+
+#: sub/entrylist.tpl.php:24
+msgid "entry.name"
+msgstr "Entry name|The entry name or filename"
+
+#: sub/entrylist.tpl.php:25
+msgid "entry.hits"
+msgstr "Hits|Hit times of this entry (loaded from this cache)"
+
+#: sub/entrylist.tpl.php:26
+msgid "entry.size"
+msgstr "Size|Size in bytes of this entry in the cache"
+
+#: sub/entrylist.tpl.php:31
+msgid "entry.refcount"
+msgstr "Refs|Reference count of this entry is holded by a php request"
+
+#: sub/entrylist.tpl.php:32
+msgid "entry.phprefcount"
+msgstr "Shares|Count of entry sharing this php data"
+
+#: sub/entrylist.tpl.php:33
+msgid "entry.class_cnt"
+msgstr "Cls.|Count of classes"
+
+#: sub/entrylist.tpl.php:34
+msgid "entry.function_cnt"
+msgstr "Funcs|Count of functions"
+
+#: sub/entrylist.tpl.php:35
+msgid "entry.file_size"
+msgstr "Src Size|Size of the source file"
+
+#: sub/entrylist.tpl.php:36
+msgid "entry.file_mtime"
+msgstr "Modified|Last modified time of the source file"
+
+#: sub/entrylist.tpl.php:39
+msgid "entry.file_device"
+msgstr "dev|device number of the source file"
+
+#: sub/entrylist.tpl.php:40
+msgid "entry.file_inode"
+msgstr "ino|inode number of the source file"
+
+#: sub/entrylist.tpl.php:44
+msgid "entry.hash"
+msgstr "Hash|Hash value of this entry"
+
+#: sub/entrylist.tpl.php:45
+msgid "entry.atime"
+msgstr "Access|Last time when this entry is accessed"
+
+#: sub/entrylist.tpl.php:46
+msgid "entry.ctime"
+msgstr "Create|The time when this entry is stored"
+
+#: sub/entrylist.tpl.php:51
+msgid "entry.delete"
+msgstr "Delete|The time when this entry is deleted"
+
+#: sub/entrylist.tpl.php:149
+msgid "Remove Selected"
+msgstr ""
+
+#: sub/moduleinfo.tpl.php:1
+msgid "Module Info"
+msgstr ""
+
+#: sub/summary.tpl.php:3
+msgid "Caches"
+msgstr "Caches"
+
+#: sub/summary.tpl.php:6
+msgid "cache.cache"
+msgstr "Cache|"
+
+#: sub/summary.tpl.php:7
+msgid "cache.slots"
+msgstr "Slots|Number of hash slots. the setting from your php.ini"
+
+#: sub/summary.tpl.php:8
+msgid "cache.size"
+msgstr "Size|Cache Size, Size of the cache (or cache chunk), in bytes"
+
+#: sub/summary.tpl.php:9
+msgid "cache.avail"
+msgstr "Avail|Available Memory, free memory in bytes of this cache"
+
+#: sub/summary.tpl.php:10
+msgid "cache.blocksgraph"
+msgstr ""
+"Percent Graph|Shows how much memory available in percent, and memory blocks "
+"status in graph"
+
+#: sub/summary.tpl.php:11
+msgid "cache.operations"
+msgstr "Operations|Press the clear button to clean this cache"
+
+#: sub/summary.tpl.php:12
+msgid "cache.status"
+msgstr ""
+"Status|Compiling flag, \"Compiling\" if the cache is busy compiling php "
+"script. \"Disabled\" if cache is disabled"
+
+#: sub/summary.tpl.php:13
+msgid "cache.hits"
+msgstr "Hits|Cache Hits, hit=a var/php is loaded from this cache"
+
+#: sub/summary.tpl.php:14
+msgid "cache.hits_graph"
+msgstr "Hits*24H|Hits graph of last 24 hours"
+
+#: sub/summary.tpl.php:15
+msgid "cache.hits_avg_h"
+msgstr "Hits/H|Average Hits per Hour. Only last 24 hours is logged"
+
+#: sub/summary.tpl.php:16
+msgid "cache.hits_avg_s"
+msgstr "Hits/S|Average Hits per Second. Only last 5 seconds is logged"
+
+#: sub/summary.tpl.php:17
+msgid "cache.updates"
+msgstr "Updates|Cache Updates"
+
+#: sub/summary.tpl.php:18
+msgid "cache.skips"
+msgstr ""
+"Skips|Skips. Skip=updates are needed but skipped for some reason. e.g.: "
+"other process/thread is busy compiling on this cache"
+
+#: sub/summary.tpl.php:19
+msgid "cache.ooms"
+msgstr ""
+"OOMs|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"
+
+#: sub/summary.tpl.php:20
+msgid "cache.errors"
+msgstr ""
+"Errs|Compiler errors, how many times your script(s) failed to be compiled by "
+"PHP. You should really check what is happening if you see this value "
+"increase. (See Help for more information)"
+
+#: sub/summary.tpl.php:21
+msgid "cache.readonly_protected"
+msgstr ""
+"Protected|Whether readonly_protection is available and enable on this cache "
+"(See help for more information)"
+
+#: sub/summary.tpl.php:22
+msgid "cache.cached"
+msgstr "Cached|Number of entries stored in this cache"
+
+#: sub/summary.tpl.php:23
+msgid "cache.deleted"
+msgstr ""
+"Deleted|Number of entries is pending in delete list (expired but referenced)"
+
+#: sub/summary.tpl.php:24
+msgid "cache.gc_timer"
+msgstr "GC|Seconds count down of Garbage Collection"
+
+#: sub/summary.tpl.php:30
+msgid "Clear"
+msgstr ""
+
+#: sub/summary.tpl.php:31
+msgid "Disabled"
+msgstr ""
+
+#: sub/summary.tpl.php:32
+msgid "Disable"
+msgstr ""
+
+#: sub/summary.tpl.php:33
+msgid "Enable"
+msgstr ""
+
+#: sub/summary.tpl.php:34
+msgid "Compiling"
+msgstr ""
+
+#: sub/summary.tpl.php:35
+msgid "Normal"
+msgstr ""
+
+#: sub/summary.tpl.php:36 sub/testcoredump.tpl.php:3
+msgid "Sure?"
+msgstr ""
+
+#: sub/summary.tpl.php:132
+msgid "Legends:"
+msgstr ""
+
+#: sub/summary.tpl.php:134
+msgid "% Free"
+msgstr ""
+
+#: sub/summary.tpl.php:134
+msgid "% Used"
+msgstr ""
+
+#: sub/summary.tpl.php:136
+msgid "Free Blocks"
+msgstr ""
+
+#: sub/summary.tpl.php:136
+msgid "Used Blocks"
+msgstr ""
+
+#: sub/summary.tpl.php:138
+msgid "Hits"
+msgstr ""
Index: /tags/3.0.0-rc1/htdocs/cacher/lang/zh-traditional.php
===================================================================
--- /tags/3.0.0-rc1/htdocs/cacher/lang/zh-traditional.php	(revision 1121)
+++ /tags/3.0.0-rc1/htdocs/cacher/lang/zh-traditional.php	(revision 1121)
@@ -0,0 +1,129 @@
+<?php
+// auto generated, do not modify
+$strings += array(
+		"Editing Variable %s"
+		=> "正在编辑变量 %s",
+		"Set %s in config to enable"
+		=> "請在配置文件中設置 %s 啟用本功能",
+		"Total"
+		=> "总共",
+		"Summary"
+		=> "簡要訊息",
+		"List PHP"
+		=> "列出PHP",
+		"List Var Data"
+		=> "列變數資料",
+		"php Cached"
+		=> "快取的 PHP 指令",
+		"var Cached"
+		=> "快取的變數",
+		"php Deleted"
+		=> "待刪 PHP 指令快取",
+		"var Deleted"
+		=> "待刪變數快取",
+		"entry.id"
+		=> "Id|",
+		"entry.remove"
+		=> "移除|",
+		"entry.name"
+		=> "項目名稱/檔案名稱|項目名稱或者檔案名稱",
+		"entry.hits"
+		=> "命中|該項目被命中的次數 (從共享記憶體區載入)",
+		"entry.size"
+		=> "大小|項目在共享記憶體裡佔用位元數",
+		"entry.refcount"
+		=> "引用數|項目依然被其他程序佔用的引用次數",
+		"entry.phprefcount"
+		=> "共享|與本項目相同 PHP 內容的个數",
+		"entry.class_cnt"
+		=> "类|类个数",
+		"entry.function_cnt"
+		=> "函数|函数个数",
+		"entry.file_size"
+		=> "源大小|原始檔案大小",
+		"entry.file_mtime"
+		=> "修改|原始檔案最後修改時間",
+		"entry.file_device"
+		=> "dev|原始檔案所在設備ID",
+		"entry.file_inode"
+		=> "ino|原始檔案的inode",
+		"entry.hash"
+		=> "Hash|Hash",
+		"entry.atime"
+		=> "存取|最後存取該項目的時間",
+		"entry.ctime"
+		=> "建立|該項目被建立於共享內的時間",
+		"entry.delete"
+		=> "移除|該項目被移除於共享內的時間",
+		"Remove Selected"
+		=> "移除所选",
+		"Module Info"
+		=> "組元訊息",
+		"Caches"
+		=> "快取",
+		"cache.cache"
+		=> "快取|",
+		"cache.slots"
+		=> "槽|Hash 槽個數，對應 php.ini 裡的設置",
+		"cache.size"
+		=> "大小|共享記憶體區大小，單位：位元",
+		"cache.avail"
+		=> "剩餘|可用記憶體，對應共享記憶體區的剩餘記憶體位元數",
+		"cache.blocksgraph"
+		=> "百分比图|條狀顯示可用記憶體的比例",
+		"cache.operations"
+		=> "操作|點擊按鈕清除對應共享記憶體區的資料",
+		"cache.status"
+		=> "狀態|狀態標記. 當共享內存區正在編譯 PHP 腳本時標記為 \"編譯中\". 當共享內存區暫停使用時標記為 \"禁用\"",
+		"cache.hits"
+		=> "命中|共享記憶體命中次數，命中=從該共享記憶體載入 PHP 或者變數",
+		"cache.hits_graph"
+		=> "24H 分布|24 小时命中分布图. 图表现是最后 24 小时的命中次数",
+		"cache.hits_avg_h"
+		=> "命中/H|每小时命中次数. 只统计最后 24 小时",
+		"cache.hits_avg_s"
+		=> "命中/S|每秒命中次数. 只统计最后 5 秒",
+		"cache.updates"
+		=> "更新|共享記憶更新過次數",
+		"cache.skips"
+		=> "跳過|跳過更新次數，跳過=XCache 自動判斷阻塞的共享記憶體區自動跳過阻塞等待，直接使用编译不存储方式繼續處理請求",
+		"cache.ooms"
+		=> "記憶體不足|記憶體不足次數，顯示需要儲存新資料但是共享記憶體區記憶體不足的次數. 如果出現太頻繁請考慮加大配置中的 xcache.size 或者 xcache.var_size",
+		"cache.errors"
+		=> "错误|编译错误, 显示您的脚本被编译时出错的次数. 如果您发现这个数字不断增长, 您应该检查什么脚本产生错误. 参考 說明 获取更多信息",
+		"cache.readonly_protected"
+		=> "保护|顯示該 Cache 是否支援並啟用 readonly_protection. 参考 說明",
+		"cache.cached"
+		=> "快取|共享記憶體於該共享記憶體區的項目個數",
+		"cache.deleted"
+		=> "待刪|共享記憶體區內將要刪除的項目 (已經刪除但是還被某些程序佔用)",
+		"cache.gc_timer"
+		=> "GC|垃圾回收的倒數計時",
+		"Clear"
+		=> "清除",
+		"Disabled"
+		=> "禁用",
+		"Disable"
+		=> "禁用",
+		"Enable"
+		=> "啟用",
+		"Compiling"
+		=> "編譯中",
+		"Normal"
+		=> "正常",
+		"Sure?"
+		=> "確認?",
+		"Legends:"
+		=> "图例:",
+		"% Free"
+		=> "% 剩余",
+		"% Used"
+		=> "% 已用",
+		"Free Blocks"
+		=> "未用块",
+		"Used Blocks"
+		=> "已用块",
+		"Hits"
+		=> "命中",
+		);
+
Index: /tags/3.0.0-rc1/htdocs/cacher/lang/zh-simplified.po
===================================================================
--- /tags/3.0.0-rc1/htdocs/cacher/lang/zh-simplified.po	(revision 1148)
+++ /tags/3.0.0-rc1/htdocs/cacher/lang/zh-simplified.po	(revision 1148)
@@ -0,0 +1,267 @@
+msgid ""
+msgstr ""
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2012-09-02 00:52+0800\n"
+"Language: zh\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: edit.tpl.php:8
+#, php-format
+msgid "Editing Variable %s"
+msgstr "正在编辑变量 %s"
+
+#: edit.tpl.php:13
+#, php-format
+msgid "Set %s in config to enable"
+msgstr "请在配置文件中设置 %s 启用本功能"
+
+#: index.php:187 index.php:213
+msgid "Total"
+msgstr "总共"
+
+#: index.php:263
+msgid "Summary"
+msgstr "摘要信息"
+
+#: index.php:264
+msgid "List PHP"
+msgstr "列出PHP"
+
+#: index.php:265
+msgid "List Var Data"
+msgstr "列变量数据"
+
+#: listentries.tpl.php:11
+msgid "php Cached"
+msgstr "缓存的 PHP 脚本"
+
+#: listentries.tpl.php:11
+msgid "var Cached"
+msgstr "缓存的变量"
+
+#: listentries.tpl.php:15
+msgid "php Deleted"
+msgstr "待删 PHP 脚本缓存"
+
+#: listentries.tpl.php:15
+msgid "var Deleted"
+msgstr "待删变量缓存"
+
+#: sub/entrylist.tpl.php:14
+msgid "entry.id"
+msgstr "Id|"
+
+#: sub/entrylist.tpl.php:19
+msgid "entry.remove"
+msgstr "删除|"
+
+#: sub/entrylist.tpl.php:24
+msgid "entry.name"
+msgstr "项目名/文件名|项目名或者文件名"
+
+#: sub/entrylist.tpl.php:25
+msgid "entry.hits"
+msgstr "命中|该项目被命中的次数 (从缓存区载入)"
+
+#: sub/entrylist.tpl.php:26
+msgid "entry.size"
+msgstr "大小|项目在缓存里占用字节数"
+
+#: sub/entrylist.tpl.php:31
+msgid "entry.refcount"
+msgstr "引用数|项目依然被其他进程占据的引用次数"
+
+#: sub/entrylist.tpl.php:32
+msgid "entry.phprefcount"
+msgstr "共享数|与本项目相同 PHP 代码的个数"
+
+#: sub/entrylist.tpl.php:33
+msgid "entry.class_cnt"
+msgstr "类|类个数"
+
+#: sub/entrylist.tpl.php:34
+msgid "entry.function_cnt"
+msgstr "函数|函数个数"
+
+#: sub/entrylist.tpl.php:35
+msgid "entry.file_size"
+msgstr "源大小|源文件大小"
+
+#: sub/entrylist.tpl.php:36
+msgid "entry.file_mtime"
+msgstr "修改|源文件最后修改时间"
+
+#: sub/entrylist.tpl.php:39
+msgid "entry.file_device"
+msgstr "dev|源文件所在设备ID"
+
+#: sub/entrylist.tpl.php:40
+msgid "entry.file_inode"
+msgstr "ino|源文件的 inode"
+
+#: sub/entrylist.tpl.php:44
+msgid "entry.hash"
+msgstr "哈希|该项目的哈希值"
+
+#: sub/entrylist.tpl.php:45
+msgid "entry.atime"
+msgstr "访问|最后访问该项目的时间"
+
+#: sub/entrylist.tpl.php:46
+msgid "entry.ctime"
+msgstr "创建|该项目被创建于缓存区内的时间"
+
+#: sub/entrylist.tpl.php:51
+msgid "entry.delete"
+msgstr "删除|该项目被决定删除的时间"
+
+#: sub/entrylist.tpl.php:149
+msgid "Remove Selected"
+msgstr "删除所选"
+
+#: sub/moduleinfo.tpl.php:1
+msgid "Module Info"
+msgstr "模块信息"
+
+#: sub/summary.tpl.php:3
+msgid "Caches"
+msgstr "缓存区"
+
+#: sub/summary.tpl.php:6
+msgid "cache.cache"
+msgstr "缓存|"
+
+#: sub/summary.tpl.php:7
+msgid "cache.slots"
+msgstr "槽|Hash 槽个数, 对应 php.ini 里的设置"
+
+#: sub/summary.tpl.php:8
+msgid "cache.size"
+msgstr "大小|共享内存区大小, 单位: 字节"
+
+#: sub/summary.tpl.php:9
+msgid "cache.avail"
+msgstr "剩余|可用内存, 对应缓存区的剩余内存字节数"
+
+#: sub/summary.tpl.php:10
+msgid "cache.blocksgraph"
+msgstr "百分比图|条状显示可用内存的比例, 以及显示分配块状态"
+
+#: sub/summary.tpl.php:11
+msgid "cache.operations"
+msgstr "操作|点击按钮清除对应缓存区的数据"
+
+#: sub/summary.tpl.php:12
+msgid "cache.status"
+msgstr ""
+"状态|状态标记. 当缓存区正在编译 PHP 脚本时标记为 \"编译中\". 当缓存区暂停使用"
+"时标记为 \"禁用\""
+
+#: sub/summary.tpl.php:13
+msgid "cache.hits"
+msgstr "命中|缓存命中次数, 命中=从该缓存载入 PHP 或者变量"
+
+#: sub/summary.tpl.php:14
+msgid "cache.hits_graph"
+msgstr "24H 分布|24 小时命中分布图. 图表现是最后 24 小时的命中次数"
+
+#: sub/summary.tpl.php:15
+msgid "cache.hits_avg_h"
+msgstr "命中/H|每小时命中次数. 只统计最后 24 小时"
+
+#: sub/summary.tpl.php:16
+msgid "cache.hits_avg_s"
+msgstr "命中/S|每秒命中次数. 只统计最后 5 秒"
+
+#: sub/summary.tpl.php:17
+msgid "cache.updates"
+msgstr "更新|缓存更新次数"
+
+#: sub/summary.tpl.php:18
+msgid "cache.skips"
+msgstr ""
+"跳过|跳过更新次数, 跳过=XCache 自动判断阻塞的缓存区自动跳过阻塞等待, 直接使用"
+"编译不缓存方式继续处理请求"
+
+#: sub/summary.tpl.php:19
+msgid "cache.ooms"
+msgstr ""
+"内存不足|内存不足次数, 显示需要存储新数据但是缓存区内存不足的次数. 如果出现太"
+"频繁请考虑加大配置中的 xcache.size 或者 xcache.var_size"
+
+#: sub/summary.tpl.php:20
+msgid "cache.errors"
+msgstr ""
+"错误|编译错误, 显示您的脚本被编译时出错的次数. 如果您发现这个数字不断增长, 您"
+"应该检查什么脚本产生错误. 参考 帮助 获取更多信息"
+
+#: sub/summary.tpl.php:21
+msgid "cache.readonly_protected"
+msgstr ""
+"保护|显示该 Cache 是否支持并启用 readonly_protection. 参考 帮助 获取更多信息"
+
+#: sub/summary.tpl.php:22
+msgid "cache.cached"
+msgstr "缓存|缓存于该缓存区的项目条数"
+
+#: sub/summary.tpl.php:23
+msgid "cache.deleted"
+msgstr "待删|缓存区内将要删除的项目 (已经删除但是还被某些进程占用)"
+
+#: sub/summary.tpl.php:24
+msgid "cache.gc_timer"
+msgstr "GC|垃圾回收的倒计时"
+
+#: sub/summary.tpl.php:30
+msgid "Clear"
+msgstr "清除"
+
+#: sub/summary.tpl.php:31
+msgid "Disabled"
+msgstr "禁用"
+
+#: sub/summary.tpl.php:32
+msgid "Disable"
+msgstr "禁用"
+
+#: sub/summary.tpl.php:33
+msgid "Enable"
+msgstr "启用"
+
+#: sub/summary.tpl.php:34
+msgid "Compiling"
+msgstr "编译中"
+
+#: sub/summary.tpl.php:35
+msgid "Normal"
+msgstr "正常"
+
+#: sub/summary.tpl.php:36 sub/testcoredump.tpl.php:3
+msgid "Sure?"
+msgstr "确认?"
+
+#: sub/summary.tpl.php:132
+msgid "Legends:"
+msgstr "图例:"
+
+#: sub/summary.tpl.php:134
+msgid "% Free"
+msgstr "% 剩余"
+
+#: sub/summary.tpl.php:134
+msgid "% Used"
+msgstr "% 已用"
+
+#: sub/summary.tpl.php:136
+msgid "Free Blocks"
+msgstr "未用块"
+
+#: sub/summary.tpl.php:136
+msgid "Used Blocks"
+msgstr "已用块"
+
+#: sub/summary.tpl.php:138
+msgid "Hits"
+msgstr "命中"
Index: /tags/3.0.0-rc1/htdocs/cacher/summary.tpl.php
===================================================================
--- /tags/3.0.0-rc1/htdocs/cacher/summary.tpl.php	(revision 1078)
+++ /tags/3.0.0-rc1/htdocs/cacher/summary.tpl.php	(revision 1078)
@@ -0,0 +1,5 @@
+<?php include "../common/header.tpl.php"; ?>
+<div class="switcher"><?php echo switcher("do", $doTypes); ?></div>
+<?php include "./sub/summary.tpl.php"; ?>
+<?php include "./sub/moduleinfo.tpl.php"; ?>
+<?php include "../common/footer.tpl.php"; ?>
Index: /tags/3.0.0-rc1/htdocs/cacher/config.example.php
===================================================================
--- /tags/3.0.0-rc1/htdocs/cacher/config.example.php	(revision 1053)
+++ /tags/3.0.0-rc1/htdocs/cacher/config.example.php	(revision 1053)
@@ -0,0 +1,20 @@
+<?php
+
+// DO NOT rename/delete/modify example file which will be overwritten when upgrade
+// How To Custom Config:
+// 1. copy config.example.php config.php; edit config.php
+// 2. upgrading your config.php when config.example.php were upgraded
+// XCache will load
+// 1. ../config.default.php
+// 2. ./config.default.php
+// 3. ../config.php
+// 4. ./config.php
+
+// width of graph for free or usage blocks
+$config['percent_graph_width'] = 120;
+$config['percent_graph_type'] = 'used'; // either 'used' or 'free'
+
+// only enable if you have password protection for admin page
+// enabling this option will cause user to eval() whatever code they want
+$config['enable_eval'] = false;
+
Index: /tags/3.0.0-rc1/htdocs/cacher/edit.tpl.php
===================================================================
--- /tags/3.0.0-rc1/htdocs/cacher/edit.tpl.php	(revision 1146)
+++ /tags/3.0.0-rc1/htdocs/cacher/edit.tpl.php	(revision 1146)
@@ -0,0 +1,18 @@
+<?php include "../common/header.tpl.php"; ?>
+<?php
+$h_name = htmlspecialchars(var_export($name, true));
+$h_value = htmlspecialchars($value);
+?>
+<form method="post" action="">
+	<fieldset>
+		<legend><?php echo sprintf(_T("Editing Variable %s"), $h_name); ?></legend>
+		<textarea name="value" style="width: 100%; height: 200px; overflow-y: auto" <?php echo $editable ? "" : "disabled=disabled"; ?>><?php echo $h_value; ?></textarea><br>
+		<input type="submit" <?php echo $editable ? "" : "disabled=disabled"; ?>>
+		<?php
+		if (!$editable) {
+			echo sprintf(_T("Set %s in config to enable"), "\$config['enable_eval'] = true");
+		}
+		?>
+	</fieldset>
+</form>
+<?php include "../common/footer.tpl.php"; ?>
Index: /tags/3.0.0-rc1/htdocs/cacher/listentries.tpl.php
===================================================================
--- /tags/3.0.0-rc1/htdocs/cacher/listentries.tpl.php	(revision 1101)
+++ /tags/3.0.0-rc1/htdocs/cacher/listentries.tpl.php	(revision 1101)
@@ -0,0 +1,22 @@
+<?php include "../common/header.tpl.php"; ?>
+<div class="switcher"><?php echo switcher("do", $doTypes); ?></div>
+<?php include "./sub/summary.tpl.php"; ?>
+<?php
+$entryList = getEntryList();
+$isphp = $entryList['type'] == XC_TYPE_PHP;
+ob_start($config['path_nicer']);
+
+$listName = 'Cached';
+$entries = $entryList['cache_list'];
+$caption = $isphp ? _T("php Cached") : _T("var Cached");
+include "./sub/entrylist.tpl.php";
+
+$listName = 'Deleted';
+$caption = $isphp ? _T("php Deleted") : _T("var Deleted");
+$entries = $entryList['deleted_list'];
+include "./sub/entrylist.tpl.php";
+
+ob_end_flush();
+unset($isphp);
+?>
+<?php include "../common/footer.tpl.php"; ?>
Index: /tags/3.0.0-rc1/htdocs/cacher/sub/testcoredump.tpl.php
===================================================================
--- /tags/3.0.0-rc1/htdocs/cacher/sub/testcoredump.tpl.php	(revision 1088)
+++ /tags/3.0.0-rc1/htdocs/cacher/sub/testcoredump.tpl.php	(revision 1088)
@@ -0,0 +1,5 @@
+<form method="post" action=""
+	><div
+		><input type="submit" name="coredump" value="Test coredump" class="submit" onclick="return confirm('<?php echo _T('Sure?'); ?>');"
+	/></div
+></form>
Index: /tags/3.0.0-rc1/htdocs/cacher/sub/moduleinfo.tpl.php
===================================================================
--- /tags/3.0.0-rc1/htdocs/cacher/sub/moduleinfo.tpl.php	(revision 1086)
+++ /tags/3.0.0-rc1/htdocs/cacher/sub/moduleinfo.tpl.php	(revision 1086)
@@ -0,0 +1,2 @@
+<h2><?php echo _T("Module Info"); ?></h2>
+<div class="phpinfo"><?php echo getModuleInfo(); ?></div>
Index: /tags/3.0.0-rc1/htdocs/cacher/sub/entrylist.tpl.php
===================================================================
--- /tags/3.0.0-rc1/htdocs/cacher/sub/entrylist.tpl.php	(revision 1146)
+++ /tags/3.0.0-rc1/htdocs/cacher/sub/entrylist.tpl.php	(revision 1146)
@@ -0,0 +1,154 @@
+<?php $cycleClass = new Cycle('class="col1"', 'class="col2"'); ?>
+<form action="" method="post">
+	<table cellspacing="0" cellpadding="4" class="cycles entries">
+		<caption><?php echo $caption; ?></caption>
+<?php
+
+echo <<<TR
+		<tr>
+
+TR;
+
+if ($isphp) {
+	echo
+		th(N_("entry.id"))
+		;
+}
+else {
+	echo
+		th(N_("entry.remove"))
+		;
+}
+
+echo
+	th(N_("entry.name"))
+	, th(N_("entry.hits"))
+	, th(N_("entry.size"))
+	;
+
+if ($isphp) {
+	echo
+		th(N_("entry.refcount"))
+		, th(N_("entry.phprefcount"))
+		, th(N_("entry.class_cnt"))
+		, th(N_("entry.function_cnt"))
+		, th(N_("entry.file_size"))
+		, th(N_("entry.file_mtime"))
+		;
+	echo
+		th(N_("entry.file_device"))
+		, th(N_("entry.file_inode"))
+		;
+}
+echo
+	th(N_("entry.hash"))
+	, th(N_("entry.atime"))
+	, th(N_("entry.ctime"))
+	;
+
+if ($listName == 'Deleted') {
+	echo
+		th(N_("entry.delete"))
+		;
+}
+?>
+		</tr>
+<?php
+foreach ($entries as $i => $entry) {
+	$class = $cycleClass->next();
+	echo <<<TR
+		<tr $class>
+
+TR;
+	$hits     = number_format($entry['hits']);
+	$size     = size($entry['size']);
+	if ($isphp) {
+		$class_cnt    = number_format($entry['class_cnt']);
+		$function_cnt = number_format($entry['function_cnt']);
+		$phprefcount  = number_format($entry['phprefcount']);
+		$file_size    = size($entry['file_size']);
+	}
+
+	if ($isphp) {
+		$file_mtime = age($entry['file_mtime']);
+	}
+	$ctime = age($entry['ctime']);
+	$atime = age($entry['atime']);
+	if ($listName == 'Deleted') {
+		$dtime = age($entry['dtime']);
+	}
+
+	if ($isphp) {
+		$hname = htmlspecialchars($entry['name']);
+		$namelink = $hname;
+		echo <<<ENTRY
+			<td>{$entry['cache_name']} {$i}</td>
+
+ENTRY;
+	}
+	else {
+		$name = $entry['name'];
+		if (!empty($config['enable_eval'])) {
+			$name = var_export($name, true);
+		}
+		$uname = urlencode($name);
+		$hname = htmlspecialchars(str_replace("\0", "\\0", $entry['name']));
+		echo <<<ENTRY
+			<td><label><input type="checkbox" name="remove[]" value="{$hname}"/>{$entry['cache_name']} {$i}</label></td>
+
+ENTRY;
+		$namelink = "<a href=\"edit.php?name=$uname\">$hname</a>";
+	}
+
+	echo <<<ENTRY
+			<td>{$namelink}</td>
+			<td align="right" int="{$entry['hits']}">{$entry['hits']}</td>
+			<td align="right" int="{$entry['size']}">{$size}</td>
+
+ENTRY;
+	if ($isphp) {
+		$refcount = number_format($entry['refcount']);
+		echo <<<ENTRY
+			<td align="right" int="{$entry['refcount']}">{$entry['refcount']}</td>
+			<td align="right" int="{$entry['phprefcount']}">{$phprefcount}</td>
+			<td align="right" int="{$entry['class_cnt']}">{$class_cnt}</td>
+			<td align="right" int="{$entry['function_cnt']}">{$function_cnt}</td>
+			<td align="right" int="{$entry['file_size']}">{$file_size}</td>
+			<td align="right" int="{$entry['file_mtime']}">{$file_mtime}</td>
+
+ENTRY;
+		if (isset($entry['file_inode'])) {
+			echo <<<ENTRY
+			<td align="right" int="{$entry['file_device']}">{$entry['file_device']}</td>
+			<td align="right" int="{$entry['file_inode']}">{$entry['file_inode']}</td>
+
+ENTRY;
+		}
+	}
+	echo <<<ENTRY
+			<td align="right" int="{$entry['hvalue']}">{$entry['hvalue']}</td>
+			<td align="right" int="{$entry['atime']}">{$atime}</td>
+			<td align="right" int="{$entry['ctime']}">{$ctime}</td>
+
+ENTRY;
+	if ($listName == 'Deleted') {
+		echo <<<ENTRY
+			<td align="right" int="{$entry['dtime']}">{$dtime}</td>
+
+ENTRY;
+	}
+
+	echo <<<TR
+		</tr>
+
+TR;
+}
+?>
+	</table>
+<?php if (!$isphp && $listName != 'Deleted') { ?>
+	<input type="submit" value="<?php echo _T("Remove Selected"); ?>">
+<?php } ?>
+</form>
+<?php
+unset($cycleClass);
+?>
Index: /tags/3.0.0-rc1/htdocs/cacher/sub/summary.tpl.php
===================================================================
--- /tags/3.0.0-rc1/htdocs/cacher/sub/summary.tpl.php	(revision 1101)
+++ /tags/3.0.0-rc1/htdocs/cacher/sub/summary.tpl.php	(revision 1101)
@@ -0,0 +1,140 @@
+<?php $cycleClass = new Cycle('class="col1"', 'class="col2"'); ?>
+<table cellspacing="0" cellpadding="4" class="cycles caches">
+	<caption><?php echo _T('Caches'); ?></caption>
+	<tr>
+	<?php echo
+		th(N_("cache.cache"))
+		, th(N_("cache.slots"))
+		, th(N_("cache.size"))
+		, th(N_("cache.avail"))
+		, th(N_("cache.blocksgraph"))
+		, th(N_("cache.operations"))
+		, th(N_("cache.status"))
+		, th(N_("cache.hits"))
+		, th(N_("cache.hits_graph"))
+		, th(N_("cache.hits_avg_h"))
+		, th(N_("cache.hits_avg_s"))
+		, th(N_("cache.updates"))
+		, th(N_("cache.skips"))
+		, th(N_("cache.ooms"))
+		, th(N_("cache.errors"))
+		, th(N_("cache.readonly_protected"))
+		, th(N_("cache.cached"))
+		, th(N_("cache.deleted"))
+		, th(N_("cache.gc_timer"))
+		;
+	?>
+	</tr>
+	<?php
+	$numkeys = explode(',', 'slots,size,avail,hits,updates,skips,ooms,errors,cached,deleted');
+	$l_clear = _T('Clear');
+	$l_disabled = _T('Disabled');
+	$l_disable = _T('Disable');
+	$l_enable = _T('Enable');
+	$l_compiling = _T('Compiling');
+	$l_normal = _T('Normal');
+	$l_confirm = _T('Sure?');
+	foreach (getCacheInfos() as $i => $ci) {
+		$class = $cycleClass->next();
+		echo <<<TR
+	<tr {$class}>
+
+TR;
+		$pvalue = (int) ($ci['avail'] / $ci['size'] * 100);
+		$pempty = 100 - $pvalue;
+		if ($config['percent_graph_type'] == 'used') {
+			// swap
+			$tmp = $pvalue;
+			$pvalue = $pempty;
+			$pempty = $tmp;
+		}
+
+		$w = $config['percent_graph_width'] + 2;
+		if (empty($ci['istotal'])) {
+			$graph = freeblock_to_graph($ci['free_blocks'], $ci['size']);
+			$blocksgraph = "<div class=\"blocksgraph\" style=\"width: {$w}px\">{$graph}</div>";
+		}
+		else {
+			$blocksgraph = '';
+		}
+
+		$ci_slots = size($ci['slots']);
+		$ci_size  = size($ci['size']);
+		$ci_avail = size($ci['avail']);
+		$ci = number_formats($ci, $numkeys);
+
+		$hits_avg_h     = number_format(array_avg($ci['hits_by_hour']), 2);
+		$hits_avg_s     = number_format(array_avg($ci['hits_by_second']), 2);
+		$hits_graph_h   = get_cache_hits_graph($ci, 'hits_by_hour');
+
+		if (!empty($ci['istotal'])) {
+			$ci['status']       = '-';
+			$ci['can_readonly'] = '-';
+		}
+		else {
+			if ($ci['disabled']) {
+				$ci['status'] = $l_disabled
+					. sprintf("(%s)", age($ci['disabled']));
+			}
+			else if ($ci['type'] == XC_TYPE_PHP) {
+				$ci['status'] = $ci['compiling']
+					? $l_compiling . sprintf("(%s)", age($ci['compiling']))
+					: $l_normal;
+			}
+			else {
+				$ci['status'] = '-';
+			}
+			$ci['can_readonly'] = $ci['can_readonly'] ? 'yes' : 'no';
+		}
+		$enabledisable = $ci['disabled'] ? 'enable' : 'disable';
+		$l_enabledisable = $ci['disabled'] ? $l_enable : $l_disable;
+		echo <<<EOS
+		<th>{$ci['cache_name']}</th>
+		<td align="right" title="{$ci['slots']}">{$ci_slots}</td>
+		<td align="right" title="{$ci['size']}">{$ci_size}</td>
+		<td align="right" title="{$ci['avail']}">{$ci_avail}</td>
+		<td title="{$pvalue} %"
+			><div class="percent" style="width: {$w}px"
+				><div style="width: {$pvalue}%" class="pvalue"></div
+				><div style="width: {$pempty}%" class="pempty"></div
+			></div
+		>{$blocksgraph}</td>
+		<td
+			><form method="post" action=""
+				><div
+					><input type="hidden" name="type" value="{$ci['type']}"
+					/><input type="hidden" name="cacheid" value="{$ci['cacheid']}"
+					/><input type="submit" name="clearcache" value="{$l_clear}" class="submit" onclick="return confirm('{$l_confirm}');"
+					/><input type="submit" name="{$enabledisable}" value="{$l_enabledisable}" class="submit"
+				/></div
+			></form
+		></td>
+		<td>{$ci['status']}</td>
+		<td align="right">{$ci['hits']}</td>
+		<td>{$hits_graph_h}</td>
+		<td align="right">{$hits_avg_h}</td>
+		<td align="right">{$hits_avg_s}</td>
+		<td align="right">{$ci['updates']}</td>
+		<td align="right">{$ci['skips']}</td>
+		<td align="right">{$ci['ooms']}</td>
+		<td align="right">{$ci['errors']}</td>
+		<td>{$ci['can_readonly']}</td>
+		<td align="right">{$ci['cached']}</td>
+		<td align="right">{$ci['deleted']}</td>
+		<td align="right">{$ci['gc']}</td>
+
+EOS;
+		?>
+	</tr>
+<?php } ?>
+</table>
+<div class="blockarea legends">
+	<div class="legendtitle"><?php echo _T('Legends:'); ?></div>
+	<div class="legend pvalue">&nbsp;&nbsp;</div>
+	<div class="legendtitle"><?php echo $config['percent_graph_type'] == 'free' ? _T('% Free') : _T('% Used'); ?></div>
+	<div class="legend" style="background: rgb(0,0,255)">&nbsp;&nbsp;</div>
+	<div class="legendtitle"><?php echo $config['percent_graph_type'] == 'free' ? _T('Free Blocks') : _T('Used Blocks'); ?></div>
+	<div class="legend" style="background: rgb(255,0,0)">&nbsp;&nbsp;</div>
+	<div class="legendtitle"><?php echo _T('Hits'); ?></div>
+</div>
+<?php unset($cycleClass); ?>
Index: /tags/3.0.0-rc1/htdocs/cacher/tablesort.js
===================================================================
--- /tags/3.0.0-rc1/htdocs/cacher/tablesort.js	(revision 1037)
+++ /tags/3.0.0-rc1/htdocs/cacher/tablesort.js	(revision 1037)
@@ -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 (var 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/3.0.0-rc1/htdocs/cacher/edit.php
===================================================================
--- /tags/3.0.0-rc1/htdocs/cacher/edit.php	(revision 1146)
+++ /tags/3.0.0-rc1/htdocs/cacher/edit.php	(revision 1146)
@@ -0,0 +1,46 @@
+<?php
+
+include "./common.php";
+
+if (!isset($_GET['name'])) {
+	die("missing name");
+}
+
+// trigger auth
+$vcnt = xcache_count(XC_TYPE_VAR);
+xcache_admin_namespace();
+
+$name = $_GET['name'];
+if (!empty($config['enable_eval'])) {
+	eval('$name = ' . $name . ';');
+}
+
+if ($_SERVER['REQUEST_METHOD'] == 'POST') {
+	if (!empty($config['enable_eval'])) {
+		eval('$value = ' . $_POST['value'] . ';');
+	}
+	else {
+		$value = $_POST['value'];
+	}
+	xcache_set($name, $value);
+	header("Location: ./?do=listvar");
+	exit;
+}
+$value = xcache_get($name);
+if (!empty($config['enable_eval'])) {
+	$value = var_export($value, true);
+	$editable = true;
+}
+else {
+	if (is_string($value)) {
+		$editable = true;
+	}
+	else {
+		$editable = false;
+		$value = var_export($value, true);
+	}
+}
+
+include "edit.tpl.php";
+
+?>
Index: /tags/3.0.0-rc1/htdocs/cacher/cacher.css
===================================================================
--- /tags/3.0.0-rc1/htdocs/cacher/cacher.css	(revision 1087)
+++ /tags/3.0.0-rc1/htdocs/cacher/cacher.css	(revision 1087)
@@ -0,0 +1,25 @@
+td, th { white-space: pre; }
+
+.percent { height: 3px; margin-bottom: 1px; border: 1px solid gray; }
+.percent div { float: left; height: 100%; }
+.pvalue { background: limegreen; }
+
+.blocksgraph { height: 13px; }
+.blocksgraph div { float: left; height: 3px; width: 4px; border: 0 solid gray; border-width: 0 0 1px 0; }
+.blocksgraph { border: 1px solid gray; border-bottom: 0; }
+.percent *, .blocksgraph *, .hitsgraph * { font-size: 1px; line-height: 1px; }
+
+.hitsgraph { margin: auto; }
+.hitsgraph a { display: block; float: left; border: 0 solid gray; }
+.hitsgraph a { width: 2px; height: 20px; border-top-width: 1px; border-bottom-width: 1px; } /* update this along with index.php */
+.hitsgraph a * { display: block; }
+.hitsgraph a.active { border-top-color: yellow; }
+.hitsgraph a:hover { background: gray; }
+
+dl { overflow: hidden; }
+dt { font-weight: bold; clear: both; float: left; width: 100px; text-align: right; margin: 0; }
+dd { margin: 0; }
+.blockarea { overflow: hidden; width: 400px; }
+.legends { padding-bottom: 8px; }
+div.legend { float: left; border: 1px solid gray; font: 12px/12px monospace; }
+div.legendtitle { float: left; padding: 2px; padding-right: 10px; font: 12px/12px monospace; }
Index: /tags/3.0.0-rc1/htdocs/cacher/index.php
===================================================================
--- /tags/3.0.0-rc1/htdocs/cacher/index.php	(revision 1146)
+++ /tags/3.0.0-rc1/htdocs/cacher/index.php	(revision 1146)
@@ -0,0 +1,318 @@
+<?php
+
+include "./common.php";
+
+function freeblock_to_graph($freeblocks, $size) // {{{
+{
+	global $config;
+
+	// cached in static variable
+	static $graph_initial;
+	if (!isset($graph_initial)) {
+		$graph_initial = array_fill(0, $config['percent_graph_width'], 0);
+	}
+	$graph = $graph_initial;
+	foreach ($freeblocks as $b) {
+		$begin = $b['offset'] / $size * $config['percent_graph_width'];
+		$end = ($b['offset'] + $b['size']) / $size * $config['percent_graph_width'];
+
+		if ((int) $begin == (int) $end) {
+			$v = $end - $begin;
+			$graph[(int) $v] += $v - (int) $v;
+		}
+		else {
+			$graph[(int) $begin] += 1 - ($begin - (int) $begin);
+			$graph[(int) $end] += $end - (int) $end;
+			for ($i = (int) $begin + 1, $e = (int) $end; $i < $e; $i ++) {
+				$graph[$i] += 1;
+			}
+		}
+	}
+	$html = array();
+	$c = 255;
+	foreach ($graph as $k => $v) {
+		if ($config['percent_graph_type'] != 'free') {
+			$v = 1 - $v;
+		}
+		$v = (int) ($v * $c);
+		$r = $g = $c - $v;
+		$b = $c;
+		$html[] = '<div style="background: rgb(' . "$r,$g,$b" . ')"></div>';
+	}
+	return implode('', $html);
+}
+// }}}
+function calc_total(&$total, $data) // {{{
+{
+	foreach ($data as $k => $v) {
+		switch ($k) {
+		case 'type':
+		case 'cache_name':
+		case 'cacheid':
+		case 'free_blocks':
+			continue 2;
+		}
+		if (!isset($total[$k])) {
+			$total[$k] = $v;
+		}
+		else {
+			switch ($k) {
+			case 'hits_by_hour':
+			case 'hits_by_second':
+				foreach ($data[$k] as $kk => $vv) {
+					$total[$k][$kk] += $vv;
+				}
+				break;
+
+			default:
+				$total[$k] += $v;
+			}
+		}
+	}
+}
+// }}}
+function array_avg($a) // {{{
+{
+	if (count($a) == 0) {
+		return '';
+	}
+	return array_sum($a) / count($a);
+}
+// }}}
+function bar_hits_percent($v, $percent, $active) // {{{
+{
+	$r = 220 + (int) ($percent * 25);
+	$g = $b = 220 - (int) ($percent * 220);
+	$percent = (int) ($percent * 100);
+	$a = $active ? ' class="active"' : '';
+	$height = 20 - 1 * 2;
+	$valueHeight = ceil($height * $percent / 100);
+	$paddingHeight = $height - $valueHeight;
+	$valueHeight = $valueHeight ? $valueHeight . "px" : 0;
+	$paddingHeight = $paddingHeight ? $paddingHeight . "px" : 0;
+	return '<a title="' . $v . '" href="javascript:;"' . $a . '>'
+		. ($paddingHeight ? '<span style="height: ' . $paddingHeight . '"></span>' : '')
+		. ($valueHeight ? '<span style="background: rgb(' . "$r,$g,$b" . '); height: ' . $valueHeight . '"></span>' : '')
+		. '</a>';
+}
+// }}}
+function get_cache_hits_graph($ci, $key) // {{{
+{
+	global $maxHitsByHour;
+	if ($ci['cacheid'] == -1) {
+		$max = max($ci[$key]);
+	}
+	else {
+		$max = $maxHitsByHour[$ci['type']];
+	}
+	if (!$max) {
+		$max = 1;
+	}
+	$t = (time() / (60 * 60)) % 24;
+
+	$html = array();
+	$width = count($ci[$key]) * 2;
+	$html[] = '<div class="hitsgraph" style="width: ' . $width . 'px">';
+	foreach ($ci[$key] as $i => $v) {
+		$html[] = bar_hits_percent($v, $v / $max, $i == $t);
+	}
+	$html[] = "</div>";
+	return implode('', $html);
+}
+// }}}
+function getModuleInfo() // {{{
+{
+	ob_start();
+	phpinfo(INFO_MODULES);
+	$moduleInfo = ob_get_clean();
+	if (!preg_match_all('!(XCache[^<>]*)</a></h2>(.*?)<h2>!is', $moduleInfo, $m)) {
+		return;
+	}
+
+	$moduleInfo = array();
+	foreach ($m[1] as $i => $dummy) {
+		$caption = trim($m[1][$i]);
+		$info = str_replace('<br />', '', trim($m[2][$i]));
+
+		$regex = '!<table[^>]*>!';
+		if (preg_match($regex, $info)) {
+			$moduleInfo[] = preg_replace($regex, "\\0<caption>$caption</caption>", $info, 1);
+		}
+		else {
+			$moduleInfo[] = "<h3>$caption</h3>";
+			$moduleInfo[] = $info;
+		}
+	}
+	$moduleInfo = implode('', $moduleInfo);
+	if (ini_get("xcache.test")) {
+		ob_start();
+		include "./sub/testcoredump.tpl.php";
+		$test_coredump = trim(ob_get_clean());
+		$moduleInfo = str_replace('xcache.coredump_directory', 'xcache.coredump_directory' . $test_coredump, $moduleInfo);
+	}
+	return $moduleInfo;
+}
+// }}}
+function getCacheInfos() // {{{
+{
+	static $cacheInfos;
+	if (isset($cacheInfos)) {
+		return $cacheInfos;
+	}
+
+	$phpCacheCount = xcache_count(XC_TYPE_PHP);
+	$varCacheCount = xcache_count(XC_TYPE_VAR);
+
+	$cacheInfos = array();
+	$total = array();
+	global $maxHitsByHour;
+	$maxHitsByHour = array(0, 0);
+	for ($i = 0; $i < $phpCacheCount; $i ++) {
+		$data = xcache_info(XC_TYPE_PHP, $i);
+		if ($_GET['do'] === 'listphp') {
+			$data += xcache_list(XC_TYPE_PHP, $i);
+		}
+		$data['type'] = XC_TYPE_PHP;
+		$data['cache_name'] = "php#$i";
+		$data['cacheid'] = $i;
+		$cacheInfos[] = $data;
+		$maxHitsByHour[XC_TYPE_PHP] = max($maxHitsByHour[XC_TYPE_PHP], max($data['hits_by_hour']));
+		if ($phpCacheCount >= 2) {
+			calc_total($total, $data);
+		}
+	}
+
+	if ($phpCacheCount >= 2) {
+		$total['type'] = XC_TYPE_PHP;
+		$total['cache_name'] = _T('Total');
+		$total['cacheid'] = -1;
+		$total['gc'] = null;
+		$total['istotal'] = true;
+		unset($total['compiling']);
+		$cacheInfos[] = $total;
+	}
+
+	$total = array();
+	for ($i = 0; $i < $varCacheCount; $i ++) {
+		$data = xcache_info(XC_TYPE_VAR, $i);
+		if ($_GET['do'] === 'listvar') {
+			$data += xcache_list(XC_TYPE_VAR, $i);
+		}
+		$data['type'] = XC_TYPE_VAR;
+		$data['cache_name'] = "var#$i";
+		$data['cacheid'] = $i;
+		$cacheInfos[] = $data;
+		$maxHitsByHour[XC_TYPE_VAR] = max($maxHitsByHour[XC_TYPE_VAR], max($data['hits_by_hour']));
+		if ($varCacheCount >= 2) {
+			calc_total($total, $data);
+		}
+	}
+
+	if ($varCacheCount >= 2) {
+		$total['type'] = XC_TYPE_VAR;
+		$total['cache_name'] = _T('Total');
+		$total['cacheid'] = -1;
+		$total['gc'] = null;
+		$total['istotal'] = true;
+		$cacheInfos[] = $total;
+	}
+	return $cacheInfos;
+}
+// }}}
+function getEntryList() // {{{
+{
+	static $entryList;
+	if (isset($entryList)) {
+		return $entryList;
+	}
+	$entryList = array('cache_list' => array(), 'deleted_list' => array());
+	if ($_GET['do'] == 'listphp') {
+		$entryList['type'] = XC_TYPE_PHP;
+	}
+	else {
+		$entryList['type'] = XC_TYPE_VAR;
+	}
+	foreach (getCacheInfos() as $i => $c) {
+		if (!empty($c['istotal'])) {
+			continue;
+		}
+		if ($c['type'] == $entryList['type'] && isset($c['cache_list'])) {
+			foreach ($c['cache_list'] as $e) {
+				$e['cache_name'] = $c['cache_name'];
+				$entryList['cache_list'][] = $e;
+			}
+			foreach ($c['deleted_list'] as $e) {
+				$e['cache_name'] = $c['cache_name'];
+				$entryList['deleted_list'][] = $e;
+			}
+		}
+	}
+	return $entryList;
+}
+// }}}
+
+if (!extension_loaded('XCache')) {
+	header("Location: ../diagnosis");
+	exit;
+}
+
+xcache_count(XC_TYPE_PHP); // trigger auth
+xcache_admin_namespace();
+
+$doTypes = array(
+		'' => _T('Summary'),
+		'listphp' => _T('List PHP'),
+		'listvar' => _T('List Var Data'),
+		);
+
+function processPOST() // {{{
+{
+	if (isset($_POST['remove']) && is_array($_POST['remove'])) {
+		foreach ($_POST['remove'] as $name) {
+			if (is_string($name)) {
+				xcache_unset($name);
+			}
+		}
+	}
+
+	$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);
+		}
+		if (isset($_POST['enable'])) {
+			xcache_enable_cache($type, $cacheid);
+		}
+		if (isset($_POST['disable'])) {
+			xcache_enable_cache($type, $cacheid, false);
+		}
+	}
+
+	if (isset($_POST['coredump'])) {
+		xcache_coredump();
+	}
+}
+// }}}
+
+processPOST();
+
+if (!isset($_GET['do'])) {
+	$_GET['do'] = '';
+}
+
+switch ($_GET['do']) {
+case 'listphp':
+case 'listvar':
+	include "./listentries.tpl.php";
+	break;
+
+default:
+	include "./summary.tpl.php";
+	break;
+}
+
+?>
Index: /tags/3.0.0-rc1/htdocs/cacher/common.php
===================================================================
--- /tags/3.0.0-rc1/htdocs/cacher/common.php	(revision 1099)
+++ /tags/3.0.0-rc1/htdocs/cacher/common.php	(revision 1099)
@@ -0,0 +1,7 @@
+<?php
+
+require_once "../common/common.php";
+
+include get_language_file("./lang");
+$module = "cacher";
+
Index: /tags/3.0.0-rc1/htdocs/cacher/config.default.php
===================================================================
--- /tags/3.0.0-rc1/htdocs/cacher/config.default.php	(revision 1053)
+++ /tags/3.0.0-rc1/htdocs/cacher/config.default.php	(revision 1053)
@@ -0,0 +1,15 @@
+<?php
+
+// [default config]
+// DO NOT rename/delete/modify this file which will be overwritten when upgrade
+// See config.example.php instead
+
+
+// width of graph for free or usage blocks
+$config['percent_graph_width'] = 120;
+$config['percent_graph_type'] = 'used'; // either 'used' or 'free'
+
+// only enable if you have password protection for admin page
+// enabling this option will cause user to eval() whatever code they want
+$config['enable_eval'] = false;
+
Index: /tags/3.0.0-rc1/htdocs/cacher/mkpassword.php
===================================================================
--- /tags/3.0.0-rc1/htdocs/cacher/mkpassword.php	(revision 546)
+++ /tags/3.0.0-rc1/htdocs/cacher/mkpassword.php	(revision 546)
@@ -0,0 +1,24 @@
+<html>
+	<head>
+		<title>Simple MD5 password generator</title>
+	</head>
+	<body>
+		<h1>Simple MD5 password generator</h1>
+		<form method="post">
+			<fieldset>
+				md5: <input type="password" name="password"> <input type="submit"><br>
+				<div>
+				<?php
+				if ($_SERVER['REQUEST_METHOD'] == 'POST') {
+					$md5 = md5(@ $_POST['password']);
+					$offs = mt_rand(0 + 1, 31 - 1);
+					$md5_1 = substr($md5, 0, $offs);
+					$md5_2 = substr($md5, $offs);
+					echo "Result: <span>$md5_1</span><span>$md5_2</span>";
+				}
+				?>
+				</div>
+			</fieldset>
+		</form>
+	</body>
+</html>
Index: /tags/3.0.0-rc1/htdocs/config.example.php
===================================================================
--- /tags/3.0.0-rc1/htdocs/config.example.php	(revision 1053)
+++ /tags/3.0.0-rc1/htdocs/config.example.php	(revision 1053)
@@ -0,0 +1,65 @@
+<?php
+
+// DO NOT rename/delete/modify example file which will be overwritten when upgrade
+// How To Custom Config:
+// 1. copy config.example.php config.php; edit config.php
+// 2. upgrading your config.php when config.example.php were upgraded
+
+// leave this setting unset to auto detect using browser request header
+// $config['lang'] = 'en-us';
+
+$config['charset'] = "UTF-8";
+
+// enable this for translators only
+$config['show_todo_strings'] = false;
+
+// this ob filter is applied for the cache list, not the whole page
+function custom_ob_filter_path_nicer($list_html)
+{
+	$list_html = ob_filter_path_nicer_default($list_html); // this function is from common.php
+	return $list_html;
+}
+$config['path_nicer'] = 'custom_ob_filter_path_nicer';
+
+// "XCache Cacher" http auth for is enforced for security reason
+// if http auth is disabled, any vhost user who can upload *.php will see all variable data cached in XCache
+
+/*// but if you have your own login/permission system, you can integerate it using the following example
+// {{{ 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()) {
+		user_load_permissions();
+		if (user_is_admin()) {
+			// user is trusted after permission checks above.
+			// tell XCache about it (the only secure way to by pass XCache http auth)
+			$_SERVER["PHP_AUTH_USER"] = "moo";
+			$_SERVER["PHP_AUTH_PW"] = "your-xcache-password-before-md5";
+		}
+		else {
+			die("Permission denied");
+		}
+	}
+	else {
+		if (!ask_the_user_to_login()) {
+			exit;
+		}
+	}
+
+	return true;
+}
+
+check_admin_and_by_pass_xcache_http_auth();
+*/
+// }}}
+
+/* by pass XCache http auth
+$_SERVER["PHP_AUTH_USER"] = "moo";
+$_SERVER["PHP_AUTH_PW"] = "your-xcache-password-before-md5";
+*/
+
Index: /tags/3.0.0-rc1/htdocs/common/header.tpl.php
===================================================================
--- /tags/3.0.0-rc1/htdocs/common/header.tpl.php	(revision 1087)
+++ /tags/3.0.0-rc1/htdocs/common/header.tpl.php	(revision 1087)
@@ -0,0 +1,30 @@
+<!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-Type" content="text/html; charset=<?php echo $GLOBALS['config']['charset']; ?>" />
+	<meta http-equiv="Content-Language" content="<?php echo $GLOBALS['config']['lang']; ?>" />
+	<script type="text/javascript" src="tablesort.js"></script>
+
+	<link rel="stylesheet" type="text/css" href="../common/common.css" />
+	<link rel="stylesheet" type="text/css" href="<?php echo $GLOBALS['module']; ?>.css" />
+	<title><?php echo sprintf("XCache %s", $xcache_version = defined('XCACHE_VERSION') ? XCACHE_VERSION : ''); ?> - <?php echo ucfirst($GLOBALS['module']); ?></title>
+</head>
+
+<body>
+<div id="header">
+	<div id="banner">
+		<a href="http://xcache.lighttpd.net/" rel="external"><img src="../common/xcache.png" id="logo" alt="XCache logo" width="175" height="51" />
+			<?php echo $xcache_version; ?> - <?php echo ucfirst($GLOBALS['module']); ?>
+		</a>
+	</div>
+	<div id="nav">
+		<div id="mainnav">
+				<?php echo mainnav(); ?>
+		</div>
+		<div id="subnav" class="switcher">
+				<?php echo subnav(); ?>
+		</div>
+	</div>
+</div>
+<div id="headerbase">&nbsp;</div>
+<div id="main">
Index: /tags/3.0.0-rc1/htdocs/common/common.php
===================================================================
--- /tags/3.0.0-rc1/htdocs/common/common.php	(revision 1099)
+++ /tags/3.0.0-rc1/htdocs/common/common.php	(revision 1099)
@@ -0,0 +1,280 @@
+<?php
+
+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 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);
+}
+
+function mainnav()
+{
+	foreach (array(
+				"http://xcache.lighttpd.net/" => "XCache",
+				"http://xcache.lighttpd.net/wiki/DocTOC" => _T("Document"),
+				"http://xcache.lighttpd.net/wiki/PhpIni" => _T("INI Reference"),
+				"http://xcache.lighttpd.net/wiki/GetSupport" => _T("Get Support"),
+				"https://groups.google.com/group/xcache/" => _T("Discusson"),
+				"http://www.php.net/" => "PHP",
+				"http://www.lighttpd.net/" => "Lighttpd",
+				) as $url => $title) {
+		$html[] = sprintf('<a href="%s" rel="external">%s</a>', $url, $title);
+	}
+	return implode('|', $html);
+}
+
+function subnav()
+{
+	global $module, $modules;
+	$html = array();
+	foreach ($modules as $k => $v) {
+		$html[] = sprintf('<a href="../%s/"%s>%s</a>', $k, $k == $module ? ' class="active"' : '', $v);
+	}
+	return implode('', $html);
+}
+
+function th($name, $attrs = null)
+{
+	$translated = __($name);
+	if ($translated == $name) {
+		$translated = "$name|$name";
+	}
+	list($text, $title) = explode('|', $translated, 2);
+	return sprintf('%s<th%s id="%s" class="h" title="%s"><a href="javascript:" onclick="resort(this); return false">%s</a></th>%s'
+			, "\t"
+			, $attrs ? " $attrs" : ""
+			, $name, htmlspecialchars(trim($title)), trim($text)
+			, "\n");
+}
+
+function xcache_validateFileName($name)
+{
+	return preg_match('!^[a-zA-Z0-9._-]+$!', $name);
+}
+
+function get_language_file_ex($dir, $lang)
+{
+	static $langMap = array(
+			'zh'    => 'zh-simplified',
+			'zh-hk' => 'zh-traditional',
+			'zh-tw' => 'zh-traditional',
+			);
+
+	if (isset($langMap[$lang])) {
+		$lang = $langMap[$lang];
+	}
+	else if (!xcache_validateFileName($lang)) {
+		return null;
+	}
+
+	$file = "$dir/$lang.php";
+	if (file_exists($file)) {
+		return $file;
+	}
+	return null;
+}
+
+function get_language_file($dir)
+{
+	global $config;
+	if (!empty($config['lang'])) {
+		$lang = strtolower($config['lang']);
+		$file = get_language_file_ex($dir, $lang);
+		if (!isset($file)) {
+			$lang = strtok($lang, ':-');
+			$file = get_language_file_ex($dir, $lang);
+		}
+	}
+	else {
+		$config['lang'] = 'en';
+
+		if (!empty($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
+			foreach (explode(',', str_replace(' ', '', $_SERVER['HTTP_ACCEPT_LANGUAGE'])) as $lang) {
+				$lang = strtok($lang, ':;');
+				$file = get_language_file_ex($dir, $lang);
+				if (isset($file)) {
+					$config['lang'] = $lang;
+					break;
+				}
+				if (strpos($lang, '-') !== false) {
+					$file = get_language_file_ex($dir, strtok($lang, ':-'));
+					if (isset($file)) {
+						$config['lang'] = $lang;
+						break;
+					}
+				}
+			}
+		}
+	}
+	return isset($file) ? $file : "$dir/en.php";
+}
+
+function _T($str)
+{
+	if (isset($GLOBALS['strings'][$str])) {
+		return $GLOBALS['strings'][$str];
+	}
+	if (!empty($GLOBALS['config']['show_todo_strings'])) {
+		return '<span style="color:red">' . $str . '</span>|';
+	}
+	return $str;
+}
+
+function __($str)
+{
+	return _T($str);
+}
+
+function N_($str)
+{
+	return $str;
+}
+
+function number_formats($a, $keys)
+{
+	foreach ($keys as $k) {
+		$a[$k] = number_format($a[$k]);
+	}
+	return $a;
+}
+
+function size($size)
+{
+	$size = (int) $size;
+	if ($size < 1024)
+		return number_format($size, 2) . ' b';
+
+	if ($size < 1048576)
+		return number_format($size / 1024, 2) . ' K';
+
+	return number_format($size / 1048576, 2) . ' M';
+}
+
+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];
+		}
+	}
+
+	return '0s';
+}
+
+function stripaddslashes_array($value, $mqs = false)
+{
+	if (is_array($value)) {
+		foreach($value as $k => $v) {
+			$value[$k] = stripaddslashes_array($v, $mqs);
+		}
+	}
+	else if(is_string($value)) {
+		$value = $mqs ? str_replace('\'\'', '\'', $value) : stripslashes($value);
+	}
+	return $value;
+}
+
+function ob_filter_path_nicer_default($list_html)
+{
+	$sep = DIRECTORY_SEPARATOR;
+	$docRoot = $_SERVER['DOCUMENT_ROOT'];
+	if ($sep != '/') {
+		$docRoot = str_replace('/', $sep, $docRoot);
+	}
+	$list_html = str_replace(">$docRoot",  ">{DOCROOT}" . (substr($docRoot, -1) == $sep ? $sep : ""), $list_html);
+	$xcachedir = realpath(dirname(__FILE__) . "$sep..$sep");
+	$list_html = str_replace(">$xcachedir$sep", ">{XCache}$sep", $list_html);
+	if ($sep == '/') {
+		$list_html = str_replace(">/home/", ">{H}/", $list_html);
+	}
+	return $list_html;
+}
+
+error_reporting(E_ALL);
+ini_set('display_errors', 'On');
+define('REQUEST_TIME', time());
+
+if (function_exists('get_magic_quotes_gpc') && @get_magic_quotes_gpc()) {
+	$mqs = (bool) ini_get('magic_quotes_sybase');
+	$_GET = stripaddslashes_array($_GET, $mqs);
+	$_POST = stripaddslashes_array($_POST, $mqs);
+	$_REQUEST = stripaddslashes_array($_REQUEST, $mqs);
+	unset($mqs);
+}
+ini_set('magic_quotes_runtime', '0');
+
+$config = array();
+if (file_exists("./config.default.php")) {
+	include "./config.default.php";
+}
+include "../config.default.php";
+if (file_exists("../config.php")) {
+	include "../config.php";
+}
+if (file_exists("./config.php")) {
+	include "./config.php";
+}
+
+$strings = array();
+include get_language_file("../common/lang");
+
+$modules = array();
+if (file_exists("../cacher/index.php")) {
+	$modules["cacher"] = _T("Cacher");
+}
+if (file_exists("../coverager/index.php")) {
+	$modules["coverager"] = _T("Coverager");
+}
+if (file_exists("../diagnosis/index.php")) {
+	$modules["diagnosis"] = _T("Diagnosis");
+}
+header("Cache-Control: no-cache, must-revalidate");
+header("Expires: Sat, 26 Jul 1997 05:00:00 GMT");
+header("Content-Type: text/html; " . $GLOBALS['config']['charset']);
+header("Content-Language: " . $GLOBALS['config']['lang']);
+
+?>
Index: /tags/3.0.0-rc1/htdocs/common/common.css
===================================================================
--- /tags/3.0.0-rc1/htdocs/common/common.css	(revision 1087)
+++ /tags/3.0.0-rc1/htdocs/common/common.css	(revision 1087)
@@ -0,0 +1,191 @@
+* {
+	box-sizing: border-box;
+	-moz-box-sizing: border-box;
+}
+body {
+	background: white;
+	color: black;
+	margin: 0;
+	padding: 0;
+	font-family: arial;
+	font-size: 12pt;
+}
+form {
+	margin: 0;
+	padding: 0;
+}
+a:link
+, a:visited {
+	color: #0066CC;
+}
+a:link:hover
+, a:visited:hover {
+	color: #BB0000;
+}
+a:link:active
+, a:visited:active {
+	color: red;
+}
+#header {
+	background: #5084D5;
+	position: relative;
+	height: 51px;
+	color: #d0d0d0;
+}
+h1, h2, h3, h4, h5, h6 {
+	margin-bottom: 2px;
+}
+#header #banner {
+	font: 32px/51px "arial", serif;
+	color: white;
+}
+#header #banner a {
+	color: white;
+}
+#header #banner #logo {
+	border: 0;
+	display: block;
+	float: left;
+	margin-right: 5px;
+	background: white;
+}
+#header #mainnav {
+	top: 3px;
+	right: 5px;
+	font-size: 16px;
+	line-height: 16px;
+	position: absolute;
+}
+#header #mainnav a {
+	font-size: 14px;
+}
+#header #subnav {
+	bottom: 0;
+	right: 5px;
+	position: absolute;
+	font-size: 28px;
+	line-height: 28px;
+}
+#header #subnav a {
+	font-size: 24px;
+}
+#header #nav {
+	font-family: "arial", serif;
+}
+#header #mainnav a:link, #header #mainnav a:visited {
+	color: black;
+}
+#header #mainnav a:active, #header #mainnav a:hover {
+	color: red;
+}
+#header #mainnav a {
+	padding: 0 8px 0 8px;
+}
+#headerbase {
+	background: #1163BC;
+	border: 1px solid #334C66;
+	border-width: 1px 0 1px 0;
+	margin-bottom: 10px;
+	font: 12px/12px serif;
+}
+#main table {
+	font-size: 12px;
+	border: 1px solid #334C66;
+	border-top-width: 0;
+}
+#main table caption {
+	background: #1163BC;
+	color: white;
+	line-height: 20px;
+	border: 1px solid #334C66;
+	border-bottom-width: 0;
+	padding: 0;
+}
+#main table tfoot {
+	background: #1163BC;
+}
+#main table th {
+	background: #E7E7FF;
+	color: black;
+}
+#main table td {
+	vertical-align: top;
+}
+#main {
+	margin: 20px;
+}
+#note {
+	font-size: 11.9px;
+}
+#footer {
+	bottom: 0px;
+	background: #E7E7FF;
+	border-top: 1px solid gray;
+}
+#poweredBy {
+	overflow: hidden;
+}
+#footer {
+	clear: both;
+	height: 40px;
+	position: relative;
+}
+#footer img {
+	margin-top: 2px;
+	margin-left: 2px;
+	border: 0;
+}
+#poweredBy h3 {
+	float: right;
+	margin-right: 20px;
+	margin-top: 20px;
+}
+#poweredBy h3 {
+	margin: 0;
+	font-size: 12px;
+	position: absolute;
+	bottom: 8px;
+	right: 8px;
+}
+.phpinfo table { border: 1px solid #334C66; margin-bottom: 1px; }
+.phpinfo table th, .phpinfo table td { border: 1px solid #334C66; }
+.phpinfo table th { font-weight: bold; }
+.phpinfo .e {background: #81BBF2; font-weight: bold; color: #000000;}
+#main .phpinfo .h th {background: #5084D5; font-weight: bold; color: #000000;}
+.phpinfo .v {color: #000000;}
+.button { }
+span.sortarrow { color: white; text-decoration: none; }
+table.cycles { border: 1px solid #334C66; margin-bottom: 5px; }
+table.cycles .col1 { background: #f5f5f5; }
+table.cycles .col2 { background: #e0e0e0; }
+table.cycles th, table.cycles td { border: 1px solid #334C66; font-family: monospace; }
+#main table.cycles caption { color: white; font-weight: bold; height: 24px; line-height: 24px; font-family: serif; }
+#main table.cycles th { background: #81BBF2; color: #334C66; font-weight: bold; height: 20px; line-height: 20px; font-family: serif; }
+#main table.cycles th.h { background: #5084D5; }
+th.h a:visited
+, th.h a:link { color: black; }
+th.h a:hover { color: #BB0000; }
+th.h a:active { color: red; }
+th a { font-weight: bold; display: block; width: 100%; height: 100%; }
+th { font-size: 12px; }
+input, table { font-family: sans-serif; }
+input { font-size: 12px; }
+table { border-collapse: collapse; font-size: 11px; margin: 0; }
+table caption {
+	font-size: 14px;
+	font-weight: bold;
+}
+
+a {
+	text-decoration: none;
+}
+#main table td {
+	vertical-align: middle;
+}
+.switcher a { color: black; padding: 1px 8px 1px 8px; border: 1px solid white; }
+.switcher a { border-color: white; border-bottom-color: #334C66; }
+#nav .switcher a { border-color: #5084D5; border-bottom-color: #334C66; }
+#nav .switcher a.active, .switcher a.active { color: white; background: #1163BC; border-color: #334C66; border-bottom-color: #1163BC; }
+#nav .switcher a:hover.active, .switcher a:hover.active { background: #81BBF2; }
+.switcher a:hover { background: #81BBF2; }
+#nav .switcher a:active, .switcher a:active { background: #81BBF2; }
Index: /tags/3.0.0-rc1/htdocs/common/lang/en.php
===================================================================
--- /tags/3.0.0-rc1/htdocs/common/lang/en.php	(revision 1102)
+++ /tags/3.0.0-rc1/htdocs/common/lang/en.php	(revision 1102)
@@ -0,0 +1,5 @@
+<?php
+// auto generated, do not modify
+$strings += array(
+		);
+
Index: /tags/3.0.0-rc1/htdocs/common/lang/zh-simplified.php
===================================================================
--- /tags/3.0.0-rc1/htdocs/common/lang/zh-simplified.php	(revision 1103)
+++ /tags/3.0.0-rc1/htdocs/common/lang/zh-simplified.php	(revision 1103)
@@ -0,0 +1,19 @@
+<?php
+// auto generated, do not modify
+$strings += array(
+		"Document"
+		=> "帮助文档",
+		"INI Reference"
+		=> "INI 参考",
+		"Get Support"
+		=> "获取支持",
+		"Discusson"
+		=> "讨论",
+		"Cacher"
+		=> "缓存器",
+		"Coverager"
+		=> "代码覆盖查看器",
+		"Diagnosis"
+		=> "诊断",
+		);
+
Index: /tags/3.0.0-rc1/htdocs/common/lang/en.po
===================================================================
--- /tags/3.0.0-rc1/htdocs/common/lang/en.po	(revision 1101)
+++ /tags/3.0.0-rc1/htdocs/common/lang/en.po	(revision 1101)
@@ -0,0 +1,36 @@
+msgid ""
+msgstr ""
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2012-08-01 14:47+0800\n"
+"Language: en\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: common.php:47
+msgid "Document"
+msgstr ""
+
+#: common.php:48
+msgid "INI Reference"
+msgstr ""
+
+#: common.php:49
+msgid "Get Support"
+msgstr ""
+
+#: common.php:50
+msgid "Discusson"
+msgstr ""
+
+#: common.php:267
+msgid "Cacher"
+msgstr ""
+
+#: common.php:270
+msgid "Coverager"
+msgstr ""
+
+#: common.php:273
+msgid "Diagnosis"
+msgstr ""
Index: /tags/3.0.0-rc1/htdocs/common/lang/zh-traditional.php
===================================================================
--- /tags/3.0.0-rc1/htdocs/common/lang/zh-traditional.php	(revision 1103)
+++ /tags/3.0.0-rc1/htdocs/common/lang/zh-traditional.php	(revision 1103)
@@ -0,0 +1,19 @@
+<?php
+// auto generated, do not modify
+$strings += array(
+		"Document"
+		=> "幫助文檔",
+		"INI Reference"
+		=> "INI 參考",
+		"Get Support"
+		=> "獲取支持",
+		"Discusson"
+		=> "討論",
+		"Cacher"
+		=> "快取器",
+		"Coverager"
+		=> "代码覆盖查看器",
+		"Diagnosis"
+		=> "診斷",
+		);
+
Index: /tags/3.0.0-rc1/htdocs/common/lang/zh-simplified.po
===================================================================
--- /tags/3.0.0-rc1/htdocs/common/lang/zh-simplified.po	(revision 1101)
+++ /tags/3.0.0-rc1/htdocs/common/lang/zh-simplified.po	(revision 1101)
@@ -0,0 +1,36 @@
+msgid ""
+msgstr ""
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2012-08-01 14:47+0800\n"
+"Language: zh\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: common.php:47
+msgid "Document"
+msgstr "帮助文档"
+
+#: common.php:48
+msgid "INI Reference"
+msgstr "INI 参考"
+
+#: common.php:49
+msgid "Get Support"
+msgstr "获取支持"
+
+#: common.php:50
+msgid "Discusson"
+msgstr "讨论"
+
+#: common.php:267
+msgid "Cacher"
+msgstr "缓存器"
+
+#: common.php:270
+msgid "Coverager"
+msgstr "代码覆盖查看器"
+
+#: common.php:273
+msgid "Diagnosis"
+msgstr "诊断"
Index: /tags/3.0.0-rc1/htdocs/common/lang/zh-traditional.po
===================================================================
--- /tags/3.0.0-rc1/htdocs/common/lang/zh-traditional.po	(revision 1101)
+++ /tags/3.0.0-rc1/htdocs/common/lang/zh-traditional.po	(revision 1101)
@@ -0,0 +1,36 @@
+msgid ""
+msgstr ""
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2012-08-01 14:47+0800\n"
+"Language: zh_TW\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: common.php:47
+msgid "Document"
+msgstr "幫助文檔"
+
+#: common.php:48
+msgid "INI Reference"
+msgstr "INI 參考"
+
+#: common.php:49
+msgid "Get Support"
+msgstr "獲取支持"
+
+#: common.php:50
+msgid "Discusson"
+msgstr "討論"
+
+#: common.php:267
+msgid "Cacher"
+msgstr "快取器"
+
+#: common.php:270
+msgid "Coverager"
+msgstr "代码覆盖查看器"
+
+#: common.php:273
+msgid "Diagnosis"
+msgstr "診斷"
Index: /tags/3.0.0-rc1/htdocs/common/footer.tpl.php
===================================================================
--- /tags/3.0.0-rc1/htdocs/common/footer.tpl.php	(revision 1087)
+++ /tags/3.0.0-rc1/htdocs/common/footer.tpl.php	(revision 1087)
@@ -0,0 +1,22 @@
+</div>
+<div id="footer">
+	<a href="http://validator.w3.org/check?uri=referer">
+		<img src="http://www.w3.org/Icons/valid-xhtml10" alt="Valid XHTML 1.0 Transitional" height="31" width="88" />
+	</a>
+	<a href="http://jigsaw.w3.org/css-validator/check/referer">
+		<img style="border:0;width:88px;height:31px" src="http://jigsaw.w3.org/css-validator/images/vcss" alt="Valid CSS!" />
+	</a>
+	<div id="poweredBy">
+		<h3>PHP <?php
+	echo phpversion();
+?> Powered By: XCache <?php
+	echo defined('XCACHE_VERSION') ? XCACHE_VERSION : '';
+?>, <?php
+	echo defined('XCACHE_MODULES') ? XCACHE_MODULES : '';
+?>
+		</h3>
+	</div>
+</div>
+
+</body>
+</html>
Index: /tags/3.0.0-rc1/htdocs/coverager/coverager.tpl.php
===================================================================
--- /tags/3.0.0-rc1/htdocs/coverager/coverager.tpl.php	(revision 1086)
+++ /tags/3.0.0-rc1/htdocs/coverager/coverager.tpl.php	(revision 1086)
@@ -0,0 +1,230 @@
+<?php include "../common/header.tpl.php"; ?>
+
+<?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"');
+	$l_dir = _T("Directory");
+	$l_per = _T("Percent");
+	$l_hit = _T("Hits");
+	$l_lns = _T("Lines");
+	$l_tds = _T("TODO");
+	return <<<EOS
+<table cellpadding="2" cellspacing="0" border="0" class="cycles">
+	<tr>
+		<th>{$l_dir}</th><th>{$l_per}</th><th>{$l_hit}</th><th>{$l_lns}</th><th>{$l_tds}</th>
+	</tr>
+EOS;
+}
+
+function dir_row($info, $srcdir)
+{
+	global $cycle;
+	if ($info['files'] || $info['todos']) {
+		$srcdir .= DIRECTORY_SEPARATOR;
+		$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"');
+	$l_fil = _T("File");
+	$l_per = _T("Percent");
+	$l_hit = _T("Hits");
+	$l_lns = _T("Lines");
+	return <<<EOS
+<table cellpadding="2" cellspacing="0" border="0" class="cycles">
+	<tr>
+		<th>{$l_fil}</th><th>{$l_per}</th><th>{$l_hit}</th><th>{$l_lns}</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;
+}
+
+$l_root = _T("root");
+if ($action == 'dir') {
+	if (function_exists('ob_filter_path_nicer')) {
+		ob_start('ob_filter_path_nicer');
+	}
+	$path_html = htmlspecialchars($path);
+	echo <<<EOS
+	<div>
+		<a href="?">$l_root</a> $path<br />
+	</div>
+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') {
+	if (function_exists('ob_filter_path_nicer')) {
+		ob_start('ob_filter_path_nicer');
+	}
+	$dir_url = urlencode($dir);
+	$dir_html = htmlspecialchars($dir);
+	echo <<<EOS
+	<div>
+		<a href="?">$l_root</a> <a href="?path={$dir_url}">{$dir_html}</a>/<strong>{$filename}</strong><br />
+	</div>
+EOS;
+
+	echo file_head();
+	echo file_row($fileinfo, $path);
+	echo file_foot();
+
+	if ($tplfile) {
+		$tplfile_html = htmlspecialchars($tplfile);
+		echo <<<EOS
+		<div>
+			<a href="#tpl">{$tplfile_html}</a><br />
+		</div>
+EOS;
+	}
+	if (function_exists('ob_filter_path_nicer')) {
+		ob_end_flush();
+	}
+	echo <<<EOS
+	<div class="code">
+		<ol>{$filecov}</ol>
+	</div>
+EOS;
+	if ($tplfile) {
+		echo <<<EOS
+	<a name="tpl">{$tplfile}</a>
+	<div class="code">
+		<ol>{$tplcov}</ol>
+	</div>
+EOS;
+	}
+}
+else {
+	$error_html = htmlspecialchars($error);
+	echo <<<EOS
+	<span class="error">{$error_html}</span>
+EOS;
+}
+?>
+
+<?php include "../common/footer.tpl.php"; ?>
+
Index: /tags/3.0.0-rc1/htdocs/coverager/lang/zh-simplified.php
===================================================================
--- /tags/3.0.0-rc1/htdocs/coverager/lang/zh-simplified.php	(revision 1103)
+++ /tags/3.0.0-rc1/htdocs/coverager/lang/zh-simplified.php	(revision 1103)
@@ -0,0 +1,19 @@
+<?php
+// auto generated, do not modify
+$strings += array(
+		"Directory"
+		=> "目录",
+		"Percent"
+		=> "覆盖率",
+		"Hits"
+		=> "命中",
+		"Lines"
+		=> "行数",
+		"TODO"
+		=> "闲置文件",
+		"File"
+		=> "文件",
+		"root"
+		=> "开始",
+		);
+
Index: /tags/3.0.0-rc1/htdocs/coverager/lang/en.po
===================================================================
--- /tags/3.0.0-rc1/htdocs/coverager/lang/en.po	(revision 1101)
+++ /tags/3.0.0-rc1/htdocs/coverager/lang/en.po	(revision 1101)
@@ -0,0 +1,36 @@
+msgid ""
+msgstr ""
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2012-08-01 14:47+0800\n"
+"Language: en\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: coverager.tpl.php:37
+msgid "Directory"
+msgstr ""
+
+#: coverager.tpl.php:38 coverager.tpl.php:100
+msgid "Percent"
+msgstr ""
+
+#: coverager.tpl.php:39 coverager.tpl.php:101
+msgid "Hits"
+msgstr ""
+
+#: coverager.tpl.php:40 coverager.tpl.php:102
+msgid "Lines"
+msgstr ""
+
+#: coverager.tpl.php:41
+msgid "TODO"
+msgstr ""
+
+#: coverager.tpl.php:99
+msgid "File"
+msgstr ""
+
+#: coverager.tpl.php:151
+msgid "root"
+msgstr ""
Index: /tags/3.0.0-rc1/htdocs/coverager/lang/zh-traditional.php
===================================================================
--- /tags/3.0.0-rc1/htdocs/coverager/lang/zh-traditional.php	(revision 1115)
+++ /tags/3.0.0-rc1/htdocs/coverager/lang/zh-traditional.php	(revision 1115)
@@ -0,0 +1,5 @@
+<?php
+// auto generated, do not modify
+$strings += array(
+		);
+
Index: /tags/3.0.0-rc1/htdocs/coverager/lang/zh-simplified.po
===================================================================
--- /tags/3.0.0-rc1/htdocs/coverager/lang/zh-simplified.po	(revision 1101)
+++ /tags/3.0.0-rc1/htdocs/coverager/lang/zh-simplified.po	(revision 1101)
@@ -0,0 +1,36 @@
+msgid ""
+msgstr ""
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2012-08-01 14:47+0800\n"
+"Language: zh\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: coverager.tpl.php:37
+msgid "Directory"
+msgstr "目录"
+
+#: coverager.tpl.php:38 coverager.tpl.php:100
+msgid "Percent"
+msgstr "覆盖率"
+
+#: coverager.tpl.php:39 coverager.tpl.php:101
+msgid "Hits"
+msgstr "命中"
+
+#: coverager.tpl.php:40 coverager.tpl.php:102
+msgid "Lines"
+msgstr "行数"
+
+#: coverager.tpl.php:41
+msgid "TODO"
+msgstr "闲置文件"
+
+#: coverager.tpl.php:99
+msgid "File"
+msgstr "文件"
+
+#: coverager.tpl.php:151
+msgid "root"
+msgstr "开始"
Index: /tags/3.0.0-rc1/htdocs/coverager/lang/zh-traditional.po
===================================================================
--- /tags/3.0.0-rc1/htdocs/coverager/lang/zh-traditional.po	(revision 1104)
+++ /tags/3.0.0-rc1/htdocs/coverager/lang/zh-traditional.po	(revision 1104)
@@ -0,0 +1,36 @@
+msgid ""
+msgstr ""
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2012-08-01 14:47+0800\n"
+"Language: zh_TW\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: coverager.tpl.php:37
+msgid "Directory"
+msgstr ""
+
+#: coverager.tpl.php:38 coverager.tpl.php:100
+msgid "Percent"
+msgstr ""
+
+#: coverager.tpl.php:39 coverager.tpl.php:101
+msgid "Hits"
+msgstr ""
+
+#: coverager.tpl.php:40 coverager.tpl.php:102
+msgid "Lines"
+msgstr ""
+
+#: coverager.tpl.php:41
+msgid "TODO"
+msgstr ""
+
+#: coverager.tpl.php:99
+msgid "File"
+msgstr ""
+
+#: coverager.tpl.php:151
+msgid "root"
+msgstr ""
Index: /tags/3.0.0-rc1/htdocs/coverager/lang/en.php
===================================================================
--- /tags/3.0.0-rc1/htdocs/coverager/lang/en.php	(revision 1102)
+++ /tags/3.0.0-rc1/htdocs/coverager/lang/en.php	(revision 1102)
@@ -0,0 +1,5 @@
+<?php
+// auto generated, do not modify
+$strings += array(
+		);
+
Index: /tags/3.0.0-rc1/htdocs/coverager/coverager.css
===================================================================
--- /tags/3.0.0-rc1/htdocs/coverager/coverager.css	(revision 1068)
+++ /tags/3.0.0-rc1/htdocs/coverager/coverager.css	(revision 1068)
@@ -0,0 +1,57 @@
+.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; height: 14px; }
+.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; }
+div.code {
+	border: 1px solid gray;
+	font-size: 12px;
+}
+pre.code {
+	font-family: monospace;
+	font-size: 12px;
+	white-space: pre;
+	padding: 0; margin: 0;
+}
+
+.error { color: red; }
Index: /tags/3.0.0-rc1/htdocs/coverager/config.example.php
===================================================================
--- /tags/3.0.0-rc1/htdocs/coverager/config.example.php	(revision 1116)
+++ /tags/3.0.0-rc1/htdocs/coverager/config.example.php	(revision 1116)
@@ -0,0 +1,19 @@
+<?php
+
+// DO NOT rename/delete/modify example file which will be overwritten when upgrade
+// How To Custom Config:
+// 1. copy config.example.php config.php; edit config.php
+// 2. upgrading your config.php when config.example.php were upgraded
+// XCache will load
+// 1. ../config.default.php
+// 2. ./config.default.php
+// 3. ../config.php
+// 4. ./config.php
+
+// $config['include_paths'] = array("/www/my-php-project/");
+// $config['exclude_paths'] = array("/www/my-php-project/tmp/");
+$config['syntax_higlight'] = true;
+$config['use_cache'] = false;
+//// $config['datadir'] is default to ini_get("xcache.coveragedump_directory")
+// $config['datadir'] = '';
+
Index: /tags/3.0.0-rc1/htdocs/coverager/index.php
===================================================================
--- /tags/3.0.0-rc1/htdocs/coverager/index.php	(revision 1126)
+++ /tags/3.0.0-rc1/htdocs/coverager/index.php	(revision 1126)
@@ -0,0 +1,332 @@
+<?php
+
+include "./common.php";
+
+class XcacheCoverageViewer
+{
+	var $syntax_higlight = true;
+	var $use_cache = false;
+	var $include_paths = array();
+	var $exclude_paths = array();
+	var $charset = 'UTF-8';
+	var $lang = 'en-us';
+	var $datadir = null;
+	var $datadir_len = null;
+	var $path = null;
+	var $outpath = null;
+
+	function XcacheCoverageViewer()
+	{
+		$this->datadir = ini_get('xcache.coveragedump_directory');
+
+		global $config;
+		foreach (array('charset', 'include_paths', 'exclude_paths', 'syntax_higlight', 'use_cache', 'datadir', 'lang') as $k) {
+			if (isset($config[$k])) {
+				$this->{$k} = $config[$k];
+			}
+		}
+
+		$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);
+		$qsep = preg_quote(DIRECTORY_SEPARATOR, '!');
+		$this->path = preg_replace("![\\\\$qsep]{2,}!", DIRECTORY_SEPARATOR, $this->path);
+		$this->path = preg_replace("!$qsep$!", '', $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->use_cache) {
+				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->syntax_higlight) {
+				$source = implode('', $lines);
+				ob_start();
+				highlight_string($source);
+				$lines = str_replace("\n", "", ob_get_clean());
+				$lines = str_replace('<code>', '', $lines);
+				$lines = str_replace('</code>', '', $lines);
+				$lines = preg_replace('(^<span[^>]*>|</span>$)', '', $lines);
+				$lines = explode('<br />', $lines);
+				$last = array_pop($lines);
+				$lines[count($lines) - 1] .= $last;
+				$filecov = sprint_cov($fileinfo['cov'], $lines, false);
+				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($tplcov, $tpllines);
+				unset($tpllines);
+			}
+		}
+		else if (!$this->datadir) {
+			$action = 'error';
+			$error  = 'require `xcache.coveragedump_directory` in ini or `$datadir` in config to be set';
+		}
+		else {
+			$action = 'error';
+			$error  = "no data";
+		}
+
+		global $config;
+		include "coverager.tpl.php";
+	}
+
+	function loadDir($outdir, $addtodo = null)
+	{
+		if ($this->use_cache) {
+			$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'];
+				if ($addtodo === true) {
+					$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->use_cache) {
+			ksort($subdirs);
+			ksort($files);
+		}
+
+		$info = array(
+				'total'   => $total,
+				'hits'    => $hits,
+				'todos'   => $todos,
+				'files'   => $files,
+				'subdirs' => $subdirs,
+				);
+
+		if ($this->use_cache) {
+			$fp = fopen($cachefile, "wb");
+			fwrite($fp, serialize($info));
+			fclose($fp);
+		}
+		return $info;
+	}
+
+	function loadFile($file)
+	{
+		if ($this->use_cache) {
+			$cachefile = $file . "cache";
+			if (file_exists($cachefile)) {
+				return unserialize(file_get_contents($cachefile));
+			}
+		}
+
+		$info = $this->loadCov($file); //, $lines);
+		unset($info['cov']);
+
+		if ($this->use_cache) {
+			$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)
+{
+	$lastattr = null;
+	foreach ($lines as $l => $line) {
+		$offs = $l + 1;
+		if ($encode) {
+			$line = str_replace("\n", "", htmlspecialchars($line));
+		}
+		else if ($line !== "") {
+			if (substr($line, 0, 7) == '</span>') {
+				$lastattr = null;
+				$line = substr($line, 7);
+			}
+			else if (isset($lastattr)) {
+				$line = $lastattr . $line;
+			}
+
+			if (preg_match('!(<span[^>]+>|</span>)[^<>]*$!', $line, $m)) {
+				if ($m[1] == '</span>') {
+					$lastattr = null;
+				}
+				else {
+					$line .= '</span>';
+					$lastattr = $m[1];
+				}
+			}
+		}
+		if (isset($cov[$offs])) {
+			$lines[$l] = sprintf("<li class=\"line%sCov\"><pre class=\"code\"> %s\t%s\n</pre></li>"
+					, $cov[$offs] ? '' : 'No'
+					, $cov[$offs]
+					, $line);
+		}
+		else {
+			$lines[$l] = "<li><pre class=\"code\">\t$line\n</pre></li>";
+		}
+	}
+	return implode('', $lines);
+}
+
+if (!function_exists('xcache_coverager_decode')) {
+	function xcache_coverager_decode($bytes)
+	{
+		$bytes = unpack('l*', $bytes);
+		$i = 1;
+		if ($bytes[$i ++] != 0x564f4350) {
+			return null;
+		}
+		$end = count($bytes);
+		$cov = array();
+		for (/* empty*/; $i <= $end; $i += 2) {
+			$hits = $bytes[$i + 1];
+			$cov[$bytes[$i]] = $hits <= 0 ? 0 : $hits;
+		}
+		return $cov;
+	}
+}
+
+$app = new XcacheCoverageViewer();
+$app->main();
+
+?>
Index: /tags/3.0.0-rc1/htdocs/coverager/common.php
===================================================================
--- /tags/3.0.0-rc1/htdocs/coverager/common.php	(revision 1099)
+++ /tags/3.0.0-rc1/htdocs/coverager/common.php	(revision 1099)
@@ -0,0 +1,7 @@
+<?php
+
+require_once "../common/common.php";
+
+include get_language_file("./lang");
+$module = "coverager";
+
Index: /tags/3.0.0-rc1/htdocs/coverager/config.default.php
===================================================================
--- /tags/3.0.0-rc1/htdocs/coverager/config.default.php	(revision 1054)
+++ /tags/3.0.0-rc1/htdocs/coverager/config.default.php	(revision 1054)
@@ -0,0 +1,12 @@
+<?php
+
+// [default config]
+// DO NOT rename/delete/modify this file which will be overwritten when upgrade
+// See config.example.php instead
+
+// $config['include_paths'] = array();
+// $config['exclude_paths'] = array();
+$config['syntax_higlight'] = true;
+$config['use_cache'] = false;
+// $config['datadir'] is default to ini_get("xcache.coveragedump_directory")
+
Index: /tags/3.0.0-rc1/htdocs/index.php
===================================================================
--- /tags/3.0.0-rc1/htdocs/index.php	(revision 1055)
+++ /tags/3.0.0-rc1/htdocs/index.php	(revision 1055)
@@ -0,0 +1,12 @@
+<?php
+
+chdir("common");
+require_once "common.php";
+if (!$modules) {
+	die("no sub modules' php pages installed");
+}
+foreach ($modules as $k => $v) {
+	header("Location: $k/");
+	break;
+}
+
Index: /tags/3.0.0-rc1/htdocs/config.default.php
===================================================================
--- /tags/3.0.0-rc1/htdocs/config.default.php	(revision 1053)
+++ /tags/3.0.0-rc1/htdocs/config.default.php	(revision 1053)
@@ -0,0 +1,17 @@
+<?php
+
+// [default config]
+// DO NOT rename/delete/modify this file which will be overwritten when upgrade
+// See config.example.php instead
+
+// detected by browser
+// $config['lang'] = 'en-us';
+
+$config['charset'] = "UTF-8";
+
+// translators only
+$config['show_todo_strings'] = false;
+
+// this ob filter function is applied for the list with paths, not the whole page
+$config['path_nicer'] = 'ob_filter_path_nicer_default';
+
Index: /tags/3.0.0-rc1/htdocs/diagnosis/lang/zh-simplified.po
===================================================================
--- /tags/3.0.0-rc1/htdocs/diagnosis/lang/zh-simplified.po	(revision 1148)
+++ /tags/3.0.0-rc1/htdocs/diagnosis/lang/zh-simplified.po	(revision 1148)
@@ -0,0 +1,383 @@
+msgid ""
+msgstr ""
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2012-09-02 00:52+0800\n"
+"Language: zh\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: diagnosis.tpl.php:4
+msgid "Diagnosis Result"
+msgstr "诊断结果"
+
+#: diagnosis.tpl.php:8
+msgid "Item"
+msgstr "项目"
+
+#: diagnosis.tpl.php:11
+msgid "Level"
+msgstr "级别"
+
+#: diagnosis.tpl.php:14
+msgid "Result"
+msgstr "结果"
+
+#: diagnosis.tpl.php:17
+msgid "Explanation/Suggestion"
+msgstr "解释/建议"
+
+#: index.php:77
+msgid "XCache extension"
+msgstr "XCache extension"
+
+#: index.php:81
+#, php-format
+msgid "Add extension=xcache.so (or xcache.dll) in %s"
+msgstr "在 %s 增加 extension=xcache.so (或 xcache.dll)"
+
+#: index.php:84
+#, php-format
+msgid ""
+"Please put a php.ini in %s and add extension=xcache.so (or xcache.dll) in it"
+msgstr ""
+"请在 %s 里放个 php.ini 并且在文件内写入 extension=xcache.so (或 xcache.dll)"
+
+#: index.php:87
+msgid "Cannot detect php.ini location"
+msgstr "无法检测 php.ini 位置"
+
+#: index.php:89
+msgid "(See above)"
+msgstr "(参见上面)"
+
+#: index.php:90
+msgid "Not loaded"
+msgstr "未载入"
+
+#: index.php:90 index.php:129 index.php:135 index.php:183 index.php:285
+#: index.php:303 index.php:368 index.php:391 index.php:394
+msgid "error"
+msgstr "错误"
+
+#: index.php:93
+msgid "Loaded"
+msgstr "已载入"
+
+#: index.php:93 index.php:141 index.php:158 index.php:175 index.php:189
+#: index.php:200 index.php:216 index.php:248 index.php:264 index.php:273
+#: index.php:291 index.php:309 index.php:332 index.php:347 index.php:373
+#: index.php:379 index.php:385 index.php:399
+msgid "info"
+msgstr "信息"
+
+#: index.php:124
+msgid "Enabling PHP Cacher"
+msgstr "启用 PHP 缓存器"
+
+#: index.php:126 index.php:146 index.php:149 index.php:163 index.php:166
+#: index.php:180 index.php:207 index.php:253 index.php:270 index.php:300
+#: index.php:318 index.php:338
+msgid "skipped"
+msgstr "跳过"
+
+#: index.php:130 index.php:184 index.php:274
+msgid "Not enabled"
+msgstr "尚未启用"
+
+#: index.php:131
+msgid ""
+"Your PHP pages is not accelerated by XCache. Set xcache.size to non-zero, "
+"set xcache.cacher = On"
+msgstr ""
+"XCache 并未对您的 PHP 网页起到加速作用. 设置 xcache.size 为非 0, 设置 xcache."
+"cacher = On"
+
+#: index.php:136
+msgid "No php script cached"
+msgstr "未缓存任何 PHP 脚本"
+
+#: index.php:137
+msgid "Your PHP pages is not accelerated by XCache. Set xcache.cacher = On"
+msgstr "XCache 并未对您的 PHP 网页起到加速作用. 设置 xcache.cacher = On"
+
+#: index.php:141 index.php:189 index.php:292 index.php:310 index.php:342
+msgid "Enabled"
+msgstr "已启用"
+
+#: index.php:144
+msgid "PHP Compile Time Error"
+msgstr "PHP 编译时错误"
+
+#: index.php:152 index.php:169 index.php:193 index.php:210 index.php:234
+#: index.php:242 index.php:256 index.php:324 index.php:341
+msgid "warning"
+msgstr "警告"
+
+#: index.php:153
+msgid "Error happened when compiling at least one of your PHP code"
+msgstr "至少在编译其中一个您的 PHP 代码时发生编译错误"
+
+#: index.php:154
+msgid ""
+"This usually means there is syntax error in your PHP code. Enable PHP "
+"error_log to see what parser error is it, fix your code"
+msgstr ""
+"这通常意味着您的 PHP 代码有语法错误. 请启用 error_log 调查具体错误原因并修复"
+"您的代码"
+
+#: index.php:158
+msgid "No error happened"
+msgstr "未发生过错误"
+
+#: index.php:161
+msgid "Busy Compiling"
+msgstr "忙着编译"
+
+#: index.php:170
+msgid "Cache marked as busy for compiling"
+msgstr "编译中, 缓存标记为忙"
+
+#: index.php:171
+msgid ""
+"It's ok if this status don't stay for long. Otherwise, it could be a sign of "
+"PHP crash/coredump, report to XCache devs"
+msgstr ""
+"这个状态如果持续不就则无影响. 否则可能标志着 PHP 曾经发生异常退出, 如果是的话"
+"请报告给 XCache 开发组"
+
+#: index.php:175 index.php:264 index.php:332
+msgid "Idle"
+msgstr "空闲"
+
+#: index.php:178
+msgid "Enabling VAR Cacher"
+msgstr "启用 VAR 缓存器"
+
+#: index.php:185
+msgid ""
+"PHP code that use XCache caching backend have to use other caching backend "
+"instead. Set xcache.var_size to non-zero"
+msgstr ""
+"使用 XCache 作为数据缓存器的 PHP 代码将不得不采用其他缓存器代替. 设置 xcache."
+"var_size 为非 0"
+
+#: index.php:191
+msgid "Using VAR Cacher"
+msgstr "使用 VAR 缓存器"
+
+#: index.php:194
+msgid "No variable data cached"
+msgstr "未缓存任何变量数据"
+
+#: index.php:195
+msgid ""
+"Var Cacher won't work simply by enabling it. PHP code must call XCache APIs "
+"like xcache_set() to use it as cache backend. 3rd party web apps may come "
+"with XCache support, config it to use XCache as caching backend"
+msgstr ""
+"只启用变量数据缓存器并无法将其利用起来. 必须通过 PHP 代码去调用 XCache API 接"
+"口(如 xcache_set() 函数) 将 XCache 作为缓存器. 第三方网页软件可能带有 XCache "
+"支持, 留意其中的设置启用 XCache 作为缓存器"
+
+#: index.php:200
+msgid "Cache in use"
+msgstr "缓存使用中"
+
+#: index.php:205
+msgid "Cache Size"
+msgstr "缓存大小"
+
+#: index.php:211
+msgid "Out of memory happened when trying to write to cache"
+msgstr "存入缓存时发生内存不足"
+
+#: index.php:212
+msgid "Increase xcache.size and/or xcache.var_size"
+msgstr "加大 xcache.size 或 xcache.var_size"
+
+#: index.php:216
+msgid "Enough"
+msgstr "充足"
+
+#: index.php:219
+msgid "Hash Slots"
+msgstr "哈希槽"
+
+#: index.php:235
+msgid "Slots value too big"
+msgstr "哈希槽设定太大"
+
+#: index.php:236
+#, php-format
+msgid ""
+"A very small value is set to %s value and leave %s value is too big.\n"
+"Decrease %s if small cache is really what you want"
+msgstr ""
+"设置给 %s 的值很小, 却采用过大的 %s. 如果您的确想要配置占用很少内存的缓存器, "
+"可减少 %s"
+
+#: index.php:243
+msgid "Slots value too small"
+msgstr "哈希槽设定太小"
+
+#: index.php:244
+#, php-format
+msgid "So many item are cached. Increase %s to a more proper value"
+msgstr "相当多的项目缓存了. 请适量加大 %s"
+
+#: index.php:248 index.php:373 index.php:385 index.php:399
+msgid "Looks good"
+msgstr "看起来还行"
+
+#: index.php:251
+msgid "Cache Status"
+msgstr "缓存状态"
+
+#: index.php:257
+msgid "At least one of the caches is disabled. "
+msgstr "至少一个缓存器是禁止状态"
+
+#: index.php:258
+msgid "Enable the cache."
+msgstr "启用已禁止的缓存器."
+
+#: index.php:259
+msgid ""
+"It was disabled by PHP crash/coredump handler or you disabled it manually."
+msgstr "可能是在 PHP 异常退出时自动标记为禁止了, 或者您手工禁止了"
+
+#: index.php:259
+msgid "You disabled it manually."
+msgstr "您手工禁止了"
+
+#: index.php:260
+msgid "If it was caused by PHP crash/coredump, report to XCache devs"
+msgstr "如果是由于 PHP 异常退出造成, 请报告给 XCache 开发组"
+
+#: index.php:268
+msgid "Coredump Directory"
+msgstr "Coredump 目录"
+
+#: index.php:275
+msgid ""
+"Enable coredump to save debugging information in case when PHP crash. It can "
+"also be enabled in other module like php-fpm beside XCache"
+msgstr ""
+"启用 coredump 设置. 这样万一发生 PHP 异常退出时可保存调试信息. 这个功能也可以"
+"在其他地方启用, 如 php-fpm"
+
+#: index.php:286
+msgid "Core files found:\n"
+msgstr "发现 core 文件:\n"
+
+#: index.php:287
+msgid ""
+"Disable XCache PHP Cacher (set xcache.size=0), remove the core file(s), then "
+"restart PHP. If core file appears again, report call stack backtrace in the "
+"core to XCache devs"
+msgstr ""
+"禁止 XCache 缓存器 (设置 xcache.size=0), 删除 Core 文件, 再重启 PHP. 如果不"
+"用 XCache 时不出现 Core, 请从 Core 中取得 call stack back trace 信息报告回 "
+"XCache 开发组"
+
+#: index.php:293
+#, php-format
+msgid "You can see core files if PHP crash in %s if PHP crash"
+msgstr "如果 PHP 异常退出, 您可以在 %s 目录看到 Core 文件"
+
+#: index.php:298
+msgid "Readonly Protection"
+msgstr "只读保护"
+
+#: index.php:304
+msgid "Set to enabled but not available"
+msgstr "设置为启用, 但目前不可用"
+
+#: index.php:305
+msgid "Use xcache.mmap_path other than /dev/zero"
+msgstr "设置 xcache.mmap_path 使用 /dev/zero 以外的值"
+
+#: index.php:310 index.php:347
+msgid "Disabled"
+msgstr "已禁止"
+
+#: index.php:311
+msgid ""
+"Enable readonly_protection == --performance & ++stability. Disable "
+"readonly_protection == ++performance & --stability"
+msgstr ""
+"启用 readonly_protection == --性能 & ++稳定性. 禁用 readonly_protection == +"
+"+性能 & --稳定性"
+
+#: index.php:316
+msgid "XCache modules"
+msgstr "XCache 模块"
+
+#: index.php:326
+msgid ""
+"Acceptable. Module(s) listed are built into XCache but not for production "
+"server.\n"
+"Leave it as is if you're feeling good.\n"
+"Re-configure XCache with the module(s) disabled if you're strict with server "
+"security."
+msgstr ""
+"可接受. 以上列出的模块已编译入 XCache, 但这些模块并非用于产业服务器.\n"
+"如果您觉得没大碍, 就保持现状.\n"
+"如果您对稳定性/安全性要求极其严格, 建议重新编译 XCache 不启用这些模块\n"
+
+#: index.php:336
+msgid "XCache test setting"
+msgstr "XCache 测试设置"
+
+#: index.php:343
+msgid "xcache.test is for testing only, not for server. set it to off"
+msgstr "xcache.test 仅用于开发测试用, 不用于服务器. 将它设置为 off"
+
+#: index.php:350
+msgid "PHP Version"
+msgstr "PHP 版本"
+
+#: index.php:369
+msgid "The version of PHP you're using is known to be unstable: "
+msgstr "您所使用的 PHP 版本, 是众所周知的不稳定版本: "
+
+#: index.php:370
+msgid "Upgrade to new version of PHP"
+msgstr "升级到更新的 PHP 版本"
+
+#: index.php:376
+msgid "Extension Compatibility"
+msgstr "Extension 兼容性"
+
+#: index.php:380
+msgid "Zend Optimizer loaded"
+msgstr "Zend Optimizer 载入了"
+
+#: index.php:381
+msgid ""
+"Optimizer feature of 'Zend Optimizer' is disabled by XCache due to "
+"compatibility reason; the Loader of it is still available, encoded files are "
+"still supported"
+msgstr ""
+"由于兼容性问题, 'Zend Optimizer' 的优化器已被 XCache 禁止; 其加载器依然可用, "
+"可继续使用 Zend 加密的文件"
+
+#: index.php:388
+#, fuzzy
+msgid "SAPI Compatibility"
+msgstr "Extension 兼容性"
+
+#: index.php:391
+msgid "CGI is not supported"
+msgstr ""
+
+#: index.php:391
+msgid "Use FastCGI or FPM instead"
+msgstr ""
+
+#: index.php:396
+msgid ""
+"PHP_FCGI_CHILDREN should be >= 1 and use 1 group of parent/childs model. See "
+"http://xcache.lighttpd.net/wiki/Faq"
+msgstr ""
Index: /tags/3.0.0-rc1/htdocs/diagnosis/lang/zh-traditional.po
===================================================================
--- /tags/3.0.0-rc1/htdocs/diagnosis/lang/zh-traditional.po	(revision 1148)
+++ /tags/3.0.0-rc1/htdocs/diagnosis/lang/zh-traditional.po	(revision 1148)
@@ -0,0 +1,356 @@
+msgid ""
+msgstr ""
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2012-09-02 00:52+0800\n"
+"Language: zh_TW\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: diagnosis.tpl.php:4
+msgid "Diagnosis Result"
+msgstr ""
+
+#: diagnosis.tpl.php:8
+msgid "Item"
+msgstr ""
+
+#: diagnosis.tpl.php:11
+msgid "Level"
+msgstr ""
+
+#: diagnosis.tpl.php:14
+msgid "Result"
+msgstr ""
+
+#: diagnosis.tpl.php:17
+msgid "Explanation/Suggestion"
+msgstr ""
+
+#: index.php:77
+msgid "XCache extension"
+msgstr ""
+
+#: index.php:81
+#, php-format
+msgid "Add extension=xcache.so (or xcache.dll) in %s"
+msgstr ""
+
+#: index.php:84
+#, php-format
+msgid ""
+"Please put a php.ini in %s and add extension=xcache.so (or xcache.dll) in it"
+msgstr ""
+
+#: index.php:87
+msgid "Cannot detect php.ini location"
+msgstr ""
+
+#: index.php:89
+msgid "(See above)"
+msgstr ""
+
+#: index.php:90
+msgid "Not loaded"
+msgstr ""
+
+#: index.php:90 index.php:129 index.php:135 index.php:183 index.php:285
+#: index.php:303 index.php:368 index.php:391 index.php:394
+msgid "error"
+msgstr ""
+
+#: index.php:93
+msgid "Loaded"
+msgstr ""
+
+#: index.php:93 index.php:141 index.php:158 index.php:175 index.php:189
+#: index.php:200 index.php:216 index.php:248 index.php:264 index.php:273
+#: index.php:291 index.php:309 index.php:332 index.php:347 index.php:373
+#: index.php:379 index.php:385 index.php:399
+msgid "info"
+msgstr ""
+
+#: index.php:124
+msgid "Enabling PHP Cacher"
+msgstr ""
+
+#: index.php:126 index.php:146 index.php:149 index.php:163 index.php:166
+#: index.php:180 index.php:207 index.php:253 index.php:270 index.php:300
+#: index.php:318 index.php:338
+msgid "skipped"
+msgstr ""
+
+#: index.php:130 index.php:184 index.php:274
+msgid "Not enabled"
+msgstr ""
+
+#: index.php:131
+msgid ""
+"Your PHP pages is not accelerated by XCache. Set xcache.size to non-zero, "
+"set xcache.cacher = On"
+msgstr ""
+
+#: index.php:136
+msgid "No php script cached"
+msgstr ""
+
+#: index.php:137
+msgid "Your PHP pages is not accelerated by XCache. Set xcache.cacher = On"
+msgstr ""
+
+#: index.php:141 index.php:189 index.php:292 index.php:310 index.php:342
+msgid "Enabled"
+msgstr ""
+
+#: index.php:144
+msgid "PHP Compile Time Error"
+msgstr ""
+
+#: index.php:152 index.php:169 index.php:193 index.php:210 index.php:234
+#: index.php:242 index.php:256 index.php:324 index.php:341
+msgid "warning"
+msgstr ""
+
+#: index.php:153
+msgid "Error happened when compiling at least one of your PHP code"
+msgstr ""
+
+#: index.php:154
+msgid ""
+"This usually means there is syntax error in your PHP code. Enable PHP "
+"error_log to see what parser error is it, fix your code"
+msgstr ""
+
+#: index.php:158
+msgid "No error happened"
+msgstr ""
+
+#: index.php:161
+msgid "Busy Compiling"
+msgstr ""
+
+#: index.php:170
+msgid "Cache marked as busy for compiling"
+msgstr ""
+
+#: index.php:171
+msgid ""
+"It's ok if this status don't stay for long. Otherwise, it could be a sign of "
+"PHP crash/coredump, report to XCache devs"
+msgstr ""
+
+#: index.php:175 index.php:264 index.php:332
+msgid "Idle"
+msgstr ""
+
+#: index.php:178
+msgid "Enabling VAR Cacher"
+msgstr ""
+
+#: index.php:185
+msgid ""
+"PHP code that use XCache caching backend have to use other caching backend "
+"instead. Set xcache.var_size to non-zero"
+msgstr ""
+
+#: index.php:191
+msgid "Using VAR Cacher"
+msgstr ""
+
+#: index.php:194
+msgid "No variable data cached"
+msgstr ""
+
+#: index.php:195
+msgid ""
+"Var Cacher won't work simply by enabling it. PHP code must call XCache APIs "
+"like xcache_set() to use it as cache backend. 3rd party web apps may come "
+"with XCache support, config it to use XCache as caching backend"
+msgstr ""
+
+#: index.php:200
+msgid "Cache in use"
+msgstr ""
+
+#: index.php:205
+msgid "Cache Size"
+msgstr ""
+
+#: index.php:211
+msgid "Out of memory happened when trying to write to cache"
+msgstr ""
+
+#: index.php:212
+msgid "Increase xcache.size and/or xcache.var_size"
+msgstr ""
+
+#: index.php:216
+msgid "Enough"
+msgstr ""
+
+#: index.php:219
+msgid "Hash Slots"
+msgstr ""
+
+#: index.php:235
+msgid "Slots value too big"
+msgstr ""
+
+#: index.php:236
+#, php-format
+msgid ""
+"A very small value is set to %s value and leave %s value is too big.\n"
+"Decrease %s if small cache is really what you want"
+msgstr ""
+
+#: index.php:243
+msgid "Slots value too small"
+msgstr ""
+
+#: index.php:244
+#, php-format
+msgid "So many item are cached. Increase %s to a more proper value"
+msgstr ""
+
+#: index.php:248 index.php:373 index.php:385 index.php:399
+msgid "Looks good"
+msgstr ""
+
+#: index.php:251
+msgid "Cache Status"
+msgstr ""
+
+#: index.php:257
+msgid "At least one of the caches is disabled. "
+msgstr ""
+
+#: index.php:258
+msgid "Enable the cache."
+msgstr ""
+
+#: index.php:259
+msgid ""
+"It was disabled by PHP crash/coredump handler or you disabled it manually."
+msgstr ""
+
+#: index.php:259
+msgid "You disabled it manually."
+msgstr ""
+
+#: index.php:260
+msgid "If it was caused by PHP crash/coredump, report to XCache devs"
+msgstr ""
+
+#: index.php:268
+msgid "Coredump Directory"
+msgstr ""
+
+#: index.php:275
+msgid ""
+"Enable coredump to save debugging information in case when PHP crash. It can "
+"also be enabled in other module like php-fpm beside XCache"
+msgstr ""
+
+#: index.php:286
+msgid "Core files found:\n"
+msgstr ""
+
+#: index.php:287
+msgid ""
+"Disable XCache PHP Cacher (set xcache.size=0), remove the core file(s), then "
+"restart PHP. If core file appears again, report call stack backtrace in the "
+"core to XCache devs"
+msgstr ""
+
+#: index.php:293
+#, php-format
+msgid "You can see core files if PHP crash in %s if PHP crash"
+msgstr ""
+
+#: index.php:298
+msgid "Readonly Protection"
+msgstr ""
+
+#: index.php:304
+msgid "Set to enabled but not available"
+msgstr ""
+
+#: index.php:305
+msgid "Use xcache.mmap_path other than /dev/zero"
+msgstr ""
+
+#: index.php:310 index.php:347
+msgid "Disabled"
+msgstr ""
+
+#: index.php:311
+msgid ""
+"Enable readonly_protection == --performance & ++stability. Disable "
+"readonly_protection == ++performance & --stability"
+msgstr ""
+
+#: index.php:316
+msgid "XCache modules"
+msgstr ""
+
+#: index.php:326
+msgid ""
+"Acceptable. Module(s) listed are built into XCache but not for production "
+"server.\n"
+"Leave it as is if you're feeling good.\n"
+"Re-configure XCache with the module(s) disabled if you're strict with server "
+"security."
+msgstr ""
+
+#: index.php:336
+msgid "XCache test setting"
+msgstr ""
+
+#: index.php:343
+msgid "xcache.test is for testing only, not for server. set it to off"
+msgstr ""
+
+#: index.php:350
+msgid "PHP Version"
+msgstr ""
+
+#: index.php:369
+msgid "The version of PHP you're using is known to be unstable: "
+msgstr ""
+
+#: index.php:370
+msgid "Upgrade to new version of PHP"
+msgstr ""
+
+#: index.php:376
+msgid "Extension Compatibility"
+msgstr ""
+
+#: index.php:380
+msgid "Zend Optimizer loaded"
+msgstr ""
+
+#: index.php:381
+msgid ""
+"Optimizer feature of 'Zend Optimizer' is disabled by XCache due to "
+"compatibility reason; the Loader of it is still available, encoded files are "
+"still supported"
+msgstr ""
+
+#: index.php:388
+msgid "SAPI Compatibility"
+msgstr ""
+
+#: index.php:391
+msgid "CGI is not supported"
+msgstr ""
+
+#: index.php:391
+msgid "Use FastCGI or FPM instead"
+msgstr ""
+
+#: index.php:396
+msgid ""
+"PHP_FCGI_CHILDREN should be >= 1 and use 1 group of parent/childs model. See "
+"http://xcache.lighttpd.net/wiki/Faq"
+msgstr ""
Index: /tags/3.0.0-rc1/htdocs/diagnosis/lang/en.php
===================================================================
--- /tags/3.0.0-rc1/htdocs/diagnosis/lang/en.php	(revision 1102)
+++ /tags/3.0.0-rc1/htdocs/diagnosis/lang/en.php	(revision 1102)
@@ -0,0 +1,5 @@
+<?php
+// auto generated, do not modify
+$strings += array(
+		);
+
Index: /tags/3.0.0-rc1/htdocs/diagnosis/lang/zh-simplified.php
===================================================================
--- /tags/3.0.0-rc1/htdocs/diagnosis/lang/zh-simplified.php	(revision 1148)
+++ /tags/3.0.0-rc1/htdocs/diagnosis/lang/zh-simplified.php	(revision 1148)
@@ -0,0 +1,151 @@
+<?php
+// auto generated, do not modify
+$strings += array(
+		"Diagnosis Result"
+		=> "诊断结果",
+		"Item"
+		=> "项目",
+		"Level"
+		=> "级别",
+		"Result"
+		=> "结果",
+		"Explanation/Suggestion"
+		=> "解释/建议",
+		"XCache extension"
+		=> "XCache extension",
+		"Add extension=xcache.so (or xcache.dll) in %s"
+		=> "在 %s 增加 extension=xcache.so (或 xcache.dll)",
+		"Please put a php.ini in %s and add extension=xcache.so (or xcache.dll) in it"
+		=> "请在 %s 里放个 php.ini 并且在文件内写入 extension=xcache.so (或 xcache.dll)",
+		"Cannot detect php.ini location"
+		=> "无法检测 php.ini 位置",
+		"(See above)"
+		=> "(参见上面)",
+		"Not loaded"
+		=> "未载入",
+		"error"
+		=> "错误",
+		"Loaded"
+		=> "已载入",
+		"info"
+		=> "信息",
+		"Enabling PHP Cacher"
+		=> "启用 PHP 缓存器",
+		"skipped"
+		=> "跳过",
+		"Not enabled"
+		=> "尚未启用",
+		"Your PHP pages is not accelerated by XCache. Set xcache.size to non-zero, set xcache.cacher = On"
+		=> "XCache 并未对您的 PHP 网页起到加速作用. 设置 xcache.size 为非 0, 设置 xcache.cacher = On",
+		"No php script cached"
+		=> "未缓存任何 PHP 脚本",
+		"Your PHP pages is not accelerated by XCache. Set xcache.cacher = On"
+		=> "XCache 并未对您的 PHP 网页起到加速作用. 设置 xcache.cacher = On",
+		"Enabled"
+		=> "已启用",
+		"PHP Compile Time Error"
+		=> "PHP 编译时错误",
+		"warning"
+		=> "警告",
+		"Error happened when compiling at least one of your PHP code"
+		=> "至少在编译其中一个您的 PHP 代码时发生编译错误",
+		"This usually means there is syntax error in your PHP code. Enable PHP error_log to see what parser error is it, fix your code"
+		=> "这通常意味着您的 PHP 代码有语法错误. 请启用 error_log 调查具体错误原因并修复您的代码",
+		"No error happened"
+		=> "未发生过错误",
+		"Busy Compiling"
+		=> "忙着编译",
+		"Cache marked as busy for compiling"
+		=> "编译中, 缓存标记为忙",
+		"It's ok if this status don't stay for long. Otherwise, it could be a sign of PHP crash/coredump, report to XCache devs"
+		=> "这个状态如果持续不就则无影响. 否则可能标志着 PHP 曾经发生异常退出, 如果是的话请报告给 XCache 开发组",
+		"Idle"
+		=> "空闲",
+		"Enabling VAR Cacher"
+		=> "启用 VAR 缓存器",
+		"PHP code that use XCache caching backend have to use other caching backend instead. Set xcache.var_size to non-zero"
+		=> "使用 XCache 作为数据缓存器的 PHP 代码将不得不采用其他缓存器代替. 设置 xcache.var_size 为非 0",
+		"Using VAR Cacher"
+		=> "使用 VAR 缓存器",
+		"No variable data cached"
+		=> "未缓存任何变量数据",
+		"Var Cacher won't work simply by enabling it. PHP code must call XCache APIs like xcache_set() to use it as cache backend. 3rd party web apps may come with XCache support, config it to use XCache as caching backend"
+		=> "只启用变量数据缓存器并无法将其利用起来. 必须通过 PHP 代码去调用 XCache API 接口(如 xcache_set() 函数) 将 XCache 作为缓存器. 第三方网页软件可能带有 XCache 支持, 留意其中的设置启用 XCache 作为缓存器",
+		"Cache in use"
+		=> "缓存使用中",
+		"Cache Size"
+		=> "缓存大小",
+		"Out of memory happened when trying to write to cache"
+		=> "存入缓存时发生内存不足",
+		"Increase xcache.size and/or xcache.var_size"
+		=> "加大 xcache.size 或 xcache.var_size",
+		"Enough"
+		=> "充足",
+		"Hash Slots"
+		=> "哈希槽",
+		"Slots value too big"
+		=> "哈希槽设定太大",
+		"A very small value is set to %s value and leave %s value is too big.\nDecrease %s if small cache is really what you want"
+		=> "设置给 %s 的值很小, 却采用过大的 %s. 如果您的确想要配置占用很少内存的缓存器, 可减少 %s",
+		"Slots value too small"
+		=> "哈希槽设定太小",
+		"So many item are cached. Increase %s to a more proper value"
+		=> "相当多的项目缓存了. 请适量加大 %s",
+		"Looks good"
+		=> "看起来还行",
+		"Cache Status"
+		=> "缓存状态",
+		"At least one of the caches is disabled. "
+		=> "至少一个缓存器是禁止状态",
+		"Enable the cache."
+		=> "启用已禁止的缓存器.",
+		"It was disabled by PHP crash/coredump handler or you disabled it manually."
+		=> "可能是在 PHP 异常退出时自动标记为禁止了, 或者您手工禁止了",
+		"You disabled it manually."
+		=> "您手工禁止了",
+		"If it was caused by PHP crash/coredump, report to XCache devs"
+		=> "如果是由于 PHP 异常退出造成, 请报告给 XCache 开发组",
+		"Coredump Directory"
+		=> "Coredump 目录",
+		"Enable coredump to save debugging information in case when PHP crash. It can also be enabled in other module like php-fpm beside XCache"
+		=> "启用 coredump 设置. 这样万一发生 PHP 异常退出时可保存调试信息. 这个功能也可以在其他地方启用, 如 php-fpm",
+		"Core files found:\n"
+		=> "发现 core 文件:\n",
+		"Disable XCache PHP Cacher (set xcache.size=0), remove the core file(s), then restart PHP. If core file appears again, report call stack backtrace in the core to XCache devs"
+		=> "禁止 XCache 缓存器 (设置 xcache.size=0), 删除 Core 文件, 再重启 PHP. 如果不用 XCache 时不出现 Core, 请从 Core 中取得 call stack back trace 信息报告回 XCache 开发组",
+		"You can see core files if PHP crash in %s if PHP crash"
+		=> "如果 PHP 异常退出, 您可以在 %s 目录看到 Core 文件",
+		"Readonly Protection"
+		=> "只读保护",
+		"Set to enabled but not available"
+		=> "设置为启用, 但目前不可用",
+		"Use xcache.mmap_path other than /dev/zero"
+		=> "设置 xcache.mmap_path 使用 /dev/zero 以外的值",
+		"Disabled"
+		=> "已禁止",
+		"Enable readonly_protection == --performance & ++stability. Disable readonly_protection == ++performance & --stability"
+		=> "启用 readonly_protection == --性能 & ++稳定性. 禁用 readonly_protection == ++性能 & --稳定性",
+		"XCache modules"
+		=> "XCache 模块",
+		"Acceptable. Module(s) listed are built into XCache but not for production server.\nLeave it as is if you're feeling good.\nRe-configure XCache with the module(s) disabled if you're strict with server security."
+		=> "可接受. 以上列出的模块已编译入 XCache, 但这些模块并非用于产业服务器.\n如果您觉得没大碍, 就保持现状.\n如果您对稳定性/安全性要求极其严格, 建议重新编译 XCache 不启用这些模块\n",
+		"XCache test setting"
+		=> "XCache 测试设置",
+		"xcache.test is for testing only, not for server. set it to off"
+		=> "xcache.test 仅用于开发测试用, 不用于服务器. 将它设置为 off",
+		"PHP Version"
+		=> "PHP 版本",
+		"The version of PHP you're using is known to be unstable: "
+		=> "您所使用的 PHP 版本, 是众所周知的不稳定版本: ",
+		"Upgrade to new version of PHP"
+		=> "升级到更新的 PHP 版本",
+		"Extension Compatibility"
+		=> "Extension 兼容性",
+		"Zend Optimizer loaded"
+		=> "Zend Optimizer 载入了",
+		"Optimizer feature of 'Zend Optimizer' is disabled by XCache due to compatibility reason; the Loader of it is still available, encoded files are still supported"
+		=> "由于兼容性问题, 'Zend Optimizer' 的优化器已被 XCache 禁止; 其加载器依然可用, 可继续使用 Zend 加密的文件",
+		"SAPI Compatibility"
+		=> "Extension 兼容性",
+		);
+
Index: /tags/3.0.0-rc1/htdocs/diagnosis/lang/en.po
===================================================================
--- /tags/3.0.0-rc1/htdocs/diagnosis/lang/en.po	(revision 1148)
+++ /tags/3.0.0-rc1/htdocs/diagnosis/lang/en.po	(revision 1148)
@@ -0,0 +1,356 @@
+msgid ""
+msgstr ""
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2012-09-02 00:52+0800\n"
+"Language: en\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: diagnosis.tpl.php:4
+msgid "Diagnosis Result"
+msgstr ""
+
+#: diagnosis.tpl.php:8
+msgid "Item"
+msgstr ""
+
+#: diagnosis.tpl.php:11
+msgid "Level"
+msgstr ""
+
+#: diagnosis.tpl.php:14
+msgid "Result"
+msgstr ""
+
+#: diagnosis.tpl.php:17
+msgid "Explanation/Suggestion"
+msgstr ""
+
+#: index.php:77
+msgid "XCache extension"
+msgstr ""
+
+#: index.php:81
+#, php-format
+msgid "Add extension=xcache.so (or xcache.dll) in %s"
+msgstr ""
+
+#: index.php:84
+#, php-format
+msgid ""
+"Please put a php.ini in %s and add extension=xcache.so (or xcache.dll) in it"
+msgstr ""
+
+#: index.php:87
+msgid "Cannot detect php.ini location"
+msgstr ""
+
+#: index.php:89
+msgid "(See above)"
+msgstr ""
+
+#: index.php:90
+msgid "Not loaded"
+msgstr ""
+
+#: index.php:90 index.php:129 index.php:135 index.php:183 index.php:285
+#: index.php:303 index.php:368 index.php:391 index.php:394
+msgid "error"
+msgstr ""
+
+#: index.php:93
+msgid "Loaded"
+msgstr ""
+
+#: index.php:93 index.php:141 index.php:158 index.php:175 index.php:189
+#: index.php:200 index.php:216 index.php:248 index.php:264 index.php:273
+#: index.php:291 index.php:309 index.php:332 index.php:347 index.php:373
+#: index.php:379 index.php:385 index.php:399
+msgid "info"
+msgstr ""
+
+#: index.php:124
+msgid "Enabling PHP Cacher"
+msgstr ""
+
+#: index.php:126 index.php:146 index.php:149 index.php:163 index.php:166
+#: index.php:180 index.php:207 index.php:253 index.php:270 index.php:300
+#: index.php:318 index.php:338
+msgid "skipped"
+msgstr ""
+
+#: index.php:130 index.php:184 index.php:274
+msgid "Not enabled"
+msgstr ""
+
+#: index.php:131
+msgid ""
+"Your PHP pages is not accelerated by XCache. Set xcache.size to non-zero, "
+"set xcache.cacher = On"
+msgstr ""
+
+#: index.php:136
+msgid "No php script cached"
+msgstr ""
+
+#: index.php:137
+msgid "Your PHP pages is not accelerated by XCache. Set xcache.cacher = On"
+msgstr ""
+
+#: index.php:141 index.php:189 index.php:292 index.php:310 index.php:342
+msgid "Enabled"
+msgstr ""
+
+#: index.php:144
+msgid "PHP Compile Time Error"
+msgstr ""
+
+#: index.php:152 index.php:169 index.php:193 index.php:210 index.php:234
+#: index.php:242 index.php:256 index.php:324 index.php:341
+msgid "warning"
+msgstr ""
+
+#: index.php:153
+msgid "Error happened when compiling at least one of your PHP code"
+msgstr ""
+
+#: index.php:154
+msgid ""
+"This usually means there is syntax error in your PHP code. Enable PHP "
+"error_log to see what parser error is it, fix your code"
+msgstr ""
+
+#: index.php:158
+msgid "No error happened"
+msgstr ""
+
+#: index.php:161
+msgid "Busy Compiling"
+msgstr ""
+
+#: index.php:170
+msgid "Cache marked as busy for compiling"
+msgstr ""
+
+#: index.php:171
+msgid ""
+"It's ok if this status don't stay for long. Otherwise, it could be a sign of "
+"PHP crash/coredump, report to XCache devs"
+msgstr ""
+
+#: index.php:175 index.php:264 index.php:332
+msgid "Idle"
+msgstr ""
+
+#: index.php:178
+msgid "Enabling VAR Cacher"
+msgstr ""
+
+#: index.php:185
+msgid ""
+"PHP code that use XCache caching backend have to use other caching backend "
+"instead. Set xcache.var_size to non-zero"
+msgstr ""
+
+#: index.php:191
+msgid "Using VAR Cacher"
+msgstr ""
+
+#: index.php:194
+msgid "No variable data cached"
+msgstr ""
+
+#: index.php:195
+msgid ""
+"Var Cacher won't work simply by enabling it. PHP code must call XCache APIs "
+"like xcache_set() to use it as cache backend. 3rd party web apps may come "
+"with XCache support, config it to use XCache as caching backend"
+msgstr ""
+
+#: index.php:200
+msgid "Cache in use"
+msgstr ""
+
+#: index.php:205
+msgid "Cache Size"
+msgstr ""
+
+#: index.php:211
+msgid "Out of memory happened when trying to write to cache"
+msgstr ""
+
+#: index.php:212
+msgid "Increase xcache.size and/or xcache.var_size"
+msgstr ""
+
+#: index.php:216
+msgid "Enough"
+msgstr ""
+
+#: index.php:219
+msgid "Hash Slots"
+msgstr ""
+
+#: index.php:235
+msgid "Slots value too big"
+msgstr ""
+
+#: index.php:236
+#, php-format
+msgid ""
+"A very small value is set to %s value and leave %s value is too big.\n"
+"Decrease %s if small cache is really what you want"
+msgstr ""
+
+#: index.php:243
+msgid "Slots value too small"
+msgstr ""
+
+#: index.php:244
+#, php-format
+msgid "So many item are cached. Increase %s to a more proper value"
+msgstr ""
+
+#: index.php:248 index.php:373 index.php:385 index.php:399
+msgid "Looks good"
+msgstr ""
+
+#: index.php:251
+msgid "Cache Status"
+msgstr ""
+
+#: index.php:257
+msgid "At least one of the caches is disabled. "
+msgstr ""
+
+#: index.php:258
+msgid "Enable the cache."
+msgstr ""
+
+#: index.php:259
+msgid ""
+"It was disabled by PHP crash/coredump handler or you disabled it manually."
+msgstr ""
+
+#: index.php:259
+msgid "You disabled it manually."
+msgstr ""
+
+#: index.php:260
+msgid "If it was caused by PHP crash/coredump, report to XCache devs"
+msgstr ""
+
+#: index.php:268
+msgid "Coredump Directory"
+msgstr ""
+
+#: index.php:275
+msgid ""
+"Enable coredump to save debugging information in case when PHP crash. It can "
+"also be enabled in other module like php-fpm beside XCache"
+msgstr ""
+
+#: index.php:286
+msgid "Core files found:\n"
+msgstr ""
+
+#: index.php:287
+msgid ""
+"Disable XCache PHP Cacher (set xcache.size=0), remove the core file(s), then "
+"restart PHP. If core file appears again, report call stack backtrace in the "
+"core to XCache devs"
+msgstr ""
+
+#: index.php:293
+#, php-format
+msgid "You can see core files if PHP crash in %s if PHP crash"
+msgstr ""
+
+#: index.php:298
+msgid "Readonly Protection"
+msgstr ""
+
+#: index.php:304
+msgid "Set to enabled but not available"
+msgstr ""
+
+#: index.php:305
+msgid "Use xcache.mmap_path other than /dev/zero"
+msgstr ""
+
+#: index.php:310 index.php:347
+msgid "Disabled"
+msgstr ""
+
+#: index.php:311
+msgid ""
+"Enable readonly_protection == --performance & ++stability. Disable "
+"readonly_protection == ++performance & --stability"
+msgstr ""
+
+#: index.php:316
+msgid "XCache modules"
+msgstr ""
+
+#: index.php:326
+msgid ""
+"Acceptable. Module(s) listed are built into XCache but not for production "
+"server.\n"
+"Leave it as is if you're feeling good.\n"
+"Re-configure XCache with the module(s) disabled if you're strict with server "
+"security."
+msgstr ""
+
+#: index.php:336
+msgid "XCache test setting"
+msgstr ""
+
+#: index.php:343
+msgid "xcache.test is for testing only, not for server. set it to off"
+msgstr ""
+
+#: index.php:350
+msgid "PHP Version"
+msgstr ""
+
+#: index.php:369
+msgid "The version of PHP you're using is known to be unstable: "
+msgstr ""
+
+#: index.php:370
+msgid "Upgrade to new version of PHP"
+msgstr ""
+
+#: index.php:376
+msgid "Extension Compatibility"
+msgstr ""
+
+#: index.php:380
+msgid "Zend Optimizer loaded"
+msgstr ""
+
+#: index.php:381
+msgid ""
+"Optimizer feature of 'Zend Optimizer' is disabled by XCache due to "
+"compatibility reason; the Loader of it is still available, encoded files are "
+"still supported"
+msgstr ""
+
+#: index.php:388
+msgid "SAPI Compatibility"
+msgstr ""
+
+#: index.php:391
+msgid "CGI is not supported"
+msgstr ""
+
+#: index.php:391
+msgid "Use FastCGI or FPM instead"
+msgstr ""
+
+#: index.php:396
+msgid ""
+"PHP_FCGI_CHILDREN should be >= 1 and use 1 group of parent/childs model. See "
+"http://xcache.lighttpd.net/wiki/Faq"
+msgstr ""
Index: /tags/3.0.0-rc1/htdocs/diagnosis/lang/zh-traditional.php
===================================================================
--- /tags/3.0.0-rc1/htdocs/diagnosis/lang/zh-traditional.php	(revision 1115)
+++ /tags/3.0.0-rc1/htdocs/diagnosis/lang/zh-traditional.php	(revision 1115)
@@ -0,0 +1,5 @@
+<?php
+// auto generated, do not modify
+$strings += array(
+		);
+
Index: /tags/3.0.0-rc1/htdocs/diagnosis/diagnosis.tpl.php
===================================================================
--- /tags/3.0.0-rc1/htdocs/diagnosis/diagnosis.tpl.php	(revision 1103)
+++ /tags/3.0.0-rc1/htdocs/diagnosis/diagnosis.tpl.php	(revision 1103)
@@ -0,0 +1,29 @@
+<?php include "../common/header.tpl.php"; ?>
+<table cellspacing="0" cellpadding="4" class="cycles" id="diagnosisResult">
+	<caption>
+		<?php echo _T("Diagnosis Result"); ?>
+	</caption>
+	<tr>
+		<th>
+			<?php echo _T("Item"); ?>
+		</th>
+		<th>
+			<?php echo _T("Level"); ?>
+		</th>
+		<th>
+			<?php echo _T("Result"); ?>
+		</th>
+		<th>
+			<?php echo _T("Explanation/Suggestion"); ?>
+		</th>
+	</tr>
+<?php foreach ($notes as $note) { ?>
+	<tr class="<?php echo $note['type']; ?>">
+		<td nowrap="nowrap" align="right"><?php echo $note['item']; ?></td>
+		<td nowrap="nowrap"><?php echo ucfirst(__($note['type'])); ?></td>
+		<td nowrap="nowrap"><?php echo nl2br($note['result']); ?></td>
+		<td><?php echo nl2br($note['suggestion']); ?></td>
+	</tr>
+<?php } ?>
+</table>
+<?php include "../common/footer.tpl.php"; ?>
Index: /tags/3.0.0-rc1/htdocs/diagnosis/diagnosis.css
===================================================================
--- /tags/3.0.0-rc1/htdocs/diagnosis/diagnosis.css	(revision 1092)
+++ /tags/3.0.0-rc1/htdocs/diagnosis/diagnosis.css	(revision 1092)
@@ -0,0 +1,12 @@
+#diagnosisResult .info {
+	background: #C0FFC0;
+}
+#diagnosisResult .warning {
+	background: #FFF0FF;
+}
+#diagnosisResult .error {
+	background: #FFA0A0;
+}
+#main #diagnosisResult td {
+	vertical-align: top;
+}
Index: /tags/3.0.0-rc1/htdocs/diagnosis/index.php
===================================================================
--- /tags/3.0.0-rc1/htdocs/diagnosis/index.php	(revision 1125)
+++ /tags/3.0.0-rc1/htdocs/diagnosis/index.php	(revision 1125)
@@ -0,0 +1,404 @@
+<?php
+
+include "../common/common.php";
+include get_language_file("./lang");
+
+$knownUnstablePhpVersions = array(
+		array('=', '5.3.14', 'random corrupt memory on high concurrent'),
+		);
+
+$module = "diagnosis";
+
+$notes = array();
+$activeNote = null;
+function checking($item) // {{{
+{
+	global $activeNote;
+	$activeNote = array('item' => $item);
+}
+// }}}
+function result($type, $result, $suggestion = "") // {{{
+{
+	global $notes, $activeNote;
+	$notes[] = array(
+			'type' => $type
+			, 'result' => ($type != 'skipped' && !$suggestion ? "OK. " : "") . $result
+			, 'suggestion' => $suggestion
+			) + $activeNote;
+}
+// }}}
+function getCacheInfos() // {{{
+{
+	$phpCacheCount = xcache_count(XC_TYPE_PHP);
+	$varCacheCount = xcache_count(XC_TYPE_VAR);
+
+	$cacheInfos = array();
+	for ($i = 0; $i < $phpCacheCount; $i ++) {
+		$cacheInfo = xcache_info(XC_TYPE_PHP, $i);
+		$cacheInfo['type'] = XC_TYPE_PHP;
+		$cacheInfos[] = $cacheInfo;
+	}
+
+	for ($i = 0; $i < $varCacheCount; $i ++) {
+		$cacheInfo = xcache_info(XC_TYPE_VAR, $i);
+		$cacheInfo['type'] = XC_TYPE_VAR;
+		$cacheInfos[] = $cacheInfo;
+	}
+	return $cacheInfos;
+}
+// }}}
+function getIniFileInfo() // {{{
+{
+	ob_start();
+	phpinfo(INFO_GENERAL);
+	$info = ob_get_clean();
+	ob_start();
+	if (preg_match_all("!<tr>[^<]*<td[^>]*>[^<]*(?:Configuration|ini|Server API)[^<]*</td>[^<]*<td[^>]*>[^<]*</td>[^<]*</tr>!s", $info, $m)) {
+		$iniInfo = '<table class="phpinfo">'
+			. implode('', $m[0])
+			. '</table>';
+	}
+	else {
+		$iniInfo = '';
+	}
+	$loadedIni = '';
+	$iniDirectory = '';
+	if (preg_match('!<td class="v">(.*?\\.ini)!', $info, $m)) {
+		$loadedIni = $m[1];
+	}
+	else if (preg_match('!Configuration File \\(php.ini\\) Path *</td><td class="v">([^<]+)!', $info, $m)) {
+		$iniDirectory = $m[1];
+	}
+	return array($loadedIni, $iniDirectory, $iniInfo);
+}
+// }}}
+
+$xcacheLoaded = extension_loaded('XCache');
+checking(_T("XCache extension")); // {{{
+if (!$xcacheLoaded) {
+	list($loadedIni, $iniDirectory, $iniInfo) = getIniFileInfo();
+	if ($loadedIni) {
+		echo sprintf(_T("Add extension=xcache.so (or xcache.dll) in %s"), $loadedIni);
+	}
+	else if (preg_match('!Configuration File \\(php.ini\\) Path *</td><td class="v">([^<]+)!', $info, $m)) {
+		echo sprintf(_T("Please put a php.ini in %s and add extension=xcache.so (or xcache.dll) in it"), $iniDirectory);
+	}
+	else {
+		echo _T("Cannot detect php.ini location");
+	}
+	echo " ", _T("(See above)");
+	result(N_("error"), _T('Not loaded'), ob_get_clean());
+}
+else {
+	result(N_("info"), _T('Loaded'));
+}
+// }}}
+if ($xcacheLoaded) { // {{{ load XCache summary
+	$cacheInfos = getCacheInfos();
+
+	$ooms = 0;
+	$errors = 0;
+	$disabled = 0;
+	$compiling = 0;
+	$readonlyProtection = false;
+	$phpCacheCount = xcache_count(XC_TYPE_PHP);
+	$phpCached = 0;
+	$varCached = 0;
+	foreach ($cacheInfos as $cacheInfo) {
+		$ooms += $cacheInfo['ooms'];
+		$errors += $cacheInfo['errors'];
+		$disabled += $cacheInfo['disabled'] ? 1 : 0;
+		if ($cacheInfo['type'] == XC_TYPE_PHP) {
+			$compiling += $cacheInfo['compiling'] ? 1 : 0;
+			$phpCached += $cacheInfo['cached'];
+		}
+		if ($cacheInfo['type'] == XC_TYPE_VAR && $cacheInfo['cached']) {
+			$varCached += $cacheInfo['cached'];
+		}
+		if ($cacheInfo['can_readonly']) {
+			$readonlyProtection = true;
+		}
+	}
+}
+// }}}
+checking(_T("Enabling PHP Cacher")); // {{{
+if (!$xcacheLoaded) {
+	result(N_("skipped"), "XCache not loaded");
+}
+else if (!ini_get("xcache.size")) {
+	result(N_("error")
+		, _T("Not enabled")
+		, _T("Your PHP pages is not accelerated by XCache. Set xcache.size to non-zero, set xcache.cacher = On")
+		);
+}
+else if (!$phpCached) {
+	result(N_("error")
+		, _T("No php script cached")
+		, _T("Your PHP pages is not accelerated by XCache. Set xcache.cacher = On")
+		);
+}
+else {
+	result(N_("info"), _T('Enabled'));
+}
+// }}}
+checking(_T("PHP Compile Time Error")); // {{{
+if (!$xcacheLoaded) {
+	result(N_("skipped"), "XCache not loaded");
+}
+else if (!$phpCacheCount) {
+	result(N_("skipped"), "XCache PHP cacher not enabled");
+}
+else if ($errors) {
+	result(N_("warning")
+		, _T("Error happened when compiling at least one of your PHP code")
+		, _T("This usually means there is syntax error in your PHP code. Enable PHP error_log to see what parser error is it, fix your code")
+		);
+}
+else {
+	result(N_("info"), _T('No error happened'));
+}
+// }}}
+checking(_T("Busy Compiling")); // {{{
+if (!$xcacheLoaded) {
+	result(N_("skipped"), "XCache not loaded");
+}
+else if (!$phpCacheCount) {
+	result(N_("skipped"), "XCache PHP cacher not enabled");
+}
+else if ($compiling) {
+	result(N_("warning")
+		, _T("Cache marked as busy for compiling")
+		, _T("It's ok if this status don't stay for long. Otherwise, it could be a sign of PHP crash/coredump, report to XCache devs")
+		);
+}
+else {
+	result(N_("info"), _T('Idle'));
+}
+// }}}
+checking(_T("Enabling VAR Cacher")); // {{{
+if (!$xcacheLoaded) {
+	result(N_("skipped"), "XCache not loaded");
+}
+else if (!ini_get("xcache.var_size")) {
+	result(N_("error")
+		, _T("Not enabled")
+		, _T("PHP code that use XCache caching backend have to use other caching backend instead. Set xcache.var_size to non-zero")
+		);
+}
+else {
+	result(N_("info"), _T('Enabled'));
+
+	checking(_T("Using VAR Cacher")); // {{{
+	if (!$varCached) {
+		result(N_("warning")
+			, _T("No variable data cached")
+			, _T("Var Cacher won't work simply by enabling it."
+				. " PHP code must call XCache APIs like xcache_set() to use it as cache backend. 3rd party web apps may come with XCache support, config it to use XCache as caching backend")
+			);
+	}
+	else {
+		result(N_("info"), _T('Cache in use'));
+	}
+	// }}}
+}
+// }}}
+checking(_T("Cache Size")); // {{{
+if (!$xcacheLoaded) {
+	result(N_("skipped"), "XCache not loaded");
+}
+else if ($ooms) {
+	result(N_("warning")
+		, _T("Out of memory happened when trying to write to cache")
+		, _T("Increase xcache.size and/or xcache.var_size")
+		);
+}
+else {
+	result(N_("info"), _T('Enough'));
+}
+// }}}
+checking(_T("Hash Slots")); // {{{
+$slotsTooBig = null;
+$slotsTooSmall = null;
+foreach ($cacheInfos as $cacheInfo) {
+	if ($cacheInfo['size'] < '1024000' && $cacheInfo['slots'] >= '8192') {
+		$slotsTooBig = $cacheInfo['type'];
+		break;
+	}
+	if ($cacheInfo['slots'] < $cacheInfo['cached'] / 2) {
+		$slotsTooSmall = $cacheInfo['type'];
+		break;
+	}
+}
+if (isset($slotsTooBig)) {
+	$prefix = $slotsTooBig == XC_TYPE_PHP ? '' : 'var_';
+	result(N_("warning")
+		, _T("Slots value too big")
+		, sprintf(_T("A very small value is set to %s value and leave %s value is too big.\n"
+			. "Decrease %s if small cache is really what you want"), "xcache.{$prefix}size", "xcache.{$prefix}slots", "xcache.{$prefix}slots")
+		);
+}
+else if (isset($slotsTooSmall)) {
+	$prefix = $slotsTooSmall == XC_TYPE_PHP ? '' : 'var_';
+	result(N_("warning")
+		, _T("Slots value too small")
+		, sprintf(_T("So many item are cached. Increase %s to a more proper value"), "xcache.{$prefix}slots")
+		);
+}
+else {
+	result(N_("info"), _T('Looks good'));
+}
+// }}}
+checking(_T("Cache Status")); // {{{
+if (!$xcacheLoaded) {
+	result(N_("skipped"), "XCache not loaded");
+}
+else if ($disabled) {
+	result(N_("warning")
+		, _T("At least one of the caches is disabled. ")
+		, _T("Enable the cache.")
+			. (ini_get("xcache.crash_on_coredump") ? " " . _T("It was disabled by PHP crash/coredump handler or you disabled it manually.") : _T('You disabled it manually.'))
+			. (ini_get("xcache.crash_on_coredump") ? " " . _T("If it was caused by PHP crash/coredump, report to XCache devs") : "")
+		);
+}
+else {
+	result(N_("info"), _T('Idle'));
+}
+// }}}
+
+checking(_T("Coredump Directory")); // {{{
+if (!$xcacheLoaded) {
+	result(N_("skipped"), "XCache not loaded");
+}
+else if (!ini_get("xcache.coredump_directory")) {
+	result(N_("info")
+			, _T("Not enabled")
+			, _T("Enable coredump to save debugging information in case when PHP crash. It can also be enabled in other module like php-fpm beside XCache")
+			);
+}
+else if (ini_get("xcache.coredump_directory")) {
+	$coreDir = ini_get("xcache.coredump_directory");
+	if (substr($coreDir, -1) != DIRECTORY_SEPARATOR) {
+		$coreDir .= DIRECTORY_SEPARATOR;
+	}
+	$coreFiles = glob($coreDir . "core*");
+	if ($coreFiles) {
+		result(N_("error")
+				, _T("Core files found:\n") . implode("\n", $coreFiles)
+				, _T("Disable XCache PHP Cacher (set xcache.size=0), remove the core file(s), then restart PHP. If core file appears again, report call stack backtrace in the core to XCache devs")
+				);
+	}
+	else {
+		result(N_("info")
+				, _T("Enabled")
+				, sprintf(_T("You can see core files if PHP crash in %s if PHP crash"), ini_get("xcache.coredump_directory"))
+				);
+	}
+}
+// }}}
+checking(_T("Readonly Protection")); // {{{
+if (!$xcacheLoaded) {
+	result(N_("skipped"), "XCache not loaded");
+}
+else if (ini_get("xcache.readonly_protection") && !$readonlyProtection) {
+	result(N_("error")
+		, _T("Set to enabled but not available")
+		, _T("Use xcache.mmap_path other than /dev/zero")
+		);
+}
+else {
+	result(N_("info")
+		, $readonlyProtection ? _T("Enabled") : _T("Disabled")
+		, _T("Enable readonly_protection == --performance & ++stability. "
+			. "Disable readonly_protection == ++performance & --stability")
+		);
+}
+// }}}
+checking(_T("XCache modules")); // {{{
+if (!$xcacheLoaded) {
+	result(N_("skipped"), "XCache not loaded");
+}
+else {
+	$xcacheModules = explode(" ", XCACHE_MODULES);
+	$unexpectedModules = array_intersect($xcacheModules, array("coverager", "disassembler"));
+	if ($unexpectedModules) {
+		result(N_("warning")
+			, implode("\n", $unexpectedModules)
+			, _T("Acceptable. Module(s) listed are built into XCache but not for production server.\n"
+				. "Leave it as is if you're feeling good.\n"
+				. "Re-configure XCache with the module(s) disabled if you're strict with server security.")
+			);
+	}
+	else {
+		result(N_("info"), _T('Idle'));
+	}
+}
+// }}}
+checking(_T("XCache test setting")); // {{{
+if (!$xcacheLoaded) {
+	result(N_("skipped"), "XCache not loaded");
+}
+else if ((int) ini_get('xcache.test') == 1) {
+	result(N_("warning")
+		, _T("Enabled")
+		, _T("xcache.test is for testing only, not for server. set it to off")
+		);
+}
+else {
+	result(N_("info"), _T('Disabled'));
+}
+// }}}
+checking(_T("PHP Version")); // {{{
+$phpVersion = phpversion();
+$unstablePhpVersionReason = null;
+foreach ($knownUnstablePhpVersions as $knownUnstablePhpVersion) {
+	list($compareOp, $unstablePhpVersion, $reason) = $knownUnstablePhpVersion;
+	if ($compareOp) {
+		$isUnstable = version_compare($phpVersion, $unstablePhpVersion, $compareOp);
+	}
+	else {
+		$isUnstable = substr($phpVersion, 0, strlen($unstablePhpVersion)) == $unstablePhpVersion;
+	}
+
+	if ($isUnstable) {
+		$unstablePhpVersionReason = $reason;
+		break;
+	}
+}
+if ($unstablePhpVersionReason) {
+	result(N_("error")
+			, _T("The version of PHP you're using is known to be unstable: ") . $unstablePhpVersionReason
+			, _T("Upgrade to new version of PHP"));
+}
+else {
+	result(N_("info"), _T("Looks good"));
+}
+// }}}
+checking(_T("Extension Compatibility")); // {{{
+$loadedZendExtensions = get_loaded_extensions(true);
+if (array_search("Zend Optimizer", $loadedZendExtensions) !== false) {
+	result(N_("info")
+		, _T("Zend Optimizer loaded")
+		, _T("Optimizer feature of 'Zend Optimizer' is disabled by XCache due to compatibility reason; the Loader of it is still available, encoded files are still supported")
+		);
+}
+else {
+	result(N_("info"), _T("Looks good"));
+}
+// }}}
+checking(_T("SAPI Compatibility")); // {{{
+
+if (php_sapi_name() == "cgi" || php_sapi_name() == "cgi-fcgi" && !isset($_SERVER["FCGI_ROLE"])) {
+	result(N_("error"), _T("CGI is not supported"), _T("Use FastCGI or FPM instead"));
+}
+else if (php_sapi_name() == "cgi-fcgi" && isset($_SERVER["FCGI_ROLE"]) && (int) getenv("PHP_FCGI_CHILDREN") < 1) {
+	result(N_("error")
+		, "PHP_FCGI_CHILDREN<1"
+		, _T("PHP_FCGI_CHILDREN should be >= 1 and use 1 group of parent/childs model. See http://xcache.lighttpd.net/wiki/Faq"));
+}
+else {
+	result(N_("info"), _T("Looks good"));
+}
+// }}}
+
+include "./diagnosis.tpl.php";
+
Index: /tags/3.0.0-rc1/Makefile.frag.deps
===================================================================
--- /tags/3.0.0-rc1/Makefile.frag.deps	(revision 1141)
+++ /tags/3.0.0-rc1/Makefile.frag.deps	(revision 1141)
@@ -0,0 +1,25 @@
+$(XCACHE_INCLUDES_I) $(builddir)/includes.lo: $(srcdir)/mod_cacher/xc_cache.h $(srcdir)/xcache.h $(srcdir)/xcache/xc_compatibility.h $(srcdir)/xcache/xc_lock.h $(srcdir)/xcache/xc_shm.h $(srcdir)/xcache/xc_utils.h
+$(builddir)/mod_assembler/xc_assembler.lo:
+$(builddir)/mod_cacher/xc_cacher.lo: $(srcdir)/mod_cacher/xc_cache.h $(srcdir)/mod_cacher/xc_cacher.h $(srcdir)/util/xc_align.h $(srcdir)/util/xc_stack.h $(srcdir)/util/xc_trace.h $(srcdir)/util/xc_vector.h $(srcdir)/xcache_globals.h $(srcdir)/xcache.h $(srcdir)/xcache/xc_allocator.h $(srcdir)/xcache/xc_compatibility.h $(srcdir)/xcache/xc_extension.h $(srcdir)/xcache/xc_ini.h $(srcdir)/xcache/xc_lock.h $(srcdir)/xcache/xc_sandbox.h $(srcdir)/xcache/xc_shm.h $(srcdir)/xcache/xc_utils.h $(XCACHE_PROC_H)
+$(builddir)/mod_coverager/xc_coverager.lo: $(srcdir)/mod_coverager/xc_coverager.h $(srcdir)/util/xc_stack.h $(srcdir)/util/xc_trace.h $(srcdir)/xcache_globals.h $(srcdir)/xcache.h $(srcdir)/xcache/xc_compatibility.h $(srcdir)/xcache/xc_extension.h $(srcdir)/xcache/xc_ini.h $(srcdir)/xcache/xc_lock.h $(srcdir)/xcache/xc_shm.h $(srcdir)/xcache/xc_utils.h
+$(builddir)/mod_decoder/xc_decoder.lo:
+$(builddir)/mod_disassembler/xc_disassembler.lo: $(srcdir)/mod_cacher/xc_cache.h $(srcdir)/mod_disassembler/xc_disassembler.h $(srcdir)/xcache.h $(srcdir)/xcache/xc_allocator.h $(srcdir)/xcache/xc_compatibility.h $(srcdir)/xcache/xc_ini.h $(srcdir)/xcache/xc_lock.h $(srcdir)/xcache/xc_sandbox.h $(srcdir)/xcache/xc_shm.h $(srcdir)/xcache/xc_utils.h $(XCACHE_PROC_H)
+$(builddir)/mod_encoder/xc_encoder.lo:
+$(builddir)/mod_optimizer/xc_optimizer.lo: $(srcdir)/mod_optimizer/xc_optimizer.h $(srcdir)/util/xc_stack.h $(srcdir)/util/xc_trace.h $(srcdir)/xcache_globals.h $(srcdir)/xcache.h $(srcdir)/xcache/xc_compatibility.h $(srcdir)/xcache/xc_extension.h $(srcdir)/xcache/xc_ini.h $(srcdir)/xcache/xc_lock.h $(srcdir)/xcache/xc_shm.h $(srcdir)/xcache/xc_utils.h
+$(builddir)/util/xc_stack.lo: $(srcdir)/util/xc_stack.h $(srcdir)/util/xc_trace.h
+$(builddir)/util/xc_trace.lo: $(srcdir)/util/xc_trace.h
+$(builddir)/xcache.lo: $(srcdir)/util/xc_foreachcoresig.h $(srcdir)/util/xc_stack.h $(srcdir)/xcache_globals.h $(srcdir)/xcache.h $(srcdir)/xcache/xc_compatibility.h $(srcdir)/xcache/xc_const_string.h $(srcdir)/xcache/xc_extension.h $(srcdir)/xcache/xc_ini.h $(srcdir)/xcache/xc_lock.h $(srcdir)/xcache/xc_opcode_spec.h $(srcdir)/xcache/xc_shm.h $(srcdir)/xcache/xc_utils.h
+$(builddir)/xcache/xc_allocator_bestfit.lo: $(srcdir)/util/xc_align.h $(srcdir)/util/xc_trace.h $(srcdir)/xcache/xc_allocator.h $(srcdir)/xcache/xc_shm.h
+$(builddir)/xcache/xc_allocator.lo: $(srcdir)/xcache/xc_allocator.h $(srcdir)/xcache/xc_shm.h
+$(builddir)/xcache/xc_compatibility.lo: $(srcdir)/xcache/xc_compatibility.h
+$(builddir)/xcache/xc_const_string.lo: $(srcdir)/xcache.h $(srcdir)/xcache/xc_compatibility.h $(srcdir)/xcache/xc_const_string.h $(srcdir)/xcache/xc_const_string_opcodes_php5.4.h $(srcdir)/xcache/xc_lock.h $(srcdir)/xcache/xc_shm.h
+$(builddir)/xcache/xc_extension.lo: $(srcdir)/util/xc_stack.h $(srcdir)/util/xc_trace.h $(srcdir)/xcache.h $(srcdir)/xcache/xc_compatibility.h $(srcdir)/xcache/xc_extension.h $(srcdir)/xcache/xc_lock.h $(srcdir)/xcache/xc_shm.h
+$(builddir)/xcache/xc_ini.lo: $(srcdir)/xcache/xc_ini.h
+$(builddir)/xcache/xc_lock.lo: $(srcdir)/xcache.h $(srcdir)/xcache/xc_compatibility.h $(srcdir)/xcache/xc_lock.h $(srcdir)/xcache/xc_shm.h
+$(builddir)/xcache/xc_malloc.lo: $(srcdir)/util/xc_align.h $(srcdir)/xcache.h $(srcdir)/xcache/xc_allocator.h $(srcdir)/xcache/xc_compatibility.h $(srcdir)/xcache/xc_lock.h $(srcdir)/xcache/xc_shm.h
+$(builddir)/xcache/xc_opcode_spec.lo: $(srcdir)/xcache.h $(srcdir)/xcache/xc_compatibility.h $(srcdir)/xcache/xc_const_string.h $(srcdir)/xcache/xc_lock.h $(srcdir)/xcache/xc_opcode_spec_def.h $(srcdir)/xcache/xc_opcode_spec.h $(srcdir)/xcache/xc_shm.h
+$(builddir)/xcache/xc_processor.lo: $(srcdir)/mod_cacher/xc_cache.h $(srcdir)/util/xc_align.h $(srcdir)/util/xc_stack.h $(srcdir)/xcache_globals.h $(srcdir)/xcache.h $(srcdir)/xcache/xc_allocator.h $(srcdir)/xcache/xc_compatibility.h $(srcdir)/xcache/xc_const_string.h $(srcdir)/xcache/xc_lock.h $(srcdir)/xcache/xc_shm.h $(srcdir)/xcache/xc_utils.h $(XCACHE_PROC_C) $(XCACHE_PROC_H)
+$(builddir)/xcache/xc_sandbox.lo: $(srcdir)/util/xc_stack.h $(srcdir)/xcache_globals.h $(srcdir)/xcache.h $(srcdir)/xcache/xc_compatibility.h $(srcdir)/xcache/xc_lock.h $(srcdir)/xcache/xc_sandbox.h $(srcdir)/xcache/xc_shm.h $(srcdir)/xcache/xc_utils.h
+$(builddir)/xcache/xc_shm.lo: $(srcdir)/xcache/xc_shm.h
+$(builddir)/xcache/xc_shm_mmap.lo: $(srcdir)/xcache.h $(srcdir)/xcache/xc_compatibility.h $(srcdir)/xcache/xc_lock.h $(srcdir)/xcache/xc_shm.h $(srcdir)/xcache/xc_utils.h
+$(builddir)/xcache/xc_utils.lo: $(srcdir)/util/xc_stack.h $(srcdir)/util/xc_trace.h $(srcdir)/xcache_globals.h $(srcdir)/xcache.h $(srcdir)/xcache/xc_compatibility.h $(srcdir)/xcache/xc_lock.h $(srcdir)/xcache/xc_opcode_spec.h $(srcdir)/xcache/xc_shm.h $(srcdir)/xcache/xc_utils.h
Index: /tags/3.0.0-rc1/xcache-zh-gb2312.ini
===================================================================
--- /tags/3.0.0-rc1/xcache-zh-gb2312.ini	(revision 1117)
+++ /tags/3.0.0-rc1/xcache-zh-gb2312.ini	(revision 1117)
@@ -0,0 +1,76 @@
+;; ���ļ�ֻ������, ���� php.ini �������Ա���Ч
+[xcache-common]
+;; �� windows ����:
+extension = xcache.so
+;; Windows ϵͳ����:
+; extension = php_xcache.dll
+
+[xcache.admin]
+xcache.admin.enable_auth = On
+xcache.admin.user = "mOo"
+; xcache.admin.pass = md5($��������)
+; ��¼ʹ�� $your_password
+xcache.admin.pass = ""
+
+[xcache]
+; ����Ķ���ѡ����� ini ������޸�, �����г��Ķ���Ĭ��ֵ, ��������˵��
+
+; select low level shm/allocator scheme implemenation
+xcache.shm_scheme =        "mmap"
+; ����: xcache.size=0
+; ����: xcache.size=64M ֮�� (����>0��ֵ) ͬʱ��ע������ϵͳ mmap ����
+xcache.size  =               60M
+; ��������Ϊ cpu �� (cat /proc/cpuinfo |grep -c processor)
+xcache.count =                 1
+; ֻ�Ǹ��ο�ֵ, �����Է��ĵش洢���ڴ���������Ŀ(php�ű�/����)
+xcache.slots =                8K
+; ������Ŀ�� ttl, 0=����
+xcache.ttl   =                 0
+; ɨ�������Ŀ��ʱ����, 0=��ɨ��, ����ֵ����Ϊ��λ
+xcache.gc_interval =           0
+
+; ͬ��, ֻ����Ա�����������
+xcache.var_size  =            4M
+xcache.var_count =             1
+xcache.var_slots =            8K
+; xcache_*() ���� ttl ������Ĭ��ֵ
+xcache.var_ttl   =             0
+; ���� xcache_*() ���� ttl ����������������. 0=������
+xcache.var_maxttl   =          0
+xcache.var_gc_interval =     300
+
+; /dev/zero ʱ��Ч
+xcache.readonly_protection = Off
+; ���� *nix ϵͳ, xcache.mmap_path ���ļ�·��������Ŀ¼. (�Զ�����/����)
+; ������������� ReadonlyProtection, �������ʹ�� "/dev/*", ����ʹ������ "/tmp/xcache"
+; ��ͬ php �����鲻�Ṳ��ͬһ�� /tmp/xcache
+; ���� Win32 ϵͳ, xcache.mmap_path=����MAP����, �����ļ�·��. ����ʹ�� XCache ���۱�������������ͻ
+xcache.mmap_path =    "/dev/zero"
+
+
+; ����Ϊ��(����) �������� "/tmp/phpcore/"
+; ע���Ŀ¼Ӧ���ܱ� php д���ļ� (�� open_basedir �޹�)
+xcache.coredump_directory =   ""
+; disable cache after crash
+xcache.disable_on_crash =    Off
+
+; ����ʵ���Թ��� (�����)
+xcache.experimental =        Off
+
+; per request settings. ���� ini_set, .htaccess ��
+xcache.cacher =               On
+xcache.stat   =               On
+xcache.optimizer =           Off
+
+[xcache.coverager]
+; �����ܿ���󽵵���������
+; ���� xcache.coverager == On && xcache.coveragedump_directory == "�ǿ�ֵ" ʱ�����ܲŻ�����
+
+; per request settings. ���� ini_set, .htaccess ��
+; ���ô������̸�������Ϣ�ɼ��Լ� xcache_coverager_start/stop/get/clean() �Ⱥ���
+xcache.coverager =           Off
+xcache.coverager_autostart =  On
+
+; ���� php ini �ļ�������
+; ��ȷ����Ŀ¼�ܱ� coverage viewer �ű���ȡ (ע�� open_basedir)
+xcache.coveragedump_directory = ""
Index: /tags/3.0.0-rc1/includes.c
===================================================================
--- /tags/3.0.0-rc1/includes.c	(revision 1051)
+++ /tags/3.0.0-rc1/includes.c	(revision 1051)
@@ -0,0 +1,4 @@
+#include "xcache.h"
+#include "mod_cacher/xc_cache.h"
+#include "xcache/xc_utils.h"
+#include "zend_compile.h"
Index: /tags/3.0.0-rc1/ChangeLog
===================================================================
--- /tags/3.0.0-rc1/ChangeLog	(revision 1146)
+++ /tags/3.0.0-rc1/ChangeLog	(revision 1146)
@@ -0,0 +1,210 @@
+3.0.0 2012-??-??
+API Changes
+========
+ * chg: proto array xcache_clear_cache(int type, [ int id = -1 ]). -1 means all cache splits
+ * new: proto array xcache_enable_cache(int type, [ int id = -1, [ bool enable = true ] ])
+ * new: proto array xcache_admin_namespace()
+ * new: proto array xcache_set_namespace(string namespace)
+
+Ini Settings Changes
+========
+ * new: xcache.disable_on_crash = Off
+ * new: xcache.coverager_autostart = On
+ * new: xcache.allocator = bestfit (no other option value yet)
+ * new: xcache.var_allocator = bestfit (no other option value yet)
+
+ChangeLog
+========
+ * closes #2: auto disable caching on crash
+ * closes #73: warn for improper PHP_FCGI_CHILDREN setting fcgi mode (>=PHP_5_3)
+ * closes #174: updates api to support "clear all cache"
+ * closes #198: support for caching protocol url
+ * closes #287: namespace support
+ * fixes #39: ini_set never work for xcache.coverager setting. use API instead
+ * code refactor
+   * uses extension= to load XCache. loading via zend_extension= is unsupported
+   * split XCache features into multiple sub modules
+ * updates XCache admin page
+ * adds an diagnosis module to give professional advise, accessable via htdocs pages
+ * cache can be enabled/disabled manually
+
+2.0.1 2012-07-14
+ChangeLog
+========
+ * fixed #279: segv when cache is full (since 2.0)
+ * fixed #281: subsequenc request segv when timeout happens during compiling
+ * admin/ config changed. please update accordingly
+ * WIN32: kill invalidate CRT parameters on shutdown
+ * fixed: <=PHP_5_2 duplicate error message failed to include file
+ * fixed #283: XCache admin APIs (admin page) cause SEGV if XCache failed to initize
+ * fixed possible re-include a file by mixing include/include_once
+ * fixed #264, #284: __FILE__ __DIR__ handling for moved/hardlinked files (set "xcache.experimental = on" to eanble this fix)
+
+2.0.0 2012-04-20
+Ini Settings Changes
+========
+ * new: xcache.experimental = Off
+
+ChangeLog
+========
+ * support for PHP_5_4
+ * reduce memory usage by caching 1 for multiple same content files
+ * correct __FILE__ __DIR__ supported for hardlinked files
+ * fixed #275: one line struct definition was confusing struct parser
+ * fixed #102: segv when var cacher is too small
+ * fixed #55: segv php tokenizer on certain special situation
+ * fixed #278: admin page: wrong layout in opera
+ * compiler errors: all compiler warning (E_STRICT only currently) is now cached and is supported for user handler
+ * tests/bug52160.phpt: report multiple error correctly
+
+1.3.2 2011-06-04
+========
+ * avoid possible filename injection in admin page
+ * adds 30 seconds timeout to "compiling" flag
+ * decompiler: improves decompiling
+ * disassembler: improper handling of null field
+ * disassembler: DECLARE_INHERITED_CLASS/DELAYED class not found
+ * disassembler: don't dump builtin functions
+ * fix win32 build against win32 native gnu tools
+ * compatibility fix: fix segv on shutdown when ionCube Loader is loaded
+ * fixed undefined index for xcache.count=1 and xcache.var_size>1
+ * fixed #258: builtin constant memory leak on compile
+
+1.3.1 2010-11-27
+========
+ * 2G/4G limitation on 64bit arch
+ * xcache_unset matching e.g. prefixed_ values
+
+1.3.0 2009-08-04
+== ChangeLog ==
+ * PHP 5.3 support
+ * fixed #138: no segv if cache is not initialized correctly
+ * default to 64M for xcache.size in xcache.ini
+ * could not show module info in admin page when XCache is the last module
+ * wrong http auth realm
+ * coverager: font-size and newline fix for firefox
+ * admin page is now magic quote gpc aware
+
+1.2.2 2007-12-29
+== ChangeLog ==
+ * added module dependency
+ * live with wrong system time: allow caching files with mtime in further
+ * bug fix for compatibility with Zend Optimizer and other non-cachable
+ * #59: Maximum execution time of 60 seconds exceeded
+ * #102: segv when var cacher is too small
+ * #55: segv php tokenizer on certain special situation
+
+1.2.1 2007-07-01
+== Ini Settings Changes ==
+ * new: xcache.admin.enable_auth = On
+
+== ChangeLog ==
+ * #86: remove/edit variable in admin page
+ * fixed #109: fast inc/dec was trying to break ro protection
+ * fixed #101, #105: Fixed compatibility issue for apache 1.x
+ * fixed #94: Garbage collector disabled when xcache.cacher set to off
+ * fixed #92: Zend Optimizer compatibility issue
+ * fixed #77: hits/misses was not updated
+ * fixed #59: pass by reference for internal function was broken
+ * fixed #56: xcache_set segfaults when xcache.var_size=0
+
+========
+1.2.0 2006-12-10
+Ini Settings Changes
+========
+ * new: xcache.stat = On
+ * new: xcache.coverager =  Off
+ * chg: xcache.coveragedump_directory default to ""
+ * del: xcache.coveragedumper = Off
+
+New APIs
+========
+ * array xcache_coverager_decode(string data)
+ * void  xcache_coverager_start([bool clean = true])
+ * void  xcache_coverager_stop([bool clean = false])
+ * array xcache_coverager_get([bool clean = false])
+
+ChangeLog
+========
+ * [290] [291] [292] build with the m4 on solaris
+ * [283] removed zend_append_version_info. not needed after [282] 
+ * [282] fix possible alloca() scope problem in lock 
+ * [281] keep config.nice on make xcachesvnclean 
+ * [279] fixed #48, was leaking info when cacher is not enabled by size 
+ * [280] [278] trunk: fix coredump on shutdown when loaded as "extension" and after "suhosin" or "zend optimizer". thanks to Alex, Cristian and Esser 
+ * [271] fix auto detection of php-cli/php-cgi for test 
+ * [270] make [269] pass test cases 
+ * [269] do not destruct shallow copied tmp_auto_globals. also improve copying of other hash tables
+ * [268] full compatible with auto_globals_jit, no need to disable it in ini from now on 
+ * [250] fixed css class on switcher
+ * [231] fix zval reference handling
+ * [230] update dprint support, added configure option: --enable-xcache-dprint
+ * [228] more robust coverager
+ * [227] cacher: remove redundant open_basedir check which broke php-src/ext/standard/tests/file/bug24313.phpt 
+ * [221] cacher: fix eleak in op_array non-shadow-copy (readonly_protection=on)
+ * [220] fixed #36, Bug in inherited static class variables
+ * [219] fix prototype for readonly_protection=off, fix testcase Zend/tests/bug37632.phpt 
+ * [217] kill leak warning on debug build
+ * [216] avoid crash on php compiler error
+ * [215] add `make xcachetest` to run xcache enabled test
+ * [214] [212] fixed #41, early class binding
+ * [272] [267] [263] [200] fixes for php6
+ * [224] [193] kill 64bit warning when self test is enabled 
+ * [190] trick to load and work with zend optimizer 
+ * [189] call op_array_ctor handler on restore to be more compatible with other zend_extension 
+ * [257] [183] xcache module is not required by coverage viewer any more
+ * [165] xcache.stat support to allow tuning off stat (new ini)
+ * [164] better way to handle system level ini settings so it can be display in phpinfo standardly
+
+1.1.0 2006-11-11
+ * merged [254] fix xcache.var_ttl displaying in info, fix xcache_get for ttl-unlimited
+ * merged [250] admin: fix switcher class on active
+ * merged [249] return 0 s instead of empty for deltatime
+ * merged [201] coverager: avoid crash when upstream failed to compile file
+ * merged from trunk: 159,161-162,167-180,182,184,186-187,194
+   * [194] PHP_5_2: new element in zend_brk_cont_element
+   * [186] [187] fix build on some rare arch
+   * [184] fix tplcov
+   * [178] fix type processor_t conflict with Mac OS X
+ * remove redundant open_basedir check, it's done before compiling
+ * trick in_compilation state, don't trigger __autoload at compile time
+ * FIX conflict between sandbox and user error handler 
+ * [154] fix segv on MSHUTDOWN
+ * [153] win32/vc build fix
+ * [150] avoid crash when OOM on mem_realloc
+ * [148] reconstruct shm/allocator
+ * [147] show module info in statistics page
+ * [146] avoid reading of uninitialized data. thanks to valgrind
+ * [144] compat size displaying in admin page func
+ * [143] fixed string parameter parsing arg type for disassembler functions. thanks to check_paramaters.php
+ * [141] fix cache clear corruption bug
+ * [140] fix refcount on cache #1 #2 …
+ * [133] admin-page: be more friendly if XCache isn't loaded
+ * [132] fix zts on calling destroy_op_array
+ * [131] move open_files out of sandbox, it's not needed
+ * [130] improve locking for compile
+ * [137] [138] changed the coding way of unlinking list. fixed ttl expires dead loop
+ * [114] gc expired items, new ini: xcache.ttl xcache.gc_interval xcache.var_ttl …
+ * [126] fix xcache_isset reported by http://forum.lighttpd.net/topic/1397
+ * [119] fix leak in xcache.test=1; XCACHE_VERSION/XCACHE_MODULES length off-by-one
+ * [118] show gc countdown in admin page
+ * [113] zts build fix
+ * [112] avoid crash when OOM on mem_(calloc|realloc|strndup)
+ * [108] update percent bar to vertical/avail
+ * [107] show XCache version in admin page
+ * [105] trigger jit on $_SERVER when needed
+ * [101] note: xcache.mmap_path is a file
+ * [100] FIX: alloc'ed wrong size for string on restore
+ * [99]  sohosin compatible & TSRM fix.
+ * [96]  remove tailing \0 in filename of administration html output. reported by …
+ * [94]  PHP_5_2: __tostring cache was MFH by php
+ * [93]  try to show both count/size assert before abort
+ * [92]  PHP_5_2: auto module_global is maintained by php engine
+ * [90] [91] kill compiler warnings
+ * [87]  XCACHE_INDENT fallback
+ * [84]  handle without inodes
+ * [79]  fix messy XCACHE_MAP_FAILED checking
+ * [78]  catch up with PHP_5_2, zend_property_info.ce
+ * [77]  leakcheck
+
+ (not all changesets is list here)
Index: /tags/3.0.0-rc1/run-xcachetest
===================================================================
--- /tags/3.0.0-rc1/run-xcachetest	(revision 863)
+++ /tags/3.0.0-rc1/run-xcachetest	(revision 863)
@@ -0,0 +1,36 @@
+#!/bin/sh
+
+getAbsolutePath() {
+	which readlink >/dev/null 2>&1 && readlink -f "$@" || echo "$@"
+}
+
+# use symlink first
+if test -x ./php-cli ; then
+	php_cli=`getAbsolutePath ./php-cli`
+elif test ! -z "$TEST_PHP_EXECUTABLE" && test -x "$TEST_PHP_EXECUTABLE"; then
+	php_cli="$TEST_PHP_EXECUTABLE"
+else
+	php_cli="`which php`"
+fi
+
+if test -x ./php-cgi ; then
+	php_cgi=`getAbsolutePath ./php-cgi`
+else
+	php_cgi="`which php-cgi`"
+fi
+
+TEST_PHP_EXECUTABLE="$php_cli"
+TEST_PHP_CGI_EXECUTABLE="$php_cgi"
+test -z "$TEST_PHP_SRCDIR" && TEST_PHP_SRCDIR=`getAbsolutePath ./php-src`
+
+export TEST_PHP_EXECUTABLE
+export TEST_PHP_CGI_EXECUTABLE
+export TEST_PHP_SRCDIR
+
+echo "XCache test running with:"
+echo "TEST_PHP_CGI_EXECUTABLE: $TEST_PHP_CGI_EXECUTABLE"
+echo "TEST_PHP_EXECUTABLE:     $TEST_PHP_EXECUTABLE"
+echo "TEST_PHP_SRCDIR:         $TEST_PHP_SRCDIR"
+
+run_tests_php=$TEST_PHP_SRCDIR/run-tests.php
+exec "$php_cli" -d "open_basedir=" -d "safe_mode=0" -d "output_buffering=0" -d "memory_limit=-1" $run_tests_php "$@"
Index: /tags/3.0.0-rc1/README
===================================================================
--- /tags/3.0.0-rc1/README	(revision 1003)
+++ /tags/3.0.0-rc1/README	(revision 1003)
@@ -0,0 +1,5 @@
+XCache is a fast, stable PHP opcode cacher that has been tested and is now running on production servers under high load.
+It is tested (on linux) and supported on all of the latest version of PHP popular release branches.
+ThreadSafe/Windows is also perfectly supported.
+
+Please check http://xcache.lighttpd.net/ and https://groups.google.com/group/xcache for help
Index: /tags/3.0.0-rc1/.vimrc
===================================================================
--- /tags/3.0.0-rc1/.vimrc	(revision 605)
+++ /tags/3.0.0-rc1/.vimrc	(revision 605)
@@ -0,0 +1,3 @@
+set noexpandtab
+au FileType m4 setlocal ts=2 sw=2 fdm=marker noexpandtab
+au FileType c setlocal ts=4 sw=4 fdm=marker noexpandtab
Index: /tags/3.0.0-rc1/xcache.ini
===================================================================
--- /tags/3.0.0-rc1/xcache.ini	(revision 1147)
+++ /tags/3.0.0-rc1/xcache.ini	(revision 1147)
@@ -0,0 +1,82 @@
+;; this is an example, it won't work unless properly configured into php.ini
+[xcache-common]
+;; non-Windows example:
+extension = xcache.so
+;; Windows example:
+; extension = php_xcache.dll
+
+[xcache.admin]
+xcache.admin.enable_auth = On
+xcache.admin.user = "mOo"
+; set xcache.admin.pass = md5($your_password)
+; login use $your_password
+xcache.admin.pass = ""
+
+[xcache]
+; ini only settings, all the values here is default unless explained
+
+; select low level shm/allocator scheme implemenation
+xcache.shm_scheme =        "mmap"
+; to disable: xcache.size=0
+; to enable : xcache.size=64M etc (any size > 0) and your system mmap allows
+xcache.size  =               60M
+; 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
+; ttl of the cache item, 0=forever
+xcache.ttl   =                 0
+; interval of gc scanning expired items, 0=no scan, other values is in seconds
+xcache.gc_interval =           0
+
+; same as aboves but for variable cache
+xcache.var_size  =            4M
+xcache.var_count =             1
+xcache.var_slots =            8K
+; default value for $ttl parameter of xcache_*() functions
+xcache.var_ttl   =             0
+; hard limit ttl that cannot be exceed by xcache_*() functions. 0=unlimited
+xcache.var_maxttl   =          0
+xcache.var_gc_interval =     300
+
+; mode:0, const string specified by xcache.var_namespace
+; mode:1, $_SERVER[xcache.var_namespace]
+; mode:2, uid or gid (specified by xcache.var_namespace)
+xcache.var_namespace_mode =    0
+xcache.var_namespace =        ""
+
+; N/A for /dev/zero
+xcache.readonly_protection = Off
+; for *nix, xcache.mmap_path is a file path, not directory. (auto create/overwrite)
+; Use something like "/tmp/xcache" instead of "/dev/*" if you want to turn on ReadonlyProtection
+; different process group of php won't share the same /tmp/xcache
+; for win32, xcache.mmap_path=anonymous map name, not file path
+xcache.mmap_path =    "/dev/zero"
+
+
+; leave it blank(disabled) or "/tmp/phpcore/"
+; make sure it's writable by php (open_basedir is not checked)
+xcache.coredump_directory =   ""
+; disable cache after crash
+xcache.disable_on_crash =    Off
+
+; enable experimental documented features for each release if available
+xcache.experimental =        Off
+
+; per request settings. can ini_set, .htaccess etc
+xcache.cacher =               On
+xcache.stat   =               On
+xcache.optimizer =           Off
+
+[xcache.coverager]
+; enabling this feature will impact performance
+; enabled only if xcache.coverager == On && xcache.coveragedump_directory == "non-empty-value"
+
+; per request settings. can ini_set, .htaccess etc
+; enable coverage data collecting and xcache_coverager_start/stop/get/clean() functions
+xcache.coverager =           Off
+xcache.coverager_autostart =  On
+
+; set in php ini file only
+; make sure it's readable (open_basedir is checked) by coverage viewer script
+xcache.coveragedump_directory = ""
Index: /tags/3.0.0-rc1/gen_structinfo.awk
===================================================================
--- /tags/3.0.0-rc1/gen_structinfo.awk	(revision 982)
+++ /tags/3.0.0-rc1/gen_structinfo.awk	(revision 982)
@@ -0,0 +1,212 @@
+#! /usr/bin/awk -f
+# vim:ts=4:sw=4
+BEGIN {
+	brace = 0;
+	incomment = 0;
+	buffer_len = 0;
+}
+function printstruct(structname) {
+	printf "define(`ELEMENTSOF_%s', `%s')\n", structname, ELEMENTSOF[structname];
+	printf "define(`COUNTOF_%s', `%s')\n", structname, COUNTOF[structname];
+	printf "define(`SIZEOF_%s', `(  %s  )')\n", structname, SIZEOF[structname];
+}
+function countBrace(text,  len, i, char, braceCount) {
+	len = length(text);
+	braceCount = 0;
+	for (i = 1; i <= len; ++i) {
+		char = substr(text, i, 1);
+		if (char == "{") {
+			braceCount = braceCount + 1;
+		}
+		else if (char == "}") {
+			braceCount = braceCount - 1;
+		}
+	}
+	return braceCount;
+}
+
+# multiline comment handling
+{
+	# removes one line comment
+	gsub(/\/\*(.+?)\*\//, " ");
+}
+/\*\// {
+	if (incomment) {
+		sub(/.*\*\//, "");
+		incomment = 0;
+	}
+}
+incomment {
+	next;
+}
+/\/\*/ {
+	sub(/\/\*.*/, "");
+	incomment = 1;
+	# fall through
+}
+
+# skip file/line mark here to be faster
+/^#/ {
+	next;
+}
+
+/^}.*;/ {
+	if (instruct) {
+		sub(";", "");
+		structname = instruct;
+		if (structname == 1 && $2) {
+			structname = $2;
+		}
+		if (structname in typedefs) {
+			structname = typedefs[structname];
+		}
+		sizeinfo = "";
+		elms = "";
+		for (i = 0; i in buffer; i ++) {
+			if (i) {
+				sizeinfo = sizeinfo " + ";
+			}
+			sizeinfo = sizeinfo "sizeof(((" structname "*)NULL)->" buffer[i] ")";
+
+			if (i == 0) {
+				elms = "\"" buffer[i] "\"";
+			}
+			else {
+				elms = elms "," "\"" buffer[i] "\"";
+			}
+		}
+		ELEMENTSOF[structname] = elms;
+		COUNTOF[structname]    = i;
+		SIZEOF[structname]     = sizeinfo;
+		printstruct(structname);
+		print "\n";
+		for (i in buffer) {
+			delete buffer[i];
+		}
+		buffer_len = 0;
+		instruct = 0;
+	}
+	next;
+}
+
+/.[{}]/ {
+	brace += countBrace($0);
+}
+
+{
+	if (brace == 1 && instruct) {
+		gsub(/(^[\t ]+|[\t ]+$)/, ""); # trim whitespaces
+		sub(/.*[{}]/, "");
+		gsub(/\[[^\]]+\]/, ""); # ignore [...]
+		gsub(/:[0-9]+/, ""); # ignore struct bit
+		if (match($0, /^[^(]*\([ ]*\*([^)]+)\)/)) {
+			sub(/ +/, "")
+			sub(/^[^(]*\(\*/, "");
+			sub(/\).*/, "");
+			# function pointer
+			buffer[buffer_len] = $0;
+			buffer_len ++;
+		}
+		else {
+			# process normal variables
+
+			# ignore any ()s
+			while (gsub(/(\([^)]*\))/, "")) {
+			}
+			if (match($0, /[()]/)) {
+				next;
+			}
+			# unsigned int *a,  b; int c;
+			gsub(/[*]/, " ");
+			# unsigned int a,  b; int c;
+			gsub(/ +/, " ");
+			# unsigned int a, b; int c;
+			gsub(/ *[,;]/, ";");
+			# unsigned int a; b; int c;
+			if (!match($0, /;/)) {
+				next;
+			}
+			# print "=DEBUG=" $0 "==";
+			split($0, chunks, ";");
+			# [unsigned int a, b, c]
+
+			for (i = 1; i in chunks; i ++) {
+				if (chunks[i] == "") {
+					delete chunks[i];
+					continue;
+				}
+				split(chunks[i], pieces, " ");
+				# [unsigned, int, a]
+				# [b]
+				# [c]
+
+				last_piece = "";
+				for (j = 1; j in pieces; j ++) {
+					last_piece = pieces[j];
+					delete pieces[j];
+				}
+				if (last_piece == "") {
+					# print "=ERROR=" chunks[i] "==";
+					delete chunks[i];
+					continue;
+				}
+				# a
+				# b
+				# c
+
+				buffer[buffer_len] = last_piece;
+				buffer_len ++;
+				delete chunks[i]
+			}
+			last_piece = "";
+		}
+		next;
+	}
+}
+
+/^typedef struct [^{]*;/ {
+	sub(";", "");
+	typename=$3;
+	newtypename=$4;
+	typedefs[typename] = newtypename;
+	if (ELEMENTSOF[typename]) {
+		ELEMENTSOF[newtypename] = ELEMENTSOF[typename];
+		COUNTOF[newtypename]    = COUNTOF[typename];
+		sub(/.*/, SIZEOF[typename]);
+		gsub(typename, newtypename);
+		SIZEOF[newtypename]     = $0;
+		printstruct(newtypename);
+	}
+	next;
+}
+/^typedef struct .*\{[^}]*$/ {
+	brace = countBrace($0);
+	if (brace > 0) {
+		instruct = 1;
+	}
+	else {
+		brace = 0;
+		instruct = 0;
+	}
+
+	for (i in buffer) {
+		delete buffer[i];
+	}
+	next;
+}
+
+/^struct .*\{.*/ {
+	brace = countBrace($0);
+	if (brace > 0) {
+		instruct = $2;
+	}
+	else {
+		brace = 0;
+		instruct = 0;
+	}
+
+	for (i in buffer) {
+		delete buffer[i];
+	}
+	next;
+}
Index: /tags/3.0.0-rc1/mod_disassembler/sample.php
===================================================================
--- /tags/3.0.0-rc1/mod_disassembler/sample.php	(revision 1010)
+++ /tags/3.0.0-rc1/mod_disassembler/sample.php	(revision 1010)
@@ -0,0 +1,468 @@
+<?php
+
+//* >= PHP 5.3
+namespace ns;
+// */
+
+abstract class ClassName
+{
+	const CONST_VALUE = 'A constant value';
+
+	/** doc */
+	static public $static = array(
+		array('array'),
+		'str'
+		);
+	/** doc */
+	static public $public_static = array(2, 'str');
+	/** doc */
+	static private $private_static = array(2, 'str');
+	/** doc */
+	static protected $protected_static = array(2, 'str');
+	/** doc */
+	public $property = array(
+		array('array'),
+		'str'
+		);
+	/** doc */
+	public $public_property = array(2, 'str');
+	/** doc */
+	private $private_property = array(2, 'str');
+	/** doc */
+	protected $protected_property = array(2, 'str');
+
+	/** doc */
+	public function __construct($a, $b)
+	{
+		echo CONST_VALUE;
+		echo ClassName::CONST_VALUE;
+		unset(ClassName::$classProp);
+		unset($obj->objProp);
+		unset($this->thisProp);
+		unset($array['index']->valueProp);
+		unset($obj->array['index']);
+		unset($this->array['index']);
+		$obj->objProp = 1;
+		$this->thisProp = 1;
+		$array['index']->valueProp = 1;
+		$array['index'] = 1;
+		$array[1] = 1;
+	}
+
+	/** doc */
+	abstract public function abastractMethod();
+
+	/** doc */
+	public function method(array $a = NULL, $b = NULL)
+	{
+	}
+
+	/** doc */
+	public function publicMethod(ClassName $a = NULL, $b = 2)
+	{
+	}
+
+	/** doc */
+	protected function protectedMethod(ClassName $a, $b = array(
+			array('array')
+			))
+	{
+		$runtimeArray = array('1');
+		$runtimeArray2 = array(
+			'1',
+			array()
+			);
+		$runtimeArray3 = array(
+			'a' => '1',
+			2   => array()
+			);
+		return 'protected';
+	}
+
+	/** doc */
+	private function privateMethod(ClassName $a, $b = NULL)
+	{
+		return 'private';
+	}
+}
+
+interface IInterface
+{
+	public function nothing();
+}
+
+function f1($f)
+{
+	echo __FUNCTION__;
+	echo $f;
+}
+
+final class Child extends ClassName implements IInterface
+{
+	public function __construct()
+	{
+		parent::__construct();
+		ClassName::__construct();
+		echo __CLASS__;
+		echo __METHOD__;
+		throw new Exception();
+		$this->methodCall();
+	}
+
+	public function __destruct()
+	{
+		parent::__destruct();
+		functionCall();
+	}
+
+	static public function __callStatic($name, $args)
+	{
+	}
+
+	public function __toString()
+	{
+	}
+
+	public function __set($name, $value)
+	{
+	}
+
+	public function __get($name)
+	{
+	}
+
+	public function __isset($name)
+	{
+	}
+
+	public function __unset($name)
+	{
+	}
+
+	public function __sleep()
+	{
+	}
+
+	public function __wakeup()
+	{
+	}
+
+	public function __clone()
+	{
+		return array();
+	}
+}
+
+if ($late) {
+	class LateBindingClass
+	{
+		public function __construct()
+		{
+		}
+	}
+
+	function lateBindingFunction($arg)
+	{
+		echo 'lateFunction';
+	}
+}
+
+echo "\r\n";
+echo "\r";
+echo "\n";
+echo str_replace(array('a' => 'a', 'b' => 'c'), 'b');
+$object = new ClassName();
+$object = new $className();
+$result = $object instanceof ClassName;
+$cloned = clone $object;
+$a = 1;
+$a = $b + $c;
+$a = $b + 1;
+$a = 1 + $b;
+$a = $b - $c;
+$a = $b * $c;
+$a = $b / $c;
+$a = $b % $c;
+$a = $b . $c;
+$a = $b = $c;
+$a = $b & $c;
+$a = $b | $c;
+$a = $b ^ $c;
+$a = ~$b;
+$a = -$b;
+$a = +$b;
+$a = $b >> $c;
+$a = $b >> $c;
+$a = $b == $c;
+$a = $b === $c;
+$a = $b != $c;
+$a = $b < $c;
+$a = $b <= $c;
+$a = $b <= $c;
+$a = $b++;
+$a = ++$b;
+$a = $obj->b++;
+$a = ++$obj->b;
+$a = $b--;
+$a = --$b;
+$a = $obj->b--;
+$a = --$obj->b;
+$a = !$b;
+$a = $b === $c;
+$a = $b !== $c;
+$a = $b << 2;
+$a = $b >> 3;
+$a += $b;
+$a -= $b;
+$a *= $b;
+$a /= $b;
+$a <<= $b;
+$a >>= $b;
+$a &= $b;
+$a |= $b;
+$a .= $b;
+$a %= $b;
+$a ^= $b;
+$a = 'a' . 'b';
+$a = 'a' . 'abc';
+@f1();
+print('1');
+ref(&$a);
+$a = $array['index'];
+$a = $object->prop;
+$a = $this->prop;
+$array['index'] = 1;
+$object->prop = 1;
+$this->prop = 1;
+$a = isset($b);
+$a = empty($b);
+$a = isset($array['index']);
+$a = empty($array['index']);
+$a = isset($object->prop);
+$a = empty($object->prop);
+$a = isset($this->prop);
+$a = empty($this->prop);
+$a = (int) $b;
+$a = (double) $b;
+$a = (string) $b;
+$a = (array) $b;
+$a = (object) $b;
+$a = (bool) $b;
+$a = (unset) $b;
+$a = (array) $b;
+$a = (object) $b;
+// PHP6+ $a = (scalar) $b;
+$a = ($b ? $c : $d);
+$a = (f1() ? f2() : f3());
+($a = $b) xor $c;
+($a = $b) and $c;
+($a = $b) or $c;
+$a = $b && $c;
+$a = $b || $c;
+
+do {
+	try {
+		echo 'outer try 1';
+
+		try {
+			echo 'inner try';
+		}
+		catch (InnerException $e) {
+			echo $e;
+		}
+
+		echo 'outer try 2';
+	}
+	catch (OuterException $e) {
+		echo $e;
+	}
+} while (0);
+
+if (if_()) {
+	echo 'if';
+
+	if (innerIf_()) {
+		echo 'if innerIf';
+	}
+}
+else if (elseif_()) {
+	echo 'else if';
+
+	if (innerIf_()) {
+		echo 'if innerIf';
+	}
+}
+else {
+	if (innerIf_()) {
+		echo 'if innerIf';
+	}
+
+	echo 'else';
+}
+
+while (false) {
+	echo 'while';
+}
+
+do {
+	echo 'do/while';
+} while (false);
+
+$i = 1;
+
+for (; $i < 10; ++$i) {
+	echo $i;
+	break;
+}
+
+foreach ($array as $key => $value) {
+	foreach ($value as $key => $value) {
+		echo $key . ' = ' . $value . "\n";
+		break 2;
+		continue;
+	}
+}
+
+switch ($normalSwitch) {
+case 'case1':
+	echo 'case1';
+
+	switch ($nestedSwitch) {
+	case 1:
+	}
+
+	break;
+
+case 'case2':
+	echo 'case2';
+	break;
+
+default:
+	switch ($nestedSwitch) {
+	case 1:
+	}
+
+	echo 'default';
+	break;
+}
+
+switch ($switchWithoutDefault) {
+case 'case1':
+	echo 'case1';
+	break;
+
+case 'case2':
+	echo 'case2';
+	break;
+}
+
+switch ($switchWithMiddleDefault) {
+case 'case1':
+	echo 'case1';
+	break;
+
+default:
+	echo 'default';
+	break;
+
+case 'case2':
+	echo 'case2';
+	break;
+}
+
+switch ($switchWithInitialDefault) {
+default:
+	echo 'default';
+	break;
+
+case 'case1':
+	echo 'case1';
+	break;
+
+case 'case2':
+	echo 'case2';
+	break;
+}
+
+switch (emptySwitch()) {
+}
+
+switch (emptySwitch()) {
+default:
+}
+
+declare (ticks=1) {
+	echo 1;
+	while (1) {
+		echo 2;
+	}
+}
+
+require 'require.php';
+require_once 'require_once.php';
+include 'include.php';
+include_once 'include_once.php';
+echo __FILE__;
+echo __LINE__;
+
+//*
+echo 'PHP 5.3+ code testing';
+const CONST_VALUE = 1;
+echo $this::CONST_VALUE;
+echo $a::CONST_VALUE;
+echo CONST_VALUE;
+$this::__construct();
+$obj::__construct();
+$a = $b ?: $d;
+$a = ($b ?: $d) + $c;
+$a = f1() ?: f2();
+$a = ($b ? $c : $d);
+$a = ($b ? $c : $d) + $c;
+$a = (f1() ? f3() : f2());
+
+if ($b ?: $d) {
+	echo 'if ($b ?: $d)';
+}
+
+if (($b ?: $d) + $c) {
+	echo 'if (($b ?: $d) + $c)';
+}
+
+if (f1() ?: f2()) {
+	echo 'if (f1() ?: f2())';
+}
+
+echo 'goto a';
+goto a;
+
+$i = 1;
+
+for (; $i <= 2; ++$i) {
+	goto a;
+}
+
+a:
+echo 'label a';
+echo preg_replace_callback('~-([a-z])~', function($match) {
+	return strtoupper($match[1]);
+}, 'hello-world');
+$greet = function($name) {
+	printf("Hello %s\r\n", $name);
+};
+$greet('World');
+$greet('PHP');
+$total = 0;
+$tax = 1;
+$callback = function($quantity, $product) use($tax, &$total) {
+	$tax = 'tax';
+	static $static1 = array(1);
+	static $static2;
+	$tax = 'tax';
+	$tax = --$tax;
+	$pricePerItem = constant('PRICE_' . strtoupper($product));
+	$total += $pricePerItem * $quantity * ($tax + 1);
+};
+// */
+exit();
+
+?>
Index: /tags/3.0.0-rc1/mod_disassembler/xc_disassembler.c
===================================================================
--- /tags/3.0.0-rc1/mod_disassembler/xc_disassembler.c	(revision 1043)
+++ /tags/3.0.0-rc1/mod_disassembler/xc_disassembler.c	(revision 1043)
@@ -0,0 +1,266 @@
+#include "xc_disassembler.h"
+#include "xcache.h"
+#include "xcache/xc_ini.h"
+#include "xcache/xc_utils.h"
+#include "xcache/xc_sandbox.h"
+#include "xcache/xc_compatibility.h"
+#include "xc_processor.h"
+
+#include "ext/standard/info.h"
+
+static void xc_dasm(zval *output, zend_op_array *op_array TSRMLS_DC) /* {{{ */
+{
+	const Bucket *b;
+	zval *zv, *list;
+	xc_compile_result_t cr;
+	int bufsize = 2;
+	char *buf;
+	xc_dasm_t dasm;
+
+	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(output);
+
+	ALLOC_INIT_ZVAL(zv);
+	array_init(zv);
+	xc_dasm_zend_op_array(&dasm, zv, op_array TSRMLS_CC);
+	add_assoc_zval_ex(output, ZEND_STRS("op_array"), zv);
+
+	buf = emalloc(bufsize);
+
+	ALLOC_INIT_ZVAL(list);
+	array_init(list);
+	for (b = xc_sandbox_user_function_begin(TSRMLS_C); b; b = b->pListNext) {
+		int keysize, keyLength;
+
+		ALLOC_INIT_ZVAL(zv);
+		array_init(zv);
+		xc_dasm_zend_function(&dasm, zv, 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_S(b), keysize);
+		buf[keysize - 2] = buf[keysize - 1] = ""[0];
+		keyLength = b->nKeyLength;
+#ifdef IS_UNICODE
+		if (BUCKET_KEY_TYPE(b) == IS_UNICODE) {
+			if (buf[0] == ""[0] && buf[1] == ""[0]) {
+				keyLength ++;
+			}
+		} else
+#endif
+		{
+			if (buf[0] == ""[0]) {
+				keyLength ++;
+			}
+		}
+
+		add_u_assoc_zval_ex(list, BUCKET_KEY_TYPE(b), ZSTR(buf), keyLength, zv);
+	}
+	add_assoc_zval_ex(output, ZEND_STRS("function_table"), list);
+	
+	ALLOC_INIT_ZVAL(list);
+	array_init(list);
+	for (b = xc_sandbox_user_class_begin(TSRMLS_C); b; b = b->pListNext) {
+		int keysize, keyLength;
+
+		ALLOC_INIT_ZVAL(zv);
+		array_init(zv);
+		xc_dasm_zend_class_entry(&dasm, 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_S(b), keysize);
+		buf[keysize - 2] = buf[keysize - 1] = ""[0];
+		keyLength = b->nKeyLength;
+#ifdef IS_UNICODE
+		if (BUCKET_KEY_TYPE(b) == IS_UNICODE) {
+			if (buf[0] == ""[0] && buf[1] == ""[0]) {
+				keyLength ++;
+			}
+		} else
+#endif
+		{
+			if (buf[0] == ""[0]) {
+				keyLength ++;
+			}
+		}
+		add_u_assoc_zval_ex(list, BUCKET_KEY_TYPE(b), ZSTR(buf), keyLength, zv);
+	}
+	efree(buf);
+	add_assoc_zval_ex(output, ZEND_STRS("class_table"), list);
+
+	/*xc_apply_op_array(&cr, (apply_func_t) xc_redo_pass_two TSRMLS_CC);*/
+	xc_compile_result_free(&cr);
+}
+/* }}} */
+typedef struct xc_dasm_sandboxed_t { /* {{{ */
+	enum Type {
+		xc_dasm_file_t
+		, xc_dasm_string_t
+	} type;
+	union {
+		zval *zfilename;
+		struct {
+			zval *source;
+			char *eval_name;
+		} compile_string;
+	} input;
+
+	zval *output;
+} xc_dasm_sandboxed_t; /* }}} */
+zend_op_array *xc_dasm_sandboxed(void *data TSRMLS_DC) /* {{{ */
+{
+	zend_bool catched = 0;
+	zend_op_array *op_array = NULL;
+	xc_dasm_sandboxed_t *sandboxed_dasm = (xc_dasm_sandboxed_t *) data;
+
+	zend_try {
+		if (sandboxed_dasm->type == xc_dasm_file_t) {
+			op_array = compile_filename(ZEND_REQUIRE, sandboxed_dasm->input.zfilename TSRMLS_CC);
+		}
+		else {
+			op_array = compile_string(sandboxed_dasm->input.compile_string.source, sandboxed_dasm->input.compile_string.eval_name TSRMLS_CC);
+		}
+	} zend_catch {
+		catched = 1;
+	} zend_end_try();
+
+	if (catched || !op_array) {
+#define return_value sandboxed_dasm->output
+		RETVAL_FALSE;
+#undef return_value
+		return NULL;
+	}
+
+	xc_dasm(sandboxed_dasm->output, op_array TSRMLS_CC);
+
+	/* free */
+#ifdef ZEND_ENGINE_2
+	destroy_op_array(op_array TSRMLS_CC);
+#else
+	destroy_op_array(op_array);
+#endif
+	efree(op_array);
+
+	return NULL;
+} /* }}} */
+void xc_dasm_string(zval *output, zval *source TSRMLS_DC) /* {{{ */
+{
+	xc_dasm_sandboxed_t sandboxed_dasm;
+	char *eval_name = zend_make_compiled_string_description("runtime-created function" TSRMLS_CC);
+
+	sandboxed_dasm.output = output;
+	sandboxed_dasm.type = xc_dasm_string_t;
+	sandboxed_dasm.input.compile_string.source = source;
+	sandboxed_dasm.input.compile_string.eval_name = eval_name;
+	xc_sandbox(&xc_dasm_sandboxed, (void *) &sandboxed_dasm, eval_name TSRMLS_CC);
+	efree(eval_name);
+}
+/* }}} */
+void xc_dasm_file(zval *output, const char *filename TSRMLS_DC) /* {{{ */
+{
+	zval *zfilename;
+	xc_dasm_sandboxed_t sandboxed_dasm;
+
+	MAKE_STD_ZVAL(zfilename);
+	zfilename->value.str.val = estrdup(filename);
+	zfilename->value.str.len = strlen(filename);
+	zfilename->type = IS_STRING;
+
+	sandboxed_dasm.output = output;
+	sandboxed_dasm.type = xc_dasm_file_t;
+	sandboxed_dasm.input.zfilename = zfilename;
+	xc_sandbox(&xc_dasm_sandboxed, (void *) &sandboxed_dasm, zfilename->value.str.val TSRMLS_CC);
+
+	zval_dtor(zfilename);
+	FREE_ZVAL(zfilename);
+}
+/* }}} */
+
+/* {{{ proto array xcache_dasm_file(string filename)
+   Disassemble file into opcode array by filename */
+PHP_FUNCTION(xcache_dasm_file)
+{
+	char *filename;
+	int 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);
+}
+/* }}} */
+
+/* {{{ PHP_MINFO_FUNCTION(xcache_disassembler) */
+static PHP_MINFO_FUNCTION(xcache_disassembler)
+{
+	php_info_print_table_start();
+	php_info_print_table_row(2, "XCache Disassembler Module", "enabled");
+	php_info_print_table_end();
+
+	DISPLAY_INI_ENTRIES();
+}
+/* }}} */
+static zend_function_entry xcache_disassembler_functions[] = /* {{{ */
+{
+	PHP_FE(xcache_dasm_file,         NULL)
+	PHP_FE(xcache_dasm_string,       NULL)
+	PHP_FE_END
+};
+/* }}} */
+static zend_module_entry xcache_disassembler_module_entry = { /* {{{ */
+	STANDARD_MODULE_HEADER,
+	XCACHE_NAME " Disassembler",
+	xcache_disassembler_functions,
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+	PHP_MINFO(xcache_disassembler),
+	XCACHE_VERSION,
+#ifdef PHP_GINIT
+	NO_MODULE_GLOBALS,
+#endif
+#ifdef ZEND_ENGINE_2
+	NULL,
+#else
+	NULL,
+	NULL,
+#endif
+	STANDARD_MODULE_PROPERTIES_EX
+};
+/* }}} */
+int xc_disassembler_startup_module() /* {{{ */
+{
+	return zend_startup_module(&xcache_disassembler_module_entry);
+}
+/* }}} */
Index: /tags/3.0.0-rc1/mod_disassembler/xc_disassembler.h
===================================================================
--- /tags/3.0.0-rc1/mod_disassembler/xc_disassembler.h	(revision 1044)
+++ /tags/3.0.0-rc1/mod_disassembler/xc_disassembler.h	(revision 1044)
@@ -0,0 +1,10 @@
+#ifndef XC_DISASSEMBLER_H_1547840703D7ADD9C19041818BE9E3C7
+#define XC_DISASSEMBLER_H_1547840703D7ADD9C19041818BE9E3C7
+
+#if _MSC_VER > 1000
+#pragma once
+#endif /* _MSC_VER > 1000 */
+
+int xc_disassembler_startup_module();
+
+#endif /* XC_DISASSEMBLER_H_1547840703D7ADD9C19041818BE9E3C7 */
Index: /tags/3.0.0-rc1/util/README
===================================================================
--- /tags/3.0.0-rc1/util/README	(revision 982)
+++ /tags/3.0.0-rc1/util/README	(revision 982)
@@ -0,0 +1,1 @@
+generic utility stuffs unrelatived to ZendEngine
Index: /tags/3.0.0-rc1/util/xc_trace.h
===================================================================
--- /tags/3.0.0-rc1/util/xc_trace.h	(revision 1044)
+++ /tags/3.0.0-rc1/util/xc_trace.h	(revision 1044)
@@ -0,0 +1,57 @@
+#ifndef XC_TRACE_H_709AE2523EDACB72B54D9CB42DDB0FEE
+#define XC_TRACE_H_709AE2523EDACB72B54D9CB42DDB0FEE
+
+#if _MSC_VER > 1000
+#pragma once
+#endif /* _MSC_VER > 1000 */
+
+#ifdef ZEND_WIN32
+#	ifndef inline
+#		ifdef ZEND_WIN32_FORCE_INLINE
+#			define inline __forceinline
+#		else
+#			define inline
+#		endif
+#	endif
+#endif
+
+#ifdef XCACHE_DEBUG
+#	define IFDEBUG(x) (x)
+int xc_vtrace(const char *fmt, va_list args);
+int xc_trace(const char *fmt, ...) ZEND_ATTRIBUTE_PTR_FORMAT(printf, 1, 2);
+
+#	ifdef ZEND_WIN32
+static inline int TRACE(const char *fmt, ...) 
+{
+	va_list args;
+	int ret;
+
+	va_start(args, fmt);
+	ret = xc_vtrace(fmt, args);
+	va_end(args);
+	return ret;
+}
+#	else
+#		define TRACE(fmt, ...) \
+		xc_trace("%s:%d: " fmt "\r\n", __FILE__, __LINE__, __VA_ARGS__)
+#	endif /* ZEND_WIN32 */
+#   undef NDEBUG
+#   undef inline
+#   define inline
+#else /* XCACHE_DEBUG */
+
+#	ifdef ZEND_WIN32
+static inline int TRACE_DUMMY(const char *fmt, ...)
+{
+	return 0;
+}
+#		define TRACE 1 ? 0 : TRACE_DUMMY
+#	else
+#		define TRACE(fmt, ...) do { } while (0)
+#	endif /* ZEND_WIN32 */
+
+#	define IFDEBUG(x) do { } while (0)
+#endif /* XCACHE_DEBUG */
+#include <assert.h>
+
+#endif /* XC_TRACE_H_709AE2523EDACB72B54D9CB42DDB0FEE */
Index: /tags/3.0.0-rc1/util/xc_stack.c
===================================================================
--- /tags/3.0.0-rc1/util/xc_stack.c	(revision 990)
+++ /tags/3.0.0-rc1/util/xc_stack.c	(revision 990)
@@ -0,0 +1,63 @@
+#include <stdlib.h>
+#include "xc_trace.h"
+#include "xc_stack.h"
+
+typedef xc_stack_t* S;
+
+void xc_stack_init_ex(S stack, int initsize)
+{
+	stack->cnt = 0;
+	stack->size = initsize;
+	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_count(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/3.0.0-rc1/util/xc_vector.h
===================================================================
--- /tags/3.0.0-rc1/util/xc_vector.h	(revision 1044)
+++ /tags/3.0.0-rc1/util/xc_vector.h	(revision 1044)
@@ -0,0 +1,56 @@
+#ifndef XC_VECTOR_H_0957AC4E1A44E838C7B8DBECFF9C4B3B
+#define XC_VECTOR_H_0957AC4E1A44E838C7B8DBECFF9C4B3B
+
+#if _MSC_VER > 1000
+#pragma once
+#endif /* _MSC_VER > 1000 */
+
+typedef struct {
+	zend_uint size;
+	zend_uint cnt;
+	void *data;
+} xc_vector_t;
+
+#define xc_vector_init(type, vector) do { \
+	(vector)->cnt = 0;     \
+	(vector)->size = 0;    \
+	(vector)->data = NULL; \
+} while (0)
+
+#define xc_vector_add(type, vector, value) do { \
+	if ((vector)->cnt == (vector)->size) { \
+		if ((vector)->size) { \
+			(vector)->size <<= 1; \
+			(vector)->data = erealloc((vector)->data, sizeof(type) * (vector)->size); \
+		} \
+		else { \
+			(vector)->size = 8; \
+			(vector)->data = emalloc(sizeof(type) * (vector)->size); \
+		} \
+	} \
+	((type *) (vector)->data)[(vector)->cnt++] = value; \
+} while (0)
+
+static inline void *xc_vector_detach_impl(xc_vector_t *vector)
+{
+	void *data = vector->data;
+	vector->data = NULL;
+	vector->size = 0;
+	vector->cnt = 0;
+	return data;
+}
+
+#define xc_vector_detach(type, vector) ((type *) xc_vector_detach_impl(vector))
+
+static inline void xc_vector_free_impl(xc_vector_t *vector TSRMLS_DC)
+{
+	if (vector->data) {
+		efree(vector->data);
+	}
+	vector->size = 0;
+	vector->cnt = 0;
+}
+
+#define xc_vector_free(type, vector) xc_vector_free_impl(vector TSRMLS_CC)
+
+#endif /* XC_VECTOR_H_0957AC4E1A44E838C7B8DBECFF9C4B3B */
Index: /tags/3.0.0-rc1/util/xc_foreachcoresig.h
===================================================================
--- /tags/3.0.0-rc1/util/xc_foreachcoresig.h	(revision 982)
+++ /tags/3.0.0-rc1/util/xc_foreachcoresig.h	(revision 982)
@@ -0,0 +1,50 @@
+/* all signals generate coredump by default is list here */
+
+#ifdef SIGABRT
+FOREACH_SIG(SIGABRT);
+#endif
+
+#ifdef SIGBUS
+FOREACH_SIG(SIGBUS);
+#endif
+
+#ifdef SIGEMT
+FOREACH_SIG(SIGEMT);
+#endif
+
+#ifdef SIGFPE
+FOREACH_SIG(SIGFPE);
+#endif
+
+#ifdef SIGILL
+FOREACH_SIG(SIGILL);
+#endif
+
+#ifdef SIGIOT
+FOREACH_SIG(SIGIOT);
+#endif
+
+#ifdef SIGQUIT
+FOREACH_SIG(SIGQUIT);
+#endif
+
+#ifdef SIGSEGV
+FOREACH_SIG(SIGSEGV);
+#endif
+
+#ifdef SIGSYS
+FOREACH_SIG(SIGSYS);
+#endif
+
+#ifdef SIGTRAP
+FOREACH_SIG(SIGTRAP);
+#endif
+
+#ifdef SIGXCPU
+FOREACH_SIG(SIGXCPU);
+#endif
+
+#ifdef SIGXFSZ
+FOREACH_SIG(SIGXFSZ);
+#endif
+
Index: /tags/3.0.0-rc1/util/xc_stack.h
===================================================================
--- /tags/3.0.0-rc1/util/xc_stack.h	(revision 982)
+++ /tags/3.0.0-rc1/util/xc_stack.h	(revision 982)
@@ -0,0 +1,22 @@
+#ifndef __XC_UTIL_STACK
+#define __XC_UTIL_STACK
+
+typedef struct {
+	void **data;
+	int cnt;
+	int size;
+} xc_stack_t;
+
+#define S xc_stack_t*
+void xc_stack_init_ex(S stack, int initsize);
+#define xc_stack_init(stack) xc_stack_init_ex(stack, 8)
+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_count(S stack);
+void xc_stack_reverse(S stack);
+#undef S
+
+#endif /* __XC_UTIL_STACK */
Index: /tags/3.0.0-rc1/util/xc_trace.c
===================================================================
--- /tags/3.0.0-rc1/util/xc_trace.c	(revision 990)
+++ /tags/3.0.0-rc1/util/xc_trace.c	(revision 990)
@@ -0,0 +1,21 @@
+#include "xc_trace.h"
+#include <stdio.h>
+#include <stdarg.h>
+
+int xc_vtrace(const char *fmt, va_list args) /* {{{ */
+{
+	return vfprintf(stderr, fmt, args);
+}
+/* }}} */
+int xc_trace(const char *fmt, ...) /* {{{ */
+{
+	va_list args;
+	int ret;
+
+	va_start(args, fmt);
+	ret = xc_vtrace(fmt, args);
+	va_end(args);
+	return ret;
+}
+/* }}} */
+
Index: /tags/3.0.0-rc1/util/xc_align.h
===================================================================
--- /tags/3.0.0-rc1/util/xc_align.h	(revision 982)
+++ /tags/3.0.0-rc1/util/xc_align.h	(revision 982)
@@ -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/3.0.0-rc1/mod_encoder/xc_encoder.c
===================================================================
--- /tags/3.0.0-rc1/mod_encoder/xc_encoder.c	(revision 1113)
+++ /tags/3.0.0-rc1/mod_encoder/xc_encoder.c	(revision 1113)
@@ -0,0 +1,1 @@
+static void dummy() { }
Index: /tags/3.0.0-rc1/processor/string.m4
===================================================================
--- /tags/3.0.0-rc1/processor/string.m4	(revision 860)
+++ /tags/3.0.0-rc1/processor/string.m4	(revision 860)
@@ -0,0 +1,124 @@
+
+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(`PTRTYPE', ifelse(
+			STRTYPE, `char',      `char',
+			STRTYPE, `zstr_char', `char',
+			`',      `',          `UChar'))
+	pushdef(`ISTYPE', ifelse(PTRTYPE,`UChar',IS_UNICODE,IS_STRING))
+	pushdef(`UNI_STRLEN', ifelse(
+			STRTYPE, `zstr_uchar', `xc_zstrlen_uchar',
+			STRTYPE, `zstr_char',  `xc_zstrlen_char',
+			`',      `',           `strlen'))
+	pushdef(`SRCSTR', ifelse(STRTYPE,`char',`ZSTR($2)',STRTYPE,`UChar',`ZSTR($2)',`$2'))
+	pushdef(`SRCPTR', ifelse(
+			STRTYPE, `zstr_uchar', `ZSTR_U($2)',
+			STRTYPE, `zstr_char',  `ZSTR_S($2)',
+			`',      `',           `$2'))
+	pushdef(`DSTPTR', ifelse(
+			STRTYPE, `zstr_uchar', `ZSTR_U($1)',
+			STRTYPE, `zstr_char',  `ZSTR_S($1)',
+			`',      `',           `$1'))
+	pushdef(`STRDUP', ifelse(
+			PTRTYPE, `char',  `estrndup',
+			PTRTYPE, `UChar', `eustrndup'))
+	if (SRCPTR == NULL) {
+		IFNOTMEMCPY(`IFCOPY(`
+			DSTPTR = NULL;
+		')')
+		IFDASM(`
+			add_assoc_null_ex(dst, ZEND_STRS("$4"));
+		')
+	}
+	else {
+		IFDPRINT(`INDENT()
+			ifelse(STRTYPE, `zstr_uchar', `
+#ifdef IS_UNICODE
+			do {
+				zval zv;
+				zval reszv;
+				int usecopy;
+
+				INIT_ZVAL(zv);
+				ZVAL_UNICODEL(&zv, ZSTR_U($2), $3 - 1, 1);
+				zend_make_printable_zval(&zv, &reszv, &usecopy);
+				fprintf(stderr, "string:%s:\t\"", "$1");
+				xc_dprint_str_len(Z_STRVAL(reszv), Z_STRLEN(reszv));
+				fprintf(stderr, "\" len=%lu\n", (unsigned long) $3 - 1);
+				if (usecopy) {
+					zval_dtor(&reszv);
+				}
+				zval_dtor(&zv);
+			} while (0);
+#endif
+			', `
+			fprintf(stderr, "string:%s:\t\"", "$1");
+			xc_dprint_str_len(SRCPTR, $3 - 1);
+			fprintf(stderr, "\" len=%lu\n", (unsigned long) $3 - 1);
+			')
+		')
+		IFCALC(`xc_calc_string_n(processor, ISTYPE, SRCSTR, $3 C_RELAYLINE);')
+		IFSTORE(`DSTPTR = ifdef(`REALPTRTYPE', `(REALPTRTYPE() *)') ifelse(PTRTYPE,`char',`ZSTR_S',`ZSTR_U')(xc_store_string_n(processor, ISTYPE, SRCSTR, $3 C_RELAYLINE));')
+		IFRESTORE(`
+			DSTPTR = ifdef(`REALPTRTYPE', `(REALPTRTYPE() *)') STRDUP() (SRCPTR, ($3) - 1);
+		')
+		FIXPOINTER_EX(ifdef(`REALPTRTYPE', `REALPTRTYPE()', `PTRTYPE'), DSTPTR)
+		IFDASM(`
+			ifelse(STRTYPE,zstr_uchar, `
+				add_assoc_unicodel_ex(dst, ZEND_STRS("$4"), ZSTR_U($2), $3-1, 1);
+				', ` dnl else
+				ifelse(STRTYPE,zstr_char, `
+					add_assoc_stringl_ex(dst, ZEND_STRS("$4"), (char *) ZSTR_S($2), $3-1, 1);
+					', `
+					add_assoc_stringl_ex(dst, ZEND_STRS("$4"), (char *) $2, $3-1, 1);
+				')
+			')
+		')
+	}
+	popdef(`STRDUP')
+	popdef(`DSTPTR')
+	popdef(`SRCPTR')
+	popdef(`SRCSTR')
+	popdef(`UNI_STRLEN')
+	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_USTRING_N', `DBG(`$0($*)') DONE(`$1')`'PROC_STRING_N_EX(`DST(`$1')', `SRC(`$1')', `SRC(`$2')', `$1', `UChar')')
+
+define(`PROC_STRING_L', `DBG(`$0($*)') PROC_STRING_N(`$1', `$2 + 1')')
+define(`PROC_USTRING_L', `DBG(`$0($*)') PROC_USTRING_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')')
+define(`PROC_USTRING',  `DBG(`$0($*)') DONE(`$1')`'PROC_STRING_N_EX(`DST(`$1')', `SRC(`$1')', `strlen(SRC(`$1')) + 1', `$1', `UChar')')
+
+dnl {{{ PROC_ZSTRING_N(1:type, 2:name, 3:size, 4:size_type)
+define(`PROC_ZSTRING_N', `
+	DBG(`$0($*)')
+#ifdef IS_UNICODE
+	pushdef(`NSIZE', ifelse(
+			`$4', `strlen', `UNI_STRLEN (SRC(`$2')) + 1',
+			`$4', `len',    `SRC(`$3') + 1',
+			`',   `',       `SRC(`$3')',
+			))
+	DONE(`$2')
+	ifelse(`$1', `1', `PROC_STRING_N_EX(`DST(`$2')', `SRC(`$2')', defn(`NSIZE'), `$2', `zstr_uchar')
+	', `
+		if (ifelse(`$1', `', `UG(unicode)', `SRC(`$1') == IS_UNICODE')) {
+			PROC_STRING_N_EX(`DST(`$2')', `SRC(`$2')', defn(`NSIZE'), `$2', `zstr_uchar')
+		}
+		else {
+			PROC_STRING_N_EX(`DST(`$2')', `SRC(`$2')', defn(`NSIZE'), `$2', `zstr_char')
+		}
+	')
+#else
+	DONE(`$2')
+	PROC_STRING_N_EX(`DST(`$2')', `SRC(`$2')', NSIZE, `$2', `zstr_char')
+#endif
+	popdef(`NSIZE')
+')
+dnl }}}
+define(`PROC_ZSTRING_L', `DBG(`$0($*)') PROC_ZSTRING_N(`$1', `$2', `$3', `len')')
+define(`PROC_ZSTRING', `DBG(`$0($*)') PROC_ZSTRING_N(`$1', `$2', , `strlen')')
Index: /tags/3.0.0-rc1/processor/hashtable.m4
===================================================================
--- /tags/3.0.0-rc1/processor/hashtable.m4	(revision 932)
+++ /tags/3.0.0-rc1/processor/hashtable.m4	(revision 932)
@@ -0,0 +1,185 @@
+dnl DEF_HASH_TABLE_FUNC(1:name, 2:datatype [, 3:dataname] [, 4:check_function])
+define(`DEF_HASH_TABLE_FUNC', `
+	DEF_STRUCT_P_FUNC(`HashTable', `$1', `
+		pushdefFUNC_NAME(`$2', `$3')
+		dnl {{{ dasm
+		IFDASM(`
+			const Bucket *srcBucket;
+			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 (srcBucket = src->pListHead; srcBucket != NULL; srcBucket = srcBucket->pListNext) {
+				ALLOC_INIT_ZVAL(zv);
+				array_init(zv);
+				FUNC_NAME (dasm, zv, (($2*)srcBucket->pData) TSRMLS_CC);
+				keysize = BUCKET_KEY_SIZE(srcBucket) + 2;
+				if (keysize > bufsize) {
+					do {
+						bufsize *= 2;
+					} while (keysize > bufsize);
+					buf = erealloc(buf, bufsize);
+				}
+				memcpy(buf, BUCKET_KEY_S(srcBucket), keysize);
+				buf[keysize - 2] = buf[keysize - 1] = ""[0];
+				keysize = srcBucket->nKeyLength;
+#ifdef IS_UNICODE
+				if (BUCKET_KEY_TYPE(srcBucket) == 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(srcBucket), ZSTR(buf), keysize, zv);
+			}
+			')
+
+			efree(buf);
+		', `
+		dnl }}}
+		Bucket *srcBucket;
+		Bucket *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
+				PROCESS(unsigned int, canary)
+			')
+		')
+#endif
+		PROCESS(uint, nTableSize)
+		PROCESS(uint, nTableMask)
+		PROCESS(uint, nNumOfElements)
+		PROCESS(ulong, nNextFreeElement)
+		IFCOPY(`dst->pInternalPointer = NULL;	/* Used for element traversal */') DONE(pInternalPointer)
+		IFCOPY(`dst->pListHead = NULL;') DONE(pListHead)
+#ifdef ZEND_ENGINE_2_4
+		if (src->nTableMask) {
+#endif
+		CALLOC(dst->arBuckets, Bucket*, src->nTableSize)
+		DONE(arBuckets)
+		DISABLECHECK(`
+		for (srcBucket = src->pListHead; srcBucket != NULL; srcBucket = srcBucket->pListNext) {
+			ifelse($4, `', `', `
+				pushdef(`BUCKET', `srcBucket')
+				if ($4 == ZEND_HASH_APPLY_REMOVE) {
+					IFCOPY(`dst->nNumOfElements --;')
+					continue;
+				}
+				popdef(`BUCKET')
+			')
+
+			IFCALCCOPY(`bucketsize = BUCKET_SIZE(srcBucket);')
+			ALLOC(pnew, char, bucketsize, , Bucket)
+			IFCOPY(`
+#ifdef ZEND_ENGINE_2_4
+			memcpy(pnew, srcBucket, BUCKET_HEAD_SIZE(Bucket));
+			if (BUCKET_KEY_SIZE(srcBucket)) {
+				memcpy((char *) (pnew + 1), srcBucket->arKey, BUCKET_KEY_SIZE(srcBucket));
+				pnew->arKey = (const char *) (pnew + 1);
+			}
+			else {
+				pnew->arKey = NULL;
+			}
+#else
+			memcpy(pnew, srcBucket, bucketsize);
+#endif
+			')
+			IFCOPY(`
+				n = srcBucket->h & src->nTableMask;
+				/* pnew into hash node chain */
+				pnew->pLast = NULL;
+				pnew->pNext = dst->arBuckets[n];
+				if (pnew->pNext) {
+					pnew->pNext->pLast = pnew;
+				}
+				dst->arBuckets[n] = pnew;
+			')
+			IFDPRINT(`
+				INDENT()
+				fprintf(stderr, "$2:\"");
+				xc_dprint_str_len(BUCKET_KEY_S(srcBucket), BUCKET_KEY_SIZE(srcBucket));
+				fprintf(stderr, "\" %d:h=%lu ", BUCKET_KEY_SIZE(srcBucket), srcBucket->h);
+			')
+			if (sizeof(void *) == sizeof($2)) {
+				IFCOPY(`pnew->pData = &pnew->pDataPtr;')
+				dnl no alloc
+				STRUCT_P_EX(`$2', pnew->pData, (($2*)srcBucket->pData), `', `$3', ` ')
+			}
+			else {
+				STRUCT_P_EX(`$2', pnew->pData, (($2*)srcBucket->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;
+		}
+		')
+#ifdef ZEND_ENGINE_2_4
+	}
+	else { /* if (src->nTableMask) */
+		DONE(arBuckets)
+	}
+#endif
+		IFCOPY(`dst->pListTail = pnew;') DONE(pListTail)
+		IFCOPY(`dst->pDestructor = src->pDestructor;') DONE(pDestructor)
+		PROCESS(zend_bool, persistent)
+#ifdef IS_UNICODE
+		PROCESS(zend_bool, unicode)
+#endif
+		PROCESS(unsigned char, nApplyCount)
+		PROCESS(zend_bool, bApplyProtection)
+#if ZEND_DEBUG
+		PROCESS(int, inconsistent)
+#endif
+		')dnl IFDASM
+		popdef(`FUNC_NAME')
+	')
+')
Index: /tags/3.0.0-rc1/processor/process.m4
===================================================================
--- /tags/3.0.0-rc1/processor/process.m4	(revision 917)
+++ /tags/3.0.0-rc1/processor/process.m4	(revision 917)
@@ -0,0 +1,145 @@
+define(`PROCESS_SCALAR', `dnl {{{ (1:elm, 2:format=%d, 3:type=)
+	IFNOTMEMCPY(`IFCOPY(`DST(`$1') = SRC(`$1');')')
+	IFDPRINT(`
+		INDENT()
+		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 }}}
+define(`PROCESS_xc_ztstring', `dnl {{{ (1:elm)
+	pushdef(`REALPTRTYPE', `zend_class_entry')
+	PROC_STRING(`$1')
+	popdef(`REALPTRTYPE')
+')
+dnl }}}
+define(`PROCESS_xc_zval_type_t', `dnl {{{ (1:elm)
+	IFDPRINT(`
+		INDENT()
+		fprintf(stderr, ":$1:\t%d %s\n", SRC(`$1'), xc_get_data_type(SRC(`$1')));
+		DONE(`$1')
+	', `PROCESS_SCALAR(`$1')')
+')
+dnl }}}
+define(`PROCESS_xc_op_type', `dnl {{{ (1:elm)
+	IFDPRINT(`
+		INDENT()
+		fprintf(stderr, ":$1:\t%d %s\n", SRC(`$1'), xc_get_op_type(SRC(`$1')));
+		DONE(`$1')
+	', `PROCESS_SCALAR(`$1')')
+')
+dnl }}}
+define(`PROCESS_xc_opcode', `dnl {{{ (1:elm)
+	IFDPRINT(`
+		INDENT()
+		fprintf(stderr, ":$1:\t%u %s\n", SRC(`$1'), xc_get_opcode(SRC(`$1')));
+		DONE(`$1')
+	', `PROCESS_SCALAR(`$1')')
+')
+dnl }}}
+define(`PROCESS', `dnl PROCESS(1:type, 2:elm)
+	DBG(`$0($*)')
+	assert(sizeof($1) == sizeof(SRC(`$2')));
+	ifelse(
+		`$1', `zend_bool',        `PROCESS_SCALAR(`$2', `u',  `$1')'
+	, `$1', `zend_uchar',       `PROCESS_SCALAR(`$2', `u',  `$1')'
+	, `$1', `char',             `PROCESS_SCALAR(`$2', `d',  `$1')'
+	, `$1', `int32_t',          `PROCESS_SCALAR(`$2', `d',  `$1')'
+	, `$1', `unsigned char',    `PROCESS_SCALAR(`$2', `u',  `$1')'
+	, `$1', `zend_uint',        `PROCESS_SCALAR(`$2', `u',  `$1')'
+	, `$1', `uint',             `PROCESS_SCALAR(`$2', `u',  `$1')'
+	, `$1', `unsigned int',     `PROCESS_SCALAR(`$2', `u',  `$1')'
+	, `$1', `zend_ulong',       `PROCESS_SCALAR(`$2', `lu', `$1')'
+	, `$1', `ulong',            `PROCESS_SCALAR(`$2', `lu', `$1')'
+	, `$1', `size_t',           `PROCESS_SCALAR(`$2', `lu', `$1')'
+	, `$1', `long',             `PROCESS_SCALAR(`$2', `ld', `$1')'
+	, `$1', `time_t',           `PROCESS_SCALAR(`$2', `ld', `$1')'
+	, `$1', `zend_ushort',      `PROCESS_SCALAR(`$2', `hu', `$1')'
+	, `$1', `int',              `PROCESS_SCALAR(`$2', `d',  `$1')'
+	, `$1', `double',           `PROCESS_SCALAR(`$2', `f',  `$1')'
+	, `$1', `xc_entry_type_t',  `PROCESS_SCALAR(`$2', `d',  `$1')'
+	, `$1', `xc_hash_value_t',  `PROCESS_SCALAR(`$2', `lu', `$1')'
+	, `$1', `last_brk_cont_t',  `PROCESS_SCALAR(`$2', `d', `$1')'
+
+	, `$1', `xc_ztstring',       `PROCESS_xc_ztstring(`$2')'
+	, `$1', `xc_zval_type_t',    `PROCESS_xc_zval_type_t(`$2')'
+	, `$1', `xc_op_type',        `PROCESS_xc_op_type(`$2')'
+	, `$1', `xc_opcode',         `PROCESS_xc_opcode(`$2')'
+	, `$1', `opcode_handler_t',  `/* is copying enough? */COPY(`$2')'
+	, `$1', `xc_md5sum_t',       `COPY(`$2')'
+	, `', `', `m4_errprint(`AUTOCHECK ERROR: Unknown type "$1"')define(`EXIT_PENDING', 1)'
+	)
+')
+define(`PROCESS_ARRAY', `dnl {{{ (1:count, 2:type, 3:elm, [4:real_type])
+	if (src->$3) {
+		int LOOPCOUNTER;
+		IFDASM(`
+			zval *arr;
+			ALLOC_INIT_ZVAL(arr);
+			array_init(arr);
+
+			for (LOOPCOUNTER = 0;
+					ifelse(`$1', `', `src->$3[LOOPCOUNTER]',
+					`', `', `LOOPCOUNTER < SRC(`$1')');
+					++LOOPCOUNTER) {
+				pushdef(`dst', `arr')
+				pushdef(`SRC', `ifelse(`$4', `', `', `', `', `($2)')' defn(`SRC') `[LOOPCOUNTER]')
+				popdef(`add_assoc_bool_ex', `add_next_index_bool($1, $3)')
+				popdef(`add_assoc_string_ex', `add_next_index_string($1, $3)')
+				popdef(`add_assoc_long_ex', `add_next_index_long($1, $3)')
+				popdef(`add_assoc_zval_ex', `add_next_index_zval($1, $3)')
+				DISABLECHECK(`
+					PROCESS(`$2', `$3')
+				')
+				popdef(`add_assoc_zval_ex')
+				popdef(`add_assoc_long_ex')
+				popdef(`add_assoc_string_ex')
+				popdef(`add_assoc_bool_ex')
+				popdef(`SRC')
+				popdef(`dst')
+
+				++LOOPCOUNTER;
+			}
+			add_assoc_zval_ex(dst, ZEND_STRS("$3"), arr);
+		', `
+			dnl find count with NULL
+			ifelse(`$1', `', `
+				size_t count = 0;
+				while (SRC(`$3[count]')) {
+					++count;
+				}
+				++count;
+				pushdef(`STRUCT_COUNT', `count')
+			',
+			`', `', `pushdef(`STRUCT_COUNT', `SRC(`$1')')')
+			ALLOC(`dst->$3', `$2', `STRUCT_COUNT', , `$4')
+			popdef(`STRUCT_COUNT')
+
+			for (LOOPCOUNTER = 0;
+					ifelse(`$1', `', `src->$3[LOOPCOUNTER]',
+					`', `', `LOOPCOUNTER < SRC(`$1')');
+					++LOOPCOUNTER) {
+				DISABLECHECK(`
+					pushdef(`DST', defn(`DST') `[LOOPCOUNTER]')
+					pushdef(`SRC', `ifelse(`$4', `', `', `', `', `($2)')' defn(`SRC') `[LOOPCOUNTER]')
+					PROCESS(`$2', `$3')
+					popdef(`SRC')
+					popdef(`DST')
+				')
+			}
+			dnl the end marker
+			ifelse(`$1', `', `IFCOPY(`DST(`$3[LOOPCOUNTER]') = NULL;')')
+		')dnl IFDASM
+		DONE(`$3')
+	}
+	else {
+		COPYNULL(`$3')
+	}
+')
+dnl }}}
Index: /tags/3.0.0-rc1/processor/processor.m4
===================================================================
--- /tags/3.0.0-rc1/processor/processor.m4	(revision 1051)
+++ /tags/3.0.0-rc1/processor/processor.m4	(revision 1051)
@@ -0,0 +1,1224 @@
+dnl ================
+/* {{{ Pre-declare */
+DECL_STRUCT_P_FUNC(`zval')
+DECL_STRUCT_P_FUNC(`zval_ptr')
+DECL_STRUCT_P_FUNC(`zval_ptr_nullable')
+DECL_STRUCT_P_FUNC(`zend_op_array')
+DECL_STRUCT_P_FUNC(`zend_class_entry')
+#ifdef HAVE_XCACHE_CONSTANT
+DECL_STRUCT_P_FUNC(`zend_constant')
+#endif
+DECL_STRUCT_P_FUNC(`zend_function')
+DECL_STRUCT_P_FUNC(`xc_entry_var_t')
+DECL_STRUCT_P_FUNC(`xc_entry_php_t')
+#ifdef ZEND_ENGINE_2
+DECL_STRUCT_P_FUNC(`zend_property_info')
+#endif
+/* }}} */
+dnl ====================================================
+#ifdef IS_CV
+DEF_STRUCT_P_FUNC(`zend_compiled_variable', , `dnl {{{
+	PROCESS(int, name_len)
+	PROC_ZSTRING_L(, name, name_len)
+	PROCESS(ulong, hash_value)
+')
+dnl }}}
+#endif
+DEF_STRUCT_P_FUNC(`zend_uint', , `dnl {{{
+	IFCOPY(`dst[0] = src[0];')
+	IFDPRINT(`
+		INDENT()
+		fprintf(stderr, "%u\n", src[0]);
+	')
+	DONE_SIZE(sizeof(src[0]))
+')
+dnl }}}
+#ifndef ZEND_ENGINE_2
+DEF_STRUCT_P_FUNC(`int', , `dnl {{{
+	IFCOPY(`*dst = *src;')
+	IFDPRINT(`
+		INDENT()
+		fprintf(stderr, "%d\n", src[0]);
+	')
+	DONE_SIZE(sizeof(src[0]))
+')
+dnl }}}
+#endif
+#ifdef ZEND_ENGINE_2
+DEF_STRUCT_P_FUNC(`zend_try_catch_element', , `dnl {{{
+	PROCESS(zend_uint, try_op)
+	PROCESS(zend_uint, catch_op)
+')
+dnl }}}
+#endif
+DEF_STRUCT_P_FUNC(`zend_brk_cont_element', , `dnl {{{
+#ifdef ZEND_ENGINE_2_2
+	PROCESS(int, start)
+#endif
+	PROCESS(int, cont)
+	PROCESS(int, brk)
+	PROCESS(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);
+		Z_SET_REFCOUNT(*dst, 1);
+		DONE(value)
+		DONE(type)
+#ifdef ZEND_ENGINE_2_3
+		DONE(is_ref__gc)
+		DONE(refcount__gc)
+#else
+		DONE(is_ref)
+		DONE(refcount)
+#endif
+	} while(0);
+	', `
+		dnl IFDASM else
+		/* Variable information */
+dnl {{{ zvalue_value
+		DISABLECHECK(`
+		switch ((Z_TYPE_P(src) & IS_CONSTANT_TYPE_MASK)) {
+			case IS_LONG:
+			case IS_RESOURCE:
+			case IS_BOOL:
+				PROCESS(long, value.lval)
+				break;
+			case IS_DOUBLE:
+				PROCESS(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
+				PROCESS(int, value.str.len)
+				PROC_STRING_L(value.str.val, value.str.len)
+				break;
+#ifdef IS_UNICODE
+			case IS_UNICODE:
+proc_unicode:
+				PROCESS(int32_t, value.uni.len)
+				PROC_ZSTRING_L(1, value.uni.val, value.uni.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)
+		PROCESS(xc_zval_type_t, type)
+#ifdef ZEND_ENGINE_2_3
+		PROCESS(zend_uchar, is_ref__gc)
+#else
+		PROCESS(zend_uchar, is_ref)
+#endif
+
+#ifdef ZEND_ENGINE_2_3
+		PROCESS(zend_uint, refcount__gc)
+#elif defined(ZEND_ENGINE_2)
+		PROCESS(zend_uint, refcount)
+#else
+		PROCESS(zend_ushort, refcount)
+#endif
+	')dnl IFDASM
+')
+dnl }}}
+DEF_STRUCT_P_FUNC(`zval_ptr', , `dnl {{{
+	IFDASM(`
+		pushdefFUNC_NAME(`zval')
+		FUNC_NAME (dasm, 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, PROCESSOR_TYPE is_shm %d\n", dst[0], xc_is_shm(dst[0]));
+						')
+						IFCALCSTORE(`processor->have_references = 1;')
+						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];
+						FIXPOINTER_EX(zval, pzv)
+					')
+					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]);
+			')
+			IFDPRINT(`INDENT()`'fprintf(stderr, "[%p] ", src[0]);')
+			STRUCT_P_EX(zval, dst[0], src[0], `[0]', `', ` ')
+			FIXPOINTER_EX(zval, dst[0])
+		} while (0);
+	')
+	DONE_SIZE(sizeof(zval_ptr))
+')
+dnl }}}
+DEF_STRUCT_P_FUNC(`zval_ptr_nullable', , `dnl {{{
+	if (src[0]) {
+		STRUCT_P_EX(zval_ptr, dst, src, `', `', ` ')
+	}
+	else {
+		IFCOPY(`COPYNULL_EX(src[0], src)')
+	}
+	DONE_SIZE(sizeof(zval_ptr_nullable))
+')
+dnl }}}
+#ifdef ZEND_ENGINE_2
+DEF_STRUCT_P_FUNC(`zend_arg_info', , `dnl {{{
+	PROCESS(zend_uint, name_len)
+	PROC_ZSTRING_L(, name, name_len)
+	PROCESS(zend_uint, class_name_len)
+	PROC_ZSTRING_L(, class_name, class_name_len)
+#ifdef ZEND_ENGINE_2_4
+	PROCESS(zend_uchar, type_hint)
+#else
+	PROCESS(zend_bool, array_type_hint)
+#endif
+	PROCESS(zend_bool, allow_null)
+	PROCESS(zend_bool, pass_by_reference)
+#ifndef ZEND_ENGINE_2_4
+	PROCESS(zend_bool, return_reference)
+	PROCESS(int, required_num_args)
+#endif
+')
+dnl }}}
+#endif
+#ifdef HAVE_XCACHE_CONSTANT
+DEF_STRUCT_P_FUNC(`zend_constant', , `dnl {{{
+	STRUCT(zval, value)
+	PROCESS(int, flags)
+	PROCESS(uint, name_len)
+	pushdef(`estrndup', `zend_strndup')
+	PROC_ZSTRING_N(, name, name_len)
+	popdef(`estrndup')
+	PROCESS(int, module_number)
+')
+dnl }}}
+#endif
+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 }}}
+#ifdef ZEND_ENGINE_2
+DEF_STRUCT_P_FUNC(`zend_property_info', , `dnl {{{
+	PROCESS(zend_uint, flags)
+	PROCESS(int, name_length)
+	PROC_ZSTRING_L(, name, name_length)
+	PROCESS(ulong, h)
+#ifdef ZEND_ENGINE_2_4
+	PROCESS(int, offset)
+#endif
+#ifdef ZEND_ENGINE_2_1
+	PROCESS(int, doc_comment_len)
+	PROC_ZSTRING_L(, doc_comment, doc_comment_len)
+#endif
+	dnl isnt in php6 yet
+#if defined(ZEND_ENGINE_2_2)
+	PROC_CLASS_ENTRY_P(ce)
+#endif
+')
+dnl }}}
+#endif
+#ifdef ZEND_ENGINE_2_4
+DEF_STRUCT_P_FUNC(`zend_trait_method_reference', , `dnl {{{
+	PROCESS(unsigned int, mname_len)
+	PROC_STRING_L(method_name, mname_len)
+	COPYNULL(ce)
+	PROCESS(unsigned int, cname_len)
+	PROC_STRING_L(class_name, cname_len)
+')
+dnl }}}
+DEF_STRUCT_P_FUNC(`zend_trait_alias', , `dnl {{{
+	STRUCT_P(zend_trait_method_reference, trait_method)
+	PROCESS(unsigned int, alias_len)
+	PROC_STRING_L(alias, alias_len)
+	PROCESS(zend_uint, modifiers)
+	COPYNULL(function)
+')
+dnl }}}
+DEF_STRUCT_P_FUNC(`zend_trait_precedence', , `dnl {{{
+	STRUCT_P(zend_trait_method_reference, trait_method)
+	PROCESS_ARRAY(, xc_ztstring, exclude_from_classes, zend_class_entry*)
+	COPYNULL(function)
+')
+dnl }}}
+DEF_STRUCT_P_FUNC(`zend_trait_alias_ptr', , `dnl {{{
+	IFDASM(`
+		pushdefFUNC_NAME(`zend_trait_alias')
+		FUNC_NAME (dasm, dst, src[0] TSRMLS_CC);
+		popdef(`FUNC_NAME')
+	', `
+		ALLOC(dst[0], zend_trait_alias)
+		STRUCT_P_EX(zend_trait_alias, dst[0], src[0], `[0]', `', ` ')
+		FIXPOINTER_EX(zend_trait_alias, dst[0])
+	')
+	DONE_SIZE(sizeof(zend_trait_alias))
+')
+dnl }}}
+DEF_STRUCT_P_FUNC(`zend_trait_precedence_ptr', , `dnl {{{
+	IFDASM(`
+		pushdefFUNC_NAME(`zend_trait_precedence')
+		FUNC_NAME (dasm, dst, src[0] TSRMLS_CC);
+		popdef(`FUNC_NAME')
+	', `
+		ALLOC(dst[0], zend_trait_precedence)
+		STRUCT_P_EX(zend_trait_precedence, dst[0], src[0], `[0]', `', ` ')
+		FIXPOINTER_EX(zend_trait_precedence, dst[0])
+	')
+	DONE_SIZE(sizeof(zend_trait_precedence))
+')
+dnl }}}
+#endif
+DEF_STRUCT_P_FUNC(`zend_class_entry', , `dnl {{{
+	IFCALCCOPY(`
+		processor->active_class_entry_src = src;
+		IFCOPY(`processor->active_class_entry_dst = dst;')
+	')
+	PROCESS(char, type)
+	PROCESS(zend_uint, name_length)
+	PROC_ZSTRING_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
+	PROCESS(int, refcount)
+#else
+	STRUCT_P(int, refcount)
+#endif
+#ifndef ZEND_ENGINE_2_4
+	PROCESS(zend_bool, constants_updated)
+#endif
+#ifdef ZEND_ENGINE_2
+	PROCESS(zend_uint, ce_flags)
+#endif
+
+#ifdef ZEND_ENGINE_2
+	STRUCT(HashTable, properties_info, HashTable_zend_property_info)
+#endif
+
+#ifdef ZEND_ENGINE_2_4
+	STRUCT_ARRAY(int, default_properties_count, zval_ptr_nullable, default_properties_table)
+	PROCESS(int, default_properties_count)
+	STRUCT_ARRAY(int, default_static_members_count, zval_ptr_nullable, default_static_members_table)
+	PROCESS(int, default_static_members_count)
+	IFCOPY(`dst->static_members_table = dst->default_static_members_table;')
+	DONE(static_members_table)
+#else
+	IFCOPY(`dst->builtin_functions = src->builtin_functions;')
+	DONE(builtin_functions)
+	STRUCT(HashTable, default_properties, HashTable_zval_ptr)
+#	ifdef ZEND_ENGINE_2_1
+	STRUCT(HashTable, default_static_members, HashTable_zval_ptr)
+	IFCOPY(`dst->static_members = &dst->default_static_members;')
+	DONE(static_members)
+#	elif defined(ZEND_ENGINE_2)
+	STRUCT_P(HashTable, static_members, HashTable_zval_ptr)
+#	endif
+#endif /* ZEND_ENGINE_2_4 */
+
+#ifdef ZEND_ENGINE_2
+	STRUCT(HashTable, constants_table, HashTable_zval_ptr)
+
+#ifdef ZEND_ENGINE_2_2
+	dnl runtime binding: ADD_INTERFACE will deal with it
+	COPYNULL(`interfaces')
+	COPYZERO(`num_interfaces')
+
+#	ifdef ZEND_ENGINE_2_4
+	dnl runtime binding: ADD_TRAIT will deal with it
+	COPYNULL(traits)
+	COPYZERO(num_traits)
+	STRUCT_ARRAY(, , zend_trait_alias_ptr, trait_aliases)
+	STRUCT_ARRAY(, , zend_trait_precedence_ptr, trait_precedences)
+#	endif
+#else
+	IFRESTORE(`
+		if (src->num_interfaces) {
+			CALLOC(dst->interfaces, zend_class_entry*, src->num_interfaces)
+			DONE(`interfaces')
+		}
+		else {
+			COPYNULL(`interfaces')
+		}
+	', `
+		DONE(`interfaces')
+	')
+	PROCESS(zend_uint, num_interfaces)
+#endif
+
+#	ifdef ZEND_ENGINE_2_4
+	DISABLECHECK(`
+	IFRESTORE(`dst->info.user.filename = processor->entry_php_src->filepath;', `PROC_STRING(info.user.filename)')
+	PROCESS(zend_uint, info.user.line_start)
+	PROCESS(zend_uint, info.user.line_end)
+	PROCESS(zend_uint, info.user.doc_comment_len)
+	PROC_ZSTRING_L(, info.user.doc_comment, info.user.doc_comment_len)
+	')
+	DONE(info)
+#	else
+	IFRESTORE(`dst->filename = processor->entry_php_src->filepath;DONE(filename)', `PROC_STRING(filename)')
+	PROCESS(zend_uint, line_start)
+	PROCESS(zend_uint, line_end)
+#		ifdef ZEND_ENGINE_2_1
+	PROCESS(zend_uint, doc_comment_len)
+	PROC_ZSTRING_L(, doc_comment, doc_comment_len)
+#		endif
+#	endif
+
+	/* # NOT DONE */
+	COPY(serialize_func)
+	COPY(unserialize_func)
+	COPY(iterator_funcs)
+	COPY(create_object)
+	COPY(get_iterator)
+	COPY(interface_gets_implemented)
+#	ifdef ZEND_ENGINE_2_3
+	COPY(get_static_method)
+#	endif
+	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 defined(ZEND_ENGINE_2_2) || PHP_MAJOR_VERSION >= 6
+	COPY(__tostring)
+#	 endif
+#	endif
+	COPY(__call)
+#	ifdef ZEND_CALLSTATIC_FUNC_NAME
+	COPY(__callstatic)
+#	endif
+#	ifndef ZEND_ENGINE_2_4
+	/* # NOT DONE */
+	COPY(module)
+#	endif
+#else /* ZEND_ENGINE_2 */
+	COPY(handle_function_call)
+	COPY(handle_property_get)
+	COPY(handle_property_set)
+#endif
+	dnl must do after SETNULL(constructor) and dst->parent
+	STRUCT(HashTable, function_table, HashTable_zend_function)
+	IFRESTORE(`dst->function_table.pDestructor = ZEND_FUNCTION_DTOR;')
+	IFCALCCOPY(`
+		processor->active_class_entry_src = NULL;
+		IFCOPY(`processor->active_class_entry_dst = NULL;')
+	')
+')
+dnl }}}
+#ifdef ZEND_ENGINE_2_4
+undefine(`UNION_znode_op')
+define(`UNION_znode_op', `dnl {{{
+#ifndef NDEBUG
+	switch ((src->$1_type ifelse($1, `result', & ~EXT_TYPE_UNUSED))) {
+	case IS_CONST:
+	case IS_VAR:
+	case IS_CV:
+	case IS_TMP_VAR:
+	case IS_UNUSED:
+		break;
+
+	default:
+		assert(0);
+	}
+#endif
+
+	dnl dirty dispatch
+	DISABLECHECK(`
+	switch ((src->$1_type ifelse($1, `result', & ~EXT_TYPE_UNUSED))) {
+		case IS_CONST:
+			ifelse($1, `result', `
+				PROCESS(zend_uint, $1.constant)
+			', `
+				IFDASM(`{
+					zval *zv;
+					ALLOC_INIT_ZVAL(zv);
+					*zv = dasm->active_op_array_src->literals[src->$1.constant].constant;
+					zval_copy_ctor(zv);
+					add_assoc_zval_ex(dst, ZEND_STRS("$1.constant"), zv);
+				}
+				', `
+					IFCOPY(`
+						dst->$1 = src->$1;
+					', `
+						PROCESS(zend_uint, $1.constant)
+					')
+				')
+			')
+			break;
+		IFCOPY(`
+			IFNOTMEMCPY(`
+				default:
+					$1 = $2;
+			')
+		', `
+		case IS_VAR:
+		case IS_TMP_VAR:
+		case IS_CV:
+			PROCESS(zend_uint, $1.var)
+			break;
+		case IS_UNUSED:
+			IFDASM(`PROCESS(zend_uint, $1.var)')
+			PROCESS(zend_uint, $1.opline_num)
+			break;
+		')
+	}
+	')
+	DONE($1)
+')
+dnl }}}
+#else
+DEF_STRUCT_P_FUNC(`znode', , `dnl {{{
+	PROCESS(xc_op_type, 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);
+	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:
+		case XCACHE_IS_CV:
+			PROCESS(zend_uint, u.var)
+			PROCESS(zend_uint, u.EA.type)
+			break;
+		case IS_UNUSED:
+			IFDASM(`PROCESS(zend_uint, u.var)')
+			PROCESS(zend_uint, u.opline_num)
+#ifndef ZEND_ENGINE_2
+			PROCESS(zend_uint, u.fetch_type)
+#endif
+			PROCESS(zend_uint, u.EA.type)
+			break;
+		')
+	}
+	')
+	DONE(u)
+#if 0
+	DONE(EA)
+#endif
+#undef XCACHE_IS_CV
+')
+dnl }}}
+#endif
+DEF_STRUCT_P_FUNC(`zend_op', , `dnl {{{
+	PROCESS(xc_opcode, opcode)
+#ifdef ZEND_ENGINE_2_4
+	IFRESTORE(`', `
+	switch (src->opcode) {
+	case ZEND_BIND_TRAITS:
+		((zend_op *) src)->op2_type = IS_UNUSED;
+		break;
+	}
+	')
+	UNION_znode_op(result)
+	UNION_znode_op(op1)
+	UNION_znode_op(op2)
+#else
+	STRUCT(znode, result)
+	STRUCT(znode, op1)
+	STRUCT(znode, op2)
+#endif
+	PROCESS(ulong, extended_value)
+	PROCESS(uint, lineno)
+#ifdef ZEND_ENGINE_2_1
+#ifdef ZEND_ENGINE_2_4
+	PROCESS(zend_uchar, op1_type)
+	PROCESS(zend_uchar, op2_type)
+	PROCESS(zend_uchar, result_type)
+#endif
+	IFCOPY(`
+		assert(processor->active_op_array_src);
+		assert(processor->active_op_array_dst);
+#ifdef ZEND_ENGINE_2_4
+		pushdef(`UNION_znode_op_literal', `
+			if (src->$1_type == IS_CONST) {
+				dst->$1.constant = src->$1.literal - processor->active_op_array_src->literals;
+				dst->$1.literal = &processor->active_op_array_dst->literals[dst->$1.constant];
+			}
+		')
+		UNION_znode_op_literal(op1)
+		UNION_znode_op_literal(op2)
+#endif
+		popdef(`UNION_znode_op_literal')
+		switch (src->opcode) {
+#ifdef ZEND_GOTO
+			case ZEND_GOTO:
+#endif
+			case ZEND_JMP:
+#ifdef ZEND_ENGINE_2
+				assert(Z_OP(src->op1).jmp_addr >= processor->active_op_array_src->opcodes && Z_OP(src->op1).jmp_addr - processor->active_op_array_src->opcodes < processor->active_op_array_src->last);
+				Z_OP(dst->op1).jmp_addr = processor->active_op_array_dst->opcodes + (Z_OP(src->op1).jmp_addr - processor->active_op_array_src->opcodes);
+				assert(Z_OP(dst->op1).jmp_addr >= processor->active_op_array_dst->opcodes && Z_OP(dst->op1).jmp_addr - processor->active_op_array_dst->opcodes < processor->active_op_array_dst->last);
+#endif
+				break;
+
+			case ZEND_JMPZ:
+			case ZEND_JMPNZ:
+			case ZEND_JMPZ_EX:
+			case ZEND_JMPNZ_EX:
+#ifdef ZEND_JMP_SET
+			case ZEND_JMP_SET:
+#endif
+#ifdef ZEND_JMP_SET_VAR
+			case ZEND_JMP_SET_VAR:
+#endif
+#ifdef ZEND_ENGINE_2
+				assert(Z_OP(src->op2).jmp_addr >= processor->active_op_array_src->opcodes && Z_OP(src->op2).jmp_addr - processor->active_op_array_src->opcodes < processor->active_op_array_src->last);
+				Z_OP(dst->op2).jmp_addr = processor->active_op_array_dst->opcodes + (Z_OP(src->op2).jmp_addr - processor->active_op_array_src->opcodes);
+				assert(Z_OP(dst->op2).jmp_addr >= processor->active_op_array_dst->opcodes && Z_OP(dst->op2).jmp_addr - processor->active_op_array_dst->opcodes < processor->active_op_array_dst->last);
+#endif
+				break;
+
+			default:
+				break;
+		}
+	')
+	PROCESS(opcode_handler_t, handler)
+#endif
+')
+dnl }}}
+#ifdef ZEND_ENGINE_2_4
+DEF_STRUCT_P_FUNC(`zend_literal', , `dnl {{{
+	STRUCT(zval, constant)
+	PROCESS(zend_ulong, hash_value)
+	PROCESS(zend_uint,  cache_slot)
+')
+dnl }}}
+#endif
+DEF_STRUCT_P_FUNC(`zend_op_array', , `dnl {{{
+	IFCOPY(`
+		processor->active_op_array_dst = dst;
+		processor->active_op_array_src = src;
+	')
+	IFDASM(`
+		dasm->active_op_array_src = src;
+	')
+	{
+	IFRESTORE(`
+	const xc_op_array_info_t *op_array_info = &processor->active_op_array_infos_src[processor->active_op_array_index++];
+	dnl shadow copy must NOT meet:
+	dnl readonly_protection=on
+	dnl main op_array && have early binding
+#ifdef ZEND_COMPILE_DELAYED_BINDING
+	zend_bool need_early_binding = 0;
+#else
+	zend_bool need_early_binding = processor->php_src->have_early_binding;
+#endif
+	zend_bool shallow_copy = !processor->readonly_protection && !(src == processor->php_src->op_array && need_early_binding);
+	if (shallow_copy) {
+		zend_bool gc_arg_info = 0;
+		zend_bool gc_opcodes  = 0;
+		/* really fast shallow copy */
+		memcpy(dst, src, sizeof(src[0]));
+		dst->refcount[0] = 1000;
+		/* deep */
+		STRUCT_P(HashTable, static_variables, HashTable_zval_ptr)
+#ifdef ZEND_ENGINE_2
+		STRUCT_ARRAY(zend_uint, num_args, zend_arg_info, arg_info)
+		gc_arg_info = 1;
+#endif
+		dst->filename = processor->entry_php_src->filepath;
+#ifdef ZEND_ENGINE_2_4
+		if (src->literals /* || op_array_info->literalsinfo_cnt */) {
+			gc_opcodes = 1;
+		}
+#else
+		if (op_array_info->oplineinfo_cnt) {
+			gc_opcodes = 1;
+		}
+#endif
+		if (gc_opcodes) {
+			zend_op *opline, *end;
+			COPY_N_EX(last, zend_op, opcodes)
+
+			for (opline = dst->opcodes, end = opline + src->last; opline < end; ++opline) {
+#ifdef ZEND_ENGINE_2_4
+				pushdef(`UNION_znode_op_literal', `
+					if (opline->$1_type == IS_CONST) {
+						opline->$1.literal = &dst->literals[opline->$1.literal - src->literals];
+					}
+				')
+				UNION_znode_op_literal(op1)
+				UNION_znode_op_literal(op2)
+				popdef(`UNION_znode_op_literal')
+#endif
+
+				switch (opline->opcode) {
+#ifdef ZEND_GOTO
+					case ZEND_GOTO:
+#endif
+					case ZEND_JMP:
+#ifdef ZEND_ENGINE_2
+						Z_OP(opline->op1).jmp_addr = &dst->opcodes[Z_OP(opline->op1).jmp_addr - src->opcodes];
+#endif
+						break;
+
+					case ZEND_JMPZ:
+					case ZEND_JMPNZ:
+					case ZEND_JMPZ_EX:
+					case ZEND_JMPNZ_EX:
+#ifdef ZEND_JMP_SET
+					case ZEND_JMP_SET:
+#endif
+#ifdef ZEND_JMP_SET_VAR
+			case ZEND_JMP_SET_VAR:
+#endif
+#ifdef ZEND_ENGINE_2
+						Z_OP(opline->op2).jmp_addr = &dst->opcodes[Z_OP(opline->op2).jmp_addr - src->opcodes];
+#endif
+						break;
+
+					default:
+						break;
+				}
+			}
+		}
+		if (gc_arg_info || gc_opcodes) {
+			xc_gc_op_array_t gc_op_array;
+#ifdef ZEND_ENGINE_2
+			gc_op_array.num_args = gc_arg_info ? dst->num_args : 0;
+			gc_op_array.arg_info = gc_arg_info ? dst->arg_info : NULL;
+#endif
+			gc_op_array.opcodes  = gc_opcodes ? dst->opcodes : NULL;
+			xc_gc_add_op_array(&gc_op_array TSRMLS_CC);
+		}
+		IFAUTOCHECK(`xc_autocheck_skip = 1;')
+	}
+	else
+	')
+	do {
+	dnl RESTORE is done above!
+
+	/* Common elements */
+	PROCESS(zend_uchar, type)
+	PROC_ZSTRING(, function_name)
+#ifdef ZEND_ENGINE_2
+	PROCESS(zend_uint, fn_flags)
+	STRUCT_ARRAY(zend_uint, num_args, zend_arg_info, arg_info)
+	PROCESS(zend_uint, num_args)
+	PROCESS(zend_uint, required_num_args)
+#	ifndef ZEND_ENGINE_2_4
+	PROCESS(zend_bool, pass_rest_by_reference)
+#	endif
+#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 {
+			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 {
+		COPYNULL(arg_types)
+	}
+#endif
+#ifndef ZEND_ENGINE_2_4
+	PROCESS(unsigned char, return_reference)
+#endif
+	/* END of common elements */
+#ifdef IS_UNICODE
+	dnl SETNULL(u_twin)
+#endif
+
+	STRUCT_P(zend_uint, refcount)
+	UNFIXPOINTER(zend_uint, refcount)
+	IFSTORE(`dst->refcount[0] = 1;')
+
+#ifdef ZEND_ENGINE_2_4
+	dnl used when copying opcodes
+	STRUCT_ARRAY(int, last_literal, zend_literal, literals)
+	PROCESS(int, last_literal)
+#endif
+
+	dnl uses literals
+	STRUCT_ARRAY(zend_uint, last, zend_op, opcodes)
+	PROCESS(zend_uint, last)
+#ifndef ZEND_ENGINE_2_4
+	IFCOPY(`dst->size = src->last;DONE(size)', `PROCESS(zend_uint, size)')
+#endif
+
+#ifdef IS_CV
+	STRUCT_ARRAY(int, last_var, zend_compiled_variable, vars)
+	PROCESS(int, last_var)
+#	ifndef ZEND_ENGINE_2_4
+	IFCOPY(`dst->size_var = src->last_var;DONE(size_var)', `PROCESS(zend_uint, size_var)')
+#	endif
+#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
+
+	PROCESS(zend_uint, T)
+
+	STRUCT_ARRAY(last_brk_cont_t, last_brk_cont, zend_brk_cont_element, brk_cont_array)
+	PROCESS(last_brk_cont_t, last_brk_cont)
+#ifndef ZEND_ENGINE_2_4
+	PROCESS(zend_uint, current_brk_cont)
+#endif
+#ifndef ZEND_ENGINE_2
+	PROCESS(zend_bool, uses_globals)
+#endif
+
+#ifdef ZEND_ENGINE_2
+	STRUCT_ARRAY(int, last_try_catch, zend_try_catch_element, try_catch_array)
+	PROCESS(int, last_try_catch)
+#endif
+
+	STRUCT_P(HashTable, static_variables, HashTable_zval_ptr)
+
+#ifndef ZEND_ENGINE_2_4
+	COPY(start_op)
+	PROCESS(int, backpatch_count)
+#endif
+#ifdef ZEND_ENGINE_2_3
+	PROCESS(zend_uint, this_var)
+#endif
+
+#ifndef ZEND_ENGINE_2_4
+	PROCESS(zend_bool, done_pass_two)
+#endif
+	/* 5.0 <= ver < 5.3 */
+#if defined(ZEND_ENGINE_2) && !defined(ZEND_ENGINE_2_3)
+	PROCESS(zend_bool, uses_this)
+#endif
+
+	IFRESTORE(`dst->filename = processor->entry_php_src->filepath;DONE(filename)', `PROC_STRING(filename)')
+#ifdef IS_UNICODE
+	IFRESTORE(`
+		COPY(script_encoding)
+	', `
+		PROC_STRING(script_encoding)
+	')
+#endif
+#ifdef ZEND_ENGINE_2
+	PROCESS(zend_uint, line_start)
+	PROCESS(zend_uint, line_end)
+	PROCESS(int, doc_comment_len)
+	PROC_ZSTRING_L(, doc_comment, doc_comment_len)
+#endif
+#ifdef ZEND_COMPILE_DELAYED_BINDING
+	PROCESS(zend_uint, early_binding);
+#endif
+
+	/* reserved */
+	DONE(reserved)
+#if defined(HARDENING_PATCH) && HARDENING_PATCH
+	PROCESS(zend_bool, created_by_eval)
+#endif
+#ifdef ZEND_ENGINE_2_4
+	SETNULL(run_time_cache)
+	PROCESS(int, last_cache_slot)
+#endif
+	} while (0);
+	IFRESTORE(`xc_fix_op_array_info(processor->entry_php_src, processor->php_src, dst, shallow_copy, op_array_info TSRMLS_CC);')
+
+#ifdef ZEND_ENGINE_2
+	dnl mark it as -1 on store, and lookup parent on restore
+	IFSTORE(`dst->prototype = (processor->active_class_entry_src && src->prototype) ? (zend_function *) -1 : NULL;', `
+		IFRESTORE(`do {
+			zend_function *parent;
+			if (src->prototype != NULL
+			 && zend_u_hash_find(&(processor->active_class_entry_dst->parent->function_table),
+					UG(unicode) ? IS_UNICODE : IS_STRING,
+					src->function_name, xc_zstrlen(UG(unicode) ? IS_UNICODE : IS_STRING, src->function_name) + 1,
+					(void **) &parent) == SUCCESS) {
+				/* see do_inherit_method_check() */
+				if ((parent->common.fn_flags & ZEND_ACC_ABSTRACT)) {
+					dst->prototype = parent;
+				} else if (!(parent->common.fn_flags & ZEND_ACC_CTOR) || (parent->common.prototype && (parent->common.prototype->common.scope->ce_flags & ZEND_ACC_INTERFACE))) {
+					/* ctors only have a prototype if it comes from an interface */
+					dst->prototype = parent->common.prototype ? parent->common.prototype : parent;
+				}
+				else {
+					dst->prototype = NULL;
+				}
+			}
+			else {
+				dst->prototype = NULL;
+			}
+		} while (0);
+		')
+	')
+	DONE(prototype)
+
+#endif
+
+#ifdef ZEND_ENGINE_2
+	PROC_CLASS_ENTRY_P(scope)
+	IFCOPY(`
+		if (src->scope) {
+			xc_fix_method(processor, dst TSRMLS_CC);
+		}
+	')
+#endif
+
+	IFRESTORE(`
+		if (xc_have_op_array_ctor) {
+			zend_llist_apply_with_argument(&zend_extensions, (llist_apply_with_arg_func_t) xc_zend_extension_op_array_ctor_handler, dst TSRMLS_CC);
+		}
+	')
+	}
+	IFCOPY(`
+		processor->active_op_array_dst = NULL;
+		processor->active_op_array_src = NULL;
+	')
+	IFDASM(`
+		dasm->active_op_array_src = NULL;
+	')
+')
+dnl }}}
+
+#ifdef HAVE_XCACHE_CONSTANT
+DEF_STRUCT_P_FUNC(`xc_constinfo_t', , `dnl {{{
+	PROCESS(zend_uint, key_size)
+#ifdef IS_UNICODE
+	PROCESS(zend_uchar, type)
+#endif
+	IFRESTORE(`COPY(key)', `
+		PROC_ZSTRING_N(type, key, key_size)
+	')
+	PROCESS(ulong, h)
+	STRUCT(zend_constant, constant)
+')
+dnl }}}
+#endif
+IFRESTORE(`', `
+DEF_STRUCT_P_FUNC(`xc_op_array_info_detail_t', , `dnl {{{
+	PROCESS(zend_uint, index)
+	PROCESS(zend_uint, info)
+')
+dnl }}}
+DEF_STRUCT_P_FUNC(`xc_op_array_info_t', , `dnl {{{
+#ifdef ZEND_ENGINE_2_4
+	PROCESS(zend_uint, literalinfo_cnt)
+	STRUCT_ARRAY(zend_uint, literalinfo_cnt, xc_op_array_info_detail_t, literalinfos)
+#else
+	PROCESS(zend_uint, oplineinfo_cnt)
+	STRUCT_ARRAY(zend_uint, oplineinfo_cnt, xc_op_array_info_detail_t, oplineinfos)
+#endif
+')
+dnl }}}
+')
+DEF_STRUCT_P_FUNC(`xc_funcinfo_t', , `dnl {{{
+	PROCESS(zend_uint, key_size)
+#ifdef IS_UNICODE
+	PROCESS(zend_uchar, type)
+#endif
+	IFRESTORE(`COPY(key)', `
+		PROC_ZSTRING_N(type, key, key_size)
+	')
+	PROCESS(ulong, h)
+	IFRESTORE(`COPY(op_array_info)', `
+		STRUCT(xc_op_array_info_t, op_array_info)
+	')
+	IFRESTORE(`
+		processor->active_op_array_infos_src = &src->op_array_info;
+		processor->active_op_array_index = 0;
+	')
+	STRUCT(zend_function, func)
+')
+dnl }}}
+DEF_STRUCT_P_FUNC(`xc_classinfo_t', , `dnl {{{
+	PROCESS(zend_uint, key_size)
+#ifdef IS_UNICODE
+	PROCESS(zend_uchar, type)
+#endif
+	IFRESTORE(`COPY(key)', `
+		PROC_ZSTRING_N(type, key, key_size)
+	')
+	PROCESS(ulong, h)
+	PROCESS(zend_uint, methodinfo_cnt)
+	IFRESTORE(`COPY(methodinfos)', `
+		STRUCT_ARRAY(zend_uint, methodinfo_cnt, xc_op_array_info_t, methodinfos)
+	')
+	IFRESTORE(`
+		processor->active_op_array_infos_src = src->methodinfos;
+		processor->active_op_array_index = 0;
+	')
+#ifdef ZEND_ENGINE_2
+	STRUCT_P(zend_class_entry, cest)
+#else
+	STRUCT(zend_class_entry, cest)
+#endif
+#ifndef ZEND_COMPILE_DELAYED_BINDING
+	PROCESS(int, oplineno)
+#endif
+')
+dnl }}}
+IFRESTORE(`', `
+#ifdef ZEND_ENGINE_2_1
+DEF_STRUCT_P_FUNC(`xc_autoglobal_t', , `dnl {{{
+	PROCESS(zend_uint, key_len)
+#ifdef IS_UNICODE
+	PROCESS(zend_uchar, type)
+#endif
+	IFRESTORE(`COPY(key)', `
+		PROC_ZSTRING_L(type, key, key_len)
+	')
+	PROCESS(ulong, h)
+')
+dnl }}}
+#endif
+')
+IFRESTORE(`', `
+#ifdef XCACHE_ERROR_CACHING
+DEF_STRUCT_P_FUNC(`xc_compilererror_t', , `dnl {{{
+	PROCESS(int, type)
+	PROCESS(uint, lineno)
+	PROCESS(int, error_len)
+	PROC_STRING_L(error, error_len)
+')
+dnl }}}
+#endif
+')
+DEF_STRUCT_P_FUNC(`xc_entry_data_php_t', , `dnl {{{
+	IFCOPY(`
+		processor->php_dst = dst;
+		processor->php_src = src;
+	')
+
+	/* skip */
+	DONE(next)
+	PROCESS(xc_hash_value_t, hvalue)
+	PROCESS(xc_md5sum_t, md5)
+	PROCESS(zend_ulong, refcount)
+
+	PROCESS(zend_ulong, hits)
+	PROCESS(size_t, size)
+
+	IFRESTORE(`COPY(op_array_info)', `
+		STRUCT(xc_op_array_info_t, op_array_info)
+	')
+	IFRESTORE(`
+		processor->active_op_array_infos_src = &dst->op_array_info;
+		processor->active_op_array_index = 0;
+	')
+	STRUCT_P(zend_op_array, op_array)
+
+#ifdef HAVE_XCACHE_CONSTANT
+	PROCESS(zend_uint, constinfo_cnt)
+	STRUCT_ARRAY(zend_uint, constinfo_cnt, xc_constinfo_t, constinfos)
+#endif
+
+	PROCESS(zend_uint, funcinfo_cnt)
+	STRUCT_ARRAY(zend_uint, funcinfo_cnt, xc_funcinfo_t, funcinfos)
+
+	PROCESS(zend_uint, classinfo_cnt)
+	STRUCT_ARRAY(zend_uint, classinfo_cnt, xc_classinfo_t, classinfos, , IFRESTORE(`processor->active_class_index'))
+#ifdef ZEND_ENGINE_2_1
+	PROCESS(zend_uint, autoglobal_cnt)
+	IFRESTORE(`
+		COPY(autoglobals)
+	', `
+		STRUCT_ARRAY(zend_uint, autoglobal_cnt, xc_autoglobal_t, autoglobals)
+	')
+#endif
+#ifdef XCACHE_ERROR_CACHING
+	PROCESS(zend_uint, compilererror_cnt)
+	IFRESTORE(`
+		COPY(compilererrors)
+	', `
+		STRUCT_ARRAY(zend_uint, compilererror_cnt, xc_compilererror_t, compilererrors)
+	')
+#endif
+#ifndef ZEND_COMPILE_DELAYED_BINDING
+	PROCESS(zend_bool, have_early_binding)
+#endif
+	PROCESS(zend_bool, have_references)
+')
+dnl }}}
+DEF_STRUCT_P_FUNC(`xc_entry_t', , `dnl {{{
+	/* skip */
+	DONE(next)
+	PROCESS(size_t, size)
+
+	PROCESS(time_t, ctime)
+	PROCESS(time_t, atime)
+	PROCESS(time_t, dtime)
+	PROCESS(long, ttl)
+	PROCESS(zend_ulong, hits)
+	DONE(name) dnl handle in xc_entry_php_t and xc_entry_var_t
+')
+dnl }}}
+DEF_STRUCT_P_FUNC(`xc_entry_php_t', , `dnl {{{
+	STRUCT(xc_entry_t, entry)
+	DISABLECHECK(`
+		PROCESS(int, entry.name.str.len)
+		IFRESTORE(`COPY(entry.name.str.val)', `
+			PROC_STRING_L(entry.name.str.val, entry.name.str.len)
+		')
+	')
+
+	IFCALCCOPY(`COPY(php)', `STRUCT_P(xc_entry_data_php_t, php)')
+
+	IFSTORE(`dst->refcount = 0; DONE(refcount)', `PROCESS(long, refcount)')
+	PROCESS(time_t, file_mtime)
+	PROCESS(size_t, file_size)
+	PROCESS(int, file_device)
+	PROCESS(int, file_inode)
+
+	PROCESS(int, filepath_len)
+	IFRESTORE(`COPY(filepath)', `PROC_STRING_L(filepath, filepath_len)')
+	PROCESS(int, dirpath_len)
+	IFRESTORE(`COPY(dirpath)', `PROC_STRING_L(dirpath, dirpath_len)')
+#ifdef IS_UNICODE
+	PROCESS(int, ufilepath_len)
+	IFRESTORE(`COPY(ufilepath)', `PROC_USTRING_L(ufilepath, ufilepath_len)')
+	PROCESS(int, udirpath_len)
+	IFRESTORE(`COPY(udirpath)', `PROC_USTRING_L(udirpath, udirpath_len)')
+#endif
+')
+dnl }}}
+DEF_STRUCT_P_FUNC(`xc_entry_var_t', , `dnl {{{
+	STRUCT(xc_entry_t, entry)
+
+#ifdef IS_UNICODE
+	PROCESS(zend_uchar, name_type)
+#endif
+	dnl {{{ entry.name
+	DISABLECHECK(`
+#ifdef IS_UNICODE
+		if (src->name_type == IS_UNICODE) {
+			PROCESS(int32_t, entry.name.ustr.len)
+		}
+		else {
+			PROCESS(int, entry.name.str.len)
+		}
+#else
+		PROCESS(int, entry.name.str.len)
+#endif
+		IFRESTORE(`COPY(entry.name.str.val)', `
+#ifdef IS_UNICODE
+			PROC_ZSTRING_L(name_type, entry.name.uni.val, entry.name.uni.len)
+#else
+			PROC_STRING_L(entry.name.str.val, entry.name.str.len)
+#endif
+		')
+	')
+	dnl }}}
+
+	IFDPRINT(`INDENT()`'fprintf(stderr, "zval:value");')
+	STRUCT_P_EX(zval_ptr, dst->value, src->value, `value', `', `&')
+	PROCESS(zend_bool, have_references)
+	DONE(value)
+')
+dnl }}}
+dnl ====================================================
Index: /tags/3.0.0-rc1/processor/head.m4
===================================================================
--- /tags/3.0.0-rc1/processor/head.m4	(revision 1135)
+++ /tags/3.0.0-rc1/processor/head.m4	(revision 1135)
@@ -0,0 +1,554 @@
+dnl {{{ === program start ========================================
+divert(0)
+#include <string.h>
+#include <stdio.h>
+
+#include "php.h"
+#include "zend_extensions.h"
+#include "zend_compile.h"
+#include "zend_API.h"
+#include "zend_ini.h"
+
+/* export: #include "xcache.h" :export */
+#include "xcache.h"
+/* export: #include "mod_cacher/xc_cache.h" :export */
+#include "mod_cacher/xc_cache.h"
+/* export: #include "xcache/xc_shm.h" :export */
+#include "xcache/xc_shm.h"
+/* export: #include "xcache/xc_allocator.h" :export */
+#include "xcache/xc_allocator.h"
+#include "xcache/xc_const_string.h"
+#include "xcache/xc_utils.h"
+#include "util/xc_align.h"
+#include "xc_processor.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_zval_ptr_nullable', `sizeof(zval_ptr_nullable)')
+define(`COUNTOF_zval_ptr_nullable', `1')
+define(`SIZEOF_zend_trait_alias_ptr', `sizeof(zend_trait_alias)')
+define(`COUNTOF_zend_trait_alias_ptr', `1')
+define(`SIZEOF_zend_trait_precedence_ptr', `sizeof(zend_trait_precedence)')
+define(`COUNTOF_zend_trait_precedence_ptr', `1')
+define(`SIZEOF_xc_entry_name_t', `sizeof(xc_entry_name_t)')
+define(`COUNTOF_xc_entry_name_t', `1')
+define(`SIZEOF_xc_ztstring', `sizeof(xc_ztstring)')
+define(`COUNTOF_xc_ztstring', `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)')
+')
+ifdef(`DEBUG_SIZE', `static int xc_totalsize = 0;')
+
+sinclude(builddir`/structinfo.m4')
+
+#ifndef NDEBUG
+#	undef inline
+#define inline
+#endif
+
+typedef zval *zval_ptr;
+typedef zval *zval_ptr_nullable;
+typedef char *xc_ztstring;
+#ifdef ZEND_ENGINE_2_4
+typedef zend_trait_alias *zend_trait_alias_ptr;
+typedef zend_trait_precedence *zend_trait_precedence_ptr;
+#endif
+#ifdef ZEND_ENGINE_2_3
+typedef int last_brk_cont_t;
+#else
+typedef zend_uint last_brk_cont_t;
+#endif
+
+typedef zend_uchar xc_zval_type_t;
+typedef int xc_op_type;
+typedef zend_uchar xc_opcode;
+#ifdef IS_UNICODE
+typedef UChar zstr_uchar;
+#endif
+typedef char  zstr_char;
+
+#define MAX_DUP_STR_LEN 256
+dnl }}}
+/* export: typedef struct _xc_processor_t xc_processor_t; :export {{{ */
+struct _xc_processor_t {
+	char *p;
+	zend_uint size;
+	HashTable strings;
+	HashTable zvalptrs;
+	zend_bool reference; /* enable if to deal with reference */
+	zend_bool have_references;
+	const xc_entry_php_t *entry_php_src;
+	const xc_entry_php_t *entry_php_dst;
+	const xc_entry_data_php_t *php_src;
+	const xc_entry_data_php_t *php_dst;
+	xc_shm_t                  *shm;
+	xc_allocator_t            *allocator;
+	const zend_class_entry *cache_ce;
+	zend_uint cache_class_index;
+
+	const zend_op_array    *active_op_array_src;
+	zend_op_array          *active_op_array_dst;
+	const zend_class_entry *active_class_entry_src;
+	zend_class_entry       *active_class_entry_dst;
+	zend_uint                 active_class_index;
+	zend_uint                 active_op_array_index;
+	const xc_op_array_info_t *active_op_array_infos_src;
+
+	zend_bool readonly_protection; /* wheather it's present */
+IFAUTOCHECK(xc_stack_t allocsizes;)
+};
+/* }}} */
+/* export: typedef struct _xc_dasm_t { const zend_op_array *active_op_array_src; } xc_dasm_t; :export {{{ */
+/* }}} */
+/* {{{ memsetptr */
+IFAUTOCHECK(`dnl
+static void *memsetptr(void *mem, void *content, size_t n)
+{
+	void **p = (void **) mem;
+	void **end = (void **) ((char *) mem + n);
+	while (p < end - sizeof(content)) {
+		*p = content;
+		p += sizeof(content);
+	}
+	if (p < end) {
+		memset(p, -1, end - p);
+	}
+	return mem;
+}
+')
+/* }}} */
+#ifdef HAVE_XCACHE_DPRINT
+static void xc_dprint_indent(int indent) /* {{{ */
+{
+	int i;
+	for (i = 0; i < indent; i ++) {
+		fprintf(stderr, "  ");
+	}
+}
+/* }}} */
+static void xc_dprint_str_len(const char *str, int len) /* {{{ */
+{
+	const unsigned char *p = (const unsigned char *) str;
+	int i;
+	for (i = 0; i < len; i ++) {
+		if (p[i] < 32 || p[i] == 127) {
+			fprintf(stderr, "\\%03o", (unsigned int) p[i]);
+		}
+		else {
+			fputc(p[i], stderr);
+		}
+	}
+}
+/* }}} */
+#endif
+/* {{{ xc_zstrlen_char */
+static inline int xc_zstrlen_char(const_zstr s)
+{
+	return strlen(ZSTR_S(s));
+}
+/* }}} */
+#ifdef IS_UNICODE
+/* {{{ xc_zstrlen_uchar */
+static inline int xc_zstrlen_uchar(zstr s)
+{
+	return u_strlen(ZSTR_U(s));
+}
+/* }}} */
+/* {{{ xc_zstrlen */
+static inline int xc_zstrlen(int type, const_zstr s)
+{
+	return type == IS_UNICODE ? xc_zstrlen_uchar(s) : xc_zstrlen_char(s);
+}
+/* }}} */
+#else
+/* {{{ xc_zstrlen */
+#define xc_zstrlen(dummy, s) xc_zstrlen_char(s)
+/* }}} */
+#endif
+/* {{{ xc_calc_string_n */
+REDEF(`PROCESSOR_TYPE', `calc')
+#undef C_RELAYLINE
+#define C_RELAYLINE
+IFAUTOCHECK(`
+#undef C_RELAYLINE
+#define C_RELAYLINE , __LINE__
+')
+static inline void xc_calc_string_n(xc_processor_t *processor, zend_uchar type, const_zstr str, long size IFAUTOCHECK(`, int relayline')) {
+	pushdef(`__LINE__', `relayline')
+	int realsize = UNISW(size, (type == IS_UNICODE) ? UBYTES(size) : size);
+	long dummy = 1;
+
+	if (realsize > MAX_DUP_STR_LEN) {
+		ALLOC(, char, realsize)
+	}
+	else if (zend_u_hash_add(&processor->strings, type, str, size, (void *) &dummy, sizeof(dummy), NULL) == SUCCESS) {
+		/* new string */
+		ALLOC(, char, realsize)
+	} 
+	IFAUTOCHECK(`
+		else {
+			dnl fprintf(stderr, "dupstr %s\n", ZSTR_S(str));
+		}
+	')
+	popdef(`__LINE__')
+}
+/* }}} */
+/* {{{ xc_store_string_n */
+REDEF(`PROCESSOR_TYPE', `store')
+static inline zstr xc_store_string_n(xc_processor_t *processor, zend_uchar type, const_zstr str, long size IFAUTOCHECK(`, int relayline')) {
+	pushdef(`__LINE__', `relayline')
+	int realsize = UNISW(size, (type == IS_UNICODE) ? UBYTES(size) : size);
+	zstr ret, *pret;
+
+	if (realsize > MAX_DUP_STR_LEN) {
+		ALLOC(ZSTR_V(ret), char, realsize)
+		memcpy(ZSTR_V(ret), ZSTR_V(str), realsize);
+		return ret;
+	}
+
+	if (zend_u_hash_find(&processor->strings, type, str, size, (void **) &pret) == SUCCESS) {
+		return *pret;
+	}
+
+	/* new string */
+	ALLOC(ZSTR_V(ret), char, realsize)
+	memcpy(ZSTR_V(ret), ZSTR_V(str), realsize);
+	zend_u_hash_add(&processor->strings, type, str, size, (void *) &ret, sizeof(zstr), NULL);
+	return ret;
+
+	popdef(`__LINE__')
+}
+/* }}} */
+/* {{{ xc_get_class_num
+ * return class_index + 1
+ */
+static zend_ulong xc_get_class_num(xc_processor_t *processor, zend_class_entry *ce) {
+	zend_ulong i;
+	const xc_entry_data_php_t *php = processor->php_src;
+	zend_class_entry *ceptr;
+
+	if (processor->cache_ce == ce) {
+		return processor->cache_class_index + 1;
+	}
+	for (i = 0; i < php->classinfo_cnt; i ++) {
+		ceptr = CestToCePtr(php->classinfos[i].cest);
+		if (ZCEP_REFCOUNT_PTR(ceptr) == ZCEP_REFCOUNT_PTR(ce)) {
+			processor->cache_ce = ceptr;
+			processor->cache_class_index = i;
+			return i + 1;
+		}
+	}
+	assert(0);
+	return (zend_ulong) -1;
+}
+define(`xc_get_class_num', `xc_get_class_numNOTDEFINED')
+/* }}} */
+/* {{{ xc_get_class */
+#ifdef ZEND_ENGINE_2
+static zend_class_entry *xc_get_class(xc_processor_t *processor, zend_ulong class_num) {
+	/* must be parent or currrent class */
+	assert(class_num <= processor->active_class_index + 1);
+	return CestToCePtr(processor->php_dst->classinfos[class_num - 1].cest);
+}
+#endif
+define(`xc_get_class', `xc_get_classNOTDEFINED')
+/* }}} */
+#ifdef ZEND_ENGINE_2
+/* fix method on store */
+static void xc_fix_method(xc_processor_t *processor, zend_op_array *dst TSRMLS_DC) /* {{{ */
+{
+	zend_function *zf = (zend_function *) dst;
+	zend_class_entry *ce = processor->active_class_entry_dst;
+	const zend_class_entry *srcce = processor->active_class_entry_src;
+
+	/* 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 {
+	pushdef(`SET_IF_SAME_NAMEs', `
+		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);
+#ifdef ZEND_CALLSTATIC_FUNC_NAME
+		SET_IF_SAME_NAME(__callstatic);
+#endif
+#if defined(ZEND_ENGINE_2_2) || PHP_MAJOR_VERSION >= 6
+		SET_IF_SAME_NAME(__tostring);
+#endif
+	')
+#ifdef IS_UNICODE
+		if (UG(unicode)) {
+#define SET_IF_SAME_NAME(member) \
+			do { \
+				if (srcce->member && u_strcmp(ZSTR_U(zf->common.function_name), ZSTR_U(srcce->member->common.function_name)) == 0) { \
+					ce->member = zf; \
+				} \
+			} \
+			while(0)
+
+			SET_IF_SAME_NAMEs()
+#undef SET_IF_SAME_NAME
+		}
+		else
+#endif
+		do {
+#define SET_IF_SAME_NAME(member) \
+			do { \
+				if (srcce->member && strcmp(ZSTR_S(zf->common.function_name), ZSTR_S(srcce->member->common.function_name)) == 0) { \
+					ce->member = zf; \
+				} \
+			} \
+			while(0)
+
+			SET_IF_SAME_NAMEs()
+#undef SET_IF_SAME_NAME
+		} while (0);
+
+	popdef(`SET_IF_SAME_NAMEs')
+
+	}
+}
+/* }}} */
+#endif
+/* {{{ call op_array ctor handler */
+extern zend_bool xc_have_op_array_ctor;
+static void xc_zend_extension_op_array_ctor_handler(zend_extension *extension, zend_op_array *op_array TSRMLS_DC)
+{
+	if (extension->op_array_ctor) {
+		extension->op_array_ctor(op_array);
+	}
+}
+/* }}} */
+/* {{{ field name checker */
+IFAUTOCHECK(`dnl
+static int xc_check_names(const char *file, int line, const char *functionName, const char **assert_names, int assert_names_count, HashTable *done_names)
+{
+	int errors = 0;
+	if (assert_names_count) {
+		int i;
+		Bucket *b;
+
+		for (i = 0; i < assert_names_count; ++i) {
+			if (!zend_u_hash_exists(done_names, IS_STRING, assert_names[i], strlen(assert_names[i]) + 1)) {
+				fprintf(stderr
+					, "Error: missing field at %s `#'%d %s`' : %s\n"
+					, file, line, functionName
+					, assert_names[i]
+					);
+				++errors;
+			}
+		}
+
+		for (b = done_names->pListHead; b != NULL; b = b->pListNext) {
+			int known = 0;
+			for (i = 0; i < assert_names_count; ++i) {
+				if (strcmp(assert_names[i], BUCKET_KEY_S(b)) == 0) {
+					known = 1;
+					break;
+				}
+			}
+			if (!known) {
+				fprintf(stderr
+					, "Error: unknown field at %s `#'%d %s`' : %s\n"
+					, file, line, functionName
+					, BUCKET_KEY_S(b)
+					);
+				++errors;
+			}
+		}
+	}
+	return errors;
+}
+')
+/* }}} */
+dnl ================ export API
+define(`DEFINE_STORE_API', `
+/* export: $1 *xc_processor_store_$1(xc_shm_t *shm, xc_allocator_t *allocator, $1 *src TSRMLS_DC); :export {{{ */
+$1 *xc_processor_store_$1(xc_shm_t *shm, xc_allocator_t *allocator, $1 *src TSRMLS_DC) {
+	$1 *dst;
+	xc_processor_t processor;
+
+	memset(&processor, 0, sizeof(processor));
+	processor.reference = 1;
+	processor.shm = shm;
+	processor.allocator = allocator;
+
+	IFAUTOCHECK(`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_$1(&processor, src TSRMLS_CC);
+		if (processor.reference) {
+			zend_hash_destroy(&processor.zvalptrs);
+		}
+		zend_hash_destroy(&processor.strings);
+	}
+	src->ifelse(
+		`$1', `xc_entry_data_php_t', `',
+		`', `', entry.)size = processor.size;
+	ifelse(
+		`$1', `xc_entry_var_t', `src->have_references = processor.have_references;',
+		`$1', `xc_entry_data_php_t', `src->have_references = processor.have_references;'
+	)
+
+	IFAUTOCHECK(`xc_stack_reverse(&processor.allocsizes);')
+	/* store {{{ */
+	{
+		IFAUTOCHECK(`char *oldp;')
+		zend_hash_init(&processor.strings, 0, NULL, NULL, 0);
+		if (processor.reference) {
+			zend_hash_init(&processor.zvalptrs, 0, NULL, NULL, 0);
+		}
+
+		/* allocator :) */
+		processor.p = (char *) processor.allocator->vtable->malloc(processor.allocator, processor.size);
+		if (processor.p == NULL) {
+			dst = NULL;
+			goto err_alloc;
+		}
+		IFAUTOCHECK(`oldp = processor.p;')
+		assert(processor.p == (char *) ALIGN(processor.p));
+
+		/* allocate */
+		dst = ($1 *) processor.p;
+		processor.p = (char *) ALIGN(processor.p + sizeof(dst[0]));
+
+		xc_store_$1(&processor, dst, src TSRMLS_CC);
+		IFAUTOCHECK(` {
+			size_t unexpected = processor.p - oldp;
+			size_t expected = processor.size;
+			if (unexpected != processor.size) {
+				fprintf(stderr, "unexpected:%lu - expected:%lu = %ld != 0\n", (unsigned long) unexpected, (unsigned long) expected, (long) unexpected - expected);
+				abort();
+			}
+		}')
+err_alloc:
+		if (processor.reference) {
+			zend_hash_destroy(&processor.zvalptrs);
+		}
+		zend_hash_destroy(&processor.strings);
+	}
+	/* }}} */
+
+	IFAUTOCHECK(`xc_stack_destroy(&processor.allocsizes);')
+
+	return dst;
+}
+/* }}} */
+')
+DEFINE_STORE_API(`xc_entry_var_t')
+DEFINE_STORE_API(`xc_entry_php_t')
+DEFINE_STORE_API(`xc_entry_data_php_t')
+/* export: xc_entry_php_t *xc_processor_restore_xc_entry_php_t(xc_entry_php_t *dst, const xc_entry_php_t *src TSRMLS_DC); :export {{{ */
+xc_entry_php_t *xc_processor_restore_xc_entry_php_t(xc_entry_php_t *dst, const xc_entry_php_t *src TSRMLS_DC) {
+	xc_processor_t processor;
+
+	memset(&processor, 0, sizeof(processor));
+	xc_restore_xc_entry_php_t(&processor, dst, src TSRMLS_CC);
+
+	return dst;
+}
+/* }}} */
+/* export: xc_entry_data_php_t *xc_processor_restore_xc_entry_data_php_t(const xc_entry_php_t *entry_php, xc_entry_data_php_t *dst, const xc_entry_data_php_t *src, zend_bool readonly_protection TSRMLS_DC); :export {{{ */
+xc_entry_data_php_t *xc_processor_restore_xc_entry_data_php_t(const xc_entry_php_t *entry_php, xc_entry_data_php_t *dst, const xc_entry_data_php_t *src, zend_bool readonly_protection TSRMLS_DC) {
+	xc_processor_t processor;
+
+	memset(&processor, 0, sizeof(processor));
+	processor.readonly_protection = readonly_protection;
+	/* this function is used for php data only */
+	if (src->have_references) {
+		processor.reference = 1;
+	}
+	processor.entry_php_src = entry_php;
+
+	if (processor.reference) {
+		zend_hash_init(&processor.zvalptrs, 0, NULL, NULL, 0);
+	}
+	xc_restore_xc_entry_data_php_t(&processor, dst, src TSRMLS_CC);
+	if (processor.reference) {
+		zend_hash_destroy(&processor.zvalptrs);
+	}
+	return dst;
+}
+/* }}} */
+/* export: xc_entry_var_t *xc_processor_restore_xc_entry_var_t(xc_entry_var_t *dst, const xc_entry_var_t *src TSRMLS_DC); :export {{{ */
+xc_entry_var_t *xc_processor_restore_xc_entry_var_t(xc_entry_var_t *dst, const xc_entry_var_t *src TSRMLS_DC) {
+	xc_processor_t processor;
+
+	memset(&processor, 0, sizeof(processor));
+	xc_restore_xc_entry_var_t(&processor, dst, src TSRMLS_CC);
+
+	return dst;
+}
+/* }}} */
+/* export: zval *xc_processor_restore_zval(zval *dst, const zval *src, zend_bool have_references TSRMLS_DC); :export {{{ */
+zval *xc_processor_restore_zval(zval *dst, const zval *src, zend_bool have_references TSRMLS_DC) {
+	xc_processor_t processor;
+
+	memset(&processor, 0, sizeof(processor));
+	processor.reference = have_references;
+
+	if (processor.reference) {
+		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);
+	if (processor.reference) {
+		zend_hash_destroy(&processor.zvalptrs);
+	}
+
+	return dst;
+}
+/* }}} */
+/* export: void xc_dprint(xc_entry_php_t *src, int indent TSRMLS_DC); :export {{{ */
+#ifdef HAVE_XCACHE_DPRINT
+void xc_dprint(xc_entry_php_t *src, int indent TSRMLS_DC) {
+	IFDPRINT(`INDENT()`'fprintf(stderr, "xc_entry_php_t:src");')
+	xc_dprint_xc_entry_php_t(src, indent TSRMLS_CC);
+}
+#endif
+/* }}} */
Index: /tags/3.0.0-rc1/processor/main.m4
===================================================================
--- /tags/3.0.0-rc1/processor/main.m4	(revision 1132)
+++ /tags/3.0.0-rc1/processor/main.m4	(revision 1132)
@@ -0,0 +1,286 @@
+divert(-1)
+dnl ================ start ======================
+dnl define(`XCACHE_ENABLE_TEST')
+dnl define(`DEBUG_SIZE')
+define(`USEMEMCPY')
+
+dnl ================ main
+
+dnl {{{ basic
+define(`REDEF', `ifdef(`$1', `undefine(`$1')') define(`$1', `$2')')
+define(`MAKE_MACRONAME', `translit(`$1', ` ():
+', `_____')')
+define(`ONCE', `ifdef(MAKE_MACRONAME(`ONCE $1'), `', `define(MAKE_MACRONAME(`ONCE $1'))$1')')
+define(`m4_errprint', `ONCE(`errprint(`$1
+')')')
+ifdef(`len', `
+define(`m4_len', defn(`len'))
+undefine(`len')
+')
+define(`ZEND_STRS', `($1), (sizeof($1))')
+define(`ZEND_STRL', `($1), (sizeof($1) - 1)')
+define(`DST', `dst->$1')
+define(`SRC', `src->$1')
+dnl ============
+define(`INDENT', `xc_dprint_indent(indent);')
+dnl }}}
+dnl {{{ ALLOC(1:dst, 2:type, 3:count=1, 4:clean=false, 5:realtype=$2)
+define(`ALLOC', `
+	pushdef(`COUNT', `ifelse(`$3', `', `1', `$3')')
+	pushdef(`SIZE', `sizeof($2)ifelse(`$3', `', `', ` * $3')')
+	pushdef(`REALTYPE', `ifelse(`$5', , `$2', `$5')')
+	/* allocate */
+	IFCALC(`
+		IFAUTOCHECK(`
+			xc_stack_push(&processor->allocsizes, (void *) (long) (SIZE));
+			xc_stack_push(&processor->allocsizes, (void *) (long) (__LINE__));
+		')
+		processor->size = (size_t) ALIGN(processor->size);
+		processor->size += SIZE;
+	')
+	IFSTORE(`
+		IFAUTOCHECK(`{
+			if (!xc_stack_count(&processor->allocsizes)) {
+				fprintf(stderr, "mismatch `$@' at line %d\n", __LINE__);
+			}
+			else {
+				unsigned long expect = (unsigned long) xc_stack_pop(&processor->allocsizes);
+				unsigned long atline = (unsigned long) xc_stack_pop(&processor->allocsizes);
+				unsigned long real = SIZE;
+				if (expect != real) {
+					fprintf(stderr, "mismatch `$@' at line %d(was %lu): real %lu - expect %lu = %lu\n", __LINE__, atline, real, expect, real - expect);
+				}
+			}
+		}')
+		ifdef(`DEBUG_SIZE', ` {
+			void *oldp = processor->p;
+		')
+		$1 = (REALTYPE *) (processor->p = (char *) ALIGN(processor->p));
+		ifelse(`$4', `', `
+				IFAUTOCHECK(`memsetptr($1, (void *) (unsigned long) __LINE__, SIZE);')
+			', `
+				memset($1, 0, SIZE);
+		')
+		processor->p += SIZE;
+
+		ifdef(`DEBUG_SIZE', `
+			xc_totalsize += (char *) processor->p - (char *) oldp;
+			fprintf(stderr, "%d\t%d\t`'SIZE()\n", (char *) processor->p - (char *) oldp, xc_totalsize);
+		}
+		')
+	')
+	IFRESTORE(`ifelse(`$4', `', `
+			ifelse(
+				REALTYPE*COUNT, `zval*1', `ALLOC_ZVAL($1);',
+				REALTYPE*COUNT, `HashTable*1', `ALLOC_HASHTABLE($1);',
+				`', `', `$1 = (REALTYPE *) emalloc(SIZE);')
+			IFAUTOCHECK(`memsetptr($1, (void *) __LINE__, SIZE);')
+		', `
+			$1 = (REALTYPE *) ecalloc(COUNT, sizeof($2));
+		')
+	')
+	popdef(`REALTYPE')
+	popdef(`COUNT')
+	popdef(`SIZE')
+')
+dnl CALLOC(1:dst, 2:type [, 3:count=1, 4:realtype=$2 ])
+define(`CALLOC', `ALLOC(`$1', `$2', `$3', `1', `$4')')
+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_ulong) $2);')
+#ifdef IS_UNICODE
+		IFDASM(`add_assoc_unicodel_ex(dst, ZEND_STRS("$3"), ZSTR_U($2->name), $2->name_length, 1);')
+#else
+		IFDASM(`add_assoc_stringl_ex(dst, ZEND_STRS("$3"), (char *) $2->name, $2->name_length, 1);')
+#endif
+	}
+	else {
+		COPYNULL_EX(`$1', `$3')
+	}
+')
+dnl }}}
+dnl {{{ IFAUTOCHECKEX
+define(`IFAUTOCHECKEX', `ifdef(`XCACHE_ENABLE_TEST', `$1', `$2')')
+dnl }}}
+dnl {{{ IFAUTOCHECK
+define(`IFAUTOCHECK', `IFAUTOCHECKEX(`
+#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 *) processor->shm->handlers->to_readonly(processor->shm, (char *)$2);
+')')
+define(`UNFIXPOINTER', `UNFIXPOINTER_EX(`$1', `dst->$2')')
+define(`UNFIXPOINTER_EX', `IFSTORE(`
+	$2 = ($1 *) processor->shm->handlers->to_readwrite(processor->shm, (char *)$2);
+')')
+dnl }}}
+dnl {{{ COPY
+define(`COPY', `IFNOTMEMCPY(`IFCOPY(`dst->$1 = SRC(`$1');')')DONE(`$1')')
+dnl }}}
+dnl {{{ COPY_N_EX
+define(`COPY_N_EX', `
+	ALLOC(`dst->$3', `$2', `SRC(`$1')')
+	IFCOPY(`
+		memcpy(dst->$3, SRC(`$3'), sizeof(dst->$3[0]) * SRC(`$1'));
+		')
+')
+dnl }}}
+dnl {{{ COPY_N
+define(`COPY_N', `COPY_N_EX(`$1',`$2')DONE(`$1')')
+dnl }}}
+dnl {{{ COPYPOINTER
+define(`COPYPOINTER', `COPY(`$1')')
+dnl }}}
+dnl {{{ COPYARRAY_EX
+define(`COPYARRAY_EX', `IFNOTMEMCPY(`IFCOPY(`memcpy(dst->$1, SRC(`$1'), sizeof(dst->$1));')')')
+dnl }}}
+dnl {{{ COPYARRAY
+define(`COPYARRAY', `COPYARRAY_EX(`$1',`$2')DONE(`$1')')
+dnl }}}
+dnl {{{ SETNULL_EX
+define(`SETNULL_EX', `IFCOPY(`$1 = NULL;')')
+define(`SETNULL', `SETNULL_EX(`dst->$1')DONE(`$1')')
+dnl }}}
+dnl {{{ SETZERO_EX
+define(`SETZERO_EX', `IFCOPY(`$1 = 0;')')
+define(`SETZERO', `SETZERO_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;')')
+	assert(patsubst($1, dst, src) == NULL);
+')
+dnl }}}
+dnl {{{ COPYNULL(1:elm)
+define(`COPYNULL', `
+	COPYNULL_EX(`dst->$1', `$1')DONE(`$1')
+')
+dnl }}}
+dnl {{{ COPYZERO_EX(1:dst, 2:elm-name)
+define(`COPYZERO_EX', `
+	IFDASM(`add_assoc_long_ex(dst, ZEND_STRS("$2"), 0);')
+	IFNOTMEMCPY(`IFCOPY(`$1 = 0;')')
+	assert(patsubst($1, dst, src) == 0);
+')
+dnl }}}
+dnl {{{ COPYZERO(1:elm)
+define(`COPYZERO', `
+	COPYZERO_EX(`dst->$1', `$1')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)', `define(`item_'defn(`i'))popdef(`item_'defn(`i'))')dnl
+foreach(`i', `($1)', `popdef(`item_'defn(`i'))')dnl
+')
+dnl }}}
+dnl {{{ DONE_*
+define(`DONE_SIZE', `IFAUTOCHECK(`dnl
+	xc_autocheck_done_size += $1`';
+	xc_autocheck_done_count ++;
+')')
+define(`DONE', `
+	define(`ELEMENTS_DONE', defn(`ELEMENTS_DONE')`,"$1"')
+	IFAUTOCHECK(`dnl
+		if (zend_u_hash_exists(&xc_autocheck_done_names, IS_STRING, "$1", sizeof("$1"))) {
+			fprintf(stderr
+				, "duplicate field at %s `#'%d FUNC_NAME`' : %s\n"
+				, __FILE__, __LINE__
+				, "$1"
+				);
+		}
+		else {
+			zend_uchar b = 1;
+			zend_hash_add(&xc_autocheck_done_names, "$1", sizeof("$1"), (void*)&b, sizeof(b), NULL);
+		}
+	')
+	DONE_SIZE(`sizeof(SRC(`$1'))')
+')
+define(`DISABLECHECK', `
+	pushdef(`DONE_SIZE')
+	pushdef(`DONE')
+$1
+	popdef(`DONE_SIZE')
+	popdef(`DONE')
+')
+dnl }}}
+dnl {{{ IF**
+define(`IFCALC', `ifelse(PROCESSOR_TYPE, `calc', `$1', `$2')')
+define(`IFSTORE', `ifelse(PROCESSOR_TYPE, `store', `$1', `$2')')
+define(`IFCALCSTORE', `IFSTORE(`$1', `IFCALC(`$1', `$2')')')
+define(`IFRESTORE', `ifelse(PROCESSOR_TYPE, `restore', `$1', `$2')')
+define(`IFCOPY', `IFSTORE(`$1', `IFRESTORE(`$1', `$2')')')
+define(`IFCALCCOPY', `IFCALC(`$1', `IFCOPY(`$1', `$2')')')
+define(`IFDPRINT', `ifelse(PROCESSOR_TYPE, `dprint', `$1', `$2')')
+define(`IFASM', `ifelse(PROCESSOR_TYPE, `asm', `$1', `$2')')
+define(`IFDASM', `ifelse(PROCESSOR_TYPE, `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_var_t')
+EXPORT(`xc_entry_php_t')
+EXPORT(`xc_entry_data_php_t')
+EXPORT(`zval')
+
+include(srcdir`/processor/hashtable.m4')
+include(srcdir`/processor/string.m4')
+include(srcdir`/processor/struct.m4')
+include(srcdir`/processor/process.m4')
+include(srcdir`/processor/head.m4')
+
+define(`IFNOTMEMCPY', `ifdef(`USEMEMCPY', `', `$1')')
+REDEF(`PROCESSOR_TYPE', `calc') include(srcdir`/processor/processor.m4')
+pushdef(`xc_get_class_num', ``xc_get_class_num'($@)')
+REDEF(`PROCESSOR_TYPE', `store') include(srcdir`/processor/processor.m4')
+popdef(`xc_get_class_num')
+pushdef(`xc_get_class', ``xc_get_class'($@)')
+REDEF(`PROCESSOR_TYPE', `restore') include(srcdir`/processor/processor.m4')
+popdef(`xc_get_class')
+
+REDEF(`IFNOTMEMCPY', `$1')
+#ifdef HAVE_XCACHE_DPRINT
+REDEF(`PROCESSOR_TYPE', `dprint') include(srcdir`/processor/processor.m4')
+#endif /* HAVE_XCACHE_DPRINT */
+#ifdef HAVE_XCACHE_DISASSEMBLER
+REDEF(`PROCESSOR_TYPE', `dasm') include(srcdir`/processor/processor.m4')
+#endif /* HAVE_XCACHE_DISASSEMBLER */
+#ifdef HAVE_XCACHE_ASSEMBLER
+REDEF(`PROCESSOR_TYPE', `asm') include(srcdir`/processor/processor.m4')
+#endif /* HAVE_XCACHE_ASSEMBLER */
+
+ifdef(`EXIT_PENDING', `m4exit(EXIT_PENDING)')
Index: /tags/3.0.0-rc1/processor/struct.m4
===================================================================
--- /tags/3.0.0-rc1/processor/struct.m4	(revision 1112)
+++ /tags/3.0.0-rc1/processor/struct.m4	(revision 1112)
@@ -0,0 +1,237 @@
+define(`pushdefFUNC_NAME', `
+	pushdef(`FUNC_NAME', `xc_`'PROCESSOR_TYPE`'_`'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(   `xc_processor_t *processor, const $1 * const src')
+		IFSTORE(  `xc_processor_t *processor, $1 *dst, const $1 * const src')
+		IFRESTORE(`xc_processor_t *processor, $1 *dst, const $1 * const src')
+		IFDASM(   `xc_dasm_t *dasm, 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')
+		IFAUTOCHECK(`
+			/* {{{ init assert */
+			ifdef(`SIZEOF_$1', , `m4_errprint(`Warning: missing SIZEOF_$1, safe to ignore')')
+			ifdef(`COUNTOF_$1', , `m4_errprint(`Warning: missing COUNTOF_$1, safe to ignore')')
+			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 xc_autocheck_assert_size = SIZEOF_$1, assert_count = COUNTOF_$1;
+			int xc_autocheck_done_size = 0, xc_autocheck_done_count = 0;
+			ifdef(`ELEMENTSOF_$1', `
+				const char *xc_autocheck_assert_names[] = { ELEMENTSOF_$1 };
+				size_t xc_autocheck_assert_names_count = sizeof(xc_autocheck_assert_names) / sizeof(xc_autocheck_assert_names[0]);
+			', `
+				const char **xc_autocheck_assert_names = NULL;
+				size_t xc_autocheck_assert_names_count = 0;
+			')
+			zend_bool xc_autocheck_skip = 0;
+			HashTable xc_autocheck_done_names;
+			zend_hash_init(&xc_autocheck_done_names, 0, NULL, NULL, 0);
+			/* }}} */
+			IFRESTORE(`assert(xc_is_shm(src));')
+			IFCALCSTORE(`assert(!xc_is_shm(src));')
+			do {
+		')
+		ifdef(`SIZEOF_$1', , `m4_errprint(`AUTOCHECK WARN: $1: missing structinfo, dont panic')')
+
+		ifdef(`USEMEMCPY', `IFCOPY(`
+			memcpy(dst, src, sizeof($1));
+			do {
+		')')
+
+		IFDPRINT(`
+			fprintf(stderr, "%s", "{\n");
+			indent ++;
+		')
+		$3`'
+		IFDPRINT(`
+			indent --;
+			INDENT()fprintf(stderr, "}\n");
+		')
+		IFAUTOCHECK(`
+		/* {{{ autocheck */
+		if (!xc_autocheck_skip) {
+			int name_check_errors = xc_check_names(__FILE__, __LINE__, "FUNC_NAME", xc_autocheck_assert_names, xc_autocheck_assert_names_count, &xc_autocheck_done_names);
+
+			if (xc_autocheck_done_count != assert_count) {
+				fprintf(stderr
+					, "count assertion failed at %s `#'%d FUNC_NAME`' : unexpected:%d - expecting:%d = %d != 0\n"
+					, __FILE__, __LINE__
+					, xc_autocheck_done_count, assert_count, xc_autocheck_done_count - assert_count
+					);
+			}
+			if (xc_autocheck_done_size != xc_autocheck_assert_size) {
+				fprintf(stderr
+					, "size assertion failed at %s `#'%d FUNC_NAME`' : unexpected:%d - expecting:%d = %d != 0\n"
+					, __FILE__, __LINE__
+					, xc_autocheck_done_size, xc_autocheck_assert_size, xc_autocheck_done_size - xc_autocheck_assert_size
+					);
+			}
+			if (name_check_errors || xc_autocheck_done_count != assert_count || xc_autocheck_done_size != xc_autocheck_assert_size) {
+				assert(0);
+			}
+		}
+		zend_hash_destroy(&xc_autocheck_done_names);
+		/* }}} */
+		')
+		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: ====' PROCESSOR_TYPE `$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);
+		')')
+		IFAUTOCHECK(`
+			} 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(`AUTOCHECK ERROR: Unknown struct "'ifelse(`$5', `', `$1', `$5')`"')define(`EXIT_PENDING', 1)')
+	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(   `dasm, 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')) {
+		IFDPRINT(`INDENT()`'fprintf(stderr, "$1:$2 ");')
+		STRUCT_P_EX(`$1', `dst->$2', `SRC(`$2')', `$2', `$3')
+	}
+	else {
+		IFDPRINT(`INDENT()`'fprintf(stderr, "$1:$2:\tNULL\n");')
+		COPYNULL_EX(`dst->$2', `$2')
+	}
+	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(1:count_type, 2:count, 3:type, 4:elm, 5:name=type, 6:loopcounter)
+define(`STRUCT_ARRAY', `
+	if (SRC(`$4')) {
+		ifelse(
+			`$6', `', `ifelse(`$1', `', `size_t', `$1') i; pushdef(`LOOPCOUNTER', `i')',
+			`', `', `pushdef(`LOOPCOUNTER', `$6')')
+		pushdefFUNC_NAME(`$3', `$5')
+		IFDASM(`
+			zval *arr;
+			ALLOC_INIT_ZVAL(arr);
+			array_init(arr);
+
+			for (LOOPCOUNTER = 0;
+					ifelse(`$2', `', `SRC(`$4[LOOPCOUNTER]')',
+					`', `', `LOOPCOUNTER < SRC(`$2')');
+					++LOOPCOUNTER) {
+				zval *zv;
+
+				ALLOC_INIT_ZVAL(zv);
+				array_init(zv);
+				FUNC_NAME (dasm, zv, &(SRC(`$4[LOOPCOUNTER]')) TSRMLS_CC);
+				add_next_index_zval(arr, zv);
+			}
+			add_assoc_zval_ex(dst, ZEND_STRS("$4"), arr);
+		', `
+			dnl find count with NULL
+			ifelse(`$2', `', `
+				size_t count = 0;
+				while (SRC(`$4[count]')) {
+					++count;
+				}
+				++count;
+				pushdef(`ARRAY_ELEMENT_COUNT', `count')
+			',
+			`', `', `pushdef(`ARRAY_ELEMENT_COUNT', `SRC(`$2')')')
+			ALLOC(`dst->$4', `$3', `ARRAY_ELEMENT_COUNT')
+			popdef(`ARRAY_ELEMENT_COUNT')
+
+			for (LOOPCOUNTER = 0;
+					ifelse(`$2', `', `SRC(`$4[LOOPCOUNTER]')',
+					`', `', `LOOPCOUNTER < SRC(`$2')');
+					++LOOPCOUNTER) {
+				DISABLECHECK(`
+					STRUCT(`$3', `$4[LOOPCOUNTER]', `$5')
+				')
+			}
+			dnl the end marker
+			ifelse(`$2', `', `IFCOPY(`DST(`$4[LOOPCOUNTER]') = NULL;')')
+		')dnl IFDASM
+		DONE(`$4')
+		popdef(`FUNC_NAME')
+		popdef(`LOOPCOUNTER')
+	}
+	else {
+		COPYNULL(`$4')
+	}
+')
+dnl }}}
Index: /tags/3.0.0-rc1/mod_cacher/xc_cacher.c
===================================================================
--- /tags/3.0.0-rc1/mod_cacher/xc_cacher.c	(revision 1146)
+++ /tags/3.0.0-rc1/mod_cacher/xc_cacher.c	(revision 1146)
@@ -0,0 +1,3803 @@
+#if 0
+#define XCACHE_DEBUG
+#endif
+
+#if 0
+#define SHOW_DPRINT
+#endif
+
+/* {{{ macros */
+#include "xc_cacher.h"
+#include "xc_cache.h"
+#include "xcache.h"
+#include "xc_processor.h"
+#include "xcache_globals.h"
+#include "xcache/xc_extension.h"
+#include "xcache/xc_ini.h"
+#include "xcache/xc_utils.h"
+#include "xcache/xc_sandbox.h"
+#include "util/xc_trace.h"
+#include "util/xc_vector.h"
+#include "util/xc_align.h"
+
+#include "php.h"
+#include "ext/standard/info.h"
+#include "ext/standard/md5.h"
+#ifdef ZEND_ENGINE_2_1
+#include "ext/date/php_date.h"
+#endif
+#include "ext/standard/php_math.h"
+#include "SAPI.h"
+
+#define ECALLOC_N(x, n) ((x) = ecalloc(n, sizeof((x)[0])))
+#define ECALLOC_ONE(x) ECALLOC_N(x, 1)
+#define VAR_ENTRY_EXPIRED(pentry) ((pentry)->ttl && XG(request_time) > (pentry)->ctime + (time_t) (pentry)->ttl)
+#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_EX(x) \
+	xc_lock((x)->lck); \
+	zend_try { \
+		do
+#define LEAVE_LOCK_EX(x) \
+		while (0); \
+	} zend_catch { \
+		catched = 1; \
+	} zend_end_try(); \
+	xc_unlock((x)->lck)
+
+#define ENTER_LOCK(x) do { \
+	int catched = 0; \
+	ENTER_LOCK_EX(x)
+#define LEAVE_LOCK(x) \
+	LEAVE_LOCK_EX(x); \
+	if (catched) { \
+		zend_bailout(); \
+	} \
+} while(0)
+/* }}} */
+
+struct _xc_hash_t { /* {{{ */
+	size_t bits;
+	size_t size;
+	xc_hash_value_t mask;
+};
+/* }}} */
+struct _xc_cached_t { /* {{{ stored in shm */
+	int cacheid;
+
+	time_t     compiling;
+	time_t     disabled;
+	zend_ulong updates;
+	zend_ulong hits;
+	zend_ulong skips;
+	zend_ulong ooms;
+	zend_ulong errors;
+
+	xc_entry_t **entries;
+	int entries_count;
+	xc_entry_data_php_t **phps;
+	int phps_count;
+	xc_entry_t *deletes;
+	int deletes_count;
+
+	time_t     last_gc_deletes;
+	time_t     last_gc_expires;
+
+	time_t     hits_by_hour_cur_time;
+	zend_uint  hits_by_hour_cur_slot;
+	zend_ulong hits_by_hour[24];
+	time_t     hits_by_second_cur_time;
+	zend_uint  hits_by_second_cur_slot;
+	zend_ulong hits_by_second[5];
+};
+/* }}} */
+typedef struct { /* {{{ xc_cache_t: only cache info, not in shm */
+	int cacheid;
+	xc_hash_t  *hcache; /* hash to cacheid */
+
+	struct _xc_lock_t  *lck;
+	struct _xc_shm_t   *shm; /* which shm contains us */
+	xc_allocator_t *allocator;
+
+	xc_hash_t  *hentry; /* hash settings to entry */
+	xc_hash_t  *hphp;   /* hash settings to php */
+	xc_cached_t *cached;
+} xc_cache_t;
+/* }}} */
+
+/* {{{ globals */
+static char *xc_shm_scheme = NULL;
+static char *xc_mmap_path = NULL;
+
+static zend_bool xc_admin_enable_auth = 1;
+static xc_hash_t xc_php_hcache = { 0, 0, 0 };
+static xc_hash_t xc_php_hentry = { 0, 0, 0 };
+static xc_hash_t xc_var_hcache = { 0, 0, 0 };
+static xc_hash_t xc_var_hentry = { 0, 0, 0 };
+
+static zend_ulong xc_php_ttl    = 0;
+static zend_ulong xc_var_maxttl = 0;
+
+enum { xc_deletes_gc_interval = 120 };
+static zend_ulong xc_php_gc_interval = 0;
+static zend_ulong xc_var_gc_interval = 0;
+
+static char *xc_php_allocator = NULL;
+static char *xc_var_allocator = NULL;
+
+/* 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 time_t xc_init_time = 0;
+static long unsigned xc_init_instance_id = 0;
+#ifdef ZTS
+static long unsigned xc_init_instance_subid = 0;
+#endif
+static zend_compile_file_t *old_compile_file = NULL;
+
+static zend_bool xc_readonly_protection = 0;
+
+static zend_ulong xc_var_namespace_mode = 0;
+static char *xc_var_namespace = NULL;
+
+
+zend_bool xc_have_op_array_ctor = 0;
+/* }}} */
+
+typedef enum { XC_TYPE_PHP, XC_TYPE_VAR } xc_entry_type_t;
+
+/* any function in *_unlocked is only safe be called within locked (single thread access) area */
+
+static void xc_php_add_unlocked(xc_cached_t *cached, xc_entry_data_php_t *php) /* {{{ */
+{
+	xc_entry_data_php_t **head = &(cached->phps[php->hvalue]);
+	php->next = *head;
+	*head = php;
+	cached->phps_count ++;
+}
+/* }}} */
+static xc_entry_data_php_t *xc_php_store_unlocked(xc_cache_t *cache, xc_entry_data_php_t *php TSRMLS_DC) /* {{{ */
+{
+	xc_entry_data_php_t *stored_php;
+
+	php->hits     = 0;
+	php->refcount = 0;
+	stored_php = xc_processor_store_xc_entry_data_php_t(cache->shm, cache->allocator, php TSRMLS_CC);
+	if (stored_php) {
+		xc_php_add_unlocked(cache->cached, stored_php);
+		return stored_php;
+	}
+	else {
+		cache->cached->ooms ++;
+		return NULL;
+	}
+}
+/* }}} */
+static xc_entry_data_php_t *xc_php_find_unlocked(xc_cached_t *cached, xc_entry_data_php_t *php TSRMLS_DC) /* {{{ */
+{
+	xc_entry_data_php_t *p;
+	for (p = cached->phps[php->hvalue]; p; p = (xc_entry_data_php_t *) p->next) {
+		if (memcmp(&php->md5.digest, &p->md5.digest, sizeof(php->md5.digest)) == 0) {
+			p->hits ++;
+			return p;
+		}
+	}
+	return NULL;
+}
+/* }}} */
+static void xc_php_free_unlocked(xc_cache_t *cache, xc_entry_data_php_t *php) /* {{{ */
+{
+	cache->allocator->vtable->free(cache->allocator, (xc_entry_data_php_t *)php);
+}
+/* }}} */
+static void xc_php_addref_unlocked(xc_entry_data_php_t *php) /* {{{ */
+{
+	php->refcount ++;
+}
+/* }}} */
+static void xc_php_release_unlocked(xc_cache_t *cache, xc_entry_data_php_t *php) /* {{{ */
+{
+	if (-- php->refcount == 0) {
+		xc_entry_data_php_t **pp = &(cache->cached->phps[php->hvalue]);
+		xc_entry_data_php_t *p;
+		for (p = *pp; p; pp = &(p->next), p = p->next) {
+			if (memcmp(&php->md5.digest, &p->md5.digest, sizeof(php->md5.digest)) == 0) {
+				/* unlink */
+				*pp = p->next;
+				xc_php_free_unlocked(cache, php);
+				return;
+			}
+		}
+		assert(0);
+	}
+}
+/* }}} */
+
+static inline int xc_entry_equal_unlocked(xc_entry_type_t type, const xc_entry_t *entry1, const xc_entry_t *entry2 TSRMLS_DC) /* {{{ */
+{
+	/* this function isn't required but can be in unlocked */
+	switch (type) {
+		case XC_TYPE_PHP:
+			{
+				const xc_entry_php_t *php_entry1 = (const xc_entry_php_t *) entry1;
+				const xc_entry_php_t *php_entry2 = (const xc_entry_php_t *) entry2;
+				if (php_entry1->file_inode && php_entry2->file_inode) {
+					zend_bool inodeIsSame = php_entry1->file_inode == php_entry2->file_inode
+						                 && php_entry1->file_device == php_entry2->file_device;
+					if (XG(experimental)) {
+						/* new experimental behavior: quick check by inode, first */
+						if (!inodeIsSame) {
+							return 0;
+						}
+
+						/* and then opened_path compare */
+					}
+					else {
+						/* old behavior: inode check only */
+						return inodeIsSame;
+					}
+				}
+			}
+
+			assert(strstr(entry1->name.str.val, "://") != NULL || IS_ABSOLUTE_PATH(entry1->name.str.val, entry1->name.str.len));
+			assert(strstr(entry1->name.str.val, "://") != NULL || IS_ABSOLUTE_PATH(entry2->name.str.val, entry2->name.str.len));
+
+			return entry1->name.str.len == entry2->name.str.len
+				&& memcmp(entry1->name.str.val, entry2->name.str.val, entry1->name.str.len + 1) == 0;
+
+		case XC_TYPE_VAR:
+#ifdef IS_UNICODE
+			if (entry1->name_type != entry2->name_type) {
+				return 0;
+			}
+
+			if (entry1->name_type == IS_UNICODE) {
+				return entry1->name.ustr.len == entry2->name.ustr.len
+				    && memcmp(entry1->name.ustr.val, entry2->name.ustr.val, (entry1->name.ustr.len + 1) * sizeof(entry1->name.ustr.val[0])) == 0;
+			}
+#endif
+			return entry1->name.str.len == entry2->name.str.len
+			    && memcmp(entry1->name.str.val, entry2->name.str.val, entry1->name.str.len + 1) == 0;
+			break;
+
+		default:
+			assert(0);
+	}
+	return 0;
+}
+/* }}} */
+static void xc_entry_add_unlocked(xc_cached_t *cached, xc_hash_value_t entryslotid, xc_entry_t *entry) /* {{{ */
+{
+	xc_entry_t **head = &(cached->entries[entryslotid]);
+	entry->next = *head;
+	*head = entry;
+	cached->entries_count ++;
+}
+/* }}} */
+static xc_entry_t *xc_entry_store_unlocked(xc_entry_type_t type, xc_cache_t *cache, xc_hash_value_t entryslotid, xc_entry_t *entry TSRMLS_DC) /* {{{ */
+{
+	xc_entry_t *stored_entry;
+
+	entry->hits  = 0;
+	entry->ctime = XG(request_time);
+	entry->atime = XG(request_time);
+	stored_entry = type == XC_TYPE_PHP
+		? (xc_entry_t *) xc_processor_store_xc_entry_php_t(cache->shm, cache->allocator, (xc_entry_php_t *) entry TSRMLS_CC)
+		: (xc_entry_t *) xc_processor_store_xc_entry_var_t(cache->shm, cache->allocator, (xc_entry_var_t *) entry TSRMLS_CC);
+	if (stored_entry) {
+		xc_entry_add_unlocked(cache->cached, entryslotid, stored_entry);
+		++cache->cached->updates;
+		return stored_entry;
+	}
+	else {
+		cache->cached->ooms ++;
+		return NULL;
+	}
+}
+/* }}} */
+static xc_entry_php_t *xc_entry_php_store_unlocked(xc_cache_t *cache, xc_hash_value_t entryslotid, xc_entry_php_t *entry_php TSRMLS_DC) /* {{{ */
+{
+	return (xc_entry_php_t *) xc_entry_store_unlocked(XC_TYPE_PHP, cache, entryslotid, (xc_entry_t *) entry_php TSRMLS_CC);
+}
+/* }}} */
+static xc_entry_var_t *xc_entry_var_store_unlocked(xc_cache_t *cache, xc_hash_value_t entryslotid, xc_entry_var_t *entry_var TSRMLS_DC) /* {{{ */
+{
+	return (xc_entry_var_t *) xc_entry_store_unlocked(XC_TYPE_VAR, cache, entryslotid, (xc_entry_t *) entry_var TSRMLS_CC);
+}
+/* }}} */
+static void xc_entry_free_real_unlocked(xc_entry_type_t type, xc_cache_t *cache, volatile xc_entry_t *entry) /* {{{ */
+{
+	if (type == XC_TYPE_PHP) {
+		xc_php_release_unlocked(cache, ((xc_entry_php_t *) entry)->php);
+	}
+	cache->allocator->vtable->free(cache->allocator, (xc_entry_t *)entry);
+}
+/* }}} */
+static void xc_entry_free_unlocked(xc_entry_type_t type, xc_cache_t *cache, xc_entry_t *entry TSRMLS_DC) /* {{{ */
+{
+	cache->cached->entries_count --;
+	if ((type == XC_TYPE_PHP ? ((xc_entry_php_t *) entry)->refcount : 0) == 0) {
+		xc_entry_free_real_unlocked(type, cache, entry);
+	}
+	else {
+		entry->next = cache->cached->deletes;
+		cache->cached->deletes = entry;
+		entry->dtime = XG(request_time);
+		cache->cached->deletes_count ++;
+	}
+	return;
+}
+/* }}} */
+static void xc_entry_remove_unlocked(xc_entry_type_t type, xc_cache_t *cache, xc_hash_value_t entryslotid, xc_entry_t *entry TSRMLS_DC) /* {{{ */
+{
+	xc_entry_t **pp = &(cache->cached->entries[entryslotid]);
+	xc_entry_t *p;
+	for (p = *pp; p; pp = &(p->next), p = p->next) {
+		if (xc_entry_equal_unlocked(type, entry, p TSRMLS_CC)) {
+			/* unlink */
+			*pp = p->next;
+			xc_entry_free_unlocked(type, cache, entry TSRMLS_CC);
+			return;
+		}
+	}
+	assert(0);
+}
+/* }}} */
+static xc_entry_t *xc_entry_find_unlocked(xc_entry_type_t type, xc_cache_t *cache, xc_hash_value_t entryslotid, xc_entry_t *entry TSRMLS_DC) /* {{{ */
+{
+	xc_entry_t *p;
+	for (p = cache->cached->entries[entryslotid]; p; p = p->next) {
+		if (xc_entry_equal_unlocked(type, entry, p TSRMLS_CC)) {
+			zend_bool fresh;
+			switch (type) {
+			case XC_TYPE_PHP:
+				{
+					xc_entry_php_t *p_php = (xc_entry_php_t *) p;
+					xc_entry_php_t *entry_php = (xc_entry_php_t *) entry;
+					fresh = p_php->file_mtime == entry_php->file_mtime && p_php->file_size == entry_php->file_size;
+				}
+				break;
+
+			case XC_TYPE_VAR:
+				{
+					fresh = !VAR_ENTRY_EXPIRED(p);
+				}
+				break;
+
+			default:
+				assert(0);
+			}
+
+			if (fresh) {
+				p->hits ++;
+				p->atime = XG(request_time);
+				return p;
+			}
+
+			xc_entry_remove_unlocked(type, cache, entryslotid, p TSRMLS_CC);
+			return NULL;
+		}
+	}
+	return NULL;
+}
+/* }}} */
+static void xc_entry_hold_php_unlocked(xc_cache_t *cache, xc_entry_php_t *entry TSRMLS_DC) /* {{{ */
+{
+	TRACE("hold %d:%s", entry->file_inode, entry->entry.name.str.val);
+	entry->refcount ++;
+	xc_stack_push(&XG(php_holds)[cache->cacheid], (void *)entry);
+}
+/* }}} */
+static inline zend_uint advance_wrapped(zend_uint val, zend_uint count) /* {{{ */
+{
+	if (val + 1 >= count) {
+		return 0;
+	}
+	return val + 1;
+}
+/* }}} */
+static inline void xc_counters_inc(time_t *curtime, zend_uint *curslot, time_t interval, zend_ulong *counters, zend_uint count TSRMLS_DC) /* {{{ */
+{
+	time_t n = XG(request_time) / interval;
+	if (*curtime != n) {
+		zend_uint target_slot = n % count;
+		zend_uint slot;
+		for (slot = advance_wrapped(*curslot, count);
+				slot != target_slot;
+				slot = advance_wrapped(slot, count)) {
+			counters[slot] = 0;
+		}
+		counters[target_slot] = 0;
+		*curtime = n;
+		*curslot = target_slot;
+	}
+	counters[*curslot] ++;
+}
+/* }}} */
+static inline void xc_cached_hit_unlocked(xc_cached_t *cached TSRMLS_DC) /* {{{ */
+{
+	cached->hits ++;
+
+	xc_counters_inc(&cached->hits_by_hour_cur_time
+			, &cached->hits_by_hour_cur_slot, 60 * 60
+			, cached->hits_by_hour
+			, sizeof(cached->hits_by_hour) / sizeof(cached->hits_by_hour[0])
+			TSRMLS_CC);
+
+	xc_counters_inc(&cached->hits_by_second_cur_time
+			, &cached->hits_by_second_cur_slot, 1
+			, cached->hits_by_second
+			, sizeof(cached->hits_by_second) / sizeof(cached->hits_by_second[0])
+			TSRMLS_CC);
+}
+/* }}} */
+
+/* helper function that loop through each entry */
+#define XC_ENTRY_APPLY_FUNC(name) zend_bool name(xc_entry_t *entry TSRMLS_DC)
+typedef XC_ENTRY_APPLY_FUNC((*cache_apply_unlocked_func_t));
+static void xc_entry_apply_unlocked(xc_entry_type_t type, xc_cache_t *cache, cache_apply_unlocked_func_t apply_func TSRMLS_DC) /* {{{ */
+{
+	xc_entry_t *p, **pp;
+	int i, c;
+
+	for (i = 0, c = cache->hentry->size; i < c; i ++) {
+		pp = &(cache->cached->entries[i]);
+		for (p = *pp; p; p = *pp) {
+			if (apply_func(p TSRMLS_CC)) {
+				/* unlink */
+				*pp = p->next;
+				xc_entry_free_unlocked(type, cache, p TSRMLS_CC);
+			}
+			else {
+				pp = &(p->next);
+			}
+		}
+	}
+}
+/* }}} */
+
+#define XC_CACHE_APPLY_FUNC(name) void name(xc_cache_t *cache TSRMLS_DC)
+/* call graph:
+ * xc_gc_expires_php -> xc_gc_expires_one -> xc_entry_apply_unlocked -> xc_gc_expires_php_entry_unlocked
+ * xc_gc_expires_var -> xc_gc_expires_one -> xc_entry_apply_unlocked -> xc_gc_expires_var_entry_unlocked
+ */
+static XC_ENTRY_APPLY_FUNC(xc_gc_expires_php_entry_unlocked) /* {{{ */
+{
+	TRACE("ttl %lu, %lu %lu", (zend_ulong) XG(request_time), (zend_ulong) entry->atime, xc_php_ttl);
+	if (XG(request_time) > entry->atime + (time_t) xc_php_ttl) {
+		return 1;
+	}
+	return 0;
+}
+/* }}} */
+static XC_ENTRY_APPLY_FUNC(xc_gc_expires_var_entry_unlocked) /* {{{ */
+{
+	if (VAR_ENTRY_EXPIRED(entry)) {
+		return 1;
+	}
+	return 0;
+}
+/* }}} */
+static void xc_gc_expires_one(xc_entry_type_t type, xc_cache_t *cache, zend_ulong gc_interval, cache_apply_unlocked_func_t apply_func TSRMLS_DC) /* {{{ */
+{
+	TRACE("interval %lu, %lu %lu", (zend_ulong) XG(request_time), (zend_ulong) cache->cached->last_gc_expires, gc_interval);
+	if (!cache->cached->disabled && XG(request_time) >= cache->cached->last_gc_expires + (time_t) gc_interval) {
+		ENTER_LOCK(cache) {
+			if (XG(request_time) >= cache->cached->last_gc_expires + (time_t) gc_interval) {
+				cache->cached->last_gc_expires = XG(request_time);
+				xc_entry_apply_unlocked(type, cache, apply_func TSRMLS_CC);
+			}
+		} LEAVE_LOCK(cache);
+	}
+}
+/* }}} */
+static void xc_gc_expires_php(TSRMLS_D) /* {{{ */
+{
+	size_t i, c;
+
+	if (!xc_php_ttl || !xc_php_gc_interval || !xc_php_caches) {
+		return;
+	}
+
+	for (i = 0, c = xc_php_hcache.size; i < c; i ++) {
+		xc_gc_expires_one(XC_TYPE_PHP, &xc_php_caches[i], xc_php_gc_interval, xc_gc_expires_php_entry_unlocked TSRMLS_CC);
+	}
+}
+/* }}} */
+static void xc_gc_expires_var(TSRMLS_D) /* {{{ */
+{
+	int i, c;
+
+	if (!xc_var_gc_interval || !xc_var_caches) {
+		return;
+	}
+
+	for (i = 0, c = xc_var_hcache.size; i < c; i ++) {
+		xc_gc_expires_one(XC_TYPE_VAR, &xc_var_caches[i], xc_var_gc_interval, xc_gc_expires_var_entry_unlocked TSRMLS_CC);
+	}
+}
+/* }}} */
+
+static XC_CACHE_APPLY_FUNC(xc_gc_delete_unlocked) /* {{{ */
+{
+	xc_entry_t *p, **pp;
+
+	pp = &cache->cached->deletes;
+	for (p = *pp; p; p = *pp) {
+		xc_entry_php_t *entry = (xc_entry_php_t *) p;
+		if (XG(request_time) - p->dtime > 3600) {
+			entry->refcount = 0;
+			/* issue warning here */
+		}
+		if (entry->refcount == 0) {
+			/* unlink */
+			*pp = p->next;
+			cache->cached->deletes_count --;
+			xc_entry_free_real_unlocked(XC_TYPE_PHP, cache, p);
+		}
+		else {
+			pp = &(p->next);
+		}
+	}
+}
+/* }}} */
+static XC_CACHE_APPLY_FUNC(xc_gc_deletes_one) /* {{{ */
+{
+	if (!cache->cached->disabled && cache->cached->deletes && XG(request_time) - cache->cached->last_gc_deletes > xc_deletes_gc_interval) {
+		ENTER_LOCK(cache) {
+			if (cache->cached->deletes && XG(request_time) - cache->cached->last_gc_deletes > xc_deletes_gc_interval) {
+				cache->cached->last_gc_deletes = XG(request_time);
+				xc_gc_delete_unlocked(cache TSRMLS_CC);
+			}
+		} LEAVE_LOCK(cache);
+	}
+}
+/* }}} */
+static void xc_gc_deletes(TSRMLS_D) /* {{{ */
+{
+	size_t i, c;
+
+	if (xc_php_caches) {
+		for (i = 0, c = xc_php_hcache.size; i < c; i ++) {
+			xc_gc_deletes_one(&xc_php_caches[i] TSRMLS_CC);
+		}
+	}
+
+	if (xc_var_caches) {
+		for (i = 0, c = xc_var_hcache.size; i < c; i ++) {
+			xc_gc_deletes_one(&xc_var_caches[i] TSRMLS_CC);
+		}
+	}
+}
+/* }}} */
+
+/* helper functions for user functions */
+static void xc_fillinfo_unlocked(int cachetype, xc_cache_t *cache, zval *return_value TSRMLS_DC) /* {{{ */
+{
+	zval *blocks, *hits;
+	size_t i;
+	const xc_allocator_block_t *b;
+#ifndef NDEBUG
+	xc_memsize_t avail = 0;
+#endif
+	const xc_allocator_t *allocator = cache->allocator;
+	const xc_allocator_vtable_t *vtable = allocator->vtable;
+	zend_ulong interval;
+	const xc_cached_t *cached = cache->cached;
+
+	if (cachetype == XC_TYPE_PHP) {
+		interval = xc_php_ttl ? xc_php_gc_interval : 0;
+	}
+	else {
+		interval = xc_var_gc_interval;
+	}
+
+	add_assoc_long_ex(return_value, ZEND_STRS("slots"),     cache->hentry->size);
+	add_assoc_long_ex(return_value, ZEND_STRS("compiling"), cached->compiling);
+	add_assoc_long_ex(return_value, ZEND_STRS("disabled"),  cached->disabled);
+	add_assoc_long_ex(return_value, ZEND_STRS("updates"),   cached->updates);
+	add_assoc_long_ex(return_value, ZEND_STRS("misses"),    cached->updates); /* deprecated */
+	add_assoc_long_ex(return_value, ZEND_STRS("hits"),      cached->hits);
+	add_assoc_long_ex(return_value, ZEND_STRS("skips"),     cached->skips);
+	add_assoc_long_ex(return_value, ZEND_STRS("clogs"),     cached->skips); /* deprecated */
+	add_assoc_long_ex(return_value, ZEND_STRS("ooms"),      cached->ooms);
+	add_assoc_long_ex(return_value, ZEND_STRS("errors"),    cached->errors);
+
+	add_assoc_long_ex(return_value, ZEND_STRS("cached"),    cached->entries_count);
+	add_assoc_long_ex(return_value, ZEND_STRS("deleted"),   cached->deletes_count);
+	if (interval) {
+		time_t gc = (cached->last_gc_expires + interval) - XG(request_time);
+		add_assoc_long_ex(return_value, ZEND_STRS("gc"),    gc > 0 ? gc : 0);
+	}
+	else {
+		add_assoc_null_ex(return_value, ZEND_STRS("gc"));
+	}
+	MAKE_STD_ZVAL(hits);
+	array_init(hits);
+	for (i = 0; i < sizeof(cached->hits_by_hour) / sizeof(cached->hits_by_hour[0]); i ++) {
+		add_next_index_long(hits, (long) cached->hits_by_hour[i]);
+	}
+	add_assoc_zval_ex(return_value, ZEND_STRS("hits_by_hour"), hits);
+
+	MAKE_STD_ZVAL(hits);
+	array_init(hits);
+	for (i = 0; i < sizeof(cached->hits_by_second) / sizeof(cached->hits_by_second[0]); i ++) {
+		add_next_index_long(hits, (long) cached->hits_by_second[i]);
+	}
+	add_assoc_zval_ex(return_value, ZEND_STRS("hits_by_second"), hits);
+
+	MAKE_STD_ZVAL(blocks);
+	array_init(blocks);
+
+	add_assoc_long_ex(return_value, ZEND_STRS("size"),  vtable->size(allocator));
+	add_assoc_long_ex(return_value, ZEND_STRS("avail"), vtable->avail(allocator));
+	add_assoc_bool_ex(return_value, ZEND_STRS("can_readonly"), xc_readonly_protection);
+
+	for (b = vtable->freeblock_first(allocator); b; b = vtable->freeblock_next(b)) {
+		zval *bi;
+
+		MAKE_STD_ZVAL(bi);
+		array_init(bi);
+
+		add_assoc_long_ex(bi, ZEND_STRS("size"),   vtable->block_size(b));
+		add_assoc_long_ex(bi, ZEND_STRS("offset"), vtable->block_offset(allocator, b));
+		add_next_index_zval(blocks, bi);
+#ifndef NDEBUG
+		avail += vtable->block_size(b);
+#endif
+	}
+	add_assoc_zval_ex(return_value, ZEND_STRS("free_blocks"), blocks);
+#ifndef NDEBUG
+	assert(avail == vtable->avail(allocator));
+#endif
+}
+/* }}} */
+static void xc_fillentry_unlocked(xc_entry_type_t type, const xc_entry_t *entry, xc_hash_value_t entryslotid, int del, zval *list TSRMLS_DC) /* {{{ */
+{
+	zval* ei;
+	const xc_entry_data_php_t *php;
+
+	ALLOC_INIT_ZVAL(ei);
+	array_init(ei);
+
+	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("hvalue"),   entryslotid);
+	if (del) {
+		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);
+#endif
+	switch (type) {
+		case XC_TYPE_PHP: {
+			xc_entry_php_t *entry_php = (xc_entry_php_t *) entry;
+			php = entry_php->php;
+			add_assoc_long_ex(ei, ZEND_STRS("size"),          entry->size + php->size);
+			add_assoc_long_ex(ei, ZEND_STRS("refcount"),      entry_php->refcount);
+			add_assoc_long_ex(ei, ZEND_STRS("phprefcount"),   php->refcount);
+			add_assoc_long_ex(ei, ZEND_STRS("file_mtime"),    entry_php->file_mtime);
+			add_assoc_long_ex(ei, ZEND_STRS("file_size"),     entry_php->file_size);
+			add_assoc_long_ex(ei, ZEND_STRS("file_device"),   entry_php->file_device);
+			add_assoc_long_ex(ei, ZEND_STRS("file_inode"),    entry_php->file_inode);
+
+#ifdef HAVE_XCACHE_CONSTANT
+			add_assoc_long_ex(ei, ZEND_STRS("constinfo_cnt"), php->constinfo_cnt);
+#endif
+			add_assoc_long_ex(ei, ZEND_STRS("function_cnt"),  php->funcinfo_cnt);
+			add_assoc_long_ex(ei, ZEND_STRS("class_cnt"),     php->classinfo_cnt);
+#ifdef ZEND_ENGINE_2_1
+			add_assoc_long_ex(ei, ZEND_STRS("autoglobal_cnt"),php->autoglobal_cnt);
+#endif
+			break;
+		}
+
+		case XC_TYPE_VAR:
+			add_assoc_long_ex(ei, ZEND_STRS("refcount"),      0); /* for BC only */
+			add_assoc_long_ex(ei, ZEND_STRS("size"),          entry->size);
+			break;
+
+		default:
+			assert(0);
+	}
+
+	add_next_index_zval(list, ei);
+}
+/* }}} */
+static void xc_filllist_unlocked(xc_entry_type_t type, 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->cached->entries[i]; e; e = e->next) {
+			xc_fillentry_unlocked(type, e, i, 0, list TSRMLS_CC);
+		}
+	}
+	add_assoc_zval(return_value, "cache_list", list);
+
+	ALLOC_INIT_ZVAL(list);
+	array_init(list);
+	for (e = cache->cached->deletes; e; e = e->next) {
+		xc_fillentry_unlocked(XC_TYPE_PHP, e, 0, 1, list TSRMLS_CC);
+	}
+	add_assoc_zval(return_value, "deleted_list", list);
+}
+/* }}} */
+
+static zend_op_array *xc_entry_install(xc_entry_php_t *entry_php TSRMLS_DC) /* {{{ */
+{
+	zend_uint i;
+	xc_entry_data_php_t *p = entry_php->php;
+	zend_op_array *old_active_op_array = CG(active_op_array);
+#ifndef ZEND_ENGINE_2
+	ALLOCA_FLAG(use_heap)
+	/* new ptr which is stored inside CG(class_table) */
+	xc_cest_t **new_cest_ptrs = (xc_cest_t **)my_do_alloca(sizeof(xc_cest_t*) * p->classinfo_cnt, use_heap);
+#endif
+
+	CG(active_op_array) = p->op_array;
+
+#ifdef HAVE_XCACHE_CONSTANT
+	/* install constant */
+	for (i = 0; i < p->constinfo_cnt; i ++) {
+		xc_constinfo_t *ci = &p->constinfos[i];
+		xc_install_constant(entry_php->entry.name.str.val, &ci->constant,
+				UNISW(0, ci->type), ci->key, ci->key_size, ci->h TSRMLS_CC);
+	}
+#endif
+
+	/* install function */
+	for (i = 0; i < p->funcinfo_cnt; i ++) {
+		xc_funcinfo_t  *fi = &p->funcinfos[i];
+		xc_install_function(entry_php->entry.name.str.val, &fi->func,
+				UNISW(0, fi->type), fi->key, fi->key_size, fi->h 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) (long) ce->parent) - 1;
+			assert(class_idx < i);
+			ci->cest.parent = new_cest_ptrs[class_idx];
+		}
+		new_cest_ptrs[i] =
+#endif
+#ifdef ZEND_COMPILE_DELAYED_BINDING
+		xc_install_class(entry_php->entry.name.str.val, &ci->cest, -1,
+				UNISW(0, ci->type), ci->key, ci->key_size, ci->h TSRMLS_CC);
+#else
+		xc_install_class(entry_php->entry.name.str.val, &ci->cest, ci->oplineno,
+				UNISW(0, ci->type), ci->key, ci->key_size, ci->h TSRMLS_CC);
+#endif
+	}
+
+#ifdef ZEND_ENGINE_2_1
+	/* trigger auto_globals jit */
+	for (i = 0; i < p->autoglobal_cnt; i ++) {
+		xc_autoglobal_t *aginfo = &p->autoglobals[i];
+		zend_u_is_auto_global(aginfo->type, aginfo->key, aginfo->key_len TSRMLS_CC);
+	}
+#endif
+#ifdef XCACHE_ERROR_CACHING
+	/* restore trigger errors */
+	for (i = 0; i < p->compilererror_cnt; i ++) {
+		xc_compilererror_t *error = &p->compilererrors[i];
+		CG(zend_lineno) = error->lineno;
+		zend_error(error->type, "%s", error->error);
+	}
+	CG(zend_lineno) = 0;
+#endif
+
+	i = 1;
+#ifndef ZEND_ENGINE_2_2
+	zend_hash_add(&EG(included_files), entry_php->entry.name.str.val, entry_php->entry.name.str.len+1, (void *)&i, sizeof(int), NULL);
+#endif
+
+#ifndef ZEND_ENGINE_2
+	my_free_alloca(new_cest_ptrs, use_heap);
+#endif
+	CG(active_op_array) = old_active_op_array;
+	return p->op_array;
+}
+/* }}} */
+
+static inline void xc_entry_unholds_real(xc_stack_t *holds, xc_cache_t *caches, size_t cachecount TSRMLS_DC) /* {{{ */
+{
+	size_t i;
+	xc_stack_t *s;
+	xc_cache_t *cache;
+	xc_entry_php_t *entry_php;
+
+	for (i = 0; i < cachecount; i ++) {
+		s = &holds[i];
+		TRACE("holded %d items", xc_stack_count(s));
+		if (xc_stack_count(s)) {
+			cache = &caches[i];
+			ENTER_LOCK(cache) {
+				while (xc_stack_count(s)) {
+					entry_php = (xc_entry_php_t *) xc_stack_pop(s);
+					TRACE("unhold %d:%s", entry_php->file_inode, entry_php->entry.name.str.val);
+					assert(entry_php->refcount > 0);
+					--entry_php->refcount;
+				}
+			} LEAVE_LOCK(cache);
+		}
+	}
+}
+/* }}} */
+static void xc_entry_unholds(TSRMLS_D) /* {{{ */
+{
+	if (xc_php_caches) {
+		xc_entry_unholds_real(XG(php_holds), xc_php_caches, xc_php_hcache.size TSRMLS_CC);
+	}
+
+	if (xc_var_caches) {
+		xc_entry_unholds_real(XG(var_holds), xc_var_caches, xc_var_hcache.size TSRMLS_CC);
+	}
+}
+/* }}} */
+
+#define HASH(i) (i)
+#define HASH_ZSTR_L(t, s, l) HASH(zend_u_inline_hash_func((t), (s), ((l) + 1) * sizeof(UChar)))
+#define HASH_STR_S(s, l) HASH(zend_inline_hash_func((char *) (s), (l)))
+#define HASH_STR_L(s, l) HASH_STR_S((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_hash_fold(xc_hash_value_t hvalue, const xc_hash_t *hasher) /* {{{ fold hash bits as needed */
+{
+	xc_hash_value_t folded = 0;
+	while (hvalue) {
+		folded ^= (hvalue & hasher->mask);
+		hvalue >>= hasher->bits;
+	}
+	return folded;
+}
+/* }}} */
+static inline xc_hash_value_t xc_entry_hash_name(xc_entry_t *entry TSRMLS_DC) /* {{{ */
+{
+	return UNISW(NOTHING, UG(unicode) ? HASH_ZSTR_L(entry->name_type, entry->name.uni.val, entry->name.uni.len) :)
+		HASH_STR_L(entry->name.str.val, entry->name.str.len);
+}
+/* }}} */
+#define xc_entry_hash_var xc_entry_hash_name
+static void xc_entry_free_key_php(xc_entry_php_t *entry_php TSRMLS_DC) /* {{{ */
+{
+#define X_FREE(var) do {\
+	if (entry_php->var) { \
+		efree(entry_php->var); \
+	} \
+} while (0)
+	X_FREE(dirpath);
+#ifdef IS_UNICODE
+	X_FREE(ufilepath);
+	X_FREE(udirpath);
+#endif
+
+#undef X_FREE
+}
+/* }}} */
+static char *xc_expand_url(const char *filepath, char *real_path TSRMLS_DC) /* {{{ */
+{
+	if (strstr(filepath, "://") != NULL) {
+		size_t filepath_len = strlen(filepath);
+		size_t copy_len = filepath_len > MAXPATHLEN - 1 ? MAXPATHLEN - 1 : filepath_len;
+		memcpy(real_path, filepath, filepath_len);
+		real_path[copy_len] = '\0';
+		return real_path;
+	}
+	return expand_filepath(filepath, real_path TSRMLS_CC);
+}
+/* }}} */
+
+#define XC_RESOLVE_PATH_CHECKER(name) int name(const char *filepath, size_t filepath_len, void *data TSRMLS_DC)
+typedef XC_RESOLVE_PATH_CHECKER((*xc_resolve_path_checker_func_t));
+static int xc_resolve_path(const char *filepath, char *path_buffer, xc_resolve_path_checker_func_t checker_func, void *data TSRMLS_DC) /* {{{ */
+{
+	char *paths, *path;
+	char *tokbuf;
+	size_t path_buffer_len;
+	int size;
+	char tokens[] = { DEFAULT_DIR_SEPARATOR, '\0' };
+	int ret;
+	ALLOCA_FLAG(use_heap)
+
+#if 0
+	if ((*filepath == '.' && 
+	     (IS_SLASH(filepath[1]) || 
+	      ((filepath[1] == '.') && IS_SLASH(filepath[2])))) ||
+	    IS_ABSOLUTE_PATH(filepath, strlen(filepath)) ||
+	    !path ||
+	    !*path) {
+
+		ret = checker_func(path_buffer, path_buffer_len, data TSRMLS_CC);
+		goto finish;
+	}
+#endif
+
+	size = strlen(PG(include_path)) + 1;
+	paths = (char *)my_do_alloca(size, use_heap);
+	memcpy(paths, PG(include_path), size);
+
+	for (path = php_strtok_r(paths, tokens, &tokbuf); path; path = php_strtok_r(NULL, tokens, &tokbuf)) {
+		path_buffer_len = snprintf(path_buffer, MAXPATHLEN, "%s/%s", path, filepath);
+		if (path_buffer_len < MAXPATHLEN - 1) {
+			ret = checker_func(path_buffer, path_buffer_len, data TSRMLS_CC);
+			if (ret == SUCCESS) {
+				goto finish;
+			}
+		}
+	}
+
+	/* fall back to current directory */
+	if (zend_is_executing(TSRMLS_C)) {
+		const char *executing_filename = zend_get_executed_filename(TSRMLS_C);
+		int dirname_len = strlen(executing_filename);
+		size_t filename_len = strlen(filepath);
+
+		while ((--dirname_len >= 0) && !IS_SLASH(executing_filename[dirname_len]));
+		if (executing_filename && dirname_len > 0 && executing_filename[0] && executing_filename[0] != '['
+		 && dirname_len + 1 + filename_len + 1 < MAXPATHLEN) {
+			memcpy(path_buffer, executing_filename, dirname_len + 1);
+			memcpy(path_buffer + dirname_len + 1, filepath, filename_len + 1);
+			path_buffer_len = dirname_len + 1 + filename_len;
+			ret = checker_func(path_buffer, path_buffer_len, data TSRMLS_CC);
+			if (ret == SUCCESS) {
+				goto finish;
+			}
+		}
+	}
+
+	ret = FAILURE;
+
+finish:
+	my_free_alloca(paths, use_heap);
+
+	return ret;
+}
+/* }}} */
+
+static zend_bool xc_is_absolute(const char *filepath, size_t filepath_len) /* {{{ */
+{
+	const char *p;
+
+	if (IS_ABSOLUTE_PATH(filepath, filepath_len)) {
+		return 1;
+	}
+
+	for (p = filepath; isalnum((int)*p) || *p == '+' || *p == '-' || *p == '.'; p++);
+	if ((*p == ':') && (p - filepath > 1) && (p[1] == '/') && (p[2] == '/')) {
+		return 1;
+	}
+
+	return 0;
+}
+/* }}} */
+static int xc_stat(const char *filepath, struct stat *statbuf TSRMLS_DC) /* {{{ */
+{
+	if (strstr(filepath, "://") != NULL) {
+		php_stream_statbuf ssb; 
+		php_stream_wrapper *wrapper = NULL; 
+		char *path_for_open = NULL; 
+
+		wrapper = php_stream_locate_url_wrapper(filepath, &path_for_open, 0 TSRMLS_CC); 
+		if (wrapper && wrapper->wops->url_stat
+		 && wrapper != &php_plain_files_wrapper
+		 && wrapper->wops->url_stat(wrapper, path_for_open, PHP_STREAM_URL_STAT_QUIET, &ssb, NULL TSRMLS_CC) == SUCCESS) {
+			*statbuf = ssb.sb;
+			return SUCCESS;
+		}
+
+		return FAILURE;
+	}
+
+	return VCWD_STAT(filepath, statbuf);
+}
+/* }}} */
+static XC_RESOLVE_PATH_CHECKER(xc_resolve_path_stat_checker) /* {{{ */
+{
+	return xc_stat(filepath, (struct stat *) data TSRMLS_CC);
+}
+/* }}} */
+#ifndef ZEND_ENGINE_2_3
+static int xc_resolve_path_stat(const char *filepath, char *path_buffer, struct stat *pbuf TSRMLS_DC) /* {{{ */
+{
+	return xc_resolve_path(filepath, path_buffer, xc_resolve_path_stat_checker, (void *) pbuf TSRMLS_CC);
+}
+/* }}} */
+#endif
+typedef struct xc_compiler_t { /* {{{ */
+	/* XCache cached compile state */
+	const char *filename;
+	size_t filename_len;
+	const char *opened_path;
+	char opened_path_buffer[MAXPATHLEN];
+
+	xc_entry_hash_t entry_hash;
+	xc_entry_php_t new_entry;
+	xc_entry_data_php_t new_php;
+} xc_compiler_t;
+/* }}} */
+typedef struct xc_resolve_path_entry_checker_t { /* {{{ */
+	xc_compiler_t *compiler;
+	xc_entry_php_t **stored_entry;
+} xc_resolve_path_entry_checker_data_t;
+/* }}} */
+static XC_RESOLVE_PATH_CHECKER(xc_resolve_path_entry_checker) /* {{{ */
+{
+	xc_resolve_path_entry_checker_data_t *entry_checker_data = (xc_resolve_path_entry_checker_data_t *) data;
+	xc_compiler_t *compiler = entry_checker_data->compiler;
+
+	compiler->new_entry.entry.name.str.val = xc_expand_url(filepath, compiler->opened_path_buffer TSRMLS_CC);
+	compiler->new_entry.entry.name.str.len = strlen(compiler->new_entry.entry.name.str.val);
+
+	*entry_checker_data->stored_entry = (xc_entry_php_t *) xc_entry_find_unlocked(
+			XC_TYPE_PHP
+			, &xc_php_caches[compiler->entry_hash.cacheid]
+			, compiler->entry_hash.entryslotid
+			, (xc_entry_t *) &compiler->new_entry
+			TSRMLS_CC);
+
+	return *entry_checker_data->stored_entry ? SUCCESS : FAILURE;
+}
+/* }}} */
+static int xc_resolve_path_check_entry_unlocked(xc_compiler_t *compiler, const char *filepath, xc_entry_php_t **stored_entry TSRMLS_DC) /* {{{ */
+{
+	char path_buffer[MAXPATHLEN];
+	xc_resolve_path_entry_checker_data_t entry_checker_data;
+	entry_checker_data.compiler = compiler;
+	entry_checker_data.stored_entry = stored_entry;
+
+	return xc_resolve_path(filepath, path_buffer, xc_resolve_path_entry_checker, (void *) &entry_checker_data TSRMLS_CC);
+}
+/* }}} */
+static int xc_entry_php_quick_resolve_opened_path(xc_compiler_t *compiler, struct stat *statbuf TSRMLS_DC) /* {{{ */
+{
+	if (strcmp(SG(request_info).path_translated, compiler->filename) == 0) {
+		/* sapi has already done this stat() for us */
+		if (statbuf) {
+			struct stat *sapi_stat = sapi_get_stat(TSRMLS_C);
+			if (!sapi_stat) {
+				goto giveupsapistat;
+			}
+			*statbuf = *sapi_stat;
+		}
+
+		compiler->opened_path = xc_expand_url(compiler->filename, compiler->opened_path_buffer TSRMLS_CC);
+		return SUCCESS;
+	}
+giveupsapistat:
+
+	/* absolute path */
+	if (xc_is_absolute(compiler->filename, strlen(compiler->filename))) {
+		if (statbuf && xc_stat(compiler->filename, statbuf TSRMLS_CC) != SUCCESS) {
+			return FAILURE;
+		}
+		compiler->opened_path = xc_expand_url(compiler->filename, compiler->opened_path_buffer TSRMLS_CC);
+		return SUCCESS;
+	}
+
+	/* relative path */
+	if (*compiler->filename == '.' && (IS_SLASH(compiler->filename[1]) || compiler->filename[1] == '.')) {
+		const char *ptr = compiler->filename + 1;
+		if (*ptr == '.') {
+			while (*(++ptr) == '.');
+			if (!IS_SLASH(*ptr)) {
+				return FAILURE;
+			}   
+		}
+
+		if (statbuf && VCWD_STAT(compiler->filename, statbuf) != 0) {
+			return FAILURE;
+		}
+
+		compiler->opened_path = xc_expand_url(compiler->filename, compiler->opened_path_buffer TSRMLS_CC);
+		return SUCCESS;
+	}
+
+	return FAILURE;
+}
+/* }}} */
+static int xc_entry_php_resolve_opened_path(xc_compiler_t *compiler, struct stat *statbuf TSRMLS_DC) /* {{{ */
+{
+	if (xc_entry_php_quick_resolve_opened_path(compiler, statbuf TSRMLS_CC) == SUCCESS) {
+		/* opened_path resolved */
+		return SUCCESS;
+	}
+	/* fall back to real stat call */
+	else {
+#ifdef ZEND_ENGINE_2_3
+		char *opened_path = php_resolve_path(compiler->filename, compiler->filename_len, PG(include_path) TSRMLS_CC);
+		if (opened_path) {
+			strcpy(compiler->opened_path_buffer, opened_path);
+			efree(opened_path);
+			compiler->opened_path = compiler->opened_path_buffer;
+			if (!statbuf || xc_stat(compiler->opened_path, statbuf TSRMLS_CC) == SUCCESS) {
+				return SUCCESS;
+			}
+		}
+#else
+		char path_buffer[MAXPATHLEN];
+		if (xc_resolve_path_stat(compiler->filename, path_buffer, statbuf TSRMLS_CC) == SUCCESS) {
+			compiler->opened_path = xc_expand_url(path_buffer, compiler->opened_path_buffer TSRMLS_CC);
+			return SUCCESS;
+		}
+#endif
+	}
+	return FAILURE;
+}
+/* }}} */
+static int xc_entry_php_init_key(xc_compiler_t *compiler TSRMLS_DC) /* {{{ */
+{
+	if (XG(stat)) {
+		struct stat buf;
+		time_t delta;
+
+		if (compiler->opened_path) {
+			if (xc_stat(compiler->opened_path, &buf TSRMLS_CC) != SUCCESS) {
+				return FAILURE;
+			}
+		}
+		else {
+			if (xc_entry_php_resolve_opened_path(compiler, &buf TSRMLS_CC) != SUCCESS) {
+				return FAILURE;
+			}
+		}
+
+		delta = XG(request_time) - buf.st_mtime;
+		if (abs(delta) < 2 && !xc_test) {
+			return FAILURE;
+		}
+
+		compiler->new_entry.file_mtime   = buf.st_mtime;
+		compiler->new_entry.file_size    = buf.st_size;
+		compiler->new_entry.file_device  = buf.st_dev;
+		compiler->new_entry.file_inode   = buf.st_ino;
+	}
+	else {
+		xc_entry_php_quick_resolve_opened_path(compiler, NULL TSRMLS_CC);
+
+		compiler->new_entry.file_mtime   = 0;
+		compiler->new_entry.file_size    = 0;
+		compiler->new_entry.file_device  = 0;
+		compiler->new_entry.file_inode   = 0;
+	}
+
+	{
+		xc_hash_value_t basename_hash_value;
+		if (xc_php_hcache.size > 1
+		 || !compiler->new_entry.file_inode) {
+			const char *filename_end = compiler->filename + compiler->filename_len;
+			const char *basename_begin = filename_end - 1;
+
+			/* scan till out of basename part */
+			while (basename_begin >= compiler->filename && !IS_SLASH(*basename_begin)) {
+				--basename_begin;
+			}
+			/* get back to basename_begin */
+			++basename_begin;
+
+			basename_hash_value = HASH_STR_L(basename_begin, filename_end - basename_begin);
+		}
+
+		compiler->entry_hash.cacheid = xc_php_hcache.size > 1 ? xc_hash_fold(basename_hash_value, &xc_php_hcache) : 0;
+		compiler->entry_hash.entryslotid = xc_hash_fold(
+				compiler->new_entry.file_inode
+				? (xc_hash_value_t) HASH(compiler->new_entry.file_device + compiler->new_entry.file_inode)
+				: basename_hash_value
+				, &xc_php_hentry);
+	}
+
+	compiler->new_entry.filepath  = NULL;
+	compiler->new_entry.dirpath   = NULL;
+#ifdef IS_UNICODE
+	compiler->new_entry.ufilepath = NULL;
+	compiler->new_entry.udirpath  = NULL;
+#endif
+
+	return SUCCESS;
+}
+/* }}} */
+static inline xc_hash_value_t xc_php_hash_md5(xc_entry_data_php_t *php TSRMLS_DC) /* {{{ */
+{
+	return HASH_STR_S(php->md5.digest, sizeof(php->md5.digest));
+}
+/* }}} */
+static int xc_entry_data_php_init_md5(xc_cache_t *cache, xc_compiler_t *compiler TSRMLS_DC) /* {{{ */
+{
+	unsigned char   buf[1024];
+	PHP_MD5_CTX     context;
+	int             n;
+	php_stream     *stream;
+	ulong           old_rsid = EG(regular_list).nNextFreeElement;
+
+	stream = php_stream_open_wrapper((char *) compiler->filename, "rb", USE_PATH | REPORT_ERRORS | ENFORCE_SAFE_MODE | STREAM_DISABLE_OPEN_BASEDIR, NULL);
+	if (!stream) {
+		return FAILURE;
+	}
+
+	PHP_MD5Init(&context);
+	while ((n = php_stream_read(stream, (char *) buf, sizeof(buf))) > 0) {
+		PHP_MD5Update(&context, buf, n);
+	}
+	PHP_MD5Final((unsigned char *) compiler->new_php.md5.digest, &context);
+
+	php_stream_close(stream);
+	if (EG(regular_list).nNextFreeElement == old_rsid + 1) {
+		EG(regular_list).nNextFreeElement = old_rsid;
+	}
+
+	if (n < 0) {
+		return FAILURE;
+	}
+
+	compiler->new_php.hvalue = (xc_php_hash_md5(&compiler->new_php TSRMLS_CC) & cache->hphp->mask);
+#ifdef XCACHE_DEBUG
+	{
+		char md5str[33];
+		make_digest(md5str, (unsigned char *) compiler->new_php.md5.digest);
+		TRACE("md5 %s", md5str);
+	}
+#endif
+
+	return SUCCESS;
+}
+/* }}} */
+static void xc_entry_php_init(xc_entry_php_t *entry_php, const char *filepath TSRMLS_DC) /* {{{*/
+{
+	entry_php->filepath     = ZEND_24((char *), NOTHING) filepath;
+	entry_php->filepath_len = strlen(entry_php->filepath);
+	entry_php->dirpath      = estrndup(entry_php->filepath, entry_php->filepath_len);
+	entry_php->dirpath_len  = zend_dirname(entry_php->dirpath, entry_php->filepath_len);
+#ifdef IS_UNICODE
+	zend_string_to_unicode(ZEND_U_CONVERTER(UG(runtime_encoding_conv)), &entry_php->ufilepath, &entry_php->ufilepath_len, entry_php->filepath, entry_php->filepath_len TSRMLS_CC);
+	zend_string_to_unicode(ZEND_U_CONVERTER(UG(runtime_encoding_conv)), &entry_php->udirpath,  &entry_php->udirpath_len,  entry_php->dirpath,  entry_php->dirpath_len TSRMLS_CC);
+#endif
+}
+/* }}} */
+#ifndef ZEND_COMPILE_DELAYED_BINDING
+static void xc_cache_early_binding_class_cb(zend_op *opline, int oplineno, void *data TSRMLS_DC) /* {{{ */
+{
+	char *class_name;
+	zend_uint i;
+	int class_len;
+	xc_cest_t cest;
+	xc_entry_data_php_t *php = (xc_entry_data_php_t *) data;
+
+	class_name = Z_OP_CONSTANT(opline->op1).value.str.val;
+	class_len  = Z_OP_CONSTANT(opline->op1).value.str.len;
+	if (zend_hash_find(CG(class_table), class_name, class_len, (void **) &cest) == FAILURE) {
+		assert(0);
+	}
+	TRACE("got ZEND_DECLARE_INHERITED_CLASS: %s", class_name + 1);
+	/* let's see which class */
+	for (i = 0; i < php->classinfo_cnt; i ++) {
+		if (memcmp(ZSTR_S(php->classinfos[i].key), class_name, class_len) == 0) {
+			php->classinfos[i].oplineno = oplineno;
+			php->have_early_binding = 1;
+			break;
+		}
+	}
+
+	if (i == php->classinfo_cnt) {
+		assert(0);
+	}
+}
+/* }}} */
+#endif
+
+/* {{{ Constant Usage */
+#ifdef ZEND_ENGINE_2_4
+#	define xcache_literal_is_dir  1
+#	define xcache_literal_is_file 2
+#else
+#	define xcache_op1_is_file 1
+#	define xcache_op1_is_dir  2
+#	define xcache_op2_is_file 4
+#	define xcache_op2_is_dir  8
+#endif
+typedef struct {
+	zend_bool filepath_used;
+	zend_bool dirpath_used;
+	zend_bool ufilepath_used;
+	zend_bool udirpath_used;
+} xc_const_usage_t;
+/* }}} */
+static void xc_collect_op_array_info(xc_compiler_t *compiler, xc_const_usage_t *usage, xc_op_array_info_t *op_array_info, zend_op_array *op_array TSRMLS_DC) /* {{{ */
+{
+#ifdef ZEND_ENGINE_2_4
+	int literalindex;
+#else
+	zend_uint oplinenum;
+#endif
+	xc_vector_t details;
+
+	xc_vector_init(xc_op_array_info_detail_t, &details);
+
+#define XCACHE_ANALYZE_LITERAL(type) \
+	if (zend_binary_strcmp(Z_STRVAL(literal->constant), Z_STRLEN(literal->constant), compiler->new_entry.type##path, compiler->new_entry.type##path_len) == 0) { \
+		usage->type##path_used = 1; \
+		literalinfo |= xcache_##literal##_is_##type; \
+	}
+
+#define XCACHE_U_ANALYZE_LITERAL(type) \
+	if (zend_u_##binary_strcmp(Z_USTRVAL(literal->constant), Z_USTRLEN(literal->constant), compiler->new_entry.u##type##path, compiler->new_entry.u##type##path_len) == 0) { \
+		usage->u##type##path_used = 1; \
+		literalinfo |= xcache_##literal##_is_##type; \
+	}
+
+#define XCACHE_ANALYZE_OP(type, op) \
+	if (zend_binary_strcmp(Z_STRVAL(Z_OP_CONSTANT(opline->op)), Z_STRLEN(Z_OP_CONSTANT(opline->op)), compiler->new_entry.type##path, compiler->new_entry.type##path_len) == 0) { \
+		usage->type##path_used = 1; \
+		oplineinfo |= xcache_##op##_is_##type; \
+	}
+
+#define XCACHE_U_ANALYZE_OP(type, op) \
+	if (zend_u_##binary_strcmp(Z_USTRVAL(Z_OP_CONSTANT(opline->op)), Z_USTRLEN(Z_OP_CONSTANT(opline->op)), compiler->new_entry.u##type##path, compiler->new_entry.u##type##path_len) == 0) { \
+		usage->u##type##path_used = 1; \
+		oplineinfo |= xcache_##op##_is_##type; \
+	}
+
+#ifdef ZEND_ENGINE_2_4
+	for (literalindex = 0; literalindex < op_array->last_literal; literalindex++) {
+		zend_literal *literal = &op_array->literals[literalindex];
+		zend_uint literalinfo = 0;
+		if (Z_TYPE(literal->constant) == IS_STRING) {
+			XCACHE_ANALYZE_LITERAL(file)
+			else XCACHE_ANALYZE_LITERAL(dir)
+		}
+#ifdef IS_UNICODE
+		else if (Z_TYPE(literal->constant) == IS_UNICODE) {
+			XCACHE_U_ANALYZE_LITERAL(file)
+			else XCACHE_U_ANALYZE_LITERAL(dir)
+		}
+#endif
+		if (literalinfo) {
+			xc_op_array_info_detail_t detail;
+			detail.index = literalindex;
+			detail.info  = literalinfo;
+			xc_vector_add(xc_op_array_info_detail_t, &details, detail);
+		}
+	}
+
+	op_array_info->literalinfo_cnt = details.cnt;
+	op_array_info->literalinfos    = xc_vector_detach(xc_op_array_info_detail_t, &details);
+#else /* ZEND_ENGINE_2_4 */
+	for (oplinenum = 0; oplinenum < op_array->last; oplinenum++) {
+		zend_op *opline = &op_array->opcodes[oplinenum];
+		zend_uint oplineinfo = 0;
+		if (Z_OP_TYPE(opline->op1) == IS_CONST) {
+			if (Z_TYPE(Z_OP_CONSTANT(opline->op1)) == IS_STRING) {
+				XCACHE_ANALYZE_OP(file, op1)
+				else XCACHE_ANALYZE_OP(dir, op1)
+			}
+#ifdef IS_UNICODE
+			else if (Z_TYPE(Z_OP_CONSTANT(opline->op1)) == IS_UNICODE) {
+				XCACHE_U_ANALYZE_OP(file, op1)
+				else XCACHE_U_ANALYZE_OP(dir, op1)
+			}
+#endif
+		}
+
+		if (Z_OP_TYPE(opline->op2) == IS_CONST) {
+			if (Z_TYPE(Z_OP_CONSTANT(opline->op2)) == IS_STRING) {
+				XCACHE_ANALYZE_OP(file, op2)
+				else XCACHE_ANALYZE_OP(dir, op2)
+			}
+#ifdef IS_UNICODE
+			else if (Z_TYPE(Z_OP_CONSTANT(opline->op2)) == IS_UNICODE) {
+				XCACHE_U_ANALYZE_OP(file, op2)
+				else XCACHE_U_ANALYZE_OP(dir, op2)
+			}
+#endif
+		}
+
+		if (oplineinfo) {
+			xc_op_array_info_detail_t detail;
+			detail.index = oplinenum;
+			detail.info  = oplineinfo;
+			xc_vector_add(xc_op_array_info_detail_t, &details, detail);
+		}
+	}
+
+	op_array_info->oplineinfo_cnt = details.cnt;
+	op_array_info->oplineinfos    = xc_vector_detach(xc_op_array_info_detail_t, &details);
+#endif /* ZEND_ENGINE_2_4 */
+	xc_vector_free(xc_op_array_info_detail_t, &details);
+}
+/* }}} */
+void xc_fix_op_array_info(const xc_entry_php_t *entry_php, const xc_entry_data_php_t *php, zend_op_array *op_array, int shallow_copy, const xc_op_array_info_t *op_array_info TSRMLS_DC) /* {{{ */
+{
+#ifdef ZEND_ENGINE_2_4
+	zend_uint literalinfoindex;
+
+	for (literalinfoindex = 0; literalinfoindex < op_array_info->literalinfo_cnt; ++literalinfoindex) {
+		int literalindex = op_array_info->literalinfos[literalinfoindex].index;
+		int literalinfo = op_array_info->literalinfos[literalinfoindex].info;
+		zend_literal *literal = &op_array->literals[literalindex];
+		if ((literalinfo & xcache_literal_is_file)) {
+			if (!shallow_copy) {
+				efree(Z_STRVAL(literal->constant));
+			}
+			if (Z_TYPE(literal->constant) == IS_STRING) {
+				assert(entry_php->filepath);
+				ZVAL_STRINGL(&literal->constant, entry_php->filepath, entry_php->filepath_len, !shallow_copy);
+				TRACE("restored literal constant: %s", entry_php->filepath);
+			}
+#ifdef IS_UNICODE
+			else if (Z_TYPE(literal->constant) == IS_UNICODE) {
+				assert(entry_php->ufilepath);
+				ZVAL_UNICODEL(&literal->constant, entry_php->ufilepath, entry_php->ufilepath_len, !shallow_copy);
+			}
+#endif
+			else {
+				assert(0);
+			}
+		}
+		else if ((literalinfo & xcache_literal_is_dir)) {
+			if (!shallow_copy) {
+				efree(Z_STRVAL(literal->constant));
+			}
+			if (Z_TYPE(literal->constant) == IS_STRING) {
+				assert(entry_php->dirpath);
+				TRACE("restored literal constant: %s", entry_php->dirpath);
+				ZVAL_STRINGL(&literal->constant, entry_php->dirpath, entry_php->dirpath_len, !shallow_copy);
+			}
+#ifdef IS_UNICODE
+			else if (Z_TYPE(literal->constant) == IS_UNICODE) {
+				assert(!entry_php->udirpath);
+				ZVAL_UNICODEL(&literal->constant, entry_php->udirpath, entry_php->udirpath_len, !shallow_copy);
+			}
+#endif
+			else {
+				assert(0);
+			}
+		}
+	}
+#else /* ZEND_ENGINE_2_4 */
+	zend_uint oplinenum;
+
+	for (oplinenum = 0; oplinenum < op_array_info->oplineinfo_cnt; ++oplinenum) {
+		int oplineindex = op_array_info->oplineinfos[oplinenum].index;
+		int oplineinfo = op_array_info->oplineinfos[oplinenum].info;
+		zend_op *opline = &op_array->opcodes[oplineindex];
+		if ((oplineinfo & xcache_op1_is_file)) {
+			assert(Z_OP_TYPE(opline->op1) == IS_CONST);
+			if (!shallow_copy) {
+				efree(Z_STRVAL(Z_OP_CONSTANT(opline->op1)));
+			}
+			if (Z_TYPE(Z_OP_CONSTANT(opline->op1)) == IS_STRING) {
+				assert(entry_php->filepath);
+				ZVAL_STRINGL(&Z_OP_CONSTANT(opline->op1), entry_php->filepath, entry_php->filepath_len, !shallow_copy);
+				TRACE("restored op1 constant: %s", entry_php->filepath);
+			}
+#ifdef IS_UNICODE
+			else if (Z_TYPE(Z_OP_CONSTANT(opline->op1)) == IS_UNICODE) {
+				assert(entry_php->ufilepath);
+				ZVAL_UNICODEL(&Z_OP_CONSTANT(opline->op1), entry_php->ufilepath, entry_php->ufilepath_len, !shallow_copy);
+			}
+#endif
+			else {
+				assert(0);
+			}
+		}
+		else if ((oplineinfo & xcache_op1_is_dir)) {
+			assert(Z_OP_TYPE(opline->op1) == IS_CONST);
+			if (!shallow_copy) {
+				efree(Z_STRVAL(Z_OP_CONSTANT(opline->op1)));
+			}
+			if (Z_TYPE(Z_OP_CONSTANT(opline->op1)) == IS_STRING) {
+				assert(entry_php->dirpath);
+				TRACE("restored op1 constant: %s", entry_php->dirpath);
+				ZVAL_STRINGL(&Z_OP_CONSTANT(opline->op1), entry_php->dirpath, entry_php->dirpath_len, !shallow_copy);
+			}
+#ifdef IS_UNICODE
+			else if (Z_TYPE(Z_OP_CONSTANT(opline->op1)) == IS_UNICODE) {
+				assert(!entry_php->udirpath);
+				ZVAL_UNICODEL(&Z_OP_CONSTANT(opline->op1), entry_php->udirpath, entry_php->udirpath_len, !shallow_copy);
+			}
+#endif
+			else {
+				assert(0);
+			}
+		}
+
+		if ((oplineinfo & xcache_op2_is_file)) {
+			assert(Z_OP_TYPE(opline->op2) == IS_CONST);
+			if (!shallow_copy) {
+				efree(Z_STRVAL(Z_OP_CONSTANT(opline->op2)));
+			}
+			if (Z_TYPE(Z_OP_CONSTANT(opline->op2)) == IS_STRING) {
+				assert(entry_php->filepath);
+				TRACE("restored op2 constant: %s", entry_php->filepath);
+				ZVAL_STRINGL(&Z_OP_CONSTANT(opline->op2), entry_php->filepath, entry_php->filepath_len, !shallow_copy);
+			}
+#ifdef IS_UNICODE
+			else if (Z_TYPE(Z_OP_CONSTANT(opline->op2)) == IS_UNICODE) {
+				assert(entry_php->ufilepath);
+				ZVAL_UNICODEL(&Z_OP_CONSTANT(opline->op2), entry_php->ufilepath, entry_php->ufilepath_len, !shallow_copy);
+			}
+#endif
+			else {
+				assert(0);
+			}
+		}
+		else if ((oplineinfo & xcache_op2_is_dir)) {
+			assert(Z_OP_TYPE(opline->op2) == IS_CONST);
+			if (!shallow_copy) {
+				efree(Z_STRVAL(Z_OP_CONSTANT(opline->op2)));
+			}
+			if (Z_TYPE(Z_OP_CONSTANT(opline->op2)) == IS_STRING) {
+				assert(entry_php->dirpath);
+				TRACE("restored op2 constant: %s", entry_php->dirpath);
+				ZVAL_STRINGL(&Z_OP_CONSTANT(opline->op2), entry_php->dirpath, entry_php->dirpath_len, !shallow_copy);
+			}
+#ifdef IS_UNICODE
+			else if (Z_TYPE(Z_OP_CONSTANT(opline->op2)) == IS_UNICODE) {
+				assert(entry_php->udirpath);
+				ZVAL_UNICODEL(&Z_OP_CONSTANT(opline->op2), entry_php->udirpath, entry_php->udirpath_len, !shallow_copy);
+			}
+#endif
+			else {
+				assert(0);
+			}
+		}
+	}
+#endif /* ZEND_ENGINE_2_4 */
+}
+/* }}} */
+static void xc_free_op_array_info(xc_op_array_info_t *op_array_info TSRMLS_DC) /* {{{ */
+{
+#ifdef ZEND_ENGINE_2_4
+	if (op_array_info->literalinfos) {
+		efree(op_array_info->literalinfos);
+	}
+#else
+	if (op_array_info->oplineinfos) {
+		efree(op_array_info->oplineinfos);
+	}
+#endif
+}
+/* }}} */
+static void xc_free_php(xc_entry_data_php_t *php TSRMLS_DC) /* {{{ */
+{
+	zend_uint i;
+	if (php->classinfos) {
+		for (i = 0; i < php->classinfo_cnt; i ++) {
+			xc_classinfo_t *classinfo = &php->classinfos[i];
+			zend_uint j;
+
+			for (j = 0; j < classinfo->methodinfo_cnt; j ++) {
+				xc_free_op_array_info(&classinfo->methodinfos[j] TSRMLS_CC);
+			}
+
+			if (classinfo->methodinfos) {
+				efree(classinfo->methodinfos);
+			}
+		}
+	}
+	if (php->funcinfos) {
+		for (i = 0; i < php->funcinfo_cnt; i ++) {
+			xc_free_op_array_info(&php->funcinfos[i].op_array_info TSRMLS_CC);
+		}
+	}
+	xc_free_op_array_info(&php->op_array_info TSRMLS_CC);
+
+#define X_FREE(var) do {\
+	if (php->var) { \
+		efree(php->var); \
+	} \
+} while (0)
+
+#ifdef ZEND_ENGINE_2_1
+	X_FREE(autoglobals);
+#endif
+	X_FREE(classinfos);
+	X_FREE(funcinfos);
+#ifdef HAVE_XCACHE_CONSTANT
+	X_FREE(constinfos);
+#endif
+#undef X_FREE
+}
+/* }}} */
+static void xc_compile_php(xc_compiler_t *compiler, zend_file_handle *h, int type TSRMLS_DC) /* {{{ */
+{
+	zend_uint old_constinfo_cnt, old_funcinfo_cnt, old_classinfo_cnt;
+	zend_bool catched = 0;
+
+	/* {{{ compile */
+	TRACE("compiling %s", h->opened_path ? h->opened_path : h->filename);
+
+	old_classinfo_cnt = zend_hash_num_elements(CG(class_table));
+	old_funcinfo_cnt  = zend_hash_num_elements(CG(function_table));
+	old_constinfo_cnt = zend_hash_num_elements(EG(zend_constants));
+
+	zend_try {
+		compiler->new_php.op_array = old_compile_file(h, type TSRMLS_CC);
+	} zend_catch {
+		catched = 1;
+	} zend_end_try();
+
+	if (catched) {
+		goto err_bailout;
+	}
+
+	if (compiler->new_php.op_array == NULL) {
+		goto err_op_array;
+	}
+
+	if (!XG(initial_compile_file_called)) {
+		TRACE("%s", "!initial_compile_file_called, give up");
+		return;
+	}
+
+	/* }}} */
+	/* {{{ prepare */
+	zend_restore_compiled_filename(h->opened_path ? h->opened_path : (char *) h->filename TSRMLS_CC);
+
+#ifdef HAVE_XCACHE_CONSTANT
+	compiler->new_php.constinfo_cnt  = zend_hash_num_elements(EG(zend_constants)) - old_constinfo_cnt;
+#endif
+	compiler->new_php.funcinfo_cnt   = zend_hash_num_elements(CG(function_table)) - old_funcinfo_cnt;
+	compiler->new_php.classinfo_cnt  = zend_hash_num_elements(CG(class_table))    - old_classinfo_cnt;
+#ifdef ZEND_ENGINE_2_1
+	/* {{{ count new_php.autoglobal_cnt */ {
+		Bucket *b;
+
+		compiler->new_php.autoglobal_cnt = 0;
+		for (b = CG(auto_globals)->pListHead; b != NULL; b = b->pListNext) {
+			zend_auto_global *auto_global = (zend_auto_global *) b->pData;
+			/* check if actived */
+			if (auto_global->auto_global_callback && !auto_global->armed) {
+				compiler->new_php.autoglobal_cnt ++;
+			}
+		}
+	}
+	/* }}} */
+#endif
+
+#define X_ALLOC_N(var, cnt) do {     \
+	if (compiler->new_php.cnt) {                  \
+		ECALLOC_N(compiler->new_php.var, compiler->new_php.cnt); \
+		if (!compiler->new_php.var) {             \
+			goto err_alloc;          \
+		}                            \
+	}                                \
+	else {                           \
+		compiler->new_php.var = NULL;             \
+	}                                \
+} while (0)
+
+#ifdef HAVE_XCACHE_CONSTANT
+	X_ALLOC_N(constinfos,  constinfo_cnt);
+#endif
+	X_ALLOC_N(funcinfos,   funcinfo_cnt);
+	X_ALLOC_N(classinfos,  classinfo_cnt);
+#ifdef ZEND_ENGINE_2_1
+	X_ALLOC_N(autoglobals, autoglobal_cnt);
+#endif
+#undef X_ALLOC
+	/* }}} */
+
+	/* {{{ shallow copy, pointers only */ {
+		Bucket *b;
+		zend_uint i;
+		zend_uint j;
+
+#define COPY_H(vartype, var, cnt, name, datatype) do {        \
+	for (i = 0, j = 0; b; i ++, b = b->pListNext) {           \
+		vartype *data = &compiler->new_php.var[j];                         \
+                                                              \
+		if (i < old_##cnt) {                                  \
+			continue;                                         \
+		}                                                     \
+		j ++;                                                 \
+                                                              \
+		assert(i < old_##cnt + compiler->new_php.cnt);                     \
+		assert(b->pData);                                     \
+		memcpy(&data->name, b->pData, sizeof(datatype));      \
+		UNISW(NOTHING, data->type = b->key.type;)             \
+		if (UNISW(1, b->key.type == IS_STRING)) {             \
+			ZSTR_S(data->key)      = BUCKET_KEY_S(b);         \
+		}                                                     \
+		else {                                                \
+			ZSTR_U(data->key)      = BUCKET_KEY_U(b);         \
+		}                                                     \
+		data->key_size   = b->nKeyLength;                     \
+		data->h          = b->h;                              \
+	}                                                         \
+} while(0)
+
+#ifdef HAVE_XCACHE_CONSTANT
+		b = EG(zend_constants)->pListHead; COPY_H(xc_constinfo_t, constinfos, constinfo_cnt, constant, zend_constant);
+#endif
+		b = CG(function_table)->pListHead; COPY_H(xc_funcinfo_t,  funcinfos,  funcinfo_cnt,  func,     zend_function);
+		b = CG(class_table)->pListHead;    COPY_H(xc_classinfo_t, classinfos, classinfo_cnt, cest,     xc_cest_t);
+
+#undef COPY_H
+
+		/* for ZE1, cest need to be fixed inside store */
+
+#ifdef ZEND_ENGINE_2_1
+		/* scan for acatived auto globals */
+		i = 0;
+		for (b = CG(auto_globals)->pListHead; b != NULL; b = b->pListNext) {
+			zend_auto_global *auto_global = (zend_auto_global *) b->pData;
+			/* check if actived */
+			if (auto_global->auto_global_callback && !auto_global->armed) {
+				xc_autoglobal_t *data = &compiler->new_php.autoglobals[i];
+
+				assert(i < compiler->new_php.autoglobal_cnt);
+				i ++;
+				UNISW(NOTHING, data->type = b->key.type;)
+				if (UNISW(1, b->key.type == IS_STRING)) {
+					ZSTR_S(data->key)     = BUCKET_KEY_S(b);
+				}
+				else {
+					ZSTR_U(data->key)     = BUCKET_KEY_U(b);
+				}
+				data->key_len = b->nKeyLength - 1;
+				data->h       = b->h;
+			}
+		}
+#endif
+	}
+	/* }}} */
+
+	/* {{{ collect info for file/dir path */ {
+		Bucket *b;
+		xc_const_usage_t const_usage;
+		unsigned int i;
+
+		xc_entry_php_init(&compiler->new_entry, zend_get_compiled_filename(TSRMLS_C) TSRMLS_CC);
+		memset(&const_usage, 0, sizeof(const_usage));
+
+		for (i = 0; i < compiler->new_php.classinfo_cnt; i ++) {
+			xc_classinfo_t *classinfo = &compiler->new_php.classinfos[i];
+			zend_class_entry *ce = CestToCePtr(classinfo->cest);
+			classinfo->methodinfo_cnt = ce->function_table.nTableSize;
+			if (classinfo->methodinfo_cnt) {
+				int j;
+
+				ECALLOC_N(classinfo->methodinfos, classinfo->methodinfo_cnt);
+				if (!classinfo->methodinfos) {
+					goto err_alloc;
+				}
+
+				for (j = 0, b = ce->function_table.pListHead; b; j ++, b = b->pListNext) {
+					xc_collect_op_array_info(compiler, &const_usage, &classinfo->methodinfos[j], (zend_op_array *) b->pData TSRMLS_CC);
+				}
+			}
+			else {
+				classinfo->methodinfos = NULL;
+			}
+		}
+
+		for (i = 0; i < compiler->new_php.funcinfo_cnt; i ++) {
+			xc_collect_op_array_info(compiler, &const_usage, &compiler->new_php.funcinfos[i].op_array_info, (zend_op_array *) &compiler->new_php.funcinfos[i].func TSRMLS_CC);
+		}
+
+		xc_collect_op_array_info(compiler, &const_usage, &compiler->new_php.op_array_info, compiler->new_php.op_array TSRMLS_CC);
+
+		/* file/dir path free unused */
+#define X_FREE_UNUSED(var) \
+		if (!const_usage.var##path_used) { \
+			efree(compiler->new_entry.var##path); \
+			compiler->new_entry.var##path = NULL; \
+			compiler->new_entry.var##path_len = 0; \
+		}
+		/* filepath is required to restore op_array->filename, so no free filepath here */
+		X_FREE_UNUSED(dir)
+#ifdef IS_UNICODE
+		X_FREE_UNUSED(ufile)
+		X_FREE_UNUSED(udir)
+#endif
+#undef X_FREE_UNUSED
+	}
+	/* }}} */
+#ifdef XCACHE_ERROR_CACHING
+	compiler->new_php.compilererrors = xc_sandbox_compilererrors(TSRMLS_C);
+	compiler->new_php.compilererror_cnt = xc_sandbox_compilererror_cnt(TSRMLS_C);
+#endif
+#ifndef ZEND_COMPILE_DELAYED_BINDING
+	/* {{{ find inherited classes that should be early-binding */
+	compiler->new_php.have_early_binding = 0;
+	{
+		zend_uint i;
+		for (i = 0; i < compiler->new_php.classinfo_cnt; i ++) {
+			compiler->new_php.classinfos[i].oplineno = -1;
+		}
+	}
+
+	xc_undo_pass_two(compiler->new_php.op_array TSRMLS_CC);
+	xc_foreach_early_binding_class(compiler->new_php.op_array, xc_cache_early_binding_class_cb, (void *) &compiler->new_php TSRMLS_CC);
+	xc_redo_pass_two(compiler->new_php.op_array TSRMLS_CC);
+	/* }}} */
+#endif
+
+	return;
+
+err_alloc:
+	xc_free_php(&compiler->new_php TSRMLS_CC);
+
+err_bailout:
+err_op_array:
+
+	if (catched) {
+		zend_bailout();
+	}
+}
+/* }}} */
+static zend_op_array *xc_compile_restore(xc_entry_php_t *stored_entry, xc_entry_data_php_t *stored_php TSRMLS_DC) /* {{{ */
+{
+	zend_op_array *op_array;
+	xc_entry_php_t restored_entry;
+	xc_entry_data_php_t restored_php;
+	zend_bool catched;
+	zend_uint i;
+
+	/* still needed because in zend_language_scanner.l, require()/include() check file_handle.handle.stream.handle */
+	i = 1;
+	zend_hash_add(&EG(included_files), stored_entry->entry.name.str.val, stored_entry->entry.name.str.len + 1, (void *)&i, sizeof(int), NULL);
+
+	CG(in_compilation)    = 1;
+	CG(compiled_filename) = stored_entry->entry.name.str.val;
+	CG(zend_lineno)       = 0;
+	TRACE("restoring %d:%s", stored_entry->file_inode, stored_entry->entry.name.str.val);
+	xc_processor_restore_xc_entry_php_t(&restored_entry, stored_entry TSRMLS_CC);
+	xc_processor_restore_xc_entry_data_php_t(stored_entry, &restored_php, stored_php, xc_readonly_protection TSRMLS_CC);
+	restored_entry.php = &restored_php;
+#ifdef SHOW_DPRINT
+	xc_dprint(&restored_entry, 0 TSRMLS_CC);
+#endif
+
+	catched = 0;
+	zend_try {
+		op_array = xc_entry_install(&restored_entry TSRMLS_CC);
+	} zend_catch {
+		catched = 1;
+	} zend_end_try();
+
+#ifdef HAVE_XCACHE_CONSTANT
+	if (restored_php.constinfos) {
+		efree(restored_php.constinfos);
+	}
+#endif
+	if (restored_php.funcinfos) {
+		efree(restored_php.funcinfos);
+	}
+	if (restored_php.classinfos) {
+		efree(restored_php.classinfos);
+	}
+
+	if (catched) {
+		zend_bailout();
+	}
+	CG(in_compilation)    = 0;
+	CG(compiled_filename) = NULL;
+	TRACE("restored %d:%s", stored_entry->file_inode, stored_entry->entry.name.str.val);
+	return op_array;
+}
+/* }}} */
+typedef struct xc_sandboxed_compiler_t { /* {{{ */
+	xc_compiler_t *compiler;
+	/* input */
+	zend_file_handle *h;
+	int type;
+
+	/* sandbox output */
+	xc_entry_php_t *stored_entry;
+	xc_entry_data_php_t *stored_php;
+} xc_sandboxed_compiler_t;
+/* }}} */
+
+static zend_op_array *xc_compile_file_sandboxed(void *data TSRMLS_DC) /* {{{ */
+{
+	xc_sandboxed_compiler_t *sandboxed_compiler = (xc_sandboxed_compiler_t *) data;
+	xc_compiler_t *compiler = sandboxed_compiler->compiler;
+	zend_bool catched = 0;
+	xc_cache_t *cache = &xc_php_caches[compiler->entry_hash.cacheid];
+	xc_entry_php_t *stored_entry;
+	xc_entry_data_php_t *stored_php;
+
+	/* {{{ compile */
+	/* make compile inside sandbox */
+#ifdef HAVE_XCACHE_CONSTANT
+	compiler->new_php.constinfos  = NULL;
+#endif
+	compiler->new_php.funcinfos   = NULL;
+	compiler->new_php.classinfos  = NULL;
+#ifdef ZEND_ENGINE_2_1
+	compiler->new_php.autoglobals = NULL;
+#endif
+	memset(&compiler->new_php.op_array_info, 0, sizeof(compiler->new_php.op_array_info));
+
+	XG(initial_compile_file_called) = 0;
+	zend_try {
+		compiler->new_php.op_array = NULL;
+		xc_compile_php(compiler, sandboxed_compiler->h, sandboxed_compiler->type TSRMLS_CC);
+	} zend_catch {
+		catched = 1;
+	} zend_end_try();
+
+	if (catched
+	 || !compiler->new_php.op_array /* possible ? */
+	 || !XG(initial_compile_file_called)) {
+		goto err_aftersandbox;
+	}
+
+	/* }}} */
+#ifdef SHOW_DPRINT
+	compiler->new_entry.php = &compiler->new_php;
+	xc_dprint(&compiler->new_entry, 0 TSRMLS_CC);
+#endif
+
+	stored_entry = NULL;
+	stored_php = NULL;
+	ENTER_LOCK_EX(cache) { /* {{{ php_store/entry_store */
+		/* php_store */
+		stored_php = xc_php_store_unlocked(cache, &compiler->new_php TSRMLS_CC);
+		if (!stored_php) {
+			/* error */
+			break;
+		}
+		/* entry_store */
+		compiler->new_entry.php = stored_php;
+		stored_entry = xc_entry_php_store_unlocked(cache, compiler->entry_hash.entryslotid, &compiler->new_entry TSRMLS_CC);
+		if (stored_entry) {
+			xc_php_addref_unlocked(stored_php);
+			TRACE(" cached %d:%s, holding", compiler->new_entry.file_inode, stored_entry->entry.name.str.val);
+			xc_entry_hold_php_unlocked(cache, stored_entry TSRMLS_CC);
+		}
+	} LEAVE_LOCK_EX(cache);
+	/* }}} */
+	TRACE("%s", stored_entry ? "stored" : "store failed");
+
+	if (catched || !stored_php) {
+		goto err_aftersandbox;
+	}
+
+	cache->cached->compiling = 0;
+	xc_free_php(&compiler->new_php TSRMLS_CC);
+
+	if (stored_entry) {
+		sandboxed_compiler->stored_entry = stored_entry;
+		sandboxed_compiler->stored_php = stored_php;
+		/* discard newly compiled result, restore from stored one */
+		if (compiler->new_php.op_array) {
+#ifdef ZEND_ENGINE_2
+			destroy_op_array(compiler->new_php.op_array TSRMLS_CC);
+#else
+			destroy_op_array(compiler->new_php.op_array);
+#endif
+			efree(compiler->new_php.op_array);
+			compiler->new_php.op_array = NULL;
+		}
+		return NULL;
+	}
+	else {
+		return compiler->new_php.op_array;
+	}
+
+err_aftersandbox:
+	xc_free_php(&compiler->new_php TSRMLS_CC);
+
+	cache->cached->compiling = 0;
+	if (catched) {
+		cache->cached->errors ++;
+		zend_bailout();
+	}
+	return compiler->new_php.op_array;
+} /* }}} */
+static zend_op_array *xc_compile_file_cached(xc_compiler_t *compiler, zend_file_handle *h, int type TSRMLS_DC) /* {{{ */
+{
+	/*
+	if (clog) {
+		return old;
+	}
+
+	if (cached_entry = getby entry_hash) {
+		php = cached_entry.php;
+		php = restore(php);
+		return php;
+	}
+	else {
+		if (!(php = getby md5)) {
+			if (clog) {
+				return old;
+			}
+
+			inside_sandbox {
+				php = compile;
+				entry = create entries[entry];
+			}
+		}
+
+		entry.php = php;
+		return php;
+	}
+	*/
+
+	xc_entry_php_t *stored_entry;
+	xc_entry_data_php_t *stored_php;
+	zend_bool gaveup = 0;
+	zend_bool catched = 0;
+	zend_op_array *op_array;
+	xc_cache_t *cache = &xc_php_caches[compiler->entry_hash.cacheid];
+	xc_sandboxed_compiler_t sandboxed_compiler;
+
+	if (cache->cached->disabled) {
+		return old_compile_file(h, type TSRMLS_CC);
+	}
+	/* stale skips precheck */
+	if (cache->cached->disabled || XG(request_time) - cache->cached->compiling < 30) {
+		cache->cached->skips ++;
+		return old_compile_file(h, type TSRMLS_CC);
+	}
+
+	/* {{{ entry_lookup/hit/md5_init/php_lookup */
+	stored_entry = NULL;
+	stored_php = NULL;
+
+	ENTER_LOCK_EX(cache) {
+		if (!compiler->opened_path && xc_resolve_path_check_entry_unlocked(compiler, compiler->filename, &stored_entry TSRMLS_CC) == SUCCESS) {
+			compiler->opened_path = compiler->new_entry.entry.name.str.val;
+		}
+		else {
+			if (!compiler->opened_path && xc_entry_php_resolve_opened_path(compiler, NULL TSRMLS_CC) != SUCCESS) {
+				gaveup = 1;
+				break;
+			}
+
+			/* finalize name */
+			compiler->new_entry.entry.name.str.val = (char *) compiler->opened_path;
+			compiler->new_entry.entry.name.str.len = strlen(compiler->new_entry.entry.name.str.val);
+
+			stored_entry = (xc_entry_php_t *) xc_entry_find_unlocked(XC_TYPE_PHP, cache, compiler->entry_hash.entryslotid, (xc_entry_t *) &compiler->new_entry TSRMLS_CC);
+		}
+
+		if (stored_entry) {
+			xc_cached_hit_unlocked(cache->cached TSRMLS_CC);
+
+			TRACE(" hit %d:%s, holding", compiler->new_entry.file_inode, stored_entry->entry.name.str.val);
+			xc_entry_hold_php_unlocked(cache, stored_entry TSRMLS_CC);
+			stored_php = stored_entry->php;
+			break;
+		}
+
+		TRACE("miss entry %d:%s", compiler->new_entry.file_inode, compiler->new_entry.entry.name.str.val);
+
+		if (xc_entry_data_php_init_md5(cache, compiler TSRMLS_CC) != SUCCESS) {
+			gaveup = 1;
+			break;
+		}
+
+		stored_php = xc_php_find_unlocked(cache->cached, &compiler->new_php TSRMLS_CC);
+
+		if (stored_php) {
+			compiler->new_entry.php = stored_php;
+			xc_entry_php_init(&compiler->new_entry, compiler->opened_path TSRMLS_CC);
+			stored_entry = xc_entry_php_store_unlocked(cache, compiler->entry_hash.entryslotid, &compiler->new_entry TSRMLS_CC);
+			if (stored_entry) {
+				xc_php_addref_unlocked(stored_php);
+				TRACE(" cached %d:%s, holding", compiler->new_entry.file_inode, stored_entry->entry.name.str.val);
+				xc_entry_hold_php_unlocked(cache, stored_entry TSRMLS_CC);
+			}
+			else {
+				gaveup = 1;
+			}
+			break;
+		}
+
+		if (XG(request_time) - cache->cached->compiling < 30) {
+			TRACE("%s", "miss php, but compiling");
+			cache->cached->skips ++;
+			gaveup = 1;
+			break;
+		}
+
+		TRACE("%s", "miss php, going to compile");
+		cache->cached->compiling = XG(request_time);
+	} LEAVE_LOCK_EX(cache);
+
+	if (catched) {
+		cache->cached->compiling = 0;
+		zend_bailout();
+	}
+
+	/* found entry */
+	if (stored_entry && stored_php) {
+		zend_llist_add_element(&CG(open_files), h);
+		return xc_compile_restore(stored_entry, stored_php TSRMLS_CC);
+	}
+
+	/* gaveup */
+	if (gaveup) {
+		return old_compile_file(h, type TSRMLS_CC);
+	}
+	/* }}} */
+
+	sandboxed_compiler.compiler = compiler;
+	sandboxed_compiler.h = h;
+	sandboxed_compiler.type = type;
+	sandboxed_compiler.stored_php = NULL;
+	sandboxed_compiler.stored_entry = NULL;
+	op_array = xc_sandbox(xc_compile_file_sandboxed, (void *) &sandboxed_compiler, h->opened_path ? h->opened_path : h->filename TSRMLS_CC);
+	if (sandboxed_compiler.stored_entry) {
+		return xc_compile_restore(sandboxed_compiler.stored_entry, sandboxed_compiler.stored_php TSRMLS_CC);
+	}
+	else {
+		return op_array;
+	}
+}
+/* }}} */
+static zend_op_array *xc_compile_file(zend_file_handle *h, int type TSRMLS_DC) /* {{{ */
+{
+	xc_compiler_t compiler;
+	zend_op_array *op_array;
+
+	assert(xc_initized);
+
+	TRACE("xc_compile_file: type=%d name=%s", h->type, h->filename ? h->filename : "NULL");
+
+	if (!XG(cacher)
+	 || !h->filename
+	 || !SG(request_info).path_translated
+
+	) {
+		TRACE("%s", "cacher not enabled");
+		return old_compile_file(h, type TSRMLS_CC);
+	}
+
+	/* {{{ entry_init_key */
+	compiler.opened_path = h->opened_path;
+	compiler.filename = compiler.opened_path ? compiler.opened_path : h->filename;
+	compiler.filename_len = strlen(compiler.filename);
+	if (xc_entry_php_init_key(&compiler TSRMLS_CC) != SUCCESS) {
+		TRACE("failed to init key for %s", compiler.filename);
+		return old_compile_file(h, type TSRMLS_CC);
+	}
+	/* }}} */
+
+	op_array = xc_compile_file_cached(&compiler, h, type TSRMLS_CC);
+
+	xc_entry_free_key_php(&compiler.new_entry TSRMLS_CC);
+
+	return op_array;
+}
+/* }}} */
+
+/* gdb helper functions, but N/A for coredump */
+int xc_is_rw(const void *p) /* {{{ */
+{
+	xc_shm_t *shm;
+	size_t i;
+
+	if (xc_php_caches) {
+		for (i = 0; i < xc_php_hcache.size; i ++) {
+			shm = xc_php_caches[i].shm;
+			if (shm->handlers->is_readwrite(shm, p)) {
+				return 1;
+			}
+		}
+	}
+
+	if (xc_var_caches) {
+		for (i = 0; i < xc_var_hcache.size; i ++) {
+			shm = xc_var_caches[i].shm;
+			if (shm->handlers->is_readwrite(shm, p)) {
+				return 1;
+			}
+		}
+	}
+	return 0;
+}
+/* }}} */
+int xc_is_ro(const void *p) /* {{{ */
+{
+	xc_shm_t *shm;
+	size_t i;
+
+	if (xc_php_caches) {
+		for (i = 0; i < xc_php_hcache.size; i ++) {
+			shm = xc_php_caches[i].shm;
+			if (shm->handlers->is_readonly(shm, p)) {
+				return 1;
+			}
+		}
+	}
+
+	if (xc_var_caches) {
+		for (i = 0; i < xc_var_hcache.size; i ++) {
+			shm = xc_var_caches[i].shm;
+			if (shm->handlers->is_readonly(shm, p)) {
+				return 1;
+			}
+		}
+	}
+	return 0;
+}
+/* }}} */
+int xc_is_shm(const void *p) /* {{{ */
+{
+	return xc_is_ro(p) || xc_is_rw(p);
+}
+/* }}} */
+
+void xc_gc_add_op_array(xc_gc_op_array_t *gc_op_array TSRMLS_DC) /* {{{ */
+{
+	zend_llist_add_element(&XG(gc_op_arrays), (void *) gc_op_array);
+}
+/* }}} */
+static void xc_gc_op_array(void *pDest) /* {{{ */
+{
+	xc_gc_op_array_t *op_array = (xc_gc_op_array_t *) pDest;
+	zend_uint i;
+#ifdef ZEND_ENGINE_2
+	if (op_array->arg_info) {
+		for (i = 0; i < op_array->num_args; i++) {
+			efree((char *) ZSTR_V(op_array->arg_info[i].name));
+			if (ZSTR_V(op_array->arg_info[i].class_name)) {
+				efree((char *) ZSTR_V(op_array->arg_info[i].class_name));
+			}
+		}
+		efree(op_array->arg_info);
+	}
+#endif
+	if (op_array->opcodes) {
+		efree(op_array->opcodes);
+	}
+}
+/* }}} */
+
+/* variable namespace */
+#ifdef IS_UNICODE
+void xc_var_namespace_init_from_unicodel(const UChar *string, int len TSRMLS_DC) /* {{{ */
+{
+	if (!len) {
+#ifdef IS_UNICODE
+		ZVAL_EMPTY_UNICODE(&XG(uvar_namespace_hard));
+#endif
+		ZVAL_EMPTY_STRING(&XG(var_namespace_hard));
+	}
+	else {
+		ZVAL_UNICODE_L(&XG(uvar_namespace_hard), string, len, 1);
+		/* TODO: copy to var */
+	}
+}
+/* }}} */
+#endif
+void xc_var_namespace_init_from_stringl(const char *string, int len TSRMLS_DC) /* {{{ */
+{
+	if (!len) {
+#ifdef IS_UNICODE
+		ZVAL_EMPTY_UNICODE(&XG(uvar_namespace_hard));
+#endif
+		ZVAL_EMPTY_STRING(&XG(var_namespace_hard));
+	}
+	else {
+		ZVAL_STRINGL(&XG(var_namespace_hard), string, len, 1);
+#ifdef IS_UNICODE
+		/* TODO: copy to uvar */
+#endif
+	}
+}
+/* }}} */
+void xc_var_namespace_init_from_long(long value TSRMLS_DC) /* {{{ */
+{
+	ZVAL_LONG(&XG(var_namespace_hard), value);
+#ifdef IS_UNICODE
+	/* TODO: copy to uvar_namespace */
+#endif
+}
+/* }}} */
+#ifdef IS_UNICODE
+void xc_var_namespace_set_unicodel(const UChar *unicode, int len TSRMLS_DC) /* {{{ */
+{
+	zval_dtor(&XG(uvar_namespace_soft));
+	zval_dtor(&XG(var_namespace_soft));
+	if (len) {
+		if (!Z_USTRLEN_P(&XG(uvar_namespace_soft))) {
+			ZVAL_UNICODEL(&XG(uvar_namespace_soft), unicode, len, 1);
+		}
+		else {
+			int buffer_len = Z_USTRLEN_P(&XG(var_namespace_hard)) + 1 + len;
+			char *buffer = emalloc((buffer_len + 1) * sizeof(unicode[0]));
+			char *p = buffer;
+			memcpy(p, Z_USTRVAL_P(&XG(var_namespace_hard)), (Z_USTRLEN_P(&XG(var_namespace_hard)) + 1));
+			p += (Z_USTRLEN_P(&XG(var_namespace_hard)) + 1) * sizeof(unicode[0]);
+			memcpy(p, unicode, (len + 1) * sizeof(unicode[0]));
+			ZVAL_UNICODEL(&XG(uvar_namespace_soft), buffer, buffer_len, 0);
+		}
+		/* TODO: copy to var */
+	}
+	else {
+#ifdef IS_UNICODE
+		XG(uvar_namespace_soft) = XG(uvar_namespace_hard);
+		zval_copy_ctor(&XG(uvar_namespace_soft));
+#endif
+		XG(var_namespace_soft) = XG(var_namespace_hard);
+		zval_copy_ctor(&XG(var_namespace_soft));
+	}
+}
+/* }}} */
+#endif
+void xc_var_namespace_set_stringl(const char *string, int len TSRMLS_DC) /* {{{ */
+{
+#ifdef IS_UNICODE
+	zval_dtor(&XG(uvar_namespace_soft));
+#endif
+	zval_dtor(&XG(var_namespace_soft));
+	if (len) {
+		if (!Z_STRLEN_P(&XG(var_namespace_soft))) {
+			ZVAL_STRINGL(&XG(var_namespace_soft), string, len, 1);
+		}
+		else {
+			int buffer_len = Z_STRLEN_P(&XG(var_namespace_hard)) + 1 + len;
+			char *buffer = emalloc(buffer_len + 1);
+			char *p = buffer;
+			memcpy(p, Z_STRVAL_P(&XG(var_namespace_hard)), Z_STRLEN_P(&XG(var_namespace_hard)) + 1);
+			p += Z_STRLEN_P(&XG(var_namespace_hard)) + 1;
+			memcpy(p, string, len + 1);
+			ZVAL_STRINGL(&XG(var_namespace_soft), buffer, buffer_len, 0);
+		}
+#ifdef IS_UNICODE
+		/* TODO: copy to uvar */
+#endif
+	}
+	else {
+#ifdef IS_UNICODE
+		XG(uvar_namespace_soft) = XG(uvar_namespace_hard);
+		zval_copy_ctor(&XG(uvar_namespace_soft));
+#endif
+		XG(var_namespace_soft) = XG(var_namespace_hard);
+		zval_copy_ctor(&XG(var_namespace_soft));
+	}
+}
+/* }}} */
+static void xc_var_namespace_break(TSRMLS_D) /* {{{ */
+{
+#ifdef IS_UNICODE
+	zval_dtor(&XG(uvar_namespace_soft));
+#endif
+	zval_dtor(&XG(var_namespace_soft));
+#ifdef IS_UNICODE
+	ZVAL_EMPTY_UNICODE(&XG(uvar_namespace_soft));
+#endif
+	ZVAL_EMPTY_STRING(&XG(var_namespace_soft));
+}
+/* }}} */
+static void xc_var_namespace_init(TSRMLS_D) /* {{{ */
+{
+	uid_t id = (uid_t) -1;
+
+	switch (xc_var_namespace_mode) {
+		case 1:
+			{
+				zval **server;
+				HashTable *ht;
+				zval **val;
+
+#ifdef ZEND_ENGINE_2_1
+				zend_is_auto_global("_SERVER", sizeof("_SERVER") - 1 TSRMLS_CC);
+#endif
+
+				if (zend_hash_find(&EG(symbol_table), "_SERVER", sizeof("_SERVER"), (void**)&server) == FAILURE
+				 || Z_TYPE_PP(server) != IS_ARRAY
+				 || !(ht = Z_ARRVAL_P(*server))
+				 || zend_hash_find(ht, xc_var_namespace, strlen(xc_var_namespace) + 1, (void**)&val) == FAILURE) {
+					xc_var_namespace_init_from_stringl(NULL, 0 TSRMLS_CC);
+				}
+				else {
+#ifdef IS_UNICODE
+					if (Z_TYPE_PP(val) == IS_UNICODE) {
+						xc_var_namespace_init_from_unicodel(Z_USTRVAL_PP(val), Z_USTRLEN_PP(val) TSRMLS_CC);
+					}
+					else
+#endif
+					{
+						xc_var_namespace_init_from_stringl(Z_STRVAL_PP(val), Z_STRLEN_PP(val) TSRMLS_CC);
+					}
+				}
+			}
+			break;
+
+		case 2:
+			if (strncmp(xc_var_namespace, "uid", 3) == 0) {
+				id = getuid();
+			}
+			else if (strncmp(xc_var_namespace, "gid", 3) == 0) {
+				id = getgid();
+			}
+
+			if (id == (uid_t) -1){
+				xc_var_namespace_init_from_stringl(NULL, 0 TSRMLS_CC);
+			}
+			else {
+				xc_var_namespace_init_from_long((long) id TSRMLS_CC);
+			}
+			break;
+
+		case 0:
+		default:
+			xc_var_namespace_init_from_stringl(xc_var_namespace, strlen(xc_var_namespace) TSRMLS_CC);
+			break;
+	}
+
+#ifdef IS_UNICODE
+	INIT_ZVAL(XG(uvar_namespace_soft));
+#endif
+	INIT_ZVAL(XG(var_namespace_soft));
+	xc_var_namespace_set_stringl("", 0 TSRMLS_CC);
+}
+/* }}} */
+static void xc_var_namespace_destroy(TSRMLS_D) /* {{{ */
+{
+#ifdef IS_UNICODE
+	zval_dtor(&XG(uvar_namespace_hard));
+	zval_dtor(&XG(uvar_namespace_soft));
+#endif
+	zval_dtor(&XG(var_namespace_hard));
+	zval_dtor(&XG(var_namespace_soft));
+}
+/* }}} */
+static int xc_var_buffer_prepare(zval *name TSRMLS_DC) /* {{{ prepare name, calculate buffer size */
+{
+	int namespace_len;
+	switch (name->type) {
+#ifdef IS_UNICODE
+		case IS_UNICODE:
+do_unicode:
+			namespace_len = Z_USTRLEN_P(&XG(uvar_namespace_soft));
+			return (namespace_len ? namespace_len + 1 : 0) + Z_USTRLEN_P(name);
+#endif
+
+		case IS_STRING:
+do_string:
+			namespace_len = Z_STRLEN_P(&XG(var_namespace_soft));
+			return (namespace_len ? namespace_len + 1 : 0) + Z_STRLEN_P(name);
+
+		default:
+#ifdef IS_UNICODE
+			convert_to_unicode(name);
+			goto do_unicode;
+#else
+			convert_to_string(name);
+			goto do_string;
+#endif
+	}
+}
+/* }}} */
+static int xc_var_buffer_alloca_size(zval *name TSRMLS_DC) /* {{{ prepare name, calculate buffer size */
+{
+	int namespace_len;
+	switch (name->type) {
+#ifdef IS_UNICODE
+		case IS_UNICODE:
+			namespace_len = Z_USTRLEN_P(&XG(uvar_namespace_soft));
+			return !namespace_len ? 0 : (namespace_len + 1 + Z_USTRLEN_P(name) + 1) * sizeof(Z_USTRVAL_P(&XG(uvar_namespace_soft))[0]);
+#endif
+
+		case IS_STRING:
+			namespace_len = Z_STRLEN_P(&XG(var_namespace_soft));
+			return !namespace_len ? 0 : (namespace_len + 1 + Z_STRLEN_P(name) + 1);
+	}
+	assert(0);
+	return 0;
+}
+/* }}} */
+static void xc_var_buffer_init(char *buffer, zval *name TSRMLS_DC) /* {{{ prepare name, calculate buffer size */
+{
+#ifdef IS_UNICODE
+	if (Z_TYPE(name) == IS_UNICODE) {
+		memcpy(buffer, Z_USTRVAL_P(&XG(uvar_namespace_soft)), (Z_USTRLEN_P(&XG(uvar_namespace_soft)) + 1) * sizeof(Z_USTRVAL_P(name)[0]));
+		buffer += (Z_USTRLEN_P(&XG(uvar_namespace_soft)) + 1) * sizeof(Z_USTRVAL_P(name)[0]);
+		memcpy(buffer, Z_USTRVAL_P(name), (Z_USTRLEN_P(name) + 1) * sizeof(Z_USTRVAL_P(name)[0]));
+	}
+#endif
+	memcpy(buffer, Z_STRVAL_P(&XG(var_namespace_soft)), (Z_STRLEN_P(&XG(var_namespace_soft)) + 1));
+	buffer += (Z_STRLEN_P(&XG(var_namespace_soft)) + 1);
+	memcpy(buffer, Z_STRVAL_P(name), (Z_STRLEN_P(name) + 1));
+}
+/* }}} */
+typedef struct xc_namebuffer_t_ { /* {{{ */
+	ALLOCA_FLAG(useheap);
+	void *buffer;
+	int alloca_size;
+	int len;
+} xc_namebuffer_t;
+/* }}} */
+
+#define VAR_BUFFER_FLAGS(name) \
+	xc_namebuffer_t name##_buffer;
+
+#define VAR_BUFFER_INIT(name) \
+	name##_buffer.len = xc_var_buffer_prepare(name TSRMLS_CC); \
+	name##_buffer.alloca_size = xc_var_buffer_alloca_size(name TSRMLS_CC); \
+	name##_buffer.buffer = name##_buffer.alloca_size \
+		? do_alloca(name##_buffer.alloca_size, name##_buffer.useheap) \
+		: UNISW(Z_STRVAL_P(name), Z_TYPE(name) == IS_UNICODE ? Z_USTRVAL_P(name) : Z_STRVAL_P(name)); \
+	if (name##_buffer.alloca_size) xc_var_buffer_init(name##_buffer.buffer, name TSRMLS_CC);
+
+#define VAR_BUFFER_FREE(name) \
+	if (name##_buffer.alloca_size) { \
+		free_alloca(name##_buffer.buffer, name##_buffer.useheap); \
+	}
+
+static inline int xc_var_has_prefix(xc_entry_t *entry, zval *prefix TSRMLS_DC) /* {{{ */
+{
+	zend_bool result = 0;
+	VAR_BUFFER_FLAGS(prefix);
+
+	if (UNISW(IS_STRING, entry->name_type) != prefix->type) {
+		return 0;
+	}
+	VAR_BUFFER_INIT(prefix);
+
+#ifdef IS_UNICODE
+	if (Z_TYPE(prefix) == IS_UNICODE) {
+		result = entry->name.ustr.len >= prefix_buffer.len
+		 && memcmp(entry->name.ustr.val, prefix_buffer.buffer, prefix_buffer.len * sizeof(Z_USTRVAL_P(prefix)[0])) == 0;
+		goto finish;
+	}
+#endif
+
+	result = entry->name.str.len >= prefix_buffer.len
+	 && memcmp(entry->name.str.val, prefix_buffer.buffer, prefix_buffer.len) == 0;
+	goto finish;
+
+finish:
+	VAR_BUFFER_FREE(prefix);
+	return result;
+}
+/* }}} */
+
+/* module helper function */
+static int xc_init_constant(int module_number TSRMLS_DC) /* {{{ */
+{
+	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) /* {{{ */
+{
+	size_t i;
+	xc_shm_t *shm = NULL;
+
+	assert(caches);
+
+	for (i = 0; i < hcache->size; i ++) {
+		xc_cache_t *cache = &caches[i];
+		if (cache) {
+			if (cache->lck) {
+				xc_lock_destroy(cache->lck);
+			}
+			/* do NOT touch cached data */
+			shm = cache->shm;
+			cache->shm->handlers->memdestroy(cache->allocator);
+		}
+	}
+	free(caches);
+	return shm;
+}
+/* }}} */
+static xc_cache_t *xc_cache_init(xc_shm_t *shm, const char *allocator_name, xc_hash_t *hcache, xc_hash_t *hentry, xc_hash_t *hphp, xc_shmsize_t shmsize) /* {{{ */
+{
+	xc_cache_t *caches = NULL;
+	xc_allocator_t *allocator;
+	time_t now = time(NULL);
+	size_t 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 ++) {
+		xc_cache_t *cache = &caches[i];
+		CHECK(allocator = shm->handlers->meminit(shm, memsize), "Failed init shm");
+		if (!(allocator->vtable = xc_allocator_find(allocator_name))) {
+			zend_error(E_ERROR, "Allocator %s not found", allocator_name);
+			goto err;
+		}
+		CHECK(allocator->vtable->init(shm, allocator, memsize), "Failed init allocator");
+		CHECK(cache->cached           = allocator->vtable->calloc(allocator, 1, sizeof(xc_cached_t)), "cache OOM");
+		CHECK(cache->cached->entries  = allocator->vtable->calloc(allocator, hentry->size, sizeof(xc_entry_t*)), "entries OOM");
+		if (hphp) {
+			CHECK(cache->cached->phps = allocator->vtable->calloc(allocator, hphp->size, sizeof(xc_entry_data_php_t*)), "phps OOM");
+		}
+		CHECK(cache->lck              = xc_lock_init(NULL), "can't create lock");
+
+		cache->hcache  = hcache;
+		cache->hentry  = hentry;
+		cache->hphp    = hphp;
+		cache->shm     = shm;
+		cache->allocator = allocator;
+		cache->cacheid = i;
+		cache->cached->last_gc_deletes = now;
+		cache->cached->last_gc_expires = now;
+	}
+	return caches;
+
+err:
+	if (caches) {
+		xc_cache_destroy(caches, hcache);
+	}
+	return NULL;
+}
+/* }}} */
+static void xc_destroy() /* {{{ */
+{
+	xc_shm_t *shm = NULL;
+	if (old_compile_file && zend_compile_file == xc_compile_file) {
+		zend_compile_file = old_compile_file;
+		old_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);
+	}
+
+	xc_initized = 0;
+}
+/* }}} */
+static int xc_init() /* {{{ */
+{
+	xc_shm_t *shm = NULL;
+	xc_shmsize_t shmsize = ALIGN(xc_php_size) + ALIGN(xc_var_size);
+
+	xc_php_caches = xc_var_caches = NULL;
+
+	if (shmsize < (size_t) xc_php_size || shmsize < (size_t) xc_var_size) {
+		zend_error(E_ERROR, "XCache: neither xcache.size nor xcache.var_size can be negative");
+		goto err;
+	}
+
+	if (xc_php_size || xc_var_size) {
+		CHECK(shm = xc_shm_init(xc_shm_scheme, shmsize, xc_readonly_protection, xc_mmap_path, NULL), "Cannot create shm");
+		if (!shm->handlers->can_readonly(shm)) {
+			xc_readonly_protection = 0;
+		}
+
+		if (xc_php_size) {
+			CHECK(xc_php_caches = xc_cache_init(shm, xc_php_allocator, &xc_php_hcache, &xc_php_hentry, &xc_php_hentry, xc_php_size), "failed init opcode cache");
+		}
+
+		if (xc_var_size) {
+			CHECK(xc_var_caches = xc_cache_init(shm, xc_var_allocator, &xc_var_hcache, &xc_var_hentry, NULL, xc_var_size), "failed init variable cache");
+		}
+	}
+	return SUCCESS;
+
+err:
+	if (xc_php_caches || xc_var_caches) {
+		xc_destroy();
+		/* shm destroied in xc_destroy() */
+	}
+	else if (shm) {
+		xc_destroy();
+		xc_shm_destroy(shm);
+		shm = NULL;
+	}
+	return 0;
+}
+/* }}} */
+static void xc_request_init(TSRMLS_D) /* {{{ */
+{
+	size_t i;
+
+	if (!XG(internal_table_copied)) {
+		zend_function tmp_func;
+		xc_cest_t tmp_cest;
+
+#ifdef HAVE_XCACHE_CONSTANT
+		zend_hash_destroy(&XG(internal_constant_table));
+#endif
+		zend_hash_destroy(&XG(internal_function_table));
+		zend_hash_destroy(&XG(internal_class_table));
+
+#ifdef HAVE_XCACHE_CONSTANT
+		zend_hash_init_ex(&XG(internal_constant_table), 20,  NULL, (dtor_func_t) xc_zend_constant_dtor, 1, 0);
+#endif
+		zend_hash_init_ex(&XG(internal_function_table), 100, NULL, NULL, 1, 0);
+		zend_hash_init_ex(&XG(internal_class_table),    10,  NULL, NULL, 1, 0);
+
+#ifdef HAVE_XCACHE_CONSTANT
+		xc_copy_internal_zend_constants(&XG(internal_constant_table), EG(zend_constants));
+#endif
+		zend_hash_copy(&XG(internal_function_table), CG(function_table), NULL, &tmp_func, sizeof(tmp_func));
+		zend_hash_copy(&XG(internal_class_table), CG(class_table), NULL, &tmp_cest, sizeof(tmp_cest));
+
+		XG(internal_table_copied) = 1;
+	}
+	if (xc_php_caches && !XG(php_holds)) {
+		XG(php_holds_size) = xc_php_hcache.size;
+		XG(php_holds) = calloc(XG(php_holds_size), sizeof(xc_stack_t));
+		for (i = 0; i < xc_php_hcache.size; i ++) {
+			xc_stack_init(&XG(php_holds[i]));
+		}
+	}
+
+	if (xc_var_caches && !XG(var_holds)) {
+		XG(var_holds_size) = xc_var_hcache.size;
+		XG(var_holds) = calloc(XG(var_holds_size), sizeof(xc_stack_t));
+		for (i = 0; i < xc_var_hcache.size; i ++) {
+			xc_stack_init(&XG(var_holds[i]));
+		}
+	}
+	xc_var_namespace_init(TSRMLS_C);
+#ifdef ZEND_ENGINE_2
+	zend_llist_init(&XG(gc_op_arrays), sizeof(xc_gc_op_array_t), xc_gc_op_array, 0);
+#endif
+
+#if PHP_API_VERSION <= 20041225
+	XG(request_time) = time(NULL);
+#else
+	XG(request_time) = sapi_get_request_time(TSRMLS_C);
+#endif
+}
+/* }}} */
+static void xc_request_shutdown(TSRMLS_D) /* {{{ */
+{
+	xc_entry_unholds(TSRMLS_C);
+	xc_gc_expires_php(TSRMLS_C);
+	xc_gc_expires_var(TSRMLS_C);
+	xc_gc_deletes(TSRMLS_C);
+	xc_var_namespace_destroy(TSRMLS_C);
+#ifdef ZEND_ENGINE_2
+	zend_llist_destroy(&XG(gc_op_arrays));
+#endif
+}
+/* }}} */
+
+/* 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;
+
+	/* auth disabled, nothing to do.. */
+	if (!xc_admin_enable_auth) {
+		return 1;
+	}
+
+	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(XCACHE_WIKI_URL "/InstallAdministration" TSRMLS_CC, E_ERROR,
+				"xcache.admin.user and/or xcache.admin.pass settings is not configured."
+				" Make sure you've modified the correct php ini file for your php used in webserver.");
+		zend_bailout();
+	}
+	if (strlen(admin_pass) != 32) {
+		php_error_docref(NULL TSRMLS_CC, E_ERROR, "xcache.admin.pass is %lu chars unexpectedly, it is supposed to be the password after md5() which should be 32 chars", (unsigned long) strlen(admin_pass));
+		zend_bailout();
+	}
+
+#ifdef ZEND_ENGINE_2_1
+	zend_is_auto_global("_SERVER", sizeof("_SERVER") - 1 TSRMLS_CC);
+#endif
+	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 = Z_ARRVAL_P((*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, (unsigned char *) 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 "HTTP/1.0 401 Unauthorized"
+	sapi_add_header_ex(STR, sizeof(STR) - 1, 1, 1 TSRMLS_CC);
+#undef STR
+#define STR "WWW-authenticate: Basic Realm=\"XCache Administration\""
+	sapi_add_header_ex(STR, sizeof(STR) - 1, 1, 1 TSRMLS_CC);
+#undef STR
+#define STR "Content-type: text/html; charset=UTF-8"
+	sapi_add_header_ex(STR, sizeof(STR) - 1, 1, 1 TSRMLS_CC);
+#undef STR
+	ZEND_PUTS("<html>\n");
+	ZEND_PUTS("<head><title>XCache Authentication Failed</title></head>\n");
+	ZEND_PUTS("<body>\n");
+	ZEND_PUTS("<h1>XCache Authentication Failed</h1>\n");
+	ZEND_PUTS("<p>You're not authorized to access this page due to wrong username and/or password you typed.<br />The following check points is suggested:</p>\n");
+	ZEND_PUTS("<ul>\n");
+	ZEND_PUTS("<li>Be aware that `Username' and `Password' is case sense. Check capslock status led on your keyboard, and punch left/right Shift keys once for each</li>\n");
+	ZEND_PUTS("<li>Make sure the md5 password is generated correctly. You may use <a href=\"mkpassword.php\">mkpassword.php</a></li>\n");
+	ZEND_PUTS("<li>Reload browser cache by pressing F5 and/or Ctrl+F5, or simply clear browser cache after you've updated username/password in php ini.</li>\n");
+	ZEND_PUTS("</ul>\n");
+	ZEND_PUTS("Check <a href=\"" XCACHE_WIKI_URL "/InstallAdministration\">XCache wiki page</a> for more information.\n");
+	ZEND_PUTS("</body>\n");
+	ZEND_PUTS("</html>\n");
+
+	zend_bailout();
+	return 0;
+}
+/* }}} */
+static void xc_clear(long type, xc_cache_t *cache TSRMLS_DC) /* {{{ */
+{
+	xc_entry_t *e, *next;
+	int entryslotid, c;
+
+	ENTER_LOCK(cache) {
+		for (entryslotid = 0, c = cache->hentry->size; entryslotid < c; entryslotid ++) {
+			for (e = cache->cached->entries[entryslotid]; e; e = next) {
+				next = e->next;
+				xc_entry_remove_unlocked(type, cache, entryslotid, e TSRMLS_CC);
+			}
+			cache->cached->entries[entryslotid] = NULL;
+		}
+	} LEAVE_LOCK(cache);
+} /* }}} */
+/* {{{ xcache_admin_operate */
+typedef enum { XC_OP_COUNT, XC_OP_INFO, XC_OP_LIST, XC_OP_CLEAR, XC_OP_ENABLE } xcache_op_type;
+static void xcache_admin_operate(xcache_op_type optype, INTERNAL_FUNCTION_PARAMETERS)
+{
+	long type;
+	long size;
+	xc_cache_t *caches, *cache;
+	long id = 0;
+	zend_bool enable = 1;
+
+	xcache_admin_auth_check(TSRMLS_C);
+
+	if (!xc_initized) {
+		RETURN_NULL();
+	}
+
+	switch (optype) {
+		case XC_OP_COUNT:
+			if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &type) == FAILURE) {
+				return;
+			}
+			break;
+
+		case XC_OP_CLEAR:
+			id = -1;
+			if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l|l", &type, &id) == FAILURE) {
+				return;
+			}
+			break;
+
+		case XC_OP_ENABLE:
+			id = -1;
+			if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l|lb", &type, &id, &enable) == FAILURE) {
+				return;
+			}
+			break;
+
+		default:
+			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(caches ? size : 0)
+			break;
+
+		case XC_OP_INFO:
+		case XC_OP_LIST:
+			if (!caches || 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_unlocked(type, cache, return_value TSRMLS_CC);
+				}
+				else {
+					xc_filllist_unlocked(type, cache, return_value TSRMLS_CC);
+				}
+			} LEAVE_LOCK(cache);
+			break;
+
+		case XC_OP_CLEAR:
+			if (!caches || id < -1 || id >= size) {
+				php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cache not exists");
+				RETURN_FALSE;
+			}
+
+			if (id == -1) {
+				for (id = 0; id < size; ++id) {
+					xc_clear(type, &caches[id] TSRMLS_CC);
+				}
+			}
+			else {
+				xc_clear(type, &caches[id] TSRMLS_CC);
+			}
+
+			xc_gc_deletes(TSRMLS_C);
+			break;
+
+		case XC_OP_ENABLE:
+			if (!caches || id < -1 || id >= size) {
+				php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cache not exists");
+				RETURN_FALSE;
+			}
+
+			if (id == -1) {
+				for (id = 0; id < size; ++id) {
+					caches[id].cached->disabled = !enable ? XG(request_time) : 0;
+				}
+			}
+			else {
+				caches[id].cached->disabled = !enable ? XG(request_time) : 0;
+			}
+
+			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 = -1 ])
+   Clear cache by id on specified cache type */
+PHP_FUNCTION(xcache_clear_cache)
+{
+	xcache_admin_operate(XC_OP_CLEAR, INTERNAL_FUNCTION_PARAM_PASSTHRU);
+}
+/* }}} */
+/* {{{ proto array xcache_enable_cache(int type, [ int id = -1, [ bool enable = true ] ])
+   Enable or disable cache by id on specified cache type */
+PHP_FUNCTION(xcache_enable_cache)
+{
+	xcache_admin_operate(XC_OP_ENABLE, INTERNAL_FUNCTION_PARAM_PASSTHRU);
+}
+/* }}} */
+/* {{{ proto mixed xcache_admin_namespace()
+   Break out of namespace limitation */
+PHP_FUNCTION(xcache_admin_namespace)
+{
+	xcache_admin_auth_check(TSRMLS_C);
+	xc_var_namespace_break(TSRMLS_C);
+}
+/* }}} */
+
+#define VAR_CACHE_NOT_INITIALIZED() do { \
+		php_error_docref(NULL TSRMLS_CC, E_WARNING, "XCache var cache was not initialized properly. Check php log for actual reason"); \
+} while (0)
+
+static int xc_entry_var_init_key(xc_entry_var_t *entry_var, xc_entry_hash_t *entry_hash, xc_namebuffer_t *name_buffer TSRMLS_DC) /* {{{ */
+{
+	xc_hash_value_t hv;
+
+#ifdef IS_UNICODE
+	entry_var->name_type = name->type;
+#endif
+	entry_var->entry.name.str.val = name_buffer->buffer;
+	entry_var->entry.name.str.len = name_buffer->len;
+
+	hv = xc_entry_hash_var((xc_entry_t *) entry_var TSRMLS_CC);
+
+	entry_hash->cacheid = (hv & xc_var_hcache.mask);
+	hv >>= xc_var_hcache.bits;
+	entry_hash->entryslotid = (hv & xc_var_hentry.mask);
+	return SUCCESS;
+}
+/* }}} */
+/* {{{ proto mixed xcache_set_namespace(string namespace)
+   Switch to user defined namespace */
+PHP_FUNCTION(xcache_set_namespace)
+{
+	zval *namespace;
+
+	if (!xc_var_caches) {
+		VAR_CACHE_NOT_INITIALIZED();
+		RETURN_NULL();
+	}
+
+	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &namespace) == FAILURE) {
+		return;
+	}
+
+	if (Z_TYPE_P(namespace) == IS_STRING) {
+		xc_var_namespace_set_stringl(Z_STRVAL_P(namespace), Z_STRLEN_P(namespace) TSRMLS_CC);
+	}
+#ifdef IS_UNICODE
+	else if (Z_TYPE_P(namespace) == IS_UNICODE) {
+		xc_var_namespace_set_unicodel(Z_USTRVAL_P(namespace), Z_USTRLEN_P(namespace) TSRMLS_CC);
+	}
+#endif
+}
+/* }}} */
+/* {{{ proto mixed xcache_get(string name)
+   Get cached data by specified name */
+PHP_FUNCTION(xcache_get)
+{
+	xc_entry_hash_t entry_hash;
+	xc_cache_t *cache;
+	xc_entry_var_t entry_var, *stored_entry_var;
+	zval *name;
+	VAR_BUFFER_FLAGS(name);
+
+	if (!xc_var_caches) {
+		VAR_CACHE_NOT_INITIALIZED();
+		RETURN_NULL();
+	}
+
+	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &name) == FAILURE) {
+		return;
+	}
+	VAR_BUFFER_INIT(name);
+	xc_entry_var_init_key(&entry_var, &entry_hash, &name_buffer TSRMLS_CC);
+	cache = &xc_var_caches[entry_hash.cacheid];
+
+	if (cache->cached->disabled) {
+		VAR_BUFFER_FREE(name);
+		RETURN_NULL();
+	}
+
+	ENTER_LOCK(cache) {
+		stored_entry_var = (xc_entry_var_t *) xc_entry_find_unlocked(XC_TYPE_VAR, cache, entry_hash.entryslotid, (xc_entry_t *) &entry_var TSRMLS_CC);
+		if (stored_entry_var) {
+			/* return */
+			xc_processor_restore_zval(return_value, stored_entry_var->value, stored_entry_var->have_references TSRMLS_CC);
+			xc_cached_hit_unlocked(cache->cached TSRMLS_CC);
+		}
+		else {
+			RETVAL_NULL();
+		}
+	} LEAVE_LOCK(cache);
+	VAR_BUFFER_FREE(name);
+}
+/* }}} */
+/* {{{ proto bool  xcache_set(string name, mixed value [, int ttl])
+   Store data to cache by specified name */
+PHP_FUNCTION(xcache_set)
+{
+	xc_entry_hash_t entry_hash;
+	xc_cache_t *cache;
+	xc_entry_var_t entry_var, *stored_entry_var;
+	zval *name;
+	zval *value;
+	VAR_BUFFER_FLAGS(name);
+
+	if (!xc_var_caches) {
+		VAR_CACHE_NOT_INITIALIZED();
+		RETURN_NULL();
+	}
+
+	entry_var.entry.ttl = XG(var_ttl);
+	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz|l", &name, &value, &entry_var.entry.ttl) == FAILURE) {
+		return;
+	}
+
+	if (Z_TYPE_P(value) == IS_OBJECT) {
+		php_error_docref(NULL TSRMLS_CC, E_ERROR, "Objects cannot be stored in the variable cache. Use serialize before xcache_set");
+		RETURN_NULL();
+	}
+
+	/* max ttl */
+	if (xc_var_maxttl && (!entry_var.entry.ttl || entry_var.entry.ttl > xc_var_maxttl)) {
+		entry_var.entry.ttl = xc_var_maxttl;
+	}
+
+	VAR_BUFFER_INIT(name);
+	xc_entry_var_init_key(&entry_var, &entry_hash, &name_buffer TSRMLS_CC);
+	cache = &xc_var_caches[entry_hash.cacheid];
+
+	if (cache->cached->disabled) {
+		VAR_BUFFER_FREE(name);
+		RETURN_NULL();
+	}
+
+	ENTER_LOCK(cache) {
+		stored_entry_var = (xc_entry_var_t *) xc_entry_find_unlocked(XC_TYPE_VAR, cache, entry_hash.entryslotid, (xc_entry_t *) &entry_var TSRMLS_CC);
+		if (stored_entry_var) {
+			xc_entry_remove_unlocked(XC_TYPE_VAR, cache, entry_hash.entryslotid, (xc_entry_t *) stored_entry_var TSRMLS_CC);
+		}
+		entry_var.value = value;
+		RETVAL_BOOL(xc_entry_var_store_unlocked(cache, entry_hash.entryslotid, &entry_var TSRMLS_CC) != NULL ? 1 : 0);
+	} LEAVE_LOCK(cache);
+	VAR_BUFFER_FREE(name);
+}
+/* }}} */
+/* {{{ proto bool  xcache_isset(string name)
+   Check if an entry exists in cache by specified name */
+PHP_FUNCTION(xcache_isset)
+{
+	xc_entry_hash_t entry_hash;
+	xc_cache_t *cache;
+	xc_entry_var_t entry_var, *stored_entry_var;
+	zval *name;
+	VAR_BUFFER_FLAGS(name);
+
+	if (!xc_var_caches) {
+		VAR_CACHE_NOT_INITIALIZED();
+		RETURN_FALSE;
+	}
+
+	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &name) == FAILURE) {
+		return;
+	}
+	VAR_BUFFER_INIT(name);
+	xc_entry_var_init_key(&entry_var, &entry_hash, &name_buffer TSRMLS_CC);
+	cache = &xc_var_caches[entry_hash.cacheid];
+
+	if (cache->cached->disabled) {
+		VAR_BUFFER_FREE(name);
+		RETURN_FALSE;
+	}
+
+	ENTER_LOCK(cache) {
+		stored_entry_var = (xc_entry_var_t *) xc_entry_find_unlocked(XC_TYPE_VAR, cache, entry_hash.entryslotid, (xc_entry_t *) &entry_var TSRMLS_CC);
+		if (stored_entry_var) {
+			xc_cached_hit_unlocked(cache->cached TSRMLS_CC);
+			RETVAL_TRUE;
+			/* return */
+		}
+		else {
+			RETVAL_FALSE;
+		}
+
+	} LEAVE_LOCK(cache);
+	VAR_BUFFER_FREE(name);
+}
+/* }}} */
+/* {{{ proto bool  xcache_unset(string name)
+   Unset existing data in cache by specified name */
+PHP_FUNCTION(xcache_unset)
+{
+	xc_entry_hash_t entry_hash;
+	xc_cache_t *cache;
+	xc_entry_var_t entry_var, *stored_entry_var;
+	zval *name;
+	VAR_BUFFER_FLAGS(name);
+
+	if (!xc_var_caches) {
+		VAR_CACHE_NOT_INITIALIZED();
+		RETURN_FALSE;
+	}
+
+	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &name) == FAILURE) {
+		return;
+	}
+	VAR_BUFFER_INIT(name);
+	xc_entry_var_init_key(&entry_var, &entry_hash, &name_buffer TSRMLS_CC);
+	cache = &xc_var_caches[entry_hash.cacheid];
+
+	if (cache->cached->disabled) {
+		VAR_BUFFER_FREE(name);
+		RETURN_FALSE;
+	}
+
+	ENTER_LOCK(cache) {
+		stored_entry_var = (xc_entry_var_t *) xc_entry_find_unlocked(XC_TYPE_VAR, cache, entry_hash.entryslotid, (xc_entry_t *) &entry_var TSRMLS_CC);
+		if (stored_entry_var) {
+			xc_entry_remove_unlocked(XC_TYPE_VAR, cache, entry_hash.entryslotid, (xc_entry_t *) stored_entry_var TSRMLS_CC);
+			RETVAL_TRUE;
+		}
+		else {
+			RETVAL_FALSE;
+		}
+	} LEAVE_LOCK(cache);
+	VAR_BUFFER_FREE(name);
+}
+/* }}} */
+/* {{{ proto bool  xcache_unset_by_prefix(string prefix)
+   Unset existing data in cache by specified prefix */
+PHP_FUNCTION(xcache_unset_by_prefix)
+{
+	zval *prefix;
+	int i, iend;
+
+	if (!xc_var_caches) {
+		VAR_CACHE_NOT_INITIALIZED();
+		RETURN_FALSE;
+	}
+
+	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &prefix) == FAILURE) {
+		return;
+	}
+
+	for (i = 0, iend = xc_var_hcache.size; i < iend; i ++) {
+		xc_cache_t *cache = &xc_var_caches[i];
+		if (cache->cached->disabled) {
+			continue;
+		}
+
+		ENTER_LOCK(cache) {
+			int entryslotid, jend;
+			for (entryslotid = 0, jend = cache->hentry->size; entryslotid < jend; entryslotid ++) {
+				xc_entry_t *entry, *next;
+				for (entry = cache->cached->entries[entryslotid]; entry; entry = next) {
+					next = entry->next;
+					if (xc_var_has_prefix(entry, prefix TSRMLS_CC)) {
+						xc_entry_remove_unlocked(XC_TYPE_VAR, cache, entryslotid, entry TSRMLS_CC);
+					}
+				}
+			}
+		} LEAVE_LOCK(cache);
+	}
+}
+/* }}} */
+static inline void xc_var_inc_dec(int inc, INTERNAL_FUNCTION_PARAMETERS) /* {{{ */
+{
+	xc_entry_hash_t entry_hash;
+	xc_cache_t *cache;
+	xc_entry_var_t entry_var, *stored_entry_var;
+	zval *name;
+	long count = 1;
+	long value = 0;
+	zval oldzval;
+	VAR_BUFFER_FLAGS(name);
+
+	if (!xc_var_caches) {
+		VAR_CACHE_NOT_INITIALIZED();
+		RETURN_NULL();
+	}
+
+	entry_var.entry.ttl = XG(var_ttl);
+	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|ll", &name, &count, &entry_var.entry.ttl) == FAILURE) {
+		return;
+	}
+
+	/* max ttl */
+	if (xc_var_maxttl && (!entry_var.entry.ttl || entry_var.entry.ttl > xc_var_maxttl)) {
+		entry_var.entry.ttl = xc_var_maxttl;
+	}
+
+	VAR_BUFFER_INIT(name);
+	xc_entry_var_init_key(&entry_var, &entry_hash, &name_buffer TSRMLS_CC);
+	cache = &xc_var_caches[entry_hash.cacheid];
+
+	if (cache->cached->disabled) {
+		VAR_BUFFER_FREE(name);
+		RETURN_NULL();
+	}
+
+	ENTER_LOCK(cache) {
+		stored_entry_var = (xc_entry_var_t *) xc_entry_find_unlocked(XC_TYPE_VAR, cache, entry_hash.entryslotid, (xc_entry_t *) &entry_var TSRMLS_CC);
+		if (stored_entry_var) {
+			TRACE("incdec: got entry_var %s", entry_var.entry.name.str.val);
+			/* do it in place */
+			if (Z_TYPE_P(stored_entry_var->value) == IS_LONG) {
+				zval *zv;
+				stored_entry_var->entry.ctime = XG(request_time);
+				stored_entry_var->entry.ttl   = entry_var.entry.ttl;
+				TRACE("%s", "incdec: islong");
+				value = Z_LVAL_P(stored_entry_var->value);
+				value += (inc == 1 ? count : - count);
+				RETVAL_LONG(value);
+
+				zv = (zval *) cache->shm->handlers->to_readwrite(cache->shm, (char *) stored_entry_var->value);
+				Z_LVAL_P(zv) = value;
+				++cache->cached->updates;
+				break; /* leave lock */
+			}
+
+			TRACE("%s", "incdec: notlong");
+			xc_processor_restore_zval(&oldzval, stored_entry_var->value, stored_entry_var->have_references TSRMLS_CC);
+			convert_to_long(&oldzval);
+			value = Z_LVAL(oldzval);
+			zval_dtor(&oldzval);
+		}
+		else {
+			TRACE("incdec: %s not found", entry_var.entry.name.str.val);
+		}
+
+		value += (inc == 1 ? count : - count);
+		RETVAL_LONG(value);
+		entry_var.value = return_value;
+
+		if (stored_entry_var) {
+			entry_var.entry.atime = stored_entry_var->entry.atime;
+			entry_var.entry.ctime = stored_entry_var->entry.ctime;
+			entry_var.entry.hits  = stored_entry_var->entry.hits;
+			xc_entry_remove_unlocked(XC_TYPE_VAR, cache, entry_hash.entryslotid, (xc_entry_t *) stored_entry_var TSRMLS_CC);
+		}
+		xc_entry_var_store_unlocked(cache, entry_hash.entryslotid, &entry_var TSRMLS_CC);
+	} LEAVE_LOCK(cache);
+	VAR_BUFFER_FREE(name);
+}
+/* }}} */
+/* {{{ 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);
+}
+/* }}} */
+static zend_function_entry xcache_cacher_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_enable_cache,      NULL)
+	PHP_FE(xcache_admin_namespace,   NULL)
+	PHP_FE(xcache_set_namespace,     NULL)
+	PHP_FE(xcache_get,               NULL)
+	PHP_FE(xcache_set,               NULL)
+	PHP_FE(xcache_isset,             NULL)
+	PHP_FE(xcache_unset,             NULL)
+	PHP_FE(xcache_unset_by_prefix,   NULL)
+	PHP_FE(xcache_inc,               NULL)
+	PHP_FE(xcache_dec,               NULL)
+	PHP_FE_END
+};
+/* }}} */
+
+static int xc_cacher_zend_startup(zend_extension *extension) /* {{{ */
+{
+	if ((xc_php_size || xc_var_size) && xc_mmap_path && xc_mmap_path[0]) {
+		if (xc_init() != SUCCESS) {
+			zend_error(E_ERROR, "XCache: Cannot init");
+			return FAILURE;
+		}
+		xc_initized = 1;
+		xc_init_time = time(NULL);
+#ifdef PHP_WIN32
+		xc_init_instance_id = GetCurrentProcessId();
+#else
+		xc_init_instance_id = getpid();
+#endif
+#ifdef ZTS
+		xc_init_instance_subid = tsrm_thread_id();
+#endif
+	}
+
+	if (xc_php_size) {
+		old_compile_file = zend_compile_file;
+		zend_compile_file = xc_compile_file;
+	}
+
+	return SUCCESS;
+}
+/* }}} */
+static void xc_cacher_zend_shutdown(zend_extension *extension) /* {{{ */
+{
+	if (xc_initized) {
+		xc_destroy();
+	}
+}
+/* }}} */
+/* {{{ zend extension definition structure */
+static zend_extension xc_cacher_zend_extension_entry = {
+	XCACHE_NAME " Cacher",
+	XCACHE_VERSION,
+	XCACHE_AUTHOR,
+	XCACHE_URL,
+	XCACHE_COPYRIGHT,
+	xc_cacher_zend_startup,
+	xc_cacher_zend_shutdown,
+	NULL,           /* activate_func_t */
+	NULL,           /* deactivate_func_t */
+	NULL,           /* message_handler_func_t */
+	NULL,           /* op_array_handler_func_t */
+	NULL,           /* statement_handler_func_t */
+	NULL,           /* fcall_begin_handler_func_t */
+	NULL,           /* fcall_end_handler_func_t */
+	NULL,           /* op_array_ctor_func_t */
+	NULL,           /* op_array_dtor_func_t */
+	STANDARD_ZEND_EXTENSION_PROPERTIES
+};
+/* }}} */
+
+/* {{{ ini */
+#ifdef ZEND_WIN32
+#	define DEFAULT_PATH "xcache"
+#else
+#	define DEFAULT_PATH "/dev/zero"
+#endif
+PHP_INI_BEGIN()
+	PHP_INI_ENTRY1     ("xcache.shm_scheme",          "mmap", PHP_INI_SYSTEM, xcache_OnUpdateString,   &xc_shm_scheme)
+	PHP_INI_ENTRY1     ("xcache.mmap_path",     DEFAULT_PATH, PHP_INI_SYSTEM, xcache_OnUpdateString,   &xc_mmap_path)
+	PHP_INI_ENTRY1_EX  ("xcache.readonly_protection",    "0", PHP_INI_SYSTEM, xcache_OnUpdateBool,     &xc_readonly_protection, zend_ini_boolean_displayer_cb)
+	/* opcode cache */
+	PHP_INI_ENTRY1_EX  ("xcache.admin.enable_auth",      "1", PHP_INI_SYSTEM, xcache_OnUpdateBool,     &xc_admin_enable_auth,   zend_ini_boolean_displayer_cb)
+	PHP_INI_ENTRY1     ("xcache.size",                   "0", PHP_INI_SYSTEM, xcache_OnUpdateDummy,    NULL)
+	PHP_INI_ENTRY1     ("xcache.count",                  "1", PHP_INI_SYSTEM, xcache_OnUpdateDummy,    NULL)
+	PHP_INI_ENTRY1     ("xcache.slots",                 "8K", PHP_INI_SYSTEM, xcache_OnUpdateDummy,    NULL)
+	PHP_INI_ENTRY1     ("xcache.allocator",        "bestfit", PHP_INI_SYSTEM, xcache_OnUpdateString,   &xc_php_allocator)
+	PHP_INI_ENTRY1     ("xcache.ttl",                    "0", PHP_INI_SYSTEM, xcache_OnUpdateULong,    &xc_php_ttl)
+	PHP_INI_ENTRY1     ("xcache.gc_interval",            "0", PHP_INI_SYSTEM, xcache_OnUpdateULong,    &xc_php_gc_interval)
+	STD_PHP_INI_BOOLEAN("xcache.cacher",                 "1", PHP_INI_ALL,    OnUpdateBool,    cacher, zend_xcache_globals, xcache_globals)
+	STD_PHP_INI_BOOLEAN("xcache.stat",                   "1", PHP_INI_ALL,    OnUpdateBool,    stat,   zend_xcache_globals, xcache_globals)
+	/* var cache */
+	PHP_INI_ENTRY1     ("xcache.var_size",               "0", PHP_INI_SYSTEM, xcache_OnUpdateDummy,    NULL)
+	PHP_INI_ENTRY1     ("xcache.var_count",              "1", PHP_INI_SYSTEM, xcache_OnUpdateDummy,    NULL)
+	PHP_INI_ENTRY1     ("xcache.var_slots",             "8K", PHP_INI_SYSTEM, xcache_OnUpdateDummy,    NULL)
+	PHP_INI_ENTRY1     ("xcache.var_maxttl",             "0", PHP_INI_SYSTEM, xcache_OnUpdateULong,    &xc_var_maxttl)
+	PHP_INI_ENTRY1     ("xcache.var_gc_interval",      "120", PHP_INI_SYSTEM, xcache_OnUpdateULong,    &xc_var_gc_interval)
+	PHP_INI_ENTRY1     ("xcache.var_allocator",    "bestfit", PHP_INI_SYSTEM, xcache_OnUpdateString,   &xc_var_allocator)
+	STD_PHP_INI_ENTRY  ("xcache.var_ttl",                "0", PHP_INI_ALL,    OnUpdateLong, var_ttl,   zend_xcache_globals, xcache_globals)
+	PHP_INI_ENTRY1     ("xcache.var_namespace_mode",     "0", PHP_INI_SYSTEM, xcache_OnUpdateULong,    &xc_var_namespace_mode)
+	PHP_INI_ENTRY1     ("xcache.var_namespace",           "", PHP_INI_SYSTEM, xcache_OnUpdateString,   &xc_var_namespace)
+PHP_INI_END()
+/* }}} */
+static PHP_MINFO_FUNCTION(xcache_cacher) /* {{{ */
+{
+	char buf[100];
+	char *ptr;
+	int left, len;
+	xc_shm_scheme_t *scheme;
+
+	php_info_print_table_start();
+	php_info_print_table_row(2, "XCache Cacher Module", "enabled");
+	php_info_print_table_row(2, "Readonly Protection", xc_readonly_protection ? "enabled" : "disabled");
+#ifdef ZEND_ENGINE_2_1
+	ptr = php_format_date("Y-m-d H:i:s", sizeof("Y-m-d H:i:s") - 1, XG(request_time), 1 TSRMLS_CC);
+	php_info_print_table_row(2, "Page Request Time", ptr);
+	efree(ptr);
+
+	ptr = php_format_date("Y-m-d H:i:s", sizeof("Y-m-d H:i:s") - 1, xc_init_time, 1 TSRMLS_CC);
+	php_info_print_table_row(2, "Cache Init Time", ptr);
+	efree(ptr);
+#else
+	snprintf(buf, sizeof(buf), "%lu", (long unsigned) XG(request_time));
+	php_info_print_table_row(2, "Page Request Time", buf);
+
+	snprintf(buf, sizeof(buf), "%lu", (long unsigned) xc_init_time);
+	php_info_print_table_row(2, "Cache Init Time", buf);
+#endif
+
+#ifdef ZTS
+	snprintf(buf, sizeof(buf), "%lu.%lu", xc_init_instance_id, xc_init_instance_subid);
+#else
+	snprintf(buf, sizeof(buf), "%lu", xc_init_instance_id);
+#endif
+	php_info_print_table_row(2, "Cache Instance Id", buf);
+
+	if (xc_php_size) {
+		ptr = _php_math_number_format(xc_php_size, 0, '.', ',');
+		snprintf(buf, sizeof(buf), "enabled, %s bytes, %lu split(s), with %lu slots each", ptr, (unsigned long) xc_php_hcache.size, xc_php_hentry.size);
+		php_info_print_table_row(2, "Opcode Cache", buf);
+		efree(ptr);
+	}
+	else {
+		php_info_print_table_row(2, "Opcode Cache", "disabled");
+	}
+	if (xc_var_size) {
+		ptr = _php_math_number_format(xc_var_size, 0, '.', ',');
+		snprintf(buf, sizeof(buf), "enabled, %s bytes, %lu split(s), with %lu slots each", ptr, (unsigned long) xc_var_hcache.size, xc_var_hentry.size);
+		php_info_print_table_row(2, "Variable Cache", buf);
+		efree(ptr);
+	}
+	else {
+		php_info_print_table_row(2, "Variable Cache", "disabled");
+	}
+
+	left = sizeof(buf);
+	ptr = buf;
+	buf[0] = '\0';
+	for (scheme = xc_shm_scheme_first(); scheme; scheme = xc_shm_scheme_next(scheme)) {
+		len = snprintf(ptr, left, ptr == buf ? "%s" : ", %s", xc_shm_scheme_name(scheme));
+		left -= len;
+		ptr += len;
+	}
+	php_info_print_table_row(2, "Shared Memory Schemes", buf);
+
+	php_info_print_table_end();
+
+	DISPLAY_INI_ENTRIES();
+}
+/* }}} */
+static int xc_config_hash(xc_hash_t *p, char *name, char *default_value) /* {{{ */
+{
+	size_t bits, size;
+	char *value;
+
+	if (cfg_get_string(name, &value) != SUCCESS) {
+		value = default_value;
+	}
+
+	p->size = zend_atoi(value, strlen(value));
+	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 int xc_config_long(zend_ulong *p, char *name, char *default_value) /* {{{ */
+{
+	char *value;
+
+	if (cfg_get_string(name, &value) != SUCCESS) {
+		value = default_value;
+	}
+
+	*p = zend_atol(value, strlen(value));
+	return SUCCESS;
+}
+/* }}} */
+static PHP_MINIT_FUNCTION(xcache_cacher) /* {{{ */
+{
+	zend_extension *ext;
+	zend_llist_position lpos;
+
+	ext = zend_get_extension("Zend Optimizer");
+	if (ext) {
+		/* zend_optimizer.optimization_level>0 is not compatible with other cacher, disabling */
+		ext->op_array_handler = NULL;
+	}
+	/* cache if there's an op_array_ctor */
+	for (ext = zend_llist_get_first_ex(&zend_extensions, &lpos);
+			ext;
+			ext = zend_llist_get_next_ex(&zend_extensions, &lpos)) {
+		if (ext->op_array_ctor) {
+			xc_have_op_array_ctor = 1;
+			break;
+		}
+	}
+
+	xc_config_long(&xc_php_size,       "xcache.size",        "0");
+	xc_config_hash(&xc_php_hcache,     "xcache.count",       "1");
+	xc_config_hash(&xc_php_hentry,     "xcache.slots",      "8K");
+
+	xc_config_long(&xc_var_size,       "xcache.var_size",    "0");
+	xc_config_hash(&xc_var_hcache,     "xcache.var_count",   "1");
+	xc_config_hash(&xc_var_hentry,     "xcache.var_slots",  "8K");
+
+	if (strcmp(sapi_module.name, "cli") == 0) {
+		if (!xc_test) {
+			/* disable cache for cli except for testing */
+			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;
+	}
+
+	xc_init_constant(module_number TSRMLS_CC);
+
+	REGISTER_INI_ENTRIES();
+
+	xc_sandbox_module_init(module_number TSRMLS_CC);
+	return xcache_zend_extension_add(&xc_cacher_zend_extension_entry, 0);
+}
+/* }}} */
+static PHP_MSHUTDOWN_FUNCTION(xcache_cacher) /* {{{ */
+{
+	xc_sandbox_module_shutdown();
+
+	xcache_zend_extension_remove(&xc_cacher_zend_extension_entry);
+	UNREGISTER_INI_ENTRIES();
+
+	if (xc_mmap_path) {
+		pefree(xc_mmap_path, 1);
+		xc_mmap_path = NULL;
+	}
+	if (xc_shm_scheme) {
+		pefree(xc_shm_scheme, 1);
+		xc_shm_scheme = NULL;
+	}
+	if (xc_php_allocator) {
+		pefree(xc_php_allocator, 1);
+		xc_php_allocator = NULL;
+	}
+	if (xc_var_allocator) {
+		pefree(xc_var_allocator, 1);
+		xc_var_allocator = NULL;
+	}
+	if (xc_var_namespace) {
+		pefree(xc_var_namespace, 1);
+		xc_var_namespace = NULL;
+	}
+
+	return SUCCESS;
+}
+/* }}} */
+static PHP_RINIT_FUNCTION(xcache_cacher) /* {{{ */
+{
+	xc_request_init(TSRMLS_C);
+	return SUCCESS;
+}
+/* }}} */
+/* {{{ static PHP_RSHUTDOWN_FUNCTION(xcache_cacher) */
+#ifndef ZEND_ENGINE_2
+static PHP_RSHUTDOWN_FUNCTION(xcache_cacher)
+#else
+static ZEND_MODULE_POST_ZEND_DEACTIVATE_D(xcache_cacher)
+#endif
+{
+#ifdef ZEND_ENGINE_2
+	TSRMLS_FETCH();
+#endif
+
+	xc_request_shutdown(TSRMLS_C);
+	return SUCCESS;
+}
+/* }}} */
+static zend_module_entry xcache_cacher_module_entry = { /* {{{ */
+	STANDARD_MODULE_HEADER,
+	XCACHE_NAME " Cacher",
+	xcache_cacher_functions,
+	PHP_MINIT(xcache_cacher),
+	PHP_MSHUTDOWN(xcache_cacher),
+	PHP_RINIT(xcache_cacher),
+#ifndef ZEND_ENGINE_2
+	PHP_RSHUTDOWN(xcache_cacher),
+#else
+	NULL,
+#endif
+	PHP_MINFO(xcache_cacher),
+	XCACHE_VERSION,
+#ifdef PHP_GINIT
+	NO_MODULE_GLOBALS,
+#endif
+#ifdef ZEND_ENGINE_2
+	ZEND_MODULE_POST_ZEND_DEACTIVATE_N(xcache_cacher),
+#else
+	NULL,
+	NULL,
+#endif
+	STANDARD_MODULE_PROPERTIES_EX
+};
+/* }}} */
+int xc_cacher_startup_module() /* {{{ */
+{
+	return zend_startup_module(&xcache_cacher_module_entry);
+}
+/* }}} */
+void xc_cacher_disable() /* {{{ */
+{
+	time_t now = time(NULL);
+	size_t i;
+
+	if (xc_php_caches) {
+		for (i = 0; i < xc_php_hcache.size; i ++) {
+			if (xc_php_caches[i].cached) {
+				xc_php_caches[i].cached->disabled = now;
+			}
+		}
+	}
+
+	if (xc_var_caches) {
+		for (i = 0; i < xc_var_hcache.size; i ++) {
+			if (xc_var_caches[i].cached) {
+				xc_var_caches[i].cached->disabled = now;
+			}
+		}
+	}
+}
+/* }}} */
Index: /tags/3.0.0-rc1/mod_cacher/xc_cache.h
===================================================================
--- /tags/3.0.0-rc1/mod_cacher/xc_cache.h	(revision 1132)
+++ /tags/3.0.0-rc1/mod_cacher/xc_cache.h	(revision 1132)
@@ -0,0 +1,202 @@
+#ifndef XC_CACHE_H_684B099102B4651FB10058EF6F7E80CE
+#define XC_CACHE_H_684B099102B4651FB10058EF6F7E80CE
+
+#if _MSC_VER > 1000
+#pragma once
+#endif /* _MSC_VER > 1000 */
+
+#include "xcache.h"
+#include "xcache/xc_compatibility.h"
+
+typedef ulong xc_hash_value_t;
+typedef struct _xc_hash_t xc_hash_t;
+typedef struct _xc_cached_t xc_cached_t;
+typedef struct _xc_entry_t xc_entry_t;
+typedef struct _xc_entry_data_php_t xc_entry_data_php_t;
+
+struct _xc_lock_t;
+struct _xc_shm_t;
+/* {{{ xc_op_array_info_detail_t */
+typedef struct {
+	zend_uint index;
+	zend_uint info;
+} xc_op_array_info_detail_t;
+/* }}} */
+/* {{{ xc_op_array_info_t */
+typedef struct {
+#ifdef ZEND_ENGINE_2_4
+	zend_uint literalinfo_cnt;
+	xc_op_array_info_detail_t *literalinfos;
+#else
+	zend_uint oplineinfo_cnt;
+	xc_op_array_info_detail_t *oplineinfos;
+#endif
+} xc_op_array_info_t;
+/* }}} */
+/* {{{ xc_classinfo_t */
+typedef struct {
+#ifdef IS_UNICODE
+	zend_uchar   type;
+#endif
+	const24_zstr key;
+	zend_uint    key_size;
+	ulong        h;
+	zend_uint  methodinfo_cnt;
+	xc_op_array_info_t *methodinfos;
+	xc_cest_t    cest;
+#ifndef ZEND_COMPILE_DELAYED_BINDING
+	int          oplineno;
+#endif
+} xc_classinfo_t;
+/* }}} */
+#ifdef HAVE_XCACHE_CONSTANT
+/* {{{ xc_constinfo_t */
+typedef struct {
+#ifdef IS_UNICODE
+	zend_uchar    type;
+#endif
+	const24_zstr  key;
+	zend_uint     key_size;
+	ulong         h;
+	zend_constant constant;
+} xc_constinfo_t;
+/* }}} */
+#endif
+/* {{{ xc_funcinfo_t */
+typedef struct {
+#ifdef IS_UNICODE
+	zend_uchar     type;
+#endif
+	const24_zstr   key;
+	zend_uint      key_size;
+	ulong          h;
+	xc_op_array_info_t op_array_info;
+	zend_function func;
+} xc_funcinfo_t;
+/* }}} */
+#ifdef ZEND_ENGINE_2_1
+/* {{{ xc_autoglobal_t */
+typedef struct {
+#ifdef IS_UNICODE
+	zend_uchar   type;
+#endif
+	const24_zstr key;
+	zend_uint    key_len;
+	ulong        h;
+} xc_autoglobal_t;
+/* }}} */
+#endif
+
+typedef struct {
+	char digest[16];
+} xc_md5sum_t;
+struct _xc_compilererror_t;
+/* {{{ xc_entry_data_php_t */
+struct _xc_entry_data_php_t {
+	xc_entry_data_php_t *next;
+	xc_hash_value_t      hvalue;
+
+	xc_md5sum_t md5;        /* md5sum of the source */
+	zend_ulong  refcount;   /* count of entries referencing to this data */
+
+	zend_ulong hits;        /* hits of this php */
+	size_t     size;
+
+	xc_op_array_info_t op_array_info;
+	zend_op_array *op_array;
+
+#ifdef HAVE_XCACHE_CONSTANT
+	zend_uint constinfo_cnt;
+	xc_constinfo_t *constinfos;
+#endif
+
+	zend_uint funcinfo_cnt;
+	xc_funcinfo_t *funcinfos;
+
+	zend_uint classinfo_cnt;
+	xc_classinfo_t *classinfos;
+#ifndef ZEND_COMPILE_DELAYED_BINDING
+	zend_bool have_early_binding;
+#endif
+
+#ifdef ZEND_ENGINE_2_1
+	zend_uint autoglobal_cnt;
+	xc_autoglobal_t *autoglobals;
+#endif
+
+#ifdef XCACHE_ERROR_CACHING
+	zend_uint compilererror_cnt;
+	struct _xc_compilererror_t *compilererrors;
+#endif
+
+	zend_bool  have_references;
+};
+/* }}} */
+typedef zvalue_value xc_entry_name_t;
+/* {{{ xc_entry_t */
+struct _xc_entry_t {
+	xc_entry_t *next;
+
+	size_t     size;
+	time_t     ctime;           /* creation ctime of this entry */
+	time_t     atime;           /*   access atime of this entry */
+	time_t     dtime;           /*  deletion time of this entry */
+	zend_ulong hits;
+	zend_ulong ttl;
+
+	xc_entry_name_t name;
+};
+
+typedef struct {
+	xc_entry_t entry;
+	xc_entry_data_php_t *php;
+
+	zend_ulong refcount;    /* count of php instances holding this entry */
+	time_t file_mtime;
+	size_t file_size;
+	int file_device;
+	int file_inode;
+
+	int    filepath_len;
+	ZEND_24(NOTHING, const) char *filepath;
+	int    dirpath_len;
+	char  *dirpath;
+#ifdef IS_UNICODE
+	int    ufilepath_len;
+	UChar *ufilepath;
+	int    udirpath_len;
+	UChar *udirpath;
+#endif
+} xc_entry_php_t;
+
+typedef struct {
+	xc_entry_t entry;
+#ifdef IS_UNICODE
+	zend_uchar name_type;
+#endif
+	zval      *value;
+	zend_bool  have_references;
+} xc_entry_var_t;
+/* }}} */
+typedef struct xc_entry_hash_t { /* {{{ */
+	xc_hash_value_t cacheid;
+	xc_hash_value_t entryslotid;
+} xc_entry_hash_t;
+/* }}} */
+
+int xc_is_rw(const void *p);
+int xc_is_ro(const void *p);
+int xc_is_shm(const void *p);
+/* {{{ xc_gc_op_array_t */
+typedef struct {
+#ifdef ZEND_ENGINE_2
+	zend_uint num_args;
+	zend_arg_info *arg_info;
+#endif
+	zend_op *opcodes;
+} xc_gc_op_array_t;
+/* }}} */
+void xc_gc_add_op_array(xc_gc_op_array_t *gc_op_array TSRMLS_DC);
+void xc_fix_op_array_info(const xc_entry_php_t *xce, const xc_entry_data_php_t *php, zend_op_array *op_array, int shallow_copy, const xc_op_array_info_t *op_array_info TSRMLS_DC);
+
+#endif /* XC_CACHE_H_684B099102B4651FB10058EF6F7E80CE */
Index: /tags/3.0.0-rc1/mod_cacher/xc_cacher.h
===================================================================
--- /tags/3.0.0-rc1/mod_cacher/xc_cacher.h	(revision 1064)
+++ /tags/3.0.0-rc1/mod_cacher/xc_cacher.h	(revision 1064)
@@ -0,0 +1,11 @@
+#ifndef XC_CACHER_H_1CADCD7E46ABC70014D0766CE97B9741
+#define XC_CACHER_H_1CADCD7E46ABC70014D0766CE97B9741
+
+#if _MSC_VER > 1000
+#pragma once
+#endif /* _MSC_VER > 1000 */
+
+int xc_cacher_startup_module();
+void xc_cacher_disable();
+
+#endif /* XC_CACHER_H_1CADCD7E46ABC70014D0766CE97B9741 */
Index: /tags/3.0.0-rc1/xcache_globals.h
===================================================================
--- /tags/3.0.0-rc1/xcache_globals.h	(revision 1146)
+++ /tags/3.0.0-rc1/xcache_globals.h	(revision 1146)
@@ -0,0 +1,48 @@
+#include "util/xc_stack.h"
+
+ZEND_BEGIN_MODULE_GLOBALS(xcache)
+	zend_bool initial_compile_file_called; /* true is origin_compile_file is called */
+	zend_bool cacher;      /* true if enabled */
+	zend_bool stat;
+	zend_bool experimental;
+#ifdef HAVE_XCACHE_OPTIMIZER
+	zend_bool optimizer;   /* true if enabled */
+#endif
+#ifdef HAVE_XCACHE_COVERAGER
+	zend_bool coverager;
+	zend_bool coverager_autostart;
+	zend_bool coverager_started;
+	HashTable *coverages;  /* coverages[file][line] = times */
+#endif
+	xc_stack_t *php_holds;
+	zend_uint php_holds_size;
+	xc_stack_t *var_holds;
+	zend_uint var_holds_size;
+	time_t request_time;
+	long   var_ttl;
+#ifdef IS_UNCODE
+	zval uvar_namespace_hard;
+	zval uvar_namespace_soft;
+#endif
+	zval var_namespace_hard;
+	zval var_namespace_soft;
+
+	zend_llist gc_op_arrays;
+
+#ifdef HAVE_XCACHE_CONSTANT
+	HashTable internal_constant_table;
+#endif
+	HashTable internal_function_table;
+	HashTable internal_class_table;
+	zend_bool internal_table_copied;
+
+	void *sandbox;
+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/3.0.0-rc1/AUTHORS
===================================================================
--- /tags/3.0.0-rc1/AUTHORS	(revision 393)
+++ /tags/3.0.0-rc1/AUTHORS	(revision 393)
@@ -0,0 +1,1 @@
+mOo <phpxcache@gmail.com>
Index: /tags/3.0.0-rc1/xcache-test.ini
===================================================================
--- /tags/3.0.0-rc1/xcache-test.ini	(revision 1026)
+++ /tags/3.0.0-rc1/xcache-test.ini	(revision 1026)
@@ -0,0 +1,25 @@
+memory_limit = 256M
+error_reporting = E_ALL|E_STRICT
+
+[xcache]
+extension_dir="./modules/"
+extension=xcache.so
+xcache.cacher = On
+xcache.test = 1
+xcache.stat = 1
+xcache.experimental = On
+xcache.size = 16M
+xcache.count = 1
+xcache.var_size = 1M
+xcache.var_count = 1
+xcache.var_slots = 1000
+; xcache.mmap_path = "/dev/zero"
+xcache.mmap_path = "/tmp/xcache"
+xcache.readonly_protection = Off
+xcache.optimizer = On
+xcache.coredump_directory = "/tmp/"
+;xcache.coveragedump_directory = "/tmp/pcov/"
+xcache.coverager = On
+
+xcache.admin.user = "test"
+xcache.admin.pass = "098f6bcd4621d373cade4e832627b4f6"
Index: /tags/3.0.0-rc1/THANKS
===================================================================
--- /tags/3.0.0-rc1/THANKS	(revision 605)
+++ /tags/3.0.0-rc1/THANKS	(revision 605)
@@ -0,0 +1,9 @@
+
+Jan <jan@kneschke.de>, host XCache website
+Alex <ale@freebsd.org>, redist to FreeBSD
+darix <darix@irssi.org>, redist to openSUSE
+judas_iscariote <judas.iscariote@gmail.com>, redist/test with openSUSE
+Finjon Kiang <kiange@gmail.com>, Chinese Traditional translation
+
+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/3.0.0-rc1/Makefile.frag
===================================================================
--- /tags/3.0.0-rc1/Makefile.frag	(revision 1015)
+++ /tags/3.0.0-rc1/Makefile.frag	(revision 1015)
@@ -0,0 +1,35 @@
+XCACHE_PROC_SRC=$(srcdir)/processor/main.m4
+XCACHE_PROC_OUT=$(builddir)/processor.out.c
+XCACHE_PROC_C=$(builddir)/xc_processor.c.h
+XCACHE_PROC_H=$(builddir)/xc_processor.h
+XCACHE_INCLUDES_SRC=$(srcdir)/includes.c
+XCACHE_INCLUDES_I=$(builddir)/includes.i
+XCACHE_STRUCTINFO_OUT=$(builddir)/structinfo.m4
+
+$(XCACHE_INCLUDES_I):
+	$(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)/gen_structinfo.awk
+	@echo $(XCACHE_STRUCTINFO_OUT) is optional if XCache test is not enabled, feel free if it awk failed to produce it
+	-$(XCACHE_AWK) -f $(srcdir)/gen_structinfo.awk < $(XCACHE_INCLUDES_I) > $(XCACHE_STRUCTINFO_OUT).tmp && mv $(XCACHE_STRUCTINFO_OUT).tmp $(XCACHE_STRUCTINFO_OUT)
+
+$(XCACHE_PROC_OUT): $(XCACHE_PROC_SRC) $(XCACHE_STRUCTINFO_OUT) $(XCACHE_PROC_SOURCES)
+	$(M4) -D srcdir=$(XCACHE_BACKTICK)"$(srcdir)'" -D builddir=$(XCACHE_BACKTICK)"$(builddir)'" $(XCACHE_ENABLE_TEST) $(XCACHE_PROC_SRC) > $(XCACHE_PROC_OUT).tmp
+	mv $(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_PROC_H)
+	-$(XCACHE_INDENT) < $(XCACHE_PROC_H) > $(XCACHE_PROC_H).tmp && mv $(XCACHE_PROC_H).tmp $(XCACHE_PROC_H)
+
+$(XCACHE_PROC_C): $(XCACHE_PROC_OUT) $(XCACHE_PROC_H)
+	cp $(XCACHE_PROC_OUT) $(XCACHE_PROC_C)
+	-$(XCACHE_INDENT) < $(XCACHE_PROC_OUT) > $(XCACHE_PROC_C).tmp && mv $(XCACHE_PROC_C).tmp $(XCACHE_PROC_C)
+
+xcachesvnclean: clean
+	-svn propget svn:ignore . > .svnignore.tmp 2>/dev/null && mv .svnignore.tmp .svnignore
+	cat .svnignore | grep -v devel | grep -v svnignore | grep -v ^Makefile | grep -v ^config.nice | xargs rm -rf
+
+xcachetest: all
+	$(SED) "s#\\./modules/#$(top_builddir)/modules/#" < $(srcdir)/xcache-test.ini > $(top_builddir)/tmp-php.ini
+	TEST_PHP_SRCDIR=$(srcdir) $(srcdir)/run-xcachetest $(TESTS) $(TEST_ARGS) -c $(top_builddir)/tmp-php.ini
+	$(srcdir)/run-xcachetest $(TESTS) $(TEST_ARGS) -c $(top_builddir)/tmp-php.ini
Index: /tags/3.0.0-rc1/xcache/xc_opcode_spec_def.h
===================================================================
--- /tags/3.0.0-rc1/xcache/xc_opcode_spec_def.h	(revision 982)
+++ /tags/3.0.0-rc1/xcache/xc_opcode_spec_def.h	(revision 982)
@@ -0,0 +1,260 @@
+static const xc_opcode_spec_t xc_opcode_spec[] = {
+	OPSPEC(    UNUSED,     UNUSED,     UNUSED,     UNUSED) /* 0 NOP                            */
+	OPSPEC(    UNUSED,        STD,        STD,        TMP) /* 1 ADD                            */
+	OPSPEC(    UNUSED,        STD,        STD,        TMP) /* 2 SUB                            */
+	OPSPEC(    UNUSED,        STD,        STD,        TMP) /* 3 MUL                            */
+	OPSPEC(    UNUSED,        STD,        STD,        TMP) /* 4 DIV                            */
+	OPSPEC(    UNUSED,        STD,        STD,        TMP) /* 5 MOD                            */
+	OPSPEC(    UNUSED,        STD,        STD,        TMP) /* 6 SL                             */
+	OPSPEC(    UNUSED,        STD,        STD,        TMP) /* 7 SR                             */
+	OPSPEC(    UNUSED,        STD,        STD,        TMP) /* 8 CONCAT                         */
+	OPSPEC(    UNUSED,        STD,        STD,        TMP) /* 9 BW_OR                          */
+	OPSPEC(    UNUSED,        STD,        STD,        TMP) /* 10 BW_AND                         */
+	OPSPEC(    UNUSED,        STD,        STD,        TMP) /* 11 BW_XOR                         */
+	OPSPEC(    UNUSED,        STD,     UNUSED,        TMP) /* 12 BW_NOT                         */
+	OPSPEC(    UNUSED,        STD,        STD,        TMP) /* 13 BOOL_NOT                       */
+	OPSPEC(    UNUSED,        STD,        STD,        TMP) /* 14 BOOL_XOR                       */
+	OPSPEC(    UNUSED,        STD,        STD,        TMP) /* 15 IS_IDENTICAL                   */
+	OPSPEC(    UNUSED,        STD,        STD,        TMP) /* 16 IS_NOT_IDENTICAL               */
+	OPSPEC(    UNUSED,        STD,        STD,        TMP) /* 17 IS_EQUAL                       */
+	OPSPEC(    UNUSED,        STD,        STD,        TMP) /* 18 IS_NOT_EQUAL                   */
+	OPSPEC(    UNUSED,        STD,        STD,        TMP) /* 19 IS_SMALLER                     */
+	OPSPEC(    UNUSED,        STD,        STD,        TMP) /* 20 IS_SMALLER_OR_EQUAL            */
+	OPSPEC(      CAST,        STD,     UNUSED,        TMP) /* 21 CAST                           */
+	OPSPEC(    UNUSED,        STD,     UNUSED,        TMP) /* 22 QM_ASSIGN                      */
+#ifdef ZEND_ENGINE_2
+	OPSPEC(    ASSIGN,        STD,        STD,        VAR) /* 23 ASSIGN_ADD                     */
+	OPSPEC(    ASSIGN,        STD,        STD,        VAR) /* 24 ASSIGN_SUB                     */
+	OPSPEC(    ASSIGN,        STD,        STD,        VAR) /* 25 ASSIGN_MUL                     */
+	OPSPEC(    ASSIGN,        STD,        STD,        VAR) /* 26 ASSIGN_DIV                     */
+	OPSPEC(    ASSIGN,        STD,        STD,        VAR) /* 27 ASSIGN_MOD                     */
+	OPSPEC(    ASSIGN,        STD,        STD,        VAR) /* 28 ASSIGN_SL                      */
+	OPSPEC(    ASSIGN,        STD,        STD,        VAR) /* 29 ASSIGN_SR                      */
+	OPSPEC(    ASSIGN,        STD,        STD,        VAR) /* 30 ASSIGN_CONCAT                  */
+	OPSPEC(    ASSIGN,        STD,        STD,        VAR) /* 31 ASSIGN_BW_OR                   */
+	OPSPEC(    ASSIGN,        STD,        STD,        VAR) /* 32 ASSIGN_BW_AND                  */
+	OPSPEC(    ASSIGN,        STD,        STD,        VAR) /* 33 ASSIGN_BW_XOR                  */
+#else
+	OPSPEC(    UNUSED,        VAR,        STD,        VAR)
+	OPSPEC(    UNUSED,        VAR,        STD,        VAR)
+	OPSPEC(    UNUSED,        VAR,        STD,        VAR)
+	OPSPEC(    UNUSED,        VAR,        STD,        VAR)
+	OPSPEC(    UNUSED,        VAR,        STD,        VAR)
+	OPSPEC(    UNUSED,        VAR,        STD,        VAR)
+	OPSPEC(    UNUSED,        VAR,        STD,        VAR)
+	OPSPEC(    UNUSED,        VAR,        STD,        VAR)
+	OPSPEC(    UNUSED,        VAR,        STD,        VAR)
+	OPSPEC(    UNUSED,        VAR,        STD,        VAR)
+	OPSPEC(    UNUSED,        VAR,        STD,        VAR)
+#endif
+	OPSPEC(    UNUSED,        VAR,     UNUSED,        VAR) /* 34 PRE_INC                        */
+	OPSPEC(    UNUSED,        VAR,     UNUSED,        VAR) /* 35 PRE_DEC                        */
+	OPSPEC(    UNUSED,        VAR,     UNUSED,        TMP) /* 36 POST_INC                       */
+	OPSPEC(    UNUSED,        VAR,     UNUSED,        TMP) /* 37 POST_DEC                       */
+	OPSPEC(    UNUSED,        VAR,        STD,        VAR) /* 38 ASSIGN                         */
+	OPSPEC(    UNUSED,        VAR,        VAR,        VAR) /* 39 ASSIGN_REF                     */
+	OPSPEC(    UNUSED,        STD,     UNUSED,     UNUSED) /* 40 ECHO                           */
+	OPSPEC(    UNUSED,        STD,     UNUSED,        TMP) /* 41 PRINT                          */
+#ifdef ZEND_ENGINE_2
+	OPSPEC(    UNUSED,    JMPADDR,     UNUSED,     UNUSED) /* 42 JMP                            */
+	OPSPEC(    UNUSED,        STD,    JMPADDR,     UNUSED) /* 43 JMPZ                           */
+	OPSPEC(    UNUSED,        STD,    JMPADDR,     UNUSED) /* 44 JMPNZ                          */
+#else
+	OPSPEC(    UNUSED,     OPLINE,     UNUSED,     UNUSED)
+	OPSPEC(    UNUSED,        STD,     OPLINE,     UNUSED)
+	OPSPEC(    UNUSED,        STD,     OPLINE,     UNUSED)
+#endif
+	OPSPEC(    OPLINE,        STD,     OPLINE,     UNUSED) /* 45 JMPZNZ                         */
+#ifdef ZEND_ENGINE_2
+	OPSPEC(    UNUSED,        STD,    JMPADDR,        TMP) /* 46 JMPZ_EX                        */
+	OPSPEC(    UNUSED,        STD,    JMPADDR,        TMP) /* 47 JMPNZ_EX                       */
+#else
+	OPSPEC(    UNUSED,        STD,     OPLINE,        TMP)
+	OPSPEC(    UNUSED,        STD,     OPLINE,        TMP)
+#endif
+	OPSPEC(    UNUSED,        STD,        STD,        TMP) /* 48 CASE                           */
+	OPSPEC(       BIT,        STD,     UNUSED,     UNUSED) /* 49 SWITCH_FREE                    */
+	OPSPEC(    UNUSED,        BRK,        STD,     UNUSED) /* 50 BRK                            */
+	OPSPEC(    UNUSED,       CONT,        STD,     UNUSED) /* 51 CONT                           */
+	OPSPEC(    UNUSED,        STD,     UNUSED,        TMP) /* 52 BOOL                           */
+	OPSPEC(    UNUSED,     UNUSED,     UNUSED,        TMP) /* 53 INIT_STRING                    */
+	OPSPEC(    UNUSED,        STD,        STD,        TMP) /* 54 ADD_CHAR                       */
+	OPSPEC(    UNUSED,        STD,        STD,        TMP) /* 55 ADD_STRING                     */
+	OPSPEC(    UNUSED,        STD,        STD,        TMP) /* 56 ADD_VAR                        */
+	OPSPEC(    UNUSED,     UNUSED,     UNUSED,        TMP) /* 57 BEGIN_SILENCE                  */
+	OPSPEC(    UNUSED,        TMP,     UNUSED,     UNUSED) /* 58 END_SILENCE                    */
+	OPSPEC(INIT_FCALL,        STD,        STD,     UNUSED) /* 59 INIT_FCALL_BY_NAME             */
+#ifdef ZEND_ENGINE_2
+	OPSPEC(     FCALL,        STD,     OPLINE,        VAR) /* 60 DO_FCALL                       */
+	OPSPEC(     FCALL,        STD,     OPLINE,        VAR) /* 61 DO_FCALL_BY_NAME               */
+#else
+	OPSPEC(     FCALL,        STD,     UNUSED,        VAR)
+	OPSPEC(     FCALL,        STD,     UNUSED,        VAR)
+#endif
+	OPSPEC(    UNUSED,        STD,     UNUSED,     UNUSED) /* 62 RETURN                         */
+	OPSPEC(    UNUSED,        ARG,     UNUSED,        VAR) /* 63 RECV                           */
+	OPSPEC(    UNUSED,        ARG,        STD,        VAR) /* 64 RECV_INIT                      */
+	OPSPEC(      SEND,        STD,        ARG,     UNUSED) /* 65 SEND_VAL                       */
+	OPSPEC(      SEND,        VAR,        ARG,     UNUSED) /* 66 SEND_VAR                       */
+	OPSPEC(      SEND,        VAR,        ARG,     UNUSED) /* 67 SEND_REF                       */
+#ifdef ZEND_ENGINE_2
+	OPSPEC(    UNUSED,      CLASS,     UNUSED,        VAR) /* 68 NEW                            */
+#else
+	OPSPEC(    UNUSED,        STD,     UNUSED,        VAR)
+#endif
+#ifdef ZEND_ENGINE_2_3
+	OPSPEC(       STD,        STD,        STD,     UNUSED) /* 69 INIT_NS_FCALL_BY_NAME          */
+#else
+	OPSPEC(    UNUSED,        STD,     OPLINE,     UNUSED) /* 69 JMP_NO_CTOR                    */
+#endif
+	OPSPEC(    UNUSED,        TMP,     UNUSED,     UNUSED) /* 70 FREE                           */
+	OPSPEC(       BIT,        STD,        STD,        TMP) /* 71 INIT_ARRAY                     */
+	OPSPEC(       BIT,        STD,        STD,        TMP) /* 72 ADD_ARRAY_ELEMENT              */
+	OPSPEC(    UNUSED,        STD,    INCLUDE,        VAR) /* 73 INCLUDE_OR_EVAL                */
+#ifdef ZEND_ENGINE_2_1
+  /* php 5.1 and up */
+	OPSPEC(    UNUSED,        STD,      FETCH,     UNUSED) /* 74 UNSET_VAR                      */
+	OPSPEC(       STD,        STD,        STD,     UNUSED) /* 75 UNSET_DIM                      */
+	OPSPEC(       STD,        STD,        STD,     UNUSED) /* 76 UNSET_OBJ                      */
+	OPSPEC(       BIT,        STD,     OPLINE,        VAR) /* 77 FE_RESET                       */
+#else
+  /* <= php 5.0 */
+  /* though there is no ISSET_ISEMPTY in php 5.0 it's better to leave it here i guess */
+	OPSPEC(    UNUSED,        STD,     UNUSED,     UNUSED)
+	OPSPEC(    UNUSED,        VAR,        STD,     UNUSED)
+	OPSPEC(    UNUSED,        VAR,      ISSET,        TMP)
+	OPSPEC(       BIT,        STD,     UNUSED,        VAR)
+#endif
+	OPSPEC(        FE,        STD,     OPLINE,        TMP) /* 78 FE_FETCH                       */
+	OPSPEC(    UNUSED,        STD,     UNUSED,     UNUSED) /* 79 EXIT                           */
+	OPSPEC(    UNUSED,        STD,      FETCH,        VAR) /* 80 FETCH_R                        */
+	OPSPEC(     FETCH,        VAR,        STD,        VAR) /* 81 FETCH_DIM_R                    */
+	OPSPEC(    UNUSED,      VAR_2,        STD,        VAR) /* 82 FETCH_OBJ_R                    */
+	OPSPEC(    UNUSED,        STD,      FETCH,        VAR) /* 83 FETCH_W                        */
+	OPSPEC(    UNUSED,        VAR,        STD,        VAR) /* 84 FETCH_DIM_W                    */
+	OPSPEC(    UNUSED,      VAR_2,        STD,        VAR) /* 85 FETCH_OBJ_W                    */
+	OPSPEC(    UNUSED,        STD,      FETCH,        VAR) /* 86 FETCH_RW                       */
+	OPSPEC(    UNUSED,        VAR,        STD,        VAR) /* 87 FETCH_DIM_RW                   */
+	OPSPEC(    UNUSED,      VAR_2,        STD,        VAR) /* 88 FETCH_OBJ_RW                   */
+	OPSPEC(    UNUSED,        STD,      FETCH,        VAR) /* 89 FETCH_IS                       */
+	OPSPEC(    UNUSED,        VAR,        STD,        VAR) /* 90 FETCH_DIM_IS                   */
+	OPSPEC(    UNUSED,      VAR_2,        STD,        VAR) /* 91 FETCH_OBJ_IS                   */
+	OPSPEC(       ARG,        STD,      FETCH,        VAR) /* 92 FETCH_FUNC_ARG                 */
+	OPSPEC(       ARG,        VAR,        STD,        VAR) /* 93 FETCH_DIM_FUNC_ARG             */
+	OPSPEC(       ARG,      VAR_2,        STD,        VAR) /* 94 FETCH_OBJ_FUNC_ARG             */
+	OPSPEC(    UNUSED,        STD,      FETCH,        VAR) /* 95 FETCH_UNSET                    */
+	OPSPEC(    UNUSED,        VAR,        STD,        VAR) /* 96 FETCH_DIM_UNSET                */
+	OPSPEC(    UNUSED,      VAR_2,        STD,        VAR) /* 97 FETCH_OBJ_UNSET                */
+	OPSPEC(    UNUSED,        STD,        STD,        VAR) /* 98 FETCH_DIM_TMP_VAR              */
+#ifdef ZEND_ENGINE_2_3
+	OPSPEC(    UNUSED,      VAR_2,        STD,        TMP) /* 99 FETCH_CONSTANT                 */
+#elif defined(ZEND_ENGINE_2)
+	OPSPEC(    UNUSED,     UCLASS,        STD,        TMP) /* 99 FETCH_CONSTANT                 */
+#else
+	OPSPEC(    UNUSED,        STD,     UNUSED,        TMP) /* 99 FETCH_CONSTANT                 */
+#endif
+#ifdef ZEND_ENGINE_2_3
+	OPSPEC(       STD,    JMPADDR,        STD,     UNUSED) /* 100 GOTO                           */
+#else
+	OPSPEC(   DECLARE,        STD,        STD,     UNUSED) /* 100 DECLARE_FUNCTION_OR_CLASS      */
+#endif
+	OPSPEC(       STD,        STD,        STD,        STD) /* 101 EXT_STMT                       */
+	OPSPEC(       STD,        STD,        STD,        STD) /* 102 EXT_FCALL_BEGIN                */
+	OPSPEC(       STD,        STD,        STD,        STD) /* 103 EXT_FCALL_END                  */
+	OPSPEC(    UNUSED,     UNUSED,     UNUSED,     UNUSED) /* 104 EXT_NOP                        */
+	OPSPEC(    UNUSED,        STD,     UNUSED,     UNUSED) /* 105 TICKS                          */
+	OPSPEC(SEND_NOREF,        VAR,        ARG,     UNUSED) /* 106 SEND_VAR_NO_REF                */
+#ifdef ZEND_ENGINE_2
+	OPSPEC(    OPLINE,      CLASS,        STD,     UNUSED) /* 107 CATCH                          */
+	OPSPEC(    UNUSED,        STD,     OPLINE,     UNUSED) /* 108 THROW                          */
+	OPSPEC(    FCLASS,        STD,        STD,      CLASS) /* 109 FETCH_CLASS                    */
+	OPSPEC(    UNUSED,        STD,     UNUSED,        VAR) /* 110 CLONE                          */
+
+#ifdef ZEND_ENGINE_2_4
+	OPSPEC(    UNUSED,        STD,     UNUSED,     UNUSED) /* 111 RETURN_BY_REF                  */
+#else
+	OPSPEC(    UNUSED,        STD,     UNUSED,     UNUSED) /* 111 INIT_CTOR_CALL                 */
+#endif
+
+	OPSPEC(    UNUSED,        STD,        STD,        VAR) /* 112 INIT_METHOD_CALL               */
+#	ifdef ZEND_ENGINE_2_3
+	OPSPEC(    UNUSED,        STD,        STD,     UNUSED) /* 113 INIT_STATIC_METHOD_CALL        */
+#	else
+	OPSPEC(    UNUSED,     UCLASS,        STD,     UNUSED) /* 113 INIT_STATIC_METHOD_CALL        */
+#	endif
+	OPSPEC(     ISSET,        STD,      FETCH,        TMP) /* 114 ISSET_ISEMPTY_VAR              */
+	OPSPEC(     ISSET,        STD,        STD,        TMP) /* 115 ISSET_ISEMPTY_DIM_OBJ          */
+
+	OPSPEC(    UNUSED,      CLASS,        STD,     UNUSED) /* 116 IMPORT_FUNCTION                */
+	OPSPEC(    UNUSED,      CLASS,        STD,     UNUSED) /* 117 IMPORT_CLASS                   */
+	OPSPEC(    UNUSED,      CLASS,        STD,     UNUSED) /* 118 IMPORT_CONST                   */
+	OPSPEC(       STD,        STD,        STD,        STD) /* 119 OP_119                         */
+	OPSPEC(       STD,        STD,        STD,        STD) /* 120 OP_120                         */
+	OPSPEC(    UNUSED,        STD,        STD,        VAR) /* 121 ASSIGN_ADD_OBJ                 */
+	OPSPEC(    UNUSED,        STD,        STD,        VAR) /* 122 ASSIGN_SUB_OBJ                 */
+	OPSPEC(    UNUSED,        STD,        STD,        VAR) /* 123 ASSIGN_MUL_OBJ                 */
+	OPSPEC(    UNUSED,        STD,        STD,        VAR) /* 124 ASSIGN_DIV_OBJ                 */
+	OPSPEC(    UNUSED,        STD,        STD,        VAR) /* 125 ASSIGN_MOD_OBJ                 */
+	OPSPEC(    UNUSED,        STD,        STD,        VAR) /* 126 ASSIGN_SL_OBJ                  */
+	OPSPEC(    UNUSED,        STD,        STD,        VAR) /* 127 ASSIGN_SR_OBJ                  */
+	OPSPEC(    UNUSED,        STD,        STD,        VAR) /* 128 ASSIGN_CONCAT_OBJ              */
+	OPSPEC(    UNUSED,        STD,        STD,        VAR) /* 129 ASSIGN_BW_OR_OBJ               */
+	OPSPEC(    UNUSED,        STD,        STD,        VAR) /* 130 ASSIGN_BW_AND_OBJ              */
+	OPSPEC(    UNUSED,        STD,        STD,        VAR) /* 131 ASSIGN_BW_XOR_OBJ              */
+
+	OPSPEC(    UNUSED,        STD,        STD,        VAR) /* 132 PRE_INC_OBJ                    */
+	OPSPEC(    UNUSED,        STD,        STD,        VAR) /* 133 PRE_DEC_OBJ                    */
+	OPSPEC(    UNUSED,        STD,        STD,        TMP) /* 134 POST_INC_OBJ                   */
+	OPSPEC(    UNUSED,        STD,        STD,        TMP) /* 135 POST_DEC_OBJ                   */
+	OPSPEC(    UNUSED,        STD,        STD,        VAR) /* 136 ASSIGN_OBJ                     */
+	OPSPEC(    UNUSED,        STD,        STD,        STD) /* 137 OP_DATA                        */
+	OPSPEC(    UNUSED,        STD,      CLASS,        TMP) /* 138 INSTANCEOF                     */
+	OPSPEC(    UNUSED,        STD,        STD,      CLASS) /* 139 DECLARE_CLASS                  */
+	OPSPEC(     CLASS,        STD,        STD,      CLASS) /* 140 DECLARE_INHERITED_CLASS        */
+	OPSPEC(    UNUSED,        STD,        STD,     UNUSED) /* 141 DECLARE_FUNCTION               */
+	OPSPEC(    UNUSED,     UNUSED,     UNUSED,     UNUSED) /* 142 RAISE_ABSTRACT_ERROR           */
+#ifdef ZEND_ENGINE_2_3
+	OPSPEC(   DECLARE,        STD,        STD,     UNUSED) /* 143 DECLARE_CONST                  */
+#else
+	OPSPEC(    UNUSED,     UNUSED,     UNUSED,     UNUSED) /* 143 UNDEF-143                      */
+#endif
+#ifdef ZEND_ENGINE_2_3
+	OPSPEC(     IFACE,      CLASS,        STD,     UNUSED) /* 144 ADD_INTERFACE                  */
+#else
+	OPSPEC(     IFACE,      CLASS,      CLASS,     UNUSED) /* 144 ADD_INTERFACE                  */
+#endif
+#ifdef ZEND_ENGINE_2_3
+	OPSPEC(     CLASS,        STD,        STD,     OPLINE) /* 145 DECLARE_INHERITED_CLASS_DELAYED */
+#else
+	OPSPEC(    UNUSED,      CLASS,        STD,     UNUSED) /* 145 VERIFY_INSTANCEOF              */
+#endif
+	OPSPEC(    UNUSED,      CLASS,     UNUSED,     UNUSED) /* 146 VERIFY_ABSTRACT_CLASS          */
+	OPSPEC(    UNUSED,        STD,        STD,        VAR) /* 147 ASSIGN_DIM                     */
+	OPSPEC(     ISSET,        STD,        STD,        TMP) /* 148 ISSET_ISEMPTY_PROP_OBJ         */
+	OPSPEC(       STD,     UNUSED,     UNUSED,        STD) /* 149 HANDLE_EXCEPTION               */
+	OPSPEC(       STD,     UNUSED,     UNUSED,        STD) /* 150 USER_OPCODE                    */
+# ifdef ZEND_ENGINE_2_3
+	OPSPEC(    UNUSED,     UNUSED,     UNUSED,     UNUSED) /* 151 UNDEF                          */
+	OPSPEC(    UNUSED,        STD,    JMPADDR,        TMP) /* 152 JMP_SET                        */
+	OPSPEC(    UNUSED,        STD,        STD,        TMP) /* 153 DECLARE_LAMBDA_FUNCTION        */
+#  ifdef ZEND_ENGINE_2_4
+	OPSPEC(    UNUSED,     UNUSED,     UNUSED,     UNUSED) /* 154 ADD_TRAIT                      */
+	OPSPEC(    UNUSED,     UNUSED,     UNUSED,     UNUSED) /* 155 BIND_TRAITS                    */
+	OPSPEC(    UNUSED,     UNUSED,     UNUSED,     UNUSED) /* 156 SEPARATE                       */
+	OPSPEC(    UNUSED,     UNUSED,     UNUSED,     UNUSED) /* 157 QM_ASSIGN_VAR                  */
+	OPSPEC(    UNUSED,     UNUSED,     UNUSED,     UNUSED) /* 158 JMP_SET_VAR                    */
+#  endif
+# else
+	OPSPEC(    UNUSED,     UNUSED,     UNUSED,     UNUSED) /* 151 UNDEF                          */
+	OPSPEC(    UNUSED,     UNUSED,     UNUSED,     UNUSED) /* 152 UNDEF                          */
+	OPSPEC(    UNUSED,     UNUSED,     UNUSED,     UNUSED) /* 153 UNDEF                          */
+# endif
+#else
+	OPSPEC(    UNUSED,     UNUSED,     UNUSED,     UNUSED) /* 107 UNDEF                          */
+	OPSPEC(    UNUSED,     UNUSED,     UNUSED,     UNUSED) /* 108 UNDEF                          */
+	OPSPEC(    UNUSED,     UNUSED,     UNUSED,     UNUSED) /* 109 UNDEF                          */
+	OPSPEC(     FCALL,        STD,     OPLINE,        VAR) /* 61 DO_FCALL_BY_FUNC                */
+	OPSPEC(INIT_FCALL,        STD,        STD,     UNUSED) /* 111 INIT_FCALL_BY_FUNC             */
+	OPSPEC(    UNUSED,     UNUSED,     UNUSED,     UNUSED) /* 112 UNDEF                          */
+#endif
+};
Index: /tags/3.0.0-rc1/xcache/xc_malloc.c
===================================================================
--- /tags/3.0.0-rc1/xcache/xc_malloc.c	(revision 1135)
+++ /tags/3.0.0-rc1/xcache/xc_malloc.c	(revision 1135)
@@ -0,0 +1,246 @@
+#define XC_SHM_IMPL _xc_malloc_shm_t
+#define _xc_allocator_t _xc_allocator_malloc_t
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include "xc_shm.h"
+#include "xc_allocator.h"
+#ifndef TEST
+#include "xcache.h"
+#endif
+#include "util/xc_align.h"
+
+struct _xc_allocator_malloc_t {
+	const xc_allocator_vtable_t *vtable;
+	xc_shm_t *shm;
+	xc_memsize_t size;
+	xc_memsize_t avail;       /* total free */
+};
+
+/* {{{ _xc_malloc_shm_t */
+struct _xc_malloc_shm_t {
+	xc_shm_handlers_t *handlers;
+	xc_shmsize_t       size;
+	xc_shmsize_t       memoffset;
+#ifndef TEST
+	HashTable blocks;
+#endif
+};
+/* }}} */
+
+#ifndef TEST
+#	define CHECK(x, e) do { if ((x) == NULL) { zend_error(E_ERROR, "XCache: " e); goto err; } } while (0)
+#else
+#	define CHECK(x, e) do { if ((x) == NULL) { fprintf(stderr, "%s\n", "XCache: " e); goto err; } } while (0)
+#endif
+
+static void *xc_add_to_blocks(xc_allocator_t *allocator, void *p, size_t size) /* {{{ */
+{
+	if (p) {
+#ifdef TEST
+		allocator->avail -= size;
+#else
+		zend_hash_add(&allocator->shm->blocks, (void *) &p, sizeof(p), (void *) &size, sizeof(size), NULL);
+#endif
+	}
+	return p;
+}
+/* }}} */
+static void xc_del_from_blocks(xc_allocator_t *allocator, void *p) /* {{{ */
+{
+#ifdef TEST
+	/* TODO: allocator->avail += size; */
+#else
+	zend_hash_del(&allocator->shm->blocks, (void *) &p, sizeof(p));
+#endif
+}
+/* }}} */
+
+static XC_ALLOCATOR_MALLOC(xc_allocator_malloc_malloc) /* {{{ */
+{
+	return xc_add_to_blocks(allocator, malloc(size), size);
+}
+/* }}} */
+static XC_ALLOCATOR_FREE(xc_allocator_malloc_free) /* {{{ return block size freed */
+{
+	xc_del_from_blocks(allocator, (void *) p);
+	free((void *) p);
+	return 0;
+}
+/* }}} */
+static XC_ALLOCATOR_CALLOC(xc_allocator_malloc_calloc) /* {{{ */
+{
+	return xc_add_to_blocks(allocator, calloc(memb, size), size);
+}
+/* }}} */
+static XC_ALLOCATOR_REALLOC(xc_allocator_malloc_realloc) /* {{{ */
+{
+	return xc_add_to_blocks(allocator, realloc((void *) p, size), size);
+}
+/* }}} */
+
+static XC_ALLOCATOR_AVAIL(xc_allocator_malloc_avail) /* {{{ */
+{
+	return allocator->avail;
+}
+/* }}} */
+static XC_ALLOCATOR_SIZE(xc_allocator_malloc_size) /* {{{ */
+{
+	return allocator->size;
+}
+/* }}} */
+
+static XC_ALLOCATOR_FREEBLOCK_FIRST(xc_allocator_malloc_freeblock_first) /* {{{ */
+{
+	return (void *) -1;
+}
+/* }}} */
+static XC_ALLOCATOR_FREEBLOCK_NEXT(xc_allocator_malloc_freeblock_next) /* {{{ */
+{
+	return NULL;
+}
+/* }}} */
+static XC_ALLOCATOR_BLOCK_SIZE(xc_allocator_malloc_block_size) /* {{{ */
+{
+	return 0;
+}
+/* }}} */
+static XC_ALLOCATOR_BLOCK_OFFSET(xc_allocator_malloc_block_offset) /* {{{ */
+{
+	return 0;
+}
+/* }}} */
+
+static XC_ALLOCATOR_INIT(xc_allocator_malloc_init) /* {{{ */
+{
+#define MINSIZE (ALIGN(sizeof(xc_allocator_t)))
+	/* requires at least the header and 1 tail block */
+	if (size < MINSIZE) {
+		fprintf(stderr, "xc_allocator_malloc_init requires %lu bytes at least\n", (unsigned long) MINSIZE);
+		return NULL;
+	}
+	allocator->shm = shm;
+	allocator->size = size;
+	allocator->avail = size - MINSIZE;
+#undef MINSIZE
+
+	return allocator;
+}
+/* }}} */
+static XC_ALLOCATOR_DESTROY(xc_allocator_malloc_destroy) /* {{{ */
+{
+}
+/* }}} */
+
+static XC_SHM_CAN_READONLY(xc_malloc_can_readonly) /* {{{ */
+{
+	return 0;
+}
+/* }}} */
+static XC_SHM_IS_READWRITE(xc_malloc_is_readwrite) /* {{{ */
+{
+#ifndef TEST
+	HashPosition pos;
+	size_t *psize;
+	char **ptr;
+
+	zend_hash_internal_pointer_reset_ex(&shm->blocks, &pos);
+	while (zend_hash_get_current_data_ex(&shm->blocks, (void **) &psize, &pos) == SUCCESS) {
+		zend_hash_get_current_key_ex(&shm->blocks, (void *) &ptr, NULL, NULL, 0, &pos);
+		if ((char *) p >= *ptr && (char *) p < *ptr + *psize) {
+			return 1;
+		}
+		zend_hash_move_forward_ex(&shm->blocks, &pos);
+	}
+#endif
+
+	return 0;
+}
+/* }}} */
+static XC_SHM_IS_READONLY(xc_malloc_is_readonly) /* {{{ */
+{
+	return 0;
+}
+/* }}} */
+static XC_SHM_TO_READWRITE(xc_malloc_to_readwrite) /* {{{ */
+{
+	return p;
+}
+/* }}} */
+static XC_SHM_TO_READONLY(xc_malloc_to_readonly) /* {{{ */
+{
+	return p;
+}
+/* }}} */
+
+static XC_SHM_DESTROY(xc_malloc_destroy) /* {{{ */
+{
+#ifndef TEST
+	zend_hash_destroy(&shm->blocks);
+#endif
+	free(shm);
+	return;
+}
+/* }}} */
+static XC_SHM_INIT(xc_malloc_init) /* {{{ */
+{
+	xc_shm_t *shm;
+	CHECK(shm = calloc(1, sizeof(xc_shm_t)), "shm OOM");
+	shm->size = size;
+
+#ifndef TEST
+	zend_hash_init(&shm->blocks, 64, NULL, NULL, 1);
+#endif
+	return shm;
+err:
+	return NULL;
+}
+/* }}} */
+
+static XC_SHM_MEMINIT(xc_malloc_meminit) /* {{{ */
+{
+	void *mem;
+	if (shm->memoffset + size > shm->size) {
+#ifndef TEST
+		zend_error(E_ERROR, "XCache: internal error at %s#%d", __FILE__, __LINE__);
+#endif
+		return NULL;
+	}
+	shm->memoffset += size;
+	CHECK(mem = calloc(1, size), "mem OOM");
+	return mem;
+err:
+	return NULL;
+}
+/* }}} */
+static XC_SHM_MEMDESTROY(xc_malloc_memdestroy) /* {{{ */
+{
+	free(mem);
+}
+/* }}} */
+
+static xc_allocator_vtable_t xc_allocator_malloc_vtable = XC_ALLOCATOR_VTABLE(allocator_malloc);
+static xc_shm_handlers_t xc_shm_malloc_handlers = XC_SHM_HANDLERS(malloc);
+void xc_allocator_malloc_register() /* {{{ */
+{
+	if (xc_allocator_register("malloc", &xc_allocator_malloc_vtable) == 0) {
+#ifndef TEST
+		zend_error(E_ERROR, "XCache: failed to register malloc mem_scheme");
+#endif
+	}
+}
+/* }}} */
+
+#ifndef TEST
+void xc_shm_malloc_register() /* {{{ */
+{
+	if (xc_shm_scheme_register("malloc", &xc_shm_malloc_handlers) == 0) {
+		zend_error(E_ERROR, "XCache: failed to register malloc shm_scheme");
+	}
+}
+/* }}} */
+#endif
Index: /tags/3.0.0-rc1/xcache/xc_compatibility.c
===================================================================
--- /tags/3.0.0-rc1/xcache/xc_compatibility.c	(revision 991)
+++ /tags/3.0.0-rc1/xcache/xc_compatibility.c	(revision 991)
@@ -0,0 +1,45 @@
+#include "xc_compatibility.h"
+
+#ifndef ZEND_ENGINE_2_3
+#include "ext/standard/php_string.h"
+size_t xc_dirname(char *path, size_t len) /* {{{ */
+{
+#ifdef ZEND_ENGINE_2
+	return php_dirname(path, len);
+#else
+	php_dirname(path, len);
+	return strlen(path);
+#endif
+}
+/* }}} */
+
+long xc_atol(const char *str, int str_len) /* {{{ */
+{
+	long retval;
+
+	if (!str_len) {
+		str_len = strlen(str);
+	}
+
+	retval = strtol(str, NULL, 0);
+	if (str_len > 0) {
+		switch (str[str_len - 1]) {
+		case 'g':
+		case 'G':
+			retval *= 1024;
+			/* break intentionally missing */
+		case 'm':
+		case 'M':
+			retval *= 1024;
+			/* break intentionally missing */
+		case 'k':
+		case 'K':
+			retval *= 1024;
+			break;
+		}
+	}
+
+	return retval;
+}
+/* }}} */
+#endif
Index: /tags/3.0.0-rc1/xcache/xc_compatibility.h
===================================================================
--- /tags/3.0.0-rc1/xcache/xc_compatibility.h	(revision 1044)
+++ /tags/3.0.0-rc1/xcache/xc_compatibility.h	(revision 1044)
@@ -0,0 +1,242 @@
+#ifndef XC_COMPATIBILITY_H_54F26ED90198353558718191D5EE244C
+#define XC_COMPATIBILITY_H_54F26ED90198353558718191D5EE244C
+
+#if _MSC_VER > 1000
+#pragma once
+#endif /* _MSC_VER > 1000 */
+
+#include "php.h"
+
+/* Purpose: Privode stuffs for compatibility with different PHP version
+ */
+
+#if !defined(ZEND_ENGINE_2_4) && (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 4 || PHP_MAJOR_VERSION > 5)
+#	define ZEND_ENGINE_2_4
+#endif
+#if !defined(ZEND_ENGINE_2_3) && (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION == 3 || defined(ZEND_ENGINE_2_4))
+#	define ZEND_ENGINE_2_3
+#endif
+#if !defined(ZEND_ENGINE_2_2) && (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION == 2 || defined(ZEND_ENGINE_2_3))
+#	define ZEND_ENGINE_2_2
+#endif
+#if !defined(ZEND_ENGINE_2_1) && (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION == 1 || defined(ZEND_ENGINE_2_2))
+#	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
+#ifdef ZEND_ENGINE_2_4
+#	define ZEND_24(pre24, v24) v24
+#else
+#	define ZEND_24(pre24, v24) pre24
+#endif
+
+#ifdef do_alloca_with_limit
+#	define my_do_alloca(size, use_heap) do_alloca_with_limit(size, use_heap)
+#	define my_free_alloca(size, use_heap) free_alloca_with_limit(size, use_heap)
+#elif defined(ALLOCA_FLAG)
+#	define my_do_alloca(size, use_heap) do_alloca(size, use_heap)
+#	define my_free_alloca(size, use_heap) free_alloca(size, use_heap)
+#else
+#	define my_do_alloca(size, use_heap) do_alloca(size)
+#	define my_free_alloca(size, use_heap) free_alloca(size)
+#	define ALLOCA_FLAG(x)
+#endif
+#ifndef Z_ISREF
+#	define Z_ISREF(z) (z).is_ref
+#endif
+#ifndef Z_SET_ISREF
+#	define Z_SET_ISREF(z) (z).is_ref = 1
+#endif
+#ifndef Z_UNSET_ISREF
+#	define Z_UNSET_ISREF(z) (z).is_ref = 0
+#endif
+#ifndef Z_REFCOUNT
+#	define Z_REFCOUNT(z) (z).refcount
+#endif
+#ifndef Z_SET_REFCOUNT
+#	define Z_SET_REFCOUNT(z, rc) (z).refcount = rc
+#endif
+#ifndef IS_CONSTANT_TYPE_MASK
+#	define IS_CONSTANT_TYPE_MASK (~IS_CONSTANT_INDEX)
+#endif
+/* {{{ dirty fix for PHP 6 */
+#ifdef add_assoc_long_ex
+static inline void my_add_assoc_long_ex(zval *arg, char *key, uint key_len, long value)
+{
+	add_assoc_long_ex(arg, key, key_len, value);
+}
+#	undef add_assoc_long_ex
+#	define add_assoc_long_ex my_add_assoc_long_ex
+#endif
+#ifdef add_assoc_bool_ex
+static inline void my_add_assoc_bool_ex(zval *arg, char *key, uint key_len, zend_bool value)
+{
+	add_assoc_bool_ex(arg, key, key_len, value);
+}
+#	undef add_assoc_bool_ex
+#	define add_assoc_bool_ex my_add_assoc_bool_ex
+#endif
+#ifdef add_assoc_null_ex
+static inline void my_add_assoc_null_ex(zval *arg, char *key, uint key_len)
+{
+	add_assoc_null_ex(arg, key, key_len);
+}
+#	undef add_assoc_null_ex
+#	define add_assoc_null_ex my_add_assoc_null_ex
+#endif
+/* }}} */
+
+#ifdef ZEND_ENGINE_2_4
+#	define Z_OP(op) (op)
+#	define Z_OP_CONSTANT(op) (op).literal->constant
+#	define Z_OP_TYPE(op) op##_##type
+#	define Z_OP_TYPEOF_TYPE zend_uchar
+
+#	define Z_CLASS_INFO(className) (className).info.user
+#else
+#	define Z_OP(op) (op).u
+#	define Z_OP_CONSTANT(op) (op).u.constant
+#	define Z_OP_TYPE(op) (op).op_type
+#	define Z_OP_TYPEOF_TYPE int
+typedef znode znode_op;
+
+#	define Z_CLASS_INFO(className) (className)
+#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.arKey))
+#define BUCKET_KEY_S(b)    ZSTR_S(BUCKET_KEY(b))
+#define BUCKET_KEY_U(b)    ZSTR_U(BUCKET_KEY(b))
+#define BUCKET_KEY_TYPE(b) (UNISW(IS_STRING,  (b)->key.type))
+#ifdef IS_UNICODE
+#	define BUCKET_HEAD_SIZE(b) XtOffsetOf(Bucket, key.arKey)
+#else
+#	define BUCKET_HEAD_SIZE(b) XtOffsetOf(Bucket, arKey)
+#endif
+
+#ifdef ZEND_ENGINE_2_4
+#	define BUCKET_SIZE(b) (sizeof(Bucket) + BUCKET_KEY_SIZE(b))
+#else
+#	define BUCKET_SIZE(b) (BUCKET_HEAD_SIZE(b) + BUCKET_KEY_SIZE(b))
+#endif
+
+#ifndef IS_UNICODE
+typedef char *zstr;
+typedef const char *const_zstr;
+#ifdef ZEND_ENGINE_2_4
+typedef const char *const24_zstr;
+typedef const char *const24_str;
+#else
+typedef char *const24_zstr;
+typedef char *const24_str;
+#endif
+
+#	define ZSTR_S(s)     (s)
+#	define ZSTR_U(s)     (s)
+#	define ZSTR_V(s)     (s)
+#	define ZSTR_PS(s)    (s)
+#	define ZSTR_PU(s)    (s)
+#	define ZSTR_PV(s)    (s)
+#else
+typedef const zstr const_zstr;
+#	define ZSTR_S(zs)    ((zs).s)
+#	define ZSTR_U(zs)    ((zs).u)
+#	define ZSTR_V(zs)    ((zs).v)
+#	define ZSTR_PS(pzs)  ((pzs)->s)
+#	define ZSTR_PU(pzs)  ((pzs)->u)
+#	define ZSTR_PV(pzs)  ((pzs)->v)
+#endif
+
+#ifndef ZSTR
+#	define ZSTR(s)      (s)
+#endif
+
+#ifndef Z_UNIVAL
+#	define Z_UNIVAL(zval) (zval).value.str.val
+#	define Z_UNILEN(zval) (zval).value.str.len
+#endif
+
+/* {{{ u hash wrapper */
+#ifndef IS_UNICODE
+#	define zend_u_hash_add(ht, type, arKey, nKeyLength, pData, nDataSize, pDest) \
+ 	   zend_hash_add(ht, ZEND_24((char *), NOTHING) arKey, nKeyLength, pData, nDataSize, pDest)
+
+#	define zend_u_hash_quick_add(ht, type, arKey, nKeyLength, h, pData, nDataSize, pDest) \
+ 	   zend_hash_quick_add(ht, ZEND_24((char *), NOTHING) arKey, nKeyLength, h, pData, nDataSize, pDest)
+
+#	define zend_u_hash_update(ht, type, arKey, nKeyLength, pData, nDataSize, pDest) \
+ 	   zend_hash_update(ht, ZEND_24((char *), NOTHING) arKey, nKeyLength, pData, nDataSize, pDest)
+
+#	define zend_u_hash_quick_update(ht, type, arKey, nKeyLength, h, pData, nDataSize, pDest) \
+ 	   zend_hash_quick_update(ht, ZEND_24((char *), NOTHING) arKey, nKeyLength, h, pData, nDataSize, pDest)
+
+#	define zend_u_hash_find(ht, type, arKey, nKeyLength, pData) \
+ 	   zend_hash_find(ht, ZEND_24((char *), NOTHING) arKey, nKeyLength, pData)
+
+#	define zend_u_hash_quick_find(ht, type, arKey, nKeyLength, h, pData) \
+ 	   zend_hash_quick_find(ht, ZEND_24((char *), NOTHING) arKey, nKeyLength, h, pData)
+
+#	define zend_u_hash_exists(ht, type, arKey, nKeyLength) \
+ 	   zend_hash_exists(ht, ZEND_24((char *), NOTHING) arKey, nKeyLength)
+
+#	define add_u_assoc_zval_ex(arg, type, key, key_len, value) \
+		add_assoc_zval_ex(arg, key, key_len, value)
+
+#	define zend_u_is_auto_global(type, name, name_len) \
+		zend_is_auto_global(name, name_len)
+#endif
+/* }}} */
+
+/* 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) \
+			))
+
+#ifndef ZEND_ENGINE_2_3
+size_t xc_dirname(char *path, size_t len);
+#define zend_dirname xc_dirname
+long xc_atol(const char *str, int len);
+#define zend_atol xc_atol
+#endif
+
+#ifndef ZEND_MOD_END
+#	define ZEND_MOD_END {NULL, NULL, NULL, 0}
+#endif
+
+#ifndef PHP_FE_END
+#	ifdef ZEND_ENGINE_2
+#		define PHP_FE_END {NULL, NULL, NULL, 0, 0}
+#	else
+#		define PHP_FE_END {NULL, NULL, NULL}
+#	endif
+#endif
+
+#endif /* XC_COMPATIBILITY_H_54F26ED90198353558718191D5EE244C */
Index: /tags/3.0.0-rc1/xcache/xc_allocator.c
===================================================================
--- /tags/3.0.0-rc1/xcache/xc_allocator.c	(revision 1135)
+++ /tags/3.0.0-rc1/xcache/xc_allocator.c	(revision 1135)
@@ -0,0 +1,112 @@
+#include "xc_allocator.h"
+#include <string.h>
+#include <stdio.h>
+
+typedef struct {
+	const char *name;
+	const xc_allocator_vtable_t *allocator_vtable;
+} xc_allocator_info_t;
+static xc_allocator_info_t xc_allocator_infos[10];
+
+int xc_allocator_register(const char *name, const xc_allocator_vtable_t *allocator_vtable) /* {{{ */
+{
+	size_t i;
+	for (i = 0; i < sizeof(xc_allocator_infos) / sizeof(xc_allocator_infos[0]); i ++) {
+		if (!xc_allocator_infos[i].name) {
+			xc_allocator_infos[i].name = name;
+			xc_allocator_infos[i].allocator_vtable = allocator_vtable;
+			return 1;
+		}
+	}
+	return 0;
+}
+/* }}} */
+const xc_allocator_vtable_t *xc_allocator_find(const char *name) /* {{{ */
+{
+	size_t i;
+	for (i = 0; i < sizeof(xc_allocator_infos) / sizeof(xc_allocator_infos[0]) && xc_allocator_infos[i].name; i ++) {
+		if (strcmp(xc_allocator_infos[i].name, name) == 0) {
+			return xc_allocator_infos[i].allocator_vtable;
+		}
+	}
+	return NULL;
+}
+/* }}} */
+void xc_allocator_init() /* {{{ */
+{
+	extern void xc_allocator_bestfit_register();
+#ifdef HAVE_XCACHE_TEST
+	extern void xc_allocator_malloc_register();
+#endif
+
+	memset(xc_allocator_infos, 0, sizeof(xc_allocator_infos));
+	xc_allocator_bestfit_register();
+#ifdef HAVE_XCACHE_TEST
+	xc_allocator_malloc_register();
+#endif
+}
+/* }}} */
+#ifdef TEST
+/* {{{ testing */
+#undef CHECK
+#define CHECK(a, msg) do { \
+	if (!(a)) { \
+		fprintf(stderr, "%s\n", msg); return -1; \
+	} \
+} while (0)
+
+#include <time.h>
+
+int testAllocator(const xc_allocator_vtable_t *allocator_vtable)
+{
+	int count = 0;
+	void *p;
+	xc_allocator_t *allocator;
+	void *memory;
+	void **ptrs;
+	int size, i;
+
+#if 0
+	fprintf(stderr, "%s", "Input test size: ");
+	scanf("%d", &size);
+#else
+	size = 1024;
+#endif
+	CHECK(memory = malloc(size), "OOM");
+	CHECK(ptrs   = malloc(size * sizeof(void *)), "OOM");
+	allocator = (xc_allocator_t *) memory;
+	allocator->vtable = allocator_vtable;
+	CHECK(allocator = allocator->vtable->init(NULL, allocator, size), "Failed init memory allocator");
+
+	while ((p = allocator->vtable->malloc(allocator, 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);
+		allocator->vtable->free(allocator, ptrs[i]);
+		ptrs[i] = ptrs[count - 1];
+		count --;
+	}
+
+	free(ptrs);
+	free(memory);
+	return 0;
+}
+/* }}} */
+int main() /* {{{ */
+{
+	int i;
+
+	xc_allocator_init();
+
+	for (i = 0; i < sizeof(xc_allocator_infos) / sizeof(xc_allocator_infos[0]) && xc_allocator_infos[i].name; i ++) {
+		fprintf(stderr, "testing %s...\n", xc_allocator_infos[i].name);
+		testAllocator(xc_allocator_infos[i].allocator_vtable);
+	}
+	return 0;
+}
+/* }}} */
+#endif
Index: /tags/3.0.0-rc1/xcache/xc_allocator.h
===================================================================
--- /tags/3.0.0-rc1/xcache/xc_allocator.h	(revision 1135)
+++ /tags/3.0.0-rc1/xcache/xc_allocator.h	(revision 1135)
@@ -0,0 +1,73 @@
+#ifndef XC_ALLOCATOR_H_155E773CA8AFC18F3CCCDCF0831EE41D
+#define XC_ALLOCATOR_H_155E773CA8AFC18F3CCCDCF0831EE41D
+
+#if _MSC_VER > 1000
+#pragma once
+#endif /* _MSC_VER > 1000 */
+
+#include "xc_shm.h"
+
+typedef struct _xc_allocator_vtable_t xc_allocator_vtable_t;
+
+#ifndef _xc_allocator_t
+struct _xc_allocator_t {
+	const xc_allocator_vtable_t *vtable;
+	xc_shm_t *shm;
+};
+#endif
+
+typedef struct _xc_allocator_t xc_allocator_t;
+typedef struct _xc_allocator_block_t xc_allocator_block_t;
+typedef xc_shmsize_t xc_memsize_t;
+
+/* allocator */
+#define XC_ALLOCATOR_MALLOC(func)          void *func(xc_allocator_t *allocator, xc_memsize_t size)
+#define XC_ALLOCATOR_FREE(func)            xc_memsize_t  func(xc_allocator_t *allocator, const void *p)
+#define XC_ALLOCATOR_CALLOC(func)          void *func(xc_allocator_t *allocator, xc_memsize_t memb, xc_memsize_t size)
+#define XC_ALLOCATOR_REALLOC(func)         void *func(xc_allocator_t *allocator, const void *p, xc_memsize_t size)
+#define XC_ALLOCATOR_AVAIL(func)           xc_memsize_t      func(const xc_allocator_t *allocator)
+#define XC_ALLOCATOR_SIZE(func)            xc_memsize_t      func(const xc_allocator_t *allocator)
+#define XC_ALLOCATOR_FREEBLOCK_FIRST(func) const xc_allocator_block_t *func(const xc_allocator_t *allocator)
+#define XC_ALLOCATOR_FREEBLOCK_NEXT(func)  const xc_allocator_block_t *func(const xc_allocator_block_t *block)
+#define XC_ALLOCATOR_BLOCK_SIZE(func)      xc_memsize_t      func(const xc_allocator_block_t *block)
+#define XC_ALLOCATOR_BLOCK_OFFSET(func)    xc_memsize_t      func(const xc_allocator_t *allocator, const xc_allocator_block_t *block)
+
+#define XC_ALLOCATOR_INIT(func)            xc_allocator_t *func(xc_shm_t *shm, xc_allocator_t *allocator, xc_memsize_t size)
+#define XC_ALLOCATOR_DESTROY(func)         void func(xc_allocator_t *allocator)
+
+#define XC_ALLOCATOR_VTABLE(name)   {  \
+	xc_##name##_malloc             \
+	, xc_##name##_free             \
+	, xc_##name##_calloc           \
+	, xc_##name##_realloc          \
+	, xc_##name##_avail            \
+	, xc_##name##_size             \
+	, xc_##name##_freeblock_first  \
+	, xc_##name##_freeblock_next   \
+	, xc_##name##_block_size       \
+	, xc_##name##_block_offset     \
+\
+	, xc_##name##_init             \
+	, xc_##name##_destroy          \
+}
+
+struct _xc_allocator_vtable_t {
+	XC_ALLOCATOR_MALLOC((*malloc));
+	XC_ALLOCATOR_FREE((*free));
+	XC_ALLOCATOR_CALLOC((*calloc));
+	XC_ALLOCATOR_REALLOC((*realloc));
+	XC_ALLOCATOR_AVAIL((*avail));
+	XC_ALLOCATOR_SIZE((*size));
+	XC_ALLOCATOR_FREEBLOCK_FIRST((*freeblock_first));
+	XC_ALLOCATOR_FREEBLOCK_NEXT((*freeblock_next));
+	XC_ALLOCATOR_BLOCK_SIZE((*block_size));
+	XC_ALLOCATOR_BLOCK_OFFSET((*block_offset));
+
+	XC_ALLOCATOR_INIT((*init));
+	XC_ALLOCATOR_DESTROY((*destroy));
+};
+
+int xc_allocator_register(const char *name, const xc_allocator_vtable_t *allocator_vtable);
+const xc_allocator_vtable_t *xc_allocator_find(const char *name);
+
+#endif /* XC_ALLOCATOR_H_155E773CA8AFC18F3CCCDCF0831EE41D */
Index: /tags/3.0.0-rc1/xcache/xc_const_string_opcodes_php5.0.h
===================================================================
--- /tags/3.0.0-rc1/xcache/xc_const_string_opcodes_php5.0.h	(revision 1095)
+++ /tags/3.0.0-rc1/xcache/xc_const_string_opcodes_php5.0.h	(revision 1095)
@@ -0,0 +1,153 @@
+/* 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 */	"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/3.0.0-rc1/xcache/xc_lock.c
===================================================================
--- /tags/3.0.0-rc1/xcache/xc_lock.c	(revision 1027)
+++ /tags/3.0.0-rc1/xcache/xc_lock.c	(revision 1027)
@@ -0,0 +1,165 @@
+#include "xc_lock.h"
+#include "xcache.h"
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#ifndef ZEND_WIN32
+typedef int HANDLE;
+#	ifndef INVALID_HANDLE_VALUE
+#		define INVALID_HANDLE_VALUE -1
+#	endif
+#else
+#	define close(h) CloseHandle(h)
+#	define open(filename, mode, permission) CreateFile(filename, \
+		GENERIC_READ | GENERIC_WRITE, \
+		FILE_SHARE_READ | FILE_SHARE_WRITE, \
+		NULL, \
+		OPEN_ALWAYS, \
+		FILE_ATTRIBUTE_NORMAL, \
+		NULL)
+#endif
+#include "xc_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>
+#	undef errno
+#	define errno GetLastError()
+#	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 = malloc(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 = 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 {
+		zend_error(E_ERROR, "xc_fcntl_create: open(%s, O_RDWR|O_CREAT, 0666) failed:", pathname);
+		lck = NULL;
+	}
+
+	if (myname) {
+		free(myname);
+	}
+
+	return lck;
+}
+/* }}} */
+void xc_fcntl_destroy(xc_lock_t *lck) /* {{{ */
+{   
+	close(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) {
+		zend_error(E_ERROR, "xc_fcntl_lock failed errno:%d", errno);
+	}
+}
+/* }}} */
+void xc_fcntl_rdlock(xc_lock_t *lck) /* {{{ */
+{   
+	if (dolock(lck, LCK_RD) < 0) {
+		zend_error(E_ERROR, "xc_fcntl_lock failed errno:%d", errno);
+	}
+}
+/* }}} */
+void xc_fcntl_unlock(xc_lock_t *lck) /* {{{ */
+{   
+	if (dolock(lck, LCK_UN) < 0) {
+		zend_error(E_ERROR, "xc_fcntl_unlock failed errno:%d", errno);
+	}
+}
+/* }}} */
Index: /tags/3.0.0-rc1/xcache/xc_const_string_opcodes_php5.1.h
===================================================================
--- /tags/3.0.0-rc1/xcache/xc_const_string_opcodes_php5.1.h	(revision 1095)
+++ /tags/3.0.0-rc1/xcache/xc_const_string_opcodes_php5.1.h	(revision 1095)
@@ -0,0 +1,154 @@
+/* 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"
+};
Index: /tags/3.0.0-rc1/xcache/xc_const_string_opcodes_php5.3.h
===================================================================
--- /tags/3.0.0-rc1/xcache/xc_const_string_opcodes_php5.3.h	(revision 1095)
+++ /tags/3.0.0-rc1/xcache/xc_const_string_opcodes_php5.3.h	(revision 1095)
@@ -0,0 +1,157 @@
+/* size = 154 */
+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 */	"INIT_NS_FCALL_BY_NAME",
+/* 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 */	"GOTO",
+/* 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 */	"DECLARE_CONST",
+/* 144 */	"ADD_INTERFACE",
+/* 145 */	"DECLARE_INHERITED_CLASS_DELAYED",
+/* 146 */	"VERIFY_ABSTRACT_CLASS",
+/* 147 */	"ASSIGN_DIM",
+/* 148 */	"ISSET_ISEMPTY_PROP_OBJ",
+/* 149 */	"HANDLE_EXCEPTION",
+/* 150 */	"USER_OPCODE",
+/* 151 */	"UNDEF",
+/* 152 */	"JMP_SET",
+/* 153 */	"DECLARE_LAMBDA_FUNCTION"
+};
Index: /tags/3.0.0-rc1/xcache/xc_const_string_opcodes_php5.4.h
===================================================================
--- /tags/3.0.0-rc1/xcache/xc_const_string_opcodes_php5.4.h	(revision 982)
+++ /tags/3.0.0-rc1/xcache/xc_const_string_opcodes_php5.4.h	(revision 982)
@@ -0,0 +1,162 @@
+/* size = 159 */
+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 */	"INIT_NS_FCALL_BY_NAME",
+/* 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 */	"GOTO",
+/* 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 */	"RETURN_BY_REF",
+/* 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 */	"DECLARE_CONST",
+/* 144 */	"ADD_INTERFACE",
+/* 145 */	"DECLARE_INHERITED_CLASS_DELAYED",
+/* 146 */	"VERIFY_ABSTRACT_CLASS",
+/* 147 */	"ASSIGN_DIM",
+/* 148 */	"ISSET_ISEMPTY_PROP_OBJ",
+/* 149 */	"HANDLE_EXCEPTION",
+/* 150 */	"USER_OPCODE",
+/* 151 */	"UNDEF",
+/* 152 */	"JMP_SET",
+/* 153 */	"DECLARE_LAMBDA_FUNCTION",
+/* 154 */	"ADD_TRAIT",
+/* 155 */	"BIND_TRAITS",
+/* 156 */	"SEPARATE",
+/* 157 */	"QM_ASSIGN_VAR",
+/* 158 */	"JMP_SET_VAR"
+};
Index: /tags/3.0.0-rc1/xcache/xc_lock.h
===================================================================
--- /tags/3.0.0-rc1/xcache/xc_lock.h	(revision 1044)
+++ /tags/3.0.0-rc1/xcache/xc_lock.h	(revision 1044)
@@ -0,0 +1,20 @@
+#ifndef XC_LOCK_H_1913F3DED68715D7CDA5A055E79FE0FF
+#define XC_LOCK_H_1913F3DED68715D7CDA5A055E79FE0FF
+
+#if _MSC_VER > 1000
+#pragma once
+#endif /* _MSC_VER > 1000 */
+
+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)
+
+#endif /* XC_LOCK_H_1913F3DED68715D7CDA5A055E79FE0FF */
Index: /tags/3.0.0-rc1/xcache/xc_sandbox.c
===================================================================
--- /tags/3.0.0-rc1/xcache/xc_sandbox.c	(revision 992)
+++ /tags/3.0.0-rc1/xcache/xc_sandbox.c	(revision 992)
@@ -0,0 +1,455 @@
+
+#include "xcache.h"
+#include "xc_sandbox.h"
+#include "xc_utils.h"
+#include "xcache_globals.h"
+
+/* utilities used by sandbox */
+static void (*old_zend_error_cb)(int type, const char *error_filename, const uint error_lineno, const char *format, va_list args) = NULL;
+static void call_old_zend_error_cb(int type, const char *error_filename, const uint error_lineno, const char *format, ...) /* {{{ */
+{
+	va_list args;
+	va_start(args, format);
+	old_zend_error_cb(type, error_filename, error_lineno, format, args);
+}
+/* }}} */
+#ifdef ZEND_ENGINE_2_1
+static zend_bool xc_auto_global_callback(ZEND_24(NOTHING, const) char *name, uint name_len TSRMLS_DC) /* {{{ */
+{
+	return 0;
+}
+/* }}} */
+static int xc_auto_global_arm(zend_auto_global *auto_global TSRMLS_DC) /* {{{ */
+{
+	if (auto_global->auto_global_callback) {
+		auto_global->armed = 1;
+		auto_global->auto_global_callback = xc_auto_global_callback;
+	}
+	else {
+		auto_global->armed = 0;
+	}
+	return ZEND_HASH_APPLY_KEEP;
+}
+/* }}} */
+#endif
+
+#ifdef HAVE_XCACHE_CONSTANT
+static void xc_free_zend_constant(zend_constant *c) /* {{{ */
+{
+	if (!(c->flags & CONST_PERSISTENT)) {
+		zval_dtor(&c->value);
+	}
+	free(ZSTR_V(c->name));
+}
+/* }}} */
+#endif
+
+typedef struct { /* sandbox {{{ */
+	ZEND_24(NOTHING, const) char *filename;
+
+	HashTable orig_included_files;
+	HashTable *tmp_included_files;
+
+#ifdef HAVE_XCACHE_CONSTANT
+	HashTable *orig_zend_constants;
+	HashTable tmp_zend_constants;
+#endif
+	HashTable *orig_function_table;
+	HashTable *orig_class_table;
+	HashTable *orig_auto_globals;
+	HashTable tmp_function_table;
+	HashTable tmp_class_table;
+	HashTable tmp_auto_globals;
+#ifdef HAVE_XCACHE_CONSTANT
+	Bucket    *tmp_internal_constant_tail;
+#endif
+	Bucket    *tmp_internal_function_tail;
+	Bucket    *tmp_internal_class_tail;
+
+#ifdef XCACHE_ERROR_CACHING
+	int orig_user_error_handler_error_reporting;
+	zend_uint compilererror_cnt;
+	zend_uint compilererror_size;
+	xc_compilererror_t *compilererrors;
+#endif
+
+#ifdef ZEND_COMPILE_IGNORE_INTERNAL_CLASSES
+	zend_uint orig_compiler_options;
+#endif
+} xc_sandbox_t;
+
+#undef TG
+#undef OG
+#define TG(x) (sandbox->tmp_##x)
+#define OG(x) (sandbox->orig_##x)
+/* }}} */
+#ifdef XCACHE_ERROR_CACHING
+static void xc_sandbox_error_cb(int type, const char *error_filename, const uint error_lineno, const char *format, va_list args) /* {{{ */
+{
+	xc_compilererror_t *compilererror;
+	xc_sandbox_t *sandbox;
+	TSRMLS_FETCH();
+
+	sandbox = (xc_sandbox_t *) XG(sandbox);
+	if (!sandbox) {
+		old_zend_error_cb(type, error_filename, error_lineno, format, args);
+		return;
+	}
+
+	switch (type) {
+#ifdef E_STRICT
+	case E_STRICT:
+#endif
+#ifdef E_DEPRECATED
+	case E_DEPRECATED:
+#endif
+		if (sandbox->compilererror_cnt <= sandbox->compilererror_size) {
+			if (sandbox->compilererror_size) {
+				sandbox->compilererror_size += 16;
+				sandbox->compilererrors = erealloc(sandbox->compilererrors, sandbox->compilererror_size * sizeof(sandbox->compilererrors));
+			}
+			else {
+				sandbox->compilererror_size = 16;
+				sandbox->compilererrors = emalloc(sandbox->compilererror_size * sizeof(sandbox->compilererrors));
+			}
+		}
+		compilererror = &sandbox->compilererrors[sandbox->compilererror_cnt++];
+		compilererror->type = type;
+		compilererror->lineno = error_lineno;
+		compilererror->error_len = vspprintf(&compilererror->error, 0, format, args);
+		break;
+
+	default: {
+		/* give up, and user handler is not supported in this case */
+		zend_uint i;
+		zend_uint old_lineno = CG(zend_lineno);
+
+		for (i = 0; i < sandbox->compilererror_cnt; i ++) {
+			compilererror = &sandbox->compilererrors[i];
+			CG(zend_lineno) = compilererror->lineno;
+			call_old_zend_error_cb(compilererror->type, error_filename, error_lineno, "%s", compilererror->error);
+			efree(compilererror->error);
+		}
+		if (sandbox->compilererrors) {
+			efree(sandbox->compilererrors);
+			sandbox->compilererrors = NULL;
+		}
+		sandbox->compilererror_cnt  = 0;
+		sandbox->compilererror_size = 0;
+
+		CG(zend_lineno) = old_lineno;
+		old_zend_error_cb(type, error_filename, error_lineno, format, args);
+		break;
+	}
+	}
+}
+/* }}} */
+#endif
+
+static xc_sandbox_t *xc_sandbox_init(xc_sandbox_t *sandbox, ZEND_24(NOTHING, const) char *filename TSRMLS_DC) /* {{{ */
+{
+	HashTable *h;
+
+	assert(sandbox);
+	memset(sandbox, 0, sizeof(sandbox[0]));
+
+	memcpy(&OG(included_files), &EG(included_files), sizeof(EG(included_files)));
+
+#ifdef HAVE_XCACHE_CONSTANT
+	OG(zend_constants) = EG(zend_constants);
+	EG(zend_constants) = &TG(zend_constants);
+#endif
+
+	OG(function_table) = CG(function_table);
+	CG(function_table) = &TG(function_table);
+
+	OG(class_table) = CG(class_table);
+	CG(class_table) = &TG(class_table);
+	EG(class_table) = CG(class_table);
+
+#ifdef ZEND_ENGINE_2_1
+	OG(auto_globals) = CG(auto_globals);
+	CG(auto_globals) = &TG(auto_globals);
+#endif
+
+	TG(included_files) = &EG(included_files);
+
+	zend_hash_init_ex(TG(included_files), 5, NULL, NULL, 0, 1);
+#ifdef HAVE_XCACHE_CONSTANT
+	h = OG(zend_constants);
+	zend_hash_init_ex(&TG(zend_constants),  20, NULL, (dtor_func_t) xc_free_zend_constant, h->persistent, h->bApplyProtection);
+	xc_copy_internal_zend_constants(&TG(zend_constants), &XG(internal_constant_table));
+	TG(internal_constant_tail) = TG(zend_constants).pListTail;
+#endif
+	h = OG(function_table);
+	zend_hash_init_ex(&TG(function_table), 128, NULL, ZEND_FUNCTION_DTOR, h->persistent, h->bApplyProtection);
+	{
+		zend_function tmp_func;
+		zend_hash_copy(&TG(function_table), &XG(internal_function_table), NULL, (void *) &tmp_func, sizeof(tmp_func));
+	}
+	TG(internal_function_tail) = TG(function_table).pListTail;
+
+	h = OG(class_table);
+	zend_hash_init_ex(&TG(class_table),     16, NULL, ZEND_CLASS_DTOR, h->persistent, h->bApplyProtection);
+#if 0 && TODO
+	{
+		xc_cest_t tmp_cest;
+		zend_hash_copy(&TG(class_table), &XG(internal_class_table), NULL, (void *) &tmp_cest, sizeof(tmp_cest));
+	}
+#endif
+	TG(internal_class_tail) = TG(class_table).pListTail;
+
+#ifdef ZEND_ENGINE_2_1
+	/* shallow copy, don't destruct */
+	h = OG(auto_globals);
+	zend_hash_init_ex(&TG(auto_globals),     8, NULL,           NULL, h->persistent, h->bApplyProtection);
+	{
+		zend_auto_global tmp_autoglobal;
+
+		zend_hash_copy(&TG(auto_globals), OG(auto_globals), NULL, (void *) &tmp_autoglobal, sizeof(tmp_autoglobal));
+		zend_hash_apply(&TG(auto_globals), (apply_func_t) xc_auto_global_arm TSRMLS_CC);
+	}
+#endif
+
+	sandbox->filename = filename;
+
+#ifdef XCACHE_ERROR_CACHING
+	sandbox->orig_user_error_handler_error_reporting = EG(user_error_handler_error_reporting);
+	EG(user_error_handler_error_reporting) = 0;
+
+	sandbox->compilererror_cnt  = 0;
+	sandbox->compilererror_size = 0;
+#endif
+
+#ifdef ZEND_COMPILE_IGNORE_INTERNAL_CLASSES
+	sandbox->orig_compiler_options = CG(compiler_options);
+	/* Using ZEND_COMPILE_IGNORE_INTERNAL_CLASSES for ZEND_FETCH_CLASS_RT_NS_CHECK
+	 */
+	CG(compiler_options) |= ZEND_COMPILE_IGNORE_INTERNAL_CLASSES | ZEND_COMPILE_NO_CONSTANT_SUBSTITUTION | ZEND_COMPILE_DELAYED_BINDING;
+#endif
+
+	XG(sandbox) = (void *) sandbox;
+	return sandbox;
+}
+/* }}} */
+
+#ifndef ZEND_COMPILE_DELAYED_BINDING
+static void xc_early_binding_cb(zend_op *opline, int oplineno, void *data TSRMLS_DC) /* {{{ */
+{
+	xc_sandbox_t *sandbox = (xc_sandbox_t *) data;
+	xc_do_early_binding(CG(active_op_array), OG(class_table), oplineno TSRMLS_CC);
+}
+/* }}} */
+#endif
+static void xc_sandbox_install(xc_sandbox_t *sandbox TSRMLS_DC) /* {{{ */
+{
+	zend_uint i;
+	Bucket *b;
+
+#ifdef HAVE_XCACHE_CONSTANT
+	for (b = TG(zend_constants).pListHead; b != NULL && b != TG(internal_constant_tail); b = b->pListNext) {
+		zend_constant *c = (zend_constant*) b->pData;
+		xc_free_zend_constant(c);
+	}
+
+	b = TG(internal_constant_tail) ? TG(internal_constant_tail)->pListNext : TG(zend_constants).pListHead;
+	/* install constants */
+	while (b != NULL) {
+		zend_constant *c = (zend_constant*) b->pData;
+		xc_install_constant(sandbox->filename, c,
+				BUCKET_KEY_TYPE(b), ZSTR(BUCKET_KEY_S(b)), b->nKeyLength, b->h TSRMLS_CC);
+		b = b->pListNext;
+	}
+#endif
+
+	b = TG(internal_function_tail) ? TG(internal_function_tail)->pListNext : 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), ZSTR(BUCKET_KEY_S(b)), b->nKeyLength, b->h TSRMLS_CC);
+		b = b->pListNext;
+	}
+
+	b = TG(internal_class_tail) ? TG(internal_class_tail)->pListNext : TG(class_table).pListHead;
+	/* install class */
+	while (b != NULL) {
+		xc_install_class(sandbox->filename, (xc_cest_t*) b->pData, -1,
+				BUCKET_KEY_TYPE(b), ZSTR(BUCKET_KEY_S(b)), b->nKeyLength, b->h TSRMLS_CC);
+		b = b->pListNext;
+	}
+
+#ifdef ZEND_ENGINE_2_1
+	/* trigger auto_globals jit */
+	for (b = TG(auto_globals).pListHead; b != NULL; b = b->pListNext) {
+		zend_auto_global *auto_global = (zend_auto_global *) b->pData;
+		/* check if actived */
+		if (auto_global->auto_global_callback && !auto_global->armed) {
+			zend_u_is_auto_global(BUCKET_KEY_TYPE(b), ZSTR(BUCKET_KEY_S(b)), auto_global->name_len TSRMLS_CC);
+		}
+	}
+#endif
+
+#ifdef ZEND_COMPILE_DELAYED_BINDING
+	zend_do_delayed_early_binding(CG(active_op_array) TSRMLS_CC);
+#else
+	xc_undo_pass_two(CG(active_op_array) TSRMLS_CC);
+	xc_foreach_early_binding_class(CG(active_op_array), xc_early_binding_cb, (void *) sandbox TSRMLS_CC);
+	xc_redo_pass_two(CG(active_op_array) TSRMLS_CC);
+#endif
+
+#ifdef XCACHE_ERROR_CACHING
+	/* restore trigger errors */
+	for (i = 0; i < sandbox->compilererror_cnt; i ++) {
+		xc_compilererror_t *error = &sandbox->compilererrors[i];
+		CG(zend_lineno) = error->lineno;
+		zend_error(error->type, "%s", error->error);
+	}
+	CG(zend_lineno) = 0;
+#endif
+
+	i = 1;
+	/* still needed because in zend_language_scanner.l, require()/include() check file_handle.handle.stream.handle */
+	zend_hash_add(&OG(included_files), sandbox->filename, strlen(sandbox->filename) + 1, (void *)&i, sizeof(int), NULL);
+}
+/* }}} */
+static void xc_sandbox_free(xc_sandbox_t *sandbox, zend_op_array *op_array TSRMLS_DC) /* {{{ */
+{
+	XG(sandbox) = NULL;
+#ifdef XCACHE_ERROR_CACHING
+	EG(user_error_handler_error_reporting) = sandbox->orig_user_error_handler_error_reporting;
+#endif
+
+	/* restore first first install function/class */
+#ifdef HAVE_XCACHE_CONSTANT
+	EG(zend_constants) = OG(zend_constants);
+#endif
+	CG(function_table) = OG(function_table);
+	CG(class_table)    = OG(class_table);
+	EG(class_table)    = CG(class_table);
+#ifdef ZEND_ENGINE_2_1
+	CG(auto_globals)   = OG(auto_globals);
+#endif
+
+	if (op_array) {
+		zend_op_array *old_active_op_array = CG(active_op_array);
+		CG(in_compilation)    = 1;
+		CG(compiled_filename) = ZEND_24(NOTHING, (char *)) sandbox->filename;
+		CG(zend_lineno)       = 0;
+
+		CG(active_op_array) = op_array;
+		xc_sandbox_install(sandbox TSRMLS_CC);
+		CG(active_op_array) = old_active_op_array;
+
+		CG(in_compilation)    = 0;
+		CG(compiled_filename) = NULL;
+
+		/* no free as it's installed */
+#ifdef HAVE_XCACHE_CONSTANT
+		TG(zend_constants).pDestructor = NULL;
+#endif
+		TG(function_table).pDestructor = NULL;
+		TG(class_table).pDestructor = NULL;
+	}
+
+	/* destroy all the tmp */
+#ifdef HAVE_XCACHE_CONSTANT
+	zend_hash_destroy(&TG(zend_constants));
+#endif
+	zend_hash_destroy(&TG(function_table));
+	zend_hash_destroy(&TG(class_table));
+#ifdef ZEND_ENGINE_2_1
+	zend_hash_destroy(&TG(auto_globals));
+#endif
+	zend_hash_destroy(TG(included_files));
+
+	/* restore orig here, as EG/CG holded tmp before */
+	memcpy(&EG(included_files), &OG(included_files), sizeof(EG(included_files)));
+
+#ifdef XCACHE_ERROR_CACHING
+	if (sandbox->compilererrors) {
+		zend_uint i;
+		for (i = 0; i < sandbox->compilererror_cnt; i ++) {
+			efree(sandbox->compilererrors[i].error);
+		}
+		efree(sandbox->compilererrors);
+	}
+#endif
+
+#ifdef ZEND_COMPILE_IGNORE_INTERNAL_CLASSES
+	CG(compiler_options) = sandbox->orig_compiler_options;
+#endif
+}
+/* }}} */
+zend_op_array *xc_sandbox(xc_sandboxed_func_t sandboxed_func, void *data, ZEND_24(NOTHING, const) char *filename TSRMLS_DC) /* {{{ */
+{
+	xc_sandbox_t sandbox;
+	zend_op_array *op_array = NULL;
+	zend_bool catched = 0;
+
+	memset(&sandbox, 0, sizeof(sandbox));
+	zend_try {
+		xc_sandbox_init(&sandbox, filename TSRMLS_CC);
+		op_array = sandboxed_func(data TSRMLS_CC);
+	} zend_catch {
+		catched = 1;
+	} zend_end_try();
+
+	xc_sandbox_free(&sandbox, op_array TSRMLS_CC);
+	if (catched) {
+		zend_bailout();
+	}
+	return op_array;
+}
+/* }}} */
+const Bucket *xc_sandbox_user_function_begin(TSRMLS_D) /* {{{ */
+{
+	xc_sandbox_t *sandbox = (xc_sandbox_t *) XG(sandbox);
+	assert(sandbox);
+	return TG(internal_function_tail) ? TG(internal_function_tail)->pListNext : TG(function_table).pListHead;
+}
+/* }}} */
+const Bucket *xc_sandbox_user_class_begin(TSRMLS_D) /* {{{ */
+{
+	xc_sandbox_t *sandbox = (xc_sandbox_t *) XG(sandbox);
+	assert(sandbox);
+	return TG(internal_class_tail) ? TG(internal_class_tail)->pListNext : TG(class_table).pListHead;
+}
+/* }}} */
+#ifdef XCACHE_ERROR_CACHING
+xc_compilererror_t *xc_sandbox_compilererrors(TSRMLS_D) /* {{{ */
+{
+	xc_sandbox_t *sandbox = (xc_sandbox_t *) XG(sandbox);
+	assert(sandbox);
+	return sandbox->compilererrors;
+}
+/* }}} */
+zend_uint xc_sandbox_compilererror_cnt(TSRMLS_D) /* {{{ */
+{
+	xc_sandbox_t *sandbox = (xc_sandbox_t *) XG(sandbox);
+	assert(sandbox);
+	return sandbox->compilererror_cnt;
+}
+/* }}} */
+#endif
+
+/* MINIT/MSHUTDOWN */
+int xc_sandbox_module_init(int module_number TSRMLS_DC) /* {{{ */
+{
+#ifdef XCACHE_ERROR_CACHING
+	old_zend_error_cb = zend_error_cb;
+	zend_error_cb = xc_sandbox_error_cb;
+#endif
+
+	return SUCCESS;
+}
+/* }}} */
+void xc_sandbox_module_shutdown() /* {{{ */
+{
+#ifdef XCACHE_ERROR_CACHING
+	if (zend_error_cb == xc_sandbox_error_cb) {
+		zend_error_cb = old_zend_error_cb;
+	}
+#endif
+}
+/* }}} */
Index: /tags/3.0.0-rc1/xcache/xc_const_string_opcodes_php4.x.h
===================================================================
--- /tags/3.0.0-rc1/xcache/xc_const_string_opcodes_php4.x.h	(revision 982)
+++ /tags/3.0.0-rc1/xcache/xc_const_string_opcodes_php4.x.h	(revision 982)
@@ -0,0 +1,116 @@
+/* size = 113 */
+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/3.0.0-rc1/xcache/xc_const_string_opcodes_php6.x.h
===================================================================
--- /tags/3.0.0-rc1/xcache/xc_const_string_opcodes_php6.x.h	(revision 982)
+++ /tags/3.0.0-rc1/xcache/xc_const_string_opcodes_php6.x.h	(revision 982)
@@ -0,0 +1,162 @@
+/* size = 159 */
+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 */	"INIT_NS_FCALL_BY_NAME",
+/* 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 */	"GOTO",
+/* 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 */	"RETURN_BY_REF",
+/* 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 */	"DECLARE_CONST",
+/* 144 */	"ADD_INTERFACE",
+/* 145 */	"DECLARE_INHERITED_CLASS_DELAYED",
+/* 146 */	"VERIFY_ABSTRACT_CLASS",
+/* 147 */	"ASSIGN_DIM",
+/* 148 */	"ISSET_ISEMPTY_PROP_OBJ",
+/* 149 */	"HANDLE_EXCEPTION",
+/* 150 */	"USER_OPCODE",
+/* 151 */	"UNDEF",
+/* 152 */	"JMP_SET",
+/* 153 */	"DECLARE_LAMBDA_FUNCTION",
+/* 154 */	"ADD_TRAIT",
+/* 155 */	"BIND_TRAITS",
+/* 156 */	"SEPARATE",
+/* 157 */	"QM_ASSIGN_VAR",
+/* 158 */	"JMP_SET_VAR"
+};
Index: /tags/3.0.0-rc1/xcache/xc_utils.c
===================================================================
--- /tags/3.0.0-rc1/xcache/xc_utils.c	(revision 1112)
+++ /tags/3.0.0-rc1/xcache/xc_utils.c	(revision 1112)
@@ -0,0 +1,618 @@
+
+#include "xcache.h"
+#include "xcache_globals.h"
+#include "xc_utils.h"
+#ifdef ZEND_ENGINE_2_1
+#include "zend_vm.h"
+#endif
+#include "xc_opcode_spec.h"
+#include "util/xc_trace.h"
+
+#ifndef max
+#define max(a, b) ((a) < (b) ? (b) : (a))
+#endif
+
+#ifndef ZEND_VM_SET_OPCODE_HANDLER
+#	define ZEND_VM_SET_OPCODE_HANDLER(opline) do { } while (0)
+#endif
+
+#ifdef ZEND_ENGINE_2_4
+#	define OP_ZVAL_DTOR(op) do { } while(0)
+#else
+#	define OP_ZVAL_DTOR(op) do { \
+		Z_UNSET_ISREF(Z_OP_CONSTANT(op)); \
+		zval_dtor(&Z_OP_CONSTANT(op)); \
+	} while(0)
+#endif
+
+/* }}} */
+
+xc_compile_result_t *xc_compile_result_init(xc_compile_result_t *cr, /* {{{ */
+		zend_op_array *op_array,
+		HashTable *function_table,
+		HashTable *class_table)
+{
+	assert(cr);
+	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) /* {{{ */
+{
+	assert(cr);
+	return xc_compile_result_init(cr, op_array, CG(function_table), CG(class_table));
+}
+/* }}} */
+void xc_compile_result_free(xc_compile_result_t *cr) /* {{{ */
+{
+}
+/* }}} */
+
+typedef struct {
+	apply_func_t applyer;
+} xc_apply_func_info;
+static int xc_apply_function(zend_function *zf, xc_apply_func_info *fi TSRMLS_DC) /* {{{ */
+{
+	switch (zf->type) {
+	case ZEND_USER_FUNCTION:
+	case ZEND_EVAL_CODE:
+		return fi->applyer(&zf->op_array TSRMLS_CC);
+		break;
+
+	case ZEND_INTERNAL_FUNCTION:
+	case ZEND_OVERLOADED_FUNCTION:
+		break;
+
+	EMPTY_SWITCH_DEFAULT_CASE();
+	}
+	return 0;
+}
+/* }}} */
+typedef struct {
+	xc_apply_func_info fi;
+	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->fi TSRMLS_CC);
+}
+/* }}} */
+static int xc_apply_cest(xc_cest_t *cest, xc_apply_func_info *fi TSRMLS_DC) /* {{{ */
+{
+	xc_apply_method_info mi;
+
+	mi.fi = *fi;
+	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) /* {{{ */
+{
+	xc_apply_func_info fi;
+	fi.applyer = applyer;
+	zend_hash_apply_with_argument(cr->function_table, (apply_func_arg_t) xc_apply_function, &fi TSRMLS_CC);
+	zend_hash_apply_with_argument(cr->class_table, (apply_func_arg_t) xc_apply_cest, &fi TSRMLS_CC);
+
+	return applyer(cr->op_array TSRMLS_CC);
+}
+/* }}} */
+int xc_undo_pass_two(zend_op_array *op_array TSRMLS_DC) /* {{{ */
+{
+	zend_op *opline, *opline_end;
+
+#ifdef ZEND_ENGINE_2_4
+	if (!(op_array->fn_flags & ZEND_ACC_DONE_PASS_TWO)) {
+		return 0;
+	}
+#else
+	if (!op_array->done_pass_two) {
+		return 0;
+	}
+#endif
+
+	opline = op_array->opcodes;
+	opline_end = opline + op_array->last;
+	while (opline < opline_end) {
+#ifdef ZEND_ENGINE_2_4
+		if (opline->op1_type == IS_CONST) {
+			opline->op1.constant = opline->op1.literal - op_array->literals;
+		}
+		if (opline->op2_type == IS_CONST) {
+			opline->op2.constant = opline->op2.literal - op_array->literals;
+		}
+#endif
+
+#ifdef ZEND_ENGINE_2_1
+		switch (opline->opcode) {
+#ifdef ZEND_GOTO
+			case ZEND_GOTO:
+#endif
+			case ZEND_JMP:
+				assert(Z_OP(opline->op1).jmp_addr >= op_array->opcodes && (zend_uint) (Z_OP(opline->op1).jmp_addr - op_array->opcodes) < op_array->last);
+				Z_OP(opline->op1).opline_num = Z_OP(opline->op1).jmp_addr - op_array->opcodes;
+				break;
+			case ZEND_JMPZ:
+			case ZEND_JMPNZ:
+			case ZEND_JMPZ_EX:
+			case ZEND_JMPNZ_EX:
+#ifdef ZEND_JMP_SET
+			case ZEND_JMP_SET:
+#endif
+#ifdef ZEND_JMP_SET_VAR
+			case ZEND_JMP_SET_VAR:
+#endif
+				assert(Z_OP(opline->op2).jmp_addr >= op_array->opcodes && (zend_uint) (Z_OP(opline->op2).jmp_addr - op_array->opcodes) < op_array->last);
+				Z_OP(opline->op2).opline_num = Z_OP(opline->op2).jmp_addr - op_array->opcodes;
+				break;
+		}
+#endif
+		opline++;
+	}
+#ifdef ZEND_ENGINE_2_4
+	op_array->fn_flags &= ~ZEND_ACC_DONE_PASS_TWO;
+#else
+	op_array->done_pass_two = 0;
+#endif
+
+	return 0;
+}
+/* }}} */
+int xc_redo_pass_two(zend_op_array *op_array TSRMLS_DC) /* {{{ */
+{
+	zend_op *opline, *opline_end;
+#ifdef ZEND_ENGINE_2_4
+	zend_literal *literal = op_array->literals;
+#endif
+
+#ifdef ZEND_ENGINE_2_4
+	if ((op_array->fn_flags & ZEND_ACC_DONE_PASS_TWO)) {
+		return 0;
+	}
+#else
+	if (op_array->done_pass_two) {
+		return 0;
+	}
+#endif
+
+	/*
+	op_array->opcodes = (zend_op *) erealloc(op_array->opcodes, sizeof(zend_op)*op_array->last);
+	op_array->size = op_array->last;
+	*/
+#ifdef ZEND_ENGINE_2_4
+	if (literal) {
+		zend_literal *literal_end = literal + op_array->last_literal;
+		while (literal < literal_end) {
+			Z_SET_ISREF(literal->constant);
+			Z_SET_REFCOUNT(literal->constant, 2); /* Make sure is_ref won't be reset */
+			literal++;
+		}
+	}
+#endif
+
+	opline = op_array->opcodes;
+	opline_end = opline + op_array->last;
+	while (opline < opline_end) {
+#ifdef ZEND_ENGINE_2_4
+		if (opline->op1_type == IS_CONST) {
+			opline->op1.literal = op_array->literals + opline->op1.constant;
+		}
+		if (opline->op2_type == IS_CONST) {
+			opline->op2.literal = op_array->literals + opline->op2.constant;
+		}
+#else
+		if (Z_OP_TYPE(opline->op1) == IS_CONST) {
+			Z_SET_ISREF(Z_OP_CONSTANT(opline->op1));
+			Z_SET_REFCOUNT(Z_OP_CONSTANT(opline->op1), 2); /* Make sure is_ref won't be reset */
+		}
+		if (Z_OP_TYPE(opline->op2) == IS_CONST) {
+			Z_SET_ISREF(Z_OP_CONSTANT(opline->op2));
+			Z_SET_REFCOUNT(Z_OP_CONSTANT(opline->op2), 2);
+		}
+#endif
+#ifdef ZEND_ENGINE_2_1
+		switch (opline->opcode) {
+#ifdef ZEND_GOTO
+			case ZEND_GOTO:
+#endif
+			case ZEND_JMP:
+				assert(Z_OP(opline->op1).opline_num < op_array->last);
+				Z_OP(opline->op1).jmp_addr = op_array->opcodes + Z_OP(opline->op1).opline_num;
+				break;
+			case ZEND_JMPZ:
+			case ZEND_JMPNZ:
+			case ZEND_JMPZ_EX:
+			case ZEND_JMPNZ_EX:
+#ifdef ZEND_JMP_SET
+			case ZEND_JMP_SET:
+#endif
+				assert(Z_OP(opline->op2).opline_num < op_array->last);
+				Z_OP(opline->op2).jmp_addr = op_array->opcodes + Z_OP(opline->op2).opline_num;
+				break;
+		}
+		ZEND_VM_SET_OPCODE_HANDLER(opline);
+#endif
+		opline++;
+	}
+
+#ifdef ZEND_ENGINE_2_4
+	op_array->fn_flags |= ZEND_ACC_DONE_PASS_TWO;
+#else
+	op_array->done_pass_two = 1;
+#endif
+	return 0;
+}
+/* }}} */
+
+static void xc_fix_opcode_ex_znode(int tofix, xc_op_spec_t spec, Z_OP_TYPEOF_TYPE *op_type, znode_op *op, int type TSRMLS_DC) /* {{{ */
+{
+#ifdef ZEND_ENGINE_2
+	if ((*op_type != IS_UNUSED && (spec == OPSPEC_UCLASS || spec == OPSPEC_CLASS)) ||
+			spec == OPSPEC_FETCH) {
+		if (tofix) {
+			switch (*op_type) {
+			case IS_VAR:
+			case IS_TMP_VAR:
+				break;
+
+			default:
+				/* TODO: data lost, find a way to keep it */
+				/* assert(*op_type == IS_CONST); */
+				*op_type = IS_TMP_VAR;
+			}
+		}
+	}
+	switch (*op_type) {
+	case IS_TMP_VAR:
+	case IS_VAR:
+		if (tofix) {
+			Z_OP(*op).var /= sizeof(temp_variable);
+		}
+		else {
+			Z_OP(*op).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, &Z_OP_TYPE(opline->op1),    &opline->op1, 0 TSRMLS_CC);
+			xc_fix_opcode_ex_znode(tofix, spec->op2, &Z_OP_TYPE(opline->op2),    &opline->op2, 1 TSRMLS_CC);
+			xc_fix_opcode_ex_znode(tofix, spec->res, &Z_OP_TYPE(opline->result), &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;
+}
+/* }}} */
+
+int xc_foreach_early_binding_class(zend_op_array *op_array, xc_foreach_early_binding_class_cb callback, void *data TSRMLS_DC) /* {{{ */
+{
+	zend_op *opline, *begin, *opline_end, *next = NULL;
+
+	opline = begin = op_array->opcodes;
+	opline_end = opline + op_array->last;
+	while (opline < opline_end) {
+		switch (opline->opcode) {
+#ifdef ZEND_GOTO
+			case ZEND_GOTO:
+#endif
+			case ZEND_JMP:
+				next = begin + Z_OP(opline->op1).opline_num;
+				break;
+
+			case ZEND_JMPZNZ:
+				next = begin + max(Z_OP(opline->op2).opline_num, opline->extended_value);
+				break;
+
+			case ZEND_JMPZ:
+			case ZEND_JMPNZ:
+			case ZEND_JMPZ_EX:
+			case ZEND_JMPNZ_EX:
+#ifdef ZEND_JMP_SET
+			case ZEND_JMP_SET:
+#endif
+				next = begin + Z_OP(opline->op2).opline_num;
+				break;
+
+			case ZEND_RETURN:
+				opline = opline_end;
+				break;
+
+#ifdef ZEND_ENGINE_2
+			case ZEND_DECLARE_INHERITED_CLASS:
+				callback(opline, opline - begin, data TSRMLS_CC);
+				break;
+#else
+			case ZEND_DECLARE_FUNCTION_OR_CLASS:
+				if (opline->extended_value == ZEND_DECLARE_INHERITED_CLASS) {
+					callback(opline, opline - begin, data TSRMLS_CC);
+				}
+				break;
+#endif
+		}
+
+		if (opline < next) {
+			opline = next;
+		}
+		else {
+			opline ++;
+		}
+	}
+	return SUCCESS;
+}
+/* }}} */
+#ifndef ZEND_COMPILE_DELAYED_BINDING
+int xc_do_early_binding(zend_op_array *op_array, HashTable *class_table, int oplineno TSRMLS_DC) /* {{{ */
+{
+	zend_op *opline;
+
+	TRACE("binding %d", oplineno);
+	assert(oplineno >= 0);
+
+	/* do early binding */
+	opline = &(op_array->opcodes[oplineno]);
+
+	switch (opline->opcode) {
+#ifdef ZEND_ENGINE_2
+	case ZEND_DECLARE_INHERITED_CLASS:
+		{
+			zval *parent_name;
+			zend_class_entry **pce;
+
+			/* don't early-bind classes that implement interfaces */
+			if ((opline + 1)->opcode == ZEND_FETCH_CLASS && (opline + 2)->opcode == ZEND_ADD_INTERFACE) {
+				return FAILURE;
+			}
+
+			parent_name = &(Z_OP_CONSTANT((opline - 1)->op2));
+			TRACE("binding with parent %s", Z_STRVAL_P(parent_name));
+			if (zend_lookup_class(Z_STRVAL_P(parent_name), Z_STRLEN_P(parent_name), &pce TSRMLS_CC) == FAILURE) {
+				return FAILURE;
+			}
+
+			if (do_bind_inherited_class(opline, class_table, *pce, 1 TSRMLS_CC) == NULL) {
+				return FAILURE;
+			}
+		}
+
+		/* clear unnecessary ZEND_FETCH_CLASS opcode */
+		if (opline > op_array->opcodes
+		 && (opline - 1)->opcode == ZEND_FETCH_CLASS) {
+			zend_op *fetch_class_opline = opline - 1;
+
+			TRACE("%s %p", Z_STRVAL(Z_OP_CONSTANT(fetch_class_opline->op2)), Z_STRVAL(Z_OP_CONSTANT(fetch_class_opline->op2)));
+			OP_ZVAL_DTOR(fetch_class_opline->op2);
+			fetch_class_opline->opcode = ZEND_NOP;
+			ZEND_VM_SET_OPCODE_HANDLER(fetch_class_opline);
+			memset(&fetch_class_opline->op1, 0, sizeof(znode));
+			memset(&fetch_class_opline->op2, 0, sizeof(znode));
+			SET_UNUSED(fetch_class_opline->op1);
+			SET_UNUSED(fetch_class_opline->op2);
+			SET_UNUSED(fetch_class_opline->result);
+		}
+
+		/* clear unnecessary ZEND_VERIFY_ABSTRACT_CLASS opcode */
+		if ((opline + 1)->opcode == ZEND_VERIFY_ABSTRACT_CLASS) {
+			zend_op *abstract_op = opline + 1;
+			memset(abstract_op, 0, sizeof(abstract_op[0]));
+			abstract_op->lineno = 0;
+			SET_UNUSED(abstract_op->op1);
+			SET_UNUSED(abstract_op->op2);
+			SET_UNUSED(abstract_op->result);
+			abstract_op->opcode = ZEND_NOP;
+			ZEND_VM_SET_OPCODE_HANDLER(abstract_op);
+		}
+#else
+	case ZEND_DECLARE_FUNCTION_OR_CLASS:
+		if (do_bind_function_or_class(opline, NULL, class_table, 1) == FAILURE) {
+			return FAILURE;
+		}
+#endif
+		break;
+
+	default:
+		return FAILURE;
+	}
+
+	zend_hash_del(class_table, Z_OP_CONSTANT(opline->op1).value.str.val, Z_OP_CONSTANT(opline->op1).value.str.len);
+	OP_ZVAL_DTOR(opline->op1);
+	OP_ZVAL_DTOR(opline->op2);
+	opline->opcode = ZEND_NOP;
+	ZEND_VM_SET_OPCODE_HANDLER(opline);
+	memset(&opline->op1, 0, sizeof(znode));
+	memset(&opline->op2, 0, sizeof(znode));
+	SET_UNUSED(opline->op1);
+	SET_UNUSED(opline->op2);
+	return SUCCESS;
+}
+/* }}} */
+#endif
+
+#ifdef HAVE_XCACHE_CONSTANT
+void xc_install_constant(ZEND_24(NOTHING, const) char *filename, zend_constant *constant, zend_uchar type, const24_zstr key, uint len, ulong h TSRMLS_DC) /* {{{ */
+{
+	if (zend_u_hash_add(EG(zend_constants), type, key, len,
+				constant, sizeof(zend_constant),
+				NULL
+				) == FAILURE) {
+		CG(zend_lineno) = 0;
+#ifdef IS_UNICODE
+		zend_error(E_NOTICE, "Constant %R already defined", type, key);
+#else
+		zend_error(E_NOTICE, "Constant %s already defined", key);
+#endif
+		free(ZSTR_V(constant->name));
+		if (!(constant->flags & CONST_PERSISTENT)) {
+			zval_dtor(&constant->value);
+		}
+	}
+}
+/* }}} */
+#endif
+void xc_install_function(ZEND_24(NOTHING, const) char *filename, zend_function *func, zend_uchar type, const24_zstr key, uint len, ulong h TSRMLS_DC) /* {{{ */
+{
+	zend_bool istmpkey;
+
+	if (func->type == ZEND_USER_FUNCTION) {
+#ifdef IS_UNICODE
+		istmpkey = (type == IS_STRING && ZSTR_S(key)[0] == 0) || ZSTR_U(key)[0] == 0;
+#else
+		istmpkey = ZSTR_S(key)[0] == 0;
+#endif
+		if (istmpkey) {
+			zend_u_hash_update(CG(function_table), type, key, len,
+						func, sizeof(zend_op_array),
+						NULL
+						);
+		}
+		else if (zend_u_hash_add(CG(function_table), type, key, len,
+					func, sizeof(zend_op_array),
+					NULL
+					) == FAILURE) {
+			CG(zend_lineno) = ZESW(func->op_array.opcodes[0].lineno, func->op_array.line_start);
+#ifdef IS_UNICODE
+			zend_error(E_ERROR, "Cannot redeclare %R()", type, key);
+#else
+			zend_error(E_ERROR, "Cannot redeclare %s()", key);
+#endif
+		}
+	}
+}
+/* }}} */
+ZESW(xc_cest_t *, void) xc_install_class(ZEND_24(NOTHING, const) char *filename, xc_cest_t *cest, int oplineno, zend_uchar type, const24_zstr key, uint len, ulong h TSRMLS_DC) /* {{{ */
+{
+	zend_bool istmpkey;
+	zend_class_entry *cep = CestToCePtr(*cest);
+	ZESW(void *stored_ce_ptr, NOTHING);
+
+#ifdef IS_UNICODE
+	istmpkey = (type == IS_STRING && ZSTR_S(key)[0] == 0) || ZSTR_U(key)[0] == 0;
+#else
+	istmpkey = ZSTR_S(key)[0] == 0;
+#endif
+	if (istmpkey) {
+		zend_u_hash_quick_update(CG(class_table), type, key, len, h,
+					cest, sizeof(xc_cest_t),
+					ZESW(&stored_ce_ptr, NULL)
+					);
+#ifndef ZEND_COMPILE_DELAYED_BINDING
+		if (oplineno != -1) {
+			xc_do_early_binding(CG(active_op_array), CG(class_table), oplineno TSRMLS_CC);
+		}
+#endif
+	}
+	else if (zend_u_hash_quick_add(CG(class_table), type, key, len, h,
+				cest, sizeof(xc_cest_t),
+				ZESW(&stored_ce_ptr, NULL)
+				) == FAILURE) {
+		CG(zend_lineno) = ZESW(0, Z_CLASS_INFO(*cep).line_start);
+#ifdef IS_UNICODE
+		zend_error(E_ERROR, "Cannot redeclare class %R", type, cep->name);
+#else
+		zend_error(E_ERROR, "Cannot redeclare class %s", cep->name);
+#endif
+		assert(oplineno == -1);
+	}
+	ZESW(return (xc_cest_t *) stored_ce_ptr, NOTHING);
+}
+/* }}} */
+
+void xc_hash_copy_if(HashTable *target, HashTable *source, copy_ctor_func_t pCopyConstructor, void *tmp, uint size, xc_if_func_t checker) /* {{{ */
+{
+	Bucket *p;
+	void *new_entry;
+	zend_bool setTargetPointer;
+
+	setTargetPointer = !target->pInternalPointer;
+	p = source->pListHead;
+	while (p) {
+		if (checker(p->pData)) {
+			if (setTargetPointer && source->pInternalPointer == p) {
+				target->pInternalPointer = NULL;
+			}
+			if (p->nKeyLength) {
+				zend_u_hash_quick_update(target, p->key.type, ZSTR(BUCKET_KEY_S(p)), p->nKeyLength, p->h, p->pData, size, &new_entry);
+			} else {
+				zend_hash_index_update(target, p->h, p->pData, size, &new_entry);
+			}
+			if (pCopyConstructor) {
+				pCopyConstructor(new_entry);
+			}
+		}
+		p = p->pListNext;
+	}
+	if (!target->pInternalPointer) {
+		target->pInternalPointer = target->pListHead;
+	}
+}
+/* }}} */
+#ifdef HAVE_XCACHE_CONSTANT
+static zend_bool xc_is_internal_zend_constant(zend_constant *c) /* {{{ */
+{
+	return (c->flags & CONST_PERSISTENT) ? 1 : 0;
+}
+/* }}} */
+void xc_zend_constant_ctor(zend_constant *c) /* {{{ */
+{
+	assert((c->flags & CONST_PERSISTENT));
+	ZSTR_U(c->name) = UNISW(zend_strndup, zend_ustrndup)(ZSTR_U(c->name), c->name_len - 1);
+}
+/* }}} */
+void xc_zend_constant_dtor(zend_constant *c) /* {{{ */
+{
+	free(ZSTR_V(c->name));
+}
+/* }}} */
+void xc_copy_internal_zend_constants(HashTable *target, HashTable *source) /* {{{ */
+{
+	zend_constant tmp_const;
+	xc_hash_copy_if(target, source, (copy_ctor_func_t) xc_zend_constant_ctor, (void *) &tmp_const, sizeof(zend_constant), (xc_if_func_t) xc_is_internal_zend_constant);
+}
+/* }}} */
+#endif
Index: /tags/3.0.0-rc1/xcache/xc_shm_mmap.c
===================================================================
--- /tags/3.0.0-rc1/xcache/xc_shm_mmap.c	(revision 1135)
+++ /tags/3.0.0-rc1/xcache/xc_shm_mmap.c	(revision 1135)
@@ -0,0 +1,320 @@
+
+#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
+#	include <process.h>
+#	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>
+/* make sure to mark(change) it to NULL to keep consistent */
+#	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"
+#define XC_SHM_IMPL _xc_mmap_shm_t
+#include "xc_shm.h"
+#include "xc_utils.h"
+
+#ifndef max
+#define max(a, b) ((a) < (b) ? (b) : (a))
+#endif
+
+/* {{{ xc_shm_t */
+struct _xc_mmap_shm_t {
+	xc_shm_handlers_t *handlers;
+	zend_bool disabled;
+	void *ptr;
+	void *ptr_ro;
+	long  diff;
+	xc_shmsize_t size;
+	xc_shmsize_t memoffset;
+	char *name;
+#ifdef ZEND_WIN32
+	HANDLE hmap;
+	HANDLE hmap_ro;
+#else
+	int newfile;
+#endif
+};
+
+/* }}} */
+#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))
+
+static XC_SHM_CAN_READONLY(xc_mmap_can_readonly) /* {{{ */
+{
+	return shm->ptr_ro != NULL;
+}
+/* }}} */
+static XC_SHM_IS_READWRITE(xc_mmap_is_readwrite) /* {{{ */
+{
+	return p >= shm->ptr && (char *)p < (char *)shm->ptr + shm->size;
+}
+/* }}} */
+static XC_SHM_IS_READONLY(xc_mmap_is_readonly) /* {{{ */
+{
+	return xc_mmap_can_readonly(shm) && p >= shm->ptr_ro && (char *)p < (char *)shm->ptr_ro + shm->size;
+}
+/* }}} */
+static XC_SHM_TO_READWRITE(xc_mmap_to_readwrite) /* {{{ */
+{
+	if (shm->diff) {
+		assert(xc_mmap_is_readonly(shm, p));
+		p = PTR_SUB(p, shm->diff);
+	}
+	assert(xc_mmap_is_readwrite(shm, p));
+	return p;
+}
+/* }}} */
+static XC_SHM_TO_READONLY(xc_mmap_to_readonly) /* {{{ */
+{
+	assert(xc_mmap_is_readwrite(shm, p));
+	if (shm->diff) {
+		p = PTR_ADD(p, shm->diff);
+		assert(xc_mmap_is_readonly(shm, p));
+	}
+	return p;
+}
+/* }}} */
+
+static XC_SHM_DESTROY(xc_mmap_destroy) /* {{{ */
+{
+	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) {
+#ifndef ZEND_WIN32
+#	ifdef __CYGWIN__
+		if (shm->newfile) {
+			unlink(shm->name);
+		}
+#	endif
+#endif
+		free(shm->name);
+	}
+	/*
+	shm->size = NULL;
+	shm->diff = 0;
+	*/
+
+	free(shm);
+	return;
+}
+/* }}} */
+static XC_SHM_INIT(xc_mmap_init) /* {{{ */
+{
+#ifdef ZEND_WIN32
+#	define TMP_PATH "XCache"
+#else
+#	define TMP_PATH "/tmp/XCache"
+	int fd = -1;
+#endif
+	xc_shm_t *shm = NULL;
+	int ro_ok;
+	volatile void *romem;
+	char tmpname[sizeof(TMP_PATH) - 1 + 100];
+	const char *errstr = NULL;
+	const char *path = (const char *) arg1;
+
+	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.%d", TMP_PATH, (int) getuid(), (int) getpid(), inc ++, rand());
+		path = tmpname;
+	}
+#ifdef ZEND_WIN32
+	else {
+		static int inc2 = 0;
+		snprintf(tmpname, sizeof(tmpname) - 1, "%s.%d.%d.%d.%d", path, (int) getuid(), (int) getpid(), inc2 ++, rand());
+		path = tmpname;
+	}
+#endif
+
+	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) {
+			perror(shm->name);
+			errstr = "Cannot open file set by xcache.mmap_path, check the xcache.size/var_size against system limitation";
+			goto err;
+		}
+		fd = open(shm->name, O_CREAT | O_RDWR, XCACHE_MMAP_PERMISSION);
+		shm->newfile = 1;
+		if (fd == -1) {
+			perror(shm->name);
+			errstr = "Cannot open or create file set by xcache.mmap_path, check the path permission or check xcache.size/var_size against system limitation";
+			goto err;
+		}
+	}
+
+	if (ftruncate(fd, size) != 0 && errno != EINVAL) {
+		perror(shm->name);
+		errstr = "Failed to ftruncate the file";
+		goto err;
+	}
+#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) {
+		perror(shm->name);
+		errstr = "Failed creating file mapping";
+		shm->ptr = NULL;
+		goto err;
+	}
+
+	/* {{{ readonly protection, mmap it readonly and check if ptr_ro works */
+	if (readonly_protection) {
+		ro_ok = 0;
+
+#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
+		if (shm->ptr_ro == XCACHE_MAP_FAILED) {
+			shm->ptr_ro = NULL;
+		}
+		romem = shm->ptr_ro;
+
+		do {
+			if (romem == NULL || romem == 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);
+			/* no overlap */
+			assert((xc_shmsize_t) abs(shm->diff) >= size);
+		}
+		else {
+			if (shm->ptr_ro) {
+				munmap(shm->ptr_ro, size);
+			}
+#ifdef ZEND_WIN32
+			if (shm->hmap_ro) {
+				CloseHandle(shm->hmap_ro);
+			}
+#endif
+			shm->ptr_ro = NULL;
+			shm->diff = 0;
+		}
+	}
+
+	/* }}} */
+
+#ifndef ZEND_WIN32
+	close(fd);
+
+#	ifndef __CYGWIN__
+	if (shm->newfile) {
+		unlink(shm->name);
+	}
+#	endif
+#endif
+
+	return shm;
+
+err:
+#ifndef ZEND_WIN32
+	if (fd != -1) {
+		close(fd);
+	}
+#endif
+	if (shm) {
+		xc_mmap_destroy(shm);
+	}
+	if (errstr) {
+		fprintf(stderr, "%s\n", errstr);
+		zend_error(E_ERROR, "%s", errstr);
+	}
+	return NULL;
+}
+/* }}} */
+
+static XC_SHM_MEMINIT(xc_mmap_meminit) /* {{{ */
+{
+	void *mem;
+	if (shm->memoffset + size > shm->size) {
+		zend_error(E_ERROR, "XCache: internal error at %s#%d", __FILE__, __LINE__);
+		return NULL;
+	}
+	mem = PTR_ADD(shm->ptr, shm->memoffset);
+	shm->memoffset += size;
+	return mem;
+}
+/* }}} */
+static XC_SHM_MEMDESTROY(xc_mmap_memdestroy) /* {{{ */
+{
+}
+/* }}} */
+
+static xc_shm_handlers_t xc_shm_mmap_handlers = XC_SHM_HANDLERS(mmap);
+void xc_shm_mmap_register() /* {{{ */
+{
+	if (xc_shm_scheme_register("mmap", &xc_shm_mmap_handlers) == 0) {
+		zend_error(E_ERROR, "XCache: failed to register mmap shm_scheme");
+	}
+	return;
+}
+/* }}} */
Index: /tags/3.0.0-rc1/xcache/xc_sandbox.h
===================================================================
--- /tags/3.0.0-rc1/xcache/xc_sandbox.h	(revision 1051)
+++ /tags/3.0.0-rc1/xcache/xc_sandbox.h	(revision 1051)
@@ -0,0 +1,28 @@
+#ifndef XC_SANDBOX_H_3AFE4094B1D005188B909F9B6538599C
+#define XC_SANDBOX_H_3AFE4094B1D005188B909F9B6538599C
+
+#if _MSC_VER > 1000
+#pragma once
+#endif /* _MSC_VER > 1000 */
+
+/* Purpose: run specified function in compiler sandbox, restore everything to previous state after it returns
+ */
+
+#include "xc_compatibility.h"
+
+int xc_sandbox_module_init(int module_number TSRMLS_DC);
+void xc_sandbox_module_shutdown();
+
+/* return op_array to install */
+typedef zend_op_array *(*xc_sandboxed_func_t)(void *data TSRMLS_DC);
+zend_op_array *xc_sandbox(xc_sandboxed_func_t sandboxed_func, void *data, ZEND_24(NOTHING, const) char *filename TSRMLS_DC);
+const Bucket *xc_sandbox_user_function_begin(TSRMLS_D);
+const Bucket *xc_sandbox_user_class_begin(TSRMLS_D);
+zend_uint xc_sandbox_compilererror_cnt(TSRMLS_D);
+#ifdef XCACHE_ERROR_CACHING
+struct _xc_compilererror_t;
+struct _xc_compilererror_t *xc_sandbox_compilererrors(TSRMLS_D);
+zend_uint xc_sandbox_compilererror_cnt(TSRMLS_D);
+#endif
+
+#endif /* XC_SANDBOX_H_3AFE4094B1D005188B909F9B6538599C */
Index: /tags/3.0.0-rc1/xcache/xc_utils.h
===================================================================
--- /tags/3.0.0-rc1/xcache/xc_utils.h	(revision 1051)
+++ /tags/3.0.0-rc1/xcache/xc_utils.h	(revision 1051)
@@ -0,0 +1,55 @@
+#include "xcache.h"
+#include "xc_compatibility.h"
+
+typedef zend_op_array *(zend_compile_file_t)(zend_file_handle *h, int type TSRMLS_DC);
+
+typedef struct _xc_compilererror_t {
+	int type;
+	uint lineno;
+	int error_len;
+	char *error;
+} xc_compilererror_t;
+
+typedef struct _xc_compile_result_t {
+	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_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);
+
+typedef void (*xc_foreach_early_binding_class_cb)(zend_op *opline, int oplineno, void *data TSRMLS_DC);
+int xc_foreach_early_binding_class(zend_op_array *op_array, xc_foreach_early_binding_class_cb callback, void *data TSRMLS_DC);
+
+/* installer */
+#ifdef HAVE_XCACHE_CONSTANT
+void xc_install_constant(ZEND_24(NOTHING, const) char *filename, zend_constant *constant, zend_uchar type, const24_zstr key, uint len, ulong h TSRMLS_DC);
+#endif
+void xc_install_function(ZEND_24(NOTHING, const) char *filename, zend_function *func, zend_uchar type, const24_zstr key, uint len, ulong h TSRMLS_DC);
+ZESW(xc_cest_t *, void) xc_install_class(ZEND_24(NOTHING, const) char *filename, xc_cest_t *cest, int oplineno, zend_uchar type, const24_zstr key, uint len, ulong h TSRMLS_DC);
+
+typedef zend_bool (*xc_if_func_t)(void *data);
+
+void xc_hash_copy_if(HashTable *target, HashTable *source, copy_ctor_func_t pCopyConstructor, void *tmp, uint size, xc_if_func_t checker);
+#ifdef HAVE_XCACHE_CONSTANT
+void xc_zend_constant_ctor(zend_constant *c);
+void xc_zend_constant_dtor(zend_constant *c);
+void xc_copy_internal_zend_constants(HashTable *target, HashTable *source);
+#endif
+
+#ifndef ZEND_COMPILE_DELAYED_BINDING
+int xc_do_early_binding(zend_op_array *op_array, HashTable *class_table, int oplineno TSRMLS_DC);
+#endif
Index: /tags/3.0.0-rc1/xcache/xc_extension.c
===================================================================
--- /tags/3.0.0-rc1/xcache/xc_extension.c	(revision 1047)
+++ /tags/3.0.0-rc1/xcache/xc_extension.c	(revision 1047)
@@ -0,0 +1,90 @@
+
+#include "xc_extension.h"
+#include "xcache.h"
+#include "util/xc_trace.h"
+
+
+int xcache_zend_extension_add(zend_extension *new_extension, zend_bool prepend) /* {{{ */
+{
+	zend_extension extension;
+
+	extension = *new_extension;
+	extension.handle = 0;
+
+	zend_extension_dispatch_message(ZEND_EXTMSG_NEW_EXTENSION, &extension);
+
+	if (prepend) {
+		zend_llist_prepend_element(&zend_extensions, &extension);
+	}
+	else {
+		zend_llist_add_element(&zend_extensions, &extension);
+	}
+	TRACE("%s", "registered");
+	return SUCCESS;
+}
+/* }}} */
+static int xc_ptr_compare_func(void *p1, void *p2) /* {{{ */
+{
+	return p1 == p2;
+}
+/* }}} */
+static int xc_zend_extension_remove(zend_extension *extension) /* {{{ */
+{
+	llist_dtor_func_t dtor;
+
+	assert(extension);
+	dtor = zend_extensions.dtor; /* avoid dtor */
+	zend_extensions.dtor = NULL;
+	zend_llist_del_element(&zend_extensions, extension, xc_ptr_compare_func);
+	zend_extensions.dtor = dtor;
+	return SUCCESS;
+}
+/* }}} */
+int xcache_zend_extension_remove(zend_extension *extension) /* {{{ */
+{
+	zend_extension *ext = zend_get_extension(extension->name);
+	if (!ext) {
+		return FAILURE;
+	}
+
+	if (ext->shutdown) {
+		ext->shutdown(ext);
+	}
+	xc_zend_extension_remove(ext);
+	return SUCCESS;
+}
+/* }}} */
+
+void xcache_llist_prepend(zend_llist *l, zend_llist_element *element) /* {{{ */
+{
+	element->next = l->head;
+	element->prev = NULL;
+	if (l->head) {
+		l->head->prev = element;
+	}
+	else {
+		l->tail = element;
+	}
+	l->head = element;
+	++l->count;
+}
+/* }}} */
+void xcache_llist_unlink(zend_llist *l, zend_llist_element *element) /* {{{ */
+{
+	if ((element)->prev) {
+		(element)->prev->next = (element)->next;
+	}
+	else {
+		(l)->head = (element)->next;
+	}
+
+	if ((element)->next) {
+		(element)->next->prev = (element)->prev;
+	}
+	else {
+		(l)->tail = (element)->prev;
+	}
+
+	--l->count;
+}
+/* }}} */
Index: /tags/3.0.0-rc1/xcache/xc_const_string.c
===================================================================
--- /tags/3.0.0-rc1/xcache/xc_const_string.c	(revision 1095)
+++ /tags/3.0.0-rc1/xcache/xc_const_string.c	(revision 1095)
@@ -0,0 +1,88 @@
+#include "xcache.h"
+#include "xc_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"
+};
+
+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)
+{
+	return data_type_names[(data_type & IS_CONSTANT_TYPE_MASK)];
+}
+/* }}} */
+/* {{{ xc_get_opcode */
+#if PHP_MAJOR_VERSION >= 6
+#	include "xc_const_string_opcodes_php6.x.h"
+#elif defined(ZEND_ENGINE_2_4)
+#	include "xc_const_string_opcodes_php5.4.h"
+#elif defined(ZEND_ENGINE_2_3)
+#	include "xc_const_string_opcodes_php5.3.h"
+#elif defined(ZEND_ENGINE_2_1)
+#	include "xc_const_string_opcodes_php5.1.h"
+#elif defined(ZEND_ENGINE_2)
+#	include "xc_const_string_opcodes_php5.0.h"
+#else
+#	include "xc_const_string_opcodes_php4.x.h"
+#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/3.0.0-rc1/xcache/xc_ini.c
===================================================================
--- /tags/3.0.0-rc1/xcache/xc_ini.c	(revision 1026)
+++ /tags/3.0.0-rc1/xcache/xc_ini.c	(revision 1026)
@@ -0,0 +1,38 @@
+#include "xc_ini.h"
+
+PHP_INI_MH(xcache_OnUpdateDummy)
+{
+	return SUCCESS;
+}
+
+PHP_INI_MH(xcache_OnUpdateULong)
+{
+	zend_ulong *p = (zend_ulong *) mh_arg1;
+
+	*p = (zend_ulong) atoi(new_value);
+	return SUCCESS;
+}
+
+PHP_INI_MH(xcache_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;
+}
+
+PHP_INI_MH(xcache_OnUpdateString)
+{
+	char **p = (char**)mh_arg1;
+	if (*p) {
+		pefree(*p, 1);
+	}
+	*p = pemalloc(strlen(new_value) + 1, 1);
+	strcpy(*p, new_value);
+	return SUCCESS;
+}
Index: /tags/3.0.0-rc1/xcache/xc_processor.c
===================================================================
--- /tags/3.0.0-rc1/xcache/xc_processor.c	(revision 1003)
+++ /tags/3.0.0-rc1/xcache/xc_processor.c	(revision 1003)
@@ -0,0 +1,1 @@
+#include "xc_processor.c.h"
Index: /tags/3.0.0-rc1/xcache/xc_extension.h
===================================================================
--- /tags/3.0.0-rc1/xcache/xc_extension.h	(revision 1047)
+++ /tags/3.0.0-rc1/xcache/xc_extension.h	(revision 1047)
@@ -0,0 +1,16 @@
+#ifndef XC_EXTENSION_H_9885D3A6DE7C469D13E34AF331E02BB8
+#define XC_EXTENSION_H_9885D3A6DE7C469D13E34AF331E02BB8
+
+#if _MSC_VER > 1000
+#pragma once
+#endif /* _MSC_VER > 1000 */
+
+#include "util/xc_stack.h"
+#include "zend_extensions.h"
+int xcache_zend_extension_add(zend_extension *new_extension, zend_bool prepend);
+int xcache_zend_extension_remove(zend_extension *extension);
+
+void xcache_llist_prepend(zend_llist *l, zend_llist_element *element);
+void xcache_llist_unlink(zend_llist *l, zend_llist_element *element);
+
+#endif /* XC_EXTENSION_H_9885D3A6DE7C469D13E34AF331E02BB8 */
Index: /tags/3.0.0-rc1/xcache/xc_const_string.h
===================================================================
--- /tags/3.0.0-rc1/xcache/xc_const_string.h	(revision 982)
+++ /tags/3.0.0-rc1/xcache/xc_const_string.h	(revision 982)
@@ -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/3.0.0-rc1/xcache/README
===================================================================
--- /tags/3.0.0-rc1/xcache/README	(revision 982)
+++ /tags/3.0.0-rc1/xcache/README	(revision 982)
@@ -0,0 +1,1 @@
+understructure
Index: /tags/3.0.0-rc1/xcache/xc_opcode_spec.c
===================================================================
--- /tags/3.0.0-rc1/xcache/xc_opcode_spec.c	(revision 982)
+++ /tags/3.0.0-rc1/xcache/xc_opcode_spec.c	(revision 982)
@@ -0,0 +1,46 @@
+#include "xcache.h"
+#include "xc_opcode_spec.h"
+#include "xc_const_string.h"
+
+/* {{{ 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 "xc_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)
+{
+#ifndef NDEBUG
+	if (xc_get_opcode_count() != xc_get_opcode_spec_count()) {
+		fprintf(stderr, "count mismatch: xc_get_opcode_count=%d, xc_get_opcode_spec_count=%d\n", xc_get_opcode_count(), xc_get_opcode_spec_count());
+	}
+#endif
+	assert(xc_get_opcode_count() == xc_get_opcode_spec_count());
+	assert(opcode < xc_get_opcode_spec_count());
+	return &xc_opcode_spec[opcode];
+}
+/* }}} */
+/* {{{ 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/3.0.0-rc1/xcache/xc_ini.h
===================================================================
--- /tags/3.0.0-rc1/xcache/xc_ini.h	(revision 1044)
+++ /tags/3.0.0-rc1/xcache/xc_ini.h	(revision 1044)
@@ -0,0 +1,19 @@
+#ifndef XC_INI_H_E208B8E597E7FAD950D249BE9C6B6F53
+#define XC_INI_H_E208B8E597E7FAD950D249BE9C6B6F53
+
+#if _MSC_VER > 1000
+#pragma once
+#endif /* _MSC_VER > 1000 */
+
+#include "php.h"
+#include "php_ini.h"
+
+PHP_INI_MH(xcache_OnUpdateDummy);
+PHP_INI_MH(xcache_OnUpdateULong);
+PHP_INI_MH(xcache_OnUpdateBool);
+PHP_INI_MH(xcache_OnUpdateString);
+#ifndef ZEND_ENGINE_2
+#define OnUpdateLong OnUpdateInt
+#endif
+
+#endif /* XC_INI_H_E208B8E597E7FAD950D249BE9C6B6F53 */
Index: /tags/3.0.0-rc1/xcache/xc_shm.c
===================================================================
--- /tags/3.0.0-rc1/xcache/xc_shm.c	(revision 1135)
+++ /tags/3.0.0-rc1/xcache/xc_shm.c	(revision 1135)
@@ -0,0 +1,99 @@
+#ifdef TEST
+#include <limits.h>
+#include <stdio.h>
+#else
+#include <php.h>
+#endif
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include "xc_shm.h"
+
+struct _xc_shm_scheme_t {
+	const char              *name;
+	const xc_shm_handlers_t *handlers;
+};
+static xc_shm_scheme_t xc_shm_schemes[10];
+
+void xc_shm_init_modules() /* {{{ */
+{
+	extern void xc_allocator_init();
+#ifdef HAVE_XCACHE_TEST
+	extern void xc_shm_malloc_register();
+#endif
+	extern void xc_shm_mmap_register();
+
+	memset(xc_shm_schemes, 0, sizeof(xc_shm_schemes));
+	xc_allocator_init();
+#ifdef HAVE_XCACHE_TEST
+	xc_shm_malloc_register();
+#endif
+	xc_shm_mmap_register();
+}
+/* }}} */
+int xc_shm_scheme_register(const char *name, const xc_shm_handlers_t *handlers) /* {{{ */
+{
+	int i;
+	for (i = 0; i < 10; i ++) {
+		if (!xc_shm_schemes[i].name) {
+			xc_shm_schemes[i].name = name;
+			xc_shm_schemes[i].handlers = handlers;
+			return 1;
+		}
+	}
+	return 0;
+}
+/* }}} */
+const xc_shm_handlers_t *xc_shm_scheme_find(const char *name) /* {{{ */
+{
+	int i;
+	for (i = 0; i < 10 && xc_shm_schemes[i].name; i ++) {
+		if (strcmp(xc_shm_schemes[i].name, name) == 0) {
+			return xc_shm_schemes[i].handlers;
+		}
+	}
+	return NULL;
+}
+/* }}} */
+xc_shm_scheme_t *xc_shm_scheme_first() /* {{{ */
+{
+	return xc_shm_schemes;
+}
+/* }}} */
+xc_shm_scheme_t *xc_shm_scheme_next(xc_shm_scheme_t *scheme) /* {{{ */
+{
+	scheme ++;
+	return scheme->name ? scheme : NULL;
+}
+/* }}} */
+const char *xc_shm_scheme_name(xc_shm_scheme_t *scheme) /* {{{ */
+{
+	assert(scheme);
+	return scheme->name;
+}
+/* }}} */
+xc_shm_t *xc_shm_init(const char *type, xc_shmsize_t size, int readonly_protection, const void *arg1, const void *arg2) /* {{{ */
+{
+	const xc_shm_handlers_t *handlers = xc_shm_scheme_find(type);
+
+	if (handlers) {
+		xc_shm_t *shm = handlers->init(size, readonly_protection, arg1, arg2);
+		if (shm) {
+			shm->handlers = handlers;
+		}
+		return shm;
+	}
+
+	return NULL;
+}
+/* }}} */
+void xc_shm_destroy(xc_shm_t *shm) /* {{{ */
+{
+	shm->handlers->destroy(shm);
+}
+/* }}} */
Index: /tags/3.0.0-rc1/xcache/xc_opcode_spec.h
===================================================================
--- /tags/3.0.0-rc1/xcache/xc_opcode_spec.h	(revision 982)
+++ /tags/3.0.0-rc1/xcache/xc_opcode_spec.h	(revision 982)
@@ -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) OPSPEC_DUMMY } 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/3.0.0-rc1/xcache/xc_shm.h
===================================================================
--- /tags/3.0.0-rc1/xcache/xc_shm.h	(revision 1135)
+++ /tags/3.0.0-rc1/xcache/xc_shm.h	(revision 1135)
@@ -0,0 +1,69 @@
+#ifndef XC_SHM_H
+#define XC_SHM_H
+
+#include <stdlib.h>
+
+typedef struct _xc_shm_handlers_t xc_shm_handlers_t;
+
+#ifndef XC_SHM_IMPL
+struct _xc_shm_t {
+	const xc_shm_handlers_t *handlers;
+};
+#define XC_SHM_IMPL _xc_shm_t
+#endif
+
+typedef struct XC_SHM_IMPL xc_shm_t;
+typedef size_t xc_shmsize_t;
+
+/* shm */
+#define XC_SHM_CAN_READONLY(func) int   func(xc_shm_t *shm)
+#define XC_SHM_IS_READWRITE(func) int   func(xc_shm_t *shm, const void *p)
+#define XC_SHM_IS_READONLY(func)  int   func(xc_shm_t *shm, const void *p)
+#define XC_SHM_TO_READWRITE(func) void *func(xc_shm_t *shm, void *p)
+#define XC_SHM_TO_READONLY(func)  void *func(xc_shm_t *shm, void *p)
+
+#define XC_SHM_INIT(func)         xc_shm_t *func(xc_shmsize_t size, int readonly_protection, const void *arg1, const void *arg2)
+#define XC_SHM_DESTROY(func)      void func(xc_shm_t *shm)
+
+#define XC_SHM_MEMINIT(func)      void *func(xc_shm_t *shm, xc_shmsize_t size)
+#define XC_SHM_MEMDESTROY(func)   void func(void *mem)
+
+#define XC_SHM_HANDLERS(name)    { \
+	xc_##name##_can_readonly       \
+	, xc_##name##_is_readwrite     \
+	, xc_##name##_is_readonly      \
+	, xc_##name##_to_readwrite     \
+	, xc_##name##_to_readonly      \
+\
+	, xc_##name##_init             \
+	, xc_##name##_destroy          \
+\
+	, xc_##name##_meminit          \
+	, xc_##name##_memdestroy       \
+}
+
+struct _xc_shm_handlers_t {
+	XC_SHM_CAN_READONLY((*can_readonly));
+	XC_SHM_IS_READWRITE((*is_readwrite));
+	XC_SHM_IS_READONLY((*is_readonly));
+	XC_SHM_TO_READWRITE((*to_readwrite));
+	XC_SHM_TO_READONLY((*to_readonly));
+	XC_SHM_INIT((*init));
+	XC_SHM_DESTROY((*destroy));
+
+	XC_SHM_MEMINIT((*meminit));
+	XC_SHM_MEMDESTROY((*memdestroy));
+};
+
+typedef struct _xc_shm_scheme_t xc_shm_scheme_t;
+
+void xc_shm_init_modules();
+int xc_shm_scheme_register(const char *name, const xc_shm_handlers_t *handlers);
+const xc_shm_handlers_t *xc_shm_scheme_find(const char *name);
+xc_shm_scheme_t *xc_shm_scheme_first();
+xc_shm_scheme_t *xc_shm_scheme_next(xc_shm_scheme_t *scheme);
+const char *xc_shm_scheme_name(xc_shm_scheme_t *scheme);
+
+xc_shm_t *xc_shm_init(const char *type, xc_shmsize_t size, int readonly_protection, const void *arg1, const void *arg2);
+void xc_shm_destroy(xc_shm_t *shm);
+#endif
Index: /tags/3.0.0-rc1/xcache/xc_allocator_bestfit.c
===================================================================
--- /tags/3.0.0-rc1/xcache/xc_allocator_bestfit.c	(revision 1136)
+++ /tags/3.0.0-rc1/xcache/xc_allocator_bestfit.c	(revision 1136)
@@ -0,0 +1,322 @@
+#define _xc_allocator_t _xc_allocator_bestfit_t
+#define _xc_allocator_block_t _xc_allocator_bestfit_block_t
+#include "xc_allocator.h"
+#undef _xc_allocator_t
+#undef _xc_allocator_block_t
+
+#ifdef TEST
+#	include <limits.h>
+#	include <stdio.h>
+#	define XCACHE_DEBUG
+typedef int zend_bool;
+#	define ZEND_ATTRIBUTE_PTR_FORMAT(a, b, c)
+#	define zend_error(type, error) fprintf(stderr, "%s", error)
+#else
+#	include <php.h>
+#endif
+
+#ifdef XCACHE_DEBUG
+#	define ALLOC_DEBUG_BLOCK_CHECK
+#endif
+
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include "xc_shm.h"
+#include "util/xc_align.h"
+#include "util/xc_trace.h"
+
+#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))
+
+/* {{{ allocator */
+typedef struct _xc_allocator_bestfit_block_t xc_allocator_bestfit_block_t;
+struct _xc_allocator_bestfit_block_t {
+#ifdef ALLOC_DEBUG_BLOCK_CHECK
+	unsigned int magic;
+#endif
+	xc_memsize_t size; /* reserved even after alloc */
+	xc_allocator_bestfit_block_t *next;  /* not used after alloc */
+};
+
+typedef struct _xc_allocator_bestfit_t {
+	const xc_allocator_vtable_t *vtable;
+	xc_shm_t *shm;
+	xc_memsize_t size;
+	xc_memsize_t avail;       /* total free */
+	xc_allocator_bestfit_block_t headblock[1];  /* just as a pointer to first block*/
+} xc_allocator_bestfit_t;
+
+#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_allocator_bestfit_block_t, size) + SizeOf(xc_allocator_bestfit_block_t, size) ))
+
+#define BLOCK_MAGIC ((unsigned int) 0x87655678)
+
+/* }}} */
+static inline void xc_block_setup(xc_allocator_bestfit_block_t *b, xc_memsize_t size, xc_allocator_bestfit_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_allocator_bestfit_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
+
+
+static XC_ALLOCATOR_MALLOC(xc_allocator_bestfit_malloc) /* {{{ */
+{
+	xc_allocator_bestfit_block_t *prev, *cur;
+	xc_allocator_bestfit_block_t *newb, *b;
+	xc_memsize_t realsize;
+	xc_memsize_t minsize;
+	void *p;
+	/* [xc_allocator_bestfit_block_t:size|size] */
+	realsize = BLOCK_HEADER_SIZE() + size;
+	/* realsize is ALIGNed so next block start at ALIGNed address */
+	realsize = ALIGN(realsize);
+
+	TRACE("avail: %lu (%luKB). Allocate size: %lu realsize: %lu (%luKB)"
+			, allocator->avail, allocator->avail / 1024
+			, size
+			, realsize, realsize / 1024
+			);
+	do {
+		p = NULL;
+		if (allocator->avail < realsize) {
+			TRACE("%s", " oom");
+			break;
+		}
+
+		b = NULL;
+		minsize = ULONG_MAX;
+
+		/* prev|cur */
+
+		for (prev = allocator->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_allocator_bestfit_block_t) + realsize) &&
+					cur->size < minsize) {
+				/* cur is acceptable and memller */
+				b = prev;
+				minsize = cur->size;
+			}
+			prev = cur;
+		}
+
+		if (b == NULL) {
+			TRACE("%s", " no fit chunk");
+			break;
+		}
+
+		prev = b;
+
+		cur = prev->next;
+		p = PADD(cur, BLOCK_HEADER_SIZE());
+
+		/* update the block header */
+		allocator->avail -= realsize;
+
+		/* perfect fit, just unlink */
+		if (cur->size == realsize) {
+			prev->next = cur->next;
+			TRACE(" perfect fit. Got: %p", p);
+			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_allocator_bestfit_block_t *)PADD(cur, realsize);
+		xc_block_setup(newb, cur->size - realsize, b);
+		cur->size = realsize;
+		/* prev|cur|newb|next
+		 *            `--^
+		 */
+
+		TRACE(" -> avail: %lu (%luKB). new next: %p offset: %lu %luKB. Got: %p"
+				, allocator->avail, allocator->avail / 1024
+				, newb
+				, PSUB(newb, allocator), PSUB(newb, allocator) / 1024
+				, p
+				);
+		prev->next = newb;
+		/* prev|cur|newb|next
+		 *    `-----^
+		 */
+
+	} while (0);
+
+	return p;
+}
+/* }}} */
+static XC_ALLOCATOR_FREE(xc_allocator_bestfit_free) /* {{{ return block size freed */
+{
+	xc_allocator_bestfit_block_t *cur, *b;
+	int size;
+
+	cur = (xc_allocator_bestfit_block_t *) (CHAR_PTR(p) - BLOCK_HEADER_SIZE());
+	TRACE("freeing: %p, size=%lu", p, cur->size);
+	xc_block_check(cur);
+	assert((char*)allocator < (char*)cur && (char*)cur < (char*)allocator + allocator->size);
+
+	/* find free block right before the p */
+	b = allocator->headblock;
+	while (b->next != 0 && b->next < cur) {
+		b = b->next;
+	}
+
+	/* restore block */
+	cur->next = b->next;
+	b->next = cur;
+	size = cur->size;
+
+	TRACE(" avail %lu (%luKB)", allocator->avail, allocator->avail / 1024);
+	allocator->avail += size;
+
+	/* combine prev|cur */
+	if (PADD(b, b->size) == (char *)cur) {
+		b->size += cur->size;
+		b->next = cur->next;
+		cur = b;
+		TRACE("%s", " combine prev");
+	}
+
+	/* combine cur|next */
+	b = cur->next;
+	if (PADD(cur, cur->size) == (char *)b) {
+		cur->size += b->size;
+		cur->next = b->next;
+		TRACE("%s", " combine next");
+	}
+	TRACE(" -> avail %lu (%luKB)", allocator->avail, allocator->avail / 1024);
+	return size;
+}
+/* }}} */
+static XC_ALLOCATOR_CALLOC(xc_allocator_bestfit_calloc) /* {{{ */
+{
+	xc_memsize_t realsize = memb * size;
+	void *p = xc_allocator_bestfit_malloc(allocator, realsize);
+
+	if (p) {
+		memset(p, 0, realsize);
+	}
+	return p;
+}
+/* }}} */
+static XC_ALLOCATOR_REALLOC(xc_allocator_bestfit_realloc) /* {{{ */
+{
+	void *newp = xc_allocator_bestfit_malloc(allocator, size);
+	if (p && newp) {
+		memcpy(newp, p, size);
+		xc_allocator_bestfit_free(allocator, p);
+	}
+	return newp;
+}
+/* }}} */
+
+static XC_ALLOCATOR_AVAIL(xc_allocator_bestfit_avail) /* {{{ */
+{
+	return allocator->avail;
+}
+/* }}} */
+static XC_ALLOCATOR_SIZE(xc_allocator_bestfit_size) /* {{{ */
+{
+	return allocator->size;
+}
+/* }}} */
+
+static XC_ALLOCATOR_FREEBLOCK_FIRST(xc_allocator_bestfit_freeblock_first) /* {{{ */
+{
+	return allocator->headblock->next;
+}
+/* }}} */
+static XC_ALLOCATOR_FREEBLOCK_NEXT(xc_allocator_bestfit_freeblock_next) /* {{{ */
+{
+	return block->next;
+}
+/* }}} */
+static XC_ALLOCATOR_BLOCK_SIZE(xc_allocator_bestfit_block_size) /* {{{ */
+{
+	return block->size;
+}
+/* }}} */
+static XC_ALLOCATOR_BLOCK_OFFSET(xc_allocator_bestfit_block_offset) /* {{{ */
+{
+	return ((char *) block) - ((char *) allocator);
+}
+/* }}} */
+
+static XC_ALLOCATOR_INIT(xc_allocator_bestfit_init) /* {{{ */
+{
+	xc_allocator_bestfit_block_t *b;
+#define MINSIZE (ALIGN(sizeof(xc_allocator_bestfit_t)) + sizeof(xc_allocator_bestfit_block_t))
+	/* requires at least the header and 1 tail block */
+	if (size < MINSIZE) {
+		fprintf(stderr, "xc_allocator_bestfit_init requires %lu bytes at least\n", (unsigned long) MINSIZE);
+		return NULL;
+	}
+	TRACE("size=%lu", size);
+	allocator->shm = shm;
+	allocator->size = size;
+	allocator->avail = size - MINSIZE;
+
+	/* pointer to first block, right after ALIGNed header */
+	b = allocator->headblock;
+	xc_block_setup(b, 0, (xc_allocator_bestfit_block_t *) PADD(allocator, ALIGN(sizeof(xc_allocator_bestfit_t))));
+
+	/* first block*/
+	b = b->next;
+	xc_block_setup(b, allocator->avail, 0);
+#undef MINSIZE
+
+	return allocator;
+}
+/* }}} */
+static XC_ALLOCATOR_DESTROY(xc_allocator_bestfit_destroy) /* {{{ */
+{
+}
+/* }}} */
+
+static xc_allocator_vtable_t xc_allocator_bestfit = XC_ALLOCATOR_VTABLE(allocator_bestfit);
+void xc_allocator_bestfit_register() /* {{{ */
+{
+	if (xc_allocator_register("bestfit", &xc_allocator_bestfit) == 0) {
+		zend_error(E_ERROR, "XCache: failed to register allocator 'bestfit'");
+	}
+}
+/* }}} */
Index: /tags/3.0.0-rc1/devel/make
===================================================================
--- /tags/3.0.0-rc1/devel/make	(revision 998)
+++ /tags/3.0.0-rc1/devel/make	(revision 998)
@@ -0,0 +1,2 @@
+#!/bin/bash
+exec ./run make "$@"
Index: /tags/3.0.0-rc1/devel/graph/cached_compile.dot
===================================================================
--- /tags/3.0.0-rc1/devel/graph/cached_compile.dot	(revision 311)
+++ /tags/3.0.0-rc1/devel/graph/cached_compile.dot	(revision 311)
@@ -0,0 +1,31 @@
+digraph tree {
+	subgraph cluster_compiling {
+		label="compiling";
+		php_compile;
+		php_store;
+		entry_store;
+	}
+	error [color=red];
+	origin_compile [color=red]
+
+	begin -> origin_compile [label="compiling", color=red];
+
+	begin -> entry_init_key -> entry_lookup;
+	edge [label=hit, color=blue]
+	entry_lookup -> restore;
+	php_lookup -> entry_store;
+	edge [label=miss, color=green]
+	entry_lookup -> md5_init;
+	md5_init -> php_lookup;
+	php_lookup -> php_compile;
+
+	edge [label="", color=""]
+	php_lookup -> origin_compile [label="miss but compiling", color=red];
+	php_compile -> php_store -> entry_store -> restore;
+
+	edge [color=red];
+	md5_init -> error;
+	php_compile -> error;
+	php_store -> error;
+	entry_store -> error;
+}
Index: /tags/3.0.0-rc1/devel/gen_const_string_opcodes.awk
===================================================================
--- /tags/3.0.0-rc1/devel/gen_const_string_opcodes.awk	(revision 982)
+++ /tags/3.0.0-rc1/devel/gen_const_string_opcodes.awk	(revision 982)
@@ -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 + 1;
+	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/3.0.0-rc1/devel/run
===================================================================
--- /tags/3.0.0-rc1/devel/run	(revision 1141)
+++ /tags/3.0.0-rc1/devel/run	(revision 1141)
@@ -0,0 +1,359 @@
+#!/bin/bash
+# this script is for developers only
+
+set -e
+MAKE=/usr/bin/make
+
+true() { # {{{1
+	return 0
+}
+
+hi() { # {{{1
+	colors=(4 2 3 5 6 7 8 9)
+	re=()
+	i=0
+	for r in "$@"; do
+		((color=$i % ${#colors[@]})) || true
+		color=${colors[$color]}
+		r="${r/\#/\\#}"
+		r="s#$r#[4${color}m[31m\0[0m#g"
+		re[$i]="-e$r"
+		((i=i+1))
+	done
+	sed -ur "${re[@]}"
+}
+hiecho() { # {{{1
+	echo "[32m""$@""[0m"
+}
+
+# }}}
+
+stopfpm() { # {{{1
+	if [[ -f $1 ]]; then
+		local pid=`cat $1 2>/dev/null || true`
+		if [[ $pid -gt 0 ]]; then
+			hiecho Stopping fpm $pid @ $1
+			kill $pid || true
+		fi
+	fi
+}
+
+xtest() { # {{{1
+	$MAKE -f devel/test.mak
+}
+
+prep() { # {{{1
+	$MAKE -f devel/prepare.mak "$@"
+}
+
+mergepo() { # {{{1
+	prep
+	local i
+	find htdocs -iname '*.po' | while read -r i; do
+		if [[ -f $i-merged ]]; then
+			mv $i-merged $i
+		fi
+	done
+}
+
+po2php() { # {{{1
+	mergepo
+
+	local phpfile
+	find htdocs -iname '*.po' | while read -r i; do
+		phpfile=${i/.po/.php}
+		devel/po2php.awk < $i > $phpfile.tmp
+		mv $phpfile.tmp $phpfile
+	done
+}
+
+updatedeps() { # {{{1
+	pwd=$(readlink -f "$(pwd)")
+	builddir=$(readlink -f ../trunk-php5-debug-zts)
+	if [[ -z $builddir ]]; then
+		hiecho required ../trunk-php5-debug-zts not found
+		return 1
+	fi
+	find . -iname \*.c | sort | while read -r sourceFile; do
+		sourceFile=${sourceFile#./}
+		{
+			case "$sourceFile" in
+			includes.c)
+				echo '$(XCACHE_INCLUDES_I)'
+				;;
+			esac
+			echo '$(builddir)/'${sourceFile%.c}.lo:
+			hiecho "Checking $sourceFile ..." >&2
+			for dependency in $(gcc -MM $sourceFile -I$HOME/test/php5-debug-zts/include/php/{,main,Zend,TSRM} -I. -I${builddir} -MG | sed 's#.*:##g' | sed 's#\\##g'); do
+				dependency=$(readlink -f "$dependency")
+				case "$dependency" in
+				$pwd/*)
+					dependency=${dependency#$pwd/}
+					;;
+				$builddir/*)
+					dependency="\$(builddir)/"${dependency#$builddir/}
+					;;
+				esac
+
+				case "$dependency" in
+				/*) ;;
+				$sourceFile) ;;
+
+				\$\(builddir\)/xc_processor.h)
+					echo '$(XCACHE_PROC_H)'
+					;;
+				\$\(builddir\)/xc_processor.c.h)
+					echo '$(XCACHE_PROC_C)'
+					;;
+				*)
+					if [[ -r $dependency ]]; then
+						echo '$(srcdir)/'$dependency
+					else
+						hiecho "$dependency not found" >&2
+					fi
+				esac
+			done | sort | uniq
+		} | xargs
+	done > Makefile.frag.deps
+}
+# }}}1
+
+hiecho "Loading config devel/run.cfg"
+. devel/run.cfg
+PHPSDIR=${PHPSDIR:-$HOME/test}
+
+if [[ $# -eq 0 ]]; then
+	set -- $action "${args[@]}"
+fi
+
+# devel actions
+case "$1" in
+prep*) shift; prep "$@"; exit;;
+tags) shift; rm -f tags; prep tags "$@"; exit;;
+po2php) po2php; exit;;
+mergepo) mergepo; exit;;
+dep*) updatedeps; exit;;
+xtest) xtest; exit;;
+stopfpm) stopfpm devel.pid; exit;;
+esac
+
+basename=$(basename $(pwd))
+case "$basename" in
+*-*)
+	# in build dir, starts from src dir
+	dirs="$basename"
+	xcachesrcdir=../${basename%%-*}
+	cd $xcachesrcdir
+	;;
+*)
+	# in src dir
+	dirs=${dirs:-php5-debug-zts}
+	xcachesrcdir=../$basename
+	;;
+esac
+
+touch devel.pid
+svn propget svn:ignore . > .svnignore
+
+# ==========================
+
+do_phpize() { # {{{1
+	if [[ ! -x $PHPSDIR/$phpbasename/bin/phpize ]]; then
+		hiecho $PHPSDIR/$phpbasename/bin/phpize not found
+		exit
+	fi
+	export PATH=$PHPSDIR/$phpbasename/bin:$PATH
+	local pedantic=
+	case $phpbasename in
+	php5|php5.4) pedantic=-pedantic-errors;;
+	*) pedantic=-pedantic;;
+	esac
+	phpize --clean \
+	&& phpize \
+	&& CFLAGS="-g -O0 $pedanti -Wno-variadic-macros -Wno-long-long -Wall -Wno-unused-parameter -Wno-unused-function -W -Wshadow -Werror=implicit-function-declaration -std=c89 -D_GNU_SOURCE -D_POSIX_SOURCE -Dinline=" ./configure \
+		--enable-xcache-cacher \
+		--enable-xcache-optimizer \
+		--enable-xcache-encoder \
+		--enable-xcache-decoder \
+		--enable-xcache-disassembler \
+		--enable-xcache-coverager \
+		--enable-xcache-test \
+		--enable-xcache-constant
+}
+do_make() { # {{{1
+	if [[ ! -f Makefile ]]; then
+		do_phpize
+	fi
+	LANG=C $MAKE $MAKEOPTS "$@" 2>&1 \
+	| sed -ur \
+		-e 's#Werror=implicit-function-declaration#We/rror=i/mplicit-function-declaration#' \
+		-e 's#-pedantic-errors#-pedantic-e/rrors#' \
+		-e 's#\./xc_processor\.h#'$PWD'/xc_processor.h#' \
+		-e 's#\./xc_processor\.c\.h#'$PWD'/xc_processor.c.h#' \
+	| hi error implicit warn FAIL
+	ret=${PIPESTATUS[0]}
+	if [[ $ret -ne 0 ]]; then
+		exit $ret
+	fi
+}
+cleanfpm() { # {{{1
+	echo
+	stopfpm $pidfile
+}
+# }}}
+run() {
+	pidfile=$xcachesrcdir/devel.pid
+
+	# prepare {{{1
+	case "$1" in
+	phpize)
+		if [[ -r Makefile ]]; then
+			$MAKE xcachesvnclean || true
+		fi
+		;;
+	esac
+
+	rm -f php-src
+	find -L . -type l | xargs rm -fv
+	lndir "$xcachesrcdir" >/dev/null || true
+	find . -iname .\*.swp | xargs rm -f
+	ln -snf ~/src/php/$phpbasename php-src
+	for i in ~/src/php/$phpbasename/sapi/cgi/php{,-cgi}; do
+		if [[ -r $i ]]; then
+			ln -snf "$i" php-cgi
+		fi
+	done
+	ln -snf ~/src/php/$phpbasename/sapi/cli/php php-cli
+	ln -snf ~/src/php/$phpbasename/sapi/fpm/php-fpm php-fpm
+
+	case "$1" in
+	phpize) do_phpize; exit;;
+	make) shift; do_make "$@"; exit;;
+	*) do_make;;
+	esac
+	# }}}1
+
+	if [[ -z $1 ]]; then
+		set -- devel.php
+	fi
+
+	cmd=()
+	tracer=()
+
+	# run utils {{{1
+	case "$1" in
+	dc)
+		shift
+		./php-cli -c devel.ini ./bin/phpdc.phpr $@ | tee decompiled.php
+		return
+		;;
+	dop)
+		shift
+		./php-cli -c devel.ini ./bin/phpdop.phpr $@
+		return
+		;;
+	retest)
+		shift
+		$MAKE xcachetest "$@" TESTS="`grep '^/.*\.phpt$' php_test_results_*.txt | uniq | xargs`"
+		return
+		;;
+	test)
+		shift
+		case "$1" in
+		*.phpt)
+			$MAKE xcachetest TEST_ARGS=-v TESTS="$*"
+			return
+			;;
+		*/)
+			$MAKE xcachetest TESTS="$*"
+			return
+			;;
+		*)
+			$MAKE xcachetest
+			return
+			;;
+		esac
+		;;
+	esac
+	# }}}
+	# pick tracer {{{1
+	case "$1" in
+	ltr*)
+		shift
+		export USE_ZEND_ALLOC=0
+		tracer=(ltrace -s1024 -e malloc,realloc,free,write)
+		;;
+	str*)
+		shift
+		tracer=(strace -s1024 -T)
+		;;
+	gdb)
+		shift
+		#USE_ZEND_ALLOC=0
+		tracer=(gdb --args)
+		;;
+	val*)
+		shift
+		export USE_ZEND_ALLOC=0
+		tracer=(valgrind --gen-suppressions=all)
+		;;
+	esac
+
+	# pick sapi {{{1
+	case "$basename" in
+	*-apache1*)
+		cmd=($HOME/apache1/bin/httpd -X)
+		;;
+	*-apache*)
+		echo "Don't know how to run apache"
+		exit 1
+		;;
+	*)
+		case "$1" in
+		fcgi)
+			shift
+			cmd=(./php-cgi -q -c devel.ini)
+			set -- -b 1026
+			;;
+		fpm)
+			shift
+			cmd=(./php-fpm -c devel.ini -y devel.fpm -g $(readlink -f $pidfile))
+			set --
+			;;
+		*)
+			cmd=(./php-cgi -q -c devel.ini)
+			;;
+		esac
+
+		"${cmd[@]}" -v || true
+	esac
+
+	# run {{{1
+	commandLine=("${tracer[@]}" "${cmd[@]}" "$@")
+
+	case "${cmd[0]}" in
+	*php-fpm*)
+		stopfpm
+		hiecho Starting fpm "${commandLine[@]}" ...
+		"${commandLine[@]}"
+		echo -n "Ctrl-C to stop"
+		trap cleanfpm SIGINT SIGTERM exit
+		cat > /dev/null || true
+		stopfpm
+		;;
+	*)
+		hiecho "${commandLine[@]}"
+		"${commandLine[@]}"
+		;;
+	esac
+	# }}}
+}
+
+for phpbasename in "${dirs[@]}"; do
+	mkdir -p ../${basename}-${phpbasename}
+	cd ../${basename}-${phpbasename} || exit
+	lndir ${xcachesrcdir} >/dev/null || true
+
+	pwd
+	run "$@"
+done
Index: /tags/3.0.0-rc1/devel/prepare.mak
===================================================================
--- /tags/3.0.0-rc1/devel/prepare.mak	(revision 1103)
+++ /tags/3.0.0-rc1/devel/prepare.mak	(revision 1103)
@@ -0,0 +1,136 @@
+CTAGS=$(shell which ctags 2>/dev/null || which exuberant-ctags 2>/dev/null)
+AWK=$(shell which gawk 2>/dev/null || which awk 2>/dev/null)
+
+include devel/prepare.cfg
+
+.PHONY: dummy
+.PHONY: all
+all: xcache/xc_opcode_spec_def.h xc_const_string tags po
+
+.PHONY: clean
+clean: clean_xc_const_string clean_po
+	rm -f tags xcache/xc_opcode_spec_def.h
+
+.PHONY: clean_xc_const_string
+clean_xc_const_string:
+	rm -f xcache/xc_const_string_opcodes_php*.h
+
+.PHONY: xc_const_string
+xc_const_string: \
+	xcache/xc_const_string_opcodes_php4.x.h \
+	xcache/xc_const_string_opcodes_php5.0.h \
+	xcache/xc_const_string_opcodes_php5.1.h \
+	xcache/xc_const_string_opcodes_php5.3.h \
+	xcache/xc_const_string_opcodes_php5.4.h \
+	xcache/xc_const_string_opcodes_php6.x.h
+
+ifeq (${EA_DIR},)
+xcache/xc_opcode_spec_def.h: dummy
+	@echo "Skipped $@: EA_DIR not set"
+else
+xcache/xc_opcode_spec_def.h: ${EA_DIR}/opcodes.c
+	$(AWK) -f ./devel/gen_xc_opcode_spec.awk < "$<" > "$@".tmp
+	mv "$@".tmp "$@"
+endif
+
+ifeq (${PHP4_x_DIR},)
+xcache/xc_const_string_opcodes_php4.x.h: dummy
+	@echo "Skipped $@: PHP_4_x_DIR not set"
+else
+xcache/xc_const_string_opcodes_php4.x.h: ${PHP4_x_DIR}/Zend/zend_compile.h
+	$(AWK) -f ./devel/gen_const_string_opcodes.awk < "$<" > "$@.tmp"
+	mv "$@.tmp" "$@"
+endif
+
+ifeq (${PHP5_0_DIR},)
+xcache/xc_const_string_opcodes_php5.0.h: dummy
+	@echo "Skipped $@: PHP_5_0_DIR not set"
+else
+xcache/xc_const_string_opcodes_php5.0.h: ${PHP5_0_DIR}/Zend/zend_compile.h
+	$(AWK) -f ./devel/gen_const_string_opcodes.awk < "$<" > "$@.tmp"
+	mv "$@.tmp" "$@"
+endif
+
+ifeq (${PHP5_1_DIR},)
+xcache/xc_const_string_opcodes_php5.1.h: dummy
+	@echo "Skipped $@: PHP_5_1_DIR not set"
+else
+xcache/xc_const_string_opcodes_php5.1.h: ${PHP5_1_DIR}/Zend/zend_vm_def.h
+	$(AWK) -f ./devel/gen_const_string_opcodes.awk < "$<" > "$@.tmp"
+	mv "$@.tmp" "$@"
+endif
+
+ifeq (${PHP5_3_DIR},)
+xcache/xc_const_string_opcodes_php5.3.h: dummy
+	@echo "Skipped $@: PHP_5_3_DIR not set"
+else
+xcache/xc_const_string_opcodes_php5.3.h: ${PHP5_3_DIR}/Zend/zend_vm_def.h
+	$(AWK) -f ./devel/gen_const_string_opcodes.awk < "$<" > "$@.tmp"
+	mv "$@.tmp" "$@"
+endif
+
+ifeq (${PHP5_4_DIR},)
+xcache/xc_const_string_opcodes_php5.4.h: dummy
+	@echo "Skipped $@: PHP_5_4_DIR not set"
+else
+xcache/xc_const_string_opcodes_php5.4.h: ${PHP5_4_DIR}/Zend/zend_vm_def.h
+	$(AWK) -f ./devel/gen_const_string_opcodes.awk < "$<" > "$@.tmp"
+	mv "$@.tmp" "$@"
+endif
+
+ifeq (${PHP6_x_DIR},)
+xcache/xc_const_string_opcodes_php6.x.h: dummy
+	@echo "Skipped $@: PHP_6_x_DIR not set"
+else
+xcache/xc_const_string_opcodes_php6.x.h: ${PHP6_x_DIR}/Zend/zend_vm_def.h
+	$(AWK) -f ./devel/gen_const_string_opcodes.awk < "$<" > "$@.tmp"
+	mv "$@.tmp" "$@"
+endif
+
+ifeq (${PHP_DEVEL_DIR},)
+tags:
+	echo "* Making tags without php source files"
+	"$(CTAGS)" -R .
+else
+tags:
+	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"
+endif
+
+.PHONY: po
+define htdocspo
+  po: \
+	htdocs/$(1)/lang/en.po \
+	htdocs/$(1)/lang/en.po-merged \
+	htdocs/$(1)/lang/zh-simplified.po-merged \
+	htdocs/$(1)/lang/zh-simplified.po \
+	htdocs/$(1)/lang/zh-traditional.po \
+	htdocs/$(1)/lang/zh-traditional.po-merged
+
+  htdocs/$(1)/lang/%.po-merged: htdocs/$(1)/lang/%.po htdocs/$(1)/lang/$(1).pot
+	msgmerge -o "$$@".tmp $$^
+	mv "$$@".tmp "$$@"
+
+  htdocs/$(1)/lang/%.po:
+	touch "$$@"
+
+  htdocs/$(1)/lang/$(1).pot:
+	xgettext --keyword=_T --keyword=N_ --from-code=UTF-8 -F -D htdocs/$(1)/ $$(subst htdocs/$(1)/,,$$^) -o "$$@".tmp
+	mv "$$@".tmp "$$@"
+
+  htdocs/$(1)/lang/$(1).pot: $(shell find htdocs/$(1) -type f | grep php | grep -v lang | grep -v config | grep -vF .swp)
+
+endef
+
+$(eval $(call htdocspo,cacher))
+$(eval $(call htdocspo,common))
+$(eval $(call htdocspo,coverager))
+$(eval $(call htdocspo,diagnosis))
+
+.PHONY: clean_po
+clean_po: clean_pot
+	rm -f htdocs/*/lang/*.po-merged
+
+.PHONY: clean_pot
+clean_pot:
+	rm -f htdocs/*/lang/*.pot
Index: /tags/3.0.0-rc1/devel/prepare.cfg.example
===================================================================
--- /tags/3.0.0-rc1/devel/prepare.cfg.example	(revision 1095)
+++ /tags/3.0.0-rc1/devel/prepare.cfg.example	(revision 1095)
@@ -0,0 +1,12 @@
+# copy this file as prepare.cfg before modifying
+PHP4_x_DIR=
+PHP5_0_DIR=
+PHP5_1_DIR=
+PHP5_3_DIR=
+PHP5_4_DIR=
+PHP6_x_DIR=
+
+PHP_DEVEL_DIR=
+
+# path to eaccelerator source dir
+EA_DIR=
Index: /tags/3.0.0-rc1/devel/test.mak
===================================================================
--- /tags/3.0.0-rc1/devel/test.mak	(revision 1135)
+++ /tags/3.0.0-rc1/devel/test.mak	(revision 1135)
@@ -0,0 +1,18 @@
+#! /usr/bin/make -f
+
+EXES=allocator_test
+OBJS=allocator.o
+CC=gcc
+CFLAGS=-g -O0 -I. -D TEST -D HAVE_XCACHE_TEST -Wall
+TEST=valgrind
+
+all: allocator
+
+allocator_test: xcache/xc_allocator.h xcache/xc_allocator.c xcache/xc_malloc.c xcache/xc_allocator_bestfit.c util/xc_trace.c util/xc_trace.h
+	$(CC) $(CFLAGS) -o allocator_test xcache/xc_allocator.c xcache/xc_malloc.c xcache/xc_allocator_bestfit.c util/xc_trace.c
+	
+allocator: allocator_test
+	$(TEST) ./allocator_test
+
+clean:
+	rm -f $(OBJS) $(EXES)
Index: /tags/3.0.0-rc1/devel/gen_xc_opcode_spec.awk
===================================================================
--- /tags/3.0.0-rc1/devel/gen_xc_opcode_spec.awk	(revision 982)
+++ /tags/3.0.0-rc1/devel/gen_xc_opcode_spec.awk	(revision 982)
@@ -0,0 +1,46 @@
+#! /usr/bin/awk -f
+# vim:ts=4:sw=4
+# process eaccelerator/opcodes.c
+BEGIN {
+	FS=" "
+	max = 0;
+	started = 0
+}
+
+/OPDEF/ {
+	if (started) {
+		name = "";
+		if (match($0, /"([^"]+)"/, m)) { 
+			name = m[1]; 
+		} 
+		sub(/"[^"]*"/, "");
+		if (!match($0, /EXT_([^ |]+).*OP[1S]_([^ |]+).*OP2_([^ |]+).*RES_([^ |)]+).*/, array)) {
+			print "error" $0
+			exit
+		}
+		id = "";
+		if (match($0, /\/\* *([0-9]+) *\*\//, comments)) {
+			id = comments[1];
+		}
+		printf "\tOPSPEC(%10s, %10s, %10s, %10s) /* %s %-30s */\n", array[1], array[2], array[3], array[4], id, name;
+		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/3.0.0-rc1/devel/lsnewini
===================================================================
--- /tags/3.0.0-rc1/devel/lsnewini	(revision 1005)
+++ /tags/3.0.0-rc1/devel/lsnewini	(revision 1005)
@@ -0,0 +1,8 @@
+#!/bin/sh
+
+tmp1=`mktemp`
+tmp2=`mktemp`
+grep -F '=' xcache.ini |grep -v '^;' | sed -r -e 's# *=.*##' | sort > $tmp2
+grep 'PHP_INI.*("' *.c | sed -r -e 's#^[^"]*"([^"]*)".*#\1#' | sort > $tmp1
+diff -iu $tmp2 $tmp1 |grep '^[-+]'
+rm -f $tmp1 $tmp2
Index: /tags/3.0.0-rc1/devel/po2php.awk
===================================================================
--- /tags/3.0.0-rc1/devel/po2php.awk	(revision 1103)
+++ /tags/3.0.0-rc1/devel/po2php.awk	(revision 1103)
@@ -0,0 +1,67 @@
+#!/usr/bin/awk -f
+BEGIN {
+	print "<?php";
+	print "// auto generated, do not modify";
+	print "$strings += array(";
+}
+
+function flushOut() {
+	if (section) {
+		if (section == "msgstr") {
+			if (msgid == "") {
+			}
+			else if (msgstr == "") {
+			}
+			else {
+				print "\t\t\""msgid"\"";
+				print "\t\t=> \""msgstr"\",";
+			}
+		}
+		else {
+			print "unexpected section " section;
+			exit 1;
+		}
+		section = null;
+	}
+}
+
+/^msgid ".*"$/ {
+	$0 = gensub(/^msgid "(.*)"$/, "\\1", $0);
+
+	section = "msgid";
+	msgid = $0;
+	next;
+}
+/^msgstr ".*"$/ {
+	$0 = gensub(/^msgstr "(.*)"$/, "\\1", $0);
+
+	section = "msgstr";
+	msgstr = $0;
+	next;
+}
+/^".*"$/ {
+	$0 = gensub(/^"(.*)"$/, "\\1", $0);
+	if (section == "msgid") {
+		msgid = msgid $0;
+	}
+	else {
+		msgstr = msgstr $0;
+	}
+	next;
+}
+/^$/ {
+	flushOut();
+	next;
+}
+/^#/ {
+	next;
+}
+/./ {
+	print "error", $0;
+	exit 1;
+}
+END {
+	flushOut();
+	print "\t\t);";
+	print "";
+}
Index: /tags/3.0.0-rc1/tests/xcache_is_autoglobal.phpt
===================================================================
--- /tags/3.0.0-rc1/tests/xcache_is_autoglobal.phpt	(revision 861)
+++ /tags/3.0.0-rc1/tests/xcache_is_autoglobal.phpt	(revision 861)
@@ -0,0 +1,8 @@
+--TEST--
+xcache_is_autoglobal
+--FILE--
+<?php
+var_dump(xcache_is_autoglobal("GLOBALS"));
+?>
+--EXPECT--
+bool(true)
Index: /tags/3.0.0-rc1/tests/xcache_var.phpt
===================================================================
--- /tags/3.0.0-rc1/tests/xcache_var.phpt	(revision 858)
+++ /tags/3.0.0-rc1/tests/xcache_var.phpt	(revision 858)
@@ -0,0 +1,25 @@
+--TEST--
+xcache_set/get test
+--FILE--
+<?php
+var_dump(xcache_isset("a"));
+var_dump(xcache_set("a", 1));
+var_dump(xcache_get("a"));
+var_dump(xcache_isset("a"));
+var_dump(xcache_inc("a", 10));
+var_dump(xcache_get("a"));
+var_dump(xcache_dec("a", 5));
+var_dump(xcache_get("a"));
+xcache_unset("a");
+var_dump(xcache_isset("a"));
+?>
+--EXPECT--
+bool(false)
+bool(true)
+int(1)
+bool(true)
+int(11)
+int(11)
+int(6)
+int(6)
+bool(false)
Index: /tags/3.0.0-rc1/tests/include-skipif.inc
===================================================================
--- /tags/3.0.0-rc1/tests/include-skipif.inc	(revision 1000)
+++ /tags/3.0.0-rc1/tests/include-skipif.inc	(revision 1000)
@@ -0,0 +1,5 @@
+<?php
+if (version_compare(PHP_VERSION, '5.3.0', '<')) {
+	die('skip __DIR__ not supported in this php version');
+}
+?>
Index: /tags/3.0.0-rc1/tests/sub-a.inc
===================================================================
--- /tags/3.0.0-rc1/tests/sub-a.inc	(revision 1000)
+++ /tags/3.0.0-rc1/tests/sub-a.inc	(revision 1000)
@@ -0,0 +1,5 @@
+<?php
+
+echo __DIR__, PHP_EOL;
+echo __FILE__, PHP_EOL;
+
Index: /tags/3.0.0-rc1/tests/sub-b.inc
===================================================================
--- /tags/3.0.0-rc1/tests/sub-b.inc	(revision 1000)
+++ /tags/3.0.0-rc1/tests/sub-b.inc	(revision 1000)
@@ -0,0 +1,5 @@
+<?php
+
+echo __DIR__, PHP_EOL;
+echo __FILE__, PHP_EOL;
+
Index: /tags/3.0.0-rc1/tests/xcache_include_relative_cwd.phpt
===================================================================
--- /tags/3.0.0-rc1/tests/xcache_include_relative_cwd.phpt	(revision 1000)
+++ /tags/3.0.0-rc1/tests/xcache_include_relative_cwd.phpt	(revision 1000)
@@ -0,0 +1,17 @@
+--TEST--
+include relative to current working dir
+--SKIPIF--
+<?php
+require("include-skipif.inc");
+?>
+--FILE--
+<?php
+chdir(__DIR__);
+include "./sub-a.inc";
+include "./sub-b.inc";
+?>
+--EXPECTF--
+%stests
+%stests%ssub-a.inc
+%stests
+%stests%ssub-b.inc
Index: /tags/3.0.0-rc1/tests/xcache_include_relative_file.phpt
===================================================================
--- /tags/3.0.0-rc1/tests/xcache_include_relative_file.phpt	(revision 1000)
+++ /tags/3.0.0-rc1/tests/xcache_include_relative_file.phpt	(revision 1000)
@@ -0,0 +1,16 @@
+--TEST--
+include relative to current file
+--SKIPIF--
+<?php
+require("include-skipif.inc");
+?>
+--FILE--
+<?php
+include "sub-a.inc";
+include "sub-b.inc";
+?>
+--EXPECTF--
+%stests
+%stests%ssub-a.inc
+%stests
+%stests%ssub-b.inc
Index: /tags/3.0.0-rc1/tests/xcache_include_absolute.phpt
===================================================================
--- /tags/3.0.0-rc1/tests/xcache_include_absolute.phpt	(revision 1000)
+++ /tags/3.0.0-rc1/tests/xcache_include_absolute.phpt	(revision 1000)
@@ -0,0 +1,16 @@
+--TEST--
+include absolute path
+--SKIPIF--
+<?php
+require("include-skipif.inc");
+?>
+--FILE--
+<?php
+include __DIR__ . "/sub-a.inc";
+include __DIR__ . "/sub-b.inc";
+?>
+--EXPECTF--
+%stests
+%stests%ssub-a.inc
+%stests
+%stests%ssub-b.inc
Index: /tags/3.0.0-rc1/mod_decoder/xc_decoder.c
===================================================================
--- /tags/3.0.0-rc1/mod_decoder/xc_decoder.c	(revision 1113)
+++ /tags/3.0.0-rc1/mod_decoder/xc_decoder.c	(revision 1113)
@@ -0,0 +1,1 @@
+static void dummy() { }
Index: /tags/3.0.0-rc1/INSTALL
===================================================================
--- /tags/3.0.0-rc1/INSTALL	(revision 605)
+++ /tags/3.0.0-rc1/INSTALL	(revision 605)
@@ -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/3.0.0-rc1/lib/Decompiler.class.php
===================================================================
--- /tags/3.0.0-rc1/lib/Decompiler.class.php	(revision 982)
+++ /tags/3.0.0-rc1/lib/Decompiler.class.php	(revision 982)
@@ -0,0 +1,2817 @@
+<?php
+
+define('INDENT', "\t");
+ini_set('error_reporting', E_ALL);
+
+function color($str, $color = 33)
+{
+	return "\x1B[{$color}m$str\x1B[0m";
+}
+
+function str($code, $indent = '') // {{{
+{
+	if (is_array($code)) {
+		$array = array();
+		foreach ($code as $key => $value) {
+			$array[$key] = str($value, $indent);
+		}
+		return $array;
+	}
+	if (is_object($code)) {
+		$code = foldToCode($code, $indent);
+		return $code->toCode($indent);
+	}
+
+	return (string) $code;
+}
+// }}}
+function foldToCode($src, $indent = '') // {{{ wrap or rewrap anything to Decompiler_Code
+{
+	if (is_array($indent)) {
+		$indent = $indent['indent'];
+	}
+
+	if (!is_object($src)) {
+		return new Decompiler_Code($src);
+	}
+
+	if (!method_exists($src, 'toCode')) {
+		var_dump($src);
+		exit('no toCode');
+	}
+	if (get_class($src) != 'Decompiler_Code') {
+		// rewrap it
+		$src = new Decompiler_Code($src->toCode($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_a($value, 'Decompiler_Object')) {
+		// use as is
+	}
+	else if (is_array($value)) {
+		$value = new Decompiler_ConstArray($value);
+	}
+	else {
+		$value = new Decompiler_Value($value);
+	}
+	return $value;
+}
+// }}}
+function unquoteName_($str, $asVariableName, $indent = '') // {{{
+{
+	$str = str($str, $indent);
+	if (preg_match("!^'[\\w_][\\w\\d_\\\\]*'\$!", $str)) {
+		return str_replace('\\\\', '\\', substr($str, 1, -1));
+	}
+	else if ($asVariableName) {
+		return "{" . $str . "}";
+	}
+	else {
+		return $str;
+	}
+}
+// }}}
+function unquoteVariableName($str, $indent = '') // {{{
+{
+	return unquoteName_($str, true, $indent);
+}
+// }}}
+function unquoteName($str, $indent = '') // {{{
+{
+	return unquoteName_($str, false, $indent);
+}
+// }}}
+class Decompiler_Object // {{{
+{
+}
+// }}}
+class Decompiler_Value extends Decompiler_Object // {{{
+{
+	var $value;
+
+	function Decompiler_Value($value = null)
+	{
+		$this->value = $value;
+	}
+
+	function toCode($indent)
+	{
+		$code = var_export($this->value, true);
+		if (gettype($this->value) == 'string') {
+			switch ($this->value) {
+			case "\r":
+				return '"\\r"';
+			case "\n":
+				return '"\\n"';
+			case "\r\n":
+				return '"\\r\\n"';
+			}
+			$code = str_replace("\r\n", '\' . "\\r\\n" . \'', $code);
+			$code = str_replace("\r", '\' . "\\r" . \'', $code);
+			$code = str_replace("\n", '\' . "\\n" . \'', $code);
+		}
+		return $code;
+	}
+}
+// }}}
+class Decompiler_Code extends Decompiler_Object // {{{
+{
+	var $src;
+
+	function Decompiler_Code($src)
+	{
+		assert('isset($src)');
+		$this->src = $src;
+	}
+
+	function toCode($indent)
+	{
+		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 toCode($indent)
+	{
+		$opstr = $this->parent->binops[$this->opc];
+
+		if (is_a($this->op1, 'Decompiler_TriOp') || is_a($this->op1, 'Decompiler_Binop') && $this->op1->opc != $this->opc) {
+			$op1 = "(" . str($this->op1, $indent) . ")";
+		}
+		else {
+			$op1 = $this->op1;
+		}
+
+		if (is_a($this->op2, 'Decompiler_TriOp') || is_a($this->op2, 'Decompiler_Binop') && $this->op2->opc != $this->opc && substr($opstr, -1) != '=') {
+			$op2 = "(" . str($this->op2, $indent) . ")";
+		}
+		else {
+			$op2 = $this->op2;
+		}
+
+		if (str($op1) == '0' && ($this->opc == XC_ADD || $this->opc == XC_SUB)) {
+			return $opstr . str($op2, $indent);
+		}
+
+		return str($op1, $indent) . ' ' . $opstr . ($this->opc == XC_ASSIGN_REF ? '' : ' ') . str($op2, $indent);
+	}
+}
+// }}}
+class Decompiler_TriOp extends Decompiler_Code // {{{
+{
+	var $condition;
+	var $trueValue;
+	var $falseValue;
+
+	function Decompiler_TriOp($condition, $trueValue, $falseValue)
+	{
+		$this->condition = $condition;
+		$this->trueValue = $trueValue;
+		$this->falseValue = $falseValue;
+	}
+
+	function toCode($indent)
+	{
+		$trueValue = $this->trueValue;
+		if (is_a($this->trueValue, 'Decompiler_TriOp')) {
+			$trueValue = "(" . str($trueValue, $indent) . ")";
+		}
+		$falseValue = $this->falseValue;
+		if (is_a($this->falseValue, 'Decompiler_TriOp')) {
+			$falseValue = "(" . str($falseValue, $indent) . ")";
+		}
+
+		return str($this->condition) . ' ? ' . str($trueValue) . ' : ' . str($falseValue);
+	}
+}
+// }}}
+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 toCode($indent)
+	{
+		switch ($this->fetchType) {
+		case ZEND_FETCH_LOCAL:
+			return '$' . substr($this->src, 1, -1);
+		case ZEND_FETCH_STATIC:
+			if (ZEND_ENGINE_2_3) {
+				// closure local variable?
+				return str($this->src);
+			}
+			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 toCode($indent)
+	{
+		return $this->obj->toCode($indent);
+	}
+}
+// }}}
+class Decompiler_Dim extends Decompiler_Value // {{{
+{
+	var $offsets = array();
+	var $isLast = false;
+	var $isObject = false;
+	var $assign = null;
+
+	function toCode($indent)
+	{
+		if (is_a($this->value, 'Decompiler_ListBox')) {
+			$exp = str($this->value->obj->src, $indent);
+		}
+		else {
+			$exp = str($this->value, $indent);
+		}
+		$last = count($this->offsets) - 1;
+		foreach ($this->offsets as $i => $dim) {
+			if ($this->isObject && $i == $last) {
+				$exp .= '->' . unquoteVariableName($dim, $indent);
+			}
+			else {
+				$exp .= '[' . str($dim, $indent) . ']';
+			}
+		}
+		return $exp;
+	}
+}
+// }}}
+class Decompiler_DimBox extends Decompiler_Box // {{{
+{
+}
+// }}}
+class Decompiler_List extends Decompiler_Code // {{{
+{
+	var $src;
+	var $dims = array();
+	var $everLocked = false;
+
+	function toCode($indent)
+	{
+		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, $indent);
+			}
+			return str($this->dims[0]->assign, $indent) . ' = ' . str($dim, $indent);
+		}
+		/* flatten dims */
+		$assigns = array();
+		foreach ($this->dims as $dim) {
+			$assign = &$assigns;
+			foreach ($dim->offsets as $offset) {
+				$assign = &$assign[$offset];
+			}
+			$assign = foldToCode($dim->assign, $indent);
+		}
+		return str($this->toList($assigns)) . ' = ' . str($this->src, $indent);
+	}
+
+	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 // {{{
+{
+	// emenets
+	function Decompiler_Array()
+	{
+		$this->value = array();
+	}
+
+	function toCode($indent)
+	{
+		$subindent = $indent . INDENT;
+
+		$elementsCode = array();
+		$index = 0;
+		foreach ($this->value as $element) {
+			list($key, $value) = $element;
+			if (!isset($key)) {
+				$key = $index++;
+			}
+			$elementsCode[] = array(str($key, $subindent), str($value, $subindent), $key, $value);
+		}
+
+		$exp = "array(";
+		$indent = $indent . INDENT;
+		$assocWidth = 0;
+		$multiline = 0;
+		$i = 0;
+		foreach ($elementsCode as $element) {
+			list($keyCode, $valueCode) = $element;
+			if ((string) $i !== $keyCode) {
+				$assocWidth = 1;
+				break;
+			}
+			++$i;
+		}
+		foreach ($elementsCode as $element) {
+			list($keyCode, $valueCode, $key, $value) = $element;
+			if ($assocWidth) {
+				$len = strlen($keyCode);
+				if ($assocWidth < $len) {
+					$assocWidth = $len;
+				}
+			}
+			if (is_array($value) || is_a($value, 'Decompiler_Array')) {
+				$multiline ++;
+			}
+		}
+
+		$i = 0;
+		foreach ($elementsCode as $element) {
+			list($keyCode, $value) = $element;
+			if ($multiline) {
+				if ($i) {
+					$exp .= ",";
+				}
+				$exp .= "\n";
+				$exp .= $indent;
+			}
+			else {
+				if ($i) {
+					$exp .= ", ";
+				}
+			}
+
+			if ($assocWidth) {
+				if ($multiline) {
+					$exp .= sprintf("%-{$assocWidth}s => ", $keyCode);
+				}
+				else {
+					$exp .= $keyCode . ' => ';
+				}
+			}
+
+			$exp .= $value;
+
+			$i ++;
+		}
+		if ($multiline) {
+			$exp .= "\n$indent)";
+		}
+		else {
+			$exp .= ")";
+		}
+		return $exp;
+	}
+}
+// }}}
+class Decompiler_ConstArray extends Decompiler_Array // {{{
+{
+	function Decompiler_ConstArray($array)
+	{
+		$elements = array();
+		foreach ($array as $key => $value) {
+			$elements[] = array(value($key), value($value));
+		}
+		$this->value = $elements;
+	}
+}
+// }}}
+class Decompiler_ForeachBox extends Decompiler_Box // {{{
+{
+	var $iskey;
+
+	function toCode($indent)
+	{
+		return 'foreach (' . '';
+	}
+}
+// }}}
+
+class Decompiler
+{
+	var $namespace;
+	var $namespaceDecided;
+
+	function Decompiler()
+	{
+		// {{{ testing
+		// XC_UNDEF XC_OP_DATA
+		$this->test = !empty($_ENV['XCACHE_DECOMPILER_TEST']);
+		$this->usedOps = array();
+
+		if ($this->test) {
+			$content = file_get_contents(__FILE__);
+			for ($i = 0; $opname = xcache_get_opcode($i); $i ++) {
+				if (!preg_match("/\\bXC_" . $opname . "\\b(?!')/", $content)) {
+					echo "not recognized opcode ", $opname, "\n";
+				}
+			}
+		}
+		// }}}
+		// {{{ 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",
+				XC_ASSIGN              => "=",
+				XC_ASSIGN_REF          => "= &",
+				XC_JMP_SET             => "?:",
+				XC_JMPZ_EX             => "&&",
+				XC_JMPNZ_EX            => "||",
+				);
+		// }}}
+		$this->includeTypes = array( // {{{
+				ZEND_EVAL         => 'eval',
+				ZEND_INCLUDE      => 'include',
+				ZEND_INCLUDE_ONCE => 'include_once',
+				ZEND_REQUIRE      => 'require',
+				ZEND_REQUIRE_ONCE => 'require_once',
+				);
+				// }}}
+	}
+	function detectNamespace($name) // {{{
+	{
+		if ($this->namespaceDecided) {
+			return;
+		}
+
+		if (strpos($name, '\\') !== false) {
+			$this->namespace = strtok($name, '\\');
+			echo 'namespace ', $this->namespace, ";\n\n";
+		}
+
+		$this->namespaceDecided = true;
+	}
+	// }}}
+	function stripNamespace($name) // {{{
+	{
+		$len = strlen($this->namespace) + 1;
+		if (substr($name, 0, $len) == $this->namespace . '\\') {
+			return substr($name, $len);
+		}
+		else {
+			return $name;
+		}
+	}
+	// }}}
+	function outputPhp(&$EX, $range) // {{{
+	{
+		$needBlankline = isset($EX['lastBlock']);
+		$indent = $EX['indent'];
+		$curticks = 0;
+		for ($i = $range[0]; $i <= $range[1]; $i ++) {
+			$op = $EX['opcodes'][$i];
+			if (isset($op['gofrom'])) {
+				if ($needBlankline) {
+					$needBlankline = false;
+					echo PHP_EOL;
+				}
+				echo 'label' . $i, ":\n";
+			}
+			if (isset($op['php'])) {
+				$toticks = isset($op['ticks']) ? (int) str($op['ticks']) : 0;
+				if ($curticks != $toticks) {
+					$oldticks = $curticks;
+					$curticks = $toticks;
+					if (!$curticks) {
+						echo $EX['indent'], "}\n\n";
+						$indent = $EX['indent'];
+					}
+					else {
+						if ($oldticks) {
+							echo $EX['indent'], "}\n\n";
+						}
+						else if (!$oldticks) {
+							$indent .= INDENT;
+						}
+						if ($needBlankline) {
+							$needBlankline = false;
+							echo PHP_EOL;
+						}
+						echo $EX['indent'], "declare (ticks=$curticks) {\n";
+					}
+				}
+				if ($needBlankline) {
+					$needBlankline = false;
+					echo PHP_EOL;
+				}
+				echo $indent, str($op['php'], $indent), ";\n";
+				$EX['lastBlock'] = 'basic';
+			}
+		}
+		if ($curticks) {
+			echo $EX['indent'], "}\n";
+		}
+	}
+	// }}}
+	function getOpVal($op, &$EX, $free = false) // {{{
+	{
+		switch ($op['op_type']) {
+		case XC_IS_CONST:
+			return value($op['constant']);
+
+		case XC_IS_VAR:
+		case XC_IS_TMP_VAR:
+			$T = &$EX['Ts'];
+			$ret = $T[$op['var']];
+			if ($free && empty($this->keepTs)) {
+				unset($T[$op['var']]);
+			}
+			return $ret;
+
+		case XC_IS_CV:
+			$var = $op['var'];
+			$var = $EX['op_array']['vars'][$var];
+			return '$' . $var['name'];
+
+		case XC_IS_UNUSED:
+			return null;
+		}
+	}
+	// }}}
+	function removeKeyPrefix($array, $prefix) // {{{
+	{
+		$prefixLen = strlen($prefix);
+		$ret = array();
+		foreach ($array as $key => $value) {
+			if (substr($key, 0, $prefixLen) == $prefix) {
+				$key = substr($key, $prefixLen);
+			}
+			$ret[$key] = $value;
+		}
+		return $ret;
+	}
+	// }}}
+	function &fixOpcode($opcodes, $removeTailing = false, $defaultReturnValue = null) // {{{
+	{
+		$last = count($opcodes) - 1;
+		for ($i = 0; $i <= $last; $i ++) {
+			if (function_exists('xcache_get_fixed_opcode')) {
+				$opcodes[$i]['opcode'] = xcache_get_fixed_opcode($opcodes[$i]['opcode'], $i);
+			}
+			if (isset($opcodes[$i]['op1'])) {
+				$opcodes[$i]['op1'] = $this->removeKeyPrefix($opcodes[$i]['op1'], 'u.');
+				$opcodes[$i]['op2'] = $this->removeKeyPrefix($opcodes[$i]['op2'], 'u.');
+				$opcodes[$i]['result'] = $this->removeKeyPrefix($opcodes[$i]['result'], 'u.');
+			}
+			else {
+				$op = array(
+					'op1' => array(),
+					'op2' => array(),
+					'op3' => array(),
+				);
+				foreach ($opcodes[$i] as $name => $value) {
+					if (preg_match('!^(op1|op2|result)\\.(.*)!', $name, $m)) {
+						list(, $which, $field) = $m;
+						$op[$which][$field] = $value;
+					}
+					else if (preg_match('!^(op1|op2|result)_type$!', $name, $m)) {
+						list(, $which) = $m;
+						$op[$which]['op_type'] = $value;
+					}
+					else {
+						$op[$name] = $value;
+					}
+				}
+				$opcodes[$i] = $op;
+			}
+		}
+
+		if ($removeTailing) {
+			$last = count($opcodes) - 1;
+			if ($opcodes[$last]['opcode'] == XC_HANDLE_EXCEPTION) {
+				$this->usedOps[XC_HANDLE_EXCEPTION] = true;
+				$opcodes[$last]['opcode'] = XC_NOP;
+				--$last;
+			}
+			if ($opcodes[$last]['opcode'] == XC_RETURN) {
+				$op1 = $opcodes[$last]['op1'];
+				if ($op1['op_type'] == XC_IS_CONST && array_key_exists('constant', $op1) && $op1['constant'] === $defaultReturnValue) {
+					$opcodes[$last]['opcode'] = XC_NOP;
+					--$last;
+				}
+			}
+		}
+		return $opcodes;
+	}
+	// }}}
+	function decompileBasicBlock(&$EX, $range, $unhandled = false) // {{{
+	{
+		$this->dasmBasicBlock($EX, $range);
+		if ($unhandled) {
+			$this->dumpRange($EX, $range);
+		}
+		$this->outputPhp($EX, $range);
+	}
+	// }}}
+	function isIfCondition(&$EX, $range) // {{{
+	{
+		$opcodes = &$EX['opcodes'];
+		$firstOp = &$opcodes[$range[0]];
+		return $firstOp['opcode'] == XC_JMPZ && !empty($firstOp['jmpouts']) && $opcodes[$firstOp['jmpouts'][0] - 1]['opcode'] == XC_JMP
+		 && !empty($opcodes[$firstOp['jmpouts'][0] - 1]['jmpouts'])
+		 && $opcodes[$firstOp['jmpouts'][0] - 1]['jmpouts'][0] == $range[1] + 1;
+	}
+	// }}}
+	function removeJmpInfo(&$EX, $line) // {{{
+	{
+		$opcodes = &$EX['opcodes'];
+		foreach ($opcodes[$line]['jmpouts'] as $jmpTo) {
+			$jmpins = &$opcodes[$jmpTo]['jmpins'];
+			$jmpins = array_flip($jmpins);
+			unset($jmpins[$line]);
+			$jmpins = array_keys($jmpins);
+		}
+		// $opcodes[$line]['opcode'] = XC_NOP;
+		unset($opcodes[$line]['jmpouts']);
+	}
+	// }}}
+	function beginScope(&$EX, $doIndent = true) // {{{
+	{
+		array_push($EX['scopeStack'], array($EX['lastBlock'], $EX['indent']));
+		if ($doIndent) {
+			$EX['indent'] .= INDENT;
+		}
+		$EX['lastBlock'] = null;
+	}
+	// }}}
+	function endScope(&$EX) // {{{
+	{
+		list($EX['lastBlock'], $EX['indent']) = array_pop($EX['scopeStack']);
+	}
+	// }}}
+	function beginComplexBlock(&$EX) // {{{
+	{
+		if (isset($EX['lastBlock'])) {
+			echo PHP_EOL;
+			$EX['lastBlock'] = null;
+		}
+	}
+	// }}}
+	function endComplexBlock(&$EX) // {{{
+	{
+		$EX['lastBlock'] = 'complex';
+	}
+	// }}}
+	function decompileComplexBlock(&$EX, $range) // {{{
+	{
+		$T = &$EX['Ts'];
+		$opcodes = &$EX['opcodes'];
+		$indent = $EX['indent'];
+
+		$firstOp = &$opcodes[$range[0]];
+		$lastOp = &$opcodes[$range[1]];
+
+		// {{{ && || and or
+		if (($firstOp['opcode'] == XC_JMPZ_EX || $firstOp['opcode'] == XC_JMPNZ_EX) && !empty($firstOp['jmpouts'])
+		 && $firstOp['jmpouts'][0] == $range[1] + 1
+		 && $lastOp['opcode'] == XC_BOOL
+		 && $firstOp['opcode']['result']['var'] == $lastOp['opcode']['result']['var']
+		) {
+			$this->removeJmpInfo($EX, $range[0]);
+
+			$this->recognizeAndDecompileClosedBlocks($EX, array($range[0], $range[0]));
+			$op1 = $this->getOpVal($firstOp['result'], $EX, true);
+
+			$this->recognizeAndDecompileClosedBlocks($EX, array($range[0] + 1, $range[1]));
+			$op2 = $this->getOpVal($lastOp['result'], $EX, true);
+
+			$T[$firstOp['result']['var']] = new Decompiler_Binop($this, $op1, $firstOp['opcode'], $op2);
+			return false;
+		}
+		// }}}
+		// {{{ ?: excluding JMP_SET
+		if ($firstOp['opcode'] == XC_JMPZ && !empty($firstOp['jmpouts'])
+		 && $range[1] >= $range[0] + 3
+		 && $opcodes[$firstOp['jmpouts'][0] - 2]['opcode'] == XC_QM_ASSIGN
+		 && $opcodes[$firstOp['jmpouts'][0] - 1]['opcode'] == XC_JMP && $opcodes[$firstOp['jmpouts'][0] - 1]['jmpouts'][0] == $range[1] + 1
+		 && $lastOp['opcode'] == XC_QM_ASSIGN
+		) {
+			$trueRange = array($range[0] + 1, $firstOp['jmpouts'][0] - 2);
+			$falseRange = array($firstOp['jmpouts'][0], $range[1]);
+			$this->removeJmpInfo($EX, $range[0]);
+
+			$condition = $this->getOpVal($firstOp['op1'], $EX);
+			$this->recognizeAndDecompileClosedBlocks($EX, $trueRange);
+			$trueValue = $this->getOpVal($opcodes[$trueRange[1]]['result'], $EX, true);
+			$this->recognizeAndDecompileClosedBlocks($EX, $falseRange);
+			$falseValue = $this->getOpVal($opcodes[$falseRange[1]]['result'], $EX, true);
+			$T[$opcodes[$trueRange[1]]['result']['var']] = new Decompiler_TriOp($condition, $trueValue, $falseValue);
+			return false;
+		}
+		// }}}
+		// {{{ goto
+		if ($firstOp['opcode'] == XC_JMP && !empty($firstOp['jmpouts']) && $firstOp['jmpouts'][0] == $range[1] + 1) {
+			$this->removeJmpInfo($EX, $range[0]);
+			$firstOp['opcode'] = XC_GOTO;
+			$target = $firstOp['op1']['var'];
+			$firstOp['goto'] = $target;
+			$opcodes[$target]['gofrom'][] = $range[0];
+
+			$this->recognizeAndDecompileClosedBlocks($EX, $range);
+			return false;
+		}
+		// }}}
+		// {{{ for
+		if (!empty($firstOp['jmpins']) && $opcodes[$firstOp['jmpins'][0]]['opcode'] == XC_JMP
+		 && $lastOp['opcode'] == XC_JMP && !empty($lastOp['jmpouts']) && $lastOp['jmpouts'][0] <= $firstOp['jmpins'][0]
+		 && !empty($opcodes[$range[1] + 1]['jmpins']) && $opcodes[$opcodes[$range[1] + 1]['jmpins'][0]]['opcode'] == XC_JMPZNZ
+		) {
+			$nextRange = array($lastOp['jmpouts'][0], $firstOp['jmpins'][0]);
+			$conditionRange = array($range[0], $nextRange[0] - 1);
+			$this->removeJmpInfo($EX, $conditionRange[1]);
+			$bodyRange = array($nextRange[1], $range[1]);
+			$this->removeJmpInfo($EX, $bodyRange[1]);
+
+			$initial = '';
+			$this->beginScope($EX);
+			$this->dasmBasicBlock($EX, $conditionRange);
+			$conditionCodes = array();
+			for ($i = $conditionRange[0]; $i <= $conditionRange[1]; ++$i) {
+				if (isset($opcodes[$i]['php'])) {
+					$conditionCodes[] = str($opcodes[$i]['php'], $EX);
+				}
+			}
+			$conditionCodes[] = str($this->getOpVal($opcodes[$conditionRange[1]]['op1'], $EX), $EX);
+			if (implode(',', $conditionCodes) == 'true') {
+				$conditionCodes = array();
+			}
+			$this->endScope($EX);
+
+			$this->beginScope($EX);
+			$this->dasmBasicBlock($EX, $nextRange);
+			$nextCodes = array();
+			for ($i = $nextRange[0]; $i <= $nextRange[1]; ++$i) {
+				if (isset($opcodes[$i]['php'])) {
+					$nextCodes[] = str($opcodes[$i]['php'], $EX);
+				}
+			}
+			$this->endScope($EX);
+
+			$this->beginComplexBlock($EX);
+			echo $indent, 'for (', str($initial, $EX), '; ', implode(', ', $conditionCodes), '; ', implode(', ', $nextCodes), ') ', '{', PHP_EOL;
+			$this->beginScope($EX);
+			$this->recognizeAndDecompileClosedBlocks($EX, $bodyRange);
+			$this->endScope($EX);
+			echo $indent, '}', PHP_EOL;
+			$this->endComplexBlock($EX);
+			return;
+		}
+		// }}}
+		// {{{ if/elseif/else
+		if ($this->isIfCondition($EX, $range)) {
+			$this->beginComplexBlock($EX);
+			$isElseIf = false;
+			do {
+				$ifRange = array($range[0], $opcodes[$range[0]]['jmpouts'][0] - 1);
+				$this->removeJmpInfo($EX, $ifRange[0]);
+				$this->removeJmpInfo($EX, $ifRange[1]);
+				$condition = $this->getOpVal($opcodes[$ifRange[0]]['op1'], $EX);
+
+				echo $indent, $isElseIf ? 'else if' : 'if', ' (', str($condition, $EX), ') ', '{', PHP_EOL;
+				$this->beginScope($EX);
+				$this->recognizeAndDecompileClosedBlocks($EX, $ifRange);
+				$this->endScope($EX);
+				$EX['lastBlock'] = null;
+				echo $indent, '}', PHP_EOL;
+
+				$isElseIf = true;
+				// search for else if
+				$range[0] = $ifRange[1] + 1;
+				for ($i = $ifRange[1] + 1; $i <= $range[1]; ++$i) {
+					// find first jmpout
+					if (!empty($opcodes[$i]['jmpouts'])) {
+						if ($this->isIfCondition($EX, array($i, $range[1]))) {
+							$this->dasmBasicBlock($EX, array($range[0], $i));
+							$range[0] = $i;
+						}
+						break;
+					}
+				}
+			} while ($this->isIfCondition($EX, $range));
+			if ($ifRange[1] < $range[1]) {
+				$elseRange = array($ifRange[1], $range[1]);
+				echo $indent, 'else ', '{', PHP_EOL;
+				$this->beginScope($EX);
+				$this->recognizeAndDecompileClosedBlocks($EX, $elseRange);
+				$this->endScope($EX);
+				$EX['lastBlock'] = null;
+				echo $indent, '}', PHP_EOL;
+			}
+			$this->endComplexBlock($EX);
+			return;
+		}
+		if ($firstOp['opcode'] == XC_JMPZ && !empty($firstOp['jmpouts'])
+		 && $firstOp['jmpouts'][0] - 1 == $range[1] && $opcodes[$firstOp['jmpouts'][0] - 1]['opcode'] == XC_RETURN) {
+			$this->beginComplexBlock($EX);
+			$this->removeJmpInfo($EX, $range[0]);
+			$condition = $this->getOpVal($opcodes[$range[0]]['op1'], $EX);
+
+			echo $indent, 'if (', str($condition, $EX), ') ', '{', PHP_EOL;
+			$this->beginScope($EX);
+			$this->recognizeAndDecompileClosedBlocks($EX, $range);
+			$this->endScope($EX);
+			echo $indent, '}', PHP_EOL;
+			$this->endComplexBlock($EX);
+			return;
+		}
+		// }}}
+		// {{{ try/catch
+		if (!empty($firstOp['jmpins']) && !empty($opcodes[$firstOp['jmpins'][0]]['isCatchBegin'])) {
+			$catchBlocks = array();
+			$catchFirst = $firstOp['jmpins'][0];
+
+			$tryRange = array($range[0], $catchFirst - 1);
+
+			// search for XC_CATCH
+			$this->removeJmpInfo($EX, $catchFirst);
+			for ($i = $catchFirst; $i <= $range[1]; ) {
+				if ($opcodes[$i]['opcode'] == XC_CATCH) {
+					$catchOpLine = $i;
+					$this->removeJmpInfo($EX, $catchOpLine);
+
+					$catchNext = $opcodes[$catchOpLine]['extended_value'];
+					$catchBodyLast = $catchNext - 1;
+					if ($opcodes[$catchBodyLast]['opcode'] == XC_JMP) {
+						--$catchBodyLast;
+					}
+
+					$catchBlocks[$catchFirst] = array($catchOpLine, $catchBodyLast);
+
+					$i = $catchFirst = $catchNext;
+				}
+				else {
+					++$i;
+				}
+			}
+
+			if ($opcodes[$tryRange[1]]['opcode'] == XC_JMP) {
+				--$tryRange[1];
+			}
+
+			$this->beginComplexBlock($EX);
+			echo $indent, "try {", PHP_EOL;
+			$this->beginScope($EX);
+			$this->recognizeAndDecompileClosedBlocks($EX, $tryRange);
+			$this->endScope($EX);
+			echo $indent, '}', PHP_EOL;
+			foreach ($catchBlocks as $catchFirst => $catchInfo) {
+				list($catchOpLine, $catchBodyLast) = $catchInfo;
+				$catchBodyFirst = $catchOpLine + 1;
+				$this->dasmBasicBlock($EX, array($catchFirst, $catchOpLine));
+				$catchOp = &$opcodes[$catchOpLine];
+				echo $indent, 'catch (', str($this->getOpVal($catchOp['op1'], $EX)), ' ', str($this->getOpVal($catchOp['op2'], $EX)), ") {", PHP_EOL;
+				unset($catchOp);
+
+				$EX['lastBlock'] = null;
+				$this->beginScope($EX);
+				$this->recognizeAndDecompileClosedBlocks($EX, array($catchBodyFirst, $catchBodyLast));
+				$this->endScope($EX);
+				echo $indent, '}', PHP_EOL;
+			}
+			$this->endComplexBlock($EX);
+			return;
+		}
+		// }}}
+		// {{{ switch/case
+		if ($firstOp['opcode'] == XC_SWITCH_FREE && isset($T[$firstOp['op1']['var']])) {
+			// TODO: merge this code to CASE code. use SWITCH_FREE to detect begin of switch by using $Ts if possible
+			$this->beginComplexBlock($EX);
+			echo $indent, 'switch (', str($this->getOpVal($firstOp['op1'], $EX)), ") {", PHP_EOL;
+			echo $indent, '}', PHP_EOL;
+			$this->endComplexBlock($EX);
+			return;
+		}
+
+		if (
+			($firstOp['opcode'] == XC_CASE
+			|| $firstOp['opcode'] == XC_JMP && !empty($firstOp['jmpouts']) && $opcodes[$firstOp['jmpouts'][0]]['opcode'] == XC_CASE
+			)
+		 	 && !empty($lastOp['jmpouts'])
+		) {
+			$cases = array();
+			$caseDefault = null;
+			$caseOp = null;
+			for ($i = $range[0]; $i <= $range[1]; ) {
+				$op = $opcodes[$i];
+				if ($op['opcode'] == XC_CASE) {
+					if (!isset($caseOp)) {
+						$caseOp = $op;
+					}
+					$jmpz = $opcodes[$i + 1];
+					assert('$jmpz["opcode"] == XC_JMPZ');
+					$caseNext = $jmpz['jmpouts'][0];
+					$cases[$i] = $caseNext - 1;
+					$i = $caseNext;
+				}
+				else if ($op['opcode'] == XC_JMP && $op['jmpouts'][0] >= $i) {
+					// default
+					$caseNext = $op['jmpouts'][0];
+					$caseDefault = $i;
+					$cases[$i] = $caseNext - 1;
+					$i = $caseNext;
+				}
+				else {
+					++$i;
+				}
+			}
+
+			$this->beginComplexBlock($EX);
+
+			echo $indent, 'switch (', str($this->getOpVal($caseOp['op1'], $EX), $EX), ") {", PHP_EOL;
+			$caseIsOut = false;
+			foreach ($cases as $caseFirst => $caseLast) {
+				if ($caseIsOut && empty($lastCaseFall)) {
+					echo PHP_EOL;
+				}
+
+				$caseOp = $opcodes[$caseFirst];
+
+				echo $indent;
+				if ($caseOp['opcode'] == XC_CASE) {
+					echo 'case ';
+					echo str($this->getOpVal($caseOp['op2'], $EX), $EX);
+					echo ':', PHP_EOL;
+
+					$this->removeJmpInfo($EX, $caseFirst);
+					++$caseFirst;
+
+					assert('$opcodes[$caseFirst]["opcode"] == XC_JMPZ');
+					$this->removeJmpInfo($EX, $caseFirst);
+					++$caseFirst;
+				}
+				else {
+					echo 'default';
+					echo ':', PHP_EOL;
+
+					assert('$opcodes[$caseFirst]["opcode"] == XC_JMP');
+					$this->removeJmpInfo($EX, $caseFirst);
+					++$caseFirst;
+				}
+
+				assert('$opcodes[$caseLast]["opcode"] == XC_JMP');
+				$this->removeJmpInfo($EX, $caseLast);
+				--$caseLast;
+				switch ($opcodes[$caseLast]['opcode']) {
+				case XC_BRK:
+				case XC_CONT:
+				case XC_GOTO:
+					$lastCaseFall = false;
+					break;
+
+				default:
+					$lastCaseFall = true;
+				}
+
+				$this->beginScope($EX);
+				$this->recognizeAndDecompileClosedBlocks($EX, array($caseFirst, $caseLast));
+				$this->endScope($EX);
+				$caseIsOut = true;
+			}
+			echo $indent, '}', PHP_EOL;
+
+			$this->endComplexBlock($EX);
+			return;
+		}
+		// }}}
+		// {{{ do/while
+		if ($lastOp['opcode'] == XC_JMPNZ && !empty($lastOp['jmpouts'])
+		 && $lastOp['jmpouts'][0] == $range[0]) {
+			$this->removeJmpInfo($EX, $range[1]);
+			$this->beginComplexBlock($EX);
+
+			echo $indent, "do {", PHP_EOL;
+			$this->beginScope($EX);
+			$this->recognizeAndDecompileClosedBlocks($EX, $range);
+			$this->endScope($EX);
+			echo $indent, "} while (", str($this->getOpVal($lastOp['op1'], $EX)), ');', PHP_EOL;
+
+			$this->endComplexBlock($EX);
+			return;
+		}
+		// }}}
+
+		// {{{ search firstJmpOp
+		$firstJmp = null;
+		$firstJmpOp = null;
+		for ($i = $range[0]; $i <= $range[1]; ++$i) {
+			if (!empty($opcodes[$i]['jmpouts'])) {
+				$firstJmp = $i;
+				$firstJmpOp = &$opcodes[$firstJmp];
+				break;
+			}
+		}
+		// }}}
+
+		// {{{ while
+		if (isset($firstJmpOp)
+		 && $firstJmpOp['opcode'] == XC_JMPZ
+		 && $firstJmpOp['jmpouts'][0] > $range[1]
+		 && $lastOp['opcode'] == XC_JMP && !empty($lastOp['jmpouts'])
+		 && $lastOp['jmpouts'][0] == $range[0]) {
+			$this->removeJmpInfo($EX, $firstJmp);
+			$this->removeJmpInfo($EX, $range[1]);
+			$this->beginComplexBlock($EX);
+
+			ob_start();
+			$this->beginScope($EX);
+			$this->recognizeAndDecompileClosedBlocks($EX, $range);
+			$this->endScope($EX);
+			$body = ob_get_clean();
+
+			echo $indent, 'while (', str($this->getOpVal($firstJmpOp['op1'], $EX)), ") {", PHP_EOL;
+			echo $body;
+			echo $indent, '}', PHP_EOL;
+
+			$this->endComplexBlock($EX);
+			return;
+		}
+		// }}}
+		// {{{ foreach
+		if (isset($firstJmpOp)
+		 && $firstJmpOp['opcode'] == XC_FE_FETCH
+		 && $firstJmpOp['jmpouts'][0] > $range[1]
+		 && $lastOp['opcode'] == XC_JMP && !empty($lastOp['jmpouts'])
+		 && $lastOp['jmpouts'][0] == $firstJmp) {
+			$this->removeJmpInfo($EX, $firstJmp);
+			$this->removeJmpInfo($EX, $range[1]);
+			$this->beginComplexBlock($EX);
+
+			ob_start();
+			$this->beginScope($EX);
+			$this->recognizeAndDecompileClosedBlocks($EX, $range);
+			$this->endScope($EX);
+			$body = ob_get_clean();
+
+			$as = foldToCode($firstJmpOp['fe_as'], $EX);
+			if (isset($firstJmpOp['fe_key'])) {
+				$as = str($firstJmpOp['fe_key'], $EX) . ' => ' . str($as);
+			}
+
+			echo $indent, 'foreach (', str($firstJmpOp['fe_src'], $EX), " as $as) {", PHP_EOL;
+			echo $body;
+			echo $indent, '}', PHP_EOL;
+
+			$this->endComplexBlock($EX);
+			if ($opcodes[$range[1] + 1]['opcode'] == XC_SWITCH_FREE) {
+				$this->removeJmpInfo($EX, $range[1] + 1);
+			}
+			return;
+		}
+		// }}}
+
+		$this->decompileBasicBlock($EX, $range, true);
+	}
+	// }}}
+	function recognizeAndDecompileClosedBlocks(&$EX, $range) // {{{ decompile in a tree way
+	{
+		$opcodes = &$EX['opcodes'];
+
+		$starti = $range[0];
+		for ($i = $starti; $i <= $range[1]; ) {
+			if (!empty($opcodes[$i]['jmpins']) || !empty($opcodes[$i]['jmpouts'])) {
+				$blockFirst = $i;
+				$blockLast = -1;
+				$j = $blockFirst;
+				do {
+					$op = $opcodes[$j];
+					if (!empty($op['jmpins'])) {
+						// care about jumping from blocks behind, not before
+						foreach ($op['jmpins'] as $oplineNumber) {
+							if ($oplineNumber <= $range[1] && $blockLast < $oplineNumber) {
+								$blockLast = $oplineNumber;
+							}
+						}
+					}
+					if (!empty($op['jmpouts'])) {
+						$blockLast = max($blockLast, max($op['jmpouts']) - 1);
+					}
+					++$j;
+				} while ($j <= $blockLast);
+				if (!assert('$blockLast <= $range[1]')) {
+					var_dump($blockLast, $range[1]);
+				}
+
+				if ($blockLast >= $blockFirst) {
+					if ($blockFirst > $starti) {
+						$this->decompileBasicBlock($EX, array($starti, $blockFirst - 1));
+					}
+					if ($this->decompileComplexBlock($EX, array($blockFirst, $blockLast)) === false) {
+						if ($EX['lastBlock'] == 'complex') {
+							echo PHP_EOL;
+						}
+						$EX['lastBlock'] = null;
+					}
+					$starti = $blockLast + 1;
+					$i = $starti;
+				}
+				else {
+					++$i;
+				}
+			}
+			else {
+				++$i;
+			}
+		}
+		if ($starti <= $range[1]) {
+			$this->decompileBasicBlock($EX, array($starti, $range[1]));
+		}
+	}
+	// }}}
+	function &dop_array($op_array, $indent = '') // {{{
+	{
+		$op_array['opcodes'] = $this->fixOpcode($op_array['opcodes'], true, $indent == '' ? 1 : null);
+		$opcodes = &$op_array['opcodes'];
+		$last = count($opcodes) - 1;
+		// {{{ build jmpins/jmpouts to op_array
+		for ($i = 0; $i <= $last; $i ++) {
+			$op = &$opcodes[$i];
+			$op['line'] = $i;
+			switch ($op['opcode']) {
+			case XC_CONT:
+			case XC_BRK:
+				$op['jmpouts'] = array();
+				break;
+
+			case XC_GOTO:
+				$target = $op['op1']['var'];
+				$op['goto'] = $target;
+				$opcodes[$target]['gofrom'][] = $i;
+				break;
+
+			case XC_JMP:
+				$target = $op['op1']['var'];
+				$op['jmpouts'] = array($target);
+				$opcodes[$target]['jmpins'][] = $i;
+				break;
+
+			case XC_JMPZNZ:
+				$jmpz = $op['op2']['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_JMP_SET:
+			// case XC_FE_RESET:
+			case XC_FE_FETCH:
+			// case XC_JMP_NO_CTOR:
+				$target = $op['op2']['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;
+			*/
+
+			case XC_SWITCH_FREE:
+				$op['jmpouts'] = array($i + 1);
+				$opcodes[$i + 1]['jmpins'][] = $i;
+				break;
+
+			case XC_CASE:
+				// just to link together
+				$op['jmpouts'] = array($i + 2);
+				$opcodes[$i + 2]['jmpins'][] = $i;
+				break;
+
+			case XC_CATCH:
+				$catchNext = $op['extended_value'];
+				$op['jmpouts'] = array($catchNext);
+				$opcodes[$catchNext]['jmpins'][] = $i;
+				break;
+			}
+			/*
+			if (!empty($op['jmpouts']) || !empty($op['jmpins'])) {
+				echo $i, "\t", xcache_get_opcode($op['opcode']), PHP_EOL;
+			}
+			// */
+		}
+		unset($op);
+		if ($op_array['try_catch_array']) {
+			foreach ($op_array['try_catch_array'] as $try_catch_element) {
+				$catch_op = $try_catch_element['catch_op'];
+				$try_op = $try_catch_element['try_op'];
+				$opcodes[$try_op]['jmpins'][] = $catch_op;
+				$opcodes[$catch_op]['jmpouts'][] = $try_op;
+				$opcodes[$catch_op]['isCatchBegin'] = true;
+			}
+		}
+		// }}}
+		// build semi-basic blocks
+		$nextbbs = array();
+		$starti = 0;
+		for ($i = 1; $i <= $last; $i ++) {
+			if (isset($opcodes[$i]['jmpins'])
+			 || isset($opcodes[$i - 1]['jmpouts'])) {
+				$nextbbs[$starti] = $i;
+				$starti = $i;
+			}
+		}
+		$nextbbs[$starti] = $last + 1;
+
+		$EX = array();
+		$EX['Ts'] = array();
+		$EX['indent'] = $indent;
+		$EX['nextbbs'] = $nextbbs;
+		$EX['op_array'] = &$op_array;
+		$EX['opcodes'] = &$opcodes;
+		$EX['range'] = array(0, count($opcodes) - 1);
+		// func call
+		$EX['object'] = null;
+		$EX['called_scope'] = null;
+		$EX['fbc'] = null;
+		$EX['argstack'] = array();
+		$EX['arg_types_stack'] = array();
+		$EX['scopeStack'] = array();
+		$EX['silence'] = 0;
+		$EX['recvs'] = array();
+		$EX['uses'] = array();
+		$EX['lastBlock'] = null;
+
+		/* dump whole array
+		$this->keepTs = true;
+		$this->dasmBasicBlock($EX, $range);
+		for ($i = $range[0]; $i <= $range[1]; ++$i) {
+			echo $i, "\t", $this->dumpop($opcodes[$i], $EX);
+		}
+		// */
+		// decompile in a tree way
+		$this->recognizeAndDecompileClosedBlocks($EX, $EX['range'], $EX['indent']);
+		return $EX;
+	}
+	// }}}
+	function dasmBasicBlock(&$EX, $range) // {{{
+	{
+		$T = &$EX['Ts'];
+		$opcodes = &$EX['opcodes'];
+		$lastphpop = null;
+
+		for ($i = $range[0]; $i <= $range[1]; $i ++) {
+			// {{{ prepair
+			$op = &$opcodes[$i];
+			$opc = $op['opcode'];
+			if ($opc == XC_NOP) {
+				$this->usedOps[$opc] = true;
+				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;
+			}
+			// echo $i, ' '; $this->dumpop($op, $EX); //var_dump($op);
+
+			$resvar = null;
+			unset($curResVar);
+			if (array_key_exists($res['var'], $T)) {
+				$curResVar = &$T[$res['var']];
+			}
+			if ((ZEND_ENGINE_2_4 ? ($res['op_type'] & EXT_TYPE_UNUSED) : ($res['EA.type'] & EXT_TYPE_UNUSED)) || $res['op_type'] == XC_IS_UNUSED) {
+				$istmpres = false;
+			}
+			else {
+				$istmpres = true;
+			}
+			// }}}
+			// echo $opname, "\n";
+
+			$notHandled = false;
+			switch ($opc) {
+			case XC_NEW: // {{{
+				array_push($EX['arg_types_stack'], array($EX['fbc'], $EX['object'], $EX['called_scope']));
+				$EX['object'] = (int) $res['var'];
+				$EX['called_scope'] = null;
+				$EX['fbc'] = 'new ' . unquoteName($this->getOpVal($op1, $EX), $EX);
+				if (!ZEND_ENGINE_2) {
+					$resvar = '$new object$';
+				}
+				break;
+				// }}}
+			case XC_THROW: // {{{
+				$resvar = 'throw ' . str($this->getOpVal($op1, $EX));
+				break;
+				// }}}
+			case XC_CLONE: // {{{
+				$resvar = 'clone ' . str($this->getOpVal($op1, $EX));
+				break;
+				// }}}
+			case XC_CATCH: // {{{
+				break;
+				// }}}
+			case XC_INSTANCEOF: // {{{
+				$resvar = str($this->getOpVal($op1, $EX)) . ' instanceof ' . str($this->getOpVal($op2, $EX));
+				break;
+				// }}}
+			case XC_FETCH_CLASS: // {{{
+				if ($op2['op_type'] == XC_IS_UNUSED) {
+					switch (($ext & (defined('ZEND_FETCH_CLASS_MASK') ? ZEND_FETCH_CLASS_MASK : 0xFF))) {
+					case ZEND_FETCH_CLASS_SELF:
+						$class = 'self';
+						break;
+					case ZEND_FETCH_CLASS_PARENT:
+						$class = 'parent';
+						break;
+					case ZEND_FETCH_CLASS_STATIC:
+						$class = 'static';
+						break;
+					}
+					$istmpres = true;
+				}
+				else {
+					$class = $this->getOpVal($op2, $EX);
+					if (isset($op2['constant'])) {
+						$class = $this->stripNamespace(unquoteName($class));
+					}
+				}
+				$resvar = $class;
+				break;
+				// }}}
+			case XC_FETCH_CONSTANT: // {{{
+				if ($op1['op_type'] == XC_IS_UNUSED) {
+					$resvar = $this->stripNamespace($op2['constant']);
+					break;
+				}
+
+				if ($op1['op_type'] == XC_IS_CONST) {
+					$resvar = $this->stripNamespace($op1['constant']);
+				}
+				else {
+					$resvar = $this->getOpVal($op1, $EX);
+				}
+
+				$resvar = str($resvar) . '::' . unquoteName($this->getOpVal($op2, $EX));
+				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);
+				if (defined('ZEND_FETCH_TYPE_MASK')) {
+					$fetchtype = ($ext & ZEND_FETCH_TYPE_MASK);
+				}
+				else {
+					$fetchtype = $op2[!ZEND_ENGINE_2 ? 'fetch_type' : 'EA.type'];
+				}
+				switch ($fetchtype) {
+				case ZEND_FETCH_STATIC_MEMBER:
+					$class = $this->getOpVal($op2, $EX);
+					$rvalue = str($class) . '::$' . unquoteName($rvalue, $EX);
+					break;
+				default:
+					$name = unquoteName($rvalue, $EX);
+					$globalname = xcache_is_autoglobal($name) ? "\$$name" : "\$GLOBALS[" . str($rvalue) . "]";
+					$rvalue = new Decompiler_Fetch($rvalue, $fetchtype, $globalname);
+					break;
+				}
+				if ($opc == XC_UNSET_VAR) {
+					$op['php'] = "unset(" . str($rvalue, $EX) . ")";
+					$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_OBJ: // PHP 4 only
+			case XC_UNSET_DIM:
+			case XC_UNSET_OBJ:
+				$src = $this->getOpVal($op1, $EX);
+				if (is_a($src, "Decompiler_ForeachBox")) {
+					$src->iskey = $this->getOpVal($op2, $EX);
+					$resvar = $src;
+					break;
+				}
+
+				if (is_a($src, "Decompiler_DimBox")) {
+					$dimbox = $src;
+				}
+				else {
+					if (!is_a($src, "Decompiler_ListBox")) {
+						$op1val = $this->getOpVal($op1, $EX);
+						$list = new Decompiler_List(isset($op1val) ? $op1val : '$this');
+
+						$src = new Decompiler_ListBox($list);
+						if (!isset($op1['var'])) {
+							$this->dumpop($op, $EX);
+							var_dump($op);
+							die('missing var');
+						}
+						$T[$op1['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;
+				}
+				if ($opc == XC_UNSET_OBJ) {
+					$dim->isObject = true;
+				}
+				unset($dim);
+				$rvalue = $dimbox;
+				unset($dimbox);
+
+				if ($opc == XC_ASSIGN_DIM) {
+					$lvalue = $rvalue;
+					++ $i;
+					$rvalue = $this->getOpVal($opcodes[$i]['op1'], $EX);
+					$resvar = str($lvalue, $EX) . ' = ' . str($rvalue);
+				}
+				else if ($opc == XC_UNSET_DIM || $opc == XC_UNSET_OBJ) {
+					$op['php'] = "unset(" . str($rvalue, $EX) . ")";
+					$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);
+				if (is_a($rvalue, 'Decompiler_ForeachBox')) {
+					$type = $rvalue->iskey ? 'fe_key' : 'fe_as';
+					$rvalue->obj[$type] = $lvalue;
+					unset($T[$op2['var']]);
+					break;
+				}
+				if (is_a($rvalue, "Decompiler_DimBox")) {
+					$dim = &$rvalue->obj;
+					$dim->assign = $lvalue;
+					if ($dim->isLast) {
+						$resvar = foldToCode($dim->value, $EX);
+					}
+					unset($dim);
+					break;
+				}
+				if (is_a($rvalue, 'Decompiler_Fetch')) {
+					$src = str($rvalue->src, $EX);
+					if ('$' . unquoteName($src) == $lvalue) {
+						switch ($rvalue->fetchType) {
+						case ZEND_FETCH_STATIC:
+							$statics = &$EX['op_array']['static_variables'];
+							if ((xcache_get_type($statics[$name]) & IS_LEXICAL_VAR)) {
+								$EX['uses'][] = str($lvalue);
+								unset($statics);
+								break 2;
+							}
+							unset($statics);
+						}
+					}
+				}
+				$resvar = new Decompiler_Binop($this, $lvalue, XC_ASSIGN, $rvalue);
+				break;
+				// }}}
+			case XC_ASSIGN_REF: // {{{
+				$lvalue = $this->getOpVal($op1, $EX);
+				$rvalue = $this->getOpVal($op2, $EX);
+				if (is_a($rvalue, 'Decompiler_Fetch')) {
+					$src = str($rvalue->src, $EX);
+					if ('$' . unquoteName($src) == $lvalue) {
+						switch ($rvalue->fetchType) {
+						case ZEND_FETCH_GLOBAL:
+						case ZEND_FETCH_GLOBAL_LOCK:
+							$resvar = 'global ' . $lvalue;
+							break 2;
+						case ZEND_FETCH_STATIC:
+							$statics = &$EX['op_array']['static_variables'];
+							if ((xcache_get_type($statics[$name]) & IS_LEXICAL_REF)) {
+								$EX['uses'][] = '&' . str($lvalue);
+								unset($statics);
+								break 2;
+							}
+
+							$resvar = 'static ' . $lvalue;
+							$name = unquoteName($src);
+							if (isset($statics[$name])) {
+								$var = $statics[$name];
+								$resvar .= ' = ';
+								$resvar .= str(value($var), $EX);
+							}
+							unset($statics);
+							break 2;
+						default:
+						}
+					}
+				}
+				// TODO: PHP_6 global
+				$resvar = new Decompiler_Binop($this, $lvalue, XC_ASSIGN_REF, $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';
+				}
+				$rvalue = str($obj) . "->" . unquoteVariableName($this->getOpVal($op2, $EX), $EX);
+				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 = " . str($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);
+					// for < PHP_5_3
+					if ($op1['op_type'] == XC_IS_CONST) {
+						$rvalue = '$' . unquoteVariableName($this->getOpVal($op1, $EX));
+					}
+					if ($op2['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);
+					if ($opc == XC_ISSET_ISEMPTY_PROP_OBJ) {
+						if (!isset($container)) {
+							$container = '$this';
+						}
+						$rvalue = $container . "->" . unquoteVariableName($dim);
+					}
+					else {
+						$rvalue = $container . '[' . str($dim) .']';
+					}
+				}
+
+				switch ((!ZEND_ENGINE_2 ? $op['op2']['var'] /* constant */ : $ext) & (ZEND_ISSET|ZEND_ISEMPTY)) {
+				case ZEND_ISSET:
+					$rvalue = "isset(" . str($rvalue) . ")";
+					break;
+				case ZEND_ISEMPTY:
+					$rvalue = "empty(" . str($rvalue) . ")";
+					break;
+				}
+				$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 . str($this->getOpVal($op1, $EX));
+				break;
+				// }}}
+			case XC_INIT_STATIC_METHOD_CALL:
+			case XC_INIT_METHOD_CALL: // {{{
+				array_push($EX['arg_types_stack'], array($EX['fbc'], $EX['object'], $EX['called_scope']));
+				if ($opc == XC_INIT_STATIC_METHOD_CALL || $opc == XC_INIT_METHOD_CALL || $op1['op_type'] != XC_IS_UNUSED) {
+					$obj = $this->getOpVal($op1, $EX);
+					if (!isset($obj)) {
+						$obj = '$this';
+					}
+					if ($opc == XC_INIT_STATIC_METHOD_CALL || /* PHP4 */ isset($op1['constant'])) {
+						$EX['object'] = null;
+						$EX['called_scope'] = $this->stripNamespace(unquoteName($obj, $EX));
+					}
+					else {
+						$EX['object'] = $obj;
+						$EX['called_scope'] = null;
+					}
+					if ($res['op_type'] != XC_IS_UNUSED) {
+						$resvar = '$obj call$';
+					}
+				}
+				else {
+					$EX['object'] = null;
+					$EX['called_scope'] = null;
+				}
+
+				$EX['fbc'] = $this->getOpVal($op2, $EX);
+				if (($opc == XC_INIT_STATIC_METHOD_CALL || $opc == XC_INIT_METHOD_CALL) && !isset($EX['fbc'])) {
+					$EX['fbc'] = '__construct';
+				}
+				break;
+				// }}}
+			case XC_INIT_NS_FCALL_BY_NAME:
+			case XC_INIT_FCALL_BY_NAME: // {{{
+				array_push($EX['arg_types_stack'], array($EX['fbc'], $EX['object'], $EX['called_scope']));
+				if (!ZEND_ENGINE_2 && ($ext & ZEND_CTOR_CALL)) {
+					break;
+				}
+				$EX['object'] = null;
+				$EX['called_scope'] = null;
+				$EX['fbc'] = $this->getOpVal($op2, $EX);
+				break;
+				// }}}
+			case XC_INIT_FCALL_BY_FUNC: // {{{ deprecated even in PHP 4?
+				$EX['object'] = null;
+				$EX['called_scope'] = null;
+				$which = $op1['var'];
+				$EX['fbc'] = $EX['op_array']['funcs'][$which]['name'];
+				break;
+				// }}}
+			case XC_DO_FCALL_BY_FUNC:
+				$which = $op1['var'];
+				$fname = $EX['op_array']['funcs'][$which]['name'];
+				$args = $this->popargs($EX, $ext);
+				$resvar = $fname . "($args)";
+				break;
+			case XC_DO_FCALL:
+				$fname = unquoteName($this->getOpVal($op1, $EX), $EX);
+				$args = $this->popargs($EX, $ext);
+				$resvar = $fname . "($args)";
+				break;
+			case XC_DO_FCALL_BY_NAME: // {{{
+				$object = null;
+
+				$fname = unquoteName($EX['fbc'], $EX);
+				if (!is_int($EX['object'])) {
+					$object = $EX['object'];
+				}
+
+				$args = $this->popargs($EX, $ext);
+
+				$prefix = (isset($object) ? $object . '->' : '' )
+					. (isset($EX['called_scope']) ? $EX['called_scope'] . '::' : '' );
+				$resvar = $prefix
+					. (!$prefix ? $this->stripNamespace($fname) : $fname)
+					. "($args)";
+				unset($args);
+
+				if (is_int($EX['object'])) {
+					$T[$EX['object']] = $resvar;
+					$resvar = null;
+				}
+				list($EX['fbc'], $EX['object'], $EX['called_scope']) = array_pop($EX['arg_types_stack']);
+				break;
+				// }}}
+			case XC_VERIFY_ABSTRACT_CLASS: // {{{
+				//unset($T[$op1['var']]);
+				break;
+				// }}}
+			case XC_DECLARE_CLASS: 
+			case XC_DECLARE_INHERITED_CLASS:
+			case XC_DECLARE_INHERITED_CLASS_DELAYED: // {{{
+				$key = $op1['constant'];
+				if (!isset($this->dc['class_table'][$key])) {
+					echo 'class not found: ', $key, 'existing classes are:', "\n";
+					var_dump(array_keys($this->dc['class_table']));
+					exit;
+				}
+				$class = &$this->dc['class_table'][$key];
+				if (!isset($class['name'])) {
+					$class['name'] = unquoteName($this->getOpVal($op2, $EX), $EX);
+				}
+				if ($opc == XC_DECLARE_INHERITED_CLASS || $opc == XC_DECLARE_INHERITED_CLASS_DELAYED) {
+					$ext /= XC_SIZEOF_TEMP_VARIABLE;
+					$class['parent'] = $T[$ext];
+					unset($T[$ext]);
+				}
+				else {
+					$class['parent'] = null;
+				}
+
+				for (;;) {
+					if ($i + 1 <= $range[1]
+					 && $opcodes[$i + 1]['opcode'] == XC_ADD_INTERFACE
+					 && $opcodes[$i + 1]['op1']['var'] == $res['var']) {
+						// continue
+					}
+					else if ($i + 2 <= $range[1]
+					 && $opcodes[$i + 2]['opcode'] == XC_ADD_INTERFACE
+					 && $opcodes[$i + 2]['op1']['var'] == $res['var']
+					 && $opcodes[$i + 1]['opcode'] == XC_FETCH_CLASS) {
+						// continue
+					}
+					else {
+						break;
+					}
+					$this->usedOps[XC_ADD_INTERFACE] = true;
+
+					$fetchop = &$opcodes[$i + 1];
+					$interface = $this->stripNamespace(unquoteName($this->getOpVal($fetchop['op2'], $EX), $EX));
+					$addop = &$opcodes[$i + 2];
+					$class['interfaces'][$addop['extended_value']] = $interface;
+					unset($fetchop, $addop);
+					$i += 2;
+				}
+				$this->dclass($class, $EX['indent']);
+				echo "\n";
+				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 = value(chr(str($op2val)));
+					break;
+				case XC_ADD_STRING:
+					break;
+				case XC_ADD_VAR:
+					break;
+				}
+				if (str($op1val) == "''") {
+					$rvalue = $op2val;
+				}
+				else if (str($op2val) == "''") {
+					$rvalue = $op1val;
+				}
+				else {
+					$rvalue = str($op1val) . ' . ' . str($op2val);
+				}
+				$resvar = $rvalue;
+				// }}}
+				break;
+			case XC_PRINT: // {{{
+				$op1val = $this->getOpVal($op1, $EX);
+				$resvar = "print(" . str($op1val) . ")";
+				break;
+				// }}}
+			case XC_ECHO: // {{{
+				$op1val = $this->getOpVal($op1, $EX);
+				$resvar = "echo " . str($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, true);
+
+				if ($opc == XC_ADD_ARRAY_ELEMENT) {
+					$assoc = $this->getOpVal($op2, $EX);
+					if (isset($assoc)) {
+						$curResVar->value[] = array($assoc, $rvalue);
+					}
+					else {
+						$curResVar->value[] = array(null, $rvalue);
+					}
+				}
+				else {
+					if ($opc == XC_INIT_ARRAY) {
+						$resvar = new Decompiler_Array();
+						if (!isset($rvalue)) {
+							continue;
+						}
+					}
+
+					$assoc = $this->getOpVal($op2, $EX);
+					if (isset($assoc)) {
+						$resvar->value[] = array($assoc, $rvalue);
+					}
+					else {
+						$resvar->value[] = array(null, $rvalue);
+					}
+				}
+				break;
+				// }}}
+			case XC_QM_ASSIGN: // {{{
+				if (isset($curResVar) && is_a($curResVar, 'Decompiler_Binop')) {
+					$curResVar->op2 = $this->getOpVal($op1, $EX);
+				}
+				else {
+					$resvar = $this->getOpVal($op1, $EX);
+				}
+				break;
+				// }}}
+			case XC_BOOL: // {{{
+				$resvar = /*'(bool) ' .*/ $this->getOpVal($op1, $EX);
+				break;
+				// }}}
+			case XC_RETURN: // {{{
+				$resvar = "return " . str($this->getOpVal($op1, $EX));
+				break;
+				// }}}
+			case XC_INCLUDE_OR_EVAL: // {{{
+				$type = $op2['var']; // hack
+				$keyword = $this->includeTypes[$type];
+				$resvar = "$keyword " . str($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, true);
+				$fe = new Decompiler_ForeachBox($op);
+				$fe->iskey = false;
+				$T[$res['var']] = $fe;
+
+				++ $i;
+				if (($ext & ZEND_FE_FETCH_WITH_KEY)) {
+					$fe = new Decompiler_ForeachBox($op);
+					$fe->iskey = true;
+
+					$res = $opcodes[$i]['result'];
+					$T[$res['var']] = $fe;
+				}
+				break;
+				// }}}
+			case XC_SWITCH_FREE: // {{{
+				break;
+				// }}}
+			case XC_FREE: // {{{
+				$free = $T[$op1['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['var']], $free);
+				break;
+				// }}}
+			case XC_JMP_NO_CTOR:
+				break;
+			case XC_JMP_SET: // ?:
+				$resvar = new Decompiler_Binop($this, $this->getOpVal($op1, $EX), XC_JMP_SET, null);
+				break;
+			case XC_JMPZ_EX: // and
+			case XC_JMPNZ_EX: // or
+				$resvar = $this->getOpVal($op1, $EX);
+				break;
+
+			case XC_JMPNZ: // while
+			case XC_JMPZNZ: // for
+			case XC_JMPZ: // {{{
+				break;
+				// }}}
+			case XC_CONT:
+			case XC_BRK:
+				$resvar = $opc == XC_CONT ? 'continue' : 'break';
+				$count = str($this->getOpVal($op2, $EX));
+				if ($count != '1') {
+					$resvar .= ' ' . $count;
+				}
+				break;
+			case XC_GOTO:
+				$resvar = 'goto label' . $op['op1']['var'];
+				$istmpres = false;
+				break;
+
+			case XC_JMP: // {{{
+				break;
+				// }}}
+			case XC_CASE:
+				// $switchValue = $this->getOpVal($op1, $EX);
+				$caseValue = $this->getOpVal($op2, $EX);
+				$resvar = $caseValue;
+				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']['constant']);
+				}
+				else {
+					$default = null;
+				}
+				$EX['recvs'][str($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) . '->' . unquoteVariableName($this->getOpVal($op2, $EX), $EX);
+				}
+				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, $EX);
+				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:
+				$this->dfunction($this->dc['function_table'][$op1['constant']], $EX['indent']);
+				break;
+			case XC_DECLARE_LAMBDA_FUNCTION: // {{{
+				ob_start();
+				$this->dfunction($this->dc['function_table'][$op1['constant']], $EX['indent']);
+				$resvar = ob_get_clean();
+				$istmpres = true;
+				break;
+				// }}}
+			case XC_DECLARE_CONST:
+				$name = $this->stripNamespace(unquoteName($this->getOpVal($op1, $EX), $EX));
+				$value = str($this->getOpVal($op2, $EX));
+				$resvar = 'const ' . $name . ' = ' . $value;
+				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;
+			case XC_RAISE_ABSTRACT_ERROR:
+				// abstract function body is empty, don't need this code
+				break;
+			case XC_USER_OPCODE:
+				echo '// ZEND_USER_OPCODE, impossible to decompile';
+				break;
+			case XC_OP_DATA:
+				break;
+			default: // {{{
+				$call = array(&$this, $opname);
+				if (is_callable($call)) {
+					$this->usedOps[$opc] = true;
+					$this->{$opname}($op, $EX);
+				}
+				else if (isset($this->binops[$opc])) { // {{{
+					$this->usedOps[$opc] = true;
+					$op1val = $this->getOpVal($op1, $EX);
+					$op2val = $this->getOpVal($op2, $EX);
+					$rvalue = new Decompiler_Binop($this, $op1val, $opc, $op2val);
+					$resvar = $rvalue;
+					// }}}
+				}
+				else if (isset($this->unaryops[$opc])) { // {{{
+					$this->usedOps[$opc] = true;
+					$op1val = $this->getOpVal($op1, $EX);
+					$myop = $this->unaryops[$opc];
+					$rvalue = $myop . str($op1val);
+					$resvar = $rvalue;
+					// }}}
+				}
+				else {
+					$notHandled = true;
+				}
+				// }}}
+			}
+			if ($notHandled) {
+				echo "\x1B[31m * TODO ", $opname, "\x1B[0m\n";
+			}
+			else {
+				$this->usedOps[$opc] = true;
+			}
+
+			if (isset($resvar)) {
+				if ($istmpres) {
+					$T[$res['var']] = $resvar;
+					$lastresvar = &$T[$res['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, foldToCode($a, $EX));
+			}
+			else {
+				array_unshift($args, $a);
+			}
+		}
+		return implode(', ', $args);
+	}
+	// }}}
+	function dumpop($op, &$EX) // {{{
+	{
+		assert('isset($op)');
+		$op1 = $op['op1'];
+		$op2 = $op['op2'];
+		$d = array(xcache_get_opcode($op['opcode']), $op['opcode']);
+
+		foreach (array('op1' => '1:', 'op2' => '2:', 'result' => '>') as $k => $kk) {
+			switch ($op[$k]['op_type']) {
+			case XC_IS_UNUSED:
+				$d[$kk] = 'U:' . $op[$k]['opline_num'];
+				break;
+
+			case XC_IS_VAR:
+				$d[$kk] = '$' . $op[$k]['var'];
+				if ($k != 'result') {
+					$d[$kk] .= ':' . str($this->getOpVal($op[$k], $EX));
+				}
+				break;
+
+			case XC_IS_TMP_VAR:
+				$d[$kk] = '#' . $op[$k]['var'];
+				if ($k != 'result') {
+					$d[$kk] .= ':' . str($this->getOpVal($op[$k], $EX));
+				}
+				break;
+
+			case XC_IS_CV:
+				$d[$kk] = $this->getOpVal($op[$k], $EX);
+				break;
+
+			default:
+				if ($k == 'result') {
+					var_dump($op);
+					assert(0);
+					exit;
+				}
+				else {
+					$d[$kk] = $this->getOpVal($op[$k], $EX);
+				}
+			}
+		}
+		$d[';'] = $op['extended_value'];
+		if (!empty($op['jmpouts'])) {
+			$d['>>'] = implode(',', $op['jmpouts']);
+		}
+		if (!empty($op['jmpins'])) {
+			$d['<<'] = implode(',', $op['jmpins']);
+		}
+
+		foreach ($d as $k => $v) {
+			echo is_int($k) ? '' : $k, str($v), "\t";
+		}
+		echo PHP_EOL;
+	}
+	// }}}
+	function dumpRange(&$EX, $range) // {{{
+	{
+		for ($i = $range[0]; $i <= $range[1]; ++$i) {
+			echo $EX['indent'], $i, "\t"; $this->dumpop($EX['opcodes'][$i], $EX);
+		}
+		echo $EX['indent'], "==", PHP_EOL;
+	}
+	// }}}
+	function dargs(&$EX) // {{{
+	{
+		$op_array = &$EX['op_array'];
+
+		if (isset($op_array['num_args'])) {
+			$c = $op_array['num_args'];
+		}
+		else if (!empty($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 ', ';
+			}
+			$arg = $EX['recvs'][$i + 1];
+			if (isset($op_array['arg_info'])) {
+				$ai = $op_array['arg_info'][$i];
+				if (!empty($ai['class_name'])) {
+					echo $this->stripNamespace($ai['class_name']), ' ';
+					if (!ZEND_ENGINE_2_2 && $ai['allow_null']) {
+						echo 'or NULL ';
+					}
+				}
+				else if (!empty($ai['array_type_hint'])) {
+					echo 'array ';
+					if (!ZEND_ENGINE_2_2 && $ai['allow_null']) {
+						echo 'or NULL ';
+					}
+				}
+				if ($ai['pass_by_reference']) {
+					echo '&';
+				}
+				printf("\$%s", $ai['name']);
+			}
+			else {
+				if ($refrest) {
+					echo '&';
+				}
+				else if (!empty($op_array['arg_types']) && 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);
+					}
+				}
+				echo str($arg[0], $EX);
+			}
+			if (isset($arg[1])) {
+				echo ' = ', str($arg[1], $EX);
+			}
+		}
+	}
+	// }}}
+	function duses(&$EX) // {{{
+	{
+		if ($EX['uses']) {
+			echo ' use(', implode(', ', $EX['uses']), ')';
+		}
+	}
+	// }}}
+	function dfunction($func, $indent = '', $decorations = array(), $nobody = false) // {{{
+	{
+		$this->detectNamespace($func['op_array']['function_name']);
+
+		if ($nobody) {
+			$EX = array();
+			$EX['op_array'] = &$func['op_array'];
+			$EX['recvs'] = array();
+			$EX['uses'] = array();
+		}
+		else {
+			ob_start();
+			$EX = &$this->dop_array($func['op_array'], $indent . INDENT);
+			$body = ob_get_clean();
+		}
+
+		$functionName = $this->stripNamespace($func['op_array']['function_name']);
+		$isExpression = false;
+		if ($functionName == '{closure}') {
+			$functionName = '';
+			$isExpression = true;
+		}
+		echo $isExpression ? '' : $indent;
+		if ($decorations) {
+			echo implode(' ', $decorations), ' ';
+		}
+		echo 'function', $functionName ? ' ' . $functionName : '', '(';
+		$this->dargs($EX);
+		echo ")";
+		$this->duses($EX);
+		if ($nobody) {
+			echo ";\n";
+		}
+		else {
+			if (!$isExpression) {
+				echo "\n";
+				echo $indent, "{\n";
+			}
+			else {
+				echo " {\n";
+			}
+
+			echo $body;
+			echo "$indent}";
+			if (!$isExpression) {
+				echo "\n";
+			}
+		}
+	}
+	// }}}
+	function dclass($class, $indent = '') // {{{
+	{
+		$this->detectNamespace($class['name']);
+
+		// {{{ class decl
+		if (!empty($class['doc_comment'])) {
+			echo $indent;
+			echo $class['doc_comment'];
+			echo "\n";
+		}
+		$isInterface = false;
+		$decorations = array();
+		if (!empty($class['ce_flags'])) {
+			if ($class['ce_flags'] & ZEND_ACC_INTERFACE) {
+				$isInterface = true;
+			}
+			else {
+				if ($class['ce_flags'] & ZEND_ACC_IMPLICIT_ABSTRACT_CLASS) {
+					$decorations[] = "abstract";
+				}
+				if ($class['ce_flags'] & ZEND_ACC_FINAL_CLASS) {
+					$decorations[] = "final";
+				}
+			}
+		}
+
+		echo $indent;
+		if ($decorations) {
+			echo implode(' ', $decorations), ' ';
+		}
+		echo $isInterface ? 'interface ' : 'class ', $this->stripNamespace($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), $newindent);
+					echo ";\n";
+				}
+			}
+		}
+		// }}}
+		// {{{ properties
+		$member_variables = isset($class['properties_info']) ? $class['properties_info'] : ($class['default_static_members'] + $class['default_properties']);
+		if ($member_variables) {
+			echo "\n";
+			$infos = !empty($class['properties_info']) ? $class['properties_info'] : null;
+			foreach ($member_variables as $name => $dummy) {
+				$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;
+				$static = false;
+				if (isset($info)) {
+					if ($info['flags'] & ZEND_ACC_STATIC) {
+						$static = true;
+					}
+				}
+				else if (isset($class['default_static_members'][$name])) {
+					$static = true;
+				}
+
+				if ($static) {
+					echo "static ";
+				}
+
+				$mangled = false;
+				if (!ZEND_ENGINE_2) {
+					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 ";
+						$mangled = true;
+						break;
+					case ZEND_ACC_PROTECTED:
+						echo "protected ";
+						$mangled = true;
+						break;
+					}
+				}
+
+				echo '$', $name;
+
+				if (isset($info['offset'])) {
+					$value = $class[$static ? 'default_static_members_table' : 'default_properties_table'][$info['offset']];
+				}
+				else {
+					$key = isset($info) ? $info['name'] . ($mangled ? "\000" : "") : $name;
+
+					$value = $class[$static ? 'default_static_members' : 'default_properties'][$key];
+				}
+				if (isset($value)) {
+					echo ' = ';
+					echo str(value($value), $newindent);
+				}
+				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";
+					}
+					$isAbstractMethod = false;
+					$decorations = array();
+					if (isset($opa['fn_flags'])) {
+						if (($opa['fn_flags'] & ZEND_ACC_ABSTRACT) && !$isInterface) {
+							$decorations[] = "abstract";
+							$isAbstractMethod = true;
+						}
+						if ($opa['fn_flags'] & ZEND_ACC_FINAL) {
+							$decorations[] = "final";
+						}
+						if ($opa['fn_flags'] & ZEND_ACC_STATIC) {
+							$decorations[] = "static";
+						}
+
+						switch ($opa['fn_flags'] & ZEND_ACC_PPP_MASK) {
+							case ZEND_ACC_PUBLIC:
+								$decorations[] = "public";
+								break;
+							case ZEND_ACC_PRIVATE:
+								$decorations[] = "private";
+								break;
+							case ZEND_ACC_PROTECTED:
+								$decorations[] = "protected";
+								break;
+							default:
+								$decorations[] = "<visibility error>";
+								break;
+						}
+					}
+					$this->dfunction($func, $newindent, $decorations, $isInterface || $isAbstractMethod);
+					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 decompileDasm($content) // {{{
+	{
+		$this->dc = $content;
+	}
+	// }}}
+	function output() // {{{
+	{
+		echo "<?". "php\n\n";
+		foreach ($this->dc['class_table'] as $key => $class) {
+			if ($key{0} != "\0") {
+				$this->dclass($class);
+				echo "\n";
+			}
+		}
+
+		foreach ($this->dc['function_table'] as $key => $func) {
+			if ($key{0} != "\0") {
+				$this->dfunction($func);
+				echo "\n";
+			}
+		}
+
+		$this->dop_array($this->dc['op_array']);
+		echo "\n?" . ">\n";
+
+		if (!empty($this->test)) {
+			$this->outputUnusedOp();
+		}
+		return true;
+	}
+	// }}}
+	function outputUnusedOp() // {{{
+	{
+		for ($i = 0; $opname = xcache_get_opcode($i); $i ++) {
+			if ($opname == 'UNDEF')  {
+				continue;
+			}
+
+			if (!isset($this->usedOps[$i])) {
+				echo "not covered opcode ", $opname, "\n";
+			}
+		}
+	}
+	// }}}
+}
+
+// {{{ defines
+define('ZEND_ENGINE_2_4', PHP_VERSION >= "5.3.99");
+define('ZEND_ENGINE_2_3', ZEND_ENGINE_2_4 || PHP_VERSION >= "5.3.");
+define('ZEND_ENGINE_2_2', ZEND_ENGINE_2_3 || PHP_VERSION >= "5.2.");
+define('ZEND_ENGINE_2_1', ZEND_ENGINE_2_2 || PHP_VERSION >= "5.1.");
+define('ZEND_ENGINE_2',   ZEND_ENGINE_2_1 || PHP_VERSION >= "5.0.");
+
+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);
+if (ZEND_ENGINE_2_4) {
+	define('ZEND_ACC_TRAIT',                  0x120);
+}
+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);
+
+if (ZEND_ENGINE_2_4) {
+	define('ZEND_FETCH_GLOBAL',           0x00000000);
+	define('ZEND_FETCH_LOCAL',            0x10000000);
+	define('ZEND_FETCH_STATIC',           0x20000000);
+	define('ZEND_FETCH_STATIC_MEMBER',    0x30000000);
+	define('ZEND_FETCH_GLOBAL_LOCK',      0x40000000);
+	define('ZEND_FETCH_LEXICAL',          0x50000000);
+
+	define('ZEND_FETCH_TYPE_MASK',        0x70000000);
+}
+else {
+	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_FETCH_CLASS_STATIC',     7);
+if (ZEND_ENGINE_2_4) {
+	define('ZEND_FETCH_CLASS_TRAIT',     14);
+}
+if (ZEND_ENGINE_2_3) {
+	define('ZEND_FETCH_CLASS_MASK',     0xF);
+}
+
+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));
+if (ZEND_ENGINE_2_4) {
+	define('EXT_TYPE_UNUSED',     (1<<5));
+}
+else {
+	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_BOOL',     ZEND_ENGINE_2 ? 3 : 6);
+define('IS_ARRAY',    4);
+define('IS_OBJECT',   5);
+define('IS_STRING',   ZEND_ENGINE_2 ? 6 : 3);
+define('IS_RESOURCE', 7);
+define('IS_CONSTANT', 8);
+define('IS_CONSTANT_ARRAY',   9);
+/* Ugly hack to support constants as static array indices */
+define('IS_CONSTANT_TYPE_MASK',   0x0f);
+define('IS_CONSTANT_UNQUALIFIED', 0x10);
+define('IS_CONSTANT_INDEX',       0x80);
+define('IS_LEXICAL_VAR',          0x20);
+define('IS_LEXICAL_REF',          0x40);
+
+@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_UNSET_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_STATIC_METHOD_CALL' => -1,
+	'XC_INIT_METHOD_CALL' => -1,
+	'XC_VERIFY_ABSTRACT_CLASS' => -1,
+	'XC_DECLARE_CLASS' => -1,
+	'XC_DECLARE_INHERITED_CLASS' => -1,
+	'XC_DECLARE_INHERITED_CLASS_DELAYED' => -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_ISSET_ISEMPTY' => -1,
+	'XC_INIT_FCALL_BY_FUNC' => -1,
+	'XC_DO_FCALL_BY_FUNC' => -1,
+	'XC_DECLARE_FUNCTION_OR_CLASS' => -1,
+	'XC_INIT_NS_FCALL_BY_NAME' => -1,
+	'XC_GOTO' => -1,
+	'XC_CATCH' => -1,
+	'XC_THROW' => -1,
+	'XC_INSTANCEOF' => -1,
+	'XC_DECLARE_FUNCTION' => -1,
+	'XC_RAISE_ABSTRACT_ERROR' => -1,
+	'XC_DECLARE_CONST' => -1,
+	'XC_USER_OPCODE' => -1,
+	'XC_JMP_SET' => -1,
+	'XC_DECLARE_LAMBDA_FUNCTION' => -1,
+) as $k => $v) {
+	if (!defined($k)) {
+		define($k, $v);
+	}
+}
+// }}}
+
Index: /tags/3.0.0-rc1/bin/phpdop.phpr
===================================================================
--- /tags/3.0.0-rc1/bin/phpdop.phpr	(revision 982)
+++ /tags/3.0.0-rc1/bin/phpdop.phpr	(revision 982)
@@ -0,0 +1,130 @@
+#! /usr/bin/php
+<?php
+
+$srcdir = dirname(__FILE__);
+require_once("$srcdir/../lib/Decompiler.class.php");
+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['constant'], true);
+
+	case 2: // IS_TMP_VAR
+		return 't@' . $op['var'];
+
+	case 4:
+		return 'v$' . $op['var'];
+
+	case 8: // UNUSED
+		if (isset($op['opline_num'])) {
+			return 'l#' . $op['opline_num'];
+		}
+		else {
+			return '-';
+		}
+
+	default:
+		return $op['op_type'] . $op['var'];
+	}
+}
+
+function dump_opcodes($opcodes, $indent = '')
+{
+	global $decompiler;
+
+	$types = array('result' => 5, 'op1' => 20, 'op2' => 20);
+	foreach ($decompiler->fixOpcode($opcodes) 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);
+		}
+	}
+}
+
+if (!isset($argv[1])) {
+	die("Usage: $argv[0] <file>\n");
+}
+$decompiler = new Decompiler();
+if (isset($argv[2])) {
+	eval('$pk = ' . file_get_contents($argv[2]) . ';');
+}
+else {
+	$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($classes)) {
+	foreach ($classes as $name => $class) {
+		dump_class($name, $class);
+	}
+}
+if (isset($funcs)) {
+	foreach ($funcs as $name => $func) {
+		dump_function($name, $func);
+	}
+}
+if (isset($op_array)) {
+	dump_opcodes($op_array['opcodes']);
+}
+
Index: /tags/3.0.0-rc1/bin/phpdc.phpr
===================================================================
--- /tags/3.0.0-rc1/bin/phpdc.phpr	(revision 982)
+++ /tags/3.0.0-rc1/bin/phpdc.phpr	(revision 982)
@@ -0,0 +1,33 @@
+#! /usr/bin/php -dopen_basedir=
+<?php
+
+$srcdir = dirname(__FILE__);
+require_once("$srcdir/../lib/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[2])) {
+	eval('$dc->dc = ' . file_get_contents($argv[2]) . ';');
+}
+else 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->decompileString($phpcode);
+}
+$dc->output();
+
Index: /tags/3.0.0-rc1/COPYING
===================================================================
--- /tags/3.0.0-rc1/COPYING	(revision 609)
+++ /tags/3.0.0-rc1/COPYING	(revision 609)
@@ -0,0 +1,31 @@
+
+
+Copyright (c) 2005-2009, 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.
+
