#include <mono/utils/mono-error-internals.h>
#include <mono/utils/mono-membar.h>
#include <mono/utils/mono-compiler.h>
+#include <mono/utils/mono-threads-coop.h>
#include "mini.h"
* Either IMPL_METHOD or OUT_AOT_ADDR will be set on return.
*/
gpointer*
-mini_resolve_imt_method (MonoVTable *vt, gpointer *vtable_slot, MonoMethod *imt_method, MonoMethod **impl_method, gpointer *out_aot_addr, gboolean *out_need_rgctx_tramp, MonoMethod **variant_iface)
+mini_resolve_imt_method (MonoVTable *vt, gpointer *vtable_slot, MonoMethod *imt_method, MonoMethod **impl_method, gpointer *out_aot_addr, gboolean *out_need_rgctx_tramp, MonoMethod **variant_iface, MonoError *error)
{
MonoMethod *impl = NULL, *generic_virtual = NULL;
gboolean lookup_aot, variance_used = FALSE, need_rgctx_tramp = FALSE;
g_assert (imt_slot < MONO_IMT_SIZE);
+ mono_error_init (error);
/* This has to be variance aware since imt_method can be from an interface that vt->klass doesn't directly implement */
interface_offset = mono_class_interface_offset_with_variance (vt->klass, imt_method->klass, &variance_used);
if (interface_offset < 0)
mono_vtable_build_imt_slot (vt, mono_method_get_imt_slot (imt_method));
if (imt_method->is_inflated && ((MonoMethodInflated*)imt_method)->context.method_inst) {
- MonoError error;
MonoGenericContext context = { NULL, NULL };
/*
if (impl->klass->generic_class)
context.class_inst = impl->klass->generic_class->context.class_inst;
context.method_inst = ((MonoMethodInflated*)imt_method)->context.method_inst;
- impl = mono_class_inflate_generic_method_checked (impl, &context, &error);
- g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
+ impl = mono_class_inflate_generic_method_checked (impl, &context, error);
+ mono_error_assert_ok (error);
} else {
+
/* Avoid loading metadata or creating a generic vtable if possible */
- if (lookup_aot && !vt->klass->valuetype)
- aot_addr = (guint8 *)mono_aot_get_method_from_vt_slot (mono_domain_get (), vt, interface_offset + mono_method_get_vtable_slot (imt_method));
- else
+ if (lookup_aot && !vt->klass->valuetype) {
+ aot_addr = (guint8 *)mono_aot_get_method_from_vt_slot (mono_domain_get (), vt, interface_offset + mono_method_get_vtable_slot (imt_method), error);
+ return_val_if_nok (error, NULL);
+ } else {
aot_addr = NULL;
+ }
if (aot_addr)
impl = NULL;
else
}
/**
- * common_call_trampoline_inner:
+ * common_call_trampoline:
*
* The code to handle normal, virtual, and interface method calls and jumps, both
* from JITted and LLVM compiled code.
*/
static gpointer
-common_call_trampoline_inner (mgreg_t *regs, guint8 *code, MonoMethod *m, MonoVTable *vt, gpointer *vtable_slot, MonoError *error)
+common_call_trampoline (mgreg_t *regs, guint8 *code, MonoMethod *m, MonoVTable *vt, gpointer *vtable_slot, MonoError *error)
{
gpointer addr, compiled_method;
gboolean generic_shared = FALSE;
need_rgctx_tramp = TRUE;
}
- vtable_slot = mini_resolve_imt_method (vt, vtable_slot, imt_method, &impl_method, &addr, &need_rgctx_tramp, &variant_iface);
+ vtable_slot = mini_resolve_imt_method (vt, vtable_slot, imt_method, &impl_method, &addr, &need_rgctx_tramp, &variant_iface, error);
+ return_val_if_nok (error, NULL);
+
/* This is the vcall slot which gets called through the IMT thunk */
vtable_slot_to_patch = vtable_slot;
* return TRUE for methods used in IMT calls too.
*/
if (virtual_ && is_generic_method_definition (m)) {
- MonoError error;
MonoGenericContext context = { NULL, NULL };
MonoMethod *declaring;
g_assert (generic_virtual->is_inflated);
context.method_inst = ((MonoMethodInflated*)generic_virtual)->context.method_inst;
- m = mono_class_inflate_generic_method_checked (declaring, &context, &error);
- g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
+ m = mono_class_inflate_generic_method_checked (declaring, &context, error);
+ mono_error_assert_ok (error);
/* FIXME: only do this if the method is sharable */
need_rgctx_tramp = TRUE;
} else if ((context_used = mono_method_check_context_used (m))) {
}
if (method_inst || m->wrapper_type) {
- MonoError error;
MonoGenericContext context = { NULL, NULL };
if (m->is_inflated)
context.class_inst = klass->generic_container->context.class_inst;
context.method_inst = method_inst;
- actual_method = mono_class_inflate_generic_method_checked (declaring, &context, &error);
- g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
+ actual_method = mono_class_inflate_generic_method_checked (declaring, &context, error);
+ mono_error_assert_ok (error);
} else {
actual_method = mono_class_get_method_generic (klass, m);
}
*/
no_patch = TRUE;
}
-
+#if LLVM_API_VERSION > 100
+ /* LLVM code doesn't make direct calls */
+ if (ji && ji->from_llvm)
+ no_patch = TRUE;
+#endif
if (!no_patch && mono_method_same_domain (ji, target_ji))
mono_arch_patch_callsite ((guint8 *)ji->code_start, code, (guint8 *)addr);
}
return addr;
}
-static gpointer
-common_call_trampoline (mgreg_t *regs, guint8 *code, MonoMethod *m, MonoVTable *vt, gpointer *vtable_slot, MonoError *error)
-{
- gpointer res;
- MONO_PREPARE_RESET_BLOCKING;
- res = common_call_trampoline_inner (regs, code, m, vt, vtable_slot, error);
- MONO_FINISH_RESET_BLOCKING;
- return res;
-}
-
/**
* mono_magic_trampoline:
*
gpointer
mono_magic_trampoline (mgreg_t *regs, guint8 *code, gpointer arg, guint8* tramp)
{
- MonoError error;
gpointer res;
+ MONO_ENTER_GC_UNSAFE_UNBALANCED;
+
+ MonoError error;
+
trampoline_calls ++;
res = common_call_trampoline (regs, code, (MonoMethod *)arg, NULL, NULL, &error);
- if (!mono_error_ok (&error)) {
- mono_error_set_pending_exception (&error);
- return NULL;
- }
+ mono_error_set_pending_exception (&error);
+
+ mono_interruption_checkpoint_from_trampoline ();
+
+ MONO_EXIT_GC_UNSAFE_UNBALANCED;
+
return res;
}
static gpointer
mono_vcall_trampoline (mgreg_t *regs, guint8 *code, int slot, guint8 *tramp)
{
+ MONO_REQ_GC_UNSAFE_MODE;
+
MonoObject *this_arg;
MonoVTable *vt;
gpointer *vtable_slot;
vtable_slot = &(vt->vtable [slot]);
/* Avoid loading metadata or creating a generic vtable if possible */
- addr = mono_aot_get_method_from_vt_slot (mono_domain_get (), vt, slot);
+ addr = mono_aot_get_method_from_vt_slot (mono_domain_get (), vt, slot, &error);
+ if (!is_ok (&error))
+ goto leave;
if (addr && !vt->klass->valuetype) {
if (mono_domain_owns_vtable_slot (mono_domain_get (), vtable_slot))
*vtable_slot = addr;
}
res = common_call_trampoline (regs, code, m, vt, vtable_slot, &error);
+leave:
if (!mono_error_ok (&error)) {
mono_error_set_pending_exception (&error);
return NULL;
gpointer
mono_generic_virtual_remoting_trampoline (mgreg_t *regs, guint8 *code, MonoMethod *m, guint8 *tramp)
{
+ MONO_REQ_GC_UNSAFE_MODE;
+
MonoError error;
MonoGenericContext context = { NULL, NULL };
MonoMethod *imt_method, *declaring;
mono_aot_trampoline (mgreg_t *regs, guint8 *code, guint8 *token_info,
guint8* tramp)
{
+ MONO_REQ_GC_UNSAFE_MODE;
+
MonoImage *image;
guint32 token;
MonoMethod *method = NULL;
gpointer addr;
guint8 *plt_entry;
+ MonoError error;
trampoline_calls ++;
token_info += sizeof (gpointer);
token = *(guint32*)(gpointer)token_info;
- addr = mono_aot_get_method_from_token (mono_domain_get (), image, token);
+ addr = mono_aot_get_method_from_token (mono_domain_get (), image, token, &error);
+ if (!is_ok (&error))
+ mono_error_cleanup (&error);
if (!addr) {
- MonoError error;
method = mono_get_method_checked (image, token, NULL, NULL, &error);
if (!method)
g_error ("Could not load AOT trampoline due to %s", mono_error_get_message (&error));
mono_aot_plt_trampoline (mgreg_t *regs, guint8 *code, guint8 *aot_module,
guint8* tramp)
{
+ MONO_REQ_GC_UNSAFE_MODE;
+
guint32 plt_info_offset = mono_aot_get_plt_info_offset (regs, code);
gpointer res;
MonoError error;
static gpointer
mono_rgctx_lazy_fetch_trampoline (mgreg_t *regs, guint8 *code, gpointer data, guint8 *tramp)
{
+ MONO_REQ_GC_UNSAFE_MODE;
+
static gboolean inited = FALSE;
static int num_lookups = 0;
guint32 slot = GPOINTER_TO_UINT (data);
gpointer
mono_delegate_trampoline (mgreg_t *regs, guint8 *code, gpointer *arg, guint8* tramp)
{
+ MONO_REQ_GC_UNSAFE_MODE;
+
MonoDomain *domain = mono_domain_get ();
MonoDelegate *delegate;
MonoJitInfo *ji;
static gpointer
mono_handler_block_guard_trampoline (mgreg_t *regs, guint8 *code, gpointer *tramp_info, guint8* tramp)
{
+ MONO_REQ_GC_UNSAFE_MODE;
+
MonoContext ctx;
MonoException *exc;
MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_native_tls_get_value (mono_jit_tls_id);
mono_create_handler_block_trampoline (void)
{
static gpointer code;
- if (code) {
+
+ if (code)
+ return code;
+
+ if (mono_aot_only) {
+ gpointer tmp = mono_aot_get_trampoline ("handler_block_trampoline");
+ g_assert (tmp);
mono_memory_barrier ();
+ code = tmp;
return code;
}
- g_assert (!mono_aot_only);
-
mono_trampolines_lock ();
-
if (!code) {
MonoTrampInfo *info;
gpointer tmp;
mono_error_init (error);
if (mono_aot_only) {
+ if (mono_llvm_only && method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
+ method = mono_marshal_get_synchronized_wrapper (method);
+
/* Avoid creating trampolines if possible */
gpointer code = mono_jit_find_compiled_method (domain, method);
if (code)
return code;
if (mono_llvm_only) {
- if (method->wrapper_type == MONO_WRAPPER_PROXY_ISINST || method->wrapper_type == MONO_WRAPPER_LDFLD_REMOTE ||
- method->wrapper_type == MONO_WRAPPER_STFLD_REMOTE)
+ if (method->wrapper_type == MONO_WRAPPER_PROXY_ISINST)
/* These wrappers are not generated */
return method_not_found;
/* Methods are lazily initialized on first call, so this can't lead recursion */