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