This should fix #76928. This fix incorporates ideas from a patch
[mono.git] / mono / mini / tramp-s390x.c
1 /*------------------------------------------------------------------*/
2 /*                                                                  */
3 /* Name        - tramp-s390.c                                       */
4 /*                                                                  */
5 /* Function    - JIT trampoline code for S/390.                     */
6 /*                                                                  */
7 /* Name        - Neale Ferguson (Neale.Ferguson@SoftwareAG-usa.com) */
8 /*                                                                  */
9 /* Date        - January, 2004                                      */
10 /*                                                                  */
11 /* Derivation  - From exceptions-x86 & exceptions-ppc               */
12 /*               Paolo Molaro (lupus@ximian.com)                    */
13 /*               Dietmar Maurer (dietmar@ximian.com)                */
14 /*                                                                  */
15 /* Copyright   - 2001 Ximian, Inc.                                  */
16 /*                                                                  */
17 /*------------------------------------------------------------------*/
18
19 /*------------------------------------------------------------------*/
20 /*                 D e f i n e s                                    */
21 /*------------------------------------------------------------------*/
22
23 #define GR_SAVE_SIZE            4*sizeof(long)
24 #define FP_SAVE_SIZE            16*sizeof(double)
25 #define 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
31 /*------------------------------------------------------------------*/
32 /* Method-specific trampoline code fragment sizes                   */
33 /*------------------------------------------------------------------*/
34 #define METHOD_TRAMPOLINE_SIZE  96
35 #define JUMP_TRAMPOLINE_SIZE    96
36
37 /*========================= End of Defines =========================*/
38
39 /*------------------------------------------------------------------*/
40 /*                 I n c l u d e s                                  */
41 /*------------------------------------------------------------------*/
42
43 #include <config.h>
44 #include <glib.h>
45 #include <string.h>
46
47 #include <mono/metadata/appdomain.h>
48 #include <mono/metadata/marshal.h>
49 #include <mono/metadata/tabledefs.h>
50 #include <mono/arch/s390x/s390x-codegen.h>
51 #include <mono/metadata/mono-debug-debugger.h>
52
53 #include "mini.h"
54 #include "mini-s390x.h"
55
56 /*========================= End of Includes ========================*/
57
58 /*------------------------------------------------------------------*/
59 /*                 T y p e d e f s                                  */
60 /*------------------------------------------------------------------*/
61
62 /*========================= End of Typedefs ========================*/
63
64 /*------------------------------------------------------------------*/
65 /*                   P r o t o t y p e s                            */
66 /*------------------------------------------------------------------*/
67
68 /*========================= End of Prototypes ======================*/
69
70 /*------------------------------------------------------------------*/
71 /*                 G l o b a l   V a r i a b l e s                  */
72 /*------------------------------------------------------------------*/
73
74
75 /*====================== End of Global Variables ===================*/
76
77 /*------------------------------------------------------------------*/
78 /*                                                                  */
79 /* Name         - get_unbox_trampoline                              */
80 /*                                                                  */
81 /* Function     - Return a pointer to a trampoline which does the   */
82 /*                unboxing before calling the method.               */
83 /*                                                                  */
84 /*                When value type methods are called through the    */
85 /*                vtable we need to unbox the 'this' argument.      */
86 /*                                                                  */
87 /* Parameters   - method - Methd pointer                            */
88 /*                addr   - Pointer to native code for method        */
89 /*                                                                  */
90 /*------------------------------------------------------------------*/
91
92 static gpointer
93 get_unbox_trampoline (MonoMethod *method, gpointer addr)
94 {
95         guint8 *code, *start;
96         int this_pos = s390_r2;
97
98         start = addr;
99         if ((!mono_method_signature (method)->ret->byref) && 
100             (MONO_TYPE_ISSTRUCT (mono_method_signature (method)->ret)))
101                 this_pos = s390_r3;
102     
103         start = code = mono_global_codeman_reserve (28);
104
105         s390_basr (code, s390_r1, 0);
106         s390_j    (code, 6);
107         s390_llong(code, addr);
108         s390_lg   (code, s390_r1, 0, s390_r1, 4);
109         s390_aghi (code, this_pos, sizeof(MonoObject));
110         s390_br   (code, s390_r1);
111
112         g_assert ((code - start) <= 28);
113
114         return start;
115 }
116
117 /*========================= End of Function ========================*/
118
119 /*------------------------------------------------------------------*/
120 /*                                                                  */
121 /* Name         - s390_magic_trampoline                             */
122 /*                                                                  */
123 /* Function     - This method is called by the function             */
124 /*                "arch_create_jit_trampoline", which in turn is    */
125 /*                called by the trampoline functions for virtual    */
126 /*                methods. After having called the JIT compiler to  */
127 /*                compile the method, it inspects the caller code   */
128 /*                to find the address of the method-specific part   */
129 /*                of the trampoline vtable slot for this method,    */
130 /*                updates it with a fragment that calls the newly   */
131 /*                compiled code and returns this address. The calls */
132 /*                generated by mono for S/390 will look like either:*/
133 /*                1. l     %r1,xxx(%rx)                             */
134 /*                   bras  %r14,%r1                                 */
135 /*                2. brasl %r14,xxxxxx                              */
136 /*                                                                  */
137 /* Parameters   - code   - Pointer into caller code                 */
138 /*                method - The method to compile                    */
139 /*                sp     - Stack pointer                            */
140 /*                                                                  */
141 /*------------------------------------------------------------------*/
142
143 static gpointer
144 s390_magic_trampoline (MonoMethod *method, guchar *code, char *sp)
145 {
146         gpointer addr;
147         gint64 displace;
148         guchar reg, lkReg;
149         guchar *base;
150         unsigned short opcode;
151         MonoJitInfo *codeJi, 
152                     *addrJi;
153
154         addr = mono_compile_method(method);
155         g_assert(addr);
156
157         if (code) {
158
159                 codeJi = mono_jit_info_table_find (mono_domain_get(), code);
160                 addrJi = mono_jit_info_table_find (mono_domain_get(), addr);
161                 if (mono_method_same_domain (codeJi, addrJi)) {
162
163                         opcode = *((unsigned short *) (code - 6));
164                         if (opcode == 0xc0e5) {
165                                 /* This is the 'brasl' instruction */
166                                 code    -= 4;
167                                 displace = ((gint64) addr - (gint64) (code - 2)) / 2;
168                                 if (mono_method_same_domain (codeJi, addrJi)) {
169                                         s390_patch_rel (code, displace);
170                                         mono_arch_flush_icache (code, 4);
171                                 }
172                         } else {
173                                 /*-----------------------------------*/
174                                 /* This is a bras r14,Rz instruction */
175                                 /* If it's preceded by a LG Rx,d(Ry) */
176                                 /* If Rz == 1 then we check if unbox-*/
177                                 /* is required. We patch the address */
178                                 /* by determining the location desc- */
179                                 /* cribed by *Ry+d.                  */ 
180                                 /*-----------------------------------*/
181                                 code    -= 6;
182
183                                 /*-----------------------------------*/
184                                 /* If call is preceded by LGR then   */
185                                 /* there's nothing to patch          */
186                                 /*-----------------------------------*/
187                                 if ((code[0] == 0xb9) &&
188                                     (code[1] == 0x04))
189                                         return addr;
190
191                                 /*-----------------------------------*/
192                                 /* We back up until we're pointing at*/
193                                 /* the base/displacement portion of  */
194                                 /* the LG instruction                */
195                                 /*-----------------------------------*/
196                                 lkReg    = code[5] & 0x0f;
197
198                                 /*-----------------------------------*/
199                                 /* The LG instruction has format:    */
200                                 /* E3x0ylllhh04 - where:             */
201                                 /* x = Rx; y = Ry;                   */
202                                 /* lll = low 12 bits of displacement */
203                                 /* hh  = high 8 bits of displacement */
204                                 /*-----------------------------------*/
205                                 reg      = code[0] >> 4;
206                                 displace = (code[2] << 12) +
207                                            ((code[0] & 0x0f) << 8) + 
208                                            code[1];
209
210                                 if (reg > 5) 
211                                         base = *((guchar **) (sp + S390_REG_SAVE_OFFSET +
212                                                                sizeof(long)*(reg-6)));
213                                 else
214                                         base = *((guchar **) ((sp - CREATE_STACK_SIZE) + 
215                                                                CREATE_GR_OFFSET +
216                                                                sizeof(long)*(reg-2)));
217
218                                 /* Calls that need unboxing use R1 */
219                                 if (lkReg == 1)  {
220                                         if ((method->klass->valuetype) && 
221                                             (!mono_aot_is_got_entry(code, base)))
222                                                 addr = get_unbox_trampoline(method, addr);
223
224                                         code = base + displace;
225                                         if (mono_domain_owns_vtable_slot(mono_domain_get(), 
226                                                                          code))
227                                                 s390_patch_addr(code, addr);
228                                 } else {
229                                         code = base + displace;
230                                         s390_patch_addr(code, addr);
231                                 }
232                         }
233                 }
234         }
235
236         return addr;
237 }
238
239 /*========================= End of Function ========================*/
240
241 /*------------------------------------------------------------------*/
242 /*                                                                  */
243 /* Name         - s390_class_init_trampoline                        */
244 /*                                                                  */
245 /* Function     - Initialize a class and then no-op the call to     */
246 /*                the trampoline.                                   */
247 /*                                                                  */
248 /*------------------------------------------------------------------*/
249
250 static void
251 s390_class_init_trampoline (void *vtable, guchar *code, char *sp)
252 {
253         char patch[2] = {0x07, 0x00};
254
255         mono_runtime_class_init (vtable);
256
257         code = code - 2;
258
259         memcpy(code, patch, sizeof(patch));
260 }
261
262 /*========================= End of Function ========================*/
263
264 /*------------------------------------------------------------------*/
265 /*                                                                  */
266 /* Name         - mono_arch_create_trampoline_code                            */
267 /*                                                                  */
268 /* Function     - Create the designated type of trampoline according*/
269 /*                to the 'tramp_type' parameter.                    */
270 /*                                                                  */
271 /*------------------------------------------------------------------*/
272
273 guchar *
274 mono_arch_create_trampoline_code (MonoTrampolineType tramp_type)
275 {
276
277         guint8 *buf, *code = NULL;
278         int i, offset, lmfOffset;
279
280         if(!code) {
281                 /* Now we'll create in 'buf' the S/390 trampoline code. This
282                  is the trampoline code common to all methods  */
283                 
284                 code = buf = mono_global_codeman_reserve(512);
285                 
286                 /*-----------------------------------------------------------
287                 STEP 0: First create a non-standard function prologue with a
288                 stack size big enough to save our registers.
289                 -----------------------------------------------------------*/
290                 
291                 s390_stmg (buf, s390_r6, s390_r14, STK_BASE, S390_REG_SAVE_OFFSET);
292                 s390_lgr  (buf, s390_r11, s390_r15);
293                 s390_aghi (buf, STK_BASE, -CREATE_STACK_SIZE);
294                 s390_stg  (buf, s390_r11, 0, STK_BASE, 0);
295                 s390_stg  (buf, s390_r1, 0, STK_BASE, METHOD_SAVE_OFFSET);
296                 s390_stmg (buf, s390_r2, s390_r5, STK_BASE, CREATE_GR_OFFSET);
297
298                 /* Save the FP registers */
299                 offset = CREATE_FP_OFFSET;
300                 for (i = s390_f0; i <= s390_f15; ++i) {
301                         s390_std  (buf, i, 0, STK_BASE, offset);
302                         offset += 8;
303                 }
304
305                 /*----------------------------------------------------------
306                 STEP 1: call 'mono_get_lmf_addr()' to get the address of our
307                 LMF. We'll need to restore it after the call to
308                 's390_magic_trampoline' and before the call to the native
309                 method.
310                 ----------------------------------------------------------*/
311                                 
312                 s390_basr (buf, s390_r13, 0);
313                 s390_j    (buf, 6);
314                 s390_llong(buf, mono_get_lmf_addr);
315                 s390_lg   (buf, s390_r1, 0, s390_r13, 4);
316                 s390_basr (buf, s390_r14, s390_r1);
317
318                 /*---------------------------------------------------------------*/
319                 /* we build the MonoLMF structure on the stack - see mini-s390.h */
320                 /* Keep in sync with the code in mono_arch_emit_prolog           */
321                 /*---------------------------------------------------------------*/
322                 lmfOffset = CREATE_STACK_SIZE - sizeof(MonoLMF);
323                                                                                         
324                 s390_lgr   (buf, s390_r13, STK_BASE);
325                 s390_aghi  (buf, s390_r13, lmfOffset);  
326                                                                                         
327                 /*---------------------------------------------------------------*/     
328                 /* Set lmf.lmf_addr = jit_tls->lmf                               */     
329                 /*---------------------------------------------------------------*/     
330                 s390_stg   (buf, s390_r2, 0, s390_r13,                          
331                             G_STRUCT_OFFSET(MonoLMF, lmf_addr));                        
332                                                                                         
333                 /*---------------------------------------------------------------*/     
334                 /* Get current lmf                                               */     
335                 /*---------------------------------------------------------------*/     
336                 s390_lg    (buf, s390_r0, 0, s390_r2, 0);                               
337                                                                                         
338                 /*---------------------------------------------------------------*/     
339                 /* Set our lmf as the current lmf                                */     
340                 /*---------------------------------------------------------------*/     
341                 s390_stg   (buf, s390_r13, 0, s390_r2, 0);                              
342                                                                                         
343                 /*---------------------------------------------------------------*/     
344                 /* Have our lmf.previous_lmf point to the last lmf               */     
345                 /*---------------------------------------------------------------*/     
346                 s390_stg   (buf, s390_r0, 0, s390_r13,                          
347                             G_STRUCT_OFFSET(MonoLMF, previous_lmf));                    
348                                                                                         
349                 /*---------------------------------------------------------------*/     
350                 /* save method info                                              */     
351                 /*---------------------------------------------------------------*/     
352                 s390_lg    (buf, s390_r1, 0, STK_BASE, METHOD_SAVE_OFFSET);
353                 s390_stg   (buf, s390_r1, 0, s390_r13,                          
354                             G_STRUCT_OFFSET(MonoLMF, method));                          
355                                                                         
356                 /*---------------------------------------------------------------*/     
357                 /* save the current SP                                           */     
358                 /*---------------------------------------------------------------*/     
359                 s390_lg    (buf, s390_r1, 0, STK_BASE, 0);
360                 s390_stg   (buf, s390_r1, 0, s390_r13, G_STRUCT_OFFSET(MonoLMF, ebp));  
361                                                                         
362                 /*---------------------------------------------------------------*/     
363                 /* save the current IP                                           */     
364                 /*---------------------------------------------------------------*/     
365                 if (tramp_type == MONO_TRAMPOLINE_JUMP) {
366                         s390_lghi  (buf, s390_r1, 0);
367                 } else {
368                         s390_lg    (buf, s390_r1, 0, s390_r1, S390_RET_ADDR_OFFSET);
369 //                      s390_la    (buf, s390_r1, 0, s390_r1, 0);
370                 }
371                 s390_stg   (buf, s390_r1, 0, s390_r13, G_STRUCT_OFFSET(MonoLMF, eip));  
372                                                                                         
373                 /*---------------------------------------------------------------*/     
374                 /* Save general and floating point registers                     */     
375                 /*---------------------------------------------------------------*/     
376                 s390_stmg  (buf, s390_r2, s390_r12, s390_r13,                           
377                             G_STRUCT_OFFSET(MonoLMF, gregs[2]));                        
378                 for (i = 0; i < 16; i++) {                                              
379                         s390_std  (buf, i, 0, s390_r13,                                 
380                                    G_STRUCT_OFFSET(MonoLMF, fregs[i]));                 
381                 }                                                                       
382
383                 /*---------------------------------------------------------------*/
384                 /* STEP 2: call 's390_magic_trampoline()', who will compile the  */
385                 /* code and fix the method vtable entry for us                   */
386                 /*---------------------------------------------------------------*/
387                                 
388                 /* Set arguments */
389                 
390                 /* Arg 1: MonoMethod *method. It was put in r1 by the
391                 method-specific trampoline code, and then saved before the call
392                 to mono_get_lmf_addr()'. */
393                 s390_lg (buf, s390_r2, 0, STK_BASE, METHOD_SAVE_OFFSET);
394                 
395                 /* Arg 2: code (next address to the instruction that called us) */
396                 if (tramp_type == MONO_TRAMPOLINE_JUMP) {
397                         s390_lghi (buf, s390_r3, 0);
398                 } else {
399                         s390_lg   (buf, s390_r3, 0, s390_r11, S390_RET_ADDR_OFFSET);
400                 }
401                 
402                 /* Arg 3: stack pointer */
403                 s390_lgr  (buf, s390_r4, STK_BASE);
404                 s390_ahi  (buf, s390_r4, CREATE_STACK_SIZE);
405                 
406                 /* Calculate call address and call
407                 's390_magic_trampoline'. Return value will be in r2 */
408                 s390_basr (buf, s390_r13, 0);
409                 s390_j    (buf, 6);
410                 if (tramp_type == MONO_TRAMPOLINE_CLASS_INIT) {
411                         s390_llong(buf, s390_class_init_trampoline);
412                 } else {
413                         s390_llong(buf, s390_magic_trampoline);
414                 }
415                 s390_lg   (buf, s390_r1, 0, s390_r13, 4);
416                 s390_basr (buf, s390_r14, s390_r1);
417                 
418                 /* OK, code address is now on r2. Move it to r1, so that we
419                 can restore r2 and use it from r1 later */
420                 s390_lgr  (buf, s390_r1, s390_r2);
421
422                 /*----------------------------------------------------------
423                 STEP 3: Restore the LMF
424                 ----------------------------------------------------------*/
425                 restoreLMF(buf, STK_BASE, CREATE_STACK_SIZE);
426         
427                 /*----------------------------------------------------------
428                 STEP 4: call the compiled method
429                 ----------------------------------------------------------*/
430                 
431                 /* Restore registers */
432
433                 s390_lmg  (buf, s390_r2, s390_r5, STK_BASE, CREATE_GR_OFFSET);
434                 
435                 /* Restore the FP registers */
436                 offset = CREATE_FP_OFFSET;
437                 for (i = s390_f0; i <= s390_f15; ++i) {
438                         s390_ld  (buf, i, 0, STK_BASE, offset);
439                         offset += 8;
440                 }
441
442                 /* Restore stack pointer and jump to the code - 
443                    R14 contains the return address to our caller */
444                 s390_lgr  (buf, STK_BASE, s390_r11);
445                 s390_lmg  (buf, s390_r6, s390_r14, STK_BASE, S390_REG_SAVE_OFFSET);
446                 s390_br   (buf, s390_r1);
447
448                 /* Flush instruction cache, since we've generated code */
449                 mono_arch_flush_icache (code, buf - code);
450         
451                 /* Sanity check */
452                 g_assert ((buf - code) <= 512);
453         }
454
455         return code;
456 }
457
458 /*========================= End of Function ========================*/
459
460 /*------------------------------------------------------------------*/
461 /*                                                                  */
462 /* Name         - mono_arch_create_jump_trampoline                  */
463 /*                                                                  */
464 /* Function     - Create the designated type of trampoline according*/
465 /*                to the 'tramp_type' parameter.                    */
466 /*                                                                  */
467 /*------------------------------------------------------------------*/
468
469 MonoJitInfo *
470 mono_arch_create_jump_trampoline (MonoMethod *method)
471 {
472         guint8 *code, *buf, *tramp = NULL;
473         MonoJitInfo *ji;
474         MonoDomain *domain = mono_domain_get();
475         gint32 displace;
476
477         tramp = mono_get_trampoline_code (MONO_TRAMPOLINE_JUMP);
478
479         mono_domain_lock (domain);
480         code = buf = mono_code_manager_reserve (domain->code_mp, JUMP_TRAMPOLINE_SIZE);
481         mono_domain_unlock (domain);
482
483         s390_basr (buf, s390_r1, 0);
484         s390_j    (buf, 6);
485         s390_llong(buf, method);
486         s390_lg   (buf, s390_r1, 0, s390_r1, 4);
487         displace = (tramp - buf) / 2;
488         s390_jcl  (buf, S390_CC_UN, displace);
489
490         mono_arch_flush_icache (code, buf-code);
491
492         g_assert ((buf - code) <= JUMP_TRAMPOLINE_SIZE);
493         
494         ji              = g_new0 (MonoJitInfo, 1);
495         ji->method      = method;
496         ji->code_start  = code;
497         ji->code_size   = buf - code;
498         
499         mono_jit_stats.method_trampolines++;
500
501         return ji;
502 }
503
504 /*========================= End of Function ========================*/
505
506 /*------------------------------------------------------------------*/
507 /*                                                                  */
508 /* Name         - mono_arch_create_jit_trampoline                   */
509 /*                                                                  */
510 /* Function     - Creates a trampoline function for virtual methods.*/
511 /*                If the created code is called it first starts JIT */
512 /*                compilation and then calls the newly created      */
513 /*                method. It also replaces the corresponding vtable */
514 /*                entry (see s390_magic_trampoline).                */
515 /*                                                                  */
516 /*                A trampoline consists of two parts: a main        */
517 /*                fragment, shared by all method trampolines, and   */
518 /*                and some code specific to each method, which      */
519 /*                hard-codes a reference to that method and then    */
520 /*                calls the main fragment.                          */
521 /*                                                                  */
522 /*                The main fragment contains a call to              */
523 /*                's390_magic_trampoline', which performs a call    */
524 /*                to the JIT compiler and substitutes the method-   */
525 /*                specific fragment with some code that directly    */
526 /*                calls the JIT-compiled method.                    */
527 /*                                                                  */
528 /* Parameter    - method - Pointer to the method information        */
529 /*                                                                  */
530 /* Returns      - A pointer to the newly created code               */
531 /*                                                                  */
532 /*------------------------------------------------------------------*/
533
534 gpointer
535 mono_arch_create_jit_trampoline (MonoMethod *method)
536 {
537         guint8 *code, *buf;
538         static guint8 *vc = NULL;
539         gint32 displace;
540
541         vc = mono_get_trampoline_code (MONO_TRAMPOLINE_GENERIC);
542
543         /* This is the method-specific part of the trampoline. Its purpose is
544         to provide the generic part with the MonoMethod *method pointer. We'll
545         use r1 to keep that value, for instance. */
546         code = buf = mono_global_codeman_reserve(METHOD_TRAMPOLINE_SIZE);
547
548         s390_basr (buf, s390_r1, 0);
549         s390_j    (buf, 6);
550         s390_llong(buf, method);
551         s390_lg   (buf, s390_r1, 0, s390_r1, 4);
552         displace = (vc - buf) / 2;
553         s390_jcl  (buf, S390_CC_UN, displace);
554
555         /* Flush instruction cache, since we've generated code */
556         mono_arch_flush_icache (code, buf - code);
557                 
558         /* Sanity check */
559         g_assert ((buf - code) <= METHOD_TRAMPOLINE_SIZE);
560         
561         return code;
562 }
563
564 /*========================= End of Function ========================*/
565
566 /*------------------------------------------------------------------*/
567 /*                                                                  */
568 /* Name         - mono_arch_create_class_init_trampoline            */
569 /*                                                                  */
570 /* Function     - Creates a trampoline function to run a type init- */
571 /*                ializer. If the trampoline is called, it calls    */
572 /*                mono_runtime_class_init with the given vtable,    */
573 /*                then patches the caller code so it does not get   */
574 /*                called any more.                                  */
575 /*                                                                  */
576 /* Parameter    - vtable - The type to initialize                   */
577 /*                                                                  */
578 /* Returns      - A pointer to the newly created code               */
579 /*                                                                  */
580 /*------------------------------------------------------------------*/
581
582 gpointer
583 mono_arch_create_class_init_trampoline (MonoVTable *vtable)
584 {
585         guint8 *code, *buf, *tramp;
586
587         tramp = mono_get_trampoline_code (MONO_TRAMPOLINE_CLASS_INIT);
588
589         /*-----------------------------------------------------------*/
590         /* This is the method-specific part of the trampoline. Its   */
591         /* purpose is to provide the generic part with the MonoMethod*/
592         /* *method pointer.                                          */
593         /*-----------------------------------------------------------*/
594         code = buf = mono_global_codeman_reserve(METHOD_TRAMPOLINE_SIZE);
595
596         s390_stg  (buf, s390_r14, 0, STK_BASE, S390_RET_ADDR_OFFSET);
597         s390_aghi (buf, STK_BASE, -S390_MINIMAL_STACK_SIZE);
598
599         s390_basr (buf, s390_r1, 0);
600         s390_j    (buf, 10);
601         s390_llong(buf, vtable);
602         s390_llong(buf, s390_class_init_trampoline);
603         s390_lgr  (buf, s390_r3, s390_r14);
604         s390_lg   (buf, s390_r2, 0, s390_r1, 4);
605         s390_lghi (buf, s390_r4, 0);
606         s390_lg   (buf, s390_r1, 0, s390_r1, 12);
607         s390_basr (buf, s390_r14, s390_r1);
608
609         s390_aghi (buf, STK_BASE, S390_MINIMAL_STACK_SIZE);
610         s390_lg   (buf, s390_r14, 0, STK_BASE, S390_RET_ADDR_OFFSET);
611         s390_br   (buf, s390_r14);
612
613         /* Flush instruction cache, since we've generated code */
614         mono_arch_flush_icache (code, buf - code);
615                 
616         /* Sanity check */
617         g_assert ((buf - code) <= METHOD_TRAMPOLINE_SIZE);
618
619         mono_jit_stats.method_trampolines++;
620
621         return code;
622 }
623
624 /*========================= End of Function ========================*/
625
626 /*------------------------------------------------------------------*/
627 /*                                                                  */
628 /* Name         - mono_debuger_create_notification_function         */
629 /*                                                                  */
630 /* Function     - This method is only called when running in the    */
631 /*                Mono debugger. It returns a pointer to the        */
632 /*                arch specific notification function.              */
633 /*                                                                  */
634 /*------------------------------------------------------------------*/
635
636 gpointer
637 mono_debugger_create_notification_function (gpointer *notification_address)
638 {
639         guint8 *ptr, *buf;
640
641         ptr = buf = mono_global_codeman_reserve (16);
642         s390_break (buf);
643         if (notification_address)
644                 *notification_address = buf;
645         s390_br (buf, s390_r14);
646
647         return ptr;
648 }
649
650 /*========================= End of Function ========================*/