Skip to content
35 changes: 33 additions & 2 deletions src/coreclr/jit/emit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8440,12 +8440,43 @@ void emitter::emitOutputDataSec(dataSecDsc* sec, AllocMemChunk* chunks)
BYTE* target = emitLoc->Valid() ? emitOffsetToPtr(emitLoc->CodeOffset(this)) : nullptr;
aDstRW[i].Resume = (target_size_t)(uintptr_t)emitAsyncResumeStubEntryPoint;
aDstRW[i].DiagnosticIP = (target_size_t)(uintptr_t)target;

if (m_compiler->opts.compReloc)
{
emitRecordRelocation(&aDstRW[i].Resume, emitAsyncResumeStubEntryPoint, CorInfoReloc::DIRECT);
#ifdef TARGET_ARM
// The runtime and ILC will handle setting the thumb bit on the async resumption stub entrypoint,
// either directly in the emitAsyncResumeStubEntryPoint value (runtime) or will add the thumb bit
// to the symbol definition (ilc). ReadyToRun is different here: it emits method symbols without the
// thumb bit, then during fixups, the runtime adds the thumb bit. This works for all cases where
// the method entrypoint is fixed up at runtime, but doesn't hold for the resumption stub, which is
// emitted as a direct call without the typical indirection cell + fixup. This is okay in this case
// (while regular method calls could not do this) because the async method and its resumption stub
// are tightly coupled and effectively funclets of the same method. However, this means that
// crossgen needs the reloc for the resumption stubs entrypoint to include the thumb bit. Until we
// unify the behavior of crossgen with the runtime and ilc, we will work around this by emitting the
// reloc with the addend for the thumb bit.
if (m_compiler->IsReadyToRun())
{
emitRecordRelocationWithAddlDelta(&aDstRW[i].Resume, emitAsyncResumeStubEntryPoint,
CorInfoReloc::DIRECT, 1);
}
else
#endif
{
emitRecordRelocation(&aDstRW[i].Resume, emitAsyncResumeStubEntryPoint, CorInfoReloc::DIRECT);
}
if (target != nullptr)
{
emitRecordRelocation(&aDstRW[i].DiagnosticIP, target, CorInfoReloc::DIRECT);
#ifdef TARGET_ARM
if (m_compiler->IsReadyToRun())
{
emitRecordRelocationWithAddlDelta(&aDstRW[i].DiagnosticIP, target, CorInfoReloc::DIRECT, 1);
}
else
#endif
{
emitRecordRelocation(&aDstRW[i].DiagnosticIP, target, CorInfoReloc::DIRECT);
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -482,16 +482,6 @@ public IEnumerable<MethodWithGCInfo> EnumerateCompiledMethods(EcmaModule moduleT
foreach (IMethodNode methodNode in MetadataManager.GetCompiledMethods(moduleToEnumerate, methodCategory))
{
MethodDesc method = methodNode.Method;
// Async methods are not emitted in composite mode nor on ARM32
// The mutable module tokens emission is not well tested for composite mode and we should find a real solution for that problem
// ARM32 relocs require the thumb bit set, and the JIT/crossgen doesn't set it properly for the usages in async methods.
// https://github.com/dotnet/runtime/issues/125337
// https://github.com/dotnet/runtime/issues/125338
if (Target.Architecture == TargetArchitecture.ARM
&& (method.IsAsyncVariant() || method.IsCompilerGeneratedILBodyForAsync()))
{
continue;
}
MethodWithGCInfo methodCodeNode = methodNode as MethodWithGCInfo;
#if DEBUG
if ((!methodCodeNode.IsEmpty || CompilationModuleGroup.VersionsWithMethodBody(method)) && method.IsPrimaryMethodDesc())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -573,6 +573,7 @@ public static bool ShouldSkipCompilation(InstructionSetSupport instructionSetSup
// version bubble the stubs are not wrapped with ManifestModuleWrappedMethodIL, so
// token resolution for InstantiatedType / ParameterizedType falls through to a path
// that cannot handle them. Skip compilation and let the runtime JIT these stubs.
// https://github.com/dotnet/runtime/issues/125337
if (methodNeedingCode.IsCompilerGeneratedILBodyForAsync() && compilation != null && compilation.NodeFactory.CompilationModuleGroup.IsCompositeBuildMode)
{
return true;
Expand Down
Loading