@@ -182,7 +182,7 @@ ZEND_METHOD(Closure, call)
182
182
ZEND_METHOD (Closure , bind )
183
183
{
184
184
zval * newthis , * zclosure , * scope_arg = NULL ;
185
- zend_closure * closure , * new_closure ;
185
+ zend_closure * closure ;
186
186
zend_class_entry * ce , * called_scope ;
187
187
188
188
if (zend_parse_method_parameters (ZEND_NUM_ARGS (), getThis (), "Oo!|z" , & zclosure , zend_ce_closure , & newthis , & scope_arg ) == FAILURE ) {
@@ -223,15 +223,6 @@ ZEND_METHOD(Closure, bind)
223
223
}
224
224
225
225
zend_create_closure (return_value , & closure -> func , ce , called_scope , newthis );
226
- new_closure = (zend_closure * ) Z_OBJ_P (return_value );
227
-
228
- /* Runtime cache relies on bound scope to be immutable, hence we need a separate rt cache in case scope changed */
229
- 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 ))) {
230
- new_closure -> func .op_array .run_time_cache = emalloc (new_closure -> func .op_array .cache_size );
231
- memset (new_closure -> func .op_array .run_time_cache , 0 , new_closure -> func .op_array .cache_size );
232
-
233
- new_closure -> func .op_array .fn_flags |= ZEND_ACC_NO_RT_ARENA ;
234
- }
235
226
}
236
227
/* }}} */
237
228
@@ -667,9 +658,24 @@ ZEND_API void zend_create_closure(zval *res, zend_function *func, zend_class_ent
667
658
closure -> func .op_array .static_variables =
668
659
zend_array_dup (closure -> func .op_array .static_variables );
669
660
}
670
- if (UNEXPECTED (!closure -> func .op_array .run_time_cache )) {
671
- closure -> func .op_array .run_time_cache = func -> op_array .run_time_cache = zend_arena_alloc (& CG (arena ), func -> op_array .cache_size );
672
- memset (func -> op_array .run_time_cache , 0 , func -> op_array .cache_size );
661
+
662
+ /* Runtime cache is scope-dependent, so we cannot reuse it if the scope changed */
663
+ if (!closure -> func .op_array .run_time_cache
664
+ || func -> common .scope != scope
665
+ || (func -> common .fn_flags & ZEND_ACC_NO_RT_ARENA )
666
+ ) {
667
+ if (!func -> op_array .run_time_cache && (func -> common .fn_flags & ZEND_ACC_CLOSURE )) {
668
+ /* If a real closure is used for the first time, we create a shared runtime cache
669
+ * and remember which scope it is for. */
670
+ func -> common .scope = scope ;
671
+ func -> op_array .run_time_cache = zend_arena_alloc (& CG (arena ), func -> op_array .cache_size );
672
+ closure -> func .op_array .run_time_cache = func -> op_array .run_time_cache ;
673
+ } else {
674
+ /* Otherwise, we use a non-shared runtime cache */
675
+ closure -> func .op_array .run_time_cache = emalloc (func -> op_array .cache_size );
676
+ closure -> func .op_array .fn_flags |= ZEND_ACC_NO_RT_ARENA ;
677
+ }
678
+ memset (closure -> func .op_array .run_time_cache , 0 , func -> op_array .cache_size );
673
679
}
674
680
if (closure -> func .op_array .refcount ) {
675
681
(* closure -> func .op_array .refcount )++ ;
0 commit comments