From 545017baf35d64639f69c1be0a83f7fe0e7882cf Mon Sep 17 00:00:00 2001 From: henderkes Date: Sat, 7 Nov 2026 16:22:11 +0700 Subject: [PATCH 1/4] avoid stack accessor calls for output buffering --- main/output.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/main/output.c b/main/output.c index f7e1244a3d9d..09198e6541f5 100644 --- a/main/output.c +++ b/main/output.c @@ -1105,13 +1105,13 @@ static inline void php_output_op(int op, const char *str, size_t len) * - apply op to the one active handler; note that OG(active) might be popped off the stack on a flush * - or apply op to the handler stack */ - if (OG(active) && (obh_cnt = zend_stack_count(&OG(handlers)))) { + if (OG(active) && (obh_cnt = OG(handlers).top)) { context.in.data = (char *) str; context.in.used = len; if (obh_cnt > 1) { zend_stack_apply_with_argument(&OG(handlers), ZEND_STACK_APPLY_TOPDOWN, php_output_stack_apply_op, &context); - } else if ((active = zend_stack_top(&OG(handlers))) && (!((*active)->flags & PHP_OUTPUT_HANDLER_DISABLED))) { + } else if ((active = OG(handlers).elements) && (!((*active)->flags & PHP_OUTPUT_HANDLER_DISABLED))) { php_output_handler_op(*active, &context); } else { php_output_context_pass(&context); From be9b67d10ccc713c2aef48fcb94cac47113f692e Mon Sep 17 00:00:00 2001 From: henderkes Date: Sun, 8 Nov 2026 17:16:22 +0700 Subject: [PATCH 2/4] move to header with zend_always_inline instead --- Zend/zend_stack.c | 22 ---------------------- Zend/zend_stack.h | 22 +++++++++++++++++++--- main/output.c | 4 ++-- 3 files changed, 21 insertions(+), 27 deletions(-) diff --git a/Zend/zend_stack.c b/Zend/zend_stack.c index d999d684d05d..1ec5e5b5843c 100644 --- a/Zend/zend_stack.c +++ b/Zend/zend_stack.c @@ -41,16 +41,6 @@ ZEND_API int zend_stack_push(zend_stack *stack, const void *element) } -ZEND_API void *zend_stack_top(const zend_stack *stack) -{ - if (stack->top > 0) { - return ZEND_STACK_ELEMENT(stack, stack->top - 1); - } else { - return NULL; - } -} - - ZEND_API void zend_stack_del_top(zend_stack *stack) { --stack->top; @@ -83,18 +73,6 @@ ZEND_API void zend_stack_destroy(zend_stack *stack) } -ZEND_API void *zend_stack_base(const zend_stack *stack) -{ - return stack->elements; -} - - -ZEND_API int zend_stack_count(const zend_stack *stack) -{ - return stack->top; -} - - ZEND_API void zend_stack_apply(zend_stack *stack, int type, int (*apply_function)(void *element)) { int i; diff --git a/Zend/zend_stack.h b/Zend/zend_stack.h index 66c90f0b5217..affabf1cba35 100644 --- a/Zend/zend_stack.h +++ b/Zend/zend_stack.h @@ -37,16 +37,32 @@ typedef enum { BEGIN_EXTERN_C() ZEND_API void zend_stack_init(zend_stack *stack, int size); ZEND_API int zend_stack_push(zend_stack *stack, const void *element); -ZEND_API void *zend_stack_top(const zend_stack *stack); ZEND_API void zend_stack_del_top(zend_stack *stack); ZEND_API int zend_stack_int_top(const zend_stack *stack); ZEND_API bool zend_stack_is_empty(const zend_stack *stack); ZEND_API void zend_stack_destroy(zend_stack *stack); -ZEND_API void *zend_stack_base(const zend_stack *stack); -ZEND_API int zend_stack_count(const zend_stack *stack); ZEND_API void zend_stack_apply(zend_stack *stack, int type, int (*apply_function)(void *element)); ZEND_API void zend_stack_apply_with_argument(zend_stack *stack, zend_stack_apply_direction type, int (*apply_function)(void *element, void *arg), void *arg); ZEND_API void zend_stack_clean(zend_stack *stack, void (*func)(void *), bool free_elements); END_EXTERN_C() +static zend_always_inline void *zend_stack_top(const zend_stack *stack) +{ + if (stack->top > 0) { + return (void *) ((char *) stack->elements + stack->size * (stack->top - 1)); + } else { + return NULL; + } +} + +static zend_always_inline void *zend_stack_base(const zend_stack *stack) +{ + return stack->elements; +} + +static zend_always_inline int zend_stack_count(const zend_stack *stack) +{ + return stack->top; +} + #endif /* ZEND_STACK_H */ diff --git a/main/output.c b/main/output.c index 09198e6541f5..d56f04e0daee 100644 --- a/main/output.c +++ b/main/output.c @@ -1105,13 +1105,13 @@ static inline void php_output_op(int op, const char *str, size_t len) * - apply op to the one active handler; note that OG(active) might be popped off the stack on a flush * - or apply op to the handler stack */ - if (OG(active) && (obh_cnt = OG(handlers).top)) { + if (OG(active) && (obh_cnt = zend_stack_count(&OG(handlers)))) { context.in.data = (char *) str; context.in.used = len; if (obh_cnt > 1) { zend_stack_apply_with_argument(&OG(handlers), ZEND_STACK_APPLY_TOPDOWN, php_output_stack_apply_op, &context); - } else if ((active = OG(handlers).elements) && (!((*active)->flags & PHP_OUTPUT_HANDLER_DISABLED))) { + } else if ((active = zend_stack_base(&OG(handlers))) && (!((*active)->flags & PHP_OUTPUT_HANDLER_DISABLED))) { php_output_handler_op(*active, &context); } else { php_output_context_pass(&context); From aff5596125214ea6e36bb6333adbdb91ec83ccb6 Mon Sep 17 00:00:00 2001 From: henderkes Date: Sun, 8 Nov 2026 18:47:06 +0700 Subject: [PATCH 3/4] move macro definition --- Zend/zend_stack.c | 2 -- Zend/zend_stack.h | 3 ++- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/Zend/zend_stack.c b/Zend/zend_stack.c index 1ec5e5b5843c..f3717aae59c4 100644 --- a/Zend/zend_stack.c +++ b/Zend/zend_stack.c @@ -19,8 +19,6 @@ #include "zend.h" #include "zend_stack.h" -#define ZEND_STACK_ELEMENT(stack, n) ((void *)((char *) (stack)->elements + (stack)->size * (n))) - ZEND_API void zend_stack_init(zend_stack *stack, int size) { stack->size = size; diff --git a/Zend/zend_stack.h b/Zend/zend_stack.h index affabf1cba35..6aeb8cf16310 100644 --- a/Zend/zend_stack.h +++ b/Zend/zend_stack.h @@ -28,6 +28,7 @@ typedef struct _zend_stack { #define STACK_BLOCK_SIZE 16 +#define ZEND_STACK_ELEMENT(stack, n) ((void *)((char *) (stack)->elements + (stack)->size * (n))) typedef enum { ZEND_STACK_APPLY_TOPDOWN, @@ -49,7 +50,7 @@ END_EXTERN_C() static zend_always_inline void *zend_stack_top(const zend_stack *stack) { if (stack->top > 0) { - return (void *) ((char *) stack->elements + stack->size * (stack->top - 1)); + return ZEND_STACK_ELEMENT(stack, stack->top - 1); } else { return NULL; } From 2a5b48dd46a3539c2956757f1aea838878a77e19 Mon Sep 17 00:00:00 2001 From: henderkes Date: Sun, 8 Nov 2026 18:51:33 +0700 Subject: [PATCH 4/4] move other small functions too --- Zend/zend_stack.c | 12 ------------ Zend/zend_stack.h | 12 ++++++++++-- 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/Zend/zend_stack.c b/Zend/zend_stack.c index f3717aae59c4..0d9e11d9824e 100644 --- a/Zend/zend_stack.c +++ b/Zend/zend_stack.c @@ -39,12 +39,6 @@ ZEND_API int zend_stack_push(zend_stack *stack, const void *element) } -ZEND_API void zend_stack_del_top(zend_stack *stack) -{ - --stack->top; -} - - ZEND_API int zend_stack_int_top(const zend_stack *stack) { int *e = zend_stack_top(stack); @@ -56,12 +50,6 @@ ZEND_API int zend_stack_int_top(const zend_stack *stack) } -ZEND_API bool zend_stack_is_empty(const zend_stack *stack) -{ - return stack->top == 0; -} - - ZEND_API void zend_stack_destroy(zend_stack *stack) { if (stack->elements) { diff --git a/Zend/zend_stack.h b/Zend/zend_stack.h index 6aeb8cf16310..7006145ed80b 100644 --- a/Zend/zend_stack.h +++ b/Zend/zend_stack.h @@ -38,9 +38,7 @@ typedef enum { BEGIN_EXTERN_C() ZEND_API void zend_stack_init(zend_stack *stack, int size); ZEND_API int zend_stack_push(zend_stack *stack, const void *element); -ZEND_API void zend_stack_del_top(zend_stack *stack); ZEND_API int zend_stack_int_top(const zend_stack *stack); -ZEND_API bool zend_stack_is_empty(const zend_stack *stack); ZEND_API void zend_stack_destroy(zend_stack *stack); ZEND_API void zend_stack_apply(zend_stack *stack, int type, int (*apply_function)(void *element)); ZEND_API void zend_stack_apply_with_argument(zend_stack *stack, zend_stack_apply_direction type, int (*apply_function)(void *element, void *arg), void *arg); @@ -56,6 +54,16 @@ static zend_always_inline void *zend_stack_top(const zend_stack *stack) } } +static zend_always_inline void zend_stack_del_top(zend_stack *stack) +{ + --stack->top; +} + +static zend_always_inline bool zend_stack_is_empty(const zend_stack *stack) +{ + return stack->top == 0; +} + static zend_always_inline void *zend_stack_base(const zend_stack *stack) { return stack->elements;