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)
150 unsigned short opcode;
155 addr = mono_compile_method(method);
161 /* The top bit needs to be ignored on S/390 */
162 code = (guchar*)((guint32)code & 0x7fffffff);
164 fname = mono_method_full_name (method, TRUE);
165 codeJi = mono_jit_info_table_find (mono_domain_get(), code);
166 addrJi = mono_jit_info_table_find (mono_domain_get(), addr);
167 if (mono_method_same_domain (codeJi, addrJi)) {
169 opcode = *((unsigned short *) (code - 6));
172 /* This is a bras r14,r1 instruction */
175 displace = *((short *)code) & 0x0fff;
177 base = *((guchar **) (sp + S390_REG_SAVE_OFFSET+
178 sizeof(int)*(reg-6)));
180 base = *((guchar **) (sp + CREATE_GR_OFFSET+
181 sizeof(int)*(reg-2)));
183 if ((method->klass->valuetype) &&
184 (!mono_aot_is_got_entry(code, base)))
185 addr = get_unbox_trampoline(method, addr);
187 code = base + displace;
188 if (mono_domain_owns_vtable_slot(mono_domain_get(),
190 s390_patch(code, addr);
193 /* This is the 'brasl' instruction */
195 displace = ((gint32) addr - (gint32) (code - 2)) / 2;
196 if (mono_method_same_domain (codeJi, addrJi)) {
197 s390_patch (code, displace);
198 mono_arch_flush_icache (code, 4);
202 g_error("Unable to patch instruction prior to %p",code);
211 /*========================= End of Function ========================*/
213 /*------------------------------------------------------------------*/
215 /* Name - s390_class_init_trampoline */
217 /* Function - Initialize a class and then no-op the call to */
218 /* the trampoline. */
220 /*------------------------------------------------------------------*/
223 s390_class_init_trampoline (void *vtable, guchar *code, char *sp)
225 char patch[6] = {0x47, 0x00, 0x00, 0x00, 0x07, 0x00};
227 mono_runtime_class_init (vtable);
231 memcpy(code, patch, sizeof(patch));
234 /*========================= End of Function ========================*/
236 /*------------------------------------------------------------------*/
238 /* Name - mono_arch_create_trampoline_code */
240 /* Function - Create the designated type of trampoline according*/
241 /* to the 'tramp_type' parameter. */
243 /*------------------------------------------------------------------*/
246 mono_arch_create_trampoline_code (MonoTrampolineType tramp_type)
249 guint8 *buf, *code = NULL;
250 int i, offset, lmfOffset;
253 /* Now we'll create in 'buf' the S/390 trampoline code. This
254 is the trampoline code common to all methods */
256 code = buf = mono_global_codeman_reserve(512);
258 /*-----------------------------------------------------------
259 STEP 0: First create a non-standard function prologue with a
260 stack size big enough to save our registers.
261 -----------------------------------------------------------*/
263 s390_stm (buf, s390_r6, s390_r14, STK_BASE, S390_REG_SAVE_OFFSET);
264 s390_lr (buf, s390_r11, s390_r15);
265 s390_ahi (buf, STK_BASE, -CREATE_STACK_SIZE);
266 s390_st (buf, s390_r11, 0, STK_BASE, 0);
267 s390_stm (buf, s390_r2, s390_r5, STK_BASE, CREATE_GR_OFFSET);
269 /* Save the FP registers */
270 offset = CREATE_FP_OFFSET;
271 for (i = s390_f0; i <= s390_f15; ++i) {
272 s390_std (buf, i, 0, STK_BASE, offset);
276 /*----------------------------------------------------------
277 STEP 1: call 'mono_get_lmf_addr()' to get the address of our
278 LMF. We'll need to restore it after the call to
279 's390_magic_trampoline' and before the call to the native
281 ----------------------------------------------------------*/
283 s390_basr (buf, s390_r13, 0);
285 s390_word (buf, mono_get_lmf_addr);
286 s390_l (buf, s390_r1, 0, s390_r13, 4);
287 s390_basr (buf, s390_r14, s390_r1);
289 /*---------------------------------------------------------------*/
290 /* we build the MonoLMF structure on the stack - see mini-s390.h */
291 /* Keep in sync with the code in mono_arch_emit_prolog */
292 /*---------------------------------------------------------------*/
293 lmfOffset = CREATE_STACK_SIZE - sizeof(MonoLMF);
295 s390_lr (buf, s390_r13, STK_BASE);
296 s390_ahi (buf, s390_r13, lmfOffset);
298 /*---------------------------------------------------------------*/
299 /* Set lmf.lmf_addr = jit_tls->lmf */
300 /*---------------------------------------------------------------*/
301 s390_st (buf, s390_r2, 0, s390_r13,
302 G_STRUCT_OFFSET(MonoLMF, lmf_addr));
304 /*---------------------------------------------------------------*/
305 /* Get current lmf */
306 /*---------------------------------------------------------------*/
307 s390_l (buf, s390_r0, 0, s390_r2, 0);
309 /*---------------------------------------------------------------*/
310 /* Set our lmf as the current lmf */
311 /*---------------------------------------------------------------*/
312 s390_st (buf, s390_r13, 0, s390_r2, 0);
314 /*---------------------------------------------------------------*/
315 /* Have our lmf.previous_lmf point to the last lmf */
316 /*---------------------------------------------------------------*/
317 s390_st (buf, s390_r0, 0, s390_r13,
318 G_STRUCT_OFFSET(MonoLMF, previous_lmf));
320 /*---------------------------------------------------------------*/
321 /* save method info */
322 /*---------------------------------------------------------------*/
323 s390_l (buf, s390_r1, 0, s390_r11, METHOD_SAVE_OFFSET);
324 s390_st (buf, s390_r1, 0, s390_r13,
325 G_STRUCT_OFFSET(MonoLMF, method));
327 /*---------------------------------------------------------------*/
328 /* save the current SP */
329 /*---------------------------------------------------------------*/
330 s390_l (buf, s390_r1, 0, STK_BASE, 0);
331 s390_st (buf, s390_r1, 0, s390_r13, G_STRUCT_OFFSET(MonoLMF, ebp));
333 /*---------------------------------------------------------------*/
334 /* save the current IP */
335 /*---------------------------------------------------------------*/
336 if (tramp_type == MONO_TRAMPOLINE_JUMP) {
337 s390_lhi (buf, s390_r1, 0);
339 s390_l (buf, s390_r1, 0, s390_r1, S390_RET_ADDR_OFFSET);
340 s390_la (buf, s390_r1, 0, s390_r1, 0);
342 s390_st (buf, s390_r1, 0, s390_r13, G_STRUCT_OFFSET(MonoLMF, eip));
344 /*---------------------------------------------------------------*/
345 /* Save general and floating point registers */
346 /*---------------------------------------------------------------*/
347 s390_stm (buf, s390_r2, s390_r12, s390_r13,
348 G_STRUCT_OFFSET(MonoLMF, gregs[2]));
349 for (i = 0; i < 16; i++) {
350 s390_std (buf, i, 0, s390_r13,
351 G_STRUCT_OFFSET(MonoLMF, fregs[i]));
354 /*---------------------------------------------------------------*/
355 /* STEP 2: call 's390_magic_trampoline()', who will compile the */
356 /* code and fix the method vtable entry for us */
357 /*---------------------------------------------------------------*/
361 /* Arg 1: MonoMethod *method. It was put in r11 by the
362 method-specific trampoline code, and then saved before the call
363 to mono_get_lmf_addr()'. Restore r13, by the way :-) */
364 s390_l (buf, s390_r2, 0, s390_r11, METHOD_SAVE_OFFSET);
366 /* Arg 2: code (next address to the instruction that called us) */
367 if (tramp_type == MONO_TRAMPOLINE_JUMP) {
368 s390_lhi (buf, s390_r3, 0);
370 s390_l (buf, s390_r3, 0, s390_r11, S390_RET_ADDR_OFFSET);
373 /* Arg 3: stack pointer */
374 s390_lr (buf, s390_r4, STK_BASE);
376 /* Calculate call address and call
377 's390_magic_trampoline'. Return value will be in r2 */
378 s390_basr (buf, s390_r13, 0);
380 if (tramp_type == MONO_TRAMPOLINE_CLASS_INIT) {
381 s390_word (buf, s390_class_init_trampoline);
383 s390_word (buf, s390_magic_trampoline);
385 s390_l (buf, s390_r1, 0, s390_r13, 4);
386 s390_basr (buf, s390_r14, s390_r1);
388 /* OK, code address is now on r2. Move it to r1, so that we
389 can restore r2 and use it from r1 later */
390 s390_lr (buf, s390_r1, s390_r2);
392 /*----------------------------------------------------------
393 STEP 3: Restore the LMF
394 ----------------------------------------------------------*/
395 restoreLMF(buf, STK_BASE, CREATE_STACK_SIZE);
397 /*----------------------------------------------------------
398 STEP 4: call the compiled method
399 ----------------------------------------------------------*/
401 /* Restore registers */
403 s390_lm (buf, s390_r2, s390_r5, STK_BASE, CREATE_GR_OFFSET);
405 /* Restore the FP registers */
406 offset = CREATE_FP_OFFSET;
407 for (i = s390_f0; i <= s390_f15; ++i) {
408 s390_ld (buf, i, 0, STK_BASE, offset);
412 /* Restore stack pointer and jump to the code -
413 R14 contains the return address to our caller */
414 s390_lr (buf, STK_BASE, s390_r11);
415 s390_lm (buf, s390_r6, s390_r14, STK_BASE, S390_REG_SAVE_OFFSET);
416 s390_br (buf, s390_r1);
418 /* Flush instruction cache, since we've generated code */
419 mono_arch_flush_icache (code, buf - code);
422 g_assert ((buf - code) <= 512);
428 /*========================= End of Function ========================*/
430 /*------------------------------------------------------------------*/
432 /* Name - mono_arch_create_jump_trampoline */
434 /* Function - Create the designated type of trampoline according*/
435 /* to the 'tramp_type' parameter. */
437 /*------------------------------------------------------------------*/
440 mono_arch_create_jump_trampoline (MonoMethod *method)
442 guint8 *code, *buf, *tramp = NULL;
444 MonoDomain *domain = mono_domain_get();
447 tramp = mono_get_trampoline_code (MONO_TRAMPOLINE_JUMP);
449 mono_domain_lock (domain);
450 code = buf = mono_code_manager_reserve (domain->code_mp, METHOD_TRAMPOLINE_SIZE);
451 mono_domain_unlock (domain);
453 s390_basr (buf, s390_r13, 0);
455 s390_word (buf, method);
456 s390_l (buf, s390_r13, 0, s390_r13, 4);
457 displace = (tramp - buf) / 2;
458 s390_jcl (buf, S390_CC_UN, displace);
460 mono_arch_flush_icache (code, buf-code);
462 g_assert ((buf - code) <= JUMP_TRAMPOLINE_SIZE);
464 ji = g_new0 (MonoJitInfo, 1);
466 ji->code_start = code;
467 ji->code_size = buf - code;
469 mono_jit_stats.method_trampolines++;
474 /*========================= End of Function ========================*/
476 /*------------------------------------------------------------------*/
478 /* Name - mono_arch_create_jit_trampoline */
480 /* Function - Creates a trampoline function for virtual methods.*/
481 /* If the created code is called it first starts JIT */
482 /* compilation and then calls the newly created */
483 /* method. It also replaces the corresponding vtable */
484 /* entry (see s390_magic_trampoline). */
486 /* A trampoline consists of two parts: a main */
487 /* fragment, shared by all method trampolines, and */
488 /* and some code specific to each method, which */
489 /* hard-codes a reference to that method and then */
490 /* calls the main fragment. */
492 /* The main fragment contains a call to */
493 /* 's390_magic_trampoline', which performs a call */
494 /* to the JIT compiler and substitutes the method- */
495 /* specific fragment with some code that directly */
496 /* calls the JIT-compiled method. */
498 /* Parameter - method - Pointer to the method information */
500 /* Returns - A pointer to the newly created code */
502 /*------------------------------------------------------------------*/
505 mono_arch_create_jit_trampoline (MonoMethod *method)
508 static guint8 *vc = NULL;
511 vc = mono_get_trampoline_code (MONO_TRAMPOLINE_GENERIC);
513 /* This is the method-specific part of the trampoline. Its purpose is
514 to provide the generic part with the MonoMethod *method pointer. We'll
515 use r13 to keep that value, for instance. However, the generic part of
516 the trampoline relies on r11 having the same value it had before coming
517 here, so we must save it before. */
518 code = buf = mono_global_codeman_reserve(METHOD_TRAMPOLINE_SIZE);
520 s390_basr (buf, s390_r13, 0);
522 s390_word (buf, method);
523 s390_l (buf, s390_r13, 0, s390_r13, 4);
524 displace = (vc - buf) / 2;
525 s390_jcl (buf, S390_CC_UN, displace);
527 /* Flush instruction cache, since we've generated code */
528 mono_arch_flush_icache (code, buf - code);
531 g_assert ((buf - code) <= METHOD_TRAMPOLINE_SIZE);
536 /*========================= End of Function ========================*/
538 /*------------------------------------------------------------------*/
540 /* Name - mono_arch_create_class_init_trampoline */
542 /* Function - Creates a trampoline function to run a type init- */
543 /* ializer. If the trampoline is called, it calls */
544 /* mono_runtime_class_init with the given vtable, */
545 /* then patches the caller code so it does not get */
546 /* called any more. */
548 /* Parameter - vtable - The type to initialize */
550 /* Returns - A pointer to the newly created code */
552 /*------------------------------------------------------------------*/
555 mono_arch_create_class_init_trampoline (MonoVTable *vtable)
557 guint8 *code, *buf, *tramp;
559 tramp = mono_get_trampoline_code (MONO_TRAMPOLINE_CLASS_INIT);
561 /*-----------------------------------------------------------*/
562 /* This is the method-specific part of the trampoline. Its */
563 /* purpose is to provide the generic part with the MonoMethod*/
564 /* *method pointer. We'll use r11 to keep that value, for */
565 /* instance. However, the generic part of the trampoline */
566 /* relies on r11 having the same value it had before coming */
567 /* here, so we must save it before. */
568 /*-----------------------------------------------------------*/
569 code = buf = mono_global_codeman_reserve(METHOD_TRAMPOLINE_SIZE);
571 s390_st (buf, s390_r14, 0, STK_BASE, S390_RET_ADDR_OFFSET);
572 s390_ahi (buf, STK_BASE, -S390_MINIMAL_STACK_SIZE);
574 s390_basr (buf, s390_r1, 0);
576 s390_word (buf, vtable);
577 s390_word (buf, s390_class_init_trampoline);
578 s390_lr (buf, s390_r3, s390_r14);
579 s390_l (buf, s390_r2, 0, s390_r1, 4);
580 s390_lhi (buf, s390_r4, 0);
581 s390_l (buf, s390_r1, 0, s390_r1, 8);
582 s390_basr (buf, s390_r14, s390_r1);
584 s390_ahi (buf, STK_BASE, S390_MINIMAL_STACK_SIZE);
585 s390_l (buf, s390_r14, 0, STK_BASE, S390_RET_ADDR_OFFSET);
586 s390_br (buf, s390_r14);
588 /* Flush instruction cache, since we've generated code */
589 mono_arch_flush_icache (code, buf - code);
592 g_assert ((buf - code) <= METHOD_TRAMPOLINE_SIZE);
594 mono_jit_stats.method_trampolines++;
599 /*========================= End of Function ========================*/
601 /*------------------------------------------------------------------*/
603 /* Name - mono_debuger_create_notification_function */
605 /* Function - This method is only called when running in the */
606 /* Mono debugger. It returns a pointer to the */
607 /* arch specific notification function. */
609 /*------------------------------------------------------------------*/
612 mono_debugger_create_notification_function (gpointer *notification_address)
616 ptr = buf = mono_global_codeman_reserve (16);
618 if (notification_address)
619 *notification_address = buf;
620 s390_br (buf, s390_r14);
625 /*========================= End of Function ========================*/