From f3443a49bda6d59147ef95dafcc425af91a63dd7 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Sun, 16 Mar 2025 21:09:43 +0100 Subject: [PATCH 1/2] Merge JMP_FRAMELESS cache slots in Optimizer/compact_literals This avoids repeated lookups in the function table for the same function name. Although this optimization is observable, i.e. defining a function via an include in between 2 JMP_FRAMELESS for the same function, this cannot be relied on already as far as I know if the optimizer runs. --- Zend/Optimizer/compact_literals.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/Zend/Optimizer/compact_literals.c b/Zend/Optimizer/compact_literals.c index 4b27aebc9d39a..90c84a99b9e5a 100644 --- a/Zend/Optimizer/compact_literals.c +++ b/Zend/Optimizer/compact_literals.c @@ -165,7 +165,7 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx HashTable hash; zend_string *key = NULL; void *checkpoint = zend_arena_checkpoint(ctx->arena); - int *const_slot, *class_slot, *func_slot, *bind_var_slot, *property_slot, *method_slot; + int *const_slot, *class_slot, *func_slot, *bind_var_slot, *property_slot, *method_slot, *jmp_slot; if (op_array->last_literal) { info = (literal_info*)zend_arena_calloc(&ctx->arena, op_array->last_literal, sizeof(literal_info)); @@ -175,6 +175,9 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx end = opline + op_array->last; while (opline < end) { switch (opline->opcode) { + case ZEND_JMP_FRAMELESS: + LITERAL_INFO(opline->op1.constant, 1); + break; case ZEND_INIT_FCALL_BY_NAME: LITERAL_INFO(opline->op2.constant, 2); break; @@ -480,13 +483,14 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx zend_hash_clean(&hash); op_array->last_literal = j; - const_slot = zend_arena_alloc(&ctx->arena, j * 6 * sizeof(int)); - memset(const_slot, -1, j * 6 * sizeof(int)); + const_slot = zend_arena_alloc(&ctx->arena, j * 7 * sizeof(int)); + memset(const_slot, -1, j * 7 * sizeof(int)); class_slot = const_slot + j; func_slot = class_slot + j; bind_var_slot = func_slot + j; property_slot = bind_var_slot + j; method_slot = property_slot + j; + jmp_slot = method_slot + j; /* Update opcodes to use new literals table */ cache_size = zend_op_array_extension_handles * sizeof(void*); @@ -774,8 +778,14 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx case ZEND_DECLARE_ANON_CLASS: case ZEND_DECLARE_CLASS_DELAYED: case ZEND_JMP_FRAMELESS: - opline->extended_value = cache_size; - cache_size += sizeof(void *); + // op1 func + if (jmp_slot[opline->op1.constant] >= 0) { + opline->extended_value = jmp_slot[opline->op1.constant]; + } else { + opline->extended_value = cache_size; + cache_size += sizeof(void *); + jmp_slot[opline->op1.constant] = opline->extended_value; + } break; case ZEND_SEND_VAL: case ZEND_SEND_VAL_EX: From 9387145d47b42852e52a104172298cdf21f8e81c Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Mon, 17 Mar 2025 19:36:31 +0100 Subject: [PATCH 2/2] split case --- Zend/Optimizer/compact_literals.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Zend/Optimizer/compact_literals.c b/Zend/Optimizer/compact_literals.c index 90c84a99b9e5a..db973572aca3a 100644 --- a/Zend/Optimizer/compact_literals.c +++ b/Zend/Optimizer/compact_literals.c @@ -777,6 +777,9 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx break; case ZEND_DECLARE_ANON_CLASS: case ZEND_DECLARE_CLASS_DELAYED: + opline->extended_value = cache_size; + cache_size += sizeof(void *); + break; case ZEND_JMP_FRAMELESS: // op1 func if (jmp_slot[opline->op1.constant] >= 0) {