diff options
author | Anatol Belski <ab@php.net> | 2015-07-10 12:06:06 +0200 |
---|---|---|
committer | Anatol Belski <ab@php.net> | 2015-07-10 12:06:06 +0200 |
commit | 2928e412e603e4a2c0a7a89ba0ea1c03b6b706cd (patch) | |
tree | 744effcb2af247623f70a3143e085cdf16538210 | |
parent | 770571bce95e086cf6dad703e863c5874082cd6b (diff) | |
download | php-git-2928e412e603e4a2c0a7a89ba0ea1c03b6b706cd.tar.gz |
Revert "Remove loop_var_stack"
This reverts commit b3a4c05071c3786e27e1326fa1b4d5acad62fccd.
-rw-r--r-- | Zend/zend.c | 3 | ||||
-rw-r--r-- | Zend/zend_compile.c | 102 | ||||
-rw-r--r-- | Zend/zend_compile.h | 2 | ||||
-rw-r--r-- | Zend/zend_globals.h | 2 |
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; |