Index: /trunk/coverager.c
===================================================================
--- /trunk/coverager.c	(revision 211)
+++ /trunk/coverager.c	(revision 212)
@@ -147,9 +147,11 @@
 			for (; len >= sizeof(long) * 2; len -= sizeof(long) * 2, p += 2) {
 				if (zend_hash_index_find(cov, p[0], (void**)&phits) == SUCCESS) {
-					if (p[1] == 0) {
+					if (p[1] == -1) {
 						/* OPTIMIZE: already marked */
 						continue;
 					}
-					p[1] += *phits;
+					if (*phits != -1) {
+						p[1] += *phits;
+					}
 				}
 				zend_hash_index_update(cov, p[0], &p[1], sizeof(p[1]), NULL);
@@ -219,6 +221,6 @@
 				long hits = *phits;
 
-				if (hits != 0) {
-					hits = 0;
+				if (hits != -1) {
+					hits = -1;
 					zend_hash_index_update(cov, pos2->h, &hits, sizeof(hits), NULL);
 				}
@@ -377,9 +379,11 @@
 	}
 	if (zend_hash_index_find(cov, line, (void**)&poldhits) == SUCCESS) {
-		if (hits == 0) {
-			/* OPTIMIZE: already marked */
+		if (hits == -1) {
+			/* OPTIMIZE: -1 == init-ing, but it's already initized */
 			return;
 		}
-		hits += *poldhits;
+		if (*poldhits != -1) {
+			hits += *poldhits;
+		}
 	}
 	zend_hash_index_update(cov, line, &hits, sizeof(hits), NULL);
@@ -430,5 +434,5 @@
 			case ZEND_EXT_FCALL_END:
 #endif
-				xc_coverager_add_hits(cov, op_array->opcodes[i].lineno, 0 TSRMLS_CC);
+				xc_coverager_add_hits(cov, op_array->opcodes[i].lineno, -1 TSRMLS_CC);
 				break;
 		}
Index: /trunk/processor/processor.m4
===================================================================
--- /trunk/processor/processor.m4	(revision 211)
+++ /trunk/processor/processor.m4	(revision 212)
@@ -474,5 +474,8 @@
 DEF_STRUCT_P_FUNC(`zend_op_array', , `dnl {{{
 	IFRESTORE(`
-	if (!processor->readonly_protection) {
+	dnl shadow copy must NOT meet:
+	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)) {
 		/* really fast shallow copy */
 		memcpy(dst, src, sizeof(src[0]));
@@ -685,4 +688,5 @@
 	STRUCT(zend_class_entry, cest)
 #endif
+	DISPATCH(int, oplineno)
 ')
 dnl }}}
@@ -715,4 +719,5 @@
 	')
 	STRUCT_ARRAY(classinfo_cnt, xc_classinfo_t, classinfos)
+	DISPATCH(zend_bool, have_early_binding)
 	popdef(`BEFORE_LOOP')
 ')
Index: /trunk/utils.c
===================================================================
--- /trunk/utils.c	(revision 211)
+++ /trunk/utils.c	(revision 212)
@@ -1,3 +1,3 @@
-#include "php.h"
+
 #include "xcache.h"
 #include "utils.h"
@@ -9,4 +9,12 @@
 #include "assert.h"
 
+#ifndef ZEND_VM_SET_OPCODE_HANDLER
+#	define ZEND_VM_SET_OPCODE_HANDLER(opline) do { } while (0)
+#endif
+
+#define OP_ZVAL_DTOR(op) do { \
+	(op).u.constant.is_ref = 0; \
+	zval_dtor(&(op).u.constant); \
+} while(0)
 xc_compile_result_t *xc_compile_result_init(xc_compile_result_t *cr, /* {{{ */
 		zend_op_array *op_array,
@@ -264,4 +272,120 @@
 /* }}} */
 #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;
+	xc_cest_t cest;
+
+	opline = begin = op_array->opcodes;
+	end = opline + op_array->last;
+	while (opline < end) {
+		switch (opline->opcode) {
+			case ZEND_JMP:
+				next = begin + opline->op1.u.opline_num;
+				break;
+
+			case ZEND_JMPZNZ:
+				next = begin + max(opline->op2.u.opline_num, opline->extended_value);
+				break;
+
+			case ZEND_JMPZ:
+			case ZEND_JMPNZ:
+			case ZEND_JMPZ_EX:
+			case ZEND_JMPNZ_EX:
+				next = begin + opline->op2.u.opline_num;
+				break;
+
+			case ZEND_RETURN:
+				opline = end;
+				break;
+
+			case ZEND_DECLARE_INHERITED_CLASS:
+				callback(opline, opline - begin, data TSRMLS_CC);
+				break;
+		}
+
+		if (opline < next) {
+			opline = next;
+		}
+		else {
+			opline ++;
+		}
+	}
+}
+/* }}} */
+int xc_do_early_binding(zend_op_array *op_array, HashTable *class_table, int oplineno TSRMLS_DC) /* {{{ */
+{
+	zend_op *opline, *opcodes;
+
+#ifdef DEBUG
+	fprintf(stderr, "binding %d\n", oplineno);
+#endif
+	assert(oplineno >= 0);
+
+	/* do early binding */
+	opline = &(op_array->opcodes[oplineno]);
+
+	switch (opline->opcode) {
+	case ZEND_DECLARE_INHERITED_CLASS:
+#ifdef ZEND_ENGINE_2
+		{
+			zval *parent_name;
+			zend_class_entry **pce;
+			parent_name = &(opline - 1)->op2.u.constant;
+#ifdef DEBUG
+			fprintf(stderr, "binding with parent %s\n", Z_STRVAL_P(parent_name));
+#endif
+			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;
+			}
+		}
+#else
+		if (do_bind_function_or_class(opline, NULL, class_table, 1) == FAILURE) {
+			return FAILURE;
+		}
+#endif
+
+#ifdef ZEND_FETCH_CLASS
+		/* clear unnecessary ZEND_FETCH_CLASS opcode */
+		if (opline > op_array->opcodes
+		 && (opline - 1)->opcode == ZEND_FETCH_CLASS) {
+			zend_op *fetch_class_opline = opline - 1;
+
+#ifdef DEBUG
+			fprintf(stderr, "%s %p\n", Z_STRVAL(fetch_class_opline->op2.u.constant), Z_STRVAL(fetch_class_opline->op2.u.constant));
+#endif
+			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);
+		}
+#endif
+		break;
+
+	default:
+		return FAILURE;
+	}
+
+	zend_hash_del(class_table, opline->op1.u.constant.value.str.val, opline->op1.u.constant.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;
+}
+/* }}} */
 
 #ifdef HAVE_XCACHE_CONSTANT
@@ -320,5 +444,5 @@
 }
 /* }}} */
-ZESW(xc_cest_t *, void) xc_install_class(char *filename, xc_cest_t *cest, zend_uchar type, zstr key, uint len TSRMLS_DC) /* {{{ */
+ZESW(xc_cest_t *, void) xc_install_class(char *filename, xc_cest_t *cest, int oplineno, zend_uchar type, zstr key, uint len TSRMLS_DC) /* {{{ */
 {
 	zend_bool istmpkey;
@@ -336,4 +460,7 @@
 					ZESW(&stored_ce_ptr, NULL)
 					);
+		if (oplineno != -1) {
+			xc_do_early_binding(CG(active_op_array), CG(class_table), oplineno TSRMLS_CC);
+		}
 	}
 	else if (zend_u_hash_add(CG(class_table), type, key, len,
@@ -349,4 +476,5 @@
 		zend_error(E_ERROR, "Cannot redeclare class %s", cep->name);
 #endif
+		assert(oplineno == -1);
 	}
 	ZESW(return (xc_cest_t *) stored_ce_ptr, NOTHING);
@@ -403,4 +531,10 @@
 
 	return sandbox;
+}
+/* }}} */
+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);
 }
 /* }}} */
@@ -433,8 +567,11 @@
 	/* install class */
 	while (b != NULL) {
-		xc_install_class(sandbox->filename, (xc_cest_t*) b->pData,
+		xc_install_class(sandbox->filename, (xc_cest_t*) b->pData, -1,
 				BUCKET_KEY_TYPE(b), ZSTR(BUCKET_KEY_S(b)), b->nKeyLength TSRMLS_CC);
 		b = b->pListNext;
 	}
+	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);
 
 	i = 1;
Index: /trunk/utils.h
===================================================================
--- /trunk/utils.h	(revision 211)
+++ /trunk/utils.h	(revision 212)
@@ -25,4 +25,6 @@
 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
@@ -30,5 +32,5 @@
 #endif
 void xc_install_function(char *filename, zend_function *func, zend_uchar type, zstr key, uint len TSRMLS_DC);
-ZESW(xc_cest_t *, void) xc_install_class(char *filename, xc_cest_t *cest, zend_uchar type, zstr key, uint len TSRMLS_DC);
+ZESW(xc_cest_t *, void) xc_install_class(char *filename, xc_cest_t *cest, int oplineno, zend_uchar type, zstr key, uint len TSRMLS_DC);
 
 /* sandbox */
Index: /trunk/xcache.c
===================================================================
--- /trunk/xcache.c	(revision 211)
+++ /trunk/xcache.c	(revision 212)
@@ -66,4 +66,8 @@
 	} \
 } while(0)
+
+#ifndef max
+#define max(a, b) ((a) < (b) ? (b) : (a))
+#endif
 
 /* }}} */
@@ -542,4 +546,6 @@
 #endif
 
+	CG(active_op_array) = p->op_array;
+
 #ifdef HAVE_XCACHE_CONSTANT
 	/* install constant */
@@ -571,5 +577,5 @@
 		new_cest_ptrs[i] =
 #endif
-		xc_install_class(xce->name.str.val, &ci->cest,
+		xc_install_class(xce->name.str.val, &ci->cest, ci->oplineno,
 				UNISW(0, ci->type), ci->key, ci->key_size TSRMLS_CC);
 	}
@@ -771,4 +777,33 @@
 	xce->type = XC_TYPE_PHP;
 	return 1;
+}
+/* }}} */
+static void xc_cache_early_binding_class_cb(zend_op *opline, int oplineno, void *data TSRMLS_DC) /* {{{ */
+{
+	char *class_name;
+	int i, class_len;
+	xc_cest_t cest;
+	xc_entry_data_php_t *php = (xc_entry_data_php_t *) data;
+
+	class_name = opline->op1.u.constant.value.str.val;
+	class_len  = opline->op1.u.constant.value.str.len;
+	if (zend_hash_find(CG(class_table), class_name, class_len, (void **) &cest) == FAILURE) {
+		assert(0);
+	}
+#ifdef DEBUG
+	fprintf(stderr, "got ZEND_DECLARE_INHERITED_CLASS: %s\n", class_name + 1);
+#endif
+	/* 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);
+	}
 }
 /* }}} */
@@ -785,4 +820,5 @@
 	char opened_path_buffer[MAXPATHLEN];
 	int old_constinfo_cnt, old_funcinfo_cnt, old_classinfo_cnt;
+	int i;
 
 	if (!xc_initized) {
@@ -895,5 +931,4 @@
 #ifdef HAVE_INODE
 	if (xce.data.php->inode)
-#endif
 	{
 		if (xce.name.str.val != filename) {
@@ -902,4 +937,5 @@
 		}
 	}
+#endif
 
 #ifdef HAVE_XCACHE_OPTIMIZER
@@ -908,5 +944,6 @@
 	}
 #endif
-
+	/* }}} */
+	/* {{{ prepare */
 	php.op_array      = op_array;
 
@@ -972,4 +1009,14 @@
 	}
 	/* }}} */
+	/* {{{ 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);
+	/* }}} */
 	ENTER_LOCK_EX(cache) { /* {{{ store/add entry */
 		stored_xce = xc_entry_store_dmz(&xce TSRMLS_CC);
@@ -1001,4 +1048,5 @@
 	}
 	else {
+		CG(active_op_array) = op_array;
 		xc_sandbox_free(&sandbox, 1 TSRMLS_CC);
 	}
Index: /trunk/xcache.h
===================================================================
--- /trunk/xcache.h	(revision 211)
+++ /trunk/xcache.h	(revision 212)
@@ -169,4 +169,5 @@
 	zend_uint key_size;
 	xc_cest_t cest;
+	int       oplineno;
 } xc_classinfo_t;
 /* }}} */
@@ -215,4 +216,5 @@
 	zend_uint classinfo_cnt;
 	xc_classinfo_t *classinfos;
+	zend_bool have_early_binding;
 } xc_entry_data_php_t;
 /* }}} */
