@@ -289,13 +289,104 @@ bool UnixNativeCodeManager::UnwindStackFrame(MethodInfo * pMethodInfo,
289289 return true ;
290290}
291291
292+ // Convert the return kind that was encoded by RyuJIT to the
293+ // enum used by the runtime.
294+ GCRefKind GetGcRefKind (ReturnKind returnKind)
295+ {
296+ static_assert ((GCRefKind)ReturnKind::RT_Scalar == GCRK_Scalar, " ReturnKind::RT_Scalar does not match GCRK_Scalar" );
297+ static_assert ((GCRefKind)ReturnKind::RT_Object == GCRK_Object, " ReturnKind::RT_Object does not match GCRK_Object" );
298+ static_assert ((GCRefKind)ReturnKind::RT_ByRef == GCRK_Byref, " ReturnKind::RT_ByRef does not match GCRK_Byref" );
299+ ASSERT ((returnKind == RT_Scalar) || (returnKind == RT_Object) || (returnKind == RT_ByRef));
300+
301+ return (GCRefKind)returnKind;
302+ }
303+
292304bool UnixNativeCodeManager::GetReturnAddressHijackInfo (MethodInfo * pMethodInfo,
293305 REGDISPLAY * pRegisterSet, // in
294306 PTR_PTR_VOID * ppvRetAddrLocation, // out
295307 GCRefKind * pRetValueKind) // out
296308{
297- // @TODO: GetReturnAddressHijackInfo
309+ UnixNativeMethodInfo* pNativeMethodInfo = (UnixNativeMethodInfo*)pMethodInfo;
310+
311+ PTR_UInt8 p = pNativeMethodInfo->pMainLSDA ;
312+
313+ uint8_t unwindBlockFlags = *p++;
314+
315+ if ((unwindBlockFlags & UBF_FUNC_HAS_ASSOCIATED_DATA) != 0 )
316+ p += sizeof (int32_t );
317+
318+ // Check whether this is a funclet
319+ if ((unwindBlockFlags & UBF_FUNC_KIND_MASK) != UBF_FUNC_KIND_ROOT)
320+ return false ;
321+
322+ // Skip hijacking a reverse-pinvoke method - it doesn't get us much because we already synchronize
323+ // with the GC on the way back to native code.
324+ if ((unwindBlockFlags & UBF_FUNC_REVERSE_PINVOKE) != 0 )
325+ return false ;
326+
327+ if ((unwindBlockFlags & UBF_FUNC_HAS_EHINFO) != 0 )
328+ p += sizeof (int32_t );
329+
330+ // Decode the GC info for the current method to determine its return type
331+ GcInfoDecoderFlags flags = DECODE_RETURN_KIND;
332+ #if defined(TARGET_ARM) || defined(TARGET_ARM64)
333+ flags = (GcInfoDecoderFlags)(flags | DECODE_HAS_TAILCALLS);
334+ #endif // TARGET_ARM || TARGET_ARM64
335+ GcInfoDecoder decoder (GCInfoToken (p), flags);
336+
337+ GCRefKind gcRefKind = GetGcRefKind (decoder.GetReturnKind ());
338+
339+ // Unwind the current method context to the caller's context to get its stack pointer
340+ // and obtain the location of the return address on the stack
341+ #if defined(TARGET_AMD64)
342+
343+ if (!VirtualUnwind (pRegisterSet))
344+ {
345+ return false ;
346+ }
347+
348+ *ppvRetAddrLocation = (PTR_PTR_VOID)(pRegisterSet->GetSP () - sizeof (TADDR));
349+ *pRetValueKind = gcRefKind;
350+ return true ;
351+
352+ #elif defined(TARGET_ARM64)
353+
354+ if (decoder.HasTailCalls ())
355+ {
356+ // Do not hijack functions that have tail calls, since there are two problems:
357+ // 1. When a function that tail calls another one is hijacked, the LR may be
358+ // stored at a different location in the stack frame of the tail call target.
359+ // So just by performing tail call, the hijacked location becomes invalid and
360+ // unhijacking would corrupt stack by writing to that location.
361+ // 2. There is a small window after the caller pops LR from the stack in its
362+ // epilog and before the tail called function pushes LR in its prolog when
363+ // the hijacked return address would not be not on the stack and so we would
364+ // not be able to unhijack.
365+ return false ;
366+ }
367+
368+ PTR_UIntNative pLR = pRegisterSet->pLR ;
369+ if (!VirtualUnwind (pRegisterSet))
370+ {
371+ return false ;
372+ }
373+
374+ if (pRegisterSet->pLR == pLR)
375+ {
376+ // This is the case when we are either:
377+ //
378+ // 1) In a leaf method that does not push LR on stack, OR
379+ // 2) In the prolog/epilog of a non-leaf method that has not yet pushed LR on stack
380+ // or has LR already popped off.
381+ return false ;
382+ }
383+
384+ *ppvRetAddrLocation = (PTR_PTR_VOID)pRegisterSet->pLR ;
385+ *pRetValueKind = gcRefKind;
386+ return true ;
387+ #else
298388 return false ;
389+ #endif // defined(TARGET_AMD64)
299390}
300391
301392PTR_VOID UnixNativeCodeManager::RemapHardwareFaultToGCSafePoint (MethodInfo * pMethodInfo, PTR_VOID controlPC)
0 commit comments