Index: /tags/2.0.1/.cvsignore
===================================================================
--- /tags/2.0.1/.cvsignore	(revision 966)
+++ /tags/2.0.1/.cvsignore	(revision 966)
@@ -0,0 +1,34 @@
+acinclude.m4
+aclocal.m4
+build
+config.cache
+config.guess
+config.h
+config.h.in
+config.log
+config.nice
+config.status
+config.sub
+configure
+configure.in
+conftest
+conftest.c
+.deps
+include
+includes.i
+install-sh
+libtool
+ltmain.sh
+Makefile
+Makefile.fragments
+Makefile.global
+Makefile.objects
+missing
+mkinstalldirs
+modules
+processor.h
+processor.out
+processor_real.c
+run-tests.php
+structinfo.m4
+autom4te.cache
Index: /tags/2.0.1/.vimrc
===================================================================
--- /tags/2.0.1/.vimrc	(revision 966)
+++ /tags/2.0.1/.vimrc	(revision 966)
@@ -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/2.0.1/AUTHORS
===================================================================
--- /tags/2.0.1/AUTHORS	(revision 966)
+++ /tags/2.0.1/AUTHORS	(revision 966)
@@ -0,0 +1,1 @@
+mOo <phpxcache@gmail.com>
Index: /tags/2.0.1/COPYING
===================================================================
--- /tags/2.0.1/COPYING	(revision 966)
+++ /tags/2.0.1/COPYING	(revision 966)
@@ -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.
+
Index: /tags/2.0.1/ChangeLog
===================================================================
--- /tags/2.0.1/ChangeLog	(revision 966)
+++ /tags/2.0.1/ChangeLog	(revision 966)
@@ -0,0 +1,180 @@
+2.0.1 2012-??-??
+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/2.0.1/Decompiler.class.php
===================================================================
--- /tags/2.0.1/Decompiler.class.php	(revision 966)
+++ /tags/2.0.1/Decompiler.class.php	(revision 966)
@@ -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/2.0.1/INSTALL
===================================================================
--- /tags/2.0.1/INSTALL	(revision 966)
+++ /tags/2.0.1/INSTALL	(revision 966)
@@ -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/2.0.1/Makefile.frag
===================================================================
--- /tags/2.0.1/Makefile.frag	(revision 966)
+++ /tags/2.0.1/Makefile.frag	(revision 966)
@@ -0,0 +1,46 @@
+XCACHE_PROC_SRC=$(srcdir)/processor/main.m4
+XCACHE_PROC_OUT=$(builddir)/processor.out
+XCACHE_PROC_C=$(builddir)/processor_real.c
+XCACHE_PROC_H=$(builddir)/processor.h
+XCACHE_INCLUDES_SRC=$(srcdir)/includes.c
+XCACHE_INCLUDES_I=$(builddir)/includes.i
+XCACHE_STRUCTINFO_OUT=$(builddir)/structinfo.m4
+
+$(XCACHE_INCLUDES_I): $(XCACHE_INCLUDES_SRC) $(srcdir)/xcache.h
+	$(CC) -I. -I$(srcdir) $(COMMON_FLAGS) $(CFLAGS_CLEAN) $(EXTRA_CFLAGS) -E $(XCACHE_INCLUDES_SRC) -o $(XCACHE_INCLUDES_I)
+
+$(XCACHE_STRUCTINFO_OUT): $(XCACHE_INCLUDES_I) $(srcdir)/mkstructinfo.awk
+	@echo $(XCACHE_STRUCTINFO_OUT) is optional if XCache test is not enabled, feel free if it awk failed to produce it
+	-$(XCACHE_AWK) -f $(srcdir)/mkstructinfo.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)
+
+$(builddir)/processor.lo: $(XCACHE_PROC_C) $(XCACHE_PROC_H) $(srcdir)/processor.c
+processor.lo: $(XCACHE_PROC_C) $(XCACHE_PROC_H) $(srcdir)/processor.c
+
+$(builddir)/disassembler.lo: $(XCACHE_PROC_H) $(srcdir)/processor.c
+disassembler.lo: $(XCACHE_PROC_H) $(srcdir)/processor.c
+
+$(builddir)/opcode_spec.lo: $(srcdir)/xcache.h $(srcdir)/opcode_spec.c $(srcdir)/opcode_spec_def.h $(srcdir)/const_string.h
+opcode_spec.lo: $(srcdir)/xcache.h $(srcdir)/opcode_spec.c $(srcdir)/opcode_spec_def.h $(srcdir)/const_string.h
+
+$(builddir)/xcache.lo: $(XCACHE_PROC_H) $(srcdir)/xc_shm.h $(srcdir)/stack.h $(srcdir)/xcache_globals.h $(srcdir)/xcache.c $(srcdir)/foreachcoresig.h $(srcdir)/utils.h
+xcache.lo: $(XCACHE_PROC_H) $(srcdir)/xc_shm.h $(srcdir)/stack.h $(srcdir)/xcache_globals.h $(srcdir)/xcache.c $(srcdir)/foreachcoresig.h $(srcdir)/utils.h
+
+xcachesvnclean: clean
+	cat $(srcdir)/.cvsignore | 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/2.0.1/NEWS
===================================================================
--- /tags/2.0.1/NEWS	(revision 966)
+++ /tags/2.0.1/NEWS	(revision 966)
@@ -0,0 +1,72 @@
+2.0.1 2012-??-??
+========
+ * 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/2.0.1/README
===================================================================
--- /tags/2.0.1/README	(revision 966)
+++ /tags/2.0.1/README	(revision 966)
@@ -0,0 +1,1 @@
+Please check http://xcache.lighttpd.net/ and https://groups.google.com/forum/?fromgroups#!forum/xcache for help
Index: /tags/2.0.1/THANKS
===================================================================
--- /tags/2.0.1/THANKS	(revision 966)
+++ /tags/2.0.1/THANKS	(revision 966)
@@ -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/2.0.1/admin/common-en.lang.php
===================================================================
--- /tags/2.0.1/admin/common-en.lang.php	(revision 966)
+++ /tags/2.0.1/admin/common-en.lang.php	(revision 966)
@@ -0,0 +1,5 @@
+<?php
+
+$GLOBALS['config']['show_todo_strings'] = false;
+
+?>
Index: /tags/2.0.1/admin/common-zh-simplified-utf-8.lang.php
===================================================================
--- /tags/2.0.1/admin/common-zh-simplified-utf-8.lang.php	(revision 966)
+++ /tags/2.0.1/admin/common-zh-simplified-utf-8.lang.php	(revision 966)
@@ -0,0 +1,126 @@
+<?php
+
+$strings = array(
+		'Cache Legends'
+		=> 'Cache 帮助',
+		'List Legends'
+		=> 'List 帮助',
+		'XCache Administration Help'
+		=> 'XCache 管理页面帮助信息',
+		'Help'
+		=> '帮助',
+		'Slots'
+		=> '槽',
+		'Size'
+		=> '大小',
+		'Avail'
+		=> '剩余',
+		'Used'
+		=> '已用',
+		'Clear'
+		=> '清除',
+		'Sure to clear?'
+		=> '确认要清除吗?',
+		'Compiling'
+		=> '编译中',
+		'% Free'
+		=> '% 剩余',
+		'% Used'
+		=> '% 已用',
+		'Hits'
+		=> '命中',
+		'Hits 24H'
+		=> '24H 分布',
+		'Hits/H'
+		=> '命中/H',
+		'Hits/S'
+		=> '命中/S',
+		'Updates'
+		=> '更新',
+		'Clogs'
+		=> '阻塞',
+		'OOMs'
+		=> '内存不足',
+		'Errors'
+		=> '错误',
+		'Protected'
+		=> '保护',
+		'Cached'
+		=> '缓存',
+		'Deleted'
+		=> '待删',
+		'Delete'
+		=> '删除',
+		'Free Blocks'
+		=> '空闲块',
+
+		'entry'
+		=> '项目',
+		'Refcount'
+		=> '引用数',
+		'PhpShared'
+		=> '共享',
+		'SrcSize'
+		=> '源大小',
+		'Modify'
+		=> '修改',
+		'device'
+		=> '设备',
+		'inode'
+		=> 'Inode',
+		'hash'
+		=> 'Hash',
+		'Access'
+		=> '访问',
+		'Create'
+		=> '创建',
+		'See also'
+		=> '建议参考',
+		'GC'
+		=> 'GC',
+		'Legends:'
+		=> '图例:',
+		'Used Blocks'
+		=> '已用块',
+		'Free Blocks'
+		=> '未用块',
+		'Total'
+		=> '总共',
+		'Cache'
+		=> '缓冲区',
+		'Caches'
+		=> '缓冲区',
+		'Cached'
+		=> '缓冲',
+		'php Cached'
+		=> '缓冲的 php 脚本',
+		'php Deleted'
+		=> '待删 php 脚本',
+		'var Cached'
+		=> '缓冲的变量',
+		'var Deleted'
+		=> '待删变量',
+		'Statistics'
+		=> '摘要统计',
+		'List PHP'
+		=> '列出PHP',
+		'List Var Data'
+		=> '列变量数据',
+		'XCache %s Administration'
+		=> 'XCache %s 管理页面',
+		'size'
+		=> '大小',
+		'offset'
+		=> '位置',
+		'Module Info'
+		=> '模块信息',
+		'Remove Selected'
+		=> '删除所选',
+		'Editing Variable %s'
+		=> '正在编辑变量 %s',
+		'Set %s in config to enable'
+		=> '请在配置文件中设置 %s 启用本功能',
+		''
+		=> '',
+		);
+
Index: /tags/2.0.1/admin/common-zh-traditional-utf-8.lang.php
===================================================================
--- /tags/2.0.1/admin/common-zh-traditional-utf-8.lang.php	(revision 966)
+++ /tags/2.0.1/admin/common-zh-traditional-utf-8.lang.php	(revision 966)
@@ -0,0 +1,126 @@
+<?php
+
+$strings = array(
+		'Cache Legends'
+		=> 'Cache 說明',
+		'List Legends'
+		=> 'List 說明',
+		'XCache Administration Help'
+		=> 'XCache 管理頁面說明訊息',
+		'Help'
+		=> '說明',
+		'Slots'
+		=> '槽',
+		'Size'
+		=> '大小',
+		'Avail'
+		=> '剩餘',
+		'Used'
+		=> '已用',
+		'Clear'
+		=> '清除',
+		'Sure to clear?'
+		=> '確認要清除嗎?',
+		'Compiling'
+		=> '編譯中',
+		'% Free'
+		=> '% 剩余',
+		'% Used'
+		=> '% 已用',
+		'Hits'
+		=> '命中',
+		'Hits 24H'
+		=> '24H 分布',
+		'Hits/H'
+		=> '命中/H',
+		'Hits/S'
+		=> '命中/S',
+		'Updates'
+		=> '更新',
+		'Clogs'
+		=> '阻塞',
+		'OOMs'
+		=> '記憶體不足',
+		'Errors'
+		=> '错误',
+		'Protected'
+		=> '保護',
+		'Cached'
+		=> '快取',
+		'Deleted'
+		=> '待刪',
+		'Delete'
+		=> '刪除',
+		'Free Blocks'
+		=> '空閒塊',
+
+		'entry'
+		=> '項目',
+		'Refcount'
+		=> '引用數',
+		'PhpShared'
+		=> '共享',
+		'SrcSize'
+		=> '原始檔案大小',
+		'Modify'
+		=> '修改',
+		'device'
+		=> '設備',
+		'inode'
+		=> 'Inode',
+		'hash'
+		=> 'Hash',
+		'Access'
+		=> '存取',
+		'Create'
+		=> '建立',
+		'See also'
+		=> '建議參考',
+		'GC'
+		=> 'GC',
+		'Legends:'
+		=> '图例:',
+		'Used Blocks'
+		=> '已用块',
+		'Free Blocks'
+		=> '未用块',
+		'Total'
+		=> '总共',
+		'Cache'
+		=> '快取',
+		'Caches'
+		=> '快取',
+		'Cached'
+		=> '快取',
+		'php Cached'
+		=> '快取的 php 指令',
+		'php Deleted'
+		=> '待刪 php 指令',
+		'var Cached'
+		=> '快取的變數',
+		'var Deleted'
+		=> '待刪變數',
+		'Statistics'
+		=> '摘要統計',
+		'List PHP'
+		=> '列出PHP',
+		'List Var Data'
+		=> '列變數資料',
+		'XCache %s Administration'
+		=> 'XCache %s 管理頁面',
+		'size'
+		=> '大小',
+		'offset'
+		=> '位置',
+		'Module Info'
+		=> '組元訊息',
+		'Remove Selected'
+		=> '移除所选',
+		'Editing Variable %s'
+		=> '正在编辑变量 %s',
+		'Set %s in config to enable'
+		=> '請在配置文件中設置 %s 啟用本功能',
+		''
+		=> '',
+		);
+
Index: /tags/2.0.1/admin/common.php
===================================================================
--- /tags/2.0.1/admin/common.php	(revision 966)
+++ /tags/2.0.1/admin/common.php	(revision 966)
@@ -0,0 +1,142 @@
+<?php
+
+function xcache_validateFileName($name)
+{
+	return preg_match('!^[a-zA-Z0-9._-]+$!', $name);
+}
+
+function get_language_file_ex($name, $l, $s)
+{
+	static $lmap = array(
+			'zh'    => 'zh-simplified',
+			'zh-hk' => 'zh-traditional',
+			'zh-tw' => 'zh-traditional',
+			);
+	static $smap = array(
+			'gbk'     => 'gb2312',
+			'gb18030' => 'gb2312',
+			);
+
+	if (isset($lmap[$l])) {
+		$l = $lmap[$l];
+	}
+	$file = "$name-$l-$s.lang.php";
+	if (xcache_validateFileName($file) && file_exists($file)) {
+		return $file;
+	}
+	if (isset($smap[$s])) {
+		$s = $smap[$s];
+		$file = "$name-$l-$s.lang.php";
+		if (xcache_validateFileName($file) && file_exists($file)) {
+			return $file;
+		}
+	}
+	$file = "$name-$l.lang.php";
+	if (xcache_validateFileName($file) && file_exists($file)) {
+		return $file;
+	}
+	return null;
+}
+
+function get_language_file($name)
+{
+	global $config;
+	$s = strtolower($config['charset']);
+	if (!empty($config['lang'])) {
+		$l = strtolower($config['lang']);
+		$file = get_language_file_ex($name, $l, $s);
+		if (!isset($file)) {
+			$l = strtok($l, ':-');
+			$file = get_language_file_ex($name, $l, $s);
+		}
+	}
+	else if (!empty($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
+		foreach (explode(',', str_replace(' ', '', $_SERVER['HTTP_ACCEPT_LANGUAGE'])) as $l) {
+			$l = strtok($l, ':;');
+			$file = get_language_file_ex($name, $l, $s);
+			if (isset($file)) {
+				$config['lang'] = $l;
+				break;
+			}
+			if (strpos($l, '-') !== false) {
+				$ll = strtok($l, ':-');
+				$file = get_language_file_ex($name, $ll, $s);
+				if (isset($file)) {
+					$config['lang'] = $l;
+					break;
+				}
+			}
+		}
+	}
+	return isset($file) ? $file : "$name-en.lang.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">' . htmlspecialchars($str) . '</span>';
+	}
+	return $str;
+}
+
+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();
+include("./config.default.php");
+if (file_exists("./config.php")) {
+	include("./config.php");
+}
+
+include(get_language_file("common"));
+if (empty($config['lang'])) {
+	$config['lang'] = 'en-us';
+}
+
+header("Cache-Control: no-cache, must-revalidate");
+header("Expires: Sat, 26 Jul 1997 05:00:00 GMT");
+
+?>
Index: /tags/2.0.1/admin/config.default.php
===================================================================
--- /tags/2.0.1/admin/config.default.php	(revision 966)
+++ /tags/2.0.1/admin/config.default.php	(revision 966)
@@ -0,0 +1,26 @@
+<?php
+
+// this is default config
+// DO NOT rename/delete/modify this file
+// see config.example.php
+
+// detected by browser
+// $config['lang'] = 'en-us';
+
+$config['charset'] = "UTF-8";
+
+// translators only
+$config['show_todo_strings'] = false;
+
+// 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;
+
+// this ob filter is applied for the cache list, not the whole page
+$config['path_nicer'] = 'ob_filter_path_nicer_default';
+
+?>
Index: /tags/2.0.1/admin/config.example.php
===================================================================
--- /tags/2.0.1/admin/config.example.php	(revision 966)
+++ /tags/2.0.1/admin/config.example.php	(revision 966)
@@ -0,0 +1,74 @@
+<?php
+
+// this is example config
+// DO NOT rename/delete/modify this file
+// if you want to customize config, copy this file and name it as config.php
+// 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;
+
+// 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;
+
+// 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 builtin http auth is enforce for security reason
+// if http auth is disabled, any vhost user that can upload *.php, will see all variable data cached in XCache
+
+// but if you have your own login/permission system, you can use 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/2.0.1/admin/edit.php
===================================================================
--- /tags/2.0.1/admin/edit.php	(revision 966)
+++ /tags/2.0.1/admin/edit.php	(revision 966)
@@ -0,0 +1,45 @@
+<?php
+
+include("./common.php");
+
+if (!isset($_GET['name'])) {
+	die("missing name");
+}
+
+$name = $_GET['name'];
+// trigger auth
+$vcnt = xcache_count(XC_TYPE_VAR);
+
+if ($_SERVER['REQUEST_METHOD'] == 'POST') {
+	if (!empty($config['enable_eval'])) {
+		eval('$value = ' . $_POST['value']);
+	}
+	else {
+		$value = $_POST['value'];
+	}
+	xcache_set($name, $value);
+	header("Location: xcache.php?type=" . XC_TYPE_VAR);
+	exit;
+}
+$value = xcache_get($name);
+if (!empty($enable['enable_eval'])) {
+	$value = var_export($value, true);
+	$editable = true;
+}
+else {
+	if (is_string($value)) {
+		$editable = true;
+	}
+	else {
+		$editable = false;
+		$value = var_export($value, true);
+	}
+}
+
+$php_version = phpversion();
+$xcache_version = XCACHE_VERSION;
+$xcache_modules = XCACHE_MODULES;
+
+include("edit.tpl.php");
+
+?>
Index: /tags/2.0.1/admin/edit.tpl.php
===================================================================
--- /tags/2.0.1/admin/edit.tpl.php	(revision 966)
+++ /tags/2.0.1/admin/edit.tpl.php	(revision 966)
@@ -0,0 +1,18 @@
+<?php include("header.tpl.php"); ?>
+<?php
+$h_name = htmlspecialchars($name);
+$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("footer.tpl.php"); ?>
Index: /tags/2.0.1/admin/footer.tpl.php
===================================================================
--- /tags/2.0.1/admin/footer.tpl.php	(revision 966)
+++ /tags/2.0.1/admin/footer.tpl.php	(revision 966)
@@ -0,0 +1,9 @@
+<div class="footnote">
+<?php echo <<<EOS
+PHP {$php_version} Powered By: XCache {$xcache_version}, {$xcache_modules}
+EOS;
+?>
+</div>
+
+</body>
+</html>
Index: /tags/2.0.1/admin/header.tpl.php
===================================================================
--- /tags/2.0.1/admin/header.tpl.php	(revision 966)
+++ /tags/2.0.1/admin/header.tpl.php	(revision 966)
@@ -0,0 +1,17 @@
+<!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>
+<?php
+echo <<<HEAD
+	<meta http-equiv="Content-Type" content="text/html; charset=$config[charset]" />
+	<meta http-equiv="Content-Language" content="$config[lang]" />
+	<script type="text/javascript" src="tablesort.js" charset="$config[charset]"></script>
+HEAD;
+?>
+
+	<link rel="stylesheet" type="text/css" href="xcache.css" />
+	<title><?php echo sprintf(_T("XCache %s Administration"), $xcache_version); ?></title>
+</head>
+
+<body>
+<h1><?php echo sprintf(_T("XCache %s Administration"), $xcache_version); ?></h1>
Index: /tags/2.0.1/admin/help-en.lang.php
===================================================================
--- /tags/2.0.1/admin/help-en.lang.php	(revision 966)
+++ /tags/2.0.1/admin/help-en.lang.php	(revision 966)
@@ -0,0 +1,37 @@
+<h2><?php echo _T('Cache Legends'); ?></h2>
+<dl>
+<dt><?php echo _T('Slots'); ?>: </dt><dd>Number of hash slots. the setting from your php.ini</dd>
+<dt><?php echo _T('Size'); ?>: </dt><dd>Cache Size, Size of the cache (or cache chunk), in bytes</dd>
+<dt><?php echo _T('Avail'); ?>: </dt><dd>Available Memory, free memory in bytes of this cache</dd>
+<dt><?php echo _T('% Used'); ?>: </dt><dd>Percent, A bar shows how much memory available in percent, and memory blocks status</dd>
+<dt><?php echo _T('Clear'); ?>: </dt><dd>Clear Button, Press the button to clean this cache</dd>
+<dt><?php echo _T('Compiling'); ?>: </dt><dd>Compiling flag, "yes" if the cache is busy compiling php script</dd>
+<dt><?php echo _T('Hits'); ?>: </dt><dd>Cache Hits, hit=a var/php is loaded from this cache</dd>
+<dt><?php echo _T('Hits/H'); ?>: </dt><dd>Average Hits per Hour. Only last 24 hours is logged</dd>
+<dt><?php echo _T('Hits 24H'); ?>: </dt><dd>Hits 24 Hours. Hits graph of last 24 hours</dd>
+<dt><?php echo _T('Hits/S'); ?>: </dt><dd>Average Hits per Second. Only last 5 seconds is logged</dd>
+<dt><?php echo _T('Updates'); ?>: </dt><dd>Cache Updates</dd>
+<dt><?php echo _T('Clogs'); ?>: </dt><dd>Compiling Clogs, clog=compiling is needed but avoided to wait(be blocked) when the cache is busy compiling already</dd>
+<dt><?php echo _T('OOMs'); ?>: </dt><dd>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</dd>
+<dt><?php echo _T('Errors'); ?>: </dt><dd>Compiler errors, how many times your script is compiled but failed. You should really check what is happening if you see this value increase. See <a href="http://www.php.net/manual/en/ref.errorfunc.php#ini.error-log">ini.error-log</a> and <a href="http://cn2.php.net/manual/en/ref.errorfunc.php#ini.display-errors">ini.display-errors</a></dd>
+<dt><?php echo _T('Protected'); ?>: </dt><dd>Whether <a href="http://xcache.lighttpd.net/wiki/ReadonlyProtection">readonly_protection</a> is available and enable on this cache</dd>
+<dt><?php echo _T('Cached'); ?>: </dt><dd>Number of entries stored in this cache</dd>
+<dt><?php echo _T('Deleted'); ?>: </dt><dd>Number of entries is pending in delete list (expired but referenced)</dd>
+<dt><?php echo _T('GC'); ?>: </dt><dd>Seconds count down of Garbage Collection</dd>
+<dt><?php echo _T('Free Blocks'); ?>: </dt><dd>Free blocks list in the specified cache</dd>
+</dl>
+
+<h2><?php echo _T('List Legends'); ?></h2>
+<dl>
+<dt><?php echo _T('entry'); ?>: </dt><dd>The entry name or filename</dd>
+<dt><?php echo _T('Hits'); ?>: </dt><dd>Times this entry is hit (loaded from this cache)</dd>
+<dt><?php echo _T('Refcount'); ?>: </dt><dd>Reference count of this entry is holded by a php request</dd>
+<dt><?php echo _T('Size'); ?>: </dt><dd>Size in bytes of this entry in the cache</dd>
+<dt><?php echo _T('PhpShared'); ?>: </dt><dd>Count of entry sharing this php data</dd>
+<dt><?php echo _T('SrcSize'); ?>: </dt><dd>Size of the source file</dd>
+<dt><?php echo _T('Modify'); ?>: </dt><dd>Last modified time of the source file</dd>
+<dt><?php echo _T('device'); ?>: </dt><dd>device number of the source file</dd>
+<dt><?php echo _T('inode'); ?>: </dt><dd>inode number of the source file</dd>
+<dt><?php echo _T('Access'); ?>: </dt><dd>Last access time of the cached entry</dd>
+<dt><?php echo _T('Create'); ?>: </dt><dd>The time when this entry is stored</dd>
+</dl>
Index: /tags/2.0.1/admin/help-zh-simplified-utf-8.lang.php
===================================================================
--- /tags/2.0.1/admin/help-zh-simplified-utf-8.lang.php	(revision 966)
+++ /tags/2.0.1/admin/help-zh-simplified-utf-8.lang.php	(revision 966)
@@ -0,0 +1,37 @@
+<h2><?php echo _T('Cache Legends'); ?></h2>
+<dl>
+<dt><?php echo _T('Slots'); ?>: </dt><dd>Hash 槽个数, 对应 php.ini 里的设置</dd>
+<dt><?php echo _T('Size'); ?>: </dt><dd>共享内存区大小, 单位: 字节</dd>
+<dt><?php echo _T('Avail'); ?>: </dt><dd>可用内存, 对应共享内存区的剩余内存字节数</dd>
+<dt><?php echo _T('% Used'); ?>: </dt><dd>百分比, 条状显示可用内存的比例, 以及显示分配块状态</dd>
+<dt><?php echo _T('Clear'); ?>: </dt><dd>清除按钮, 点击按钮清除对应共享内存区的数据</dd>
+<dt><?php echo _T('Compiling'); ?>: </dt><dd>编译标记, 当共享内存区正在编译 php 脚本时标记为 "yes"</dd>
+<dt><?php echo _T('Hits'); ?>: </dt><dd>共享内存命中次数, 命中=从该共享内存载入php或者变量</dd>
+<dt><?php echo _T('Hits/H'); ?>: </dt><dd>每小时命中次数. 只统计最后 24 小时</dd>
+<dt><?php echo _T('Hits 24H'); ?>: </dt><dd>24 小时命中分布图. 图表现是最后 24 小时的命中次数</dd>
+<dt><?php echo _T('Hits/S'); ?>: </dt><dd>每秒命中次数. 只统计最后 5 秒</dd>
+<dt><?php echo _T('Updates'); ?>: </dt><dd>共享内存更新次数</dd>
+<dt><?php echo _T('Clogs'); ?>: </dt><dd>编译阻塞跳过, 阻塞=当需该共享内存区负责编译时, 其他进程/现成无法访问此共享内存. 跳过=XCache 自动判断阻塞的共享内存区自动跳过阻塞等待, 直接使用非共享内存方式继续处理请求</dd>
+<dt><?php echo _T('OOMs'); ?>: </dt><dd>内存不足次数, 显示需要存储新数据但是共享内存区内存不足的次数. 如果出现太频繁请考虑加大配置中的 xcache.size 或者 xcache.var_size</dd>
+<dt><?php echo _T('Errors'); ?>: </dt><dd>编译错误, 显示您的脚本被编译时出错的次数. 如果您发现这个数字不断增长, 您应该检查什么脚本产生错误. 参考 <a href="http://www.php.net/manual/en/ref.errorfunc.php#ini.error-log">ini.error-log</a> and <a href="http://cn2.php.net/manual/en/ref.errorfunc.php#ini.display-errors">ini.display-errors</a></dd>
+<dt><?php echo _T('Protected'); ?>: </dt><dd>显示该 Cache 是否支持并启用 <a href="http://xcache.lighttpd.net/xcache/wiki/ReadonlyProtection">readonly_protection</a></dd>
+<dt><?php echo _T('Cached'); ?>: </dt><dd>共享内存于该共享内存区的项目条数</dd>
+<dt><?php echo _T('Deleted'); ?>: </dt><dd>共享内存区内将要删除的项目 (已经删除但是还被某些进程占用)</dd>
+<dt><?php echo _T('GC'); ?>: </dt><dd>垃圾回收的倒计时</dd>
+<dt><?php echo _T('Free Blocks'); ?>: </dt><dd>共享内存区内的空闲内存块</dd>
+</dl>
+
+<h2><?php echo _T('List Legends'); ?></h2>
+<dl>
+<dt><?php echo _T('entry'); ?>: </dt><dd>项目名或者文件名</dd>
+<dt><?php echo _T('Hits'); ?>: </dt><dd>该项目被命中的次数 (从共享内存区载入)</dd>
+<dt><?php echo _T('Refcount'); ?>: </dt><dd>项目依然被其他进程占据的引用次数</dd>
+<dt><?php echo _T('Size'); ?>: </dt><dd>项目在共享内存里占用字节数</dd>
+<dt><?php echo _T('PhpShared'); ?>: </dt><dd>与本项目相同 PHP 代码的个数</dd>
+<dt><?php echo _T('SrcSize'); ?>: </dt><dd>源文件大小</dd>
+<dt><?php echo _T('Modify'); ?>: </dt><dd>源文件最后修改时间</dd>
+<dt><?php echo _T('device'); ?>: </dt><dd>源文件所在设备ID</dd>
+<dt><?php echo _T('inode'); ?>: </dt><dd>源文件的inode</dd>
+<dt><?php echo _T('Access'); ?>: </dt><dd>最后访问该项目的时间</dd>
+<dt><?php echo _T('Create'); ?>: </dt><dd>该项目被创建于共享内的时间</dd>
+</dl>
Index: /tags/2.0.1/admin/help-zh-traditional-utf-8.lang.php
===================================================================
--- /tags/2.0.1/admin/help-zh-traditional-utf-8.lang.php	(revision 966)
+++ /tags/2.0.1/admin/help-zh-traditional-utf-8.lang.php	(revision 966)
@@ -0,0 +1,34 @@
+<h2><?php echo _T('Cache Legends'); ?></h2>
+<dl>
+<dt><?php echo _T('Slots'); ?>: </dt><dd>Hash 槽個數，對應 php.ini 裡的設置</dd>
+<dt><?php echo _T('Size'); ?>: </dt><dd>共享記憶體區大小，單位：位元</dd>
+<dt><?php echo _T('Avail'); ?>: </dt><dd>可用記憶體，對應共享記憶體區的剩餘記憶體位元數</dd>
+<dt><?php echo _T('% Used'); ?>: </dt><dd>百分比，條狀顯示可用記憶體的比例</dd>
+<dt><?php echo _T('Clear'); ?>: </dt><dd>清除按鈕，點擊按鈕清除對應共享記憶體區的資料</dd>
+<dt><?php echo _T('Compiling'); ?>: </dt><dd>編譯標記，當共享記憶體區正在編譯 php 指令時標記為 "yes"</dd>
+<dt><?php echo _T('Hits'); ?>: </dt><dd>共享記憶體命中次數，命中=從該共享記憶體載入php或者變數</dd>
+<dt><?php echo _T('Updates'); ?>: </dt><dd>共享記憶更新過次數</dd>
+<dt><?php echo _T('Clogs'); ?>: </dt><dd>編譯阻塞跳過，阻塞=當需該共享記憶體區負責編譯時，其他程序/現成無法存取此共享記憶體. 跳過=XCache 自動判斷阻塞的共享記憶體區自動跳過阻塞等待，直接使用非共享記憶體方式繼續處理請求</dd>
+<dt><?php echo _T('OOMs'); ?>: </dt><dd>記憶體不足次數，顯示需要儲存新資料但是共享記憶體區記憶體不足的次數. 如果出現太頻繁請考慮加大配置中的 xcache.size 或者 xcache.var_size</dd>
+<dt><?php echo _T('Errors'); ?>: </dt><dd>编译错误, 显示您的脚本被编译时出错的次数. 如果您发现这个数字不断增长, 您应该检查什么脚本产生错误. 参考 <a href="http://www.php.net/manual/en/ref.errorfunc.php#ini.error-log">ini.error-log</a> and <a href="http://cn2.php.net/manual/en/ref.errorfunc.php#ini.display-errors">ini.display-errors</a></dd>
+<dt><?php echo _T('Protected'); ?>: </dt><dd>顯示該 Cache 是否支援並啟用 <a href="http://xcache.lighttpd.net/xcache/wiki/ReadonlyProtection">readonly_protection</a></dd>
+<dt><?php echo _T('Cached'); ?>: </dt><dd>共享記憶體於該共享記憶體區的項目個數</dd>
+<dt><?php echo _T('Deleted'); ?>: </dt><dd>共享記憶體區內將要刪除的項目 (已經刪除但是還被某些程序佔用)</dd>
+<dt><?php echo _T('GC'); ?>: </dt><dd>垃圾回收的倒數計時</dd>
+<dt><?php echo _T('Free Blocks'); ?>: </dt><dd>共享記憶體區內的空閒記憶體區塊</dd>
+</dl>
+
+<h2><?php echo _T('List Legends'); ?></h2>
+<dl>
+<dt><?php echo _T('entry'); ?>: </dt><dd>項目名稱或者檔案名稱</dd>
+<dt><?php echo _T('Hits'); ?>: </dt><dd>該項目被命中的次數 (從共享記憶體區載入)</dd>
+<dt><?php echo _T('Refcount'); ?>: </dt><dd>項目依然被其他程序佔用的引用次數</dd>
+<dt><?php echo _T('Size'); ?>: </dt><dd>項目在共享記憶體裡佔用位元數</dd>
+<dt><?php echo _T('PhpShared'); ?>: </dt><dd>與本項目相同 PHP 內容的个數</dd>
+<dt><?php echo _T('SrcSize'); ?>: </dt><dd>原始檔案大小</dd>
+<dt><?php echo _T('Modify'); ?>: </dt><dd>原始檔案最後修改時間</dd>
+<dt><?php echo _T('device'); ?>: </dt><dd>原始檔案所在設備ID</dd>
+<dt><?php echo _T('inode'); ?>: </dt><dd>原始檔案的inode</dd>
+<dt><?php echo _T('Access'); ?>: </dt><dd>最後存取該項目的時間</dd>
+<dt><?php echo _T('Create'); ?>: </dt><dd>該項目被建立於共享內的時間</dd>
+</dl>
Index: /tags/2.0.1/admin/help.php
===================================================================
--- /tags/2.0.1/admin/help.php	(revision 966)
+++ /tags/2.0.1/admin/help.php	(revision 966)
@@ -0,0 +1,33 @@
+<?php
+include("./common.php");
+?>
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<?php
+echo <<<HEAD
+	<meta http-equiv="Content-Type" content="text/html; charset=$config[charset]" />
+	<meta http-equiv="Content-Language" content="$config[lang]" />
+	<script type="text/javascript" src="tablesort.js" charset="$config[charset]"></script>
+HEAD;
+?>
+
+	<link rel="stylesheet" type="text/css" href="xcache.css" />
+	<title><?php echo _T('XCache Administration Help'); ?></title>
+	<script>
+	function toggle(o)
+	{
+		o.style.display = o.style.display != 'block' ? 'block' : 'none';
+	}
+	</script>
+</head>
+
+<body>
+<h1><?php echo _T('XCache Administration Help'); ?></h1>
+<div id1="help">
+<?php include(get_language_file("help")); ?>
+</div>
+
+<?php echo _T('See also'); ?>: <a href="http://xcache.lighttpd.net/wiki/PhpIni">setting php.ini for XCache</a> in the <a href="http://xcache.lighttpd.net/">XCache wiki</a>
+</body>
+</html>
Index: /tags/2.0.1/admin/index.php
===================================================================
--- /tags/2.0.1/admin/index.php	(revision 966)
+++ /tags/2.0.1/admin/index.php	(revision 966)
@@ -0,0 +1,3 @@
+<?php
+
+include("xcache.php");
Index: /tags/2.0.1/admin/mkpassword.php
===================================================================
--- /tags/2.0.1/admin/mkpassword.php	(revision 966)
+++ /tags/2.0.1/admin/mkpassword.php	(revision 966)
@@ -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/2.0.1/admin/tablesort.js
===================================================================
--- /tags/2.0.1/admin/tablesort.js	(revision 966)
+++ /tags/2.0.1/admin/tablesort.js	(revision 966)
@@ -0,0 +1,58 @@
+var sort_column;
+var prev_span = null;
+function get_inner_text(el) {
+ if((typeof el == 'string')||(typeof el == 'undefined'))
+  return el;
+ if(el.innerText)
+  return el.innerText;
+ else {
+  var str = "";
+  var cs = el.childNodes;
+  var l = cs.length;
+  for (i=0;i<l;i++) {
+   if (cs[i].nodeType==1) str += get_inner_text(cs[i]);
+   else if (cs[i].nodeType==3) str += cs[i].nodeValue;
+  }
+ }
+ return str;
+}
+function sortfn(a,b) {
+ var i = a.cells[sort_column].getAttribute('int');
+ if (i != null) {
+  return parseInt(i)-parseInt(b.cells[sort_column].getAttribute('int'));
+ } else {
+  var at = get_inner_text(a.cells[sort_column]);
+  var bt = get_inner_text(b.cells[sort_column]);
+  aa = at.toLowerCase();
+  bb = bt.toLowerCase();
+  if (aa==bb) return 0;
+  else if (aa<bb) return -1;
+  else return 1;
+ }
+}
+function resort(lnk) {
+ var span = lnk.childNodes[1];
+ if (!span) {
+ 	 var span = document.createElement("span")
+ 	 span.className = "sortarrow";
+ 	 lnk.appendChild(span);
+ }
+ var table = lnk.parentNode.parentNode.parentNode.parentNode;
+ var rows = new Array();
+ for (j=1;j<table.rows.length;j++)
+  rows[j-1] = table.rows[j];
+ sort_column = lnk.parentNode.cellIndex;
+ rows.sort(sortfn);
+ if (prev_span != null) prev_span.innerHTML = '';
+ if (span.getAttribute('sortdir')=='down') {
+  span.innerHTML = '&uarr;';
+  span.setAttribute('sortdir','up');
+  rows.reverse();
+ } else {
+  span.innerHTML = '&darr;';
+  span.setAttribute('sortdir','down');
+ }
+ for (i=0;i<rows.length;i++)
+  table.tBodies[0].appendChild(rows[i]);
+ prev_span = span;
+}
Index: /tags/2.0.1/admin/xcache.css
===================================================================
--- /tags/2.0.1/admin/xcache.css	(revision 966)
+++ /tags/2.0.1/admin/xcache.css	(revision 966)
@@ -0,0 +1,54 @@
+input, table { font-family: sans-serif; }
+input { font-size: 12px; }
+table { border-collapse: collapse; font-size: 11px; margin: 0; margin-bottom: 10px; }
+table caption, h2 { font-size: 16px; font-weight: bold; text-align: left; padding-top: 20px; margin-bottom: 2px; }
+td, th { white-space: pre; }
+table.cycles { border: 1px solid black; margin-top: 5px; margin-bottom: 5px; }
+table.cycles .col1 { background-color: #f5f5f5; }
+table.cycles .col2 { background-color: #e0e0e0; }
+table.cycles th, table.cycles td { border: 1px solid black; font-family: monospace; }
+table.cycles th { background-color: #9999cc; color: black; font-weight: bold; height: 20px; line-height: 20px; font-family: serif; }
+th a { color: black; font-weight: bold; display: block; width: 100%; height: 100%; }
+th { font-size: 12px; }
+.moduleinfo table { border: 1px solid black; }
+.moduleinfo table th, .moduleinfo table td { border: 1px solid black; }
+.moduleinfo table th { font-weight: bold; }
+.moduleinfo .e {background-color: #ccccff; font-weight: bold; color: #000000;}
+.moduleinfo .h {background-color: #9999cc; font-weight: bold; color: #000000;}
+.moduleinfo .v {background-color: #cccccc; color: #000000;}
+.button { }
+span.sortarrow { color: white; text-decoration: none; }
+form {margin: 0; padding: 0}
+
+.percent { height: 3px; margin-bottom: 1px; border: 1px solid gray; }
+.percent div { float: left; height: 100%; }
+.pvalue { background: limegreen; }
+
+.blocksgraph { height: 16px; }
+.blocksgraph div { float: left; height: 3px; width: 4px; border: solid gray; border-width: 0 0px 1px 0; }
+.blocksgraph { border: 1px solid gray; border-bottom: 0px; }
+
+.hitsgraph { height: 20px; margin: auto; }
+.hitsgraph div { float: left; width: 2px; height: 100%; }
+.hitsgraph div:hover { background: gray; }
+.hitsgraph div div { float: none; width: 100%; }
+.hitsgraph div div.barf { border: 0px solid gray; border-width: 1px 0 0 0; }
+.hitsgraph div div.barv { border: 0px solid gray; border-width: 0 0 1px 0; }
+.hitsgraph div div.barf.active { border-color: yellow; }
+.hitsgraph div div.barv.active { border-color: yellow; }
+
+.switcher, h1 { text-align: center; display: block; }
+.switcher a { color: blue; padding: 0 8px 0 8px; border: 1px solid white; border-bottom-color: black; }
+.switcher a:hover.active
+, .switcher a:active.active
+, .switcher a.active { color: black; text-decoration: none; background: #99C; border-color: #99C; border-left-color: black; border-right-color: black; }
+.switcher a:hover { background: #f0f0f0; }
+.switcher a:active { background: #e0e0e0; }
+#help { display: block; float: right; }
+.footnote { text-align: right; font-size: 12px; }
+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: 1px; }
+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/2.0.1/admin/xcache.php
===================================================================
--- /tags/2.0.1/admin/xcache.php	(revision 966)
+++ /tags/2.0.1/admin/xcache.php	(revision 966)
@@ -0,0 +1,376 @@
+<?php
+
+include("./common.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 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 '0 s';
+}
+
+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 ? ' active' : '';
+	return '<div title="' . $v . '">'
+		. '<div class="barf' . $a . '" style="height: ' . (100 - $percent) . '%"></div>'
+		. '<div class="barv' . $a . '" style="background: rgb(' . "$r,$g,$b" . '); height: ' . $percent . '%"></div>'
+		. '</div>';
+}
+
+function hits_to_graph($hits)
+{
+	$max = 0;
+	foreach ($hits as $v) {
+		if ($max < $v) {
+			$max = $v;
+		}
+	}
+	if (!$max) {
+		return '';
+	}
+	$t = (time() / (60 * 60)) % 24;
+	$html = array();
+	foreach ($hits as $i => $v) {
+		$html[] = bar_hits_percent($v, $v / $max, $i == $t);
+	}
+	return implode('', $html);
+}
+
+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);
+}
+
+if (!extension_loaded('XCache')) {
+	echo '<h1>XCache is not loaded</h1>';
+	ob_start();
+	phpinfo();
+	$info = ob_get_clean();
+	if (preg_match('!<td class="v">(.*\\.ini)!', $info, $m)) {
+		echo "Please check $m[1]";
+	}
+	else if (preg_match('!Configuration File \\(php.ini\\) Path *</td><td class="v">([^<]+)!', $info, $m)) {
+		echo "Please put a php.ini in $m[1] and load XCache extension";
+	}
+	else {
+		echo "You don't even have a php.ini yet?";
+	}
+	exit;
+}
+$pcnt = xcache_count(XC_TYPE_PHP);
+$vcnt = xcache_count(XC_TYPE_VAR);
+
+if ($_SERVER['REQUEST_METHOD'] == 'POST') {
+	$remove = @ $_POST['remove'];
+	if ($remove && is_array($remove)) {
+		foreach ($remove as $name) {
+			xcache_unset($name);
+		}
+	}
+}
+
+$moduleinfo = null;
+$type_none = -1;
+if (!isset($_GET['type'])) {
+	$_GET['type'] = $type_none;
+}
+$_GET['type'] = $type = (int) $_GET['type'];
+
+// {{{ process clear
+function processClear()
+{
+	$type = isset($_POST['type']) ? $_POST['type'] : null;
+	if ($type != XC_TYPE_PHP && $type != XC_TYPE_VAR) {
+		$type = null;
+	}
+	if (isset($type)) {
+		$cacheid = (int) (isset($_POST['cacheid']) ? $_POST['cacheid'] : 0);
+		if (isset($_POST['clearcache'])) {
+			$count = xcache_count($type);
+			if ($cacheid == $count) {
+				for ($cacheid = 0; $cacheid < $count; $cacheid ++) {
+					xcache_clear_cache($type, $cacheid);
+				}
+			}
+			else {
+				xcache_clear_cache($type, $cacheid);
+			}
+		}
+	}
+}
+processClear();
+// }}}
+// {{{ load info/list
+$cacheinfos = array();
+$total = array();
+for ($i = 0; $i < $pcnt; $i ++) {
+	$data = xcache_info(XC_TYPE_PHP, $i);
+	if ($type === XC_TYPE_PHP) {
+		$data += xcache_list(XC_TYPE_PHP, $i);
+	}
+	$data['type'] = XC_TYPE_PHP;
+	$data['cache_name'] = "php#$i";
+	$data['cacheid'] = $i;
+	$cacheinfos[] = $data;
+	if ($pcnt >= 2) {
+		calc_total($total, $data);
+	}
+}
+
+if ($pcnt >= 2) {
+	$total['type'] = XC_TYPE_PHP;
+	$total['cache_name'] = _T('Total');
+	$total['cacheid'] = $pcnt;
+	$total['gc'] = null;
+	$total['istotal'] = true;
+	$cacheinfos[] = $total;
+}
+
+$total = array();
+for ($i = 0; $i < $vcnt; $i ++) {
+	$data = xcache_info(XC_TYPE_VAR, $i);
+	if ($type === XC_TYPE_VAR) {
+		$data += xcache_list(XC_TYPE_VAR, $i);
+	}
+	$data['type'] = XC_TYPE_VAR;
+	$data['cache_name'] = "var#$i";
+	$data['cacheid'] = $i;
+	$cacheinfos[] = $data;
+	if ($vcnt >= 2) {
+		calc_total($total, $data);
+	}
+}
+
+if ($vcnt >= 2) {
+	$total['type'] = XC_TYPE_VAR;
+	$total['cache_name'] = _T('Total');
+	$total['cacheid'] = $vcnt;
+	$total['gc'] = null;
+	$total['istotal'] = true;
+	$cacheinfos[] = $total;
+}
+// }}}
+// {{{ merge the list
+switch ($type) {
+case XC_TYPE_PHP:
+case XC_TYPE_VAR:
+	$cachelist = array('type' => $type, 'cache_list' => array(), 'deleted_list' => array());
+	if ($type == XC_TYPE_VAR) {
+		$cachelist['type_name'] = 'var';
+	}
+	else {
+		$cachelist['type_name'] = 'php';
+	}
+	foreach ($cacheinfos as $i => $c) {
+		if (!empty($c['istotal'])) {
+			continue;
+		}
+		if ($c['type'] == $type && isset($c['cache_list'])) {
+			foreach ($c['cache_list'] as $e) {
+				$e['cache_name'] = $c['cache_name'];
+				$cachelist['cache_list'][] = $e;
+			}
+			foreach ($c['deleted_list'] as $e) {
+				$e['cache_name'] = $c['cache_name'];
+				$cachelist['deleted_list'][] = $e;
+			}
+		}
+	}
+	if ($type == XC_TYPE_PHP) {
+		$inodes = array();
+		$haveinode = false;
+		foreach ($cachelist['cache_list'] as $e) {
+			if (isset($e['file_inode'])) {
+				$haveinode = true;
+				break;
+			}
+		}
+		if (!$haveinode) {
+			foreach ($cachelist['deleted_list'] as $e) {
+				if (isset($e['file_inode'])) {
+					$haveinode = true;
+					break;
+				}
+			}
+		}
+	}
+	unset($data);
+	break;
+
+default:
+	$_GET['type'] = $type_none;
+	$cachelist = array();
+	ob_start();
+	phpinfo(INFO_MODULES);
+	$moduleinfo = ob_get_clean();
+	if (preg_match('!XCache</a></h2>(.*?)<h2>!is', $moduleinfo, $m)) {
+		$moduleinfo = $m[1];
+	}
+	else {
+		$moduleinfo = null;
+	}
+	break;
+}
+// }}}
+
+$type_php = XC_TYPE_PHP;
+$type_var = XC_TYPE_VAR;
+$types = array($type_none => _T('Statistics'), $type_php => _T('List PHP'), $type_var => _T('List Var Data'));
+$php_version = phpversion();
+$xcache_version = XCACHE_VERSION;
+$xcache_modules = XCACHE_MODULES;
+
+include("xcache.tpl.php");
+
+?>
Index: /tags/2.0.1/admin/xcache.tpl.php
===================================================================
--- /tags/2.0.1/admin/xcache.tpl.php	(revision 966)
+++ /tags/2.0.1/admin/xcache.tpl.php	(revision 966)
@@ -0,0 +1,271 @@
+<?php include("header.tpl.php"); ?>
+<div id="help">
+	<a href="help.php"><?php echo _T("Help") ?> &raquo;</a>
+</div>
+<div class="switcher"><?php echo switcher("type", $types); ?></div>
+<?php
+$a = new Cycle('class="col1"', 'class="col2"');
+$b = new Cycle('class="col1"', 'class="col2"');
+?>
+<table cellspacing="0" cellpadding="4" class="cycles">
+	<caption><?php echo _T('Caches'); ?></caption>
+	<col />
+	<col align="right" />
+	<col align="right" />
+	<col align="right" />
+	<col />
+	<col />
+	<col align="right" />
+	<col align="right" />
+	<col align="right" />
+	<col />
+	<col align="right" />
+	<col align="right" />
+	<col align="right" />
+	<col align="right" />
+	<col align="right" />
+	<col align="right" />
+	<col align="right" />
+	<col />
+	<tr <?php echo $a->next(); ?>>
+		<th>-</th>
+		<th><?php echo _T('Slots'); ?></th>
+		<th><?php echo _T('Size'); ?></th>
+		<th><?php echo _T('Avail'); ?></th>
+		<th><?php echo _T($config['percent_graph_type'] == 'free' ? '% Free' : '% Used'); ?></th>
+		<th><?php echo _T('Clear'); ?></th>
+		<th><?php echo _T('Compiling'); ?></th>
+		<th><?php echo _T('Hits'); ?></th>
+		<th><?php echo _T('Hits/H'); ?></th>
+		<th><?php echo _T('Hits 24H'); ?></th>
+		<th><?php echo _T('Hits/S'); ?></th>
+		<th><?php echo _T('Updates'); ?></th>
+		<th><?php echo _T('Clogs'); ?></th>
+		<th><?php echo _T('OOMs'); ?></th>
+		<th><?php echo _T('Errors'); ?></th>
+		<th><?php echo _T('Protected'); ?></th>
+		<th><?php echo _T('Cached'); ?></th>
+		<th><?php echo _T('Deleted'); ?></th>
+		<th><?php echo _T('GC'); ?></th>
+	</tr>
+	<?php
+	$numkeys = explode(',', 'slots,size,avail,hits,updates,clogs,ooms,errors,cached,deleted');
+	$l_clear = _T('Clear');
+	$l_clear_confirm = _T('Sure to clear?');
+	foreach ($cacheinfos as $i => $ci) {
+		echo "
+		<tr ", $a->next(), ">";
+		$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'];
+		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   = hits_to_graph($ci['hits_by_hour']);
+		$hits_graph_h_w = count($ci['hits_by_hour']) * 2;
+
+		if (!empty($ci['istotal'])) {
+			$ci['compiling']    = '-';
+			$ci['can_readonly'] = '-';
+		}
+		else {
+			$ci['compiling']    = $ci['type'] == $type_php ? ($ci['compiling'] ? 'yes' : 'no') : '-';
+			$ci['can_readonly'] = $ci['can_readonly'] ? 'yes' : 'no';
+		}
+		echo <<<EOS
+		<th>{$ci['cache_name']}</th>
+		<td title="{$ci['slots']}">{$ci_slots}</td>
+		<td title="{$ci['size']}">{$ci_size}</td>
+		<td 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_clear_confirm}');"
+				/></div
+			></form
+		></td>
+		<td>{$ci['compiling']}</td>
+		<td>{$ci['hits']}</td>
+		<td>{$hits_avg_h}</td>
+		<td><div class="hitsgraph" style="width: {$hits_graph_h_w}px">{$hits_graph_h}</div></td>
+		<td>{$hits_avg_s}</td>
+		<td>{$ci['updates']}</td>
+		<td>{$ci['clogs']}</td>
+		<td>{$ci['ooms']}</td>
+		<td>{$ci['errors']}</td>
+		<td>{$ci['can_readonly']}</td>
+		<td>{$ci['cached']}</td>
+		<td>{$ci['deleted']}</td>
+		<td>{$ci['gc']}</td>
+EOS;
+
+			$b->reset();
+			?>
+	</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 _T($config['percent_graph_type'] == 'free' ? '% Free' : '% Used'); ?></div>
+	<div class="legend" style="background: rgb(0,0,255)">&nbsp;&nbsp;</div>
+	<div class="legendtitle"><?php echo _T($config['percent_graph_type'] == 'free' ? 'Free Blocks' : '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
+
+if ($cachelist) {
+	$isphp = $cachelist['type'] == $type_php;
+	ob_start($config['path_nicer']);
+	foreach (array('Cached' => $cachelist['cache_list'], 'Deleted' => $cachelist['deleted_list']) as $listname => $entries) {
+		$a->reset();
+		?>
+
+	<form action="" method="post">
+	<table cellspacing="0" cellpadding="4" class="cycles entries" width="100%">
+		<caption><?php echo _T("{$cachelist['type_name']} $listname"); ?></caption>
+		<?php
+		echo "
+		<tr ", $a->next(), ">";
+		?>
+
+			<?php if (!$isphp) { ?>
+			<th width="20">R</th>
+			<?php } ?>
+			<th><a href="javascript:" onclick="resort(this); return false"><?php echo _T('Cache'); ?></a></th>
+			<th><a href="javascript:" onclick="resort(this); return false"><?php echo _T('entry'); ?></a></th>
+			<th><a href="javascript:" onclick="resort(this); return false"><?php echo _T('Hits'); ?></a></th>
+			<th><a href="javascript:" onclick="resort(this); return false"><?php echo _T('Size'); ?></a></th>
+			<?php if ($isphp) { ?>
+			<th><a href="javascript:" onclick="resort(this); return false"><?php echo _T('Refcount'); ?></a></th>
+			<th><a href="javascript:" onclick="resort(this); return false"><?php echo _T('PhpShared'); ?></a></th>
+			<th><a href="javascript:" onclick="resort(this); return false"><?php echo _T('SrcSize'); ?></a></th>
+			<th><a href="javascript:" onclick="resort(this); return false"><?php echo _T('Modify'); ?></a></th>
+			<?php if ($haveinode) { ?>
+			<th><a href="javascript:" onclick="resort(this); return false"><?php echo _T('device'); ?></a></th>
+			<th><a href="javascript:" onclick="resort(this); return false"><?php echo _T('inode'); ?></a></th>
+			<?php } ?>
+			<?php } ?>
+			<th><a href="javascript:" onclick="resort(this); return false"><?php echo _T('hash'); ?></a></th>
+			<th><a href="javascript:" onclick="resort(this); return false"><?php echo _T('Access'); ?></a></th>
+			<th><a href="javascript:" onclick="resort(this); return false"><?php echo _T('Create'); ?></a></th>
+			<?php if ($listname == 'Deleted') { ?>
+			<th><a href="javascript:" onclick="resort(this); return false"><?php echo _T('Delete'); ?></a></th>
+			<?php } ?>
+		</tr>
+		<?php
+		foreach ($entries as $i => $entry) {
+			echo "
+			<tr ", $a->next(), ">";
+			$name     = htmlspecialchars($entry['name']);
+			$hits     = number_format($entry['hits']);
+			$size     = size($entry['size']);
+			if ($isphp) {
+				$file_size   = size($entry['file_size']);
+				$phprefcount = number_format($entry['phprefcount']);
+			}
+
+			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) {
+				echo <<<ENTRY
+					<td><input type="checkbox" name="remove[]" value="{$name}"/></td>
+ENTRY;
+				$uname = urlencode($entry['name']);
+				$namelink = "<a href=\"edit.php?name=$uname\">$name</a>";
+			}
+			else {
+				$namelink = $name;
+			}
+
+			echo <<<ENTRY
+			<td>{$entry['cache_name']} {$i}</td>
+			<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['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>
+			";
+		}
+		?>
+
+	</table>
+	<?php if (!$isphp) { ?>
+	<input type="submit" value="<?php echo _T("Remove Selected"); ?>">
+	<?php } ?>
+	</form>
+<?php
+	}
+	ob_end_flush();
+}
+if ($moduleinfo) {
+	$t_moduleinfo = _T("Module Info");
+	echo <<<HTML
+<h2>$t_moduleinfo</h2>
+<div class="moduleinfo">$moduleinfo</div>
+HTML;
+}
+?>
+<?php include("footer.tpl.php"); ?>
Index: /tags/2.0.1/align.h
===================================================================
--- /tags/2.0.1/align.h	(revision 966)
+++ /tags/2.0.1/align.h	(revision 966)
@@ -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/2.0.1/config.m4
===================================================================
--- /tags/2.0.1/config.m4	(revision 966)
+++ /tags/2.0.1/config.m4	(revision 966)
@@ -0,0 +1,134 @@
+dnl vim:ts=2:sw=2:expandtab
+
+AC_DEFUN([XCACHE_OPTION], [
+  PHP_ARG_ENABLE(xcache-$1, for XCache $1,
+  [  --enable-xcache-$2    XCache: $4], no, no)
+  if test "$PHP_$3" != "no"; then
+    xcache_sources="$xcache_sources $1.c"
+    XCACHE_MODULES="$XCACHE_MODULES $1"
+    HAVE_$3=1
+    AC_DEFINE([HAVE_$3], 1, [Define for XCache: $4])
+  else
+    HAVE_$3=
+  fi
+])dnl
+
+PHP_ARG_ENABLE(xcache, for XCache support,
+[  --enable-xcache         Include XCache support.])
+
+if test "$PHP_XCACHE" != "no"; then
+	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="processor.c \
+                  xcache.c \
+                  mmap.c \
+                  mem.c \
+                  xc_shm.c \
+                  const_string.c \
+                  opcode_spec.c \
+                  stack.c \
+                  utils.c \
+                  lock.c \
+                  "
+  XCACHE_MODULES="cacher"
+  XCACHE_OPTION([optimizer],    [optimizer   ], [XCACHE_OPTIMIZER],    [(N/A)])
+  XCACHE_OPTION([coverager],    [coverager   ], [XCACHE_COVERAGER],    [Enable code coverage dumper, useful for testing php scripts])
+  XCACHE_OPTION([assembler],    [assembler   ], [XCACHE_ASSEMBLER],    [(N/A)])
+  XCACHE_OPTION([disassembler], [disassembler], [XCACHE_DISASSEMBLER], [Enable opcode to php variable dumper, NOT for production server])
+  XCACHE_OPTION([encoder],      [encoder     ], [XCACHE_ENCODER],      [(N/A)])
+  XCACHE_OPTION([decoder],      [decoder     ], [XCACHE_DECODER],      [(N/A)])
+  AC_DEFINE_UNQUOTED([XCACHE_MODULES], "$XCACHE_MODULES", [Define what modules is built with XCache])
+
+  PHP_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 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_MAKEFILE_FRAGMENT()
+
+  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])
+
+  AC_MSG_CHECKING(if you have opcode_spec_def.h for XCache)
+  if test -e "$ac_srcdir/opcode_spec_def.h" ; then
+    AC_DEFINE([HAVE_XCACHE_OPCODE_SPEC_DEF], 1, [Define if you have opcode_spec_def.h for XCache])
+    AC_MSG_RESULT(yes)
+  else
+    dnl check for features depend on opcode_spec_def.h
+    AC_MSG_RESULT(no)
+    define([ERROR], [
+      AC_MSG_ERROR([cannot build with $1, $ac_srcdir/opcode_spec_def.h required])
+    ])
+    if test "$PHP_XCACHE_DISASSEMBLER" != "no" ; then
+      ERROR(disassembler)
+    fi
+    undefine([ERROR])
+  fi
+fi
Index: /tags/2.0.1/config.w32
===================================================================
--- /tags/2.0.1/config.w32	(revision 966)
+++ /tags/2.0.1/config.w32	(revision 966)
@@ -0,0 +1,151 @@
+// vim:ft=javascript
+
+
+ARG_ENABLE("xcache", "Include XCache support", "yes,shared");
+
+if (PHP_XCACHE != "no") {
+	// {{{ 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");
+	}
+	// }}}
+
+	var xcache_sources = "processor.c \
+	                      xcache.c \
+	                      mmap.c \
+	                      mem.c \
+	                      xc_shm.c \
+	                      const_string.c \
+	                      opcode_spec.c \
+	                      stack.c \
+	                      utils.c \
+	                      lock.c \
+	                      ";
+	// {{{ add sources on enabled
+	ARG_ENABLE("xcache-optimizer",    "(N/A)", "no");
+	ARG_ENABLE("xcache-coverager",    "Enable code coverage dumper, useful for testing php scripts", "no");
+	ARG_ENABLE("xcache-assembler",    "(N/A)", "no");
+	ARG_ENABLE("xcache-disassembler", "Enable opcode to php variable dumper, NOT for production server", "no");
+	ARG_ENABLE("xcache-encoder",      "(N/A)", "no");
+	ARG_ENABLE("xcache-decoder",      "(N/A)", "no");
+
+	var XCACHE_MODULES = "cacher";
+	var options = ["optimizer",
+	               "coverager",
+	               "assembler", "disassembler",
+	               "encoder", "decoder"];
+	for (var i in options) {
+		var name = options[i];
+		var uname = name.toUpperCase();
+		var withval = eval("PHP_XCACHE_" + uname);
+		if (withval != "no") {
+			xcache_sources += " " + name + ".c";
+			XCACHE_MODULES += " " + name;
+			STDOUT.WriteLine("Enabling XCache Module: " + name);
+			AC_DEFINE("HAVE_XCACHE_" + uname, 1, "Define for XCache: " + name)
+		}
+	}
+	AC_DEFINE("XCACHE_MODULES", XCACHE_MODULES);
+	// }}}
+	// {{{ check for programs needed
+	var apps = ["m4", "grep", "sed"];
+	for (var i in apps) {
+		if (!PATH_PROG(apps[i])) {
+			ERROR(apps[i] + " is currently required to build XCache");
+		}
+	}
+	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");
+		xcache_sources += " xc_malloc.c";
+		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");
+	}
+	// }}}
+	// {{{ create extension
+	EXTENSION("xcache", xcache_sources);
+	var srcdir = configure_module_dirname;
+	// it's a bit harder to get builddir
+	var mfofile = "Makefile.objects";
+	MFO.Close();
+
+	var mfo = file_get_contents(mfofile);
+	mfo.match(/(.*)\\xcache.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 file = srcdir + "\\Makefile.frag";
+	STDOUT.WriteLine("Adding Makefile.frag: " + file);
+	var frag = file_get_contents(file);
+	frag = frag.replace(/\$\(srcdir\)\//g,   srcdir + '\\');
+	frag = frag.replace(/\$\(srcdir\)/g,     srcdir);
+	frag = frag.replace(/\$\(builddir\)\//g, builddir + '\\');
+	frag = frag.replace(/\$\(builddir\)/g,   builddir);
+	frag = frag.replace(/processor\//g,      "processor\\");
+	frag = frag.replace(/\.lo:/g, ".obj:");
+	frag = frag.replace(/.*\$\(CC\).* -E (.*) -o (.*)/, ccrule + " /E $1 > $2");
+	frag = frag.replace(/ -o /g, " /Fo");
+	frag = frag.replace(/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);
+	// {{{ check for opcode_spec_def.h
+	STDOUT.Write("Checking if you have opcode_spec_def.h for XCache ... ");
+	var file = srcdir + "\\opcode_spec_def.h";
+	if (FSO.FileExists(file)) {
+		STDOUT.WriteLine("yes");
+		AC_DEFINE("HAVE_XCACHE_OPCODE_SPEC_DEF", 1, "Define if you have opcode_spec_def.h for XCache");
+	}
+	else {
+		STDOUT.WriteLine("no");
+
+		// check for features depend on opcode_spec_def.h
+		var xcache_require_opcode_spec_def = function(withval, name) {
+			if (withval != "no") {
+				ERROR(file + " is required to enable XCache " + name);
+			}
+		}
+		xcache_require_opcode_spec_def(PHP_XCACHE_DISASSEMBLER, "disassembler");
+	}
+	// }}}
+}
Index: /tags/2.0.1/const_string.c
===================================================================
--- /tags/2.0.1/const_string.c	(revision 966)
+++ /tags/2.0.1/const_string.c	(revision 966)
@@ -0,0 +1,86 @@
+#include "xcache.h"
+#include "const_string.h"
+
+/* {{{ xc_get_op_type */
+static const char *const op_type_names[] = {
+	/* 0 */ "NULL?",
+	/* 1 */ "IS_CONST",
+	/* 2 */ "IS_TMP_VAR",
+	/* 3 */ NULL,
+	/* 4 */ "IS_VAR",
+	/* 5 */ NULL,
+	/* 6 */ NULL,
+	/* 7 */ NULL,
+	/* 8 */ "IS_UNUSED",
+#ifdef IS_CV
+	/* 9  */ NULL,
+	/* 10 */ NULL,
+	/* 11 */ NULL,
+	/* 12 */ NULL,
+	/* 13 */ NULL,
+	/* 14 */ NULL,
+	/* 15 */ NULL,
+	/* 16 */ "IS_CV"
+#endif
+};
+
+zend_uchar xc_get_op_type_count()
+{
+	return sizeof(op_type_names) / sizeof(op_type_names[0]);
+}
+
+const char *xc_get_op_type(zend_uchar op_type)
+{
+	assert(op_type < xc_get_op_type_count());
+	return op_type_names[op_type];
+}
+/* }}} */
+/* {{{ xc_get_data_type */
+static const char *const data_type_names[] = {
+	/* 0 */ "IS_NULL",
+	/* 1 */ "IS_LONG",
+	/* 2 */ "IS_DOUBLE",
+	/* 3 */ "IS_BOOL",
+	/* 4 */ "IS_ARRAY",
+	/* 5 */ "IS_OBJECT",
+	/* 6 */ "IS_STRING",
+	/* 7 */ "IS_RESOURCE",
+	/* 8 */ "IS_CONSTANT",
+	/* 9 */ "IS_CONSTANT_ARRAY",
+	/* 10 */ "IS_UNICODE"
+};
+
+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 "const_string_opcodes_php6.x.h"
+#elif defined(ZEND_ENGINE_2_4)
+#	include "const_string_opcodes_php5.4.h"
+#elif defined(ZEND_ENGINE_2_1)
+#	include "const_string_opcodes_php5.1.h"
+#elif defined(ZEND_ENGINE_2)
+#	include "const_string_opcodes_php5.0.h"
+#else
+#	include "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/2.0.1/const_string.h
===================================================================
--- /tags/2.0.1/const_string.h	(revision 966)
+++ /tags/2.0.1/const_string.h	(revision 966)
@@ -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/2.0.1/const_string_opcodes_php4.x.h
===================================================================
--- /tags/2.0.1/const_string_opcodes_php4.x.h	(revision 966)
+++ /tags/2.0.1/const_string_opcodes_php4.x.h	(revision 966)
@@ -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/2.0.1/const_string_opcodes_php5.0.h
===================================================================
--- /tags/2.0.1/const_string_opcodes_php5.0.h	(revision 966)
+++ /tags/2.0.1/const_string_opcodes_php5.0.h	(revision 966)
@@ -0,0 +1,153 @@
+/* size = 149 */
+static const char *const xc_opcode_names[] = {
+/* 0 */	"NOP",
+/* 1 */	"ADD",
+/* 2 */	"SUB",
+/* 3 */	"MUL",
+/* 4 */	"DIV",
+/* 5 */	"MOD",
+/* 6 */	"SL",
+/* 7 */	"SR",
+/* 8 */	"CONCAT",
+/* 9 */	"BW_OR",
+/* 10 */	"BW_AND",
+/* 11 */	"BW_XOR",
+/* 12 */	"BW_NOT",
+/* 13 */	"BOOL_NOT",
+/* 14 */	"BOOL_XOR",
+/* 15 */	"IS_IDENTICAL",
+/* 16 */	"IS_NOT_IDENTICAL",
+/* 17 */	"IS_EQUAL",
+/* 18 */	"IS_NOT_EQUAL",
+/* 19 */	"IS_SMALLER",
+/* 20 */	"IS_SMALLER_OR_EQUAL",
+/* 21 */	"CAST",
+/* 22 */	"QM_ASSIGN",
+/* 23 */	"ASSIGN_ADD",
+/* 24 */	"ASSIGN_SUB",
+/* 25 */	"ASSIGN_MUL",
+/* 26 */	"ASSIGN_DIV",
+/* 27 */	"ASSIGN_MOD",
+/* 28 */	"ASSIGN_SL",
+/* 29 */	"ASSIGN_SR",
+/* 30 */	"ASSIGN_CONCAT",
+/* 31 */	"ASSIGN_BW_OR",
+/* 32 */	"ASSIGN_BW_AND",
+/* 33 */	"ASSIGN_BW_XOR",
+/* 34 */	"PRE_INC",
+/* 35 */	"PRE_DEC",
+/* 36 */	"POST_INC",
+/* 37 */	"POST_DEC",
+/* 38 */	"ASSIGN",
+/* 39 */	"ASSIGN_REF",
+/* 40 */	"ECHO",
+/* 41 */	"PRINT",
+/* 42 */	"JMP",
+/* 43 */	"JMPZ",
+/* 44 */	"JMPNZ",
+/* 45 */	"JMPZNZ",
+/* 46 */	"JMPZ_EX",
+/* 47 */	"JMPNZ_EX",
+/* 48 */	"CASE",
+/* 49 */	"SWITCH_FREE",
+/* 50 */	"BRK",
+/* 51 */	"CONT",
+/* 52 */	"BOOL",
+/* 53 */	"INIT_STRING",
+/* 54 */	"ADD_CHAR",
+/* 55 */	"ADD_STRING",
+/* 56 */	"ADD_VAR",
+/* 57 */	"BEGIN_SILENCE",
+/* 58 */	"END_SILENCE",
+/* 59 */	"INIT_FCALL_BY_NAME",
+/* 60 */	"DO_FCALL",
+/* 61 */	"DO_FCALL_BY_NAME",
+/* 62 */	"RETURN",
+/* 63 */	"RECV",
+/* 64 */	"RECV_INIT",
+/* 65 */	"SEND_VAL",
+/* 66 */	"SEND_VAR",
+/* 67 */	"SEND_REF",
+/* 68 */	"NEW",
+/* 69 */	"JMP_NO_CTOR",
+/* 70 */	"FREE",
+/* 71 */	"INIT_ARRAY",
+/* 72 */	"ADD_ARRAY_ELEMENT",
+/* 73 */	"INCLUDE_OR_EVAL",
+/* 74 */	"UNSET_VAR",
+/* 75 */	"UNSET_DIM_OBJ",
+/* 76 */	"UNDEF",
+/* 77 */	"FE_RESET",
+/* 78 */	"FE_FETCH",
+/* 79 */	"EXIT",
+/* 80 */	"FETCH_R",
+/* 81 */	"FETCH_DIM_R",
+/* 82 */	"FETCH_OBJ_R",
+/* 83 */	"FETCH_W",
+/* 84 */	"FETCH_DIM_W",
+/* 85 */	"FETCH_OBJ_W",
+/* 86 */	"FETCH_RW",
+/* 87 */	"FETCH_DIM_RW",
+/* 88 */	"FETCH_OBJ_RW",
+/* 89 */	"FETCH_IS",
+/* 90 */	"FETCH_DIM_IS",
+/* 91 */	"FETCH_OBJ_IS",
+/* 92 */	"FETCH_FUNC_ARG",
+/* 93 */	"FETCH_DIM_FUNC_ARG",
+/* 94 */	"FETCH_OBJ_FUNC_ARG",
+/* 95 */	"FETCH_UNSET",
+/* 96 */	"FETCH_DIM_UNSET",
+/* 97 */	"FETCH_OBJ_UNSET",
+/* 98 */	"FETCH_DIM_TMP_VAR",
+/* 99 */	"FETCH_CONSTANT",
+/* 100 */	"UNDEF",
+/* 101 */	"EXT_STMT",
+/* 102 */	"EXT_FCALL_BEGIN",
+/* 103 */	"EXT_FCALL_END",
+/* 104 */	"EXT_NOP",
+/* 105 */	"TICKS",
+/* 106 */	"SEND_VAR_NO_REF",
+/* 107 */	"CATCH",
+/* 108 */	"THROW",
+/* 109 */	"FETCH_CLASS",
+/* 110 */	"CLONE",
+/* 111 */	"INIT_CTOR_CALL",
+/* 112 */	"INIT_METHOD_CALL",
+/* 113 */	"INIT_STATIC_METHOD_CALL",
+/* 114 */	"ISSET_ISEMPTY_VAR",
+/* 115 */	"ISSET_ISEMPTY_DIM_OBJ",
+/* 116 */	"UNDEF",
+/* 117 */	"UNDEF",
+/* 118 */	"UNDEF",
+/* 119 */	"UNDEF",
+/* 120 */	"UNDEF",
+/* 121 */	"UNDEF",
+/* 122 */	"UNDEF",
+/* 123 */	"UNDEF",
+/* 124 */	"UNDEF",
+/* 125 */	"UNDEF",
+/* 126 */	"UNDEF",
+/* 127 */	"UNDEF",
+/* 128 */	"UNDEF",
+/* 129 */	"UNDEF",
+/* 130 */	"UNDEF",
+/* 131 */	"UNDEF",
+/* 132 */	"PRE_INC_OBJ",
+/* 133 */	"PRE_DEC_OBJ",
+/* 134 */	"POST_INC_OBJ",
+/* 135 */	"POST_DEC_OBJ",
+/* 136 */	"ASSIGN_OBJ",
+/* 137 */	"OP_DATA",
+/* 138 */	"INSTANCEOF",
+/* 139 */	"DECLARE_CLASS",
+/* 140 */	"DECLARE_INHERITED_CLASS",
+/* 141 */	"DECLARE_FUNCTION",
+/* 142 */	"RAISE_ABSTRACT_ERROR",
+/* 143 */	"UNDEF",
+/* 144 */	"ADD_INTERFACE",
+/* 145 */	"UNDEF",
+/* 146 */	"VERIFY_ABSTRACT_CLASS",
+/* 147 */	"ASSIGN_DIM",
+/* 148 */	"ISSET_ISEMPTY_PROP_OBJ",
+/* 149 */	"HANDLE_EXCEPTION"
+};
Index: /tags/2.0.1/const_string_opcodes_php5.1.h
===================================================================
--- /tags/2.0.1/const_string_opcodes_php5.1.h	(revision 966)
+++ /tags/2.0.1/const_string_opcodes_php5.1.h	(revision 966)
@@ -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/2.0.1/const_string_opcodes_php5.4.h
===================================================================
--- /tags/2.0.1/const_string_opcodes_php5.4.h	(revision 966)
+++ /tags/2.0.1/const_string_opcodes_php5.4.h	(revision 966)
@@ -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/2.0.1/const_string_opcodes_php6.x.h
===================================================================
--- /tags/2.0.1/const_string_opcodes_php6.x.h	(revision 966)
+++ /tags/2.0.1/const_string_opcodes_php6.x.h	(revision 966)
@@ -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/2.0.1/coverager.c
===================================================================
--- /tags/2.0.1/coverager.c	(revision 966)
+++ /tags/2.0.1/coverager.c	(revision 966)
@@ -0,0 +1,593 @@
+#if 0
+#define XCACHE_DEBUG
+#endif
+
+#include <stdio.h>
+#include "xcache.h"
+#include "ext/standard/flock_compat.h"
+#ifdef HAVE_SYS_FILE_H
+#	include <sys/file.h>
+#endif
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include "stack.h"
+#include "xcache_globals.h"
+#include "coverager.h"
+#include "utils.h"
+typedef HashTable *coverager_t;
+#define PCOV_HEADER_MAGIC 0x564f4350
+
+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);
+}
+/* }}} */
+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 >= 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_enable(TSRMLS_D) /* {{{ */
+{
+	XG(coverage_enabled) = 1;
+}
+/* }}} */
+static void xc_coverager_disable(TSRMLS_D) /* {{{ */
+{
+	XG(coverage_enabled) = 0;
+}
+/* }}} */
+
+void xc_coverager_request_init(TSRMLS_D) /* {{{ */
+{
+	if (XG(coverager)) {
+		xc_coverager_enable(TSRMLS_C);
+#ifdef ZEND_COMPILE_EXTENDED_INFO
+		CG(compiler_options) |= ZEND_COMPILE_EXTENDED_INFO;
+#else
+		CG(extended_info) = 1;
+#endif
+	}
+	else {
+		XG(coverage_enabled) = 0;
+	}
+}
+/* }}} */
+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();
+	}
+}
+/* }}} */
+void xc_coverager_request_shutdown(TSRMLS_D) /* {{{ */
+{
+	if (XG(coverager)) {
+		xc_coverager_autodump(TSRMLS_C);
+		xc_coverager_cleanup(TSRMLS_C);
+	}
+}
+/* }}} */
+
+/* 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 */
+void xc_coverager_handle_ext_stmt(zend_op_array *op_array, zend_uchar op) /* {{{ */
+{
+	TSRMLS_FETCH();
+
+	if (XG(coverages) && XG(coverage_enabled)) {
+		int size = xc_coverager_get_op_array_size_no_tail(op_array);
+		int oplineno = (*EG(opline_ptr)) - op_array->opcodes;
+		if (oplineno < size) {
+			xc_coverager_add_hits(xc_coverager_get(op_array->filename TSRMLS_CC), (*EG(opline_ptr))->lineno, 1 TSRMLS_CC);
+		}
+	}
+}
+/* }}} */
+
+/* init/destroy */
+int xc_coverager_init(int module_number TSRMLS_DC) /* {{{ */
+{
+	old_compile_file = zend_compile_file;
+	zend_compile_file = xc_compile_file_for_coverage;
+
+	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 SUCCESS;
+}
+/* }}} */
+void xc_coverager_destroy() /* {{{ */
+{
+	if (old_compile_file == xc_compile_file_for_coverage) {
+		zend_compile_file = old_compile_file;
+	}
+	if (xc_coveragedump_dir) {
+		pefree(xc_coveragedump_dir, 1);
+		xc_coveragedump_dir = NULL;
+	}
+}
+/* }}} */
+
+/* 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 >= 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_enable(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_disable(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);
+	}
+}
+/* }}} */
Index: /tags/2.0.1/coverager.h
===================================================================
--- /tags/2.0.1/coverager.h	(revision 966)
+++ /tags/2.0.1/coverager.h	(revision 966)
@@ -0,0 +1,12 @@
+#include "php.h"
+#include "xcache.h"
+
+void xc_coverager_handle_ext_stmt(zend_op_array *op_array, zend_uchar op);
+int xc_coverager_init(int module_number TSRMLS_DC);
+void xc_coverager_destroy();
+void xc_coverager_request_init(TSRMLS_D);
+void xc_coverager_request_shutdown(TSRMLS_D);
+PHP_FUNCTION(xcache_coverager_decode);
+PHP_FUNCTION(xcache_coverager_start);
+PHP_FUNCTION(xcache_coverager_stop);
+PHP_FUNCTION(xcache_coverager_get);
Index: /tags/2.0.1/coverager/common-en.lang.php
===================================================================
--- /tags/2.0.1/coverager/common-en.lang.php	(revision 966)
+++ /tags/2.0.1/coverager/common-en.lang.php	(revision 966)
@@ -0,0 +1,5 @@
+<?php
+
+$GLOBALS['show_todo_strings'] = false;
+
+?>
Index: /tags/2.0.1/coverager/common-zh-simplified-gb2312.lang.php
===================================================================
--- /tags/2.0.1/coverager/common-zh-simplified-gb2312.lang.php	(revision 966)
+++ /tags/2.0.1/coverager/common-zh-simplified-gb2312.lang.php	(revision 966)
@@ -0,0 +1,25 @@
+<?php
+
+$strings = array(
+		'root'
+		=> '¿ªÊ¼',
+		'Directory'
+		=> 'Ä¿Â¼',
+		'File'
+		=> 'ÎÄ¼þ',
+		'Percent'
+		=> '¸²¸ÇÂÊ',
+		'Hits'
+		=> 'ÃüÖÐ',
+		'Lines'
+		=> 'ÐÐÊý',
+		'TODO'
+		=> 'ÏÐÖÃÎÄ¼þ',
+		'XCache PHP Code Coverage Viewer'
+		=> 'XCache PHP ´úÂë¸²¸Ç²é¿´Æ÷',
+		'module'
+		=> 'Ä£¿é',
+		''
+		=> '',
+		);
+
Index: /tags/2.0.1/coverager/common-zh-simplified-utf-8.lang.php
===================================================================
--- /tags/2.0.1/coverager/common-zh-simplified-utf-8.lang.php	(revision 966)
+++ /tags/2.0.1/coverager/common-zh-simplified-utf-8.lang.php	(revision 966)
@@ -0,0 +1,25 @@
+<?php
+
+$strings = array(
+		'root'
+		=> '开始',
+		'Directory'
+		=> '目录',
+		'File'
+		=> '文件',
+		'Percent'
+		=> '覆盖率',
+		'Hits'
+		=> '命中',
+		'Lines'
+		=> '行数',
+		'TODO'
+		=> '闲置文件',
+		'XCache PHP Code Coverage Viewer'
+		=> 'XCache PHP 代码覆盖查看器',
+		'module'
+		=> '模块',
+		''
+		=> '',
+		);
+
Index: /tags/2.0.1/coverager/common.php
===================================================================
--- /tags/2.0.1/coverager/common.php	(revision 966)
+++ /tags/2.0.1/coverager/common.php	(revision 966)
@@ -0,0 +1,112 @@
+<?php
+
+function get_language_file_ex($name, $l, $s)
+{
+	static $lmap = array(
+			'zh'    => 'zh-simplified',
+			'zh-hk' => 'zh-traditional',
+			'zh-tw' => 'zh-traditional',
+			);
+	static $smap = array(
+			'gbk'     => 'gb2312',
+			'gb18030' => 'gb2312',
+			);
+
+	if (isset($lmap[$l])) {
+		$l = $lmap[$l];
+	}
+	if (file_exists($file = "$name-$l-$s.lang.php")) {
+		return $file;
+	}
+	if (isset($smap[$s])) {
+		$s = $smap[$s];
+		if (file_exists($file = "$name-$l-$s.lang.php")) {
+			return $file;
+		}
+	}
+	if (file_exists($file = "$name-$l.lang.php")) {
+		return $file;
+	}
+	return null;
+}
+
+function get_language_file($name)
+{
+	global $charset, $lang;
+	$s = strtolower($charset);
+	if (isset($lang)) {
+		$l = strtolower($lang);
+		$file = get_language_file_ex($name, $l, $s);
+		if (!isset($file)) {
+			$l = strtok($l, '-');
+			$file = get_language_file_ex($name, $l, $s);
+		}
+	}
+	else if (!empty($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
+		foreach (explode(',', str_replace(' ', '', $_SERVER['HTTP_ACCEPT_LANGUAGE'])) as $l) {
+			$l = strtok($l, ';');
+			$file = get_language_file_ex($name, $l, $s);
+			if (isset($file)) {
+				$lang = $l;
+				break;
+			}
+			if (strpos($l, '-') !== false) {
+				$ll = strtok($l, '-');
+				$file = get_language_file_ex($name, $ll, $s);
+				if (isset($file)) {
+					$lang = $l;
+					break;
+				}
+			}
+		}
+	}
+	return isset($file) ? $file : "$name-en.lang.php";
+}
+
+function _T($str)
+{
+	if (isset($GLOBALS['strings'][$str])) {
+		return $GLOBALS['strings'][$str];
+	}
+	if (!empty($GLOBALS['show_todo_strings'])) {
+		return '<span style="color:red">' . htmlspecialchars($str) . '</span>';
+	}
+	return $str;
+}
+
+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;
+}
+
+error_reporting(E_ALL);
+ini_set('display_errors', 'On');
+define('REQUEST_TIME', time());
+
+if (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);
+}
+ini_set('magic_quotes_runtime', '0');
+
+$charset = "UTF-8";
+if (file_exists("./config.php")) {
+	include("./config.php");
+}
+
+include(get_language_file("common"));
+if (!isset($lang)) {
+	$lang = 'en-us';
+}
+
+?>
Index: /tags/2.0.1/coverager/config.php.example
===================================================================
--- /tags/2.0.1/coverager/config.php.example	(revision 966)
+++ /tags/2.0.1/coverager/config.php.example	(revision 966)
@@ -0,0 +1,59 @@
+<?php
+
+// this is an example only
+// write your own config and name it as config.php
+
+// detected by browser
+// $lang = 'en-us';
+
+$charset = "UTF-8";
+
+// developers only
+$show_todo_strings = false;
+
+// $include_paths = array("/www/my-php-project/");
+// $exclude_paths = array("/www/my-php-project/tmp/");
+$syntaxhiglight = true;
+$usecache = false;
+//// $datadir is default to ini_get("xcache.coveragedump_directory")
+// $datadir = '';
+
+function ob_filter_path_nicer($o)
+{
+	$sep = DIRECTORY_SEPARATOR;
+	$o = str_replace($_SERVER['DOCUMENT_ROOT'],  "{DOCROOT}" . (substr($d, -1) == $sep ? $sep : ""), $o);
+	$xcachedir = realpath(dirname(__FILE__) . "$sep..$sep");
+	$o = str_replace($xcachedir . $sep, "{XCache}$sep", $o);
+	if ($sep == '/') {
+		$o = str_replace("/home/", "{H}/", $o);
+	}
+	return $o;
+}
+
+// implement your auth here if needed
+// {{{ home made login example
+// this is an example only, it's won't work for you without your implemention.
+function check_admin_auth()
+{
+	require("/path/to/user-login-and-permission-lib.php");
+	session_start();
+
+	if (!user_logined()) {
+		if (!ask_the_user_to_login()) {
+			exit;
+		}
+	}
+
+	user_load_permissions();
+	if (!user_is_admin()) {
+		die("Permission denied");
+	}
+
+	return true;
+}
+
+// uncomment:
+// check_admin_auth()
+// }}}
+
+?>
Index: /tags/2.0.1/coverager/coverager.css
===================================================================
--- /tags/2.0.1/coverager/coverager.css	(revision 966)
+++ /tags/2.0.1/coverager/coverager.css	(revision 966)
@@ -0,0 +1,71 @@
+h1 { text-align: center; display: block; }
+input, table { font-family: sans-serif; font-size: 11px; }
+th { font-size: 12px; }
+table { border-collapse: collapse; }
+table.center { margin-left: auto; margin-right: auto; }
+table\-center { text-align: center; }
+table.cycles { border: 1px solid black; margin-top: 5px; margin-bottom: 5px; }
+table.cycles .col1 { background-color: #f5f5f5; }
+table.cycles .col2 { background-color: #e0e0e0; }
+table.cycles th, table.cycles td { border: 1px solid black; font-family: monospace; }
+table.cycles th { background-color: #9999cc; color: black; font-weight: bold; height: 20px; line-height: 20px; font-family: serif; }
+th a { color: black; font-weight: bold; display: block; width: 100%; height: 100%; }
+
+.coverFile {
+	text-align:       left;
+	color:            gray;
+	padding-left:     10px;
+	padding-right:    10px;
+}
+
+.coverBar {
+	padding-left:     10px;
+	padding-right:    10px;
+}
+
+.coverBarOutline {
+	border: 1px solid black;
+	background-color: #ffffff;
+	width: 100px;
+	font-size: 11px; line-height: 11px;
+	font-family: tahoma;
+	position: relative;
+}
+
+.coverPerHi, .coverPerMed, .coverPerLo {
+	text-align:       center;
+	font-weight:      bold;
+	left: 0px; top: 2px;
+	position: absolute;
+	width: 100%;
+}
+.coverBarHi, .coverBarMed, .coverBarLo { left: 1px; top: 1px; 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;
+}
+
+.footnote { text-align: right; font-size: 12px; }
+.error { color: red; }
Index: /tags/2.0.1/coverager/coverager.php
===================================================================
--- /tags/2.0.1/coverager/coverager.php	(revision 966)
+++ /tags/2.0.1/coverager/coverager.php	(revision 966)
@@ -0,0 +1,360 @@
+<?php
+
+include("./common.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;
+	}
+}
+
+class XcacheCoverageViewer
+{
+	var $syntaxhiglight = true;
+	var $usecache = 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');
+
+		// copy config
+		foreach (array('charset', 'include_paths', 'exclude_paths', 'syntaxhiglight', 'usecache', 'datadir', 'lang') as $k) {
+			if (isset($GLOBALS[$k])) {
+				$this->{$k} = $GLOBALS[$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->usecache) {
+				ksort($dirinfo['subdirs']);
+				ksort($dirinfo['files']);
+			}
+		}
+		else if (is_file($this->outpath . ".pcov")) {
+			$action = 'file';
+
+			$dir = dirname($path);
+			$filename = basename($path);
+
+			$fileinfo = $this->loadCov($this->outpath . ".pcov");
+
+			$lines = file($path);
+			// fix the tabs not in the middle
+			foreach ($lines as $l => $line) {
+				if (preg_match('!^(\\t*)([^\\t]+\\t.*)$!s', $line, $m)) {
+					$lines[$l] = $m[1];
+					$chunks = explode("\t", $m[2]);
+					for ($i = 0, $c = count($chunks) - 1; $i < $c; $i ++) {
+						$lines[$l] .= $chunks[$i] . str_repeat(" ", 4 - (strlen($chunks[$i]) % 4));
+					}
+					$lines[$l] .= $chunks[$c];
+				}
+			}
+			if ($this->syntaxhiglight) {
+				$source = implode('', $lines);
+				ob_start();
+				highlight_string($source);
+				$lines = 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 `ini:xcache.coveragedump_directory` or `config:$datadir` to be set';
+		}
+		else {
+			$action = 'error';
+			$error  = "no data";
+		}
+
+		$xcache_version = defined('XCACHE_VERSION') ? XCACHE_VERSION : '';
+		include("coverager.tpl.php");
+	}
+
+	function loadDir($outdir, $addtodo = null)
+	{
+		if ($this->usecache) {
+			$cachefile = $outdir . "/.pcovcache";
+			if (file_exists($cachefile)) {
+				return unserialize(file_get_contents($cachefile));
+			}
+		}
+		$srcdir = substr($outdir, $this->datadir_len);
+
+		$total = $hits = $todos = 0;
+		$files = array();
+		$subdirs = array();
+		if (!isset($addtodo)) {
+			if ($this->include_paths) {
+				foreach ($this->include_paths as $p) {
+					if (strncmp($p, $srcdir, strlen($p)) == 0) {
+						$addtodo = true;
+						break;
+					}
+				}
+			}
+		}
+		if ($addtodo) {
+			if ($this->exclude_paths) {
+				foreach ($this->exclude_paths as $p) {
+					if (strncmp($p, $srcdir, strlen($p)) == 0) {
+						$addtodo = false;
+						break;
+					}
+				}
+			}
+		}
+		foreach (glob($outdir . "/*") as $outfile) {
+			if (is_dir($outfile)) {
+				$info = $this->loadDir($outfile, $addtodo);
+				$srcfile = substr($outfile, $this->datadir_len);
+				$subdirs += $info['subdirs'];
+				$total   += $info['total'];
+				$hits    += $info['hits'];
+				$todos   += $info['todos'];
+				unset($info['subdirs']);
+				$subdirs[$srcfile] = $info;
+			}
+			else if (substr($outfile, -5) == ".pcov") {
+				// pass
+				$info = $this->loadFile($outfile);
+				$total += $info['total'];
+				$hits  += $info['hits'];
+				$srcfile = substr($outfile, $this->datadir_len, -5);
+				$files[$srcfile] = $info;
+			}
+			else {
+				continue;
+			}
+		}
+		if ($addtodo === true) {
+			foreach (glob($srcdir . "/*") as $srcfile) {
+				if (!isset($files[$srcfile]) && is_file($srcfile)) {
+					$files[$srcfile] = array('total' => 0, 'hits' => 0);
+					$todos ++;
+				}
+				else if (!isset($subdirs[$srcfile]) && is_dir($srcfile)) {
+					$subdirs[$srcfile] = array('total' => 0, 'hits' => 0, 'todos' => 1, 'files' => 0, 'subdirs' => array());
+					$todos ++;
+				}
+			}
+		}
+
+		if ($this->usecache) {
+			ksort($subdirs);
+			ksort($files);
+		}
+
+		$info = array(
+				'total'   => $total,
+				'hits'    => $hits,
+				'todos'   => $todos,
+				'files'   => $files,
+				'subdirs' => $subdirs,
+				);
+
+		if ($this->usecache) {
+			$fp = fopen($cachefile, "wb");
+			fwrite($fp, serialize($info));
+			fclose($fp);
+		}
+		return $info;
+	}
+
+	function loadFile($file)
+	{
+		if ($this->usecache) {
+			$cachefile = $file . "cache";
+			if (file_exists($cachefile)) {
+				return unserialize(file_get_contents($cachefile));
+			}
+		}
+
+		$info = $this->loadCov($file); //, $lines);
+		unset($info['cov']);
+
+		if ($this->usecache) {
+			$fp = fopen($cachefile, "wb");
+			fwrite($fp, serialize($info));
+			fclose($fp);
+		}
+		return $info;
+	}
+
+	function loadCov($file)//, $lines)
+	{
+		$total = $hits = 0;
+
+		$cov = xcache_coverager_decode(file_get_contents($file));
+
+		return array('total' => count($cov) - 1, 'hits' => $cov[0], 'cov' => $cov);
+	}
+
+	function loadTplCov($cov, $ctpl)
+	{
+		$tplinfofile = $ctpl . '.phpinfo';
+
+		if (!file_exists($tplinfofile)) {
+			return;
+		}
+
+		$tplinfo = unserialize(file_get_contents($tplinfofile));
+
+		if (!isset($tplinfo['sourceFile'])) {
+			return;
+		}
+		$tplfile = $tplinfo['sourceFile'];
+		if (!isset($tplinfo['lineMap']) || !count($tplinfo['lineMap'])) {
+			return;
+		}
+
+		$tpllines = file($tplfile);
+
+		$dline = 0;
+		$sline = 0;
+		$tplcov = array();
+		foreach ($cov as $line => $times) {
+			// find nearest line
+			while ($dline < $line) {
+				if ((list($dline, $sline) = each($tplinfo['lineMap'])) === false) {
+					break 2;
+				}
+			}
+
+			$tplcov[$sline] = $times;
+		}
+		return array($tplfile, $tpllines, $tplcov);
+	}
+}
+
+function sprint_cov($cov, $lines, $encode = true)
+{
+	$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/2.0.1/coverager/coverager.tpl.php
===================================================================
--- /tags/2.0.1/coverager/coverager.tpl.php	(revision 966)
+++ /tags/2.0.1/coverager/coverager.tpl.php	(revision 966)
@@ -0,0 +1,253 @@
+<!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>
+<?php
+echo <<<HEAD
+	<meta http-equiv="Content-Type" content="text/html; charset=$this->charset" />
+	<meta http-equiv="Content-Language" content="{$this->lang}" />
+	<script type="text/javascript" src="tablesort.js" charset="$this->charset"></script>
+HEAD;
+?>
+
+	<link rel="stylesheet" type="text/css" href="coverager.css" />
+	<title><?php echo _T("XCache PHP Code Coverage Viewer"); ?></title>
+</head>
+<body>
+<h1><?php echo _T("XCache PHP Code Coverage Viewer"); ?></h1>
+
+<?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
+<div class="table-center">
+	<table cellpadding="2" cellspacing="0" border="0" class="cycles center">
+	<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>
+</div>
+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
+<div class="center-table">
+	<table cellpadding="2" cellspacing="0" border="0" class="cycles center">
+	<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>
+</div>
+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;
+}
+?>
+
+<div class="footnote">
+Powered By: XCache <?php echo $xcache_version; ?> coverager <?php echo _T("module"); ?>
+</div>
+
+</body>
+</html>
Index: /tags/2.0.1/coverager/index.php
===================================================================
--- /tags/2.0.1/coverager/index.php	(revision 966)
+++ /tags/2.0.1/coverager/index.php	(revision 966)
@@ -0,0 +1,3 @@
+<?php
+
+include("coverager.php");
Index: /tags/2.0.1/decompilesample.php
===================================================================
--- /tags/2.0.1/decompilesample.php	(revision 966)
+++ /tags/2.0.1/decompilesample.php	(revision 966)
@@ -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/2.0.1/disassembler.c
===================================================================
--- /tags/2.0.1/disassembler.c	(revision 966)
+++ /tags/2.0.1/disassembler.c	(revision 966)
@@ -0,0 +1,192 @@
+#include "disassembler.h"
+#include "xcache.h"
+#include "utils.h"
+#include "processor.h"
+
+#ifndef HAVE_XCACHE_OPCODE_SPEC_DEF
+#error disassembler cannot be built without xcache/opcode_spec_def.h
+#endif
+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);
+}
+/* }}} */
Index: /tags/2.0.1/disassembler.h
===================================================================
--- /tags/2.0.1/disassembler.h	(revision 966)
+++ /tags/2.0.1/disassembler.h	(revision 966)
@@ -0,0 +1,4 @@
+#include "php.h"
+
+void xc_dasm_string(zval *return_value, zval *code TSRMLS_DC);
+void xc_dasm_file(zval *return_value, const char *filename TSRMLS_DC);
Index: /tags/2.0.1/foreachcoresig.h
===================================================================
--- /tags/2.0.1/foreachcoresig.h	(revision 966)
+++ /tags/2.0.1/foreachcoresig.h	(revision 966)
@@ -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/2.0.1/graph/cached_compile.dot
===================================================================
--- /tags/2.0.1/graph/cached_compile.dot	(revision 966)
+++ /tags/2.0.1/graph/cached_compile.dot	(revision 966)
@@ -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/2.0.1/includes.c
===================================================================
--- /tags/2.0.1/includes.c	(revision 966)
+++ /tags/2.0.1/includes.c	(revision 966)
@@ -0,0 +1,2 @@
+#include "xcache.h"
+#include "zend_compile.h"
Index: /tags/2.0.1/lock.c
===================================================================
--- /tags/2.0.1/lock.c	(revision 966)
+++ /tags/2.0.1/lock.c	(revision 966)
@@ -0,0 +1,164 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <php.h>
+#ifndef ZEND_WIN32
+typedef int HANDLE;
+#	ifndef INVALID_HANDLE_VALUE
+#		define INVALID_HANDLE_VALUE -1
+#	endif
+#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 "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/2.0.1/lock.h
===================================================================
--- /tags/2.0.1/lock.h	(revision 966)
+++ /tags/2.0.1/lock.h	(revision 966)
@@ -0,0 +1,11 @@
+typedef struct _xc_lock_t xc_lock_t;
+
+xc_lock_t *xc_fcntl_init(const char *pathname);
+void xc_fcntl_destroy(xc_lock_t *lck);
+void xc_fcntl_lock(xc_lock_t *lck);
+void xc_fcntl_unlock(xc_lock_t *lck);
+
+#define xc_lock_init(name)  xc_fcntl_init(name)
+#define xc_lock_destroy(fd) xc_fcntl_destroy(fd)
+#define xc_lock(fd)         xc_fcntl_lock(fd)
+#define xc_unlock(fd)       xc_fcntl_unlock(fd)
Index: /tags/2.0.1/mem.c
===================================================================
--- /tags/2.0.1/mem.c	(revision 966)
+++ /tags/2.0.1/mem.c	(revision 966)
@@ -0,0 +1,406 @@
+#ifdef TEST
+#include <limits.h>
+#include <stdio.h>
+#	define XCACHE_DEBUG
+#else
+#include <php.h>
+#endif
+
+#ifdef XCACHE_DEBUG
+#	define ALLOC_DEBUG_BLOCK_CHECK
+#endif
+
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#define XC_MEMBLOCK_IMPL _xc_mem_block_t
+#define XC_MEM_IMPL _xc_mem_mem_t
+#include "xc_shm.h"
+#include "align.h"
+#include "utils.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))
+
+/* {{{ mem */
+struct _xc_mem_block_t {
+#ifdef ALLOC_DEBUG_BLOCK_CHECK
+	unsigned int magic;
+#endif
+	xc_memsize_t size; /* reserved even after alloc */
+	xc_block_t *next;  /* not used after alloc */
+};
+
+struct _xc_mem_mem_t {
+	const xc_mem_handlers_t *handlers;
+	xc_shm_t                *shm;
+	xc_memsize_t size;
+	xc_memsize_t avail;       /* total free */
+	xc_block_t headblock[1];  /* just as a pointer to first block*/
+};
+
+#ifndef XtOffsetOf
+#	include <linux/stddef.h>
+#	define XtOffsetOf(s_type, field) offsetof(s_type, field)
+#endif
+
+#define SizeOf(type, field) sizeof( ((type *) 0)->field )
+#define BLOCK_HEADER_SIZE() (ALIGN( XtOffsetOf(xc_block_t, size) + SizeOf(xc_block_t, size) ))
+
+#define BLOCK_MAGIC ((unsigned int) 0x87655678)
+
+/* }}} */
+static inline void xc_block_setup(xc_block_t *b, xc_memsize_t size, xc_block_t *next) /* {{{ */
+{
+#ifdef ALLOC_DEBUG_BLOCK_CHECK
+	b->magic = BLOCK_MAGIC;
+#endif
+	b->size = size;
+	b->next = next;
+}
+/* }}} */
+#ifdef ALLOC_DEBUG_BLOCK_CHECK
+static void xc_block_check(xc_block_t *b) /* {{{ */
+{
+	if (b->magic != BLOCK_MAGIC) {
+		fprintf(stderr, "0x%X != 0x%X magic wrong \n", b->magic, BLOCK_MAGIC);
+	}
+}
+/* }}} */
+#else
+#	define xc_block_check(b) do { } while(0)
+#endif
+
+
+static XC_MEM_MALLOC(xc_mem_malloc) /* {{{ */
+{
+	xc_block_t *prev, *cur;
+	xc_block_t *newb, *b;
+	xc_memsize_t realsize;
+	xc_memsize_t minsize;
+	void *p;
+	/* [xc_block_t:size|size] */
+	realsize = BLOCK_HEADER_SIZE() + size;
+	/* realsize is ALIGNed so next block start at ALIGNed address */
+	realsize = ALIGN(realsize);
+
+	TRACE("avail: %lu (%luKB). Allocate size: %lu realsize: %lu (%luKB)"
+			, mem->avail, mem->avail / 1024
+			, size
+			, realsize, realsize / 1024
+			);
+	do {
+		p = NULL;
+		if (mem->avail < realsize) {
+			TRACE("%s", " oom");
+			break;
+		}
+
+		b = NULL;
+		minsize = ULONG_MAX;
+
+		/* prev|cur */
+
+		for (prev = mem->headblock; prev->next; prev = cur) {
+			/* while (prev->next != 0) { */
+			cur = prev->next;
+			xc_block_check(cur);
+			if (cur->size == realsize) {
+				/* found a perfect fit, stop searching */
+				b = prev;
+				break;
+			}
+			/* make sure we can split on the block */
+			else if (cur->size > (sizeof(xc_block_t) + realsize) &&
+					cur->size < minsize) {
+				/* cur is acceptable and memller */
+				b = prev;
+				minsize = cur->size;
+			}
+			prev = cur;
+		}
+
+		if (b == NULL) {
+			TRACE("%s", " no fit chunk");
+			break;
+		}
+
+		prev = b;
+
+		cur = prev->next;
+		p = PADD(cur, BLOCK_HEADER_SIZE());
+
+		/* update the block header */
+		mem->avail -= realsize;
+
+		/* perfect fit, just unlink */
+		if (cur->size == realsize) {
+			prev->next = cur->next;
+			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_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"
+				, mem->avail, mem->avail / 1024
+				, newb
+				, PSUB(newb, mem), PSUB(newb, mem) / 1024
+				, p
+				);
+		prev->next = newb;
+		/* prev|cur|newb|next
+		 *    `-----^
+		 */
+
+	} while (0);
+
+	return p;
+}
+/* }}} */
+static XC_MEM_FREE(xc_mem_free) /* {{{ return block size freed */
+{
+	xc_block_t *cur, *b;
+	int size;
+
+	cur = (xc_block_t *) (CHAR_PTR(p) - BLOCK_HEADER_SIZE());
+	TRACE("freeing: %p, size=%lu", p, cur->size);
+	xc_block_check(cur);
+	assert((char*)mem < (char*)cur && (char*)cur < (char*)mem + mem->size);
+
+	/* find free block right before the p */
+	b = mem->headblock;
+	while (b->next != 0 && b->next < cur) {
+		b = b->next;
+	}
+
+	/* restore block */
+	cur->next = b->next;
+	b->next = cur;
+	size = cur->size;
+
+	TRACE(" avail %lu (%luKB)", mem->avail, mem->avail / 1024);
+	mem->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)", mem->avail, mem->avail / 1024);
+	return size;
+}
+/* }}} */
+static XC_MEM_CALLOC(xc_mem_calloc) /* {{{ */
+{
+	xc_memsize_t realsize = memb * size;
+	void *p = xc_mem_malloc(mem, realsize);
+
+	if (p) {
+		memset(p, 0, realsize);
+	}
+	return p;
+}
+/* }}} */
+static XC_MEM_REALLOC(xc_mem_realloc) /* {{{ */
+{
+	void *newp = xc_mem_malloc(mem, size);
+	if (p && newp) {
+		memcpy(newp, p, size);
+		xc_mem_free(mem, p);
+	}
+	return newp;
+}
+/* }}} */
+static XC_MEM_STRNDUP(xc_mem_strndup) /* {{{ */
+{
+	void *p = xc_mem_malloc(mem, len + 1);
+	if (p) {
+		memcpy(p, str, len + 1);
+	}
+	return p;
+}
+/* }}} */
+static XC_MEM_STRDUP(xc_mem_strdup) /* {{{ */
+{
+	return xc_mem_strndup(mem, str, strlen(str));
+}
+/* }}} */
+
+static XC_MEM_AVAIL(xc_mem_avail) /* {{{ */
+{
+	return mem->avail;
+}
+/* }}} */
+static XC_MEM_SIZE(xc_mem_size) /* {{{ */
+{
+	return mem->size;
+}
+/* }}} */
+
+static XC_MEM_FREEBLOCK_FIRST(xc_mem_freeblock_first) /* {{{ */
+{
+	return mem->headblock->next;
+}
+/* }}} */
+XC_MEM_FREEBLOCK_NEXT(xc_mem_freeblock_next) /* {{{ */
+{
+	return block->next;
+}
+/* }}} */
+XC_MEM_BLOCK_SIZE(xc_mem_block_size) /* {{{ */
+{
+	return block->size;
+}
+/* }}} */
+XC_MEM_BLOCK_OFFSET(xc_mem_block_offset) /* {{{ */
+{
+	return ((char *) block) - ((char *) mem);
+}
+/* }}} */
+
+static XC_MEM_INIT(xc_mem_init) /* {{{ */
+{
+	xc_block_t *b;
+#define MINSIZE (ALIGN(sizeof(xc_mem_t)) + sizeof(xc_block_t))
+	/* requires at least the header and 1 tail block */
+	if (size < MINSIZE) {
+		fprintf(stderr, "xc_mem_init requires %lu bytes at least\n", (unsigned long) MINSIZE);
+		return NULL;
+	}
+	TRACE("size=%lu", size);
+	mem->shm = shm;
+	mem->size = size;
+	mem->avail = size - MINSIZE;
+
+	/* pointer to first block, right after ALIGNed header */
+	b = mem->headblock;
+	xc_block_setup(b, 0, (xc_block_t *) PADD(mem, ALIGN(sizeof(xc_mem_t))));
+
+	/* first block*/
+	b = b->next;
+	xc_block_setup(b, mem->avail, 0);
+#undef MINSIZE
+
+	return mem;
+}
+/* }}} */
+static XC_MEM_DESTROY(xc_mem_destroy) /* {{{ */
+{
+}
+/* }}} */
+
+#ifdef TEST
+/* {{{ */
+#undef CHECK
+#define CHECK(a, msg) do { if ((a) == NULL) { puts(msg); return -1; } } while (0)
+#include <time.h>
+
+int main()
+{
+	int count = 0;
+	void *p;
+	void *memory;
+	xc_mem_t *mem;
+	void **ptrs;
+	int size, i;
+
+#if 0
+	fprintf(stderr, "%s", "Input test size: ");
+	scanf("%d", &size);
+#else
+	size = 100;
+#endif
+	CHECK(memory = malloc(size), "OOM");
+	CHECK(ptrs   = malloc(size * sizeof(void*)), "OOM");
+	CHECK(mem    = xc_mem_init(memory, size), "Failed init memory allocator");
+
+	while ((p = xc_mem_malloc(mem, 1))) {
+		ptrs[count ++] = p;
+	}
+	fprintf(stderr, "count=%d, random freeing\n", count);
+	srandom(time(NULL));
+	while (count) {
+		i = (random() % count);
+		fprintf(stderr, "freeing %d: ", i);
+		xc_mem_free(mem, ptrs[i]);
+		ptrs[i] = ptrs[count - 1];
+		count --;
+	}
+
+	free(ptrs);
+	free(memory);
+	return 0;
+}
+/* }}} */
+#endif
+
+typedef struct {
+	const char              *name;
+	const xc_mem_handlers_t *handlers;
+} xc_mem_scheme_t;
+static xc_mem_scheme_t xc_mem_schemes[10];
+
+int xc_mem_scheme_register(const char *name, const xc_mem_handlers_t *handlers) /* {{{ */
+{
+	int i;
+	for (i = 0; i < 10; i ++) {
+		if (!xc_mem_schemes[i].name) {
+			xc_mem_schemes[i].name = name;
+			xc_mem_schemes[i].handlers = handlers;
+			return 1;
+		}
+	}
+	return 0;
+}
+/* }}} */
+const xc_mem_handlers_t *xc_mem_scheme_find(const char *name) /* {{{ */
+{
+	int i;
+	for (i = 0; i < 10 && xc_mem_schemes[i].name; i ++) {
+		if (strcmp(xc_mem_schemes[i].name, name) == 0) {
+			return xc_mem_schemes[i].handlers;
+		}
+	}
+	return NULL;
+}
+/* }}} */
+
+static xc_mem_handlers_t xc_mem_mem_handlers = XC_MEM_HANDLERS(mem);
+void xc_shm_mem_init() /* {{{ */
+{
+	memset(xc_mem_schemes, 0, sizeof(xc_mem_schemes));
+
+	if (xc_mem_scheme_register("mem", &xc_mem_mem_handlers) == 0) {
+		zend_error(E_ERROR, "XCache: failed to register mem mem_scheme");
+	}
+}
+/* }}} */
Index: /tags/2.0.1/mem.h
===================================================================
--- /tags/2.0.1/mem.h	(revision 966)
+++ /tags/2.0.1/mem.h	(revision 966)
@@ -0,0 +1,74 @@
+#include "xc_shm.h"
+
+typedef struct _xc_mem_handlers_t xc_mem_handlers_t;
+
+#ifndef XC_MEM_IMPL
+struct _xc_mem_t {
+	const xc_mem_handlers_t *handlers;
+	xc_shm_t                *shm;
+};
+#   define XC_MEM_IMPL _xc_mem_t
+#endif
+
+#ifndef XC_MEMBLOCK_IMPL
+#   define XC_MEMBLOCK_IMPL _xc_block_t
+#endif
+typedef struct XC_MEM_IMPL xc_mem_t;
+typedef struct XC_MEMBLOCK_IMPL xc_block_t;
+typedef xc_shmsize_t xc_memsize_t;
+
+/* shm::mem */
+#define XC_MEM_MALLOC(func)          void *func(xc_mem_t *mem, xc_memsize_t size)
+#define XC_MEM_FREE(func)            xc_memsize_t  func(xc_mem_t *mem, const void *p)
+#define XC_MEM_CALLOC(func)          void *func(xc_mem_t *mem, xc_memsize_t memb, xc_memsize_t size)
+#define XC_MEM_REALLOC(func)         void *func(xc_mem_t *mem, const void *p, xc_memsize_t size)
+#define XC_MEM_STRNDUP(func)         char *func(xc_mem_t *mem, const char *str, xc_memsize_t len)
+#define XC_MEM_STRDUP(func)          char *func(xc_mem_t *mem, const char *str)
+#define XC_MEM_AVAIL(func)           xc_memsize_t      func(xc_mem_t *mem)
+#define XC_MEM_SIZE(func)            xc_memsize_t      func(xc_mem_t *mem)
+#define XC_MEM_FREEBLOCK_FIRST(func) const xc_block_t *func(xc_mem_t *mem)
+#define XC_MEM_FREEBLOCK_NEXT(func)  const xc_block_t *func(const xc_block_t *block)
+#define XC_MEM_BLOCK_SIZE(func)      xc_memsize_t      func(const xc_block_t *block)
+#define XC_MEM_BLOCK_OFFSET(func)    xc_memsize_t      func(const xc_mem_t *mem, const xc_block_t *block)
+
+#define XC_MEM_INIT(func)            xc_mem_t *func(xc_shm_t *shm, xc_mem_t *mem, xc_memsize_t size)
+#define XC_MEM_DESTROY(func)         void func(xc_mem_t *mem)
+
+#define XC_MEM_HANDLERS(name)   {  \
+	xc_##name##_malloc             \
+	, xc_##name##_free             \
+	, xc_##name##_calloc           \
+	, xc_##name##_realloc          \
+	, xc_##name##_strndup          \
+	, xc_##name##_strdup           \
+	, 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_mem_handlers_t {
+	XC_MEM_MALLOC((*malloc));
+	XC_MEM_FREE((*free));
+	XC_MEM_CALLOC((*calloc));
+	XC_MEM_REALLOC((*realloc));
+	XC_MEM_STRNDUP((*strndup));
+	XC_MEM_STRDUP((*strdup));
+	XC_MEM_AVAIL((*avail));
+	XC_MEM_SIZE((*size));
+	XC_MEM_FREEBLOCK_FIRST((*freeblock_first));
+	XC_MEM_FREEBLOCK_NEXT((*freeblock_next));
+	XC_MEM_BLOCK_SIZE((*block_size));
+	XC_MEM_BLOCK_OFFSET((*block_offset));
+
+	XC_MEM_INIT((*init));
+	XC_MEM_DESTROY((*destroy));
+};
+
+int xc_mem_scheme_register(const char *name, const xc_mem_handlers_t *handlers);
+const xc_mem_handlers_t *xc_mem_scheme_find(const char *name);
Index: /tags/2.0.1/mkopcode.awk
===================================================================
--- /tags/2.0.1/mkopcode.awk	(revision 966)
+++ /tags/2.0.1/mkopcode.awk	(revision 966)
@@ -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/2.0.1/mkopcode_spec.awk
===================================================================
--- /tags/2.0.1/mkopcode_spec.awk	(revision 966)
+++ /tags/2.0.1/mkopcode_spec.awk	(revision 966)
@@ -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/2.0.1/mkstructinfo.awk
===================================================================
--- /tags/2.0.1/mkstructinfo.awk	(revision 966)
+++ /tags/2.0.1/mkstructinfo.awk	(revision 966)
@@ -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/2.0.1/mmap.c
===================================================================
--- /tags/2.0.1/mmap.c	(revision 966)
+++ /tags/2.0.1/mmap.c	(revision 966)
@@ -0,0 +1,323 @@
+
+#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 "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;
+	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(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) /* {{{ */
+{
+	xc_mem_t *mem;
+	if (shm->memoffset + size > shm->size) {
+		zend_error(E_ERROR, "XCache: internal error at %s#%d", __FILE__, __LINE__);
+		return NULL;
+	}
+	mem = (xc_mem_t *) PTR_ADD(shm->ptr, shm->memoffset);
+	shm->memoffset += size;
+	mem->handlers = shm->handlers->memhandlers;
+	mem->handlers->init(shm, mem, 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() /* {{{ */
+{
+	CHECK(xc_shm_mmap_handlers.memhandlers = xc_mem_scheme_find("mem"), "cannot find mem handlers");
+	if (xc_shm_scheme_register("mmap", &xc_shm_mmap_handlers) == 0) {
+		zend_error(E_ERROR, "XCache: failed to register mmap shm_scheme");
+	}
+err:
+	return;
+}
+/* }}} */
Index: /tags/2.0.1/opcode_spec.c
===================================================================
--- /tags/2.0.1/opcode_spec.c	(revision 966)
+++ /tags/2.0.1/opcode_spec.c	(revision 966)
@@ -0,0 +1,48 @@
+#include "xcache.h"
+#include "opcode_spec.h"
+#include "const_string.h"
+
+#ifdef HAVE_XCACHE_OPCODE_SPEC_DEF
+/* {{{ opcode_spec */
+#define OPSPEC(ext, op1, op2, res) { OPSPEC_##ext, OPSPEC_##op1, OPSPEC_##op2, OPSPEC_##res },
+#ifdef ZEND_ENGINE_2
+#	define OPSPEC_VAR_2 OPSPEC_STD
+#else
+#	define OPSPEC_VAR_2 OPSPEC_VAR
+#endif
+#include "opcode_spec_def.h"
+
+zend_uchar xc_get_opcode_spec_count()
+{
+	return sizeof(xc_opcode_spec) / sizeof(xc_opcode_spec[0]);
+}
+
+const xc_opcode_spec_t *xc_get_opcode_spec(zend_uchar opcode)
+{
+#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];
+}
+/* }}} */
+#endif
+/* {{{ op_spec */
+
+#define OPSPECS_DEF_NAME(name) #name,
+static const char *xc_op_spec[] = { OPSPECS(OPSPECS_DEF_NAME) };
+
+zend_uchar xc_get_op_spec_count()
+{
+	return sizeof(xc_op_spec) / sizeof(xc_op_spec[0]);
+}
+
+const char *xc_get_op_spec(zend_uchar spec)
+{
+	assert(spec < xc_get_op_spec_count());
+	return xc_op_spec[spec];
+}
+/* }}} */
Index: /tags/2.0.1/opcode_spec.h
===================================================================
--- /tags/2.0.1/opcode_spec.h	(revision 966)
+++ /tags/2.0.1/opcode_spec.h	(revision 966)
@@ -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/2.0.1/opcode_spec_def.h
===================================================================
--- /tags/2.0.1/opcode_spec_def.h	(revision 966)
+++ /tags/2.0.1/opcode_spec_def.h	(revision 966)
@@ -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/2.0.1/optimizer.c
===================================================================
--- /tags/2.0.1/optimizer.c	(revision 966)
+++ /tags/2.0.1/optimizer.c	(revision 966)
@@ -0,0 +1,616 @@
+#if 0
+#	define XCACHE_DEBUG
+#endif
+
+#include "utils.h"
+#include "optimizer.h"
+/* the "vector" stack */
+#include "stack.h"
+#include "xcache_globals.h"
+
+#ifdef XCACHE_DEBUG
+#	include "processor.h"
+#	include "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 int bbid_t;
+enum {
+	BBID_INVALID = -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
+
+	int        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) /* {{{ */
+{
+	int 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 ++) {
+		int 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;
+}
+/* }}} */
+void xc_optimizer_op_array_handler(zend_op_array *op_array) /* {{{ */
+{
+	TSRMLS_FETCH();
+	if (XG(optimizer)) {
+		xc_optimize_op_array(op_array TSRMLS_CC);
+	}
+}
+/* }}} */
Index: /tags/2.0.1/optimizer.h
===================================================================
--- /tags/2.0.1/optimizer.h	(revision 966)
+++ /tags/2.0.1/optimizer.h	(revision 966)
@@ -0,0 +1,4 @@
+#include "php.h"
+#include "xcache.h"
+
+void xc_optimizer_op_array_handler(zend_op_array *op_array);
Index: /tags/2.0.1/phpdc.phpr
===================================================================
--- /tags/2.0.1/phpdc.phpr	(revision 966)
+++ /tags/2.0.1/phpdc.phpr	(revision 966)
@@ -0,0 +1,33 @@
+#! /usr/bin/php -dopen_basedir=
+<?php
+
+$srcdir = dirname(__FILE__);
+require_once("$srcdir/Decompiler.class.php");
+if (file_exists("$srcdir/phpdc.debug.php")) {
+	include("$srcdir/phpdc.debug.php");
+}
+
+if (!isset($argv)) {
+	$argv = $_SERVER['argv'];
+	$argc = $_SERVER['argc'];
+}
+
+$dc = new Decompiler();
+if (isset($argv[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/2.0.1/phpdop.phpr
===================================================================
--- /tags/2.0.1/phpdop.phpr	(revision 966)
+++ /tags/2.0.1/phpdop.phpr	(revision 966)
@@ -0,0 +1,130 @@
+#! /usr/bin/php
+<?php
+
+$srcdir = dirname(__FILE__);
+require_once("$srcdir/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/2.0.1/prepare.devel
===================================================================
--- /tags/2.0.1/prepare.devel	(revision 966)
+++ /tags/2.0.1/prepare.devel	(revision 966)
@@ -0,0 +1,105 @@
+#! /bin/bash
+SELF="$0"
+
+if test -e prepare.devel.inc ; then
+	. prepare.devel.inc
+else
+	echo prepare.devel.inc is required, see prepare.devel.inc.example >&2
+	exit
+fi
+
+CTAGS=`which ctags 2>/dev/null || which exuberant-ctags 2>/dev/null `
+AWK=`which gawk 2>/dev/null || which awk 2>/dev/null `
+
+make_all() {
+	make_opcode_spec_def.h
+	make_const_string
+	test -e tags && echo tags exists, skipping. use \""$0" tags\" to rebuild || make_tags
+}
+
+make_clean() {
+ 	make_clean_const_string
+	echo "*" rm -f tags opcode_spec_def.h
+	rm -f tags opcode_spec_def.h
+}
+
+make_const_string() {
+	make_const_string_opcodes_php4.x.h
+	make_const_string_opcodes_php5.0.h
+	make_const_string_opcodes_php5.1.h
+	make_const_string_opcodes_php5.4.h
+	make_const_string_opcodes_php6.x.h
+}
+
+make_clean_const_string() {
+	echo "*" rm -f const_string_opcodes_php*.h{,.tmp}
+	rm -f const_string_opcodes_php*.h
+}
+
+make_const_string_opcodes_php4.x.h() {
+	precheck const_string_opcodes_php4.x.h "${PHP4_x_DIR}/Zend/zend_compile.h" && "$AWK" -f ./mkopcode.awk < "$I" > "$O.tmp" && mv "$O.tmp" "$O"
+}
+
+make_const_string_opcodes_php5.0.h() {
+	precheck const_string_opcodes_php5.0.h "${PHP5_0_DIR}/Zend/zend_compile.h" && "$AWK" -f ./mkopcode.awk < "$I" > "$O.tmp" && mv "$O.tmp" "$O"
+}
+
+make_const_string_opcodes_php5.1.h() {
+	precheck const_string_opcodes_php5.1.h "${PHP5_1_DIR}/Zend/zend_vm_def.h"  && "$AWK" -f ./mkopcode.awk < "$I" > "$O.tmp" && mv "$O.tmp" "$O"
+}
+
+make_const_string_opcodes_php5.4.h() {
+	precheck const_string_opcodes_php5.4.h "${PHP5_4_DIR}/Zend/zend_vm_def.h"  && "$AWK" -f ./mkopcode.awk < "$I" > "$O.tmp" && mv "$O.tmp" "$O"
+}
+
+make_const_string_opcodes_php6.x.h() {
+	precheck const_string_opcodes_php6.x.h "${PHP6_x_DIR}/Zend/zend_vm_def.h"  && "$AWK" -f ./mkopcode.awk < "$I" > "$O.tmp" && mv "$O.tmp" "$O"
+}
+
+make_opcode_spec_def.h() {
+	precheck "opcode_spec_def.h" "${EA_DIR}/opcodes.c" && "$AWK" -f ./mkopcode_spec.awk < "$I" > "$O"
+}
+
+make_tags() {
+	if test -z "$CTAGS" ; then
+		echo tool ctags not found, skip building tags >&2
+		return
+	fi
+
+	if test -d "${PHP_DEVEL_DIR}" ; then
+		echo "* Making tags with ${PHP_DEVEL_DIR}"
+		"$CTAGS" -R . "${PHP_DEVEL_DIR}/main" "${PHP_DEVEL_DIR}/Zend" "${PHP_DEVEL_DIR}/TSRM" "${PHP_DEVEL_DIR}/ext/standard"
+	else
+		echo "* Making tags without php source files"
+		"$CTAGS" -R .
+	fi
+}
+
+error() {
+	echo "$@" >&2
+}
+
+precheck() {
+	if test -e "$2" ; then :; else
+		error X skipping "$1" because "$2" not found
+		return 1
+	fi
+	if test "$1" -ot "$2" ; then :; else
+		echo O "$1" is up to date.
+		return 1
+	fi
+	O="$1"
+	I="$2"
+	echo "* Making $1 from $2"
+	return 0
+}
+
+if test -z "$1" ; then
+	make_all
+else
+	while ! test -z "$1" ; do
+		eval "make_$1"
+		shift
+	done
+fi
+
Index: /tags/2.0.1/prepare.devel.inc.example
===================================================================
--- /tags/2.0.1/prepare.devel.inc.example	(revision 966)
+++ /tags/2.0.1/prepare.devel.inc.example	(revision 966)
@@ -0,0 +1,11 @@
+# copy this file as devel.prepare.inc before modifying
+PHP4_x_DIR=
+PHP5_0_DIR=
+PHP5_1_DIR=
+PHP5_3_DIR=
+PHP6_x_DIR=
+
+PHP_DEVEL_DIR=
+
+# path to eaccelerator source dir
+EA_DIR=
Index: /tags/2.0.1/processor.c
===================================================================
--- /tags/2.0.1/processor.c	(revision 966)
+++ /tags/2.0.1/processor.c	(revision 966)
@@ -0,0 +1,1 @@
+#include "processor_real.c"
Index: /tags/2.0.1/processor/hashtable.m4
===================================================================
--- /tags/2.0.1/processor/hashtable.m4	(revision 966)
+++ /tags/2.0.1/processor/hashtable.m4	(revision 966)
@@ -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/2.0.1/processor/head.m4
===================================================================
--- /tags/2.0.1/processor/head.m4	(revision 966)
+++ /tags/2.0.1/processor/head.m4	(revision 966)
@@ -0,0 +1,546 @@
+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"
+
+#include "xcache.h"
+#include "align.h"
+#include "const_string.h"
+#include "processor.h"
+#include "stack.h"
+#include "xcache_globals.h"
+
+#if defined(HARDENING_PATCH_HASH_PROTECT) && HARDENING_PATCH_HASH_PROTECT
+extern unsigned int zend_hash_canary;
+#endif
+
+define(`SIZEOF_zend_uint', `sizeof(zend_uint)')
+define(`COUNTOF_zend_uint', `1')
+define(`SIZEOF_int', `sizeof(int)')
+define(`COUNTOF_int', `1')
+define(`SIZEOF_zend_function', `sizeof(zend_function)')
+define(`COUNTOF_zend_function', `1')
+define(`SIZEOF_zval_ptr', `sizeof(zval_ptr)')
+define(`COUNTOF_zval_ptr', `1')
+define(`SIZEOF_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;
+	const xc_cache_t          *cache;
+	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
+					, "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;
+			int i;
+			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
+					, "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_cache_t *cache, $1 *src TSRMLS_DC); :export {{{ */
+$1 *xc_processor_store_$1(xc_cache_t *cache, $1 *src TSRMLS_DC) {
+	$1 *dst;
+	xc_processor_t processor;
+
+	memset(&processor, 0, sizeof(processor));
+	processor.reference = 1;
+	processor.cache = cache;
+
+	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);
+		}
+
+		/* mem :) */
+		processor.p = (char *) processor.cache->mem->handlers->malloc(processor.cache->mem, 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(` {
+			int real = processor.p - oldp;
+			int should = processor.size;
+			if (real != processor.size) {
+				fprintf(stderr, "real %d - should %d = %d\n", real, should, real - should);
+				abort();
+			}
+		}')
+err_alloc:
+		if (processor.reference) {
+			zend_hash_destroy(&processor.zvalptrs);
+		}
+		zend_hash_destroy(&processor.strings);
+	}
+	/* }}} */
+
+	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/2.0.1/processor/main.m4
===================================================================
--- /tags/2.0.1/processor/main.m4	(revision 966)
+++ /tags/2.0.1/processor/main.m4	(revision 966)
@@ -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->cache->shm->handlers->to_readonly(processor->cache->shm, (char *)$2);
+')')
+define(`UNFIXPOINTER', `UNFIXPOINTER_EX(`$1', `dst->$2')')
+define(`UNFIXPOINTER_EX', `IFSTORE(`
+	$2 = ($1 *) processor->cache->shm->handlers->to_readwrite(processor->cache->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/2.0.1/processor/process.m4
===================================================================
--- /tags/2.0.1/processor/process.m4	(revision 966)
+++ /tags/2.0.1/processor/process.m4	(revision 966)
@@ -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/2.0.1/processor/processor.m4
===================================================================
--- /tags/2.0.1/processor/processor.m4	(revision 966)
+++ /tags/2.0.1/processor/processor.m4	(revision 966)
@@ -0,0 +1,1216 @@
+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:
+				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);
+				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(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);
+				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:
+						Z_OP(opline->op1).jmp_addr = &dst->opcodes[Z_OP(opline->op1).jmp_addr - src->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
+						Z_OP(opline->op2).jmp_addr = &dst->opcodes[Z_OP(opline->op2).jmp_addr - src->opcodes];
+						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 E_STRICT
+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 E_STRICT
+	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/2.0.1/processor/string.m4
===================================================================
--- /tags/2.0.1/processor/string.m4	(revision 966)
+++ /tags/2.0.1/processor/string.m4	(revision 966)
@@ -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/2.0.1/processor/struct.m4
===================================================================
--- /tags/2.0.1/processor/struct.m4	(revision 966)
+++ /tags/2.0.1/processor/struct.m4	(revision 966)
@@ -0,0 +1,231 @@
+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(`missing SIZEOF_$1, safe to ignore')')
+			ifdef(`COUNTOF_$1', , `m4_errprint(`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;
+			const char *xc_autocheck_assert_names[] = { ifdef(`ELEMENTSOF_$1', `ELEMENTSOF_$1') };
+			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, sizeof(xc_autocheck_assert_names) / sizeof(xc_autocheck_assert_names[0]), &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/2.0.1/run-xcachetest
===================================================================
--- /tags/2.0.1/run-xcachetest	(revision 966)
+++ /tags/2.0.1/run-xcachetest	(revision 966)
@@ -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/2.0.1/stack.c
===================================================================
--- /tags/2.0.1/stack.c	(revision 966)
+++ /tags/2.0.1/stack.c	(revision 966)
@@ -0,0 +1,62 @@
+#include <stdlib.h>
+#include <assert.h>
+#include "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/2.0.1/stack.h
===================================================================
--- /tags/2.0.1/stack.h	(revision 966)
+++ /tags/2.0.1/stack.h	(revision 966)
@@ -0,0 +1,18 @@
+
+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
Index: /tags/2.0.1/test.mak
===================================================================
--- /tags/2.0.1/test.mak	(revision 966)
+++ /tags/2.0.1/test.mak	(revision 966)
@@ -0,0 +1,21 @@
+#! /usr/bin/make -f
+
+EXES=mem_test
+OBJS=mem.o
+CC=gcc
+CFLAGS=-g -O0 -D TEST -Wall
+TEST=valgrind
+
+all: mem
+
+mem_test: mem.c
+	$(CC) $(CFLAGS) -o mem_test mem.c
+	
+mem: mem_test
+	$(TEST) ./mem_test
+
+clean:
+	rm -f $(OBJS) $(EXES)
+
+leakcheck:
+	valgrind php -c test.ini test.ini
Index: /tags/2.0.1/tests/include-skipif.php
===================================================================
--- /tags/2.0.1/tests/include-skipif.php	(revision 966)
+++ /tags/2.0.1/tests/include-skipif.php	(revision 966)
@@ -0,0 +1,5 @@
+<?php
+if (version_compare(PHP_VERSION, '5.3.0', '<')) {
+	die('skip __DIR__ not supported in this php version');
+}
+?>
Index: /tags/2.0.1/tests/sub-a.php
===================================================================
--- /tags/2.0.1/tests/sub-a.php	(revision 966)
+++ /tags/2.0.1/tests/sub-a.php	(revision 966)
@@ -0,0 +1,5 @@
+<?php
+
+echo __DIR__, PHP_EOL;
+echo __FILE__, PHP_EOL;
+
Index: /tags/2.0.1/tests/sub-b.php
===================================================================
--- /tags/2.0.1/tests/sub-b.php	(revision 966)
+++ /tags/2.0.1/tests/sub-b.php	(revision 966)
@@ -0,0 +1,5 @@
+<?php
+
+echo __DIR__, PHP_EOL;
+echo __FILE__, PHP_EOL;
+
Index: /tags/2.0.1/tests/xcache_include_absolute.phpt
===================================================================
--- /tags/2.0.1/tests/xcache_include_absolute.phpt	(revision 966)
+++ /tags/2.0.1/tests/xcache_include_absolute.phpt	(revision 966)
@@ -0,0 +1,16 @@
+--TEST--
+include absolute path
+--SKIPIF--
+<?php
+require("include-skipif.php");
+?>
+--FILE--
+<?php
+include __DIR__ . "/sub-a.php";
+include __DIR__ . "/sub-b.php";
+?>
+--EXPECTF--
+%stests
+%stests%ssub-a.php
+%stests
+%stests%ssub-b.php
Index: /tags/2.0.1/tests/xcache_include_relative_cwd.phpt
===================================================================
--- /tags/2.0.1/tests/xcache_include_relative_cwd.phpt	(revision 966)
+++ /tags/2.0.1/tests/xcache_include_relative_cwd.phpt	(revision 966)
@@ -0,0 +1,17 @@
+--TEST--
+include relative to current working dir
+--SKIPIF--
+<?php
+require("include-skipif.php");
+?>
+--FILE--
+<?php
+chdir(__DIR__);
+include "./sub-a.php";
+include "./sub-b.php";
+?>
+--EXPECTF--
+%stests
+%stests%ssub-a.php
+%stests
+%stests%ssub-b.php
Index: /tags/2.0.1/tests/xcache_include_relative_file.phpt
===================================================================
--- /tags/2.0.1/tests/xcache_include_relative_file.phpt	(revision 966)
+++ /tags/2.0.1/tests/xcache_include_relative_file.phpt	(revision 966)
@@ -0,0 +1,16 @@
+--TEST--
+include relative to current file
+--SKIPIF--
+<?php
+require("include-skipif.php");
+?>
+--FILE--
+<?php
+include "sub-a.php";
+include "sub-b.php";
+?>
+--EXPECTF--
+%stests
+%stests%ssub-a.php
+%stests
+%stests%ssub-b.php
Index: /tags/2.0.1/tests/xcache_is_autoglobal.phpt
===================================================================
--- /tags/2.0.1/tests/xcache_is_autoglobal.phpt	(revision 966)
+++ /tags/2.0.1/tests/xcache_is_autoglobal.phpt	(revision 966)
@@ -0,0 +1,8 @@
+--TEST--
+xcache_is_autoglobal
+--FILE--
+<?php
+var_dump(xcache_is_autoglobal("GLOBALS"));
+?>
+--EXPECT--
+bool(true)
Index: /tags/2.0.1/tests/xcache_var.phpt
===================================================================
--- /tags/2.0.1/tests/xcache_var.phpt	(revision 966)
+++ /tags/2.0.1/tests/xcache_var.phpt	(revision 966)
@@ -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/2.0.1/utils.c
===================================================================
--- /tags/2.0.1/utils.c	(revision 966)
+++ /tags/2.0.1/utils.c	(revision 966)
@@ -0,0 +1,1135 @@
+
+#include "xcache.h"
+#include "stack.h"
+#include "xcache_globals.h"
+#include "utils.h"
+#ifdef ZEND_ENGINE_2_1
+#include "zend_vm.h"
+#endif
+#include "opcode_spec.h"
+#undef NDEBUG
+#include "assert.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
+
+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);
+}
+/* }}} */
+
+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) /* {{{ */
+{
+}
+/* }}} */
+
+int xc_apply_function(zend_function *zf, apply_func_t applyer TSRMLS_DC) /* {{{ */
+{
+	switch (zf->type) {
+	case ZEND_USER_FUNCTION:
+	case ZEND_EVAL_CODE:
+		return applyer(&zf->op_array TSRMLS_CC);
+		break;
+
+	case ZEND_INTERNAL_FUNCTION:
+	case ZEND_OVERLOADED_FUNCTION:
+		break;
+
+	EMPTY_SWITCH_DEFAULT_CASE();
+	}
+	return 0;
+}
+/* }}} */
+typedef struct {
+	apply_func_t applyer;
+	zend_class_entry *ce;
+} xc_apply_method_info;
+int xc_apply_method(zend_function *zf, xc_apply_method_info *mi TSRMLS_DC) /* {{{ */
+{
+	/* avoid duplicate apply for shadowed method */
+#ifdef ZEND_ENGINE_2
+	if (mi->ce != zf->common.scope) {
+		/* fprintf(stderr, "avoided duplicate %s\n", zf->common.function_name); */
+		return 0;
+	}
+#else
+	char *name = zf->common.function_name;
+	int name_s = strlen(name) + 1;
+	zend_class_entry *ce;
+	zend_function *ptr;
+
+	for (ce = mi->ce->parent; ce; ce = ce->parent) {
+		if (zend_hash_find(&ce->function_table, name, name_s, (void **) &ptr) == SUCCESS) {
+			if (ptr->op_array.refcount == zf->op_array.refcount) {
+				return 0;
+			}
+		}
+	}
+#endif
+	return xc_apply_function(zf, mi->applyer TSRMLS_CC);
+}
+/* }}} */
+#if 0
+int xc_apply_class(zend_class_entry *ce, apply_func_t applyer TSRMLS_DC) /* {{{ */
+{
+	xc_apply_method_info mi;
+
+	mi.applyer = applyer;
+	mi.ce      = ce;
+	zend_hash_apply_with_argument(&(ce->function_table), (apply_func_arg_t) xc_apply_method, &mi TSRMLS_CC);
+	return 0;
+}
+/* }}} */
+#endif
+static int xc_apply_cest(xc_cest_t *cest, apply_func_t applyer TSRMLS_DC) /* {{{ */
+{
+	xc_apply_method_info mi;
+
+	mi.applyer = applyer;
+	mi.ce      = CestToCePtr(*cest);
+	zend_hash_apply_with_argument(&(CestToCePtr(*cest)->function_table), (apply_func_arg_t) xc_apply_method, &mi TSRMLS_CC);
+	return 0;
+}
+/* }}} */
+int xc_apply_op_array(xc_compile_result_t *cr, apply_func_t applyer TSRMLS_DC) /* {{{ */
+{
+	zend_hash_apply_with_argument(cr->function_table, (apply_func_arg_t) xc_apply_function, (void *) applyer TSRMLS_CC);
+	zend_hash_apply_with_argument(cr->class_table, (apply_func_arg_t) xc_apply_cest, (void *) applyer TSRMLS_CC);
+
+	return applyer(cr->op_array TSRMLS_CC);
+}
+/* }}} */
+int xc_undo_pass_two(zend_op_array *op_array TSRMLS_DC) /* {{{ */
+{
+	zend_op *opline, *end;
+
+#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;
+	end = opline + op_array->last;
+	while (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, *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 *end = literal + op_array->last_literal;
+		while (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;
+	end = opline + op_array->last;
+	while (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;
+}
+/* }}} */
+
+#ifdef HAVE_XCACHE_OPCODE_SPEC_DEF
+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;
+}
+/* }}} */
+#endif
+
+int xc_foreach_early_binding_class(zend_op_array *op_array, void (*callback)(zend_op *opline, int oplineno, void *data TSRMLS_DC), void *data TSRMLS_DC) /* {{{ */
+{
+	zend_op *opline, *begin, *end, *next = NULL;
+
+	opline = begin = op_array->opcodes;
+	end = opline + op_array->last;
+	while (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 = 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
+static 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);
+}
+/* }}} */
+
+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
+#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
+
+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));
+}
+/* }}} */
+static void xc_free_zend_constant(zend_constant *c) /* {{{ */
+{
+	if (!(c->flags & CONST_PERSISTENT)) {
+		zval_dtor(&c->value);
+	}
+	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
+
+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
+
+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;
+}
+/* }}} */
+
+#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
+
+/* init/destroy */
+int xc_util_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_util_destroy() /* {{{ */
+{
+#ifdef XCACHE_ERROR_CACHING
+	if (zend_error_cb == xc_sandbox_error_cb) {
+		zend_error_cb = old_zend_error_cb;
+	}
+#endif
+}
+/* }}} */
+
Index: /tags/2.0.1/utils.h
===================================================================
--- /tags/2.0.1/utils.h	(revision 966)
+++ /tags/2.0.1/utils.h	(revision 966)
@@ -0,0 +1,158 @@
+#include "php.h"
+#include "xcache.h"
+
+#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>
+
+int xc_util_init(int module_number TSRMLS_DC);
+void xc_util_destroy();
+
+typedef struct {
+	zend_op_array *op_array;
+	HashTable *function_table;
+	HashTable *class_table;
+} xc_compile_result_t;
+
+xc_compile_result_t *xc_compile_result_init(xc_compile_result_t *cr,
+		zend_op_array *op_array,
+		HashTable *function_table,
+		HashTable *class_table);
+void xc_compile_result_free(xc_compile_result_t *cr);
+xc_compile_result_t *xc_compile_result_init_cur(xc_compile_result_t *cr, zend_op_array *op_array TSRMLS_DC);
+/* apply func */
+int xc_apply_function(zend_function *zf, apply_func_t applyer TSRMLS_DC);
+int xc_apply_class(zend_class_entry *ce, apply_func_t applyer TSRMLS_DC);
+int xc_apply_op_array(xc_compile_result_t *cr, apply_func_t applyer TSRMLS_DC);
+
+int xc_undo_pass_two(zend_op_array *op_array TSRMLS_DC);
+int xc_redo_pass_two(zend_op_array *op_array TSRMLS_DC);
+int xc_fix_opcode(zend_op_array *op_array TSRMLS_DC);
+int xc_undo_fix_opcode(zend_op_array *op_array TSRMLS_DC);
+zend_uchar xc_get_fixed_opcode(zend_uchar opcode, int line);
+
+int xc_foreach_early_binding_class(zend_op_array *op_array, void (*callback)(zend_op *opline, int oplineno, void *data TSRMLS_DC), 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);
+
+#if defined(E_STRICT) || defined(E_DEPRECATED)
+#define XCACHE_ERROR_CACHING
+#endif
+
+/* 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
+xc_compilererror_t *xc_sandbox_compilererrors(TSRMLS_D);
+zend_uint xc_sandbox_compilererror_cnt(TSRMLS_D);
+#endif
+
+void xc_zend_class_add_ref(zend_class_entry ZESW(*ce, **ce));
+
+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_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
+
+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)
+
Index: /tags/2.0.1/xc_malloc.c
===================================================================
--- /tags/2.0.1/xc_malloc.c	(revision 966)
+++ /tags/2.0.1/xc_malloc.c	(revision 966)
@@ -0,0 +1,250 @@
+#define XC_SHM_IMPL _xc_malloc_shm_t
+#define XC_MEM_IMPL _xc_malloc_mem_t
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include "xc_shm.h"
+#include "php.h"
+#include "align.h"
+#include "utils.h"
+
+struct _xc_malloc_mem_t {
+	const xc_mem_handlers_t *handlers;
+	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;
+#ifdef HAVE_XCACHE_TEST
+	HashTable blocks;
+#endif
+};
+/* }}} */
+
+#define CHECK(x, e) do { if ((x) == NULL) { zend_error(E_ERROR, "XCache: " e); goto err; } } while (0)
+
+static void *xc_add_to_blocks(xc_mem_t *mem, void *p, size_t size) /* {{{ */
+{
+#ifdef HAVE_XCACHE_TEST
+	if (p) {
+		zend_hash_add(&mem->shm->blocks, (void *) &p, sizeof(p), (void *) &size, sizeof(size), NULL);
+	}
+#endif
+	return p;
+}
+/* }}} */
+static void xc_del_from_blocks(xc_mem_t *mem, void *p) /* {{{ */
+{
+#ifdef HAVE_XCACHE_TEST
+	zend_hash_del(&mem->shm->blocks, (void *) &p, sizeof(p));
+#endif
+}
+/* }}} */
+
+static XC_MEM_MALLOC(xc_malloc_malloc) /* {{{ */
+{
+	return xc_add_to_blocks(mem, malloc(size), size);
+}
+/* }}} */
+static XC_MEM_FREE(xc_malloc_free) /* {{{ return block size freed */
+{
+	xc_del_from_blocks(mem, (void *) p);
+	free((void *) p);
+	return 0;
+}
+/* }}} */
+static XC_MEM_CALLOC(xc_malloc_calloc) /* {{{ */
+{
+	return xc_add_to_blocks(mem, calloc(memb, size), size);
+}
+/* }}} */
+static XC_MEM_REALLOC(xc_malloc_realloc) /* {{{ */
+{
+	return xc_add_to_blocks(mem, realloc((void *) p, size), size);
+}
+/* }}} */
+static XC_MEM_STRNDUP(xc_malloc_strndup) /* {{{ */
+{
+	char *p = xc_add_to_blocks(mem, malloc(len), len);
+	if (!p) {
+		return NULL;
+	}
+	return memcpy(p, str, len);
+}
+/* }}} */
+static XC_MEM_STRDUP(xc_malloc_strdup) /* {{{ */
+{
+	return xc_malloc_strndup(mem, str, strlen(str) + 1);
+}
+/* }}} */
+
+static XC_MEM_AVAIL(xc_malloc_avail) /* {{{ */
+{
+	return mem->avail;
+}
+/* }}} */
+static XC_MEM_SIZE(xc_malloc_size) /* {{{ */
+{
+	return mem->size;
+}
+/* }}} */
+
+static XC_MEM_FREEBLOCK_FIRST(xc_malloc_freeblock_first) /* {{{ */
+{
+	return (void *) -1;
+}
+/* }}} */
+XC_MEM_FREEBLOCK_NEXT(xc_malloc_freeblock_next) /* {{{ */
+{
+	return NULL;
+}
+/* }}} */
+XC_MEM_BLOCK_SIZE(xc_malloc_block_size) /* {{{ */
+{
+	return 0;
+}
+/* }}} */
+XC_MEM_BLOCK_OFFSET(xc_malloc_block_offset) /* {{{ */
+{
+	return 0;
+}
+/* }}} */
+
+static XC_MEM_INIT(xc_mem_malloc_init) /* {{{ */
+{
+#define MINSIZE (ALIGN(sizeof(xc_mem_t)))
+	/* requires at least the header and 1 tail block */
+	if (size < MINSIZE) {
+		fprintf(stderr, "xc_mem_malloc_init requires %lu bytes at least\n", (unsigned long) MINSIZE);
+		return NULL;
+	}
+	mem->shm = shm;
+	mem->size = size;
+	mem->avail = size - MINSIZE;
+#undef MINSIZE
+
+	return mem;
+}
+/* }}} */
+static XC_MEM_DESTROY(xc_mem_malloc_destroy) /* {{{ */
+{
+}
+/* }}} */
+
+static XC_SHM_CAN_READONLY(xc_malloc_can_readonly) /* {{{ */
+{
+	return 0;
+}
+/* }}} */
+static XC_SHM_IS_READWRITE(xc_malloc_is_readwrite) /* {{{ */
+{
+#ifdef HAVE_XCACHE_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) /* {{{ */
+{
+#ifdef HAVE_XCACHE_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;
+
+#ifdef HAVE_XCACHE_TEST
+	zend_hash_init(&shm->blocks, 64, NULL, NULL, 1);
+#endif
+	return shm;
+err:
+	return NULL;
+}
+/* }}} */
+
+static XC_SHM_MEMINIT(xc_malloc_meminit) /* {{{ */
+{
+	xc_mem_t *mem;
+	if (shm->memoffset + size > shm->size) {
+		zend_error(E_ERROR, "XCache: internal error at %s#%d", __FILE__, __LINE__);
+		return NULL;
+	}
+	shm->memoffset += size;
+	CHECK(mem = calloc(1, sizeof(xc_mem_t)), "mem OOM");
+	mem->handlers = shm->handlers->memhandlers;
+	mem->handlers->init(shm, mem, size);
+	return mem;
+err:
+	return NULL;
+}
+/* }}} */
+static XC_SHM_MEMDESTROY(xc_malloc_memdestroy) /* {{{ */
+{
+	mem->handlers->destroy(mem);
+	free(mem);
+}
+/* }}} */
+
+#define xc_malloc_destroy xc_mem_malloc_destroy
+#define xc_malloc_init xc_mem_malloc_init
+static xc_mem_handlers_t xc_mem_malloc_handlers = XC_MEM_HANDLERS(malloc);
+#undef xc_malloc_init
+#undef xc_malloc_destroy
+static xc_shm_handlers_t xc_shm_malloc_handlers = XC_SHM_HANDLERS(malloc);
+void xc_shm_malloc_register() /* {{{ */
+{
+	if (xc_mem_scheme_register("malloc", &xc_mem_malloc_handlers) == 0) {
+		zend_error(E_ERROR, "XCache: failed to register malloc mem_scheme");
+	}
+
+	CHECK(xc_shm_malloc_handlers.memhandlers = xc_mem_scheme_find("malloc"), "cannot find malloc handlers");
+	if (xc_shm_scheme_register("malloc", &xc_shm_malloc_handlers) == 0) {
+		zend_error(E_ERROR, "XCache: failed to register malloc shm_scheme");
+	}
+err:
+	return;
+}
+/* }}} */
Index: /tags/2.0.1/xc_shm.c
===================================================================
--- /tags/2.0.1/xc_shm.c	(revision 966)
+++ /tags/2.0.1/xc_shm.c	(revision 966)
@@ -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_shm_mem_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_shm_mem_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/2.0.1/xc_shm.h
===================================================================
--- /tags/2.0.1/xc_shm.h	(revision 966)
+++ /tags/2.0.1/xc_shm.h	(revision 966)
@@ -0,0 +1,70 @@
+#ifndef XC_SHM_H
+#define XC_SHM_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;
+
+#include "mem.h"
+
+/* 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)      xc_mem_t *func(xc_shm_t *shm, xc_memsize_t size)
+#define XC_SHM_MEMDESTROY(func)   void func(xc_mem_t *mem)
+
+#define XC_SHM_HANDLERS(name)    { \
+	NULL                           \
+	, 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 {
+	const xc_mem_handlers_t *memhandlers;
+	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/2.0.1/xcache-test.ini
===================================================================
--- /tags/2.0.1/xcache-test.ini	(revision 966)
+++ /tags/2.0.1/xcache-test.ini	(revision 966)
@@ -0,0 +1,27 @@
+memory_limit = 256M
+error_reporting = E_ALL|E_STRICT
+
+[xcache]
+zend_extension_debug_ts=./modules/xcache.so
+zend_extension_debug=./modules/xcache.so
+zend_extension_ts=./modules/xcache.so
+zend_extension=./modules/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/2.0.1/xcache-zh-gb2312.ini
===================================================================
--- /tags/2.0.1/xcache-zh-gb2312.ini	(revision 966)
+++ /tags/2.0.1/xcache-zh-gb2312.ini	(revision 966)
@@ -0,0 +1,81 @@
+;; ±¾ÎÄ¼þÖ»ÊÇÀý×Ó, ÇëÔÚ php.ini ÀïÉèÖÃÒÔ±ãÉúÐ§
+[xcache-common]
+;; ¾¯¸æ: zend_extension* = *xcache* ±ØÐëÊÇËùÓÐ zend_extension*=* Ö®ÖÐµÚÒ»¸ö³öÏÖ
+;; °²×°³É zend extension, Â·¾¶Ò»°ãÊÇ "$extension_dir/xcache.so"
+;; ²»ÍÆ¼öÊ¹ÓÃ extension=xcache.so
+
+;; ·Ç windows Àý×Ó
+;; install as zend extension, normally "$extension_dir/xcache.so"
+zend_extension = /usr/local/lib/php/extensions/non-debug-non-zts-xxx/xcache.so
+;; Windows ÏµÍ³Àý×Ó:
+zend_extension_ts = c:/php/extensions/php_xcache.dll
+;; ¶ÔÓÚÐÂ°æ±¾ PHP, _ts ºó×ºÒÑ¾­ÒÆ³ý, ÇëÊ¹ÓÃÏÂÃæÕâÐÐ
+zend_extension = c:/php/extensions/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"
+
+
+; ½öÓÃÓÚ *nix ÏµÍ³
+; ÉèÖÃÎª¿Õ(½ûÓÃ) »òÕßÀàËÆ "/tmp/phpcore/"
+; ×¢Òâ¸ÃÄ¿Â¼Ó¦¸ÃÄÜ±» php Ð´ÈëÎÄ¼þ (¸ú open_basedir ÎÞ¹Ø)
+xcache.coredump_directory =   ""
+
+; ÆôÓÃÊµÑéÐÔ¹¦ÄÜ (Èç¹ûÓÐ)
+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
+
+; ½öÔÚ php ini ÎÄ¼þÄÚÉèÖÃ
+; ÇëÈ·±£±¾Ä¿Â¼ÄÜ±» coverage viewer ½Å±¾¶ÁÈ¡ (×¢Òâ open_basedir)
+xcache.coveragedump_directory = ""
Index: /tags/2.0.1/xcache.c
===================================================================
--- /tags/2.0.1/xcache.c	(revision 966)
+++ /tags/2.0.1/xcache.c	(revision 966)
@@ -0,0 +1,4136 @@
+
+#if 0
+#define XCACHE_DEBUG
+#endif
+
+#if 0
+#define SHOW_DPRINT
+#endif
+
+/* {{{ macros */
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <signal.h>
+
+#include "php.h"
+#include "ext/standard/info.h"
+#include "ext/standard/md5.h"
+#include "ext/standard/php_math.h"
+#include "ext/standard/php_string.h"
+#include "zend_extensions.h"
+#include "SAPI.h"
+
+#include "xcache.h"
+#ifdef ZEND_ENGINE_2_1
+#include "ext/date/php_date.h"
+#endif
+#include "optimizer.h"
+#include "coverager.h"
+#include "disassembler.h"
+#include "align.h"
+#include "stack.h"
+#include "xcache_globals.h"
+#include "processor.h"
+#include "const_string.h"
+#include "opcode_spec.h"
+#include "utils.h"
+
+#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)
+
+/* }}} */
+
+/* {{{ globals */
+static char *xc_shm_scheme = NULL;
+static char *xc_mmap_path = NULL;
+static char *xc_coredump_dir = NULL;
+
+static xc_hash_t xc_php_hcache = { 0 };
+static xc_hash_t xc_php_hentry = { 0 };
+static xc_hash_t xc_var_hcache = { 0 };
+static xc_hash_t xc_var_hentry = { 0 };
+
+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;
+
+/* 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 *origin_compile_file = NULL;
+static zend_compile_file_t *old_compile_file = NULL;
+static zend_llist_element  *xc_llist_zend_extension = NULL;
+
+static zend_bool xc_test = 0;
+static zend_bool xc_readonly_protection = 0;
+
+zend_bool xc_have_op_array_ctor = 0;
+
+static zend_bool xc_module_gotup = 0;
+static zend_bool xc_zend_extension_gotup = 0;
+static zend_bool xc_zend_extension_faked = 0;
+#if !COMPILE_DL_XCACHE
+#	define zend_extension_entry xcache_zend_extension_entry
+#endif
+ZEND_DLEXPORT zend_extension zend_extension_entry;
+ZEND_DECLARE_MODULE_GLOBALS(xcache);
+
+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_cache_t *cache, xc_entry_data_php_t *php) /* {{{ */
+{
+	xc_entry_data_php_t **head = &(cache->phps[php->hvalue]);
+	php->next = *head;
+	*head = php;
+	cache->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, php TSRMLS_CC);
+	if (stored_php) {
+		xc_php_add_unlocked(cache, stored_php);
+		return stored_php;
+	}
+	else {
+		cache->ooms ++;
+		return NULL;
+	}
+}
+/* }}} */
+static xc_entry_data_php_t *xc_php_find_unlocked(xc_cache_t *cache, xc_entry_data_php_t *php TSRMLS_DC) /* {{{ */
+{
+	xc_entry_data_php_t *p;
+	for (p = cache->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->mem->handlers->free(cache->mem, (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->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(IS_ABSOLUTE_PATH(entry1->name.str.val, entry1->name.str.len));
+			assert(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(UChar)) == 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 inline int xc_entry_has_prefix_unlocked(xc_entry_type_t type, xc_entry_t *entry, zval *prefix) /* {{{ */
+{
+	/* this function isn't required but can be in unlocked */
+
+#ifdef IS_UNICODE
+	if (entry->name_type != prefix->type) {
+		return 0;
+	}
+
+	if (entry->name_type == IS_UNICODE) {
+		if (entry->name.ustr.len < Z_USTRLEN_P(prefix)) {
+			return 0;
+		}
+		return memcmp(entry->name.ustr.val, Z_USTRVAL_P(prefix), Z_USTRLEN_P(prefix) * sizeof(UChar)) == 0;
+	}
+#endif
+	if (prefix->type != IS_STRING) {
+		return 0;
+	}
+
+	if (entry->name.str.len < Z_STRLEN_P(prefix)) {
+		return 0;
+	}
+
+	return memcmp(entry->name.str.val, Z_STRVAL_P(prefix), Z_STRLEN_P(prefix)) == 0;
+}
+/* }}} */
+static void xc_entry_add_unlocked(xc_cache_t *cache, xc_hash_value_t entryslotid, xc_entry_t *entry) /* {{{ */
+{
+	xc_entry_t **head = &(cache->entries[entryslotid]);
+	entry->next = *head;
+	*head = entry;
+	cache->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, (xc_entry_php_t *) entry TSRMLS_CC)
+		: (xc_entry_t *) xc_processor_store_xc_entry_var_t(cache, (xc_entry_var_t *) entry TSRMLS_CC);
+	if (stored_entry) {
+		xc_entry_add_unlocked(cache, entryslotid, stored_entry);
+		++cache->updates;
+		return stored_entry;
+	}
+	else {
+		cache->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->mem->handlers->free(cache->mem, (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->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->deletes;
+		cache->deletes = entry;
+		entry->dtime = XG(request_time);
+		cache->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->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->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 void xc_counters_inc(time_t *curtime, zend_uint *curslot, time_t period, zend_ulong *counters, zend_uint count TSRMLS_DC) /* {{{ */
+{
+	time_t n = XG(request_time) / period;
+	if (*curtime != n) {
+		zend_uint target_slot = n % count;
+		if (n - *curtime > period) {
+			memset(counters, 0, sizeof(counters[0]) * count);
+		}
+		else {
+			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 void xc_cache_hit_unlocked(xc_cache_t *cache TSRMLS_DC) /* {{{ */
+{
+	cache->hits ++;
+
+	xc_counters_inc(&cache->hits_by_hour_cur_time
+			, &cache->hits_by_hour_cur_slot, 60 * 60
+			, cache->hits_by_hour
+			, sizeof(cache->hits_by_hour) / sizeof(cache->hits_by_hour[0])
+			TSRMLS_CC);
+
+	xc_counters_inc(&cache->hits_by_second_cur_time
+			, &cache->hits_by_second_cur_slot
+			, 1
+			, cache->hits_by_second
+			, sizeof(cache->hits_by_second) / sizeof(cache->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->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->last_gc_expires, gc_interval);
+	if (XG(request_time) >= cache->last_gc_expires + (time_t) gc_interval) {
+		ENTER_LOCK(cache) {
+			if (XG(request_time) >= cache->last_gc_expires + (time_t) gc_interval) {
+				cache->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) /* {{{ */
+{
+	int 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->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->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->deletes && XG(request_time) - cache->last_gc_deletes > xc_deletes_gc_interval) {
+		ENTER_LOCK(cache) {
+			if (cache->deletes && XG(request_time) - cache->last_gc_deletes > xc_deletes_gc_interval) {
+				cache->last_gc_deletes = XG(request_time);
+				xc_gc_delete_unlocked(cache TSRMLS_CC);
+			}
+		} LEAVE_LOCK(cache);
+	}
+}
+/* }}} */
+static void xc_gc_deletes(TSRMLS_D) /* {{{ */
+{
+	int 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;
+	int i;
+	const xc_block_t *b;
+#ifndef NDEBUG
+	xc_memsize_t avail = 0;
+#endif
+	xc_mem_t *mem = cache->mem;
+	const xc_mem_handlers_t *handlers = mem->handlers;
+	zend_ulong interval;
+	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"), cache->compiling);
+	add_assoc_long_ex(return_value, ZEND_STRS("updates"),   cache->updates);
+	add_assoc_long_ex(return_value, ZEND_STRS("misses"),    cache->updates); /* deprecated */
+	add_assoc_long_ex(return_value, ZEND_STRS("hits"),      cache->hits);
+	add_assoc_long_ex(return_value, ZEND_STRS("clogs"),     cache->clogs);
+	add_assoc_long_ex(return_value, ZEND_STRS("ooms"),      cache->ooms);
+	add_assoc_long_ex(return_value, ZEND_STRS("errors"),    cache->errors);
+
+	add_assoc_long_ex(return_value, ZEND_STRS("cached"),    cache->entries_count);
+	add_assoc_long_ex(return_value, ZEND_STRS("deleted"),   cache->deletes_count);
+	if (interval) {
+		time_t gc = (cache->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(cache->hits_by_hour) / sizeof(cache->hits_by_hour[0]); i ++) {
+		add_next_index_long(hits, (long) cache->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(cache->hits_by_second) / sizeof(cache->hits_by_second[0]); i ++) {
+		add_next_index_long(hits, (long) cache->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"),  handlers->size(mem));
+	add_assoc_long_ex(return_value, ZEND_STRS("avail"), handlers->avail(mem));
+	add_assoc_bool_ex(return_value, ZEND_STRS("can_readonly"), xc_readonly_protection);
+
+	for (b = handlers->freeblock_first(mem); b; b = handlers->freeblock_next(b)) {
+		zval *bi;
+
+		MAKE_STD_ZVAL(bi);
+		array_init(bi);
+
+		add_assoc_long_ex(bi, ZEND_STRS("size"),   handlers->block_size(b));
+		add_assoc_long_ex(bi, ZEND_STRS("offset"), handlers->block_offset(mem, b));
+		add_next_index_zval(blocks, bi);
+#ifndef NDEBUG
+		avail += handlers->block_size(b);
+#endif
+	}
+	add_assoc_zval_ex(return_value, ZEND_STRS("free_blocks"), blocks);
+#ifndef NDEBUG
+	assert(avail == handlers->avail(mem));
+#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->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->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, int cachecount TSRMLS_DC) /* {{{ */
+{
+	int 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);
+					--entry_php->refcount;
+					assert(entry_php->refcount >= 0);
+				}
+			} 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) zend_bool name(const char *filepath, size_t filepath_len, void *data TSRMLS_DC)
+typedef XC_RESOLVE_PATH_CHECKER((*xc_resolve_path_checker_func_t));
+static zend_bool 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) {
+
+		if (checker_func(path_buffer, path_buffer_len, data TSRMLS_CC)) {
+			ret = 1;
+		}
+		else {
+			ret = FAILURE;
+		}
+		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) {
+			if (checker_func(path_buffer, path_buffer_len, data TSRMLS_CC)) {
+				ret = 1;
+				goto finish;
+			}
+		}
+	}
+
+	/* fall back to current directory */
+	if (zend_is_executing(TSRMLS_C)) {
+		const char *executed_filename = zend_get_executed_filename(TSRMLS_C);
+		if (executed_filename && executed_filename[0] && executed_filename[0] != '[') {
+			size_t filename_len = strlen(filepath);
+			size_t dirname_len;
+
+			for (dirname_len = strlen(executed_filename) - 1; dirname_len > 0; --dirname_len) {
+				if (IS_SLASH(executed_filename[dirname_len])) {
+					if (dirname_len + filename_len < MAXPATHLEN - 1) {
+						++dirname_len; /* include tailing slash */
+						memcpy(path_buffer, executed_filename, dirname_len);
+						memcpy(path_buffer + dirname_len, filepath, filename_len);
+						path_buffer_len = dirname_len + filename_len;
+						path_buffer[path_buffer_len] = '\0';
+						if (checker_func(path_buffer, path_buffer_len, data TSRMLS_CC)) {
+							ret = 1;
+							goto finish;
+						}
+					}
+					break;
+				}
+			}
+		}
+	}
+
+	ret = 0;
+
+finish:
+	my_free_alloca(paths, use_heap);
+
+	return ret;
+}
+/* }}} */
+#ifndef ZEND_ENGINE_2_3
+static XC_RESOLVE_PATH_CHECKER(xc_stat_file) /* {{{ */
+{
+	return VCWD_STAT(filepath, (struct stat *) data) == 0 ? 1 : 0;
+}
+/* }}} */
+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_stat_file, (void *) pbuf TSRMLS_CC)
+		? SUCCESS
+		: FAILURE;
+}
+/* }}} */
+#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_entry_resolve_path_data_t { /* {{{ */
+	xc_compiler_t *compiler;
+	xc_entry_php_t **stored_entry;
+} xc_entry_resolve_path_data_t;
+/* }}} */
+static XC_RESOLVE_PATH_CHECKER(xc_entry_resolve_path_func_unlocked) /* {{{ */
+{
+	xc_entry_resolve_path_data_t *entry_resolve_path_data = (xc_entry_resolve_path_data_t *) data;
+	xc_compiler_t *compiler = entry_resolve_path_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_resolve_path_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_resolve_path_data->stored_entry ? 1 : 0;
+}
+/* }}} */
+static int xc_entry_resolve_path_unlocked(xc_compiler_t *compiler, const char *filepath, xc_entry_php_t **stored_entry TSRMLS_DC) /* {{{ */
+{
+	char path_buffer[MAXPATHLEN];
+	xc_entry_resolve_path_data_t entry_resolve_path_data;
+	entry_resolve_path_data.compiler = compiler;
+	entry_resolve_path_data.stored_entry = stored_entry;
+
+	return xc_resolve_path(filepath, path_buffer, xc_entry_resolve_path_func_unlocked, (void *) &entry_resolve_path_data TSRMLS_CC)
+		? SUCCESS
+		: FAILURE;
+}
+/* }}} */
+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 (IS_ABSOLUTE_PATH(compiler->filename, strlen(compiler->filename))) {
+		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;
+	}
+
+	/* 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 || VCWD_STAT(compiler->opened_path, statbuf) == 0) {
+				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 (VCWD_STAT(compiler->opened_path, &buf) != 0) {
+				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 = filename_end - 1;
+
+			/* scan till out of basename part */
+			while (basename >= compiler->filename && !IS_SLASH(*basename)) {
+				--basename;
+			}
+			/* get back to basename */
+			++basename;
+
+			basename_hash_value = HASH_STR_L(basename, filename_end - basename);
+		}
+
+		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
+				? 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 linteralindex;
+
+	for (linteralindex = 0; linteralindex < op_array_info->literalinfo_cnt; ++linteralindex) {
+		int index = op_array_info->literalinfos[linteralindex].index;
+		int literalinfo = op_array_info->literalinfos[linteralindex].info;
+		zend_literal *literal = &op_array->literals[index];
+		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 oplineno = op_array_info->oplineinfos[oplinenum].index;
+		int oplineinfo = op_array_info->oplineinfos[oplinenum].info;
+		zend_op *opline = &op_array->opcodes[oplineno];
+		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)) {
+		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;
+}
+/* }}} */
+static zend_op_array *xc_check_initial_compile_file(zend_file_handle *h, int type TSRMLS_DC) /* {{{ */
+{
+	XG(initial_compile_file_called) = 1;
+	return origin_compile_file(h, type TSRMLS_CC);
+}
+/* }}} */
+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->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->compiling = 0;
+	if (catched) {
+		cache->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;
+
+	/* stale clogs precheck */
+	if (XG(request_time) - cache->compiling < 30) {
+		cache->clogs ++;
+		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_entry_resolve_path_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_cache_hit_unlocked(cache 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, &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->compiling < 30) {
+			TRACE("%s", "miss php, but compiling");
+			cache->clogs ++;
+			gaveup = 1;
+			break;
+		}
+
+		TRACE("%s", "miss php, going to compile");
+		cache->compiling = XG(request_time);
+	} LEAVE_LOCK_EX(cache);
+
+	if (catched) {
+		cache->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
+	 || strstr(h->filename, "://") != NULL
+#ifdef ZEND_ENGINE_2_3
+	 /* supported by php_resolve_path */
+	 || (!XG(stat) && strstr(PG(include_path), "://") != NULL)
+#else
+	 || strstr(PG(include_path), "://") != NULL
+#endif
+	 ) {
+		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);
+	}
+}
+/* }}} */
+
+/* module helper function */
+static int xc_init_constant(int module_number TSRMLS_DC) /* {{{ */
+{
+	typedef struct {
+		const char *prefix;
+		zend_uchar (*getsize)();
+		const char *(*get)(zend_uchar i);
+	} xc_meminfo_t;
+	xc_meminfo_t nameinfos[] = {
+		{ "",        xc_get_op_type_count,   xc_get_op_type   },
+		{ "",        xc_get_data_type_count, xc_get_data_type },
+		{ "",        xc_get_opcode_count,    xc_get_opcode    },
+		{ "OPSPEC_", xc_get_op_spec_count,   xc_get_op_spec   },
+		{ NULL, NULL, NULL }
+	};
+	xc_meminfo_t* p;
+	zend_uchar i, count;
+	char const_name[96];
+	int const_name_len;
+	int undefdone = 0;
+
+	for (p = nameinfos; p->getsize; p ++) {
+		count = p->getsize();
+		for (i = 0; i < count; i ++) {
+			const char *name = p->get(i);
+			if (!name) continue;
+			if (strcmp(name, "UNDEF") == 0) {
+				if (undefdone) continue;
+				undefdone = 1;
+			}
+			const_name_len = snprintf(const_name, sizeof(const_name), "XC_%s%s", p->prefix, name);
+			zend_register_long_constant(const_name, const_name_len+1, i, CONST_CS | CONST_PERSISTENT, module_number TSRMLS_CC);
+		}
+	}
+
+	zend_register_long_constant(ZEND_STRS("XC_SIZEOF_TEMP_VARIABLE"), sizeof(temp_variable), CONST_CS | CONST_PERSISTENT, module_number TSRMLS_CC);
+	zend_register_long_constant(ZEND_STRS("XC_TYPE_PHP"), XC_TYPE_PHP, CONST_CS | CONST_PERSISTENT, module_number TSRMLS_CC);
+	zend_register_long_constant(ZEND_STRS("XC_TYPE_VAR"), XC_TYPE_VAR, CONST_CS | CONST_PERSISTENT, module_number TSRMLS_CC);
+	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;
+}
+/* }}} */
+static xc_shm_t *xc_cache_destroy(xc_cache_t **caches, xc_hash_t *hcache) /* {{{ */
+{
+	size_t i;
+	xc_cache_t *cache;
+	xc_shm_t *shm;
+
+	if (!caches) {
+		return NULL;
+	}
+	shm = NULL;
+	for (i = 0; i < hcache->size; i ++) {
+		cache = caches[i];
+		if (cache) {
+			if (cache->lck) {
+				xc_lock_destroy(cache->lck);
+			}
+			/* do NOT free
+			if (cache->entries) {
+				cache->mem->handlers->free(cache->mem, cache->entries);
+			}
+			cache->mem->handlers->free(cache->mem, cache);
+			*/
+			shm = cache->shm;
+			shm->handlers->memdestroy(cache->mem);
+		}
+	}
+	free(caches);
+	return shm;
+}
+/* }}} */
+static xc_cache_t **xc_cache_init(xc_shm_t *shm, xc_hash_t *hcache, xc_hash_t *hentry, xc_hash_t *hphp, xc_shmsize_t shmsize) /* {{{ */
+{
+	xc_cache_t **caches = NULL, *cache;
+	xc_mem_t *mem;
+	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 ++) {
+		CHECK(mem            = shm->handlers->meminit(shm, memsize), "Failed init memory allocator");
+		CHECK(cache          = mem->handlers->calloc(mem, 1, sizeof(xc_cache_t)), "cache OOM");
+		CHECK(cache->entries = mem->handlers->calloc(mem, hentry->size, sizeof(xc_entry_t*)), "entries OOM");
+		if (hphp) {
+			CHECK(cache->phps= mem->handlers->calloc(mem, 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->mem     = mem;
+		cache->cacheid = i;
+		cache->last_gc_deletes = now;
+		cache->last_gc_expires = now;
+		caches[i] = cache;
+	}
+	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 = old_compile_file;
+		old_compile_file = NULL;
+	}
+
+	if (origin_compile_file) {
+		zend_compile_file = origin_compile_file;
+		origin_compile_file = NULL;
+	}
+
+	if (xc_php_caches) {
+		shm = xc_cache_destroy(xc_php_caches, &xc_php_hcache);
+		xc_php_caches = NULL;
+	}
+
+	if (xc_var_caches) {
+		shm = xc_cache_destroy(xc_var_caches, &xc_var_hcache);
+		xc_var_caches = NULL;
+	}
+
+	if (shm) {
+		xc_shm_destroy(shm);
+	}
+
+	xc_initized = 0;
+}
+/* }}} */
+static int xc_init(int module_number TSRMLS_DC) /* {{{ */
+{
+	xc_shm_t *shm;
+	xc_shmsize_t shmsize = ALIGN(xc_php_size) + ALIGN(xc_var_size);
+
+	xc_php_caches = xc_var_caches = NULL;
+	shm = 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) {
+			old_compile_file = zend_compile_file;
+			zend_compile_file = xc_compile_file;
+
+			CHECK(xc_php_caches = xc_cache_init(shm, &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_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);
+	}
+	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) = calloc(xc_php_hcache.size, sizeof(xc_stack_t));
+		for (i = 0; i < xc_php_hcache.size; i ++) {
+			xc_stack_init(&XG(php_holds[i]));
+		}
+	}
+
+	if (xc_var_caches && !XG(var_holds)) {
+		XG(var_holds) = calloc(xc_var_hcache.size, sizeof(xc_stack_t));
+		for (i = 0; i < xc_var_hcache.size; i ++) {
+			xc_stack_init(&XG(var_holds[i]));
+		}
+	}
+
+#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
+
+#ifdef HAVE_XCACHE_COVERAGER
+	xc_coverager_request_init(TSRMLS_C);
+#endif
+}
+/* }}} */
+static void xc_request_shutdown(TSRMLS_D) /* {{{ */
+{
+	xc_entry_unholds(TSRMLS_C);
+#ifdef ZEND_ENGINE_2
+	zend_llist_destroy(&XG(gc_op_arrays));
+#endif
+	xc_gc_expires_php(TSRMLS_C);
+	xc_gc_expires_var(TSRMLS_C);
+	xc_gc_deletes(TSRMLS_C);
+#ifdef HAVE_XCACHE_COVERAGER
+	xc_coverager_request_shutdown(TSRMLS_C);
+#endif
+}
+/* }}} */
+/* {{{ PHP_GINIT_FUNCTION(xcache) */
+static
+#ifdef PHP_GINIT_FUNCTION
+PHP_GINIT_FUNCTION(xcache)
+#else
+void xc_init_globals(zend_xcache_globals* xcache_globals TSRMLS_DC)
+#endif
+{
+	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 < xc_php_hcache.size; i ++) {
+			xc_stack_destroy(&xcache_globals->php_holds[i]);
+		}
+		free(xcache_globals->php_holds);
+		xcache_globals->php_holds = NULL;
+	}
+
+	if (xcache_globals->var_holds != NULL) {
+		for (i = 0; i < xc_var_hcache.size; i ++) {
+			xc_stack_destroy(&xcache_globals->var_holds[i]);
+		}
+		free(xcache_globals->var_holds);
+		xcache_globals->var_holds = NULL;
+	}
+
+	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);
+	}
+}
+/* }}} */
+
+/* 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 (!XG(auth_enabled)) {
+		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 = HASH_OF((*server));
+
+	if (zend_hash_find(ht, "PHP_AUTH_USER", sizeof("PHP_AUTH_USER"), (void **) &user) == FAILURE) {
+	 	user = NULL;
+	}
+	else if (Z_TYPE_PP(user) != IS_STRING) {
+		user = NULL;
+	}
+
+	if (zend_hash_find(ht, "PHP_AUTH_PW", sizeof("PHP_AUTH_PW"), (void **) &pass) == FAILURE) {
+	 	pass = NULL;
+	}
+	else if (Z_TYPE_PP(pass) != IS_STRING) {
+		pass = NULL;
+	}
+
+	if (user != NULL && pass != NULL && strcmp(admin_user, Z_STRVAL_PP(user)) == 0) {
+		PHP_MD5_CTX context;
+		char md5str[33];
+		unsigned char digest[16];
+
+		PHP_MD5Init(&context);
+		PHP_MD5Update(&context, (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;
+}
+/* }}} */
+/* {{{ xcache_admin_operate */
+typedef enum { XC_OP_COUNT, XC_OP_INFO, XC_OP_LIST, XC_OP_CLEAR } xcache_op_type;
+static void xcache_admin_operate(xcache_op_type optype, INTERNAL_FUNCTION_PARAMETERS)
+{
+	long type;
+	int size;
+	xc_cache_t **caches, *cache;
+	long id = 0;
+
+	xcache_admin_auth_check(TSRMLS_C);
+
+	if (!xc_initized) {
+		RETURN_NULL();
+	}
+
+	if (optype == XC_OP_COUNT) {
+		if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &type) == FAILURE) {
+			return;
+		}
+	}
+	else if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ll", &type, &id) == FAILURE) {
+		return;
+	}
+
+	switch (type) {
+		case XC_TYPE_PHP:
+			size = xc_php_hcache.size;
+			caches = xc_php_caches;
+			break;
+
+		case XC_TYPE_VAR:
+			size = xc_var_hcache.size;
+			caches = xc_var_caches;
+			break;
+
+		default:
+			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown type %ld", type);
+			RETURN_FALSE;
+	}
+
+	switch (optype) {
+		case XC_OP_COUNT:
+			RETURN_LONG(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:
+			{
+				xc_entry_t *e, *next;
+				int entryslotid, c;
+
+				if (!caches || id < 0 || id >= size) {
+					php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cache not exists");
+					RETURN_FALSE;
+				}
+
+				cache = caches[id];
+				ENTER_LOCK(cache) {
+					for (entryslotid = 0, c = cache->hentry->size; entryslotid < c; entryslotid ++) {
+						for (e = cache->entries[entryslotid]; e; e = next) {
+							next = e->next;
+							xc_entry_remove_unlocked(type, cache, entryslotid, e TSRMLS_CC);
+						}
+						cache->entries[entryslotid] = NULL;
+					}
+				} LEAVE_LOCK(cache);
+				xc_gc_deletes(TSRMLS_C);
+			}
+			break;
+
+		default:
+			assert(0);
+	}
+}
+/* }}} */
+/* {{{ proto int xcache_count(int type)
+   Return count of cache on specified cache type */
+PHP_FUNCTION(xcache_count)
+{
+	xcache_admin_operate(XC_OP_COUNT, INTERNAL_FUNCTION_PARAM_PASSTHRU);
+}
+/* }}} */
+/* {{{ proto array xcache_info(int type, int id)
+   Get cache info by id on specified cache type */
+PHP_FUNCTION(xcache_info)
+{
+	xcache_admin_operate(XC_OP_INFO, INTERNAL_FUNCTION_PARAM_PASSTHRU);
+}
+/* }}} */
+/* {{{ proto array xcache_list(int type, int id)
+   Get cache entries list by id on specified cache type */
+PHP_FUNCTION(xcache_list)
+{
+	xcache_admin_operate(XC_OP_LIST, INTERNAL_FUNCTION_PARAM_PASSTHRU);
+}
+/* }}} */
+/* {{{ proto array xcache_clear_cache(int type, int id)
+   Clear cache by id on specified cache type */
+PHP_FUNCTION(xcache_clear_cache)
+{
+	xcache_admin_operate(XC_OP_CLEAR, INTERNAL_FUNCTION_PARAM_PASSTHRU);
+}
+/* }}} */
+
+#define VAR_DISABLED_WARNING() 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, zval *name TSRMLS_DC) /* {{{ */
+{
+	xc_hash_value_t hv;
+
+	switch (name->type) {
+#ifdef IS_UNICODE
+		case IS_UNICODE:
+		case IS_STRING:
+#endif
+		default:
+#ifdef IS_UNICODE
+			convert_to_unicode(name);
+#else
+			convert_to_string(name);
+#endif
+	}
+
+#ifdef IS_UNICODE
+	entry_var->name_type = name->type;
+#endif
+	entry_var->entry.name = name->value;
+
+	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_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;
+
+	if (!xc_var_caches) {
+		VAR_DISABLED_WARNING();
+		RETURN_NULL();
+	}
+
+	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &name) == FAILURE) {
+		return;
+	}
+	xc_entry_var_init_key(&entry_var, &entry_hash, name TSRMLS_CC);
+	cache = xc_var_caches[entry_hash.cacheid];
+
+	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_cache_hit_unlocked(cache TSRMLS_CC);
+		}
+		else {
+			RETVAL_NULL();
+		}
+	} LEAVE_LOCK(cache);
+}
+/* }}} */
+/* {{{ 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;
+
+	if (!xc_var_caches) {
+		VAR_DISABLED_WARNING();
+		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;
+	}
+
+	/* max ttl */
+	if (xc_var_maxttl && (!entry_var.entry.ttl || entry_var.entry.ttl > xc_var_maxttl)) {
+		entry_var.entry.ttl = xc_var_maxttl;
+	}
+
+	xc_entry_var_init_key(&entry_var, &entry_hash, name TSRMLS_CC);
+	cache = xc_var_caches[entry_hash.cacheid];
+
+	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);
+}
+/* }}} */
+/* {{{ 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;
+
+	if (!xc_var_caches) {
+		VAR_DISABLED_WARNING();
+		RETURN_FALSE;
+	}
+
+	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &name) == FAILURE) {
+		return;
+	}
+	xc_entry_var_init_key(&entry_var, &entry_hash, name TSRMLS_CC);
+	cache = xc_var_caches[entry_hash.cacheid];
+
+	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_cache_hit_unlocked(cache TSRMLS_CC);
+			RETVAL_TRUE;
+			/* return */
+		}
+		else {
+			RETVAL_FALSE;
+		}
+
+	} LEAVE_LOCK(cache);
+}
+/* }}} */
+/* {{{ 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;
+
+	if (!xc_var_caches) {
+		VAR_DISABLED_WARNING();
+		RETURN_FALSE;
+	}
+
+	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &name) == FAILURE) {
+		return;
+	}
+	xc_entry_var_init_key(&entry_var, &entry_hash, name TSRMLS_CC);
+	cache = xc_var_caches[entry_hash.cacheid];
+
+	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);
+}
+/* }}} */
+/* {{{ 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_DISABLED_WARNING();
+		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];
+		ENTER_LOCK(cache) {
+			int entryslotid, jend;
+			for (entryslotid = 0, jend = cache->hentry->size; entryslotid < jend; entryslotid ++) {
+				xc_entry_t *entry, *next;
+				for (entry = cache->entries[entryslotid]; entry; entry = next) {
+					next = entry->next;
+					if (xc_entry_has_prefix_unlocked(XC_TYPE_VAR, entry, prefix)) {
+						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;
+
+	if (!xc_var_caches) {
+		VAR_DISABLED_WARNING();
+		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;
+	}
+
+	xc_entry_var_init_key(&entry_var, &entry_hash, name TSRMLS_CC);
+	cache = xc_var_caches[entry_hash.cacheid];
+
+	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->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);
+}
+/* }}} */
+/* {{{ proto int xcache_inc(string name [, int value [, int ttl]])
+   Increase an int counter in cache by specified name, create it if not exists */
+PHP_FUNCTION(xcache_inc)
+{
+	xc_var_inc_dec(1, INTERNAL_FUNCTION_PARAM_PASSTHRU);
+}
+/* }}} */
+/* {{{ proto int xcache_dec(string name [, int value [, int ttl]])
+   Decrease an int counter in cache by specified name, create it if not exists */
+PHP_FUNCTION(xcache_dec)
+{
+	xc_var_inc_dec(-1, INTERNAL_FUNCTION_PARAM_PASSTHRU);
+}
+/* }}} */
+/* {{{ proto 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 */
+ZEND_BEGIN_ARG_INFO_EX(arginfo_xcache_get_isref, 0, 0, 1)
+	ZEND_ARG_INFO(1, variable)
+ZEND_END_ARG_INFO()
+
+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
+/* }}} */
+#ifdef HAVE_XCACHE_DISASSEMBLER
+/* {{{ proto array  xcache_dasm_file(string filename)
+   Disassemble file into opcode array by filename */
+PHP_FUNCTION(xcache_dasm_file)
+{
+	char *filename;
+	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);
+}
+/* }}} */
+#endif
+/* {{{ proto string xcache_encode(string filename)
+   Encode php file into XCache opcode encoded format */
+#ifdef HAVE_XCACHE_ENCODER
+PHP_FUNCTION(xcache_encode)
+{
+}
+#endif
+/* }}} */
+/* {{{ proto bool xcache_decode_file(string filename)
+   Decode(load) opcode from XCache encoded format file */
+#ifdef HAVE_XCACHE_DECODER
+PHP_FUNCTION(xcache_decode_file)
+{
+}
+#endif
+/* }}} */
+/* {{{ proto bool xcache_decode_string(string data)
+   Decode(load) opcode from XCache encoded format data */
+#ifdef HAVE_XCACHE_DECODER
+PHP_FUNCTION(xcache_decode_string)
+{
+}
+#endif
+/* }}} */
+/* {{{ xc_call_getter */
+typedef const char *(xc_name_getter_t)(zend_uchar type);
+static void xc_call_getter(xc_name_getter_t getter, int count, INTERNAL_FUNCTION_PARAMETERS)
+{
+	long spec;
+	const char *name;
+
+	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &spec) == FAILURE) {
+		return;
+	}
+	if (spec >= 0 && spec < count) {
+		name = getter((zend_uchar) spec);
+		if (name) {
+			/* RETURN_STRING */
+			int len = strlen(name);
+			return_value->value.str.len = len;
+			return_value->value.str.val = estrndup(name, len);
+			return_value->type = IS_STRING; 
+			return;
+		}
+	}
+	RETURN_NULL();
+}
+/* }}} */
+/* {{{ proto string xcache_get_op_type(int op_type) */
+PHP_FUNCTION(xcache_get_op_type)
+{
+	xc_call_getter(xc_get_op_type, xc_get_op_type_count(), INTERNAL_FUNCTION_PARAM_PASSTHRU);
+}
+/* }}} */
+/* {{{ proto string xcache_get_data_type(int type) */
+PHP_FUNCTION(xcache_get_data_type)
+{
+	xc_call_getter(xc_get_data_type, xc_get_data_type_count(), INTERNAL_FUNCTION_PARAM_PASSTHRU);
+}
+/* }}} */
+/* {{{ proto string xcache_get_opcode(int opcode) */
+PHP_FUNCTION(xcache_get_opcode)
+{
+	xc_call_getter(xc_get_opcode, xc_get_opcode_count(), INTERNAL_FUNCTION_PARAM_PASSTHRU);
+}
+/* }}} */
+/* {{{ proto string xcache_get_op_spec(int op_type) */
+PHP_FUNCTION(xcache_get_op_spec)
+{
+	xc_call_getter(xc_get_op_spec, xc_get_op_spec_count(), INTERNAL_FUNCTION_PARAM_PASSTHRU);
+}
+/* }}} */
+#ifdef HAVE_XCACHE_OPCODE_SPEC_DEF
+/* {{{ proto string xcache_get_opcode_spec(int opcode) */
+PHP_FUNCTION(xcache_get_opcode_spec)
+{
+	long spec;
+	const xc_opcode_spec_t *opspec;
+
+	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &spec) == FAILURE) {
+		return;
+	}
+	if ((zend_uchar) spec <= xc_get_opcode_spec_count()) {
+		opspec = xc_get_opcode_spec((zend_uchar) spec);
+		if (opspec) {
+			array_init(return_value);
+			add_assoc_long_ex(return_value, ZEND_STRS("ext"), opspec->ext);
+			add_assoc_long_ex(return_value, ZEND_STRS("op1"), opspec->op1);
+			add_assoc_long_ex(return_value, ZEND_STRS("op2"), opspec->op2);
+			add_assoc_long_ex(return_value, ZEND_STRS("res"), opspec->res);
+			return;
+		}
+	}
+	RETURN_NULL();
+}
+/* }}} */
+#endif
+/* {{{ proto mixed xcache_get_special_value(zval value)
+   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_count,             NULL)
+	PHP_FE(xcache_info,              NULL)
+	PHP_FE(xcache_list,              NULL)
+	PHP_FE(xcache_clear_cache,       NULL)
+	PHP_FE(xcache_coredump,          NULL)
+#ifdef HAVE_XCACHE_ASSEMBLER
+	PHP_FE(xcache_asm,               NULL)
+#endif
+#ifdef HAVE_XCACHE_DISASSEMBLER
+	PHP_FE(xcache_dasm_file,         NULL)
+	PHP_FE(xcache_dasm_string,       NULL)
+#endif
+#ifdef HAVE_XCACHE_ENCODER
+	PHP_FE(xcache_encode,            NULL)
+#endif
+#ifdef HAVE_XCACHE_DECODER
+	PHP_FE(xcache_decode_file,       NULL)
+	PHP_FE(xcache_decode_string,     NULL)
+#endif
+#ifdef HAVE_XCACHE_COVERAGER
+	PHP_FE(xcache_coverager_decode,  NULL)
+	PHP_FE(xcache_coverager_start,   NULL)
+	PHP_FE(xcache_coverager_stop,    NULL)
+	PHP_FE(xcache_coverager_get,     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)
+#ifdef HAVE_XCACHE_OPCODE_SPEC_DEF
+	PHP_FE(xcache_get_opcode_spec,   NULL)
+#endif
+	PHP_FE(xcache_is_autoglobal,     NULL)
+	PHP_FE(xcache_inc,               NULL)
+	PHP_FE(xcache_dec,               NULL)
+	PHP_FE(xcache_get,               NULL)
+	PHP_FE(xcache_set,               NULL)
+	PHP_FE(xcache_isset,             NULL)
+	PHP_FE(xcache_unset,             NULL)
+	PHP_FE(xcache_unset_by_prefix,   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
+	{NULL, NULL,                     NULL}
+};
+/* }}} */
+
+#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;
+
+	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);
+			return 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());
+	}
+
+	return EXCEPTION_CONTINUE_SEARCH;
+}
+/* }}} */
+
+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 "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 "foreachcoresig.h"
+#undef FOREACH_SIG
+}
+/* }}} */
+static void xcache_init_crash_handler() /* {{{ */
+{
+#define FOREACH_SIG(sig) \
+	old_##sig##_handler = signal(sig, xcache_signal_handler)
+#include "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 */
+		}
+	}
+	raise(sig);
+}
+/* }}} */
+#endif
+
+/* {{{ PHP_INI */
+
+static PHP_INI_MH(xc_OnUpdateDummy)
+{
+	return SUCCESS;
+}
+
+static PHP_INI_MH(xc_OnUpdateULong)
+{
+	zend_ulong *p = (zend_ulong *) mh_arg1;
+
+	*p = (zend_ulong) atoi(new_value);
+	return SUCCESS;
+}
+
+static PHP_INI_MH(xc_OnUpdateBool)
+{
+	zend_bool *p = (zend_bool *)mh_arg1;
+
+	if (strncasecmp("on", new_value, sizeof("on"))) {
+		*p = (zend_bool) atoi(new_value);
+	}
+	else {
+		*p = (zend_bool) 1;
+	}
+	return SUCCESS;
+}
+
+static PHP_INI_MH(xc_OnUpdateString)
+{
+	char **p = (char**)mh_arg1;
+	if (*p) {
+		pefree(*p, 1);
+	}
+	*p = pemalloc(strlen(new_value) + 1, 1);
+	strcpy(*p, new_value);
+	return SUCCESS;
+}
+
+#ifndef ZEND_ENGINE_2
+#define OnUpdateLong OnUpdateInt
+#endif
+
+#ifdef ZEND_WIN32
+#	define DEFAULT_PATH "xcache"
+#else
+#	define DEFAULT_PATH "/dev/zero"
+#endif
+PHP_INI_BEGIN()
+	PHP_INI_ENTRY1     ("xcache.mmap_path",     DEFAULT_PATH, PHP_INI_SYSTEM, xc_OnUpdateString,   &xc_mmap_path)
+	PHP_INI_ENTRY1     ("xcache.coredump_directory",      "", PHP_INI_SYSTEM, xc_OnUpdateString,   &xc_coredump_dir)
+	PHP_INI_ENTRY1     ("xcache.test",                   "0", PHP_INI_SYSTEM, xc_OnUpdateBool,     &xc_test)
+	PHP_INI_ENTRY1     ("xcache.readonly_protection",    "0", PHP_INI_SYSTEM, xc_OnUpdateBool,     &xc_readonly_protection)
+	/* opcode cache */
+	PHP_INI_ENTRY1     ("xcache.size",                   "0", PHP_INI_SYSTEM, xc_OnUpdateDummy,    NULL)
+	PHP_INI_ENTRY1     ("xcache.count",                  "1", PHP_INI_SYSTEM, xc_OnUpdateDummy,    NULL)
+	PHP_INI_ENTRY1     ("xcache.slots",                 "8K", PHP_INI_SYSTEM, xc_OnUpdateDummy,    NULL)
+	PHP_INI_ENTRY1     ("xcache.shm_scheme",          "mmap", PHP_INI_SYSTEM, xc_OnUpdateString,   &xc_shm_scheme)
+	PHP_INI_ENTRY1     ("xcache.ttl",                    "0", PHP_INI_SYSTEM, xc_OnUpdateULong,    &xc_php_ttl)
+	PHP_INI_ENTRY1     ("xcache.gc_interval",            "0", PHP_INI_SYSTEM, xc_OnUpdateULong,    &xc_php_gc_interval)
+	/* var cache */
+	PHP_INI_ENTRY1     ("xcache.var_size",               "0", PHP_INI_SYSTEM, xc_OnUpdateDummy,    NULL)
+	PHP_INI_ENTRY1     ("xcache.var_count",              "1", PHP_INI_SYSTEM, xc_OnUpdateDummy,    NULL)
+	PHP_INI_ENTRY1     ("xcache.var_slots",             "8K", PHP_INI_SYSTEM, xc_OnUpdateDummy,    NULL)
+	PHP_INI_ENTRY1     ("xcache.var_maxttl",             "0", PHP_INI_SYSTEM, xc_OnUpdateULong,    &xc_var_maxttl)
+	PHP_INI_ENTRY1     ("xcache.var_gc_interval",      "120", PHP_INI_SYSTEM, xc_OnUpdateULong,    &xc_var_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)
+	STD_PHP_INI_BOOLEAN("xcache.admin.enable_auth",      "1", PHP_INI_SYSTEM, OnUpdateBool,        auth_enabled,      zend_xcache_globals, xcache_globals)
+	STD_PHP_INI_BOOLEAN("xcache.experimental",           "0", PHP_INI_ALL,    OnUpdateBool,        experimental,      zend_xcache_globals, xcache_globals)
+#ifdef HAVE_XCACHE_OPTIMIZER
+	STD_PHP_INI_BOOLEAN("xcache.optimizer",              "0", PHP_INI_ALL,    OnUpdateBool,        optimizer,         zend_xcache_globals, xcache_globals)
+#endif
+	STD_PHP_INI_ENTRY  ("xcache.var_ttl",                "0", PHP_INI_ALL,    OnUpdateLong,        var_ttl,           zend_xcache_globals, xcache_globals)
+#ifdef HAVE_XCACHE_COVERAGER
+	STD_PHP_INI_BOOLEAN("xcache.coverager"      ,        "0", PHP_INI_ALL,    OnUpdateBool,        coverager,         zend_xcache_globals, xcache_globals)
+	PHP_INI_ENTRY1     ("xcache.coveragedump_directory",  "", PHP_INI_SYSTEM, xc_OnUpdateDummy,    NULL)
+#endif
+PHP_INI_END()
+/* }}} */
+/* {{{ PHP_MINFO_FUNCTION(xcache) */
+static PHP_MINFO_FUNCTION(xcache)
+{
+	char buf[100];
+	char *ptr;
+	int left, len;
+	xc_shm_scheme_t *scheme;
+#ifdef HAVE_XCACHE_COVERAGER
+	char *covdumpdir;
+#endif
+
+	php_info_print_table_start();
+	php_info_print_table_header(2, "XCache Support", "enabled");
+	php_info_print_table_row(2, "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_row(2, "Readonly Protection", xc_readonly_protection ? "enabled" : "N/A");
+#ifdef ZEND_ENGINE_2_1
+	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) 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, %d split(s), with %d slots each", ptr, 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, %d split(s), with %d slots each", ptr, 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);
+
+#ifdef HAVE_XCACHE_COVERAGER
+	if (cfg_get_string("xcache.coveragedump_directory", &covdumpdir) != SUCCESS || !covdumpdir[0]) {
+		covdumpdir = NULL;
+	}
+	php_info_print_table_row(2, "Coverage Auto Dumper", XG(coverager) && covdumpdir ? "enabled" : "disabled");
+#endif
+	php_info_print_table_end();
+
+	DISPLAY_INI_ENTRIES();
+}
+/* }}} */
+/* {{{ extension startup */
+static void xc_zend_extension_register(zend_extension *new_extension, DL_HANDLE handle)
+{
+	zend_extension extension;
+
+	extension = *new_extension;
+	extension.handle = handle;
+
+	zend_extension_dispatch_message(ZEND_EXTMSG_NEW_EXTENSION, &extension);
+
+	zend_llist_prepend_element(&zend_extensions, &extension);
+	TRACE("%s", "registered");
+}
+
+static zend_llist_element *xc_llist_get_element_by_zend_extension(zend_llist *l, const char *extension_name)
+{
+	zend_llist_element *element;
+
+	for (element = zend_extensions.head; element; element = element->next) {
+		zend_extension *extension = (zend_extension *) element->data;
+
+		if (!strcmp(extension->name, extension_name)) {
+			return element;
+		}
+	}
+	return NULL;
+}
+
+static void xc_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;
+}
+
+static void xc_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;
+}
+
+static int xc_zend_extension_startup(zend_extension *extension)
+{
+	if (extension->startup) {
+		if (extension->startup(extension) != SUCCESS) {
+			return FAILURE;
+		}
+	}
+	return SUCCESS;
+}
+/* }}} */
+static int xc_ptr_compare_func(void *p1, void *p2) /* {{{ */
+{
+	return p1 == p2;
+}
+/* }}} */
+static int xc_zend_remove_extension(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;
+}
+/* }}} */
+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;
+}
+/* }}} */
+/* {{{ PHP_MINIT_FUNCTION(xcache) */
+static PHP_MINIT_FUNCTION(xcache)
+{
+	char *env;
+	zend_extension *ext;
+	zend_llist_position lpos;
+
+	xc_module_gotup = 1;
+	if (!xc_zend_extension_gotup) {
+		xc_zend_extension_register(&zend_extension_entry, 0);
+		xc_zend_extension_startup(&zend_extension_entry);
+		xc_zend_extension_faked = 1;
+	}
+
+	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;
+		}
+	}
+
+
+#ifndef PHP_GINIT
+	ZEND_INIT_MODULE_GLOBALS(xcache, xc_init_globals, xc_shutdown_globals);
+#endif
+	REGISTER_INI_ENTRIES();
+
+	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 ((env = getenv("XCACHE_TEST")) != NULL) {
+			xc_test = atoi(env);
+		}
+		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;
+	}
+
+	if (xc_coredump_dir && xc_coredump_dir[0]) {
+		xcache_init_crash_handler();
+	}
+
+	xc_init_constant(module_number TSRMLS_CC);
+	xc_shm_init_modules();
+
+	if ((xc_php_size || xc_var_size) && xc_mmap_path && xc_mmap_path[0]) {
+		if (xc_init(module_number TSRMLS_CC) != SUCCESS) {
+			zend_error(E_ERROR, "XCache: Cannot init");
+			goto err_init;
+		}
+		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
+	}
+
+	xc_util_init(module_number TSRMLS_CC);
+#ifdef HAVE_XCACHE_COVERAGER
+	xc_coverager_init(module_number TSRMLS_CC);
+#endif
+
+	return SUCCESS;
+
+err_init:
+	return FAILURE;
+}
+/* }}} */
+/* {{{ PHP_MSHUTDOWN_FUNCTION(xcache) */
+static PHP_MSHUTDOWN_FUNCTION(xcache)
+{
+#ifdef HAVE_XCACHE_COVERAGER
+	xc_coverager_destroy();
+#endif
+	xc_util_destroy();
+
+	if (xc_initized) {
+		xc_destroy();
+	}
+	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_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
+
+	if (xc_zend_extension_faked) {
+		zend_extension *ext = zend_get_extension(XCACHE_NAME);
+		if (ext) {
+			if (ext->shutdown) {
+				ext->shutdown(ext);
+			}
+			xc_zend_remove_extension(ext);
+		}
+	}
+	UNREGISTER_INI_ENTRIES();
+
+	xc_module_gotup = 0;
+	xc_zend_extension_gotup = 0;
+	xc_zend_extension_faked = 0;
+
+	return SUCCESS;
+}
+/* }}} */
+/* {{{ PHP_RINIT_FUNCTION(xcache) */
+static PHP_RINIT_FUNCTION(xcache)
+{
+	xc_request_init(TSRMLS_C);
+	return SUCCESS;
+}
+/* }}} */
+/* {{{ PHP_RSHUTDOWN_FUNCTION(xcache) */
+#ifndef ZEND_ENGINE_2
+static PHP_RSHUTDOWN_FUNCTION(xcache)
+#else
+static ZEND_MODULE_POST_ZEND_DEACTIVATE_D(xcache)
+#endif
+{
+#ifdef ZEND_ENGINE_2
+	TSRMLS_FETCH();
+#endif
+
+	xc_request_shutdown(TSRMLS_C);
+	return SUCCESS;
+}
+/* }}} */
+/* {{{ module dependencies */
+#if ZEND_MODULE_API_NO >= 20050922
+static zend_module_dep xcache_module_deps[] = {
+	ZEND_MOD_REQUIRED("standard")
+	ZEND_MOD_CONFLICTS("apc")
+	ZEND_MOD_CONFLICTS("eAccelerator")
+	ZEND_MOD_CONFLICTS("Turck MMCache")
+	{NULL, NULL, NULL}
+};
+#endif
+/* }}} */ 
+/* {{{ module definition structure */
+
+zend_module_entry xcache_module_entry = {
+#if ZEND_MODULE_API_NO >= 20050922
+	STANDARD_MODULE_HEADER_EX,
+	NULL,
+	xcache_module_deps,
+#else
+	STANDARD_MODULE_HEADER,
+#endif
+	XCACHE_NAME,
+	xcache_functions,
+	PHP_MINIT(xcache),
+	PHP_MSHUTDOWN(xcache),
+	PHP_RINIT(xcache),
+#ifndef ZEND_ENGINE_2
+	PHP_RSHUTDOWN(xcache),
+#else
+	NULL,
+#endif
+	PHP_MINFO(xcache),
+	XCACHE_VERSION,
+#ifdef PHP_GINIT
+	PHP_MODULE_GLOBALS(xcache),
+	PHP_GINIT(xcache),
+	PHP_GSHUTDOWN(xcache),
+#endif
+#ifdef ZEND_ENGINE_2
+	ZEND_MODULE_POST_ZEND_DEACTIVATE_N(xcache),
+#else
+	NULL,
+	NULL,
+#endif
+	STANDARD_MODULE_PROPERTIES_EX
+};
+
+#ifdef COMPILE_DL_XCACHE
+ZEND_GET_MODULE(xcache)
+#endif
+/* }}} */
+static startup_func_t xc_last_ext_startup;
+static int xc_zend_startup_last(zend_extension *extension) /* {{{ */
+{
+	/* restore */
+	extension->startup = xc_last_ext_startup;
+	if (extension->startup) {
+		if (extension->startup(extension) != SUCCESS) {
+			return FAILURE;
+		}
+	}
+	assert(xc_llist_zend_extension);
+	xc_llist_prepend(&zend_extensions, xc_llist_zend_extension);
+	if (!xc_module_gotup) {
+		return zend_startup_module(&xcache_module_entry);
+	}
+	return SUCCESS;
+}
+/* }}} */
+ZEND_DLEXPORT int xcache_zend_startup(zend_extension *extension) /* {{{ */
+{
+	xc_zend_extension_gotup = 1;
+
+	if (!origin_compile_file) {
+		origin_compile_file = zend_compile_file;
+		zend_compile_file = xc_check_initial_compile_file;
+	}
+
+	if (zend_llist_count(&zend_extensions) > 1) {
+		zend_llist_position lpos;
+		zend_extension *ext;
+
+		xc_llist_zend_extension = xc_llist_get_element_by_zend_extension(&zend_extensions, XCACHE_NAME);
+		xc_llist_unlink(&zend_extensions, xc_llist_zend_extension);
+
+		ext = (zend_extension *) zend_llist_get_last_ex(&zend_extensions, &lpos);
+		assert(ext && ext != (zend_extension *) xc_llist_zend_extension->data);
+		xc_last_ext_startup = ext->startup;
+		ext->startup = xc_zend_startup_last;
+	}
+	else if (!xc_module_gotup) {
+		return zend_startup_module(&xcache_module_entry);
+	}
+	return SUCCESS;
+}
+/* }}} */
+ZEND_DLEXPORT void xcache_zend_shutdown(zend_extension *extension) /* {{{ */
+{
+	/* empty */
+}
+/* }}} */
+ZEND_DLEXPORT void xcache_statement_handler(zend_op_array *op_array) /* {{{ */
+{
+#ifdef HAVE_XCACHE_COVERAGER
+	xc_coverager_handle_ext_stmt(op_array, ZEND_EXT_STMT);
+#endif
+}
+/* }}} */
+ZEND_DLEXPORT void xcache_fcall_begin_handler(zend_op_array *op_array) /* {{{ */
+{
+#if 0
+	xc_coverager_handle_ext_stmt(op_array, ZEND_EXT_FCALL_BEGIN);
+#endif
+}
+/* }}} */
+ZEND_DLEXPORT void xcache_fcall_end_handler(zend_op_array *op_array) /* {{{ */
+{
+#if 0
+	xc_coverager_handle_ext_stmt(op_array, ZEND_EXT_FCALL_END);
+#endif
+}
+/* }}} */
+/* {{{ zend extension definition structure */
+ZEND_DLEXPORT zend_extension zend_extension_entry = {
+	XCACHE_NAME,
+	XCACHE_VERSION,
+	XCACHE_AUTHOR,
+	XCACHE_URL,
+	XCACHE_COPYRIGHT,
+	xcache_zend_startup,
+	xcache_zend_shutdown,
+	NULL,           /* activate_func_t */
+	NULL,           /* deactivate_func_t */
+	NULL,           /* message_handler_func_t */
+#ifdef HAVE_XCACHE_OPTIMIZER
+	xc_optimizer_op_array_handler,
+#else
+	NULL,           /* op_array_handler_func_t */
+#endif
+	xcache_statement_handler,
+	xcache_fcall_begin_handler,
+	xcache_fcall_end_handler,
+	NULL,           /* op_array_ctor_func_t */
+	NULL,           /* op_array_dtor_func_t */
+	STANDARD_ZEND_EXTENSION_PROPERTIES
+};
+
+#ifndef ZEND_EXT_API
+#	define ZEND_EXT_API ZEND_DLEXPORT
+#endif
+#if COMPILE_DL_XCACHE
+ZEND_EXTENSION();
+#endif
+/* }}} */
Index: /tags/2.0.1/xcache.h
===================================================================
--- /tags/2.0.1/xcache.h	(revision 966)
+++ /tags/2.0.1/xcache.h	(revision 966)
@@ -0,0 +1,483 @@
+#ifndef __XCACHE_H
+#define __XCACHE_H
+#define XCACHE_NAME       "XCache"
+#ifndef XCACHE_VERSION
+#	define XCACHE_VERSION "2.0.1-rc3"
+#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>
+#include <zend_compile.h>
+#include <zend_API.h>
+#include <zend.h>
+#include "php_ini.h"
+#include "zend_hash.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include "xc_shm.h"
+#include "lock.h"
+
+#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
+/* }}} */
+
+
+#define ECALLOC_N(x, n) ((x) = ecalloc(n, sizeof((x)[0])))
+#define ECALLOC_ONE(x) ECALLOC_N(x, 1)
+
+
+
+typedef ulong xc_hash_value_t;
+typedef struct {
+	size_t bits;
+	size_t size;
+	xc_hash_value_t mask;
+} xc_hash_t;
+
+/* the class entry type to be stored in class_table */
+typedef ZESW(zend_class_entry, zend_class_entry*) xc_cest_t;
+
+/* xc_cest_t to (zend_class_entry*) */
+#define CestToCePtr(st) (ZESW(\
+			&(st), \
+			st \
+			) )
+
+/* ZCEP=zend class entry ptr */
+#define ZCEP_REFCOUNT_PTR(pce) (ZESW( \
+			(pce)->refcount, \
+			&((pce)->refcount) \
+			))
+
+#define ZCE_REFCOUNT_PTR(ce) ZCE_REFCOUNT_PTR(&ce)
+
+typedef zend_op_array *(zend_compile_file_t)(zend_file_handle *h, int type TSRMLS_DC);
+
+typedef struct _xc_entry_t xc_entry_t;
+typedef struct _xc_entry_data_php_t xc_entry_data_php_t;
+/* {{{ xc_cache_t */
+typedef struct {
+	int cacheid;
+	xc_hash_t  *hcache; /* hash to cacheid */
+
+	time_t     compiling;
+	zend_ulong updates;
+	zend_ulong hits;
+	zend_ulong clogs;
+	zend_ulong ooms;
+	zend_ulong errors;
+	xc_lock_t  *lck;
+	xc_shm_t   *shm; /* which shm contains us */
+	xc_mem_t   *mem; /* which mem contains us */
+
+	xc_entry_t **entries;
+	int entries_count;
+	xc_entry_data_php_t **phps;
+	int phps_count;
+	xc_entry_t *deletes;
+	int deletes_count;
+	xc_hash_t  *hentry; /* hash settings to entry */
+	xc_hash_t  *hphp;   /* hash settings to php */
+
+	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];
+} xc_cache_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;
+/* {{{ xc_compilererror_t */
+typedef struct {
+	int type;
+	uint lineno;
+	int error_len;
+	char *error;
+} 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 E_STRICT
+	zend_uint compilererror_cnt;
+	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;
+/* }}} */
+
+extern zend_module_entry xcache_module_entry;
+#define phpext_xcache_ptr &xcache_module_entry
+
+int xc_is_rw(const void *p);
+int xc_is_ro(const void *p);
+int xc_is_shm(const void *p);
+/* {{{ 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 /* __XCACHE_H */
Index: /tags/2.0.1/xcache.ini
===================================================================
--- /tags/2.0.1/xcache.ini	(revision 966)
+++ /tags/2.0.1/xcache.ini	(revision 966)
@@ -0,0 +1,79 @@
+;; this is an example, it won't work unless properly configured into php.ini
+[xcache-common]
+;; WARNING: zend_extension* = *xcache* MUST be the first(above) of all zend_extension*=*
+;; using extension=xcache.so is not recommended
+
+;; non-windows example
+;; update xxx accordingly
+zend_extension = /usr/local/lib/php/extensions/non-debug-non-zts-xxx/xcache.so
+;; windows example:
+zend_extension_ts = c:/php/extensions/php_xcache.dll
+;; for newer PHP, _ts is removed, use the following line instead
+zend_extension = c:/php/extensions/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
+
+; 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 =   ""
+
+; 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
+; enable 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
+
+; set in php ini file only
+; make sure it's readable (open_basedir is checked) by coverage viewer script
+xcache.coveragedump_directory = ""
Index: /tags/2.0.1/xcache_globals.h
===================================================================
--- /tags/2.0.1/xcache_globals.h	(revision 966)
+++ /tags/2.0.1/xcache_globals.h	(revision 966)
@@ -0,0 +1,39 @@
+
+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 coverage_enabled;
+	HashTable *coverages;  /* coverages[file][line] = times */
+#endif
+	xc_stack_t *php_holds;
+	xc_stack_t *var_holds;
+	time_t request_time;
+	long   var_ttl;
+	zend_bool auth_enabled;
+
+	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
