Index: trunk/xcache.c
===================================================================
--- trunk/xcache.c	(revision 661)
+++ trunk/xcache.c	(revision 662)
@@ -37,4 +37,12 @@
 #include "opcode_spec.h"
 #include "utils.h"
+
+#ifndef ZEND_ENGINE_2_3
+ZEND_API size_t zend_dirname(char *path, size_t len)
+{
+	php_dirname(path, len);
+	return strlen(path);
+}
+#endif
 
 #define VAR_ENTRY_EXPIRED(pentry) ((pentry)->ttl && XG(request_time) > pentry->ctime + (pentry)->ttl)
@@ -1005,4 +1013,5 @@
 	{
 		/* hash on filename, let's expand it to real path */
+		/* FIXME */
 		filename = expand_filepath(filename, opened_path_buffer TSRMLS_CC);
 		if (filename == NULL) {
@@ -1108,6 +1117,197 @@
 /* }}} */
 #endif
+
+/* {{{ Constant Usage */
+#define xcache_op1_is_file 1
+#define xcache_op1_is_dir  2
+#define xcache_op2_is_file 4
+#define xcache_op2_is_dir  8
+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_entry_data_php_t *php, xc_const_usage_t *usage, xc_op_array_info_t *op_array_info, zend_op_array *op_array TSRMLS_DC) /* {{{ */
+{
+	int oplineno;
+	xc_vector_t vector_int;
+
+	xc_vector_init(int, &vector_int);
+
+#define XCACHE_CHECK_OP(type, op) \
+	if (zend_binary_strcmp(Z_STRVAL(opline->op.u.constant), Z_STRLEN(opline->op.u.constant), php->type##path, php->type##path_len) == 0) { \
+		usage->type##path_used = 1; \
+		oplineinfo |= xcache_##op##_is_##type; \
+	}
+
+#define XCACHE_U_CHECK_OP(type, op) \
+	if (zend_u_##binary_strcmp(Z_USTRVAL(opline->op.u.constant), Z_USTRLEN(opline->op.u.constant), php->u##type##path, php->u##type##path_len) == 0) { \
+		usage->u##type##path_used = 1; \
+		oplineinfo |= xcache_##op##_is_##type; \
+	}
+
+	for (oplineno = 0; oplineno < op_array->last; oplineno++) {
+		zend_op *opline = &op_array->opcodes[oplineno];
+		int oplineinfo = 0;
+		if (opline->op1.op_type == IS_CONST) {
+			if (Z_TYPE(opline->op1.u.constant) == IS_STRING) {
+				XCACHE_CHECK_OP(file, op1)
+				else XCACHE_CHECK_OP(dir, op1)
+			}
+
+#ifdef IS_UNICODE
+			else if (Z_TYPE(opline->op1.u.constant) == IS_UNICODE) {
+				XCACHE_U_CHECK_OP(file, op1)
+				else XCACHE_U_CHECK_OP(dir, op1)
+			}
+#endif
+		}
+		if (opline->op2.op_type == IS_CONST) {
+			if (Z_TYPE(opline->op2.u.constant) == IS_STRING) {
+				XCACHE_CHECK_OP(file, op2)
+				else XCACHE_CHECK_OP(dir, op2)
+			}
+
+#ifdef IS_UNICODE
+			else if (Z_TYPE(opline->op2.u.constant) == IS_UNICODE) {
+				XCACHE_U_CHECK_OP(file, op2)
+				else XCACHE_U_CHECK_OP(dir, op2)
+			}
+#endif
+		}
+		if (oplineinfo) {
+			xc_vector_add(int, &vector_int, oplineno);
+			xc_vector_add(int, &vector_int, oplineinfo);
+		}
+	}
+
+	op_array_info->oplineinfo_cnt = vector_int.cnt;
+	op_array_info->oplineinfos    = xc_vector_detach(int, &vector_int);
+	xc_vector_free(int, &vector_int);
+}
+/* }}} */
+void xc_fix_op_array_info(const xc_entry_data_php_t *php, zend_op_array *op_array, int copy, const xc_op_array_info_t *op_array_info TSRMLS_DC) /* {{{ */
+{
+	int i;
+	if (!op_array_info->oplineinfo_cnt) {
+		return;
+	}
+
+	for (i = 0; i < op_array_info->oplineinfo_cnt; i += 2) {
+		int oplineno = op_array_info->oplineinfos[i];
+		int oplineinfo = op_array_info->oplineinfos[i + 1];
+		zend_op *opline = &op_array->opcodes[oplineno];
+		if ((oplineinfo & xcache_op1_is_file)) {
+			assert(opline->op1.op_type == IS_CONST);
+			if (copy) {
+				efree(Z_STRVAL(opline->op1.u.constant));
+			}
+			if (Z_TYPE(opline->op1.u.constant) == IS_STRING) {
+				assert(php->filepath);
+				ZVAL_STRINGL(&opline->op1.u.constant, php->filepath, php->filepath_len, copy);
+			}
+#ifdef IS_UNICODE
+			else if (Z_TYPE(opline->op1.u.constant) == IS_UNICODE) {
+				assert(php->ufilepath);
+				ZVAL_UNICODEL(&opline->op1.u.constant, php->ufilepath, php->ufilepath_len, copy);
+			}
+#endif
+			else {
+				assert(0);
+			}
+		}
+		else if ((oplineinfo & xcache_op1_is_dir)) {
+			assert(opline->op1.op_type == IS_CONST);
+			if (copy) {
+				efree(Z_STRVAL(opline->op1.u.constant));
+			}
+			if (Z_TYPE(opline->op1.u.constant) == IS_STRING) {
+				assert(php->dirpath);
+				ZVAL_STRINGL(&opline->op1.u.constant, php->dirpath, php->dirpath_len, copy);
+			}
+#ifdef IS_UNICODE
+			else if (Z_TYPE(opline->op1.u.constant) == IS_UNICODE) {
+				assert(!php->udirpath);
+				ZVAL_UNICODEL(&opline->op1.u.constant, php->udirpath, php->udirpath_len, copy);
+			}
+#endif
+			else {
+				assert(0);
+			}
+		}
+
+		if ((oplineinfo & xcache_op2_is_file)) {
+			assert(opline->op2.op_type == IS_CONST);
+			if (copy) {
+				efree(Z_STRVAL(opline->op2.u.constant));
+			}
+			if (Z_TYPE(opline->op2.u.constant) == IS_STRING) {
+				assert(php->filepath);
+				ZVAL_STRINGL(&opline->op2.u.constant, php->filepath, php->filepath_len, copy);
+			}
+#ifdef IS_UNICODE
+			else if (Z_TYPE(opline->op2.u.constant) == IS_UNICODE) {
+				assert(php->ufilepath);
+				ZVAL_UNICODEL(&opline->op2.u.constant, php->ufilepath, php->ufilepath_len, copy);
+			}
+#endif
+			else {
+				assert(0);
+			}
+		}
+		else if ((oplineinfo & xcache_op2_is_dir)) {
+			assert(opline->op2.op_type == IS_CONST);
+			if (copy) {
+				efree(Z_STRVAL(opline->op2.u.constant));
+			}
+			if (Z_TYPE(opline->op2.u.constant) == IS_STRING) {
+				assert(!php->dirpath);
+				ZVAL_STRINGL(&opline->op2.u.constant, php->dirpath, php->dirpath_len, copy);
+			}
+#ifdef IS_UNICODE
+			else if (Z_TYPE(opline->op2.u.constant) == IS_UNICODE) {
+				assert(!php->udirpath);
+				ZVAL_UNICODEL(&opline->op2.u.constant, php->udirpath, php->udirpath_len, copy);
+			}
+#endif
+			else {
+				assert(0);
+			}
+		}
+	}
+}
+/* }}} */
+static void xc_free_op_array_info(xc_op_array_info_t *op_array_info TSRMLS_DC) /* {{{ */
+{
+	if (op_array_info->oplineinfos) {
+		efree(op_array_info->oplineinfos);
+	}
+}
+/* }}} */
 static void xc_free_php(xc_entry_data_php_t *php TSRMLS_DC) /* {{{ */
 {
+	int i;
+	if (php->classinfos) {
+		for (i = 0; i < php->classinfo_cnt; i ++) {
+			xc_classinfo_t *classinfo = &php->classinfos[i];
+			int 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) { \
@@ -1116,4 +1316,10 @@
 } while (0)
 
+	X_FREE(dirpath);
+#ifdef IS_UNICODE
+	X_FREE(ufilepath);
+	X_FREE(udirpath);
+#endif
+
 #ifdef ZEND_ENGINE_2_1
 	X_FREE(autoglobals);
@@ -1132,4 +1338,5 @@
 	int old_constinfo_cnt, old_funcinfo_cnt, old_classinfo_cnt;
 	zend_bool catched = 0;
+	xc_const_usage_t const_usage;
 
 	/* {{{ compile */
@@ -1162,4 +1369,5 @@
 	/* }}} */
 	/* {{{ prepare */
+	zend_restore_compiled_filename(h->opened_path ? h->opened_path : h->filename TSRMLS_CC);
 	php->op_array      = op_array;
 
@@ -1206,4 +1414,16 @@
 #endif
 #undef X_ALLOC
+	/* }}} */
+
+	/* {{{ file/dir path init */
+	memset(&const_usage, 0, sizeof(const_usage));
+	php->filepath     = zend_get_compiled_filename(TSRMLS_C);
+	php->filepath_len = strlen(php->filepath);
+	php->dirpath      = estrndup(php->filepath, php->filepath_len);
+	php->dirpath_len  = zend_dirname(php->dirpath, php->filepath_len);
+#ifdef IS_UNICODE
+	zend_string_to_unicode(ZEND_U_CONVERTER(UG(runtime_encoding_conv)), &php->ufilepath, &php->ufilepath_len, php->filepath, php->filepath_len TSRMLS_CC);
+	zend_string_to_unicode(ZEND_U_CONVERTER(UG(runtime_encoding_conv)), &php->udirpath,  &php->udirpath_len,  php->dirpath,  php->dirpath_len TSRMLS_CC);
+#endif
 	/* }}} */
 	/* {{{ shallow copy, pointers only */ {
@@ -1242,4 +1462,31 @@
 		b = CG(class_table)->pListHead;    COPY_H(xc_classinfo_t, classinfos, classinfo_cnt, cest,     xc_cest_t);
 
+		for (i = 0; i < php->classinfo_cnt; i ++) {
+			xc_classinfo_t *classinfo = &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(php, &const_usage, &classinfo->methodinfos[j], (zend_op_array *) b->pData TSRMLS_CC);
+				}
+			}
+			else {
+				classinfo->methodinfos = NULL;
+			}
+		}
+
+		for (i = 0; i < php->funcinfo_cnt; i ++) {
+			xc_collect_op_array_info(php, &const_usage, &php->funcinfos[i].op_array_info, (zend_op_array *) &php->funcinfos[i].func TSRMLS_CC);
+		}
+
+		xc_collect_op_array_info(php, &const_usage, &php->op_array_info, php->op_array TSRMLS_CC);
+
 #undef COPY_H
 
@@ -1271,4 +1518,22 @@
 	}
 	/* }}} */
+	/* {{{ file/dir path free unused */
+#define X_FREE_UNUSED(var) \
+	if (!const_usage.var##path_used) { \
+		efree(php->var##path); \
+		php->var##path = NULL; \
+		php->var##path_len = 0; \
+	}
+	if (!const_usage.filepath_used) {
+		php->filepath = NULL;
+		php->filepath_len = 0;
+	}
+	X_FREE_UNUSED(dir)
+#ifdef IS_UNICODE
+	X_FREE_UNUSED(ufile)
+	X_FREE_UNUSED(udir)
+#endif
+#undef X_FREE_UNUSED
+	/* }}} */
 #ifdef E_STRICT
 	php->compilererrors = ((xc_sandbox_t *) XG(sandbox))->compilererrors;
@@ -1467,4 +1732,6 @@
 		php.autoglobals = NULL;
 #endif
+		memset(&php.op_array_info, 0, sizeof(php.op_array_info));
+
 		zend_try {
 			op_array = xc_compile_php(&php, h, type TSRMLS_CC);
@@ -1638,19 +1905,7 @@
 /* }}} */
 
-#ifdef ZEND_ENGINE_2
-/* {{{ xc_gc_op_array_t */
-typedef struct {
-	zend_uint num_args;
-	zend_arg_info *arg_info;
-} xc_gc_op_array_t;
-/* }}} */
-void xc_gc_add_op_array(zend_op_array *op_array TSRMLS_DC) /* {{{ */
-{
-	xc_gc_op_array_t gc_op_array;
-	gc_op_array.num_args = op_array->num_args;
-	gc_op_array.arg_info = op_array->arg_info;
-#ifdef ZEND_ENGINE_2
-	zend_llist_add_element(&XG(gc_op_arrays), (void *) &gc_op_array);
-#endif
+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);
 }
 /* }}} */
@@ -1659,4 +1914,5 @@
 	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++) {
@@ -1668,7 +1924,10 @@
 		efree(op_array->arg_info);
 	}
-}
-/* }}} */
-#endif
+#endif
+	if (op_array->opcodes) {
+		efree(op_array->opcodes);
+	}
+}
+/* }}} */
 
 /* module helper function */
