diff options
Diffstat (limited to 'Zend/zend_compile.c')
-rw-r--r-- | Zend/zend_compile.c | 203 |
1 files changed, 79 insertions, 124 deletions
diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 69aecc4108..78266f6172 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -32,7 +32,6 @@ #include "zend_multibyte.h" #include "zend_language_scanner.h" #include "zend_inheritance.h" -#include "zend_vm.h" #define SET_NODE(target, src) do { \ target ## _type = (src)->op_type; \ @@ -211,21 +210,16 @@ void zend_oparray_context_begin(zend_oparray_context *prev_context) /* {{{ */ CG(context).opcodes_size = INITIAL_OP_ARRAY_SIZE; CG(context).vars_size = 0; CG(context).literals_size = 0; + CG(context).current_brk_cont = -1; CG(context).backpatch_count = 0; CG(context).in_finally = 0; CG(context).fast_call_var = -1; - CG(context).current_brk_cont = -1; - CG(context).last_brk_cont = 0; - CG(context).brk_cont_array = NULL; CG(context).labels = NULL; } /* }}} */ void zend_oparray_context_end(zend_oparray_context *prev_context) /* {{{ */ { - if (CG(context).brk_cont_array) { - efree(CG(context).brk_cont_array); - } if (CG(context).labels) { zend_hash_destroy(CG(context).labels); FREE_HASHTABLE(CG(context).labels); @@ -568,7 +562,7 @@ static inline void zend_begin_loop(const znode *loop_var) /* {{{ */ zend_brk_cont_element *brk_cont_element; int parent = CG(context).current_brk_cont; - CG(context).current_brk_cont = CG(context).last_brk_cont; + CG(context).current_brk_cont = CG(active_op_array)->last_brk_cont; brk_cont_element = get_next_brk_cont_element(CG(active_op_array)); brk_cont_element->parent = parent; @@ -586,7 +580,7 @@ static inline void zend_begin_loop(const znode *loop_var) /* {{{ */ static inline void zend_end_loop(int cont_addr) /* {{{ */ { zend_brk_cont_element *brk_cont_element - = &CG(context).brk_cont_array[CG(context).current_brk_cont]; + = &CG(active_op_array)->brk_cont_array[CG(context).current_brk_cont]; 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; @@ -880,6 +874,61 @@ static void str_dtor(zval *zv) /* {{{ */ { } /* }}} */ +void zend_resolve_goto_label(zend_op_array *op_array, zend_op *opline, int pass2) /* {{{ */ +{ + zend_label *dest; + int current, distance; + zval *label; + + if (pass2) { + label = RT_CONSTANT(op_array, opline->op2); + } else { + label = CT_CONSTANT_EX(op_array, opline->op2.constant); + } + if (CG(context).labels == NULL || + (dest = zend_hash_find_ptr(CG(context).labels, Z_STR_P(label))) == NULL) { + + if (pass2) { + CG(in_compilation) = 1; + CG(active_op_array) = op_array; + CG(zend_lineno) = opline->lineno; + zend_error_noreturn(E_COMPILE_ERROR, "'goto' to undefined label '%s'", Z_STRVAL_P(label)); + } else { + /* Label is not defined. Delay to pass 2. */ + return; + } + } + + opline->op1.opline_num = dest->opline_num; + zval_dtor(label); + ZVAL_NULL(label); + + /* Check that we are not moving into loop or switch */ + current = opline->extended_value; + for (distance = 0; current != dest->brk_cont; distance++) { + if (current == -1) { + if (pass2) { + CG(in_compilation) = 1; + CG(active_op_array) = op_array; + CG(zend_lineno) = opline->lineno; + } + zend_error_noreturn(E_COMPILE_ERROR, "'goto' into loop or switch statement is disallowed"); + } + current = op_array->brk_cont_array[current].parent; + } + + if (distance == 0) { + /* Nothing to break out of, optimize to ZEND_JMP */ + opline->opcode = ZEND_JMP; + opline->extended_value = 0; + SET_UNUSED(opline->op2); + } else { + /* Set real break distance */ + ZVAL_LONG(label, distance); + } +} +/* }}} */ + static zend_bool zend_is_call(zend_ast *ast); static int generate_free_loop_var(znode *var) /* {{{ */ @@ -3573,12 +3622,12 @@ void zend_compile_break_continue(zend_ast *ast) /* {{{ */ depth, depth == 1 ? "" : "s"); } - if (nest_level > 1 && CG(context).brk_cont_array[array_offset].start >= 0) { + if (nest_level > 1 && CG(active_op_array)->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; + array_offset = CG(active_op_array)->brk_cont_array[array_offset].parent; } while (--nest_level > 0); } opline = zend_emit_op(NULL, ast->kind == ZEND_AST_BREAK ? ZEND_BRK : ZEND_CONT, NULL, NULL); @@ -3587,125 +3636,16 @@ void zend_compile_break_continue(zend_ast *ast) /* {{{ */ } /* }}} */ -void zend_resolve_goto_label(zend_op_array *op_array, znode *label_node, zend_op *pass2_opline) /* {{{ */ -{ - 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); - } else { - label = &label_node->u.constant; - } - if (CG(context).labels == NULL || - (dest = zend_hash_find_ptr(CG(context).labels, Z_STR_P(label))) == NULL) { - - if (pass2_opline) { - CG(in_compilation) = 1; - CG(active_op_array) = op_array; - CG(zend_lineno) = pass2_opline->lineno; - zend_error_noreturn(E_COMPILE_ERROR, "'goto' to undefined label '%s'", Z_STRVAL_P(label)); - } else { - /* Label is not defined. Delay to pass 2. */ - zend_op *opline; - - current = CG(context).current_brk_cont; - while (current != -1) { - 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; - } - opline = zend_emit_op(NULL, ZEND_GOTO, NULL, label_node); - opline->extended_value = CG(context).current_brk_cont; - return; - } - } - - zval_dtor(label); - ZVAL_NULL(label); - - /* Check that we are not moving into loop or switch */ - if (pass2_opline) { - current = pass2_opline->extended_value; - } 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) { - CG(in_compilation) = 1; - CG(active_op_array) = op_array; - CG(zend_lineno) = pass2_opline->lineno; - } - zend_error_noreturn(E_COMPILE_ERROR, "'goto' into loop or switch statement is disallowed"); - } - if (CG(context).brk_cont_array[current].start >= 0) { - if (pass2_opline) { - free_vars++; - } else { - generate_free_loop_var(loop_var); - loop_var--; - } - } - current = CG(context).brk_cont_array[current].parent; - } - - if (pass2_opline) { - if (free_vars) { - current = pass2_opline->extended_value; - while (current != dest->brk_cont) { - if (CG(context).brk_cont_array[current].start >= 0) { - zend_op *brk_opline = &op_array->opcodes[CG(context).brk_cont_array[current].brk]; - - 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--; - } - } - current = CG(context).brk_cont_array[current].parent; - } - } - pass2_opline->opcode = ZEND_JMP; - pass2_opline->op1.opline_num = dest->opline_num; - SET_UNUSED(pass2_opline->op2); - pass2_opline->extended_value = 0; - } else { - zend_op *opline = zend_emit_op(NULL, ZEND_JMP, NULL, NULL); - opline->op1.opline_num = dest->opline_num; - } -} -/* }}} */ - void zend_compile_goto(zend_ast *ast) /* {{{ */ { zend_ast *label_ast = ast->child[0]; znode label_node; + zend_op *opline; zend_compile_expr(&label_node, label_ast); - zend_resolve_goto_label(CG(active_op_array), &label_node, NULL); + opline = zend_emit_op(NULL, ZEND_GOTO, NULL, &label_node); + opline->extended_value = CG(context).current_brk_cont; + zend_resolve_goto_label(CG(active_op_array), opline, 0); } /* }}} */ @@ -6345,7 +6285,10 @@ void zend_compile_silence(znode *result, zend_ast *ast) /* {{{ */ { zend_ast *expr_ast = ast->child[0]; znode silence_node; + uint32_t begin_opline_num, end_opline_num; + zend_brk_cont_element *brk_cont_element; + begin_opline_num = get_next_op_number(CG(active_op_array)); zend_emit_op_tmp(&silence_node, ZEND_BEGIN_SILENCE, NULL, NULL); if (expr_ast->kind == ZEND_AST_VAR) { @@ -6356,7 +6299,15 @@ void zend_compile_silence(znode *result, zend_ast *ast) /* {{{ */ zend_compile_expr(result, expr_ast); } + end_opline_num = get_next_op_number(CG(active_op_array)); zend_emit_op(NULL, ZEND_END_SILENCE, &silence_node, NULL); + + /* Store BEGIN_SILENCE/END_SILENCE pair to restore previous + * EG(error_reporting) value on exception */ + brk_cont_element = get_next_brk_cont_element(CG(active_op_array)); + brk_cont_element->start = begin_opline_num; + brk_cont_element->cont = brk_cont_element->brk = end_opline_num; + brk_cont_element->parent = -1; } /* }}} */ @@ -6684,6 +6635,10 @@ static void zend_compile_encaps_list(znode *result, zend_ast *ast) /* {{{ */ GET_NODE(result, opline->result); } else { uint32_t var; + zend_brk_cont_element *info = get_next_brk_cont_element(CG(active_op_array)); + info->start = rope_init_lineno; + info->parent = CG(context).current_brk_cont; + info->cont = info->brk = opline - CG(active_op_array)->opcodes; init_opline->extended_value = j; opline->opcode = ZEND_ROPE_END; |