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 /* Method-specific trampoline code fragment sizes */
33 /*------------------------------------------------------------------*/
34 #define METHOD_TRAMPOLINE_SIZE 64
35 #define JUMP_TRAMPOLINE_SIZE 64
37 /*========================= End of Defines =========================*/
39 /*------------------------------------------------------------------*/
41 /*------------------------------------------------------------------*/
47 #include <mono/metadata/appdomain.h>
48 #include <mono/metadata/marshal.h>
49 #include <mono/metadata/tabledefs.h>
50 #include <mono/arch/s390/s390-codegen.h>
51 #include <mono/metadata/mono-debug-debugger.h>
54 #include "mini-s390.h"
56 /*========================= End of Includes ========================*/
58 /*------------------------------------------------------------------*/
60 /*------------------------------------------------------------------*/
62 /*========================= End of Typedefs ========================*/
64 /*------------------------------------------------------------------*/
65 /* P r o t o t y p e s */
66 /*------------------------------------------------------------------*/
68 /*========================= End of Prototypes ======================*/
70 /*------------------------------------------------------------------*/
71 /* G l o b a l V a r i a b l e s */
72 /*------------------------------------------------------------------*/
75 /*====================== End of Global Variables ===================*/
77 /*------------------------------------------------------------------*/
79 /* Name - get_unbox_trampoline */
81 /* Function - Return a pointer to a trampoline which does the */
82 /* unboxing before calling the method. */
84 /* When value type methods are called through the */
85 /* vtable we need to unbox the 'this' argument. */
87 /* Parameters - method - Methd pointer */
88 /* addr - Pointer to native code for method */
90 /*------------------------------------------------------------------*/
93 get_unbox_trampoline (MonoMethod *method, gpointer addr)
96 int this_pos = s390_r2;
99 if ((!mono_method_signature (method)->ret->byref) &&
100 (MONO_TYPE_ISSTRUCT (mono_method_signature (method)->ret)))
103 start = code = mono_global_codeman_reserve (28);
105 s390_basr (code, s390_r13, 0);
107 s390_word (code, addr);
108 s390_l (code, s390_r1, 0, s390_r13, 4);
109 s390_ahi (code, this_pos, sizeof(MonoObject));
110 s390_br (code, s390_r1);
112 g_assert ((code - start) <= 28);
117 /*========================= End of Function ========================*/
119 /*------------------------------------------------------------------*/
121 /* Name - s390_magic_trampoline */
123 /* Function - This method is called by the function */
124 /* "arch_create_jit_trampoline", which in turn is */
125 /* called by the trampoline functions for virtual */
126 /* methods. After having called the JIT compiler to */
127 /* compile the method, it inspects the caller code */
128 /* to find the address of the method-specific part */
129 /* of the trampoline vtable slot for this method, */
130 /* updates it with a fragment that calls the newly */
131 /* compiled code and returns this address. The calls */
132 /* generated by mono for S/390 will look like either:*/
133 /* 1. l %r1,xxx(%rx) */
135 /* 2. brasl %r14,xxxxxx */
137 /* Parameters - code - Pointer into caller code */
138 /* method - The method to compile */
139 /* sp - Stack pointer */
141 /*------------------------------------------------------------------*/
144 s390_magic_trampoline (MonoMethod *method, guchar *code, char *sp)
149 unsigned short opcode;
154 addr = mono_compile_method(method);
160 /* The top bit needs to be ignored on S/390 */
161 (guint32) code &= 0x7fffffff;
163 fname = mono_method_full_name (method, TRUE);
164 codeJi = mono_jit_info_table_find (mono_domain_get(), code);
165 addrJi = mono_jit_info_table_find (mono_domain_get(), addr);
166 if (mono_method_same_domain (codeJi, addrJi)) {
168 opcode = *((unsigned short *) (code - 6));
171 /* This is a bras r14,r1 instruction */
174 displace = *((short *)code) & 0x0fff;
176 base = *((int *) (sp + S390_REG_SAVE_OFFSET+
177 sizeof(int)*(reg-6)));
179 base = *((int *) (sp + CREATE_GR_OFFSET+
180 sizeof(int)*(reg-2)));
182 if ((method->klass->valuetype) &&
183 (!mono_aot_is_got_entry(code, base)))
184 addr = get_unbox_trampoline(method, addr);
186 code = base + displace;
187 if (mono_domain_owns_vtable_slot(mono_domain_get(),
189 s390_patch(code, addr);
192 /* This is the 'brasl' instruction */
194 displace = ((gint32) addr - (gint32) (code - 2)) / 2;
195 if (mono_method_same_domain (codeJi, addrJi)) {
196 s390_patch (code, displace);
197 mono_arch_flush_icache (code, 4);
201 g_error("Unable to patch instruction prior to %p",code);
210 /*========================= End of Function ========================*/
212 /*------------------------------------------------------------------*/
214 /* Name - s390_class_init_trampoline */
216 /* Function - Initialize a class and then no-op the call to */
217 /* the trampoline. */
219 /*------------------------------------------------------------------*/
222 s390_class_init_trampoline (void *vtable, guchar *code, char *sp)
224 char patch[6] = {0x47, 0x00, 0x00, 0x00, 0x07, 0x00};
226 mono_runtime_class_init (vtable);
230 memcpy(code, patch, sizeof(patch));
233 /*========================= End of Function ========================*/
235 /*------------------------------------------------------------------*/
237 /* Name - mono_arch_create_trampoline_code */
239 /* Function - Create the designated type of trampoline according*/
240 /* to the 'tramp_type' parameter. */
242 /*------------------------------------------------------------------*/
245 mono_arch_create_trampoline_code (MonoTrampolineType tramp_type)
248 guint8 *buf, *code = NULL;
249 int i, offset, lmfOffset;
252 /* Now we'll create in 'buf' the S/390 trampoline code. This
253 is the trampoline code common to all methods */
255 code = buf = mono_global_codeman_reserve(512);
257 /*-----------------------------------------------------------
258 STEP 0: First create a non-standard function prologue with a
259 stack size big enough to save our registers.
260 -----------------------------------------------------------*/
262 s390_stm (buf, s390_r6, s390_r14, STK_BASE, S390_REG_SAVE_OFFSET);
263 s390_lr (buf, s390_r11, s390_r15);
264 s390_ahi (buf, STK_BASE, -CREATE_STACK_SIZE);
265 s390_st (buf, s390_r11, 0, STK_BASE, 0);
266 s390_stm (buf, s390_r2, s390_r5, STK_BASE, CREATE_GR_OFFSET);
268 /* Save the FP registers */
269 offset = CREATE_FP_OFFSET;
270 for (i = s390_f0; i <= s390_f15; ++i) {
271 s390_std (buf, i, 0, STK_BASE, offset);
275 /*----------------------------------------------------------
276 STEP 1: call 'mono_get_lmf_addr()' to get the address of our
277 LMF. We'll need to restore it after the call to
278 's390_magic_trampoline' and before the call to the native
280 ----------------------------------------------------------*/
282 s390_basr (buf, s390_r13, 0);
284 s390_word (buf, mono_get_lmf_addr);
285 s390_l (buf, s390_r1, 0, s390_r13, 4);
286 s390_basr (buf, s390_r14, s390_r1);
288 /*---------------------------------------------------------------*/
289 /* we build the MonoLMF structure on the stack - see mini-s390.h */
290 /* Keep in sync with the code in mono_arch_emit_prolog */
291 /*---------------------------------------------------------------*/
292 lmfOffset = CREATE_STACK_SIZE - sizeof(MonoLMF);
294 s390_lr (buf, s390_r13, STK_BASE);
295 s390_ahi (buf, s390_r13, lmfOffset);
297 /*---------------------------------------------------------------*/
298 /* Set lmf.lmf_addr = jit_tls->lmf */
299 /*---------------------------------------------------------------*/
300 s390_st (buf, s390_r2, 0, s390_r13,
301 G_STRUCT_OFFSET(MonoLMF, lmf_addr));
303 /*---------------------------------------------------------------*/
304 /* Get current lmf */
305 /*---------------------------------------------------------------*/
306 s390_l (buf, s390_r0, 0, s390_r2, 0);
308 /*---------------------------------------------------------------*/
309 /* Set our lmf as the current lmf */
310 /*---------------------------------------------------------------*/
311 s390_st (buf, s390_r13, 0, s390_r2, 0);
313 /*---------------------------------------------------------------*/
314 /* Have our lmf.previous_lmf point to the last lmf */
315 /*---------------------------------------------------------------*/
316 s390_st (buf, s390_r0, 0, s390_r13,
317 G_STRUCT_OFFSET(MonoLMF, previous_lmf));
319 /*---------------------------------------------------------------*/
320 /* save method info */
321 /*---------------------------------------------------------------*/
322 s390_l (buf, s390_r1, 0, s390_r11, METHOD_SAVE_OFFSET);
323 s390_st (buf, s390_r1, 0, s390_r13,
324 G_STRUCT_OFFSET(MonoLMF, method));
326 /*---------------------------------------------------------------*/
327 /* save the current SP */
328 /*---------------------------------------------------------------*/
329 s390_l (buf, s390_r1, 0, STK_BASE, 0);
330 s390_st (buf, s390_r1, 0, s390_r13, G_STRUCT_OFFSET(MonoLMF, ebp));
332 /*---------------------------------------------------------------*/
333 /* save the current IP */
334 /*---------------------------------------------------------------*/
335 if (tramp_type == MONO_TRAMPOLINE_JUMP) {
336 s390_lhi (buf, s390_r1, 0);
338 s390_l (buf, s390_r1, 0, s390_r1, S390_RET_ADDR_OFFSET);
339 s390_la (buf, s390_r1, 0, s390_r1, 0);
341 s390_st (buf, s390_r1, 0, s390_r13, G_STRUCT_OFFSET(MonoLMF, eip));
343 /*---------------------------------------------------------------*/
344 /* Save general and floating point registers */
345 /*---------------------------------------------------------------*/
346 s390_stm (buf, s390_r2, s390_r12, s390_r13,
347 G_STRUCT_OFFSET(MonoLMF, gregs[2]));
348 for (i = 0; i < 16; i++) {
349 s390_std (buf, i, 0, s390_r13,
350 G_STRUCT_OFFSET(MonoLMF, fregs[i]));
353 /*---------------------------------------------------------------*/
354 /* STEP 2: call 's390_magic_trampoline()', who will compile the */
355 /* code and fix the method vtable entry for us */
356 /*---------------------------------------------------------------*/
360 /* Arg 1: MonoMethod *method. It was put in r11 by the
361 method-specific trampoline code, and then saved before the call
362 to mono_get_lmf_addr()'. Restore r13, by the way :-) */
363 s390_l (buf, s390_r2, 0, s390_r11, METHOD_SAVE_OFFSET);
365 /* Arg 2: code (next address to the instruction that called us) */
366 if (tramp_type == MONO_TRAMPOLINE_JUMP) {
367 s390_lhi (buf, s390_r3, 0);
369 s390_l (buf, s390_r3, 0, s390_r11, S390_RET_ADDR_OFFSET);
372 /* Arg 3: stack pointer */
373 s390_lr (buf, s390_r4, STK_BASE);
375 /* Calculate call address and call
376 's390_magic_trampoline'. Return value will be in r2 */
377 s390_basr (buf, s390_r13, 0);
379 if (tramp_type == MONO_TRAMPOLINE_CLASS_INIT) {
380 s390_word (buf, s390_class_init_trampoline);
382 s390_word (buf, s390_magic_trampoline);
384 s390_l (buf, s390_r1, 0, s390_r13, 4);
385 s390_basr (buf, s390_r14, s390_r1);
387 /* OK, code address is now on r2. Move it to r1, so that we
388 can restore r2 and use it from r1 later */
389 s390_lr (buf, s390_r1, s390_r2);
391 /*----------------------------------------------------------
392 STEP 3: Restore the LMF
393 ----------------------------------------------------------*/
394 restoreLMF(buf, STK_BASE, CREATE_STACK_SIZE);
396 /*----------------------------------------------------------
397 STEP 4: call the compiled method
398 ----------------------------------------------------------*/
400 /* Restore registers */
402 s390_lm (buf, s390_r2, s390_r5, STK_BASE, CREATE_GR_OFFSET);
404 /* Restore the FP registers */
405 offset = CREATE_FP_OFFSET;
406 for (i = s390_f0; i <= s390_f15; ++i) {
407 s390_ld (buf, i, 0, STK_BASE, offset);
411 /* Restore stack pointer and jump to the code -
412 R14 contains the return address to our caller */
413 s390_lr (buf, STK_BASE, s390_r11);
414 s390_lm (buf, s390_r6, s390_r14, STK_BASE, S390_REG_SAVE_OFFSET);
415 s390_br (buf, s390_r1);
417 /* Flush instruction cache, since we've generated code */
418 mono_arch_flush_icache (code, buf - code);
421 g_assert ((buf - code) <= 512);
427 /*========================= End of Function ========================*/
429 /*------------------------------------------------------------------*/
431 /* Name - mono_arch_create_jump_trampoline */
433 /* Function - Create the designated type of trampoline according*/
434 /* to the 'tramp_type' parameter. */
436 /*------------------------------------------------------------------*/
439 mono_arch_create_jump_trampoline (MonoMethod *method)
441 guint8 *code, *buf, *tramp = NULL;
443 MonoDomain *domain = mono_domain_get();
446 tramp = mono_get_trampoline_code (MONO_TRAMPOLINE_JUMP);
448 mono_domain_lock (domain);
449 code = buf = mono_code_manager_reserve (domain->code_mp, METHOD_TRAMPOLINE_SIZE);
450 mono_domain_unlock (domain);
452 s390_basr (buf, s390_r13, 0);
454 s390_word (buf, method);
455 s390_l (buf, s390_r13, 0, s390_r13, 4);
456 displace = (tramp - buf) / 2;
457 s390_jcl (buf, S390_CC_UN, displace);
459 mono_arch_flush_icache (code, buf-code);
461 g_assert ((buf - code) <= JUMP_TRAMPOLINE_SIZE);
463 ji = g_new0 (MonoJitInfo, 1);
465 ji->code_start = code;
466 ji->code_size = buf - code;
468 mono_jit_stats.method_trampolines++;
473 /*========================= End of Function ========================*/
475 /*------------------------------------------------------------------*/
477 /* Name - mono_arch_create_jit_trampoline */
479 /* Function - Creates a trampoline function for virtual methods.*/
480 /* If the created code is called it first starts JIT */
481 /* compilation and then calls the newly created */
482 /* method. It also replaces the corresponding vtable */
483 /* entry (see s390_magic_trampoline). */
485 /* A trampoline consists of two parts: a main */
486 /* fragment, shared by all method trampolines, and */
487 /* and some code specific to each method, which */
488 /* hard-codes a reference to that method and then */
489 /* calls the main fragment. */
491 /* The main fragment contains a call to */
492 /* 's390_magic_trampoline', which performs a call */
493 /* to the JIT compiler and substitutes the method- */
494 /* specific fragment with some code that directly */
495 /* calls the JIT-compiled method. */
497 /* Parameter - method - Pointer to the method information */
499 /* Returns - A pointer to the newly created code */
501 /*------------------------------------------------------------------*/
504 mono_arch_create_jit_trampoline (MonoMethod *method)
507 static guint8 *vc = NULL;
510 vc = mono_get_trampoline_code (MONO_TRAMPOLINE_GENERIC);
512 /* This is the method-specific part of the trampoline. Its purpose is
513 to provide the generic part with the MonoMethod *method pointer. We'll
514 use r13 to keep that value, for instance. However, the generic part of
515 the trampoline relies on r11 having the same value it had before coming
516 here, so we must save it before. */
517 code = buf = mono_global_codeman_reserve(METHOD_TRAMPOLINE_SIZE);
519 s390_basr (buf, s390_r13, 0);
521 s390_word (buf, method);
522 s390_l (buf, s390_r13, 0, s390_r13, 4);
523 displace = (vc - buf) / 2;
524 s390_jcl (buf, S390_CC_UN, displace);
526 /* Flush instruction cache, since we've generated code */
527 mono_arch_flush_icache (code, buf - code);
530 g_assert ((buf - code) <= METHOD_TRAMPOLINE_SIZE);
535 /*========================= End of Function ========================*/
537 /*------------------------------------------------------------------*/
539 /* Name - mono_arch_create_class_init_trampoline */
541 /* Function - Creates a trampoline function to run a type init- */
542 /* ializer. If the trampoline is called, it calls */
543 /* mono_runtime_class_init with the given vtable, */
544 /* then patches the caller code so it does not get */
545 /* called any more. */
547 /* Parameter - vtable - The type to initialize */
549 /* Returns - A pointer to the newly created code */
551 /*------------------------------------------------------------------*/
554 mono_arch_create_class_init_trampoline (MonoVTable *vtable)
556 guint8 *code, *buf, *tramp;
558 tramp = mono_get_trampoline_code (MONO_TRAMPOLINE_CLASS_INIT);
560 /*-----------------------------------------------------------*/
561 /* This is the method-specific part of the trampoline. Its */
562 /* purpose is to provide the generic part with the MonoMethod*/
563 /* *method pointer. We'll use r11 to keep that value, for */
564 /* instance. However, the generic part of the trampoline */
565 /* relies on r11 having the same value it had before coming */
566 /* here, so we must save it before. */
567 /*-----------------------------------------------------------*/
568 code = buf = mono_global_codeman_reserve(METHOD_TRAMPOLINE_SIZE);
570 s390_st (buf, s390_r14, 0, STK_BASE, S390_RET_ADDR_OFFSET);
571 s390_ahi (buf, STK_BASE, -S390_MINIMAL_STACK_SIZE);
573 s390_basr (buf, s390_r1, 0);
575 s390_word (buf, vtable);
576 s390_word (buf, s390_class_init_trampoline);
577 s390_lr (buf, s390_r3, s390_r14);
578 s390_l (buf, s390_r2, 0, s390_r1, 4);
579 s390_lhi (buf, s390_r4, 0);
580 s390_l (buf, s390_r1, 0, s390_r1, 8);
581 s390_basr (buf, s390_r14, s390_r1);
583 s390_ahi (buf, STK_BASE, S390_MINIMAL_STACK_SIZE);
584 s390_l (buf, s390_r14, 0, STK_BASE, S390_RET_ADDR_OFFSET);
585 s390_br (buf, s390_r14);
587 /* Flush instruction cache, since we've generated code */
588 mono_arch_flush_icache (code, buf - code);
591 g_assert ((buf - code) <= METHOD_TRAMPOLINE_SIZE);
593 mono_jit_stats.method_trampolines++;
598 /*========================= End of Function ========================*/
600 /*------------------------------------------------------------------*/
602 /* Name - mono_debuger_create_notification_function */
604 /* Function - This method is only called when running in the */
605 /* Mono debugger. It returns a pointer to the */
606 /* arch specific notification function. */
608 /*------------------------------------------------------------------*/
611 mono_debugger_create_notification_function (gpointer *notification_address)
615 ptr = buf = mono_global_codeman_reserve (16);
617 if (notification_address)
618 *notification_address = buf;
619 s390_br (buf, s390_r14);
624 /*========================= End of Function ========================*/