1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
5 #include "asmconstants.h"
6 #include "unixasmmacros.inc"
8 // LPVOID __stdcall GetCurrentIP(void)//
9 LEAF_ENTRY GetCurrentIP, _TEXT
12 LEAF_END GetCurrentIP, _TEXT
14 // LPVOID __stdcall GetCurrentSP(void)//
15 LEAF_ENTRY GetCurrentSP, _TEXT
18 LEAF_END GetCurrentSP, _TEXT
20 //-----------------------------------------------------------------------------
21 // This routine captures the machine state. It is used by helper method frame
22 //-----------------------------------------------------------------------------
23 //void LazyMachStateCaptureState(struct LazyMachState *pState)//
24 LEAF_ENTRY LazyMachStateCaptureState, _TEXT
25 // marks that this is not yet valid
27 str w1, [x0, #MachState__isValid]
29 str lr, [x0, #LazyMachState_captureIp]
31 // str instruction does not save sp register directly so move to temp register
33 str x1, [x0, #LazyMachState_captureSp]
35 // save non-volatile registers that can contain object references
36 add x1, x0, #LazyMachState_captureX19_X29
37 stp x19, x20, [x1, #(16*0)]
38 stp x21, x22, [x1, #(16*1)]
39 stp x23, x24, [x1, #(16*2)]
40 stp x25, x26, [x1, #(16*3)]
41 stp x27, x28, [x1, #(16*4)]
42 str x29, [x1, #(16*5)]
45 LEAF_END LazyMachStateCaptureState, _TEXT
48 // If a preserved register were pushed onto the stack between
49 // the managed caller and the H_M_F, ptrX19_X29 will point to its
50 // location on the stack and it would have been updated on the
51 // stack by the GC already and it will be popped back into the
52 // appropriate register when the appropriate epilog is run.
54 // Otherwise, the register is preserved across all the code
55 // in this HCALL or FCALL, so we need to update those registers
56 // here because the GC will have updated our copies in the
59 // So, if ptrX19_X29 points into the MachState, we need to update
60 // the register here. That's what this macro does.
62 .macro RestoreRegMS regIndex, reg
65 // x0 = address of MachState
67 // $regIndex: Index of the register (x19-x28). For x19, index is 19.
68 //For x20, index is 20, and so on.
70 // $reg: Register name (e.g. x19, x20, etc)
72 // Get the address of the specified captured register from machine state
73 add x2, x0, #(MachState__captureX19_X29 + ((\regIndex-19)*8))
75 // Get the content of specified preserved register pointer from machine state
76 ldr x3, [x0, #(MachState__ptrX19_X29 + ((\regIndex-19)*8))]
79 bne LOCAL_LABEL(NoRestore_\reg)
81 LOCAL_LABEL(NoRestore_\reg):
85 // EXTERN_C int __fastcall HelperMethodFrameRestoreState(
86 // INDEBUG_COMMA(HelperMethodFrame *pFrame)
89 LEAF_ENTRY HelperMethodFrameRestoreState, _TEXT
95 // If machine state is invalid, then simply exit
96 ldr w1, [x0, #MachState__isValid]
112 // Its imperative that the return value of HelperMethodFrameRestoreState is zero
113 // as it is used in the state machine to loop until it becomes zero.
114 // Refer to HELPER_METHOD_FRAME_END macro for details.
118 LEAF_END HelperMethodFrameRestoreState, _TEXT
120 // ------------------------------------------------------------------
121 // The call in ndirect import precode points to this function.
122 NESTED_ENTRY NDirectImportThunk, _TEXT, NoHandler
124 PROLOG_SAVE_REG_PAIR_INDEXED fp, lr, -224
125 SAVE_ARGUMENT_REGISTERS sp, 16
126 SAVE_FLOAT_ARGUMENT_REGISTERS sp, 96
129 bl NDirectImportWorker
132 // pop the stack and restore original register state
133 RESTORE_FLOAT_ARGUMENT_REGISTERS sp, 96
134 RESTORE_ARGUMENT_REGISTERS sp, 16
135 EPILOG_RESTORE_REG_PAIR_INDEXED fp, lr, 224
137 // If we got back from NDirectImportWorker, the MD has been successfully
138 // linked. Proceed to execute the original DLL call.
139 EPILOG_BRANCH_REG x12
141 NESTED_END NDirectImportThunk, _TEXT
143 // ------------------------------------------------------------------
144 // The call in fixup precode initally points to this function.
145 // The pupose of this function is to load the MethodDesc and forward the call to prestub.
146 NESTED_ENTRY PrecodeFixupThunk, _TEXT, NoHandler
147 // x12 = FixupPrecode *
151 // Inline computation done by FixupPrecode::GetMethodDesc()
152 ldrb w13, [x12, #Offset_PrecodeChunkIndex] //m_PrecodeChunkIndex
153 ldrb w14, [x12, #Offset_MethodDescChunkIndex] // m_MethodDescChunkIndex
155 add x12, x12, w13, uxtw #FixupPrecode_ALIGNMENT_SHIFT_1
156 add x13, x12, w13, uxtw #FixupPrecode_ALIGNMENT_SHIFT_2
157 ldr x13, [x13, #SIZEOF__FixupPrecode]
158 add x12, x13, w14, uxtw #MethodDesc_ALIGNMENT_SHIFT
161 NESTED_END PrecodeFixupThunk, _TEXT
162 // ------------------------------------------------------------------
164 NESTED_ENTRY ThePreStub, _TEXT, NoHandler
166 PROLOG_WITH_TRANSITION_BLOCK
168 add x0, sp, #__PWTB_TransitionBlock // pTransitionBlock
169 mov x1, METHODDESC_REGISTER // pMethodDesc
175 EPILOG_WITH_TRANSITION_BLOCK_TAILCALL
178 NESTED_END ThePreStub, _TEXT
180 // ------------------------------------------------------------------
183 LEAF_ENTRY ThePreStubPatch, _TEXT
185 .globl C_FUNC(ThePreStubPatchLabel)
186 C_FUNC(ThePreStubPatchLabel):
188 LEAF_END ThePreStubPatch, _TEXT
191 //-----------------------------------------------------------------------------
192 // The following Macros help in WRITE_BARRIER Implemetations
193 // WRITE_BARRIER_ENTRY
195 // Declare the start of a write barrier function. Use similarly to NESTED_ENTRY. This is the only legal way
196 // to declare a write barrier function.
198 .macro WRITE_BARRIER_ENTRY name
199 LEAF_ENTRY \name, _TEXT
204 // The partner to WRITE_BARRIER_ENTRY, used like NESTED_END.
206 .macro WRITE_BARRIER_END name
207 LEAF_END_MARKED \name, _TEXT
210 // ------------------------------------------------------------------
211 // Start of the writeable code region
212 LEAF_ENTRY JIT_PatchedCodeStart, _TEXT
214 LEAF_END JIT_PatchedCodeStart, _TEXT
216 // void JIT_UpdateWriteBarrierState(bool skipEphemeralCheck)
218 // Update shadow copies of the various state info required for barrier
220 // State info is contained in a literal pool at the end of the function
221 // Placed in text section so that it is close enough to use ldr literal and still
222 // be relocatable. Eliminates need for PREPARE_EXTERNAL_VAR in hot code.
224 // Align and group state info together so it fits in a single cache line
225 // and each entry can be written atomically
227 WRITE_BARRIER_ENTRY JIT_UpdateWriteBarrierState
228 PROLOG_SAVE_REG_PAIR_INDEXED fp, lr, -16
230 // x0-x7 will contain intended new state
231 // x8 will preserve skipEphemeralCheck
232 // x12 will be used for pointers
236 PREPARE_EXTERNAL_VAR g_card_table, x12
239 #ifdef FEATURE_MANUALLY_MANAGED_CARD_BUNDLES
240 PREPARE_EXTERNAL_VAR g_card_bundle_table, x12
244 #ifdef WRITE_BARRIER_CHECK
245 PREPARE_EXTERNAL_VAR g_GCShadow, x12
249 #ifdef FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP
250 PREPARE_EXTERNAL_VAR g_sw_ww_table, x12
254 PREPARE_EXTERNAL_VAR g_ephemeral_low, x12
257 PREPARE_EXTERNAL_VAR g_ephemeral_high, x12
260 cbz x8, LOCAL_LABEL(EphemeralCheckEnabled)
263 LOCAL_LABEL(EphemeralCheckEnabled):
265 PREPARE_EXTERNAL_VAR g_lowest_address, x12
268 PREPARE_EXTERNAL_VAR g_highest_address, x12
272 adr x12, LOCAL_LABEL(wbs_begin)
274 stp x0, x1, [x12], 16
275 stp x2, x3, [x12], 16
276 stp x4, x5, [x12], 16
277 stp x6, x7, [x12], 16
279 EPILOG_RESTORE_REG_PAIR_INDEXED fp, lr, 16
282 // Begin patchable literal pool
283 .balign 64 // Align to power of two at least as big as patchable literal pool so that it fits optimally in cache line
284 LOCAL_LABEL(wbs_begin):
285 LOCAL_LABEL(wbs_card_table):
287 LOCAL_LABEL(wbs_card_bundle_table):
289 LOCAL_LABEL(wbs_GCShadow):
291 LOCAL_LABEL(wbs_sw_ww_table):
293 LOCAL_LABEL(wbs_ephemeral_low):
295 LOCAL_LABEL(wbs_ephemeral_high):
297 LOCAL_LABEL(wbs_lowest_address):
299 LOCAL_LABEL(wbs_highest_address):
301 WRITE_BARRIER_END JIT_UpdateWriteBarrierState
304 // ------------------------------------------------------------------
305 // End of the writeable code region
306 LEAF_ENTRY JIT_PatchedCodeLast, _TEXT
308 LEAF_END JIT_PatchedCodeLast, _TEXT
310 // void JIT_ByRefWriteBarrier
312 // x13 : the source address (points to object reference to write)
313 // x14 : the destination address (object reference written here)
317 // x13 : incremented by 8
318 // x14 : incremented by 8
320 // x17 : trashed (ip1) if FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP
322 WRITE_BARRIER_ENTRY JIT_ByRefWriteBarrier
325 b C_FUNC(JIT_CheckedWriteBarrier)
327 WRITE_BARRIER_END JIT_ByRefWriteBarrier
329 //-----------------------------------------------------------------------------
330 // Simple WriteBarriers
331 // void JIT_CheckedWriteBarrier(Object** dst, Object* src)
333 // x14 : the destination address (LHS of the assignment)
334 // x15 : the object reference (RHS of the assignment)
338 // x14 : trashed (incremented by 8 to implement JIT_ByRefWriteBarrier contract)
340 // x17 : trashed (ip1) if FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP
342 WRITE_BARRIER_ENTRY JIT_CheckedWriteBarrier
343 ldr x12, LOCAL_LABEL(wbs_lowest_address)
346 ldr x12, LOCAL_LABEL(wbs_highest_address)
348 // Compare against the upper bound if the previous comparison indicated
349 // that the destination address is greater than or equal to the lower
350 // bound. Otherwise, set the C flag (specified by the 0x2) so that the
351 // branch below is not taken.
352 ccmp x14, x12, #0x2, hs
354 blo C_FUNC(JIT_WriteBarrier)
356 LOCAL_LABEL(NotInHeap):
359 WRITE_BARRIER_END JIT_CheckedWriteBarrier
361 // void JIT_WriteBarrier(Object** dst, Object* src)
363 // x14 : the destination address (LHS of the assignment)
364 // x15 : the object reference (RHS of the assignment)
368 // x14 : trashed (incremented by 8 to implement JIT_ByRefWriteBarrier contract)
370 // x17 : trashed (ip1) if FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP
372 WRITE_BARRIER_ENTRY JIT_WriteBarrier
375 #ifdef WRITE_BARRIER_CHECK
376 // Update GC Shadow Heap
378 // Do not perform the work if g_GCShadow is 0
379 ldr x12, LOCAL_LABEL(wbs_GCShadow)
380 cbz x12, LOCAL_LABEL(ShadowUpdateDisabled)
382 // need temporary register. Save before using.
385 // Compute address of shadow heap location:
386 // pShadow = g_GCShadow + (x14 - g_lowest_address)
387 ldr x13, LOCAL_LABEL(wbs_lowest_address)
391 // if (pShadow >= g_GCShadowEnd) goto end
392 PREPARE_EXTERNAL_VAR g_GCShadowEnd, x13
395 bhs LOCAL_LABEL(ShadowUpdateEnd)
400 // Ensure that the write to the shadow heap occurs before the read from the GC heap so that race
401 // conditions are caught by INVALIDGCVALUE.
404 // if ([x14] == x15) goto end
407 beq LOCAL_LABEL(ShadowUpdateEnd)
409 // *pShadow = INVALIDGCVALUE (0xcccccccd)
411 movk x13, #0xcccc, LSL #16
414 LOCAL_LABEL(ShadowUpdateEnd):
416 LOCAL_LABEL(ShadowUpdateDisabled):
419 #ifdef FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP
420 // Update the write watch table if necessary
421 ldr x12, LOCAL_LABEL(wbs_sw_ww_table)
422 cbz x12, LOCAL_LABEL(CheckCardTable)
423 add x12, x12, x14, lsr #0xc // SoftwareWriteWatch::AddressToTableByteIndexShift
425 cbnz x17, LOCAL_LABEL(CheckCardTable)
430 LOCAL_LABEL(CheckCardTable):
431 // Branch to Exit if the reference is not in the Gen0 heap
433 ldr x12, LOCAL_LABEL(wbs_ephemeral_low)
434 cbz x12, LOCAL_LABEL(SkipEphemeralCheck)
437 ldr x12, LOCAL_LABEL(wbs_ephemeral_high)
439 // Compare against the upper bound if the previous comparison indicated
440 // that the destination address is greater than or equal to the lower
441 // bound. Otherwise, set the C flag (specified by the 0x2) so that the
442 // branch to exit is taken.
443 ccmp x15, x12, #0x2, hs
445 bhi LOCAL_LABEL(Exit)
447 LOCAL_LABEL(SkipEphemeralCheck):
448 // Check if we need to update the card table
449 ldr x12, LOCAL_LABEL(wbs_card_table)
450 add x15, x12, x14, lsr #11
453 beq LOCAL_LABEL(Exit)
455 LOCAL_LABEL(UpdateCardTable):
459 #ifdef FEATURE_MANUALLY_MANAGED_CARD_BUNDLES
460 // Check if we need to update the card bundle table
461 ldr x12, LOCAL_LABEL(wbs_card_bundle_table)
462 add x15, x12, x14, lsr #21
465 beq LOCAL_LABEL(Exit)
467 LOCAL_LABEL(UpdateCardBundle):
475 WRITE_BARRIER_END JIT_WriteBarrier
477 #ifdef FEATURE_PREJIT
478 //------------------------------------------------
479 // VirtualMethodFixupStub
481 // In NGEN images, virtual slots inherited from cross-module dependencies
482 // point to a jump thunk that calls into the following function that will
483 // call into a VM helper. The VM helper is responsible for patching up
484 // thunk, upon executing the precode, so that all subsequent calls go directly
485 // to the actual method body.
487 // This is done lazily for performance reasons.
491 // x0 = "this" pointer
492 // x12 = Address of thunk
494 NESTED_ENTRY VirtualMethodFixupStub, _TEXT, NoHandler
496 // Save arguments and return address
497 PROLOG_SAVE_REG_PAIR_INDEXED fp, lr, -224
498 SAVE_ARGUMENT_REGISTERS sp, 16
499 SAVE_FLOAT_ARGUMENT_REGISTERS sp, 96
501 // Refer to ZapImportVirtualThunk::Save
502 // for details on this.
504 // Move the thunk start address in x1
507 // Call the helper in the VM to perform the actual fixup
508 // and tell us where to tail call. x0 already contains
510 bl C_FUNC(VirtualMethodFixupWorker)
511 // On return, x0 contains the target to tailcall to
514 // pop the stack and restore original register state
515 RESTORE_ARGUMENT_REGISTERS sp, 16
516 RESTORE_FLOAT_ARGUMENT_REGISTERS sp, 96
517 EPILOG_RESTORE_REG_PAIR_INDEXED fp, lr, 224
519 PATCH_LABEL VirtualMethodFixupPatchLabel
521 // and tailcall to the actual method
522 EPILOG_BRANCH_REG x12
524 NESTED_END VirtualMethodFixupStub, _TEXT
525 #endif // FEATURE_PREJIT
527 //------------------------------------------------
528 // ExternalMethodFixupStub
530 // In NGEN images, calls to cross-module external methods initially
531 // point to a jump thunk that calls into the following function that will
532 // call into a VM helper. The VM helper is responsible for patching up the
533 // thunk, upon executing the precode, so that all subsequent calls go directly
534 // to the actual method body.
536 // This is done lazily for performance reasons.
540 // x12 = Address of thunk
542 NESTED_ENTRY ExternalMethodFixupStub, _TEXT, NoHandler
544 PROLOG_WITH_TRANSITION_BLOCK
546 add x0, sp, #__PWTB_TransitionBlock // pTransitionBlock
547 mov x1, x12 // pThunk
548 mov x2, #0 // sectionIndex
549 mov x3, #0 // pModule
551 bl C_FUNC(ExternalMethodFixupWorker)
553 // mov the address we patched to in x12 so that we can tail call to it
556 EPILOG_WITH_TRANSITION_BLOCK_TAILCALL
557 PATCH_LABEL ExternalMethodFixupPatchLabel
558 EPILOG_BRANCH_REG x12
560 NESTED_END ExternalMethodFixupStub, _TEXT
562 // void SinglecastDelegateInvokeStub(Delegate *pThis)
563 LEAF_ENTRY SinglecastDelegateInvokeStub, _TEXT
565 beq LOCAL_LABEL(LNullThis)
567 ldr x16, [x0, #DelegateObject___methodPtr]
568 ldr x0, [x0, #DelegateObject___target]
572 LOCAL_LABEL(LNullThis):
573 mov x0, #CORINFO_NullReferenceException_ASM
574 b C_FUNC(JIT_InternalThrow)
576 LEAF_END SinglecastDelegateInvokeStub, _TEXT
578 #ifdef FEATURE_COMINTEROP
580 #define ComCallPreStub_FrameSize (SIZEOF__GSCookie + SIZEOF__ComMethodFrame)
581 #define ComCallPreStub_FirstStackAdjust (8 + SIZEOF__ArgumentRegisters + 2 * 8) // x8, reg args , fp & lr already pushed
582 #define ComCallPreStub_StackAlloc0 (ComCallPreStub_FrameSize - ComCallPreStub_FirstStackAdjust)
583 #define ComCallPreStub_StackAlloc1 (ComCallPreStub_StackAlloc0 + SIZEOF__FloatArgumentRegisters + 8)// 8 for ErrorReturn
584 #define ComCallPreStub_StackAlloc (ComCallPreStub_StackAlloc1 + (ComCallPreStub_StackAlloc1 & 8))
586 #define ComCallPreStub_FrameOffset (ComCallPreStub_StackAlloc - (SIZEOF__ComMethodFrame - ComCallPreStub_FirstStackAdjust))
587 #define ComCallPreStub_ErrorReturnOffset0 SIZEOF__FloatArgumentRegisters
589 #define ComCallPreStub_FirstStackAdjust (ComCallPreStub_ErrorReturnOffset0 + (ComCallPreStub_ErrorReturnOffset0 & 8))
591 // ------------------------------------------------------------------
592 // COM to CLR stub called the first time a particular method is invoked.//
595 // x12 : ComCallMethodDesc* provided by prepad thunk
596 // plus user arguments in registers and on the stack
599 // tail calls to real method
601 NESTED_ENTRY ComCallPreStub, _TEXT, NoHandler
603 // Save arguments and return address
604 PROLOG_SAVE_REG_PAIR fp, lr, -ComCallPreStub_FirstStackAdjust!
605 PROLOG_STACK_ALLOC ComCallPreStub_StackAlloc
607 SAVE_ARGUMENT_REGISTERS sp, (16+ComCallPreStub_StackAlloc)
609 SAVE_FLOAT_ARGUMENT_REGISTERS sp, 0
611 str x12, [sp, #(ComCallPreStub_FrameOffset + UnmanagedToManagedFrame__m_pvDatum)]
612 add x0, sp, #(ComCallPreStub_FrameOffset)
613 add x1, sp, #(ComCallPreStub_ErrorReturnOffset)
616 cbz x0, ComCallPreStub_ErrorExit
620 // pop the stack and restore original register state
621 RESTORE_FLOAT_ARGUMENT_REGISTERS sp, 0
622 RESTORE_ARGUMENT_REGISTERS sp, (16+ComCallPreStub_StackAlloc)
624 EPILOG_STACK_FREE ComCallPreStub_StackAlloc
625 EPILOG_RESTORE_REG_PAIR fp, lr, ComCallPreStub_FirstStackAdjust!
627 // and tailcall to the actual method
628 EPILOG_BRANCH_REG x12
630 ComCallPreStub_ErrorExit
631 ldr x0, [sp, #(ComCallPreStub_ErrorReturnOffset)] // ErrorReturn
634 EPILOG_STACK_FREE ComCallPreStub_StackAlloc
635 EPILOG_RESTORE_REG_PAIR fp, lr, ComCallPreStub_FirstStackAdjust!
639 NESTED_END ComCallPreStub, _TEXT
641 // ------------------------------------------------------------------
642 // COM to CLR stub which sets up a ComMethodFrame and calls COMToCLRWorker.
645 // x12 : ComCallMethodDesc* provided by prepad thunk
646 // plus user arguments in registers and on the stack
649 // Result in x0/d0 as per the real method being called
651 NESTED_ENTRY GenericComCallStub, _TEXT, NoHandler
653 // Save arguments and return address
654 PROLOG_SAVE_REG_PAIR fp, lr, -GenericComCallStub_FirstStackAdjust!
655 PROLOG_STACK_ALLOC GenericComCallStub_StackAlloc
657 SAVE_ARGUMENT_REGISTERS sp, (16+GenericComCallStub_StackAlloc)
658 SAVE_FLOAT_ARGUMENT_REGISTERS sp, 0
660 str x12, [sp, #(GenericComCallStub_FrameOffset + UnmanagedToManagedFrame__m_pvDatum)]
661 add x1, sp, #GenericComCallStub_FrameOffset
665 EPILOG_STACK_FREE GenericComCallStub_StackAlloc
666 EPILOG_RESTORE_REG_PAIR fp, lr, GenericComCallStub_FirstStackAdjust!
670 NESTED_END GenericComCallStub, _TEXT
672 // ------------------------------------------------------------------
673 // COM to CLR stub called from COMToCLRWorker that actually dispatches to the real managed method.
676 // x0 : dwStackSlots, count of argument stack slots to copy
677 // x1 : pFrame, ComMethodFrame pushed by GenericComCallStub above
678 // x2 : pTarget, address of code to call
679 // x3 : pSecretArg, hidden argument passed to target above in x12
680 // x4 : pDangerousThis, managed 'this' reference
683 // Result in x0/d0 as per the real method being called
685 NESTED_ENTRY COMToCLRDispatchHelper, _TEXT,CallDescrWorkerUnwindFrameChainHandler
687 PROLOG_SAVE_REG_PAIR fp, lr, -16!
689 cbz x0, COMToCLRDispatchHelper_RegSetup
691 add x9, x1, #SIZEOF__ComMethodFrame
692 add x9, x9, x0, LSL #3
693 COMToCLRDispatchHelper_StackLoop
697 cbnz x0, COMToCLRDispatchHelper_StackLoop
699 COMToCLRDispatchHelper_RegSetup
701 RESTORE_FLOAT_ARGUMENT_REGISTERS x1, -1 * GenericComCallStub_FrameOffset
708 ldp x2, x3, [x1, #(SIZEOF__ComMethodFrame - SIZEOF__ArgumentRegisters + 16)]
709 ldp x4, x5, [x1, #(SIZEOF__ComMethodFrame - SIZEOF__ArgumentRegisters + 32)]
710 ldp x6, x7, [x1, #(SIZEOF__ComMethodFrame - SIZEOF__ArgumentRegisters + 48)]
711 ldr x8, [x1, #(SIZEOF__ComMethodFrame - SIZEOF__ArgumentRegisters - 8)]
713 ldr x1, [x1, #(SIZEOF__ComMethodFrame - SIZEOF__ArgumentRegisters + 8)]
718 EPILOG_RESTORE_REG_PAIR fp, lr, 16!
721 NESTED_END COMToCLRDispatchHelper, _TEXT
723 #endif // FEATURE_COMINTEROP
725 // x12 = UMEntryThunk*
727 NESTED_ENTRY TheUMEntryPrestub, _TEXT, UnhandledExceptionHandlerUnix
729 // Save arguments and return address
730 PROLOG_SAVE_REG_PAIR_INDEXED fp, lr, -224
731 SAVE_ARGUMENT_REGISTERS sp, 16
732 SAVE_FLOAT_ARGUMENT_REGISTERS sp, 96
735 bl C_FUNC(TheUMEntryPrestubWorker)
737 // save real target address in x12.
740 // pop the stack and restore original register state
741 RESTORE_ARGUMENT_REGISTERS sp, 16
742 RESTORE_FLOAT_ARGUMENT_REGISTERS sp, 96
743 EPILOG_RESTORE_REG_PAIR_INDEXED fp, lr, 224
745 // and tailcall to the actual method
746 EPILOG_BRANCH_REG x12
748 NESTED_END TheUMEntryPrestub, _TEXT
751 // x12 = UMEntryThunk*
753 NESTED_ENTRY UMThunkStub, _TEXT, UnhandledExceptionHandlerUnix
755 // Save arguments and return address
756 PROLOG_SAVE_REG_PAIR_INDEXED fp, lr, -112 // 72 for regArgs, 8 for x19 & 8 for x12
757 // save callee saved reg x19. x19 is used in the method to store thread*
758 PROLOG_SAVE_REG x19, 96
760 SAVE_ARGUMENT_REGISTERS sp, 16
762 #define UMThunkStub_HiddenArg 88 // offset of saved UMEntryThunk *
763 #define UMThunkStub_StackArgs 112 // offset of original stack args (total size of UMThunkStub frame)
765 // save UMEntryThunk*
766 str x12, [sp, #UMThunkStub_HiddenArg]
768 // assuming GetThread does not clobber FP Args
770 cbz x0, LOCAL_LABEL(UMThunkStub_DoThreadSetup)
772 LOCAL_LABEL(UMThunkStub_HaveThread):
773 mov x19, x0 // x19 = Thread *
776 // m_fPreemptiveGCDisabled is 4 byte field so using 32-bit variant
777 str w9, [x19, #Thread__m_fPreemptiveGCDisabled]
779 PREPARE_EXTERNAL_VAR g_TrapReturningThreads, x2
781 // assuming x0 contains Thread* before jumping to UMThunkStub_DoTrapReturningThreads
782 cbnz x3, LOCAL_LABEL(UMThunkStub_DoTrapReturningThreads)
784 LOCAL_LABEL(UMThunkStub_InCooperativeMode):
785 ldr x12, [fp, #UMThunkStub_HiddenArg] // x12 = UMEntryThunk*
786 ldr x3, [x12, #UMEntryThunk__m_pUMThunkMarshInfo] // x3 = m_pUMThunkMarshInfo
788 // m_cbActualArgSize is UINT32 and hence occupies 4 bytes
789 ldr w2, [x3, #UMThunkMarshInfo__m_cbActualArgSize] // w2 = Stack arg bytes
790 cbz w2, LOCAL_LABEL(UMThunkStub_RegArgumentsSetup)
796 add x0, fp, #UMThunkStub_StackArgs
798 // move source pointer to end of Stack Args
801 // Count of stack slot pairs to copy (divide by 16)
804 // Is there an extra stack slot (can happen when stack arg bytes not multiple of 16)
807 // If yes then start source pointer from 16 byte aligned stack slot
810 // increment stack slot pair count by 1 if x2 is not zero
811 add x1, x1, x2, LSR #3
813 LOCAL_LABEL(UMThunkStub_StackLoop):
814 ldp x4, x5, [x0, #-16]! // pre-Index
815 stp x4, x5, [sp, #-16]! // pre-Index
817 bne LOCAL_LABEL(UMThunkStub_StackLoop)
819 LOCAL_LABEL(UMThunkStub_RegArgumentsSetup):
820 ldr x16, [x3, #UMThunkMarshInfo__m_pILStub]
822 RESTORE_ARGUMENT_REGISTERS fp, 16
826 LOCAL_LABEL(UMThunkStub_PostCall):
828 // m_fPreemptiveGCDisabled is 4 byte field so using 32-bit variant
829 str w4, [x19, #Thread__m_fPreemptiveGCDisabled]
832 EPILOG_RESTORE_REG x19, 96
833 EPILOG_RESTORE_REG_PAIR_INDEXED fp, lr, 112
837 LOCAL_LABEL(UMThunkStub_DoThreadSetup):
838 sub sp, sp, #SIZEOF__FloatArgumentRegisters
839 SAVE_FLOAT_ARGUMENT_REGISTERS sp, 0
840 bl C_FUNC(CreateThreadBlockThrow)
841 RESTORE_FLOAT_ARGUMENT_REGISTERS sp, 0
842 add sp, sp, #SIZEOF__FloatArgumentRegisters
843 b LOCAL_LABEL(UMThunkStub_HaveThread)
845 LOCAL_LABEL(UMThunkStub_DoTrapReturningThreads):
846 sub sp, sp, #SIZEOF__FloatArgumentRegisters
847 SAVE_FLOAT_ARGUMENT_REGISTERS sp, 0
848 // x0 already contains Thread* pThread
849 // UMEntryThunk* pUMEntry
850 ldr x1, [fp, #UMThunkStub_HiddenArg]
851 bl C_FUNC(UMThunkStubRareDisableWorker)
852 RESTORE_FLOAT_ARGUMENT_REGISTERS sp, 0
853 add sp, sp, #SIZEOF__FloatArgumentRegisters
854 b LOCAL_LABEL(UMThunkStub_InCooperativeMode)
856 NESTED_END UMThunkStub, _TEXT
858 #ifdef FEATURE_HIJACK
859 // ------------------------------------------------------------------
860 // Hijack function for functions which return a scalar type or a struct (value type)
861 NESTED_ENTRY OnHijackTripThread, _TEXT, NoHandler
862 PROLOG_SAVE_REG_PAIR_INDEXED fp, lr, -176
863 // Spill callee saved registers
864 PROLOG_SAVE_REG_PAIR x19, x20, 16
865 PROLOG_SAVE_REG_PAIR x21, x22, 32
866 PROLOG_SAVE_REG_PAIR x23, x24, 48
867 PROLOG_SAVE_REG_PAIR x25, x26, 64
868 PROLOG_SAVE_REG_PAIR x27, x28, 80
870 // save any integral return value(s)
871 stp x0, x1, [sp, #96]
873 // save any FP/HFA return value(s)
874 stp q0, q1, [sp, #112]
875 stp q2, q3, [sp, #144]
880 // restore any integral return value(s)
881 ldp x0, x1, [sp, #96]
883 // restore any FP/HFA return value(s)
884 ldp q0, q1, [sp, #112]
885 ldp q2, q3, [sp, #144]
887 EPILOG_RESTORE_REG_PAIR x19, x20, 16
888 EPILOG_RESTORE_REG_PAIR x21, x22, 32
889 EPILOG_RESTORE_REG_PAIR x23, x24, 48
890 EPILOG_RESTORE_REG_PAIR x25, x26, 64
891 EPILOG_RESTORE_REG_PAIR x27, x28, 80
892 EPILOG_RESTORE_REG_PAIR_INDEXED fp, lr, 176
894 NESTED_END OnHijackTripThread, _TEXT
896 #endif // FEATURE_HIJACK
898 // ------------------------------------------------------------------
899 // Redirection Stub for GC in fully interruptible method
900 //GenerateRedirectedHandledJITCaseStub GCThreadControl
901 // ------------------------------------------------------------------
902 //GenerateRedirectedHandledJITCaseStub DbgThreadControl
903 // ------------------------------------------------------------------
904 //GenerateRedirectedHandledJITCaseStub UserSuspend
907 // ------------------------------------------------------------------
908 // Redirection Stub for GC Stress
909 GenerateRedirectedHandledJITCaseStub GCStress
913 // ------------------------------------------------------------------
915 // This helper enables us to call into a funclet after restoring Fp register
916 NESTED_ENTRY CallEHFunclet, _TEXT, NoHandler
921 // X2 = address of X19 register in CONTEXT record// used to restore the non-volatile registers of CrawlFrame
922 // X3 = address of the location where the SP of funclet's caller (i.e. this helper) should be saved.
925 // Using below prolog instead of PROLOG_SAVE_REG_PAIR_INDEXED fp,lr, -96
926 // is intentional. Above statement would also emit instruction to save
927 // sp in fp. If sp is saved in fp in prolog then it is not expected that fp can change in the body
928 // of method. However, this method needs to be able to change fp before calling funclet.
929 // This is required to access locals in funclet.
930 PROLOG_SAVE_REG_PAIR_INDEXED x29, lr, -96
932 // Spill callee saved registers
933 PROLOG_SAVE_REG_PAIR x19, x20, 16
934 PROLOG_SAVE_REG_PAIR x21, x22, 32
935 PROLOG_SAVE_REG_PAIR x23, x24, 48
936 PROLOG_SAVE_REG_PAIR x25, x26, 64
937 PROLOG_SAVE_REG_PAIR x27, x28, 80
939 // Save the SP of this function
943 ldp x19, x20, [x2, #0]
944 ldp x21, x22, [x2, #16]
945 ldp x23, x24, [x2, #32]
946 ldp x25, x26, [x2, #48]
947 ldp x27, x28, [x2, #64]
948 ldr fp, [x2, #80] // offset of fp in CONTEXT relative to X19
950 // Invoke the funclet
954 EPILOG_RESTORE_REG_PAIR x19, x20, 16
955 EPILOG_RESTORE_REG_PAIR x21, x22, 32
956 EPILOG_RESTORE_REG_PAIR x23, x24, 48
957 EPILOG_RESTORE_REG_PAIR x25, x26, 64
958 EPILOG_RESTORE_REG_PAIR x27, x28, 80
959 EPILOG_RESTORE_REG_PAIR_INDEXED fp, lr, 96
962 NESTED_END CallEHFunclet, _TEXT
964 // This helper enables us to call into a filter funclet by passing it the CallerSP to lookup the
965 // frame pointer for accessing the locals in the parent method.
966 NESTED_ENTRY CallEHFilterFunclet, _TEXT, NoHandler
968 PROLOG_SAVE_REG_PAIR_INDEXED fp, lr, -16
973 // X1 = SP of the caller of the method/funclet containing the filter
975 // X3 = address of the location where the SP of funclet's caller (i.e. this helper) should be saved.
977 // Save the SP of this function
979 // Invoke the filter funclet
982 EPILOG_RESTORE_REG_PAIR_INDEXED fp, lr, 16
985 NESTED_END CallEHFilterFunclet, _TEXT
987 #define FaultingExceptionFrame_StackAlloc (SIZEOF__GSCookie + SIZEOF__FaultingExceptionFrame)
988 #define FaultingExceptionFrame_FrameOffset SIZEOF__GSCookie
990 .macro GenerateRedirectedStubWithFrame stub, target
993 // This is the primary function to which execution will be redirected to.
995 NESTED_ENTRY \stub, _TEXT, NoHandler
998 // IN: lr: original IP before redirect
1001 PROLOG_SAVE_REG_PAIR_INDEXED fp, lr, -16
1002 PROLOG_STACK_ALLOC FaultingExceptionFrame_StackAlloc
1004 // At this point, the stack maybe misaligned if the thread abort was asynchronously
1005 // triggered in the prolog or epilog of the managed method. For such a case, we must
1006 // align the stack before calling into the VM.
1008 // Runtime check for 16-byte alignment.
1013 // Save pointer to FEF for GetFrameFromRedirectedStubStackFrame
1014 add x19, sp, #FaultingExceptionFrame_FrameOffset
1016 // Prepare to initialize to NULL
1018 str x1, [x19]// Initialize vtbl (it is not strictly necessary)
1019 str x1, [x19, #FaultingExceptionFrame__m_fFilterExecuted]// Initialize BOOL for personality routine
1021 mov x0, x19 // move the ptr to FEF in X0
1025 // Target should not return.
1028 NESTED_END \stub, _TEXT
1033 // ------------------------------------------------------------------
1034 // ResolveWorkerChainLookupAsmStub
1036 // This method will perform a quick chained lookup of the entry if the
1037 // initial cache lookup fails.
1040 // x9 contains the pointer to the current ResolveCacheElem
1041 // x11 contains the address of the indirection (and the flags in the low two bits)
1042 // x12 contains our contract the DispatchToken
1043 // Must be preserved:
1044 // x0 contains the instance object ref that we are making an interface call on
1045 // x9 Must point to a ResolveCacheElem [For Sanity]
1046 // [x1-x7] contains any additional register arguments for the interface method
1049 // x13 contains our type the MethodTable (from object ref in x0)
1052 // x0, [x1-x7] arguments for the interface implementation target
1054 // On Exit (to ResolveWorkerAsmStub):
1055 // x11 contains the address of the indirection and the flags in the low two bits.
1056 // x12 contains our contract (DispatchToken)
1057 // x16,x17 will be trashed
1060 #define BACKPATCH_FLAG 1
1061 #define PROMOTE_CHAIN_FLAG 2
1063 NESTED_ENTRY ResolveWorkerChainLookupAsmStub, _TEXT, NoHandler
1065 tst x11, #BACKPATCH_FLAG // First we check if x11 has the BACKPATCH_FLAG set
1066 bne LOCAL_LABEL(Fail) // If the BACKPATCH_FLAGS is set we will go directly to the ResolveWorkerAsmStub
1068 ldr x13, [x0] // retrieve the MethodTable from the object ref in x0
1069 LOCAL_LABEL(MainLoop):
1070 ldr x9, [x9, #ResolveCacheElem__pNext] // x9 <= the next entry in the chain
1072 beq LOCAL_LABEL(Fail)
1075 cmp x16, x13 // compare our MT with the one in the ResolveCacheElem
1076 bne LOCAL_LABEL(MainLoop)
1078 cmp x17, x12 // compare our DispatchToken with one in the ResolveCacheElem
1079 bne LOCAL_LABEL(MainLoop)
1081 LOCAL_LABEL(Success):
1082 PREPARE_EXTERNAL_VAR g_dispatch_cache_chain_success_counter, x13
1086 blt LOCAL_LABEL(Promote)
1088 ldr x16, [x9, #ResolveCacheElem__target] // get the ImplTarget
1089 br x16 // branch to interface implemenation target
1091 LOCAL_LABEL(Promote):
1092 // Move this entry to head postion of the chain
1094 str x16, [x13] // be quick to reset the counter so we don't get a bunch of contending threads
1095 orr x11, x11, #PROMOTE_CHAIN_FLAG // set PROMOTE_CHAIN_FLAG
1096 mov x12, x9 // We pass the ResolveCacheElem to ResolveWorkerAsmStub instead of the DispatchToken
1099 b ResolveWorkerAsmStub // call the ResolveWorkerAsmStub method to transition into the VM
1101 NESTED_END ResolveWorkerChainLookupAsmStub, _TEXT
1103 // ------------------------------------------------------------------
1104 // void ResolveWorkerAsmStub(args in regs x0-x7 & stack and possibly retbuf arg in x8, x11:IndirectionCellAndFlags, x12:DispatchToken)
1106 // The stub dispatch thunk which transfers control to VSD_ResolveWorker.
1107 NESTED_ENTRY ResolveWorkerAsmStub, _TEXT, NoHandler
1109 PROLOG_WITH_TRANSITION_BLOCK
1111 add x0, sp, #__PWTB_TransitionBlock // pTransitionBlock
1112 and x1, x11, #-4 // Indirection cell
1113 mov x2, x12 // DispatchToken
1114 and x3, x11, #3 // flag
1115 bl VSD_ResolveWorker
1118 EPILOG_WITH_TRANSITION_BLOCK_TAILCALL
1120 EPILOG_BRANCH_REG x9
1122 NESTED_END ResolveWorkerAsmStub, _TEXT
1124 #ifdef FEATURE_READYTORUN
1126 NESTED_ENTRY DelayLoad_MethodCall_FakeProlog, _TEXT, NoHandler
1127 DelayLoad_MethodCall:
1128 .global DelayLoad_MethodCall
1129 PROLOG_WITH_TRANSITION_BLOCK
1131 add x0, sp, #__PWTB_TransitionBlock // pTransitionBlock
1132 mov x1, x11 // Indirection cell
1133 mov x2, x9 // sectionIndex
1134 mov x3, x10 // Module*
1135 bl ExternalMethodFixupWorker
1138 EPILOG_WITH_TRANSITION_BLOCK_TAILCALL
1139 // Share patch label
1140 b ExternalMethodFixupPatchLabel
1142 NESTED_END DelayLoad_MethodCall_FakeProlog, _TEXT
1145 .macro DynamicHelper frameFlags, suffix
1146 NESTED_ENTRY DelayLoad_Helper\suffix\()_FakeProlog, _TEXT, NoHandler
1147 DelayLoad_Helper\suffix:
1148 .global DelayLoad_Helper\suffix
1150 PROLOG_WITH_TRANSITION_BLOCK
1152 add x0, sp, #__PWTB_TransitionBlock // pTransitionBlock
1153 mov x1, x11 // Indirection cell
1154 mov x2, x9 // sectionIndex
1155 mov x3, x10 // Module*
1157 bl DynamicHelperWorker
1158 cbnz x0, LOCAL_LABEL(FakeProlog\suffix\()_0)
1159 ldr x0, [sp, #__PWTB_ArgumentRegister_FirstArg]
1160 EPILOG_WITH_TRANSITION_BLOCK_RETURN
1161 LOCAL_LABEL(FakeProlog\suffix\()_0):
1163 EPILOG_WITH_TRANSITION_BLOCK_TAILCALL
1164 EPILOG_BRANCH_REG x12
1166 NESTED_END DelayLoad_Helper\suffix\()_FakeProlog, _TEXT
1169 DynamicHelper DynamicHelperFrameFlags_Default
1170 DynamicHelper DynamicHelperFrameFlags_ObjectArg, _Obj
1171 DynamicHelper DynamicHelperFrameFlags_ObjectArg | DynamicHelperFrameFlags_ObjectArg2, _ObjObj
1174 #ifdef FEATURE_PREJIT
1175 // ------------------------------------------------------------------
1176 // void StubDispatchFixupStub(args in regs x0-x7 & stack and possibly retbuff arg in x8, x11:IndirectionCellAndFlags)
1178 // The stub dispatch thunk which transfers control to StubDispatchFixupWorker.
1179 NESTED_ENTRY StubDispatchFixupStub, _TEXT, NoHandler
1181 PROLOG_WITH_TRANSITION_BLOCK
1183 add x0, sp, #__PWTB_TransitionBlock // pTransitionBlock
1184 and x1, x11, #-4 // Indirection cell
1185 mov x2, #0 // sectionIndex
1186 mov x3, #0 // pModule
1187 bl C_FUNC(StubDispatchFixupWorker)
1190 EPILOG_WITH_TRANSITION_BLOCK_TAILCALL
1191 PATCH_LABEL StubDispatchFixupPatchLabel
1192 EPILOG_BRANCH_REG x12
1194 NESTED_END StubDispatchFixupStub, _TEXT
1197 #ifdef FEATURE_COMINTEROP
1199 // Function used by COM interop to get floating point return value (since it's not in the same
1200 // register(s) as non-floating point values).
1203 // x0 : size of the FP result (4 or 8 bytes)
1204 // x1 : pointer to 64-bit buffer to receive result
1207 // buffer pointed to by x1 on entry contains the float or double argument as appropriate
1209 LEAF_ENTRY getFPReturn, _TEXT
1211 LEAF_END getFPReturn, _TEXT
1213 // ------------------------------------------------------------------
1214 // Function used by COM interop to set floating point return value (since it's not in the same
1215 // register(s) as non-floating point values).
1218 // x0 : size of the FP result (4 or 8 bytes)
1219 // x1 : 32-bit or 64-bit FP result
1222 // s0 : float result if x0 == 4
1223 // d0 : double result if x0 == 8
1225 LEAF_ENTRY setFPReturn, _TEXT
1227 LEAF_END setFPReturn, _TEXT
1231 // JIT Static access helpers when coreclr host specifies single appdomain flag
1234 // ------------------------------------------------------------------
1235 // void* JIT_GetSharedNonGCStaticBase(SIZE_T moduleDomainID, DWORD dwClassDomainID)
1237 LEAF_ENTRY JIT_GetSharedNonGCStaticBase_SingleAppDomain, _TEXT
1238 // If class is not initialized, bail to C++ helper
1239 add x2, x0, #DomainLocalModule__m_pDataBlob
1240 ldrb w2, [x2, w1, UXTW]
1242 beq LOCAL_LABEL(JIT_GetSharedNonGCStaticBase_SingleAppDomain_CallHelper)
1246 LOCAL_LABEL(JIT_GetSharedNonGCStaticBase_SingleAppDomain_CallHelper):
1247 // Tail call JIT_GetSharedNonGCStaticBase_Helper
1248 b C_FUNC(JIT_GetSharedNonGCStaticBase_Helper)
1249 LEAF_END JIT_GetSharedNonGCStaticBase_SingleAppDomain, _TEXT
1252 // ------------------------------------------------------------------
1253 // void* JIT_GetSharedNonGCStaticBaseNoCtor(SIZE_T moduleDomainID, DWORD dwClassDomainID)
1255 LEAF_ENTRY JIT_GetSharedNonGCStaticBaseNoCtor_SingleAppDomain, _TEXT
1257 LEAF_END JIT_GetSharedNonGCStaticBaseNoCtor_SingleAppDomain, _TEXT
1260 // ------------------------------------------------------------------
1261 // void* JIT_GetSharedGCStaticBase(SIZE_T moduleDomainID, DWORD dwClassDomainID)
1263 LEAF_ENTRY JIT_GetSharedGCStaticBase_SingleAppDomain, _TEXT
1264 // If class is not initialized, bail to C++ helper
1265 add x2, x0, #DomainLocalModule__m_pDataBlob
1266 ldrb w2, [x2, w1, UXTW]
1268 beq LOCAL_LABEL(JIT_GetSharedGCStaticBase_SingleAppDomain_CallHelper)
1270 ldr x0, [x0, #DomainLocalModule__m_pGCStatics]
1273 LOCAL_LABEL(JIT_GetSharedGCStaticBase_SingleAppDomain_CallHelper):
1274 // Tail call Jit_GetSharedGCStaticBase_Helper
1275 b C_FUNC(JIT_GetSharedGCStaticBase_Helper)
1276 LEAF_END JIT_GetSharedGCStaticBase_SingleAppDomain, _TEXT
1279 // ------------------------------------------------------------------
1280 // void* JIT_GetSharedGCStaticBaseNoCtor(SIZE_T moduleDomainID, DWORD dwClassDomainID)
1282 LEAF_ENTRY JIT_GetSharedGCStaticBaseNoCtor_SingleAppDomain, _TEXT
1283 ldr x0, [x0, #DomainLocalModule__m_pGCStatics]
1285 LEAF_END JIT_GetSharedGCStaticBaseNoCtor_SingleAppDomain, _TEXT
1287 // ------------------------------------------------------------------
1288 // __declspec(naked) void F_CALL_CONV JIT_Stelem_Ref(PtrArray* array, unsigned idx, Object* val)
1289 LEAF_ENTRY JIT_Stelem_Ref, _TEXT
1290 // We retain arguments as they were passed and use x0 == array x1 == idx x2 == val
1292 // check for null array
1293 cbz x0, LOCAL_LABEL(ThrowNullReferenceException)
1296 ldr x3,[x0,#ArrayBase__m_NumComponents]
1298 bls LOCAL_LABEL(ThrowIndexOutOfRangeException)
1300 // fast path to null assignment (doesn't need any write-barriers)
1301 cbz x2, LOCAL_LABEL(AssigningNull)
1303 // Verify the array-type and val-type matches before writing
1304 ldr x12, [x0] // x12 = array MT
1305 ldr x3, [x2] // x3 = val->GetMethodTable()
1306 ldr x12, [x12, #MethodTable__m_ElementType] // array->GetArrayElementTypeHandle()
1308 beq C_FUNC(JIT_Stelem_DoWrite)
1310 // Types didnt match but allow writing into an array of objects
1311 PREPARE_EXTERNAL_VAR g_pObjectClass, x3
1312 ldr x3, [x3] // x3 = *g_pObjectClass
1313 cmp x3, x12 // array type matches with Object*
1314 beq C_FUNC(JIT_Stelem_DoWrite)
1316 // array type and val type do not exactly match. Raise frame and do detailed match
1317 b C_FUNC(JIT_Stelem_Ref_NotExactMatch)
1319 LOCAL_LABEL(AssigningNull):
1320 // Assigning null doesn't need write barrier
1321 add x0, x0, x1, LSL #3 // x0 = x0 + (x1 x 8) = array->m_array[idx]
1322 str x2, [x0, #PtrArray__m_Array] // array->m_array[idx] = val
1325 LOCAL_LABEL(ThrowNullReferenceException):
1326 // Tail call JIT_InternalThrow(NullReferenceException)
1327 ldr x0, =CORINFO_NullReferenceException_ASM
1328 b C_FUNC(JIT_InternalThrow)
1330 LOCAL_LABEL(ThrowIndexOutOfRangeException):
1331 // Tail call JIT_InternalThrow(NullReferenceException)
1332 ldr x0, =CORINFO_IndexOutOfRangeException_ASM
1333 b C_FUNC(JIT_InternalThrow)
1335 LEAF_END JIT_Stelem_Ref, _TEXT
1337 // ------------------------------------------------------------------
1338 // __declspec(naked) void F_CALL_CONV JIT_Stelem_Ref_NotExactMatch(PtrArray* array,
1339 // unsigned idx, Object* val)
1340 // x12 = array->GetArrayElementTypeHandle()
1342 NESTED_ENTRY JIT_Stelem_Ref_NotExactMatch, _TEXT, NoHandler
1343 PROLOG_SAVE_REG_PAIR_INDEXED fp, lr, -48
1344 // Spill callee saved registers
1345 PROLOG_SAVE_REG_PAIR x0, x1, 16
1346 PROLOG_SAVE_REG x2, 32
1348 // allow in case val can be casted to array element type
1349 // call ObjIsInstanceOfNoGC(val, array->GetArrayElementTypeHandle())
1350 mov x1, x12 // array->GetArrayElementTypeHandle()
1352 bl C_FUNC(ObjIsInstanceOfNoGC)
1353 cmp x0, TypeHandle_CanCast
1354 beq LOCAL_LABEL(DoWrite) // ObjIsInstance returned TypeHandle::CanCast
1356 // check via raising frame
1357 LOCAL_LABEL(NeedFrame):
1358 add x1, sp, #16 // x1 = &array
1359 add x0, sp, #32 // x0 = &val
1361 bl C_FUNC(ArrayStoreCheck) // ArrayStoreCheck(&val, &array)
1363 LOCAL_LABEL(DoWrite):
1364 EPILOG_RESTORE_REG_PAIR x0, x1, 16
1365 EPILOG_RESTORE_REG x2, 32
1366 EPILOG_RESTORE_REG_PAIR_INDEXED fp, lr, 48
1367 b C_FUNC(JIT_Stelem_DoWrite)
1368 NESTED_END JIT_Stelem_Ref_NotExactMatch, _TEXT
1370 // ------------------------------------------------------------------
1371 // __declspec(naked) void F_CALL_CONV JIT_Stelem_DoWrite(PtrArray* array, unsigned idx, Object* val)
1372 LEAF_ENTRY JIT_Stelem_DoWrite, _TEXT
1374 // Setup args for JIT_WriteBarrier. x14 = &array->m_array[idx] x15 = val
1375 add x14, x0, #PtrArray__m_Array // x14 = &array->m_array
1376 add x14, x14, x1, LSL #3
1377 mov x15, x2 // x15 = val
1379 // Branch to the write barrier (which is already correctly overwritten with
1380 // single or multi-proc code based on the current CPU
1381 b C_FUNC(JIT_WriteBarrier)
1382 LEAF_END JIT_Stelem_DoWrite, _TEXT
1384 #ifdef PROFILING_SUPPORTED
1386 // ------------------------------------------------------------------
1387 LEAF_ENTRY JIT_ProfilerEnterLeaveTailcallStub, _TEXT
1389 LEAF_END JIT_ProfilerEnterLeaveTailcallStub, _TEXT
1391 // ------------------------------------------------------------------
1392 #define PROFILE_ENTER 1
1393 #define PROFILE_LEAVE 2
1394 #define PROFILE_TAILCALL 4
1395 #define SIZEOF__PROFILE_PLATFORM_SPECIFIC_DATA 256
1397 // ------------------------------------------------------------------
1398 .macro GenerateProfileHelper helper, flags
1399 NESTED_ENTRY \helper\()Naked, _TEXT, NoHandler
1401 // x10 = functionIDOrClientID
1406 // Values of x0-x8, q0-q7, fp are preserved.
1407 // Values of other volatile registers are not preserved.
1409 PROLOG_SAVE_REG_PAIR_INDEXED fp, lr, -SIZEOF__PROFILE_PLATFORM_SPECIFIC_DATA // Allocate space and save Fp, Pc.
1410 SAVE_ARGUMENT_REGISTERS sp, 16 // Save x8 and argument registers (x0-x7).
1411 str xzr, [sp, 88] // Clear functionId.
1412 SAVE_FLOAT_ARGUMENT_REGISTERS sp, 96 // Save floating-point/SIMD registers (q0-q7).
1413 add x12, fp, SIZEOF__PROFILE_PLATFORM_SPECIFIC_DATA // Compute probeSp - initial value of Sp on entry to the helper.
1414 stp x12, x11, [sp, 224] // Save probeSp, profiledSp.
1415 str xzr, [sp, 240] // Clear hiddenArg.
1417 stp w12, wzr, [sp, 248] // Save flags and clear unused field.
1423 RESTORE_ARGUMENT_REGISTERS sp, 16 // Restore x8 and argument registers.
1424 RESTORE_FLOAT_ARGUMENT_REGISTERS sp, 96 // Restore floating-point/SIMD registers.
1426 EPILOG_RESTORE_REG_PAIR_INDEXED fp, lr, SIZEOF__PROFILE_PLATFORM_SPECIFIC_DATA
1429 NESTED_END \helper\()Naked, _TEXT
1432 GenerateProfileHelper ProfileEnter, PROFILE_ENTER
1433 GenerateProfileHelper ProfileLeave, PROFILE_LEAVE
1434 GenerateProfileHelper ProfileTailcall, PROFILE_TAILCALL