X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmini%2Fmini-arm.c;h=9f2be7efacc50d72195d484bcfcafa460ac77e44;hb=2015a4ab214a8ec73e6a132da76d9681aaa99e06;hp=13a3ffee37f8159a3b1346bf99c09b007ab5159b;hpb=56e413a81e5e05fe5157546559de5b1e0b81214c;p=mono.git diff --git a/mono/mini/mini-arm.c b/mono/mini/mini-arm.c index 13a3ffee37f..9f2be7efacc 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" @@ -329,100 +323,58 @@ 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); - 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 - g_assert_not_reached (); +#if defined(__ARM_EABI__) && defined(__linux__) && !defined(PLATFORM_ANDROID) && !defined(MONO_CROSS_COMPILE) +#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); - 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); +#ifdef HAVE_AEABI_READ_TP + static gboolean have_fast_tls = FALSE; + static gboolean inited = FALSE; + + if (mini_get_debug_options ()->use_fallback_tls) + return FALSE; + + if (inited) + return have_fast_tls; + + if (v7_supported) { + gpointer tp1, tp2; + + tp1 = __aeabi_read_tp (); + asm volatile("mrc p15, 0, %0, c13, c0, 3" : "=r" (tp2)); + + have_fast_tls = tp1 && tp1 == tp2; } - if (dreg != ARMREG_R0) - ARM_MOV_REG_REG (code, dreg, ARMREG_R0); + 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 + g_assert (v7_supported); + 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; + 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; } @@ -435,31 +387,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 */ @@ -602,22 +536,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 @@ -869,7 +787,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 @@ -879,7 +797,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 @@ -899,6 +817,7 @@ mono_arch_init (void) if (soft && !strncmp (soft, "1", 1)) arm_fpu = MONO_ARM_FPU_NONE; + g_free (soft); #endif #endif @@ -921,7 +840,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; @@ -946,6 +865,7 @@ mono_arch_init (void) thumb_supported = strstr (cpu_arch, "thumb") != NULL; thumb2_supported = strstr (cpu_arch, "thumb2") != NULL; + g_free (cpu_arch); } } @@ -1029,10 +949,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)) @@ -1357,11 +1273,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; @@ -1510,11 +1422,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; @@ -1603,6 +1511,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)) @@ -1734,8 +1643,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) @@ -2227,6 +2135,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; @@ -2249,12 +2162,29 @@ 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; + } 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; @@ -2863,10 +2793,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: @@ -2968,10 +2894,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: @@ -4116,6 +4038,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* @@ -4286,16 +4220,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: @@ -5153,19 +5081,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); @@ -6002,40 +5924,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); - - get_tls_tramp = tls_imp.get_tls_thunk; - - 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 {\ @@ -7539,7 +7427,7 @@ mono_arch_get_call_info (MonoMemPool *mp, MonoMethodSignature *sig) gpointer mono_arch_get_get_tls_tramp (void) { - return get_tls_tramp; + return NULL; } static guint8* @@ -7555,3 +7443,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; +}