From fdb23b3a768cbc182a6de33f1815de6ca77d0f62 Mon Sep 17 00:00:00 2001 From: sergeych Date: Mon, 16 Feb 2026 17:50:39 +0300 Subject: [PATCH] Reuse void slot for if statements --- .../sergeych/lyng/bytecode/BytecodeCompiler.kt | 17 +++++++++++++---- notes/fast_ops_optimizations_plan.md | 6 +++--- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/bytecode/BytecodeCompiler.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/bytecode/BytecodeCompiler.kt index 7920f0d..942dc52 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/bytecode/BytecodeCompiler.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/bytecode/BytecodeCompiler.kt @@ -86,6 +86,7 @@ class BytecodeCompiler( private val loopVarSlots = HashSet() private val loopStack = ArrayDeque() private var currentPos: Pos? = null + private var cachedVoidSlot: Int? = null private data class LoopContext( val label: String?, @@ -5623,6 +5624,17 @@ class BytecodeCompiler( private fun emitInlineBlock(stmt: BlockStatement, needResult: Boolean): CompiledValue? = emitInlineStatements(stmt.statements(), needResult) + private fun ensureVoidSlot(): Int { + val existing = cachedVoidSlot + if (existing != null) return existing + val slot = allocSlot() + val voidId = builder.addConst(BytecodeConst.ObjRef(ObjVoid)) + builder.emit(Opcode.CONST_OBJ, voidId, slot) + updateSlotType(slot, SlotType.OBJ) + cachedVoidSlot = slot + return slot + } + private fun shouldInlineBlock(stmt: BlockStatement): Boolean { return allowLocalSlots } @@ -6449,10 +6461,7 @@ class BytecodeCompiler( restoreFlowTypeOverride(elseRestore) } builder.mark(endLabel) - val slot = allocSlot() - val voidId = builder.addConst(BytecodeConst.ObjRef(ObjVoid)) - builder.emit(Opcode.CONST_OBJ, voidId, slot) - return CompiledValue(slot, SlotType.OBJ) + return CompiledValue(ensureVoidSlot(), SlotType.OBJ) } private fun updateSlotTypeByName(name: String, type: SlotType) { diff --git a/notes/fast_ops_optimizations_plan.md b/notes/fast_ops_optimizations_plan.md index def0503..01df7b9 100644 --- a/notes/fast_ops_optimizations_plan.md +++ b/notes/fast_ops_optimizations_plan.md @@ -13,9 +13,9 @@ Candidates (not started) 3) Boolean conversion (done; do not revert without review) - Skip redundant OBJ_TO_BOOL in logical AND/OR when compiler already emits BOOL. - MixedCompareBenchmarkTest: 275 ms -> 249 ms. -4) Range/loop hot path - - Keep range iteration in INT ops, avoid accidental boxing. - - Confirm loop-var slots avoid re-boxing in loop bodies. +4) Range/loop hot path (done) + - Reuse a cached ObjVoid slot for if-statements in statement context (avoids per-iteration CONST_OBJ). + - MixedCompareBenchmarkTest: 249 ms -> 247 ms. 5) String ops - Extend fast path for string comparisons in hot loops. 6) Box/unbox audit