private void EmitInstantiatedTypeSignature(InstantiatedType type, SignatureContext context) { EcmaModule targetModule = context.GetTargetModule(type); EmitModuleOverride(targetModule, context); EmitElementType(CorElementType.ELEMENT_TYPE_GENERICINST); EmitTypeSignature(type.GetTypeDefinition(), context.InnerContext(targetModule)); SignatureContext outerContext = context.OuterContext; EmitUInt((uint)type.Instantiation.Length); for (int paramIndex = 0; paramIndex < type.Instantiation.Length; paramIndex++) { EmitTypeSignature(type.Instantiation[paramIndex], outerContext); } }
public void TestVariantCasting() { TypeDesc stringType = _context.GetWellKnownType(WellKnownType.String); TypeDesc objectType = _context.GetWellKnownType(WellKnownType.Object); TypeDesc exceptionType = _context.GetWellKnownType(WellKnownType.Exception); TypeDesc stringSzArrayType = stringType.MakeArrayType(); MetadataType iEnumerableOfTType = _context.SystemModule.GetType("System.Collections.Generic", "IEnumerable`1"); InstantiatedType iEnumerableOfObjectType = iEnumerableOfTType.MakeInstantiatedType(objectType); InstantiatedType iEnumerableOfExceptionType = iEnumerableOfTType.MakeInstantiatedType(exceptionType); Assert.True(stringSzArrayType.CanCastTo(iEnumerableOfObjectType)); Assert.False(stringSzArrayType.CanCastTo(iEnumerableOfExceptionType)); }
public void TestVirtualDispatchOnGenericType() { // Verifies that virtual dispatch to a non-generic method on a generic instantiation works DefType objectType = _context.GetWellKnownType(WellKnownType.Object); MethodSignature toStringSig = new MethodSignature(MethodSignatureFlags.None, 0, _stringType, Array.Empty <TypeDesc>()); MethodDesc objectToString = objectType.GetMethod("ToString", toStringSig); Assert.NotNull(objectToString); MetadataType openTestType = _testModule.GetType("VirtualFunctionOverride", "SimpleGeneric`1"); InstantiatedType testInstance = openTestType.MakeInstantiatedType(new Instantiation(new TypeDesc[] { objectType })); MethodDesc targetOnInstance = testInstance.GetMethod("ToString", toStringSig); MethodDesc targetMethod = testInstance.FindVirtualFunctionTargetMethodOnObjectType(objectToString); Assert.Equal(targetOnInstance, targetMethod); }
public void TestArrayInterfaceCasting() { TypeDesc intType = _context.GetWellKnownType(WellKnownType.Int32); MetadataType iListType = _context.SystemModule.GetType("System.Collections", "IList"); MetadataType iListOfTType = _context.SystemModule.GetType("System.Collections.Generic", "IList`1"); InstantiatedType iListOfIntType = iListOfTType.MakeInstantiatedType(intType); TypeDesc intSzArrayType = intType.MakeArrayType(); TypeDesc intArrayType = intType.MakeArrayType(1); Assert.True(intSzArrayType.CanCastTo(iListOfIntType)); Assert.True(intSzArrayType.CanCastTo(iListType)); Assert.False(intArrayType.CanCastTo(iListOfIntType)); Assert.True(intArrayType.CanCastTo(iListType)); }
public override IEnumerable <MethodDesc> ComputeAllVirtualMethods(TypeDesc type) { var context = (CompilerTypeSystemContext)type.Context; InstantiatedType instantiatedType = type as InstantiatedType; if (instantiatedType != null) { DelegateInfo info = context.GetDelegateInfo(type.GetTypeDefinition()); yield return(context.GetMethodForInstantiatedType(info.GetThunkMethod, instantiatedType)); } else { DelegateInfo info = context.GetDelegateInfo(type); yield return(info.GetThunkMethod); } }
protected virtual IEnumerable<MethodDesc> GetAllMethodsForDelegate(TypeDesc type) { // Inject the synthetic methods that support the implementation of the delegate. InstantiatedType instantiatedType = type as InstantiatedType; if (instantiatedType != null) { DelegateInfo info = GetDelegateInfo(type.GetTypeDefinition()); foreach (MethodDesc syntheticMethod in info.Methods) yield return GetMethodForInstantiatedType(syntheticMethod, instantiatedType); } else { DelegateInfo info = GetDelegateInfo(type); foreach (MethodDesc syntheticMethod in info.Methods) yield return syntheticMethod; } // Append all the methods defined in metadata foreach (var m in type.GetMethods()) yield return m; }
/// <summary> /// Convert from an unboxing stub to the actual target method /// </summary> public MethodDesc GetTargetOfSpecialUnboxingThunk(MethodDesc method) { MethodDesc typicalMethodTarget = ((GenericUnboxingThunk)method.GetTypicalMethodDefinition()).TargetMethod; MethodDesc methodOnInstantiatedType = typicalMethodTarget; if (method.OwningType.HasInstantiation) { InstantiatedType instantiatedType = GetInstantiatedType((MetadataType)typicalMethodTarget.OwningType, method.OwningType.Instantiation); methodOnInstantiatedType = GetMethodForInstantiatedType(typicalMethodTarget, instantiatedType); } MethodDesc instantiatedMethod = methodOnInstantiatedType; if (method.HasInstantiation) { instantiatedMethod = GetInstantiatedMethod(methodOnInstantiatedType, method.Instantiation); } return(instantiatedMethod); }
private IEnumerable <MethodDesc> GetAllMethodsForDelegate(TypeDesc type) { // Inject the synthetic GetThunk virtual override InstantiatedType instantiatedType = type as InstantiatedType; if (instantiatedType != null) { DelegateInfo info = GetDelegateInfo(type.GetTypeDefinition()); yield return(GetMethodForInstantiatedType(info.GetThunkMethod, instantiatedType)); } else { DelegateInfo info = GetDelegateInfo(type); yield return(info.GetThunkMethod); } // Append all the methods defined in metadata foreach (var m in type.GetMethods()) { yield return(m); } }
public MethodDesc GetUnboxingThunk(MethodDesc targetMethod, ModuleDesc ownerModuleOfThunk) { TypeDesc owningType = targetMethod.OwningType; Debug.Assert(owningType.IsValueType); var owningTypeDefinition = (MetadataType)owningType.GetTypeDefinition(); // Get a reference type that has the same layout as the boxed valuetype. var typeKey = new BoxedValuetypeHashtableKey(owningTypeDefinition, ownerModuleOfThunk); BoxedValueType boxedTypeDefinition = _boxedValuetypeHashtable.GetOrCreateValue(typeKey); // Get a method on the reference type with the same signature as the target method (but different // calling convention, since 'this' will be a reference type). var targetMethodDefinition = targetMethod.GetTypicalMethodDefinition(); var methodKey = new UnboxingThunkHashtableKey(targetMethodDefinition, boxedTypeDefinition); UnboxingThunk thunkDefinition = _nonGenericUnboxingThunkHashtable.GetOrCreateValue(methodKey); // Find the thunk on the instantiated version of the reference type. MethodDesc thunk; if (owningType != owningTypeDefinition) { InstantiatedType boxedType = boxedTypeDefinition.MakeInstantiatedType(owningType.Instantiation); thunk = GetMethodForInstantiatedType(thunkDefinition, boxedType); } else { thunk = thunkDefinition; } if (thunk.HasInstantiation) { thunk = thunk.MakeInstantiatedMethod(targetMethod.Instantiation); } return(thunk); }
protected virtual IEnumerable <MethodDesc> GetAllMethodsForDelegate(TypeDesc type, bool virtualOnly) { // Inject the synthetic methods that support the implementation of the delegate. InstantiatedType instantiatedType = type as InstantiatedType; if (instantiatedType != null) { DelegateInfo info = GetDelegateInfo(type.GetTypeDefinition()); foreach (MethodDesc syntheticMethod in info.Methods) { if (!virtualOnly || syntheticMethod.IsVirtual) { yield return(GetMethodForInstantiatedType(syntheticMethod, instantiatedType)); } } } else { DelegateInfo info = GetDelegateInfo(type); foreach (MethodDesc syntheticMethod in info.Methods) { if (!virtualOnly || syntheticMethod.IsVirtual) { yield return(syntheticMethod); } } } // Append all the methods defined in metadata IEnumerable <MethodDesc> metadataMethods = virtualOnly ? type.GetVirtualMethods() : type.GetMethods(); foreach (var m in metadataMethods) { yield return(m); } }
public string Visit(IType type, OutputSettings settings) { StringBuilder result = new StringBuilder(); if (type is AnonymousType) { result.Append("new {"); foreach (IProperty property in type.Properties) { result.AppendLine(); result.Append("\t"); if (property.ReturnType != null && !string.IsNullOrEmpty(property.ReturnType.FullName)) { result.Append(property.ReturnType.AcceptVisitor(this, settings)); result.Append(" "); } else { result.Append("? "); } result.Append(property.Name); result.Append(";"); } result.AppendLine(); result.Append("}"); return(result.ToString()); } InstantiatedType instantiatedType = type as InstantiatedType; string modStr = base.GetString(type.ClassType == ClassType.Enum ? (type.Modifiers & ~Modifiers.Sealed) : type.Modifiers); string modifiers = !String.IsNullOrEmpty(modStr) ? settings.EmitModifiers(modStr) : ""; string keyword = settings.EmitKeyword(GetString(type.ClassType)); string name = null; if (instantiatedType == null && type.Name.EndsWith("[]")) { List <IMember> member = type.SearchMember("Item", true); if (member != null && member.Count > 0) { name = Visit(member[0].ReturnType, settings); } if (settings.IncludeGenerics) { name += "[]"; } } if (name == null) { if (settings.UseFullName && type.DeclaringType == null) { name = Format(instantiatedType == null ? type.FullName : instantiatedType.UninstantiatedType.FullName); } else { IType realType = instantiatedType == null ? type : instantiatedType.UninstantiatedType; name = Format(NormalizeTypeName((settings.UseFullInnerTypeName && realType.DeclaringType != null) ? GetString(realType.DeclaringType, OutputFlags.UseFullInnerTypeName) + "." + realType.Name : realType.Name)); } } int parameterCount = type.TypeParameters.Count; if (instantiatedType != null) { parameterCount = instantiatedType.UninstantiatedType.TypeParameters.Count; } result.Append(modifiers); result.Append(keyword); if (result.Length > 0 && !result.ToString().EndsWith(" ")) { result.Append(settings.Markup(" ")); } if (type.ClassType == ClassType.Delegate && settings.ReformatDelegates && settings.IncludeReturnType) { IMethod invoke = type.SearchMember("Invoke", true).FirstOrDefault() as IMethod; if (invoke != null) { result.Append(this.GetString(invoke.ReturnType, settings)); result.Append(settings.Markup(" ")); } } if (settings.UseFullName && type.DeclaringType != null) { bool includeGenerics = settings.IncludeGenerics; settings.OutputFlags |= OutputFlags.IncludeGenerics; string typeString = GetString(type.DeclaringType, settings); if (!includeGenerics) { settings.OutputFlags &= ~OutputFlags.IncludeGenerics; } result.Append(typeString); result.Append(settings.Markup(".")); } result.Append(settings.EmitName(type, name)); if (settings.IncludeGenerics && parameterCount > 0) { result.Append(settings.Markup("<")); for (int i = 0; i < parameterCount; i++) { if (i > 0) { result.Append(settings.Markup(settings.HideGenericParameterNames ? "," : ", ")); } if (!settings.HideGenericParameterNames) { if (instantiatedType != null) { if (i < instantiatedType.GenericParameters.Count) { result.Append(this.GetString(instantiatedType.GenericParameters[i], settings)); } else { result.Append(instantiatedType.UninstantiatedType.TypeParameters[i].Name); } } else { result.Append(NetToCSharpTypeName(type.TypeParameters[i].Name)); } } } result.Append(settings.Markup(">")); } if (type.ClassType == ClassType.Delegate && settings.ReformatDelegates) { CSharpFormattingPolicy policy = GetPolicy(settings); if (policy.BeforeMethodCallParentheses) { result.Append(settings.Markup(" ")); } result.Append(settings.Markup("(")); IMethod invoke = type.SearchMember("Invoke", true).FirstOrDefault() as IMethod; if (invoke != null) { AppendParameterList(result, settings, invoke.Parameters); } result.Append(settings.Markup(")")); return(result.ToString()); } if (settings.IncludeBaseTypes && type.BaseTypes.Any()) { bool first = true; foreach (IReturnType baseType in type.BaseTypes) { if (baseType.FullName == "System.Object" || baseType.FullName == "System.Enum") { continue; } result.Append(settings.Markup(first ? " : " : ", ")); first = false; result.Append(this.GetString(baseType, settings)); } } OutputConstraints(result, settings, type.TypeParameters); return(result.ToString()); }
private void TestIndeterminatedNestedStructFieldPerContext(TypeSystemContext context, ModuleDesc testModule, out InstantiatedType genOfIntNestedInt, out InstantiatedType genOfLongNestedInt) { // Given a struct with all field universal, what is the layout? MetadataType tGen = testModule.GetType("GenericTypes", "GenStruct`3"); InstantiatedType genOfUUU = tGen.MakeInstantiatedType(context.UniversalCanonType, context.UniversalCanonType, context.UniversalCanonType); genOfIntNestedInt = tGen.MakeInstantiatedType(context.GetWellKnownType(WellKnownType.Int32), genOfUUU, context.GetWellKnownType(WellKnownType.Int32)); genOfLongNestedInt = tGen.MakeInstantiatedType(context.GetWellKnownType(WellKnownType.Int64), genOfUUU, context.GetWellKnownType(WellKnownType.Int32)); Assert.Equal(LayoutInt.Indeterminate, genOfIntNestedInt.InstanceFieldAlignment); Assert.Equal(LayoutInt.Indeterminate, genOfIntNestedInt.InstanceFieldSize); Assert.Equal(LayoutInt.Indeterminate, genOfIntNestedInt.InstanceByteCount); Assert.Equal(LayoutInt.Indeterminate, genOfIntNestedInt.InstanceByteCountUnaligned); Assert.Equal(0, genOfIntNestedInt.GetFields().First().Offset.AsInt); Assert.Equal(LayoutInt.Indeterminate, genOfIntNestedInt.GetFields().ElementAt(1).Offset); Assert.Equal(LayoutInt.Indeterminate, genOfIntNestedInt.GetFields().ElementAt(2).Offset); Assert.Equal(LayoutInt.Indeterminate, genOfLongNestedInt.InstanceFieldAlignment); Assert.Equal(LayoutInt.Indeterminate, genOfLongNestedInt.InstanceFieldSize); Assert.Equal(LayoutInt.Indeterminate, genOfLongNestedInt.InstanceByteCount); Assert.Equal(LayoutInt.Indeterminate, genOfLongNestedInt.InstanceByteCountUnaligned); Assert.Equal(0, genOfLongNestedInt.GetFields().First().Offset.AsInt); if (context.Target.MaximumAlignment <= 8) { Assert.Equal(8, genOfLongNestedInt.GetFields().ElementAt(1).Offset.AsInt); } else { Assert.Equal(LayoutInt.Indeterminate, genOfLongNestedInt.GetFields().ElementAt(1).Offset); } Assert.Equal(LayoutInt.Indeterminate, genOfLongNestedInt.GetFields().ElementAt(2).Offset); }
public void TestConstructedMethodAdjustment() { TypeDesc intType = _context.GetWellKnownType(WellKnownType.Int32); TypeDesc stringType = _context.GetWellKnownType(WellKnownType.String); TypeDesc charType = _context.GetWellKnownType(WellKnownType.Char); TypeDesc objectType = _context.GetWellKnownType(WellKnownType.Object); MetadataType genericOpenType = _testModule.GetType("GenericTypes", "TwoParamGenericClass`2"); MetadataType nonGenericType = _testModule.GetType("GenericTypes", "NonGenericClass"); MethodDesc nonGenericOnGeneric = genericOpenType.GetMethod("NonGenericFunction", null); MethodDesc genericOnGeneric = genericOpenType.GetMethod("GenericFunction", null); MethodDesc genericOnNonGeneric = nonGenericType.GetMethod("GenericFunction", null); InstantiatedType genericIntString = genericOpenType.MakeInstantiatedType(intType, stringType); InstantiatedType genericCharString = genericOpenType.MakeInstantiatedType(charType, stringType); InstantiatedType genericCharObject = genericOpenType.MakeInstantiatedType(charType, objectType); MethodDesc nonGenericOnGenericIntString = genericIntString.GetMethod("NonGenericFunction", null); MethodDesc nonGenericOnGenericCharString = genericCharString.GetMethod("NonGenericFunction", null); MethodDesc nonGenericOnGenericCharObject = genericCharObject.GetMethod("NonGenericFunction", null); MethodDesc genericIntStringOnGenericIntString = genericIntString.GetMethod("GenericFunction", null).MakeInstantiatedMethod(intType, stringType); MethodDesc genericCharStringOnGenericCharString = genericCharString.GetMethod("GenericFunction", null).MakeInstantiatedMethod(charType, stringType); MethodDesc genericCharObjectOnGenericCharObject = genericCharObject.GetMethod("GenericFunction", null).MakeInstantiatedMethod(charType, objectType); MethodDesc genericIntStringOnNonGeneric = genericOnNonGeneric.MakeInstantiatedMethod(intType, stringType); MethodDesc genericCharStringOnNonGeneric = genericOnNonGeneric.MakeInstantiatedMethod(charType, stringType); MethodDesc genericCharObjectOnNonGeneric = genericOnNonGeneric.MakeInstantiatedMethod(charType, objectType); // Test complete replacement MethodDesc testDirectReplacementNonGenericOnGeneric = nonGenericOnGenericIntString.ReplaceTypesInConstructionOfMethod(new TypeDesc[] { intType, stringType }, new TypeDesc[] { charType, objectType }); Assert.Equal(nonGenericOnGenericCharObject, testDirectReplacementNonGenericOnGeneric); MethodDesc testDirectReplacementGenericOnGeneric = genericIntStringOnGenericIntString.ReplaceTypesInConstructionOfMethod(new TypeDesc[] { intType, stringType }, new TypeDesc[] { charType, objectType }); Assert.Equal(genericCharObjectOnGenericCharObject, testDirectReplacementGenericOnGeneric); MethodDesc testDirectReplacementGenericOnNonGeneric = genericIntStringOnNonGeneric.ReplaceTypesInConstructionOfMethod(new TypeDesc[] { intType, stringType }, new TypeDesc[] { charType, objectType }); Assert.Equal(genericCharObjectOnNonGeneric, testDirectReplacementGenericOnNonGeneric); // Test replace first type in instantiation MethodDesc testPartialReplacementNonGenericOnGeneric = nonGenericOnGenericIntString.ReplaceTypesInConstructionOfMethod(new TypeDesc[] { intType }, new TypeDesc[] { charType }); Assert.Equal(nonGenericOnGenericCharString, testPartialReplacementNonGenericOnGeneric); MethodDesc testPartialReplacementGenericOnGeneric = genericIntStringOnGenericIntString.ReplaceTypesInConstructionOfMethod(new TypeDesc[] { intType }, new TypeDesc[] { charType }); Assert.Equal(genericCharStringOnGenericCharString, testPartialReplacementGenericOnGeneric); MethodDesc testPartialReplacementGenericOnNonGeneric = genericIntStringOnNonGeneric.ReplaceTypesInConstructionOfMethod(new TypeDesc[] { intType }, new TypeDesc[] { charType }); Assert.Equal(genericCharStringOnNonGeneric, testPartialReplacementGenericOnNonGeneric); // Test ArrayMethod case ArrayType mdArrayChar = _context.GetArrayType(charType, 3); ArrayType mdArrayInt = _context.GetArrayType(intType, 3); MethodDesc getMethodOnMDIntArray = mdArrayInt.GetArrayMethod(ArrayMethodKind.Get); MethodDesc getMethodOnMDCharArray = mdArrayChar.GetArrayMethod(ArrayMethodKind.Get); MethodDesc testArrayMethodCase = getMethodOnMDIntArray.ReplaceTypesInConstructionOfMethod(new TypeDesc[] { intType }, new TypeDesc[] { charType }); Assert.Equal(getMethodOnMDCharArray, testArrayMethodCase); }
public void TestConstructedTypeAdjustment() { TypeDesc intType = _context.GetWellKnownType(WellKnownType.Int32); TypeDesc stringType = _context.GetWellKnownType(WellKnownType.String); TypeDesc charType = _context.GetWellKnownType(WellKnownType.Char); TypeDesc objectType = _context.GetWellKnownType(WellKnownType.Object); MetadataType genericOpenType = _testModule.GetType("GenericTypes", "TwoParamGenericClass`2"); InstantiatedType genericOfCharObject = genericOpenType.MakeInstantiatedType(charType, objectType); InstantiatedType genericOfCharString = genericOpenType.MakeInstantiatedType(charType, stringType); InstantiatedType genericOfIntString = genericOpenType.MakeInstantiatedType(intType, stringType); InstantiatedType genericOfIntObject = genericOpenType.MakeInstantiatedType(intType, objectType); Assert.Equal(true, genericOfCharObject.IsConstructedOverType(new TypeDesc[] { charType })); Assert.Equal(true, genericOfCharObject.IsConstructedOverType(new TypeDesc[] { objectType })); Assert.Equal(false, genericOfCharObject.IsConstructedOverType(new TypeDesc[] { intType })); Assert.Equal(false, genericOfCharObject.IsConstructedOverType(new TypeDesc[] { stringType })); Assert.Equal(false, genericOfCharObject.IsConstructedOverType(new TypeDesc[] { genericOpenType })); Assert.Equal(true, genericOfCharString.IsConstructedOverType(new TypeDesc[] { charType })); Assert.Equal(false, genericOfCharString.IsConstructedOverType(new TypeDesc[] { objectType })); Assert.Equal(false, genericOfCharString.IsConstructedOverType(new TypeDesc[] { intType })); Assert.Equal(true, genericOfCharString.IsConstructedOverType(new TypeDesc[] { stringType })); // Test direct replacement TypeDesc testDirectReplaceAllTypes = genericOfCharObject.ReplaceTypesInConstructionOfType(new TypeDesc[] { charType, objectType }, new TypeDesc[] { intType, stringType }); Assert.Equal(genericOfIntString, testDirectReplaceAllTypes); // Test direct replacement where not all types are replaced TypeDesc testDirectReplaceFirstType = genericOfCharObject.ReplaceTypesInConstructionOfType(new TypeDesc[] { charType }, new TypeDesc[] { intType }); Assert.Equal(genericOfIntObject, testDirectReplaceFirstType); TypeDesc testDirectReplaceSecondType = genericOfCharObject.ReplaceTypesInConstructionOfType(new TypeDesc[] { objectType }, new TypeDesc[] { stringType }); Assert.Equal(genericOfCharString, testDirectReplaceSecondType); // Test Arrays TypeDesc arrayChar = _context.GetArrayType(charType); Assert.False(arrayChar.IsMdArray); Assert.True(arrayChar.IsSzArray); Assert.True(arrayChar.IsArray); TypeDesc arrayInt = _context.GetArrayType(intType); Assert.False(arrayInt.IsMdArray); Assert.True(arrayInt.IsSzArray); Assert.True(arrayInt.IsArray); InstantiatedType genericOfCharArrayObject = genericOpenType.MakeInstantiatedType(arrayChar, objectType); InstantiatedType genericOfIntArrayObject = genericOpenType.MakeInstantiatedType(arrayInt, objectType); TypeDesc testReplaceTypeInArrayInGeneric = genericOfCharArrayObject.ReplaceTypesInConstructionOfType(new TypeDesc[] { charType }, new TypeDesc[] { intType }); Assert.Equal(genericOfIntArrayObject, testReplaceTypeInArrayInGeneric); // Test multidimensional arrays TypeDesc mdArrayChar = _context.GetArrayType(charType, 3); Assert.True(mdArrayChar.IsMdArray); Assert.False(mdArrayChar.IsSzArray); Assert.True(mdArrayChar.IsArray); TypeDesc mdArrayInt = _context.GetArrayType(intType, 3); Assert.True(mdArrayInt.IsMdArray); Assert.False(mdArrayInt.IsSzArray); Assert.True(mdArrayInt.IsArray); InstantiatedType genericOfCharMdArrayObject = genericOpenType.MakeInstantiatedType(mdArrayChar, objectType); InstantiatedType genericOfIntMdArrayObject = genericOpenType.MakeInstantiatedType(mdArrayInt, objectType); TypeDesc testReplaceTypeInMdArrayInGeneric = genericOfCharMdArrayObject.ReplaceTypesInConstructionOfType(new TypeDesc[] { charType }, new TypeDesc[] { intType }); Assert.Equal(genericOfIntMdArrayObject, testReplaceTypeInMdArrayInGeneric); // Test pointers TypeDesc charPointer = _context.GetPointerType(charType); TypeDesc intPointer = _context.GetPointerType(intType); TypeDesc testReplaceTypeInPointer = charPointer.ReplaceTypesInConstructionOfType(new TypeDesc[] { charType }, new TypeDesc[] { intType }); Assert.Equal(intPointer, testReplaceTypeInPointer); Assert.Equal(true, charPointer.IsConstructedOverType(new TypeDesc[] { charType })); Assert.Equal(false, charPointer.IsConstructedOverType(new TypeDesc[] { intType })); // Test byref TypeDesc charByRef = _context.GetByRefType(charType); TypeDesc intByRef = _context.GetByRefType(intType); TypeDesc testReplaceTypeInByRef = charByRef.ReplaceTypesInConstructionOfType(new TypeDesc[] { charType }, new TypeDesc[] { intType }); Assert.Equal(intByRef, testReplaceTypeInByRef); Assert.Equal(true, charByRef.IsConstructedOverType(new TypeDesc[] { charType })); Assert.Equal(false, charByRef.IsConstructedOverType(new TypeDesc[] { intType })); // Test replace type entirely TypeDesc testReplaceTypeEntirely = charByRef.ReplaceTypesInConstructionOfType(new TypeDesc[] { charByRef }, new TypeDesc[] { intByRef }); Assert.Equal(intByRef, testReplaceTypeEntirely); Assert.Equal(true, charByRef.IsConstructedOverType(new TypeDesc[] { charByRef })); }
public override Type AsType() { if (_type == null) _type = new InstantiatedType(this); return _type; }
/// <summary> /// Gets a value indicating whether '<paramref name="type"/>' might have a non-empty dispatch map. /// Note that this is only an approximation because we might not be able to take into account /// whether the interface methods are actually used. /// </summary> public static bool MightHaveInterfaceDispatchMap(TypeDesc type, NodeFactory factory) { if (type.IsArrayTypeWithoutGenericInterfaces()) { return(false); } if (!type.IsArray && !type.IsDefType) { return(false); } // Interfaces don't have a dispatch map because we dispatch them based on the // dispatch map of the implementing class. // The only exception are IDynamicInterfaceCastable scenarios that dispatch // using the interface dispatch map. // We generate the dispatch map irrespective of whether the interface actually // implements any methods (we don't run the for loop below) so that at runtime // we can distinguish between "the interface returned by IDynamicInterfaceCastable // wasn't marked as [DynamicInterfaceCastableImplementation]" and "we couldn't find an // implementation". We don't want to use the custom attribute for that at runtime because // that's reflection and this should work without reflection. if (type.IsInterface) { return(((MetadataType)type).IsDynamicInterfaceCastableImplementation()); } TypeDesc declType = type.GetClosestDefType(); for (int interfaceIndex = 0; interfaceIndex < declType.RuntimeInterfaces.Length; interfaceIndex++) { DefType interfaceType = declType.RuntimeInterfaces[interfaceIndex]; InstantiatedType interfaceOnDefinitionType = interfaceType.IsTypeDefinition ? null : (InstantiatedType)declType.GetTypeDefinition().RuntimeInterfaces[interfaceIndex]; IEnumerable <MethodDesc> slots; // If the vtable has fixed slots, we can query it directly. // If it's a lazily built vtable, we might not be able to query slots // just yet, so approximate by looking at all methods. VTableSliceNode vtableSlice = factory.VTable(interfaceType); if (vtableSlice.HasFixedSlots) { slots = vtableSlice.Slots; } else { slots = interfaceType.GetAllVirtualMethods(); } foreach (MethodDesc slotMethod in slots) { MethodDesc declMethod = slotMethod; Debug.Assert(!declMethod.Signature.IsStatic && declMethod.IsVirtual); if (interfaceOnDefinitionType != null) { declMethod = factory.TypeSystemContext.GetMethodForInstantiatedType(declMethod.GetTypicalMethodDefinition(), interfaceOnDefinitionType); } var implMethod = declType.GetTypeDefinition().ResolveInterfaceMethodToVirtualMethodOnType(declMethod); if (implMethod != null) { return(true); } else { DefaultInterfaceMethodResolution result = declType.ResolveInterfaceMethodToDefaultImplementationOnType(slotMethod, out _); if (result != DefaultInterfaceMethodResolution.None) { return(true); } } } } return(false); }
/// <summary> /// Returns 'true' if the struct is passed in registers, 'false' otherwise. /// </summary> private static bool ClassifyEightBytes(TypeDesc typeDesc, ref SystemVStructRegisterPassingHelper helper, int startOffsetOfStruct) { FieldDesc firstField = null; int numIntroducedFields = 0; foreach (FieldDesc field in typeDesc.GetFields()) { if (!field.IsStatic) { if (firstField == null) { firstField = field; } numIntroducedFields++; } } if (numIntroducedFields == 0) { return(false); } // The SIMD Intrinsic types are meant to be handled specially and should not be passed as struct registers if (typeDesc.IsIntrinsic) { InstantiatedType instantiatedType = typeDesc as InstantiatedType; if (instantiatedType != null) { if (VectorFieldLayoutAlgorithm.IsVectorType(instantiatedType) || VectorOfTFieldLayoutAlgorithm.IsVectorOfTType(instantiatedType)) { return(false); } } } MetadataType mdType = typeDesc as MetadataType; Debug.Assert(mdType != null); TypeDesc firstFieldElementType = firstField.FieldType; int firstFieldSize = firstFieldElementType.GetElementSize().AsInt; // A fixed buffer type is always a value type that has exactly one value type field at offset 0 // and who's size is an exact multiple of the size of the field. // It is possible that we catch a false positive with this check, but that chance is extremely slim // and the user can always change their structure to something more descriptive of what they want // instead of adding additional padding at the end of a one-field structure. // We do this check here to save looking up the FixedBufferAttribute when loading the field // from metadata. bool isFixedBuffer = numIntroducedFields == 1 && firstFieldElementType.IsValueType && firstField.Offset.AsInt == 0 && mdType.HasLayout() && ((typeDesc.GetElementSize().AsInt % firstFieldSize) == 0); if (isFixedBuffer) { numIntroducedFields = typeDesc.GetElementSize().AsInt / firstFieldSize; } int fieldIndex = 0; foreach (FieldDesc field in FieldEnumerator.GetInstanceFields(typeDesc, isFixedBuffer, numIntroducedFields)) { Debug.Assert(fieldIndex < numIntroducedFields); int fieldOffset = isFixedBuffer ? fieldIndex * firstFieldSize : field.Offset.AsInt; int normalizedFieldOffset = fieldOffset + startOffsetOfStruct; int fieldSize = field.FieldType.GetElementSize().AsInt; // The field can't span past the end of the struct. if ((normalizedFieldOffset + fieldSize) > helper.StructSize) { Debug.Assert(false, "Invalid struct size. The size of fields and overall size don't agree"); return(false); } SystemVClassificationType fieldClassificationType; if (typeDesc.IsByReferenceOfT) { // ByReference<T> is a special type whose single IntPtr field holds a by-ref potentially interior pointer to GC // memory, so classify its field as such Debug.Assert(numIntroducedFields == 1); Debug.Assert(field.FieldType.IsWellKnownType(WellKnownType.IntPtr)); fieldClassificationType = SystemVClassificationTypeIntegerByRef; } else { fieldClassificationType = TypeDef2SystemVClassification(field.FieldType); } if (fieldClassificationType == SystemVClassificationTypeStruct) { bool inEmbeddedStructPrev = helper.InEmbeddedStruct; helper.InEmbeddedStruct = true; bool structRet = false; structRet = ClassifyEightBytes(field.FieldType, ref helper, normalizedFieldOffset); helper.InEmbeddedStruct = inEmbeddedStructPrev; if (!structRet) { // If the nested struct says not to enregister, there's no need to continue analyzing at this level. Just return do not enregister. return(false); } continue; } if (fieldClassificationType == SystemVClassificationTypeTypedReference || TypeDef2SystemVClassification(typeDesc) == SystemVClassificationTypeTypedReference) { // The TypedReference is a very special type. // In source/metadata it has two fields - Type and Value and both are defined of type IntPtr. // When the VM creates a layout of the type it changes the type of the Value to ByRef type and the // type of the Type field is left to IntPtr (TYPE_I internally - native int type.) // This requires a special treatment of this type. The code below handles the both fields (and this entire type). for (int i = 0; i < 2; i++) { fieldSize = 8; fieldOffset = (i == 0 ? 0 : 8); normalizedFieldOffset = fieldOffset + startOffsetOfStruct; fieldClassificationType = (i == 0 ? SystemVClassificationTypeIntegerByRef : SystemVClassificationTypeInteger); if ((normalizedFieldOffset % fieldSize) != 0) { // The spec requires that struct values on the stack from register passed fields expects // those fields to be at their natural alignment. return(false); } helper.LargestFieldOffset = (int)normalizedFieldOffset; // Set the data for a new field. // The new field classification must not have been initialized yet. Debug.Assert(helper.FieldClassifications[helper.CurrentUniqueOffsetField] == SystemVClassificationTypeNoClass); helper.FieldClassifications[helper.CurrentUniqueOffsetField] = fieldClassificationType; helper.FieldSizes[helper.CurrentUniqueOffsetField] = fieldSize; helper.FieldOffsets[helper.CurrentUniqueOffsetField] = normalizedFieldOffset; helper.CurrentUniqueOffsetField++; } // Both fields of the special TypedReference struct are handled. // Done classifying the System.TypedReference struct fields. break; } if ((normalizedFieldOffset % fieldSize) != 0) { // The spec requires that struct values on the stack from register passed fields expects // those fields to be at their natural alignment. return(false); } if (normalizedFieldOffset <= helper.LargestFieldOffset) { // Find the field corresponding to this offset and update the size if needed. // If the offset matches a previously encountered offset, update the classification and field size. int i; for (i = helper.CurrentUniqueOffsetField - 1; i >= 0; i--) { if (helper.FieldOffsets[i] == normalizedFieldOffset) { if (fieldSize > helper.FieldSizes[i]) { helper.FieldSizes[i] = fieldSize; } helper.FieldClassifications[i] = ReClassifyField(helper.FieldClassifications[i], fieldClassificationType); break; } } if (i >= 0) { // The proper size of the union set of fields has been set above; continue to the next field. continue; } } else { helper.LargestFieldOffset = (int)normalizedFieldOffset; } // Set the data for a new field. // The new field classification must not have been initialized yet. Debug.Assert(helper.FieldClassifications[helper.CurrentUniqueOffsetField] == SystemVClassificationTypeNoClass); // There are only a few field classifications that are allowed. Debug.Assert((fieldClassificationType == SystemVClassificationTypeInteger) || (fieldClassificationType == SystemVClassificationTypeIntegerReference) || (fieldClassificationType == SystemVClassificationTypeIntegerByRef) || (fieldClassificationType == SystemVClassificationTypeSSE)); helper.FieldClassifications[helper.CurrentUniqueOffsetField] = fieldClassificationType; helper.FieldSizes[helper.CurrentUniqueOffsetField] = fieldSize; helper.FieldOffsets[helper.CurrentUniqueOffsetField] = normalizedFieldOffset; Debug.Assert(helper.CurrentUniqueOffsetField < SYSTEMV_MAX_NUM_FIELDS_IN_REGISTER_PASSED_STRUCT); helper.CurrentUniqueOffsetField++; fieldIndex++; } AssignClassifiedEightByteTypes(ref helper); return(true); }
public static void RootType(IRootingServiceProvider rootProvider, TypeDesc type, string reason) { rootProvider.AddCompilationRoot(type, reason); InstantiatedType fallbackNonCanonicalOwningType = null; // Instantiate generic types over something that will be useful at runtime if (type.IsGenericDefinition) { Instantiation canonInst = TypeExtensions.GetInstantiationThatMeetsConstraints(type.Instantiation, allowCanon: true); if (canonInst.IsNull) { return; } Instantiation concreteInst = TypeExtensions.GetInstantiationThatMeetsConstraints(type.Instantiation, allowCanon: false); if (!concreteInst.IsNull) { fallbackNonCanonicalOwningType = ((MetadataType)type).MakeInstantiatedType(concreteInst); } type = ((MetadataType)type).MakeInstantiatedType(canonInst); rootProvider.AddCompilationRoot(type, reason); } // Also root base types. This is so that we make methods on the base types callable. // This helps in cases like "class Foo : Bar<int> { }" where we discover new // generic instantiations. TypeDesc baseType = type.BaseType; if (baseType != null) { RootType(rootProvider, baseType.NormalizeInstantiation(), reason); } if (type.IsDefType) { foreach (var method in type.GetMethods()) { if (method.HasInstantiation) { // Make a non-canonical instantiation. // We currently have a file format limitation that requires generic methods to be concrete. // A rooted canonical method body is not visible to the reflection mapping tables. Instantiation inst = TypeExtensions.GetInstantiationThatMeetsConstraints(method.Instantiation, allowCanon: false); if (inst.IsNull) { // Can't root anything useful } else if (!method.OwningType.IsCanonicalSubtype(CanonicalFormKind.Any)) { // Owning type is not canonical, can use the instantiation directly. TryRootMethod(rootProvider, method.MakeInstantiatedMethod(inst), reason); } else if (fallbackNonCanonicalOwningType != null) { // We have a fallback non-canonical type we can root a body on MethodDesc alternateMethod = method.Context.GetMethodForInstantiatedType(method.GetTypicalMethodDefinition(), fallbackNonCanonicalOwningType); TryRootMethod(rootProvider, alternateMethod.MakeInstantiatedMethod(inst), reason); } } else { TryRootMethod(rootProvider, method, reason); } } } }