2009-07-27 Mark Probst <mark.probst@gmail.com>
[mono.git] / mono / mini / method-to-ir.c
index afd24b4eb0de9ce2399c53a83f0ba9cec1639369..9f9c21b28185650ede6aa839332840112ea04331 100644 (file)
@@ -121,7 +121,11 @@ extern MonoMethodSignature *helper_sig_monitor_enter_exit_trampoline;
 #ifdef MINI_OP
 #undef MINI_OP
 #endif
-#define MINI_OP(a,b,dest,src1,src2) dest, src1, src2,
+#ifdef MINI_OP3
+#undef MINI_OP3
+#endif
+#define MINI_OP(a,b,dest,src1,src2) dest, src1, src2, ' ',
+#define MINI_OP3(a,b,dest,src1,src2,src3) dest, src1, src2, src3,
 #define NONE ' '
 #define IREG 'i'
 #define FREG 'f'
@@ -138,6 +142,19 @@ ins_info[] = {
 #include "mini-ops.h"
 };
 #undef MINI_OP
+#undef MINI_OP3
+
+#define MINI_OP(a,b,dest,src1,src2) ((src2) != NONE ? 2 : ((src1) != NONE ? 1 : 0)),
+#define MINI_OP3(a,b,dest,src1,src2,src3) ((src3) != NONE ? 3 : ((src2) != NONE ? 2 : ((src1) != NONE ? 1 : 0))),
+/* 
+ * This should contain the index of the last sreg + 1. This is not the same
+ * as the number of sregs for opcodes like IA64_CMP_EQ_IMM.
+ */
+const gint8 ins_sreg_counts[] = {
+#include "mini-ops.h"
+};
+#undef MINI_OP
+#undef MINI_OP3
 
 extern GHashTable *jit_icall_name_hash;
 
@@ -147,6 +164,14 @@ extern GHashTable *jit_icall_name_hash;
        (vi)->idx = (id); \
 } while (0)
 
+void
+mono_inst_set_src_registers (MonoInst *ins, int *regs)
+{
+       ins->sreg1 = regs [0];
+       ins->sreg2 = regs [1];
+       ins->sreg3 = regs [2];
+}
+
 guint32
 mono_alloc_ireg (MonoCompile *cfg)
 {
@@ -270,7 +295,7 @@ mono_print_bb (MonoBasicBlock *bb, const char *msg)
                } \
        } while (0)
 
-#if defined(__i386__) || defined(__x86_64__)
+#if defined(TARGET_X86) || defined(TARGET_AMD64)
 #define EMIT_NEW_X86_LEA(cfg,dest,sr1,sr2,shift,imm) do { \
                MONO_INST_NEW (cfg, dest, OP_X86_LEA); \
                (dest)->dreg = alloc_preg ((cfg)); \
@@ -307,8 +332,7 @@ mono_print_bb (MonoBasicBlock *bb, const char *msg)
         ADD_WIDEN_OP (ins, sp [0], sp [1]); \
         ins->dreg = alloc_dreg ((cfg), (ins)->type); \
         MONO_ADD_INS ((cfg)->cbb, (ins)); \
-               *sp++ = ins;    \
-        mono_decompose_opcode ((cfg), (ins)); \
+        *sp++ = mono_decompose_opcode ((cfg), (ins)); \
        } while (0)
 
 #define ADD_UNOP(op) do {      \
@@ -319,8 +343,7 @@ mono_print_bb (MonoBasicBlock *bb, const char *msg)
                CHECK_TYPE (ins);       \
         (ins)->dreg = alloc_dreg ((cfg), (ins)->type); \
         MONO_ADD_INS ((cfg)->cbb, (ins)); \
-               *sp++ = ins;    \
-               mono_decompose_opcode (cfg, ins); \
+               *sp++ = mono_decompose_opcode (cfg, ins); \
        } while (0)
 
 #define ADD_BINCOND(next_block) do {   \
@@ -444,7 +467,6 @@ mono_find_block_region (MonoCompile *cfg, int offset)
        MonoExceptionClause *clause;
        int i;
 
-       /* first search for handlers and filters */
        for (i = 0; i < header->num_clauses; ++i) {
                clause = &header->clauses [i];
                if ((clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) && (offset >= clause->data.filter_offset) &&
@@ -459,11 +481,7 @@ mono_find_block_region (MonoCompile *cfg, int offset)
                        else
                                return ((i + 1) << 8) | MONO_REGION_CATCH | clause->flags;
                }
-       }
 
-       /* search the try blocks */
-       for (i = 0; i < header->num_clauses; ++i) {
-               clause = &header->clauses [i];
                if (MONO_OFFSET_IN_CLAUSE (clause, offset))
                        return ((i + 1) << 8) | clause->flags;
        }
@@ -1029,7 +1047,7 @@ mono_get_domainvar (MonoCompile *cfg)
  * The got_var contains the address of the Global Offset Table when AOT 
  * compiling.
  */
-inline static MonoInst *
+MonoInst *
 mono_get_got_var (MonoCompile *cfg)
 {
 #ifdef MONO_ARCH_NEED_GOT_VAR
@@ -1611,19 +1629,19 @@ mini_emit_memset (MonoCompile *cfg, int destreg, int offset, int size, int val,
                switch (size) {
                case 1:
                        MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI1_MEMBASE_IMM, destreg, offset, val);
-                       break;
+                       return;
                case 2:
                        MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI2_MEMBASE_IMM, destreg, offset, val);
-                       break;
+                       return;
                case 4:
                        MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI4_MEMBASE_IMM, destreg, offset, val);
-                       break;
+                       return;
 #if SIZEOF_REGISTER == 8
                case 8:
                        MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI8_MEMBASE_IMM, destreg, offset, val);
+                       return;
 #endif
                }
-               return;
        }
 
        val_reg = alloc_preg (cfg);
@@ -2085,21 +2103,29 @@ mono_emit_jit_icall (MonoCompile *cfg, gconstpointer func, MonoInst **args);
 
 inline static MonoCallInst *
 mono_emit_call_args (MonoCompile *cfg, MonoMethodSignature *sig, 
-                    MonoInst **args, int calli, int virtual)
+                                        MonoInst **args, int calli, int virtual, int tail)
 {
        MonoCallInst *call;
 #ifdef MONO_ARCH_SOFT_FLOAT
        int i;
 #endif
 
-       MONO_INST_NEW_CALL (cfg, call, ret_type_to_call_opcode (sig->ret, calli, virtual, cfg->generic_sharing_context));
+       if (tail)
+               MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
+       else
+               MONO_INST_NEW_CALL (cfg, call, ret_type_to_call_opcode (sig->ret, calli, virtual, cfg->generic_sharing_context));
 
        call->args = args;
        call->signature = sig;
 
        type_to_eval_stack_type ((cfg), sig->ret, &call->inst);
 
-       if (MONO_TYPE_ISSTRUCT (sig->ret)) {
+       if (tail) {
+               if (MONO_TYPE_ISSTRUCT (sig->ret)) {
+                       call->vret_var = cfg->vret_addr;
+                       //g_assert_not_reached ();
+               }
+       } else if (MONO_TYPE_ISSTRUCT (sig->ret)) {
                MonoInst *temp = mono_compile_create_var (cfg, sig->ret, OP_LOCAL);
                MonoInst *loada;
 
@@ -2155,7 +2181,14 @@ mono_emit_call_args (MonoCompile *cfg, MonoMethodSignature *sig,
        }
 #endif
 
+#ifdef ENABLE_LLVM
+       if (COMPILE_LLVM (cfg))
+               mono_llvm_emit_call (cfg, call);
+       else
+               mono_arch_emit_call (cfg, call);
+#else
        mono_arch_emit_call (cfg, call);
+#endif
 
        cfg->param_area = MAX (cfg->param_area, call->stack_usage);
        cfg->flags |= MONO_CFG_HAS_CALLS;
@@ -2166,7 +2199,7 @@ mono_emit_call_args (MonoCompile *cfg, MonoMethodSignature *sig,
 inline static MonoInst*
 mono_emit_calli (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args, MonoInst *addr)
 {
-       MonoCallInst *call = mono_emit_call_args (cfg, sig, args, TRUE, FALSE);
+       MonoCallInst *call = mono_emit_call_args (cfg, sig, args, TRUE, FALSE, FALSE);
 
        call->inst.sreg1 = addr->dreg;
 
@@ -2190,6 +2223,7 @@ mono_emit_rgctx_calli (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **ar
        if (rgctx_arg) {
                mono_call_inst_add_outarg_reg (cfg, call, rgctx_reg, MONO_ARCH_RGCTX_REG, FALSE);
                cfg->uses_rgctx_reg = TRUE;
+               call->rgctx_reg = TRUE;
        }
        return (MonoInst*)call;
 #else
@@ -2198,12 +2232,17 @@ mono_emit_rgctx_calli (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **ar
 #endif
 }
 
+static MonoInst*
+emit_get_rgctx_method (MonoCompile *cfg, int context_used, MonoMethod *cmethod, int rgctx_type);
+
 static MonoInst*
 mono_emit_method_call_full (MonoCompile *cfg, MonoMethod *method, MonoMethodSignature *sig,
                                                        MonoInst **args, MonoInst *this, MonoInst *imt_arg)
 {
+       gboolean might_be_remote;
        gboolean virtual = this != NULL;
        gboolean enable_for_aot = TRUE;
+       int context_used;
        MonoCallInst *call;
 
        if (method->string_ctor) {
@@ -2215,15 +2254,27 @@ mono_emit_method_call_full (MonoCompile *cfg, MonoMethod *method, MonoMethodSign
                sig = ctor_sig;
        }
 
-       call = mono_emit_call_args (cfg, sig, args, FALSE, virtual);
+       might_be_remote = this && sig->hasthis &&
+               (method->klass->marshalbyref || method->klass == mono_defaults.object_class) &&
+               !(method->flags & METHOD_ATTRIBUTE_VIRTUAL) && !MONO_CHECK_THIS (this);
+
+       context_used = mono_method_check_context_used (method);
+       if (might_be_remote && context_used) {
+               MonoInst *addr;
 
-       if (this && sig->hasthis && 
-           (method->klass->marshalbyref || method->klass == mono_defaults.object_class) && 
-           !(method->flags & METHOD_ATTRIBUTE_VIRTUAL) && !MONO_CHECK_THIS (this)) {
+               g_assert (cfg->generic_sharing_context);
+
+               addr = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK);
+
+               return mono_emit_calli (cfg, sig, args, addr);
+       }
+
+       call = mono_emit_call_args (cfg, sig, args, FALSE, virtual, FALSE);
+
+       if (might_be_remote)
                call->method = mono_marshal_get_remoting_invoke_with_check (method);
-       } else {
+       else
                call->method = method;
-       }
        call->inst.flags |= MONO_INST_HAS_METHOD;
        call->inst.inst_left = this;
 
@@ -2348,6 +2399,7 @@ mono_emit_rgctx_method_call_full (MonoCompile *cfg, MonoMethod *method, MonoMeth
 #ifdef MONO_ARCH_RGCTX_REG
                mono_call_inst_add_outarg_reg (cfg, call, rgctx_reg, MONO_ARCH_RGCTX_REG, FALSE);
                cfg->uses_rgctx_reg = TRUE;
+               call->rgctx_reg = TRUE;
 #else
                NOT_IMPLEMENTED;
 #endif
@@ -2370,7 +2422,7 @@ mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature
 
        g_assert (sig);
 
-       call = mono_emit_call_args (cfg, sig, args, FALSE, FALSE);
+       call = mono_emit_call_args (cfg, sig, args, FALSE, FALSE, FALSE);
        call->fptr = func;
 
        MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
@@ -2411,6 +2463,48 @@ mono_emit_abs_call (MonoCompile *cfg, MonoJumpInfoType patch_type, gconstpointer
        ((MonoCallInst*)ins)->fptr_is_patch = TRUE;
        return ins;
 }
+static MonoInst*
+mono_emit_widen_call_res (MonoCompile *cfg, MonoInst *ins, MonoMethodSignature *fsig)
+{
+       if (!MONO_TYPE_IS_VOID (fsig->ret)) {
+               if ((fsig->pinvoke || LLVM_ENABLED) && !fsig->ret->byref) {
+                       int widen_op = -1;
+
+                       /* 
+                        * Native code might return non register sized integers 
+                        * without initializing the upper bits.
+                        */
+                       switch (mono_type_to_load_membase (cfg, fsig->ret)) {
+                       case OP_LOADI1_MEMBASE:
+                               widen_op = OP_ICONV_TO_I1;
+                               break;
+                       case OP_LOADU1_MEMBASE:
+                               widen_op = OP_ICONV_TO_U1;
+                               break;
+                       case OP_LOADI2_MEMBASE:
+                               widen_op = OP_ICONV_TO_I2;
+                               break;
+                       case OP_LOADU2_MEMBASE:
+                               widen_op = OP_ICONV_TO_U2;
+                               break;
+                       default:
+                               break;
+                       }
+
+                       if (widen_op != -1) {
+                               int dreg = alloc_preg (cfg);
+                               MonoInst *widen;
+
+                               EMIT_NEW_UNALU (cfg, widen, widen_op, dreg, ins->dreg);
+                               widen->type = ins->type;
+                               ins = widen;
+                       }
+               }
+       }
+
+       return ins;
+}
 
 static MonoMethod*
 get_memcpy_method (void)
@@ -2613,6 +2707,36 @@ emit_get_rgctx_field (MonoCompile *cfg, int context_used,
        return emit_rgctx_fetch (cfg, rgctx, entry);
 }
 
+static void
+emit_generic_class_init (MonoCompile *cfg, MonoClass *klass)
+{
+       MonoInst *vtable_arg;
+       MonoCallInst *call;
+       int context_used = 0;
+
+       if (cfg->generic_sharing_context)
+               context_used = mono_class_check_context_used (klass);
+
+       if (context_used) {
+               vtable_arg = emit_get_rgctx_klass (cfg, context_used,
+                                                                                  klass, MONO_RGCTX_INFO_VTABLE);
+       } else {
+               MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
+
+               if (!vtable)
+                       return;
+               EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
+       }
+
+       call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_GENERIC_CLASS_INIT, NULL, helper_sig_generic_class_init_trampoline, &vtable_arg);
+#ifdef MONO_ARCH_VTABLE_REG
+       mono_call_inst_add_outarg_reg (cfg, call, vtable_arg->dreg, MONO_ARCH_VTABLE_REG, FALSE);
+       cfg->uses_vtable_reg = TRUE;
+#else
+       NOT_IMPLEMENTED;
+#endif
+}
+
 static void
 mini_emit_check_array_type (MonoCompile *cfg, MonoInst *obj, MonoClass *array_class)
 {
@@ -2782,7 +2906,11 @@ handle_alloc (MonoCompile *cfg, MonoClass *klass, gboolean for_box)
                return mono_emit_jit_icall (cfg, mono_helper_newobj_mscorlib, iargs);
        } else {
                MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
+#ifdef MONO_CROSS_COMPILE
+               MonoMethod *managed_alloc = NULL;
+#else
                MonoMethod *managed_alloc = mono_gc_get_managed_allocator (vtable, for_box);
+#endif
                gboolean pass_lw;
 
                if (managed_alloc) {
@@ -3261,6 +3389,9 @@ handle_array_new (MonoCompile *cfg, int rank, MonoInst **sp, unsigned char *ip)
 
        cfg->flags |= MONO_CFG_HAS_VARARGS;
 
+       /* mono_array_new_va () needs a vararg calling convention */
+       cfg->disable_llvm = TRUE;
+
        /* FIXME: This uses info->sig, but it should use the signature of the wrapper */
        return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, sp);
 }
@@ -3458,7 +3589,7 @@ mini_emit_ldelema_1_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, Mono
 
        MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index2_reg);
 
-#if defined(__i386__) || defined(__x86_64__)
+#if defined(TARGET_X86) || defined(TARGET_AMD64)
        if (size == 1 || size == 2 || size == 4 || size == 8) {
                static const int fast_log2 [] = { 1, 0, 1, -1, 2, -1, -1, -1, 3 };
 
@@ -3591,7 +3722,7 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign
 #endif 
                        MONO_EMIT_BOUNDS_CHECK (cfg, args [0]->dreg, MonoString, length, index_reg);
 
-#if defined(__i386__) || defined(__x86_64__)
+#if defined(TARGET_X86) || defined(TARGET_AMD64)
                        EMIT_NEW_X86_LEA (cfg, ins, args [0]->dreg, index_reg, 1, G_STRUCT_OFFSET (MonoString, chars));
                        add_reg = ins->dreg;
                        /* Avoid a warning */
@@ -3835,17 +3966,16 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign
 #ifdef MONO_ARCH_HAVE_ATOMIC_EXCHANGE
                if (strcmp (cmethod->name, "Exchange") == 0) {
                        guint32 opcode;
+                       gboolean is_ref = fsig->params [0]->type == MONO_TYPE_OBJECT;
 
                        if (fsig->params [0]->type == MONO_TYPE_I4)
                                opcode = OP_ATOMIC_EXCHANGE_I4;
 #if SIZEOF_REGISTER == 8
-                       else if ((fsig->params [0]->type == MONO_TYPE_I8) ||
-                                        (fsig->params [0]->type == MONO_TYPE_I) ||
-                                        (fsig->params [0]->type == MONO_TYPE_OBJECT))
+                       else if (is_ref || (fsig->params [0]->type == MONO_TYPE_I8) ||
+                                       (fsig->params [0]->type == MONO_TYPE_I))
                                opcode = OP_ATOMIC_EXCHANGE_I8;
 #else
-                       else if ((fsig->params [0]->type == MONO_TYPE_I) ||
-                                        (fsig->params [0]->type == MONO_TYPE_OBJECT))
+                       else if (is_ref || (fsig->params [0]->type == MONO_TYPE_I))
                                opcode = OP_ATOMIC_EXCHANGE_I4;
 #endif
                        else
@@ -3872,30 +4002,53 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign
                        default:
                                g_assert_not_reached ();
                        }
+
+#if HAVE_WRITE_BARRIERS
+                       if (is_ref) {
+                               MonoMethod *write_barrier = mono_gc_get_write_barrier ();
+                               mono_emit_method_call (cfg, write_barrier, &args [0], NULL);
+                       }
+#endif
                }
 #endif /* MONO_ARCH_HAVE_ATOMIC_EXCHANGE */
  
-#ifdef MONO_ARCH_HAVE_ATOMIC_CAS_IMM
-               /* 
-                * Can't implement CompareExchange methods this way since they have
-                * three arguments. We can implement one of the common cases, where the new
-                * value is a constant.
-                */
+#ifdef MONO_ARCH_HAVE_ATOMIC_CAS
                if ((strcmp (cmethod->name, "CompareExchange") == 0)) {
-                       if ((fsig->params [1]->type == MONO_TYPE_I4 ||
-                                               (sizeof (gpointer) == 4 && fsig->params [1]->type == MONO_TYPE_I))
-                                       && args [2]->opcode == OP_ICONST) {
-                               MONO_INST_NEW (cfg, ins, OP_ATOMIC_CAS_IMM_I4);
+                       int size = 0;
+                       gboolean is_ref = MONO_TYPE_IS_REFERENCE (fsig->params [1]);
+                       if (fsig->params [1]->type == MONO_TYPE_I4)
+                               size = 4;
+                       else if (is_ref || fsig->params [1]->type == MONO_TYPE_I)
+                               size = sizeof (gpointer);
+                       else if (sizeof (gpointer) == 8 && fsig->params [1]->type == MONO_TYPE_I4)
+                               size = 8;
+                       if (size == 4) {
+                               MONO_INST_NEW (cfg, ins, OP_ATOMIC_CAS_I4);
                                ins->dreg = alloc_ireg (cfg);
                                ins->sreg1 = args [0]->dreg;
                                ins->sreg2 = args [1]->dreg;
-                               ins->backend.data = GINT_TO_POINTER (args [2]->inst_c0);
+                               ins->sreg3 = args [2]->dreg;
                                ins->type = STACK_I4;
                                MONO_ADD_INS (cfg->cbb, ins);
+                       } else if (size == 8) {
+                               MONO_INST_NEW (cfg, ins, OP_ATOMIC_CAS_I8);
+                               ins->dreg = alloc_ireg (cfg);
+                               ins->sreg1 = args [0]->dreg;
+                               ins->sreg2 = args [1]->dreg;
+                               ins->sreg3 = args [2]->dreg;
+                               ins->type = STACK_I8;
+                               MONO_ADD_INS (cfg->cbb, ins);
+                       } else {
+                               /* g_assert_not_reached (); */
+                       }
+#if HAVE_WRITE_BARRIERS
+                       if (is_ref) {
+                               MonoMethod *write_barrier = mono_gc_get_write_barrier ();
+                               mono_emit_method_call (cfg, write_barrier, &args [0], NULL);
                        }
-                       /* The I8 case is hard to detect, since the arg might be a conv.i8 (iconst) tree */
+#endif
                }
-#endif /* MONO_ARCH_HAVE_ATOMIC_CAS_IMM */
+#endif /* MONO_ARCH_HAVE_ATOMIC_CAS */
 
                if (ins)
                        return ins;
@@ -3947,7 +4100,11 @@ mini_redirect_call (MonoCompile *cfg, MonoMethod *method,
                if (strcmp (method->name, "InternalAllocateStr") == 0) {
                        MonoInst *iargs [2];
                        MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
+#ifdef MONO_CROSS_COMPILE
+                       MonoMethod *managed_alloc = NULL;
+#else
                        MonoMethod *managed_alloc = mono_gc_get_managed_allocator (vtable, FALSE);
+#endif
                        if (!managed_alloc)
                                return NULL;
                        EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
@@ -4460,53 +4617,83 @@ emit_throw_method_access_exception (MonoCompile *cfg, MonoMethod *caller, MonoMe
 }
 
 static MonoMethod*
-verification_exception (void)
+field_access_exception (void)
 {
        static MonoMethod *method = NULL;
 
        if (!method) {
                MonoSecurityManager *secman = mono_security_manager_get_methods ();
                method = mono_class_get_method_from_name (secman->securitymanager,
-                                                         "VerificationException", 0);
+                                                         "FieldAccessException", 2);
        }
        g_assert (method);
        return method;
 }
 
 static void
-emit_throw_verification_exception (MonoCompile *cfg, MonoBasicBlock *bblock, unsigned char *ip)
+emit_throw_field_access_exception (MonoCompile *cfg, MonoMethod *caller, MonoClassField *field,
+                                   MonoBasicBlock *bblock, unsigned char *ip)
 {
-       MonoMethod *thrower = verification_exception ();
+       MonoMethod *thrower = field_access_exception ();
+       MonoInst *args [2];
 
-       mono_emit_method_call (cfg, thrower, NULL, NULL);
+       EMIT_NEW_METHODCONST (cfg, args [0], caller);
+       EMIT_NEW_METHODCONST (cfg, args [1], field);
+       mono_emit_method_call (cfg, thrower, args, NULL);
+}
+
+/*
+ * Return the original method is a wrapper is specified. We can only access 
+ * the custom attributes from the original method.
+ */
+static MonoMethod*
+get_original_method (MonoMethod *method)
+{
+       if (method->wrapper_type == MONO_WRAPPER_NONE)
+               return method;
+
+       /* native code (which is like Critical) can call any managed method XXX FIXME XXX to validate all usages */
+       if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED)
+               return NULL;
+
+       /* in other cases we need to find the original method */
+       return mono_marshal_method_from_wrapper (method);
 }
 
 static void
-ensure_method_is_allowed_to_call_method (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee,
-                                        MonoBasicBlock *bblock, unsigned char *ip)
+ensure_method_is_allowed_to_access_field (MonoCompile *cfg, MonoMethod *caller, MonoClassField *field,
+                                         MonoBasicBlock *bblock, unsigned char *ip)
 {
-       MonoSecurityCoreCLRLevel caller_level = mono_security_core_clr_method_level (caller, TRUE);
-       MonoSecurityCoreCLRLevel callee_level = mono_security_core_clr_method_level (callee, TRUE);
-       gboolean is_safe = TRUE;
+       /* there's no restriction to access Transparent or SafeCritical fields, so we only check calls to Critical methods */
+       if (mono_security_core_clr_class_level (mono_field_get_parent (field)) != MONO_SECURITY_CORE_CLR_CRITICAL)
+               return;
 
-       if (!(caller_level >= callee_level ||
-                       caller_level == MONO_SECURITY_CORE_CLR_SAFE_CRITICAL ||
-                       callee_level == MONO_SECURITY_CORE_CLR_SAFE_CRITICAL)) {
-               is_safe = FALSE;
-       }
+       /* we can't get the coreclr security level on wrappers since they don't have the attributes */
+       caller = get_original_method (caller);
+       if (!caller)
+               return;
 
-       if (!is_safe)
-               emit_throw_method_access_exception (cfg, caller, callee, bblock, ip);
+       /* caller is Critical! only SafeCritical and Critical callers can access the field, so we throw if caller is Transparent */
+       if (mono_security_core_clr_method_level (caller, TRUE) == MONO_SECURITY_CORE_CLR_TRANSPARENT)
+               emit_throw_field_access_exception (cfg, caller, field, bblock, ip);
 }
 
-static gboolean
-method_is_safe (MonoMethod *method)
+static void
+ensure_method_is_allowed_to_call_method (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee,
+                                        MonoBasicBlock *bblock, unsigned char *ip)
 {
-       /*
-       if (strcmp (method->name, "unsafeMethod") == 0)
-               return FALSE;
-       */
-       return TRUE;
+       /* there's no restriction to call Transparent or SafeCritical code, so we only check calls to Critical methods */
+       if (mono_security_core_clr_method_level (callee, TRUE) != MONO_SECURITY_CORE_CLR_CRITICAL)
+               return;
+
+       /* we can't get the coreclr security level on wrappers since they don't have the attributes */
+       caller = get_original_method (caller);
+       if (!caller)
+               return;
+
+       /* caller is Critical! only SafeCritical and Critical callers can call it, so we throw if the caller is Transparent */
+       if (mono_security_core_clr_method_level (caller, TRUE) == MONO_SECURITY_CORE_CLR_TRANSPARENT)
+               emit_throw_method_access_exception (cfg, caller, callee, bblock, ip);
 }
 
 /*
@@ -4550,7 +4737,7 @@ initialize_array_data (MonoMethod *method, gboolean aot, unsigned char *ip, Mono
                case MONO_TYPE_U1:
                        size = 1; break;
                /* we need to swap on big endian, so punt. Should we handle R4 and R8 as well? */
-#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+#if TARGET_BYTE_ORDER == G_LITTLE_ENDIAN
                case MONO_TYPE_CHAR:
                case MONO_TYPE_I2:
                case MONO_TYPE_U2:
@@ -5125,6 +5312,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
        GSList *class_inits = NULL;
        gboolean dont_verify, dont_verify_stloc, readonly = FALSE;
        int context_used;
+       gboolean init_locals;
 
        /* serialization and xdomain stuff may need access to private fields and methods */
        dont_verify = method->klass->image->assembly->corlib_internal? TRUE: FALSE;
@@ -5150,6 +5338,13 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
        cfg->cil_start = ip;
        end = ip + header->code_size;
        mono_jit_stats.cil_code_size += header->code_size;
+       init_locals = header->init_locals;
+
+       /* 
+        * Methods without init_locals set could cause asserts in various passes
+        * (#497220).
+        */
+       init_locals = TRUE;
 
        method_definition = method;
        while (method_definition->is_inflated) {
@@ -5382,7 +5577,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                }
        }
        
-       if ((header->init_locals || (cfg->method == method && (cfg->opt & MONO_OPT_SHARED))) || cfg->compile_aot || security || pinvoke) {
+       if ((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 */
                NEW_BBLOCK (cfg, init_localsbb);
                cfg->bb_init = init_localsbb;
@@ -5443,8 +5638,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                }
                        }
                }
-               if (!method_is_safe (method))
-                       emit_throw_verification_exception (cfg, bblock, ip);
        }
 
        if (header->code_size == 0)
@@ -5556,7 +5749,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        cfg->coverage_info->data [cil_offset].cil_code = ip;
 
                        /* TODO: Use an increment here */
-#if defined(__i386__)
+#if defined(TARGET_X86)
                        MONO_INST_NEW (cfg, ins, OP_STORE_MEM_IMM);
                        ins->inst_p0 = &(cfg->coverage_info->data [cil_offset].count);
                        ins->inst_imm = 1;
@@ -5744,38 +5937,76 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        break;
                case CEE_LDC_R4: {
                        float *f;
+                       gboolean use_aotconst = FALSE;
+
+#ifdef TARGET_POWERPC
+                       /* FIXME: Clean this up */
+                       if (cfg->compile_aot)
+                               use_aotconst = TRUE;
+#endif
+
                        /* FIXME: we should really allocate this only late in the compilation process */
                        f = mono_domain_alloc (cfg->domain, sizeof (float));
                        CHECK_OPSIZE (5);
                        CHECK_STACK_OVF (1);
-                       MONO_INST_NEW (cfg, ins, OP_R4CONST);
-                       ins->type = STACK_R8;
-                       ins->dreg = alloc_dreg (cfg, STACK_R8);
+
+                       if (use_aotconst) {
+                               MonoInst *cons;
+                               int dreg;
+
+                               EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R4, f);
+
+                               dreg = alloc_freg (cfg);
+                               EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR4_MEMBASE, dreg, cons->dreg, 0);
+                               ins->type = STACK_R8;
+                       } else {
+                               MONO_INST_NEW (cfg, ins, OP_R4CONST);
+                               ins->type = STACK_R8;
+                               ins->dreg = alloc_dreg (cfg, STACK_R8);
+                               ins->inst_p0 = f;
+                               MONO_ADD_INS (bblock, ins);
+                       }
                        ++ip;
                        readr4 (ip, f);
-                       ins->inst_p0 = f;
-                       MONO_ADD_INS (bblock, ins);
-                       
                        ip += 4;
                        *sp++ = ins;                    
                        break;
                }
                case CEE_LDC_R8: {
                        double *d;
+                       gboolean use_aotconst = FALSE;
+
+#ifdef TARGET_POWERPC
+                       /* FIXME: Clean this up */
+                       if (cfg->compile_aot)
+                               use_aotconst = TRUE;
+#endif
+
                        /* FIXME: we should really allocate this only late in the compilation process */
                        d = mono_domain_alloc (cfg->domain, sizeof (double));
                        CHECK_OPSIZE (9);
                        CHECK_STACK_OVF (1);
-                       MONO_INST_NEW (cfg, ins, OP_R8CONST);
-                       ins->type = STACK_R8;
-                       ins->dreg = alloc_dreg (cfg, STACK_R8);
+
+                       if (use_aotconst) {
+                               MonoInst *cons;
+                               int dreg;
+
+                               EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R8, d);
+
+                               dreg = alloc_freg (cfg);
+                               EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR8_MEMBASE, dreg, cons->dreg, 0);
+                               ins->type = STACK_R8;
+                       } else {
+                               MONO_INST_NEW (cfg, ins, OP_R8CONST);
+                               ins->type = STACK_R8;
+                               ins->dreg = alloc_dreg (cfg, STACK_R8);
+                               ins->inst_p0 = d;
+                               MONO_ADD_INS (bblock, ins);
+                       }
                        ++ip;
                        readr8 (ip, d);
-                       ins->inst_p0 = d;
-                       MONO_ADD_INS (bblock, ins);
-
                        ip += 8;
-                       *sp++ = ins;                    
+                       *sp++ = ins;
                        break;
                }
                case CEE_DUP: {
@@ -5803,7 +6034,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        ip++;
                        --sp;
 
-#ifdef __i386__
+#ifdef TARGET_X86
                        if (sp [0]->type == STACK_R8)
                                /* we need to pop the value from the x86 FP stack */
                                MONO_EMIT_NEW_UNALU (cfg, OP_X86_FPOP, -1, sp [0]->dreg);
@@ -5830,7 +6061,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS)
                                CHECK_CFG_EXCEPTION;
 
-#ifdef __x86_64__
+#ifdef MONO_ARCH_USE_OP_TAIL_CALL
                        {
                                MonoMethodSignature *fsig = mono_method_signature (cmethod);
                                int i, n;
@@ -5879,6 +6110,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        gboolean pass_mrgctx = FALSE;
                        MonoInst *vtable_arg = NULL;
                        gboolean check_this = FALSE;
+                       gboolean supported_tail_call = FALSE;
 
                        CHECK_OPSIZE (5);
                        token = read32 (ip + 1);
@@ -6019,6 +6251,13 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        if (*ip != CEE_CALLI && check_call_signature (cfg, fsig, sp))
                                UNVERIFIED;
 
+                       /* 
+                        * If the callee is a shared method, then its static cctor
+                        * might not get called after the call was patched.
+                        */
+                       if (cfg->generic_sharing_context && cmethod && cmethod->klass != method->klass && cmethod->klass->generic_class && mono_method_is_generic_sharable_impl (cmethod, TRUE) && mono_class_needs_cctor_run (cmethod->klass, method)) {
+                               emit_generic_class_init (cfg, cmethod->klass);
+                       }
 
                        if (cmethod && ((cmethod->flags & METHOD_ATTRIBUTE_STATIC) || cmethod->klass->valuetype) &&
                                        (cmethod->klass->generic_class || cmethod->klass->generic_container)) {
@@ -6138,8 +6377,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                /* Prevent inlining of methods that contain indirect calls */
                                INLINE_FAILURE;
 
-#if MONO_ARCH_HAVE_GENERALIZED_IMT_THUNK
-                               if (cmethod->wrapper_type == MONO_WRAPPER_NONE) {
+#if MONO_ARCH_HAVE_GENERALIZED_IMT_THUNK && !defined(ENABLE_LLVM)
+                               if (cmethod->wrapper_type == MONO_WRAPPER_NONE && mono_use_imt) {
                                        g_assert (!imt_arg);
                                        if (context_used) {
                                                imt_arg = emit_get_rgctx_method (cfg, context_used,
@@ -6179,34 +6418,37 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                }
 
                                if (!MONO_TYPE_IS_VOID (fsig->ret))
-                                       *sp++ = ins;
+                                       *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
 
                                ip += 5;
                                ins_flag = 0;
                                break;
                        }
 
+#ifdef MONO_ARCH_USE_OP_TAIL_CALL
+                       supported_tail_call = cmethod && MONO_ARCH_USE_OP_TAIL_CALL (mono_method_signature (method), mono_method_signature (cmethod));
+#else
+                       supported_tail_call = cmethod && mono_metadata_signature_equal (mono_method_signature (method), mono_method_signature (cmethod)) && !MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->ret);
+#endif
+
                        /* Tail prefix */
                        /* FIXME: runtime generic context pointer for jumps? */
                        /* FIXME: handle this for generic sharing eventually */
-                       if ((ins_flag & MONO_INST_TAILCALL) && !cfg->generic_sharing_context && !vtable_arg && cmethod && (*ip == CEE_CALL) &&
-                                (mono_metadata_signature_equal (mono_method_signature (method), mono_method_signature (cmethod)))) {
+                       if ((ins_flag & MONO_INST_TAILCALL) && !cfg->generic_sharing_context && !vtable_arg && cmethod && (*ip == CEE_CALL) && supported_tail_call) {
                                MonoCallInst *call;
 
                                /* Prevent inlining of methods with tail calls (the call stack would be altered) */
                                INLINE_FAILURE;
 
+#ifdef MONO_ARCH_USE_OP_TAIL_CALL
+                               /* Handle tail calls similarly to calls */
+                               call = mono_emit_call_args (cfg, mono_method_signature (cmethod), sp, FALSE, FALSE, TRUE);
+#else
                                MONO_INST_NEW_CALL (cfg, call, OP_JMP);
                                call->tail_call = TRUE;
                                call->method = cmethod;
                                call->signature = mono_method_signature (cmethod);
 
-#ifdef __x86_64__
-                               /* Handle tail calls similarly to calls */
-                               call->inst.opcode = OP_TAILCALL;
-                               call->args = sp;
-                               mono_arch_emit_call (cfg, call);
-#else
                                /*
                                 * We implement tail calls by storing the actual arguments into the 
                                 * argument variables, then emitting a CEE_JMP.
@@ -6360,6 +6602,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        call = (MonoCallInst*)ins;
                                        mono_call_inst_add_outarg_reg (cfg, call, rgctx_reg, MONO_ARCH_RGCTX_REG, FALSE);
                                        cfg->uses_rgctx_reg = TRUE;
+                                       call->rgctx_reg = TRUE;
 #else
                                        NOT_IMPLEMENTED;
 #endif
@@ -6371,47 +6614,15 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                                 */
                                                ins = (MonoInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_ICALL_ADDR, addr->inst_p0, fsig, sp);
                                                NULLIFY_INS (addr);
+                                       } else if (addr->opcode == OP_GOT_ENTRY && addr->inst_right->inst_c1 == MONO_PATCH_INFO_ICALL_ADDR) {
+                                               ins = (MonoInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_ICALL_ADDR, addr->inst_right->inst_left, fsig, sp);
+                                               NULLIFY_INS (addr);
                                        } else {
                                                ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr);
                                        }
                                }
-                               if (!MONO_TYPE_IS_VOID (fsig->ret)) {
-                                       if (fsig->pinvoke && !fsig->ret->byref) {
-                                               int widen_op = -1;
-
-                                               /* 
-                                                * Native code might return non register sized integers 
-                                                * without initializing the upper bits.
-                                                */
-                                               switch (mono_type_to_load_membase (cfg, fsig->ret)) {
-                                               case OP_LOADI1_MEMBASE:
-                                                       widen_op = OP_ICONV_TO_I1;
-                                                       break;
-                                               case OP_LOADU1_MEMBASE:
-                                                       widen_op = OP_ICONV_TO_U1;
-                                                       break;
-                                               case OP_LOADI2_MEMBASE:
-                                                       widen_op = OP_ICONV_TO_I2;
-                                                       break;
-                                               case OP_LOADU2_MEMBASE:
-                                                       widen_op = OP_ICONV_TO_U2;
-                                                       break;
-                                               default:
-                                                       break;
-                                               }
-
-                                               if (widen_op != -1) {
-                                                       int dreg = alloc_preg (cfg);
-                                                       MonoInst *widen;
-
-                                                       EMIT_NEW_UNALU (cfg, widen, widen_op, dreg, ins->dreg);
-                                                       widen->type = ins->type;
-                                                       ins = widen;
-                                               }
-                                       }
-
-                                       *sp++ = ins;
-                               }
+                               if (!MONO_TYPE_IS_VOID (fsig->ret))
+                                       *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
 
                                ip += 5;
                                ins_flag = 0;
@@ -6459,7 +6670,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        ins = mini_redirect_call (cfg, cmethod, fsig, sp, virtual ? sp [0] : NULL);
                        if (ins) {
                                if (!MONO_TYPE_IS_VOID (fsig->ret))
-                                       *sp++ = ins;
+                                       *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
 
                                ip += 5;
                                ins_flag = 0;
@@ -6478,7 +6689,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        }
 
                        if (!MONO_TYPE_IS_VOID (fsig->ret))
-                               *sp++ = ins;
+                               *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
 
                        ip += 5;
                        ins_flag = 0;
@@ -6751,13 +6962,18 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        table->table_size = n;
 
                        use_op_switch = FALSE;
-#ifdef __arm__
+#ifdef TARGET_ARM
                        /* ARM implements SWITCH statements differently */
                        /* FIXME: Make it use the generic implementation */
                        if (!cfg->compile_aot)
                                use_op_switch = TRUE;
 #endif
-                       
+
+                       if (COMPILE_LLVM (cfg))
+                               use_op_switch = TRUE;
+
+                       cfg->cbb->has_jump_table = 1;
+
                        if (use_op_switch) {
                                MONO_INST_NEW (cfg, ins, OP_SWITCH);
                                ins->sreg1 = src1->dreg;
@@ -6840,21 +7056,19 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        CHECK_STACK (2);
                        sp -= 2;
 
+                       NEW_STORE_MEMBASE (cfg, ins, stind_to_store_membase (*ip), sp [0]->dreg, 0, sp [1]->dreg);
+                       ins->flags |= ins_flag;
+                       ins_flag = 0;
+                       MONO_ADD_INS (bblock, ins);
+
 #if HAVE_WRITE_BARRIERS
                        if (*ip == CEE_STIND_REF && method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER && !((sp [1]->opcode == OP_PCONST) && (sp [1]->inst_p0 == 0))) {
                                /* insert call to write barrier */
                                MonoMethod *write_barrier = mono_gc_get_write_barrier ();
                                mono_emit_method_call (cfg, write_barrier, sp, NULL);
-                               ins_flag = 0;
-                               ip++;
-                               break;
                        }
 #endif
 
-                       NEW_STORE_MEMBASE (cfg, ins, stind_to_store_membase (*ip), sp [0]->dreg, 0, sp [1]->dreg);
-                       ins->flags |= ins_flag;
-                       ins_flag = 0;
-                       MONO_ADD_INS (bblock, ins);
                        inline_costs += 1;
                        ++ip;
                        break;
@@ -6883,9 +7097,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        }
 
                        MONO_ADD_INS ((cfg)->cbb, (ins));
-                       *sp++ = ins;
 
-                       mono_decompose_opcode (cfg, ins);
+                       *sp++ = mono_decompose_opcode (cfg, ins);
                        ip++;
                        break;
                case CEE_ADD:
@@ -6938,9 +7151,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                }
                        }
                        MONO_ADD_INS ((cfg)->cbb, (ins));
-                       *sp++ = ins;
 
-                       mono_decompose_opcode (cfg, ins);
+                       *sp++ = mono_decompose_opcode (cfg, ins);
                        ip++;
                        break;
                case CEE_NEG:
@@ -7102,7 +7314,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                        /* Optimize the ldobj+stobj combination */
                        /* The reference case ends up being a load+store anyway */
-                       if (((ip [5] == CEE_STOBJ) && ip_in_bb (cfg, bblock, ip + 9) && read32 (ip + 6) == token) && !generic_class_is_reference_type (cfg, klass)) {
+                       if (((ip [5] == CEE_STOBJ) && ip_in_bb (cfg, bblock, ip + 5) && read32 (ip + 6) == token) && !generic_class_is_reference_type (cfg, klass)) {
                                CHECK_STACK (1);
 
                                sp --;
@@ -7400,8 +7612,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        INLINE_FAILURE;
                                        ins = mono_emit_rgctx_method_call_full (cfg, cmethod, fsig, sp,
                                                                                                                        callvirt_this_arg, NULL, vtable_arg);
-                                       if (mono_method_is_generic_sharable_impl (cmethod, TRUE) && ((MonoCallInst*)ins)->method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK)
-                                               GENERIC_SHARING_FAILURE (*ip);
                                }
                        }
 
@@ -7744,6 +7954,12 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                FIELD_ACCESS_FAILURE;
                        mono_class_init (klass);
 
+                       /* XXX this is technically required but, so far (SL2), no [SecurityCritical] types (not many exists) have
+                          any visible *instance* field  (in fact there's a single case for a static field in Marshal) XXX
+                       if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR)
+                               ensure_method_is_allowed_to_access_field (cfg, method, field, bblock, ip);
+                       */
+
                        foffset = klass->valuetype? field->offset - sizeof (MonoObject): field->offset;
                        if (*ip == CEE_STFLD) {
                                if (target_type_is_incompatible (cfg, field->type, sp [1]))
@@ -7774,6 +7990,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                } else {
                                        MonoInst *store;
 
+                                       EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, sp [0]->dreg, foffset, sp [1]->dreg);
+
 #if HAVE_WRITE_BARRIERS
                                if (mini_type_to_stind (cfg, field->type) == CEE_STIND_REF && !(sp [1]->opcode == OP_PCONST && sp [1]->inst_c0 == 0)) {
                                        /* insert call to write barrier */
@@ -7788,8 +8006,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                }
 #endif
 
-                                       EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, sp [0]->dreg, foffset, sp [1]->dreg);
-                                               
                                        store->flags |= ins_flag;
                                }
                                ins_flag = 0;
@@ -7805,7 +8021,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
                                EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
                                EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : field->offset);
-                               if ((cfg->opt & MONO_OPT_INLINE) && !MONO_TYPE_ISSTRUCT (mono_method_signature (wrapper)->ret)) {
+                               if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
                                        costs = inline_method (cfg, wrapper, mono_method_signature (wrapper), 
                                                                                   iargs, ip, cfg->real_offset, dont_inline, TRUE);
                                        bblock = cfg->cbb;
@@ -7877,6 +8093,10 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_field (method, field))
                                FIELD_ACCESS_FAILURE;
 
+                       /* if the class is Critical then transparent code cannot access it's fields */
+                       if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR)
+                               ensure_method_is_allowed_to_access_field (cfg, method, field, bblock, ip);
+
                        /*
                         * We can only support shared generic static
                         * field access on architectures where the
@@ -8389,9 +8609,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        ins->dreg = alloc_freg (cfg);
                        ins->type = STACK_R8;
                        MONO_ADD_INS (bblock, ins);
-                       *sp++ = ins;
 
-                       mono_decompose_opcode (cfg, ins);
+                       *sp++ = mono_decompose_opcode (cfg, ins);
 
                        ++ip;
                        break;
@@ -8571,7 +8790,13 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                                ins = emit_get_rgctx_klass (cfg, context_used,
                                                        tclass, MONO_RGCTX_INFO_REFLECTION_TYPE);
                                        } else if (cfg->compile_aot) {
-                                               EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, image, n, generic_context);
+                                               if (method->wrapper_type) {
+                                                       /* FIXME: n is not a normal token */
+                                                       cfg->disable_aot = TRUE;
+                                                       EMIT_NEW_PCONST (cfg, ins, NULL);
+                                               } else {
+                                                       EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, image, n, generic_context);
+                                               }
                                        } else {
                                                EMIT_NEW_PCONST (cfg, ins, mono_type_get_object (cfg->domain, handle));
                                        }
@@ -8708,6 +8933,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        MONO_INST_NEW (cfg, ins, OP_CALL_HANDLER);
                                        ins->inst_target_bb = tblock;
                                        MONO_ADD_INS (bblock, ins);
+                                       bblock->has_call_handler = 1;
                                }
                                g_list_free (handlers);
                        } 
@@ -9090,6 +9316,11 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
                                        if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
                                                MonoInst *target_ins;
+                                               MonoMethod *invoke;
+
+                                               invoke = mono_get_delegate_invoke (ctor_method->klass);
+                                               if (!invoke || !mono_method_signature (invoke))
+                                                       goto load_error;
 
                                                ip += 6;
                                                if (cfg->verbose_level > 3)
@@ -9105,12 +9336,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 #endif
 
                                if (context_used) {
-                                       if (needs_static_rgctx_invoke)
-                                               cmethod = mono_marshal_get_static_rgctx_invoke (cmethod);
-
                                        argconst = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD);
-                               } else if (needs_static_rgctx_invoke) {
-                                       EMIT_NEW_METHODCONST (cfg, argconst, mono_marshal_get_static_rgctx_invoke (cmethod));
                                } else {
                                        EMIT_NEW_METHODCONST (cfg, argconst, cmethod);
                                }
@@ -9248,7 +9474,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                MONO_ADD_INS (cfg->cbb, ins);
 
                                cfg->flags |= MONO_CFG_HAS_ALLOCA;
-                               if (header->init_locals)
+                               if (init_locals)
                                        ins->flags |= MONO_INST_INIT;
 
                                *sp++ = ins;
@@ -9460,10 +9686,16 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                MONO_ADD_INS (cfg->cbb, store);
        }
 
+#ifdef TARGET_POWERPC
+       if (cfg->compile_aot)
+               /* FIXME: The plt slots require a GOT var even if the method doesn't use it */
+               mono_get_got_var (cfg);
+#endif
+
        if (cfg->method == method && cfg->got_var)
                mono_emit_load_got_addr (cfg);
 
-       if (header->init_locals) {
+       if (init_locals) {
                MonoInst *store;
 
                cfg->cbb = init_localsbb;
@@ -9640,13 +9872,13 @@ mono_op_to_op_imm (int opcode)
        case OP_STOREI4_MEMBASE_REG:
                return OP_STOREI4_MEMBASE_IMM;
 
-#if defined(__i386__) || defined (__x86_64__)
+#if defined(TARGET_X86) || defined (TARGET_AMD64)
        case OP_X86_PUSH:
                return OP_X86_PUSH_IMM;
        case OP_X86_COMPARE_MEMBASE_REG:
                return OP_X86_COMPARE_MEMBASE_IMM;
 #endif
-#if defined(__x86_64__)
+#if defined(TARGET_AMD64)
        case OP_AMD64_ICOMPARE_MEMBASE_REG:
                return OP_AMD64_ICOMPARE_MEMBASE_IMM;
 #endif
@@ -9728,7 +9960,7 @@ int
 mono_load_membase_to_load_mem (int opcode)
 {
        // FIXME: Add a MONO_ARCH_HAVE_LOAD_MEM macro
-#if defined(__i386__) || defined(__x86_64__)
+#if defined(TARGET_X86) || defined(TARGET_AMD64)
        switch (opcode) {
        case OP_LOAD_MEMBASE:
                return OP_LOAD_MEM;
@@ -9753,7 +9985,7 @@ mono_load_membase_to_load_mem (int opcode)
 static inline int
 op_to_op_dest_membase (int store_opcode, int opcode)
 {
-#if defined(__i386__)
+#if defined(TARGET_X86)
        if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG)))
                return -1;
 
@@ -9788,7 +10020,7 @@ op_to_op_dest_membase (int store_opcode, int opcode)
        }
 #endif
 
-#if defined(__x86_64__)
+#if defined(TARGET_AMD64)
        if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG) || (store_opcode == OP_STOREI8_MEMBASE_REG)))
                return -1;
 
@@ -9849,7 +10081,7 @@ op_to_op_dest_membase (int store_opcode, int opcode)
 static inline int
 op_to_op_store_membase (int store_opcode, int opcode)
 {
-#if defined(__i386__) || defined(__x86_64__)
+#if defined(TARGET_X86) || defined(TARGET_AMD64)
        switch (opcode) {
        case OP_ICEQ:
                if (store_opcode == OP_STOREI1_MEMBASE_REG)
@@ -9866,7 +10098,7 @@ op_to_op_store_membase (int store_opcode, int opcode)
 static inline int
 op_to_op_src1_membase (int load_opcode, int opcode)
 {
-#ifdef __i386__
+#ifdef TARGET_X86
        /* FIXME: This has sign extension issues */
        /*
        if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
@@ -9888,7 +10120,7 @@ op_to_op_src1_membase (int load_opcode, int opcode)
        }
 #endif
 
-#ifdef __x86_64__
+#ifdef TARGET_AMD64
        /* FIXME: This has sign extension issues */
        /*
        if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
@@ -9928,7 +10160,7 @@ op_to_op_src1_membase (int load_opcode, int opcode)
 static inline int
 op_to_op_src2_membase (int load_opcode, int opcode)
 {
-#ifdef __i386__
+#ifdef TARGET_X86
        if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
                return -1;
        
@@ -9949,7 +10181,7 @@ op_to_op_src2_membase (int load_opcode, int opcode)
        }
 #endif
 
-#ifdef __x86_64__
+#ifdef TARGET_AMD64
        switch (opcode) {
        case OP_ICOMPARE:
                if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
@@ -10058,7 +10290,7 @@ mono_handle_global_vregs (MonoCompile *cfg)
 
                        g_assert (ins->opcode >= MONO_CEE_LAST);
 
-                       for (regindex = 0; regindex < 3; regindex ++) {
+                       for (regindex = 0; regindex < 4; regindex ++) {
                                int vreg;
 
                                if (regindex == 0) {
@@ -10071,15 +10303,21 @@ mono_handle_global_vregs (MonoCompile *cfg)
                                        if (regtype == ' ')
                                                continue;
                                        vreg = ins->sreg1;
-                               } else {
+                               } else if (regindex == 2) {
                                        regtype = spec [MONO_INST_SRC2];
                                        if (regtype == ' ')
                                                continue;
                                        vreg = ins->sreg2;
+                               } else if (regindex == 3) {
+                                       regtype = spec [MONO_INST_SRC3];
+                                       if (regtype == ' ')
+                                               continue;
+                                       vreg = ins->sreg3;
                                }
 
 #if SIZEOF_REGISTER == 4
-                               if (regtype == 'l') {
+                               /* In the LLVM case, the long opcodes are not decomposed */
+                               if (regtype == 'l' && !COMPILE_LLVM (cfg)) {
                                        /*
                                         * Since some instructions reference the original long vreg,
                                         * and some reference the two component vregs, it is quite hard
@@ -10151,7 +10389,7 @@ mono_handle_global_vregs (MonoCompile *cfg)
 #if SIZEOF_REGISTER == 8
                case STACK_I8:
 #endif
-#if !defined(__i386__) && !defined(MONO_ARCH_SOFT_FLOAT)
+#if !defined(TARGET_X86) && !defined(MONO_ARCH_SOFT_FLOAT)
                /* Enabling this screws up the fp stack on x86 */
                case STACK_R8:
 #endif
@@ -10351,8 +10589,9 @@ mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
                cfg->cbb = bb;
                MONO_BB_FOR_EACH_INS (bb, ins) {
                        const char *spec = INS_INFO (ins->opcode);
-                       int regtype, srcindex, sreg, tmp_reg, prev_dreg;
+                       int regtype, srcindex, sreg, tmp_reg, prev_dreg, num_sregs;
                        gboolean store, no_lvreg;
+                       int sregs [MONO_MAX_SRC_REGS];
 
                        if (G_UNLIKELY (cfg->verbose_level > 2))
                                mono_print_ins (ins);
@@ -10411,6 +10650,7 @@ mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
                                spec2 [MONO_INST_DEST] = ' ';
                                spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
                                spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
+                               spec2 [MONO_INST_SRC3] = ' ';
                                spec = spec2;
                        } else if (MONO_IS_STORE_MEMINDEX (ins))
                                g_assert_not_reached ();
@@ -10418,8 +10658,13 @@ mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
                                store = FALSE;
                        no_lvreg = FALSE;
 
-                       if (G_UNLIKELY (cfg->verbose_level > 2))
-                               printf ("\t %.3s %d %d %d\n", spec, ins->dreg, ins->sreg1, ins->sreg2);
+                       if (G_UNLIKELY (cfg->verbose_level > 2)) {
+                               printf ("\t %.3s %d", spec, ins->dreg);
+                               num_sregs = mono_inst_get_src_registers (ins, sregs);
+                               for (srcindex = 0; srcindex < 3; ++srcindex)
+                                       printf (" %d", sregs [srcindex]);
+                               printf ("\n");
+                       }
 
                        /***************/
                        /*    DREG     */
@@ -10492,6 +10737,7 @@ mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
                                                        ins->inst_imm = ins->inst_c0;
                                                        ins->inst_destbasereg = var->inst_basereg;
                                                        ins->inst_offset = var->inst_offset;
+                                                       spec = INS_INFO (ins->opcode);
                                                } else if (!lvreg && ((ins->opcode == OP_MOVE) || (ins->opcode == OP_FMOVE) || (ins->opcode == OP_LMOVE))) {
                                                        ins->opcode = store_opcode;
                                                        ins->inst_destbasereg = var->inst_basereg;
@@ -10507,6 +10753,7 @@ mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
                                                        spec2 [MONO_INST_DEST] = ' ';
                                                        spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
                                                        spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
+                                                       spec2 [MONO_INST_SRC3] = ' ';
                                                        spec = spec2;
                                                } else if (!lvreg && (op_to_op_store_membase (store_opcode, ins->opcode) != -1)) {
                                                        // FIXME: The backends expect the base reg to be in inst_basereg
@@ -10545,9 +10792,10 @@ mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
                        /************/
                        /*  SREGS   */
                        /************/
-                       for (srcindex = 0; srcindex < 2; ++srcindex) {
-                               regtype = spec [(srcindex == 0) ? MONO_INST_SRC1 : MONO_INST_SRC2];
-                               sreg = srcindex == 0 ? ins->sreg1 : ins->sreg2;
+                       num_sregs = mono_inst_get_src_registers (ins, sregs);
+                       for (srcindex = 0; srcindex < 3; ++srcindex) {
+                               regtype = spec [MONO_INST_SRC1 + srcindex];
+                               sreg = sregs [srcindex];
 
                                g_assert (((sreg == -1) && (regtype == ' ')) || ((sreg != -1) && (regtype != ' ')));
                                if ((sreg != -1) && get_vreg_to_inst (cfg, sreg)) {
@@ -10557,12 +10805,10 @@ mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
                                        guint32 load_opcode;
 
                                        if (var->opcode == OP_REGVAR) {
-                                               if (srcindex == 0)
-                                                       ins->sreg1 = var->dreg;
-                                               else
-                                                       ins->sreg2 = var->dreg;
-                                               live_range_end [var->dreg] = use_ins;
-                                               live_range_end_bb [var->dreg] = bb;
+                                               sregs [srcindex] = var->dreg;
+                                               //mono_inst_set_src_registers (ins, sregs);
+                                               live_range_end [sreg] = use_ins;
+                                               live_range_end_bb [sreg] = bb;
                                                continue;
                                        }
 
@@ -10573,24 +10819,26 @@ mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
                                        g_assert (load_opcode != OP_LOADV_MEMBASE);
 
                                        if (vreg_to_lvreg [sreg]) {
+                                               g_assert (vreg_to_lvreg [sreg] != -1);
+
                                                /* The variable is already loaded to an lvreg */
                                                if (G_UNLIKELY (cfg->verbose_level > 2))
                                                        printf ("\t\tUse lvreg R%d for R%d.\n", vreg_to_lvreg [sreg], sreg);
-                                               if (srcindex == 0)
-                                                       ins->sreg1 = vreg_to_lvreg [sreg];
-                                               else
-                                                       ins->sreg2 = vreg_to_lvreg [sreg];
+                                               sregs [srcindex] = vreg_to_lvreg [sreg];
+                                               //mono_inst_set_src_registers (ins, sregs);
                                                continue;
                                        }
 
                                        /* Try to fuse the load into the instruction */
                                        if ((srcindex == 0) && (op_to_op_src1_membase (load_opcode, ins->opcode) != -1)) {
                                                ins->opcode = op_to_op_src1_membase (load_opcode, ins->opcode);
-                                               ins->inst_basereg = var->inst_basereg;
+                                               sregs [0] = var->inst_basereg;
+                                               //mono_inst_set_src_registers (ins, sregs);
                                                ins->inst_offset = var->inst_offset;
                                        } else if ((srcindex == 1) && (op_to_op_src2_membase (load_opcode, ins->opcode) != -1)) {
                                                ins->opcode = op_to_op_src2_membase (load_opcode, ins->opcode);
-                                               ins->sreg2 = var->inst_basereg;
+                                               sregs [1] = var->inst_basereg;
+                                               //mono_inst_set_src_registers (ins, sregs);
                                                ins->inst_offset = var->inst_offset;
                                        } else {
                                                if (MONO_IS_REAL_MOVE (ins)) {
@@ -10610,16 +10858,15 @@ mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
                                                                         */
                                                                        sreg = ins->dreg;
                                                                }
+                                                               g_assert (sreg != -1);
                                                                vreg_to_lvreg [var->dreg] = sreg;
                                                                g_assert (lvregs_len < 1024);
                                                                lvregs [lvregs_len ++] = var->dreg;
                                                        }
                                                }
 
-                                               if (srcindex == 0)
-                                                       ins->sreg1 = sreg;
-                                               else
-                                                       ins->sreg2 = sreg;
+                                               sregs [srcindex] = sreg;
+                                               //mono_inst_set_src_registers (ins, sregs);
 
                                                if (regtype == 'l') {
                                                        NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, sreg + 2, var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET);
@@ -10644,8 +10891,10 @@ mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
                                        }
                                }
                        }
+                       mono_inst_set_src_registers (ins, sregs);
 
                        if (dest_has_lvreg) {
+                               g_assert (ins->dreg != -1);
                                vreg_to_lvreg [prev_dreg] = ins->dreg;
                                g_assert (lvregs_len < 1024);
                                lvregs [lvregs_len ++] = prev_dreg;
@@ -10663,6 +10912,9 @@ mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
                                for (i = 0; i < lvregs_len; i++)
                                        vreg_to_lvreg [lvregs [i]] = 0;
                                lvregs_len = 0;
+                       } else if (ins->opcode == OP_NOP) {
+                               ins->dreg = -1;
+                               MONO_INST_NULLIFY_SREGS (ins);
                        }
 
                        if (cfg->verbose_level > 2)
@@ -10682,11 +10934,13 @@ mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
                if (live_range_start [vreg]) {
                        MONO_INST_NEW (cfg, ins, OP_LIVERANGE_START);
                        ins->inst_c0 = i;
+                       ins->inst_c1 = vreg;
                        mono_bblock_insert_after_ins (live_range_start_bb [vreg], live_range_start [vreg], ins);
                }
                if (live_range_end [vreg]) {
                        MONO_INST_NEW (cfg, ins, OP_LIVERANGE_END);
                        ins->inst_c0 = i;
+                       ins->inst_c1 = vreg;
                        mono_bblock_insert_after_ins (live_range_end_bb [vreg], live_range_end [vreg], ins);
                }
        }