diff options
author | Dmitry Stogov <dmitry@zend.com> | 2015-07-10 04:44:21 +0300 |
---|---|---|
committer | Dmitry Stogov <dmitry@zend.com> | 2015-07-10 04:44:21 +0300 |
commit | ef1b588f6a39bcc2c0d5fad9f2094bb011aeaf0b (patch) | |
tree | c96d23b817c0b8c745b814ea76c65404aa32f896 /Zend | |
parent | 44f7348caa188d6c2b6228eaa622d0ef86b2647e (diff) | |
download | php-git-ef1b588f6a39bcc2c0d5fad9f2094bb011aeaf0b.tar.gz |
Resolve GOTO at compile time and replace it with sequnce of FREE/FE_FREE and JMP.
Diffstat (limited to 'Zend')
-rw-r--r-- | Zend/zend_compile.c | 173 | ||||
-rw-r--r-- | Zend/zend_compile.h | 5 | ||||
-rw-r--r-- | Zend/zend_opcode.c | 7 | ||||
-rw-r--r-- | Zend/zend_vm_def.h | 25 | ||||
-rw-r--r-- | Zend/zend_vm_execute.h | 35 | ||||
-rw-r--r-- | Zend/zend_vm_opcodes.c | 2 | ||||
-rw-r--r-- | Zend/zend_vm_opcodes.h | 1 |
7 files changed, 125 insertions, 123 deletions
diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 44807d359b..ce5d748118 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -32,6 +32,7 @@ #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; \ @@ -874,61 +875,6 @@ 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) /* {{{ */ @@ -3652,16 +3598,125 @@ 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 (op_array->brk_cont_array[current].start >= 0) { + zend_emit_op(NULL, ZEND_NOP, NULL, NULL); + } + current = op_array->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 (op_array->brk_cont_array[current].start >= 0) { + if (pass2_opline) { + free_vars++; + } else { + generate_free_loop_var(loop_var); + loop_var--; + } + } + current = op_array->brk_cont_array[current].parent; + } + + if (pass2_opline) { + if (free_vars) { + current = pass2_opline->extended_value; + while (current != dest->brk_cont) { + if (op_array->brk_cont_array[current].start >= 0) { + zend_op *brk_opline = &op_array->opcodes[op_array->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 = op_array->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); - 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); + zend_resolve_goto_label(CG(active_op_array), &label_node, NULL); } /* }}} */ diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index 8e9cfe795b..a5e5ddece5 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -712,7 +712,7 @@ void zend_do_extended_fcall_end(void); void zend_verify_namespace(void); -void zend_resolve_goto_label(zend_op_array *op_array, zend_op *opline, int pass2); +void zend_resolve_goto_label(zend_op_array *op_array, znode *label_node, zend_op *pass2_opline); ZEND_API void function_add_ref(zend_function *function); @@ -953,7 +953,8 @@ static zend_always_inline int zend_check_arg_send_type(const zend_function *zf, #define ZEND_ARRAY_SIZE_SHIFT 2 /* Pseudo-opcodes that are used only temporarily during compilation */ -#define ZEND_BRK 254 +#define ZEND_GOTO 253 +#define ZEND_BRK 254 #define ZEND_CONT 255 diff --git a/Zend/zend_opcode.c b/Zend/zend_opcode.c index a971a5e900..62b58b4e57 100644 --- a/Zend/zend_opcode.c +++ b/Zend/zend_opcode.c @@ -700,11 +700,8 @@ static void zend_resolve_finally_calls(zend_op_array *op_array) break; case ZEND_GOTO: if (Z_TYPE_P(CT_CONSTANT_EX(op_array, opline->op2.constant)) != IS_LONG) { - uint32_t num = opline->op2.constant; - ZEND_PASS_TWO_UPDATE_CONSTANT(op_array, opline->op2); - zend_resolve_goto_label(op_array, opline, 1); - opline->op2.constant = num; + zend_resolve_goto_label(op_array, NULL, opline); } /* break omitted intentionally */ case ZEND_JMP: @@ -787,7 +784,7 @@ ZEND_API int pass_two(zend_op_array *op_array) break; case ZEND_GOTO: if (Z_TYPE_P(RT_CONSTANT(op_array, opline->op2)) != IS_LONG) { - zend_resolve_goto_label(op_array, opline, 1); + zend_resolve_goto_label(op_array, NULL, opline); } /* break omitted intentionally */ case ZEND_JMP: diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 5ea7b8a1fa..b4eeeb43bb 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -4792,31 +4792,6 @@ ZEND_VM_HANDLER(52, ZEND_BOOL, CONST|TMPVAR|CV, ANY) ZEND_VM_NEXT_OPCODE(); } -ZEND_VM_HANDLER(100, ZEND_GOTO, ANY, CONST) -{ - USE_OPLINE - zend_brk_cont_element *el; - - SAVE_OPLINE(); - el = zend_brk_cont(Z_LVAL_P(EX_CONSTANT(opline->op2)), opline->extended_value, - &EX(func)->op_array, execute_data); - - if (el->start >= 0) { - zend_op *brk_opline = EX(func)->op_array.opcodes + el->brk; - - if (brk_opline->opcode == ZEND_FREE) { - zval_ptr_dtor_nogc(EX_VAR(brk_opline->op1.var)); - } else if (brk_opline->opcode == ZEND_FE_FREE) { - zval *var = EX_VAR(brk_opline->op1.var); - if (Z_TYPE_P(var) != IS_ARRAY && Z_FE_ITER_P(var) != (uint32_t)-1) { - zend_hash_iterator_del(Z_FE_ITER_P(var)); - } - zval_ptr_dtor_nogc(var); - } - } - ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op1)); -} - ZEND_VM_HANDLER(48, ZEND_CASE, CONST|TMPVAR|CV, CONST|TMPVAR|CV) { USE_OPLINE diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 8a6918e7ef..a84fcda647 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -2231,31 +2231,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_RECV_INIT_SPEC_CONST_HANDLER(Z ZEND_VM_NEXT_OPCODE(); } -static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_GOTO_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) -{ - USE_OPLINE - zend_brk_cont_element *el; - - SAVE_OPLINE(); - el = zend_brk_cont(Z_LVAL_P(EX_CONSTANT(opline->op2)), opline->extended_value, - &EX(func)->op_array, execute_data); - - if (el->start >= 0) { - zend_op *brk_opline = EX(func)->op_array.opcodes + el->brk; - - if (brk_opline->opcode == ZEND_FREE) { - zval_ptr_dtor_nogc(EX_VAR(brk_opline->op1.var)); - } else if (brk_opline->opcode == ZEND_FE_FREE) { - zval *var = EX_VAR(brk_opline->op1.var); - if (Z_TYPE_P(var) != IS_ARRAY && Z_FE_ITER_P(var) != (uint32_t)-1) { - zend_hash_iterator_del(Z_FE_ITER_P(var)); - } - zval_ptr_dtor_nogc(var); - } - } - ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op1)); -} - static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ADD_INTERFACE_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -47704,27 +47679,27 @@ void zend_init_opcodes_handlers(void) ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, - ZEND_GOTO_SPEC_CONST_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, - ZEND_GOTO_SPEC_CONST_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, - ZEND_GOTO_SPEC_CONST_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, - ZEND_GOTO_SPEC_CONST_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, - ZEND_GOTO_SPEC_CONST_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, diff --git a/Zend/zend_vm_opcodes.c b/Zend/zend_vm_opcodes.c index 705ab9cd29..1f26f0439e 100644 --- a/Zend/zend_vm_opcodes.c +++ b/Zend/zend_vm_opcodes.c @@ -122,7 +122,7 @@ const char *zend_vm_opcodes_map[173] = { "ZEND_FETCH_OBJ_UNSET", "ZEND_FETCH_LIST", "ZEND_FETCH_CONSTANT", - "ZEND_GOTO", + NULL, "ZEND_EXT_STMT", "ZEND_EXT_FCALL_BEGIN", "ZEND_EXT_FCALL_END", diff --git a/Zend/zend_vm_opcodes.h b/Zend/zend_vm_opcodes.h index f6de5b1b57..bb2d7717bd 100644 --- a/Zend/zend_vm_opcodes.h +++ b/Zend/zend_vm_opcodes.h @@ -130,7 +130,6 @@ END_EXTERN_C() #define ZEND_FETCH_OBJ_UNSET 97 #define ZEND_FETCH_LIST 98 #define ZEND_FETCH_CONSTANT 99 -#define ZEND_GOTO 100 #define ZEND_EXT_STMT 101 #define ZEND_EXT_FCALL_BEGIN 102 #define ZEND_EXT_FCALL_END 103 |