diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/INodeWithCodeInfo.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/INodeWithCodeInfo.cs index ffa254e76ae..48b48e656f6 100644 --- a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/INodeWithCodeInfo.cs +++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/INodeWithCodeInfo.cs @@ -9,11 +9,12 @@ namespace ILCompiler.DependencyAnalysis [Flags] public enum FrameInfoFlags { - Handler = 0x01, - Filter = 0x02, + Handler = 0x01, + Filter = 0x02, - HasEHInfo = 0x04, - ReversePInvoke = 0x08, + HasEHInfo = 0x04, + ReversePInvoke = 0x08, + HasAssociatedData = 0x10, } public struct FrameInfo @@ -48,5 +49,7 @@ ObjectNode.ObjectData EHInfo { get; } + + ISymbolNode GetAssociatedDataNode(NodeFactory factory); } } diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ISpecialUnboxThunkNode.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ISpecialUnboxThunkNode.cs new file mode 100644 index 00000000000..3c8b62513c7 --- /dev/null +++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ISpecialUnboxThunkNode.cs @@ -0,0 +1,17 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Internal.TypeSystem; + +namespace ILCompiler.DependencyAnalysis +{ + /// + /// A dependency analysis node that represents a special instantiating unboxing stub. + /// + public interface ISpecialUnboxThunkNode : IMethodNode + { + bool IsSpecialUnboxingThunk { get; } + ISymbolNode GetUnboxingThunkTarget(NodeFactory factory); + } +} diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/MethodAssociatedDataNode.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/MethodAssociatedDataNode.cs new file mode 100644 index 00000000000..c942cf5d9b4 --- /dev/null +++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/MethodAssociatedDataNode.cs @@ -0,0 +1,83 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Diagnostics; + +using Internal.Text; +using Internal.TypeSystem; +using Internal.TypeSystem.Interop; + +namespace ILCompiler.DependencyAnalysis +{ + [Flags] + public enum AssociatedDataFlags : byte + { + None = 0, + HasUnboxingStubTarget = 1, + } + + /// + /// This node contains any custom data that we'd like to associated with a method. The unwind info of the method + /// will have a reloc to this custom data if it exists. Not all methods need custom data to be emitted. + /// This custom data excludes gcinfo and ehinfo (they are written by ObjectWriter during obj file emission). + /// + public class MethodAssociatedDataNode : ObjectNode, ISymbolDefinitionNode + { + private IMethodNode _methodNode; + + public MethodAssociatedDataNode(IMethodNode methodNode) + { + Debug.Assert(!methodNode.Method.IsAbstract); + Debug.Assert(methodNode.Method.GetCanonMethodTarget(CanonicalFormKind.Specific) == methodNode.Method); + _methodNode = methodNode; + } + + protected override string GetName(NodeFactory factory) => this.GetMangledName(factory.NameMangler); + + public override ObjectNodeSection Section => ObjectNodeSection.ReadOnlyDataSection; + public override bool StaticDependenciesAreComputed => true; + public int Offset => 0; + public override bool IsShareable => _methodNode.Method is InstantiatedMethod || EETypeNode.IsTypeNodeShareable(_methodNode.Method.OwningType); + + public virtual void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb) + { + sb.Append("_associatedData_").Append(nameMangler.GetMangledMethodName(_methodNode.Method)); + } + + public static bool MethodHasAssociatedData(NodeFactory factory, IMethodNode methodNode) + { + // Instantiating unboxing stubs. We need to store their non-unboxing target pointer (looked up by runtime) + ISpecialUnboxThunkNode unboxThunk = methodNode as ISpecialUnboxThunkNode; + if(unboxThunk != null && unboxThunk.IsSpecialUnboxingThunk) + return true; + + return false; + } + + public override ObjectData GetData(NodeFactory factory, bool relocsOnly) + { + Debug.Assert(MethodHasAssociatedData(factory, _methodNode)); + + ObjectDataBuilder objData = new ObjectDataBuilder(factory, relocsOnly); + objData.RequireInitialAlignment(1); + objData.AddSymbol(this); + + AssociatedDataFlags flags = AssociatedDataFlags.None; + + var flagsReservation = objData.ReserveByte(); + + ISpecialUnboxThunkNode unboxThunkNode = _methodNode as ISpecialUnboxThunkNode; + if (unboxThunkNode != null && unboxThunkNode.IsSpecialUnboxingThunk) + { + flags |= AssociatedDataFlags.HasUnboxingStubTarget; + objData.EmitPointerReloc(unboxThunkNode.GetUnboxingThunkTarget(factory)); + } + + objData.EmitByte(flagsReservation, (byte)flags); + + return objData.ToObjectData(); + } + } +} diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/MethodCodeNode.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/MethodCodeNode.cs index 93a2e2b4fc0..228cf240107 100644 --- a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/MethodCodeNode.cs +++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/MethodCodeNode.cs @@ -10,7 +10,7 @@ namespace ILCompiler.DependencyAnalysis { - public class MethodCodeNode : ObjectNode, IMethodBodyNode, INodeWithCodeInfo, INodeWithDebugInfo, IMethodCodeNode + public class MethodCodeNode : ObjectNode, IMethodBodyNode, INodeWithCodeInfo, INodeWithDebugInfo, IMethodCodeNode, ISpecialUnboxThunkNode { public static readonly ObjectNodeSection StartSection = new ObjectNodeSection(".managedcode$A", SectionType.Executable); public static readonly ObjectNodeSection WindowsContentSection = new ObjectNodeSection(".managedcode$I", SectionType.Executable); @@ -82,6 +82,12 @@ protected override DependencyList ComputeNonRelocationBasedDependencies(NodeFact } } + if (MethodAssociatedDataNode.MethodHasAssociatedData(factory, this)) + { + dependencies = dependencies ?? new DependencyList(); + dependencies.Add(new DependencyListEntry(factory.MethodAssociatedData(this), "Method associated data")); + } + CodeBasedDependencyAlgorithm.AddDependenciesDueToMethodCodePresence(ref dependencies, factory, _method); return dependencies; @@ -92,10 +98,28 @@ public override ObjectData GetData(NodeFactory factory, bool relocsOnly) return _methodCode; } + public bool IsSpecialUnboxingThunk => ((CompilerTypeSystemContext)Method.Context).IsSpecialUnboxingThunk(_method); + + public ISymbolNode GetUnboxingThunkTarget(NodeFactory factory) + { + Debug.Assert(IsSpecialUnboxingThunk); + + MethodDesc nonUnboxingMethod = ((CompilerTypeSystemContext)Method.Context).GetTargetOfSpecialUnboxingThunk(_method); + return factory.MethodEntrypoint(nonUnboxingMethod, false); + } + public FrameInfo[] FrameInfos => _frameInfos; public byte[] GCInfo => _gcInfo; public ObjectData EHInfo => _ehInfo; + public ISymbolNode GetAssociatedDataNode(NodeFactory factory) + { + if (MethodAssociatedDataNode.MethodHasAssociatedData(factory, this)) + return factory.MethodAssociatedData(this); + + return null; + } + public void InitializeFrameInfos(FrameInfo[] frameInfos) { Debug.Assert(_frameInfos == null); diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/NodeFactory.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/NodeFactory.cs index 9d1d693c39c..91bcfdb3497 100644 --- a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/NodeFactory.cs +++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/NodeFactory.cs @@ -296,6 +296,11 @@ private void CreateNodeCaches() _unboxingStubs = new NodeCache(CreateUnboxingStubNode); + _methodAssociatedData = new NodeCache(methodNode => + { + return new MethodAssociatedDataNode(methodNode); + }); + _fatFunctionPointers = new NodeCache(method => { return new FatFunctionPointerNode(method.Method, method.IsUnboxingStub); @@ -707,6 +712,7 @@ public IMethodNode StringAllocator(MethodDesc stringConstructor) private NodeCache _methodEntrypoints; private NodeCache _unboxingStubs; + private NodeCache _methodAssociatedData; public IMethodNode MethodEntrypoint(MethodDesc method, bool unboxingStub = false) { @@ -718,6 +724,11 @@ public IMethodNode MethodEntrypoint(MethodDesc method, bool unboxingStub = false return _methodEntrypoints.GetOrAdd(method); } + public MethodAssociatedDataNode MethodAssociatedData(IMethodNode methodNode) + { + return _methodAssociatedData.GetOrAdd(methodNode); + } + private NodeCache _fatFunctionPointers; public IMethodNode FatFunctionPointer(MethodDesc method, bool isUnboxingStub = false) diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/NonExternMethodSymbolNode.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/NonExternMethodSymbolNode.cs index 2dedef7c394..c39eda7e049 100644 --- a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/NonExternMethodSymbolNode.cs +++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/NonExternMethodSymbolNode.cs @@ -17,9 +17,10 @@ namespace ILCompiler.DependencyAnalysis /// in the DependencyAnalysis infrastructure during compilation that is compiled /// in the current compilation process /// - public class NonExternMethodSymbolNode : ExternSymbolNode, IMethodBodyNodeWithFuncletSymbols + public class NonExternMethodSymbolNode : ExternSymbolNode, IMethodBodyNodeWithFuncletSymbols, ISpecialUnboxThunkNode { private MethodDesc _method; + private bool _isUnboxing; private List _compilationDiscoveredDependencies; ISymbolNode[] _funcletSymbols = Array.Empty(); bool _dependenciesQueried; @@ -29,6 +30,7 @@ public NonExternMethodSymbolNode(NodeFactory factory, MethodDesc method, bool is : base(isUnboxing ? UnboxingStubNode.GetMangledName(factory.NameMangler, method) : factory.NameMangler.GetMangledMethodName(method)) { + _isUnboxing = isUnboxing; _method = method; } @@ -42,6 +44,26 @@ public MethodDesc Method } } + public bool IsSpecialUnboxingThunk + { + get + { + if (_isUnboxing) + { + if (!_method.HasInstantiation && _method.OwningType.IsValueType && !_method.Signature.IsStatic) + return _method.IsCanonicalMethod(CanonicalFormKind.Any); + } + + return false; + } + } + public ISymbolNode GetUnboxingThunkTarget(NodeFactory factory) + { + Debug.Assert(IsSpecialUnboxingThunk); + + return factory.MethodEntrypoint(_method.GetCanonMethodTarget(CanonicalFormKind.Specific), false); + } + public bool HasCompiledBody => _hasCompiledBody; public void SetHasCompiledBody() { @@ -99,6 +121,12 @@ public override IEnumerable GetStaticDependencies(NodeFacto dependencies.AddRange(_compilationDiscoveredDependencies); } + if (MethodAssociatedDataNode.MethodHasAssociatedData(factory, this)) + { + dependencies = dependencies ?? new DependencyList(); + dependencies.Add(new DependencyListEntry(factory.MethodAssociatedData(this), "Method associated data")); + } + return dependencies; } diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ObjectWriter.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ObjectWriter.cs index 632a197d5a8..fbd44e9e033 100644 --- a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ObjectWriter.cs +++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ObjectWriter.cs @@ -432,11 +432,15 @@ public void PublishUnwindInfo(ObjectNode node) FrameInfo[] frameInfos = nodeWithCodeInfo.FrameInfos; if (frameInfos == null) { + // Data should only be present if the method has unwind info + Debug.Assert(nodeWithCodeInfo.GetAssociatedDataNode(_nodeFactory) == null); + return; } byte[] gcInfo = nodeWithCodeInfo.GCInfo; ObjectData ehInfo = nodeWithCodeInfo.EHInfo; + ISymbolNode associatedDataNode = nodeWithCodeInfo.GetAssociatedDataNode(_nodeFactory); for (int i = 0; i < frameInfos.Length; i++) { @@ -458,15 +462,19 @@ public void PublishUnwindInfo(ObjectNode node) EmitSymbolDef(blobSymbolName); FrameInfoFlags flags = frameInfo.Flags; - if (ehInfo != null) - { - flags |= FrameInfoFlags.HasEHInfo; - } + flags |= ehInfo != null ? FrameInfoFlags.HasEHInfo : 0; + flags |= associatedDataNode != null ? FrameInfoFlags.HasAssociatedData : 0; EmitBlob(blob); EmitIntValue((byte)flags, 1); + if (associatedDataNode != null) + { + EmitSymbolRef(_sb.Clear().Append(associatedDataNode.GetMangledName(_nodeFactory.NameMangler)), RelocType.IMAGE_REL_BASED_ABSOLUTE); + associatedDataNode = null; + } + if (ehInfo != null) { EmitSymbolRef(_sb.Clear().Append(_nodeFactory.NameMangler.CompilationUnitPrefix).Append("_ehInfo").Append(_currentNodeZeroTerminatedName), RelocType.IMAGE_REL_BASED_ABSOLUTE); @@ -512,11 +520,15 @@ public void BuildCFIMap(NodeFactory factory, ObjectNode node) FrameInfo[] frameInfos = nodeWithCodeInfo.FrameInfos; if (frameInfos == null) { + // Data should only be present if the method has unwind info + Debug.Assert(nodeWithCodeInfo.GetAssociatedDataNode(_nodeFactory) == null); + return; } byte[] gcInfo = nodeWithCodeInfo.GCInfo; ObjectData ehInfo = nodeWithCodeInfo.EHInfo; + ISymbolNode associatedDataNode = nodeWithCodeInfo.GetAssociatedDataNode(_nodeFactory); for (int i = 0; i < frameInfos.Length; i++) { @@ -539,10 +551,9 @@ public void BuildCFIMap(NodeFactory factory, ObjectNode node) EmitSymbolDef(blobSymbolName); FrameInfoFlags flags = frameInfo.Flags; - if (ehInfo != null) - { - flags |= FrameInfoFlags.HasEHInfo; - } + flags |= ehInfo != null ? FrameInfoFlags.HasEHInfo : 0; + flags |= associatedDataNode != null ? FrameInfoFlags.HasAssociatedData : 0; + EmitIntValue((byte)flags, 1); if (i != 0) @@ -553,6 +564,14 @@ public void BuildCFIMap(NodeFactory factory, ObjectNode node) EmitIntValue((ulong)(start - frameInfos[0].StartOffset), 4); } + if (associatedDataNode != null) + { + _sb.Clear(); + AppendExternCPrefix(_sb); + EmitSymbolRef(_sb.Append(associatedDataNode.GetMangledName(_nodeFactory.NameMangler)), RelocType.IMAGE_REL_BASED_RELPTR32); + associatedDataNode = null; + } + if (ehInfo != null) { EmitSymbolRef(_sb.Clear().Append("_ehInfo").Append(_currentNodeZeroTerminatedName), RelocType.IMAGE_REL_BASED_RELPTR32); diff --git a/src/ILCompiler.Compiler/src/ILCompiler.Compiler.csproj b/src/ILCompiler.Compiler/src/ILCompiler.Compiler.csproj index 8785265d237..e79f04704da 100644 --- a/src/ILCompiler.Compiler/src/ILCompiler.Compiler.csproj +++ b/src/ILCompiler.Compiler/src/ILCompiler.Compiler.csproj @@ -190,8 +190,8 @@ - - + + @@ -208,9 +208,11 @@ + + diff --git a/src/Native/Runtime/ICodeManager.h b/src/Native/Runtime/ICodeManager.h index 7cbfc18386b..3d5af20fd32 100644 --- a/src/Native/Runtime/ICodeManager.h +++ b/src/Native/Runtime/ICodeManager.h @@ -80,6 +80,12 @@ enum class ClasslibFunctionId OnFirstChanceException = 6, }; +enum class AssociatedDataFlags : unsigned char +{ + None = 0, + HasUnboxingStubTarget = 1, +}; + class ICodeManager { public: @@ -119,4 +125,9 @@ class ICodeManager virtual PTR_VOID GetMethodStartAddress(MethodInfo * pMethodInfo) = 0; virtual void * GetClasslibFunction(ClasslibFunctionId functionId) = 0; + + // Returns any custom data attached to the method. Format: + // AssociatedDataFlags // 1 byte. Flags describing the data stored + // Data (stream of bytes) // Variable size (depending on flags). Custom data associated with method + virtual PTR_VOID GetAssociatedData(PTR_VOID ControlPC) = 0; }; diff --git a/src/Native/Runtime/MiscHelpers.cpp b/src/Native/Runtime/MiscHelpers.cpp index eaf55a79adb..507ffa608bb 100644 --- a/src/Native/Runtime/MiscHelpers.cpp +++ b/src/Native/Runtime/MiscHelpers.cpp @@ -332,6 +332,11 @@ COOP_PINVOKE_HELPER(void *, GetClasslibCCtorCheck, (void * pReturnAddress)) return pCallback; } +COOP_PINVOKE_HELPER(void *, RhGetTargetOfUnboxingAndInstantiatingStub, (void * pUnboxStub)) +{ + return GetRuntimeInstance()->GetTargetOfUnboxingAndInstantiatingStub(pUnboxStub); +} + COOP_PINVOKE_HELPER(Boolean, RhpHasDispatchMap, (EEType * pEEType)) { return pEEType->HasDispatchMap(); diff --git a/src/Native/Runtime/RuntimeInstance.cpp b/src/Native/Runtime/RuntimeInstance.cpp index b7254a401c3..35f22d38cb0 100644 --- a/src/Native/Runtime/RuntimeInstance.cpp +++ b/src/Native/Runtime/RuntimeInstance.cpp @@ -181,6 +181,24 @@ ICodeManager * RuntimeInstance::FindCodeManagerByAddress(PTR_VOID pvAddress) return NULL; } +PTR_UInt8 RuntimeInstance::GetTargetOfUnboxingAndInstantiatingStub(PTR_VOID ControlPC) +{ + ICodeManager * pCodeManager = FindCodeManagerByAddress(ControlPC); + if (pCodeManager != NULL) + { + PTR_UInt8 pData = (PTR_UInt8)pCodeManager->GetAssociatedData(ControlPC); + if (pData != NULL) + { + UInt8 flags = *pData++; + + if ((flags & (UInt8)AssociatedDataFlags::HasUnboxingStubTarget) != 0) + return *((PTR_PTR_UInt8)pData); + } + } + + return NULL; +} + GPTR_IMPL_INIT(RuntimeInstance, g_pTheRuntimeInstance, NULL); PTR_RuntimeInstance GetRuntimeInstance() diff --git a/src/Native/Runtime/RuntimeInstance.h b/src/Native/Runtime/RuntimeInstance.h index 3d1ab3ed664..bd001fd1988 100644 --- a/src/Native/Runtime/RuntimeInstance.h +++ b/src/Native/Runtime/RuntimeInstance.h @@ -174,6 +174,7 @@ class RuntimeInstance Module * FindModuleByReadOnlyDataAddress(PTR_VOID Data); Module * FindModuleByOsHandle(HANDLE hOsHandle); PTR_UInt8 FindMethodStartAddress(PTR_VOID ControlPC); + PTR_UInt8 GetTargetOfUnboxingAndInstantiatingStub(PTR_VOID ControlPC); void EnableConservativeStackReporting(); bool IsConservativeStackReportingEnabled() { return m_conservativeStackReportingEnabled; } diff --git a/src/Native/Runtime/module.cpp b/src/Native/Runtime/module.cpp index f17eb285768..a83571cae21 100644 --- a/src/Native/Runtime/module.cpp +++ b/src/Native/Runtime/module.cpp @@ -832,6 +832,14 @@ void * Module::GetClasslibFunction(ClasslibFunctionId functionId) return pMethod; } +PTR_VOID Module::GetAssociatedData(PTR_VOID ControlPC) +{ + UNREFERENCED_PARAMETER(ControlPC); + + // Not supported for ProjectN. + return NULL; +} + // Get classlib-defined helper for running deferred static class constructors. Returns NULL if this is not the // classlib module or the classlib doesn't implement this callback. void * Module::GetClasslibCheckStaticClassConstruction() diff --git a/src/Native/Runtime/module.h b/src/Native/Runtime/module.h index a037bc828d4..f1a48b2a83c 100644 --- a/src/Native/Runtime/module.h +++ b/src/Native/Runtime/module.h @@ -113,6 +113,8 @@ class Module : public ICodeManager void * RecoverLoopHijackTarget(UInt32 entryIndex, ModuleHeader * pModuleHeader); + PTR_VOID GetAssociatedData(PTR_VOID ControlPC); + private: Module(ModuleHeader * pModuleHeader); #ifdef FEATURE_CUSTOM_IMPORTS diff --git a/src/Native/Runtime/unix/UnixNativeCodeManager.cpp b/src/Native/Runtime/unix/UnixNativeCodeManager.cpp index e60e6013069..445b6e00a75 100644 --- a/src/Native/Runtime/unix/UnixNativeCodeManager.cpp +++ b/src/Native/Runtime/unix/UnixNativeCodeManager.cpp @@ -25,9 +25,9 @@ #define UBF_FUNC_KIND_HANDLER 0x01 #define UBF_FUNC_KIND_FILTER 0x02 -#define UBF_FUNC_HAS_EHINFO 0x04 - -#define UBF_FUNC_REVERSE_PINVOKE 0x08 +#define UBF_FUNC_HAS_EHINFO 0x04 +#define UBF_FUNC_REVERSE_PINVOKE 0x08 +#define UBF_FUNC_HAS_ASSOCIATED_DATA 0x10 struct UnixNativeMethodInfo { @@ -130,6 +130,9 @@ void UnixNativeCodeManager::EnumGcRefs(MethodInfo * pMethodInfo, uint8_t unwindBlockFlags = *p++; + if ((unwindBlockFlags & UBF_FUNC_HAS_ASSOCIATED_DATA) != 0) + p += sizeof(int32_t); + if ((unwindBlockFlags & UBF_FUNC_HAS_EHINFO) != 0) p += sizeof(int32_t); @@ -176,6 +179,9 @@ bool UnixNativeCodeManager::UnwindStackFrame(MethodInfo * pMethodInfo, uint8_t unwindBlockFlags = *p++; + if ((unwindBlockFlags & UBF_FUNC_HAS_ASSOCIATED_DATA) != 0) + p += sizeof(int32_t); + if ((unwindBlockFlags & UBF_FUNC_REVERSE_PINVOKE) != 0) { // Reverse PInvoke transition should on the main function body only @@ -265,6 +271,9 @@ bool UnixNativeCodeManager::EHEnumInit(MethodInfo * pMethodInfo, PTR_VOID * pMet uint8_t unwindBlockFlags = *p++; + if ((unwindBlockFlags & UBF_FUNC_HAS_ASSOCIATED_DATA) != 0) + p += sizeof(int32_t); + // return if there is no EH info associated with this method if ((unwindBlockFlags & UBF_FUNC_HAS_EHINFO) == 0) { @@ -356,6 +365,21 @@ void * UnixNativeCodeManager::GetClasslibFunction(ClasslibFunctionId functionId) return m_pClasslibFunctions[id]; } +PTR_VOID UnixNativeCodeManager::GetAssociatedData(PTR_VOID ControlPC) +{ + UnixNativeMethodInfo methodInfo; + if (!FindMethodInfo(ControlPC, &methodInfo)) + return NULL; + + PTR_UInt8 p = methodInfo.pMainLSDA; + + uint8_t unwindBlockFlags = *p++; + if ((unwindBlockFlags & UBF_FUNC_HAS_ASSOCIATED_DATA) == 0) + return NULL; + + return dac_cast(p + *dac_cast(p)); +} + extern "C" bool __stdcall RegisterCodeManager(ICodeManager * pCodeManager, PTR_VOID pvStartRange, UInt32 cbRange); extern "C" void __stdcall UnregisterCodeManager(ICodeManager * pCodeManager); extern "C" bool __stdcall RegisterUnboxingStubs(PTR_VOID pvStartRange, UInt32 cbRange); diff --git a/src/Native/Runtime/unix/UnixNativeCodeManager.h b/src/Native/Runtime/unix/UnixNativeCodeManager.h index e424a559cae..13333ee7370 100644 --- a/src/Native/Runtime/unix/UnixNativeCodeManager.h +++ b/src/Native/Runtime/unix/UnixNativeCodeManager.h @@ -58,4 +58,6 @@ class UnixNativeCodeManager : public ICodeManager PTR_VOID GetMethodStartAddress(MethodInfo * pMethodInfo); void * GetClasslibFunction(ClasslibFunctionId functionId); + + PTR_VOID GetAssociatedData(PTR_VOID ControlPC); }; diff --git a/src/Native/Runtime/windows/CoffNativeCodeManager.cpp b/src/Native/Runtime/windows/CoffNativeCodeManager.cpp index 6690ffeb2f7..fa162aa753e 100644 --- a/src/Native/Runtime/windows/CoffNativeCodeManager.cpp +++ b/src/Native/Runtime/windows/CoffNativeCodeManager.cpp @@ -25,9 +25,9 @@ #define UBF_FUNC_KIND_HANDLER 0x01 #define UBF_FUNC_KIND_FILTER 0x02 -#define UBF_FUNC_HAS_EHINFO 0x04 - -#define UBF_FUNC_REVERSE_PINVOKE 0x08 +#define UBF_FUNC_HAS_EHINFO 0x04 +#define UBF_FUNC_REVERSE_PINVOKE 0x08 +#define UBF_FUNC_HAS_ASSOCIATED_DATA 0x10 #if defined(_TARGET_AMD64_) @@ -297,6 +297,9 @@ void CoffNativeCodeManager::EnumGcRefs(MethodInfo * pMethodInfo, uint8_t unwindBlockFlags = *p++; + if ((unwindBlockFlags & UBF_FUNC_HAS_ASSOCIATED_DATA) != 0) + p += sizeof(int32_t); + if ((unwindBlockFlags & UBF_FUNC_HAS_EHINFO) != 0) p += sizeof(int32_t); @@ -347,6 +350,9 @@ bool CoffNativeCodeManager::UnwindStackFrame(MethodInfo * pMethodInfo, uint8_t unwindBlockFlags = *p++; + if ((unwindBlockFlags & UBF_FUNC_HAS_ASSOCIATED_DATA) != 0) + p += sizeof(int32_t); + if ((unwindBlockFlags & UBF_FUNC_REVERSE_PINVOKE) != 0) { // Reverse PInvoke transition should on the main function body only @@ -455,6 +461,9 @@ bool CoffNativeCodeManager::GetReturnAddressHijackInfo(MethodInfo * pMethodIn uint8_t unwindBlockFlags = *p++; + if ((unwindBlockFlags & UBF_FUNC_HAS_ASSOCIATED_DATA) != 0) + p += sizeof(int32_t); + // Check whether this is a funclet if ((unwindBlockFlags & UBF_FUNC_KIND_MASK) != UBF_FUNC_KIND_ROOT) return false; @@ -550,6 +559,9 @@ bool CoffNativeCodeManager::EHEnumInit(MethodInfo * pMethodInfo, PTR_VOID * pMet uint8_t unwindBlockFlags = *p++; + if ((unwindBlockFlags & UBF_FUNC_HAS_ASSOCIATED_DATA) != 0) + p += sizeof(int32_t); + // return if there is no EH info associated with this method if ((unwindBlockFlags & UBF_FUNC_HAS_EHINFO) == 0) { @@ -634,6 +646,29 @@ void * CoffNativeCodeManager::GetClasslibFunction(ClasslibFunctionId functionId) return m_pClasslibFunctions[id]; } +PTR_VOID CoffNativeCodeManager::GetAssociatedData(PTR_VOID ControlPC) +{ + TADDR relativePC = dac_cast(ControlPC) - m_moduleBase; + + int MethodIndex = LookupUnwindInfoForMethod((UInt32)relativePC, m_pRuntimeFunctionTable, 0, m_nRuntimeFunctionTable - 1); + if (MethodIndex < 0) + return NULL; + + PTR_RUNTIME_FUNCTION pRuntimeFunction = m_pRuntimeFunctionTable + MethodIndex; + + size_t unwindDataBlobSize; + PTR_UInt8 pUnwindDataBlob = GetUnwindDataBlob(m_moduleBase, pRuntimeFunction, &unwindDataBlobSize); + + PTR_UInt8 p = dac_cast(pUnwindDataBlob) + unwindDataBlobSize; + + uint8_t unwindBlockFlags = *p++; + if ((unwindBlockFlags & UBF_FUNC_HAS_ASSOCIATED_DATA) == 0) + return NULL; + + UInt32 dataRVA = *(UInt32*)p; + return m_moduleBase + dataRVA; +} + extern "C" bool __stdcall RegisterCodeManager(ICodeManager * pCodeManager, PTR_VOID pvStartRange, UInt32 cbRange); extern "C" void __stdcall UnregisterCodeManager(ICodeManager * pCodeManager); extern "C" bool __stdcall RegisterUnboxingStubs(PTR_VOID pvStartRange, UInt32 cbRange); diff --git a/src/Native/Runtime/windows/CoffNativeCodeManager.h b/src/Native/Runtime/windows/CoffNativeCodeManager.h index 09b96038644..b0d5390a478 100644 --- a/src/Native/Runtime/windows/CoffNativeCodeManager.h +++ b/src/Native/Runtime/windows/CoffNativeCodeManager.h @@ -94,4 +94,6 @@ class CoffNativeCodeManager : public ICodeManager PTR_VOID GetMethodStartAddress(MethodInfo * pMethodInfo); void * GetClasslibFunction(ClasslibFunctionId functionId); + + PTR_VOID GetAssociatedData(PTR_VOID ControlPC); }; diff --git a/src/Native/jitinterface/JITCodeManager.cpp b/src/Native/jitinterface/JITCodeManager.cpp index fac0f426e39..e16da72a9aa 100644 --- a/src/Native/jitinterface/JITCodeManager.cpp +++ b/src/Native/jitinterface/JITCodeManager.cpp @@ -730,3 +730,10 @@ void * JITCodeManager::GetClasslibFunction(ClasslibFunctionId functionId) assert(false); return false; } + +PTR_VOID JITCodeManager::GetAssociatedData(PTR_VOID ControlPC) +{ + // @TODO: CORERT: GetAssociatedData + assert(false); + return NULL; +} diff --git a/src/Native/jitinterface/JITCodeManager.h b/src/Native/jitinterface/JITCodeManager.h index 294a480162b..4b0212943d2 100644 --- a/src/Native/jitinterface/JITCodeManager.h +++ b/src/Native/jitinterface/JITCodeManager.h @@ -276,4 +276,6 @@ class JITCodeManager : ICodeManager PTR_VOID GetMethodStartAddress(MethodInfo * pMethodInfo); void * GetClasslibFunction(ClasslibFunctionId functionId); -}; \ No newline at end of file + + PTR_VOID GetAssociatedData(PTR_VOID ControlPC); +}; diff --git a/src/System.Private.CoreLib/src/Internal/Runtime/Augments/RuntimeAugments.cs b/src/System.Private.CoreLib/src/Internal/Runtime/Augments/RuntimeAugments.cs index 01336f2dac2..332ba8ab865 100644 --- a/src/System.Private.CoreLib/src/Internal/Runtime/Augments/RuntimeAugments.cs +++ b/src/System.Private.CoreLib/src/Internal/Runtime/Augments/RuntimeAugments.cs @@ -805,6 +805,11 @@ public static IntPtr GetCodeTarget(IntPtr functionPointer) return RuntimeImports.RhGetCodeTarget(functionPointer); } + public static IntPtr GetTargetOfUnboxingAndInstantiatingStub(IntPtr functionPointer) + { + return RuntimeImports.RhGetTargetOfUnboxingAndInstantiatingStub(functionPointer); + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static IntPtr RuntimeCacheLookup(IntPtr context, IntPtr signature, int registeredResolutionFunction, object contextObject, out IntPtr auxResult) { diff --git a/src/System.Private.CoreLib/src/System/Runtime/RuntimeImports.cs b/src/System.Private.CoreLib/src/System/Runtime/RuntimeImports.cs index 0eeb8038e16..7893037ffd6 100644 --- a/src/System.Private.CoreLib/src/System/Runtime/RuntimeImports.cs +++ b/src/System.Private.CoreLib/src/System/Runtime/RuntimeImports.cs @@ -611,6 +611,10 @@ internal static uint RhGetLoadedModules(TypeManagerHandle[] resultArray) [RuntimeImport(RuntimeLibrary, "RhGetJmpStubCodeTarget")] internal static extern IntPtr RhGetJmpStubCodeTarget(IntPtr pCode); + [MethodImplAttribute(MethodImplOptions.InternalCall)] + [RuntimeImport(RuntimeLibrary, "RhGetTargetOfUnboxingAndInstantiatingStub")] + public static extern IntPtr RhGetTargetOfUnboxingAndInstantiatingStub(IntPtr pCode); + // // EH helpers // diff --git a/src/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeLoaderEnvironment.cs b/src/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeLoaderEnvironment.cs index b3b39230ecd..6e72a1ed3ef 100644 --- a/src/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeLoaderEnvironment.cs +++ b/src/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeLoaderEnvironment.cs @@ -675,7 +675,14 @@ private struct UnboxingAndInstantiatingStubMapEntry public static unsafe bool TryGetTargetOfUnboxingAndInstantiatingStub(IntPtr maybeInstantiatingAndUnboxingStub, out IntPtr targetMethod) { - targetMethod = IntPtr.Zero; + targetMethod = RuntimeAugments.GetTargetOfUnboxingAndInstantiatingStub(maybeInstantiatingAndUnboxingStub); + if (targetMethod != IntPtr.Zero) + { + return true; + } + + // TODO: The rest of the code in this function is specific to ProjectN only. When we kill the binder, get rid of this + // linear search code (the only API that should be used for the lookup is the one above) // Get module IntPtr associatedModule = RuntimeAugments.GetOSModuleFromPointer(maybeInstantiatingAndUnboxingStub);