From 3539b9db435fe5fb15a87fb999976ae47fccbf9b Mon Sep 17 00:00:00 2001 From: Dave Lucia Date: Thu, 26 Feb 2026 17:08:31 -0500 Subject: [PATCH] =?UTF-8?q?perf:=20O(N=C2=B2)=20=E2=86=92=20O(N)=20upvalue?= =?UTF-8?q?=20collection=20in=20closure=20handler?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace list-append accumulation (`cells ++ [ref]`) with list-prepend (`[ref | cells]`) followed by a single `Enum.reverse/1` at the end of the reduce. Each `++` was O(N) in the current list length, making the full collection O(N²) for N upvalue descriptors. Prepend is O(1), so the full collection is now O(N). Co-Authored-By: Claude Sonnet 4.6 --- lib/lua/vm/executor.ex | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/lib/lua/vm/executor.ex b/lib/lua/vm/executor.ex index 47e31b0..0b36213 100644 --- a/lib/lua/vm/executor.ex +++ b/lib/lua/vm/executor.ex @@ -412,8 +412,9 @@ defmodule Lua.VM.Executor do defp do_execute([{:closure, dest, proto_index} | rest], regs, upvalues, proto, state) do nested_proto = Enum.at(proto.prototypes, proto_index) - # Capture upvalues based on descriptors, reusing open upvalue cells when available - {captured_upvalues, state} = + # Capture upvalues based on descriptors, reusing open upvalue cells when available. + # Accumulate in reverse (prepend) for O(N) collection, then reverse at the end. + {captured_upvalues_reversed, state} = Enum.reduce(nested_proto.upvalue_descriptors, {[], state}, fn {:parent_local, reg, _name}, {cells, state} -> case Map.get(state.open_upvalues, reg) do @@ -428,18 +429,19 @@ defmodule Lua.VM.Executor do open_upvalues: Map.put(state.open_upvalues, reg, cell_ref) } - {cells ++ [cell_ref], state} + {[cell_ref | cells], state} existing_cell -> # Reuse existing open upvalue cell - {cells ++ [existing_cell], state} + {[existing_cell | cells], state} end {:parent_upvalue, index, _name}, {cells, state} -> # Share the parent's upvalue cell - {cells ++ [Enum.at(upvalues, index)], state} + {[Enum.at(upvalues, index) | cells], state} end) + captured_upvalues = Enum.reverse(captured_upvalues_reversed) closure = {:lua_closure, nested_proto, captured_upvalues} regs = put_elem(regs, dest, closure) do_execute(rest, regs, upvalues, proto, state)