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>()); } }
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); }
/// <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); }
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); }
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); }
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); }
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); } }
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); }
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); }