diff --git a/src/coreclr/tools/Common/Compiler/DependencyAnalysis/ObjectNode.cs b/src/coreclr/tools/Common/Compiler/DependencyAnalysis/ObjectNode.cs index 151fa1e8f587bf..7e6fd49eb4da53 100644 --- a/src/coreclr/tools/Common/Compiler/DependencyAnalysis/ObjectNode.cs +++ b/src/coreclr/tools/Common/Compiler/DependencyAnalysis/ObjectNode.cs @@ -68,12 +68,14 @@ public sealed override IEnumerable GetStaticDependencies(No } } - if (factory.Target.IsWasm && this is IMethodCodeNodeWithTypeSignature wasmMethodCodeNode) + if (factory.Target.IsWasm && this is INodeWithTypeSignature wasmCodeNode) { dependencies ??= new DependencyList(); - WasmTypeNode wasmTypeNode = factory.WasmTypeNode(wasmMethodCodeNode.Method); - dependencies.Add(wasmTypeNode, "Wasm Method Code Nodes Require Signature"); +WasmTypeNode wasmTypeNode = wasmCodeNode is IMethodCodeNodeWithTypeSignature methodCodeNode + ? factory.WasmTypeNode(methodCodeNode.Method) + : factory.WasmTypeNode(wasmCodeNode); + dependencies.Add(wasmTypeNode, "Wasm Code Nodes Require Signature"); } if (dependencies == null) diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/NodeFactory.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/NodeFactory.cs index a25655b2f78860..0bfa672b0823b6 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/NodeFactory.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/NodeFactory.cs @@ -1630,6 +1630,11 @@ public WasmTypeNode WasmTypeNode(MethodDesc desc) return _wasmTypeNodes.GetOrAdd(WasmLowering.GetSignature(desc).FuncType); } + public WasmTypeNode WasmTypeNode(INodeWithTypeSignature node) + { + return _wasmTypeNodes.GetOrAdd(WasmLowering.GetSignature(node).FuncType); + } + public WasmTypeNode WasmTypeNode(CorInfoWasmType[] types) { return _wasmTypeNodes.GetOrAdd(WasmFuncType.FromCorInfoSignature(types)); diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/Target_Wasm/WasmReadyToRunHelperNode.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/Target_Wasm/WasmReadyToRunHelperNode.cs index 310f7e22c3153d..7369c7ee767e38 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/Target_Wasm/WasmReadyToRunHelperNode.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/Target_Wasm/WasmReadyToRunHelperNode.cs @@ -2,16 +2,206 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.Collections.Generic; +using System.Diagnostics; using ILCompiler.DependencyAnalysis.Wasm; +using ILCompiler.ObjectWriter.WasmInstructions; + +using Internal.JitInterface; +using Internal.TypeSystem; namespace ILCompiler.DependencyAnalysis { - public partial class ReadyToRunHelperNode + public partial class ReadyToRunHelperNode : INodeWithTypeSignature { + private MethodSignature _signature; + + public MethodSignature Signature => _signature ??= InitializeWasmSignature(); + public bool IsUnmanagedCallersOnly => false; + public bool IsAsyncCall => false; + public bool HasGenericContextArg => false; + + private MethodSignature InitializeWasmSignature() + { + TypeSystemContext context = Id switch + { + ReadyToRunHelperId.DelegateCtor => ((DelegateCreationInfo)Target).DelegateType.Context, + _ => ((TypeSystemEntity)Target).Context, + }; + + TypeDesc nativeIntType = context.GetWellKnownType(WellKnownType.IntPtr); + TypeDesc[] parameters = Id switch + { + ReadyToRunHelperId.DelegateCtor => [nativeIntType, nativeIntType], + ReadyToRunHelperId.ResolveVirtualFunction => [nativeIntType], + _ => [], + }; + TypeDesc returnType = Id == ReadyToRunHelperId.DelegateCtor ? + context.GetWellKnownType(WellKnownType.Void) : nativeIntType; + + return new MethodSignature(MethodSignatureFlags.Static, genericParameterCount: 0, returnType, parameters); + } + protected override void EmitCode(NodeFactory factory, ref WasmEmitter encoder, bool relocsOnly) { - throw new NotImplementedException(); + Debug.Assert(!encoder.Is64Bit); + + List expressions = new List(); + + switch (Id) + { + case ReadyToRunHelperId.GetNonGCStaticBase: + { + MetadataType target = (MetadataType)Target; + ISymbolNode staticBase = factory.TypeNonGCStaticsSymbol(target); + + if (!factory.PreinitializationManager.HasLazyStaticConstructor(target)) + { + expressions.Add(I32.ConstRVA(staticBase)); + } + else + { + ISymbolNode helper = factory.HelperEntrypoint(HelperEntrypoint.EnsureClassConstructorRunAndReturnNonGCStaticBase); + expressions.Add(Local.Get(0)); + expressions.Add(I32.ConstRVA(staticBase)); + expressions.Add(I32.Const(NonGCStaticsNode.GetClassConstructorContextSize(factory.Target))); + expressions.Add(I32.Sub); + expressions.Add(I32.ConstRVA(staticBase)); + expressions.Add(ControlFlow.ReturnCall(helper)); + } + } + break; + + case ReadyToRunHelperId.GetThreadStaticBase: + { + MetadataType target = (MetadataType)Target; + ISortableSymbolNode index = factory.TypeThreadStaticIndex(target); + if (index is TypeThreadStaticIndexNode ti && ti.IsInlined) + { + throw new NotImplementedException(); + } + + expressions.Add(Local.Get(0)); + expressions.Add(I32.ConstRVA(index)); + expressions.Add(I32.Load(0)); + expressions.Add(I32.ConstRVA(index)); + expressions.Add(I32.Load((ulong)factory.Target.PointerSize)); + + ISymbolNode helper; + if (!factory.PreinitializationManager.HasLazyStaticConstructor(target)) + { + helper = factory.HelperEntrypoint(HelperEntrypoint.GetThreadStaticBaseForType); + } + else + { + ISymbolNode staticBase = factory.TypeNonGCStaticsSymbol(target); + expressions.Add(I32.ConstRVA(staticBase)); + expressions.Add(I32.Const(NonGCStaticsNode.GetClassConstructorContextSize(factory.Target))); + expressions.Add(I32.Sub); + helper = factory.HelperEntrypoint(HelperEntrypoint.EnsureClassConstructorRunAndReturnThreadStaticBase); + } + + expressions.Add(ControlFlow.ReturnCall(helper)); + } + break; + + case ReadyToRunHelperId.GetGCStaticBase: + { + MetadataType target = (MetadataType)Target; + ISymbolNode gcStaticBase = factory.TypeGCStaticsSymbol(target); + + if (!factory.PreinitializationManager.HasLazyStaticConstructor(target)) + { + expressions.Add(I32.ConstRVA(gcStaticBase)); + expressions.Add(I32.Load(0)); + } + else + { + ISymbolNode nonGCStaticBase = factory.TypeNonGCStaticsSymbol(target); + ISymbolNode helper = factory.HelperEntrypoint(HelperEntrypoint.EnsureClassConstructorRunAndReturnGCStaticBase); + expressions.Add(Local.Get(0)); + expressions.Add(I32.ConstRVA(nonGCStaticBase)); + expressions.Add(I32.Const(NonGCStaticsNode.GetClassConstructorContextSize(factory.Target))); + expressions.Add(I32.Sub); + expressions.Add(I32.ConstRVA(gcStaticBase)); + expressions.Add(I32.Load(0)); + expressions.Add(ControlFlow.ReturnCall(helper)); + } + } + break; + + case ReadyToRunHelperId.DelegateCtor: + { + DelegateCreationInfo target = (DelegateCreationInfo)Target; + + expressions.Add(Local.Get(0)); + expressions.Add(Local.Get(1)); + expressions.Add(Local.Get(2)); + + if (target.TargetNeedsVTableLookup) + { + Debug.Assert(!target.TargetMethod.CanMethodBeInSealedVTable(factory)); + expressions.Add(Local.Get(2)); + expressions.Add(I32.Load(0)); + + int slot = 0; + if (!relocsOnly) + { + slot = VirtualMethodSlotHelper.GetVirtualMethodSlot(factory, target.TargetMethod, target.TargetMethod.OwningType); + } + + Debug.Assert(slot != -1); + expressions.Add(I32.Load((ulong)(EETypeNode.GetVTableOffset(factory.Target.PointerSize) + (slot * factory.Target.PointerSize)))); + } + else + { + expressions.Add(I32.ConstRVA(target.GetTargetNode(factory))); + } + + if (target.Thunk is not null) + { + Debug.Assert(target.Constructor.Method.Signature.Length == 3); + expressions.Add(I32.ConstRVA(target.Thunk)); + } + else + { + Debug.Assert(target.Constructor.Method.Signature.Length == 2); + } + + expressions.Add(ControlFlow.ReturnCall(target.Constructor)); + } + break; + + case ReadyToRunHelperId.ResolveVirtualFunction: + { + MethodDesc targetMethod = (MethodDesc)Target; + if (targetMethod.OwningType.IsInterface) + { + ISymbolNode helper = factory.ExternFunctionSymbol(s_RhpResolveInterfaceMethod); + expressions.Add(Local.Get(0)); + expressions.Add(Local.Get(1)); + expressions.Add(I32.ConstRVA(factory.DispatchCell(targetMethod))); + expressions.Add(ControlFlow.ReturnCall(helper)); + } + else if (!relocsOnly) + { + expressions.Add(Local.Get(1)); + expressions.Add(I32.Load(0)); + + Debug.Assert(!targetMethod.CanMethodBeInSealedVTable(factory)); + int slot = VirtualMethodSlotHelper.GetVirtualMethodSlot(factory, targetMethod, targetMethod.OwningType); + Debug.Assert(slot != -1); + expressions.Add(I32.Load((ulong)(EETypeNode.GetVTableOffset(factory.Target.PointerSize) + (slot * factory.Target.PointerSize)))); + } + } + break; + + default: + throw new NotImplementedException(); + } + + encoder.FunctionBody = new WasmFunctionBody(WasmLowering.GetSignature(this).FuncType, expressions.ToArray()); } } } diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRunCodegenNodeFactory.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRunCodegenNodeFactory.cs index 4011785193ee40..978adbe6d9c650 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRunCodegenNodeFactory.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRunCodegenNodeFactory.cs @@ -1518,6 +1518,11 @@ public WasmTypeNode WasmTypeNode(MethodDesc method) return _wasmTypeNodes.GetOrAdd(funcType); } + public WasmTypeNode WasmTypeNode(INodeWithTypeSignature node) + { + return _wasmTypeNodes.GetOrAdd(WasmLowering.GetSignature(node).FuncType); + } + internal WasmMethodRelativeVirtualIPNode WasmMethodRelativeVirtualIP(MethodWithGCInfo method) { return _wasmMethodRelativeVirtualIPs.GetOrAdd(method);