summaryrefslogtreecommitdiff
path: root/Zend
diff options
context:
space:
mode:
authorNikita Popov <nikita.ppv@gmail.com>2018-02-16 21:25:49 +0100
committerNikita Popov <nikita.ppv@gmail.com>2018-02-16 21:30:48 +0100
commitb0af9ac7331e3efa0dcee4f43b2ba8b1e4e52f2f (patch)
tree5b40edba9eee94ab22fe494ce0c919b3ffdfebe4 /Zend
parent07ad75ca9603b8b0195ddcd90229ae9dbe650900 (diff)
downloadphp-git-b0af9ac7331e3efa0dcee4f43b2ba8b1e4e52f2f.tar.gz
Avoid live range references in opcodes
Don't store the live range of the freed variable for FREE_ON_RETURN frees, instead look it up at runtime. As this is an extremely unlikely codepath (in particular, it requires a loop variable with a throwing destructor), saving the runtime lookup of the live range is not worth the extra complexity this adds everywhere else.
Diffstat (limited to 'Zend')
-rw-r--r--Zend/zend_compile.c19
-rw-r--r--Zend/zend_execute.c14
-rw-r--r--Zend/zend_vm_def.h23
-rw-r--r--Zend/zend_vm_execute.h19
-rw-r--r--Zend/zend_vm_gen.php3
-rw-r--r--Zend/zend_vm_opcodes.c4
-rw-r--r--Zend/zend_vm_opcodes.h1
7 files changed, 37 insertions, 46 deletions
diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c
index 9c8fe3f4d7..1190cef1b4 100644
--- a/Zend/zend_compile.c
+++ b/Zend/zend_compile.c
@@ -629,7 +629,6 @@ static uint32_t zend_start_live_range_ex(zend_op_array *op_array, uint32_t start
if (!zend_stack_is_empty(&CG(loop_var_stack))) {
zend_loop_var *loop_var = zend_stack_top(&CG(loop_var_stack));
zend_loop_var *base = zend_stack_base(&CG(loop_var_stack));
- int check_opcodes = 0;
for (; loop_var >= base; loop_var--) {
if (loop_var->opcode == ZEND_RETURN) {
@@ -639,28 +638,11 @@ static uint32_t zend_start_live_range_ex(zend_op_array *op_array, uint32_t start
loop_var->opcode == ZEND_FE_FREE) {
if (loop_var->u.live_range_offset >= n) {
loop_var->u.live_range_offset++;
- check_opcodes = 1;
} else {
break;
}
}
}
-
- /* update previously generated FREE/FE_FREE opcodes */
- if (check_opcodes) {
- zend_op *opline = op_array->opcodes + op_array->live_range[n+1].start;
- zend_op *end = op_array->opcodes + op_array->last;
-
- while (opline < end) {
- if ((opline->opcode == ZEND_FREE ||
- opline->opcode == ZEND_FE_FREE) &&
- (opline->extended_value & ZEND_FREE_ON_RETURN) &&
- opline->op2.num >= n) {
- opline->op2.num++;
- }
- opline++;
- }
- }
}
return n;
}
@@ -4463,7 +4445,6 @@ static int zend_handle_loops_and_finally_ex(zend_long depth, znode *return_value
opline->op1_type = loop_var->var_type;
opline->op1.var = loop_var->var_num;
SET_UNUSED(opline->op2);
- opline->op2.num = loop_var->u.live_range_offset;
opline->extended_value = ZEND_FREE_ON_RETURN;
depth--;
}
diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c
index 80217b72f3..63073f5957 100644
--- a/Zend/zend_execute.c
+++ b/Zend/zend_execute.c
@@ -2576,6 +2576,20 @@ static void cleanup_unfinished_calls(zend_execute_data *execute_data, uint32_t o
}
/* }}} */
+static const zend_live_range *find_live_range(const zend_op_array *op_array, uint32_t op_num, uint32_t var_num) /* {{{ */
+{
+ int i;
+ for (i = 0; i < op_array->last_live_range; i++) {
+ const zend_live_range *range = &op_array->live_range[i];
+ if (op_num >= range->start && op_num < range->end
+ && var_num == (range->var & ~ZEND_LIVE_MASK)) {
+ return range;
+ }
+ }
+ return NULL;
+}
+/* }}} */
+
static void cleanup_live_vars(zend_execute_data *execute_data, uint32_t op_num, uint32_t catch_op_num) /* {{{ */
{
int i;
diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h
index c105450563..a838dd0668 100644
--- a/Zend/zend_vm_def.h
+++ b/Zend/zend_vm_def.h
@@ -2730,7 +2730,7 @@ ZEND_VM_HANDLER(47, ZEND_JMPNZ_EX, CONST|TMPVAR|CV, JMP_ADDR)
ZEND_VM_JMP(opline);
}
-ZEND_VM_HANDLER(70, ZEND_FREE, TMPVAR, LIVE_RANGE)
+ZEND_VM_HANDLER(70, ZEND_FREE, TMPVAR, ANY)
{
USE_OPLINE
@@ -2739,7 +2739,7 @@ ZEND_VM_HANDLER(70, ZEND_FREE, TMPVAR, LIVE_RANGE)
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
}
-ZEND_VM_HANDLER(127, ZEND_FE_FREE, TMPVAR, LIVE_RANGE)
+ZEND_VM_HANDLER(127, ZEND_FE_FREE, TMPVAR, ANY)
{
zval *var;
USE_OPLINE
@@ -7129,16 +7129,15 @@ ZEND_VM_HANDLER(149, ZEND_HANDLE_EXCEPTION, ANY, ANY)
uint32_t throw_op_num = throw_op - EX(func)->op_array.opcodes;
int i, current_try_catch_offset = -1;
- {
- const zend_op *exc_opline = EG(opline_before_exception);
- if ((exc_opline->opcode == ZEND_FREE || exc_opline->opcode == ZEND_FE_FREE)
- && exc_opline->extended_value & ZEND_FREE_ON_RETURN) {
- /* exceptions thrown because of loop var destruction on return/break/...
- * are logically thrown at the end of the foreach loop, so adjust the
- * throw_op_num.
- */
- throw_op_num = EX(func)->op_array.live_range[exc_opline->op2.num].end;
- }
+ if ((throw_op->opcode == ZEND_FREE || throw_op->opcode == ZEND_FE_FREE)
+ && throw_op->extended_value & ZEND_FREE_ON_RETURN) {
+ /* exceptions thrown because of loop var destruction on return/break/...
+ * are logically thrown at the end of the foreach loop, so adjust the
+ * throw_op_num.
+ */
+ const zend_live_range *range = find_live_range(
+ &EX(func)->op_array, throw_op_num, throw_op->op1.var);
+ throw_op_num = range->end;
}
/* Find the innermost try/catch/finally the exception was thrown in */
diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h
index 7b2a15d28a..1f6ab1b412 100644
--- a/Zend/zend_vm_execute.h
+++ b/Zend/zend_vm_execute.h
@@ -1726,16 +1726,15 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_HANDLE_EXCEPTION_SPEC_HANDLER(
uint32_t throw_op_num = throw_op - EX(func)->op_array.opcodes;
int i, current_try_catch_offset = -1;
- {
- const zend_op *exc_opline = EG(opline_before_exception);
- if ((exc_opline->opcode == ZEND_FREE || exc_opline->opcode == ZEND_FE_FREE)
- && exc_opline->extended_value & ZEND_FREE_ON_RETURN) {
- /* exceptions thrown because of loop var destruction on return/break/...
- * are logically thrown at the end of the foreach loop, so adjust the
- * throw_op_num.
- */
- throw_op_num = EX(func)->op_array.live_range[exc_opline->op2.num].end;
- }
+ if ((throw_op->opcode == ZEND_FREE || throw_op->opcode == ZEND_FE_FREE)
+ && throw_op->extended_value & ZEND_FREE_ON_RETURN) {
+ /* exceptions thrown because of loop var destruction on return/break/...
+ * are logically thrown at the end of the foreach loop, so adjust the
+ * throw_op_num.
+ */
+ const zend_live_range *range = find_live_range(
+ &EX(func)->op_array, throw_op_num, throw_op->op1.var);
+ throw_op_num = range->end;
}
/* Find the innermost try/catch/finally the exception was thrown in */
diff --git a/Zend/zend_vm_gen.php b/Zend/zend_vm_gen.php
index 37a660127f..f9b2280d31 100644
--- a/Zend/zend_vm_gen.php
+++ b/Zend/zend_vm_gen.php
@@ -64,7 +64,7 @@ $vm_op_flags = array(
"ZEND_VM_OP_NUM" => 0x10,
"ZEND_VM_OP_JMP_ADDR" => 0x20,
"ZEND_VM_OP_TRY_CATCH" => 0x30,
- "ZEND_VM_OP_LIVE_RANGE" => 0x40,
+ // unused 0x40
"ZEND_VM_OP_THIS" => 0x50,
"ZEND_VM_OP_NEXT" => 0x60,
"ZEND_VM_OP_CLASS_FETCH" => 0x70,
@@ -110,7 +110,6 @@ $vm_op_decode = array(
"NUM" => ZEND_VM_OP_NUM,
"JMP_ADDR" => ZEND_VM_OP_JMP_ADDR,
"TRY_CATCH" => ZEND_VM_OP_TRY_CATCH,
- "LIVE_RANGE" => ZEND_VM_OP_LIVE_RANGE,
"THIS" => ZEND_VM_OP_THIS,
"NEXT" => ZEND_VM_OP_NEXT,
"CLASS_FETCH" => ZEND_VM_OP_CLASS_FETCH,
diff --git a/Zend/zend_vm_opcodes.c b/Zend/zend_vm_opcodes.c
index 52b7cb855c..f37b769da3 100644
--- a/Zend/zend_vm_opcodes.c
+++ b/Zend/zend_vm_opcodes.c
@@ -295,7 +295,7 @@ static uint32_t zend_vm_opcodes_flags[199] = {
0x00001001,
0x0100a173,
0x01040300,
- 0x00004005,
+ 0x00000005,
0x00186703,
0x00106703,
0x08000007,
@@ -352,7 +352,7 @@ static uint32_t zend_vm_opcodes_flags[199] = {
0x0000a103,
0x00002003,
0x03000001,
- 0x00004005,
+ 0x00000005,
0x01000700,
0x00000000,
0x00000000,
diff --git a/Zend/zend_vm_opcodes.h b/Zend/zend_vm_opcodes.h
index 6f9b323bb0..b5c0a483d8 100644
--- a/Zend/zend_vm_opcodes.h
+++ b/Zend/zend_vm_opcodes.h
@@ -42,7 +42,6 @@
#define ZEND_VM_OP_NUM 0x00000010
#define ZEND_VM_OP_JMP_ADDR 0x00000020
#define ZEND_VM_OP_TRY_CATCH 0x00000030
-#define ZEND_VM_OP_LIVE_RANGE 0x00000040
#define ZEND_VM_OP_THIS 0x00000050
#define ZEND_VM_OP_NEXT 0x00000060
#define ZEND_VM_OP_CLASS_FETCH 0x00000070