-//Licensed to the .NET Foundation under one or more agreements.
+// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+#include "asmconstants.h"
#include "unixasmmacros.inc"
-NESTED_ENTRY FuncEvalHijack, _TEXT, FuncEvalHijackPersonalityRoutine
+//
+// hijacking stub used to perform a func-eval, see Debugger::FuncEvalSetup() for use.
+//
+// on entry:
+// x0 : pointer to DebuggerEval object
+//
-// NOTE: FuncEvalHijackPersonalityRoutine is dependent on the stack layout so if
-// you change the prolog you will also need to update the personality routine.
+// @dbgtodo- once we port Funceval, use the ExceptionHijack stub instead of this func-eval stub.
+NESTED_ENTRY FuncEvalHijack, _TEXT, UnhandledExceptionHandlerUnix
-// push arg to the stack so our personality routine can find it
-// push lr to get good stacktrace in debugger
+ // NOTE: FuncEvalHijackPersonalityRoutine is dependent on the stack layout so if
+ // you change the prolog you will also need to update the personality routine.
-PROLOG_SAVE_REG_PAIR fp, lr, #-32
+ // push arg to the stack so our personality routine can find it
+ // push lr to get good stacktrace in debugger
+ PROLOG_SAVE_REG_PAIR_INDEXED fp, lr, -32
+ str x0, [sp, #16]
+ // FuncEvalHijackWorker returns the address we should jump to.
+ bl FuncEvalHijackWorker
+
+ EPILOG_STACK_FREE 32
+ EPILOG_BRANCH_REG x0
+NESTED_END FuncEvalHijack
+
+// This is the general purpose hijacking stub. The DacDbi Hijack primitive will
+// set up the stack and then set the IP here, and so this just makes the call.
+NESTED_ENTRY ExceptionHijack, _TEXT, UnhandledExceptionHandlerUnix
+
+ // make the call
+ bl ExceptionHijackWorker
+
+ // effective NOP to terminate unwind
+ mov x3, x3
+
+ // *** should never get here ***
+ EMIT_BREAKPOINT
+
+// exported label so the debugger knows where the end of this function is
+PATCH_LABEL ExceptionHijackEnd
+
+NESTED_END ExceptionHijack, _TEXT
- str x0, [sp, #16]
- // FuncEvalHijackWorker returns the address we should jump to.
- bl FuncEvalHijackWorker
-
- EPILOG_STACK_FREE 32
- EPILOG_BRANCH_REG x0
-NESTED_END FuncEvalHijack, _TEXT
-//NESTED_ENTRY ExceptionHijack,,ExceptionHijackPersonalityRoutine
\ No newline at end of file
if(CLR_CMAKE_PLATFORM_ARCH_AMD64 OR CLR_CMAKE_PLATFORM_ARCH_ARM OR CLR_CMAKE_PLATFORM_ARCH_ARM64 OR CLR_CMAKE_PLATFORM_ARCH_I386)
add_library_clr(cordbee_wks ${CORDBEE_SOURCES_WKS} ../${ARCH_SOURCES_DIR}/dbghelpers.S)
elseif(CLR_CMAKE_PLATFORM_ARCH_ARM64)
- add_library_clr(cordbee_wks ${CORDBEE_SOURCES_WKS})
+ add_library_clr(cordbee_wks ${CORDBEE_SOURCES_WKS} ../${ARCH_SOURCES_DIR}/dbghelpers.S)
else()
message(FATAL_ERROR "Only ARM and AMD64 is supported")
endif()
.endm
.macro LEAF_END_MARKED Name, Section
- .global C_FUNC(\Name\()_End)
C_FUNC(\Name\()_End):
+ .global C_FUNC(\Name\()_End)
LEAF_END \Name, \Section
.endm
.macro EPILOG_STACK_FREE Size
add sp, sp, \Size
+ .cfi_adjust_cfa_offset -\Size
.endm
.macro EPILOG_STACK_RESTORE
mov sp, fp
+ .cfi_restore sp
.endm
.macro PROLOG_SAVE_REG reg, ofs
str \reg, [sp, \ofs]
+ .cfi_rel_offset \reg, \ofs
.endm
.macro PROLOG_SAVE_REG_PAIR reg1, reg2, ofs
stp \reg1, \reg2, [sp, \ofs]
+ .cfi_rel_offset \reg1, \ofs
+ .cfi_rel_offset \reg2, \ofs + 8
.ifc \reg1, fp
mov fp, sp
.endif
.macro PROLOG_SAVE_REG_PAIR_INDEXED reg1, reg2, ofs
stp \reg1, \reg2, [sp, \ofs]!
+ .cfi_adjust_cfa_offset -\ofs
+ .cfi_rel_offset \reg1, 0
+ .cfi_rel_offset \reg2, 8
.ifc \reg1, fp
mov fp, sp
.endif
.macro EPILOG_RESTORE_REG reg, ofs
ldr \reg, [sp, \ofs]
+ .cfi_restore \reg1
.endm
.macro EPILOG_RESTORE_REG_PAIR reg1, reg2, ofs
ldp \reg1, \reg2, [sp, \ofs]
+ .cfi_restore \reg1
+ .cfi_restore \reg2
.endm
.macro EPILOG_RESTORE_REG_PAIR_INDEXED reg1, reg2, ofs
ldp \reg1, \reg2, [sp], \ofs
+ .cfi_restore \reg1
+ .cfi_restore \reg2
+ .cfi_adjust_cfa_offset -\ofs
.endm
.macro EPILOG_RETURN
//-----------------------------------------------------------------------------
// Define the prolog for a TransitionFrame-based method. This macro should be called first in the method and
-// comprises the entire prolog (i.e. don't modify SP after calling this).The locals must be 8 byte aligned
+// comprises the entire prolog (i.e. don't modify SP after calling this).The locals must be 8 byte aligned
//
// Stack layout:
//
// (stack parameters)
// ...
// fp
-// lr
+// lr
// CalleeSavedRegisters::x28
// CalleeSavedRegisters::x27
// CalleeSavedRegisters::x26
.macro PROLOG_WITH_TRANSITION_BLOCK extraLocals = 0, SaveFPArgs = 1
__PWTB_FloatArgumentRegisters = \extraLocals
+ __PWTB_SaveFPArgs = \SaveFPArgs
.if ((__PWTB_FloatArgumentRegisters % 16) != 0)
__PWTB_FloatArgumentRegisters = __PWTB_FloatArgumentRegisters + 8
__PWTB_TransitionBlock = __PWTB_FloatArgumentRegisters
- .if \SaveFPArgs > 0
+ .if (__PWTB_SaveFPArgs == 1)
__PWTB_TransitionBlock = __PWTB_TransitionBlock + SIZEOF__FloatArgumentRegisters
.endif
__PWTB_StackAlloc = __PWTB_TransitionBlock
- __PWTB_ArgumentRegisters = __PWTB_StackAlloc + 96
-
- PROLOG_SAVE_REG_PAIR_INDEXED fp, lr, #-160
- // Spill callee saved registers
- PROLOG_SAVE_REG_PAIR x19, x20, #16
- PROLOG_SAVE_REG_PAIR x21, x22, #32
- PROLOG_SAVE_REG_PAIR x23, x24, #48
- PROLOG_SAVE_REG_PAIR x25, x26, #64
- PROLOG_SAVE_REG_PAIR x27, x28, #80
-
+ __PWTB_ArgumentRegisters = __PWTB_StackAlloc + 96
+
+ PROLOG_SAVE_REG_PAIR_INDEXED fp, lr, -176
+ // Spill callee saved registers
+ PROLOG_SAVE_REG_PAIR x19, x20, 16
+ PROLOG_SAVE_REG_PAIR x21, x22, 32
+ PROLOG_SAVE_REG_PAIR x23, x24, 48
+ PROLOG_SAVE_REG_PAIR x25, x26, 64
+ PROLOG_SAVE_REG_PAIR x27, x28, 80
+
// Allocate space for the rest of the frame
PROLOG_STACK_ALLOC __PWTB_StackAlloc
-
+
// Spill argument registers.
SAVE_ARGUMENT_REGISTERS sp, __PWTB_ArgumentRegisters
- .if \SaveFPArgs > 0
+ .if (__PWTB_SaveFPArgs == 1)
SAVE_FLOAT_ARGUMENT_REGISTERS sp, \extraLocals
.endif
.endm
//-----------------------------------------------------------------------------
-// The Following sets of SAVE_*_REGISTERS expect the memory to be reserved and
+// The Following sets of SAVE_*_REGISTERS expect the memory to be reserved and
// base address to be passed in $reg
//
// Reserve 64 bytes of memory before calling SAVE_ARGUMENT_REGISTERS
-.macro SAVE_ARGUMENT_REGISTERS reg, ofs
+.macro SAVE_ARGUMENT_REGISTERS reg, ofs
stp x0, x1, [\reg, #(\ofs)]
+ .cfi_rel_offset x0, \ofs
+ .cfi_rel_offset x1, \ofs + 8
stp x2, x3, [\reg, #(\ofs + 16)]
+ .cfi_rel_offset x2, \ofs + 16
+ .cfi_rel_offset x3, \ofs + 24
stp x4, x5, [\reg, #(\ofs + 32)]
+ .cfi_rel_offset x4, \ofs + 32
+ .cfi_rel_offset x5, \ofs + 40
stp x6, x7, [\reg, #(\ofs + 48)]
+ .cfi_rel_offset x6, \ofs + 48
+ .cfi_rel_offset x7, \ofs + 56
+ str x8, [\reg, #(\ofs + 64)]
+ .cfi_rel_offset x8, \ofs + 64
.endm
// Reserve 64 bytes of memory before calling SAVE_FLOAT_ARGUMENT_REGISTERS
-.macro SAVE_FLOAT_ARGUMENT_REGISTERS reg, ofs
+.macro SAVE_FLOAT_ARGUMENT_REGISTERS reg, ofs
stp d0, d1, [\reg, #(\ofs)]
+ .cfi_rel_offset d0, \ofs + 0
+ .cfi_rel_offset d1, \ofs + 8
stp d2, d3, [\reg, #(\ofs + 16)]
+ .cfi_rel_offset d2, \ofs + 16
+ .cfi_rel_offset d3, \ofs + 24
stp d4, d5, [\reg, #(\ofs + 32)]
+ .cfi_rel_offset d4, \ofs + 32
+ .cfi_rel_offset d5, \ofs + 40
stp d6, d7, [\reg, #(\ofs + 48)]
+ .cfi_rel_offset d6, \ofs + 48
+ .cfi_rel_offset d7, \ofs + 56
.endm
-.macro RESTORE_ARGUMENT_REGISTERS reg, ofs
+.macro RESTORE_ARGUMENT_REGISTERS reg, ofs
ldp x0, x1, [\reg, #(\ofs)]
+ .cfi_restore x0
+ .cfi_restore x1
ldp x2, x3, [\reg, #(\ofs + 16)]
+ .cfi_restore x2
+ .cfi_restore x3
ldp x4, x5, [\reg, #(\ofs + 32)]
+ .cfi_restore x4
+ .cfi_restore x5
ldp x6, x7, [\reg, #(\ofs + 48)]
+ .cfi_restore x6
+ .cfi_restore x7
+ ldr x8, [\reg, #(\ofs + 64)]
+ .cfi_restore x8
.endm
-.macro RESTORE_FLOAT_ARGUMENT_REGISTERS reg, ofs
+.macro RESTORE_FLOAT_ARGUMENT_REGISTERS reg, ofs
ldp d0, d1, [\reg, #(\ofs)]
+ .cfi_restore d0
+ .cfi_restore d1
ldp d2, d3, [\reg, #(\ofs + 16)]
+ .cfi_restore d2
+ .cfi_restore d3
ldp d4, d5, [\reg, #(\ofs + 32)]
+ .cfi_restore d4
+ .cfi_restore d5
ldp d6, d7, [\reg, #(\ofs + 48)]
+ .cfi_restore d6
+ .cfi_restore d7
+
+.endm
+.macro EPILOG_BRANCH Target
+ b \Target
.endm
.macro EPILOG_BRANCH_REG reg
.endm
-//-----------------------------------------------------------------------------
-// Provides a matching epilog to PROLOG_WITH_TRANSITION_BLOCK and ends by preparing for tail-calling.
-// Since this is a tail call argument registers are restored.
-//
-.macro EPILOG_WITH_TRANSITION_BLOCK_TAILCALL extraLocals = 0, SaveFPArgs =1
- __PWTB_FloatArgumentRegisters = \extraLocals
+.macro EPILOG_WITH_TRANSITION_BLOCK_RETURN
- .if ((__PWTB_FloatArgumentRegisters % 16) != 0)
- __PWTB_FloatArgumentRegisters = __PWTB_FloatArgumentRegisters + 8
- .endif
+ EPILOG_STACK_FREE __PWTB_StackAlloc
- __PWTB_TransitionBlock = __PWTB_FloatArgumentRegisters
+ EPILOG_RESTORE_REG_PAIR x19, x20, 16
+ EPILOG_RESTORE_REG_PAIR x21, x22, 32
+ EPILOG_RESTORE_REG_PAIR x23, x24, 48
+ EPILOG_RESTORE_REG_PAIR x25, x26, 64
+ EPILOG_RESTORE_REG_PAIR x27, x28, 80
+ EPILOG_RESTORE_REG_PAIR_INDEXED fp, lr, 176
+ ret
- .if \SaveFPArgs > 0
- __PWTB_TransitionBlock = __PWTB_TransitionBlock + SIZEOF__FloatArgumentRegisters
- .endif
+.endm
- __PWTB_StackAlloc = __PWTB_TransitionBlock
- __PWTB_ArgumentRegisters = __PWTB_StackAlloc + 96
- .if \SaveFPArgs > 0
- RESTORE_FLOAT_ARGUMENT_REGISTERS sp, __PWTB_FloatArgumentRegisters
+//-----------------------------------------------------------------------------
+// Provides a matching epilog to PROLOG_WITH_TRANSITION_BLOCK and ends by preparing for tail-calling.
+// Since this is a tail call argument registers are restored.
+//
+.macro EPILOG_WITH_TRANSITION_BLOCK_TAILCALL
+
+ .if (__PWTB_SaveFPArgs == 1)
+ RESTORE_FLOAT_ARGUMENT_REGISTERS sp, __PWTB_FloatArgumentRegisters
.endif
RESTORE_ARGUMENT_REGISTERS sp, __PWTB_ArgumentRegisters
+
EPILOG_STACK_FREE __PWTB_StackAlloc
-
- EPILOG_RESTORE_REG_PAIR x19, x20, #16
- EPILOG_RESTORE_REG_PAIR x21, x22, #32
- EPILOG_RESTORE_REG_PAIR x23, x24, #48
- EPILOG_RESTORE_REG_PAIR x25, x26, #64
- EPILOG_RESTORE_REG_PAIR x27, x28, #80
- EPILOG_RESTORE_REG_PAIR_INDEXED fp, lr, #160
+
+ EPILOG_RESTORE_REG_PAIR x19, x20, 16
+ EPILOG_RESTORE_REG_PAIR x21, x22, 32
+ EPILOG_RESTORE_REG_PAIR x23, x24, 48
+ EPILOG_RESTORE_REG_PAIR x25, x26, 64
+ EPILOG_RESTORE_REG_PAIR x27, x28, 80
+ EPILOG_RESTORE_REG_PAIR_INDEXED fp, lr, 176
.endm
IMPORT $__RedirectionFuncName
NESTED_ENTRY $__RedirectionStubFuncName
- PROLOG_SAVE_REG_PAIR fp, lr, #-16
- sub sp, sp, #16 // stack slot for CONTEXT * and padding
+ PROLOG_SAVE_REG_PAIR fp, lr, -16
+ sub sp, sp, #16 // stack slot for CONTEXT * and padding
//REDIRECTSTUB_SP_OFFSET_CONTEXT is defined in asmconstants.h and is used in GetCONTEXTFromRedirectedStubStackFrame
//If CONTEXT is not saved at 0 offset from SP it must be changed as well.
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#ifndef __PAL_ARM64_ASMCONSTANTS_H__
+#define __PAL_ARM64_ASMCONSTANTS_H__
+
+#define CONTEXT_ARM64 0x00400000L
+
+#define CONTEXT_CONTROL_BIT (0)
+#define CONTEXT_INTEGER_BIT (1)
+#define CONTEXT_FLOATING_POINT_BIT (2)
+#define CONTEXT_DEBUG_REGISTERS_BIT (3)
+
+#define CONTEXT_CONTROL (CONTEXT_ARM64 | (1L << CONTEXT_CONTROL_BIT))
+#define CONTEXT_INTEGER (CONTEXT_ARM64 | (1 << CONTEXT_INTEGER_BIT))
+#define CONTEXT_FLOATING_POINT (CONTEXT_ARM64 | (1 << CONTEXT_FLOATING_POINT_BIT))
+#define CONTEXT_DEBUG_REGISTERS (CONTEXT_ARM64 | (1 << CONTEXT_DEBUG_REGISTERS_BIT))
+
+#define CONTEXT_FULL (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_FLOATING_POINT)
+
+
+#define CONTEXT_ContextFlags 0
+#define CONTEXT_Cpsr CONTEXT_ContextFlags+4
+#define CONTEXT_X0 CONTEXT_Cpsr+4
+#define CONTEXT_X1 CONTEXT_X0+8
+#define CONTEXT_X2 CONTEXT_X1+8
+#define CONTEXT_X3 CONTEXT_X2+8
+#define CONTEXT_X4 CONTEXT_X3+8
+#define CONTEXT_X5 CONTEXT_X4+8
+#define CONTEXT_X6 CONTEXT_X5+8
+#define CONTEXT_X7 CONTEXT_X6+8
+#define CONTEXT_X8 CONTEXT_X7+8
+#define CONTEXT_X9 CONTEXT_X8+8
+#define CONTEXT_X10 CONTEXT_X9+8
+#define CONTEXT_X11 CONTEXT_X10+8
+#define CONTEXT_X12 CONTEXT_X11+8
+#define CONTEXT_X13 CONTEXT_X12+8
+#define CONTEXT_X14 CONTEXT_X13+8
+#define CONTEXT_X15 CONTEXT_X14+8
+#define CONTEXT_X16 CONTEXT_X15+8
+#define CONTEXT_X17 CONTEXT_X16+8
+#define CONTEXT_X18 CONTEXT_X17+8
+#define CONTEXT_X19 CONTEXT_X18+8
+#define CONTEXT_X20 CONTEXT_X19+8
+#define CONTEXT_X21 CONTEXT_X20+8
+#define CONTEXT_X22 CONTEXT_X21+8
+#define CONTEXT_X23 CONTEXT_X22+8
+#define CONTEXT_X24 CONTEXT_X23+8
+#define CONTEXT_X25 CONTEXT_X24+8
+#define CONTEXT_X26 CONTEXT_X25+8
+#define CONTEXT_X27 CONTEXT_X26+8
+#define CONTEXT_X28 CONTEXT_X27+8
+#define CONTEXT_Fp CONTEXT_X28+8
+#define CONTEXT_Lr CONTEXT_Fp+8
+#define CONTEXT_Sp CONTEXT_Lr+8
+#define CONTEXT_Pc CONTEXT_Sp+8
+#define CONTEXT_NEON_OFFSET CONTEXT_Pc+8
+#define CONTEXT_V0 0
+#define CONTEXT_V1 CONTEXT_V0+16
+#define CONTEXT_V2 CONTEXT_V1+16
+#define CONTEXT_V3 CONTEXT_V2+16
+#define CONTEXT_V4 CONTEXT_V3+16
+#define CONTEXT_V5 CONTEXT_V4+16
+#define CONTEXT_V6 CONTEXT_V5+16
+#define CONTEXT_V7 CONTEXT_V6+16
+#define CONTEXT_V8 CONTEXT_V7+16
+#define CONTEXT_V9 CONTEXT_V8+16
+#define CONTEXT_V10 CONTEXT_V9+16
+#define CONTEXT_V11 CONTEXT_V10+16
+#define CONTEXT_V12 CONTEXT_V11+16
+#define CONTEXT_V13 CONTEXT_V12+16
+#define CONTEXT_V14 CONTEXT_V13+16
+#define CONTEXT_V15 CONTEXT_V14+16
+#define CONTEXT_V16 CONTEXT_V15+16
+#define CONTEXT_V17 CONTEXT_V16+16
+#define CONTEXT_V18 CONTEXT_V17+16
+#define CONTEXT_V19 CONTEXT_V18+16
+#define CONTEXT_V20 CONTEXT_V19+16
+#define CONTEXT_V21 CONTEXT_V20+16
+#define CONTEXT_V22 CONTEXT_V21+16
+#define CONTEXT_V23 CONTEXT_V22+16
+#define CONTEXT_V24 CONTEXT_V23+16
+#define CONTEXT_V25 CONTEXT_V24+16
+#define CONTEXT_V26 CONTEXT_V25+16
+#define CONTEXT_V27 CONTEXT_V26+16
+#define CONTEXT_V28 CONTEXT_V27+16
+#define CONTEXT_V29 CONTEXT_V28+16
+#define CONTEXT_V30 CONTEXT_V29+16
+#define CONTEXT_V31 CONTEXT_V30+16
+#define CONTEXT_FLOAT_CONTROL_OFFSET CONTEXT_V31
+#define CONTEXT_Fpcr 0
+#define CONTEXT_Fpsr CONTEXT_Fpcr+4
+
+#endif
//
#include "unixasmmacros.inc"
-
-#define CONTEXT_ARM64 0x00400000L
-
-#define CONTEXT_CONTROL (CONTEXT_ARM64 | 0x1L)
-#define CONTEXT_INTEGER (CONTEXT_ARM64 | 0x2L)
-#define CONTEXT_FLOATING_POINT (CONTEXT_ARM64 | 0x4L)
-#define CONTEXT_DEBUG_REGISTERS (CONTEXT_ARM64 | 0x8L)
-
-#define CONTEXT_FULL (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_FLOATING_POINT)
-
-#define CONTEXT_ContextFlags 0
-#define CONTEXT_Cpsr CONTEXT_ContextFlags+4
-#define CONTEXT_X0 CONTEXT_Cpsr+4
-#define CONTEXT_X1 CONTEXT_X0+8
-#define CONTEXT_X2 CONTEXT_X1+8
-#define CONTEXT_X3 CONTEXT_X2+8
-#define CONTEXT_X4 CONTEXT_X3+8
-#define CONTEXT_X5 CONTEXT_X4+8
-#define CONTEXT_X6 CONTEXT_X5+8
-#define CONTEXT_X7 CONTEXT_X6+8
-#define CONTEXT_X8 CONTEXT_X7+8
-#define CONTEXT_X9 CONTEXT_X8+8
-#define CONTEXT_X10 CONTEXT_X9+8
-#define CONTEXT_X11 CONTEXT_X10+8
-#define CONTEXT_X12 CONTEXT_X11+8
-#define CONTEXT_X13 CONTEXT_X12+8
-#define CONTEXT_X14 CONTEXT_X13+8
-#define CONTEXT_X15 CONTEXT_X14+8
-#define CONTEXT_X16 CONTEXT_X15+8
-#define CONTEXT_X17 CONTEXT_X16+8
-#define CONTEXT_X18 CONTEXT_X17+8
-#define CONTEXT_X19 CONTEXT_X18+8
-#define CONTEXT_X20 CONTEXT_X19+8
-#define CONTEXT_X21 CONTEXT_X20+8
-#define CONTEXT_X22 CONTEXT_X21+8
-#define CONTEXT_X23 CONTEXT_X22+8
-#define CONTEXT_X24 CONTEXT_X23+8
-#define CONTEXT_X25 CONTEXT_X24+8
-#define CONTEXT_X26 CONTEXT_X25+8
-#define CONTEXT_X27 CONTEXT_X26+8
-#define CONTEXT_X28 CONTEXT_X27+8
-#define CONTEXT_Fp CONTEXT_X28+8
-#define CONTEXT_Lr CONTEXT_Fp+8
-#define CONTEXT_Sp CONTEXT_Lr+8
-#define CONTEXT_Pc CONTEXT_Sp+8
-#define CONTEXT_NEON_OFFSET CONTEXT_Pc+8
-#define CONTEXT_V0 0
-#define CONTEXT_V1 CONTEXT_V0+16
-#define CONTEXT_V2 CONTEXT_V1+16
-#define CONTEXT_V3 CONTEXT_V2+16
-#define CONTEXT_V4 CONTEXT_V3+16
-#define CONTEXT_V5 CONTEXT_V4+16
-#define CONTEXT_V6 CONTEXT_V5+16
-#define CONTEXT_V7 CONTEXT_V6+16
-#define CONTEXT_V8 CONTEXT_V7+16
-#define CONTEXT_V9 CONTEXT_V8+16
-#define CONTEXT_V10 CONTEXT_V9+16
-#define CONTEXT_V11 CONTEXT_V10+16
-#define CONTEXT_V12 CONTEXT_V11+16
-#define CONTEXT_V13 CONTEXT_V12+16
-#define CONTEXT_V14 CONTEXT_V13+16
-#define CONTEXT_V15 CONTEXT_V14+16
-#define CONTEXT_V16 CONTEXT_V15+16
-#define CONTEXT_V17 CONTEXT_V16+16
-#define CONTEXT_V18 CONTEXT_V17+16
-#define CONTEXT_V19 CONTEXT_V18+16
-#define CONTEXT_V20 CONTEXT_V19+16
-#define CONTEXT_V21 CONTEXT_V20+16
-#define CONTEXT_V22 CONTEXT_V21+16
-#define CONTEXT_V23 CONTEXT_V22+16
-#define CONTEXT_V24 CONTEXT_V23+16
-#define CONTEXT_V25 CONTEXT_V24+16
-#define CONTEXT_V26 CONTEXT_V25+16
-#define CONTEXT_V27 CONTEXT_V26+16
-#define CONTEXT_V28 CONTEXT_V27+16
-#define CONTEXT_V29 CONTEXT_V28+16
-#define CONTEXT_V30 CONTEXT_V29+16
-#define CONTEXT_V31 CONTEXT_V30+16
-#define CONTEXT_FLOAT_CONTROL_OFFSET CONTEXT_V31
-#define CONTEXT_Fpcr 0
-#define CONTEXT_Fpsr CONTEXT_Fpcr+4
+#include "asmconstants.h"
// Incoming:
// x0: Context*
ldr x2, [sp, 24]
str w2, [x0, CONTEXT_Cpsr]
stp fp, lr, [x0, CONTEXT_Fp]
- add sp, sp, #32
- mov x2, sp
+ add x2, sp, #32
stp x2, lr, [x0, CONTEXT_Sp]
- sub sp, sp, #32
LOCAL_LABEL(Done_CONTEXT_CONTROL):
// we dont clobber x1 in the CONTEXT_CONTROL case
// since we potentially clobber x0 below, we'll bank it in x16
mov x16, x0
- ldr w2, [x16, CONTEXT_ContextFlags]
- // clangs assembler doesn't seem to support the mov Wx, imm32 yet
- movz w3, #0x40, lsl #16
- movk w3, #0x4
- mov w4, w3
- and w3, w2, w3
- cmp w3, w4
- b.ne LOCAL_LABEL(No_Restore_CONTEXT_FLOATING_POINT)
+ ldr w17, [x16, CONTEXT_ContextFlags]
+ tbz w17, #CONTEXT_FLOATING_POINT_BIT, LOCAL_LABEL(No_Restore_CONTEXT_FLOATING_POINT)
add x16, x16, CONTEXT_NEON_OFFSET
ldp q0, q1, [x16, CONTEXT_V0]
sub x16, x16, CONTEXT_NEON_OFFSET
LOCAL_LABEL(No_Restore_CONTEXT_FLOATING_POINT):
- movz w2, #0x40, lsl #16
- movk w2, #0x2
- mov w3, w2
- and w2, w1, w2
- cmp w2, w3
- b.ne LOCAL_LABEL(No_Restore_CONTEXT_INTEGER)
+ tbz w17, #CONTEXT_INTEGER_BIT, LOCAL_LABEL(No_Restore_CONTEXT_INTEGER)
ldp x0, x1, [x16, CONTEXT_X0]
ldp x2, x3, [x16, CONTEXT_X2]
ldr x28, [x16, CONTEXT_X28]
LOCAL_LABEL(No_Restore_CONTEXT_INTEGER):
- movz w2, #0x40, lsl #16
- movk w2, #0x2
- mov w3, w2
- and w2, w1, w2
- cmp w2, w3
- b.ne LOCAL_LABEL(No_Restore_CONTEXT_CONTROL)
+ tbz w17, #CONTEXT_CONTROL_BIT, LOCAL_LABEL(No_Restore_CONTEXT_CONTROL)
ldr w17, [x16, CONTEXT_Cpsr]
msr nzcv, x17
mov sp, x17
ldr x17, [x16, CONTEXT_Pc]
br x17
-
+
LOCAL_LABEL(No_Restore_CONTEXT_CONTROL):
- ret
+ ret
LEAF_END RtlRestoreContext, _TEXT
// See the LICENSE file in the project root for more information.
#include "unixasmmacros.inc"
+#include "asmconstants.h"
+//////////////////////////////////////////////////////////////////////////
+//
+// This function creates a stack frame right below the target frame, restores all callee
+// saved registers, SP, and LR from the passed in context.
+// Then it uses the ThrowExceptionHelper to throw the passed in exception from that context.
+// EXTERN_C void ThrowExceptionFromContextInternal(CONTEXT* context, PAL_SEHException* ex);
LEAF_ENTRY ThrowExceptionFromContextInternal, _TEXT
- EMIT_BREAKPOINT
+ // Save the FP & LR to the stack so that the unwind can work at the instruction after
+ // loading the FP from the context, but before loading the SP from the context.
+ stp fp, lr, [sp, -16]!
+
+ ldp x19,x20, [x0, #(CONTEXT_X19)]
+ ldp x21,x22, [x0, #(CONTEXT_X21)]
+ ldp x23,x24, [x0, #(CONTEXT_X23)]
+ ldp x24,x25, [x0, #(CONTEXT_X24)]
+ ldp x26,x27, [x0, #(CONTEXT_X26)]
+ ldp x28,fp, [x0, #(CONTEXT_X28)]
+ ldr lr, [x0, #(CONTEXT_Pc)]
+ ldr x2, [x0, #(CONTEXT_Sp)]
+ mov sp, x2
+
+ // The PAL_SEHException pointer
+ mov x0, x1
+ b EXTERNAL_C_FUNC(ThrowExceptionHelper)
LEAF_END ThrowExceptionFromContextInternal, _TEXT
GetContextPointer(cursor, unwContext, UNW_AARCH64_X26, &contextPointers->X26);
GetContextPointer(cursor, unwContext, UNW_AARCH64_X27, &contextPointers->X27);
GetContextPointer(cursor, unwContext, UNW_AARCH64_X28, &contextPointers->X28);
+ GetContextPointer(cursor, unwContext, UNW_AARCH64_X29, &contextPointers->Fp);
#else
#error unsupported architecture
#endif
#define MCREG_Sp(mc) ((mc).sp)
#define MCREG_Pc(mc) ((mc).pc)
-#define MCREG_PState(mc) ((mc).pstate)
-#define MCREG_Cpsr(mc) ((mc).cpsr)
+#define MCREG_Cpsr(mc) ((mc).pstate)
#else
// For FreeBSD, as found in x86/ucontext.h
#define MCREG_Rbp(mc) ((mc).mc_rbp)
ASSIGN_REG(R12)
#elif defined(_ARM64_)
#define ASSIGN_CONTROL_REGS \
+ ASSIGN_REG(Cpsr) \
+ ASSIGN_REG(Fp) \
ASSIGN_REG(Sp) \
ASSIGN_REG(Lr) \
ASSIGN_REG(Pc)
typedef struct _ARM64_UNWIND_PARAMS
{
- ULONG_PTR ControlPc;
- PULONG_PTR LowLimit;
- PULONG_PTR HighLimit;
PKNONVOLATILE_CONTEXT_POINTERS ContextPointers;
} ARM64_UNWIND_PARAMS, *PARM64_UNWIND_PARAMS;
#define UNWIND_PARAMS_SET_TRAP_FRAME(Params, Address, Size)
-#define UPDATE_CONTEXT_POINTERS(Params, RegisterNumber, Address)
-#define UPDATE_FP_CONTEXT_POINTERS(Params, RegisterNumber, Address)
+#define UPDATE_CONTEXT_POINTERS(Params, RegisterNumber, Address) \
+do { \
+ if (ARGUMENT_PRESENT(Params)) { \
+ PKNONVOLATILE_CONTEXT_POINTERS ContextPointers = (Params)->ContextPointers; \
+ if (ARGUMENT_PRESENT(ContextPointers)) { \
+ if (RegisterNumber >= 19 && RegisterNumber <= 30) { \
+ (&ContextPointers->X19)[RegisterNumber - 19] = (PDWORD64)Address; \
+ } \
+ } \
+ } \
+} while (0)
+
+
+#define UPDATE_FP_CONTEXT_POINTERS(Params, RegisterNumber, Address) \
+do { \
+ if (ARGUMENT_PRESENT(Params)) { \
+ PKNONVOLATILE_CONTEXT_POINTERS ContextPointers = (Params)->ContextPointers; \
+ if (ARGUMENT_PRESENT(ContextPointers) && \
+ (RegisterNumber >= 8) && \
+ (RegisterNumber <= 15)) { \
+ \
+ (&ContextPointers->D8)[RegisterNumber - 8] = (PDWORD64)Address; \
+ } \
+ } \
+} while (0)
+
#define VALIDATE_STACK_ADDRESS_EX(Params, Context, Address, DataSize, Alignment, OutStatus)
#define VALIDATE_STACK_ADDRESS(Params, Context, DataSize, Alignment, OutStatus)
for (RegIndex = 0; RegIndex < 18; RegIndex++) {
UPDATE_CONTEXT_POINTERS(UnwindParams, RegIndex, SourceAddress);
#ifdef __clang__
- *(&ContextRecord->X0 + (RegIndex * sizeof(void*))) = MEMORY_READ_QWORD(UnwindParams, SourceAddress);
+ *(&ContextRecord->X0 + RegIndex) = MEMORY_READ_QWORD(UnwindParams, SourceAddress);
#else
ContextRecord->X[RegIndex] = MEMORY_READ_QWORD(UnwindParams, SourceAddress);
#endif
for (RegIndex = 0; RegIndex < 29; RegIndex++) {
UPDATE_CONTEXT_POINTERS(UnwindParams, RegIndex, SourceAddress);
#ifdef __clang__
- *(&ContextRecord->X0 + (RegIndex * sizeof(void*))) = MEMORY_READ_QWORD(UnwindParams, SourceAddress);
+ *(&ContextRecord->X0 + RegIndex) = MEMORY_READ_QWORD(UnwindParams, SourceAddress);
#else
ContextRecord->X[RegIndex] = MEMORY_READ_QWORD(UnwindParams, SourceAddress);
#endif
//
for (RegIndex = 0; RegIndex < RegisterCount; RegIndex++) {
- UPDATE_CONTEXT_POINTERS(UnwindParams, RegIndex, CurAddress);
+ UPDATE_CONTEXT_POINTERS(UnwindParams, FirstRegister + RegIndex, CurAddress);
#ifdef __clang__
- *(&ContextRecord->X0 + (RegIndex * sizeof(void*))) = MEMORY_READ_QWORD(UnwindParams, CurAddress);
+ *(&ContextRecord->X0 + FirstRegister + RegIndex) = MEMORY_READ_QWORD(UnwindParams, CurAddress);
#else
ContextRecord->X[FirstRegister + RegIndex] = MEMORY_READ_QWORD(UnwindParams, CurAddress);
#endif
//
for (RegIndex = 0; RegIndex < RegisterCount; RegIndex++) {
- UPDATE_FP_CONTEXT_POINTERS(UnwindParams, RegIndex, CurAddress);
+ UPDATE_FP_CONTEXT_POINTERS(UnwindParams, FirstRegister + RegIndex, CurAddress);
ContextRecord->V[FirstRegister + RegIndex].Low = MEMORY_READ_QWORD(UnwindParams, CurAddress);
CurAddress += 8;
}
}
#if defined(FEATURE_PAL)
-//TODO: Fix the context pointers
PEXCEPTION_ROUTINE
RtlVirtualUnwind(
IN ULONG HandlerType,
rfe.BeginAddress = FunctionEntry->BeginAddress;
rfe.UnwindData = FunctionEntry->UnwindData;
+ ARM64_UNWIND_PARAMS unwindParams;
+ unwindParams.ContextPointers = ContextPointers;
+
if ((rfe.UnwindData & 3) != 0)
{
hr = RtlpUnwindFunctionCompact(ControlPc - ImageBase,
EstablisherFrame,
&handlerRoutine,
HandlerData,
- NULL);
+ &unwindParams);
}
else
EstablisherFrame,
&handlerRoutine,
HandlerData,
- NULL);
+ &unwindParams);
}
_ASSERTE(SUCCEEDED(hr));
RestoreRegMS 26, X26
RestoreRegMS 27, X27
RestoreRegMS 28, X28
+ RestoreRegMS 29, X29
LOCAL_LABEL(Done):
// Its imperative that the return value of HelperMethodFrameRestoreState is zero
// as it is used in the state machine to loop until it becomes zero.
// The call in ndirect import precode points to this function.
NESTED_ENTRY NDirectImportThunk, _TEXT, NoHandler
- PROLOG_SAVE_REG_PAIR_INDEXED fp, lr, #-144
+ PROLOG_SAVE_REG_PAIR_INDEXED fp, lr, -160
SAVE_ARGUMENT_REGISTERS sp, 16
- SAVE_FLOAT_ARGUMENT_REGISTERS sp, 80
+ SAVE_FLOAT_ARGUMENT_REGISTERS sp, 88
mov x0, x12
bl NDirectImportWorker
mov x12, x0
// pop the stack and restore original register state
- RESTORE_FLOAT_ARGUMENT_REGISTERS sp, 80
+ RESTORE_FLOAT_ARGUMENT_REGISTERS sp, 88
RESTORE_ARGUMENT_REGISTERS sp, 16
- EPILOG_RESTORE_REG_PAIR_INDEXED fp, lr, #144
+ EPILOG_RESTORE_REG_PAIR_INDEXED fp, lr, 160
// If we got back from NDirectImportWorker, the MD has been successfully
// linked. Proceed to execute the original DLL call.
NESTED_END NDirectImportThunk, _TEXT
// ------------------------------------------------------------------
-// ARM64TODO: Implement PrecodeFixupThunk when PreCode is Enabled
+// The call in fixup precode initally points to this function.
+// The pupose of this function is to load the MethodDesc and forward the call to prestub.
NESTED_ENTRY PrecodeFixupThunk, _TEXT, NoHandler
+ // x12 = FixupPrecode *
+ // On Exit
+ // x12 = MethodDesc*
+ // x13, x14 Trashed
+ // Inline computation done by FixupPrecode::GetMethodDesc()
ldrb w13, [x12, #Offset_PrecodeChunkIndex] //m_PrecodeChunkIndex
ldrb w14, [x12, #Offset_MethodDescChunkIndex] // m_MethodDescChunkIndex
LEAF_END ThePreStubPatch, _TEXT
-// ------------------------------------------------------------------
-// void ResolveWorkerAsmStub(args in regs x0-x7 & stack, x11:IndirectionCellAndFlags, x12:DispatchToken)
-//
-// The stub dispatch thunk which transfers control to VSD_ResolveWorker.
-NESTED_ENTRY ResolveWorkerAsmStub, _TEXT, NoHandler
-
- PROLOG_WITH_TRANSITION_BLOCK
-
- add x0, sp, #__PWTB_TransitionBlock // pTransitionBlock
- and x1, x11, #-4 // Indirection cell
- mov x2, x12 // DispatchToken
- and x3, x11, #3 // flag
- bl C_FUNC(VSD_ResolveWorker)
- mov x9, x0
-
- EPILOG_WITH_TRANSITION_BLOCK_TAILCALL
-
- EPILOG_BRANCH_REG x9
-
-NESTED_END ResolveWorkerAsmStub, _TEXT
-
-NESTED_ENTRY ResolveWorkerChainLookupAsmStub, _TEXT, NoHandler
-
- // ARMSTUB TODO: implement chained lookup
- b C_FUNC(ResolveWorkerAsmStub)
-
-NESTED_END ResolveWorkerChainLookupAsmStub, _TEXT
-
//-----------------------------------------------------------------------------
// The following Macros help in WRITE_BARRIER Implemetations
// WRITE_BARRIER_ENTRY
dmb ST
str x15, [x14]
+#ifdef WRITE_BARRIER_CHECK
+ // Update GC Shadow Heap
+
+ // need temporary registers. Save them before using.
+ stp x12, x13, [sp, #-16]!
+
+ // Compute address of shadow heap location:
+ // pShadow = g_GCShadow + (x14 - g_lowest_address)
+ PREPARE_EXTERNAL_VAR g_lowest_address, x12
+ ldr x12, [x12]
+ sub x12, x14, x12
+ PREPARE_EXTERNAL_VAR g_GCShadow, x13
+ ldr x13, [x13]
+ add x12, x13, x12
+
+ // if (pShadow >= g_GCShadowEnd) goto end
+ PREPARE_EXTERNAL_VAR g_GCShadowEnd, x13
+ ldr x13, [x13]
+ cmp x12, x13
+ bhs LOCAL_LABEL(shadowupdateend)
+
+ // *pShadow = x15
+ str x15, [x12]
+
+ // Ensure that the write to the shadow heap occurs before the read from the GC heap so that race
+ // conditions are caught by INVALIDGCVALUE.
+ dmb sy
+
+ // if ([x14] == x15) goto end
+ ldr x13, [x14]
+ cmp x13, x15
+ beq LOCAL_LABEL(shadowupdateend)
+
+ // *pShadow = INVALIDGCVALUE (0xcccccccd)
+ mov x13, #0
+ movk x13, #0xcccd
+ movk x13, #0xcccc, LSL #16
+ str x13, [x12]
+
+LOCAL_LABEL(shadowupdateend):
+ ldp x12, x13, [sp],#16
+#endif
+
// Branch to Exit if the reference is not in the Gen0 heap
//
PREPARE_EXTERNAL_VAR g_ephemeral_low, x12
NESTED_ENTRY VirtualMethodFixupStub, _TEXT, NoHandler
// Save arguments and return address
- PROLOG_SAVE_REG_PAIR_INDEXED fp, lr, #-144
+ PROLOG_SAVE_REG_PAIR_INDEXED fp, lr, -160
SAVE_ARGUMENT_REGISTERS sp, 16
- SAVE_FLOAT_ARGUMENT_REGISTERS sp, 80
+ SAVE_FLOAT_ARGUMENT_REGISTERS sp, 88
// Refer to ZapImportVirtualThunk::Save
// for details on this.
// pop the stack and restore original register state
RESTORE_ARGUMENT_REGISTERS sp, 16
- RESTORE_FLOAT_ARGUMENT_REGISTERS sp, 80
- EPILOG_RESTORE_REG_PAIR_INDEXED fp, lr, #144
+ RESTORE_FLOAT_ARGUMENT_REGISTERS sp, 88
+ EPILOG_RESTORE_REG_PAIR_INDEXED fp, lr, 160
PATCH_LABEL VirtualMethodFixupPatchLabel
LEAF_END SinglecastDelegateInvokeStub, _TEXT
+#ifdef FEATURE_COMINTEROP
+
+#define ComCallPreStub_FrameSize (SIZEOF__GSCookie + SIZEOF__ComMethodFrame)
+#define ComCallPreStub_FirstStackAdjust (SIZEOF__ArgumentRegisters + 2 * 8) // reg args , fp & lr already pushed
+#define ComCallPreStub_StackAlloc0 (ComCallPreStub_FrameSize - ComCallPreStub_FirstStackAdjust)
+#define ComCallPreStub_StackAlloc1 (ComCallPreStub_StackAlloc0 + SIZEOF__FloatArgumentRegisters + 8)// 8 for ErrorReturn
+#define ComCallPreStub_StackAlloc (ComCallPreStub_StackAlloc1 + (ComCallPreStub_StackAlloc1 & 8))
+
+#define ComCallPreStub_FrameOffset (ComCallPreStub_StackAlloc - (SIZEOF__ComMethodFrame - ComCallPreStub_FirstStackAdjust))
+#define ComCallPreStub_ErrorReturnOffset0 SIZEOF__FloatArgumentRegisters
+
+#define ComCallPreStub_FirstStackAdjust (ComCallPreStub_ErrorReturnOffset0 + (ComCallPreStub_ErrorReturnOffset0 & 8))
+
+// ------------------------------------------------------------------
+// COM to CLR stub called the first time a particular method is invoked.//
+//
+// On entry:
+// x12 : ComCallMethodDesc* provided by prepad thunk
+// plus user arguments in registers and on the stack
+//
+// On exit:
+// tail calls to real method
+//
+NESTED_ENTRY ComCallPreStub, _TEXT, NoHandler
+
+ // Save arguments and return address
+ PROLOG_SAVE_REG_PAIR fp, lr, -ComCallPreStub_FirstStackAdjust!
+ PROLOG_STACK_ALLOC ComCallPreStub_StackAlloc
+
+ SAVE_ARGUMENT_REGISTERS sp, (16+ComCallPreStub_StackAlloc)
+
+ SAVE_FLOAT_ARGUMENT_REGISTERS sp, 0
+
+ str x12, [sp, #(ComCallPreStub_FrameOffset + UnmanagedToManagedFrame__m_pvDatum)]
+ add x0, sp, #(ComCallPreStub_FrameOffset)
+ add x1, sp, #(ComCallPreStub_ErrorReturnOffset)
+ bl ComPreStubWorker
+
+ cbz x0, ComCallPreStub_ErrorExit
+
+ mov x12, x0
+
+ // pop the stack and restore original register state
+ RESTORE_FLOAT_ARGUMENT_REGISTERS sp, 0
+ RESTORE_ARGUMENT_REGISTERS sp, (16+ComCallPreStub_StackAlloc)
+
+ EPILOG_STACK_FREE ComCallPreStub_StackAlloc
+ EPILOG_RESTORE_REG_PAIR fp, lr, ComCallPreStub_FirstStackAdjust!
+
+ // and tailcall to the actual method
+ EPILOG_BRANCH_REG x12
+
+ComCallPreStub_ErrorExit
+ ldr x0, [sp, #(ComCallPreStub_ErrorReturnOffset)] // ErrorReturn
+
+ // pop the stack
+ EPILOG_STACK_FREE ComCallPreStub_StackAlloc
+ EPILOG_RESTORE_REG_PAIR fp, lr, ComCallPreStub_FirstStackAdjust!
+
+ EPILOG_RETURN
+
+NESTED_END ComCallPreStub, _TEXT
+
+// ------------------------------------------------------------------
+// COM to CLR stub which sets up a ComMethodFrame and calls COMToCLRWorker.
+//
+// On entry:
+// x12 : ComCallMethodDesc* provided by prepad thunk
+// plus user arguments in registers and on the stack
+//
+// On exit:
+// Result in x0/d0 as per the real method being called
+//
+ NESTED_ENTRY GenericComCallStub, _TEXT, NoHandler
+
+ // Save arguments and return address
+ PROLOG_SAVE_REG_PAIR fp, lr, -GenericComCallStub_FirstStackAdjust!
+ PROLOG_STACK_ALLOC GenericComCallStub_StackAlloc
+
+ SAVE_ARGUMENT_REGISTERS sp, (16+GenericComCallStub_StackAlloc)
+ SAVE_FLOAT_ARGUMENT_REGISTERS sp, 0
+
+ str x12, [sp, #(GenericComCallStub_FrameOffset + UnmanagedToManagedFrame__m_pvDatum)]
+ add x1, sp, #GenericComCallStub_FrameOffset
+ bl COMToCLRWorker
+
+ // pop the stack
+ EPILOG_STACK_FREE GenericComCallStub_StackAlloc
+ EPILOG_RESTORE_REG_PAIR fp, lr, GenericComCallStub_FirstStackAdjust!
+
+ EPILOG_RETURN
+
+ NESTED_END GenericComCallStub, _TEXT
+
+// ------------------------------------------------------------------
+// COM to CLR stub called from COMToCLRWorker that actually dispatches to the real managed method.
+//
+// On entry:
+// x0 : dwStackSlots, count of argument stack slots to copy
+// x1 : pFrame, ComMethodFrame pushed by GenericComCallStub above
+// x2 : pTarget, address of code to call
+// x3 : pSecretArg, hidden argument passed to target above in x12
+// x4 : pDangerousThis, managed 'this' reference
+//
+// On exit:
+// Result in x0/d0 as per the real method being called
+//
+ NESTED_ENTRY COMToCLRDispatchHelper, _TEXT,CallDescrWorkerUnwindFrameChainHandler
+
+ PROLOG_SAVE_REG_PAIR fp, lr, -16!
+
+ cbz x0, COMToCLRDispatchHelper_RegSetup
+
+ add x9, x1, #SIZEOF__ComMethodFrame
+ add x9, x9, x0, LSL #3
+COMToCLRDispatchHelper_StackLoop
+ ldr x8, [x9, #-8]!
+ str x8, [sp, #-8]!
+ sub x0, x0, #1
+ cbnz x0, COMToCLRDispatchHelper_StackLoop
+
+COMToCLRDispatchHelper_RegSetup
+
+ RESTORE_FLOAT_ARGUMENT_REGISTERS x1, -1 * GenericComCallStub_FrameOffset
+
+ mov lr, x2
+ mov x12, x3
+
+ mov x0, x4
+
+ ldp x2, x3, [x1, #(SIZEOF__ComMethodFrame - SIZEOF__ArgumentRegisters + 16)]
+ ldp x4, x5, [x1, #(SIZEOF__ComMethodFrame - SIZEOF__ArgumentRegisters + 32)]
+ ldp x6, x7, [x1, #(SIZEOF__ComMethodFrame - SIZEOF__ArgumentRegisters + 48)]
+ ldr x8, [x1, #(SIZEOF__ComMethodFrame - SIZEOF__ArgumentRegisters + 64)]
+
+ ldr x1, [x1, #(SIZEOF__ComMethodFrame - SIZEOF__ArgumentRegisters + 8)]
+
+ blr lr
+
+ EPILOG_STACK_RESTORE
+ EPILOG_RESTORE_REG_PAIR fp, lr, 16!
+ EPILOG_RETURN
+
+ NESTED_END COMToCLRDispatchHelper, _TEXT
+
+#endif // FEATURE_COMINTEROP
//
// x12 = UMEntryThunk*
//
NESTED_ENTRY TheUMEntryPrestub, _TEXT, UnhandledExceptionHandlerUnix
// Save arguments and return address
- PROLOG_SAVE_REG_PAIR_INDEXED fp, lr, #-144
+ PROLOG_SAVE_REG_PAIR_INDEXED fp, lr, -160
SAVE_ARGUMENT_REGISTERS sp, 16
- SAVE_FLOAT_ARGUMENT_REGISTERS sp, 80
+ SAVE_FLOAT_ARGUMENT_REGISTERS sp, 88
mov x0, x12
bl C_FUNC(TheUMEntryPrestubWorker)
// pop the stack and restore original register state
RESTORE_ARGUMENT_REGISTERS sp, 16
- RESTORE_FLOAT_ARGUMENT_REGISTERS sp, 80
- EPILOG_RESTORE_REG_PAIR_INDEXED fp, lr, #144
+ RESTORE_FLOAT_ARGUMENT_REGISTERS sp, 88
+ EPILOG_RESTORE_REG_PAIR_INDEXED fp, lr, 160
// and tailcall to the actual method
EPILOG_BRANCH_REG x12
NESTED_ENTRY UMThunkStub, _TEXT, UnhandledExceptionHandlerUnix
// Save arguments and return address
- PROLOG_SAVE_REG_PAIR_INDEXED fp, lr, #-96 // 64 for regArgs, 8 for x19 & 8 for x12
+ PROLOG_SAVE_REG_PAIR_INDEXED fp, lr, -112 // 72 for regArgs, 8 for x19 & 8 for x12
// save callee saved reg x19. x19 is used in the method to store thread*
- PROLOG_SAVE_REG x19, #88
+ PROLOG_SAVE_REG x19, 96
SAVE_ARGUMENT_REGISTERS sp, 16
-#define UMThunkStub_HiddenArg 80 // offset of saved UMEntryThunk *
-#define UMThunkStub_StackArgs 96 // offset of original stack args (total size of UMThunkStub frame)
+#define UMThunkStub_HiddenArg 88 // offset of saved UMEntryThunk *
+#define UMThunkStub_StackArgs 112 // offset of original stack args (total size of UMThunkStub frame)
// save UMEntryThunk*
str x12, [sp, #UMThunkStub_HiddenArg]
str w4, [x19, #Thread__m_fPreemptiveGCDisabled]
EPILOG_STACK_RESTORE
- EPILOG_RESTORE_REG x19, #88
- EPILOG_RESTORE_REG_PAIR_INDEXED fp, lr, #96
+ EPILOG_RESTORE_REG x19, 96
+ EPILOG_RESTORE_REG_PAIR_INDEXED fp, lr, 112
EPILOG_RETURN
bl C_FUNC(UM2MDoADCallBack)
// restore integral return value
- ldr x0, [fp, #16]
+ ldp x0, x1, [fp, #16]
// restore FP or HFA return value
RESTORE_FLOAT_ARGUMENT_REGISTERS sp, 0
NESTED_ENTRY UM2MThunk_WrapperHelper, _TEXT, NoHandler
- PROLOG_SAVE_REG_PAIR_INDEXED fp, lr, #-32
- PROLOG_SAVE_REG x19, #16
+ PROLOG_SAVE_REG_PAIR_INDEXED fp, lr, -32
+ PROLOG_SAVE_REG x19, 16
// save pThunkArgs in non-volatile reg. It is required after return from call to ILStub
blr x16
// save integral return value
- str x0, [x19]
+ stp x0, x1, [x19]
+
// save FP/HFA return values
SAVE_FLOAT_ARGUMENT_REGISTERS x19, -1 * (SIZEOF__FloatArgumentRegisters + 16)
EPILOG_STACK_RESTORE
- EPILOG_RESTORE_REG x19, #16
- EPILOG_RESTORE_REG_PAIR_INDEXED fp, lr, #32
+ EPILOG_RESTORE_REG x19, 16
+ EPILOG_RESTORE_REG_PAIR_INDEXED fp, lr, 32
EPILOG_RETURN
NESTED_END UM2MThunk_WrapperHelper, _TEXT
// ------------------------------------------------------------------
// Hijack function for functions which return a scalar type or a struct (value type)
NESTED_ENTRY OnHijackTripThread, _TEXT, NoHandler
- PROLOG_SAVE_REG_PAIR fp, lr, #-144
- // Spill callee saved registers
- PROLOG_SAVE_REG_PAIR x19, x20, #16
- PROLOG_SAVE_REG_PAIR x21, x22, #32
- PROLOG_SAVE_REG_PAIR x23, x24, #48
- PROLOG_SAVE_REG_PAIR x25, x26, #64
- PROLOG_SAVE_REG_PAIR x27, x28, #80
+ PROLOG_SAVE_REG_PAIR_INDEXED fp, lr, -144
+ // Spill callee saved registers
+ PROLOG_SAVE_REG_PAIR x19, x20, 16
+ PROLOG_SAVE_REG_PAIR x21, x22, 32
+ PROLOG_SAVE_REG_PAIR x23, x24, 48
+ PROLOG_SAVE_REG_PAIR x25, x26, 64
+ PROLOG_SAVE_REG_PAIR x27, x28, 80
// save any integral return value(s)
stp x0, x1, [sp, #96]
mov x0, sp
bl OnHijackWorker
-
+
// restore any integral return value(s)
ldp x0, x1, [sp, #96]
ldp d0, d1, [sp, #112]
ldp d2, d3, [sp, #128]
- EPILOG_RESTORE_REG_PAIR x19, x20, #16
- EPILOG_RESTORE_REG_PAIR x21, x22, #32
- EPILOG_RESTORE_REG_PAIR x23, x24, #48
- EPILOG_RESTORE_REG_PAIR x25, x26, #64
- EPILOG_RESTORE_REG_PAIR x27, x28, #80
- EPILOG_RESTORE_REG_PAIR fp, lr, #144
+ EPILOG_RESTORE_REG_PAIR x19, x20, 16
+ EPILOG_RESTORE_REG_PAIR x21, x22, 32
+ EPILOG_RESTORE_REG_PAIR x23, x24, 48
+ EPILOG_RESTORE_REG_PAIR x25, x26, 64
+ EPILOG_RESTORE_REG_PAIR x27, x28, 80
+ EPILOG_RESTORE_REG_PAIR_INDEXED fp, lr, 144
EPILOG_RETURN
NESTED_END OnHijackTripThread, _TEXT
// This helper enables us to call into a funclet after restoring Fp register
NESTED_ENTRY CallEHFunclet, _TEXT, NoHandler
-
- // Using below prolog instead of PROLOG_SAVE_REG_PAIR fp,lr, #-16
- // is intentional. Above statement would also emit instruction to save
- // sp in fp. If sp is saved in fp in prolog then it is not expected that fp can change in the body
- // of method. However, this method needs to be able to change fp before calling funclet.
- // This is required to access locals in funclet.
- PROLOG_SAVE_REG_PAIR_INDEXED x19,x20, #-16
- PROLOG_SAVE_REG fp, #0
- PROLOG_SAVE_REG lr, #8
-
// On entry:
//
// X0 = throwable
// X2 = address of X19 register in CONTEXT record// used to restore the non-volatile registers of CrawlFrame
// X3 = address of the location where the SP of funclet's caller (i.e. this helper) should be saved.
//
- // Save the SP of this function
- str fp, [x3]
+ PROLOG_SAVE_REG_PAIR_INDEXED fp, lr, -96
+ // Spill callee saved registers
+ PROLOG_SAVE_REG_PAIR x19, x20, 16
+ PROLOG_SAVE_REG_PAIR x21, x22, 32
+ PROLOG_SAVE_REG_PAIR x23, x24, 48
+ PROLOG_SAVE_REG_PAIR x25, x26, 64
+ PROLOG_SAVE_REG_PAIR x27, x28, 80
+
+ // Save the SP of this function
+ mov x4, sp
+ str x4, [x3]
+
+ ldp x19, x20, [x2, #0]
+ ldp x21, x22, [x2, #16]
+ ldp x23, x24, [x2, #32]
+ ldp x25, x26, [x2, #48]
+ ldp x27, x28, [x2, #64]
ldr fp, [x2, #80] // offset of fp in CONTEXT relative to X19
// Invoke the funclet
blr x1
nop
- EPILOG_RESTORE_REG_PAIR_INDEXED fp, lr, #16
+ EPILOG_RESTORE_REG_PAIR x19, x20, 16
+ EPILOG_RESTORE_REG_PAIR x21, x22, 32
+ EPILOG_RESTORE_REG_PAIR x23, x24, 48
+ EPILOG_RESTORE_REG_PAIR x25, x26, 64
+ EPILOG_RESTORE_REG_PAIR x27, x28, 80
+ EPILOG_RESTORE_REG_PAIR_INDEXED fp, lr, 96
EPILOG_RETURN
NESTED_END CallEHFunclet, _TEXT
// frame pointer for accessing the locals in the parent method.
NESTED_ENTRY CallEHFilterFunclet, _TEXT, NoHandler
- PROLOG_SAVE_REG_PAIR_INDEXED fp, lr, #-16
+ PROLOG_SAVE_REG_PAIR_INDEXED fp, lr, -16
// On entry:
//
// Invoke the filter funclet
blr x2
- EPILOG_RESTORE_REG_PAIR_INDEXED fp, lr, #16
+ EPILOG_RESTORE_REG_PAIR_INDEXED fp, lr, 16
EPILOG_RETURN
NESTED_END CallEHFilterFunclet, _TEXT
// IN: lr: original IP before redirect
//
- PROLOG_SAVE_REG_PAIR_INDEXED fp, lr, #-16
+ PROLOG_SAVE_REG_PAIR_INDEXED fp, lr, -16
PROLOG_STACK_ALLOC FaultingExceptionFrame_StackAlloc
// At this point, the stack maybe misaligned if the thread abort was asynchronously
//
NESTED_ENTRY NakedThrowHelper2, _TEXT ,FixContextHandler
- PROLOG_SAVE_REG_PAIR_INDEXED fp,lr, #-16
+ PROLOG_SAVE_REG_PAIR_INDEXED fp,lr, -16
// On entry:
//
NESTED_END NakedThrowHelper2, _TEXT
+
GenerateRedirectedStubWithFrame NakedThrowHelper, NakedThrowHelper2
+// ------------------------------------------------------------------
+// ResolveWorkerChainLookupAsmStub
+//
+// This method will perform a quick chained lookup of the entry if the
+// initial cache lookup fails.
+//
+// On Entry:
+// x9 contains the pointer to the current ResolveCacheElem
+// x11 contains the address of the indirection (and the flags in the low two bits)
+// x12 contains our contract the DispatchToken
+// Must be preserved:
+// x0 contains the instance object ref that we are making an interface call on
+// x9 Must point to a ResolveCacheElem [For Sanity]
+// [x1-x7] contains any additional register arguments for the interface method
+//
+// Loaded from x0
+// x13 contains our type the MethodTable (from object ref in x0)
+//
+// On Exit:
+// x0, [x1-x7] arguments for the interface implementation target
+//
+// On Exit (to ResolveWorkerAsmStub):
+// x11 contains the address of the indirection and the flags in the low two bits.
+// x12 contains our contract (DispatchToken)
+// x16,x17 will be trashed
+//
+
+#define BACKPATCH_FLAG 1
+#define PROMOTE_CHAIN_FLAG 2
+
+NESTED_ENTRY ResolveWorkerChainLookupAsmStub, _TEXT, NoHandler
+
+ tst x11, #BACKPATCH_FLAG // First we check if x11 has the BACKPATCH_FLAG set
+ bne LOCAL_LABEL(Fail) // If the BACKPATCH_FLAGS is set we will go directly to the ResolveWorkerAsmStub
+
+ ldr x13, [x0] // retrieve the MethodTable from the object ref in x0
+LOCAL_LABEL(MainLoop):
+ ldr x9, [x9, #ResolveCacheElem__pNext] // x9 <= the next entry in the chain
+ cmp x9, #0
+ beq LOCAL_LABEL(Fail)
+
+ ldp x16, x17, [x9]
+ cmp x16, x13 // compare our MT with the one in the ResolveCacheElem
+ bne LOCAL_LABEL(MainLoop)
+
+ cmp x17, x12 // compare our DispatchToken with one in the ResolveCacheElem
+ bne LOCAL_LABEL(MainLoop)
+
+LOCAL_LABEL(Success):
+ PREPARE_EXTERNAL_VAR g_dispatch_cache_chain_success_counter, x13
+ ldr x16, [x13]
+ subs x16, x16, #1
+ str x16, [x13]
+ blt LOCAL_LABEL(Promote)
+
+ ldr x16, [x9, #ResolveCacheElem__target] // get the ImplTarget
+ br x16 // branch to interface implemenation target
+
+LOCAL_LABEL(Promote):
+ // Move this entry to head postion of the chain
+ mov x16, #256
+ str x16, [x13] // be quick to reset the counter so we don't get a bunch of contending threads
+ orr x11, x11, #PROMOTE_CHAIN_FLAG // set PROMOTE_CHAIN_FLAG
+
+LOCAL_LABEL(Fail):
+ b ResolveWorkerAsmStub // call the ResolveWorkerAsmStub method to transition into the VM
+
+NESTED_END ResolveWorkerChainLookupAsmStub, _TEXT
+
+// ------------------------------------------------------------------
+// void ResolveWorkerAsmStub(args in regs x0-x7 & stack and possibly retbuf arg in x8, x11:IndirectionCellAndFlags, x12:DispatchToken)
+//
+// The stub dispatch thunk which transfers control to VSD_ResolveWorker.
+NESTED_ENTRY ResolveWorkerAsmStub, _TEXT, NoHandler
+
+ PROLOG_WITH_TRANSITION_BLOCK
+
+ add x0, sp, #__PWTB_TransitionBlock // pTransitionBlock
+ and x1, x11, #-4 // Indirection cell
+ mov x2, x12 // DispatchToken
+ and x3, x11, #3 // flag
+ bl VSD_ResolveWorker
+ mov x9, x0
+
+ EPILOG_WITH_TRANSITION_BLOCK_TAILCALL
+
+ EPILOG_BRANCH_REG x9
+
+NESTED_END ResolveWorkerAsmStub, _TEXT
+
#ifdef FEATURE_READYTORUN
NESTED_ENTRY DelayLoad_MethodCall_FakeProlog, _TEXT, NoHandler
DelayLoad_MethodCall:
.global DelayLoad_MethodCall
+ PROLOG_WITH_TRANSITION_BLOCK
+
+ add x0, sp, #__PWTB_TransitionBlock // pTransitionBlock
+ mov x1, x11 // Indirection cell
+ mov x2, x9 // sectionIndex
+ mov x3, x10 // Module*
+ bl ExternalMethodFixupWorker
+ mov x12, x0
+
+ EPILOG_WITH_TRANSITION_BLOCK_TAILCALL
+ // Share patch label
+ b ExternalMethodFixupPatchLabel
- EMIT_BREAKPOINT
NESTED_END DelayLoad_MethodCall_FakeProlog, _TEXT
.macro DynamicHelper frameFlags, suffix
- NESTED_ENTRY DelayLoad_Helper\suffix\()_FakeProlog, _TEXT, NoHandler
+NESTED_ENTRY DelayLoad_Helper\suffix\()_FakeProlog, _TEXT, NoHandler
DelayLoad_Helper\suffix:
- .global DelayLoad_Helper\suffix
+ .global DelayLoad_Helper\suffix
- EMIT_BREAKPOINT
+ PROLOG_WITH_TRANSITION_BLOCK
+
+ add x0, sp, #__PWTB_TransitionBlock // pTransitionBlock
+ mov x1, x11 // Indirection cell
+ mov x2, x9 // sectionIndex
+ mov x3, x10 // Module*
+ mov x4, \frameFlags
+ bl DynamicHelperWorker
+ cbnz x0, LOCAL_LABEL(FakeProlog\suffix\()_0)
+ ldr x0, [sp, #__PWTB_ArgumentRegisters]
+ EPILOG_WITH_TRANSITION_BLOCK_RETURN
+LOCAL_LABEL(FakeProlog\suffix\()_0):
+ mov x12, x0
+ EPILOG_WITH_TRANSITION_BLOCK_TAILCALL
+ EPILOG_BRANCH_REG x12
- NESTED_END DelayLoad_Helper\suffix\()_FakeProlog, _TEXT
+NESTED_END DelayLoad_Helper\suffix\()_FakeProlog, _TEXT
.endm
DynamicHelper DynamicHelperFrameFlags_Default
DynamicHelper DynamicHelperFrameFlags_ObjectArg, _Obj
DynamicHelper DynamicHelperFrameFlags_ObjectArg | DynamicHelperFrameFlags_ObjectArg2, _ObjObj
-
#endif
#ifdef FEATURE_PREJIT
and x1, x11, #-4 // Indirection cell
mov x2, #0 // sectionIndex
mov x3, #0 // pModule
- bl StubDispatchFixupWorker
+ bl C_FUNC(StubDispatchFixupWorker)
mov x9, x0
EPILOG_WITH_TRANSITION_BLOCK_TAILCALL
NESTED_END StubDispatchFixupStub, _TEXT
#endif
+
+#ifdef FEATURE_COMINTEROP
+
+// Function used by COM interop to get floating point return value (since it's not in the same
+// register(s) as non-floating point values).
+//
+// On entry//
+// x0 : size of the FP result (4 or 8 bytes)
+// x1 : pointer to 64-bit buffer to receive result
+//
+// On exit:
+// buffer pointed to by x1 on entry contains the float or double argument as appropriate
+//
+ LEAF_ENTRY getFPReturn
+ str d0, [x1]
+ LEAF_END
+
+// ------------------------------------------------------------------
+// Function used by COM interop to set floating point return value (since it's not in the same
+// register(s) as non-floating point values).
+//
+// On entry:
+// x0 : size of the FP result (4 or 8 bytes)
+// x1 : 32-bit or 64-bit FP result
+//
+// On exit:
+// s0 : float result if x0 == 4
+// d0 : double result if x0 == 8
+//
+ LEAF_ENTRY setFPReturn
+ fmov d0, x1
+ LEAF_END
+#endif
#endif
; Must be at very end of file
- END
\ No newline at end of file
+ END
//-----------------------------------------------------------------------------
//void CallDescrWorkerInternal(CallDescrData * pCallDescrData);
-NESTED_ENTRY CallDescrWorkerInternal, _TEXT, UnhandledExceptionHandlerUnix
- PROLOG_SAVE_REG_PAIR_INDEXED fp, lr, #-32
- PROLOG_SAVE_REG x19, #16 //the stack slot at sp+24 is empty for 16 byte alligment
+NESTED_ENTRY CallDescrWorkerInternal, _TEXT, NoHandler
+ PROLOG_SAVE_REG_PAIR_INDEXED fp, lr, -32
+ PROLOG_SAVE_REG x19, 16
+ PROLOG_SAVE_REG x0, 24
mov x19, x0 // save pCallDescrData in x19
bne LOCAL_LABEL(stackloop)
LOCAL_LABEL(donestack):
- // If FP arguments are supplied in registers (x8 != NULL) then initialize all of them from the pointer
+ // If FP arguments are supplied in registers (x9 != NULL) then initialize all of them from the pointer
// given in x8.
- ldr x8, [x19,#CallDescrData__pFloatArgumentRegisters]
- cbz x8, LOCAL_LABEL(NoFloatingPoint)
- ldp d0, d1, [x8]
- ldp d2, d3, [x8, #16]
- ldp d4, d5, [x8, #32]
- ldp d6, d7, [x8, #48]
+ ldr x9, [x19,#CallDescrData__pFloatArgumentRegisters]
+ cbz x9, LOCAL_LABEL(NoFloatingPoint)
+ ldp d0, d1, [x9]
+ ldp d2, d3, [x9, #16]
+ ldp d4, d5, [x9, #32]
+ ldp d6, d7, [x9, #48]
LOCAL_LABEL(NoFloatingPoint):
// Copy [pArgumentRegisters, ..., pArgumentRegisters + 56]
// into x0, ..., x7
- ldr x8, [x19,#CallDescrData__pArgumentRegisters]
- ldp x0, x1, [x8]
- ldp x2, x3, [x8, #16]
- ldp x4, x5, [x8, #32]
- ldp x6, x7, [x8, #48]
+ ldr x9, [x19,#CallDescrData__pArgumentRegisters]
+ ldp x0, x1, [x9]
+ ldp x2, x3, [x9, #16]
+ ldp x4, x5, [x9, #32]
+ ldp x6, x7, [x9, #48]
+ ldr x8, [x9, #64]
- // ARM64TODO: => see if anything special needs to be done for remoting
// call pTarget
- ldr x8, [x19,#CallDescrData__pTarget]
- blr x8
+ ldr x9, [x19,#CallDescrData__pTarget]
+ blr x9
+
+ ldr x19, [fp, 24] // Fixup corrupted X19 caller preserved register
ldr w3, [x19,#CallDescrData__fpReturnSize]
LOCAL_LABEL(IntReturn):
// Save return value into retbuf for int
- str x0, [x19, #(CallDescrData__returnValue + 0)]
+ stp x0, x1, [x19, #(CallDescrData__returnValue + 0)]
LOCAL_LABEL(ReturnDone):
#endif
EPILOG_STACK_RESTORE
- EPILOG_RESTORE_REG x19, #16 //the stack slot at sp+24 is empty for 16 byte alligment
- EPILOG_RESTORE_REG_PAIR_INDEXED fp, lr, #32
+ EPILOG_RESTORE_REG x19, 16 //the stack slot at sp+24 is empty for 16 byte alligment
+ EPILOG_RESTORE_REG_PAIR_INDEXED fp, lr, 32
EPILOG_RETURN
NESTED_END CallDescrWorkerInternal, _TEXT
#define INSTRFMT_K64
#include <stublink.h>
+#ifndef FEATURE_PAL
#define USE_REDIRECT_FOR_GCSTRESS
+#endif // FEATURE_PAL
EXTERN_C void getFPReturn(int fpSize, INT64 *pRetVal);
EXTERN_C void setFPReturn(int fpSize, INT64 retVal);
_sp = copy->_sp;
_pc = copy->_pc;
- // Now copy the preserved register pointers. Note that some of the pointers could be
- // pointing to copy->captureX19_X29[]. If that is case then while copying to destination
- // ensure that they point to corresponding element in captureX19_X29[] of destination.
- ULONG64* srcLowerBound = ©->captureX19_X29[0];
- ULONG64* srcUpperBound = (ULONG64*)((BYTE*)copy + offsetof(MachState, ptrX19_X29));
+ // Capture* has already been set, so there is no need to touch it
+ // loop over the nonvolatile context pointers and make
+ // sure to properly copy interior pointers into the
+ // new struct
- for (int i = 0; i<NUM_NONVOLATILE_CONTEXT_POINTERS; i++)
+ PULONG64* pSrc = (PULONG64 *)©->ptrX19_X29;
+ PULONG64* pDst = (PULONG64 *)&this->ptrX19_X29;
+
+ const PULONG64 LowerBoundDst = (PULONG64) this;
+ const PULONG64 LowerBoundSrc = (PULONG64) copy;
+
+ const PULONG64 UpperBoundSrc = (PULONG64) ((BYTE*)LowerBoundSrc + sizeof(*copy));
+
+ for (int i = 0; i < NUM_NONVOLATILE_CONTEXT_POINTERS; i++)
{
- if (copy->ptrX19_X29[i] >= srcLowerBound && copy->ptrX19_X29[i] < srcUpperBound)
- {
- ptrX19_X29[i] = (PTR_ULONG64)((BYTE*)copy->ptrX19_X29[i] - (BYTE*)srcLowerBound + (BYTE*)captureX19_X29);
- }
- else
+ PULONG64 valueSrc = *pSrc++;
+
+ if ((LowerBoundSrc <= valueSrc) && (valueSrc < UpperBoundSrc))
{
- ptrX19_X29[i] = copy->ptrX19_X29[i];
+ // make any pointer interior to 'src' interior to 'dst'
+ valueSrc = (PULONG64)((BYTE*)valueSrc - (BYTE*)LowerBoundSrc + (BYTE*)LowerBoundDst);
}
+
+ *pDst++ = valueSrc;
}
+
// this has to be last because we depend on write ordering to
// synchronize the race implicit in updating this struct
VolatileStore(&_isValid, TRUE);
// $VASigCookieReg : register which contains the VASigCookie
// $SaveFPArgs : "Yes" or "No" . For varidic functions FP Args are not present in FP regs
// So need not save FP Args registers for vararg Pinvoke
-.macro PINVOKE_STUB FuncPrefix,VASigCookieReg,HiddenArg,SaveFPArgs
+.macro PINVOKE_STUB __PInvokeStubFuncName,__PInvokeGenStubFuncName,__PInvokeStubWorkerName,VASigCookieReg,HiddenArg,SaveFPArgs
-#if NOTYET
- GBLS __PInvokeStubFuncName
- GBLS __PInvokeGenStubFuncName
- GBLS __PInvokeStubWorkerName
- IF "\FuncPrefix" == "GenericPInvokeCalli"
-__PInvokeStubFuncName SETS "\FuncPrefix":CC:"Helper"
- ELSE
-__PInvokeStubFuncName SETS "\FuncPrefix":CC:"Stub"
- ENDIF
-__PInvokeGenStubFuncName SETS "\FuncPrefix":CC:"GenILStub"
-__PInvokeStubWorkerName SETS "\FuncPrefix":CC:"StubWorker"
-
- IF "\VASigCookieReg" == "x1"
-__PInvokeStubFuncName SETS "\__PInvokeStubFuncName":CC:"_RetBuffArg"
-__PInvokeGenStubFuncName SETS "\__PInvokeGenStubFuncName":CC:"_RetBuffArg"
- ENDIF
-
- NESTED_ENTRY \__PInvokeStubFuncName
+ NESTED_ENTRY \__PInvokeStubFuncName, _TEXT, NoHandler
// get the stub
ldr x9, [\VASigCookieReg, #VASigCookie__pNDirectILStub]
// if null goto stub generation
- cbz x9, %0
+ cbz x9, LOCAL_LABEL(\__PInvokeStubFuncName\()_0)
EPILOG_BRANCH_REG x9
-0
+LOCAL_LABEL(\__PInvokeStubFuncName\()_0):
+
EPILOG_BRANCH \__PInvokeGenStubFuncName
- NESTED_END
+ NESTED_END \__PInvokeStubFuncName, _TEXT
- NESTED_ENTRY \__PInvokeGenStubFuncName
+ NESTED_ENTRY \__PInvokeGenStubFuncName, _TEXT, NoHandler
PROLOG_WITH_TRANSITION_BLOCK 0, \SaveFPArgs
mov x2, \HiddenArg
// x1 = VaSigCookie
- IF "\VASigCookieReg" != "x1"
+ .ifnc \VASigCookieReg, x1
mov x1, \VASigCookieReg
- ENDIF
+ .endif
// x0 = pTransitionBlock
add x0, sp, #__PWTB_TransitionBlock
EPILOG_BRANCH \__PInvokeStubFuncName
- NESTED_END
-#else
- EMIT_BREAKPOINT
-#endif
+ NESTED_END \__PInvokeGenStubFuncName, _TEXT
.endm
// ------------------------------------------------------------------
// x0 = VASigCookie*
// x12 = MethodDesc *
//
-PINVOKE_STUB VarargPInvoke, x0, x12, 1
+PINVOKE_STUB VarargPInvokeStub, VarargPInvokeGenILStub, VarargPInvokeStubWorker, x0, x12, 0
// ------------------------------------------------------------------
// x15 = VASigCookie*
// x14 = Unmanaged target
//
-PINVOKE_STUB GenericPInvokeCalli, x15, x14, 1
+PINVOKE_STUB GenericPInvokeCalliHelper, GenericPInvokeCalliGenILStub, GenericPInvokeCalliStubWorker, x15, x14, 1
// ------------------------------------------------------------------
// VarargPInvokeStub_RetBuffArg & VarargPInvokeGenILStub_RetBuffArg
// x1 = VASigCookie*
// x12 = MethodDesc*
//
-PINVOKE_STUB VarargPInvoke, x1, x12, 0
+PINVOKE_STUB VarargPInvokeStub_RetBuffArg, VarargPInvokeGenILStub_RetBuffArg, VarargPInvokeStubWorker, x1, x12, 0
#endif
+void ClearRegDisplayArgumentAndScratchRegisters(REGDISPLAY * pRD)
+{
+ for (int i=0; i < 18; i++)
+ pRD->volatileCurrContextPointers.X[i] = NULL;
+}
+
#ifndef CROSSGEN_COMPILE
void LazyMachState::unwindLazyState(LazyMachState* baseState,
MachState* unwoundstate,
}
} while (true);
+#ifdef FEATURE_PAL
+ unwoundstate->captureX19_X29[0] = context.X19;
+ unwoundstate->captureX19_X29[1] = context.X20;
+ unwoundstate->captureX19_X29[2] = context.X21;
+ unwoundstate->captureX19_X29[3] = context.X22;
+ unwoundstate->captureX19_X29[4] = context.X23;
+ unwoundstate->captureX19_X29[5] = context.X24;
+ unwoundstate->captureX19_X29[6] = context.X25;
+ unwoundstate->captureX19_X29[7] = context.X26;
+ unwoundstate->captureX19_X29[8] = context.X27;
+ unwoundstate->captureX19_X29[9] = context.X28;
+ unwoundstate->captureX19_X29[10] = context.Fp;
+#endif
+
#ifdef DACCESS_COMPILE
// For DAC builds, we update the registers directly since we dont have context pointers
unwoundstate->captureX19_X29[0] = context.X19;
pRD->pCurrentContext->X28 = (DWORD64)(pUnwoundState->captureX19_X29[9]);
pRD->pCurrentContext->Fp = (DWORD64)(pUnwoundState->captureX19_X29[10]);
pRD->pCurrentContext->Lr = NULL; // Unwind again to get Caller's PC
+
+ pRD->pCurrentContextPointers->X19 = pUnwoundState->ptrX19_X29[0];
+ pRD->pCurrentContextPointers->X20 = pUnwoundState->ptrX19_X29[1];
+ pRD->pCurrentContextPointers->X21 = pUnwoundState->ptrX19_X29[2];
+ pRD->pCurrentContextPointers->X22 = pUnwoundState->ptrX19_X29[3];
+ pRD->pCurrentContextPointers->X23 = pUnwoundState->ptrX19_X29[4];
+ pRD->pCurrentContextPointers->X24 = pUnwoundState->ptrX19_X29[5];
+ pRD->pCurrentContextPointers->X25 = pUnwoundState->ptrX19_X29[6];
+ pRD->pCurrentContextPointers->X26 = pUnwoundState->ptrX19_X29[7];
+ pRD->pCurrentContextPointers->X27 = pUnwoundState->ptrX19_X29[8];
+ pRD->pCurrentContextPointers->X28 = pUnwoundState->ptrX19_X29[9];
+ pRD->pCurrentContextPointers->Fp = pUnwoundState->ptrX19_X29[10];
+ pRD->pCurrentContextPointers->Lr = NULL;
+
return;
}
#endif // DACCESS_COMPILE
pRD->pCurrentContext->Pc = pRD->ControlPC;
pRD->pCurrentContext->Sp = pRD->SP;
+#ifdef FEATURE_PAL
+ pRD->pCurrentContext->X19 = m_MachState.ptrX19_X29[0] ? *m_MachState.ptrX19_X29[0] : m_MachState.captureX19_X29[0];
+ pRD->pCurrentContext->X20 = m_MachState.ptrX19_X29[1] ? *m_MachState.ptrX19_X29[1] : m_MachState.captureX19_X29[1];
+ pRD->pCurrentContext->X21 = m_MachState.ptrX19_X29[2] ? *m_MachState.ptrX19_X29[2] : m_MachState.captureX19_X29[2];
+ pRD->pCurrentContext->X22 = m_MachState.ptrX19_X29[3] ? *m_MachState.ptrX19_X29[3] : m_MachState.captureX19_X29[3];
+ pRD->pCurrentContext->X23 = m_MachState.ptrX19_X29[4] ? *m_MachState.ptrX19_X29[4] : m_MachState.captureX19_X29[4];
+ pRD->pCurrentContext->X24 = m_MachState.ptrX19_X29[5] ? *m_MachState.ptrX19_X29[5] : m_MachState.captureX19_X29[5];
+ pRD->pCurrentContext->X25 = m_MachState.ptrX19_X29[6] ? *m_MachState.ptrX19_X29[6] : m_MachState.captureX19_X29[6];
+ pRD->pCurrentContext->X26 = m_MachState.ptrX19_X29[7] ? *m_MachState.ptrX19_X29[7] : m_MachState.captureX19_X29[7];
+ pRD->pCurrentContext->X27 = m_MachState.ptrX19_X29[8] ? *m_MachState.ptrX19_X29[8] : m_MachState.captureX19_X29[8];
+ pRD->pCurrentContext->X28 = m_MachState.ptrX19_X29[9] ? *m_MachState.ptrX19_X29[9] : m_MachState.captureX19_X29[9];
+ pRD->pCurrentContext->Fp = m_MachState.ptrX19_X29[10] ? *m_MachState.ptrX19_X29[10] : m_MachState.captureX19_X29[10];
+ pRD->pCurrentContext->Lr = NULL; // Unwind again to get Caller's PC
+#else // FEATURE_PAL
pRD->pCurrentContext->X19 = *m_MachState.ptrX19_X29[0];
pRD->pCurrentContext->X20 = *m_MachState.ptrX19_X29[1];
pRD->pCurrentContext->X21 = *m_MachState.ptrX19_X29[2];
pRD->pCurrentContext->X28 = *m_MachState.ptrX19_X29[9];
pRD->pCurrentContext->Fp = *m_MachState.ptrX19_X29[10];
pRD->pCurrentContext->Lr = NULL; // Unwind again to get Caller's PC
+#endif
#if !defined(DACCESS_COMPILE)
pRD->pCurrentContextPointers->X19 = m_MachState.ptrX19_X29[0];
pRD->pCurrentContextPointers->Fp = m_MachState.ptrX19_X29[10];
pRD->pCurrentContextPointers->Lr = NULL; // Unwind again to get Caller's PC
#endif
+
+ ClearRegDisplayArgumentAndScratchRegisters(pRD);
}
#endif // CROSSGEN_COMPILE
void TransitionFrame::UpdateRegDisplay(const PREGDISPLAY pRD)
{
-
pRD->IsCallerContextValid = FALSE;
pRD->IsCallerSPValid = FALSE; // Don't add usage of this field. This is only temporary.
- // copy the argumetn registers
- ArgumentRegisters *pArgRegs = GetArgumentRegisters();
- for (int i = 0; i < ARGUMENTREGISTERS_SIZE; i++)
-#ifdef __clang__
- *(&pRD->pCurrentContext->X0 + (sizeof(void*)*i)) = pArgRegs->x[i];
-#else
- pRD->pCurrentContext->X[i] = pArgRegs->x[i];
-#endif
-
// copy the callee saved regs
CalleeSavedRegisters *pCalleeSaved = GetCalleeSavedRegisters();
UpdateRegDisplayFromCalleeSavedRegisters(pRD, pCalleeSaved);
+ ClearRegDisplayArgumentAndScratchRegisters(pRD);
+
// copy the control registers
pRD->pCurrentContext->Fp = pCalleeSaved->x29;
pRD->pCurrentContext->Lr = pCalleeSaved->x30;
LOG((LF_GCROOTS, LL_INFO100000, "STACKWALK TransitionFrame::UpdateRegDisplay(pc:%p, sp:%p)\n", pRD->ControlPC, pRD->SP));
}
+
#endif
#ifndef CROSSGEN_COMPILE
pRD->pCurrentContextPointers->Fp = (PDWORD64)&m_ctx.Fp;
pRD->pCurrentContextPointers->Lr = (PDWORD64)&m_ctx.Lr;
+ ClearRegDisplayArgumentAndScratchRegisters(pRD);
+
pRD->IsCallerContextValid = FALSE;
pRD->IsCallerSPValid = FALSE; // Don't add usage of this field. This is only temporary.
return;
}
- // reset pContext; it's only valid for active (top-most) frame
- pRD->pContext = NULL;
+ pRD->IsCallerContextValid = FALSE;
+ pRD->IsCallerSPValid = FALSE;
+
+ pRD->pCurrentContext->Pc = *(DWORD64 *)&m_pCallerReturnAddress;
+ pRD->pCurrentContext->Sp = *(DWORD64 *)&m_pCallSiteSP;
+ pRD->pCurrentContext->Fp = *(DWORD64 *)&m_pCalleeSavedFP;
+
+ pRD->pCurrentContextPointers->X19 = NULL;
+ pRD->pCurrentContextPointers->X20 = NULL;
+ pRD->pCurrentContextPointers->X21 = NULL;
+ pRD->pCurrentContextPointers->X22 = NULL;
+ pRD->pCurrentContextPointers->X23 = NULL;
+ pRD->pCurrentContextPointers->X24 = NULL;
+ pRD->pCurrentContextPointers->X25 = NULL;
+ pRD->pCurrentContextPointers->X26 = NULL;
+ pRD->pCurrentContextPointers->X27 = NULL;
+ pRD->pCurrentContextPointers->X28 = NULL;
pRD->ControlPC = m_pCallerReturnAddress;
pRD->SP = (DWORD) dac_cast<TADDR>(m_pCallSiteSP);
- pRD->IsCallerContextValid = FALSE;
- pRD->IsCallerSPValid = FALSE;
+ // reset pContext; it's only valid for active (top-most) frame
+ pRD->pContext = NULL;
+
+ ClearRegDisplayArgumentAndScratchRegisters(pRD);
- pRD->pCurrentContext->Pc = m_pCallerReturnAddress;
- pRD->pCurrentContext->Sp = pRD->SP;
// Update the frame pointer in the current context.
- pRD->pCurrentContext->Fp = m_pCalleeSavedFP;
pRD->pCurrentContextPointers->Fp = &m_pCalleeSavedFP;
LOG((LF_GCROOTS, LL_INFO100000, "STACKWALK InlinedCallFrame::UpdateRegDisplay(pc:%p, sp:%p)\n", pRD->ControlPC, pRD->SP));
UPDATEREG(X26);
UPDATEREG(X27);
UPDATEREG(X28);
- // Obtain value of Fp from CurrentContext instead of from CurrentContextPointers
- // It should not matter. CurrentContextPointers does not have value of FP as this will
- // require changes in MachState to also store pointer of FP which it does not do currently.
- pContextRecord->Fp = pRegDisplay->pCurrentContext->Fp;
- if (pAbortContext)
- {
- pAbortContext->Fp = pContextRecord->Fp;
- }
+ UPDATEREG(Fp);
#else
PORTABILITY_ASSERT("ExceptionTracker::UpdateNonvolatileRegisters");