diff --git a/src/coreclr/jit/codegenwasm.cpp b/src/coreclr/jit/codegenwasm.cpp index a877d5b0651f83..d69ff9da405bcf 100644 --- a/src/coreclr/jit/codegenwasm.cpp +++ b/src/coreclr/jit/codegenwasm.cpp @@ -187,6 +187,14 @@ void CodeGen::genAllocLclFrame(unsigned frameSize, regNumber initReg, bool* pIni GetEmitter()->emitIns_I(INS_local_get, EA_PTRSIZE, GetFramePointerRegIndex()); GetEmitter()->emitFuncletAddressConstant(0 /* funcletId for main method */); GetEmitter()->emitIns_S(ins_Store(TYP_I_IMPL), EA_PTRSIZE, m_compiler->lvaWasmFunctionIndex, 0); + + // Ensure the resume IP is initialized to a non-resuming value. + if ((m_compiler->funCurrentFuncIdx() == ROOT_FUNC_IDX) && (m_compiler->lvaWasmResumeIP != BAD_VAR_NUM)) + { + GetEmitter()->emitIns_I(INS_local_get, EA_PTRSIZE, GetFramePointerRegIndex()); + GetEmitter()->emitIns_I(INS_I_const, EA_4BYTE, 0); + GetEmitter()->emitIns_S(ins_Store(TYP_INT), EA_4BYTE, m_compiler->lvaWasmResumeIP, 0); + } } } diff --git a/src/coreclr/jit/fgwasm.cpp b/src/coreclr/jit/fgwasm.cpp index 95500b9a1d8543..87a521bc4c649c 100644 --- a/src/coreclr/jit/fgwasm.cpp +++ b/src/coreclr/jit/fgwasm.cpp @@ -3254,14 +3254,14 @@ void Compiler::fgWasmEhTransformTry(ArrayStack* catchRetBlocks, cases[i] = nullptr; } - // Track the unique edge per continuation block. When many cases share the + // Track the unique reset pad and edge per continuation block. When many cases share the // same continuation (e.g. a large mutual-protect catch set whose handlers // all `leave` to the same target) this avoids an O(N^2) cost in // fgAddRefPred (which must do an O(preds) scan of the destination's // pred list per call) -- we just bump dup counts directly for duplicates. // - BlockToFlowEdgeMap* const continuationEdges = - new (this, CMK_FlowEdge) BlockToFlowEdgeMap(getAllocator(CMK_FlowEdge)); + BlockToBlockMap resumePads(getAllocator(CMK_FlowEdge)); + BlockToFlowEdgeMap continuationEdges(getAllocator(CMK_FlowEdge)); for (BasicBlock* const catchRetBlock : catchRetBlocks->TopDownOrder()) { @@ -3274,23 +3274,46 @@ void Compiler::fgWasmEhTransformTry(ArrayStack* catchRetBlocks, JITDUMP(" case %u: " FMT_BB "\n", biasedCaseIndex, continuation->bbNum); - FlowEdge* caseEdge; - if (continuationEdges->Lookup(continuation, &caseEdge)) + BasicBlock* resumePad; + FlowEdge* caseEdge; + if (resumePads.Lookup(continuation, &resumePad)) { // Edge from switchBlock to this continuation already exists; just // bump the dup count (and the destination's ref count) instead of // doing another linear pred-list scan via fgAddRefPred. // + bool const found = continuationEdges.Lookup(continuation, &caseEdge); + assert(found); caseEdge->incrementDupCount(); - continuation->bbRefs++; + resumePad->bbRefs++; } else { - caseEdge = fgAddRefPred(continuation, switchBlock); - continuationEdges->Set(continuation, caseEdge); + // Clear the resume IP only after this try has accepted the resumption. + // A nonmatching inner try must preserve the value for an enclosing try. + // + resumePad = fgNewBBafter(BBJ_ALWAYS, switchBlock, /* extendRegion */ false); + resumePad->copyEHRegion(continuation); + resumePad->inheritWeightPercentage(switchBlock, 0); + + FlowEdge* const padEdge = fgAddRefPred(continuation, resumePad); + padEdge->setLikelihood(1.0); + resumePad->SetTargetEdge(padEdge); + + GenTree* const zero = gtNewIconNode(0, TYP_INT); + GenTree* const store = gtNewStoreLclVarNode(resumeIPLocalNum, zero); + LIR::Range range = LIR::SeqTree(this, store); + LIR::AsRange(resumePad).InsertAtEnd(std::move(range)); + + resumePads.Set(continuation, resumePad); + + caseEdge = fgAddRefPred(resumePad, switchBlock); + continuationEdges.Set(continuation, caseEdge); // We only get here on exception caseEdge->setLikelihood(0); + + JITDUMP("Resume pad " FMT_BB " for " FMT_BB "\n", resumePad->bbNum, continuation->bbNum); } assert(cases[biasedCaseIndex] == nullptr); @@ -3319,7 +3342,10 @@ void Compiler::fgWasmEhTransformTry(ArrayStack* catchRetBlocks, for (BasicBlock* const catchRetBlock : catchRetBlocks->TopDownOrder()) { BasicBlock* const continuation = catchRetBlock->GetTarget(); - if (BitVecOps::TryAddElemD(&bitVecTraits, succBlocks, continuation->bbNum)) + BasicBlock* resumePad; + bool const found = resumePads.Lookup(continuation, &resumePad); + assert(found); + if (BitVecOps::TryAddElemD(&bitVecTraits, succBlocks, resumePad->bbNum)) { succCount++; } @@ -3340,10 +3366,13 @@ void Compiler::fgWasmEhTransformTry(ArrayStack* catchRetBlocks, for (BasicBlock* const catchRetBlock : catchRetBlocks->TopDownOrder()) { BasicBlock* const continuation = catchRetBlock->GetTarget(); - if (BitVecOps::TryAddElemD(&bitVecTraits, succBlocks, continuation->bbNum)) + BasicBlock* resumePad; + bool const foundPad = resumePads.Lookup(continuation, &resumePad); + assert(foundPad); + if (BitVecOps::TryAddElemD(&bitVecTraits, succBlocks, resumePad->bbNum)) { FlowEdge* edge = nullptr; - bool const found = continuationEdges->Lookup(continuation, &edge); + bool const found = continuationEdges.Lookup(continuation, &edge); assert(found); succs[succNumber] = edge; succNumber++; diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/ExceptionTests.cs b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/ExceptionTests.cs index 879dfff4cd8d23..e830356e9c1a9a 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/ExceptionTests.cs +++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/ExceptionTests.cs @@ -177,6 +177,42 @@ private static void ThrowException() throw new Exception("Boom!"); } + [Fact] + public static void RepeatedCatch_ThrowFromSecondCatch_HandledByOuterCatch() + { + bool caught = false; + + try + { + ThrowFromSecondCatch(); + } + catch (InvalidOperationException) + { + caught = true; + } + + Assert.True(caught); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static void ThrowFromSecondCatch() + { + for (int i = 0; i < 2; i++) + { + try + { + throw new Exception(); + } + catch + { + if (i != 0) + { + throw new InvalidOperationException(); + } + } + } + } + private static void VerifyCallStack( (string CallerMemberName, string SourceFilePath, int SourceLineNumber) expectedStackFrame, string reportedCallStack, int skipFrames)