Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/coreclr/jit/compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -5468,6 +5468,7 @@ class Compiler
bool impMatchIsInstBooleanConversion(const BYTE* codeAddr, const BYTE* codeEndp, int* consumed);

const BYTE* impMatchTaskAwaitPattern(const BYTE* codeAddr, const BYTE* codeEndp, int* configVal, IL_OFFSET* awaitOffset);
bool impCheckOptimizeAwait(IL_OFFSET awaitOffset);

GenTree* impCastClassOrIsInstToTree(
GenTree* op1, GenTree* op2, CORINFO_RESOLVED_TOKEN* pResolvedToken, bool isCastClass, bool* booleanCheck, IL_OFFSET ilOffset);
Expand Down
33 changes: 32 additions & 1 deletion src/coreclr/jit/importer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9091,7 +9091,7 @@ void Compiler::impImportBlockCode(BasicBlock* block)
if (isAwait)
{
_impResolveToken(CORINFO_TOKENKIND_Await);
if (resolvedToken.hMethod == NO_METHOD_HANDLE)
if ((resolvedToken.hMethod == NO_METHOD_HANDLE) || !impCheckOptimizeAwait(awaitOffset))
{
// This can happen in cases when the Task-returning method is not a runtime Async
Comment thread
jakobbotsch marked this conversation as resolved.
// function. For example "T M1<T>(T arg) => arg" when called with a Task argument.
Expand Down Expand Up @@ -11155,6 +11155,37 @@ void Compiler::impImportBlockCode(BasicBlock* block)
#undef _impResolveToken
}

//------------------------------------------------------------------------
// impCheckOptimizeAwait:
// Check if an await at a specified offset should be optimized.
//
// Arguments:
// awaitOffset - The offset of the await
//
// Returns:
// True if we should use the async variant.
//
bool Compiler::impCheckOptimizeAwait(IL_OFFSET awaitOffset)
{
#ifdef DEBUG
static ConfigMethodRange s_jitOptimizeAwaitRange;
s_jitOptimizeAwaitRange.EnsureInit(JitConfig.JitOptimizeAwaitRange());

unsigned hash = impInlineRoot()->info.compMethodHash();
hash = ((hash << 5) + hash) ^ (compIsForInlining() ? compInlineContext->GetOrdinal() : 0);
hash = ((hash << 5) + hash) ^ awaitOffset;

if ((JitConfig.JitAwaitHashBreak() != -1) && (hash == (unsigned)JitConfig.JitAwaitHashBreak()))
{
assert(!"JitAwaitHashBreak reached");
}

return s_jitOptimizeAwaitRange.Contains(hash);
#else
return true;
#endif
}

//------------------------------------------------------------------------
// impCreateLocal: create a GT_LCL_VAR node to access a local that might need to be normalized on load
//
Expand Down
2 changes: 2 additions & 0 deletions src/coreclr/jit/jitconfigvalues.h
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,8 @@ RELEASE_CONFIG_INTEGER(JitInlineBudget, "JitInlineBudget", DEFAULT_INLINE_BUDGET
CONFIG_INTEGER(JitForceInlineDepth, "JitForceInlineDepth", DEFAULT_MAX_FORCE_INLINE_DEPTH)
RELEASE_CONFIG_INTEGER(JitInlineMethodsWithEH, "JitInlineMethodsWithEH", 1)
CONFIG_STRING(JitInlineMethodsWithEHRange, "JitInlineMethodsWithEHRange")
CONFIG_STRING(JitOptimizeAwaitRange, "JitOptimizeAwaitRange") // Optimize awaits in this hash range
CONFIG_INTEGER(JitAwaitHashBreak, "JitAwaitHashBreak", -1) // Break on jitting await with specified hash

CONFIG_INTEGER(JitLongAddress, "JitLongAddress", 0) // Force using the large pseudo instruction form for long address
CONFIG_INTEGER(JitMaxUncheckedOffset, "JitMaxUncheckedOffset", 8)
Expand Down
9 changes: 8 additions & 1 deletion src/coreclr/vm/method.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ enum class AsyncMethodFlags
Thunk = 16,
// A special thunk to drop return value in covariant return scenario
ReturnDroppingThunk = 32,
// Note: If adding more flags make sure to modify RequiresAsyncContextSaveAndRestore

// The rest of the methods that are not in any of the above groups.
// Such methods are not interesting to the Runtime Async feature.
// Note: Generic T-returning methods are classified as "None", even if T could be a Task.
Expand Down Expand Up @@ -117,6 +119,11 @@ inline AsyncMethodFlags operator&(AsyncMethodFlags lhs, AsyncMethodFlags rhs)
return (AsyncMethodFlags)((int)lhs & (int)rhs);
}

inline AsyncMethodFlags operator~(AsyncMethodFlags flags)
{
return (AsyncMethodFlags)~(int)flags;
}

inline AsyncMethodFlags& operator|=(AsyncMethodFlags& lhs, AsyncMethodFlags rhs)
{
lhs = lhs | rhs;
Expand Down Expand Up @@ -2161,7 +2168,7 @@ class MethodDesc

AsyncMethodFlags asyncFlags = GetAddrOfAsyncMethodData()->flags;
// asynccall that is also async variant, but not a thunk
return asyncFlags == (AsyncMethodFlags::AsyncCall | AsyncMethodFlags::IsAsyncVariant);
return (asyncFlags & ~AsyncMethodFlags::IsAsyncVariantForValueTask) == (AsyncMethodFlags::AsyncCall | AsyncMethodFlags::IsAsyncVariant);

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actual bug fix.

}

#ifdef FEATURE_METADATA_UPDATER
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -577,7 +577,6 @@ protected static void VerifyTag<T>(KeyValuePair<string, object?>[] tags, string
}
}

[ActiveIssue("https://github.com/dotnet/runtime/issues/129771")]
[ConditionalTheory(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))]
[InlineData(false)]
[InlineData(true)]
Expand Down
18 changes: 18 additions & 0 deletions src/tests/async/execution-context/execution-context.cs
Original file line number Diff line number Diff line change
Expand Up @@ -152,4 +152,22 @@ private static async Task LoopWithOsrTransition()

s_osrLocal.Value = val;
}

[Fact]
public static void TestValueTask()
{
TestValueTaskAsync().GetAwaiter().GetResult();
}

private static async ValueTask TestValueTaskAsync()
{
s_local.Value = 42;
await ChangeThenReturnValueTask();
Assert.Equal(42, s_local.Value);
}

private static async ValueTask ChangeThenReturnValueTask()
{
s_local.Value = 123;
}
Comment thread
jakobbotsch marked this conversation as resolved.
}
Loading