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);