diff --git a/Jint/Runtime/Interpreter/Statements/JintBlockStatement.cs b/Jint/Runtime/Interpreter/Statements/JintBlockStatement.cs index 020e6049d..2be32daff 100644 --- a/Jint/Runtime/Interpreter/Statements/JintBlockStatement.cs +++ b/Jint/Runtime/Interpreter/Statements/JintBlockStatement.cs @@ -79,7 +79,7 @@ public Completion ExecuteBlock(EvaluationContext context) { // Reuse environment: update outer reference and reset slots cachedEnv._outerEnv = oldEnv; - blockState.SlotTemplates.AsSpan().CopyTo(cachedEnv._slots); + ResetSlots(cachedEnv._slots!, blockState.SlotTemplates!); blockEnv = cachedEnv; } else @@ -244,6 +244,28 @@ protected override Completion ExecuteInternal(EvaluationContext context) return ExecuteBlock(context); } + /// + /// Reset the slots of a reused block environment to the pre-computed templates. + /// Hand-rolled small-array fast path: typical block scopes hold 1-3 bindings, where the + /// JIT can unroll this loop and avoid the Span construction + generic copy of CopyTo. + /// + [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] + private static void ResetSlots(Binding[] slots, Binding[] templates) + { + var len = slots.Length; + if (len == templates.Length && len <= 4) + { + for (var i = 0; i < len; i++) + { + slots[i] = templates[i]; + } + } + else + { + templates.AsSpan().CopyTo(slots); + } + } + /// /// Pre-computed block scope state, cached on AST node UserData. ///