summaryrefslogtreecommitdiff
path: root/Zend
diff options
context:
space:
mode:
authorDmitry Stogov <dmitry@zend.com>2015-07-10 04:44:21 +0300
committerDmitry Stogov <dmitry@zend.com>2015-07-10 04:44:21 +0300
commitef1b588f6a39bcc2c0d5fad9f2094bb011aeaf0b (patch)
treec96d23b817c0b8c745b814ea76c65404aa32f896 /Zend
parent44f7348caa188d6c2b6228eaa622d0ef86b2647e (diff)
downloadphp-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.c173
-rw-r--r--Zend/zend_compile.h5
-rw-r--r--Zend/zend_opcode.c7
-rw-r--r--Zend/zend_vm_def.h25
-rw-r--r--Zend/zend_vm_execute.h35
-rw-r--r--Zend/zend_vm_opcodes.c2
-rw-r--r--Zend/zend_vm_opcodes.h1
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