Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[NativeAOT] Linux/ARM bring-up (4/n) #97269

Merged
merged 16 commits into from
Jan 25, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/coreclr/nativeaot/Runtime/StackFrameIterator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -609,6 +609,8 @@ void StackFrameIterator::InternalInit(Thread * pThreadToWalk, NATIVE_CONTEXT* pC

m_RegDisplay.pR0 = (PTR_UIntNative)PTR_TO_REG(pCtx, R0);
m_RegDisplay.pR1 = (PTR_UIntNative)PTR_TO_REG(pCtx, R1);
m_RegDisplay.pR2 = (PTR_UIntNative)PTR_TO_REG(pCtx, R2);
m_RegDisplay.pR3 = (PTR_UIntNative)PTR_TO_REG(pCtx, R3);
m_RegDisplay.pR4 = (PTR_UIntNative)PTR_TO_REG(pCtx, R4);
m_RegDisplay.pR5 = (PTR_UIntNative)PTR_TO_REG(pCtx, R5);
m_RegDisplay.pR6 = (PTR_UIntNative)PTR_TO_REG(pCtx, R6);
Expand Down
108 changes: 106 additions & 2 deletions src/coreclr/nativeaot/Runtime/arm/GcProbe.S
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,103 @@
#include "AsmOffsets.inc"

.global RhpGcPoll2
.global RhpThrowHwEx

// See PUSH_COOP_PINVOKE_FRAME, this macro is very similar, but also saves return registers
// and accepts the register bitmask
// Call this macro first in the method (no further prolog instructions can be added after this).
//
// threadReg : register containing the Thread* (this will be preserved).
// trashReg : register that can be trashed by this macro
// BITMASK : value to initialize m_dwFlags field with (register or #constant)
.macro PUSH_PROBE_FRAME threadReg, trashReg, BITMASK
// Define the method prolog, allocating enough stack space for the PInvokeTransitionFrame and saving
// incoming register values into it.
PROLOG_STACK_ALLOC 4 // Space for saved APSR
PROLOG_VPUSH "{d0-d3}" // Save floating point return registers
PROLOG_PUSH "{r0-r3,lr}" // Save volatile registers
filipnavara marked this conversation as resolved.
Show resolved Hide resolved
PROLOG_STACK_ALLOC 4 // Space for caller's SP
PROLOG_PUSH "{r4-r6,r8-r10}" // Save non-volatile registers
PROLOG_STACK_ALLOC 8 // Space for flags and Thread*
PROLOG_PUSH "{r7}" // Save caller's frame pointer
PROLOG_PUSH "{r11,lr}" // Save frame-chain pointer and return address

str \threadReg, [sp, #OFFSETOF__PInvokeTransitionFrame__m_pThread]
mov \trashReg, \BITMASK
str \trashReg, [sp, #OFFSETOF__PInvokeTransitionFrame__m_Flags]

// Compute SP value at entry to this method and save it in slot of the frame.
add \trashReg, sp, #(22 * 4)
str \trashReg, [sp, #(11 * 4)]

// Link the frame into the Thread
str sp, [\threadReg, #OFFSETOF__Thread__m_pDeferredTransitionFrame]
.endm

//
// Remove the frame from a previous call to PUSH_PROBE_FRAME from the top of the stack and restore preserved
// registers and return value to their values from before the probe was called (while also updating any
// object refs or byrefs).
//
.macro POP_PROBE_FRAME
EPILOG_POP "{r11,lr}" // Restore frame-chain pointer and return address
EPILOG_POP "{r7}" // Restore caller's frame pointer
EPILOG_STACK_FREE 8 // Discard flags and Thread*
EPILOG_POP "{r4-r6,r8-r10}" // Restore non-volatile registers
EPILOG_STACK_FREE 4 // Discard caller's SP
EPILOG_POP "{r0-r3,lr}" // Restore volatile registers
EPILOG_VPOP "{d0-d3}" // Restore floating point return registers
EPILOG_STACK_FREE 4 // Space for saved APSR
.endm

//
// The prolog for all GC suspension hijacks (normal and stress). Fixes up the hijacked return address, and
// clears the hijack state.
//
// Register state on entry:
// All registers correct for return to the original return address.
//
// Register state on exit:
// r2: thread pointer
// r12: trashed
//
.macro FixupHijackedCallstack
mov r12, r0

// r0 <- GetThread()
INLINE_GETTHREAD

mov r2, r0
mov r0, r12

// Fix the stack by restoring the original return address
ldr lr, [r2, #OFFSETOF__Thread__m_pvHijackedReturnAddress]

// Clear hijack state
mov r12, #0
str r12, [r2, #OFFSETOF__Thread__m_ppvHijackedReturnAddressLocation]
str r12, [r2, #OFFSETOF__Thread__m_pvHijackedReturnAddress]
.endm

NESTED_ENTRY RhpWaitForGC, _TEXT, NoHandler
PUSH_PROBE_FRAME r2, r3, r12

ldr r0, [r2, #OFFSETOF__Thread__m_pDeferredTransitionFrame]
bl RhpWaitForGC2

ldr r2, [sp, #OFFSETOF__PInvokeTransitionFrame__m_Flags]
tst r2, #PTFF_THREAD_ABORT
bne LOCAL_LABEL(ThrowThreadAbort)

POP_PROBE_FRAME
bx lr

LOCAL_LABEL(ThrowThreadAbort):
POP_PROBE_FRAME
mov r0, #STATUS_REDHAWK_THREAD_ABORT
mov r1, lr // return address as exception PC
b C_FUNC(RhpThrowHwEx)
NESTED_END RhpWaitForGC

LEAF_ENTRY RhpGcPoll
PREPARE_EXTERNAL_VAR_INDIRECT RhpTrapThreads, r0
Expand All @@ -24,8 +121,15 @@ NESTED_ENTRY RhpGcPollRare, _TEXT, NoHandler
NESTED_END RhpGcPollRare

NESTED_ENTRY RhpGcProbeHijack, _TEXT, NoHandler
// Not implemented
EMIT_BREAKPOINT
FixupHijackedCallstack

PREPARE_EXTERNAL_VAR_INDIRECT RhpTrapThreads, r3
tst r3, #TrapThreadsFlags_None
bne LOCAL_LABEL(WaitForGC)
bx lr
LOCAL_LABEL(WaitForGC):
mov r12, #(DEFAULT_FRAME_SAVE_FLAGS + PTFF_SAVE_R0)
b RhpWaitForGC
NESTED_END RhpGcProbeHijack

#ifdef FEATURE_GC_STRESS
Expand Down
4 changes: 4 additions & 0 deletions src/coreclr/nativeaot/Runtime/unix/UnixContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,8 @@
#define MCREG_Lr(mc) ((mc).arm_lr)
#define MCREG_R0(mc) ((mc).arm_r0)
#define MCREG_R1(mc) ((mc).arm_r1)
#define MCREG_R2(mc) ((mc).arm_r2)
#define MCREG_R3(mc) ((mc).arm_r3)
#define MCREG_R4(mc) ((mc).arm_r4)
#define MCREG_R5(mc) ((mc).arm_r5)
#define MCREG_R6(mc) ((mc).arm_r6)
Expand Down Expand Up @@ -514,6 +516,8 @@ uint64_t GetPC(void* context)
uint64_t& UNIX_CONTEXT::Lr(){ return (uint64_t&)MCREG_Lr(ctx.uc_mcontext); }
uint64_t& UNIX_CONTEXT::R0(){ return (uint64_t&)MCREG_R0(ctx.uc_mcontext); }
uint64_t& UNIX_CONTEXT::R1(){ return (uint64_t&)MCREG_R1(ctx.uc_mcontext); }
uint64_t& UNIX_CONTEXT::R2(){ return (uint64_t&)MCREG_R2(ctx.uc_mcontext); }
uint64_t& UNIX_CONTEXT::R3(){ return (uint64_t&)MCREG_R3(ctx.uc_mcontext); }
uint64_t& UNIX_CONTEXT::R4(){ return (uint64_t&)MCREG_R4(ctx.uc_mcontext); }
uint64_t& UNIX_CONTEXT::R5(){ return (uint64_t&)MCREG_R5(ctx.uc_mcontext); }
uint64_t& UNIX_CONTEXT::R6(){ return (uint64_t&)MCREG_R6(ctx.uc_mcontext); }
Expand Down
2 changes: 2 additions & 0 deletions src/coreclr/nativeaot/Runtime/unix/UnixContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,8 @@ struct UNIX_CONTEXT
uint64_t& Lr();
uint64_t& R0();
uint64_t& R1();
uint64_t& R2();
uint64_t& R3();
uint64_t& R4();
uint64_t& R5();
uint64_t& R6();
Expand Down
19 changes: 16 additions & 3 deletions src/coreclr/nativeaot/Runtime/unix/UnixNativeCodeManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -775,13 +775,25 @@ bool UnixNativeCodeManager::GetReturnAddressHijackInfo(MethodInfo * pMethodIn

// Decode the GC info for the current method to determine its return type
GcInfoDecoderFlags flags = DECODE_RETURN_KIND;
#if defined(TARGET_ARM) || defined(TARGET_ARM64)
uint32_t codeOffset = 0;
#if defined(TARGET_ARM)
PTR_UInt8 gcInfo;
codeOffset = GetCodeOffset(pMethodInfo, (PTR_VOID)pRegisterSet->IP, &gcInfo);
flags = (GcInfoDecoderFlags)(flags | DECODE_HAS_TAILCALLS | DECODE_INTERRUPTIBILITY);
#elif defined(TARGET_ARM64)
flags = (GcInfoDecoderFlags)(flags | DECODE_HAS_TAILCALLS);
#endif // TARGET_ARM || TARGET_ARM64

GcInfoDecoder decoder(GCInfoToken(p), flags);
GcInfoDecoder decoder(GCInfoToken(p), flags, codeOffset);
*pRetValueKind = GetGcRefKind(decoder.GetReturnKind());

#if defined(TARGET_ARM)
// FIXME: Figure out how to encode this correctly or implement TrailingEpilogueInstructionsCount
if (!decoder.IsInterruptible())
{
return false;
}
filipnavara marked this conversation as resolved.
Show resolved Hide resolved
#else
int epilogueInstructions = TrailingEpilogueInstructionsCount(pMethodInfo, (PTR_VOID)pRegisterSet->IP);
if (epilogueInstructions < 0)
{
Expand All @@ -793,6 +805,7 @@ bool UnixNativeCodeManager::GetReturnAddressHijackInfo(MethodInfo * pMethodIn
*ppvRetAddrLocation = (PTR_PTR_VOID)(pRegisterSet->GetSP() + (sizeof(TADDR) * (epilogueInstructions - 1)));
return true;
}
#endif

#if defined(TARGET_APPLE) && defined(TARGET_ARM64)
// If we are inside a prolog without a saved frame then we cannot safely unwind.
Expand Down Expand Up @@ -822,7 +835,7 @@ bool UnixNativeCodeManager::GetReturnAddressHijackInfo(MethodInfo * pMethodIn
*ppvRetAddrLocation = (PTR_PTR_VOID)(pRegisterSet->GetSP() - sizeof(TADDR));
return true;

#elif defined(TARGET_ARM64)
#elif defined(TARGET_ARM64) || defined(TARGET_ARM)

if (decoder.HasTailCalls())
{
Expand Down
3 changes: 3 additions & 0 deletions src/coreclr/nativeaot/Runtime/unix/unixasmmacros.inc
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@

#define INVALIDGCVALUE 0xCCCCCCCD

// This must match HwExceptionCode.STATUS_REDHAWK_THREAD_ABORT
#define STATUS_REDHAWK_THREAD_ABORT 0x43

// Enforce subsections via symbols to workaround bugs in Xcode 15 linker.
#if defined(__APPLE__)
.subsections_via_symbols
Expand Down
3 changes: 0 additions & 3 deletions src/coreclr/nativeaot/Runtime/unix/unixasmmacrosamd64.inc
Original file line number Diff line number Diff line change
Expand Up @@ -252,9 +252,6 @@ C_FUNC(\Name):
#define TSF_SuppressGcStress 0x08
#define TSF_DoNotTriggerGc 0x10

// This must match HwExceptionCode.STATUS_REDHAWK_THREAD_ABORT
#define STATUS_REDHAWK_THREAD_ABORT 0x43

//
// Rename fields of nested structs
//
Expand Down
2 changes: 2 additions & 0 deletions src/coreclr/nativeaot/Runtime/unix/unixasmmacrosarm.inc
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
#define PTFF_SAVE_ALL_PRESERVED 0x0000007F // NOTE: R11 is not included in this set!
#define PTFF_SAVE_SP 0x00000100
#define PTFF_SAVE_R0 0x00000200
#define PTFF_THREAD_ABORT 0x00100000

#define DEFAULT_FRAME_SAVE_FLAGS (PTFF_SAVE_ALL_PRESERVED + PTFF_SAVE_SP)

// These must match the TrapThreadsFlags enum
Expand Down
3 changes: 0 additions & 3 deletions src/coreclr/nativeaot/Runtime/unix/unixasmmacrosarm64.inc
Original file line number Diff line number Diff line change
Expand Up @@ -372,9 +372,6 @@ PTFF_THREAD_ABORT_BIT = 36
TrapThreadsFlags_AbortInProgress_Bit = 0
TrapThreadsFlags_TrapThreads_Bit = 1

// This must match HwExceptionCode.STATUS_REDHAWK_THREAD_ABORT
#define STATUS_REDHAWK_THREAD_ABORT 0x43

// These must match the TrapThreadsFlags enum
#define TrapThreadsFlags_None 0
#define TrapThreadsFlags_AbortInProgress 1
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -216,5 +216,14 @@ public void EmitRETIfEqual()
EmitBNE(4);
EmitRET();
}

// beq label(+4): ret(2) + next(2)
// bx lr
// label: ...
public void EmitRETIfNotEqual()
{
EmitBEQ(4);
EmitRET();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,18 @@ protected void EmitDictionaryLookup(NodeFactory factory, ref ARMEmitter encoder,

// Load the generic dictionary cell
encoder.EmitLDR(result, context, dictionarySlot * factory.Target.PointerSize);

// If there's any invalid entries, we need to test for them
//
// Only do this in relocsOnly to make it easier to weed out bugs - the _hasInvalidEntries
filipnavara marked this conversation as resolved.
Show resolved Hide resolved
// flag can change over the course of compilation and the bad slot helper dependency
// should be reported by someone else - the system should not rely on it coming from here.
if (!relocsOnly && _hasInvalidEntries)
{
encoder.EmitCMP(result, 0);
encoder.EmitRETIfNotEqual();
encoder.EmitJMP(GetBadSlotHelper(factory));
}
}

protected sealed override void EmitCode(NodeFactory factory, ref ARMEmitter encoder, bool relocsOnly)
Expand Down
6 changes: 1 addition & 5 deletions src/native/external/llvm-libunwind/src/AddressSpace.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -583,11 +583,7 @@ inline bool LocalAddressSpace::findUnwindSections(pint_t targetAddr,
// `_dl_find_object`. Use _LIBUNWIND_SUPPORT_DWARF_INDEX, because libunwind
// support for _dl_find_object on other unwind formats is not implemented,
// yet.
#if defined(DLFO_STRUCT_HAS_EH_DBASE) & defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
// We expect `_dl_find_object` to return PT_GNU_EH_FRAME.
#if DLFO_EH_SEGMENT_TYPE != PT_GNU_EH_FRAME
#error _dl_find_object retrieves an unexpected section type
#endif
#if defined(DLFO_STRUCT_HAS_EH_DBASE) && defined(_LIBUNWIND_SUPPORT_DWARF_INDEX) && DLFO_EH_SEGMENT_TYPE == PT_GNU_EH_FRAME
// We look-up `dl_find_object` dynamically at runtime to ensure backwards
// compatibility with earlier version of glibc not yet providing it. On older
// systems, we gracefully fallback to `dl_iterate_phdr`. Cache the pointer
Expand Down