Merge pull request #3796 from ntherning/windows-backend-for-MemoryMappedFile
[mono.git] / mono / mini / mini-arm.c
index 8b48bc98fd3e95aedc60133921e5a72ee42fed28..13a3ffee37f8159a3b1346bf99c09b007ab5159b 100644 (file)
@@ -18,7 +18,7 @@
 #include <mono/metadata/profiler-private.h>
 #include <mono/metadata/debug-helpers.h>
 #include <mono/utils/mono-mmap.h>
-#include <mono/utils/mono-hwcap-arm.h>
+#include <mono/utils/mono-hwcap.h>
 #include <mono/utils/mono-memory-model.h>
 #include <mono/utils/mono-threads-coop.h>
 
@@ -127,6 +127,7 @@ 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
@@ -167,6 +168,9 @@ int mono_exc_esp_offset = 0;
 static void mono_arch_compute_omit_fp (MonoCompile *cfg);
 #endif
 
+static guint8*
+emit_aotconst (MonoCompile *cfg, guint8 *code, int dreg, int patch_type, gpointer data);
+
 const char*
 mono_arch_regname (int reg)
 {
@@ -330,9 +334,21 @@ mono_arm_emit_tls_get (MonoCompile *cfg, guint8* code, int dreg, int tls_offset)
 {
 #ifdef HAVE_FAST_TLS
        code = mono_arm_emit_load_imm (code, ARMREG_R0, tls_offset);
-       mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
-                       "mono_get_tls_key");
-       code = emit_call_seq (cfg, code);
+       if (cfg->compile_aot) {
+               /*
+                * This opcode is generated by CEE_MONO_JIT_ATTACH, so it can execute on
+                * threads which are not yet attached to the runtime. This means we can't
+                * call it directly, since the call would go through the trampoline code
+                * which assumes the thread is attached. So use a separate patch info type
+                * for it, and load it from a preinitialized GOT slot.
+                */
+               code = emit_aotconst (cfg, code, ARMREG_R1, MONO_PATCH_INFO_GET_TLS_TRAMP, NULL);
+               code = emit_call_reg (code, ARMREG_R1);
+       } else {
+               mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
+                                                        "mono_get_tls_key");
+               code = emit_call_seq (cfg, code);
+       }
        if (dreg != ARMREG_R0)
                ARM_MOV_REG_REG (code, dreg, ARMREG_R0);
 #else
@@ -347,9 +363,14 @@ mono_arm_emit_tls_get_reg (MonoCompile *cfg, guint8* code, int dreg, int tls_off
 #ifdef HAVE_FAST_TLS
        if (tls_offset_reg != ARMREG_R0)
                ARM_MOV_REG_REG (code, ARMREG_R0, tls_offset_reg);
-       mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
-                       "mono_get_tls_key");
-       code = emit_call_seq (cfg, code);
+       if (cfg->compile_aot) {
+               code = emit_aotconst (cfg, code, ARMREG_R1, MONO_PATCH_INFO_GET_TLS_TRAMP, NULL);
+               code = emit_call_reg (code, ARMREG_R1);
+       } else {
+               mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
+                                                        "mono_get_tls_key");
+               code = emit_call_seq (cfg, code);
+       }
        if (dreg != ARMREG_R0)
                ARM_MOV_REG_REG (code, dreg, ARMREG_R0);
 #else
@@ -836,8 +857,8 @@ mono_arch_init (void)
                if (!mono_aot_only)
                        breakpoint_tramp = mini_get_breakpoint_trampoline ();
        } else {
-               ss_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ|MONO_MMAP_32BIT);
-               bp_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ|MONO_MMAP_32BIT);
+               ss_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ|MONO_MMAP_32BIT, MONO_MEM_ACCOUNT_OTHER);
+               bp_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ|MONO_MMAP_32BIT, MONO_MEM_ACCOUNT_OTHER);
                mono_mprotect (bp_trigger_page, mono_pagesize (), 0);
        }
 
@@ -4442,14 +4463,12 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                                ARM_DMB (code, ARM_DMB_SY);
                        break;
                }
-               /*case OP_BIGMUL:
-                       ppc_mullw (code, ppc_r4, ins->sreg1, ins->sreg2);
-                       ppc_mulhw (code, ppc_r3, ins->sreg1, ins->sreg2);
+               case OP_BIGMUL:
+                       ARM_SMULL_REG_REG (code, ins->backend.reg3, ins->dreg, ins->sreg1, ins->sreg2);
                        break;
                case OP_BIGMUL_UN:
-                       ppc_mullw (code, ppc_r4, ins->sreg1, ins->sreg2);
-                       ppc_mulhwu (code, ppc_r3, ins->sreg1, ins->sreg2);
-                       break;*/
+                       ARM_UMULL_REG_REG (code, ins->backend.reg3, ins->dreg, ins->sreg1, ins->sreg2);
+                       break;
                case OP_STOREI1_MEMBASE_IMM:
                        code = mono_arm_emit_load_imm (code, ARMREG_LR, ins->inst_imm & 0xFF);
                        g_assert (arm_is_imm12 (ins->inst_offset));
@@ -4629,6 +4648,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                                g_assert (((guint64)(gsize)ss_trigger_page >> 32) == 0);
                        }
 
+                       /* Single step check */
                        if (ins->flags & MONO_INST_SINGLE_STEP_LOC) {
                                if (cfg->soft_breakpoints) {
                                        /* Load the address of the sequence point method variable. */
@@ -4663,6 +4683,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
 
                        mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
 
+                       /* Breakpoint check */
                        if (cfg->compile_aot) {
                                guint32 offset = code - cfg->native_code;
                                guint32 val;
@@ -5989,6 +6010,8 @@ mono_arch_register_lowlevel_calls (void)
                mono_register_jit_icall (tls_imp.get_tls_thunk, "mono_get_tls_key", mono_create_icall_signature ("ptr ptr"), TRUE);
                mono_register_jit_icall (tls_imp.set_tls_thunk, "mono_set_tls_key", mono_create_icall_signature ("void ptr ptr"), TRUE);
 
+               get_tls_tramp = tls_imp.get_tls_thunk;
+
                if (tls_imp.get_tls_thunk_end) {
                        mono_tramp_info_register (
                                mono_tramp_info_create (
@@ -6543,22 +6566,36 @@ mono_arch_emit_prolog (MonoCompile *cfg)
        if (cfg->arch.seq_point_ss_method_var) {
                MonoInst *ss_method_ins = cfg->arch.seq_point_ss_method_var;
                MonoInst *bp_method_ins = cfg->arch.seq_point_bp_method_var;
+
                g_assert (ss_method_ins->opcode == OP_REGOFFSET);
                g_assert (arm_is_imm12 (ss_method_ins->inst_offset));
-               g_assert (bp_method_ins->opcode == OP_REGOFFSET);
-               g_assert (arm_is_imm12 (bp_method_ins->inst_offset));
 
-               ARM_MOV_REG_REG (code, ARMREG_LR, ARMREG_PC);
-               ARM_B (code, 1);
-               *(gpointer*)code = &single_step_tramp;
-               code += 4;
-               *(gpointer*)code = breakpoint_tramp;
-               code += 4;
+               if (cfg->compile_aot) {
+                       MonoInst *info_var = cfg->arch.seq_point_info_var;
+                       int dreg = ARMREG_LR;
 
-               ARM_LDR_IMM (code, ARMREG_IP, ARMREG_LR, 0);
-               ARM_STR_IMM (code, ARMREG_IP, ss_method_ins->inst_basereg, ss_method_ins->inst_offset);
-               ARM_LDR_IMM (code, ARMREG_IP, ARMREG_LR, 4);
-               ARM_STR_IMM (code, ARMREG_IP, bp_method_ins->inst_basereg, bp_method_ins->inst_offset);
+                       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);
+                       ARM_LDR_IMM (code, dreg, dreg, MONO_STRUCT_OFFSET (SeqPointInfo, ss_tramp_addr));
+                       ARM_STR_IMM (code, dreg, ss_method_ins->inst_basereg, ss_method_ins->inst_offset);
+               } else {
+                       g_assert (bp_method_ins->opcode == OP_REGOFFSET);
+                       g_assert (arm_is_imm12 (bp_method_ins->inst_offset));
+
+                       ARM_MOV_REG_REG (code, ARMREG_LR, ARMREG_PC);
+                       ARM_B (code, 1);
+                       *(gpointer*)code = &single_step_tramp;
+                       code += 4;
+                       *(gpointer*)code = breakpoint_tramp;
+                       code += 4;
+
+                       ARM_LDR_IMM (code, ARMREG_IP, ARMREG_LR, 0);
+                       ARM_STR_IMM (code, ARMREG_IP, ss_method_ins->inst_basereg, ss_method_ins->inst_offset);
+                       ARM_LDR_IMM (code, ARMREG_IP, ARMREG_LR, 4);
+                       ARM_STR_IMM (code, ARMREG_IP, bp_method_ins->inst_basereg, bp_method_ins->inst_offset);
+               }
        }
 
        cfg->code_len = code - cfg->native_code;
@@ -6908,7 +6945,7 @@ mini_dump_bad_imt (int input_imt, int compared_imt, int pc)
 #endif
 
 gpointer
-mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count,
+mono_arch_build_imt_trampoline (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count,
        gpointer fail_tramp)
 {
        int size, i;
@@ -6960,7 +6997,7 @@ mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckI
                size += 4 * count; /* The ARM_ADD_REG_IMM to pop the stack */
 
        if (fail_tramp)
-               code = mono_method_alloc_generic_virtual_thunk (domain, size);
+               code = mono_method_alloc_generic_virtual_trampoline (domain, size);
        else
                code = mono_domain_code_reserve (domain, size);
        start = code;
@@ -6968,7 +7005,7 @@ mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckI
        unwind_ops = mono_arch_get_cie_program ();
 
 #ifdef DEBUG_IMT
-       g_print ("Building IMT thunk for class %s %s entries %d code size %d code at %p end %p vtable %p fail_tramp %p\n", vtable->klass->name_space, vtable->klass->name, count, size, start, ((guint8*)start) + size, vtable, fail_tramp);
+       g_print ("Building IMT trampoline for class %s %s entries %d code size %d code at %p end %p vtable %p fail_tramp %p\n", vtable->klass->name_space, vtable->klass->name, count, size, start, ((guint8*)start) + size, vtable, fail_tramp);
        for (i = 0; i < count; ++i) {
                MonoIMTCheckItem *item = imt_entries [i];
                g_print ("method %d (%p) %s vtable slot %p is_equals %d chunk size %d\n", i, item->key, ((MonoMethod*)item->key)->name, &vtable->vtable [item->value.vtable_slot], item->is_equals, item->chunk_size);
@@ -7134,7 +7171,7 @@ mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckI
 
        mono_arch_flush_icache ((guint8*)start, size);
        mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_IMT_TRAMPOLINE, NULL);
-       mono_stats.imt_thunks_size += code - start;
+       mono_stats.imt_trampolines_size += code - start;
 
        g_assert (DISTANCE (start, code) <= size);
 
@@ -7400,6 +7437,7 @@ mono_arch_get_seq_point_info (MonoDomain *domain, guint8 *code)
 
                info->ss_trigger_page = ss_trigger_page;
                info->bp_trigger_page = bp_trigger_page;
+               info->ss_tramp_addr = &single_step_tramp;
 
                mono_domain_lock (domain);
                g_hash_table_insert (domain_jit_info (domain)->arch_seq_points,
@@ -7497,3 +7535,23 @@ mono_arch_get_call_info (MonoMemPool *mp, MonoMethodSignature *sig)
 {
        return get_call_info (mp, sig);
 }
+
+gpointer
+mono_arch_get_get_tls_tramp (void)
+{
+       return get_tls_tramp;
+}
+
+static guint8*
+emit_aotconst (MonoCompile *cfg, guint8 *code, int dreg, int patch_type, gpointer data)
+{
+       /* OP_AOTCONST */
+       mono_add_patch_info (cfg, code - cfg->native_code, patch_type, data);
+       ARM_LDR_IMM (code, dreg, ARMREG_PC, 0);
+       ARM_B (code, 0);
+       *(gpointer*)code = NULL;
+       code += 4;
+       /* Load the value from the GOT */
+       ARM_LDR_REG_REG (code, dreg, ARMREG_PC, dreg);
+       return code;
+}