ArgumentClass class2 = ARG_CLASS_NO_CLASS;
MonoType *ptype;
- ptype = mono_type_get_underlying_type (type);
+ ptype = mini_type_get_underlying_type (NULL, type);
switch (ptype->type) {
case MONO_TYPE_BOOLEAN:
case MONO_TYPE_CHAR:
{
guint32 size, quad, nquads, i;
ArgumentClass args [2];
- MonoMarshalType *info;
+ MonoMarshalType *info = NULL;
MonoClass *klass;
+ MonoGenericSharingContext tmp_gsctx;
+
+ /*
+ * The gsctx currently contains no data, it is only used for checking whenever
+ * open types are allowed, some callers like mono_arch_get_argument_info ()
+ * don't pass it to us, so work around that.
+ */
+ if (!gsctx)
+ gsctx = &tmp_gsctx;
klass = mono_class_from_mono_type (type);
- if (sig->pinvoke)
- size = mono_type_native_stack_size (&klass->byval_arg, NULL);
- else
- size = mini_type_stack_size (gsctx, &klass->byval_arg, NULL);
+ size = mini_type_stack_size_full (gsctx, &klass->byval_arg, NULL, sig->pinvoke);
#ifndef PLATFORM_WIN32
if (!sig->pinvoke && !disable_vtypes_in_regs && ((is_return && (size == 8)) || (!is_return && (size <= 16)))) {
/* We pass and return vtypes of size 8 in a register */
/* return value */
{
- ret_type = mono_type_get_underlying_type (sig->ret);
- ret_type = mini_get_basic_type_from_generic (gsctx, ret_type);
+ ret_type = mini_type_get_underlying_type (gsctx, sig->ret);
switch (ret_type->type) {
case MONO_TYPE_BOOLEAN:
case MONO_TYPE_I1:
ArgInfo *ainfo = &cinfo->args [sig->hasthis + i];
MonoType *ptype;
+#ifdef PLATFORM_WIN32
+ /* The float param registers and other param registers must be the same index on Windows x64.*/
+ if (gr > fr)
+ fr = gr;
+ else if (fr > gr)
+ gr = fr;
+#endif
+
if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
/* We allways pass the sig cookie on the stack for simplicity */
/*
add_general (&gr, &stack_size, ainfo);
continue;
}
- ptype = mono_type_get_underlying_type (sig->params [i]);
- ptype = mini_get_basic_type_from_generic (gsctx, ptype);
+ ptype = mini_type_get_underlying_type (gsctx, sig->params [i]);
switch (ptype->type) {
case MONO_TYPE_BOOLEAN:
case MONO_TYPE_I1:
} else
*exclude_mask |= MONO_OPT_CMOV;
}
+
return opts;
}
break;
case ArgValuetypeInReg:
break;
- case ArgValuetypeAddrInIReg:
- break; /*FIXME: Not sure what to do for this case yet on Winx64*/
+ case ArgValuetypeAddrInIReg: {
+ MonoInst *indir;
+ g_assert (!cfg->arch.omit_fp);
+
+ MONO_INST_NEW (cfg, indir, 0);
+ indir->opcode = OP_REGOFFSET;
+ if (ainfo->pair_storage [0] == ArgInIReg) {
+ indir->inst_basereg = cfg->frame_reg;
+ offset = ALIGN_TO (offset, sizeof (gpointer));
+ offset += (sizeof (gpointer));
+ indir->inst_offset = - offset;
+ }
+ else {
+ indir->inst_basereg = cfg->frame_reg;
+ indir->inst_offset = ainfo->offset + ARGS_OFFSET;
+ }
+
+ ins->opcode = OP_VTARG_ADDR;
+ ins->inst_left = indir;
+
+ break;
+ }
default:
NOT_IMPLEMENTED;
}
- if (!inreg && (ainfo->storage != ArgOnStack)) {
+ if (!inreg && (ainfo->storage != ArgOnStack) && (ainfo->storage != ArgValuetypeAddrInIReg)) {
ins->opcode = OP_REGOFFSET;
ins->inst_basereg = cfg->frame_reg;
/* These arguments are saved to the stack in the prolog */
/*Copy the argument to the temp variable.*/
MONO_INST_NEW (cfg, load, OP_MEMCPY);
load->backend.memcpy_args = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoMemcpyArgs));
- load->backend.memcpy_args->size = mono_class_value_size (in->klass, &align);
+ load->backend.memcpy_args->size = size;
load->backend.memcpy_args->align = align;
load->inst_left = (cfg)->varinfo [vtaddr->inst_c0];
load->inst_right = in->inst_i0;
#ifdef PLATFORM_WIN32
/* Always reserve 32 bytes of stack space on Win64 */
- MONO_INST_NEW (cfg, arg, OP_AMD64_OUTARG_ALIGN_STACK);
+ /*MONO_INST_NEW (cfg, arg, OP_AMD64_OUTARG_ALIGN_STACK);
arg->inst_c0 = 32;
- MONO_INST_LIST_ADD_TAIL (&arg->node, &call->out_args);
+ MONO_INST_LIST_ADD_TAIL (&arg->node, &call->out_args);*/
+ NOT_IMPLEMENTED;
#endif
#if 0
MONO_ADD_INS (cfg->cbb, arg);
}
+#define NEW_VARSTORE(cfg,dest,var,vartype,inst) do { \
+ MONO_INST_NEW ((cfg), (dest), OP_MOVE); \
+ (dest)->opcode = mono_type_to_regmove ((cfg), (vartype)); \
+ (dest)->klass = (var)->klass; \
+ (dest)->sreg1 = (inst)->dreg; \
+ (dest)->dreg = (var)->dreg; \
+ if ((dest)->opcode == OP_VMOVE) (dest)->klass = mono_class_from_mono_type ((vartype)); \
+ } while (0)
+
+#define NEW_ARGSTORE(cfg,dest,num,inst) NEW_VARSTORE ((cfg), (dest), cfg->args [(num)], cfg->arg_types [(num)], (inst))
+
+#define EMIT_NEW_ARGSTORE(cfg,dest,num,inst) do { NEW_ARGSTORE ((cfg), (dest), (num), (inst)); MONO_ADD_INS ((cfg)->cbb, (dest)); } while (0)
+
void
mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
{
break;
case ArgOnStack:
case ArgValuetypeInReg:
- if (ainfo->storage == ArgOnStack && call->tail_call)
- NOT_IMPLEMENTED;
- if ((i >= sig->hasthis) && (MONO_TYPE_ISSTRUCT(sig->params [i - sig->hasthis]))) {
+ case ArgValuetypeAddrInIReg:
+ if (ainfo->storage == ArgOnStack && call->tail_call) {
+ MonoInst *call_inst = (MonoInst*)call;
+ cfg->args [i]->flags |= MONO_INST_VOLATILE;
+ EMIT_NEW_ARGSTORE (cfg, call_inst, i, in);
+ } else if ((i >= sig->hasthis) && (MONO_TYPE_ISSTRUCT(sig->params [i - sig->hasthis]))) {
guint32 align;
guint32 size;
* result there.
*/
call->vret_in_reg = TRUE;
+ /*
+ * Nullify the instruction computing the vret addr to enable
+ * future optimizations.
+ */
+ if (call->vret_var)
+ NULLIFY_INS (call->vret_var);
} else {
if (call->tail_call)
NOT_IMPLEMENTED;
}
#ifdef PLATFORM_WIN32
- // FIXME:
- NOT_IMPLEMENTED;
+ if (call->inst.opcode != OP_JMP && OP_TAILCALL != call->inst.opcode) {
+ MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SUB_IMM, X86_ESP, X86_ESP, 0x20);
+ }
#endif
if (cfg->method->save_lmf) {
add_outarg_reg2 (cfg, call, ainfo->pair_storage [part], ainfo->pair_regs [part], load);
}
+ } else if (ainfo->storage == ArgValuetypeAddrInIReg) {
+ MonoInst *vtaddr, *load;
+ vtaddr = mono_compile_create_var (cfg, &ins->klass->byval_arg, OP_LOCAL);
+
+ MONO_INST_NEW (cfg, load, OP_LDADDR);
+ load->inst_p0 = vtaddr;
+ vtaddr->flags |= MONO_INST_INDIRECT;
+ load->type = STACK_MP;
+ load->klass = vtaddr->klass;
+ load->dreg = mono_alloc_ireg (cfg);
+ MONO_ADD_INS (cfg->cbb, load);
+ mini_emit_memcpy2 (cfg, load->dreg, 0, src->dreg, 0, size, 4);
+
+ if (ainfo->pair_storage [0] == ArgInIReg) {
+ MONO_INST_NEW (cfg, arg, OP_X86_LEA_MEMBASE);
+ arg->dreg = mono_alloc_ireg (cfg);
+ arg->sreg1 = load->dreg;
+ arg->inst_imm = 0;
+ MONO_ADD_INS (cfg->cbb, arg);
+ mono_call_inst_add_outarg_reg (cfg, call, arg->dreg, ainfo->pair_regs [0], FALSE);
+ } else {
+ MONO_INST_NEW (cfg, arg, OP_X86_PUSH);
+ arg->sreg1 = load->dreg;
+ MONO_ADD_INS (cfg->cbb, arg);
+ }
} else {
if (size == 8) {
/* Can't use this for < 8 since it does an 8 byte memory load */
void
mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val)
{
- MonoType *ret = mono_type_get_underlying_type (mono_method_signature (method)->ret);
+ MonoType *ret = mini_type_get_underlying_type (NULL, mono_method_signature (method)->ret);
if (!ret->byref) {
if (ret->type == MONO_TYPE_R4) {
near_call = TRUE;
if ((patch_type == MONO_PATCH_INFO_METHOD) || (patch_type == MONO_PATCH_INFO_METHOD_JUMP)) {
- if (((MonoMethod*)data)->klass->image->assembly->aot_module)
+ if (((MonoMethod*)data)->klass->image->aot_module)
/* The callee might be an AOT method */
near_call = FALSE;
if (((MonoMethod*)data)->dynamic)
}
}
else {
- if (mono_find_class_init_trampoline_by_addr (data))
+ if (!cfg->new_ir && mono_find_class_init_trampoline_by_addr (data))
near_call = TRUE;
- else {
+ else if (cfg->abs_patches && g_hash_table_lookup (cfg->abs_patches, data)) {
+ /*
+ * This is not really an optimization, but required because the
+ * generic class init trampolines use R11 to pass the vtable.
+ */
+ near_call = TRUE;
+ } else {
MonoJitICallInfo *info = mono_find_jit_icall_by_addr (data);
if (info) {
if ((cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) &&
near_call = TRUE;
}
}
- else if ((((guint64)data) >> 32) == 0)
+ else if ((((guint64)data) >> 32) == 0) {
near_call = TRUE;
+ no_patch = TRUE;
+ }
}
}
case OP_DIV_IMM:
case OP_REM_IMM:
case OP_IDIV_IMM:
- case OP_IREM_IMM:
case OP_IDIV_UN_IMM:
case OP_IREM_UN_IMM:
mono_decompose_op_imm (cfg, bb, ins);
break;
+ case OP_IREM_IMM:
+ /* Keep the opcode if we can implement it efficiently */
+ if (!((ins->inst_imm > 0) && (mono_is_power_of_two (ins->inst_imm) != -1)))
+ mono_decompose_op_imm (cfg, bb, ins);
+ break;
case OP_COMPARE_IMM:
case OP_LCOMPARE_IMM:
if (!amd64_is_imm32 (ins->inst_imm)) {
}
/*
- * emit_tls_get:
+ * mono_amd64_emit_tls_get:
* @code: buffer to store code to
* @dreg: hard register where to place the result
* @tls_offset: offset info
*
- * emit_tls_get emits in @code the native code that puts in the dreg register
- * the item in the thread local storage identified by tls_offset.
+ * mono_amd64_emit_tls_get emits in @code the native code that puts in
+ * the dreg register the item in the thread local storage identified
+ * by tls_offset.
*
* Returns: a pointer to the end of the stored code
*/
-static guint8*
-emit_tls_get (guint8* code, int dreg, int tls_offset)
+guint8*
+mono_amd64_emit_tls_get (guint8* code, int dreg, int tls_offset)
{
+#ifdef PLATFORM_WIN32
+ g_assert (tls_offset < 64);
+ x86_prefix (code, X86_GS_PREFIX);
+ amd64_mov_reg_mem (code, dreg, (tls_offset * 8) + 0x1480, 8);
+#else
if (optimize_for_xen) {
x86_prefix (code, X86_FS_PREFIX);
amd64_mov_reg_mem (code, dreg, 0, 8);
x86_prefix (code, X86_FS_PREFIX);
amd64_mov_reg_mem (code, dreg, tls_offset, 8);
}
+#endif
return code;
}
}
}
break;
+ case ArgValuetypeAddrInIReg:
+ if (ainfo->pair_storage [0] == ArgInIReg)
+ amd64_mov_reg_membase (code, ainfo->pair_regs [0], ins->inst_left->inst_basereg, ins->inst_left->inst_offset, sizeof (gpointer));
+ break;
default:
break;
}
#define LOOP_ALIGNMENT 8
#define bb_is_loop_start(bb) ((bb)->loop_body_start && (bb)->nesting)
+#ifndef DISABLE_JIT
+
void
mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
{
mono_debug_open_block (cfg, bb, offset);
+ 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)
+ x86_breakpoint (code);
+
MONO_BB_FOR_EACH_INS (bb, ins) {
offset = code - cfg->native_code;
case OP_BREAK:
amd64_breakpoint (code);
break;
+ case OP_RELAXED_NOP:
+ x86_prefix (code, X86_REP_PREFIX);
+ x86_nop (code);
+ break;
+ case OP_HARD_NOP:
+ x86_nop (code);
+ break;
case OP_NOP:
case OP_DUMMY_USE:
case OP_DUMMY_STORE:
amd64_div_reg_size (code, ins->sreg2, FALSE, 4);
}
break;
+ case OP_IREM_IMM: {
+ int power = mono_is_power_of_two (ins->inst_imm);
+
+ g_assert (ins->sreg1 == X86_EAX);
+ g_assert (ins->dreg == X86_EAX);
+ g_assert (power >= 0);
+
+ if (power == 0) {
+ amd64_mov_reg_imm (code, ins->dreg, 0);
+ break;
+ }
+
+ /* Based on gcc code */
+
+ /* Add compensation for negative dividents */
+ amd64_mov_reg_reg_size (code, AMD64_RDX, AMD64_RAX, 4);
+ if (power > 1)
+ amd64_shift_reg_imm_size (code, X86_SAR, AMD64_RDX, 31, 4);
+ amd64_shift_reg_imm_size (code, X86_SHR, AMD64_RDX, 32 - power, 4);
+ amd64_alu_reg_reg_size (code, X86_ADD, AMD64_RAX, AMD64_RDX, 4);
+ /* Compute remainder */
+ amd64_alu_reg_imm_size (code, X86_AND, AMD64_RAX, (1 << power) - 1, 4);
+ /* Remove compensation */
+ amd64_alu_reg_reg_size (code, X86_SUB, AMD64_RAX, AMD64_RDX, 4);
+ break;
+ }
case OP_LMUL_OVF:
amd64_imul_reg_reg (code, ins->sreg1, ins->sreg2);
EMIT_COND_SYSTEM_EXCEPTION (X86_CC_O, FALSE, "OverflowException");
case OP_X86_PUSH_MEMBASE:
amd64_push_membase (code, ins->inst_basereg, ins->inst_offset);
break;
- case OP_X86_PUSH_OBJ:
- amd64_alu_reg_imm (code, X86_SUB, AMD64_RSP, ins->inst_imm);
+ case OP_X86_PUSH_OBJ: {
+ int size = ALIGN_TO (ins->inst_imm, 8);
+ amd64_alu_reg_imm (code, X86_SUB, AMD64_RSP, size);
amd64_push_reg (code, AMD64_RDI);
amd64_push_reg (code, AMD64_RSI);
amd64_push_reg (code, AMD64_RCX);
amd64_lea_membase (code, AMD64_RSI, ins->inst_basereg, ins->inst_offset);
else
amd64_mov_reg_reg (code, AMD64_RSI, ins->inst_basereg, 8);
- amd64_lea_membase (code, AMD64_RDI, AMD64_RSP, 3 * 8);
- amd64_mov_reg_imm (code, AMD64_RCX, (ins->inst_imm >> 3));
+ amd64_lea_membase (code, AMD64_RDI, AMD64_RSP, (3 * 8));
+ amd64_mov_reg_imm (code, AMD64_RCX, (size >> 3));
amd64_cld (code);
amd64_prefix (code, X86_REP_PREFIX);
amd64_movsd (code);
amd64_pop_reg (code, AMD64_RSI);
amd64_pop_reg (code, AMD64_RDI);
break;
+ }
case OP_X86_LEA:
amd64_lea_memindex (code, ins->dreg, ins->sreg1, ins->inst_imm, ins->sreg2, ins->backend.shift_amount);
break;
size = (size + (MONO_ARCH_FRAME_ALIGNMENT - 1)) & ~ (MONO_ARCH_FRAME_ALIGNMENT - 1);
if (ins->flags & MONO_INST_INIT) {
- /* FIXME: Optimize this */
- amd64_mov_reg_imm (code, ins->dreg, size);
- ins->sreg1 = ins->dreg;
+ if (size < 64) {
+ int i;
- code = mono_emit_stack_alloc (code, ins);
- amd64_mov_reg_reg (code, ins->dreg, AMD64_RSP, 8);
+ amd64_alu_reg_imm (code, X86_SUB, AMD64_RSP, size);
+ amd64_alu_reg_reg (code, X86_XOR, ins->dreg, ins->dreg);
+
+ for (i = 0; i < size; i += 8)
+ amd64_mov_membase_reg (code, AMD64_RSP, i, ins->dreg, 8);
+ amd64_mov_reg_reg (code, ins->dreg, AMD64_RSP, 8);
+ } else {
+ amd64_mov_reg_imm (code, ins->dreg, size);
+ ins->sreg1 = ins->dreg;
+
+ code = mono_emit_stack_alloc (code, ins);
+ amd64_mov_reg_reg (code, ins->dreg, AMD64_RSP, 8);
+ }
} else {
amd64_alu_reg_imm (code, X86_SUB, AMD64_RSP, size);
amd64_mov_reg_reg (code, ins->dreg, AMD64_RSP, 8);
amd64_alu_reg_imm (code, X86_ADD, AMD64_RSP, 16);
break;
case OP_TLS_GET: {
- code = emit_tls_get (code, ins->dreg, ins->inst_offset);
+ code = mono_amd64_emit_tls_get (code, ins->dreg, ins->inst_offset);
break;
}
case OP_MEMORY_BARRIER: {
cfg->code_len = code - cfg->native_code;
}
+#endif /* DISABLE_JIT */
+
void
mono_arch_register_lowlevel_calls (void)
{
while (remaining_size >= 0x1000) {
amd64_alu_reg_imm (code, X86_SUB, AMD64_RSP, 0x1000);
async_exc_point (code);
+#ifdef PLATFORM_WIN32
+ if (cfg->arch.omit_fp)
+ mono_arch_unwindinfo_add_alloc_stack (&cfg->arch.unwindinfo, cfg->native_code, code, 0x1000);
+#endif
+
amd64_test_membase_reg (code, AMD64_RSP, 0, AMD64_RSP);
remaining_size -= 0x1000;
}
if (remaining_size) {
amd64_alu_reg_imm (code, X86_SUB, AMD64_RSP, remaining_size);
async_exc_point (code);
+#ifdef PLATFORM_WIN32
+ if (cfg->arch.omit_fp)
+ mono_arch_unwindinfo_add_alloc_stack (&cfg->arch.unwindinfo, cfg->native_code, code, remaining_size);
+#endif
}
#else
amd64_alu_reg_imm (code, X86_SUB, AMD64_RSP, alloc_size);
}
}
break;
+ case ArgValuetypeAddrInIReg:
+ if (ainfo->pair_storage [0] == ArgInIReg)
+ amd64_mov_membase_reg (code, ins->inst_left->inst_basereg, ins->inst_left->inst_offset, ainfo->pair_regs [0], sizeof (gpointer));
+ break;
default:
break;
}
if (appdomain_tls_offset != -1 && lmf_tls_offset != -1) {
guint8 *buf, *no_domain_branch;
- code = emit_tls_get (code, AMD64_RAX, appdomain_tls_offset);
+ code = mono_amd64_emit_tls_get (code, AMD64_RAX, appdomain_tls_offset);
if ((domain >> 32) == 0)
amd64_mov_reg_imm_size (code, AMD64_ARG_REG1, domain, 4);
else
amd64_alu_reg_reg (code, X86_CMP, AMD64_RAX, AMD64_ARG_REG1);
no_domain_branch = code;
x86_branch8 (code, X86_CC_NE, 0, 0);
- code = emit_tls_get ( code, AMD64_RAX, lmf_addr_tls_offset);
+ code = mono_amd64_emit_tls_get ( code, AMD64_RAX, lmf_addr_tls_offset);
amd64_test_reg_reg (code, AMD64_RAX, AMD64_RAX);
buf = code;
x86_branch8 (code, X86_CC_NE, 0, 0);
code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD,
(gpointer)"mono_jit_thread_attach", TRUE);
amd64_patch (buf, code);
+#ifdef PLATFORM_WIN32
+ /* The TLS key actually contains a pointer to the MonoJitTlsData structure */
+ /* FIXME: Add a separate key for LMF to avoid this */
+ amd64_alu_reg_imm (code, X86_ADD, AMD64_RAX, G_STRUCT_OFFSET (MonoJitTlsData, lmf));
+#endif
} else {
g_assert (!cfg->compile_aot);
if ((domain >> 32) == 0)
} else {
if (lmf_addr_tls_offset != -1) {
/* Load lmf quicky using the FS register */
- code = emit_tls_get (code, AMD64_RAX, lmf_addr_tls_offset);
+ code = mono_amd64_emit_tls_get (code, AMD64_RAX, lmf_addr_tls_offset);
+#ifdef PLATFORM_WIN32
+ /* The TLS key actually contains a pointer to the MonoJitTlsData structure */
+ /* FIXME: Add a separate key for LMF to avoid this */
+ amd64_alu_reg_imm (code, X86_ADD, AMD64_RAX, G_STRUCT_OFFSET (MonoJitTlsData, lmf));
+#endif
}
else {
/*
pos = 0;
if (method->save_lmf) {
+ /* check if we need to restore protection of the stack after a stack overflow */
+ if (mono_get_jit_tls_offset () != -1) {
+ guint8 *patch;
+ code = mono_amd64_emit_tls_get (code, X86_ECX, mono_get_jit_tls_offset ());
+ /* we load the value in a separate instruction: this mechanism may be
+ * used later as a safer way to do thread interruption
+ */
+ amd64_mov_reg_membase (code, X86_ECX, X86_ECX, G_STRUCT_OFFSET (MonoJitTlsData, restore_stack_prot), 8);
+ x86_alu_reg_imm (code, X86_CMP, X86_ECX, 0);
+ patch = code;
+ x86_branch8 (code, X86_CC_Z, 0, FALSE);
+ /* note that the call trampoline will preserve eax/edx */
+ x86_call_reg (code, X86_ECX);
+ x86_patch (patch, code);
+ } else {
+ /* FIXME: maybe save the jit tls in the prolog */
+ }
if ((lmf_tls_offset != -1) && !optimize_for_xen) {
/*
* Optimized version which uses the mono_lmf TLS variable instead of indirection
guchar *code = p;
int save_mode = SAVE_NONE;
MonoMethod *method = cfg->method;
- int rtype = mono_type_get_underlying_type (mono_method_signature (method)->ret)->type;
+ int rtype = mini_type_get_underlying_type (NULL, mono_method_signature (method)->ret)->type;
switch (rtype) {
case MONO_TYPE_VOID:
} else {
/* We have to shift the arguments left */
amd64_mov_reg_reg (code, AMD64_RAX, AMD64_ARG_REG1, 8);
- for (i = 0; i < sig->param_count; ++i)
+ for (i = 0; i < sig->param_count; ++i) {
+#ifdef PLATFORM_WIN32
+ if (i < 3)
+ amd64_mov_reg_reg (code, param_regs [i], param_regs [i + 1], 8);
+ else
+ amd64_mov_reg_membase (code, param_regs [i], AMD64_RSP, 0x28, 8);
+#else
amd64_mov_reg_reg (code, param_regs [i], param_regs [i + 1], 8);
+#endif
+ }
amd64_jump_membase (code, AMD64_RAX, G_STRUCT_OFFSET (MonoDelegate, method_ptr));
}
mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
{
if (!tls_offset_inited) {
+#ifdef PLATFORM_WIN32
+ /*
+ * We need to init this multiple times, since when we are first called, the key might not
+ * be initialized yet.
+ */
+ appdomain_tls_offset = mono_domain_get_tls_key ();
+ lmf_tls_offset = mono_get_jit_tls_key ();
+ thread_tls_offset = mono_thread_get_tls_key ();
+ lmf_addr_tls_offset = mono_get_jit_tls_key ();
+
+ /* Only 64 tls entries can be accessed using inline code */
+ if (appdomain_tls_offset >= 64)
+ appdomain_tls_offset = -1;
+ if (lmf_tls_offset >= 64)
+ lmf_tls_offset = -1;
+ if (thread_tls_offset >= 64)
+ thread_tls_offset = -1;
+#else
tls_offset_inited = TRUE;
#ifdef MONO_XEN_OPT
optimize_for_xen = access ("/proc/xen", F_OK) == 0;
lmf_tls_offset = mono_get_lmf_tls_offset ();
lmf_addr_tls_offset = mono_get_lmf_addr_tls_offset ();
thread_tls_offset = mono_thread_get_tls_offset ();
+#endif
}
}
* LOCKING: called with the domain lock held
*/
gpointer
-mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count)
+mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count,
+ gpointer fail_tramp)
{
int i;
int size = 0;
if (item->is_equals) {
if (item->check_target_idx) {
if (!item->compare_done) {
- if (amd64_is_imm32 (item->method))
+ if (amd64_is_imm32 (item->key))
item->chunk_size += CMP_SIZE;
else
item->chunk_size += MOV_REG_IMM_SIZE + CMP_REG_REG_SIZE;
item->chunk_size += MOV_REG_IMM_SIZE;
item->chunk_size += BR_SMALL_SIZE + JUMP_REG_SIZE;
} else {
- if (vtable_is_32bit)
- item->chunk_size += MOV_REG_IMM_32BIT_SIZE;
- else
- item->chunk_size += MOV_REG_IMM_SIZE;
- item->chunk_size += JUMP_REG_SIZE;
- /* with assert below:
- * item->chunk_size += CMP_SIZE + BR_SMALL_SIZE + 1;
- */
+ if (fail_tramp) {
+ item->chunk_size += MOV_REG_IMM_SIZE * 3 + CMP_REG_REG_SIZE +
+ BR_SMALL_SIZE + JUMP_REG_SIZE * 2;
+ } else {
+ if (vtable_is_32bit)
+ item->chunk_size += MOV_REG_IMM_32BIT_SIZE;
+ else
+ item->chunk_size += MOV_REG_IMM_SIZE;
+ item->chunk_size += JUMP_REG_SIZE;
+ /* with assert below:
+ * item->chunk_size += CMP_SIZE + BR_SMALL_SIZE + 1;
+ */
+ }
}
} else {
- if (amd64_is_imm32 (item->method))
+ if (amd64_is_imm32 (item->key))
item->chunk_size += CMP_SIZE;
else
item->chunk_size += MOV_REG_IMM_SIZE + CMP_REG_REG_SIZE;
}
size += item->chunk_size;
}
- code = mono_code_manager_reserve (domain->code_mp, size);
+ if (fail_tramp)
+ code = mono_method_alloc_generic_virtual_thunk (domain, size);
+ else
+ code = mono_code_manager_reserve (domain->code_mp, size);
start = code;
for (i = 0; i < count; ++i) {
MonoIMTCheckItem *item = imt_entries [i];
if (item->is_equals) {
if (item->check_target_idx) {
if (!item->compare_done) {
- if (amd64_is_imm32 (item->method))
- amd64_alu_reg_imm (code, X86_CMP, MONO_ARCH_IMT_REG, (guint32)(gssize)item->method);
+ if (amd64_is_imm32 (item->key))
+ amd64_alu_reg_imm (code, X86_CMP, MONO_ARCH_IMT_REG, (guint32)(gssize)item->key);
else {
- amd64_mov_reg_imm (code, AMD64_R10, item->method);
+ amd64_mov_reg_imm (code, AMD64_R10, item->key);
amd64_alu_reg_reg (code, X86_CMP, MONO_ARCH_IMT_REG, AMD64_R10);
}
}
item->jmp_code = code;
amd64_branch8 (code, X86_CC_NE, 0, FALSE);
/* See the comment below about R10 */
- amd64_mov_reg_imm (code, AMD64_R10, & (vtable->vtable [item->vtable_slot]));
- amd64_jump_membase (code, AMD64_R10, 0);
+ if (fail_tramp) {
+ amd64_mov_reg_imm (code, AMD64_R10, item->value.target_code);
+ amd64_jump_reg (code, AMD64_R10);
+ } else {
+ amd64_mov_reg_imm (code, AMD64_R10, & (vtable->vtable [item->value.vtable_slot]));
+ amd64_jump_membase (code, AMD64_R10, 0);
+ }
} else {
- /* enable the commented code to assert on wrong method */
+ if (fail_tramp) {
+ if (amd64_is_imm32 (item->key))
+ amd64_alu_reg_imm (code, X86_CMP, MONO_ARCH_IMT_REG, (guint32)(gssize)item->key);
+ else {
+ amd64_mov_reg_imm (code, AMD64_R10, item->key);
+ amd64_alu_reg_reg (code, X86_CMP, MONO_ARCH_IMT_REG, AMD64_R10);
+ }
+ item->jmp_code = code;
+ amd64_branch8 (code, X86_CC_NE, 0, FALSE);
+ amd64_mov_reg_imm (code, AMD64_R10, item->value.target_code);
+ amd64_jump_reg (code, AMD64_R10);
+ amd64_patch (item->jmp_code, code);
+ amd64_mov_reg_imm (code, AMD64_R10, fail_tramp);
+ amd64_jump_reg (code, AMD64_R10);
+ item->jmp_code = NULL;
+
+ } else {
+ /* enable the commented code to assert on wrong method */
#if 0
- if (amd64_is_imm32 (item->method))
- amd64_alu_reg_imm (code, X86_CMP, MONO_ARCH_IMT_REG, (guint32)(gssize)item->method);
- else {
- amd64_mov_reg_imm (code, AMD64_R10, item->method);
- amd64_alu_reg_reg (code, X86_CMP, MONO_ARCH_IMT_REG, AMD64_R10);
- }
- item->jmp_code = code;
- amd64_branch8 (code, X86_CC_NE, 0, FALSE);
- /* See the comment below about R10 */
- amd64_mov_reg_imm (code, AMD64_R10, & (vtable->vtable [item->vtable_slot]));
- amd64_jump_membase (code, AMD64_R10, 0);
- amd64_patch (item->jmp_code, code);
- amd64_breakpoint (code);
- item->jmp_code = NULL;
+ if (amd64_is_imm32 (item->key))
+ amd64_alu_reg_imm (code, X86_CMP, MONO_ARCH_IMT_REG, (guint32)(gssize)item->key);
+ else {
+ amd64_mov_reg_imm (code, AMD64_R10, item->key);
+ amd64_alu_reg_reg (code, X86_CMP, MONO_ARCH_IMT_REG, AMD64_R10);
+ }
+ item->jmp_code = code;
+ amd64_branch8 (code, X86_CC_NE, 0, FALSE);
+ /* See the comment below about R10 */
+ amd64_mov_reg_imm (code, AMD64_R10, & (vtable->vtable [item->value.vtable_slot]));
+ amd64_jump_membase (code, AMD64_R10, 0);
+ amd64_patch (item->jmp_code, code);
+ amd64_breakpoint (code);
+ item->jmp_code = NULL;
#else
- /* We're using R10 here because R11
- needs to be preserved. R10 needs
- to be preserved for calls which
- require a runtime generic context,
- but interface calls don't. */
- amd64_mov_reg_imm (code, AMD64_R10, & (vtable->vtable [item->vtable_slot]));
- amd64_jump_membase (code, AMD64_R10, 0);
+ /* We're using R10 here because R11
+ needs to be preserved. R10 needs
+ to be preserved for calls which
+ require a runtime generic context,
+ but interface calls don't. */
+ amd64_mov_reg_imm (code, AMD64_R10, & (vtable->vtable [item->value.vtable_slot]));
+ amd64_jump_membase (code, AMD64_R10, 0);
#endif
+ }
}
} else {
- if (amd64_is_imm32 (item->method))
- amd64_alu_reg_imm (code, X86_CMP, MONO_ARCH_IMT_REG, (guint32)(gssize)item->method);
+ if (amd64_is_imm32 (item->key))
+ amd64_alu_reg_imm (code, X86_CMP, MONO_ARCH_IMT_REG, (guint32)(gssize)item->key);
else {
- amd64_mov_reg_imm (code, AMD64_R10, item->method);
+ amd64_mov_reg_imm (code, AMD64_R10, item->key);
amd64_alu_reg_reg (code, X86_CMP, MONO_ARCH_IMT_REG, AMD64_R10);
}
item->jmp_code = code;
}
}
}
-
- mono_stats.imt_thunks_size += code - start;
+
+ if (!fail_tramp)
+ mono_stats.imt_thunks_size += code - start;
g_assert (code - start <= size);
return start;
}
void
-mono_arch_emit_imt_argument (MonoCompile *cfg, MonoCallInst *call)
+mono_arch_emit_imt_argument (MonoCompile *cfg, MonoCallInst *call, MonoInst *imt_arg)
{
/* Done by the implementation of the CALL_MEMBASE opcodes */
}