[mini] Add x86 gsharedvt.
authorRodrigo Kumpera <kumpera@gmail.com>
Mon, 16 Nov 2015 05:22:56 +0000 (00:22 -0500)
committerRodrigo Kumpera <kumpera@gmail.com>
Mon, 28 Mar 2016 22:31:38 +0000 (15:31 -0700)
List of original contributors:

Zoltan Varga <vargaz@gmail.com>
Joao Matos <joao@tritao.eu>

mono/mini/Makefile.am.in
mono/mini/mini-x86-gsharedvt.c [new file with mode: 0644]
mono/mini/mini-x86.c
mono/mini/mini-x86.h
mono/mini/tramp-x86-gsharedvt.c [new file with mode: 0644]
mono/mini/tramp-x86.c

index 2160bef0f074a2d396798bc690919f9f3df0ec10..f82baef48637761d91db5347328e9b1309590e15 100755 (executable)
@@ -304,7 +304,9 @@ x86_sources = \
        mini-x86.c              \
        mini-x86.h              \
        exceptions-x86.c        \
        mini-x86.c              \
        mini-x86.h              \
        exceptions-x86.c        \
-       tramp-x86.c
+       tramp-x86.c     \
+       mini-x86-gsharedvt.c    \
+       tramp-x86-gsharedvt.c
 
 amd64_sources = \
        mini-amd64.c            \
 
 amd64_sources = \
        mini-amd64.c            \
diff --git a/mono/mini/mini-x86-gsharedvt.c b/mono/mini/mini-x86-gsharedvt.c
new file mode 100644 (file)
index 0000000..130d48e
--- /dev/null
@@ -0,0 +1,210 @@
+/*
+ * mini-x86-gsharedvt.c: gsharedvt support code for x86
+ *
+ * Authors:
+ *   Zoltan Varga <vargaz@gmail.com>
+ *
+ * Copyright 2013 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"
+
+#ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
+
+#define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1))
+
+/*
+ * GSHAREDVT
+ */
+
+gboolean
+mono_arch_gsharedvt_sig_supported (MonoMethodSignature *sig)
+{
+       /*
+       if (sig->ret && is_variable_size (sig->ret))
+               return FALSE;
+       */
+       return TRUE;
+}
+
+/*
+ * mono_arch_get_gsharedvt_call_info:
+ *
+ *   Compute calling convention information for marshalling a call between NORMAL_SIG and GSHAREDVT_SIG.
+ * If GSHAREDVT_IN is TRUE, then the caller calls using the signature NORMAL_SIG but the call is received by
+ * a method with signature GSHAREDVT_SIG, otherwise its the other way around.
+ */
+gpointer
+mono_arch_get_gsharedvt_call_info (gpointer addr, MonoMethodSignature *normal_sig, MonoMethodSignature *gsharedvt_sig, gboolean gsharedvt_in, gint32 vcall_offset, gboolean calli)
+{
+       GSharedVtCallInfo *info;
+       CallInfo *caller_cinfo, *callee_cinfo;
+       MonoMethodSignature *caller_sig, *callee_sig;
+       int i, j;
+       gboolean var_ret = FALSE;
+       CallInfo *cinfo, *gcinfo;
+       MonoMethodSignature *sig, *gsig;
+       GPtrArray *map;
+
+       if (gsharedvt_in) {
+               caller_sig = normal_sig;
+               callee_sig = gsharedvt_sig;
+               caller_cinfo = mono_arch_get_call_info (NULL, caller_sig);
+               callee_cinfo = mono_arch_get_call_info (NULL, callee_sig);
+       } else {
+               callee_sig = normal_sig;
+               callee_cinfo = mono_arch_get_call_info (NULL, callee_sig);
+               caller_sig = gsharedvt_sig;
+               caller_cinfo = mono_arch_get_call_info (NULL, caller_sig);
+       }
+
+       /*
+        * If GSHAREDVT_IN is true, this means we are transitioning from normal to gsharedvt code. The caller uses the
+        * normal call signature, while the callee uses the gsharedvt signature.
+        * If GSHAREDVT_IN is false, its the other way around.
+        */
+
+       /* sig/cinfo describes the normal call, while gsig/gcinfo describes the gsharedvt call */
+       if (gsharedvt_in) {
+               sig = caller_sig;
+               gsig = callee_sig;
+               cinfo = caller_cinfo;
+               gcinfo = callee_cinfo;
+       } else {
+               sig = callee_sig;
+               gsig = caller_sig;
+               cinfo = callee_cinfo;
+               gcinfo = caller_cinfo;
+       }
+
+       if (gcinfo->vtype_retaddr && gsig->ret && mini_is_gsharedvt_type (gsig->ret)) {
+               /*
+                * The return type is gsharedvt
+                */
+               var_ret = TRUE;
+       }
+
+       /*
+        * The stack looks like this:
+        * <arguments>
+        * <ret addr>
+        * <saved ebp>
+        * <call area>
+        * We have to map the stack slots in <arguments> to the stack slots in <call area>.
+        */
+       map = g_ptr_array_new ();
+
+       if (cinfo->vtype_retaddr) {
+               /*
+                * Map ret arg.
+                * This handles the case when the method returns a normal vtype, and when it returns a type arg, and its instantiated
+                * with a vtype.
+                */             
+               g_ptr_array_add (map, GUINT_TO_POINTER (caller_cinfo->vret_arg_offset / sizeof (gpointer)));
+               g_ptr_array_add (map, GUINT_TO_POINTER (callee_cinfo->vret_arg_offset / sizeof (gpointer)));
+       }
+
+       for (i = 0; i < cinfo->nargs; ++i) {
+               ArgInfo *ainfo = &caller_cinfo->args [i];
+               ArgInfo *ainfo2 = &callee_cinfo->args [i];
+               int nslots;
+
+               switch (ainfo->storage) {
+               case ArgGSharedVt:
+                       if (ainfo2->storage == ArgOnStack) {
+                               nslots = callee_cinfo->args [i].nslots;
+                               if (!nslots)
+                                       nslots = 1;
+                               g_ptr_array_add (map, GUINT_TO_POINTER ((ainfo->offset / sizeof (gpointer)) + (1 << 16) + (nslots << 18)));
+                               g_ptr_array_add (map, GUINT_TO_POINTER ((ainfo2->offset / sizeof (gpointer))));
+                       } else {
+                               g_ptr_array_add (map, GUINT_TO_POINTER ((ainfo->offset / sizeof (gpointer))));
+                               g_ptr_array_add (map, GUINT_TO_POINTER ((ainfo2->offset / sizeof (gpointer))));
+                       }
+                       break;
+               default:
+                       if (ainfo2->storage == ArgOnStack) {
+                               nslots = cinfo->args [i].nslots;
+                               if (!nslots)
+                                       nslots = 1;
+                               for (j = 0; j < nslots; ++j) {
+                                       g_ptr_array_add (map, GUINT_TO_POINTER ((ainfo->offset / sizeof (gpointer)) + j));
+                                       g_ptr_array_add (map, GUINT_TO_POINTER ((ainfo2->offset / sizeof (gpointer)) + j));
+                               }
+                       } else {
+                               g_assert (ainfo2->storage == ArgGSharedVt);
+                               g_ptr_array_add (map, GUINT_TO_POINTER ((ainfo->offset / sizeof (gpointer)) + (2 << 16)));
+                               g_ptr_array_add (map, GUINT_TO_POINTER ((ainfo2->offset / sizeof (gpointer))));
+                       }
+                       break;
+               }
+       }
+
+       info = mono_domain_alloc0 (mono_domain_get (), sizeof (GSharedVtCallInfo) + (map->len * sizeof (int)));
+       info->addr = addr;
+       info->stack_usage = callee_cinfo->stack_usage;
+       info->ret_marshal = GSHAREDVT_RET_NONE;
+       info->gsharedvt_in = gsharedvt_in ? 1 : 0;
+       info->vret_slot = -1;
+       info->calli = calli ? 1 : 0;
+       if (var_ret)
+               info->vret_arg_slot = gcinfo->vret_arg_offset / sizeof (gpointer);
+       else
+               info->vret_arg_slot = -1;
+       info->vcall_offset = vcall_offset;
+       info->map_count = map->len / 2;
+       for (i = 0; i < map->len; ++i)
+               info->map [i] = GPOINTER_TO_UINT (g_ptr_array_index (map, i));
+       g_ptr_array_free (map, TRUE);
+
+       /* Compute return value marshalling */
+       if (var_ret) {
+               switch (cinfo->ret.storage) {
+               case ArgInIReg:
+                       if (gsharedvt_in && !sig->ret->byref && sig->ret->type == MONO_TYPE_I1)
+                               info->ret_marshal = GSHAREDVT_RET_I1;
+                       else if (gsharedvt_in && !sig->ret->byref && (sig->ret->type == MONO_TYPE_U1 || sig->ret->type == MONO_TYPE_BOOLEAN))
+                               info->ret_marshal = GSHAREDVT_RET_U1;
+                       else if (gsharedvt_in && !sig->ret->byref && sig->ret->type == MONO_TYPE_I2)
+                               info->ret_marshal = GSHAREDVT_RET_I2;
+                       else if (gsharedvt_in && !sig->ret->byref && (sig->ret->type == MONO_TYPE_U2 || sig->ret->type == MONO_TYPE_CHAR))
+                               info->ret_marshal = GSHAREDVT_RET_U2;
+                       else if (cinfo->ret.is_pair)
+                               info->ret_marshal = GSHAREDVT_RET_IREGS;
+                       else
+                               info->ret_marshal = GSHAREDVT_RET_IREG;
+                       break;
+               case ArgOnDoubleFpStack:
+                       info->ret_marshal = GSHAREDVT_RET_DOUBLE_FPSTACK;
+                       break;
+               case ArgOnFloatFpStack:
+                       info->ret_marshal = GSHAREDVT_RET_FLOAT_FPSTACK;
+                       break;
+               case ArgOnStack:
+                       /* The caller passes in a vtype ret arg as well */
+                       g_assert (gcinfo->vtype_retaddr);
+                       /* Just have to pop the arg, as done by normal methods in their epilog */
+                       info->ret_marshal = GSHAREDVT_RET_STACK_POP;
+                       break;
+               default:
+                       g_assert_not_reached ();
+               }
+       } else if (gsharedvt_in && cinfo->vtype_retaddr) {
+               info->ret_marshal = GSHAREDVT_RET_STACK_POP;
+       }
+
+       if (gsharedvt_in && var_ret && !caller_cinfo->vtype_retaddr) {
+               /* Allocate stack space for the return value */
+               info->vret_slot = info->stack_usage / sizeof (gpointer);
+               // FIXME:
+               info->stack_usage += sizeof (gpointer) * 3;
+       }
+
+       info->stack_usage = ALIGN_TO (info->stack_usage, MONO_ARCH_FRAME_ALIGNMENT);
+
+       g_free (caller_cinfo);
+       g_free (callee_cinfo);
+
+       return info;
+}
+#endif
index 1ef8d4614dd92f90cad7202396f7c9894ec9d5ea..e63198ad732a13a053caf3714a696662b87077a2 100644 (file)
@@ -179,49 +179,6 @@ mono_x86_patch (unsigned char* code, gpointer target)
        x86_patch (code, (unsigned char*)target);
 }
 
        x86_patch (code, (unsigned char*)target);
 }
 
-typedef enum {
-       ArgInIReg,
-       ArgInFloatSSEReg,
-       ArgInDoubleSSEReg,
-       ArgOnStack,
-       ArgValuetypeInReg,
-       ArgOnFloatFpStack,
-       ArgOnDoubleFpStack,
-       /* gsharedvt argument passed by addr */
-       ArgGSharedVt,
-       ArgNone
-} ArgStorage;
-
-typedef struct {
-       gint16 offset;
-       gint8  reg;
-       ArgStorage storage;
-       int nslots;
-       gboolean is_pair;
-
-       /* Only if storage == ArgValuetypeInReg */
-       ArgStorage pair_storage [2];
-       gint8 pair_regs [2];
-} ArgInfo;
-
-typedef struct {
-       int nargs;
-       guint32 stack_usage;
-       guint32 reg_usage;
-       guint32 freg_usage;
-       gboolean need_stack_align;
-       guint32 stack_align_amount;
-       gboolean vtype_retaddr;
-       /* The index of the vret arg in the argument list */
-       int vret_arg_index;
-       int vret_arg_offset;
-       /* Argument space popped by the callee */
-       int callee_stack_pop;
-       ArgInfo ret;
-       ArgInfo sig_cookie;
-       ArgInfo args [1];
-} CallInfo;
-
 #define FLOAT_PARAM_REGS 0
 
 static const guint32 thiscall_param_regs [] = { X86_ECX, X86_NREG };
 #define FLOAT_PARAM_REGS 0
 
 static const guint32 thiscall_param_regs [] = { X86_ECX, X86_NREG };
@@ -761,7 +718,7 @@ mono_arch_init (void)
 
        mono_aot_register_jit_icall ("mono_x86_throw_exception", mono_x86_throw_exception);
        mono_aot_register_jit_icall ("mono_x86_throw_corlib_exception", mono_x86_throw_corlib_exception);
 
        mono_aot_register_jit_icall ("mono_x86_throw_exception", mono_x86_throw_exception);
        mono_aot_register_jit_icall ("mono_x86_throw_corlib_exception", mono_x86_throw_corlib_exception);
-#if defined(ENABLE_GSHAREDVT)
+#if defined(MONO_ARCH_GSHAREDVT_SUPPORTED)
        mono_aot_register_jit_icall ("mono_x86_start_gsharedvt_call", mono_x86_start_gsharedvt_call);
 #endif
 }
        mono_aot_register_jit_icall ("mono_x86_start_gsharedvt_call", mono_x86_start_gsharedvt_call);
 #endif
 }
@@ -6806,8 +6763,8 @@ mono_arch_opcode_supported (int opcode)
        }
 }
 
        }
 }
 
-#if defined(ENABLE_GSHAREDVT)
-
-#include "../../../mono-extensions/mono/mini/mini-x86-gsharedvt.c"
-
-#endif /* !MONOTOUCH */
+CallInfo*
+mono_arch_get_call_info (MonoMemPool *mp, MonoMethodSignature *sig)
+{
+       return get_call_info (mp, sig);
+}
index 212f844af4ca27f1076c08c4b917081aeac08c4e..969b679f29bbfdd161bd5a77c6c68cf7d6900cbc 100644 (file)
@@ -300,6 +300,49 @@ typedef struct {
        int map [MONO_ZERO_LEN_ARRAY];
 } GSharedVtCallInfo;
 
        int map [MONO_ZERO_LEN_ARRAY];
 } GSharedVtCallInfo;
 
+typedef enum {
+       ArgInIReg,
+       ArgInFloatSSEReg,
+       ArgInDoubleSSEReg,
+       ArgOnStack,
+       ArgValuetypeInReg,
+       ArgOnFloatFpStack,
+       ArgOnDoubleFpStack,
+       /* gsharedvt argument passed by addr */
+       ArgGSharedVt,
+       ArgNone
+} ArgStorage;
+
+typedef struct {
+       gint16 offset;
+       gint8  reg;
+       ArgStorage storage;
+       int nslots;
+       gboolean is_pair;
+
+       /* Only if storage == ArgValuetypeInReg */
+       ArgStorage pair_storage [2];
+       gint8 pair_regs [2];
+} ArgInfo;
+
+typedef struct {
+       int nargs;
+       guint32 stack_usage;
+       guint32 reg_usage;
+       guint32 freg_usage;
+       gboolean need_stack_align;
+       guint32 stack_align_amount;
+       gboolean vtype_retaddr;
+       /* The index of the vret arg in the argument list */
+       int vret_arg_index;
+       int vret_arg_offset;
+       /* Argument space popped by the callee */
+       int callee_stack_pop;
+       ArgInfo ret;
+       ArgInfo sig_cookie;
+       ArgInfo args [1];
+} CallInfo;
+
 guint8*
 mono_x86_emit_tls_get (guint8* code, int dreg, int tls_offset);
 
 guint8*
 mono_x86_emit_tls_get (guint8* code, int dreg, int tls_offset);
 
@@ -326,5 +369,8 @@ mono_x86_patch (unsigned char* code, gpointer target);
 gpointer
 mono_x86_start_gsharedvt_call (GSharedVtCallInfo *info, gpointer *caller, gpointer *callee, gpointer mrgctx_reg);
 
 gpointer
 mono_x86_start_gsharedvt_call (GSharedVtCallInfo *info, gpointer *caller, gpointer *callee, gpointer mrgctx_reg);
 
+CallInfo*
+mono_arch_get_call_info (MonoMemPool *mp, MonoMethodSignature *sig);
+
 #endif /* __MONO_MINI_X86_H__ */  
 
 #endif /* __MONO_MINI_X86_H__ */  
 
diff --git a/mono/mini/tramp-x86-gsharedvt.c b/mono/mini/tramp-x86-gsharedvt.c
new file mode 100644 (file)
index 0000000..757325c
--- /dev/null
@@ -0,0 +1,369 @@
+/*
+ * tramp-x86-gsharedvt.c: gsharedvt support code for x86
+ *
+ * Authors:
+ *   Zoltan Varga <vargaz@gmail.com>
+ *
+ * Copyright 2013 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 <mono/metadata/abi-details.h>
+
+#ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
+
+gpointer
+mono_x86_start_gsharedvt_call (GSharedVtCallInfo *info, gpointer *caller, gpointer *callee, gpointer mrgctx_reg)
+{
+       int i;
+       int *map = info->map;
+
+       /* Set vtype ret arg */
+       if (info->vret_arg_slot != -1) {
+               callee [info->vret_arg_slot] = &callee [info->vret_slot];
+       }
+       /* Copy data from the caller argument area to the callee */
+       for (i = 0; i < info->map_count; ++i) {
+               int src = map [i * 2];
+               int dst = map [i * 2 + 1];
+
+               switch ((src >> 16) & 0x3) {
+               case 0:
+                       callee [dst] = caller [src];
+                       break;
+               case 1: {
+                       int j, nslots;
+                       gpointer *arg;
+
+                       /* gsharedvt->normal */
+                       nslots = src >> 18;
+                       arg = (gpointer*)caller [src & 0xffff];
+                       for (j = 0; j < nslots; ++j)
+                               callee [dst + j] = arg [j];
+                       break;
+               }
+               case 2:
+                       /* gsharedvt arg, have to take its address */
+                       callee [dst] = caller + (src & 0xffff);
+                       break;
+#if 0
+               int dst = map [i * 2 + 1];
+               if (dst >= 0xffff) {
+                       /* gsharedvt arg, have to take its address */
+                       callee [dst - 0xffff] = caller + map [i * 2];
+               } else {
+                       callee [dst] = caller [map [i * 2]];
+               }
+#endif
+               }
+       }
+
+       if (info->vcall_offset != -1) {
+               MonoObject *this_obj = caller [0];
+
+               if (G_UNLIKELY (!this_obj))
+                       return NULL;
+               if (info->vcall_offset == MONO_GSHAREDVT_DEL_INVOKE_VT_OFFSET)
+                       /* delegate invoke */
+                       return ((MonoDelegate*)this_obj)->invoke_impl;
+               else
+                       return *(gpointer*)((char*)this_obj->vtable + info->vcall_offset);
+       } else if (info->calli) {
+               /* The address to call is passed in the mrgctx reg */
+               return mrgctx_reg;
+       } else {
+               return info->addr;
+       }
+
+}
+
+gpointer
+mono_arch_get_gsharedvt_trampoline (MonoTrampInfo **info, gboolean aot)
+{
+       guint8 *code, *buf;
+       int buf_len, cfa_offset;
+       GSList *unwind_ops = NULL;
+       MonoJumpInfo *ji = NULL;
+       guint8 *br_out, *br [16];
+       int info_offset, mrgctx_offset;
+
+       buf_len = 320;
+       buf = code = mono_global_codeman_reserve (buf_len);
+
+       /*
+        * This trampoline is responsible for marshalling calls between normal code and gsharedvt code. The
+        * caller is a normal or gshared method which uses the signature of the inflated method to make the call, while
+        * the callee is a gsharedvt method which has a signature which uses valuetypes in place of type parameters, i.e.
+        * caller:
+        * foo<bool> (bool b)
+        * callee:
+        * T=<type used to represent vtype type arguments, currently TypedByRef>
+        * foo<T> (T b)
+        * The trampoline is responsible for marshalling the arguments and marshalling the result back. To simplify
+        * things, we create our own stack frame, and do most of the work in a C function, which receives a
+        * GSharedVtCallInfo structure as an argument. The structure should contain information to execute the C function to
+        * be as fast as possible. The argument is received in EAX from a gsharedvt trampoline. So the real
+        * call sequence looks like this:
+        * caller -> gsharedvt trampoline -> gsharevt in trampoline -> start_gsharedvt_call
+        * FIXME: Optimize this.
+        */
+
+       cfa_offset = sizeof (gpointer);
+       mono_add_unwind_op_def_cfa (unwind_ops, code, buf, X86_ESP, cfa_offset);
+       mono_add_unwind_op_offset (unwind_ops, code, buf, X86_NREG, -cfa_offset);
+       x86_push_reg (code, X86_EBP);
+       cfa_offset += sizeof (gpointer);
+       mono_add_unwind_op_def_cfa_offset (unwind_ops, code, buf, cfa_offset);
+       mono_add_unwind_op_offset (unwind_ops, code, buf, X86_EBP, - cfa_offset);
+       x86_mov_reg_reg (code, X86_EBP, X86_ESP, sizeof (gpointer));
+       mono_add_unwind_op_def_cfa_reg (unwind_ops, code, buf, X86_EBP);
+       /* Alloc stack frame/align stack */
+       x86_alu_reg_imm (code, X86_SUB, X86_ESP, 8);
+       info_offset = -4;
+       mrgctx_offset = - 8;
+       /* The info struct is put into EAX by the gsharedvt trampoline */
+       /* Save info struct addr */
+       x86_mov_membase_reg (code, X86_EBP, info_offset, X86_EAX, 4);
+       /* Save rgctx */
+       x86_mov_membase_reg (code, X86_EBP, mrgctx_offset, MONO_ARCH_RGCTX_REG, 4);
+
+       /* Allocate stack area used to pass arguments to the method */
+       x86_mov_reg_membase (code, X86_EAX, X86_EAX, MONO_STRUCT_OFFSET (GSharedVtCallInfo, stack_usage), sizeof (gpointer));
+       x86_alu_reg_reg (code, X86_SUB, X86_ESP, X86_EAX);
+
+#if 0
+       /* Stack alignment check */
+       x86_mov_reg_reg (code, X86_ECX, X86_ESP, 4);
+       x86_alu_reg_imm (code, X86_AND, X86_ECX, MONO_ARCH_FRAME_ALIGNMENT - 1);
+       x86_alu_reg_imm (code, X86_CMP, X86_ECX, 0);
+       x86_branch_disp (code, X86_CC_EQ, 3, FALSE);
+       x86_breakpoint (code);
+#endif
+
+       /* ecx = caller argument area */
+       x86_mov_reg_reg (code, X86_ECX, X86_EBP, 4);
+       x86_alu_reg_imm (code, X86_ADD, X86_ECX, 8);
+       /* eax = callee argument area */
+       x86_mov_reg_reg (code, X86_EAX, X86_ESP, 4);
+
+       /* Call start_gsharedvt_call */
+       /* Arg 4 */
+       x86_push_membase (code, X86_EBP, mrgctx_offset);
+       /* Arg3 */
+       x86_push_reg (code, X86_EAX);
+       /* Arg2 */
+       x86_push_reg (code, X86_ECX);
+       /* Arg1 */
+       x86_push_membase (code, X86_EBP, info_offset);
+       if (aot) {
+               code = mono_arch_emit_load_aotconst (buf, code, &ji, MONO_PATCH_INFO_JIT_ICALL_ADDR, "mono_x86_start_gsharedvt_call");
+               x86_call_reg (code, X86_EAX);
+       } else {
+               x86_call_code (code, mono_x86_start_gsharedvt_call);
+       }
+       x86_alu_reg_imm (code, X86_ADD, X86_ESP, 4 * 4);
+       /* The address to call is in eax */
+       /* The stack is now setup for the real call */
+       /* Load info struct */
+       x86_mov_reg_membase (code, X86_ECX, X86_EBP, info_offset, 4);
+       /* Load rgctx */
+       x86_mov_reg_membase (code, MONO_ARCH_RGCTX_REG, X86_EBP, mrgctx_offset, sizeof (gpointer));
+       /* Make the call */
+       x86_call_reg (code, X86_EAX);
+       /* The return value is either in registers, or stored to an area beginning at sp [info->vret_slot] */
+       /* EAX/EDX might contain the return value, only ECX is free */
+       /* Load info struct */
+       x86_mov_reg_membase (code, X86_ECX, X86_EBP, info_offset, 4);
+
+       /* Branch to the in/out handling code */
+       x86_alu_membase_imm (code, X86_CMP, X86_ECX, MONO_STRUCT_OFFSET (GSharedVtCallInfo, gsharedvt_in), 1);  
+       br_out = code;
+       x86_branch32 (code, X86_CC_NE, 0, TRUE);
+
+       /*
+        * IN CASE
+        */
+
+       /* Load ret marshal type */
+       x86_mov_reg_membase (code, X86_ECX, X86_ECX, MONO_STRUCT_OFFSET (GSharedVtCallInfo, ret_marshal), 4);
+       x86_alu_reg_imm (code, X86_CMP, X86_ECX, GSHAREDVT_RET_NONE);
+       br [0] = code;
+       x86_branch8 (code, X86_CC_NE, 0, TRUE);
+
+       /* Normal return, no marshalling required */
+       x86_leave (code);
+       x86_ret (code);
+
+       /* Return value marshalling */
+       x86_patch (br [0], code);
+       /* Load info struct */
+       x86_mov_reg_membase (code, X86_EAX, X86_EBP, info_offset, 4);
+       /* Load 'vret_slot' */
+       x86_mov_reg_membase (code, X86_EAX, X86_EAX, MONO_STRUCT_OFFSET (GSharedVtCallInfo, vret_slot), 4);
+       /* Compute ret area address */
+       x86_shift_reg_imm (code, X86_SHL, X86_EAX, 2);
+       x86_alu_reg_reg (code, X86_ADD, X86_EAX, X86_ESP);
+       /* The callee does a ret $4, so sp is off by 4 */
+       x86_alu_reg_imm (code, X86_SUB, X86_EAX, sizeof (gpointer));
+
+       /* Branch to specific marshalling code */
+       // FIXME: Move the I4 case to the top */
+       x86_alu_reg_imm (code, X86_CMP, X86_ECX, GSHAREDVT_RET_DOUBLE_FPSTACK);
+       br [1] = code;
+       x86_branch8 (code, X86_CC_E, 0, TRUE);
+       x86_alu_reg_imm (code, X86_CMP, X86_ECX, GSHAREDVT_RET_FLOAT_FPSTACK);
+       br [2] = code;
+       x86_branch8 (code, X86_CC_E, 0, TRUE);
+       x86_alu_reg_imm (code, X86_CMP, X86_ECX, GSHAREDVT_RET_STACK_POP);
+       br [3] = code;
+       x86_branch8 (code, X86_CC_E, 0, TRUE);
+       x86_alu_reg_imm (code, X86_CMP, X86_ECX, GSHAREDVT_RET_I1);
+       br [4] = code;
+       x86_branch8 (code, X86_CC_E, 0, TRUE);
+       x86_alu_reg_imm (code, X86_CMP, X86_ECX, GSHAREDVT_RET_U1);
+       br [5] = code;
+       x86_branch8 (code, X86_CC_E, 0, TRUE);
+       x86_alu_reg_imm (code, X86_CMP, X86_ECX, GSHAREDVT_RET_I2);
+       br [6] = code;
+       x86_branch8 (code, X86_CC_E, 0, TRUE);
+       x86_alu_reg_imm (code, X86_CMP, X86_ECX, GSHAREDVT_RET_U2);
+       br [7] = code;
+       x86_branch8 (code, X86_CC_E, 0, TRUE);
+       /* IREGS case */
+       /* Load both eax and edx for simplicity */
+       x86_mov_reg_membase (code, X86_EDX, X86_EAX, sizeof (gpointer), sizeof (gpointer));
+       x86_mov_reg_membase (code, X86_EAX, X86_EAX, 0, sizeof (gpointer));
+       x86_leave (code);
+       x86_ret (code);
+       /* DOUBLE_FPSTACK case */
+       x86_patch (br [1], code);
+       x86_fld_membase (code, X86_EAX, 0, TRUE);
+       x86_jump8 (code, 0);
+       x86_leave (code);
+       x86_ret (code);
+       /* FLOAT_FPSTACK case */
+       x86_patch (br [2], code);
+       x86_fld_membase (code, X86_EAX, 0, FALSE);
+       x86_leave (code);
+       x86_ret (code);
+       /* STACK_POP case */
+       x86_patch (br [3], code);
+       x86_leave (code);
+       x86_ret_imm (code, 4);
+       /* I1 case */
+       x86_patch (br [4], code);
+       x86_widen_membase (code, X86_EAX, X86_EAX, 0, TRUE, FALSE);
+       x86_leave (code);
+       x86_ret (code);
+       /* U1 case */
+       x86_patch (br [5], code);
+       x86_widen_membase (code, X86_EAX, X86_EAX, 0, FALSE, FALSE);
+       x86_leave (code);
+       x86_ret (code);
+       /* I2 case */
+       x86_patch (br [6], code);
+       x86_widen_membase (code, X86_EAX, X86_EAX, 0, TRUE, TRUE);
+       x86_leave (code);
+       x86_ret (code);
+       /* U2 case */
+       x86_patch (br [7], code);
+       x86_widen_membase (code, X86_EAX, X86_EAX, 0, FALSE, TRUE);
+       x86_leave (code);
+       x86_ret (code);
+
+       /*
+        * OUT CASE
+        */
+
+       x86_patch (br_out, code);
+       /* Load ret marshal type into ECX */
+       x86_mov_reg_membase (code, X86_ECX, X86_ECX, MONO_STRUCT_OFFSET (GSharedVtCallInfo, ret_marshal), 4);
+       x86_alu_reg_imm (code, X86_CMP, X86_ECX, GSHAREDVT_RET_NONE);
+       br [0] = code;
+       x86_branch8 (code, X86_CC_NE, 0, TRUE);
+
+       /* Normal return, no marshalling required */
+       x86_leave (code);
+       x86_ret (code);
+
+       /* Return value marshalling */
+       x86_patch (br [0], code);
+
+       /* EAX might contain the return value */
+       // FIXME: Use moves
+       x86_push_reg (code, X86_EAX);
+
+       /* Load info struct */
+       x86_mov_reg_membase (code, X86_EAX, X86_EBP, info_offset, 4);
+       /* Load 'vret_arg_slot' */
+       x86_mov_reg_membase (code, X86_EAX, X86_EAX, MONO_STRUCT_OFFSET (GSharedVtCallInfo, vret_arg_slot), 4);
+       /* Compute ret area address in the caller frame in EAX */
+       x86_shift_reg_imm (code, X86_SHL, X86_EAX, 2);
+       x86_alu_reg_reg (code, X86_ADD, X86_EAX, X86_EBP);
+       x86_alu_reg_imm (code, X86_ADD, X86_EAX, 8);
+       x86_mov_reg_membase (code, X86_EAX, X86_EAX, 0, sizeof (gpointer));
+
+       /* Branch to specific marshalling code */
+       x86_alu_reg_imm (code, X86_CMP, X86_ECX, GSHAREDVT_RET_DOUBLE_FPSTACK);
+       br [1] = code;
+       x86_branch8 (code, X86_CC_E, 0, TRUE);
+       x86_alu_reg_imm (code, X86_CMP, X86_ECX, GSHAREDVT_RET_FLOAT_FPSTACK);
+       br [2] = code;
+       x86_branch8 (code, X86_CC_E, 0, TRUE);
+       x86_alu_reg_imm (code, X86_CMP, X86_ECX, GSHAREDVT_RET_STACK_POP);
+       br [3] = code;
+       x86_branch8 (code, X86_CC_E, 0, TRUE);
+       x86_alu_reg_imm (code, X86_CMP, X86_ECX, GSHAREDVT_RET_IREGS);
+       br [4] = code;
+       x86_branch8 (code, X86_CC_E, 0, TRUE);
+       /* IREG case */
+       x86_mov_reg_reg (code, X86_ECX, X86_EAX, sizeof (gpointer));
+       x86_pop_reg (code, X86_EAX);
+       x86_mov_membase_reg (code, X86_ECX, 0, X86_EAX, sizeof (gpointer));
+       x86_leave (code);
+       x86_ret_imm (code, 4);
+       /* IREGS case */
+       x86_patch (br [4], code);
+       x86_mov_reg_reg (code, X86_ECX, X86_EAX, sizeof (gpointer));
+       x86_pop_reg (code, X86_EAX);
+       x86_mov_membase_reg (code, X86_ECX, sizeof (gpointer), X86_EDX, sizeof (gpointer));
+       x86_mov_membase_reg (code, X86_ECX, 0, X86_EAX, sizeof (gpointer));
+       x86_leave (code);
+       x86_ret_imm (code, 4);
+       /* DOUBLE_FPSTACK case */
+       x86_alu_reg_imm (code, X86_ADD, X86_ESP, 4);
+       x86_patch (br [1], code);
+       x86_fst_membase (code, X86_EAX, 0, TRUE, TRUE);
+       x86_jump8 (code, 0);
+       x86_leave (code);
+       x86_ret_imm (code, 4);
+       /* FLOAT_FPSTACK case */
+       x86_alu_reg_imm (code, X86_ADD, X86_ESP, 4);
+       x86_patch (br [2], code);
+       x86_fst_membase (code, X86_EAX, 0, FALSE, TRUE);
+       x86_leave (code);
+       x86_ret_imm (code, 4);
+       /* STACK_POP case */
+       x86_patch (br [3], code);
+       x86_leave (code);
+       x86_ret_imm (code, 4);
+
+       g_assert ((code - buf) < buf_len);
+
+       if (info)
+               *info = mono_tramp_info_create ("gsharedvt_trampoline", buf, code - buf, ji, unwind_ops);
+
+       mono_arch_flush_icache (buf, code - buf);
+       return buf;
+}
+
+#else
+
+gpointer
+mono_arch_get_gsharedvt_trampoline (MonoTrampInfo **info, gboolean aot)
+{
+       *info = NULL;
+       return NULL;
+}
+
+#endif /* MONO_ARCH_GSHAREDVT_SUPPORTED */
index e416527c2b3ceb59d8979a129a84384581520cfe..dd560843018d8a2a3a59b8917eb25aada8874680 100644 (file)
@@ -878,17 +878,3 @@ mono_arch_create_sdb_trampoline (gboolean single_step, MonoTrampInfo **info, gbo
        return buf;
 }
 
        return buf;
 }
 
-#if defined(ENABLE_GSHAREDVT)
-
-#include "../../../mono-extensions/mono/mini/tramp-x86-gsharedvt.c"
-
-#else
-
-gpointer
-mono_arch_get_gsharedvt_trampoline (MonoTrampInfo **info, gboolean aot)
-{
-       *info = NULL;
-       return NULL;
-}
-
-#endif /* !MONOTOUCH */