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 (©->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