Implement genProfilingEnterCallback genProfilingLeaveCallback on Arm64 (dotnet/corecl...
[platform/upstream/coreclr.git] / src / vm / arm64 / asmhelpers.S
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.
4
5 #include "asmconstants.h"
6 #include "unixasmmacros.inc"
7
8 // LPVOID __stdcall GetCurrentIP(void)//
9 LEAF_ENTRY GetCurrentIP, _TEXT
10     mov x0, lr
11     ret lr
12 LEAF_END GetCurrentIP, _TEXT
13
14 // LPVOID __stdcall GetCurrentSP(void)//
15 LEAF_ENTRY GetCurrentSP, _TEXT
16     mov x0, sp
17     ret lr
18 LEAF_END GetCurrentSP, _TEXT
19
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
26     mov w1, #0
27     str w1, [x0, #MachState__isValid]
28
29     str lr, [x0, #LazyMachState_captureIp]
30
31     // str instruction does not save sp register directly so move to temp register
32     mov x1, sp
33     str x1, [x0, #LazyMachState_captureSp]
34
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)]
43
44     ret lr
45 LEAF_END LazyMachStateCaptureState, _TEXT
46
47 //
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.
53 //
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
57 // frame.
58 //
59 // So, if ptrX19_X29 points into the MachState, we need to update
60 // the register here.  That's what this macro does.
61 //
62 .macro RestoreRegMS regIndex, reg
63     // Incoming:
64     //
65     // x0 = address of MachState
66     //
67     // $regIndex: Index of the register (x19-x28). For x19, index is 19.
68     //For x20, index is 20, and so on.
69     //
70     // $reg: Register name (e.g. x19, x20, etc)
71     //
72     // Get the address of the specified captured register from machine state
73     add x2, x0, #(MachState__captureX19_X29 + ((\regIndex-19)*8))
74
75     // Get the content of specified preserved register pointer from machine state
76     ldr x3, [x0, #(MachState__ptrX19_X29 + ((\regIndex-19)*8))]
77
78     cmp x2, x3
79     bne LOCAL_LABEL(NoRestore_\reg)
80     ldr \reg, [x2]
81 LOCAL_LABEL(NoRestore_\reg):
82
83 .endmacro
84
85 // EXTERN_C int __fastcall HelperMethodFrameRestoreState(
86 // INDEBUG_COMMA(HelperMethodFrame *pFrame)
87 // MachState *pState
88 // )
89 LEAF_ENTRY HelperMethodFrameRestoreState, _TEXT
90
91     #ifdef _DEBUG
92     mov x0, x1
93     #endif
94
95     // If machine state is invalid, then simply exit
96     ldr w1, [x0, #MachState__isValid]
97     cmp w1, #0
98     beq LOCAL_LABEL(Done)
99
100     RestoreRegMS 19, X19
101     RestoreRegMS 20, X20
102     RestoreRegMS 21, X21
103     RestoreRegMS 22, X22
104     RestoreRegMS 23, X23
105     RestoreRegMS 24, X24
106     RestoreRegMS 25, X25
107     RestoreRegMS 26, X26
108     RestoreRegMS 27, X27
109     RestoreRegMS 28, X28
110     RestoreRegMS 29, X29
111 LOCAL_LABEL(Done):
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.
115     mov x0,#0
116     ret lr
117
118 LEAF_END HelperMethodFrameRestoreState, _TEXT
119
120 // ------------------------------------------------------------------
121 // The call in ndirect import precode points to this function.
122 NESTED_ENTRY NDirectImportThunk, _TEXT, NoHandler
123
124     PROLOG_SAVE_REG_PAIR_INDEXED fp, lr, -224
125     SAVE_ARGUMENT_REGISTERS sp, 16
126     SAVE_FLOAT_ARGUMENT_REGISTERS sp, 96
127
128     mov x0, x12
129     bl NDirectImportWorker
130     mov x12, x0
131
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
136
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
140
141 NESTED_END NDirectImportThunk, _TEXT
142
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 *
148     // On Exit
149     // x12 = MethodDesc*
150     // x13, x14 Trashed
151     // Inline computation done by FixupPrecode::GetMethodDesc()
152     ldrb    w13, [x12, #Offset_PrecodeChunkIndex]    //m_PrecodeChunkIndex
153     ldrb    w14, [x12, #Offset_MethodDescChunkIndex] // m_MethodDescChunkIndex
154
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
159
160     b ThePreStub
161 NESTED_END PrecodeFixupThunk, _TEXT
162 // ------------------------------------------------------------------
163
164 NESTED_ENTRY ThePreStub, _TEXT, NoHandler
165
166     PROLOG_WITH_TRANSITION_BLOCK
167
168     add x0, sp, #__PWTB_TransitionBlock // pTransitionBlock
169     mov x1, METHODDESC_REGISTER // pMethodDesc
170
171     bl  PreStubWorker
172
173     mov x9, x0
174
175     EPILOG_WITH_TRANSITION_BLOCK_TAILCALL
176     EPILOG_BRANCH_REG  x9
177
178 NESTED_END ThePreStub, _TEXT
179
180 // ------------------------------------------------------------------
181 // ThePreStubPatch()
182
183 LEAF_ENTRY ThePreStubPatch, _TEXT
184     nop
185 .globl C_FUNC(ThePreStubPatchLabel)
186 C_FUNC(ThePreStubPatchLabel):
187     ret lr
188 LEAF_END ThePreStubPatch, _TEXT
189
190
191 //-----------------------------------------------------------------------------
192 // The following Macros help in WRITE_BARRIER Implemetations
193 // WRITE_BARRIER_ENTRY
194 //
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.
197 //
198 .macro WRITE_BARRIER_ENTRY name
199     LEAF_ENTRY \name, _TEXT
200 .endmacro
201
202 // WRITE_BARRIER_END
203 //
204 // The partner to WRITE_BARRIER_ENTRY, used like NESTED_END.
205 //
206 .macro WRITE_BARRIER_END name
207     LEAF_END_MARKED \name, _TEXT
208 .endmacro
209
210 // ------------------------------------------------------------------
211 // Start of the writeable code region
212 LEAF_ENTRY JIT_PatchedCodeStart, _TEXT
213     ret  lr
214 LEAF_END JIT_PatchedCodeStart, _TEXT
215
216 // void JIT_UpdateWriteBarrierState(bool skipEphemeralCheck)
217 //
218 // Update shadow copies of the various state info required for barrier
219 //
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.
223 //
224 // Align and group state info together so it fits in a single cache line
225 // and each entry can be written atomically
226 //
227 WRITE_BARRIER_ENTRY JIT_UpdateWriteBarrierState
228     PROLOG_SAVE_REG_PAIR_INDEXED   fp, lr, -16
229
230     // x0-x7 will contain intended new state
231     // x8 will preserve skipEphemeralCheck
232     // x12 will be used for pointers
233
234     mov x8, x0
235
236     PREPARE_EXTERNAL_VAR g_card_table, x12
237     ldr  x0, [x12]
238
239 #ifdef FEATURE_MANUALLY_MANAGED_CARD_BUNDLES
240     PREPARE_EXTERNAL_VAR g_card_bundle_table, x12
241     ldr  x1, [x12]
242 #endif
243
244 #ifdef WRITE_BARRIER_CHECK
245     PREPARE_EXTERNAL_VAR g_GCShadow, x12
246     ldr  x2, [x12]
247 #endif
248
249 #ifdef FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP
250     PREPARE_EXTERNAL_VAR g_sw_ww_table, x12
251     ldr  x3, [x12]
252 #endif
253
254     PREPARE_EXTERNAL_VAR g_ephemeral_low, x12
255     ldr  x4, [x12]
256
257     PREPARE_EXTERNAL_VAR g_ephemeral_high, x12
258     ldr  x5, [x12]
259
260     cbz  x8, LOCAL_LABEL(EphemeralCheckEnabled)
261     movz x4, #0
262     movn x5, #0
263 LOCAL_LABEL(EphemeralCheckEnabled):
264
265     PREPARE_EXTERNAL_VAR g_lowest_address, x12
266     ldr  x6, [x12]
267
268     PREPARE_EXTERNAL_VAR g_highest_address, x12
269     ldr  x7, [x12]
270
271     // Update wbs state
272     adr  x12, LOCAL_LABEL(wbs_begin)
273
274     stp  x0, x1, [x12], 16
275     stp  x2, x3, [x12], 16
276     stp  x4, x5, [x12], 16
277     stp  x6, x7, [x12], 16
278
279     EPILOG_RESTORE_REG_PAIR_INDEXED fp, lr, 16
280     EPILOG_RETURN
281
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):
286     .quad 0
287 LOCAL_LABEL(wbs_card_bundle_table):
288     .quad 0
289 LOCAL_LABEL(wbs_GCShadow):
290     .quad 0
291 LOCAL_LABEL(wbs_sw_ww_table):
292     .quad 0
293 LOCAL_LABEL(wbs_ephemeral_low):
294     .quad 0
295 LOCAL_LABEL(wbs_ephemeral_high):
296     .quad 0
297 LOCAL_LABEL(wbs_lowest_address):
298     .quad 0
299 LOCAL_LABEL(wbs_highest_address):
300     .quad 0
301 WRITE_BARRIER_END JIT_UpdateWriteBarrierState
302
303
304 // ------------------------------------------------------------------
305 // End of the writeable code region
306 LEAF_ENTRY JIT_PatchedCodeLast, _TEXT
307     ret  lr
308 LEAF_END JIT_PatchedCodeLast, _TEXT
309
310 // void JIT_ByRefWriteBarrier
311 // On entry:
312 //   x13  : the source address (points to object reference to write)
313 //   x14  : the destination address (object reference written here)
314 //
315 // On exit:
316 //   x12  : trashed
317 //   x13  : incremented by 8
318 //   x14  : incremented by 8
319 //   x15  : trashed
320 //   x17  : trashed (ip1) if FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP
321 //
322 WRITE_BARRIER_ENTRY JIT_ByRefWriteBarrier
323
324     ldr  x15, [x13], 8
325     b C_FUNC(JIT_CheckedWriteBarrier)
326
327 WRITE_BARRIER_END JIT_ByRefWriteBarrier 
328
329 //-----------------------------------------------------------------------------
330 // Simple WriteBarriers
331 // void JIT_CheckedWriteBarrier(Object** dst, Object* src)
332 // On entry:
333 //   x14  : the destination address (LHS of the assignment)
334 //   x15  : the object reference (RHS of the assignment)
335 //
336 // On exit:
337 //   x12  : trashed
338 //   x14  : trashed (incremented by 8 to implement JIT_ByRefWriteBarrier contract)
339 //   x15  : trashed
340 //   x17  : trashed (ip1) if FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP
341 //
342 WRITE_BARRIER_ENTRY JIT_CheckedWriteBarrier
343     ldr  x12,  LOCAL_LABEL(wbs_lowest_address)
344     cmp  x14,  x12
345
346     ldr  x12, LOCAL_LABEL(wbs_highest_address)
347
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
353
354     blo  C_FUNC(JIT_WriteBarrier)
355
356 LOCAL_LABEL(NotInHeap):
357     str  x15, [x14], 8
358     ret  lr
359 WRITE_BARRIER_END JIT_CheckedWriteBarrier
360
361 // void JIT_WriteBarrier(Object** dst, Object* src)
362 // On entry:
363 //   x14  : the destination address (LHS of the assignment)
364 //   x15  : the object reference (RHS of the assignment)
365 //
366 // On exit:
367 //   x12  : trashed
368 //   x14  : trashed (incremented by 8 to implement JIT_ByRefWriteBarrier contract)
369 //   x15  : trashed
370 //   x17  : trashed (ip1) if FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP
371 //
372 WRITE_BARRIER_ENTRY JIT_WriteBarrier
373     stlr  x15, [x14]
374
375 #ifdef WRITE_BARRIER_CHECK
376     // Update GC Shadow Heap
377
378     // Do not perform the work if g_GCShadow is 0
379     ldr  x12, LOCAL_LABEL(wbs_GCShadow)
380     cbz  x12, LOCAL_LABEL(ShadowUpdateDisabled)
381
382     // need temporary register. Save before using.
383     str  x13, [sp, #-16]!
384
385     // Compute address of shadow heap location:
386     //   pShadow = g_GCShadow + (x14 - g_lowest_address)
387     ldr  x13, LOCAL_LABEL(wbs_lowest_address)
388     sub  x13, x14, x13
389     add  x12, x13, x12
390
391     // if (pShadow >= g_GCShadowEnd) goto end
392     PREPARE_EXTERNAL_VAR g_GCShadowEnd, x13
393     ldr  x13, [x13]
394     cmp  x12, x13
395     bhs  LOCAL_LABEL(ShadowUpdateEnd)
396
397     // *pShadow = x15
398     str  x15, [x12]
399
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.
402     dmb  ish
403
404     // if ([x14] == x15) goto end
405     ldr  x13, [x14]
406     cmp  x13, x15
407     beq LOCAL_LABEL(ShadowUpdateEnd)
408
409     // *pShadow = INVALIDGCVALUE (0xcccccccd)
410     movz x13, #0xcccd
411     movk x13, #0xcccc, LSL #16
412     str  x13, [x12]
413
414 LOCAL_LABEL(ShadowUpdateEnd):
415     ldr  x13, [sp], #16
416 LOCAL_LABEL(ShadowUpdateDisabled):
417 #endif
418
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
424     ldrb w17, [x12]
425     cbnz x17, LOCAL_LABEL(CheckCardTable)
426     mov  w17, #0xFF
427     strb w17, [x12]
428 #endif
429
430 LOCAL_LABEL(CheckCardTable):
431     // Branch to Exit if the reference is not in the Gen0 heap
432     //
433     ldr  x12, LOCAL_LABEL(wbs_ephemeral_low)
434     cbz  x12, LOCAL_LABEL(SkipEphemeralCheck)
435     cmp  x15,  x12
436
437     ldr  x12, LOCAL_LABEL(wbs_ephemeral_high)
438
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
444
445     bhi  LOCAL_LABEL(Exit)
446
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
451     ldrb w12, [x15]
452     cmp  x12, 0xFF
453     beq  LOCAL_LABEL(Exit)
454
455 LOCAL_LABEL(UpdateCardTable):
456     mov  x12, 0xFF 
457     strb w12, [x15]
458
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
463     ldrb w12, [x15]
464     cmp  x12, 0xFF
465     beq  LOCAL_LABEL(Exit)
466
467 LOCAL_LABEL(UpdateCardBundle):
468     mov  x12, 0xFF
469     strb w12, [x15]
470 #endif
471
472 LOCAL_LABEL(Exit):
473     add  x14, x14, 8
474     ret  lr  
475 WRITE_BARRIER_END JIT_WriteBarrier
476
477 #ifdef FEATURE_PREJIT
478 //------------------------------------------------
479 // VirtualMethodFixupStub
480 //
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.
486 //
487 // This is done lazily for performance reasons.
488 //
489 // On entry:
490 //
491 // x0 = "this" pointer
492 // x12 = Address of thunk
493
494 NESTED_ENTRY VirtualMethodFixupStub, _TEXT, NoHandler
495
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
500
501     // Refer to ZapImportVirtualThunk::Save
502     // for details on this.
503     //
504     // Move the thunk start address in x1
505     mov x1, x12
506
507     // Call the helper in the VM to perform the actual fixup
508     // and tell us where to tail call. x0 already contains
509     // the this pointer.
510     bl C_FUNC(VirtualMethodFixupWorker)
511     // On return, x0 contains the target to tailcall to
512     mov x12, x0
513
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
518
519     PATCH_LABEL VirtualMethodFixupPatchLabel
520
521     // and tailcall to the actual method
522     EPILOG_BRANCH_REG x12
523
524 NESTED_END VirtualMethodFixupStub, _TEXT
525 #endif // FEATURE_PREJIT
526
527 //------------------------------------------------
528 // ExternalMethodFixupStub
529 //
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.
535 //
536 // This is done lazily for performance reasons.
537 //
538 // On entry:
539 //
540 // x12 = Address of thunk 
541
542 NESTED_ENTRY ExternalMethodFixupStub, _TEXT, NoHandler
543
544     PROLOG_WITH_TRANSITION_BLOCK
545
546     add x0, sp, #__PWTB_TransitionBlock // pTransitionBlock
547     mov x1, x12 // pThunk
548     mov x2, #0  // sectionIndex
549     mov x3, #0  // pModule
550
551     bl C_FUNC(ExternalMethodFixupWorker)
552
553     // mov the address we patched to in x12 so that we can tail call to it
554     mov x12, x0
555
556     EPILOG_WITH_TRANSITION_BLOCK_TAILCALL
557     PATCH_LABEL ExternalMethodFixupPatchLabel
558     EPILOG_BRANCH_REG   x12
559
560 NESTED_END ExternalMethodFixupStub, _TEXT
561
562 // void SinglecastDelegateInvokeStub(Delegate *pThis)
563 LEAF_ENTRY SinglecastDelegateInvokeStub, _TEXT
564     cmp x0, #0
565     beq LOCAL_LABEL(LNullThis)
566
567     ldr x16, [x0, #DelegateObject___methodPtr]
568     ldr x0, [x0, #DelegateObject___target]
569
570     br x16
571
572 LOCAL_LABEL(LNullThis):
573     mov x0, #CORINFO_NullReferenceException_ASM
574     b C_FUNC(JIT_InternalThrow)
575
576 LEAF_END SinglecastDelegateInvokeStub, _TEXT
577
578 #ifdef FEATURE_COMINTEROP
579
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))
585
586 #define ComCallPreStub_FrameOffset   (ComCallPreStub_StackAlloc - (SIZEOF__ComMethodFrame - ComCallPreStub_FirstStackAdjust))
587 #define ComCallPreStub_ErrorReturnOffset0 SIZEOF__FloatArgumentRegisters
588
589 #define ComCallPreStub_FirstStackAdjust (ComCallPreStub_ErrorReturnOffset0 + (ComCallPreStub_ErrorReturnOffset0 & 8))
590
591 // ------------------------------------------------------------------
592 // COM to CLR stub called the first time a particular method is invoked.//
593 //
594 // On entry:
595 //   x12         : ComCallMethodDesc* provided by prepad thunk
596 //   plus user arguments in registers and on the stack
597 //
598 // On exit:
599 //   tail calls to real method
600 //
601 NESTED_ENTRY ComCallPreStub, _TEXT, NoHandler
602
603     // Save arguments and return address
604     PROLOG_SAVE_REG_PAIR           fp, lr, -ComCallPreStub_FirstStackAdjust!
605     PROLOG_STACK_ALLOC  ComCallPreStub_StackAlloc
606
607     SAVE_ARGUMENT_REGISTERS        sp, (16+ComCallPreStub_StackAlloc)
608
609     SAVE_FLOAT_ARGUMENT_REGISTERS  sp, 0
610
611     str x12, [sp, #(ComCallPreStub_FrameOffset + UnmanagedToManagedFrame__m_pvDatum)]
612     add x0, sp, #(ComCallPreStub_FrameOffset)
613     add x1, sp, #(ComCallPreStub_ErrorReturnOffset)
614     bl ComPreStubWorker
615
616     cbz x0, ComCallPreStub_ErrorExit
617
618     mov x12, x0
619
620     // pop the stack and restore original register state
621     RESTORE_FLOAT_ARGUMENT_REGISTERS  sp, 0
622     RESTORE_ARGUMENT_REGISTERS        sp, (16+ComCallPreStub_StackAlloc)
623
624     EPILOG_STACK_FREE ComCallPreStub_StackAlloc
625     EPILOG_RESTORE_REG_PAIR           fp, lr, ComCallPreStub_FirstStackAdjust!
626
627     // and tailcall to the actual method
628     EPILOG_BRANCH_REG x12
629
630 ComCallPreStub_ErrorExit
631     ldr x0, [sp, #(ComCallPreStub_ErrorReturnOffset)] // ErrorReturn
632
633     // pop the stack
634     EPILOG_STACK_FREE ComCallPreStub_StackAlloc
635     EPILOG_RESTORE_REG_PAIR           fp, lr, ComCallPreStub_FirstStackAdjust!
636
637     EPILOG_RETURN
638
639 NESTED_END ComCallPreStub, _TEXT
640
641 // ------------------------------------------------------------------
642 // COM to CLR stub which sets up a ComMethodFrame and calls COMToCLRWorker.
643 //
644 // On entry:
645 //   x12         : ComCallMethodDesc*  provided by prepad thunk
646 //   plus user arguments in registers and on the stack
647 //
648 // On exit:
649 //   Result in x0/d0 as per the real method being called
650 //
651     NESTED_ENTRY GenericComCallStub, _TEXT, NoHandler
652
653     // Save arguments and return address
654     PROLOG_SAVE_REG_PAIR           fp, lr, -GenericComCallStub_FirstStackAdjust!
655     PROLOG_STACK_ALLOC  GenericComCallStub_StackAlloc
656
657     SAVE_ARGUMENT_REGISTERS        sp, (16+GenericComCallStub_StackAlloc)
658     SAVE_FLOAT_ARGUMENT_REGISTERS  sp, 0
659
660     str x12, [sp, #(GenericComCallStub_FrameOffset + UnmanagedToManagedFrame__m_pvDatum)]
661     add x1, sp, #GenericComCallStub_FrameOffset
662     bl COMToCLRWorker
663
664     // pop the stack
665     EPILOG_STACK_FREE GenericComCallStub_StackAlloc
666     EPILOG_RESTORE_REG_PAIR           fp, lr, GenericComCallStub_FirstStackAdjust!
667
668     EPILOG_RETURN
669
670     NESTED_END GenericComCallStub, _TEXT
671
672 // ------------------------------------------------------------------
673 // COM to CLR stub called from COMToCLRWorker that actually dispatches to the real managed method.
674 //
675 // On entry:
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
681 //
682 // On exit:
683 //   Result in x0/d0 as per the real method being called
684 //
685     NESTED_ENTRY COMToCLRDispatchHelper, _TEXT,CallDescrWorkerUnwindFrameChainHandler
686
687     PROLOG_SAVE_REG_PAIR           fp, lr, -16!
688
689     cbz x0, COMToCLRDispatchHelper_RegSetup
690
691     add x9, x1, #SIZEOF__ComMethodFrame
692     add x9, x9, x0, LSL #3
693 COMToCLRDispatchHelper_StackLoop
694     ldr x8, [x9, #-8]!
695     str x8, [sp, #-8]!
696     sub x0, x0, #1
697     cbnz x0, COMToCLRDispatchHelper_StackLoop
698
699 COMToCLRDispatchHelper_RegSetup
700
701     RESTORE_FLOAT_ARGUMENT_REGISTERS x1, -1 * GenericComCallStub_FrameOffset
702
703     mov lr, x2
704     mov x12, x3
705
706     mov x0, x4
707
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)]
712
713     ldr x1, [x1, #(SIZEOF__ComMethodFrame - SIZEOF__ArgumentRegisters + 8)]
714
715     blr lr
716
717     EPILOG_STACK_RESTORE
718     EPILOG_RESTORE_REG_PAIR           fp, lr, 16!
719     EPILOG_RETURN
720
721     NESTED_END COMToCLRDispatchHelper, _TEXT
722
723 #endif // FEATURE_COMINTEROP
724 //
725 // x12 = UMEntryThunk*
726 //
727 NESTED_ENTRY TheUMEntryPrestub, _TEXT, UnhandledExceptionHandlerUnix
728
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
733
734     mov x0, x12
735     bl C_FUNC(TheUMEntryPrestubWorker)
736
737     // save real target address in x12.
738     mov x12, x0
739
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
744
745     // and tailcall to the actual method
746     EPILOG_BRANCH_REG x12
747
748 NESTED_END TheUMEntryPrestub, _TEXT
749
750 //
751 // x12 = UMEntryThunk*
752 //
753 NESTED_ENTRY UMThunkStub, _TEXT, UnhandledExceptionHandlerUnix
754
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
759
760     SAVE_ARGUMENT_REGISTERS sp, 16
761
762 #define UMThunkStub_HiddenArg 88 // offset of saved UMEntryThunk *
763 #define UMThunkStub_StackArgs 112 // offset of original stack args (total size of UMThunkStub frame)
764
765     // save UMEntryThunk*
766     str x12, [sp, #UMThunkStub_HiddenArg]
767
768     // assuming GetThread does not clobber FP Args
769     bl C_FUNC(GetThread)
770     cbz x0, LOCAL_LABEL(UMThunkStub_DoThreadSetup)
771
772 LOCAL_LABEL(UMThunkStub_HaveThread):
773     mov x19, x0  // x19 = Thread *
774
775     mov x9, 1
776     // m_fPreemptiveGCDisabled is 4 byte field so using 32-bit variant
777     str w9, [x19, #Thread__m_fPreemptiveGCDisabled]
778
779     PREPARE_EXTERNAL_VAR g_TrapReturningThreads, x2
780     ldr x3, [x2]
781     // assuming x0 contains Thread* before jumping to UMThunkStub_DoTrapReturningThreads
782     cbnz x3, LOCAL_LABEL(UMThunkStub_DoTrapReturningThreads)
783
784 LOCAL_LABEL(UMThunkStub_InCooperativeMode):
785     ldr x12, [fp, #UMThunkStub_HiddenArg] // x12 = UMEntryThunk*
786     ldr x3, [x12, #UMEntryThunk__m_pUMThunkMarshInfo] // x3 = m_pUMThunkMarshInfo
787
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)
791
792     // extend to 64-bits
793     uxtw x2, w2
794
795     // Source pointer
796     add x0, fp, #UMThunkStub_StackArgs
797
798     // move source pointer to end of Stack Args
799     add x0, x0, x2 
800
801     // Count of stack slot pairs to copy (divide by 16)
802     lsr x1, x2, #4
803
804     // Is there an extra stack slot (can happen when stack arg bytes not multiple of 16)
805     and x2, x2, #8
806
807     // If yes then start source pointer from 16 byte aligned stack slot
808     add x0, x0, x2  
809
810     // increment stack slot pair count by 1 if x2 is not zero
811     add x1, x1, x2, LSR #3 
812
813 LOCAL_LABEL(UMThunkStub_StackLoop):
814     ldp x4, x5, [x0, #-16]! // pre-Index
815     stp x4, x5, [sp, #-16]! // pre-Index
816     subs x1, x1, #1
817     bne LOCAL_LABEL(UMThunkStub_StackLoop)
818
819 LOCAL_LABEL(UMThunkStub_RegArgumentsSetup):
820     ldr x16, [x3, #UMThunkMarshInfo__m_pILStub]
821
822     RESTORE_ARGUMENT_REGISTERS fp, 16
823
824     blr x16
825
826 LOCAL_LABEL(UMThunkStub_PostCall):
827     mov x4, 0
828     // m_fPreemptiveGCDisabled is 4 byte field so using 32-bit variant
829     str w4, [x19, #Thread__m_fPreemptiveGCDisabled]
830
831     EPILOG_STACK_RESTORE
832     EPILOG_RESTORE_REG x19, 96
833     EPILOG_RESTORE_REG_PAIR_INDEXED   fp, lr, 112
834
835     EPILOG_RETURN
836
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)
844
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)
855
856 NESTED_END UMThunkStub, _TEXT
857
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
869
870     // save any integral return value(s)
871     stp x0, x1, [sp, #96]
872
873     // save any FP/HFA return value(s)
874     stp q0, q1, [sp, #112]
875     stp q2, q3, [sp, #144]
876
877     mov x0, sp
878     bl OnHijackWorker
879
880     // restore any integral return value(s)
881     ldp x0, x1, [sp, #96]
882
883     // restore any FP/HFA return value(s)
884     ldp q0, q1, [sp, #112]
885     ldp q2, q3, [sp, #144]
886
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
893     EPILOG_RETURN
894 NESTED_END OnHijackTripThread, _TEXT
895
896 #endif // FEATURE_HIJACK
897
898 // ------------------------------------------------------------------
899 // Redirection Stub for GC in fully interruptible method
900 //GenerateRedirectedHandledJITCaseStub GCThreadControl
901 // ------------------------------------------------------------------
902 //GenerateRedirectedHandledJITCaseStub DbgThreadControl
903 // ------------------------------------------------------------------
904 //GenerateRedirectedHandledJITCaseStub UserSuspend
905
906 #ifdef _DEBUG
907 // ------------------------------------------------------------------
908 // Redirection Stub for GC Stress
909 GenerateRedirectedHandledJITCaseStub GCStress
910 #endif
911
912
913 // ------------------------------------------------------------------
914
915 // This helper enables us to call into a funclet after restoring Fp register
916 NESTED_ENTRY CallEHFunclet, _TEXT, NoHandler
917     // On entry:
918     //
919     // X0 = throwable
920     // X1 = PC to invoke
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.
923     //
924
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
931
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
938
939     // Save the SP of this function
940     mov x4, sp
941     str x4, [x3]
942
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
949
950     // Invoke the funclet
951     blr x1
952     nop
953
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
960     EPILOG_RETURN
961
962 NESTED_END CallEHFunclet, _TEXT
963
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
967
968     PROLOG_SAVE_REG_PAIR_INDEXED   fp, lr, -16
969
970     // On entry:
971     //
972     // X0 = throwable
973     // X1 = SP of the caller of the method/funclet containing the filter
974     // X2 = PC to invoke
975     // X3 = address of the location where the SP of funclet's caller (i.e. this helper) should be saved.
976     //
977     // Save the SP of this function
978     str fp, [x3]
979     // Invoke the filter funclet
980     blr x2
981
982     EPILOG_RESTORE_REG_PAIR_INDEXED   fp, lr,   16
983     EPILOG_RETURN
984
985 NESTED_END CallEHFilterFunclet, _TEXT
986
987 #define FaultingExceptionFrame_StackAlloc (SIZEOF__GSCookie + SIZEOF__FaultingExceptionFrame)
988 #define FaultingExceptionFrame_FrameOffset SIZEOF__GSCookie
989
990 .macro GenerateRedirectedStubWithFrame stub, target
991
992     // 
993     // This is the primary function to which execution will be redirected to.
994     //
995     NESTED_ENTRY \stub, _TEXT, NoHandler
996
997         //
998         // IN: lr: original IP before redirect
999         //
1000
1001         PROLOG_SAVE_REG_PAIR_INDEXED fp, lr, -16
1002         PROLOG_STACK_ALLOC  FaultingExceptionFrame_StackAlloc
1003
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.
1007         //
1008         // Runtime check for 16-byte alignment. 
1009         mov x0, sp
1010         and x0, x0, #15
1011         sub sp, sp, x0
1012
1013         // Save pointer to FEF for GetFrameFromRedirectedStubStackFrame
1014         add x19, sp, #FaultingExceptionFrame_FrameOffset
1015
1016         // Prepare to initialize to NULL
1017         mov x1,#0
1018         str x1, [x19]// Initialize vtbl (it is not strictly necessary)
1019         str x1, [x19, #FaultingExceptionFrame__m_fFilterExecuted]// Initialize BOOL for personality routine
1020
1021         mov x0, x19   // move the ptr to FEF in X0
1022
1023         bl C_FUNC(\target)
1024
1025         // Target should not return.
1026         EMIT_BREAKPOINT
1027
1028     NESTED_END \stub, _TEXT
1029
1030 .endmacro
1031
1032
1033 // ------------------------------------------------------------------
1034 // ResolveWorkerChainLookupAsmStub
1035 //
1036 // This method will perform a quick chained lookup of the entry if the
1037 //  initial cache lookup fails.
1038 //
1039 // On Entry:
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
1047 //
1048 // Loaded from x0
1049 //   x13       contains our type     the MethodTable  (from object ref in x0)
1050 //
1051 // On Exit:
1052 //   x0, [x1-x7] arguments for the interface implementation target
1053 //
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
1058 //
1059
1060 #define BACKPATCH_FLAG      1
1061 #define PROMOTE_CHAIN_FLAG  2
1062
1063 NESTED_ENTRY ResolveWorkerChainLookupAsmStub, _TEXT, NoHandler
1064
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
1067
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
1071     cmp     x9, #0
1072     beq     LOCAL_LABEL(Fail)
1073
1074     ldp     x16, x17, [x9]
1075     cmp     x16, x13          // compare our MT with the one in the ResolveCacheElem
1076     bne     LOCAL_LABEL(MainLoop)
1077
1078     cmp     x17, x12          // compare our DispatchToken with one in the ResolveCacheElem
1079     bne     LOCAL_LABEL(MainLoop)
1080
1081 LOCAL_LABEL(Success):
1082     PREPARE_EXTERNAL_VAR g_dispatch_cache_chain_success_counter, x13
1083     ldr     x16, [x13]
1084     subs    x16, x16, #1
1085     str     x16, [x13]
1086     blt     LOCAL_LABEL(Promote)
1087
1088     ldr     x16, [x9, #ResolveCacheElem__target]    // get the ImplTarget
1089     br      x16               // branch to interface implemenation target
1090
1091 LOCAL_LABEL(Promote):
1092                               // Move this entry to head postion of the chain
1093     mov     x16, #256
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
1097
1098 LOCAL_LABEL(Fail):
1099     b       ResolveWorkerAsmStub // call the ResolveWorkerAsmStub method to transition into the VM
1100
1101 NESTED_END ResolveWorkerChainLookupAsmStub, _TEXT
1102
1103 // ------------------------------------------------------------------
1104 // void ResolveWorkerAsmStub(args in regs x0-x7 & stack and possibly retbuf arg in x8, x11:IndirectionCellAndFlags, x12:DispatchToken)
1105 //
1106 // The stub dispatch thunk which transfers control to VSD_ResolveWorker.
1107 NESTED_ENTRY ResolveWorkerAsmStub, _TEXT, NoHandler
1108
1109     PROLOG_WITH_TRANSITION_BLOCK
1110
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
1116     mov x9, x0
1117
1118     EPILOG_WITH_TRANSITION_BLOCK_TAILCALL
1119
1120     EPILOG_BRANCH_REG  x9
1121
1122 NESTED_END ResolveWorkerAsmStub, _TEXT
1123
1124 #ifdef FEATURE_READYTORUN
1125
1126 NESTED_ENTRY DelayLoad_MethodCall_FakeProlog, _TEXT, NoHandler
1127 DelayLoad_MethodCall:
1128     .global DelayLoad_MethodCall
1129     PROLOG_WITH_TRANSITION_BLOCK
1130
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
1136     mov x12, x0
1137
1138     EPILOG_WITH_TRANSITION_BLOCK_TAILCALL
1139     // Share patch label
1140     b ExternalMethodFixupPatchLabel
1141
1142 NESTED_END DelayLoad_MethodCall_FakeProlog, _TEXT
1143
1144
1145 .macro DynamicHelper frameFlags, suffix
1146 NESTED_ENTRY DelayLoad_Helper\suffix\()_FakeProlog, _TEXT, NoHandler
1147 DelayLoad_Helper\suffix:
1148     .global DelayLoad_Helper\suffix
1149
1150     PROLOG_WITH_TRANSITION_BLOCK
1151
1152     add x0, sp, #__PWTB_TransitionBlock // pTransitionBlock
1153     mov x1, x11 // Indirection cell
1154     mov x2, x9 // sectionIndex
1155     mov x3, x10 // Module*
1156     mov x4, \frameFlags
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):
1162     mov x12, x0
1163     EPILOG_WITH_TRANSITION_BLOCK_TAILCALL
1164     EPILOG_BRANCH_REG  x12
1165
1166 NESTED_END DelayLoad_Helper\suffix\()_FakeProlog, _TEXT
1167 .endm
1168
1169 DynamicHelper DynamicHelperFrameFlags_Default
1170 DynamicHelper DynamicHelperFrameFlags_ObjectArg, _Obj
1171 DynamicHelper DynamicHelperFrameFlags_ObjectArg | DynamicHelperFrameFlags_ObjectArg2, _ObjObj
1172 #endif
1173
1174 #ifdef FEATURE_PREJIT
1175 // ------------------------------------------------------------------
1176 // void StubDispatchFixupStub(args in regs x0-x7 & stack and possibly retbuff arg in x8, x11:IndirectionCellAndFlags)
1177 //
1178 // The stub dispatch thunk which transfers control to StubDispatchFixupWorker.
1179 NESTED_ENTRY StubDispatchFixupStub, _TEXT, NoHandler
1180
1181     PROLOG_WITH_TRANSITION_BLOCK
1182
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)
1188     mov x12, x0
1189
1190     EPILOG_WITH_TRANSITION_BLOCK_TAILCALL
1191     PATCH_LABEL StubDispatchFixupPatchLabel
1192     EPILOG_BRANCH_REG  x12
1193
1194 NESTED_END StubDispatchFixupStub, _TEXT
1195 #endif
1196
1197 #ifdef FEATURE_COMINTEROP
1198
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).
1201 //
1202 // On entry//
1203 //   x0          : size of the FP result (4 or 8 bytes)
1204 //   x1          : pointer to 64-bit buffer to receive result
1205 //
1206 // On exit:
1207 //   buffer pointed to by x1 on entry contains the float or double argument as appropriate
1208 //
1209 LEAF_ENTRY getFPReturn, _TEXT
1210     str d0, [x1]
1211 LEAF_END getFPReturn, _TEXT
1212
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).
1216 //
1217 // On entry:
1218 //   x0          : size of the FP result (4 or 8 bytes)
1219 //   x1          : 32-bit or 64-bit FP result
1220 //
1221 // On exit:
1222 //   s0          : float result if x0 == 4
1223 //   d0          : double result if x0 == 8
1224 //
1225 LEAF_ENTRY setFPReturn, _TEXT
1226     fmov d0, x1
1227 LEAF_END setFPReturn, _TEXT
1228 #endif
1229
1230 //
1231 // JIT Static access helpers when coreclr host specifies single appdomain flag 
1232 //
1233
1234 // ------------------------------------------------------------------
1235 // void* JIT_GetSharedNonGCStaticBase(SIZE_T moduleDomainID, DWORD dwClassDomainID)
1236
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]
1241     tst w2, #1
1242     beq LOCAL_LABEL(JIT_GetSharedNonGCStaticBase_SingleAppDomain_CallHelper)
1243
1244     ret lr
1245
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
1250
1251
1252 // ------------------------------------------------------------------
1253 // void* JIT_GetSharedNonGCStaticBaseNoCtor(SIZE_T moduleDomainID, DWORD dwClassDomainID)
1254
1255 LEAF_ENTRY JIT_GetSharedNonGCStaticBaseNoCtor_SingleAppDomain, _TEXT
1256     ret lr
1257 LEAF_END JIT_GetSharedNonGCStaticBaseNoCtor_SingleAppDomain, _TEXT
1258
1259
1260 // ------------------------------------------------------------------
1261 // void* JIT_GetSharedGCStaticBase(SIZE_T moduleDomainID, DWORD dwClassDomainID)
1262
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]
1267     tst w2, #1
1268     beq LOCAL_LABEL(JIT_GetSharedGCStaticBase_SingleAppDomain_CallHelper)
1269
1270     ldr x0, [x0, #DomainLocalModule__m_pGCStatics]
1271     ret lr
1272
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
1277
1278
1279 // ------------------------------------------------------------------
1280 // void* JIT_GetSharedGCStaticBaseNoCtor(SIZE_T moduleDomainID, DWORD dwClassDomainID)
1281
1282 LEAF_ENTRY JIT_GetSharedGCStaticBaseNoCtor_SingleAppDomain, _TEXT
1283     ldr x0, [x0, #DomainLocalModule__m_pGCStatics]
1284     ret lr
1285 LEAF_END JIT_GetSharedGCStaticBaseNoCtor_SingleAppDomain, _TEXT
1286
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
1291
1292     // check for null array
1293     cbz     x0, LOCAL_LABEL(ThrowNullReferenceException)
1294
1295     // idx bounds check
1296     ldr     x3,[x0,#ArrayBase__m_NumComponents]
1297     cmp     x3, x1
1298     bls     LOCAL_LABEL(ThrowIndexOutOfRangeException)
1299
1300     // fast path to null assignment (doesn't need any write-barriers)
1301     cbz     x2, LOCAL_LABEL(AssigningNull)
1302
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()
1307     cmp     x3, x12
1308     beq     C_FUNC(JIT_Stelem_DoWrite)
1309
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)
1315
1316     // array type and val type do not exactly match. Raise frame and do detailed match
1317     b       C_FUNC(JIT_Stelem_Ref_NotExactMatch)
1318
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
1323     ret
1324
1325 LOCAL_LABEL(ThrowNullReferenceException):
1326     // Tail call JIT_InternalThrow(NullReferenceException)
1327     ldr     x0, =CORINFO_NullReferenceException_ASM
1328     b       C_FUNC(JIT_InternalThrow)
1329
1330 LOCAL_LABEL(ThrowIndexOutOfRangeException):
1331     // Tail call JIT_InternalThrow(NullReferenceException)
1332     ldr     x0, =CORINFO_IndexOutOfRangeException_ASM
1333     b       C_FUNC(JIT_InternalThrow)
1334
1335 LEAF_END JIT_Stelem_Ref, _TEXT
1336
1337 // ------------------------------------------------------------------
1338 // __declspec(naked) void F_CALL_CONV JIT_Stelem_Ref_NotExactMatch(PtrArray* array,
1339 //                                                       unsigned idx, Object* val)
1340 //   x12 = array->GetArrayElementTypeHandle()
1341 //
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
1347
1348     // allow in case val can be casted to array element type
1349     // call ObjIsInstanceOfNoGC(val, array->GetArrayElementTypeHandle())
1350     mov     x1, x12 // array->GetArrayElementTypeHandle()
1351     mov     x0, x2
1352     bl      C_FUNC(ObjIsInstanceOfNoGC)
1353     cmp     x0, TypeHandle_CanCast
1354     beq     LOCAL_LABEL(DoWrite)             // ObjIsInstance returned TypeHandle::CanCast
1355
1356     // check via raising frame
1357 LOCAL_LABEL(NeedFrame):
1358     add     x1, sp, #16             // x1 = &array
1359     add     x0, sp, #32             // x0 = &val
1360
1361     bl      C_FUNC(ArrayStoreCheck) // ArrayStoreCheck(&val, &array)
1362
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
1369
1370 // ------------------------------------------------------------------
1371 // __declspec(naked) void F_CALL_CONV JIT_Stelem_DoWrite(PtrArray* array, unsigned idx, Object* val)
1372 LEAF_ENTRY  JIT_Stelem_DoWrite, _TEXT
1373
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
1378
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
1383
1384 #ifdef PROFILING_SUPPORTED
1385
1386 // ------------------------------------------------------------------
1387 LEAF_ENTRY JIT_ProfilerEnterLeaveTailcallStub, _TEXT
1388     ret     lr
1389 LEAF_END JIT_ProfilerEnterLeaveTailcallStub, _TEXT
1390
1391 // ------------------------------------------------------------------
1392 #define PROFILE_ENTER    1
1393 #define PROFILE_LEAVE    2
1394 #define PROFILE_TAILCALL 4
1395 #define SIZEOF__PROFILE_PLATFORM_SPECIFIC_DATA 256
1396
1397 // ------------------------------------------------------------------
1398 .macro GenerateProfileHelper helper, flags
1399 NESTED_ENTRY \helper\()Naked, _TEXT, NoHandler
1400     // On entry:
1401     //   x10 = functionIDOrClientID
1402     //   x11 = profiledSp
1403     //   x12 = throwable
1404     //
1405     // On exit:
1406     //   Values of x0-x8, q0-q7, fp are preserved.
1407     //   Values of other volatile registers are not preserved.
1408
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.
1416     mov     w12, \flags
1417     stp     w12, wzr, [sp, 248]             // Save flags and clear unused field.
1418
1419     mov     x0, x10
1420     mov     x1, sp
1421     bl      \helper
1422
1423     RESTORE_ARGUMENT_REGISTERS sp, 16       // Restore x8 and argument registers.
1424     RESTORE_FLOAT_ARGUMENT_REGISTERS sp, 96 // Restore floating-point/SIMD registers.
1425
1426     EPILOG_RESTORE_REG_PAIR_INDEXED fp, lr, SIZEOF__PROFILE_PLATFORM_SPECIFIC_DATA
1427     EPILOG_RETURN
1428
1429 NESTED_END \helper\()Naked, _TEXT
1430 .endmacro
1431
1432 GenerateProfileHelper ProfileEnter, PROFILE_ENTER
1433 GenerateProfileHelper ProfileLeave, PROFILE_LEAVE
1434 GenerateProfileHelper ProfileTailcall, PROFILE_TAILCALL
1435
1436 #endif