public override ObjectData GetData(NodeFactory factory, bool relocsOnly) { ObjectDataBuilder objData = new ObjectDataBuilder(factory, relocsOnly); objData.RequireInitialPointerAlignment(); objData.AddSymbol(this); ComputeOptionalEETypeFields(factory, relocsOnly); OutputGCDesc(ref objData); OutputComponentSize(ref objData); OutputFlags(factory, ref objData); OutputBaseSize(ref objData); OutputRelatedType(factory, ref objData); // Number of vtable slots will be only known later. Reseve the bytes for it. var vtableSlotCountReservation = objData.ReserveShort(); // Number of interfaces will only be known later. Reserve the bytes for it. var interfaceCountReservation = objData.ReserveShort(); objData.EmitInt(_type.GetHashCode()); objData.EmitPointerReloc(factory.TypeManagerIndirection); if (EmitVirtualSlotsAndInterfaces) { // Emit VTable Debug.Assert(objData.CountBytes - ((ISymbolDefinitionNode)this).Offset == GetVTableOffset(objData.TargetPointerSize)); SlotCounter virtualSlotCounter = SlotCounter.BeginCounting(ref /* readonly */ objData); OutputVirtualSlots(factory, ref objData, _type, _type, relocsOnly); // Update slot count int numberOfVtableSlots = virtualSlotCounter.CountSlots(ref /* readonly */ objData); objData.EmitShort(vtableSlotCountReservation, checked ((short)numberOfVtableSlots)); // Emit interface map SlotCounter interfaceSlotCounter = SlotCounter.BeginCounting(ref /* readonly */ objData); OutputInterfaceMap(factory, ref objData); // Update slot count int numberOfInterfaceSlots = interfaceSlotCounter.CountSlots(ref /* readonly */ objData); objData.EmitShort(interfaceCountReservation, checked ((short)numberOfInterfaceSlots)); } else { // If we're not emitting any slots, the number of slots is zero. objData.EmitShort(vtableSlotCountReservation, 0); objData.EmitShort(interfaceCountReservation, 0); } OutputFinalizerMethod(factory, ref objData); OutputOptionalFields(factory, ref objData); OutputNullableTypeParameter(factory, ref objData); OutputGenericInstantiationDetails(factory, ref objData); return(objData.ToObjectData()); }
public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false) { ObjectDataBuilder builder = new ObjectDataBuilder(factory); builder.Alignment = factory.Target.PointerSize; builder.DefinedSymbols.Add(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 (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()); }
void EmitDispatchMap(ref ObjectDataBuilder builder, NodeFactory factory) { var entryCountReservation = builder.ReserveShort(); var defaultEntryCountReservation = builder.ReserveShort(); var staticEntryCountReservation = builder.ReserveShort(); var defaultStaticEntryCountReservation = builder.ReserveShort(); int entryCount = 0; TypeDesc declType = _type.GetClosestDefType(); TypeDesc declTypeDefinition = declType.GetTypeDefinition(); DefType[] declTypeRuntimeInterfaces = declType.RuntimeInterfaces; DefType[] declTypeDefinitionRuntimeInterfaces = declTypeDefinition.RuntimeInterfaces; // Catch any runtime interface collapsing. We shouldn't have any Debug.Assert(declTypeRuntimeInterfaces.Length == declTypeDefinitionRuntimeInterfaces.Length); var defaultImplementations = new List <(int InterfaceIndex, int InterfaceMethodSlot, int ImplMethodSlot)>(); var staticImplementations = new List <(int InterfaceIndex, int InterfaceMethodSlot, int ImplMethodSlot, int Context)>(); var staticDefaultImplementations = new List <(int InterfaceIndex, int InterfaceMethodSlot, int ImplMethodSlot, int Context)>(); // Resolve all the interfaces, but only emit non-static and non-default implementations for (int interfaceIndex = 0; interfaceIndex < declTypeRuntimeInterfaces.Length; interfaceIndex++) { var interfaceType = declTypeRuntimeInterfaces[interfaceIndex]; var interfaceDefinitionType = declTypeDefinitionRuntimeInterfaces[interfaceIndex]; Debug.Assert(interfaceType.IsInterface); IReadOnlyList <MethodDesc> virtualSlots = factory.VTable(interfaceType).Slots; for (int interfaceMethodSlot = 0; interfaceMethodSlot < virtualSlots.Count; interfaceMethodSlot++) { MethodDesc declMethod = virtualSlots[interfaceMethodSlot]; if (!interfaceType.IsTypeDefinition) { declMethod = factory.TypeSystemContext.GetMethodForInstantiatedType(declMethod.GetTypicalMethodDefinition(), (InstantiatedType)interfaceDefinitionType); } var implMethod = declMethod.Signature.IsStatic ? declTypeDefinition.ResolveInterfaceMethodToStaticVirtualMethodOnType(declMethod) : declTypeDefinition.ResolveInterfaceMethodToVirtualMethodOnType(declMethod); // Interface methods first implemented by a base type in the hierarchy will return null for the implMethod (runtime interface // dispatch will walk the inheritance chain). if (implMethod != null) { TypeDesc implType = declType; while (!implType.HasSameTypeDefinition(implMethod.OwningType)) { implType = implType.BaseType; } MethodDesc targetMethod = implMethod; if (!implType.IsTypeDefinition) { targetMethod = factory.TypeSystemContext.GetMethodForInstantiatedType(implMethod.GetTypicalMethodDefinition(), (InstantiatedType)implType); } int emittedInterfaceSlot = interfaceMethodSlot + (interfaceType.HasGenericDictionarySlot() ? 1 : 0); int emittedImplSlot = VirtualMethodSlotHelper.GetVirtualMethodSlot(factory, targetMethod, declType); if (targetMethod.Signature.IsStatic) { // If this is a static virtual, also remember whether we need generic context. // The implementation is not callable without the generic context. // Instance methods acquire the generic context from `this` and don't need it. // The pointer to the generic context is stored in the owning type's vtable. int genericContext = targetMethod.GetCanonMethodTarget(CanonicalFormKind.Specific).RequiresInstArg() ? StaticVirtualMethodContextSource.ContextFromThisClass : StaticVirtualMethodContextSource.None; staticImplementations.Add((interfaceIndex, emittedInterfaceSlot, emittedImplSlot, genericContext)); } else { builder.EmitShort((short)checked ((ushort)interfaceIndex)); builder.EmitShort((short)checked ((ushort)emittedInterfaceSlot)); builder.EmitShort((short)checked ((ushort)emittedImplSlot)); entryCount++; } } else { // Is there a default implementation? int?implSlot = null; DefaultInterfaceMethodResolution result = declTypeDefinition.ResolveInterfaceMethodToDefaultImplementationOnType(declMethod, out implMethod); DefType providingInterfaceDefinitionType = null; if (result == DefaultInterfaceMethodResolution.DefaultImplementation) { providingInterfaceDefinitionType = (DefType)implMethod.OwningType; implMethod = implMethod.InstantiateSignature(declType.Instantiation, Instantiation.Empty); implSlot = VirtualMethodSlotHelper.GetDefaultInterfaceMethodSlot(factory, implMethod, declType, providingInterfaceDefinitionType); } else if (result == DefaultInterfaceMethodResolution.Reabstraction) { implSlot = SpecialDispatchMapSlot.Reabstraction; } else if (result == DefaultInterfaceMethodResolution.Diamond) { implSlot = SpecialDispatchMapSlot.Diamond; } if (implSlot.HasValue) { int emittedInterfaceSlot = interfaceMethodSlot + (interfaceType.HasGenericDictionarySlot() ? 1 : 0); if (declMethod.Signature.IsStatic) { int genericContext = StaticVirtualMethodContextSource.None; if (result == DefaultInterfaceMethodResolution.DefaultImplementation && implMethod.GetCanonMethodTarget(CanonicalFormKind.Specific).RequiresInstArg()) { // If this is a static virtual, also remember whether we need generic context. // The implementation is not callable without the generic context. // Instance methods acquire the generic context from `this` and don't need it. // For default interface methods, the generic context is acquired by indexing // into the interface list of the owning type. Debug.Assert(providingInterfaceDefinitionType != null); int indexOfInterface = Array.IndexOf(declTypeDefinitionRuntimeInterfaces, providingInterfaceDefinitionType); Debug.Assert(indexOfInterface >= 0); genericContext = StaticVirtualMethodContextSource.ContextFromFirstInterface + indexOfInterface; } staticDefaultImplementations.Add(( interfaceIndex, emittedInterfaceSlot, implSlot.Value, genericContext)); } else { defaultImplementations.Add(( interfaceIndex, emittedInterfaceSlot, implSlot.Value)); } } } } } // Now emit the default implementations foreach (var defaultImplementation in defaultImplementations) { builder.EmitShort((short)checked ((ushort)defaultImplementation.InterfaceIndex)); builder.EmitShort((short)checked ((ushort)defaultImplementation.InterfaceMethodSlot)); builder.EmitShort((short)checked ((ushort)defaultImplementation.ImplMethodSlot)); } // Now emit the static implementations foreach (var staticImplementation in staticImplementations) { builder.EmitShort((short)checked ((ushort)staticImplementation.InterfaceIndex)); builder.EmitShort((short)checked ((ushort)staticImplementation.InterfaceMethodSlot)); builder.EmitShort((short)checked ((ushort)staticImplementation.ImplMethodSlot)); builder.EmitShort((short)checked ((ushort)staticImplementation.Context)); } // Now emit the static default implementations foreach (var staticImplementation in staticDefaultImplementations) { builder.EmitShort((short)checked ((ushort)staticImplementation.InterfaceIndex)); builder.EmitShort((short)checked ((ushort)staticImplementation.InterfaceMethodSlot)); builder.EmitShort((short)checked ((ushort)staticImplementation.ImplMethodSlot)); builder.EmitShort((short)checked ((ushort)staticImplementation.Context)); } // Update the header builder.EmitShort(entryCountReservation, (short)checked ((ushort)entryCount)); builder.EmitShort(defaultEntryCountReservation, (short)checked ((ushort)defaultImplementations.Count)); builder.EmitShort(staticEntryCountReservation, (short)checked ((ushort)staticImplementations.Count)); builder.EmitShort(defaultStaticEntryCountReservation, (short)checked ((ushort)staticDefaultImplementations.Count)); }
void EmitDispatchMap(ref ObjectDataBuilder builder, NodeFactory factory) { var entryCountReservation = builder.ReserveShort(); var defaultEntryCountReservation = builder.ReserveShort(); int entryCount = 0; TypeDesc declType = _type.GetClosestDefType(); TypeDesc declTypeDefinition = declType.GetTypeDefinition(); DefType[] declTypeRuntimeInterfaces = declType.RuntimeInterfaces; DefType[] declTypeDefinitionRuntimeInterfaces = declTypeDefinition.RuntimeInterfaces; // Catch any runtime interface collapsing. We shouldn't have any Debug.Assert(declTypeRuntimeInterfaces.Length == declTypeDefinitionRuntimeInterfaces.Length); var defaultImplementations = new List <(int InterfaceIndex, int InterfaceMethodSlot, int ImplMethodSlot)>(); // Resolve all the interfaces, but only emit non-default implementations for (int interfaceIndex = 0; interfaceIndex < declTypeRuntimeInterfaces.Length; interfaceIndex++) { var interfaceType = declTypeRuntimeInterfaces[interfaceIndex]; var interfaceDefinitionType = declTypeDefinitionRuntimeInterfaces[interfaceIndex]; Debug.Assert(interfaceType.IsInterface); IReadOnlyList <MethodDesc> virtualSlots = factory.VTable(interfaceType).Slots; for (int interfaceMethodSlot = 0; interfaceMethodSlot < virtualSlots.Count; interfaceMethodSlot++) { MethodDesc declMethod = virtualSlots[interfaceMethodSlot]; if (!interfaceType.IsTypeDefinition) { declMethod = factory.TypeSystemContext.GetMethodForInstantiatedType(declMethod.GetTypicalMethodDefinition(), (InstantiatedType)interfaceDefinitionType); } var implMethod = declTypeDefinition.ResolveInterfaceMethodToVirtualMethodOnType(declMethod); // Interface methods first implemented by a base type in the hierarchy will return null for the implMethod (runtime interface // dispatch will walk the inheritance chain). if (implMethod != null) { TypeDesc implType = declType; while (!implType.HasSameTypeDefinition(implMethod.OwningType)) { implType = implType.BaseType; } MethodDesc targetMethod = implMethod; if (!implType.IsTypeDefinition) { targetMethod = factory.TypeSystemContext.GetMethodForInstantiatedType(implMethod.GetTypicalMethodDefinition(), (InstantiatedType)implType); } builder.EmitShort((short)checked ((ushort)interfaceIndex)); builder.EmitShort((short)checked ((ushort)(interfaceMethodSlot + (interfaceType.HasGenericDictionarySlot() ? 1 : 0)))); builder.EmitShort((short)checked ((ushort)VirtualMethodSlotHelper.GetVirtualMethodSlot(factory, targetMethod, declType))); entryCount++; } else { // Is there a default implementation? int?implSlot = null; DefaultInterfaceMethodResolution result = declTypeDefinition.ResolveInterfaceMethodToDefaultImplementationOnType(declMethod, out implMethod); if (result == DefaultInterfaceMethodResolution.DefaultImplementation) { DefType providingInterfaceDefinitionType = (DefType)implMethod.OwningType; implMethod = implMethod.InstantiateSignature(declType.Instantiation, Instantiation.Empty); implSlot = VirtualMethodSlotHelper.GetDefaultInterfaceMethodSlot(factory, implMethod, declType, providingInterfaceDefinitionType); } else if (result == DefaultInterfaceMethodResolution.Reabstraction) { implSlot = SpecialDispatchMapSlot.Reabstraction; } else if (result == DefaultInterfaceMethodResolution.Diamond) { implSlot = SpecialDispatchMapSlot.Diamond; } if (implSlot.HasValue) { defaultImplementations.Add(( interfaceIndex, interfaceMethodSlot + (interfaceType.HasGenericDictionarySlot() ? 1 : 0), implSlot.Value)); } } } } // Now emit the default implementations foreach (var defaultImplementation in defaultImplementations) { builder.EmitShort((short)checked ((ushort)defaultImplementation.InterfaceIndex)); builder.EmitShort((short)checked ((ushort)defaultImplementation.InterfaceMethodSlot)); builder.EmitShort((short)checked ((ushort)defaultImplementation.ImplMethodSlot)); } // Update the header builder.EmitShort(entryCountReservation, (short)checked ((ushort)entryCount)); builder.EmitShort(defaultEntryCountReservation, (short)checked ((ushort)defaultImplementations.Count)); }
public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false) { ObjectDataBuilder builder = new ObjectDataBuilder(factory); builder.Alignment = factory.Target.PointerSize; builder.DefinedSymbols.Add(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 (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(); }