Index: /trunk/graph/cached_compile.dot
===================================================================
--- /trunk/graph/cached_compile.dot	(revision 311)
+++ /trunk/graph/cached_compile.dot	(revision 311)
@@ -0,0 +1,31 @@
+digraph tree {
+	subgraph cluster_compiling {
+		label="compiling";
+		php_compile;
+		php_store;
+		entry_store;
+	}
+	error [color=red];
+	origin_compile [color=red]
+
+	begin -> origin_compile [label="compiling", color=red];
+
+	begin -> entry_init_key -> entry_lookup;
+	edge [label=hit, color=blue]
+	entry_lookup -> restore;
+	php_lookup -> entry_store;
+	edge [label=miss, color=green]
+	entry_lookup -> md5_init;
+	md5_init -> php_lookup;
+	php_lookup -> php_compile;
+
+	edge [label="", color=""]
+	php_lookup -> origin_compile [label="miss but compiling", color=red];
+	php_compile -> php_store -> entry_store -> restore;
+
+	edge [color=red];
+	md5_init -> error;
+	php_compile -> error;
+	php_store -> error;
+	entry_store -> error;
+}
Index: /trunk/processor/dispatch.m4
===================================================================
--- /trunk/processor/dispatch.m4	(revision 310)
+++ /trunk/processor/dispatch.m4	(revision 311)
@@ -23,4 +23,5 @@
 	, `$1', `xc_entry_type_t',  `PROC_INT(`$2', `d',  `$1')'
 	, `$1', `xc_hash_value_t',  `PROC_INT(`$2', `lu', `$1')'
+	, `$1', `xc_md5sum_t',      `/* is copying enough? */COPY(`$2')'
 	, `', `', `m4_errprint(`Unknown type "$1"')'
 	)
Index: /trunk/processor/head.m4
===================================================================
--- /trunk/processor/head.m4	(revision 310)
+++ /trunk/processor/head.m4	(revision 311)
@@ -65,6 +65,7 @@
 	zend_bool reference; /* enable if to deal with reference */
 	zend_bool have_references;
-	const xc_entry_t *xce_src;
-	const xc_entry_t *xce_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_num;
@@ -186,5 +187,5 @@
 static zend_ulong xc_get_class_num(xc_processor_t *processor, zend_class_entry *ce) {
 	zend_ulong i;
-	const xc_entry_t *xce = processor->xce_src;
+	const xc_entry_data_php_t *php = processor->php_src;
 	zend_class_entry *ceptr;
 
@@ -192,6 +193,6 @@
 		return processor->cache_class_num;
 	}
-	for (i = 0; i < xce->data.php->classinfo_cnt; i ++) {
-		ceptr = CestToCePtr(xce->data.php->classinfos[i].cest);
+	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;
@@ -209,5 +210,5 @@
 	/* must be parent or currrent class */
 	assert(class_num <= processor->active_class_num);
-	return CestToCePtr(processor->xce_dst->data.php->classinfos[class_num - 1].cest);
+	return CestToCePtr(processor->php_dst->classinfos[class_num - 1].cest);
 }
 #endif
@@ -275,11 +276,13 @@
 /* }}} */
 dnl ================ export API
-/* export: xc_entry_t *xc_processor_store_xc_entry_t(xc_entry_t *src TSRMLS_DC); :export {{{ */
-xc_entry_t *xc_processor_store_xc_entry_t(xc_entry_t *src TSRMLS_DC) {
-	xc_entry_t *dst;
+define(`DEFINE_STORE_API', `
+/* export: $1 *xc_processor_store_$1($1 *src TSRMLS_DC); :export {{{ */
+$1 *xc_processor_store_$1($1 *src TSRMLS_DC) {
+	$1 *dst;
 	xc_processor_t processor;
 
 	memset(&processor, 0, sizeof(processor));
 	processor.reference = 1;
+	processor.cache = src->cache;
 
 	IFASSERT(`xc_stack_init(&processor.allocsizes);')
@@ -295,5 +298,5 @@
 		processor.size = ALIGN(processor.size + sizeof(src[0]));
 
-		xc_calc_xc_entry_t(&processor, src TSRMLS_CC);
+		xc_calc_$1(&processor, src TSRMLS_CC);
 		if (processor.reference) {
 			zend_hash_destroy(&processor.zvalptrs);
@@ -302,5 +305,9 @@
 	}
 	src->size = processor.size;
-	src->have_references = processor.have_references;
+	ifelse(`$1', `xc_entry_t', `
+		src->data.var->have_references = processor.have_references;
+	', `
+		src->have_references = processor.have_references;
+	')
 
 	IFASSERT(`xc_stack_reverse(&processor.allocsizes);')
@@ -314,5 +321,5 @@
 
 		/* mem :) */
-		processor.p = (char *) src->cache->mem->handlers->malloc(src->cache->mem, processor.size);
+		processor.p = (char *) processor.cache->mem->handlers->malloc(processor.cache->mem, processor.size);
 		if (processor.p == NULL) {
 			dst = NULL;
@@ -323,8 +330,8 @@
 
 		/* allocate */
-		dst = (xc_entry_t *) processor.p;
+		dst = ($1 *) processor.p;
 		processor.p = (char *) ALIGN(processor.p + sizeof(dst[0]));
 
-		xc_store_xc_entry_t(&processor, dst, src TSRMLS_CC);
+		xc_store_$1(&processor, dst, src TSRMLS_CC);
 		IFASSERT(` {
 			int real = processor.p - oldp;
@@ -348,10 +355,24 @@
 }
 /* }}} */
-/* export: xc_entry_t *xc_processor_restore_xc_entry_t(xc_entry_t *dst, const xc_entry_t *src, zend_bool readonly_protection TSRMLS_DC); :export {{{ */
-xc_entry_t *xc_processor_restore_xc_entry_t(xc_entry_t *dst, const xc_entry_t *src, zend_bool readonly_protection TSRMLS_DC) {
+')
+DEFINE_STORE_API(`xc_entry_t')
+DEFINE_STORE_API(`xc_entry_data_php_t')
+/* export: xc_entry_t *xc_processor_restore_xc_entry_t(xc_entry_t *dst, const xc_entry_t *src TSRMLS_DC); :export {{{ */
+xc_entry_t *xc_processor_restore_xc_entry_t(xc_entry_t *dst, const xc_entry_t *src TSRMLS_DC) {
+	xc_processor_t processor;
+
+	memset(&processor, 0, sizeof(processor));
+	xc_restore_xc_entry_t(&processor, dst, src TSRMLS_CC);
+
+	return dst;
+}
+/* }}} */
+/* export: xc_entry_data_php_t *xc_processor_restore_xc_entry_data_php_t(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(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;
@@ -361,5 +382,5 @@
 		zend_hash_init(&processor.zvalptrs, 0, NULL, NULL, 0);
 	}
-	xc_restore_xc_entry_t(&processor, dst, src TSRMLS_CC);
+	xc_restore_xc_entry_data_php_t(&processor, dst, src TSRMLS_CC);
 	if (processor.reference) {
 		zend_hash_destroy(&processor.zvalptrs);
Index: /trunk/processor/main.m4
===================================================================
--- /trunk/processor/main.m4	(revision 310)
+++ /trunk/processor/main.m4	(revision 311)
@@ -136,13 +136,19 @@
 define(`FIXPOINTER', `FIXPOINTER_EX(`$1', `dst->$2')')
 define(`FIXPOINTER_EX', `IFSTORE(`
-	$2 = ($1 *) processor->xce_src->cache->shm->handlers->to_readonly(processor->xce_src->cache->shm, (char *)$2);
+	$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->xce_src->cache->shm->handlers->to_readwrite(processor->xce_src->cache->shm, (char *)$2);
+	$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 {{{ COPYPOINTER
+define(`COPYPOINTER', `COPY(`$1')')
+dnl }}}
+dnl {{{ COPYARRAY
+define(`COPYARRAY', `IFNOTMEMCPY(`IFCOPY(`memcpy(dst->$1, src->$1, sizeof(dst->$1));')')DONE(`$1')')
 dnl }}}
 dnl {{{ SETNULL_EX
@@ -223,4 +229,5 @@
 EXPORT(`xc_funcinfo_t')
 EXPORT(`xc_entry_t')
+EXPORT(`xc_entry_data_php_t')
 EXPORT(`zval')
 
Index: /trunk/processor/processor.m4
===================================================================
--- /trunk/processor/processor.m4	(revision 310)
+++ /trunk/processor/processor.m4	(revision 311)
@@ -479,5 +479,5 @@
 	dnl readonly_protection=on
 	dnl main op_array && have early binding
-	if (!processor->readonly_protection && !(src == processor->xce_src->data.php->op_array && processor->xce_src->data.php->have_early_binding)) {
+	if (!processor->readonly_protection && !(src == processor->php_src->op_array && processor->php_src->have_early_binding)) {
 		/* really fast shallow copy */
 		memcpy(dst, src, sizeof(src[0]));
@@ -719,11 +719,19 @@
 	zend_uint i;
 
-#ifdef HAVE_INODE
-	DISPATCH(int, device)
-	DISPATCH(int, inode)
-#endif
+	IFCOPY(`
+		processor->php_dst = dst;
+		processor->php_src = src;
+	')
+
+	DISPATCH(xc_hash_value_t, hvalue)
+	/* skip */
+	DONE(next)
+	COPY(cache)
+	DISPATCH(xc_md5sum_t, md5)
+	DISPATCH(zend_ulong, refcount)
+
 	DISPATCH(size_t, sourcesize)
-
-	DISPATCH(time_t, mtime)
+	DISPATCH(zend_ulong, hits)
+	DISPATCH(size_t, size)
 
 	STRUCT_P(zend_op_array, op_array)
@@ -750,4 +758,5 @@
 	DISPATCH(zend_bool, have_early_binding)
 	popdef(`BEFORE_LOOP')
+	DISPATCH(zend_bool, have_references)
 ')
 dnl }}}
@@ -755,4 +764,5 @@
 	IFDPRINT(`INDENT()`'fprintf(stderr, "zval:value");')
 	STRUCT_P_EX(zval_ptr, dst->value, src->value, `value', `', `&')
+	DISPATCH(zend_bool, have_references)
 	DONE(value)
 ')
@@ -760,8 +770,4 @@
 dnl {{{ xc_entry_t
 DEF_STRUCT_P_FUNC(`xc_entry_t', , `
-	IFCOPY(`
-		processor->xce_dst = dst;
-		processor->xce_src = src;
-	')
 	DISPATCH(xc_entry_type_t, type)
 	DISPATCH(size_t, size)
@@ -809,9 +815,11 @@
 		switch (src->type) {
 		case XC_TYPE_PHP:
-			STRUCT_P(xc_entry_data_php_t, data.php)
+			IFCALCCOPY(`DONE(data.php)', `STRUCT_P(xc_entry_data_php_t, data.php)')
 			break;
+
 		case XC_TYPE_VAR:
 			STRUCT_P(xc_entry_data_var_t, data.var)
 			break;
+
 		default:
 			assert(0);
@@ -820,5 +828,9 @@
 	DONE(data)
 	dnl }}}
-	DISPATCH(zend_bool, have_references)
+	DISPATCH(time_t, mtime)
+#ifdef HAVE_INODE
+	DISPATCH(int, device)
+	DISPATCH(int, inode)
+#endif
 ')
 dnl }}}
Index: /trunk/xcache.c
===================================================================
--- /trunk/xcache.c	(revision 310)
+++ /trunk/xcache.c	(revision 311)
@@ -106,4 +106,64 @@
 /* any function in *_dmz is only safe be called within locked(single thread) area */
 
+static void xc_php_add_dmz(xc_entry_data_php_t *php) /* {{{ */
+{
+	xc_entry_data_php_t **head = &(php->cache->phps[php->hvalue]);
+	php->next = *head;
+	*head = php;
+	php->cache->phps_count ++;
+}
+/* }}} */
+static xc_entry_data_php_t *xc_php_store_dmz(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(php TSRMLS_CC);
+	if (stored_php) {
+		xc_php_add_dmz(stored_php);
+		return stored_php;
+	}
+	else {
+		php->cache->ooms ++;
+		return NULL;
+	}
+}
+/* }}} */
+static xc_entry_data_php_t *xc_php_find_dmz(xc_entry_data_php_t *php TSRMLS_DC) /* {{{ */
+{
+	xc_entry_data_php_t *p;
+	for (p = php->cache->phps[php->hvalue]; p; p = p->next) {
+		if (memcmp(php->md5, p->md5, sizeof(php->md5)) == 0) {
+			p->hits ++;
+			return p;
+		}
+	}
+	return NULL;
+}
+/* }}} */
+static void xc_php_free_dmz(xc_entry_data_php_t *php) /* {{{ */
+{
+	php->cache->mem->handlers->free(php->cache->mem, (xc_entry_data_php_t *)php);
+}
+/* }}} */
+static void xc_php_remove_dmz(xc_entry_data_php_t *php) /* {{{ */
+{
+	if (-- php->refcount == 0) {
+		xc_entry_data_php_t **pp = &(php->cache->phps[php->hvalue]);
+		xc_entry_data_php_t *p;
+		for (p = *pp; p; pp = &(p->next), p = p->next) {
+			if (memcmp(php->md5, p->md5, sizeof(php->md5)) == 0) {
+				/* unlink */
+				*pp = p->next;
+				xc_php_free_dmz(php);
+				return;
+			}
+		}
+		assert(0);
+	}
+}
+/* }}} */
+
 static inline int xc_entry_equal_dmz(xc_entry_t *a, xc_entry_t *b) /* {{{ */
 {
@@ -117,9 +177,7 @@
 #ifdef HAVE_INODE
 			do {
-				xc_entry_data_php_t *ap = a->data.php;
-				xc_entry_data_php_t *bp = b->data.php;
-				if (ap->inode) {
-					return ap->inode == bp->inode
-						&& ap->device == bp->device;
+				if (a->inode) {
+					return a->inode == b->inode
+						&& a->device == b->device;
 				}
 			} while(0);
@@ -150,9 +208,4 @@
 }
 /* }}} */
-static void xc_entry_free_real_dmz(volatile xc_entry_t *xce) /* {{{ */
-{
-	xce->cache->mem->handlers->free(xce->cache->mem, (xc_entry_t *)xce);
-}
-/* }}} */
 static void xc_entry_add_dmz(xc_entry_t *xce) /* {{{ */
 {
@@ -179,4 +232,12 @@
 		return NULL;
 	}
+}
+/* }}} */
+static void xc_entry_free_real_dmz(volatile xc_entry_t *xce) /* {{{ */
+{
+	if (xce->type == XC_TYPE_PHP) {
+		xc_php_remove_dmz(xce->data.php);
+	}
+	xce->cache->mem->handlers->free(xce->cache->mem, (xc_entry_t *)xce);
 }
 /* }}} */
@@ -216,5 +277,5 @@
 	for (p = xce->cache->entries[xce->hvalue]; p; p = p->next) {
 		if (xc_entry_equal_dmz(xce, p)) {
-			if (p->type == XC_TYPE_VAR || /* PHP */ p->data.php->mtime == xce->data.php->mtime) {
+			if (p->type == XC_TYPE_VAR || /* PHP */ p->mtime == xce->mtime) {
 				p->hits ++;
 				p->atime = XG(request_time);
@@ -474,8 +535,8 @@
 			add_assoc_long_ex(ei, ZEND_STRS("sourcesize"),    php->sourcesize);
 #ifdef HAVE_INODE
-			add_assoc_long_ex(ei, ZEND_STRS("device"),        php->device);
-			add_assoc_long_ex(ei, ZEND_STRS("inode"),         php->inode);
-#endif
-			add_assoc_long_ex(ei, ZEND_STRS("mtime"),         php->mtime);
+			add_assoc_long_ex(ei, ZEND_STRS("device"),        entry->device);
+			add_assoc_long_ex(ei, ZEND_STRS("inode"),         entry->inode);
+#endif
+			add_assoc_long_ex(ei, ZEND_STRS("mtime"),         entry->mtime);
 
 #ifdef HAVE_XCACHE_CONSTANT
@@ -644,5 +705,5 @@
 		if (VCWD_STAT(filepath, pbuf) == 0) {
 			free_alloca(paths);
-			return 0;
+			return FAILURE;
 		}
 	}
@@ -650,5 +711,5 @@
 	free_alloca(paths);
 
-	return 1;
+	return SUCCESS;
 }
 /* }}} */
@@ -656,5 +717,6 @@
 #define HASH(i) (i)
 #define HASH_USTR_L(t, s, l) HASH(zend_u_inline_hash_func(t, s, (l + 1) * sizeof(UChar)))
-#define HASH_STR_L(s, l) HASH(zend_inline_hash_func(s, l + 1))
+#define HASH_STR_S(s, l) HASH(zend_inline_hash_func(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)
@@ -669,6 +731,6 @@
 {
 #ifdef HAVE_INODE
-	if (xce->data.php->inode) {
-		return HASH(xce->data.php->device + xce->data.php->inode);
+	if (xce->inode) {
+		return HASH(xce->device + xce->inode);
 	}
 #endif
@@ -685,5 +747,5 @@
 
 	if (!filename || !SG(request_info).path_translated) {
-		return 0;
+		return FAILURE;
 	}
 
@@ -703,5 +765,5 @@
 		if (IS_ABSOLUTE_PATH(filename, strlen(filename))) {
 			if (VCWD_STAT(filename, pbuf) != 0) {
-				return 0;
+				return FAILURE;
 			}
 			goto stat_done;
@@ -719,5 +781,5 @@
 
 			if (VCWD_STAT(filename, pbuf) != 0) {
-				return 0;
+				return FAILURE;
 			}
 			goto stat_done;
@@ -726,6 +788,6 @@
 
 		/* use include_path */
-		if (xc_stat(filename, PG(include_path), pbuf TSRMLS_CC) != 0) {   
-			return 0;
+		if (xc_stat(filename, PG(include_path), pbuf TSRMLS_CC) != SUCCESS) {
+			return FAILURE;
 		}
 
@@ -734,19 +796,19 @@
 stat_done:
 		if (XG(request_time) - pbuf->st_mtime < 2 && !xc_test) {
-			return 0;
-		}
-
-		php->mtime        = pbuf->st_mtime;
+			return FAILURE;
+		}
+
+		xce->mtime        = pbuf->st_mtime;
 #ifdef HAVE_INODE
-		php->device       = pbuf->st_dev;
-		php->inode        = pbuf->st_ino;
+		xce->device       = pbuf->st_dev;
+		xce->inode        = pbuf->st_ino;
 #endif
 		php->sourcesize   = pbuf->st_size;
 	}
 	else { /* XG(inode) */
-		php->mtime        = 0;
+		xce->mtime        = 0;
 #ifdef HAVE_INODE
-		php->device       = 0;
-		php->inode        = 0;
+		xce->device       = 0;
+		xce->inode        = 0;
 #endif
 		php->sourcesize   = 0;
@@ -754,5 +816,5 @@
 
 #ifdef HAVE_INODE
-	if (!php->inode)
+	if (!xce->inode)
 #endif
 	{
@@ -760,5 +822,5 @@
 		filename = expand_filepath(filename, opened_path_buffer TSRMLS_CC);
 		if (filename == NULL) {
-			return 0;
+			return FAILURE;
 		}
 	}
@@ -775,5 +837,49 @@
 
 	xce->type = XC_TYPE_PHP;
-	return 1;
+	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, sizeof(php->md5));
+}
+/* }}} */
+static int xc_entry_init_key_php_md5(xc_entry_data_php_t *php, xc_entry_t *xce TSRMLS_DC) /* {{{ */
+{
+	unsigned char   buf[1024];
+	PHP_MD5_CTX     context;
+	int             n;
+	php_stream     *stream;
+	xc_hash_value_t hv;
+
+	stream = php_stream_open_wrapper(xce->name.str.val, "rb", REPORT_ERRORS | ENFORCE_SAFE_MODE, 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 *) php->md5, &context);
+
+	php_stream_close(stream);
+
+	if (n < 0) {
+		return FAILURE;
+	}
+
+	hv = xc_php_hash_md5(php TSRMLS_CC);
+	php->cache  = xce->cache;
+	php->hvalue = (hv & php->cache->hphp->mask);
+#ifdef DEBUG
+	{
+		char md5str[33];
+		make_digest(md5str, (unsigned char *) php->md5);
+		TRACE("md5 %s", md5str);
+	}
+#endif
+
+	return SUCCESS;
 }
 /* }}} */
@@ -805,98 +911,32 @@
 }
 /* }}} */
-static zend_op_array *xc_compile_file(zend_file_handle *h, int type TSRMLS_DC) /* {{{ */
-{
-	xc_sandbox_t sandbox;
+static void xc_free_php(xc_entry_data_php_t *php TSRMLS_DC) /* {{{ */
+{
+#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 zend_op_array *xc_compile_php(xc_entry_data_php_t *php, zend_file_handle *h, int type TSRMLS_DC) /* {{{ */
+{
 	zend_op_array *op_array;
-	xc_entry_t xce, *stored_xce;
-	xc_entry_data_php_t php;
-	xc_cache_t *cache;
-	zend_bool clogged = 0;
-	zend_bool catched = 0;
-	char *filename;
-	char opened_path_buffer[MAXPATHLEN];
 	int old_constinfo_cnt, old_funcinfo_cnt, old_classinfo_cnt;
 	int i;
-
-	if (!xc_initized) {
-		assert(0);
-	}
-
-	if (!XG(cacher)) {
-		op_array = origin_compile_file(h, type TSRMLS_CC);
-#ifdef HAVE_XCACHE_OPTIMIZER
-		if (XG(optimizer)) {
-			xc_optimize(op_array TSRMLS_CC);
-		}
-#endif
-		return op_array;
-	}
-
-	/* {{{ prepare key
-	 * include_once() and require_once() gives us opened_path
-	 * however, include() and require() non-absolute path which break
-	 * included_files, and may confuse with (include|require)_once
-	 * -- Xuefer
-	 */
-
-	filename = h->opened_path ? h->opened_path : h->filename;
-	xce.data.php = &php;
-	if (!xc_entry_init_key_php(&xce, filename, opened_path_buffer TSRMLS_CC)) {
-		return origin_compile_file(h, type TSRMLS_CC);
-	}
-	cache = xce.cache;
-	/* }}} */
-	/* {{{ restore */
-	/* stale precheck */
-	if (cache->compiling) {
-		cache->clogs ++; /* is it safe here? */
-		return origin_compile_file(h, type TSRMLS_CC);
-	}
-
-	stored_xce = NULL;
-	op_array = NULL;
-	ENTER_LOCK_EX(cache) {
-		/* clogged */
-		if (cache->compiling) {
-			cache->clogs ++;
-			op_array = NULL;
-			clogged = 1;
-			break;
-		}
-
-		stored_xce = xc_entry_find_dmz(&xce TSRMLS_CC);
-		/* found */
-		if (stored_xce) {
-			TRACE("found %s, catch it", stored_xce->name.str.val);
-			xc_entry_hold_php_dmz(stored_xce TSRMLS_CC);
-			cache->hits ++;
-			break;
-		}
-
-		cache->compiling = XG(request_time);
-		cache->misses ++;
-	} LEAVE_LOCK_EX(cache);
-
-	if (catched) {
-		cache->compiling = 0;
-		zend_bailout();
-	}
-
-	/* found */
-	if (stored_xce) {
-		goto restore;
-	}
-
-	/* clogged */
-	if (clogged) {
-		return origin_compile_file(h, type TSRMLS_CC);
-	}
-	/* }}} */
+	zend_bool catched = 0;
 
 	/* {{{ compile */
-	TRACE("compiling %s", filename);
-
-	/* make compile inside sandbox */
-	xc_sandbox_init(&sandbox, filename TSRMLS_CC);
+	TRACE("compiling %s", h->opened_path ? h->opened_path : h->filename);
 
 	old_classinfo_cnt = zend_hash_num_elements(CG(class_table));
@@ -915,20 +955,6 @@
 
 	if (op_array == NULL) {
-		goto err_oparray;
-	}
-
-	filename = h->opened_path ? h->opened_path : h->filename;
-	/* none-inode enabled entry hash/compare on name
-	 * do not update to its name to real pathname
-	 */
-#ifdef HAVE_INODE
-	if (xce.data.php->inode)
-	{
-		if (xce.name.str.val != filename) {
-			xce.name.str.val = filename;
-			xce.name.str.len = strlen(filename);
-		}
-	}
-#endif
+		goto err_op_array;
+	}
 
 #ifdef HAVE_XCACHE_OPTIMIZER
@@ -939,21 +965,21 @@
 	/* }}} */
 	/* {{{ prepare */
-	php.op_array      = op_array;
+	php->op_array      = op_array;
 
 #ifdef HAVE_XCACHE_CONSTANT
-	php.constinfo_cnt  = zend_hash_num_elements(EG(zend_constants)) - old_constinfo_cnt;
-#endif
-	php.funcinfo_cnt   = zend_hash_num_elements(CG(function_table)) - old_funcinfo_cnt;
-	php.classinfo_cnt  = zend_hash_num_elements(CG(class_table))    - old_classinfo_cnt;
+	php->constinfo_cnt  = zend_hash_num_elements(EG(zend_constants)) - old_constinfo_cnt;
+#endif
+	php->funcinfo_cnt   = zend_hash_num_elements(CG(function_table)) - old_funcinfo_cnt;
+	php->classinfo_cnt  = zend_hash_num_elements(CG(class_table))    - old_classinfo_cnt;
 #ifdef ZEND_ENGINE_2_1
-	/* {{{ count php.autoglobal_cnt */ {
+	/* {{{ count php->autoglobal_cnt */ {
 		Bucket *b;
 
-		php.autoglobal_cnt = 0;
+		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) {
-				php.autoglobal_cnt ++;
+				php->autoglobal_cnt ++;
 			}
 		}
@@ -963,12 +989,12 @@
 
 #define X_ALLOC_N(var, cnt) do {     \
-	if (php.cnt) {                   \
-		ECALLOC_N(php.var, php.cnt); \
-		if (!php.var) {              \
-			goto err_##var;          \
+	if (php->cnt) {                  \
+		ECALLOC_N(php->var, php->cnt); \
+		if (!php->var) {             \
+			goto err_alloc;          \
 		}                            \
 	}                                \
 	else {                           \
-		php.var = NULL;              \
+		php->var = NULL;             \
 	}                                \
 } while (0)
@@ -990,5 +1016,5 @@
 #define COPY_H(vartype, var, cnt, name, datatype) do {        \
 	for (i = 0; b; i ++, b = b->pListNext) {                  \
-		vartype *data = &php.var[i];                          \
+		vartype *data = &php->var[i];                         \
                                                               \
 		if (i < old_##cnt) {                                  \
@@ -996,10 +1022,10 @@
 		}                                                     \
                                                               \
-		assert(i < old_##cnt + php.cnt);                      \
+		assert(i < old_##cnt + 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);          \
+			ZSTR_S(data->key)      = BUCKET_KEY_S(b);         \
 		}                                                     \
 		else {                                                \
@@ -1027,7 +1053,7 @@
 			/* check if actived */
 			if (auto_global->auto_global_callback && !auto_global->armed) {
-				xc_autoglobal_t *data = &php.autoglobals[i];
-
-				assert(i < php.autoglobal_cnt);
+				xc_autoglobal_t *data = &php->autoglobals[i];
+
+				assert(i < php->autoglobal_cnt);
 				i ++;
 				UNISW(NOTHING, data->type = b->key.type;)
@@ -1045,78 +1071,43 @@
 	/* }}} */
 	/* {{{ find inherited classes that should be early-binding */
-	php.have_early_binding = 0;
-	for (i = 0; i < php.classinfo_cnt; i ++) {
-		php.classinfos[i].oplineno = -1;
-	}
-
-	xc_undo_pass_two(php.op_array TSRMLS_CC);
-	xc_foreach_early_binding_class(php.op_array, xc_cache_early_binding_class_cb, (void *) &php TSRMLS_CC);
-	xc_redo_pass_two(php.op_array TSRMLS_CC);
+	php->have_early_binding = 0;
+	for (i = 0; i < php->classinfo_cnt; i ++) {
+		php->classinfos[i].oplineno = -1;
+	}
+
+	xc_undo_pass_two(php->op_array TSRMLS_CC);
+	xc_foreach_early_binding_class(php->op_array, xc_cache_early_binding_class_cb, (void *) &php TSRMLS_CC);
+	xc_redo_pass_two(php->op_array TSRMLS_CC);
 	/* }}} */
-#ifdef SHOW_DPRINT
-	xc_dprint(&xce, 0 TSRMLS_CC);
-#endif
-	ENTER_LOCK_EX(cache) { /* {{{ store/add entry */
-		stored_xce = xc_entry_store_dmz(&xce TSRMLS_CC);
-	} LEAVE_LOCK_EX(cache);
-	/* }}} */
-	TRACE("%s", "stored");
-
-#define X_FREE(var) \
-	if (xce.data.php->var) { \
-		efree(xce.data.php->var); \
-	} \
-err_##var:
-
-#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
-
-err_oparray:
+
+	return op_array;
+
+err_alloc:
+	xc_free_php(php TSRMLS_CC);
+
 err_bailout:
-
-	if (xc_test && stored_xce) {
-		/* free it, no install. restore now */
-		xc_sandbox_free(&sandbox, 0 TSRMLS_CC);
-	}
-	else if (!op_array) {
-		/* failed to compile free it, no install */
-		xc_sandbox_free(&sandbox, 0 TSRMLS_CC);
-	}
-	else {
-		CG(active_op_array) = op_array;
-		xc_sandbox_free(&sandbox, 1 TSRMLS_CC);
-	}
-
-	ENTER_LOCK(cache) {
-		cache->compiling = 0;
-	} LEAVE_LOCK(cache);
+err_op_array:
+
 	if (catched) {
 		zend_bailout();
 	}
-	if (xc_test && stored_xce) {
-#ifdef ZEND_ENGINE_2
-		destroy_op_array(op_array TSRMLS_CC);
-#else
-		destroy_op_array(op_array);
-#endif
-		efree(op_array);
-		h = NULL;
-		goto restore;
-	}
+
 	return op_array;
-
-restore:
+}
+/* }}} */
+static zend_op_array *xc_compile_restore(xc_entry_t *stored_xce, zend_file_handle *h TSRMLS_DC) /* {{{ */
+{
+	zend_op_array *op_array;
+	xc_entry_t xce;
+	xc_entry_data_php_t php;
+	zend_bool catched;
+
 	CG(in_compilation)    = 1;
 	CG(compiled_filename) = stored_xce->name.str.val;
 	CG(zend_lineno)       = 0;
 	TRACE("restoring %s", stored_xce->name.str.val);
-	xc_processor_restore_xc_entry_t(&xce, stored_xce, xc_readonly_protection TSRMLS_CC);
+	xc_processor_restore_xc_entry_t(&xce, stored_xce TSRMLS_CC);
+	xc_processor_restore_xc_entry_data_php_t(&php, xce.data.php, xc_readonly_protection TSRMLS_CC);
+	xce.data.php = &php;
 #ifdef SHOW_DPRINT
 	xc_dprint(&xce, 0 TSRMLS_CC);
@@ -1130,18 +1121,5 @@
 	} zend_end_try();
 
-#define X_FREE(var) \
-	if (xce.data.php->var) { \
-		efree(xce.data.php->var); \
-	}
-#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
-	efree(xce.data.php);
+	xc_free_php(&php TSRMLS_CC);
 
 	if (catched) {
@@ -1151,4 +1129,187 @@
 	CG(compiled_filename) = NULL;
 	TRACE("restored  %s", stored_xce->name.str.val);
+	return op_array;
+}
+/* }}} */
+static zend_op_array *xc_compile_file(zend_file_handle *h, int type TSRMLS_DC) /* {{{ */
+{
+	zend_op_array *op_array;
+	xc_entry_t xce, *stored_xce;
+	xc_entry_data_php_t php, *stored_php;
+	xc_cache_t *cache;
+	zend_bool gaveup = 0;
+	zend_bool catched = 0;
+	zend_bool cached_php;
+	char *filename;
+	char opened_path_buffer[MAXPATHLEN];
+	xc_sandbox_t sandbox;
+
+	assert(xc_initized);
+
+	if (!XG(cacher)) {
+		op_array = origin_compile_file(h, type TSRMLS_CC);
+#ifdef HAVE_XCACHE_OPTIMIZER
+		if (XG(optimizer)) {
+			xc_optimize(op_array TSRMLS_CC);
+		}
+#endif
+		return op_array;
+	}
+
+	/* {{{ entry_init_key */
+	filename = h->opened_path ? h->opened_path : h->filename;
+	xce.data.php = &php;
+	if (xc_entry_init_key_php(&xce, filename, opened_path_buffer TSRMLS_CC) != SUCCESS) {
+		return origin_compile_file(h, type TSRMLS_CC);
+	}
+	cache = xce.cache;
+	/* }}} */
+
+	/* stale clogs precheck */
+	if (cache->compiling) {
+		cache->clogs ++;
+		return origin_compile_file(h, type TSRMLS_CC);
+	}
+	/* {{{ entry_lookup/hit/md5_init/php_lookup */
+	stored_xce = NULL;
+	stored_php = NULL;
+	ENTER_LOCK_EX(cache) {
+		stored_xce = xc_entry_find_dmz(&xce TSRMLS_CC);
+		if (stored_xce) {
+			cache->hits ++;
+
+			TRACE("hit %s, holding", stored_xce->name.str.val);
+			xc_entry_hold_php_dmz(stored_xce TSRMLS_CC);
+		}
+		else {
+			cache->misses ++;
+			TRACE("miss %s", xce.name.str.val);
+
+			if (xc_entry_init_key_php_md5(&php, &xce TSRMLS_CC) != SUCCESS) {
+				gaveup = 1;
+				break;
+			}
+
+			stored_php = xc_php_find_dmz(&php TSRMLS_CC);
+
+			/* miss but compiling */
+			if (!stored_php) {
+				if (cache->compiling) {
+					TRACE("%s", "miss but compiling");
+					cache->clogs ++;
+					gaveup = 1;
+					break;
+				}
+				TRACE("%s", "php_lookup miss");
+			}
+			else {
+				TRACE("%s", "php_lookup hit");
+			}
+
+			cache->compiling = XG(request_time);
+		}
+	} LEAVE_LOCK_EX(cache);
+
+	if (catched) {
+		cache->compiling = 0;
+		zend_bailout();
+	}
+
+	/* hit */
+	if (stored_xce) {
+		return xc_compile_restore(stored_xce, h TSRMLS_CC);
+	}
+
+	/* gaveup */
+	if (gaveup) {
+		return origin_compile_file(h, type TSRMLS_CC);
+	}
+	/* }}} */
+	op_array = NULL;
+	/* {{{ compile */
+	if (stored_php) {
+		cached_php = 1;
+		xce.data.php = stored_php;
+	}
+	else {
+		cached_php = 0;
+
+		/* make compile inside sandbox */
+		xc_sandbox_init(&sandbox, filename TSRMLS_CC);
+		zend_try {
+			op_array = xc_compile_php(&php, h, type TSRMLS_CC);
+		} zend_catch {
+			catched = 1;
+		} zend_end_try();
+		xc_sandbox_free(&sandbox, 0 TSRMLS_CC);
+
+		if (catched) {
+			cache->compiling = 0;
+			zend_bailout();
+		}
+
+		xce.data.php = &php;
+	}
+	/* }}} */
+#ifdef HAVE_INODE
+	/* {{{ path name fix
+	 * inode enabled entry hash/compare on name
+	 * do not update to its name to real pathname
+	 * WARNING: this code is required to be after compile
+	 */
+	if (xce.inode) {
+		filename = h->opened_path ? h->opened_path : h->filename;
+		if (xce.name.str.val != filename) {
+			xce.name.str.val = filename;
+			xce.name.str.len = strlen(filename);
+		}
+	}
+	/* }}} */
+#endif
+#ifdef SHOW_DPRINT
+	xc_dprint(&xce, 0 TSRMLS_CC);
+#endif
+	stored_xce = NULL;
+	ENTER_LOCK_EX(cache) { /* {{{ php_store/entry_store */
+		/* php_store */
+		if (!cached_php) {
+			stored_php = xc_php_store_dmz(&php TSRMLS_CC);
+			/* error */
+			if (!stored_php) {
+				break;
+			}
+		}
+		/* entry_store */
+		stored_xce = xc_entry_store_dmz(&xce TSRMLS_CC);
+		if (stored_xce) {
+			stored_xce->data.php = stored_php;
+			stored_php->refcount ++;
+		}
+		else {
+			/* error */
+			xc_php_remove_dmz(stored_php);
+			stored_php = NULL;
+		}
+	} LEAVE_LOCK_EX(cache);
+	/* }}} */
+	TRACE("%s", stored_xce ? "stored" : "store failed");
+
+	cache->compiling = 0;
+	if (catched) {
+		zend_bailout();
+	}
+
+	if (stored_xce) {
+		if (op_array) {
+#ifdef ZEND_ENGINE_2
+			destroy_op_array(op_array TSRMLS_CC);
+#else
+			destroy_op_array(op_array);
+#endif
+			efree(op_array);
+			h = NULL;
+		}
+		return xc_compile_restore(stored_xce, h TSRMLS_CC);
+	}
 	return op_array;
 }
@@ -1279,5 +1440,5 @@
 }
 /* }}} */
-static xc_cache_t **xc_cache_init(xc_shm_t *shm, xc_hash_t *hcache, xc_hash_t *hentry, xc_shmsize_t shmsize) /* {{{ */
+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;
@@ -1306,8 +1467,12 @@
 		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;
@@ -1364,9 +1529,9 @@
 			zend_compile_file = xc_compile_file;
 
-			CHECK(xc_php_caches = xc_cache_init(shm, &xc_php_hcache, &xc_php_hentry, xc_php_size), "failed init opcode cache");
+			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, xc_var_size), "failed init variable cache");
+			CHECK(xc_var_caches = xc_cache_init(shm, &xc_var_hcache, &xc_var_hentry, NULL, xc_var_size), "failed init variable cache");
 		}
 	}
@@ -1715,5 +1880,5 @@
 		if (stored_xce) {
 			if (!VAR_ENTRY_EXPIRED(stored_xce)) {
-				xc_processor_restore_zval(return_value, stored_xce->data.var->value, stored_xce->have_references TSRMLS_CC);
+				xc_processor_restore_zval(return_value, stored_xce->data.var->value, stored_xce->data.var->have_references TSRMLS_CC);
 				/* return */
 				break;
@@ -1864,5 +2029,5 @@
 				else {
 					TRACE("%s", "incdec: notlong");
-					xc_processor_restore_zval(&oldzval, stored_xce->data.var->value, stored_xce->have_references TSRMLS_CC);
+					xc_processor_restore_zval(&oldzval, stored_xce->data.var->value, stored_xce->data.var->have_references TSRMLS_CC);
 					convert_to_long(&oldzval);
 					value = Z_LVAL(oldzval);
Index: /trunk/xcache.h
===================================================================
--- /trunk/xcache.h	(revision 310)
+++ /trunk/xcache.h	(revision 311)
@@ -165,6 +165,7 @@
 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 _xc_entry_t xc_entry_t;
 typedef struct {
 	int cacheid;
@@ -182,7 +183,10 @@
 	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 to entry */
+	xc_hash_t  *hentry; /* hash settings to entry */
+	xc_hash_t  *hphp;   /* hash settings to php */
 
 	time_t     last_gc_deletes;
@@ -235,12 +239,17 @@
 #endif
 typedef enum { XC_TYPE_PHP, XC_TYPE_VAR } xc_entry_type_t;
+typedef char xc_md5sum_t[16];
 /* {{{ xc_entry_data_php_t */
-typedef struct {
+struct _xc_entry_data_php_t {
+	xc_hash_value_t hvalue; /* hash of md5 */
+	xc_entry_data_php_t *next;
+	xc_cache_t *cache;      /* which cache it's on */
+
+	xc_md5sum_t md5;        /* md5sum of the source */
+	zend_ulong  refcount;   /* count of entries referencing to this data */
+
 	size_t sourcesize;
-#ifdef HAVE_INODE
-	int device;             /* the filesystem device */
-	int inode;              /* the filesystem inode */
-#endif
-	time_t mtime;           /* the mtime of origin source file */
+	zend_ulong hits;        /* hits of this php */
+	size_t     size;
 
 	zend_op_array *op_array;
@@ -262,9 +271,13 @@
 	xc_autoglobal_t *autoglobals;
 #endif
-} xc_entry_data_php_t;
+
+	zend_bool  have_references;
+};
 /* }}} */
 /* {{{ xc_entry_data_var_t */
 typedef struct {
 	zval   *value;
+
+	zend_bool  have_references;
 } xc_entry_data_var_t;
 /* }}} */
@@ -278,5 +291,5 @@
 
 	size_t     size;
-	zend_ulong refcount;
+	zend_ulong refcount;    /* count of instances holding this entry */
 	zend_ulong hits;
 	time_t     ctime;           /* the ctime of this entry */
@@ -295,5 +308,9 @@
 	} data;
 
-	zend_bool  have_references;
+	time_t mtime;           /* the mtime of origin source file */
+#ifdef HAVE_INODE
+	int device;             /* the filesystem device */
+	int inode;              /* the filesystem inode */
+#endif
 };
 /* }}} */
