summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnatol Belski <ab@php.net>2015-07-10 12:06:06 +0200
committerAnatol Belski <ab@php.net>2015-07-10 12:06:06 +0200
commit2928e412e603e4a2c0a7a89ba0ea1c03b6b706cd (patch)
tree744effcb2af247623f70a3143e085cdf16538210
parent770571bce95e086cf6dad703e863c5874082cd6b (diff)
downloadphp-git-2928e412e603e4a2c0a7a89ba0ea1c03b6b706cd.tar.gz
Revert "Remove loop_var_stack"
This reverts commit b3a4c05071c3786e27e1326fa1b4d5acad62fccd.
-rw-r--r--Zend/zend.c3
-rw-r--r--Zend/zend_compile.c102
-rw-r--r--Zend/zend_compile.h2
-rw-r--r--Zend/zend_globals.h2
4 files changed, 79 insertions, 30 deletions
diff --git a/Zend/zend.c b/Zend/zend.c
index e200c05b67..e5fd2e8bee 100644
--- a/Zend/zend.c
+++ b/Zend/zend.c
@@ -1045,6 +1045,7 @@ static void zend_error_va_list(int type, const char *format, va_list args)
zval orig_user_error_handler;
zend_bool in_compilation;
zend_class_entry *saved_class_entry;
+ zend_stack loop_var_stack;
zend_stack delayed_oplines_stack;
zend_array *symbol_table;
@@ -1211,6 +1212,7 @@ static void zend_error_va_list(int type, const char *format, va_list args)
if (in_compilation) {
saved_class_entry = CG(active_class_entry);
CG(active_class_entry) = NULL;
+ SAVE_STACK(loop_var_stack);
SAVE_STACK(delayed_oplines_stack);
CG(in_compilation) = 0;
}
@@ -1229,6 +1231,7 @@ static void zend_error_va_list(int type, const char *format, va_list args)
if (in_compilation) {
CG(active_class_entry) = saved_class_entry;
+ RESTORE_STACK(loop_var_stack);
RESTORE_STACK(delayed_oplines_stack);
CG(in_compilation) = 1;
}
diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c
index 51eb0bc754..69aecc4108 100644
--- a/Zend/zend_compile.c
+++ b/Zend/zend_compile.c
@@ -289,6 +289,7 @@ void zend_file_context_end(zend_file_context *prev_context) /* {{{ */
void zend_init_compiler_data_structures(void) /* {{{ */
{
+ zend_stack_init(&CG(loop_var_stack), sizeof(znode));
zend_stack_init(&CG(delayed_oplines_stack), sizeof(zend_op));
CG(active_class_entry) = NULL;
CG(in_compilation) = 0;
@@ -321,6 +322,7 @@ void init_compiler(void) /* {{{ */
void shutdown_compiler(void) /* {{{ */
{
+ zend_stack_destroy(&CG(loop_var_stack));
zend_stack_destroy(&CG(delayed_oplines_stack));
zend_hash_destroy(&CG(filenames_table));
zend_hash_destroy(&CG(const_filenames));
@@ -569,10 +571,14 @@ static inline void zend_begin_loop(const znode *loop_var) /* {{{ */
CG(context).current_brk_cont = CG(context).last_brk_cont;
brk_cont_element = get_next_brk_cont_element(CG(active_op_array));
brk_cont_element->parent = parent;
- if (loop_var && (loop_var->op_type & (IS_TMP_VAR|IS_VAR))) {
- brk_cont_element->loop_var = *loop_var;
+
+ if (loop_var) {
+ zend_stack_push(&CG(loop_var_stack), loop_var);
+ brk_cont_element->start = get_next_op_number(CG(active_op_array));
} else {
- brk_cont_element->loop_var.op_type = IS_UNUSED;
+ /* The start field is used to free temporary variables in case of exceptions.
+ * We won't try to free something of we don't have loop variable. */
+ brk_cont_element->start = -1;
}
}
/* }}} */
@@ -584,6 +590,10 @@ static inline void zend_end_loop(int cont_addr) /* {{{ */
brk_cont_element->cont = cont_addr;
brk_cont_element->brk = get_next_op_number(CG(active_op_array));
CG(context).current_brk_cont = brk_cont_element->parent;
+
+ if (brk_cont_element->start >= 0) {
+ zend_stack_del_top(&CG(loop_var_stack));
+ }
}
/* }}} */
@@ -872,15 +882,24 @@ static void str_dtor(zval *zv) /* {{{ */ {
static zend_bool zend_is_call(zend_ast *ast);
-static void generate_free_loop_var(znode *var) /* {{{ */
+static int generate_free_loop_var(znode *var) /* {{{ */
{
- if (var->op_type != IS_UNUSED) {
- zend_op *opline = get_next_op(CG(active_op_array));
+ switch (var->op_type) {
+ case IS_UNUSED:
+ /* Stack separator on function boundary, stop applying */
+ return 1;
+ case IS_VAR:
+ case IS_TMP_VAR:
+ {
+ zend_op *opline = get_next_op(CG(active_op_array));
- opline->opcode = var->flag ? ZEND_FE_FREE : ZEND_FREE;
- SET_NODE(opline->op1, var);
- SET_UNUSED(opline->op2);
+ opline->opcode = var->flag ? ZEND_FE_FREE : ZEND_FREE;
+ SET_NODE(opline->op1, var);
+ SET_UNUSED(opline->op2);
+ }
}
+
+ return 0;
}
/* }}} */
@@ -3443,12 +3462,7 @@ void zend_compile_unset(zend_ast *ast) /* {{{ */
static void zend_free_foreach_and_switch_variables(void) /* {{{ */
{
- int array_offset = CG(context).current_brk_cont;
- while (array_offset != -1) {
- zend_brk_cont_element *brk_cont = &CG(context).brk_cont_array[array_offset];
- generate_free_loop_var(&brk_cont->loop_var);
- array_offset = brk_cont->parent;
- }
+ zend_stack_apply(&CG(loop_var_stack), ZEND_STACK_APPLY_TOPDOWN, (int (*)(void *element)) generate_free_loop_var);
}
/* }}} */
@@ -3550,6 +3564,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) {
@@ -3558,8 +3573,9 @@ void zend_compile_break_continue(zend_ast *ast) /* {{{ */
depth, depth == 1 ? "" : "s");
}
- if (nest_level > 1) {
- generate_free_loop_var(&CG(context).brk_cont_array[array_offset].loop_var);
+ if (nest_level > 1 && CG(context).brk_cont_array[array_offset].start >= 0) {
+ generate_free_loop_var(loop_var);
+ loop_var--;
}
array_offset = CG(context).brk_cont_array[array_offset].parent;
@@ -3576,6 +3592,7 @@ void zend_resolve_goto_label(zend_op_array *op_array, znode *label_node, zend_op
zend_label *dest;
int current, distance, free_vars;
zval *label;
+ znode *loop_var = NULL;
if (pass2_opline) {
label = RT_CONSTANT(op_array, pass2_opline->op2);
@@ -3596,7 +3613,7 @@ void zend_resolve_goto_label(zend_op_array *op_array, znode *label_node, zend_op
current = CG(context).current_brk_cont;
while (current != -1) {
- if (CG(context).brk_cont_array[current].loop_var.op_type != IS_UNUSED) {
+ if (CG(context).brk_cont_array[current].start >= 0) {
zend_emit_op(NULL, ZEND_NOP, NULL, NULL);
}
current = CG(context).brk_cont_array[current].parent;
@@ -3616,6 +3633,9 @@ void zend_resolve_goto_label(zend_op_array *op_array, znode *label_node, zend_op
} else {
current = CG(context).current_brk_cont;
}
+ if (!pass2_opline) {
+ loop_var = zend_stack_top(&CG(loop_var_stack));
+ }
for (distance = 0, free_vars = 0; current != dest->brk_cont; distance++) {
if (current == -1) {
if (pass2_opline) {
@@ -3625,11 +3645,12 @@ void zend_resolve_goto_label(zend_op_array *op_array, znode *label_node, zend_op
}
zend_error_noreturn(E_COMPILE_ERROR, "'goto' into loop or switch statement is disallowed");
}
- if (CG(context).brk_cont_array[current].loop_var.op_type != IS_UNUSED) {
+ if (CG(context).brk_cont_array[current].start >= 0) {
if (pass2_opline) {
free_vars++;
} else {
- generate_free_loop_var(&CG(context).brk_cont_array[current].loop_var);
+ generate_free_loop_var(loop_var);
+ loop_var--;
}
}
current = CG(context).brk_cont_array[current].parent;
@@ -3639,18 +3660,30 @@ void zend_resolve_goto_label(zend_op_array *op_array, znode *label_node, zend_op
if (free_vars) {
current = pass2_opline->extended_value;
while (current != dest->brk_cont) {
- if (CG(context).brk_cont_array[current].loop_var.op_type != IS_UNUSED) {
+ if (CG(context).brk_cont_array[current].start >= 0) {
zend_op *brk_opline = &op_array->opcodes[CG(context).brk_cont_array[current].brk];
- (pass2_opline - free_vars)->opcode = brk_opline->opcode;
- (pass2_opline - free_vars)->op1_type = brk_opline->op1_type;
- if (op_array->fn_flags & ZEND_ACC_HAS_FINALLY_BLOCK) {
- (pass2_opline - free_vars)->op1.var = brk_opline->op1.var;
- } else {
- (pass2_opline - free_vars)->op1.var = (uint32_t)(zend_intptr_t)ZEND_CALL_VAR_NUM(NULL, op_array->last_var + brk_opline->op1.var);
- ZEND_VM_SET_OPCODE_HANDLER(pass2_opline - free_vars);
+ if (brk_opline->opcode == ZEND_FREE) {
+ (pass2_opline - free_vars)->opcode = ZEND_FREE;
+ (pass2_opline - free_vars)->op1_type = brk_opline->op1_type;
+ if (op_array->fn_flags & ZEND_ACC_HAS_FINALLY_BLOCK) {
+ (pass2_opline - free_vars)->op1.var = brk_opline->op1.var;
+ } else {
+ (pass2_opline - free_vars)->op1.var = (uint32_t)(zend_intptr_t)ZEND_CALL_VAR_NUM(NULL, op_array->last_var + brk_opline->op1.var);
+ ZEND_VM_SET_OPCODE_HANDLER(pass2_opline - free_vars);
+ }
+ free_vars--;
+ } else if (brk_opline->opcode == ZEND_FE_FREE) {
+ (pass2_opline - free_vars)->opcode = ZEND_FE_FREE;
+ (pass2_opline - free_vars)->op1_type = brk_opline->op1_type;
+ if (op_array->fn_flags & ZEND_ACC_HAS_FINALLY_BLOCK) {
+ (pass2_opline - free_vars)->op1.var = brk_opline->op1.var;
+ } else {
+ (pass2_opline - free_vars)->op1.var = (uint32_t)(zend_intptr_t)ZEND_CALL_VAR_NUM(NULL, op_array->last_var + brk_opline->op1.var);
+ ZEND_VM_SET_OPCODE_HANDLER(pass2_opline - free_vars);
+ }
+ free_vars--;
}
- free_vars--;
}
current = CG(context).brk_cont_array[current].parent;
}
@@ -4768,6 +4801,14 @@ void zend_compile_func_decl(znode *result, zend_ast *ast) /* {{{ */
opline_ext->lineno = decl->start_lineno;
}
+ {
+ /* Push a separator to the loop variable stack */
+ znode dummy_var;
+ dummy_var.op_type = IS_UNUSED;
+
+ zend_stack_push(&CG(loop_var_stack), (void *) &dummy_var);
+ }
+
zend_compile_params(params_ast, return_type_ast);
if (uses_ast) {
zend_compile_closure_uses(uses_ast);
@@ -4785,6 +4826,9 @@ void zend_compile_func_decl(znode *result, zend_ast *ast) /* {{{ */
pass_two(CG(active_op_array));
zend_oparray_context_end(&orig_oparray_context);
+ /* Pop the loop variable stack separator */
+ zend_stack_del_top(&CG(loop_var_stack));
+
CG(active_op_array) = orig_op_array;
}
/* }}} */
diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h
index 3f9c091061..993a19fb6b 100644
--- a/Zend/zend_compile.h
+++ b/Zend/zend_compile.h
@@ -110,10 +110,10 @@ typedef struct _zend_declarables {
} zend_declarables;
typedef struct _zend_brk_cont_element {
+ int start;
int cont;
int brk;
int parent;
- znode loop_var;
} zend_brk_cont_element;
typedef struct _zend_label {
diff --git a/Zend/zend_globals.h b/Zend/zend_globals.h
index 780007174e..28487a2a4a 100644
--- a/Zend/zend_globals.h
+++ b/Zend/zend_globals.h
@@ -68,6 +68,8 @@ typedef struct _zend_ini_entry zend_ini_entry;
struct _zend_compiler_globals {
+ zend_stack loop_var_stack;
+
zend_class_entry *active_class_entry;
zend_string *compiled_filename;