3 * gsharedvt support code for x86
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.
13 #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
20 mono_arch_gsharedvt_sig_supported (MonoMethodSignature
*sig
)
23 if (sig->ret && is_variable_size (sig->ret))
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.
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
;
43 gboolean var_ret
= FALSE
;
44 CallInfo
*cinfo
, *gcinfo
;
45 MonoMethodSignature
*sig
, *gsig
;
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
);
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 */
71 gcinfo
= 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
87 * The stack looks like this:
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
) {
99 * This handles the case when the method returns a normal vtype, and when it returns a type arg, and its instantiated
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
];
111 switch (ainfo
->storage
) {
113 if (ainfo2
->storage
== ArgOnStack
) {
114 nslots
= callee_cinfo
->args
[i
].nslots
;
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
))));
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
))));
125 if (ainfo2
->storage
== ArgOnStack
) {
126 nslots
= cinfo
->args
[i
].nslots
;
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
));
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
))));
142 info
= mono_domain_alloc0 (mono_domain_get (), sizeof (GSharedVtCallInfo
) + (map
->len
* sizeof (int)));
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;
150 info
->vret_arg_slot
= gcinfo
->vret_arg_offset
/ sizeof (target_mgreg_t
);
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 */
161 switch (cinfo
->ret
.storage
) {
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
;
174 info
->ret_marshal
= GSHAREDVT_RET_IREG
;
176 case ArgOnDoubleFpStack
:
177 info
->ret_marshal
= GSHAREDVT_RET_DOUBLE_FPSTACK
;
179 case ArgOnFloatFpStack
:
180 info
->ret_marshal
= GSHAREDVT_RET_FLOAT_FPSTACK
;
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
;
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
);
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
);