X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmini%2Fmini-arm.c;h=f80d5f5b0272e5f6315be7c26c65cf5941b91f7c;hb=f704d56c378b28e252572db4730a6e13edc14aa0;hp=7b2e1fa7b48e2438c7e85deeb87108be375a6936;hpb=3fd54893bc792eee42164bfb605b418105a92f92;p=mono.git diff --git a/mono/mini/mini-arm.c b/mono/mini/mini-arm.c index 7b2e1fa7b48..f80d5f5b027 100644 --- a/mono/mini/mini-arm.c +++ b/mono/mini/mini-arm.c @@ -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) @@ -23,7 +24,6 @@ #include #include "mini-arm.h" -#include "mini-arm-tls.h" #include "cpu-arm.h" #include "trace.h" #include "ir-emit.h" @@ -31,12 +31,6 @@ #include "mini-gc.h" #include "mono/arch/arm/arm-vfp-codegen.h" -#if (defined(HAVE_KW_THREAD) && defined(__linux__) && defined(__ARM_EABI__)) \ - || defined(TARGET_ANDROID) \ - || (defined(TARGET_IOS) && !defined(TARGET_WATCHOS)) -#define HAVE_FAST_TLS -#endif - /* Sanity check: This makes no sense */ #if defined(ARM_FPU_NONE) && (defined(ARM_FPU_VFP) || defined(ARM_FPU_VFP_HARD)) #error "ARM_FPU_NONE is defined while one of ARM_FPU_VFP/ARM_FPU_VFP_HARD is defined" @@ -127,6 +121,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 +162,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) { @@ -325,83 +323,53 @@ mono_arm_patchable_bl (guint8 *code, int cond) return code; } -static guint8* -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 (dreg != ARMREG_R0) - ARM_MOV_REG_REG (code, dreg, ARMREG_R0); -#else - g_assert_not_reached (); +#if defined(__ARM_EABI__) && defined(__linux__) && !defined(PLATFORM_ANDROID) && !defined(__native_client__) +#define HAVE_AEABI_READ_TP 1 #endif - return code; -} -static guint8* -mono_arm_emit_tls_get_reg (MonoCompile *cfg, guint8* code, int dreg, int tls_offset_reg) +#ifdef HAVE_AEABI_READ_TP +gpointer __aeabi_read_tp (void); +#endif + +gboolean +mono_arch_have_fast_tls (void) { -#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 (dreg != ARMREG_R0) - ARM_MOV_REG_REG (code, dreg, ARMREG_R0); +#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; + + if (inited) + return have_fast_tls; + + 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 - g_assert_not_reached (); + return FALSE; #endif - return code; } static guint8* -mono_arm_emit_tls_set (MonoCompile *cfg, guint8* code, int sreg, int tls_offset) +emit_tls_get (guint8 *code, int dreg, int tls_offset) { -#ifdef HAVE_FAST_TLS - if (sreg != ARMREG_R1) - ARM_MOV_REG_REG (code, ARMREG_R1, sreg); - 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_set_tls_key"); - code = emit_call_seq (cfg, code); -#else - g_assert_not_reached (); -#endif + ARM_MRC (code, 15, 0, dreg, 13, 0, 3); + ARM_LDR_IMM (code, dreg, dreg, tls_offset); return code; } static guint8* -mono_arm_emit_tls_set_reg (MonoCompile *cfg, guint8* code, int sreg, int tls_offset_reg) +emit_tls_set (guint8 *code, int sreg, int tls_offset) { -#ifdef HAVE_FAST_TLS - /* Get sreg in R1 and tls_offset_reg in R0 */ - if (tls_offset_reg == ARMREG_R1) { - if (sreg == ARMREG_R0) { - /* swap sreg and tls_offset_reg */ - ARM_EOR_REG_REG (code, sreg, sreg, tls_offset_reg); - ARM_EOR_REG_REG (code, tls_offset_reg, sreg, tls_offset_reg); - ARM_EOR_REG_REG (code, sreg, sreg, tls_offset_reg); - } else { - ARM_MOV_REG_REG (code, ARMREG_R0, tls_offset_reg); - if (sreg != ARMREG_R1) - ARM_MOV_REG_REG (code, ARMREG_R1, sreg); - } - } else { - if (sreg != ARMREG_R1) - ARM_MOV_REG_REG (code, ARMREG_R1, sreg); - 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_set_tls_key"); - code = emit_call_seq (cfg, code); -#else - g_assert_not_reached (); -#endif + int tp_reg = (sreg != ARMREG_R0) ? ARMREG_R0 : ARMREG_R1; + ARM_MRC (code, 15, 0, tp_reg, 13, 0, 3); + ARM_STR_IMM (code, sreg, tp_reg, tls_offset); return code; } @@ -414,31 +382,13 @@ mono_arm_emit_tls_set_reg (MonoCompile *cfg, guint8* code, int sreg, int tls_off static guint8* emit_save_lmf (MonoCompile *cfg, guint8 *code, gint32 lmf_offset) { - gboolean get_lmf_fast = FALSE; int i; - if (mono_arm_have_tls_get ()) { - get_lmf_fast = TRUE; - if (cfg->compile_aot) { - /* OP_AOTCONST */ - mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_TLS_OFFSET, (gpointer)TLS_KEY_LMF_ADDR); - ARM_LDR_IMM (code, ARMREG_R1, ARMREG_PC, 0); - ARM_B (code, 0); - *(gpointer*)code = NULL; - code += 4; - /* Load the value from the GOT */ - ARM_LDR_REG_REG (code, ARMREG_R1, ARMREG_PC, ARMREG_R1); - code = mono_arm_emit_tls_get_reg (cfg, code, ARMREG_R0, ARMREG_R1); - } else { - gint32 lmf_addr_tls_offset = mono_get_lmf_addr_tls_offset (); - g_assert (lmf_addr_tls_offset != -1); - code = mono_arm_emit_tls_get (cfg, code, ARMREG_R0, lmf_addr_tls_offset); - } - } - - if (!get_lmf_fast) { - mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, - (gpointer)"mono_get_lmf_addr"); + if (mono_arch_have_fast_tls () && mono_tls_get_tls_offset (TLS_KEY_LMF_ADDR) != -1) { + code = emit_tls_get (code, ARMREG_R0, mono_tls_get_tls_offset (TLS_KEY_LMF_ADDR)); + } else { + mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, + (gpointer)"mono_tls_get_lmf_addr"); code = emit_call_seq (cfg, code); } /* we build the MonoLMF structure on the stack - see mini-arm.h */ @@ -581,22 +531,6 @@ emit_restore_lmf (MonoCompile *cfg, guint8 *code, gint32 lmf_offset) #endif /* #ifndef DISABLE_JIT */ -/* - * mono_arm_have_tls_get: - * - * Returns whether we have tls access implemented on the current - * platform - */ -gboolean -mono_arm_have_tls_get (void) -{ -#ifdef HAVE_FAST_TLS - return TRUE; -#else - return FALSE; -#endif -} - /* * mono_arch_get_argument_info: * @csig: a method signature @@ -836,8 +770,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); } @@ -848,7 +782,7 @@ 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); - + mono_aot_register_jit_icall ("mono_arm_handler_block_trampoline_helper", mono_arm_handler_block_trampoline_helper); #if defined(__ARM_EABI__) eabi_supported = TRUE; #endif @@ -858,7 +792,7 @@ mono_arch_init (void) #else arm_fpu = MONO_ARM_FPU_VFP; -#if defined(ARM_FPU_NONE) && !defined(__APPLE__) +#if defined(ARM_FPU_NONE) && !defined(TARGET_IOS) /* * If we're compiling with a soft float fallback and it * turns out that no VFP unit is available, we need to @@ -878,6 +812,7 @@ mono_arch_init (void) if (soft && !strncmp (soft, "1", 1)) arm_fpu = MONO_ARM_FPU_NONE; + g_free (soft); #endif #endif @@ -900,7 +835,7 @@ mono_arch_init (void) v7_supported = TRUE; #endif -#if defined(__APPLE__) +#if defined(TARGET_IOS) /* iOS is special-cased here because we don't yet have a way to properly detect CPU features on it. */ thumb_supported = TRUE; @@ -925,6 +860,7 @@ mono_arch_init (void) thumb_supported = strstr (cpu_arch, "thumb") != NULL; thumb2_supported = strstr (cpu_arch, "thumb2") != NULL; + g_free (cpu_arch); } } @@ -1008,10 +944,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)) @@ -1336,11 +1268,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; @@ -1489,11 +1417,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; @@ -1582,6 +1506,7 @@ get_call_info (MonoMemPool *mp, MonoMethodSignature *sig) nwords = (align_size + sizeof (gpointer) -1 ) / sizeof (gpointer); ainfo->storage = RegTypeStructByVal; ainfo->struct_size = size; + ainfo->align = align; /* FIXME: align stack_size if needed */ if (eabi_supported) { if (align >= 8 && (gr & 1)) @@ -1713,8 +1638,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) @@ -2206,6 +2130,11 @@ mono_arch_get_llvm_call_info (MonoCompile *cfg, MonoMethodSignature *sig) linfo->ret.nslots = cinfo->ret.nregs; break; #endif + case RegTypeHFA: + linfo->ret.storage = LLVMArgFpStruct; + linfo->ret.nslots = cinfo->ret.nregs; + linfo->ret.esize = cinfo->ret.esize; + break; default: cfg->exception_message = g_strdup_printf ("unknown ret conv (%d)", cinfo->ret.storage); cfg->disable_llvm = TRUE; @@ -2228,12 +2157,31 @@ mono_arch_get_llvm_call_info (MonoCompile *cfg, MonoMethodSignature *sig) break; case RegTypeStructByVal: lainfo->storage = LLVMArgAsIArgs; - lainfo->nslots = ainfo->struct_size / sizeof (gpointer); + if (eabi_supported && ainfo->align == 8) { + /* LLVM models this by passing an int64 array */ + lainfo->nslots = ALIGN_TO (ainfo->struct_size, 8) / 8; + lainfo->esize = 8; + } else { + lainfo->nslots = ainfo->struct_size / sizeof (gpointer); + lainfo->esize = 4; + } + + printf ("D: %d\n", ainfo->align); break; case RegTypeStructByAddr: case RegTypeStructByAddrOnStack: lainfo->storage = LLVMArgVtypeByRef; break; + case RegTypeHFA: { + int j; + + lainfo->storage = LLVMArgAsFpArgs; + lainfo->nslots = ainfo->nregs; + lainfo->esize = ainfo->esize; + for (j = 0; j < ainfo->nregs; ++j) + lainfo->pair_storage [j] = LLVMArgInFPReg; + break; + } default: cfg->exception_message = g_strdup_printf ("ainfo->storage (%d)", ainfo->storage); cfg->disable_llvm = TRUE; @@ -2842,10 +2790,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: @@ -2947,10 +2891,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: @@ -4265,16 +4205,10 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) } break; case OP_TLS_GET: - code = mono_arm_emit_tls_get (cfg, code, ins->dreg, ins->inst_offset); - break; - case OP_TLS_GET_REG: - code = mono_arm_emit_tls_get_reg (cfg, code, ins->dreg, ins->sreg1); + code = emit_tls_get (code, ins->dreg, ins->inst_offset); break; case OP_TLS_SET: - code = mono_arm_emit_tls_set (cfg, code, ins->sreg1, ins->inst_offset); - break; - case OP_TLS_SET_REG: - code = mono_arm_emit_tls_set_reg (cfg, code, ins->sreg1, ins->sreg2); + code = emit_tls_set (code, ins->sreg1, ins->inst_offset); break; case OP_ATOMIC_EXCHANGE_I4: case OP_ATOMIC_CAS_I4: @@ -5132,19 +5066,13 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) break; } case OP_GENERIC_CLASS_INIT: { - static int byte_offset = -1; - static guint8 bitmask; - guint32 imm8; + int byte_offset; guint8 *jump; - if (byte_offset < 0) - mono_marshal_find_bitfield_offset (MonoVTable, initialized, &byte_offset, &bitmask); + byte_offset = MONO_STRUCT_OFFSET (MonoVTable, initialized); g_assert (arm_is_imm8 (byte_offset)); ARM_LDRSB_IMM (code, ARMREG_IP, ins->sreg1, byte_offset); - imm8 = mono_arm_is_rotated_imm8 (bitmask, &rot_amount); - g_assert (imm8 >= 0); - ARM_AND_REG_IMM (code, ARMREG_IP, ARMREG_IP, imm8, rot_amount); ARM_CMP_REG_IMM (code, ARMREG_IP, 0, 0); jump = code; ARM_B_COND (code, ARMCOND_NE, 0); @@ -5981,38 +5909,6 @@ mono_arch_register_lowlevel_calls (void) mono_register_jit_icall (mono_arm_throw_exception, "mono_arm_throw_exception", mono_create_icall_signature ("void"), TRUE); mono_register_jit_icall (mono_arm_throw_exception_by_token, "mono_arm_throw_exception_by_token", mono_create_icall_signature ("void"), TRUE); mono_register_jit_icall (mono_arm_unaligned_stack, "mono_arm_unaligned_stack", mono_create_icall_signature ("void"), TRUE); - -#ifndef MONO_CROSS_COMPILE - if (mono_arm_have_tls_get ()) { - MonoTlsImplementation tls_imp = mono_arm_get_tls_implementation (); - - 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); - - if (tls_imp.get_tls_thunk_end) { - mono_tramp_info_register ( - mono_tramp_info_create ( - "mono_get_tls_key", - (guint8*)tls_imp.get_tls_thunk, - (guint8*)tls_imp.get_tls_thunk_end - (guint8*)tls_imp.get_tls_thunk, - NULL, - mono_arch_get_cie_program () - ), - NULL - ); - mono_tramp_info_register ( - mono_tramp_info_create ( - "mono_set_tls_key", - (guint8*)tls_imp.set_tls_thunk, - (guint8*)tls_imp.set_tls_thunk_end - (guint8*)tls_imp.set_tls_thunk, - NULL, - mono_arch_get_cie_program () - ), - NULL - ); - } - } -#endif } #define patch_lis_ori(ip,val) do {\ @@ -6922,7 +6818,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; @@ -6974,7 +6870,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; @@ -6982,7 +6878,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); @@ -7148,7 +7044,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); @@ -7512,3 +7408,37 @@ mono_arch_get_call_info (MonoMemPool *mp, MonoMethodSignature *sig) { return get_call_info (mp, sig); } + +gpointer +mono_arch_get_get_tls_tramp (void) +{ + return NULL; +} + +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; +} + +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; +}