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 /* 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/s390x/s390x-codegen.h>
51 #include <mono/metadata/mono-debug-debugger.h>
54 #include "mini-s390x.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 ((method->klass->valuetype)) {
100 if ((!mono_method_signature (method)->ret->byref) &&
101 (MONO_TYPE_ISSTRUCT (mono_method_signature (method)->ret)))
104 start = code = g_malloc (28);
106 s390_basr (code, s390_r13, 0);
108 s390_llong(code, addr);
109 s390_lg (code, s390_r1, 0, s390_r13, 4);
110 s390_aghi (code, this_pos, sizeof(MonoObject));
111 s390_br (code, s390_r1);
113 g_assert ((code - start) <= 28);
119 /*========================= End of Function ========================*/
121 /*------------------------------------------------------------------*/
123 /* Name - s390_magic_trampoline */
125 /* Function - This method is called by the function */
126 /* "arch_create_jit_trampoline", which in turn is */
127 /* called by the trampoline functions for virtual */
128 /* methods. After having called the JIT compiler to */
129 /* compile the method, it inspects the caller code */
130 /* to find the address of the method-specific part */
131 /* of the trampoline vtable slot for this method, */
132 /* updates it with a fragment that calls the newly */
133 /* compiled code and returns this address. The calls */
134 /* generated by mono for S/390 will look like either:*/
135 /* 1. l %r1,xxx(%rx) */
137 /* 2. brasl %r14,xxxxxx */
139 /* Parameters - code - Pointer into caller code */
140 /* method - The method to compile */
141 /* sp - Stack pointer */
143 /*------------------------------------------------------------------*/
146 s390_magic_trampoline (MonoMethod *method, guchar *code, char *sp)
152 unsigned short opcode;
155 addr = mono_compile_method(method);
160 fname = mono_method_full_name (method, TRUE);
162 opcode = *((unsigned short *) (code - 6));
163 if (opcode == 0xc0e5) {
164 /* This is the 'brasl' instruction */
166 displace = ((gint64) addr - (gint64) (code - 2)) / 2;
167 s390_patch (code, displace);
168 mono_arch_flush_icache (code, 4);
170 /* This is a bras rx,r1 instruction */
173 displace = ((*(char *)(code+2) << 8) |
174 (*((short *)code) & 0x0fff));
176 base = *((gint64 *) (sp + S390_REG_SAVE_OFFSET+
177 sizeof(gint64)*(reg-6)));
179 base = *((gint64 *) (sp + CREATE_GR_OFFSET+
180 sizeof(gint64)*(reg-2)));
181 addr = get_unbox_trampoline(method, addr);
182 code = base + displace;
183 *((guint64 *) (code)) = addr;
191 /*========================= End of Function ========================*/
193 /*------------------------------------------------------------------*/
195 /* Name - s390_class_init_trampoline */
197 /* Function - Initialize a class and then no-op the call to */
198 /* the trampoline. */
200 /*------------------------------------------------------------------*/
203 s390_class_init_trampoline (void *vtable, guchar *code, char *sp)
205 char patch[6] = {0x47, 0x00, 0x00, 0x00, 0x07, 0x00};
207 mono_runtime_class_init (vtable);
211 memcpy(code, patch, sizeof(patch));
214 /*========================= End of Function ========================*/
216 /*------------------------------------------------------------------*/
218 /* Name - mono_arch_create_trampoline_code */
220 /* Function - Create the designated type of trampoline according*/
221 /* to the 'tramp_type' parameter. */
223 /*------------------------------------------------------------------*/
226 mono_arch_create_trampoline_code (MonoTrampolineType tramp_type)
229 guint8 *buf, *code = NULL;
233 /* Now we'll create in 'buf' the S/390 trampoline code. This
234 is the trampoline code common to all methods */
236 code = buf = g_malloc(512);
238 /*-----------------------------------------------------------
239 STEP 0: First create a non-standard function prologue with a
240 stack size big enough to save our registers.
241 -----------------------------------------------------------*/
243 s390_stmg (buf, s390_r6, s390_r14, STK_BASE, S390_REG_SAVE_OFFSET);
244 s390_lgr (buf, s390_r11, s390_r15);
245 s390_aghi (buf, STK_BASE, -CREATE_STACK_SIZE);
246 s390_stg (buf, s390_r11, 0, STK_BASE, 0);
247 s390_stmg (buf, s390_r2, s390_r5, STK_BASE, CREATE_GR_OFFSET);
249 /* Save the FP registers */
250 offset = CREATE_FP_OFFSET;
251 for (i = s390_f0; i <= s390_f15; ++i) {
252 s390_std (buf, i, 0, STK_BASE, offset);
256 /*----------------------------------------------------------
257 STEP 1: call 'mono_get_lmf_addr()' to get the address of our
258 LMF. We'll need to restore it after the call to
259 's390_magic_trampoline' and before the call to the native
261 ----------------------------------------------------------*/
263 s390_basr (buf, s390_r13, 0);
265 s390_llong(buf, mono_get_lmf_addr);
266 s390_lg (buf, s390_r1, 0, s390_r13, 4);
267 s390_basr (buf, s390_r14, s390_r1);
269 /*----------------------------------------------------------
270 STEP 2: call 's390_magic_trampoline()', who will compile the
271 code and fix the method vtable entry for us
272 ----------------------------------------------------------*/
276 /* Arg 1: MonoMethod *method. It was put in r11 by the
277 method-specific trampoline code, and then saved before the call
278 to mono_get_lmf_addr()'. Restore r13, by the way :-) */
279 s390_lg (buf, s390_r2, 0, s390_r11, METHOD_SAVE_OFFSET);
281 /* Arg 2: code (next address to the instruction that called us) */
282 if (tramp_type == MONO_TRAMPOLINE_JUMP) {
283 s390_lghi (buf, s390_r3, 0);
285 s390_lg (buf, s390_r3, 0, s390_r11, S390_RET_ADDR_OFFSET);
288 /* Arg 3: stack pointer */
289 s390_lgr (buf, s390_r4, STK_BASE);
291 /* Calculate call address and call
292 's390_magic_trampoline'. Return value will be in r2 */
293 s390_basr (buf, s390_r13, 0);
295 if (tramp_type == MONO_TRAMPOLINE_CLASS_INIT) {
296 s390_llong(buf, s390_class_init_trampoline);
298 s390_llong(buf, s390_magic_trampoline);
300 s390_lg (buf, s390_r1, 0, s390_r13, 4);
301 s390_basr (buf, s390_r14, s390_r1);
303 /* OK, code address is now on r2. Move it to r1, so that we
304 can restore r2 and use it from r1 later */
305 s390_lgr (buf, s390_r1, s390_r2);
308 /*----------------------------------------------------------
309 STEP 3: Restore the LMF
310 ----------------------------------------------------------*/
314 /*----------------------------------------------------------
315 STEP 4: call the compiled method
316 ----------------------------------------------------------*/
318 /* Restore registers */
320 s390_lmg (buf, s390_r2, s390_r5, STK_BASE, CREATE_GR_OFFSET);
322 /* Restore the FP registers */
323 offset = CREATE_FP_OFFSET;
324 for (i = s390_f0; i <= s390_f15; ++i) {
325 s390_ld (buf, i, 0, STK_BASE, offset);
329 /* Restore stack pointer and jump to the code -
330 R14 contains the return address to our caller */
331 s390_lgr (buf, STK_BASE, s390_r11);
332 s390_lmg (buf, s390_r6, s390_r14, STK_BASE, S390_REG_SAVE_OFFSET);
333 s390_br (buf, s390_r1);
335 /* Flush instruction cache, since we've generated code */
336 mono_arch_flush_icache (code, buf - code);
339 g_assert ((buf - code) <= 512);
345 /*========================= End of Function ========================*/
347 /*------------------------------------------------------------------*/
349 /* Name - mono_arch_create_jump_trampoline */
351 /* Function - Create the designated type of trampoline according*/
352 /* to the 'tramp_type' parameter. */
354 /*------------------------------------------------------------------*/
357 mono_arch_create_jump_trampoline (MonoMethod *method)
359 guint8 *code, *buf, *tramp = NULL;
361 MonoDomain *domain = mono_domain_get();
364 tramp = mono_get_trampoline_code (MONO_TRAMPOLINE_JUMP);
366 mono_domain_lock (domain);
367 code = buf = mono_code_manager_reserve (domain->code_mp, METHOD_TRAMPOLINE_SIZE);
368 mono_domain_unlock (domain);
370 s390_basr (buf, s390_r13, 0);
372 s390_llong(buf, method);
373 s390_lg (buf, s390_r13, 0, s390_r13, 4);
374 displace = (tramp - buf) / 2;
375 s390_jcl (buf, S390_CC_UN, displace);
377 mono_arch_flush_icache (code, buf-code);
379 g_assert ((buf - code) <= JUMP_TRAMPOLINE_SIZE);
381 ji = g_new0 (MonoJitInfo, 1);
383 ji->code_start = code;
384 ji->code_size = buf - code;
386 mono_jit_stats.method_trampolines++;
391 /*========================= End of Function ========================*/
393 /*------------------------------------------------------------------*/
395 /* Name - mono_arch_create_jit_trampoline */
397 /* Function - Creates a trampoline function for virtual methods.*/
398 /* If the created code is called it first starts JIT */
399 /* compilation and then calls the newly created */
400 /* method. It also replaces the corresponding vtable */
401 /* entry (see s390_magic_trampoline). */
403 /* A trampoline consists of two parts: a main */
404 /* fragment, shared by all method trampolines, and */
405 /* and some code specific to each method, which */
406 /* hard-codes a reference to that method and then */
407 /* calls the main fragment. */
409 /* The main fragment contains a call to */
410 /* 's390_magic_trampoline', which performs a call */
411 /* to the JIT compiler and substitutes the method- */
412 /* specific fragment with some code that directly */
413 /* calls the JIT-compiled method. */
415 /* Parameter - method - Pointer to the method information */
417 /* Returns - A pointer to the newly created code */
419 /*------------------------------------------------------------------*/
422 mono_arch_create_jit_trampoline (MonoMethod *method)
425 static guint8 *vc = NULL;
428 vc = mono_get_trampoline_code (MONO_TRAMPOLINE_GENERIC);
430 /* This is the method-specific part of the trampoline. Its purpose is
431 to provide the generic part with the MonoMethod *method pointer. We'll
432 use r13 to keep that value, for instance. However, the generic part of
433 the trampoline relies on r11 having the same value it had before coming
434 here, so we must save it before. */
435 code = buf = g_malloc(METHOD_TRAMPOLINE_SIZE);
437 s390_basr (buf, s390_r13, 0);
439 s390_llong(buf, method);
440 s390_lg (buf, s390_r13, 0, s390_r13, 4);
441 displace = (vc - buf) / 2;
442 s390_jcl (buf, S390_CC_UN, displace);
444 /* Flush instruction cache, since we've generated code */
445 mono_arch_flush_icache (code, buf - code);
448 g_assert ((buf - code) <= METHOD_TRAMPOLINE_SIZE);
450 mono_jit_stats.method_trampolines++;
455 /*========================= End of Function ========================*/
457 /*------------------------------------------------------------------*/
459 /* Name - mono_arch_create_class_init_trampoline */
461 /* Function - Creates a trampoline function to run a type init- */
462 /* ializer. If the trampoline is called, it calls */
463 /* mono_runtime_class_init with the given vtable, */
464 /* then patches the caller code so it does not get */
465 /* called any more. */
467 /* Parameter - vtable - The type to initialize */
469 /* Returns - A pointer to the newly created code */
471 /*------------------------------------------------------------------*/
474 mono_arch_create_class_init_trampoline (MonoVTable *vtable)
476 guint8 *code, *buf, *tramp;
478 tramp = mono_get_trampoline_code (MONO_TRAMPOLINE_CLASS_INIT);
480 /* This is the method-specific part of the trampoline. Its purpose is
481 to provide the generic part with the MonoMethod *method pointer. We'll
482 use r11 to keep that value, for instance. However, the generic part of
483 the trampoline relies on r11 having the same value it had before coming
484 here, so we must save it before. */
485 code = buf = g_malloc(METHOD_TRAMPOLINE_SIZE);
487 s390_stg (buf, s390_r14, 0, STK_BASE, S390_RET_ADDR_OFFSET);
488 s390_aghi (buf, STK_BASE, -S390_MINIMAL_STACK_SIZE);
490 s390_basr (buf, s390_r1, 0);
492 s390_llong(buf, vtable);
493 s390_llong(buf, s390_class_init_trampoline);
494 s390_lgr (buf, s390_r3, s390_r14);
495 s390_lg (buf, s390_r2, 0, s390_r1, 4);
496 s390_lghi (buf, s390_r4, 0);
497 s390_lg (buf, s390_r1, 0, s390_r1, 8);
498 s390_basr (buf, s390_r14, s390_r1);
500 s390_aghi (buf, STK_BASE, S390_MINIMAL_STACK_SIZE);
501 s390_lg (buf, s390_r14, 0, STK_BASE, S390_RET_ADDR_OFFSET);
502 s390_br (buf, s390_r14);
504 /* Flush instruction cache, since we've generated code */
505 mono_arch_flush_icache (code, buf - code);
508 g_assert ((buf - code) <= METHOD_TRAMPOLINE_SIZE);
510 mono_jit_stats.method_trampolines++;
515 /*========================= End of Function ========================*/
517 /*------------------------------------------------------------------*/
519 /* Name - mono_debuger_create_notification_function */
521 /* Function - This method is only called when running in the */
522 /* Mono debugger. It returns a pointer to the */
523 /* arch specific notification function. */
525 /*------------------------------------------------------------------*/
528 mono_debugger_create_notification_function (gpointer *notification_address)
532 ptr = buf = g_malloc0 (16);
534 if (notification_address)
535 *notification_address = buf;
536 s390_br (buf, s390_r14);
541 /*========================= End of Function ========================*/