New tests.
[mono.git] / mono / mini / tramp-s390x.c
index d8e114c2ba46013a7e28b8823085be918941f2f5..b635e7ce6b706970b1cf440d82c73976771d8813 100644 (file)
 
 #define GR_SAVE_SIZE           4*sizeof(long)
 #define FP_SAVE_SIZE           16*sizeof(double)
-#define CREATE_STACK_SIZE      (S390_MINIMAL_STACK_SIZE+GR_SAVE_SIZE+FP_SAVE_SIZE+2*sizeof(long))
-#define CREATE_GR_OFFSET       S390_MINIMAL_STACK_SIZE
+#define METHOD_SAVE_OFFSET     S390_MINIMAL_STACK_SIZE
+#define CREATE_GR_OFFSET       METHOD_SAVE_OFFSET+8
 #define CREATE_FP_OFFSET       CREATE_GR_OFFSET+GR_SAVE_SIZE
 #define CREATE_LMF_OFFSET      CREATE_FP_OFFSET+FP_SAVE_SIZE
-#define METHOD_SAVE_OFFSET     S390_RET_ADDR_OFFSET-8
+#define CREATE_STACK_SIZE      (CREATE_LMF_OFFSET+2*sizeof(long)+sizeof(MonoLMF))
 
 /*------------------------------------------------------------------*/
 /* Method-specific trampoline code fragment sizes                  */
 /*------------------------------------------------------------------*/
-#define METHOD_TRAMPOLINE_SIZE 64
-#define JUMP_TRAMPOLINE_SIZE   64
+#define SPECIFIC_TRAMPOLINE_SIZE       96
 
 /*========================= End of Defines =========================*/
 
@@ -48,7 +47,6 @@
 #include <mono/metadata/marshal.h>
 #include <mono/metadata/tabledefs.h>
 #include <mono/arch/s390x/s390x-codegen.h>
-#include <mono/metadata/mono-debug-debugger.h>
 
 #include "mini.h"
 #include "mini-s390x.h"
@@ -76,7 +74,7 @@
 
 /*------------------------------------------------------------------*/
 /*                                                                  */
-/* Name                - get_unbox_trampoline                              */
+/* Name                - mono_arch_get_unbox_trampoline                    */
 /*                                                                  */
 /* Function    - Return a pointer to a trampoline which does the   */
 /*               unboxing before calling the method.               */
 /*                When value type methods are called through the    */
 /*               vtable we need to unbox the 'this' argument.      */
 /*                                                                 */
-/* Parameters   - method - Methd pointer                           */
+/* Parameters   - gsctx  - Generic sharing context                 */
+/*                method - Methd pointer                           */
 /*               addr   - Pointer to native code for method        */
 /*                                                                 */
 /*------------------------------------------------------------------*/
 
-static gpointer
-get_unbox_trampoline (MonoMethod *method, gpointer addr)
+gpointer
+mono_arch_get_unbox_trampoline (MonoGenericSharingContext *gsctx, MonoMethod *method, gpointer addr)
 {
        guint8 *code, *start;
        int this_pos = s390_r2;
+       MonoDomain *domain = mono_domain_get ();
 
        start = addr;
-       if ((method->klass->valuetype)) {
-               if ((!mono_method_signature (method)->ret->byref) && 
-                   (MONO_TYPE_ISSTRUCT (mono_method_signature (method)->ret)))
-                       this_pos = s390_r3;
-           
-               start = code = g_malloc (28);
-
-               s390_basr (code, s390_r13, 0);
-               s390_j    (code, 6);
-               s390_llong(code, addr);
-               s390_lg   (code, s390_r1, 0, s390_r13, 4);
-               s390_aghi (code, this_pos, sizeof(MonoObject));
-               s390_br   (code, s390_r1);
-
-               g_assert ((code - start) <= 28);
-       }
+       if (MONO_TYPE_ISSTRUCT (mono_method_signature (method)->ret))
+               this_pos = s390_r3;
+
+       start = code = mono_domain_code_reserve (domain, 28);
+
+       s390_basr (code, s390_r1, 0);
+       s390_j    (code, 6);
+       s390_llong(code, addr);
+       s390_lg   (code, s390_r1, 0, s390_r1, 4);
+       s390_aghi (code, this_pos, sizeof(MonoObject));
+       s390_br   (code, s390_r1);
+
+       g_assert ((code - start) <= 28);
+
+       mono_arch_flush_icache (start, code - start);
 
        return start;
 }
@@ -120,334 +119,379 @@ get_unbox_trampoline (MonoMethod *method, gpointer addr)
 
 /*------------------------------------------------------------------*/
 /*                                                                  */
-/* Name                - s390_magic_trampoline                             */
+/* Name                - mono_arch_patch_callsite                          */
 /*                                                                  */
-/* Function    - This method is called by the function             */
-/*                "arch_create_jit_trampoline", which in turn is    */
-/*                called by the trampoline functions for virtual    */
-/*                methods. After having called the JIT compiler to  */
-/*                compile the method, it inspects the caller code   */
-/*                to find the address of the method-specific part   */
-/*                of the trampoline vtable slot for this method,    */
-/*                updates it with a fragment that calls the newly   */
-/*                compiled code and returns this address. The calls */
-/*                generated by mono for S/390 will look like either:*/
-/*                1. l     %r1,xxx(%rx)                             */
-/*                   bras  %r14,%r1                                 */
-/*                2. brasl %r14,xxxxxx                              */
-/*                                                                  */
-/* Parameters   - code   - Pointer into caller code                 */
-/*                method - The method to compile                    */
-/*                sp     - Stack pointer                            */
+/* Function    - Patch a non-virtual callsite so it calls @addr.   */
 /*                                                                  */
 /*------------------------------------------------------------------*/
 
-static gpointer
-s390_magic_trampoline (MonoMethod *method, guchar *code, char *sp)
+void
+mono_arch_patch_callsite (guint8 *method_start, guint8 *orig_code, guint8 *addr)
 {
-       gpointer addr;
-       guint32 displace;
-       gint64 base;
-       int reg;
+       gint32 displace;
        unsigned short opcode;
-       char *fname;
-
-       addr = mono_compile_method(method);
-       g_assert(addr);
-
-       if (code) {
-
-               fname = mono_method_full_name (method, TRUE);
-
-               opcode = *((unsigned short *) (code - 6));
-               if (opcode == 0xc0e5) {
-                       /* This is the 'brasl' instruction */
-                       code    -= 4;
-                       displace = ((gint64) addr - (gint64) (code - 2)) / 2;
-                       s390_patch (code, displace);
-                       mono_arch_flush_icache (code, 4);
-               } else {
-                       /* This is a bras rx,r1 instruction */
-                       code    -= 6;
-                       reg      = *code >> 4;
-                       displace = ((*(char *)(code+2) << 8) | 
-                                   (*((short *)code) & 0x0fff));
-                       if (reg > 5) 
-                               base = *((gint64 *) (sp + S390_REG_SAVE_OFFSET+
-                                                    sizeof(gint64)*(reg-6)));
-                       else
-                               base = *((gint64 *) (sp + CREATE_GR_OFFSET+
-                                                    sizeof(gint64)*(reg-2)));
-                       addr = get_unbox_trampoline(method, addr);
-                       code = base + displace;
-                       *((guint64 *) (code)) = addr;
-               }
-       }
 
-
-       return addr;
+       opcode = *((unsigned short *) (orig_code - 6));
+       if (opcode == 0xc0e5) {
+               /* This is the 'brasl' instruction */
+               orig_code    -= 4;
+               displace = ((gssize) addr - (gssize) (orig_code - 2)) / 2;
+               s390_patch_rel (orig_code, displace);
+               mono_arch_flush_icache (orig_code, 4);
+       } else {
+               /* This should be a 'lg %r14,4(%r13)' then a 'basr r14, r14' instruction */
+               g_assert (orig_code [-8] == 0xe3);
+               g_assert (orig_code [-7] == 0xe0);
+               g_assert (orig_code [-6] == 0xd0);
+               g_assert (orig_code [-5] == 0x04);
+               g_assert (orig_code [-4] == 0x00);
+               g_assert (orig_code [-3] == 0x04);
+               opcode = *((unsigned short*) (orig_code - 2));
+               g_assert (opcode == 0x0dee);
+
+               /* The call address is stored in the 8 bytes preceeding the basr instruction */
+               s390_patch_addr(orig_code - 16, (gssize)addr);
+               mono_arch_flush_icache (orig_code - 16, 8);
+       }
 }
 
 /*========================= End of Function ========================*/
 
 /*------------------------------------------------------------------*/
 /*                                                                  */
-/* Name                - s390_class_init_trampoline                        */
+/* Name                - mono_arch_patch_plt_entry.                        */
 /*                                                                  */
-/* Function    - Initialize a class and then no-op the call to     */
-/*                the trampoline.                                   */
+/* Function    - Patch a PLT entry - unused as yet.                */
 /*                                                                  */
 /*------------------------------------------------------------------*/
 
-static void
-s390_class_init_trampoline (void *vtable, guchar *code, char *sp)
+void
+mono_arch_patch_plt_entry (guint8 *code, gpointer *got, mgreg_t *regs, guint8 *addr)
 {
-       char patch[6] = {0x47, 0x00, 0x00, 0x00, 0x07, 0x00};
-
-       mono_runtime_class_init (vtable);
-
-       code = code - 6;
-
-       memcpy(code, patch, sizeof(patch));
+       g_assert_not_reached ();
 }
 
 /*========================= End of Function ========================*/
 
 /*------------------------------------------------------------------*/
 /*                                                                  */
-/* Name                - mono_arch_create_trampoline_code                            */
+/* Name                - mono_arch_nullify_class_init_trampoline           */
 /*                                                                  */
-/* Function    - Create the designated type of trampoline according*/
-/*                to the 'tramp_type' parameter.                    */
+/* Function    - Nullify a call which calls a class init trampoline*/
 /*                                                                  */
 /*------------------------------------------------------------------*/
 
-guchar*
-mono_arch_create_trampoline_code (MonoTrampolineType tramp_type)
+void
+mono_arch_nullify_class_init_trampoline (guint8 *code, mgreg_t *regs)
 {
+       char patch[2] = {0x07, 0x00};
 
-       guint8 *buf, *code = NULL;
-       int i, offset;
+       code = code - 2;
 
-       if(!code) {
-               /* Now we'll create in 'buf' the S/390 trampoline code. This
-                is the trampoline code common to all methods  */
-               
-               code = buf = g_malloc(512);
-               
-               /*-----------------------------------------------------------
-               STEP 0: First create a non-standard function prologue with a
-               stack size big enough to save our registers.
-               -----------------------------------------------------------*/
-               
-               s390_stmg (buf, s390_r6, s390_r14, STK_BASE, S390_REG_SAVE_OFFSET);
-               s390_lgr  (buf, s390_r11, s390_r15);
-               s390_aghi (buf, STK_BASE, -CREATE_STACK_SIZE);
-               s390_stg  (buf, s390_r11, 0, STK_BASE, 0);
-               s390_stmg (buf, s390_r2, s390_r5, STK_BASE, CREATE_GR_OFFSET);
-
-               /* Save the FP registers */
-               offset = CREATE_FP_OFFSET;
-               for (i = s390_f0; i <= s390_f15; ++i) {
-                       s390_std  (buf, i, 0, STK_BASE, offset);
-                       offset += 8;
-               }
-
-               /*----------------------------------------------------------
-               STEP 1: call 'mono_get_lmf_addr()' to get the address of our
-               LMF. We'll need to restore it after the call to
-               's390_magic_trampoline' and before the call to the native
-               method.
-               ----------------------------------------------------------*/
-                               
-               s390_basr (buf, s390_r13, 0);
-               s390_j    (buf, 6);
-               s390_llong(buf, mono_get_lmf_addr);
-               s390_lg   (buf, s390_r1, 0, s390_r13, 4);
-               s390_basr (buf, s390_r14, s390_r1);
-
-               /*----------------------------------------------------------
-               STEP 2: call 's390_magic_trampoline()', who will compile the
-               code and fix the method vtable entry for us
-               ----------------------------------------------------------*/
-                               
-               /* Set arguments */
-               
-               /* Arg 1: MonoMethod *method. It was put in r11 by the
-               method-specific trampoline code, and then saved before the call
-               to mono_get_lmf_addr()'. Restore r13, by the way :-) */
-               s390_lg (buf, s390_r2, 0, s390_r11, METHOD_SAVE_OFFSET);
-               
-               /* Arg 2: code (next address to the instruction that called us) */
-               if (tramp_type == MONO_TRAMPOLINE_JUMP) {
-                       s390_lghi (buf, s390_r3, 0);
-               } else {
-                       s390_lg  (buf, s390_r3, 0, s390_r11, S390_RET_ADDR_OFFSET);
-               }
-               
-               /* Arg 3: stack pointer */
-               s390_lgr  (buf, s390_r4, STK_BASE);
-               
-               /* Calculate call address and call
-               's390_magic_trampoline'. Return value will be in r2 */
-               s390_basr (buf, s390_r13, 0);
-               s390_j    (buf, 6);
-               if (tramp_type == MONO_TRAMPOLINE_CLASS_INIT) {
-                       s390_llong(buf, s390_class_init_trampoline);
-               } else {
-                       s390_llong(buf, s390_magic_trampoline);
-               }
-               s390_lg   (buf, s390_r1, 0, s390_r13, 4);
-               s390_basr (buf, s390_r14, s390_r1);
-               
-               /* OK, code address is now on r2. Move it to r1, so that we
-               can restore r2 and use it from r1 later */
-               s390_lgr  (buf, s390_r1, s390_r2);
-               
-
-               /*----------------------------------------------------------
-               STEP 3: Restore the LMF
-               ----------------------------------------------------------*/
-               
-               /* XXX Do it !!! */
-               
-               /*----------------------------------------------------------
-               STEP 4: call the compiled method
-               ----------------------------------------------------------*/
-               
-               /* Restore registers */
-
-               s390_lmg  (buf, s390_r2, s390_r5, STK_BASE, CREATE_GR_OFFSET);
-               
-               /* Restore the FP registers */
-               offset = CREATE_FP_OFFSET;
-               for (i = s390_f0; i <= s390_f15; ++i) {
-                       s390_ld  (buf, i, 0, STK_BASE, offset);
-                       offset += 8;
-               }
-
-               /* Restore stack pointer and jump to the code - 
-                  R14 contains the return address to our caller */
-               s390_lgr  (buf, STK_BASE, s390_r11);
-               s390_lmg  (buf, s390_r6, s390_r14, STK_BASE, S390_REG_SAVE_OFFSET);
-               s390_br   (buf, s390_r1);
-
-               /* Flush instruction cache, since we've generated code */
-               mono_arch_flush_icache (code, buf - code);
-       
-               /* Sanity check */
-               g_assert ((buf - code) <= 512);
-       }
-
-       return code;
+       memcpy(code, patch, sizeof(patch));
 }
 
 /*========================= End of Function ========================*/
 
 /*------------------------------------------------------------------*/
 /*                                                                  */
-/* Name                - mono_arch_create_jump_trampoline                  */
+/* Name                - mono_arch_nullify_plt_entry                       */
 /*                                                                  */
-/* Function    - Create the designated type of trampoline according*/
-/*                to the 'tramp_type' parameter.                    */
+/* Function    - Nullify a PLT entry call.                         */
 /*                                                                  */
 /*------------------------------------------------------------------*/
 
-MonoJitInfo *
-mono_arch_create_jump_trampoline (MonoMethod *method)
+void
+mono_arch_nullify_plt_entry (guint8 *code, mgreg_t *regs)
 {
-       guint8 *code, *buf, *tramp = NULL;
-       MonoJitInfo *ji;
-       MonoDomain *domain = mono_domain_get();
-       gint32 displace;
-
-       tramp = mono_get_trampoline_code (MONO_TRAMPOLINE_JUMP);
-
-       mono_domain_lock (domain);
-       code = buf = mono_code_manager_reserve (domain->code_mp, METHOD_TRAMPOLINE_SIZE);
-       mono_domain_unlock (domain);
-
-       s390_basr (buf, s390_r13, 0);
-       s390_j    (buf, 6);
-       s390_llong(buf, method);
-       s390_lg   (buf, s390_r13, 0, s390_r13, 4);
-       displace = (tramp - buf) / 2;
-       s390_jcl  (buf, S390_CC_UN, displace);
-
-       mono_arch_flush_icache (code, buf-code);
-
-       g_assert ((buf - code) <= JUMP_TRAMPOLINE_SIZE);
-       
-       ji              = g_new0 (MonoJitInfo, 1);
-       ji->method      = method;
-       ji->code_start  = code;
-       ji->code_size   = buf - code;
-       
-       mono_jit_stats.method_trampolines++;
-
-       return ji;
+       g_assert_not_reached ();
 }
 
 /*========================= End of Function ========================*/
 
 /*------------------------------------------------------------------*/
 /*                                                                  */
-/* Name                - mono_arch_create_jit_trampoline                   */
+/* Name                - mono_arch_get_vcall_slot                          */
 /*                                                                  */
-/* Function    - Creates a trampoline function for virtual methods.*/
-/*                If the created code is called it first starts JIT */
-/*                compilation and then calls the newly created      */
-/*                method. It also replaces the corresponding vtable */
-/*                entry (see s390_magic_trampoline).                */
+/* Function    - This method is called by the arch independent     */
+/*            trampoline code to determine the vtable slot used by  */
+/*            the call which invoked the trampoline.                */
 /*                                                                  */
-/*                A trampoline consists of two parts: a main        */
-/*                fragment, shared by all method trampolines, and   */
-/*                and some code specific to each method, which      */
-/*                hard-codes a reference to that method and then    */
-/*                calls the main fragment.                          */
+/* Parameters   - code   - Pointer into caller code                 */
+/*                regs   - Register state at the point of the call  */
+/*                displacement - Out parameter which will receive   */
+/*                the displacement of the vtable slot               */
 /*                                                                  */
-/*                The main fragment contains a call to              */
-/*                's390_magic_trampoline', which performs a call    */
-/*                to the JIT compiler and substitutes the method-   */
-/*                specific fragment with some code that directly    */
-/*                calls the JIT-compiled method.                    */
+/*------------------------------------------------------------------*/
+
+gpointer
+mono_arch_get_vcall_slot (guint8 *code, mgreg_t *regs, int *displacement)
+{
+       int reg, lkReg;
+       guchar* base;
+       unsigned short opcode;
+       char *sp;
+       MonoLMF *lmf = (MonoLMF *) ((gchar *) regs - sizeof(MonoLMF));
+
+       // We are passed sp instead of the register array
+#if 0
+       sp = (char *) regs;
+#endif
+       sp = (char *) lmf->gregs[s390_r15];
+
+       *displacement = 0;
+
+       opcode = *((unsigned short *) (code - 6));
+       if (opcode == 0xc0e5)
+               /* This is the 'brasl' instruction */
+               return NULL;
+
+       /*-----------------------------------*/
+       /* This is a basr r14,Rz instruction */
+       /* If it's preceded by a LG Rx,d(Ry) */
+       /* If Rz == 1 then this is virtual   */
+       /* call.                             */
+       /*-----------------------------------*/
+       code    -= 6;
+
+       /*-----------------------------------*/
+       /* If call is preceded by LGR then   */
+       /* there's nothing to patch          */
+       /*-----------------------------------*/
+       if ((code[0] == 0xb9) && (code[1] == 0x04))
+               return NULL;
+
+       /*-----------------------------------*/
+       /* We back up until we're pointing at*/
+       /* the base/displacement portion of  */
+       /* the LG instruction                */
+       /*-----------------------------------*/
+       lkReg    = code[5] & 0x0f;
+
+       /*-----------------------------------*/
+       /* The LG instruction has format:    */
+       /* E3x0ylllhh04 - where:             */
+       /* x = Rx; y = Ry;                   */
+       /* lll = low 12 bits of displacement */
+       /* hh  = high 8 bits of displacement */
+       /*-----------------------------------*/
+       reg      = code[0] >> 4;
+       *displacement = (code[2] << 12) |
+                       ((code[0] & 0x0f) << 8) |
+                       code[1];
+
+       if (code[2] & 0x80)
+               *displacement |= 0xfff00000;
+
+       base = ((guchar *) lmf->gregs[reg]);
+#if 0
+       if (reg > 5)
+               base = *((guchar **) (sp + S390_REG_SAVE_OFFSET +
+                                                         sizeof(long)*(reg-6)));
+       else
+               base = *((guchar **) ((sp - CREATE_STACK_SIZE) +
+                                                         CREATE_GR_OFFSET +
+                                                         sizeof(long)*(reg-2)));
+#endif
+       if (lkReg != 1)
+               /* Non virtual call */
+               return NULL;
+
+       return base;
+}
+
+/*========================= End of Function ========================*/
+
+/*------------------------------------------------------------------*/
 /*                                                                  */
-/* Parameter    - method - Pointer to the method information        */
+/* Name                - mono_arch_create_trampoline_code                  */
 /*                                                                  */
-/* Returns      - A pointer to the newly created code               */
+/* Function    - Create the designated type of trampoline according*/
+/*                to the 'tramp_type' parameter.                    */
 /*                                                                  */
 /*------------------------------------------------------------------*/
 
-gpointer
-mono_arch_create_jit_trampoline (MonoMethod *method)
+guchar *
+mono_arch_create_trampoline_code (MonoTrampolineType tramp_type)
 {
-       guint8 *code, *buf;
-       static guint8 *vc = NULL;
-       gint32 displace;
 
-       vc = mono_get_trampoline_code (MONO_TRAMPOLINE_GENERIC);
+       guint8 *buf, *tramp, *code;
+       int i, offset, lmfOffset;
 
-       /* This is the method-specific part of the trampoline. Its purpose is
-       to provide the generic part with the MonoMethod *method pointer. We'll
-       use r13 to keep that value, for instance. However, the generic part of
-       the trampoline relies on r11 having the same value it had before coming
-       here, so we must save it before. */
-       code = buf = g_malloc(METHOD_TRAMPOLINE_SIZE);
+       /* Now we'll create in 'buf' the S/390 trampoline code. This
+          is the trampoline code common to all methods  */
+               
+       code = buf = mono_global_codeman_reserve(512);
+               
+       /*-----------------------------------------------------------
+         STEP 0: First create a non-standard function prologue with a
+         stack size big enough to save our registers.
+         -----------------------------------------------------------*/
+               
+       s390_stmg (buf, s390_r6, s390_r15, STK_BASE, S390_REG_SAVE_OFFSET);
+       s390_lgr  (buf, s390_r11, s390_r15);
+       s390_aghi (buf, STK_BASE, -CREATE_STACK_SIZE);
+       s390_stg  (buf, s390_r11, 0, STK_BASE, 0);
+       s390_stg  (buf, s390_r1, 0, STK_BASE, METHOD_SAVE_OFFSET);
+       s390_stmg (buf, s390_r2, s390_r5, STK_BASE, CREATE_GR_OFFSET);
+
+       /* Save the FP registers */
+       offset = CREATE_FP_OFFSET;
+       for (i = s390_f0; i <= s390_f15; ++i) {
+               s390_std  (buf, i, 0, STK_BASE, offset);
+               offset += 8;
+       }
 
+       /*----------------------------------------------------------
+         STEP 1: call 'mono_get_lmf_addr()' to get the address of our
+         LMF. We'll need to restore it after the call to
+         's390_magic_trampoline' and before the call to the native
+         method.
+         ----------------------------------------------------------*/
+                               
        s390_basr (buf, s390_r13, 0);
        s390_j    (buf, 6);
-       s390_llong(buf, method);
-       s390_lg   (buf, s390_r13, 0, s390_r13, 4);
-       displace = (vc - buf) / 2;
-       s390_jcl  (buf, S390_CC_UN, displace);
+       s390_llong(buf, mono_get_lmf_addr);
+       s390_lg   (buf, s390_r1, 0, s390_r13, 4);
+       s390_basr (buf, s390_r14, s390_r1);
+
+       /*---------------------------------------------------------------*/
+       /* we build the MonoLMF structure on the stack - see mini-s390.h */
+       /* Keep in sync with the code in mono_arch_emit_prolog           */
+       /*---------------------------------------------------------------*/
+       lmfOffset = CREATE_STACK_SIZE - sizeof(MonoLMF);
+                                                                                       
+       s390_lgr   (buf, s390_r13, STK_BASE);
+       s390_aghi  (buf, s390_r13, lmfOffset);  
+                                                                                       
+       /*---------------------------------------------------------------*/     
+       /* Set lmf.lmf_addr = jit_tls->lmf                               */     
+       /*---------------------------------------------------------------*/     
+       s390_stg   (buf, s390_r2, 0, s390_r13,                          
+                           G_STRUCT_OFFSET(MonoLMF, lmf_addr));                        
+                                                                                       
+       /*---------------------------------------------------------------*/     
+       /* Get current lmf                                               */     
+       /*---------------------------------------------------------------*/     
+       s390_lg    (buf, s390_r0, 0, s390_r2, 0);                               
+                                                                                       
+       /*---------------------------------------------------------------*/     
+       /* Set our lmf as the current lmf                                */     
+       /*---------------------------------------------------------------*/     
+       s390_stg   (buf, s390_r13, 0, s390_r2, 0);                              
+                                                                                       
+       /*---------------------------------------------------------------*/     
+       /* Have our lmf.previous_lmf point to the last lmf               */     
+       /*---------------------------------------------------------------*/     
+       s390_stg   (buf, s390_r0, 0, s390_r13,                          
+                           G_STRUCT_OFFSET(MonoLMF, previous_lmf));                    
+                                                                                       
+       /*---------------------------------------------------------------*/     
+       /* save method info                                              */     
+       /*---------------------------------------------------------------*/     
+       s390_lg    (buf, s390_r1, 0, STK_BASE, METHOD_SAVE_OFFSET);
+       s390_stg   (buf, s390_r1, 0, s390_r13,                          
+                           G_STRUCT_OFFSET(MonoLMF, method));                          
+                                                                       
+       /*---------------------------------------------------------------*/     
+       /* save the current SP                                           */     
+       /*---------------------------------------------------------------*/     
+       s390_lg    (buf, s390_r1, 0, STK_BASE, 0);
+       s390_stg   (buf, s390_r1, 0, s390_r13, G_STRUCT_OFFSET(MonoLMF, ebp));  
+                                                                       
+       /*---------------------------------------------------------------*/     
+       /* save the current IP                                           */     
+       /*---------------------------------------------------------------*/     
+       if (tramp_type == MONO_TRAMPOLINE_JUMP) {
+               s390_lghi  (buf, s390_r1, 0);
+       } else {
+               s390_lg    (buf, s390_r1, 0, s390_r1, S390_RET_ADDR_OFFSET);
+               //                      s390_la    (buf, s390_r1, 0, s390_r1, 0);
+       }
+       s390_stg   (buf, s390_r1, 0, s390_r13, G_STRUCT_OFFSET(MonoLMF, eip));  
+                                                                                       
+       /*---------------------------------------------------------------*/     
+       /* Save general and floating point registers                     */     
+       /*---------------------------------------------------------------*/     
+       s390_mvc   (buf, 4*sizeof(gulong), s390_r13, G_STRUCT_OFFSET(MonoLMF, gregs[2]), 
+                   STK_BASE, CREATE_GR_OFFSET);
+       s390_mvc   (buf, 10*sizeof(gulong), s390_r13, G_STRUCT_OFFSET(MonoLMF, gregs[6]), 
+                   s390_r11, S390_REG_SAVE_OFFSET);
+
+       /* Simply copy fpregs already saved above                        */
+       s390_mvc   (buf, 16*sizeof(double), s390_r13, G_STRUCT_OFFSET(MonoLMF, fregs[0]),
+                   STK_BASE, CREATE_FP_OFFSET);
+
+       /*---------------------------------------------------------------*/
+       /* STEP 2: call the C trampoline function                        */
+       /*---------------------------------------------------------------*/
+                               
+       /* Set arguments */
+
+       /* Arg 1: mgreg_t *regs. We pass sp instead */
+       s390_la  (buf, s390_r2, 0, STK_BASE, CREATE_STACK_SIZE);
+               
+       /* Arg 2: code (next address to the instruction that called us) */
+       if (tramp_type == MONO_TRAMPOLINE_JUMP) {
+               s390_lghi (buf, s390_r3, 0);
+       } else {
+               s390_lg   (buf, s390_r3, 0, s390_r11, S390_RET_ADDR_OFFSET);
+       }
+
+       /* Arg 3: MonoMethod *method. It was put in r1 by the
+          method-specific trampoline code, and then saved before the call
+          to mono_get_lmf_addr()'. */
+       s390_lg  (buf, s390_r4, 0, STK_BASE, METHOD_SAVE_OFFSET);
+
+       /* Arg 4: trampoline address. Ignore for now */
+               
+       /* Calculate call address and call the C trampoline. Return value will be in r2 */
+       s390_basr (buf, s390_r13, 0);
+       s390_j    (buf, 6);
+       tramp = (guint8*)mono_get_trampoline_func (tramp_type);
+       s390_llong (buf, tramp);
+       s390_lg   (buf, s390_r1, 0, s390_r13, 4);
+       s390_basr (buf, s390_r14, s390_r1);
+               
+       /* OK, code address is now on r2. Move it to r1, so that we
+          can restore r2 and use it from r1 later */
+       s390_lgr  (buf, s390_r1, s390_r2);
+
+       /*----------------------------------------------------------
+         STEP 3: Restore the LMF
+         ----------------------------------------------------------*/
+       restoreLMF(buf, STK_BASE, CREATE_STACK_SIZE);
+       
+       /*----------------------------------------------------------
+         STEP 4: call the compiled method
+         ----------------------------------------------------------*/
+               
+       /* Restore registers */
+
+       s390_lmg  (buf, s390_r2, s390_r5, STK_BASE, CREATE_GR_OFFSET);
+               
+       /* Restore the FP registers */
+       offset = CREATE_FP_OFFSET;
+       for (i = s390_f0; i <= s390_f15; ++i) {
+               s390_ld  (buf, i, 0, STK_BASE, offset);
+               offset += 8;
+       }
+
+       /* Restore stack pointer and jump to the code -
+          R14 contains the return address to our caller */
+       s390_lgr  (buf, STK_BASE, s390_r11);
+       s390_lmg  (buf, s390_r6, s390_r14, STK_BASE, S390_REG_SAVE_OFFSET);
+
+       if (tramp_type == MONO_TRAMPOLINE_CLASS_INIT || tramp_type == MONO_TRAMPOLINE_GENERIC_CLASS_INIT)
+               s390_br (buf, s390_r14);
+       else
+               s390_br (buf, s390_r1);
 
        /* Flush instruction cache, since we've generated code */
        mono_arch_flush_icache (code, buf - code);
-               
-       /* Sanity check */
-       g_assert ((buf - code) <= METHOD_TRAMPOLINE_SIZE);
        
-       mono_jit_stats.method_trampolines++;
+       /* Sanity check */
+       g_assert ((buf - code) <= 512);
 
        return code;
 }
@@ -456,86 +500,62 @@ mono_arch_create_jit_trampoline (MonoMethod *method)
 
 /*------------------------------------------------------------------*/
 /*                                                                  */
-/* Name                - mono_arch_create_class_init_trampoline            */
-/*                                                                  */
-/* Function    - Creates a trampoline function to run a type init- */
-/*                ializer. If the trampoline is called, it calls    */
-/*                mono_runtime_class_init with the given vtable,    */
-/*                then patches the caller code so it does not get   */
-/*                called any more.                                  */
-/*                                                                  */
-/* Parameter    - vtable - The type to initialize                   */
+/* Name                - mono_arch_create_specific_trampoline              */
 /*                                                                  */
-/* Returns      - A pointer to the newly created code               */
+/* Function    - Creates the given kind of specific trampoline     */
 /*                                                                  */
 /*------------------------------------------------------------------*/
 
 gpointer
-mono_arch_create_class_init_trampoline (MonoVTable *vtable)
+mono_arch_create_specific_trampoline (gpointer arg1, MonoTrampolineType tramp_type, MonoDomain *domain, guint32 *code_len)
 {
        guint8 *code, *buf, *tramp;
+       gint32 displace;
 
-       tramp = mono_get_trampoline_code (MONO_TRAMPOLINE_CLASS_INIT);
-
-       /* This is the method-specific part of the trampoline. Its purpose is
-       to provide the generic part with the MonoMethod *method pointer. We'll
-       use r11 to keep that value, for instance. However, the generic part of
-       the trampoline relies on r11 having the same value it had before coming
-       here, so we must save it before. */
-       code = buf = g_malloc(METHOD_TRAMPOLINE_SIZE);
+       tramp = mono_get_trampoline_code (tramp_type);
 
-       s390_stg  (buf, s390_r14, 0, STK_BASE, S390_RET_ADDR_OFFSET);
-       s390_aghi (buf, STK_BASE, -S390_MINIMAL_STACK_SIZE);
+       /*----------------------------------------------------------*/
+       /* This is the method-specific part of the trampoline. Its  */
+       /* purpose is to provide the generic part with the          */
+       /* MonoMethod *method pointer. We'll use r1 to keep it.     */
+       /*----------------------------------------------------------*/
+       code = buf = mono_domain_code_reserve (domain, SPECIFIC_TRAMPOLINE_SIZE);
 
        s390_basr (buf, s390_r1, 0);
        s390_j    (buf, 6);
-       s390_llong(buf, vtable);
-        s390_llong(buf, s390_class_init_trampoline);
-       s390_lgr  (buf, s390_r3, s390_r14);
-       s390_lg   (buf, s390_r2, 0, s390_r1, 4);
-       s390_lghi (buf, s390_r4, 0);
-       s390_lg   (buf, s390_r1, 0, s390_r1, 8);
-       s390_basr (buf, s390_r14, s390_r1);
-
-       s390_aghi (buf, STK_BASE, S390_MINIMAL_STACK_SIZE);
-       s390_lg   (buf, s390_r14, 0, STK_BASE, S390_RET_ADDR_OFFSET);
-       s390_br   (buf, s390_r14);
+       s390_llong(buf, arg1);
+       s390_lg   (buf, s390_r1, 0, s390_r1, 4);
+       displace = (tramp - buf) / 2;
+       s390_jcl  (buf, S390_CC_UN, displace);
 
        /* Flush instruction cache, since we've generated code */
        mono_arch_flush_icache (code, buf - code);
-               
-       /* Sanity check */
-       g_assert ((buf - code) <= METHOD_TRAMPOLINE_SIZE);
 
-       mono_jit_stats.method_trampolines++;
+       /* Sanity check */
+       g_assert ((buf - code) <= SPECIFIC_TRAMPOLINE_SIZE);
 
+       if (code_len)
+               *code_len = buf - code;
+       
        return code;
-}
+}      
 
 /*========================= End of Function ========================*/
 
 /*------------------------------------------------------------------*/
 /*                                                                  */
-/* Name                - mono_debuger_create_notification_function         */
+/* Name                - mono_arch_create_rgctx_lazy_fetch_trampoline      */
 /*                                                                  */
-/* Function    - This method is only called when running in the    */
-/*                Mono debugger. It returns a pointer to the        */
-/*                arch specific notification function.              */
+/* Function    -                                                   */
 /*                                                                  */
 /*------------------------------------------------------------------*/
 
 gpointer
-mono_debugger_create_notification_function (gpointer *notification_address)
+mono_arch_create_rgctx_lazy_fetch_trampoline (guint32 encoded_offset)
 {
-       guint8 *ptr, *buf;
-
-       ptr = buf = g_malloc0 (16);
-       s390_break (buf);
-       if (notification_address)
-               *notification_address = buf;
-       s390_br (buf, s390_r14);
-
-       return ptr;
-}
+       /* FIXME: implement! */
+       g_assert_not_reached ();
+       return NULL;
+}      
 
 /*========================= End of Function ========================*/