2007-04-11 Martin Baulig <martin@ximian.com>
[mono.git] / mono / mini / mini.c
index 881a32f7f7f6fc6252653f4ca09977fa2c788ec6..3db26016be6916051fc83df8484df66823b41208 100644 (file)
 #include <pthread.h>
 #endif
 
+#ifdef PLATFORM_WIN32
+#define _WIN32_WINNT 0x0500
+#endif
+
 #ifdef HAVE_VALGRIND_MEMCHECK_H
 #include <valgrind/memcheck.h>
 #endif
@@ -92,6 +96,7 @@ static gpointer mono_jit_compile_method_with_opt (MonoMethod *method, guint32 op
 static gpointer mono_jit_compile_method (MonoMethod *method);
 static gpointer mono_jit_find_compiled_method (MonoDomain *domain, MonoMethod *method);
 static gpointer mono_create_jit_trampoline_in_domain (MonoDomain *domain, MonoMethod *method);
+inline static int mono_emit_jit_icall (MonoCompile *cfg, MonoBasicBlock *bblock, gconstpointer func, MonoInst **args, const guint8 *ip);
 
 static void handle_stobj (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *dest, MonoInst *src, 
                          const unsigned char *ip, MonoClass *klass, gboolean to_end, gboolean native, gboolean write_barrier);
@@ -228,13 +233,35 @@ get_method_from_ip (void *ip)
        return res;
 }
 
+/** 
+ * mono_pmip:
+ * @ip: an instruction pointer address
+ *
+ * This method is used from a debugger to get the name of the
+ * method at address @ip.   This routine is typically invoked from
+ * a debugger like this:
+ *
+ * (gdb) print mono_pmip ($pc)
+ *
+ * Returns: the name of the method at address @ip.
+ */
 G_GNUC_UNUSED char *
 mono_pmip (void *ip)
 {
        return get_method_from_ip (ip);
 }
 
-/* debug function */
+/** 
+ * mono_print_method_from_ip
+ * @ip: an instruction pointer address
+ *
+ * This method is used from a debugger to get the name of the
+ * method at address @ip.
+ *
+ * This prints the name of the method at address @ip in the standard
+ * output.  Unlike mono_pmip which returns a string, this routine
+ * prints the value on the standard output. 
+ */
 void
 mono_print_method_from_ip (void *ip)
 {
@@ -866,9 +893,11 @@ mono_find_block_region (MonoCompile *cfg, int offset)
                        return ((i + 1) << 8) | MONO_REGION_FILTER | clause->flags;
                           
                if (MONO_OFFSET_IN_HANDLER (clause, offset)) {
-                       if (clause->flags & MONO_EXCEPTION_CLAUSE_FINALLY)
+                       if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY)
                                return ((i + 1) << 8) | MONO_REGION_FINALLY | clause->flags;
-                       else
+                       else if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
+                               return ((i + 1) << 8) | MONO_REGION_FAULT | clause->flags;
+                       else if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE)
                                return ((i + 1) << 8) | MONO_REGION_CATCH | clause->flags;
                }
        }
@@ -1318,11 +1347,15 @@ type_from_op (MonoInst *ins) {
                        ins->opcode = OP_LCOMPARE;
                return;
        case OP_CEQ:
+               ins->type = bin_comp_table [ins->inst_i0->type] [ins->inst_i1->type] ? STACK_I4: STACK_INV;
+               ins->opcode += ceqops_op_map [ins->inst_i0->type];
+               return;
+               
        case OP_CGT:
        case OP_CGT_UN:
        case OP_CLT:
        case OP_CLT_UN:
-               ins->type = bin_comp_table [ins->inst_i0->type] [ins->inst_i1->type] ? STACK_I4: STACK_INV;
+               ins->type = (bin_comp_table [ins->inst_i0->type] [ins->inst_i1->type] & 1) ? STACK_I4: STACK_INV;
                ins->opcode += ceqops_op_map [ins->inst_i0->type];
                return;
        /* unops */
@@ -1382,8 +1415,12 @@ type_from_op (MonoInst *ins) {
                ins->type = STACK_PTR;
                switch (ins->inst_i0->type) {
                case STACK_I4:
+                       break;
                case STACK_PTR:
                case STACK_MP:
+#if SIZEOF_VOID_P == 8
+                       ins->opcode = OP_LCONV_TO_U;
+#endif
                        break;
                case STACK_I8:
                        ins->opcode = OP_LCONV_TO_U;
@@ -1599,7 +1636,8 @@ mono_compile_create_var (MonoCompile *cfg, MonoType *type, int opcode)
        MONO_INIT_VARINFO (cfg->vars [num], num);
 
        cfg->num_varinfo++;
-       //g_print ("created temp %d of type %s\n", num, mono_type_get_name (type));
+       if (cfg->verbose_level > 2)
+               g_print ("created temp %d of type %s\n", num, mono_type_get_name (type));
        return inst;
 }
 
@@ -1645,18 +1683,21 @@ type_from_stack_type (MonoInst *ins) {
        case STACK_R8: return &mono_defaults.double_class->byval_arg;
        case STACK_MP:
                /* 
-                * FIXME: This doesn't work because mono_class_from_mono_type ()
-                * returns the original klass for a byref type, not a 'byref' class,
-                * causing the JIT to create variables with the wrong type, for
-                * example.
+                * this if used to be commented without any specific reason, but
+                * it breaks #80235 when commented
                 */
-               /*
                if (ins->klass)
                        return &ins->klass->this_arg;
                else
-               */
                        return &mono_defaults.object_class->this_arg;
-       case STACK_OBJ: return &mono_defaults.object_class->byval_arg;
+       case STACK_OBJ:
+               /* ins->klass may not be set for ldnull.
+                * Also, if we have a boxed valuetype, we want an object lass,
+                * not the valuetype class
+                */
+               if (ins->klass && !ins->klass->valuetype)
+                       return &ins->klass->byval_arg;
+               return &mono_defaults.object_class->byval_arg;
        case STACK_VTYPE: return &ins->klass->byval_arg;
        default:
                g_error ("stack type %d to montype not handled\n", ins->type);
@@ -1670,7 +1711,7 @@ mono_type_from_stack_type (MonoInst *ins) {
 }
 
 static MonoClass*
-array_access_to_klass (int opcode)
+array_access_to_klass (int opcode, MonoInst *array_obj)
 {
        switch (opcode) {
        case CEE_LDELEM_U1:
@@ -1701,8 +1742,13 @@ array_access_to_klass (int opcode)
        case CEE_STELEM_R8:
                return mono_defaults.double_class;
        case CEE_LDELEM_REF:
-       case CEE_STELEM_REF:
+       case CEE_STELEM_REF: {
+               MonoClass *klass = array_obj->klass;
+               /* FIXME: add assert */
+               if (klass && klass->rank)
+                       return klass->element_class;
                return mono_defaults.object_class;
+       }
        default:
                g_assert_not_reached ();
        }
@@ -1962,11 +2008,16 @@ handle_stack_args (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst **sp, int coun
                                 * in the inlined methods do not inherit their in_stack from
                                 * the bblock they are inlined to. See bug #58863 for an
                                 * example.
+                                * This hack is disabled since it also prevents proper tracking of types.
                                 */
+#if 1
+                               bb->out_stack [i] = mono_compile_create_var (cfg, type_from_stack_type (sp [i]), OP_LOCAL);
+#else
                                if (cfg->inlined_method)
                                        bb->out_stack [i] = mono_compile_create_var (cfg, type_from_stack_type (sp [i]), OP_LOCAL);
                                else
                                        bb->out_stack [i] = mono_compile_get_interface_var (cfg, i, sp [i]);
+#endif
                        }
                }
        }
@@ -2194,9 +2245,20 @@ target_type_is_incompatible (MonoCompile *cfg, MonoType *target, MonoInst *arg)
                if (arg->type != STACK_I4 && arg->type != STACK_PTR)
                        return 1;
                return 0;
-       case MONO_TYPE_CLASS:
-       case MONO_TYPE_STRING:
        case MONO_TYPE_OBJECT:
+               if (arg->type != STACK_OBJ)
+                       return 1;
+               return 0;
+       case MONO_TYPE_STRING:
+               if (arg->type != STACK_OBJ)
+                       return 1;
+               /* ldnull has arg->klass unset */
+               /*if (arg->klass && arg->klass != mono_defaults.string_class) {
+                       G_BREAKPOINT ();
+                       return 1;
+               }*/
+               return 0;
+       case MONO_TYPE_CLASS:
        case MONO_TYPE_SZARRAY:
        case MONO_TYPE_ARRAY:    
                if (arg->type != STACK_OBJ)
@@ -2229,9 +2291,11 @@ target_type_is_incompatible (MonoCompile *cfg, MonoType *target, MonoInst *arg)
                return 0;
        case MONO_TYPE_GENERICINST:
                if (mono_type_generic_inst_is_valuetype (simple_type)) {
+                       klass = mono_class_from_mono_type (simple_type);
+                       if (klass->enumtype)
+                               return target_type_is_incompatible (cfg, klass->enum_basetype, arg);
                        if (arg->type != STACK_VTYPE)
                                return 1;
-                       klass = mono_class_from_mono_type (simple_type);
                        if (klass != arg->klass)
                                return 1;
                        return 0;
@@ -2410,13 +2474,31 @@ mono_emit_call_args (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethodSignatu
        MonoInst *arg;
 
        MONO_INST_NEW_CALL (cfg, call, ret_type_to_call_opcode (sig->ret, calli, virtual));
-       
+
+#ifdef MONO_ARCH_SOFT_FLOAT
+       /* we need to convert the r4 value to an int value */
+       {
+               int i;
+               for (i = 0; i < sig->param_count; ++i) {
+                       if (sig->params [i]->type == MONO_TYPE_R4) {
+                               MonoInst *iargs [1];
+                               int temp;
+                               iargs [0] = args [i + sig->hasthis];
+
+                               temp = mono_emit_jit_icall (cfg, bblock, mono_fload_r4_arg, iargs, ip);
+                               NEW_TEMPLOAD (cfg, arg, temp);
+                               args [i + sig->hasthis] = arg;
+                       }
+               }
+       }
+#endif
+
        call->inst.cil_code = ip;
        call->args = args;
        call->signature = sig;
        call = mono_arch_call_opcode (cfg, bblock, call, virtual);
        type_to_eval_stack_type (sig->ret, &call->inst);
-       
+
        for (arg = call->out_args; arg;) {
                MonoInst *narg = arg->next;
                arg->next = NULL;
@@ -2582,49 +2664,6 @@ mono_emulate_opcode (MonoCompile *cfg, MonoInst *tree, MonoInst **iargs, MonoJit
        }
 }
 
-static MonoMethodSignature *
-mono_get_element_address_signature (int arity)
-{
-       static GHashTable *sighash = NULL;
-       MonoMethodSignature *res;
-       int i;
-
-       mono_jit_lock ();
-       if (!sighash) {
-               sighash = g_hash_table_new (NULL, NULL);
-       }
-       else if ((res = g_hash_table_lookup (sighash, GINT_TO_POINTER (arity)))) {
-               LeaveCriticalSection (&jit_mutex);
-               return res;
-       }
-
-       res = mono_metadata_signature_alloc (mono_defaults.corlib, arity + 1);
-
-       res->pinvoke = 1;
-#ifdef MONO_ARCH_VARARG_ICALLS
-       /* Only set this only some archs since not all backends can handle varargs+pinvoke */
-       res->call_convention = MONO_CALL_VARARG;
-#endif
-       res->params [0] = &mono_defaults.array_class->byval_arg; 
-
-#ifdef PLATFORM_WIN32
-       /* 
-        * The default pinvoke calling convention is STDCALL but we need CDECL.
-        */
-       res->call_convention = MONO_CALL_C;
-#endif
-
-       for (i = 1; i <= arity; i++)
-               res->params [i] = &mono_defaults.int_class->byval_arg;
-
-       res->ret = &mono_defaults.int_class->byval_arg;
-
-       g_hash_table_insert (sighash, GINT_TO_POINTER (arity), res);
-       mono_jit_unlock ();
-
-       return res;
-}
-
 static MonoMethodSignature *
 mono_get_array_new_va_signature (int arity)
 {
@@ -2686,7 +2725,7 @@ handle_load_float (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *ptr, cons
 }
 
 #define LDLOC_SOFT_FLOAT(cfg,ins,idx,ip) do {\
-               if (header->locals [(idx)]->type == MONO_TYPE_R4) {     \
+               if (header->locals [(idx)]->type == MONO_TYPE_R4 && !header->locals [(idx)]->byref) {   \
                        int temp;       \
                        NEW_LOCLOADA (cfg, (ins), (idx));       \
                        temp = handle_load_float (cfg, bblock, (ins), (ip));    \
@@ -2694,7 +2733,7 @@ handle_load_float (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *ptr, cons
                }       \
        } while (0)
 #define STLOC_SOFT_FLOAT(cfg,ins,idx,ip) do {\
-               if (header->locals [(idx)]->type == MONO_TYPE_R4) {     \
+               if (header->locals [(idx)]->type == MONO_TYPE_R4 && !header->locals [(idx)]->byref) {   \
                        int temp;       \
                        NEW_LOCLOADA (cfg, (ins), (idx));       \
                        handle_store_float (cfg, bblock, (ins), *sp, (ip));     \
@@ -2702,17 +2741,26 @@ handle_load_float (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *ptr, cons
                }       \
        } while (0)
 #define LDARG_SOFT_FLOAT(cfg,ins,idx,ip) do {\
-               if (param_types [(idx)]->type == MONO_TYPE_R4) {        \
+               if (param_types [(idx)]->type == MONO_TYPE_R4 && !param_types [(idx)]->byref) { \
                        int temp;       \
                        NEW_ARGLOADA (cfg, (ins), (idx));       \
                        temp = handle_load_float (cfg, bblock, (ins), (ip));    \
                        NEW_TEMPLOAD (cfg, (ins), temp);        \
                }       \
        } while (0)
+#define STARG_SOFT_FLOAT(cfg,ins,idx,ip) do {\
+               if (param_types [(idx)]->type == MONO_TYPE_R4 && !param_types [(idx)]->byref) { \
+                       int temp;       \
+                       NEW_ARGLOADA (cfg, (ins), (idx));       \
+                       handle_store_float (cfg, bblock, (ins), *sp, (ip));     \
+                       MONO_INST_NEW (cfg, (ins), CEE_NOP);    \
+               }       \
+       } while (0)
 #else
 #define LDLOC_SOFT_FLOAT(cfg,ins,idx,ip)
 #define STLOC_SOFT_FLOAT(cfg,ins,idx,ip)
 #define LDARG_SOFT_FLOAT(cfg,ins,idx,ip)
+#define STARG_SOFT_FLOAT(cfg,ins,idx,ip)
 #endif
 
 static MonoMethod*
@@ -2916,6 +2964,11 @@ handle_box (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *val, const gucha
        vstore->inst_left = add;
        vstore->inst_right = val;
 
+#ifdef MONO_ARCH_SOFT_FLOAT
+       if (vstore->opcode == CEE_STIND_R4) {
+               handle_store_float (cfg, bblock, add, val, ip);
+       } else
+#endif
        if (vstore->opcode == CEE_STOBJ) {
                handle_stobj (cfg, bblock, add, val, ip, klass, FALSE, FALSE, TRUE);
        } else
@@ -3023,11 +3076,21 @@ mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method)
            MONO_TYPE_ISSTRUCT (signature->ret))
                return FALSE;
 
+#ifdef MONO_ARCH_SOFT_FLOAT
+       /* this complicates things, fix later */
+       if (signature->ret->type == MONO_TYPE_R4)
+               return FALSE;
+#endif
        /* its not worth to inline methods with valuetype arguments?? */
        for (i = 0; i < signature->param_count; i++) {
                if (MONO_TYPE_ISSTRUCT (signature->params [i])) {
                        return FALSE;
                }
+#ifdef MONO_ARCH_SOFT_FLOAT
+               /* this complicates things, fix later */
+               if (signature->params [i]->type == MONO_TYPE_R4)
+                       return FALSE;
+#endif
        }
 
        /*
@@ -3103,10 +3166,8 @@ mini_get_ldelema_ins (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *cmet
 {
        int temp, rank;
        MonoInst *addr;
-       MonoMethodSignature *esig;
-       char icall_name [256];
-       char *name;
-       MonoJitICallInfo *info;
+       MonoMethod *addr_method;
+       int element_size;
 
        rank = mono_method_signature (cmethod)->param_count - (is_set? 1: 0);
 
@@ -3136,26 +3197,12 @@ mini_get_ldelema_ins (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *cmet
 #endif
        }
 
-       /* Need to register the icall so it gets an icall wrapper */
-       sprintf (icall_name, "ves_array_element_address_%d", rank);
-
-       mono_jit_lock ();
-       info = mono_find_jit_icall_by_name (icall_name);
-       if (info == NULL) {
-               esig = mono_get_element_address_signature (rank);
-               name = g_strdup (icall_name);
-               info = mono_register_jit_icall (ves_array_element_address, name, esig, FALSE);
-
-               g_hash_table_insert (jit_icall_name_hash, name, name);
-       }
-       mono_jit_unlock ();
-
-       /* FIXME: This uses info->sig, but it should use the signature of the wrapper */
-       temp = mono_emit_native_call (cfg, bblock, mono_icall_get_wrapper (info), info->sig, sp, ip, FALSE, FALSE);
-       cfg->flags |= MONO_CFG_HAS_VARARGS;
-
+       element_size = mono_class_array_element_size (cmethod->klass->element_class);
+       addr_method = mono_marshal_get_array_address (rank, element_size);
+       temp = mono_emit_method_call_spilled (cfg, bblock, addr_method, addr_method->signature, sp, ip, NULL);
        NEW_TEMPLOAD (cfg, addr, temp);
        return addr;
+
 }
 
 static MonoJitICallInfo **emul_opcode_map = NULL;
@@ -3262,6 +3309,21 @@ mini_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSigna
                store->inst_left = args [2];
                store->inst_right = load;
                return store;
+       } else if (cmethod->klass->image == mono_defaults.corlib) {
+               if (cmethod->name [0] == 'B' && strcmp (cmethod->name, "Break") == 0
+                               && strcmp (cmethod->klass->name, "Debugger") == 0) {
+                       MONO_INST_NEW (cfg, ins, CEE_BREAK);
+                       return ins;
+               }
+               if (cmethod->name [0] == 'g' && strcmp (cmethod->name, "get_IsRunningOnWindows") == 0
+                               && strcmp (cmethod->klass->name, "Environment") == 0) {
+#ifdef PLATFORM_WIN32
+                       NEW_ICONST (cfg, ins, 1);
+#else
+                       NEW_ICONST (cfg, ins, 0);
+#endif
+                       return ins;
+               }
        }
 
        return mono_arch_get_inst_for_method (cfg, cmethod, fsig, args);
@@ -3698,6 +3760,13 @@ can_access_internals (MonoAssembly *accessing, MonoAssembly* accessed)
 static gboolean
 can_access_member (MonoClass *access_klass, MonoClass *member_klass, int access_level)
 {
+       if (access_klass->generic_class && member_klass->generic_class &&
+           access_klass->generic_class->container_class && member_klass->generic_class->container_class) {
+               if (can_access_member (access_klass->generic_class->container_class,
+                                      member_klass->generic_class->container_class, access_level))
+                       return TRUE;
+       }
+
        /* Partition I 8.5.3.2 */
        /* the access level values are the same for fields and methods */
        switch (access_level) {
@@ -3708,7 +3777,7 @@ can_access_member (MonoClass *access_klass, MonoClass *member_klass, int access_
                return access_klass == member_klass;
        case FIELD_ATTRIBUTE_FAM_AND_ASSEM:
                if (mono_class_has_parent (access_klass, member_klass) &&
-                               can_access_internals (access_klass->image->assembly, member_klass->image->assembly))
+                   can_access_internals (access_klass->image->assembly, member_klass->image->assembly))
                        return TRUE;
                return FALSE;
        case FIELD_ATTRIBUTE_ASSEMBLY:
@@ -3769,6 +3838,73 @@ can_access_method (MonoMethod *method, MonoMethod *called)
        return can;
 }
 
+/*
+ * Check that the IL instructions at ip are the array initialization
+ * sequence and return the pointer to the data and the size.
+ */
+static const char*
+initialize_array_data (MonoMethod *method, gboolean aot, unsigned char *ip, MonoInst *newarr, int *out_size)
+{
+       /*
+        * newarr[System.Int32]
+        * dup
+        * ldtoken field valuetype ...
+        * call void class [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype [mscorlib]System.RuntimeFieldHandle)
+        */
+       if (ip [0] == CEE_DUP && ip [1] == CEE_LDTOKEN && ip [5] == 0x4 && ip [6] == CEE_CALL) {
+               MonoClass *klass = newarr->inst_newa_class;
+               guint32 token = read32 (ip + 7);
+               guint32 rva, field_index;
+               const char *data_ptr;
+               int size = 0;
+               MonoMethod *cmethod;
+
+               if (newarr->inst_newa_len->opcode != OP_ICONST)
+                       return NULL;
+               cmethod = mini_get_method (method, token, NULL, NULL);
+               if (strcmp (cmethod->name, "InitializeArray") || strcmp (cmethod->klass->name, "RuntimeHelpers") || cmethod->klass->image != mono_defaults.corlib)
+                       return NULL;
+               switch (mono_type_get_underlying_type (&klass->byval_arg)->type) {
+               case MONO_TYPE_BOOLEAN:
+               case MONO_TYPE_I1:
+               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
+               case MONO_TYPE_CHAR:
+               case MONO_TYPE_I2:
+               case MONO_TYPE_U2:
+                       size = 2; break;
+               case MONO_TYPE_I4:
+               case MONO_TYPE_U4:
+               case MONO_TYPE_R4:
+                       size = 4; break;
+               case MONO_TYPE_R8:
+#ifdef ARM_FPU_FPA
+                       return NULL; /* stupid ARM FP swapped format */
+#endif
+               case MONO_TYPE_I8:
+               case MONO_TYPE_U8:
+                       size = 8; break;
+#endif
+               default:
+                       return NULL;
+               }
+               size *= newarr->inst_newa_len->inst_c0;
+               *out_size = size;
+               /*g_print ("optimized in %s: size: %d, numelems: %d\n", method->name, size, newarr->inst_newa_len->inst_c0);*/
+               field_index = read32 (ip + 2) & 0xffffff;
+               mono_metadata_field_info (method->klass->image, field_index - 1, NULL, &rva, NULL);
+               data_ptr = mono_image_rva_map (method->klass->image, rva);
+               /*g_print ("field: 0x%08x, rva: %d, rva_ptr: %p\n", read32 (ip + 2), rva, data_ptr);*/
+               /* for aot code we do the lookup on load */
+               if (aot && data_ptr)
+                       return GUINT_TO_POINTER (rva);
+               return data_ptr;
+       }
+       return NULL;
+}
+
 /*
  * mono_method_to_ir: translates IL into basic blocks containing trees
  */
@@ -3832,7 +3968,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
        mono_jit_stats.cil_code_size += header->code_size;
 
        if (sig->is_inflated)
-               generic_context = ((MonoMethodInflated *) method)->context;
+               generic_context = mono_method_get_context (method);
        else if (generic_container)
                generic_context = &generic_container->context;
 
@@ -3892,7 +4028,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                tblock->flags |= BB_EXCEPTION_DEAD_OBJ;
 
                        if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY ||
-                           clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
+                           clause->flags == MONO_EXCEPTION_CLAUSE_FILTER ||
+                           clause->flags == MONO_EXCEPTION_CLAUSE_FAULT) {
                                MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
                                MONO_ADD_INS (tblock, ins);
 
@@ -4247,6 +4384,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        ins->cil_code = ip;
                        if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [ip [1]], *sp))
                                UNVERIFIED;
+                       STARG_SOFT_FLOAT (cfg, ins, ip [1], ip);
                        if (ins->opcode == CEE_STOBJ) {
                                NEW_ARGLOADA (cfg, ins, ip [1]);
                                handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE, FALSE);
@@ -4487,6 +4625,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                } else if (constrained_call) {
                                        cmethod = mono_get_method_constrained (image, token, constrained_call, generic_context, &cil_method);
                                        cmethod = mono_get_inflated_method (cmethod);
+                                       cil_method = cmethod;
                                } else {
                                        cmethod = mini_get_method (method, token, NULL, generic_context);
                                        cil_method = cmethod;
@@ -4607,7 +4746,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                                NEW_TEMPLOAD (cfg, iargs [0], this_temp->inst_c0);
                                NEW_PCONST (cfg, iargs [1], cmethod);
-                               NEW_PCONST (cfg, iargs [2], ((MonoMethodInflated *) cmethod)->context);
+                               NEW_PCONST (cfg, iargs [2], mono_method_get_context (cmethod));
                                NEW_TEMPLOADA (cfg, iargs [3], this_arg_temp->inst_c0);
                                temp = mono_emit_jit_icall (cfg, bblock, mono_helper_compile_generic_method, iargs, ip);
 
@@ -5109,7 +5248,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 #ifdef MONO_ARCH_SOFT_FLOAT
                        if (*ip == CEE_LDIND_R4) {
                                int temp;
-                               ++sp;
+                               --sp;
                                temp = handle_load_float (cfg, bblock, ins->inst_i0, ip);
                                NEW_TEMPLOAD (cfg, *sp, temp);
                                sp++;
@@ -5412,6 +5551,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        n = read32 (ip + 1);
 
                        if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
+                               /* FIXME: moving GC */
                                NEW_PCONST (cfg, ins, mono_method_get_wrapper_data (method, n));
                                ins->cil_code = ip;
                                ins->type = STACK_OBJ;
@@ -6314,6 +6454,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                link_bblock (cfg, bblock, tblock);
                                CHECK_BBLOCK (target, ip, tblock);
                                ins->inst_target_bb = tblock;
+                               GET_BBLOCK (cfg, bbhash, tblock, ip);
+                               link_bblock (cfg, bblock, tblock);
                                if (sp != stack_start) {
                                        handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
                                        sp = stack_start;
@@ -6351,7 +6493,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        ins->inst_newa_class = klass;
                        ins->inst_newa_len = *sp;
                        ins->type = STACK_OBJ;
-                       ins->klass = klass;
+                       ins->klass = mono_array_class_get (klass, 1);
                        ip += 5;
                        *sp++ = ins;
                        /* 
@@ -6360,11 +6502,40 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                         */
                        if (1) {
                                MonoInst *store, *temp, *load;
+                               const char *data_ptr;
+                               int data_size = 0;
                                --sp;
                                temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
                                NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
                                store->cil_code = ins->cil_code;
                                MONO_ADD_INS (bblock, store);
+                               /* 
+                                * we inline/optimize the initialization sequence if possible.
+                                * we should also allocate the array as not cleared, since we spend as much time clearing to 0 as initializing
+                                * for small sizes open code the memcpy
+                                * ensure the rva field is big enough
+                                */
+                               if ((cfg->opt & MONO_OPT_INTRINS) && ip_in_bb (cfg, bblock, ip + 6) && (data_ptr = initialize_array_data (method, cfg->compile_aot, ip, ins, &data_size))) {
+                                       MonoMethod *memcpy_method = get_memcpy_method ();
+                                       MonoInst *data_offset, *add;
+                                       MonoInst *iargs [3];
+                                       NEW_ICONST (cfg, iargs [2], data_size);
+                                       NEW_TEMPLOAD (cfg, load, temp->inst_c0);
+                                       load->cil_code = ins->cil_code;
+                                       NEW_ICONST (cfg, data_offset, G_STRUCT_OFFSET (MonoArray, vector));
+                                       MONO_INST_NEW (cfg, add, OP_PADD);
+                                       add->inst_left = load;
+                                       add->inst_right = data_offset;
+                                       add->cil_code = ip;
+                                       iargs [0] = add;
+                                       if (cfg->compile_aot) {
+                                               NEW_AOTCONST_TOKEN (cfg, iargs [1], MONO_PATCH_INFO_RVA, method->klass->image, GPOINTER_TO_UINT(data_ptr), STACK_PTR, NULL);
+                                       } else {
+                                               NEW_PCONST (cfg, iargs [1], (char*)data_ptr);
+                                       }
+                                       mono_emit_method_call_spilled (cfg, bblock, memcpy_method, memcpy_method->signature, iargs, ip, NULL);
+                                       ip += 11;
+                               }
                                NEW_TEMPLOAD (cfg, load, temp->inst_c0);
                                load->cil_code = ins->cil_code;
                                *sp++ = load;
@@ -6397,6 +6568,10 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                         */
                        if (!klass->valuetype && method->wrapper_type == MONO_WRAPPER_NONE) {
                                MonoInst* check;
+
+                               /* Needed by the code generated in inssel.brg */
+                               mono_get_got_var (cfg);
+
                                MONO_INST_NEW (cfg, check, OP_CHECK_ARRAY_TYPE);
                                check->cil_code = ip;
                                check->klass = klass;
@@ -6454,7 +6629,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        sp -= 2;
                        if (sp [0]->type != STACK_OBJ)
                                UNVERIFIED;
-                       klass = array_access_to_klass (*ip);
+                       klass = array_access_to_klass (*ip, sp [0]);
                        NEW_LDELEMA (cfg, load, sp, klass);
                        load->cil_code = ip;
 #ifdef MONO_ARCH_SOFT_FLOAT
@@ -6493,7 +6668,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        sp -= 3;
                        if (sp [0]->type != STACK_OBJ)
                                UNVERIFIED;
-                       klass = array_access_to_klass (*ip);
+                       klass = array_access_to_klass (*ip, sp [0]);
                        NEW_LDELEMA (cfg, load, sp, klass);
                        load->cil_code = ip;
 #ifdef MONO_ARCH_SOFT_FLOAT
@@ -6817,8 +6992,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                }
                        }
 
-                       /* fixme: call fault handler ? */
-
                        if ((handlers = mono_find_final_block (cfg, ip, target, MONO_EXCEPTION_CLAUSE_FINALLY))) {
                                GList *tmp;
                                for (tmp = handlers; tmp; tmp = tmp->next) {
@@ -6880,7 +7053,11 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                token = read32 (ip + 2);
                                func = mono_method_get_wrapper_data (method, token);
                                info = mono_find_jit_icall_by_addr (func);
-                               g_assert (info);
+                               if (info == NULL){
+                                       g_error ("An attempt has been made to perform an icall to address %p, "
+                                                "but the address has not been registered as an icall\n", info);
+                                       g_assert_not_reached ();
+                               }
 
                                CHECK_STACK (info->sig->param_count);
                                sp -= info->sig->param_count;
@@ -7190,6 +7367,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                ins->cil_code = ip;
                                if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [n], *sp))
                                        UNVERIFIED;
+                               STARG_SOFT_FLOAT (cfg, ins, n, ip);
                                if (ins->opcode == CEE_STOBJ) {
                                        NEW_ARGLOADA (cfg, ins, n);
                                        handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE, FALSE);
@@ -8038,15 +8216,28 @@ mono_dynamic_code_hash_lookup (MonoDomain *domain, MonoMethod *method)
 typedef struct {
        MonoClass *vtype;
        GList *active;
-       GList *slots;
+       GSList *slots;
 } StackSlotInfo;
 
+static inline GSList*
+g_slist_prepend_mempool (MonoMemPool *mp, GSList   *list,
+                                                gpointer  data)
+{
+  GSList *new_list;
+
+  new_list = mono_mempool_alloc (mp, sizeof (GSList));
+  new_list->data = data;
+  new_list->next = list;
+
+  return new_list;
+}
+
 /*
  *  mono_allocate_stack_slots_full:
  *
  *  Allocate stack slots for all non register allocated variables using a
  * linear scan algorithm.
- * Returns: an array of stack offsets which the caller should free.
+ * Returns: an array of stack offsets.
  * STACK_SIZE is set to the amount of stack space needed.
  * STACK_ALIGN is set to the alignment needed by the locals area.
  */
@@ -8063,11 +8254,11 @@ mono_allocate_stack_slots_full (MonoCompile *m, gboolean backward, guint32 *stac
        MonoType *t;
        int nvtypes;
 
-       scalar_stack_slots = g_new0 (StackSlotInfo, MONO_TYPE_PINNED);
-       vtype_stack_slots = g_new0 (StackSlotInfo, 256);
+       scalar_stack_slots = mono_mempool_alloc0 (m->mempool, sizeof (StackSlotInfo) * MONO_TYPE_PINNED);
+       vtype_stack_slots = NULL;
        nvtypes = 0;
 
-       offsets = g_new (gint32, m->num_varinfo);
+       offsets = mono_mempool_alloc (m->mempool, sizeof (gint32) * m->num_varinfo);
        for (i = 0; i < m->num_varinfo; ++i)
                offsets [i] = -1;
 
@@ -8111,6 +8302,8 @@ mono_allocate_stack_slots_full (MonoCompile *m, gboolean backward, guint32 *stac
                                }
                                /* Fall through */
                        case MONO_TYPE_VALUETYPE:
+                               if (!vtype_stack_slots)
+                                       vtype_stack_slots = mono_mempool_alloc0 (m->mempool, sizeof (StackSlotInfo) * 256);
                                for (i = 0; i < nvtypes; ++i)
                                        if (t->data.klass == vtype_stack_slots [i].vtype)
                                                break;
@@ -8123,6 +8316,22 @@ mono_allocate_stack_slots_full (MonoCompile *m, gboolean backward, guint32 *stac
                                        nvtypes ++;
                                }
                                break;
+                       case MONO_TYPE_CLASS:
+                       case MONO_TYPE_OBJECT:
+                       case MONO_TYPE_ARRAY:
+                       case MONO_TYPE_SZARRAY:
+                       case MONO_TYPE_STRING:
+                       case MONO_TYPE_PTR:
+                       case MONO_TYPE_I:
+                       case MONO_TYPE_U:
+#if SIZEOF_VOID_P == 4
+                       case MONO_TYPE_I4:
+#else
+                       case MONO_TYPE_I8:
+#endif
+                               /* Share non-float stack slots of the same size */
+                               slot_info = &scalar_stack_slots [MONO_TYPE_CLASS];
+                               break;
                        default:
                                slot_info = &scalar_stack_slots [t->type];
                        }
@@ -8142,7 +8351,7 @@ mono_allocate_stack_slots_full (MonoCompile *m, gboolean backward, guint32 *stac
                                //printf ("EXPIR  %2d %08x %08x C%d R%d\n", amv->idx, amv->range.first_use.abs_pos, amv->range.last_use.abs_pos, amv->spill_costs, amv->reg);
 
                                slot_info->active = g_list_delete_link (slot_info->active, slot_info->active);
-                               slot_info->slots = g_list_prepend (slot_info->slots, GINT_TO_POINTER (offsets [amv->idx]));
+                               slot_info->slots = g_slist_prepend_mempool (m->mempool, slot_info->slots, GINT_TO_POINTER (offsets [amv->idx]));
                        }
 
                        /* 
@@ -8157,7 +8366,7 @@ mono_allocate_stack_slots_full (MonoCompile *m, gboolean backward, guint32 *stac
                                if (slot_info->slots) {
                                        slot = GPOINTER_TO_INT (slot_info->slots->data);
 
-                                       slot_info->slots = g_list_delete_link (slot_info->slots, slot_info->slots);
+                                       slot_info->slots = slot_info->slots->next;
                                }
 
                                slot_info->active = mono_varlist_insert_sorted (m, slot_info->active, vmv, TRUE);
@@ -8208,15 +8417,15 @@ mono_allocate_stack_slots_full (MonoCompile *m, gboolean backward, guint32 *stac
        }
        g_list_free (vars);
        for (i = 0; i < MONO_TYPE_PINNED; ++i) {
-               g_list_free (scalar_stack_slots [i].active);
-               g_list_free (scalar_stack_slots [i].slots);
+               if (scalar_stack_slots [i].active)
+                       g_list_free (scalar_stack_slots [i].active);
        }
        for (i = 0; i < nvtypes; ++i) {
-               g_list_free (vtype_stack_slots [i].active);
-               g_list_free (vtype_stack_slots [i].slots);
+               if (vtype_stack_slots [i].active)
+                       g_list_free (vtype_stack_slots [i].active);
        }
-       g_free (scalar_stack_slots);
-       g_free (vtype_stack_slots);
+
+       mono_jit_stats.locals_stack_size += offset;
 
        *stack_size = offset;
        return offsets;
@@ -8715,6 +8924,7 @@ mono_patch_info_dup_mp (MonoMemPool *mp, MonoJumpInfo *patch_info)
        memcpy (res, patch_info, sizeof (MonoJumpInfo));
 
        switch (patch_info->type) {
+       case MONO_PATCH_INFO_RVA:
        case MONO_PATCH_INFO_LDSTR:
        case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
        case MONO_PATCH_INFO_LDTOKEN:
@@ -8739,6 +8949,7 @@ mono_patch_info_hash (gconstpointer data)
        const MonoJumpInfo *ji = (MonoJumpInfo*)data;
 
        switch (ji->type) {
+       case MONO_PATCH_INFO_RVA:
        case MONO_PATCH_INFO_LDSTR:
        case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
        case MONO_PATCH_INFO_LDTOKEN:
@@ -8766,6 +8977,7 @@ mono_patch_info_equal (gconstpointer ka, gconstpointer kb)
                return 0;
 
        switch (ji1->type) {
+       case MONO_PATCH_INFO_RVA:
        case MONO_PATCH_INFO_LDSTR:
        case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
        case MONO_PATCH_INFO_LDTOKEN:
@@ -8883,6 +9095,9 @@ mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code,
                target = (char*)vtable->data + patch_info->data.field->offset;
                break;
        }
+       case MONO_PATCH_INFO_RVA:
+               target = mono_image_rva_map (patch_info->data.token->image, patch_info->data.token->token);
+               break;
        case MONO_PATCH_INFO_R4:
        case MONO_PATCH_INFO_R8:
                target = patch_info->data.target;
@@ -9828,8 +10043,7 @@ mini_select_instructions (MonoCompile *cfg)
                        }
                        emit_state (cfg, mbstate, MB_NTERM_stmt);
                }
-               bb->max_ireg = cfg->rs->next_vireg;
-               bb->max_freg = cfg->rs->next_vfreg;
+               bb->max_vreg = cfg->rs->next_vreg;
 
                if (bb->last_ins)
                        bb->last_ins->next = NULL;
@@ -10347,6 +10561,15 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
                g_list_free (regs);
        }
 
+       /* todo: remove code when we have verified that the liveness for try/catch blocks
+        * works perfectly 
+        */
+       /* 
+        * Currently, this can't be commented out since exception blocks are not
+        * processed during liveness analysis.
+        */
+       mono_liveness_handle_exception_clauses (cfg);
+
        if (cfg->opt & MONO_OPT_LINEARS) {
                GList *vars, *regs;
                
@@ -10838,6 +11061,11 @@ mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObjec
        return runtime_invoke (obj, params, exc, compiled_method);
 }
 
+#ifdef MONO_GET_CONTEXT
+#define GET_CONTEXT MONO_GET_CONTEXT
+#endif
+
+#ifndef GET_CONTEXT
 #ifdef PLATFORM_WIN32
 #define GET_CONTEXT \
        struct sigcontext *ctx = (struct sigcontext*)_dummy;
@@ -10854,6 +11082,7 @@ mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObjec
        struct sigcontext *ctx = (struct sigcontext *)++_p;
 #endif
 #endif
+#endif
 
 #ifdef MONO_ARCH_USE_SIGACTION
 #define SIG_HANDLER_SIGNATURE(ftn) ftn (int _dummy, siginfo_t *info, void *context)
@@ -10945,6 +11174,8 @@ SIG_HANDLER_SIGNATURE (sigsegv_signal_handler)
        mono_arch_handle_exception (ctx, exc, FALSE);
 }
 
+#ifndef PLATFORM_WIN32
+
 static void
 SIG_HANDLER_SIGNATURE (sigabrt_signal_handler)
 {
@@ -11014,6 +11245,16 @@ SIG_HANDLER_SIGNATURE (sigquit_signal_handler)
        mono_print_thread_dump (ctx);
 }
 
+static void
+SIG_HANDLER_SIGNATURE (sigusr2_signal_handler)
+{
+       gboolean enabled = mono_trace_is_enabled ();
+
+       mono_trace_enable (!enabled);
+}
+
+#endif
+
 static void
 SIG_HANDLER_SIGNATURE (sigint_signal_handler)
 {
@@ -11025,14 +11266,6 @@ SIG_HANDLER_SIGNATURE (sigint_signal_handler)
        mono_arch_handle_exception (ctx, exc, FALSE);
 }
 
-static void
-SIG_HANDLER_SIGNATURE (sigusr2_signal_handler)
-{
-       gboolean enabled = mono_trace_is_enabled ();
-
-       mono_trace_enable (!enabled);
-}
-
 #ifdef PLATFORM_MACOSX
 
 /*
@@ -11286,6 +11519,26 @@ enable_rtc_timer (gboolean enable)
 }
 #endif
 
+#ifdef PLATFORM_WIN32
+static HANDLE win32_main_thread;
+static MMRESULT win32_timer;
+
+static void CALLBACK
+win32_time_proc (UINT uID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2)
+{
+       CONTEXT context;
+
+       context.ContextFlags = CONTEXT_CONTROL;
+       if (GetThreadContext (win32_main_thread, &context)) {
+#ifdef _WIN64
+               mono_profiler_stat_hit ((guchar *) context.Rip, &context);
+#else
+               mono_profiler_stat_hit ((guchar *) context.Eip, &context);
+#endif
+       }
+}
+#endif
+
 static void
 setup_stat_profiler (void)
 {
@@ -11338,6 +11591,27 @@ setup_stat_profiler (void)
                return;
        inited = 1;
        add_signal_handler (SIGPROF, sigprof_signal_handler);
+#elif defined (PLATFORM_WIN32)
+       static int inited = 0;
+       TIMECAPS timecaps;
+
+       if (inited)
+               return;
+
+       inited = 1;
+       if (timeGetDevCaps (&timecaps, sizeof (timecaps)) != TIMERR_NOERROR)
+               return;
+
+       if ((win32_main_thread = OpenThread (READ_CONTROL | THREAD_GET_CONTEXT, FALSE, GetCurrentThreadId ())) == NULL)
+               return;
+
+       if (timeBeginPeriod (1) != TIMERR_NOERROR)
+               return;
+
+       if ((win32_timer = timeSetEvent (1, 0, win32_time_proc, 0, TIME_PERIODIC)) == 0) {
+               timeEndPeriod (1);
+               return;
+       }
 #endif
 }
 
@@ -11396,7 +11670,7 @@ mini_parse_debug_options (void)
 }
 
 MonoDomain *
-mini_init (const char *filename)
+mini_init (const char *filename, const char *runtime_version)
 {
        MonoDomain *domain;
 
@@ -11514,7 +11788,10 @@ mini_init (const char *filename)
                mono_aot_set_make_unreadable (TRUE);
        }
 
-       domain = mono_init_from_assembly (filename, filename);
+       if (runtime_version)
+               domain = mono_init_version (filename, runtime_version);
+       else
+               domain = mono_init_from_assembly (filename, filename);
        mono_icall_init ();
 
        mono_add_internal_call ("System.Diagnostics.StackFrame::get_frame_info", 
@@ -11627,6 +11904,7 @@ mini_init (const char *filename)
        mono_register_opcode_emulation (OP_FMUL, "__emul_fmul", "double double double", mono_fmul, FALSE);
        mono_register_opcode_emulation (OP_FNEG, "__emul_fneg", "double double", mono_fneg, FALSE);
        mono_register_opcode_emulation (CEE_CONV_R8, "__emul_conv_r8", "double int32", mono_conv_to_r8, FALSE);
+       mono_register_opcode_emulation (CEE_CONV_R4, "__emul_conv_r4", "double int32", mono_conv_to_r4, FALSE);
        mono_register_opcode_emulation (OP_FCONV_TO_R4, "__emul_fconv_to_r4", "double double", mono_fconv_r4, FALSE);
        mono_register_opcode_emulation (OP_FCONV_TO_I1, "__emul_fconv_to_i1", "int8 double", mono_fconv_i1, FALSE);
        mono_register_opcode_emulation (OP_FCONV_TO_I2, "__emul_fconv_to_i2", "int16 double", mono_fconv_i2, FALSE);
@@ -11653,6 +11931,7 @@ mini_init (const char *filename)
 
        register_icall (mono_fload_r4, "mono_fload_r4", "double ptr", FALSE);
        register_icall (mono_fstore_r4, "mono_fstore_r4", "void double ptr", FALSE);
+       register_icall (mono_fload_r4_arg, "mono_fload_r4_arg", "uint32 double", FALSE);
 #endif
 
 #if SIZEOF_VOID_P == 4
@@ -11717,7 +11996,8 @@ print_jit_stats (void)
                g_print ("Allocated code size:    %ld\n", mono_jit_stats.allocated_code_size);
                g_print ("Inlineable methods:     %ld\n", mono_jit_stats.inlineable_methods);
                g_print ("Inlined methods:        %ld\n", mono_jit_stats.inlined_methods);
-               
+               g_print ("Locals stack size:      %ld\n", mono_jit_stats.locals_stack_size);
+
                g_print ("\nCreated object count:   %ld\n", mono_stats.new_object_count);
                g_print ("Initialized classes:    %ld\n", mono_stats.initialized_class_count);
                g_print ("Used classes:           %ld\n", mono_stats.used_class_count);