summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Zend/zend_closures.c15
-rw-r--r--Zend/zend_closures.h1
-rw-r--r--Zend/zend_compile.c42
-rw-r--r--Zend/zend_compile.h1
-rw-r--r--Zend/zend_types.h2
-rw-r--r--Zend/zend_variables.c53
-rw-r--r--Zend/zend_variables.h2
-rw-r--r--Zend/zend_vm_def.h31
-rw-r--r--Zend/zend_vm_execute.h56
-rw-r--r--Zend/zend_vm_opcodes.c6
-rw-r--r--Zend/zend_vm_opcodes.h3
-rw-r--r--ext/opcache/Optimizer/zend_cfg.c18
-rw-r--r--ext/opcache/Optimizer/zend_dfg.c1
-rw-r--r--ext/opcache/Optimizer/zend_dump.c3
-rw-r--r--ext/opcache/Optimizer/zend_inference.c14
-rw-r--r--ext/opcache/Optimizer/zend_ssa.c7
16 files changed, 157 insertions, 98 deletions
diff --git a/Zend/zend_closures.c b/Zend/zend_closures.c
index beca1cef07..4d3a97c0ac 100644
--- a/Zend/zend_closures.c
+++ b/Zend/zend_closures.c
@@ -570,11 +570,8 @@ ZEND_API void zend_create_closure(zval *res, zend_function *func, zend_class_ent
closure->func.common.prototype = (zend_function*)closure;
closure->func.common.fn_flags |= ZEND_ACC_CLOSURE;
if (closure->func.op_array.static_variables) {
- HashTable *static_variables = closure->func.op_array.static_variables;
-
- ALLOC_HASHTABLE(closure->func.op_array.static_variables);
- zend_hash_init(closure->func.op_array.static_variables, zend_hash_num_elements(static_variables), NULL, ZVAL_PTR_DTOR, 0);
- zend_hash_apply_with_arguments(static_variables, zval_copy_static_var, 1, closure->func.op_array.static_variables);
+ closure->func.op_array.static_variables =
+ zend_array_dup(closure->func.op_array.static_variables);
}
if (UNEXPECTED(!closure->func.op_array.run_time_cache)) {
closure->func.op_array.run_time_cache = func->op_array.run_time_cache = zend_arena_alloc(&CG(arena), func->op_array.cache_size);
@@ -629,6 +626,14 @@ ZEND_API void zend_create_fake_closure(zval *res, zend_function *func, zend_clas
}
/* }}} */
+void zend_closure_bind_var(zval *closure_zv, zend_string *var_name, zval *var) /* {{{ */
+{
+ zend_closure *closure = (zend_closure *) Z_OBJ_P(closure_zv);
+ HashTable *static_variables = closure->func.op_array.static_variables;
+ zend_hash_update(static_variables, var_name, var);
+}
+/* }}} */
+
/*
* Local variables:
* tab-width: 4
diff --git a/Zend/zend_closures.h b/Zend/zend_closures.h
index 8d4edfd37a..c6dff9b4bf 100644
--- a/Zend/zend_closures.h
+++ b/Zend/zend_closures.h
@@ -25,6 +25,7 @@
BEGIN_EXTERN_C()
void zend_register_closure_ce(void);
+void zend_closure_bind_var(zval *closure_zv, zend_string *var_name, zval *var);
extern ZEND_API zend_class_entry *zend_ce_closure;
diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c
index 3a7e0b552c..9c07afe694 100644
--- a/Zend/zend_compile.c
+++ b/Zend/zend_compile.c
@@ -2055,7 +2055,8 @@ static void zend_check_live_ranges(zend_op *opline) /* {{{ */
opline->opcode == ZEND_ROPE_END ||
opline->opcode == ZEND_END_SILENCE ||
opline->opcode == ZEND_FETCH_LIST ||
- opline->opcode == ZEND_VERIFY_RETURN_TYPE) {
+ opline->opcode == ZEND_VERIFY_RETURN_TYPE ||
+ opline->opcode == ZEND_BIND_LEXICAL) {
/* these opcodes are handled separately */
} else {
zend_find_live_range(opline, opline->op1_type, opline->op1.var);
@@ -4893,28 +4894,44 @@ void zend_compile_params(zend_ast *ast, zend_ast *return_type_ast) /* {{{ */
}
/* }}} */
-void zend_compile_closure_uses(zend_ast *ast) /* {{{ */
+static void zend_compile_closure_binding(znode *closure, zend_ast *uses_ast) /* {{{ */
{
- zend_ast_list *list = zend_ast_get_list(ast);
+ zend_ast_list *list = zend_ast_get_list(uses_ast);
uint32_t i;
for (i = 0; i < list->children; ++i) {
- zend_ast *var_ast = list->child[i];
- zend_string *name = zend_ast_get_str(var_ast);
- zend_bool by_ref = var_ast->attr;
- zval zv;
+ zend_ast *var_name_ast = list->child[i];
+ zend_string *var_name = zend_ast_get_str(var_name_ast);
+ zend_bool by_ref = var_name_ast->attr;
+ zend_op *opline;
- if (zend_string_equals_literal(name, "this")) {
+ if (zend_string_equals_literal(var_name, "this")) {
zend_error_noreturn(E_COMPILE_ERROR, "Cannot use $this as lexical variable");
}
- if (zend_is_auto_global(name)) {
+ if (zend_is_auto_global(var_name)) {
zend_error_noreturn(E_COMPILE_ERROR, "Cannot use auto-global as lexical variable");
}
- ZVAL_NULL(&zv);
- Z_CONST_FLAGS(zv) = by_ref ? IS_LEXICAL_REF : IS_LEXICAL_VAR;
+ opline = zend_emit_op(NULL, ZEND_BIND_LEXICAL, closure, NULL);
+ opline->op2_type = IS_CV;
+ opline->op2.var = lookup_cv(CG(active_op_array), zend_string_copy(var_name));
+ opline->extended_value = by_ref;
+ }
+}
+/* }}} */
+void zend_compile_closure_uses(zend_ast *ast) /* {{{ */
+{
+ zend_ast_list *list = zend_ast_get_list(ast);
+ uint32_t i;
+
+ for (i = 0; i < list->children; ++i) {
+ zend_ast *var_ast = list->child[i];
+ zend_bool by_ref = var_ast->attr;
+
+ zval zv;
+ ZVAL_NULL(&zv);
zend_compile_static_var_common(var_ast, &zv, by_ref);
}
}
@@ -5166,6 +5183,9 @@ void zend_compile_func_decl(znode *result, zend_ast *ast) /* {{{ */
zend_begin_method_decl(op_array, decl->name, has_body);
} else {
zend_begin_func_decl(result, op_array, decl);
+ if (uses_ast) {
+ zend_compile_closure_binding(result, uses_ast);
+ }
}
CG(active_op_array) = op_array;
diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h
index b157db5f63..d145ffc0a0 100644
--- a/Zend/zend_compile.h
+++ b/Zend/zend_compile.h
@@ -892,7 +892,6 @@ ZEND_API void zend_assert_valid_class_name(const zend_string *const_name);
#define ZEND_FETCH_LOCAL 0x10000000
#define ZEND_FETCH_STATIC 0x20000000
#define ZEND_FETCH_GLOBAL_LOCK 0x40000000
-#define ZEND_FETCH_LEXICAL 0x50000000
#define ZEND_FETCH_TYPE_MASK 0x70000000
diff --git a/Zend/zend_types.h b/Zend/zend_types.h
index 65360619fd..17845e0538 100644
--- a/Zend/zend_types.h
+++ b/Zend/zend_types.h
@@ -412,8 +412,6 @@ static zend_always_inline zend_uchar zval_get_type(const zval* pz) {
/* zval.u1.v.const_flags */
#define IS_CONSTANT_UNQUALIFIED 0x010
-#define IS_LEXICAL_VAR 0x020
-#define IS_LEXICAL_REF 0x040
#define IS_CONSTANT_CLASS 0x080 /* __CLASS__ in trait */
#define IS_CONSTANT_IN_NAMESPACE 0x100 /* used only in opline->extended_value */
diff --git a/Zend/zend_variables.c b/Zend/zend_variables.c
index 7f99d71a14..fa57a83e70 100644
--- a/Zend/zend_variables.c
+++ b/Zend/zend_variables.c
@@ -267,59 +267,6 @@ ZEND_API void _zval_internal_ptr_dtor_wrapper(zval *zval_ptr)
}
#endif
-ZEND_API int zval_copy_static_var(zval *p, int num_args, va_list args, zend_hash_key *key) /* {{{ */
-{
- zend_array *symbol_table;
- HashTable *target = va_arg(args, HashTable*);
- zend_bool is_ref;
- zval tmp;
-
- if (Z_CONST_FLAGS_P(p) & (IS_LEXICAL_VAR|IS_LEXICAL_REF)) {
- is_ref = Z_CONST_FLAGS_P(p) & IS_LEXICAL_REF;
-
- symbol_table = zend_rebuild_symbol_table();
- p = zend_hash_find(symbol_table, key->key);
- if (!p) {
- p = &tmp;
- ZVAL_NULL(&tmp);
- if (is_ref) {
- ZVAL_NEW_REF(&tmp, &tmp);
- zend_hash_add_new(symbol_table, key->key, &tmp);
- Z_ADDREF_P(p);
- } else {
- zend_error(E_NOTICE,"Undefined variable: %s", ZSTR_VAL(key->key));
- }
- } else {
- if (Z_TYPE_P(p) == IS_INDIRECT) {
- p = Z_INDIRECT_P(p);
- if (Z_TYPE_P(p) == IS_UNDEF) {
- if (!is_ref) {
- zend_error(E_NOTICE,"Undefined variable: %s", ZSTR_VAL(key->key));
- p = &tmp;
- ZVAL_NULL(&tmp);
- } else {
- ZVAL_NULL(p);
- }
- }
- }
- if (is_ref) {
- ZVAL_MAKE_REF(p);
- Z_ADDREF_P(p);
- } else if (Z_ISREF_P(p)) {
- ZVAL_DUP(&tmp, Z_REFVAL_P(p));
- p = &tmp;
- } else if (Z_REFCOUNTED_P(p)) {
- Z_ADDREF_P(p);
- }
- }
- } else if (Z_REFCOUNTED_P(p)) {
- Z_ADDREF_P(p);
- }
- zend_hash_add(target, key->key, p);
- return ZEND_HASH_APPLY_KEEP;
-}
-/* }}} */
-
/*
* Local variables:
* tab-width: 4
diff --git a/Zend/zend_variables.h b/Zend/zend_variables.h
index 9748a4ad24..41027d18aa 100644
--- a/Zend/zend_variables.h
+++ b/Zend/zend_variables.h
@@ -106,8 +106,6 @@ static zend_always_inline void _zval_opt_copy_ctor_no_imm(zval *zvalue ZEND_FILE
}
}
-ZEND_API int zval_copy_static_var(zval *p, int num_args, va_list args, zend_hash_key *key);
-
ZEND_API size_t zend_print_variable(zval *var);
ZEND_API void _zval_ptr_dtor(zval *zval_ptr ZEND_FILE_LINE_DC);
ZEND_API void _zval_internal_dtor_for_ptr(zval *zvalue ZEND_FILE_LINE_DC);
diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h
index 263e2fa756..0efbd93f59 100644
--- a/Zend/zend_vm_def.h
+++ b/Zend/zend_vm_def.h
@@ -7997,4 +7997,35 @@ ZEND_VM_C_LABEL(call_trampoline_end):
ZEND_VM_LEAVE();
}
+ZEND_VM_HANDLER(182, ZEND_BIND_LEXICAL, TMP, CV, REF)
+{
+ USE_OPLINE
+ zend_free_op free_op1, free_op2;
+ zval *closure, *var;
+ zend_string *var_name;
+
+ closure = GET_OP1_ZVAL_PTR(BP_VAR_R);
+ if (opline->extended_value) {
+ /* By-ref binding */
+ var = GET_OP2_ZVAL_PTR(BP_VAR_W);
+ ZVAL_MAKE_REF(var);
+ Z_ADDREF_P(var);
+ } else {
+ var = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R);
+ if (UNEXPECTED(Z_ISUNDEF_P(var))) {
+ SAVE_OPLINE();
+ var = GET_OP2_UNDEF_CV(var, BP_VAR_R);
+ if (UNEXPECTED(EG(exception))) {
+ HANDLE_EXCEPTION();
+ }
+ }
+ ZVAL_DEREF(var);
+ Z_TRY_ADDREF_P(var);
+ }
+
+ var_name = CV_DEF_OF(EX_VAR_TO_NUM(opline->op2.var));
+ zend_closure_bind_var(closure, var_name, var);
+ ZEND_VM_NEXT_OPCODE();
+}
+
ZEND_VM_DEFINE_OP(137, ZEND_OP_DATA);
diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h
index a923dffd9c..cfe8a620ad 100644
--- a/Zend/zend_vm_execute.h
+++ b/Zend/zend_vm_execute.h
@@ -14210,6 +14210,37 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_SPEC_TMP_CV_HANDLER(ZEND
ZEND_VM_RETURN();
}
+static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_BIND_LEXICAL_SPEC_TMP_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
+{
+ USE_OPLINE
+ zend_free_op free_op1;
+ zval *closure, *var;
+ zend_string *var_name;
+
+ closure = _get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1);
+ if (opline->extended_value) {
+ /* By-ref binding */
+ var = _get_zval_ptr_cv_BP_VAR_W(execute_data, opline->op2.var);
+ ZVAL_MAKE_REF(var);
+ Z_ADDREF_P(var);
+ } else {
+ var = _get_zval_ptr_cv_undef(execute_data, opline->op2.var);
+ if (UNEXPECTED(Z_ISUNDEF_P(var))) {
+ SAVE_OPLINE();
+ var = GET_OP2_UNDEF_CV(var, BP_VAR_R);
+ if (UNEXPECTED(EG(exception))) {
+ HANDLE_EXCEPTION();
+ }
+ }
+ ZVAL_DEREF(var);
+ Z_TRY_ADDREF_P(var);
+ }
+
+ var_name = CV_DEF_OF(EX_VAR_TO_NUM(opline->op2.var));
+ zend_closure_bind_var(closure, var_name, var);
+ ZEND_VM_NEXT_OPCODE();
+}
+
static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_TMP_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
USE_OPLINE
@@ -49334,6 +49365,31 @@ void zend_init_opcodes_handlers(void)
ZEND_NULL_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,
+ ZEND_NULL_HANDLER,
+ ZEND_NULL_HANDLER,
+ ZEND_NULL_HANDLER,
+ ZEND_BIND_LEXICAL_SPEC_TMP_CV_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,
+ ZEND_NULL_HANDLER,
+ ZEND_NULL_HANDLER,
+ ZEND_NULL_HANDLER,
+ ZEND_NULL_HANDLER,
+ ZEND_NULL_HANDLER,
+ ZEND_NULL_HANDLER,
+ ZEND_NULL_HANDLER,
ZEND_NULL_HANDLER
};
zend_opcode_handlers = labels;
diff --git a/Zend/zend_vm_opcodes.c b/Zend/zend_vm_opcodes.c
index 2776a80e6f..1bf19d01e3 100644
--- a/Zend/zend_vm_opcodes.c
+++ b/Zend/zend_vm_opcodes.c
@@ -21,7 +21,7 @@
#include <stdio.h>
#include <zend.h>
-static const char *zend_vm_opcodes_names[182] = {
+static const char *zend_vm_opcodes_names[183] = {
"ZEND_NOP",
"ZEND_ADD",
"ZEND_SUB",
@@ -204,9 +204,10 @@ static const char *zend_vm_opcodes_names[182] = {
"ZEND_UNSET_STATIC_PROP",
"ZEND_ISSET_ISEMPTY_STATIC_PROP",
"ZEND_FETCH_CLASS_CONSTANT",
+ "ZEND_BIND_LEXICAL",
};
-static uint32_t zend_vm_opcodes_flags[182] = {
+static uint32_t zend_vm_opcodes_flags[183] = {
0x00000000,
0x00000707,
0x00000707,
@@ -389,6 +390,7 @@ static uint32_t zend_vm_opcodes_flags[182] = {
0x00007307,
0x00027307,
0x00000373,
+ 0x00100101,
};
ZEND_API const char* zend_get_opcode_name(zend_uchar opcode) {
diff --git a/Zend/zend_vm_opcodes.h b/Zend/zend_vm_opcodes.h
index 21f48cdb2b..03793910b2 100644
--- a/Zend/zend_vm_opcodes.h
+++ b/Zend/zend_vm_opcodes.h
@@ -254,7 +254,8 @@ END_EXTERN_C()
#define ZEND_UNSET_STATIC_PROP 179
#define ZEND_ISSET_ISEMPTY_STATIC_PROP 180
#define ZEND_FETCH_CLASS_CONSTANT 181
+#define ZEND_BIND_LEXICAL 182
-#define ZEND_VM_LAST_OPCODE 181
+#define ZEND_VM_LAST_OPCODE 182
#endif
diff --git a/ext/opcache/Optimizer/zend_cfg.c b/ext/opcache/Optimizer/zend_cfg.c
index 9446954e51..9ada8df1a0 100644
--- a/ext/opcache/Optimizer/zend_cfg.c
+++ b/ext/opcache/Optimizer/zend_cfg.c
@@ -372,24 +372,6 @@ int zend_build_cfg(zend_arena **arena, const zend_op_array *op_array, uint32_t b
BB_START(OP_JMP_ADDR(opline, opline->op2) - op_array->opcodes);
BB_START(i + 1);
break;
- case ZEND_DECLARE_LAMBDA_FUNCTION: {
-//??? zend_op_array *lambda_op_array;
-//???
-//??? zv = CRT_CONSTANT(opline->op1);
-//??? if (ctx->main_script &&
-//??? (lambda_op_array = zend_hash_find_ptr(&ctx->main_script->function_table, Z_STR_P(zv))) != NULL) {
-//??? if (lambda_op_array->type == ZEND_USER_FUNCTION &&
-//??? lambda_op_array->static_variables) {
-//??? // FIXME: Really we should try to perform alias
-//??? // analysis on variables used by the closure
-//??? info->flags |= ZEND_FUNC_TOO_DYNAMIC;
-//??? }
-//??? } else {
-//??? // FIXME: how to find the lambda function?
- flags |= ZEND_FUNC_TOO_DYNAMIC;
-//??? }
- }
- break;
case ZEND_UNSET_VAR:
if (!(opline->extended_value & ZEND_QUICK_SET)) {
flags |= ZEND_FUNC_TOO_DYNAMIC;
diff --git a/ext/opcache/Optimizer/zend_dfg.c b/ext/opcache/Optimizer/zend_dfg.c
index 7c3e80db1f..ea81e288d9 100644
--- a/ext/opcache/Optimizer/zend_dfg.c
+++ b/ext/opcache/Optimizer/zend_dfg.c
@@ -99,6 +99,7 @@ int zend_build_dfg(const zend_op_array *op_array, const zend_cfg *cfg, zend_dfg
case ZEND_FE_RESET_RW:
case ZEND_ADD_ARRAY_ELEMENT:
case ZEND_INIT_ARRAY:
+ case ZEND_BIND_LEXICAL:
if (!DFG_ISSET(use, set_size, j, EX_VAR_TO_NUM(opline->op1.var))) {
// FIXME: include into "use" to ...?
DFG_SET(use, set_size, j, EX_VAR_TO_NUM(opline->op1.var));
diff --git a/ext/opcache/Optimizer/zend_dump.c b/ext/opcache/Optimizer/zend_dump.c
index 0b4848baf1..c8fb945067 100644
--- a/ext/opcache/Optimizer/zend_dump.c
+++ b/ext/opcache/Optimizer/zend_dump.c
@@ -516,9 +516,6 @@ static void zend_dump_op(const zend_op_array *op_array, const zend_basic_block *
case ZEND_FETCH_GLOBAL_LOCK:
fprintf(stderr, " (global+lock)");
break;
- case ZEND_FETCH_LEXICAL:
- fprintf(stderr, " (lexical)");
- break;
}
}
if (ZEND_VM_EXT_ISSET & flags) {
diff --git a/ext/opcache/Optimizer/zend_inference.c b/ext/opcache/Optimizer/zend_inference.c
index 8fa9bfdbb5..84abb27a53 100644
--- a/ext/opcache/Optimizer/zend_inference.c
+++ b/ext/opcache/Optimizer/zend_inference.c
@@ -3062,6 +3062,20 @@ static void zend_update_type_info(const zend_op_array *op_array,
UPDATE_SSA_OBJ_TYPE(NULL, 0, ssa_ops[i].op1_def);
}
break;
+ case ZEND_BIND_LEXICAL:
+ if (ssa_ops[i].op2_def >= 0) {
+ tmp = t2 | MAY_BE_RC1 | MAY_BE_RCN;
+ if (opline->extended_value) {
+ tmp |= MAY_BE_REF;
+ }
+ UPDATE_SSA_TYPE(tmp, ssa_ops[i].op2_def);
+ if ((t2 & MAY_BE_OBJECT) && ssa_var_info[ssa_ops[i].op2_use].ce) {
+ UPDATE_SSA_OBJ_TYPE(ssa_var_info[ssa_ops[i].op2_use].ce, ssa_var_info[ssa_ops[i].op2_use].is_instanceof, ssa_ops[i].op2_def);
+ } else {
+ UPDATE_SSA_OBJ_TYPE(NULL, 0, ssa_ops[i].op2_def);
+ }
+ }
+ break;
case ZEND_SEND_VAR_EX:
case ZEND_SEND_VAR_NO_REF:
case ZEND_SEND_REF:
diff --git a/ext/opcache/Optimizer/zend_ssa.c b/ext/opcache/Optimizer/zend_ssa.c
index 505c0b978f..de9263026b 100644
--- a/ext/opcache/Optimizer/zend_ssa.c
+++ b/ext/opcache/Optimizer/zend_ssa.c
@@ -354,6 +354,13 @@ static int zend_ssa_rename(const zend_op_array *op_array, uint32_t build_flags,
//NEW_SSA_VAR(opline->op1.var)
}
break;
+ case ZEND_BIND_LEXICAL:
+ if (opline->extended_value || (build_flags & ZEND_SSA_RC_INFERENCE)) {
+ ssa_ops[k].op2_def = ssa_vars_count;
+ var[EX_VAR_TO_NUM(opline->op2.var)] = ssa_vars_count;
+ ssa_vars_count++;
+ }
+ break;
default:
break;
}