| File: Compiler\DependencyAnalysis\Target_Wasm\WasmReadyToRunHelperNode.cs | Web Access |
| Project: ILCompiler.Compiler.csproj (ILCompiler.Compiler) |
// Licensed to the .NET Foundation under one or more agreements. // 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.ReadyToRunConstants; using Internal.TypeSystem; namespace ILCompiler.DependencyAnalysis { 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) { Debug.Assert(!encoder.Is64Bit); List<WasmExpr> expressions = new List<WasmExpr>(); 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.ReadyToRunHelper(ReadyToRunHelper.ResolveInterfaceMethod); 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()); } } }