2005-05-22 Zoltan Varga <vargaz@freemail.hu>
[mono.git] / mono / mini / mini.c
index 98efdb1291e039993ed2a83e37b1d2a2e1a9c88c..1a4cce2e10f318b9bea5098259f505540050f203 100644 (file)
@@ -49,6 +49,7 @@
 #include <mono/metadata/monitor.h>
 #include <mono/metadata/security-manager.h>
 #include <mono/utils/mono-math.h>
+#include <mono/utils/mono-compiler.h>
 #include <mono/os/gc_wrapper.h>
 
 #include "mini.h"
@@ -98,6 +99,7 @@ static MonoMethodSignature *helper_sig_compile_virt = NULL;
 static MonoMethodSignature *helper_sig_obj_ptr = NULL;
 static MonoMethodSignature *helper_sig_obj_ptr_ptr = NULL;
 static MonoMethodSignature *helper_sig_obj_obj_ptr_ptr = NULL;
+static MonoMethodSignature *helper_sig_obj_obj_obj_ptr = NULL;
 static MonoMethodSignature *helper_sig_obj_void = NULL;
 static MonoMethodSignature *helper_sig_ptr_void = NULL;
 static MonoMethodSignature *helper_sig_void_void = NULL;
@@ -112,9 +114,6 @@ static MonoMethodSignature *helper_sig_ptr_ptr_ptr_ptr = NULL;
 static MonoMethodSignature *helper_sig_ptr_obj = NULL;
 static MonoMethodSignature *helper_sig_ptr_obj_int = NULL;
 static MonoMethodSignature *helper_sig_ptr_int = NULL;
-static MonoMethodSignature *helper_sig_initobj = NULL;
-static MonoMethodSignature *helper_sig_memcpy = NULL;
-static MonoMethodSignature *helper_sig_memset = NULL;
 static MonoMethodSignature *helper_sig_ulong_double = NULL;
 static MonoMethodSignature *helper_sig_long_double = NULL;
 static MonoMethodSignature *helper_sig_double_long = NULL;
@@ -148,6 +147,16 @@ static MonoCodeManager *global_codeman = NULL;
 
 static GHashTable *jit_icall_name_hash = NULL;
 
+static MonoDebugOptions debug_options;
+
+/*
+ * Address of the trampoline code.  This is used by the debugger to check
+ * whether a method is a trampoline.
+ */
+guint8 *mono_generic_trampoline_code = NULL;
+
+static guint8* trampoline_code [MONO_TRAMPOLINE_NUM];
+
 gboolean
 mono_running_on_valgrind (void)
 {
@@ -176,7 +185,7 @@ get_method_from_ip (void *ip)
                return NULL;
        }
        method = mono_method_full_name (ji->method, TRUE);
-       source = mono_debug_source_location_from_address (ji->method, (int) ip, NULL, domain);
+       source = mono_debug_source_location_from_address (ji->method, (guint32)((guint8*)ip - (guint8*)ji->code_start), NULL, domain);
 
        res = g_strdup_printf (" %s + 0x%x (%p %p) [%p - %s]", method, (int)((char*)ip - (char*)ji->code_start), ji->code_start, (char*)ji->code_start + ji->code_size, domain, domain->friendly_name);
 
@@ -201,7 +210,7 @@ print_method_from_ip (void *ip)
                return;
        }
        method = mono_method_full_name (ji->method, TRUE);
-       source = mono_debug_source_location_from_address (ji->method, (int) ip, NULL, domain);
+       source = mono_debug_source_location_from_address (ji->method, (guint32)((guint8*)ip - (guint8*)ji->code_start), NULL, domain);
 
        g_print ("IP %p at offset 0x%x of method %s (%p %p)[domain %p - %s]\n", ip, (int)((char*)ip - (char*)ji->code_start), method, ji->code_start, (char*)ji->code_start + ji->code_size, domain, domain->friendly_name);
 
@@ -456,7 +465,7 @@ mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
                (dest)->ssa_op = MONO_SSA_MAYBE_LOAD;   \
                (dest)->inst_i0 = (cfg)->ret;   \
                (dest)->inst_i0->flags |= MONO_INST_INDIRECT;   \
-               (dest)->opcode = CEE_LDIND_I;   \
+               (dest)->opcode = cfg->ret_var_is_local ? OP_LDADDR : CEE_LDIND_I;       \
                (dest)->type = STACK_MP;        \
                (dest)->klass = (dest)->inst_i0->klass; \
                 (cfg)->disable_ssa = TRUE; \
@@ -1908,6 +1917,7 @@ handle_enum:
        case MONO_TYPE_I:
        case MONO_TYPE_U:
        case MONO_TYPE_PTR:
+       case MONO_TYPE_FNPTR:
                return calli? OP_CALL_REG: virt? CEE_CALLVIRT: CEE_CALL;
        case MONO_TYPE_CLASS:
        case MONO_TYPE_STRING:
@@ -2035,6 +2045,7 @@ handle_enum:
                case MONO_TYPE_I:
                case MONO_TYPE_U:
                case MONO_TYPE_PTR:
+               case MONO_TYPE_FNPTR:
                        if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR && args [i]->type != STACK_MP && args [i]->type != STACK_OBJ)
                                return 1;
                        continue;
@@ -2184,13 +2195,13 @@ mono_emit_calli (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethodSignature *
 }
 
 static MonoCallInst*
-mono_emit_method_call (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *method, MonoMethodSignature *sig,
-                      MonoInst **args, const guint8 *ip, MonoInst *this)
+mono_emit_method_call_full (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *method, MonoMethodSignature *sig,
+                      MonoInst **args, const guint8 *ip, MonoInst *this, gboolean to_end)
 {
        gboolean virtual = this != NULL;
        MonoCallInst *call;
 
-       call = mono_emit_call_args (cfg, bblock, sig, args, FALSE, virtual, ip, FALSE);
+       call = mono_emit_call_args (cfg, bblock, sig, args, FALSE, virtual, ip, to_end);
 
        if (this && sig->hasthis && 
            (method->klass->marshalbyref || method->klass == mono_defaults.object_class) && 
@@ -2211,6 +2222,13 @@ mono_emit_method_call (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *met
        return call;
 }
 
+static MonoCallInst*
+mono_emit_method_call (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *method, MonoMethodSignature *sig,
+                      MonoInst **args, const guint8 *ip, MonoInst *this)
+{
+       return mono_emit_method_call_full (cfg, bblock, method, sig, args, ip, this, FALSE);
+}
+
 inline static int
 mono_emit_method_call_spilled (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *method,  
                       MonoMethodSignature *signature, MonoInst **args, const guint8 *ip, MonoInst *this)
@@ -2220,6 +2238,16 @@ mono_emit_method_call_spilled (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMet
        return mono_spill_call (cfg, bblock, call, signature, method->string_ctor, ip, FALSE);
 }
 
+inline static int
+mono_emit_method_call_spilled_full (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *method,  
+                      MonoMethodSignature *signature, MonoInst **args, const guint8 *ip, MonoInst *this,
+                      gboolean ret_object, gboolean to_end)
+{
+       MonoCallInst *call = mono_emit_method_call_full (cfg, bblock, method, signature, args, ip, this, to_end);
+
+       return mono_spill_call (cfg, bblock, call, signature, ret_object, ip, to_end);
+}
+
 inline static int
 mono_emit_native_call (MonoCompile *cfg, MonoBasicBlock *bblock, gconstpointer func, MonoMethodSignature *sig,
                       MonoInst **args, const guint8 *ip, gboolean ret_object, gboolean to_end)
@@ -2385,11 +2413,24 @@ mono_get_array_new_va_signature (int arity)
        return res;
 }
 
+static MonoMethod*
+get_memcpy_method (void)
+{
+       static MonoMethod *memcpy_method = NULL;
+       if (!memcpy_method) {
+               memcpy_method = mono_class_get_method_from_name (mono_defaults.string_class, "memcpy", 3);
+               if (!memcpy_method)
+                       g_error ("Old corlib found. Install a new one");
+       }
+       return memcpy_method;
+}
+
 static void
 handle_stobj (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *dest, MonoInst *src, const unsigned char *ip, MonoClass *klass, gboolean to_end, gboolean native) {
        MonoInst *iargs [3];
        int n;
-       guint32 align = 0;
+       int align = 0;
+       MonoMethod *memcpy_method;
 
        g_assert (klass);
        /*
@@ -2421,15 +2462,29 @@ handle_stobj (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *dest, MonoInst
        iargs [1] = src;
        NEW_ICONST (cfg, iargs [2], n);
 
-       mono_emit_native_call (cfg, bblock, helper_memcpy, helper_sig_memcpy, iargs, ip, FALSE, to_end);
+       memcpy_method = get_memcpy_method ();
+       mono_emit_method_call_spilled_full (cfg, bblock, memcpy_method, memcpy_method->signature, iargs, ip, NULL, FALSE, to_end);
+}
+
+static MonoMethod*
+get_memset_method (void)
+{
+       static MonoMethod *memset_method = NULL;
+       if (!memset_method) {
+               memset_method = mono_class_get_method_from_name (mono_defaults.string_class, "memset", 3);
+               if (!memset_method)
+                       g_error ("Old corlib found. Install a new one");
+       }
+       return memset_method;
 }
 
 static void
 handle_initobj (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *dest, const guchar *ip, MonoClass *klass, MonoInst **stack_start, MonoInst **sp)
 {
-       MonoInst *iargs [2];
+       MonoInst *iargs [3];
        MonoInst *ins, *zero_int32;
        int n;
+       MonoMethod *memset_method;
 
        NEW_ICONST (cfg, zero_int32, 0);
 
@@ -2460,17 +2515,18 @@ handle_initobj (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *dest, const
                        MONO_ADD_INS (bblock, ins);
                        break;
                }
+               memset_method = get_memset_method ();
                handle_loaded_temps (cfg, bblock, stack_start, sp);
-               NEW_ICONST (cfg, ins, n);
                iargs [0] = dest;
-               iargs [1] = ins;
-               mono_emit_jit_icall (cfg, bblock, helper_initobj, iargs, ip);
+               NEW_ICONST (cfg, iargs [1], 0);
+               NEW_ICONST (cfg, iargs [2], n);
+               mono_emit_method_call_spilled (cfg, bblock, memset_method, memset_method->signature, iargs, ip, NULL);
                break;
        }
 }
 
 static int
-handle_alloc (MonoCompile *cfg, MonoBasicBlock *bblock, MonoClass *klass, const guchar *ip)
+handle_alloc (MonoCompile *cfg, MonoBasicBlock *bblock, MonoClass *klass, gboolean for_box, const guchar *ip)
 {
        MonoInst *iargs [2];
        void *alloc_ftn;
@@ -2484,7 +2540,7 @@ handle_alloc (MonoCompile *cfg, MonoBasicBlock *bblock, MonoClass *klass, const
                MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
                gboolean pass_lw;
                
-               alloc_ftn = mono_class_get_allocation_ftn (vtable, &pass_lw);
+               alloc_ftn = mono_class_get_allocation_ftn (vtable, for_box, &pass_lw);
                if (pass_lw) {
                        guint32 lw = vtable->klass->instance_size;
                        lw = ((lw + (sizeof (gpointer) - 1)) & ~(sizeof (gpointer) - 1)) / sizeof (gpointer);
@@ -2504,7 +2560,7 @@ handle_box (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *val, const gucha
        MonoInst *dest, *vtoffset, *add, *vstore;
        int temp;
 
-       temp = handle_alloc (cfg, bblock, klass, ip);
+       temp = handle_alloc (cfg, bblock, klass, TRUE, ip);
        NEW_TEMPLOAD (cfg, dest, temp);
        NEW_ICONST (cfg, vtoffset, sizeof (MonoObject));
        MONO_INST_NEW (cfg, add, OP_PADD);
@@ -3052,6 +3108,33 @@ mini_get_method (MonoImage *image, guint32 token, MonoClass *klass, MonoGenericC
        return method;
 }
 
+static
+void check_linkdemand (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee, MonoBasicBlock *bblock, unsigned char *ip)
+{
+       guint32 result = mono_declsec_linkdemand (cfg->domain, caller, callee);
+       if (result == MONO_JIT_SECURITY_OK)
+               return;
+
+       if (result == MONO_JIT_LINKDEMAND_ECMA) {
+               /* Generate code to throw a SecurityException before the actual call/link */
+               MonoAssembly *assembly = mono_image_get_assembly (caller->klass->image);
+               MonoReflectionAssembly *refass = (MonoReflectionAssembly*) mono_assembly_get_object (cfg->domain, assembly);
+               MonoReflectionMethod *refmet = mono_method_get_object (cfg->domain, caller, NULL);
+               MonoSecurityManager *secman = mono_security_manager_get_methods ();
+               MonoInst *args [3];
+
+               NEW_ICONST (cfg, args [0], 4);
+               NEW_PCONST (cfg, args [1], refass);
+               NEW_PCONST (cfg, args [2], refmet);
+               mono_emit_method_call_spilled (cfg, bblock, secman->linkdemandsecurityexception, mono_method_signature (secman->linkdemandsecurityexception), args, ip, NULL);
+       } else if (cfg->exception_type == MONO_EXCEPTION_NONE) {
+                /* don't hide previous results */
+               cfg->exception_type = MONO_EXCEPTION_SECURITY_LINKDEMAND;
+               cfg->exception_data = result;
+       }
+}
+
+
 /*
  * mono_method_to_ir: translates IL into basic blocks containing trees
  */
@@ -3082,7 +3165,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
        int num_calls = 0, inline_costs = 0;
        int breakpoint_id = 0;
        guint real_offset, num_args;
-       MonoBoolean security;
+       MonoBoolean security, pinvoke;
+       MonoSecurityManager* secman = NULL;
        MonoDeclSecurityActions actions;
 
        image = method->klass->image;
@@ -3211,7 +3295,10 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                }
        }
 
-       security = mono_use_security_manager && mono_method_has_declsec (method);
+       if (mono_use_security_manager)
+               secman = mono_security_manager_get_methods ();
+
+       security = (secman && mono_method_has_declsec (method));
        /* at this point having security doesn't mean we have any code to generate */
        if (security && (cfg->method == method)) {
                /* Only Demand, NonCasDemand and DemandChoice requires code generation.
@@ -3219,8 +3306,32 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                 * have nothing to generate */
                security = mono_declsec_get_demands (method, &actions);
        }
+
+       /* we must Demand SecurityPermission.Unmanaged before P/Invoking */
+       pinvoke = (secman && (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE));
+       if (pinvoke) {
+               MonoMethod *wrapped = mono_marshal_method_from_wrapper (method);
+               if (wrapped && (wrapped->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
+                       MonoCustomAttrInfo* custom = mono_custom_attrs_from_method (wrapped);
+
+                       /* unless the method or it's class has the [SuppressUnmanagedCodeSecurity] attribute */
+                       if (custom && mono_custom_attrs_has_attr (custom, secman->suppressunmanagedcodesecurity)) {
+                               pinvoke = FALSE;
+                       }
+
+                       if (pinvoke) {
+                               custom = mono_custom_attrs_from_class (wrapped->klass);
+                               if (custom && mono_custom_attrs_has_attr (custom, secman->suppressunmanagedcodesecurity)) {
+                                       pinvoke = FALSE;
+                               }
+                       }
+               } else {
+                       /* not a P/Invoke after all */
+                       pinvoke = FALSE;
+               }
+       }
        
-       if ((header->init_locals || (cfg->method == method && (cfg->opt & MONO_OPT_SHARED))) || mono_compile_aot || security) {
+       if ((header->init_locals || (cfg->method == method && (cfg->opt & MONO_OPT_SHARED))) || mono_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;
@@ -3237,7 +3348,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
        /* at this point we know, if security is TRUE, that some code needs to be generated */
        if (security && (cfg->method == method)) {
                MonoInst *args [2];
-               MonoSecurityManager* secman = mono_security_manager_get_methods ();
+
+               mono_jit_stats.cas_demand_generation++;
 
                if (actions.demand.blob) {
                        /* Add code for SecurityAction.Demand */
@@ -3263,6 +3375,11 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                }
        }
 
+       /* we must Demand SecurityPermission.Unmanaged before p/invoking */
+       if (pinvoke) {
+               mono_emit_method_call_spilled (cfg, init_localsbb, secman->demandunmanaged, mono_method_signature (secman->demandunmanaged), NULL, ip, NULL);
+       }
+
        if (get_basic_blocks (cfg, bbhash, header, real_offset, ip, end, &err_pos)) {
                ip = err_pos;
                goto unverified;
@@ -3544,7 +3661,11 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        *sp++ = ins;
                        break;
                case CEE_LDC_R4: {
-                       float *f = mono_mempool_alloc (cfg->domain->mp, sizeof (float));
+                       float *f;
+                       /* we should really allocate this only late in the compilation process */
+                       mono_domain_lock (cfg->domain);
+                       f = mono_mempool_alloc (cfg->domain->mp, sizeof (float));
+                       mono_domain_unlock (cfg->domain);
                        CHECK_OPSIZE (5);
                        CHECK_STACK_OVF (1);
                        MONO_INST_NEW (cfg, ins, OP_R4CONST);
@@ -3558,7 +3679,10 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        break;
                }
                case CEE_LDC_R8: {
-                       double *d = mono_mempool_alloc (cfg->domain->mp, sizeof (double));
+                       double *d;
+                       mono_domain_lock (cfg->domain);
+                       d = mono_mempool_alloc (cfg->domain->mp, sizeof (double));
+                       mono_domain_unlock (cfg->domain);
                        CHECK_OPSIZE (9);
                        CHECK_STACK_OVF (1);
                        MONO_INST_NEW (cfg, ins, OP_R8CONST);
@@ -3628,6 +3752,11 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        token = read32 (ip + 1);
                        /* FIXME: check the signature matches */
                        cmethod = mini_get_method (image, token, NULL, generic_context);
+
+                       if (mono_use_security_manager) {
+                               check_linkdemand (cfg, method, cmethod, bblock, ip);
+                       }
+
                        ins->inst_p0 = cmethod;
                        MONO_ADD_INS (bblock, ins);
                        ip += 5;
@@ -3667,6 +3796,9 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                                g_assert (cmethod);
 
+                               if (!virtual && (cmethod->flags & METHOD_ATTRIBUTE_ABSTRACT))
+                                       goto unverified;
+
                                if (!cmethod->klass->inited)
                                        mono_class_init (cmethod->klass);
 
@@ -3681,6 +3813,10 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                                n = fsig->param_count + fsig->hasthis;
 
+                               if (mono_use_security_manager) {
+                                       check_linkdemand (cfg, method, cmethod, bblock, ip);
+                               }
+
                                if (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL &&
                                    cmethod->klass->parent == mono_defaults.array_class) {
                                        array_rank = cmethod->klass->rank;
@@ -3894,14 +4030,22 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        link_bblock (cfg, bblock, tblock);
                                        ins->inst_target_bb = tblock;
                                        start_new_bblock = 1;
-                                       ip += 5;
-                                       
+
                                        if (!MONO_TYPE_IS_VOID (fsig->ret)) {
                                                /* just create a dummy - the value is never used */
                                                ins = mono_compile_create_var (cfg, fsig->ret, OP_LOCAL);
                                                NEW_TEMPLOAD (cfg, *sp, ins->inst_c0);
                                                sp++;
+                                               MONO_INST_NEW (cfg, ins, CEE_POP);
+                                               MONO_ADD_INS (bblock, ins);
+                                               --sp;
+                                               ins->inst_i0 = *sp;
                                        }
+                                       /* skip the CEE_RET, too */
+                                       if (ip_in_bb (cfg, bblock, ip + 5))
+                                               ip += 6;
+                                       else
+                                               ip += 5;
 
                                        break;
                                }
@@ -4354,13 +4498,14 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        copy->unused = n;
                                        MONO_ADD_INS (bblock, copy);
                                } else {
+                                       MonoMethod *memcpy_method = get_memcpy_method ();
                                        MonoInst *iargs [3];
                                        iargs [0] = sp [0];
                                        iargs [1] = sp [1];
                                        NEW_ICONST (cfg, iargs [2], n);
                                        iargs [2]->cil_code = ip;
 
-                                       mono_emit_jit_icall (cfg, bblock, helper_memcpy, iargs, ip);
+                                       mono_emit_method_call_spilled (cfg, bblock, memcpy_method, memcpy_method->signature, iargs, ip, NULL);
                                }
                        }
                        ins_flag = 0;
@@ -4437,11 +4582,12 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                copy->unused = n;
                                MONO_ADD_INS (bblock, copy);
                        } else {
+                               MonoMethod *memcpy_method = get_memcpy_method ();
                                iargs [1] = *sp;
                                NEW_ICONST (cfg, iargs [2], n);
                                iargs [2]->cil_code = ip;
 
-                               mono_emit_jit_icall (cfg, bblock, helper_memcpy, iargs, ip);
+                               mono_emit_method_call_spilled (cfg, bblock, memcpy_method, memcpy_method->signature, iargs, ip, NULL);
                        }
                        NEW_TEMPLOAD (cfg, *sp, ins->inst_c0);
                        ++sp;
@@ -4505,7 +4651,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        MonoInst *iargs [2];
                        MonoMethodSignature *fsig;
                        int temp;
-
+                       
                        CHECK_OPSIZE (5);
                        token = read32 (ip + 1);
                        if (method->wrapper_type != MONO_WRAPPER_NONE) {
@@ -4516,6 +4662,10 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                        mono_class_init (cmethod->klass);
 
+                       if (mono_use_security_manager) {
+                               check_linkdemand (cfg, method, cmethod, bblock, ip);
+                       }
+
                        n = fsig->param_count;
                        CHECK_STACK (n);
 
@@ -4526,7 +4676,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        }
 
                        handle_loaded_temps (cfg, bblock, stack_start, sp);
-                       
 
                        if (cmethod->klass->parent == mono_defaults.array_class) {
                                NEW_METHODCONST (cfg, *sp, cmethod);
@@ -4537,15 +4686,29 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                /* now call the string ctor */
                                temp = mono_emit_method_call_spilled (cfg, bblock, cmethod, fsig, sp, ip, NULL);
                        } else {
+                               MonoInst* callvirt_this_arg = NULL;
+                               
                                if (cmethod->klass->valuetype) {
                                        iargs [0] = mono_compile_create_var (cfg, &cmethod->klass->byval_arg, OP_LOCAL);
                                        temp = iargs [0]->inst_c0;
                                        NEW_TEMPLOADA (cfg, *sp, temp);
+
+                                       /* 
+                                        * The code generated by mini_emit_virtual_call () expects
+                                        * iargs [0] to be a boxed instance, but luckily the vcall
+                                        * will be transformed into a normal call there. The AOT
+                                        * case needs an already allocate got_var.
+                                        */
+                                       mono_get_got_var (cfg);
                                } else {
-                                       temp = handle_alloc (cfg, bblock, cmethod->klass, ip);
+                                       temp = handle_alloc (cfg, bblock, cmethod->klass, FALSE, ip);
                                        NEW_TEMPLOAD (cfg, *sp, temp);
                                }
 
+                               /* Avoid virtual calls to ctors if possible */
+                               if (cmethod->klass->marshalbyref)
+                                       callvirt_this_arg = sp [0];
+                               
                                if ((cfg->opt & MONO_OPT_INLINE) && cmethod &&
                                    mono_method_check_inlining (cfg, cmethod) &&
                                    !mono_class_is_subclass_of (cmethod->klass, mono_defaults.exception_class, FALSE) &&
@@ -4572,11 +4735,11 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                                break;
                                                
                                        } else {
-                                               mono_emit_method_call_spilled (cfg, bblock, cmethod, fsig, sp, ip, sp[0]);
+                                               mono_emit_method_call_spilled (cfg, bblock, cmethod, fsig, sp, ip, callvirt_this_arg);
                                        }
                                } else {
                                        /* now call the actual ctor */
-                                       mono_emit_method_call_spilled (cfg, bblock, cmethod, fsig, sp, ip, sp[0]);
+                                       mono_emit_method_call_spilled (cfg, bblock, cmethod, fsig, sp, ip, callvirt_this_arg);
                                }
                        }
 
@@ -4727,11 +4890,12 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                copy->unused = n;
                                MONO_ADD_INS (bblock, copy);
                        } else {
+                               MonoMethod *memcpy_method = get_memcpy_method ();
                                iargs [1] = *sp;
                                NEW_ICONST (cfg, iargs [2], n);
                                iargs [2]->cil_code = ip;
 
-                               mono_emit_jit_icall (cfg, bblock, helper_memcpy, iargs, ip);
+                               mono_emit_method_call_spilled (cfg, bblock, memcpy_method, memcpy_method->signature, iargs, ip, NULL);
                        }
                        NEW_TEMPLOAD (cfg, *sp, ins->inst_c0);
                        ++sp;
@@ -4834,9 +4998,13 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        ins->cil_code = ip++;
                        bblock->out_of_line = TRUE;
                        MONO_ADD_INS (bblock, ins);
+                       MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
+                       ins->cil_code = ip - 1;
+                       MONO_ADD_INS (bblock, ins);
                        sp = stack_start;
                        link_bblock (cfg, bblock, end_bblock);
                        start_new_bblock = 1;
+                       mono_get_got_var (cfg);
                        break;
                case CEE_LDFLD:
                case CEE_LDFLDA:
@@ -5004,6 +5172,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        field = mono_field_from_token (image, token, &klass, generic_context);
                        mono_class_init (klass);
 
+                       g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
+
                        if ((*ip) == CEE_STSFLD)
                                handle_loaded_temps (cfg, bblock, stack_start, sp);
 
@@ -5012,9 +5182,10 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                         */
                        if (!(cfg->opt & MONO_OPT_SHARED))
                                mono_class_vtable (cfg->domain, klass);
-                       
+                       mono_domain_lock (cfg->domain);
                        if (cfg->domain->special_static_fields)
                                addr = g_hash_table_lookup (cfg->domain->special_static_fields, field);
+                       mono_domain_unlock (cfg->domain);
 
                        if ((cfg->opt & MONO_OPT_SHARED) || (cfg->compile_aot && addr)) {
                                int temp;
@@ -5854,6 +6025,10 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                ip += 6;
                                inline_costs += 10 * num_calls++;
                                break;
+                       case CEE_MONO_NOT_TAKEN:
+                               bblock->out_of_line = TRUE;
+                               ip += 2;
+                               break;
                        default:
                                g_error ("opcode 0x%02x 0x%02x not handled", MONO_CUSTOM_PREFIX, ip [1]);
                                break;
@@ -5937,6 +6112,11 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                }
 
                                mono_class_init (cmethod->klass);
+
+                               if (mono_use_security_manager) {
+                                       check_linkdemand (cfg, method, cmethod, bblock, ip);
+                               }
+
                                handle_loaded_temps (cfg, bblock, stack_start, sp);
 
                                NEW_METHODCONST (cfg, argconst, cmethod);
@@ -5964,6 +6144,11 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        cmethod = mini_get_method (image, n, NULL, generic_context);
 
                                mono_class_init (cmethod->klass);
+
+                               if (mono_use_security_manager) {
+                                       check_linkdemand (cfg, method, cmethod, bblock, ip);
+                               }
+
                                handle_loaded_temps (cfg, bblock, stack_start, sp);
 
                                --sp;
@@ -6177,9 +6362,11 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                iargs [2] = sp [2];
                                handle_loaded_temps (cfg, bblock, stack_start, sp);
                                if (ip [1] == CEE_CPBLK) {
-                                       mono_emit_jit_icall (cfg, bblock, helper_memcpy, iargs, ip);
+                                       MonoMethod *memcpy_method = get_memcpy_method ();
+                                       mono_emit_method_call_spilled (cfg, bblock, memcpy_method, memcpy_method->signature, iargs, ip, NULL);
                                } else {
-                                       mono_emit_jit_icall (cfg, bblock, helper_memset, iargs, ip);
+                                       MonoMethod *memset_method = get_memset_method ();
+                                       mono_emit_method_call_spilled (cfg, bblock, memset_method, memset_method->signature, iargs, ip, NULL);
                                }
                                ip += 2;
                                inline_costs += 1;
@@ -6218,6 +6405,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                link_bblock (cfg, bblock, end_bblock);
                                start_new_bblock = 1;
                                ip += 2;
+                               mono_get_got_var (cfg);
                                break;
                        }
                        case CEE_SIZEOF:
@@ -6296,8 +6484,11 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        int t = ptype->type;
                        if (t == MONO_TYPE_VALUETYPE && ptype->data.klass->enumtype)
                                t = ptype->data.klass->enum_basetype->type;
-                       /* FIXME: use initobj for valuetypes, handle pointers, long, float. */
-                       if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
+                       if (ptype->byref) {
+                               NEW_PCONST (cfg, ins, NULL);
+                               NEW_LOCSTORE (cfg, store, i, ins);
+                               MONO_ADD_INS (init_localsbb, store);
+                       } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
                                NEW_ICONST (cfg, ins, 0);
                                NEW_LOCSTORE (cfg, store, i, ins);
                                MONO_ADD_INS (init_localsbb, store);
@@ -6624,16 +6815,9 @@ create_helper_signature (void)
        /* int amethod (double) */
        helper_sig_int_double = make_icall_sig ("int32 double");
 
-       /* void  initobj (intptr, int size) */
-       helper_sig_initobj = make_icall_sig ("void ptr int32");
-
-       /* void  memcpy (intptr, intptr, int size) */
-       helper_sig_memcpy = make_icall_sig ("void ptr ptr int32");
-
-       /* void  memset (intptr, int val, int size) */
-       helper_sig_memset = make_icall_sig ("void ptr int32 int32");
-
        helper_sig_class_init_trampoline = make_icall_sig ("void");
+
+       helper_sig_obj_obj_obj_ptr = make_icall_sig ("object object object ptr");
 }
 
 gconstpointer
@@ -6661,6 +6845,25 @@ mono_icall_get_wrapper (MonoJitICallInfo* callinfo)
        return callinfo->wrapper;
 }
 
+static void
+mono_init_trampolines (void)
+{
+       trampoline_code [MONO_TRAMPOLINE_GENERIC] = mono_arch_create_trampoline_code (MONO_TRAMPOLINE_GENERIC);
+       trampoline_code [MONO_TRAMPOLINE_JUMP] = mono_arch_create_trampoline_code (MONO_TRAMPOLINE_JUMP);
+       trampoline_code [MONO_TRAMPOLINE_CLASS_INIT] = mono_arch_create_trampoline_code (MONO_TRAMPOLINE_CLASS_INIT);
+#ifdef MONO_ARCH_HAVE_PIC_AOT
+       trampoline_code [MONO_TRAMPOLINE_AOT] = mono_arch_create_trampoline_code (MONO_TRAMPOLINE_AOT);
+#endif
+
+       mono_generic_trampoline_code = trampoline_code [MONO_TRAMPOLINE_GENERIC];
+}
+
+guint8 *
+mono_get_trampoline_code (MonoTrampolineType tramp_type)
+{
+       return trampoline_code [tramp_type];
+}
+
 gpointer
 mono_create_class_init_trampoline (MonoVTable *vtable)
 {
@@ -6734,22 +6937,40 @@ mono_create_jit_trampoline (MonoMethod *method)
        MonoDomain *domain = mono_domain_get ();
        gpointer tramp;
 
-       /* Trampoline are domain specific, so cache only the one used in the root domain */
-       if ((domain == mono_get_root_domain ()) && method->info)
-               return method->info;
+       mono_domain_lock (domain);
+       tramp = g_hash_table_lookup (domain->jit_trampoline_hash, method);
+       mono_domain_unlock (domain);
+       if (tramp)
+               return tramp;
 
        if (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
                return mono_create_jit_trampoline (mono_marshal_get_synchronized_wrapper (method));
 
        tramp = mono_arch_create_jit_trampoline (method);
-       if (domain == mono_get_root_domain ())
-               method->info = tramp;
+       
+       mono_domain_lock (domain);
+       g_hash_table_insert (domain->jit_trampoline_hash, method, tramp);
+       mono_domain_unlock (domain);
 
        mono_jit_stats.method_trampolines++;
 
        return tramp;
 }      
 
+#ifdef MONO_ARCH_HAVE_CREATE_TRAMPOLINE_FROM_TOKEN
+gpointer
+mono_create_jit_trampoline_from_token (MonoImage *image, guint32 token)
+{
+       gpointer tramp;
+
+       tramp = mono_arch_create_jit_trampoline_from_token (image, token);
+
+       mono_jit_stats.method_trampolines++;
+
+       return tramp;
+}      
+#endif
+
 MonoVTable*
 mono_find_class_init_trampoline_by_addr (gconstpointer addr)
 {
@@ -6815,7 +7036,7 @@ mono_allocate_stack_slots (MonoCompile *m, guint32 *stack_size, guint32 *stack_a
        vtype_stack_slots = g_new0 (StackSlotInfo, 256);
        nvtypes = 0;
 
-       offsets = g_new (guint32, m->num_varinfo);
+       offsets = g_new (gint32, m->num_varinfo);
        for (i = 0; i < m->num_varinfo; ++i)
                offsets [i] = -1;
 
@@ -7129,9 +7350,23 @@ mono_destroy_compile (MonoCompile *cfg)
 }
 
 #ifdef HAVE_KW_THREAD
-static __thread gpointer mono_lmf_addr;
+static __thread gpointer mono_lmf_addr MONO_TLS_FAST;
 #endif
 
+guint32
+mono_get_jit_tls_key (void)
+{
+       return mono_jit_tls_id;
+}
+
+gint32
+mono_get_lmf_tls_offset (void)
+{
+       int offset;
+       MONO_THREAD_VAR_OFFSET(mono_lmf_addr,offset);
+       return offset;
+}
+
 MonoLMF **
 mono_get_lmf_addr (void)
 {
@@ -7148,6 +7383,20 @@ mono_get_lmf_addr (void)
 #endif
 }
 
+/* Called by native->managed wrappers */
+void
+mono_jit_thread_attach (MonoDomain *domain)
+{
+#ifdef HAVE_KW_THREAD
+       if (!mono_lmf_addr) {
+               mono_thread_attach (domain);
+       }
+#else
+       if (!TlsGetValue (mono_jit_tls_id))
+               mono_thread_attach (domain);
+#endif
+}      
+
 /**
  * mono_thread_abort:
  * @obj: exception object
@@ -7689,7 +7938,7 @@ remove_block_if_useless (MonoCompile *cfg, MonoBasicBlock *bb, MonoBasicBlock *p
        
        if (target_bb != NULL) {
                int i;
-               
+
                if (cfg->verbose_level > 1) {
                        printf ("remove_block_if_useless %s, removed BB%d\n", mono_method_full_name (cfg->method, TRUE), bb->block_num);
                }
@@ -7756,7 +8005,9 @@ merge_basic_blocks (MonoBasicBlock *bb, MonoBasicBlock *bbn)
 static void
 move_basic_block_to_end (MonoCompile *cfg, MonoBasicBlock *bb)
 {
-       MonoBasicBlock *bbn;
+       MonoBasicBlock *bbn, *next;
+
+       next = bb->next_bb;
 
        /* Find the previous */
        for (bbn = cfg->bb_entry; bbn->next_bb && bbn->next_bb != bb; bbn = bbn->next_bb)
@@ -7770,6 +8021,16 @@ move_basic_block_to_end (MonoCompile *cfg, MonoBasicBlock *bb)
                ;
        bbn->next_bb = bb;
        bb->next_bb = NULL;
+
+       /* Add a branch */
+       if (next && (!bb->last_ins || (bb->last_ins->opcode != OP_NOT_REACHED))) {
+               MonoInst *ins;
+
+               MONO_INST_NEW (cfg, ins, CEE_BR);
+               MONO_ADD_INS (bb, ins);
+               link_bblock (cfg, bb, next);
+               ins->inst_target_bb = next;
+       }               
 }
 
 /*
@@ -7977,9 +8238,8 @@ optimize_branches (MonoCompile *cfg)
                                        }
                                }
 
-#ifdef MONO_ARCH_HAVE_OUT_OF_LINE_BBLOCKS
                                if (bb->last_ins && MONO_IS_COND_BRANCH_NOFP (bb->last_ins)) {
-                                       if (bb->last_ins->inst_false_bb->out_of_line) {
+                                       if (bb->last_ins->inst_false_bb->out_of_line && (bb->region == bb->last_ins->inst_false_bb->region)) {
                                                /* Reverse the branch */
                                                bb->last_ins->opcode = reverse_branch_op (bb->last_ins->opcode);
                                                bbn = bb->last_ins->inst_false_bb;
@@ -7992,7 +8252,6 @@ optimize_branches (MonoCompile *cfg)
                                                                         bb->block_num);
                                        }
                                }
-#endif
                        }
                }
        } while (changed && (niterations > 0));
@@ -8037,6 +8296,10 @@ mono_compile_create_vars (MonoCompile *cfg)
                mono_compile_create_var (cfg, header->locals [i], OP_LOCAL);
        if (cfg->verbose_level > 2)
                g_print ("locals done\n");
+
+#ifdef MONO_ARCH_HAVE_CREATE_VARS
+       mono_arch_create_vars (cfg);
+#endif
 }
 
 void
@@ -8250,7 +8513,6 @@ mono_codegen (MonoCompile *cfg)
                bb->native_offset = cfg->code_len;
                mono_arch_output_basic_block (cfg, bb);
 
-#ifdef MONO_ARCH_HAVE_OUT_OF_LINE_BBLOCKS
                if (bb == cfg->bb_exit) {
                        cfg->epilog_begin = cfg->code_len;
 
@@ -8262,17 +8524,11 @@ mono_codegen (MonoCompile *cfg)
 
                        mono_arch_emit_epilog (cfg);
                }
-#endif
        }
 
-#ifndef MONO_ARCH_HAVE_OUT_OF_LINE_BBLOCKS
-       cfg->bb_exit->native_offset = cfg->code_len;
-       max_epilog_size = mono_arch_max_epilog_size (cfg);
-#else
        mono_arch_emit_exceptions (cfg);
 
        max_epilog_size = 0;
-#endif
 
        code = cfg->native_code + cfg->code_len;
 
@@ -8301,18 +8557,6 @@ mono_codegen (MonoCompile *cfg)
        code = cfg->native_code + cfg->code_len;
   
        /* g_assert (((int)cfg->native_code & (MONO_ARCH_CODE_ALIGNMENT - 1)) == 0); */
-
-#ifndef MONO_ARCH_HAVE_OUT_OF_LINE_BBLOCKS
-       cfg->epilog_begin = cfg->code_len;
-
-       if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
-               code = mono_arch_instrument_epilog (cfg, mono_profiler_method_leave, code, FALSE);
-
-       cfg->code_len = code - cfg->native_code;
-
-       mono_arch_emit_epilog (cfg);
-#endif
-
        for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
                switch (patch_info->type) {
                case MONO_PATCH_INFO_ABS: {
@@ -8365,11 +8609,14 @@ mono_codegen (MonoCompile *cfg)
                }
        }
        
-       if (cfg->verbose_level > 0)
+       if (cfg->verbose_level > 0) {
+               char* nm = mono_method_full_name (cfg->method, TRUE);
                g_print ("Method %s emitted at %p to %p [%s]\n", 
-                                mono_method_full_name (cfg->method, TRUE)
+                                nm
                                 cfg->native_code, cfg->native_code + cfg->code_len, cfg->domain->friendly_name);
-
+               g_free (nm);
+       }
+       
        mono_arch_patch_code (cfg->method, cfg->domain, cfg->native_code, cfg->patch_info, cfg->run_cctors);
 
        if (cfg->method->dynamic) {
@@ -8912,10 +9159,14 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
                g_free (id);
        }
        
-       if (cfg->method->dynamic)
+       if (cfg->method->dynamic) {
                jinfo = g_malloc0 (sizeof (MonoJitInfo) + (header->num_clauses * sizeof (MonoJitExceptionInfo)));
-       else
+       } else {
+               /* we access cfg->domain->mp */
+               mono_domain_lock (cfg->domain);
                jinfo = mono_mempool_alloc0 (cfg->domain->mp, sizeof (MonoJitInfo) + (header->num_clauses * sizeof (MonoJitExceptionInfo)));
+               mono_domain_unlock (cfg->domain);
+       }
 
        jinfo->method = method;
        jinfo->code_start = cfg->native_code;
@@ -8964,10 +9215,12 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
 
        cfg->jit_info = jinfo;
 
+       mono_domain_lock (cfg->domain);
        mono_jit_info_table_add (cfg->domain, jinfo);
 
        if (cfg->method->dynamic)
                mono_dynamic_code_hash_lookup (cfg->domain, cfg->method)->ji = jinfo;
+       mono_domain_unlock (cfg->domain);
 
        /* collect statistics */
        mono_jit_stats.allocated_code_size += cfg->code_len;
@@ -8986,6 +9239,26 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
        if (cfg->prof_options & MONO_PROFILE_JIT_COMPILATION)
                mono_profiler_method_end_jit (method, MONO_PROFILE_OK);
 
+       /* this can only be set if the security manager is active */
+       if (cfg->exception_type == MONO_EXCEPTION_SECURITY_LINKDEMAND) {
+               MonoAssembly *assembly = mono_image_get_assembly (method->klass->image);
+               MonoReflectionAssembly *refass = (MonoReflectionAssembly*) mono_assembly_get_object (domain, assembly);
+               MonoReflectionMethod *refmet = mono_method_get_object (domain, method, NULL);
+               MonoSecurityManager* secman = mono_security_manager_get_methods ();
+               MonoObject *exc = NULL;
+               gpointer args [3];
+
+               args [0] = &cfg->exception_data;
+               args [1] = refass;
+               args [2] = refmet;
+               mono_runtime_invoke (secman->linkdemandsecurityexception, NULL, args, &exc);
+
+               mono_destroy_compile (cfg);
+               cfg = NULL;
+
+               mono_raise_exception ((MonoException*)exc);
+       }
+
        return cfg;
 }
 
@@ -9026,6 +9299,9 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain)
                MonoMethod *nm;
                MonoMethodPInvoke* piinfo = (MonoMethodPInvoke *) method;
 
+               if (method->iflags & METHOD_IMPL_ATTRIBUTE_NATIVE)
+                       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) {
                        if (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL)
                                piinfo->addr = mono_lookup_internal_call (method);
@@ -9044,8 +9320,9 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain)
 
                if (method->klass->parent == mono_defaults.multicastdelegate_class) {
                        if (*name == '.' && (strcmp (name, ".ctor") == 0)) {
-                               /* FIXME: uhm, we need a wrapper to handle exceptions? */
-                               return (gpointer)mono_delegate_ctor;
+                               MonoJitICallInfo *mi = mono_find_jit_icall_by_name ("mono_delegate_ctor");
+                               g_assert (mi);
+                               return (gpointer)mono_icall_get_wrapper (mi);
                        } else if (*name == 'I' && (strcmp (name, "Invoke") == 0)) {
                                nm = mono_marshal_get_delegate_invoke (method);
                                return mono_jit_compile_method (nm);
@@ -9141,11 +9418,11 @@ mono_jit_compile_method (MonoMethod *method)
 }
 
 static void
-invalidated_delegate_trampoline (MonoClass *klass)
+invalidated_delegate_trampoline (char *desc)
 {
        g_error ("Unmanaged code called delegate of type %s which was already garbage collected.\n"
                 "See http://www.go-mono.com/delegate.html for an explanation and ways to fix this.",
-                mono_type_full_name (&klass->byval_arg));
+                desc);
 }
 
 /*
@@ -9157,37 +9434,38 @@ static void
 mono_jit_free_method (MonoDomain *domain, MonoMethod *method)
 {
        MonoJitDynamicMethodInfo *ji;
+       gboolean destroy = TRUE;
 
        g_assert (method->dynamic);
 
        mono_domain_lock (domain);
        ji = mono_dynamic_code_hash_lookup (domain, method);
        mono_domain_unlock (domain);
+
+       if (!ji)
+               return;
+       mono_domain_lock (domain);
+       g_hash_table_remove (domain->dynamic_code_hash, method);
+       g_hash_table_remove (domain->jit_code_hash, method);
+       mono_domain_unlock (domain);
+
 #ifdef MONO_ARCH_HAVE_INVALIDATE_METHOD
-       /* FIXME: only enable this with a env var */
-       if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
+       if (debug_options.keep_delegates && method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
                /*
                 * Instead of freeing the code, change it to call an error routine
                 * so people can fix their code.
                 */
-               if (ji){
-                       char *type = mono_type_full_name (&method->klass->byval_arg);
-                       char *type_and_method = g_strdup_printf ("%s.%s", type, method->name);
+               char *type = mono_type_full_name (&method->klass->byval_arg);
+               char *type_and_method = g_strdup_printf ("%s.%s", type, method->name);
 
-                       g_free (type);
-                       mono_arch_invalidate_method (ji->ji, invalidated_delegate_trampoline, type_and_method);
-               }
-               return;
+               g_free (type);
+               mono_arch_invalidate_method (ji->ji, invalidated_delegate_trampoline, type_and_method);
+               destroy = FALSE;
        }
 #endif
 
-       if (!ji)
-               return;
-       mono_domain_lock (domain);
-       g_hash_table_remove (domain->dynamic_code_hash, method);
-       mono_domain_unlock (domain);
-
-       mono_code_manager_destroy (ji->code_mp);
+       if (destroy)
+               mono_code_manager_destroy (ji->code_mp);
        mono_jit_info_table_remove (domain, ji->ji);
        g_free (ji->ji);
        g_free (ji);
@@ -9311,13 +9589,22 @@ SIG_HANDLER_SIGNATURE (sigill_signal_handler)
 
 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
 
+#ifndef MONO_ARCH_USE_SIGACTION
+#error "Can't use sigaltstack without sigaction"
+#endif
+
+#endif
+
 static void
-sigsegv_signal_handler (int _dummy, siginfo_t *info, void *context)
+SIG_HANDLER_SIGNATURE (sigsegv_signal_handler)
 {
-       MonoException *exc;
+       MonoException *exc = NULL;
+#ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
        MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
-       struct sigcontext *ctx = (struct sigcontext *)&(((ucontext_t*)context)->uc_mcontext);
+#endif
+       GET_CONTEXT
 
+#ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
        /* Can't allocate memory using Boehm GC on altstack */
        if (jit_tls->stack_size && 
                ((guint8*)info->si_addr >= (guint8*)jit_tls->end_of_stack - jit_tls->stack_size) &&
@@ -9325,31 +9612,37 @@ sigsegv_signal_handler (int _dummy, siginfo_t *info, void *context)
                exc = mono_domain_get ()->stack_overflow_ex;
        else
                exc = mono_domain_get ()->null_reference_ex;
+#endif
+
+       if (debug_options.abort_on_sigsegv) {
+               MonoJitInfo *ji = mono_jit_info_table_find (mono_domain_get (), mono_arch_ip_from_context(ctx));
+               if (!ji) {
+                       fprintf (stderr, "Got SIGSEGV while in unmanaged code, and the 'abort-on-sigsegv' MONO_DEBUG option is set. Aborting...\n");
+                       /* Segfault in unmanaged code */
+                       abort ();
+               }
+       }
                        
        mono_arch_handle_exception (ctx, exc, FALSE);
 }
 
-#else
-
-static void
-SIG_HANDLER_SIGNATURE (sigsegv_signal_handler)
-{
-       GET_CONTEXT;
-
-       mono_arch_handle_exception (ctx, NULL, FALSE);
-}
-
-#endif
-
 static void
 SIG_HANDLER_SIGNATURE (sigusr1_signal_handler)
 {
        gboolean running_managed;
        MonoException *exc;
+       void *ji;
        
-       GET_CONTEXT
+       GET_CONTEXT;
 
-       running_managed = (mono_jit_info_table_find (mono_domain_get (), mono_arch_ip_from_context(ctx)) != NULL);
+       /*
+        * FIXME:
+        * This is an async signal, so the code below must not call anything which
+        * is not async safe. That includes the pthread locking functions. If we
+        * know that we interrupted managed code, then locking is safe.
+        */
+       ji = mono_jit_info_table_find (mono_domain_get (), mono_arch_ip_from_context(ctx));
+       running_managed = ji != NULL;
        
        exc = mono_thread_request_interruption (running_managed); 
        if (!exc) return;
@@ -9418,7 +9711,7 @@ mono_runtime_install_handlers (void)
        win32_seh_set_handler(SIGFPE, sigfpe_signal_handler);
        win32_seh_set_handler(SIGILL, sigill_signal_handler);
        win32_seh_set_handler(SIGSEGV, sigsegv_signal_handler);
-       if (getenv ("MONO_DEBUG"))
+       if (debug_options.handle_sigint)
                win32_seh_set_handler(SIGINT, sigint_signal_handler);
 #else /* !PLATFORM_WIN32 */
 
@@ -9427,9 +9720,8 @@ mono_runtime_install_handlers (void)
         * handlers. If not we must call syscall directly instead 
         * of sigaction */
 
-       if (getenv ("MONO_DEBUG")) {
+       if (debug_options.handle_sigint)
                add_signal_handler (SIGINT, sigint_signal_handler);
-       }
 
        add_signal_handler (SIGFPE, sigfpe_signal_handler);
        add_signal_handler (SIGQUIT, sigquit_signal_handler);
@@ -9557,6 +9849,34 @@ mono_jit_create_remoting_trampoline (MonoMethod *method, MonoRemotingTarget targ
        return addr;
 }
 
+static void
+mini_parse_debug_options (void)
+{
+       char *options = getenv ("MONO_DEBUG");
+       gchar **args, **ptr;
+       
+       if (!options)
+               return;
+
+       args = g_strsplit (options, ",", -1);
+
+       for (ptr = args; ptr && *ptr; ptr++) {
+               const char *arg = *ptr;
+
+               if (!strcmp (arg, "handle-sigint"))
+                       debug_options.handle_sigint = TRUE;
+               else if (!strcmp (arg, "keep-delegates"))
+                       debug_options.keep_delegates = TRUE;
+               else if (!strcmp (arg, "abort-on-sigsegv"))
+                       debug_options.abort_on_sigsegv = TRUE;
+               else {
+                       fprintf (stderr, "Invalid option for the MONO_DEBUG env variable: %s\n", arg);
+                       fprintf (stderr, "Available options: 'handle-sigint', 'keep-delegates', 'abort-on-sigsegv'\n");
+                       exit (1);
+               }
+       }
+}
+
 MonoDomain *
 mini_init (const char *filename)
 {
@@ -9569,8 +9889,13 @@ mini_init (const char *filename)
 
        mono_arch_cpu_init ();
 
+       mono_init_trampolines ();
+
        if (!g_thread_supported ())
                g_thread_init (NULL);
+
+       if (getenv ("MONO_DEBUG") != NULL)
+               mini_parse_debug_options ();
        
        MONO_GC_PRE_INIT ();
 
@@ -9598,6 +9923,8 @@ mini_init (const char *filename)
        mono_install_handler (mono_arch_get_throw_exception ());
 #endif
        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);
 
        domain = mono_init_from_assembly (filename, filename);
        mono_icall_init ();
@@ -9629,6 +9956,7 @@ mini_init (const char *filename)
        mono_register_jit_icall (mono_trace_enter_method, "mono_trace_enter_method", NULL, TRUE);
        mono_register_jit_icall (mono_trace_leave_method, "mono_trace_leave_method", NULL, TRUE);
        mono_register_jit_icall (mono_get_lmf_addr, "mono_get_lmf_addr", helper_sig_ptr_void, TRUE);
+       mono_register_jit_icall (mono_jit_thread_attach, "mono_jit_thread_attach", helper_sig_void_void, TRUE);
        mono_register_jit_icall (mono_domain_get, "mono_domain_get", helper_sig_domain_get, TRUE);
 
        mono_register_jit_icall (mono_arch_get_throw_exception (), "mono_arch_throw_exception", helper_sig_void_obj, TRUE);
@@ -9650,13 +9978,15 @@ mini_init (const char *filename)
         * when adding emulation for some opcodes, remember to also add a dummy
         * rule to the burg files, because we need the arity information to be correct.
         */
+#ifndef MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS
        mono_register_opcode_emulation (OP_LMUL, "__emul_lmul", helper_sig_long_long_long, mono_llmult, TRUE);
-       mono_register_opcode_emulation (OP_LMUL_OVF_UN, "__emul_lmul_ovf_un", helper_sig_long_long_long, mono_llmult_ovf_un, FALSE);
-       mono_register_opcode_emulation (OP_LMUL_OVF, "__emul_lmul_ovf", helper_sig_long_long_long, mono_llmult_ovf, FALSE);
        mono_register_opcode_emulation (OP_LDIV, "__emul_ldiv", helper_sig_long_long_long, mono_lldiv, FALSE);
        mono_register_opcode_emulation (OP_LDIV_UN, "__emul_ldiv_un", helper_sig_long_long_long, mono_lldiv_un, FALSE);
        mono_register_opcode_emulation (OP_LREM, "__emul_lrem", helper_sig_long_long_long, mono_llrem, FALSE);
        mono_register_opcode_emulation (OP_LREM_UN, "__emul_lrem_un", helper_sig_long_long_long, mono_llrem_un, FALSE);
+       mono_register_opcode_emulation (OP_LMUL_OVF_UN, "__emul_lmul_ovf_un", helper_sig_long_long_long, mono_llmult_ovf_un, FALSE);
+       mono_register_opcode_emulation (OP_LMUL_OVF, "__emul_lmul_ovf", helper_sig_long_long_long, mono_llmult_ovf, FALSE);
+#endif
 
 #ifndef MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
        mono_register_opcode_emulation (OP_LSHL, "__emul_lshl", helper_sig_long_long_int, mono_lshl, TRUE);
@@ -9693,14 +10023,12 @@ mini_init (const char *filename)
 #endif
 
        /* other jit icalls */
+       mono_register_jit_icall (mono_delegate_ctor, "mono_delegate_ctor", helper_sig_obj_obj_obj_ptr, FALSE);
        mono_register_jit_icall (mono_class_static_field_address , "mono_class_static_field_address", 
                                 helper_sig_ptr_ptr_ptr, FALSE);
        mono_register_jit_icall (mono_ldtoken_wrapper, "mono_ldtoken_wrapper", helper_sig_ptr_ptr_ptr_ptr, FALSE);
        mono_register_jit_icall (mono_get_special_static_data, "mono_get_special_static_data", helper_sig_ptr_int, FALSE);
        mono_register_jit_icall (mono_ldstr, "mono_ldstr", helper_sig_ldstr, FALSE);
-       mono_register_jit_icall (helper_memcpy, "helper_memcpy", helper_sig_memcpy, FALSE);
-       mono_register_jit_icall (helper_memset, "helper_memset", helper_sig_memset, FALSE);
-       mono_register_jit_icall (helper_initobj, "helper_initobj", helper_sig_initobj, FALSE);
        mono_register_jit_icall (helper_stelem_ref, "helper_stelem_ref", helper_sig_stelem_ref, FALSE);
        mono_register_jit_icall (helper_stelem_ref_check, "helper_stelem_ref_check", helper_sig_stelem_ref_check, FALSE);
        mono_register_jit_icall (mono_object_new, "mono_object_new", helper_sig_object_new, FALSE);
@@ -9762,6 +10090,15 @@ print_jit_stats (void)
                         mono_stats.inflated_method_count);
                g_print ("Inflated types:         %ld\n", mono_stats.inflated_type_count);
                g_print ("Generics metadata size: %ld\n", mono_stats.generics_metadata_size);
+
+               if (mono_use_security_manager) {
+                       g_print ("\nDecl security check   : %ld\n", mono_jit_stats.cas_declsec_check);
+                       g_print ("LinkDemand (user)     : %ld\n", mono_jit_stats.cas_linkdemand);
+                       g_print ("LinkDemand (icall)    : %ld\n", mono_jit_stats.cas_linkdemand_icall);
+                       g_print ("LinkDemand (pinvoke)  : %ld\n", mono_jit_stats.cas_linkdemand_pinvoke);
+                       g_print ("LinkDemand (aptc)     : %ld\n", mono_jit_stats.cas_linkdemand_aptc);
+                       g_print ("Demand (code gen)     : %ld\n", mono_jit_stats.cas_demand_generation);
+               }
        }
 }
 
@@ -9813,10 +10150,16 @@ mono_set_defaults (int verbose_level, guint32 opts)
 static void
 mono_precompile_assembly (MonoAssembly *ass, void *user_data)
 {
+       GHashTable *assemblies = (GHashTable*)user_data;
        MonoImage *image = mono_assembly_get_image (ass);
        MonoMethod *method, *invoke;
        int i, count = 0;
 
+       if (g_hash_table_lookup (assemblies, ass))
+               return;
+
+       g_hash_table_insert (assemblies, ass, ass);
+
        if (mini_verbose > 0)
                printf ("PRECOMPILE: %s.\n", mono_image_get_filename (image));
 
@@ -9841,9 +10184,20 @@ mono_precompile_assembly (MonoAssembly *ass, void *user_data)
                        mono_compile_method (invoke);
                }
        }
+
+       /* Load and precompile referenced assemblies as well */
+       for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_ASSEMBLYREF); ++i) {
+               mono_assembly_load_reference (image, i);
+               if (image->references [i])
+                       mono_precompile_assembly (image->references [i], assemblies);
+       }
 }
 
 void mono_precompile_assemblies ()
 {
-       mono_assembly_foreach ((GFunc)mono_precompile_assembly, NULL);
+       GHashTable *assemblies = g_hash_table_new (NULL, NULL);
+
+       mono_assembly_foreach ((GFunc)mono_precompile_assembly, assemblies);
+
+       g_hash_table_destroy (assemblies);
 }