public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false) { Debug.Assert((EETypeNode.GetVTableOffset(factory.Target.PointerSize) % factory.Target.PointerSize) == 0, "vtable offset must be aligned"); ObjectDataBuilder objData = new ObjectDataBuilder(factory, relocsOnly); objData.AddSymbol(this); if (!relocsOnly) { int tableOffset; if (_targetMethod.OwningType.IsInterface) { tableOffset = 0; } else { tableOffset = EETypeNode.GetVTableOffset(factory.Target.PointerSize) / factory.Target.PointerSize; } objData.EmitInt(tableOffset + VirtualMethodSlotHelper.GetVirtualMethodSlot(factory, _targetMethod, _targetMethod.OwningType)); } return(objData.ToObjectData()); }
public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false) { bool hasVariance = _details.Variance != null; var builder = new ObjectDataBuilder(factory, relocsOnly); builder.AddSymbol(this); builder.RequireInitialPointerAlignment(); builder.EmitShort((short)checked ((UInt16)_details.Instantiation.Length)); builder.EmitByte((byte)(hasVariance ? 1 : 0)); // TODO: general purpose padding builder.EmitByte(0); if (factory.Target.PointerSize == 8) { builder.EmitInt(0); } foreach (var typeArg in _details.Instantiation) { builder.EmitPointerRelocOrIndirectionReference(factory.NecessaryTypeSymbol(typeArg)); } if (hasVariance) { foreach (var argVariance in _details.Variance) { builder.EmitByte(checked ((byte)argVariance)); } } return(builder.ToObjectData()); }
public sealed override ObjectData GetData(NodeFactory factory, bool relocsOnly = false) { ObjectDataBuilder builder = new ObjectDataBuilder(factory, relocsOnly); builder.AddSymbol(this); builder.RequireInitialPointerAlignment(); DictionaryLayoutNode layout = GetDictionaryLayout(factory); // Node representing the generic dictionary layout might be one of two kinds: // With fixed slots, or where slots are added as we're expanding the graph. // If it's the latter, we can't touch the collection of slots before the graph expansion // is complete (relocsOnly == false). It's someone else's responsibility // to make sure the dependencies are properly generated. // If this is a dictionary layout with fixed slots, it's the responsibility of // each dictionary to ensure the targets are marked. if (layout.HasFixedSlots || !relocsOnly) { // TODO: pass the layout we already have to EmitDataInternal EmitDataInternal(ref builder, factory, relocsOnly); } return(builder.ToObjectData()); }
public override ObjectData GetData(NodeFactory factory, bool relocsOnly) { ObjectDataBuilder builder = new ObjectDataBuilder(factory, relocsOnly); // If the type has a class constructor, its non-GC statics section is prefixed // by System.Runtime.CompilerServices.StaticClassConstructionContext struct. if (factory.TypeSystemContext.HasLazyStaticConstructor(_type)) { int alignmentRequired = Math.Max(_type.NonGCStaticFieldAlignment.AsInt, GetClassConstructorContextAlignment(_type.Context.Target)); int classConstructorContextStorageSize = GetClassConstructorContextStorageSize(factory.Target, _type); builder.RequireInitialAlignment(alignmentRequired); Debug.Assert(classConstructorContextStorageSize >= GetClassConstructorContextSize(_type.Context.Target)); // Add padding before the context if alignment forces us to do so builder.EmitZeros(classConstructorContextStorageSize - GetClassConstructorContextSize(_type.Context.Target)); // Emit the actual StaticClassConstructionContext MethodDesc cctorMethod = _type.GetStaticConstructor(); MethodDesc canonCctorMethod = cctorMethod.GetCanonMethodTarget(CanonicalFormKind.Specific); if (cctorMethod != canonCctorMethod) builder.EmitPointerReloc(factory.FatFunctionPointer(cctorMethod)); else builder.EmitPointerReloc(factory.MethodEntrypoint(cctorMethod)); builder.EmitZeroPointer(); } else { builder.RequireInitialAlignment(_type.NonGCStaticFieldAlignment.AsInt); } builder.EmitZeros(_type.NonGCStaticFieldSize.AsInt); builder.AddSymbol(this); return builder.ToObjectData(); }
public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false) { if (relocsOnly) { return(new ObjectData(Array.Empty <byte>(), Array.Empty <Relocation>(), 1, new ISymbolDefinitionNode[] { this })); } // Ensure the native layout blob has been saved factory.MetadataManager.NativeLayoutInfo.SaveNativeLayoutInfoWriter(factory); ObjectDataBuilder objData = new ObjectDataBuilder(factory, relocsOnly); objData.RequireInitialPointerAlignment(); objData.AddSymbol(this); if (_methodToTemplateIndex == null) { BuildMethodToIdMap(factory); } TypeDesc containerType = null; foreach (var method in _methodToTemplateIndex.Keys) { Debug.Assert(containerType == null || containerType == method.OwningType); containerType = method.OwningType; #if !DEBUG break; #endif } if (factory.Target.SupportsRelativePointers) { objData.EmitReloc(factory.NecessaryTypeSymbol(containerType), RelocType.IMAGE_REL_BASED_RELPTR32); } else { objData.EmitPointerReloc(factory.NecessaryTypeSymbol(containerType)); } List <KeyValuePair <MethodDesc, int> > sortedList = new List <KeyValuePair <MethodDesc, int> >(_methodToTemplateIndex); sortedList.Sort((firstEntry, secondEntry) => firstEntry.Value.CompareTo(secondEntry.Value)); for (int i = 0; i < sortedList.Count; i++) { var nameAndSig = factory.NativeLayout.PlacedSignatureVertex(factory.NativeLayout.MethodNameAndSignatureVertex(sortedList[i].Key)); if (factory.Target.SupportsRelativePointers) { objData.EmitInt(nameAndSig.SavedVertex.VertexOffset); objData.EmitReloc(factory.MethodEntrypoint(sortedList[i].Key), RelocType.IMAGE_REL_BASED_RELPTR32); } else { objData.EmitNaturalInt(nameAndSig.SavedVertex.VertexOffset); objData.EmitPointerReloc(factory.MethodEntrypoint(sortedList[i].Key)); } } _endSymbol.SetSymbolOffset(objData.CountBytes); objData.AddSymbol(_endSymbol); return(objData.ToObjectData()); }
public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false) { // This node does not trigger generation of other nodes. if (relocsOnly) { return(new ObjectData(Array.Empty <byte>(), Array.Empty <Relocation>(), 1, new ISymbolDefinitionNode[] { this })); } ObjectDataBuilder objDataBuilder = new ObjectDataBuilder(factory, relocsOnly); // Emit number of dictionaries in table objDataBuilder.AddSymbol(this); IReadOnlyCollection <GenericDictionaryNode> dictionariesEmitted = factory.MetadataManager.GetCompiledGenericDictionaries(); objDataBuilder.EmitInt(dictionariesEmitted.Count); DebugInfoBlob signatureData = new DebugInfoBlob(); BlobBuilder signatureBlobBuilder = new BlobBuilder(); BlobBuilder signatureLenBuilder = new BlobBuilder(); ManagedBinaryEmitter pseudoAssembly = factory.WindowsDebugData.DebugPseudoAssemblySection.PseudoAssembly; foreach (GenericDictionaryNode dictionary in dictionariesEmitted) { objDataBuilder.EmitReloc(dictionary, RelocType.IMAGE_REL_BASED_ADDR32NB); objDataBuilder.EmitUInt(signatureData.Size()); signatureBlobBuilder.Clear(); int typeDictLen = dictionary.TypeInstantiation.IsNull ? 0 : dictionary.TypeInstantiation.Length; int methodDictLen = dictionary.MethodInstantiation.IsNull ? 0 : dictionary.MethodInstantiation.Length; signatureBlobBuilder.WriteCompressedInteger(typeDictLen + methodDictLen); if (typeDictLen != 0) { foreach (TypeDesc type in dictionary.TypeInstantiation) { pseudoAssembly.EncodeSignatureForType(type, signatureBlobBuilder); } } if (methodDictLen != 0) { foreach (TypeDesc type in dictionary.MethodInstantiation) { pseudoAssembly.EncodeSignatureForType(type, signatureBlobBuilder); } } int blobSize = signatureBlobBuilder.Count; signatureLenBuilder.Clear(); signatureLenBuilder.WriteCompressedInteger(blobSize); // Prepend the signature data with a length signatureData.WriteBuffer(signatureLenBuilder); // And then attach the actual signature data signatureData.WriteBuffer(signatureBlobBuilder); } // Attach signature information to end after all of the rva/offset pairs objDataBuilder.EmitBytes(signatureData.ToArray()); return(objDataBuilder.ToObjectData()); }
public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false) { ObjectDataBuilder builder = new ObjectDataBuilder(factory, relocsOnly); builder.RequireInitialPointerAlignment(); builder.AddSymbol(this); // Don't bother sorting if we're not emitting the contents if (!relocsOnly) { _items.Sort((x, y) => Comparer <int> .Default.Compare((int)x.Id, (int)y.Id)); } // ReadyToRunHeader.Magic builder.EmitInt((int)(ReadyToRunHeaderConstants.Signature)); // ReadyToRunHeader.MajorVersion builder.EmitShort((short)(ReadyToRunHeaderConstants.CurrentMajorVersion)); builder.EmitShort((short)(ReadyToRunHeaderConstants.CurrentMinorVersion)); // ReadyToRunHeader.Flags builder.EmitInt(0); // ReadyToRunHeader.NumberOfSections var sectionCountReservation = builder.ReserveShort(); // ReadyToRunHeader.EntrySize builder.EmitByte((byte)(8 + 2 * factory.Target.PointerSize)); // ReadyToRunHeader.EntryType builder.EmitByte(1); int count = 0; foreach (var item in _items) { // Skip empty entries if (!relocsOnly && item.Node.ShouldSkipEmittingObjectNode(factory)) { continue; } builder.EmitInt((int)item.Id); ModuleInfoFlags flags = 0; if (item.EndSymbol != null) { flags |= ModuleInfoFlags.HasEndPointer; } builder.EmitInt((int)flags); builder.EmitPointerReloc(item.StartSymbol); if (item.EndSymbol != null) { builder.EmitPointerReloc(item.EndSymbol); } else { builder.EmitZeroPointer(); } count++; } builder.EmitShort(sectionCountReservation, checked ((short)count)); return(builder.ToObjectData()); }
public override ObjectData GetData(NodeFactory factory, bool relocsOnly) { ObjectDataBuilder builder = new ObjectDataBuilder(factory, relocsOnly); // If the type has a class constructor, its non-GC statics section is prefixed // by System.Runtime.CompilerServices.StaticClassConstructionContext struct. if (factory.TypeSystemContext.HasLazyStaticConstructor(_type)) { int alignmentRequired = Math.Max(_type.NonGCStaticFieldAlignment.AsInt, GetClassConstructorContextAlignment(_type.Context.Target)); int classConstructorContextStorageSize = GetClassConstructorContextStorageSize(factory.Target, _type); builder.RequireInitialAlignment(alignmentRequired); Debug.Assert(classConstructorContextStorageSize >= GetClassConstructorContextSize(_type.Context.Target)); // Add padding before the context if alignment forces us to do so builder.EmitZeros(classConstructorContextStorageSize - GetClassConstructorContextSize(_type.Context.Target)); // Emit the actual StaticClassConstructionContext MethodDesc cctorMethod = _type.GetStaticConstructor(); builder.EmitPointerReloc(factory.ExactCallableAddress(cctorMethod)); builder.EmitZeroPointer(); } else { builder.RequireInitialAlignment(_type.NonGCStaticFieldAlignment.AsInt); } if (_sortedPreInitFields != null) { int staticOffsetBegin = builder.CountBytes; int staticOffsetEnd = builder.CountBytes + _type.NonGCStaticFieldSize.AsInt; int staticOffset = staticOffsetBegin; int idx = 0; while (staticOffset < staticOffsetEnd) { int writeTo = staticOffsetEnd; if (idx < _sortedPreInitFields.Count) { writeTo = staticOffsetBegin + _sortedPreInitFields[idx].Field.Offset.AsInt; } // Emit the zeros before the next preinitField builder.EmitZeros(writeTo - staticOffset); staticOffset = writeTo; // Emit the data if (idx < _sortedPreInitFields.Count) { _sortedPreInitFields[idx].WriteData(ref builder, factory); idx++; staticOffset = builder.CountBytes; } } } else { builder.EmitZeros(_type.NonGCStaticFieldSize.AsInt); } builder.AddSymbol(this); return(builder.ToObjectData()); }
public override ObjectData GetData(NodeFactory factory, bool relocsOnly) { ObjectDataBuilder builder = new ObjectDataBuilder(factory, relocsOnly); // If the type has a class constructor, its non-GC statics section is prefixed // by System.Runtime.CompilerServices.StaticClassConstructionContext struct. if (factory.PreinitializationManager.HasLazyStaticConstructor(_type)) { int alignmentRequired = Math.Max(_type.NonGCStaticFieldAlignment.AsInt, GetClassConstructorContextAlignment(_type.Context.Target)); int classConstructorContextStorageSize = GetClassConstructorContextStorageSize(factory.Target, _type); builder.RequireInitialAlignment(alignmentRequired); Debug.Assert(classConstructorContextStorageSize >= GetClassConstructorContextSize(_type.Context.Target)); // Add padding before the context if alignment forces us to do so builder.EmitZeros(classConstructorContextStorageSize - GetClassConstructorContextSize(_type.Context.Target)); // Emit the actual StaticClassConstructionContext MethodDesc cctorMethod = _type.GetStaticConstructor(); builder.EmitPointerReloc(factory.ExactCallableAddress(cctorMethod)); builder.EmitZeroPointer(); } else { builder.RequireInitialAlignment(_type.NonGCStaticFieldAlignment.AsInt); } if (_preinitializationManager.IsPreinitialized(_type)) { TypePreinit.PreinitializationInfo preinitInfo = _preinitializationManager.GetPreinitializationInfo(_type); int initialOffset = builder.CountBytes; foreach (FieldDesc field in _type.GetFields()) { if (!field.IsStatic || field.HasRva || field.IsLiteral || field.IsThreadStatic || field.HasGCStaticBase) { continue; } int padding = field.Offset.AsInt - builder.CountBytes + initialOffset; Debug.Assert(padding >= 0); builder.EmitZeros(padding); TypePreinit.ISerializableValue val = preinitInfo.GetFieldValue(field); int currentOffset = builder.CountBytes; val.WriteFieldData(ref builder, factory); Debug.Assert(builder.CountBytes - currentOffset == field.FieldType.GetElementSize().AsInt); } int pad = _type.NonGCStaticFieldSize.AsInt - builder.CountBytes + initialOffset; Debug.Assert(pad >= 0); builder.EmitZeros(pad); } else { builder.EmitZeros(_type.NonGCStaticFieldSize.AsInt); } builder.AddSymbol(this); return(builder.ToObjectData()); }
public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false) { // This is a summary node that doesn't introduce dependencies. if (relocsOnly) { return(new ObjectData(Array.Empty <byte>(), Array.Empty <Relocation>(), 1, new ISymbolDefinitionNode[] { this })); } var modulesWithCctor = new List <ModuleDesc>(); foreach (var methodNode in factory.MetadataManager.GetCompiledMethodBodies()) { MethodDesc method = methodNode.Method; if (method.OwningType is MetadataType mdType && mdType.IsModuleType && method.IsStaticConstructor) { modulesWithCctor.Add(mdType.Module); } } // We have a list of modules with a class constructor. // Do a topological sort based on the assembly references of each module. // This is an approximation that tries to deal with module initializers that might have // dependencies on each other. The spec doesn't guarantee any ordering so this is best effort. List <ModuleDesc> sortedModules = new List <ModuleDesc>(); var graphFactory = new ModuleGraphFactory(); // This is a list because we want to keep a stable sort order. var allModules = new List <ModuleGraphNode>(); // Seed the graph with the list of modules we're interested in foreach (ModuleDesc module in modulesWithCctor) { allModules.Add(graphFactory.GetNode(module)); } // Expand the graph to include all the nodes in between the interesting ones var modulesToExpand = new Queue <ModuleGraphNode>(allModules); while (modulesToExpand.Count > 0) { ModuleGraphNode node = modulesToExpand.Dequeue(); foreach (var reference in node.Edges) { if (!allModules.Contains(reference)) { allModules.Add(reference); modulesToExpand.Enqueue(reference); } } } // Now sort the nodes // // We start with the modules that don't reference any other modules. // Then we add modules that reference the modules we already sorted. // Etc. until we figured out the order of all modules with a cctor. // // This might appear counter intuitive (the cctor of the entrypoint module // will likely run last), but if the entrypoint module cctor calls into another // module that has a cctor, CoreCLR will run that cctor first. // // If a module doesn't call into other modules with a cctor, it doesn't matter // when we sort it. If it does call into one, it should run before. var markedModules = new HashSet <ModuleGraphNode>(); while (sortedModules.Count != modulesWithCctor.Count) { bool madeProgress = false; // Add nodes that have all their dependencies already satisfied. foreach (var module in allModules) { if (!markedModules.Contains(module) && module.Satisfies(markedModules)) { madeProgress = true; markedModules.Add(module); if (modulesWithCctor.Contains(module.Module)) { sortedModules.Add(module.Module); } } } // If we haven't made progress, there's a cycle. Pick the first unmarked node as victim. if (!madeProgress) { foreach (var module in allModules) { if (!markedModules.Contains(module)) { markedModules.Add(module); if (modulesWithCctor.Contains(module.Module)) { sortedModules.Add(module.Module); } break; } } } } // The data structure is a flat list of module constructors to call. // This is insufficient for the purposes of ordering in the multi-object-module mode. // If this mode ever becomes more interesting, we'll need to do the sorting at // the time of startup. (Linker likely can't do it, unfortunately.) ObjectDataBuilder builder = new ObjectDataBuilder(factory, relocsOnly); builder.AddSymbol(this); builder.AddSymbol(_endSymbol); foreach (var module in sortedModules) { builder.EmitPointerReloc(factory.MethodEntrypoint(module.GetGlobalModuleType().GetStaticConstructor())); } var result = builder.ToObjectData(); _endSymbol.SetSymbolOffset(result.Data.Length); return(result); }
protected override void GetElementDataForNodes(ref ObjectDataBuilder builder, NodeFactory factory, bool relocsOnly) { if (relocsOnly) { return; } // The interface dispatch cell has an alignment requirement of 2 * [Pointer size] as part of the // synchronization mechanism of the two values in the runtime. builder.RequireInitialAlignment(factory.Target.PointerSize * 2); // This number chosen to be high enough that the cost of recording slot numbers is cheap. const int InterfaceDispatchCellRunLength = 32; const int NoSlot = -1; // // We emit the individual dispatch cells in groups. The purpose of the grouping is to save // us the number of slots we need to emit. The grouping looks like this: // // DispatchCell1 // DispatchCell2 // ... // DispatchCellN // Null // Slot of the above dispatch cells // int runLength = 0; int currentSlot = NoSlot; foreach (InterfaceDispatchCellNode node in NodesList) { MethodDesc targetMethod = node.TargetMethod; int targetSlot = VirtualMethodSlotHelper.GetVirtualMethodSlot(factory, targetMethod, targetMethod.OwningType); if (currentSlot == NoSlot) { // This is the first dispatch cell we're emitting currentSlot = targetSlot; } else if (currentSlot != targetSlot || runLength == InterfaceDispatchCellRunLength) { // Make sure we are sorted Debug.Assert(targetSlot >= currentSlot); // End the run of dispatch cells builder.EmitZeroPointer(); builder.EmitNaturalInt(currentSlot); currentSlot = targetSlot; runLength = 0; } node.InitializeOffsetFromBeginningOfArray(builder.CountBytes); node.EncodeData(ref builder, factory, relocsOnly); builder.AddSymbol(node); runLength++; } if (runLength > 0) { // End the run of dispatch cells builder.EmitZeroPointer(); builder.EmitNaturalInt(currentSlot); } }