#include <mono/utils/mono-counters.h>
#include <mono/utils/mono-mmap.h>
#include <mono/utils/mono-memory-model.h>
-#include <mono/utils/mono-hwcap-x86.h>
+#include <mono/utils/mono-hwcap.h>
#include <mono/utils/mono-threads.h>
#include "trace.h"
#ifdef TARGET_WIN32
/* Under windows, the default pinvoke calling convention is stdcall */
-#define CALLCONV_IS_STDCALL(sig) ((((sig)->call_convention) == MONO_CALL_STDCALL) || ((sig)->pinvoke && ((sig)->call_convention) == MONO_CALL_DEFAULT) || ((sig)->pinvoke && ((sig)->call_convention) == MONO_CALL_THISCALL))
+#define CALLCONV_IS_STDCALL(sig) ((sig)->pinvoke && ((sig)->call_convention == MONO_CALL_STDCALL || (sig)->call_convention == MONO_CALL_DEFAULT || (sig)->call_convention == MONO_CALL_THISCALL))
#else
-#define CALLCONV_IS_STDCALL(sig) (((sig)->call_convention) == MONO_CALL_STDCALL || ((sig)->pinvoke && ((sig)->call_convention) == MONO_CALL_THISCALL))
+#define CALLCONV_IS_STDCALL(sig) ((sig)->pinvoke && ((sig)->call_convention == MONO_CALL_STDCALL || (sig)->call_convention == MONO_CALL_THISCALL))
#endif
#define X86_IS_CALLEE_SAVED_REG(reg) (((reg) == X86_EBX) || ((reg) == X86_EDI) || ((reg) == X86_ESI))
klass = mono_class_from_mono_type (type);
size = mini_type_stack_size_full (&klass->byval_arg, NULL, sig->pinvoke);
+#if defined(TARGET_WIN32)
+ /*
+ * 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.
+ * This cause a little dilemma since runtime build using none GCC compiler will not be compatible with
+ * GCC build C libraries and the other way around. On platforms where empty structs has size of 1 byte
+ * it must be represented in call and cannot be dropped.
+ */
+ if (size == 0 && MONO_TYPE_ISSTRUCT (type) && sig->pinvoke) {
+ /* Empty structs (1 byte size) needs to be represented in a stack slot */
+ ainfo->pass_empty_struct = TRUE;
+ size = 1;
+ }
+#endif
+
#ifdef SMALL_STRUCTS_IN_REGS
if (sig->pinvoke && is_return) {
MonoMarshalType *info;
- /*
- * the exact rules are not very well documented, the code below seems to work with the
- * code generated by gcc 3.3.3 -mno-cygwin.
- */
info = mono_marshal_load_type_info (klass);
g_assert (info);
ainfo->pair_storage [0] = ainfo->pair_storage [1] = ArgNone;
+ /* Ignore empty struct return value, if used. */
+ if (info->num_fields == 0 && ainfo->pass_empty_struct) {
+ ainfo->storage = ArgValuetypeInReg;
+ return;
+ }
+
+ /*
+ * Windows x86 ABI for returning structs of size 4 or 8 bytes (regardless of type) dictates that
+ * values are passed in EDX:EAX register pairs, https://msdn.microsoft.com/en-us/library/984x0h58.aspx.
+ * This is different compared to for example float or double return types (not in struct) that will be returned
+ * in ST(0), https://msdn.microsoft.com/en-us/library/ha59cbfz.aspx.
+ *
+ * Apples OSX x86 ABI for returning structs of size 4 or 8 bytes uses a slightly different approach.
+ * If a struct includes only one scalar value, it will be handled with the same rules as scalar values.
+ * This means that structs with one float or double will be returned in ST(0). For more details,
+ * https://developer.apple.com/library/mac/documentation/DeveloperTools/Conceptual/LowLevelABI/130-IA-32_Function_Calling_Conventions/IA32.html.
+ */
+#if !defined(TARGET_WIN32)
+
/* Special case structs with only a float member */
if (info->num_fields == 1) {
int ftype = mini_get_underlying_type (info->fields [0].field->type)->type;
return;
}
}
+#endif
+
if ((info->native_size == 1) || (info->native_size == 2) || (info->native_size == 4) || (info->native_size == 8)) {
ainfo->storage = ArgValuetypeInReg;
ainfo->pair_storage [0] = ArgInIReg;
* For x86 ELF, see the "System V Application Binary Interface Intel386
* Architecture Processor Supplment, Fourth Edition" document for more
* information.
- * For x86 win32, see ???.
+ * For x86 win32, see https://msdn.microsoft.com/en-us/library/984x0h58.aspx.
*/
static CallInfo*
get_call_info_internal (CallInfo *cinfo, MonoMethodSignature *sig)
if (cinfo->vtype_retaddr) {
/* if the function returns a struct on stack, the called method already does a ret $0x4 */
cinfo->callee_stack_pop = 4;
- } else if (CALLCONV_IS_STDCALL (sig) && sig->pinvoke) {
+ } else if (CALLCONV_IS_STDCALL (sig)) {
/* Have to compensate for the stack space popped by the native callee */
cinfo->callee_stack_pop = stack_size;
}
sentinelpos = sig->sentinelpos + (sig->hasthis ? 1 : 0);
if (sig_ret && MONO_TYPE_ISSTRUCT (sig_ret)) {
- if (cinfo->ret.storage == ArgValuetypeInReg) {
+ if (cinfo->ret.storage == ArgValuetypeInReg && cinfo->ret.pair_storage[0] != ArgNone ) {
/*
* Tell the JIT to use a more efficient calling convention: call using
* OP_CALL, compute the result location after the call, and save the
size = mini_type_stack_size_full (&in->klass->byval_arg, &align, sig->pinvoke);
}
- if (size > 0) {
+ if (size > 0 || ainfo->pass_empty_struct) {
arg->opcode = OP_OUTARG_VT;
arg->sreg1 = in->dreg;
arg->klass = in->klass;
MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, X86_ESP, ainfo->offset, src->dreg);
} else if (size <= 4) {
int dreg = mono_alloc_ireg (cfg);
- MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, src->dreg, 0);
+ if (ainfo->pass_empty_struct) {
+ //Pass empty struct value as 0 on platforms representing empty structs as 1 byte.
+ MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
+ } else {
+ MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, src->dreg, 0);
+ }
MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, X86_ESP, ainfo->offset, dreg);
} else if (size <= 20) {
mini_emit_memcpy (cfg, X86_ESP, ainfo->offset, src->dreg, 0, size, 4);
#endif
gboolean
-mono_x86_have_tls_get (void)
+mono_arch_have_fast_tls (void)
{
#ifdef TARGET_MACH
static gboolean have_tls_get = FALSE;
return code;
}
- /*
- * mono_arch_translate_tls_offset:
- *
- * Translate the TLS offset OFFSET computed by MONO_THREAD_VAR_OFFSET () into a format usable by OP_TLS_GET_REG/OP_TLS_SET_REG.
- */
-int
-mono_arch_translate_tls_offset (int offset)
-{
-#ifdef __APPLE__
- return tls_gs_offset + (offset * 4);
-#else
- return offset;
-#endif
-}
-
/*
* emit_setup_lmf:
*
case OP_XZERO:
x86_sse_alu_pd_reg_reg (code, X86_SSE_PXOR, ins->dreg, ins->dreg);
break;
+ case OP_XONES:
+ x86_sse_alu_pd_reg_reg (code, X86_SSE_PCMPEQB, ins->dreg, ins->dreg);
+ break;
case OP_FCONV_TO_R8_X:
x86_fst_membase (code, ins->backend.spill_var->inst_basereg, ins->backend.spill_var->inst_offset, TRUE, TRUE);
if (method->save_lmf) {
gint32 lmf_offset = cfg->lmf_var->inst_offset;
guint8 *patch;
- gboolean supported = FALSE;
-
- if (cfg->compile_aot) {
-#if defined(MONO_HAVE_FAST_TLS)
- supported = TRUE;
-#endif
- } else if (mono_get_jit_tls_offset () != -1) {
- supported = TRUE;
- }
/* check if we need to restore protection of the stack after a stack overflow */
+ /* FIXME */
+#if 0
if (supported) {
if (cfg->compile_aot) {
code = emit_load_aotconst (NULL, code, cfg, NULL, X86_ECX, MONO_PATCH_INFO_TLS_OFFSET, GINT_TO_POINTER (TLS_KEY_JIT_TLS));
} else {
/* FIXME: maybe save the jit tls in the prolog */
}
+#endif
/* restore caller saved regs */
if (cfg->used_int_regs & (1 << X86_EBX)) {
* 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_trampoline (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count,
gpointer fail_tramp)
{
int i;
size += item->chunk_size;
}
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;
}
if (!fail_tramp)
- mono_stats.imt_thunks_size += code - start;
+ mono_stats.imt_trampolines_size += code - start;
g_assert (code - start <= size);
#if DEBUG_IMT
if (vtable)
buff = g_strdup_printf ("imt_%s_%s_entries_%d", vtable->klass->name_space, vtable->klass->name, count);
else
- buff = g_strdup_printf ("imt_thunk_entries_%d", count);
+ buff = g_strdup_printf ("imt_trampoline_entries_%d", count);
mono_emit_jit_tramp (start, code - start, buff);
g_free (buff);
}
x86_jump_membase (code, X86_EAX, 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);