16
16
#include "virtualcallstub.h"
17
17
#include "utilcode.h"
18
18
#include "interoplibinterface.h"
19
+ #include "corinfo.h"
19
20
20
21
#if defined(TARGET_X86)
21
22
#define USE_CURRENT_CONTEXT_IN_FILTER
@@ -1776,8 +1777,10 @@ CLRUnwindStatus ExceptionTracker::ProcessOSExceptionNotification(
1776
1777
// InlinedCallFrames (ICF) are allocated, initialized and linked to the Frame chain
1777
1778
// by the code generated by the JIT for a method containing a PInvoke.
1778
1779
//
1779
- // JIT generates code that links in the ICF at the start of the method and unlinks it towards
1780
- // the method end. Thus, ICF is present on the Frame chain at any given point so long as the
1780
+ // On platforms where USE_PER_FRAME_PINVOKE_INIT is not defined,
1781
+ // the JIT generates code that links in the ICF
1782
+ // at the start of the method and unlinks it towards the method end.
1783
+ // Thus, ICF is present on the Frame chain at any given point so long as the
1781
1784
// method containing the PInvoke is on the stack.
1782
1785
//
1783
1786
// Now, if the method containing ICF catches an exception, we will reset the Frame chain
@@ -1815,13 +1818,16 @@ CLRUnwindStatus ExceptionTracker::ProcessOSExceptionNotification(
1815
1818
// below the callerSP for which we will invoke ExceptionUnwind.
1816
1819
//
1817
1820
// Thus, ICF::ExceptionUnwind should not do anything significant. If any of these assumptions
1818
- // break, then the next best thing will be to make the JIT link/unlink the frame dynamically.
1821
+ // break, then the next best thing will be to make the JIT link/unlink the frame dynamically
1819
1822
//
1820
- // If the current method executing is from precompiled ReadyToRun code, then the above is no longer
1821
- // applicable because each PInvoke is wrapped by calls to the JIT_PInvokeBegin and JIT_PInvokeEnd
1822
- // helpers, which push and pop the ICF to the current thread. Unlike jitted code, the ICF is not
1823
- // linked during the method prolog, and unlinked at the epilog (it looks more like the X64 case) .
1823
+ // If the current method executing is from precompiled ReadyToRun code, each PInvoke is wrapped
1824
+ // by calls to the JIT_PInvokeBegin and JIT_PInvokeEnd helpers,
1825
+ // which push and pop the ICF to the current thread. The ICF is not
1826
+ // linked during the method prolog, and unlinked at the epilog.
1824
1827
// In that case, we need to unlink the ICF during unwinding here.
1828
+ // On platforms where USE_PER_FRAME_PINVOKE_INIT is defined, the JIT generates code that links in
1829
+ // the ICF immediately before and after a PInvoke in non-IL-stubs, like ReadyToRun.
1830
+ // See the usages for USE_PER_FRAME_PINVOKE_INIT for more information.
1825
1831
1826
1832
if (fTargetUnwind && (pFrame->GetVTablePtr() == InlinedCallFrame::GetMethodFrameVPtr()))
1827
1833
{
@@ -1830,8 +1836,12 @@ CLRUnwindStatus ExceptionTracker::ProcessOSExceptionNotification(
1830
1836
//
1831
1837
// 1) ICF address is higher than the current frame's SP (which we get from DispatcherContext), AND
1832
1838
// 2) ICF address is below callerSP.
1833
- if ((GetSP(pDispatcherContext->ContextRecord) < (TADDR)pICF) &&
1834
- ((UINT_PTR)pICF < uCallerSP))
1839
+ // 3) ICF is active.
1840
+ // - IL stubs link the frame in for the whole stub, so if an exception is thrown during marshalling,
1841
+ // the ICF will be on the frame chain and inactive.
1842
+ if ((GetSP(pDispatcherContext->ContextRecord) < (TADDR)pICF)
1843
+ && ((UINT_PTR)pICF < uCallerSP)
1844
+ && InlinedCallFrame::FrameHasActiveCall(pICF))
1835
1845
{
1836
1846
pICFForUnwindTarget = pFrame;
1837
1847
@@ -1840,9 +1850,18 @@ CLRUnwindStatus ExceptionTracker::ProcessOSExceptionNotification(
1840
1850
// to the JIT_PInvokeBegin and JIT_PInvokeEnd helpers, which push and pop the ICF on the thread. The
1841
1851
// ICF is not linked at the method prolog and unlined at the epilog when running R2R code. Since the
1842
1852
// JIT_PInvokeEnd helper will be skipped, we need to unlink the ICF here. If the executing method
1843
- // has another pinovoke , it will re-link the ICF again when the JIT_PInvokeBegin helper is called
1853
+ // has another pinvoke , it will re-link the ICF again when the JIT_PInvokeBegin helper is called.
1844
1854
1845
- if (ExecutionManager::IsReadyToRunCode(((InlinedCallFrame*)pFrame)->m_pCallerReturnAddress))
1855
+ TADDR returnAddress = ((InlinedCallFrame*)pFrame)->m_pCallerReturnAddress;
1856
+ #ifdef USE_PER_FRAME_PINVOKE_INIT
1857
+ // If we're setting up the frame for each P/Invoke for the given platform,
1858
+ // then we do this for all P/Invokes except ones in IL stubs.
1859
+ if (!ExecutionManager::GetCodeMethodDesc(returnAddress)->IsILStub())
1860
+ #else
1861
+ // If we aren't setting up the frame for each P/Invoke (instead setting up once per method),
1862
+ // then ReadyToRun code is the only code using the per-P/Invoke logic.
1863
+ if (ExecutionManager::IsReadyToRunCode(returnAddress))
1864
+ #endif
1846
1865
{
1847
1866
pICFForUnwindTarget = pICFForUnwindTarget->Next();
1848
1867
}
0 commit comments