summaryrefslogtreecommitdiff
path: root/ext
diff options
context:
space:
mode:
authorAnatol Belski <ab@php.net>2015-07-10 12:06:56 +0200
committerAnatol Belski <ab@php.net>2015-07-10 12:06:56 +0200
commitad8a73dd55c087de465ad80e8715611693bb1460 (patch)
treef76e6e2950a1e1cd958dab53e4100ab93c640938 /ext
parentceefc0947a12376eb6612376fd750744ac054f5c (diff)
downloadphp-git-php-7.0.0beta1.tar.gz
Revert "Fixed bug #62210 (Exceptions can leak temporary variables. As a part of the fix serious refactoring was done. op_array->brk_cont_array was removed, and replaced with more general and speed efficient op_array->T_liveliness. ZEND_GOTO opcode is always replaced by ZEND_JMP at compile time). (Bob, Dmitry, Laruence)"php-7.0.0beta1
This reverts commit 5ee841325901a4b040cfea56292a24702fe224d9.
Diffstat (limited to 'ext')
-rw-r--r--ext/opcache/Optimizer/block_pass.c83
-rw-r--r--ext/opcache/Optimizer/nop_removal.c16
-rw-r--r--ext/opcache/Optimizer/pass1_5.c1
-rw-r--r--ext/opcache/Optimizer/zend_optimizer.c40
-rw-r--r--ext/opcache/Optimizer/zend_optimizer_internal.h3
-rw-r--r--ext/opcache/zend_file_cache.c6
-rw-r--r--ext/opcache/zend_persist.c9
-rw-r--r--ext/opcache/zend_persist_calc.c8
8 files changed, 140 insertions, 26 deletions
diff --git a/ext/opcache/Optimizer/block_pass.c b/ext/opcache/Optimizer/block_pass.c
index dfe0e4baef..e1e07ea01b 100644
--- a/ext/opcache/Optimizer/block_pass.c
+++ b/ext/opcache/Optimizer/block_pass.c
@@ -123,6 +123,10 @@ static int find_code_blocks(zend_op_array *op_array, zend_cfg *cfg, zend_optimiz
blocks[0].start_opline_no = 0;
while (opline < end) {
switch((unsigned)opline->opcode) {
+ case ZEND_GOTO:
+ /* would not optimize GOTOs - we cannot really know where it jumps,
+ * so these optimizations are too dangerous */
+ return 0;
case ZEND_FAST_CALL:
START_BLOCK_OP(ZEND_OP1(opline).opline_num);
if (opline->extended_value) {
@@ -193,6 +197,65 @@ static int find_code_blocks(zend_op_array *op_array, zend_cfg *cfg, zend_optimiz
blocks[op_array->try_catch_array[i].try_op].protected = 1;
}
}
+ /* Currently, we don't optimize op_arrays with BRK/CONT/GOTO opcodes,
+ * but, we have to keep brk_cont_array to avoid memory leaks during
+ * exception handling */
+ if (op_array->last_brk_cont) {
+ int i, j;
+
+ j = 0;
+ for (i = 0; i< op_array->last_brk_cont; i++) {
+ if (op_array->brk_cont_array[i].start >= 0 &&
+ (op_array->opcodes[op_array->brk_cont_array[i].brk].opcode == ZEND_FREE ||
+ op_array->opcodes[op_array->brk_cont_array[i].brk].opcode == ZEND_FE_FREE ||
+ op_array->opcodes[op_array->brk_cont_array[i].brk].opcode == ZEND_ROPE_END ||
+ op_array->opcodes[op_array->brk_cont_array[i].brk].opcode == ZEND_END_SILENCE)) {
+ int parent = op_array->brk_cont_array[i].parent;
+
+ while (parent >= 0 &&
+ op_array->brk_cont_array[parent].start < 0 &&
+ (op_array->opcodes[op_array->brk_cont_array[parent].brk].opcode != ZEND_FREE ||
+ op_array->opcodes[op_array->brk_cont_array[parent].brk].opcode != ZEND_FE_FREE ||
+ op_array->opcodes[op_array->brk_cont_array[i].brk].opcode != ZEND_ROPE_END ||
+ op_array->opcodes[op_array->brk_cont_array[parent].brk].opcode != ZEND_END_SILENCE)) {
+ parent = op_array->brk_cont_array[parent].parent;
+ }
+ op_array->brk_cont_array[i].parent = parent;
+ j++;
+ }
+ }
+ if (j) {
+ cfg->loop_start = zend_arena_calloc(&ctx->arena, op_array->last_brk_cont, sizeof(zend_code_block *));
+ cfg->loop_cont = zend_arena_calloc(&ctx->arena, op_array->last_brk_cont, sizeof(zend_code_block *));
+ cfg->loop_brk = zend_arena_calloc(&ctx->arena, op_array->last_brk_cont, sizeof(zend_code_block *));
+ j = 0;
+ for (i = 0; i< op_array->last_brk_cont; i++) {
+ if (op_array->brk_cont_array[i].start >= 0 &&
+ (op_array->opcodes[op_array->brk_cont_array[i].brk].opcode == ZEND_FREE ||
+ op_array->opcodes[op_array->brk_cont_array[i].brk].opcode == ZEND_FE_FREE ||
+ op_array->opcodes[op_array->brk_cont_array[i].brk].opcode == ZEND_ROPE_END ||
+ op_array->opcodes[op_array->brk_cont_array[i].brk].opcode == ZEND_END_SILENCE)) {
+ if (i != j) {
+ op_array->brk_cont_array[j] = op_array->brk_cont_array[i];
+ }
+ cfg->loop_start[j] = &blocks[op_array->brk_cont_array[j].start];
+ cfg->loop_cont[j] = &blocks[op_array->brk_cont_array[j].cont];
+ cfg->loop_brk[j] = &blocks[op_array->brk_cont_array[j].brk];
+ START_BLOCK_OP(op_array->brk_cont_array[j].start);
+ START_BLOCK_OP(op_array->brk_cont_array[j].cont);
+ START_BLOCK_OP(op_array->brk_cont_array[j].brk);
+ blocks[op_array->brk_cont_array[j].start].protected = 1;
+ blocks[op_array->brk_cont_array[j].brk].protected = 1;
+ j++;
+ }
+ }
+ op_array->last_brk_cont = j;
+ } else {
+ efree(op_array->brk_cont_array);
+ op_array->brk_cont_array = NULL;
+ op_array->last_brk_cont = 0;
+ }
+ }
/* Build CFG (Control Flow Graph) */
cur_block = blocks;
@@ -460,6 +523,16 @@ static void zend_rebuild_access_path(zend_cfg *cfg, zend_op_array *op_array, int
/* Walk thorough all paths */
zend_access_path(start, ctx);
+ /* Add brk/cont paths */
+ if (op_array->last_brk_cont) {
+ int i;
+ for (i=0; i< op_array->last_brk_cont; i++) {
+ zend_access_path(cfg->loop_start[i], ctx);
+ zend_access_path(cfg->loop_cont[i], ctx);
+ zend_access_path(cfg->loop_brk[i], ctx);
+ }
+ }
+
/* Add exception paths */
if (op_array->last_try_catch) {
int i;
@@ -1123,6 +1196,16 @@ static void assemble_code_blocks(zend_cfg *cfg, zend_op_array *op_array)
op_array->last_try_catch = j;
}
+ /* adjust loop jump targets */
+ if (op_array->last_brk_cont) {
+ int i;
+ for (i = 0; i< op_array->last_brk_cont; i++) {
+ op_array->brk_cont_array[i].start = cfg->loop_start[i]->start_opline - new_opcodes;
+ op_array->brk_cont_array[i].cont = cfg->loop_cont[i]->start_opline - new_opcodes;
+ op_array->brk_cont_array[i].brk = cfg->loop_brk[i]->start_opline - new_opcodes;
+ }
+ }
+
/* adjust jump targets */
for (cur_block = blocks; cur_block; cur_block = cur_block->next) {
if (!cur_block->access) {
diff --git a/ext/opcache/Optimizer/nop_removal.c b/ext/opcache/Optimizer/nop_removal.c
index 9983ff4f60..20510b4163 100644
--- a/ext/opcache/Optimizer/nop_removal.c
+++ b/ext/opcache/Optimizer/nop_removal.c
@@ -44,6 +44,14 @@ void zend_optimizer_nop_removal(zend_op_array *op_array)
end = op_array->opcodes + op_array->last;
for (opline = op_array->opcodes; opline < end; opline++) {
+ /* GOTO target is unresolved yet. We can't optimize. */
+ if (opline->opcode == ZEND_GOTO &&
+ Z_TYPE(ZEND_OP2_LITERAL(opline)) != IS_LONG) {
+ /* TODO: in general we can avoid this restriction */
+ FREE_ALLOCA(shiftlist);
+ return;
+ }
+
/* Kill JMP-over-NOP-s */
if (opline->opcode == ZEND_JMP && ZEND_OP1(opline).opline_num > i) {
/* check if there are only NOPs under the branch */
@@ -77,6 +85,7 @@ void zend_optimizer_nop_removal(zend_op_array *op_array)
for (opline = op_array->opcodes; opline<end; opline++) {
switch (opline->opcode) {
case ZEND_JMP:
+ case ZEND_GOTO:
case ZEND_FAST_CALL:
case ZEND_DECLARE_ANON_CLASS:
case ZEND_DECLARE_ANON_INHERITED_CLASS:
@@ -108,6 +117,13 @@ void zend_optimizer_nop_removal(zend_op_array *op_array)
}
}
+ /* update brk/cont array */
+ for (j = 0; j < op_array->last_brk_cont; j++) {
+ op_array->brk_cont_array[j].brk -= shiftlist[op_array->brk_cont_array[j].brk];
+ op_array->brk_cont_array[j].cont -= shiftlist[op_array->brk_cont_array[j].cont];
+ op_array->brk_cont_array[j].start -= shiftlist[op_array->brk_cont_array[j].start];
+ }
+
/* update try/catch array */
for (j = 0; j < op_array->last_try_catch; j++) {
op_array->try_catch_array[j].try_op -= shiftlist[op_array->try_catch_array[j].try_op];
diff --git a/ext/opcache/Optimizer/pass1_5.c b/ext/opcache/Optimizer/pass1_5.c
index 766eb2c2d4..6fcdc3e47a 100644
--- a/ext/opcache/Optimizer/pass1_5.c
+++ b/ext/opcache/Optimizer/pass1_5.c
@@ -624,6 +624,7 @@ void zend_optimizer_pass1(zend_op_array *op_array, zend_optimizer_ctx *ctx)
case ZEND_EXIT:
case ZEND_THROW:
case ZEND_CATCH:
+ case ZEND_GOTO:
case ZEND_FAST_CALL:
case ZEND_FAST_RET:
case ZEND_JMP:
diff --git a/ext/opcache/Optimizer/zend_optimizer.c b/ext/opcache/Optimizer/zend_optimizer.c
index 86b0837137..dc69d2511e 100644
--- a/ext/opcache/Optimizer/zend_optimizer.c
+++ b/ext/opcache/Optimizer/zend_optimizer.c
@@ -340,11 +340,29 @@ int zend_optimizer_replace_by_const(zend_op_array *op_array,
*/
case ZEND_FREE:
case ZEND_CASE: {
- zend_op *m = opline;
- zend_op *end = op_array->opcodes + op_array->last;
+ zend_op *m, *n;
+ int brk = op_array->last_brk_cont;
+ zend_bool in_switch = 0;
+ while (brk--) {
+ if (op_array->brk_cont_array[brk].start <= (opline - op_array->opcodes) &&
+ op_array->brk_cont_array[brk].brk > (opline - op_array->opcodes)) {
+ in_switch = 1;
+ break;
+ }
+ }
- while (m < end) {
- if (ZEND_OP1_TYPE(m) == type && ZEND_OP1(m).var == var) {
+ if (!in_switch) {
+ ZEND_ASSERT(opline->opcode == ZEND_FREE);
+ MAKE_NOP(opline);
+ zval_dtor(val);
+ return 1;
+ }
+
+ m = opline;
+ n = op_array->opcodes + op_array->brk_cont_array[brk].brk + 1;
+ while (m < n) {
+ if (ZEND_OP1_TYPE(m) == type &&
+ ZEND_OP1(m).var == var) {
if (m->opcode == ZEND_CASE) {
zval old_val;
ZVAL_COPY_VALUE(&old_val, val);
@@ -353,7 +371,6 @@ int zend_optimizer_replace_by_const(zend_op_array *op_array,
ZVAL_COPY_VALUE(val, &old_val);
} else if (m->opcode == ZEND_FREE) {
MAKE_NOP(m);
- break;
} else {
ZEND_ASSERT(0);
}
@@ -458,17 +475,6 @@ static void zend_optimize(zend_op_array *op_array,
if (ZEND_OPTIMIZER_PASS_11 & OPTIMIZATION_LEVEL) {
zend_optimizer_compact_literals(op_array, ctx);
}
-
- if ((ZEND_OPTIMIZER_PASS_1
- |ZEND_OPTIMIZER_PASS_2
- |ZEND_OPTIMIZER_PASS_3
- |ZEND_OPTIMIZER_PASS_4
- |ZEND_OPTIMIZER_PASS_5
- |ZEND_OPTIMIZER_PASS_9
- |ZEND_OPTIMIZER_PASS_10
- |ZEND_OPTIMIZER_PASS_11) & OPTIMIZATION_LEVEL) {
- zend_regenerate_var_liveliness_info(op_array);
- }
}
static void zend_accel_optimize(zend_op_array *op_array,
@@ -488,6 +494,7 @@ static void zend_accel_optimize(zend_op_array *op_array,
}
switch (opline->opcode) {
case ZEND_JMP:
+ case ZEND_GOTO:
case ZEND_FAST_CALL:
case ZEND_DECLARE_ANON_CLASS:
case ZEND_DECLARE_ANON_INHERITED_CLASS:
@@ -532,6 +539,7 @@ static void zend_accel_optimize(zend_op_array *op_array,
}
switch (opline->opcode) {
case ZEND_JMP:
+ case ZEND_GOTO:
case ZEND_FAST_CALL:
case ZEND_DECLARE_ANON_CLASS:
case ZEND_DECLARE_ANON_INHERITED_CLASS:
diff --git a/ext/opcache/Optimizer/zend_optimizer_internal.h b/ext/opcache/Optimizer/zend_optimizer_internal.h
index 69288c7228..c2f97ff715 100644
--- a/ext/opcache/Optimizer/zend_optimizer_internal.h
+++ b/ext/opcache/Optimizer/zend_optimizer_internal.h
@@ -73,6 +73,9 @@ typedef struct _zend_cfg {
zend_code_block *blocks;
zend_code_block **try;
zend_code_block **catch;
+ zend_code_block **loop_start;
+ zend_code_block **loop_cont;
+ zend_code_block **loop_brk;
zend_op **Tsource;
char *same_t;
} zend_cfg;
diff --git a/ext/opcache/zend_file_cache.c b/ext/opcache/zend_file_cache.c
index 54e2ab639a..0781b91c9d 100644
--- a/ext/opcache/zend_file_cache.c
+++ b/ext/opcache/zend_file_cache.c
@@ -386,6 +386,7 @@ static void zend_file_cache_serialize_op_array(zend_op_array *op_arra
# if ZEND_USE_ABS_JMP_ADDR
switch (opline->opcode) {
case ZEND_JMP:
+ case ZEND_GOTO:
case ZEND_FAST_CALL:
case ZEND_DECLARE_ANON_CLASS:
case ZEND_DECLARE_ANON_INHERITED_CLASS:
@@ -458,11 +459,11 @@ static void zend_file_cache_serialize_op_array(zend_op_array *op_arra
SERIALIZE_STR(op_array->function_name);
SERIALIZE_STR(op_array->filename);
+ SERIALIZE_PTR(op_array->brk_cont_array);
SERIALIZE_PTR(op_array->scope);
SERIALIZE_STR(op_array->doc_comment);
SERIALIZE_PTR(op_array->try_catch_array);
SERIALIZE_PTR(op_array->prototype);
- SERIALIZE_PTR(op_array->T_liveliness);
}
}
@@ -912,6 +913,7 @@ static void zend_file_cache_unserialize_op_array(zend_op_array *op_arr
# if ZEND_USE_ABS_JMP_ADDR
switch (opline->opcode) {
case ZEND_JMP:
+ case ZEND_GOTO:
case ZEND_FAST_CALL:
case ZEND_DECLARE_ANON_CLASS:
case ZEND_DECLARE_ANON_INHERITED_CLASS:
@@ -980,11 +982,11 @@ static void zend_file_cache_unserialize_op_array(zend_op_array *op_arr
UNSERIALIZE_STR(op_array->function_name);
UNSERIALIZE_STR(op_array->filename);
+ UNSERIALIZE_PTR(op_array->brk_cont_array);
UNSERIALIZE_PTR(op_array->scope);
UNSERIALIZE_STR(op_array->doc_comment);
UNSERIALIZE_PTR(op_array->try_catch_array);
UNSERIALIZE_PTR(op_array->prototype);
- UNSERIALIZE_PTR(op_array->T_liveliness);
}
}
diff --git a/ext/opcache/zend_persist.c b/ext/opcache/zend_persist.c
index 0f789090cd..bbcb20713b 100644
--- a/ext/opcache/zend_persist.c
+++ b/ext/opcache/zend_persist.c
@@ -501,6 +501,7 @@ static void zend_persist_op_array_ex(zend_op_array *op_array, zend_persistent_sc
/* fix jumps to point to new array */
switch (opline->opcode) {
case ZEND_JMP:
+ case ZEND_GOTO:
case ZEND_FAST_CALL:
case ZEND_DECLARE_ANON_CLASS:
case ZEND_DECLARE_ANON_INHERITED_CLASS:
@@ -589,6 +590,10 @@ static void zend_persist_op_array_ex(zend_op_array *op_array, zend_persistent_sc
op_array->arg_info = arg_info;
}
+ if (op_array->brk_cont_array) {
+ zend_accel_store(op_array->brk_cont_array, sizeof(zend_brk_cont_element) * op_array->last_brk_cont);
+ }
+
if (op_array->scope) {
op_array->scope = zend_shared_alloc_get_xlat_entry(op_array->scope);
}
@@ -613,10 +618,6 @@ static void zend_persist_op_array_ex(zend_op_array *op_array, zend_persistent_sc
zend_accel_store(op_array->try_catch_array, sizeof(zend_try_catch_element) * op_array->last_try_catch);
}
- if (op_array->T_liveliness) {
- zend_accel_store(op_array->T_liveliness, sizeof(uint32_t) * op_array->T_liveliness[op_array->last]);
- }
-
if (op_array->vars) {
if (already_stored) {
persist_ptr = zend_shared_alloc_get_xlat_entry(op_array->vars);
diff --git a/ext/opcache/zend_persist_calc.c b/ext/opcache/zend_persist_calc.c
index 9265ba5ce9..d78cc59259 100644
--- a/ext/opcache/zend_persist_calc.c
+++ b/ext/opcache/zend_persist_calc.c
@@ -229,6 +229,10 @@ static void zend_persist_op_array_calc_ex(zend_op_array *op_array)
}
}
+ if (op_array->brk_cont_array) {
+ ADD_DUP_SIZE(op_array->brk_cont_array, sizeof(zend_brk_cont_element) * op_array->last_brk_cont);
+ }
+
if (ZCG(accel_directives).save_comments && op_array->doc_comment) {
ADD_STRING(op_array->doc_comment);
}
@@ -237,10 +241,6 @@ static void zend_persist_op_array_calc_ex(zend_op_array *op_array)
ADD_DUP_SIZE(op_array->try_catch_array, sizeof(zend_try_catch_element) * op_array->last_try_catch);
}
- if (op_array->T_liveliness) {
- ADD_DUP_SIZE(op_array->T_liveliness, sizeof(uint32_t) * op_array->T_liveliness[op_array->last]);
- }
-
if (op_array->vars) {
int i;