From 882f5397f78211fe785f4c9ad7db1842116ba0ff Mon Sep 17 00:00:00 2001 From: Kelvin Nishikawa Date: Mon, 18 Nov 2024 00:58:25 -0800 Subject: [PATCH] Stack memory optimization --- Wacs.Core/Instructions/Control.cs | 4 +- Wacs.Core/Instructions/Variable.cs | 16 +++--- Wacs.Core/Runtime/ExecContext.cs | 55 ++++++++++--------- Wacs.Core/Runtime/Frame.cs | 29 ++++++++-- Wacs.Core/Runtime/Label.cs | 2 +- Wacs.Core/Runtime/RuntimeAttributes.cs | 4 ++ Wacs.Core/Runtime/WasmRuntime.cs | 5 +- Wacs.Core/Types/IndexSpace.cs | 45 ++++++++------- .../Utilities/{IReusable.cs => IPoolable.cs} | 4 +- Wacs.Core/Utilities/ObjectPoolExtension.cs | 38 +++++++++++++ Wacs.Core/Utilities/ReusableStack.cs | 4 +- ...oledObjectPolicy.cs => StackPoolPolicy.cs} | 12 ++-- Wacs.Core/Validation/WasmValidationContext.cs | 5 +- 13 files changed, 148 insertions(+), 75 deletions(-) rename Wacs.Core/Utilities/{IReusable.cs => IPoolable.cs} (91%) create mode 100644 Wacs.Core/Utilities/ObjectPoolExtension.cs rename Wacs.Core/Utilities/{LocalsSpacePooledObjectPolicy.cs => StackPoolPolicy.cs} (77%) diff --git a/Wacs.Core/Instructions/Control.cs b/Wacs.Core/Instructions/Control.cs index 9d7d9c5..418c486 100644 --- a/Wacs.Core/Instructions/Control.cs +++ b/Wacs.Core/Instructions/Control.cs @@ -723,8 +723,8 @@ public override void Execute(ExecContext context) $"Instruction return failed. Operand stack underflow"); //We're managing separate stacks, so we won't need to shift the operands // var vals = context.OpStack.PopResults(context.Frame.Type.ResultType); - var frame = context.PopFrame(); - context.ResumeSequence(frame.ContinuationAddress); + var address = context.PopFrame(); + context.ResumeSequence(address); } } diff --git a/Wacs.Core/Instructions/Variable.cs b/Wacs.Core/Instructions/Variable.cs index 3c356c4..8255aa7 100644 --- a/Wacs.Core/Instructions/Variable.cs +++ b/Wacs.Core/Instructions/Variable.cs @@ -54,7 +54,7 @@ public override string RenderText(ExecContext? context) if (!context.Frame.Locals.Contains(Index)) return $"{base.RenderText(context)} {Index.Value}"; - var value = context.Frame.Locals[Index]; + var value = context.Frame.Locals.Get(Index); string valStr = $" (;>{value}<;)"; return $"{base.RenderText(context)} {Index.Value}{valStr}"; } @@ -70,7 +70,7 @@ private static void ValidateLocalGet(IWasmValidationContext context, LocalIdx lo { context.Assert(context.Locals.Contains(localIndex), $"Instruction local.get was invalid. Context Locals did not contain {localIndex}"); - var value = context.Locals[localIndex]; + var value = context.Locals.Get(localIndex); context.OpStack.PushType(value.Type); } @@ -81,7 +81,7 @@ private static void ExecuteLocalGet(ExecContext context, LocalIdx localIndex) context.Assert( context.Frame.Locals.Contains(localIndex), $"Instruction local.get could not get Local {localIndex}"); //3. - var value = context.Frame.Locals[localIndex]; + var value = context.Frame.Locals.Get(localIndex); //4. context.OpStack.PushValue(value); } @@ -91,7 +91,7 @@ private static void ValidateLocalSet(IWasmValidationContext context, LocalIdx lo { context.Assert(context.Locals.Contains(localIndex), $"Instruction local.set was invalid. Context Locals did not contain {localIndex}"); - var value = context.Locals[localIndex]; + var value = context.Locals.Get(localIndex); context.OpStack.PopType(value.Type); } @@ -104,12 +104,12 @@ private static void ExecuteLocalSet(ExecContext context, LocalIdx localIndex) //3. context.Assert( context.OpStack.HasValue, $"Operand Stack underflow in instruction local.set"); - var localValue = context.Frame.Locals[localIndex]; + var localValue = context.Frame.Locals.Get(localIndex); var type = localValue.Type; //4. var value = context.OpStack.PopType(type); //5. - context.Frame.Locals[localIndex] = value; + context.Frame.Locals.Set(localIndex, value); } //0x22 @@ -118,7 +118,7 @@ private static void ValidateLocalTee(IWasmValidationContext context, LocalIdx lo { context.Assert(context.Locals.Contains(localIndex), $"Instruction local.tee was invalid. Context Locals did not contain {localIndex}"); - var value = context.Locals[localIndex]; + var value = context.Locals.Get(localIndex); context.OpStack.PopType(value.Type); context.OpStack.PushType(value.Type); context.OpStack.PushType(value.Type); @@ -131,7 +131,7 @@ private static void ExecuteLocalTee(ExecContext context, LocalIdx localIndex) //1. context.Assert( context.OpStack.HasValue, $"Operand Stack underflow in instruction local.tee"); - var localValue = context.Frame.Locals[localIndex]; + var localValue = context.Frame.Locals.Get(localIndex); //2. var value = context.OpStack.PopType(localValue.Type); //3. diff --git a/Wacs.Core/Runtime/ExecContext.cs b/Wacs.Core/Runtime/ExecContext.cs index 51a1f79..8757e68 100644 --- a/Wacs.Core/Runtime/ExecContext.cs +++ b/Wacs.Core/Runtime/ExecContext.cs @@ -15,6 +15,7 @@ // */ using System; +using System.Buffers; using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; @@ -51,13 +52,15 @@ public ExecContext(Store store, RuntimeAttributes? attributes = default) { Store = store; Attributes = attributes ?? new RuntimeAttributes(); - FrameStack = new(Attributes.InitialCallStack, Attributes.GrowCallStack); - LabelStack = new(Attributes.InitialCallStack * 2, Attributes.GrowCallStack); - CallStack = FrameStack.GetSubStack(); - var poolPolicy = new LocalsSpacePooledObjectPolicy(); - LocalsPool = new DefaultObjectPool(poolPolicy, Attributes.InitialCallStack); + FramePool = new DefaultObjectPool(new StackPoolPolicy(), Attributes.MaxCallStack) + .Prime(Attributes.InitialCallStack); + LocalsDataPool = ArrayPool.Create(Attributes.MaxFunctionLocals, Attributes.LocalPoolSize); + + CallStack = new (Attributes.InitialCallStack); + LabelStack = new(Attributes.InitialLabelsStack, Attributes.GrowLabelsStack); + _hostReturnSequence = new InstructionSequence( InstructionFactory.CreateInstruction(OpCode.Func) ); @@ -75,11 +78,10 @@ public ExecContext(Store store, RuntimeAttributes? attributes = default) public Store Store { get; } public OpStack OpStack { get; } - private ReusableStack FrameStack { get; } - private SubStack CallStack { get; } private ReusableStack