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 ((method->klass->valuetype)) {
117 // if ((method->klass->valuetype) &&
118 // (method->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
119 if ((!method->signature->ret->byref) &&
120 (MONO_TYPE_ISSTRUCT (method->signature->ret)))
123 start = code = g_malloc (28);
125 s390_basr (code, s390_r13, 0);
127 s390_word (code, addr);
128 s390_l (code, s390_r1, 0, s390_r13, 4);
129 s390_ahi (code, this_pos, sizeof(MonoObject));
130 s390_br (code, s390_r1);
132 g_assert ((code - start) <= 28);
138 /*========================= End of Function ========================*/
140 /*------------------------------------------------------------------*/
142 /* Name - s390_magic_trampoline */
144 /* Function - This method is called by the function */
145 /* "arch_create_jit_trampoline", which in turn is */
146 /* called by the trampoline functions for virtual */
147 /* methods. After having called the JIT compiler to */
148 /* compile the method, it inspects the caller code */
149 /* to find the address of the method-specific part */
150 /* of the trampoline vtable slot for this method, */
151 /* updates it with a fragment that calls the newly */
152 /* compiled code and returns this address. The calls */
153 /* generated by mono for S/390 will look like either:*/
154 /* 1. l %r1,xxx(%rx) */
156 /* 2. brasl %r14,xxxxxx */
158 /* Parameters - code - Pointer into caller code */
159 /* method - The method to compile */
160 /* sp - Stack pointer */
162 /*------------------------------------------------------------------*/
165 s390_magic_trampoline (MonoMethod *method, guchar *code, char *sp)
170 unsigned short opcode;
175 addr = mono_compile_method(method);
181 /* The top bit needs to be ignored on S/390 */
182 (guint32) code &= 0x7fffffff;
184 fname = mono_method_full_name (method, TRUE);
185 codeJi = mono_jit_info_table_find (mono_domain_get(), code);
186 addrJi = mono_jit_info_table_find (mono_domain_get(), addr);
188 opcode = *((unsigned short *) (code - 6));
191 /* This is a bras r14,r1 instruction */
194 displace = *((short *)code) & 0x0fff;
196 base = *((int *) (sp + S390_REG_SAVE_OFFSET+
197 sizeof(int)*(reg-6)));
199 base = *((int *) (sp + CREATE_GR_OFFSET+
200 sizeof(int)*(reg-2)));
201 addr = get_unbox_trampoline(method, addr);
202 if (mono_method_same_domain (codeJi, addrJi)) {
203 code = base + displace;
204 s390_patch(code, addr);
208 /* This is the 'brasl' instruction */
210 displace = ((gint32) addr - (gint32) (code - 2)) / 2;
211 if (mono_method_same_domain (codeJi, addrJi)) {
212 s390_patch (code, displace);
213 mono_arch_flush_icache (code, 4);
217 g_error("Unable to patch instruction prior to %p",code);
225 /*========================= End of Function ========================*/
227 /*------------------------------------------------------------------*/
229 /* Name - s390_class_init_trampoline */
231 /* Function - Initialize a class and then no-op the call to */
232 /* the trampoline. */
234 /*------------------------------------------------------------------*/
237 s390_class_init_trampoline (void *vtable, guchar *code, char *sp)
239 char patch[6] = {0x47, 0x00, 0x00, 0x00, 0x07, 0x00};
241 mono_runtime_class_init (vtable);
245 memcpy(code, patch, sizeof(patch));
248 /*========================= End of Function ========================*/
250 /*------------------------------------------------------------------*/
252 /* Name - create_trampoline_code */
254 /* Function - Create the designated type of trampoline according*/
255 /* to the 'tramp_type' parameter. */
257 /*------------------------------------------------------------------*/
260 create_trampoline_code (MonoTrampolineType tramp_type)
263 guint8 *buf, *code = NULL;
264 static guint8* generic_jump_trampoline = NULL;
265 static guint8 *generic_class_init_trampoline = NULL;
266 int i, offset, lmfOffset;
268 switch (tramp_type) {
269 case MONO_TRAMPOLINE_GENERIC:
270 if (mono_generic_trampoline_code)
271 return mono_generic_trampoline_code;
273 case MONO_TRAMPOLINE_JUMP:
274 if (generic_jump_trampoline)
275 return generic_jump_trampoline;
277 case MONO_TRAMPOLINE_CLASS_INIT:
278 if (generic_class_init_trampoline)
279 return generic_class_init_trampoline;
284 /* Now we'll create in 'buf' the S/390 trampoline code. This
285 is the trampoline code common to all methods */
287 code = buf = g_malloc(512);
289 /*-----------------------------------------------------------
290 STEP 0: First create a non-standard function prologue with a
291 stack size big enough to save our registers.
292 -----------------------------------------------------------*/
294 s390_stm (buf, s390_r6, s390_r14, STK_BASE, S390_REG_SAVE_OFFSET);
295 s390_lr (buf, s390_r11, s390_r15);
296 s390_ahi (buf, STK_BASE, -CREATE_STACK_SIZE);
297 s390_st (buf, s390_r11, 0, STK_BASE, 0);
298 s390_stm (buf, s390_r2, s390_r5, STK_BASE, CREATE_GR_OFFSET);
300 /* Save the FP registers */
301 offset = CREATE_FP_OFFSET;
302 for (i = s390_f0; i <= s390_f15; ++i) {
303 s390_std (buf, i, 0, STK_BASE, offset);
307 /*----------------------------------------------------------
308 STEP 1: call 'mono_get_lmf_addr()' to get the address of our
309 LMF. We'll need to restore it after the call to
310 's390_magic_trampoline' and before the call to the native
312 ----------------------------------------------------------*/
314 s390_basr (buf, s390_r13, 0);
316 s390_word (buf, mono_get_lmf_addr);
317 s390_l (buf, s390_r1, 0, s390_r13, 4);
318 s390_basr (buf, s390_r14, s390_r1);
320 /*---------------------------------------------------------------*/
321 /* we build the MonoLMF structure on the stack - see mini-s390.h */
322 /* Keep in sync with the code in mono_arch_emit_prolog */
323 /*---------------------------------------------------------------*/
324 lmfOffset = CREATE_STACK_SIZE - sizeof(MonoLMF);
326 s390_lr (buf, s390_r13, STK_BASE);
327 s390_ahi (buf, s390_r13, lmfOffset);
329 /*---------------------------------------------------------------*/
330 /* Set lmf.lmf_addr = jit_tls->lmf */
331 /*---------------------------------------------------------------*/
332 s390_st (buf, s390_r2, 0, s390_r13,
333 G_STRUCT_OFFSET(MonoLMF, lmf_addr));
335 /*---------------------------------------------------------------*/
336 /* Get current lmf */
337 /*---------------------------------------------------------------*/
338 s390_l (buf, s390_r0, 0, s390_r2, 0);
340 /*---------------------------------------------------------------*/
341 /* Set our lmf as the current lmf */
342 /*---------------------------------------------------------------*/
343 s390_st (buf, s390_r13, 0, s390_r2, 0);
345 /*---------------------------------------------------------------*/
346 /* Have our lmf.previous_lmf point to the last lmf */
347 /*---------------------------------------------------------------*/
348 s390_st (buf, s390_r0, 0, s390_r13,
349 G_STRUCT_OFFSET(MonoLMF, previous_lmf));
351 /*---------------------------------------------------------------*/
352 /* save method info */
353 /*---------------------------------------------------------------*/
354 s390_l (buf, s390_r1, 0, s390_r11, METHOD_SAVE_OFFSET);
355 s390_st (buf, s390_r1, 0, s390_r13,
356 G_STRUCT_OFFSET(MonoLMF, method));
358 /*---------------------------------------------------------------*/
359 /* save the current IP */
360 /*---------------------------------------------------------------*/
361 s390_l (buf, s390_r1, 0, STK_BASE, 0);
362 s390_st (buf, s390_r1, 0, s390_r13, G_STRUCT_OFFSET(MonoLMF, ebp));
363 if (tramp_type == MONO_TRAMPOLINE_JUMP) {
364 s390_lhi (buf, s390_r1, 0);
366 s390_l (buf, s390_r1, 0, s390_r1, S390_RET_ADDR_OFFSET);
367 s390_la (buf, s390_r1, 0, s390_r1, 0);
369 s390_st (buf, s390_r1, 0, s390_r13, G_STRUCT_OFFSET(MonoLMF, eip));
371 /*---------------------------------------------------------------*/
372 /* Save general and floating point registers */
373 /*---------------------------------------------------------------*/
374 s390_stm (buf, s390_r2, s390_r12, s390_r13,
375 G_STRUCT_OFFSET(MonoLMF, gregs[2]));
376 for (i = 0; i < 16; i++) {
377 s390_std (buf, i, 0, s390_r13,
378 G_STRUCT_OFFSET(MonoLMF, fregs[i]));
381 /*---------------------------------------------------------------*/
382 /* STEP 2: call 's390_magic_trampoline()', who will compile the */
383 /* code and fix the method vtable entry for us */
384 /*---------------------------------------------------------------*/
388 /* Arg 1: MonoMethod *method. It was put in r11 by the
389 method-specific trampoline code, and then saved before the call
390 to mono_get_lmf_addr()'. Restore r13, by the way :-) */
391 s390_l (buf, s390_r2, 0, s390_r11, METHOD_SAVE_OFFSET);
393 /* Arg 2: code (next address to the instruction that called us) */
394 if (tramp_type == MONO_TRAMPOLINE_JUMP) {
395 s390_lhi (buf, s390_r3, 0);
397 s390_l (buf, s390_r3, 0, s390_r11, S390_RET_ADDR_OFFSET);
400 /* Arg 3: stack pointer */
401 s390_lr (buf, s390_r4, STK_BASE);
403 /* Calculate call address and call
404 's390_magic_trampoline'. Return value will be in r2 */
405 s390_basr (buf, s390_r13, 0);
407 if (tramp_type == MONO_TRAMPOLINE_CLASS_INIT) {
408 s390_word (buf, s390_class_init_trampoline);
410 s390_word (buf, s390_magic_trampoline);
412 s390_l (buf, s390_r1, 0, s390_r13, 4);
413 s390_basr (buf, s390_r14, s390_r1);
415 /* OK, code address is now on r2. Move it to r1, so that we
416 can restore r2 and use it from r1 later */
417 s390_lr (buf, s390_r1, s390_r2);
419 /*----------------------------------------------------------
420 STEP 3: Restore the LMF
421 ----------------------------------------------------------*/
422 restoreLMF(buf, STK_BASE, CREATE_STACK_SIZE);
424 /*----------------------------------------------------------
425 STEP 4: call the compiled method
426 ----------------------------------------------------------*/
428 /* Restore registers */
430 s390_lm (buf, s390_r2, s390_r5, STK_BASE, CREATE_GR_OFFSET);
432 /* Restore the FP registers */
433 offset = CREATE_FP_OFFSET;
434 for (i = s390_f0; i <= s390_f15; ++i) {
435 s390_ld (buf, i, 0, STK_BASE, offset);
439 /* Restore stack pointer and jump to the code -
440 R14 contains the return address to our caller */
441 s390_lr (buf, STK_BASE, s390_r11);
442 s390_lm (buf, s390_r6, s390_r14, STK_BASE, S390_REG_SAVE_OFFSET);
443 s390_br (buf, s390_r1);
445 /* Flush instruction cache, since we've generated code */
446 mono_arch_flush_icache (code, buf - code);
449 g_assert ((buf - code) <= 512);
452 switch (tramp_type) {
453 case MONO_TRAMPOLINE_GENERIC:
454 mono_generic_trampoline_code = code;
456 case MONO_TRAMPOLINE_JUMP:
457 generic_jump_trampoline = code;
459 case MONO_TRAMPOLINE_CLASS_INIT:
460 generic_class_init_trampoline = code;
467 /*========================= End of Function ========================*/
469 /*------------------------------------------------------------------*/
471 /* Name - mono_arch_create_jump_trampoline */
473 /* Function - Create the designated type of trampoline according*/
474 /* to the 'tramp_type' parameter. */
476 /*------------------------------------------------------------------*/
479 mono_arch_create_jump_trampoline (MonoMethod *method)
481 guint8 *code, *buf, *tramp = NULL;
483 MonoDomain *domain = mono_domain_get();
486 tramp = create_trampoline_code (MONO_TRAMPOLINE_JUMP);
488 mono_domain_lock (domain);
489 code = buf = mono_code_manager_reserve (domain->code_mp, METHOD_TRAMPOLINE_SIZE);
490 mono_domain_unlock (domain);
492 s390_basr (buf, s390_r13, 0);
494 s390_word (buf, method);
495 s390_l (buf, s390_r13, 0, s390_r13, 4);
496 displace = (tramp - buf) / 2;
497 s390_jcl (buf, S390_CC_UN, displace);
499 mono_arch_flush_icache (code, buf-code);
501 g_assert ((buf - code) <= JUMP_TRAMPOLINE_SIZE);
503 ji = g_new0 (MonoJitInfo, 1);
505 ji->code_start = code;
506 ji->code_size = buf - code;
508 mono_jit_stats.method_trampolines++;
513 /*========================= End of Function ========================*/
515 /*------------------------------------------------------------------*/
517 /* Name - mono_arch_create_jit_trampoline */
519 /* Function - Creates a trampoline function for virtual methods.*/
520 /* If the created code is called it first starts JIT */
521 /* compilation and then calls the newly created */
522 /* method. It also replaces the corresponding vtable */
523 /* entry (see s390_magic_trampoline). */
525 /* A trampoline consists of two parts: a main */
526 /* fragment, shared by all method trampolines, and */
527 /* and some code specific to each method, which */
528 /* hard-codes a reference to that method and then */
529 /* calls the main fragment. */
531 /* The main fragment contains a call to */
532 /* 's390_magic_trampoline', which performs a call */
533 /* to the JIT compiler and substitutes the method- */
534 /* specific fragment with some code that directly */
535 /* calls the JIT-compiled method. */
537 /* Parameter - method - Pointer to the method information */
539 /* Returns - A pointer to the newly created code */
541 /*------------------------------------------------------------------*/
544 mono_arch_create_jit_trampoline (MonoMethod *method)
547 static guint8 *vc = NULL;
550 vc = create_trampoline_code (MONO_TRAMPOLINE_GENERIC);
552 /* This is the method-specific part of the trampoline. Its purpose is
553 to provide the generic part with the MonoMethod *method pointer. We'll
554 use r13 to keep that value, for instance. However, the generic part of
555 the trampoline relies on r11 having the same value it had before coming
556 here, so we must save it before. */
557 code = buf = g_malloc(METHOD_TRAMPOLINE_SIZE);
559 s390_basr (buf, s390_r13, 0);
561 s390_word (buf, method);
562 s390_l (buf, s390_r13, 0, s390_r13, 4);
563 displace = (vc - buf) / 2;
564 s390_jcl (buf, S390_CC_UN, displace);
566 /* Flush instruction cache, since we've generated code */
567 mono_arch_flush_icache (code, buf - code);
570 g_assert ((buf - code) <= METHOD_TRAMPOLINE_SIZE);
572 mono_jit_stats.method_trampolines++;
577 /*========================= End of Function ========================*/
579 /*------------------------------------------------------------------*/
581 /* Name - mono_arch_create_class_init_trampoline */
583 /* Function - Creates a trampoline function to run a type init- */
584 /* ializer. If the trampoline is called, it calls */
585 /* mono_runtime_class_init with the given vtable, */
586 /* then patches the caller code so it does not get */
587 /* called any more. */
589 /* Parameter - vtable - The type to initialize */
591 /* Returns - A pointer to the newly created code */
593 /*------------------------------------------------------------------*/
596 mono_arch_create_class_init_trampoline (MonoVTable *vtable)
598 guint8 *code, *buf, *tramp;
600 tramp = create_trampoline_code (MONO_TRAMPOLINE_CLASS_INIT);
602 /* This is the method-specific part of the trampoline. Its purpose is
603 to provide the generic part with the MonoMethod *method pointer. We'll
604 use r11 to keep that value, for instance. However, the generic part of
605 the trampoline relies on r11 having the same value it had before coming
606 here, so we must save it before. */
607 code = buf = g_malloc(METHOD_TRAMPOLINE_SIZE);
609 s390_st (buf, s390_r14, 0, STK_BASE, S390_RET_ADDR_OFFSET);
610 s390_ahi (buf, STK_BASE, -S390_MINIMAL_STACK_SIZE);
612 s390_basr (buf, s390_r1, 0);
614 s390_word (buf, vtable);
615 s390_word (buf, s390_class_init_trampoline);
616 s390_lr (buf, s390_r3, s390_r14);
617 s390_l (buf, s390_r2, 0, s390_r1, 4);
618 s390_lhi (buf, s390_r4, 0);
619 s390_l (buf, s390_r1, 0, s390_r1, 8);
620 s390_basr (buf, s390_r14, s390_r1);
622 s390_ahi (buf, STK_BASE, S390_MINIMAL_STACK_SIZE);
623 s390_l (buf, s390_r14, 0, STK_BASE, S390_RET_ADDR_OFFSET);
624 s390_br (buf, s390_r14);
626 /* Flush instruction cache, since we've generated code */
627 mono_arch_flush_icache (code, buf - code);
630 g_assert ((buf - code) <= METHOD_TRAMPOLINE_SIZE);
632 mono_jit_stats.method_trampolines++;
637 /*========================= End of Function ========================*/
639 /*------------------------------------------------------------------*/
641 /* Name - mono_debuger_create_notification_function */
643 /* Function - This method is only called when running in the */
644 /* Mono debugger. It returns a pointer to the */
645 /* arch specific notification function. */
647 /*------------------------------------------------------------------*/
650 mono_debugger_create_notification_function (gpointer *notification_address)
654 ptr = buf = g_malloc0 (16);
656 if (notification_address)
657 *notification_address = buf;
658 s390_br (buf, s390_r14);
663 /*========================= End of Function ========================*/