mirror of
https://github.com/php/php-src.git
synced 2024-09-21 09:57:23 +00:00
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:
parent
cd6dda1679
commit
948b7f5421
27
Zend/tests/temporary_cleaning_009.phpt
Normal file
27
Zend/tests/temporary_cleaning_009.phpt
Normal 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
|
23
Zend/tests/temporary_cleaning_010.phpt
Normal file
23
Zend/tests/temporary_cleaning_010.phpt
Normal 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
|
20
Zend/tests/try/try_finally_021.phpt
Normal file
20
Zend/tests/try/try_finally_021.phpt
Normal 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
|
41
Zend/tests/try/try_finally_022.phpt
Normal file
41
Zend/tests/try/try_finally_022.phpt
Normal 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
|
||||||
|
|
@ -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) {
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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(
|
||||||
|
@ -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,
|
||||||
|
@ -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
|
||||||
|
@ -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++;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user