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+8
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 96
35 #define JUMP_TRAMPOLINE_SIZE 96
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 ((!mono_method_signature (method)->ret->byref) &&
100 (MONO_TYPE_ISSTRUCT (mono_method_signature (method)->ret)))
103 start = code = mono_global_codeman_reserve (28);
105 s390_basr (code, s390_r1, 0);
107 s390_llong(code, addr);
108 s390_lg (code, s390_r1, 0, s390_r1, 4);
109 s390_aghi (code, this_pos, sizeof(MonoObject));
110 s390_br (code, s390_r1);
112 g_assert ((code - start) <= 28);
117 /*========================= End of Function ========================*/
119 /*------------------------------------------------------------------*/
121 /* Name - s390_magic_trampoline */
123 /* Function - This method is called by the function */
124 /* "arch_create_jit_trampoline", which in turn is */
125 /* called by the trampoline functions for virtual */
126 /* methods. After having called the JIT compiler to */
127 /* compile the method, it inspects the caller code */
128 /* to find the address of the method-specific part */
129 /* of the trampoline vtable slot for this method, */
130 /* updates it with a fragment that calls the newly */
131 /* compiled code and returns this address. The calls */
132 /* generated by mono for S/390 will look like either:*/
133 /* 1. l %r1,xxx(%rx) */
135 /* 2. brasl %r14,xxxxxx */
137 /* Parameters - code - Pointer into caller code */
138 /* method - The method to compile */
139 /* sp - Stack pointer */
141 /*------------------------------------------------------------------*/
144 s390_magic_trampoline (MonoMethod *method, guchar *code, char *sp)
150 unsigned short opcode;
154 addr = mono_compile_method(method);
159 codeJi = mono_jit_info_table_find (mono_domain_get(), code);
160 addrJi = mono_jit_info_table_find (mono_domain_get(), addr);
161 if (mono_method_same_domain (codeJi, addrJi)) {
163 opcode = *((unsigned short *) (code - 6));
164 if (opcode == 0xc0e5) {
165 /* This is the 'brasl' instruction */
167 displace = ((gint64) addr - (gint64) (code - 2)) / 2;
168 if (mono_method_same_domain (codeJi, addrJi)) {
169 s390_patch_rel (code, displace);
170 mono_arch_flush_icache (code, 4);
173 /*-----------------------------------*/
174 /* This is a bras r14,Rz instruction */
175 /* If it's preceded by a LG Rx,d(Ry) */
176 /* If Rz == 1 then we check if unbox-*/
177 /* is required. We patch the address */
178 /* by determining the location desc- */
179 /* cribed by *Ry+d. */
180 /*-----------------------------------*/
183 /*-----------------------------------*/
184 /* If call is preceded by LGR then */
185 /* there's nothing to patch */
186 /*-----------------------------------*/
187 if ((code[0] == 0xb9) &&
191 /*-----------------------------------*/
192 /* We back up until we're pointing at*/
193 /* the base/displacement portion of */
194 /* the LG instruction */
195 /*-----------------------------------*/
196 lkReg = code[5] & 0x0f;
198 /*-----------------------------------*/
199 /* The LG instruction has format: */
200 /* E3x0ylllhh04 - where: */
201 /* x = Rx; y = Ry; */
202 /* lll = low 12 bits of displacement */
203 /* hh = high 8 bits of displacement */
204 /*-----------------------------------*/
206 displace = (code[2] << 12) +
207 ((code[0] & 0x0f) << 8) +
211 base = *((guchar **) (sp + S390_REG_SAVE_OFFSET +
212 sizeof(long)*(reg-6)));
214 base = *((guchar **) ((sp - CREATE_STACK_SIZE) +
216 sizeof(long)*(reg-2)));
218 /* Calls that need unboxing use R1 */
220 if ((method->klass->valuetype) &&
221 (!mono_aot_is_got_entry(code, base)))
222 addr = get_unbox_trampoline(method, addr);
224 code = base + displace;
225 if (mono_domain_owns_vtable_slot(mono_domain_get(),
227 s390_patch_addr(code, addr);
229 code = base + displace;
230 s390_patch_addr(code, addr);
239 /*========================= End of Function ========================*/
241 /*------------------------------------------------------------------*/
243 /* Name - s390_class_init_trampoline */
245 /* Function - Initialize a class and then no-op the call to */
246 /* the trampoline. */
248 /*------------------------------------------------------------------*/
251 s390_class_init_trampoline (void *vtable, guchar *code, char *sp)
253 char patch[2] = {0x07, 0x00};
255 mono_runtime_class_init (vtable);
259 memcpy(code, patch, sizeof(patch));
262 /*========================= End of Function ========================*/
264 /*------------------------------------------------------------------*/
266 /* Name - mono_arch_create_trampoline_code */
268 /* Function - Create the designated type of trampoline according*/
269 /* to the 'tramp_type' parameter. */
271 /*------------------------------------------------------------------*/
274 mono_arch_create_trampoline_code (MonoTrampolineType tramp_type)
277 guint8 *buf, *code = NULL;
278 int i, offset, lmfOffset;
281 /* Now we'll create in 'buf' the S/390 trampoline code. This
282 is the trampoline code common to all methods */
284 code = buf = mono_global_codeman_reserve(512);
286 /*-----------------------------------------------------------
287 STEP 0: First create a non-standard function prologue with a
288 stack size big enough to save our registers.
289 -----------------------------------------------------------*/
291 s390_stmg (buf, s390_r6, s390_r14, STK_BASE, S390_REG_SAVE_OFFSET);
292 s390_lgr (buf, s390_r11, s390_r15);
293 s390_aghi (buf, STK_BASE, -CREATE_STACK_SIZE);
294 s390_stg (buf, s390_r11, 0, STK_BASE, 0);
295 s390_stg (buf, s390_r1, 0, STK_BASE, METHOD_SAVE_OFFSET);
296 s390_stmg (buf, s390_r2, s390_r5, STK_BASE, CREATE_GR_OFFSET);
298 /* Save the FP registers */
299 offset = CREATE_FP_OFFSET;
300 for (i = s390_f0; i <= s390_f15; ++i) {
301 s390_std (buf, i, 0, STK_BASE, offset);
305 /*----------------------------------------------------------
306 STEP 1: call 'mono_get_lmf_addr()' to get the address of our
307 LMF. We'll need to restore it after the call to
308 's390_magic_trampoline' and before the call to the native
310 ----------------------------------------------------------*/
312 s390_basr (buf, s390_r13, 0);
314 s390_llong(buf, mono_get_lmf_addr);
315 s390_lg (buf, s390_r1, 0, s390_r13, 4);
316 s390_basr (buf, s390_r14, s390_r1);
318 /*---------------------------------------------------------------*/
319 /* we build the MonoLMF structure on the stack - see mini-s390.h */
320 /* Keep in sync with the code in mono_arch_emit_prolog */
321 /*---------------------------------------------------------------*/
322 lmfOffset = CREATE_STACK_SIZE - sizeof(MonoLMF);
324 s390_lgr (buf, s390_r13, STK_BASE);
325 s390_aghi (buf, s390_r13, lmfOffset);
327 /*---------------------------------------------------------------*/
328 /* Set lmf.lmf_addr = jit_tls->lmf */
329 /*---------------------------------------------------------------*/
330 s390_stg (buf, s390_r2, 0, s390_r13,
331 G_STRUCT_OFFSET(MonoLMF, lmf_addr));
333 /*---------------------------------------------------------------*/
334 /* Get current lmf */
335 /*---------------------------------------------------------------*/
336 s390_lg (buf, s390_r0, 0, s390_r2, 0);
338 /*---------------------------------------------------------------*/
339 /* Set our lmf as the current lmf */
340 /*---------------------------------------------------------------*/
341 s390_stg (buf, s390_r13, 0, s390_r2, 0);
343 /*---------------------------------------------------------------*/
344 /* Have our lmf.previous_lmf point to the last lmf */
345 /*---------------------------------------------------------------*/
346 s390_stg (buf, s390_r0, 0, s390_r13,
347 G_STRUCT_OFFSET(MonoLMF, previous_lmf));
349 /*---------------------------------------------------------------*/
350 /* save method info */
351 /*---------------------------------------------------------------*/
352 s390_lg (buf, s390_r1, 0, STK_BASE, METHOD_SAVE_OFFSET);
353 s390_stg (buf, s390_r1, 0, s390_r13,
354 G_STRUCT_OFFSET(MonoLMF, method));
356 /*---------------------------------------------------------------*/
357 /* save the current SP */
358 /*---------------------------------------------------------------*/
359 s390_lg (buf, s390_r1, 0, STK_BASE, 0);
360 s390_stg (buf, s390_r1, 0, s390_r13, G_STRUCT_OFFSET(MonoLMF, ebp));
362 /*---------------------------------------------------------------*/
363 /* save the current IP */
364 /*---------------------------------------------------------------*/
365 if (tramp_type == MONO_TRAMPOLINE_JUMP) {
366 s390_lghi (buf, s390_r1, 0);
368 s390_lg (buf, s390_r1, 0, s390_r1, S390_RET_ADDR_OFFSET);
369 // s390_la (buf, s390_r1, 0, s390_r1, 0);
371 s390_stg (buf, s390_r1, 0, s390_r13, G_STRUCT_OFFSET(MonoLMF, eip));
373 /*---------------------------------------------------------------*/
374 /* Save general and floating point registers */
375 /*---------------------------------------------------------------*/
376 s390_stmg (buf, s390_r2, s390_r12, s390_r13,
377 G_STRUCT_OFFSET(MonoLMF, gregs[2]));
378 for (i = 0; i < 16; i++) {
379 s390_std (buf, i, 0, s390_r13,
380 G_STRUCT_OFFSET(MonoLMF, fregs[i]));
383 /*---------------------------------------------------------------*/
384 /* STEP 2: call 's390_magic_trampoline()', who will compile the */
385 /* code and fix the method vtable entry for us */
386 /*---------------------------------------------------------------*/
390 /* Arg 1: MonoMethod *method. It was put in r1 by the
391 method-specific trampoline code, and then saved before the call
392 to mono_get_lmf_addr()'. */
393 s390_lg (buf, s390_r2, 0, STK_BASE, METHOD_SAVE_OFFSET);
395 /* Arg 2: code (next address to the instruction that called us) */
396 if (tramp_type == MONO_TRAMPOLINE_JUMP) {
397 s390_lghi (buf, s390_r3, 0);
399 s390_lg (buf, s390_r3, 0, s390_r11, S390_RET_ADDR_OFFSET);
402 /* Arg 3: stack pointer */
403 s390_lgr (buf, s390_r4, STK_BASE);
404 s390_ahi (buf, s390_r4, CREATE_STACK_SIZE);
406 /* Calculate call address and call
407 's390_magic_trampoline'. Return value will be in r2 */
408 s390_basr (buf, s390_r13, 0);
410 if (tramp_type == MONO_TRAMPOLINE_CLASS_INIT) {
411 s390_llong(buf, s390_class_init_trampoline);
413 s390_llong(buf, s390_magic_trampoline);
415 s390_lg (buf, s390_r1, 0, s390_r13, 4);
416 s390_basr (buf, s390_r14, s390_r1);
418 /* OK, code address is now on r2. Move it to r1, so that we
419 can restore r2 and use it from r1 later */
420 s390_lgr (buf, s390_r1, s390_r2);
422 /*----------------------------------------------------------
423 STEP 3: Restore the LMF
424 ----------------------------------------------------------*/
425 restoreLMF(buf, STK_BASE, CREATE_STACK_SIZE);
427 /*----------------------------------------------------------
428 STEP 4: call the compiled method
429 ----------------------------------------------------------*/
431 /* Restore registers */
433 s390_lmg (buf, s390_r2, s390_r5, STK_BASE, CREATE_GR_OFFSET);
435 /* Restore the FP registers */
436 offset = CREATE_FP_OFFSET;
437 for (i = s390_f0; i <= s390_f15; ++i) {
438 s390_ld (buf, i, 0, STK_BASE, offset);
442 /* Restore stack pointer and jump to the code -
443 R14 contains the return address to our caller */
444 s390_lgr (buf, STK_BASE, s390_r11);
445 s390_lmg (buf, s390_r6, s390_r14, STK_BASE, S390_REG_SAVE_OFFSET);
446 s390_br (buf, s390_r1);
448 /* Flush instruction cache, since we've generated code */
449 mono_arch_flush_icache (code, buf - code);
452 g_assert ((buf - code) <= 512);
458 /*========================= End of Function ========================*/
460 /*------------------------------------------------------------------*/
462 /* Name - mono_arch_create_jump_trampoline */
464 /* Function - Create the designated type of trampoline according*/
465 /* to the 'tramp_type' parameter. */
467 /*------------------------------------------------------------------*/
470 mono_arch_create_jump_trampoline (MonoMethod *method)
472 guint8 *code, *buf, *tramp = NULL;
474 MonoDomain *domain = mono_domain_get();
477 tramp = mono_get_trampoline_code (MONO_TRAMPOLINE_JUMP);
479 mono_domain_lock (domain);
480 code = buf = mono_code_manager_reserve (domain->code_mp, JUMP_TRAMPOLINE_SIZE);
481 mono_domain_unlock (domain);
483 s390_basr (buf, s390_r1, 0);
485 s390_llong(buf, method);
486 s390_lg (buf, s390_r1, 0, s390_r1, 4);
487 displace = (tramp - buf) / 2;
488 s390_jcl (buf, S390_CC_UN, displace);
490 mono_arch_flush_icache (code, buf-code);
492 g_assert ((buf - code) <= JUMP_TRAMPOLINE_SIZE);
494 ji = g_new0 (MonoJitInfo, 1);
496 ji->code_start = code;
497 ji->code_size = buf - code;
499 mono_jit_stats.method_trampolines++;
504 /*========================= End of Function ========================*/
506 /*------------------------------------------------------------------*/
508 /* Name - mono_arch_create_jit_trampoline */
510 /* Function - Creates a trampoline function for virtual methods.*/
511 /* If the created code is called it first starts JIT */
512 /* compilation and then calls the newly created */
513 /* method. It also replaces the corresponding vtable */
514 /* entry (see s390_magic_trampoline). */
516 /* A trampoline consists of two parts: a main */
517 /* fragment, shared by all method trampolines, and */
518 /* and some code specific to each method, which */
519 /* hard-codes a reference to that method and then */
520 /* calls the main fragment. */
522 /* The main fragment contains a call to */
523 /* 's390_magic_trampoline', which performs a call */
524 /* to the JIT compiler and substitutes the method- */
525 /* specific fragment with some code that directly */
526 /* calls the JIT-compiled method. */
528 /* Parameter - method - Pointer to the method information */
530 /* Returns - A pointer to the newly created code */
532 /*------------------------------------------------------------------*/
535 mono_arch_create_jit_trampoline (MonoMethod *method)
538 static guint8 *vc = NULL;
541 vc = mono_get_trampoline_code (MONO_TRAMPOLINE_GENERIC);
543 /* This is the method-specific part of the trampoline. Its purpose is
544 to provide the generic part with the MonoMethod *method pointer. We'll
545 use r1 to keep that value, for instance. */
546 code = buf = mono_global_codeman_reserve(METHOD_TRAMPOLINE_SIZE);
548 s390_basr (buf, s390_r1, 0);
550 s390_llong(buf, method);
551 s390_lg (buf, s390_r1, 0, s390_r1, 4);
552 displace = (vc - buf) / 2;
553 s390_jcl (buf, S390_CC_UN, displace);
555 /* Flush instruction cache, since we've generated code */
556 mono_arch_flush_icache (code, buf - code);
559 g_assert ((buf - code) <= METHOD_TRAMPOLINE_SIZE);
564 /*========================= End of Function ========================*/
566 /*------------------------------------------------------------------*/
568 /* Name - mono_arch_create_class_init_trampoline */
570 /* Function - Creates a trampoline function to run a type init- */
571 /* ializer. If the trampoline is called, it calls */
572 /* mono_runtime_class_init with the given vtable, */
573 /* then patches the caller code so it does not get */
574 /* called any more. */
576 /* Parameter - vtable - The type to initialize */
578 /* Returns - A pointer to the newly created code */
580 /*------------------------------------------------------------------*/
583 mono_arch_create_class_init_trampoline (MonoVTable *vtable)
585 guint8 *code, *buf, *tramp;
587 tramp = mono_get_trampoline_code (MONO_TRAMPOLINE_CLASS_INIT);
589 /*-----------------------------------------------------------*/
590 /* This is the method-specific part of the trampoline. Its */
591 /* purpose is to provide the generic part with the MonoMethod*/
592 /* *method pointer. */
593 /*-----------------------------------------------------------*/
594 code = buf = mono_global_codeman_reserve(METHOD_TRAMPOLINE_SIZE);
596 s390_stg (buf, s390_r14, 0, STK_BASE, S390_RET_ADDR_OFFSET);
597 s390_aghi (buf, STK_BASE, -S390_MINIMAL_STACK_SIZE);
599 s390_basr (buf, s390_r1, 0);
601 s390_llong(buf, vtable);
602 s390_llong(buf, s390_class_init_trampoline);
603 s390_lgr (buf, s390_r3, s390_r14);
604 s390_lg (buf, s390_r2, 0, s390_r1, 4);
605 s390_lghi (buf, s390_r4, 0);
606 s390_lg (buf, s390_r1, 0, s390_r1, 12);
607 s390_basr (buf, s390_r14, s390_r1);
609 s390_aghi (buf, STK_BASE, S390_MINIMAL_STACK_SIZE);
610 s390_lg (buf, s390_r14, 0, STK_BASE, S390_RET_ADDR_OFFSET);
611 s390_br (buf, s390_r14);
613 /* Flush instruction cache, since we've generated code */
614 mono_arch_flush_icache (code, buf - code);
617 g_assert ((buf - code) <= METHOD_TRAMPOLINE_SIZE);
619 mono_jit_stats.method_trampolines++;
624 /*========================= End of Function ========================*/
626 /*------------------------------------------------------------------*/
628 /* Name - mono_debuger_create_notification_function */
630 /* Function - This method is only called when running in the */
631 /* Mono debugger. It returns a pointer to the */
632 /* arch specific notification function. */
634 /*------------------------------------------------------------------*/
637 mono_debugger_create_notification_function (gpointer *notification_address)
641 ptr = buf = mono_global_codeman_reserve (16);
643 if (notification_address)
644 *notification_address = buf;
645 s390_br (buf, s390_r14);
650 /*========================= End of Function ========================*/