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