Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions Zend/zend_execute.c
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,10 @@ ZEND_API const zend_internal_function zend_pass_function = {
ZEND_API void zend_vm_stack_init(void)
{
EG(vm_stack_page_size) = ZEND_VM_STACK_PAGE_SIZE;
EG(vm_stack_page_cache) = NULL;
EG(vm_stack_page_cache_count) = 0;
EG(fiber_vm_stack_page_cache) = NULL;
EG(fiber_vm_stack_page_cache_count) = 0;
EG(vm_stack) = zend_vm_stack_new_page(ZEND_VM_STACK_PAGE_SIZE, NULL);
EG(vm_stack_top) = EG(vm_stack)->top;
EG(vm_stack_end) = EG(vm_stack)->end;
Expand All @@ -201,6 +205,10 @@ ZEND_API void zend_vm_stack_init_ex(size_t page_size)
/* page_size must be a power of 2 */
ZEND_ASSERT(page_size > 0 && (page_size & (page_size - 1)) == 0);
EG(vm_stack_page_size) = page_size;
EG(vm_stack_page_cache) = NULL;
EG(vm_stack_page_cache_count) = 0;
EG(fiber_vm_stack_page_cache) = NULL;
EG(fiber_vm_stack_page_cache_count) = 0;
EG(vm_stack) = zend_vm_stack_new_page(page_size, NULL);
EG(vm_stack_top) = EG(vm_stack)->top;
EG(vm_stack_end) = EG(vm_stack)->end;
Expand All @@ -217,6 +225,23 @@ ZEND_API void zend_vm_stack_destroy(void)
}
}

ZEND_API void zend_vm_stack_destroy_caches(void)
{
while (EG(vm_stack_page_cache) != NULL) {
zend_vm_stack cached = EG(vm_stack_page_cache);
EG(vm_stack_page_cache) = cached->prev;
efree(cached);
}
EG(vm_stack_page_cache_count) = 0;

while (EG(fiber_vm_stack_page_cache) != NULL) {
zend_vm_stack cached = EG(fiber_vm_stack_page_cache);
EG(fiber_vm_stack_page_cache) = cached->prev;
efree(cached);
}
EG(fiber_vm_stack_page_cache_count) = 0;
}

ZEND_API void* zend_vm_stack_extend(size_t size)
{
zend_vm_stack stack;
Expand Down
52 changes: 50 additions & 2 deletions Zend/zend_execute.h
Original file line number Diff line number Diff line change
Expand Up @@ -322,10 +322,41 @@ ZEND_STATIC_ASSERT(ZEND_MM_ALIGNED_SIZE(sizeof(zval)) == sizeof(zval),
ZEND_API void zend_vm_stack_init(void);
ZEND_API void zend_vm_stack_init_ex(size_t page_size);
ZEND_API void zend_vm_stack_destroy(void);
ZEND_API void zend_vm_stack_destroy_caches(void);
ZEND_API void* zend_vm_stack_extend(size_t size);

#define ZEND_FIBER_VM_STACK_SIZE (1024 * sizeof(zval))

static zend_always_inline zend_vm_stack zend_vm_stack_cached_page(size_t size) {
zend_vm_stack page;

if (size == ZEND_FIBER_VM_STACK_SIZE) {
page = EG(fiber_vm_stack_page_cache);
if (page) {
ZEND_ASSERT((size_t)((char*)page->end - (char*)page) == size);
EG(fiber_vm_stack_page_cache) = page->prev;
EG(fiber_vm_stack_page_cache_count)--;
return page;
}
} else {
page = EG(vm_stack_page_cache);
ZEND_ASSERT(!page || ((size_t)((char*)page->end - (char*)page) == size) || size != EG(vm_stack_page_size));
if (page && EXPECTED((size_t)((char*)page->end - (char*)page) == size)) {
EG(vm_stack_page_cache) = page->prev;
EG(vm_stack_page_cache_count)--;
return page;
}
}

return NULL;
}

static zend_always_inline zend_vm_stack zend_vm_stack_new_page(size_t size, zend_vm_stack prev) {
zend_vm_stack page = (zend_vm_stack)emalloc(size);
zend_vm_stack page = zend_vm_stack_cached_page(size);

if (!page) {
page = (zend_vm_stack)emalloc(size);
}

page->top = ZEND_VM_STACK_ELEMENTS(page);
page->end = (zval*)((char*)page + size);
Expand Down Expand Up @@ -421,7 +452,24 @@ static zend_always_inline void zend_vm_stack_free_call_frame_ex(uint32_t call_in
EG(vm_stack_top) = prev->top;
EG(vm_stack_end) = prev->end;
EG(vm_stack) = prev;
efree(p);
if ((size_t)((char*)p->end - (char*)p) == ZEND_FIBER_VM_STACK_SIZE) {
if (EG(fiber_vm_stack_page_cache_count) < 32) {
p->prev = EG(fiber_vm_stack_page_cache);
EG(fiber_vm_stack_page_cache) = p;
EG(fiber_vm_stack_page_cache_count)++;
} else {
efree(p);
}
} else {
if (EG(vm_stack_page_cache_count) < 32
&& (size_t)((char*)p->end - (char*)p) == EG(vm_stack_page_size)) {
p->prev = EG(vm_stack_page_cache);
EG(vm_stack_page_cache) = p;
EG(vm_stack_page_cache_count)++;
} else {
efree(p);
}
}
} else {
EG(vm_stack_top) = (zval*)call;
}
Expand Down
1 change: 1 addition & 0 deletions Zend/zend_execute_API.c
Original file line number Diff line number Diff line change
Expand Up @@ -482,6 +482,7 @@ void shutdown_executor(void) /* {{{ */
zend_hash_discard(EG(class_table), EG(persistent_classes_count));
} else {
zend_vm_stack_destroy();
zend_vm_stack_destroy_caches();

if (EG(full_tables_cleanup)) {
zend_hash_reverse_apply(EG(function_table), clean_non_persistent_function_full);
Expand Down
1 change: 0 additions & 1 deletion Zend/zend_fibers.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
#define ZEND_FIBER_GUARD_PAGES 1

#define ZEND_FIBER_DEFAULT_C_STACK_SIZE (4096 * (((sizeof(void *)) < 8) ? 256 : 512))
#define ZEND_FIBER_VM_STACK_SIZE (1024 * sizeof(zval))

BEGIN_EXTERN_C()

Expand Down
5 changes: 5 additions & 0 deletions Zend/zend_globals.h
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,11 @@ struct _zend_executor_globals {
zval *vm_stack_end;
zend_vm_stack vm_stack;
size_t vm_stack_page_size;
zend_vm_stack vm_stack_page_cache;
uint32_t vm_stack_page_cache_count;
/* Fibers use a different page size, so they need a separate cache */
zend_vm_stack fiber_vm_stack_page_cache;
uint32_t fiber_vm_stack_page_cache_count;

struct _zend_execute_data *current_execute_data;
const zend_class_entry *fake_scope; /* used to avoid checks accessing properties */
Expand Down
Loading