From d568bba4d9add5932c223b52ee710771fdea1331 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Strehovsk=C3=BD?= Date: Fri, 3 Nov 2023 14:15:45 +0100 Subject: [PATCH 1/2] Allow RyuJIT to refer to frozen RuntimeType instances MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With #93440 it became possible to place `RuntimeType` instances in the frozen region. This adds support for generating frozen `RuntimeType` instances within the compiler. We give these to RyuJIT whenever it asks for them. * New `FrozenObjectNode` descendant that represents a `RuntimeType` instance. We have two flavors - one wraps constructed and the other wraps necessary `MethodTable`s (we have a need for freezing both kinds to keep our ability to optimize `RuntimeTypes` used in comparisons only). * We hand out references to these whenever RyuJIT needs them. * At `MethodTable` emission time, we check whether a frozen `RuntimeType` for this `MethodTable` was generated. If so, we pre-populate `MethodTable`’s `WritableData` section with a reloc to the `RuntimeType`. Otherwise we use null as usual. * At runtime for `GetTypeFromEEType`, if `WritableData` is non-null, we just return that. Otherwise we create a pinned `RuntimeType` instance and write it into `WritableData`. In the future, we should allocate this on a frozen heap. Old codegen for `Console.WriteLine(typeof(Program))`: ```asm sub rsp,28h lea rcx,[repro_Program::`vftable' (07FF7D03154E0h)] call S_P_CoreLib_Internal_Runtime_CompilerHelpers_LdTokenHelpers__GetRuntimeType (07FF7D0253290h) mov rcx,rax call System_Console_System_Console__WriteLine_11 (07FF7D0262AC0h) nop add rsp,28h ret ``` New codegen: ```asm sub rsp,28h lea rcx,[__RuntimeType_repro_Program (07FF7A218EC50h)] call System_Console_System_Console__WriteLine_11 (07FF7A20F2680h) nop add rsp,28h ret ``` I’ll do cctor preinitialization in a subsequent PR to keep things short. Contributes to #91704. --- .../src/System/RuntimeType.cs | 8 +++ .../src/System/Type.NativeAot.cs | 36 +++++++----- .../ArrayOfFrozenObjectsNode.cs | 7 +-- .../DependencyAnalysis/CanonicalEETypeNode.cs | 3 + .../ConstructedEETypeNode.cs | 5 ++ .../Compiler/DependencyAnalysis/EETypeNode.cs | 50 ++++++++++++++-- .../FrozenRuntimeTypeNode.cs | 57 +++++++++++++++++++ .../NecessaryCanonicalEETypeNode.cs | 3 + .../DependencyAnalysis/NodeFactory.cs | 24 ++++++++ .../ILCompiler.Compiler.csproj | 1 + .../Compiler/RyuJitCompilation.cs | 10 ++++ .../JitInterface/CorInfoImpl.RyuJit.cs | 20 ++++--- 12 files changed, 190 insertions(+), 34 deletions(-) create mode 100644 src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/FrozenRuntimeTypeNode.cs diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/RuntimeType.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/RuntimeType.cs index 773253831403b..e9fca05ca8012 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/RuntimeType.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/RuntimeType.cs @@ -15,6 +15,8 @@ using Internal.Reflection.Core.Execution; using Internal.Runtime; +using Debug = System.Diagnostics.Debug; + namespace System { internal sealed unsafe class RuntimeType : TypeInfo, ICloneable @@ -33,6 +35,12 @@ internal RuntimeType(RuntimeTypeInfo runtimeTypeInfo) _runtimeTypeInfoHandle = RuntimeImports.RhHandleAlloc(runtimeTypeInfo, GCHandleType.Normal); } + internal void DangerousSetUnderlyingEEType(MethodTable* pEEType) + { + Debug.Assert(_pUnderlyingEEType == null); + _pUnderlyingEEType = pEEType; + } + internal void Free() { RuntimeImports.RhHandleFree(_runtimeTypeInfoHandle); diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Type.NativeAot.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Type.NativeAot.cs index 819aa5609cf07..8c637957be4e7 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Type.NativeAot.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Type.NativeAot.cs @@ -4,6 +4,7 @@ using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Reflection; +using System.Runtime; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; @@ -30,15 +31,8 @@ internal static unsafe RuntimeType GetTypeFromMethodTable(MethodTable* pMT) // unifier's hash table. if (MethodTable.SupportsWritableData) { - ref UnsafeGCHandle handle = ref Unsafe.AsRef(pMT->WritableData); - if (handle.IsAllocated) - { - return Unsafe.As(handle.Target); - } - else - { - return GetTypeFromMethodTableSlow(pMT, ref handle); - } + ref RuntimeType? type = ref Unsafe.AsRef(pMT->WritableData); + return type ?? GetTypeFromMethodTableSlow(pMT, ref type); } else { @@ -47,17 +41,29 @@ internal static unsafe RuntimeType GetTypeFromMethodTable(MethodTable* pMT) } [MethodImpl(MethodImplOptions.NoInlining)] - private static unsafe RuntimeType GetTypeFromMethodTableSlow(MethodTable* pMT, ref UnsafeGCHandle handle) + private static unsafe RuntimeType GetTypeFromMethodTableSlow(MethodTable* pMT, ref RuntimeType? runtimeTypeCache) { - UnsafeGCHandle tempHandle = UnsafeGCHandle.Alloc(new RuntimeType(pMT)); + // TODO: instead of fragmenting the frozen object heap, we should have our own allocator + // for objects that live forever outside the GC heap. + + RuntimeType? type = null; + RuntimeImports.RhAllocateNewObject( + (IntPtr)MethodTable.Of(), + (uint)GC_ALLOC_FLAGS.GC_ALLOC_PINNED_OBJECT_HEAP, + Unsafe.AsPointer(ref type)); + + if (type == null) + throw new OutOfMemoryException(); + + type.DangerousSetUnderlyingEEType(pMT); - // We don't want to leak a handle if there's a race - if (Interlocked.CompareExchange(ref Unsafe.As(ref handle), Unsafe.As(ref tempHandle), default) != default) + if (Interlocked.CompareExchange(ref runtimeTypeCache, type, null) == null) { - tempHandle.Free(); + // Create and leak a GC handle + UnsafeGCHandle.Alloc(type); } - return Unsafe.As(handle.Target); + return runtimeTypeCache; } // diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/ArrayOfFrozenObjectsNode.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/ArrayOfFrozenObjectsNode.cs index e6ca20b6507d2..bb77597f53f07 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/ArrayOfFrozenObjectsNode.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/ArrayOfFrozenObjectsNode.cs @@ -31,7 +31,7 @@ protected override ObjectData GetDehydratableData(NodeFactory factory, bool relo var builder = new ObjectDataBuilder(factory, relocsOnly); builder.AddSymbol(this); - foreach (EmbeddedObjectNode node in factory.MetadataManager.GetFrozenObjects()) + foreach (FrozenObjectNode node in factory.MetadataManager.GetFrozenObjects()) { AlignNextObject(ref builder, factory); @@ -46,10 +46,7 @@ protected override ObjectData GetDehydratableData(NodeFactory factory, bool relo builder.EmitZeros(minimumObjectSize - objectSize); } - if (node is ISymbolDefinitionNode) - { - builder.AddSymbol((ISymbolDefinitionNode)node); - } + builder.AddSymbol(node); } // Terminate with a null pointer as expected by the GC diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/CanonicalEETypeNode.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/CanonicalEETypeNode.cs index 2af56d7fb163d..86aa561fd8baa 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/CanonicalEETypeNode.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/CanonicalEETypeNode.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System; using System.Diagnostics; using Internal.TypeSystem; @@ -63,6 +64,8 @@ protected override ISymbolNode GetBaseTypeNode(NodeFactory factory) return _type.BaseType != null ? factory.NecessaryTypeSymbol(_type.BaseType.NormalizeInstantiation()) : null; } + protected override FrozenRuntimeTypeNode GetFrozenRuntimeTypeNode(NodeFactory factory) => throw new NotSupportedException(); + protected override ISymbolNode GetNonNullableValueTypeArrayElementTypeNode(NodeFactory factory) { return factory.ConstructedTypeSymbol(((ArrayType)_type).ElementType); diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/ConstructedEETypeNode.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/ConstructedEETypeNode.cs index 0d3f97754c8d8..2f623bf740554 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/ConstructedEETypeNode.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/ConstructedEETypeNode.cs @@ -76,6 +76,11 @@ protected override ISymbolNode GetBaseTypeNode(NodeFactory factory) return _type.BaseType != null ? factory.ConstructedTypeSymbol(_type.BaseType) : null; } + protected override FrozenRuntimeTypeNode GetFrozenRuntimeTypeNode(NodeFactory factory) + { + return factory.SerializedConstructedRuntimeTypeObject(_type); + } + protected override ISymbolNode GetNonNullableValueTypeArrayElementTypeNode(NodeFactory factory) { return factory.ConstructedTypeSymbol(((ArrayType)_type).ElementType); diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/EETypeNode.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/EETypeNode.cs index beb16cf020085..ffdec3f84eaaa 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/EETypeNode.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/EETypeNode.cs @@ -94,7 +94,7 @@ public EETypeNode(NodeFactory factory, TypeDesc type) Debug.Assert(!type.IsRuntimeDeterminedSubtype); _type = type; _optionalFieldsNode = new EETypeOptionalFieldsNode(this); - _writableDataNode = factory.Target.SupportsRelativePointers ? new WritableDataNode(this) : null; + _writableDataNode = SupportsWritableData(factory.Target) && !_type.IsCanonicalSubtype(CanonicalFormKind.Any) ? new WritableDataNode(this) : null; _hasConditionalDependenciesFromMetadataManager = factory.MetadataManager.HasConditionalDependenciesDueToEETypePresence(type); if (EmitVirtualSlotsAndInterfaces) @@ -103,6 +103,12 @@ public EETypeNode(NodeFactory factory, TypeDesc type) factory.TypeSystemContext.EnsureLoadableType(type); } + public static bool SupportsWritableData(TargetDetails target) + => target.SupportsRelativePointers; + + public static bool SupportsFrozenRuntimeTypeInstances(TargetDetails target) + => SupportsWritableData(target); + private static VirtualMethodAnalysisFlags AnalyzeVirtualMethods(TypeDesc type) { var result = VirtualMethodAnalysisFlags.None; @@ -878,6 +884,11 @@ protected virtual ISymbolNode GetBaseTypeNode(NodeFactory factory) return _type.BaseType != null ? factory.NecessaryTypeSymbol(_type.BaseType) : null; } + protected virtual FrozenRuntimeTypeNode GetFrozenRuntimeTypeNode(NodeFactory factory) + { + return factory.SerializedNecessaryRuntimeTypeObject(_type); + } + protected virtual ISymbolNode GetNonNullableValueTypeArrayElementTypeNode(NodeFactory factory) { return factory.NecessaryTypeSymbol(((ArrayType)_type).ElementType); @@ -1116,6 +1127,10 @@ protected void OutputWritableData(NodeFactory factory, ref ObjectDataBuilder obj { objData.EmitReloc(_writableDataNode, RelocType.IMAGE_REL_BASED_RELPTR32); } + else if (SupportsWritableData(factory.Target)) + { + objData.EmitInt(0); + } } protected void OutputOptionalFields(NodeFactory factory, ref ObjectDataBuilder objData) @@ -1407,7 +1422,11 @@ private sealed class WritableDataNode : ObjectNode, ISymbolDefinitionNode private readonly EETypeNode _type; public WritableDataNode(EETypeNode type) => _type = type; - public override ObjectNodeSection GetSection(NodeFactory factory) => ObjectNodeSection.BssSection; + public override ObjectNodeSection GetSection(NodeFactory factory) + => SupportsFrozenRuntimeTypeInstances(factory.Target) && _type.GetFrozenRuntimeTypeNode(factory).Marked + ? (factory.Target.IsWindows ? ObjectNodeSection.ReadOnlyDataSection : ObjectNodeSection.DataSection) + : ObjectNodeSection.BssSection; + public override bool StaticDependenciesAreComputed => true; public void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb) => sb.Append("__writableData").Append(nameMangler.GetMangledTypeName(_type.Type)); @@ -1416,10 +1435,29 @@ public void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb) public override bool ShouldSkipEmittingObjectNode(NodeFactory factory) => _type.ShouldSkipEmittingObjectNode(factory); public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false) - => new ObjectData(new byte[WritableData.GetSize(factory.Target.PointerSize)], - Array.Empty(), - WritableData.GetAlignment(factory.Target.PointerSize), - new ISymbolDefinitionNode[] { this }); + { + ObjectDataBuilder builder = new ObjectDataBuilder(factory, relocsOnly); + + builder.RequireInitialAlignment(WritableData.GetAlignment(factory.Target.PointerSize)); + builder.AddSymbol(this); + + // If the whole program view contains a reference to a preallocated RuntimeType + // instance for this type, generate a reference to it. + // Otherwise, generate as zero to save size. + if (SupportsFrozenRuntimeTypeInstances(factory.Target) + && _type.GetFrozenRuntimeTypeNode(factory) is { Marked: true } runtimeTypeObject) + { + builder.EmitPointerReloc(runtimeTypeObject); + } + else + { + builder.EmitZeroPointer(); + } + + Debug.Assert(builder.CountBytes == WritableData.GetSize(factory.Target.PointerSize)); + + return builder.ToObjectData(); + } protected override string GetName(NodeFactory factory) => this.GetMangledName(factory.NameMangler); diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/FrozenRuntimeTypeNode.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/FrozenRuntimeTypeNode.cs new file mode 100644 index 0000000000000..14c5596840b67 --- /dev/null +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/FrozenRuntimeTypeNode.cs @@ -0,0 +1,57 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Internal.IL; +using Internal.Text; +using Internal.TypeSystem; + +using Debug = System.Diagnostics.Debug; + +namespace ILCompiler.DependencyAnalysis +{ + public sealed class FrozenRuntimeTypeNode : FrozenObjectNode + { + private readonly TypeDesc _type; + private readonly bool _constructed; + + public FrozenRuntimeTypeNode(TypeDesc type, bool constructed) + { + Debug.Assert(EETypeNode.SupportsFrozenRuntimeTypeInstances(type.Context.Target)); + _type = type; + _constructed = constructed; + } + + public override void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb) + { + sb.Append(nameMangler.CompilationUnitPrefix).Append("__RuntimeType_").Append(nameMangler.GetMangledTypeName(_type)); + } + + protected override int ContentSize => ObjectType.InstanceByteCount.AsInt; + + public override void EncodeContents(ref ObjectDataBuilder dataBuilder, NodeFactory factory, bool relocsOnly) + { + IEETypeNode typeSymbol = _constructed + ? factory.ConstructedTypeSymbol(_type) + : factory.NecessaryTypeSymbol(_type); + + dataBuilder.EmitPointerReloc(factory.ConstructedTypeSymbol(ObjectType)); + dataBuilder.EmitPointerReloc(typeSymbol); // RuntimeType::_pUnderlyingEEType + dataBuilder.EmitZeroPointer(); // RuntimeType::_runtimeTypeInfoHandle + } + + protected override string GetName(NodeFactory factory) => this.GetMangledName(factory.NameMangler); + + public override int ClassCode => 726422757; + + public override int CompareToImpl(ISortableNode other, CompilerComparer comparer) + { + return comparer.Compare(_type, ((FrozenRuntimeTypeNode)other)._type); + } + + public override int? ArrayLength => null; + + public override bool IsKnownImmutable => false; + + public override DefType ObjectType => _type.Context.SystemModule.GetKnownType("System", "RuntimeType"); + } +} diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/NecessaryCanonicalEETypeNode.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/NecessaryCanonicalEETypeNode.cs index d7d6671f0df9f..3695e9c794be2 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/NecessaryCanonicalEETypeNode.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/NecessaryCanonicalEETypeNode.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System; using System.Diagnostics; using Internal.TypeSystem; @@ -25,6 +26,8 @@ protected override ISymbolNode GetBaseTypeNode(NodeFactory factory) return _type.BaseType != null ? factory.NecessaryTypeSymbol(_type.BaseType.NormalizeInstantiation()) : null; } + protected override FrozenRuntimeTypeNode GetFrozenRuntimeTypeNode(NodeFactory factory) => throw new NotSupportedException(); + public override int ClassCode => 1505000724; } } diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/NodeFactory.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/NodeFactory.cs index 0400ba0b77a8a..f2d0736abb2d0 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/NodeFactory.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/NodeFactory.cs @@ -368,6 +368,16 @@ private void CreateNodeCaches() return new SerializedFrozenObjectNode(key.OwnerType, key.AllocationSiteId, key.SerializableObject); }); + _frozenConstructedRuntimeTypeNodes = new NodeCache(key => + { + return new FrozenRuntimeTypeNode(key, constructed: true); + }); + + _frozenNecessaryRuntimeTypeNodes = new NodeCache(key => + { + return new FrozenRuntimeTypeNode(key, constructed: false); + }); + _interfaceDispatchCells = new NodeCache(callSiteCell => { return new InterfaceDispatchCellNode(callSiteCell.Target, callSiteCell.CallsiteId); @@ -1227,6 +1237,20 @@ public SerializedFrozenObjectNode SerializedFrozenObject(MetadataType owningType return _frozenObjectNodes.GetOrAdd(new SerializedFrozenObjectKey(owningType, allocationSiteId, data)); } + private NodeCache _frozenConstructedRuntimeTypeNodes; + + public FrozenRuntimeTypeNode SerializedConstructedRuntimeTypeObject(TypeDesc type) + { + return _frozenConstructedRuntimeTypeNodes.GetOrAdd(type); + } + + private NodeCache _frozenNecessaryRuntimeTypeNodes; + + public FrozenRuntimeTypeNode SerializedNecessaryRuntimeTypeObject(TypeDesc type) + { + return _frozenNecessaryRuntimeTypeNodes.GetOrAdd(type); + } + private NodeCache _eagerCctorIndirectionNodes; public EmbeddedObjectNode EagerCctorIndirection(MethodDesc cctorMethod) diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/ILCompiler.Compiler.csproj b/src/coreclr/tools/aot/ILCompiler.Compiler/ILCompiler.Compiler.csproj index 65a5887d439db..804427d276c34 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/ILCompiler.Compiler.csproj +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/ILCompiler.Compiler.csproj @@ -412,6 +412,7 @@ + diff --git a/src/coreclr/tools/aot/ILCompiler.RyuJit/Compiler/RyuJitCompilation.cs b/src/coreclr/tools/aot/ILCompiler.RyuJit/Compiler/RyuJitCompilation.cs index efb047737c0b0..29e7bce780467 100644 --- a/src/coreclr/tools/aot/ILCompiler.RyuJit/Compiler/RyuJitCompilation.cs +++ b/src/coreclr/tools/aot/ILCompiler.RyuJit/Compiler/RyuJitCompilation.cs @@ -79,6 +79,16 @@ public override IEETypeNode NecessaryTypeSymbolIfPossible(TypeDesc type) return _nodeFactory.NecessaryTypeSymbol(type); } + public FrozenRuntimeTypeNode NecessaryRuntimeTypeIfPossible(TypeDesc type) + { + bool canPotentiallyConstruct = _devirtualizationManager == null + ? true : _devirtualizationManager.CanConstructType(type); + if (canPotentiallyConstruct && ConstructedEETypeNode.CreationAllowed(type)) + return _nodeFactory.SerializedConstructedRuntimeTypeObject(type); + + return _nodeFactory.SerializedNecessaryRuntimeTypeObject(type); + } + protected override void CompileInternal(string outputFile, ObjectDumper dumper) { _dependencyGraph.ComputeMarkedNodes(); diff --git a/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs b/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs index e86b3502942f0..460dbb744d934 100644 --- a/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs +++ b/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs @@ -44,6 +44,9 @@ public CorInfoImpl(RyuJitCompilation compilation) _compilation = compilation; } + private FrozenObjectNode HandleToObject(CORINFO_OBJECT_STRUCT_* obj) => (FrozenObjectNode)HandleToObject((void*)obj); + private CORINFO_OBJECT_STRUCT_* ObjectToHandle(FrozenObjectNode obj) => (CORINFO_OBJECT_STRUCT_*)ObjectToHandle((object)obj); + private UnboxingMethodDesc getUnboxingThunk(MethodDesc method) { return _unboxingThunkFactory.GetUnboxingMethod(method); @@ -2298,7 +2301,7 @@ private bool getObjectContent(CORINFO_OBJECT_STRUCT_* objPtr, byte* buffer, int Debug.Assert(bufferSize >= 0); Debug.Assert(valueOffset >= 0); - object obj = HandleToObject(objPtr); + FrozenObjectNode obj = HandleToObject(objPtr); if (obj is FrozenStringNode frozenStr) { // Only support reading the string data @@ -2320,20 +2323,21 @@ private bool getObjectContent(CORINFO_OBJECT_STRUCT_* objPtr, byte* buffer, int private CORINFO_CLASS_STRUCT_* getObjectType(CORINFO_OBJECT_STRUCT_* objPtr) { - return ObjectToHandle(((FrozenObjectNode)HandleToObject(objPtr)).ObjectType); + return ObjectToHandle(HandleToObject(objPtr).ObjectType); } -#pragma warning disable CA1822 // Mark members as static private CORINFO_OBJECT_STRUCT_* getRuntimeTypePointer(CORINFO_CLASS_STRUCT_* cls) -#pragma warning restore CA1822 // Mark members as static { - // TODO: https://github.com/dotnet/runtime/pull/75573#issuecomment-1250824543 - return null; + if (!EETypeNode.SupportsFrozenRuntimeTypeInstances(_compilation.NodeFactory.Target)) + return null; + + TypeDesc type = HandleToObject(cls); + return ObjectToHandle(_compilation.NecessaryRuntimeTypeIfPossible(type)); } private bool isObjectImmutable(CORINFO_OBJECT_STRUCT_* objPtr) { - return ((FrozenObjectNode)HandleToObject(objPtr)).IsKnownImmutable; + return HandleToObject(objPtr).IsKnownImmutable; } private bool getStringChar(CORINFO_OBJECT_STRUCT_* strObj, int index, ushort* value) @@ -2348,7 +2352,7 @@ private bool getStringChar(CORINFO_OBJECT_STRUCT_* strObj, int index, ushort* va private int getArrayOrStringLength(CORINFO_OBJECT_STRUCT_* objHnd) { - return ((FrozenObjectNode)HandleToObject(objHnd)).ArrayLength ?? -1; + return HandleToObject(objHnd).ArrayLength ?? -1; } private bool getIsClassInitedFlagAddress(CORINFO_CLASS_STRUCT_* cls, ref CORINFO_CONST_LOOKUP addr, ref int offset) From 1ba9f32cbbc07b0442f280a23ba4a4d45be5d72c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Strehovsk=C3=BD?= Date: Mon, 6 Nov 2023 08:13:15 +0100 Subject: [PATCH 2/2] FB --- .../System.Private.CoreLib/src/System/EETypePtr.cs | 6 ------ .../System.Private.CoreLib/src/System/Type.NativeAot.cs | 5 +++-- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/EETypePtr.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/EETypePtr.cs index ab2e132816105..28d30d0e4eaed 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/EETypePtr.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/EETypePtr.cs @@ -405,12 +405,6 @@ internal RuntimeImports.RhCorElementTypeInfo CorElementTypeInfo } } - internal ref T GetWritableData() where T : unmanaged - { - Debug.Assert(Internal.Runtime.WritableData.GetSize(IntPtr.Size) == sizeof(T)); - return ref Unsafe.AsRef((void*)_value->WritableData); - } - [Intrinsic] [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static EETypePtr EETypePtrOf() diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Type.NativeAot.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Type.NativeAot.cs index 8c637957be4e7..0a9cd70dd643e 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Type.NativeAot.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Type.NativeAot.cs @@ -32,7 +32,7 @@ internal static unsafe RuntimeType GetTypeFromMethodTable(MethodTable* pMT) if (MethodTable.SupportsWritableData) { ref RuntimeType? type = ref Unsafe.AsRef(pMT->WritableData); - return type ?? GetTypeFromMethodTableSlow(pMT, ref type); + return type ?? GetTypeFromMethodTableSlow(pMT); } else { @@ -41,7 +41,7 @@ internal static unsafe RuntimeType GetTypeFromMethodTable(MethodTable* pMT) } [MethodImpl(MethodImplOptions.NoInlining)] - private static unsafe RuntimeType GetTypeFromMethodTableSlow(MethodTable* pMT, ref RuntimeType? runtimeTypeCache) + private static unsafe RuntimeType GetTypeFromMethodTableSlow(MethodTable* pMT) { // TODO: instead of fragmenting the frozen object heap, we should have our own allocator // for objects that live forever outside the GC heap. @@ -57,6 +57,7 @@ private static unsafe RuntimeType GetTypeFromMethodTableSlow(MethodTable* pMT, r type.DangerousSetUnderlyingEEType(pMT); + ref RuntimeType? runtimeTypeCache = ref Unsafe.AsRef(pMT->WritableData); if (Interlocked.CompareExchange(ref runtimeTypeCache, type, null) == null) { // Create and leak a GC handle