1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation llacenses this file to you under the MIT license.
4 #include "asmconstants.h"
5 #include "unixasmmacros.inc"
7 LEAF_ENTRY GetCurrentIP, _TEXT
10 LEAF_END GetCurrentIP, _TEXT
12 // LPVOID __stdcall GetCurrentSP(void)//
13 LEAF_ENTRY GetCurrentSP, _TEXT
16 LEAF_END GetCurrentSP, _TEXT
18 //-----------------------------------------------------------------------------
19 // The following Macros help in WRITE_BARRIER Implementations
20 // WRITE_BARRIER_ENTRY
22 // Declare the start of a write barrier function. Use similarly to NESTED_ENTRY. This is the only legal way
23 // to declare a write barrier function.
25 .macro WRITE_BARRIER_ENTRY name
26 LEAF_ENTRY \name, _TEXT
31 // The partner to WRITE_BARRIER_ENTRY, used llake NESTED_END.
33 .macro WRITE_BARRIER_END name
34 LEAF_END_MARKED \name, _TEXT
37 // void JIT_UpdateWriteBarrierState(bool skipEphemeralCheck, size_t writeableOffset)
39 // Update shadow copies of the various state info required for barrier
41 // State info is contained in a llateral pool at the end of the function
42 // Placed in text section so that it is close enough to use ldr llateral and still
43 // be relocatable. Ellaminates need for PREPARE_EXTERNAL_VAR in hot code.
45 // Allagn and group state info together so it fits in a single cache line
46 // and each entry can be written atomically
48 WRITE_BARRIER_ENTRY JIT_UpdateWriteBarrierState
49 // a0-a7 and t3 will contain intended new state
50 // t0 will preserve skipEphemeralCheck
51 // t2 will be used for pointers
59 #ifdef FEATURE_MANUALLY_MANAGED_CARD_BUNDLES
60 lla a1, g_card_bundle_table
64 #ifdef WRITE_BARRIER_CHECK
72 #ifdef FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP
77 lla a5, g_ephemeral_low
80 lla a6, g_ephemeral_high
83 beq t0, zero, LOCAL_LABEL(EphemeralCheckEnabled)
87 LOCAL_LABEL(EphemeralCheckEnabled):
89 lla a7, g_lowest_address
92 lla t3, g_highest_address
96 lla t2, JIT_WriteBarrier_Table_Loc
112 WRITE_BARRIER_END JIT_UpdateWriteBarrierState
114 // ----------------------------------------------------------------------------------------
115 // __declspec(naked) void F_CALL_CONV JIT_WriteBarrier_Callable(Object **dst, Object* val)
116 LEAF_ENTRY JIT_WriteBarrier_Callable, _TEXT
117 // Setup args for JIT_WriteBarrier. a0 = dst ; a1 = val
118 addi t3, a0, 0 // t3 = dst
119 addi t4, a1, 0 // t4 = val
121 // Branch to the write barrier
122 lla t1, JIT_WriteBarrier_Loc
125 LEAF_END JIT_WriteBarrier_Callable, _TEXT
128 .balign 64 // Align to power of two at least as big as patchable literal pool so that it fits optimally in cache line
129 // ------------------------------------------------------------------
130 // Start of the writeable code region
131 LEAF_ENTRY JIT_PatchedCodeStart, _TEXT
133 LEAF_END JIT_PatchedCodeStart, _TEXT
135 // void JIT_ByRefWriteBarrier
138 // t5 : the source address (points to object reference to write)
139 // t3: the destination address (object reference written here)
142 // t5 : incremented by 8
146 // void JIT_ByRefWriteBarrier
147 WRITE_BARRIER_ENTRY JIT_ByRefWriteBarrier
150 tail C_FUNC(JIT_CheckedWriteBarrier)
151 WRITE_BARRIER_END JIT_ByRefWriteBarrier
153 //-----------------------------------------------------------------------------
154 // Simple WriteBarriers
155 // void JIT_CheckedWriteBarrier(Object** dst, Object* src)
158 // t3 : the destination address (LHS of the assignment)
159 // t4 : the object reference (RHS of the assignment)
165 // t3 : trashed (incremented by 8 to implement JIT_ByRefWriteBarrier contract)
168 WRITE_BARRIER_ENTRY JIT_CheckedWriteBarrier
169 lla t6, wbs_lowest_address
173 lla t1, wbs_highest_address
177 beq t6, zero, C_FUNC(JIT_WriteBarrier)
182 WRITE_BARRIER_END JIT_CheckedWriteBarrier
184 // void JIT_WriteBarrier(Object** dst, Object* src)
186 // t3 : the destination address (LHS of the assignment)
187 // t4 1 the object reference (RHS of the assignment)
194 // t3 : trashed (incremented by 8 to implement JIT_ByRefWriteBarrier contract)
196 WRITE_BARRIER_ENTRY JIT_WriteBarrier
197 // TODO: sync_release (runtime detection required)
202 #ifdef WRITE_BARRIER_CHECK
203 // Update GC Shadow Heap
205 // Do not perform the work if g_GCShadow is 0
209 beq t1, zero, LOCAL_LABEL(ShadowUpdateDisabled)
211 // Compute address of shadow heap location:
212 // pShadow = g_GCShadow + ($t3 - g_lowest_address)
213 lla t6, wbs_lowest_address
219 // if (pShadow >= g_GCShadowEnd) goto end
220 lla t6, wbs_GCShadowEnd
224 beq t6, zero, LOCAL_LABEL(ShadowUpdateEnd)
229 // Ensure that the write to the shadow heap occurs before the read from the GC heap so that race
230 // conditions are caught by INVALIDGCVALUE.
233 // if (*t3 == t4) goto end
235 beq t6, t4, LOCAL_LABEL(ShadowUpdateEnd)
237 // *pShadow = INVALIDGCVALUE (0xcccccccd)
240 LOCAL_LABEL(ShadowUpdateEnd):
241 LOCAL_LABEL(ShadowUpdateDisabled):
244 #ifdef FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP
245 // Update the write watch table if necessary
247 lla t6, wbs_sw_ww_table
249 beq t6, zero, LOCAL_LABEL(CheckCardTable)
252 add t6, t6, t0 // SoftwareWriteWatch::AddressToTableByteIndexShift
254 bne t0, zero, LOCAL_LABEL(CheckCardTable)
259 LOCAL_LABEL(CheckCardTable):
261 // Branch to Exit if the reference is not in the Gen0 heap
262 lla t6, wbs_ephemeral_low
264 beq t6, zero, LOCAL_LABEL(SkipEphemeralCheck)
267 lla t6, wbs_ephemeral_high
271 bne t0, zero, LOCAL_LABEL(Exit)
273 LOCAL_LABEL(SkipEphemeralCheck):
274 // Check if we need to update the card table
275 lla t6, wbs_card_table
281 beq t1, t0, LOCAL_LABEL(Exit)
285 #ifdef FEATURE_MANUALLY_MANAGED_CARD_BUNDLES
286 // Check if we need to update the card bundle table
287 lla t6, wbs_card_bundle_table
294 beq t6, t0, LOCAL_LABEL(Exit)
301 WRITE_BARRIER_END JIT_WriteBarrier
303 // Begin patchable literal pool
304 .balign 64 // Align to power of two at least as big as patchable literal pool so that it fits optimally in cache line
305 WRITE_BARRIER_ENTRY JIT_WriteBarrier_Table
309 wbs_card_bundle_table:
325 WRITE_BARRIER_END JIT_WriteBarrier_Table
327 // ------------------------------------------------------------------
328 // End of the writeable code region
329 LEAF_ENTRY JIT_PatchedCodeLast, _TEXT
331 LEAF_END JIT_PatchedCodeLast, _TEXT
335 // If a preserved register were pushed onto the stack between
336 // the managed caller and the H_M_F, ptrS0_S8 will point to its
337 // location on the stack and it would have been updated on the
338 // stack by the GC already and it will be popped back into the
339 // appropriate register when the appropriate epilog is run.
341 // Otherwise, the register is preserved across all the code
342 // in this HCALL or FCALL, so we need to update those registers
343 // here because the GC will have updated our copies in the
346 // So, if ptrS0_S8 points into the MachState, we need to update
347 // the register here. That's what this macro does.
349 .macro RestoreRegMS idx, reg
352 // a0 = address of MachState
354 // idx: Index of the callee register
355 // s0/fp: 0, s1: 1, s3-s11: 4-11, gp: 12 tp: 13
357 // reg: Register name (e.g. s0, s1, etc)
359 // Get the address of the specified captured register from machine state
360 addi a2, a0, (MachState__captureCalleeSavedRegisters + (\idx * 8))
362 //// Get the content of specified preserved register pointer from machine state
363 ld a3, (MachState__ptrCalleeSavedRegisters + (\idx * 8))(a0)
365 bne a2, a3, LOCAL_LABEL(NoRestore_\reg)
368 LOCAL_LABEL(NoRestore_\reg):
372 NESTED_ENTRY ThePreStub, _TEXT, NoHandler
373 PROLOG_WITH_TRANSITION_BLOCK
375 addi a1, METHODDESC_REGISTER, 0 // pMethodDesc
377 addi a0, sp, __PWTB_TransitionBlock // pTransitionBlock
381 EPILOG_WITH_TRANSITION_BLOCK_TAILCALL
383 NESTED_END ThePreStub, _TEXT
385 // ------------------------------------------------------------------
387 // EXTERN_C int __fastcall HelperMethodFrameRestoreState(
388 // INDEBUG_COMMA(HelperMethodFrame *pFrame)
391 LEAF_ENTRY HelperMethodFrameRestoreState, _TEXT
396 // If machine state is invalid, then simply exit
397 lw a1, MachState__isValid(a0)
398 beq a1, zero, LOCAL_LABEL(Done)
400 // manually assign index
401 // s0/fp: 0, s1: 1, s3-s11: 4-11, gp: 12 tp: 13
417 // Its imperative that the return value of HelperMethodFrameRestoreState is zero
418 // as it is used in the state machine to loop until it becomes zero.
419 // Refer to HELPER_METHOD_FRAME_END macro for details.
422 LEAF_END HelperMethodFrameRestoreState, _TEXT
424 //-----------------------------------------------------------------------------
425 // This routine captures the machine state. It is used by helper method frame
426 //-----------------------------------------------------------------------------
427 //void LazyMachStateCaptureState(struct LazyMachState *pState)//
428 LEAF_ENTRY LazyMachStateCaptureState, _TEXT
429 // marks that this is not yet valid
430 sw zero, (MachState__isValid)(a0)
432 sd ra, (LazyMachState_captureIp)(a0)
435 sd sp, (LazyMachState_captureSp)(a0)
437 // save non-volatile registers that can contain object references
438 addi a1, a0, LazyMachState_captureCalleeSavedRegisters
456 LEAF_END LazyMachStateCaptureState, _TEXT
458 // ------------------------------------------------------------------
459 // The call in ndirect import precode points to this function.
460 NESTED_ENTRY NDirectImportThunk, _TEXT, NoHandler
461 PROLOG_SAVE_REG_PAIR_INDEXED fp, ra, 0xa0
462 SAVE_ARGUMENT_REGISTERS sp, 0x20
463 SAVE_FLOAT_ARGUMENT_REGISTERS sp, 0x60
466 call C_FUNC(NDirectImportWorker)
469 // pop the stack and restore original register state
470 RESTORE_FLOAT_ARGUMENT_REGISTERS sp, 0x60
471 RESTORE_ARGUMENT_REGISTERS sp, 0x20
472 //EPILOG_RESTORE_REG gp, 16
473 EPILOG_RESTORE_REG_PAIR_INDEXED fp, ra, 0xa0
475 // If we got back from NDirectImportWorker, the MD has been successfully
476 // linked. Proceed to execute the original DLL call.
478 NESTED_END NDirectImportThunk, _TEXT
480 // void SinglecastDelegateInvokeStub(Delegate *pThis)
481 LEAF_ENTRY SinglecastDelegateInvokeStub, _TEXT
482 beq a0, zero, LOCAL_LABEL(LNullThis)
484 ld t4, (DelegateObject___methodPtr)(a0)
485 ld a0, (DelegateObject___target)(a0)
488 LOCAL_LABEL(LNullThis):
489 addi a0, zero, CORINFO_NullReferenceException_ASM
490 tail JIT_InternalThrow
491 LEAF_END SinglecastDelegateInvokeStub, _TEXT
493 // ------------------------------------------------------------------
495 LEAF_ENTRY ThePreStubPatch, _TEXT
496 .globl C_FUNC(ThePreStubPatchLabel)
497 C_FUNC(ThePreStubPatchLabel):
499 LEAF_END ThePreStubPatch, _TEXT
501 NESTED_ENTRY TheUMEntryPrestub, _TEXT, UnhandledExceptionHandlerUnix
502 // Save arguments and return address
503 PROLOG_SAVE_REG_PAIR_INDEXED fp, ra, 0xa0
504 //PROLOG_SAVE_REG gp, 16
505 SAVE_ARGUMENT_REGISTERS sp, 32
506 SAVE_FLOAT_ARGUMENT_REGISTERS sp, 96
510 call TheUMEntryPrestubWorker
513 // pop the stack and restore original register state
514 RESTORE_FLOAT_ARGUMENT_REGISTERS sp, 96
515 RESTORE_ARGUMENT_REGISTERS sp, 32
516 //EPILOG_RESTORE_REG gp, 16
517 EPILOG_RESTORE_REG_PAIR_INDEXED fp, ra, 0xa0
519 // and tailcall to the actual method
521 NESTED_END TheUMEntryPrestub, _TEXT
523 // ------------------------------------------------------------------
524 // void* JIT_GetSharedGCStaticBase(SIZE_T moduleDomainID, DWORD dwClassDomainID)
526 LEAF_ENTRY JIT_GetSharedGCStaticBase_SingleAppDomain, _TEXT
527 // If class is not initialized, bail to C++ helper
528 addi a2, a0, DomainLocalModule__m_pDataBlob
532 beq t5, zero, LOCAL_LABEL(JIT_GetSharedGCStaticBase_SingleAppDomain_CallHelper)
534 ld a0, DomainLocalModule__m_pGCStatics(a0)
537 LOCAL_LABEL(JIT_GetSharedGCStaticBase_SingleAppDomain_CallHelper):
538 // Tail call JIT_GetSharedGCStaticBase_Helper
539 call JIT_GetSharedGCStaticBase_Helper
540 LEAF_END JIT_GetSharedGCStaticBase_SingleAppDomain, _TEXT
542 // Make sure the `FaultingExceptionFrame_StackAlloc` is 16-byte aligned.
543 #define FaultingExceptionFrame_StackAlloc (SIZEOF__GSCookie + SIZEOF__FaultingExceptionFrame + 0x8)
544 #define FaultingExceptionFrame_FrameOffset SIZEOF__GSCookie
546 .macro GenerateRedirectedStubWithFrame stub, target
549 // This is the primary function to which execution will be redirected to.
551 NESTED_ENTRY \stub, _TEXT, NoHandler
554 // IN: ra: original IP before redirect
557 PROLOG_SAVE_REG_PAIR_INDEXED fp, ra, 16
559 // alloc stack for FaultingExceptionFrame.
560 addi sp, sp, -FaultingExceptionFrame_StackAlloc
562 // stack must be 16 bytes aligned
563 CHECK_STACK_ALIGNMENT
565 // Save pointer to FEF for GetFrameFromRedirectedStubStackFrame
566 addi a0, sp, FaultingExceptionFrame_FrameOffset
568 // Prepare to initialize to NULL
569 sd zero, 0(a0) // Initialize vtbl (it is not strictly necessary)
570 sd zero, FaultingExceptionFrame__m_fFilterExecuted(a0) // Initialize BOOL for personality routine
573 // Target should not return.
576 NESTED_END \stub, _TEXT
580 GenerateRedirectedStubWithFrame RedirectForThreadAbort, ThrowControlForThread
582 // ------------------------------------------------------------------
583 // ResolveWorkerChainLookupAsmStub
585 // This method will perform a quick chained lookup of the entry if the
586 // initial cache lookup fails.
589 // t1 contains the pointer to the current ResolveCacheElem
590 // t5 contains the address of the indirection (and the flags in the low two bits)
591 // t2 contains our contract the DispatchToken
592 // Must be preserved:
593 // a0 contains the instance object ref that we are making an interface call on
594 // t1 Must point to a ResolveCacheElem [For Sanity]
595 // [a1-a7] contains any additional register arguments for the interface method
598 // t6 contains our type the MethodTable (from object ref in a0)
601 // a0, [a1-a7] arguments for the interface implementation target
603 // On Exit (to ResolveWorkerAsmStub):
604 // t5 contains the address of the indirection and the flags in the low two bits.
605 // t2 contains our contract (DispatchToken)
606 // t4 will be trashed
609 #define BACKPATCH_FLAG 1
610 #define PROMOTE_CHAIN_FLAG 2
612 NESTED_ENTRY ResolveWorkerChainLookupAsmStub, _TEXT, NoHandler
613 andi t4, t5, BACKPATCH_FLAG // First we check if t5 has the BACKPATCH_FLAG set
614 bne t4, zero, LOCAL_LABEL(Fail) // If the BACKPATCH_FLAGS is set we will go directly to the ResolveWorkerAsmStub
616 ld t6, 0(a0) // retrieve the MethodTable from the object ref in a0
617 LOCAL_LABEL(MainLoop):
618 ld t1, (ResolveCacheElem__pNext)(t1) // t1 <= the next entry in the chain
619 beq t1, zero, LOCAL_LABEL(Fail)
622 // compare our MT with the one in the ResolveCacheElem
623 bne t4, t6, LOCAL_LABEL(MainLoop)
626 // compare our DispatchToken with one in the ResolveCacheElem
627 bne t2, t4, LOCAL_LABEL(MainLoop)
629 LOCAL_LABEL(Success):
630 PREPARE_EXTERNAL_VAR g_dispatch_cache_chain_success_counter, t6
634 blt t4, zero, LOCAL_LABEL(Promote)
636 ld t4, (ResolveCacheElem__target)(t1) // get the ImplTarget
637 jr t4 // branch to interface implementation target
639 LOCAL_LABEL(Promote):
640 // Move this entry to head position of the chain
642 sd t4, 0(t6) // be quick to reset the counter so we don't get a bunch of contending threads
643 ori t5, t5, PROMOTE_CHAIN_FLAG // set PROMOTE_CHAIN_FLAG
644 addi t2, t1, 0 // We pass the ResolveCacheElem to ResolveWorkerAsmStub instead of the DispatchToken
647 tail C_FUNC(ResolveWorkerAsmStub) // call the ResolveWorkerAsmStub method to transition into the VM
648 NESTED_END ResolveWorkerChainLookupAsmStub, _TEXT
650 // ------------------------------------------------------------------
651 // void ResolveWorkerAsmStub(args in regs a0-a7 & stack, t5:IndirectionCellAndFlags, t2:DispatchToken)
653 // The stub dispatch thunk which transfers control to VSD_ResolveWorker.
654 NESTED_ENTRY ResolveWorkerAsmStub, _TEXT, NoHandler
655 PROLOG_WITH_TRANSITION_BLOCK
657 addi a2, t2, 0 // DispatchToken
658 addi a0, sp, __PWTB_TransitionBlock // pTransitionBlock
660 andi a3, t5, 3 // flag
662 call C_FUNC(VSD_ResolveWorker)
665 EPILOG_WITH_TRANSITION_BLOCK_TAILCALL
668 NESTED_END ResolveWorkerAsmStub, _TEXT
670 // ------------------------------------------------------------------
671 // void* JIT_GetSharedNonGCStaticBaseNoCtor(SIZE_T moduleDomainID, DWORD dwClassDomainID)
673 LEAF_ENTRY JIT_GetSharedNonGCStaticBaseNoCtor_SingleAppDomain, _TEXT
675 LEAF_END JIT_GetSharedNonGCStaticBaseNoCtor_SingleAppDomain, _TEXT
677 // ------------------------------------------------------------------
678 // void* JIT_GetSharedGCStaticBaseNoCtor(SIZE_T moduleDomainID, DWORD dwClassDomainID)
680 LEAF_ENTRY JIT_GetSharedGCStaticBaseNoCtor_SingleAppDomain, _TEXT
681 ld a0, (DomainLocalModule__m_pGCStatics)(a0)
683 LEAF_END JIT_GetSharedGCStaticBaseNoCtor_SingleAppDomain, _TEXT
686 #ifdef FEATURE_HIJACK
687 // ------------------------------------------------------------------
688 // Hijack function for functions which return a scalar type or a struct (value type)
689 NESTED_ENTRY OnHijackTripThread, _TEXT, NoHandler
690 PROLOG_SAVE_REG_PAIR_INDEXED fp, ra, 0xa0
692 // Spill callee saved registers
693 PROLOG_SAVE_REG_PAIR s1, s2, 16
694 PROLOG_SAVE_REG_PAIR s3, s4, 32
695 PROLOG_SAVE_REG_PAIR s5, s6, 48
696 PROLOG_SAVE_REG_PAIR s7, s8, 64
697 PROLOG_SAVE_REG_PAIR s9, s10, 80
698 PROLOG_SAVE_REG_PAIR s11, gp, 96
699 PROLOG_SAVE_REG tp, 112
701 // save any integral return value(s)
705 // save any FP/HFA return value(s)
710 call C_FUNC(OnHijackWorker)
712 // restore callee saved registers
714 // restore any integral return value(s)
718 // restore any FP/HFA return value(s)
722 EPILOG_RESTORE_REG_PAIR s1, s2, 16
723 EPILOG_RESTORE_REG_PAIR s3, s4, 32
724 EPILOG_RESTORE_REG_PAIR s5, s6, 48
725 EPILOG_RESTORE_REG_PAIR s7, s8, 64
726 EPILOG_RESTORE_REG_PAIR s9, s10, 80
727 EPILOG_RESTORE_REG_PAIR s11, gp, 96
728 EPILOG_RESTORE_REG tp, 112
729 EPILOG_RESTORE_REG_PAIR_INDEXED fp, ra, 0xa0
731 NESTED_END OnHijackTripThread, _TEXT
733 #endif // FEATURE_HIJACK
735 // ------------------------------------------------------------------
736 // Redirection Stub for GC in fully interruptible method
737 //GenerateRedirectedHandledJITCaseStub GCThreadControl
738 // ------------------------------------------------------------------
739 //GenerateRedirectedHandledJITCaseStub DbgThreadControl
740 // ------------------------------------------------------------------
741 //GenerateRedirectedHandledJITCaseStub UserSuspend
744 // ------------------------------------------------------------------
745 // Redirection Stub for GC Stress
746 GenerateRedirectedHandledJITCaseStub GCStress
750 // ------------------------------------------------------------------
751 // This helper enables us to call into a funclet after restoring Fp register
752 NESTED_ENTRY CallEHFunclet, _TEXT, NoHandler
757 // a2 = address of s0 register in CONTEXT record// used to restore the non-volatile registers of CrawlFrame
758 // a3 = address of the location where the SP of funclet's caller (i.e. this helper) should be saved.
761 PROLOG_SAVE_REG_PAIR_INDEXED fp, ra, 128, 0
763 // Spill callee saved registers
764 PROLOG_SAVE_REG_PAIR s1, s2, 16
765 PROLOG_SAVE_REG_PAIR s3, s4, 32
766 PROLOG_SAVE_REG_PAIR s5, s6, 48
767 PROLOG_SAVE_REG_PAIR s7, s8, 64
768 PROLOG_SAVE_REG_PAIR s9, s10, 80
769 PROLOG_SAVE_REG_PAIR s11, gp, 96
770 PROLOG_SAVE_REG tp, 112
772 // Save the SP of this function
775 ld gp, (-40)(a2) // offset of tp in PCONTEXT relative to S0.
776 ld tp, (-32)(a2) // offset of tp in PCONTEXT relative to S0.
777 ld fp, 0(a2) // offset of fp in PCONTEXT relative to S0.
790 // Invoke the funclet
793 EPILOG_RESTORE_REG_PAIR s1, s2, 16
794 EPILOG_RESTORE_REG_PAIR s3, s4, 32
795 EPILOG_RESTORE_REG_PAIR s5, s6, 48
796 EPILOG_RESTORE_REG_PAIR s7, s8, 64
797 EPILOG_RESTORE_REG_PAIR s9, s10, 80
798 EPILOG_RESTORE_REG_PAIR s11, gp, 96
799 EPILOG_RESTORE_REG tp, 112
801 EPILOG_RESTORE_REG_PAIR_INDEXED fp, ra, 128
803 NESTED_END CallEHFunclet, _TEXT
805 // This helper enables us to call into a filter funclet by passing it the CallerSP to lookup the
806 // frame pointer for accessing the locals in the parent method.
807 NESTED_ENTRY CallEHFilterFunclet, _TEXT, NoHandler
808 PROLOG_SAVE_REG_PAIR_INDEXED fp, ra, 16
813 // a1 = SP of the caller of the method/funclet containing the filter
815 // a3 = address of the location where the SP of funclet's caller (i.e. this helper) should be saved.
817 // Save the SP of this function
819 // Invoke the filter funclet
822 EPILOG_RESTORE_REG_PAIR_INDEXED fp, ra, 16
824 NESTED_END CallEHFilterFunclet, _TEXT
826 #ifdef FEATURE_COMINTEROP
827 // Function used by COM interop to get floating point return value (since it's not in the same
828 // register(s) as non-floating point values).
831 // a0 : size of the FP result (4 or 8 bytes)
832 // a1 : pointer to 64-bit buffer to receive result
835 // buffer pointed to by a1 on entry contains the float or double argument as appropriate
837 LEAF_ENTRY getFPReturn, _TEXT
839 LEAF_END getFPReturn, _TEXT
841 // ------------------------------------------------------------------
842 // Function used by COM interop to set floating point return value (since it's not in the same
843 // register(s) as non-floating point values).
845 LEAF_ENTRY setFPReturn, _TEXT
847 LEAF_END setFPReturn, _TEXT
849 #endif // FEATURE_COMINTEROP
852 // JIT Static access helpers when coreclr host specifies single appdomain flag
855 // ------------------------------------------------------------------
856 // void* JIT_GetSharedNonGCStaticBase(SIZE_T moduleDomainID, DWORD dwClassDomainID)
858 LEAF_ENTRY JIT_GetSharedNonGCStaticBase_SingleAppDomain, _TEXT
859 // If class is not initialized, bail to C++ helper
860 // dext a1, a1, 0, 32
861 addi a2, a0, DomainLocalModule__m_pDataBlob
866 beq t4, zero, LOCAL_LABEL(JIT_GetSharedNonGCStaticBase_SingleAppDomain_CallHelper)
870 LOCAL_LABEL(JIT_GetSharedNonGCStaticBase_SingleAppDomain_CallHelper):
871 // Tail call JIT_GetSharedNonGCStaticBase_Helper
872 tail JIT_GetSharedNonGCStaticBase_Helper
873 LEAF_END JIT_GetSharedNonGCStaticBase_SingleAppDomain, _TEXT
875 #ifdef FEATURE_READYTORUN
877 NESTED_ENTRY DelayLoad_MethodCall_FakeProlog, _TEXT, NoHandler
878 C_FUNC(DelayLoad_MethodCall):
879 .global C_FUNC(DelayLoad_MethodCall)
880 PROLOG_WITH_TRANSITION_BLOCK
882 addi a1, t5, 0 // Indirection cell
883 addi a2, t0, 0 // sectionIndex
884 addi a3, t1, 0 // Module*
886 addi a0, sp, __PWTB_TransitionBlock // pTransitionBlock
887 call C_FUNC(ExternalMethodFixupWorker)
890 EPILOG_WITH_TRANSITION_BLOCK_TAILCALL
891 PATCH_LABEL ExternalMethodFixupPatchLabel
893 NESTED_END DelayLoad_MethodCall_FakeProlog, _TEXT
896 .macro DynamicHelper frameFlags, suffix
897 NESTED_ENTRY DelayLoad_Helper\suffix\()_FakeProlog, _TEXT, NoHandler
898 DelayLoad_Helper\suffix:
899 .global DelayLoad_Helper\suffix
901 PROLOG_WITH_TRANSITION_BLOCK
903 //DynamicHelperWorker(TransitionBlock * pTransitionBlock, TADDR * pCell,
904 // DWORD sectionIndex, Module * pModule, INT frameFlags)
905 addi a1, t5, 0 // Indirection cell
906 addi a2, t0, 0 // sectionIndex
907 addi a3, t1, 0 // Module*
908 addi a4, x0, \frameFlags
910 addi a0, sp, __PWTB_TransitionBlock // pTransitionBlock
911 call DynamicHelperWorker
913 bne a0, x0, LOCAL_LABEL(FakeProlog\suffix\()_0)
915 ld a0, __PWTB_ArgumentRegisters(sp)
916 EPILOG_WITH_TRANSITION_BLOCK_RETURN
918 LOCAL_LABEL(FakeProlog\suffix\()_0):
920 EPILOG_WITH_TRANSITION_BLOCK_TAILCALL
923 NESTED_END DelayLoad_Helper\suffix\()_FakeProlog, _TEXT
926 DynamicHelper DynamicHelperFrameFlags_Default
927 DynamicHelper DynamicHelperFrameFlags_ObjectArg, _Obj
928 DynamicHelper DynamicHelperFrameFlags_ObjectArg | DynamicHelperFrameFlags_ObjectArg2, _ObjObj
932 #ifdef PROFILING_SUPPORTED
934 // ------------------------------------------------------------------
935 LEAF_ENTRY JIT_ProfilerEnterLeaveTailcallStub, _TEXT
937 LEAF_END JIT_ProfilerEnterLeaveTailcallStub, _TEXT
939 // ------------------------------------------------------------------
940 .macro GenerateProfileHelper helper, flags
941 NESTED_ENTRY \helper\()Naked, _TEXT, NoHandler
943 // t0 = functionIDOrClientID
948 // Values of a0-a7, fa0-fa7, fp are preserved.
949 // Values of other volatile registers are not preserved.
951 // Fill in PROFILE_PLATFORM_SPECIFIC_DATA struct
952 PROLOG_SAVE_REG_PAIR_INDEXED fp, ra, SIZEOF__PROFILE_PLATFORM_SPECIFIC_DATA // Allocate space and save Fp, Pc.
953 SAVE_ARGUMENT_REGISTERS sp, PROFILE_PLATFORM_SPECIFIC_DATA__argumentRegisters
954 sd zero, PROFILE_PLATFORM_SPECIFIC_DATA__functionId(sp)
955 SAVE_FLOAT_ARGUMENT_REGISTERS sp, PROFILE_PLATFORM_SPECIFIC_DATA__floatArgumentRegisters
956 addi t6, sp, SIZEOF__PROFILE_PLATFORM_SPECIFIC_DATA // Compute probeSp - initial value of Sp on entry to the helper.
957 sd t6, PROFILE_PLATFORM_SPECIFIC_DATA__probeSp(sp)
958 sd t1, PROFILE_PLATFORM_SPECIFIC_DATA__profiledSp(sp)
959 sd zero, PROFILE_PLATFORM_SPECIFIC_DATA__hiddenArg(sp)
960 addi t6, zero, \flags
961 sd t6, PROFILE_PLATFORM_SPECIFIC_DATA__flags(sp)
967 RESTORE_ARGUMENT_REGISTERS sp, PROFILE_PLATFORM_SPECIFIC_DATA__argumentRegisters
968 RESTORE_FLOAT_ARGUMENT_REGISTERS sp, PROFILE_PLATFORM_SPECIFIC_DATA__floatArgumentRegisters
969 EPILOG_RESTORE_REG_PAIR_INDEXED fp, ra, SIZEOF__PROFILE_PLATFORM_SPECIFIC_DATA
972 NESTED_END \helper\()Naked, _TEXT
975 GenerateProfileHelper ProfileEnter, PROFILE_ENTER
976 GenerateProfileHelper ProfileLeave, PROFILE_LEAVE
977 GenerateProfileHelper ProfileTailcall, PROFILE_TAILCALL
979 #endif // PROFILING_SUPPORTED
982 #ifdef FEATURE_TIERED_COMPILATION
984 NESTED_ENTRY OnCallCountThresholdReachedStub, _TEXT, NoHandler
985 PROLOG_WITH_TRANSITION_BLOCK
987 addi a0, sp, __PWTB_TransitionBlock // TransitionBlock *
988 addi a1, t3, 0 // stub-identifying token
989 call C_FUNC(OnCallCountThresholdReached)
992 EPILOG_WITH_TRANSITION_BLOCK_TAILCALL
994 NESTED_END OnCallCountThresholdReachedStub, _TEXT
996 #endif // FEATURE_TIERED_COMPILATION
998 // ------------------------------------------------------------------
999 // size_t GetThreadStaticsVariableOffset()
1001 // Load offset of native thread local variable `t_ThreadStatics` in TCB and return it in `a0` register.
1002 LEAF_ENTRY GetThreadStaticsVariableOffset, _TEXT
1003 la.tls.ie a0, t_ThreadStatics
1005 LEAF_END GetThreadStaticsVariableOffset, _TEXT