* Dietmar Maurer (dietmar@ximian.com)
* Patrik Torstensson
* Zoltan Varga (vargaz@gmail.com)
+ * Johan Lorensson (lateralusx.github@gmail.com)
*
* (C) 2003 Ximian, Inc.
* Copyright 2003-2011 Novell, Inc (http://www.novell.com)
}
inline gboolean
-allocate_return_register_for_valyetype_win64 (ArgInfo *arg_info, ArgumentClass arg_class, guint32 arg_size, guint32 *current_int_reg, guint32 *current_float_reg)
+allocate_return_register_for_valuetype_win64 (ArgInfo *arg_info, ArgumentClass arg_class, guint32 arg_size, guint32 *current_int_reg, guint32 *current_float_reg)
{
return allocate_register_for_valuetype_win64 (arg_info, arg_class, arg_size, return_regs, RETURN_REGS, float_return_regs, FLOAT_RETURN_REGS, current_int_reg, current_float_reg);
}
/* Parameter cases. */
if (arg_class != ARG_CLASS_MEMORY && MONO_WIN64_VALUE_TYPE_FITS_REG (arg_size)) {
-
assert (arg_size == 1 || arg_size == 2 || arg_size == 4 || arg_size == 8);
/* First, try to use registers for parameter. If type is struct it can only be passed by value in integer register. */
arg_info->storage = ArgValuetypeInReg;
if (!allocate_parameter_register_for_valuetype_win64 (arg_info, !MONO_TYPE_ISSTRUCT (type) ? arg_class : ARG_CLASS_INTEGER, arg_size, current_int_reg, current_float_reg)) {
-
/* No more registers, fallback passing parameter on stack as value. */
assert (arg_info->pair_storage [0] == ArgNone && arg_info->pair_storage [1] == ArgNone && arg_info->pair_size [0] == 0 && arg_info->pair_size [1] == 0 && arg_info->nregs == 0);
*stack_size += arg_size;
}
} else {
-
/* Fallback to stack, try to pass address to parameter in register. Always use integer register to represent stack address. */
arg_info->storage = ArgValuetypeAddrInIReg;
if (!allocate_parameter_register_for_valuetype_win64 (arg_info, ARG_CLASS_INTEGER, arg_size, current_int_reg, current_float_reg)) {
-
/* No more registers, fallback passing address to parameter on stack. */
assert (arg_info->pair_storage [0] == ArgNone && arg_info->pair_storage [1] == ArgNone && arg_info->pair_size [0] == 0 && arg_info->pair_size [1] == 0 && arg_info->nregs == 0);
}
}
} else {
-
/* Return value cases. */
if (arg_class != ARG_CLASS_MEMORY && MONO_WIN64_VALUE_TYPE_FITS_REG (arg_size)) {
-
assert (arg_size == 1 || arg_size == 2 || arg_size == 4 || arg_size == 8);
/* Return value fits into return registers. If type is struct it can only be returned by value in integer register. */
arg_info->storage = ArgValuetypeInReg;
- allocate_return_register_for_valyetype_win64 (arg_info, !MONO_TYPE_ISSTRUCT (type) ? arg_class : ARG_CLASS_INTEGER, arg_size, current_int_reg, current_float_reg);
+ allocate_return_register_for_valuetype_win64 (arg_info, !MONO_TYPE_ISSTRUCT (type) ? arg_class : ARG_CLASS_INTEGER, arg_size, current_int_reg, current_float_reg);
- /* Only RAX/XMM0 should be used to return valyetype. */
+ /* Only RAX/XMM0 should be used to return valuetype. */
assert ((arg_info->pair_regs[0] == AMD64_RAX && arg_info->pair_regs[1] == ArgNone) || (arg_info->pair_regs[0] == AMD64_XMM0 && arg_info->pair_regs[1] == ArgNone));
-
} else {
-
/* Return value doesn't fit into return register, return address to allocated stack space (allocated by caller and passed as input). */
arg_info->storage = ArgValuetypeAddrInIReg;
- allocate_return_register_for_valyetype_win64 (arg_info, ARG_CLASS_INTEGER, arg_size, current_int_reg, current_float_reg);
+ allocate_return_register_for_valuetype_win64 (arg_info, ARG_CLASS_INTEGER, arg_size, current_int_reg, current_float_reg);
- /* Only RAX should be used to return valyetype address. */
+ /* Only RAX should be used to return valuetype address. */
assert (arg_info->pair_regs[0] == AMD64_RAX && arg_info->pair_regs[1] == ArgNone);
arg_size = ALIGN_TO (arg_size, sizeof (mgreg_t));
assert (klass != NULL && arg_info != NULL && type != NULL && arg_class != NULL && arg_size != NULL);
- if (pinvoke == TRUE) {
+ if (pinvoke) {
/* Calculate argument class type and size of marshalled type. */
MonoMarshalType *info = mono_marshal_load_type_info (klass);
*arg_size = info->native_size;
/* Calculate argument class type and size of managed type. */
*arg_size = mono_class_value_size (klass, NULL);
}
-
- if (!MONO_WIN64_VALUE_TYPE_FITS_REG (*arg_size)) {
+
+ /* Windows ABI only handle value types on stack or passed in integer register (if it fits register size). */
+ *arg_class = MONO_WIN64_VALUE_TYPE_FITS_REG (*arg_size) ? ARG_CLASS_INTEGER : ARG_CLASS_MEMORY;
+
+ if (*arg_class == ARG_CLASS_MEMORY) {
/* Value type has a size that doesn't seem to fit register according to ABI. Try to used full stack size of type. */
*arg_size = mini_type_stack_size_full (&klass->byval_arg, NULL, pinvoke);
}
- /* Windows ABI only handle value types on stack or passed in integer register (if it fits register size). */
- *arg_class = (*arg_size > SIZEOF_REGISTER) ? ARG_CLASS_MEMORY : ARG_CLASS_INTEGER;
-
/*
* Standard C and C++ doesn't allow empty structs, empty structs will always have a size of 1 byte.
* GCC have an extension to allow empty structs, https://gcc.gnu.org/onlinedocs/gcc/Empty-Structures.html.
if ((arg_size == 0 && !arg_info->pass_empty_struct) || (arg_size == 0 && arg_info->pass_empty_struct && is_return)) {
arg_info->storage = ArgValuetypeInReg;
arg_info->pair_storage [0] = arg_info->pair_storage [1] = ArgNone;
- }
- else
- {
+ } else {
/* Alocate storage for value type. */
allocate_storage_for_valuetype_win64 (arg_info, type, is_return, arg_class, arg_size, current_int_reg, current_float_reg, stack_size);
}
mono_aot_register_jit_icall ("mono_amd64_throw_corlib_exception", mono_amd64_throw_corlib_exception);
mono_aot_register_jit_icall ("mono_amd64_resume_unwind", mono_amd64_resume_unwind);
mono_aot_register_jit_icall ("mono_amd64_get_original_ip", mono_amd64_get_original_ip);
+ mono_aot_register_jit_icall ("mono_amd64_handler_block_trampoline_helper", mono_amd64_handler_block_trampoline_helper);
+
#if defined(MONO_ARCH_GSHAREDVT_SUPPORTED)
mono_aot_register_jit_icall ("mono_amd64_start_gsharedvt_call", mono_amd64_start_gsharedvt_call);
#endif
}
#ifdef TARGET_WIN32
+ /* The current SIMD doesn't support the argument used by a LD_ADDR to be of type OP_VTARG_ADDR. */
+ /* This will now be used for value types > 8 or of size 3,5,6,7 as dictated by windows x64 value type ABI. */
+ /* Since OP_VTARG_ADDR needs to be resolved in mono_spill_global_vars and the SIMD implementation optimize */
+ /* away the LD_ADDR in load_simd_vreg, that will cause an error in mono_spill_global_vars since incorrect opcode */
+ /* will now have a reference to an argument that won't be fully decomposed. */
*exclude_mask |= MONO_OPT_SIMD;
#endif
return code;
}
+#ifdef TARGET_WIN32
+
+#define TEB_LAST_ERROR_OFFSET 0x068
+
+static guint8*
+emit_get_last_error (guint8* code, int dreg)
+{
+ /* Threads last error value is located in TEB_LAST_ERROR_OFFSET. */
+ x86_prefix (code, X86_GS_PREFIX);
+ amd64_mov_reg_membase (code, dreg, TEB_LAST_ERROR_OFFSET, 0, sizeof (guint32));
+
+ return code;
+}
+
+#else
+
+static guint8*
+emit_get_last_error (guint8* code, int dreg)
+{
+ g_assert_not_reached ();
+}
+
+#endif
+
/* benchmark and set based on cpu */
#define LOOP_ALIGNMENT 8
#define bb_is_loop_start(bb) ((bb)->loop_body_start && (bb)->nesting)
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_GET_LAST_ERROR:
+ emit_get_last_error(code, ins->dreg);
+ break;
default:
g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
g_assert_not_reached ();
amd64_jump_membase (code, AMD64_RAX, offset);
mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_DELEGATE_INVOKE, NULL);
- if (load_imt_reg)
- tramp_name = g_strdup_printf ("delegate_virtual_invoke_imt_%d", - offset / sizeof (gpointer));
- else
- tramp_name = g_strdup_printf ("delegate_virtual_invoke_%d", offset / sizeof (gpointer));
+ tramp_name = mono_get_delegate_virtual_invoke_impl_name (load_imt_reg, offset);
*info = mono_tramp_info_create (tramp_name, start, code - start, NULL, unwind_ops);
g_free (tramp_name);
res = g_slist_prepend (res, info);
}
- for (i = 0; i <= MAX_VIRTUAL_DELEGATE_OFFSET; ++i) {
+ for (i = 1; i <= MONO_IMT_SIZE; ++i) {
get_delegate_virtual_invoke_impl (&info, TRUE, - i * SIZEOF_VOID_P);
res = g_slist_prepend (res, info);
+ }
+ for (i = 0; i <= MAX_VIRTUAL_DELEGATE_OFFSET; ++i) {
get_delegate_virtual_invoke_impl (&info, FALSE, i * SIZEOF_VOID_P);
res = g_slist_prepend (res, info);
+ get_delegate_virtual_invoke_impl (&info, TRUE, i * SIZEOF_VOID_P);
+ res = g_slist_prepend (res, info);
}
return res;