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