* (C) 2003 Ximian, Inc.
* Copyright 2003-2011 Novell, Inc (http://www.novell.com)
* Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include "mini.h"
#include <string.h>
#include "mini-gc.h"
#include "mono/arch/arm/arm-vfp-codegen.h"
-#if defined(HAVE_KW_THREAD) && defined(__linux__) \
+#if (defined(HAVE_KW_THREAD) && defined(__linux__) && defined(__ARM_EABI__)) \
|| defined(TARGET_ANDROID) \
- || defined(TARGET_IOS)
+ || (defined(TARGET_IOS) && !defined(TARGET_WATCHOS))
#define HAVE_FAST_TLS
#endif
#endif
/* This mutex protects architecture specific caches */
-#define mono_mini_arch_lock() mono_mutex_lock (&mini_arch_mutex)
-#define mono_mini_arch_unlock() mono_mutex_unlock (&mini_arch_mutex)
+#define mono_mini_arch_lock() mono_os_mutex_lock (&mini_arch_mutex)
+#define mono_mini_arch_unlock() mono_os_mutex_unlock (&mini_arch_mutex)
static mono_mutex_t mini_arch_mutex;
static gboolean v5_supported = FALSE;
static gboolean v6_supported = FALSE;
static gboolean v7_supported = FALSE;
static gboolean v7s_supported = FALSE;
+static gboolean v7k_supported = FALSE;
static gboolean thumb_supported = FALSE;
static gboolean thumb2_supported = FALSE;
/*
static int i8_align;
-static volatile int ss_trigger_var = 0;
-
static gpointer single_step_tramp, breakpoint_tramp;
/*
#endif /* #ifndef DISABLE_JIT */
-#ifndef MONO_CROSS_COMPILE
-static gboolean
-mono_arm_have_fast_tls (void)
-{
- if (mini_get_debug_options ()->arm_use_fallback_tls)
- return FALSE;
-#if (defined(HAVE_KW_THREAD) && defined(__linux__)) \
- || defined(TARGET_ANDROID)
- guint32* kuser_get_tls = (void*)0xffff0fe0;
- guint32 expected [] = {0xee1d0f70, 0xe12fff1e};
-
- /* Expecting mrc + bx lr in the kuser_get_tls kernel helper */
- return memcmp (kuser_get_tls, expected, 8) == 0;
-#elif defined(TARGET_IOS)
- guint32 expected [] = {0x1f70ee1d, 0x0103f021, 0x0020f851, 0xbf004770};
- /* Discard thumb bit */
- guint32* pthread_getspecific_addr = (guint32*) ((guint32)pthread_getspecific & 0xfffffffe);
- return memcmp ((void*)pthread_getspecific_addr, expected, 16) == 0;
-#else
- return FALSE;
-#endif
-}
-#endif
-
/*
* mono_arm_have_tls_get:
*
{
const char *cpu_arch;
- mono_mutex_init_recursive (&mini_arch_mutex);
+ mono_os_mutex_init_recursive (&mini_arch_mutex);
if (mini_get_debug_options ()->soft_breakpoints) {
- single_step_tramp = mini_get_single_step_trampoline ();
breakpoint_tramp = mini_get_breakpoint_trampoline ();
} else {
ss_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ|MONO_MMAP_32BIT);
mono_aot_register_jit_icall ("mono_arm_throw_exception", mono_arm_throw_exception);
mono_aot_register_jit_icall ("mono_arm_throw_exception_by_token", mono_arm_throw_exception_by_token);
mono_aot_register_jit_icall ("mono_arm_resume_unwind", mono_arm_resume_unwind);
-#if defined(ENABLE_GSHAREDVT)
+#if defined(MONO_ARCH_GSHAREDVT_SUPPORTED)
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;
v5_supported = mono_hwcap_arm_is_v5;
v6_supported = mono_hwcap_arm_is_v6;
v7_supported = mono_hwcap_arm_is_v7;
- v7s_supported = mono_hwcap_arm_is_v7s;
#if defined(__APPLE__)
/* iOS is special-cased here because we don't yet
v6_supported = cpu_arch [4] >= '6';
v7_supported = cpu_arch [4] >= '7';
v7s_supported = strncmp (cpu_arch, "armv7s", 6) == 0;
+ v7k_supported = strncmp (cpu_arch, "armv7k", 6) == 0;
}
thumb_supported = strstr (cpu_arch, "thumb") != NULL;
gboolean
mono_arch_opcode_needs_emulation (MonoCompile *cfg, int opcode)
{
- if (v7s_supported) {
+ if (v7s_supported || v7k_supported) {
switch (opcode) {
case OP_IDIV:
case OP_IREM:
#endif /* #ifndef DISABLE_JIT */
-#ifndef __GNUC_PREREQ
-#define __GNUC_PREREQ(maj, min) (0)
-#endif
-
void
mono_arch_flush_icache (guint8 *code, gint size)
{
-#if defined(__native_client__)
+#if defined(MONO_CROSS_COMPILE) || defined(__native_client__)
// For Native Client we don't have to flush i-cache here,
// as it's being done by dyncode interface.
-#else
-
-#ifdef MONO_CROSS_COMPILE
#elif __APPLE__
sys_icache_invalidate (code, size);
-#elif __GNUC_PREREQ(4, 3)
- __builtin___clear_cache (code, code + size);
-#elif __GNUC_PREREQ(4, 1)
- __clear_cache (code, code + size);
-#elif defined(PLATFORM_ANDROID)
- const int syscall = 0xf0002;
- __asm __volatile (
- "mov r0, %0\n"
- "mov r1, %1\n"
- "mov r7, %2\n"
- "mov r2, #0x0\n"
- "svc 0x00000000\n"
- :
- : "r" (code), "r" (code + size), "r" (syscall)
- : "r0", "r1", "r7", "r2"
- );
#else
- __asm __volatile ("mov r0, %0\n"
- "mov r1, %1\n"
- "mov r2, %2\n"
- "swi 0x9f0002 @ sys_cacheflush"
- : /* no outputs */
- : "r" (code), "r" (code + size), "r" (0)
- : "r0", "r1", "r3" );
+ __builtin___clear_cache (code, code + size);
#endif
-#endif /* !__native_client__ */
}
-typedef enum {
- RegTypeNone,
- /* Passed/returned in an ireg */
- RegTypeGeneral,
- /* Passed/returned in a pair of iregs */
- RegTypeIRegPair,
- /* Passed on the stack */
- RegTypeBase,
- /* First word in r3, second word on the stack */
- RegTypeBaseGen,
- /* FP value passed in either an ireg or a vfp reg */
- RegTypeFP,
- RegTypeStructByVal,
- RegTypeStructByAddr,
- /* gsharedvt argument passed by addr in greg */
- RegTypeGSharedVtInReg,
- /* gsharedvt argument passed by addr on stack */
- RegTypeGSharedVtOnStack,
- RegTypeHFA
-} ArgStorage;
-
-typedef struct {
- gint32 offset;
- guint16 vtsize; /* in param area */
- /* RegTypeHFA */
- int esize;
- /* RegTypeHFA */
- int nregs;
- guint8 reg;
- ArgStorage storage;
- gint32 struct_size;
- guint8 size : 4; /* 1, 2, 4, 8, or regs used by RegTypeStructByVal */
-} ArgInfo;
-
-typedef struct {
- int nargs;
- guint32 stack_usage;
- /* The index of the vret arg in the argument list for RegTypeStructByAddr */
- int vret_arg_index;
- ArgInfo ret;
- ArgInfo sig_cookie;
- ArgInfo args [1];
-} CallInfo;
-
#define DEBUG(a)
static void inline
cinfo->ret.reg = ARMREG_R0;
break;
}
- // FIXME: Only for variable types
- if (mini_is_gsharedvt_type (t)) {
+ if (mini_is_gsharedvt_variable_type (t)) {
cinfo->ret.storage = RegTypeStructByAddr;
break;
}
}
}
- DEBUG(printf("params: %d\n", sig->param_count));
+ DEBUG(g_print("params: %d\n", sig->param_count));
for (i = pstart; i < sig->param_count; ++i) {
ArgInfo *ainfo = &cinfo->args [n];
/* Emit the signature cookie just before the implicit arguments */
add_general (&gr, &stack_size, &cinfo->sig_cookie, TRUE);
}
- DEBUG(printf("param %d: ", i));
+ DEBUG(g_print("param %d: ", i));
if (sig->params [i]->byref) {
- DEBUG(printf("byref\n"));
+ DEBUG(g_print("byref\n"));
add_general (&gr, &stack_size, ainfo, TRUE);
n++;
continue;
add_general (&gr, &stack_size, ainfo, TRUE);
break;
}
- if (mini_is_gsharedvt_type (t)) {
+ if (mini_is_gsharedvt_variable_type (t)) {
/* gsharedvt arguments are passed by ref */
g_assert (mini_is_gsharedvt_type (t));
add_general (&gr, &stack_size, ainfo, TRUE);
ainfo->reg = fpr;
ainfo->nregs = nfields;
ainfo->esize = esize;
- fpr += nfields;
+ if (esize == 4)
+ fpr += nfields;
+ else
+ fpr += nfields * 2;
break;
} else {
fpr = ARM_VFP_F16;
else
size = mini_type_stack_size_full (t, &align, FALSE);
}
- DEBUG(printf ("load %d bytes struct\n", size));
+ DEBUG(g_print ("load %d bytes struct\n", size));
align_size = size;
nwords = 0;
align_size += (sizeof (gpointer) - 1);
}
/* align stack size to 8 */
- DEBUG (printf (" stack size: %d (%d)\n", (stack_size + 15) & ~15, stack_size));
+ DEBUG (g_print (" stack size: %d (%d)\n", (stack_size + 15) & ~15, stack_size));
stack_size = (stack_size + 7) & ~7;
cinfo->stack_usage = stack_size;
ins->opcode = OP_REGOFFSET;
ins->inst_basereg = cfg->frame_reg;
if (G_UNLIKELY (cfg->verbose_level > 1)) {
- printf ("vret_addr =");
+ g_print ("vret_addr =");
mono_print_ins (cfg->vret_addr);
}
offset += sizeof(gpointer);
offset += size;
}
- if (cfg->arch.seq_point_read_var) {
+ if (cfg->arch.seq_point_ss_method_var) {
MonoInst *ins;
- ins = cfg->arch.seq_point_read_var;
-
- size = 4;
- align = 4;
- offset += align - 1;
- offset &= ~(align - 1);
- ins->opcode = OP_REGOFFSET;
- ins->inst_basereg = cfg->frame_reg;
- ins->inst_offset = offset;
- offset += size;
-
ins = cfg->arch.seq_point_ss_method_var;
size = 4;
align = 4;
/* These arguments are saved to the stack in the prolog */
ins->inst_offset = offset;
if (cfg->verbose_level >= 2)
- printf ("arg %d allocated to %s+0x%0x.\n", i, mono_arch_regname (ins->inst_basereg), (int)ins->inst_offset);
+ g_print ("arg %d allocated to %s+0x%0x.\n", i, mono_arch_regname (ins->inst_basereg), (int)ins->inst_offset);
// FIXME:
offset += 32;
break;
if (cinfo->ret.storage == RegTypeStructByAddr) {
cfg->vret_addr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_ARG);
if (G_UNLIKELY (cfg->verbose_level > 1)) {
- printf ("vret_addr = ");
+ g_print ("vret_addr = ");
mono_print_ins (cfg->vret_addr);
}
}
if (cfg->gen_sdb_seq_points) {
if (cfg->soft_breakpoints) {
- MonoInst *ins = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
- ins->flags |= MONO_INST_VOLATILE;
- cfg->arch.seq_point_read_var = ins;
+ MonoInst *ins;
ins = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
ins->flags |= MONO_INST_VOLATILE;
case RegTypeIRegPair:
case RegTypeBase:
case RegTypeBaseGen:
- linfo->args [i].storage = LLVMArgInIReg;
+ linfo->args [i].storage = LLVMArgNormal;
break;
case RegTypeStructByVal:
linfo->args [i].storage = LLVMArgAsIArgs;
if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
MONO_INST_NEW (cfg, ins, OP_MOVE);
ins->dreg = mono_alloc_ireg (cfg);
- ins->sreg1 = in->dreg + 1;
+ ins->sreg1 = MONO_LVREG_LS (in->dreg);
MONO_ADD_INS (cfg->cbb, ins);
mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
MONO_INST_NEW (cfg, ins, OP_MOVE);
ins->dreg = mono_alloc_ireg (cfg);
- ins->sreg1 = in->dreg + 2;
+ ins->sreg1 = MONO_LVREG_MS (in->dreg);
MONO_ADD_INS (cfg->cbb, ins);
mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg + 1, FALSE);
} else if (!t->byref && ((t->type == MONO_TYPE_R8) || (t->type == MONO_TYPE_R4))) {
} else {
int creg;
+ cfg->param_area = MAX (cfg->param_area, 8);
MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, ARMREG_SP, (cfg->param_area - 8), in->dreg);
creg = mono_alloc_ireg (cfg);
MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOAD_MEMBASE, creg, ARMREG_SP, (cfg->param_area - 8));
} else {
int creg;
+ cfg->param_area = MAX (cfg->param_area, 8);
MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, ARMREG_SP, (cfg->param_area - 8), in->dreg);
creg = mono_alloc_ireg (cfg);
MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOAD_MEMBASE, creg, ARMREG_SP, (cfg->param_area - 8));
break;
case RegTypeBaseGen:
if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
- MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, ARMREG_SP, ainfo->offset, (G_BYTE_ORDER == G_BIG_ENDIAN) ? in->dreg + 1 : in->dreg + 2);
+ MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, ARMREG_SP, ainfo->offset, (G_BYTE_ORDER == G_BIG_ENDIAN) ? MONO_LVREG_LS (in->dreg) : MONO_LVREG_MS (in->dreg));
MONO_INST_NEW (cfg, ins, OP_MOVE);
ins->dreg = mono_alloc_ireg (cfg);
- ins->sreg1 = G_BYTE_ORDER == G_BIG_ENDIAN ? in->dreg + 2 : in->dreg + 1;
+ ins->sreg1 = G_BYTE_ORDER == G_BIG_ENDIAN ? MONO_LVREG_MS (in->dreg) : MONO_LVREG_LS (in->dreg);
MONO_ADD_INS (cfg->cbb, ins);
mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ARMREG_R3, FALSE);
} else if (!t->byref && (t->type == MONO_TYPE_R8)) {
/* This should work for soft-float as well */
+ cfg->param_area = MAX (cfg->param_area, 8);
MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, ARMREG_SP, (cfg->param_area - 8), in->dreg);
creg = mono_alloc_ireg (cfg);
mono_call_inst_add_outarg_reg (cfg, call, creg, ARMREG_R3, FALSE);
call->float_args = g_slist_append_mempool (cfg->mempool, call->float_args, fad);
} else {
- add_outarg_reg (cfg, call, RegTypeFP, ainfo->reg + i, load);
+ add_outarg_reg (cfg, call, RegTypeFP, ainfo->reg + (i * 2), load);
}
}
break;
MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg);
} else {
MONO_INST_NEW (cfg, ins, OP_SETLRET);
- ins->sreg1 = val->dreg + 1;
- ins->sreg2 = val->dreg + 2;
+ ins->sreg1 = MONO_LVREG_LS (val->dreg);
+ ins->sreg2 = MONO_LVREG_MS (val->dreg);
MONO_ADD_INS (cfg->cbb, ins);
}
return;
switch (ainfo->storage) {
case RegTypeGeneral:
- break;
case RegTypeIRegPair:
+ case RegTypeBaseGen:
break;
case RegTypeBase:
if (ainfo->offset >= (DYN_CALL_STACK_ARGS * sizeof (gpointer)))
ArgInfo *ainfo = &dinfo->cinfo->args [i + sig->hasthis];
int slot = -1;
- if (ainfo->storage == RegTypeGeneral || ainfo->storage == RegTypeIRegPair || ainfo->storage == RegTypeStructByVal)
+ if (ainfo->storage == RegTypeGeneral || ainfo->storage == RegTypeIRegPair || ainfo->storage == RegTypeStructByVal) {
slot = ainfo->reg;
- else if (ainfo->storage == RegTypeBase)
+ } else if (ainfo->storage == RegTypeBase) {
slot = PARAM_REGS + (ainfo->offset / 4);
- else
+ } else if (ainfo->storage == RegTypeBaseGen) {
+ /* slot + 1 is the first stack slot, so the code below will work */
+ slot = 3;
+ } else {
g_assert_not_reached ();
+ }
if (t->byref) {
p->regs [slot] = (mgreg_t)*arg;
MONO_DELETE_INS (bb, ins);
continue;
} else {
- //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
+ //static int c = 0; g_print ("MATCHX %s %d\n", cfg->method->name,c++);
ins->opcode = OP_MOVE;
ins->sreg1 = last_ins->sreg1;
}
|| last_ins->opcode == OP_STORE_MEMBASE_IMM) &&
ins->inst_basereg == last_ins->inst_destbasereg &&
ins->inst_offset == last_ins->inst_offset) {
- //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
+ //static int c = 0; g_print ("MATCHX %s %d\n", cfg->method->name,c++);
ins->opcode = OP_ICONST;
ins->inst_c0 = last_ins->inst_imm;
g_assert_not_reached (); // check this rule
case OP_IOR_IMM:
case OP_IXOR_IMM:
if ((imm8 = mono_arm_is_rotated_imm8 (ins->inst_imm, &rot_amount)) < 0) {
+ int opcode2 = mono_op_imm_to_op (ins->opcode);
ADD_NEW_INS (cfg, temp, OP_ICONST);
temp->inst_c0 = ins->inst_imm;
temp->dreg = mono_alloc_ireg (cfg);
ins->sreg2 = temp->dreg;
- ins->opcode = mono_op_imm_to_op (ins->opcode);
+ if (opcode2 == -1)
+ g_error ("mono_op_imm_to_op failed for %s\n", mono_inst_name (ins->opcode));
+ ins->opcode = opcode2;
}
if (ins->opcode == OP_SBB || ins->opcode == OP_ISBB || ins->opcode == OP_SUBCC)
goto loop_start;
case OP_IDIV_IMM:
case OP_IDIV_UN_IMM:
case OP_IREM_IMM:
- case OP_IREM_UN_IMM:
+ case OP_IREM_UN_IMM: {
+ int opcode2 = mono_op_imm_to_op (ins->opcode);
ADD_NEW_INS (cfg, temp, OP_ICONST);
temp->inst_c0 = ins->inst_imm;
temp->dreg = mono_alloc_ireg (cfg);
ins->sreg2 = temp->dreg;
- ins->opcode = mono_op_imm_to_op (ins->opcode);
+ if (opcode2 == -1)
+ g_error ("mono_op_imm_to_op failed for %s\n", mono_inst_name (ins->opcode));
+ ins->opcode = opcode2;
break;
+ }
case OP_LOCALLOC_IMM:
ADD_NEW_INS (cfg, temp, OP_ICONST);
temp->inst_c0 = ins->inst_imm;
if (long_ins->opcode == OP_LNEG) {
ins = long_ins;
- MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ARM_RSBS_IMM, ins->dreg + 1, ins->sreg1 + 1, 0);
- MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ARM_RSC_IMM, ins->dreg + 2, ins->sreg1 + 2, 0);
+ MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ARM_RSBS_IMM, MONO_LVREG_LS (ins->dreg), MONO_LVREG_LS (ins->sreg1), 0);
+ MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ARM_RSC_IMM, MONO_LVREG_MS (ins->dreg), MONO_LVREG_MS (ins->sreg1), 0);
NULLIFY_INS (ins);
}
}
/* Free entry */
target_thunk = p;
break;
+ } else if (((guint32*)p) [2] == (guint32)target) {
+ /* Thunk already points to target */
+ target_thunk = p;
+ break;
}
}
}
- //printf ("THUNK: %p %p %p\n", code, target, target_thunk);
+ //g_print ("THUNK: %p %p %p\n", code, target, target_thunk);
if (!target_thunk) {
mono_mini_arch_unlock ();
code += 4;
return code;
#endif
+ if (mini_get_debug_options()->single_imm_size && v7_supported) {
+ ARM_MOVW_REG_IMM (code, dreg, val & 0xffff);
+ ARM_MOVT_REG_IMM (code, dreg, (val >> 16) & 0xffff);
+ return code;
+ }
+
if ((imm8 = mono_arm_is_rotated_imm8 (val, &rot_amount)) >= 0) {
ARM_MOV_REG_IMM (code, dreg, imm8, rot_amount);
} else if ((imm8 = mono_arm_is_rotated_imm8 (~val, &rot_amount)) >= 0) {
int i;
MonoInst *info_var = cfg->arch.seq_point_info_var;
MonoInst *ss_trigger_page_var = cfg->arch.ss_trigger_page_var;
- MonoInst *ss_read_var = cfg->arch.seq_point_read_var;
MonoInst *ss_method_var = cfg->arch.seq_point_ss_method_var;
MonoInst *bp_method_var = cfg->arch.seq_point_bp_method_var;
MonoInst *var;
g_assert (arm_is_imm12 (info_var->inst_offset));
}
- if (!cfg->soft_breakpoints) {
+ if (!cfg->soft_breakpoints && !cfg->compile_aot) {
/*
* Read from the single stepping trigger page. This will cause a
* SIGSEGV when single stepping is enabled.
if (ins->flags & MONO_INST_SINGLE_STEP_LOC) {
if (cfg->soft_breakpoints) {
- /* Load the address of the sequence point trigger variable. */
- var = ss_read_var;
+ /* Load the address of the sequence point method variable. */
+ var = ss_method_var;
g_assert (var);
g_assert (var->opcode == OP_REGOFFSET);
g_assert (arm_is_imm12 (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);
-
- /* Load the address of the sequence point method. */
- 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);
-
/* Call it conditionally. */
ARM_BLX_REG_COND (code, ARMCOND_NE, dreg);
} else {
ARM_AND_REG_IMM (code, ins->dreg, ins->sreg1, imm8, rot_amount);
break;
case OP_IDIV:
- g_assert (v7s_supported);
+ g_assert (v7s_supported || v7k_supported);
ARM_SDIV (code, ins->dreg, ins->sreg1, ins->sreg2);
break;
case OP_IDIV_UN:
- g_assert (v7s_supported);
+ g_assert (v7s_supported || v7k_supported);
ARM_UDIV (code, ins->dreg, ins->sreg1, ins->sreg2);
break;
case OP_IREM:
- g_assert (v7s_supported);
+ g_assert (v7s_supported || v7k_supported);
ARM_SDIV (code, ARMREG_LR, ins->sreg1, ins->sreg2);
ARM_MLS (code, ins->dreg, ARMREG_LR, ins->sreg2, ins->sreg1);
break;
case OP_IREM_UN:
- g_assert (v7s_supported);
+ g_assert (v7s_supported || v7k_supported);
ARM_UDIV (code, ARMREG_LR, ins->sreg1, ins->sreg2);
ARM_MLS (code, ins->dreg, ARMREG_LR, ins->sreg2, ins->sreg1);
break;
if (IS_HARD_FLOAT)
code = emit_float_args (cfg, call, code, &max_len, &offset);
- if (!arm_is_imm12 (ins->inst_offset))
+ if (!arm_is_imm12 (ins->inst_offset)) {
+ /* sreg1 might be IP */
+ ARM_MOV_REG_REG (code, ARMREG_LR, ins->sreg1);
code = mono_arm_emit_load_imm (code, ARMREG_IP, ins->inst_offset);
- ARM_MOV_REG_REG (code, ARMREG_LR, ARMREG_PC);
- if (!arm_is_imm12 (ins->inst_offset))
- ARM_LDR_REG_REG (code, ARMREG_PC, ins->sreg1, ARMREG_IP);
- else
+ ARM_ADD_REG_REG (code, ARMREG_IP, ARMREG_IP, ARMREG_LR);
+ ARM_MOV_REG_REG (code, ARMREG_LR, ARMREG_PC);
+ ARM_LDR_IMM (code, ARMREG_PC, ARMREG_IP, 0);
+ } else {
+ ARM_MOV_REG_REG (code, ARMREG_LR, ARMREG_PC);
ARM_LDR_IMM (code, ARMREG_PC, ins->sreg1, ins->inst_offset);
+ }
ins->flags |= MONO_INST_GC_CALLSITE;
ins->backend.pc_offset = code - cfg->native_code;
code = emit_move_return_value (cfg, ins, code);
}
case OP_LOCALLOC: {
/* round the size to 8 bytes */
- ARM_ADD_REG_IMM8 (code, ins->dreg, ins->sreg1, 7);
- ARM_BIC_REG_IMM8 (code, ins->dreg, ins->dreg, 7);
+ ARM_ADD_REG_IMM8 (code, ins->dreg, ins->sreg1, (MONO_ARCH_FRAME_ALIGNMENT - 1));
+ ARM_BIC_REG_IMM8 (code, ins->dreg, ins->dreg, (MONO_ARCH_FRAME_ALIGNMENT - 1));
ARM_SUB_REG_REG (code, ARMREG_SP, ARMREG_SP, ins->dreg);
/* memzero the area: dreg holds the size, sp is the pointer */
if (ins->flags & MONO_INST_INIT) {
}
case OP_START_HANDLER: {
MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
+ int param_area = ALIGN_TO (cfg->param_area, MONO_ARCH_FRAME_ALIGNMENT);
int i, rot_amount;
/* Reserve a param area, see filter-stack.exe */
- if (cfg->param_area) {
- if ((i = mono_arm_is_rotated_imm8 (cfg->param_area, &rot_amount)) >= 0) {
+ if (param_area) {
+ if ((i = mono_arm_is_rotated_imm8 (param_area, &rot_amount)) >= 0) {
ARM_SUB_REG_IMM (code, ARMREG_SP, ARMREG_SP, i, rot_amount);
} else {
- code = mono_arm_emit_load_imm (code, ARMREG_IP, cfg->param_area);
+ code = mono_arm_emit_load_imm (code, ARMREG_IP, param_area);
ARM_SUB_REG_REG (code, ARMREG_SP, ARMREG_SP, ARMREG_IP);
}
}
}
case OP_ENDFILTER: {
MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
+ int param_area = ALIGN_TO (cfg->param_area, MONO_ARCH_FRAME_ALIGNMENT);
int i, rot_amount;
/* Free the param area */
- if (cfg->param_area) {
- if ((i = mono_arm_is_rotated_imm8 (cfg->param_area, &rot_amount)) >= 0) {
+ if (param_area) {
+ if ((i = mono_arm_is_rotated_imm8 (param_area, &rot_amount)) >= 0) {
ARM_ADD_REG_IMM (code, ARMREG_SP, ARMREG_SP, i, rot_amount);
} else {
- code = mono_arm_emit_load_imm (code, ARMREG_IP, cfg->param_area);
+ code = mono_arm_emit_load_imm (code, ARMREG_IP, param_area);
ARM_ADD_REG_REG (code, ARMREG_SP, ARMREG_SP, ARMREG_IP);
}
}
}
case OP_ENDFINALLY: {
MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
+ int param_area = ALIGN_TO (cfg->param_area, MONO_ARCH_FRAME_ALIGNMENT);
int i, rot_amount;
/* Free the param area */
- if (cfg->param_area) {
- if ((i = mono_arm_is_rotated_imm8 (cfg->param_area, &rot_amount)) >= 0) {
+ if (param_area) {
+ if ((i = mono_arm_is_rotated_imm8 (param_area, &rot_amount)) >= 0) {
ARM_ADD_REG_IMM (code, ARMREG_SP, ARMREG_SP, i, rot_amount);
} else {
- code = mono_arm_emit_load_imm (code, ARMREG_IP, cfg->param_area);
+ code = mono_arm_emit_load_imm (code, ARMREG_IP, param_area);
ARM_ADD_REG_REG (code, ARMREG_SP, ARMREG_SP, ARMREG_IP);
}
}
#endif
ARM_CMPD (code, vfp_scratch2, vfp_scratch1);
ARM_FMSTAT (code);
- EMIT_COND_SYSTEM_EXCEPTION_FLAGS (ARMCOND_GT, "ArithmeticException");
+ EMIT_COND_SYSTEM_EXCEPTION_FLAGS (ARMCOND_GT, "OverflowException");
ARM_CMPD (code, ins->sreg1, ins->sreg1);
ARM_FMSTAT (code);
- EMIT_COND_SYSTEM_EXCEPTION_FLAGS (ARMCOND_VS, "ArithmeticException");
+ EMIT_COND_SYSTEM_EXCEPTION_FLAGS (ARMCOND_VS, "OverflowException");
ARM_CPYD (code, ins->dreg, ins->sreg1);
code = mono_arm_emit_vfp_scratch_restore (cfg, code, vfp_scratch1);
ins->backend.pc_offset = code - cfg->native_code;
bb->spill_slot_defs = g_slist_prepend_mempool (cfg->mempool, bb->spill_slot_defs, ins);
break;
+ case OP_GC_SAFE_POINT: {
+ const char *polling_func = NULL;
+ guint8 *buf [1];
+
+ g_assert (mono_threads_is_coop_enabled ());
+
+ polling_func = "mono_threads_state_poll";
+ ARM_LDR_IMM (code, ARMREG_IP, ins->sreg1, 0);
+ ARM_CMP_REG_IMM (code, ARMREG_IP, 0, 0);
+ buf [0] = code;
+ ARM_B_COND (code, ARMCOND_EQ, 0);
+ mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, polling_func);
+ code = emit_call_seq (cfg, code);
+ arm_patch (buf [0], code);
+ break;
+ }
default:
g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
/* The signature doesn't matter */
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 ()) {
- if (mono_arm_have_fast_tls ()) {
- mono_register_jit_icall (mono_fast_get_tls_key, "mono_get_tls_key", mono_create_icall_signature ("ptr ptr"), TRUE);
- mono_register_jit_icall (mono_fast_set_tls_key, "mono_set_tls_key", mono_create_icall_signature ("void ptr ptr"), TRUE);
- } else {
- g_warning ("No fast tls on device. Using fallbacks.");
- mono_register_jit_icall (mono_fallback_get_tls_key, "mono_get_tls_key", mono_create_icall_signature ("ptr ptr"), TRUE);
- mono_register_jit_icall (mono_fallback_set_tls_key, "mono_set_tls_key", mono_create_icall_signature ("void ptr ptr"), TRUE);
+ 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
}
}
+void
+mono_arm_unaligned_stack (MonoMethod *method)
+{
+ g_assert_not_reached ();
+}
+
#ifndef DISABLE_JIT
/*
}
/* the stack used in the pushed regs */
- if (prev_sp_offset & 4)
- alloc_size += 4;
+ alloc_size += ALIGN_TO (prev_sp_offset, MONO_ARCH_FRAME_ALIGNMENT) - prev_sp_offset;
cfg->stack_usage = alloc_size;
if (alloc_size) {
if ((i = mono_arm_is_rotated_imm8 (alloc_size, &rot_amount)) >= 0) {
max_offset += ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
}
+ /* stack alignment check */
+ /*
+ {
+ guint8 *buf [16];
+ ARM_MOV_REG_REG (code, ARMREG_LR, ARMREG_SP);
+ code = mono_arm_emit_load_imm (code, ARMREG_IP, MONO_ARCH_FRAME_ALIGNMENT -1);
+ ARM_AND_REG_REG (code, ARMREG_LR, ARMREG_LR, ARMREG_IP);
+ ARM_CMP_REG_IMM (code, ARMREG_LR, 0, 0);
+ buf [0] = code;
+ ARM_B_COND (code, ARMCOND_EQ, 0);
+ if (cfg->compile_aot)
+ ARM_MOV_REG_IMM8 (code, ARMREG_R0, 0);
+ else
+ code = mono_arm_emit_load_imm (code, ARMREG_R0, (guint32)cfg->method);
+ mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, "mono_arm_unaligned_stack");
+ code = emit_call_seq (cfg, code);
+ arm_patch (buf [0], code);
+ }
+ */
+
/* store runtime generic context */
if (cfg->rgctx_var) {
MonoInst *ins = cfg->rgctx_var;
}
}
- if (cfg->arch.seq_point_read_var) {
- MonoInst *read_ins = cfg->arch.seq_point_read_var;
+ 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;
#ifdef USE_JUMP_TABLES
gpointer *jte;
#endif
- g_assert (read_ins->opcode == OP_REGOFFSET);
- g_assert (arm_is_imm12 (read_ins->inst_offset));
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);
#ifdef USE_JUMP_TABLES
jte = mono_jumptable_add_entries (3);
- jte [0] = (gpointer)&ss_trigger_var;
- jte [1] = single_step_tramp;
- jte [2] = breakpoint_tramp;
+ jte [0] = &single_step_tramp;
+ jte [1] = breakpoint_tramp;
code = mono_arm_load_jumptable_entry_addr (code, jte, ARMREG_LR);
#else
ARM_MOV_REG_REG (code, ARMREG_LR, ARMREG_PC);
- ARM_B (code, 2);
- *(volatile int **)code = &ss_trigger_var;
- code += 4;
- *(gpointer*)code = single_step_tramp;
+ ARM_B (code, 1);
+ *(gpointer*)code = &single_step_tramp;
code += 4;
*(gpointer*)code = breakpoint_tramp;
code += 4;
#endif
ARM_LDR_IMM (code, ARMREG_IP, ARMREG_LR, 0);
- ARM_STR_IMM (code, ARMREG_IP, read_ins->inst_basereg, read_ins->inst_offset);
- ARM_LDR_IMM (code, ARMREG_IP, ARMREG_LR, 4);
ARM_STR_IMM (code, ARMREG_IP, ss_method_ins->inst_basereg, ss_method_ins->inst_offset);
- ARM_LDR_IMM (code, ARMREG_IP, ARMREG_LR, 8);
+ 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);
}
}
arm_patch (ip, code);
- exc_class = mono_class_from_name (mono_defaults.corlib, "System", patch_info->data.name);
- g_assert (exc_class);
+ exc_class = mono_class_load_from_name (mono_defaults.corlib, "System", patch_info->data.name);
ARM_MOV_REG_REG (code, ARMREG_R1, ARMREG_LR);
#ifdef USE_JUMP_TABLES
patch_info->ip.i = code - cfg->native_code;
ARM_BL (code, 0);
cfg->thunk_area += THUNK_SIZE;
- *(guint32*)(gpointer)code = exc_class->type_token;
+ *(guint32*)(gpointer)code = exc_class->type_token - MONO_TOKEN_TYPE_DEF;
code += 4;
#endif
break;
if (ss_trigger_page)
mono_mprotect (ss_trigger_page, mono_pagesize (), 0);
else
- ss_trigger_var = 1;
+ single_step_tramp = mini_get_single_step_trampoline ();
}
/*
if (ss_trigger_page)
mono_mprotect (ss_trigger_page, mono_pagesize (), MONO_MMAP_READ);
else
- ss_trigger_var = 0;
+ single_step_tramp = NULL;
}
#if __APPLE__
if (strstr (mtriple, "armv7s")) {
v7s_supported = TRUE;
}
+ if (strstr (mtriple, "armv7k")) {
+ v7k_supported = TRUE;
+ }
if (strstr (mtriple, "thumbv7s")) {
v5_supported = TRUE;
v6_supported = TRUE;
}
}
-#if defined(ENABLE_GSHAREDVT)
-
-#include "../../../mono-extensions/mono/mini/mini-arm-gsharedvt.c"
-
-#endif /* !MONOTOUCH */
+CallInfo*
+mono_arch_get_call_info (MonoMemPool *mp, MonoMethodSignature *sig)
+{
+ return get_call_info (mp, sig);
+}