1 /*------------------------------------------------------------------*/
3 /* Name - tramp-s390.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 CREATE_GR_OFFSET S390_MINIMAL_STACK_SIZE
26 #define CREATE_FP_OFFSET CREATE_GR_OFFSET+GR_SAVE_SIZE
27 #define CREATE_LMF_OFFSET CREATE_FP_OFFSET+FP_SAVE_SIZE
28 #define CREATE_STACK_SIZE (CREATE_LMF_OFFSET+2*sizeof(long)+sizeof(MonoLMF))
29 #define METHOD_SAVE_OFFSET S390_RET_ADDR_OFFSET-4
31 /*------------------------------------------------------------------*/
32 /* adapt to mini later... */
33 /*------------------------------------------------------------------*/
34 #define mono_jit_share_code (1)
36 /*------------------------------------------------------------------*/
37 /* Method-specific trampoline code fragment sizes */
38 /*------------------------------------------------------------------*/
39 #define METHOD_TRAMPOLINE_SIZE 64
40 #define JUMP_TRAMPOLINE_SIZE 64
42 /*========================= End of Defines =========================*/
44 /*------------------------------------------------------------------*/
46 /*------------------------------------------------------------------*/
52 #include <mono/metadata/appdomain.h>
53 #include <mono/metadata/marshal.h>
54 #include <mono/metadata/tabledefs.h>
55 #include <mono/arch/s390/s390-codegen.h>
56 #include <mono/metadata/mono-debug-debugger.h>
59 #include "mini-s390.h"
61 /*========================= End of Includes ========================*/
63 /*------------------------------------------------------------------*/
65 /*------------------------------------------------------------------*/
68 MONO_TRAMPOLINE_GENERIC,
70 MONO_TRAMPOLINE_CLASS_INIT
73 /*========================= End of Typedefs ========================*/
75 /*------------------------------------------------------------------*/
76 /* P r o t o t y p e s */
77 /*------------------------------------------------------------------*/
79 /*------------------------------------------------------------------*/
80 /* Address of the generic trampoline code. This is used by the */
81 /* debugger to check whether a method is a trampoline. */
82 /*------------------------------------------------------------------*/
83 guint8 *mono_generic_trampoline_code = NULL;
85 /*========================= End of Prototypes ======================*/
87 /*------------------------------------------------------------------*/
88 /* G l o b a l V a r i a b l e s */
89 /*------------------------------------------------------------------*/
92 /*====================== End of Global Variables ===================*/
94 /*------------------------------------------------------------------*/
96 /* Name - get_unbox_trampoline */
98 /* Function - Return a pointer to a trampoline which does the */
99 /* unboxing before calling the method. */
101 /* When value type methods are called through the */
102 /* vtable we need to unbox the 'this' argument. */
104 /* Parameters - method - Methd pointer */
105 /* addr - Pointer to native code for method */
107 /*------------------------------------------------------------------*/
110 get_unbox_trampoline (MonoMethod *method, gpointer addr)
112 guint8 *code, *start;
113 int this_pos = s390_r2;
116 if ((!mono_method_signature (method)->ret->byref) &&
117 (MONO_TYPE_ISSTRUCT (mono_method_signature (method)->ret)))
120 start = code = mono_global_codeman_reserve (28);
122 s390_basr (code, s390_r13, 0);
124 s390_word (code, addr);
125 s390_l (code, s390_r1, 0, s390_r13, 4);
126 s390_ahi (code, this_pos, sizeof(MonoObject));
127 s390_br (code, s390_r1);
129 g_assert ((code - start) <= 28);
134 /*========================= End of Function ========================*/
136 /*------------------------------------------------------------------*/
138 /* Name - s390_magic_trampoline */
140 /* Function - This method is called by the function */
141 /* "arch_create_jit_trampoline", which in turn is */
142 /* called by the trampoline functions for virtual */
143 /* methods. After having called the JIT compiler to */
144 /* compile the method, it inspects the caller code */
145 /* to find the address of the method-specific part */
146 /* of the trampoline vtable slot for this method, */
147 /* updates it with a fragment that calls the newly */
148 /* compiled code and returns this address. The calls */
149 /* generated by mono for S/390 will look like either:*/
150 /* 1. l %r1,xxx(%rx) */
152 /* 2. brasl %r14,xxxxxx */
154 /* Parameters - code - Pointer into caller code */
155 /* method - The method to compile */
156 /* sp - Stack pointer */
158 /*------------------------------------------------------------------*/
161 s390_magic_trampoline (MonoMethod *method, guchar *code, char *sp)
166 unsigned short opcode;
171 addr = mono_compile_method(method);
177 /* The top bit needs to be ignored on S/390 */
178 (guint32) code &= 0x7fffffff;
180 fname = mono_method_full_name (method, TRUE);
181 codeJi = mono_jit_info_table_find (mono_domain_get(), code);
182 addrJi = mono_jit_info_table_find (mono_domain_get(), addr);
183 if (mono_method_same_domain (codeJi, addrJi)) {
185 opcode = *((unsigned short *) (code - 6));
188 /* This is a bras r14,r1 instruction */
191 displace = *((short *)code) & 0x0fff;
193 base = *((int *) (sp + S390_REG_SAVE_OFFSET+
194 sizeof(int)*(reg-6)));
196 base = *((int *) (sp + CREATE_GR_OFFSET+
197 sizeof(int)*(reg-2)));
199 if ((method->klass->valuetype) &&
200 (!mono_aot_is_got_entry(code, base)))
201 addr = get_unbox_trampoline(method, addr);
203 code = base + displace;
204 if (mono_domain_owns_vtable_slot(mono_domain_get(),
206 s390_patch(code, addr);
209 /* This is the 'brasl' instruction */
211 displace = ((gint32) addr - (gint32) (code - 2)) / 2;
212 if (mono_method_same_domain (codeJi, addrJi)) {
213 s390_patch (code, displace);
214 mono_arch_flush_icache (code, 4);
218 g_error("Unable to patch instruction prior to %p",code);
227 /*========================= End of Function ========================*/
229 /*------------------------------------------------------------------*/
231 /* Name - s390_class_init_trampoline */
233 /* Function - Initialize a class and then no-op the call to */
234 /* the trampoline. */
236 /*------------------------------------------------------------------*/
239 s390_class_init_trampoline (void *vtable, guchar *code, char *sp)
241 char patch[6] = {0x47, 0x00, 0x00, 0x00, 0x07, 0x00};
243 mono_runtime_class_init (vtable);
247 memcpy(code, patch, sizeof(patch));
250 /*========================= End of Function ========================*/
252 /*------------------------------------------------------------------*/
254 /* Name - create_trampoline_code */
256 /* Function - Create the designated type of trampoline according*/
257 /* to the 'tramp_type' parameter. */
259 /*------------------------------------------------------------------*/
262 create_trampoline_code (MonoTrampolineType tramp_type)
265 guint8 *buf, *code = NULL;
266 static guint8* generic_jump_trampoline = NULL;
267 static guint8 *generic_class_init_trampoline = NULL;
268 int i, offset, lmfOffset;
270 switch (tramp_type) {
271 case MONO_TRAMPOLINE_GENERIC:
272 if (mono_generic_trampoline_code)
273 return mono_generic_trampoline_code;
275 case MONO_TRAMPOLINE_JUMP:
276 if (generic_jump_trampoline)
277 return generic_jump_trampoline;
279 case MONO_TRAMPOLINE_CLASS_INIT:
280 if (generic_class_init_trampoline)
281 return generic_class_init_trampoline;
286 /* Now we'll create in 'buf' the S/390 trampoline code. This
287 is the trampoline code common to all methods */
289 code = buf = mono_global_codeman_reserve(512);
291 /*-----------------------------------------------------------
292 STEP 0: First create a non-standard function prologue with a
293 stack size big enough to save our registers.
294 -----------------------------------------------------------*/
296 s390_stm (buf, s390_r6, s390_r14, STK_BASE, S390_REG_SAVE_OFFSET);
297 s390_lr (buf, s390_r11, s390_r15);
298 s390_ahi (buf, STK_BASE, -CREATE_STACK_SIZE);
299 s390_st (buf, s390_r11, 0, STK_BASE, 0);
300 s390_stm (buf, s390_r2, s390_r5, STK_BASE, CREATE_GR_OFFSET);
302 /* Save the FP registers */
303 offset = CREATE_FP_OFFSET;
304 for (i = s390_f0; i <= s390_f15; ++i) {
305 s390_std (buf, i, 0, STK_BASE, offset);
309 /*----------------------------------------------------------
310 STEP 1: call 'mono_get_lmf_addr()' to get the address of our
311 LMF. We'll need to restore it after the call to
312 's390_magic_trampoline' and before the call to the native
314 ----------------------------------------------------------*/
316 s390_basr (buf, s390_r13, 0);
318 s390_word (buf, mono_get_lmf_addr);
319 s390_l (buf, s390_r1, 0, s390_r13, 4);
320 s390_basr (buf, s390_r14, s390_r1);
322 /*---------------------------------------------------------------*/
323 /* we build the MonoLMF structure on the stack - see mini-s390.h */
324 /* Keep in sync with the code in mono_arch_emit_prolog */
325 /*---------------------------------------------------------------*/
326 lmfOffset = CREATE_STACK_SIZE - sizeof(MonoLMF);
328 s390_lr (buf, s390_r13, STK_BASE);
329 s390_ahi (buf, s390_r13, lmfOffset);
331 /*---------------------------------------------------------------*/
332 /* Set lmf.lmf_addr = jit_tls->lmf */
333 /*---------------------------------------------------------------*/
334 s390_st (buf, s390_r2, 0, s390_r13,
335 G_STRUCT_OFFSET(MonoLMF, lmf_addr));
337 /*---------------------------------------------------------------*/
338 /* Get current lmf */
339 /*---------------------------------------------------------------*/
340 s390_l (buf, s390_r0, 0, s390_r2, 0);
342 /*---------------------------------------------------------------*/
343 /* Set our lmf as the current lmf */
344 /*---------------------------------------------------------------*/
345 s390_st (buf, s390_r13, 0, s390_r2, 0);
347 /*---------------------------------------------------------------*/
348 /* Have our lmf.previous_lmf point to the last lmf */
349 /*---------------------------------------------------------------*/
350 s390_st (buf, s390_r0, 0, s390_r13,
351 G_STRUCT_OFFSET(MonoLMF, previous_lmf));
353 /*---------------------------------------------------------------*/
354 /* save method info */
355 /*---------------------------------------------------------------*/
356 s390_l (buf, s390_r1, 0, s390_r11, METHOD_SAVE_OFFSET);
357 s390_st (buf, s390_r1, 0, s390_r13,
358 G_STRUCT_OFFSET(MonoLMF, method));
360 /*---------------------------------------------------------------*/
361 /* save the current SP */
362 /*---------------------------------------------------------------*/
363 s390_l (buf, s390_r1, 0, STK_BASE, 0);
364 s390_st (buf, s390_r1, 0, s390_r13, G_STRUCT_OFFSET(MonoLMF, ebp));
366 /*---------------------------------------------------------------*/
367 /* save the current IP */
368 /*---------------------------------------------------------------*/
369 if (tramp_type == MONO_TRAMPOLINE_JUMP) {
370 s390_lhi (buf, s390_r1, 0);
372 s390_l (buf, s390_r1, 0, s390_r1, S390_RET_ADDR_OFFSET);
373 s390_la (buf, s390_r1, 0, s390_r1, 0);
375 s390_st (buf, s390_r1, 0, s390_r13, G_STRUCT_OFFSET(MonoLMF, eip));
377 /*---------------------------------------------------------------*/
378 /* Save general and floating point registers */
379 /*---------------------------------------------------------------*/
380 s390_stm (buf, s390_r2, s390_r12, s390_r13,
381 G_STRUCT_OFFSET(MonoLMF, gregs[2]));
382 for (i = 0; i < 16; i++) {
383 s390_std (buf, i, 0, s390_r13,
384 G_STRUCT_OFFSET(MonoLMF, fregs[i]));
387 /*---------------------------------------------------------------*/
388 /* STEP 2: call 's390_magic_trampoline()', who will compile the */
389 /* code and fix the method vtable entry for us */
390 /*---------------------------------------------------------------*/
394 /* Arg 1: MonoMethod *method. It was put in r11 by the
395 method-specific trampoline code, and then saved before the call
396 to mono_get_lmf_addr()'. Restore r13, by the way :-) */
397 s390_l (buf, s390_r2, 0, s390_r11, METHOD_SAVE_OFFSET);
399 /* Arg 2: code (next address to the instruction that called us) */
400 if (tramp_type == MONO_TRAMPOLINE_JUMP) {
401 s390_lhi (buf, s390_r3, 0);
403 s390_l (buf, s390_r3, 0, s390_r11, S390_RET_ADDR_OFFSET);
406 /* Arg 3: stack pointer */
407 s390_lr (buf, s390_r4, STK_BASE);
409 /* Calculate call address and call
410 's390_magic_trampoline'. Return value will be in r2 */
411 s390_basr (buf, s390_r13, 0);
413 if (tramp_type == MONO_TRAMPOLINE_CLASS_INIT) {
414 s390_word (buf, s390_class_init_trampoline);
416 s390_word (buf, s390_magic_trampoline);
418 s390_l (buf, s390_r1, 0, s390_r13, 4);
419 s390_basr (buf, s390_r14, s390_r1);
421 /* OK, code address is now on r2. Move it to r1, so that we
422 can restore r2 and use it from r1 later */
423 s390_lr (buf, s390_r1, s390_r2);
425 /*----------------------------------------------------------
426 STEP 3: Restore the LMF
427 ----------------------------------------------------------*/
428 restoreLMF(buf, STK_BASE, CREATE_STACK_SIZE);
430 /*----------------------------------------------------------
431 STEP 4: call the compiled method
432 ----------------------------------------------------------*/
434 /* Restore registers */
436 s390_lm (buf, s390_r2, s390_r5, STK_BASE, CREATE_GR_OFFSET);
438 /* Restore the FP registers */
439 offset = CREATE_FP_OFFSET;
440 for (i = s390_f0; i <= s390_f15; ++i) {
441 s390_ld (buf, i, 0, STK_BASE, offset);
445 /* Restore stack pointer and jump to the code -
446 R14 contains the return address to our caller */
447 s390_lr (buf, STK_BASE, s390_r11);
448 s390_lm (buf, s390_r6, s390_r14, STK_BASE, S390_REG_SAVE_OFFSET);
449 s390_br (buf, s390_r1);
451 /* Flush instruction cache, since we've generated code */
452 mono_arch_flush_icache (code, buf - code);
455 g_assert ((buf - code) <= 512);
458 switch (tramp_type) {
459 case MONO_TRAMPOLINE_GENERIC:
460 mono_generic_trampoline_code = code;
462 case MONO_TRAMPOLINE_JUMP:
463 generic_jump_trampoline = code;
465 case MONO_TRAMPOLINE_CLASS_INIT:
466 generic_class_init_trampoline = code;
473 /*========================= End of Function ========================*/
475 /*------------------------------------------------------------------*/
477 /* Name - mono_arch_create_jump_trampoline */
479 /* Function - Create the designated type of trampoline according*/
480 /* to the 'tramp_type' parameter. */
482 /*------------------------------------------------------------------*/
485 mono_arch_create_jump_trampoline (MonoMethod *method)
487 guint8 *code, *buf, *tramp = NULL;
489 MonoDomain *domain = mono_domain_get();
492 tramp = create_trampoline_code (MONO_TRAMPOLINE_JUMP);
494 mono_domain_lock (domain);
495 code = buf = mono_code_manager_reserve (domain->code_mp, METHOD_TRAMPOLINE_SIZE);
496 mono_domain_unlock (domain);
498 s390_basr (buf, s390_r13, 0);
500 s390_word (buf, method);
501 s390_l (buf, s390_r13, 0, s390_r13, 4);
502 displace = (tramp - buf) / 2;
503 s390_jcl (buf, S390_CC_UN, displace);
505 mono_arch_flush_icache (code, buf-code);
507 g_assert ((buf - code) <= JUMP_TRAMPOLINE_SIZE);
509 ji = g_new0 (MonoJitInfo, 1);
511 ji->code_start = code;
512 ji->code_size = buf - code;
514 mono_jit_stats.method_trampolines++;
519 /*========================= End of Function ========================*/
521 /*------------------------------------------------------------------*/
523 /* Name - mono_arch_create_jit_trampoline */
525 /* Function - Creates a trampoline function for virtual methods.*/
526 /* If the created code is called it first starts JIT */
527 /* compilation and then calls the newly created */
528 /* method. It also replaces the corresponding vtable */
529 /* entry (see s390_magic_trampoline). */
531 /* A trampoline consists of two parts: a main */
532 /* fragment, shared by all method trampolines, and */
533 /* and some code specific to each method, which */
534 /* hard-codes a reference to that method and then */
535 /* calls the main fragment. */
537 /* The main fragment contains a call to */
538 /* 's390_magic_trampoline', which performs a call */
539 /* to the JIT compiler and substitutes the method- */
540 /* specific fragment with some code that directly */
541 /* calls the JIT-compiled method. */
543 /* Parameter - method - Pointer to the method information */
545 /* Returns - A pointer to the newly created code */
547 /*------------------------------------------------------------------*/
550 mono_arch_create_jit_trampoline (MonoMethod *method)
553 static guint8 *vc = NULL;
556 vc = create_trampoline_code (MONO_TRAMPOLINE_GENERIC);
558 /* This is the method-specific part of the trampoline. Its purpose is
559 to provide the generic part with the MonoMethod *method pointer. We'll
560 use r13 to keep that value, for instance. However, the generic part of
561 the trampoline relies on r11 having the same value it had before coming
562 here, so we must save it before. */
563 code = buf = mono_global_codeman_reserve(METHOD_TRAMPOLINE_SIZE);
565 s390_basr (buf, s390_r13, 0);
567 s390_word (buf, method);
568 s390_l (buf, s390_r13, 0, s390_r13, 4);
569 displace = (vc - buf) / 2;
570 s390_jcl (buf, S390_CC_UN, displace);
572 /* Flush instruction cache, since we've generated code */
573 mono_arch_flush_icache (code, buf - code);
576 g_assert ((buf - code) <= METHOD_TRAMPOLINE_SIZE);
581 /*========================= End of Function ========================*/
583 /*------------------------------------------------------------------*/
585 /* Name - mono_arch_create_class_init_trampoline */
587 /* Function - Creates a trampoline function to run a type init- */
588 /* ializer. If the trampoline is called, it calls */
589 /* mono_runtime_class_init with the given vtable, */
590 /* then patches the caller code so it does not get */
591 /* called any more. */
593 /* Parameter - vtable - The type to initialize */
595 /* Returns - A pointer to the newly created code */
597 /*------------------------------------------------------------------*/
600 mono_arch_create_class_init_trampoline (MonoVTable *vtable)
602 guint8 *code, *buf, *tramp;
604 tramp = create_trampoline_code (MONO_TRAMPOLINE_CLASS_INIT);
606 /*-----------------------------------------------------------*/
607 /* This is the method-specific part of the trampoline. Its */
608 /* purpose is to provide the generic part with the MonoMethod*/
609 /* *method pointer. We'll use r11 to keep that value, for */
610 /* instance. However, the generic part of the trampoline */
611 /* relies on r11 having the same value it had before coming */
612 /* here, so we must save it before. */
613 /*-----------------------------------------------------------*/
614 code = buf = mono_global_codeman_reserve(METHOD_TRAMPOLINE_SIZE);
616 s390_st (buf, s390_r14, 0, STK_BASE, S390_RET_ADDR_OFFSET);
617 s390_ahi (buf, STK_BASE, -S390_MINIMAL_STACK_SIZE);
619 s390_basr (buf, s390_r1, 0);
621 s390_word (buf, vtable);
622 s390_word (buf, s390_class_init_trampoline);
623 s390_lr (buf, s390_r3, s390_r14);
624 s390_l (buf, s390_r2, 0, s390_r1, 4);
625 s390_lhi (buf, s390_r4, 0);
626 s390_l (buf, s390_r1, 0, s390_r1, 8);
627 s390_basr (buf, s390_r14, s390_r1);
629 s390_ahi (buf, STK_BASE, S390_MINIMAL_STACK_SIZE);
630 s390_l (buf, s390_r14, 0, STK_BASE, S390_RET_ADDR_OFFSET);
631 s390_br (buf, s390_r14);
633 /* Flush instruction cache, since we've generated code */
634 mono_arch_flush_icache (code, buf - code);
637 g_assert ((buf - code) <= METHOD_TRAMPOLINE_SIZE);
639 mono_jit_stats.method_trampolines++;
644 /*========================= End of Function ========================*/
646 /*------------------------------------------------------------------*/
648 /* Name - mono_debuger_create_notification_function */
650 /* Function - This method is only called when running in the */
651 /* Mono debugger. It returns a pointer to the */
652 /* arch specific notification function. */
654 /*------------------------------------------------------------------*/
657 mono_debugger_create_notification_function (gpointer *notification_address)
661 ptr = buf = mono_global_codeman_reserve (16);
663 if (notification_address)
664 *notification_address = buf;
665 s390_br (buf, s390_r14);
670 /*========================= End of Function ========================*/