[arm] Fix the build.
[mono.git] / mono / mini / mini-arm.c
index 6c9cfb1dc18b6849df83f1573dc112aa55355056..d277aef5d6b05c0e1810932b7a87750c535d3636 100644 (file)
@@ -60,6 +60,8 @@
 #define HAVE_AEABI_READ_TP 1
 #endif
 
+#define THUNK_SIZE (3 * 4)
+
 #ifdef __native_client_codegen__
 const guint kNaClAlignment = kNaClAlignmentARM;
 const guint kNaClAlignmentMask = kNaClAlignmentMaskARM;
@@ -330,6 +332,7 @@ emit_call_seq (MonoCompile *cfg, guint8 *code)
        } else {
                ARM_BL (code, 0);
        }
+       cfg->thunk_area += THUNK_SIZE;
 #endif
        return code;
 }
@@ -3683,134 +3686,104 @@ emit_r4_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gb
 
 #endif /* #ifndef DISABLE_JIT */
 
-typedef struct {
-       guchar *code;
-       const guchar *target;
-       int absolute;
-       int found;
-} PatchData;
-
 #define is_call_imm(diff) ((gint)(diff) >= -33554432 && (gint)(diff) <= 33554431)
 
-static int
-search_thunk_slot (void *data, int csize, int bsize, void *user_data) {
-       PatchData *pdata = (PatchData*)user_data;
-       guchar *code = data;
-       guint32 *thunks = data;
-       guint32 *endthunks = (guint32*)(code + bsize);
-       int count = 0;
-       int difflow, diffhigh;
-
-       /* always ensure a call from pdata->code can reach to the thunks without further thunks */
-       difflow = (char*)pdata->code - (char*)thunks;
-       diffhigh = (char*)pdata->code - (char*)endthunks;
-       if (!((is_call_imm (thunks) && is_call_imm (endthunks)) || (is_call_imm (difflow) && is_call_imm (diffhigh))))
-               return 0;
+static void
+emit_thunk (guint8 *code, gconstpointer target)
+{
+       guint8 *p = code;
 
-       /*
-        * The thunk is composed of 3 words:
-        * load constant from thunks [2] into ARM_IP
-        * bx to ARM_IP
-        * address constant
-        * Note that the LR register is already setup
-        */
-       //g_print ("thunk nentries: %d\n", ((char*)endthunks - (char*)thunks)/16);
-       if ((pdata->found == 2) || (pdata->code >= code && pdata->code <= code + csize)) {
-               while (thunks < endthunks) {
-                       //g_print ("looking for target: %p at %p (%08x-%08x)\n", pdata->target, thunks, thunks [0], thunks [1]);
-                       if (thunks [2] == (guint32)pdata->target) {
-                               arm_patch (pdata->code, (guchar*)thunks);
-                               mono_arch_flush_icache (pdata->code, 4);
-                               pdata->found = 1;
-                               return 1;
-                       } else if ((thunks [0] == 0) && (thunks [1] == 0) && (thunks [2] == 0)) {
-                               /* found a free slot instead: emit thunk */
-                               /* ARMREG_IP is fine to use since this can't be an IMT call
-                                * which is indirect
-                                */
-                               code = (guchar*)thunks;
-                               ARM_LDR_IMM (code, ARMREG_IP, ARMREG_PC, 0);
-                               if (thumb_supported)
-                                       ARM_BX (code, ARMREG_IP);
-                               else
-                                       ARM_MOV_REG_REG (code, ARMREG_PC, ARMREG_IP);
-                               thunks [2] = (guint32)pdata->target;
-                               mono_arch_flush_icache ((guchar*)thunks, 12);
-
-                               arm_patch (pdata->code, (guchar*)thunks);
-                               mono_arch_flush_icache (pdata->code, 4);
-                               pdata->found = 1;
-                               return 1;
-                       }
-                       /* skip 12 bytes, the size of the thunk */
-                       thunks += 3;
-                       count++;
-               }
-               //g_print ("failed thunk lookup for %p from %p at %p (%d entries)\n", pdata->target, pdata->code, data, count);
-       }
-       return 0;
+       ARM_LDR_IMM (code, ARMREG_IP, ARMREG_PC, 0);
+       if (thumb_supported)
+               ARM_BX (code, ARMREG_IP);
+       else
+               ARM_MOV_REG_REG (code, ARMREG_PC, ARMREG_IP);
+       *(guint32*)code = (guint32)target;
+       code += 4;
+       mono_arch_flush_icache (p, code - p);
 }
 
 static void
-handle_thunk (MonoDomain *domain, int absolute, guchar *code, const guchar *target, MonoCodeManager *dyn_code_mp)
+handle_thunk (MonoCompile *cfg, MonoDomain *domain, guchar *code, const guchar *target)
 {
-       PatchData pdata;
+       MonoJitInfo *ji = NULL;
+       MonoThunkJitInfo *info;
+       guint8 *thunks, *p;
+       int thunks_size;
+       guint8 *orig_target;
+       guint8 *target_thunk;
 
        if (!domain)
                domain = mono_domain_get ();
 
-       pdata.code = code;
-       pdata.target = target;
-       pdata.absolute = absolute;
-       pdata.found = 0;
+       if (cfg) {
+               /*
+                * This can be called multiple times during JITting,
+                * save the current position in cfg->arch to avoid
+                * doing a O(n^2) search.
+                */
+               if (!cfg->arch.thunks) {
+                       cfg->arch.thunks = cfg->thunks;
+                       cfg->arch.thunks_size = cfg->thunk_area;
+               }
+               thunks = cfg->arch.thunks;
+               thunks_size = cfg->arch.thunks_size;
+               if (!thunks_size) {
+                       g_print ("thunk failed %p->%p, thunk space=%d method %s", code, target, thunks_size, mono_method_full_name (cfg->method, TRUE));
+                       g_assert_not_reached ();
+               }
 
-       if (dyn_code_mp) {
-               mono_code_manager_foreach (dyn_code_mp, search_thunk_slot, &pdata);
-       }
+               g_assert (*(guint32*)thunks == 0);
+               emit_thunk (thunks, target);
+               arm_patch (code, thunks);
 
-       if (pdata.found != 1) {
-               mono_domain_lock (domain);
-               mono_domain_code_foreach (domain, search_thunk_slot, &pdata);
+               cfg->arch.thunks += THUNK_SIZE;
+               cfg->arch.thunks_size -= THUNK_SIZE;
+       } else {
+               ji = mini_jit_info_table_find (domain, (char*)code, NULL);
+               g_assert (ji);
+               info = mono_jit_info_get_thunk_info (ji);
+               g_assert (info);
 
-               if (!pdata.found) {
-                       /* this uses the first available slot */
-                       pdata.found = 2;
-                       mono_domain_code_foreach (domain, search_thunk_slot, &pdata);
-               }
-               mono_domain_unlock (domain);
-       }
+               thunks = (guint8*)ji->code_start + info->thunks_offset;
+               thunks_size = info->thunks_size;
 
-       if (pdata.found != 1) {
-               GHashTable *hash;
-               GHashTableIter iter;
-               MonoJitDynamicMethodInfo *ji;
+               orig_target = mono_arch_get_call_target (code + 4);
 
-               /*
-                * This might be a dynamic method, search its code manager. We can only
-                * use the dynamic method containing CODE, since the others might be freed later.
-                */
-               pdata.found = 0;
+               mono_mini_arch_lock ();
 
-               mono_domain_lock (domain);
-               hash = domain_jit_info (domain)->dynamic_code_hash;
-               if (hash) {
-                       /* FIXME: Speed this up */
-                       g_hash_table_iter_init (&iter, hash);
-                       while (g_hash_table_iter_next (&iter, NULL, (gpointer*)&ji)) {
-                               mono_code_manager_foreach (ji->code_mp, search_thunk_slot, &pdata);
-                               if (pdata.found == 1)
+               target_thunk = NULL;
+               if (orig_target >= thunks && orig_target < thunks + thunks_size) {
+                       /* The call already points to a thunk, because of trampolines etc. */
+                       target_thunk = orig_target;
+               } else {
+                       for (p = thunks; p < thunks + thunks_size; p += THUNK_SIZE) {
+                               if (((guint32*)p) [0] == 0) {
+                                       /* Free entry */
+                                       target_thunk = p;
                                        break;
+                               }
                        }
                }
-               mono_domain_unlock (domain);
+
+               //printf ("THUNK: %p %p %p\n", code, target, target_thunk);
+
+               if (!target_thunk) {
+                       mono_mini_arch_unlock ();
+                       g_print ("thunk failed %p->%p, thunk space=%d method %s", code, target, thunks_size, cfg ? mono_method_full_name (cfg->method, TRUE) : mono_method_full_name (jinfo_get_method (ji), TRUE));
+                       g_assert_not_reached ();
+               }
+
+               emit_thunk (target_thunk, target);
+               arm_patch (code, target_thunk);
+               mono_arch_flush_icache (code, 4);
+
+               mono_mini_arch_unlock ();
        }
-       if (pdata.found != 1)
-               g_print ("thunk failed for %p from %p\n", target, code);
-       g_assert (pdata.found == 1);
 }
 
 static void
-arm_patch_general (MonoDomain *domain, guchar *code, const guchar *target, MonoCodeManager *dyn_code_mp)
+arm_patch_general (MonoCompile *cfg, MonoDomain *domain, guchar *code, const guchar *target)
 {
        guint32 *code32 = (void*)code;
        guint32 ins = *code32;
@@ -3856,7 +3829,7 @@ arm_patch_general (MonoDomain *domain, guchar *code, const guchar *target, MonoC
                        }
                }
                
-               handle_thunk (domain, TRUE, code, target, dyn_code_mp);
+               handle_thunk (cfg, domain, code, target);
                return;
        }
 
@@ -3967,7 +3940,7 @@ arm_patch_general (MonoDomain *domain, guchar *code, const guchar *target, MonoC
 void
 arm_patch (guchar *code, const guchar *target)
 {
-       arm_patch_general (NULL, code, target, NULL);
+       arm_patch_general (NULL, NULL, code, target);
 }
 
 /* 
@@ -5330,6 +5303,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                case OP_CALL_HANDLER: 
                        mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
                        code = mono_arm_patchable_bl (code, ARMCOND_AL);
+                       cfg->thunk_area += THUNK_SIZE;
                        mono_cfg_add_try_hole (cfg, ins->inst_eh_block, code, bb);
                        break;
                case OP_GET_EX_OBJ:
@@ -5998,85 +5972,68 @@ mono_arch_register_lowlevel_calls (void)
        } while (0)
 
 void
-mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, MonoCodeManager *dyn_code_mp, gboolean run_cctors)
+mono_arch_patch_code_new (MonoCompile *cfg, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gpointer target)
 {
-       MonoJumpInfo *patch_info;
-       gboolean compile_aot = !run_cctors;
+       unsigned char *ip = ji->ip.i + code;
 
-       for (patch_info = ji; patch_info; patch_info = patch_info->next) {
-               unsigned char *ip = patch_info->ip.i + code;
-               const unsigned char *target;
+       if (ji->type == MONO_PATCH_INFO_SWITCH) {
+       }
 
-               if (patch_info->type == MONO_PATCH_INFO_SWITCH && !compile_aot) {
+       switch (ji->type) {
+       case MONO_PATCH_INFO_SWITCH: {
 #ifdef USE_JUMP_TABLES
-                       gpointer *jt = mono_jumptable_get_entry (ip);
+               gpointer *jt = mono_jumptable_get_entry (ip);
 #else
-                       gpointer *jt = (gpointer*)(ip + 8);
+               gpointer *jt = (gpointer*)(ip + 8);
 #endif
-                       int i;
-                       /* jt is the inlined jump table, 2 instructions after ip
-                        * In the normal case we store the absolute addresses,
-                        * otherwise the displacements.
-                        */
-                       for (i = 0; i < patch_info->data.table->table_size; i++)
-                               jt [i] = code + (int)patch_info->data.table->table [i];
-                       continue;
-               }
-
-               if (compile_aot) {
-                       switch (patch_info->type) {
-                       case MONO_PATCH_INFO_BB:
-                       case MONO_PATCH_INFO_LABEL:
-                               break;
-                       default:
-                               /* No need to patch these */
-                               continue;
-                       }
-               }
-
-               target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
-
-               switch (patch_info->type) {
-               case MONO_PATCH_INFO_IP:
-                       g_assert_not_reached ();
-                       patch_lis_ori (ip, ip);
-                       continue;
-               case MONO_PATCH_INFO_METHOD_REL:
-                       g_assert_not_reached ();
-                       *((gpointer *)(ip)) = code + patch_info->data.offset;
-                       continue;
-               case MONO_PATCH_INFO_METHODCONST:
-               case MONO_PATCH_INFO_CLASS:
-               case MONO_PATCH_INFO_IMAGE:
-               case MONO_PATCH_INFO_FIELD:
-               case MONO_PATCH_INFO_VTABLE:
-               case MONO_PATCH_INFO_IID:
-               case MONO_PATCH_INFO_SFLDA:
-               case MONO_PATCH_INFO_LDSTR:
-               case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
-               case MONO_PATCH_INFO_LDTOKEN:
-                       g_assert_not_reached ();
-                       /* from OP_AOTCONST : lis + ori */
-                       patch_lis_ori (ip, target);
-                       continue;
-               case MONO_PATCH_INFO_R4:
-               case MONO_PATCH_INFO_R8:
-                       g_assert_not_reached ();
-                       *((gconstpointer *)(ip + 2)) = patch_info->data.target;
-                       continue;
-               case MONO_PATCH_INFO_EXC_NAME:
-                       g_assert_not_reached ();
-                       *((gconstpointer *)(ip + 1)) = patch_info->data.name;
-                       continue;
-               case MONO_PATCH_INFO_NONE:
-               case MONO_PATCH_INFO_BB_OVF:
-               case MONO_PATCH_INFO_EXC_OVF:
-                       /* everything is dealt with at epilog output time */
-                       continue;
-               default:
-                       break;
-               }
-               arm_patch_general (domain, ip, target, dyn_code_mp);
+               int i;
+               /* jt is the inlined jump table, 2 instructions after ip
+                * In the normal case we store the absolute addresses,
+                * otherwise the displacements.
+                */
+               for (i = 0; i < ji->data.table->table_size; i++)
+                       jt [i] = code + (int)ji->data.table->table [i];
+               break;
+       }
+       case MONO_PATCH_INFO_IP:
+               g_assert_not_reached ();
+               patch_lis_ori (ip, ip);
+               break;
+       case MONO_PATCH_INFO_METHOD_REL:
+               g_assert_not_reached ();
+               *((gpointer *)(ip)) = target;
+               break;
+       case MONO_PATCH_INFO_METHODCONST:
+       case MONO_PATCH_INFO_CLASS:
+       case MONO_PATCH_INFO_IMAGE:
+       case MONO_PATCH_INFO_FIELD:
+       case MONO_PATCH_INFO_VTABLE:
+       case MONO_PATCH_INFO_IID:
+       case MONO_PATCH_INFO_SFLDA:
+       case MONO_PATCH_INFO_LDSTR:
+       case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
+       case MONO_PATCH_INFO_LDTOKEN:
+               g_assert_not_reached ();
+               /* from OP_AOTCONST : lis + ori */
+               patch_lis_ori (ip, target);
+               break;
+       case MONO_PATCH_INFO_R4:
+       case MONO_PATCH_INFO_R8:
+               g_assert_not_reached ();
+               *((gconstpointer *)(ip + 2)) = target;
+               break;
+       case MONO_PATCH_INFO_EXC_NAME:
+               g_assert_not_reached ();
+               *((gconstpointer *)(ip + 1)) = target;
+               break;
+       case MONO_PATCH_INFO_NONE:
+       case MONO_PATCH_INFO_BB_OVF:
+       case MONO_PATCH_INFO_EXC_OVF:
+               /* everything is dealt with at epilog output time */
+               break;
+       default:
+               arm_patch_general (cfg, domain, ip, target);
+               break;
        }
 }
 
@@ -6770,6 +6727,7 @@ mono_arch_emit_exceptions (MonoCompile *cfg)
                        patch_info->data.name = "mono_arch_throw_corlib_exception";
                        patch_info->ip.i = code - cfg->native_code;
                        ARM_BL (code, 0);
+                       cfg->thunk_area += THUNK_SIZE;
                        *(guint32*)(gpointer)code = exc_class->type_token;
                        code += 4;
 #endif