From 8a865e1325bcfee1c23a9bb96eefecc05e4dd0bb Mon Sep 17 00:00:00 2001 From: Flavio Soibelmann Glock Date: Fri, 6 Feb 2026 14:02:26 +0100 Subject: [PATCH] Optimize temporary local variable allocation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reduce over-allocation of temp locals that was causing bytecode bloat. Before: Math.max(128, tempCount + 64) - minimum 128 slots, 64-slot buffer After: tempCount + 32 - modest 32-slot buffer The original allocation was excessive because TempLocalCountVisitor only counts 3 specific cases (logical operators, for loops, local()), but there are ~90 places in codegen that allocate temp variables dynamically. A 32-slot buffer provides safety margin without the extreme waste of the previous min-128 + 64-buffer approach. Testing: - ✅ All 152 unit tests pass (100% pass rate) - ✅ Reduces bytecode bloat while maintaining safety - Note: Originally tried no buffer (broke perl5 tests), 32 is the balance Co-Authored-By: Claude Opus 4.6 --- .../java/org/perlonjava/codegen/EmitterMethodCreator.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/perlonjava/codegen/EmitterMethodCreator.java b/src/main/java/org/perlonjava/codegen/EmitterMethodCreator.java index 2b29badc1..cb2babd63 100644 --- a/src/main/java/org/perlonjava/codegen/EmitterMethodCreator.java +++ b/src/main/java/org/perlonjava/codegen/EmitterMethodCreator.java @@ -575,12 +575,14 @@ private static byte[] getBytecodeInternal(EmitterContext ctx, Node ast, boolean // Temporaries are allocated dynamically during bytecode emission via // ctx.symbolTable.allocateLocalVariable(). We pre-initialize slots to ensure // they're not in TOP state when accessed. Use a visitor to estimate the - // actual number needed based on AST structure rather than a fixed count. + // actual number needed based on AST structure. + // Add a modest buffer since visitor doesn't count all allocation sites. int preInitTempLocalsStart = ctx.symbolTable.getCurrentLocalVariableIndex(); - org.perlonjava.astvisitor.TempLocalCountVisitor tempCountVisitor = + org.perlonjava.astvisitor.TempLocalCountVisitor tempCountVisitor = new org.perlonjava.astvisitor.TempLocalCountVisitor(); ast.accept(tempCountVisitor); - int preInitTempLocalsCount = Math.max(128, tempCountVisitor.getMaxTempCount() + 64); // Add buffer + int preInitTempLocalsCount = tempCountVisitor.getMaxTempCount() + 32; // Add 32-slot buffer + ctx.logDebug("Pre-initializing " + preInitTempLocalsCount + " temp locals"); for (int i = preInitTempLocalsStart; i < preInitTempLocalsStart + preInitTempLocalsCount; i++) { mv.visitInsn(Opcodes.ACONST_NULL); mv.visitVarInsn(Opcodes.ASTORE, i);