summaryrefslogtreecommitdiff
path: root/src/vm/threadsuspend.cpp
diff options
context:
space:
mode:
authorSwaroop Sridhar <swaroops@microsoft.com>2016-07-20 16:50:22 -0700
committerSwaroop Sridhar <swaroops@microsoft.com>2016-08-05 14:05:55 -0700
commitd302e64bcb4ea445f6702c529f8a964df20ab494 (patch)
tree6fda2c392acf1d44aa4222ed6d9813533c455a0a /src/vm/threadsuspend.cpp
parent5b0953d50e9d0c6e388643210476d6a95a55a247 (diff)
downloadcoreclr-d302e64bcb4ea445f6702c529f8a964df20ab494.tar.gz
coreclr-d302e64bcb4ea445f6702c529f8a964df20ab494.tar.bz2
coreclr-d302e64bcb4ea445f6702c529f8a964df20ab494.zip
Implement GcInfo v2
Ref #4379 This change implements GcInfo version 2 for all platforms that use the GcInfo library (all architectures other than X86). Changes are: 1) Defines ReturnKind enumeration for all platforms 2) Change the GcInfo encoder library to encode the ReturnKind and ReversePInvokeFrame slot 3) Change the CM's GcInfo decoder to encode the ReturnKind and ReversePInvokeFrame slot for GCINFO_VERSION 2 4) Some corrections to GCINFO_MEASUREments 5) Changes to RYU Jit to provide the correct information to the encoder 6) Changes to the VM to use the ReturnKind information while hijacking a thread - If ReturnKind is available from GcInfo, new hijack routines are used - Otherwise, fall back to old method (for compatibility) 7) Rework and simplify the thread hijack routines by scanning HijackFrames directly for gcroots 8) Supporting code to implement the above features. Returning Structs in multiple registers Hijacking for StructInRegs is currently only implemented for Unix SystemV ABI Multi-reg struct returns. However, the hijack-workers that use ReturnKind are ready to handle other platforms (ex: ARM/ARM64 Windows) once the corresponding HijackTripThread() assembly routines are defined. The New feature flag: FEATURE_MULTIREG_RETURN is set for platforms where a struct value can be returned in multiple registers [ex: Windows/Unix ARM/ARM64, Unix-AMD64] FEATURE_UNIX_AMD64_STRUCT_PASSING is a specific kind of FEATURE_MULTIREG_RETURN specified by SystemV ABI for AMD64 Compatibility with other JITs - All new GCInfo generated by RYU Jit is in GcInfo version 2 - All Ngen images must be regenerated with the new GcInfo version. - Ready-to-run images with old GcInfo will continue to work. - Jit64/X64 uses the GcInfo library, so it generates GcInfo version 2. However, it doesn't (yet) provide the data to encode the correct ReturnKind Similar is the case for ARM32 code running on JIT32, and any other JITs that may be using GcInfo library but not yet modified to use the new API. So, compatibility is achived using RT_Unset flag. When ReturnKind is RT_Unset, it means that the JIT did not set the ReturnKind in the GCInfo, and therefore the VM cannot rely on it, and must use other mechanisms (similar to GcInfo ver 1) to determine the Return type's GC information. Implement GC root scanning for Hijack-frames This change implements GCScanRoots() method for Hijacke-frames based on the ReturnKind information available from the GcInfo. If the exact ReturnKind is not available in the GcInfo, the thread-suspension logic will compute the ReturnKind based on the method-signature. As a result of this change, several hijack-helpers in the VM are cleaned up. There's only one implementation of HijackWorker() to handle all returnKinds. This change also simplifies the thread-hijack logic by using a single assembly helper OnHijackTripThread() in most cases. The only other helper used is for X86 floating point return values for save/restoring the top of the FP stack. ARM64 Only GcIndfo v2 is reliably supported for ARM64 platform. The changes to thread-hijack mechanism fixes #6494 for ARM64. No measurable change in JIT throughput, performance or native-image size from this change.
Diffstat (limited to 'src/vm/threadsuspend.cpp')
-rw-r--r--src/vm/threadsuspend.cpp381
1 files changed, 115 insertions, 266 deletions
diff --git a/src/vm/threadsuspend.cpp b/src/vm/threadsuspend.cpp
index 6d25012bbd..2cf32dfb6b 100644
--- a/src/vm/threadsuspend.cpp
+++ b/src/vm/threadsuspend.cpp
@@ -6948,8 +6948,7 @@ void Thread::UnhijackThread()
// Can't make the following assertion, because sometimes we unhijack after
// the hijack has tripped (i.e. in the case we actually got some value from
// it.
-// _ASSERTE(*m_ppvHJRetAddrPtr == OnHijackObjectTripThread ||
-// *m_ppvHJRetAddrPtr == OnHijackScalarTripThread);
+// _ASSERTE(*m_ppvHJRetAddrPtr == OnHijackTripThread);
STRESS_LOG2(LF_SYNC, LL_INFO100, "Unhijacking return address 0x%p for thread %p\n", m_pvHJRetAddr, this);
// restore the return address and clear the flag
@@ -7147,31 +7146,30 @@ HijackFrame::HijackFrame(LPVOID returnAddress, Thread *thread, HijackArgs *args)
m_Thread->SetFrame(this);
}
-// A hijacked method is returning an ObjectRef to its caller. Note that we bash the
-// return address in HijackArgs.
-void STDCALL OnHijackObjectWorker(HijackArgs * pArgs)
+void STDCALL OnHijackWorker(HijackArgs * pArgs)
{
- CONTRACTL {
+ CONTRACTL{
THROWS;
GC_TRIGGERS;
SO_TOLERANT;
}
CONTRACTL_END;
+#ifdef HIJACK_NONINTERRUPTIBLE_THREADS
Thread *thread = GetThread();
#ifdef FEATURE_STACK_PROBE
if (GetEEPolicy()->GetActionOnFailure(FAIL_StackOverflow) == eRudeUnloadAppDomain)
{
+ // Make sure default domain does not see SO.
+ // probe for our entry point amount and throw if not enough stack
RetailStackProbe(ADJUST_PROBE(DEFAULT_ENTRY_PROBE_AMOUNT), thread);
}
-#endif
+#endif // FEATURE_STACK_PROBE
CONTRACT_VIOLATION(SOToleranceViolation);
-#ifdef HIJACK_NONINTERRUPTIBLE_THREADS
- OBJECTREF oref(ObjectToOBJECTREF(*(Object **) &pArgs->ReturnValue));
- FastInterlockAnd((ULONG *) &thread->m_State, ~Thread::TS_Hijacked);
+ thread->ResetThreadState(Thread::TS_Hijacked);
// Fix up our caller's stack, so it can resume from the hijack correctly
pArgs->ReturnAddress = (size_t)thread->m_pvHJRetAddr;
@@ -7180,238 +7178,148 @@ void STDCALL OnHijackObjectWorker(HijackArgs * pArgs)
// we will resume execution.
FrameWithCookie<HijackFrame> frame((void *)pArgs->ReturnAddress, thread, pArgs);
- GCPROTECT_BEGIN(oref)
- {
#ifdef _DEBUG
- BOOL GCOnTransition = FALSE;
- if (g_pConfig->FastGCStressLevel()) {
- GCOnTransition = GC_ON_TRANSITIONS (FALSE);
- }
-#endif
+ BOOL GCOnTransition = FALSE;
+ if (g_pConfig->FastGCStressLevel()) {
+ GCOnTransition = GC_ON_TRANSITIONS(FALSE);
+ }
+#endif // _DEBUG
#ifdef TIME_SUSPEND
- g_SuspendStatistics.cntHijackTrap++;
-#endif
+ g_SuspendStatistics.cntHijackTrap++;
+#endif // TIME_SUSPEND
+
+ CommonTripThread();
- CommonTripThread();
#ifdef _DEBUG
- if (g_pConfig->FastGCStressLevel()) {
- GC_ON_TRANSITIONS (GCOnTransition);
- }
-#endif
- *((OBJECTREF *) &pArgs->ReturnValue) = oref;
+ if (g_pConfig->FastGCStressLevel()) {
+ GC_ON_TRANSITIONS(GCOnTransition);
}
- GCPROTECT_END(); // trashes oref here!
+#endif // _DEBUG
frame.Pop();
#else
- PORTABILITY_ASSERT("OnHijackObjectWorker not implemented on this platform.");
-#endif
+ PORTABILITY_ASSERT("OnHijackWorker not implemented on this platform.");
+#endif // HIJACK_NONINTERRUPTIBLE_THREADS
}
-// A hijacked method is returning an ObjectRef to its caller. Note that we bash the
-// return address in HijackObjectArgs.
-void STDCALL OnHijackInteriorPointerWorker(HijackArgs * pArgs)
+ReturnKind GetReturnKindFromMethodTable(Thread *pThread, EECodeInfo *codeInfo)
{
- CONTRACTL {
- THROWS;
- GC_TRIGGERS;
- SO_TOLERANT;
- } CONTRACTL_END;
-
-#ifdef HIJACK_NONINTERRUPTIBLE_THREADS
- Thread *thread = GetThread();
- void* ptr = (void*)(pArgs->ReturnValue);
-
-#ifdef FEATURE_STACK_PROBE
- if (GetEEPolicy()->GetActionOnFailure(FAIL_StackOverflow) == eRudeUnloadAppDomain)
- {
- RetailStackProbe(ADJUST_PROBE(DEFAULT_ENTRY_PROBE_AMOUNT), thread);
- }
-#endif
-
- CONTRACT_VIOLATION(SOToleranceViolation);
-
- FastInterlockAnd((ULONG *) &thread->m_State, ~Thread::TS_Hijacked);
+#ifdef _WIN64
+ // For simplicity, we don't hijack in funclets, but if you ever change that,
+ // be sure to choose the OnHijack... callback type to match that of the FUNCLET
+ // not the main method (it would probably be Scalar).
+#endif // _WIN64
- // Fix up our caller's stack, so it can resume from the hijack correctly
- pArgs->ReturnAddress = (size_t)thread->m_pvHJRetAddr;
+ ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE();
+ // Mark that we are performing a stackwalker like operation on the current thread.
+ // This is necessary to allow the signature parsing functions to work without triggering any loads
+ ClrFlsValueSwitch threadStackWalking(TlsIdx_StackWalkerWalkingThread, pThread);
- // Build a frame so that stack crawling can proceed from here back to where
- // we will resume execution.
- FrameWithCookie<HijackFrame> frame((void *)pArgs->ReturnAddress, thread, pArgs);
+ MethodDesc *methodDesc = codeInfo->GetMethodDesc();
+ _ASSERTE(methodDesc != nullptr);
- GCPROTECT_BEGININTERIOR(ptr)
+#ifdef _TARGET_X86_
+ MetaSig msig(methodDesc);
+ if (msig.HasFPReturn())
{
-#ifdef _DEBUG
- BOOL GCOnTransition = FALSE;
- if (g_pConfig->FastGCStressLevel()) {
- GCOnTransition = GC_ON_TRANSITIONS (FALSE);
- }
-#endif
-
-#ifdef TIME_SUSPEND
- g_SuspendStatistics.cntHijackTrap++;
-#endif
-
- CommonTripThread();
-#ifdef _DEBUG
- if (g_pConfig->FastGCStressLevel()) {
- GC_ON_TRANSITIONS (GCOnTransition);
- }
-#endif
- *(size_t*)&pArgs->ReturnValue = (size_t)ptr;
+ // Figuring out whether the function returns FP or not is hard to do
+ // on-the-fly, so we use a different callback helper on x86 where this
+ // piece of information is needed in order to perform the right save &
+ // restore of the return value around the call to OnHijackScalarWorker.
+ return RT_Float;
}
- GCPROTECT_END(); // trashes or here!
-
- frame.Pop();
-#else
- PORTABILITY_ASSERT("OnHijackInteriorPointerWorker not implemented on this platform.");
-#endif
-}
-
-// A hijacked method is returning a scalar to its caller. Note that we bash the
-// return address as an int on the stack. Since this is cdecl, our caller gets the
-// bashed value. This is not intuitive for C programmers!
-void STDCALL OnHijackScalarWorker(HijackArgs * pArgs)
-{
- CONTRACTL {
- THROWS;
- GC_TRIGGERS;
- SO_TOLERANT;
- } CONTRACTL_END;
-
-#ifdef HIJACK_NONINTERRUPTIBLE_THREADS
- Thread *thread = GetThread();
+#endif // _TARGET_X86_
-#ifdef FEATURE_STACK_PROBE
- if (GetEEPolicy()->GetActionOnFailure(FAIL_StackOverflow) == eRudeUnloadAppDomain)
+ MethodTable* pMT = NULL;
+ MetaSig::RETURNTYPE type = methodDesc->ReturnsObject(INDEBUG_COMMA(false) &pMT);
+ if (type == MetaSig::RETOBJ)
{
- // Make sure default domain does not see SO.
- // probe for our entry point amount and throw if not enough stack
- RetailStackProbe(ADJUST_PROBE(DEFAULT_ENTRY_PROBE_AMOUNT), thread);
+ return RT_Object;
}
-#endif
- CONTRACT_VIOLATION(SOToleranceViolation);
- FastInterlockAnd((ULONG *) &thread->m_State, ~Thread::TS_Hijacked);
-
- // Fix up our caller's stack, so it can resume from the hijack correctly
- pArgs->ReturnAddress = (size_t)thread->m_pvHJRetAddr;
-
- // Build a frame so that stack crawling can proceed from here back to where
- // we will resume execution.
- FrameWithCookie<HijackFrame> frame((void *)pArgs->ReturnAddress, thread, pArgs);
-
-#ifdef _DEBUG
- BOOL GCOnTransition = FALSE;
- if (g_pConfig->FastGCStressLevel()) {
- GCOnTransition = GC_ON_TRANSITIONS (FALSE);
+ if (type == MetaSig::RETBYREF)
+ {
+ return RT_ByRef;
}
-#endif
-
-#ifdef TIME_SUSPEND
- g_SuspendStatistics.cntHijackTrap++;
-#endif
- CommonTripThread();
-#ifdef _DEBUG
- if (g_pConfig->FastGCStressLevel()) {
- GC_ON_TRANSITIONS (GCOnTransition);
+#ifdef FEATURE_UNIX_AMD64_STRUCT_PASSING
+ // The Multi-reg return case using the classhandle is only implemented for AMD64 SystemV ABI.
+ // On other platforms, multi-reg return is not supported with GcInfo v1.
+ // So, the relevant information must be obtained from the GcInfo tables (which requires version2).
+ if (type == MetaSig::RETVALUETYPE)
+ {
+ EEClass *eeClass = pMT->GetClass();
+ ReturnKind regKinds[2] = { RT_Unset, RT_Unset };
+ int orefCount = 0;
+ for (int i = 0; i < 2; i++)
+ {
+ if (eeClass->GetEightByteClassification(i) == SystemVClassificationTypeIntegerReference)
+ {
+ regKinds[i] = RT_Object;
+ }
+ else if (eeClass->GetEightByteClassification(i) == SystemVClassificationTypeIntegerByRef)
+ {
+ regKinds[i] = RT_ByRef;
+ }
+ else
+ {
+ regKinds[i] = RT_Scalar;
+ }
+ }
+ ReturnKind structReturnKind = GetStructReturnKind(regKinds[0], regKinds[1]);
+ return structReturnKind;
}
-#endif
+#endif // FEATURE_UNIX_AMD64_STRUCT_PASSING
- frame.Pop();
-#else
- PORTABILITY_ASSERT("OnHijackScalarWorker not implemented on this platform.");
-#endif
+ return RT_Scalar;
}
-#ifdef FEATURE_UNIX_AMD64_STRUCT_PASSING
-// A hijacked method is returning a struct in registers to its caller.
-// The struct can possibly contain object references that we have to
-// protect.
-void STDCALL OnHijackStructInRegsWorker(HijackArgs * pArgs)
+ReturnKind GetReturnKind(Thread *pThread, EECodeInfo *codeInfo)
{
- CONTRACTL {
- THROWS;
- GC_TRIGGERS;
- SO_TOLERANT;
- } CONTRACTL_END;
+ ReturnKind returnKind = RT_Illegal;
-#ifdef HIJACK_NONINTERRUPTIBLE_THREADS
- Thread *thread = GetThread();
-
- EEClass* eeClass = thread->GetHijackReturnTypeClass();
-
- OBJECTREF oref[CLR_SYSTEMV_MAX_EIGHTBYTES_COUNT_TO_PASS_IN_REGISTERS];
- int orefCount = 0;
- for (int i = 0; i < eeClass->GetNumberEightBytes(); i++)
+#ifdef _TARGET_X86_
+ // X86 GCInfo updates yet to be implemented.
+#else
+ GCInfoToken gcInfoToken = codeInfo->GetGCInfoToken();
+ if (gcInfoToken.IsReturnKindAvailable())
{
- if ((eeClass->GetEightByteClassification(i) == SystemVClassificationTypeIntegerReference) ||
- (eeClass->GetEightByteClassification(i) == SystemVClassificationTypeIntegerByRef))
- {
- oref[orefCount++] = ObjectToOBJECTREF(*(Object **) &pArgs->ReturnValue[i]);
- }
+ GcInfoDecoder gcInfoDecoder(gcInfoToken, DECODE_RETURN_KIND);
+ ReturnKind returnKind = gcInfoDecoder.GetReturnKind();
}
+#endif // _TARGET_X86_
-#ifdef FEATURE_STACK_PROBE
- if (GetEEPolicy()->GetActionOnFailure(FAIL_StackOverflow) == eRudeUnloadAppDomain)
+ if (!IsValidReturnKind(returnKind))
{
- RetailStackProbe(ADJUST_PROBE(DEFAULT_ENTRY_PROBE_AMOUNT), thread);
+ returnKind = GetReturnKindFromMethodTable(pThread, codeInfo);
}
-#endif
-
- CONTRACT_VIOLATION(SOToleranceViolation);
-
- thread->ResetThreadState(Thread::TS_Hijacked);
-
- // Fix up our caller's stack, so it can resume from the hijack correctly
- pArgs->ReturnAddress = (size_t)thread->m_pvHJRetAddr;
-
- // Build a frame so that stack crawling can proceed from here back to where
- // we will resume execution.
- FrameWithCookie<HijackFrame> frame((void *)pArgs->ReturnAddress, thread, pArgs);
-
- GCPROTECT_ARRAY_BEGIN(oref[0], orefCount)
+ else
{
-#ifdef _DEBUG
- BOOL GCOnTransition = FALSE;
- if (g_pConfig->FastGCStressLevel()) {
- GCOnTransition = GC_ON_TRANSITIONS (FALSE);
- }
-#endif
+#if !defined(FEATURE_MULTIREG_RETURN) || defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
+ // For ARM64 struct-return, GetReturnKindFromMethodTable() is not supported
+ _ASSERTE(returnKind == GetReturnKindFromMethodTable(pThread, codeInfo));
+#endif // !FEATURE_MULTIREG_RETURN || FEATURE_UNIX_AMD64_STRUCT_PASSING
+ }
-#ifdef TIME_SUSPEND
- g_SuspendStatistics.cntHijackTrap++;
-#endif
+ _ASSERTE(IsValidReturnKind(returnKind));
+ return returnKind;
+}
- CommonTripThread();
-#ifdef _DEBUG
- if (g_pConfig->FastGCStressLevel()) {
- GC_ON_TRANSITIONS (GCOnTransition);
- }
-#endif
+VOID * GetHijackAddr(Thread *pThread, EECodeInfo *codeInfo)
+{
+ ReturnKind returnKind = GetReturnKind(pThread, codeInfo);
+ pThread->SetHijackReturnKind(returnKind);
- // Update the references in the returned struct
- orefCount = 0;
- for (int i = 0; i < eeClass->GetNumberEightBytes(); i++)
- {
- if ((eeClass->GetEightByteClassification(i) == SystemVClassificationTypeIntegerReference) ||
- (eeClass->GetEightByteClassification(i) == SystemVClassificationTypeIntegerByRef))
- {
- *((OBJECTREF *) &pArgs->ReturnValue[i]) = oref[orefCount++];
- }
- }
+#ifdef _TARGET_X86_
+ if (returnKind == RT_Float)
+ {
+ return OnHijackFPTripThread;
}
- GCPROTECT_END();
+#endif // _TARGET_X86_
- frame.Pop();
-#else
- PORTABILITY_ASSERT("OnHijackInteriorPointerWorker not implemented on this platform.");
-#endif
+ return OnHijackTripThread;
}
-#endif // FEATURE_UNIX_AMD64_STRUCT_PASSING
#ifndef PLATFORM_UNIX
@@ -7801,11 +7709,12 @@ BOOL Thread::HandledJITCase(BOOL ForTaskSwitchIn)
return FALSE;
}
- if (!ExecutionManager::IsManagedCode(GetIP(&ctx)))
+ PCODE ip = GetIP(&ctx);
+ if (!ExecutionManager::IsManagedCode(ip))
{
return FALSE;
}
-
+
#ifdef WORKAROUND_RACES_WITH_KERNEL_MODE_EXCEPTION_HANDLING
if (ThreadCaughtInKernelModeExceptionHandling(this, &ctx))
{
@@ -7865,48 +7774,8 @@ BOOL Thread::HandledJITCase(BOOL ForTaskSwitchIn)
// we need to hijack the return address. Base this on whether or not
// the method returns an object reference, so we know whether to protect
// it or not.
- VOID *pvHijackAddr = OnHijackScalarTripThread;
- if (esb.m_pFD)
- {
-#ifdef _WIN64
- // For simplicity, we don't hijack in funclets, but if you ever change that,
- // be sure to choose the OnHijack... callback type to match that of the FUNCLET
- // not the main method (it would probably be Scalar).
-#endif // _WIN64
-
- ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE();
- // Mark that we are performing a stackwalker like operation on the current thread.
- // This is necessary to allow the signature parsing functions to work without triggering any loads
- ClrFlsValueSwitch threadStackWalking(TlsIdx_StackWalkerWalkingThread, this);
-
-#ifdef _TARGET_X86_
- MetaSig msig(esb.m_pFD);
- if (msig.HasFPReturn())
- {
- // Figuring out whether the function returns FP or not is hard to do
- // on-the-fly, so we use a different callback helper on x86 where this
- // piece of information is needed in order to perform the right save &
- // restore of the return value around the call to OnHijackScalarWorker.
- pvHijackAddr = OnHijackFloatingPointTripThread;
- }
- else
-#endif // _TARGET_X86_
- {
- MethodTable* pMT = NULL;
- MetaSig::RETURNTYPE type = esb.m_pFD->ReturnsObject(INDEBUG_COMMA(false) &pMT);
- if (type == MetaSig::RETOBJ)
- pvHijackAddr = OnHijackObjectTripThread;
- else if (type == MetaSig::RETBYREF)
- pvHijackAddr = OnHijackInteriorPointerTripThread;
-#ifdef FEATURE_UNIX_AMD64_STRUCT_PASSING
- else if (type == MetaSig::RETVALUETYPE)
- {
- pThread->SetHijackReturnTypeClass(pMT->GetClass());
- pvHijackAddr = OnHijackStructInRegsTripThread;
- }
-#endif // FEATURE_UNIX_AMD64_STRUCT_PASSING
- }
- }
+ EECodeInfo codeInfo(ip);
+ VOID *pvHijackAddr = GetHijackAddr(this, &codeInfo);
#ifdef FEATURE_ENABLE_GCPOLL
// On platforms that support both hijacking and GC polling
@@ -7919,7 +7788,6 @@ BOOL Thread::HandledJITCase(BOOL ForTaskSwitchIn)
{
HijackThread(pvHijackAddr, &esb);
}
-
}
}
// else it's not even a JIT case
@@ -8455,26 +8323,7 @@ void PALAPI HandleGCSuspensionForInterruptedThread(CONTEXT *interruptedContext)
ClrFlsValueSwitch threadStackWalking(TlsIdx_StackWalkerWalkingThread, pThread);
// Hijack the return address to point to the appropriate routine based on the method's return type.
- void *pvHijackAddr = reinterpret_cast<void*>(OnHijackScalarTripThread);
- MethodDesc *pMethodDesc = codeInfo.GetMethodDesc();
- MethodTable* pMT = NULL;
- MetaSig::RETURNTYPE type = pMethodDesc->ReturnsObject(INDEBUG_COMMA(false) &pMT);
- if (type == MetaSig::RETOBJ)
- {
- pvHijackAddr = reinterpret_cast<void*>(OnHijackObjectTripThread);
- }
- else if (type == MetaSig::RETBYREF)
- {
- pvHijackAddr = reinterpret_cast<void*>(OnHijackInteriorPointerTripThread);
- }
-#ifdef FEATURE_UNIX_AMD64_STRUCT_PASSING
- else if (type == MetaSig::RETVALUETYPE)
- {
- pThread->SetHijackReturnTypeClass(pMT->GetClass());
- pvHijackAddr = reinterpret_cast<void*>(OnHijackStructInRegsTripThread);
- }
-#endif // FEATURE_UNIX_AMD64_STRUCT_PASSING
-
+ void *pvHijackAddr = GetHijackAddr(pThread, &codeInfo);
pThread->HijackThread(pvHijackAddr, &executionState);
}
}