private static void InvokeSecondPassWasm(uint idxStart, uint idxTryLandingStart, ref EHClauseIterator clauseIter, uint idxLimit, void *shadowStack) { uint lastTryStart = 0, lastTryEnd = 0; // Search the clauses for one that contains the current offset. RhEHClauseWasm ehClause = new RhEHClauseWasm(); for (uint curIdx = 0; clauseIter.Next(ref ehClause) && curIdx < idxLimit; curIdx++) { // // Skip to the starting try region. This is used by collided unwinds and rethrows to pickup where // the previous dispatch left off. // if (idxStart != MaxTryRegionIdx) { if (curIdx <= idxStart) { lastTryStart = ehClause._tryStartOffset; lastTryEnd = ehClause._tryEndOffset; continue; } // Now, we continue skipping while the try region is identical to the one that invoked the // previous dispatch. if ((ehClause._tryStartOffset == lastTryStart) && (ehClause._tryEndOffset == lastTryEnd)) { continue; } // We are done skipping. This is required to handle empty finally block markers that are used // to separate runs of different try blocks with same native code offsets. idxStart = MaxTryRegionIdx; } EHClauseIterator.RhEHClauseKindWasm clauseKind = ehClause._clauseKind; if ((clauseKind != EHClauseIterator.RhEHClauseKindWasm.RH_EH_CLAUSE_FAULT) || !ehClause.TryStartsAt(idxTryLandingStart)) { continue; } // Found a containing clause. Because of the order of the clauses, we know this is the // most containing. // N.B. -- We need to suppress GC "in-between" calls to finallys in this loop because we do // not have the correct next-execution point live on the stack and, therefore, may cause a GC // hole if we allow a GC between invocation of finally funclets (i.e. after one has returned // here to the dispatcher, but before the next one is invoked). Once they are running, it's // fine for them to trigger a GC, obviously. // // As a result, RhpCallFinallyFunclet will set this state in the runtime upon return from the // funclet, and we need to reset it if/when we fall out of the loop and we know that the // method will no longer get any more GC callbacks. byte *pFinallyHandler = ehClause._handlerAddress; InternalCalls.RhpCallFinallyFunclet(pFinallyHandler, shadowStack); } }
private static void InvokeSecondPass(ref ExInfo exInfo, uint idxStart, uint idxLimit) { EHEnum ehEnum; byte * pbMethodStartAddress; if (!InternalCalls.RhpEHEnumInitFromStackFrameIterator(ref exInfo._frameIter, &pbMethodStartAddress, &ehEnum)) { return; } byte *pbControlPC = exInfo._frameIter.ControlPC; uint codeOffset = (uint)(pbControlPC - pbMethodStartAddress); uint lastTryStart = 0, lastTryEnd = 0; // Search the clauses for one that contains the current offset. RhEHClause ehClause; for (uint curIdx = 0; InternalCalls.RhpEHEnumNext(&ehEnum, &ehClause) && curIdx < idxLimit; curIdx++) { // // Skip to the starting try region. This is used by collided unwinds and rethrows to pickup where // the previous dispatch left off. // if (idxStart != MaxTryRegionIdx) { if (curIdx <= idxStart) { lastTryStart = ehClause._tryStartOffset; lastTryEnd = ehClause._tryEndOffset; continue; } // Now, we continue skipping while the try region is identical to the one that invoked the // previous dispatch. if ((ehClause._tryStartOffset == lastTryStart) && (ehClause._tryEndOffset == lastTryEnd)) { continue; } } RhEHClauseKind clauseKind = ehClause._clauseKind; if ((clauseKind != RhEHClauseKind.RH_EH_CLAUSE_FAULT) || !ehClause.ContainsCodeOffset(codeOffset)) { continue; } // Found a containing clause. Because of the order of the clauses, we know this is the // most containing. // N.B. -- We need to suppress GC "in-between" calls to finallys in this loop because we do // not have the correct next-execution point live on the stack and, therefore, may cause a GC // hole if we allow a GC between invocation of finally funclets (i.e. after one has returned // here to the dispatcher, but before the next one is invoked). Once they are running, it's // fine for them to trigger a GC, obviously. // // As a result, RhpCallFinallyFunclet will set this state in the runtime upon return from the // funclet, and we need to reset it if/when we fall out of the loop and we know that the // method will no longer get any more GC callbacks. byte *pFinallyHandler = ehClause._handlerAddress; exInfo._idxCurClause = curIdx; InternalCalls.RhpCallFinallyFunclet(pFinallyHandler, exInfo._frameIter.RegisterSet); exInfo._idxCurClause = MaxTryRegionIdx; } }