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