[Sockets]: Always reset internal SAEA completion when reattempting connection in...
[mono-project.git] / mono / mini / mini-arm-gsharedvt.c
blob7b19419f8a6a9b096bc13d3702e412df14f91912
1 /**
2 * \file
3 * gsharedvt support code for arm
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 <config.h>
12 #include <glib.h>
14 #include <mono/metadata/abi-details.h>
15 #include <mono/metadata/appdomain.h>
16 #include <mono/metadata/marshal.h>
17 #include <mono/metadata/tabledefs.h>
18 #include <mono/metadata/profiler-private.h>
19 #include <mono/arch/arm/arm-codegen.h>
20 #include <mono/arch/arm/arm-vfp-codegen.h>
22 #include "mini.h"
23 #include "mini-arm.h"
25 #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
28 * GSHAREDVT
31 gboolean
32 mono_arch_gsharedvt_sig_supported (MonoMethodSignature *sig)
35 if (sig->ret && is_variable_size (sig->ret))
36 return FALSE;
38 return TRUE;
41 static void
42 add_to_map (GPtrArray *map, int src, int dst)
44 g_ptr_array_add (map, GUINT_TO_POINTER (src));
45 g_ptr_array_add (map, GUINT_TO_POINTER (dst));
48 static int
49 map_reg (int reg)
51 return reg;
54 static int
55 map_stack_slot (int slot)
57 return slot + 4;
60 static int
61 get_arg_slots (ArgInfo *ainfo, int **out_slots)
63 int sreg = ainfo->reg;
64 int sslot = ainfo->offset / 4;
65 int *src = NULL;
66 int i, nsrc;
68 switch (ainfo->storage) {
69 case RegTypeGeneral:
70 nsrc = 1;
71 src = g_malloc (nsrc * sizeof (int));
72 src [0] = map_reg (sreg);
73 break;
74 case RegTypeIRegPair:
75 nsrc = 2;
76 src = g_malloc (nsrc * sizeof (int));
77 src [0] = map_reg (sreg);
78 src [1] = map_reg (sreg + 1);
79 break;
80 case RegTypeStructByVal:
81 nsrc = ainfo->struct_size / 4;
82 src = g_malloc (nsrc * sizeof (int));
83 g_assert (ainfo->size <= nsrc);
84 for (i = 0; i < ainfo->size; ++i)
85 src [i] = map_reg (sreg + i);
86 for (i = ainfo->size; i < nsrc; ++i)
87 src [i] = map_stack_slot (sslot + (i - ainfo->size));
88 break;
89 case RegTypeBase:
90 nsrc = ainfo->size / 4;
91 src = g_malloc (nsrc * sizeof (int));
92 for (i = 0; i < nsrc; ++i)
93 src [i] = map_stack_slot (sslot + i);
94 break;
95 case RegTypeBaseGen:
96 nsrc = 2;
97 src = g_malloc (nsrc * sizeof (int));
98 src [0] = map_reg (ARMREG_R3);
99 src [1] = map_stack_slot (sslot);
100 break;
101 default:
102 g_assert_not_reached ();
103 break;
106 *out_slots = src;
107 return nsrc;
111 * mono_arch_get_gsharedvt_call_info:
113 * See mini-x86.c for documentation.
115 gpointer
116 mono_arch_get_gsharedvt_call_info (gpointer addr, MonoMethodSignature *normal_sig, MonoMethodSignature *gsharedvt_sig, gboolean gsharedvt_in, gint32 vcall_offset, gboolean calli)
118 GSharedVtCallInfo *info;
119 CallInfo *caller_cinfo, *callee_cinfo;
120 MonoMethodSignature *caller_sig, *callee_sig;
121 int aindex, i;
122 gboolean var_ret = FALSE;
123 gboolean have_fregs = FALSE;
124 CallInfo *cinfo, *gcinfo;
125 MonoMethodSignature *sig, *gsig;
126 GPtrArray *map;
128 if (gsharedvt_in) {
129 caller_sig = normal_sig;
130 callee_sig = gsharedvt_sig;
131 caller_cinfo = mono_arch_get_call_info (NULL, caller_sig);
132 callee_cinfo = mono_arch_get_call_info (NULL, callee_sig);
133 } else {
134 callee_sig = normal_sig;
135 callee_cinfo = mono_arch_get_call_info (NULL, callee_sig);
136 caller_sig = gsharedvt_sig;
137 caller_cinfo = mono_arch_get_call_info (NULL, caller_sig);
141 * If GSHAREDVT_IN is true, this means we are transitioning from normal to gsharedvt code. The caller uses the
142 * normal call signature, while the callee uses the gsharedvt signature.
143 * If GSHAREDVT_IN is false, its the other way around.
146 /* sig/cinfo describes the normal call, while gsig/gcinfo describes the gsharedvt call */
147 if (gsharedvt_in) {
148 sig = caller_sig;
149 gsig = callee_sig;
150 cinfo = caller_cinfo;
151 gcinfo = callee_cinfo;
152 } else {
153 sig = callee_sig;
154 gsig = caller_sig;
155 cinfo = callee_cinfo;
156 gcinfo = caller_cinfo;
159 if (gcinfo->ret.storage == RegTypeStructByAddr && gsig->ret && mini_is_gsharedvt_type (gsig->ret)) {
161 * The return type is gsharedvt
163 var_ret = TRUE;
167 * The stack looks like this:
168 * <arguments>
169 * <ret addr>
170 * <saved ebp>
171 * <call area>
172 * We have to map the stack slots in <arguments> to the stack slots in <call area>.
173 * The argument registers are mapped to slot 0..3, stack slot 0 is mapped to slot 4, etc.
175 map = g_ptr_array_new ();
177 if (cinfo->ret.storage == RegTypeStructByAddr) {
179 * Map ret arg.
180 * This handles the case when the method returns a normal vtype, and when it returns a type arg, and its instantiated
181 * with a vtype.
183 g_assert (caller_cinfo->ret.storage == RegTypeStructByAddr);
184 g_assert (callee_cinfo->ret.storage == RegTypeStructByAddr);
185 add_to_map (map, map_reg (caller_cinfo->ret.reg), map_reg (callee_cinfo->ret.reg));
188 for (aindex = 0; aindex < cinfo->nargs; ++aindex) {
189 ArgInfo *ainfo = &caller_cinfo->args [aindex];
190 ArgInfo *ainfo2 = &callee_cinfo->args [aindex];
191 int *src = NULL, *dst = NULL;
192 int nsrc, ndst, nslots, src_slot, arg_marshal;
194 if (ainfo->storage == RegTypeFP || ainfo2->storage == RegTypeFP) {
195 have_fregs = TRUE;
196 continue;
200 * The src descriptor looks like this:
201 * - 4 bits src slot
202 * - 12 bits number of slots
203 * - 8 bits marshal type (GSHAREDVT_ARG_...)
206 arg_marshal = GSHAREDVT_ARG_NONE;
208 if (ainfo->storage == RegTypeGSharedVtInReg || ainfo->storage == RegTypeGSharedVtOnStack) {
209 /* Pass the value whose address is received in a reg by value */
210 g_assert (ainfo2->storage != RegTypeGSharedVtInReg);
211 ndst = get_arg_slots (ainfo2, &dst);
212 nsrc = 1;
213 src = g_new0 (int, 1);
214 if (ainfo->storage == RegTypeGSharedVtInReg)
215 src_slot = map_reg (ainfo->reg);
216 else
217 src_slot = map_stack_slot (ainfo->offset / sizeof (target_mgreg_t));
218 g_assert (ndst < 256);
219 g_assert (src_slot < 256);
220 src [0] = (ndst << 8) | src_slot;
222 if (ainfo2->storage == RegTypeGeneral && ainfo2->size != 0 && ainfo2->size != sizeof (target_mgreg_t)) {
223 /* Have to load less than 4 bytes */
224 switch (ainfo2->size) {
225 case 1:
226 arg_marshal = ainfo2->is_signed ? GSHAREDVT_ARG_BYREF_TO_BYVAL_I1 : GSHAREDVT_ARG_BYREF_TO_BYVAL_U1;
227 break;
228 case 2:
229 arg_marshal = ainfo2->is_signed ? GSHAREDVT_ARG_BYREF_TO_BYVAL_I2 : GSHAREDVT_ARG_BYREF_TO_BYVAL_U2;
230 break;
231 default:
232 g_assert_not_reached ();
233 break;
235 } else {
236 arg_marshal = GSHAREDVT_ARG_BYREF_TO_BYVAL;
238 } else {
239 nsrc = get_arg_slots (ainfo, &src);
241 if (ainfo2->storage == RegTypeGSharedVtInReg) {
242 /* Pass the address of the first src slot in a reg */
243 arg_marshal = GSHAREDVT_ARG_BYVAL_TO_BYREF;
244 ndst = 1;
245 dst = g_new0 (int, 1);
246 dst [0] = map_reg (ainfo2->reg);
247 } else if (ainfo2->storage == RegTypeGSharedVtOnStack) {
248 /* Pass the address of the first src slot in a stack slot */
249 arg_marshal = GSHAREDVT_ARG_BYVAL_TO_BYREF;
250 ndst = 1;
251 dst = g_new0 (int, 1);
252 dst [0] = map_stack_slot (ainfo2->offset / sizeof (target_mgreg_t));
253 } else {
254 ndst = get_arg_slots (ainfo2, &dst);
256 if (nsrc)
257 src [0] |= (arg_marshal << 24);
258 nslots = MIN (nsrc, ndst);
260 for (i = 0; i < nslots; ++i)
261 add_to_map (map, src [i], dst [i]);
263 g_free (src);
264 g_free (dst);
267 info = mono_domain_alloc0 (mono_domain_get (), sizeof (GSharedVtCallInfo) + (map->len * sizeof (int)));
268 info->addr = addr;
269 info->stack_usage = callee_cinfo->stack_usage;
270 info->ret_marshal = GSHAREDVT_RET_NONE;
271 info->gsharedvt_in = gsharedvt_in ? 1 : 0;
272 info->vret_slot = -1;
273 info->calli = calli;
274 if (var_ret) {
275 g_assert (gcinfo->ret.storage == RegTypeStructByAddr);
276 info->vret_arg_reg = gcinfo->ret.reg;
277 } else {
278 info->vret_arg_reg = -1;
280 info->vcall_offset = vcall_offset;
281 info->map_count = map->len / 2;
282 for (i = 0; i < map->len; ++i)
283 info->map [i] = GPOINTER_TO_UINT (g_ptr_array_index (map, i));
284 g_ptr_array_free (map, TRUE);
286 /* Compute return value marshalling */
287 if (var_ret) {
288 switch (cinfo->ret.storage) {
289 case RegTypeGeneral:
290 if (gsharedvt_in && !sig->ret->byref && sig->ret->type == MONO_TYPE_I1)
291 info->ret_marshal = GSHAREDVT_RET_I1;
292 else if (gsharedvt_in && !sig->ret->byref && (sig->ret->type == MONO_TYPE_U1 || sig->ret->type == MONO_TYPE_BOOLEAN))
293 info->ret_marshal = GSHAREDVT_RET_U1;
294 else if (gsharedvt_in && !sig->ret->byref && sig->ret->type == MONO_TYPE_I2)
295 info->ret_marshal = GSHAREDVT_RET_I2;
296 else if (gsharedvt_in && !sig->ret->byref && (sig->ret->type == MONO_TYPE_U2 || sig->ret->type == MONO_TYPE_CHAR))
297 info->ret_marshal = GSHAREDVT_RET_U2;
298 else
299 info->ret_marshal = GSHAREDVT_RET_IREG;
300 break;
301 case RegTypeIRegPair:
302 info->ret_marshal = GSHAREDVT_RET_IREGS;
303 break;
304 case RegTypeFP:
305 if (mono_arm_is_hard_float ()) {
306 if (cinfo->ret.size == 4)
307 info->ret_marshal = GSHAREDVT_RET_VFP_R4;
308 else
309 info->ret_marshal = GSHAREDVT_RET_VFP_R8;
310 } else {
311 if (cinfo->ret.size == sizeof (target_mgreg_t))
312 info->ret_marshal = GSHAREDVT_RET_IREG;
313 else
314 info->ret_marshal = GSHAREDVT_RET_IREGS;
316 break;
317 case RegTypeStructByAddr:
318 info->ret_marshal = GSHAREDVT_RET_NONE;
319 break;
320 default:
321 g_assert_not_reached ();
325 if (gsharedvt_in && var_ret && caller_cinfo->ret.storage != RegTypeStructByAddr) {
326 /* Allocate stack space for the return value */
327 info->vret_slot = map_stack_slot (info->stack_usage / sizeof (target_mgreg_t));
328 info->stack_usage += mono_type_stack_size_internal (normal_sig->ret, NULL, FALSE) + sizeof (target_mgreg_t);
331 info->stack_usage = ALIGN_TO (info->stack_usage, MONO_ARCH_FRAME_ALIGNMENT);
332 info->caller_cinfo = caller_cinfo;
333 info->callee_cinfo = callee_cinfo;
334 info->have_fregs = have_fregs;
336 return info;
339 #endif