Index: trunk/optimizer.c
===================================================================
--- trunk/optimizer.c	(revision 822)
+++ trunk/optimizer.c	(revision 834)
@@ -57,4 +57,5 @@
 {
 	int i;
+	zend_bool preserve_brk_cont_array = 0;
 
 	if (op_array->brk_cont_array == NULL) {
@@ -65,9 +66,22 @@
 		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;
 
-		if (opline->opcode != ZEND_BRK && opline->opcode != ZEND_CONT) {
+		switch (opline->opcode) {
+		case ZEND_BRK:
+		case ZEND_CONT:
+			break;
+
+#ifdef ZEND_GOTO
+		case ZEND_GOTO:
+			preserve_brk_cont_array = 1;
 			continue;
-		}
+#endif
+
+		default:
+			continue;
+		}
+
 		if (Z_OP_TYPE(opline->op2) != IS_CONST
 		 || Z_OP_CONSTANT(opline->op2).type != IS_LONG) {
@@ -92,6 +106,9 @@
 				switch (brk_opline->opcode) {
 				case ZEND_SWITCH_FREE:
-					break;
 				case ZEND_FREE:
+					if (!(brk_opline->extended_value & EXT_TYPE_FREE_ON_RETURN)) {
+						can_convert = 0;
+						preserve_brk_cont_array = 1;
+					}
 					break;
 				}
@@ -100,20 +117,27 @@
 		} while (--nest_levels > 0);
 
-		/* rewrite to jmp */
-		if (opline->opcode == ZEND_BRK) {
-			Z_OP(opline->op1).opline_num = jmp_to->brk;
-		}
-		else {
-			Z_OP(opline->op1).opline_num = jmp_to->cont;
-		}
-		Z_OP_TYPE(opline->op2) = IS_UNUSED;
-		opline->opcode = ZEND_JMP;
-	}
-
-	if (op_array->brk_cont_array != NULL) {
-		efree(op_array->brk_cont_array);
-		op_array->brk_cont_array = NULL;
-	}
-	op_array->last_brk_cont = 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;
+		}
+	}
+
+	if (!preserve_brk_cont_array) {
+		if (op_array->brk_cont_array != NULL) {
+			efree(op_array->brk_cont_array);
+			op_array->brk_cont_array = NULL;
+		}
+		op_array->last_brk_cont = 0;
+	}
 	return SUCCESS;
 }
