Merge pull request #5714 from alexischr/update_bockbuild
[mono.git] / mono / mini / tramp-amd64-gsharedvt.c
1 /**
2  * \file
3  * libcorkscrew-based native unwinder
4  *
5  * Authors:
6  *   Zoltan Varga <vargaz@gmail.com>
7  *   Rodrigo Kumpera <kumpera@gmail.com>
8  *   Andi McClure <andi.mcclure@xamarin.com>
9  *   Johan Lorensson <johan.lorensson@xamarin.com>
10  *
11  * Copyright 2015 Xamarin, Inc (http://www.xamarin.com)
12  * Licensed under the MIT license. See LICENSE file in the project root for full license information.
13  */
14 #include <config.h>
15 #include <glib.h>
16
17 #include <mono/metadata/abi-details.h>
18 #include <mono/metadata/appdomain.h>
19 #include <mono/metadata/marshal.h>
20 #include <mono/metadata/tabledefs.h>
21 #include <mono/metadata/profiler-private.h>
22 #include <mono/metadata/gc-internals.h>
23 #include <mono/arch/amd64/amd64-codegen.h>
24
25 #include <mono/utils/memcheck.h>
26
27 #include "mini.h"
28 #include "mini-amd64.h"
29 #include "mini-amd64-gsharedvt.h"
30 #include "debugger-agent.h"
31
32 #if defined (MONO_ARCH_GSHAREDVT_SUPPORTED)
33
34 #define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1))
35
36 #define SRC_REG_SHIFT 0
37 #define SRC_REG_MASK 0xFFFF
38
39 #define SRC_DESCRIPTOR_MARSHAL_SHIFT 16
40 #define SRC_DESCRIPTOR_MARSHAL_MASK 0x0FF
41
42 #define SLOT_COUNT_SHIFT 24
43 #define SLOT_COUNT_MASK 0xFF
44
45 gpointer
46 mono_amd64_start_gsharedvt_call (GSharedVtCallInfo *info, gpointer *caller, gpointer *callee, gpointer mrgctx_reg)
47 {
48         int i;
49
50 #ifdef DEBUG_AMD64_GSHAREDVT
51         printf ("mono_amd64_start_gsharedvt_call info %p caller %p callee %p ctx %p\n", info, caller, callee, mrgctx_reg);
52
53         for (i = 0; i < PARAM_REGS; ++i)
54                 printf ("\treg [%d] -> %p\n", i, caller [i]);
55 #endif
56
57         /* Set vtype ret arg */
58         if (info->vret_slot != -1) {
59                 DEBUG_AMD64_GSHAREDVT_PRINT ("vret handling\n[%d] < &%d (%p)\n", info->vret_arg_reg, info->vret_slot, &callee [info->vret_slot]);
60                 g_assert (info->vret_slot);
61                 callee [info->vret_arg_reg] = &callee [info->vret_slot];
62         }
63
64         for (i = 0; i < info->map_count; ++i) {
65                 int src = info->map [i * 2];
66                 int dst = info->map [(i * 2) + 1];
67                 int arg_marshal = (src >> SRC_DESCRIPTOR_MARSHAL_SHIFT) & SRC_DESCRIPTOR_MARSHAL_MASK;
68
69                 int source_reg = src & SRC_REG_MASK;
70                 int dest_reg = dst & SRC_REG_MASK;
71
72                 DEBUG_AMD64_GSHAREDVT_PRINT ("source %x dest %x marshal %d: ", src, dst, arg_marshal);
73                 switch (arg_marshal) {
74                 case GSHAREDVT_ARG_NONE:
75                         callee [dest_reg] = caller [source_reg];
76                         DEBUG_AMD64_GSHAREDVT_PRINT ("[%d] <- %d (%p) <- (%p)\n", dest_reg, source_reg, &callee [dest_reg], caller [source_reg]);
77                         break;
78                 case GSHAREDVT_ARG_BYVAL_TO_BYREF:
79                         /* gsharedvt argument passed by addr in reg/stack slot */
80                         callee [dest_reg] = &caller [source_reg];
81                         DEBUG_AMD64_GSHAREDVT_PRINT ("[%d] <- &%d (%p) <- (%p)\n", dest_reg, source_reg, &callee [dest_reg], &caller [source_reg]);
82                         break;
83                 case GSHAREDVT_ARG_BYREF_TO_BYVAL: {
84                         int slot_count = (src >> SLOT_COUNT_SHIFT) & SLOT_COUNT_MASK;
85                         int j;
86                         gpointer *addr = caller [source_reg];
87
88                         for (j = 0; j < slot_count; ++j)
89                                 callee [dest_reg + j] = addr [j];
90                         DEBUG_AMD64_GSHAREDVT_PRINT ("[%d] <- [%d] (%d words) (%p) <- (%p)\n", dest_reg, source_reg, slot_count, &callee [dest_reg], &caller [source_reg]);
91                         break;
92                 }
93                 case GSHAREDVT_ARG_BYREF_TO_BYVAL_U1: {
94                         guint8 *addr = caller [source_reg];
95
96                         callee [dest_reg] = (gpointer)(mgreg_t)*addr;
97                         DEBUG_AMD64_GSHAREDVT_PRINT ("[%d] <- (u1) [%d] (%p) <- (%p)\n", dest_reg, source_reg, &callee [dest_reg], &caller [source_reg]);
98                         break;
99                 }
100                 case GSHAREDVT_ARG_BYREF_TO_BYVAL_U2: {
101                         guint16 *addr = caller [source_reg];
102
103                         callee [dest_reg] = (gpointer)(mgreg_t)*addr;
104                         DEBUG_AMD64_GSHAREDVT_PRINT ("[%d] <- (u2) [%d] (%p) <- (%p)\n", dest_reg, source_reg, &callee [dest_reg], &caller [source_reg]);
105                         break;
106                 }
107                 case GSHAREDVT_ARG_BYREF_TO_BYVAL_U4: {
108                         guint32 *addr = caller [source_reg];
109
110                         callee [dest_reg] = (gpointer)(mgreg_t)*addr;
111                         DEBUG_AMD64_GSHAREDVT_PRINT ("[%d] <- (u4) [%d] (%p) <- (%p)\n", dest_reg, source_reg, &callee [dest_reg], &caller [source_reg]);
112                         break;
113                 }
114
115                 default:
116                         g_error ("cant handle arg marshal %d\n", arg_marshal);
117                 }
118         }
119
120         //Can't handle for now
121         if (info->vcall_offset != -1){
122                 MonoObject *this_obj = caller [0];
123
124                 DEBUG_AMD64_GSHAREDVT_PRINT ("target is a vcall at offset %d\n", info->vcall_offset / 8);
125                 if (G_UNLIKELY (!this_obj))
126                         return NULL;
127                 if (info->vcall_offset == MONO_GSHAREDVT_DEL_INVOKE_VT_OFFSET)
128                         /* delegate invoke */
129                         return ((MonoDelegate*)this_obj)->invoke_impl;
130                 else
131                         return *(gpointer*)((char*)this_obj->vtable + info->vcall_offset);
132         } else if (info->calli) {
133                 /* The address to call is passed in the mrgctx reg */
134                 return mrgctx_reg;
135         } else {
136                 DEBUG_AMD64_GSHAREDVT_PRINT ("target is %p\n", info->addr);
137                 return info->addr;
138         }
139 }
140
141 #ifndef DISABLE_JIT
142
143 // Compiler support
144
145 /*
146  * mono_arch_get_gsharedvt_arg_trampoline:
147  *
148  *   See tramp-x86.c for documentation.
149  */
150 gpointer
151 mono_arch_get_gsharedvt_arg_trampoline (MonoDomain *domain, gpointer arg, gpointer addr)
152 {
153         guint8 *code, *start;
154         int buf_len;
155
156         buf_len = 32;
157
158         start = code = mono_domain_code_reserve (domain, buf_len);
159
160         amd64_mov_reg_imm (code, AMD64_RAX, arg);
161         amd64_jump_code (code, addr);
162         g_assert ((code - start) < buf_len);
163
164         mono_arch_flush_icache (start, code - start);
165         MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_GENERICS_TRAMPOLINE, NULL));
166
167         mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, NULL), domain);
168
169         return start;
170 }
171
172 gpointer
173 mono_arch_get_gsharedvt_trampoline (MonoTrampInfo **info, gboolean aot)
174 {
175         guint8 *code, *buf;
176         int buf_len, cfa_offset;
177         GSList *unwind_ops = NULL;
178         MonoJumpInfo *ji = NULL;
179         int n_arg_regs, n_arg_fregs, framesize, i;
180         int info_offset, offset, rgctx_arg_reg_offset;
181         int caller_reg_area_offset, callee_reg_area_offset, callee_stack_area_offset;
182         guint8 *br_out, *br [64], *br_ret [64];
183         int b_ret_index;
184         int reg_area_size;
185
186         buf_len = 2048;
187         buf = code = mono_global_codeman_reserve (buf_len + MONO_MAX_TRAMPOLINE_UNWINDINFO_SIZE);
188
189         /*
190          * We are being called by an gsharedvt arg trampoline, the info argument is in AMD64_RAX.
191          */
192         n_arg_regs = PARAM_REGS;
193         n_arg_fregs = FLOAT_PARAM_REGS;
194
195         /* Compute stack frame size and offsets */
196         offset = 0;
197         /* info reg */
198         info_offset = offset;
199         offset += 8;
200
201         /* rgctx reg */
202         rgctx_arg_reg_offset = offset;
203         offset += 8;
204
205         /*callconv in regs */
206         caller_reg_area_offset = offset;
207         reg_area_size = ALIGN_TO ((n_arg_regs + n_arg_fregs) * 8, MONO_ARCH_FRAME_ALIGNMENT);
208         offset += reg_area_size;
209
210         framesize = offset;
211
212         g_assert (framesize % MONO_ARCH_FRAME_ALIGNMENT == 0);
213         g_assert (reg_area_size % MONO_ARCH_FRAME_ALIGNMENT == 0);
214
215         /* unwind markers 1/3 */
216         cfa_offset = sizeof (gpointer);
217         mono_add_unwind_op_def_cfa (unwind_ops, code, buf, AMD64_RSP, cfa_offset);
218         mono_add_unwind_op_offset (unwind_ops, code, buf, AMD64_RIP, -cfa_offset);
219
220         /* save the old frame pointer */
221         amd64_push_reg (code, AMD64_RBP);
222
223         /* unwind markers 2/3 */
224         cfa_offset += sizeof (gpointer);
225         mono_add_unwind_op_def_cfa_offset (unwind_ops, code, buf, cfa_offset);
226         mono_add_unwind_op_offset (unwind_ops, code, buf, AMD64_RBP, - cfa_offset);
227
228         /* set it as the new frame pointer */
229         amd64_mov_reg_reg (code, AMD64_RBP, AMD64_RSP, sizeof(mgreg_t));
230
231         /* unwind markers 3/3 */
232         mono_add_unwind_op_def_cfa_reg (unwind_ops, code, buf, AMD64_RBP);
233         mono_add_unwind_op_fp_alloc (unwind_ops, code, buf, AMD64_RBP, 0);
234
235         /* setup the frame */
236         amd64_alu_reg_imm (code, X86_SUB, AMD64_RSP, framesize);
237         
238         /* save stuff */
239
240         /* save info */
241         amd64_mov_membase_reg (code, AMD64_RSP, info_offset, AMD64_RAX, sizeof (mgreg_t));
242         /* save rgctx */
243         amd64_mov_membase_reg (code, AMD64_RSP, rgctx_arg_reg_offset, MONO_ARCH_RGCTX_REG, sizeof (mgreg_t));
244
245         for (i = 0; i < n_arg_regs; ++i)
246                 amd64_mov_membase_reg (code, AMD64_RSP, caller_reg_area_offset + i * 8, param_regs [i], sizeof (mgreg_t));
247
248         for (i = 0; i < n_arg_fregs; ++i)
249                 amd64_sse_movsd_membase_reg (code, AMD64_RSP, caller_reg_area_offset + (i + n_arg_regs) * 8, i);
250
251         /* TODO Allocate stack area used to pass arguments to the method */
252
253
254         /* Allocate callee register area just below the caller area so it can be accessed from start_gsharedvt_call using negative offsets */
255         /* XXX figure out alignment */
256         callee_reg_area_offset = reg_area_size - ((n_arg_regs + n_arg_fregs) * 8); /* Ensure alignment */
257         callee_stack_area_offset = callee_reg_area_offset + reg_area_size;
258         amd64_alu_reg_imm (code, X86_SUB, AMD64_RSP, reg_area_size);
259
260         /* Allocate stack area used to pass arguments to the method */
261         amd64_mov_reg_membase (code, AMD64_R11, AMD64_RAX, MONO_STRUCT_OFFSET (GSharedVtCallInfo, stack_usage), 4);
262         amd64_alu_reg_reg (code, X86_SUB, AMD64_RSP, AMD64_R11);
263
264         /* The stack now looks like this:
265
266         <caller stack params area>
267         <return address>
268         <old frame pointer>
269         <caller registers area>
270         <rgctx>
271         <gsharedvt info>
272         <callee stack area>
273         <callee reg area>
274          */
275
276         /* Call start_gsharedvt_call () */
277         /* arg1 == info */
278         amd64_mov_reg_reg (code, MONO_AMD64_ARG_REG1, AMD64_RAX, sizeof(mgreg_t));
279         /* arg2 = caller stack area */
280         amd64_lea_membase (code, MONO_AMD64_ARG_REG2, AMD64_RBP, -(framesize - caller_reg_area_offset)); 
281
282         /* arg3 == callee stack area */
283         amd64_lea_membase (code, MONO_AMD64_ARG_REG3, AMD64_RSP, callee_reg_area_offset);
284
285         /* arg4 = mrgctx reg */
286         amd64_mov_reg_reg (code, MONO_AMD64_ARG_REG4, MONO_ARCH_RGCTX_REG, sizeof(mgreg_t));
287
288         if (aot) {
289                 code = mono_arch_emit_load_aotconst (buf, code, &ji, MONO_PATCH_INFO_JIT_ICALL_ADDR, "mono_amd64_start_gsharedvt_call");
290                 #ifdef TARGET_WIN32
291                         /* Since we are doing a call as part of setting up stackframe, the reserved shadow stack used by Windows platform is allocated up in
292                         the callee stack area but currently the callee reg area is in between. Windows calling convention dictates that room is made on stack where
293                         callee can save any parameters passed in registers. Since Windows x64 calling convention
294                         uses 4 registers for the first 4 parameters, stack needs to be adjusted before making the call.
295                         NOTE, Windows calling convention assumes that space for all registers have been reserved, regardless
296                         of the number of function parameters actually used.
297                         */
298                         int shadow_reg_size = 0;
299
300                         shadow_reg_size = ALIGN_TO (PARAM_REGS * sizeof(gpointer), MONO_ARCH_FRAME_ALIGNMENT);
301                         amd64_alu_reg_imm (code, X86_SUB, AMD64_RSP, shadow_reg_size);
302                         amd64_call_reg (code, AMD64_R11);
303                         amd64_alu_reg_imm (code, X86_ADD, AMD64_RSP, shadow_reg_size);
304                 #else
305                         amd64_call_reg (code, AMD64_R11);
306                 #endif
307         } else {
308                 amd64_call_code (code, mono_amd64_start_gsharedvt_call);
309         }
310
311         /* Method to call is now on RAX. Restore regs and jump */
312         amd64_mov_reg_reg (code, AMD64_R11, AMD64_RAX, sizeof(mgreg_t));
313
314         for (i = 0; i < n_arg_regs; ++i)
315                 amd64_mov_reg_membase (code, param_regs [i], AMD64_RSP, callee_reg_area_offset + i * 8, sizeof (mgreg_t));
316
317         for (i = 0; i < n_arg_fregs; ++i)
318                 amd64_sse_movsd_reg_membase (code, i, AMD64_RSP, callee_reg_area_offset + (i + n_arg_regs) * 8);
319
320         //load rgctx
321         amd64_mov_reg_membase (code, MONO_ARCH_RGCTX_REG, AMD64_RBP, -(framesize - rgctx_arg_reg_offset), sizeof (mgreg_t));
322
323         /* Clear callee reg area */
324         amd64_alu_reg_imm (code, X86_ADD, AMD64_RSP, reg_area_size);
325
326         /* Call the thing */
327         amd64_call_reg (code, AMD64_R11);
328
329         /* Marshal return value. Available registers: R10 and R11 */
330         /* Load info struct */
331         amd64_mov_reg_membase (code, AMD64_R10, AMD64_RBP, -(framesize - info_offset), sizeof (mgreg_t));
332
333         /* Branch to the in/out handling code */
334         amd64_alu_membase_imm_size (code, X86_CMP, AMD64_R10, MONO_STRUCT_OFFSET (GSharedVtCallInfo, gsharedvt_in), 1, 4);
335
336         b_ret_index = 0;
337         br_out = code;
338         x86_branch32 (code, X86_CC_NE, 0, TRUE);
339
340         /*
341          * IN CASE
342          */
343
344         /* Load vret_slot */
345         /* Use first input parameter register as scratch since it is volatile on all platforms */
346         amd64_mov_reg_membase (code, MONO_AMD64_ARG_REG1, AMD64_R10, MONO_STRUCT_OFFSET (GSharedVtCallInfo, vret_slot), 4);
347         amd64_alu_reg_imm (code, X86_SUB, MONO_AMD64_ARG_REG1, n_arg_regs + n_arg_fregs);
348         amd64_shift_reg_imm (code, X86_SHL, MONO_AMD64_ARG_REG1, 3);
349
350         /* vret address is RBP - (framesize - caller_reg_area_offset) */
351         amd64_mov_reg_reg (code, AMD64_R11, AMD64_RSP, sizeof(mgreg_t));
352         amd64_alu_reg_reg (code, X86_ADD, AMD64_R11, MONO_AMD64_ARG_REG1);
353
354         /* Load ret marshal type */
355         /* Load vret address in R11 */
356         amd64_mov_reg_membase (code, AMD64_R10, AMD64_R10, MONO_STRUCT_OFFSET (GSharedVtCallInfo, ret_marshal), 4);
357
358         for (i = GSHAREDVT_RET_NONE; i < GSHAREDVT_RET_NUM; ++i) {
359                 amd64_alu_reg_imm (code, X86_CMP, AMD64_R10, i);
360                 br [i] = code;
361                 amd64_branch8 (code, X86_CC_EQ, 0, TRUE);
362         }
363         x86_breakpoint (code); /* unhandled case */
364
365         for (i = GSHAREDVT_RET_NONE; i < GSHAREDVT_RET_NUM; ++i) {
366                 mono_amd64_patch (br [i], code);
367                 switch (i) {
368                 case GSHAREDVT_RET_NONE:
369                         break;
370                 case GSHAREDVT_RET_I1:
371                         amd64_widen_membase (code, AMD64_RAX, AMD64_R11, 0, TRUE, FALSE);
372                         break;
373                 case GSHAREDVT_RET_U1:
374                         amd64_widen_membase (code, AMD64_RAX, AMD64_R11, 0, FALSE, FALSE);
375                         break;
376                 case GSHAREDVT_RET_I2:
377                         amd64_widen_membase (code, AMD64_RAX, AMD64_R11, 0, TRUE, TRUE);
378                         break;
379                 case GSHAREDVT_RET_U2:
380                         amd64_widen_membase (code, AMD64_RAX, AMD64_R11, 0, FALSE, TRUE);
381                         break;
382                 case GSHAREDVT_RET_I4: // CORRECT
383                 case GSHAREDVT_RET_U4: // THIS IS INCORRECT. WHY IS IT NOT FAILING?
384                         amd64_movsxd_reg_membase (code, AMD64_RAX, AMD64_R11, 0);
385                         break;
386                 case GSHAREDVT_RET_I8:
387                         amd64_mov_reg_membase (code, AMD64_RAX, AMD64_R11, 0, 8);
388                         break;
389                 case GSHAREDVT_RET_IREGS_1:
390                         amd64_mov_reg_membase (code, return_regs [i - GSHAREDVT_RET_IREGS_1], AMD64_R11, 0, 8);
391                         break;
392                 case GSHAREDVT_RET_R8:
393                         amd64_sse_movsd_reg_membase (code, AMD64_XMM0, AMD64_R11, 0);
394                         break;
395                 default:
396                         x86_breakpoint (code); /* can't handle specific case */
397                 }
398
399                 br_ret [b_ret_index ++] = code;
400                 x86_jump32 (code, 0);
401         }
402
403         /*
404          * OUT CASE
405          */
406         mono_amd64_patch (br_out, code);
407
408         /*
409                 Address to write return to is in the original value of the register specified by vret_arg_reg.
410                 This will be either RSI, RDI (System V) or RCX, RDX (Windows) depending on whether this is a static call.
411                 Its location:
412                 We alloc 'framesize' bytes below RBP to save regs, info and rgctx. RSP = RBP - framesize
413                 We store RDI (System V), RCX (Windows) at RSP + caller_reg_area_offset + slot_index_of (register) * 8.
414
415                 address: RBP - framesize + caller_reg_area_offset + 8*slot
416         */
417
418         int caller_vret_offset = caller_reg_area_offset - framesize;
419
420         /* Load vret address in R11 */
421         /* Position to return to is passed as a hidden argument. Load 'vret_arg_slot' to find it */
422         amd64_movsxd_reg_membase (code, AMD64_R11, AMD64_R10, MONO_STRUCT_OFFSET (GSharedVtCallInfo, vret_arg_reg));
423
424         // In the GSHAREDVT_RET_NONE case, vret_arg_slot is -1. In this case, skip marshalling.
425         amd64_alu_reg_imm (code, X86_CMP, AMD64_R11, 0);
426         br_ret [b_ret_index ++] = code;
427         amd64_branch32 (code, X86_CC_LT, 0, TRUE);
428
429         /* Compute ret area address in the caller frame, *( ((gpointer *)RBP) [R11+2] ) */
430         amd64_shift_reg_imm (code, X86_SHL, AMD64_R11, 3);
431         amd64_alu_reg_imm (code, X86_ADD, AMD64_R11, caller_vret_offset);
432         amd64_alu_reg_reg (code, X86_ADD, AMD64_R11, AMD64_RBP);
433         amd64_mov_reg_membase (code, AMD64_R11, AMD64_R11, 0, sizeof (gpointer));
434
435         /* Load ret marshal type in R10 */
436         amd64_mov_reg_membase (code, AMD64_R10, AMD64_R10, MONO_STRUCT_OFFSET (GSharedVtCallInfo, ret_marshal), 4);
437
438         // Switch table for ret_marshal value
439         for (i = GSHAREDVT_RET_NONE; i < GSHAREDVT_RET_NUM; ++i) {
440                 amd64_alu_reg_imm (code, X86_CMP, AMD64_R10, i);
441                 br [i] = code;
442                 amd64_branch8 (code, X86_CC_EQ, 0, TRUE);
443         }
444         x86_breakpoint (code); /* unhandled case */
445
446         for (i = GSHAREDVT_RET_NONE; i < GSHAREDVT_RET_NUM; ++i) {
447                 mono_amd64_patch (br [i], code);
448                 switch (i) {
449                 case GSHAREDVT_RET_NONE:
450                         break;
451                 case GSHAREDVT_RET_IREGS_1:
452                         amd64_mov_membase_reg (code, AMD64_R11, 0, return_regs [i - GSHAREDVT_RET_IREGS_1], 8);
453                         break;
454                 case GSHAREDVT_RET_R8:
455                         amd64_sse_movsd_membase_reg (code, AMD64_R11, 0, AMD64_XMM0);
456                         break;
457                 default:
458                         x86_breakpoint (code); /* can't handle specific case */
459                 }
460
461                 br_ret [b_ret_index ++] = code;
462                 x86_jump32 (code, 0);
463         }
464
465         /* exit path */
466         for (i = 0; i < b_ret_index; ++i)
467                 mono_amd64_patch (br_ret [i], code);
468
469         /* Exit code path */
470 #if TARGET_WIN32
471         amd64_lea_membase (code, AMD64_RSP, AMD64_RBP, 0);
472         amd64_pop_reg (code, AMD64_RBP);
473         mono_add_unwind_op_same_value (unwind_ops, code, buf, AMD64_RBP);
474 #else
475         amd64_leave (code);
476 #endif
477         amd64_ret (code);
478
479         g_assert ((code - buf) < buf_len);
480         g_assert_checked (mono_arch_unwindinfo_validate_size (unwind_ops, MONO_MAX_TRAMPOLINE_UNWINDINFO_SIZE));
481
482         if (info)
483                 *info = mono_tramp_info_create ("gsharedvt_trampoline", buf, code - buf, ji, unwind_ops);
484
485         mono_arch_flush_icache (buf, code - buf);
486         return buf;
487 }
488
489 #else
490
491 gpointer
492 mono_arch_get_gsharedvt_arg_trampoline (MonoDomain *domain, gpointer arg, gpointer addr)
493 {
494         g_assert_not_reached ();
495         return NULL;
496 }
497
498 gpointer
499 mono_arch_get_gsharedvt_trampoline (MonoTrampInfo **info, gboolean aot)
500 {
501         g_assert_not_reached ();
502         return NULL;
503 }
504
505 #endif
506
507 #else
508
509 gpointer
510 mono_amd64_start_gsharedvt_call (GSharedVtCallInfo *info, gpointer *caller, gpointer *callee, gpointer mrgctx_reg)
511 {
512         g_assert_not_reached ();
513         return NULL;
514 }
515
516 #endif