diff --git a/src/coreclr/interpreter/compiler.cpp b/src/coreclr/interpreter/compiler.cpp index 28ef2438eb1d4b..0d614a135a6aa9 100644 --- a/src/coreclr/interpreter/compiler.cpp +++ b/src/coreclr/interpreter/compiler.cpp @@ -7425,7 +7425,13 @@ bool InterpCompiler::IsRuntimeAsyncCall(const uint8_t* ip, OpcodePeepElement* pa bool InterpCompiler::IsRuntimeAsyncCallConfigureAwaitTask(const uint8_t* ip, OpcodePeepElement* pattern, void** ppComputedInfo) { - switch (*(ip + pattern[2].offsetIntoPeep - 1)) + // IL pattern: + // # CALL | CALLVIRT at offset 0 + // # LDC_I4_0 | LDC_I4_1 + // CALLVIRT + // CALL + + switch (*(ip + pattern[0].offsetIntoPeep - 1)) { case CEE_LDC_I4_0: m_currentContinuationContextHandling = ContinuationContextHandling::ContinueOnThreadPool; @@ -7437,38 +7443,8 @@ bool InterpCompiler::IsRuntimeAsyncCallConfigureAwaitTask(const uint8_t* ip, Opc return false; } - uint32_t stLocVar = 0; - uint32_t ldlocaVar = 0; - - switch (*(ip + pattern[0].offsetIntoPeep)) - { - case CEE_STLOC_S: - stLocVar = (ip + pattern[0].offsetIntoPeep)[1]; - break; - default: - // Must be STLOC - stLocVar = getU2LittleEndian(ip + pattern[0].offsetIntoPeep + 2); - break; - } - - switch (*(ip + pattern[1].offsetIntoPeep)) - { - case CEE_LDLOCA_S: - ldlocaVar = (ip + pattern[1].offsetIntoPeep)[1]; - break; - default: - // Must be LDLOCA - ldlocaVar = getU2LittleEndian(ip + pattern[1].offsetIntoPeep + 2); - break; - } - - if (ldlocaVar != stLocVar) - { - return false; - } - CORINFO_RESOLVED_TOKEN configureAwaitResolvedToken; - ResolveToken(getU4LittleEndian(ip + pattern[2].offsetIntoPeep + 1), CORINFO_TOKENKIND_Method, &configureAwaitResolvedToken); + ResolveToken(getU4LittleEndian(ip + pattern[0].offsetIntoPeep + 1), CORINFO_TOKENKIND_Method, &configureAwaitResolvedToken); if (!m_compHnd->isIntrinsic(configureAwaitResolvedToken.hMethod) || GetNamedIntrinsic(m_compHnd, m_methodHnd, configureAwaitResolvedToken.hMethod) != NI_System_Threading_Tasks_Task_ConfigureAwait) { @@ -7476,7 +7452,7 @@ bool InterpCompiler::IsRuntimeAsyncCallConfigureAwaitTask(const uint8_t* ip, Opc } CORINFO_RESOLVED_TOKEN awaitResolvedToken; - ResolveToken(getU4LittleEndian(ip + pattern[3].offsetIntoPeep + 1), CORINFO_TOKENKIND_Method, &awaitResolvedToken); + ResolveToken(getU4LittleEndian(ip + pattern[1].offsetIntoPeep + 1), CORINFO_TOKENKIND_Method, &awaitResolvedToken); if (!m_compHnd->isIntrinsic(awaitResolvedToken.hMethod) || GetNamedIntrinsic(m_compHnd, m_methodHnd, awaitResolvedToken.hMethod) != NI_System_Runtime_CompilerServices_AsyncHelpers_Await) { @@ -7488,17 +7464,13 @@ bool InterpCompiler::IsRuntimeAsyncCallConfigureAwaitTask(const uint8_t* ip, Opc bool InterpCompiler::IsRuntimeAsyncCallConfigureAwaitValueTaskExactStLoc(const uint8_t* ip, OpcodePeepElement* pattern, void** ppComputedInfo) { - switch (*(ip + pattern[1].offsetIntoPeep - 1)) - { - case CEE_LDC_I4_0: - m_currentContinuationContextHandling = ContinuationContextHandling::ContinueOnThreadPool; - break; - case CEE_LDC_I4_1: - m_currentContinuationContextHandling = ContinuationContextHandling::ContinueOnCapturedContext; - break; - default: - return false; - } + // IL pattern: + // # CALL | CALLVIRT at offset 0 + // # STLOC_0 | STLOC_1 | STLOC_2 | STLOC_3 + // LDLOCA | LDLOCA_S + // # LDC_I4_0 | LDC_I4_1 + // CALL + // CALL uint32_t stLocVar = 0; uint32_t ldlocaVar = 0; @@ -7521,14 +7493,14 @@ bool InterpCompiler::IsRuntimeAsyncCallConfigureAwaitValueTaskExactStLoc(const u return false; } - switch (*(ip + pattern[1].offsetIntoPeep)) + switch (*(ip + pattern[0].offsetIntoPeep)) { case CEE_LDLOCA_S: - ldlocaVar = (ip + pattern[1].offsetIntoPeep)[1]; + ldlocaVar = (ip + pattern[0].offsetIntoPeep)[1]; break; default: // Must be LDLOCA - ldlocaVar = getU2LittleEndian(ip + pattern[1].offsetIntoPeep + 2); + ldlocaVar = getU2LittleEndian(ip + pattern[0].offsetIntoPeep + 2); break; } @@ -7537,6 +7509,18 @@ bool InterpCompiler::IsRuntimeAsyncCallConfigureAwaitValueTaskExactStLoc(const u return false; } + switch (*(ip + pattern[1].offsetIntoPeep - 1)) + { + case CEE_LDC_I4_0: + m_currentContinuationContextHandling = ContinuationContextHandling::ContinueOnThreadPool; + break; + case CEE_LDC_I4_1: + m_currentContinuationContextHandling = ContinuationContextHandling::ContinueOnCapturedContext; + break; + default: + return false; + } + CORINFO_RESOLVED_TOKEN configureAwaitResolvedToken; ResolveToken(getU4LittleEndian(ip + pattern[1].offsetIntoPeep + 1), CORINFO_TOKENKIND_Method, &configureAwaitResolvedToken); if (!m_compHnd->isIntrinsic(configureAwaitResolvedToken.hMethod) || @@ -7558,7 +7542,45 @@ bool InterpCompiler::IsRuntimeAsyncCallConfigureAwaitValueTaskExactStLoc(const u bool InterpCompiler::IsRuntimeAsyncCallConfigureAwaitValueTask(const uint8_t* ip, OpcodePeepElement* pattern, void** ppComputedInfo) { - switch (*(ip + pattern[0].offsetIntoPeep - 1)) + // IL pattern: + // # CALL | CALLVIRT at offset 0 + // STLOC | STLOC_S + // LDLOCA | LDLOCA_S + // # LDC_I4_0 | LDC_I4_1 + // CALL + // CALL + + uint32_t stLocVar = 0; + uint32_t ldlocaVar = 0; + + switch (*(ip + pattern[0].offsetIntoPeep)) + { + case CEE_STLOC_S: + stLocVar = (ip + pattern[0].offsetIntoPeep)[1]; + break; + default: + // Must be STLOC + stLocVar = getU2LittleEndian(ip + pattern[0].offsetIntoPeep + 2); + break; + } + + switch (*(ip + pattern[1].offsetIntoPeep)) + { + case CEE_LDLOCA_S: + ldlocaVar = (ip + pattern[1].offsetIntoPeep)[1]; + break; + default: + // Must be LDLOCA + ldlocaVar = getU2LittleEndian(ip + pattern[1].offsetIntoPeep + 2); + break; + } + + if (ldlocaVar != stLocVar) + { + return false; + } + + switch (*(ip + pattern[2].offsetIntoPeep - 1)) { case CEE_LDC_I4_0: m_currentContinuationContextHandling = ContinuationContextHandling::ContinueOnThreadPool; @@ -7571,7 +7593,7 @@ bool InterpCompiler::IsRuntimeAsyncCallConfigureAwaitValueTask(const uint8_t* ip } CORINFO_RESOLVED_TOKEN configureAwaitResolvedToken; - ResolveToken(getU4LittleEndian(ip + pattern[0].offsetIntoPeep + 1), CORINFO_TOKENKIND_Method, &configureAwaitResolvedToken); + ResolveToken(getU4LittleEndian(ip + pattern[2].offsetIntoPeep + 1), CORINFO_TOKENKIND_Method, &configureAwaitResolvedToken); if (!m_compHnd->isIntrinsic(configureAwaitResolvedToken.hMethod) || GetNamedIntrinsic(m_compHnd, m_methodHnd, configureAwaitResolvedToken.hMethod) != NI_System_Threading_Tasks_Task_ConfigureAwait) { @@ -7579,7 +7601,7 @@ bool InterpCompiler::IsRuntimeAsyncCallConfigureAwaitValueTask(const uint8_t* ip } CORINFO_RESOLVED_TOKEN awaitResolvedToken; - ResolveToken(getU4LittleEndian(ip + pattern[1].offsetIntoPeep + 1), CORINFO_TOKENKIND_Method, &awaitResolvedToken); + ResolveToken(getU4LittleEndian(ip + pattern[3].offsetIntoPeep + 1), CORINFO_TOKENKIND_Method, &awaitResolvedToken); if (!m_compHnd->isIntrinsic(awaitResolvedToken.hMethod) || GetNamedIntrinsic(m_compHnd, m_methodHnd, awaitResolvedToken.hMethod) != NI_System_Runtime_CompilerServices_AsyncHelpers_Await) { @@ -7649,10 +7671,10 @@ bool InterpCompiler::FindAndApplyPeep(OpcodePeep* Peeps[]) // Check to see if peep applies to the current block just looking at the IL streams // starting at the current ip. - for (int iPeepOpCode = 0; peep->pattern[iPeepOpCode].opcode != CEE_ILLEGAL; iPeepOpCode++) + int iPeepOpCode = 0; + for (; peep->pattern[iPeepOpCode].opcode != CEE_ILLEGAL; iPeepOpCode++) { const uint8_t *ipForOpcode = ip + peep->pattern[iPeepOpCode].offsetIntoPeep; - int32_t insOffset = (int32_t)(ipForOpcode - m_pILCode); if (ipForOpcode >= m_pILCode + m_ILCodeSize) { @@ -7660,17 +7682,29 @@ bool InterpCompiler::FindAndApplyPeep(OpcodePeep* Peeps[]) skipToNextPeep = true; break; } - InterpBasicBlock *pNewBB = m_ppOffsetToBB[insOffset]; - if (pNewBB != NULL && m_pCBB != pNewBB) + + if (peep->pattern[iPeepOpCode].opcode != CEEDecodeOpcode(&ipForOpcode)) { - // Ran into a different basic block + // Opcode does not match skipToNextPeep = true; break; } + } + if (skipToNextPeep) + continue; - if (peep->pattern[iPeepOpCode].opcode != CEEDecodeOpcode(&ipForOpcode)) + // Peeps don't necessarily contain all the opcodes that should match. The opcodes that we + // are matching in the peep have not been reached yet by the compiler, so we don't have + // the `m_ppOffsetToBB` offset initialized for them, since this is initialized only for + // the first instruction in the bblock. We therefore need to scan all offsets looking for + // a new bblock. + int32_t startOffset = (int32_t)(ip - m_pILCode); + int32_t endOffset = startOffset + peep->pattern[iPeepOpCode].offsetIntoPeep; + for (int32_t ilOffset = startOffset + 1; ilOffset < endOffset; ilOffset++) + { + InterpBasicBlock *pNewBB = m_ppOffsetToBB[ilOffset]; + if (pNewBB != NULL && m_pCBB != pNewBB) { - // Opcode does not match skipToNextPeep = true; break; }