summaryrefslogtreecommitdiff
path: root/src/vm/threadsuspend.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/vm/threadsuspend.cpp')
-rw-r--r--src/vm/threadsuspend.cpp106
1 files changed, 103 insertions, 3 deletions
diff --git a/src/vm/threadsuspend.cpp b/src/vm/threadsuspend.cpp
index 10ea699faa..5d414192c4 100644
--- a/src/vm/threadsuspend.cpp
+++ b/src/vm/threadsuspend.cpp
@@ -7260,7 +7260,7 @@ void STDCALL OnHijackInteriorPointerWorker(HijackArgs * pArgs)
GC_ON_TRANSITIONS (GCOnTransition);
}
#endif
- pArgs->ReturnValue = (size_t)ptr;
+ *(size_t*)&pArgs->ReturnValue = (size_t)ptr;
}
GCPROTECT_END(); // trashes or here!
@@ -7327,6 +7327,90 @@ void STDCALL OnHijackScalarWorker(HijackArgs * pArgs)
#endif
}
+#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)
+{
+ CONTRACTL {
+ THROWS;
+ GC_TRIGGERS;
+ SO_TOLERANT;
+ } CONTRACTL_END;
+
+#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++)
+ {
+ if (eeClass->GetEightByteClassification(i) == SystemVClassificationTypeIntegerReference)
+ {
+ oref[orefCount++] = ObjectToOBJECTREF(*(Object **) &pArgs->ReturnValue[i]);
+ }
+ }
+
+#ifdef FEATURE_STACK_PROBE
+ if (GetEEPolicy()->GetActionOnFailure(FAIL_StackOverflow) == eRudeUnloadAppDomain)
+ {
+ RetailStackProbe(ADJUST_PROBE(DEFAULT_ENTRY_PROBE_AMOUNT), thread);
+ }
+#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)
+ {
+#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
+
+ // Update the references in the returned struct
+ orefCount = 0;
+ for (int i = 0; i < eeClass->GetNumberEightBytes(); i++)
+ {
+ if (eeClass->GetEightByteClassification(i) == SystemVClassificationTypeIntegerReference)
+ {
+ *((OBJECTREF *) &pArgs->ReturnValue[i]) = oref[orefCount++];
+ }
+ }
+ }
+ GCPROTECT_END();
+
+ frame.Pop();
+#else
+ PORTABILITY_ASSERT("OnHijackInteriorPointerWorker not implemented on this platform.");
+#endif
+}
+#endif // FEATURE_UNIX_AMD64_STRUCT_PASSING
+
#ifndef PLATFORM_UNIX
// Get the ExecutionState for the specified SwitchIn thread. Note that this is
@@ -7806,11 +7890,19 @@ BOOL Thread::HandledJITCase(BOOL ForTaskSwitchIn)
else
#endif // _TARGET_X86_
{
- MetaSig::RETURNTYPE type = esb.m_pFD->ReturnsObject();
+ 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
}
}
@@ -8354,7 +8446,8 @@ void PALAPI HandleGCSuspensionForInterruptedThread(CONTEXT *interruptedContext)
// Hijack the return address to point to the appropriate routine based on the method's return type.
void *pvHijackAddr = OnHijackScalarTripThread;
MethodDesc *pMethodDesc = codeInfo.GetMethodDesc();
- MetaSig::RETURNTYPE type = pMethodDesc->ReturnsObject();
+ MethodTable* pMT = NULL;
+ MetaSig::RETURNTYPE type = pMethodDesc->ReturnsObject(INDEBUG_COMMA(false) &pMT);
if (type == MetaSig::RETOBJ)
{
pvHijackAddr = OnHijackObjectTripThread;
@@ -8363,6 +8456,13 @@ void PALAPI HandleGCSuspensionForInterruptedThread(CONTEXT *interruptedContext)
{
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
pThread->HijackThread(pvHijackAddr, &executionState);
}