Thu Nov 23 20:01:12 CET 2006 Paolo Molaro <lupus@ximian.com>
[mono.git] / mono / mini / mini.c
index 48ecbd52b6a087495beddebba55c32175fb7129d..716feaa2acd486330ba028823f8b40b4e847f7d0 100644 (file)
 #include <math.h>
 #include <sys/time.h>
 
+#ifdef PLATFORM_MACOSX
+#include <mach/mach.h>
+#include <mach/mach_error.h>
+#include <mach/exception.h>
+#include <mach/task.h>
+#include <pthread.h>
+#endif
+
 #ifdef HAVE_VALGRIND_MEMCHECK_H
 #include <valgrind/memcheck.h>
 #endif
@@ -220,13 +228,35 @@ get_method_from_ip (void *ip)
        return res;
 }
 
+/** 
+ * mono_pmip:
+ * @ip: an instruction pointer address
+ *
+ * This method is used from a debugger to get the name of the
+ * method at address @ip.   This routine is typically invoked from
+ * a debugger like this:
+ *
+ * (gdb) print mono_pmip ($pc)
+ *
+ * Returns: the name of the method at address @ip.
+ */
 G_GNUC_UNUSED char *
 mono_pmip (void *ip)
 {
        return get_method_from_ip (ip);
 }
 
-/* debug function */
+/** 
+ * mono_print_method_from_ip
+ * @ip: an instruction pointer address
+ *
+ * This method is used from a debugger to get the name of the
+ * method at address @ip.
+ *
+ * This prints the name of the method at address @ip in the standard
+ * output.  Unlike mono_pmip which returns a string, this routine
+ * prints the value on the standard output. 
+ */
 void
 mono_print_method_from_ip (void *ip)
 {
@@ -330,7 +360,7 @@ mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
 } while (0)
 
 //#define UNVERIFIED do { G_BREAKPOINT (); goto unverified; } while (0)
-#define UNVERIFIED do { goto unverified; } while (0)
+#define UNVERIFIED do { if (debug_options.break_on_unverified) G_BREAKPOINT (); else goto unverified; } while (0)
 
 /*
  * Basic blocks have two numeric identifiers:
@@ -1075,6 +1105,27 @@ reverse_branch_op (guint32 opcode)
        return opcode;
 }
 
+#ifdef MONO_ARCH_SOFT_FLOAT
+static int
+condbr_to_fp_br (int opcode)
+{
+       switch (opcode) {
+       case CEE_BEQ: return OP_FBEQ;
+       case CEE_BGE: return OP_FBGE;
+       case CEE_BGT: return OP_FBGT;
+       case CEE_BLE: return OP_FBLE;
+       case CEE_BLT: return OP_FBLT;
+       case CEE_BNE_UN: return OP_FBNE_UN;
+       case CEE_BGE_UN: return OP_FBGE_UN;
+       case CEE_BGT_UN: return OP_FBGT_UN;
+       case CEE_BLE_UN: return OP_FBLE_UN;
+       case CEE_BLT_UN: return OP_FBLT_UN;
+       }
+       g_assert_not_reached ();
+       return 0;
+}
+#endif
+
 /*
  * Returns the type used in the eval stack when @type is loaded.
  * FIXME: return a MonoType/MonoClass for the byref and VALUETYPE cases.
@@ -1243,7 +1294,7 @@ ovf3ops_op_map [STACK_MAX] = {
 /* handles from CEE_CEQ to CEE_CLT_UN */
 static const guint16
 ceqops_op_map [STACK_MAX] = {
-       0, 0, OP_LCEQ-CEE_CEQ, OP_PCEQ-CEE_CEQ, OP_FCEQ-CEE_CEQ, OP_LCEQ-CEE_CEQ
+       0, 0, OP_LCEQ-OP_CEQ, OP_PCEQ-OP_CEQ, OP_FCEQ-OP_CEQ, OP_LCEQ-OP_CEQ
 };
 
 /*
@@ -1289,11 +1340,15 @@ type_from_op (MonoInst *ins) {
                        ins->opcode = OP_LCOMPARE;
                return;
        case OP_CEQ:
+               ins->type = bin_comp_table [ins->inst_i0->type] [ins->inst_i1->type] ? STACK_I4: STACK_INV;
+               ins->opcode += ceqops_op_map [ins->inst_i0->type];
+               return;
+               
        case OP_CGT:
        case OP_CGT_UN:
        case OP_CLT:
        case OP_CLT_UN:
-               ins->type = bin_comp_table [ins->inst_i0->type] [ins->inst_i1->type] ? STACK_I4: STACK_INV;
+               ins->type = (bin_comp_table [ins->inst_i0->type] [ins->inst_i1->type] & 1) ? STACK_I4: STACK_INV;
                ins->opcode += ceqops_op_map [ins->inst_i0->type];
                return;
        /* unops */
@@ -1562,7 +1617,7 @@ mono_compile_create_var (MonoCompile *cfg, MonoType *type, int opcode)
        inst->inst_vtype = type;
        inst->klass = mono_class_from_mono_type (type);
        /* if set to 1 the variable is native */
-       inst->unused = 0;
+       inst->backend.is_pinvoke = 0;
 
        cfg->varinfo [num] = inst;
 
@@ -2343,7 +2398,7 @@ mono_spill_call (MonoCompile *cfg, MonoBasicBlock *bblock, MonoCallInst *call, M
                                MONO_ADD_INS (bblock, dummy_store);
 
                        /* we use this to allocate native sized structs */
-                       temp->unused = sig->pinvoke;
+                       temp->backend.is_pinvoke = sig->pinvoke;
 
                        NEW_TEMPLOADA (cfg, loada, temp->inst_c0);
                        if (call->inst.opcode == OP_VCALL)
@@ -2381,13 +2436,31 @@ mono_emit_call_args (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethodSignatu
        MonoInst *arg;
 
        MONO_INST_NEW_CALL (cfg, call, ret_type_to_call_opcode (sig->ret, calli, virtual));
-       
+
+#ifdef MONO_ARCH_SOFT_FLOAT
+       /* we need to convert the r4 value to an int value */
+       {
+               int i;
+               for (i = 0; i < sig->param_count; ++i) {
+                       if (sig->params [i]->type == MONO_TYPE_R4) {
+                               MonoInst *iargs [1];
+                               int temp;
+                               iargs [0] = args [i + sig->hasthis];
+
+                               temp = mono_emit_jit_icall (cfg, bblock, mono_fload_r4_arg, iargs, ip);
+                               NEW_TEMPLOAD (cfg, arg, temp);
+                               args [i + sig->hasthis] = arg;
+                       }
+               }
+       }
+#endif
+
        call->inst.cil_code = ip;
        call->args = args;
        call->signature = sig;
        call = mono_arch_call_opcode (cfg, bblock, call, virtual);
        type_to_eval_stack_type (sig->ret, &call->inst);
-       
+
        for (arg = call->out_args; arg;) {
                MonoInst *narg = arg->next;
                arg->next = NULL;
@@ -2577,7 +2650,14 @@ mono_get_element_address_signature (int arity)
        res->call_convention = MONO_CALL_VARARG;
 #endif
        res->params [0] = &mono_defaults.array_class->byval_arg; 
-       
+
+#ifdef PLATFORM_WIN32
+       /* 
+        * The default pinvoke calling convention is STDCALL but we need CDECL.
+        */
+       res->call_convention = MONO_CALL_C;
+#endif
+
        for (i = 1; i <= arity; i++)
                res->params [i] = &mono_defaults.int_class->byval_arg;
 
@@ -2613,6 +2693,10 @@ mono_get_array_new_va_signature (int arity)
        res->call_convention = MONO_CALL_VARARG;
 #endif
 
+#ifdef PLATFORM_WIN32
+       res->call_convention = MONO_CALL_C;
+#endif
+
        res->params [0] = &mono_defaults.int_class->byval_arg;  
        for (i = 0; i < arity; i++)
                res->params [i + 1] = &mono_defaults.int_class->byval_arg;
@@ -2625,6 +2709,56 @@ mono_get_array_new_va_signature (int arity)
        return res;
 }
 
+#ifdef MONO_ARCH_SOFT_FLOAT
+static void
+handle_store_float (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *ptr, MonoInst *val, const unsigned char *ip)
+{
+       MonoInst *iargs [2];
+       iargs [0] = val;
+       iargs [1] = ptr;
+
+       mono_emit_jit_icall (cfg, bblock, mono_fstore_r4, iargs, ip);
+}
+
+static int
+handle_load_float (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *ptr, const unsigned char *ip)
+{
+       MonoInst *iargs [1];
+       iargs [0] = ptr;
+
+       return mono_emit_jit_icall (cfg, bblock, mono_fload_r4, iargs, ip);
+}
+
+#define LDLOC_SOFT_FLOAT(cfg,ins,idx,ip) do {\
+               if (header->locals [(idx)]->type == MONO_TYPE_R4 && !header->locals [(idx)]->byref) {   \
+                       int temp;       \
+                       NEW_LOCLOADA (cfg, (ins), (idx));       \
+                       temp = handle_load_float (cfg, bblock, (ins), (ip));    \
+                       NEW_TEMPLOAD (cfg, (ins), temp);        \
+               }       \
+       } while (0)
+#define STLOC_SOFT_FLOAT(cfg,ins,idx,ip) do {\
+               if (header->locals [(idx)]->type == MONO_TYPE_R4 && !header->locals [(idx)]->byref) {   \
+                       int temp;       \
+                       NEW_LOCLOADA (cfg, (ins), (idx));       \
+                       handle_store_float (cfg, bblock, (ins), *sp, (ip));     \
+                       MONO_INST_NEW (cfg, (ins), CEE_NOP);    \
+               }       \
+       } while (0)
+#define LDARG_SOFT_FLOAT(cfg,ins,idx,ip) do {\
+               if (param_types [(idx)]->type == MONO_TYPE_R4 && !param_types [(idx)]->byref) { \
+                       int temp;       \
+                       NEW_ARGLOADA (cfg, (ins), (idx));       \
+                       temp = handle_load_float (cfg, bblock, (ins), (ip));    \
+                       NEW_TEMPLOAD (cfg, (ins), temp);        \
+               }       \
+       } while (0)
+#else
+#define LDLOC_SOFT_FLOAT(cfg,ins,idx,ip)
+#define STLOC_SOFT_FLOAT(cfg,ins,idx,ip)
+#define LDARG_SOFT_FLOAT(cfg,ins,idx,ip)
+#endif
+
 static MonoMethod*
 get_memcpy_method (void)
 {
@@ -2679,7 +2813,7 @@ handle_stobj (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *dest, MonoInst
                inst->inst_left = dest;
                inst->inst_right = src;
                inst->cil_code = ip;
-               inst->unused = n;
+               inst->backend.size = n;
                MONO_ADD_INS (bblock, inst);
                return;
        }
@@ -2736,7 +2870,7 @@ handle_initobj (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *dest, const
                if (n <= sizeof (gpointer) * 5) {
                        ins->opcode = OP_MEMSET;
                        ins->inst_imm = 0;
-                       ins->unused = n;
+                       ins->backend.size = n;
                        MONO_ADD_INS (bblock, ins);
                        break;
                }
@@ -2846,19 +2980,20 @@ handle_array_new (MonoCompile *cfg, MonoBasicBlock *bblock, int rank, MonoInst *
        /* Need to register the icall so it gets an icall wrapper */
        sprintf (icall_name, "ves_array_new_va_%d", rank);
 
+       mono_jit_lock ();
        info = mono_find_jit_icall_by_name (icall_name);
        if (info == NULL) {
                esig = mono_get_array_new_va_signature (rank);
                name = g_strdup (icall_name);
                info = mono_register_jit_icall (mono_array_new_va, name, esig, FALSE);
 
-               mono_jit_lock ();
                g_hash_table_insert (jit_icall_name_hash, name, name);
-               mono_jit_unlock ();
        }
+       mono_jit_unlock ();
 
        cfg->flags |= MONO_CFG_HAS_VARARGS;
 
+       /* FIXME: This uses info->sig, but it should use the signature of the wrapper */
        return mono_emit_native_call (cfg, bblock, mono_icall_get_wrapper (info), info->sig, sp, ip, TRUE, FALSE);
 }
 
@@ -2902,8 +3037,6 @@ mini_class_is_system_array (MonoClass *klass)
 {
        if (klass->parent == mono_defaults.array_class)
                return TRUE;
-       else if (mono_defaults.generic_array_class && klass->parent && klass->parent->generic_class)
-               return klass->parent->generic_class->container_class == mono_defaults.generic_array_class;
        else
                return FALSE;
 }
@@ -2939,6 +3072,11 @@ mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method)
                if (MONO_TYPE_ISSTRUCT (signature->params [i])) {
                        return FALSE;
                }
+#ifdef MONO_ARCH_SOFT_FLOAT
+               /* this complicates things, fix later */
+               if (signature->params [i]->type == MONO_TYPE_R4)
+                       return FALSE;
+#endif
        }
 
        /*
@@ -3032,7 +3170,7 @@ mini_get_ldelema_ins (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *cmet
        }
 
        if (rank == 2 && (cfg->opt & MONO_OPT_INTRINS)) {
-#ifdef MONO_ARCH_EMULATE_MUL_DIV
+#if defined(MONO_ARCH_EMULATE_MUL_DIV) && !defined(MONO_ARCH_NO_EMULATE_MUL)
                /* OP_LDELEMA2D depends on OP_LMUL */
 #else
                MonoInst *indexes;
@@ -3042,7 +3180,7 @@ mini_get_ldelema_ins (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *cmet
                addr->inst_right = indexes;
                addr->cil_code = ip;
                addr->type = STACK_MP;
-               addr->klass = cmethod->klass;
+               addr->klass = cmethod->klass->element_class;
                return addr;
 #endif
        }
@@ -3050,17 +3188,18 @@ mini_get_ldelema_ins (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *cmet
        /* Need to register the icall so it gets an icall wrapper */
        sprintf (icall_name, "ves_array_element_address_%d", rank);
 
+       mono_jit_lock ();
        info = mono_find_jit_icall_by_name (icall_name);
        if (info == NULL) {
                esig = mono_get_element_address_signature (rank);
                name = g_strdup (icall_name);
                info = mono_register_jit_icall (ves_array_element_address, name, esig, FALSE);
 
-               mono_jit_lock ();
                g_hash_table_insert (jit_icall_name_hash, name, name);
-               mono_jit_unlock ();
        }
+       mono_jit_unlock ();
 
+       /* FIXME: This uses info->sig, but it should use the signature of the wrapper */
        temp = mono_emit_native_call (cfg, bblock, mono_icall_get_wrapper (info), info->sig, sp, ip, FALSE, FALSE);
        cfg->flags |= MONO_CFG_HAS_VARARGS;
 
@@ -3068,11 +3207,12 @@ mini_get_ldelema_ins (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *cmet
        return addr;
 }
 
-MonoJitICallInfo **emul_opcode_map = NULL;
+static MonoJitICallInfo **emul_opcode_map = NULL;
 
 MonoJitICallInfo *
 mono_find_jit_opcode_emulation (int opcode)
 {
+       g_assert (opcode >= 0 && opcode <= OP_LAST);
        if  (emul_opcode_map)
                return emul_opcode_map [opcode];
        else
@@ -3287,6 +3427,9 @@ inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig,
                return 0;
 #endif
 
+       if (bblock->out_of_line && !inline_allways)
+               return 0;
+
        if (cfg->verbose_level > 2)
                g_print ("INLINE START %p %s -> %s\n", cmethod,  mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
 
@@ -3381,6 +3524,7 @@ inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig,
 #define CHECK_LOCAL(num) if ((unsigned)(num) >= (unsigned)header->num_locals) UNVERIFIED
 #define CHECK_OPSIZE(size) if (ip + size > end) UNVERIFIED
 #define CHECK_UNVERIFIABLE(cfg) if (cfg->unverifiable) UNVERIFIED
+#define CHECK_TYPELOAD(klass) if (!(klass) || (klass)->exception_type) {cfg->exception_ptr = klass; goto load_error;}
 
 /* offset from br.s -> br like opcodes */
 #define BIG_BRANCH_OFFSET 13
@@ -3716,6 +3860,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
        dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE;
        dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH;
        dont_verify |= method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE; /* bug #77896 */
+       dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP;
+       dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP_INVOKE;
 
        /* still some type unsafety issues in marshal wrappers... (unknown is PtrToStructure) */
        dont_verify_stloc = method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE;
@@ -3904,7 +4050,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                }
        }
        
-       if ((header->init_locals || (cfg->method == method && (cfg->opt & MONO_OPT_SHARED))) || mono_compile_aot || security || pinvoke) {
+       if ((header->init_locals || (cfg->method == method && (cfg->opt & MONO_OPT_SHARED))) || cfg->compile_aot || security || pinvoke) {
                /* we use a separate basic block for the initialization code */
                cfg->bb_init = init_localsbb = NEW_BBLOCK (cfg);
                init_localsbb->real_offset = real_offset;
@@ -4083,6 +4229,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        n = (*ip)-CEE_LDARG_0;
                        CHECK_ARG (n);
                        NEW_ARGLOAD (cfg, ins, n);
+                       LDARG_SOFT_FLOAT (cfg, ins, n, ip);
                        ins->cil_code = ip++;
                        *sp++ = ins;
                        break;
@@ -4094,6 +4241,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        n = (*ip)-CEE_LDLOC_0;
                        CHECK_LOCAL (n);
                        NEW_LOCLOAD (cfg, ins, n);
+                       LDLOC_SOFT_FLOAT (cfg, ins, n, ip);
                        ins->cil_code = ip++;
                        *sp++ = ins;
                        break;
@@ -4110,6 +4258,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        ins->cil_code = ip;
                        if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
                                UNVERIFIED;
+                       STLOC_SOFT_FLOAT (cfg, ins, n, ip);
                        if (ins->opcode == CEE_STOBJ) {
                                NEW_LOCLOADA (cfg, ins, n);
                                handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE, FALSE);
@@ -4123,6 +4272,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        CHECK_STACK_OVF (1);
                        CHECK_ARG (ip [1]);
                        NEW_ARGLOAD (cfg, ins, ip [1]);
+                       LDARG_SOFT_FLOAT (cfg, ins, ip [1], ip);
                        ins->cil_code = ip;
                        *sp++ = ins;
                        ip += 2;
@@ -4158,6 +4308,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        CHECK_STACK_OVF (1);
                        CHECK_LOCAL (ip [1]);
                        NEW_LOCLOAD (cfg, ins, ip [1]);
+                       LDLOC_SOFT_FLOAT (cfg, ins, ip [1], ip);
                        ins->cil_code = ip;
                        *sp++ = ins;
                        ip += 2;
@@ -4181,6 +4332,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        ins->cil_code = ip;
                        if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [ip [1]], *sp))
                                UNVERIFIED;
+                       STLOC_SOFT_FLOAT (cfg, ins, ip [1], ip);
                        if (ins->opcode == CEE_STOBJ) {
                                NEW_LOCLOADA (cfg, ins, ip [1]);
                                handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE, FALSE);
@@ -4376,18 +4528,22 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                                n = fsig->param_count + fsig->hasthis;
                        } else {
+                               MonoMethod *cil_method;
+                               
                                if (method->wrapper_type != MONO_WRAPPER_NONE) {
                                        cmethod =  (MonoMethod *)mono_method_get_wrapper_data (method, token);
+                                       cil_method = cmethod;
                                } else if (constrained_call) {
-                                       cmethod = mono_get_method_constrained (image, token, constrained_call, generic_context);
+                                       cmethod = mono_get_method_constrained (image, token, constrained_call, generic_context, &cil_method);
                                        cmethod = mono_get_inflated_method (cmethod);
                                } else {
                                        cmethod = mini_get_method (method, token, NULL, generic_context);
+                                       cil_method = cmethod;
                                }
 
                                if (!cmethod)
                                        goto load_error;
-                               if (!dont_verify && !can_access_method (method, cmethod))
+                               if (!dont_verify && !cfg->skip_visibility && !can_access_method (method, cil_method))
                                        UNVERIFIED;
 
                                if (!virtual && (cmethod->flags & METHOD_ATTRIBUTE_ABSTRACT))
@@ -4480,8 +4636,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                            !((cmethod->flags & METHOD_ATTRIBUTE_FINAL) && 
                              cmethod->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK) &&
                            mono_method_signature (cmethod)->generic_param_count) {
-                               MonoInst *this_temp, *store;
-                               MonoInst *iargs [3];
+                               MonoInst *this_temp, *this_arg_temp, *store;
+                               MonoInst *iargs [4];
 
                                g_assert (mono_method_signature (cmethod)->is_inflated);
                                /* Prevent inlining of methods that contain indirect calls */
@@ -4494,13 +4650,18 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                store->cil_code = ip;
                                MONO_ADD_INS (bblock, store);
 
+                               /* FIXME: This should be a managed pointer */
+                               this_arg_temp = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
+                               this_arg_temp->cil_code = ip;
+
                                NEW_TEMPLOAD (cfg, iargs [0], this_temp->inst_c0);
                                NEW_PCONST (cfg, iargs [1], cmethod);
                                NEW_PCONST (cfg, iargs [2], ((MonoMethodInflated *) cmethod)->context);
+                               NEW_TEMPLOADA (cfg, iargs [3], this_arg_temp->inst_c0);
                                temp = mono_emit_jit_icall (cfg, bblock, mono_helper_compile_generic_method, iargs, ip);
 
                                NEW_TEMPLOAD (cfg, addr, temp);
-                               NEW_TEMPLOAD (cfg, sp [0], this_temp->inst_c0);
+                               NEW_TEMPLOAD (cfg, sp [0], this_arg_temp->inst_c0);
 
                                if ((temp = mono_emit_calli (cfg, bblock, fsig, sp, addr, ip)) != -1) {
                                        NEW_TEMPLOAD (cfg, *sp, temp);
@@ -4508,23 +4669,36 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                }
 
                                ip += 5;
+                               ins_flag = 0;
                                break;
                        }
 
                        if ((ins_flag & MONO_INST_TAILCALL) && cmethod && (*ip == CEE_CALL) &&
                                 (mono_metadata_signature_equal (mono_method_signature (method), mono_method_signature (cmethod)))) {
                                int i;
+
                                /* Prevent inlining of methods with tail calls (the call stack would be altered) */
                                INLINE_FAILURE;
                                /* FIXME: This assumes the two methods has the same number and type of arguments */
+                               /*
+                                * We implement tail calls by storing the actual arguments into the 
+                                * argument variables, then emitting a CEE_JMP. Since the actual arguments
+                                * can refer to the arg variables, we have to spill them.
+                                */
+                               handle_loaded_temps (cfg, bblock, sp, sp + n);
                                for (i = 0; i < n; ++i) {
+                                       /* Prevent argument from being register allocated */
+                                       arg_array [i]->flags |= MONO_INST_VOLATILE;
+
                                        /* Check if argument is the same */
+                                       /* 
+                                        * FIXME: This loses liveness info, so it can only be done if the
+                                        * argument is not register allocated.
+                                        */
                                        NEW_ARGLOAD (cfg, ins, i);
                                        if ((ins->opcode == sp [i]->opcode) && (ins->inst_i0 == sp [i]->inst_i0))
                                                continue;
 
-                                       /* Prevent argument from being register allocated */
-                                       arg_array [i]->flags |= MONO_INST_VOLATILE;
                                        NEW_ARGSTORE (cfg, ins, i, sp [i]);
                                        ins->cil_code = ip;
                                        if (ins->opcode == CEE_STOBJ) {
@@ -4558,6 +4732,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                }
 
                                ip += 5;
+                               ins_flag = 0;
                                break;
                        }
 
@@ -4595,6 +4770,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        bblock = ebblock;
 
                                        inline_costs += costs;
+                                       ins_flag = 0;
                                        break;
                                }
                        }
@@ -4633,7 +4809,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                                ip += 6;
                                        else
                                                ip += 5;
-
+                                       ins_flag = 0;
                                        break;
                                }
                        }
@@ -4720,6 +4896,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        }
 
                        ip += 5;
+                       ins_flag = 0;
                        break;
                }
                case CEE_RET:
@@ -4822,7 +4999,22 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        ins->cil_code = ip++;
                        target = ip + 1 + *(signed char*)ip;
                        ip++;
+#ifdef MONO_ARCH_SOFT_FLOAT
+                       if (sp [-1]->type == STACK_R8 || sp [-2]->type == STACK_R8) {
+                               ins->opcode = condbr_to_fp_br (ins->opcode);
+                               sp -= 2;
+                               ins->inst_left = sp [0];
+                               ins->inst_right = sp [1];
+                               ins->type = STACK_I4;
+                               *sp++ = emit_tree (cfg, bblock, ins, ins->cil_code);
+                               MONO_INST_NEW (cfg, ins, CEE_BRTRUE);
+                               ADD_UNCOND (TRUE);
+                       } else {
+                               ADD_BINCOND (NULL);
+                       }
+#else
                        ADD_BINCOND (NULL);
+#endif
                        if (sp != stack_start) {
                                handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
                                sp = stack_start;
@@ -4883,7 +5075,22 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        ins->cil_code = ip++;
                        target = ip + 4 + (gint32)read32(ip);
                        ip += 4;
-                       ADD_BINCOND(NULL);
+#ifdef MONO_ARCH_SOFT_FLOAT
+                       if (sp [-1]->type == STACK_R8 || sp [-2]->type == STACK_R8) {
+                               ins->opcode = condbr_to_fp_br (ins->opcode);
+                               sp -= 2;
+                               ins->inst_left = sp [0];
+                               ins->inst_right = sp [1];
+                               ins->type = STACK_I4;
+                               *sp++ = emit_tree (cfg, bblock, ins, ins->cil_code);
+                               MONO_INST_NEW (cfg, ins, CEE_BRTRUE);
+                               ADD_UNCOND (TRUE);
+                       } else {
+                               ADD_BINCOND (NULL);
+                       }
+#else
+                       ADD_BINCOND (NULL);
+#endif
                        if (sp != stack_start) {
                                handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
                                sp = stack_start;
@@ -4948,6 +5155,15 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        ins_flag = 0;
                        if (ins->type == STACK_OBJ)
                                ins->klass = mono_defaults.object_class;
+#ifdef MONO_ARCH_SOFT_FLOAT
+                       if (*ip == CEE_LDIND_R4) {
+                               int temp;
+                               ++sp;
+                               temp = handle_load_float (cfg, bblock, ins->inst_i0, ip);
+                               NEW_TEMPLOAD (cfg, *sp, temp);
+                               sp++;
+                       }
+#endif
                        ++ip;
                        break;
                case CEE_STIND_REF:
@@ -4958,6 +5174,14 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                case CEE_STIND_R4:
                case CEE_STIND_R8:
                        CHECK_STACK (2);
+#ifdef MONO_ARCH_SOFT_FLOAT
+                       if (*ip == CEE_STIND_R4) {
+                               sp -= 2;
+                               handle_store_float (cfg, bblock, sp [0], sp [1], ip);
+                               ip++;
+                               break;
+                       }
+#endif
 #if HAVE_WRITE_BARRIERS
                        if (*ip == CEE_STIND_REF && method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER) {
                                /* insert call to write barrier */
@@ -5108,8 +5332,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        CHECK_STACK (2);
                        token = read32 (ip + 1);
                        klass = mini_get_class (method, token, generic_context);
-                       if (!klass)
-                               goto load_error;
+                       CHECK_TYPELOAD (klass);
                        sp -= 2;
                        if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
                                MonoInst *store, *load;
@@ -5134,7 +5357,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        copy->inst_left = sp [0];
                                        copy->inst_right = sp [1];
                                        copy->cil_code = ip;
-                                       copy->unused = n;
+                                       copy->backend.size = n;
                                        MONO_ADD_INS (bblock, copy);
                                } else {
                                        MonoMethod *memcpy_method = get_memcpy_method ();
@@ -5159,8 +5382,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        --sp;
                        token = read32 (ip + 1);
                        klass = mini_get_class (method, token, generic_context);
-                       if (!klass)
-                               goto load_error;
+                       CHECK_TYPELOAD (klass);
                        if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
                                MONO_INST_NEW (cfg, ins, CEE_LDIND_REF);
                                ins->cil_code = ip;
@@ -5216,7 +5438,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                copy->inst_left = iargs [0];
                                copy->inst_right = *sp;
                                copy->cil_code = ip;
-                               copy->unused = n;
+                               copy->backend.size = n;
                                MONO_ADD_INS (bblock, copy);
                        } else {
                                MonoMethod *memcpy_method = get_memcpy_method ();
@@ -5427,8 +5649,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        CHECK_OPSIZE (5);
                        token = read32 (ip + 1);
                        klass = mini_get_class (method, token, generic_context);
-                       if (!klass)
-                               goto load_error;
+                       CHECK_TYPELOAD (klass);
                        if (sp [0]->type != STACK_OBJ)
                                UNVERIFIED;
 
@@ -5484,8 +5705,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        CHECK_OPSIZE (5);
                        token = read32 (ip + 1);
                        klass = mini_get_class (method, token, generic_context);
-                       if (!klass)
-                               goto load_error;
+                       CHECK_TYPELOAD (klass);
 
                        if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
                                /* CASTCLASS */
@@ -5563,7 +5783,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                copy->inst_left = iargs [0];
                                copy->inst_right = *sp;
                                copy->cil_code = ip;
-                               copy->unused = n;
+                               copy->backend.size = n;
                                MONO_ADD_INS (bblock, copy);
                        } else {
                                MonoMethod *memcpy_method = get_memcpy_method ();
@@ -5586,8 +5806,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        CHECK_OPSIZE (5);
                        token = read32 (ip + 1);
                        klass = mini_get_class (method, token, generic_context);
-                       if (!klass)
-                               goto load_error;
+                       CHECK_TYPELOAD (klass);
 
                        if (mono_class_is_nullable (klass)) {
                                int v = handle_unbox_nullable (cfg, bblock, *sp, ip, klass);
@@ -5624,8 +5843,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        CHECK_OPSIZE (5);
                        token = read32 (ip + 1);
                        klass = mini_get_class (method, token, generic_context);
-                       if (!klass)
-                               goto load_error;
+                       CHECK_TYPELOAD (klass);
                        if (sp [0]->type != STACK_OBJ)
                                UNVERIFIED;
 
@@ -5719,7 +5937,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        if (!field)
                                goto load_error;
                        mono_class_init (klass);
-                       if (!dont_verify && !can_access_field (method, field))
+                       if (!dont_verify && !cfg->skip_visibility && !can_access_field (method, field))
                                UNVERIFIED;
 
                        foffset = klass->valuetype? field->offset - sizeof (MonoObject): field->offset;
@@ -5774,6 +5992,17 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        iargs [0] = ins;
                                        iargs [1] = sp [1];
                                        mono_emit_method_call_spilled (cfg, bblock, write_barrier, mono_method_signature (write_barrier), iargs, ip, NULL);
+#endif
+#ifdef MONO_ARCH_SOFT_FLOAT
+                               } else if (mono_type_to_stind (field->type) == CEE_STIND_R4) {
+                                       NEW_ICONST (cfg, offset_ins, foffset);
+                                       MONO_INST_NEW (cfg, ins, OP_PADD);
+                                       ins->cil_code = ip;
+                                       ins->inst_left = *sp;
+                                       ins->inst_right = offset_ins;
+                                       ins->type = STACK_MP;
+                                       ins->klass = mono_defaults.object_class;
+                                       handle_store_float (cfg, bblock, ins, sp [1], ip);
 #endif
                                } else {
                                        MonoInst *store;
@@ -5854,6 +6083,14 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                                load->inst_left = ins;
                                                load->flags |= ins_flag;
                                                ins_flag = 0;
+#ifdef MONO_ARCH_SOFT_FLOAT
+                                               if (mono_type_to_ldind (field->type) == CEE_LDIND_R4) {
+                                                       int temp;
+                                                       temp = handle_load_float (cfg, bblock, ins, ip);
+                                                       NEW_TEMPLOAD (cfg, *sp, temp);
+                                                       sp++;
+                                               } else
+#endif
                                                *sp++ = load;
                                        }
                                }
@@ -6062,8 +6299,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        CHECK_OPSIZE (5);
                        token = read32 (ip + 1);
                        klass = mini_get_class (method, token, generic_context);
-                       if (!klass)
-                               goto load_error;
+                       CHECK_TYPELOAD (klass);
                        n = mono_type_to_stind (&klass->byval_arg);
                        if (n == CEE_STOBJ) {
                                handle_stobj (cfg, bblock, sp [0], sp [1], ip, klass, FALSE, FALSE, TRUE);
@@ -6089,8 +6325,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        CHECK_OPSIZE (5);
                        token = read32 (ip + 1);
                        klass = mini_get_class (method, token, generic_context);
-                       if (!klass)
-                               goto load_error;
+                       CHECK_TYPELOAD (klass);
 
                        if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
                                *sp++ = val;
@@ -6161,8 +6396,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        mono_get_got_var (cfg);
 
                        klass = mini_get_class (method, token, generic_context);
-                       if (!klass)
-                               goto load_error;
+                       CHECK_TYPELOAD (klass);
                        ins->inst_newa_class = klass;
                        ins->inst_newa_len = *sp;
                        ins->type = STACK_OBJ;
@@ -6205,8 +6439,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                UNVERIFIED;
 
                        klass = mini_get_class (method, read32 (ip + 1), generic_context);
-                       if (!klass)
-                               goto load_error;                        
+                       CHECK_TYPELOAD (klass);
                        /* we need to make sure that this array is exactly the type it needs
                         * to be for correctness. the wrappers are lax with their usage
                         * so we need to ignore them here
@@ -6237,8 +6470,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        CHECK_OPSIZE (5);
                        token = read32 (ip + 1);
                        klass = mono_class_get_full (image, token, generic_context);
-                       if (!klass)
-                               goto load_error;
+                       CHECK_TYPELOAD (klass);
                        mono_class_init (klass);
                        NEW_LDELEMA (cfg, load, sp, klass);
                        load->cil_code = ip;
@@ -6274,6 +6506,16 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        klass = array_access_to_klass (*ip);
                        NEW_LDELEMA (cfg, load, sp, klass);
                        load->cil_code = ip;
+#ifdef MONO_ARCH_SOFT_FLOAT
+                       if (*ip == CEE_LDELEM_R4) {
+                               int temp;
+                               temp = handle_load_float (cfg, bblock, load, ip);
+                               NEW_TEMPLOAD (cfg, *sp, temp);
+                               sp++;
+                               ++ip;
+                               break;
+                       }
+#endif
                        MONO_INST_NEW (cfg, ins, ldelem_to_ldind [*ip - CEE_LDELEM_I1]);
                        ins->cil_code = ip;
                        ins->inst_left = load;
@@ -6303,6 +6545,13 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        klass = array_access_to_klass (*ip);
                        NEW_LDELEMA (cfg, load, sp, klass);
                        load->cil_code = ip;
+#ifdef MONO_ARCH_SOFT_FLOAT
+                       if (*ip == CEE_STELEM_R4) {
+                               handle_store_float (cfg, bblock, load, sp [2], ip);
+                               ip++;
+                               break;
+                       }
+#endif
                        MONO_INST_NEW (cfg, ins, stelem_to_stind [*ip - CEE_STELEM_I]);
                        ins->cil_code = ip;
                        ins->inst_left = load;
@@ -6327,8 +6576,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        CHECK_OPSIZE (5);
                        token = read32 (ip + 1);
                        klass = mono_class_get_full (image, token, generic_context);
-                       if (!klass)
-                               goto load_error;
+                       CHECK_TYPELOAD (klass);
                        mono_class_init (klass);
                        if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
                                MonoMethod* helper = mono_marshal_get_stelemref ();
@@ -6423,8 +6671,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        --sp;
                        CHECK_OPSIZE (5);
                        klass = mono_class_get_full (image, read32 (ip + 1), generic_context);
-                       if (!klass)
-                               goto load_error;
+                       CHECK_TYPELOAD (klass);
                        mono_class_init (klass);
                        ins->type = STACK_MP;
                        ins->inst_left = *sp;
@@ -6442,8 +6689,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        --sp;
                        CHECK_OPSIZE (5);
                        klass = mono_class_get_full (image, read32 (ip + 1), generic_context);
-                       if (!klass)
-                               goto load_error;
+                       CHECK_TYPELOAD (klass);
                        mono_class_init (klass);
                        ins->cil_code = ip;
 
@@ -6874,13 +7120,21 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                cmp->cil_code = ip;
                                type_from_op (cmp);
                                CHECK_TYPE (cmp);
+                               ins->cil_code = ip;
+                               ins->type = STACK_I4;
+                               ins->inst_i0 = cmp;
+#if MONO_ARCH_SOFT_FLOAT
+                               if (sp [0]->type == STACK_R8) {
+                                       cmp->type = STACK_I4;
+                                       *sp++ = emit_tree (cfg, bblock, cmp, ip + 2);
+                                       ip += 2;
+                                       break;
+                               }
+#endif
                                if ((sp [0]->type == STACK_I8) || ((sizeof (gpointer) == 8) && ((sp [0]->type == STACK_PTR) || (sp [0]->type == STACK_OBJ) || (sp [0]->type == STACK_MP))))
                                        cmp->opcode = OP_LCOMPARE;
                                else
                                        cmp->opcode = OP_COMPARE;
-                               ins->cil_code = ip;
-                               ins->type = STACK_I4;
-                               ins->inst_i0 = cmp;
                                *sp++ = ins;
                                /* spill it to reduce the expression complexity
                                 * and workaround bug 54209 
@@ -6959,6 +7213,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                n = read16 (ip + 2);
                                CHECK_ARG (n);
                                NEW_ARGLOAD (cfg, ins, n);
+                               LDARG_SOFT_FLOAT (cfg, ins, n, ip);
                                ins->cil_code = ip;
                                *sp++ = ins;
                                ip += 4;
@@ -6997,6 +7252,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                n = read16 (ip + 2);
                                CHECK_LOCAL (n);
                                NEW_LOCLOAD (cfg, ins, n);
+                               LDLOC_SOFT_FLOAT (cfg, ins, n, ip);
                                ins->cil_code = ip;
                                *sp++ = ins;
                                ip += 4;
@@ -7022,6 +7278,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
                                        UNVERIFIED;
                                ins->cil_code = ip;
+                               STLOC_SOFT_FLOAT (cfg, ins, n, ip);
                                if (ins->opcode == CEE_STOBJ) {
                                        NEW_LOCLOADA (cfg, ins, n);
                                        handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE, FALSE);
@@ -7110,8 +7367,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                CHECK_OPSIZE (6);
                                token = read32 (ip + 2);
                                klass = mini_get_class (method, token, generic_context);
-                               if (!klass)
-                                       goto load_error;
+                               CHECK_TYPELOAD (klass);
                                if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
                                        MonoInst *store, *load;
                                        NEW_PCONST (cfg, load, NULL);
@@ -7135,8 +7391,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                CHECK_OPSIZE (6);
                                token = read32 (ip + 2);
                                constrained_call = mono_class_get_full (image, token, generic_context);
-                               if (!constrained_call)
-                                       goto load_error;
+                               CHECK_TYPELOAD (constrained_call);
                                ip += 6;
                                break;
                        case CEE_CPBLK:
@@ -7150,7 +7405,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        copy->inst_left = sp [0];
                                        copy->inst_right = sp [1];
                                        copy->cil_code = ip;
-                                       copy->unused = n;
+                                       copy->backend.size = n;
                                        MONO_ADD_INS (bblock, copy);
                                        ip += 2;
                                        break;
@@ -7217,8 +7472,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        token = mono_type_size (type, &ialign);
                                } else {
                                        MonoClass *klass = mono_class_get_full (image, token, generic_context);
-                                       if (!klass)
-                                               goto load_error;
+                                       CHECK_TYPELOAD (klass);
                                        mono_class_init (klass);
                                        token = mono_class_value_size (klass, &align);
                                }
@@ -7300,11 +7554,15 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                NEW_LOCSTORE (cfg, store, i, ins);
                                MONO_ADD_INS (init_localsbb, store);
                        } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
+#ifdef MONO_ARCH_SOFT_FLOAT
+                               /* FIXME: handle init of R4 */
+#else
                                MONO_INST_NEW (cfg, ins, OP_R8CONST);
                                ins->type = STACK_R8;
                                ins->inst_p0 = (void*)&r8_0;
                                NEW_LOCSTORE (cfg, store, i, ins);
                                MONO_ADD_INS (init_localsbb, store);
+#endif
                        } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
                                   ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (ptype))) {
                                NEW_LOCLOADA (cfg, ins, i);
@@ -7537,6 +7795,8 @@ mono_icall_get_wrapper (MonoJitICallInfo* callinfo)
 {
        char *name;
        MonoMethod *wrapper;
+       gconstpointer trampoline;
+       MonoDomain *domain = mono_get_root_domain ();
        
        if (callinfo->wrapper) {
                return callinfo->wrapper;
@@ -7545,13 +7805,28 @@ mono_icall_get_wrapper (MonoJitICallInfo* callinfo)
        if (callinfo->trampoline)
                return callinfo->trampoline;
 
+       /* 
+        * We use the lock on the root domain instead of the JIT lock to protect 
+        * callinfo->trampoline, since we do a lot of stuff inside the critical section.
+        */
+       mono_domain_lock (domain);
+
+       if (callinfo->trampoline) {
+               mono_domain_unlock (domain);
+               return callinfo->trampoline;
+       }
+
        name = g_strdup_printf ("__icall_wrapper_%s", callinfo->name);
        wrapper = mono_marshal_get_icall_wrapper (callinfo->sig, name, callinfo->func);
        g_free (name);
 
-       callinfo->trampoline = mono_create_ftnptr (mono_get_root_domain (), mono_create_jit_trampoline_in_domain (mono_get_root_domain (), wrapper));
-       mono_register_jit_icall_wrapper (callinfo, callinfo->trampoline);
+       trampoline = mono_create_ftnptr (domain, mono_create_jit_trampoline_in_domain (domain, wrapper));
+       mono_register_jit_icall_wrapper (callinfo, trampoline);
 
+       callinfo->trampoline = trampoline;
+
+       mono_domain_unlock (domain);
+       
        return callinfo->trampoline;
 }
 
@@ -7816,7 +8091,7 @@ typedef struct {
 } StackSlotInfo;
 
 /*
- * mono_allocate_stack_slots_full:
+ *  mono_allocate_stack_slots_full:
  *
  *  Allocate stack slots for all non register allocated variables using a
  * linear scan algorithm.
@@ -7862,9 +8137,9 @@ mono_allocate_stack_slots_full (MonoCompile *m, gboolean backward, guint32 *stac
                vmv = l->data;
                inst = m->varinfo [vmv->idx];
 
-               /* inst->unused indicates native sized value types, this is used by the
+               /* inst->backend.is_pinvoke indicates native sized value types, this is used by the
                * pinvoke wrappers when they call functions returning structures */
-               if (inst->unused && MONO_TYPE_ISSTRUCT (inst->inst_vtype) && inst->inst_vtype->type != MONO_TYPE_TYPEDBYREF)
+               if (inst->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (inst->inst_vtype) && inst->inst_vtype->type != MONO_TYPE_TYPEDBYREF)
                        size = mono_class_native_size (inst->inst_vtype->data.klass, &align);
                else {
                        int ialign;
@@ -7874,28 +8149,32 @@ mono_allocate_stack_slots_full (MonoCompile *m, gboolean backward, guint32 *stac
                }
 
                t = mono_type_get_underlying_type (inst->inst_vtype);
-               switch (t->type) {
-               case MONO_TYPE_GENERICINST:
-                       if (!mono_type_generic_inst_is_valuetype (t)) {
-                               slot_info = &scalar_stack_slots [t->type];
-                               break;
-                       }
-                       /* Fall through */
-               case MONO_TYPE_VALUETYPE:
-                       for (i = 0; i < nvtypes; ++i)
-                               if (t->data.klass == vtype_stack_slots [i].vtype)
+               if (t->byref) {
+                       slot_info = &scalar_stack_slots [MONO_TYPE_I];
+               } else {
+                       switch (t->type) {
+                       case MONO_TYPE_GENERICINST:
+                               if (!mono_type_generic_inst_is_valuetype (t)) {
+                                       slot_info = &scalar_stack_slots [t->type];
                                        break;
-                       if (i < nvtypes)
-                               slot_info = &vtype_stack_slots [i];
-                       else {
-                               g_assert (nvtypes < 256);
-                               vtype_stack_slots [nvtypes].vtype = t->data.klass;
-                               slot_info = &vtype_stack_slots [nvtypes];
-                               nvtypes ++;
+                               }
+                               /* Fall through */
+                       case MONO_TYPE_VALUETYPE:
+                               for (i = 0; i < nvtypes; ++i)
+                                       if (t->data.klass == vtype_stack_slots [i].vtype)
+                                               break;
+                               if (i < nvtypes)
+                                       slot_info = &vtype_stack_slots [i];
+                               else {
+                                       g_assert (nvtypes < 256);
+                                       vtype_stack_slots [nvtypes].vtype = t->data.klass;
+                                       slot_info = &vtype_stack_slots [nvtypes];
+                                       nvtypes ++;
+                               }
+                               break;
+                       default:
+                               slot_info = &scalar_stack_slots [t->type];
                        }
-                       break;
-               default:
-                       slot_info = &scalar_stack_slots [t->type];
                }
 
                slot = 0xffffff;
@@ -8071,6 +8350,58 @@ decompose_foreach (MonoInst *tree, gpointer data)
                        dec_foreach (iargs [i], cfg);
                break;
        }
+#ifdef MONO_ARCH_SOFT_FLOAT
+       case OP_FBEQ:
+       case OP_FBGE:
+       case OP_FBGT:
+       case OP_FBLE:
+       case OP_FBLT:
+       case OP_FBNE_UN:
+       case OP_FBGE_UN:
+       case OP_FBGT_UN:
+       case OP_FBLE_UN:
+       case OP_FBLT_UN: {
+               if ((info = mono_find_jit_opcode_emulation (tree->opcode))) {
+                       MonoCompile *cfg = data;
+                       MonoInst *iargs [2];
+               
+                       iargs [0] = tree->inst_i0;
+                       iargs [1] = tree->inst_i1;
+               
+                       mono_emulate_opcode (cfg, tree, iargs, info);
+
+                       dec_foreach (iargs [0], cfg);
+                       dec_foreach (iargs [1], cfg);
+                       break;
+               } else {
+                       g_assert_not_reached ();
+               }
+               break;
+       }
+       case OP_FCEQ:
+       case OP_FCGT:
+       case OP_FCGT_UN:
+       case OP_FCLT:
+       case OP_FCLT_UN: {
+               if ((info = mono_find_jit_opcode_emulation (tree->opcode))) {
+                       MonoCompile *cfg = data;
+                       MonoInst *iargs [2];
+
+                       /* the args are in the compare opcode ... */
+                       iargs [0] = tree->inst_i0;
+                       iargs [1] = tree->inst_i1;
+               
+                       mono_emulate_opcode (cfg, tree, iargs, info);
+
+                       dec_foreach (iargs [0], cfg);
+                       dec_foreach (iargs [1], cfg);
+                       break;
+               } else {
+                       g_assert_not_reached ();
+               }
+               break;
+       }
+#endif
 
        default:
                break;
@@ -8203,6 +8534,13 @@ mono_destroy_compile (MonoCompile *cfg)
 
 #ifdef HAVE_KW_THREAD
 static __thread gpointer mono_lmf_addr MONO_TLS_FAST;
+#ifdef MONO_ARCH_ENABLE_MONO_LMF_VAR
+/* 
+ * When this is defined, the current lmf is stored in this tls variable instead of in 
+ * jit_tls->lmf.
+ */
+static __thread gpointer mono_lmf MONO_TLS_FAST;
+#endif
 #endif
 
 guint32
@@ -8213,12 +8551,40 @@ mono_get_jit_tls_key (void)
 
 gint32
 mono_get_lmf_tls_offset (void)
+{
+#if defined(HAVE_KW_THREAD) && defined(MONO_ARCH_ENABLE_MONO_LMF_VAR)
+       int offset;
+       MONO_THREAD_VAR_OFFSET(mono_lmf,offset);
+       return offset;
+#else
+       return -1;
+#endif
+}
+
+gint32
+mono_get_lmf_addr_tls_offset (void)
 {
        int offset;
        MONO_THREAD_VAR_OFFSET(mono_lmf_addr,offset);
        return offset;
 }
 
+MonoLMF *
+mono_get_lmf (void)
+{
+#if defined(HAVE_KW_THREAD) && defined(MONO_ARCH_ENABLE_MONO_LMF_VAR)
+       return mono_lmf;
+#else
+       MonoJitTlsData *jit_tls;
+
+       if ((jit_tls = TlsGetValue (mono_jit_tls_id)))
+               return jit_tls->lmf;
+
+       g_assert_not_reached ();
+       return NULL;
+#endif
+}
+
 MonoLMF **
 mono_get_lmf_addr (void)
 {
@@ -8286,10 +8652,18 @@ setup_jit_tls_data (gpointer stack_start, gpointer abort_func)
        lmf = g_new0 (MonoLMF, 1);
        lmf->ebp = -1;
 
-       jit_tls->lmf = jit_tls->first_lmf = lmf;
+       jit_tls->first_lmf = lmf;
 
-#ifdef HAVE_KW_THREAD
-       mono_lmf_addr = &jit_tls->lmf;
+#if defined(HAVE_KW_THREAD) && defined(MONO_ARCH_ENABLE_MONO_LMF_VAR)
+       /* jit_tls->lmf is unused */
+       mono_lmf = lmf;
+       mono_lmf_addr = &mono_lmf;
+#else
+#if defined(HAVE_KW_THREAD)
+       mono_lmf_addr = &jit_tls->lmf;  
+#endif
+
+       jit_tls->lmf = lmf;
 #endif
 
        mono_arch_setup_jit_tls_data (jit_tls);
@@ -8378,6 +8752,86 @@ mono_remove_patch_info (MonoCompile *cfg, int ip)
        }
 }
 
+/**
+ * mono_patch_info_dup_mp:
+ *
+ * Make a copy of PATCH_INFO, allocating memory from the mempool MP.
+ */
+MonoJumpInfo*
+mono_patch_info_dup_mp (MonoMemPool *mp, MonoJumpInfo *patch_info)
+{
+       MonoJumpInfo *res = mono_mempool_alloc (mp, sizeof (MonoJumpInfo));
+       memcpy (res, patch_info, sizeof (MonoJumpInfo));
+
+       switch (patch_info->type) {
+       case MONO_PATCH_INFO_LDSTR:
+       case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
+       case MONO_PATCH_INFO_LDTOKEN:
+       case MONO_PATCH_INFO_DECLSEC:
+               res->data.token = mono_mempool_alloc (mp, sizeof (MonoJumpInfoToken));
+               memcpy (res->data.token, patch_info->data.token, sizeof (MonoJumpInfoToken));
+               break;
+       case MONO_PATCH_INFO_SWITCH:
+               res->data.table = mono_mempool_alloc (mp, sizeof (MonoJumpInfoBBTable));
+               memcpy (res->data.table, patch_info->data.table, sizeof (MonoJumpInfoBBTable));
+               break;
+       default:
+               break;
+       }
+
+       return res;
+}
+
+guint
+mono_patch_info_hash (gconstpointer data)
+{
+       const MonoJumpInfo *ji = (MonoJumpInfo*)data;
+
+       switch (ji->type) {
+       case MONO_PATCH_INFO_LDSTR:
+       case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
+       case MONO_PATCH_INFO_LDTOKEN:
+       case MONO_PATCH_INFO_DECLSEC:
+               return (ji->type << 8) | ji->data.token->token;
+       default:
+               return (ji->type << 8);
+       }
+}
+
+/* 
+ * mono_patch_info_equal:
+ * 
+ * This might fail to recognize equivalent patches, i.e. floats, so its only
+ * usable in those cases where this is not a problem, i.e. sharing GOT slots
+ * in AOT.
+ */
+gint
+mono_patch_info_equal (gconstpointer ka, gconstpointer kb)
+{
+       const MonoJumpInfo *ji1 = (MonoJumpInfo*)ka;
+       const MonoJumpInfo *ji2 = (MonoJumpInfo*)kb;
+
+       if (ji1->type != ji2->type)
+               return 0;
+
+       switch (ji1->type) {
+       case MONO_PATCH_INFO_LDSTR:
+       case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
+       case MONO_PATCH_INFO_LDTOKEN:
+       case MONO_PATCH_INFO_DECLSEC:
+               if ((ji1->data.token->image != ji2->data.token->image) ||
+                       (ji1->data.token->token != ji2->data.token->token))
+                       return 0;
+               break;
+       default:
+               if (ji1->data.name != ji2->data.name)
+                       return 0;
+               break;
+       }
+
+       return 1;
+}
+
 gpointer
 mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *patch_info, gboolean run_cctors)
 {
@@ -9284,7 +9738,6 @@ emit_state (MonoCompile *cfg, MBState *state, int goal)
        MBState *kids [10];
        int ern = mono_burg_rule (state, goal);
        const guint16 *nts = mono_burg_nts_data + mono_burg_nts [ern];
-       MBEmitFunc emit;
 
        //g_print ("rule: %s\n", mono_burg_rule_string [ern]);
        switch (goal) {
@@ -9303,7 +9756,12 @@ emit_state (MonoCompile *cfg, MBState *state, int goal)
                state->reg2 = mono_regstate_next_int (cfg->rs);
                break;
        case MB_NTERM_freg:
+#ifdef MONO_ARCH_SOFT_FLOAT
+               state->reg1 = mono_regstate_next_int (cfg->rs);
+               state->reg2 = mono_regstate_next_int (cfg->rs);
+#else
                state->reg1 = mono_regstate_next_float (cfg->rs);
+#endif
                break;
        default:
 #ifdef MONO_ARCH_ENABLE_EMIT_STATE_OPT
@@ -9336,8 +9794,7 @@ emit_state (MonoCompile *cfg, MBState *state, int goal)
        }
 
 //     g_print ("emit: %s (%p)\n", mono_burg_rule_string [ern], state);
-       if ((emit = mono_burg_func [ern]))
-               emit (state, state->tree, cfg); 
+       mono_burg_emit (ern, state, state->tree, cfg);
 }
 
 #define DEBUG_SELECTION
@@ -9760,6 +10217,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
        cfg->domain = domain;
        cfg->verbose_level = mini_verbose;
        cfg->compile_aot = compile_aot;
+       cfg->skip_visibility = method->skip_visibility;
        if (!header) {
                cfg->exception_type = MONO_EXCEPTION_INVALID_PROGRAM;
                cfg->exception_message = g_strdup_printf ("Missing or incorrect header for method %s", cfg->method->name);
@@ -9791,7 +10249,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
        mono_jit_stats.basic_blocks += cfg->num_bblocks;
        mono_jit_stats.max_basic_blocks = MAX (cfg->num_bblocks, mono_jit_stats.max_basic_blocks);
 
-       if ((cfg->num_varinfo > 2000) && !mono_compile_aot) {
+       if ((cfg->num_varinfo > 2000) && !cfg->compile_aot) {
                /* 
                 * we disable some optimizations if there are too many variables
                 * because JIT time may become too expensive. The actual number needs 
@@ -10087,18 +10545,16 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in
        method = mono_get_inflated_method (method);
 
 #ifdef MONO_USE_AOT_COMPILER
-       if (!mono_compile_aot && (opt & MONO_OPT_AOT) && !(mono_profiler_get_events () & MONO_PROFILE_JIT_COMPILATION)) {
-               MonoJitInfo *info;
+       if ((opt & MONO_OPT_AOT) && !(mono_profiler_get_events () & MONO_PROFILE_JIT_COMPILATION)) {
                MonoDomain *domain = mono_domain_get ();
 
-               mono_domain_lock (domain);
-
                mono_class_init (method->klass);
-               if ((info = mono_aot_get_method (domain, method))) {
-                       g_hash_table_insert (domain->jit_code_hash, method, info);
+
+               mono_domain_lock (domain);
+               if ((code = mono_aot_get_method (domain, method))) {
                        mono_domain_unlock (domain);
                        mono_runtime_class_init (mono_class_vtable (domain, method->klass));
-                       return info->code_start;
+                       return code;
                }
 
                mono_domain_unlock (domain);
@@ -10110,7 +10566,7 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in
                MonoMethod *nm;
                MonoMethodPInvoke* piinfo = (MonoMethodPInvoke *) method;
 
-               if (method->iflags & METHOD_IMPL_ATTRIBUTE_NATIVE)
+               if (method->iflags & METHOD_IMPL_ATTRIBUTE_NATIVE && !MONO_CLASS_IS_IMPORT(method->klass))
                        g_error ("Method '%s' in assembly '%s' contains native code and mono can't run it. The assembly was probably created by Managed C++.\n", mono_method_full_name (method, TRUE), method->klass->image->name);
 
                if (!piinfo->addr) {
@@ -10158,11 +10614,16 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in
                /* Throw a type load exception if needed */
                MonoLoaderError *error = mono_loader_get_last_error ();
 
-               mono_destroy_compile (cfg);
                if (error) {
                        MonoException *ex = mono_loader_error_prepare_exception (error);
+                       mono_destroy_compile (cfg);
                        mono_raise_exception (ex);
                } else {
+                       if (cfg->exception_ptr) {
+                               MonoException *ex = mono_class_get_exception_for_failure (cfg->exception_ptr);
+                               mono_destroy_compile (cfg);
+                               mono_raise_exception (ex);
+                       }
                        g_assert_not_reached ();
                }
        }
@@ -10426,29 +10887,33 @@ mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObjec
        return runtime_invoke (obj, params, exc, compiled_method);
 }
 
+#ifdef MONO_GET_CONTEXT
+#define GET_CONTEXT MONO_GET_CONTEXT
+#endif
+
+#ifndef GET_CONTEXT
 #ifdef PLATFORM_WIN32
 #define GET_CONTEXT \
        struct sigcontext *ctx = (struct sigcontext*)_dummy;
 #else
-#ifdef __sparc
+#ifdef MONO_ARCH_USE_SIGACTION
 #define GET_CONTEXT \
     void *ctx = context;
-#elif defined(sun)    // Solaris x86
+#elif defined(__sparc__)
 #define GET_CONTEXT \
-    ucontext_t *uctx = context; \
-    struct sigcontext *ctx = (struct sigcontext *)&(uctx->uc_mcontext);
-#elif defined (MONO_ARCH_USE_SIGACTION)
-#define GET_CONTEXT \
-    void *ctx = context;
+    void *ctx = sigctx;
 #else
 #define GET_CONTEXT \
        void **_p = (void **)&_dummy; \
        struct sigcontext *ctx = (struct sigcontext *)++_p;
 #endif
 #endif
+#endif
 
 #ifdef MONO_ARCH_USE_SIGACTION
 #define SIG_HANDLER_SIGNATURE(ftn) ftn (int _dummy, siginfo_t *info, void *context)
+#elif defined(__sparc__)
+#define SIG_HANDLER_SIGNATURE(ftn) ftn (int _dummy, void *sigctx)
 #else
 #define SIG_HANDLER_SIGNATURE(ftn) ftn (int _dummy)
 #endif
@@ -10623,6 +11088,127 @@ SIG_HANDLER_SIGNATURE (sigusr2_signal_handler)
        mono_trace_enable (!enabled);
 }
 
+#ifdef PLATFORM_MACOSX
+
+/*
+ * This code disables the CrashReporter of MacOS X by installing
+ * a dummy Mach exception handler.
+ */
+
+/*
+ * http://darwinsource.opendarwin.org/10.4.3/xnu-792.6.22/osfmk/man/exc_server.html
+ */
+extern
+boolean_t
+exc_server (mach_msg_header_t *request_msg,
+           mach_msg_header_t *reply_msg);
+
+/*
+ * The exception message
+ */
+typedef struct {
+       mach_msg_base_t msg;  /* common mach message header */
+       char payload [1024];  /* opaque */
+} mach_exception_msg_t;
+
+/* The exception port */
+static mach_port_t mach_exception_port = VM_MAP_NULL;
+
+/*
+ * Implicitly called by exc_server. Must be public.
+ *
+ * http://darwinsource.opendarwin.org/10.4.3/xnu-792.6.22/osfmk/man/catch_exception_raise.html
+ */
+kern_return_t
+catch_exception_raise (
+       mach_port_t exception_port,
+       mach_port_t thread,
+       mach_port_t task,
+       exception_type_t exception,
+       exception_data_t code,
+       mach_msg_type_number_t code_count)
+{
+       /* consume the exception */
+       return KERN_FAILURE;
+}
+
+/*
+ * Exception thread handler.
+ */
+static
+void *
+mach_exception_thread (void *arg)
+{
+       for (;;) {
+               mach_exception_msg_t request;
+               mach_exception_msg_t reply;
+               mach_msg_return_t result;
+
+               /* receive from "mach_exception_port" */
+               result = mach_msg (&request.msg.header,
+                                  MACH_RCV_MSG | MACH_RCV_LARGE,
+                                  0,
+                                  sizeof (request),
+                                  mach_exception_port,
+                                  MACH_MSG_TIMEOUT_NONE,
+                                  MACH_PORT_NULL);
+
+               g_assert (result == MACH_MSG_SUCCESS);
+
+               /* dispatch to catch_exception_raise () */
+               exc_server (&request.msg.header, &reply.msg.header);
+
+               /* send back to sender */
+               result = mach_msg (&reply.msg.header,
+                                  MACH_SEND_MSG,
+                                  reply.msg.header.msgh_size,
+                                  0,
+                                  MACH_PORT_NULL,
+                                  MACH_MSG_TIMEOUT_NONE,
+                                  MACH_PORT_NULL);
+
+               g_assert (result == MACH_MSG_SUCCESS);
+       }
+       return NULL;
+}
+
+static void
+macosx_register_exception_handler ()
+{
+       mach_port_t task;
+       pthread_attr_t attr;
+       pthread_t thread;
+
+       if (mach_exception_port != VM_MAP_NULL)
+               return;
+
+       task = mach_task_self ();
+
+       /* create the "mach_exception_port" with send & receive rights */
+       g_assert (mach_port_allocate (task, MACH_PORT_RIGHT_RECEIVE,
+                                     &mach_exception_port) == KERN_SUCCESS);
+       g_assert (mach_port_insert_right (task, mach_exception_port, mach_exception_port,
+                                         MACH_MSG_TYPE_MAKE_SEND) == KERN_SUCCESS);
+
+       /* create the exception handler thread */
+       g_assert (!pthread_attr_init (&attr));
+       g_assert (!pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED));
+       g_assert (!pthread_create (&thread, &attr, mach_exception_thread, NULL));
+       pthread_attr_destroy (&attr);
+
+       /*
+        * register "mach_exception_port" as a receiver for the
+        * EXC_BAD_ACCESS exception
+        *
+        * http://darwinsource.opendarwin.org/10.4.3/xnu-792.6.22/osfmk/man/task_set_exception_ports.html
+        */
+       g_assert (task_set_exception_ports (task, EXC_MASK_BAD_ACCESS,
+                                           mach_exception_port,
+                                           EXCEPTION_DEFAULT,
+                                           MACHINE_THREAD_STATE) == KERN_SUCCESS);
+}
+#endif
+
 #ifndef PLATFORM_WIN32
 static void
 add_signal_handler (int signo, gpointer handler)
@@ -10640,6 +11226,18 @@ add_signal_handler (int signo, gpointer handler)
 #endif
        g_assert (sigaction (signo, &sa, NULL) != -1);
 }
+
+static void
+remove_signal_handler (int signo)
+{
+       struct sigaction sa;
+
+       sa.sa_handler = SIG_DFL;
+       sigemptyset (&sa.sa_mask);
+       sa.sa_flags = 0;
+
+       g_assert (sigaction (signo, &sa, NULL) != -1);
+}
 #endif
 
 static void
@@ -10659,10 +11257,10 @@ mono_runtime_install_handlers (void)
 
 #else /* !PLATFORM_WIN32 */
 
-       /* libpthreads has its own implementation of sigaction(),
-        * but it seems to work well with our current exception
-        * handlers. If not we must call syscall directly instead 
-        * of sigaction */
+
+#ifdef PLATFORM_MACOSX
+       macosx_register_exception_handler ();
+#endif
 
        if (debug_options.handle_sigint)
                add_signal_handler (SIGINT, sigint_signal_handler);
@@ -10691,6 +11289,30 @@ mono_runtime_install_handlers (void)
 #endif /* PLATFORM_WIN32 */
 }
 
+static void
+mono_runtime_cleanup_handlers (void)
+{
+#ifdef PLATFORM_WIN32
+       win32_seh_cleanup();
+#else
+       if (debug_options.handle_sigint)
+               remove_signal_handler (SIGINT);
+
+       remove_signal_handler (SIGFPE);
+       remove_signal_handler (SIGQUIT);
+       remove_signal_handler (SIGILL);
+       remove_signal_handler (SIGBUS);
+       if (mono_jit_trace_calls != NULL)
+               remove_signal_handler (SIGUSR2);
+
+       remove_signal_handler (mono_thread_get_abort_signal ());
+
+       remove_signal_handler (SIGABRT);
+
+       remove_signal_handler (SIGSEGV);
+#endif /* PLATFORM_WIN32 */
+}
+
 
 #ifdef HAVE_LINUX_RTC_H
 #include <linux/rtc.h>
@@ -10818,9 +11440,11 @@ mini_parse_debug_options (void)
                        debug_options.keep_delegates = TRUE;
                else if (!strcmp (arg, "collect-pagefault-stats"))
                        debug_options.collect_pagefault_stats = TRUE;
+               else if (!strcmp (arg, "break-on-unverified"))
+                       debug_options.break_on_unverified = TRUE;
                else {
                        fprintf (stderr, "Invalid option for the MONO_DEBUG env variable: %s\n", arg);
-                       fprintf (stderr, "Available options: 'handle-sigint', 'keep-delegates', 'collect-pagefault-stats'\n");
+                       fprintf (stderr, "Available options: 'handle-sigint', 'keep-delegates', 'collect-pagefault-stats', 'break-on-unverified'\n");
                        exit (1);
                }
        }
@@ -10831,6 +11455,13 @@ mini_init (const char *filename)
 {
        MonoDomain *domain;
 
+#ifdef __linux__
+       if (access ("/proc/self/maps", F_OK) != 0) {
+               g_print ("Mono requires /proc to be mounted.\n");
+               exit (1);
+       }
+#endif
+
        /* Happens when using the embedding interface */
        if (!default_opt_set)
                default_opt = mono_parse_default_optimizations (NULL);
@@ -10876,7 +11507,17 @@ mini_init (const char *filename)
                 * GC_register_stackbottom as well, but don't know how.
                 */
 #else
-               GC_stackbottom = (char*)sstart + size;
+               /* apparently with some linuxthreads implementations sstart can be NULL,
+                * fallback to the more imprecise method (bug# 78096).
+                */
+               if (sstart) {
+                       GC_stackbottom = (char*)sstart + size;
+               } else {
+                       gsize stack_bottom = (gsize)&domain;
+                       stack_bottom += 4095;
+                       stack_bottom &= ~4095;
+                       GC_stackbottom = (char*)stack_bottom;
+               }
 #endif
        }
 #elif defined(HAVE_PTHREAD_GET_STACKSIZE_NP) && defined(HAVE_PTHREAD_GET_STACKADDR_NP)
@@ -10920,6 +11561,7 @@ mini_init (const char *filename)
        mono_install_stack_walk (mono_jit_walk_stack);
        mono_install_init_vtable (mono_aot_init_vtable);
        mono_install_get_cached_class_info (mono_aot_get_cached_class_info);
+       mono_install_get_class_from_name (mono_aot_get_class_from_name);
        mono_install_jit_info_find_in_aot (mono_aot_find_jit_info);
 
        if (debug_options.collect_pagefault_stats) {
@@ -10995,17 +11637,19 @@ mini_init (const char *filename)
 #endif
 
 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
-       mono_register_opcode_emulation (CEE_DIV, "__emul_idiv", "int32 int32 int32", mono_idiv, TRUE);
-       mono_register_opcode_emulation (CEE_DIV_UN, "__emul_idiv_un", "int32 int32 int32", mono_idiv_un, TRUE);
-       mono_register_opcode_emulation (CEE_REM, "__emul_irem", "int32 int32 int32", mono_irem, TRUE);
-       mono_register_opcode_emulation (CEE_REM_UN, "__emul_irem_un", "int32 int32 int32", mono_irem_un, TRUE);
+       mono_register_opcode_emulation (CEE_DIV, "__emul_idiv", "int32 int32 int32", mono_idiv, FALSE);
+       mono_register_opcode_emulation (CEE_DIV_UN, "__emul_idiv_un", "int32 int32 int32", mono_idiv_un, FALSE);
+       mono_register_opcode_emulation (CEE_REM, "__emul_irem", "int32 int32 int32", mono_irem, FALSE);
+       mono_register_opcode_emulation (CEE_REM_UN, "__emul_irem_un", "int32 int32 int32", mono_irem_un, FALSE);
 #endif
 
 #ifdef MONO_ARCH_EMULATE_MUL_DIV
-       mono_register_opcode_emulation (CEE_MUL_OVF, "__emul_imul_ovf", "int32 int32 int32", mono_imul_ovf, TRUE);
-       mono_register_opcode_emulation (CEE_MUL_OVF_UN, "__emul_imul_ovf_un", "int32 int32 int32", mono_imul_ovf_un, TRUE);
+       mono_register_opcode_emulation (CEE_MUL_OVF, "__emul_imul_ovf", "int32 int32 int32", mono_imul_ovf, FALSE);
+       mono_register_opcode_emulation (CEE_MUL_OVF_UN, "__emul_imul_ovf_un", "int32 int32 int32", mono_imul_ovf_un, FALSE);
        mono_register_opcode_emulation (CEE_MUL, "__emul_imul", "int32 int32 int32", mono_imul, TRUE);
-       mono_register_opcode_emulation (OP_FDIV, "__emul_fdiv", "double double double", mono_fdiv, TRUE);
+#endif
+#if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_SOFT_FLOAT)
+       mono_register_opcode_emulation (OP_FDIV, "__emul_fdiv", "double double double", mono_fdiv, FALSE);
 #endif
 
        mono_register_opcode_emulation (OP_FCONV_TO_U8, "__emul_fconv_to_u8", "ulong double", mono_fconv_u8, FALSE);
@@ -11032,6 +11676,42 @@ mini_init (const char *filename)
        mono_register_opcode_emulation (OP_FREM, "__emul_frem", "double double double", fmod, FALSE);
 #endif
 
+#ifdef MONO_ARCH_SOFT_FLOAT
+       mono_register_opcode_emulation (OP_FSUB, "__emul_fsub", "double double double", mono_fsub, FALSE);
+       mono_register_opcode_emulation (OP_FADD, "__emul_fadd", "double double double", mono_fadd, FALSE);
+       mono_register_opcode_emulation (OP_FMUL, "__emul_fmul", "double double double", mono_fmul, FALSE);
+       mono_register_opcode_emulation (OP_FNEG, "__emul_fneg", "double double", mono_fneg, FALSE);
+       mono_register_opcode_emulation (CEE_CONV_R8, "__emul_conv_r8", "double int32", mono_conv_to_r8, FALSE);
+       mono_register_opcode_emulation (CEE_CONV_R4, "__emul_conv_r4", "double int32", mono_conv_to_r4, FALSE);
+       mono_register_opcode_emulation (OP_FCONV_TO_R4, "__emul_fconv_to_r4", "double double", mono_fconv_r4, FALSE);
+       mono_register_opcode_emulation (OP_FCONV_TO_I1, "__emul_fconv_to_i1", "int8 double", mono_fconv_i1, FALSE);
+       mono_register_opcode_emulation (OP_FCONV_TO_I2, "__emul_fconv_to_i2", "int16 double", mono_fconv_i2, FALSE);
+       mono_register_opcode_emulation (OP_FCONV_TO_I4, "__emul_fconv_to_i4", "int32 double", mono_fconv_i4, FALSE);
+       mono_register_opcode_emulation (OP_FCONV_TO_U1, "__emul_fconv_to_u1", "uint8 double", mono_fconv_u1, FALSE);
+       mono_register_opcode_emulation (OP_FCONV_TO_U2, "__emul_fconv_to_u2", "uint16 double", mono_fconv_u2, FALSE);
+
+       mono_register_opcode_emulation (OP_FBEQ, "__emul_fcmp_eq", "uint32 double double", mono_fcmp_eq, FALSE);
+       mono_register_opcode_emulation (OP_FBLT, "__emul_fcmp_lt", "uint32 double double", mono_fcmp_lt, FALSE);
+       mono_register_opcode_emulation (OP_FBGT, "__emul_fcmp_gt", "uint32 double double", mono_fcmp_gt, FALSE);
+       mono_register_opcode_emulation (OP_FBLE, "__emul_fcmp_le", "uint32 double double", mono_fcmp_le, FALSE);
+       mono_register_opcode_emulation (OP_FBGE, "__emul_fcmp_ge", "uint32 double double", mono_fcmp_ge, FALSE);
+       mono_register_opcode_emulation (OP_FBNE_UN, "__emul_fcmp_ne_un", "uint32 double double", mono_fcmp_ne_un, FALSE);
+       mono_register_opcode_emulation (OP_FBLT_UN, "__emul_fcmp_lt_un", "uint32 double double", mono_fcmp_lt_un, FALSE);
+       mono_register_opcode_emulation (OP_FBGT_UN, "__emul_fcmp_gt_un", "uint32 double double", mono_fcmp_gt_un, FALSE);
+       mono_register_opcode_emulation (OP_FBLE_UN, "__emul_fcmp_le_un", "uint32 double double", mono_fcmp_le_un, FALSE);
+       mono_register_opcode_emulation (OP_FBGE_UN, "__emul_fcmp_ge_un", "uint32 double double", mono_fcmp_ge_un, FALSE);
+
+       mono_register_opcode_emulation (OP_FCEQ, "__emul_fcmp_ceq", "uint32 double double", mono_fceq, FALSE);
+       mono_register_opcode_emulation (OP_FCGT, "__emul_fcmp_cgt", "uint32 double double", mono_fcgt, FALSE);
+       mono_register_opcode_emulation (OP_FCGT_UN, "__emul_fcmp_cgt_un", "uint32 double double", mono_fcgt_un, FALSE);
+       mono_register_opcode_emulation (OP_FCLT, "__emul_fcmp_clt", "uint32 double double", mono_fclt, FALSE);
+       mono_register_opcode_emulation (OP_FCLT_UN, "__emul_fcmp_clt_un", "uint32 double double", mono_fclt_un, FALSE);
+
+       register_icall (mono_fload_r4, "mono_fload_r4", "double ptr", FALSE);
+       register_icall (mono_fstore_r4, "mono_fstore_r4", "void double ptr", FALSE);
+       register_icall (mono_fload_r4_arg, "mono_fload_r4_arg", "uint32 double", FALSE);
+#endif
+
 #if SIZEOF_VOID_P == 4
        mono_register_opcode_emulation (OP_FCONV_TO_U, "__emul_fconv_to_u", "uint32 double", mono_fconv_u4, TRUE);
 #endif
@@ -11043,7 +11723,6 @@ mini_init (const char *filename)
        register_icall (mono_ldtoken_wrapper, "mono_ldtoken_wrapper", "ptr ptr ptr ptr", FALSE);
        register_icall (mono_get_special_static_data, "mono_get_special_static_data", "ptr int", FALSE);
        register_icall (mono_ldstr, "mono_ldstr", "object ptr ptr int32", FALSE);
-       register_icall (mono_helper_stelem_ref, "helper_stelem_ref", "void ptr int32 object", FALSE);
        register_icall (mono_helper_stelem_ref_check, "helper_stelem_ref_check", "void object object", FALSE);
        register_icall (mono_object_new, "mono_object_new", "object ptr ptr", FALSE);
        register_icall (mono_object_new_specific, "mono_object_new_specific", "object ptr", FALSE);
@@ -11053,7 +11732,7 @@ mini_init (const char *filename)
        register_icall (mono_ldftn, "mono_ldftn", "ptr ptr", FALSE);
        register_icall (mono_ldftn_nosync, "mono_ldftn_nosync", "ptr ptr", FALSE);
        register_icall (mono_ldvirtfn, "mono_ldvirtfn", "ptr object ptr", FALSE);
-       register_icall (mono_helper_compile_generic_method, "compile_generic_method", "ptr object ptr ptr", FALSE);
+       register_icall (mono_helper_compile_generic_method, "compile_generic_method", "ptr object ptr ptr ptr", FALSE);
        register_icall (mono_helper_ldstr, "helper_ldstr", "object ptr int", FALSE);
        register_icall (mono_helper_ldstr_mscorlib, "helper_ldstr_mscorlib", "object int", FALSE);
        register_icall (mono_helper_newobj_mscorlib, "helper_newobj_mscorlib", "object int", FALSE);
@@ -11099,8 +11778,11 @@ print_jit_stats (void)
                g_print ("\nCreated object count:   %ld\n", mono_stats.new_object_count);
                g_print ("Initialized classes:    %ld\n", mono_stats.initialized_class_count);
                g_print ("Used classes:           %ld\n", mono_stats.used_class_count);
+               g_print ("Generic vtables:        %ld\n", mono_stats.generic_vtable_count);
+               g_print ("Methods:                %ld\n", mono_stats.method_count);
                g_print ("Static data size:       %ld\n", mono_stats.class_static_data_size);
                g_print ("VTable data size:       %ld\n", mono_stats.class_vtable_size);
+               g_print ("Mscorlib mempool size:  %d\n", mono_mempool_get_allocated (mono_defaults.corlib->mempool));
 
                g_print ("\nGeneric instances:      %ld\n", mono_stats.generic_instance_count);
                g_print ("Initialized classes:    %ld\n", mono_stats.generic_class_count);
@@ -11151,9 +11833,7 @@ mini_cleanup (MonoDomain *domain)
 
        mono_icall_cleanup ();
 
-#ifdef PLATFORM_WIN32
-       win32_seh_cleanup();
-#endif
+       mono_runtime_cleanup_handlers ();
 
        mono_domain_free (domain, TRUE);
 
@@ -11168,6 +11848,12 @@ mini_cleanup (MonoDomain *domain)
        mono_trace_cleanup ();
 
        mono_counters_dump (-1, stdout);
+
+       TlsFree(mono_jit_tls_id);
+
+       DeleteCriticalSection (&jit_mutex);
+
+       DeleteCriticalSection (&mono_delegate_section);
 }
 
 void