2009-12-25 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mono / mini / aot-runtime.c
index 25e6bd997ca52074bb678625e359e9b4c9f8a304..6efb5bd22c79bc576592a14168d371e023102fd3 100644 (file)
@@ -362,6 +362,8 @@ decode_klass_ref (MonoAotModule *module, guint8 *buf, guint8 **endbuf)
                                MonoType *type;
 
                                gclass = decode_klass_ref (module, p, &p);
+                               if (!gclass)
+                                       return NULL;
                                g_assert (gclass->generic_container);
 
                                memset (&ctx, 0, sizeof (ctx));
@@ -1515,8 +1517,10 @@ decode_eh_frame (MonoAotModule *amodule, MonoDomain *domain,
        guint32 eh_frame_ptr;
        int fde_count;
        gint32 *table;
-       int pos, left, right, offset, offset1, offset2;
+       int i, pos, left, right, offset, offset1, offset2;
        guint32 unw_len, code_len;
+       MonoJitExceptionInfo *ei;
+       guint32 ei_len;
 
        g_assert (amodule->eh_frame_hdr);
 
@@ -1563,7 +1567,7 @@ decode_eh_frame (MonoAotModule *amodule, MonoDomain *domain,
 
        eh_frame = amodule->eh_frame_hdr + table [(pos * 2) + 1];
 
-       unwind_info = mono_unwind_get_ops_from_fde (eh_frame, &unw_len, &code_len);
+       unwind_info = mono_unwind_decode_fde (eh_frame, &unw_len, &code_len, &ei, &ei_len);
 
        jinfo->code_size = code_len;
        jinfo->used_regs = mono_cache_unwind_info (unwind_info, unw_len);
@@ -1572,6 +1576,15 @@ decode_eh_frame (MonoAotModule *amodule, MonoDomain *domain,
        jinfo->domain_neutral = 0;
        /* This signals that used_regs points to a normal cached unwind info */
        jinfo->from_aot = 0;
+
+       g_assert (ei_len == jinfo->num_clauses);
+       for (i = 0; i < jinfo->num_clauses; ++i) {
+               MonoJitExceptionInfo *jei = &jinfo->clauses [i];
+
+               jei->try_start = ei [i].try_start;
+               jei->try_end = ei [i].try_end;
+               jei->handler_start = ei [i].handler_start;
+       }
 }
  
 #ifdef TARGET_ARM
@@ -1579,47 +1592,79 @@ decode_eh_frame (MonoAotModule *amodule, MonoDomain *domain,
 /* The offsets in the table are 31 bits long, have to extend them to 32 */
 #define EXTEND_PREL31(val) ((((gint32)(val)) << 1) >> 1)
 
+static inline guint32
+decode_uleb128 (guint8 *buf, guint8 **endbuf)
+{
+       guint8 *p = buf;
+       guint32 res = 0;
+       int shift = 0;
+
+       while (TRUE) {
+               guint8 b = *p;
+               p ++;
+
+               res = res | (((int)(b & 0x7f)) << shift);
+               if (!(b & 0x80))
+                       break;
+               shift += 7;
+       }
+
+       *endbuf = p;
+
+       return res;
+}
+
 static GSList*
 decode_arm_eh_ops (guint8 *unwind_ops, int nops)
 {
-       int i, cfa_reg, cfa_offset;
-       int vsp_offset;
+       int i, vsp_reg, vsp_offset;
        GSList *ops;
        gint32 *reg_offsets;
 
        /*
         * Have to convert the ARM unwind info into DWARF unwind info.
-        * The ARM unwind opcodes manipulate a virtual stack pointer (vsp). After all
-        * the opcodes have been executed, vsp should be equal to the value of the
-        * DWARF cfa.
+        * The ARM unwind info specifies a simple set of instructions which need to be
+        * executed during unwinding. It manipulates a virtual stack pointer (vsp). The
+        * connection with DWARF unwind info is the following: after all ARM unwind
+        * opcodes have been executed, the stack should be completely unwound, i.e.
+        * vsp == DWARF CFA. This allows us to construct the DWARF opcodes corresponding
+        * to the ARM opcodes.
+        * The ARM unwind info is not instruction precise, i. e. it can't handle
+        * async exceptions etc.
         */
+       /* The reg used to compute the initial value of vsp */
+       vsp_reg = ARMREG_SP;
+       /* The offset between vsp_reg and the CFA */
+       vsp_offset = 0;
 
-       /* The offsets from the initial value of vsp */
+       /* The register save offsets from the initial value of vsp */
        reg_offsets = g_new0 (gint32, 16);
        for (i = 0; i < 16; ++i)
                reg_offsets [i] = -1;
 
-       /* The ARM unwind info is not instruction precise */
-       cfa_reg = ARMREG_SP;
-       cfa_offset = 0;
-       vsp_offset = 0;
-
        /* section 9.3 in the ehabi doc */
        for (i = 0; i < nops; ++i) {
                guint8 op = unwind_ops [i];
 
                if ((op >> 6) == 0) {
                        /* vsp = vsp + (xxxxxx << 2) + 4. */
-                       vsp_offset += ((op & 0xfff) << 2) + 4;
+                       vsp_offset += ((op & 0x3f) << 2) + 4;
+               } else if ((op >> 6) == 1) {
+                       /* vsp = vsp - (xxxxxx << 2) - 4. */
+                       vsp_offset -= ((op & 0x3f) << 2) + 4;
+               } else if (op == 0xb2) {
+                       /* vsp = vsp = vsp + 0x204 + (uleb128 << 2) */
+                       guint8 *p = unwind_ops + i + 1;
+                       guint32 v = decode_uleb128 (p, &p);
+
+                       vsp_offset += 0x204 + (v << 2);
+                       i = (p - unwind_ops) - 1;
                } else if (op >= 0x80 && op <= 0x8f) {
                        /* pop registers */
                        guint8 op2;
                        GSList *regs;
                        int j;
 
-                       /* FIXME: */
-                       g_assert (i == 0 || i == 1);
-
                        g_assert (i + 1 < nops);
                        op2 = unwind_ops [i + 1];
 
@@ -1645,8 +1690,6 @@ decode_arm_eh_ops (guint8 *unwind_ops, int nops)
                        int j;
 
                        /* pop r4-r[4 + nnn], r14 */
-                       /* FIXME: */
-                       g_assert (i == 0 || i == 1);
 
                        regs = NULL;
                        for (j = 0; j <= (op & 0x7); ++j)
@@ -1662,21 +1705,28 @@ decode_arm_eh_ops (guint8 *unwind_ops, int nops)
                } else if (op == 0xb0) {
                        /* finish */
                        break;
+               } else if (op >= 0x90 && op <= 0x9f && op != 0x9d && op != 0x9f) {
+                       /* vsp = <reg> */
+                       vsp_reg = op & 0xf;
+                       vsp_offset = 0;
                } else {
-                       for (i = 0; i < nops; ++i)
-                               printf ("%x ", unwind_ops [i]);
-                       printf ("\n");
+                       int j;
+
+                       for (j = 0; j < nops; ++j)
+                               printf ("%x ", unwind_ops [j]);
+                       printf (" / %d\n", i);
                        g_assert_not_reached ();
                }
        }
 
        ops = NULL;
 
-       /* sp + vsp_offset = CFA */
-       mono_add_unwind_op_def_cfa (ops, (guint8*)NULL, (guint8*)NULL, ARMREG_SP, vsp_offset);                  
+       /* vsp_reg + vsp_offset = CFA */
+       mono_add_unwind_op_def_cfa (ops, (guint8*)NULL, (guint8*)NULL, vsp_reg, vsp_offset);
+
        for (i = 0; i < 16; ++i) {
                if (reg_offsets [i] != -1)
-                       /* The reg is saved at sp + reg_offset [i] == CFA - (vsp_offset - reg_offset [i]) */
+                       /* The reg is saved at vsp_reg + reg_offset [i] == CFA - (vsp_offset - reg_offset [i]) */
                        mono_add_unwind_op_offset (ops, (guint8*)NULL, (guint8*)NULL, i, - (vsp_offset - reg_offsets [i]));
        }
 
@@ -1769,7 +1819,7 @@ decode_arm_exidx (MonoAotModule *amodule, MonoDomain *domain,
                        /* non-inline entry */
                        guint8 *data = (guint8*)&table [(pos * 2) + 1] + EXTEND_PREL31 (entry);
 
-                       entry = *(guint32*)data;
+                       entry = ((guint32*)data) [0];
 
                        /* compact model, personality routine 1 */
                        g_assert ((entry & 0xff000000) == 0x81000000);
@@ -1782,6 +1832,7 @@ decode_arm_exidx (MonoAotModule *amodule, MonoDomain *domain,
                        unwind_ops [1] = (entry & 0x000000ff) >> 0;
 
                        for (i = 0; i < nwords; ++i) {
+                               entry = ((guint32*)data) [1 + i];
                                unwind_ops [(i * 4) + 2] = (entry & 0xff000000) >> 24;
                                unwind_ops [(i * 4) + 2 + 1] = (entry & 0x00ff0000) >> 16;
                                unwind_ops [(i * 4) + 2 + 2] = (entry & 0x0000ff00) >> 8;
@@ -1915,19 +1966,25 @@ decode_exception_debug_info (MonoAotModule *amodule, MonoDomain *domain,
        }
 
        if (has_seq_points) {
-               GPtrArray *seq_points;
-               int il_offset, native_offset, last_il_offset, last_native_offset;
+               MonoSeqPointInfo *seq_points;
+               int il_offset, native_offset, last_il_offset, last_native_offset, j;
 
                int len = decode_value (p, &p);
 
-               seq_points = g_ptr_array_new ();
+               seq_points = g_malloc0 (sizeof (MonoSeqPointInfo) + (len - MONO_ZERO_LEN_ARRAY) * sizeof (SeqPoint));
                last_il_offset = last_native_offset = 0;
-               for (i = 0; i < len; i += 2) {
+               for (i = 0; i < len; ++i) {
+                       SeqPoint *sp = &seq_points->seq_points [i];
                        il_offset = last_il_offset + decode_value (p, &p);
                        native_offset = last_native_offset + decode_value (p, &p);
 
-                       g_ptr_array_add (seq_points, GINT_TO_POINTER (il_offset));
-                       g_ptr_array_add (seq_points, GINT_TO_POINTER (native_offset));
+                       sp->il_offset = il_offset;
+                       sp->native_offset = native_offset;
+                       
+                       sp->next_len = decode_value (p, &p);
+                       sp->next = g_new (int, sp->next_len);
+                       for (j = 0; j < sp->next_len; ++j)
+                               sp->next [j] = decode_value (p, &p);
 
                        last_il_offset = il_offset;
                        last_native_offset = native_offset;
@@ -2562,11 +2619,10 @@ load_method (MonoDomain *domain, MonoAotModule *amodule, MonoImage *image, MonoM
 }
 
 static guint32
-find_extra_method_in_amodule (MonoAotModule *amodule, MonoMethod *method)
+find_extra_method_in_amodule (MonoAotModule *amodule, MonoMethod *method, const char *name)
 {
        guint32 table_size, entry_size, hash;
        guint32 *table, *entry;
-       char *name = NULL;
        guint32 index;
        static guint32 n_extra_decodes;
 
@@ -2577,10 +2633,6 @@ find_extra_method_in_amodule (MonoAotModule *amodule, MonoMethod *method)
        table = amodule->extra_method_table + 1;
        entry_size = 3;
 
-       if (method->wrapper_type) {
-               name = mono_aot_wrapper_name (method);
-       }
-
        hash = mono_aot_method_hash (method) % table_size;
 
        entry = &table [hash * entry_size];
@@ -2651,7 +2703,6 @@ find_extra_method_in_amodule (MonoAotModule *amodule, MonoMethod *method)
                        break;
        }
 
-       g_free (name);
        return index;
 }
 
@@ -2674,12 +2725,18 @@ find_extra_method (MonoMethod *method, MonoAotModule **out_amodule)
        guint32 index;
        GPtrArray *modules;
        int i;
+       char *name = NULL;
+
+       if (method->wrapper_type)
+               name = mono_aot_wrapper_name (method);
 
        /* Try the method's module first */
        *out_amodule = method->klass->image->aot_module;
-       index = find_extra_method_in_amodule (method->klass->image->aot_module, method);
-       if (index != 0xffffff)
+       index = find_extra_method_in_amodule (method->klass->image->aot_module, method, name);
+       if (index != 0xffffff) {
+               g_free (name);
                return index;
+       }
 
        /* 
         * Try all other modules.
@@ -2699,7 +2756,7 @@ find_extra_method (MonoMethod *method, MonoAotModule **out_amodule)
                MonoAotModule *amodule = g_ptr_array_index (modules, i);
 
                if (amodule != method->klass->image->aot_module)
-                       index = find_extra_method_in_amodule (amodule, method);
+                       index = find_extra_method_in_amodule (amodule, method, name);
                if (index != 0xffffff) {
                        *out_amodule = amodule;
                        break;
@@ -2708,6 +2765,7 @@ find_extra_method (MonoMethod *method, MonoAotModule **out_amodule)
        
        g_ptr_array_free (modules, TRUE);
 
+       g_free (name);
        return index;
 }