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 METHOD_SAVE_OFFSET S390_MINIMAL_STACK_SIZE
26 #define CREATE_GR_OFFSET METHOD_SAVE_OFFSET+sizeof(gpointer)
27 #define CREATE_FP_OFFSET CREATE_GR_OFFSET+GR_SAVE_SIZE
28 #define CREATE_LMF_OFFSET CREATE_FP_OFFSET+FP_SAVE_SIZE
29 #define CREATE_STACK_SIZE (CREATE_LMF_OFFSET+2*sizeof(long)+sizeof(MonoLMF))
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>
53 #include "mini-s390.h"
55 /*========================= End of Includes ========================*/
57 /*------------------------------------------------------------------*/
59 /*------------------------------------------------------------------*/
61 /*========================= End of Typedefs ========================*/
63 /*------------------------------------------------------------------*/
64 /* P r o t o t y p e s */
65 /*------------------------------------------------------------------*/
67 /*========================= End of Prototypes ======================*/
69 /*------------------------------------------------------------------*/
70 /* G l o b a l V a r i a b l e s */
71 /*------------------------------------------------------------------*/
74 /*====================== End of Global Variables ===================*/
76 /*------------------------------------------------------------------*/
78 /* Name - get_unbox_trampoline */
80 /* Function - Return a pointer to a trampoline which does the */
81 /* unboxing before calling the method. */
83 /* When value type methods are called through the */
84 /* vtable we need to unbox the 'this' argument. */
86 /* Parameters - method - Methd pointer */
87 /* addr - Pointer to native code for method */
89 /*------------------------------------------------------------------*/
92 get_unbox_trampoline (MonoMethod *method, gpointer addr)
95 int this_pos = s390_r2;
98 if ((!mono_method_signature (method)->ret->byref) &&
99 (MONO_TYPE_ISSTRUCT (mono_method_signature (method)->ret)))
102 start = code = mono_global_codeman_reserve (28);
104 s390_basr (code, s390_r13, 0);
106 s390_word (code, addr);
107 s390_l (code, s390_r1, 0, s390_r13, 4);
108 s390_ahi (code, this_pos, sizeof(MonoObject));
109 s390_br (code, s390_r1);
111 g_assert ((code - start) <= 28);
116 /*========================= End of Function ========================*/
118 /*------------------------------------------------------------------*/
120 /* Name - s390_magic_trampoline */
122 /* Function - This method is called by the function */
123 /* "arch_create_jit_trampoline", which in turn is */
124 /* called by the trampoline functions for virtual */
125 /* methods. After having called the JIT compiler to */
126 /* compile the method, it inspects the caller code */
127 /* to find the address of the method-specific part */
128 /* of the trampoline vtable slot for this method, */
129 /* updates it with a fragment that calls the newly */
130 /* compiled code and returns this address. The calls */
131 /* generated by mono for S/390 will look like either:*/
132 /* 1. l %r1,xxx(%rx) */
134 /* 2. brasl %r14,xxxxxx */
136 /* Parameters - code - Pointer into caller code */
137 /* method - The method to compile */
138 /* sp - Stack pointer */
140 /*------------------------------------------------------------------*/
143 s390_magic_trampoline (MonoMethod *method, guchar *code, char *sp)
149 unsigned short opcode;
154 addr = mono_compile_method(method);
160 /* The top bit needs to be ignored on S/390 */
161 code = (guchar*)((guint32)code & 0x7fffffff);
163 fname = mono_method_full_name (method, TRUE);
164 codeJi = mono_jit_info_table_find (mono_domain_get(), code);
165 addrJi = mono_jit_info_table_find (mono_domain_get(), addr);
166 if (mono_method_same_domain (codeJi, addrJi)) {
168 opcode = *((unsigned short *) (code - 6));
171 /* This is a bras r14,r1 instruction */
174 displace = *((short *)code) & 0x0fff;
176 base = *((guchar **) (sp + S390_REG_SAVE_OFFSET+
177 sizeof(int)*(reg-6)));
179 base = *((guchar **) ((sp - CREATE_STACK_SIZE) +
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_st (buf, s390_r1, 0, STK_BASE, METHOD_SAVE_OFFSET);
268 s390_stm (buf, s390_r2, s390_r5, STK_BASE, CREATE_GR_OFFSET);
270 /* Save the FP registers */
271 offset = CREATE_FP_OFFSET;
272 for (i = s390_f0; i <= s390_f15; ++i) {
273 s390_std (buf, i, 0, STK_BASE, offset);
277 /*----------------------------------------------------------
278 STEP 1: call 'mono_get_lmf_addr()' to get the address of our
279 LMF. We'll need to restore it after the call to
280 's390_magic_trampoline' and before the call to the native
282 ----------------------------------------------------------*/
284 s390_basr (buf, s390_r13, 0);
286 s390_word (buf, mono_get_lmf_addr);
287 s390_l (buf, s390_r1, 0, s390_r13, 4);
288 s390_basr (buf, s390_r14, s390_r1);
290 /*---------------------------------------------------------------*/
291 /* we build the MonoLMF structure on the stack - see mini-s390.h */
292 /* Keep in sync with the code in mono_arch_emit_prolog */
293 /*---------------------------------------------------------------*/
294 lmfOffset = CREATE_STACK_SIZE - sizeof(MonoLMF);
296 s390_lr (buf, s390_r13, STK_BASE);
297 s390_ahi (buf, s390_r13, lmfOffset);
299 /*---------------------------------------------------------------*/
300 /* Set lmf.lmf_addr = jit_tls->lmf */
301 /*---------------------------------------------------------------*/
302 s390_st (buf, s390_r2, 0, s390_r13,
303 G_STRUCT_OFFSET(MonoLMF, lmf_addr));
305 /*---------------------------------------------------------------*/
306 /* Get current lmf */
307 /*---------------------------------------------------------------*/
308 s390_l (buf, s390_r0, 0, s390_r2, 0);
310 /*---------------------------------------------------------------*/
311 /* Set our lmf as the current lmf */
312 /*---------------------------------------------------------------*/
313 s390_st (buf, s390_r13, 0, s390_r2, 0);
315 /*---------------------------------------------------------------*/
316 /* Have our lmf.previous_lmf point to the last lmf */
317 /*---------------------------------------------------------------*/
318 s390_st (buf, s390_r0, 0, s390_r13,
319 G_STRUCT_OFFSET(MonoLMF, previous_lmf));
321 /*---------------------------------------------------------------*/
322 /* save method info */
323 /*---------------------------------------------------------------*/
324 s390_l (buf, s390_r1, 0, STK_BASE, METHOD_SAVE_OFFSET);
325 s390_st (buf, s390_r1, 0, s390_r13,
326 G_STRUCT_OFFSET(MonoLMF, method));
328 /*---------------------------------------------------------------*/
329 /* save the current SP */
330 /*---------------------------------------------------------------*/
331 s390_l (buf, s390_r1, 0, STK_BASE, 0);
332 s390_st (buf, s390_r1, 0, s390_r13, G_STRUCT_OFFSET(MonoLMF, ebp));
334 /*---------------------------------------------------------------*/
335 /* save the current IP */
336 /*---------------------------------------------------------------*/
337 if (tramp_type == MONO_TRAMPOLINE_JUMP) {
338 s390_lhi (buf, s390_r1, 0);
340 s390_l (buf, s390_r1, 0, s390_r1, S390_RET_ADDR_OFFSET);
341 s390_la (buf, s390_r1, 0, s390_r1, 0);
343 s390_st (buf, s390_r1, 0, s390_r13, G_STRUCT_OFFSET(MonoLMF, eip));
345 /*---------------------------------------------------------------*/
346 /* Save general and floating point registers */
347 /*---------------------------------------------------------------*/
348 s390_stm (buf, s390_r2, s390_r12, s390_r13,
349 G_STRUCT_OFFSET(MonoLMF, gregs[2]));
350 for (i = 0; i < 16; i++) {
351 s390_std (buf, i, 0, s390_r13,
352 G_STRUCT_OFFSET(MonoLMF, fregs[i]));
355 /*---------------------------------------------------------------*/
356 /* STEP 2: call 's390_magic_trampoline()', who will compile the */
357 /* code and fix the method vtable entry for us */
358 /*---------------------------------------------------------------*/
362 /* Arg 1: MonoMethod *method. It was put in r1 by the
363 method-specific trampoline code, and then saved before the call
364 to mono_get_lmf_addr()'. */
365 s390_l (buf, s390_r2, 0, STK_BASE, METHOD_SAVE_OFFSET);
367 /* Arg 2: code (next address to the instruction that called us) */
368 if (tramp_type == MONO_TRAMPOLINE_JUMP) {
369 s390_lhi (buf, s390_r3, 0);
371 s390_l (buf, s390_r3, 0, s390_r11, S390_RET_ADDR_OFFSET);
374 /* Arg 3: stack pointer */
375 s390_lr (buf, s390_r4, STK_BASE);
376 s390_ahi (buf, s390_r4, CREATE_STACK_SIZE);
378 /* Calculate call address and call
379 's390_magic_trampoline'. Return value will be in r2 */
380 s390_basr (buf, s390_r13, 0);
382 if (tramp_type == MONO_TRAMPOLINE_CLASS_INIT) {
383 s390_word (buf, s390_class_init_trampoline);
385 s390_word (buf, s390_magic_trampoline);
387 s390_l (buf, s390_r1, 0, s390_r13, 4);
388 s390_basr (buf, s390_r14, s390_r1);
390 /* OK, code address is now on r2. Move it to r1, so that we
391 can restore r2 and use it from r1 later */
392 s390_lr (buf, s390_r1, s390_r2);
394 /*----------------------------------------------------------
395 STEP 3: Restore the LMF
396 ----------------------------------------------------------*/
397 restoreLMF(buf, STK_BASE, CREATE_STACK_SIZE);
399 /*----------------------------------------------------------
400 STEP 4: call the compiled method
401 ----------------------------------------------------------*/
403 /* Restore registers */
405 s390_lm (buf, s390_r2, s390_r5, STK_BASE, CREATE_GR_OFFSET);
407 /* Restore the FP registers */
408 offset = CREATE_FP_OFFSET;
409 for (i = s390_f0; i <= s390_f15; ++i) {
410 s390_ld (buf, i, 0, STK_BASE, offset);
414 /* Restore stack pointer and jump to the code -
415 R14 contains the return address to our caller */
416 s390_lr (buf, STK_BASE, s390_r11);
417 s390_lm (buf, s390_r6, s390_r14, STK_BASE, S390_REG_SAVE_OFFSET);
418 s390_br (buf, s390_r1);
420 /* Flush instruction cache, since we've generated code */
421 mono_arch_flush_icache (code, buf - code);
424 g_assert ((buf - code) <= 512);
430 /*========================= End of Function ========================*/
432 /*------------------------------------------------------------------*/
434 /* Name - mono_arch_create_jump_trampoline */
436 /* Function - Create the designated type of trampoline according*/
437 /* to the 'tramp_type' parameter. */
439 /*------------------------------------------------------------------*/
442 mono_arch_create_jump_trampoline (MonoMethod *method)
444 guint8 *code, *buf, *tramp = NULL;
446 MonoDomain *domain = mono_domain_get();
449 tramp = mono_get_trampoline_code (MONO_TRAMPOLINE_JUMP);
451 mono_domain_lock (domain);
452 code = buf = mono_code_manager_reserve (domain->code_mp, METHOD_TRAMPOLINE_SIZE);
453 mono_domain_unlock (domain);
455 s390_basr (buf, s390_r1, 0);
457 s390_word (buf, method);
458 s390_l (buf, s390_r1, 0, s390_r1, 4);
459 displace = (tramp - buf) / 2;
460 s390_jcl (buf, S390_CC_UN, displace);
462 mono_arch_flush_icache (code, buf-code);
464 g_assert ((buf - code) <= JUMP_TRAMPOLINE_SIZE);
466 ji = g_new0 (MonoJitInfo, 1);
468 ji->code_start = code;
469 ji->code_size = buf - code;
471 mono_jit_stats.method_trampolines++;
476 /*========================= End of Function ========================*/
478 /*------------------------------------------------------------------*/
480 /* Name - mono_arch_create_jit_trampoline */
482 /* Function - Creates a trampoline function for virtual methods.*/
483 /* If the created code is called it first starts JIT */
484 /* compilation and then calls the newly created */
485 /* method. It also replaces the corresponding vtable */
486 /* entry (see s390_magic_trampoline). */
488 /* A trampoline consists of two parts: a main */
489 /* fragment, shared by all method trampolines, and */
490 /* and some code specific to each method, which */
491 /* hard-codes a reference to that method and then */
492 /* calls the main fragment. */
494 /* The main fragment contains a call to */
495 /* 's390_magic_trampoline', which performs a call */
496 /* to the JIT compiler and substitutes the method- */
497 /* specific fragment with some code that directly */
498 /* calls the JIT-compiled method. */
500 /* Parameter - method - Pointer to the method information */
502 /* Returns - A pointer to the newly created code */
504 /*------------------------------------------------------------------*/
507 mono_arch_create_jit_trampoline (MonoMethod *method)
510 static guint8 *vc = NULL;
513 vc = mono_get_trampoline_code (MONO_TRAMPOLINE_GENERIC);
515 /*----------------------------------------------------------*/
516 /* This is the method-specific part of the trampoline. Its */
517 /* purpose is to provide the generic part with the */
518 /* MonoMethod *method pointer. We'll use r1 to keep it. */
519 /*----------------------------------------------------------*/
520 code = buf = mono_global_codeman_reserve(METHOD_TRAMPOLINE_SIZE);
522 s390_basr (buf, s390_r1, 0);
524 s390_word (buf, method);
525 s390_l (buf, s390_r1, 0, s390_r1, 4);
526 displace = (vc - buf) / 2;
527 s390_jcl (buf, S390_CC_UN, displace);
529 /* Flush instruction cache, since we've generated code */
530 mono_arch_flush_icache (code, buf - code);
533 g_assert ((buf - code) <= METHOD_TRAMPOLINE_SIZE);
538 /*========================= End of Function ========================*/
540 /*------------------------------------------------------------------*/
542 /* Name - mono_arch_create_class_init_trampoline */
544 /* Function - Creates a trampoline function to run a type init- */
545 /* ializer. If the trampoline is called, it calls */
546 /* mono_runtime_class_init with the given vtable, */
547 /* then patches the caller code so it does not get */
548 /* called any more. */
550 /* Parameter - vtable - The type to initialize */
552 /* Returns - A pointer to the newly created code */
554 /*------------------------------------------------------------------*/
557 mono_arch_create_class_init_trampoline (MonoVTable *vtable)
559 guint8 *code, *buf, *tramp;
561 tramp = mono_get_trampoline_code (MONO_TRAMPOLINE_CLASS_INIT);
563 /*-----------------------------------------------------------*/
564 /* This is the method-specific part of the trampoline. Its */
565 /* purpose is to provide the generic part with the MonoMethod*/
566 /* *method pointer. We'll use r11 to keep that value, for */
567 /* instance. However, the generic part of the trampoline */
568 /* relies on r11 having the same value it had before coming */
569 /* here, so we must save it before. */
570 /*-----------------------------------------------------------*/
571 code = buf = mono_global_codeman_reserve(METHOD_TRAMPOLINE_SIZE);
573 s390_st (buf, s390_r14, 0, STK_BASE, S390_RET_ADDR_OFFSET);
574 s390_ahi (buf, STK_BASE, -S390_MINIMAL_STACK_SIZE);
576 s390_basr (buf, s390_r1, 0);
578 s390_word (buf, vtable);
579 s390_word (buf, s390_class_init_trampoline);
580 s390_lr (buf, s390_r3, s390_r14);
581 s390_l (buf, s390_r2, 0, s390_r1, 4);
582 s390_lhi (buf, s390_r4, 0);
583 s390_l (buf, s390_r1, 0, s390_r1, 8);
584 s390_basr (buf, s390_r14, s390_r1);
586 s390_ahi (buf, STK_BASE, S390_MINIMAL_STACK_SIZE);
587 s390_l (buf, s390_r14, 0, STK_BASE, S390_RET_ADDR_OFFSET);
588 s390_br (buf, s390_r14);
590 /* Flush instruction cache, since we've generated code */
591 mono_arch_flush_icache (code, buf - code);
594 g_assert ((buf - code) <= METHOD_TRAMPOLINE_SIZE);
596 mono_jit_stats.method_trampolines++;
601 /*========================= End of Function ========================*/
603 /*------------------------------------------------------------------*/
605 /* Name - mono_debuger_create_notification_function */
607 /* Function - This method is only called when running in the */
608 /* Mono debugger. It returns a pointer to the */
609 /* arch specific notification function. */
611 /*------------------------------------------------------------------*/
614 mono_debugger_create_notification_function (MonoCodeManager *codeman)
618 ptr = buf = mono_code_manager_reserve (codeman, 16);
620 s390_br (buf, s390_r14);
625 /*========================= End of Function ========================*/