[jit] Add arm64 backend and gsharedvt code.
[mono.git] / mono / mini / tramp-arm64-gsharedvt.c
1 /*
2  * tramp-arm64-gsharedvt.c: gsharedvt support code for arm64
3  *
4  * Authors:
5  *   Zoltan Varga <vargaz@gmail.com>
6  *
7  * Copyright 2013 Xamarin, Inc (http://www.xamarin.com)
8  * Licensed under the MIT license. See LICENSE file in the project root for full license information.
9  */
10 #include <mono/metadata/abi-details.h>
11
12 #include "mini.h"
13 #include "mini-arm64.h"
14 #include "mini-arm64-gsharedvt.h"
15
16 /*
17  * GSHAREDVT
18  */
19 #ifdef MONO_ARCH_GSHARED_SUPPORTED
20
21 /*
22  * mono_arch_get_gsharedvt_arg_trampoline:
23  *
24  *   See tramp-x86.c for documentation.
25  */
26 gpointer
27 mono_arch_get_gsharedvt_arg_trampoline (MonoDomain *domain, gpointer arg, gpointer addr)
28 {
29         guint8 *code, *buf;
30         int buf_len = 40;
31
32         /*
33          * Return a trampoline which calls ADDR passing in ARG.
34          * Pass the argument in ip1, clobbering ip0.
35          */
36         buf = code = mono_global_codeman_reserve (buf_len);
37
38         code = mono_arm_emit_imm64 (code, ARMREG_IP1, (guint64)arg);
39         code = mono_arm_emit_imm64 (code, ARMREG_IP0, (guint64)addr);
40
41         arm_brx (code, ARMREG_IP0);
42
43         g_assert ((code - buf) < buf_len);
44         mono_arch_flush_icache (buf, code - buf);
45
46         return buf;
47 }
48
49 gpointer
50 mono_arm_start_gsharedvt_call (GSharedVtCallInfo *info, gpointer *caller, gpointer *callee, gpointer mrgctx_reg)
51 {
52         int i;
53
54         /* Set vtype ret arg */
55         if (info->vret_slot != -1) {
56                 g_assert (info->vret_slot);
57                 callee [info->vret_arg_reg] = &callee [info->vret_slot];
58         }
59
60         for (i = 0; i < info->map_count; ++i) {
61                 int src = info->map [i * 2];
62                 int dst = info->map [(i * 2) + 1];
63                 int arg_marshal = (src >> 18) & 0xf;
64                 int arg_size = (src >> 22) & 0xf;
65
66                 if (G_UNLIKELY (arg_size)) {
67                         int src_offset = (src >> 26) & 0xf;
68                         int dst_offset = (dst >> 26) & 0xf;
69                         int src_slot, dst_slot;
70                         guint8 *src_ptr, *dst_ptr;
71
72                         /*
73                          * Argument passed in part of a stack slot on ios.
74                          * src_offset/dst_offset is the offset within the stack slot.
75                          */
76                         switch (arg_marshal) {
77                         case GSHAREDVT_ARG_NONE:
78                                 src_slot = src & 0xffff;
79                                 dst_slot = dst & 0xffff;
80                                 src_ptr = (guint8*)(caller + src_slot) + src_offset;
81                                 dst_ptr = (guint8*)(callee + dst_slot) + dst_offset;
82                                 break;
83                         case GSHAREDVT_ARG_BYREF_TO_BYVAL:
84                                 src_slot = src & 0x3f;
85                                 dst_slot = dst & 0xffff;
86                                 src_ptr = caller [src_slot];
87                                 dst_ptr = (guint8*)(callee + dst_slot) + dst_offset;
88                                 break;
89                         case GSHAREDVT_ARG_BYVAL_TO_BYREF_HFAR4:
90                         case GSHAREDVT_ARG_BYREF_TO_BYVAL_HFAR4:
91                         case GSHAREDVT_ARG_BYREF_TO_BYREF:
92                                 g_assert_not_reached ();
93                                 break;
94                         default:
95                                 NOT_IMPLEMENTED;
96                                 break;
97                         }
98
99                         switch (arg_size) {
100                         case GSHAREDVT_ARG_SIZE_I1:
101                                 *(gint8*)dst_ptr = *(gint8*)src_ptr;
102                                 break;
103                         case GSHAREDVT_ARG_SIZE_U1:
104                                 *(guint8*)dst_ptr = *(guint8*)src_ptr;
105                                 break;
106                         case GSHAREDVT_ARG_SIZE_I2:
107                                 *(gint16*)dst_ptr = *(gint16*)src_ptr;
108                                 break;
109                         case GSHAREDVT_ARG_SIZE_U2:
110                                 *(guint16*)dst_ptr = *(guint16*)src_ptr;
111                                 break;
112                         case GSHAREDVT_ARG_SIZE_I4:
113                                 *(gint32*)dst_ptr = *(gint32*)src_ptr;
114                                 break;
115                         case GSHAREDVT_ARG_SIZE_U4:
116                                 *(guint32*)dst_ptr = *(guint32*)src_ptr;
117                                 break;
118                         default:
119                                 g_assert_not_reached ();
120                         }
121                         continue;
122                 }
123
124                 switch (arg_marshal) {
125                 case GSHAREDVT_ARG_NONE:
126                         callee [dst] = caller [src];
127                         break;
128                 case GSHAREDVT_ARG_BYVAL_TO_BYREF:
129                         /* gsharedvt argument passed by addr in reg/stack slot */
130                         src = src & 0x3f;
131                         callee [dst] = caller + src;
132                         break;
133                 case GSHAREDVT_ARG_BYVAL_TO_BYREF_HFAR4: {
134                         int nslots = (src >> 6) & 0xff;
135                         int src_slot = src & 0x3f;
136                         int j;
137                         float *dst_arr = (float*)(caller + src_slot);
138
139                         /* The r4 hfa is in separate slots, need to compress them together in place */
140                         for (j = 0; j < nslots; ++j)
141                                 dst_arr [j] = *(float*)(caller + src_slot + j);
142
143                         callee [dst] = caller + src_slot;
144                         break;
145                 }
146                 case GSHAREDVT_ARG_BYREF_TO_BYVAL: {
147                         int nslots = (src >> 6) & 0xff;
148                         int src_slot = src & 0x3f;
149                         int j;
150                         gpointer *addr = caller [src_slot];
151
152                         for (j = 0; j < nslots; ++j)
153                                 callee [dst + j] = addr [j];
154                         break;
155                 }
156                 case GSHAREDVT_ARG_BYREF_TO_BYVAL_HFAR4: {
157                         int nslots = (src >> 6) & 0xff;
158                         int src_slot = src & 0x3f;
159                         int j;
160                         guint32 *addr = (guint32*)(caller [src_slot]);
161
162                         /* addr points to an array of floats, need to load them to registers */
163                         for (j = 0; j < nslots; ++j)
164                                 callee [dst + j] = GUINT_TO_POINTER (addr [j]);
165                         break;
166                 }
167                 case GSHAREDVT_ARG_BYREF_TO_BYREF: {
168                         int src_slot = src & 0x3f;
169
170                         callee [dst] = caller [src_slot];
171                         break;
172                 }
173                 default:
174                         g_assert_not_reached ();
175                         break;
176                 }
177         }
178
179         if (info->vcall_offset != -1) {
180                 MonoObject *this_obj = caller [0];
181
182                 if (G_UNLIKELY (!this_obj))
183                         return NULL;
184                 if (info->vcall_offset == MONO_GSHAREDVT_DEL_INVOKE_VT_OFFSET)
185                         /* delegate invoke */
186                         return ((MonoDelegate*)this_obj)->invoke_impl;
187                 else
188                         return *(gpointer*)((char*)this_obj->vtable + info->vcall_offset);
189         } else if (info->calli) {
190                 /* The address to call is passed in the mrgctx reg */
191                 return mrgctx_reg;
192         } else {
193                 return info->addr;
194         }
195 }
196
197 #ifndef DISABLE_JIT
198
199 gpointer
200 mono_arch_get_gsharedvt_trampoline (MonoTrampInfo **info, gboolean aot)
201 {
202         guint8 *code, *buf;
203         int buf_len, cfa_offset;
204         GSList *unwind_ops = NULL;
205         MonoJumpInfo *ji = NULL;
206         guint8 *br_out, *br [64], *br_ret [64], *bcc_ret [64];
207         int i, n_arg_regs, n_arg_fregs, offset, arg_reg, info_offset, rgctx_arg_reg_offset;
208         int caller_reg_area_offset, callee_reg_area_offset, callee_stack_area_offset;
209         int br_ret_index, bcc_ret_index;
210
211         buf_len = 2048;
212         buf = code = mono_global_codeman_reserve (buf_len);
213
214         /*
215          * We are being called by an gsharedvt arg trampoline, the info argument is in IP1.
216          */
217         arg_reg = ARMREG_IP1;
218         n_arg_regs = NUM_GSHAREDVT_ARG_GREGS;
219         n_arg_fregs = NUM_GSHAREDVT_ARG_FREGS;
220
221         /* Compute stack frame size and offsets */
222         offset = 0;
223         /* frame block */
224         offset += 2 * 8;
225         /* info argument */
226         info_offset = offset;
227         offset += 8;
228         /* saved rgctx */
229         rgctx_arg_reg_offset = offset;
230         offset += 8;
231         /* alignment */
232         offset += 8;
233         /* argument regs */
234         caller_reg_area_offset = offset;
235         offset += (n_arg_regs + n_arg_fregs) * 8;
236
237         /* We need the argument regs to be saved at the top of the frame */
238         g_assert (offset % MONO_ARCH_FRAME_ALIGNMENT == 0);
239
240         cfa_offset = offset;
241
242         /* Setup frame */
243         arm_stpx_pre (code, ARMREG_FP, ARMREG_LR, ARMREG_SP, -cfa_offset);
244         mono_add_unwind_op_def_cfa (unwind_ops, code, buf, ARMREG_SP, cfa_offset);
245         mono_add_unwind_op_offset (unwind_ops, code, buf, ARMREG_FP, -cfa_offset + 0);
246         mono_add_unwind_op_offset (unwind_ops, code, buf, ARMREG_LR, -cfa_offset + 8);
247         arm_movspx (code, ARMREG_FP, ARMREG_SP);
248         mono_add_unwind_op_def_cfa_reg (unwind_ops, code, buf, ARMREG_FP);
249
250         /* Save info argument */
251         arm_strx (code, arg_reg, ARMREG_FP, info_offset);
252
253         /* Save rgxctx */
254         arm_strx (code, MONO_ARCH_RGCTX_REG, ARMREG_FP, rgctx_arg_reg_offset);
255
256         /* Save argument regs below the stack arguments */
257         for (i = 0; i < n_arg_regs; ++i)
258                 arm_strx (code, i, ARMREG_SP, caller_reg_area_offset + (i * 8));
259         // FIXME: Only do this if fp regs are used
260         for (i = 0; i < n_arg_fregs; ++i)
261                 arm_strfpx (code, i, ARMREG_SP, caller_reg_area_offset + ((n_arg_regs + i) * 8));
262
263         /* Allocate callee area */
264         arm_ldrw (code, ARMREG_IP0, arg_reg, MONO_STRUCT_OFFSET (GSharedVtCallInfo, stack_usage));
265         arm_movspx (code, ARMREG_LR, ARMREG_SP);
266         arm_subx (code, ARMREG_LR, ARMREG_LR, ARMREG_IP0);
267         arm_movspx (code, ARMREG_SP, ARMREG_LR);
268         /* Allocate callee register area just below the callee area so it can be accessed from start_gsharedvt_call using negative offsets */
269         /* The + 8 is for alignment */
270         callee_reg_area_offset = 8;
271         callee_stack_area_offset = callee_reg_area_offset + (n_arg_regs * sizeof (gpointer));
272         arm_subx_imm (code, ARMREG_SP, ARMREG_SP, ((n_arg_regs + n_arg_fregs) * sizeof (gpointer)) + 8);
273
274         /*
275          * The stack now looks like this:
276          * <caller frame>
277          * <saved r0-r8>
278          * <our frame>
279          * <saved fp, lr> <- fp
280          * <callee area> <- sp
281          */
282
283         /* Call start_gsharedvt_call () */
284         /* arg1 == info */
285         arm_ldrx (code, ARMREG_R0, ARMREG_FP, info_offset);
286         /* arg2 = caller stack area */
287         arm_addx_imm (code, ARMREG_R1, ARMREG_FP, caller_reg_area_offset);
288         /* arg3 == callee stack area */
289         arm_addx_imm (code, ARMREG_R2, ARMREG_SP, callee_reg_area_offset);
290         /* arg4 = mrgctx reg */
291         arm_ldrx (code, ARMREG_R3, ARMREG_FP, rgctx_arg_reg_offset);
292
293         if (aot)
294                 code = mono_arm_emit_aotconst (&ji, code, buf, ARMREG_IP0, MONO_PATCH_INFO_JIT_ICALL_ADDR, "mono_arm_start_gsharedvt_call");
295         else
296                 code = mono_arm_emit_imm64 (code, ARMREG_IP0, (guint64)mono_arm_start_gsharedvt_call);
297         arm_blrx (code, ARMREG_IP0);
298
299         /* Make the real method call */
300         /* R0 contains the addr to call */
301         arm_movx (code, ARMREG_IP1, ARMREG_R0);
302         /* Load rgxctx */
303         arm_ldrx (code, MONO_ARCH_RGCTX_REG, ARMREG_FP, rgctx_arg_reg_offset);
304         /* Load argument registers */
305         // FIXME:
306         for (i = 0; i < n_arg_regs; ++i)
307                 arm_ldrx (code, i, ARMREG_SP, callee_reg_area_offset + (i * 8));
308         // FIXME: Only do this if needed
309         for (i = 0; i < n_arg_fregs; ++i)
310                 arm_ldrfpx (code, i, ARMREG_SP, callee_reg_area_offset + ((n_arg_regs + i) * 8));
311         /* Clear callee reg area */
312         arm_addx_imm (code, ARMREG_SP, ARMREG_SP, ((n_arg_regs + n_arg_fregs) * sizeof (gpointer)) + 8);
313         /* Make the call */
314         arm_blrx (code, ARMREG_IP1);
315
316         br_ret_index = 0;
317         bcc_ret_index = 0;
318
319         // FIXME: Use a switch
320         /* Branch between IN/OUT cases */
321         arm_ldrx (code, ARMREG_IP1, ARMREG_FP, info_offset);
322         arm_ldrw (code, ARMREG_IP1, ARMREG_IP1, MONO_STRUCT_OFFSET (GSharedVtCallInfo, gsharedvt_in));
323         br_out = code;
324         arm_cbzx (code, ARMREG_IP1, 0);
325
326         /* IN CASE */
327
328         /* IP1 == return marshalling type */
329         arm_ldrx (code, ARMREG_IP1, ARMREG_FP, info_offset);
330         arm_ldrw (code, ARMREG_IP1, ARMREG_IP1, MONO_STRUCT_OFFSET (GSharedVtCallInfo, ret_marshal));
331
332         /* Continue if no marshalling required */
333         // FIXME: Use cmpx_imm
334         code = mono_arm_emit_imm64 (code, ARMREG_IP0, GSHAREDVT_RET_NONE);
335         arm_cmpx (code, ARMREG_IP0, ARMREG_IP1);
336         bcc_ret [bcc_ret_index ++] = code;
337         arm_bcc (code, ARMCOND_EQ, 0);
338
339         /* Compute vret area address in LR */
340         arm_ldrx (code, ARMREG_LR, ARMREG_FP, info_offset);
341         arm_ldrw (code, ARMREG_LR, ARMREG_LR, MONO_STRUCT_OFFSET (GSharedVtCallInfo, vret_slot));
342         arm_subx_imm (code, ARMREG_LR, ARMREG_LR, n_arg_regs + n_arg_fregs);
343         arm_lslx (code, ARMREG_LR, ARMREG_LR, 3);
344         arm_movspx (code, ARMREG_IP0, ARMREG_SP);
345         arm_addx (code, ARMREG_LR, ARMREG_IP0, ARMREG_LR);
346
347         /* Branch to specific marshalling code */
348         for (i = GSHAREDVT_RET_NONE; i < GSHAREDVT_RET_NUM; ++i) {
349                 code = mono_arm_emit_imm64 (code, ARMREG_IP0, i);
350                 arm_cmpx (code, ARMREG_IP0, ARMREG_IP1);
351                 br [i] = code;
352                 arm_bcc (code, ARMCOND_EQ, 0);
353         }
354
355         arm_brk (code, 0);
356
357         /*
358          * The address of the return value area is in LR, have to load it into
359          * registers.
360          */
361         for (i = GSHAREDVT_RET_NONE; i < GSHAREDVT_RET_NUM; ++i) {
362                 mono_arm_patch (br [i], code, MONO_R_ARM64_BCC);
363                 switch (i) {
364                 case GSHAREDVT_RET_NONE:
365                         break;
366                 case GSHAREDVT_RET_I8:
367                         arm_ldrx (code, ARMREG_R0, ARMREG_LR, 0);
368                         break;
369                 case GSHAREDVT_RET_I1:
370                         arm_ldrsbx (code, ARMREG_R0, ARMREG_LR, 0);
371                         break;
372                 case GSHAREDVT_RET_U1:
373                         arm_ldrb (code, ARMREG_R0, ARMREG_LR, 0);
374                         break;
375                 case GSHAREDVT_RET_I2:
376                         arm_ldrshx (code, ARMREG_R0, ARMREG_LR, 0);
377                         break;
378                 case GSHAREDVT_RET_U2:
379                         arm_ldrh (code, ARMREG_R0, ARMREG_LR, 0);
380                         break;
381                 case GSHAREDVT_RET_I4:
382                         arm_ldrswx (code, ARMREG_R0, ARMREG_LR, 0);
383                         break;
384                 case GSHAREDVT_RET_U4:
385                         arm_ldrw (code, ARMREG_R0, ARMREG_LR, 0);
386                         break;
387                 case GSHAREDVT_RET_R8:
388                         arm_ldrfpx (code, ARMREG_D0, ARMREG_LR, 0);
389                         break;
390                 case GSHAREDVT_RET_R4:
391                         arm_ldrfpw (code, ARMREG_D0, ARMREG_LR, 0);
392                         break;
393                 case GSHAREDVT_RET_IREGS_1:
394                 case GSHAREDVT_RET_IREGS_2:
395                 case GSHAREDVT_RET_IREGS_3:
396                 case GSHAREDVT_RET_IREGS_4:
397                 case GSHAREDVT_RET_IREGS_5:
398                 case GSHAREDVT_RET_IREGS_6:
399                 case GSHAREDVT_RET_IREGS_7:
400                 case GSHAREDVT_RET_IREGS_8: {
401                         int j;
402
403                         for (j = 0; j < i - GSHAREDVT_RET_IREGS_1 + 1; ++j)
404                                 arm_ldrx (code, j, ARMREG_LR, j * 8);
405                         break;
406                 }
407                 case GSHAREDVT_RET_HFAR8_1:
408                 case GSHAREDVT_RET_HFAR8_2:
409                 case GSHAREDVT_RET_HFAR8_3:
410                 case GSHAREDVT_RET_HFAR8_4: {
411                         int j;
412
413                         for (j = 0; j < i - GSHAREDVT_RET_HFAR8_1 + 1; ++j)
414                                 arm_ldrfpx (code, j, ARMREG_LR, j * 8);
415                         break;
416                 }
417                 case GSHAREDVT_RET_HFAR4_1:
418                 case GSHAREDVT_RET_HFAR4_2:
419                 case GSHAREDVT_RET_HFAR4_3:
420                 case GSHAREDVT_RET_HFAR4_4: {
421                         int j;
422
423                         for (j = 0; j < i - GSHAREDVT_RET_HFAR4_1 + 1; ++j)
424                                 arm_ldrfpw (code, j, ARMREG_LR, j * 4);
425                         break;
426                 }
427                 default:
428                         g_assert_not_reached ();
429                         break;
430                 }
431                 br_ret [br_ret_index ++] = code;
432                 arm_b (code, 0);
433         }
434
435         /* OUT CASE */
436         mono_arm_patch (br_out, code, MONO_R_ARM64_CBZ);
437
438         /* Compute vret area address in LR */
439         arm_ldrx (code, ARMREG_LR, ARMREG_FP, caller_reg_area_offset + (ARMREG_R8 * 8));
440
441         /* IP1 == return marshalling type */
442         arm_ldrx (code, ARMREG_IP1, ARMREG_FP, info_offset);
443         arm_ldrw (code, ARMREG_IP1, ARMREG_IP1, MONO_STRUCT_OFFSET (GSharedVtCallInfo, ret_marshal));
444
445         /* Branch to specific marshalling code */
446         for (i = GSHAREDVT_RET_NONE; i < GSHAREDVT_RET_NUM; ++i) {
447                 code = mono_arm_emit_imm64 (code, ARMREG_IP0, i);
448                 arm_cmpx (code, ARMREG_IP0, ARMREG_IP1);
449                 br [i] = code;
450                 arm_bcc (code, ARMCOND_EQ, 0);
451         }
452
453         /*
454          * The return value is in registers, need to save to the return area passed by the caller in
455          * R8.
456          */
457         for (i = GSHAREDVT_RET_NONE; i < GSHAREDVT_RET_NUM; ++i) {
458                 mono_arm_patch (br [i], code, MONO_R_ARM64_BCC);
459                 switch (i) {
460                 case GSHAREDVT_RET_NONE:
461                         break;
462                 case GSHAREDVT_RET_I8:
463                         arm_strx (code, ARMREG_R0, ARMREG_LR, 0);
464                         break;
465                 case GSHAREDVT_RET_I1:
466                 case GSHAREDVT_RET_U1:
467                         arm_strb (code, ARMREG_R0, ARMREG_LR, 0);
468                         break;
469                 case GSHAREDVT_RET_I2:
470                 case GSHAREDVT_RET_U2:
471                         arm_strh (code, ARMREG_R0, ARMREG_LR, 0);
472                         break;
473                 case GSHAREDVT_RET_I4:
474                 case GSHAREDVT_RET_U4:
475                         arm_strw (code, ARMREG_R0, ARMREG_LR, 0);
476                         break;
477                 case GSHAREDVT_RET_R8:
478                         arm_strfpx (code, ARMREG_D0, ARMREG_LR, 0);
479                         break;
480                 case GSHAREDVT_RET_R4:
481                         arm_strfpw (code, ARMREG_D0, ARMREG_LR, 0);
482                         break;
483                 case GSHAREDVT_RET_IREGS_1:
484                 case GSHAREDVT_RET_IREGS_2:
485                 case GSHAREDVT_RET_IREGS_3:
486                 case GSHAREDVT_RET_IREGS_4:
487                 case GSHAREDVT_RET_IREGS_5:
488                 case GSHAREDVT_RET_IREGS_6:
489                 case GSHAREDVT_RET_IREGS_7:
490                 case GSHAREDVT_RET_IREGS_8: {
491                         int j;
492
493                         for (j = 0; j < i - GSHAREDVT_RET_IREGS_1 + 1; ++j)
494                                 arm_strx (code, j, ARMREG_LR, j * 8);
495                         break;
496                 }
497                 case GSHAREDVT_RET_HFAR8_1:
498                 case GSHAREDVT_RET_HFAR8_2:
499                 case GSHAREDVT_RET_HFAR8_3:
500                 case GSHAREDVT_RET_HFAR8_4: {
501                         int j;
502
503                         for (j = 0; j < i - GSHAREDVT_RET_HFAR8_1 + 1; ++j)
504                                 arm_strfpx (code, j, ARMREG_LR, j * 8);
505                         break;
506                 }
507                 case GSHAREDVT_RET_HFAR4_1:
508                 case GSHAREDVT_RET_HFAR4_2:
509                 case GSHAREDVT_RET_HFAR4_3:
510                 case GSHAREDVT_RET_HFAR4_4: {
511                         int j;
512
513                         for (j = 0; j < i - GSHAREDVT_RET_HFAR4_1 + 1; ++j)
514                                 arm_strfpw (code, j, ARMREG_LR, j * 4);
515                         break;
516                 }
517                 default:
518                         arm_brk (code, i);
519                         break;
520                 }
521                 br_ret [br_ret_index ++] = code;
522                 arm_b (code, 0);
523         }
524
525         arm_brk (code, 0);
526
527         for (i = 0; i < br_ret_index; ++i)
528                 mono_arm_patch (br_ret [i], code, MONO_R_ARM64_B);
529         for (i = 0; i < bcc_ret_index; ++i)
530                 mono_arm_patch (bcc_ret [i], code, MONO_R_ARM64_BCC);
531
532         /* Normal return */
533         arm_movspx (code, ARMREG_SP, ARMREG_FP);
534         arm_ldpx_post (code, ARMREG_FP, ARMREG_LR, ARMREG_SP, offset);
535         arm_retx (code, ARMREG_LR);
536
537         g_assert ((code - buf) < buf_len);
538
539         if (info)
540                 *info = mono_tramp_info_create ("gsharedvt_trampoline", buf, code - buf, ji, unwind_ops);
541
542         mono_arch_flush_icache (buf, code - buf);
543         return buf;
544 }
545
546 #else
547
548 gpointer
549 mono_arch_get_gsharedvt_trampoline (MonoTrampInfo **info, gboolean aot)
550 {
551         g_assert_not_reached ();
552         return NULL;
553 }
554
555 #endif
556
557 #else
558
559 gpointer
560 mono_arch_get_gsharedvt_trampoline (MonoTrampInfo **info, gboolean aot)
561 {
562         if (info)
563                 *info = NULL;
564         return NULL;
565 }
566
567 gpointer
568 mono_arch_get_gsharedvt_arg_trampoline (MonoDomain *domain, gpointer arg, gpointer addr)
569 {
570         g_assert_not_reached ();
571         return NULL;
572 }
573
574 #endif /* MONO_ARCH_GSHARED_SUPPORTED */