Selaa lähdekoodia

Add beginnings of support for calling JIT icalls directly in full-aot mode.

Zoltan Varga 13 vuotta sitten
vanhempi
sitoutus
09354d2feb

+ 7 - 0
mono/metadata/class-internals.h

@@ -633,6 +633,7 @@ typedef struct {
 	gconstpointer wrapper;
 	gconstpointer wrapper;
 	gconstpointer trampoline;
 	gconstpointer trampoline;
 	MonoMethodSignature *sig;
 	MonoMethodSignature *sig;
+	const char *c_symbol;
 } MonoJitICallInfo;
 } MonoJitICallInfo;
 
 
 typedef struct {
 typedef struct {
@@ -1175,6 +1176,9 @@ mono_create_icall_signature (const char *sigstr) MONO_INTERNAL;
 MonoJitICallInfo *
 MonoJitICallInfo *
 mono_register_jit_icall (gconstpointer func, const char *name, MonoMethodSignature *sig, gboolean is_save) MONO_INTERNAL;
 mono_register_jit_icall (gconstpointer func, const char *name, MonoMethodSignature *sig, gboolean is_save) MONO_INTERNAL;
 
 
+MonoJitICallInfo *
+mono_register_jit_icall_full (gconstpointer func, const char *name, MonoMethodSignature *sig, gboolean is_save, const char *c_symbol) MONO_INTERNAL;
+
 void
 void
 mono_register_jit_icall_wrapper (MonoJitICallInfo *info, gconstpointer wrapper) MONO_INTERNAL;
 mono_register_jit_icall_wrapper (MonoJitICallInfo *info, gconstpointer wrapper) MONO_INTERNAL;
 
 
@@ -1187,6 +1191,9 @@ mono_find_jit_icall_by_addr (gconstpointer addr) MONO_LLVM_INTERNAL;
 GHashTable*
 GHashTable*
 mono_get_jit_icall_info (void) MONO_INTERNAL;
 mono_get_jit_icall_info (void) MONO_INTERNAL;
 
 
+const char*
+mono_lookup_jit_icall_symbol (const char *name) MONO_INTERNAL;
+
 gboolean
 gboolean
 mono_class_set_failure (MonoClass *klass, guint32 ex_type, void *ex_data) MONO_INTERNAL;
 mono_class_set_failure (MonoClass *klass, guint32 ex_type, void *ex_data) MONO_INTERNAL;
 
 

+ 28 - 1
mono/metadata/icall.c

@@ -8387,6 +8387,25 @@ mono_get_jit_icall_info (void)
 	return jit_icall_hash_name;
 	return jit_icall_hash_name;
 }
 }
 
 
+/*
+ * mono_lookup_jit_icall_symbol:
+ *
+ *   Given the jit icall NAME, returns its C symbol if possible, or NULL.
+ */
+const char*
+mono_lookup_jit_icall_symbol (const char *name)
+{
+	MonoJitICallInfo *info;
+	const char *res = NULL;
+
+	mono_loader_lock ();
+	info = g_hash_table_lookup (jit_icall_hash_name, name);
+	if (info)
+		res = info->c_symbol;
+	mono_loader_unlock ();
+	return res;
+}
+
 void
 void
 mono_register_jit_icall_wrapper (MonoJitICallInfo *info, gconstpointer wrapper)
 mono_register_jit_icall_wrapper (MonoJitICallInfo *info, gconstpointer wrapper)
 {
 {
@@ -8396,7 +8415,7 @@ mono_register_jit_icall_wrapper (MonoJitICallInfo *info, gconstpointer wrapper)
 }
 }
 
 
 MonoJitICallInfo *
 MonoJitICallInfo *
-mono_register_jit_icall (gconstpointer func, const char *name, MonoMethodSignature *sig, gboolean is_save)
+mono_register_jit_icall_full (gconstpointer func, const char *name, MonoMethodSignature *sig, gboolean is_save, const char *c_symbol)
 {
 {
 	MonoJitICallInfo *info;
 	MonoJitICallInfo *info;
 	
 	
@@ -8420,6 +8439,7 @@ mono_register_jit_icall (gconstpointer func, const char *name, MonoMethodSignatu
 	info->name = name;
 	info->name = name;
 	info->func = func;
 	info->func = func;
 	info->sig = sig;
 	info->sig = sig;
+	info->c_symbol = c_symbol;
 
 
 	if (is_save) {
 	if (is_save) {
 		info->wrapper = func;
 		info->wrapper = func;
@@ -8433,3 +8453,10 @@ mono_register_jit_icall (gconstpointer func, const char *name, MonoMethodSignatu
 	mono_loader_unlock ();
 	mono_loader_unlock ();
 	return info;
 	return info;
 }
 }
+
+MonoJitICallInfo *
+mono_register_jit_icall (gconstpointer func, const char *name, MonoMethodSignature *sig, gboolean is_save)
+{
+	return mono_register_jit_icall_full (func, name, sig, is_save, NULL);
+}
+

+ 17 - 11
mono/mini/aot-compiler.c

@@ -210,6 +210,7 @@ typedef struct MonoAotCompile {
 	char *plt_symbol;
 	char *plt_symbol;
 	GHashTable *method_label_hash;
 	GHashTable *method_label_hash;
 	const char *temp_prefix;
 	const char *temp_prefix;
+	const char *user_symbol_prefix;
 	const char *llvm_label_prefix;
 	const char *llvm_label_prefix;
 	guint32 label_generator;
 	guint32 label_generator;
 	gboolean llvm;
 	gboolean llvm;
@@ -589,6 +590,7 @@ arch_init (MonoAotCompile *acfg)
 	 * symbols.
 	 * symbols.
 	 */
 	 */
 	acfg->llvm_label_prefix = "";
 	acfg->llvm_label_prefix = "";
+	acfg->user_symbol_prefix = "";
 
 
 #ifdef TARGET_ARM
 #ifdef TARGET_ARM
 	if (acfg->aot_opts.mtriple && strstr (acfg->aot_opts.mtriple, "darwin")) {
 	if (acfg->aot_opts.mtriple && strstr (acfg->aot_opts.mtriple, "darwin")) {
@@ -609,6 +611,7 @@ arch_init (MonoAotCompile *acfg)
 #endif
 #endif
 
 
 #ifdef TARGET_MACH
 #ifdef TARGET_MACH
+	acfg->user_symbol_prefix = "_";
 	acfg->llvm_label_prefix = "_";
 	acfg->llvm_label_prefix = "_";
 	acfg->need_no_dead_strip = TRUE;
 	acfg->need_no_dead_strip = TRUE;
 #endif
 #endif
@@ -630,11 +633,11 @@ arch_init (MonoAotCompile *acfg)
  * calling code.
  * calling code.
  */
  */
 static void
 static void
-arch_emit_direct_call (MonoAotCompile *acfg, const char *target, int *call_size)
+arch_emit_direct_call (MonoAotCompile *acfg, const char *target, gboolean external, int *call_size)
 {
 {
 #if defined(TARGET_X86) || defined(TARGET_AMD64)
 #if defined(TARGET_X86) || defined(TARGET_AMD64)
 	/* Need to make sure this is exactly 5 bytes long */
 	/* Need to make sure this is exactly 5 bytes long */
-	if (FALSE && !acfg->use_bin_writer) {
+	if (external && !acfg->use_bin_writer) {
 		img_writer_emit_unset_mode (acfg->w);
 		img_writer_emit_unset_mode (acfg->w);
 		fprintf (acfg->fp, "call %s\n", target);
 		fprintf (acfg->fp, "call %s\n", target);
 	} else {
 	} else {
@@ -4145,7 +4148,7 @@ emit_and_reloc_code (MonoAotCompile *acfg, MonoMethod *method, guint8 *code, gui
 	GPtrArray *patches;
 	GPtrArray *patches;
 	MonoJumpInfo *patch_info;
 	MonoJumpInfo *patch_info;
 	MonoMethodHeader *header;
 	MonoMethodHeader *header;
-	gboolean skip, direct_call;
+	gboolean skip, direct_call, external_call;
 	guint32 got_slot;
 	guint32 got_slot;
 	const char *direct_call_target;
 	const char *direct_call_target;
 	const char *direct_pinvoke;
 	const char *direct_pinvoke;
@@ -4195,6 +4198,7 @@ emit_and_reloc_code (MonoAotCompile *acfg, MonoMethod *method, guint8 *code, gui
 				 * the same assembly and requires no initialization.
 				 * the same assembly and requires no initialization.
 				 */
 				 */
 				direct_call = FALSE;
 				direct_call = FALSE;
+				external_call = FALSE;
 				if ((patch_info->type == MONO_PATCH_INFO_METHOD) && (patch_info->data.method->klass->image == acfg->image)) {
 				if ((patch_info->type == MONO_PATCH_INFO_METHOD) && (patch_info->data.method->klass->image == acfg->image)) {
 					if (!got_only && is_direct_callable (acfg, method, patch_info)) {
 					if (!got_only && is_direct_callable (acfg, method, patch_info)) {
 						MonoCompile *callee_cfg = g_hash_table_lookup (acfg->method_to_cfg, patch_info->data.method);
 						MonoCompile *callee_cfg = g_hash_table_lookup (acfg->method_to_cfg, patch_info->data.method);
@@ -4213,17 +4217,19 @@ emit_and_reloc_code (MonoAotCompile *acfg, MonoMethod *method, guint8 *code, gui
 						else
 						else
 							direct_pinvoke = get_pinvoke_import (acfg, patch_info->data.method);
 							direct_pinvoke = get_pinvoke_import (acfg, patch_info->data.method);
 						if (direct_pinvoke) {
 						if (direct_pinvoke) {
-							const char*prefix;
-#if defined(TARGET_MACH)
-							prefix = "_";
-#else
-							prefix = "";
-#endif
 							direct_call = TRUE;
 							direct_call = TRUE;
 							g_assert (strlen (direct_pinvoke) < 1000);
 							g_assert (strlen (direct_pinvoke) < 1000);
-							direct_call_target = g_strdup_printf ("%s%s", prefix, direct_pinvoke);
+							direct_call_target = g_strdup_printf ("%s%s", acfg->user_symbol_prefix, direct_pinvoke);
 						}
 						}
 					}
 					}
+				} else if (patch_info->type == MONO_PATCH_INFO_JIT_ICALL_ADDR) {
+					const char *sym = mono_lookup_jit_icall_symbol (patch_info->data.name);
+					if (sym && acfg->aot_opts.direct_icalls) {
+						direct_call = TRUE;
+						external_call = TRUE;
+						g_assert (strlen (sym) < 1000);
+						direct_call_target = g_strdup_printf ("%s%s", acfg->user_symbol_prefix, sym);
+					}
 				}
 				}
 
 
 				if (direct_call) {
 				if (direct_call) {
@@ -4247,7 +4253,7 @@ emit_and_reloc_code (MonoAotCompile *acfg, MonoMethod *method, guint8 *code, gui
 				if (direct_call) {
 				if (direct_call) {
 					int call_size;
 					int call_size;
 
 
-					arch_emit_direct_call (acfg, direct_call_target, &call_size);
+					arch_emit_direct_call (acfg, direct_call_target, external_call, &call_size);
 					i += call_size - 1;
 					i += call_size - 1;
 				} else {
 				} else {
 					int code_size;
 					int code_size;

+ 5 - 2
mono/mini/image-writer.c

@@ -1586,8 +1586,11 @@ asm_writer_emit_global (MonoImageWriter *acfg, const char *name, gboolean func)
 {
 {
 	asm_writer_emit_unset_mode (acfg);
 	asm_writer_emit_unset_mode (acfg);
 #if  ((defined(__ppc__) || defined(TARGET_X86)) && defined(TARGET_ASM_APPLE)) || (defined(HOST_WIN32) && !defined(MONO_CROSS_COMPILE))
 #if  ((defined(__ppc__) || defined(TARGET_X86)) && defined(TARGET_ASM_APPLE)) || (defined(HOST_WIN32) && !defined(MONO_CROSS_COMPILE))
-    // mach-o always uses a '_' prefix.
-	fprintf (acfg->fp, "\t.globl _%s\n", name);
+	if (name[0] != '_')
+		// mach-o always uses a '_' prefix.
+		fprintf (acfg->fp, "\t.globl _%s\n", name);
+	else
+		fprintf (acfg->fp, "\t.globl %s\n", name);
 #else
 #else
 	fprintf (acfg->fp, "\t.globl %s\n", name);
 	fprintf (acfg->fp, "\t.globl %s\n", name);
 #endif
 #endif

+ 25 - 9
mono/mini/mini.c

@@ -2315,11 +2315,28 @@ mono_register_opcode_emulation (int opcode, const char *name, const char *sigstr
 	emul_opcode_hit_cache [opcode >> (EMUL_HIT_SHIFT + 3)] |= (1 << (opcode & EMUL_HIT_MASK));
 	emul_opcode_hit_cache [opcode >> (EMUL_HIT_SHIFT + 3)] |= (1 << (opcode & EMUL_HIT_MASK));
 }
 }
 
 
+/*
+ * For JIT icalls implemented in C.
+ * NAME should be the same as the name of the C function whose address is FUNC.
+ */
 static void
 static void
 register_icall (gpointer func, const char *name, const char *sigstr, gboolean save)
 register_icall (gpointer func, const char *name, const char *sigstr, gboolean save)
 {
 {
 	MonoMethodSignature *sig;
 	MonoMethodSignature *sig;
 
 
+	if (sigstr)
+		sig = mono_create_icall_signature (sigstr);
+	else
+		sig = NULL;
+
+	mono_register_jit_icall_full (func, name, sig, save, name);
+}
+
+static void
+register_dyn_icall (gpointer func, const char *name, const char *sigstr, gboolean save)
+{
+	MonoMethodSignature *sig;
+
 	if (sigstr)
 	if (sigstr)
 		sig = mono_create_icall_signature (sigstr);
 		sig = mono_create_icall_signature (sigstr);
 	else
 	else
@@ -6902,10 +6919,9 @@ mini_init (const char *filename, const char *runtime_version)
 	register_icall (mono_jit_set_domain, "mono_jit_set_domain", "void ptr", TRUE);
 	register_icall (mono_jit_set_domain, "mono_jit_set_domain", "void ptr", TRUE);
 	register_icall (mono_domain_get, "mono_domain_get", "ptr", TRUE);
 	register_icall (mono_domain_get, "mono_domain_get", "ptr", TRUE);
 
 
-	register_icall (mono_get_throw_exception (), "mono_arch_throw_exception", "void object", TRUE);
-	register_icall (mono_get_rethrow_exception (), "mono_arch_rethrow_exception", "void object", TRUE);
-	register_icall (mono_get_throw_corlib_exception (), "mono_arch_throw_corlib_exception", 
-				 "void ptr", TRUE);
+	register_dyn_icall (mono_get_throw_exception (), "mono_arch_throw_exception", "void object", TRUE);
+	register_dyn_icall (mono_get_rethrow_exception (), "mono_arch_rethrow_exception", "void object", TRUE);
+	register_dyn_icall (mono_get_throw_corlib_exception (), "mono_arch_throw_corlib_exception", "void ptr", TRUE);
 	register_icall (mono_thread_get_undeniable_exception, "mono_thread_get_undeniable_exception", "object", FALSE);
 	register_icall (mono_thread_get_undeniable_exception, "mono_thread_get_undeniable_exception", "object", FALSE);
 	register_icall (mono_thread_interruption_checkpoint, "mono_thread_interruption_checkpoint", "void", FALSE);
 	register_icall (mono_thread_interruption_checkpoint, "mono_thread_interruption_checkpoint", "void", FALSE);
 	register_icall (mono_thread_force_interruption_checkpoint, "mono_thread_force_interruption_checkpoint", "void", FALSE);
 	register_icall (mono_thread_force_interruption_checkpoint, "mono_thread_force_interruption_checkpoint", "void", FALSE);
@@ -7041,7 +7057,7 @@ mini_init (const char *filename, const char *runtime_version)
 		"ptr ptr ptr ptr", FALSE);
 		"ptr ptr ptr ptr", FALSE);
 	register_icall (mono_get_special_static_data, "mono_get_special_static_data", "ptr int", FALSE);
 	register_icall (mono_get_special_static_data, "mono_get_special_static_data", "ptr int", FALSE);
 	register_icall (mono_ldstr, "mono_ldstr", "object ptr ptr int32", FALSE);
 	register_icall (mono_ldstr, "mono_ldstr", "object ptr ptr int32", FALSE);
-	register_icall (mono_helper_stelem_ref_check, "helper_stelem_ref_check", "void object object", 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, "mono_object_new", "object ptr ptr", FALSE);
 	register_icall (mono_object_new_specific, "mono_object_new_specific", "object ptr", FALSE);
 	register_icall (mono_object_new_specific, "mono_object_new_specific", "object ptr", FALSE);
 	register_icall (mono_array_new, "mono_array_new", "object ptr ptr int32", FALSE);
 	register_icall (mono_array_new, "mono_array_new", "object ptr ptr int32", FALSE);
@@ -7050,10 +7066,10 @@ mini_init (const char *filename, const char *runtime_version)
 	register_icall (mono_ldftn, "mono_ldftn", "ptr ptr", FALSE);
 	register_icall (mono_ldftn, "mono_ldftn", "ptr ptr", FALSE);
 	register_icall (mono_ldvirtfn, "mono_ldvirtfn", "ptr object ptr", FALSE);
 	register_icall (mono_ldvirtfn, "mono_ldvirtfn", "ptr object ptr", FALSE);
 	register_icall (mono_ldvirtfn_gshared, "mono_ldvirtfn_gshared", "ptr object ptr", FALSE);
 	register_icall (mono_ldvirtfn_gshared, "mono_ldvirtfn_gshared", "ptr object ptr", FALSE);
-	register_icall (mono_helper_compile_generic_method, "compile_generic_method", "ptr object ptr ptr", FALSE);
-	register_icall (mono_helper_ldstr, "helper_ldstr", "object ptr int", FALSE);
-	register_icall (mono_helper_ldstr_mscorlib, "helper_ldstr_mscorlib", "object int", FALSE);
-	register_icall (mono_helper_newobj_mscorlib, "helper_newobj_mscorlib", "object int", FALSE);
+	register_icall (mono_helper_compile_generic_method, "mono_helper_compile_generic_method", "ptr object ptr ptr", FALSE);
+	register_icall (mono_helper_ldstr, "mono_helper_ldstr", "object ptr int", FALSE);
+	register_icall (mono_helper_ldstr_mscorlib, "mono_helper_ldstr_mscorlib", "object int", FALSE);
+	register_icall (mono_helper_newobj_mscorlib, "mono_helper_newobj_mscorlib", "object int", FALSE);
 	register_icall (mono_value_copy, "mono_value_copy", "void ptr ptr ptr", FALSE);
 	register_icall (mono_value_copy, "mono_value_copy", "void ptr ptr ptr", FALSE);
 	register_icall (mono_object_castclass, "mono_object_castclass", "object object ptr", FALSE);
 	register_icall (mono_object_castclass, "mono_object_castclass", "object object ptr", FALSE);
 	register_icall (mono_break, "mono_break", NULL, TRUE);
 	register_icall (mono_break, "mono_break", NULL, TRUE);