fa664e12e11f8b57ae731c0a7afd29404193589f
[mono.git] / mono / mini / tramp-s390x.c
1 /*------------------------------------------------------------------*/
2 /*                                                                  */
3 /* Name        - tramp-s390x.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 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))
30 #define GENERIC_REG_OFFSET      CREATE_STACK_SIZE + \
31                                 S390_REG_SAVE_OFFSET + \
32                                 3*sizeof(long)
33
34 /*------------------------------------------------------------------*/
35 /* Method-specific trampoline code fragment sizes                   */
36 /*------------------------------------------------------------------*/
37 #define SPECIFIC_TRAMPOLINE_SIZE        96
38
39 /*========================= End of Defines =========================*/
40
41 /*------------------------------------------------------------------*/
42 /*                 I n c l u d e s                                  */
43 /*------------------------------------------------------------------*/
44
45 #include <config.h>
46 #include <glib.h>
47 #include <string.h>
48
49 #include <mono/metadata/abi-details.h>
50 #include <mono/metadata/appdomain.h>
51 #include <mono/metadata/marshal.h>
52 #include <mono/metadata/tabledefs.h>
53 #include <mono/arch/s390x/s390x-codegen.h>
54
55 #include "mini.h"
56 #include "mini-s390x.h"
57 #include "support-s390x.h"
58
59 /*========================= End of Includes ========================*/
60
61 /*------------------------------------------------------------------*/
62 /*                 T y p e d e f s                                  */
63 /*------------------------------------------------------------------*/
64
65 /*========================= End of Typedefs ========================*/
66
67 /*------------------------------------------------------------------*/
68 /*                   P r o t o t y p e s                            */
69 /*------------------------------------------------------------------*/
70
71 /*========================= End of Prototypes ======================*/
72
73 /*------------------------------------------------------------------*/
74 /*                 G l o b a l   V a r i a b l e s                  */
75 /*------------------------------------------------------------------*/
76
77
78 /*====================== End of Global Variables ===================*/
79
80 /*------------------------------------------------------------------*/
81 /*                                                                  */
82 /* Name         - mono_arch_get_unbox_trampoline                    */
83 /*                                                                  */
84 /* Function     - Return a pointer to a trampoline which does the   */
85 /*                unboxing before calling the method.               */
86 /*                                                                  */
87 /*                When value type methods are called through the    */
88 /*                vtable we need to unbox the 'this' argument.      */
89 /*                                                                  */
90 /* Parameters   - method - Methd pointer                            */
91 /*                addr   - Pointer to native code for method        */
92 /*                                                                  */
93 /*------------------------------------------------------------------*/
94
95 gpointer
96 mono_arch_get_unbox_trampoline (MonoMethod *method, gpointer addr)
97 {
98         guint8 *code, *start;
99         int this_pos = s390_r2;
100         MonoDomain *domain = mono_domain_get ();
101
102         start = code = mono_domain_code_reserve (domain, 28);
103
104         S390_SET  (code, s390_r1, addr);
105         s390_aghi (code, this_pos, sizeof(MonoObject));
106         s390_br   (code, s390_r1);
107
108         g_assert ((code - start) <= 28);
109
110         mono_arch_flush_icache (start, code - start);
111
112         return start;
113 }
114
115 /*========================= End of Function ========================*/
116
117 /*------------------------------------------------------------------*/
118 /*                                                                  */
119 /* Name         - mono_arch_patch_callsite                          */
120 /*                                                                  */
121 /* Function     - Patch a non-virtual callsite so it calls @addr.   */
122 /*                                                                  */
123 /*------------------------------------------------------------------*/
124
125 void
126 mono_arch_patch_callsite (guint8 *method_start, guint8 *orig_code, guint8 *addr)
127 {
128         gint32 displace;
129         unsigned short opcode;
130
131         opcode = *((unsigned short *) (orig_code - 2));
132         if (opcode == 0x0dee) {
133                 /* This should be a 'iihf/iilf' sequence */
134                 S390_EMIT_CALL((orig_code - 14), addr);
135                 mono_arch_flush_icache (orig_code - 14, 12);
136         } else {
137 fprintf(stderr, "%p %02x %02x %02x %02x\n",
138 &orig_code[-14], orig_code[-12], orig_code[-11], orig_code[-6], orig_code[-5]);
139 fflush(stderr);
140                 /* This is the 'brasl' instruction */
141                 orig_code    -= 4;
142                 displace = ((gssize) addr - (gssize) (orig_code - 2)) / 2;
143                 s390_patch_rel (orig_code, displace);
144                 mono_arch_flush_icache (orig_code, 4);
145         }
146 }
147
148 /*========================= End of Function ========================*/
149
150 /*------------------------------------------------------------------*/
151 /*                                                                  */
152 /* Name         - mono_arch_patch_plt_entry.                        */
153 /*                                                                  */
154 /* Function     - Patch a PLT entry - unused as yet.                */
155 /*                                                                  */
156 /*------------------------------------------------------------------*/
157
158 void
159 mono_arch_patch_plt_entry (guint8 *code, gpointer *got, mgreg_t *regs, guint8 *addr)
160 {
161         g_assert_not_reached ();
162 }
163
164 /*========================= End of Function ========================*/
165
166 /*------------------------------------------------------------------*/
167 /*                                                                  */
168 /* Name         - mono_arch_nullify_class_init_trampoline           */
169 /*                                                                  */
170 /* Function     - Nullify a call which calls a class init trampoline*/
171 /*                                                                  */
172 /*------------------------------------------------------------------*/
173
174 void
175 mono_arch_nullify_class_init_trampoline (guint8 *code, mgreg_t *regs)
176 {
177         char patch[2] = {0x07, 0x00};
178
179         code = code - 2;
180
181         memcpy(code, patch, sizeof(patch));
182 }
183
184 /*========================= End of Function ========================*/
185
186 /*------------------------------------------------------------------*/
187 /*                                                                  */
188 /* Name         - mono_arch_get_nullified_class_init                */
189 /*                                                                  */
190 /* Function     - Nullify a PLT entry call.                         */
191 /*                                                                  */
192 /*------------------------------------------------------------------*/
193
194 gpointer
195 mono_arch_get_nullified_class_init_trampoline (MonoTrampInfo **info)
196 {
197         guint8 *buf, *code;
198
199         code = buf = mono_global_codeman_reserve (16);
200
201         s390_br (code, s390_r14);
202
203         if (info)
204                 *info = mono_tramp_info_create ("nullified_class_init_trampoline", 
205                                                 buf, code - buf, NULL, NULL);
206
207         return (buf);
208 }
209
210 /*========================= End of Function ========================*/
211
212 /*------------------------------------------------------------------*/
213 /*                                                                  */
214 /* Name         - mono_arch_create_trampoline_code                  */
215 /*                                                                  */
216 /* Function     - Create the designated type of trampoline according*/
217 /*                to the 'tramp_type' parameter.                    */
218 /*                                                                  */
219 /*------------------------------------------------------------------*/
220
221 guchar*
222 mono_arch_create_generic_trampoline (MonoTrampolineType tramp_type, MonoTrampInfo **info, gboolean aot)
223 {
224         char *tramp_name;
225         guint8 *buf, *tramp, *code;
226         int i, offset, lmfOffset, has_caller;
227         GSList *unwind_ops = NULL;
228         MonoJumpInfo *ji = NULL;
229
230         g_assert (!aot);
231
232         /* Now we'll create in 'buf' the S/390 trampoline code. This
233            is the trampoline code common to all methods  */
234                 
235         code = buf = mono_global_codeman_reserve(512);
236                 
237         if ((tramp_type == MONO_TRAMPOLINE_JUMP) ||
238             (tramp_type == MONO_TRAMPOLINE_HANDLER_BLOCK_GUARD)) 
239                 has_caller = 0;
240         else
241                 has_caller = 1;
242
243         /*-----------------------------------------------------------
244           STEP 0: First create a non-standard function prologue with a
245           stack size big enough to save our registers.
246           -----------------------------------------------------------*/
247                 
248         s390_stmg (buf, s390_r6, s390_r15, STK_BASE, S390_REG_SAVE_OFFSET);
249         s390_lgr  (buf, s390_r11, s390_r15);
250         s390_aghi (buf, STK_BASE, -CREATE_STACK_SIZE);
251         s390_stg  (buf, s390_r11, 0, STK_BASE, 0);
252         s390_stg  (buf, s390_r1, 0, STK_BASE, METHOD_SAVE_OFFSET);
253         s390_stmg (buf, s390_r2, s390_r5, STK_BASE, CREATE_GR_OFFSET);
254
255         /* Save the FP registers */
256         offset = CREATE_FP_OFFSET;
257         for (i = s390_f0; i <= s390_f15; ++i) {
258                 s390_std  (buf, i, 0, STK_BASE, offset);
259                 offset += 8;
260         }
261
262         /*----------------------------------------------------------
263           STEP 1: call 'mono_get_lmf_addr()' to get the address of our
264           LMF. We'll need to restore it after the call to
265           's390_magic_trampoline' and before the call to the native
266           method.
267           ----------------------------------------------------------*/
268                                 
269         S390_SET  (buf, s390_r1, mono_get_lmf_addr);
270         s390_basr (buf, s390_r14, s390_r1);
271
272         /*---------------------------------------------------------------*/
273         /* we build the MonoLMF structure on the stack - see mini-s390.h */
274         /* Keep in sync with the code in mono_arch_emit_prolog           */
275         /*---------------------------------------------------------------*/
276         lmfOffset = CREATE_STACK_SIZE - sizeof(MonoLMF);
277                                                                                         
278         s390_lgr   (buf, s390_r13, STK_BASE);
279         s390_aghi  (buf, s390_r13, lmfOffset);  
280                                                                                         
281         /*---------------------------------------------------------------*/     
282         /* Set lmf.lmf_addr = jit_tls->lmf                               */     
283         /*---------------------------------------------------------------*/     
284         s390_stg   (buf, s390_r2, 0, s390_r13,                          
285                             G_STRUCT_OFFSET(MonoLMF, lmf_addr));                        
286                                                                                         
287         /*---------------------------------------------------------------*/     
288         /* Get current lmf                                               */     
289         /*---------------------------------------------------------------*/     
290         s390_lg    (buf, s390_r0, 0, s390_r2, 0);                               
291                                                                                         
292         /*---------------------------------------------------------------*/     
293         /* Set our lmf as the current lmf                                */     
294         /*---------------------------------------------------------------*/     
295         s390_stg   (buf, s390_r13, 0, s390_r2, 0);                              
296                                                                                         
297         /*---------------------------------------------------------------*/     
298         /* Have our lmf.previous_lmf point to the last lmf               */     
299         /*---------------------------------------------------------------*/     
300         s390_stg   (buf, s390_r0, 0, s390_r13,                          
301                             G_STRUCT_OFFSET(MonoLMF, previous_lmf));                    
302                                                                                         
303         /*---------------------------------------------------------------*/     
304         /* save method info                                              */     
305         /*---------------------------------------------------------------*/     
306         s390_lg    (buf, s390_r1, 0, STK_BASE, METHOD_SAVE_OFFSET);
307         s390_stg   (buf, s390_r1, 0, s390_r13,                          
308                             G_STRUCT_OFFSET(MonoLMF, method));                          
309                                                                         
310         /*---------------------------------------------------------------*/     
311         /* save the current SP                                           */     
312         /*---------------------------------------------------------------*/     
313         s390_lg    (buf, s390_r1, 0, STK_BASE, 0);
314         s390_stg   (buf, s390_r1, 0, s390_r13, G_STRUCT_OFFSET(MonoLMF, ebp));  
315                                                                         
316         /*---------------------------------------------------------------*/     
317         /* save the current IP                                           */     
318         /*---------------------------------------------------------------*/     
319         if (has_caller) {
320                 s390_lg    (buf, s390_r1, 0, s390_r1, S390_RET_ADDR_OFFSET);
321         } else {
322                 s390_lghi  (buf, s390_r1, 0);
323         }
324         s390_stg   (buf, s390_r1, 0, s390_r13, G_STRUCT_OFFSET(MonoLMF, eip));  
325                                                                                         
326         /*---------------------------------------------------------------*/     
327         /* Save general and floating point registers                     */     
328         /*---------------------------------------------------------------*/     
329         s390_mvc   (buf, 4*sizeof(gulong), s390_r13, G_STRUCT_OFFSET(MonoLMF, gregs[2]), 
330                     STK_BASE, CREATE_GR_OFFSET);
331         s390_mvc   (buf, 10*sizeof(gulong), s390_r13, G_STRUCT_OFFSET(MonoLMF, gregs[6]), 
332                     s390_r11, S390_REG_SAVE_OFFSET);
333
334         /* Simply copy fpregs already saved above                        */
335         s390_mvc   (buf, 16*sizeof(double), s390_r13, G_STRUCT_OFFSET(MonoLMF, fregs[0]),
336                     STK_BASE, CREATE_FP_OFFSET);
337
338         /*---------------------------------------------------------------*/
339         /* STEP 2: call the C trampoline function                        */
340         /*---------------------------------------------------------------*/
341                                 
342         /* Set arguments */
343
344         /* Arg 1: mgreg_t *regs. We pass sp instead */
345         s390_la  (buf, s390_r2, 0, STK_BASE, CREATE_STACK_SIZE);
346                 
347         /* Arg 2: code (next address to the instruction that called us) */
348         if (has_caller) {
349                 s390_lg   (buf, s390_r3, 0, s390_r11, S390_RET_ADDR_OFFSET);
350         } else {
351                 s390_lghi (buf, s390_r3, 0);
352         }
353
354         /* Arg 3: Trampoline argument */
355         if (tramp_type == MONO_TRAMPOLINE_GENERIC_CLASS_INIT)
356                 s390_lg (buf, s390_r4, 0, STK_BASE, GENERIC_REG_OFFSET);
357         else
358                 s390_lg (buf, s390_r4, 0, STK_BASE, METHOD_SAVE_OFFSET);
359
360         /* Arg 4: trampoline address. Ignore for now */
361                 
362         /* Calculate call address and call the C trampoline. Return value will be in r2 */
363         tramp = (guint8*)mono_get_trampoline_func (tramp_type);
364         S390_SET  (buf, s390_r1, tramp);
365         s390_basr (buf, s390_r14, s390_r1);
366                 
367         /* OK, code address is now on r2. Move it to r1, so that we
368            can restore r2 and use it from r1 later */
369         s390_lgr  (buf, s390_r1, s390_r2);
370
371         /*----------------------------------------------------------
372           STEP 3: Restore the LMF
373           ----------------------------------------------------------*/
374         restoreLMF(buf, STK_BASE, CREATE_STACK_SIZE);
375         
376         /*----------------------------------------------------------
377           STEP 4: call the compiled method
378           ----------------------------------------------------------*/
379                 
380         /* Restore registers */
381
382         s390_lmg  (buf, s390_r2, s390_r5, STK_BASE, CREATE_GR_OFFSET);
383                 
384         /* Restore the FP registers */
385         offset = CREATE_FP_OFFSET;
386         for (i = s390_f0; i <= s390_f15; ++i) {
387                 s390_ld  (buf, i, 0, STK_BASE, offset);
388                 offset += 8;
389         }
390
391         /* Restore stack pointer and jump to the code -
392            R14 contains the return address to our caller */
393         s390_lgr  (buf, STK_BASE, s390_r11);
394         s390_lmg  (buf, s390_r6, s390_r14, STK_BASE, S390_REG_SAVE_OFFSET);
395
396         if (MONO_TRAMPOLINE_TYPE_MUST_RETURN(tramp_type)) {
397                 s390_lgr (buf, s390_r2, s390_r1);
398                 s390_br  (buf, s390_r14);
399         } else {
400                 s390_br  (buf, s390_r1);
401         }
402
403         /* Flush instruction cache, since we've generated code */
404         mono_arch_flush_icache (code, buf - code);
405         
406         if (info) {
407                 tramp_name = mono_get_generic_trampoline_name (tramp_type);
408                 *info = mono_tramp_info_create (tramp_name, buf, buf - code, ji, unwind_ops);
409                 g_free (tramp_name);
410         }
411
412         /* Sanity check */
413         g_assert ((buf - code) <= 512);
414
415         return code;
416 }
417
418 /*========================= End of Function ========================*/
419
420 /*------------------------------------------------------------------*/
421 /*                                                                  */
422 /* Name         - mono_arch_invalidate_method                       */
423 /*                                                                  */
424 /* Function     -                                                   */
425 /*                                                                  */
426 /*------------------------------------------------------------------*/
427
428 void
429 mono_arch_invalidate_method (MonoJitInfo *ji, void *func, gpointer func_arg)
430 {
431         /* FIXME: This is not thread safe */
432         guint8 *code = ji->code_start;
433
434         S390_SET  (code, s390_r1, func);
435         S390_SET  (code, s390_r2, func_arg);
436         s390_br   (code, s390_r1);
437
438 }
439
440 /*========================= End of Function ========================*/
441
442 /*------------------------------------------------------------------*/
443 /*                                                                  */
444 /* Name         - mono_arch_create_specific_trampoline              */
445 /*                                                                  */
446 /* Function     - Creates the given kind of specific trampoline     */
447 /*                                                                  */
448 /*------------------------------------------------------------------*/
449
450 gpointer
451 mono_arch_create_specific_trampoline (gpointer arg1, MonoTrampolineType tramp_type, MonoDomain *domain, guint32 *code_len)
452 {
453         guint8 *code, *buf, *tramp;
454         gint32 displace;
455
456         tramp = mono_get_trampoline_code (tramp_type);
457
458         /*----------------------------------------------------------*/
459         /* This is the method-specific part of the trampoline. Its  */
460         /* purpose is to provide the generic part with the          */
461         /* MonoMethod *method pointer. We'll use r1 to keep it.     */
462         /*----------------------------------------------------------*/
463         code = buf = mono_domain_code_reserve (domain, SPECIFIC_TRAMPOLINE_SIZE);
464
465         S390_SET  (buf, s390_r1, arg1);
466         displace = (tramp - buf) / 2;
467         s390_jg   (buf, displace);
468
469         /* Flush instruction cache, since we've generated code */
470         mono_arch_flush_icache (code, buf - code);
471
472         /* Sanity check */
473         g_assert ((buf - code) <= SPECIFIC_TRAMPOLINE_SIZE);
474
475         if (code_len)
476                 *code_len = buf - code;
477         
478         return code;
479 }       
480
481 /*========================= End of Function ========================*/
482
483 /*------------------------------------------------------------------*/
484 /*                                                                  */
485 /* Name         - mono_arch_create_rgctx_lazy_fetch_trampoline      */
486 /*                                                                  */
487 /* Function     -                                                   */
488 /*                                                                  */
489 /*------------------------------------------------------------------*/
490
491 gpointer
492 mono_arch_create_rgctx_lazy_fetch_trampoline (guint32 slot, MonoTrampInfo **info, gboolean aot)
493 {
494 #ifdef MONO_ARCH_VTABLE_REG
495         guint8 *tramp;
496         guint8 *code, *buf;
497         guint8 **rgctx_null_jumps;
498         gint32 displace;
499         int tramp_size,
500             depth, 
501             index, 
502             iPatch = 0,
503             i;
504         gboolean mrgctx;
505         MonoJumpInfo *ji = NULL;
506         GSList *unwind_ops = NULL;
507
508         mrgctx = MONO_RGCTX_SLOT_IS_MRGCTX (slot);
509         index = MONO_RGCTX_SLOT_INDEX (slot);
510         if (mrgctx)
511                 index += MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
512         for (depth = 0; ; ++depth) {
513                 int size = mono_class_rgctx_get_array_size (depth, mrgctx);
514
515                 if (index < size - 1)
516                         break;
517                 index -= size - 1;
518         }
519
520         tramp_size = 48 + 16 * depth;
521         if (mrgctx)
522                 tramp_size += 4;
523         else
524                 tramp_size += 12;
525
526         code = buf = mono_global_codeman_reserve (tramp_size);
527
528         unwind_ops = mono_arch_get_cie_program ();
529
530         rgctx_null_jumps = g_malloc (sizeof (guint8*) * (depth + 2));
531
532         if (mrgctx) {
533                 /* get mrgctx ptr */
534                 s390_lgr (code, s390_r1, s390_r2);
535         } else {
536                 /* load rgctx ptr from vtable */
537                 s390_lg (code, s390_r1, 0, s390_r2, MONO_STRUCT_OFFSET(MonoVTable, runtime_generic_context));
538                 /* is the rgctx ptr null? */
539                 s390_ltgr (code, s390_r1, s390_r1);
540                 /* if yes, jump to actual trampoline */
541                 rgctx_null_jumps [iPatch++] = code;
542                 s390_jge (code, 0);
543         }
544
545         for (i = 0; i < depth; ++i) {
546                 /* load ptr to next array */
547                 if (mrgctx && i == 0)
548                         s390_lg (code, s390_r1, 0, s390_r1, MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT);
549                 else
550                         s390_lg (code, s390_r1, 0, s390_r1, 0);
551                 s390_ltgr (code, s390_r1, s390_r1);
552                 /* if the ptr is null then jump to actual trampoline */
553                 rgctx_null_jumps [iPatch++] = code;
554                 s390_jge (code, 0);
555         }
556
557         /* fetch slot */
558         s390_lg (code, s390_r1, 0, s390_r1, (sizeof (gpointer) * (index  + 1)));
559         /* is the slot null? */
560         s390_ltgr (code, s390_r1, s390_r1);
561         /* if yes, jump to actual trampoline */
562         rgctx_null_jumps [iPatch++] = code;
563         s390_jge (code, 0);
564         /* otherwise return r1 */
565         s390_lgr (code, s390_r2, s390_r1);
566         s390_br  (code, s390_r14);
567
568         for (i = 0; i < iPatch; i++) {
569                 displace = ((uintptr_t) code - (uintptr_t) rgctx_null_jumps[i]) / 2;
570                 s390_patch_rel ((rgctx_null_jumps [i] + 2), displace);
571         }
572
573         g_free (rgctx_null_jumps);
574
575         /* move the rgctx pointer to the VTABLE register */
576         s390_lgr (code, MONO_ARCH_VTABLE_REG, s390_r2);
577
578         tramp = mono_arch_create_specific_trampoline (GUINT_TO_POINTER (slot),
579                 MONO_TRAMPOLINE_RGCTX_LAZY_FETCH, mono_get_root_domain (), NULL);
580
581         /* jump to the actual trampoline */
582         displace = (tramp - code) / 2;
583         s390_jg (code, displace);
584
585         mono_arch_flush_icache (buf, code - buf);
586
587         g_assert (code - buf <= tramp_size);
588
589         if (info) {
590                 char *name = mono_get_rgctx_fetch_trampoline_name (slot);
591                 *info = mono_tramp_info_create (name, buf, code - buf, ji, unwind_ops);
592                 g_free (name);
593         }
594
595         return(buf);
596 #else
597         g_assert_not_reached ();
598 #endif
599         return(NULL);
600 }       
601
602 /*========================= End of Function ========================*/
603
604 /*------------------------------------------------------------------*/
605 /*                                                                  */
606 /* Name         - mono_arch_get_static_rgctx_trampoline             */
607 /*                                                                  */
608 /* Function     - Create a trampoline which sets RGCTX_REG to MRGCTX*/
609 /*                then jumps to ADDR.                               */
610 /*                                                                  */
611 /*------------------------------------------------------------------*/
612
613 gpointer
614 mono_arch_get_static_rgctx_trampoline (MonoMethod *m, 
615                                         MonoMethodRuntimeGenericContext *mrgctx, 
616                                         gpointer addr)
617 {
618         guint8 *code, *start;
619         gint32 displace;
620         int buf_len;
621
622         MonoDomain *domain = mono_domain_get ();
623
624         buf_len = 32;
625
626         start = code = mono_domain_code_reserve (domain, buf_len);
627
628         S390_SET  (code, MONO_ARCH_RGCTX_REG, mrgctx);
629         displace = ((uintptr_t) addr - (uintptr_t) code) / 2;
630         s390_jg   (code, displace);
631         g_assert ((code - start) < buf_len);
632
633         mono_arch_flush_icache (start, code - start);
634
635         return(start);
636 }       
637
638 /*========================= End of Function ========================*/
639
640 /*------------------------------------------------------------------*/
641 /*                                                                  */
642 /* Name         - handler_block_trampoline_helper                   */
643 /*                                                                  */
644 /* Function     -                                                   */
645 /*                                                                  */
646 /*------------------------------------------------------------------*/
647
648 static void
649 handler_block_trampoline_helper (gpointer *ptr)
650 {
651         MonoJitTlsData *jit_tls = mono_native_tls_get_value (mono_jit_tls_id);
652         *ptr = jit_tls->handler_block_return_address;
653 }
654
655 /*========================= End of Function ========================*/
656
657 /*------------------------------------------------------------------*/
658 /*                                                                  */
659 /* Name         - mono_arch_create_handler_block_trampoline         */
660 /*                                                                  */
661 /* Function     -                                                   */
662 /*                                                                  */
663 /*------------------------------------------------------------------*/
664
665 gpointer
666 mono_arch_create_handler_block_trampoline (MonoTrampInfo **info, gboolean aot)
667 {
668         guint8 *tramp = mono_get_trampoline_code (MONO_TRAMPOLINE_HANDLER_BLOCK_GUARD);
669         guint8 *code, *buf;
670         int tramp_size = 64;
671         MonoJumpInfo *ji = NULL;
672         GSList *unwind_ops = NULL;
673
674         g_assert (!aot);
675
676         code = buf = mono_global_codeman_reserve (tramp_size);
677
678         /*
679          * This trampoline restore the call chain of the handler block 
680          * then jumps into the code that deals with it.
681          */
682
683         if (mono_get_jit_tls_offset () != -1) {
684                 s390_ear  (code, s390_r1, 0);
685                 s390_sllg (code, s390_r1, s390_r1, 0, 32);
686                 s390_ear  (code, s390_r1, 1);
687                 S390_SET  (code, s390_r14, mono_get_jit_tls_offset());
688                 s390_lg   (code, s390_r14, s390_r1, 0, G_STRUCT_OFFSET(MonoJitTlsData, handler_block_return_address));
689                 /* 
690                  * Simulate a call 
691                  */
692                 S390_SET  (code, s390_r1, tramp);
693                 s390_br   (code, s390_r1);
694         } else {
695                 /*
696                  * Slow path uses a C helper
697                  */
698                 S390_SET  (code, s390_r2, tramp);
699                 S390_SET  (code, s390_r1, handler_block_trampoline_helper);
700                 s390_br   (code, s390_r1);
701         }
702
703         mono_arch_flush_icache (buf, code - buf);
704         g_assert (code - buf <= tramp_size);
705
706         if (info)
707                 *info = mono_tramp_info_create ("handler_block_trampoline", buf, code - buf, ji, unwind_ops);
708
709         return buf;
710 }
711
712 /*========================= End of Function ========================*/
713
714 /*------------------------------------------------------------------*/
715 /*                                                                  */
716 /* Name         - mono_arch_create_generic_class_init_trampoline    */
717 /*                                                                  */
718 /* Function     -                                                   */
719 /*                                                                  */
720 /*------------------------------------------------------------------*/
721
722 gpointer
723 mono_arch_create_generic_class_init_trampoline (MonoTrampInfo **info, gboolean aot)
724 {
725         guint8 *tramp;
726         guint8 *code, *buf;
727         static int byte_offset = -1;
728         static guint8 bitmask;
729         gint32 displace;
730         int tramp_size;
731         GSList *unwind_ops = NULL;
732         MonoJumpInfo *ji = NULL;
733
734         tramp_size = 48;
735
736         code = buf = mono_global_codeman_reserve (tramp_size);
737
738         unwind_ops = mono_arch_get_cie_program ();
739
740         if (byte_offset < 0)
741                 mono_marshal_find_bitfield_offset (MonoVTable, initialized, &byte_offset, &bitmask);
742
743         s390_llgc(code, s390_r0, 0, MONO_ARCH_VTABLE_REG, byte_offset);
744         s390_nill(code, s390_r0, bitmask);
745         s390_bnzr(code, s390_r14);
746
747         tramp = mono_arch_create_specific_trampoline (NULL, MONO_TRAMPOLINE_GENERIC_CLASS_INIT,
748                 mono_get_root_domain (), NULL);
749
750         /* jump to the actual trampoline */
751         displace = (tramp - code) / 2;
752         s390_jg (code, displace);
753
754         mono_arch_flush_icache (buf, code - buf);
755
756         g_assert (code - buf <= tramp_size);
757
758         if (info)
759                 *info = mono_tramp_info_create ("generic_class_init_trampoline", buf, code - buf, ji, unwind_ops);
760
761         return(buf);
762 }
763
764 /*========================= End of Function ========================*/