|
// 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 ILCompiler.DependencyAnalysis.ReadyToRun;
using Internal.JitInterface;
using Internal.TypeSystem;
using Internal.TypeSystem.Ecma;
using Internal.ReadyToRunConstants;
using Internal.Text;
using System.Diagnostics;
namespace ILCompiler.DependencyAnalysis
{
public enum ReadyToRunHelperId
{
Invalid,
NewHelper,
NewArr1,
IsInstanceOf,
CastClass,
GetNonGCStaticBase,
GetGCStaticBase,
GetThreadStaticBase,
GetThreadNonGcStaticBase,
CctorTrigger,
//// The following helpers are used for generic lookups only
TypeHandle,
DeclaringTypeHandle,
MethodHandle,
FieldHandle,
MethodDictionary,
TypeDictionary,
MethodEntry,
VirtualDispatchCell,
}
public sealed class ReadyToRunSymbolNodeFactory
{
private readonly NodeFactory _codegenNodeFactory;
private readonly bool _verifyTypeAndFieldLayout;
public bool VerifyTypeAndFieldLayout => _verifyTypeAndFieldLayout;
public ReadyToRunSymbolNodeFactory(NodeFactory codegenNodeFactory, bool verifyTypeAndFieldLayout)
{
_codegenNodeFactory = codegenNodeFactory;
_verifyTypeAndFieldLayout = verifyTypeAndFieldLayout;
CreateNodeCaches();
}
private void CreateNodeCaches()
{
_importStrings = new NodeCache<ModuleToken, Import>(key =>
{
return new StringImport(_codegenNodeFactory.StringImports, key);
});
_r2rHelpers = new NodeCache<ReadyToRunHelperKey, Import>(CreateReadyToRunHelper);
_instructionSetSupportFixups = new NodeCache<string, Import>(key =>
{
return new PrecodeHelperImport(
_codegenNodeFactory,
new ReadyToRunInstructionSetSupportSignature(key));
});
_resumptionStubEntryPointFixups = new NodeCache<MethodWithGCInfo, Import>(key =>
{
return new PrecodeHelperImport(
_codegenNodeFactory,
new ResumptionStubEntryPointSignature(key));
});
_fieldAddressCache = new NodeCache<FieldWithToken, Import>(key =>
{
return new DelayLoadHelperImport(
_codegenNodeFactory,
_codegenNodeFactory.HelperImports,
ReadyToRunHelper.DelayLoad_Helper,
new FieldFixupSignature(ReadyToRunFixupKind.FieldAddress, key, _codegenNodeFactory)
);
});
_fieldOffsetCache = new NodeCache<FieldWithToken, Import>(key =>
{
return new PrecodeHelperImport(
_codegenNodeFactory,
new FieldFixupSignature(ReadyToRunFixupKind.FieldOffset, key, _codegenNodeFactory)
);
});
_fieldBaseOffsetCache = new NodeCache<TypeDesc, Import>(key =>
{
return new PrecodeHelperImport(
_codegenNodeFactory,
_codegenNodeFactory.TypeSignature(ReadyToRunFixupKind.FieldBaseOffset, key)
);
});
_rvaFieldAddressCache = new NodeCache<FieldWithToken, Import>(key =>
{
return new PrecodeHelperImport(
_codegenNodeFactory,
new FieldFixupSignature(ReadyToRunFixupKind.FieldAddress, key, _codegenNodeFactory)
);
});
_checkFieldOffsetCache = new NodeCache<FieldWithToken, Import>(key =>
{
return new PrecodeHelperImport(
_codegenNodeFactory,
new FieldFixupSignature(_verifyTypeAndFieldLayout ? ReadyToRunFixupKind.Verify_FieldOffset : ReadyToRunFixupKind.Check_FieldOffset, key, _codegenNodeFactory)
);
});
_interfaceDispatchCells = new NodeCache<MethodAndCallSite, Import>(cellKey =>
{
return new DelayLoadHelperMethodImport(
_codegenNodeFactory,
_codegenNodeFactory.DispatchImports,
ReadyToRunHelper.DelayLoad_MethodCall,
cellKey.Method,
useVirtualCall: true,
useInstantiatingStub: false,
_codegenNodeFactory.MethodSignature(ReadyToRunFixupKind.VirtualEntry,
cellKey.Method,
isInstantiatingStub: false),
cellKey.CallingMethod);
});
_delegateCtors = new NodeCache<TypeAndMethod, Import>(ctorKey =>
{
IMethodNode targetMethodNode = _codegenNodeFactory.MethodEntrypoint(
ctorKey.Method,
isInstantiatingStub: ctorKey.Method.Method.HasInstantiation,
isPrecodeImportRequired: false,
isJumpableImportRequired: false);
return new DelayLoadHelperImport(
_codegenNodeFactory,
_codegenNodeFactory.HelperImports,
ReadyToRunHelper.DelayLoad_Helper_ObjObj,
new DelegateCtorSignature(ctorKey.Type, targetMethodNode, ctorKey.Method));
});
_checkTypeLayoutCache = new NodeCache<TypeDesc, Import>(key =>
{
return new PrecodeHelperImport(
_codegenNodeFactory,
_codegenNodeFactory.TypeSignature(_verifyTypeAndFieldLayout ? ReadyToRunFixupKind.Verify_TypeLayout: ReadyToRunFixupKind.Check_TypeLayout, key)
);
});
_virtualFunctionOverrideCache = new NodeCache<VirtualResolutionFixupSignature, Import>(key =>
{
return new PrecodeHelperImport(_codegenNodeFactory, key);
});
_ilBodyFixupsCache = new NodeCache<ILBodyFixupSignature, Import>(key => new PrecodeHelperImport(_codegenNodeFactory.ILBodyPrecodeImports, key));
_genericLookupHelpers = new NodeCache<GenericLookupKey, Import>(key =>
{
return new DelayLoadHelperImport(
_codegenNodeFactory,
_codegenNodeFactory.HelperImports,
ReadyToRunHelper.DelayLoad_Helper,
new GenericLookupSignature(
key.LookupKind,
key.FixupKind,
key.TypeArgument,
key.MethodArgument,
key.FieldArgument,
key.MethodContext));
});
_pInvokeTargetNodes = new NodeCache<PInvokeTargetKey, Import>(key =>
{
return new PrecodeHelperImport(
_codegenNodeFactory,
_codegenNodeFactory.MethodSignature(
key.IsIndirect ? ReadyToRunFixupKind.IndirectPInvokeTarget : ReadyToRunFixupKind.PInvokeTarget,
key.MethodWithToken,
isInstantiatingStub: false));
});
_continuationTypeFixups = new NodeCache<AsyncContinuationType, ISymbolNode>((key) =>
{
return new PrecodeHelperImport(
_codegenNodeFactory,
_codegenNodeFactory.TypeSignature(ReadyToRunFixupKind.ContinuationLayout, key)
);
});
_ecmaModuleFixupCache = new NodeCache<IEcmaModule, Import>(key =>
{
return new PrecodeHelperImport(
_codegenNodeFactory,
new ReadyToRunModuleSignature(key));
});
}
private NodeCache<AsyncContinuationType, ISymbolNode> _continuationTypeFixups;
public ISymbolNode ContinuationTypeSymbol(AsyncContinuationType key)
{
return _continuationTypeFixups.GetOrAdd(key);
}
private NodeCache<ModuleToken, Import> _importStrings;
public Import StringLiteral(ModuleToken moduleToken)
{
return _importStrings.GetOrAdd(moduleToken);
}
private struct ReadyToRunHelperKey
{
public readonly ReadyToRunHelperId Id;
public readonly object Target;
public ReadyToRunHelperKey(ReadyToRunHelperId id, object target)
{
Id = id;
Target = target;
}
public bool Equals(ReadyToRunHelperKey other)
{
return Id == other.Id && Target.Equals(other.Target);
}
public override bool Equals(object obj)
{
return obj is ReadyToRunHelperKey other && Equals(other);
}
public override int GetHashCode()
{
return Id.GetHashCode() ^ (Target.GetHashCode() * 23);
}
}
private NodeCache<ReadyToRunHelperKey, Import> _r2rHelpers;
private Import CreateReadyToRunHelper(ReadyToRunHelperKey key)
{
switch (key.Id)
{
case ReadyToRunHelperId.NewHelper:
return CreateNewHelper((TypeDesc)key.Target);
case ReadyToRunHelperId.NewArr1:
return CreateNewArrayHelper((ArrayType)key.Target);
case ReadyToRunHelperId.GetGCStaticBase:
return CreateGCStaticBaseHelper((TypeDesc)key.Target);
case ReadyToRunHelperId.GetNonGCStaticBase:
return CreateNonGCStaticBaseHelper((TypeDesc)key.Target);
case ReadyToRunHelperId.GetThreadStaticBase:
return CreateThreadGcStaticBaseHelper((TypeDesc)key.Target);
case ReadyToRunHelperId.GetThreadNonGcStaticBase:
return CreateThreadNonGcStaticBaseHelper((TypeDesc)key.Target);
case ReadyToRunHelperId.IsInstanceOf:
return CreateIsInstanceOfHelper((TypeDesc)key.Target);
case ReadyToRunHelperId.CastClass:
return CreateCastClassHelper((TypeDesc)key.Target);
case ReadyToRunHelperId.TypeHandle:
return CreateTypeHandleHelper((TypeDesc)key.Target);
case ReadyToRunHelperId.MethodHandle:
return CreateMethodHandleHelper((MethodWithToken)key.Target);
case ReadyToRunHelperId.FieldHandle:
return CreateFieldHandleHelper((FieldWithToken)key.Target);
case ReadyToRunHelperId.CctorTrigger:
return CreateCctorTrigger((TypeDesc)key.Target);
case ReadyToRunHelperId.TypeDictionary:
return CreateTypeDictionary((TypeDesc)key.Target);
case ReadyToRunHelperId.MethodDictionary:
return CreateMethodDictionary((MethodWithToken)key.Target);
default:
throw new NotImplementedException(key.Id.ToString());
}
}
public Import CreateReadyToRunHelper(ReadyToRunHelperId id, object target)
{
return _r2rHelpers.GetOrAdd(new ReadyToRunHelperKey(id, target));
}
private NodeCache<string, Import> _instructionSetSupportFixups;
private NodeCache<MethodWithGCInfo, Import> _resumptionStubEntryPointFixups;
public Import PerMethodInstructionSetSupportFixup(InstructionSetSupport instructionSetSupport)
{
string key = ReadyToRunInstructionSetSupportSignature.ToInstructionSetSupportString(instructionSetSupport);
return _instructionSetSupportFixups.GetOrAdd(key);
}
private Import CreateNewHelper(TypeDesc type)
{
return new DelayLoadHelperImport(
_codegenNodeFactory,
_codegenNodeFactory.HelperImports,
ReadyToRunHelper.DelayLoad_Helper,
new NewObjectFixupSignature(type));
}
private Import CreateNewArrayHelper(ArrayType type)
{
return new DelayLoadHelperImport(
_codegenNodeFactory,
_codegenNodeFactory.HelperImports,
ReadyToRunHelper.DelayLoad_Helper,
new NewArrayFixupSignature(type));
}
private Import CreateGCStaticBaseHelper(TypeDesc type)
{
return new DelayLoadHelperImport(
_codegenNodeFactory,
_codegenNodeFactory.HelperImports,
ReadyToRunHelper.DelayLoad_Helper,
_codegenNodeFactory.TypeSignature(ReadyToRunFixupKind.StaticBaseGC, type));
}
private Import CreateNonGCStaticBaseHelper(TypeDesc type)
{
return new DelayLoadHelperImport(
_codegenNodeFactory,
_codegenNodeFactory.HelperImports,
ReadyToRunHelper.DelayLoad_Helper,
_codegenNodeFactory.TypeSignature(ReadyToRunFixupKind.StaticBaseNonGC, type));
}
private Import CreateThreadGcStaticBaseHelper(TypeDesc type)
{
return new DelayLoadHelperImport(
_codegenNodeFactory,
_codegenNodeFactory.HelperImports,
ReadyToRunHelper.DelayLoad_Helper,
_codegenNodeFactory.TypeSignature(ReadyToRunFixupKind.ThreadStaticBaseGC, type));
}
private Import CreateThreadNonGcStaticBaseHelper(TypeDesc type)
{
return new DelayLoadHelperImport(
_codegenNodeFactory,
_codegenNodeFactory.HelperImports,
ReadyToRunHelper.DelayLoad_Helper,
_codegenNodeFactory.TypeSignature(ReadyToRunFixupKind.ThreadStaticBaseNonGC, type));
}
private Import CreateIsInstanceOfHelper(TypeDesc type)
{
return new DelayLoadHelperImport(
_codegenNodeFactory,
_codegenNodeFactory.HelperImports,
ReadyToRunHelper.DelayLoad_Helper_Obj,
_codegenNodeFactory.TypeSignature(ReadyToRunFixupKind.IsInstanceOf, type));
}
private Import CreateCastClassHelper(TypeDesc type)
{
return new DelayLoadHelperImport(
_codegenNodeFactory,
_codegenNodeFactory.HelperImports,
ReadyToRunHelper.DelayLoad_Helper_Obj,
_codegenNodeFactory.TypeSignature(ReadyToRunFixupKind.ChkCast, type));
}
private Import CreateTypeHandleHelper(TypeDesc type)
{
return new PrecodeHelperImport(
_codegenNodeFactory,
_codegenNodeFactory.TypeSignature(ReadyToRunFixupKind.TypeHandle, type));
}
private Import CreateMethodHandleHelper(MethodWithToken method)
{
bool useInstantiatingStub = method.Method.GetCanonMethodTarget(CanonicalFormKind.Specific) != method.Method;
return new PrecodeHelperImport(
_codegenNodeFactory,
_codegenNodeFactory.MethodSignature(
ReadyToRunFixupKind.MethodHandle,
method,
isInstantiatingStub: useInstantiatingStub));
}
private Import CreateFieldHandleHelper(FieldWithToken field)
{
return new PrecodeHelperImport(
_codegenNodeFactory,
new FieldFixupSignature(ReadyToRunFixupKind.FieldHandle, field, _codegenNodeFactory));
}
private Import CreateCctorTrigger(TypeDesc type)
{
return new DelayLoadHelperImport(
_codegenNodeFactory,
_codegenNodeFactory.HelperImports,
ReadyToRunHelper.DelayLoad_Helper,
_codegenNodeFactory.TypeSignature(ReadyToRunFixupKind.CctorTrigger, type));
}
private Import CreateTypeDictionary(TypeDesc type)
{
return new PrecodeHelperImport(
_codegenNodeFactory,
_codegenNodeFactory.TypeSignature(ReadyToRunFixupKind.TypeDictionary, type)
);
}
private Import CreateMethodDictionary(MethodWithToken method)
{
return new PrecodeHelperImport(
_codegenNodeFactory,
_codegenNodeFactory.MethodSignature(
ReadyToRunFixupKind.MethodDictionary,
method,
isInstantiatingStub: true));
}
private NodeCache<FieldWithToken, Import> _fieldAddressCache;
public Import FieldAddress(FieldWithToken fieldWithToken)
{
return _fieldAddressCache.GetOrAdd(fieldWithToken);
}
private NodeCache<FieldWithToken, Import> _fieldOffsetCache;
public Import FieldOffset(FieldWithToken fieldWithToken)
{
return _fieldOffsetCache.GetOrAdd(fieldWithToken);
}
private NodeCache<FieldWithToken, Import> _checkFieldOffsetCache;
public Import CheckFieldOffset(FieldWithToken fieldWithToken)
{
return _checkFieldOffsetCache.GetOrAdd(fieldWithToken);
}
private NodeCache<TypeDesc, Import> _fieldBaseOffsetCache;
public Import FieldBaseOffset(TypeDesc typeDesc)
{
return _fieldBaseOffsetCache.GetOrAdd(typeDesc);
}
private NodeCache<FieldWithToken, Import> _rvaFieldAddressCache;
public Import RvaFieldAddress(FieldWithToken fieldWithToken)
{
return _rvaFieldAddressCache.GetOrAdd(fieldWithToken);
}
private NodeCache<MethodAndCallSite, Import> _interfaceDispatchCells = new NodeCache<MethodAndCallSite, Import>();
public Import InterfaceDispatchCell(MethodWithToken method, MethodDesc callingMethod)
{
MethodAndCallSite cellKey = new MethodAndCallSite(method, null);
return _interfaceDispatchCells.GetOrAdd(cellKey);
}
private NodeCache<TypeAndMethod, Import> _delegateCtors = new NodeCache<TypeAndMethod, Import>();
public Import DelegateCtor(TypeDesc delegateType, MethodWithToken method)
{
TypeAndMethod ctorKey = new TypeAndMethod(
delegateType,
method,
isInstantiatingStub: false,
isPrecodeImportRequired: false,
isJumpableImportRequired: false);
return _delegateCtors.GetOrAdd(ctorKey);
}
private NodeCache<TypeDesc, Import> _checkTypeLayoutCache;
public Import CheckTypeLayout(TypeDesc type)
{
return _checkTypeLayoutCache.GetOrAdd(type);
}
private NodeCache<VirtualResolutionFixupSignature, Import> _virtualFunctionOverrideCache;
public Import CheckVirtualFunctionOverride(MethodWithToken declMethod, TypeDesc implType, MethodWithToken implMethod, bool checkOnly = false)
{
ReadyToRunFixupKind fixupKind = (checkOnly || !_verifyTypeAndFieldLayout) ?
ReadyToRunFixupKind.Check_VirtualFunctionOverride :
ReadyToRunFixupKind.Verify_VirtualFunctionOverride;
return _virtualFunctionOverrideCache.GetOrAdd(_codegenNodeFactory.VirtualResolutionFixupSignature(fixupKind, declMethod, implType, implMethod));
}
private NodeCache<ILBodyFixupSignature, Import> _ilBodyFixupsCache;
public Import CheckILBodyFixupSignature(MethodDesc method)
{
Debug.Assert(method.IsTypicalMethodDefinition);
return _ilBodyFixupsCache.GetOrAdd(_codegenNodeFactory.ILBodyFixupSignature(
_verifyTypeAndFieldLayout ? ReadyToRunFixupKind.Verify_IL_Body : ReadyToRunFixupKind.Check_IL_Body,
method));
}
private NodeCache<IEcmaModule, Import> _ecmaModuleFixupCache;
public Import ModuleLookup(IEcmaModule module)
{
return _ecmaModuleFixupCache.GetOrAdd(module);
}
struct MethodAndCallSite : IEquatable<MethodAndCallSite>
{
public readonly MethodWithToken Method;
public readonly MethodDesc CallingMethod;
public MethodAndCallSite(MethodWithToken method, MethodDesc callingMethod)
{
Method = method;
CallingMethod = callingMethod;
}
public bool Equals(MethodAndCallSite other)
{
return Method.Equals(other.Method) && CallingMethod == other.CallingMethod;
}
public override bool Equals(object obj)
{
return obj is MethodAndCallSite other && Equals(other);
}
public override int GetHashCode()
{
return (CallingMethod != null ? unchecked(199 * CallingMethod.GetHashCode()) : 0)
^ unchecked(31 * Method.GetHashCode());
}
}
private struct GenericLookupKey : IEquatable<GenericLookupKey>
{
public readonly CORINFO_RUNTIME_LOOKUP_KIND LookupKind;
public readonly ReadyToRunFixupKind FixupKind;
public readonly TypeDesc TypeArgument;
public readonly MethodWithToken MethodArgument;
public readonly FieldWithToken FieldArgument;
public readonly GenericContext MethodContext;
public GenericLookupKey(
CORINFO_RUNTIME_LOOKUP_KIND lookupKind,
ReadyToRunFixupKind fixupKind,
TypeDesc typeArgument,
MethodWithToken methodArgument,
FieldWithToken fieldArgument,
GenericContext methodContext)
{
LookupKind = lookupKind;
FixupKind = fixupKind;
TypeArgument = typeArgument;
MethodArgument = methodArgument;
FieldArgument = fieldArgument;
MethodContext = methodContext;
}
public bool Equals(GenericLookupKey other)
{
return LookupKind == other.LookupKind &&
FixupKind == other.FixupKind &&
RuntimeDeterminedTypeHelper.Equals(TypeArgument, other.TypeArgument) &&
RuntimeDeterminedTypeHelper.Equals(MethodArgument, other.MethodArgument) &&
RuntimeDeterminedTypeHelper.Equals(FieldArgument, other.FieldArgument) &&
MethodContext.Equals(other.MethodContext);
}
public override bool Equals(object obj)
{
return obj is GenericLookupKey other && Equals(other);
}
public override int GetHashCode()
{
return unchecked(((int)LookupKind << 24) +
(int)FixupKind +
(TypeArgument != null ? 31 * RuntimeDeterminedTypeHelper.GetHashCode(TypeArgument) : 0) +
(MethodArgument != null ? 31 * RuntimeDeterminedTypeHelper.GetHashCode(MethodArgument) : 0) +
(FieldArgument != null ? 31 * RuntimeDeterminedTypeHelper.GetHashCode(FieldArgument) : 0) +
MethodContext.GetHashCode());
}
}
private NodeCache<GenericLookupKey, Import> _genericLookupHelpers;
public Import GenericLookupHelper(
CORINFO_RUNTIME_LOOKUP_KIND runtimeLookupKind,
ReadyToRunHelperId helperId,
object helperArgument,
GenericContext methodContext)
{
switch (helperId)
{
case ReadyToRunHelperId.TypeHandle:
return GenericLookupTypeHelper(
runtimeLookupKind,
ReadyToRunFixupKind.TypeHandle,
helperArgument,
methodContext);
case ReadyToRunHelperId.MethodHandle:
return GenericLookupMethodHelper(
runtimeLookupKind,
ReadyToRunFixupKind.MethodHandle,
(MethodWithToken)helperArgument,
methodContext);
case ReadyToRunHelperId.MethodEntry:
return GenericLookupMethodHelper(
runtimeLookupKind,
ReadyToRunFixupKind.MethodEntry,
(MethodWithToken)helperArgument,
methodContext);
case ReadyToRunHelperId.MethodDictionary:
return GenericLookupMethodHelper(
runtimeLookupKind,
ReadyToRunFixupKind.MethodHandle,
(MethodWithToken)helperArgument,
methodContext);
case ReadyToRunHelperId.TypeDictionary:
return GenericLookupTypeHelper(
runtimeLookupKind,
ReadyToRunFixupKind.TypeDictionary,
(TypeDesc)helperArgument,
methodContext);
case ReadyToRunHelperId.VirtualDispatchCell:
return GenericLookupMethodHelper(
runtimeLookupKind,
ReadyToRunFixupKind.VirtualEntry,
(MethodWithToken)helperArgument,
methodContext);
case ReadyToRunHelperId.FieldHandle:
return GenericLookupFieldHelper(
runtimeLookupKind,
ReadyToRunFixupKind.FieldHandle,
(FieldWithToken)helperArgument,
methodContext);
default:
throw new NotImplementedException(helperId.ToString());
}
}
private Import GenericLookupTypeHelper(
CORINFO_RUNTIME_LOOKUP_KIND runtimeLookupKind,
ReadyToRunFixupKind fixupKind,
object helperArgument,
GenericContext methodContext)
{
TypeDesc typeArgument;
if (helperArgument is MethodWithToken methodWithToken)
{
typeArgument = methodWithToken.Method.OwningType;
}
else if (helperArgument is FieldWithToken fieldWithToken)
{
typeArgument = fieldWithToken.Field.OwningType;
}
else
{
typeArgument = (TypeDesc)helperArgument;
}
GenericLookupKey key = new GenericLookupKey(runtimeLookupKind, fixupKind, typeArgument, methodArgument: null, fieldArgument: null, methodContext);
return _genericLookupHelpers.GetOrAdd(key);
}
private Import GenericLookupFieldHelper(
CORINFO_RUNTIME_LOOKUP_KIND runtimeLookupKind,
ReadyToRunFixupKind fixupKind,
FieldWithToken fieldArgument,
GenericContext methodContext)
{
GenericLookupKey key = new GenericLookupKey(runtimeLookupKind, fixupKind, typeArgument: null, methodArgument: null, fieldArgument: fieldArgument, methodContext);
return _genericLookupHelpers.GetOrAdd(key);
}
private Import GenericLookupMethodHelper(
CORINFO_RUNTIME_LOOKUP_KIND runtimeLookupKind,
ReadyToRunFixupKind fixupKind,
MethodWithToken methodArgument,
GenericContext methodContext)
{
GenericLookupKey key = new GenericLookupKey(runtimeLookupKind, fixupKind, typeArgument: null, methodArgument, fieldArgument: null, methodContext);
return _genericLookupHelpers.GetOrAdd(key);
}
private struct PInvokeTargetKey : IEquatable<PInvokeTargetKey>
{
public readonly MethodWithToken MethodWithToken;
public readonly bool IsIndirect;
public PInvokeTargetKey(MethodWithToken methodWithToken, bool isIndirect)
{
MethodWithToken = methodWithToken;
IsIndirect = isIndirect;
}
public bool Equals(PInvokeTargetKey other)
{
return IsIndirect.Equals(other.IsIndirect) && MethodWithToken.Equals(other.MethodWithToken);
}
public override bool Equals(object obj)
{
return obj is PInvokeTargetKey other && Equals(other);
}
public override int GetHashCode()
{
return IsIndirect.GetHashCode() ^ (MethodWithToken.GetHashCode() * 23);
}
}
private NodeCache<PInvokeTargetKey, Import> _pInvokeTargetNodes = new NodeCache<PInvokeTargetKey, Import>();
public Import GetIndirectPInvokeTargetNode(MethodWithToken methodWithToken)
{
return _pInvokeTargetNodes.GetOrAdd(new PInvokeTargetKey(methodWithToken, isIndirect: true));
}
public Import GetPInvokeTargetNode(MethodWithToken methodWithToken)
{
return _pInvokeTargetNodes.GetOrAdd(new PInvokeTargetKey(methodWithToken, isIndirect: false));
}
internal Import ResumptionStubEntryPoint(MethodWithGCInfo resumptionStub)
{
return _resumptionStubEntryPointFixups.GetOrAdd(resumptionStub);
}
}
}
|