summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikita Popov <nikic@php.net>2015-05-22 22:17:40 +0200
committerNikita Popov <nikic@php.net>2015-05-23 10:51:33 +0200
commit7a88d16cf318c877d56c71756da95b57249c134a (patch)
treee54e2c2d3ef60570213b0f33f19aa1d94d7177f7
parent9325ada7253efb330e4fd79579d6e6fc0334d7b2 (diff)
downloadphp-git-7a88d16cf318c877d56c71756da95b57249c134a.tar.gz
Use ZEND_JMP instead of ZEND_BRK/ZEND_CONT
Emit necessary FREEs during compilation, convert to JMP during pass_two (we may not know target opline beforehand).
-rw-r--r--Zend/zend_compile.c7
-rw-r--r--Zend/zend_opcode.c42
2 files changed, 33 insertions, 16 deletions
diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c
index 2ea4451b09..3c23888aa9 100644
--- a/Zend/zend_compile.c
+++ b/Zend/zend_compile.c
@@ -3557,6 +3557,7 @@ void zend_compile_break_continue(zend_ast *ast) /* {{{ */
} else {
int array_offset = CG(context).current_brk_cont;
zend_long nest_level = depth;
+ znode *loop_var = zend_stack_top(&CG(loop_var_stack));
do {
if (array_offset == -1) {
@@ -3564,6 +3565,12 @@ void zend_compile_break_continue(zend_ast *ast) /* {{{ */
ast->kind == ZEND_AST_BREAK ? "break" : "continue",
depth, depth == 1 ? "" : "s");
}
+
+ if (nest_level > 1 && CG(active_op_array)->brk_cont_array[array_offset].start >= 0) {
+ generate_free_loop_var(loop_var);
+ loop_var--;
+ }
+
array_offset = CG(active_op_array)->brk_cont_array[array_offset].parent;
} while (--nest_level > 0);
}
diff --git a/Zend/zend_opcode.c b/Zend/zend_opcode.c
index 933c75a706..7365d6a518 100644
--- a/Zend/zend_opcode.c
+++ b/Zend/zend_opcode.c
@@ -666,6 +666,20 @@ static void zend_resolve_finally_ret(zend_op_array *op_array, uint32_t op_num)
}
}
+static uint32_t zend_get_brk_cont_target(const zend_op_array *op_array, const zend_op *opline) {
+ int nest_levels = opline->op2.num;
+ int array_offset = opline->op1.num;
+ zend_brk_cont_element *jmp_to;
+ do {
+ jmp_to = &op_array->brk_cont_array[array_offset];
+ if (nest_levels > 1) {
+ array_offset = jmp_to->parent;
+ }
+ } while (--nest_levels > 0);
+
+ return opline->opcode == ZEND_BRK ? jmp_to->brk : jmp_to->cont;
+}
+
static void zend_resolve_finally_calls(zend_op_array *op_array)
{
uint32_t i, j;
@@ -681,22 +695,8 @@ static void zend_resolve_finally_calls(zend_op_array *op_array)
break;
case ZEND_BRK:
case ZEND_CONT:
- {
- int nest_levels = opline->op2.num;
- int array_offset = opline->op1.num;
- zend_brk_cont_element *jmp_to;
-
- if (array_offset != -1) {
- do {
- jmp_to = &op_array->brk_cont_array[array_offset];
- if (nest_levels > 1) {
- array_offset = jmp_to->parent;
- }
- } while (--nest_levels > 0);
- zend_resolve_finally_call(op_array, i, opline->opcode == ZEND_BRK ? jmp_to->brk : jmp_to->cont);
- break;
- }
- }
+ zend_resolve_finally_call(op_array, i, zend_get_brk_cont_target(op_array, opline));
+ break;
case ZEND_GOTO:
if (Z_TYPE_P(CT_CONSTANT_EX(op_array, opline->op2.constant)) != IS_LONG) {
uint32_t num = opline->op2.constant;
@@ -774,6 +774,16 @@ ZEND_API int pass_two(zend_op_array *op_array)
case ZEND_DECLARE_INHERITED_CLASS_DELAYED:
opline->extended_value = (uint32_t)(zend_intptr_t)ZEND_CALL_VAR_NUM(NULL, op_array->last_var + opline->extended_value);
break;
+ case ZEND_BRK:
+ case ZEND_CONT:
+ {
+ uint32_t jmp_target = zend_get_brk_cont_target(op_array, opline);
+ opline->opcode = ZEND_JMP;
+ opline->op1.opline_num = jmp_target;
+ opline->op2.num = 0;
+ ZEND_PASS_TWO_UPDATE_JMP_TARGET(op_array, opline, opline->op1);
+ }
+ break;
case ZEND_GOTO:
if (Z_TYPE_P(RT_CONSTANT(op_array, opline->op2)) != IS_LONG) {
zend_resolve_goto_label(op_array, opline, 1);