summaryrefslogtreecommitdiff
path: root/Zend/zend_closures.c
diff options
context:
space:
mode:
authorNikita Popov <nikita.ppv@gmail.com>2018-01-15 12:13:55 +0100
committerNikita Popov <nikita.ppv@gmail.com>2018-01-15 12:15:40 +0100
commit20233469737ba007a1bdd38b7acd5512a2e7d534 (patch)
treebc0e820962e864fce6ac9adb12149db7d9f78a18 /Zend/zend_closures.c
parent089a3213ae9f0b61b19a4dc77897fa07da5298f3 (diff)
downloadphp-git-20233469737ba007a1bdd38b7acd5512a2e7d534.tar.gz
Fixed bug #75079
Diffstat (limited to 'Zend/zend_closures.c')
-rw-r--r--Zend/zend_closures.c32
1 files changed, 19 insertions, 13 deletions
diff --git a/Zend/zend_closures.c b/Zend/zend_closures.c
index 799531b6bf..01aae545d4 100644
--- a/Zend/zend_closures.c
+++ b/Zend/zend_closures.c
@@ -186,7 +186,7 @@ ZEND_METHOD(Closure, call)
ZEND_METHOD(Closure, bind)
{
zval *newthis, *zclosure, *scope_arg = NULL;
- zend_closure *closure, *new_closure;
+ zend_closure *closure;
zend_class_entry *ce, *called_scope;
if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Oo!|z", &zclosure, zend_ce_closure, &newthis, &scope_arg) == FAILURE) {
@@ -226,15 +226,6 @@ ZEND_METHOD(Closure, bind)
}
zend_create_closure(return_value, &closure->func, ce, called_scope, newthis);
- new_closure = (zend_closure *) Z_OBJ_P(return_value);
-
- /* Runtime cache relies on bound scope to be immutable, hence we need a separate rt cache in case scope changed */
- if (ZEND_USER_CODE(closure->func.type) && (closure->func.common.scope != new_closure->func.common.scope || (closure->func.op_array.fn_flags & ZEND_ACC_NO_RT_ARENA))) {
- new_closure->func.op_array.run_time_cache = emalloc(new_closure->func.op_array.cache_size);
- memset(new_closure->func.op_array.run_time_cache, 0, new_closure->func.op_array.cache_size);
-
- new_closure->func.op_array.fn_flags |= ZEND_ACC_NO_RT_ARENA;
- }
}
/* }}} */
@@ -669,9 +660,24 @@ ZEND_API void zend_create_closure(zval *res, zend_function *func, zend_class_ent
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);
- memset(func->op_array.run_time_cache, 0, func->op_array.cache_size);
+
+ /* Runtime cache is scope-dependent, so we cannot reuse it if the scope changed */
+ if (!closure->func.op_array.run_time_cache
+ || func->common.scope != scope
+ || (func->common.fn_flags & ZEND_ACC_NO_RT_ARENA)
+ ) {
+ if (!func->op_array.run_time_cache && (func->common.fn_flags & ZEND_ACC_CLOSURE)) {
+ /* If a real closure is used for the first time, we create a shared runtime cache
+ * and remember which scope it is for. */
+ func->common.scope = scope;
+ func->op_array.run_time_cache = zend_arena_alloc(&CG(arena), func->op_array.cache_size);
+ closure->func.op_array.run_time_cache = func->op_array.run_time_cache;
+ } else {
+ /* Otherwise, we use a non-shared runtime cache */
+ closure->func.op_array.run_time_cache = emalloc(func->op_array.cache_size);
+ closure->func.op_array.fn_flags |= ZEND_ACC_NO_RT_ARENA;
+ }
+ memset(closure->func.op_array.run_time_cache, 0, func->op_array.cache_size);
}
if (closure->func.op_array.refcount) {
(*closure->func.op_array.refcount)++;