Generate runtime interop data for structs and delegates

In order to make the Marshal APIs to work, this change generates runtime
interop data for the following cases:

. Delegates with UnmanagedFunctionPointerAttribute
. Structs with StructLayoutAttribute
. Generic parameters for Marshal generic API calls which are struct or
delegate
This commit is contained in:
Faizur Rahman 2017-05-31 16:18:24 -07:00
Родитель f8bce0a3a9
Коммит f63296bcb4
19 изменённых файлов: 561 добавлений и 130 удалений

Просмотреть файл

@ -21,7 +21,7 @@ namespace Internal.Runtime
EmbeddedMetadata = 13,
DefaultConstructorMap = 14,
UnboxingAndInstantiatingStubMap = 15,
InvokeInstantiations = 16, // unused
StructMarshallingStubMap = 16,
DelegateMarshallingStubMap = 17,
GenericVirtualMethodTable = 18,
InterfaceGenericVirtualMethodTable = 19,

Просмотреть файл

@ -93,6 +93,22 @@ namespace Internal.IL.Stubs
}
}
private TypeDesc GetNativeMethodParameterType(TypeDesc managedType, MarshalAsDescriptor marshalAs, InteropStateManager interopStateManager, bool isReturn, bool isAnsi)
{
TypeDesc nativeType;
try
{
nativeType = MarshalHelpers.GetNativeMethodParameterType(managedType, marshalAs, interopStateManager, isReturn, isAnsi);
}
catch (NotSupportedException)
{
// if marshalling is not supported for this type the generated stubs will emit appropriate
// error message. We just set native type to be same as managedtype
nativeType = managedType;
}
return nativeType;
}
public override MethodSignature Signature
{
get
@ -123,7 +139,7 @@ namespace Internal.IL.Stubs
marshalAs = parameterMetadataArray[parameterIndex++].MarshalAsDescriptor;
}
TypeDesc nativeReturnType = MarshalHelpers.GetNativeMethodParameterType(delegateSignature.ReturnType, null, _interopStateManager, true, isAnsi);
TypeDesc nativeReturnType = GetNativeMethodParameterType(delegateSignature.ReturnType, null, _interopStateManager, true, isAnsi);
for (int i = 0; i < delegateSignature.Length; i++)
{
int sequence = i + 1;
@ -142,7 +158,7 @@ namespace Internal.IL.Stubs
var managedType = isByRefType ? delegateSignature[i].GetParameterType() : delegateSignature[i];
var nativeType = MarshalHelpers.GetNativeMethodParameterType(managedType, marshalAs, _interopStateManager, false, isAnsi);
var nativeType = GetNativeMethodParameterType(managedType, marshalAs, _interopStateManager, false, isAnsi);
nativeParameterTypes[i] = isByRefType ? nativeType.MakePointerType() : nativeType;
}

Просмотреть файл

@ -127,7 +127,23 @@ namespace Internal.TypeSystem.Interop
private NativeStructField[] _fields;
private InteropStateManager _interopStateManager;
private bool _hasInvalidLayout;
public bool HasInvalidLayout
{
get
{
return _hasInvalidLayout;
}
}
public FieldDesc[] Fields
{
get
{
return _fields;
}
}
public NativeStructType(ModuleDesc owningModule, MetadataType managedStructType, InteropStateManager interopStateManager)
{
@ -138,6 +154,7 @@ namespace Internal.TypeSystem.Interop
Module = owningModule;
ManagedStructType = managedStructType;
_interopStateManager = interopStateManager;
_hasInvalidLayout = false;
CalculateFields();
}
@ -179,6 +196,7 @@ namespace Internal.TypeSystem.Interop
// if marshalling is not supported for this type the generated stubs will emit appropriate
// error message. We just set native type to be same as managedtype
nativeType = managedType;
_hasInvalidLayout = true;
}
_fields[index++] = new NativeStructField(nativeType, this, field);

Просмотреть файл

@ -8,6 +8,7 @@ using Internal.Text;
using Internal.TypeSystem;
using ILCompiler.DependencyAnalysisFramework;
using ILCompiler.DependencyAnalysis;
using Internal.TypeSystem.Interop;
using DependencyList=ILCompiler.DependencyAnalysisFramework.DependencyNodeCore<ILCompiler.DependencyAnalysis.NodeFactory>.DependencyList;
using DependencyListEntry=ILCompiler.DependencyAnalysisFramework.DependencyNodeCore<ILCompiler.DependencyAnalysis.NodeFactory>.DependencyListEntry;
@ -87,6 +88,7 @@ namespace ILCompiler.DependencyAnalysis
}
GenericMethodsTemplateMap.GetTemplateMethodDependencies(ref dependencies, factory, method);
AddMarshalAPIsGenericDependencies(ref dependencies, factory, method);
}
else
{
@ -118,23 +120,77 @@ namespace ILCompiler.DependencyAnalysis
}
}
private static void AddPInvokeParameterDependencies(ref DependencyList dependencies, NodeFactory factory, TypeDesc parameter)
public static void AddInterestingInteropConstructedTypeDependencies(ref DependencyList dependencies, NodeFactory factory, TypeDesc type)
{
if (parameter.IsDelegate)
if (type.IsDelegate)
{
dependencies.Add(factory.NecessaryTypeSymbol(parameter), "Delegate Marshalling Stub");
dependencies.Add(factory.MethodEntrypoint(factory.InteropStubManager.GetOpenStaticDelegateMarshallingStub(parameter)), "Delegate Marshalling Stub");
dependencies.Add(factory.MethodEntrypoint(factory.InteropStubManager.GetClosedDelegateMarshallingStub(parameter)), "Delegate Marshalling Stub");
dependencies.Add(factory.MethodEntrypoint(factory.InteropStubManager.GetForwardDelegateCreationStub(parameter)), "Delegate Marshalling Stub");
var delegateType = type as MetadataType;
if (delegateType != null && delegateType.HasCustomAttribute("System.Runtime.InteropServices", "UnmanagedFunctionPointerAttribute"))
{
AddDependenciesDuePInvokeDelegate(ref dependencies, factory, delegateType);
}
}
else if (Internal.TypeSystem.Interop.MarshalHelpers.IsStructMarshallingRequired(parameter))
else if (type.IsValueType && type.IsTypeDefinition && !(type is NativeStructType))
{
var stub = (Internal.IL.Stubs.StructMarshallingThunk)factory.InteropStubManager.GetStructMarshallingManagedToNativeStub(parameter);
dependencies.Add(factory.ConstructedTypeSymbol(factory.InteropStubManager.GetStructMarshallingType(parameter)), "Struct Marshalling Type");
var structType = type as MetadataType;
if (structType != null && structType.HasCustomAttribute("System.Runtime.InteropServices", "StructLayoutAttribute"))
{
AddDependenciesDuePInvokeStruct(ref dependencies, factory, type);
}
}
}
/// <summary>
/// For Marshal generic APIs(eg. Marshal.StructureToPtr<T>, GetFunctionPointerForDelegate) we add
/// the generic parameter as dependencies so that we can generate runtime data for them
/// </summary>
public static void AddMarshalAPIsGenericDependencies(ref DependencyList dependencies, NodeFactory factory, MethodDesc method)
{
TypeDesc owningType = method.OwningType;
MetadataType metadataType = owningType as MetadataType;
if (metadataType != null)
{
if (metadataType.Name == "Marshal" && metadataType.Namespace == "System.Runtime.InteropServices")
{
foreach (TypeDesc type in method.Instantiation)
{
AddPInvokeParameterDependencies(ref dependencies, factory, type);
}
}
}
}
public static void AddPInvokeParameterDependencies(ref DependencyList dependencies, NodeFactory factory, TypeDesc parameter)
{
AddDependenciesDuePInvokeDelegate(ref dependencies, factory, parameter);
AddDependenciesDuePInvokeStruct(ref dependencies, factory, parameter);
}
public static void AddDependenciesDuePInvokeDelegate(ref DependencyList dependencies, NodeFactory factory, TypeDesc type)
{
if (type.IsDelegate)
{
dependencies.Add(factory.NecessaryTypeSymbol(type), "Delegate Marshalling Stub");
dependencies.Add(factory.MethodEntrypoint(factory.InteropStubManager.GetOpenStaticDelegateMarshallingStub(type)), "Delegate Marshalling Stub");
dependencies.Add(factory.MethodEntrypoint(factory.InteropStubManager.GetClosedDelegateMarshallingStub(type)), "Delegate Marshalling Stub");
dependencies.Add(factory.MethodEntrypoint(factory.InteropStubManager.GetForwardDelegateCreationStub(type)), "Delegate Marshalling Stub");
}
}
public static void AddDependenciesDuePInvokeStruct(ref DependencyList dependencies, NodeFactory factory, TypeDesc type)
{
if (MarshalHelpers.IsStructMarshallingRequired(type))
{
dependencies.Add(factory.NecessaryTypeSymbol(type), "Struct Marshalling Stub");
var stub = (Internal.IL.Stubs.StructMarshallingThunk)factory.InteropStubManager.GetStructMarshallingManagedToNativeStub(type);
dependencies.Add(factory.ConstructedTypeSymbol(factory.InteropStubManager.GetStructMarshallingType(type)), "Struct Marshalling Type");
dependencies.Add(factory.MethodEntrypoint(stub), "Struct Marshalling stub");
dependencies.Add(factory.MethodEntrypoint(factory.InteropStubManager.GetStructMarshallingNativeToManagedStub(parameter)), "Struct Marshalling stub");
dependencies.Add(factory.MethodEntrypoint(factory.InteropStubManager.GetStructMarshallingCleanupStub(parameter)), "Struct Marshalling stub");
dependencies.Add(factory.MethodEntrypoint(factory.InteropStubManager.GetStructMarshallingNativeToManagedStub(type)), "Struct Marshalling stub");
dependencies.Add(factory.MethodEntrypoint(factory.InteropStubManager.GetStructMarshallingCleanupStub(type)), "Struct Marshalling stub");
foreach (var inlineArrayCandidate in stub.GetInlineArrayCandidates())
{

Просмотреть файл

@ -2,12 +2,10 @@
// 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.Collections.Generic;
using System.Diagnostics;
using Internal.Runtime;
using Internal.Text;
using Internal.TypeSystem;
using Internal.IL;
@ -168,6 +166,8 @@ namespace ILCompiler.DependencyAnalysis
// Ask the metadata manager if we have any dependencies due to reflectability.
factory.MetadataManager.GetDependenciesDueToReflectability(ref dependencyList, factory, _type);
CodeBasedDependencyAlgorithm.AddInterestingInteropConstructedTypeDependencies(ref dependencyList, factory, _type);
return dependencyList;
}

Просмотреть файл

@ -203,6 +203,9 @@ namespace ILCompiler.DependencyAnalysis
{
DependencyList dependencies = new DependencyList();
GenericMethodsHashtableNode.GetGenericMethodsHashtableDependenciesForMethod(ref dependencies, factory, _owningMethod);
CodeBasedDependencyAlgorithm.AddMarshalAPIsGenericDependencies(ref dependencies, factory, _owningMethod);
return dependencies;
}

Просмотреть файл

@ -0,0 +1,107 @@
// 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 Internal.NativeFormat;
using Internal.Text;
namespace ILCompiler.DependencyAnalysis
{
/// <summary>
/// Represents a hash table of struct marshalling stub types generated into the image.
/// </summary>
internal sealed class StructMarshallingStubMapNode : ObjectNode, ISymbolDefinitionNode
{
private ObjectAndOffsetSymbolNode _endSymbol;
private ExternalReferencesTableNode _externalReferences;
public StructMarshallingStubMapNode(ExternalReferencesTableNode externalReferences)
{
_endSymbol = new ObjectAndOffsetSymbolNode(this, 0, "__struct_marshalling_stub_map_End", true);
_externalReferences = externalReferences;
}
public ISymbolDefinitionNode EndSymbol => _endSymbol;
public void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb)
{
sb.Append(nameMangler.CompilationUnitPrefix).Append("__struct_marshalling_stub_map");
}
public int Offset => 0;
public override bool IsShareable => false;
public override ObjectNodeSection Section => _externalReferences.Section;
public override bool StaticDependenciesAreComputed => true;
protected override string GetName(NodeFactory factory) => this.GetMangledName(factory.NameMangler);
public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false)
{
// This node does not trigger generation of other nodes.
if (relocsOnly)
return new ObjectData(Array.Empty<byte>(), Array.Empty<Relocation>(), 1, new ISymbolDefinitionNode[] { this });
var writer = new NativeWriter();
var typeMapHashTable = new VertexHashtable();
Section hashTableSection = writer.NewSection();
hashTableSection.Place(typeMapHashTable);
foreach (var structEntry in factory.InteropStubManager.GetStructMarshallingTypes())
{
// the order of data written is as follows:
// 0. managed struct type
// 1. native struct type
// 2. struct marshalling thunk
// 3. struct unmarshalling thunk
// 4. struct cleanup thunk
// 5. NumFields << 1 | HasInvalidLayout
// 6 for each field
// a. name
// b. offset
var structType = structEntry.StructType;
var nativeType = structEntry.NativeStructType;
Vertex data= writer.GetTuple(
writer.GetUnsignedConstant(_externalReferences.GetIndex(factory.MethodEntrypoint(structEntry.MarshallingThunk))),
writer.GetUnsignedConstant(_externalReferences.GetIndex(factory.MethodEntrypoint(structEntry.UnmarshallingThunk))),
writer.GetUnsignedConstant(_externalReferences.GetIndex(factory.MethodEntrypoint(structEntry.CleanupThunk)))
);
uint mask = (uint)(nativeType.Fields.Length << 1) | (uint)(nativeType.HasInvalidLayout ? 1 : 0);
data = writer.GetTuple(
data,
writer.GetUnsignedConstant(mask)
);
for (int i = 0; i < nativeType.Fields.Length; i++)
{
data = writer.GetTuple(
data,
writer.GetStringConstant(nativeType.Fields[i].Name),
writer.GetUnsignedConstant((uint)nativeType.Fields[i].Offset.AsInt)
);
}
Vertex vertex = writer.GetTuple(
writer.GetUnsignedConstant(_externalReferences.GetIndex(factory.NecessaryTypeSymbol(structType))),
writer.GetUnsignedConstant(_externalReferences.GetIndex(factory.NecessaryTypeSymbol(nativeType))),
data
);
int hashCode = structType.GetHashCode();
typeMapHashTable.Append((uint)hashCode, hashTableSection.Place(vertex));
}
byte[] hashTableBytes = writer.Save();
_endSymbol.SetSymbolOffset(hashTableBytes.Length);
return new ObjectData(hashTableBytes, Array.Empty<Relocation>(), 1, new ISymbolDefinitionNode[] { this, _endSymbol });
}
}
}

Просмотреть файл

@ -101,32 +101,49 @@ namespace ILCompiler
internal struct DelegateMarshallingThunks
{
public TypeDesc DelegateType;
public DelegateMarshallingMethodThunk OpenStaticDelegateMarshallingThunk;
public DelegateMarshallingMethodThunk ClosedDelegateMarshallingThunk;
public ForwardDelegateCreationThunk DelegateCreationThunk;
public MethodDesc OpenStaticDelegateMarshallingThunk;
public MethodDesc ClosedDelegateMarshallingThunk;
public MethodDesc DelegateCreationThunk;
}
internal IEnumerable<DelegateMarshallingThunks> GetDelegateMarshallingThunks()
{
foreach (var delegateType in _delegateMarshalingTypes)
{
var openStub = InteropStateManager.GetOpenStaticDelegateMarshallingThunk(delegateType);
var closedStub = InteropStateManager.GetClosedDelegateMarshallingThunk(delegateType);
var delegateCreationStub = InteropStateManager.GetForwardDelegateCreationThunk(delegateType);
yield return
new DelegateMarshallingThunks()
{
DelegateType = delegateType,
OpenStaticDelegateMarshallingThunk = openStub,
ClosedDelegateMarshallingThunk = closedStub,
DelegateCreationThunk = delegateCreationStub
OpenStaticDelegateMarshallingThunk = InteropStateManager.GetOpenStaticDelegateMarshallingThunk(delegateType),
ClosedDelegateMarshallingThunk = InteropStateManager.GetClosedDelegateMarshallingThunk(delegateType),
DelegateCreationThunk = InteropStateManager.GetForwardDelegateCreationThunk(delegateType)
};
}
}
internal HashSet<NativeStructType> GetStructMarshallingTypes()
internal struct StructMarshallingThunks
{
return _structMarshallingTypes;
public TypeDesc StructType;
public NativeStructType NativeStructType;
public MethodDesc MarshallingThunk;
public MethodDesc UnmarshallingThunk;
public MethodDesc CleanupThunk;
}
internal IEnumerable<StructMarshallingThunks> GetStructMarshallingTypes()
{
foreach (var nativeStuctType in _structMarshallingTypes)
{
yield return
new StructMarshallingThunks()
{
StructType = nativeStuctType.ManagedStructType,
NativeStructType = nativeStuctType,
MarshallingThunk = InteropStateManager.GetStructMarshallingManagedToNativeThunk(nativeStuctType.ManagedStructType),
UnmarshallingThunk = InteropStateManager.GetStructMarshallingNativeToManagedThunk(nativeStuctType.ManagedStructType),
CleanupThunk = InteropStateManager.GetStructMarshallingCleanupThunk(nativeStuctType.ManagedStructType)
};
}
}
}
}

Просмотреть файл

@ -100,6 +100,9 @@ namespace ILCompiler
var delegateMapNode = new DelegateMarshallingStubMapNode(commonFixupsTableNode);
header.Add(BlobIdToReadyToRunSection(ReflectionMapBlob.DelegateMarshallingStubMap), delegateMapNode, delegateMapNode, delegateMapNode.EndSymbol);
var structMapNode = new StructMarshallingStubMapNode(commonFixupsTableNode);
header.Add(BlobIdToReadyToRunSection(ReflectionMapBlob.StructMarshallingStubMap), structMapNode, structMapNode, structMapNode.EndSymbol);
var arrayMapNode = new ArrayMapNode(commonFixupsTableNode);
header.Add(BlobIdToReadyToRunSection(ReflectionMapBlob.ArrayMap), arrayMapNode, arrayMapNode, arrayMapNode.EndSymbol);

Просмотреть файл

@ -148,6 +148,7 @@
<Compile Include="Compiler\DependencyAnalysis\CallingConventionConverterKey.cs" />
<Compile Include="Compiler\DependencyAnalysis\CodeBasedDependencyAlgorithm.cs" />
<Compile Include="Compiler\DependencyAnalysis\DelegateMarshallingStubMapNode.cs" />
<Compile Include="Compiler\DependencyAnalysis\StructMarshallingStubMapNode.cs" />
<Compile Include="Compiler\DependencyAnalysis\GenericVirtualMethodTableNode.cs" />
<Compile Include="Compiler\DependencyAnalysis\InterfaceGenericVirtualMethodTableNode.cs" />
<Compile Include="Compiler\DependencyAnalysis\IObjectDumper.cs" />

Просмотреть файл

@ -12,5 +12,15 @@ namespace Internal.Runtime.Augments
public abstract class InteropCallbacks
{
public abstract bool TryGetMarshallerDataForDelegate(RuntimeTypeHandle delegateTypeHandle, out McgPInvokeDelegateData delegateData);
public abstract bool TryGetStructUnsafeStructType(RuntimeTypeHandle structureTypeHandle, out RuntimeTypeHandle unsafeStructType);
public abstract bool TryGetStructUnmarshalStub(RuntimeTypeHandle structureTypeHandle, out IntPtr unmarshalStub);
public abstract bool TryGetStructMarshalStub(RuntimeTypeHandle structureTypeHandle, out IntPtr marshalStub);
public abstract bool TryGetDestroyStructureStub(RuntimeTypeHandle structureTypeHandle, out IntPtr destroyStructureStub, out bool hasInvalidLayout);
public abstract bool TryGetStructFieldOffset(RuntimeTypeHandle structureTypeHandle, string fieldName, out bool structExists, out uint offset);
}
}

Просмотреть файл

@ -1,91 +0,0 @@
// 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 Internal.Runtime.Augments;
using Internal.NativeFormat;
using Internal.Runtime.TypeLoader;
using Internal.Reflection.Execution;
using System.Runtime.InteropServices;
namespace Internal.Runtime.CompilerHelpers
{
internal class Callbacks : InteropCallbacks
{
public override bool TryGetMarshallerDataForDelegate(RuntimeTypeHandle delegateTypeHandle, out McgPInvokeDelegateData data)
{
IntPtr openStub, closedStub, delegateCreationStub;
if (!TryGetMarshallersForDelegate(delegateTypeHandle, out openStub, out closedStub, out delegateCreationStub))
{
data = default(McgPInvokeDelegateData);
return false;
}
data = new global::System.Runtime.InteropServices.McgPInvokeDelegateData()
{
ReverseOpenStaticDelegateStub = openStub,
ReverseStub = closedStub,
ForwardDelegateCreationStub = delegateCreationStub
};
return true;
}
private static unsafe bool TryGetNativeReaderForBlob(NativeFormatModuleInfo module, ReflectionMapBlob blob, out NativeReader reader)
{
byte* pBlob;
uint cbBlob;
if (module.TryFindBlob((int)blob, out pBlob, out cbBlob))
{
reader = new NativeReader(pBlob, cbBlob);
return true;
}
reader = default(NativeReader);
return false;
}
private unsafe bool TryGetMarshallersForDelegate(RuntimeTypeHandle delegateTypeHandle, out IntPtr openStub, out IntPtr closedStub, out IntPtr delegateCreationStub)
{
int delegateHashcode = delegateTypeHandle.GetHashCode();
openStub = IntPtr.Zero;
closedStub = IntPtr.Zero;
delegateCreationStub = IntPtr.Zero;
foreach (NativeFormatModuleInfo module in ModuleList.EnumerateModules())
{
NativeReader delegateMapReader;
if (TryGetNativeReaderForBlob(module, ReflectionMapBlob.DelegateMarshallingStubMap, out delegateMapReader))
{
NativeParser delegateMapParser = new NativeParser(delegateMapReader, 0);
NativeHashtable delegateHashtable = new NativeHashtable(delegateMapParser);
ExternalReferencesTable externalReferences = default(ExternalReferencesTable);
externalReferences.InitializeCommonFixupsTable(module);
var lookup = delegateHashtable.Lookup(delegateHashcode);
NativeParser entryParser;
while (!(entryParser = lookup.GetNext()).IsNull)
{
RuntimeTypeHandle foundDelegateType = externalReferences.GetRuntimeTypeHandleFromIndex(entryParser.GetUnsigned());
if (foundDelegateType.Equals(delegateTypeHandle))
{
byte* pOpen = (byte*)externalReferences.GetIntPtrFromIndex(entryParser.GetUnsigned());
byte* pClose = (byte*)externalReferences.GetIntPtrFromIndex(entryParser.GetUnsigned());
byte* pDelegateCreation = (byte*)externalReferences.GetIntPtrFromIndex(entryParser.GetUnsigned());
openStub = (IntPtr)pOpen;
closedStub = (IntPtr)pClose;
delegateCreationStub = (IntPtr)pDelegateCreation;
return true;
}
}
}
}
return false;
}
}
}

Просмотреть файл

@ -22,7 +22,7 @@ namespace Internal.Runtime.CompilerHelpers
__vtable_IUnknown.Initialize();
McgModuleManager.Initialize();
#endif
RuntimeAugments.InitializeInteropLookups(new Callbacks());
RuntimeAugments.InitializeInteropLookups(RuntimeInteropData.Instance);
}
}
}

Просмотреть файл

@ -0,0 +1,204 @@
// 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 Internal.Runtime.Augments;
using Internal.NativeFormat;
using Internal.Runtime.TypeLoader;
using Internal.Reflection.Execution;
using System.Runtime.InteropServices;
namespace Internal.Runtime.CompilerHelpers
{
internal partial class RuntimeInteropData
{
public override bool TryGetMarshallerDataForDelegate(RuntimeTypeHandle delegateTypeHandle, out McgPInvokeDelegateData data)
{
IntPtr openStub, closedStub, delegateCreationStub;
if (!TryGetMarshallersForDelegate(delegateTypeHandle, out openStub, out closedStub, out delegateCreationStub))
{
data = default(McgPInvokeDelegateData);
return false;
}
data = new global::System.Runtime.InteropServices.McgPInvokeDelegateData()
{
ReverseOpenStaticDelegateStub = openStub,
ReverseStub = closedStub,
ForwardDelegateCreationStub = delegateCreationStub
};
return true;
}
#region "Struct Data"
public override bool TryGetStructUnsafeStructType(RuntimeTypeHandle structureTypeHandle, out RuntimeTypeHandle unsafeStructType)
{
IntPtr marshalStub;
IntPtr unmarshalStub;
IntPtr destroyStub;
bool hasInvalidLayout;
return TryGetMarshallersForStruct(structureTypeHandle, out unsafeStructType, out marshalStub, out unmarshalStub, out destroyStub, out hasInvalidLayout);
}
public override bool TryGetStructUnmarshalStub(RuntimeTypeHandle structureTypeHandle, out IntPtr unmarshalStub)
{
RuntimeTypeHandle unsafeStructType;
IntPtr marshalStub;
IntPtr destroyStub;
bool hasInvalidLayout;
return TryGetMarshallersForStruct(structureTypeHandle, out unsafeStructType, out marshalStub, out unmarshalStub, out destroyStub, out hasInvalidLayout);
}
public override bool TryGetStructMarshalStub(RuntimeTypeHandle structureTypeHandle, out IntPtr marshalStub)
{
RuntimeTypeHandle unsafeStructType;
IntPtr unmarshalStub;
IntPtr destroyStub;
bool hasInvalidLayout;
return TryGetMarshallersForStruct(structureTypeHandle, out unsafeStructType, out marshalStub, out unmarshalStub, out destroyStub, out hasInvalidLayout);
}
public override bool TryGetDestroyStructureStub(RuntimeTypeHandle structureTypeHandle, out IntPtr destroyStub, out bool hasInvalidLayout)
{
RuntimeTypeHandle unsafeStructType;
IntPtr marshalStub;
IntPtr unmarshalStub;
return TryGetMarshallersForStruct(structureTypeHandle, out unsafeStructType, out marshalStub, out unmarshalStub, out destroyStub, out hasInvalidLayout);
}
public override bool TryGetStructFieldOffset(RuntimeTypeHandle structureTypeHandle, string fieldName, out bool structExists, out uint offset)
{
ExternalReferencesTable externalReferences;
NativeParser entryParser;
structExists = false;
if (TryGetStructData(structureTypeHandle, out externalReferences, out entryParser))
{
structExists = true;
// skip the first 4 IntPtrs
for (int i = 0; i < 4; i++)
{
entryParser.GetUnsigned();
}
uint mask = entryParser.GetUnsigned();
bool hasInvalidLayout = (mask & 0x1) == 1;
uint fieldCount = mask >> 1;
for (uint index = 0; index < fieldCount; index++)
{
string name = entryParser.GetString();
offset = entryParser.GetUnsigned();
if (name == fieldName)
{
return true;
}
}
}
offset = 0;
return false;
}
#endregion
private static unsafe bool TryGetNativeReaderForBlob(NativeFormatModuleInfo module, ReflectionMapBlob blob, out NativeReader reader)
{
byte* pBlob;
uint cbBlob;
if (module.TryFindBlob((int)blob, out pBlob, out cbBlob))
{
reader = new NativeReader(pBlob, cbBlob);
return true;
}
reader = default(NativeReader);
return false;
}
private unsafe bool TryGetMarshallersForDelegate(RuntimeTypeHandle delegateTypeHandle, out IntPtr openStub, out IntPtr closedStub, out IntPtr delegateCreationStub)
{
int delegateHashcode = delegateTypeHandle.GetHashCode();
openStub = IntPtr.Zero;
closedStub = IntPtr.Zero;
delegateCreationStub = IntPtr.Zero;
foreach (NativeFormatModuleInfo module in ModuleList.EnumerateModules())
{
NativeReader delegateMapReader;
if (TryGetNativeReaderForBlob(module, ReflectionMapBlob.DelegateMarshallingStubMap, out delegateMapReader))
{
NativeParser delegateMapParser = new NativeParser(delegateMapReader, 0);
NativeHashtable delegateHashtable = new NativeHashtable(delegateMapParser);
ExternalReferencesTable externalReferences = default(ExternalReferencesTable);
externalReferences.InitializeCommonFixupsTable(module);
var lookup = delegateHashtable.Lookup(delegateHashcode);
NativeParser entryParser;
while (!(entryParser = lookup.GetNext()).IsNull)
{
RuntimeTypeHandle foundDelegateType = externalReferences.GetRuntimeTypeHandleFromIndex(entryParser.GetUnsigned());
if (foundDelegateType.Equals(delegateTypeHandle))
{
openStub = externalReferences.GetIntPtrFromIndex(entryParser.GetUnsigned());
closedStub = externalReferences.GetIntPtrFromIndex(entryParser.GetUnsigned());
delegateCreationStub = externalReferences.GetIntPtrFromIndex(entryParser.GetUnsigned());
return true;
}
}
}
}
return false;
}
private unsafe bool TryGetStructData(RuntimeTypeHandle structTypeHandle, out ExternalReferencesTable externalReferences, out NativeParser entryParser)
{
int structHashcode = structTypeHandle.GetHashCode();
externalReferences = default(ExternalReferencesTable);
entryParser = default(NativeParser);
foreach (NativeFormatModuleInfo module in ModuleList.EnumerateModules())
{
NativeReader structMapReader;
if (TryGetNativeReaderForBlob(module, ReflectionMapBlob.StructMarshallingStubMap, out structMapReader))
{
NativeParser structMapParser = new NativeParser(structMapReader, 0);
NativeHashtable structHashtable = new NativeHashtable(structMapParser);
externalReferences.InitializeCommonFixupsTable(module);
var lookup = structHashtable.Lookup(structHashcode);
while (!(entryParser = lookup.GetNext()).IsNull)
{
RuntimeTypeHandle foundStructType = externalReferences.GetRuntimeTypeHandleFromIndex(entryParser.GetUnsigned());
if (foundStructType.Equals(structTypeHandle))
{
return true;
}
}
}
}
return false;
}
private unsafe bool TryGetMarshallersForStruct(RuntimeTypeHandle structTypeHandle, out RuntimeTypeHandle unsafeStructType, out IntPtr marshalStub, out IntPtr unmarshalStub, out IntPtr destroyStub, out bool hasInvalidLayout)
{
marshalStub = IntPtr.Zero;
unmarshalStub = IntPtr.Zero;
destroyStub = IntPtr.Zero;
unsafeStructType = default(RuntimeTypeHandle);
hasInvalidLayout = true;
ExternalReferencesTable externalReferences;
NativeParser entryParser;
if (TryGetStructData(structTypeHandle, out externalReferences, out entryParser))
{
unsafeStructType = externalReferences.GetRuntimeTypeHandleFromIndex(entryParser.GetUnsigned());
marshalStub = externalReferences.GetIntPtrFromIndex(entryParser.GetUnsigned());
unmarshalStub = externalReferences.GetIntPtrFromIndex(entryParser.GetUnsigned());
destroyStub = externalReferences.GetIntPtrFromIndex(entryParser.GetUnsigned());
uint mask = entryParser.GetUnsigned();
hasInvalidLayout = (mask & 0x1) == 1;
return true;
}
return false;
}
}
}

Просмотреть файл

@ -0,0 +1,49 @@
// 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 Internal.Runtime.Augments;
using Internal.NativeFormat;
using Internal.Runtime.TypeLoader;
using Internal.Reflection.Execution;
using System.Runtime.InteropServices;
namespace Internal.Runtime.CompilerHelpers
{
internal class RuntimeInteropData : InteropCallbacks
{
public override bool TryGetMarshallerDataForDelegate(RuntimeTypeHandle delegateTypeHandle, out McgPInvokeDelegateData data)
{
return McgModuleManager.GetPInvokeDelegateData(delegateTypeHandle, out data);
}
#region "Struct Data"
public override bool TryGetStructUnsafeStructType(RuntimeTypeHandle structureTypeHandle, out RuntimeTypeHandle unsafeStructType)
{
return McgModuleManager.TryGetStructUnsafeStructType(structureTypeHandle, out unsafeStructType);
}
public override bool TryGetStructUnmarshalStub(RuntimeTypeHandle structureTypeHandle, out IntPtr unmarshalStub)
{
return McgModuleManager.TryGetStructUnmarshalStub(structureTypeHandle, out unmarshalStub);
}
public override bool TryGetStructMarshalStub(RuntimeTypeHandle structureTypeHandle, out IntPtr marshalStub)
{
return McgModuleManager.TryGetStructMarshalStub(structureTypeHandle, out marshalStub);
}
public override bool TryGetDestroyStructureStub(RuntimeTypeHandle structureTypeHandle, out IntPtr destroyStructureStub, out bool hasInvalidLayout)
{
return McgModuleManager.TryGetDestroyStructureStub(structureTypeHandle, out destroyStructureStub, out hasInvalidLayout);
}
public override bool TryGetStructFieldOffset(RuntimeTypeHandle structureTypeHandle, string fieldName, out bool structExists, out uint offset)
{
return McgModuleManager.TryGetStructFieldOffset(structureTypeHandle, fieldName, out structExists, out offset);
}
#endregion
}
}

Просмотреть файл

@ -12,11 +12,19 @@ using System.Runtime.InteropServices;
namespace Internal.Runtime.CompilerHelpers
{
internal class Callbacks : InteropCallbacks
internal partial class RuntimeInteropData : InteropCallbacks
{
public override bool TryGetMarshallerDataForDelegate(RuntimeTypeHandle delegateTypeHandle, out McgPInvokeDelegateData data)
private static RuntimeInteropData s_interopData;
public static RuntimeInteropData Instance
{
return McgModuleManager.GetPInvokeDelegateData(delegateTypeHandle, out data);
get
{
if (s_interopData == null)
{
s_interopData = new RuntimeInteropData();
}
return s_interopData;
}
}
}
}

Просмотреть файл

@ -139,8 +139,9 @@
<Compile Include="System\Runtime\InteropServices\WindowsRuntime\EventRegistrationToken.cs" />
<Compile Include="Internal\Runtime\CompilerHelpers\LibraryInitializer.cs" />
<Compile Include="Interop\Interop.Memory.cs" />
<Compile Condition="'$(IsProjectNLibrary)' == 'true'" Include="Internal\Runtime\CompilerHelpers\Callbacks.ProjectN.cs"/>
<Compile Condition="'$(IsProjectNLibrary)' != 'true'" Include="Internal\Runtime\CompilerHelpers\Callbacks.CoreRT.cs"/>
<Compile Include="Internal\Runtime\CompilerHelpers\RuntimeInteropData.cs"/>
<Compile Condition="'$(IsProjectNLibrary)' == 'true'" Include="Internal\Runtime\CompilerHelpers\RuntimeInteropData.ProjectN.cs"/>
<Compile Condition="'$(IsProjectNLibrary)' != 'true'" Include="Internal\Runtime\CompilerHelpers\RuntimeInteropData.CoreRT.cs"/>
</ItemGroup>
<ItemGroup Condition="'$(IsProjectNLibrary)' != 'true'">
<Compile Include="..\..\Common\src\Internal\Runtime\MetadataBlob.cs">

Просмотреть файл

@ -20,6 +20,7 @@ using System.Security;
using System.Text;
using System.Threading;
using System.Runtime.InteropServices.ComTypes;
using Internal.Runtime.CompilerHelpers;
namespace System.Runtime.InteropServices
{
@ -178,7 +179,7 @@ namespace System.Runtime.InteropServices
RuntimeTypeHandle typeHandle = t.TypeHandle;
RuntimeTypeHandle unsafeStructType;
if (McgModuleManager.TryGetStructUnsafeStructType(typeHandle, out unsafeStructType))
if (RuntimeInteropData.Instance.TryGetStructUnsafeStructType(typeHandle, out unsafeStructType))
{
return unsafeStructType.GetValueTypeSize();
}
@ -216,7 +217,7 @@ namespace System.Runtime.InteropServices
{
bool structExists;
uint offset;
if (McgModuleManager.TryGetStructFieldOffset(t.TypeHandle, fieldName, out structExists, out offset))
if (RuntimeInteropData.Instance.TryGetStructFieldOffset(t.TypeHandle, fieldName, out structExists, out offset))
{
return new IntPtr(offset);
}
@ -1096,7 +1097,7 @@ namespace System.Runtime.InteropServices
}
IntPtr unmarshalStub;
if (McgModuleManager.TryGetStructUnmarshalStub(structureTypeHandle, out unmarshalStub))
if (RuntimeInteropData.Instance.TryGetStructUnmarshalStub(structureTypeHandle, out unmarshalStub))
{
InteropExtensions.PinObjectAndCall(structure,
unboxedStructPtr =>
@ -1191,7 +1192,7 @@ namespace System.Runtime.InteropServices
bool isBlittable = false; // whether Mcg treat this struct as blittable struct
IntPtr marshalStub;
if (McgModuleManager.TryGetStructMarshalStub(structureTypeHandle, out marshalStub))
if (RuntimeInteropData.Instance.TryGetStructMarshalStub(structureTypeHandle, out marshalStub))
{
if (marshalStub != IntPtr.Zero)
{
@ -1279,7 +1280,7 @@ namespace System.Runtime.InteropServices
IntPtr destroyStructureStub;
bool hasInvalidLayout;
if (McgModuleManager.TryGetDestroyStructureStub(structureTypeHandle, out destroyStructureStub, out hasInvalidLayout))
if (RuntimeInteropData.Instance.TryGetDestroyStructureStub(structureTypeHandle, out destroyStructureStub, out hasInvalidLayout))
{
if (hasInvalidLayout)
throw new ArgumentException(SR.Argument_MustHaveLayoutOrBeBlittable, structureTypeHandle.GetDisplayName());

Просмотреть файл

@ -519,6 +519,16 @@ namespace PInvokeTests
public ExplicitStruct f2;
}
[StructLayout(LayoutKind.Explicit)]
public struct TestStruct2
{
[FieldOffset(0)]
public int f1;
[FieldOffset(8)]
public bool f2;
}
private static void TestStruct()
{
@ -582,6 +592,24 @@ namespace PInvokeTests
ius.inlineString = "Hello World";
#if !CODEGEN_CPP
TestStruct2 ts = new Program.TestStruct2() { f1 = 100, f2 = true };
int size = Marshal.SizeOf<TestStruct2>(ts);
IntPtr memory = Marshal.AllocHGlobal(size);
try
{
Marshal.StructureToPtr<Program.TestStruct2>(ts, memory, false);
TestStruct2 ts2 = Marshal.PtrToStructure<Program.TestStruct2>(memory);
ThrowIfNotEquals(true, ts2.f1 == 100 && ts2.f2 == true, "Struct marshalling Marshal API failed");
IntPtr offset = Marshal.OffsetOf<Program.TestStruct2>("f2");
ThrowIfNotEquals(new IntPtr(8), offset, "Struct marshalling OffsetOf failed.");
}
finally
{
Marshal.FreeHGlobal(memory);
}
ThrowIfNotEquals(true, InlineArrayTest(ref ias, ref ius), "inline array marshalling failed");
bool pass = true;
for (short i = 0; i < 128; i++)