Beispiel #1
0
        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);
            }
        }
Beispiel #2
0
        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);
        }
Beispiel #4
0
        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);
            }
        }
Beispiel #6
0
        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;
        }
Beispiel #7
0
        /// <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);
        }
Beispiel #8
0
        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);
            }
        }
Beispiel #9
0
        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);
        }
Beispiel #10
0
        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);
            }
        }
Beispiel #11
0
        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;
 }
Beispiel #16
0
        /// <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);
        }
Beispiel #18
0
        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);
                    }
                }
            }
        }