1 /**
2  * \file
3  * Support functions for generic sharing.
4  *
5  * Author:
6  *   Mark Probst (mark.probst@gmail.com)
7  *
8  * Copyright 2007-2011 Novell, Inc (http://www.novell.com)
9  * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
10  * Licensed under the MIT license. See LICENSE file in the project root for full license information.
11  */
12 
13 #include <config.h>
14 
15 #include <mono/metadata/class.h>
16 #include <mono/metadata/method-builder.h>
17 #include <mono/metadata/reflection-internals.h>
18 #include <mono/utils/mono-counters.h>
19 #include <mono/utils/atomic.h>
20 #include <mono/utils/unlocked.h>
21 
22 #include "mini.h"
23 #include "aot-runtime.h"
24 #include "mini-runtime.h"
25 
26 #define ALLOW_PARTIAL_SHARING TRUE
27 //#define ALLOW_PARTIAL_SHARING FALSE
28 
29 #if 0
30 #define DEBUG(...) __VA_ARGS__
31 #else
32 #define DEBUG(...)
33 #endif
34 
35 static void
36 mono_class_unregister_image_generic_subclasses (MonoImage *image, gpointer user_data);
37 
38 /* Counters */
39 static gint32 rgctx_template_num_allocated;
40 static gint32 rgctx_template_bytes_allocated;
41 static gint32 rgctx_oti_num_allocated;
42 static gint32 rgctx_oti_bytes_allocated;
43 static gint32 rgctx_oti_num_markers;
44 static gint32 rgctx_oti_num_data;
45 static gint32 rgctx_max_slot_number;
46 static gint32 rgctx_num_allocated;
47 static gint32 rgctx_num_arrays_allocated;
48 static gint32 rgctx_bytes_allocated;
49 static gint32 mrgctx_num_arrays_allocated;
50 static gint32 mrgctx_bytes_allocated;
51 static gint32 gsharedvt_num_trampolines;
52 
53 #define gshared_lock() mono_os_mutex_lock (&gshared_mutex)
54 #define gshared_unlock() mono_os_mutex_unlock (&gshared_mutex)
55 static mono_mutex_t gshared_mutex;
56 
57 static gboolean partial_supported = FALSE;
58 
59 static inline gboolean
partial_sharing_supported(void)60 partial_sharing_supported (void)
61 {
62 	if (!ALLOW_PARTIAL_SHARING)
63 		return FALSE;
64 	/* Enable this when AOT compiling or running in full-aot mode */
65 	if (mono_aot_only)
66 		return TRUE;
67 	if (partial_supported)
68 		return TRUE;
69 	return FALSE;
70 }
71 
72 static int
type_check_context_used(MonoType * type,gboolean recursive)73 type_check_context_used (MonoType *type, gboolean recursive)
74 {
75 	switch (mono_type_get_type (type)) {
76 	case MONO_TYPE_VAR:
77 		return MONO_GENERIC_CONTEXT_USED_CLASS;
78 	case MONO_TYPE_MVAR:
79 		return MONO_GENERIC_CONTEXT_USED_METHOD;
80 	case MONO_TYPE_SZARRAY:
81 		return mono_class_check_context_used (mono_type_get_class (type));
82 	case MONO_TYPE_ARRAY:
83 		return mono_class_check_context_used (mono_type_get_array_type (type)->eklass);
84 	case MONO_TYPE_CLASS:
85 		if (recursive)
86 			return mono_class_check_context_used (mono_type_get_class (type));
87 		else
88 			return 0;
89 	case MONO_TYPE_GENERICINST:
90 		if (recursive) {
91 			MonoGenericClass *gclass = type->data.generic_class;
92 
93 			g_assert (mono_class_is_gtd (gclass->container_class));
94 			return mono_generic_context_check_used (&gclass->context);
95 		} else {
96 			return 0;
97 		}
98 	default:
99 		return 0;
100 	}
101 }
102 
103 static int
inst_check_context_used(MonoGenericInst * inst)104 inst_check_context_used (MonoGenericInst *inst)
105 {
106 	int context_used = 0;
107 	int i;
108 
109 	if (!inst)
110 		return 0;
111 
112 	for (i = 0; i < inst->type_argc; ++i)
113 		context_used |= type_check_context_used (inst->type_argv [i], TRUE);
114 
115 	return context_used;
116 }
117 
118 /*
119  * mono_generic_context_check_used:
120  * @context: a generic context
121  *
122  * Checks whether the context uses a type variable.  Returns an int
123  * with the bit MONO_GENERIC_CONTEXT_USED_CLASS set to reflect whether
124  * the context's class instantiation uses type variables.
125  */
126 int
mono_generic_context_check_used(MonoGenericContext * context)127 mono_generic_context_check_used (MonoGenericContext *context)
128 {
129 	int context_used = 0;
130 
131 	context_used |= inst_check_context_used (context->class_inst);
132 	context_used |= inst_check_context_used (context->method_inst);
133 
134 	return context_used;
135 }
136 
137 /*
138  * mono_class_check_context_used:
139  * @class: a class
140  *
141  * Checks whether the class's generic context uses a type variable.
142  * Returns an int with the bit MONO_GENERIC_CONTEXT_USED_CLASS set to
143  * reflect whether the context's class instantiation uses type
144  * variables.
145  */
146 int
mono_class_check_context_used(MonoClass * klass)147 mono_class_check_context_used (MonoClass *klass)
148 {
149 	int context_used = 0;
150 
151 	context_used |= type_check_context_used (&klass->this_arg, FALSE);
152 	context_used |= type_check_context_used (&klass->byval_arg, FALSE);
153 
154 	if (mono_class_is_ginst (klass))
155 		context_used |= mono_generic_context_check_used (&mono_class_get_generic_class (klass)->context);
156 	else if (mono_class_is_gtd (klass))
157 		context_used |= mono_generic_context_check_used (&mono_class_get_generic_container (klass)->context);
158 
159 	return context_used;
160 }
161 
162 /*
163  * LOCKING: loader lock
164  */
165 static MonoRuntimeGenericContextInfoTemplate*
get_info_templates(MonoRuntimeGenericContextTemplate * template_,int type_argc)166 get_info_templates (MonoRuntimeGenericContextTemplate *template_, int type_argc)
167 {
168 	g_assert (type_argc >= 0);
169 	if (type_argc == 0)
170 		return template_->infos;
171 	return (MonoRuntimeGenericContextInfoTemplate *)g_slist_nth_data (template_->method_templates, type_argc - 1);
172 }
173 
174 /*
175  * LOCKING: loader lock
176  */
177 static void
set_info_templates(MonoImage * image,MonoRuntimeGenericContextTemplate * template_,int type_argc,MonoRuntimeGenericContextInfoTemplate * oti)178 set_info_templates (MonoImage *image, MonoRuntimeGenericContextTemplate *template_, int type_argc,
179 	MonoRuntimeGenericContextInfoTemplate *oti)
180 {
181 	g_assert (type_argc >= 0);
182 	if (type_argc == 0)
183 		template_->infos = oti;
184 	else {
185 		int length = g_slist_length (template_->method_templates);
186 		GSList *list;
187 
188 		/* FIXME: quadratic! */
189 		while (length < type_argc) {
190 			template_->method_templates = g_slist_append_image (image, template_->method_templates, NULL);
191 			length++;
192 		}
193 
194 		list = g_slist_nth (template_->method_templates, type_argc - 1);
195 		g_assert (list);
196 		list->data = oti;
197 	}
198 }
199 
200 /*
201  * LOCKING: loader lock
202  */
203 static int
template_get_max_argc(MonoRuntimeGenericContextTemplate * template_)204 template_get_max_argc (MonoRuntimeGenericContextTemplate *template_)
205 {
206 	return g_slist_length (template_->method_templates);
207 }
208 
209 /*
210  * LOCKING: loader lock
211  */
212 static MonoRuntimeGenericContextInfoTemplate*
rgctx_template_get_other_slot(MonoRuntimeGenericContextTemplate * template_,int type_argc,int slot)213 rgctx_template_get_other_slot (MonoRuntimeGenericContextTemplate *template_, int type_argc, int slot)
214 {
215 	int i;
216 	MonoRuntimeGenericContextInfoTemplate *oti;
217 
218 	g_assert (slot >= 0);
219 
220 	for (oti = get_info_templates (template_, type_argc), i = 0; i < slot; oti = oti->next, ++i) {
221 		if (!oti)
222 			return NULL;
223 	}
224 
225 	return oti;
226 }
227 
228 /*
229  * LOCKING: loader lock
230  */
231 static int
rgctx_template_num_infos(MonoRuntimeGenericContextTemplate * template_,int type_argc)232 rgctx_template_num_infos (MonoRuntimeGenericContextTemplate *template_, int type_argc)
233 {
234 	MonoRuntimeGenericContextInfoTemplate *oti;
235 	int i;
236 
237 	for (i = 0, oti = get_info_templates (template_, type_argc); oti; ++i, oti = oti->next)
238 		;
239 
240 	return i;
241 }
242 
243 /* Maps from uninstantiated generic classes to GList's of
244  * uninstantiated generic classes whose parent is the key class or an
245  * instance of the key class.
246  *
247  * LOCKING: loader lock
248  */
249 static GHashTable *generic_subclass_hash;
250 
251 /*
252  * LOCKING: templates lock
253  */
254 static void
class_set_rgctx_template(MonoClass * klass,MonoRuntimeGenericContextTemplate * rgctx_template)255 class_set_rgctx_template (MonoClass *klass, MonoRuntimeGenericContextTemplate *rgctx_template)
256 {
257 	if (!klass->image->rgctx_template_hash)
258 		klass->image->rgctx_template_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
259 
260 	g_hash_table_insert (klass->image->rgctx_template_hash, klass, rgctx_template);
261 }
262 
263 /*
264  * LOCKING: loader lock
265  */
266 static MonoRuntimeGenericContextTemplate*
class_lookup_rgctx_template(MonoClass * klass)267 class_lookup_rgctx_template (MonoClass *klass)
268 {
269 	MonoRuntimeGenericContextTemplate *template_;
270 
271 	if (!klass->image->rgctx_template_hash)
272 		return NULL;
273 
274 	template_ = (MonoRuntimeGenericContextTemplate *)g_hash_table_lookup (klass->image->rgctx_template_hash, klass);
275 
276 	return template_;
277 }
278 
279 /*
280  * LOCKING: loader lock
281  */
282 static void
register_generic_subclass(MonoClass * klass)283 register_generic_subclass (MonoClass *klass)
284 {
285 	MonoClass *parent = klass->parent;
286 	MonoClass *subclass;
287 	MonoRuntimeGenericContextTemplate *rgctx_template = class_lookup_rgctx_template (klass);
288 
289 	g_assert (rgctx_template);
290 
291 	if (mono_class_is_ginst (parent))
292 		parent = mono_class_get_generic_class (parent)->container_class;
293 
294 	if (!generic_subclass_hash)
295 		generic_subclass_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
296 
297 	subclass = (MonoClass *)g_hash_table_lookup (generic_subclass_hash, parent);
298 	rgctx_template->next_subclass = subclass;
299 	g_hash_table_insert (generic_subclass_hash, parent, klass);
300 }
301 
302 static void
move_subclasses_not_in_image_foreach_func(MonoClass * klass,MonoClass * subclass,MonoImage * image)303 move_subclasses_not_in_image_foreach_func (MonoClass *klass, MonoClass *subclass, MonoImage *image)
304 {
305 	MonoClass *new_list;
306 
307 	if (klass->image == image) {
308 		/* The parent class itself is in the image, so all the
309 		   subclasses must be in the image, too.  If not,
310 		   we're removing an image containing a class which
311 		   still has a subclass in another image. */
312 
313 		while (subclass) {
314 			g_assert (subclass->image == image);
315 			subclass = class_lookup_rgctx_template (subclass)->next_subclass;
316 		}
317 
318 		return;
319 	}
320 
321 	new_list = NULL;
322 	while (subclass) {
323 		MonoRuntimeGenericContextTemplate *subclass_template = class_lookup_rgctx_template (subclass);
324 		MonoClass *next = subclass_template->next_subclass;
325 
326 		if (subclass->image != image) {
327 			subclass_template->next_subclass = new_list;
328 			new_list = subclass;
329 		}
330 
331 		subclass = next;
332 	}
333 
334 	if (new_list)
335 		g_hash_table_insert (generic_subclass_hash, klass, new_list);
336 }
337 
338 /*
339  * mono_class_unregister_image_generic_subclasses:
340  * @image: an image
341  *
342  * Removes all classes of the image from the generic subclass hash.
343  * Must be called when an image is unloaded.
344  */
345 static void
mono_class_unregister_image_generic_subclasses(MonoImage * image,gpointer user_data)346 mono_class_unregister_image_generic_subclasses (MonoImage *image, gpointer user_data)
347 {
348 	GHashTable *old_hash;
349 
350 	//g_print ("unregistering image %s\n", image->name);
351 
352 	if (!generic_subclass_hash)
353 		return;
354 
355 	mono_loader_lock ();
356 
357 	old_hash = generic_subclass_hash;
358 	generic_subclass_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
359 
360 	g_hash_table_foreach (old_hash, (GHFunc)move_subclasses_not_in_image_foreach_func, image);
361 
362 	mono_loader_unlock ();
363 
364 	g_hash_table_destroy (old_hash);
365 }
366 
367 static MonoRuntimeGenericContextTemplate*
alloc_template(MonoClass * klass)368 alloc_template (MonoClass *klass)
369 {
370 	gint32 size = sizeof (MonoRuntimeGenericContextTemplate);
371 
372 	mono_atomic_inc_i32 (&rgctx_template_num_allocated);
373 	mono_atomic_fetch_add_i32 (&rgctx_template_bytes_allocated, size);
374 
375 	return (MonoRuntimeGenericContextTemplate *)mono_image_alloc0 (klass->image, size);
376 }
377 
378 /* LOCKING: Takes the loader lock */
379 static MonoRuntimeGenericContextInfoTemplate*
alloc_oti(MonoImage * image)380 alloc_oti (MonoImage *image)
381 {
382 	gint32 size = sizeof (MonoRuntimeGenericContextInfoTemplate);
383 
384 	mono_atomic_inc_i32 (&rgctx_oti_num_allocated);
385 	mono_atomic_fetch_add_i32 (&rgctx_oti_bytes_allocated, size);
386 
387 	return (MonoRuntimeGenericContextInfoTemplate *)mono_image_alloc0 (image, size);
388 }
389 
390 #define MONO_RGCTX_SLOT_USED_MARKER	((gpointer)&mono_defaults.object_class->byval_arg)
391 
392 /*
393  * Return true if this info type has the notion of identify.
394  *
395  * Some info types expect that each insert results in a new slot been assigned.
396  */
397 static int
info_has_identity(MonoRgctxInfoType info_type)398 info_has_identity (MonoRgctxInfoType info_type)
399 {
400 	return info_type != MONO_RGCTX_INFO_CAST_CACHE;
401 }
402 
403 /*
404  * LOCKING: loader lock
405  */
406 #if defined(HOST_ANDROID) && defined(TARGET_ARM)
407 /* work around for HW bug on Nexus9 when running on armv7 */
408 #ifdef __clang__
409 static __attribute__ ((optnone)) void
410 #else
411 /* gcc */
412 static __attribute__ ((optimize("O0"))) void
413 #endif
414 #else
415 static void
416 #endif
rgctx_template_set_slot(MonoImage * image,MonoRuntimeGenericContextTemplate * template_,int type_argc,int slot,gpointer data,MonoRgctxInfoType info_type)417 rgctx_template_set_slot (MonoImage *image, MonoRuntimeGenericContextTemplate *template_, int type_argc,
418 	int slot, gpointer data, MonoRgctxInfoType info_type)
419 {
420 	int i;
421 	MonoRuntimeGenericContextInfoTemplate *list = get_info_templates (template_, type_argc);
422 	MonoRuntimeGenericContextInfoTemplate **oti = &list;
423 
424 	g_assert (slot >= 0);
425 	g_assert (data);
426 
427 	i = 0;
428 	while (i <= slot) {
429 		if (i > 0)
430 			oti = &(*oti)->next;
431 		if (!*oti)
432 			*oti = alloc_oti (image);
433 		++i;
434 	}
435 
436 	g_assert (!(*oti)->data);
437 	(*oti)->data = data;
438 	(*oti)->info_type = info_type;
439 
440 	set_info_templates (image, template_, type_argc, list);
441 
442 	/* interlocked by loader lock (by definition) */
443 	if (data == MONO_RGCTX_SLOT_USED_MARKER)
444 		UnlockedIncrement (&rgctx_oti_num_markers);
445 	else
446 		UnlockedIncrement (&rgctx_oti_num_data);
447 }
448 
449 /*
450  * mono_method_get_declaring_generic_method:
451  * @method: an inflated method
452  *
453  * Returns an inflated method's declaring method.
454  */
455 MonoMethod*
mono_method_get_declaring_generic_method(MonoMethod * method)456 mono_method_get_declaring_generic_method (MonoMethod *method)
457 {
458 	MonoMethodInflated *inflated;
459 
460 	g_assert (method->is_inflated);
461 
462 	inflated = (MonoMethodInflated*)method;
463 
464 	return inflated->declaring;
465 }
466 
467 /*
468  * mono_class_get_method_generic:
469  * @klass: a class
470  * @method: a method
471  *
472  * Given a class and a generic method, which has to be of an
473  * instantiation of the same class that klass is an instantiation of,
474  * returns the corresponding method in klass.  Example:
475  *
476  * klass is Gen<string>
477  * method is Gen<object>.work<int>
478  *
479  * returns: Gen<string>.work<int>
480  */
481 MonoMethod*
mono_class_get_method_generic(MonoClass * klass,MonoMethod * method)482 mono_class_get_method_generic (MonoClass *klass, MonoMethod *method)
483 {
484 	MonoMethod *declaring, *m;
485 	int i;
486 
487 	if (method->is_inflated)
488 		declaring = mono_method_get_declaring_generic_method (method);
489 	else
490 		declaring = method;
491 
492 	m = NULL;
493 	if (mono_class_is_ginst (klass))
494 		m = mono_class_get_inflated_method (klass, declaring);
495 
496 	if (!m) {
497 		mono_class_setup_methods (klass);
498 		if (mono_class_has_failure (klass))
499 			return NULL;
500 		int mcount = mono_class_get_method_count (klass);
501 		for (i = 0; i < mcount; ++i) {
502 			m = klass->methods [i];
503 			if (m == declaring)
504 				break;
505 			if (m->is_inflated && mono_method_get_declaring_generic_method (m) == declaring)
506 				break;
507 		}
508 		if (i >= mcount)
509 			return NULL;
510 	}
511 
512 	if (method != declaring) {
513 		MonoError error;
514 		MonoGenericContext context;
515 
516 		context.class_inst = NULL;
517 		context.method_inst = mono_method_get_context (method)->method_inst;
518 
519 		m = mono_class_inflate_generic_method_checked (m, &context, &error);
520 		g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
521 	}
522 
523 	return m;
524 }
525 
526 static gpointer
inflate_info(MonoRuntimeGenericContextInfoTemplate * oti,MonoGenericContext * context,MonoClass * klass,gboolean temporary)527 inflate_info (MonoRuntimeGenericContextInfoTemplate *oti, MonoGenericContext *context, MonoClass *klass, gboolean temporary)
528 {
529 	gpointer data = oti->data;
530 	MonoRgctxInfoType info_type = oti->info_type;
531 	MonoError error;
532 
533 	g_assert (data);
534 
535 	if (data == MONO_RGCTX_SLOT_USED_MARKER)
536 		return MONO_RGCTX_SLOT_USED_MARKER;
537 
538 	switch (info_type)
539 	{
540 	case MONO_RGCTX_INFO_STATIC_DATA:
541 	case MONO_RGCTX_INFO_KLASS:
542 	case MONO_RGCTX_INFO_ELEMENT_KLASS:
543 	case MONO_RGCTX_INFO_VTABLE:
544 	case MONO_RGCTX_INFO_TYPE:
545 	case MONO_RGCTX_INFO_REFLECTION_TYPE:
546 	case MONO_RGCTX_INFO_CAST_CACHE:
547 	case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
548 	case MONO_RGCTX_INFO_VALUE_SIZE:
549 	case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
550 	case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS:
551 	case MONO_RGCTX_INFO_MEMCPY:
552 	case MONO_RGCTX_INFO_BZERO:
553 	case MONO_RGCTX_INFO_LOCAL_OFFSET:
554 	case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
555 	case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: {
556 		gpointer result = mono_class_inflate_generic_type_with_mempool (temporary ? NULL : klass->image,
557 			(MonoType *)data, context, &error);
558 		if (!mono_error_ok (&error)) /*FIXME proper error handling */
559 			g_error ("Could not inflate generic type due to %s", mono_error_get_message (&error));
560 		return result;
561 	}
562 
563 	case MONO_RGCTX_INFO_METHOD:
564 	case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
565 	case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER:
566 	case MONO_RGCTX_INFO_METHOD_RGCTX:
567 	case MONO_RGCTX_INFO_METHOD_CONTEXT:
568 	case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
569 	case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE: {
570 		MonoMethod *method = (MonoMethod *)data;
571 		MonoMethod *inflated_method;
572 		MonoType *inflated_type = mono_class_inflate_generic_type_checked (&method->klass->byval_arg, context, &error);
573 		mono_error_assert_ok (&error); /* FIXME don't swallow the error */
574 
575 		MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
576 
577 		mono_metadata_free_type (inflated_type);
578 
579 		mono_class_init (inflated_class);
580 
581 		g_assert (!method->wrapper_type);
582 
583 		if (inflated_class->byval_arg.type == MONO_TYPE_ARRAY ||
584 				inflated_class->byval_arg.type == MONO_TYPE_SZARRAY) {
585 			inflated_method = mono_method_search_in_array_class (inflated_class,
586 				method->name, method->signature);
587 		} else {
588 			MonoError error;
589 			inflated_method = mono_class_inflate_generic_method_checked (method, context, &error);
590 			g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
591 		}
592 		mono_class_init (inflated_method->klass);
593 		g_assert (inflated_method->klass == inflated_class);
594 		return inflated_method;
595 	}
596 	case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: {
597 		MonoGSharedVtMethodInfo *oinfo = (MonoGSharedVtMethodInfo *)data;
598 		MonoGSharedVtMethodInfo *res;
599 		MonoDomain *domain = mono_domain_get ();
600 		int i;
601 
602 		res = (MonoGSharedVtMethodInfo *)mono_domain_alloc0 (domain, sizeof (MonoGSharedVtMethodInfo));
603 		/*
604 		res->nlocals = info->nlocals;
605 		res->locals_types = g_new0 (MonoType*, info->nlocals);
606 		for (i = 0; i < info->nlocals; ++i)
607 			res->locals_types [i] = mono_class_inflate_generic_type (info->locals_types [i], context);
608 		*/
609 		res->num_entries = oinfo->num_entries;
610 		res->entries = (MonoRuntimeGenericContextInfoTemplate *)mono_domain_alloc0 (domain, sizeof (MonoRuntimeGenericContextInfoTemplate) * oinfo->num_entries);
611 		for (i = 0; i < oinfo->num_entries; ++i) {
612 			MonoRuntimeGenericContextInfoTemplate *otemplate = &oinfo->entries [i];
613 			MonoRuntimeGenericContextInfoTemplate *template_ = &res->entries [i];
614 
615 			memcpy (template_, otemplate, sizeof (MonoRuntimeGenericContextInfoTemplate));
616 			template_->data = inflate_info (template_, context, klass, FALSE);
617 		}
618 		return res;
619 	}
620 	case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
621 	case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: {
622 		MonoJumpInfoGSharedVtCall *info = (MonoJumpInfoGSharedVtCall *)data;
623 		MonoMethod *method = info->method;
624 		MonoMethod *inflated_method;
625 		MonoType *inflated_type = mono_class_inflate_generic_type_checked (&method->klass->byval_arg, context, &error);
626 		mono_error_assert_ok (&error); /* FIXME don't swallow the error */
627 		WrapperInfo *winfo = NULL;
628 
629 		MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
630 		MonoJumpInfoGSharedVtCall *res;
631 		MonoDomain *domain = mono_domain_get ();
632 
633 		res = (MonoJumpInfoGSharedVtCall *)mono_domain_alloc0 (domain, sizeof (MonoJumpInfoGSharedVtCall));
634 		/* Keep the original signature */
635 		res->sig = info->sig;
636 
637 		mono_metadata_free_type (inflated_type);
638 
639 		mono_class_init (inflated_class);
640 
641 		if (method->wrapper_type) {
642 			winfo = mono_marshal_get_wrapper_info (method);
643 
644 			g_assert (winfo);
645 			g_assert (winfo->subtype == WRAPPER_SUBTYPE_SYNCHRONIZED_INNER);
646 			method = winfo->d.synchronized_inner.method;
647 		}
648 
649 		if (inflated_class->byval_arg.type == MONO_TYPE_ARRAY ||
650 				inflated_class->byval_arg.type == MONO_TYPE_SZARRAY) {
651 			inflated_method = mono_method_search_in_array_class (inflated_class,
652 				method->name, method->signature);
653 		} else {
654 			MonoError error;
655 			inflated_method = mono_class_inflate_generic_method_checked (method, context, &error);
656 			g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
657 		}
658 		mono_class_init (inflated_method->klass);
659 		g_assert (inflated_method->klass == inflated_class);
660 
661 		if (winfo) {
662 			g_assert (winfo->subtype == WRAPPER_SUBTYPE_SYNCHRONIZED_INNER);
663 			inflated_method = mono_marshal_get_synchronized_inner_wrapper (inflated_method);
664 		}
665 
666 		res->method = inflated_method;
667 
668 		return res;
669 	}
670 
671 	case MONO_RGCTX_INFO_CLASS_FIELD:
672 	case MONO_RGCTX_INFO_FIELD_OFFSET: {
673 		MonoError error;
674 		MonoClassField *field = (MonoClassField *)data;
675 		MonoType *inflated_type = mono_class_inflate_generic_type_checked (&field->parent->byval_arg, context, &error);
676 		mono_error_assert_ok (&error); /* FIXME don't swallow the error */
677 
678 		MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
679 		int i = field - field->parent->fields;
680 		gpointer dummy = NULL;
681 
682 		mono_metadata_free_type (inflated_type);
683 
684 		mono_class_get_fields (inflated_class, &dummy);
685 		g_assert (inflated_class->fields);
686 
687 		return &inflated_class->fields [i];
688 	}
689 	case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI:
690 	case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: {
691 		MonoMethodSignature *sig = (MonoMethodSignature *)data;
692 		MonoMethodSignature *isig;
693 		MonoError error;
694 
695 		isig = mono_inflate_generic_signature (sig, context, &error);
696 		g_assert (mono_error_ok (&error));
697 		return isig;
698 	}
699 	case MONO_RGCTX_INFO_VIRT_METHOD_CODE:
700 	case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: {
701 		MonoJumpInfoVirtMethod *info = (MonoJumpInfoVirtMethod *)data;
702 		MonoJumpInfoVirtMethod *res;
703 		MonoType *t;
704 		MonoDomain *domain = mono_domain_get ();
705 		MonoError error;
706 
707 		// FIXME: Temporary
708 		res = (MonoJumpInfoVirtMethod *)mono_domain_alloc0 (domain, sizeof (MonoJumpInfoVirtMethod));
709 		t = mono_class_inflate_generic_type_checked (&info->klass->byval_arg, context, &error);
710 		mono_error_assert_ok (&error); /* FIXME don't swallow the error */
711 
712 		res->klass = mono_class_from_mono_type (t);
713 		mono_metadata_free_type (t);
714 
715 		res->method = mono_class_inflate_generic_method_checked (info->method, context, &error);
716 		g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
717 
718 		return res;
719 	}
720 	default:
721 		g_assert_not_reached ();
722 	}
723 	/* Not reached, quiet compiler */
724 	return NULL;
725 }
726 
727 static void
free_inflated_info(MonoRgctxInfoType info_type,gpointer info)728 free_inflated_info (MonoRgctxInfoType info_type, gpointer info)
729 {
730 	if (!info)
731 		return;
732 
733 	switch (info_type) {
734 	case MONO_RGCTX_INFO_STATIC_DATA:
735 	case MONO_RGCTX_INFO_KLASS:
736 	case MONO_RGCTX_INFO_ELEMENT_KLASS:
737 	case MONO_RGCTX_INFO_VTABLE:
738 	case MONO_RGCTX_INFO_TYPE:
739 	case MONO_RGCTX_INFO_REFLECTION_TYPE:
740 	case MONO_RGCTX_INFO_CAST_CACHE:
741 		mono_metadata_free_type ((MonoType *)info);
742 		break;
743 	default:
744 		break;
745 	}
746 }
747 
748 static MonoRuntimeGenericContextInfoTemplate
749 class_get_rgctx_template_oti (MonoClass *klass, int type_argc, guint32 slot, gboolean temporary, gboolean shared, gboolean *do_free);
750 
751 static MonoClass*
class_uninstantiated(MonoClass * klass)752 class_uninstantiated (MonoClass *klass)
753 {
754 	if (mono_class_is_ginst (klass))
755 		return mono_class_get_generic_class (klass)->container_class;
756 	return klass;
757 }
758 
759 /*
760  * get_shared_class:
761  *
762  *   Return the class used to store information when using generic sharing.
763  */
764 static MonoClass*
get_shared_class(MonoClass * klass)765 get_shared_class (MonoClass *klass)
766 {
767 	return class_uninstantiated (klass);
768 }
769 
770 /*
771  * mono_class_get_runtime_generic_context_template:
772  * @class: a class
773  *
774  * Looks up or constructs, if necessary, the runtime generic context template for class.
775  * The template is the same for all instantiations of a class.
776  */
777 static MonoRuntimeGenericContextTemplate*
mono_class_get_runtime_generic_context_template(MonoClass * klass)778 mono_class_get_runtime_generic_context_template (MonoClass *klass)
779 {
780 	MonoRuntimeGenericContextTemplate *parent_template, *template_;
781 	guint32 i;
782 
783 	klass = get_shared_class (klass);
784 
785 	mono_loader_lock ();
786 	template_ = class_lookup_rgctx_template (klass);
787 	mono_loader_unlock ();
788 
789 	if (template_)
790 		return template_;
791 
792 	//g_assert (get_shared_class (class) == class);
793 
794 	template_ = alloc_template (klass);
795 
796 	mono_loader_lock ();
797 
798 	if (klass->parent) {
799 		guint32 num_entries;
800 		int max_argc, type_argc;
801 
802 		parent_template = mono_class_get_runtime_generic_context_template (klass->parent);
803 		max_argc = template_get_max_argc (parent_template);
804 
805 		for (type_argc = 0; type_argc <= max_argc; ++type_argc) {
806 			num_entries = rgctx_template_num_infos (parent_template, type_argc);
807 
808 			/* FIXME: quadratic! */
809 			for (i = 0; i < num_entries; ++i) {
810 				MonoRuntimeGenericContextInfoTemplate oti;
811 
812 				oti = class_get_rgctx_template_oti (klass->parent, type_argc, i, FALSE, FALSE, NULL);
813 				if (oti.data && oti.data != MONO_RGCTX_SLOT_USED_MARKER) {
814 					rgctx_template_set_slot (klass->image, template_, type_argc, i,
815 											 oti.data, oti.info_type);
816 				}
817 			}
818 		}
819 	}
820 
821 	if (class_lookup_rgctx_template (klass)) {
822 		/* some other thread already set the template */
823 		template_ = class_lookup_rgctx_template (klass);
824 	} else {
825 		class_set_rgctx_template (klass, template_);
826 
827 		if (klass->parent)
828 			register_generic_subclass (klass);
829 	}
830 
831 	mono_loader_unlock ();
832 
833 	return template_;
834 }
835 
836 /*
837  * class_get_rgctx_template_oti:
838  *
839  *   Return the info template of CLASS numbered TYPE_ARGC/SLOT.
840  * temporary signifies whether the inflated info (oti.data) will be
841  * used temporarily, in which case it might be heap-allocated, or
842  * permanently, in which case it will be mempool-allocated.  If
843  * temporary is set then *do_free will return whether the returned
844  * data must be freed.
845  *
846  * LOCKING: loader lock
847  */
848 static MonoRuntimeGenericContextInfoTemplate
class_get_rgctx_template_oti(MonoClass * klass,int type_argc,guint32 slot,gboolean temporary,gboolean shared,gboolean * do_free)849 class_get_rgctx_template_oti (MonoClass *klass, int type_argc, guint32 slot, gboolean temporary, gboolean shared, gboolean *do_free)
850 {
851 	g_assert ((temporary && do_free) || (!temporary && !do_free));
852 
853 	DEBUG (printf ("get slot: %s %d\n", mono_type_full_name (&class->byval_arg), slot));
854 
855 	if (mono_class_is_ginst (klass) && !shared) {
856 		MonoRuntimeGenericContextInfoTemplate oti;
857 		gboolean tmp_do_free;
858 
859 		oti = class_get_rgctx_template_oti (mono_class_get_generic_class (klass)->container_class,
860 											type_argc, slot, TRUE, FALSE, &tmp_do_free);
861 		if (oti.data) {
862 			gpointer info = oti.data;
863 			oti.data = inflate_info (&oti, &mono_class_get_generic_class (klass)->context, klass, temporary);
864 			if (tmp_do_free)
865 				free_inflated_info (oti.info_type, info);
866 		}
867 		if (temporary)
868 			*do_free = TRUE;
869 
870 		return oti;
871 	} else {
872 		MonoRuntimeGenericContextTemplate *template_;
873 		MonoRuntimeGenericContextInfoTemplate *oti;
874 
875 		template_ = mono_class_get_runtime_generic_context_template (klass);
876 		oti = rgctx_template_get_other_slot (template_, type_argc, slot);
877 		g_assert (oti);
878 
879 		if (temporary)
880 			*do_free = FALSE;
881 
882 		return *oti;
883 	}
884 }
885 
886 static gpointer
class_type_info(MonoDomain * domain,MonoClass * klass,MonoRgctxInfoType info_type,MonoError * error)887 class_type_info (MonoDomain *domain, MonoClass *klass, MonoRgctxInfoType info_type, MonoError *error)
888 {
889 	error_init (error);
890 
891 	switch (info_type) {
892 	case MONO_RGCTX_INFO_STATIC_DATA: {
893 		MonoVTable *vtable = mono_class_vtable (domain, klass);
894 		if (!vtable) {
895 			mono_error_set_for_class_failure (error, klass);
896 			return NULL;
897 		}
898 		return mono_vtable_get_static_field_data (vtable);
899 	}
900 	case MONO_RGCTX_INFO_KLASS:
901 		return klass;
902 	case MONO_RGCTX_INFO_ELEMENT_KLASS:
903 		return klass->element_class;
904 	case MONO_RGCTX_INFO_VTABLE: {
905 		MonoVTable *vtable = mono_class_vtable (domain, klass);
906 		if (!vtable) {
907 			mono_error_set_for_class_failure (error, klass);
908 			return NULL;
909 		}
910 		return vtable;
911 	}
912 	case MONO_RGCTX_INFO_CAST_CACHE: {
913 		/*First slot is the cache itself, the second the vtable.*/
914 		gpointer **cache_data = (gpointer **)mono_domain_alloc0 (domain, sizeof (gpointer) * 2);
915 		cache_data [1] = (gpointer *)klass;
916 		return cache_data;
917 	}
918 	case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
919 		return GUINT_TO_POINTER (mono_class_array_element_size (klass));
920 	case MONO_RGCTX_INFO_VALUE_SIZE:
921 		if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg))
922 			return GUINT_TO_POINTER (sizeof (gpointer));
923 		else
924 			return GUINT_TO_POINTER (mono_class_value_size (klass, NULL));
925 	case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
926 		if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg))
927 			return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_REF);
928 		else if (mono_class_is_nullable (klass))
929 			return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_NULLABLE);
930 		else
931 			return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_VTYPE);
932 	case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS:
933 		mono_class_init (klass);
934 		/* Can't return 0 */
935 		if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg) || klass->has_references)
936 			return GUINT_TO_POINTER (2);
937 		else
938 			return GUINT_TO_POINTER (1);
939 	case MONO_RGCTX_INFO_MEMCPY:
940 	case MONO_RGCTX_INFO_BZERO: {
941 		static MonoMethod *memcpy_method [17];
942 		static MonoMethod *bzero_method [17];
943 		MonoJitDomainInfo *domain_info;
944 		int size;
945 		guint32 align;
946 
947 		domain_info = domain_jit_info (domain);
948 
949 		if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
950 			size = sizeof (gpointer);
951 			align = sizeof (gpointer);
952 		} else {
953 			size = mono_class_value_size (klass, &align);
954 		}
955 
956 		if (size != 1 && size != 2 && size != 4 && size != 8)
957 			size = 0;
958 		if (align < size)
959 			size = 0;
960 
961 		if (info_type == MONO_RGCTX_INFO_MEMCPY) {
962 			if (!memcpy_method [size]) {
963 				MonoMethod *m;
964 				char name [32];
965 
966 				if (size == 0)
967 					sprintf (name, "memcpy");
968 				else
969 					sprintf (name, "memcpy_aligned_%d", size);
970 				m = mono_class_get_method_from_name (mono_defaults.string_class, name, 3);
971 				g_assert (m);
972 				mono_memory_barrier ();
973 				memcpy_method [size] = m;
974 			}
975 			if (!domain_info->memcpy_addr [size]) {
976 				gpointer addr = mono_compile_method_checked (memcpy_method [size], error);
977 				mono_memory_barrier ();
978 				domain_info->memcpy_addr [size] = (gpointer *)addr;
979 				mono_error_assert_ok (error);
980 			}
981 			return domain_info->memcpy_addr [size];
982 		} else {
983 			if (!bzero_method [size]) {
984 				MonoMethod *m;
985 				char name [32];
986 
987 				if (size == 0)
988 					sprintf (name, "bzero");
989 				else
990 					sprintf (name, "bzero_aligned_%d", size);
991 				m = mono_class_get_method_from_name (mono_defaults.string_class, name, 2);
992 				g_assert (m);
993 				mono_memory_barrier ();
994 				bzero_method [size] = m;
995 			}
996 			if (!domain_info->bzero_addr [size]) {
997 				gpointer addr = mono_compile_method_checked (bzero_method [size], error);
998 				mono_memory_barrier ();
999 				domain_info->bzero_addr [size] = (gpointer *)addr;
1000 				mono_error_assert_ok (error);
1001 			}
1002 			return domain_info->bzero_addr [size];
1003 		}
1004 	}
1005 	case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
1006 	case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: {
1007 		MonoMethod *method;
1008 		gpointer addr, arg;
1009 		MonoJitInfo *ji;
1010 		MonoMethodSignature *sig, *gsig;
1011 		MonoMethod *gmethod;
1012 
1013 		if (!mono_class_is_nullable (klass))
1014 			/* This can happen since all the entries in MonoGSharedVtMethodInfo are inflated, even those which are not used */
1015 			return NULL;
1016 
1017 		if (info_type == MONO_RGCTX_INFO_NULLABLE_CLASS_BOX)
1018 			method = mono_class_get_method_from_name (klass, "Box", 1);
1019 		else
1020 			method = mono_class_get_method_from_name (klass, "Unbox", 1);
1021 
1022 		addr = mono_jit_compile_method (method, error);
1023 		if (!mono_error_ok (error))
1024 			return NULL;
1025 
1026 		// The caller uses the gsharedvt call signature
1027 
1028 		if (mono_llvm_only) {
1029 			/* FIXME: We have no access to the gsharedvt signature/gsctx used by the caller, so have to construct it ourselves */
1030 			gmethod = mini_get_shared_method_full (method, FALSE, TRUE);
1031 			sig = mono_method_signature (method);
1032 			gsig = mono_method_signature (gmethod);
1033 
1034 			addr = mini_add_method_wrappers_llvmonly (method, addr, TRUE, FALSE, &arg);
1035 			return mini_create_llvmonly_ftndesc (domain, addr, arg);
1036 		}
1037 
1038 		ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr), NULL);
1039 		g_assert (ji);
1040 		if (mini_jit_info_is_gsharedvt (ji))
1041 			return mono_create_static_rgctx_trampoline (method, addr);
1042 		else {
1043 			/* Need to add an out wrapper */
1044 
1045 			/* FIXME: We have no access to the gsharedvt signature/gsctx used by the caller, so have to construct it ourselves */
1046 			gmethod = mini_get_shared_method_full (method, FALSE, TRUE);
1047 			sig = mono_method_signature (method);
1048 			gsig = mono_method_signature (gmethod);
1049 
1050 			addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, -1, FALSE);
1051 			addr = mono_create_static_rgctx_trampoline (method, addr);
1052 			return addr;
1053 		}
1054 	}
1055 	default:
1056 		g_assert_not_reached ();
1057 	}
1058 	/* Not reached */
1059 	return NULL;
1060 }
1061 
1062 static gboolean
ji_is_gsharedvt(MonoJitInfo * ji)1063 ji_is_gsharedvt (MonoJitInfo *ji)
1064 {
1065 	if (ji && ji->has_generic_jit_info && (mono_jit_info_get_generic_sharing_context (ji)->is_gsharedvt))
1066 		return TRUE;
1067 	else
1068 		return FALSE;
1069 }
1070 
1071 /*
1072  * Describes the information used to construct a gsharedvt arg trampoline.
1073  */
1074 typedef struct {
1075 	gboolean is_in;
1076 	gboolean calli;
1077 	gint32 vcall_offset;
1078 	gpointer addr;
1079 	MonoMethodSignature *sig, *gsig;
1080 } GSharedVtTrampInfo;
1081 
1082 static guint
tramp_info_hash(gconstpointer key)1083 tramp_info_hash (gconstpointer key)
1084 {
1085 	GSharedVtTrampInfo *tramp = (GSharedVtTrampInfo *)key;
1086 
1087 	return (gsize)tramp->addr;
1088 }
1089 
1090 static gboolean
tramp_info_equal(gconstpointer a,gconstpointer b)1091 tramp_info_equal (gconstpointer a, gconstpointer b)
1092 {
1093 	GSharedVtTrampInfo *tramp1 = (GSharedVtTrampInfo *)a;
1094 	GSharedVtTrampInfo *tramp2 = (GSharedVtTrampInfo *)b;
1095 
1096 	/* The signatures should be internalized */
1097 	return tramp1->is_in == tramp2->is_in && tramp1->calli == tramp2->calli && tramp1->vcall_offset == tramp2->vcall_offset &&
1098 		tramp1->addr == tramp2->addr && tramp1->sig == tramp2->sig && tramp1->gsig == tramp2->gsig;
1099 }
1100 
1101 static MonoType*
get_wrapper_shared_type(MonoType * t)1102 get_wrapper_shared_type (MonoType *t)
1103 {
1104 	if (t->byref)
1105 		return &mono_defaults.int_class->this_arg;
1106 	t = mini_get_underlying_type (t);
1107 
1108 	switch (t->type) {
1109 	case MONO_TYPE_I1:
1110 		/* This removes any attributes etc. */
1111 		return &mono_defaults.sbyte_class->byval_arg;
1112 	case MONO_TYPE_U1:
1113 		return &mono_defaults.byte_class->byval_arg;
1114 	case MONO_TYPE_I2:
1115 		return &mono_defaults.int16_class->byval_arg;
1116 	case MONO_TYPE_U2:
1117 		return &mono_defaults.uint16_class->byval_arg;
1118 	case MONO_TYPE_I4:
1119 		return &mono_defaults.int32_class->byval_arg;
1120 	case MONO_TYPE_U4:
1121 		return &mono_defaults.uint32_class->byval_arg;
1122 	case MONO_TYPE_OBJECT:
1123 	case MONO_TYPE_CLASS:
1124 	case MONO_TYPE_SZARRAY:
1125 	case MONO_TYPE_ARRAY:
1126 	case MONO_TYPE_PTR:
1127 		// FIXME: refs and intptr cannot be shared because
1128 		// they are treated differently when a method has a vret arg,
1129 		// see get_call_info ().
1130 		return &mono_defaults.object_class->byval_arg;
1131 		//return &mono_defaults.int_class->byval_arg;
1132 	case MONO_TYPE_GENERICINST: {
1133 		MonoError error;
1134 		MonoClass *klass;
1135 		MonoGenericContext ctx;
1136 		MonoGenericContext *orig_ctx;
1137 		MonoGenericInst *inst;
1138 		MonoType *args [16];
1139 		int i;
1140 
1141 		if (!MONO_TYPE_ISSTRUCT (t))
1142 			return get_wrapper_shared_type (&mono_defaults.object_class->byval_arg);
1143 
1144 		klass = mono_class_from_mono_type (t);
1145 		orig_ctx = &mono_class_get_generic_class (klass)->context;
1146 
1147 		memset (&ctx, 0, sizeof (MonoGenericContext));
1148 
1149 		inst = orig_ctx->class_inst;
1150 		if (inst) {
1151 			g_assert (inst->type_argc < 16);
1152 			for (i = 0; i < inst->type_argc; ++i)
1153 				args [i] = get_wrapper_shared_type (inst->type_argv [i]);
1154 			ctx.class_inst = mono_metadata_get_generic_inst (inst->type_argc, args);
1155 		}
1156 		inst = orig_ctx->method_inst;
1157 		if (inst) {
1158 			g_assert (inst->type_argc < 16);
1159 			for (i = 0; i < inst->type_argc; ++i)
1160 				args [i] = get_wrapper_shared_type (inst->type_argv [i]);
1161 			ctx.method_inst = mono_metadata_get_generic_inst (inst->type_argc, args);
1162 		}
1163 		klass = mono_class_inflate_generic_class_checked (mono_class_get_generic_class (klass)->container_class, &ctx, &error);
1164 		mono_error_assert_ok (&error); /* FIXME don't swallow the error */
1165 		return &klass->byval_arg;
1166 	}
1167 #if SIZEOF_VOID_P == 8
1168 	case MONO_TYPE_I8:
1169 		return &mono_defaults.int_class->byval_arg;
1170 #endif
1171 	default:
1172 		break;
1173 	}
1174 
1175 	//printf ("%s\n", mono_type_full_name (t));
1176 
1177 	return t;
1178 }
1179 
1180 static MonoMethodSignature*
mini_get_underlying_signature(MonoMethodSignature * sig)1181 mini_get_underlying_signature (MonoMethodSignature *sig)
1182 {
1183 	MonoMethodSignature *res = mono_metadata_signature_dup (sig);
1184 	int i;
1185 
1186 	res->ret = get_wrapper_shared_type (sig->ret);
1187 	for (i = 0; i < sig->param_count; ++i)
1188 		res->params [i] = get_wrapper_shared_type (sig->params [i]);
1189 	res->generic_param_count = 0;
1190 	res->is_inflated = 0;
1191 
1192 	return res;
1193 }
1194 
1195 /*
1196  * mini_get_gsharedvt_in_sig_wrapper:
1197  *
1198  *   Return a wrapper to translate between the normal and gsharedvt calling conventions of SIG.
1199  * The returned wrapper has a signature of SIG, plus one extra argument, which is an <addr, rgctx> pair.
1200  * The extra argument is passed the same way as an rgctx to shared methods.
1201  * It calls <addr> using the gsharedvt version of SIG, passing in <rgctx> as an extra argument.
1202  */
1203 MonoMethod*
mini_get_gsharedvt_in_sig_wrapper(MonoMethodSignature * sig)1204 mini_get_gsharedvt_in_sig_wrapper (MonoMethodSignature *sig)
1205 {
1206 	MonoMethodBuilder *mb;
1207 	MonoMethod *res, *cached;
1208 	WrapperInfo *info;
1209 	MonoMethodSignature *csig, *gsharedvt_sig;
1210 	int i, pindex, retval_var = 0;
1211 	static GHashTable *cache;
1212 
1213 	// FIXME: Memory management
1214 	sig = mini_get_underlying_signature (sig);
1215 
1216 	// FIXME: Normal cache
1217 	gshared_lock ();
1218 	if (!cache)
1219 		cache = g_hash_table_new_full ((GHashFunc)mono_signature_hash, (GEqualFunc)mono_metadata_signature_equal, NULL, NULL);
1220 	res = g_hash_table_lookup (cache, sig);
1221 	gshared_unlock ();
1222 	if (res) {
1223 		g_free (sig);
1224 		return res;
1225 	}
1226 
1227 	/* Create the signature for the wrapper */
1228 	// FIXME:
1229 	csig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 1) * sizeof (MonoType*)));
1230 	memcpy (csig, sig, mono_metadata_signature_size (sig));
1231 	csig->param_count ++;
1232 	csig->params [sig->param_count] = &mono_defaults.int_class->byval_arg;
1233 
1234 	/* Create the signature for the gsharedvt callconv */
1235 	gsharedvt_sig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 2) * sizeof (MonoType*)));
1236 	memcpy (gsharedvt_sig, sig, mono_metadata_signature_size (sig));
1237 	pindex = 0;
1238 	/* The return value is returned using an explicit vret argument */
1239 	if (sig->ret->type != MONO_TYPE_VOID) {
1240 		gsharedvt_sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1241 		gsharedvt_sig->ret = &mono_defaults.void_class->byval_arg;
1242 	}
1243 	for (i = 0; i < sig->param_count; i++) {
1244 		gsharedvt_sig->params [pindex] = sig->params [i];
1245 		if (!sig->params [i]->byref) {
1246 			gsharedvt_sig->params [pindex] = mono_metadata_type_dup (NULL, gsharedvt_sig->params [pindex]);
1247 			gsharedvt_sig->params [pindex]->byref = 1;
1248 		}
1249 		pindex ++;
1250 	}
1251 	/* Rgctx arg */
1252 	gsharedvt_sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1253 	gsharedvt_sig->param_count = pindex;
1254 
1255 	// FIXME: Use shared signatures
1256 	mb = mono_mb_new (mono_defaults.object_class, sig->hasthis ? "gsharedvt_in_sig" : "gsharedvt_in_sig_static", MONO_WRAPPER_UNKNOWN);
1257 
1258 #ifndef DISABLE_JIT
1259 	if (sig->ret->type != MONO_TYPE_VOID)
1260 		retval_var = mono_mb_add_local (mb, sig->ret);
1261 
1262 	/* Make the call */
1263 	if (sig->hasthis)
1264 		mono_mb_emit_ldarg (mb, 0);
1265 	if (sig->ret->type != MONO_TYPE_VOID)
1266 		mono_mb_emit_ldloc_addr (mb, retval_var);
1267 	for (i = 0; i < sig->param_count; i++) {
1268 		if (sig->params [i]->byref)
1269 			mono_mb_emit_ldarg (mb, i + (sig->hasthis == TRUE));
1270 		else
1271 			mono_mb_emit_ldarg_addr (mb, i + (sig->hasthis == TRUE));
1272 	}
1273 	/* Rgctx arg */
1274 	mono_mb_emit_ldarg (mb, sig->param_count + (sig->hasthis ? 1 : 0));
1275 	mono_mb_emit_icon (mb, sizeof (gpointer));
1276 	mono_mb_emit_byte (mb, CEE_ADD);
1277 	mono_mb_emit_byte (mb, CEE_LDIND_I);
1278 	/* Method to call */
1279 	mono_mb_emit_ldarg (mb, sig->param_count + (sig->hasthis ? 1 : 0));
1280 	mono_mb_emit_byte (mb, CEE_LDIND_I);
1281 	mono_mb_emit_calli (mb, gsharedvt_sig);
1282 	if (sig->ret->type != MONO_TYPE_VOID)
1283 		mono_mb_emit_ldloc (mb, retval_var);
1284 	mono_mb_emit_byte (mb, CEE_RET);
1285 #endif
1286 
1287 	info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_GSHAREDVT_IN_SIG);
1288 	info->d.gsharedvt.sig = sig;
1289 
1290 	res = mono_mb_create (mb, csig, sig->param_count + 16, info);
1291 
1292 	gshared_lock ();
1293 	cached = g_hash_table_lookup (cache, sig);
1294 	if (cached)
1295 		res = cached;
1296 	else
1297 		g_hash_table_insert (cache, sig, res);
1298 	gshared_unlock ();
1299 	return res;
1300 }
1301 
1302 /*
1303  * mini_get_gsharedvt_out_sig_wrapper:
1304  *
1305  *   Same as in_sig_wrapper, but translate between the gsharedvt and normal signatures.
1306  */
1307 MonoMethod*
mini_get_gsharedvt_out_sig_wrapper(MonoMethodSignature * sig)1308 mini_get_gsharedvt_out_sig_wrapper (MonoMethodSignature *sig)
1309 {
1310 	MonoMethodBuilder *mb;
1311 	MonoMethod *res, *cached;
1312 	WrapperInfo *info;
1313 	MonoMethodSignature *normal_sig, *csig;
1314 	int i, pindex, args_start, ldind_op, stind_op;
1315 	static GHashTable *cache;
1316 
1317 	// FIXME: Memory management
1318 	sig = mini_get_underlying_signature (sig);
1319 
1320 	// FIXME: Normal cache
1321 	gshared_lock ();
1322 	if (!cache)
1323 		cache = g_hash_table_new_full ((GHashFunc)mono_signature_hash, (GEqualFunc)mono_metadata_signature_equal, NULL, NULL);
1324 	res = g_hash_table_lookup (cache, sig);
1325 	gshared_unlock ();
1326 	if (res) {
1327 		g_free (sig);
1328 		return res;
1329 	}
1330 
1331 	/* Create the signature for the wrapper */
1332 	// FIXME:
1333 	csig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 2) * sizeof (MonoType*)));
1334 	memcpy (csig, sig, mono_metadata_signature_size (sig));
1335 	pindex = 0;
1336 	/* The return value is returned using an explicit vret argument */
1337 	if (sig->ret->type != MONO_TYPE_VOID) {
1338 		csig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1339 		csig->ret = &mono_defaults.void_class->byval_arg;
1340 	}
1341 	args_start = pindex;
1342 	if (sig->hasthis)
1343 		args_start ++;
1344 	for (i = 0; i < sig->param_count; i++) {
1345 		csig->params [pindex] = sig->params [i];
1346 		if (!sig->params [i]->byref) {
1347 			csig->params [pindex] = mono_metadata_type_dup (NULL, csig->params [pindex]);
1348 			csig->params [pindex]->byref = 1;
1349 		}
1350 		pindex ++;
1351 	}
1352 	/* Rgctx arg */
1353 	csig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1354 	csig->param_count = pindex;
1355 
1356 	/* Create the signature for the normal callconv */
1357 	normal_sig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 2) * sizeof (MonoType*)));
1358 	memcpy (normal_sig, sig, mono_metadata_signature_size (sig));
1359 	normal_sig->param_count ++;
1360 	normal_sig->params [sig->param_count] = &mono_defaults.int_class->byval_arg;
1361 
1362 	// FIXME: Use shared signatures
1363 	mb = mono_mb_new (mono_defaults.object_class, "gsharedvt_out_sig", MONO_WRAPPER_UNKNOWN);
1364 
1365 #ifndef DISABLE_JIT
1366 	if (sig->ret->type != MONO_TYPE_VOID)
1367 		/* Load return address */
1368 		mono_mb_emit_ldarg (mb, sig->hasthis ? 1 : 0);
1369 
1370 	/* Make the call */
1371 	if (sig->hasthis)
1372 		mono_mb_emit_ldarg (mb, 0);
1373 	for (i = 0; i < sig->param_count; i++) {
1374 		if (sig->params [i]->byref) {
1375 			mono_mb_emit_ldarg (mb, args_start + i);
1376 		} else {
1377 			ldind_op = mono_type_to_ldind (sig->params [i]);
1378 			mono_mb_emit_ldarg (mb, args_start + i);
1379 			// FIXME:
1380 			if (ldind_op == CEE_LDOBJ)
1381 				mono_mb_emit_op (mb, CEE_LDOBJ, mono_class_from_mono_type (sig->params [i]));
1382 			else
1383 				mono_mb_emit_byte (mb, ldind_op);
1384 		}
1385 	}
1386 	/* Rgctx arg */
1387 	mono_mb_emit_ldarg (mb, args_start + sig->param_count);
1388 	mono_mb_emit_icon (mb, sizeof (gpointer));
1389 	mono_mb_emit_byte (mb, CEE_ADD);
1390 	mono_mb_emit_byte (mb, CEE_LDIND_I);
1391 	/* Method to call */
1392 	mono_mb_emit_ldarg (mb, args_start + sig->param_count);
1393 	mono_mb_emit_byte (mb, CEE_LDIND_I);
1394 	mono_mb_emit_calli (mb, normal_sig);
1395 	if (sig->ret->type != MONO_TYPE_VOID) {
1396 		/* Store return value */
1397 		stind_op = mono_type_to_stind (sig->ret);
1398 		// FIXME:
1399 		if (stind_op == CEE_STOBJ)
1400 			mono_mb_emit_op (mb, CEE_STOBJ, mono_class_from_mono_type (sig->ret));
1401 		else if (stind_op == CEE_STIND_REF)
1402 			/* Avoid write barriers, the vret arg points to the stack */
1403 			mono_mb_emit_byte (mb, CEE_STIND_I);
1404 		else
1405 			mono_mb_emit_byte (mb, stind_op);
1406 	}
1407 	mono_mb_emit_byte (mb, CEE_RET);
1408 #endif
1409 
1410 	info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_GSHAREDVT_OUT_SIG);
1411 	info->d.gsharedvt.sig = sig;
1412 
1413 	res = mono_mb_create (mb, csig, sig->param_count + 16, info);
1414 
1415 	gshared_lock ();
1416 	cached = g_hash_table_lookup (cache, sig);
1417 	if (cached)
1418 		res = cached;
1419 	else
1420 		g_hash_table_insert (cache, sig, res);
1421 	gshared_unlock ();
1422 	return res;
1423 }
1424 
1425 /*
1426  * mini_get_interp_in_wrapper:
1427  *
1428  *   Return a wrapper which can be used to transition from compiled code to the interpreter.
1429  * The wrapper has the same signature as SIG. It is very similar to a gsharedvt_in wrapper,
1430  * except the 'extra_arg' is passed in the rgctx reg, so this wrapper needs to be
1431  * called through a static rgctx trampoline.
1432  * FIXME: Move this elsewhere.
1433  */
1434 MonoMethod*
mini_get_interp_in_wrapper(MonoMethodSignature * sig)1435 mini_get_interp_in_wrapper (MonoMethodSignature *sig)
1436 {
1437 	MonoMethodBuilder *mb;
1438 	MonoMethod *res, *cached;
1439 	WrapperInfo *info;
1440 	MonoMethodSignature *csig, *entry_sig;
1441 	int i, pindex, retval_var = 0;
1442 	static GHashTable *cache;
1443 	const char *name;
1444 	gboolean generic = FALSE;
1445 
1446 	sig = mini_get_underlying_signature (sig);
1447 
1448 	gshared_lock ();
1449 	if (!cache)
1450 		cache = g_hash_table_new_full ((GHashFunc)mono_signature_hash, (GEqualFunc)mono_metadata_signature_equal, NULL, NULL);
1451 	res = g_hash_table_lookup (cache, sig);
1452 	gshared_unlock ();
1453 	if (res) {
1454 		g_free (sig);
1455 		return res;
1456 	}
1457 
1458 	if (sig->param_count > 8)
1459 		/* Call the generic interpreter entry point, the specialized ones only handle a limited number of arguments */
1460 		generic = TRUE;
1461 
1462 	/* Create the signature for the wrapper */
1463 	csig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + (sig->param_count * sizeof (MonoType*)));
1464 	memcpy (csig, sig, mono_metadata_signature_size (sig));
1465 
1466 	/* Create the signature for the callee callconv */
1467 	if (generic) {
1468 		/*
1469 		 * The called function has the following signature:
1470 		 * interp_entry_general (gpointer this_arg, gpointer res, gpointer *args, gpointer rmethod)
1471 		 */
1472 		entry_sig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + (4 * sizeof (MonoType*)));
1473 		entry_sig->ret = &mono_defaults.void_class->byval_arg;
1474 		entry_sig->param_count = 4;
1475 		entry_sig->params [0] = &mono_defaults.int_class->byval_arg;
1476 		entry_sig->params [1] = &mono_defaults.int_class->byval_arg;
1477 		entry_sig->params [2] = &mono_defaults.int_class->byval_arg;
1478 		entry_sig->params [3] = &mono_defaults.int_class->byval_arg;
1479 		name = "interp_in_generic";
1480 		generic = TRUE;
1481 	} else  {
1482 		/*
1483 		 * The called function has the following signature:
1484 		 * void entry(<optional this ptr>, <optional return ptr>, <arguments>, <extra arg>)
1485 		 */
1486 		entry_sig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 2) * sizeof (MonoType*)));
1487 		memcpy (entry_sig, sig, mono_metadata_signature_size (sig));
1488 		pindex = 0;
1489 		/* The return value is returned using an explicit vret argument */
1490 		if (sig->ret->type != MONO_TYPE_VOID) {
1491 			entry_sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1492 			entry_sig->ret = &mono_defaults.void_class->byval_arg;
1493 		}
1494 		for (i = 0; i < sig->param_count; i++) {
1495 			entry_sig->params [pindex] = sig->params [i];
1496 			if (!sig->params [i]->byref) {
1497 				entry_sig->params [pindex] = mono_metadata_type_dup (NULL, entry_sig->params [pindex]);
1498 				entry_sig->params [pindex]->byref = 1;
1499 			}
1500 			pindex ++;
1501 		}
1502 		/* Extra arg */
1503 		entry_sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1504 		entry_sig->param_count = pindex;
1505 		name = sig->hasthis ? "interp_in" : "interp_in_static";
1506 	}
1507 
1508 	mb = mono_mb_new (mono_defaults.object_class, name, MONO_WRAPPER_UNKNOWN);
1509 
1510 	/* This is needed to be able to unwind out of interpreted code */
1511 	mb->method->save_lmf = 1;
1512 
1513 #ifndef DISABLE_JIT
1514 	if (sig->ret->type != MONO_TYPE_VOID)
1515 		retval_var = mono_mb_add_local (mb, sig->ret);
1516 
1517 	/* Make the call */
1518 	if (generic) {
1519 		/* Collect arguments */
1520 		int args_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1521 
1522 		mono_mb_emit_icon (mb, sizeof (gpointer) * sig->param_count);
1523 		mono_mb_emit_byte (mb, CEE_PREFIX1);
1524 		mono_mb_emit_byte (mb, CEE_LOCALLOC);
1525 		mono_mb_emit_stloc (mb, args_var);
1526 
1527 		for (i = 0; i < sig->param_count; i++) {
1528 			mono_mb_emit_ldloc (mb, args_var);
1529 			mono_mb_emit_icon (mb, sizeof (gpointer) * i);
1530 			mono_mb_emit_byte (mb, CEE_ADD);
1531 			if (sig->params [i]->byref)
1532 				mono_mb_emit_ldarg (mb, i + (sig->hasthis == TRUE));
1533 			else
1534 				mono_mb_emit_ldarg_addr (mb, i + (sig->hasthis == TRUE));
1535 			mono_mb_emit_byte (mb, CEE_STIND_I);
1536 		}
1537 
1538 		if (sig->hasthis)
1539 			mono_mb_emit_ldarg (mb, 0);
1540 		else
1541 			mono_mb_emit_byte (mb, CEE_LDNULL);
1542 		if (sig->ret->type != MONO_TYPE_VOID)
1543 			mono_mb_emit_ldloc_addr (mb, retval_var);
1544 		else
1545 			mono_mb_emit_byte (mb, CEE_LDNULL);
1546 		mono_mb_emit_ldloc (mb, args_var);
1547 	} else {
1548 		if (sig->hasthis)
1549 			mono_mb_emit_ldarg (mb, 0);
1550 		if (sig->ret->type != MONO_TYPE_VOID)
1551 			mono_mb_emit_ldloc_addr (mb, retval_var);
1552 		for (i = 0; i < sig->param_count; i++) {
1553 			if (sig->params [i]->byref)
1554 				mono_mb_emit_ldarg (mb, i + (sig->hasthis == TRUE));
1555 			else
1556 				mono_mb_emit_ldarg_addr (mb, i + (sig->hasthis == TRUE));
1557 		}
1558 	}
1559 	/* Extra arg */
1560 	mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
1561 	mono_mb_emit_byte (mb, CEE_MONO_GET_RGCTX_ARG);
1562 	mono_mb_emit_icon (mb, sizeof (gpointer));
1563 	mono_mb_emit_byte (mb, CEE_ADD);
1564 	mono_mb_emit_byte (mb, CEE_LDIND_I);
1565 	/* Method to call */
1566 	mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
1567 	mono_mb_emit_byte (mb, CEE_MONO_GET_RGCTX_ARG);
1568 	mono_mb_emit_byte (mb, CEE_LDIND_I);
1569 	mono_mb_emit_calli (mb, entry_sig);
1570 	if (sig->ret->type != MONO_TYPE_VOID)
1571 		mono_mb_emit_ldloc (mb, retval_var);
1572 	mono_mb_emit_byte (mb, CEE_RET);
1573 #endif
1574 
1575 	info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_INTERP_IN);
1576 	info->d.interp_in.sig = sig;
1577 
1578 	res = mono_mb_create (mb, csig, sig->param_count + 16, info);
1579 
1580 	gshared_lock ();
1581 	cached = g_hash_table_lookup (cache, sig);
1582 	if (cached) {
1583 		mono_free_method (res);
1584 		res = cached;
1585 	} else {
1586 		g_hash_table_insert (cache, sig, res);
1587 	}
1588 	gshared_unlock ();
1589 	mono_mb_free (mb);
1590 
1591 	return res;
1592 }
1593 
1594 MonoMethodSignature*
mini_get_gsharedvt_out_sig_wrapper_signature(gboolean has_this,gboolean has_ret,int param_count)1595 mini_get_gsharedvt_out_sig_wrapper_signature (gboolean has_this, gboolean has_ret, int param_count)
1596 {
1597 	MonoMethodSignature *sig = g_malloc0 (sizeof (MonoMethodSignature) + (32 * sizeof (MonoType*)));
1598 	int i, pindex;
1599 
1600 	sig->ret = &mono_defaults.void_class->byval_arg;
1601 	sig->sentinelpos = -1;
1602 	pindex = 0;
1603 	if (has_this)
1604 		/* this */
1605 		sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1606 	if (has_ret)
1607 		/* vret */
1608 		sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1609 	for (i = 0; i < param_count; ++i)
1610 		/* byref arguments */
1611 		sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1612 	/* extra arg */
1613 	sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
1614 	sig->param_count = pindex;
1615 
1616 	return sig;
1617 }
1618 
1619 /*
1620  * mini_get_gsharedvt_wrapper:
1621  *
1622  *   Return a gsharedvt in/out wrapper for calling ADDR.
1623  */
1624 gpointer
mini_get_gsharedvt_wrapper(gboolean gsharedvt_in,gpointer addr,MonoMethodSignature * normal_sig,MonoMethodSignature * gsharedvt_sig,gint32 vcall_offset,gboolean calli)1625 mini_get_gsharedvt_wrapper (gboolean gsharedvt_in, gpointer addr, MonoMethodSignature *normal_sig, MonoMethodSignature *gsharedvt_sig, gint32 vcall_offset, gboolean calli)
1626 {
1627 	MonoError error;
1628 	gpointer res, info;
1629 	MonoDomain *domain = mono_domain_get ();
1630 	MonoJitDomainInfo *domain_info;
1631 	GSharedVtTrampInfo *tramp_info;
1632 	GSharedVtTrampInfo tinfo;
1633 
1634 	if (mono_llvm_only) {
1635 		MonoMethod *wrapper;
1636 
1637 		if (gsharedvt_in)
1638 			wrapper = mini_get_gsharedvt_in_sig_wrapper (normal_sig);
1639 		else
1640 			wrapper = mini_get_gsharedvt_out_sig_wrapper (normal_sig);
1641 		res = mono_compile_method_checked (wrapper, &error);
1642 		mono_error_assert_ok (&error);
1643 		return res;
1644 	}
1645 
1646 	memset (&tinfo, 0, sizeof (tinfo));
1647 	tinfo.is_in = gsharedvt_in;
1648 	tinfo.calli = calli;
1649 	tinfo.vcall_offset = vcall_offset;
1650 	tinfo.addr = addr;
1651 	tinfo.sig = normal_sig;
1652 	tinfo.gsig = gsharedvt_sig;
1653 
1654 	domain_info = domain_jit_info (domain);
1655 
1656 	/*
1657 	 * The arg trampolines might only have a finite number in full-aot, so use a cache.
1658 	 */
1659 	mono_domain_lock (domain);
1660 	if (!domain_info->gsharedvt_arg_tramp_hash)
1661 		domain_info->gsharedvt_arg_tramp_hash = g_hash_table_new (tramp_info_hash, tramp_info_equal);
1662 	res = g_hash_table_lookup (domain_info->gsharedvt_arg_tramp_hash, &tinfo);
1663 	mono_domain_unlock (domain);
1664 	if (res)
1665 		return res;
1666 
1667 	info = mono_arch_get_gsharedvt_call_info (addr, normal_sig, gsharedvt_sig, gsharedvt_in, vcall_offset, calli);
1668 
1669 	if (gsharedvt_in) {
1670 		static gpointer tramp_addr;
1671 		MonoMethod *wrapper;
1672 
1673 		if (!tramp_addr) {
1674 			wrapper = mono_marshal_get_gsharedvt_in_wrapper ();
1675 			addr = mono_compile_method_checked (wrapper, &error);
1676 			mono_memory_barrier ();
1677 			mono_error_assert_ok (&error);
1678 			tramp_addr = addr;
1679 		}
1680 		addr = tramp_addr;
1681 	} else {
1682 		static gpointer tramp_addr;
1683 		MonoMethod *wrapper;
1684 
1685 		if (!tramp_addr) {
1686 			wrapper = mono_marshal_get_gsharedvt_out_wrapper ();
1687 			addr = mono_compile_method_checked (wrapper, &error);
1688 			mono_memory_barrier ();
1689 			mono_error_assert_ok (&error);
1690 			tramp_addr = addr;
1691 		}
1692 		addr = tramp_addr;
1693 	}
1694 
1695 	if (mono_aot_only)
1696 		addr = mono_aot_get_gsharedvt_arg_trampoline (info, addr);
1697 	else
1698 		addr = mono_arch_get_gsharedvt_arg_trampoline (mono_domain_get (), info, addr);
1699 
1700 	mono_atomic_inc_i32 (&gsharedvt_num_trampolines);
1701 
1702 	/* Cache it */
1703 	tramp_info = (GSharedVtTrampInfo *)mono_domain_alloc0 (domain, sizeof (GSharedVtTrampInfo));
1704 	memcpy (tramp_info, &tinfo, sizeof (GSharedVtTrampInfo));
1705 
1706 	mono_domain_lock (domain);
1707 	/* Duplicates are not a problem */
1708 	g_hash_table_insert (domain_info->gsharedvt_arg_tramp_hash, tramp_info, addr);
1709 	mono_domain_unlock (domain);
1710 
1711 	return addr;
1712 }
1713 
1714 /*
1715  * instantiate_info:
1716  *
1717  *   Instantiate the info given by OTI for context CONTEXT.
1718  */
1719 static gpointer
instantiate_info(MonoDomain * domain,MonoRuntimeGenericContextInfoTemplate * oti,MonoGenericContext * context,MonoClass * klass,MonoError * error)1720 instantiate_info (MonoDomain *domain, MonoRuntimeGenericContextInfoTemplate *oti,
1721 				  MonoGenericContext *context, MonoClass *klass, MonoError *error)
1722 {
1723 	gpointer data;
1724 	gboolean temporary;
1725 
1726 	error_init (error);
1727 
1728 	if (!oti->data)
1729 		return NULL;
1730 
1731 	switch (oti->info_type) {
1732 	case MONO_RGCTX_INFO_STATIC_DATA:
1733 	case MONO_RGCTX_INFO_KLASS:
1734 	case MONO_RGCTX_INFO_ELEMENT_KLASS:
1735 	case MONO_RGCTX_INFO_VTABLE:
1736 	case MONO_RGCTX_INFO_CAST_CACHE:
1737 		temporary = TRUE;
1738 		break;
1739 	default:
1740 		temporary = FALSE;
1741 	}
1742 
1743 	data = inflate_info (oti, context, klass, temporary);
1744 
1745 	switch (oti->info_type) {
1746 	case MONO_RGCTX_INFO_STATIC_DATA:
1747 	case MONO_RGCTX_INFO_KLASS:
1748 	case MONO_RGCTX_INFO_ELEMENT_KLASS:
1749 	case MONO_RGCTX_INFO_VTABLE:
1750 	case MONO_RGCTX_INFO_CAST_CACHE:
1751 	case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
1752 	case MONO_RGCTX_INFO_VALUE_SIZE:
1753 	case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
1754 	case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS:
1755 	case MONO_RGCTX_INFO_MEMCPY:
1756 	case MONO_RGCTX_INFO_BZERO:
1757 	case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
1758 	case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: {
1759 		MonoClass *arg_class = mono_class_from_mono_type ((MonoType *)data);
1760 
1761 		free_inflated_info (oti->info_type, data);
1762 		g_assert (arg_class);
1763 
1764 		/* The class might be used as an argument to
1765 		   mono_value_copy(), which requires that its GC
1766 		   descriptor has been computed. */
1767 		if (oti->info_type == MONO_RGCTX_INFO_KLASS)
1768 			mono_class_compute_gc_descriptor (arg_class);
1769 
1770 		return class_type_info (domain, arg_class, oti->info_type, error);
1771 	}
1772 	case MONO_RGCTX_INFO_TYPE:
1773 		return data;
1774 	case MONO_RGCTX_INFO_REFLECTION_TYPE: {
1775 		MonoReflectionType *ret = mono_type_get_object_checked (domain, (MonoType *)data, error);
1776 
1777 		return ret;
1778 	}
1779 	case MONO_RGCTX_INFO_METHOD:
1780 		return data;
1781 	case MONO_RGCTX_INFO_GENERIC_METHOD_CODE: {
1782 		MonoMethod *m = (MonoMethod*)data;
1783 		gpointer addr;
1784 		gpointer arg = NULL;
1785 
1786 		if (mono_llvm_only) {
1787 			addr = mono_compile_method_checked (m, error);
1788 			return_val_if_nok (error, NULL);
1789 			addr = mini_add_method_wrappers_llvmonly (m, addr, FALSE, FALSE, &arg);
1790 
1791 			/* Returns an ftndesc */
1792 			return mini_create_llvmonly_ftndesc (domain, addr, arg);
1793 		} else {
1794 			addr = mono_compile_method_checked ((MonoMethod *)data, error);
1795 			return_val_if_nok (error, NULL);
1796 			return mini_add_method_trampoline ((MonoMethod *)data, addr, mono_method_needs_static_rgctx_invoke ((MonoMethod *)data, FALSE), FALSE);
1797 		}
1798 	}
1799 	case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER: {
1800 		MonoMethod *m = (MonoMethod*)data;
1801 		gpointer addr;
1802 		gpointer arg = NULL;
1803 
1804 		g_assert (mono_llvm_only);
1805 
1806 		addr = mono_compile_method_checked (m, error);
1807 		return_val_if_nok (error, NULL);
1808 
1809 		MonoJitInfo *ji;
1810 		gboolean callee_gsharedvt;
1811 
1812 		ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr), NULL);
1813 		g_assert (ji);
1814 		callee_gsharedvt = mini_jit_info_is_gsharedvt (ji);
1815 		if (callee_gsharedvt)
1816 			callee_gsharedvt = mini_is_gsharedvt_variable_signature (mono_method_signature (jinfo_get_method (ji)));
1817 		if (callee_gsharedvt) {
1818 			/* No need for a wrapper */
1819 			return mini_create_llvmonly_ftndesc (domain, addr, mini_method_get_rgctx (m));
1820 		} else {
1821 			addr = mini_add_method_wrappers_llvmonly (m, addr, TRUE, FALSE, &arg);
1822 
1823 			/* Returns an ftndesc */
1824 			return mini_create_llvmonly_ftndesc (domain, addr, arg);
1825 		}
1826 	}
1827 	case MONO_RGCTX_INFO_VIRT_METHOD_CODE: {
1828 		MonoJumpInfoVirtMethod *info = (MonoJumpInfoVirtMethod *)data;
1829 		MonoClass *iface_class = info->method->klass;
1830 		MonoMethod *method;
1831 		int ioffset, slot;
1832 		gpointer addr;
1833 
1834 		mono_class_setup_vtable (info->klass);
1835 		// FIXME: Check type load
1836 		if (mono_class_is_interface (iface_class)) {
1837 			ioffset = mono_class_interface_offset (info->klass, iface_class);
1838 			g_assert (ioffset != -1);
1839 		} else {
1840 			ioffset = 0;
1841 		}
1842 		slot = mono_method_get_vtable_slot (info->method);
1843 		g_assert (slot != -1);
1844 		g_assert (info->klass->vtable);
1845 		method = info->klass->vtable [ioffset + slot];
1846 
1847 		method = mono_class_inflate_generic_method_checked (method, context, error);
1848 		return_val_if_nok (error, NULL);
1849 
1850 		addr = mono_compile_method_checked (method, error);
1851 		return_val_if_nok (error, NULL);
1852 		if (mono_llvm_only) {
1853 			gpointer arg = NULL;
1854 			addr = mini_add_method_wrappers_llvmonly (method, addr, FALSE, FALSE, &arg);
1855 
1856 			/* Returns an ftndesc */
1857 			return mini_create_llvmonly_ftndesc (domain, addr, arg);
1858 		} else {
1859 			return mini_add_method_trampoline (method, addr, mono_method_needs_static_rgctx_invoke (method, FALSE), FALSE);
1860 		}
1861 	}
1862 	case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: {
1863 		MonoJumpInfoVirtMethod *info = (MonoJumpInfoVirtMethod *)data;
1864 		MonoClass *iface_class = info->method->klass;
1865 		MonoMethod *method;
1866 		MonoClass *impl_class;
1867 		int ioffset, slot;
1868 
1869 		mono_class_setup_vtable (info->klass);
1870 		// FIXME: Check type load
1871 		if (mono_class_is_interface (iface_class)) {
1872 			ioffset = mono_class_interface_offset (info->klass, iface_class);
1873 			g_assert (ioffset != -1);
1874 		} else {
1875 			ioffset = 0;
1876 		}
1877 		slot = mono_method_get_vtable_slot (info->method);
1878 		g_assert (slot != -1);
1879 		g_assert (info->klass->vtable);
1880 		method = info->klass->vtable [ioffset + slot];
1881 
1882 		impl_class = method->klass;
1883 		if (MONO_TYPE_IS_REFERENCE (&impl_class->byval_arg))
1884 			return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_REF);
1885 		else if (mono_class_is_nullable (impl_class))
1886 			return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_NULLABLE);
1887 		else
1888 			return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_VTYPE);
1889 	}
1890 #ifndef DISABLE_REMOTING
1891 	case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
1892 		return mono_compile_method_checked (mono_marshal_get_remoting_invoke_with_check ((MonoMethod *)data), error);
1893 #endif
1894 	case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
1895 		return mono_domain_alloc0 (domain, sizeof (gpointer));
1896 	case MONO_RGCTX_INFO_CLASS_FIELD:
1897 		return data;
1898 	case MONO_RGCTX_INFO_FIELD_OFFSET: {
1899 		MonoClassField *field = (MonoClassField *)data;
1900 
1901 		/* The value is offset by 1 */
1902 		if (field->parent->valuetype && !(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1903 			return GUINT_TO_POINTER (field->offset - sizeof (MonoObject) + 1);
1904 		else
1905 			return GUINT_TO_POINTER (field->offset + 1);
1906 	}
1907 	case MONO_RGCTX_INFO_METHOD_RGCTX: {
1908 		MonoMethodInflated *method = (MonoMethodInflated *)data;
1909 		MonoVTable *vtable;
1910 
1911 		g_assert (method->method.method.is_inflated);
1912 		g_assert (method->context.method_inst);
1913 
1914 		vtable = mono_class_vtable (domain, method->method.method.klass);
1915 		if (!vtable) {
1916 			mono_error_set_for_class_failure (error, method->method.method.klass);
1917 			return NULL;
1918 		}
1919 
1920 		return mono_method_lookup_rgctx (vtable, method->context.method_inst);
1921 	}
1922 	case MONO_RGCTX_INFO_METHOD_CONTEXT: {
1923 		MonoMethodInflated *method = (MonoMethodInflated *)data;
1924 
1925 		g_assert (method->method.method.is_inflated);
1926 		g_assert (method->context.method_inst);
1927 
1928 		return method->context.method_inst;
1929 	}
1930 	case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI: {
1931 		MonoMethodSignature *gsig = (MonoMethodSignature *)oti->data;
1932 		MonoMethodSignature *sig = (MonoMethodSignature *)data;
1933 		gpointer addr;
1934 
1935 		/*
1936 		 * This is an indirect call to the address passed by the caller in the rgctx reg.
1937 		 */
1938 		addr = mini_get_gsharedvt_wrapper (TRUE, NULL, sig, gsig, -1, TRUE);
1939 		return addr;
1940 	}
1941 	case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: {
1942 		MonoMethodSignature *gsig = (MonoMethodSignature *)oti->data;
1943 		MonoMethodSignature *sig = (MonoMethodSignature *)data;
1944 		gpointer addr;
1945 
1946 		/*
1947 		 * This is an indirect call to the address passed by the caller in the rgctx reg.
1948 		 */
1949 		addr = mini_get_gsharedvt_wrapper (FALSE, NULL, sig, gsig, -1, TRUE);
1950 		return addr;
1951 	}
1952 	case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
1953 	case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: {
1954 		MonoJumpInfoGSharedVtCall *call_info = (MonoJumpInfoGSharedVtCall *)data;
1955 		MonoMethodSignature *call_sig;
1956 		MonoMethod *method;
1957 		gpointer addr;
1958 		MonoJitInfo *callee_ji;
1959 		gboolean virtual_ = oti->info_type == MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
1960 		gint32 vcall_offset;
1961 		gboolean callee_gsharedvt;
1962 
1963 		/* This is the original generic signature used by the caller */
1964 		call_sig = call_info->sig;
1965 		/* This is the instantiated method which is called */
1966 		method = call_info->method;
1967 
1968 		g_assert (method->is_inflated);
1969 
1970 		if (mono_llvm_only && (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED))
1971 			method = mono_marshal_get_synchronized_wrapper (method);
1972 
1973 		if (!virtual_) {
1974 			addr = mono_compile_method_checked (method, error);
1975 			return_val_if_nok (error, NULL);
1976 		} else
1977 			addr = NULL;
1978 
1979 		if (virtual_) {
1980 			/* Same as in mono_emit_method_call_full () */
1981 			if ((method->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (method->name, "Invoke"))) {
1982 				/* See mono_emit_method_call_full () */
1983 				/* The gsharedvt trampoline will recognize this constant */
1984 				vcall_offset = MONO_GSHAREDVT_DEL_INVOKE_VT_OFFSET;
1985 			} else if (mono_class_is_interface (method->klass)) {
1986 				guint32 imt_slot = mono_method_get_imt_slot (method);
1987 				vcall_offset = ((gint32)imt_slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
1988 			} else {
1989 				vcall_offset = G_STRUCT_OFFSET (MonoVTable, vtable) +
1990 					((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
1991 			}
1992 		} else {
1993 			vcall_offset = -1;
1994 		}
1995 
1996 		// FIXME: This loads information in the AOT case
1997 		callee_ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr), NULL);
1998 		callee_gsharedvt = ji_is_gsharedvt (callee_ji);
1999 
2000 		/*
2001 		 * For gsharedvt calls made out of gsharedvt methods, the callee could end up being a gsharedvt method, or a normal
2002 		 * non-shared method. The latter call cannot be patched, so instead of using a normal call, we make an indirect
2003 		 * call through the rgctx, in effect patching the rgctx entry instead of the call site.
2004 		 * For virtual calls, the caller might be a normal or a gsharedvt method. Since there is only one vtable slot,
2005 		 * this difference needs to be handed on the caller side. This is currently implemented by adding a gsharedvt-in
2006 		 * trampoline to all gsharedvt methods and storing this trampoline into the vtable slot. Virtual calls made from
2007 		 * gsharedvt methods always go through a gsharedvt-out trampoline, so the calling sequence is:
2008 		 * caller -> out trampoline -> in trampoline -> callee
2009 		 * This is not very efficient, but it is easy to implement.
2010 		 */
2011 		if (virtual_ || !callee_gsharedvt) {
2012 			MonoMethodSignature *sig, *gsig;
2013 
2014 			g_assert (method->is_inflated);
2015 
2016 			sig = mono_method_signature (method);
2017 			gsig = call_sig;
2018 
2019 			if (mono_llvm_only) {
2020 				if (mini_is_gsharedvt_variable_signature (call_sig)) {
2021 					/* The virtual case doesn't go through this code */
2022 					g_assert (!virtual_);
2023 
2024 					sig = mono_method_signature (jinfo_get_method (callee_ji));
2025 					gpointer out_wrapper = mini_get_gsharedvt_wrapper (FALSE, NULL, sig, gsig, -1, FALSE);
2026 					MonoFtnDesc *out_wrapper_arg = mini_create_llvmonly_ftndesc (domain, callee_ji->code_start, mini_method_get_rgctx (method));
2027 
2028 					/* Returns an ftndesc */
2029 					addr = mini_create_llvmonly_ftndesc (domain, out_wrapper, out_wrapper_arg);
2030 				} else {
2031 					addr = mini_create_llvmonly_ftndesc (domain, addr, mini_method_get_rgctx (method));
2032 				}
2033 			} else {
2034 				addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, vcall_offset, FALSE);
2035 			}
2036 #if 0
2037 			if (virtual)
2038 				printf ("OUT-VCALL: %s\n", mono_method_full_name (method, TRUE));
2039 			else
2040 				printf ("OUT: %s\n", mono_method_full_name (method, TRUE));
2041 #endif
2042 		} else if (callee_gsharedvt) {
2043 			MonoMethodSignature *sig, *gsig;
2044 
2045 			/*
2046 			 * This is a combination of the out and in cases, since both the caller and the callee are gsharedvt methods.
2047 			 * The caller and the callee can use different gsharedvt signatures, so we have to add both an out and an in
2048 			 * trampoline, i.e.:
2049 			 * class Base<T> {
2050 			 *   public void foo<T1> (T1 t1, T t, object o) {}
2051 			 * }
2052 			 * class AClass : Base<long> {
2053 			 * public void bar<T> (T t, long time, object o) {
2054 			 *   foo (t, time, o);
2055 			 * }
2056 			 * }
2057 			 * Here, the caller uses !!0,long, while the callee uses !!0,!0
2058 			 * FIXME: Optimize this.
2059 			 */
2060 
2061 			if (mono_llvm_only) {
2062 				/* Both wrappers receive an extra <addr, rgctx> argument */
2063 				sig = mono_method_signature (method);
2064 				gsig = mono_method_signature (jinfo_get_method (callee_ji));
2065 
2066 				/* Return a function descriptor */
2067 
2068 				if (mini_is_gsharedvt_variable_signature (call_sig)) {
2069 					/*
2070 					 * This is not an optimization, but its needed, since the concrete signature 'sig'
2071 					 * might not exist at all in IL, so the AOT compiler cannot generate the wrappers
2072 					 * for it.
2073 					 */
2074 					addr = mini_create_llvmonly_ftndesc (domain, callee_ji->code_start, mini_method_get_rgctx (method));
2075 				} else if (mini_is_gsharedvt_variable_signature (gsig)) {
2076 					gpointer in_wrapper = mini_get_gsharedvt_wrapper (TRUE, callee_ji->code_start, sig, gsig, -1, FALSE);
2077 
2078 					gpointer in_wrapper_arg = mini_create_llvmonly_ftndesc (domain, callee_ji->code_start, mini_method_get_rgctx (method));
2079 
2080 					addr = mini_create_llvmonly_ftndesc (domain, in_wrapper, in_wrapper_arg);
2081 				} else {
2082 					addr = mini_create_llvmonly_ftndesc (domain, addr, mini_method_get_rgctx (method));
2083 				}
2084 			} else if (call_sig == mono_method_signature (method)) {
2085 			} else {
2086 				sig = mono_method_signature (method);
2087 				gsig = mono_method_signature (jinfo_get_method (callee_ji));
2088 
2089 				addr = mini_get_gsharedvt_wrapper (TRUE, callee_ji->code_start, sig, gsig, -1, FALSE);
2090 
2091 				sig = mono_method_signature (method);
2092 				gsig = call_sig;
2093 
2094 				addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, -1, FALSE);
2095 
2096 				//printf ("OUT-IN-RGCTX: %s\n", mono_method_full_name (method, TRUE));
2097 			}
2098 		}
2099 
2100 		return addr;
2101 	}
2102 	case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: {
2103 		MonoGSharedVtMethodInfo *info = (MonoGSharedVtMethodInfo *)data;
2104 		MonoGSharedVtMethodRuntimeInfo *res;
2105 		MonoType *t;
2106 		int i, offset, align, size;
2107 
2108 		// FIXME:
2109 		res = (MonoGSharedVtMethodRuntimeInfo *)g_malloc0 (sizeof (MonoGSharedVtMethodRuntimeInfo) + (info->num_entries * sizeof (gpointer)));
2110 
2111 		offset = 0;
2112 		for (i = 0; i < info->num_entries; ++i) {
2113 			MonoRuntimeGenericContextInfoTemplate *template_ = &info->entries [i];
2114 
2115 			switch (template_->info_type) {
2116 			case MONO_RGCTX_INFO_LOCAL_OFFSET:
2117 				t = (MonoType *)template_->data;
2118 
2119 				size = mono_type_size (t, &align);
2120 
2121 				if (align < sizeof (gpointer))
2122 					align = sizeof (gpointer);
2123 				if (MONO_TYPE_ISSTRUCT (t) && align < 2 * sizeof (gpointer))
2124 					align = 2 * sizeof (gpointer);
2125 
2126 				// FIXME: Do the same things as alloc_stack_slots
2127 				offset += align - 1;
2128 				offset &= ~(align - 1);
2129 				res->entries [i] = GINT_TO_POINTER (offset);
2130 				offset += size;
2131 				break;
2132 			default:
2133 				res->entries [i] = instantiate_info (domain, template_, context, klass, error);
2134 				if (!mono_error_ok (error))
2135 					return NULL;
2136 				break;
2137 			}
2138 		}
2139 		res->locals_size = offset;
2140 
2141 		return res;
2142 	}
2143 	default:
2144 		g_assert_not_reached ();
2145 	}
2146 	/* Not reached */
2147 	return NULL;
2148 }
2149 
2150 /*
2151  * LOCKING: loader lock
2152  */
2153 static void
fill_in_rgctx_template_slot(MonoClass * klass,int type_argc,int index,gpointer data,MonoRgctxInfoType info_type)2154 fill_in_rgctx_template_slot (MonoClass *klass, int type_argc, int index, gpointer data, MonoRgctxInfoType info_type)
2155 {
2156 	MonoRuntimeGenericContextTemplate *template_ = mono_class_get_runtime_generic_context_template (klass);
2157 	MonoClass *subclass;
2158 
2159 	rgctx_template_set_slot (klass->image, template_, type_argc, index, data, info_type);
2160 
2161 	/* Recurse for all subclasses */
2162 	if (generic_subclass_hash)
2163 		subclass = (MonoClass *)g_hash_table_lookup (generic_subclass_hash, klass);
2164 	else
2165 		subclass = NULL;
2166 
2167 	while (subclass) {
2168 		MonoRuntimeGenericContextInfoTemplate subclass_oti;
2169 		MonoRuntimeGenericContextTemplate *subclass_template = class_lookup_rgctx_template (subclass);
2170 
2171 		g_assert (subclass_template);
2172 
2173 		subclass_oti = class_get_rgctx_template_oti (subclass->parent, type_argc, index, FALSE, FALSE, NULL);
2174 		g_assert (subclass_oti.data);
2175 
2176 		fill_in_rgctx_template_slot (subclass, type_argc, index, subclass_oti.data, info_type);
2177 
2178 		subclass = subclass_template->next_subclass;
2179 	}
2180 }
2181 
2182 const char*
mono_rgctx_info_type_to_str(MonoRgctxInfoType type)2183 mono_rgctx_info_type_to_str (MonoRgctxInfoType type)
2184 {
2185 	switch (type) {
2186 	case MONO_RGCTX_INFO_STATIC_DATA: return "STATIC_DATA";
2187 	case MONO_RGCTX_INFO_KLASS: return "KLASS";
2188 	case MONO_RGCTX_INFO_ELEMENT_KLASS: return "ELEMENT_KLASS";
2189 	case MONO_RGCTX_INFO_VTABLE: return "VTABLE";
2190 	case MONO_RGCTX_INFO_TYPE: return "TYPE";
2191 	case MONO_RGCTX_INFO_REFLECTION_TYPE: return "REFLECTION_TYPE";
2192 	case MONO_RGCTX_INFO_METHOD: return "METHOD";
2193 	case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: return "GSHAREDVT_INFO";
2194 	case MONO_RGCTX_INFO_GENERIC_METHOD_CODE: return "GENERIC_METHOD_CODE";
2195 	case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER: return "GSHAREDVT_OUT_WRAPPER";
2196 	case MONO_RGCTX_INFO_CLASS_FIELD: return "CLASS_FIELD";
2197 	case MONO_RGCTX_INFO_METHOD_RGCTX: return "METHOD_RGCTX";
2198 	case MONO_RGCTX_INFO_METHOD_CONTEXT: return "METHOD_CONTEXT";
2199 	case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK: return "REMOTING_INVOKE_WITH_CHECK";
2200 	case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE: return "METHOD_DELEGATE_CODE";
2201 	case MONO_RGCTX_INFO_CAST_CACHE: return "CAST_CACHE";
2202 	case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE: return "ARRAY_ELEMENT_SIZE";
2203 	case MONO_RGCTX_INFO_VALUE_SIZE: return "VALUE_SIZE";
2204 	case MONO_RGCTX_INFO_CLASS_BOX_TYPE: return "CLASS_BOX_TYPE";
2205 	case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS: return "CLASS_IS_REF_OR_CONTAINS_REFS";
2206 	case MONO_RGCTX_INFO_FIELD_OFFSET: return "FIELD_OFFSET";
2207 	case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE";
2208 	case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT";
2209 	case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI: return "SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI";
2210 	case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: return "SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI";
2211 	case MONO_RGCTX_INFO_MEMCPY: return "MEMCPY";
2212 	case MONO_RGCTX_INFO_BZERO: return "BZERO";
2213 	case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX: return "NULLABLE_CLASS_BOX";
2214 	case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: return "NULLABLE_CLASS_UNBOX";
2215 	case MONO_RGCTX_INFO_VIRT_METHOD_CODE: return "VIRT_METHOD_CODE";
2216 	case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: return "VIRT_METHOD_BOX_TYPE";
2217 	default:
2218 		return "<UNKNOWN RGCTX INFO TYPE>";
2219 	}
2220 }
2221 
2222 G_GNUC_UNUSED static char*
rgctx_info_to_str(MonoRgctxInfoType info_type,gpointer data)2223 rgctx_info_to_str (MonoRgctxInfoType info_type, gpointer data)
2224 {
2225 	switch (info_type) {
2226 	case MONO_RGCTX_INFO_VTABLE:
2227 		return mono_type_full_name ((MonoType*)data);
2228 	default:
2229 		return g_strdup_printf ("<%p>", data);
2230 	}
2231 }
2232 
2233 /*
2234  * LOCKING: loader lock
2235  */
2236 static int
register_info(MonoClass * klass,int type_argc,gpointer data,MonoRgctxInfoType info_type)2237 register_info (MonoClass *klass, int type_argc, gpointer data, MonoRgctxInfoType info_type)
2238 {
2239 	int i;
2240 	MonoRuntimeGenericContextTemplate *template_ = mono_class_get_runtime_generic_context_template (klass);
2241 	MonoClass *parent;
2242 	MonoRuntimeGenericContextInfoTemplate *oti;
2243 
2244 	for (i = 0, oti = get_info_templates (template_, type_argc); oti; ++i, oti = oti->next) {
2245 		if (!oti->data)
2246 			break;
2247 	}
2248 
2249 	DEBUG (printf ("set slot %s, infos [%d] = %s, %s\n", mono_type_get_full_name (class), i, mono_rgctx_info_type_to_str (info_type), rgctx_info_to_str (info_type, data)));
2250 
2251 	/* Mark the slot as used in all parent classes (until we find
2252 	   a parent class which already has it marked used). */
2253 	parent = klass->parent;
2254 	while (parent != NULL) {
2255 		MonoRuntimeGenericContextTemplate *parent_template;
2256 		MonoRuntimeGenericContextInfoTemplate *oti;
2257 
2258 		if (mono_class_is_ginst (parent))
2259 			parent = mono_class_get_generic_class (parent)->container_class;
2260 
2261 		parent_template = mono_class_get_runtime_generic_context_template (parent);
2262 		oti = rgctx_template_get_other_slot (parent_template, type_argc, i);
2263 
2264 		if (oti && oti->data)
2265 			break;
2266 
2267 		rgctx_template_set_slot (parent->image, parent_template, type_argc, i,
2268 								 MONO_RGCTX_SLOT_USED_MARKER, (MonoRgctxInfoType)0);
2269 
2270 		parent = parent->parent;
2271 	}
2272 
2273 	/* Fill in the slot in this class and in all subclasses
2274 	   recursively. */
2275 	fill_in_rgctx_template_slot (klass, type_argc, i, data, info_type);
2276 
2277 	return i;
2278 }
2279 
2280 static gboolean
info_equal(gpointer data1,gpointer data2,MonoRgctxInfoType info_type)2281 info_equal (gpointer data1, gpointer data2, MonoRgctxInfoType info_type)
2282 {
2283 	switch (info_type) {
2284 	case MONO_RGCTX_INFO_STATIC_DATA:
2285 	case MONO_RGCTX_INFO_KLASS:
2286 	case MONO_RGCTX_INFO_ELEMENT_KLASS:
2287 	case MONO_RGCTX_INFO_VTABLE:
2288 	case MONO_RGCTX_INFO_TYPE:
2289 	case MONO_RGCTX_INFO_REFLECTION_TYPE:
2290 	case MONO_RGCTX_INFO_CAST_CACHE:
2291 	case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
2292 	case MONO_RGCTX_INFO_VALUE_SIZE:
2293 	case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
2294 	case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS:
2295 	case MONO_RGCTX_INFO_MEMCPY:
2296 	case MONO_RGCTX_INFO_BZERO:
2297 	case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
2298 	case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX:
2299 		return mono_class_from_mono_type ((MonoType *)data1) == mono_class_from_mono_type ((MonoType *)data2);
2300 	case MONO_RGCTX_INFO_METHOD:
2301 	case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO:
2302 	case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
2303 	case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER:
2304 	case MONO_RGCTX_INFO_CLASS_FIELD:
2305 	case MONO_RGCTX_INFO_FIELD_OFFSET:
2306 	case MONO_RGCTX_INFO_METHOD_RGCTX:
2307 	case MONO_RGCTX_INFO_METHOD_CONTEXT:
2308 	case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
2309 	case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
2310 	case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
2311 	case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT:
2312 	case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI:
2313 	case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI:
2314 		return data1 == data2;
2315 	case MONO_RGCTX_INFO_VIRT_METHOD_CODE:
2316 	case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: {
2317 		MonoJumpInfoVirtMethod *info1 = (MonoJumpInfoVirtMethod *)data1;
2318 		MonoJumpInfoVirtMethod *info2 = (MonoJumpInfoVirtMethod *)data2;
2319 
2320 		return info1->klass == info2->klass && info1->method == info2->method;
2321 	}
2322 	default:
2323 		g_assert_not_reached ();
2324 	}
2325 	/* never reached */
2326 	return FALSE;
2327 }
2328 
2329 /*
2330  * mini_rgctx_info_type_to_patch_info_type:
2331  *
2332  *   Return the type of the runtime object referred to by INFO_TYPE.
2333  */
2334 MonoJumpInfoType
mini_rgctx_info_type_to_patch_info_type(MonoRgctxInfoType info_type)2335 mini_rgctx_info_type_to_patch_info_type (MonoRgctxInfoType info_type)
2336 {
2337 	switch (info_type) {
2338 	case MONO_RGCTX_INFO_STATIC_DATA:
2339 	case MONO_RGCTX_INFO_KLASS:
2340 	case MONO_RGCTX_INFO_ELEMENT_KLASS:
2341 	case MONO_RGCTX_INFO_VTABLE:
2342 	case MONO_RGCTX_INFO_TYPE:
2343 	case MONO_RGCTX_INFO_REFLECTION_TYPE:
2344 	case MONO_RGCTX_INFO_CAST_CACHE:
2345 	case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
2346 	case MONO_RGCTX_INFO_VALUE_SIZE:
2347 	case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
2348 	case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS:
2349 	case MONO_RGCTX_INFO_MEMCPY:
2350 	case MONO_RGCTX_INFO_BZERO:
2351 	case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
2352 	case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX:
2353 	case MONO_RGCTX_INFO_LOCAL_OFFSET:
2354 		return MONO_PATCH_INFO_CLASS;
2355 	case MONO_RGCTX_INFO_FIELD_OFFSET:
2356 		return MONO_PATCH_INFO_FIELD;
2357 	default:
2358 		g_assert_not_reached ();
2359 		return (MonoJumpInfoType)-1;
2360 	}
2361 }
2362 
2363 static int
lookup_or_register_info(MonoClass * klass,int type_argc,gpointer data,MonoRgctxInfoType info_type,MonoGenericContext * generic_context)2364 lookup_or_register_info (MonoClass *klass, int type_argc, gpointer data, MonoRgctxInfoType info_type,
2365 	MonoGenericContext *generic_context)
2366 {
2367 	MonoRuntimeGenericContextTemplate *rgctx_template =
2368 		mono_class_get_runtime_generic_context_template (klass);
2369 	MonoRuntimeGenericContextInfoTemplate *oti_list, *oti;
2370 	int i;
2371 
2372 	klass = get_shared_class (klass);
2373 
2374 	mono_loader_lock ();
2375 
2376 	if (info_has_identity (info_type)) {
2377 		oti_list = get_info_templates (rgctx_template, type_argc);
2378 
2379 		for (oti = oti_list, i = 0; oti; oti = oti->next, ++i) {
2380 			gpointer inflated_data;
2381 
2382 			if (oti->info_type != info_type || !oti->data)
2383 				continue;
2384 
2385 			inflated_data = inflate_info (oti, generic_context, klass, TRUE);
2386 
2387 			if (info_equal (data, inflated_data, info_type)) {
2388 				free_inflated_info (info_type, inflated_data);
2389 				mono_loader_unlock ();
2390 				return i;
2391 			}
2392 			free_inflated_info (info_type, inflated_data);
2393 		}
2394 	}
2395 
2396 	/* We haven't found the info */
2397 	i = register_info (klass, type_argc, data, info_type);
2398 
2399 	/* interlocked by loader lock */
2400 	if (i > UnlockedRead (&rgctx_max_slot_number))
2401 		UnlockedWrite (&rgctx_max_slot_number, i);
2402 
2403 	mono_loader_unlock ();
2404 
2405 	return i;
2406 }
2407 
2408 /*
2409  * mono_method_lookup_or_register_info:
2410  * @method: a method
2411  * @in_mrgctx: whether to put the data into the MRGCTX
2412  * @data: the info data
2413  * @info_type: the type of info to register about data
2414  * @generic_context: a generic context
2415  *
2416  * Looks up and, if necessary, adds information about data/info_type in
2417  * method's or method's class runtime generic context.  Returns the
2418  * encoded slot number.
2419  */
2420 guint32
mono_method_lookup_or_register_info(MonoMethod * method,gboolean in_mrgctx,gpointer data,MonoRgctxInfoType info_type,MonoGenericContext * generic_context)2421 mono_method_lookup_or_register_info (MonoMethod *method, gboolean in_mrgctx, gpointer data,
2422 	MonoRgctxInfoType info_type, MonoGenericContext *generic_context)
2423 {
2424 	MonoClass *klass = method->klass;
2425 	int type_argc, index;
2426 
2427 	if (in_mrgctx) {
2428 		MonoGenericInst *method_inst = mono_method_get_context (method)->method_inst;
2429 
2430 		g_assert (method->is_inflated && method_inst);
2431 		type_argc = method_inst->type_argc;
2432 		g_assert (type_argc > 0);
2433 	} else {
2434 		type_argc = 0;
2435 	}
2436 
2437 	index = lookup_or_register_info (klass, type_argc, data, info_type, generic_context);
2438 
2439 	//g_print ("rgctx item at index %d argc %d\n", index, type_argc);
2440 
2441 	if (in_mrgctx)
2442 		return MONO_RGCTX_SLOT_MAKE_MRGCTX (index);
2443 	else
2444 		return MONO_RGCTX_SLOT_MAKE_RGCTX (index);
2445 }
2446 
2447 /*
2448  * mono_class_rgctx_get_array_size:
2449  * @n: The number of the array
2450  * @mrgctx: Whether it's an MRGCTX as opposed to a RGCTX.
2451  *
2452  * Returns the number of slots in the n'th array of a (M)RGCTX.  That
2453  * number includes the slot for linking and - for MRGCTXs - the two
2454  * slots in the first array for additional information.
2455  */
2456 int
mono_class_rgctx_get_array_size(int n,gboolean mrgctx)2457 mono_class_rgctx_get_array_size (int n, gboolean mrgctx)
2458 {
2459 	g_assert (n >= 0 && n < 30);
2460 
2461 	if (mrgctx)
2462 		return 6 << n;
2463 	else
2464 		return 4 << n;
2465 }
2466 
2467 /*
2468  * LOCKING: domain lock
2469  */
2470 static gpointer*
alloc_rgctx_array(MonoDomain * domain,int n,gboolean is_mrgctx)2471 alloc_rgctx_array (MonoDomain *domain, int n, gboolean is_mrgctx)
2472 {
2473 	gint32 size = mono_class_rgctx_get_array_size (n, is_mrgctx) * sizeof (gpointer);
2474 	gpointer *array = (gpointer *)mono_domain_alloc0 (domain, size);
2475 
2476 	/* interlocked by domain lock (by definition) */
2477 	if (is_mrgctx) {
2478 		UnlockedIncrement (&mrgctx_num_arrays_allocated);
2479 		UnlockedAdd (&mrgctx_bytes_allocated, size);
2480 	} else {
2481 		UnlockedIncrement (&rgctx_num_arrays_allocated);
2482 		UnlockedAdd (&rgctx_bytes_allocated, size);
2483 	}
2484 
2485 	return array;
2486 }
2487 
2488 static gpointer
fill_runtime_generic_context(MonoVTable * class_vtable,MonoRuntimeGenericContext * rgctx,guint32 slot,MonoGenericInst * method_inst,MonoError * error)2489 fill_runtime_generic_context (MonoVTable *class_vtable, MonoRuntimeGenericContext *rgctx, guint32 slot,
2490 							  MonoGenericInst *method_inst, MonoError *error)
2491 {
2492 	gpointer info;
2493 	int i, first_slot, size;
2494 	MonoDomain *domain = class_vtable->domain;
2495 	MonoClass *klass = class_vtable->klass;
2496 	MonoGenericContext *class_context = mono_class_is_ginst (klass) ? &mono_class_get_generic_class (klass)->context : NULL;
2497 	MonoRuntimeGenericContextInfoTemplate oti;
2498 	MonoGenericContext context = { class_context ? class_context->class_inst : NULL, method_inst };
2499 	int rgctx_index;
2500 	gboolean do_free;
2501 
2502 	error_init (error);
2503 
2504 	g_assert (rgctx);
2505 
2506 	mono_domain_lock (domain);
2507 
2508 	/* First check whether that slot isn't already instantiated.
2509 	   This might happen because lookup doesn't lock.  Allocate
2510 	   arrays on the way. */
2511 	first_slot = 0;
2512 	size = mono_class_rgctx_get_array_size (0, method_inst != NULL);
2513 	if (method_inst)
2514 		size -= MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
2515 	for (i = 0; ; ++i) {
2516 		int offset;
2517 
2518 		if (method_inst && i == 0)
2519 			offset = MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
2520 		else
2521 			offset = 0;
2522 
2523 		if (slot < first_slot + size - 1) {
2524 			rgctx_index = slot - first_slot + 1 + offset;
2525 			info = rgctx [rgctx_index];
2526 			if (info) {
2527 				mono_domain_unlock (domain);
2528 				return info;
2529 			}
2530 			break;
2531 		}
2532 		if (!rgctx [offset + 0])
2533 			rgctx [offset + 0] = alloc_rgctx_array (domain, i + 1, method_inst != NULL);
2534 		rgctx = (void **)rgctx [offset + 0];
2535 		first_slot += size - 1;
2536 		size = mono_class_rgctx_get_array_size (i + 1, method_inst != NULL);
2537 	}
2538 
2539 	g_assert (!rgctx [rgctx_index]);
2540 
2541 	mono_domain_unlock (domain);
2542 
2543 	oti = class_get_rgctx_template_oti (get_shared_class (klass),
2544 										method_inst ? method_inst->type_argc : 0, slot, TRUE, TRUE, &do_free);
2545 	/* This might take the loader lock */
2546 	info = instantiate_info (domain, &oti, &context, klass, error);
2547 	return_val_if_nok (error, NULL);
2548 	g_assert (info);
2549 
2550 	/*
2551 	if (method_inst)
2552 		g_print ("filling mrgctx slot %d table %d index %d\n", slot, i, rgctx_index);
2553 	*/
2554 
2555 	/*FIXME We should use CAS here, no need to take a lock.*/
2556 	mono_domain_lock (domain);
2557 
2558 	/* Check whether the slot hasn't been instantiated in the
2559 	   meantime. */
2560 	if (rgctx [rgctx_index])
2561 		info = rgctx [rgctx_index];
2562 	else
2563 		rgctx [rgctx_index] = info;
2564 
2565 	mono_domain_unlock (domain);
2566 
2567 	if (do_free)
2568 		free_inflated_info (oti.info_type, oti.data);
2569 
2570 	return info;
2571 }
2572 
2573 /*
2574  * mono_class_fill_runtime_generic_context:
2575  * @class_vtable: a vtable
2576  * @slot: a slot index to be instantiated
2577  *
2578  * Instantiates a slot in the RGCTX, returning its value.
2579  */
2580 gpointer
mono_class_fill_runtime_generic_context(MonoVTable * class_vtable,guint32 slot,MonoError * error)2581 mono_class_fill_runtime_generic_context (MonoVTable *class_vtable, guint32 slot, MonoError *error)
2582 {
2583 	MonoDomain *domain = class_vtable->domain;
2584 	MonoRuntimeGenericContext *rgctx;
2585 	gpointer info;
2586 
2587 	error_init (error);
2588 
2589 	mono_domain_lock (domain);
2590 
2591 	rgctx = class_vtable->runtime_generic_context;
2592 	if (!rgctx) {
2593 		rgctx = alloc_rgctx_array (domain, 0, FALSE);
2594 		class_vtable->runtime_generic_context = rgctx;
2595 		UnlockedIncrement (&rgctx_num_allocated); /* interlocked by domain lock */
2596 	}
2597 
2598 	mono_domain_unlock (domain);
2599 
2600 	info = fill_runtime_generic_context (class_vtable, rgctx, slot, 0, error);
2601 
2602 	DEBUG (printf ("get rgctx slot: %s %d -> %p\n", mono_type_full_name (&class_vtable->klass->byval_arg), slot, info));
2603 
2604 	return info;
2605 }
2606 
2607 /*
2608  * mono_method_fill_runtime_generic_context:
2609  * @mrgctx: an MRGCTX
2610  * @slot: a slot index to be instantiated
2611  *
2612  * Instantiates a slot in the MRGCTX.
2613  */
2614 gpointer
mono_method_fill_runtime_generic_context(MonoMethodRuntimeGenericContext * mrgctx,guint32 slot,MonoError * error)2615 mono_method_fill_runtime_generic_context (MonoMethodRuntimeGenericContext *mrgctx, guint32 slot, MonoError *error)
2616 {
2617 	gpointer info;
2618 
2619 	info = fill_runtime_generic_context (mrgctx->class_vtable, (MonoRuntimeGenericContext*)mrgctx, slot, mrgctx->method_inst, error);
2620 
2621 	return info;
2622 }
2623 
2624 static guint
mrgctx_hash_func(gconstpointer key)2625 mrgctx_hash_func (gconstpointer key)
2626 {
2627 	const MonoMethodRuntimeGenericContext *mrgctx = (const MonoMethodRuntimeGenericContext *)key;
2628 
2629 	return mono_aligned_addr_hash (mrgctx->class_vtable) ^ mono_metadata_generic_inst_hash (mrgctx->method_inst);
2630 }
2631 
2632 static gboolean
mrgctx_equal_func(gconstpointer a,gconstpointer b)2633 mrgctx_equal_func (gconstpointer a, gconstpointer b)
2634 {
2635 	const MonoMethodRuntimeGenericContext *mrgctx1 = (const MonoMethodRuntimeGenericContext *)a;
2636 	const MonoMethodRuntimeGenericContext *mrgctx2 = (const MonoMethodRuntimeGenericContext *)b;
2637 
2638 	return mrgctx1->class_vtable == mrgctx2->class_vtable &&
2639 		mono_metadata_generic_inst_equal (mrgctx1->method_inst, mrgctx2->method_inst);
2640 }
2641 
2642 /*
2643  * mono_method_lookup_rgctx:
2644  * @class_vtable: a vtable
2645  * @method_inst: the method inst of a generic method
2646  *
2647  * Returns the MRGCTX for the generic method(s) with the given
2648  * method_inst of the given class_vtable.
2649  *
2650  * LOCKING: Take the domain lock.
2651  */
2652 MonoMethodRuntimeGenericContext*
mono_method_lookup_rgctx(MonoVTable * class_vtable,MonoGenericInst * method_inst)2653 mono_method_lookup_rgctx (MonoVTable *class_vtable, MonoGenericInst *method_inst)
2654 {
2655 	MonoDomain *domain = class_vtable->domain;
2656 	MonoMethodRuntimeGenericContext *mrgctx;
2657 	MonoMethodRuntimeGenericContext key;
2658 
2659 	g_assert (!mono_class_is_gtd (class_vtable->klass));
2660 	g_assert (!method_inst->is_open);
2661 
2662 	mono_domain_lock (domain);
2663 	if (!domain->method_rgctx_hash)
2664 		domain->method_rgctx_hash = g_hash_table_new (mrgctx_hash_func, mrgctx_equal_func);
2665 
2666 	key.class_vtable = class_vtable;
2667 	key.method_inst = method_inst;
2668 
2669 	mrgctx = (MonoMethodRuntimeGenericContext *)g_hash_table_lookup (domain->method_rgctx_hash, &key);
2670 
2671 	if (!mrgctx) {
2672 		//int i;
2673 
2674 		mrgctx = (MonoMethodRuntimeGenericContext*)alloc_rgctx_array (domain, 0, TRUE);
2675 		mrgctx->class_vtable = class_vtable;
2676 		mrgctx->method_inst = method_inst;
2677 
2678 		g_hash_table_insert (domain->method_rgctx_hash, mrgctx, mrgctx);
2679 
2680 		/*
2681 		g_print ("mrgctx alloced for %s <", mono_type_get_full_name (class_vtable->klass));
2682 		for (i = 0; i < method_inst->type_argc; ++i)
2683 			g_print ("%s, ", mono_type_full_name (method_inst->type_argv [i]));
2684 		g_print (">\n");
2685 		*/
2686 	}
2687 
2688 	mono_domain_unlock (domain);
2689 
2690 	g_assert (mrgctx);
2691 
2692 	return mrgctx;
2693 }
2694 
2695 static gboolean
type_is_sharable(MonoType * type,gboolean allow_type_vars,gboolean allow_partial)2696 type_is_sharable (MonoType *type, gboolean allow_type_vars, gboolean allow_partial)
2697 {
2698 	if (allow_type_vars && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)) {
2699 		MonoType *constraint = type->data.generic_param->gshared_constraint;
2700 		if (!constraint)
2701 			return TRUE;
2702 		type = constraint;
2703 	}
2704 
2705 	if (MONO_TYPE_IS_REFERENCE (type))
2706 		return TRUE;
2707 
2708 	/* Allow non ref arguments if they are primitive types or enums (partial sharing). */
2709 	if (allow_partial && !type->byref && (((type->type >= MONO_TYPE_BOOLEAN) && (type->type <= MONO_TYPE_R8)) || (type->type == MONO_TYPE_I) || (type->type == MONO_TYPE_U) || (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype)))
2710 		return TRUE;
2711 
2712 	if (allow_partial && !type->byref && type->type == MONO_TYPE_GENERICINST && MONO_TYPE_ISSTRUCT (type)) {
2713 		MonoGenericClass *gclass = type->data.generic_class;
2714 
2715 		if (gclass->context.class_inst && !mini_generic_inst_is_sharable (gclass->context.class_inst, allow_type_vars, allow_partial))
2716 			return FALSE;
2717 		if (gclass->context.method_inst && !mini_generic_inst_is_sharable (gclass->context.method_inst, allow_type_vars, allow_partial))
2718 			return FALSE;
2719 		if (mono_class_is_nullable (mono_class_from_mono_type (type)))
2720 			return FALSE;
2721 		return TRUE;
2722 	}
2723 
2724 	return FALSE;
2725 }
2726 
2727 gboolean
mini_generic_inst_is_sharable(MonoGenericInst * inst,gboolean allow_type_vars,gboolean allow_partial)2728 mini_generic_inst_is_sharable (MonoGenericInst *inst, gboolean allow_type_vars,
2729 						  gboolean allow_partial)
2730 {
2731 	int i;
2732 
2733 	for (i = 0; i < inst->type_argc; ++i) {
2734 		if (!type_is_sharable (inst->type_argv [i], allow_type_vars, allow_partial))
2735 			return FALSE;
2736 	}
2737 
2738 	return TRUE;
2739 }
2740 
2741 /*
2742  * mono_is_partially_sharable_inst:
2743  *
2744  *   Return TRUE if INST has ref and non-ref type arguments.
2745  */
2746 gboolean
mono_is_partially_sharable_inst(MonoGenericInst * inst)2747 mono_is_partially_sharable_inst (MonoGenericInst *inst)
2748 {
2749 	int i;
2750 	gboolean has_refs = FALSE, has_non_refs = FALSE;
2751 
2752 	for (i = 0; i < inst->type_argc; ++i) {
2753 		if (MONO_TYPE_IS_REFERENCE (inst->type_argv [i]) || inst->type_argv [i]->type == MONO_TYPE_VAR || inst->type_argv [i]->type == MONO_TYPE_MVAR)
2754 			has_refs = TRUE;
2755 		else
2756 			has_non_refs = TRUE;
2757 	}
2758 
2759 	return has_refs && has_non_refs;
2760 }
2761 
2762 /*
2763  * mono_generic_context_is_sharable_full:
2764  * @context: a generic context
2765  *
2766  * Returns whether the generic context is sharable.  A generic context
2767  * is sharable iff all of its type arguments are reference type, or some of them have a
2768  * reference type, and ALLOW_PARTIAL is TRUE.
2769  */
2770 gboolean
mono_generic_context_is_sharable_full(MonoGenericContext * context,gboolean allow_type_vars,gboolean allow_partial)2771 mono_generic_context_is_sharable_full (MonoGenericContext *context,
2772 									   gboolean allow_type_vars,
2773 									   gboolean allow_partial)
2774 {
2775 	g_assert (context->class_inst || context->method_inst);
2776 
2777 	if (context->class_inst && !mini_generic_inst_is_sharable (context->class_inst, allow_type_vars, allow_partial))
2778 		return FALSE;
2779 
2780 	if (context->method_inst && !mini_generic_inst_is_sharable (context->method_inst, allow_type_vars, allow_partial))
2781 		return FALSE;
2782 
2783 	return TRUE;
2784 }
2785 
2786 gboolean
mono_generic_context_is_sharable(MonoGenericContext * context,gboolean allow_type_vars)2787 mono_generic_context_is_sharable (MonoGenericContext *context, gboolean allow_type_vars)
2788 {
2789 	return mono_generic_context_is_sharable_full (context, allow_type_vars, partial_sharing_supported ());
2790 }
2791 
2792 /*
2793  * mono_method_is_generic_impl:
2794  * @method: a method
2795  *
2796  * Returns whether the method is either generic or part of a generic
2797  * class.
2798  */
2799 gboolean
mono_method_is_generic_impl(MonoMethod * method)2800 mono_method_is_generic_impl (MonoMethod *method)
2801 {
2802 	if (method->is_inflated)
2803 		return TRUE;
2804 	/* We don't treat wrappers as generic code, i.e., we never
2805 	   apply generic sharing to them.  This is especially
2806 	   important for static rgctx invoke wrappers, which only work
2807 	   if not compiled with sharing. */
2808 	if (method->wrapper_type != MONO_WRAPPER_NONE)
2809 		return FALSE;
2810 	if (mono_class_is_gtd (method->klass))
2811 		return TRUE;
2812 	return FALSE;
2813 }
2814 
2815 static gboolean
has_constraints(MonoGenericContainer * container)2816 has_constraints (MonoGenericContainer *container)
2817 {
2818 	//int i;
2819 
2820 	return FALSE;
2821 	/*
2822 	g_assert (container->type_argc > 0);
2823 	g_assert (container->type_params);
2824 
2825 	for (i = 0; i < container->type_argc; ++i)
2826 		if (container->type_params [i].constraints)
2827 			return TRUE;
2828 	return FALSE;
2829 	*/
2830 }
2831 
2832 static gboolean
mini_method_is_open(MonoMethod * method)2833 mini_method_is_open (MonoMethod *method)
2834 {
2835 	if (method->is_inflated) {
2836 		MonoGenericContext *ctx = mono_method_get_context (method);
2837 
2838 		if (ctx->class_inst && ctx->class_inst->is_open)
2839 			return TRUE;
2840 		if (ctx->method_inst && ctx->method_inst->is_open)
2841 			return TRUE;
2842 	}
2843 	return FALSE;
2844 }
2845 
2846 /* Lazy class loading functions */
2847 static GENERATE_TRY_GET_CLASS_WITH_CACHE (iasync_state_machine, "System.Runtime.CompilerServices", "IAsyncStateMachine")
2848 
2849 static G_GNUC_UNUSED gboolean
is_async_state_machine_class(MonoClass * klass)2850 is_async_state_machine_class (MonoClass *klass)
2851 {
2852 	MonoClass *iclass;
2853 
2854 	return FALSE;
2855 
2856 	iclass = mono_class_try_get_iasync_state_machine_class ();
2857 
2858 	if (iclass && klass->valuetype && mono_class_is_assignable_from (iclass, klass))
2859 		return TRUE;
2860 	return FALSE;
2861 }
2862 
2863 static G_GNUC_UNUSED gboolean
is_async_method(MonoMethod * method)2864 is_async_method (MonoMethod *method)
2865 {
2866 	MonoError error;
2867 	MonoCustomAttrInfo *cattr;
2868 	MonoMethodSignature *sig;
2869 	gboolean res = FALSE;
2870 	MonoClass *attr_class;
2871 
2872 	return FALSE;
2873 
2874 	attr_class = mono_class_try_get_iasync_state_machine_class ();
2875 
2876 	/* Do less expensive checks first */
2877 	sig = mono_method_signature (method);
2878 	if (attr_class && sig && ((sig->ret->type == MONO_TYPE_VOID) ||
2879 				(sig->ret->type == MONO_TYPE_CLASS && !strcmp (sig->ret->data.generic_class->container_class->name, "Task")) ||
2880 				(sig->ret->type == MONO_TYPE_GENERICINST && !strcmp (sig->ret->data.generic_class->container_class->name, "Task`1")))) {
2881 		//printf ("X: %s\n", mono_method_full_name (method, TRUE));
2882 		cattr = mono_custom_attrs_from_method_checked (method, &error);
2883 		if (!is_ok (&error)) {
2884 			mono_error_cleanup (&error); /* FIXME don't swallow the error? */
2885 			return FALSE;
2886 		}
2887 		if (cattr) {
2888 			if (mono_custom_attrs_has_attr (cattr, attr_class))
2889 				res = TRUE;
2890 			mono_custom_attrs_free (cattr);
2891 		}
2892 	}
2893 	return res;
2894 }
2895 
2896 /*
2897  * mono_method_is_generic_sharable_full:
2898  * @method: a method
2899  * @allow_type_vars: whether to regard type variables as reference types
2900  * @allow_partial: whether to allow partial sharing
2901  * @allow_gsharedvt: whenever to allow sharing over valuetypes
2902  *
2903  * Returns TRUE iff the method is inflated or part of an inflated
2904  * class, its context is sharable and it has no constraints on its
2905  * type parameters.  Otherwise returns FALSE.
2906  */
2907 gboolean
mono_method_is_generic_sharable_full(MonoMethod * method,gboolean allow_type_vars,gboolean allow_partial,gboolean allow_gsharedvt)2908 mono_method_is_generic_sharable_full (MonoMethod *method, gboolean allow_type_vars,
2909 										   gboolean allow_partial, gboolean allow_gsharedvt)
2910 {
2911 	if (!mono_method_is_generic_impl (method))
2912 		return FALSE;
2913 
2914 	/*
2915 	if (!mono_debug_count ())
2916 		allow_partial = FALSE;
2917 	*/
2918 
2919 	if (!partial_sharing_supported ())
2920 		allow_partial = FALSE;
2921 
2922 	if (mono_class_is_nullable (method->klass))
2923 		// FIXME:
2924 		allow_partial = FALSE;
2925 
2926 	if (method->klass->image->dynamic)
2927 		/*
2928 		 * Enabling this causes corlib test failures because the JIT encounters generic instances whose
2929 		 * instance_size is 0.
2930 		 */
2931 		allow_partial = FALSE;
2932 
2933 	/*
2934 	 * Generic async methods have an associated state machine class which is a generic struct. This struct
2935 	 * is too large to be handled by gsharedvt so we make it visible to the AOT compiler by disabling sharing
2936 	 * of the async method and the state machine class.
2937 	 */
2938 	if (is_async_state_machine_class (method->klass))
2939 		return FALSE;
2940 
2941 	if (allow_gsharedvt && mini_is_gsharedvt_sharable_method (method)) {
2942 		if (is_async_method (method))
2943 			return FALSE;
2944 		return TRUE;
2945 	}
2946 
2947 	if (method->is_inflated) {
2948 		MonoMethodInflated *inflated = (MonoMethodInflated*)method;
2949 		MonoGenericContext *context = &inflated->context;
2950 
2951 		if (!mono_generic_context_is_sharable_full (context, allow_type_vars, allow_partial))
2952 			return FALSE;
2953 
2954 		g_assert (inflated->declaring);
2955 
2956 		if (inflated->declaring->is_generic) {
2957 			if (has_constraints (mono_method_get_generic_container (inflated->declaring)))
2958 				return FALSE;
2959 		}
2960 	}
2961 
2962 	if (mono_class_is_ginst (method->klass)) {
2963 		if (!mono_generic_context_is_sharable_full (&mono_class_get_generic_class (method->klass)->context, allow_type_vars, allow_partial))
2964 			return FALSE;
2965 
2966 		g_assert (mono_class_get_generic_class (method->klass)->container_class &&
2967 				mono_class_is_gtd (mono_class_get_generic_class (method->klass)->container_class));
2968 
2969 		if (has_constraints (mono_class_get_generic_container (mono_class_get_generic_class (method->klass)->container_class)))
2970 			return FALSE;
2971 	}
2972 
2973 	if (mono_class_is_gtd (method->klass) && !allow_type_vars)
2974 		return FALSE;
2975 
2976 	/* This does potentially expensive cattr checks, so do it at the end */
2977 	if (is_async_method (method)) {
2978 		if (mini_method_is_open (method))
2979 			/* The JIT can't compile these without sharing */
2980 			return TRUE;
2981 		return FALSE;
2982 	}
2983 
2984 	return TRUE;
2985 }
2986 
2987 gboolean
mono_method_is_generic_sharable(MonoMethod * method,gboolean allow_type_vars)2988 mono_method_is_generic_sharable (MonoMethod *method, gboolean allow_type_vars)
2989 {
2990 	return mono_method_is_generic_sharable_full (method, allow_type_vars, partial_sharing_supported (), TRUE);
2991 }
2992 
2993 /*
2994  * mono_method_needs_static_rgctx_invoke:
2995  *
2996  *   Return whenever METHOD needs an rgctx argument.
2997  * An rgctx argument is needed when the method is generic sharable, but it doesn't
2998  * have a this argument which can be used to load the rgctx.
2999  */
3000 gboolean
mono_method_needs_static_rgctx_invoke(MonoMethod * method,gboolean allow_type_vars)3001 mono_method_needs_static_rgctx_invoke (MonoMethod *method, gboolean allow_type_vars)
3002 {
3003 	if (!mono_class_generic_sharing_enabled (method->klass))
3004 		return FALSE;
3005 
3006 	if (!mono_method_is_generic_sharable (method, allow_type_vars))
3007 		return FALSE;
3008 
3009 	if (method->is_inflated && mono_method_get_context (method)->method_inst)
3010 		return TRUE;
3011 
3012 	return ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
3013 			method->klass->valuetype ||
3014 			MONO_CLASS_IS_INTERFACE (method->klass)) &&
3015 		(mono_class_is_ginst (method->klass) || mono_class_is_gtd (method->klass));
3016 }
3017 
3018 static MonoGenericInst*
get_object_generic_inst(int type_argc)3019 get_object_generic_inst (int type_argc)
3020 {
3021 	MonoType **type_argv;
3022 	int i;
3023 
3024 	type_argv = (MonoType **)alloca (sizeof (MonoType*) * type_argc);
3025 
3026 	for (i = 0; i < type_argc; ++i)
3027 		type_argv [i] = &mono_defaults.object_class->byval_arg;
3028 
3029 	return mono_metadata_get_generic_inst (type_argc, type_argv);
3030 }
3031 
3032 /*
3033  * mono_method_construct_object_context:
3034  * @method: a method
3035  *
3036  * Returns a generic context for method with all type variables for
3037  * class and method instantiated with Object.
3038  */
3039 MonoGenericContext
mono_method_construct_object_context(MonoMethod * method)3040 mono_method_construct_object_context (MonoMethod *method)
3041 {
3042 	MonoGenericContext object_context;
3043 
3044 	g_assert (!mono_class_is_ginst (method->klass));
3045 	if (mono_class_is_gtd (method->klass)) {
3046 		int type_argc = mono_class_get_generic_container (method->klass)->type_argc;
3047 
3048 		object_context.class_inst = get_object_generic_inst (type_argc);
3049 	} else {
3050 		object_context.class_inst = NULL;
3051 	}
3052 
3053 	if (mono_method_get_context_general (method, TRUE)->method_inst) {
3054 		int type_argc = mono_method_get_context_general (method, TRUE)->method_inst->type_argc;
3055 
3056 		object_context.method_inst = get_object_generic_inst (type_argc);
3057 	} else {
3058 		object_context.method_inst = NULL;
3059 	}
3060 
3061 	g_assert (object_context.class_inst || object_context.method_inst);
3062 
3063 	return object_context;
3064 }
3065 
3066 static gboolean gshared_supported;
3067 
3068 void
mono_set_generic_sharing_supported(gboolean supported)3069 mono_set_generic_sharing_supported (gboolean supported)
3070 {
3071 	gshared_supported = supported;
3072 }
3073 
3074 
3075 void
mono_set_partial_sharing_supported(gboolean supported)3076 mono_set_partial_sharing_supported (gboolean supported)
3077 {
3078 	partial_supported = supported;
3079 }
3080 
3081 /*
3082  * mono_class_generic_sharing_enabled:
3083  * @class: a class
3084  *
3085  * Returns whether generic sharing is enabled for class.
3086  *
3087  * This is a stop-gap measure to slowly introduce generic sharing
3088  * until we have all the issues sorted out, at which time this
3089  * function will disappear and generic sharing will always be enabled.
3090  */
3091 gboolean
mono_class_generic_sharing_enabled(MonoClass * klass)3092 mono_class_generic_sharing_enabled (MonoClass *klass)
3093 {
3094 	if (gshared_supported)
3095 		return TRUE;
3096 	else
3097 		return FALSE;
3098 }
3099 
3100 MonoGenericContext*
mini_method_get_context(MonoMethod * method)3101 mini_method_get_context (MonoMethod *method)
3102 {
3103 	return mono_method_get_context_general (method, TRUE);
3104 }
3105 
3106 /*
3107  * mono_method_check_context_used:
3108  * @method: a method
3109  *
3110  * Checks whether the method's generic context uses a type variable.
3111  * Returns an int with the bits MONO_GENERIC_CONTEXT_USED_CLASS and
3112  * MONO_GENERIC_CONTEXT_USED_METHOD set to reflect whether the
3113  * context's class or method instantiation uses type variables.
3114  */
3115 int
mono_method_check_context_used(MonoMethod * method)3116 mono_method_check_context_used (MonoMethod *method)
3117 {
3118 	MonoGenericContext *method_context = mini_method_get_context (method);
3119 	int context_used = 0;
3120 
3121 	if (!method_context) {
3122 		/* It might be a method of an array of an open generic type */
3123 		if (method->klass->rank)
3124 			context_used = mono_class_check_context_used (method->klass);
3125 	} else {
3126 		context_used = mono_generic_context_check_used (method_context);
3127 		context_used |= mono_class_check_context_used (method->klass);
3128 	}
3129 
3130 	return context_used;
3131 }
3132 
3133 static gboolean
generic_inst_equal(MonoGenericInst * inst1,MonoGenericInst * inst2)3134 generic_inst_equal (MonoGenericInst *inst1, MonoGenericInst *inst2)
3135 {
3136 	int i;
3137 
3138 	if (!inst1) {
3139 		g_assert (!inst2);
3140 		return TRUE;
3141 	}
3142 
3143 	g_assert (inst2);
3144 
3145 	if (inst1->type_argc != inst2->type_argc)
3146 		return FALSE;
3147 
3148 	for (i = 0; i < inst1->type_argc; ++i)
3149 		if (!mono_metadata_type_equal (inst1->type_argv [i], inst2->type_argv [i]))
3150 			return FALSE;
3151 
3152 	return TRUE;
3153 }
3154 
3155 /*
3156  * mono_generic_context_equal_deep:
3157  * @context1: a generic context
3158  * @context2: a generic context
3159  *
3160  * Returns whether context1's type arguments are equal to context2's
3161  * type arguments.
3162  */
3163 gboolean
mono_generic_context_equal_deep(MonoGenericContext * context1,MonoGenericContext * context2)3164 mono_generic_context_equal_deep (MonoGenericContext *context1, MonoGenericContext *context2)
3165 {
3166 	return generic_inst_equal (context1->class_inst, context2->class_inst) &&
3167 		generic_inst_equal (context1->method_inst, context2->method_inst);
3168 }
3169 
3170 /*
3171  * mini_class_get_container_class:
3172  * @class: a generic class
3173  *
3174  * Returns the class's container class, which is the class itself if
3175  * it doesn't have generic_class set.
3176  */
3177 MonoClass*
mini_class_get_container_class(MonoClass * klass)3178 mini_class_get_container_class (MonoClass *klass)
3179 {
3180 	if (mono_class_is_ginst (klass))
3181 		return mono_class_get_generic_class (klass)->container_class;
3182 
3183 	g_assert (mono_class_is_gtd (klass));
3184 	return klass;
3185 }
3186 
3187 /*
3188  * mini_class_get_context:
3189  * @class: a generic class
3190  *
3191  * Returns the class's generic context.
3192  */
3193 MonoGenericContext*
mini_class_get_context(MonoClass * klass)3194 mini_class_get_context (MonoClass *klass)
3195 {
3196 	if (mono_class_is_ginst (klass))
3197 		return &mono_class_get_generic_class (klass)->context;
3198 
3199 	g_assert (mono_class_is_gtd (klass));
3200 	return &mono_class_get_generic_container (klass)->context;
3201 }
3202 
3203 /*
3204  * mini_get_basic_type_from_generic:
3205  * @type: a type
3206  *
3207  * Returns a closed type corresponding to the possibly open type
3208  * passed to it.
3209  */
3210 static MonoType*
mini_get_basic_type_from_generic(MonoType * type)3211 mini_get_basic_type_from_generic (MonoType *type)
3212 {
3213 	if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && mini_is_gsharedvt_type (type))
3214 		return type;
3215 	else if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)) {
3216 		MonoType *constraint = type->data.generic_param->gshared_constraint;
3217 		/* The gparam constraint encodes the type this gparam can represent */
3218 		if (!constraint) {
3219 			return &mono_defaults.object_class->byval_arg;
3220 		} else {
3221 			MonoClass *klass;
3222 
3223 			g_assert (constraint != &mono_defaults.int_class->parent->byval_arg);
3224 			klass = mono_class_from_mono_type (constraint);
3225 			return &klass->byval_arg;
3226 		}
3227 	} else {
3228 		return mini_native_type_replace_type (mono_type_get_basic_type_from_generic (type));
3229 	}
3230 }
3231 
3232 /*
3233  * mini_type_get_underlying_type:
3234  *
3235  *   Return the underlying type of TYPE, taking into account enums, byref, bool, char, ref types and generic
3236  * sharing.
3237  */
3238 MonoType*
mini_type_get_underlying_type(MonoType * type)3239 mini_type_get_underlying_type (MonoType *type)
3240 {
3241 	type = mini_native_type_replace_type (type);
3242 
3243 	if (type->byref)
3244 		return &mono_defaults.int_class->byval_arg;
3245 	if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && mini_is_gsharedvt_type (type))
3246 		return type;
3247 	type = mini_get_basic_type_from_generic (mono_type_get_underlying_type (type));
3248 	switch (type->type) {
3249 	case MONO_TYPE_BOOLEAN:
3250 		return &mono_defaults.byte_class->byval_arg;
3251 	case MONO_TYPE_CHAR:
3252 		return &mono_defaults.uint16_class->byval_arg;
3253 	case MONO_TYPE_STRING:
3254 	case MONO_TYPE_CLASS:
3255 	case MONO_TYPE_ARRAY:
3256 	case MONO_TYPE_SZARRAY:
3257 		return &mono_defaults.object_class->byval_arg;
3258 	default:
3259 		return type;
3260 	}
3261 }
3262 
3263 /*
3264  * mini_type_stack_size:
3265  * @t: a type
3266  * @align: Pointer to an int for returning the alignment
3267  *
3268  * Returns the type's stack size and the alignment in *align.
3269  */
3270 int
mini_type_stack_size(MonoType * t,int * align)3271 mini_type_stack_size (MonoType *t, int *align)
3272 {
3273 	return mono_type_stack_size_internal (t, align, TRUE);
3274 }
3275 
3276 /*
3277  * mini_type_stack_size_full:
3278  *
3279  *   Same as mini_type_stack_size, but handle pinvoke data types as well.
3280  */
3281 int
mini_type_stack_size_full(MonoType * t,guint32 * align,gboolean pinvoke)3282 mini_type_stack_size_full (MonoType *t, guint32 *align, gboolean pinvoke)
3283 {
3284 	int size;
3285 
3286 	//g_assert (!mini_is_gsharedvt_type (t));
3287 
3288 	if (pinvoke) {
3289 		size = mono_type_native_stack_size (t, align);
3290 	} else {
3291 		int ialign;
3292 
3293 		if (align) {
3294 			size = mini_type_stack_size (t, &ialign);
3295 			*align = ialign;
3296 		} else {
3297 			size = mini_type_stack_size (t, NULL);
3298 		}
3299 	}
3300 
3301 	return size;
3302 }
3303 
3304 /*
3305  * mono_generic_sharing_init:
3306  *
3307  * Initialize the module.
3308  */
3309 void
mono_generic_sharing_init(void)3310 mono_generic_sharing_init (void)
3311 {
3312 	mono_counters_register ("RGCTX template num allocated", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_template_num_allocated);
3313 	mono_counters_register ("RGCTX template bytes allocated", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_template_bytes_allocated);
3314 	mono_counters_register ("RGCTX oti num allocated", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_oti_num_allocated);
3315 	mono_counters_register ("RGCTX oti bytes allocated", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_oti_bytes_allocated);
3316 	mono_counters_register ("RGCTX oti num markers", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_oti_num_markers);
3317 	mono_counters_register ("RGCTX oti num data", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_oti_num_data);
3318 	mono_counters_register ("RGCTX max slot number", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_max_slot_number);
3319 	mono_counters_register ("RGCTX num allocated", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_num_allocated);
3320 	mono_counters_register ("RGCTX num arrays allocated", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_num_arrays_allocated);
3321 	mono_counters_register ("RGCTX bytes allocated", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_bytes_allocated);
3322 	mono_counters_register ("MRGCTX num arrays allocated", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_num_arrays_allocated);
3323 	mono_counters_register ("MRGCTX bytes allocated", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_bytes_allocated);
3324 	mono_counters_register ("GSHAREDVT num trampolines", MONO_COUNTER_JIT | MONO_COUNTER_INT, &gsharedvt_num_trampolines);
3325 
3326 	mono_install_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
3327 
3328 	mono_os_mutex_init_recursive (&gshared_mutex);
3329 }
3330 
3331 void
mono_generic_sharing_cleanup(void)3332 mono_generic_sharing_cleanup (void)
3333 {
3334 	mono_remove_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
3335 
3336 	if (generic_subclass_hash)
3337 		g_hash_table_destroy (generic_subclass_hash);
3338 }
3339 
3340 /*
3341  * mini_type_var_is_vt:
3342  *
3343  *   Return whenever T is a type variable instantiated with a vtype.
3344  */
3345 gboolean
mini_type_var_is_vt(MonoType * type)3346 mini_type_var_is_vt (MonoType *type)
3347 {
3348 	if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) {
3349 		return type->data.generic_param->gshared_constraint && (type->data.generic_param->gshared_constraint->type == MONO_TYPE_VALUETYPE || type->data.generic_param->gshared_constraint->type == MONO_TYPE_GENERICINST);
3350 	} else {
3351 		g_assert_not_reached ();
3352 		return FALSE;
3353 	}
3354 }
3355 
3356 gboolean
mini_type_is_reference(MonoType * type)3357 mini_type_is_reference (MonoType *type)
3358 {
3359 	type = mini_type_get_underlying_type (type);
3360 	return mono_type_is_reference (type);
3361 }
3362 
3363 /*
3364  * mini_method_get_rgctx:
3365  *
3366  *  Return the RGCTX which needs to be passed to M when it is called.
3367  */
3368 gpointer
mini_method_get_rgctx(MonoMethod * m)3369 mini_method_get_rgctx (MonoMethod *m)
3370 {
3371 	if (mini_method_get_context (m)->method_inst)
3372 		return mono_method_lookup_rgctx (mono_class_vtable (mono_domain_get (), m->klass), mini_method_get_context (m)->method_inst);
3373 	else
3374 		return mono_class_vtable (mono_domain_get (), m->klass);
3375 }
3376 
3377 /*
3378  * mini_type_is_vtype:
3379  *
3380  *   Return whenever T is a vtype, or a type param instantiated with a vtype.
3381  * Should be used in place of MONO_TYPE_ISSTRUCT () which can't handle gsharedvt.
3382  */
3383 gboolean
mini_type_is_vtype(MonoType * t)3384 mini_type_is_vtype (MonoType *t)
3385 {
3386 	t = mini_type_get_underlying_type (t);
3387 
3388 	return MONO_TYPE_ISSTRUCT (t) || mini_is_gsharedvt_variable_type (t);
3389 }
3390 
3391 gboolean
mini_class_is_generic_sharable(MonoClass * klass)3392 mini_class_is_generic_sharable (MonoClass *klass)
3393 {
3394 	if (mono_class_is_ginst (klass) && is_async_state_machine_class (klass))
3395 		return FALSE;
3396 
3397 	return (mono_class_is_ginst (klass) && mono_generic_context_is_sharable (&mono_class_get_generic_class (klass)->context, FALSE));
3398 }
3399 
3400 gboolean
mini_is_gsharedvt_variable_klass(MonoClass * klass)3401 mini_is_gsharedvt_variable_klass (MonoClass *klass)
3402 {
3403 	return mini_is_gsharedvt_variable_type (&klass->byval_arg);
3404 }
3405 
3406 gboolean
mini_is_gsharedvt_gparam(MonoType * t)3407 mini_is_gsharedvt_gparam (MonoType *t)
3408 {
3409 	/* Matches get_gsharedvt_type () */
3410 	return (t->type == MONO_TYPE_VAR || t->type == MONO_TYPE_MVAR) && t->data.generic_param->gshared_constraint && t->data.generic_param->gshared_constraint->type == MONO_TYPE_VALUETYPE;
3411 }
3412 
3413 static char*
get_shared_gparam_name(MonoTypeEnum constraint,const char * name)3414 get_shared_gparam_name (MonoTypeEnum constraint, const char *name)
3415 {
3416 	if (constraint == MONO_TYPE_VALUETYPE) {
3417 		return g_strdup_printf ("%s_GSHAREDVT", name);
3418 	} else if (constraint == MONO_TYPE_OBJECT) {
3419 		return g_strdup_printf ("%s_REF", name);
3420 	} else if (constraint == MONO_TYPE_GENERICINST) {
3421 		return g_strdup_printf ("%s_INST", name);
3422 	} else {
3423 		MonoType t;
3424 		char *tname, *tname2, *res;
3425 
3426 		memset (&t, 0, sizeof (t));
3427 		t.type = constraint;
3428 		tname = mono_type_full_name (&t);
3429 		tname2 = g_utf8_strup (tname, strlen (tname));
3430 		res = g_strdup_printf ("%s_%s", name, tname2);
3431 		g_free (tname);
3432 		g_free (tname2);
3433 		return res;
3434 	}
3435 }
3436 
3437 static guint
shared_gparam_hash(gconstpointer data)3438 shared_gparam_hash (gconstpointer data)
3439 {
3440 	MonoGSharedGenericParam *p = (MonoGSharedGenericParam*)data;
3441 	guint hash;
3442 
3443 	hash = mono_metadata_generic_param_hash (p->parent);
3444 	hash = ((hash << 5) - hash) ^ mono_metadata_type_hash (p->param.param.gshared_constraint);
3445 
3446 	return hash;
3447 }
3448 
3449 static gboolean
shared_gparam_equal(gconstpointer ka,gconstpointer kb)3450 shared_gparam_equal (gconstpointer ka, gconstpointer kb)
3451 {
3452 	MonoGSharedGenericParam *p1 = (MonoGSharedGenericParam*)ka;
3453 	MonoGSharedGenericParam *p2 = (MonoGSharedGenericParam*)kb;
3454 
3455 	if (p1 == p2)
3456 		return TRUE;
3457 	if (p1->parent != p2->parent)
3458 		return FALSE;
3459 	if (!mono_metadata_type_equal (p1->param.param.gshared_constraint, p2->param.param.gshared_constraint))
3460 		return FALSE;
3461 	return TRUE;
3462 }
3463 
3464 /*
3465  * mini_get_shared_gparam:
3466  *
3467  *   Create an anonymous gparam from T with a constraint which encodes which types can match it.
3468  */
3469 MonoType*
mini_get_shared_gparam(MonoType * t,MonoType * constraint)3470 mini_get_shared_gparam (MonoType *t, MonoType *constraint)
3471 {
3472 	MonoGenericParam *par = t->data.generic_param;
3473 	MonoGSharedGenericParam *copy, key;
3474 	MonoType *res;
3475 	MonoImage *image = NULL;
3476 	char *name;
3477 
3478 	memset (&key, 0, sizeof (key));
3479 	key.parent = par;
3480 	key.param.param.gshared_constraint = constraint;
3481 
3482 	g_assert (mono_generic_param_info (par));
3483 	image = get_image_for_generic_param(par);
3484 
3485 	/*
3486 	 * Need a cache to ensure the newly created gparam
3487 	 * is unique wrt T/CONSTRAINT.
3488 	 */
3489 	mono_image_lock (image);
3490 	if (!image->gshared_types) {
3491 		image->gshared_types_len = MONO_TYPE_INTERNAL;
3492 		image->gshared_types = g_new0 (GHashTable*, image->gshared_types_len);
3493 	}
3494 	if (!image->gshared_types [constraint->type])
3495 		image->gshared_types [constraint->type] = g_hash_table_new (shared_gparam_hash, shared_gparam_equal);
3496 	res = (MonoType *)g_hash_table_lookup (image->gshared_types [constraint->type], &key);
3497 	mono_image_unlock (image);
3498 	if (res)
3499 		return res;
3500 	copy = (MonoGSharedGenericParam *)mono_image_alloc0 (image, sizeof (MonoGSharedGenericParam));
3501 	memcpy (&copy->param, par, sizeof (MonoGenericParamFull));
3502 	copy->param.info.pklass = NULL;
3503 	constraint = mono_metadata_type_dup (image, constraint);
3504 	name = get_shared_gparam_name (constraint->type, ((MonoGenericParamFull*)copy)->info.name);
3505 	copy->param.info.name = mono_image_strdup (image, name);
3506 	g_free (name);
3507 
3508 	copy->param.param.owner = par->owner;
3509 
3510 	copy->param.param.gshared_constraint = constraint;
3511 	copy->parent = par;
3512 	res = mono_metadata_type_dup (NULL, t);
3513 	res->data.generic_param = (MonoGenericParam*)copy;
3514 
3515 	if (image) {
3516 		mono_image_lock (image);
3517 		/* Duplicates are ok */
3518 		g_hash_table_insert (image->gshared_types [constraint->type], copy, res);
3519 		mono_image_unlock (image);
3520 	}
3521 
3522 	return res;
3523 }
3524 
3525 static MonoGenericInst*
3526 get_shared_inst (MonoGenericInst *inst, MonoGenericInst *shared_inst, MonoGenericContainer *container, gboolean all_vt, gboolean gsharedvt, gboolean partial);
3527 
3528 static MonoType*
get_shared_type(MonoType * t,MonoType * type)3529 get_shared_type (MonoType *t, MonoType *type)
3530 {
3531 	MonoTypeEnum ttype;
3532 
3533 	if (!type->byref && type->type == MONO_TYPE_GENERICINST && MONO_TYPE_ISSTRUCT (type)) {
3534 		MonoError error;
3535 		MonoGenericClass *gclass = type->data.generic_class;
3536 		MonoGenericContext context;
3537 		MonoClass *k;
3538 
3539 		memset (&context, 0, sizeof (context));
3540 		if (gclass->context.class_inst)
3541 			context.class_inst = get_shared_inst (gclass->context.class_inst, mono_class_get_generic_container (gclass->container_class)->context.class_inst, NULL, FALSE, FALSE, TRUE);
3542 		if (gclass->context.method_inst)
3543 			context.method_inst = get_shared_inst (gclass->context.method_inst, mono_class_get_generic_container (gclass->container_class)->context.method_inst, NULL, FALSE, FALSE, TRUE);
3544 
3545 		k = mono_class_inflate_generic_class_checked (gclass->container_class, &context, &error);
3546 		mono_error_assert_ok (&error); /* FIXME don't swallow the error */
3547 
3548 		return mini_get_shared_gparam (t, &k->byval_arg);
3549 	} else if (MONO_TYPE_ISSTRUCT (type)) {
3550 		return type;
3551 	}
3552 
3553 	/* Create a type variable with a constraint which encodes which types can match it */
3554 	ttype = type->type;
3555 	if (type->type == MONO_TYPE_VALUETYPE) {
3556 		ttype = mono_class_enum_basetype (type->data.klass)->type;
3557 	} else if (MONO_TYPE_IS_REFERENCE (type)) {
3558 		ttype = MONO_TYPE_OBJECT;
3559 	} else if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) {
3560 		if (type->data.generic_param->gshared_constraint)
3561 			return mini_get_shared_gparam (t, type->data.generic_param->gshared_constraint);
3562 		ttype = MONO_TYPE_OBJECT;
3563 	}
3564 
3565 	{
3566 		MonoType t2;
3567 		MonoClass *klass;
3568 
3569 		memset (&t2, 0, sizeof (t2));
3570 		t2.type = ttype;
3571 		klass = mono_class_from_mono_type (&t2);
3572 
3573 		return mini_get_shared_gparam (t, &klass->byval_arg);
3574 	}
3575 }
3576 
3577 static MonoType*
get_gsharedvt_type(MonoType * t)3578 get_gsharedvt_type (MonoType *t)
3579 {
3580 	/* Use TypeHandle as the constraint type since its a valuetype */
3581 	return mini_get_shared_gparam (t, &mono_defaults.typehandle_class->byval_arg);
3582 }
3583 
3584 static MonoGenericInst*
get_shared_inst(MonoGenericInst * inst,MonoGenericInst * shared_inst,MonoGenericContainer * container,gboolean all_vt,gboolean gsharedvt,gboolean partial)3585 get_shared_inst (MonoGenericInst *inst, MonoGenericInst *shared_inst, MonoGenericContainer *container, gboolean all_vt, gboolean gsharedvt, gboolean partial)
3586 {
3587 	MonoGenericInst *res;
3588 	MonoType **type_argv;
3589 	int i;
3590 
3591 	type_argv = g_new0 (MonoType*, inst->type_argc);
3592 	for (i = 0; i < inst->type_argc; ++i) {
3593 		if (all_vt || gsharedvt) {
3594 			type_argv [i] = get_gsharedvt_type (shared_inst->type_argv [i]);
3595 		} else {
3596 			/* These types match the ones in mini_generic_inst_is_sharable () */
3597 			type_argv [i] = get_shared_type (shared_inst->type_argv [i], inst->type_argv [i]);
3598 		}
3599 	}
3600 
3601 	res = mono_metadata_get_generic_inst (inst->type_argc, type_argv);
3602 	g_free (type_argv);
3603 	return res;
3604 }
3605 
3606 /*
3607  * mini_get_shared_method_full:
3608  *
3609  *   Return the method which is actually compiled/registered when doing generic sharing.
3610  * If ALL_VT is true, return the shared method belonging to an all-vtype instantiation.
3611  * If IS_GSHAREDVT is true, treat METHOD as a gsharedvt method even if it fails some constraints.
3612  * METHOD can be a non-inflated generic method.
3613  */
3614 MonoMethod*
mini_get_shared_method_full(MonoMethod * method,gboolean all_vt,gboolean is_gsharedvt)3615 mini_get_shared_method_full (MonoMethod *method, gboolean all_vt, gboolean is_gsharedvt)
3616 {
3617 	MonoError error;
3618 	MonoGenericContext shared_context;
3619 	MonoMethod *declaring_method, *res;
3620 	gboolean partial = FALSE;
3621 	gboolean gsharedvt = FALSE;
3622 	MonoGenericContainer *class_container, *method_container = NULL;
3623 	MonoGenericContext *context = mono_method_get_context (method);
3624 	MonoGenericInst *inst;
3625 
3626 	/*
3627 	 * Instead of creating a shared version of the wrapper, create a shared version of the original
3628 	 * method and construct a wrapper for it. Otherwise, we could end up with two copies of the
3629 	 * same wrapper, breaking AOT which assumes wrappers are unique.
3630 	 * FIXME: Add other cases.
3631 	 */
3632 	if (method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
3633 		MonoMethod *wrapper = mono_marshal_method_from_wrapper (method);
3634 
3635 		return mono_marshal_get_synchronized_wrapper (mini_get_shared_method_full (wrapper, all_vt, is_gsharedvt));
3636 	}
3637 	if (method->wrapper_type == MONO_WRAPPER_DELEGATE_INVOKE) {
3638 		WrapperInfo *info = mono_marshal_get_wrapper_info (method);
3639 
3640 		if (info->subtype == WRAPPER_SUBTYPE_NONE) {
3641 			MonoMethod *m = mono_marshal_get_delegate_invoke (mini_get_shared_method_full (info->d.delegate_invoke.method, all_vt, is_gsharedvt), NULL);
3642 			return m;
3643 		}
3644 	}
3645 
3646 	if (method->is_generic || (mono_class_is_gtd (method->klass) && !method->is_inflated)) {
3647 		declaring_method = method;
3648 	} else {
3649 		declaring_method = mono_method_get_declaring_generic_method (method);
3650 	}
3651 
3652 	/* shared_context is the context containing type variables. */
3653 	if (declaring_method->is_generic)
3654 		shared_context = mono_method_get_generic_container (declaring_method)->context;
3655 	else
3656 		shared_context = mono_class_get_generic_container (declaring_method->klass)->context;
3657 
3658 	if (!is_gsharedvt)
3659 		partial = mono_method_is_generic_sharable_full (method, FALSE, TRUE, FALSE);
3660 
3661 	gsharedvt = is_gsharedvt || (!partial && mini_is_gsharedvt_sharable_method (method));
3662 
3663 	class_container = mono_class_try_get_generic_container (declaring_method->klass); //FIXME is this a case for a try_get?
3664 	method_container = mono_method_get_generic_container (declaring_method);
3665 
3666 	/*
3667 	 * Create the shared context by replacing the ref type arguments with
3668 	 * type parameters, and keeping the rest.
3669 	 */
3670 	if (context)
3671 		inst = context->class_inst;
3672 	else
3673 		inst = shared_context.class_inst;
3674 	if (inst)
3675 		shared_context.class_inst = get_shared_inst (inst, shared_context.class_inst, class_container, all_vt, gsharedvt, partial);
3676 
3677 	if (context)
3678 		inst = context->method_inst;
3679 	else
3680 		inst = shared_context.method_inst;
3681 	if (inst)
3682 		shared_context.method_inst = get_shared_inst (inst, shared_context.method_inst, method_container, all_vt, gsharedvt, partial);
3683 
3684 	res = mono_class_inflate_generic_method_checked (declaring_method, &shared_context, &error);
3685 	g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
3686 
3687 	//printf ("%s\n", mono_method_full_name (res, 1));
3688 
3689 	return res;
3690 }
3691 
3692 MonoMethod*
mini_get_shared_method(MonoMethod * method)3693 mini_get_shared_method (MonoMethod *method)
3694 {
3695 	return mini_get_shared_method_full (method, FALSE, FALSE);
3696 }
3697 
3698 int
mini_get_rgctx_entry_slot(MonoJumpInfoRgctxEntry * entry)3699 mini_get_rgctx_entry_slot (MonoJumpInfoRgctxEntry *entry)
3700 {
3701 	guint32 slot = -1;
3702 
3703 	switch (entry->data->type) {
3704 	case MONO_PATCH_INFO_CLASS:
3705 		slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, &entry->data->data.klass->byval_arg, entry->info_type, mono_method_get_context (entry->method));
3706 		break;
3707 	case MONO_PATCH_INFO_METHOD:
3708 	case MONO_PATCH_INFO_METHODCONST:
3709 		slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, entry->data->data.method, entry->info_type, mono_method_get_context (entry->method));
3710 		break;
3711 	case MONO_PATCH_INFO_FIELD:
3712 		slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, entry->data->data.field, entry->info_type, mono_method_get_context (entry->method));
3713 		break;
3714 	case MONO_PATCH_INFO_SIGNATURE:
3715 		slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, entry->data->data.sig, entry->info_type, mono_method_get_context (entry->method));
3716 		break;
3717 	case MONO_PATCH_INFO_GSHAREDVT_CALL: {
3718 		MonoJumpInfoGSharedVtCall *call_info = (MonoJumpInfoGSharedVtCall *)g_malloc0 (sizeof (MonoJumpInfoGSharedVtCall)); //mono_domain_alloc0 (domain, sizeof (MonoJumpInfoGSharedVtCall));
3719 
3720 		memcpy (call_info, entry->data->data.gsharedvt, sizeof (MonoJumpInfoGSharedVtCall));
3721 		slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, call_info, entry->info_type, mono_method_get_context (entry->method));
3722 		break;
3723 	}
3724 	case MONO_PATCH_INFO_GSHAREDVT_METHOD: {
3725 		MonoGSharedVtMethodInfo *info;
3726 		MonoGSharedVtMethodInfo *oinfo = entry->data->data.gsharedvt_method;
3727 		int i;
3728 
3729 		/* Make a copy into the domain mempool */
3730 		info = (MonoGSharedVtMethodInfo *)g_malloc0 (sizeof (MonoGSharedVtMethodInfo)); //mono_domain_alloc0 (domain, sizeof (MonoGSharedVtMethodInfo));
3731 		info->method = oinfo->method;
3732 		info->num_entries = oinfo->num_entries;
3733 		info->entries = (MonoRuntimeGenericContextInfoTemplate *)g_malloc0 (sizeof (MonoRuntimeGenericContextInfoTemplate) * info->num_entries);
3734 		for (i = 0; i < oinfo->num_entries; ++i) {
3735 			MonoRuntimeGenericContextInfoTemplate *otemplate = &oinfo->entries [i];
3736 			MonoRuntimeGenericContextInfoTemplate *template_ = &info->entries [i];
3737 
3738 			memcpy (template_, otemplate, sizeof (MonoRuntimeGenericContextInfoTemplate));
3739 		}
3740 		slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, info, entry->info_type, mono_method_get_context (entry->method));
3741 		break;
3742 	}
3743 	case MONO_PATCH_INFO_VIRT_METHOD: {
3744 		MonoJumpInfoVirtMethod *info;
3745 		MonoJumpInfoVirtMethod *oinfo = entry->data->data.virt_method;
3746 
3747 		info = (MonoJumpInfoVirtMethod *)g_malloc0 (sizeof (MonoJumpInfoVirtMethod));
3748 		memcpy (info, oinfo, sizeof (MonoJumpInfoVirtMethod));
3749 		slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, info, entry->info_type, mono_method_get_context (entry->method));
3750 		break;
3751 	}
3752 	default:
3753 		g_assert_not_reached ();
3754 		break;
3755 	}
3756 
3757 	return slot;
3758 }
3759 
3760 static gboolean gsharedvt_supported;
3761 
3762 void
mono_set_generic_sharing_vt_supported(gboolean supported)3763 mono_set_generic_sharing_vt_supported (gboolean supported)
3764 {
3765 	/* ensure we do not disable gsharedvt once it's been enabled */
3766 	if (!gsharedvt_supported  && supported)
3767 		gsharedvt_supported = TRUE;
3768 }
3769 
3770 #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
3771 
3772 /*
3773  * mini_is_gsharedvt_type:
3774  *
3775  *   Return whenever T references type arguments instantiated with gshared vtypes.
3776  */
3777 gboolean
mini_is_gsharedvt_type(MonoType * t)3778 mini_is_gsharedvt_type (MonoType *t)
3779 {
3780 	int i;
3781 
3782 	if (t->byref)
3783 		return FALSE;
3784 	if ((t->type == MONO_TYPE_VAR || t->type == MONO_TYPE_MVAR) && t->data.generic_param->gshared_constraint && t->data.generic_param->gshared_constraint->type == MONO_TYPE_VALUETYPE)
3785 		return TRUE;
3786 	else if (t->type == MONO_TYPE_GENERICINST) {
3787 		MonoGenericClass *gclass = t->data.generic_class;
3788 		MonoGenericContext *context = &gclass->context;
3789 		MonoGenericInst *inst;
3790 
3791 		inst = context->class_inst;
3792 		if (inst) {
3793 			for (i = 0; i < inst->type_argc; ++i)
3794 				if (mini_is_gsharedvt_type (inst->type_argv [i]))
3795 					return TRUE;
3796 		}
3797 		inst = context->method_inst;
3798 		if (inst) {
3799 			for (i = 0; i < inst->type_argc; ++i)
3800 				if (mini_is_gsharedvt_type (inst->type_argv [i]))
3801 					return TRUE;
3802 		}
3803 
3804 		return FALSE;
3805 	} else {
3806 		return FALSE;
3807 	}
3808 }
3809 
3810 gboolean
mini_is_gsharedvt_klass(MonoClass * klass)3811 mini_is_gsharedvt_klass (MonoClass *klass)
3812 {
3813 	return mini_is_gsharedvt_type (&klass->byval_arg);
3814 }
3815 
3816 gboolean
mini_is_gsharedvt_signature(MonoMethodSignature * sig)3817 mini_is_gsharedvt_signature (MonoMethodSignature *sig)
3818 {
3819 	int i;
3820 
3821 	if (sig->ret && mini_is_gsharedvt_type (sig->ret))
3822 		return TRUE;
3823 	for (i = 0; i < sig->param_count; ++i) {
3824 		if (mini_is_gsharedvt_type (sig->params [i]))
3825 			return TRUE;
3826 	}
3827 	return FALSE;
3828 }
3829 
3830 /*
3831  * mini_is_gsharedvt_variable_type:
3832  *
3833  *   Return whenever T refers to a GSHAREDVT type whose size differs depending on the values of type parameters.
3834  */
3835 gboolean
mini_is_gsharedvt_variable_type(MonoType * t)3836 mini_is_gsharedvt_variable_type (MonoType *t)
3837 {
3838 	if (!mini_is_gsharedvt_type (t))
3839 		return FALSE;
3840 	if (t->type == MONO_TYPE_GENERICINST) {
3841 		MonoGenericClass *gclass = t->data.generic_class;
3842 		MonoGenericContext *context = &gclass->context;
3843 		MonoGenericInst *inst;
3844 		int i;
3845 
3846 		if (t->data.generic_class->container_class->byval_arg.type != MONO_TYPE_VALUETYPE || t->data.generic_class->container_class->enumtype)
3847 			return FALSE;
3848 
3849 		inst = context->class_inst;
3850 		if (inst) {
3851 			for (i = 0; i < inst->type_argc; ++i)
3852 				if (mini_is_gsharedvt_variable_type (inst->type_argv [i]))
3853 					return TRUE;
3854 		}
3855 		inst = context->method_inst;
3856 		if (inst) {
3857 			for (i = 0; i < inst->type_argc; ++i)
3858 				if (mini_is_gsharedvt_variable_type (inst->type_argv [i]))
3859 					return TRUE;
3860 		}
3861 
3862 		return FALSE;
3863 	}
3864 	return TRUE;
3865 }
3866 
3867 static gboolean
is_variable_size(MonoType * t)3868 is_variable_size (MonoType *t)
3869 {
3870 	int i;
3871 
3872 	if (t->byref)
3873 		return FALSE;
3874 
3875 	if (t->type == MONO_TYPE_VAR || t->type == MONO_TYPE_MVAR) {
3876 		MonoGenericParam *param = t->data.generic_param;
3877 
3878 		if (param->gshared_constraint && param->gshared_constraint->type != MONO_TYPE_VALUETYPE && param->gshared_constraint->type != MONO_TYPE_GENERICINST)
3879 			return FALSE;
3880 		if (param->gshared_constraint && param->gshared_constraint->type == MONO_TYPE_GENERICINST)
3881 			return is_variable_size (param->gshared_constraint);
3882 		return TRUE;
3883 	}
3884 	if (t->type == MONO_TYPE_GENERICINST && t->data.generic_class->container_class->byval_arg.type == MONO_TYPE_VALUETYPE) {
3885 		MonoGenericClass *gclass = t->data.generic_class;
3886 		MonoGenericContext *context = &gclass->context;
3887 		MonoGenericInst *inst;
3888 
3889 		inst = context->class_inst;
3890 		if (inst) {
3891 			for (i = 0; i < inst->type_argc; ++i)
3892 				if (is_variable_size (inst->type_argv [i]))
3893 					return TRUE;
3894 		}
3895 		inst = context->method_inst;
3896 		if (inst) {
3897 			for (i = 0; i < inst->type_argc; ++i)
3898 				if (is_variable_size (inst->type_argv [i]))
3899 					return TRUE;
3900 		}
3901 	}
3902 
3903 	return FALSE;
3904 }
3905 
3906 gboolean
mini_is_gsharedvt_sharable_inst(MonoGenericInst * inst)3907 mini_is_gsharedvt_sharable_inst (MonoGenericInst *inst)
3908 {
3909 	int i;
3910 	gboolean has_vt = FALSE;
3911 
3912 	for (i = 0; i < inst->type_argc; ++i) {
3913 		MonoType *type = inst->type_argv [i];
3914 
3915 		if ((MONO_TYPE_IS_REFERENCE (type) || type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && !mini_is_gsharedvt_type (type)) {
3916 		} else {
3917 			has_vt = TRUE;
3918 		}
3919 	}
3920 
3921 	return has_vt;
3922 }
3923 
3924 gboolean
mini_is_gsharedvt_sharable_method(MonoMethod * method)3925 mini_is_gsharedvt_sharable_method (MonoMethod *method)
3926 {
3927 	MonoMethodSignature *sig;
3928 
3929 	/*
3930 	 * A method is gsharedvt if:
3931 	 * - it has type parameters instantiated with vtypes
3932 	 */
3933 	if (!gsharedvt_supported)
3934 		return FALSE;
3935 	if (method->is_inflated) {
3936 		MonoMethodInflated *inflated = (MonoMethodInflated*)method;
3937 		MonoGenericContext *context = &inflated->context;
3938 		MonoGenericInst *inst;
3939 
3940 		if (context->class_inst && context->method_inst) {
3941 			/* At least one inst has to be gsharedvt sharable, and the other normal or gsharedvt sharable */
3942 			gboolean vt1 = mini_is_gsharedvt_sharable_inst (context->class_inst);
3943 			gboolean vt2 = mini_is_gsharedvt_sharable_inst (context->method_inst);
3944 
3945 			if ((vt1 && vt2) ||
3946 				(vt1 && mini_generic_inst_is_sharable (context->method_inst, TRUE, FALSE)) ||
3947 				(vt2 && mini_generic_inst_is_sharable (context->class_inst, TRUE, FALSE)))
3948 				;
3949 			else
3950 				return FALSE;
3951 		} else {
3952 			inst = context->class_inst;
3953 			if (inst && !mini_is_gsharedvt_sharable_inst (inst))
3954 				return FALSE;
3955 			inst = context->method_inst;
3956 			if (inst && !mini_is_gsharedvt_sharable_inst (inst))
3957 				return FALSE;
3958 		}
3959 	} else {
3960 		return FALSE;
3961 	}
3962 
3963 	sig = mono_method_signature (mono_method_get_declaring_generic_method (method));
3964 	if (!sig)
3965 		return FALSE;
3966 
3967 	/*
3968 	if (mini_is_gsharedvt_variable_signature (sig))
3969 		return FALSE;
3970 	*/
3971 
3972 	//DEBUG ("GSHAREDVT SHARABLE: %s\n", mono_method_full_name (method, TRUE));
3973 
3974 	return TRUE;
3975 }
3976 
3977 /*
3978  * mini_is_gsharedvt_variable_signature:
3979  *
3980  *   Return whenever the calling convention used to call SIG varies depending on the values of type parameters used by SIG,
3981  * i.e. FALSE for swap(T[] arr, int i, int j), TRUE for T get_t ().
3982  */
3983 gboolean
mini_is_gsharedvt_variable_signature(MonoMethodSignature * sig)3984 mini_is_gsharedvt_variable_signature (MonoMethodSignature *sig)
3985 {
3986 	int i;
3987 
3988 	if (sig->ret && is_variable_size (sig->ret))
3989 		return TRUE;
3990 	for (i = 0; i < sig->param_count; ++i) {
3991 		MonoType *t = sig->params [i];
3992 
3993 		if (is_variable_size (t))
3994 			return TRUE;
3995 	}
3996 	return FALSE;
3997 }
3998 #else
3999 
4000 gboolean
mini_is_gsharedvt_type(MonoType * t)4001 mini_is_gsharedvt_type (MonoType *t)
4002 {
4003 	return FALSE;
4004 }
4005 
4006 gboolean
mini_is_gsharedvt_klass(MonoClass * klass)4007 mini_is_gsharedvt_klass (MonoClass *klass)
4008 {
4009 	return FALSE;
4010 }
4011 
4012 gboolean
mini_is_gsharedvt_signature(MonoMethodSignature * sig)4013 mini_is_gsharedvt_signature (MonoMethodSignature *sig)
4014 {
4015 	return FALSE;
4016 }
4017 
4018 gboolean
mini_is_gsharedvt_variable_type(MonoType * t)4019 mini_is_gsharedvt_variable_type (MonoType *t)
4020 {
4021 	return FALSE;
4022 }
4023 
4024 gboolean
mini_is_gsharedvt_sharable_method(MonoMethod * method)4025 mini_is_gsharedvt_sharable_method (MonoMethod *method)
4026 {
4027 	return FALSE;
4028 }
4029 
4030 gboolean
mini_is_gsharedvt_variable_signature(MonoMethodSignature * sig)4031 mini_is_gsharedvt_variable_signature (MonoMethodSignature *sig)
4032 {
4033 	return FALSE;
4034 }
4035 
4036 #endif /* !MONO_ARCH_GSHAREDVT_SUPPORTED */
4037