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_STACK_SIZE (S390_MINIMAL_STACK_SIZE+GR_SAVE_SIZE+FP_SAVE_SIZE+2*sizeof(long))
26 #define CREATE_GR_OFFSET S390_MINIMAL_STACK_SIZE
27 #define CREATE_FP_OFFSET CREATE_GR_OFFSET+GR_SAVE_SIZE
28 #define CREATE_LMF_OFFSET CREATE_FP_OFFSET+FP_SAVE_SIZE
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;
173 addr = mono_compile_method(method);
179 /* The top bit needs to be ignored on S/390 */
180 (guint32) code &= 0x7fffffff;
182 fname = mono_method_full_name (method, TRUE);
184 opcode = *((unsigned short *) (code - 6));
187 /* This is a bras r14,r1 instruction */
190 displace = *((short *)code) & 0x0fff;
192 base = *((int *) (sp + S390_REG_SAVE_OFFSET+
193 sizeof(int)*(reg-6)));
195 base = *((int *) (sp + CREATE_GR_OFFSET+
196 sizeof(int)*(reg-2)));
197 addr = get_unbox_trampoline(method, addr);
198 code = base + displace;
199 s390_patch(code, addr);
202 /* This is the 'brasl' instruction */
204 displace = ((gint32) addr - (gint32) (code - 2)) / 2;
205 s390_patch (code, displace);
206 mono_arch_flush_icache (code, 4);
209 g_error("Unable to patch instruction prior to %p",code);
217 /*========================= End of Function ========================*/
219 /*------------------------------------------------------------------*/
221 /* Name - s390_class_init_trampoline */
223 /* Function - Initialize a class and then no-op the call to */
224 /* the trampoline. */
226 /*------------------------------------------------------------------*/
229 s390_class_init_trampoline (void *vtable, guchar *code, char *sp)
231 char patch[6] = {0x47, 0x00, 0x00, 0x00, 0x07, 0x00};
233 mono_runtime_class_init (vtable);
237 memcpy(code, patch, sizeof(patch));
240 /*========================= End of Function ========================*/
242 /*------------------------------------------------------------------*/
244 /* Name - create_trampoline_code */
246 /* Function - Create the designated type of trampoline according*/
247 /* to the 'tramp_type' parameter. */
249 /*------------------------------------------------------------------*/
252 create_trampoline_code (MonoTrampolineType tramp_type)
255 guint8 *buf, *code = NULL;
256 static guint8* generic_jump_trampoline = NULL;
257 static guint8 *generic_class_init_trampoline = NULL;
260 switch (tramp_type) {
261 case MONO_TRAMPOLINE_GENERIC:
262 if (mono_generic_trampoline_code)
263 return mono_generic_trampoline_code;
265 case MONO_TRAMPOLINE_JUMP:
266 if (generic_jump_trampoline)
267 return generic_jump_trampoline;
269 case MONO_TRAMPOLINE_CLASS_INIT:
270 if (generic_class_init_trampoline)
271 return generic_class_init_trampoline;
276 /* Now we'll create in 'buf' the S/390 trampoline code. This
277 is the trampoline code common to all methods */
279 code = buf = g_malloc(512);
281 /*-----------------------------------------------------------
282 STEP 0: First create a non-standard function prologue with a
283 stack size big enough to save our registers.
284 -----------------------------------------------------------*/
286 s390_stm (buf, s390_r6, s390_r14, STK_BASE, S390_REG_SAVE_OFFSET);
287 s390_lr (buf, s390_r11, s390_r15);
288 s390_ahi (buf, STK_BASE, -CREATE_STACK_SIZE);
289 s390_st (buf, s390_r11, 0, STK_BASE, 0);
290 s390_stm (buf, s390_r2, s390_r5, STK_BASE, CREATE_GR_OFFSET);
292 /* Save the FP registers */
293 offset = CREATE_FP_OFFSET;
294 for (i = s390_f0; i <= s390_f15; ++i) {
295 s390_std (buf, i, 0, STK_BASE, offset);
299 /*----------------------------------------------------------
300 STEP 1: call 'mono_get_lmf_addr()' to get the address of our
301 LMF. We'll need to restore it after the call to
302 's390_magic_trampoline' and before the call to the native
304 ----------------------------------------------------------*/
306 s390_basr (buf, s390_r13, 0);
308 s390_word (buf, mono_get_lmf_addr);
309 s390_l (buf, s390_r1, 0, s390_r13, 4);
310 s390_basr (buf, s390_r14, s390_r1);
312 /* XXX Update LMF !!! */
314 /*----------------------------------------------------------
315 STEP 2: call 's390_magic_trampoline()', who will compile the
316 code and fix the method vtable entry for us
317 ----------------------------------------------------------*/
321 /* Arg 1: MonoMethod *method. It was put in r11 by the
322 method-specific trampoline code, and then saved before the call
323 to mono_get_lmf_addr()'. Restore r13, by the way :-) */
324 s390_l (buf, s390_r2, 0, s390_r11, METHOD_SAVE_OFFSET);
326 /* Arg 2: code (next address to the instruction that called us) */
327 if (tramp_type == MONO_TRAMPOLINE_JUMP) {
328 s390_lhi (buf, s390_r3, 0);
330 s390_l (buf, s390_r3, 0, s390_r11, S390_RET_ADDR_OFFSET);
333 /* Arg 3: stack pointer */
334 s390_lr (buf, s390_r4, STK_BASE);
336 /* Calculate call address and call
337 's390_magic_trampoline'. Return value will be in r2 */
338 s390_basr (buf, s390_r13, 0);
340 if (tramp_type == MONO_TRAMPOLINE_CLASS_INIT) {
341 s390_word (buf, s390_class_init_trampoline);
343 s390_word (buf, s390_magic_trampoline);
345 s390_l (buf, s390_r1, 0, s390_r13, 4);
346 s390_basr (buf, s390_r14, s390_r1);
348 /* OK, code address is now on r2. Move it to r1, so that we
349 can restore r2 and use it from r1 later */
350 s390_lr (buf, s390_r1, s390_r2);
353 /*----------------------------------------------------------
354 STEP 3: Restore the LMF
355 ----------------------------------------------------------*/
359 /*----------------------------------------------------------
360 STEP 4: call the compiled method
361 ----------------------------------------------------------*/
363 /* Restore registers */
365 s390_lm (buf, s390_r2, s390_r5, STK_BASE, CREATE_GR_OFFSET);
367 /* Restore the FP registers */
368 offset = CREATE_FP_OFFSET;
369 for (i = s390_f0; i <= s390_f15; ++i) {
370 s390_ld (buf, i, 0, STK_BASE, offset);
374 /* Restore stack pointer and jump to the code -
375 R14 contains the return address to our caller */
376 s390_lr (buf, STK_BASE, s390_r11);
377 s390_lm (buf, s390_r6, s390_r14, STK_BASE, S390_REG_SAVE_OFFSET);
378 s390_br (buf, s390_r1);
380 /* Flush instruction cache, since we've generated code */
381 mono_arch_flush_icache (code, buf - code);
384 g_assert ((buf - code) <= 512);
387 switch (tramp_type) {
388 case MONO_TRAMPOLINE_GENERIC:
389 mono_generic_trampoline_code = code;
391 case MONO_TRAMPOLINE_JUMP:
392 generic_jump_trampoline = code;
394 case MONO_TRAMPOLINE_CLASS_INIT:
395 generic_class_init_trampoline = code;
402 /*========================= End of Function ========================*/
404 /*------------------------------------------------------------------*/
406 /* Name - mono_arch_create_jump_trampoline */
408 /* Function - Create the designated type of trampoline according*/
409 /* to the 'tramp_type' parameter. */
411 /*------------------------------------------------------------------*/
414 mono_arch_create_jump_trampoline (MonoMethod *method)
416 guint8 *code, *buf, *tramp = NULL;
418 MonoDomain *domain = mono_domain_get();
421 tramp = create_trampoline_code (MONO_TRAMPOLINE_JUMP);
423 mono_domain_lock (domain);
424 code = buf = mono_code_manager_reserve (domain->code_mp, METHOD_TRAMPOLINE_SIZE);
425 mono_domain_unlock (domain);
427 s390_basr (buf, s390_r13, 0);
429 s390_word (buf, method);
430 s390_l (buf, s390_r13, 0, s390_r13, 4);
431 displace = (tramp - buf) / 2;
432 s390_jcl (buf, S390_CC_UN, displace);
434 mono_arch_flush_icache (code, buf-code);
436 g_assert ((buf - code) <= JUMP_TRAMPOLINE_SIZE);
438 ji = g_new0 (MonoJitInfo, 1);
440 ji->code_start = code;
441 ji->code_size = buf - code;
443 mono_jit_stats.method_trampolines++;
448 /*========================= End of Function ========================*/
450 /*------------------------------------------------------------------*/
452 /* Name - mono_arch_create_jit_trampoline */
454 /* Function - Creates a trampoline function for virtual methods.*/
455 /* If the created code is called it first starts JIT */
456 /* compilation and then calls the newly created */
457 /* method. It also replaces the corresponding vtable */
458 /* entry (see s390_magic_trampoline). */
460 /* A trampoline consists of two parts: a main */
461 /* fragment, shared by all method trampolines, and */
462 /* and some code specific to each method, which */
463 /* hard-codes a reference to that method and then */
464 /* calls the main fragment. */
466 /* The main fragment contains a call to */
467 /* 's390_magic_trampoline', which performs a call */
468 /* to the JIT compiler and substitutes the method- */
469 /* specific fragment with some code that directly */
470 /* calls the JIT-compiled method. */
472 /* Parameter - method - Pointer to the method information */
474 /* Returns - A pointer to the newly created code */
476 /*------------------------------------------------------------------*/
479 mono_arch_create_jit_trampoline (MonoMethod *method)
482 static guint8 *vc = NULL;
485 /* previously created trampoline code */
489 if (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
490 return mono_arch_create_jit_trampoline (mono_marshal_get_synchronized_wrapper (method));
492 vc = create_trampoline_code (MONO_TRAMPOLINE_GENERIC);
494 /* This is the method-specific part of the trampoline. Its purpose is
495 to provide the generic part with the MonoMethod *method pointer. We'll
496 use r13 to keep that value, for instance. However, the generic part of
497 the trampoline relies on r11 having the same value it had before coming
498 here, so we must save it before. */
499 code = buf = g_malloc(METHOD_TRAMPOLINE_SIZE);
501 s390_basr (buf, s390_r13, 0);
503 s390_word (buf, method);
504 s390_l (buf, s390_r13, 0, s390_r13, 4);
505 displace = (vc - buf) / 2;
506 s390_jcl (buf, S390_CC_UN, displace);
508 /* Flush instruction cache, since we've generated code */
509 mono_arch_flush_icache (code, buf - code);
512 g_assert ((buf - code) <= METHOD_TRAMPOLINE_SIZE);
514 /* Store trampoline address */
517 mono_jit_stats.method_trampolines++;
522 /*========================= End of Function ========================*/
524 /*------------------------------------------------------------------*/
526 /* Name - mono_arch_create_class_init_trampoline */
528 /* Function - Creates a trampoline function to run a type init- */
529 /* ializer. If the trampoline is called, it calls */
530 /* mono_runtime_class_init with the given vtable, */
531 /* then patches the caller code so it does not get */
532 /* called any more. */
534 /* Parameter - vtable - The type to initialize */
536 /* Returns - A pointer to the newly created code */
538 /*------------------------------------------------------------------*/
541 mono_arch_create_class_init_trampoline (MonoVTable *vtable)
543 guint8 *code, *buf, *tramp;
545 tramp = create_trampoline_code (MONO_TRAMPOLINE_CLASS_INIT);
547 /* This is the method-specific part of the trampoline. Its purpose is
548 to provide the generic part with the MonoMethod *method pointer. We'll
549 use r11 to keep that value, for instance. However, the generic part of
550 the trampoline relies on r11 having the same value it had before coming
551 here, so we must save it before. */
552 code = buf = g_malloc(METHOD_TRAMPOLINE_SIZE);
554 s390_st (buf, s390_r14, 0, STK_BASE, S390_RET_ADDR_OFFSET);
555 s390_ahi (buf, STK_BASE, -S390_MINIMAL_STACK_SIZE);
557 s390_basr (buf, s390_r1, 0);
559 s390_word (buf, vtable);
560 s390_word (buf, s390_class_init_trampoline);
561 s390_lr (buf, s390_r3, s390_r14);
562 s390_l (buf, s390_r2, 0, s390_r1, 4);
563 s390_lhi (buf, s390_r4, 0);
564 s390_l (buf, s390_r1, 0, s390_r1, 8);
565 s390_basr (buf, s390_r14, s390_r1);
567 s390_ahi (buf, STK_BASE, S390_MINIMAL_STACK_SIZE);
568 s390_l (buf, s390_r14, 0, STK_BASE, S390_RET_ADDR_OFFSET);
569 s390_br (buf, s390_r14);
571 /* Flush instruction cache, since we've generated code */
572 mono_arch_flush_icache (code, buf - code);
575 g_assert ((buf - code) <= METHOD_TRAMPOLINE_SIZE);
577 mono_jit_stats.method_trampolines++;
582 /*========================= End of Function ========================*/
584 /*------------------------------------------------------------------*/
586 /* Name - mono_debuger_create_notification_function */
588 /* Function - This method is only called when running in the */
589 /* Mono debugger. It returns a pointer to the */
590 /* arch specific notification function. */
592 /*------------------------------------------------------------------*/
595 mono_debugger_create_notification_function (gpointer *notification_address)
599 ptr = buf = g_malloc0 (16);
601 if (notification_address)
602 *notification_address = buf;
603 s390_br (buf, s390_r14);