public override IEnumerable <CombinedDependencyListEntry> GetConditionalStaticDependencies(NodeFactory factory)
        {
            Debug.Assert(_decl.OwningType.HasInstantiation);
            Debug.Assert(!_decl.OwningType.IsInterface);
            Debug.Assert(factory.TypeSystemContext.SupportsUniversalCanon);

            DefType universalCanonicalOwningType = (DefType)_decl.OwningType.ConvertToCanonForm(CanonicalFormKind.Universal);

            Debug.Assert(universalCanonicalOwningType.IsCanonicalSubtype(CanonicalFormKind.Universal));

            if (!factory.VTable(universalCanonicalOwningType).HasFixedSlots)
            {
                // This code ensures that in cases where we don't structurally force all universal canonical instantiations
                // to have full vtables, that we ensure that all vtables are equivalently shaped between universal and non-universal types
                return(new CombinedDependencyListEntry[] {
                    new CombinedDependencyListEntry(
                        factory.VirtualMethodUse(_decl.GetCanonMethodTarget(CanonicalFormKind.Universal)),
                        factory.NativeLayout.TemplateTypeLayout(universalCanonicalOwningType),
                        "If universal canon instantiation of method exists, ensure that the universal canonical type has the right set of dependencies")
                });
            }
            else
            {
                return(Array.Empty <CombinedDependencyListEntry>());
            }
        }
Beispiel #2
0
        private bool getReadyToRunHelper(ref CORINFO_RESOLVED_TOKEN pResolvedToken, ref CORINFO_LOOKUP_KIND pGenericLookupKind, CorInfoHelpFunc id, ref CORINFO_CONST_LOOKUP pLookup)
        {
            switch (id)
            {
            case CorInfoHelpFunc.CORINFO_HELP_READYTORUN_NEW:
            case CorInfoHelpFunc.CORINFO_HELP_READYTORUN_NEWARR_1:
            case CorInfoHelpFunc.CORINFO_HELP_READYTORUN_ISINSTANCEOF:
            case CorInfoHelpFunc.CORINFO_HELP_READYTORUN_CHKCAST:
                return(false);

            case CorInfoHelpFunc.CORINFO_HELP_READYTORUN_STATIC_BASE:
            {
                var type = HandleToObject(pResolvedToken.hClass);
                if (type.IsCanonicalSubtype(CanonicalFormKind.Any))
                {
                    return(false);
                }

                pLookup = CreateConstLookupToSymbol(_compilation.NodeFactory.ReadyToRunHelper(ReadyToRunHelperId.GetNonGCStaticBase, type));
            }
            break;

            case CorInfoHelpFunc.CORINFO_HELP_READYTORUN_GENERIC_STATIC_BASE:
            {
                // Token == 0 means "initialize this class". We only expect RyuJIT to call it for this case.
                Debug.Assert(pResolvedToken.token == 0 && pResolvedToken.tokenScope == null);
                Debug.Assert(pGenericLookupKind.needsRuntimeLookup);

                DefType typeToInitialize = (DefType)MethodBeingCompiled.OwningType;
                Debug.Assert(typeToInitialize.IsCanonicalSubtype(CanonicalFormKind.Any));

                DefType     helperArg = typeToInitialize.ConvertToSharedRuntimeDeterminedForm();
                ISymbolNode helper    = GetGenericLookupHelper(pGenericLookupKind.runtimeLookupKind, ReadyToRunHelperId.GetNonGCStaticBase, helperArg);
                pLookup = CreateConstLookupToSymbol(helper);
            }
            break;

            case CorInfoHelpFunc.CORINFO_HELP_READYTORUN_GENERIC_HANDLE:
            {
                Debug.Assert(pGenericLookupKind.needsRuntimeLookup);

                ReadyToRunHelperId helperId  = (ReadyToRunHelperId)pGenericLookupKind.runtimeLookupFlags;
                object             helperArg = HandleToObject((IntPtr)pGenericLookupKind.runtimeLookupArgs);
                ISymbolNode        helper    = GetGenericLookupHelper(pGenericLookupKind.runtimeLookupKind, helperId, helperArg);
                pLookup = CreateConstLookupToSymbol(helper);
            }
            break;

            default:
                throw new NotImplementedException("ReadyToRun: " + id.ToString());
            }
            return(true);
        }
Beispiel #3
0
        /// <summary>
        /// Gets a fully canonicalized base type if base type is canonical, or unmodified base type otherwise.
        /// </summary>
        public static DefType NormalizedBaseType(this TypeDesc type)
        {
            // Base type for Foo<__Canon> where Foo is defined as
            // class Foo<T> : Bar<T, string> { }
            // is Bar<__Canon, string>. This method normalizes it to Bar<__Canon, __Canon>.
            DefType baseType = type.BaseType;

            if (baseType != null && baseType.IsCanonicalSubtype(CanonicalFormKind.Any))
            {
                baseType = (DefType)baseType.ConvertToCanonForm(CanonicalFormKind.Specific);
            }
            return(baseType);
        }
Beispiel #4
0
        protected virtual MethodDesc ResolveVirtualMethod(MethodDesc declMethod, DefType implType, out CORINFO_DEVIRTUALIZATION_DETAIL devirtualizationDetail)
        {
            devirtualizationDetail = CORINFO_DEVIRTUALIZATION_DETAIL.CORINFO_DEVIRTUALIZATION_UNKNOWN;

            MethodDesc impl;

            if (declMethod.OwningType.IsInterface)
            {
                if (declMethod.OwningType.IsCanonicalSubtype(CanonicalFormKind.Any) || implType.IsCanonicalSubtype(CanonicalFormKind.Any))
                {
                    DefType[] implTypeRuntimeInterfaces          = implType.RuntimeInterfaces;
                    int       canonicallyMatchingInterfacesFound = 0;
                    DefType   canonicalInterfaceType             = (DefType)declMethod.OwningType.ConvertToCanonForm(CanonicalFormKind.Specific);
                    for (int i = 0; i < implTypeRuntimeInterfaces.Length; i++)
                    {
                        DefType runtimeInterface = implTypeRuntimeInterfaces[i];
                        if (canonicalInterfaceType.HasSameTypeDefinition(runtimeInterface) &&
                            runtimeInterface.ConvertToCanonForm(CanonicalFormKind.Specific) == canonicalInterfaceType)
                        {
                            canonicallyMatchingInterfacesFound++;
                            if (canonicallyMatchingInterfacesFound > 1)
                            {
                                // We cannot resolve the interface as we don't know with exact enough detail which interface
                                // of multiple possible interfaces is being called.
                                devirtualizationDetail = CORINFO_DEVIRTUALIZATION_DETAIL.CORINFO_DEVIRTUALIZATION_MULTIPLE_IMPL;
                                return(null);
                            }
                        }
                    }
                }

                if (!implType.CanCastTo(declMethod.OwningType))
                {
                    devirtualizationDetail = CORINFO_DEVIRTUALIZATION_DETAIL.CORINFO_DEVIRTUALIZATION_FAILED_CAST;
                    return(null);
                }

                impl = implType.ResolveInterfaceMethodTargetWithVariance(declMethod);
                if (impl != null)
                {
                    impl = implType.FindVirtualFunctionTargetMethodOnObjectType(impl);
                }
                else
                {
                    MethodDesc dimMethod = null;
                    // This isn't the correct lookup algorithm for variant default interface methods
                    // but as we will drop any results we find in any case, it doesn't matter much.
                    // Non-variant dispatch can simply use ResolveInterfaceMethodToDefaultImplementationOnType
                    // but that implementation currently cannot handle variance.

                    MethodDesc defaultInterfaceDispatchDeclMethod = null;
                    foreach (TypeDesc iface in implType.RuntimeInterfaces)
                    {
                        if (iface == declMethod.OwningType)
                        {
                            defaultInterfaceDispatchDeclMethod = declMethod;
                            break;
                        }
                        if (iface.HasSameTypeDefinition(declMethod.OwningType) && iface.CanCastTo(declMethod.OwningType))
                        {
                            defaultInterfaceDispatchDeclMethod = iface.FindMethodOnTypeWithMatchingTypicalMethod(declMethod);
                            // Prefer to find the exact match, so don't break immediately
                        }
                    }

                    if (defaultInterfaceDispatchDeclMethod != null)
                    {
                        switch (implType.ResolveInterfaceMethodToDefaultImplementationOnType(defaultInterfaceDispatchDeclMethod, out dimMethod))
                        {
                        case DefaultInterfaceMethodResolution.Diamond:
                        case DefaultInterfaceMethodResolution.Reabstraction:
                            devirtualizationDetail = CORINFO_DEVIRTUALIZATION_DETAIL.CORINFO_DEVIRTUALIZATION_FAILED_DIM;
                            return(null);

                        case DefaultInterfaceMethodResolution.DefaultImplementation:
                            if (dimMethod.OwningType.HasInstantiation || (declMethod != defaultInterfaceDispatchDeclMethod))
                            {
                                // If we devirtualized into a default interface method on a generic type, we should actually return an
                                // instantiating stub but this is not happening.
                                // Making this work is tracked by https://github.com/dotnet/runtime/issues/9588

                                // In addition, we fail here for variant default interface dispatch
                                devirtualizationDetail = CORINFO_DEVIRTUALIZATION_DETAIL.CORINFO_DEVIRTUALIZATION_FAILED_DIM;
                                return(null);
                            }
                            else
                            {
                                impl = dimMethod;
                            }
                            break;
                        }
                    }
                }
            }
            else
            {
                // The derived class should be a subclass of the base class.
                // this check is perfomed via typedef checking instead of casting, as we accept canon methods calling exact types
                TypeDesc checkType;
                for (checkType = implType; checkType != null && !checkType.HasSameTypeDefinition(declMethod.OwningType); checkType = checkType.BaseType)
                {
                }

                if ((checkType == null) || (checkType.ConvertToCanonForm(CanonicalFormKind.Specific) != declMethod.OwningType.ConvertToCanonForm(CanonicalFormKind.Specific)))
                {
                    // The derived class should be a subclass of the base class.
                    devirtualizationDetail = CORINFO_DEVIRTUALIZATION_DETAIL.CORINFO_DEVIRTUALIZATION_FAILED_SUBCLASS;
                    return(null);
                }
                else
                {
                    // At this point, the decl method may be only canonically compatible, but not an exact match to a method in the type hierarchy
                    // Convert it to an exact match. (Or if it is an exact match, the FindMethodOnTypeWithMatchingTypicalMethod will be a no-op)
                    declMethod = checkType.FindMethodOnTypeWithMatchingTypicalMethod(declMethod);
                }

                impl = implType.FindVirtualFunctionTargetMethodOnObjectType(declMethod);
                if (impl != null && (impl != declMethod))
                {
                    MethodDesc slotDefiningMethodImpl = MetadataVirtualMethodAlgorithm.FindSlotDefiningMethodForVirtualMethod(impl);
                    MethodDesc slotDefiningMethodDecl = MetadataVirtualMethodAlgorithm.FindSlotDefiningMethodForVirtualMethod(declMethod);

                    if (slotDefiningMethodImpl != slotDefiningMethodDecl)
                    {
                        // If the derived method's slot does not match the vtable slot,
                        // bail on devirtualization, as the method was installed into
                        // the vtable slot via an explicit override and even if the
                        // method is final, the slot may not be.
                        //
                        // Note the jit could still safely devirtualize if it had an exact
                        // class, but such cases are likely rare.
                        devirtualizationDetail = CORINFO_DEVIRTUALIZATION_DETAIL.CORINFO_DEVIRTUALIZATION_FAILED_SLOT;
                        impl = null;
                    }
                }
            }

            return(impl);
        }
Beispiel #5
0
        protected virtual MethodDesc ResolveVirtualMethod(MethodDesc declMethod, DefType implType)
        {
            MethodDesc impl;

            if (declMethod.OwningType.IsInterface)
            {
                if (declMethod.OwningType.IsCanonicalSubtype(CanonicalFormKind.Any) || implType.IsCanonicalSubtype(CanonicalFormKind.Any))
                {
                    DefType[] implTypeRuntimeInterfaces          = implType.RuntimeInterfaces;
                    int       canonicallyMatchingInterfacesFound = 0;
                    DefType   canonicalInterfaceType             = (DefType)declMethod.OwningType.ConvertToCanonForm(CanonicalFormKind.Specific);
                    for (int i = 0; i < implTypeRuntimeInterfaces.Length; i++)
                    {
                        DefType runtimeInterface = implTypeRuntimeInterfaces[i];
                        if (canonicalInterfaceType.HasSameTypeDefinition(runtimeInterface) &&
                            runtimeInterface.ConvertToCanonForm(CanonicalFormKind.Specific) == canonicalInterfaceType)
                        {
                            canonicallyMatchingInterfacesFound++;
                            if (canonicallyMatchingInterfacesFound > 1)
                            {
                                // We cannot resolve the interface as we don't know with exact enough detail which interface
                                // of multiple possible interfaces is being called.
                                return(null);
                            }
                        }
                    }
                }

                impl = implType.ResolveInterfaceMethodTarget(declMethod);
                if (impl != null)
                {
                    impl = implType.FindVirtualFunctionTargetMethodOnObjectType(impl);
                }
            }
            else
            {
                impl = implType.FindVirtualFunctionTargetMethodOnObjectType(declMethod);
                if (impl != null && (impl != declMethod))
                {
                    MethodDesc slotDefiningMethodImpl = MetadataVirtualMethodAlgorithm.FindSlotDefiningMethodForVirtualMethod(impl);
                    MethodDesc slotDefiningMethodDecl = MetadataVirtualMethodAlgorithm.FindSlotDefiningMethodForVirtualMethod(declMethod);

                    if (slotDefiningMethodImpl != slotDefiningMethodDecl)
                    {
                        // We cannot resolve virtual method in case the impl is a different slot from the declMethod
                        impl = null;
                    }
                }
            }

            return(impl);
        }
Beispiel #6
0
        private bool getReadyToRunHelper(ref CORINFO_RESOLVED_TOKEN pResolvedToken, ref CORINFO_LOOKUP_KIND pGenericLookupKind, CorInfoHelpFunc id, ref CORINFO_CONST_LOOKUP pLookup)
        {
            switch (id)
            {
            case CorInfoHelpFunc.CORINFO_HELP_READYTORUN_NEW:
            {
                var type = HandleToObject(pResolvedToken.hClass);
                Debug.Assert(type.IsDefType);
                if (type.IsCanonicalSubtype(CanonicalFormKind.Any))
                {
                    return(false);
                }

                pLookup = CreateConstLookupToSymbol(_compilation.SymbolNodeFactory.ReadyToRunHelper(ReadyToRunHelperId.NewHelper, type, _signatureContext));
            }
            break;

            case CorInfoHelpFunc.CORINFO_HELP_READYTORUN_NEWARR_1:
            {
                var type = HandleToObject(pResolvedToken.hClass);
                Debug.Assert(type.IsSzArray);
                if (type.IsCanonicalSubtype(CanonicalFormKind.Any))
                {
                    return(false);
                }

                pLookup = CreateConstLookupToSymbol(_compilation.SymbolNodeFactory.ReadyToRunHelper(ReadyToRunHelperId.NewArr1, type, _signatureContext));
            }
            break;

            case CorInfoHelpFunc.CORINFO_HELP_READYTORUN_ISINSTANCEOF:
            {
                var type = HandleToObject(pResolvedToken.hClass);
                if (type.IsCanonicalSubtype(CanonicalFormKind.Any))
                {
                    return(false);
                }

                // ECMA-335 III.4.3:  If typeTok is a nullable type, Nullable<T>, it is interpreted as "boxed" T
                if (type.IsNullable)
                {
                    type = type.Instantiation[0];
                }

                pLookup = CreateConstLookupToSymbol(_compilation.SymbolNodeFactory.ReadyToRunHelper(ReadyToRunHelperId.IsInstanceOf, type, _signatureContext));
            }
            break;

            case CorInfoHelpFunc.CORINFO_HELP_READYTORUN_CHKCAST:
            {
                var type = HandleToObject(pResolvedToken.hClass);
                if (type.IsCanonicalSubtype(CanonicalFormKind.Any))
                {
                    return(false);
                }

                // ECMA-335 III.4.3:  If typeTok is a nullable type, Nullable<T>, it is interpreted as "boxed" T
                if (type.IsNullable)
                {
                    type = type.Instantiation[0];
                }

                pLookup = CreateConstLookupToSymbol(_compilation.SymbolNodeFactory.ReadyToRunHelper(ReadyToRunHelperId.CastClass, type, _signatureContext));
            }
            break;

            case CorInfoHelpFunc.CORINFO_HELP_READYTORUN_STATIC_BASE:
            {
                var type = HandleToObject(pResolvedToken.hClass);
                if (type.IsCanonicalSubtype(CanonicalFormKind.Any))
                {
                    return(false);
                }

                pLookup = CreateConstLookupToSymbol(_compilation.SymbolNodeFactory.ReadyToRunHelper(ReadyToRunHelperId.GetNonGCStaticBase, type, _signatureContext));
            }
            break;

            case CorInfoHelpFunc.CORINFO_HELP_READYTORUN_GENERIC_STATIC_BASE:
            {
                // Token == 0 means "initialize this class". We only expect RyuJIT to call it for this case.
                Debug.Assert(pResolvedToken.token == 0 && pResolvedToken.tokenScope == null);
                Debug.Assert(pGenericLookupKind.needsRuntimeLookup);

                DefType typeToInitialize = (DefType)MethodBeingCompiled.OwningType;
                Debug.Assert(typeToInitialize.IsCanonicalSubtype(CanonicalFormKind.Any));

                DefType  helperArg = typeToInitialize.ConvertToSharedRuntimeDeterminedForm();
                TypeDesc contextType;
                if (pGenericLookupKind.runtimeLookupKind == CORINFO_RUNTIME_LOOKUP_KIND.CORINFO_LOOKUP_THISOBJ)
                {
                    contextType = methodFromContext(pResolvedToken.tokenContext).OwningType;
                }
                else
                {
                    contextType = null;
                }
                ISymbolNode helper = _compilation.SymbolNodeFactory.GenericLookupHelper(
                    pGenericLookupKind.runtimeLookupKind,
                    ReadyToRunHelperId.GetNonGCStaticBase,
                    helperArg,
                    contextType,
                    _signatureContext);
                pLookup = CreateConstLookupToSymbol(helper);
            }
            break;

            case CorInfoHelpFunc.CORINFO_HELP_READYTORUN_GENERIC_HANDLE:
            {
                Debug.Assert(pGenericLookupKind.needsRuntimeLookup);

                ReadyToRunHelperId helperId  = (ReadyToRunHelperId)pGenericLookupKind.runtimeLookupFlags;
                object             helperArg = HandleToObject((IntPtr)pGenericLookupKind.runtimeLookupArgs);
                if (helperArg is MethodDesc methodArg)
                {
                    helperArg = new MethodWithToken(methodArg, new ModuleToken(_tokenContext, pResolvedToken.token));
                }
                TypeDesc contextType;
                if (pGenericLookupKind.runtimeLookupKind == CORINFO_RUNTIME_LOOKUP_KIND.CORINFO_LOOKUP_THISOBJ)
                {
                    contextType = methodFromContext(pResolvedToken.tokenContext).OwningType;
                }
                else
                {
                    contextType = null;
                }
                ISymbolNode helper = _compilation.SymbolNodeFactory.GenericLookupHelper(
                    pGenericLookupKind.runtimeLookupKind,
                    helperId,
                    helperArg,
                    contextType,
                    _signatureContext);
                pLookup = CreateConstLookupToSymbol(helper);
            }
            break;

            default:
                throw new NotImplementedException("ReadyToRun: " + id.ToString());
            }
            return(true);
        }
Beispiel #7
0
        private uint GetClassTypeIndex(TypeDesc type, bool needsCompleteType)
        {
            DefType defType = type as DefType;

            System.Diagnostics.Debug.Assert(defType != null, "GetClassTypeIndex was called with non def type");
            ClassTypeDescriptor classTypeDescriptor = new ClassTypeDescriptor
            {
                IsStruct    = type.IsValueType ? 1 : 0,
                Name        = _objectWriter.GetMangledName(type),
                BaseClassId = 0
            };

            uint typeIndex = _objectWriter.GetClassTypeIndex(classTypeDescriptor);

            _knownTypes[type] = typeIndex;

            if (type.HasBaseType && !type.IsValueType)
            {
                classTypeDescriptor.BaseClassId = GetTypeIndex(defType.BaseType, true);
            }

            List <DataFieldDescriptor> fieldsDescs        = new List <DataFieldDescriptor>();
            List <DataFieldDescriptor> nonGcStaticFields  = new List <DataFieldDescriptor>();
            List <DataFieldDescriptor> gcStaticFields     = new List <DataFieldDescriptor>();
            List <DataFieldDescriptor> threadStaticFields = new List <DataFieldDescriptor>();

            bool isCanonical = defType.IsCanonicalSubtype(CanonicalFormKind.Any);

            foreach (var fieldDesc in defType.GetFields())
            {
                if (fieldDesc.HasRva || fieldDesc.IsLiteral)
                {
                    continue;
                }

                if (isCanonical && fieldDesc.IsStatic)
                {
                    continue;
                }

                LayoutInt           fieldOffset     = fieldDesc.Offset;
                int                 fieldOffsetEmit = fieldOffset.IsIndeterminate ? 0xBAAD : fieldOffset.AsInt;
                DataFieldDescriptor field           = new DataFieldDescriptor
                {
                    FieldTypeIndex = GetVariableTypeIndex(GetFieldDebugType(fieldDesc), false),
                    Offset         = (ulong)fieldOffsetEmit,
                    Name           = fieldDesc.Name
                };

                if (fieldDesc.IsStatic)
                {
                    if (fieldDesc.IsThreadStatic)
                    {
                        threadStaticFields.Add(field);
                    }
                    else if (fieldDesc.HasGCStaticBase)
                    {
                        gcStaticFields.Add(field);
                    }
                    else
                    {
                        nonGcStaticFields.Add(field);
                    }
                }
                else
                {
                    fieldsDescs.Add(field);
                }
            }

            InsertStaticFieldRegionMember(fieldsDescs, defType, nonGcStaticFields, WindowsNodeMangler.NonGCStaticMemberName, "__type_" + WindowsNodeMangler.NonGCStaticMemberName, false);
            InsertStaticFieldRegionMember(fieldsDescs, defType, gcStaticFields, WindowsNodeMangler.GCStaticMemberName, "__type_" + WindowsNodeMangler.GCStaticMemberName, Abi == TargetAbi.CoreRT);
            InsertStaticFieldRegionMember(fieldsDescs, defType, threadStaticFields, WindowsNodeMangler.ThreadStaticMemberName, "__type_" + WindowsNodeMangler.ThreadStaticMemberName, Abi == TargetAbi.CoreRT);

            DataFieldDescriptor[] fields = new DataFieldDescriptor[fieldsDescs.Count];
            for (int i = 0; i < fieldsDescs.Count; ++i)
            {
                fields[i] = fieldsDescs[i];
            }

            LayoutInt elementSize     = defType.GetElementSize();
            int       elementSizeEmit = elementSize.IsIndeterminate ? 0xBAAD : elementSize.AsInt;
            ClassFieldsTypeDescriptor fieldsDescriptor = new ClassFieldsTypeDescriptor
            {
                Size        = (ulong)elementSizeEmit,
                FieldsCount = fieldsDescs.Count
            };

            uint completeTypeIndex = _objectWriter.GetCompleteClassTypeIndex(classTypeDescriptor, fieldsDescriptor, fields);

            _completeKnownTypes[type] = completeTypeIndex;

            if (needsCompleteType)
            {
                return(completeTypeIndex);
            }
            else
            {
                return(typeIndex);
            }
        }
        private uint GetClassTypeIndex(TypeDesc type, bool needsCompleteType)
        {
            DefType defType = type as DefType;

            System.Diagnostics.Debug.Assert(defType != null, "GetClassTypeIndex was called with non def type");
            ClassTypeDescriptor classTypeDescriptor = new ClassTypeDescriptor
            {
                IsStruct     = type.IsValueType ? 1 : 0,
                Name         = _objectWriter.GetMangledName(type),
                BaseClassId  = 0,
                InstanceSize = 0
            };

            uint typeIndex = _objectWriter.GetClassTypeIndex(classTypeDescriptor);

            _knownTypes[type] = typeIndex;

            if (!defType.InstanceByteCount.IsIndeterminate)
            {
                classTypeDescriptor.InstanceSize = (ulong)defType.InstanceByteCount.AsInt;
            }

            if (type.HasBaseType && !type.IsValueType)
            {
                classTypeDescriptor.BaseClassId = GetTypeIndex(defType.BaseType, true);
            }

            List <DataFieldDescriptor>       fieldsDescs        = new List <DataFieldDescriptor>();
            List <DataFieldDescriptor>       nonGcStaticFields  = new List <DataFieldDescriptor>();
            List <DataFieldDescriptor>       gcStaticFields     = new List <DataFieldDescriptor>();
            List <DataFieldDescriptor>       threadStaticFields = new List <DataFieldDescriptor>();
            List <StaticDataFieldDescriptor> staticsDescs       = new List <StaticDataFieldDescriptor>();

            string nonGcStaticDataName  = NodeFactory.NameMangler.NodeMangler.NonGCStatics(type);
            string gcStaticDataName     = NodeFactory.NameMangler.NodeMangler.GCStatics(type);
            string threadStaticDataName = NodeFactory.NameMangler.NodeMangler.ThreadStatics(type);
            bool   IsCoreRTAbi          = Abi == TargetAbi.CoreRT;

            bool isCanonical = defType.IsCanonicalSubtype(CanonicalFormKind.Any);

            foreach (var fieldDesc in defType.GetFields())
            {
                if (fieldDesc.HasRva || fieldDesc.IsLiteral)
                {
                    continue;
                }

                if (isCanonical && fieldDesc.IsStatic)
                {
                    continue;
                }

                LayoutInt           fieldOffset     = fieldDesc.Offset;
                int                 fieldOffsetEmit = fieldOffset.IsIndeterminate ? 0xBAAD : fieldOffset.AsInt;
                DataFieldDescriptor field           = new DataFieldDescriptor
                {
                    FieldTypeIndex = GetVariableTypeIndex(GetFieldDebugType(fieldDesc), false),
                    Offset         = (ulong)fieldOffsetEmit,
                    Name           = fieldDesc.Name
                };

                if (fieldDesc.IsStatic)
                {
                    if (NodeFactory.Target.OperatingSystem != TargetOS.Windows)
                    {
                        StaticDataFieldDescriptor staticDesc = new StaticDataFieldDescriptor
                        {
                            StaticOffset = (ulong)fieldOffsetEmit
                        };

                        // Mark field as static
                        field.Offset = 0xFFFFFFFF;

                        if (fieldDesc.IsThreadStatic)
                        {
                            staticDesc.StaticDataName       = threadStaticDataName;
                            staticDesc.IsStaticDataInObject = IsCoreRTAbi ? 1 : 0;
                        }
                        else if (fieldDesc.HasGCStaticBase)
                        {
                            staticDesc.StaticDataName       = gcStaticDataName;
                            staticDesc.IsStaticDataInObject = IsCoreRTAbi ? 1 : 0;
                        }
                        else
                        {
                            staticDesc.StaticDataName       = nonGcStaticDataName;
                            staticDesc.IsStaticDataInObject = 0;
                        }

                        staticsDescs.Add(staticDesc);
                    }

                    if (fieldDesc.IsThreadStatic)
                    {
                        threadStaticFields.Add(field);
                    }
                    else if (fieldDesc.HasGCStaticBase)
                    {
                        gcStaticFields.Add(field);
                    }
                    else
                    {
                        nonGcStaticFields.Add(field);
                    }
                }
                else
                {
                    fieldsDescs.Add(field);
                }
            }

            if (NodeFactory.Target.OperatingSystem == TargetOS.Windows)
            {
                InsertStaticFieldRegionMember(fieldsDescs, defType, nonGcStaticFields, WindowsNodeMangler.NonGCStaticMemberName, "__type_" + WindowsNodeMangler.NonGCStaticMemberName, false);
                InsertStaticFieldRegionMember(fieldsDescs, defType, gcStaticFields, WindowsNodeMangler.GCStaticMemberName, "__type_" + WindowsNodeMangler.GCStaticMemberName, IsCoreRTAbi);
                InsertStaticFieldRegionMember(fieldsDescs, defType, threadStaticFields, WindowsNodeMangler.ThreadStaticMemberName, "__type_" + WindowsNodeMangler.ThreadStaticMemberName, IsCoreRTAbi);
            }
            else
            {
                fieldsDescs.AddRange(nonGcStaticFields);
                fieldsDescs.AddRange(gcStaticFields);
                fieldsDescs.AddRange(threadStaticFields);
            }

            DataFieldDescriptor[] fields = new DataFieldDescriptor[fieldsDescs.Count];
            for (int i = 0; i < fieldsDescs.Count; ++i)
            {
                fields[i] = fieldsDescs[i];
            }

            StaticDataFieldDescriptor[] statics = new StaticDataFieldDescriptor[staticsDescs.Count];
            for (int i = 0; i < staticsDescs.Count; ++i)
            {
                statics[i] = staticsDescs[i];
            }

            LayoutInt elementSize     = defType.GetElementSize();
            int       elementSizeEmit = elementSize.IsIndeterminate ? 0xBAAD : elementSize.AsInt;
            ClassFieldsTypeDescriptor fieldsDescriptor = new ClassFieldsTypeDescriptor
            {
                Size        = (ulong)elementSizeEmit,
                FieldsCount = fieldsDescs.Count,
            };

            uint completeTypeIndex = _objectWriter.GetCompleteClassTypeIndex(classTypeDescriptor, fieldsDescriptor, fields, statics);

            _completeKnownTypes[type] = completeTypeIndex;

            if (needsCompleteType)
            {
                return(completeTypeIndex);
            }
            else
            {
                return(typeIndex);
            }
        }
Beispiel #9
0
        protected override DependencyList ComputeNonRelocationBasedDependencies(NodeFactory factory)
        {
            DependencyList dependencyList = base.ComputeNonRelocationBasedDependencies(factory);

            // Ensure that we track the necessary type symbol if we are working with a constructed type symbol.
            // The emitter will ensure we don't emit both, but this allows us assert that we only generate
            // relocs to nodes we emit.
            dependencyList.Add(factory.NecessaryTypeSymbol(_type), "NecessaryType for constructed type");

            DefType closestDefType = _type.GetClosestDefType();

            if (TrackInterfaceDispatchMapDepenendency && _type.RuntimeInterfaces.Length > 0)
            {
                dependencyList.Add(factory.InterfaceDispatchMap(_type), "Interface dispatch map");
            }

            if (_type.RuntimeInterfaces.Length > 0 && !factory.CompilationModuleGroup.ShouldProduceFullVTable(_type))
            {
                foreach (var implementedInterface in _type.RuntimeInterfaces)
                {
                    // If the type implements ICastable, the methods are implicitly necessary
                    if (implementedInterface == factory.ICastableInterface)
                    {
                        MethodDesc isInstDecl      = implementedInterface.GetKnownMethod("IsInstanceOfInterface", null);
                        MethodDesc getImplTypeDecl = implementedInterface.GetKnownMethod("GetImplType", null);

                        MethodDesc isInstMethodImpl      = _type.ResolveInterfaceMethodTarget(isInstDecl);
                        MethodDesc getImplTypeMethodImpl = _type.ResolveInterfaceMethodTarget(getImplTypeDecl);

                        if (isInstMethodImpl != null)
                        {
                            dependencyList.Add(factory.VirtualMethodUse(isInstMethodImpl), "ICastable IsInst");
                        }
                        if (getImplTypeMethodImpl != null)
                        {
                            dependencyList.Add(factory.VirtualMethodUse(getImplTypeMethodImpl), "ICastable GetImplType");
                        }
                    }

                    // If any of the implemented interfaces have variance, calls against compatible interface methods
                    // could result in interface methods of this type being used (e.g. IEnumberable<object>.GetEnumerator()
                    // can dispatch to an implementation of IEnumerable<string>.GetEnumerator()).
                    // For now, we will not try to optimize this and we will pretend all interface methods are necessary.
                    bool allInterfaceMethodsAreImplicitlyUsed = false;
                    if (implementedInterface.HasVariance)
                    {
                        TypeDesc interfaceDefinition = implementedInterface.GetTypeDefinition();
                        for (int i = 0; i < interfaceDefinition.Instantiation.Length; i++)
                        {
                            if (((GenericParameterDesc)interfaceDefinition.Instantiation[i]).Variance != 0 &&
                                !implementedInterface.Instantiation[i].IsValueType)
                            {
                                allInterfaceMethodsAreImplicitlyUsed = true;
                                break;
                            }
                        }
                    }
                    if (!allInterfaceMethodsAreImplicitlyUsed &&
                        (_type.IsArray || _type.GetTypeDefinition() == factory.ArrayOfTEnumeratorType) &&
                        implementedInterface.HasInstantiation)
                    {
                        // NOTE: we need to also do this for generic interfaces on arrays because they have a weird casting rule
                        // that doesn't require the implemented interface to be variant to consider it castable.
                        // For value types, we only need this when the array is castable by size (int[] and ICollection<uint>),
                        // or it's a reference type (Derived[] and ICollection<Base>).
                        TypeDesc elementType = _type.IsArray ? ((ArrayType)_type).ElementType : _type.Instantiation[0];
                        allInterfaceMethodsAreImplicitlyUsed =
                            CastingHelper.IsArrayElementTypeCastableBySize(elementType) ||
                            (elementType.IsDefType && !elementType.IsValueType);
                    }

                    if (allInterfaceMethodsAreImplicitlyUsed)
                    {
                        foreach (var interfaceMethod in implementedInterface.GetAllMethods())
                        {
                            if (interfaceMethod.Signature.IsStatic)
                            {
                                continue;
                            }

                            // Generic virtual methods are tracked by an orthogonal mechanism.
                            if (interfaceMethod.HasInstantiation)
                            {
                                continue;
                            }

                            MethodDesc implMethod = closestDefType.ResolveInterfaceMethodToVirtualMethodOnType(interfaceMethod);
                            if (implMethod != null)
                            {
                                dependencyList.Add(factory.VirtualMethodUse(interfaceMethod), "Variant interface method");
                                dependencyList.Add(factory.VirtualMethodUse(implMethod), "Variant interface method");
                            }
                        }
                    }
                }
            }

            if (_type.IsArray)
            {
                // Array EEType depends on System.Array's virtuals. Array EETypes don't point to
                // their base type (i.e. there's no reloc based dependency making this "just work").
                dependencyList.Add(factory.ConstructedTypeSymbol(_type.BaseType), "Array base type");
            }

            dependencyList.Add(factory.VTable(_type), "VTable");

            if (closestDefType.HasGenericDictionarySlot())
            {
                // Add a dependency on the template for this type, if the canonical type should be generated into this binary.
                DefType templateType = GenericTypesTemplateMap.GetActualTemplateTypeForType(factory, _type.ConvertToCanonForm(CanonicalFormKind.Specific));

                if (templateType.IsCanonicalSubtype(CanonicalFormKind.Any) && !factory.NecessaryTypeSymbol(templateType).RepresentsIndirectionCell)
                {
                    dependencyList.Add(factory.NativeLayout.TemplateTypeLayout(templateType), "Template Type Layout");
                }
            }

            // Generated type contains generic virtual methods that will get added to the GVM tables
            if (TypeGVMEntriesNode.TypeNeedsGVMTableEntries(_type))
            {
                dependencyList.Add(new DependencyListEntry(factory.TypeGVMEntries(_type), "Type with generic virtual methods"));
            }

            if (factory.TypeSystemContext.HasLazyStaticConstructor(_type))
            {
                // The fact that we generated an EEType means that someone can call RuntimeHelpers.RunClassConstructor.
                // We need to make sure this is possible.
                dependencyList.Add(new DependencyListEntry(factory.TypeNonGCStaticsSymbol((MetadataType)_type), "Class constructor"));
            }

            return(dependencyList);
        }
Beispiel #10
0
        protected override DependencyList ComputeNonRelocationBasedDependencies(NodeFactory factory)
        {
            DependencyList dependencyList = base.ComputeNonRelocationBasedDependencies(factory);

            // Ensure that we track the necessary type symbol if we are working with a constructed type symbol.
            // The emitter will ensure we don't emit both, but this allows us assert that we only generate
            // relocs to nodes we emit.
            dependencyList.Add(factory.NecessaryTypeSymbol(_type), "NecessaryType for constructed type");

            DefType closestDefType = _type.GetClosestDefType();

            if (_type.RuntimeInterfaces.Length > 0)
            {
                if (TrackInterfaceDispatchMapDepenendency)
                {
                    dependencyList.Add(factory.InterfaceDispatchMap(_type), "Interface dispatch map");
                }

                foreach (var implementedInterface in _type.RuntimeInterfaces)
                {
                    // If the type implements ICastable, the methods are implicitly necessary
                    if (implementedInterface == factory.ICastableInterface)
                    {
                        MethodDesc isInstDecl      = implementedInterface.GetKnownMethod("IsInstanceOfInterface", null);
                        MethodDesc getImplTypeDecl = implementedInterface.GetKnownMethod("GetImplType", null);

                        MethodDesc isInstMethodImpl      = _type.ResolveInterfaceMethodTarget(isInstDecl);
                        MethodDesc getImplTypeMethodImpl = _type.ResolveInterfaceMethodTarget(getImplTypeDecl);

                        if (isInstMethodImpl != null)
                        {
                            dependencyList.Add(factory.VirtualMethodUse(isInstMethodImpl), "ICastable IsInst");
                        }
                        if (getImplTypeMethodImpl != null)
                        {
                            dependencyList.Add(factory.VirtualMethodUse(getImplTypeMethodImpl), "ICastable GetImplType");
                        }
                    }

                    // If any of the implemented interfaces have variance, calls against compatible interface methods
                    // could result in interface methods of this type being used (e.g. IEnumberable<object>.GetEnumerator()
                    // can dispatch to an implementation of IEnumerable<string>.GetEnumerator()).
                    // For now, we will not try to optimize this and we will pretend all interface methods are necessary.
                    // NOTE: we need to also do this for generic interfaces on arrays because they have a weird casting rule
                    // that doesn't require the implemented interface to be variant to consider it castable.
                    if (implementedInterface.HasVariance || (_type.IsArray && implementedInterface.HasInstantiation))
                    {
                        foreach (var interfaceMethod in implementedInterface.GetAllMethods())
                        {
                            if (interfaceMethod.Signature.IsStatic)
                            {
                                continue;
                            }

                            // Generic virtual methods are tracked by an orthogonal mechanism.
                            if (interfaceMethod.HasInstantiation)
                            {
                                continue;
                            }

                            MethodDesc implMethod = closestDefType.ResolveInterfaceMethodToVirtualMethodOnType(interfaceMethod);
                            if (implMethod != null)
                            {
                                dependencyList.Add(factory.VirtualMethodUse(interfaceMethod), "Variant interface method");
                                dependencyList.Add(factory.VirtualMethodUse(implMethod), "Variant interface method");
                            }
                        }
                    }
                }
            }

            if (_type.IsArray)
            {
                // Array EEType depends on System.Array's virtuals. Array EETypes don't point to
                // their base type (i.e. there's no reloc based dependency making this "just work").
                dependencyList.Add(factory.ConstructedTypeSymbol(_type.BaseType), "Array base type");
            }

            dependencyList.Add(factory.VTable(_type), "VTable");

            if (closestDefType.HasGenericDictionarySlot())
            {
                // Add a dependency on the template for this type, if the canonical type should be generated into this binary.
                DefType templateType = GenericTypesTemplateMap.GetActualTemplateTypeForType(factory, _type.ConvertToCanonForm(CanonicalFormKind.Specific));

                if (templateType.IsCanonicalSubtype(CanonicalFormKind.Any) && !factory.NecessaryTypeSymbol(templateType).RepresentsIndirectionCell)
                {
                    dependencyList.Add(factory.NativeLayout.TemplateTypeLayout(templateType), "Template Type Layout");
                }
            }

            // Generated type contains generic virtual methods that will get added to the GVM tables
            if (TypeGVMEntriesNode.TypeNeedsGVMTableEntries(_type))
            {
                dependencyList.Add(new DependencyListEntry(factory.TypeGVMEntries(_type), "Type with generic virtual methods"));
            }

            if (factory.TypeSystemContext.HasLazyStaticConstructor(_type))
            {
                // The fact that we generated an EEType means that someone can call RuntimeHelpers.RunClassConstructor.
                // We need to make sure this is possible.
                dependencyList.Add(new DependencyListEntry(factory.TypeNonGCStaticsSymbol((MetadataType)_type), "Class constructor"));
            }

            // Dependencies of the StaticsInfoHashTable and the ReflectionFieldAccessMap
            if (_type is MetadataType)
            {
                MetadataType metadataType = (MetadataType)_type;

                // NOTE: The StaticsInfoHashtable entries need to reference the gc and non-gc static nodes through an indirection cell.
                // The StaticsInfoHashtable entries only exist for static fields on generic types.

                if (metadataType.GCStaticFieldSize.AsInt > 0)
                {
                    ISymbolNode gcStatics = factory.TypeGCStaticsSymbol(metadataType);
                    dependencyList.Add(_type.HasInstantiation ? factory.Indirection(gcStatics) : gcStatics, "GC statics indirection for StaticsInfoHashtable");
                }
                if (metadataType.NonGCStaticFieldSize.AsInt > 0)
                {
                    ISymbolNode nonGCStatic = factory.TypeNonGCStaticsSymbol(metadataType);
                    if (_type.HasInstantiation)
                    {
                        // The entry in the StaticsInfoHashtable points at the begining of the static fields data, so we need to add
                        // the cctor context offset to the indirection cell.

                        int cctorOffset = 0;
                        if (factory.TypeSystemContext.HasLazyStaticConstructor(metadataType))
                        {
                            cctorOffset += NonGCStaticsNode.GetClassConstructorContextStorageSize(factory.TypeSystemContext.Target, metadataType);
                        }

                        nonGCStatic = factory.Indirection(nonGCStatic, cctorOffset);
                    }
                    dependencyList.Add(nonGCStatic, "Non-GC statics indirection for StaticsInfoHashtable");
                }

                // TODO: TLS dependencies
            }

            return(dependencyList);
        }