|
// 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.Diagnostics;
using ILCompiler.DependencyAnalysis.X86;
using Internal.Text;
using Internal.TypeSystem;
namespace ILCompiler.DependencyAnalysis
{
/// <summary>
/// X86 specific portions of ReadyToRunHelperNode
/// </summary>
public partial class ReadyToRunHelperNode
{
protected override void EmitCode(NodeFactory factory, ref X86Emitter encoder, bool relocsOnly)
{
switch (Id)
{
case ReadyToRunHelperId.GetNonGCStaticBase:
{
MetadataType target = (MetadataType)Target;
bool hasLazyStaticConstructor = factory.PreinitializationManager.HasLazyStaticConstructor(target);
if (!hasLazyStaticConstructor)
{
encoder.EmitMOV(encoder.TargetRegister.Result, factory.TypeNonGCStaticsSymbol(target));
encoder.EmitRET();
}
else
{
// The fast path check is not necessary. It is always expanded by RyuJIT.
encoder.EmitMOV(encoder.TargetRegister.Arg1, factory.TypeNonGCStaticsSymbol(target));
encoder.EmitMOV(encoder.TargetRegister.Arg0, factory.TypeNonGCStaticsSymbol(target), -NonGCStaticsNode.GetClassConstructorContextSize(factory.Target));
encoder.EmitJMP(factory.HelperEntrypoint(HelperEntrypoint.EnsureClassConstructorRunAndReturnNonGCStaticBase));
}
}
break;
case ReadyToRunHelperId.GetThreadStaticBase:
{
MetadataType target = (MetadataType)Target;
ISortableSymbolNode index = factory.TypeThreadStaticIndex(target);
if (index is TypeThreadStaticIndexNode ti && ti.IsInlined)
{
throw new NotImplementedException();
}
else
{
encoder.EmitMOV(encoder.TargetRegister.Result, index);
// First arg: address of the TypeManager slot that provides the helper with
// information about module index and the type manager instance (which is used
// for initialization on first access).
AddrMode loadFromEax = new AddrMode(encoder.TargetRegister.Result, null, 0, 0, AddrModeSize.Int32);
encoder.EmitMOV(encoder.TargetRegister.Arg0, ref loadFromEax);
// Second arg: index of the type in the ThreadStatic section of the modules
AddrMode loadFromEaxAndDelta = new AddrMode(encoder.TargetRegister.Result, null, factory.Target.PointerSize, 0, AddrModeSize.Int32);
encoder.EmitMOV(encoder.TargetRegister.Arg1, ref loadFromEaxAndDelta);
ISymbolNode helper = factory.HelperEntrypoint(HelperEntrypoint.GetThreadStaticBaseForType);
if (!factory.PreinitializationManager.HasLazyStaticConstructor(target))
{
encoder.EmitJMP(helper);
}
else
{
encoder.EmitMOV(encoder.TargetRegister.Result, factory.TypeNonGCStaticsSymbol(target), -NonGCStaticsNode.GetClassConstructorContextSize(factory.Target));
AddrMode initialized = new AddrMode(encoder.TargetRegister.Result, null, 0, 0, AddrModeSize.Int32);
encoder.EmitCMP(ref initialized, 0);
encoder.EmitJE(helper);
// Add extra parameter and tail call
encoder.EmitStackDup();
AddrMode storeAtEspPlus4 = new AddrMode(Register.ESP, null, 4, 0, AddrModeSize.Int32);
encoder.EmitMOV(ref storeAtEspPlus4, encoder.TargetRegister.Result);
encoder.EmitJMP(factory.HelperEntrypoint(HelperEntrypoint.EnsureClassConstructorRunAndReturnThreadStaticBase));
}
}
}
break;
case ReadyToRunHelperId.GetGCStaticBase:
{
MetadataType target = (MetadataType)Target;
bool hasLazyStaticConstructor = factory.PreinitializationManager.HasLazyStaticConstructor(target);
encoder.EmitMOV(encoder.TargetRegister.Result, factory.TypeGCStaticsSymbol(target));
if (!hasLazyStaticConstructor)
{
AddrMode loadFromEax = new AddrMode(encoder.TargetRegister.Result, null, 0, 0, AddrModeSize.Int32);
encoder.EmitMOV(encoder.TargetRegister.Result, ref loadFromEax);
encoder.EmitRET();
}
else
{
// The fast path check is not necessary. It is always expanded by RyuJIT.
AddrMode loadFromEax = new AddrMode(encoder.TargetRegister.Result, null, 0, 0, AddrModeSize.Int32);
encoder.EmitMOV(encoder.TargetRegister.Arg1, ref loadFromEax);
encoder.EmitMOV(encoder.TargetRegister.Arg0, factory.TypeNonGCStaticsSymbol(target), -NonGCStaticsNode.GetClassConstructorContextSize(factory.Target));
encoder.EmitJMP(factory.HelperEntrypoint(HelperEntrypoint.EnsureClassConstructorRunAndReturnGCStaticBase));
}
}
break;
case ReadyToRunHelperId.DelegateCtor:
{
DelegateCreationInfo target = (DelegateCreationInfo)Target;
encoder.EmitStackDup();
if (target.TargetNeedsVTableLookup)
{
Debug.Assert(!target.TargetMethod.CanMethodBeInSealedVTable(factory));
AddrMode loadFromThisPtr = new AddrMode(encoder.TargetRegister.Arg1, null, 0, 0, AddrModeSize.Int32);
encoder.EmitMOV(encoder.TargetRegister.Result, ref loadFromThisPtr);
int slot = 0;
if (!relocsOnly)
slot = VirtualMethodSlotHelper.GetVirtualMethodSlot(factory, target.TargetMethod, target.TargetMethod.OwningType);
Debug.Assert(slot != -1);
AddrMode loadFromSlot = new AddrMode(encoder.TargetRegister.Result, null, EETypeNode.GetVTableOffset(factory.Target.PointerSize) + (slot * factory.Target.PointerSize), 0, AddrModeSize.Int32);
encoder.EmitMOV(encoder.TargetRegister.Result, ref loadFromSlot);
}
else
{
encoder.EmitMOV(encoder.TargetRegister.Result, target.GetTargetNode(factory));
}
AddrMode storeAtEspPlus4 = new AddrMode(Register.ESP, null, 4, 0, AddrModeSize.Int32);
if (target.Thunk != null)
{
Debug.Assert(target.Constructor.Method.Signature.Length == 3);
AddrMode storeAtEspPlus8 = new AddrMode(Register.ESP, null, 8, 0, AddrModeSize.Int32);
encoder.EmitStackDup();
encoder.EmitMOV(ref storeAtEspPlus8, encoder.TargetRegister.Result);
encoder.EmitMOV(ref storeAtEspPlus4, target.Thunk);
}
else
{
Debug.Assert(target.Constructor.Method.Signature.Length == 2);
encoder.EmitMOV(ref storeAtEspPlus4, encoder.TargetRegister.Result);
}
encoder.EmitJMP(target.Constructor);
}
break;
case ReadyToRunHelperId.ResolveVirtualFunction:
{
MethodDesc targetMethod = (MethodDesc)Target;
if (targetMethod.OwningType.IsInterface)
{
encoder.EmitMOV(encoder.TargetRegister.Arg1, factory.InterfaceDispatchCell(targetMethod));
encoder.EmitJMP(factory.ExternFunctionSymbol(s_RhpResolveInterfaceMethod));
}
else
{
if (relocsOnly)
break;
AddrMode loadFromThisPtr = new AddrMode(encoder.TargetRegister.Arg0, null, 0, 0, AddrModeSize.Int32);
encoder.EmitMOV(encoder.TargetRegister.Result, ref loadFromThisPtr);
Debug.Assert(!targetMethod.CanMethodBeInSealedVTable(factory));
int slot = VirtualMethodSlotHelper.GetVirtualMethodSlot(factory, targetMethod, targetMethod.OwningType);
Debug.Assert(slot != -1);
AddrMode loadFromSlot = new AddrMode(encoder.TargetRegister.Result, null, EETypeNode.GetVTableOffset(factory.Target.PointerSize) + (slot * factory.Target.PointerSize), 0, AddrModeSize.Int32);
encoder.EmitMOV(encoder.TargetRegister.Result, ref loadFromSlot);
encoder.EmitRET();
}
}
break;
default:
throw new NotImplementedException();
}
}
}
}
|