3 * llvmonly runtime support code.
8 #include "llvmonly-runtime.h"
9 #include "aot-runtime.h"
12 * mini_llvmonly_load_method:
14 * Return the AOT-ed code METHOD, or an interpreter entry for it.
18 mini_llvmonly_load_method (MonoMethod
*method
, gboolean caller_gsharedvt
, gboolean need_unbox
, gpointer
*out_arg
, MonoError
*error
)
20 gpointer addr
= mono_compile_method_checked (method
, error
);
21 return_val_if_nok (error
, NULL
);
24 return mini_llvmonly_add_method_wrappers (method
, (gpointer
)addr
, caller_gsharedvt
, need_unbox
, out_arg
);
26 MonoFtnDesc
*desc
= mini_get_interp_callbacks ()->create_method_pointer_llvmonly (method
, need_unbox
, error
);
27 return_val_if_nok (error
, NULL
);
34 * Same but returns an ftndesc which might be newly allocated.
37 mini_llvmonly_load_method_ftndesc (MonoMethod
*method
, gboolean caller_gsharedvt
, gboolean need_unbox
, MonoError
*error
)
39 gpointer addr
= mono_compile_method_checked (method
, error
);
40 return_val_if_nok (error
, NULL
);
44 addr
= mini_llvmonly_add_method_wrappers (method
, (gpointer
)addr
, caller_gsharedvt
, need_unbox
, &arg
);
46 return mini_llvmonly_create_ftndesc (mono_domain_get (), addr
, arg
);
48 MonoFtnDesc
*ftndesc
= mini_get_interp_callbacks ()->create_method_pointer_llvmonly (method
, need_unbox
, error
);
49 return_val_if_nok (error
, NULL
);
55 * Same as load_method, but for delegates.
56 * See mini_llvmonly_get_delegate_arg ().
59 mini_llvmonly_load_method_delegate (MonoMethod
*method
, gboolean caller_gsharedvt
, gboolean need_unbox
, gpointer
*out_arg
, MonoError
*error
)
61 gpointer addr
= mono_compile_method_checked (method
, error
);
62 return_val_if_nok (error
, NULL
);
66 addr
= mono_aot_get_unbox_trampoline (method
, NULL
);
67 *out_arg
= mini_llvmonly_get_delegate_arg (method
, addr
);
70 MonoFtnDesc
*desc
= mini_get_interp_callbacks ()->create_method_pointer_llvmonly (method
, need_unbox
, error
);
71 return_val_if_nok (error
, NULL
);
73 g_assert (!caller_gsharedvt
);
80 mini_llvmonly_get_delegate_arg (MonoMethod
*method
, gpointer method_ptr
)
84 if (mono_method_needs_static_rgctx_invoke (method
, FALSE
))
85 arg
= mini_method_get_rgctx (method
);
88 * Avoid adding gsharedvt in wrappers since they might not exist if
89 * this delegate is called through a gsharedvt delegate invoke wrapper.
90 * Instead, encode that the method is gsharedvt in del->extra_arg,
91 * the CEE_MONO_CALLI_EXTRA_ARG implementation in the JIT depends on this.
93 g_assert ((((gsize
)arg
) & 1) == 0);
94 if (method
->is_inflated
&& (mono_aot_get_method_flags ((guint8
*)method_ptr
) & MONO_AOT_METHOD_FLAG_GSHAREDVT_VARIABLE
)) {
95 arg
= (gpointer
)(((gsize
)arg
) | 1);
102 * mini_llvmonly_create_ftndesc:
104 * Create a function descriptor of the form <addr, arg>, which
105 * represents a callee ADDR with ARG as the last argument.
107 * - generic sharing (ARG is the rgctx)
108 * - gsharedvt signature wrappers (ARG is a function descriptor)
111 mini_llvmonly_create_ftndesc (MonoDomain
*domain
, gpointer addr
, gpointer arg
)
113 MonoFtnDesc
*ftndesc
= (MonoFtnDesc
*)mono_domain_alloc0 (mono_domain_get (), 2 * sizeof (gpointer
));
114 ftndesc
->addr
= addr
;
121 * mini_llvmonly_add_method_wrappers:
123 * Add unbox/gsharedvt wrappers around COMPILED_METHOD if needed. Return the wrapper address or COMPILED_METHOD
124 * if no wrapper is needed. Set OUT_ARG to the rgctx/extra argument needed to be passed to the returned method.
127 mini_llvmonly_add_method_wrappers (MonoMethod
*m
, gpointer compiled_method
, gboolean caller_gsharedvt
, gboolean add_unbox_tramp
, gpointer
*out_arg
)
130 gboolean callee_gsharedvt
;
134 if (m
->wrapper_type
== MONO_WRAPPER_MANAGED_TO_MANAGED
) {
135 WrapperInfo
*info
= mono_marshal_get_wrapper_info (m
);
138 * generic array helpers.
139 * Have to replace the wrappers with the original generic instances.
141 if (info
&& info
->subtype
== WRAPPER_SUBTYPE_GENERIC_ARRAY_HELPER
) {
142 m
= info
->d
.generic_array_helper
.method
;
144 } else if (m
->wrapper_type
== MONO_WRAPPER_OTHER
) {
145 WrapperInfo
*info
= mono_marshal_get_wrapper_info (m
);
147 /* Same for synchronized inner wrappers */
148 if (info
&& info
->subtype
== WRAPPER_SUBTYPE_SYNCHRONIZED_INNER
) {
149 m
= info
->d
.synchronized_inner
.method
;
153 addr
= compiled_method
;
155 if (add_unbox_tramp
) {
157 * The unbox trampolines call the method directly, so need to add
158 * an rgctx tramp before them.
160 addr
= mono_aot_get_unbox_trampoline (m
, addr
);
163 g_assert (mono_llvm_only
);
166 callee_gsharedvt
= mono_aot_get_method_flags ((guint8
*)compiled_method
) & MONO_AOT_METHOD_FLAG_GSHAREDVT_VARIABLE
;
168 if (!caller_gsharedvt
&& callee_gsharedvt
) {
169 MonoMethodSignature
*sig
, *gsig
;
172 gpointer wrapper_addr
;
174 ji
= mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (compiled_method
), NULL
);
176 jmethod
= jinfo_get_method (ji
);
178 /* Here m is a generic instance, while ji->method is the gsharedvt method implementing it */
180 /* Call from normal/gshared code to gsharedvt code with variable signature */
181 sig
= mono_method_signature_internal (m
);
182 gsig
= mono_method_signature_internal (jmethod
);
184 wrapper_addr
= mini_get_gsharedvt_wrapper (TRUE
, addr
, sig
, gsig
, -1, FALSE
);
187 * This is a gsharedvt in wrapper, it gets passed a ftndesc for the gsharedvt method as an argument.
189 *out_arg
= mini_llvmonly_create_ftndesc (mono_domain_get (), addr
, mini_method_get_rgctx (m
));
191 //printf ("IN: %s\n", mono_method_full_name (m, TRUE));
194 if (!(*out_arg
) && mono_method_needs_static_rgctx_invoke (m
, FALSE
))
195 *out_arg
= mini_method_get_rgctx (m
);
197 if (caller_gsharedvt
&& !callee_gsharedvt
) {
199 * The callee uses the gsharedvt calling convention, have to add an out wrapper.
201 gpointer out_wrapper
= mini_get_gsharedvt_wrapper (FALSE
, NULL
, mono_method_signature_internal (m
), NULL
, -1, FALSE
);
202 MonoFtnDesc
*out_wrapper_arg
= mini_llvmonly_create_ftndesc (mono_domain_get (), addr
, *out_arg
);
205 *out_arg
= out_wrapper_arg
;
217 typedef gpointer (*IMTTrampFunc
) (gpointer
*arg
, MonoMethod
*imt_method
);
220 * mini_llvmonly_initial_imt_tramp:
222 * This function is called the first time a call is made through an IMT trampoline.
223 * It should have the same signature as the llvmonly_imt_tramp_... functions.
226 mini_llvmonly_initial_imt_tramp (gpointer
*arg
, MonoMethod
*imt_method
)
228 IMTTrampInfo
*info
= (IMTTrampInfo
*)arg
;
230 IMTTrampFunc
*ftndesc
;
233 mono_vtable_build_imt_slot (info
->vtable
, info
->slot
);
235 imt
= (IMTTrampFunc
**)info
->vtable
;
236 imt
-= MONO_IMT_SIZE
;
238 /* Return what the real IMT trampoline returns */
239 ftndesc
= imt
[info
->slot
];
242 if (func
== (IMTTrampFunc
)mini_llvmonly_initial_imt_tramp
)
243 /* Happens when the imt slot contains only a generic virtual method */
245 return func ((gpointer
*)ftndesc
[1], imt_method
);
248 /* This is called indirectly through an imt slot. */
250 llvmonly_imt_tramp (gpointer
*arg
, MonoMethod
*imt_method
)
254 /* arg points to an array created in mini_llvmonly_get_imt_trampoline () */
255 while (arg
[i
] && arg
[i
] != imt_method
)
262 /* Optimized versions of mini_llvmonly_imt_trampoline () for different table sizes */
264 llvmonly_imt_tramp_1 (gpointer
*arg
, MonoMethod
*imt_method
)
266 //g_assert (arg [0] == imt_method);
271 llvmonly_imt_tramp_2 (gpointer
*arg
, MonoMethod
*imt_method
)
273 //g_assert (arg [0] == imt_method || arg [2] == imt_method);
274 if (arg
[0] == imt_method
)
281 llvmonly_imt_tramp_3 (gpointer
*arg
, MonoMethod
*imt_method
)
283 //g_assert (arg [0] == imt_method || arg [2] == imt_method || arg [4] == imt_method);
284 if (arg
[0] == imt_method
)
286 else if (arg
[2] == imt_method
)
293 * A version of the imt trampoline used for generic virtual/variant iface methods.
294 * Unlikely a normal imt trampoline, its possible that IMT_METHOD is not found
295 * in the search table. The original JIT code had a 'fallback' trampoline it could
296 * call, but we can't do that, so we just return NULL, and the compiled code
300 llvmonly_fallback_imt_tramp (gpointer
*arg
, MonoMethod
*imt_method
)
304 while (arg
[i
] && arg
[i
] != imt_method
)
313 mini_llvmonly_get_imt_trampoline (MonoVTable
*vtable
, MonoDomain
*domain
, MonoIMTCheckItem
**imt_entries
, int count
, gpointer fail_tramp
)
317 int i
, index
, real_count
;
318 gboolean virtual_generic
= FALSE
;
321 * Create an array which is passed to the imt trampoline functions.
322 * The array contains MonoMethod-function descriptor pairs, terminated by a NULL entry.
326 for (i
= 0; i
< count
; ++i
) {
327 MonoIMTCheckItem
*item
= imt_entries
[i
];
331 if (item
->has_target_code
)
332 virtual_generic
= TRUE
;
336 * Initialize all vtable entries reachable from this imt slot, so the compiled
337 * code doesn't have to check it.
339 for (i
= 0; i
< count
; ++i
) {
340 MonoIMTCheckItem
*item
= imt_entries
[i
];
343 if (!item
->is_equals
|| item
->has_target_code
)
345 vt_slot
= item
->value
.vtable_slot
;
346 mini_llvmonly_init_vtable_slot (vtable
, vt_slot
);
349 /* Save the entries into an array */
350 buf
= (void **)mono_domain_alloc (domain
, (real_count
+ 1) * 2 * sizeof (gpointer
));
352 for (i
= 0; i
< count
; ++i
) {
353 MonoIMTCheckItem
*item
= imt_entries
[i
];
355 if (!item
->is_equals
)
358 g_assert (item
->key
);
359 buf
[(index
* 2)] = item
->key
;
360 if (item
->has_target_code
)
361 buf
[(index
* 2) + 1] = item
->value
.target_code
;
363 buf
[(index
* 2) + 1] = vtable
->vtable
[item
->value
.vtable_slot
];
366 buf
[(index
* 2)] = NULL
;
367 buf
[(index
* 2) + 1] = fail_tramp
;
370 * Return a function descriptor for a C function with 'buf' as its argument.
371 * It will by called by JITted code.
373 res
= (void **)mono_domain_alloc (domain
, 2 * sizeof (gpointer
));
374 switch (real_count
) {
376 res
[0] = (gpointer
)llvmonly_imt_tramp_1
;
379 res
[0] = (gpointer
)llvmonly_imt_tramp_2
;
382 res
[0] = (gpointer
)llvmonly_imt_tramp_3
;
385 res
[0] = (gpointer
)llvmonly_imt_tramp
;
388 if (virtual_generic
|| fail_tramp
)
389 res
[0] = (gpointer
)llvmonly_fallback_imt_tramp
;
396 mini_llvmonly_get_vtable_trampoline (MonoVTable
*vt
, int slot_index
, int index
)
398 if (slot_index
< 0) {
399 /* Initialize the IMT trampoline to a 'trampoline' so the generated code doesn't have to initialize it */
400 // FIXME: Memory management
401 gpointer
*ftndesc
= g_malloc (2 * sizeof (gpointer
));
402 IMTTrampInfo
*info
= g_new0 (IMTTrampInfo
, 1);
405 ftndesc
[0] = (gpointer
)mini_llvmonly_initial_imt_tramp
;
407 mono_memory_barrier ();
415 is_generic_method_definition (MonoMethod
*m
)
417 MonoGenericContext
*context
;
423 context
= mono_method_get_context (m
);
424 if (!context
->method_inst
)
426 if (context
->method_inst
== mono_method_get_generic_container (((MonoMethodInflated
*)m
)->declaring
)->context
.method_inst
)
434 * Return the executable code for calling vt->vtable [slot].
435 * This function is called on a slowpath, so it doesn't need to be fast.
436 * This returns an ftnptr by returning the address part, and the arg in the OUT_ARG
440 resolve_vcall (MonoVTable
*vt
, int slot
, MonoMethod
*imt_method
, gpointer
*out_arg
, gboolean gsharedvt
, MonoError
*error
)
442 MonoMethod
*m
, *generic_virtual
= NULL
;
443 gpointer addr
, compiled_method
;
444 gboolean need_unbox_tramp
= FALSE
;
447 /* Same as in common_call_trampoline () */
449 /* Avoid loading metadata or creating a generic vtable if possible */
450 addr
= mono_aot_get_method_from_vt_slot (mono_domain_get (), vt
, slot
, error
);
451 return_val_if_nok (error
, NULL
);
452 if (addr
&& !m_class_is_valuetype (vt
->klass
))
453 return mono_create_ftnptr (mono_domain_get (), addr
);
455 m
= mono_class_get_vtable_entry (vt
->klass
, slot
);
457 if (is_generic_method_definition (m
)) {
458 MonoGenericContext context
= { NULL
, NULL
};
459 MonoMethod
*declaring
;
462 declaring
= mono_method_get_declaring_generic_method (m
);
466 if (mono_class_is_ginst (m
->klass
))
467 context
.class_inst
= mono_class_get_generic_class (m
->klass
)->context
.class_inst
;
469 g_assert (!mono_class_is_gtd (m
->klass
));
471 generic_virtual
= imt_method
;
472 g_assert (generic_virtual
);
473 g_assert (generic_virtual
->is_inflated
);
474 context
.method_inst
= ((MonoMethodInflated
*)generic_virtual
)->context
.method_inst
;
476 m
= mono_class_inflate_generic_method_checked (declaring
, &context
, error
);
477 mono_error_assert_ok (error
); /* FIXME don't swallow the error */
480 if (generic_virtual
) {
481 if (m_class_is_valuetype (vt
->klass
))
482 need_unbox_tramp
= TRUE
;
484 if (m_class_is_valuetype (m
->klass
))
485 need_unbox_tramp
= TRUE
;
488 if (m
->iflags
& METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED
)
489 m
= mono_marshal_get_synchronized_wrapper (m
);
491 addr
= compiled_method
= mini_llvmonly_load_method (m
, gsharedvt
, need_unbox_tramp
, out_arg
, error
);
492 mono_error_assert_ok (error
);
494 if (!gsharedvt
&& generic_virtual
) {
495 // FIXME: This wastes memory since add_generic_virtual_invocation ignores it in a lot of cases
496 MonoFtnDesc
*ftndesc
= mini_llvmonly_create_ftndesc (mono_domain_get (), addr
, out_arg
);
498 mono_method_add_generic_virtual_invocation (mono_domain_get (),
499 vt
, vt
->vtable
+ slot
,
500 generic_virtual
, ftndesc
);
507 mini_llvmonly_resolve_vcall_gsharedvt (MonoObject
*this_obj
, int slot
, MonoMethod
*imt_method
, gpointer
*out_arg
)
512 gpointer result
= resolve_vcall (this_obj
->vtable
, slot
, imt_method
, out_arg
, TRUE
, error
);
513 if (!is_ok (error
)) {
514 MonoException
*ex
= mono_error_convert_to_exception (error
);
515 mono_llvm_throw_exception ((MonoObject
*)ex
);
521 * mini_llvmonly_resolve_generic_virtual_call:
523 * Resolve a generic virtual call.
524 * This function is called on a slowpath, so it doesn't need to be fast.
527 mini_llvmonly_resolve_generic_virtual_call (MonoVTable
*vt
, int slot
, MonoMethod
*generic_virtual
)
530 gboolean need_unbox_tramp
= FALSE
;
532 MonoGenericContext context
= { NULL
, NULL
};
533 MonoMethod
*declaring
;
535 m
= mono_class_get_vtable_entry (vt
->klass
, slot
);
537 g_assert (is_generic_method_definition (m
));
540 declaring
= mono_method_get_declaring_generic_method (m
);
544 if (mono_class_is_ginst (m
->klass
))
545 context
.class_inst
= mono_class_get_generic_class (m
->klass
)->context
.class_inst
;
547 g_assert (!mono_class_is_gtd (m
->klass
));
549 g_assert (generic_virtual
->is_inflated
);
550 context
.method_inst
= ((MonoMethodInflated
*)generic_virtual
)->context
.method_inst
;
552 m
= mono_class_inflate_generic_method_checked (declaring
, &context
, error
);
553 g_assert (mono_error_ok (error
));
555 if (m_class_is_valuetype (vt
->klass
))
556 need_unbox_tramp
= TRUE
;
559 * This wastes memory but the memory usage is bounded since
560 * mono_method_add_generic_virtual_invocation () eventually builds an imt trampoline for
561 * this vtable slot so we are not called any more for this instantiation.
563 MonoFtnDesc
*ftndesc
= mini_llvmonly_load_method_ftndesc (m
, FALSE
, need_unbox_tramp
, error
);
564 mono_error_assert_ok (error
);
566 mono_method_add_generic_virtual_invocation (mono_domain_get (),
567 vt
, vt
->vtable
+ slot
,
568 generic_virtual
, ftndesc
);
573 * mini_llvmonly_resolve_generic_virtual_iface_call:
575 * Resolve a generic virtual/variant iface call on interfaces.
576 * This function is called on a slowpath, so it doesn't need to be fast.
579 mini_llvmonly_resolve_generic_virtual_iface_call (MonoVTable
*vt
, int imt_slot
, MonoMethod
*generic_virtual
)
582 MonoMethod
*m
, *variant_iface
;
583 MonoFtnDesc
*ftndesc
;
585 gboolean need_unbox_tramp
= FALSE
;
586 gboolean need_rgctx_tramp
;
589 imt
= (gpointer
*)vt
- MONO_IMT_SIZE
;
591 mini_resolve_imt_method (vt
, imt
+ imt_slot
, generic_virtual
, &m
, &aot_addr
, &need_rgctx_tramp
, &variant_iface
, error
);
592 if (!is_ok (error
)) {
593 MonoException
*ex
= mono_error_convert_to_exception (error
);
594 mono_llvm_throw_exception ((MonoObject
*)ex
);
597 if (m_class_is_valuetype (vt
->klass
))
598 need_unbox_tramp
= TRUE
;
600 if (m
->iflags
& METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED
)
601 m
= mono_marshal_get_synchronized_wrapper (m
);
604 * This wastes memory but the memory usage is bounded since
605 * mono_method_add_generic_virtual_invocation () eventually builds an imt trampoline for
606 * this vtable slot so we are not called any more for this instantiation.
608 ftndesc
= mini_llvmonly_load_method_ftndesc (m
, FALSE
, need_unbox_tramp
, error
);
610 mono_method_add_generic_virtual_invocation (mono_domain_get (),
612 variant_iface
? variant_iface
: generic_virtual
, ftndesc
);
617 * mini_llvmonly_init_vtable_slot:
619 * Initialize slot SLOT of VTABLE.
620 * Return the contents of the vtable slot.
623 mini_llvmonly_init_vtable_slot (MonoVTable
*vtable
, int slot
)
630 addr
= resolve_vcall (vtable
, slot
, NULL
, &arg
, FALSE
, error
);
631 if (mono_error_set_pending_exception (error
))
633 ftnptr
= mono_domain_alloc0 (vtable
->domain
, 2 * sizeof (gpointer
));
636 mono_memory_barrier ();
638 vtable
->vtable
[slot
] = ftnptr
;
644 * mini_llvmonly_init_delegate:
646 * Initialize a MonoDelegate object.
647 * Similar to mono_delegate_ctor ().
650 mini_llvmonly_init_delegate (MonoDelegate
*del
)
653 MonoFtnDesc
*ftndesc
= *(MonoFtnDesc
**)del
->method_code
;
656 * We store a MonoFtnDesc in del->method_code.
657 * It would be better to store an ftndesc in del->method_ptr too,
658 * but we don't have a a structure which could own its memory.
660 if (G_UNLIKELY (!ftndesc
)) {
661 MonoMethod
*m
= del
->method
;
662 gboolean need_unbox
= FALSE
;
664 if (m
->iflags
& METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED
)
665 m
= mono_marshal_get_synchronized_wrapper (m
);
667 if (m_class_is_valuetype (m
->klass
) && mono_method_signature_internal (m
)->hasthis
)
671 gpointer addr
= mini_llvmonly_load_method_delegate (m
, FALSE
, need_unbox
, &arg
, error
);
672 if (mono_error_set_pending_exception (error
))
674 ftndesc
= mini_llvmonly_create_ftndesc (mono_domain_get (), addr
, arg
);
675 mono_memory_barrier ();
676 *del
->method_code
= (guint8
*)ftndesc
;
678 del
->method_ptr
= ftndesc
->addr
;
679 del
->extra_arg
= ftndesc
->arg
;
683 mini_llvmonly_init_delegate_virtual (MonoDelegate
*del
, MonoObject
*target
, MonoMethod
*method
)
691 method
= mono_object_get_virtual_method_internal (target
, method
);
693 if (method
->iflags
& METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED
)
694 method
= mono_marshal_get_synchronized_wrapper (method
);
695 need_unbox
= m_class_is_valuetype (method
->klass
);
697 del
->method
= method
;
698 addr
= mini_llvmonly_load_method_delegate (method
, FALSE
, need_unbox
, &arg
, error
);
699 if (mono_error_set_pending_exception (error
))
701 del
->method_ptr
= addr
;
702 del
->extra_arg
= arg
;
706 * resolve_iface_call:
708 * Return the executable code for the iface method IMT_METHOD called on THIS.
709 * This function is called on a slowpath, so it doesn't need to be fast.
710 * This returns an ftnptr by returning the address part, and the arg in the OUT_ARG
714 resolve_iface_call (MonoObject
*this_obj
, int imt_slot
, MonoMethod
*imt_method
, gpointer
*out_arg
, gboolean caller_gsharedvt
, MonoError
*error
)
718 MonoMethod
*impl_method
, *generic_virtual
= NULL
, *variant_iface
= NULL
;
719 gpointer addr
, aot_addr
;
720 gboolean need_rgctx_tramp
= FALSE
, need_unbox_tramp
= FALSE
;
724 /* The caller will handle it */
727 vt
= this_obj
->vtable
;
728 imt
= (gpointer
*)vt
- MONO_IMT_SIZE
;
730 mini_resolve_imt_method (vt
, imt
+ imt_slot
, imt_method
, &impl_method
, &aot_addr
, &need_rgctx_tramp
, &variant_iface
, error
);
731 return_val_if_nok (error
, NULL
);
733 if (imt_method
->is_inflated
&& ((MonoMethodInflated
*)imt_method
)->context
.method_inst
)
734 generic_virtual
= imt_method
;
736 if (generic_virtual
|| variant_iface
) {
737 if (m_class_is_valuetype (vt
->klass
)) /*FIXME is this required variant iface?*/
738 need_unbox_tramp
= TRUE
;
740 if (m_class_is_valuetype (impl_method
->klass
))
741 need_unbox_tramp
= TRUE
;
744 addr
= mini_llvmonly_load_method (impl_method
, caller_gsharedvt
, need_unbox_tramp
, out_arg
, error
);
745 mono_error_assert_ok (error
);
748 if (generic_virtual
|| variant_iface
) {
749 MonoMethod
*target
= generic_virtual
? generic_virtual
: variant_iface
;
751 mono_method_add_generic_virtual_invocation (mono_domain_get (),
760 mini_llvmonly_resolve_iface_call_gsharedvt (MonoObject
*this_obj
, int imt_slot
, MonoMethod
*imt_method
, gpointer
*out_arg
)
763 gpointer res
= resolve_iface_call (this_obj
, imt_slot
, imt_method
, out_arg
, TRUE
, error
);
764 if (!is_ok (error
)) {
765 MonoException
*ex
= mono_error_convert_to_exception (error
);
766 mono_llvm_throw_exception ((MonoObject
*)ex
);
772 init_llvmonly_method (MonoAotModule
*amodule
, guint32 method_index
, MonoClass
*init_class
)
777 res
= mono_aot_init_llvmonly_method (amodule
, method_index
, init_class
, error
);
778 if (!res
|| !is_ok (error
)) {
779 MonoException
*ex
= mono_error_convert_to_exception (error
);
781 /* Its okay to raise in llvmonly mode */
782 if (mono_llvm_only
) {
783 mono_llvm_throw_exception ((MonoObject
*)ex
);
785 mono_set_pending_exception (ex
);
791 /* Called from generated code to initialize a method */
793 mini_llvm_init_method (gpointer aot_module
, guint32 method_index
)
795 MonoAotModule
*amodule
= (MonoAotModule
*)aot_module
;
797 init_llvmonly_method (amodule
, method_index
, NULL
);
800 /* Same for gshared methods with a this pointer */
802 mini_llvm_init_gshared_method_this (gpointer aot_module
, guint32 method_index
, MonoObject
*this_obj
)
804 MonoAotModule
*amodule
= (MonoAotModule
*)aot_module
;
809 klass
= this_obj
->vtable
->klass
;
811 init_llvmonly_method (amodule
, method_index
, klass
);
814 /* Same for gshared methods with an mrgctx arg */
816 mini_llvm_init_gshared_method_mrgctx (gpointer aot_module
, guint32 method_index
, MonoMethodRuntimeGenericContext
*rgctx
)
818 MonoAotModule
*amodule
= (MonoAotModule
*)aot_module
;
820 init_llvmonly_method (amodule
, method_index
, rgctx
->class_vtable
->klass
);
823 /* Same for gshared methods with a vtable arg */
825 mini_llvm_init_gshared_method_vtable (gpointer aot_module
, guint32 method_index
, MonoVTable
*vtable
)
827 MonoAotModule
*amodule
= (MonoAotModule
*)aot_module
;
830 klass
= vtable
->klass
;
832 init_llvmonly_method (amodule
, method_index
, klass
);
835 static GENERATE_GET_CLASS_WITH_CACHE (nullref
, "System", "NullReferenceException")
838 mini_llvmonly_throw_nullref_exception (void)
840 MonoClass
*klass
= mono_class_get_nullref_class ();
842 guint32 ex_token_index
= m_class_get_type_token (klass
) - MONO_TOKEN_TYPE_DEF
;
844 mono_llvm_throw_corlib_exception (ex_token_index
);