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