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