Revert "[mono][debugger] First PR to implement iCorDebug on mono (#20757)"
[mono-project.git] / mono / mini / mini-x86-gsharedvt.c
blobda50211c268a8317fa075b0733e7aca77d2468b5
1 /**
2 * \file
3 * gsharedvt support code for x86
5 * Authors:
6 * Zoltan Varga <vargaz@gmail.com>
8 * Copyright 2013 Xamarin, Inc (http://www.xamarin.com)
9 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
11 #include "mini.h"
13 #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
16 * GSHAREDVT
19 gboolean
20 mono_arch_gsharedvt_sig_supported (MonoMethodSignature *sig)
23 if (sig->ret && is_variable_size (sig->ret))
24 return FALSE;
26 return TRUE;
30 * mono_arch_get_gsharedvt_call_info:
32 * Compute calling convention information for marshalling a call between NORMAL_SIG and GSHAREDVT_SIG.
33 * If GSHAREDVT_IN is TRUE, then the caller calls using the signature NORMAL_SIG but the call is received by
34 * a method with signature GSHAREDVT_SIG, otherwise its the other way around.
36 gpointer
37 mono_arch_get_gsharedvt_call_info (gpointer addr, MonoMethodSignature *normal_sig, MonoMethodSignature *gsharedvt_sig, gboolean gsharedvt_in, gint32 vcall_offset, gboolean calli)
39 GSharedVtCallInfo *info;
40 CallInfo *caller_cinfo, *callee_cinfo;
41 MonoMethodSignature *caller_sig, *callee_sig;
42 int i, j;
43 gboolean var_ret = FALSE;
44 CallInfo *cinfo, *gcinfo;
45 MonoMethodSignature *sig, *gsig;
46 GPtrArray *map;
48 if (gsharedvt_in) {
49 caller_sig = normal_sig;
50 callee_sig = gsharedvt_sig;
51 caller_cinfo = mono_arch_get_call_info (NULL, caller_sig);
52 callee_cinfo = mono_arch_get_call_info (NULL, callee_sig);
53 } else {
54 callee_sig = normal_sig;
55 callee_cinfo = mono_arch_get_call_info (NULL, callee_sig);
56 caller_sig = gsharedvt_sig;
57 caller_cinfo = mono_arch_get_call_info (NULL, caller_sig);
61 * If GSHAREDVT_IN is true, this means we are transitioning from normal to gsharedvt code. The caller uses the
62 * normal call signature, while the callee uses the gsharedvt signature.
63 * If GSHAREDVT_IN is false, its the other way around.
66 /* sig/cinfo describes the normal call, while gsig/gcinfo describes the gsharedvt call */
67 if (gsharedvt_in) {
68 sig = caller_sig;
69 gsig = callee_sig;
70 cinfo = caller_cinfo;
71 gcinfo = callee_cinfo;
72 } else {
73 sig = callee_sig;
74 gsig = caller_sig;
75 cinfo = callee_cinfo;
76 gcinfo = caller_cinfo;
79 if (gcinfo->vtype_retaddr && gsig->ret && mini_is_gsharedvt_type (gsig->ret)) {
81 * The return type is gsharedvt
83 var_ret = TRUE;
87 * The stack looks like this:
88 * <arguments>
89 * <ret addr>
90 * <saved ebp>
91 * <call area>
92 * We have to map the stack slots in <arguments> to the stack slots in <call area>.
94 map = g_ptr_array_new ();
96 if (cinfo->vtype_retaddr) {
98 * Map ret arg.
99 * This handles the case when the method returns a normal vtype, and when it returns a type arg, and its instantiated
100 * with a vtype.
102 g_ptr_array_add (map, GUINT_TO_POINTER (caller_cinfo->vret_arg_offset / sizeof (target_mgreg_t)));
103 g_ptr_array_add (map, GUINT_TO_POINTER (callee_cinfo->vret_arg_offset / sizeof (target_mgreg_t)));
106 for (i = 0; i < cinfo->nargs; ++i) {
107 ArgInfo *ainfo = &caller_cinfo->args [i];
108 ArgInfo *ainfo2 = &callee_cinfo->args [i];
109 int nslots;
111 switch (ainfo->storage) {
112 case ArgGSharedVt:
113 if (ainfo2->storage == ArgOnStack) {
114 nslots = callee_cinfo->args [i].nslots;
115 if (!nslots)
116 nslots = 1;
117 g_ptr_array_add (map, GUINT_TO_POINTER ((ainfo->offset / sizeof (target_mgreg_t)) + (1 << 16) + (nslots << 18)));
118 g_ptr_array_add (map, GUINT_TO_POINTER ((ainfo2->offset / sizeof (target_mgreg_t))));
119 } else {
120 g_ptr_array_add (map, GUINT_TO_POINTER ((ainfo->offset / sizeof (target_mgreg_t))));
121 g_ptr_array_add (map, GUINT_TO_POINTER ((ainfo2->offset / sizeof (target_mgreg_t))));
123 break;
124 default:
125 if (ainfo2->storage == ArgOnStack) {
126 nslots = cinfo->args [i].nslots;
127 if (!nslots)
128 nslots = 1;
129 for (j = 0; j < nslots; ++j) {
130 g_ptr_array_add (map, GUINT_TO_POINTER ((ainfo->offset / sizeof (target_mgreg_t)) + j));
131 g_ptr_array_add (map, GUINT_TO_POINTER ((ainfo2->offset / sizeof (target_mgreg_t)) + j));
133 } else {
134 g_assert (ainfo2->storage == ArgGSharedVt);
135 g_ptr_array_add (map, GUINT_TO_POINTER ((ainfo->offset / sizeof (target_mgreg_t)) + (2 << 16)));
136 g_ptr_array_add (map, GUINT_TO_POINTER ((ainfo2->offset / sizeof (target_mgreg_t))));
138 break;
142 info = mono_domain_alloc0 (mono_domain_get (), sizeof (GSharedVtCallInfo) + (map->len * sizeof (int)));
143 info->addr = addr;
144 info->stack_usage = callee_cinfo->stack_usage;
145 info->ret_marshal = GSHAREDVT_RET_NONE;
146 info->gsharedvt_in = gsharedvt_in ? 1 : 0;
147 info->vret_slot = -1;
148 info->calli = calli ? 1 : 0;
149 if (var_ret)
150 info->vret_arg_slot = gcinfo->vret_arg_offset / sizeof (target_mgreg_t);
151 else
152 info->vret_arg_slot = -1;
153 info->vcall_offset = vcall_offset;
154 info->map_count = map->len / 2;
155 for (i = 0; i < map->len; ++i)
156 info->map [i] = GPOINTER_TO_UINT (g_ptr_array_index (map, i));
157 g_ptr_array_free (map, TRUE);
159 /* Compute return value marshalling */
160 if (var_ret) {
161 switch (cinfo->ret.storage) {
162 case ArgInIReg:
163 if (gsharedvt_in && !sig->ret->byref && sig->ret->type == MONO_TYPE_I1)
164 info->ret_marshal = GSHAREDVT_RET_I1;
165 else if (gsharedvt_in && !sig->ret->byref && (sig->ret->type == MONO_TYPE_U1 || sig->ret->type == MONO_TYPE_BOOLEAN))
166 info->ret_marshal = GSHAREDVT_RET_U1;
167 else if (gsharedvt_in && !sig->ret->byref && sig->ret->type == MONO_TYPE_I2)
168 info->ret_marshal = GSHAREDVT_RET_I2;
169 else if (gsharedvt_in && !sig->ret->byref && (sig->ret->type == MONO_TYPE_U2 || sig->ret->type == MONO_TYPE_CHAR))
170 info->ret_marshal = GSHAREDVT_RET_U2;
171 else if (cinfo->ret.is_pair)
172 info->ret_marshal = GSHAREDVT_RET_IREGS;
173 else
174 info->ret_marshal = GSHAREDVT_RET_IREG;
175 break;
176 case ArgOnDoubleFpStack:
177 info->ret_marshal = GSHAREDVT_RET_DOUBLE_FPSTACK;
178 break;
179 case ArgOnFloatFpStack:
180 info->ret_marshal = GSHAREDVT_RET_FLOAT_FPSTACK;
181 break;
182 case ArgOnStack:
183 /* The caller passes in a vtype ret arg as well */
184 g_assert (gcinfo->vtype_retaddr);
185 /* Just have to pop the arg, as done by normal methods in their epilog */
186 info->ret_marshal = GSHAREDVT_RET_STACK_POP;
187 break;
188 default:
189 g_assert_not_reached ();
191 } else if (gsharedvt_in && cinfo->vtype_retaddr) {
192 info->ret_marshal = GSHAREDVT_RET_STACK_POP;
195 if (gsharedvt_in && var_ret && !caller_cinfo->vtype_retaddr) {
196 /* Allocate stack space for the return value */
197 info->vret_slot = info->stack_usage / sizeof (target_mgreg_t);
198 // FIXME:
199 info->stack_usage += sizeof (target_mgreg_t) * 3;
202 info->stack_usage = ALIGN_TO (info->stack_usage, MONO_ARCH_FRAME_ALIGNMENT);
204 g_free (caller_cinfo);
205 g_free (callee_cinfo);
207 return info;
209 #endif