#include <mono/metadata/mono-config.h>
#include <mono/metadata/environment.h>
#include <mono/metadata/mono-debug.h>
-#include <mono/metadata/gc-internal.h>
+#include <mono/metadata/gc-internals.h>
#include <mono/metadata/threads-types.h>
#include <mono/metadata/mempool-internals.h>
#include <mono/metadata/attach.h>
#include <mono/utils/mono-compiler.h>
#include <mono/utils/mono-counters.h>
#include <mono/utils/mono-error-internals.h>
-#include <mono/utils/mono-logger-internal.h>
+#include <mono/utils/mono-logger-internals.h>
#include <mono/utils/mono-mmap.h>
#include <mono/utils/mono-path.h>
#include <mono/utils/mono-tls.h>
#include "jit-icalls.h"
#include "mini-gc.h"
+#include "mini-llvm.h"
#include "debugger-agent.h"
#ifdef MONO_ARCH_LLVM_SUPPORTED
*/
gboolean mono_use_llvm = FALSE;
-#define mono_jit_lock() mono_mutex_lock (&jit_mutex)
-#define mono_jit_unlock() mono_mutex_unlock (&jit_mutex)
+#define mono_jit_lock() mono_os_mutex_lock (&jit_mutex)
+#define mono_jit_unlock() mono_os_mutex_unlock (&jit_mutex)
static mono_mutex_t jit_mutex;
static MonoCodeManager *global_codeman;
if (!domain)
domain = mono_get_root_domain ();
- ji = mono_jit_info_table_find_internal (domain, ip, TRUE, TRUE);
+ ji = mono_jit_info_table_find_internal (domain, (char *)ip, TRUE, TRUE);
if (!ji) {
user_data.ip = ip;
user_data.method = NULL;
MonoGenericSharingContext*gsctx;
const char *shared_type;
- ji = mini_jit_info_table_find_ext (domain, ip, TRUE, &target_domain);
+ ji = mini_jit_info_table_find_ext (domain, (char *)ip, TRUE, &target_domain);
if (ji && ji->is_trampoline) {
- MonoTrampInfo *tinfo = ji->d.tramp_info;
+ MonoTrampInfo *tinfo = (MonoTrampInfo *)ji->d.tramp_info;
printf ("IP %p is at offset 0x%x of trampoline '%s'.\n", ip, (int)((guint8*)ip - tinfo->code), tinfo->name);
return;
MonoJumpInfoToken *
mono_jump_info_token_new2 (MonoMemPool *mp, MonoImage *image, guint32 token, MonoGenericContext *context)
{
- MonoJumpInfoToken *res = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoToken));
+ MonoJumpInfoToken *res = (MonoJumpInfoToken *)mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoToken));
res->image = image;
res->token = token;
res->has_context = context != NULL;
{
MonoJitInfo *ji;
- ji = mono_domain_alloc0 (domain, mono_jit_info_size (0, 0, 0));
- mono_jit_info_init (ji, NULL, info->code, info->code_size, 0, 0, 0);
+ ji = (MonoJitInfo *)mono_domain_alloc0 (domain, mono_jit_info_size ((MonoJitInfoFlags)0, 0, 0));
+ mono_jit_info_init (ji, NULL, info->code, info->code_size, (MonoJitInfoFlags)0, 0, 0);
ji->d.tramp_info = info;
ji->is_trampoline = TRUE;
GSList *l;
for (l = tramp_infos; l; l = l->next) {
- MonoTrampInfo *info = l->data;
+ MonoTrampInfo *info = (MonoTrampInfo *)l->data;
mono_tramp_info_free (info);
}
GSList *l;
for (l = tramp_infos; l; l = l->next) {
- MonoTrampInfo *info = l->data;
+ MonoTrampInfo *info = (MonoTrampInfo *)l->data;
register_trampoline_jit_info (domain, info);
}
MonoJitDynamicMethodInfo *res;
if (domain_jit_info (domain)->dynamic_code_hash)
- res = g_hash_table_lookup (domain_jit_info (domain)->dynamic_code_hash, method);
+ res = (MonoJitDynamicMethodInfo *)g_hash_table_lookup (domain_jit_info (domain)->dynamic_code_hash, method);
else
res = NULL;
return res;
mono_get_lmf (void)
{
#if defined(MONO_HAVE_FAST_TLS) && defined(MONO_ARCH_ENABLE_MONO_LMF_VAR)
- return MONO_FAST_TLS_GET (mono_lmf);
+ return (MonoLMF *)MONO_FAST_TLS_GET (mono_lmf);
#else
MonoJitTlsData *jit_tls;
mono_get_lmf_addr (void)
{
#ifdef MONO_HAVE_FAST_TLS
- return MONO_FAST_TLS_GET (mono_lmf_addr);
+ return (MonoLMF **)MONO_FAST_TLS_GET (mono_lmf_addr);
#else
MonoJitTlsData *jit_tls;
MonoJitTlsData*
mono_get_jit_tls (void)
{
- return mono_native_tls_get_value (mono_jit_tls_id);
+ return (MonoJitTlsData *)mono_native_tls_get_value (mono_jit_tls_id);
}
static void
MonoJitTlsData *jit_tls;
MonoLMF *lmf;
- jit_tls = mono_native_tls_get_value (mono_jit_tls_id);
+ jit_tls = (MonoJitTlsData *)mono_native_tls_get_value (mono_jit_tls_id);
if (jit_tls)
return jit_tls;
jit_tls = g_new0 (MonoJitTlsData, 1);
- jit_tls->abort_func = abort_func;
+ jit_tls->abort_func = (void (*)(MonoObject *))abort_func;
jit_tls->end_of_stack = stack_start;
mono_set_jit_tls (jit_tls);
* The current offender is mono_thread_manage which cleanup threads from the outside.
*/
if (info && mono_thread_info_get_tid (info) == tid) {
- jit_tls = info->jit_data;
+ jit_tls = (MonoJitTlsData *)info->jit_data;
info->jit_data = NULL;
mono_set_jit_tls (NULL);
} else {
info = mono_thread_info_lookup (tid);
if (info) {
- jit_tls = info->jit_data;
+ jit_tls = (MonoJitTlsData *)info->jit_data;
info->jit_data = NULL;
}
mono_hazard_pointer_clear (mono_hazard_pointer_get (), 1);
MonoJumpInfo*
mono_patch_info_dup_mp (MonoMemPool *mp, MonoJumpInfo *patch_info)
{
- MonoJumpInfo *res = mono_mempool_alloc (mp, sizeof (MonoJumpInfo));
+ MonoJumpInfo *res = (MonoJumpInfo *)mono_mempool_alloc (mp, sizeof (MonoJumpInfo));
memcpy (res, patch_info, sizeof (MonoJumpInfo));
switch (patch_info->type) {
case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
case MONO_PATCH_INFO_LDTOKEN:
case MONO_PATCH_INFO_DECLSEC:
- res->data.token = mono_mempool_alloc (mp, sizeof (MonoJumpInfoToken));
+ res->data.token = (MonoJumpInfoToken *)mono_mempool_alloc (mp, sizeof (MonoJumpInfoToken));
memcpy (res->data.token, patch_info->data.token, sizeof (MonoJumpInfoToken));
break;
case MONO_PATCH_INFO_SWITCH:
- res->data.table = mono_mempool_alloc (mp, sizeof (MonoJumpInfoBBTable));
+ res->data.table = (MonoJumpInfoBBTable *)mono_mempool_alloc (mp, sizeof (MonoJumpInfoBBTable));
memcpy (res->data.table, patch_info->data.table, sizeof (MonoJumpInfoBBTable));
- res->data.table->table = mono_mempool_alloc (mp, sizeof (MonoBasicBlock*) * patch_info->data.table->table_size);
+ res->data.table->table = (MonoBasicBlock **)mono_mempool_alloc (mp, sizeof (MonoBasicBlock*) * patch_info->data.table->table_size);
memcpy (res->data.table->table, patch_info->data.table->table, sizeof (MonoBasicBlock*) * patch_info->data.table->table_size);
break;
case MONO_PATCH_INFO_RGCTX_FETCH:
case MONO_PATCH_INFO_RGCTX_SLOT_INDEX:
- res->data.rgctx_entry = mono_mempool_alloc (mp, sizeof (MonoJumpInfoRgctxEntry));
+ res->data.rgctx_entry = (MonoJumpInfoRgctxEntry *)mono_mempool_alloc (mp, sizeof (MonoJumpInfoRgctxEntry));
memcpy (res->data.rgctx_entry, patch_info->data.rgctx_entry, sizeof (MonoJumpInfoRgctxEntry));
res->data.rgctx_entry->data = mono_patch_info_dup_mp (mp, res->data.rgctx_entry->data);
break;
case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE:
- res->data.del_tramp = mono_mempool_alloc0 (mp, sizeof (MonoDelegateClassMethodPair));
+ res->data.del_tramp = (MonoDelegateClassMethodPair *)mono_mempool_alloc0 (mp, sizeof (MonoDelegateClassMethodPair));
memcpy (res->data.del_tramp, patch_info->data.del_tramp, sizeof (MonoDelegateClassMethodPair));
break;
case MONO_PATCH_INFO_GSHAREDVT_CALL:
- res->data.gsharedvt = mono_mempool_alloc (mp, sizeof (MonoJumpInfoGSharedVtCall));
+ res->data.gsharedvt = (MonoJumpInfoGSharedVtCall *)mono_mempool_alloc (mp, sizeof (MonoJumpInfoGSharedVtCall));
memcpy (res->data.gsharedvt, patch_info->data.gsharedvt, sizeof (MonoJumpInfoGSharedVtCall));
break;
case MONO_PATCH_INFO_GSHAREDVT_METHOD: {
int i;
oinfo = patch_info->data.gsharedvt_method;
- info = mono_mempool_alloc (mp, sizeof (MonoGSharedVtMethodInfo));
+ info = (MonoGSharedVtMethodInfo *)mono_mempool_alloc (mp, sizeof (MonoGSharedVtMethodInfo));
res->data.gsharedvt_method = info;
memcpy (info, oinfo, sizeof (MonoGSharedVtMethodInfo));
- info->entries = mono_mempool_alloc (mp, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
+ info->entries = (MonoRuntimeGenericContextInfoTemplate *)mono_mempool_alloc (mp, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
for (i = 0; i < oinfo->num_entries; ++i) {
MonoRuntimeGenericContextInfoTemplate *otemplate = &oinfo->entries [i];
- MonoRuntimeGenericContextInfoTemplate *template = &info->entries [i];
+ MonoRuntimeGenericContextInfoTemplate *template_ = &info->entries [i];
- memcpy (template, otemplate, sizeof (MonoRuntimeGenericContextInfoTemplate));
+ memcpy (template_, otemplate, sizeof (MonoRuntimeGenericContextInfoTemplate));
}
//info->locals_types = mono_mempool_alloc0 (mp, info->nlocals * sizeof (MonoType*));
//memcpy (info->locals_types, oinfo->locals_types, info->nlocals * sizeof (MonoType*));
MonoJumpInfoVirtMethod *oinfo;
oinfo = patch_info->data.virt_method;
- info = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoVirtMethod));
+ info = (MonoJumpInfoVirtMethod *)mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoVirtMethod));
res->data.virt_method = info;
memcpy (info, oinfo, sizeof (MonoJumpInfoVirtMethod));
break;
}
case MONO_PATCH_INFO_JIT_ICALL_ADDR:
return (ji->type << 8) | g_str_hash (ji->data.target);
+ case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER:
+ return (ji->type << 8) | mono_signature_hash (ji->data.sig);
default:
printf ("info type: %d\n", ji->type);
mono_print_ji (ji); printf ("\n");
if (ji1->data.target == ji2->data.target)
return 1;
return strcmp (ji1->data.target, ji2->data.target) == 0 ? 1 : 0;
+ case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER:
+ return mono_metadata_signature_equal (ji1->data.sig, ji2->data.sig) ? 1 : 0;
default:
if (ji1->data.target != ji2->data.target)
return 0;
jump_table = g_malloc0 (sizeof(gpointer) * patch_info->data.table->table_size);
#else
if (method && method->dynamic) {
- jump_table = mono_code_manager_reserve (mono_dynamic_code_hash_lookup (domain, method)->code_mp, sizeof (gpointer) * patch_info->data.table->table_size);
+ jump_table = (void **)mono_code_manager_reserve (mono_dynamic_code_hash_lookup (domain, method)->code_mp, sizeof (gpointer) * patch_info->data.table->table_size);
} else {
if (mono_aot_only) {
- jump_table = mono_domain_alloc (domain, sizeof (gpointer) * patch_info->data.table->table_size);
+ jump_table = (void **)mono_domain_alloc (domain, sizeof (gpointer) * patch_info->data.table->table_size);
} else {
- jump_table = mono_domain_code_reserve (domain, sizeof (gpointer) * patch_info->data.table->table_size);
+ jump_table = (void **)mono_domain_code_reserve (domain, sizeof (gpointer) * patch_info->data.table->table_size);
}
}
#endif
if (!mono_error_ok (&error))
g_error ("Could not patch ldtoken due to %s", mono_error_get_message (&error));
mono_class_init (handle_class);
- mono_class_init (mono_class_from_mono_type (handle));
+ mono_class_init (mono_class_from_mono_type ((MonoType *)handle));
target =
- mono_type_get_object (domain, handle);
+ mono_type_get_object (domain, (MonoType *)handle);
break;
}
case MONO_PATCH_INFO_LDTOKEN: {
target = mono_arch_get_seq_point_info (domain, code);
break;
#endif
- case MONO_PATCH_INFO_LLVM_IMT_TRAMPOLINE:
-#ifdef MONO_ARCH_LLVM_SUPPORTED
- g_assert (mono_use_llvm);
- target = mono_create_llvm_imt_trampoline (domain, patch_info->data.imt_tramp->method, patch_info->data.imt_tramp->vt_offset);
-#else
- g_assert_not_reached ();
-#endif
- break;
case MONO_PATCH_INFO_GC_CARD_TABLE_ADDR: {
int card_table_shift_bits;
gpointer card_table_mask;
case MONO_PATCH_INFO_TLS_OFFSET: {
int offset;
- offset = mini_get_tls_offset (GPOINTER_TO_INT (patch_info->data.target));
+ offset = mini_get_tls_offset ((MonoTlsKey)GPOINTER_TO_INT (patch_info->data.target));
#ifdef MONO_ARCH_HAVE_TRANSLATE_TLS_OFFSET
offset = mono_arch_translate_tls_offset (offset);
#endif
int len;
char *s;
- len = strlen (patch_info->data.target);
- s = mono_domain_alloc0 (domain, len + 1);
+ len = strlen ((const char *)patch_info->data.target);
+ s = (char *)mono_domain_alloc0 (domain, len + 1);
memcpy (s, patch_info->data.target, len);
target = s;
break;
}
+ case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER:
+ target = mini_get_gsharedvt_wrapper (TRUE, NULL, patch_info->data.sig, NULL, -1, FALSE);
+ break;
default:
g_assert_not_reached ();
}
static int failed_lookups = 0;
mono_domain_jit_code_hash_lock (domain);
- ji = mono_internal_hash_table_lookup (&domain->jit_code_hash, method);
+ ji = (MonoJitInfo *)mono_internal_hash_table_lookup (&domain->jit_code_hash, method);
if (!ji && shared) {
/* Try generic sharing */
- ji = mono_internal_hash_table_lookup (&domain->jit_code_hash, shared);
+ ji = (MonoJitInfo *)mono_internal_hash_table_lookup (&domain->jit_code_hash, shared);
if (ji && !ji->has_generic_jit_info)
ji = NULL;
if (!inited) {
#endif
+static void
+no_gsharedvt_in_wrapper (void)
+{
+ g_assert_not_reached ();
+}
+
static gpointer
mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt, MonoException **ex)
{
/* Must be domain neutral since there is only one copy */
opt |= MONO_OPT_SHARED;
- }
-
- if (method->dynamic)
- opt &= ~MONO_OPT_SHARED;
-
- /* These methods can become invalid when a domain is unloaded */
- if (method->klass->image != mono_get_corlib () || method->is_inflated)
+ } else {
+ /* MONO_OPT_SHARED is no longer supported, we only use it for icall wrappers */
opt &= ~MONO_OPT_SHARED;
+ }
if (opt & MONO_OPT_SHARED)
target_domain = mono_get_root_domain ();
code = mono_jit_compile_method_inner (method, target_domain, opt, ex);
if (!code && mono_llvm_only) {
+ if (method->wrapper_type == MONO_WRAPPER_UNKNOWN) {
+ WrapperInfo *info = mono_marshal_get_wrapper_info (method);
+
+ if (info->subtype == WRAPPER_SUBTYPE_GSHAREDVT_IN_SIG) {
+ /*
+ * These wrappers are only created for signatures which are in the program, but
+ * sometimes we load methods too eagerly and have to create them even if they
+ * will never be called.
+ */
+ return no_gsharedvt_in_wrapper;
+ }
+ }
+
printf ("AOT method not found in llvmonly mode: %s\n", mono_method_full_name (method, 1));
g_assert_not_reached ();
}
/*
* SGEN requires the JIT info for these methods to be registered, see is_ip_in_managed_allocator ().
*/
- ji = mini_jit_info_table_find (mono_domain_get (), code, &d);
+ ji = mini_jit_info_table_find (mono_domain_get (), (char *)code, &d);
g_assert (ji);
}
remove = NULL;
for (tmp = jlist->list; tmp; tmp = tmp->next) {
- guint8 *ip = tmp->data;
+ guint8 *ip = (guint8 *)tmp->data;
if (ip >= (guint8*)ji->ji->code_start && ip < (guint8*)ji->ji->code_start + ji->ji->code_size)
remove = g_slist_prepend (remove, tmp);
}
for (tmp = remove; tmp; tmp = tmp->next) {
- jlist->list = g_slist_delete_link (jlist->list, tmp->data);
+ jlist->list = g_slist_delete_link ((GSList *)jlist->list, (GSList *)tmp->data);
}
g_slist_free (remove);
}
return NULL;
}
+static guint32 bisect_opt = 0;
+static GHashTable *bisect_methods_hash = NULL;
+
+void
+mono_set_bisect_methods (guint32 opt, const char *method_list_filename)
+{
+ FILE *file;
+ char method_name [2048];
+
+ bisect_opt = opt;
+ bisect_methods_hash = g_hash_table_new (g_str_hash, g_str_equal);
+ g_assert (bisect_methods_hash);
+
+ file = fopen (method_list_filename, "r");
+ g_assert (file);
+
+ while (fgets (method_name, sizeof (method_name), file)) {
+ size_t len = strlen (method_name);
+ g_assert (len > 0);
+ g_assert (method_name [len - 1] == '\n');
+ method_name [len - 1] = 0;
+ g_hash_table_insert (bisect_methods_hash, g_strdup (method_name), GINT_TO_POINTER (1));
+ }
+ g_assert (feof (file));
+}
+
gboolean mono_do_single_method_regression = FALSE;
guint32 mono_single_method_regression_opt = 0;
MonoMethod *mono_current_single_method;
{
g_assert (method);
+ if (bisect_methods_hash) {
+ char *name = mono_method_full_name (method, TRUE);
+ void *res = g_hash_table_lookup (bisect_methods_hash, name);
+ g_free (name);
+ if (res)
+ return default_opt | bisect_opt;
+ }
if (!mono_do_single_method_regression)
return default_opt;
if (!mono_current_single_method) {
MonoVTable *vtable;
MonoDynCallInfo *dyn_call_info;
MonoClass *ret_box_class;
- gboolean needs_rgctx;
+ MonoMethodSignature *sig;
+ gboolean gsharedvt_invoke;
+ gpointer *wrapper_arg;
} RuntimeInvokeInfo;
+static RuntimeInvokeInfo*
+create_runtime_invoke_info (MonoDomain *domain, MonoMethod *method, gpointer compiled_method, gboolean callee_gsharedvt)
+{
+ MonoMethod *invoke;
+ RuntimeInvokeInfo *info;
+
+ info = g_new0 (RuntimeInvokeInfo, 1);
+ info->compiled_method = compiled_method;
+ info->sig = mono_method_signature (method);
+
+ invoke = mono_marshal_get_runtime_invoke (method, FALSE);
+ info->vtable = mono_class_vtable_full (domain, method->klass, TRUE);
+ g_assert (info->vtable);
+
+ MonoMethodSignature *sig = mono_method_signature (method);
+ MonoType *ret_type;
+
+ /*
+ * We want to avoid AOTing 1000s of runtime-invoke wrappers when running
+ * in full-aot mode, so we use a slower, but more generic wrapper if
+ * possible, built on top of the OP_DYN_CALL opcode provided by the JIT.
+ */
+#ifdef MONO_ARCH_DYN_CALL_SUPPORTED
+ if (!mono_llvm_only && (mono_aot_only || debug_options.dyn_runtime_invoke)) {
+ gboolean supported = TRUE;
+ int i;
+
+ if (method->string_ctor)
+ sig = mono_marshal_get_string_ctor_signature (method);
+
+ for (i = 0; i < sig->param_count; ++i) {
+ MonoType *t = sig->params [i];
+
+ if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
+ supported = FALSE;
+ }
+
+ if (mono_class_is_contextbound (method->klass) || !info->compiled_method)
+ supported = FALSE;
+
+ if (supported)
+ info->dyn_call_info = mono_arch_dyn_call_prepare (sig);
+ }
+#endif
+
+ ret_type = sig->ret;
+ switch (ret_type->type) {
+ case MONO_TYPE_VOID:
+ break;
+ case MONO_TYPE_I1:
+ case MONO_TYPE_U1:
+ case MONO_TYPE_I2:
+ case MONO_TYPE_U2:
+ case MONO_TYPE_I4:
+ case MONO_TYPE_U4:
+ case MONO_TYPE_I:
+ case MONO_TYPE_U:
+ case MONO_TYPE_I8:
+ case MONO_TYPE_U8:
+ case MONO_TYPE_BOOLEAN:
+ case MONO_TYPE_CHAR:
+ case MONO_TYPE_R4:
+ case MONO_TYPE_R8:
+ info->ret_box_class = mono_class_from_mono_type (ret_type);
+ break;
+ case MONO_TYPE_PTR:
+ info->ret_box_class = mono_defaults.int_class;
+ break;
+ case MONO_TYPE_STRING:
+ case MONO_TYPE_CLASS:
+ case MONO_TYPE_ARRAY:
+ case MONO_TYPE_SZARRAY:
+ case MONO_TYPE_OBJECT:
+ break;
+ case MONO_TYPE_GENERICINST:
+ if (!MONO_TYPE_IS_REFERENCE (ret_type))
+ info->ret_box_class = mono_class_from_mono_type (ret_type);
+ break;
+ case MONO_TYPE_VALUETYPE:
+ info->ret_box_class = mono_class_from_mono_type (ret_type);
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+
+ if (!info->dyn_call_info) {
+ if (mono_llvm_only) {
+#ifndef ENABLE_GSHAREDVT
+ g_assert_not_reached ();
+#endif
+ info->gsharedvt_invoke = TRUE;
+ if (!callee_gsharedvt) {
+ /* Invoke a gsharedvt out wrapper instead */
+ MonoMethod *wrapper = mini_get_gsharedvt_out_sig_wrapper (sig);
+ MonoMethodSignature *wrapper_sig = mini_get_gsharedvt_out_sig_wrapper_signature (sig->hasthis, sig->ret->type != MONO_TYPE_VOID, sig->param_count);
+
+ info->wrapper_arg = g_malloc0 (2 * sizeof (gpointer));
+ info->wrapper_arg [0] = mini_add_method_wrappers_llvmonly (method, info->compiled_method, FALSE, FALSE, &(info->wrapper_arg [1]));
+
+ /* Pass has_rgctx == TRUE since the wrapper has an extra arg */
+ invoke = mono_marshal_get_runtime_invoke_for_sig (wrapper_sig);
+ g_free (wrapper_sig);
+
+ info->compiled_method = mono_jit_compile_method (wrapper);
+ } else {
+ /* Gsharedvt methods can be invoked the same way */
+ /* The out wrapper has the same signature as the compiled gsharedvt method */
+ MonoMethodSignature *wrapper_sig = mini_get_gsharedvt_out_sig_wrapper_signature (sig->hasthis, sig->ret->type != MONO_TYPE_VOID, sig->param_count);
+
+ info->wrapper_arg = mono_method_needs_static_rgctx_invoke (method, TRUE) ? mini_method_get_rgctx (method) : NULL;
+
+ invoke = mono_marshal_get_runtime_invoke_for_sig (wrapper_sig);
+ g_free (wrapper_sig);
+ }
+ }
+ info->runtime_invoke = mono_jit_compile_method (invoke);
+ }
+
+ return info;
+}
+
+static MonoObject*
+mono_llvmonly_runtime_invoke (MonoMethod *method, RuntimeInvokeInfo *info, void *obj, void **params, MonoObject **exc)
+{
+ MonoMethodSignature *sig = info->sig;
+ MonoDomain *domain = mono_domain_get ();
+ MonoObject *(*runtime_invoke) (MonoObject *this_obj, void **params, MonoObject **exc, void* compiled_method);
+ gpointer *args;
+ gpointer retval_ptr;
+ guint8 retval [256];
+ gpointer *param_refs;
+ int i, pindex;
+
+ g_assert (info->gsharedvt_invoke);
+
+ /*
+ * Instead of invoking the method directly, we invoke a gsharedvt out wrapper.
+ * The advantage of this is the gsharedvt out wrappers have a reduced set of
+ * signatures, so we only have to generate runtime invoke wrappers for these
+ * signatures.
+ * This code also handles invocation of gsharedvt methods directly, no
+ * out wrappers are used in that case.
+ */
+ args = (void **)g_alloca ((sig->param_count + sig->hasthis + 2) * sizeof (gpointer));
+ param_refs = (gpointer*)g_alloca ((sig->param_count + sig->hasthis + 2) * sizeof (gpointer));
+ pindex = 0;
+ /*
+ * The runtime invoke wrappers expects pointers to primitive types, so have to
+ * use indirections.
+ */
+ if (sig->hasthis)
+ args [pindex ++] = &obj;
+ if (sig->ret->type != MONO_TYPE_VOID) {
+ retval_ptr = (gpointer)&retval;
+ args [pindex ++] = &retval_ptr;
+ }
+ for (i = 0; i < sig->param_count; ++i) {
+ MonoType *t = sig->params [i];
+
+ if (t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t))) {
+ MonoClass *klass = mono_class_from_mono_type (t);
+ guint8 *nullable_buf;
+ int size;
+
+ size = mono_class_value_size (klass, NULL);
+ nullable_buf = g_alloca (size);
+ g_assert (nullable_buf);
+
+ /* The argument pointed to by params [i] is either a boxed vtype or null */
+ mono_nullable_init (nullable_buf, (MonoObject*)params [i], klass);
+ params [i] = nullable_buf;
+ }
+
+ if (!t->byref && (MONO_TYPE_IS_REFERENCE (t) || t->type == MONO_TYPE_PTR)) {
+ param_refs [i] = params [i];
+ params [i] = &(param_refs [i]);
+ }
+ args [pindex ++] = ¶ms [i];
+ }
+ /* The gsharedvt out wrapper has an extra argument which contains the method to call */
+ args [pindex ++] = &info->wrapper_arg;
+
+ runtime_invoke = (MonoObject *(*)(MonoObject *, void **, MonoObject **, void *))info->runtime_invoke;
+
+ runtime_invoke (NULL, args, exc, info->compiled_method);
+
+ if (sig->ret->type != MONO_TYPE_VOID && info->ret_box_class)
+ return mono_value_box (domain, info->ret_box_class, retval);
+ else
+ return *(MonoObject**)retval;
+}
+
/**
* mono_jit_runtime_invoke:
* @method: the method to invoke
mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
{
MonoMethod *invoke, *callee;
- MonoObject *(*runtime_invoke) (MonoObject *this, void **params, MonoObject **exc, void* compiled_method);
+ MonoObject *(*runtime_invoke) (MonoObject *this_obj, void **params, MonoObject **exc, void* compiled_method);
MonoDomain *domain = mono_domain_get ();
MonoJitDomainInfo *domain_info;
RuntimeInvokeInfo *info, *info2;
+ MonoJitInfo *ji = NULL;
+ gboolean callee_gsharedvt = FALSE;
if (obj == NULL && !(method->flags & METHOD_ATTRIBUTE_STATIC) && !method->string_ctor && (method->wrapper_type == 0)) {
g_warning ("Ignoring invocation of an instance method on a NULL instance.\n");
domain_info = domain_jit_info (domain);
- info = mono_conc_hashtable_lookup (domain_info->runtime_invoke_hash, method);
+ info = (RuntimeInvokeInfo *)mono_conc_hashtable_lookup (domain_info->runtime_invoke_hash, method);
if (!info) {
if (mono_security_core_clr_enabled ()) {
}
}
- info = g_new0 (RuntimeInvokeInfo, 1);
- info->needs_rgctx = mono_llvm_only && mono_method_needs_static_rgctx_invoke (method, TRUE);
-
- invoke = mono_marshal_get_runtime_invoke (method, FALSE, info->needs_rgctx);
- info->vtable = mono_class_vtable_full (domain, method->klass, TRUE);
- g_assert (info->vtable);
+ gpointer compiled_method;
callee = method;
if (method->klass->rank && (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) &&
MonoMethod *wrapper;
wrapper = mono_marshal_get_array_accessor_wrapper (method);
- invoke = mono_marshal_get_runtime_invoke (wrapper, FALSE, FALSE);
+ invoke = mono_marshal_get_runtime_invoke (wrapper, FALSE);
callee = wrapper;
} else {
callee = NULL;
if (callee) {
MonoException *jit_ex = NULL;
- info->compiled_method = mono_jit_compile_method_with_opt (callee, mono_get_optimizations_for_method (callee, default_opt), &jit_ex);
- if (!info->compiled_method) {
- g_free (info);
+ compiled_method = mono_jit_compile_method_with_opt (callee, mono_get_optimizations_for_method (callee, default_opt), &jit_ex);
+ if (!compiled_method) {
g_assert (jit_ex);
if (exc) {
*exc = (MonoObject*)jit_ex;
}
}
- info->compiled_method = mini_add_method_trampoline (callee, info->compiled_method, mono_method_needs_static_rgctx_invoke (callee, TRUE), FALSE);
- } else {
- info->compiled_method = NULL;
- }
-
- /*
- * We want to avoid AOTing 1000s of runtime-invoke wrappers when running
- * in full-aot mode, so we use a slower, but more generic wrapper if
- * possible, built on top of the OP_DYN_CALL opcode provided by the JIT.
- */
-#ifdef MONO_ARCH_DYN_CALL_SUPPORTED
- if (!mono_llvm_only && (mono_aot_only || debug_options.dyn_runtime_invoke)) {
- MonoType *ret_type;
- MonoMethodSignature *sig = mono_method_signature (method);
- gboolean supported = TRUE;
- int i;
-
- if (method->string_ctor)
- sig = mono_marshal_get_string_ctor_signature (method);
- g_assert (!info->needs_rgctx);
-
- for (i = 0; i < sig->param_count; ++i) {
- MonoType *t = sig->params [i];
-
- if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
- supported = FALSE;
+ if (mono_llvm_only) {
+ ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (compiled_method), NULL);
+ callee_gsharedvt = mini_jit_info_is_gsharedvt (ji);
+ if (callee_gsharedvt)
+ callee_gsharedvt = mini_is_gsharedvt_variable_signature (mono_method_signature (jinfo_get_method (ji)));
}
- if (mono_class_is_contextbound (method->klass) || !info->compiled_method)
- supported = FALSE;
-
- if (supported)
- info->dyn_call_info = mono_arch_dyn_call_prepare (sig);
-
- ret_type = sig->ret;
- if (info->dyn_call_info) {
- switch (ret_type->type) {
- case MONO_TYPE_VOID:
- break;
- case MONO_TYPE_I1:
- case MONO_TYPE_U1:
- case MONO_TYPE_I2:
- case MONO_TYPE_U2:
- case MONO_TYPE_I4:
- case MONO_TYPE_U4:
- case MONO_TYPE_I:
- case MONO_TYPE_U:
- case MONO_TYPE_I8:
- case MONO_TYPE_U8:
- case MONO_TYPE_BOOLEAN:
- case MONO_TYPE_CHAR:
- case MONO_TYPE_R4:
- case MONO_TYPE_R8:
- info->ret_box_class = mono_class_from_mono_type (ret_type);
- break;
- case MONO_TYPE_PTR:
- info->ret_box_class = mono_defaults.int_class;
- break;
- case MONO_TYPE_STRING:
- case MONO_TYPE_CLASS:
- case MONO_TYPE_ARRAY:
- case MONO_TYPE_SZARRAY:
- case MONO_TYPE_OBJECT:
- break;
- case MONO_TYPE_GENERICINST:
- if (!MONO_TYPE_IS_REFERENCE (ret_type))
- info->ret_box_class = mono_class_from_mono_type (ret_type);
- break;
- case MONO_TYPE_VALUETYPE:
- info->ret_box_class = mono_class_from_mono_type (ret_type);
- break;
- default:
- g_assert_not_reached ();
- break;
- }
- }
+ if (!callee_gsharedvt)
+ compiled_method = mini_add_method_trampoline (callee, compiled_method, mono_method_needs_static_rgctx_invoke (callee, TRUE), FALSE);
+ } else {
+ compiled_method = NULL;
}
-#endif
- if (!info->dyn_call_info)
- info->runtime_invoke = mono_jit_compile_method (invoke);
+ info = create_runtime_invoke_info (domain, method, compiled_method, callee_gsharedvt);
mono_domain_lock (domain);
- info2 = mono_conc_hashtable_insert (domain_info->runtime_invoke_hash, method, info);
+ info2 = (RuntimeInvokeInfo *)mono_conc_hashtable_insert (domain_info->runtime_invoke_hash, method, info);
mono_domain_unlock (domain);
if (info2) {
g_free (info);
}
}
- runtime_invoke = info->runtime_invoke;
-
/*
* We need this here because mono_marshal_get_runtime_invoke can place
* the helper method in System.Object and not the target class.
gpointer *args;
static RuntimeInvokeDynamicFunction dyn_runtime_invoke;
int i, pindex;
- guint8 buf [256];
+ guint8 buf [512];
guint8 retval [256];
- gpointer rgctx;
if (!dyn_runtime_invoke) {
invoke = mono_marshal_get_runtime_invoke_dynamic ();
- dyn_runtime_invoke = mono_jit_compile_method (invoke);
+ dyn_runtime_invoke = (RuntimeInvokeDynamicFunction)mono_jit_compile_method (invoke);
}
/* Convert the arguments to the format expected by start_dyn_call () */
- args = g_alloca ((sig->param_count + sig->hasthis + info->needs_rgctx) * sizeof (gpointer));
+ args = (void **)g_alloca ((sig->param_count + sig->hasthis) * sizeof (gpointer));
pindex = 0;
if (sig->hasthis)
args [pindex ++] = &obj;
args [pindex ++] = params [i];
}
}
- if (info->needs_rgctx) {
- rgctx = mini_method_get_rgctx (method);
- args [pindex ++] = &rgctx;
- }
//printf ("M: %s\n", mono_method_full_name (method, TRUE));
}
#endif
- if (info->needs_rgctx) {
- MonoMethodSignature *sig = mono_method_signature (method);
- gpointer rgctx;
- gpointer *args;
- int i, pindex;
+ if (mono_llvm_only)
+ return mono_llvmonly_runtime_invoke (method, info, obj, params, exc);
- args = g_alloca ((sig->param_count + sig->hasthis + info->needs_rgctx) * sizeof (gpointer));
- pindex = 0;
- rgctx = mini_method_get_rgctx (method);
- for (i = 0; i < sig->param_count; ++i)
- args [pindex ++] = params [i];
- args [pindex ++] = &rgctx;
- return runtime_invoke (obj, args, exc, info->compiled_method);
- } else {
- return runtime_invoke (obj, params, exc, info->compiled_method);
+ runtime_invoke = (MonoObject *(*)(MonoObject *, void **, MonoObject **, void *))info->runtime_invoke;
+
+ return runtime_invoke ((MonoObject *)obj, params, exc, info->compiled_method);
+}
+
+typedef struct {
+ MonoVTable *vtable;
+ int slot;
+} IMTThunkInfo;
+
+typedef gpointer (*IMTThunkFunc) (gpointer *arg, MonoMethod *imt_method);
+
+/*
+ * mini_llvmonly_initial_imt_thunk:
+ *
+ * This function is called the first time a call is made through an IMT thunk.
+ * It should have the same signature as the mono_llvmonly_imt_thunk_... functions.
+ */
+static gpointer
+mini_llvmonly_initial_imt_thunk (gpointer *arg, MonoMethod *imt_method)
+{
+ IMTThunkInfo *info = (IMTThunkInfo*)arg;
+ gpointer *imt;
+ gpointer *ftndesc;
+ IMTThunkFunc func;
+
+ mono_vtable_build_imt_slot (info->vtable, info->slot);
+
+ imt = (gpointer*)info->vtable;
+ imt -= MONO_IMT_SIZE;
+
+ /* Return what the real IMT thunk returns */
+ ftndesc = imt [info->slot];
+ func = ftndesc [0];
+
+ if (func == (IMTThunkFunc)mini_llvmonly_initial_imt_thunk)
+ /* Happens when the imt slot contains only a generic virtual method */
+ return NULL;
+ return func ((gpointer *)ftndesc [1], imt_method);
+}
+
+/* This is called indirectly through an imt slot. */
+static gpointer
+mono_llvmonly_imt_thunk (gpointer *arg, MonoMethod *imt_method)
+{
+ int i = 0;
+
+ /* arg points to an array created in mono_llvmonly_get_imt_thunk () */
+ while (arg [i] && arg [i] != imt_method)
+ i += 2;
+ g_assert (arg [i]);
+
+ return arg [i + 1];
+}
+
+/* Optimized versions of mono_llvmonly_imt_thunk () for different table sizes */
+static gpointer
+mono_llvmonly_imt_thunk_1 (gpointer *arg, MonoMethod *imt_method)
+{
+ //g_assert (arg [0] == imt_method);
+ return arg [1];
+}
+
+static gpointer
+mono_llvmonly_imt_thunk_2 (gpointer *arg, MonoMethod *imt_method)
+{
+ //g_assert (arg [0] == imt_method || arg [2] == imt_method);
+ if (arg [0] == imt_method)
+ return arg [1];
+ else
+ return arg [3];
+}
+
+static gpointer
+mono_llvmonly_imt_thunk_3 (gpointer *arg, MonoMethod *imt_method)
+{
+ //g_assert (arg [0] == imt_method || arg [2] == imt_method || arg [4] == imt_method);
+ if (arg [0] == imt_method)
+ return arg [1];
+ else if (arg [2] == imt_method)
+ return arg [3];
+ else
+ return arg [5];
+}
+
+/*
+ * A version of the imt thunk used for generic virtual/variant iface methods.
+ * Unlikely a normal imt thunk, its possible that IMT_METHOD is not found
+ * in the search table. The original JIT code had a 'fallback' trampoline it could
+ * call, but we can't do that, so we just return NULL, and the compiled code
+ * will handle it.
+ */
+static gpointer
+mono_llvmonly_fallback_imt_thunk (gpointer *arg, MonoMethod *imt_method)
+{
+ int i = 0;
+
+ while (arg [i] && arg [i] != imt_method)
+ i += 2;
+ if (!arg [i])
+ return NULL;
+
+ return arg [i + 1];
+}
+
+static gpointer
+mono_llvmonly_get_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count, gpointer fail_tramp)
+{
+ gpointer *buf;
+ gpointer *res;
+ int i, index, real_count;
+ gboolean virtual_generic = FALSE;
+
+ /*
+ * Create an array which is passed to the imt thunk functions.
+ * The array contains MonoMethod-function descriptor pairs, terminated by a NULL entry.
+ */
+
+ real_count = 0;
+ for (i = 0; i < count; ++i) {
+ MonoIMTCheckItem *item = imt_entries [i];
+
+ if (item->is_equals)
+ real_count ++;
+ if (item->has_target_code)
+ virtual_generic = TRUE;
+ }
+
+ /*
+ * Initialize all vtable entries reachable from this imt slot, so the compiled
+ * code doesn't have to check it.
+ */
+ for (i = 0; i < count; ++i) {
+ MonoIMTCheckItem *item = imt_entries [i];
+ int vt_slot;
+
+ if (!item->is_equals || item->has_target_code)
+ continue;
+ vt_slot = item->value.vtable_slot;
+ mono_init_vtable_slot (vtable, vt_slot);
}
+
+ /* Save the entries into an array */
+ buf = (void **)mono_domain_alloc (domain, (real_count + 1) * 2 * sizeof (gpointer));
+ index = 0;
+ for (i = 0; i < count; ++i) {
+ MonoIMTCheckItem *item = imt_entries [i];
+
+ if (!item->is_equals)
+ continue;
+
+ g_assert (item->key);
+ buf [(index * 2)] = item->key;
+ if (item->has_target_code)
+ buf [(index * 2) + 1] = item->value.target_code;
+ else
+ buf [(index * 2) + 1] = vtable->vtable [item->value.vtable_slot];
+ index ++;
+ }
+ buf [(index * 2)] = NULL;
+ buf [(index * 2) + 1] = fail_tramp;
+
+ /*
+ * Return a function descriptor for a C function with 'buf' as its argument.
+ * It will by called by JITted code.
+ */
+ res = (void **)mono_domain_alloc (domain, 2 * sizeof (gpointer));
+ switch (real_count) {
+ case 1:
+ res [0] = mono_llvmonly_imt_thunk_1;
+ break;
+ case 2:
+ res [0] = mono_llvmonly_imt_thunk_2;
+ break;
+ case 3:
+ res [0] = mono_llvmonly_imt_thunk_3;
+ break;
+ default:
+ res [0] = mono_llvmonly_imt_thunk;
+ break;
+ }
+ if (virtual_generic || fail_tramp)
+ res [0] = mono_llvmonly_fallback_imt_thunk;
+ res [1] = buf;
+
+ return res;
}
MONO_SIG_HANDLER_FUNC (, mono_sigfpe_signal_handler)
MONO_SIG_HANDLER_INFO_TYPE *info = MONO_SIG_HANDLER_GET_INFO ();
MONO_SIG_HANDLER_GET_CONTEXT;
- ji = mono_jit_info_table_find_internal (mono_domain_get (), mono_arch_ip_from_context (ctx), TRUE, TRUE);
+ ji = mono_jit_info_table_find_internal (mono_domain_get (), (char *)mono_arch_ip_from_context (ctx), TRUE, TRUE);
#if defined(MONO_ARCH_HAVE_IS_INT_OVERFLOW)
if (mono_arch_is_int_overflow (ctx, info))
MONO_SIG_HANDLER_FUNC (, mono_sigsegv_signal_handler)
{
MonoJitInfo *ji;
- MonoJitTlsData *jit_tls = mono_native_tls_get_value (mono_jit_tls_id);
+ MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_native_tls_get_value (mono_jit_tls_id);
gpointer fault_addr = NULL;
#ifdef HAVE_SIG_INFO
MONO_SIG_HANDLER_INFO_TYPE *info = MONO_SIG_HANDLER_GET_INFO ();
}
#endif
- ji = mono_jit_info_table_find_internal (mono_domain_get (), mono_arch_ip_from_context (ctx), TRUE, TRUE);
+ ji = mono_jit_info_table_find_internal (mono_domain_get (), (char *)mono_arch_ip_from_context (ctx), TRUE, TRUE);
#ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
if (mono_handle_soft_stack_ovf (jit_tls, ji, ctx, info, (guint8*)info->si_addr))
if ((method->flags & METHOD_ATTRIBUTE_ABSTRACT) ||
(mono_method_signature (method)->hasthis && (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class))) {
nm = mono_marshal_get_remoting_invoke_for_target (method, target);
- addr = mono_compile_method (nm);
+ addr = (guint8 *)mono_compile_method (nm);
} else
{
- addr = mono_compile_method (method);
+ addr = (guint8 *)mono_compile_method (method);
}
return mono_get_addr_from_ftnptr (addr);
}
static int vtable_trampolines_size;
gpointer
-mini_get_vtable_trampoline (int slot_index)
+mini_get_vtable_trampoline (MonoVTable *vt, int slot_index)
{
int index = slot_index + MONO_IMT_SIZE;
if (mono_llvm_only) {
- /* Not used */
- if (slot_index < 0)
- /* The vtable/imt construction code in object.c depends on this being non-NULL */
- return no_imt_trampoline;
- else
- return no_vcall_trampoline;
+ if (slot_index < 0) {
+ /* Initialize the IMT thunks to a 'trampoline' so the generated code doesn't have to initialize it */
+ // FIXME: Memory management
+ gpointer *ftndesc = g_malloc (2 * sizeof (gpointer));
+ IMTThunkInfo *info = g_new0 (IMTThunkInfo, 1);
+ info->vtable = vt;
+ info->slot = index;
+ ftndesc [0] = mini_llvmonly_initial_imt_thunk;
+ ftndesc [1] = info;
+ mono_memory_barrier ();
+ return ftndesc;
+ } else {
+ return NULL;
+ }
}
g_assert (slot_index >= - MONO_IMT_SIZE);
memcpy (new_table, vtable_trampolines, vtable_trampolines_size * sizeof (gpointer));
g_free (vtable_trampolines);
mono_memory_barrier ();
- vtable_trampolines = new_table;
+ vtable_trampolines = (void **)new_table;
vtable_trampolines_size = new_size;
}
mono_jit_unlock ();
return vtable_trampolines [index];
}
+static gpointer
+mini_get_imt_trampoline (MonoVTable *vt, int slot_index)
+{
+ return mini_get_vtable_trampoline (vt, slot_index - MONO_IMT_SIZE);
+}
+
+static gboolean
+mini_imt_entry_inited (MonoVTable *vt, int imt_slot_index)
+{
+ if (mono_llvm_only)
+ return FALSE;
+
+ gpointer *imt = (gpointer*)vt;
+ imt -= MONO_IMT_SIZE;
+
+ return (imt [imt_slot_index] != mini_get_imt_trampoline (vt, imt_slot_index));
+}
+
+static gboolean
+is_callee_gsharedvt_variable (gpointer addr)
+{
+ MonoJitInfo *ji;
+ gboolean callee_gsharedvt;
+
+ ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr), NULL);
+ g_assert (ji);
+ callee_gsharedvt = mini_jit_info_is_gsharedvt (ji);
+ if (callee_gsharedvt)
+ callee_gsharedvt = mini_is_gsharedvt_variable_signature (mono_method_signature (jinfo_get_method (ji)));
+ return callee_gsharedvt;
+}
+
+void
+mini_init_delegate (MonoDelegate *del)
+{
+ if (mono_llvm_only) {
+ MonoMethod *method = del->method;
+
+ if (mono_method_needs_static_rgctx_invoke (method, FALSE))
+ del->rgctx = mini_method_get_rgctx (method);
+
+ /*
+ * Avoid adding gsharedvt in wrappers since they might not exist if
+ * this delegate is called through a gsharedvt delegate invoke wrapper.
+ * Instead, encode that the method is gsharedvt in del->rgctx,
+ * the CEE_MONO_CALLI_EXTRA_ARG implementation in the JIT depends on this.
+ */
+ if (is_callee_gsharedvt_variable (del->method_ptr)) {
+ g_assert ((((mgreg_t)del->rgctx) & 1) == 0);
+ del->rgctx = (gpointer)(((mgreg_t)del->rgctx) | 1);
+ }
+ }
+}
+
gpointer
mono_get_delegate_virtual_invoke_impl (MonoMethodSignature *sig, MonoMethod *method)
{
is_interface = method->klass->flags & TYPE_ATTRIBUTE_INTERFACE ? TRUE : FALSE;
load_imt_reg = is_virtual_generic || is_interface;
- if (is_interface && !is_virtual_generic)
+ if (is_interface)
offset = ((gint32)mono_method_get_imt_slot (method) - MONO_IMT_SIZE) * SIZEOF_VOID_P;
else
offset = G_STRUCT_OFFSET (MonoVTable, vtable) + ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
int ind = (load_imt_reg ? (-offset) : offset) / SIZEOF_VOID_P;
sprintf (tramp_name, "delegate_virtual_invoke%s_%d", imt, ind);
- cache [idx] = mono_aot_get_trampoline (tramp_name);
+ cache [idx] = (guint8 *)mono_aot_get_trampoline (tramp_name);
g_assert (cache [idx]);
} else {
- cache [idx] = mono_arch_get_delegate_virtual_invoke_impl (sig, method, offset, load_imt_reg);
+ cache [idx] = (guint8 *)mono_arch_get_delegate_virtual_invoke_impl (sig, method, offset, load_imt_reg);
}
return cache [idx];
}
-static gpointer
-mini_get_imt_trampoline (int slot_index)
+/**
+ * mini_parse_debug_option:
+ * @option: The option to parse.
+ *
+ * Parses debug options for the mono runtime. The options are the same as for
+ * the MONO_DEBUG environment variable.
+ *
+ */
+gboolean
+mini_parse_debug_option (const char *option)
{
- return mini_get_vtable_trampoline (slot_index - MONO_IMT_SIZE);
+ if (!strcmp (option, "handle-sigint"))
+ debug_options.handle_sigint = TRUE;
+ else if (!strcmp (option, "keep-delegates"))
+ debug_options.keep_delegates = TRUE;
+ else if (!strcmp (option, "reverse-pinvoke-exceptions"))
+ debug_options.reverse_pinvoke_exceptions = TRUE;
+ else if (!strcmp (option, "collect-pagefault-stats"))
+ debug_options.collect_pagefault_stats = TRUE;
+ else if (!strcmp (option, "break-on-unverified"))
+ debug_options.break_on_unverified = TRUE;
+ else if (!strcmp (option, "no-gdb-backtrace"))
+ debug_options.no_gdb_backtrace = TRUE;
+ else if (!strcmp (option, "suspend-on-sigsegv"))
+ debug_options.suspend_on_sigsegv = TRUE;
+ else if (!strcmp (option, "suspend-on-exception"))
+ debug_options.suspend_on_exception = TRUE;
+ else if (!strcmp (option, "suspend-on-unhandled"))
+ debug_options.suspend_on_unhandled = TRUE;
+ else if (!strcmp (option, "dont-free-domains"))
+ mono_dont_free_domains = TRUE;
+ else if (!strcmp (option, "dyn-runtime-invoke"))
+ debug_options.dyn_runtime_invoke = TRUE;
+ else if (!strcmp (option, "gdb"))
+ debug_options.gdb = TRUE;
+ else if (!strcmp (option, "explicit-null-checks"))
+ debug_options.explicit_null_checks = TRUE;
+ else if (!strcmp (option, "gen-seq-points"))
+ debug_options.gen_sdb_seq_points = TRUE;
+ else if (!strcmp (option, "gen-compact-seq-points"))
+ debug_options.gen_seq_points_compact_data = TRUE;
+ else if (!strcmp (option, "single-imm-size"))
+ debug_options.single_imm_size = TRUE;
+ else if (!strcmp (option, "init-stacks"))
+ debug_options.init_stacks = TRUE;
+ else if (!strcmp (option, "casts"))
+ debug_options.better_cast_details = TRUE;
+ else if (!strcmp (option, "soft-breakpoints"))
+ debug_options.soft_breakpoints = TRUE;
+ else if (!strcmp (option, "check-pinvoke-callconv"))
+ debug_options.check_pinvoke_callconv = TRUE;
+ else if (!strcmp (option, "arm-use-fallback-tls"))
+ debug_options.arm_use_fallback_tls = TRUE;
+ else if (!strcmp (option, "debug-domain-unload"))
+ mono_enable_debug_domain_unload (TRUE);
+ else if (!strcmp (option, "partial-sharing"))
+ mono_set_partial_sharing_supported (TRUE);
+ else if (!strcmp (option, "align-small-structs"))
+ mono_align_small_structs = TRUE;
+ else if (!strcmp (option, "native-debugger-break"))
+ debug_options.native_debugger_break = TRUE;
+ else
+ return FALSE;
+
+ return TRUE;
}
static void
for (ptr = args; ptr && *ptr; ptr++) {
const char *arg = *ptr;
- if (!strcmp (arg, "handle-sigint"))
- debug_options.handle_sigint = TRUE;
- else if (!strcmp (arg, "keep-delegates"))
- debug_options.keep_delegates = TRUE;
- else if (!strcmp (arg, "reverse-pinvoke-exceptions"))
- debug_options.reverse_pinvoke_exceptions = TRUE;
- else if (!strcmp (arg, "collect-pagefault-stats"))
- debug_options.collect_pagefault_stats = TRUE;
- else if (!strcmp (arg, "break-on-unverified"))
- debug_options.break_on_unverified = TRUE;
- else if (!strcmp (arg, "no-gdb-backtrace"))
- debug_options.no_gdb_backtrace = TRUE;
- else if (!strcmp (arg, "suspend-on-sigsegv"))
- debug_options.suspend_on_sigsegv = TRUE;
- else if (!strcmp (arg, "suspend-on-exception"))
- debug_options.suspend_on_exception = TRUE;
- else if (!strcmp (arg, "suspend-on-unhandled"))
- debug_options.suspend_on_unhandled = TRUE;
- else if (!strcmp (arg, "dont-free-domains"))
- mono_dont_free_domains = TRUE;
- else if (!strcmp (arg, "dyn-runtime-invoke"))
- debug_options.dyn_runtime_invoke = TRUE;
- else if (!strcmp (arg, "gdb"))
- debug_options.gdb = TRUE;
- else if (!strcmp (arg, "explicit-null-checks"))
- debug_options.explicit_null_checks = TRUE;
- else if (!strcmp (arg, "gen-seq-points"))
- debug_options.gen_sdb_seq_points = TRUE;
- else if (!strcmp (arg, "gen-compact-seq-points"))
- debug_options.gen_seq_points_compact_data = TRUE;
- else if (!strcmp (arg, "single-imm-size"))
- debug_options.single_imm_size = TRUE;
- else if (!strcmp (arg, "init-stacks"))
- debug_options.init_stacks = TRUE;
- else if (!strcmp (arg, "casts"))
- debug_options.better_cast_details = TRUE;
- else if (!strcmp (arg, "soft-breakpoints"))
- debug_options.soft_breakpoints = TRUE;
- else if (!strcmp (arg, "check-pinvoke-callconv"))
- debug_options.check_pinvoke_callconv = TRUE;
- else if (!strcmp (arg, "arm-use-fallback-tls"))
- debug_options.arm_use_fallback_tls = TRUE;
- else if (!strcmp (arg, "debug-domain-unload"))
- mono_enable_debug_domain_unload (TRUE);
- else if (!strcmp (arg, "partial-sharing"))
- mono_set_partial_sharing_supported (TRUE);
- else if (!strcmp (arg, "align-small-structs"))
- mono_align_small_structs = TRUE;
- else if (!strcmp (arg, "native-debugger-break"))
- debug_options.native_debugger_break = TRUE;
- else {
+ if (!mini_parse_debug_option (arg)) {
fprintf (stderr, "Invalid option for the MONO_DEBUG env variable: %s\n", arg);
fprintf (stderr, "Available options: 'handle-sigint', 'keep-delegates', 'reverse-pinvoke-exceptions', 'collect-pagefault-stats', 'break-on-unverified', 'no-gdb-backtrace', 'suspend-on-sigsegv', 'suspend-on-exception', 'suspend-on-unhandled', 'dont-free-domains', 'dyn-runtime-invoke', 'gdb', 'explicit-null-checks', 'gen-seq-points', 'gen-compact-seq-points', 'single-imm-size', 'init-stacks', 'casts', 'soft-breakpoints', 'check-pinvoke-callconv', 'arm-use-fallback-tls', 'debug-domain-unload', 'partial-sharing', 'align-small-structs', 'native-debugger-break'\n");
exit (1);
static gint
class_method_pair_equal (gconstpointer ka, gconstpointer kb)
{
- const MonoClassMethodPair *apair = ka;
- const MonoClassMethodPair *bpair = kb;
+ const MonoClassMethodPair *apair = (const MonoClassMethodPair *)ka;
+ const MonoClassMethodPair *bpair = (const MonoClassMethodPair *)kb;
return apair->klass == bpair->klass && apair->method == bpair->method ? 1 : 0;
}
static guint
class_method_pair_hash (gconstpointer data)
{
- const MonoClassMethodPair *pair = data;
+ const MonoClassMethodPair *pair = (const MonoClassMethodPair *)data;
return (gsize)pair->klass ^ (gsize)pair->method;
}
static void
delete_jump_list (gpointer key, gpointer value, gpointer user_data)
{
- MonoJumpList *jlist = value;
+ MonoJumpList *jlist = (MonoJumpList *)value;
g_slist_free (jlist->list);
}
static void
delete_got_slot_list (gpointer key, gpointer value, gpointer user_data)
{
- GSList *list = value;
+ GSList *list = (GSList *)value;
g_slist_free (list);
}
static void
dynamic_method_info_free (gpointer key, gpointer value, gpointer user_data)
{
- MonoJitDynamicMethodInfo *di = value;
+ MonoJitDynamicMethodInfo *di = (MonoJitDynamicMethodInfo *)value;
mono_code_manager_destroy (di->code_mp);
g_free (di);
}
}
#endif
- mono_mutex_init_recursive (&jit_mutex);
+ mono_os_mutex_init_recursive (&jit_mutex);
mono_cross_helpers_run ();
#ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
if (mono_aot_only)
mono_set_generic_sharing_vt_supported (TRUE);
+#else
+ if (mono_llvm_only)
+ mono_set_generic_sharing_vt_supported (TRUE);
#endif
#ifdef MONO_HAVE_FAST_TLS
callbacks.debug_log = mono_debugger_agent_debug_log;
callbacks.debug_log_is_enabled = mono_debugger_agent_debug_log_is_enabled;
callbacks.tls_key_supported = mini_tls_key_supported;
-
callbacks.get_vtable_trampoline = mini_get_vtable_trampoline;
callbacks.get_imt_trampoline = mini_get_imt_trampoline;
+ callbacks.imt_entry_inited = mini_imt_entry_inited;
+ callbacks.init_delegate = mini_init_delegate;
mono_install_callbacks (&callbacks);
mono_marshal_use_aot_wrappers (TRUE);
}
- if (mono_aot_only)
+ if (mono_llvm_only) {
+ mono_install_imt_thunk_builder (mono_llvmonly_get_imt_thunk);
+ mono_set_always_build_imt_thunks (TRUE);
+ } else if (mono_aot_only) {
mono_install_imt_thunk_builder (mono_aot_get_imt_thunk);
- else
+ } else {
mono_install_imt_thunk_builder (mono_arch_build_imt_thunk);
+ }
/*Init arch tls information only after the metadata side is inited to make sure we see dynamic appdomain tls keys*/
mono_arch_finish_init ();
register_icall (mono_ldstr, "mono_ldstr", "object ptr ptr int32", FALSE);
register_icall (mono_helper_stelem_ref_check, "mono_helper_stelem_ref_check", "void object object", FALSE);
register_icall (mono_object_new, "mono_object_new", "object ptr ptr", FALSE);
- register_icall (mono_object_new_specific, "mono_object_new_specific", "object ptr", FALSE);
+ register_icall (ves_icall_object_new_specific, "ves_icall_object_new_specific", "object ptr", FALSE);
register_icall (mono_array_new, "mono_array_new", "object ptr ptr int32", FALSE);
register_icall (mono_array_new_specific, "mono_array_new_specific", "object ptr int32", FALSE);
register_icall (mono_runtime_class_init, "mono_runtime_class_init", "void ptr", FALSE);
register_icall (mono_aot_init_llvm_method, "mono_aot_init_llvm_method", "void ptr int", TRUE);
register_icall (mono_aot_init_gshared_method_this, "mono_aot_init_gshared_method_this", "void ptr int object", TRUE);
- register_icall (mono_aot_init_gshared_method_rgctx, "mono_aot_init_gshared_method_rgctx", "void ptr int ptr", TRUE);
-
- register_icall_no_wrapper (mono_resolve_iface_call, "mono_resolve_iface_call", "ptr object int ptr ptr");
- register_icall_no_wrapper (mono_resolve_vcall, "mono_resolve_vcall", "ptr object int ptr");
- register_icall (mono_init_delegate, "mono_init_delegate", "void object object ptr", TRUE);
- register_icall (mono_init_delegate_virtual, "mono_init_delegate_virtual", "void object object ptr", TRUE);
+ register_icall (mono_aot_init_gshared_method_mrgctx, "mono_aot_init_gshared_method_mrgctx", "void ptr int ptr", TRUE);
+ register_icall (mono_aot_init_gshared_method_vtable, "mono_aot_init_gshared_method_vtable", "void ptr int ptr", TRUE);
+
+ register_icall_no_wrapper (mono_resolve_iface_call_gsharedvt, "mono_resolve_iface_call_gsharedvt", "ptr object int ptr ptr");
+ register_icall_no_wrapper (mono_resolve_vcall_gsharedvt, "mono_resolve_vcall_gsharedvt", "ptr object int ptr ptr");
+ register_icall_no_wrapper (mono_resolve_generic_virtual_call, "mono_resolve_generic_virtual_call", "ptr ptr int ptr");
+ register_icall_no_wrapper (mono_resolve_generic_virtual_iface_call, "mono_resolve_generic_virtual_iface_call", "ptr ptr int ptr");
+ register_icall_no_wrapper (mono_llvmonly_set_calling_assembly, "mono_llvmonly_set_calling_assembly", "void ptr");
+ register_icall_no_wrapper (mono_llvmonly_get_calling_assembly, "mono_llvmonly_get_calling_assembly", "object");
+ /* This needs a wrapper so it can have a preserveall cconv */
+ register_icall (mono_init_vtable_slot, "mono_init_vtable_slot", "ptr ptr int", FALSE);
+ register_icall (mono_llvmonly_init_delegate, "mono_llvmonly_init_delegate", "void object object ptr", TRUE);
+ register_icall (mono_llvmonly_init_delegate_virtual, "mono_llvmonly_init_delegate_virtual", "void object object ptr", TRUE);
register_icall (mono_get_assembly_object, "mono_get_assembly_object", "object ptr", TRUE);
+ register_icall (mono_get_method_object, "mono_get_method_object", "object ptr", TRUE);
#ifdef TARGET_IOS
register_icall (pthread_getspecific, "pthread_getspecific", "ptr ptr", TRUE);
mono_runtime_cleanup (domain);
#endif
- free_jit_tls_data (mono_native_tls_get_value (mono_jit_tls_id));
+ free_jit_tls_data ((MonoJitTlsData *)mono_native_tls_get_value (mono_jit_tls_id));
mono_icall_cleanup ();
mono_native_tls_free (mono_jit_tls_id);
- mono_mutex_destroy (&jit_mutex);
+ mono_os_mutex_destroy (&jit_mutex);
mono_code_manager_cleanup ();
default_opt_set = TRUE;
#ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
mono_set_generic_sharing_vt_supported (mono_aot_only || ((default_opt & MONO_OPT_GSHAREDVT) != 0));
+#else
+ if (mono_llvm_only)
+ mono_set_generic_sharing_vt_supported (TRUE);
#endif
}
}
mono_compile_method (method);
if (strcmp (method->name, "Finalize") == 0) {
- invoke = mono_marshal_get_runtime_invoke (method, FALSE, FALSE);
+ invoke = mono_marshal_get_runtime_invoke (method, FALSE);
mono_compile_method (invoke);
}
#ifndef DISABLE_REMOTING
} MonoJumpTableChunk;
static MonoJumpTableChunk* g_jumptable;
-#define mono_jumptable_lock() mono_mutex_lock (&jumptable_mutex)
-#define mono_jumptable_unlock() mono_mutex_unlock (&jumptable_mutex)
+#define mono_jumptable_lock() mono_os_mutex_lock (&jumptable_mutex)
+#define mono_jumptable_unlock() mono_os_mutex_unlock (&jumptable_mutex)
static mono_mutex_t jumptable_mutex;
static MonoJumpTableChunk*
mono_jumptable_init (void)
{
if (g_jumptable == NULL) {
- mono_mutex_init_recursive (&jumptable_mutex);
+ mono_os_mutex_init_recursive (&jumptable_mutex);
g_jumptable = mono_create_jumptable_chunk (DEFAULT_JUMPTABLE_CHUNK_ELEMENTS);
}
}
current = prev;
}
g_jumptable = NULL;
- mono_mutex_destroy (&jumptable_mutex);
+ mono_os_mutex_destroy (&jumptable_mutex);
}
}