1616#include " virtualcallstub.h"
1717#include " utilcode.h"
1818#include " interoplibinterface.h"
19+ #include " corinfo.h"
1920
2021#if defined(TARGET_X86)
2122#define USE_CURRENT_CONTEXT_IN_FILTER
@@ -1773,8 +1774,10 @@ CLRUnwindStatus ExceptionTracker::ProcessOSExceptionNotification(
17731774 // InlinedCallFrames (ICF) are allocated, initialized and linked to the Frame chain
17741775 // by the code generated by the JIT for a method containing a PInvoke.
17751776 //
1776- // JIT generates code that links in the ICF at the start of the method and unlinks it towards
1777- // the method end. Thus, ICF is present on the Frame chain at any given point so long as the
1777+ // On platforms where USE_PER_FRAME_PINVOKE_INIT is not defined,
1778+ // the JIT generates code that links in the ICF
1779+ // at the start of the method and unlinks it towards the method end.
1780+ // Thus, ICF is present on the Frame chain at any given point so long as the
17781781 // method containing the PInvoke is on the stack.
17791782 //
17801783 // Now, if the method containing ICF catches an exception, we will reset the Frame chain
@@ -1812,13 +1815,16 @@ CLRUnwindStatus ExceptionTracker::ProcessOSExceptionNotification(
18121815 // below the callerSP for which we will invoke ExceptionUnwind.
18131816 //
18141817 // Thus, ICF::ExceptionUnwind should not do anything significant. If any of these assumptions
1815- // break, then the next best thing will be to make the JIT link/unlink the frame dynamically.
1818+ // break, then the next best thing will be to make the JIT link/unlink the frame dynamically
18161819 //
1817- // If the current method executing is from precompiled ReadyToRun code, then the above is no longer
1818- // applicable because each PInvoke is wrapped by calls to the JIT_PInvokeBegin and JIT_PInvokeEnd
1819- // helpers, which push and pop the ICF to the current thread. Unlike jitted code, the ICF is not
1820- // linked during the method prolog, and unlinked at the epilog (it looks more like the X64 case) .
1820+ // If the current method executing is from precompiled ReadyToRun code, each PInvoke is wrapped
1821+ // by calls to the JIT_PInvokeBegin and JIT_PInvokeEnd helpers,
1822+ // which push and pop the ICF to the current thread. The ICF is not
1823+ // linked during the method prolog, and unlinked at the epilog.
18211824 // In that case, we need to unlink the ICF during unwinding here.
1825+ // On platforms where USE_PER_FRAME_PINVOKE_INIT is defined, the JIT generates code that links in
1826+ // the ICF immediately before and after a PInvoke in non-IL-stubs, like ReadyToRun.
1827+ // See the usages for USE_PER_FRAME_PINVOKE_INIT for more information.
18221828
18231829 if (fTargetUnwind && (pFrame->GetVTablePtr () == InlinedCallFrame::GetMethodFrameVPtr ()))
18241830 {
@@ -1837,9 +1843,20 @@ CLRUnwindStatus ExceptionTracker::ProcessOSExceptionNotification(
18371843 // to the JIT_PInvokeBegin and JIT_PInvokeEnd helpers, which push and pop the ICF on the thread. The
18381844 // ICF is not linked at the method prolog and unlined at the epilog when running R2R code. Since the
18391845 // JIT_PInvokeEnd helper will be skipped, we need to unlink the ICF here. If the executing method
1840- // has another pinovoke, it will re-link the ICF again when the JIT_PInvokeBegin helper is called
1841-
1842- if (ExecutionManager::IsReadyToRunCode (((InlinedCallFrame*)pFrame)->m_pCallerReturnAddress ))
1846+ // has another pinvoke, it will re-link the ICF again when the JIT_PInvokeBegin helper is called.
1847+
1848+ TADDR returnAddress = ((InlinedCallFrame*)pFrame)->m_pCallerReturnAddress ;
1849+ #ifdef USE_PER_FRAME_PINVOKE_INIT
1850+ // If we're setting up the frame for each P/Invoke for the given platform,
1851+ // then we do this for all P/Invokes except ones in IL stubs.
1852+ // IL stubs link the frame in for the whole stub, so if an exception is thrown during marshalling,
1853+ // the ICF will be on the frame chain and inactive.
1854+ if (returnAddress != NULL && !ExecutionManager::GetCodeMethodDesc (returnAddress)->IsILStub ())
1855+ #else
1856+ // If we aren't setting up the frame for each P/Invoke (instead setting up once per method),
1857+ // then ReadyToRun code is the only code using the per-P/Invoke logic.
1858+ if (ExecutionManager::IsReadyToRunCode (returnAddress))
1859+ #endif
18431860 {
18441861 pICFForUnwindTarget = pICFForUnwindTarget->Next ();
18451862 }
0 commit comments