Permalink
Browse files

Add AOT support for calling icalls directly without going through the…

… GOT.
  • Loading branch information...
1 parent fde2b2a commit ca245f60df2c9eec4e3adfb2c8fd83c5cb24aebb @vargaz vargaz committed Mar 7, 2012
Showing with 121 additions and 20 deletions.
  1. +5 −0 configure.in
  2. +76 −0 mono/metadata/icall.c
  3. +3 −0 mono/metadata/loader.h
  4. +36 −19 mono/mini/aot-compiler.c
  5. +1 −1 mono/mini/mini-x86.h
View
@@ -2666,6 +2666,11 @@ fi
AM_CONDITIONAL(MONO_DEBUGGER_SUPPORTED, test x$mono_debugger_supported = xyes)
AC_MSG_RESULT($mono_debugger_supported)
+AC_ARG_ENABLE(icall-symbol-map,[ --enable-icall-symbol-map Generate tables which map icall functions to their C symbols], icall_symbol_map=$enableval, icall_symbol_map=no)
+if test "x$icall_symbol_map" = "xyes"; then
+ AC_DEFINE(ENABLE_ICALL_SYMBOL_MAP, 1, [Icall symbol map enabled])
+fi
+
if test "x$with_tls" = "x__thread"; then
AC_DEFINE(HAVE_KW_THREAD, 1, [Have __thread keyword])
# Pass the information to libgc
View
@@ -7881,6 +7881,18 @@ icall_functions [] = {
NULL
};
+#ifdef ENABLE_ICALL_SYMBOL_MAP
+#undef ICALL_TYPE
+#undef ICALL
+#define ICALL_TYPE(id,name,first)
+#define ICALL(id,name,func) #func,
+static const gconstpointer
+icall_symbols [] = {
+#include "metadata/icall-def.h"
+ NULL
+};
+#endif
+
static GHashTable *icall_hash = NULL;
static GHashTable *jit_icall_hash_name = NULL;
static GHashTable *jit_icall_hash_addr = NULL;
@@ -8125,6 +8137,70 @@ mono_lookup_internal_call (MonoMethod *method)
return NULL;
}
+static int
+func_cmp (gconstpointer key, gconstpointer p)
+{
+ return (gsize)key - (gsize)*(gsize*)p;
+}
+
+/*
+ * mono_lookup_icall_symbol:
+ *
+ * Given the icall METHOD, returns its C symbol.
+ */
+const char*
+mono_lookup_icall_symbol (MonoMethod *m)
+{
+#ifdef ENABLE_ICALL_SYMBOL_MAP
+ gpointer func;
+ int i;
+ gpointer slot;
+ static gconstpointer *functions_sorted;
+ static const char**symbols_sorted;
+ static gboolean inited;
+
+ if (!inited) {
+ gboolean changed;
+
+ functions_sorted = g_malloc (G_N_ELEMENTS (icall_functions) * sizeof (gpointer));
+ memcpy (functions_sorted, icall_functions, G_N_ELEMENTS (icall_functions) * sizeof (gpointer));
+ symbols_sorted = g_malloc (G_N_ELEMENTS (icall_functions) * sizeof (gpointer));
+ memcpy (symbols_sorted, icall_symbols, G_N_ELEMENTS (icall_functions) * sizeof (gpointer));
+ /* Bubble sort the two arrays */
+ changed = TRUE;
+ while (changed) {
+ changed = FALSE;
+ for (i = 0; i < G_N_ELEMENTS (icall_functions) - 1; ++i) {
+ if (functions_sorted [i] > functions_sorted [i + 1]) {
+ gconstpointer tmp;
+
+ tmp = functions_sorted [i];
+ functions_sorted [i] = functions_sorted [i + 1];
+ functions_sorted [i + 1] = tmp;
+ tmp = symbols_sorted [i];
+ symbols_sorted [i] = symbols_sorted [i + 1];
+ symbols_sorted [i + 1] = tmp;
+ changed = TRUE;
+ }
+ }
+ }
+ }
+
+ func = mono_lookup_internal_call (m);
+ if (!func)
+ return NULL;
+ slot = bsearch (func, functions_sorted, G_N_ELEMENTS (icall_functions), sizeof (gpointer), func_cmp);
+ if (!slot)
+ return NULL;
+ g_assert (slot);
+ return symbols_sorted [(gpointer*)slot - (gpointer*)functions_sorted];
+#else
+ fprintf (stderr, "icall symbol maps not enabled, pass --enable-icall-symbol-map to configure.\n");
+ g_assert_not_reached ();
+ return 0;
+#endif
+}
+
static MonoType*
type_from_typename (char *typename)
{
View
@@ -59,6 +59,9 @@ mono_add_internal_call (const char *name, const void* method);
void*
mono_lookup_internal_call (MonoMethod *method);
+const char*
+mono_lookup_icall_symbol (MonoMethod *m);
+
void
mono_dllmap_insert (MonoImage *assembly, const char *dll, const char *func, const char *tdll, const char *tfunc);
View
@@ -123,6 +123,7 @@ typedef struct MonoAotOptions {
gboolean soft_debug;
gboolean log_generics;
gboolean direct_pinvoke;
+ gboolean direct_icalls;
int nthreads;
int ntrampolines;
int nrgctx_trampolines;
@@ -619,8 +620,13 @@ arch_emit_direct_call (MonoAotCompile *acfg, const char *target, int *call_size)
{
#if defined(TARGET_X86) || defined(TARGET_AMD64)
/* Need to make sure this is exactly 5 bytes long */
- emit_byte (acfg, '\xe8');
- emit_symbol_diff (acfg, target, ".", -4);
+ if (FALSE && !acfg->use_bin_writer) {
+ img_writer_emit_unset_mode (acfg->w);
+ fprintf (acfg->fp, "call %s\n", target);
+ } else {
+ emit_byte (acfg, '\xe8');
+ emit_symbol_diff (acfg, target, ".", -4);
+ }
*call_size = 5;
#elif defined(TARGET_ARM)
if (acfg->use_bin_writer) {
@@ -3653,6 +3659,10 @@ is_direct_callable (MonoAotCompile *acfg, MonoMethod *method, MonoJumpInfo *patc
} else if ((patch_info->type == MONO_PATCH_INFO_ICALL_ADDR && patch_info->data.method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
if (acfg->aot_opts.direct_pinvoke)
return TRUE;
+ } else if (patch_info->type == MONO_PATCH_INFO_ICALL_ADDR) {
+ if (acfg->aot_opts.direct_icalls)
+ return TRUE;
+ return FALSE;
}
return FALSE;
@@ -3668,7 +3678,6 @@ get_pinvoke_import (MonoAotCompile *acfg, MonoMethod *method)
MonoTableInfo *mr = &tables [MONO_TABLE_MODULEREF];
guint32 im_cols [MONO_IMPLMAP_SIZE];
char *import;
- const char *prefix;
import = g_hash_table_lookup (acfg->method_to_pinvoke_import, method);
if (import != NULL)
@@ -3682,13 +3691,7 @@ get_pinvoke_import (MonoAotCompile *acfg, MonoMethod *method)
if (!im_cols [MONO_IMPLMAP_SCOPE] || im_cols [MONO_IMPLMAP_SCOPE] > mr->rows)
return NULL;
-#if defined(__APPLE__)
- prefix = "_";
-#else
- prefix = "";
-#endif
-
- import = g_strdup_printf ("%s%s", prefix, mono_metadata_string_heap (image, im_cols [MONO_IMPLMAP_NAME]));
+ import = g_strdup_printf ("%s", mono_metadata_string_heap (image, im_cols [MONO_IMPLMAP_NAME]));
g_hash_table_insert (acfg->method_to_pinvoke_import, method, import);
@@ -3767,22 +3770,34 @@ emit_and_reloc_code (MonoAotCompile *acfg, MonoMethod *method, guint8 *code, gui
direct_call = TRUE;
g_assert (strlen (callee_cfg->asm_symbol) < 1000);
sprintf (direct_call_target, "%s", callee_cfg->asm_symbol);
- patch_info->type = MONO_PATCH_INFO_NONE;
- acfg->stats.direct_calls ++;
}
acfg->stats.all_calls ++;
- } else if ((patch_info->type == MONO_PATCH_INFO_ICALL_ADDR) && (patch_info->data.method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
+ } else if (patch_info->type == MONO_PATCH_INFO_ICALL_ADDR) {
if (!got_only && is_direct_callable (acfg, method, patch_info)) {
- direct_call = TRUE;
- direct_pinvoke = get_pinvoke_import (acfg, patch_info->data.method);
- g_assert (strlen (direct_pinvoke) < 1000);
- sprintf (direct_call_target, "%s", direct_pinvoke);
- patch_info->type = MONO_PATCH_INFO_NONE;
- acfg->stats.direct_calls ++;
+ if (!(patch_info->data.method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL))
+ direct_pinvoke = mono_lookup_icall_symbol (patch_info->data.method);
+ else
+ direct_pinvoke = get_pinvoke_import (acfg, patch_info->data.method);
+ if (direct_pinvoke) {
+ const char*prefix;
+#if defined(__APPLE__)
+ prefix = "_";
+#else
+ prefix = "";
+#endif
+ direct_call = TRUE;
+ g_assert (strlen (direct_pinvoke) < 1000);
+ sprintf (direct_call_target, "%s%s", prefix, direct_pinvoke);
+ }
}
}
+ if (direct_call) {
+ patch_info->type = MONO_PATCH_INFO_NONE;
+ acfg->stats.direct_calls ++;
+ }
+
if (!got_only && !direct_call) {
MonoPltEntry *plt_entry = get_plt_entry (acfg, patch_info);
if (plt_entry) {
@@ -5169,6 +5184,8 @@ mono_aot_parse_options (const char *aot_options, MonoAotOptions *opts)
opts->soft_debug = TRUE;
} else if (str_begins_with (arg, "direct-pinvoke")) {
opts->direct_pinvoke = TRUE;
+ } else if (str_begins_with (arg, "direct-icalls")) {
+ opts->direct_icalls = TRUE;
} else if (str_begins_with (arg, "print-skipped")) {
opts->print_skipped_methods = TRUE;
} else if (str_begins_with (arg, "stats")) {
View
@@ -224,7 +224,7 @@ typedef struct {
#if defined(__linux__) || defined (__APPLE__)
#define MONO_ARCH_MONITOR_OBJECT_REG X86_EAX
#endif
-#if !defined (__APPLE__) || defined(__native_client_codegen__)
+#if !defined(__native_client_codegen__)
#define MONO_ARCH_HAVE_FULL_AOT_TRAMPOLINES 1
#endif
#define MONO_ARCH_GOT_REG X86_EBX

0 comments on commit ca245f6

Please sign in to comment.