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-8
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/s390x/s390x-codegen.h>
56 #include <mono/metadata/mono-debug-debugger.h>
59 #include "mini-s390x.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->signature->ret->byref) &&
118 (MONO_TYPE_ISSTRUCT (method->signature->ret)))
121 start = code = g_malloc (28);
123 s390_basr (code, s390_r13, 0);
125 s390_llong(code, addr);
126 s390_lg (code, s390_r1, 0, s390_r13, 4);
127 s390_aghi (code, this_pos, sizeof(MonoObject));
128 s390_br (code, s390_r1);
130 g_assert ((code - start) <= 28);
136 /*========================= End of Function ========================*/
138 /*------------------------------------------------------------------*/
140 /* Name - s390_magic_trampoline */
142 /* Function - This method is called by the function */
143 /* "arch_create_jit_trampoline", which in turn is */
144 /* called by the trampoline functions for virtual */
145 /* methods. After having called the JIT compiler to */
146 /* compile the method, it inspects the caller code */
147 /* to find the address of the method-specific part */
148 /* of the trampoline vtable slot for this method, */
149 /* updates it with a fragment that calls the newly */
150 /* compiled code and returns this address. The calls */
151 /* generated by mono for S/390 will look like either:*/
152 /* 1. l %r1,xxx(%rx) */
154 /* 2. brasl %r14,xxxxxx */
156 /* Parameters - code - Pointer into caller code */
157 /* method - The method to compile */
158 /* sp - Stack pointer */
160 /*------------------------------------------------------------------*/
163 s390_magic_trampoline (MonoMethod *method, guchar *code, char *sp)
169 unsigned short opcode;
172 addr = mono_compile_method(method);
177 fname = mono_method_full_name (method, TRUE);
179 opcode = *((unsigned short *) (code - 6));
180 if (opcode == 0xc0e5) {
181 /* This is the 'brasl' instruction */
183 displace = ((gint64) addr - (gint64) (code - 2)) / 2;
184 s390_patch (code, displace);
185 mono_arch_flush_icache (code, 4);
187 /* This is a bras rx,r1 instruction */
190 displace = ((*(char *)(code+2) << 8) |
191 (*((short *)code) & 0x0fff));
193 base = *((gint64 *) (sp + S390_REG_SAVE_OFFSET+
194 sizeof(gint64)*(reg-6)));
196 base = *((gint64 *) (sp + CREATE_GR_OFFSET+
197 sizeof(gint64)*(reg-2)));
198 addr = get_unbox_trampoline(method, addr);
199 code = base + displace;
200 *((guint64 *) (code)) = addr;
208 /*========================= End of Function ========================*/
210 /*------------------------------------------------------------------*/
212 /* Name - s390_class_init_trampoline */
214 /* Function - Initialize a class and then no-op the call to */
215 /* the trampoline. */
217 /*------------------------------------------------------------------*/
220 s390_class_init_trampoline (void *vtable, guchar *code, char *sp)
222 char patch[6] = {0x47, 0x00, 0x00, 0x00, 0x07, 0x00};
224 mono_runtime_class_init (vtable);
228 memcpy(code, patch, sizeof(patch));
231 /*========================= End of Function ========================*/
233 /*------------------------------------------------------------------*/
235 /* Name - create_trampoline_code */
237 /* Function - Create the designated type of trampoline according*/
238 /* to the 'tramp_type' parameter. */
240 /*------------------------------------------------------------------*/
243 create_trampoline_code (MonoTrampolineType tramp_type)
246 guint8 *buf, *code = NULL;
247 static guint8* generic_jump_trampoline = NULL;
248 static guint8 *generic_class_init_trampoline = NULL;
251 switch (tramp_type) {
252 case MONO_TRAMPOLINE_GENERIC:
253 if (mono_generic_trampoline_code)
254 return mono_generic_trampoline_code;
256 case MONO_TRAMPOLINE_JUMP:
257 if (generic_jump_trampoline)
258 return generic_jump_trampoline;
260 case MONO_TRAMPOLINE_CLASS_INIT:
261 if (generic_class_init_trampoline)
262 return generic_class_init_trampoline;
267 /* Now we'll create in 'buf' the S/390 trampoline code. This
268 is the trampoline code common to all methods */
270 code = buf = g_malloc(512);
272 /*-----------------------------------------------------------
273 STEP 0: First create a non-standard function prologue with a
274 stack size big enough to save our registers.
275 -----------------------------------------------------------*/
277 s390_stmg (buf, s390_r6, s390_r14, STK_BASE, S390_REG_SAVE_OFFSET);
278 s390_lgr (buf, s390_r11, s390_r15);
279 s390_aghi (buf, STK_BASE, -CREATE_STACK_SIZE);
280 s390_stg (buf, s390_r11, 0, STK_BASE, 0);
281 s390_stmg (buf, s390_r2, s390_r5, STK_BASE, CREATE_GR_OFFSET);
283 /* Save the FP registers */
284 offset = CREATE_FP_OFFSET;
285 for (i = s390_f0; i <= s390_f15; ++i) {
286 s390_std (buf, i, 0, STK_BASE, offset);
290 /*----------------------------------------------------------
291 STEP 1: call 'mono_get_lmf_addr()' to get the address of our
292 LMF. We'll need to restore it after the call to
293 's390_magic_trampoline' and before the call to the native
295 ----------------------------------------------------------*/
297 s390_basr (buf, s390_r13, 0);
299 s390_llong(buf, mono_get_lmf_addr);
300 s390_lg (buf, s390_r1, 0, s390_r13, 4);
301 s390_basr (buf, s390_r14, s390_r1);
303 /*----------------------------------------------------------
304 STEP 2: call 's390_magic_trampoline()', who will compile the
305 code and fix the method vtable entry for us
306 ----------------------------------------------------------*/
310 /* Arg 1: MonoMethod *method. It was put in r11 by the
311 method-specific trampoline code, and then saved before the call
312 to mono_get_lmf_addr()'. Restore r13, by the way :-) */
313 s390_lg (buf, s390_r2, 0, s390_r11, METHOD_SAVE_OFFSET);
315 /* Arg 2: code (next address to the instruction that called us) */
316 if (tramp_type == MONO_TRAMPOLINE_JUMP) {
317 s390_lghi (buf, s390_r3, 0);
319 s390_lg (buf, s390_r3, 0, s390_r11, S390_RET_ADDR_OFFSET);
322 /* Arg 3: stack pointer */
323 s390_lgr (buf, s390_r4, STK_BASE);
325 /* Calculate call address and call
326 's390_magic_trampoline'. Return value will be in r2 */
327 s390_basr (buf, s390_r13, 0);
329 if (tramp_type == MONO_TRAMPOLINE_CLASS_INIT) {
330 s390_llong(buf, s390_class_init_trampoline);
332 s390_llong(buf, s390_magic_trampoline);
334 s390_lg (buf, s390_r1, 0, s390_r13, 4);
335 s390_basr (buf, s390_r14, s390_r1);
337 /* OK, code address is now on r2. Move it to r1, so that we
338 can restore r2 and use it from r1 later */
339 s390_lgr (buf, s390_r1, s390_r2);
342 /*----------------------------------------------------------
343 STEP 3: Restore the LMF
344 ----------------------------------------------------------*/
348 /*----------------------------------------------------------
349 STEP 4: call the compiled method
350 ----------------------------------------------------------*/
352 /* Restore registers */
354 s390_lmg (buf, s390_r2, s390_r5, STK_BASE, CREATE_GR_OFFSET);
356 /* Restore the FP registers */
357 offset = CREATE_FP_OFFSET;
358 for (i = s390_f0; i <= s390_f15; ++i) {
359 s390_ld (buf, i, 0, STK_BASE, offset);
363 /* Restore stack pointer and jump to the code -
364 R14 contains the return address to our caller */
365 s390_lgr (buf, STK_BASE, s390_r11);
366 s390_lmg (buf, s390_r6, s390_r14, STK_BASE, S390_REG_SAVE_OFFSET);
367 s390_br (buf, s390_r1);
369 /* Flush instruction cache, since we've generated code */
370 mono_arch_flush_icache (code, buf - code);
373 g_assert ((buf - code) <= 512);
376 switch (tramp_type) {
377 case MONO_TRAMPOLINE_GENERIC:
378 mono_generic_trampoline_code = code;
380 case MONO_TRAMPOLINE_JUMP:
381 generic_jump_trampoline = code;
383 case MONO_TRAMPOLINE_CLASS_INIT:
384 generic_class_init_trampoline = code;
391 /*========================= End of Function ========================*/
393 /*------------------------------------------------------------------*/
395 /* Name - mono_arch_create_jump_trampoline */
397 /* Function - Create the designated type of trampoline according*/
398 /* to the 'tramp_type' parameter. */
400 /*------------------------------------------------------------------*/
403 mono_arch_create_jump_trampoline (MonoMethod *method)
405 guint8 *code, *buf, *tramp = NULL;
407 MonoDomain *domain = mono_domain_get();
410 tramp = create_trampoline_code (MONO_TRAMPOLINE_JUMP);
412 mono_domain_lock (domain);
413 code = buf = mono_code_manager_reserve (domain->code_mp, METHOD_TRAMPOLINE_SIZE);
414 mono_domain_unlock (domain);
416 s390_basr (buf, s390_r13, 0);
418 s390_llong(buf, method);
419 s390_lg (buf, s390_r13, 0, s390_r13, 4);
420 displace = (tramp - buf) / 2;
421 s390_jcl (buf, S390_CC_UN, displace);
423 mono_arch_flush_icache (code, buf-code);
425 g_assert ((buf - code) <= JUMP_TRAMPOLINE_SIZE);
427 ji = g_new0 (MonoJitInfo, 1);
429 ji->code_start = code;
430 ji->code_size = buf - code;
432 mono_jit_stats.method_trampolines++;
437 /*========================= End of Function ========================*/
439 /*------------------------------------------------------------------*/
441 /* Name - mono_arch_create_jit_trampoline */
443 /* Function - Creates a trampoline function for virtual methods.*/
444 /* If the created code is called it first starts JIT */
445 /* compilation and then calls the newly created */
446 /* method. It also replaces the corresponding vtable */
447 /* entry (see s390_magic_trampoline). */
449 /* A trampoline consists of two parts: a main */
450 /* fragment, shared by all method trampolines, and */
451 /* and some code specific to each method, which */
452 /* hard-codes a reference to that method and then */
453 /* calls the main fragment. */
455 /* The main fragment contains a call to */
456 /* 's390_magic_trampoline', which performs a call */
457 /* to the JIT compiler and substitutes the method- */
458 /* specific fragment with some code that directly */
459 /* calls the JIT-compiled method. */
461 /* Parameter - method - Pointer to the method information */
463 /* Returns - A pointer to the newly created code */
465 /*------------------------------------------------------------------*/
468 mono_arch_create_jit_trampoline (MonoMethod *method)
471 static guint8 *vc = NULL;
474 /* previously created trampoline code */
478 if (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
479 return mono_arch_create_jit_trampoline (mono_marshal_get_synchronized_wrapper (method));
481 vc = create_trampoline_code (MONO_TRAMPOLINE_GENERIC);
483 /* This is the method-specific part of the trampoline. Its purpose is
484 to provide the generic part with the MonoMethod *method pointer. We'll
485 use r13 to keep that value, for instance. However, the generic part of
486 the trampoline relies on r11 having the same value it had before coming
487 here, so we must save it before. */
488 code = buf = g_malloc(METHOD_TRAMPOLINE_SIZE);
490 s390_basr (buf, s390_r13, 0);
492 s390_llong(buf, method);
493 s390_lg (buf, s390_r13, 0, s390_r13, 4);
494 displace = (vc - buf) / 2;
495 s390_jcl (buf, S390_CC_UN, displace);
497 /* Flush instruction cache, since we've generated code */
498 mono_arch_flush_icache (code, buf - code);
501 g_assert ((buf - code) <= METHOD_TRAMPOLINE_SIZE);
503 /* Store trampoline address */
506 mono_jit_stats.method_trampolines++;
511 /*========================= End of Function ========================*/
513 /*------------------------------------------------------------------*/
515 /* Name - mono_arch_create_class_init_trampoline */
517 /* Function - Creates a trampoline function to run a type init- */
518 /* ializer. If the trampoline is called, it calls */
519 /* mono_runtime_class_init with the given vtable, */
520 /* then patches the caller code so it does not get */
521 /* called any more. */
523 /* Parameter - vtable - The type to initialize */
525 /* Returns - A pointer to the newly created code */
527 /*------------------------------------------------------------------*/
530 mono_arch_create_class_init_trampoline (MonoVTable *vtable)
532 guint8 *code, *buf, *tramp;
534 tramp = create_trampoline_code (MONO_TRAMPOLINE_CLASS_INIT);
536 /* This is the method-specific part of the trampoline. Its purpose is
537 to provide the generic part with the MonoMethod *method pointer. We'll
538 use r11 to keep that value, for instance. However, the generic part of
539 the trampoline relies on r11 having the same value it had before coming
540 here, so we must save it before. */
541 code = buf = g_malloc(METHOD_TRAMPOLINE_SIZE);
543 s390_stg (buf, s390_r14, 0, STK_BASE, S390_RET_ADDR_OFFSET);
544 s390_aghi (buf, STK_BASE, -S390_MINIMAL_STACK_SIZE);
546 s390_basr (buf, s390_r1, 0);
548 s390_llong(buf, vtable);
549 s390_llong(buf, s390_class_init_trampoline);
550 s390_lgr (buf, s390_r3, s390_r14);
551 s390_lg (buf, s390_r2, 0, s390_r1, 4);
552 s390_lghi (buf, s390_r4, 0);
553 s390_lg (buf, s390_r1, 0, s390_r1, 8);
554 s390_basr (buf, s390_r14, s390_r1);
556 s390_aghi (buf, STK_BASE, S390_MINIMAL_STACK_SIZE);
557 s390_lg (buf, s390_r14, 0, STK_BASE, S390_RET_ADDR_OFFSET);
558 s390_br (buf, s390_r14);
560 /* Flush instruction cache, since we've generated code */
561 mono_arch_flush_icache (code, buf - code);
564 g_assert ((buf - code) <= METHOD_TRAMPOLINE_SIZE);
566 mono_jit_stats.method_trampolines++;
571 /*========================= End of Function ========================*/
573 /*------------------------------------------------------------------*/
575 /* Name - mono_debuger_create_notification_function */
577 /* Function - This method is only called when running in the */
578 /* Mono debugger. It returns a pointer to the */
579 /* arch specific notification function. */
581 /*------------------------------------------------------------------*/
584 mono_debugger_create_notification_function (gpointer *notification_address)
588 ptr = buf = g_malloc0 (16);
590 if (notification_address)
591 *notification_address = buf;
592 s390_br (buf, s390_r14);
597 /*========================= End of Function ========================*/