diff --git a/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncHelpers.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncHelpers.CoreCLR.cs
index 600a6722f0645d..5ccc9a8d2f9dd6 100644
--- a/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncHelpers.CoreCLR.cs
+++ b/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncHelpers.CoreCLR.cs
@@ -12,6 +12,10 @@
using System.Threading;
using System.Threading.Tasks;
+#if NATIVEAOT
+using Internal.Runtime;
+#endif
+
namespace System.Runtime.CompilerServices
{
internal struct ExecutionAndSyncBlockStore
@@ -160,11 +164,16 @@ private struct RuntimeAsyncAwaitState
private static unsafe Continuation AllocContinuation(Continuation prevContinuation, MethodTable* contMT)
{
+#if NATIVEAOT
+ Continuation newContinuation = (Continuation)RuntimeImports.RhNewObject(contMT);
+#else
Continuation newContinuation = (Continuation)RuntimeTypeHandle.InternalAllocNoChecks(contMT);
+#endif
prevContinuation.Next = newContinuation;
return newContinuation;
}
+#if !NATIVEAOT
private static unsafe Continuation AllocContinuationMethod(Continuation prevContinuation, MethodTable* contMT, int keepAliveOffset, MethodDesc* method)
{
LoaderAllocator loaderAllocator = RuntimeMethodHandle.GetLoaderAllocator(new RuntimeMethodHandleInternal((IntPtr)method));
@@ -186,6 +195,7 @@ private static unsafe Continuation AllocContinuationClass(Continuation prevConti
}
return newContinuation;
}
+#endif
[BypassReadyToRun]
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.Async)]
diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj b/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj
index 2f46b37643aaf0..01e53975c4819b 100644
--- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj
+++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj
@@ -55,6 +55,10 @@
ExceptionStringID.cs
+
+
+
+
diff --git a/src/coreclr/tools/Common/Compiler/AsyncContinuationType.cs b/src/coreclr/tools/Common/Compiler/AsyncContinuationType.cs
new file mode 100644
index 00000000000000..7c65f73d8cbea2
--- /dev/null
+++ b/src/coreclr/tools/Common/Compiler/AsyncContinuationType.cs
@@ -0,0 +1,85 @@
+// 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.Collections.Generic;
+using System.Diagnostics;
+using System.Text;
+
+using Internal.TypeSystem;
+
+namespace ILCompiler
+{
+ ///
+ /// An async continuation type. The code generator will request this to store local state
+ /// through an async suspension/resumption. We only identify these using a
+ /// since that's all the code generator cares about - size of the type, and where the GC pointers are.
+ ///
+ public sealed partial class AsyncContinuationType : MetadataType
+ {
+ private readonly MetadataType _continuationBaseType;
+ public GCPointerMap PointerMap { get; }
+
+ public override DefType[] ExplicitlyImplementedInterfaces => [];
+ public override ReadOnlySpan Name => Encoding.UTF8.GetBytes(DiagnosticName);
+ public override ReadOnlySpan Namespace => [];
+
+ // We don't lay these out using MetadataType metadata.
+ // Autolayout (which we'd get due to GC pointers) would likely not match what codegen expects.
+ public override bool IsExplicitLayout => throw new NotImplementedException();
+ public override bool IsSequentialLayout => throw new NotImplementedException();
+ public override bool IsExtendedLayout => throw new NotImplementedException();
+ public override bool IsAutoLayout => throw new NotImplementedException();
+ public override ClassLayoutMetadata GetClassLayout() => throw new NotImplementedException();
+
+ public override bool IsBeforeFieldInit => false;
+ public override ModuleDesc Module => _continuationBaseType.Module;
+ public override MetadataType BaseType => _continuationBaseType;
+ public override bool IsSealed => true;
+ public override bool IsAbstract => false;
+ public override MetadataType ContainingType => null;
+ public override PInvokeStringFormat PInvokeStringFormat => default;
+ public override string DiagnosticName => $"ContinuationType_{PointerMap}";
+ public override string DiagnosticNamespace => "";
+ protected override int ClassCode => 0x528741a;
+ public override TypeSystemContext Context => _continuationBaseType.Context;
+
+ public AsyncContinuationType(MetadataType continuationBaseType, GCPointerMap pointerMap)
+ => (_continuationBaseType, PointerMap) = (continuationBaseType, pointerMap);
+
+ public override bool HasCustomAttribute(string attributeNamespace, string attributeName) => false;
+ public override IEnumerable GetNestedTypes() => [];
+ public override MetadataType GetNestedType(string name) => null;
+ protected override MethodImplRecord[] ComputeVirtualMethodImplsForType() => [];
+ public override MethodImplRecord[] FindMethodsImplWithMatchingDeclName(ReadOnlySpan name) => [];
+
+ protected override int CompareToImpl(TypeDesc other, TypeSystemComparer comparer)
+ {
+ Debug.Assert(_continuationBaseType == ((AsyncContinuationType)other)._continuationBaseType);
+ GCPointerMap otherPointerMap = ((AsyncContinuationType)other).PointerMap;
+ return PointerMap.CompareTo(otherPointerMap);
+ }
+
+ public override int GetHashCode() => PointerMap.GetHashCode();
+
+ protected override TypeFlags ComputeTypeFlags(TypeFlags mask)
+ {
+ TypeFlags flags = 0;
+
+ if ((mask & TypeFlags.HasGenericVarianceComputed) != 0)
+ {
+ flags |= TypeFlags.HasGenericVarianceComputed;
+ }
+
+ if ((mask & TypeFlags.CategoryMask) != 0)
+ {
+ flags |= TypeFlags.Class;
+ }
+
+ flags |= TypeFlags.HasFinalizerComputed;
+ flags |= TypeFlags.AttributeCacheComputed;
+
+ return flags;
+ }
+ }
+}
diff --git a/src/coreclr/tools/Common/Compiler/CompilerTypeSystemContext.Async.cs b/src/coreclr/tools/Common/Compiler/CompilerTypeSystemContext.Async.cs
index ba594e7f474ea7..0087ef7373a819 100644
--- a/src/coreclr/tools/Common/Compiler/CompilerTypeSystemContext.Async.cs
+++ b/src/coreclr/tools/Common/Compiler/CompilerTypeSystemContext.Async.cs
@@ -15,7 +15,7 @@ public MethodDesc GetAsyncVariantMethod(MethodDesc taskReturningMethod)
{
Debug.Assert(taskReturningMethod.Signature.ReturnsTaskOrValueTask());
MethodDesc asyncMetadataMethodDef = taskReturningMethod.GetTypicalMethodDefinition();
- MethodDesc result = _asyncVariantImplHashtable.GetOrCreateValue((EcmaMethod)asyncMetadataMethodDef);
+ MethodDesc result = _asyncVariantHashtable.GetOrCreateValue((EcmaMethod)asyncMetadataMethodDef);
if (asyncMetadataMethodDef != taskReturningMethod)
{
@@ -30,7 +30,7 @@ public MethodDesc GetAsyncVariantMethod(MethodDesc taskReturningMethod)
return result;
}
- private sealed class AsyncVariantImplHashtable : LockFreeReaderHashtable
+ private sealed class AsyncVariantHashtable : LockFreeReaderHashtable
{
protected override int GetKeyHashCode(EcmaMethod key) => key.GetHashCode();
protected override int GetValueHashCode(AsyncMethodVariant value) => value.Target.GetHashCode();
@@ -39,6 +39,32 @@ protected override bool CompareValueToValue(AsyncMethodVariant value1, AsyncMeth
=> value1.Target == value2.Target;
protected override AsyncMethodVariant CreateValueFromKey(EcmaMethod key) => new AsyncMethodVariant(key);
}
- private AsyncVariantImplHashtable _asyncVariantImplHashtable = new AsyncVariantImplHashtable();
+ private AsyncVariantHashtable _asyncVariantHashtable = new AsyncVariantHashtable();
+
+ public MetadataType GetContinuationType(GCPointerMap pointerMap)
+ {
+ return _continuationTypeHashtable.GetOrCreateValue(pointerMap);
+ }
+
+ private sealed class ContinuationTypeHashtable : LockFreeReaderHashtable
+ {
+ private readonly CompilerTypeSystemContext _parent;
+ private MetadataType _continuationType;
+
+ public ContinuationTypeHashtable(CompilerTypeSystemContext parent)
+ => _parent = parent;
+
+ protected override int GetKeyHashCode(GCPointerMap key) => key.GetHashCode();
+ protected override int GetValueHashCode(AsyncContinuationType value) => value.PointerMap.GetHashCode();
+ protected override bool CompareKeyToValue(GCPointerMap key, AsyncContinuationType value) => key.Equals(value.PointerMap);
+ protected override bool CompareValueToValue(AsyncContinuationType value1, AsyncContinuationType value2)
+ => value1.PointerMap.Equals(value2.PointerMap);
+ protected override AsyncContinuationType CreateValueFromKey(GCPointerMap key)
+ {
+ _continuationType ??= _parent.SystemModule.GetKnownType("System.Runtime.CompilerServices"u8, "Continuation"u8);
+ return new AsyncContinuationType(_continuationType, key);
+ }
+ }
+ private ContinuationTypeHashtable _continuationTypeHashtable;
}
}
diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
index 3bc5a00ce08d49..a3ca8706f9d1fe 100644
--- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
+++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
@@ -685,6 +685,7 @@ private void CompileMethodCleanup()
#if !READYTORUN
_debugInfo = null;
+ _asyncResumptionStub = null;
#endif
_debugLocInfos = null;
@@ -3401,7 +3402,19 @@ private void getAsyncInfo(ref CORINFO_ASYNC_INFO pAsyncInfoOut)
private CORINFO_CLASS_STRUCT_* getContinuationType(nuint dataSize, ref bool objRefs, nuint objRefsSize)
{
Debug.Assert(objRefsSize == (dataSize + (nuint)(PointerSize - 1)) / (nuint)PointerSize);
+#if READYTORUN
throw new NotImplementedException("getContinuationType");
+#else
+ GCPointerMapBuilder gcMapBuilder = new GCPointerMapBuilder((int)dataSize, PointerSize);
+ ReadOnlySpan bools = MemoryMarshal.CreateReadOnlySpan(ref objRefs, (int)objRefsSize);
+ for (int i = 0; i < bools.Length; i++)
+ {
+ if (bools[i])
+ gcMapBuilder.MarkGCPointer(i * PointerSize);
+ }
+
+ return ObjectToHandle(_compilation.TypeSystemContext.GetContinuationType(gcMapBuilder.ToGCMap()));
+#endif
}
private mdToken getMethodDefFromMethod(CORINFO_METHOD_STRUCT_* hMethod)
@@ -3756,7 +3769,14 @@ private bool getTailCallHelpers(ref CORINFO_RESOLVED_TOKEN callToken, CORINFO_SI
private CORINFO_METHOD_STRUCT_* getAsyncResumptionStub(ref void* entryPoint)
#pragma warning restore CA1822 // Mark members as static
{
+#if READYTORUN
throw new NotImplementedException("Crossgen2 does not support runtime-async yet");
+#else
+ _asyncResumptionStub ??= new AsyncResumptionStub(MethodBeingCompiled);
+
+ entryPoint = (void*)ObjectToHandle(_compilation.NodeFactory.MethodEntrypoint(_asyncResumptionStub));
+ return ObjectToHandle(_asyncResumptionStub);
+#endif
}
private byte[] _code;
diff --git a/src/coreclr/tools/Common/TypeSystem/IL/Stubs/AsyncResumptionStub.Mangling.cs b/src/coreclr/tools/Common/TypeSystem/IL/Stubs/AsyncResumptionStub.Mangling.cs
new file mode 100644
index 00000000000000..898a483159ae21
--- /dev/null
+++ b/src/coreclr/tools/Common/TypeSystem/IL/Stubs/AsyncResumptionStub.Mangling.cs
@@ -0,0 +1,15 @@
+// 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.Stubs;
+using Internal.TypeSystem;
+
+namespace ILCompiler
+{
+ public partial class AsyncResumptionStub : ILStubMethod, IPrefixMangledMethod
+ {
+ MethodDesc IPrefixMangledMethod.BaseMethod => _owningMethod;
+
+ string IPrefixMangledMethod.Prefix => "Resume";
+ }
+}
diff --git a/src/coreclr/tools/Common/TypeSystem/IL/Stubs/AsyncResumptionStub.Sorting.cs b/src/coreclr/tools/Common/TypeSystem/IL/Stubs/AsyncResumptionStub.Sorting.cs
new file mode 100644
index 00000000000000..2043c2f8922535
--- /dev/null
+++ b/src/coreclr/tools/Common/TypeSystem/IL/Stubs/AsyncResumptionStub.Sorting.cs
@@ -0,0 +1,18 @@
+// 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.Stubs;
+using Internal.TypeSystem;
+
+namespace ILCompiler
+{
+ public partial class AsyncResumptionStub : ILStubMethod
+ {
+ protected override int ClassCode => 0x773ab1;
+
+ protected override int CompareToImpl(MethodDesc other, TypeSystemComparer comparer)
+ {
+ return comparer.Compare(_owningMethod, ((AsyncResumptionStub)other)._owningMethod);
+ }
+ }
+}
diff --git a/src/coreclr/tools/Common/TypeSystem/IL/Stubs/AsyncResumptionStub.cs b/src/coreclr/tools/Common/TypeSystem/IL/Stubs/AsyncResumptionStub.cs
new file mode 100644
index 00000000000000..29504bb6834fcf
--- /dev/null
+++ b/src/coreclr/tools/Common/TypeSystem/IL/Stubs/AsyncResumptionStub.cs
@@ -0,0 +1,53 @@
+// 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 Internal.IL;
+using Internal.IL.Stubs;
+using Internal.TypeSystem;
+
+using Debug = System.Diagnostics.Debug;
+
+namespace ILCompiler
+{
+ public partial class AsyncResumptionStub : ILStubMethod
+ {
+ private readonly MethodDesc _owningMethod;
+ private MethodSignature _signature;
+
+ public AsyncResumptionStub(MethodDesc owningMethod)
+ {
+ Debug.Assert(owningMethod.IsAsyncVariant()
+ || (owningMethod.IsAsync && !owningMethod.Signature.ReturnsTaskOrValueTask()));
+ _owningMethod = owningMethod;
+ }
+
+ public override ReadOnlySpan Name => _owningMethod.Name;
+ public override string DiagnosticName => _owningMethod.DiagnosticName;
+
+ public override TypeDesc OwningType => _owningMethod.OwningType;
+
+ public override MethodSignature Signature => _signature ??= InitializeSignature();
+
+ public override TypeSystemContext Context => _owningMethod.Context;
+
+ private MethodSignature InitializeSignature()
+ {
+ TypeDesc objectType = Context.GetWellKnownType(WellKnownType.Object);
+ TypeDesc byrefByte = Context.GetWellKnownType(WellKnownType.Byte).MakeByRefType();
+ return _signature = new MethodSignature(0, 0, objectType, [objectType, byrefByte]);
+ }
+
+ public override MethodIL EmitIL()
+ {
+ var emitter = new ILEmitter();
+ ILCodeStream codeStream = emitter.NewCodeStream();
+
+ // TODO: match getAsyncResumptionStub from CoreCLR VM
+ codeStream.EmitCallThrowHelper(emitter, Context.GetHelperEntryPoint("ThrowHelpers"u8, "ThrowNotSupportedException"u8));
+
+ return emitter.Link(this);
+ }
+ }
+}
diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/CompilerTypeSystemContext.Aot.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/CompilerTypeSystemContext.Aot.cs
index ce21b8e0b8a981..199c6b89782d06 100644
--- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/CompilerTypeSystemContext.Aot.cs
+++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/CompilerTypeSystemContext.Aot.cs
@@ -59,6 +59,7 @@ public CompilerTypeSystemContext(TargetDetails details, SharedGenericsMode gener
_typeWithRepeatedFieldsFieldLayoutAlgorithm = new TypeWithRepeatedFieldsFieldLayoutAlgorithm(_metadataFieldLayoutAlgorithm);
_delegateInfoHashtable = new DelegateInfoHashtable(delegateFeatures);
+ _continuationTypeHashtable = new ContinuationTypeHashtable(this);
_genericCycleDetector = new LazyGenericsSupport.GenericCycleDetector(genericCycleDepthCutoff, genericCycleBreadthCutoff);
diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/AsyncContinuationEETypeNode.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/AsyncContinuationEETypeNode.cs
new file mode 100644
index 00000000000000..5f1bc894adcdc4
--- /dev/null
+++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/AsyncContinuationEETypeNode.cs
@@ -0,0 +1,75 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using Internal.Text;
+using Internal.TypeSystem;
+using Internal.TypeSystem.Ecma;
+
+using Debug = System.Diagnostics.Debug;
+
+namespace ILCompiler.DependencyAnalysis
+{
+ ///
+ /// Specialized MethodTable that describes async continuation types ().
+ ///
+ public class AsyncContinuationEETypeNode : DataOnlyEETypeNode, IEETypeNode
+ {
+ public TypeDesc Type { get; }
+
+ public AsyncContinuationEETypeNode(AsyncContinuationType type)
+ : base("Continuation", BuildPointerMap(type), type.BaseType, false)
+ {
+ Type = type;
+ }
+
+ private static GCPointerMap BuildPointerMap(AsyncContinuationType type)
+ {
+ // The GC pointer map in the continuation type doesn't include base type. Build a GC pointer map that
+ // includes the base type.
+ MetadataType continuationBaseType = type.BaseType;
+
+ GCPointerMap baseMap = GCPointerMap.FromInstanceLayout(continuationBaseType);
+ GCPointerMap dataMap = type.PointerMap;
+
+ int baseSize = baseMap.Size;
+ int dataSize = dataMap.Size;
+
+ int pointerSize = type.Context.Target.PointerSize;
+
+ Debug.Assert(continuationBaseType.InstanceByteCountUnaligned.AsInt == baseSize * pointerSize);
+
+#if DEBUG
+ // Validate we match the expected DataOffset value.
+ // DataOffset is a const int32 field in the Continuation class.
+ EcmaField dataOffsetField = (EcmaField)continuationBaseType.GetField("DataOffset"u8);
+ Debug.Assert(dataOffsetField.IsLiteral);
+
+ var reader = dataOffsetField.MetadataReader;
+ var constant = reader.GetConstant(reader.GetFieldDefinition(dataOffsetField.Handle).GetDefaultValue());
+ Debug.Assert(constant.TypeCode == System.Reflection.Metadata.ConstantTypeCode.Int32);
+ int expectedDataOffset = reader.GetBlobReader(constant.Value).ReadInt32()
+ + pointerSize /* + MethodTable field */;
+ Debug.Assert(baseSize * pointerSize == expectedDataOffset);
+#endif
+
+ GCPointerMapBuilder builder = new GCPointerMapBuilder((baseSize + dataSize) * pointerSize, pointerSize);
+ for (int i = 0; i < baseSize + dataSize; i++)
+ {
+ bool isGCPointer = i < baseSize ? baseMap[i] : dataMap[i - baseSize];
+
+ if (isGCPointer)
+ builder.MarkGCPointer(i * pointerSize);
+ }
+
+ return builder.ToGCMap();
+ }
+
+ public override int ClassCode => 9928091;
+
+ public override int CompareToImpl(ISortableNode other, CompilerComparer comparer)
+ {
+ AsyncContinuationEETypeNode otherTypeDataEETypeNode = (AsyncContinuationEETypeNode)other;
+ return comparer.Compare(otherTypeDataEETypeNode.Type, Type);
+ }
+ }
+}
diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/GCStaticEETypeNode.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/DataOnlyEETypeNode.cs
similarity index 63%
rename from src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/GCStaticEETypeNode.cs
rename to src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/DataOnlyEETypeNode.cs
index 041904b3a984b8..c82b592fac0f98 100644
--- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/GCStaticEETypeNode.cs
+++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/DataOnlyEETypeNode.cs
@@ -12,20 +12,23 @@
namespace ILCompiler.DependencyAnalysis
{
///
- /// Represents a subset of that is used to describe GC static field regions for
- /// types. It only fills out enough pieces of the MethodTable structure so that the GC can operate on it. Runtime should
- /// never see these.
+ /// MethodTable for a piece of data that can be allocated on the GC heap, with GC-reported references in it.
+ /// The shape of the data is described using a . The generated data structure
+ /// is a MethodTable that is valid for use with GC, however not all data on it is present.
+ /// A lot of the MethodTable API surface on this will not work at runtime .
///
- public class GCStaticEETypeNode : DehydratableObjectNode, ISymbolDefinitionNode
+ public class DataOnlyEETypeNode : DehydratableObjectNode, ISymbolDefinitionNode
{
- private GCPointerMap _gcMap;
- private TargetDetails _target;
- private bool _requiresAlign8;
+ private readonly string _prefix;
+ protected readonly GCPointerMap _gcMap;
+ private readonly TypeDesc _baseType;
+ protected readonly bool _requiresAlign8;
- public GCStaticEETypeNode(TargetDetails target, GCPointerMap gcMap, bool requiresAlign8)
+ public DataOnlyEETypeNode(string prefix, GCPointerMap gcMap, TypeDesc baseType, bool requiresAlign8)
{
+ _prefix = prefix;
_gcMap = gcMap;
- _target = target;
+ _baseType = baseType;
_requiresAlign8 = requiresAlign8;
}
@@ -33,7 +36,7 @@ public GCStaticEETypeNode(TargetDetails target, GCPointerMap gcMap, bool require
protected override ObjectNodeSection GetDehydratedSection(NodeFactory factory)
{
- if (_target.IsWindows)
+ if (factory.Target.IsWindows)
return ObjectNodeSection.ReadOnlyDataSection;
else
return ObjectNodeSection.DataSection;
@@ -43,7 +46,7 @@ protected override ObjectNodeSection GetDehydratedSection(NodeFactory factory)
public void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb)
{
- sb.Append("__GCStaticEEType_"u8).Append(_gcMap.ToString());
+ sb.Append($"__{_prefix}_").Append(_gcMap.ToString());
if (_requiresAlign8)
{
sb.Append("_align8"u8);
@@ -55,7 +58,7 @@ int ISymbolDefinitionNode.Offset
get
{
int numSeries = _gcMap.NumSeries;
- return numSeries > 0 ? ((numSeries * 2) + 1) * _target.PointerSize : 0;
+ return numSeries > 0 ? ((numSeries * 2) + 1) * _baseType.Context.Target.PointerSize : 0;
}
}
@@ -69,12 +72,8 @@ protected override ObjectData GetDehydratableData(NodeFactory factory, bool relo
dataBuilder.RequireInitialPointerAlignment();
dataBuilder.AddSymbol(this);
- // +1 for SyncBlock (static size already includes MethodTable)
- int totalSize = (_gcMap.Size + 1) * _target.PointerSize;
-
- // We only need to check for containsPointers because ThreadStatics are always allocated
- // on the GC heap (no matter what "HasGCStaticBase" says).
- // If that ever changes, we can assume "true" and switch this to an assert.
+ // +1 for SyncBlock (GCMap size already includes MethodTable field)
+ int totalSize = (_gcMap.Size + 1) * factory.Target.PointerSize;
bool containsPointers = _gcMap.NumSeries > 0;
if (containsPointers)
@@ -98,12 +97,10 @@ protected override ObjectData GetDehydratableData(NodeFactory factory, bool relo
dataBuilder.EmitUInt(flags);
- totalSize = Math.Max(totalSize, _target.PointerSize * 3); // minimum GC MethodTable size is 3 pointers
+ totalSize = Math.Max(totalSize, factory.Target.PointerSize * 3); // minimum GC MethodTable size is 3 pointers
dataBuilder.EmitInt(totalSize);
- // Related type: System.Object. This allows storing an instance of this type in an array of objects,
- // or finding associated module from BulkType event source events.
- dataBuilder.EmitPointerReloc(factory.NecessaryTypeSymbol(factory.TypeSystemContext.GetWellKnownType(WellKnownType.Object)));
+ dataBuilder.EmitPointerReloc(factory.NecessaryTypeSymbol(_baseType));
return dataBuilder.ToObjectData();
}
@@ -112,11 +109,11 @@ protected override ObjectData GetDehydratableData(NodeFactory factory, bool relo
public override int CompareToImpl(ISortableNode other, CompilerComparer comparer)
{
- GCStaticEETypeNode otherGCStaticEETypeNode = (GCStaticEETypeNode)other;
- int mapCompare = _gcMap.CompareTo(otherGCStaticEETypeNode._gcMap);
+ DataOnlyEETypeNode otherNode = (DataOnlyEETypeNode)other;
+ int mapCompare = _gcMap.CompareTo(otherNode._gcMap);
if (mapCompare == 0)
{
- return _requiresAlign8.CompareTo(otherGCStaticEETypeNode._requiresAlign8);
+ return _requiresAlign8.CompareTo(otherNode._requiresAlign8);
}
return mapCompare;
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 8cea4b6dee9aa9..64a1741a6d0e88 100644
--- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/NodeFactory.cs
+++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/NodeFactory.cs
@@ -250,9 +250,17 @@ private void CreateNodeCaches()
return new TypeThreadStaticIndexNode(type, null);
});
- _GCStaticEETypes = new NodeCache<(GCPointerMap, bool), GCStaticEETypeNode>(((GCPointerMap gcMap, bool requiresAlign8) key) =>
+ _GCStaticEETypes = new NodeCache<(GCPointerMap, bool), DataOnlyEETypeNode>(((GCPointerMap gcMap, bool requiresAlign8) key) =>
{
- return new GCStaticEETypeNode(Target, key.gcMap, key.requiresAlign8);
+ // Base type: System.Object. This allows storing an instance of this type in an array of objects,
+ // or finding associated module from BulkType event source events.
+ DefType baseType = _context.GetWellKnownType(WellKnownType.Object);
+ return new DataOnlyEETypeNode("GCStaticEEType", key.gcMap, baseType, key.requiresAlign8);
+ });
+
+ _asyncContinuationEETypes = new NodeCache((AsyncContinuationType key) =>
+ {
+ return new AsyncContinuationEETypeNode(key);
});
_readOnlyDataBlobs = new NodeCache(key =>
@@ -713,6 +721,7 @@ public NecessaryTypeSymbolHashtable(NodeFactory factory) : base(factory) { }
protected override IEETypeNode CreateValueFromKey(TypeDesc key) => _factory.CreateNecessaryTypeNode(key);
}
+ private NodeCache _asyncContinuationEETypes;
private NecessaryTypeSymbolHashtable _typeSymbols;
public IEETypeNode NecessaryTypeSymbol(TypeDesc type)
@@ -727,6 +736,11 @@ public IEETypeNode NecessaryTypeSymbol(TypeDesc type)
return ConstructedTypeSymbol(type);
}
+ if (type is AsyncContinuationType continuation)
+ {
+ return _asyncContinuationEETypes.GetOrAdd(continuation);
+ }
+
Debug.Assert(!TypeCannotHaveEEType(type));
return _typeSymbols.GetOrCreateValue(type);
@@ -752,6 +766,9 @@ public IEETypeNode MetadataTypeSymbol(TypeDesc type)
return ConstructedTypeSymbol(type);
}
+ // Generating typeof of a continuation type is not supported; we'd need a full MethodTable.
+ Debug.Assert(type is not AsyncContinuationType);
+
Debug.Assert(!TypeCannotHaveEEType(type));
return _metadataTypeSymbols.GetOrCreateValue(type);
@@ -772,6 +789,11 @@ public IEETypeNode ConstructedTypeSymbol(TypeDesc type)
return ImportedEETypeSymbol(type);
}
+ if (type is AsyncContinuationType continuation)
+ {
+ return _asyncContinuationEETypes.GetOrAdd(continuation);
+ }
+
Debug.Assert(!TypeCannotHaveEEType(type));
return _constructedTypeSymbols.GetOrCreateValue(type);
@@ -893,7 +915,7 @@ public EmbeddedTrimmingDescriptorNode EmbeddedTrimmingDescriptor(EcmaModule modu
return _embeddedTrimmingDescriptors.GetOrAdd(module);
}
- private NodeCache<(GCPointerMap, bool), GCStaticEETypeNode> _GCStaticEETypes;
+ private NodeCache<(GCPointerMap, bool), DataOnlyEETypeNode> _GCStaticEETypes;
public ISymbolNode GCStaticEEType(GCPointerMap gcMap, bool requiredAlign8)
{
diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/ILCompiler.Compiler.csproj b/src/coreclr/tools/aot/ILCompiler.Compiler/ILCompiler.Compiler.csproj
index 5cd4a3f196d577..0b6f858708e99d 100644
--- a/src/coreclr/tools/aot/ILCompiler.Compiler/ILCompiler.Compiler.csproj
+++ b/src/coreclr/tools/aot/ILCompiler.Compiler/ILCompiler.Compiler.csproj
@@ -33,6 +33,7 @@
+
@@ -45,6 +46,9 @@
IL\DelegateInfo.cs
+
+
+
IL\Stubs\DelegateThunks.Sorting.cs
@@ -377,6 +381,7 @@
+
@@ -586,7 +591,7 @@
-
+
diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj
index f145cbeae61297..d326121cb517ee 100644
--- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj
+++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj
@@ -55,6 +55,7 @@
+
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 11531be22667a5..ab05d31d840f50 100644
--- a/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs
+++ b/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs
@@ -33,6 +33,7 @@ internal unsafe partial class CorInfoImpl
private RyuJitCompilation _compilation;
private MethodDebugInformation _debugInfo;
+ private MethodDesc _asyncResumptionStub;
private MethodCodeNode _methodCodeNode;
private DebugLocInfo[] _debugLocInfos;
private DebugVarInfo[] _debugVarInfos;
@@ -758,6 +759,9 @@ private ISymbolNode GetHelperFtnUncached(CorInfoHelpFunc ftnNum)
id = ReadyToRunHelper.MonitorExit;
break;
+ case CorInfoHelpFunc.CORINFO_HELP_ALLOC_CONTINUATION:
+ return _compilation.NodeFactory.MethodEntrypoint(_compilation.NodeFactory.TypeSystemContext.GetCoreLibEntryPoint("System.Runtime.CompilerServices"u8, "AsyncHelpers"u8, "AllocContinuation"u8, null));
+
case CorInfoHelpFunc.CORINFO_HELP_GETSYNCFROMCLASSHANDLE:
return _compilation.NodeFactory.MethodEntrypoint(_compilation.NodeFactory.TypeSystemContext.GetCoreLibEntryPoint("System.Threading"u8, "Monitor"u8, "GetSyncObjectFromClassHandle"u8, null));
case CorInfoHelpFunc.CORINFO_HELP_GETCLASSFROMMETHODPARAM:
diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncHelpers.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncHelpers.cs
index ffd7b11516f138..167aca683121e2 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncHelpers.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncHelpers.cs
@@ -13,7 +13,7 @@ namespace System.Runtime.CompilerServices
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
public static partial class AsyncHelpers
{
-#if CORECLR
+#if CORECLR || NATIVEAOT
// "BypassReadyToRun" is until AOT/R2R typesystem has support for MethodImpl.Async
// Must be NoInlining because we use AsyncSuspend to manufacture an explicit suspension point.
// It will not capture/restore any local state that is live across it.
@@ -220,35 +220,10 @@ public static T Await(ConfiguredValueTaskAwaitable configuredAwaitable)
public static void UnsafeAwaitAwaiter(TAwaiter awaiter) where TAwaiter : ICriticalNotifyCompletion { throw new NotImplementedException(); }
[RequiresPreviewFeatures]
public static void AwaitAwaiter(TAwaiter awaiter) where TAwaiter : INotifyCompletion { throw new NotImplementedException(); }
-#if NATIVEAOT
- [RequiresPreviewFeatures]
- public static void Await(System.Threading.Tasks.Task task)
- {
- TaskAwaiter awaiter = task.GetAwaiter();
- if (!awaiter.IsCompleted)
- {
- throw new NotImplementedException();
- }
-
- awaiter.GetResult();
- }
- [RequiresPreviewFeatures]
- public static T Await(System.Threading.Tasks.Task task)
- {
- TaskAwaiter awaiter = task.GetAwaiter();
- if (!awaiter.IsCompleted)
- {
- throw new NotImplementedException();
- }
-
- return awaiter.GetResult();
- }
-#else
[RequiresPreviewFeatures]
public static void Await(System.Threading.Tasks.Task task) { throw new NotImplementedException(); }
[RequiresPreviewFeatures]
public static T Await(System.Threading.Tasks.Task task) { throw new NotImplementedException(); }
-#endif
[RequiresPreviewFeatures]
public static void Await(System.Threading.Tasks.ValueTask task) { throw new NotImplementedException(); }
[RequiresPreviewFeatures]