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