1 /**
2  * \file
3  * (C) 2003 Ximian, Inc.
4  * (C) 2003-2011 Novell, Inc.
5  * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
6  * Licensed under the MIT license. See LICENSE file in the project root for full license information.
7  */
8 #include <config.h>
9 #include <glib.h>
10 
11 #include <mono/metadata/appdomain.h>
12 #include <mono/metadata/metadata-internals.h>
13 #include <mono/metadata/marshal.h>
14 #include <mono/metadata/tabledefs.h>
15 #include <mono/utils/mono-counters.h>
16 #include <mono/utils/mono-error-internals.h>
17 #include <mono/utils/mono-membar.h>
18 #include <mono/utils/mono-compiler.h>
19 #include <mono/utils/mono-threads-coop.h>
20 #include <mono/utils/unlocked.h>
21 
22 #include "mini.h"
23 #include "lldb.h"
24 #include "aot-runtime.h"
25 #include "mini-runtime.h"
26 
27 #include "interp/interp.h"
28 
29 /*
30  * Address of the trampoline code.  This is used by the debugger to check
31  * whether a method is a trampoline.
32  */
33 guint8* mono_trampoline_code [MONO_TRAMPOLINE_NUM];
34 
35 static GHashTable *rgctx_lazy_fetch_trampoline_hash;
36 static GHashTable *rgctx_lazy_fetch_trampoline_hash_addr;
37 
38 static gint32 trampoline_calls;
39 static gint32 jit_trampolines;
40 static gint32 unbox_trampolines;
41 static gint32 static_rgctx_trampolines;
42 static gint32 rgctx_unmanaged_lookups;
43 static gint32 rgctx_num_lazy_fetch_trampolines;
44 
45 #define mono_trampolines_lock() mono_os_mutex_lock (&trampolines_mutex)
46 #define mono_trampolines_unlock() mono_os_mutex_unlock (&trampolines_mutex)
47 static mono_mutex_t trampolines_mutex;
48 
49 #ifdef MONO_ARCH_GSHARED_SUPPORTED
50 
51 typedef struct {
52 	MonoMethod *m;
53 	gpointer addr;
54 } RgctxTrampInfo;
55 
56 static gint
rgctx_tramp_info_equal(gconstpointer ka,gconstpointer kb)57 rgctx_tramp_info_equal (gconstpointer ka, gconstpointer kb)
58 {
59 	const RgctxTrampInfo *i1 = (const RgctxTrampInfo *)ka;
60 	const RgctxTrampInfo *i2 = (const RgctxTrampInfo *)kb;
61 
62 	if (i1->m == i2->m && i1->addr == i2->addr)
63 		return 1;
64 	else
65 		return 0;
66 }
67 
68 static guint
rgctx_tramp_info_hash(gconstpointer data)69 rgctx_tramp_info_hash (gconstpointer data)
70 {
71 	const RgctxTrampInfo *info = (const RgctxTrampInfo *)data;
72 
73 	return GPOINTER_TO_UINT (info->m) ^ GPOINTER_TO_UINT (info->addr);
74 }
75 
76 /**
77  * mono_create_static_rgctx_trampoline:
78  * \param m the mono method to create a trampoline for
79  * \param addr the address to jump to (where the compiled code for M lives)
80  *
81  * Creates a static rgctx trampoline for M which branches to ADDR which should
82  * point to the compiled code of M.
83  *
84  * Static rgctx trampolines are used when a shared generic method which doesn't
85  * have a this argument is called indirectly, ie. from code which can't pass in
86  * the rgctx argument. The trampoline sets the rgctx argument and jumps to the
87  * methods code. These trampolines are similar to the unbox trampolines, they
88  * perform the same task as the static rgctx wrappers, but they are smaller/faster,
89  * and can be made to work with full AOT.
90  *
91  * On PPC addr should be an ftnptr and the return value is an ftnptr too.
92  *
93  * \returns the generated static rgctx trampoline.
94  */
95 gpointer
mono_create_static_rgctx_trampoline(MonoMethod * m,gpointer addr)96 mono_create_static_rgctx_trampoline (MonoMethod *m, gpointer addr)
97 {
98 	gpointer ctx;
99 	gpointer res;
100 	MonoDomain *domain;
101 	RgctxTrampInfo tmp_info;
102 	RgctxTrampInfo *info;
103 
104 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
105 	g_assert (((gpointer*)addr) [2] == 0);
106 #endif
107 
108 	ctx = mini_method_get_rgctx (m);
109 
110 	domain = mono_domain_get ();
111 
112 	/*
113 	 * In the AOT case, addr might point to either the method, or to an unbox trampoline,
114 	 * so make the hash keyed on the m+addr pair.
115 	 */
116 	mono_domain_lock (domain);
117 	if (!domain_jit_info (domain)->static_rgctx_trampoline_hash)
118 		domain_jit_info (domain)->static_rgctx_trampoline_hash = g_hash_table_new (rgctx_tramp_info_hash, rgctx_tramp_info_equal);
119 	tmp_info.m = m;
120 	tmp_info.addr = addr;
121 	res = g_hash_table_lookup (domain_jit_info (domain)->static_rgctx_trampoline_hash,
122 							   &tmp_info);
123 	mono_domain_unlock (domain);
124 	if (res)
125 		return res;
126 
127 	if (mono_aot_only)
128 		res = mono_aot_get_static_rgctx_trampoline (ctx, addr);
129 	else
130 		res = mono_arch_get_static_rgctx_trampoline (ctx, addr);
131 
132 	mono_domain_lock (domain);
133 	/* Duplicates inserted while we didn't hold the lock are OK */
134 	info = (RgctxTrampInfo *)mono_domain_alloc (domain, sizeof (RgctxTrampInfo));
135 	info->m = m;
136 	info->addr = addr;
137 	g_hash_table_insert (domain_jit_info (domain)->static_rgctx_trampoline_hash, info, res);
138 
139 	UnlockedIncrement (&static_rgctx_trampolines);
140 	mono_domain_unlock (domain);
141 
142 	return res;
143 }
144 #else
145 gpointer
mono_create_static_rgctx_trampoline(MonoMethod * m,gpointer addr)146 mono_create_static_rgctx_trampoline (MonoMethod *m, gpointer addr)
147 {
148        /*
149         * This shouldn't happen as all arches which support generic sharing support
150         * static rgctx trampolines as well.
151         */
152        g_assert_not_reached ();
153 }
154 #endif
155 
156 #if 0
157 #define DEBUG_IMT(stmt) do { stmt; } while (0)
158 #else
159 #define DEBUG_IMT(stmt) do { } while (0)
160 #endif
161 
162 /*
163  * mini_resolve_imt_method:
164  *
165  *   Resolve the actual method called when making an IMT call through VTABLE_SLOT with IMT_METHOD as the interface method.
166  *
167  * Either IMPL_METHOD or OUT_AOT_ADDR will be set on return.
168  */
169 gpointer*
mini_resolve_imt_method(MonoVTable * vt,gpointer * vtable_slot,MonoMethod * imt_method,MonoMethod ** impl_method,gpointer * out_aot_addr,gboolean * out_need_rgctx_tramp,MonoMethod ** variant_iface,MonoError * error)170 mini_resolve_imt_method (MonoVTable *vt, gpointer *vtable_slot, MonoMethod *imt_method, MonoMethod **impl_method, gpointer *out_aot_addr, gboolean *out_need_rgctx_tramp, MonoMethod **variant_iface, MonoError *error)
171 {
172 	MonoMethod *impl = NULL, *generic_virtual = NULL;
173 	gboolean lookup_aot, variance_used = FALSE, need_rgctx_tramp = FALSE;
174 	gpointer addr;
175 	guint8 *aot_addr = NULL;
176 	int displacement = vtable_slot - ((gpointer*)vt);
177 	int interface_offset;
178 	int imt_slot = MONO_IMT_SIZE + displacement;
179 
180 	g_assert (imt_slot < MONO_IMT_SIZE);
181 
182 	error_init (error);
183 	/* This has to be variance aware since imt_method can be from an interface that vt->klass doesn't directly implement */
184 	interface_offset = mono_class_interface_offset_with_variance (vt->klass, imt_method->klass, &variance_used);
185 	if (interface_offset < 0)
186 		g_error ("%s doesn't implement interface %s\n", mono_type_get_name_full (&vt->klass->byval_arg, MONO_TYPE_NAME_FORMAT_IL), mono_type_get_name_full (&imt_method->klass->byval_arg, MONO_TYPE_NAME_FORMAT_IL));
187 
188 	*variant_iface = NULL;
189 	if (imt_method->is_inflated && ((MonoMethodInflated*)imt_method)->context.method_inst) {
190 		/* Generic virtual method */
191 		generic_virtual = imt_method;
192 		need_rgctx_tramp = TRUE;
193 	} else if (variance_used && mono_class_has_variant_generic_params (imt_method->klass)) {
194 		*variant_iface = imt_method;
195 	}
196 
197 	addr = NULL;
198 	/* We can only use the AOT compiled code if we don't require further processing */
199 	lookup_aot = !generic_virtual & !variant_iface;
200 
201 	if (!mono_llvm_only)
202 		mono_vtable_build_imt_slot (vt, mono_method_get_imt_slot (imt_method));
203 
204 	if (imt_method->is_inflated && ((MonoMethodInflated*)imt_method)->context.method_inst) {
205 		MonoGenericContext context = { NULL, NULL };
206 
207 		/*
208 		 * Generic virtual method, imt_method contains the inflated interface
209 		 * method, need to get the inflated impl method.
210 		 */
211 		/* imt_method->slot might not be set */
212 		impl = mono_class_get_vtable_entry (vt->klass, interface_offset + mono_method_get_declaring_generic_method (imt_method)->slot);
213 
214 		if (mono_class_is_ginst (impl->klass))
215 			context.class_inst = mono_class_get_generic_class (impl->klass)->context.class_inst;
216 		context.method_inst = ((MonoMethodInflated*)imt_method)->context.method_inst;
217 		impl = mono_class_inflate_generic_method_checked (impl, &context, error);
218 		mono_error_assert_ok (error);
219 	} else {
220 
221 		/* Avoid loading metadata or creating a generic vtable if possible */
222 		if (lookup_aot && !vt->klass->valuetype) {
223 			aot_addr = (guint8 *)mono_aot_get_method_from_vt_slot (mono_domain_get (), vt, interface_offset + mono_method_get_vtable_slot (imt_method), error);
224 			return_val_if_nok (error, NULL);
225 		} else {
226 			aot_addr = NULL;
227 		}
228 		if (aot_addr)
229 			impl = NULL;
230 		else
231 			impl = mono_class_get_vtable_entry (vt->klass, interface_offset + mono_method_get_vtable_slot (imt_method));
232 	}
233 
234 	if (impl && mono_method_needs_static_rgctx_invoke (impl, FALSE))
235 		need_rgctx_tramp = TRUE;
236 	if (impl && impl->wrapper_type == MONO_WRAPPER_MANAGED_TO_MANAGED) {
237 		WrapperInfo *info = mono_marshal_get_wrapper_info (impl);
238 
239 		if (info && info->subtype == WRAPPER_SUBTYPE_GENERIC_ARRAY_HELPER)
240 			need_rgctx_tramp = TRUE;
241 	}
242 	*impl_method = impl;
243 	*out_need_rgctx_tramp = need_rgctx_tramp;
244 	*out_aot_addr = aot_addr;
245 
246 	DEBUG_IMT (printf ("mono_convert_imt_slot_to_vtable_slot: method = %s.%s.%s, imt_method = %s.%s.%s\n",
247 					   method->klass->name_space, method->klass->name, method->name,
248 					   imt_method->klass->name_space, imt_method->klass->name, imt_method->name));
249 
250 	if (vt->imt_collisions_bitmap & (1 << imt_slot)) {
251 		int slot = mono_method_get_vtable_index (imt_method);
252 		int vtable_offset;
253 
254 		g_assert (slot != -1);
255 		vtable_offset = interface_offset + slot;
256 		vtable_slot = & (vt->vtable [vtable_offset]);
257 		DEBUG_IMT (printf ("mono_convert_imt_slot_to_vtable_slot: slot %p[%d] is in the IMT, and colliding becomes %p[%d] (interface_offset = %d, method->slot = %d)\n", slot, imt_slot, vtable_slot, vtable_offset, interface_offset, imt_method->slot));
258 		return vtable_slot;
259 	} else {
260 		DEBUG_IMT (printf ("mono_convert_imt_slot_to_vtable_slot: slot %p[%d] is in the IMT, but not colliding\n", slot, imt_slot));
261 		return vtable_slot;
262 	}
263 }
264 
265 /*
266  * This is a super-ugly hack to fix bug #616463.
267  *
268  * The problem is that we don't always set is_generic for generic
269  * method definitions.  See the comment at the end of
270  * mono_class_inflate_generic_method_full_checked() in class.c.
271  */
272 static gboolean
is_generic_method_definition(MonoMethod * m)273 is_generic_method_definition (MonoMethod *m)
274 {
275 	MonoGenericContext *context;
276 	if (m->is_generic)
277 		return TRUE;
278 	if (!m->is_inflated)
279 		return FALSE;
280 
281 	context = mono_method_get_context (m);
282 	if (!context->method_inst)
283 		return FALSE;
284 	if (context->method_inst == mono_method_get_generic_container (((MonoMethodInflated*)m)->declaring)->context.method_inst)
285 		return TRUE;
286 	return FALSE;
287 }
288 
289 gboolean
mini_jit_info_is_gsharedvt(MonoJitInfo * ji)290 mini_jit_info_is_gsharedvt (MonoJitInfo *ji)
291 {
292 	if (ji && ji->has_generic_jit_info && (mono_jit_info_get_generic_sharing_context (ji)->is_gsharedvt))
293 		return TRUE;
294 	else
295 		return FALSE;
296 }
297 
298 /**
299  * mini_add_method_trampoline:
300  * @m:
301  * @compiled_method:
302  * @add_static_rgctx_tramp: adds a static rgctx trampoline
303  * @add_unbox_tramp: adds an unboxing trampoline
304  *
305  * Add static rgctx/gsharedvt_in/unbox trampolines to
306  * M/COMPILED_METHOD if needed.
307  *
308  * Returns the trampoline address, or COMPILED_METHOD if no trampoline
309  * is needed.
310  */
311 gpointer
mini_add_method_trampoline(MonoMethod * m,gpointer compiled_method,gboolean add_static_rgctx_tramp,gboolean add_unbox_tramp)312 mini_add_method_trampoline (MonoMethod *m, gpointer compiled_method, gboolean add_static_rgctx_tramp, gboolean add_unbox_tramp)
313 {
314 	gpointer addr = compiled_method;
315 	gboolean callee_gsharedvt, callee_array_helper;
316 	MonoMethod *jmethod = NULL;
317 	MonoJitInfo *ji;
318 
319 	// FIXME: This loads information from AOT (perf problem)
320 	ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (compiled_method), NULL);
321 	callee_gsharedvt = mini_jit_info_is_gsharedvt (ji);
322 
323 	callee_array_helper = FALSE;
324 	if (m->wrapper_type == MONO_WRAPPER_MANAGED_TO_MANAGED) {
325 		WrapperInfo *info = mono_marshal_get_wrapper_info (m);
326 
327 		/*
328 		 * generic array helpers.
329 		 * Have to replace the wrappers with the original generic instances.
330 		 */
331 		if (info && info->subtype == WRAPPER_SUBTYPE_GENERIC_ARRAY_HELPER) {
332 			callee_array_helper = TRUE;
333 			m = info->d.generic_array_helper.method;
334 		}
335 	} else if (m->wrapper_type == MONO_WRAPPER_UNKNOWN) {
336 		WrapperInfo *info = mono_marshal_get_wrapper_info (m);
337 
338 		/* Same for synchronized inner wrappers */
339 		if (info && info->subtype == WRAPPER_SUBTYPE_SYNCHRONIZED_INNER) {
340 			m = info->d.synchronized_inner.method;
341 		}
342 	}
343 
344 	if (callee_gsharedvt)
345 		g_assert (m->is_inflated);
346 
347 	addr = compiled_method;
348 
349 	if (add_unbox_tramp) {
350 		/*
351 		 * The unbox trampolines call the method directly, so need to add
352 		 * an rgctx tramp before them.
353 		 */
354 		if (mono_aot_only) {
355 			addr = mono_aot_get_unbox_trampoline (m);
356 		} else {
357 			unbox_trampolines ++;
358 			addr = mono_arch_get_unbox_trampoline (m, addr);
359 		}
360 	}
361 
362 	if (ji && !ji->is_trampoline)
363 		jmethod = jinfo_get_method (ji);
364 	if (callee_gsharedvt && mini_is_gsharedvt_variable_signature (mono_method_signature (jmethod))) {
365 		MonoMethodSignature *sig, *gsig;
366 
367 		/* Here m is a generic instance, while ji->method is the gsharedvt method implementing it */
368 
369 		/* Call from normal/gshared code to gsharedvt code with variable signature */
370 		sig = mono_method_signature (m);
371 		gsig = mono_method_signature (jmethod);
372 
373 		addr = mini_get_gsharedvt_wrapper (TRUE, addr, sig, gsig, -1, FALSE);
374 
375 		if (mono_llvm_only)
376 			g_assert_not_reached ();
377 		//printf ("IN: %s\n", mono_method_full_name (m, TRUE));
378 	}
379 
380 	if (callee_array_helper) {
381 		add_static_rgctx_tramp = FALSE;
382 		/* In AOT mode, compiled_method points to one of the InternalArray methods in Array. */
383 		if (ji && !mono_llvm_only && mono_method_needs_static_rgctx_invoke (jinfo_get_method (ji), TRUE))
384 			add_static_rgctx_tramp = TRUE;
385 	}
386 
387 	if (mono_llvm_only)
388 		add_static_rgctx_tramp = FALSE;
389 
390 	if (add_static_rgctx_tramp)
391 		addr = mono_create_static_rgctx_trampoline (m, addr);
392 
393 	return addr;
394 }
395 
396 /*
397  * mini_create_llvmonly_ftndesc:
398  *
399  *   Create a function descriptor of the form <addr, arg>, which
400  * represents a callee ADDR with ARG as the last argument.
401  * This is used for:
402  * - generic sharing (ARG is the rgctx)
403  * - gsharedvt signature wrappers (ARG is a function descriptor)
404  */
405 MonoFtnDesc*
mini_create_llvmonly_ftndesc(MonoDomain * domain,gpointer addr,gpointer arg)406 mini_create_llvmonly_ftndesc (MonoDomain *domain, gpointer addr, gpointer arg)
407 {
408 	MonoFtnDesc *ftndesc = (MonoFtnDesc*)mono_domain_alloc0 (mono_domain_get (), 2 * sizeof (gpointer));
409 	ftndesc->addr = addr;
410 	ftndesc->arg = arg;
411 
412 	return ftndesc;
413 }
414 
415 /**
416  * mini_add_method_wrappers_llvmonly:
417  *
418  *   Add unbox/gsharedvt wrappers around COMPILED_METHOD if needed. Return the wrapper address or COMPILED_METHOD
419  * if no wrapper is needed. Set OUT_ARG to the rgctx/extra argument needed to be passed to the returned method.
420  */
421 gpointer
mini_add_method_wrappers_llvmonly(MonoMethod * m,gpointer compiled_method,gboolean caller_gsharedvt,gboolean add_unbox_tramp,gpointer * out_arg)422 mini_add_method_wrappers_llvmonly (MonoMethod *m, gpointer compiled_method, gboolean caller_gsharedvt, gboolean add_unbox_tramp, gpointer *out_arg)
423 {
424 	gpointer addr;
425 	gboolean callee_gsharedvt, callee_array_helper;
426 	MonoMethod *jmethod = NULL;
427 	MonoJitInfo *ji;
428 
429 	// FIXME: This loads information from AOT (perf problem)
430 	ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (compiled_method), NULL);
431 	callee_gsharedvt = mini_jit_info_is_gsharedvt (ji);
432 
433 	callee_array_helper = FALSE;
434 	if (m->wrapper_type == MONO_WRAPPER_MANAGED_TO_MANAGED) {
435 		WrapperInfo *info = mono_marshal_get_wrapper_info (m);
436 
437 		/*
438 		 * generic array helpers.
439 		 * Have to replace the wrappers with the original generic instances.
440 		 */
441 		if (info && info->subtype == WRAPPER_SUBTYPE_GENERIC_ARRAY_HELPER) {
442 			callee_array_helper = TRUE;
443 			m = info->d.generic_array_helper.method;
444 		}
445 	} else if (m->wrapper_type == MONO_WRAPPER_UNKNOWN) {
446 		WrapperInfo *info = mono_marshal_get_wrapper_info (m);
447 
448 		/* Same for synchronized inner wrappers */
449 		if (info && info->subtype == WRAPPER_SUBTYPE_SYNCHRONIZED_INNER) {
450 			m = info->d.synchronized_inner.method;
451 		}
452 	}
453 
454 	if (callee_gsharedvt)
455 		g_assert (m->is_inflated);
456 
457 	addr = compiled_method;
458 
459 	if (add_unbox_tramp) {
460 		/*
461 		 * The unbox trampolines call the method directly, so need to add
462 		 * an rgctx tramp before them.
463 		 */
464 		if (mono_aot_only) {
465 			addr = mono_aot_get_unbox_trampoline (m);
466 		} else {
467 			unbox_trampolines ++;
468 			addr = mono_arch_get_unbox_trampoline (m, addr);
469 		}
470 	}
471 
472 	g_assert (mono_llvm_only);
473 	g_assert (out_arg);
474 
475 	if (ji && !ji->is_trampoline)
476 		jmethod = jinfo_get_method (ji);
477 
478 	if (callee_gsharedvt)
479 		callee_gsharedvt = mini_is_gsharedvt_variable_signature (mono_method_signature (jmethod));
480 
481 	if (!caller_gsharedvt && callee_gsharedvt) {
482 		MonoMethodSignature *sig, *gsig;
483 		gpointer wrapper_addr;
484 
485 		/* Here m is a generic instance, while ji->method is the gsharedvt method implementing it */
486 
487 		/* Call from normal/gshared code to gsharedvt code with variable signature */
488 		sig = mono_method_signature (m);
489 		gsig = mono_method_signature (jmethod);
490 
491 		wrapper_addr = mini_get_gsharedvt_wrapper (TRUE, addr, sig, gsig, -1, FALSE);
492 
493 		/*
494 		 * This is a gsharedvt in wrapper, it gets passed a ftndesc for the gsharedvt method as an argument.
495 		 */
496 		*out_arg = mini_create_llvmonly_ftndesc (mono_domain_get (), addr, mini_method_get_rgctx (m));
497 		addr = wrapper_addr;
498 		//printf ("IN: %s\n", mono_method_full_name (m, TRUE));
499 	}
500 
501 	if (!(*out_arg) && mono_method_needs_static_rgctx_invoke (m, FALSE))
502 		*out_arg = mini_method_get_rgctx (m);
503 
504 	if (caller_gsharedvt && !callee_gsharedvt) {
505 		/*
506 		 * The callee uses the gsharedvt calling convention, have to add an out wrapper.
507 		 */
508 		gpointer out_wrapper = mini_get_gsharedvt_wrapper (FALSE, NULL, mono_method_signature (m), NULL, -1, FALSE);
509 		MonoFtnDesc *out_wrapper_arg = mini_create_llvmonly_ftndesc (mono_domain_get (), addr, *out_arg);
510 
511 		addr = out_wrapper;
512 		*out_arg = out_wrapper_arg;
513 	}
514 
515 	return addr;
516 }
517 
518 /**
519  * common_call_trampoline:
520  *
521  *   The code to handle normal, virtual, and interface method calls and jumps, both
522  * from JITted and LLVM compiled code.
523  */
524 static gpointer
common_call_trampoline(mgreg_t * regs,guint8 * code,MonoMethod * m,MonoVTable * vt,gpointer * vtable_slot,MonoError * error)525 common_call_trampoline (mgreg_t *regs, guint8 *code, MonoMethod *m, MonoVTable *vt, gpointer *vtable_slot, MonoError *error)
526 {
527 	gpointer addr, compiled_method;
528 	gboolean generic_shared = FALSE;
529 	gboolean need_unbox_tramp = FALSE;
530 	gboolean need_rgctx_tramp = FALSE;
531 	MonoMethod *declaring = NULL;
532 	MonoMethod *generic_virtual = NULL, *variant_iface = NULL;
533 	int context_used;
534 	gboolean imt_call, virtual_;
535 	gpointer *orig_vtable_slot, *vtable_slot_to_patch = NULL;
536 	MonoJitInfo *ji = NULL;
537 
538 	error_init (error);
539 
540 	virtual_ = vt && (gpointer)vtable_slot > (gpointer)vt;
541 	imt_call = vt && (gpointer)vtable_slot < (gpointer)vt;
542 
543 	/*
544 	 * rgctx trampolines are needed when the call is indirect so the caller can't pass
545 	 * the rgctx argument needed by the callee.
546 	 */
547 	if (virtual_ && m)
548 		need_rgctx_tramp = mono_method_needs_static_rgctx_invoke (m, FALSE);
549 
550 	orig_vtable_slot = vtable_slot;
551 	vtable_slot_to_patch = vtable_slot;
552 
553 	/* IMT call */
554 	if (imt_call) {
555 		MonoMethod *imt_method = NULL, *impl_method = NULL;
556 		MonoObject *this_arg;
557 
558 		g_assert (vtable_slot);
559 
560 		imt_method = mono_arch_find_imt_method (regs, code);
561 		this_arg = (MonoObject *)mono_arch_get_this_arg_from_call (regs, code);
562 
563 		if (mono_object_is_transparent_proxy (this_arg)) {
564 			/* Use the slow path for now */
565 		    m = mono_object_get_virtual_method (this_arg, imt_method);
566 			vtable_slot_to_patch = NULL;
567 		} else {
568 			if (imt_method->is_inflated && ((MonoMethodInflated*)imt_method)->context.method_inst) {
569 				/* Generic virtual method */
570 				generic_virtual = imt_method;
571 				need_rgctx_tramp = TRUE;
572 			}
573 
574 			vtable_slot = mini_resolve_imt_method (vt, vtable_slot, imt_method, &impl_method, &addr, &need_rgctx_tramp, &variant_iface, error);
575 			return_val_if_nok (error, NULL);
576 
577 			/* We must handle magic interfaces on rank 1 arrays of ref types as if they were variant */
578 			if (!variant_iface && vt->klass->rank == 1 && !vt->klass->element_class->valuetype && imt_method->klass->is_array_special_interface)
579 				variant_iface = imt_method;
580 
581 			/* This is the vcall slot which gets called through the IMT trampoline */
582 			vtable_slot_to_patch = vtable_slot;
583 
584 			if (addr) {
585 				/*
586 				 * We found AOT compiled code for the method, skip the rest.
587 				 */
588 				if (mono_domain_owns_vtable_slot (mono_domain_get (), vtable_slot))
589 					*vtable_slot = addr;
590 
591 				return mono_create_ftnptr (mono_domain_get (), addr);
592 			}
593 
594 			m = impl_method;
595 		}
596 	}
597 
598 	/*
599 	 * The virtual check is needed because is_generic_method_definition (m) could
600 	 * return TRUE for methods used in IMT calls too.
601 	 */
602 	if (virtual_ && is_generic_method_definition (m)) {
603 		MonoGenericContext context = { NULL, NULL };
604 		MonoMethod *declaring;
605 
606 		if (m->is_inflated)
607 			declaring = mono_method_get_declaring_generic_method (m);
608 		else
609 			declaring = m;
610 
611 		if (mono_class_is_ginst (m->klass))
612 			context.class_inst = mono_class_get_generic_class (m->klass)->context.class_inst;
613 		else
614 			g_assert (!mono_class_is_gtd (m->klass));
615 
616 		generic_virtual = mono_arch_find_imt_method (regs, code);
617 		g_assert (generic_virtual);
618 		g_assert (generic_virtual->is_inflated);
619 		context.method_inst = ((MonoMethodInflated*)generic_virtual)->context.method_inst;
620 
621 		m = mono_class_inflate_generic_method_checked (declaring, &context, error);
622 		mono_error_assert_ok (error);
623 		/* FIXME: only do this if the method is sharable */
624 		need_rgctx_tramp = TRUE;
625 	} else if ((context_used = mono_method_check_context_used (m))) {
626 		MonoClass *klass = NULL;
627 		MonoMethod *actual_method = NULL;
628 		MonoVTable *vt = NULL;
629 		MonoGenericInst *method_inst = NULL;
630 
631 		vtable_slot = NULL;
632 		generic_shared = TRUE;
633 
634 		g_assert (code);
635 
636 		/*
637 		 * The caller is gshared code, compute the actual method to call from M and this/rgctx.
638 		 */
639 		if (m->is_inflated && mono_method_get_context (m)->method_inst) {
640 			MonoMethodRuntimeGenericContext *mrgctx = (MonoMethodRuntimeGenericContext*)mono_arch_find_static_call_vtable (regs, code);
641 
642 			klass = mrgctx->class_vtable->klass;
643 			method_inst = mrgctx->method_inst;
644 		} else if ((m->flags & METHOD_ATTRIBUTE_STATIC) || m->klass->valuetype) {
645 			MonoVTable *vtable = mono_arch_find_static_call_vtable (regs, code);
646 
647 			klass = vtable->klass;
648 		} else {
649 			MonoObject *this_argument = (MonoObject *)mono_arch_get_this_arg_from_call (regs, code);
650 
651 			vt = this_argument->vtable;
652 			vtable_slot = orig_vtable_slot;
653 
654 			g_assert (this_argument->vtable->klass->inited);
655 
656 			if (!vtable_slot) {
657 				mono_class_setup_supertypes (this_argument->vtable->klass);
658 				klass = this_argument->vtable->klass->supertypes [m->klass->idepth - 1];
659 			}
660 		}
661 
662 		g_assert (vtable_slot || klass);
663 
664 		if (vtable_slot) {
665 			int displacement = vtable_slot - ((gpointer*)vt);
666 
667 			g_assert_not_reached ();
668 
669 			g_assert (displacement > 0);
670 
671 			actual_method = vt->klass->vtable [displacement];
672 		}
673 
674 		if (method_inst || m->wrapper_type) {
675 			MonoGenericContext context = { NULL, NULL };
676 
677 			if (m->is_inflated)
678 				declaring = mono_method_get_declaring_generic_method (m);
679 			else
680 				declaring = m;
681 
682 			if (mono_class_is_ginst (klass))
683 				context.class_inst = mono_class_get_generic_class (klass)->context.class_inst;
684 			else if (mono_class_is_gtd (klass))
685 				context.class_inst = mono_class_get_generic_container (klass)->context.class_inst;
686 			context.method_inst = method_inst;
687 
688 			actual_method = mono_class_inflate_generic_method_checked (declaring, &context, error);
689 			mono_error_assert_ok (error);
690 		} else {
691 			actual_method = mono_class_get_method_generic (klass, m);
692 		}
693 
694 		g_assert (klass);
695 		g_assert (actual_method);
696 		g_assert (actual_method->klass == klass);
697 
698 		if (actual_method->is_inflated)
699 			declaring = mono_method_get_declaring_generic_method (actual_method);
700 		else
701 			declaring = NULL;
702 
703 		m = actual_method;
704 	}
705 
706 	if (m->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) {
707 		m = mono_marshal_get_synchronized_wrapper (m);
708 		need_rgctx_tramp = FALSE;
709 	}
710 
711 	/* Calls made through delegates on platforms without delegate trampolines */
712 	if (!code && mono_method_needs_static_rgctx_invoke (m, FALSE))
713 		need_rgctx_tramp = TRUE;
714 
715 	addr = compiled_method = mono_jit_compile_method (m, error);
716 	if (!addr)
717 		return NULL;
718 
719 	if (generic_virtual || variant_iface) {
720 		if (vt->klass->valuetype) /*FIXME is this required variant iface?*/
721 			need_unbox_tramp = TRUE;
722 	} else if (orig_vtable_slot) {
723 		if (m->klass->valuetype)
724 			need_unbox_tramp = TRUE;
725 	}
726 
727 	addr = mini_add_method_trampoline (m, compiled_method, need_rgctx_tramp, need_unbox_tramp);
728 
729 	if (generic_virtual || variant_iface) {
730 		MonoMethod *target = generic_virtual ? generic_virtual : variant_iface;
731 
732 		vtable_slot = orig_vtable_slot;
733 		g_assert (vtable_slot);
734 
735 		mono_method_add_generic_virtual_invocation (mono_domain_get (),
736 													vt, vtable_slot,
737 													target, addr);
738 
739 		return addr;
740 	}
741 
742 	/* the method was jumped to */
743 	if (!code) {
744 		MonoDomain *domain = mono_domain_get ();
745 
746 		/* Patch the got entries pointing to this method */
747 		/*
748 		 * We do this here instead of in mono_codegen () to cover the case when m
749 		 * was loaded from an aot image.
750 		 */
751 		if (domain_jit_info (domain)->jump_target_got_slot_hash) {
752 			GSList *list, *tmp;
753 
754 			mono_domain_lock (domain);
755 			list = (GSList *)g_hash_table_lookup (domain_jit_info (domain)->jump_target_got_slot_hash, m);
756 			if (list) {
757 				for (tmp = list; tmp; tmp = tmp->next) {
758 					gpointer *got_slot = (gpointer *)tmp->data;
759 					*got_slot = addr;
760 				}
761 				g_hash_table_remove (domain_jit_info (domain)->jump_target_got_slot_hash, m);
762 				g_slist_free (list);
763 			}
764 			mono_domain_unlock (domain);
765 		}
766 
767 		return addr;
768 	}
769 
770 	vtable_slot = orig_vtable_slot;
771 
772 	if (vtable_slot) {
773 		if (vtable_slot_to_patch && (mono_aot_is_got_entry (code, (guint8*)vtable_slot_to_patch) || mono_domain_owns_vtable_slot (mono_domain_get (), vtable_slot_to_patch))) {
774 			g_assert (*vtable_slot_to_patch);
775 			*vtable_slot_to_patch = mono_get_addr_from_ftnptr (addr);
776 		}
777 	} else {
778 		guint8 *plt_entry = mono_aot_get_plt_entry (code);
779 		gboolean no_patch = FALSE;
780 		MonoJitInfo *target_ji;
781 
782 		if (plt_entry) {
783 			if (generic_shared) {
784 				target_ji =
785 					mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (compiled_method), NULL);
786 				if (!ji)
787 					ji = mini_jit_info_table_find (mono_domain_get (), (char*)code, NULL);
788 
789 				if (ji && target_ji && generic_shared && ji->has_generic_jit_info && !target_ji->has_generic_jit_info) {
790 					no_patch = TRUE;
791 				}
792 			}
793 			if (!no_patch)
794 				mono_aot_patch_plt_entry (code, plt_entry, NULL, regs, (guint8 *)addr);
795 		} else {
796 			if (generic_shared) {
797 				if (m->wrapper_type != MONO_WRAPPER_NONE)
798 					m = mono_marshal_method_from_wrapper (m);
799 				//g_assert (mono_method_is_generic_sharable (m, FALSE));
800 			}
801 
802 			/* Patch calling code */
803 			target_ji =
804 				mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (compiled_method), NULL);
805 			if (!ji)
806 				ji = mini_jit_info_table_find (mono_domain_get (), (char*)code, NULL);
807 
808 			if (ji && target_ji && generic_shared && ji->has_generic_jit_info && !target_ji->has_generic_jit_info) {
809 				/*
810 				 * Can't patch the call as the caller is gshared, but the callee is not. Happens when
811 				 * generic sharing fails.
812 				 * FIXME: Performance problem.
813 				 */
814 				no_patch = TRUE;
815 			}
816 #if LLVM_API_VERSION > 100
817 			/* LLVM code doesn't make direct calls */
818 			if (ji && ji->from_llvm)
819 				no_patch = TRUE;
820 #endif
821 			if (!no_patch && mono_method_same_domain (ji, target_ji))
822 				mono_arch_patch_callsite ((guint8 *)ji->code_start, code, (guint8 *)addr);
823 		}
824 	}
825 
826 	return addr;
827 }
828 
829 /**
830  * mono_magic_trampoline:
831  *
832  * This trampoline handles normal calls from JITted code.
833  */
834 gpointer
mono_magic_trampoline(mgreg_t * regs,guint8 * code,gpointer arg,guint8 * tramp)835 mono_magic_trampoline (mgreg_t *regs, guint8 *code, gpointer arg, guint8* tramp)
836 {
837 	gpointer res;
838 	MonoError error;
839 
840 	MONO_REQ_GC_UNSAFE_MODE;
841 
842 	g_assert (mono_thread_is_gc_unsafe_mode ());
843 
844 	UnlockedIncrement (&trampoline_calls);
845 
846 	res = common_call_trampoline (regs, code, (MonoMethod *)arg, NULL, NULL, &error);
847 	if (!is_ok (&error)) {
848 		mono_error_set_pending_exception (&error);
849 		return NULL;
850 	}
851 
852 	return res;
853 }
854 
855 /**
856  * mono_vcall_trampoline:
857  *
858  * This trampoline handles virtual calls.
859  */
860 static gpointer
mono_vcall_trampoline(mgreg_t * regs,guint8 * code,int slot,guint8 * tramp)861 mono_vcall_trampoline (mgreg_t *regs, guint8 *code, int slot, guint8 *tramp)
862 {
863 	MONO_REQ_GC_UNSAFE_MODE;
864 
865 	MonoObject *this_arg;
866 	MonoVTable *vt;
867 	gpointer *vtable_slot;
868 	MonoMethod *m;
869 	MonoError error;
870 	gpointer addr, res = NULL;
871 
872 	UnlockedIncrement (&trampoline_calls);
873 
874 	/*
875 	 * We need to obtain the following pieces of information:
876 	 * - the method which needs to be compiled.
877 	 * - the vtable slot.
878 	 * We use one vtable trampoline per vtable slot index, so we need only the vtable,
879 	 * the other two can be computed from the vtable + the slot index.
880 	 */
881 
882 	/*
883 	 * Obtain the vtable from the 'this' arg.
884 	 */
885 	this_arg = (MonoObject *)mono_arch_get_this_arg_from_call (regs, code);
886 	g_assert (this_arg);
887 
888 	vt = this_arg->vtable;
889 
890 	if (slot >= 0) {
891 		/* Normal virtual call */
892 		vtable_slot = &(vt->vtable [slot]);
893 
894 		/* Avoid loading metadata or creating a generic vtable if possible */
895 		addr = mono_aot_get_method_from_vt_slot (mono_domain_get (), vt, slot, &error);
896 		goto_if_nok (&error, leave);
897 		if (addr && !vt->klass->valuetype) {
898 			if (mono_domain_owns_vtable_slot (mono_domain_get (), vtable_slot))
899 				*vtable_slot = addr;
900 
901 			return mono_create_ftnptr (mono_domain_get (), addr);
902 		}
903 
904 		/*
905 		 * Bug #616463 (see
906 		 * is_generic_method_definition() above) also
907 		 * goes away if we do a
908 		 * mono_class_setup_vtable (vt->klass) here,
909 		 * because we then inflate the method
910 		 * correctly, put it in the cache, and the
911 		 * "wrong" inflation invocation still looks up
912 		 * the correctly inflated method.
913 		 *
914 		 * The hack above seems more stable and
915 		 * trustworthy.
916 		 */
917 		m = mono_class_get_vtable_entry (vt->klass, slot);
918 	} else {
919 		/* IMT call */
920 		vtable_slot = &(((gpointer*)vt) [slot]);
921 
922 		m = NULL;
923 	}
924 
925 	res = common_call_trampoline (regs, code, m, vt, vtable_slot, &error);
926 leave:
927 	if (!mono_error_ok (&error)) {
928 		mono_error_set_pending_exception (&error);
929 		return NULL;
930 	}
931 	return res;
932 }
933 
934 #ifndef DISABLE_REMOTING
935 gpointer
mono_generic_virtual_remoting_trampoline(mgreg_t * regs,guint8 * code,MonoMethod * m,guint8 * tramp)936 mono_generic_virtual_remoting_trampoline (mgreg_t *regs, guint8 *code, MonoMethod *m, guint8 *tramp)
937 {
938 	MONO_REQ_GC_UNSAFE_MODE;
939 
940 	MonoError error;
941 	MonoGenericContext context = { NULL, NULL };
942 	MonoMethod *imt_method, *declaring;
943 	gpointer addr;
944 
945 	UnlockedIncrement (&trampoline_calls);
946 
947 	g_assert (m->is_generic);
948 
949 	if (m->is_inflated)
950 		declaring = mono_method_get_declaring_generic_method (m);
951 	else
952 		declaring = m;
953 
954 	if (mono_class_is_ginst (m->klass))
955 		context.class_inst = mono_class_get_generic_class (m->klass)->context.class_inst;
956 	else
957 		g_assert (!mono_class_is_gtd (m->klass));
958 
959 	imt_method = mono_arch_find_imt_method (regs, code);
960 	if (imt_method->is_inflated)
961 		context.method_inst = ((MonoMethodInflated*)imt_method)->context.method_inst;
962 	m = mono_class_inflate_generic_method_checked (declaring, &context, &error);
963 	g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */;
964 	m = mono_marshal_get_remoting_invoke_with_check (m);
965 
966 	addr = mono_jit_compile_method (m, &error);
967 	if (!mono_error_ok (&error)) {
968 		mono_error_set_pending_exception (&error);
969 		return NULL;
970 	}
971 	g_assert (addr);
972 
973 	return addr;
974 }
975 #endif
976 
977 /**
978  * mono_aot_trampoline:
979  *
980  * This trampoline handles calls made from AOT code. We try to bypass the
981  * normal JIT compilation logic to avoid loading the metadata for the method.
982  */
983 #ifdef MONO_ARCH_AOT_SUPPORTED
984 gpointer
mono_aot_trampoline(mgreg_t * regs,guint8 * code,guint8 * token_info,guint8 * tramp)985 mono_aot_trampoline (mgreg_t *regs, guint8 *code, guint8 *token_info,
986 					 guint8* tramp)
987 {
988 	MONO_REQ_GC_UNSAFE_MODE;
989 
990 	MonoImage *image;
991 	guint32 token;
992 	MonoMethod *method = NULL;
993 	gpointer addr;
994 	guint8 *plt_entry;
995 	MonoError error;
996 
997 	UnlockedIncrement (&trampoline_calls);
998 
999 	image = (MonoImage *)*(gpointer*)(gpointer)token_info;
1000 	token_info += sizeof (gpointer);
1001 	token = *(guint32*)(gpointer)token_info;
1002 
1003 	addr = mono_aot_get_method_from_token (mono_domain_get (), image, token, &error);
1004 	if (!is_ok (&error))
1005 		mono_error_cleanup (&error);
1006 	if (!addr) {
1007 		method = mono_get_method_checked (image, token, NULL, NULL, &error);
1008 		if (!method)
1009 			g_error ("Could not load AOT trampoline due to %s", mono_error_get_message (&error));
1010 
1011 		/* Use the generic code */
1012 		return mono_magic_trampoline (regs, code, method, tramp);
1013 	}
1014 
1015 	addr = mono_create_ftnptr (mono_domain_get (), addr);
1016 
1017 	/* This is a normal call through a PLT entry */
1018 	plt_entry = mono_aot_get_plt_entry (code);
1019 	g_assert (plt_entry);
1020 
1021 	mono_aot_patch_plt_entry (code, plt_entry, NULL, regs, (guint8 *)addr);
1022 
1023 	return addr;
1024 }
1025 
1026 /*
1027  * mono_aot_plt_trampoline:
1028  *
1029  *   This trampoline handles calls made from AOT code through the PLT table.
1030  */
1031 gpointer
mono_aot_plt_trampoline(mgreg_t * regs,guint8 * code,guint8 * aot_module,guint8 * tramp)1032 mono_aot_plt_trampoline (mgreg_t *regs, guint8 *code, guint8 *aot_module,
1033 						 guint8* tramp)
1034 {
1035 	MONO_REQ_GC_UNSAFE_MODE;
1036 
1037 	guint32 plt_info_offset = mono_aot_get_plt_info_offset (regs, code);
1038 	gpointer res;
1039 	MonoError error;
1040 
1041 	UnlockedIncrement (&trampoline_calls);
1042 
1043 	res = mono_aot_plt_resolve (aot_module, plt_info_offset, code, &error);
1044 	if (!res) {
1045 		if (!mono_error_ok (&error)) {
1046 			mono_error_set_pending_exception (&error);
1047 			return NULL;
1048 		}
1049 		// FIXME: Error handling (how ?)
1050 		g_assert (res);
1051 	}
1052 
1053 	return res;
1054 }
1055 #endif
1056 
1057 static gpointer
mono_rgctx_lazy_fetch_trampoline(mgreg_t * regs,guint8 * code,gpointer data,guint8 * tramp)1058 mono_rgctx_lazy_fetch_trampoline (mgreg_t *regs, guint8 *code, gpointer data, guint8 *tramp)
1059 {
1060 	MONO_REQ_GC_UNSAFE_MODE;
1061 
1062 	guint32 slot = GPOINTER_TO_UINT (data);
1063 	mgreg_t *r = (mgreg_t*)regs;
1064 	gpointer arg = (gpointer)(gssize)r [MONO_ARCH_VTABLE_REG];
1065 	guint32 index = MONO_RGCTX_SLOT_INDEX (slot);
1066 	gboolean mrgctx = MONO_RGCTX_SLOT_IS_MRGCTX (slot);
1067 	MonoError error;
1068 	gpointer res;
1069 
1070 	UnlockedIncrement (&trampoline_calls);
1071 	UnlockedIncrement (&rgctx_unmanaged_lookups);
1072 
1073 	if (mrgctx)
1074 		res = mono_method_fill_runtime_generic_context ((MonoMethodRuntimeGenericContext *)arg, index, &error);
1075 	else
1076 		res = mono_class_fill_runtime_generic_context ((MonoVTable *)arg, index, &error);
1077 	if (!mono_error_ok (&error)) {
1078 		mono_error_set_pending_exception (&error);
1079 		return NULL;
1080 	}
1081 	return res;
1082 }
1083 
1084 /**
1085  * mono_delegate_trampoline:
1086  *
1087  *   This trampoline handles calls made to Delegate:Invoke ().
1088  * This is called once the first time a delegate is invoked, so it must be fast.
1089  */
1090 gpointer
mono_delegate_trampoline(mgreg_t * regs,guint8 * code,gpointer * arg,guint8 * tramp)1091 mono_delegate_trampoline (mgreg_t *regs, guint8 *code, gpointer *arg, guint8* tramp)
1092 {
1093 	MONO_REQ_GC_UNSAFE_MODE;
1094 
1095 	MonoDomain *domain = mono_domain_get ();
1096 	MonoDelegate *delegate;
1097 	MonoJitInfo *ji;
1098 	MonoMethod *m;
1099 	MonoMethod *method = NULL;
1100 	MonoError error;
1101 	gboolean multicast, callvirt = FALSE, closed_over_null = FALSE;
1102 	gboolean need_rgctx_tramp = FALSE;
1103 	gboolean need_unbox_tramp = FALSE;
1104 	gboolean enable_caching = TRUE;
1105 	MonoDelegateTrampInfo *tramp_info = (MonoDelegateTrampInfo*)arg;
1106 	MonoMethod *invoke = tramp_info->invoke;
1107 	guint8 *impl_this = (guint8 *)tramp_info->impl_this;
1108 	guint8 *impl_nothis = (guint8 *)tramp_info->impl_nothis;
1109 	MonoError err;
1110 	MonoMethodSignature *sig;
1111 	gpointer addr, compiled_method;
1112 	gboolean is_remote = FALSE;
1113 
1114 	UnlockedIncrement (&trampoline_calls);
1115 
1116 	/* Obtain the delegate object according to the calling convention */
1117 	delegate = (MonoDelegate *)mono_arch_get_this_arg_from_call (regs, code);
1118 	g_assert (mono_class_has_parent (mono_object_class (delegate), mono_defaults.multicastdelegate_class));
1119 
1120 	if (delegate->method) {
1121 		method = delegate->method;
1122 
1123 		/*
1124 		 * delegate->method_ptr == NULL means the delegate was initialized by
1125 		 * mini_delegate_ctor, while != NULL means it is initialized by
1126 		 * mono_delegate_ctor_with_method (). In both cases, we need to add wrappers
1127 		 * (ctor_with_method () does this, but it doesn't store the wrapper back into
1128 		 * delegate->method).
1129 		 */
1130 #ifndef DISABLE_REMOTING
1131 		if (delegate->target && mono_object_is_transparent_proxy (delegate->target)) {
1132 			is_remote = TRUE;
1133 #ifndef DISABLE_COM
1134 			if (((MonoTransparentProxy *)delegate->target)->remote_class->proxy_class != mono_class_get_com_object_class () &&
1135 			   !mono_class_is_com_object (((MonoTransparentProxy *)delegate->target)->remote_class->proxy_class))
1136 #endif
1137 				method = mono_marshal_get_remoting_invoke (method);
1138 		}
1139 #endif
1140 		if (!is_remote) {
1141 			sig = tramp_info->sig;
1142 			if (!(sig && method == tramp_info->method)) {
1143 				error_init (&err);
1144 				sig = mono_method_signature_checked (method, &err);
1145 				if (!sig) {
1146 					mono_error_set_pending_exception (&err);
1147 					return NULL;
1148 				}
1149 			}
1150 
1151 			if (sig->hasthis && method->klass->valuetype) {
1152 				gboolean need_unbox = TRUE;
1153 
1154 				if (tramp_info->invoke_sig->param_count > sig->param_count && tramp_info->invoke_sig->params [0]->byref)
1155 					need_unbox = FALSE;
1156 
1157 				if (need_unbox) {
1158 					if (mono_aot_only)
1159 						need_unbox_tramp = TRUE;
1160 					else
1161 						method = mono_marshal_get_unbox_wrapper (method);
1162 				}
1163 			}
1164 		}
1165 	// If "delegate->method_ptr" is null mono_get_addr_from_ftnptr will fail if
1166 	// ftnptrs are being used.  "method" would end up null on archtitectures without
1167 	// ftnptrs so we can just skip this.
1168 	} else if (delegate->method_ptr) {
1169 		ji = mono_jit_info_table_find (domain, (char *)mono_get_addr_from_ftnptr (delegate->method_ptr));
1170 		if (ji)
1171 			method = jinfo_get_method (ji);
1172 	}
1173 
1174 	if (method) {
1175 		sig = tramp_info->sig;
1176 		if (!(sig && method == tramp_info->method)) {
1177 			error_init (&err);
1178 			sig = mono_method_signature_checked (method, &err);
1179 			if (!sig) {
1180 				mono_error_set_pending_exception (&err);
1181 				return NULL;
1182 			}
1183 		}
1184 
1185 		callvirt = !delegate->target && sig->hasthis;
1186 		if (callvirt)
1187 			closed_over_null = tramp_info->invoke_sig->param_count == sig->param_count;
1188 
1189 		if (callvirt && !closed_over_null) {
1190 			/*
1191 			 * The delegate needs to make a virtual call to the target method using its
1192 			 * first argument as the receiver. This is hard to support in full-aot, so
1193 			 * optimize it in some cases if possible.
1194 			 * If the target method is not virtual or is in a sealed class,
1195 			 * the vcall will call it directly.
1196 			 * If the call doesn't return a valuetype, then the vcall uses the same calling
1197 			 * convention as a normal call.
1198 			 */
1199 			if ((mono_class_is_sealed (method->klass) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)) && !MONO_TYPE_ISSTRUCT (sig->ret)) {
1200 				callvirt = FALSE;
1201 				enable_caching = FALSE;
1202 			}
1203 		}
1204 
1205 		if (delegate->target &&
1206 			method->flags & METHOD_ATTRIBUTE_VIRTUAL &&
1207 			method->flags & METHOD_ATTRIBUTE_ABSTRACT &&
1208 			mono_class_is_abstract (method->klass)) {
1209 			method = mono_object_get_virtual_method (delegate->target, method);
1210 			enable_caching = FALSE;
1211 		}
1212 
1213 		if (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
1214 			method = mono_marshal_get_synchronized_wrapper (method);
1215 
1216 		if (method == tramp_info->method)
1217 			need_rgctx_tramp = tramp_info->need_rgctx_tramp;
1218 		else if (mono_method_needs_static_rgctx_invoke (method, FALSE))
1219 			need_rgctx_tramp = TRUE;
1220 	}
1221 
1222 	/*
1223 	 * If the called address is a trampoline, replace it with the compiled method so
1224 	 * further calls don't have to go through the trampoline.
1225 	 */
1226 	if (method && !callvirt) {
1227 		/* Avoid the overhead of looking up an already compiled method if possible */
1228 		if (enable_caching && delegate->method_code && *delegate->method_code) {
1229 			delegate->method_ptr = *delegate->method_code;
1230 		} else {
1231 			compiled_method = addr = mono_jit_compile_method (method, &error);
1232 			if (!mono_error_ok (&error)) {
1233 				mono_error_set_pending_exception (&error);
1234 				return NULL;
1235 			}
1236 			addr = mini_add_method_trampoline (method, compiled_method, need_rgctx_tramp, need_unbox_tramp);
1237 			delegate->method_ptr = addr;
1238 			if (enable_caching && delegate->method_code)
1239 				*delegate->method_code = (guint8 *)delegate->method_ptr;
1240 		}
1241 	} else {
1242 		if (need_rgctx_tramp)
1243 			delegate->method_ptr = mono_create_static_rgctx_trampoline (method, delegate->method_ptr);
1244 	}
1245 
1246 	/* Necessary for !code condition to fallback to slow path */
1247 	code = NULL;
1248 
1249 	multicast = ((MonoMulticastDelegate*)delegate)->delegates != NULL;
1250 	if (!multicast && !callvirt) {
1251 		if (method && (method->flags & METHOD_ATTRIBUTE_STATIC) && mono_method_signature (method)->param_count == mono_method_signature (invoke)->param_count + 1)
1252 			/* Closed static delegate */
1253 			code = impl_this;
1254 		else
1255 			code = delegate->target ? impl_this : impl_nothis;
1256 	}
1257 
1258 	if (!code) {
1259 		/* The general, unoptimized case */
1260 		m = mono_marshal_get_delegate_invoke (invoke, delegate);
1261 		code = (guint8 *)mono_jit_compile_method (m, &error);
1262 		if (!mono_error_ok (&error)) {
1263 			mono_error_set_pending_exception (&error);
1264 			return NULL;
1265 		}
1266 		code = (guint8 *)mini_add_method_trampoline (m, code, mono_method_needs_static_rgctx_invoke (m, FALSE), FALSE);
1267 	}
1268 
1269 	delegate->invoke_impl = mono_get_addr_from_ftnptr (code);
1270 	if (enable_caching && !callvirt && tramp_info->method) {
1271 		tramp_info->method_ptr = delegate->method_ptr;
1272 		tramp_info->invoke_impl = delegate->invoke_impl;
1273 	}
1274 
1275 	return code;
1276 }
1277 
1278 /*
1279  * mono_get_trampoline_func:
1280  *
1281  *   Return the C function which needs to be called by the generic trampoline of type
1282  * TRAMP_TYPE.
1283  */
1284 gconstpointer
mono_get_trampoline_func(MonoTrampolineType tramp_type)1285 mono_get_trampoline_func (MonoTrampolineType tramp_type)
1286 {
1287 	switch (tramp_type) {
1288 	case MONO_TRAMPOLINE_JIT:
1289 	case MONO_TRAMPOLINE_JUMP:
1290 		return mono_magic_trampoline;
1291 	case MONO_TRAMPOLINE_RGCTX_LAZY_FETCH:
1292 		return mono_rgctx_lazy_fetch_trampoline;
1293 #ifdef MONO_ARCH_AOT_SUPPORTED
1294 	case MONO_TRAMPOLINE_AOT:
1295 		return mono_aot_trampoline;
1296 	case MONO_TRAMPOLINE_AOT_PLT:
1297 		return mono_aot_plt_trampoline;
1298 #endif
1299 	case MONO_TRAMPOLINE_DELEGATE:
1300 		return mono_delegate_trampoline;
1301 	case MONO_TRAMPOLINE_RESTORE_STACK_PROT:
1302 		return mono_altstack_restore_prot;
1303 #ifndef DISABLE_REMOTING
1304 	case MONO_TRAMPOLINE_GENERIC_VIRTUAL_REMOTING:
1305 		return mono_generic_virtual_remoting_trampoline;
1306 #endif
1307 	case MONO_TRAMPOLINE_VCALL:
1308 		return mono_vcall_trampoline;
1309 	default:
1310 		g_assert_not_reached ();
1311 		return NULL;
1312 	}
1313 }
1314 
1315 static guchar*
create_trampoline_code(MonoTrampolineType tramp_type)1316 create_trampoline_code (MonoTrampolineType tramp_type)
1317 {
1318 	MonoTrampInfo *info;
1319 	guchar *code;
1320 
1321 	code = mono_arch_create_generic_trampoline (tramp_type, &info, FALSE);
1322 	mono_tramp_info_register (info, NULL);
1323 
1324 	return code;
1325 }
1326 
1327 void
mono_trampolines_init(void)1328 mono_trampolines_init (void)
1329 {
1330 	mono_os_mutex_init_recursive (&trampolines_mutex);
1331 
1332 	if (mono_aot_only)
1333 		return;
1334 
1335 	mono_trampoline_code [MONO_TRAMPOLINE_JIT] = create_trampoline_code (MONO_TRAMPOLINE_JIT);
1336 	mono_trampoline_code [MONO_TRAMPOLINE_JUMP] = create_trampoline_code (MONO_TRAMPOLINE_JUMP);
1337 	mono_trampoline_code [MONO_TRAMPOLINE_RGCTX_LAZY_FETCH] = create_trampoline_code (MONO_TRAMPOLINE_RGCTX_LAZY_FETCH);
1338 #ifdef MONO_ARCH_AOT_SUPPORTED
1339 	mono_trampoline_code [MONO_TRAMPOLINE_AOT] = create_trampoline_code (MONO_TRAMPOLINE_AOT);
1340 	mono_trampoline_code [MONO_TRAMPOLINE_AOT_PLT] = create_trampoline_code (MONO_TRAMPOLINE_AOT_PLT);
1341 #endif
1342 	mono_trampoline_code [MONO_TRAMPOLINE_DELEGATE] = create_trampoline_code (MONO_TRAMPOLINE_DELEGATE);
1343 	mono_trampoline_code [MONO_TRAMPOLINE_RESTORE_STACK_PROT] = create_trampoline_code (MONO_TRAMPOLINE_RESTORE_STACK_PROT);
1344 #ifndef DISABLE_REMOTING
1345 	mono_trampoline_code [MONO_TRAMPOLINE_GENERIC_VIRTUAL_REMOTING] = create_trampoline_code (MONO_TRAMPOLINE_GENERIC_VIRTUAL_REMOTING);
1346 #endif
1347 	mono_trampoline_code [MONO_TRAMPOLINE_VCALL] = create_trampoline_code (MONO_TRAMPOLINE_VCALL);
1348 
1349 	mono_counters_register ("Calls to trampolines", MONO_COUNTER_JIT | MONO_COUNTER_INT, &trampoline_calls);
1350 	mono_counters_register ("JIT trampolines", MONO_COUNTER_JIT | MONO_COUNTER_INT, &jit_trampolines);
1351 	mono_counters_register ("Unbox trampolines", MONO_COUNTER_JIT | MONO_COUNTER_INT, &unbox_trampolines);
1352 	mono_counters_register ("Static rgctx trampolines", MONO_COUNTER_JIT | MONO_COUNTER_INT, &static_rgctx_trampolines);
1353 	mono_counters_register ("RGCTX unmanaged lookups", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_unmanaged_lookups);
1354 	mono_counters_register ("RGCTX num lazy fetch trampolines", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_num_lazy_fetch_trampolines);
1355 }
1356 
1357 void
mono_trampolines_cleanup(void)1358 mono_trampolines_cleanup (void)
1359 {
1360 	if (rgctx_lazy_fetch_trampoline_hash)
1361 		g_hash_table_destroy (rgctx_lazy_fetch_trampoline_hash);
1362 	if (rgctx_lazy_fetch_trampoline_hash_addr)
1363 		g_hash_table_destroy (rgctx_lazy_fetch_trampoline_hash_addr);
1364 
1365 	mono_os_mutex_destroy (&trampolines_mutex);
1366 }
1367 
1368 guint8 *
mono_get_trampoline_code(MonoTrampolineType tramp_type)1369 mono_get_trampoline_code (MonoTrampolineType tramp_type)
1370 {
1371 	g_assert (mono_trampoline_code [tramp_type]);
1372 
1373 	return mono_trampoline_code [tramp_type];
1374 }
1375 
1376 gpointer
mono_create_specific_trampoline(gpointer arg1,MonoTrampolineType tramp_type,MonoDomain * domain,guint32 * code_len)1377 mono_create_specific_trampoline (gpointer arg1, MonoTrampolineType tramp_type, MonoDomain *domain, guint32 *code_len)
1378 {
1379 	gpointer code;
1380 	guint32 len;
1381 
1382 	if (mono_aot_only)
1383 		code = mono_aot_create_specific_trampoline (mono_defaults.corlib, arg1, tramp_type, domain, &len);
1384 	else
1385 		code = mono_arch_create_specific_trampoline (arg1, tramp_type, domain, &len);
1386 	mono_lldb_save_specific_trampoline_info (arg1, tramp_type, domain, code, len);
1387 	if (code_len)
1388 		*code_len = len;
1389 	return code;
1390 }
1391 
1392 gpointer
mono_create_jump_trampoline(MonoDomain * domain,MonoMethod * method,gboolean add_sync_wrapper,MonoError * error)1393 mono_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper, MonoError *error)
1394 {
1395 	MonoJitInfo *ji;
1396 	gpointer code;
1397 	guint32 code_size = 0;
1398 
1399 	error_init (error);
1400 
1401 	if (mono_use_interpreter) {
1402 		gpointer ret = mini_get_interp_callbacks ()->create_trampoline (domain, method, error);
1403 		if (!mono_error_ok (error))
1404 			return NULL;
1405 		return ret;
1406 	}
1407 
1408 	code = mono_jit_find_compiled_method_with_jit_info (domain, method, &ji);
1409 	/*
1410 	 * We cannot recover the correct type of a shared generic
1411 	 * method from its native code address, so we use the
1412 	 * trampoline instead.
1413 	 * For synchronized methods, the trampoline adds the wrapper.
1414 	 */
1415 	if (code && !ji->has_generic_jit_info && !(method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED))
1416 		return code;
1417 
1418 	if (mono_llvm_only) {
1419 		code = mono_jit_compile_method (method, error);
1420 		if (!mono_error_ok (error))
1421 			return NULL;
1422 		return code;
1423 	}
1424 
1425 	mono_domain_lock (domain);
1426 	code = g_hash_table_lookup (domain_jit_info (domain)->jump_trampoline_hash, method);
1427 	mono_domain_unlock (domain);
1428 	if (code)
1429 		return code;
1430 
1431 	code = mono_create_specific_trampoline (method, MONO_TRAMPOLINE_JUMP, mono_domain_get (), &code_size);
1432 	g_assert (code_size);
1433 
1434 	ji = (MonoJitInfo *)mono_domain_alloc0 (domain, MONO_SIZEOF_JIT_INFO);
1435 	ji->code_start = code;
1436 	ji->code_size = code_size;
1437 	ji->d.method = method;
1438 
1439 	/*
1440 	 * mono_delegate_ctor needs to find the method metadata from the
1441 	 * trampoline address, so we save it here.
1442 	 */
1443 
1444 	mono_jit_info_table_add (domain, ji);
1445 
1446 	mono_domain_lock (domain);
1447 	g_hash_table_insert (domain_jit_info (domain)->jump_trampoline_hash, method, ji->code_start);
1448 	mono_domain_unlock (domain);
1449 
1450 	return ji->code_start;
1451 }
1452 
1453 static void
method_not_found(void)1454 method_not_found (void)
1455 {
1456 	g_assert_not_reached ();
1457 }
1458 
1459 gpointer
mono_create_jit_trampoline(MonoDomain * domain,MonoMethod * method,MonoError * error)1460 mono_create_jit_trampoline (MonoDomain *domain, MonoMethod *method, MonoError *error)
1461 {
1462 	gpointer tramp;
1463 
1464 	error_init (error);
1465 
1466 	if (mono_aot_only) {
1467 		if (mono_llvm_only && method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
1468 			method = mono_marshal_get_synchronized_wrapper (method);
1469 
1470 		/* Avoid creating trampolines if possible */
1471 		gpointer code = mono_jit_find_compiled_method (domain, method);
1472 
1473 		if (code)
1474 			return code;
1475 		if (mono_llvm_only) {
1476 			if (method->wrapper_type == MONO_WRAPPER_PROXY_ISINST)
1477 				/* These wrappers are not generated */
1478 				return method_not_found;
1479 			/* Methods are lazily initialized on first call, so this can't lead recursion */
1480 			code = mono_jit_compile_method (method, error);
1481 			if (!mono_error_ok (error))
1482 				return NULL;
1483 			return code;
1484 		}
1485 	}
1486 
1487 	mono_domain_lock (domain);
1488 	tramp = g_hash_table_lookup (domain_jit_info (domain)->jit_trampoline_hash, method);
1489 	mono_domain_unlock (domain);
1490 	if (tramp)
1491 		return tramp;
1492 
1493 	tramp = mono_create_specific_trampoline (method, MONO_TRAMPOLINE_JIT, domain, NULL);
1494 
1495 	mono_domain_lock (domain);
1496 	g_hash_table_insert (domain_jit_info (domain)->jit_trampoline_hash, method, tramp);
1497 	UnlockedIncrement (&jit_trampolines);
1498 	mono_domain_unlock (domain);
1499 
1500 	return tramp;
1501 }
1502 
1503 gpointer
mono_create_jit_trampoline_from_token(MonoImage * image,guint32 token)1504 mono_create_jit_trampoline_from_token (MonoImage *image, guint32 token)
1505 {
1506 	gpointer tramp;
1507 
1508 	MonoDomain *domain = mono_domain_get ();
1509 	guint8 *buf, *start;
1510 
1511 	buf = start = (guint8 *)mono_domain_alloc0 (domain, 2 * sizeof (gpointer));
1512 
1513 	*(gpointer*)(gpointer)buf = image;
1514 	buf += sizeof (gpointer);
1515 	*(guint32*)(gpointer)buf = token;
1516 
1517 	tramp = mono_create_specific_trampoline (start, MONO_TRAMPOLINE_AOT, domain, NULL);
1518 
1519 	UnlockedIncrement (&jit_trampolines);
1520 
1521 	return tramp;
1522 }
1523 
1524 
1525 /*
1526  * mono_create_delegate_trampoline_info:
1527  *
1528  *  Create a trampoline info structure for the KLASS+METHOD pair.
1529  */
1530 MonoDelegateTrampInfo*
mono_create_delegate_trampoline_info(MonoDomain * domain,MonoClass * klass,MonoMethod * method)1531 mono_create_delegate_trampoline_info (MonoDomain *domain, MonoClass *klass, MonoMethod *method)
1532 {
1533 	MonoMethod *invoke;
1534 	MonoError error;
1535 	MonoDelegateTrampInfo *tramp_info;
1536 	MonoClassMethodPair pair, *dpair;
1537 	guint32 code_size = 0;
1538 
1539 	pair.klass = klass;
1540 	pair.method = method;
1541 	mono_domain_lock (domain);
1542 	tramp_info = (MonoDelegateTrampInfo *)g_hash_table_lookup (domain_jit_info (domain)->delegate_trampoline_hash, &pair);
1543 	mono_domain_unlock (domain);
1544 	if (tramp_info)
1545 		return tramp_info;
1546 
1547 	invoke = mono_get_delegate_invoke (klass);
1548 	g_assert (invoke);
1549 
1550 	tramp_info = (MonoDelegateTrampInfo *)mono_domain_alloc0 (domain, sizeof (MonoDelegateTrampInfo));
1551 	tramp_info->invoke = invoke;
1552 	tramp_info->invoke_sig = mono_method_signature (invoke);
1553 	tramp_info->impl_this = mono_arch_get_delegate_invoke_impl (mono_method_signature (invoke), TRUE);
1554 	tramp_info->impl_nothis = mono_arch_get_delegate_invoke_impl (mono_method_signature (invoke), FALSE);
1555 	tramp_info->method = method;
1556 	if (method) {
1557 		error_init (&error);
1558 		tramp_info->sig = mono_method_signature_checked (method, &error);
1559 		tramp_info->need_rgctx_tramp = mono_method_needs_static_rgctx_invoke (method, FALSE);
1560 	}
1561 	tramp_info->invoke_impl = mono_create_specific_trampoline (tramp_info, MONO_TRAMPOLINE_DELEGATE, domain, &code_size);
1562 	g_assert (code_size);
1563 
1564 	dpair = (MonoClassMethodPair *)mono_domain_alloc0 (domain, sizeof (MonoClassMethodPair));
1565 	memcpy (dpair, &pair, sizeof (MonoClassMethodPair));
1566 
1567 	/* store trampoline address */
1568 	mono_domain_lock (domain);
1569 	g_hash_table_insert (domain_jit_info (domain)->delegate_trampoline_hash, dpair, tramp_info);
1570 	mono_domain_unlock (domain);
1571 
1572 	return tramp_info;
1573 }
1574 
1575 static void
no_delegate_trampoline(void)1576 no_delegate_trampoline (void)
1577 {
1578 	g_assert_not_reached ();
1579 }
1580 
1581 gpointer
mono_create_delegate_trampoline(MonoDomain * domain,MonoClass * klass)1582 mono_create_delegate_trampoline (MonoDomain *domain, MonoClass *klass)
1583 {
1584 	if (mono_llvm_only || mono_use_interpreter)
1585 		return no_delegate_trampoline;
1586 
1587 	return mono_create_delegate_trampoline_info (domain, klass, NULL)->invoke_impl;
1588 }
1589 
1590 gpointer
mono_create_delegate_virtual_trampoline(MonoDomain * domain,MonoClass * klass,MonoMethod * method)1591 mono_create_delegate_virtual_trampoline (MonoDomain *domain, MonoClass *klass, MonoMethod *method)
1592 {
1593 	MonoMethod *invoke = mono_get_delegate_invoke (klass);
1594 	g_assert (invoke);
1595 
1596 	return mono_get_delegate_virtual_invoke_impl (mono_method_signature (invoke), method);
1597 }
1598 
1599 gpointer
mono_create_rgctx_lazy_fetch_trampoline(guint32 offset)1600 mono_create_rgctx_lazy_fetch_trampoline (guint32 offset)
1601 {
1602 	MonoTrampInfo *info;
1603 	gpointer tramp, ptr;
1604 
1605 	mono_trampolines_lock ();
1606 	if (rgctx_lazy_fetch_trampoline_hash)
1607 		tramp = g_hash_table_lookup (rgctx_lazy_fetch_trampoline_hash, GUINT_TO_POINTER (offset));
1608 	else
1609 		tramp = NULL;
1610 	mono_trampolines_unlock ();
1611 	if (tramp)
1612 		return tramp;
1613 
1614 	if (mono_aot_only) {
1615 		ptr = mono_aot_get_lazy_fetch_trampoline (offset);
1616 	} else {
1617 		tramp = mono_arch_create_rgctx_lazy_fetch_trampoline (offset, &info, FALSE);
1618 		mono_tramp_info_register (info, NULL);
1619 		ptr = mono_create_ftnptr (mono_get_root_domain (), tramp);
1620 	}
1621 
1622 	mono_trampolines_lock ();
1623 	if (!rgctx_lazy_fetch_trampoline_hash) {
1624 		rgctx_lazy_fetch_trampoline_hash = g_hash_table_new (NULL, NULL);
1625 		rgctx_lazy_fetch_trampoline_hash_addr = g_hash_table_new (NULL, NULL);
1626 	}
1627 	g_hash_table_insert (rgctx_lazy_fetch_trampoline_hash, GUINT_TO_POINTER (offset), ptr);
1628 	g_assert (offset != -1);
1629 	g_hash_table_insert (rgctx_lazy_fetch_trampoline_hash_addr, ptr, GUINT_TO_POINTER (offset + 1));
1630 	rgctx_num_lazy_fetch_trampolines ++;
1631 	mono_trampolines_unlock ();
1632 
1633 	return ptr;
1634 }
1635 
1636 guint32
mono_find_rgctx_lazy_fetch_trampoline_by_addr(gconstpointer addr)1637 mono_find_rgctx_lazy_fetch_trampoline_by_addr (gconstpointer addr)
1638 {
1639 	int offset;
1640 
1641 	mono_trampolines_lock ();
1642 	if (rgctx_lazy_fetch_trampoline_hash_addr) {
1643 		/* We store the real offset + 1 so we can detect when the lookup fails */
1644 		offset = GPOINTER_TO_INT (g_hash_table_lookup (rgctx_lazy_fetch_trampoline_hash_addr, addr));
1645 		if (offset)
1646 			offset -= 1;
1647 		else
1648 			offset = -1;
1649 	} else {
1650 		offset = -1;
1651 	}
1652 	mono_trampolines_unlock ();
1653 	return offset;
1654 }
1655 
1656 static const char*tramp_names [MONO_TRAMPOLINE_NUM] = {
1657 	"jit",
1658 	"jump",
1659 	"rgctx_lazy_fetch",
1660 	"aot",
1661 	"aot_plt",
1662 	"delegate",
1663 	"restore_stack_prot",
1664 	"generic_virtual_remoting",
1665 	"vcall"
1666 };
1667 
1668 /*
1669  * mono_get_generic_trampoline_simple_name:
1670  *
1671  */
1672 const char*
mono_get_generic_trampoline_simple_name(MonoTrampolineType tramp_type)1673 mono_get_generic_trampoline_simple_name (MonoTrampolineType tramp_type)
1674 {
1675 	return tramp_names [tramp_type];
1676 }
1677 
1678 /*
1679  * mono_get_generic_trampoline_name:
1680  *
1681  *   Returns a pointer to malloc-ed memory.
1682  */
1683 char*
mono_get_generic_trampoline_name(MonoTrampolineType tramp_type)1684 mono_get_generic_trampoline_name (MonoTrampolineType tramp_type)
1685 {
1686 	return g_strdup_printf ("generic_trampoline_%s", tramp_names [tramp_type]);
1687 }
1688 
1689 /*
1690  * mono_get_rgctx_fetch_trampoline_name:
1691  *
1692  *   Returns a pointer to malloc-ed memory.
1693  */
1694 char*
mono_get_rgctx_fetch_trampoline_name(int slot)1695 mono_get_rgctx_fetch_trampoline_name (int slot)
1696 {
1697 	gboolean mrgctx;
1698 	int index;
1699 
1700 	mrgctx = MONO_RGCTX_SLOT_IS_MRGCTX (slot);
1701 	index = MONO_RGCTX_SLOT_INDEX (slot);
1702 
1703 	return g_strdup_printf ("rgctx_fetch_trampoline_%s_%d", mrgctx ? "mrgctx" : "rgctx", index);
1704 }
1705 
1706 /*
1707  * mini_get_single_step_trampoline:
1708  *
1709  *   Return a trampoline which calls debugger_agent_single_step_from_context ().
1710  */
1711 gpointer
mini_get_single_step_trampoline(void)1712 mini_get_single_step_trampoline (void)
1713 {
1714 	static gpointer trampoline;
1715 
1716 	if (!trampoline) {
1717 		gpointer tramp;
1718 
1719 		if (mono_aot_only) {
1720 			tramp = mono_aot_get_trampoline ("sdb_single_step_trampoline");
1721 		} else {
1722 #ifdef MONO_ARCH_HAVE_SDB_TRAMPOLINES
1723 			MonoTrampInfo *info;
1724 			tramp = mono_arch_create_sdb_trampoline (TRUE, &info, FALSE);
1725 			mono_tramp_info_register (info, NULL);
1726 #else
1727 			tramp = NULL;
1728 			g_assert_not_reached ();
1729 #endif
1730 		}
1731 		mono_memory_barrier ();
1732 		trampoline = tramp;
1733 	}
1734 
1735 	return trampoline;
1736 }
1737 
1738 /*
1739  * mini_get_breakpoint_trampoline:
1740  *
1741  *   Return a trampoline which calls debugger_agent_breakpoint_from_context ().
1742  */
1743 gpointer
mini_get_breakpoint_trampoline(void)1744 mini_get_breakpoint_trampoline (void)
1745 {
1746 	static gpointer trampoline;
1747 
1748 	if (!trampoline) {
1749 		gpointer tramp;
1750 
1751 		if (mono_aot_only) {
1752 			tramp = mono_aot_get_trampoline ("sdb_breakpoint_trampoline");
1753 		} else {
1754 #ifdef MONO_ARCH_HAVE_SDB_TRAMPOLINES
1755 			MonoTrampInfo *info;
1756 			tramp = mono_arch_create_sdb_trampoline (FALSE, &info, FALSE);
1757 			mono_tramp_info_register (info, NULL);
1758 #else
1759 			tramp = NULL;
1760 			g_assert_not_reached ();
1761 #endif
1762 		}
1763 		mono_memory_barrier ();
1764 		trampoline = tramp;
1765 	}
1766 
1767 	return trampoline;
1768 }
1769