Changed ZEND_FREE.op2.num and ZEND_FE_FREE.op2.num back to use live_range_offset (try_catch_offset does't work)

This commit is contained in:
Dmitry Stogov 2015-11-11 11:12:44 +03:00
parent cd6dda1679
commit 948b7f5421
12 changed files with 192 additions and 51 deletions

View File

@ -0,0 +1,27 @@
--TEST--
Live range & free on return
--FILE--
<?php
class bar {
public $foo = 1;
public $bar = 1;
function __destruct() {
throw $this->foo;
}
}
foreach (new bar as &$foo) {
try {
$foo = new Exception;
return; // frees the loop variable
} catch (Exception $e) {
echo "exception\n";
}
}
echo "end\n";
?>
--EXPECTF--
Fatal error: Uncaught Exception in %stemporary_cleaning_009.php:12
Stack trace:
#0 {main}
thrown in %stemporary_cleaning_009.php on line 12

View File

@ -0,0 +1,23 @@
--TEST--
Live range & throw from finally
--XFAIL--
See Bug #62210 and attempt to fix it in "tmp_livelibess" branch
--FILE--
<?php
function test() {
try {
$a = [1, 2, 3];
return $a + [];
} finally {
throw new Exception;
}
}
try {
test();
} catch (Exception $e) {
echo "exception\n";
}
?>
--EXPECT--
exception

View File

@ -0,0 +1,20 @@
--TEST--
Live range & return from finally
--FILE--
<?php
$array = [1];
foreach ([0] as $_) {
foreach ($array as $v) {
try {
echo "ok\n";
return;
} finally {
echo "ok\n";
return;
}
}
}
?>
--EXPECT--
ok
ok

View File

@ -0,0 +1,41 @@
--TEST--
Try finally (exception in "return" statement)
--FILE--
<?php
class A {
public $x = 1;
public $y = 2;
function __destruct() {
throw new Exception();
}
}
try{
$a = 0;
switch ($a) {
case 0:
}
switch ($a) {
case 0:
}
switch ($a) {
case 0:
}
foreach([new stdClass()] as $x) {
foreach(new A() as $a) {
foreach([new stdClass()] as $y) {
try {
if (0) { echo "0" . (int)5; }
return $a;
} catch (Exception $e) {
echo "exception1\n";
}
}
}
}
} catch (Exception $e) {
echo "exception2\n";
}
?>
--EXPECT--
exception2

View File

@ -58,7 +58,10 @@ typedef struct _zend_loop_var {
zend_uchar opcode; zend_uchar opcode;
zend_uchar var_type; zend_uchar var_type;
uint32_t var_num; uint32_t var_num;
uint32_t try_catch_offset; union {
uint32_t try_catch_offset;
uint32_t live_range_offset;
} u;
} zend_loop_var; } zend_loop_var;
static inline void zend_alloc_cache_slot(uint32_t literal) { static inline void zend_alloc_cache_slot(uint32_t literal) {
@ -573,15 +576,25 @@ void zend_stop_lexing(void)
LANG_SCNG(yy_cursor) = LANG_SCNG(yy_limit); LANG_SCNG(yy_cursor) = LANG_SCNG(yy_limit);
} }
static void zend_add_live_range(zend_op_array *op_array, uint32_t start, uint32_t end) /* {{{ */ static uint32_t zend_start_live_range(zend_op_array *op_array, uint32_t start) /* {{{ */
{ {
zend_live_range *range; zend_live_range *range;
if (start != end) { op_array->last_live_range++;
op_array->last_live_range++; op_array->live_range = erealloc(op_array->live_range, sizeof(zend_live_range) * op_array->last_live_range);
op_array->live_range = erealloc(op_array->live_range, sizeof(zend_live_range) * op_array->last_live_range); range = op_array->live_range + op_array->last_live_range - 1;
range = op_array->live_range + op_array->last_live_range - 1; range->start = start;
range->start = start; return op_array->last_live_range - 1;
}
/* }}} */
static void zend_end_live_range(zend_op_array *op_array, uint32_t offset, uint32_t end) /* {{{ */
{
zend_live_range *range = op_array->live_range + offset;
if (range->start == end && offset == op_array->last_live_range - 1) {
op_array->last_live_range--;
} else {
range->end = end; range->end = end;
} }
} }
@ -598,11 +611,13 @@ static inline void zend_begin_loop(zend_uchar free_opcode, const znode *loop_var
brk_cont_element->parent = parent; brk_cont_element->parent = parent;
if (loop_var && (loop_var->op_type & (IS_VAR|IS_TMP_VAR))) { if (loop_var && (loop_var->op_type & (IS_VAR|IS_TMP_VAR))) {
uint32_t start = get_next_op_number(CG(active_op_array));
info.opcode = free_opcode; info.opcode = free_opcode;
info.var_type = loop_var->op_type; info.var_type = loop_var->op_type;
info.var_num = loop_var->u.op.var; info.var_num = loop_var->u.op.var;
info.try_catch_offset = CG(active_op_array)->last_try_catch; info.u.live_range_offset = zend_start_live_range(CG(active_op_array), start);
brk_cont_element->start = get_next_op_number(CG(active_op_array)); brk_cont_element->start = start;
} else { } else {
info.opcode = ZEND_NOP; info.opcode = ZEND_NOP;
/* The start field is used to free temporary variables in case of exceptions. /* The start field is used to free temporary variables in case of exceptions.
@ -616,12 +631,18 @@ static inline void zend_begin_loop(zend_uchar free_opcode, const znode *loop_var
static inline void zend_end_loop(int cont_addr) /* {{{ */ static inline void zend_end_loop(int cont_addr) /* {{{ */
{ {
uint32_t end = get_next_op_number(CG(active_op_array));
zend_brk_cont_element *brk_cont_element zend_brk_cont_element *brk_cont_element
= &CG(context).brk_cont_array[CG(context).current_brk_cont]; = &CG(context).brk_cont_array[CG(context).current_brk_cont];
brk_cont_element->cont = cont_addr; brk_cont_element->cont = cont_addr;
brk_cont_element->brk = get_next_op_number(CG(active_op_array)); brk_cont_element->brk = end;
CG(context).current_brk_cont = brk_cont_element->parent; CG(context).current_brk_cont = brk_cont_element->parent;
if (brk_cont_element->start != -1) {
zend_loop_var *loop_var = zend_stack_top(&CG(loop_var_stack));
zend_end_live_range(CG(active_op_array), loop_var->u.live_range_offset, end);
}
zend_stack_del_top(&CG(loop_var_stack)); zend_stack_del_top(&CG(loop_var_stack));
} }
/* }}} */ /* }}} */
@ -3591,7 +3612,7 @@ static int zend_handle_loops_and_finally_ex(zend_long depth) /* {{{ */
opline->result.var = loop_var->var_num; opline->result.var = loop_var->var_num;
SET_UNUSED(opline->op1); SET_UNUSED(opline->op1);
SET_UNUSED(opline->op2); SET_UNUSED(opline->op2);
opline->op1.num = loop_var->try_catch_offset; opline->op1.num = loop_var->u.try_catch_offset;
} else if (loop_var->opcode == ZEND_RETURN) { } else if (loop_var->opcode == ZEND_RETURN) {
/* Stack separator */ /* Stack separator */
break; break;
@ -3609,7 +3630,7 @@ static int zend_handle_loops_and_finally_ex(zend_long depth) /* {{{ */
opline->op1_type = loop_var->var_type; opline->op1_type = loop_var->var_type;
opline->op1.var = loop_var->var_num; opline->op1.var = loop_var->var_num;
SET_UNUSED(opline->op2); SET_UNUSED(opline->op2);
opline->op2.num = loop_var->try_catch_offset; opline->op2.num = loop_var->u.live_range_offset;
opline->extended_value = ZEND_FREE_ON_RETURN; opline->extended_value = ZEND_FREE_ON_RETURN;
depth--; depth--;
} }
@ -4010,8 +4031,6 @@ void zend_compile_foreach(zend_ast *ast) /* {{{ */
zend_end_loop(opnum_fetch); zend_end_loop(opnum_fetch);
opline = zend_emit_op(NULL, ZEND_FE_FREE, &reset_node, NULL); opline = zend_emit_op(NULL, ZEND_FE_FREE, &reset_node, NULL);
zend_add_live_range(CG(active_op_array),
opnum_fetch, opline - CG(active_op_array)->opcodes);
} }
/* }}} */ /* }}} */
@ -4068,11 +4087,10 @@ void zend_compile_switch(zend_ast *ast) /* {{{ */
znode expr_node, case_node; znode expr_node, case_node;
zend_op *opline; zend_op *opline;
uint32_t *jmpnz_opnums = safe_emalloc(sizeof(uint32_t), cases->children, 0); uint32_t *jmpnz_opnums = safe_emalloc(sizeof(uint32_t), cases->children, 0);
uint32_t opnum_default_jmp, opnum_start; uint32_t opnum_default_jmp;
zend_compile_expr(&expr_node, expr_ast); zend_compile_expr(&expr_node, expr_ast);
opnum_start = get_next_op_number(CG(active_op_array));
zend_begin_loop(ZEND_FREE, &expr_node); zend_begin_loop(ZEND_FREE, &expr_node);
case_node.op_type = IS_TMP_VAR; case_node.op_type = IS_TMP_VAR;
@ -4136,8 +4154,6 @@ void zend_compile_switch(zend_ast *ast) /* {{{ */
if (expr_node.op_type == IS_VAR || expr_node.op_type == IS_TMP_VAR) { if (expr_node.op_type == IS_VAR || expr_node.op_type == IS_TMP_VAR) {
opline = zend_emit_op(NULL, ZEND_FREE, &expr_node, NULL); opline = zend_emit_op(NULL, ZEND_FREE, &expr_node, NULL);
zend_add_live_range(CG(active_op_array),
opnum_start, opline - CG(active_op_array)->opcodes);
} else if (expr_node.op_type == IS_CONST) { } else if (expr_node.op_type == IS_CONST) {
zval_dtor(&expr_node.u.constant); zval_dtor(&expr_node.u.constant);
} }
@ -4185,7 +4201,7 @@ void zend_compile_try(zend_ast *ast) /* {{{ */
fast_call.opcode = ZEND_FAST_CALL; fast_call.opcode = ZEND_FAST_CALL;
fast_call.var_type = IS_TMP_VAR; fast_call.var_type = IS_TMP_VAR;
fast_call.var_num = CG(context).fast_call_var; fast_call.var_num = CG(context).fast_call_var;
fast_call.try_catch_offset = try_catch_offset; fast_call.u.try_catch_offset = try_catch_offset;
zend_stack_push(&CG(loop_var_stack), &fast_call); zend_stack_push(&CG(loop_var_stack), &fast_call);
} }
@ -6451,10 +6467,9 @@ void zend_compile_silence(znode *result, zend_ast *ast) /* {{{ */
{ {
zend_ast *expr_ast = ast->child[0]; zend_ast *expr_ast = ast->child[0];
znode silence_node; znode silence_node;
uint32_t begin_opline_num; uint32_t range;
zend_op *opline;
begin_opline_num = get_next_op_number(CG(active_op_array)); range = zend_start_live_range(CG(active_op_array), get_next_op_number(CG(active_op_array)));
zend_emit_op_tmp(&silence_node, ZEND_BEGIN_SILENCE, NULL, NULL); zend_emit_op_tmp(&silence_node, ZEND_BEGIN_SILENCE, NULL, NULL);
if (expr_ast->kind == ZEND_AST_VAR) { if (expr_ast->kind == ZEND_AST_VAR) {
@ -6465,12 +6480,11 @@ void zend_compile_silence(znode *result, zend_ast *ast) /* {{{ */
zend_compile_expr(result, expr_ast); zend_compile_expr(result, expr_ast);
} }
opline = zend_emit_op(NULL, ZEND_END_SILENCE, &silence_node, NULL);
/* Store BEGIN_SILENCE/END_SILENCE pair to restore previous /* Store BEGIN_SILENCE/END_SILENCE pair to restore previous
* EG(error_reporting) value on exception */ * EG(error_reporting) value on exception */
zend_add_live_range(CG(active_op_array), zend_end_live_range(CG(active_op_array), range, get_next_op_number(CG(active_op_array)));
begin_opline_num + 1, opline - CG(active_op_array)->opcodes);
zend_emit_op(NULL, ZEND_END_SILENCE, &silence_node, NULL);
} }
/* }}} */ /* }}} */
@ -6790,6 +6804,7 @@ static void zend_compile_encaps_list(znode *result, zend_ast *ast) /* {{{ */
GET_NODE(result, opline->result); GET_NODE(result, opline->result);
} else { } else {
uint32_t var; uint32_t var;
uint32_t range = zend_start_live_range(CG(active_op_array), rope_init_lineno);
init_opline->extended_value = j; init_opline->extended_value = j;
opline->opcode = ZEND_ROPE_END; opline->opcode = ZEND_ROPE_END;
@ -6804,8 +6819,7 @@ static void zend_compile_encaps_list(znode *result, zend_ast *ast) /* {{{ */
i--; i--;
} }
zend_add_live_range(CG(active_op_array), zend_end_live_range(CG(active_op_array), range, opline - CG(active_op_array)->opcodes);
rope_init_lineno, opline - CG(active_op_array)->opcodes);
/* Update all the previous opcodes to use the same variable */ /* Update all the previous opcodes to use the same variable */
while (opline != init_opline) { while (opline != init_opline) {

View File

@ -2549,16 +2549,12 @@ static void cleanup_live_vars(zend_execute_data *execute_data, uint32_t op_num,
{ {
int i; int i;
i = EX(func)->op_array.last_live_range; for (i = 0; i < EX(func)->op_array.last_live_range; i++) {
while (i) { const zend_live_range *range = &EX(func)->op_array.live_range[i];
const zend_live_range *range; if (range->start > op_num) {
i--;
range = &EX(func)->op_array.live_range[i];
if (range->end <= op_num) {
/* further blocks will not be relevant... */ /* further blocks will not be relevant... */
break; break;
} else if (op_num >= range->start) { } else if (op_num < range->end) {
if (!catch_op_num || catch_op_num >= range->end) { if (!catch_op_num || catch_op_num >= range->end) {
zend_op *opline = &EX(func)->op_array.opcodes[range->end]; zend_op *opline = &EX(func)->op_array.opcodes[range->end];
uint32_t var_num = opline->op1.var; uint32_t var_num = opline->op1.var;

View File

@ -2711,7 +2711,7 @@ ZEND_VM_HANDLER(47, ZEND_JMPNZ_EX, CONST|TMPVAR|CV, JMP_ADDR)
ZEND_VM_JMP(opline); ZEND_VM_JMP(opline);
} }
ZEND_VM_HANDLER(70, ZEND_FREE, TMPVAR, TRY_CATCH) ZEND_VM_HANDLER(70, ZEND_FREE, TMPVAR, LIVE_RANGE)
{ {
USE_OPLINE USE_OPLINE
@ -2720,7 +2720,7 @@ ZEND_VM_HANDLER(70, ZEND_FREE, TMPVAR, TRY_CATCH)
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
} }
ZEND_VM_HANDLER(127, ZEND_FE_FREE, TMPVAR, TRY_CATCH) ZEND_VM_HANDLER(127, ZEND_FE_FREE, TMPVAR, LIVE_RANGE)
{ {
zval *var; zval *var;
USE_OPLINE USE_OPLINE
@ -7231,7 +7231,6 @@ ZEND_VM_HANDLER(155, ZEND_BIND_TRAITS, ANY, ANY)
ZEND_VM_HANDLER(149, ZEND_HANDLE_EXCEPTION, ANY, ANY) ZEND_VM_HANDLER(149, ZEND_HANDLE_EXCEPTION, ANY, ANY)
{ {
uint32_t op_num = EG(opline_before_exception) - EX(func)->op_array.opcodes; uint32_t op_num = EG(opline_before_exception) - EX(func)->op_array.opcodes;
uint32_t last_try_catch = EX(func)->op_array.last_try_catch;
int i; int i;
uint32_t catch_op_num = 0, finally_op_num = 0, finally_op_end = 0; uint32_t catch_op_num = 0, finally_op_num = 0, finally_op_end = 0;
int in_finally = 0; int in_finally = 0;
@ -7243,14 +7242,14 @@ ZEND_VM_HANDLER(149, ZEND_HANDLE_EXCEPTION, ANY, ANY)
if ((exc_opline->opcode == ZEND_FREE || exc_opline->opcode == ZEND_FE_FREE) if ((exc_opline->opcode == ZEND_FREE || exc_opline->opcode == ZEND_FE_FREE)
&& exc_opline->extended_value & ZEND_FREE_ON_RETURN) { && exc_opline->extended_value & ZEND_FREE_ON_RETURN) {
/* exceptions thrown because of loop var destruction on return/break/... /* exceptions thrown because of loop var destruction on return/break/...
* are logically thrown at the end of the foreach loop, * are logically thrown at the end of the foreach loop, so adjust the
* so don't check the inner exception regions * op_num.
*/ */
last_try_catch = exc_opline->op2.num; op_num = EX(func)->op_array.live_range[exc_opline->op2.num].end;
} }
} }
for (i = 0; i < last_try_catch; i++) { for (i = 0; i < EX(func)->op_array.last_try_catch; i++) {
if (EX(func)->op_array.try_catch_array[i].try_op > op_num) { if (EX(func)->op_array.try_catch_array[i].try_op > op_num) {
/* further blocks will not be relevant... */ /* further blocks will not be relevant... */
break; break;

View File

@ -1476,7 +1476,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_BIND_TRAITS_SPEC_HANDLER(ZEND_
static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_HANDLE_EXCEPTION_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_HANDLE_EXCEPTION_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{ {
uint32_t op_num = EG(opline_before_exception) - EX(func)->op_array.opcodes; uint32_t op_num = EG(opline_before_exception) - EX(func)->op_array.opcodes;
uint32_t last_try_catch = EX(func)->op_array.last_try_catch;
int i; int i;
uint32_t catch_op_num = 0, finally_op_num = 0, finally_op_end = 0; uint32_t catch_op_num = 0, finally_op_num = 0, finally_op_end = 0;
int in_finally = 0; int in_finally = 0;
@ -1488,14 +1487,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_HANDLE_EXCEPTION_SPEC_HANDLER(
if ((exc_opline->opcode == ZEND_FREE || exc_opline->opcode == ZEND_FE_FREE) if ((exc_opline->opcode == ZEND_FREE || exc_opline->opcode == ZEND_FE_FREE)
&& exc_opline->extended_value & ZEND_FREE_ON_RETURN) { && exc_opline->extended_value & ZEND_FREE_ON_RETURN) {
/* exceptions thrown because of loop var destruction on return/break/... /* exceptions thrown because of loop var destruction on return/break/...
* are logically thrown at the end of the foreach loop, * are logically thrown at the end of the foreach loop, so adjust the
* so don't check the inner exception regions * op_num.
*/ */
last_try_catch = exc_opline->op2.num; op_num = EX(func)->op_array.live_range[exc_opline->op2.num].end;
} }
} }
for (i = 0; i < last_try_catch; i++) { for (i = 0; i < EX(func)->op_array.last_try_catch; i++) {
if (EX(func)->op_array.try_catch_array[i].try_op > op_num) { if (EX(func)->op_array.try_catch_array[i].try_op > op_num) {
/* further blocks will not be relevant... */ /* further blocks will not be relevant... */
break; break;

View File

@ -61,6 +61,7 @@ $vm_op_flags = array(
"ZEND_VM_OP1_NUM" => 1<<3, "ZEND_VM_OP1_NUM" => 1<<3,
"ZEND_VM_OP1_JMP_ADDR" => 1<<4, "ZEND_VM_OP1_JMP_ADDR" => 1<<4,
"ZEND_VM_OP1_TRY_CATCH" => 1<<5, "ZEND_VM_OP1_TRY_CATCH" => 1<<5,
"ZEND_VM_OP1_LIVE_RANGE" => 1<<6,
"ZEND_VM_OP2_SPEC" => 1<<8, "ZEND_VM_OP2_SPEC" => 1<<8,
"ZEND_VM_OP2_CONST" => 1<<9, "ZEND_VM_OP2_CONST" => 1<<9,
@ -68,6 +69,7 @@ $vm_op_flags = array(
"ZEND_VM_OP2_NUM" => 1<<11, "ZEND_VM_OP2_NUM" => 1<<11,
"ZEND_VM_OP2_JMP_ADDR" => 1<<12, "ZEND_VM_OP2_JMP_ADDR" => 1<<12,
"ZEND_VM_OP2_TRY_CATCH" => 1<<13, "ZEND_VM_OP2_TRY_CATCH" => 1<<13,
"ZEND_VM_OP2_LIVE_RANGE" => 1<<14,
"ZEND_VM_EXT_NUM" => 1<<16, "ZEND_VM_EXT_NUM" => 1<<16,
"ZEND_VM_EXT_VAR" => 1<<17, "ZEND_VM_EXT_VAR" => 1<<17,
@ -99,6 +101,7 @@ $vm_op_decode = array(
"NUM" => ZEND_VM_OP1_NUM, "NUM" => ZEND_VM_OP1_NUM,
"JMP_ADDR" => ZEND_VM_OP1_JMP_ADDR, "JMP_ADDR" => ZEND_VM_OP1_JMP_ADDR,
"TRY_CATCH" => ZEND_VM_OP1_TRY_CATCH, "TRY_CATCH" => ZEND_VM_OP1_TRY_CATCH,
"LIVE_RANGE" => ZEND_VM_OP1_LIVE_RANGE,
); );
$vm_ext_decode = array( $vm_ext_decode = array(

View File

@ -277,7 +277,7 @@ static uint32_t zend_vm_opcodes_flags[182] = {
0x00000801, 0x00000801,
0x00011003, 0x00011003,
0x00010300, 0x00010300,
0x00002005, 0x00004005,
0x00800703, 0x00800703,
0x00010703, 0x00010703,
0x02000007, 0x02000007,
@ -334,7 +334,7 @@ static uint32_t zend_vm_opcodes_flags[182] = {
0x00000103, 0x00000103,
0x00001003, 0x00001003,
0x00040001, 0x00040001,
0x00002005, 0x00004005,
0x00010700, 0x00010700,
0x00000000, 0x00000000,
0x00000000, 0x00000000,

View File

@ -34,12 +34,14 @@
#define ZEND_VM_OP1_NUM 0x00000008 #define ZEND_VM_OP1_NUM 0x00000008
#define ZEND_VM_OP1_JMP_ADDR 0x00000010 #define ZEND_VM_OP1_JMP_ADDR 0x00000010
#define ZEND_VM_OP1_TRY_CATCH 0x00000020 #define ZEND_VM_OP1_TRY_CATCH 0x00000020
#define ZEND_VM_OP1_LIVE_RANGE 0x00000040
#define ZEND_VM_OP2_SPEC 0x00000100 #define ZEND_VM_OP2_SPEC 0x00000100
#define ZEND_VM_OP2_CONST 0x00000200 #define ZEND_VM_OP2_CONST 0x00000200
#define ZEND_VM_OP2_TMPVAR 0x00000400 #define ZEND_VM_OP2_TMPVAR 0x00000400
#define ZEND_VM_OP2_NUM 0x00000800 #define ZEND_VM_OP2_NUM 0x00000800
#define ZEND_VM_OP2_JMP_ADDR 0x00001000 #define ZEND_VM_OP2_JMP_ADDR 0x00001000
#define ZEND_VM_OP2_TRY_CATCH 0x00002000 #define ZEND_VM_OP2_TRY_CATCH 0x00002000
#define ZEND_VM_OP2_LIVE_RANGE 0x00004000
#define ZEND_VM_EXT_NUM 0x00010000 #define ZEND_VM_EXT_NUM 0x00010000
#define ZEND_VM_EXT_VAR 0x00020000 #define ZEND_VM_EXT_VAR 0x00020000
#define ZEND_VM_EXT_JMP_ADDR 0x00040000 #define ZEND_VM_EXT_JMP_ADDR 0x00040000

View File

@ -352,9 +352,14 @@ void zend_optimizer_remove_live_range(zend_op_array *op_array, uint32_t var)
if (op_array->last_live_range) { if (op_array->last_live_range) {
int i = 0; int i = 0;
int j = 0; int j = 0;
uint32_t *map;
ALLOCA_FLAG(use_heap);
map = (uint32_t *)DO_ALLOCA(sizeof(uint32_t) * op_array->last_live_range);
do { do {
if (op_array->opcodes[op_array->live_range[i].end].op1.var != var) { if (op_array->opcodes[op_array->live_range[i].end].op1.var != var) {
map[i] = j;
if (i != j) { if (i != j) {
op_array->live_range[j] = op_array->live_range[i]; op_array->live_range[j] = op_array->live_range[i];
} }
@ -362,7 +367,19 @@ void zend_optimizer_remove_live_range(zend_op_array *op_array, uint32_t var)
} }
i++; i++;
} while (i < op_array->last_live_range); } while (i < op_array->last_live_range);
op_array->last_live_range = j; if (i != j) {
zend_op *opline = op_array->opcodes;
zend_op *end = opline + op_array->last;
op_array->last_live_range = j;
while (opline != end) {
if ((opline->opcode == ZEND_FREE || opline->opcode == ZEND_FE_FREE) &&
opline->extended_value == ZEND_FREE_ON_RETURN) {
opline->op2.num = map[opline->op2.num];
}
opline++;
}
}
} }
} }