Minor correction.
[mono.git] / mono / mini / tramp-s390.c
1 /*------------------------------------------------------------------*/
2 /*                                                                  */
3 /* Name        - tramp-s390.c                                       */
4 /*                                                                  */
5 /* Function    - JIT trampoline code for S/390.                     */
6 /*                                                                  */
7 /* Name        - Neale Ferguson (Neale.Ferguson@SoftwareAG-usa.com) */
8 /*                                                                  */
9 /* Date        - January, 2004                                      */
10 /*                                                                  */
11 /* Derivation  - From exceptions-x86 & exceptions-ppc               */
12 /*               Paolo Molaro (lupus@ximian.com)                    */
13 /*               Dietmar Maurer (dietmar@ximian.com)                */
14 /*                                                                  */
15 /* Copyright   - 2001 Ximian, Inc.                                  */
16 /*                                                                  */
17 /*------------------------------------------------------------------*/
18
19 /*------------------------------------------------------------------*/
20 /*                 D e f i n e s                                    */
21 /*------------------------------------------------------------------*/
22
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
30
31 /*------------------------------------------------------------------*/
32 /* adapt to mini later...                                           */
33 /*------------------------------------------------------------------*/
34 #define mono_jit_share_code     (1)
35
36 /*------------------------------------------------------------------*/
37 /* Method-specific trampoline code fragment sizes                   */
38 /*------------------------------------------------------------------*/
39 #define METHOD_TRAMPOLINE_SIZE  64
40 #define JUMP_TRAMPOLINE_SIZE    64
41
42 /*========================= End of Defines =========================*/
43
44 /*------------------------------------------------------------------*/
45 /*                 I n c l u d e s                                  */
46 /*------------------------------------------------------------------*/
47
48 #include <config.h>
49 #include <glib.h>
50 #include <string.h>
51
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>
57
58 #include "mini.h"
59 #include "mini-s390.h"
60
61 /*========================= End of Includes ========================*/
62
63 /*------------------------------------------------------------------*/
64 /*                 T y p e d e f s                                  */
65 /*------------------------------------------------------------------*/
66
67 typedef enum {
68         MONO_TRAMPOLINE_GENERIC,
69         MONO_TRAMPOLINE_JUMP,
70         MONO_TRAMPOLINE_CLASS_INIT
71 } MonoTrampolineType;
72
73 /*========================= End of Typedefs ========================*/
74
75 /*------------------------------------------------------------------*/
76 /*                   P r o t o t y p e s                            */
77 /*------------------------------------------------------------------*/
78
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;
84
85 /*========================= End of Prototypes ======================*/
86
87 /*------------------------------------------------------------------*/
88 /*                 G l o b a l   V a r i a b l e s                  */
89 /*------------------------------------------------------------------*/
90
91
92 /*====================== End of Global Variables ===================*/
93
94 /*------------------------------------------------------------------*/
95 /*                                                                  */
96 /* Name         - get_unbox_trampoline                              */
97 /*                                                                  */
98 /* Function     - Return a pointer to a trampoline which does the   */
99 /*                unboxing before calling the method.               */
100 /*                                                                  */
101 /*                When value type methods are called through the    */
102 /*                vtable we need to unbox the 'this' argument.      */
103 /*                                                                  */
104 /* Parameters   - method - Methd pointer                            */
105 /*                addr   - Pointer to native code for method        */
106 /*                                                                  */
107 /*------------------------------------------------------------------*/
108
109 static gpointer
110 get_unbox_trampoline (MonoMethod *method, gpointer addr)
111 {
112         guint8 *code, *start;
113         int this_pos = s390_r2;
114
115         start = addr;
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)))
121                         this_pos = s390_r3;
122             
123                 start = code = g_malloc (28);
124
125                 s390_basr (code, s390_r13, 0);
126                 s390_j    (code, 4);
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);
131
132                 g_assert ((code - start) <= 28);
133         }
134
135         return start;
136 }
137
138 /*========================= End of Function ========================*/
139
140 /*------------------------------------------------------------------*/
141 /*                                                                  */
142 /* Name         - s390_magic_trampoline                             */
143 /*                                                                  */
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)                             */
155 /*                   bras  %r14,%r1                                 */
156 /*                2. brasl %r14,xxxxxx                              */
157 /*                                                                  */
158 /* Parameters   - code   - Pointer into caller code                 */
159 /*                method - The method to compile                    */
160 /*                sp     - Stack pointer                            */
161 /*                                                                  */
162 /*------------------------------------------------------------------*/
163
164 static gpointer
165 s390_magic_trampoline (MonoMethod *method, guchar *code, char *sp)
166 {
167         gpointer addr;
168         gint32 displace;
169         int reg, base;
170         unsigned short opcode;
171         char *fname;
172         MonoJitInfo *codeJi, 
173                     *addrJi;
174
175         addr = mono_compile_method(method);
176         g_assert(addr);
177
178
179         if (code) {
180
181                 /* The top bit needs to be ignored on S/390 */
182                 (guint32) code &= 0x7fffffff;
183
184                 fname  = mono_method_full_name (method, TRUE);
185                 codeJi = mono_jit_info_table_find (mono_domain_get(), code);
186                 addrJi = mono_jit_info_table_find (mono_domain_get(), addr);
187
188                 opcode = *((unsigned short *) (code - 6));
189                 switch (opcode) {
190                         case 0x5810 :
191                                 /* This is a bras r14,r1 instruction */
192                                 code    -= 4;
193                                 reg      = *code >> 4;
194                                 displace = *((short *)code) & 0x0fff;
195                                 if (reg > 5) 
196                                         base = *((int *) (sp + S390_REG_SAVE_OFFSET+
197                                                                sizeof(int)*(reg-6)));
198                                 else
199                                         base = *((int *) (sp + CREATE_GR_OFFSET+
200                                                                sizeof(int)*(reg-2)));
201                                 addr = get_unbox_trampoline(method, addr);
202                                 if (mono_method_same_domain (codeJi, addrJi)) {
203                                         code = base + displace;
204                                         s390_patch(code, addr);
205                                 }
206                                 break;
207                         case 0xc0e5 :
208                                 /* This is the 'brasl' instruction */
209                                 code    -= 4;
210                                 displace = ((gint32) addr - (gint32) (code - 2)) / 2;
211                                 if (mono_method_same_domain (codeJi, addrJi)) {
212                                         s390_patch (code, displace);
213                                         mono_arch_flush_icache (code, 4);
214                                 }
215                                 break;
216                         default :
217                                 g_error("Unable to patch instruction prior to %p",code);
218                 }
219         }
220
221
222         return addr;
223 }
224
225 /*========================= End of Function ========================*/
226
227 /*------------------------------------------------------------------*/
228 /*                                                                  */
229 /* Name         - s390_class_init_trampoline                        */
230 /*                                                                  */
231 /* Function     - Initialize a class and then no-op the call to     */
232 /*                the trampoline.                                   */
233 /*                                                                  */
234 /*------------------------------------------------------------------*/
235
236 static void
237 s390_class_init_trampoline (void *vtable, guchar *code, char *sp)
238 {
239         char patch[6] = {0x47, 0x00, 0x00, 0x00, 0x07, 0x00};
240
241         mono_runtime_class_init (vtable);
242
243         code = code - 6;
244
245         memcpy(code, patch, sizeof(patch));
246 }
247
248 /*========================= End of Function ========================*/
249
250 /*------------------------------------------------------------------*/
251 /*                                                                  */
252 /* Name         - create_trampoline_code                            */
253 /*                                                                  */
254 /* Function     - Create the designated type of trampoline according*/
255 /*                to the 'tramp_type' parameter.                    */
256 /*                                                                  */
257 /*------------------------------------------------------------------*/
258
259 static guchar*
260 create_trampoline_code (MonoTrampolineType tramp_type)
261 {
262
263         guint8 *buf, *code = NULL;
264         static guint8* generic_jump_trampoline = NULL;
265         static guint8 *generic_class_init_trampoline = NULL;
266         int i, offset;
267
268         switch (tramp_type) {
269         case MONO_TRAMPOLINE_GENERIC:
270                 if (mono_generic_trampoline_code)
271                         return mono_generic_trampoline_code;
272                 break;
273         case MONO_TRAMPOLINE_JUMP:
274                 if (generic_jump_trampoline)
275                         return generic_jump_trampoline;
276                 break;
277         case MONO_TRAMPOLINE_CLASS_INIT:
278                 if (generic_class_init_trampoline)
279                         return generic_class_init_trampoline;
280                 break;
281         }
282
283         if(!code) {
284                 /* Now we'll create in 'buf' the S/390 trampoline code. This
285                  is the trampoline code common to all methods  */
286                 
287                 code = buf = g_malloc(512);
288                 
289                 /*-----------------------------------------------------------
290                 STEP 0: First create a non-standard function prologue with a
291                 stack size big enough to save our registers.
292                 -----------------------------------------------------------*/
293                 
294                 s390_stm  (buf, s390_r6, s390_r14, STK_BASE, S390_REG_SAVE_OFFSET);
295                 s390_lr   (buf, s390_r11, s390_r15);
296                 s390_ahi  (buf, STK_BASE, -CREATE_STACK_SIZE);
297                 s390_st   (buf, s390_r11, 0, STK_BASE, 0);
298                 s390_stm  (buf, s390_r2, s390_r5, STK_BASE, CREATE_GR_OFFSET);
299
300                 /* Save the FP registers */
301                 offset = CREATE_FP_OFFSET;
302                 for (i = s390_f0; i <= s390_f15; ++i) {
303                         s390_std  (buf, i, 0, STK_BASE, offset);
304                         offset += 8;
305                 }
306
307                 /*----------------------------------------------------------
308                 STEP 1: call 'mono_get_lmf_addr()' to get the address of our
309                 LMF. We'll need to restore it after the call to
310                 's390_magic_trampoline' and before the call to the native
311                 method.
312                 ----------------------------------------------------------*/
313                                 
314                 s390_basr (buf, s390_r13, 0);
315                 s390_j    (buf, 4);
316                 s390_word (buf, mono_get_lmf_addr);
317                 s390_l    (buf, s390_r1, 0, s390_r13, 4);
318                 s390_basr (buf, s390_r14, s390_r1);
319
320                 /* XXX Update LMF !!! */
321                 
322                 /*----------------------------------------------------------
323                 STEP 2: call 's390_magic_trampoline()', who will compile the
324                 code and fix the method vtable entry for us
325                 ----------------------------------------------------------*/
326                                 
327                 /* Set arguments */
328                 
329                 /* Arg 1: MonoMethod *method. It was put in r11 by the
330                 method-specific trampoline code, and then saved before the call
331                 to mono_get_lmf_addr()'. Restore r13, by the way :-) */
332                 s390_l  (buf, s390_r2, 0, s390_r11, METHOD_SAVE_OFFSET);
333                 
334                 /* Arg 2: code (next address to the instruction that called us) */
335                 if (tramp_type == MONO_TRAMPOLINE_JUMP) {
336                         s390_lhi (buf, s390_r3, 0);
337                 } else {
338                         s390_l  (buf, s390_r3, 0, s390_r11, S390_RET_ADDR_OFFSET);
339                 }
340                 
341                 /* Arg 3: stack pointer */
342                 s390_lr   (buf, s390_r4, STK_BASE);
343                 
344                 /* Calculate call address and call
345                 's390_magic_trampoline'. Return value will be in r2 */
346                 s390_basr (buf, s390_r13, 0);
347                 s390_j    (buf, 4);
348                 if (tramp_type == MONO_TRAMPOLINE_CLASS_INIT) {
349                         s390_word (buf, s390_class_init_trampoline);
350                 } else {
351                         s390_word (buf, s390_magic_trampoline);
352                 }
353                 s390_l    (buf, s390_r1, 0, s390_r13, 4);
354                 s390_basr (buf, s390_r14, s390_r1);
355                 
356                 /* OK, code address is now on r2. Move it to r1, so that we
357                 can restore r2 and use it from r1 later */
358                 s390_lr   (buf, s390_r1, s390_r2);
359                 
360
361                 /*----------------------------------------------------------
362                 STEP 3: Restore the LMF
363                 ----------------------------------------------------------*/
364                 
365                 /* XXX Do it !!! */
366                 
367                 /*----------------------------------------------------------
368                 STEP 4: call the compiled method
369                 ----------------------------------------------------------*/
370                 
371                 /* Restore registers */
372
373                 s390_lm   (buf, s390_r2, s390_r5, STK_BASE, CREATE_GR_OFFSET);
374                 
375                 /* Restore the FP registers */
376                 offset = CREATE_FP_OFFSET;
377                 for (i = s390_f0; i <= s390_f15; ++i) {
378                         s390_ld  (buf, i, 0, STK_BASE, offset);
379                         offset += 8;
380                 }
381
382                 /* Restore stack pointer and jump to the code - 
383                    R14 contains the return address to our caller */
384                 s390_lr   (buf, STK_BASE, s390_r11);
385                 s390_lm   (buf, s390_r6, s390_r14, STK_BASE, S390_REG_SAVE_OFFSET);
386                 s390_br   (buf, s390_r1);
387
388                 /* Flush instruction cache, since we've generated code */
389                 mono_arch_flush_icache (code, buf - code);
390         
391                 /* Sanity check */
392                 g_assert ((buf - code) <= 512);
393         }
394
395         switch (tramp_type) {
396         case MONO_TRAMPOLINE_GENERIC:
397                 mono_generic_trampoline_code = code;
398                 break;
399         case MONO_TRAMPOLINE_JUMP:
400                 generic_jump_trampoline = code;
401                 break;
402         case MONO_TRAMPOLINE_CLASS_INIT:
403                 generic_class_init_trampoline = code;
404                 break;
405         }
406
407         return code;
408 }
409
410 /*========================= End of Function ========================*/
411
412 /*------------------------------------------------------------------*/
413 /*                                                                  */
414 /* Name         - mono_arch_create_jump_trampoline                  */
415 /*                                                                  */
416 /* Function     - Create the designated type of trampoline according*/
417 /*                to the 'tramp_type' parameter.                    */
418 /*                                                                  */
419 /*------------------------------------------------------------------*/
420
421 MonoJitInfo *
422 mono_arch_create_jump_trampoline (MonoMethod *method)
423 {
424         guint8 *code, *buf, *tramp = NULL;
425         MonoJitInfo *ji;
426         MonoDomain *domain = mono_domain_get();
427         gint32 displace;
428
429         tramp = create_trampoline_code (MONO_TRAMPOLINE_JUMP);
430
431         mono_domain_lock (domain);
432         code = buf = mono_code_manager_reserve (domain->code_mp, METHOD_TRAMPOLINE_SIZE);
433         mono_domain_unlock (domain);
434
435         s390_basr (buf, s390_r13, 0);
436         s390_j    (buf, 4);
437         s390_word (buf, method);
438         s390_l    (buf, s390_r13, 0, s390_r13, 4);
439         displace = (tramp - buf) / 2;
440         s390_jcl  (buf, S390_CC_UN, displace);
441
442         mono_arch_flush_icache (code, buf-code);
443
444         g_assert ((buf - code) <= JUMP_TRAMPOLINE_SIZE);
445         
446         ji              = g_new0 (MonoJitInfo, 1);
447         ji->method      = method;
448         ji->code_start  = code;
449         ji->code_size   = buf - code;
450         
451         mono_jit_stats.method_trampolines++;
452
453         return ji;
454 }
455
456 /*========================= End of Function ========================*/
457
458 /*------------------------------------------------------------------*/
459 /*                                                                  */
460 /* Name         - mono_arch_create_jit_trampoline                   */
461 /*                                                                  */
462 /* Function     - Creates a trampoline function for virtual methods.*/
463 /*                If the created code is called it first starts JIT */
464 /*                compilation and then calls the newly created      */
465 /*                method. It also replaces the corresponding vtable */
466 /*                entry (see s390_magic_trampoline).                */
467 /*                                                                  */
468 /*                A trampoline consists of two parts: a main        */
469 /*                fragment, shared by all method trampolines, and   */
470 /*                and some code specific to each method, which      */
471 /*                hard-codes a reference to that method and then    */
472 /*                calls the main fragment.                          */
473 /*                                                                  */
474 /*                The main fragment contains a call to              */
475 /*                's390_magic_trampoline', which performs a call    */
476 /*                to the JIT compiler and substitutes the method-   */
477 /*                specific fragment with some code that directly    */
478 /*                calls the JIT-compiled method.                    */
479 /*                                                                  */
480 /* Parameter    - method - Pointer to the method information        */
481 /*                                                                  */
482 /* Returns      - A pointer to the newly created code               */
483 /*                                                                  */
484 /*------------------------------------------------------------------*/
485
486 gpointer
487 mono_arch_create_jit_trampoline (MonoMethod *method)
488 {
489         guint8 *code, *buf;
490         static guint8 *vc = NULL;
491         gint32 displace;
492
493         vc = create_trampoline_code (MONO_TRAMPOLINE_GENERIC);
494
495         /* This is the method-specific part of the trampoline. Its purpose is
496         to provide the generic part with the MonoMethod *method pointer. We'll
497         use r13 to keep that value, for instance. However, the generic part of
498         the trampoline relies on r11 having the same value it had before coming
499         here, so we must save it before. */
500         code = buf = g_malloc(METHOD_TRAMPOLINE_SIZE);
501
502         s390_basr (buf, s390_r13, 0);
503         s390_j    (buf, 4);
504         s390_word (buf, method);
505         s390_l    (buf, s390_r13, 0, s390_r13, 4);
506         displace = (vc - buf) / 2;
507         s390_jcl  (buf, S390_CC_UN, displace);
508
509         /* Flush instruction cache, since we've generated code */
510         mono_arch_flush_icache (code, buf - code);
511                 
512         /* Sanity check */
513         g_assert ((buf - code) <= METHOD_TRAMPOLINE_SIZE);
514         
515         mono_jit_stats.method_trampolines++;
516
517         return code;
518 }
519
520 /*========================= End of Function ========================*/
521
522 /*------------------------------------------------------------------*/
523 /*                                                                  */
524 /* Name         - mono_arch_create_class_init_trampoline            */
525 /*                                                                  */
526 /* Function     - Creates a trampoline function to run a type init- */
527 /*                ializer. If the trampoline is called, it calls    */
528 /*                mono_runtime_class_init with the given vtable,    */
529 /*                then patches the caller code so it does not get   */
530 /*                called any more.                                  */
531 /*                                                                  */
532 /* Parameter    - vtable - The type to initialize                   */
533 /*                                                                  */
534 /* Returns      - A pointer to the newly created code               */
535 /*                                                                  */
536 /*------------------------------------------------------------------*/
537
538 gpointer
539 mono_arch_create_class_init_trampoline (MonoVTable *vtable)
540 {
541         guint8 *code, *buf, *tramp;
542
543         tramp = create_trampoline_code (MONO_TRAMPOLINE_CLASS_INIT);
544
545         /* This is the method-specific part of the trampoline. Its purpose is
546         to provide the generic part with the MonoMethod *method pointer. We'll
547         use r11 to keep that value, for instance. However, the generic part of
548         the trampoline relies on r11 having the same value it had before coming
549         here, so we must save it before. */
550         code = buf = g_malloc(METHOD_TRAMPOLINE_SIZE);
551
552         s390_st   (buf, s390_r14, 0, STK_BASE, S390_RET_ADDR_OFFSET);
553         s390_ahi  (buf, STK_BASE, -S390_MINIMAL_STACK_SIZE);
554
555         s390_basr (buf, s390_r1, 0);
556         s390_j    (buf, 6);
557         s390_word (buf, vtable);
558         s390_word (buf, s390_class_init_trampoline);
559         s390_lr   (buf, s390_r3, s390_r14);
560         s390_l    (buf, s390_r2, 0, s390_r1, 4);
561         s390_lhi  (buf, s390_r4, 0);
562         s390_l    (buf, s390_r1, 0, s390_r1, 8);
563         s390_basr (buf, s390_r14, s390_r1);
564
565         s390_ahi  (buf, STK_BASE, S390_MINIMAL_STACK_SIZE);
566         s390_l    (buf, s390_r14, 0, STK_BASE, S390_RET_ADDR_OFFSET);
567         s390_br   (buf, s390_r14);
568
569         /* Flush instruction cache, since we've generated code */
570         mono_arch_flush_icache (code, buf - code);
571                 
572         /* Sanity check */
573         g_assert ((buf - code) <= METHOD_TRAMPOLINE_SIZE);
574
575         mono_jit_stats.method_trampolines++;
576
577         return code;
578 }
579
580 /*========================= End of Function ========================*/
581
582 /*------------------------------------------------------------------*/
583 /*                                                                  */
584 /* Name         - mono_debuger_create_notification_function         */
585 /*                                                                  */
586 /* Function     - This method is only called when running in the    */
587 /*                Mono debugger. It returns a pointer to the        */
588 /*                arch specific notification function.              */
589 /*                                                                  */
590 /*------------------------------------------------------------------*/
591
592 gpointer
593 mono_debugger_create_notification_function (gpointer *notification_address)
594 {
595         guint8 *ptr, *buf;
596
597         ptr = buf = g_malloc0 (16);
598         s390_break (buf);
599         if (notification_address)
600                 *notification_address = buf;
601         s390_br (buf, s390_r14);
602
603         return ptr;
604 }
605
606 /*========================= End of Function ========================*/