+ /* Emit the globals table */
+ sprintf (symbol, "globals");
+ emit_section_change (acfg, ".data", 0);
+ /* This is not a global, since it is accessed by the init function */
+ emit_alignment (acfg, 8);
+ emit_label (acfg, symbol);
+
+ for (i = 0; i < acfg->globals->len; ++i) {
+ char *name = g_ptr_array_index (acfg->globals, i);
+
+ sprintf (symbol, "name_%d", i);
+ emit_pointer (acfg, symbol);
+
+ sprintf (symbol, "%s", name);
+ emit_pointer (acfg, symbol);
+ }
+ /* Null terminate the table */
+ emit_int32 (acfg, 0);
+ emit_int32 (acfg, 0);
+
+ /*
+ * Emit a global symbol which can be passed by an embedding app to
+ * mono_aot_register_module ().
+ */
+#if defined(__MACH__)
+ sprintf (symbol, "_mono_aot_module_%s_info", acfg->image->assembly->aname.name);
+#else
+ sprintf (symbol, "mono_aot_module_%s_info", acfg->image->assembly->aname.name);
+#endif
+
+ /* Get rid of characters which cannot occur in symbols */
+ p = symbol;
+ for (p = symbol; *p; ++p) {
+ if (!(isalnum (*p) || *p == '_'))
+ *p = '_';
+ }
+ acfg->static_linking_symbol = g_strdup (symbol);
+ emit_global_inner (acfg, symbol, FALSE);
+ emit_alignment (acfg, 8);
+ emit_label (acfg, symbol);
+ emit_pointer (acfg, "globals");
+ }
+}
+
+static void
+emit_mem_end (MonoAotCompile *acfg)
+{
+ char symbol [128];
+
+ sprintf (symbol, "mem_end");
+ emit_section_change (acfg, ".text", 1);
+ emit_global (acfg, symbol, FALSE);
+ emit_alignment (acfg, 8);
+ emit_label (acfg, symbol);
+}
+
+/*
+ * Emit a structure containing all the information not stored elsewhere.
+ */
+static void
+emit_file_info (MonoAotCompile *acfg)
+{
+ char symbol [128];
+ int i;
+
+ sprintf (symbol, "mono_aot_file_info");
+ emit_section_change (acfg, ".data", 0);
+ emit_alignment (acfg, 8);
+ emit_label (acfg, symbol);
+ emit_global (acfg, symbol, FALSE);
+
+ /* The data emitted here must match MonoAotFileInfo in aot-runtime.c. */
+ emit_int32 (acfg, acfg->plt_got_offset_base);
+ emit_int32 (acfg, (int)(acfg->got_offset * sizeof (gpointer)));
+ emit_int32 (acfg, acfg->plt_offset);
+
+ for (i = 0; i < MONO_AOT_TRAMP_NUM; ++i)
+ emit_int32 (acfg, acfg->num_trampolines [i]);
+ for (i = 0; i < MONO_AOT_TRAMP_NUM; ++i)
+ emit_int32 (acfg, acfg->trampoline_got_offset_base [i]);
+ for (i = 0; i < MONO_AOT_TRAMP_NUM; ++i)
+ emit_int32 (acfg, acfg->trampoline_size [i]);
+}
+
+static void
+emit_dwarf_info (MonoAotCompile *acfg)
+{
+#ifdef EMIT_DWARF_INFO
+ int i;
+ char symbol [128], symbol2 [128];
+
+ /* DIEs for methods */
+ for (i = 0; i < acfg->nmethods; ++i) {
+ MonoCompile *cfg = acfg->cfgs [i];
+
+ if (!cfg)
+ continue;
+
+ sprintf (symbol, ".Lm_%x", i);
+ sprintf (symbol2, ".Lme_%x", i);
+
+ mono_dwarf_writer_emit_method (acfg->dwarf, cfg, cfg->method, symbol, symbol2, NULL, 0, cfg->args, cfg->locals, cfg->unwind_ops, NULL);
+ }
+#endif
+}
+
+static void
+collect_methods (MonoAotCompile *acfg)
+{
+ int i;
+ MonoImage *image = acfg->image;
+
+ /* Collect methods */
+ for (i = 0; i < image->tables [MONO_TABLE_METHOD].rows; ++i) {
+ MonoMethod *method;
+ guint32 token = MONO_TOKEN_METHOD_DEF | (i + 1);
+
+ method = mono_get_method (acfg->image, token, NULL);
+
+ if (!method) {
+ printf ("Failed to load method 0x%x from '%s'.\n", token, image->name);
+ exit (1);
+ }
+
+ /* Load all methods eagerly to skip the slower lazy loading code */
+ mono_class_setup_methods (method->klass);
+
+ if (acfg->aot_opts.full_aot && method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
+ /* Compile the wrapper instead */
+ /* We do this here instead of add_wrappers () because it is easy to do it here */
+ MonoMethod *wrapper = mono_marshal_get_native_wrapper (method, check_for_pending_exc, TRUE);
+ method = wrapper;
+ }
+
+ /* Since we add the normal methods first, their index will be equal to their zero based token index */
+ add_method_with_index (acfg, method, i);
+ acfg->method_index ++;
+ }
+
+ add_generic_instances (acfg);
+
+ if (acfg->aot_opts.full_aot)
+ add_wrappers (acfg);
+}
+
+static void
+compile_methods (MonoAotCompile *acfg)
+{
+ int i, methods_len;
+
+ if (acfg->aot_opts.nthreads > 0) {
+ GPtrArray *frag;
+ int len, j;
+ GPtrArray *threads;
+ HANDLE handle;
+ gpointer *user_data;
+ MonoMethod **methods;
+
+ methods_len = acfg->methods->len;
+
+ len = acfg->methods->len / acfg->aot_opts.nthreads;
+ g_assert (len > 0);
+ /*
+ * Partition the list of methods into fragments, and hand it to threads to
+ * process.
+ */
+ threads = g_ptr_array_new ();
+ /* Make a copy since acfg->methods is modified by compile_method () */
+ methods = g_new0 (MonoMethod*, methods_len);
+ //memcpy (methods, g_ptr_array_index (acfg->methods, 0), sizeof (MonoMethod*) * methods_len);
+ for (i = 0; i < methods_len; ++i)
+ methods [i] = g_ptr_array_index (acfg->methods, i);
+ i = 0;
+ while (i < methods_len) {
+ frag = g_ptr_array_new ();
+ for (j = 0; j < len; ++j) {
+ if (i < methods_len) {
+ g_ptr_array_add (frag, methods [i]);
+ i ++;
+ }
+ }
+
+ user_data = g_new0 (gpointer, 3);
+ user_data [0] = mono_domain_get ();
+ user_data [1] = acfg;
+ user_data [2] = frag;
+
+ handle = mono_create_thread (NULL, 0, (gpointer)compile_thread_main, user_data, 0, NULL);
+ g_ptr_array_add (threads, handle);
+ }
+ g_free (methods);
+
+ for (i = 0; i < threads->len; ++i) {
+ WaitForSingleObjectEx (g_ptr_array_index (threads, i), INFINITE, FALSE);
+ }
+ } else {
+ methods_len = 0;
+ }
+
+ /* Compile methods added by compile_method () or all methods if nthreads == 0 */
+ for (i = methods_len; i < acfg->methods->len; ++i) {
+ /* This can new methods to acfg->methods */
+ compile_method (acfg, g_ptr_array_index (acfg->methods, i));
+ }
+}
+
+static int
+compile_asm (MonoAotCompile *acfg)
+{
+ char *command, *objfile;
+ char *outfile_name, *tmp_outfile_name;
+
+#if defined(TARGET_AMD64)
+#define AS_OPTIONS "--64"
+#elif defined(sparc) && SIZEOF_VOID_P == 8
+#define AS_OPTIONS "-xarch=v9"
+#else
+#define AS_OPTIONS ""
+#endif
+
+ if (acfg->aot_opts.asm_only) {
+ printf ("Output file: '%s'.\n", acfg->tmpfname);
+ if (acfg->aot_opts.static_link)
+ printf ("Linking symbol: '%s'.\n", acfg->static_linking_symbol);
+ return 0;
+ }
+
+ if (acfg->aot_opts.static_link) {
+ if (acfg->aot_opts.outfile)
+ objfile = g_strdup_printf ("%s", acfg->aot_opts.outfile);
+ else
+ objfile = g_strdup_printf ("%s.o", acfg->image->name);
+ } else {
+ objfile = g_strdup_printf ("%s.o", acfg->tmpfname);
+ }
+ command = g_strdup_printf ("as %s %s -o %s", AS_OPTIONS, acfg->tmpfname, objfile);
+ printf ("Executing the native assembler: %s\n", command);
+ if (system (command) != 0) {
+ g_free (command);
+ g_free (objfile);
+ return 1;
+ }
+
+ g_free (command);
+
+ if (acfg->aot_opts.static_link) {
+ printf ("Output file: '%s'.\n", objfile);
+ printf ("Linking symbol: '%s'.\n", acfg->static_linking_symbol);
+ g_free (objfile);
+ return 0;
+ }
+
+ if (acfg->aot_opts.outfile)
+ outfile_name = g_strdup_printf ("%s", acfg->aot_opts.outfile);
+ else
+ outfile_name = g_strdup_printf ("%s%s", acfg->image->name, SHARED_EXT);
+
+ tmp_outfile_name = g_strdup_printf ("%s.tmp", outfile_name);
+
+#if defined(sparc)
+ command = g_strdup_printf ("ld -shared -G -o %s %s.o", tmp_outfile_name, acfg->tmpfname);
+#elif defined(__ppc__) && defined(__MACH__)
+ command = g_strdup_printf ("gcc -dynamiclib -o %s %s.o", tmp_outfile_name, acfg->tmpfname);
+#elif defined(PLATFORM_WIN32)
+ command = g_strdup_printf ("gcc -shared --dll -mno-cygwin -o %s %s.o", tmp_outfile_name, acfg->tmpfname);
+#else
+ command = g_strdup_printf ("ld -shared -o %s %s.o", tmp_outfile_name, acfg->tmpfname);
+#endif
+ printf ("Executing the native linker: %s\n", command);
+ if (system (command) != 0) {
+ g_free (tmp_outfile_name);
+ g_free (outfile_name);
+ g_free (command);
+ g_free (objfile);
+ return 1;
+ }
+
+ g_free (command);
+ unlink (objfile);
+ /*com = g_strdup_printf ("strip --strip-unneeded %s%s", acfg->image->name, SHARED_EXT);
+ printf ("Stripping the binary: %s\n", com);
+ system (com);
+ g_free (com);*/