1 /*------------------------------------------------------------------*/
3 /* Name - tramp-s390x.c */
5 /* Function - JIT trampoline code for S/390. */
7 /* Name - Neale Ferguson (Neale.Ferguson@SoftwareAG-usa.com) */
9 /* Date - January, 2004 */
11 /* Derivation - From exceptions-x86 & exceptions-ppc */
12 /* Paolo Molaro (lupus@ximian.com) */
13 /* Dietmar Maurer (dietmar@ximian.com) */
15 /* Copyright - 2001 Ximian, Inc. */
17 /*------------------------------------------------------------------*/
19 /*------------------------------------------------------------------*/
21 /*------------------------------------------------------------------*/
23 #define GR_SAVE_SIZE 4*sizeof(long)
24 #define FP_SAVE_SIZE 16*sizeof(double)
25 #define METHOD_SAVE_OFFSET S390_MINIMAL_STACK_SIZE
26 #define CREATE_GR_OFFSET METHOD_SAVE_OFFSET+8
27 #define CREATE_FP_OFFSET CREATE_GR_OFFSET+GR_SAVE_SIZE
28 #define CREATE_LMF_OFFSET CREATE_FP_OFFSET+FP_SAVE_SIZE
29 #define CREATE_STACK_SIZE (CREATE_LMF_OFFSET+2*sizeof(long)+sizeof(MonoLMF))
30 #define GENERIC_REG_OFFSET CREATE_STACK_SIZE + \
31 S390_REG_SAVE_OFFSET + \
34 /*------------------------------------------------------------------*/
35 /* Method-specific trampoline code fragment sizes */
36 /*------------------------------------------------------------------*/
37 #define SPECIFIC_TRAMPOLINE_SIZE 96
39 /*========================= End of Defines =========================*/
41 /*------------------------------------------------------------------*/
43 /*------------------------------------------------------------------*/
49 #include <mono/metadata/appdomain.h>
50 #include <mono/metadata/marshal.h>
51 #include <mono/metadata/tabledefs.h>
52 #include <mono/arch/s390x/s390x-codegen.h>
55 #include "mini-s390x.h"
56 #include "support-s390x.h"
58 /*========================= End of Includes ========================*/
60 /*------------------------------------------------------------------*/
62 /*------------------------------------------------------------------*/
64 /*========================= End of Typedefs ========================*/
66 /*------------------------------------------------------------------*/
67 /* P r o t o t y p e s */
68 /*------------------------------------------------------------------*/
70 /*========================= End of Prototypes ======================*/
72 /*------------------------------------------------------------------*/
73 /* G l o b a l V a r i a b l e s */
74 /*------------------------------------------------------------------*/
77 /*====================== End of Global Variables ===================*/
79 /*------------------------------------------------------------------*/
81 /* Name - mono_arch_get_unbox_trampoline */
83 /* Function - Return a pointer to a trampoline which does the */
84 /* unboxing before calling the method. */
86 /* When value type methods are called through the */
87 /* vtable we need to unbox the 'this' argument. */
89 /* Parameters - method - Methd pointer */
90 /* addr - Pointer to native code for method */
92 /*------------------------------------------------------------------*/
95 mono_arch_get_unbox_trampoline (MonoMethod *method, gpointer addr)
98 int this_pos = s390_r2;
99 MonoDomain *domain = mono_domain_get ();
101 start = code = mono_domain_code_reserve (domain, 28);
103 S390_SET (code, s390_r1, addr);
104 s390_aghi (code, this_pos, sizeof(MonoObject));
105 s390_br (code, s390_r1);
107 g_assert ((code - start) <= 28);
109 mono_arch_flush_icache (start, code - start);
114 /*========================= End of Function ========================*/
116 /*------------------------------------------------------------------*/
118 /* Name - mono_arch_patch_callsite */
120 /* Function - Patch a non-virtual callsite so it calls @addr. */
122 /*------------------------------------------------------------------*/
125 mono_arch_patch_callsite (guint8 *method_start, guint8 *orig_code, guint8 *addr)
128 unsigned short opcode;
130 opcode = *((unsigned short *) (orig_code - 2));
131 if (opcode == 0x0dee) {
132 /* This should be a 'iihf/iilf' sequence */
133 S390_EMIT_CALL((orig_code - 14), addr);
134 mono_arch_flush_icache (orig_code - 14, 12);
136 fprintf(stderr, "%p %02x %02x %02x %02x\n",
137 &orig_code[-14], orig_code[-12], orig_code[-11], orig_code[-6], orig_code[-5]);
139 /* This is the 'brasl' instruction */
141 displace = ((gssize) addr - (gssize) (orig_code - 2)) / 2;
142 s390_patch_rel (orig_code, displace);
143 mono_arch_flush_icache (orig_code, 4);
147 /*========================= End of Function ========================*/
149 /*------------------------------------------------------------------*/
151 /* Name - mono_arch_patch_plt_entry. */
153 /* Function - Patch a PLT entry - unused as yet. */
155 /*------------------------------------------------------------------*/
158 mono_arch_patch_plt_entry (guint8 *code, gpointer *got, mgreg_t *regs, guint8 *addr)
160 g_assert_not_reached ();
163 /*========================= End of Function ========================*/
165 /*------------------------------------------------------------------*/
167 /* Name - mono_arch_nullify_class_init_trampoline */
169 /* Function - Nullify a call which calls a class init trampoline*/
171 /*------------------------------------------------------------------*/
174 mono_arch_nullify_class_init_trampoline (guint8 *code, mgreg_t *regs)
176 char patch[2] = {0x07, 0x00};
180 memcpy(code, patch, sizeof(patch));
183 /*========================= End of Function ========================*/
185 /*------------------------------------------------------------------*/
187 /* Name - mono_arch_get_nullified_class_init */
189 /* Function - Nullify a PLT entry call. */
191 /*------------------------------------------------------------------*/
194 mono_arch_get_nullified_class_init_trampoline (MonoTrampInfo **info)
198 code = buf = mono_global_codeman_reserve (16);
200 s390_br (code, s390_r14);
203 *info = mono_tramp_info_create ("nullified_class_init_trampoline",
204 buf, code - buf, NULL, NULL);
209 /*========================= End of Function ========================*/
211 /*------------------------------------------------------------------*/
213 /* Name - mono_arch_create_trampoline_code */
215 /* Function - Create the designated type of trampoline according*/
216 /* to the 'tramp_type' parameter. */
218 /*------------------------------------------------------------------*/
221 mono_arch_create_generic_trampoline (MonoTrampolineType tramp_type, MonoTrampInfo **info, gboolean aot)
224 guint8 *buf, *tramp, *code;
225 int i, offset, lmfOffset, has_caller;
226 GSList *unwind_ops = NULL;
227 MonoJumpInfo *ji = NULL;
231 /* Now we'll create in 'buf' the S/390 trampoline code. This
232 is the trampoline code common to all methods */
234 code = buf = mono_global_codeman_reserve(512);
236 if ((tramp_type == MONO_TRAMPOLINE_JUMP) ||
237 (tramp_type == MONO_TRAMPOLINE_HANDLER_BLOCK_GUARD))
242 /*-----------------------------------------------------------
243 STEP 0: First create a non-standard function prologue with a
244 stack size big enough to save our registers.
245 -----------------------------------------------------------*/
247 s390_stmg (buf, s390_r6, s390_r15, STK_BASE, S390_REG_SAVE_OFFSET);
248 s390_lgr (buf, s390_r11, s390_r15);
249 s390_aghi (buf, STK_BASE, -CREATE_STACK_SIZE);
250 s390_stg (buf, s390_r11, 0, STK_BASE, 0);
251 s390_stg (buf, s390_r1, 0, STK_BASE, METHOD_SAVE_OFFSET);
252 s390_stmg (buf, s390_r2, s390_r5, STK_BASE, CREATE_GR_OFFSET);
254 /* Save the FP registers */
255 offset = CREATE_FP_OFFSET;
256 for (i = s390_f0; i <= s390_f15; ++i) {
257 s390_std (buf, i, 0, STK_BASE, offset);
261 /*----------------------------------------------------------
262 STEP 1: call 'mono_get_lmf_addr()' to get the address of our
263 LMF. We'll need to restore it after the call to
264 's390_magic_trampoline' and before the call to the native
266 ----------------------------------------------------------*/
268 S390_SET (buf, s390_r1, mono_get_lmf_addr);
269 s390_basr (buf, s390_r14, s390_r1);
271 /*---------------------------------------------------------------*/
272 /* we build the MonoLMF structure on the stack - see mini-s390.h */
273 /* Keep in sync with the code in mono_arch_emit_prolog */
274 /*---------------------------------------------------------------*/
275 lmfOffset = CREATE_STACK_SIZE - sizeof(MonoLMF);
277 s390_lgr (buf, s390_r13, STK_BASE);
278 s390_aghi (buf, s390_r13, lmfOffset);
280 /*---------------------------------------------------------------*/
281 /* Set lmf.lmf_addr = jit_tls->lmf */
282 /*---------------------------------------------------------------*/
283 s390_stg (buf, s390_r2, 0, s390_r13,
284 G_STRUCT_OFFSET(MonoLMF, lmf_addr));
286 /*---------------------------------------------------------------*/
287 /* Get current lmf */
288 /*---------------------------------------------------------------*/
289 s390_lg (buf, s390_r0, 0, s390_r2, 0);
291 /*---------------------------------------------------------------*/
292 /* Set our lmf as the current lmf */
293 /*---------------------------------------------------------------*/
294 s390_stg (buf, s390_r13, 0, s390_r2, 0);
296 /*---------------------------------------------------------------*/
297 /* Have our lmf.previous_lmf point to the last lmf */
298 /*---------------------------------------------------------------*/
299 s390_stg (buf, s390_r0, 0, s390_r13,
300 G_STRUCT_OFFSET(MonoLMF, previous_lmf));
302 /*---------------------------------------------------------------*/
303 /* save method info */
304 /*---------------------------------------------------------------*/
305 s390_lg (buf, s390_r1, 0, STK_BASE, METHOD_SAVE_OFFSET);
306 s390_stg (buf, s390_r1, 0, s390_r13,
307 G_STRUCT_OFFSET(MonoLMF, method));
309 /*---------------------------------------------------------------*/
310 /* save the current SP */
311 /*---------------------------------------------------------------*/
312 s390_lg (buf, s390_r1, 0, STK_BASE, 0);
313 s390_stg (buf, s390_r1, 0, s390_r13, G_STRUCT_OFFSET(MonoLMF, ebp));
315 /*---------------------------------------------------------------*/
316 /* save the current IP */
317 /*---------------------------------------------------------------*/
319 s390_lg (buf, s390_r1, 0, s390_r1, S390_RET_ADDR_OFFSET);
321 s390_lghi (buf, s390_r1, 0);
323 s390_stg (buf, s390_r1, 0, s390_r13, G_STRUCT_OFFSET(MonoLMF, eip));
325 /*---------------------------------------------------------------*/
326 /* Save general and floating point registers */
327 /*---------------------------------------------------------------*/
328 s390_mvc (buf, 4*sizeof(gulong), s390_r13, G_STRUCT_OFFSET(MonoLMF, gregs[2]),
329 STK_BASE, CREATE_GR_OFFSET);
330 s390_mvc (buf, 10*sizeof(gulong), s390_r13, G_STRUCT_OFFSET(MonoLMF, gregs[6]),
331 s390_r11, S390_REG_SAVE_OFFSET);
333 /* Simply copy fpregs already saved above */
334 s390_mvc (buf, 16*sizeof(double), s390_r13, G_STRUCT_OFFSET(MonoLMF, fregs[0]),
335 STK_BASE, CREATE_FP_OFFSET);
337 /*---------------------------------------------------------------*/
338 /* STEP 2: call the C trampoline function */
339 /*---------------------------------------------------------------*/
343 /* Arg 1: mgreg_t *regs. We pass sp instead */
344 s390_la (buf, s390_r2, 0, STK_BASE, CREATE_STACK_SIZE);
346 /* Arg 2: code (next address to the instruction that called us) */
348 s390_lg (buf, s390_r3, 0, s390_r11, S390_RET_ADDR_OFFSET);
350 s390_lghi (buf, s390_r3, 0);
353 /* Arg 3: Trampoline argument */
354 if (tramp_type == MONO_TRAMPOLINE_GENERIC_CLASS_INIT)
355 s390_lg (buf, s390_r4, 0, STK_BASE, GENERIC_REG_OFFSET);
357 s390_lg (buf, s390_r4, 0, STK_BASE, METHOD_SAVE_OFFSET);
359 /* Arg 4: trampoline address. Ignore for now */
361 /* Calculate call address and call the C trampoline. Return value will be in r2 */
362 tramp = (guint8*)mono_get_trampoline_func (tramp_type);
363 S390_SET (buf, s390_r1, tramp);
364 s390_basr (buf, s390_r14, s390_r1);
366 /* OK, code address is now on r2. Move it to r1, so that we
367 can restore r2 and use it from r1 later */
368 s390_lgr (buf, s390_r1, s390_r2);
370 /*----------------------------------------------------------
371 STEP 3: Restore the LMF
372 ----------------------------------------------------------*/
373 restoreLMF(buf, STK_BASE, CREATE_STACK_SIZE);
375 /*----------------------------------------------------------
376 STEP 4: call the compiled method
377 ----------------------------------------------------------*/
379 /* Restore registers */
381 s390_lmg (buf, s390_r2, s390_r5, STK_BASE, CREATE_GR_OFFSET);
383 /* Restore the FP registers */
384 offset = CREATE_FP_OFFSET;
385 for (i = s390_f0; i <= s390_f15; ++i) {
386 s390_ld (buf, i, 0, STK_BASE, offset);
390 /* Restore stack pointer and jump to the code -
391 R14 contains the return address to our caller */
392 s390_lgr (buf, STK_BASE, s390_r11);
393 s390_lmg (buf, s390_r6, s390_r14, STK_BASE, S390_REG_SAVE_OFFSET);
395 if (MONO_TRAMPOLINE_TYPE_MUST_RETURN(tramp_type)) {
396 s390_lgr (buf, s390_r2, s390_r1);
397 s390_br (buf, s390_r14);
399 s390_br (buf, s390_r1);
402 /* Flush instruction cache, since we've generated code */
403 mono_arch_flush_icache (code, buf - code);
406 tramp_name = mono_get_generic_trampoline_name (tramp_type);
407 *info = mono_tramp_info_create (tramp_name, buf, buf - code, ji, unwind_ops);
412 g_assert ((buf - code) <= 512);
417 /*========================= End of Function ========================*/
419 /*------------------------------------------------------------------*/
421 /* Name - mono_arch_invalidate_method */
425 /*------------------------------------------------------------------*/
428 mono_arch_invalidate_method (MonoJitInfo *ji, void *func, gpointer func_arg)
430 /* FIXME: This is not thread safe */
431 guint8 *code = ji->code_start;
433 S390_SET (code, s390_r1, func);
434 S390_SET (code, s390_r2, func_arg);
435 s390_br (code, s390_r1);
439 /*========================= End of Function ========================*/
441 /*------------------------------------------------------------------*/
443 /* Name - mono_arch_create_specific_trampoline */
445 /* Function - Creates the given kind of specific trampoline */
447 /*------------------------------------------------------------------*/
450 mono_arch_create_specific_trampoline (gpointer arg1, MonoTrampolineType tramp_type, MonoDomain *domain, guint32 *code_len)
452 guint8 *code, *buf, *tramp;
455 tramp = mono_get_trampoline_code (tramp_type);
457 /*----------------------------------------------------------*/
458 /* This is the method-specific part of the trampoline. Its */
459 /* purpose is to provide the generic part with the */
460 /* MonoMethod *method pointer. We'll use r1 to keep it. */
461 /*----------------------------------------------------------*/
462 code = buf = mono_domain_code_reserve (domain, SPECIFIC_TRAMPOLINE_SIZE);
464 S390_SET (buf, s390_r1, arg1);
465 displace = (tramp - buf) / 2;
466 s390_jg (buf, displace);
468 /* Flush instruction cache, since we've generated code */
469 mono_arch_flush_icache (code, buf - code);
472 g_assert ((buf - code) <= SPECIFIC_TRAMPOLINE_SIZE);
475 *code_len = buf - code;
480 /*========================= End of Function ========================*/
482 /*------------------------------------------------------------------*/
484 /* Name - mono_arch_create_rgctx_lazy_fetch_trampoline */
488 /*------------------------------------------------------------------*/
491 mono_arch_create_rgctx_lazy_fetch_trampoline (guint32 slot, MonoTrampInfo **info, gboolean aot)
493 #ifdef MONO_ARCH_VTABLE_REG
496 guint8 **rgctx_null_jumps;
504 MonoJumpInfo *ji = NULL;
505 GSList *unwind_ops = NULL;
507 mrgctx = MONO_RGCTX_SLOT_IS_MRGCTX (slot);
508 index = MONO_RGCTX_SLOT_INDEX (slot);
510 index += MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
511 for (depth = 0; ; ++depth) {
512 int size = mono_class_rgctx_get_array_size (depth, mrgctx);
514 if (index < size - 1)
519 tramp_size = 48 + 16 * depth;
525 code = buf = mono_global_codeman_reserve (tramp_size);
527 unwind_ops = mono_arch_get_cie_program ();
529 rgctx_null_jumps = g_malloc (sizeof (guint8*) * (depth + 2));
533 s390_lgr (code, s390_r1, s390_r2);
535 /* load rgctx ptr from vtable */
536 s390_lg (code, s390_r1, 0, s390_r2, G_STRUCT_OFFSET(MonoVTable, runtime_generic_context));
537 /* is the rgctx ptr null? */
538 s390_ltgr (code, s390_r1, s390_r1);
539 /* if yes, jump to actual trampoline */
540 rgctx_null_jumps [iPatch++] = code;
544 for (i = 0; i < depth; ++i) {
545 /* load ptr to next array */
546 if (mrgctx && i == 0)
547 s390_lg (code, s390_r1, 0, s390_r1, MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT);
549 s390_lg (code, s390_r1, 0, s390_r1, 0);
550 s390_ltgr (code, s390_r1, s390_r1);
551 /* if the ptr is null then jump to actual trampoline */
552 rgctx_null_jumps [iPatch++] = code;
557 s390_lg (code, s390_r1, 0, s390_r1, (sizeof (gpointer) * (index + 1)));
558 /* is the slot null? */
559 s390_ltgr (code, s390_r1, s390_r1);
560 /* if yes, jump to actual trampoline */
561 rgctx_null_jumps [iPatch++] = code;
563 /* otherwise return r1 */
564 s390_lgr (code, s390_r2, s390_r1);
565 s390_br (code, s390_r14);
567 for (i = 0; i < iPatch; i++) {
568 displace = ((uintptr_t) code - (uintptr_t) rgctx_null_jumps[i]) / 2;
569 s390_patch_rel ((rgctx_null_jumps [i] + 2), displace);
572 g_free (rgctx_null_jumps);
574 /* move the rgctx pointer to the VTABLE register */
575 s390_lgr (code, MONO_ARCH_VTABLE_REG, s390_r2);
577 tramp = mono_arch_create_specific_trampoline (GUINT_TO_POINTER (slot),
578 MONO_TRAMPOLINE_RGCTX_LAZY_FETCH, mono_get_root_domain (), NULL);
580 /* jump to the actual trampoline */
581 displace = (tramp - code) / 2;
582 s390_jg (code, displace);
584 mono_arch_flush_icache (buf, code - buf);
586 g_assert (code - buf <= tramp_size);
589 char *name = mono_get_rgctx_fetch_trampoline_name (slot);
590 *info = mono_tramp_info_create (name, buf, code - buf, ji, unwind_ops);
596 g_assert_not_reached ();
601 /*========================= End of Function ========================*/
603 /*------------------------------------------------------------------*/
605 /* Name - mono_arch_get_static_rgctx_trampoline */
607 /* Function - Create a trampoline which sets RGCTX_REG to MRGCTX*/
608 /* then jumps to ADDR. */
610 /*------------------------------------------------------------------*/
613 mono_arch_get_static_rgctx_trampoline (MonoMethod *m,
614 MonoMethodRuntimeGenericContext *mrgctx,
617 guint8 *code, *start;
621 MonoDomain *domain = mono_domain_get ();
625 start = code = mono_domain_code_reserve (domain, buf_len);
627 S390_SET (code, MONO_ARCH_RGCTX_REG, mrgctx);
628 displace = ((uintptr_t) addr - (uintptr_t) code) / 2;
629 s390_jg (code, displace);
630 g_assert ((code - start) < buf_len);
632 mono_arch_flush_icache (start, code - start);
637 /*========================= End of Function ========================*/
639 /*------------------------------------------------------------------*/
641 /* Name - handler_block_trampoline_helper */
645 /*------------------------------------------------------------------*/
648 handler_block_trampoline_helper (gpointer *ptr)
650 MonoJitTlsData *jit_tls = mono_native_tls_get_value (mono_jit_tls_id);
651 *ptr = jit_tls->handler_block_return_address;
654 /*========================= End of Function ========================*/
656 /*------------------------------------------------------------------*/
658 /* Name - mono_arch_create_handler_block_trampoline */
662 /*------------------------------------------------------------------*/
665 mono_arch_create_handler_block_trampoline (MonoTrampInfo **info, gboolean aot)
667 guint8 *tramp = mono_get_trampoline_code (MONO_TRAMPOLINE_HANDLER_BLOCK_GUARD);
670 MonoJumpInfo *ji = NULL;
671 GSList *unwind_ops = NULL;
675 code = buf = mono_global_codeman_reserve (tramp_size);
678 * This trampoline restore the call chain of the handler block
679 * then jumps into the code that deals with it.
682 if (mono_get_jit_tls_offset () != -1) {
683 s390_ear (code, s390_r1, 0);
684 s390_sllg (code, s390_r1, s390_r1, 0, 32);
685 s390_ear (code, s390_r1, 1);
686 S390_SET (code, s390_r14, mono_get_jit_tls_offset());
687 s390_lg (code, s390_r14, s390_r1, 0, G_STRUCT_OFFSET(MonoJitTlsData, handler_block_return_address));
691 S390_SET (code, s390_r1, tramp);
692 s390_br (code, s390_r1);
695 * Slow path uses a C helper
697 S390_SET (code, s390_r2, tramp);
698 S390_SET (code, s390_r1, handler_block_trampoline_helper);
699 s390_br (code, s390_r1);
702 mono_arch_flush_icache (buf, code - buf);
703 g_assert (code - buf <= tramp_size);
706 *info = mono_tramp_info_create ("handler_block_trampoline", buf, code - buf, ji, unwind_ops);
711 /*========================= End of Function ========================*/
713 /*------------------------------------------------------------------*/
715 /* Name - mono_arch_create_generic_class_init_trampoline */
719 /*------------------------------------------------------------------*/
722 mono_arch_create_generic_class_init_trampoline (MonoTrampInfo **info, gboolean aot)
726 static int byte_offset = -1;
727 static guint8 bitmask;
730 GSList *unwind_ops = NULL;
731 MonoJumpInfo *ji = NULL;
735 code = buf = mono_global_codeman_reserve (tramp_size);
737 unwind_ops = mono_arch_get_cie_program ();
740 mono_marshal_find_bitfield_offset (MonoVTable, initialized, &byte_offset, &bitmask);
742 s390_llgc(code, s390_r0, 0, MONO_ARCH_VTABLE_REG, byte_offset);
743 s390_nill(code, s390_r0, bitmask);
744 s390_bnzr(code, s390_r14);
746 tramp = mono_arch_create_specific_trampoline (NULL, MONO_TRAMPOLINE_GENERIC_CLASS_INIT,
747 mono_get_root_domain (), NULL);
749 /* jump to the actual trampoline */
750 displace = (tramp - code) / 2;
751 s390_jg (code, displace);
753 mono_arch_flush_icache (buf, code - buf);
755 g_assert (code - buf <= tramp_size);
758 *info = mono_tramp_info_create ("generic_class_init_trampoline", buf, code - buf, ji, unwind_ops);
763 /*========================= End of Function ========================*/