version = AsmExternal;
}
}
+ else version (AArch64)
+ {
+ version (Posix)
+ {
+ version = AsmAArch64_Posix;
+ version = AsmExternal;
+ version = AlignFiberStackTo16Byte;
+ }
+ }
else version (ARM)
{
version (Posix)
// Look above the definition of 'class Fiber' for some information about the implementation of this routine
version (AsmExternal)
- extern (C) void fiber_switchContext( void** oldp, void* newp ) nothrow @nogc;
+ {
+ extern (C) void fiber_switchContext( void** oldp, void* newp ) nothrow @nogc;
+ version (AArch64)
+ extern (C) void fiber_trampoline() nothrow;
+ }
else
extern (C) void fiber_switchContext( void** oldp, void* newp ) nothrow @nogc
{
pstack -= ABOVE;
*cast(size_t*)(pstack - SZ_RA) = cast(size_t)&fiber_entryPoint;
}
+ else version (AsmAArch64_Posix)
+ {
+ // Like others, FP registers and return address (lr) are kept
+ // below the saved stack top (tstack) to hide from GC scanning.
+ // fiber_switchContext expects newp sp to look like this:
+ // 19: x19
+ // ...
+ // 9: x29 (fp) <-- newp tstack
+ // 8: x30 (lr) [&fiber_entryPoint]
+ // 7: d8
+ // ...
+ // 0: d15
+
+ version (StackGrowsDown) {}
+ else
+ static assert(false, "Only full descending stacks supported on AArch64");
+
+ // Only need to set return address (lr). Everything else is fine
+ // zero initialized.
+ pstack -= size_t.sizeof * 11; // skip past x19-x29
+ push(cast(size_t) &fiber_trampoline); // see threadasm.S for docs
+ pstack += size_t.sizeof; // adjust sp (newp) above lr
+ }
else version (AsmARM_Posix)
{
/* We keep the FP registers and the return address below
*/
.text
.global CSYM(fiber_switchContext)
+ .type fiber_switchContext, %function
.p2align 2
CSYM(fiber_switchContext):
stp d15, d14, [sp, #-20*8]!
ldp d15, d14, [sp], #20*8
ret
+
+/**
+ * When generating any kind of backtrace (gdb, exception handling) for
+ * a function called in a Fiber, we need to tell the unwinder to stop
+ * at our Fiber main entry point, i.e. we need to mark the bottom of
+ * the call stack. This can be done by clearing the link register lr
+ * prior to calling fiber_entryPoint (i.e. in fiber_switchContext) or
+ * using a .cfi_undefined directive for the link register in the
+ * Fiber entry point. cfi_undefined seems to yield better results in gdb.
+ * Unfortunately we can't place it into fiber_entryPoint using inline
+ * asm, so we use this trampoline instead.
+ */
+ .text
+ .global CSYM(fiber_trampoline)
+ .p2align 2
+ .type fiber_trampoline, %function
+CSYM(fiber_trampoline):
+ .cfi_startproc
+ .cfi_undefined x30
+ // fiber_entryPoint never returns
+ bl fiber_entryPoint
+ .cfi_endproc
+
#elif defined(__MINGW32__)
/************************************************************************************
* GDC MinGW ASM BITS