[interp] Fix interp logging (#17636)
[mono-project.git] / mono / mini / mini-arm64-gsharedvt.c
blob676890244646632373c09377b45a369924a1c6b0
1 /**
2 * \file
3 * gsharedvt support code for arm64
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"
12 #include "mini-arm64.h"
13 #include "mini-arm64-gsharedvt.h"
14 #include "aot-runtime.h"
17 * GSHAREDVT
19 #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
21 void
22 mono_arm_gsharedvt_init (void)
26 gboolean
27 mono_arch_gsharedvt_sig_supported (MonoMethodSignature *sig)
30 if (sig->ret && is_variable_size (sig->ret))
31 return FALSE;
33 return TRUE;
36 static void
37 add_to_map (GPtrArray *map, int src, int dst)
39 g_ptr_array_add (map, GUINT_TO_POINTER (src));
40 g_ptr_array_add (map, GUINT_TO_POINTER (dst));
44 * Slot mapping:
45 * 0..8 - r0..r8
46 * 9..16 - d0..d7
47 * 17.. - stack slots
50 static int
51 map_reg (int reg)
53 return reg;
56 static int
57 map_freg (int reg)
59 return reg + NUM_GSHAREDVT_ARG_GREGS;
62 static int
63 map_stack_slot (int slot)
65 return slot + NUM_GSHAREDVT_ARG_GREGS + NUM_GSHAREDVT_ARG_FREGS;
68 static int
69 get_arg_slots (ArgInfo *ainfo, int **out_slots)
71 int sreg = ainfo->reg;
72 int sslot = ainfo->offset / 8;
73 int *src = NULL;
74 int i, nsrc;
76 switch (ainfo->storage) {
77 case ArgInIReg:
78 case ArgVtypeByRef:
79 nsrc = 1;
80 src = g_malloc (nsrc * sizeof (int));
81 src [0] = map_reg (sreg);
82 break;
83 case ArgVtypeByRefOnStack:
84 nsrc = 1;
85 src = g_malloc (nsrc * sizeof (int));
86 src [0] = map_stack_slot (sslot);
87 break;
88 case ArgInFReg:
89 case ArgInFRegR4:
90 nsrc = 1;
91 src = g_malloc (nsrc * sizeof (int));
92 src [0] = map_freg (sreg);
93 break;
94 case ArgHFA:
95 nsrc = ainfo->nregs;
96 src = g_malloc (nsrc * sizeof (int));
97 for (i = 0; i < ainfo->nregs; ++i)
98 src [i] = map_freg (sreg + i);
99 break;
100 case ArgVtypeInIRegs:
101 nsrc = ainfo->nregs;
102 src = g_malloc (nsrc * sizeof (int));
103 for (i = 0; i < ainfo->nregs; ++i)
104 src [i] = map_reg (sreg + i);
105 break;
106 case ArgOnStack:
107 case ArgOnStackR4:
108 case ArgOnStackR8:
109 nsrc = 1;
110 src = g_malloc (nsrc * sizeof (int));
111 src [0] = map_stack_slot (sslot);
112 break;
113 case ArgVtypeOnStack:
114 nsrc = ainfo->size / 8;
115 src = g_malloc (nsrc * sizeof (int));
116 for (i = 0; i < nsrc; ++i)
117 src [i] = map_stack_slot (sslot + i);
118 break;
119 default:
120 NOT_IMPLEMENTED;
121 break;
124 *out_slots = src;
125 return nsrc;
129 * mono_arch_get_gsharedvt_call_info:
131 * See mini-x86.c for documentation.
133 gpointer
134 mono_arch_get_gsharedvt_call_info (gpointer addr, MonoMethodSignature *normal_sig, MonoMethodSignature *gsharedvt_sig, gboolean gsharedvt_in, gint32 vcall_offset, gboolean calli)
136 GSharedVtCallInfo *info;
137 CallInfo *caller_cinfo, *callee_cinfo;
138 MonoMethodSignature *caller_sig, *callee_sig;
139 int aindex, i;
140 gboolean var_ret = FALSE;
141 CallInfo *cinfo, *gcinfo;
142 MonoMethodSignature *sig, *gsig;
143 GPtrArray *map;
145 if (gsharedvt_in) {
146 caller_sig = normal_sig;
147 callee_sig = gsharedvt_sig;
148 caller_cinfo = mono_arch_get_call_info (NULL, caller_sig);
149 callee_cinfo = mono_arch_get_call_info (NULL, callee_sig);
150 } else {
151 callee_sig = normal_sig;
152 caller_sig = gsharedvt_sig;
153 callee_cinfo = mono_arch_get_call_info (NULL, callee_sig);
154 caller_cinfo = mono_arch_get_call_info (NULL, caller_sig);
158 * If GSHAREDVT_IN is true, this means we are transitioning from normal to gsharedvt code. The caller uses the
159 * normal call signature, while the callee uses the gsharedvt signature.
160 * If GSHAREDVT_IN is false, its the other way around.
163 /* sig/cinfo describes the normal call, while gsig/gcinfo describes the gsharedvt call */
164 if (gsharedvt_in) {
165 sig = caller_sig;
166 gsig = callee_sig;
167 cinfo = caller_cinfo;
168 gcinfo = callee_cinfo;
169 } else {
170 sig = callee_sig;
171 gsig = caller_sig;
172 cinfo = callee_cinfo;
173 gcinfo = caller_cinfo;
176 if (gcinfo->ret.gsharedvt) {
178 * The return type is gsharedvt
180 var_ret = TRUE;
184 * The stack looks like this:
185 * <arguments>
186 * <trampoline frame>
187 * <call area>
188 * We have to map the stack slots in <arguments> to the stack slots in <call area>.
190 map = g_ptr_array_new ();
192 for (aindex = 0; aindex < cinfo->nargs; ++aindex) {
193 ArgInfo *ainfo = &caller_cinfo->args [aindex];
194 ArgInfo *ainfo2 = &callee_cinfo->args [aindex];
195 int *src = NULL, *dst = NULL;
196 int nsrc, ndst, nslots, src_slot, arg_marshal;
199 * The src descriptor looks like this:
200 * - 6 bits src slot
201 * - 12 bits number of slots
202 * - 4 bits marshal type (GSHAREDVT_ARG_...)
203 * - 4 bits size/sign descriptor (GSHAREDVT_ARG_SIZE)
204 * - 4 bits offset inside stack slots
206 arg_marshal = GSHAREDVT_ARG_NONE;
208 if (ainfo->gsharedvt) {
209 /* Pass the value whose address is received in a reg by value */
210 g_assert (!ainfo2->gsharedvt);
211 ndst = get_arg_slots (ainfo2, &dst);
212 nsrc = 1;
213 src = g_new0 (int, 1);
214 if (ainfo->storage == ArgVtypeByRef)
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 < 64);
220 src [0] = (ndst << 6) | src_slot;
221 if (ainfo2->storage == ArgHFA && ainfo2->esize == 4)
222 arg_marshal = GSHAREDVT_ARG_BYREF_TO_BYVAL_HFAR4;
223 else if (ainfo2->storage == ArgVtypeByRef || ainfo2->storage == ArgVtypeByRefOnStack)
224 arg_marshal = GSHAREDVT_ARG_BYREF_TO_BYREF;
225 else
226 arg_marshal = GSHAREDVT_ARG_BYREF_TO_BYVAL;
227 } else {
228 nsrc = get_arg_slots (ainfo, &src);
230 if (ainfo2->storage == ArgVtypeByRef && ainfo2->gsharedvt) {
231 /* Pass the address of the first src slot in a reg */
232 if (ainfo->storage != ArgVtypeByRef) {
233 if (ainfo->storage == ArgHFA && ainfo->esize == 4) {
234 arg_marshal = GSHAREDVT_ARG_BYVAL_TO_BYREF_HFAR4;
235 g_assert (src [0] < 64);
236 g_assert (nsrc < 256);
237 src [0] |= (nsrc << 6);
238 } else {
239 arg_marshal = GSHAREDVT_ARG_BYVAL_TO_BYREF;
242 ndst = 1;
243 dst = g_new0 (int, 1);
244 dst [0] = map_reg (ainfo2->reg);
245 } else if (ainfo2->storage == ArgVtypeByRefOnStack && ainfo2->gsharedvt) {
246 /* Pass the address of the first src slot in a stack slot */
247 if (ainfo->storage != ArgVtypeByRef)
248 arg_marshal = GSHAREDVT_ARG_BYVAL_TO_BYREF;
249 ndst = 1;
250 dst = g_new0 (int, 1);
251 dst [0] = map_stack_slot (ainfo2->offset / sizeof (target_mgreg_t));
252 } else {
253 ndst = get_arg_slots (ainfo2, &dst);
255 if (nsrc)
256 src [0] |= (arg_marshal << 18);
257 if ((ainfo->storage == ArgOnStack || ainfo->storage == ArgOnStackR4) && ainfo->slot_size != 8) {
258 GSharedVtArgSize arg_size = GSHAREDVT_ARG_SIZE_NONE;
261 * On IOS, stack arguments smaller than 8 bytes can
262 * share a stack slot. Encode this information into
263 * the descriptor.
265 switch (ainfo->slot_size) {
266 case 1:
267 arg_size = ainfo->sign ? GSHAREDVT_ARG_SIZE_I1 : GSHAREDVT_ARG_SIZE_U1;
268 break;
269 case 2:
270 arg_size = ainfo->sign ? GSHAREDVT_ARG_SIZE_I2 : GSHAREDVT_ARG_SIZE_U2;
271 break;
272 case 4:
273 arg_size = ainfo->sign ? GSHAREDVT_ARG_SIZE_I4 : GSHAREDVT_ARG_SIZE_U4;
274 break;
275 default:
276 NOT_IMPLEMENTED;
277 break;
279 /* Encode the size/sign */
280 src [0] |= (arg_size << 22);
281 /* Encode the offset inside the stack slot */
282 src [0] |= ((ainfo->offset % 8) << 26);
283 if (ainfo2->storage == ArgOnStack || ainfo2->storage == ArgOnStackR4)
284 dst [0] |= ((ainfo2->offset % 8) << 26);
285 } else if (ainfo2->storage == ArgOnStack && ainfo2->slot_size != 8) {
286 /* The caller passes in an address, need to store it into a stack slot */
288 GSharedVtArgSize arg_size = GSHAREDVT_ARG_SIZE_NONE;
289 switch (ainfo2->slot_size) {
290 case 1:
291 arg_size = ainfo2->sign ? GSHAREDVT_ARG_SIZE_I1 : GSHAREDVT_ARG_SIZE_U1;
292 break;
293 case 2:
294 arg_size = ainfo2->sign ? GSHAREDVT_ARG_SIZE_I2 : GSHAREDVT_ARG_SIZE_U2;
295 break;
296 case 4:
297 arg_size = ainfo2->sign ? GSHAREDVT_ARG_SIZE_I4 : GSHAREDVT_ARG_SIZE_U4;
298 break;
299 default:
300 NOT_IMPLEMENTED;
301 break;
303 /* Encode the size/sign */
304 src [0] |= (arg_size << 22);
305 /* Encode the offset inside the stack slot */
306 dst [0] |= ((ainfo2->offset % 8) << 26);
308 nslots = MIN (nsrc, ndst);
310 for (i = 0; i < nslots; ++i)
311 add_to_map (map, src [i], dst [i]);
313 g_free (src);
314 g_free (dst);
317 if (cinfo->ret.storage == ArgVtypeByRef) {
318 /* Both the caller and the callee pass the vtype ret address in r8 */
319 g_assert (cinfo->ret.storage == gcinfo->ret.storage);
320 add_to_map (map, map_reg (ARMREG_R8), map_reg (ARMREG_R8));
323 info = mono_domain_alloc0 (mono_domain_get (), sizeof (GSharedVtCallInfo) + (map->len * sizeof (int)));
324 info->addr = addr;
325 info->stack_usage = callee_cinfo->stack_usage;
326 info->ret_marshal = GSHAREDVT_RET_NONE;
327 info->gsharedvt_in = gsharedvt_in ? 1 : 0;
328 info->vret_slot = -1;
329 info->calli = calli;
331 if (var_ret) {
332 g_assert (gcinfo->ret.gsharedvt);
333 info->vret_arg_reg = map_reg (ARMREG_R8);
334 } else {
335 info->vret_arg_reg = -1;
338 info->vcall_offset = vcall_offset;
339 info->map_count = map->len / 2;
340 for (i = 0; i < map->len; ++i)
341 info->map [i] = GPOINTER_TO_UINT (g_ptr_array_index (map, i));
342 g_ptr_array_free (map, TRUE);
344 /* Compute return value marshalling */
345 if (var_ret) {
346 switch (cinfo->ret.storage) {
347 case ArgInIReg:
348 if (!gsharedvt_in || sig->ret->byref) {
349 info->ret_marshal = GSHAREDVT_RET_I8;
350 } else {
351 MonoType *rtype = mini_get_underlying_type (sig->ret);
353 switch (rtype->type) {
354 case MONO_TYPE_I1:
355 info->ret_marshal = GSHAREDVT_RET_I1;
356 break;
357 case MONO_TYPE_U1:
358 info->ret_marshal = GSHAREDVT_RET_U1;
359 break;
360 case MONO_TYPE_I2:
361 info->ret_marshal = GSHAREDVT_RET_I2;
362 break;
363 case MONO_TYPE_U2:
364 info->ret_marshal = GSHAREDVT_RET_U2;
365 break;
366 case MONO_TYPE_I4:
367 info->ret_marshal = GSHAREDVT_RET_I4;
368 break;
369 case MONO_TYPE_U4:
370 info->ret_marshal = GSHAREDVT_RET_U4;
371 break;
372 default:
373 info->ret_marshal = GSHAREDVT_RET_I8;
374 break;
377 break;
378 case ArgInFReg:
379 info->ret_marshal = GSHAREDVT_RET_R8;
380 break;
381 case ArgInFRegR4:
382 info->ret_marshal = GSHAREDVT_RET_R4;
383 break;
384 case ArgVtypeInIRegs:
385 info->ret_marshal = GSHAREDVT_RET_IREGS_1 - 1 + cinfo->ret.nregs;
386 break;
387 case ArgHFA:
388 if (cinfo->ret.esize == 4)
389 info->ret_marshal = GSHAREDVT_RET_HFAR4_1 - 1 + cinfo->ret.nregs;
390 else
391 info->ret_marshal = GSHAREDVT_RET_HFAR8_1 - 1 + cinfo->ret.nregs;
392 break;
393 case ArgVtypeByRef:
394 /* No conversion needed */
395 break;
396 default:
397 g_assert_not_reached ();
401 if (gsharedvt_in && var_ret && cinfo->ret.storage != ArgVtypeByRef) {
402 /* Allocate stack space for the return value */
403 info->vret_slot = map_stack_slot (info->stack_usage / sizeof (target_mgreg_t));
404 info->stack_usage += mono_type_stack_size_internal (normal_sig->ret, NULL, FALSE) + sizeof (target_mgreg_t);
407 info->stack_usage = ALIGN_TO (info->stack_usage, MONO_ARCH_FRAME_ALIGNMENT);
409 return info;
412 #else
414 void
415 mono_arm_gsharedvt_init (void)
419 #endif /* MONO_ARCH_GSHAREDVT_SUPPORTED */