[profiler] Implement call context introspection for enter/leave events.
[mono.git] / mono / mini / mini-arm.c
index f85644d42ca6d5446732a7427bb27e48b48d9177..a304dbef08062a83bfc9b907a6840ee00e42cdcb 100644 (file)
@@ -1,5 +1,6 @@
-/*
- * mini-arm.c: ARM backend for the Mono code generator
+/**
+ * \file
+ * ARM backend for the Mono code generator
  *
  * Authors:
  *   Paolo Molaro (lupus@ximian.com)
@@ -120,7 +121,6 @@ static int vfp_scratch2 = ARM_VFP_D1;
 static int i8_align;
 
 static gpointer single_step_tramp, breakpoint_tramp;
-static gpointer get_tls_tramp;
 
 /*
  * The code generated for sequence points reads from this location, which is
@@ -215,6 +215,19 @@ emit_big_add (guint8 *code, int dreg, int sreg, int imm)
        return code;
 }
 
+static guint8*
+emit_ldr_imm (guint8 *code, int dreg, int sreg, int imm)
+{
+       if (!arm_is_imm12 (imm)) {
+               g_assert (dreg != sreg);
+               code = emit_big_add (code, dreg, sreg, imm);
+               ARM_LDR_IMM (code, dreg, dreg, 0);
+       } else {
+               ARM_LDR_IMM (code, dreg, sreg, imm);
+       }
+       return code;
+}
+
 /* If dreg == sreg, this clobbers IP */
 static guint8*
 emit_sub_imm (guint8 *code, int dreg, int sreg, int imm)
@@ -322,7 +335,7 @@ mono_arm_patchable_bl (guint8 *code, int cond)
        return code;
 }
 
-#if defined(__ARM_EABI__) && defined(__linux__) && !defined(PLATFORM_ANDROID) && !defined(__native_client__)
+#if defined(__ARM_EABI__) && defined(__linux__) && !defined(PLATFORM_ANDROID) && !defined(MONO_CROSS_COMPILE)
 #define HAVE_AEABI_READ_TP 1
 #endif
 
@@ -336,7 +349,6 @@ mono_arch_have_fast_tls (void)
 #ifdef HAVE_AEABI_READ_TP
        static gboolean have_fast_tls = FALSE;
         static gboolean inited = FALSE;
-       gpointer tp1, tp2;
 
        if (mini_get_debug_options ()->use_fallback_tls)
                return FALSE;
@@ -344,10 +356,14 @@ mono_arch_have_fast_tls (void)
        if (inited)
                return have_fast_tls;
 
-       tp1 = __aeabi_read_tp ();
-       asm volatile("mrc p15, 0, %0, c13, c0, 3" : "=r" (tp2));
+       if (v7_supported) {
+               gpointer tp1, tp2;
 
-       have_fast_tls = tp1 && tp1 == tp2;
+               tp1 = __aeabi_read_tp ();
+               asm volatile("mrc p15, 0, %0, c13, c0, 3" : "=r" (tp2));
+
+               have_fast_tls = tp1 && tp1 == tp2;
+       }
        inited = TRUE;
        return have_fast_tls;
 #else
@@ -358,6 +374,7 @@ mono_arch_have_fast_tls (void)
 static guint8*
 emit_tls_get (guint8 *code, int dreg, int tls_offset)
 {
+       g_assert (v7_supported);
        ARM_MRC (code, 15, 0, dreg, 13, 0, 3);
        ARM_LDR_IMM (code, dreg, dreg, tls_offset);
        return code;
@@ -367,6 +384,7 @@ static guint8*
 emit_tls_set (guint8 *code, int sreg, int tls_offset)
 {
        int tp_reg = (sreg != ARMREG_R0) ? ARMREG_R0 : ARMREG_R1;
+       g_assert (v7_supported);
        ARM_MRC (code, 15, 0, tp_reg, 13, 0, 3);
        ARM_STR_IMM (code, sreg, tp_reg, tls_offset);
        return code;
@@ -632,7 +650,7 @@ get_delegate_invoke_impl (MonoTrampInfo **info, gboolean has_target, gboolean pa
                 g_free (name);
        }
 
-       mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_DELEGATE_INVOKE, NULL);
+       MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_DELEGATE_INVOKE, NULL));
 
        return start;
 }
@@ -758,7 +776,7 @@ mono_arch_cpu_init (void)
 void
 mono_arch_init (void)
 {
-       const char *cpu_arch;
+       char *cpu_arch;
 
 #ifdef TARGET_WATCHOS
        mini_get_debug_options ()->soft_breakpoints = TRUE;
@@ -781,7 +799,6 @@ mono_arch_init (void)
        mono_aot_register_jit_icall ("mono_arm_start_gsharedvt_call", mono_arm_start_gsharedvt_call);
 #endif
        mono_aot_register_jit_icall ("mono_arm_unaligned_stack", mono_arm_unaligned_stack);
-
 #if defined(__ARM_EABI__)
        eabi_supported = TRUE;
 #endif
@@ -807,10 +824,11 @@ mono_arch_init (void)
         * works. Most ARM devices have VFP units these days, so
         * normally soft float code would not be exercised much.
         */
-       const char *soft = g_getenv ("MONO_ARM_FORCE_SOFT_FLOAT");
+       char *soft = g_getenv ("MONO_ARM_FORCE_SOFT_FLOAT");
 
        if (soft && !strncmp (soft, "1", 1))
                arm_fpu = MONO_ARM_FPU_NONE;
+       g_free (soft);
 #endif
 #endif
 
@@ -858,6 +876,7 @@ mono_arch_init (void)
 
                thumb_supported = strstr (cpu_arch, "thumb") != NULL;
                thumb2_supported = strstr (cpu_arch, "thumb2") != NULL;
+               g_free (cpu_arch);
        }
 }
 
@@ -941,10 +960,6 @@ is_regsize_var (MonoType *t)
        case MONO_TYPE_FNPTR:
                return TRUE;
        case MONO_TYPE_OBJECT:
-       case MONO_TYPE_STRING:
-       case MONO_TYPE_CLASS:
-       case MONO_TYPE_SZARRAY:
-       case MONO_TYPE_ARRAY:
                return TRUE;
        case MONO_TYPE_GENERICINST:
                if (!mono_type_generic_inst_is_valuetype (t))
@@ -1269,11 +1284,7 @@ get_call_info (MonoMemPool *mp, MonoMethodSignature *sig)
        case MONO_TYPE_U:
        case MONO_TYPE_PTR:
        case MONO_TYPE_FNPTR:
-       case MONO_TYPE_CLASS:
        case MONO_TYPE_OBJECT:
-       case MONO_TYPE_SZARRAY:
-       case MONO_TYPE_ARRAY:
-       case MONO_TYPE_STRING:
                cinfo->ret.storage = RegTypeGeneral;
                cinfo->ret.reg = ARMREG_R0;
                break;
@@ -1422,11 +1433,7 @@ get_call_info (MonoMemPool *mp, MonoMethodSignature *sig)
                case MONO_TYPE_U:
                case MONO_TYPE_PTR:
                case MONO_TYPE_FNPTR:
-               case MONO_TYPE_CLASS:
                case MONO_TYPE_OBJECT:
-               case MONO_TYPE_STRING:
-               case MONO_TYPE_SZARRAY:
-               case MONO_TYPE_ARRAY:
                        cinfo->args [n].size = sizeof (gpointer);
                        add_general (&gr, &stack_size, ainfo, TRUE);
                        break;
@@ -1647,8 +1654,7 @@ debug_omit_fp (void)
 
 /**
  * mono_arch_compute_omit_fp:
- *
- *   Determine whenever the frame pointer can be eliminated.
+ * Determine whether the frame pointer can be eliminated.
  */
 static void
 mono_arch_compute_omit_fp (MonoCompile *cfg)
@@ -1691,8 +1697,7 @@ mono_arch_compute_omit_fp (MonoCompile *cfg)
                cfg->arch.omit_fp = FALSE;
        if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG))
                cfg->arch.omit_fp = FALSE;
-       if ((mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method)) ||
-               (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE))
+       if ((mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method)))
                cfg->arch.omit_fp = FALSE;
        for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
                ArgInfo *ainfo = &cinfo->args [i];
@@ -2175,8 +2180,6 @@ mono_arch_get_llvm_call_info (MonoCompile *cfg, MonoMethodSignature *sig)
                                lainfo->nslots = ainfo->struct_size / sizeof (gpointer);
                                lainfo->esize = 4;
                        }
-
-                       printf ("D: %d\n", ainfo->align);
                        break;
                case RegTypeStructByAddr:
                case RegTypeStructByAddrOnStack:
@@ -2800,10 +2803,6 @@ mono_arch_start_dyn_call (MonoDynCallInfo *info, gpointer **args, guint8 *ret, g
                }
 
                switch (t->type) {
-               case MONO_TYPE_STRING:
-               case MONO_TYPE_CLASS:  
-               case MONO_TYPE_ARRAY:
-               case MONO_TYPE_SZARRAY:
                case MONO_TYPE_OBJECT:
                case MONO_TYPE_PTR:
                case MONO_TYPE_I:
@@ -2905,10 +2904,6 @@ mono_arch_finish_dyn_call (MonoDynCallInfo *info, guint8 *buf)
        case MONO_TYPE_VOID:
                *(gpointer*)ret = NULL;
                break;
-       case MONO_TYPE_STRING:
-       case MONO_TYPE_CLASS:  
-       case MONO_TYPE_ARRAY:
-       case MONO_TYPE_SZARRAY:
        case MONO_TYPE_OBJECT:
        case MONO_TYPE_I:
        case MONO_TYPE_U:
@@ -4053,6 +4048,18 @@ mono_arm_thumb_supported (void)
        return thumb_supported;
 }
 
+gboolean
+mono_arm_eabi_supported (void)
+{
+       return eabi_supported;
+}
+
+int
+mono_arm_i8_align (void)
+{
+       return i8_align;
+}
+
 #ifndef DISABLE_JIT
 
 static guint8*
@@ -4184,17 +4191,6 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
 
        cpos = bb->max_offset;
 
-       if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
-               //MonoCoverageInfo *cov = mono_get_coverage_info (cfg->method);
-               //g_assert (!mono_compile_aot);
-               //cpos += 6;
-               //if (bb->cil_code)
-               //      cov->data [bb->dfn].iloffset = bb->cil_code - cfg->cil_code;
-               /* this is not thread save, but good enough */
-               /* fixme: howto handle overflows? */
-               //x86_inc_mem (code, &cov->data [bb->dfn].count); 
-       }
-
     if (mono_break_at_bb_method && mono_method_desc_full_match (mono_break_at_bb_method, cfg->method) && bb->block_num == mono_break_at_bb_bb_num) {
                mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, 
                                                         (gpointer)"mono_break");
@@ -4566,7 +4562,6 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        if (cfg->compile_aot) {
                                g_assert (info_var);
                                g_assert (info_var->opcode == OP_REGOFFSET);
-                               g_assert (arm_is_imm12 (info_var->inst_offset));
                        }
 
                        if (!cfg->soft_breakpoints && !cfg->compile_aot) {
@@ -4586,9 +4581,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                                        var = ss_method_var;
                                        g_assert (var);
                                        g_assert (var->opcode == OP_REGOFFSET);
-                                       g_assert (arm_is_imm12 (var->inst_offset));
-                                       ARM_LDR_IMM (code, dreg, var->inst_basereg, var->inst_offset);
-
+                                       code = emit_ldr_imm (code, dreg, var->inst_basereg, var->inst_offset);
                                        /* Read the value and check whether it is non-zero. */
                                        ARM_LDR_IMM (code, dreg, dreg, 0);
                                        ARM_CMP_REG_IMM (code, dreg, 0, 0);
@@ -4600,8 +4593,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                                                var = ss_trigger_page_var;
                                                g_assert (var);
                                                g_assert (var->opcode == OP_REGOFFSET);
-                                               g_assert (arm_is_imm12 (var->inst_offset));
-                                               ARM_LDR_IMM (code, dreg, var->inst_basereg, var->inst_offset);
+                                               code = emit_ldr_imm (code, dreg, var->inst_basereg, var->inst_offset);
                                        } else {
                                                ARM_LDR_IMM (code, dreg, ARMREG_PC, 0);
                                                ARM_B (code, 0);
@@ -4619,7 +4611,8 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                                guint32 offset = code - cfg->native_code;
                                guint32 val;
 
-                               ARM_LDR_IMM (code, dreg, info_var->inst_basereg, info_var->inst_offset);
+                               var = info_var;
+                               code = emit_ldr_imm (code, dreg, var->inst_basereg, var->inst_offset);
                                /* Add the offset */
                                val = ((offset / 4) * sizeof (guint8*)) + MONO_STRUCT_OFFSET (SeqPointInfo, bp_addrs);
                                /* Load the info->bp_addrs [offset], which is either 0 or the address of a trigger page */
@@ -5897,7 +5890,11 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        arm_patch (buf [0], code);
                        break;
                }
-
+               case OP_FILL_PROF_CALL_CTX:
+                       for (int i = 0; i < ARMREG_MAX; i++)
+                               if ((MONO_ARCH_CALLEE_SAVED_REGS & (1 << i)) || i == ARMREG_SP || i == ARMREG_FP)
+                                       ARM_STR_IMM (code, i, ins->sreg1, MONO_STRUCT_OFFSET (MonoContext, regs) + i * sizeof (mgreg_t));
+                       break;
                default:
                        g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
                        g_assert_not_reached ();
@@ -6146,9 +6143,6 @@ mono_arch_emit_prolog (MonoCompile *cfg)
                MonoInst *ins = bb->code;
                bb->max_offset = max_offset;
 
-               if (cfg->prof_options & MONO_PROFILE_COVERAGE)
-                       max_offset += 6; 
-
                MONO_BB_FOR_EACH_INS (bb, ins)
                        max_offset += ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
        }
@@ -6445,9 +6439,8 @@ mono_arch_emit_prolog (MonoCompile *cfg)
 
                if (info_var) {
                        g_assert (info_var->opcode == OP_REGOFFSET);
-                       g_assert (arm_is_imm12 (info_var->inst_offset));
 
-                       ARM_LDR_IMM (code, dreg, info_var->inst_basereg, info_var->inst_offset);
+                       code = emit_ldr_imm (code, dreg, info_var->inst_basereg, info_var->inst_offset);
                        /* Load the trigger page addr */
                        ARM_LDR_IMM (code, dreg, dreg, MONO_STRUCT_OFFSET (SeqPointInfo, ss_trigger_page));
                        ARM_STR_IMM (code, dreg, ss_trigger_page_var->inst_basereg, ss_trigger_page_var->inst_offset);
@@ -6511,9 +6504,6 @@ mono_arch_emit_epilog (MonoCompile *cfg)
        if (mono_jit_trace_calls != NULL)
                max_epilog_size += 50;
 
-       if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
-               max_epilog_size += 50;
-
        while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
                cfg->code_size *= 2;
                cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
@@ -7061,7 +7051,7 @@ mono_arch_build_imt_trampoline (MonoVTable *vtable, MonoDomain *domain, MonoIMTC
        g_free (constant_pool_starts);
 
        mono_arch_flush_icache ((guint8*)start, size);
-       mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_IMT_TRAMPOLINE, NULL);
+       MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_IMT_TRAMPOLINE, NULL));
        mono_stats.imt_trampolines_size += code - start;
 
        g_assert (DISTANCE (start, code) <= size);
@@ -7095,26 +7085,6 @@ mono_arch_get_trampolines (gboolean aot)
        return mono_arm_get_exception_trampolines (aot);
 }
 
-gpointer
-mono_arch_install_handler_block_guard (MonoJitInfo *ji, MonoJitExceptionInfo *clause, MonoContext *ctx, gpointer new_value)
-{
-       gpointer *lr_loc;
-       char *old_value;
-       char *bp;
-
-       /*Load the spvar*/
-       bp = MONO_CONTEXT_GET_BP (ctx);
-       lr_loc = (gpointer*)(bp + clause->exvar_offset);
-
-       old_value = *lr_loc;
-       if ((char*)old_value < (char*)ji->code_start || (char*)old_value > ((char*)ji->code_start + ji->code_size))
-               return old_value;
-
-       *lr_loc = new_value;
-
-       return old_value;
-}
-
 #if defined(MONO_ARCH_SOFT_DEBUG_SUPPORTED)
 /*
  * mono_arch_set_breakpoint:
@@ -7446,3 +7416,17 @@ emit_aotconst (MonoCompile *cfg, guint8 *code, int dreg, int patch_type, gpointe
        ARM_LDR_REG_REG (code, dreg, ARMREG_PC, dreg);
        return code;
 }
+
+guint8*
+mono_arm_emit_aotconst (gpointer ji_list, guint8 *code, guint8 *buf, int dreg, int patch_type, gconstpointer data)
+{
+       MonoJumpInfo **ji = (MonoJumpInfo**)ji_list;
+
+       *ji = mono_patch_info_list_prepend (*ji, code - buf, patch_type, data);
+       ARM_LDR_IMM (code, dreg, ARMREG_PC, 0);
+       ARM_B (code, 0);
+       *(gpointer*)code = NULL;
+       code += 4;
+       ARM_LDR_REG_REG (code, dreg, ARMREG_PC, dreg);
+       return code;
+}