Skip to content

Commit 4264ebd

Browse files
ondrejmirtesstaabm
authored andcommitted
Share the method's runtime cache with fake closures of the same scope
Creating a fake closure (Closure::fromCallable(), first-class callable syntax, ReflectionMethod::getClosure()) over a method whose runtime cache was not yet initialized allocated a cold per-closure heap cache on every creation. Initialize the method's own shared cache instead - exactly what the first real call would do - so repeated closure creations reuse one warm cache. Trampolines and heap-cache functions keep the per-closure path.
1 parent df2090a commit 4264ebd

1 file changed

Lines changed: 10 additions & 0 deletions

File tree

‎Zend/zend_closures.c‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -864,6 +864,16 @@ static void zend_create_closure_ex(
864864
ptr = zend_arena_alloc(&CG(arena), func->op_array.cache_size);
865865
ZEND_MAP_PTR_SET(func->op_array.run_time_cache, ptr);
866866
closure->func.op_array.fn_flags &= ~ZEND_ACC_HEAP_RT_CACHE;
867+
} else if (!ptr
868+
&& func->common.scope == scope
869+
&& !(func->common.fn_flags & (ZEND_ACC_HEAP_RT_CACHE|ZEND_ACC_CALL_VIA_TRAMPOLINE))) {
870+
/* Fake closure over a method that has not run yet: initialize
871+
* the method's own shared runtime cache and use it, instead
872+
* of allocating a cold per-closure heap cache on every
873+
* Closure::fromCallable()/first-class callable creation. */
874+
ptr = zend_arena_alloc(&CG(arena), func->op_array.cache_size);
875+
ZEND_MAP_PTR_SET(func->op_array.run_time_cache, ptr);
876+
closure->func.op_array.fn_flags &= ~ZEND_ACC_HEAP_RT_CACHE;
867877
} else {
868878
/* Otherwise, we use a non-shared runtime cache */
869879
ptr = emalloc(func->op_array.cache_size);

0 commit comments

Comments
 (0)