3 * Function - JIT trampoline code for S/390.
5 * Name - Neale Ferguson (Neale.Ferguson@SoftwareAG-usa.com)
9 * Derivation - From exceptions-x86 & exceptions-ppc
10 * Paolo Molaro (lupus@ximian.com)
11 * Dietmar Maurer (dietmar@ximian.com)
13 * Copyright - 2001 Ximian, Inc.
14 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
18 /*------------------------------------------------------------------*/
20 /*------------------------------------------------------------------*/
22 #define LMFReg s390_r13
25 * Method-specific trampoline code fragment sizes
27 #define SPECIFIC_TRAMPOLINE_SIZE 96
29 /*========================= End of Defines =========================*/
31 /*------------------------------------------------------------------*/
33 /*------------------------------------------------------------------*/
39 #include <mono/metadata/abi-details.h>
40 #include <mono/metadata/appdomain.h>
41 #include <mono/metadata/gc-internals.h>
42 #include <mono/metadata/marshal.h>
43 #include <mono/metadata/profiler-private.h>
44 #include <mono/metadata/tabledefs.h>
45 #include <mono/utils/mono-hwcap.h>
46 #include <mono/arch/s390x/s390x-codegen.h>
49 #include "mini-s390x.h"
50 #include "mini-runtime.h"
51 #include "support-s390x.h"
52 #include "jit-icalls.h"
54 /*========================= End of Includes ========================*/
56 /*------------------------------------------------------------------*/
58 /*------------------------------------------------------------------*/
61 guint8 stk
[S390_MINIMAL_STACK_SIZE
]; /* Standard s390x stack */
62 guint64 saveFn
; /* Call address */
63 struct MonoLMF LMF
; /* LMF */
66 /*========================= End of Typedefs ========================*/
68 /*------------------------------------------------------------------*/
69 /* P r o t o t y p e s */
70 /*------------------------------------------------------------------*/
72 /*========================= End of Prototypes ======================*/
74 /*------------------------------------------------------------------*/
75 /* G l o b a l V a r i a b l e s */
76 /*------------------------------------------------------------------*/
79 /*====================== End of Global Variables ===================*/
81 /*------------------------------------------------------------------*/
83 /* Name - mono_arch_get_unbox_trampoline */
85 /* Function - Return a pointer to a trampoline which does the */
86 /* unboxing before calling the method. */
88 /* When value type methods are called through the */
89 /* vtable we need to unbox the 'this' argument. */
91 /* Parameters - method - Methd pointer */
92 /* addr - Pointer to native code for method */
94 /*------------------------------------------------------------------*/
97 mono_arch_get_unbox_trampoline (MonoMethod
*method
, gpointer addr
)
100 int this_pos
= s390_r2
;
101 MonoDomain
*domain
= mono_domain_get ();
104 start
= code
= mono_domain_code_reserve (domain
, 28);
106 S390_SET (code
, s390_r1
, addr
);
107 s390_aghi (code
, this_pos
, MONO_ABI_SIZEOF (MonoObject
));
108 s390_br (code
, s390_r1
);
110 g_assert ((code
- start
) <= 28);
112 mono_arch_flush_icache (start
, code
- start
);
113 MONO_PROFILER_RAISE (jit_code_buffer
, (start
, code
- start
, MONO_PROFILER_CODE_BUFFER_UNBOX_TRAMPOLINE
, method
));
115 snprintf(trampName
, sizeof(trampName
), "%s_unbox_trampoline", method
->name
);
117 mono_tramp_info_register (mono_tramp_info_create (trampName
, start
, code
- start
, NULL
, NULL
), domain
);
122 /*========================= End of Function ========================*/
124 /*------------------------------------------------------------------*/
126 /* Name - mono_arch_patch_callsite */
128 /* Function - Patch a non-virtual callsite so it calls @addr. */
130 /*------------------------------------------------------------------*/
133 mono_arch_patch_callsite (guint8
*method_start
, guint8
*orig_code
, guint8
*addr
)
136 unsigned short opcode
;
138 opcode
= *((unsigned short *) (orig_code
- 2));
139 if (opcode
== 0x0dee) {
140 /* This should be a 'iihf/iilf' sequence */
141 S390_EMIT_CALL((orig_code
- 14), addr
);
142 mono_arch_flush_icache (orig_code
- 14, 12);
144 /* This is the 'brasl' instruction */
146 displace
= ((gssize
) addr
- (gssize
) (orig_code
- 2)) / 2;
147 s390_patch_rel (orig_code
, displace
);
148 mono_arch_flush_icache (orig_code
, 4);
152 /*========================= End of Function ========================*/
154 /*------------------------------------------------------------------*/
156 /* Name - mono_arch_patch_plt_entry. */
158 /* Function - Patch a PLT entry - unused as yet. */
160 /*------------------------------------------------------------------*/
163 mono_arch_patch_plt_entry (guint8
*code
, gpointer
*got
, host_mgreg_t
*regs
, guint8
*addr
)
165 g_assert_not_reached ();
168 /*========================= End of Function ========================*/
170 /*------------------------------------------------------------------*/
172 /* Name - mono_arch_create_trampoline_code */
174 /* Function - Create the designated type of trampoline according*/
175 /* to the 'tramp_type' parameter. */
177 /*------------------------------------------------------------------*/
180 mono_arch_create_generic_trampoline (MonoTrampolineType tramp_type
, MonoTrampInfo
**info
, gboolean aot
)
182 const char *tramp_name
;
183 guint8
*buf
, *tramp
, *code
;
184 int i
, offset
, has_caller
;
186 GSList
*unwind_ops
= NULL
;
187 MonoJumpInfo
*ji
= NULL
;
191 /* Now we'll create in 'buf' the S/390 trampoline code. This
192 is the trampoline code common to all methods */
194 code
= buf
= mono_global_codeman_reserve(512);
196 if (tramp_type
== MONO_TRAMPOLINE_JUMP
)
201 /*-----------------------------------------------------------
202 STEP 0: First create a non-standard function prologue with a
203 stack size big enough to save our registers.
204 -----------------------------------------------------------*/
206 s390_stmg (buf
, s390_r6
, s390_r15
, STK_BASE
, S390_REG_SAVE_OFFSET
);
207 s390_lgr (buf
, s390_r11
, s390_r15
);
208 s390_aghi (buf
, STK_BASE
, -sizeof(trampStack_t
));
209 s390_stg (buf
, s390_r11
, 0, STK_BASE
, 0);
211 /*---------------------------------------------------------------*/
212 /* we build the MonoLMF structure on the stack - see mini-s390.h */
213 /* Keep in sync with the code in mono_arch_emit_prolog */
214 /*---------------------------------------------------------------*/
216 s390_lgr (buf
, LMFReg
, STK_BASE
);
217 s390_aghi (buf
, LMFReg
, G_STRUCT_OFFSET(trampStack_t
, LMF
));
219 /*---------------------------------------------------------------*/
220 /* Save general and floating point registers in LMF */
221 /*---------------------------------------------------------------*/
222 s390_stmg (buf
, s390_r0
, s390_r1
, LMFReg
, G_STRUCT_OFFSET(MonoLMF
, gregs
[0]));
223 s390_stmg (buf
, s390_r2
, s390_r5
, LMFReg
, G_STRUCT_OFFSET(MonoLMF
, gregs
[2]));
224 s390_mvc (buf
, 10*sizeof(gulong
), LMFReg
, G_STRUCT_OFFSET(MonoLMF
, gregs
[6]),
225 s390_r11
, S390_REG_SAVE_OFFSET
);
227 offset
= G_STRUCT_OFFSET(MonoLMF
, fregs
[0]);
228 for (i
= s390_f0
; i
<= s390_f15
; ++i
) {
229 s390_std (buf
, i
, 0, LMFReg
, offset
);
230 offset
+= sizeof(gdouble
);
233 /*----------------------------------------------------------
234 STEP 1: call 'mono_get_lmf_addr()' to get the address of our
235 LMF. We'll need to restore it after the call to
236 's390_magic_trampoline' and before the call to the native
238 ----------------------------------------------------------*/
240 S390_SET (buf
, s390_r1
, mono_get_lmf_addr
);
241 s390_basr (buf
, s390_r14
, s390_r1
);
243 /*---------------------------------------------------------------*/
244 /* Set lmf.lmf_addr = jit_tls->lmf */
245 /*---------------------------------------------------------------*/
246 s390_stg (buf
, s390_r2
, 0, LMFReg
,
247 G_STRUCT_OFFSET(MonoLMF
, lmf_addr
));
249 /*---------------------------------------------------------------*/
250 /* Get current lmf */
251 /*---------------------------------------------------------------*/
252 s390_lg (buf
, s390_r0
, 0, s390_r2
, 0);
254 /*---------------------------------------------------------------*/
255 /* Set our lmf as the current lmf */
256 /*---------------------------------------------------------------*/
257 s390_stg (buf
, LMFReg
, 0, s390_r2
, 0);
259 /*---------------------------------------------------------------*/
260 /* Have our lmf.previous_lmf point to the last lmf */
261 /*---------------------------------------------------------------*/
262 s390_stg (buf
, s390_r0
, 0, LMFReg
,
263 G_STRUCT_OFFSET(MonoLMF
, previous_lmf
));
265 /*---------------------------------------------------------------*/
266 /* save method info */
267 /*---------------------------------------------------------------*/
268 s390_lg (buf
, s390_r1
, 0, LMFReg
, G_STRUCT_OFFSET(MonoLMF
, gregs
[1]));
269 s390_stg (buf
, s390_r1
, 0, LMFReg
, G_STRUCT_OFFSET(MonoLMF
, method
));
271 /*---------------------------------------------------------------*/
272 /* save the current SP */
273 /*---------------------------------------------------------------*/
274 s390_lg (buf
, s390_r1
, 0, STK_BASE
, 0);
275 s390_stg (buf
, s390_r1
, 0, LMFReg
, G_STRUCT_OFFSET(MonoLMF
, ebp
));
277 /*---------------------------------------------------------------*/
278 /* save the current IP */
279 /*---------------------------------------------------------------*/
281 s390_lg (buf
, s390_r1
, 0, s390_r1
, S390_RET_ADDR_OFFSET
);
283 s390_lghi (buf
, s390_r1
, 0);
285 s390_stg (buf
, s390_r1
, 0, LMFReg
, G_STRUCT_OFFSET(MonoLMF
, eip
));
287 /*---------------------------------------------------------------*/
288 /* STEP 2: call the C trampoline function */
289 /*---------------------------------------------------------------*/
293 /* Arg 1: host_mgreg_t *regs */
294 s390_la (buf
, s390_r2
, 0, LMFReg
, G_STRUCT_OFFSET(MonoLMF
, gregs
[0]));
296 /* Arg 2: code (next address to the instruction that called us) */
298 s390_lg (buf
, s390_r3
, 0, s390_r11
, S390_RET_ADDR_OFFSET
);
300 s390_lghi (buf
, s390_r3
, 0);
303 /* Arg 3: Trampoline argument */
304 s390_lg (buf
, s390_r4
, 0, LMFReg
, G_STRUCT_OFFSET(MonoLMF
, gregs
[1]));
306 /* Arg 4: trampoline address. */
307 S390_SET (buf
, s390_r5
, buf
);
309 /* Calculate call address and call the C trampoline. Return value will be in r2 */
310 tramp
= (guint8
*)mono_get_trampoline_func (tramp_type
);
311 S390_SET (buf
, s390_r1
, tramp
);
312 s390_basr (buf
, s390_r14
, s390_r1
);
314 /* OK, code address is now on r2. Save it, so that we
315 can restore r2 and use it later */
316 s390_stg (buf
, s390_r2
, 0, STK_BASE
, G_STRUCT_OFFSET(trampStack_t
, saveFn
));
318 /*----------------------------------------------------------
319 STEP 3: Restore the LMF
320 ----------------------------------------------------------*/
321 restoreLMF(buf
, STK_BASE
, sizeof(trampStack_t
));
323 /* Check for thread interruption */
324 S390_SET (buf
, s390_r1
, (guint8
*)mono_thread_force_interruption_checkpoint_noraise
);
325 s390_basr (buf
, s390_r14
, s390_r1
);
326 s390_ltgr (buf
, s390_r2
, s390_r2
);
327 s390_jz (buf
, 0); CODEPTR (buf
, o
[0]);
331 * We have an exception we want to throw in the caller's frame, so pop
332 * the trampoline frame and throw from the caller.
334 S390_SET (buf
, s390_r1
, (guint
*)mono_get_rethrow_preserve_exception_addr ());
335 s390_aghi (buf
, STK_BASE
, sizeof(trampStack_t
));
336 s390_lg (buf
, s390_r1
, 0, s390_r1
, 0);
337 s390_lmg (buf
, s390_r6
, s390_r14
, STK_BASE
, S390_REG_SAVE_OFFSET
);
338 s390_br (buf
, s390_r1
);
342 s390_lg (buf
, s390_r1
, 0, STK_BASE
, G_STRUCT_OFFSET(trampStack_t
, saveFn
));
344 /*----------------------------------------------------------
345 STEP 4: call the compiled method
346 ----------------------------------------------------------*/
348 /* Restore parameter registers */
349 s390_lmg (buf
, s390_r2
, s390_r5
, LMFReg
, G_STRUCT_OFFSET(MonoLMF
, gregs
[2]));
351 /* Restore the FP registers */
352 offset
= G_STRUCT_OFFSET(MonoLMF
, fregs
[0]);
353 for (i
= s390_f0
; i
<= s390_f15
; ++i
) {
354 s390_ld (buf
, i
, 0, LMFReg
, offset
);
355 offset
+= sizeof(gdouble
);
358 /* Restore stack pointer and jump to the code -
359 * R14 contains the return address to our caller
361 s390_lgr (buf
, STK_BASE
, s390_r11
);
362 s390_lmg (buf
, s390_r6
, s390_r14
, STK_BASE
, S390_REG_SAVE_OFFSET
);
364 if (MONO_TRAMPOLINE_TYPE_MUST_RETURN(tramp_type
)) {
365 s390_lgr (buf
, s390_r2
, s390_r1
);
366 s390_br (buf
, s390_r14
);
368 s390_br (buf
, s390_r1
);
371 /* Flush instruction cache, since we've generated code */
372 mono_arch_flush_icache (code
, buf
- code
);
373 MONO_PROFILER_RAISE (jit_code_buffer
, (buf
, code
- buf
, MONO_PROFILER_CODE_BUFFER_HELPER
, NULL
));
376 tramp_name
= mono_get_generic_trampoline_name (tramp_type
);
377 *info
= mono_tramp_info_create (tramp_name
, buf
, buf
- code
, ji
, unwind_ops
);
380 g_assert ((buf
- code
) <= 512);
385 /*========================= End of Function ========================*/
387 /*------------------------------------------------------------------*/
389 /* Name - mono_arch_invalidate_method */
393 /*------------------------------------------------------------------*/
396 mono_arch_invalidate_method (MonoJitInfo
*ji
, void *func
, gpointer func_arg
)
398 /* FIXME: This is not thread safe */
399 guint8
*code
= ji
->code_start
;
401 S390_SET (code
, s390_r1
, func
);
402 S390_SET (code
, s390_r2
, func_arg
);
403 s390_br (code
, s390_r1
);
407 /*========================= End of Function ========================*/
409 /*------------------------------------------------------------------*/
411 /* Name - mono_arch_create_specific_trampoline */
413 /* Function - Creates the given kind of specific trampoline */
415 /*------------------------------------------------------------------*/
418 mono_arch_create_specific_trampoline (gpointer arg1
, MonoTrampolineType tramp_type
, MonoDomain
*domain
, guint32
*code_len
)
420 guint8
*code
, *buf
, *tramp
;
423 tramp
= mono_get_trampoline_code (tramp_type
);
425 /*----------------------------------------------------------*/
426 /* This is the method-specific part of the trampoline. Its */
427 /* purpose is to provide the generic part with the */
428 /* MonoMethod *method pointer. We'll use r1 to keep it. */
429 /*----------------------------------------------------------*/
430 code
= buf
= mono_domain_code_reserve (domain
, SPECIFIC_TRAMPOLINE_SIZE
);
432 S390_SET (buf
, s390_r1
, arg1
);
433 displace
= (tramp
- buf
) / 2;
434 s390_jg (buf
, displace
);
436 /* Flush instruction cache, since we've generated code */
437 mono_arch_flush_icache (code
, buf
- code
);
438 MONO_PROFILER_RAISE (jit_code_buffer
, (buf
, code
- buf
,
439 MONO_PROFILER_CODE_BUFFER_SPECIFIC_TRAMPOLINE
,
440 (void *) mono_get_generic_trampoline_simple_name (tramp_type
)));
443 g_assert ((buf
- code
) <= SPECIFIC_TRAMPOLINE_SIZE
);
446 *code_len
= buf
- code
;
451 /*========================= End of Function ========================*/
453 /*------------------------------------------------------------------*/
455 /* Name - mono_arch_create_rgctx_lazy_fetch_trampoline */
459 /*------------------------------------------------------------------*/
462 mono_arch_create_rgctx_lazy_fetch_trampoline (guint32 slot
, MonoTrampInfo
**info
, gboolean aot
)
466 guint8
**rgctx_null_jumps
;
474 MonoJumpInfo
*ji
= NULL
;
475 GSList
*unwind_ops
= NULL
;
477 mrgctx
= MONO_RGCTX_SLOT_IS_MRGCTX (slot
);
478 index
= MONO_RGCTX_SLOT_INDEX (slot
);
480 index
+= MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT
/ sizeof (target_mgreg_t
);
481 for (depth
= 0; ; ++depth
) {
482 int size
= mono_class_rgctx_get_array_size (depth
, mrgctx
);
484 if (index
< size
- 1)
489 tramp_size
= 48 + 16 * depth
;
495 code
= buf
= mono_global_codeman_reserve (tramp_size
);
497 unwind_ops
= mono_arch_get_cie_program ();
499 rgctx_null_jumps
= g_malloc (sizeof (guint8
*) * (depth
+ 2));
503 s390_lgr (code
, s390_r1
, s390_r2
);
505 /* load rgctx ptr from vtable */
506 s390_lg (code
, s390_r1
, 0, s390_r2
, MONO_STRUCT_OFFSET(MonoVTable
, runtime_generic_context
));
507 /* is the rgctx ptr null? */
508 s390_ltgr (code
, s390_r1
, s390_r1
);
509 /* if yes, jump to actual trampoline */
510 rgctx_null_jumps
[iPatch
++] = code
;
514 for (i
= 0; i
< depth
; ++i
) {
515 /* load ptr to next array */
516 if (mrgctx
&& i
== 0)
517 s390_lg (code
, s390_r1
, 0, s390_r1
, MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT
);
519 s390_lg (code
, s390_r1
, 0, s390_r1
, 0);
520 s390_ltgr (code
, s390_r1
, s390_r1
);
521 /* if the ptr is null then jump to actual trampoline */
522 rgctx_null_jumps
[iPatch
++] = code
;
527 s390_lg (code
, s390_r1
, 0, s390_r1
, (sizeof (target_mgreg_t
) * (index
+ 1)));
528 /* is the slot null? */
529 s390_ltgr (code
, s390_r1
, s390_r1
);
530 /* if yes, jump to actual trampoline */
531 rgctx_null_jumps
[iPatch
++] = code
;
533 /* otherwise return r1 */
534 s390_lgr (code
, s390_r2
, s390_r1
);
535 s390_br (code
, s390_r14
);
537 for (i
= 0; i
< iPatch
; i
++) {
538 displace
= ((uintptr_t) code
- (uintptr_t) rgctx_null_jumps
[i
]) / 2;
539 s390_patch_rel ((rgctx_null_jumps
[i
] + 2), displace
);
542 g_free (rgctx_null_jumps
);
544 /* move the rgctx pointer to the VTABLE register */
545 #if MONO_ARCH_VTABLE_REG != s390_r2
546 s390_lgr (code
, MONO_ARCH_VTABLE_REG
, s390_r2
);
549 tramp
= (guint8
*)mono_arch_create_specific_trampoline (GUINT_TO_POINTER (slot
),
550 MONO_TRAMPOLINE_RGCTX_LAZY_FETCH
, mono_get_root_domain (), NULL
);
552 /* jump to the actual trampoline */
553 displace
= (tramp
- code
) / 2;
554 s390_jg (code
, displace
);
556 mono_arch_flush_icache (buf
, code
- buf
);
557 MONO_PROFILER_RAISE (jit_code_buffer
, (buf
, code
- buf
, MONO_PROFILER_CODE_BUFFER_GENERICS_TRAMPOLINE
, NULL
));
559 g_assert (code
- buf
<= tramp_size
);
561 char *name
= mono_get_rgctx_fetch_trampoline_name (slot
);
562 *info
= mono_tramp_info_create (name
, buf
, code
- buf
, ji
, unwind_ops
);
568 /*========================= End of Function ========================*/
570 /*------------------------------------------------------------------*/
572 /* Name - mono_arch_get_static_rgctx_trampoline */
574 /* Function - Create a trampoline which sets RGCTX_REG to ARG */
575 /* then jumps to ADDR. */
577 /*------------------------------------------------------------------*/
580 mono_arch_get_static_rgctx_trampoline (gpointer arg
, gpointer addr
)
582 guint8
*code
, *start
;
586 MonoDomain
*domain
= mono_domain_get ();
590 start
= code
= mono_domain_code_reserve (domain
, buf_len
);
592 S390_SET (code
, MONO_ARCH_RGCTX_REG
, arg
);
593 displace
= ((uintptr_t) addr
- (uintptr_t) code
) / 2;
594 s390_jg (code
, displace
);
595 g_assert ((code
- start
) < buf_len
);
597 mono_arch_flush_icache (start
, code
- start
);
598 MONO_PROFILER_RAISE (jit_code_buffer
, (start
, code
- start
, MONO_PROFILER_CODE_BUFFER_GENERICS_TRAMPOLINE
, NULL
));
600 mono_tramp_info_register (mono_tramp_info_create (NULL
, start
, code
- start
, NULL
, NULL
), domain
);
605 /*========================= End of Function ========================*/