1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4 
5 using System;
6 using Internal.IL.Stubs;
7 using Internal.TypeSystem.Interop;
8 using Debug = System.Diagnostics.Debug;
9 
10 namespace Internal.TypeSystem
11 {
12     /// <summary>
13     /// This class manages and caches  interop state information
14     /// </summary>
15     public sealed class InteropStateManager
16     {
17         private readonly ModuleDesc _generatedAssembly;
18         private readonly NativeStructTypeHashtable _nativeStructHashtable;
19         private readonly StructMarshallingThunkHashTable _structMarshallingThunkHashtable;
20         private readonly DelegateMarshallingStubHashtable _delegateMarshallingThunkHashtable;
21         private readonly ForwardDelegateCreationStubHashtable _forwardDelegateCreationStubHashtable;
22         private readonly PInvokeDelegateWrapperHashtable _pInvokeDelegateWrapperHashtable;
23         private readonly InlineArrayHashTable _inlineArrayHashtable;
24         private readonly PInvokeLazyFixupFieldHashtable _pInvokeLazyFixupFieldHashtable;
25 
InteropStateManager(ModuleDesc generatedAssembly)26         public InteropStateManager(ModuleDesc generatedAssembly)
27         {
28             _generatedAssembly = generatedAssembly;
29             _structMarshallingThunkHashtable = new StructMarshallingThunkHashTable(this, _generatedAssembly.GetGlobalModuleType());
30             _nativeStructHashtable = new NativeStructTypeHashtable(this, _generatedAssembly);
31             _delegateMarshallingThunkHashtable = new DelegateMarshallingStubHashtable(this, _generatedAssembly.GetGlobalModuleType());
32             _forwardDelegateCreationStubHashtable = new ForwardDelegateCreationStubHashtable(this, _generatedAssembly.GetGlobalModuleType());
33             _pInvokeDelegateWrapperHashtable = new PInvokeDelegateWrapperHashtable(this, _generatedAssembly);
34             _inlineArrayHashtable = new InlineArrayHashTable(this, _generatedAssembly);
35             _pInvokeLazyFixupFieldHashtable = new PInvokeLazyFixupFieldHashtable(_generatedAssembly.GetGlobalModuleType());
36         }
37         //
38         // Delegate Marshalling Stubs
39         //
40 
41         /// <summary>
42         /// Generates marshalling stubs for open static delegates
43         /// </summary>
GetOpenStaticDelegateMarshallingThunk(TypeDesc delegateType)44         public DelegateMarshallingMethodThunk GetOpenStaticDelegateMarshallingThunk(TypeDesc delegateType)
45         {
46             if (delegateType is ByRefType)
47             {
48                 delegateType = delegateType.GetParameterType();
49             }
50 
51             Debug.Assert(delegateType is MetadataType);
52 
53 
54             // Get the stub for marshalling open static delegate
55             var stubKey = new DelegateMarshallingStubHashtableKey((MetadataType)delegateType, DelegateMarshallingMethodThunkKind.ReverseOpenStatic);
56             return _delegateMarshallingThunkHashtable.GetOrCreateValue(stubKey);
57         }
58 
59         /// <summary>
60         /// Generates marshalling stubs for closed instance delegates
61         /// </summary>
GetClosedDelegateMarshallingThunk(TypeDesc delegateType)62         public DelegateMarshallingMethodThunk GetClosedDelegateMarshallingThunk(TypeDesc delegateType)
63         {
64             if (delegateType is ByRefType)
65             {
66                 delegateType = delegateType.GetParameterType();
67             }
68 
69             Debug.Assert(delegateType is MetadataType);
70 
71 
72             // Get the stub for marshalling open static delegate
73             var stubKey = new DelegateMarshallingStubHashtableKey((MetadataType)delegateType, DelegateMarshallingMethodThunkKind.ReverseClosed);
74             return _delegateMarshallingThunkHashtable.GetOrCreateValue(stubKey);
75         }
76 
77         /// <summary>
78         /// Generates thunk for creating delegate
79         /// </summary>
GetForwardDelegateCreationThunk(TypeDesc delegateType)80         public ForwardDelegateCreationThunk GetForwardDelegateCreationThunk(TypeDesc delegateType)
81         {
82             if (delegateType is ByRefType)
83             {
84                 delegateType = delegateType.GetParameterType();
85             }
86 
87             Debug.Assert(delegateType is MetadataType);
88 
89             // Get the stub for creating delegate
90             return _forwardDelegateCreationStubHashtable.GetOrCreateValue((MetadataType)delegateType);
91         }
92 
GetPInvokeDelegateWrapper(TypeDesc delegateType)93         public PInvokeDelegateWrapper GetPInvokeDelegateWrapper(TypeDesc delegateType)
94         {
95             if (delegateType is ByRefType)
96             {
97                 delegateType = delegateType.GetParameterType();
98             }
99 
100             Debug.Assert(delegateType is MetadataType);
101 
102             // Get the Type that wraps the native function
103             return _pInvokeDelegateWrapperHashtable.GetOrCreateValue((MetadataType)delegateType);
104         }
105 
106         //
107         //  Struct Marshalling
108         //  To support struct marshalling compiler needs to generate a native type which
109         //  imitates the original struct being passed to managed side with corresponding
110         //  fields of marshalled types. Additionally it needs to generate three thunks
111         //      1. Managed to Native Thunk: For forward marshalling
112         //      2. Native to Managed Thunk: For reverse marshalling
113         //      3. Cleanup Thunk: for cleaning up any allocated resources
114         //
115         /// <summary>
116         /// Generates a Native struct type which imitates the managed struct
117         /// </summary>
GetStructMarshallingNativeType(TypeDesc managedType)118         public NativeStructType GetStructMarshallingNativeType(TypeDesc managedType)
119         {
120             if (managedType is ByRefType)
121             {
122                 managedType = managedType.GetParameterType();
123             }
124 
125             Debug.Assert(managedType is MetadataType);
126 
127             return _nativeStructHashtable.GetOrCreateValue((MetadataType)managedType);
128         }
129 
130         /// <summary>
131         ///  Generates a thunk to marshal the fields of the struct from managed to native
132         /// </summary>
GetStructMarshallingManagedToNativeThunk(TypeDesc managedType)133         public MethodDesc GetStructMarshallingManagedToNativeThunk(TypeDesc managedType)
134         {
135             if (managedType is ByRefType)
136             {
137                 managedType = managedType.GetParameterType();
138             }
139 
140             Debug.Assert(managedType is MetadataType);
141 
142             var methodKey = new StructMarshallingThunkKey((MetadataType)managedType, StructMarshallingThunkType.ManagedToNative);
143             return _structMarshallingThunkHashtable.GetOrCreateValue(methodKey);
144         }
145 
146         /// <summary>
147         ///  Generates a thunk to marshal the fields of the struct from native to managed
148         /// </summary>
GetStructMarshallingNativeToManagedThunk(TypeDesc managedType)149         public MethodDesc GetStructMarshallingNativeToManagedThunk(TypeDesc managedType)
150         {
151             if (managedType is ByRefType)
152             {
153                 managedType = managedType.GetParameterType();
154             }
155 
156             Debug.Assert(managedType is MetadataType);
157 
158 
159             var methodKey = new StructMarshallingThunkKey((MetadataType)managedType, StructMarshallingThunkType.NativeToManage);
160             return _structMarshallingThunkHashtable.GetOrCreateValue(methodKey);
161         }
162 
163         /// <summary>
164         ///  Generates a thunk to cleanup any allocated resources during marshalling
165         /// </summary>
GetStructMarshallingCleanupThunk(TypeDesc managedType)166         public MethodDesc GetStructMarshallingCleanupThunk(TypeDesc managedType)
167         {
168             if (managedType is ByRefType)
169             {
170                 managedType = ((ByRefType)managedType).GetParameterType();
171             }
172 
173             Debug.Assert(managedType is MetadataType);
174 
175 
176             var methodKey = new StructMarshallingThunkKey((MetadataType)managedType, StructMarshallingThunkType.Cleanup);
177             return _structMarshallingThunkHashtable.GetOrCreateValue(methodKey);
178         }
179 
GetInlineArrayType(InlineArrayCandidate candidate)180         public TypeDesc GetInlineArrayType(InlineArrayCandidate candidate)
181         {
182             return _inlineArrayHashtable.GetOrCreateValue(candidate);
183         }
184 
GetPInvokeLazyFixupField(MethodDesc method)185         public FieldDesc GetPInvokeLazyFixupField(MethodDesc method)
186         {
187             return _pInvokeLazyFixupFieldHashtable.GetOrCreateValue(method);
188         }
189 
190         private class NativeStructTypeHashtable : LockFreeReaderHashtable<MetadataType, NativeStructType>
191         {
GetKeyHashCode(MetadataType key)192             protected override int GetKeyHashCode(MetadataType key)
193             {
194                 return key.GetHashCode();
195             }
196 
GetValueHashCode(NativeStructType value)197             protected override int GetValueHashCode(NativeStructType value)
198             {
199                 return value.ManagedStructType.GetHashCode();
200             }
201 
CompareKeyToValue(MetadataType key, NativeStructType value)202             protected override bool CompareKeyToValue(MetadataType key, NativeStructType value)
203             {
204                 return Object.ReferenceEquals(key, value.ManagedStructType);
205             }
206 
CompareValueToValue(NativeStructType value1, NativeStructType value2)207             protected override bool CompareValueToValue(NativeStructType value1, NativeStructType value2)
208             {
209                 return Object.ReferenceEquals(value1.ManagedStructType, value2.ManagedStructType);
210             }
211 
CreateValueFromKey(MetadataType key)212             protected override NativeStructType CreateValueFromKey(MetadataType key)
213             {
214                 return new NativeStructType(_owningModule, key, _interopStateManager);
215             }
216 
217             private readonly InteropStateManager _interopStateManager;
218             private readonly ModuleDesc _owningModule;
219 
NativeStructTypeHashtable(InteropStateManager interopStateManager, ModuleDesc owningModule)220             public NativeStructTypeHashtable(InteropStateManager interopStateManager, ModuleDesc owningModule)
221             {
222                 _interopStateManager = interopStateManager;
223                 _owningModule = owningModule;
224             }
225         }
226 
227         private struct StructMarshallingThunkKey
228         {
229             public readonly MetadataType ManagedType;
230             public readonly StructMarshallingThunkType ThunkType;
231 
StructMarshallingThunkKeyInternal.TypeSystem.InteropStateManager.StructMarshallingThunkKey232             public StructMarshallingThunkKey(MetadataType type, StructMarshallingThunkType thunkType)
233             {
234                 ManagedType = type;
235                 ThunkType = thunkType;
236             }
237         }
238 
239         private class StructMarshallingThunkHashTable : LockFreeReaderHashtable<StructMarshallingThunkKey, StructMarshallingThunk>
240         {
GetKeyHashCode(StructMarshallingThunkKey key)241             protected override int GetKeyHashCode(StructMarshallingThunkKey key)
242             {
243                 return key.ManagedType.GetHashCode() ^ (int)key.ThunkType;
244             }
245 
GetValueHashCode(StructMarshallingThunk value)246             protected override int GetValueHashCode(StructMarshallingThunk value)
247             {
248                 return value.ManagedType.GetHashCode() ^ (int)value.ThunkType;
249             }
250 
CompareKeyToValue(StructMarshallingThunkKey key, StructMarshallingThunk value)251             protected override bool CompareKeyToValue(StructMarshallingThunkKey key, StructMarshallingThunk value)
252             {
253                 return Object.ReferenceEquals(key.ManagedType, value.ManagedType) &&
254                         key.ThunkType == value.ThunkType;
255             }
256 
CompareValueToValue(StructMarshallingThunk value1, StructMarshallingThunk value2)257             protected override bool CompareValueToValue(StructMarshallingThunk value1, StructMarshallingThunk value2)
258             {
259                 return Object.ReferenceEquals(value1.ManagedType, value2.ManagedType) &&
260                         value1.ThunkType == value2.ThunkType;
261             }
262 
CreateValueFromKey(StructMarshallingThunkKey key)263             protected override StructMarshallingThunk CreateValueFromKey(StructMarshallingThunkKey key)
264             {
265                 return new StructMarshallingThunk(_owningType, key.ManagedType, key.ThunkType, _interopStateManager);
266             }
267 
268             private readonly InteropStateManager _interopStateManager;
269             private readonly TypeDesc _owningType;
270 
StructMarshallingThunkHashTable(InteropStateManager interopStateManager, TypeDesc owningType)271             public StructMarshallingThunkHashTable(InteropStateManager interopStateManager, TypeDesc owningType)
272             {
273                 _interopStateManager = interopStateManager;
274                 _owningType = owningType;
275             }
276         }
277 
278         private class InlineArrayHashTable : LockFreeReaderHashtable<InlineArrayCandidate, InlineArrayType>
279         {
GetKeyHashCode(InlineArrayCandidate key)280             protected override int GetKeyHashCode(InlineArrayCandidate key)
281             {
282                 return key.ElementType.GetHashCode() ^ (int)key.Length;
283             }
284 
GetValueHashCode(InlineArrayType value)285             protected override int GetValueHashCode(InlineArrayType value)
286             {
287                 return value.ElementType.GetHashCode() ^ (int)value.Length;
288             }
289 
CompareKeyToValue(InlineArrayCandidate key, InlineArrayType value)290             protected override bool CompareKeyToValue(InlineArrayCandidate key, InlineArrayType value)
291             {
292                 return Object.ReferenceEquals(key.ElementType, value.ElementType) &&
293                         key.Length == value.Length;
294             }
295 
CompareValueToValue(InlineArrayType value1, InlineArrayType value2)296             protected override bool CompareValueToValue(InlineArrayType value1, InlineArrayType value2)
297             {
298                 return Object.ReferenceEquals(value1.ElementType, value2.ElementType) &&
299                         value1.Length == value2.Length;
300             }
301 
CreateValueFromKey(InlineArrayCandidate key)302             protected override InlineArrayType CreateValueFromKey(InlineArrayCandidate key)
303             {
304                 return new InlineArrayType(_owningModule, key.ElementType, key.Length, _interopStateManager);
305             }
306 
307             private readonly InteropStateManager _interopStateManager;
308             private readonly ModuleDesc _owningModule;
309 
InlineArrayHashTable(InteropStateManager interopStateManager, ModuleDesc owningModule)310             public InlineArrayHashTable(InteropStateManager interopStateManager, ModuleDesc owningModule)
311             {
312                 _interopStateManager = interopStateManager;
313                 _owningModule = owningModule;
314             }
315         }
316 
317         private struct DelegateMarshallingStubHashtableKey
318         {
319             public readonly MetadataType DelegateType;
320             public readonly DelegateMarshallingMethodThunkKind Kind;
321 
DelegateMarshallingStubHashtableKeyInternal.TypeSystem.InteropStateManager.DelegateMarshallingStubHashtableKey322             public DelegateMarshallingStubHashtableKey(MetadataType type, DelegateMarshallingMethodThunkKind kind)
323             {
324                 DelegateType = type;
325                 Kind = kind;
326             }
327         }
328         private class DelegateMarshallingStubHashtable : LockFreeReaderHashtable<DelegateMarshallingStubHashtableKey, DelegateMarshallingMethodThunk>
329         {
GetKeyHashCode(DelegateMarshallingStubHashtableKey key)330             protected override int GetKeyHashCode(DelegateMarshallingStubHashtableKey key)
331             {
332                 return key.DelegateType.GetHashCode() ^ (int)key.Kind;
333             }
334 
GetValueHashCode(DelegateMarshallingMethodThunk value)335             protected override int GetValueHashCode(DelegateMarshallingMethodThunk value)
336             {
337                 return value.DelegateType.GetHashCode() ^ (int)value.Kind;
338             }
339 
CompareKeyToValue(DelegateMarshallingStubHashtableKey key, DelegateMarshallingMethodThunk value)340             protected override bool CompareKeyToValue(DelegateMarshallingStubHashtableKey key, DelegateMarshallingMethodThunk value)
341             {
342                 return Object.ReferenceEquals(key.DelegateType, value.DelegateType) &&
343                     key.Kind== value.Kind;
344             }
345 
CompareValueToValue(DelegateMarshallingMethodThunk value1, DelegateMarshallingMethodThunk value2)346             protected override bool CompareValueToValue(DelegateMarshallingMethodThunk value1, DelegateMarshallingMethodThunk value2)
347             {
348                 return Object.ReferenceEquals(value1.DelegateType, value2.DelegateType) &&
349                     value1.Kind== value2.Kind;
350             }
351 
CreateValueFromKey(DelegateMarshallingStubHashtableKey key)352             protected override DelegateMarshallingMethodThunk CreateValueFromKey(DelegateMarshallingStubHashtableKey key)
353             {
354                 return new DelegateMarshallingMethodThunk(key.DelegateType, _owningType,
355                     _interopStateManager, key.Kind);
356             }
357 
358             private TypeDesc _owningType;
359             private InteropStateManager _interopStateManager;
360 
DelegateMarshallingStubHashtable(InteropStateManager interopStateManager, TypeDesc owningType)361             public DelegateMarshallingStubHashtable(InteropStateManager interopStateManager, TypeDesc owningType)
362             {
363                 _interopStateManager = interopStateManager;
364                 _owningType = owningType;
365             }
366         }
367 
368         private class ForwardDelegateCreationStubHashtable : LockFreeReaderHashtable<MetadataType, ForwardDelegateCreationThunk>
369         {
GetKeyHashCode(MetadataType key)370             protected override int GetKeyHashCode(MetadataType key)
371             {
372                 return key.GetHashCode();
373             }
374 
GetValueHashCode(ForwardDelegateCreationThunk value)375             protected override int GetValueHashCode(ForwardDelegateCreationThunk value)
376             {
377                 return value.DelegateType.GetHashCode();
378             }
379 
CompareKeyToValue(MetadataType key, ForwardDelegateCreationThunk value)380             protected override bool CompareKeyToValue(MetadataType key, ForwardDelegateCreationThunk value)
381             {
382                 return Object.ReferenceEquals(key, value.DelegateType);
383             }
384 
CompareValueToValue(ForwardDelegateCreationThunk value1, ForwardDelegateCreationThunk value2)385             protected override bool CompareValueToValue(ForwardDelegateCreationThunk value1, ForwardDelegateCreationThunk value2)
386             {
387                 return Object.ReferenceEquals(value1.DelegateType, value2.DelegateType);
388             }
389 
CreateValueFromKey(MetadataType key)390             protected override ForwardDelegateCreationThunk CreateValueFromKey(MetadataType key)
391             {
392                 return new ForwardDelegateCreationThunk(key, _owningType, _interopStateManager);
393             }
394 
395             private TypeDesc _owningType;
396             private InteropStateManager _interopStateManager;
397 
ForwardDelegateCreationStubHashtable(InteropStateManager interopStateManager, TypeDesc owningType)398             public ForwardDelegateCreationStubHashtable(InteropStateManager interopStateManager, TypeDesc owningType)
399             {
400                 _interopStateManager = interopStateManager;
401                 _owningType = owningType;
402             }
403         }
404 
405         private class PInvokeDelegateWrapperHashtable : LockFreeReaderHashtable<MetadataType, PInvokeDelegateWrapper>
406         {
GetKeyHashCode(MetadataType key)407             protected override int GetKeyHashCode(MetadataType key)
408             {
409                 return key.GetHashCode();
410             }
411 
GetValueHashCode(PInvokeDelegateWrapper value)412             protected override int GetValueHashCode(PInvokeDelegateWrapper value)
413             {
414                 return value.DelegateType.GetHashCode();
415             }
416 
CompareKeyToValue(MetadataType key, PInvokeDelegateWrapper value)417             protected override bool CompareKeyToValue(MetadataType key, PInvokeDelegateWrapper value)
418             {
419                 return Object.ReferenceEquals(key, value.DelegateType);
420             }
421 
CompareValueToValue(PInvokeDelegateWrapper value1, PInvokeDelegateWrapper value2)422             protected override bool CompareValueToValue(PInvokeDelegateWrapper value1, PInvokeDelegateWrapper value2)
423             {
424                 return Object.ReferenceEquals(value1.DelegateType, value2.DelegateType);
425             }
426 
CreateValueFromKey(MetadataType key)427             protected override PInvokeDelegateWrapper CreateValueFromKey(MetadataType key)
428             {
429                 return new PInvokeDelegateWrapper(_owningModule, key, _interopStateManager);
430             }
431 
432             private readonly InteropStateManager _interopStateManager;
433             private readonly ModuleDesc _owningModule;
434 
PInvokeDelegateWrapperHashtable(InteropStateManager interopStateManager, ModuleDesc owningModule)435             public PInvokeDelegateWrapperHashtable(InteropStateManager interopStateManager, ModuleDesc owningModule)
436             {
437                 _interopStateManager = interopStateManager;
438                 _owningModule = owningModule;
439             }
440         }
441 
442         private class PInvokeLazyFixupFieldHashtable : LockFreeReaderHashtable<MethodDesc, PInvokeLazyFixupField>
443         {
GetKeyHashCode(MethodDesc key)444             protected override int GetKeyHashCode(MethodDesc key)
445             {
446                 return key.GetHashCode();
447             }
448 
GetValueHashCode(PInvokeLazyFixupField value)449             protected override int GetValueHashCode(PInvokeLazyFixupField value)
450             {
451                 return value.TargetMethod.GetHashCode();
452             }
453 
CompareKeyToValue(MethodDesc key, PInvokeLazyFixupField value)454             protected override bool CompareKeyToValue(MethodDesc key, PInvokeLazyFixupField value)
455             {
456                 return key == value.TargetMethod;
457             }
458 
CompareValueToValue(PInvokeLazyFixupField value1, PInvokeLazyFixupField value2)459             protected override bool CompareValueToValue(PInvokeLazyFixupField value1, PInvokeLazyFixupField value2)
460             {
461                 return value1.TargetMethod == value2.TargetMethod;
462             }
463 
CreateValueFromKey(MethodDesc key)464             protected override PInvokeLazyFixupField CreateValueFromKey(MethodDesc key)
465             {
466                 return new PInvokeLazyFixupField(_owningType, key);
467             }
468 
469             private readonly DefType _owningType;
470 
PInvokeLazyFixupFieldHashtable(DefType owningType)471             public PInvokeLazyFixupFieldHashtable(DefType owningType)
472             {
473                 _owningType = owningType;
474             }
475         }
476     }
477 }
478