/// <summary> /// Checks if two types are compatible according to compatible-with as described in ECMA 335 I.8.7.1 /// Most of the checks are performed by the CanCastTo, but some cases are pre-filtered out. /// </summary> public static bool IsCompatibleWith(this TypeDesc thisType, TypeDesc otherType) { // Structs can be cast to the interfaces they implement, but they are not compatible according to ECMA I.8.7.1 bool isCastFromValueTypeToReferenceType = otherType.IsValueType && !thisType.IsValueType; if (isCastFromValueTypeToReferenceType) { return(false); } // Managed pointers are compatible only if they are pointer-element-compatible-with as described in ECMA I.8.7.2 if (thisType.IsByRef && otherType.IsByRef) { return(AreVerificationTypesEqual(thisType.GetParameterType(), otherType.GetParameterType())); } // Unmanaged pointers are handled the same way as managed pointers if (thisType.IsPointer && otherType.IsPointer) { return(AreVerificationTypesEqual(thisType.GetParameterType(), otherType.GetParameterType())); } // Function pointers are compatible only if they are method-signature-compatible-with as described in ECMA I.8.7.1 if (thisType.IsFunctionPointer && otherType.IsFunctionPointer) { return(IsMethodSignatureCompatibleWith(thisType, otherType)); } // None of the types can be a managed pointer, a pointer or a function pointer here, // all the valid cases were handled above. if (thisType.IsByRef || otherType.IsByRef || thisType.IsPointer || otherType.IsPointer || thisType.IsFunctionPointer || otherType.IsFunctionPointer) { return(false); } // Nullable<T> can be cast to T, but this is not compatible according to ECMA I.8.7.1 bool isCastFromNullableOfTtoT = thisType.IsNullable && otherType.IsEquivalentTo(thisType.Instantiation[0]); if (isCastFromNullableOfTtoT) { return(false); } return(otherType.CanCastTo(thisType)); }
// // Struct Marshalling // To support struct marshalling compiler needs to generate a native type which // imitates the original struct being passed to managed side with corresponding // fields of marshalled types. Additionally it needs to generate three thunks // 1. Managed to Native Thunk: For forward marshalling // 2. Native to Managed Thunk: For reverse marshalling // 3. Cleanup Thunk: for cleaning up any allocated resources // /// <summary> /// Generates a Native struct type which imitates the managed struct /// </summary> public NativeStructType GetStructMarshallingNativeType(TypeDesc managedType) { if (managedType is ByRefType) { managedType = managedType.GetParameterType(); } Debug.Assert(managedType is MetadataType); return(_nativeStructHashtable.GetOrCreateValue((MetadataType)managedType)); }
public PInvokeDelegateWrapper GetPInvokeDelegateWrapper(TypeDesc delegateType) { if (delegateType is ByRefType) { delegateType = delegateType.GetParameterType(); } Debug.Assert(delegateType is MetadataType); // Get the Type that wraps the native function return(_pInvokeDelegateWrapperHashtable.GetOrCreateValue((MetadataType)delegateType)); }
/// <summary> /// Generates thunk for creating delegate /// </summary> public ForwardDelegateCreationThunk GetForwardDelegateCreationThunk(TypeDesc delegateType) { if (delegateType is ByRefType) { delegateType = delegateType.GetParameterType(); } Debug.Assert(delegateType is MetadataType); // Get the stub for creating delegate return(_forwardDelegateCreationStubHashtable.GetOrCreateValue((MetadataType)delegateType)); }
/// <summary> /// Generates a thunk to marshal the fields of the struct from native to managed /// </summary> public MethodDesc GetStructMarshallingNativeToManagedThunk(TypeDesc managedType) { if (managedType is ByRefType) { managedType = managedType.GetParameterType(); } Debug.Assert(managedType is MetadataType); var methodKey = new StructMarshallingThunkKey((MetadataType)managedType, StructMarshallingThunkType.NativeToManaged); return(_structMarshallingThunkHashtable.GetOrCreateValue(methodKey)); }
/// <summary> /// Generates marshalling stubs for closed instance delegates /// </summary> public DelegateMarshallingMethodThunk GetClosedDelegateMarshallingThunk(TypeDesc delegateType) { if (delegateType is ByRefType) { delegateType = delegateType.GetParameterType(); } Debug.Assert(delegateType is MetadataType); // Get the stub for marshalling open static delegate var stubKey = new DelegateMarshallingStubHashtableKey((MetadataType)delegateType, DelegateMarshallingMethodThunkKind.ReverseClosed); return(_delegateMarshallingThunkHashtable.GetOrCreateValue(stubKey)); }
private void EncodeType(BlobBuilder blobBuilder, TypeDesc type, EmbeddedSignatureDataEmitter signatureDataEmitter) { signatureDataEmitter.Push(); signatureDataEmitter.Push(); signatureDataEmitter.EmitAtCurrentIndexStack(blobBuilder); signatureDataEmitter.Pop(); signatureDataEmitter.Push(); if (type.IsPrimitive) { SignatureTypeCode primitiveCode; switch (type.Category) { case TypeFlags.Void: primitiveCode = SignatureTypeCode.Void; break; case TypeFlags.Boolean: primitiveCode = SignatureTypeCode.Boolean; break; case TypeFlags.Char: primitiveCode = SignatureTypeCode.Char; break; case TypeFlags.SByte: primitiveCode = SignatureTypeCode.SByte; break; case TypeFlags.Byte: primitiveCode = SignatureTypeCode.Byte; break; case TypeFlags.Int16: primitiveCode = SignatureTypeCode.Int16; break; case TypeFlags.UInt16: primitiveCode = SignatureTypeCode.UInt16; break; case TypeFlags.Int32: primitiveCode = SignatureTypeCode.Int32; break; case TypeFlags.UInt32: primitiveCode = SignatureTypeCode.UInt32; break; case TypeFlags.Int64: primitiveCode = SignatureTypeCode.Int64; break; case TypeFlags.UInt64: primitiveCode = SignatureTypeCode.UInt64; break; case TypeFlags.IntPtr: primitiveCode = SignatureTypeCode.IntPtr; break; case TypeFlags.UIntPtr: primitiveCode = SignatureTypeCode.UIntPtr; break; case TypeFlags.Single: primitiveCode = SignatureTypeCode.Single; break; case TypeFlags.Double: primitiveCode = SignatureTypeCode.Double; break; default: throw new Exception("Unknown primitive type"); } blobBuilder.WriteByte((byte)primitiveCode); } else if (type.IsSzArray) { blobBuilder.WriteByte((byte)SignatureTypeCode.SZArray); EncodeType(blobBuilder, type.GetParameterType(), signatureDataEmitter); } else if (type.IsArray) { var arrayType = (ArrayType)type; blobBuilder.WriteByte((byte)SignatureTypeCode.Array); EncodeType(blobBuilder, type.GetParameterType(), signatureDataEmitter); signatureDataEmitter.EmitArrayShapeAtCurrentIndexStack(blobBuilder, arrayType.Rank); } else if (type.IsPointer) { blobBuilder.WriteByte((byte)SignatureTypeCode.Pointer); EncodeType(blobBuilder, type.GetParameterType(), signatureDataEmitter); } else if (type.IsFunctionPointer) { FunctionPointerType fnptrType = (FunctionPointerType)type; blobBuilder.WriteByte((byte)SignatureTypeCode.FunctionPointer); EncodeMethodSignature(blobBuilder, fnptrType.Signature, signatureDataEmitter); } else if (type.IsByRef) { blobBuilder.WriteByte((byte)SignatureTypeCode.ByReference); EncodeType(blobBuilder, type.GetParameterType(), signatureDataEmitter); } else if (type.IsObject) { blobBuilder.WriteByte((byte)SignatureTypeCode.Object); } else if (type.IsString) { blobBuilder.WriteByte((byte)SignatureTypeCode.String); } else if (type.IsWellKnownType(WellKnownType.TypedReference)) { blobBuilder.WriteByte((byte)SignatureTypeCode.TypedReference); } else if (type.IsWellKnownType(WellKnownType.Void)) { blobBuilder.WriteByte((byte)SignatureTypeCode.Void); } else if (type is SignatureVariable) { SignatureVariable sigVar = (SignatureVariable)type; SignatureTypeCode code = sigVar.IsMethodSignatureVariable ? SignatureTypeCode.GenericMethodParameter : SignatureTypeCode.GenericTypeParameter; blobBuilder.WriteByte((byte)code); blobBuilder.WriteCompressedInteger(sigVar.Index); } else if (type is InstantiatedType) { blobBuilder.WriteByte((byte)SignatureTypeCode.GenericTypeInstance); EncodeType(blobBuilder, type.GetTypeDefinition(), signatureDataEmitter); blobBuilder.WriteCompressedInteger(type.Instantiation.Length); foreach (var instantiationArg in type.Instantiation) { EncodeType(blobBuilder, instantiationArg, signatureDataEmitter); } } else if (type is MetadataType) { var metadataType = (MetadataType)type; // Must be class or valuetype blobBuilder.WriteByte(type.IsValueType ? (byte)SignatureTypeKind.ValueType : (byte)SignatureTypeKind.Class); int codedIndex = CodedIndex.TypeDefOrRef(GetTypeRef(metadataType)); blobBuilder.WriteCompressedInteger(codedIndex); } else { throw new Exception("Unexpected type"); } signatureDataEmitter.Pop(); signatureDataEmitter.Pop(); }