[jit] Expose helper method to the rest of the JIT to get specific trampoline descript...
[mono.git] / mono / mini / mini-s390x.c
index c405aeb1d2ac6c022d87f6f27c9fc79fea88faf5..a1618c932ebf84d95e0989029c0a4cdac80b0637 100644 (file)
@@ -59,7 +59,7 @@ if (ins->inst_target_bb->native_offset) {                                     \
 #define EMIT_COND_SYSTEM_EXCEPTION(cond,exc_name)                      \
         do {                                                           \
                mono_add_patch_info (cfg, code - cfg->native_code,      \
-                                   MONO_PATCH_INFO_EXC, exc_name);     \
+                                    MONO_PATCH_INFO_EXC, exc_name);    \
                s390_jcl (code, cond, 0);                               \
        } while (0); 
 
@@ -232,7 +232,7 @@ if (ins->inst_target_bb->native_offset) {                                   \
 #define S390_TRACE_STACK_SIZE (5*sizeof(gpointer)+4*sizeof(gdouble))
 
 #define BREAKPOINT_SIZE                sizeof(breakpoint_t)
-#define S390X_NOP_SIZE         sizeof(I_Format)
+#define S390X_NOP_SIZE         sizeof(RR_Format)
 
 #define MAX(a, b) ((a) > (b) ? (a) : (b))
 
@@ -246,8 +246,8 @@ if (ins->inst_target_bb->native_offset) {                                   \
 #define JUMP_SIZE      6
 #define ENABLE_WRONG_METHOD_CHECK 0
 
-#define mono_mini_arch_lock() EnterCriticalSection (&mini_arch_mutex)
-#define mono_mini_arch_unlock() LeaveCriticalSection (&mini_arch_mutex)
+#define mono_mini_arch_lock() mono_mutex_lock (&mini_arch_mutex)
+#define mono_mini_arch_unlock() mono_mutex_unlock (&mini_arch_mutex)
 
 /*========================= End of Defines =========================*/
 
@@ -257,7 +257,10 @@ if (ins->inst_target_bb->native_offset) {                                  \
 
 #include "mini.h"
 #include <string.h>
+#include <sys/types.h>
+#include <unistd.h>
 
+#include <mono/metadata/abi-details.h>
 #include <mono/metadata/appdomain.h>
 #include <mono/metadata/debug-helpers.h>
 #include <mono/metadata/profiler-private.h>
@@ -267,6 +270,7 @@ if (ins->inst_target_bb->native_offset) {                                   \
 
 #include "mini-s390x.h"
 #include "cpu-s390x.h"
+#include "support-s390x.h"
 #include "jit-icalls.h"
 #include "ir-emit.h"
 #include "trace.h"
@@ -365,14 +369,12 @@ static guint8 * backUpStackPtr(MonoCompile *, guint8 *);
 static void decodeParm (MonoType *, void *, int);
 static void enter_method (MonoMethod *, RegParm *, char *);
 static void leave_method (MonoMethod *, ...);
-static gboolean is_regsize_var (MonoType *);
 static inline void add_general (guint *, size_data *, ArgInfo *);
 static inline void add_stackParm (guint *, size_data *, ArgInfo *, gint);
 static inline void add_float (guint *, size_data *, ArgInfo *);
 static CallInfo * get_call_info (MonoCompile *, MonoMemPool *, MonoMethodSignature *);
 static guchar * emit_float_to_int (MonoCompile *, guchar *, int, int, int, gboolean);
 static guint8 * emit_load_volatile_arguments (guint8 *, MonoCompile *);
-static void catch_SIGILL(int, siginfo_t *, void *);
 static __inline__ void emit_unwind_regs(MonoCompile *, guint8 *, int, int, long);
 
 /*========================= End of Prototypes ======================*/
@@ -383,7 +385,7 @@ static __inline__ void emit_unwind_regs(MonoCompile *, guint8 *, int, int, long)
 
 int mono_exc_esp_offset = 0;
 
-static int indent_level = 0;
+__thread int indent_level = 0;
 
 static gint appdomain_tls_offset = -1,
            lmf_tls_offset = -1,
@@ -395,14 +397,6 @@ gboolean lmf_addr_key_inited = FALSE;
 
 facilityList_t facs;
 
-#if 0
-
-extern __thread MonoDomain *tls_appdomain;
-extern __thread MonoThread *tls_current_object;
-extern __thread gpointer   mono_lmf_addr;
-               
-#endif
-
 /*
  * The code generated for sequence points reads from this location, 
  * which is made read-only when single stepping is enabled.
@@ -416,10 +410,7 @@ static gpointer bp_trigger_page;
 
 breakpoint_t breakpointCode;
 
-/* 
- * This mutex protects architecture specific caches 
- */
-static CRITICAL_SECTION mini_arch_mutex;
+static mono_mutex_t mini_arch_mutex;
 
 /*====================== End of Global Variables ===================*/
 
@@ -633,7 +624,7 @@ indent (int diff) {
        if (diff < 0)
                indent_level += diff;
        v = indent_level;
-       printf("[%3d] ",v);
+       printf("%p [%3d] ",(void *)pthread_self(),v);
        while (v-- > 0) {
                printf (". ");
        }
@@ -1234,7 +1225,7 @@ handle_enum:
                        mono_method_signature (method)->ret->type);
        }
 
-       ip = ((gint64) __builtin_return_address (0));
+       ip = ((gint64) __builtin_extract_return_addr (__builtin_return_address (0)));
        printf (" ip: %p\n", (gpointer) ip);
 }
 
@@ -1269,20 +1260,7 @@ mono_arch_init (void)
 {
        guint8 *code;
 
-#if 0
-       /*
-        * When we do an architectural level set at z9 or better 
-        * we can use the STFLE instruction to show us
-        * what hardware facilities are available
-        */
-       int lFacility = sizeof(facs) % 8;
-
-       memset((char *) &facs, 0, sizeof(facs));
-
-       __asm__ ("      lgfr    0,%1\n"
-                "      stfle   %0\n"
-                : "=m" (facs) : "r" (lFacility) : "0", "cc");
-#endif
+       mono_mutex_init_recursive (&mini_arch_mutex);
 
        ss_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ);
        bp_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ);
@@ -1309,6 +1287,11 @@ mono_arch_init (void)
 void
 mono_arch_cleanup (void)
 {
+       if (ss_trigger_page)
+               mono_vfree (ss_trigger_page, mono_pagesize ());
+       if (bp_trigger_page)
+               mono_vfree (bp_trigger_page, mono_pagesize ());
+       mono_mutex_destroy (&mini_arch_mutex);
 }
 
 /*========================= End of Function ========================*/
@@ -1329,8 +1312,7 @@ mono_arch_cpu_optimizations (guint32 *exclude_mask)
        /*----------------------------------------------------------*/
        /* No s390-specific optimizations yet                       */
        /*----------------------------------------------------------*/
-       *exclude_mask = MONO_OPT_INLINE|MONO_OPT_LINEARS;
-//     *exclude_mask = MONO_OPT_INLINE;
+       *exclude_mask = MONO_OPT_LINEARS;
        return opts;
 }
 
@@ -1351,44 +1333,6 @@ mono_arch_cpu_enumerate_simd_versions (void)
 }
 /*========================= End of Function ========================*/
 
-/*------------------------------------------------------------------*/
-/*                                                                  */
-/* Name                -                                                   */
-/*                                                                  */
-/* Function    -                                                   */
-/*                                                                 */
-/*------------------------------------------------------------------*/
-
-static gboolean
-is_regsize_var (MonoType *t) {
-       if (t->byref)
-               return TRUE;
-       switch (mono_type_get_underlying_type (t)->type) {
-       case MONO_TYPE_I4:
-       case MONO_TYPE_U4:
-       case MONO_TYPE_I:
-       case MONO_TYPE_I8:
-       case MONO_TYPE_U8:
-       case MONO_TYPE_U:
-       case MONO_TYPE_PTR:
-       case MONO_TYPE_FNPTR:
-               return TRUE;
-       case MONO_TYPE_OBJECT:
-       case MONO_TYPE_STRING:
-       case MONO_TYPE_CLASS:
-       case MONO_TYPE_SZARRAY:
-       case MONO_TYPE_ARRAY:
-               return FALSE;
-       case MONO_TYPE_VALUETYPE:
-               if (t->data.klass->enumtype)
-                       return is_regsize_var (mono_class_enum_basetype (t->data.klass));
-               return FALSE;
-       }
-       return FALSE;
-}
-
-/*========================= End of Function ========================*/
-
 /*------------------------------------------------------------------*/
 /*                                                                  */
 /* Name                - mono_arch_get_allocatable_int_vars                */
@@ -1416,7 +1360,7 @@ mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
                        continue;
 
                /* we can only allocate 32 bit values */
-               if (is_regsize_var (ins->inst_vtype)) {
+               if (mono_is_regsize_var(ins->inst_vtype)) {
                        g_assert (MONO_VARINFO (cfg, i)->reg == -1);
                        g_assert (i == vmv->idx);
                        vars = mono_varlist_insert_sorted (cfg, vars, vmv, FALSE);
@@ -1826,7 +1770,11 @@ enum_retvalue:
                        MonoMarshalType *info;
                        MonoClass *klass = mono_class_from_mono_type (ptype);
 
-                       size = mini_type_stack_size_full(gsctx, &klass->byval_arg, NULL, sig->pinvoke);
+                       if (sig->pinvoke)
+                               size = mono_class_native_size(klass, NULL);
+                       else
+                               size = mono_class_value_size(klass, NULL);
+
                        if (simpleType != MONO_TYPE_GENERICINST) {
                                info = mono_marshal_load_type_info(klass);
 
@@ -2002,7 +1950,7 @@ mono_arch_allocate_vars (MonoCompile *cfg)
        cinfo   = get_call_info (cfg, cfg->mempool, sig);
 
        if (!cinfo->struct_ret) {
-               switch (mono_type_get_underlying_type (sig->ret)->type) {
+               switch (mini_type_get_underlying_type (cfg->generic_sharing_context, sig->ret)->type) {
                case MONO_TYPE_VOID:
                        break;
                default:
@@ -2375,7 +2323,7 @@ mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
                        t = sig->params [i - sig->hasthis];
                else
                        t = &mono_defaults.int_class->byval_arg;
-               t = mono_type_get_underlying_type (t);
+               t = mini_type_get_underlying_type (cfg->generic_sharing_context, t);
 
                in = call->args [i];
 
@@ -2591,7 +2539,8 @@ mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src)
 void
 mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val)
 {
-       MonoType *ret = mono_type_get_underlying_type (mono_method_signature (method)->ret);
+       MonoType *ret = mini_type_get_underlying_type (cfg->generic_sharing_context,
+                               mono_method_signature (method)->ret);
 
        if (!ret->byref) {
                if (ret->type == MONO_TYPE_R4) {
@@ -2649,54 +2598,23 @@ mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p,
        if (cfg->method->save_lmf)
                parmOffset -= sizeof(MonoLMF);
        fpOffset   = parmOffset + (5*sizeof(gpointer));
-       if ((!mono_hwcap_s390x_has_ld) && (fpOffset > 4096)) {
-               s390_lgr (code, s390_r12, STK_BASE);
-               baseReg = s390_r12;
-               while (fpOffset > 4096) {
-                       s390_aghi (code, baseReg, 4096);
-                       fpOffset   -= 4096;
-                       parmOffset -= 4096;
-               }
-       } else {
-               baseReg = STK_BASE;
-       }       
+       baseReg = STK_BASE;
 
        s390_stmg (code, s390_r2, s390_r6, STK_BASE, parmOffset);
-       if (mono_hwcap_s390x_has_ld) {
-               s390_stdy (code, s390_f0, 0, STK_BASE, fpOffset);
-               s390_stdy (code, s390_f2, 0, STK_BASE, fpOffset+sizeof(gdouble));
-               s390_stdy (code, s390_f4, 0, STK_BASE, fpOffset+2*sizeof(gdouble));
-               s390_stdy (code, s390_f6, 0, STK_BASE, fpOffset+3*sizeof(gdouble));
-       } else {
-               s390_std  (code, s390_f0, 0, baseReg, fpOffset);
-               s390_std  (code, s390_f2, 0, baseReg, fpOffset+sizeof(gdouble));
-               s390_std  (code, s390_f4, 0, baseReg, fpOffset+2*sizeof(gdouble));
-               s390_std  (code, s390_f6, 0, baseReg, fpOffset+3*sizeof(gdouble));
-       }
-       s390_basr (code, s390_r13, 0);
-       s390_j    (code, 10);
-       s390_llong(code, cfg->method);
-       s390_llong(code, func);
-       s390_lg   (code, s390_r2, 0, s390_r13, 4);
-       if (mono_hwcap_s390x_has_ld)
-               s390_lay  (code, s390_r3, 0, STK_BASE, parmOffset);
-       else
-               s390_la   (code, s390_r3, 0, baseReg, parmOffset);
+       s390_stdy (code, s390_f0, 0, STK_BASE, fpOffset);
+       s390_stdy (code, s390_f2, 0, STK_BASE, fpOffset+sizeof(gdouble));
+       s390_stdy (code, s390_f4, 0, STK_BASE, fpOffset+2*sizeof(gdouble));
+       s390_stdy (code, s390_f6, 0, STK_BASE, fpOffset+3*sizeof(gdouble));
+       S390_SET  (code, s390_r1, func);
+       S390_SET  (code, s390_r2, cfg->method);
+       s390_lay  (code, s390_r3, 0, STK_BASE, parmOffset);
        s390_lgr  (code, s390_r4, STK_BASE);
        s390_aghi (code, s390_r4, cfg->stack_usage);
-       s390_lg   (code, s390_r1, 0, s390_r13, 12);
        s390_basr (code, s390_r14, s390_r1);
-       if (mono_hwcap_s390x_has_ld) {
-               s390_ldy  (code, s390_f6, 0, STK_BASE, fpOffset+3*sizeof(gdouble));
-               s390_ldy  (code, s390_f4, 0, STK_BASE, fpOffset+2*sizeof(gdouble));
-               s390_ldy  (code, s390_f2, 0, STK_BASE, fpOffset+sizeof(gdouble));
-               s390_ldy  (code, s390_f0, 0, STK_BASE, fpOffset);
-       } else {
-               s390_ld   (code, s390_f6, 0, baseReg, fpOffset+3*sizeof(gdouble));
-               s390_ld   (code, s390_f4, 0, baseReg, fpOffset+2*sizeof(gdouble));
-               s390_ld   (code, s390_f2, 0, baseReg, fpOffset+sizeof(gdouble));
-               s390_ld   (code, s390_f0, 0, baseReg, fpOffset);
-       }
+       s390_ldy  (code, s390_f6, 0, STK_BASE, fpOffset+3*sizeof(gdouble));
+       s390_ldy  (code, s390_f4, 0, STK_BASE, fpOffset+2*sizeof(gdouble));
+       s390_ldy  (code, s390_f2, 0, STK_BASE, fpOffset+sizeof(gdouble));
+       s390_ldy  (code, s390_f0, 0, STK_BASE, fpOffset);
        s390_lmg  (code, s390_r2, s390_r6, STK_BASE, parmOffset);
 
        return code;
@@ -2721,7 +2639,8 @@ mono_arch_instrument_epilog_full (MonoCompile *cfg, void *func, void *p, gboolea
                   saveOffset,
                   offset;
        MonoMethod *method = cfg->method;
-       int        rtype = mono_type_get_underlying_type (mono_method_signature (method)->ret)->type;
+       int rtype = mini_type_get_underlying_type (cfg->generic_sharing_context,
+                       mono_method_signature (method)->ret)->type;
 
        offset = code - cfg->native_code;
        /*-----------------------------------------*/
@@ -2796,12 +2715,8 @@ handle_enum:
                break;
        }
 
-       s390_basr (code, s390_r13, 0);
-       s390_j    (code, 10);
-       s390_llong(code, cfg->method);
-       s390_llong(code, func);
-       s390_lg   (code, s390_r2, 0, s390_r13, 4);
-       s390_lg   (code, s390_r1, 0, s390_r13, 12);
+       S390_SET  (code, s390_r1, func);
+       S390_SET  (code, s390_r2, cfg->method);
        s390_basr (code, s390_r14, s390_r1);
 
        switch (save_mode) {
@@ -2883,6 +2798,7 @@ mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
                case OP_IREM_UN_IMM:
                case OP_LAND_IMM:
                case OP_LOR_IMM:
+               case OP_LREM_IMM:
                case OP_LXOR_IMM:
                case OP_LOCALLOC_IMM:
                        mono_decompose_op_imm (cfg, bb, ins);
@@ -2930,14 +2846,14 @@ emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size,
                }
        } else {
                short *o[1];
-               s390_basr   (code, s390_r13, 0);
-               s390_j      (code, 10);
-               s390_llong  (code, 0x41e0000000000000llu);
-               s390_llong  (code, 0x41f0000000000000llu);
+               S390_SET    (code, s390_r13, 0x41e0000000000000llu);
+               s390_ldgr   (code, s390_f14, s390_r13);
                s390_ldr    (code, s390_f15, sreg);
-               s390_cdb    (code, s390_f15, 0, s390_r13, 4);
+               s390_cdbr   (code, s390_f15, s390_f14);
                s390_jl     (code, 0); CODEPTR (code, o[0]);
-               s390_sdb    (code, s390_f15, 0, s390_r13, 12);
+               S390_SET    (code, s390_r13, 0x41f0000000000000llu);
+               s390_ldgr   (code, s390_f14, s390_r13);
+               s390_sdbr   (code, s390_f15, s390_f14);
                s390_cfdbr  (code, dreg, 7, s390_f15);
                s390_j      (code, 4);
                PTRSLOT (code, o[0]);
@@ -3057,28 +2973,14 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                }
                        break;
                case OP_STOREI4_MEMBASE_IMM: {
-                       if (s390_is_imm16(ins->inst_imm)) {
-                               s390_lghi (code, s390_r0, ins->inst_imm);
-                       } else {
-                               s390_basr (code, s390_r13, 0);
-                               s390_j    (code, 6);
-                               s390_llong(code, ins->inst_imm);
-                               s390_lg   (code, s390_r0, 0, s390_r13, 4);
-                       }
+                       s390_lgfi (code, s390_r0, ins->inst_imm);
                        S390_LONG (code, sty, st, s390_r0, 0, 
                                   ins->inst_destbasereg, ins->inst_offset);
                }
                        break;
                case OP_STORE_MEMBASE_IMM:
                case OP_STOREI8_MEMBASE_IMM: {
-                       if (s390_is_imm16(ins->inst_imm)) {
-                               s390_lghi (code, s390_r0, ins->inst_imm);
-                       } else {
-                               s390_basr (code, s390_r13, 0);
-                               s390_j    (code, 6);
-                               s390_llong(code, ins->inst_imm);
-                               s390_lg   (code, s390_r0, 0, s390_r13, 4);
-                       }
+                       S390_SET (code, s390_r0, ins->inst_imm);
                        S390_LONG (code, stg, stg, s390_r0, 0, 
                                   ins->inst_destbasereg, ins->inst_offset);
                }
@@ -3144,90 +3046,35 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                }
                        break;
                case OP_LCONV_TO_I1: {
-#if 0
                        s390_lgbr (code, ins->dreg, ins->sreg1);
-#else
-                       s390_sllg (code, ins->dreg, ins->sreg1, 0, 56);
-                       s390_srag (code, ins->dreg, ins->dreg, 0, 56);
-#endif
                }
                        break;
                case OP_LCONV_TO_I2: {
-#if 0
                        s390_lghr (code, ins->dreg, ins->sreg1);
-#else
-                       s390_sllg (code, ins->dreg, ins->sreg1, 0, 48);
-                       s390_srag (code, ins->dreg, ins->dreg, 0, 48);
-#endif
                }
                        break;
                case OP_LCONV_TO_U1: {
-#if 0
-                       s390_llghr (code, ins->dreg, ins->sreg1);
-#else
-                       if (ins->dreg != ins->sreg1)
-                               s390_lgr  (code, ins->dreg, ins->sreg1);
-                       s390_lghi  (code, s390_r0, 0xff);
-                       s390_ngr   (code, ins->dreg, s390_r0);
-#endif
+                       s390_llgcr (code, ins->dreg, ins->sreg1);
                }
                        break;
                case OP_LCONV_TO_U2: {
-#if 0
                        s390_llghr (code, ins->dreg, ins->sreg1);
-#else
-                       if (ins->dreg != ins->sreg1)
-                               s390_lgr  (code, ins->dreg, ins->sreg1);
-                       s390_lghi  (code, s390_r0, -1);
-                       s390_srlg  (code, s390_r0, s390_r0, 0, 48);
-                       s390_ngr   (code, ins->dreg, s390_r0);
-#endif
                }
                        break;
                case OP_ICONV_TO_I1: {
-#if 0
-                       s390_lbr  (code, ins->dreg, ins->sreg1);
-#else
-                       if (ins->dreg != ins->sreg1)
-                               s390_lr  (code, ins->dreg, ins->sreg1);
-                       s390_sll (code, ins->dreg, 0, 24);
-                       s390_sra (code, ins->dreg, 0, 24);
-                       
-#endif
+                       s390_lgbr  (code, ins->dreg, ins->sreg1);
                }
                        break;
                case OP_ICONV_TO_I2: {
-#if 0
-                       s390_lhr  (code, ins->dreg, ins->sreg1);
-#else
-                       if (ins->dreg != ins->sreg1)
-                               s390_lr  (code, ins->dreg, ins->sreg1);
-                       s390_sll (code, ins->dreg, 0, 16);
-                       s390_sra (code, ins->dreg, 0, 16);
-#endif
+                       s390_lghr  (code, ins->dreg, ins->sreg1);
                }
                        break;
                case OP_ICONV_TO_U1: {
-#if 0
-                       s390_llcr (code, ins->dreg, ins->sreg1);
-#else
-                       if (ins->dreg != ins->sreg1)
-                               s390_lr  (code, ins->dreg, ins->sreg1);
-                       s390_lhi  (code, s390_r0, 0xff);
-                       s390_nr   (code, ins->dreg, s390_r0);
-#endif
+                       s390_llgcr (code, ins->dreg, ins->sreg1);
                }
                        break;
                case OP_ICONV_TO_U2: {
-#if 0
-                       s390_llhr (code, ins->dreg, ins->sreg1);
-#else
-                       if (ins->dreg != ins->sreg1)
-                               s390_lr  (code, ins->dreg, ins->sreg1);
-                       s390_lhi  (code, s390_r0, -1);
-                       s390_srl  (code, s390_r0, 0, 16);
-                       s390_nr   (code, ins->dreg, s390_r0);
-#endif
+                       s390_llghr (code, ins->dreg, ins->sreg1);
                }
                        break;
                case OP_COMPARE: 
@@ -3247,50 +3094,25 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        break;
                case OP_COMPARE_IMM:
                case OP_LCOMPARE_IMM: {
-                       if (s390_is_imm16 (ins->inst_imm)) {
-                               s390_lghi (code, s390_r0, ins->inst_imm);
-                               if (is_unsigned (ins->next))
-                                       s390_clgr (code, ins->sreg1, s390_r0);
-                               else
-                                       s390_cgr  (code, ins->sreg1, s390_r0);
-                       } else {
-                               s390_basr (code, s390_r13, 0);
-                               s390_j    (code, 6);
-                               s390_llong(code, ins->inst_imm);
-                               if (is_unsigned (ins->next))
-                                       s390_clg  (code, ins->sreg1, 0, s390_r13, 4);
-                               else
-                                       s390_cg   (code, ins->sreg1, 0, s390_r13, 4);
-                       }
+                       S390_SET (code, s390_r0, ins->inst_imm);
+                       if (is_unsigned (ins->next))
+                               s390_clgr (code, ins->sreg1, s390_r0);
+                       else
+                               s390_cgr  (code, ins->sreg1, s390_r0);
                }
                        break;
                case OP_ICOMPARE_IMM: {
-                       if (s390_is_imm16 (ins->inst_imm)) {
-                               s390_lghi (code, s390_r0, ins->inst_imm);
-                               if (is_unsigned (ins->next))
-                                       s390_clr  (code, ins->sreg1, s390_r0);
-                               else
-                                       s390_cr   (code, ins->sreg1, s390_r0);
-                       }
-                       else {
-                               s390_basr (code, s390_r13, 0);
-                               s390_j    (code, 4);
-                               s390_word (code, ins->inst_imm);
-                               if (is_unsigned (ins->next))
-                                       s390_cl  (code, ins->sreg1, 0, s390_r13, 4);
-                               else
-                                       s390_c   (code, ins->sreg1, 0, s390_r13, 4);
-                       }
+                       S390_SET (code, s390_r0, ins->inst_imm);
+                       if (is_unsigned (ins->next))
+                               s390_clr  (code, ins->sreg1, s390_r0);
+                       else
+                               s390_cr   (code, ins->sreg1, s390_r0);
                }
                        break;
                case OP_BREAK: {
-                       s390_basr  (code, s390_r13, 0);
-                       s390_j     (code, 6);
                        mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_ABS, 
                                             mono_break);
-                       s390_llong (code, mono_break);
-                       s390_lg    (code, s390_r14, 0, s390_r13, 4);
-                        s390_basr  (code, s390_r14, s390_r14);
+                       S390_CALL_TEMPLATE (code, s390_r14);
                }
                        break;
                case OP_ADDCC: {
@@ -3314,11 +3136,11 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        }
                        if (s390_is_imm16 (ins->inst_imm)) {
                                s390_aghi (code, ins->dreg, ins->inst_imm);
+                       } else if (s390_is_imm32 (ins->inst_imm)) {
+                               s390_agfi (code, ins->dreg, ins->inst_imm);
                        } else {
-                               s390_basr (code, s390_r13, 0);
-                               s390_j    (code, 6);
-                               s390_llong(code, ins->inst_imm);
-                               s390_ag   (code, ins->dreg, 0, s390_r13, 4);
+                               S390_SET  (code, s390_r0, ins->inst_imm);
+                               s390_agr  (code, ins->dreg, s390_r0);
                        }
                }
                        break;
@@ -3338,11 +3160,8 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                                s390_lghi  (code, s390_r0, ins->inst_imm);
                                s390_alcgr (code, ins->dreg, s390_r0);
                        } else {
-                               s390_basr  (code, s390_r13, 0);
-                               s390_j     (code, 6);
-                               s390_llong (code, ins->inst_imm);
-                               s390_lg    (code, s390_r13, 0, s390_r13, 4);
-                               s390_alcgr (code, ins->dreg, s390_r13);
+                               S390_SET   (code, s390_r0, ins->inst_imm);
+                               s390_alcgr (code, ins->dreg, s390_r0);
                        }
                }
                        break;
@@ -3399,13 +3218,12 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                                s390_lgr   (code, ins->dreg, ins->sreg1);
                        }
                        if (s390_is_imm16 (-ins->inst_imm)) {
-                               s390_lghi  (code, s390_r0, ins->inst_imm);
-                               s390_slgr  (code, ins->dreg, s390_r0);
+                               s390_aghi  (code, ins->dreg, -ins->inst_imm);
+                       } else if (s390_is_imm32 (-ins->inst_imm)) {
+                               s390_slgfi  (code, ins->dreg, ins->inst_imm);
                        } else {
-                               s390_basr (code, s390_r13, 0);
-                               s390_j    (code, 6);
-                               s390_llong(code, ins->inst_imm);
-                               s390_slg  (code, ins->dreg, 0, s390_r13, 4);
+                               S390_SET  (code, s390_r0, ins->inst_imm);
+                               s390_slgr (code, ins->dreg, s390_r0);
                        }
                }
                        break;
@@ -3414,13 +3232,12 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                                s390_lgr   (code, ins->dreg, ins->sreg1);
                        }
                        if (s390_is_imm16 (-ins->inst_imm)) {
-                               s390_lghi  (code, s390_r0, ins->inst_imm);
-                               s390_slgr  (code, ins->dreg, s390_r0);
+                               s390_aghi  (code, ins->dreg, -ins->inst_imm);
+                       } else if (s390_is_imm32 (-ins->inst_imm)) {
+                               s390_slgfi (code, ins->dreg, ins->inst_imm);
                        } else {
-                               s390_basr (code, s390_r13, 0);
-                               s390_j    (code, 6);
-                               s390_llong(code, ins->inst_imm);
-                               s390_slg  (code, ins->dreg, 0, s390_r13, 4);
+                               S390_SET  (code, s390_r0, ins->inst_imm);
+                               s390_slgr (code, ins->dreg, s390_r0);
                        }
                }
                        break;
@@ -3432,10 +3249,8 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                                s390_lghi  (code, s390_r0, ins->inst_imm);
                                s390_slbgr (code, ins->dreg, s390_r0);
                        } else {
-                               s390_basr (code, s390_r13, 0);
-                               s390_j    (code, 6);
-                               s390_llong(code, ins->inst_imm);
-                               s390_slbg (code, ins->dreg, 0, s390_r13, 4);
+                               S390_SET  (code, s390_r0, ins->inst_imm);
+                               s390_slbgr(code, ins->dreg, s390_r0);
                        }
                }
                        break;
@@ -3475,15 +3290,8 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        if (ins->dreg != ins->sreg1) {
                                s390_lgr  (code, ins->dreg, ins->sreg1);
                        }
-                       if (s390_is_imm16 (ins->inst_imm)) {
-                               s390_lghi  (code, s390_r0, ins->inst_imm);
-                               s390_ngr  (code, ins->dreg, s390_r0);
-                       } else {
-                               s390_basr (code, s390_r13, 0);
-                               s390_j    (code, 6);
-                               s390_llong(code, ins->inst_imm);
-                               s390_ng   (code, ins->dreg, 0, s390_r13, 4);
-                       }
+                       S390_SET_MASK (code, s390_r0, ins->inst_imm);
+                       s390_ngr (code, ins->dreg, s390_r0);
                }
                        break;
                case OP_LDIV: {
@@ -3505,6 +3313,17 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        s390_lgr  (code, ins->dreg, s390_r0);
                        break;
                }
+               case OP_LREM_IMM: {
+                       if (s390_is_imm16 (ins->inst_imm)) {
+                               s390_lghi (code, s390_r13, ins->inst_imm);
+                       } else {
+                               s390_lgfi (code, s390_r13, ins->inst_imm);
+                       }
+                       s390_lgr  (code, s390_r0, ins->sreg1);
+                       s390_dsgr (code, s390_r0, s390_r13);
+                       s390_lgfr (code, ins->dreg, s390_r0);
+               }
+                       break;
                case OP_LREM_UN: {
                        s390_lgr   (code, s390_r1, ins->sreg1);
                        s390_lghi  (code, s390_r0, 0);
@@ -3531,15 +3350,8 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        if (ins->dreg != ins->sreg1) {
                                s390_lgr  (code, ins->dreg, ins->sreg1);
                        }
-                       if (s390_is_imm16 (ins->inst_imm)) {
-                               s390_lghi (code, s390_r0, ins->inst_imm);
-                               s390_ogr  (code, ins->dreg, s390_r0);
-                       } else {
-                               s390_basr (code, s390_r13, 0);
-                               s390_j    (code, 6);
-                               s390_llong(code, ins->inst_imm);
-                               s390_og   (code, ins->dreg, 0, s390_r13, 4);
-                       }
+                       S390_SET_MASK(code, s390_r0, ins->inst_imm);
+                       s390_ogr (code, ins->dreg, s390_r0);
                }
                        break;
                case OP_LXOR: {
@@ -3561,15 +3373,8 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        if (ins->dreg != ins->sreg1) {
                                s390_lgr  (code, ins->dreg, ins->sreg1);
                        }
-                       if (s390_is_imm16 (ins->inst_imm)) {
-                               s390_lghi  (code, s390_r0, ins->inst_imm);
-                               s390_xgr  (code, ins->dreg, s390_r0);
-                       } else {
-                               s390_basr (code, s390_r13, 0);
-                               s390_j    (code, 6);
-                               s390_llong(code, ins->inst_imm);
-                               s390_xg   (code, ins->dreg, 0, s390_r13, 4);
-                       }
+                       S390_SET_MASK (code, s390_r0, ins->inst_imm);
+                       s390_xgr (code, ins->dreg, s390_r0);
                }
                        break;
                case OP_LSHL: {
@@ -3635,11 +3440,10 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        }
                        if (s390_is_imm16 (ins->inst_imm)) {
                                s390_lghi (code, s390_r13, ins->inst_imm);
+                       } else if (s390_is_imm32 (ins->inst_imm)) {
+                               s390_lgfi (code, s390_r13, ins->inst_imm);
                        } else {
-                               s390_basr (code, s390_r13, 0);
-                               s390_j    (code, 6);
-                               s390_llong(code, ins->inst_imm);
-                               s390_lg   (code, s390_r13, 0, s390_r13, 4);
+                               S390_SET (code, s390_r13, ins->inst_imm);
                        }
                        s390_msgr (code, ins->dreg, s390_r13);
                }
@@ -3694,12 +3498,9 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                                s390_lgfr (code, ins->dreg, ins->sreg1);
                        }
                        if (s390_is_imm16 (ins->inst_imm)) {
-                               s390_aghi(code, ins->dreg, ins->inst_imm);
+                               s390_aghi (code, ins->dreg, ins->inst_imm);
                        } else {
-                               s390_basr (code, s390_r13, 0);
-                               s390_j    (code, 4);
-                               s390_word (code, ins->inst_imm);
-                               s390_agf  (code, ins->dreg, 0, s390_r13, 4);
+                               s390_afi  (code, ins->dreg, ins->inst_imm);
                        }
                }
                        break;
@@ -3711,11 +3512,8 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                                s390_lghi  (code, s390_r0, ins->inst_imm);
                                s390_alcgr (code, ins->dreg, s390_r0);
                        } else {
-                               s390_basr  (code, s390_r13, 0);
-                               s390_j     (code, 4);
-                               s390_word  (code, ins->inst_imm);
-                               s390_lgf   (code, s390_r13, 0, s390_r13, 4);
-                               s390_alcgr (code, ins->dreg, s390_r13);
+                               S390_SET   (code, s390_r0, ins->inst_imm);
+                               s390_alcgr (code, ins->dreg, s390_r0);
                        }
                }
                        break;
@@ -3755,18 +3553,13 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        if (s390_is_imm16 (-ins->inst_imm)) {
                                s390_aghi (code, ins->dreg, -ins->inst_imm);
                        } else {
-                               s390_basr (code, s390_r13, 0);
-                               s390_j    (code, 4);
-                               s390_word (code, ins->inst_imm);
-                               s390_sgf  (code, ins->dreg, 0, s390_r13, 4);
+                               s390_agfi (code, ins->dreg, -ins->inst_imm);
                        }
                }
                        break;
                case OP_ISBB_IMM: {
-                       s390_basr (code, s390_r13, 0);
-                       s390_j    (code, 4);
-                       s390_word (code, ins->inst_imm);
-                       s390_slgf (code, ins->dreg, 0, s390_r13, 4);
+                       S390_SET (code, s390_r0, ins->inst_imm);
+                       s390_slgfr (code, ins->dreg, s390_r0);
                }
                        break;
                case OP_ISUB_OVF:
@@ -3808,15 +3601,8 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        if (ins->dreg != ins->sreg1) {
                                s390_lgfr (code, ins->dreg, ins->sreg1);
                        }
-                       if (s390_is_imm16 (ins->inst_imm)) {
-                               s390_lghi (code, s390_r0, ins->inst_imm);
-                               s390_ngr  (code, ins->dreg, s390_r0);
-                       } else {
-                               s390_basr (code, s390_r13, 0);
-                               s390_j    (code, 6);
-                               s390_llong(code, ins->inst_imm);
-                               s390_ng   (code, ins->dreg, 0, s390_r13, 4);
-                       }
+                       S390_SET_MASK (code, s390_r0, ins->inst_imm);
+                       s390_ngr  (code, ins->dreg, s390_r0);
                }
                        break;
                case OP_IDIV: {
@@ -3836,14 +3622,10 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                case OP_IDIV_IMM: {
                        if (s390_is_imm16 (ins->inst_imm)) {
                                s390_lghi (code, s390_r13, ins->inst_imm);
-                               s390_lgfr (code, s390_r0, ins->sreg1);
                        } else {
-                               s390_basr (code, s390_r13, 0);
-                               s390_j    (code, 4);
-                               s390_word (code, ins->inst_imm);
-                               s390_lgfr (code, s390_r0, ins->sreg1);
-                               s390_lgf  (code, s390_r13, 0, s390_r13, 4);
+                               s390_lgfi (code, s390_r13, ins->inst_imm);
                        }
+                       s390_lgfr (code, s390_r0, ins->sreg1);
                        s390_srda (code, s390_r0, 0, 32);
                        s390_dr   (code, s390_r0, ins->sreg2);
                        s390_lgfr (code, ins->dreg, s390_r1);
@@ -3865,14 +3647,10 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                case OP_IREM_IMM: {
                        if (s390_is_imm16 (ins->inst_imm)) {
                                s390_lghi (code, s390_r13, ins->inst_imm);
-                               s390_lgfr (code, s390_r0, ins->sreg1);
                        } else {
-                               s390_basr (code, s390_r13, 0);
-                               s390_j    (code, 4);
-                               s390_word (code, ins->inst_imm);
-                               s390_lgfr (code, s390_r0, ins->sreg1);
-                               s390_lgf  (code, s390_r13, 0, s390_r13, 4);
+                               s390_lgfi (code, s390_r13, ins->inst_imm);
                        }
+                       s390_lgfr (code, s390_r0, ins->sreg1);
                        s390_srda (code, s390_r0, 0, 32);
                        s390_dr   (code, s390_r0, ins->sreg2);
                        s390_lgfr (code, ins->dreg, s390_r0);
@@ -3887,15 +3665,8 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        if (ins->dreg != ins->sreg1) {
                                s390_lgfr (code, ins->dreg, ins->sreg1);
                        }
-                       if (s390_is_imm16 (ins->inst_imm)) {
-                               s390_lghi (code, s390_r0, ins->inst_imm);
-                               s390_ogr  (code, ins->dreg, s390_r0);
-                       } else {
-                               s390_basr (code, s390_r13, 0);
-                               s390_j    (code, 6);
-                               s390_llong(code, ins->inst_imm);
-                               s390_og   (code, ins->dreg, 0, s390_r13, 4);
-                       }
+                       S390_SET_MASK (code, s390_r0, ins->inst_imm);
+                       s390_ogr  (code, ins->dreg, s390_r0);
                }
                        break;
                case OP_IXOR: {
@@ -3907,15 +3678,8 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        if (ins->dreg != ins->sreg1) {
                                s390_lgfr (code, ins->dreg, ins->sreg1);
                        }
-                       if (s390_is_imm16 (ins->inst_imm)) {
-                               s390_lghi (code, s390_r0, ins->inst_imm);
-                               s390_xgr  (code, ins->dreg, s390_r0);
-                       } else {
-                               s390_basr (code, s390_r13, 0);
-                               s390_j    (code, 6);
-                               s390_llong(code, ins->inst_imm);
-                               s390_xg   (code, ins->dreg, 0, s390_r13, 4);
-                       }
+                       S390_SET_MASK (code, s390_r0, ins->inst_imm);
+                       s390_xgr  (code, ins->dreg, s390_r0);
                }
                        break;
                case OP_ISHL: {
@@ -3976,14 +3740,11 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                                s390_lgfr (code, ins->dreg, ins->sreg1);
                        }
                        if (s390_is_imm16 (ins->inst_imm)) {
-                               s390_lghi (code, s390_r13, ins->inst_imm);
+                               s390_lghi (code, s390_r0, ins->inst_imm);
                        } else {
-                               s390_basr (code, s390_r13, 0);
-                               s390_j    (code, 4);
-                               s390_word (code, ins->inst_imm);
-                               s390_lgf  (code, s390_r13, 0, s390_r13, 4);
+                               s390_lgfi (code, s390_r0, ins->inst_imm);
                        }
-                       s390_msr  (code, ins->dreg, s390_r13);
+                       s390_msr  (code, ins->dreg, s390_r0);
                }
                        break;
                case OP_IMUL_OVF: {
@@ -4016,32 +3777,19 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        break;
                case OP_ICONST: 
                case OP_I8CONST: {
-                       if (s390_is_imm16(ins->inst_c0)) {
-                               s390_lghi (code, ins->dreg, ins->inst_c0);
-                       } else {
-                               s390_basr (code, s390_r13, 0);
-                               s390_j    (code, 6);
-                               s390_llong(code, ins->inst_c0);
-                               s390_lg   (code, ins->dreg, 0, s390_r13, 4);
-                       }
+                       S390_SET (code, ins->dreg, ins->inst_c0);
                }
                        break;
                case OP_AOTCONST: {
-                       s390_basr (code, s390_r13, 0);
-                       s390_j    (code, 6);
                        mono_add_patch_info (cfg, code - cfg->native_code, 
                                (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
-                       s390_llong(code, 0);
-                       s390_lg   (code,ins->dreg, 0, s390_r13, 4);
+                       S390_LOAD_TEMPLATE (code, ins->dreg);
                }
                        break;
                case OP_JUMP_TABLE: {
                        mono_add_patch_info (cfg, code - cfg->native_code, 
                                (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
-                       s390_basr  (code, s390_r13, 0);
-                       s390_j     (code, 6);
-                       s390_llong (code, 0);
-                       s390_lg    (code, ins->dreg, 0, s390_r13, 4);
+                       S390_LOAD_TEMPLATE (code, ins->dreg);
                }
                        break;
                case OP_MOVE:
@@ -4064,32 +3812,32 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        s390_llgfr (code, ins->dreg, ins->sreg1);
                        break;
                case OP_LCONV_TO_OVF_U4:
-                       s390_basr (code, s390_r13, 0);
-                       s390_j    (code, 6);
-                       s390_llong(code, 4294967295);
-                       s390_clg  (code, ins->sreg1, 0, s390_r13, 4);   
+                       S390_SET  (code, s390_r0, 4294967295);
+                       s390_clgr (code, ins->sreg1, s390_r0);
                        EMIT_COND_SYSTEM_EXCEPTION (S390_CC_GT, "OverflowException");
                        s390_ltgr (code, ins->sreg1, ins->sreg1);
                        EMIT_COND_SYSTEM_EXCEPTION (S390_CC_LT, "OverflowException");
                        s390_llgfr(code, ins->dreg, ins->sreg1);
                        break;
                case OP_LCONV_TO_OVF_I4_UN:
-                       s390_basr (code, s390_r13, 0);
-                       s390_j    (code, 6);
-                       s390_llong(code, 2147483647);
-                       s390_cg   (code, ins->sreg1, 0, s390_r13, 4);
+                       S390_SET  (code, s390_r0, 2147483647);
+                       s390_cgr  (code, ins->sreg1, s390_r0);
                        EMIT_COND_SYSTEM_EXCEPTION (S390_CC_GT, "OverflowException");
                        s390_ltgr (code, ins->sreg1, ins->sreg1);
                        EMIT_COND_SYSTEM_EXCEPTION (S390_CC_LT, "OverflowException");
                        s390_lgfr (code, ins->dreg, ins->sreg1);
                        break;
-               case OP_FMOVE:
-               case OP_FCONV_TO_R4: {
+               case OP_FMOVE: {
                        if (ins->dreg != ins->sreg1) {
                                s390_ldr   (code, ins->dreg, ins->sreg1);
                        }
                }
                        break;
+               case OP_FCONV_TO_R4: {
+                       s390_ledbr (code, ins->dreg, ins->sreg1);
+                       s390_ldebr (code, ins->dreg, ins->dreg);
+               }
+                       break;
                case OP_S390_SETF4RET: {
                        s390_ledbr (code, ins->dreg, ins->sreg1);
                }
@@ -4097,11 +3845,10 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                case OP_TLS_GET: {
                        if (s390_is_imm16 (ins->inst_offset)) {
                                s390_lghi (code, s390_r13, ins->inst_offset);
+                       } else if (s390_is_imm32 (ins->inst_offset)) {
+                               s390_lgfi (code, s390_r13, ins->inst_offset);
                        } else {
-                               s390_bras (code, s390_r13, 0);
-                               s390_j    (code, 4);
-                               s390_llong(code, ins->inst_offset);
-                               s390_lg   (code, s390_r13, 0, s390_r13, 4);
+                               S390_SET  (code, s390_r13, ins->inst_offset);
                        }
                        s390_ear (code, s390_r1, 0);
                        s390_sllg(code, s390_r1, s390_r1, 0, 32);
@@ -4129,27 +3876,24 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        /* ensure ins->sreg1 is not NULL */
                        s390_lg   (code, s390_r0, 0, ins->sreg1, 0);
                        s390_ltgr (code, s390_r0, s390_r0);
-                       EMIT_COND_SYSTEM_EXCEPTION (S390_CC_ZR, "NullReferenceException");
+//                     EMIT_COND_SYSTEM_EXCEPTION (S390_CC_ZR, "NullReferenceException");
                }
                        break;
                case OP_ARGLIST: {
                        int offset = cfg->sig_cookie + cfg->stack_usage;
 
-                       if (s390_is_imm16 (offset))
+                       if (s390_is_imm16 (offset)) {
                                s390_lghi (code, s390_r0, offset);
-                       else {
-                               s390_basr (code, s390_r13, 0);
-                               s390_j    (code, 6);
-                               s390_llong(code, offset);
-                               s390_lg   (code, s390_r0, 0, s390_r13, 0);
+                       } else if (s390_is_imm32 (offset)) {
+                               s390_lgfi (code, s390_r0, offset);
+                       } else {
+                               S390_SET  (code, s390_r0, offset);
                        }
                        s390_agr  (code, s390_r0, cfg->frame_reg);
                        s390_stg  (code, s390_r0, 0, ins->sreg1, 0);
                }
                        break;
                case OP_FCALL: {
-                       s390_basr (code, s390_r13, 0);
-                       s390_j    (code, 6);
                        call = (MonoCallInst*)ins;
                        if (ins->flags & MONO_INST_HAS_METHOD)
                                mono_add_patch_info (cfg, code-cfg->native_code,
@@ -4159,9 +3903,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                                mono_add_patch_info (cfg, code-cfg->native_code,
                                                     MONO_PATCH_INFO_ABS, 
                                                     call->fptr);
-                       s390_llong(code, 0);
-                       s390_lg   (code, s390_r14, 0, s390_r13, 4);
-                       s390_basr (code, s390_r14, s390_r14);
+                       S390_CALL_TEMPLATE (code, s390_r14);
                        if (call->signature->ret->type == MONO_TYPE_R4)
                                s390_ldebr (code, s390_f0, s390_f0);
                }
@@ -4171,8 +3913,6 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                case OP_VCALL2:
                case OP_VOIDCALL:
                case OP_CALL: {
-                       s390_basr (code, s390_r13, 0);
-                       s390_j    (code, 6);
                        call = (MonoCallInst*)ins;
                        if (ins->flags & MONO_INST_HAS_METHOD)
                                mono_add_patch_info (cfg, code-cfg->native_code,
@@ -4182,9 +3922,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                                mono_add_patch_info (cfg, code-cfg->native_code,
                                                     MONO_PATCH_INFO_ABS, 
                                                     call->fptr);
-                       s390_llong(code, 0);
-                       s390_lg   (code, s390_r14, 0, s390_r13, 4);
-                       s390_basr (code, s390_r14, s390_r14);
+                       S390_CALL_TEMPLATE (code, s390_r14);
                }
                        break;
                case OP_FCALL_REG: {
@@ -4244,13 +3982,12 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                                int lmfOffset = cfg->stack_usage - sizeof(MonoLMF);
 
                                s390_lgr (code, s390_r13, cfg->frame_reg);
-                               if (s390_is_imm16(lmfOffset))
+                               if (s390_is_imm16(lmfOffset)) {
                                        s390_aghi (code, s390_r13, lmfOffset);
-                               else {
-                                       s390_basr (code, s390_r14, 0);
-                                       s390_j    (code, 4);
-                                       s390_word (code, lmfOffset);
-                                       s390_agf  (code, s390_r13, 0, s390_r14, 4);
+                               } else if (s390_is_imm32(lmfOffset)) {
+                                       s390_agfi (code, s390_r13, lmfOffset);
+                               } else {
+                                       S390_SET  (code, s390_r13, lmfOffset);
                                }
                                s390_lgr (code, s390_r14, STK_BASE);
                                s390_sgr (code, s390_r14, s390_r1);
@@ -4276,24 +4013,16 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        break;
                case OP_THROW: {
                        s390_lgr  (code, s390_r2, ins->sreg1);
-                       s390_basr (code, s390_r13, 0);
-                       s390_j    (code, 6);
                        mono_add_patch_info (cfg, code-cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, 
                                             (gpointer) "mono_arch_throw_exception");
-                       s390_llong(code, 0);
-                       s390_lg   (code, s390_r14, 0, s390_r13, 4);
-                       s390_basr (code, s390_r14, s390_r14);
+                       S390_CALL_TEMPLATE(code, s390_r14);
                }
                        break;
                case OP_RETHROW: {
                        s390_lgr  (code, s390_r2, ins->sreg1);
-                       s390_basr (code, s390_r13, 0);
-                       s390_j    (code, 6);
                        mono_add_patch_info (cfg, code-cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, 
                                             (gpointer) "mono_arch_rethrow_exception");
-                       s390_llong(code, 0);
-                       s390_lg   (code, s390_r14, 0, s390_r13, 4);
-                       s390_basr (code, s390_r14, s390_r14);
+                       S390_CALL_TEMPLATE(code, s390_r14);
                }
                        break;
                case OP_START_HANDLER: {
@@ -4343,6 +4072,9 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                case OP_NOT_NULL: {
                }
                        break;
+               case OP_IL_SEQ_POINT:
+                       mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
+                       break;
                case OP_SEQ_POINT: {
                        int i;
 
@@ -4369,6 +4101,13 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                         */
                        for (i = 0; i < (BREAKPOINT_SIZE / S390X_NOP_SIZE); ++i)
                                s390_nop (code);
+
+                       /*
+                        * Add an additional nop so skipping the bp doesn't cause the ip to point
+                        * to another IL offset.
+                        */
+                       s390_nop (code);
+
                        break;
                }
        
@@ -4505,11 +4244,8 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        if (*((double *) ins->inst_p0) == 0) {
                                s390_lzdr (code, ins->dreg);
                        } else {
-                               s390_basr  (code, s390_r13, 0);
-                               s390_j     (code, 6);
-                               s390_llong (code, ins->inst_p0);
-                               s390_lg    (code, s390_r13, 0, s390_r13, 4);
-                               s390_ld    (code, ins->dreg, 0, s390_r13, 0);
+                               S390_SET  (code, s390_r13, ins->inst_p0);
+                               s390_ld   (code, ins->dreg, 0, s390_r13, 0);
                        }
                }
                        break;
@@ -4517,10 +4253,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        if (*((float *) ins->inst_p0) == 0) {
                                s390_lzdr (code, ins->dreg);
                        } else {
-                               s390_basr (code, s390_r13, 0);
-                               s390_j    (code, 6);
-                               s390_llong(code, ins->inst_p0);
-                               s390_lg   (code, s390_r13, 0, s390_r13, 4);
+                               S390_SET  (code, s390_r13, ins->inst_p0);
                                s390_ldeb (code, ins->dreg, 0, s390_r13, 0);
                        }
                }
@@ -4550,28 +4283,25 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                case OP_ICONV_TO_R_UN: {
                        s390_cdfbr (code, ins->dreg, ins->sreg1);
                        s390_ltr   (code, ins->sreg1, ins->sreg1);
-                       s390_jnl   (code, 12);
-                       s390_basr  (code, s390_r13, 0);
-                       s390_j     (code, 6);
-                       s390_word  (code, 0x41f00000);
-                       s390_word  (code, 0);
-                       s390_adb   (code, ins->dreg, 0, s390_r13, 4);
+                       s390_jnl   (code, 8);
+                       S390_SET   (code, s390_r13, 0x41f0000000000000llu);
+                       s390_ldgr  (code, s390_f15, s390_r13);
+                       s390_adbr  (code, ins->dreg, s390_f15);
                }
                        break;
                case OP_LCONV_TO_R_UN: {
                        s390_cdgbr (code, ins->dreg, ins->sreg1);
                        s390_ltgr  (code, ins->sreg1, ins->sreg1);
-                       s390_jnl   (code, 12);
-                       s390_basr  (code, s390_r13, 0);
-                       s390_j     (code, 6);
-                       s390_word  (code, 0x41f00000);
-                       s390_word  (code, 0);
-                       s390_adb   (code, ins->dreg, 0, s390_r13, 4);
+                       s390_jnl   (code, 8);
+                       S390_SET   (code, s390_r13, 0x41f0000000000000llu);
+                       s390_ldgr  (code, s390_f15, s390_r13);
+                       s390_adbr  (code, ins->dreg, s390_f15);
                }
                        break;
                case OP_LCONV_TO_R4:
                case OP_ICONV_TO_R4: {
-                       s390_cdgbr (code, ins->dreg, ins->sreg1);
+                       s390_cegbr (code, ins->dreg, ins->sreg1);
+                       s390_ldebr (code, ins->dreg, ins->dreg);
                }
                        break;
                case OP_LCONV_TO_R8:
@@ -4773,31 +4503,31 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                                        if (ins->inst_offset > 0) {
                                                if (s390_is_imm16 (ins->inst_offset)) {
                                                        s390_aghi (code, s390_r0, ins->inst_offset);
+                                               } else if (s390_is_imm32 (ins->inst_offset)) {
+                                                       s390_agfi (code, s390_r0, ins->inst_offset);
                                                } else {
-                                                       s390_basr (code, s390_r13, 0);
-                                                       s390_j    (code, 6);
-                                                       s390_llong(code, ins->inst_offset);
-                                                       s390_ag   (code, s390_r0, 0, s390_r13, 4);
+                                                       S390_SET  (code, s390_r13, ins->inst_offset);
+                                                       s390_agr  (code, s390_r0, s390_r13);
                                                }
                                        }
                                        s390_lgr  (code, s390_r12, ins->sreg1);
                                        if (ins->inst_imm > 0) {
                                                if (s390_is_imm16 (ins->inst_imm)) {
                                                        s390_aghi (code, s390_r12, ins->inst_imm);
+                                               } else if (s390_is_imm32 (ins->inst_imm)) {
+                                                       s390_agfi (code, s390_r12, ins->inst_imm);
                                                } else {
-                                                       s390_basr (code, s390_r13, 0);
-                                                       s390_j    (code, 6);
-                                                       s390_llong(code, ins->inst_imm);
-                                                       s390_ag   (code, s390_r12, 0, s390_r13, 4);
+                                                       S390_SET  (code, s390_r13, ins->inst_imm);
+                                                       s390_agr  (code, s390_r12, s390_r13);
                                                }
                                        }
                                        if (s390_is_imm16 (ins->backend.size)) {
                                                s390_lghi (code, s390_r1, ins->backend.size);
+                                       } else if (s390_is_imm32 (ins->inst_offset)) {
+                                               s390_agfi (code, s390_r1, ins->backend.size);
                                        } else {
-                                               s390_basr (code, s390_r13, 0);
-                                               s390_j    (code, 6);
-                                               s390_llong(code, ins->backend.size);
-                                               s390_lg   (code, s390_r1, 0, s390_r13, 4);
+                                               S390_SET  (code, s390_r13, ins->backend.size);
+                                               s390_agr  (code, s390_r1, s390_r13);
                                        }
                                        s390_lgr  (code, s390_r13, s390_r1);
                                        s390_mvcle(code, s390_r0, s390_r12, 0, 0);
@@ -4815,15 +4545,6 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        s390_lgr (code, ins->dreg, s390_r1);
                }
                        break;  
-               case OP_ATOMIC_ADD_NEW_I8: {
-                       s390_lgr (code, s390_r1, ins->sreg2);
-                       s390_lg  (code, s390_r0, 0, ins->inst_basereg, ins->inst_offset);
-                       s390_agr (code, s390_r1, s390_r0);
-                       s390_csg (code, s390_r0, s390_r1, ins->inst_basereg, ins->inst_offset);
-                       s390_jnz (code, -10);
-                       s390_lgr (code, ins->dreg, s390_r1);
-               }
-                       break;  
                case OP_ATOMIC_EXCHANGE_I8: {
                        s390_lg  (code, s390_r0, 0, ins->inst_basereg, ins->inst_offset);
                        s390_csg (code, s390_r0, ins->sreg2, ins->inst_basereg, ins->inst_offset);
@@ -4840,15 +4561,6 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        s390_lgfr(code, ins->dreg, s390_r1);
                }
                        break;  
-               case OP_ATOMIC_ADD_NEW_I4: {
-                       s390_lgfr(code, s390_r1, ins->sreg2);
-                       s390_lgf (code, s390_r0, 0, ins->inst_basereg, ins->inst_offset);
-                       s390_agr (code, s390_r1, s390_r0);
-                       s390_cs  (code, s390_r0, s390_r1, ins->inst_basereg, ins->inst_offset);
-                       s390_jnz (code, -9);
-                       s390_lgfr(code, ins->dreg, s390_r1);
-               }
-                       break;  
                case OP_ATOMIC_EXCHANGE_I4: {
                        s390_l   (code, s390_r0, 0, ins->inst_basereg, ins->inst_offset);
                        s390_cs  (code, s390_r0, ins->sreg2, ins->inst_basereg, ins->inst_offset);
@@ -4860,11 +4572,11 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        s390_lgr  (code, ins->dreg, ins->sreg1);
                        if (s390_is_imm16 (cfg->stack_offset)) {
                                s390_aghi (code, ins->dreg, cfg->stack_offset);
+                       } else if (s390_is_imm32 (cfg->stack_offset)) {
+                               s390_agfi (code, ins->dreg, cfg->stack_offset);
                        } else {
-                               s390_basr (code, s390_r13, 0);
-                               s390_j    (code, 6);
-                               s390_llong(code, cfg->stack_offset);
-                               s390_ag   (code, ins->dreg, 0, s390_r13, 4);
+                               S390_SET  (code, s390_r13, cfg->stack_offset);
+                               s390_agr  (code, ins->dreg, s390_r13);
                        }
                }
                        break;  
@@ -4941,33 +4653,36 @@ mono_arch_patch_code (MonoMethod *method, MonoDomain *domain,
 
                switch (patch_info->type) {
                        case MONO_PATCH_INFO_IP:
-                       case MONO_PATCH_INFO_EXC_NAME:
                        case MONO_PATCH_INFO_LDSTR:
                        case MONO_PATCH_INFO_TYPE_FROM_HANDLE: 
                        case MONO_PATCH_INFO_LDTOKEN: 
                        case MONO_PATCH_INFO_EXC:
-                       case MONO_PATCH_INFO_ABS:
+                               s390_patch_addr (ip, (guint64) target);
+                               continue;
                        case MONO_PATCH_INFO_METHOD:
-                       case MONO_PATCH_INFO_RGCTX_FETCH:
                        case MONO_PATCH_INFO_INTERNAL_METHOD:
-                       case MONO_PATCH_INFO_CLASS_INIT:
                        case MONO_PATCH_INFO_JIT_ICALL_ADDR:
+                       case MONO_PATCH_INFO_CLASS_INIT:
                        case MONO_PATCH_INFO_GENERIC_CLASS_INIT:
-                               s390_patch_addr (ip, (guint64) target);
+                       case MONO_PATCH_INFO_RGCTX_FETCH:
+                       case MONO_PATCH_INFO_ABS: {
+                               S390_EMIT_CALL (ip, target);
                                continue;
+                       }
                        case MONO_PATCH_INFO_SWITCH: 
                                /*----------------------------------*/
                                /* ip points at the basr r13,0/j +4 */
                                /* instruction the vtable value     */
                                /* follows this (i.e. ip+6)         */
                                /*----------------------------------*/
-                               *((gconstpointer *)(ip+6)) = target;
+                               S390_EMIT_LOAD (ip, target);
                                continue;
                        case MONO_PATCH_INFO_METHODCONST:
                        case MONO_PATCH_INFO_CLASS:
                        case MONO_PATCH_INFO_IMAGE:
                        case MONO_PATCH_INFO_FIELD:
                        case MONO_PATCH_INFO_IID:
+                       case MONO_PATCH_INFO_EXC_NAME:
                                target = S390_RELATIVE(target, ip);
                                s390_patch_rel (ip, (guint64) target);
                                continue;
@@ -5149,13 +4864,15 @@ mono_arch_emit_prolog (MonoCompile *cfg)
        s390_lgr  (code, s390_r11, STK_BASE);
        if (s390_is_imm16 (alloc_size)) {
                s390_aghi (code, STK_BASE, -alloc_size);
-       } else { 
+       } else if (s390_is_imm32 (alloc_size)) { 
+               s390_agfi (code, STK_BASE, -alloc_size);
+       } else {
                int stackSize = alloc_size;
-               while (stackSize > 32767) {
-                       s390_aghi (code, STK_BASE, -32767);
-                       stackSize -= 32767;
+               while (stackSize > INT_MAX) {
+                       s390_agfi (code, STK_BASE, -INT_MAX);
+                       stackSize -= INT_MAX;
                }
-               s390_aghi (code, STK_BASE, -stackSize);
+               s390_agfi (code, STK_BASE, -stackSize);
        }
        s390_stg  (code, s390_r11, 0, STK_BASE, 0);
 
@@ -5322,14 +5039,10 @@ mono_arch_emit_prolog (MonoCompile *cfg)
                /* On return from this call r2 have the address of the &lmf      */
                /*---------------------------------------------------------------*/
                if (lmf_addr_tls_offset == -1) {
-                       s390_basr(code, s390_r14, 0);
-                       s390_j   (code, 6);
                        mono_add_patch_info (cfg, code - cfg->native_code, 
                                             MONO_PATCH_INFO_INTERNAL_METHOD, 
                                             (gpointer)"mono_get_lmf_addr");
-                       s390_llong(code, 0);
-                       s390_lg   (code, s390_r1, 0, s390_r14, 4);
-                       s390_basr (code, s390_r14, s390_r1);
+                       S390_CALL_TEMPLATE(code, s390_r1);
                } else {
                        /*-------------------------------------------------------*/
                        /* Get LMF by getting value from thread level storage    */
@@ -5365,10 +5078,7 @@ mono_arch_emit_prolog (MonoCompile *cfg)
                /*---------------------------------------------------------------*/     
                /* save method info                                              */     
                /*---------------------------------------------------------------*/     
-               s390_basr  (code, s390_r1, 0);                                          
-               s390_j     (code, 6);
-               s390_llong (code, method);                                              
-               s390_lg    (code, s390_r1, 0, s390_r1, 4);                      
+               S390_SET   (code, s390_r1, method);
                s390_stg   (code, s390_r1, 0, s390_r13,                                 
                            G_STRUCT_OFFSET(MonoLMF, method));                          
                                                                                
@@ -5539,27 +5249,19 @@ mono_arch_emit_exceptions (MonoCompile *cfg)
                                /*---------------------------------------------*/
                                /* Patch the parameter passed to the handler   */ 
                                /*---------------------------------------------*/
-                               s390_basr (code, s390_r13, 0);
-                               s390_j    (code, 6);
-//                             s390_llong(code, patch_info->data.target);
-                               s390_llong(code, exc_class->type_token);
+                               S390_SET  (code, s390_r2, exc_class->type_token);
                                /*---------------------------------------------*/
                                /* Load return address & parameter register    */
                                /*---------------------------------------------*/
                                s390_larl (code, s390_r14, (guint64)S390_RELATIVE((patch_info->ip.i +
                                                           cfg->native_code + 8), code));
-                               s390_lg   (code, s390_r2, 0, s390_r13, 4);
                                /*---------------------------------------------*/
                                /* Reuse the current patch to set the jump     */
                                /*---------------------------------------------*/
-                               s390_basr (code, s390_r13, 0);
-                               s390_j    (code, 6);
                                patch_info->type      = MONO_PATCH_INFO_INTERNAL_METHOD;
                                patch_info->data.name = "mono_arch_throw_corlib_exception";
                                patch_info->ip.i      = code - cfg->native_code;
-                               s390_llong(code, 0);
-                               s390_lg   (code, s390_r1, 0, s390_r13, 4);
-                               s390_br   (code, s390_r1);
+                               S390_BR_TEMPLATE (code, s390_r1);
                        }
                        break;
                }
@@ -5612,7 +5314,7 @@ mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
 
 /*------------------------------------------------------------------*/
 /*                                                                  */
-/* Name                - mono_arch_emit_inst_for_method                        */
+/* Name                - mono_arch_emit_inst_for_method                    */
 /*                                                                  */
 /*------------------------------------------------------------------*/
 
@@ -5754,31 +5456,6 @@ mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
 
 /*========================= End of Function ========================*/
 
-/*------------------------------------------------------------------*/
-/*                                                                  */
-/* Name                - mono_arch_get_domain_intrinsic                    */
-/*                                                                  */
-/* Function    -                                                   */
-/*                                                                 */
-/* Returns     -                                                   */
-/*                                                                  */
-/*------------------------------------------------------------------*/
-
-MonoInst * 
-mono_arch_get_domain_intrinsic (MonoCompile* cfg)
-{
-       MonoInst *ins;
-
-       if (appdomain_tls_offset == -1)
-               return NULL;
-       
-       MONO_INST_NEW (cfg, ins, OP_TLS_GET);
-       ins->inst_offset = appdomain_tls_offset;
-       return (ins);
-}
-
-/*========================= End of Function ========================*/
-
 /*------------------------------------------------------------------*/
 /*                                                                  */
 /* Name                - mono_arch_flush_register_windows                  */
@@ -5810,7 +5487,7 @@ mono_arch_flush_register_windows (void)
 gboolean 
 mono_arch_is_inst_imm (gint64 imm)
 {
-       return s390_is_imm16 (imm);
+       return s390_is_imm32 (imm);
 }
 
 /*========================= End of Function ========================*/
@@ -5884,7 +5561,40 @@ mono_arch_get_this_arg_from_call (mgreg_t *regs, guint8 *code)
 }
 
 /*========================= End of Function ========================*/
+/*------------------------------------------------------------------*/
+/*                                                                  */
+/* Name                - mono_arch_install_handler_block_guard             */
+/*                                                                  */
+/* Function    -                                                   */
+/*                                                                 */
+/*------------------------------------------------------------------*/
+
+gpointer
+mono_arch_install_handler_block_guard (MonoJitInfo *ji, MonoJitExceptionInfo *clause, 
+                                      MonoContext *ctx, gpointer new_value)
+{
+       int offset;
+       gpointer *sp, old_value;
+       char *bp;
+
+       offset = clause->exvar_offset;
+
+       /*Load the spvar*/
+       bp = MONO_CONTEXT_GET_BP (ctx);
+       sp = *(gpointer*)(bp + offset);
+
+       old_value = *sp;
+       if (old_value < ji->code_start || (char*)old_value > ((char*)ji->code_start + ji->code_size))
+               return old_value;
+
+       *sp = new_value;
 
+       return old_value;
+}
+
+/*========================= End of Function ========================*/
 /*------------------------------------------------------------------*/
 /*                                                                  */
 /* Name                - get_delegate_invoke_impl.                         */
@@ -5904,8 +5614,8 @@ get_delegate_invoke_impl (gboolean has_target, guint32 param_count, guint32 *cod
                start = code = mono_global_codeman_reserve (size);
 
                /* Replace the this argument with the target */
-               s390_lg   (code, s390_r1, 0, s390_r2, G_STRUCT_OFFSET(MonoDelegate, method_ptr));
-               s390_lg   (code, s390_r2, 0, s390_r2, G_STRUCT_OFFSET(MonoDelegate, target));
+               s390_lg   (code, s390_r1, 0, s390_r2, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr));
+               s390_lg   (code, s390_r2, 0, s390_r2, MONO_STRUCT_OFFSET (MonoDelegate, target));
                s390_br   (code, s390_r1);
                g_assert ((code - start) <= size);
 
@@ -5916,7 +5626,7 @@ get_delegate_invoke_impl (gboolean has_target, guint32 param_count, guint32 *cod
                size = 32 + param_count * 8;
                start = code = mono_global_codeman_reserve (size);
 
-               s390_lg   (code, s390_r1, 0, s390_r2, G_STRUCT_OFFSET(MonoDelegate, method_ptr));
+               s390_lg   (code, s390_r1, 0, s390_r2, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr));
                /* slide down the arguments */
                for (i = 0; i < param_count; ++i) {
                        s390_lgr (code, (s390_r2 + i), (s390_r2 + i + 1));
@@ -6031,6 +5741,48 @@ mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_targe
 
 /*========================= End of Function ========================*/
 
+/*------------------------------------------------------------------*/
+/*                                                                  */
+/* Name                - mono_arch_get_delegate_virtual_invoke_impl.       */
+/*                                                                  */
+/* Function    -                                                   */
+/*                                                                 */
+/*------------------------------------------------------------------*/
+
+gpointer
+mono_arch_get_delegate_virtual_invoke_impl (MonoMethodSignature *sig, MonoMethod *method, 
+                                           int offset, gboolean load_imt_reg)
+{
+       guint8 *code, *start;
+       int size = 20;
+
+       start = code = mono_global_codeman_reserve (size);
+
+       /*
+        * Replace the "this" argument with the target
+        */
+       s390_lgr  (code, s390_r1, s390_r2);
+       s390_lg   (code, s390_r2, s390_r1, 0, MONO_STRUCT_OFFSET(MonoDelegate, target));        
+       
+       /*
+        * Load the IMT register, if needed
+        */
+       if (load_imt_reg) {
+               s390_lg  (code, MONO_ARCH_IMT_REG, s390_r2, 0, MONO_STRUCT_OFFSET(MonoDelegate, method));
+       }
+
+       /*
+        * Load the vTable
+        */
+       s390_lg  (code, s390_r1, s390_r2, 0, MONO_STRUCT_OFFSET(MonoObject, vtable));
+       s390_agfi(code, s390_r1, offset);
+       s390_br  (code, s390_r1);
+
+       return(start);
+}
+
+/*========================= End of Function ========================*/
+
 /*------------------------------------------------------------------*/
 /*                                                                  */
 /* Name                - mono_arch_build_imt_thunk.                        */
@@ -6092,55 +5844,39 @@ mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain,
                if (item->is_equals) {
                        if (item->check_target_idx) {
                                if (!item->compare_done) {
-                                       s390_basr (code, s390_r13, s390_r0);
-                                       s390_j    (code, 6);
-                                       s390_llong(code, item->key);
-                                       s390_lg   (code, s390_r0, 0, s390_r13, 4);
+                                       S390_SET  (code, s390_r0, item->key);
                                        s390_cgr  (code, s390_r0, MONO_ARCH_IMT_REG);
                                }
                                item->jmp_code = (guint8*) code;
                                s390_jcl (code, S390_CC_NE, 0);
                                
-                               s390_basr (code, s390_r13, s390_r0);
-                               s390_j    (code, 6);
-                               if (item->has_target_code)  {
-                                       s390_llong(code, item->value.target_code);
-                                       s390_lg   (code, s390_r1, 0, s390_r13, 4);
-                               } else {        
-                                       s390_llong(code, (&(vtable->vtable [item->value.vtable_slot])));
-                                       s390_lg   (code, s390_r1, 0, s390_r13, 4);
-                                       s390_lg   (code, s390_r1, 0, s390_r1, 0);
+                               if (item->has_target_code) {
+                                       S390_SET (code, s390_r1, item->value.target_code);
+                               } else {
+                                       S390_SET (code, s390_r1, (&(vtable->vtable [item->value.vtable_slot])));
+                                       s390_lg  (code, s390_r1, 0, s390_r1, 0);
                                }
                                s390_br   (code, s390_r1);
                        } else {
                                if (fail_tramp) {
                                        gint64  target;
 
-                                       s390_basr (code, s390_r13, s390_r0);
-                                       s390_j    (code, 6);
-                                       s390_llong(code, item->key);
-                                       s390_lg   (code, s390_r0, 0, s390_r13, 4);
+                                       S390_SET  (code, s390_r0, item->key);
                                        s390_cgr  (code, s390_r0, MONO_ARCH_IMT_REG);
                                        item->jmp_code = (guint8*) code;
                                        s390_jcl  (code, S390_CC_NE, 0);
-                                       s390_basr (code, s390_r13, s390_r0);
-                                       s390_j    (code, 6);
                                        if (item->has_target_code) {
-                                               s390_llong(code, item->value.target_code);
-                                               s390_lg   (code, s390_r1, 0, s390_r13, 4);
+                                               S390_SET (code, s390_r1, item->value.target_code);
                                        } else {
                                                g_assert (vtable);
-                                               s390_llong(code, (&(vtable->vtable [item->value.vtable_slot])));
-                                               s390_lg   (code, s390_r1, 0, s390_r13, 4);
+                                               S390_SET  (code, s390_r1, 
+                                                          (&(vtable->vtable [item->value.vtable_slot])));
                                                s390_lg   (code, s390_r1, 0, s390_r1, 0);
                                        }
                                        s390_br   (code, s390_r1);
-                                       target = S390_RELATIVE(code, item->jmp_code);
+                                       target = (gint64) S390_RELATIVE(code, item->jmp_code);
                                        s390_patch_rel(item->jmp_code+2, target);
-                                       s390_basr (code, s390_r13, s390_r0);
-                                       s390_j    (code, 6);
-                                       s390_llong(code, fail_tramp);
-                                       s390_lg   (code, s390_r1, 0, s390_r13, 4);
+                                       S390_SET  (code, s390_r1, fail_tramp);
                                        s390_br   (code, s390_r1);
                                        item->jmp_code = NULL;
                                } else {
@@ -6148,34 +5884,27 @@ mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain,
 #if ENABLE_WRONG_METHOD_CHECK
                                        g_assert_not_reached ();
 #endif
-                                       s390_basr (code, s390_r13, s390_r0);
-                                       s390_j    (code, 6);
-                                       s390_llong(code, (&(vtable->vtable [item->value.vtable_slot])));
-                                       s390_lg   (code, s390_r1, 0, s390_r13, 4);
+                                       S390_SET (code, s390_r1, (&(vtable->vtable [item->value.vtable_slot])));
                                        s390_lg   (code, s390_r1, 0, s390_r1, 0);
                                        s390_br   (code, s390_r1);
-#if ENABLE_WRONG_METHOD_CHECK
-                                       g_assert_not_reached ();
-#endif
                                }
                        }
                } else {
-                       s390_basr (code, s390_r13, s390_r0);
-                       s390_j    (code, 6);
-                       s390_llong(code, item->key);
-                       s390_lg   (code, s390_r0, 0, s390_r13, 4);
+                       S390_SET  (code, s390_r0, item->key);
                        s390_cgr  (code, MONO_ARCH_IMT_REG, s390_r0);
                        item->jmp_code = (guint8 *) code;
                        s390_jcl  (code, S390_CC_GE, 0);
                }
        }
-       /* patch the branches to get to the target items */
+       /* 
+        * patch the branches to get to the target items 
+        */
        for (i = 0; i < count; ++i) {
                MonoIMTCheckItem *item = imt_entries [i];
                if (item->jmp_code) {
                        if (item->check_target_idx) {
                                gint64 offset;
-                               offset = S390_RELATIVE(imt_entries [item->check_target_idx]->code_target,
+                               offset = (gint64) S390_RELATIVE(imt_entries [item->check_target_idx]->code_target,
                                                       item->jmp_code);
                                s390_patch_rel ((guchar *) item->jmp_code + 2, (guint64) offset);
                        }
@@ -6244,7 +5973,7 @@ mono_arch_get_cie_program (void)
 {
        GSList *l = NULL;
 
-       mono_add_unwind_op_def_cfa (l, NULL, NULL, STK_BASE, 0);
+       mono_add_unwind_op_def_cfa (l, 0, 0, STK_BASE, 0);
 
        return(l);
 }
@@ -6307,7 +6036,10 @@ gboolean
 mono_arch_is_breakpoint_event (void *info, void *sigctx)
 {
        siginfo_t* sinfo = (siginfo_t*) info;
-       /* Sometimes the address is off by 4 */
+
+       /* 
+        * Sometimes the address is off by 4 
+        */
        if (sinfo->si_addr >= bp_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)bp_trigger_page + 128)
                return TRUE;
        else
@@ -6329,7 +6061,7 @@ mono_arch_is_breakpoint_event (void *info, void *sigctx)
 void
 mono_arch_skip_breakpoint (MonoContext *ctx, MonoJitInfo *ji)
 {
-       MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + BREAKPOINT_SIZE);
+       MONO_CONTEXT_SET_IP (ctx, ((guint8*)MONO_CONTEXT_GET_IP (ctx) + sizeof(RXY_Format)));
 }
 
 /*========================= End of Function ========================*/
@@ -6380,7 +6112,9 @@ mono_arch_is_single_step_event (void *info, void *sigctx)
 {
        siginfo_t* sinfo = (siginfo_t*) info;
 
-       /* Sometimes the address is off by 4 */
+       /* 
+        * Sometimes the address is off by 4 
+        */
        if (sinfo->si_addr >= ss_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)ss_trigger_page + 128)
                return TRUE;
        else
@@ -6424,6 +6158,37 @@ mono_arch_get_seq_point_info (MonoDomain *domain, guint8 *code)
        return NULL;
 }
 
+/*------------------------------------------------------------------*/
+/*                                                                  */
+/* Name                - mono_arch_init_lmf_ext.                               */
+/*                                                                  */
+/* Function -                                                       */
+/*                                                                  */
+/*------------------------------------------------------------------*/
+
+void
+mono_arch_init_lmf_ext (MonoLMFExt *ext, gpointer prev_lmf)
+{
+       ext->lmf.previous_lmf = prev_lmf;
+       /* Mark that this is a MonoLMFExt */
+       ext->lmf.previous_lmf = (gpointer)(((gssize)ext->lmf.previous_lmf) | 2);
+       ext->lmf.ebp = (gssize)ext;
+}
+
 /*========================= End of Function ========================*/
 
 #endif
+
+gboolean
+mono_arch_opcode_supported (int opcode)
+{
+       switch (opcode) {
+       case OP_ATOMIC_ADD_I4:
+       case OP_ATOMIC_ADD_I8:
+       case OP_ATOMIC_EXCHANGE_I4:
+       case OP_ATOMIC_EXCHANGE_I8:
+               return TRUE;
+       default:
+               return FALSE;
+       }
+}