1 /**
2 * \file
3 * mono Ahead of Time compiler
4 *
5 * Author:
6 * Dietmar Maurer (dietmar@ximian.com)
7 * Zoltan Varga (vargaz@gmail.com)
8 * Johan Lorensson (lateralusx.github@gmail.com)
9 *
10 * (C) 2002 Ximian, Inc.
11 * Copyright 2003-2011 Novell, Inc
12 * Copyright 2011 Xamarin Inc (http://www.xamarin.com)
13 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
14 */
15
16 #include "config.h"
17 #include <sys/types.h>
18 #ifdef HAVE_UNISTD_H
19 #include <unistd.h>
20 #endif
21 #ifdef HAVE_STDINT_H
22 #include <stdint.h>
23 #endif
24 #include <fcntl.h>
25 #include <ctype.h>
26 #include <string.h>
27 #ifndef HOST_WIN32
28 #include <sys/time.h>
29 #else
30 #include <winsock2.h>
31 #include <windows.h>
32 #endif
33
34 #include <errno.h>
35 #include <sys/stat.h>
36
37 #include <mono/metadata/abi-details.h>
38 #include <mono/metadata/tabledefs.h>
39 #include <mono/metadata/class.h>
40 #include <mono/metadata/object.h>
41 #include <mono/metadata/tokentype.h>
42 #include <mono/metadata/appdomain.h>
43 #include <mono/metadata/debug-helpers.h>
44 #include <mono/metadata/assembly.h>
45 #include <mono/metadata/metadata-internals.h>
46 #include <mono/metadata/reflection-internals.h>
47 #include <mono/metadata/marshal.h>
48 #include <mono/metadata/gc-internals.h>
49 #include <mono/metadata/mempool-internals.h>
50 #include <mono/metadata/mono-endian.h>
51 #include <mono/metadata/threads-types.h>
52 #include <mono/metadata/custom-attrs-internals.h>
53 #include <mono/utils/mono-logger-internals.h>
54 #include <mono/utils/mono-compiler.h>
55 #include <mono/utils/mono-time.h>
56 #include <mono/utils/mono-mmap.h>
57 #include <mono/utils/mono-rand.h>
58 #include <mono/utils/json.h>
59 #include <mono/utils/mono-threads-coop.h>
60 #include <mono/profiler/aot.h>
61 #include <mono/utils/w32api.h>
62
63 #include "aot-compiler.h"
64 #include "aot-runtime.h"
65 #include "seq-points.h"
66 #include "image-writer.h"
67 #include "dwarfwriter.h"
68 #include "mini-gc.h"
69 #include "mini-llvm.h"
70 #include "mini-runtime.h"
71
72 #if !defined(DISABLE_AOT) && !defined(DISABLE_JIT)
73
74 // Use MSVC toolchain, Clang for MSVC using MSVC codegen and linker, when compiling for AMD64
75 // targeting WIN32 platforms running AOT compiler on WIN32 platform with VS installation.
76 #if defined(TARGET_AMD64) && defined(TARGET_WIN32) && defined(HOST_WIN32) && defined(_MSC_VER)
77 #define TARGET_X86_64_WIN32_MSVC
78 #endif
79
80 #if defined(TARGET_X86_64_WIN32_MSVC)
81 #define TARGET_WIN32_MSVC
82 #endif
83
84 // Emit native unwind info on Windows platforms (different from DWARF). Emitted unwind info
85 // works when using the MSVC toolchain using Clang for MSVC codegen and linker. Only supported when
86 // compiling for AMD64 (Windows x64 platforms).
87 #if defined(TARGET_WIN32_MSVC) && defined(MONO_ARCH_HAVE_UNWIND_TABLE)
88 #define EMIT_WIN32_UNWIND_INFO
89 #endif
90
91 #if defined(__linux__)
92 #define RODATA_SECT ".rodata"
93 #elif defined(TARGET_MACH)
94 #define RODATA_SECT ".section __TEXT, __const"
95 #elif defined(TARGET_WIN32_MSVC)
96 #define RODATA_SECT ".rdata"
97 #else
98 #define RODATA_SECT ".text"
99 #endif
100
101 #define TV_DECLARE(name) gint64 name
102 #define TV_GETTIME(tv) tv = mono_100ns_ticks ()
103 #define TV_ELAPSED(start,end) (((end) - (start)) / 10)
104
105 #define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1))
106 #define ALIGN_PTR_TO(ptr,align) (gpointer)((((gssize)(ptr)) + (align - 1)) & (~(align - 1)))
107 #define ROUND_DOWN(VALUE,SIZE) ((VALUE) & ~((SIZE) - 1))
108
109 typedef struct {
110 char *name;
111 MonoImage *image;
112 } ImageProfileData;
113
114 typedef struct ClassProfileData ClassProfileData;
115
116 typedef struct {
117 int argc;
118 ClassProfileData **argv;
119 MonoGenericInst *inst;
120 } GInstProfileData;
121
122 struct ClassProfileData {
123 ImageProfileData *image;
124 char *ns, *name;
125 GInstProfileData *inst;
126 MonoClass *klass;
127 };
128
129 typedef struct {
130 ClassProfileData *klass;
131 int id;
132 char *name;
133 int param_count;
134 char *signature;
135 GInstProfileData *inst;
136 MonoMethod *method;
137 } MethodProfileData;
138
139 typedef struct {
140 GHashTable *images, *classes, *ginsts, *methods;
141 } ProfileData;
142
143 /* predefined values for static readonly fields without needed to run the .cctor */
144 typedef struct _ReadOnlyValue ReadOnlyValue;
145 struct _ReadOnlyValue {
146 ReadOnlyValue *next;
147 char *name;
148 int type; /* to be used later for typechecking to prevent user errors */
149 union {
150 guint8 i1;
151 guint16 i2;
152 guint32 i4;
153 guint64 i8;
154 gpointer ptr;
155 } value;
156 };
157 static ReadOnlyValue *readonly_values;
158
159 typedef struct MonoAotOptions {
160 char *outfile;
161 char *llvm_outfile;
162 char *data_outfile;
163 GList *profile_files;
164 gboolean save_temps;
165 gboolean write_symbols;
166 gboolean metadata_only;
167 gboolean bind_to_runtime_version;
168 MonoAotMode mode;
169 gboolean no_dlsym;
170 gboolean static_link;
171 gboolean asm_only;
172 gboolean asm_writer;
173 gboolean nodebug;
174 gboolean dwarf_debug;
175 gboolean soft_debug;
176 gboolean log_generics;
177 gboolean log_instances;
178 gboolean gen_msym_dir;
179 char *gen_msym_dir_path;
180 gboolean direct_pinvoke;
181 gboolean direct_icalls;
182 gboolean no_direct_calls;
183 gboolean use_trampolines_page;
184 gboolean no_instances;
185 // We are collecting inflated methods and emitting non-inflated
186 gboolean dedup;
187 // The name of the assembly for which the AOT module is going to have all deduped methods moved to.
188 // When set, we are emitting inflated methods only
189 char *dedup_include;
190 gboolean gnu_asm;
191 gboolean llvm;
192 gboolean llvm_only;
193 int nthreads;
194 int ntrampolines;
195 int nrgctx_trampolines;
196 int nimt_trampolines;
197 int ngsharedvt_arg_trampolines;
198 int nrgctx_fetch_trampolines;
199 gboolean print_skipped_methods;
200 gboolean stats;
201 gboolean verbose;
202 char *tool_prefix;
203 char *ld_flags;
204 char *mtriple;
205 char *llvm_path;
206 char *temp_path;
207 char *instances_logfile_path;
208 char *logfile;
209 gboolean dump_json;
210 gboolean profile_only;
211 } MonoAotOptions;
212
213 typedef enum {
214 METHOD_CAT_NORMAL,
215 METHOD_CAT_GSHAREDVT,
216 METHOD_CAT_INST,
217 METHOD_CAT_WRAPPER,
218 METHOD_CAT_NUM
219 } MethodCategory;
220
221 typedef struct MonoAotStats {
222 int ccount, mcount, lmfcount, abscount, gcount, ocount, genericcount;
223 gint64 code_size, info_size, ex_info_size, unwind_info_size, got_size, class_info_size, got_info_size, plt_size;
224 int methods_without_got_slots, direct_calls, all_calls, llvm_count;
225 int got_slots, offsets_size;
226 int method_categories [METHOD_CAT_NUM];
227 int got_slot_types [MONO_PATCH_INFO_NUM];
228 int got_slot_info_sizes [MONO_PATCH_INFO_NUM];
229 int jit_time, gen_time, link_time;
230 } MonoAotStats;
231
232 typedef struct GotInfo {
233 GHashTable *patch_to_got_offset;
234 GHashTable **patch_to_got_offset_by_type;
235 GPtrArray *got_patches;
236 } GotInfo;
237
238 #ifdef EMIT_WIN32_UNWIND_INFO
239 typedef struct _UnwindInfoSectionCacheItem {
240 char *xdata_section_label;
241 PUNWIND_INFO unwind_info;
242 gboolean xdata_section_emitted;
243 } UnwindInfoSectionCacheItem;
244 #endif
245
246 typedef struct MonoAotCompile {
247 MonoImage *image;
248 GPtrArray *methods;
249 GHashTable *method_indexes;
250 GHashTable *method_depth;
251 MonoCompile **cfgs;
252 int cfgs_size;
253 GHashTable **patch_to_plt_entry;
254 GHashTable *plt_offset_to_entry;
255 //GHashTable *patch_to_got_offset;
256 //GHashTable **patch_to_got_offset_by_type;
257 //GPtrArray *got_patches;
258 GotInfo got_info, llvm_got_info;
259 GHashTable *image_hash;
260 GHashTable *method_to_cfg;
261 GHashTable *token_info_hash;
262 GHashTable *method_to_pinvoke_import;
263 GPtrArray *extra_methods;
264 GPtrArray *image_table;
265 GPtrArray *globals;
266 GPtrArray *method_order;
267 GHashTable *dedup_stats;
268 GHashTable *dedup_cache;
269 gboolean dedup_cache_changed;
270 GHashTable *export_names;
271 /* Maps MonoClass* -> blob offset */
272 GHashTable *klass_blob_hash;
273 /* Maps MonoMethod* -> blob offset */
274 GHashTable *method_blob_hash;
275 GHashTable *gsharedvt_in_signatures;
276 GHashTable *gsharedvt_out_signatures;
277 guint32 *plt_got_info_offsets;
278 guint32 got_offset, llvm_got_offset, plt_offset, plt_got_offset_base, nshared_got_entries;
279 /* Number of GOT entries reserved for trampolines */
280 guint32 num_trampoline_got_entries;
281 guint32 tramp_page_size;
282
283 guint32 table_offsets [MONO_AOT_TABLE_NUM];
284 guint32 num_trampolines [MONO_AOT_TRAMP_NUM];
285 guint32 trampoline_got_offset_base [MONO_AOT_TRAMP_NUM];
286 guint32 trampoline_size [MONO_AOT_TRAMP_NUM];
287 guint32 tramp_page_code_offsets [MONO_AOT_TRAMP_NUM];
288
289 MonoAotOptions aot_opts;
290 guint32 nmethods;
291 guint32 opts;
292 guint32 simd_opts;
293 MonoMemPool *mempool;
294 MonoAotStats stats;
295 int method_index;
296 char *static_linking_symbol;
297 mono_mutex_t mutex;
298 gboolean gas_line_numbers;
299 /* Whenever to emit an object file directly from llc */
300 gboolean llvm_owriter;
301 gboolean llvm_owriter_supported;
302 MonoImageWriter *w;
303 MonoDwarfWriter *dwarf;
304 FILE *fp;
305 char *tmpbasename;
306 char *tmpfname;
307 char *llvm_sfile;
308 char *llvm_ofile;
309 GSList *cie_program;
310 GHashTable *unwind_info_offsets;
311 GPtrArray *unwind_ops;
312 guint32 unwind_info_offset;
313 char *global_prefix;
314 char *got_symbol;
315 char *llvm_got_symbol;
316 char *plt_symbol;
317 char *llvm_eh_frame_symbol;
318 GHashTable *method_label_hash;
319 const char *temp_prefix;
320 const char *user_symbol_prefix;
321 const char *llvm_label_prefix;
322 const char *inst_directive;
323 int align_pad_value;
324 guint32 label_generator;
325 gboolean llvm;
326 gboolean has_jitted_code;
327 gboolean is_full_aot;
328 MonoAotFileFlags flags;
329 MonoDynamicStream blob;
330 gboolean blob_closed;
331 GHashTable *typespec_classes;
332 GString *llc_args;
333 GString *as_args;
334 char *assembly_name_sym;
335 GHashTable *plt_entry_debug_sym_cache;
336 gboolean thumb_mixed, need_no_dead_strip, need_pt_gnu_stack;
337 GHashTable *ginst_hash;
338 GHashTable *dwarf_ln_filenames;
339 gboolean global_symbols;
340 int objc_selector_index, objc_selector_index_2;
341 GPtrArray *objc_selectors;
342 GHashTable *objc_selector_to_index;
343 GList *profile_data;
344 GHashTable *profile_methods;
345 #ifdef EMIT_WIN32_UNWIND_INFO
346 GList *unwind_info_section_cache;
347 #endif
348 FILE *logfile;
349 FILE *instances_logfile;
350 FILE *data_outfile;
351 int datafile_offset;
352 int gc_name_offset;
353 // In this mode, we are emitting dedupable methods that we encounter
354 gboolean dedup_emit_mode;
355 } MonoAotCompile;
356
357 typedef struct {
358 int plt_offset;
359 char *symbol, *llvm_symbol, *debug_sym;
360 MonoJumpInfo *ji;
361 gboolean jit_used, llvm_used;
362 } MonoPltEntry;
363
364 #define mono_acfg_lock(acfg) mono_os_mutex_lock (&((acfg)->mutex))
365 #define mono_acfg_unlock(acfg) mono_os_mutex_unlock (&((acfg)->mutex))
366
367 /* This points to the current acfg in LLVM mode */
368 static MonoAotCompile *llvm_acfg;
369
370 #ifdef HAVE_ARRAY_ELEM_INIT
371 #define MSGSTRFIELD(line) MSGSTRFIELD1(line)
372 #define MSGSTRFIELD1(line) str##line
373 static const struct msgstr_t {
374 #define PATCH_INFO(a,b) char MSGSTRFIELD(__LINE__) [sizeof (b)];
375 #include "patch-info.h"
376 #undef PATCH_INFO
377 } opstr = {
378 #define PATCH_INFO(a,b) b,
379 #include "patch-info.h"
380 #undef PATCH_INFO
381 };
382 static const gint16 opidx [] = {
383 #define PATCH_INFO(a,b) [MONO_PATCH_INFO_ ## a] = offsetof (struct msgstr_t, MSGSTRFIELD(__LINE__)),
384 #include "patch-info.h"
385 #undef PATCH_INFO
386 };
387
388 static G_GNUC_UNUSED const char*
get_patch_name(int info)389 get_patch_name (int info)
390 {
391 return (const char*)&opstr + opidx [info];
392 }
393
394 #else
395 #define PATCH_INFO(a,b) b,
396 static const char* const
397 patch_types [MONO_PATCH_INFO_NUM + 1] = {
398 #include "patch-info.h"
399 NULL
400 };
401
402 static G_GNUC_UNUSED const char*
get_patch_name(int info)403 get_patch_name (int info)
404 {
405 return patch_types [info];
406 }
407
408 #endif
409
410 static void
411 mono_flush_method_cache (MonoAotCompile *acfg);
412
413 static void
414 mono_read_method_cache (MonoAotCompile *acfg);
415
416 static guint32
417 get_unwind_info_offset (MonoAotCompile *acfg, guint8 *encoded, guint32 encoded_len);
418
419 static char*
420 get_plt_entry_debug_sym (MonoAotCompile *acfg, MonoJumpInfo *ji, GHashTable *cache);
421
422 static void
423 add_gsharedvt_wrappers (MonoAotCompile *acfg, MonoMethodSignature *sig, gboolean gsharedvt_in, gboolean gsharedvt_out);
424
425 static void
426 add_profile_instances (MonoAotCompile *acfg, ProfileData *data);
427
428 static inline gboolean
ignore_cfg(MonoCompile * cfg)429 ignore_cfg (MonoCompile *cfg)
430 {
431 return !cfg || cfg->skip;
432 }
433
434 static void
aot_printf(MonoAotCompile * acfg,const gchar * format,...)435 aot_printf (MonoAotCompile *acfg, const gchar *format, ...)
436 {
437 FILE *output;
438 va_list args;
439
440 if (acfg->logfile)
441 output = acfg->logfile;
442 else
443 output = stdout;
444
445 va_start (args, format);
446 vfprintf (output, format, args);
447 va_end (args);
448 }
449
450 static void
aot_printerrf(MonoAotCompile * acfg,const gchar * format,...)451 aot_printerrf (MonoAotCompile *acfg, const gchar *format, ...)
452 {
453 FILE *output;
454 va_list args;
455
456 if (acfg->logfile)
457 output = acfg->logfile;
458 else
459 output = stderr;
460
461 va_start (args, format);
462 vfprintf (output, format, args);
463 va_end (args);
464 }
465
466 static void
report_loader_error(MonoAotCompile * acfg,MonoError * error,gboolean fatal,const char * format,...)467 report_loader_error (MonoAotCompile *acfg, MonoError *error, gboolean fatal, const char *format, ...)
468 {
469 FILE *output;
470 va_list args;
471
472 if (mono_error_ok (error))
473 return;
474
475 if (acfg->logfile)
476 output = acfg->logfile;
477 else
478 output = stderr;
479
480 va_start (args, format);
481 vfprintf (output, format, args);
482 va_end (args);
483 mono_error_cleanup (error);
484
485 if (acfg->is_full_aot && fatal) {
486 fprintf (output, "FullAOT cannot continue if there are loader errors.\n");
487 exit (1);
488 }
489 }
490
491 /* Wrappers around the image writer functions */
492
493 #define MAX_SYMBOL_SIZE 256
494
495 static inline const char *
mangle_symbol(const char * symbol,char * mangled_symbol,gsize length)496 mangle_symbol (const char * symbol, char * mangled_symbol, gsize length)
497 {
498 gsize needed_size = length;
499
500 g_assert (NULL != symbol);
501 g_assert (NULL != mangled_symbol);
502 g_assert (0 != length);
503
504 #if defined(TARGET_WIN32) && defined(TARGET_X86)
505 if (symbol && '_' != symbol [0]) {
506 needed_size = g_snprintf (mangled_symbol, length, "_%s", symbol);
507 } else {
508 needed_size = g_snprintf (mangled_symbol, length, "%s", symbol);
509 }
510 #else
511 needed_size = g_snprintf (mangled_symbol, length, "%s", symbol);
512 #endif
513
514 g_assert (0 <= needed_size && needed_size < length);
515 return mangled_symbol;
516 }
517
518 static inline char *
mangle_symbol_alloc(const char * symbol)519 mangle_symbol_alloc (const char * symbol)
520 {
521 g_assert (NULL != symbol);
522
523 #if defined(TARGET_WIN32) && defined(TARGET_X86)
524 if (symbol && '_' != symbol [0]) {
525 return g_strdup_printf ("_%s", symbol);
526 }
527 else {
528 return g_strdup_printf ("%s", symbol);
529 }
530 #else
531 return g_strdup_printf ("%s", symbol);
532 #endif
533 }
534
535 static inline void
emit_section_change(MonoAotCompile * acfg,const char * section_name,int subsection_index)536 emit_section_change (MonoAotCompile *acfg, const char *section_name, int subsection_index)
537 {
538 mono_img_writer_emit_section_change (acfg->w, section_name, subsection_index);
539 }
540
541 #if defined(TARGET_WIN32) && defined(TARGET_X86)
542
543 static inline void
emit_local_symbol(MonoAotCompile * acfg,const char * name,const char * end_label,gboolean func)544 emit_local_symbol (MonoAotCompile *acfg, const char *name, const char *end_label, gboolean func)
545 {
546 const char * mangled_symbol_name = name;
547 char * mangled_symbol_name_alloc = NULL;
548
549 if (TRUE == func) {
550 mangled_symbol_name_alloc = mangle_symbol_alloc (name);
551 mangled_symbol_name = mangled_symbol_name_alloc;
552 }
553
554 if (name != mangled_symbol_name && 0 != g_strcasecmp (name, mangled_symbol_name)) {
555 mono_img_writer_emit_label (acfg->w, mangled_symbol_name);
556 }
557 mono_img_writer_emit_local_symbol (acfg->w, mangled_symbol_name, end_label, func);
558
559 if (NULL != mangled_symbol_name_alloc) {
560 g_free (mangled_symbol_name_alloc);
561 }
562 }
563
564 #else
565
566 static inline void
emit_local_symbol(MonoAotCompile * acfg,const char * name,const char * end_label,gboolean func)567 emit_local_symbol (MonoAotCompile *acfg, const char *name, const char *end_label, gboolean func)
568 {
569 mono_img_writer_emit_local_symbol (acfg->w, name, end_label, func);
570 }
571
572 #endif
573
574 static inline void
emit_label(MonoAotCompile * acfg,const char * name)575 emit_label (MonoAotCompile *acfg, const char *name)
576 {
577 mono_img_writer_emit_label (acfg->w, name);
578 }
579
580 static inline void
emit_bytes(MonoAotCompile * acfg,const guint8 * buf,int size)581 emit_bytes (MonoAotCompile *acfg, const guint8* buf, int size)
582 {
583 mono_img_writer_emit_bytes (acfg->w, buf, size);
584 }
585
586 static inline void
emit_string(MonoAotCompile * acfg,const char * value)587 emit_string (MonoAotCompile *acfg, const char *value)
588 {
589 mono_img_writer_emit_string (acfg->w, value);
590 }
591
592 static inline void
emit_line(MonoAotCompile * acfg)593 emit_line (MonoAotCompile *acfg)
594 {
595 mono_img_writer_emit_line (acfg->w);
596 }
597
598 static inline void
emit_alignment(MonoAotCompile * acfg,int size)599 emit_alignment (MonoAotCompile *acfg, int size)
600 {
601 mono_img_writer_emit_alignment (acfg->w, size);
602 }
603
604 static inline void
emit_alignment_code(MonoAotCompile * acfg,int size)605 emit_alignment_code (MonoAotCompile *acfg, int size)
606 {
607 if (acfg->align_pad_value)
608 mono_img_writer_emit_alignment_fill (acfg->w, size, acfg->align_pad_value);
609 else
610 mono_img_writer_emit_alignment (acfg->w, size);
611 }
612
613 static inline void
emit_padding(MonoAotCompile * acfg,int size)614 emit_padding (MonoAotCompile *acfg, int size)
615 {
616 int i;
617 guint8 buf [16];
618
619 if (acfg->align_pad_value) {
620 for (i = 0; i < 16; ++i)
621 buf [i] = acfg->align_pad_value;
622 } else {
623 memset (buf, 0, sizeof (buf));
624 }
625
626 for (i = 0; i < size; i += 16) {
627 if (size - i < 16)
628 emit_bytes (acfg, buf, size - i);
629 else
630 emit_bytes (acfg, buf, 16);
631 }
632 }
633
634 static inline void
emit_pointer(MonoAotCompile * acfg,const char * target)635 emit_pointer (MonoAotCompile *acfg, const char *target)
636 {
637 mono_img_writer_emit_pointer (acfg->w, target);
638 }
639
640 static inline void
emit_pointer_2(MonoAotCompile * acfg,const char * prefix,const char * target)641 emit_pointer_2 (MonoAotCompile *acfg, const char *prefix, const char *target)
642 {
643 if (prefix [0] != '\0') {
644 char *s = g_strdup_printf ("%s%s", prefix, target);
645 mono_img_writer_emit_pointer (acfg->w, s);
646 g_free (s);
647 } else {
648 mono_img_writer_emit_pointer (acfg->w, target);
649 }
650 }
651
652 static inline void
emit_int16(MonoAotCompile * acfg,int value)653 emit_int16 (MonoAotCompile *acfg, int value)
654 {
655 mono_img_writer_emit_int16 (acfg->w, value);
656 }
657
658 static inline void
emit_int32(MonoAotCompile * acfg,int value)659 emit_int32 (MonoAotCompile *acfg, int value)
660 {
661 mono_img_writer_emit_int32 (acfg->w, value);
662 }
663
664 static inline void
emit_symbol_diff(MonoAotCompile * acfg,const char * end,const char * start,int offset)665 emit_symbol_diff (MonoAotCompile *acfg, const char *end, const char* start, int offset)
666 {
667 mono_img_writer_emit_symbol_diff (acfg->w, end, start, offset);
668 }
669
670 static inline void
emit_zero_bytes(MonoAotCompile * acfg,int num)671 emit_zero_bytes (MonoAotCompile *acfg, int num)
672 {
673 mono_img_writer_emit_zero_bytes (acfg->w, num);
674 }
675
676 static inline void
emit_byte(MonoAotCompile * acfg,guint8 val)677 emit_byte (MonoAotCompile *acfg, guint8 val)
678 {
679 mono_img_writer_emit_byte (acfg->w, val);
680 }
681
682 #if defined(TARGET_WIN32) && defined(TARGET_X86)
683
684 static G_GNUC_UNUSED void
emit_global_inner(MonoAotCompile * acfg,const char * name,gboolean func)685 emit_global_inner (MonoAotCompile *acfg, const char *name, gboolean func)
686 {
687 const char * mangled_symbol_name = name;
688 char * mangled_symbol_name_alloc = NULL;
689
690 mangled_symbol_name_alloc = mangle_symbol_alloc (name);
691 mangled_symbol_name = mangled_symbol_name_alloc;
692
693 if (0 != g_strcasecmp (name, mangled_symbol_name)) {
694 mono_img_writer_emit_label (acfg->w, mangled_symbol_name);
695 }
696 mono_img_writer_emit_global (acfg->w, mangled_symbol_name, func);
697
698 if (NULL != mangled_symbol_name_alloc) {
699 g_free (mangled_symbol_name_alloc);
700 }
701 }
702
703 #else
704
705 static G_GNUC_UNUSED void
emit_global_inner(MonoAotCompile * acfg,const char * name,gboolean func)706 emit_global_inner (MonoAotCompile *acfg, const char *name, gboolean func)
707 {
708 mono_img_writer_emit_global (acfg->w, name, func);
709 }
710
711 #endif
712
713 static inline gboolean
link_shared_library(MonoAotCompile * acfg)714 link_shared_library (MonoAotCompile *acfg)
715 {
716 return !acfg->aot_opts.static_link && !acfg->aot_opts.asm_only;
717 }
718
719 static inline gboolean
add_to_global_symbol_table(MonoAotCompile * acfg)720 add_to_global_symbol_table (MonoAotCompile *acfg)
721 {
722 #ifdef TARGET_WIN32_MSVC
723 return acfg->aot_opts.no_dlsym || link_shared_library (acfg);
724 #else
725 return acfg->aot_opts.no_dlsym;
726 #endif
727 }
728
729 static void
emit_global(MonoAotCompile * acfg,const char * name,gboolean func)730 emit_global (MonoAotCompile *acfg, const char *name, gboolean func)
731 {
732 if (add_to_global_symbol_table (acfg))
733 g_ptr_array_add (acfg->globals, g_strdup (name));
734
735 if (acfg->aot_opts.no_dlsym) {
736 mono_img_writer_emit_local_symbol (acfg->w, name, NULL, func);
737 } else {
738 emit_global_inner (acfg, name, func);
739 }
740 }
741
742 static void
emit_symbol_size(MonoAotCompile * acfg,const char * name,const char * end_label)743 emit_symbol_size (MonoAotCompile *acfg, const char *name, const char *end_label)
744 {
745 mono_img_writer_emit_symbol_size (acfg->w, name, end_label);
746 }
747
748 /* Emit a symbol which is referenced by the MonoAotFileInfo structure */
749 static void
emit_info_symbol(MonoAotCompile * acfg,const char * name)750 emit_info_symbol (MonoAotCompile *acfg, const char *name)
751 {
752 char symbol [MAX_SYMBOL_SIZE];
753
754 if (acfg->llvm) {
755 emit_label (acfg, name);
756 /* LLVM generated code references this */
757 sprintf (symbol, "%s%s%s", acfg->user_symbol_prefix, acfg->global_prefix, name);
758 emit_label (acfg, symbol);
759 emit_global_inner (acfg, symbol, FALSE);
760 } else {
761 emit_label (acfg, name);
762 }
763 }
764
765 static void
emit_string_symbol(MonoAotCompile * acfg,const char * name,const char * value)766 emit_string_symbol (MonoAotCompile *acfg, const char *name, const char *value)
767 {
768 if (acfg->llvm) {
769 mono_llvm_emit_aot_data (name, (guint8*)value, strlen (value) + 1);
770 return;
771 }
772
773 mono_img_writer_emit_section_change (acfg->w, RODATA_SECT, 1);
774 #ifdef TARGET_MACH
775 /* On apple, all symbols need to be aligned to avoid warnings from ld */
776 emit_alignment (acfg, 4);
777 #endif
778 mono_img_writer_emit_label (acfg->w, name);
779 mono_img_writer_emit_string (acfg->w, value);
780 }
781
782 static G_GNUC_UNUSED void
emit_uleb128(MonoAotCompile * acfg,guint32 value)783 emit_uleb128 (MonoAotCompile *acfg, guint32 value)
784 {
785 do {
786 guint8 b = value & 0x7f;
787 value >>= 7;
788 if (value != 0) /* more bytes to come */
789 b |= 0x80;
790 emit_byte (acfg, b);
791 } while (value);
792 }
793
794 static G_GNUC_UNUSED void
emit_sleb128(MonoAotCompile * acfg,gint64 value)795 emit_sleb128 (MonoAotCompile *acfg, gint64 value)
796 {
797 gboolean more = 1;
798 gboolean negative = (value < 0);
799 guint32 size = 64;
800 guint8 byte;
801
802 while (more) {
803 byte = value & 0x7f;
804 value >>= 7;
805 /* the following is unnecessary if the
806 * implementation of >>= uses an arithmetic rather
807 * than logical shift for a signed left operand
808 */
809 if (negative)
810 /* sign extend */
811 value |= - ((gint64)1 <<(size - 7));
812 /* sign bit of byte is second high order bit (0x40) */
813 if ((value == 0 && !(byte & 0x40)) ||
814 (value == -1 && (byte & 0x40)))
815 more = 0;
816 else
817 byte |= 0x80;
818 emit_byte (acfg, byte);
819 }
820 }
821
822 static G_GNUC_UNUSED void
encode_uleb128(guint32 value,guint8 * buf,guint8 ** endbuf)823 encode_uleb128 (guint32 value, guint8 *buf, guint8 **endbuf)
824 {
825 guint8 *p = buf;
826
827 do {
828 guint8 b = value & 0x7f;
829 value >>= 7;
830 if (value != 0) /* more bytes to come */
831 b |= 0x80;
832 *p ++ = b;
833 } while (value);
834
835 *endbuf = p;
836 }
837
838 static G_GNUC_UNUSED void
encode_sleb128(gint32 value,guint8 * buf,guint8 ** endbuf)839 encode_sleb128 (gint32 value, guint8 *buf, guint8 **endbuf)
840 {
841 gboolean more = 1;
842 gboolean negative = (value < 0);
843 guint32 size = 32;
844 guint8 byte;
845 guint8 *p = buf;
846
847 while (more) {
848 byte = value & 0x7f;
849 value >>= 7;
850 /* the following is unnecessary if the
851 * implementation of >>= uses an arithmetic rather
852 * than logical shift for a signed left operand
853 */
854 if (negative)
855 /* sign extend */
856 value |= - (1 <<(size - 7));
857 /* sign bit of byte is second high order bit (0x40) */
858 if ((value == 0 && !(byte & 0x40)) ||
859 (value == -1 && (byte & 0x40)))
860 more = 0;
861 else
862 byte |= 0x80;
863 *p ++= byte;
864 }
865
866 *endbuf = p;
867 }
868
869 static void
encode_int(gint32 val,guint8 * buf,guint8 ** endbuf)870 encode_int (gint32 val, guint8 *buf, guint8 **endbuf)
871 {
872 // FIXME: Big-endian
873 buf [0] = (val >> 0) & 0xff;
874 buf [1] = (val >> 8) & 0xff;
875 buf [2] = (val >> 16) & 0xff;
876 buf [3] = (val >> 24) & 0xff;
877
878 *endbuf = buf + 4;
879 }
880
881 static void
encode_int16(guint16 val,guint8 * buf,guint8 ** endbuf)882 encode_int16 (guint16 val, guint8 *buf, guint8 **endbuf)
883 {
884 buf [0] = (val >> 0) & 0xff;
885 buf [1] = (val >> 8) & 0xff;
886
887 *endbuf = buf + 2;
888 }
889
890 static void
encode_string(const char * s,guint8 * buf,guint8 ** endbuf)891 encode_string (const char *s, guint8 *buf, guint8 **endbuf)
892 {
893 int len = strlen (s);
894
895 memcpy (buf, s, len + 1);
896 *endbuf = buf + len + 1;
897 }
898
899 static void
emit_unset_mode(MonoAotCompile * acfg)900 emit_unset_mode (MonoAotCompile *acfg)
901 {
902 mono_img_writer_emit_unset_mode (acfg->w);
903 }
904
905 static G_GNUC_UNUSED void
emit_set_thumb_mode(MonoAotCompile * acfg)906 emit_set_thumb_mode (MonoAotCompile *acfg)
907 {
908 emit_unset_mode (acfg);
909 fprintf (acfg->fp, ".code 16\n");
910 }
911
912 static G_GNUC_UNUSED void
emit_set_arm_mode(MonoAotCompile * acfg)913 emit_set_arm_mode (MonoAotCompile *acfg)
914 {
915 emit_unset_mode (acfg);
916 fprintf (acfg->fp, ".code 32\n");
917 }
918
919 static inline void
emit_code_bytes(MonoAotCompile * acfg,const guint8 * buf,int size)920 emit_code_bytes (MonoAotCompile *acfg, const guint8* buf, int size)
921 {
922 #ifdef TARGET_ARM64
923 int i;
924
925 g_assert (size % 4 == 0);
926 emit_unset_mode (acfg);
927 for (i = 0; i < size; i += 4)
928 fprintf (acfg->fp, "%s 0x%x\n", acfg->inst_directive, *(guint32*)(buf + i));
929 #else
930 emit_bytes (acfg, buf, size);
931 #endif
932 }
933
934 /* ARCHITECTURE SPECIFIC CODE */
935
936 #if defined(TARGET_X86) || defined(TARGET_AMD64) || defined(TARGET_ARM) || defined(TARGET_POWERPC) || defined(TARGET_ARM64)
937 #define EMIT_DWARF_INFO 1
938 #endif
939
940 #ifdef TARGET_WIN32_MSVC
941 #undef EMIT_DWARF_INFO
942 #define EMIT_WIN32_CODEVIEW_INFO
943 #endif
944
945 #ifdef EMIT_WIN32_UNWIND_INFO
946 static UnwindInfoSectionCacheItem *
947 get_cached_unwind_info_section_item_win32 (MonoAotCompile *acfg, const char *function_start, const char *function_end, GSList *unwind_ops);
948
949 static void
950 free_unwind_info_section_cache_win32 (MonoAotCompile *acfg);
951
952 static void
953 emit_unwind_info_data_win32 (MonoAotCompile *acfg, PUNWIND_INFO unwind_info);
954
955 static void
956 emit_unwind_info_sections_win32 (MonoAotCompile *acfg, const char *function_start, const char *function_end, GSList *unwind_ops);
957 #endif
958
959 static void
arch_free_unwind_info_section_cache(MonoAotCompile * acfg)960 arch_free_unwind_info_section_cache (MonoAotCompile *acfg)
961 {
962 #ifdef EMIT_WIN32_UNWIND_INFO
963 free_unwind_info_section_cache_win32 (acfg);
964 #endif
965 }
966
967 static void
arch_emit_unwind_info_sections(MonoAotCompile * acfg,const char * function_start,const char * function_end,GSList * unwind_ops)968 arch_emit_unwind_info_sections (MonoAotCompile *acfg, const char *function_start, const char *function_end, GSList *unwind_ops)
969 {
970 #ifdef EMIT_WIN32_UNWIND_INFO
971 gboolean own_unwind_ops = FALSE;
972 if (!unwind_ops) {
973 unwind_ops = mono_unwind_get_cie_program ();
974 own_unwind_ops = TRUE;
975 }
976
977 emit_unwind_info_sections_win32 (acfg, function_start, function_end, unwind_ops);
978
979 if (own_unwind_ops)
980 mono_free_unwind_info (unwind_ops);
981 #endif
982 }
983
984 #if defined(TARGET_ARM)
985 #define AOT_FUNC_ALIGNMENT 4
986 #else
987 #define AOT_FUNC_ALIGNMENT 16
988 #endif
989
990 #if defined(TARGET_POWERPC64) && !defined(__mono_ilp32__)
991 #define PPC_LD_OP "ld"
992 #define PPC_LDX_OP "ldx"
993 #else
994 #define PPC_LD_OP "lwz"
995 #define PPC_LDX_OP "lwzx"
996 #endif
997
998 #ifdef TARGET_X86_64_WIN32_MSVC
999 #define AOT_TARGET_STR "AMD64 (WIN32) (MSVC codegen)"
1000 #elif TARGET_AMD64
1001 #define AOT_TARGET_STR "AMD64"
1002 #endif
1003
1004 #ifdef TARGET_ARM
1005 #ifdef TARGET_MACH
1006 #define AOT_TARGET_STR "ARM (MACH)"
1007 #else
1008 #define AOT_TARGET_STR "ARM (!MACH)"
1009 #endif
1010 #endif
1011
1012 #ifdef TARGET_ARM64
1013 #ifdef TARGET_MACH
1014 #define AOT_TARGET_STR "ARM64 (MACH)"
1015 #else
1016 #define AOT_TARGET_STR "ARM64 (!MACH)"
1017 #endif
1018 #endif
1019
1020 #ifdef TARGET_POWERPC64
1021 #ifdef __mono_ilp32__
1022 #define AOT_TARGET_STR "POWERPC64 (mono ilp32)"
1023 #else
1024 #define AOT_TARGET_STR "POWERPC64 (!mono ilp32)"
1025 #endif
1026 #else
1027 #ifdef TARGET_POWERPC
1028 #ifdef __mono_ilp32__
1029 #define AOT_TARGET_STR "POWERPC (mono ilp32)"
1030 #else
1031 #define AOT_TARGET_STR "POWERPC (!mono ilp32)"
1032 #endif
1033 #endif
1034 #endif
1035
1036 #ifdef TARGET_X86
1037 #ifdef TARGET_WIN32
1038 #define AOT_TARGET_STR "X86 (WIN32)"
1039 #else
1040 #define AOT_TARGET_STR "X86"
1041 #endif
1042 #endif
1043
1044 #ifndef AOT_TARGET_STR
1045 #define AOT_TARGET_STR ""
1046 #endif
1047
1048 static void
arch_init(MonoAotCompile * acfg)1049 arch_init (MonoAotCompile *acfg)
1050 {
1051 acfg->llc_args = g_string_new ("");
1052 acfg->as_args = g_string_new ("");
1053 acfg->llvm_owriter_supported = TRUE;
1054
1055 /*
1056 * The prefix LLVM likes to put in front of symbol names on darwin.
1057 * The mach-os specs require this for globals, but LLVM puts them in front of all
1058 * symbols. We need to handle this, since we need to refer to LLVM generated
1059 * symbols.
1060 */
1061 acfg->llvm_label_prefix = "";
1062 acfg->user_symbol_prefix = "";
1063
1064 #if defined(TARGET_X86)
1065 g_string_append (acfg->llc_args, " -march=x86 -mattr=sse4.1");
1066 #endif
1067
1068 #if defined(TARGET_AMD64)
1069 g_string_append (acfg->llc_args, " -march=x86-64 -mattr=sse4.1");
1070 /* NOP */
1071 acfg->align_pad_value = 0x90;
1072 #endif
1073
1074 #ifdef TARGET_ARM
1075 if (acfg->aot_opts.mtriple && strstr (acfg->aot_opts.mtriple, "darwin")) {
1076 g_string_append (acfg->llc_args, "-mattr=+v6");
1077 } else {
1078 #if defined(ARM_FPU_VFP_HARD)
1079 g_string_append (acfg->llc_args, " -mattr=+vfp2,-neon,+d16 -float-abi=hard");
1080 g_string_append (acfg->as_args, " -mfpu=vfp3");
1081 #elif defined(ARM_FPU_VFP)
1082 g_string_append (acfg->llc_args, " -mattr=+vfp2,-neon,+d16");
1083 g_string_append (acfg->as_args, " -mfpu=vfp3");
1084 #else
1085 g_string_append (acfg->llc_args, " -soft-float");
1086 #endif
1087 }
1088 if (acfg->aot_opts.mtriple && strstr (acfg->aot_opts.mtriple, "thumb"))
1089 acfg->thumb_mixed = TRUE;
1090
1091 if (acfg->aot_opts.mtriple)
1092 mono_arch_set_target (acfg->aot_opts.mtriple);
1093 #endif
1094
1095 #ifdef TARGET_ARM64
1096 acfg->inst_directive = ".inst";
1097 if (acfg->aot_opts.mtriple)
1098 mono_arch_set_target (acfg->aot_opts.mtriple);
1099 #endif
1100
1101 #ifdef TARGET_MACH
1102 acfg->user_symbol_prefix = "_";
1103 acfg->llvm_label_prefix = "_";
1104 acfg->inst_directive = ".word";
1105 acfg->need_no_dead_strip = TRUE;
1106 acfg->aot_opts.gnu_asm = TRUE;
1107 #endif
1108
1109 #if defined(__linux__) && !defined(TARGET_ARM)
1110 acfg->need_pt_gnu_stack = TRUE;
1111 #endif
1112
1113 #ifdef MONOTOUCH
1114 acfg->global_symbols = TRUE;
1115 #endif
1116
1117 #ifdef TARGET_ANDROID
1118 acfg->llvm_owriter_supported = FALSE;
1119 #endif
1120 }
1121
1122 #ifdef TARGET_ARM64
1123
1124
1125 /* Load the contents of GOT_SLOT into dreg, clobbering ip0 */
1126 static void
arm64_emit_load_got_slot(MonoAotCompile * acfg,int dreg,int got_slot)1127 arm64_emit_load_got_slot (MonoAotCompile *acfg, int dreg, int got_slot)
1128 {
1129 int offset;
1130
1131 g_assert (acfg->fp);
1132 emit_unset_mode (acfg);
1133 /* r16==ip0 */
1134 offset = (int)(got_slot * sizeof (gpointer));
1135 #ifdef TARGET_MACH
1136 /* clang's integrated assembler */
1137 fprintf (acfg->fp, "adrp x16, %s@PAGE+%d\n", acfg->got_symbol, offset & 0xfffff000);
1138 fprintf (acfg->fp, "add x16, x16, %s@PAGEOFF\n", acfg->got_symbol);
1139 fprintf (acfg->fp, "ldr x%d, [x16, #%d]\n", dreg, offset & 0xfff);
1140 #else
1141 /* Linux GAS */
1142 fprintf (acfg->fp, "adrp x16, %s+%d\n", acfg->got_symbol, offset & 0xfffff000);
1143 fprintf (acfg->fp, "add x16, x16, :lo12:%s\n", acfg->got_symbol);
1144 fprintf (acfg->fp, "ldr x%d, [x16, %d]\n", dreg, offset & 0xfff);
1145 #endif
1146 }
1147
1148 static void
arm64_emit_objc_selector_ref(MonoAotCompile * acfg,guint8 * code,int index,int * code_size)1149 arm64_emit_objc_selector_ref (MonoAotCompile *acfg, guint8 *code, int index, int *code_size)
1150 {
1151 int reg;
1152
1153 g_assert (acfg->fp);
1154 emit_unset_mode (acfg);
1155
1156 /* ldr rt, target */
1157 reg = arm_get_ldr_lit_reg (code);
1158
1159 fprintf (acfg->fp, "adrp x%d, L_OBJC_SELECTOR_REFERENCES_%d@PAGE\n", reg, index);
1160 fprintf (acfg->fp, "add x%d, x%d, L_OBJC_SELECTOR_REFERENCES_%d@PAGEOFF\n", reg, reg, index);
1161 fprintf (acfg->fp, "ldr x%d, [x%d]\n", reg, reg);
1162
1163 *code_size = 12;
1164 }
1165
1166 static void
arm64_emit_direct_call(MonoAotCompile * acfg,const char * target,gboolean external,gboolean thumb,MonoJumpInfo * ji,int * call_size)1167 arm64_emit_direct_call (MonoAotCompile *acfg, const char *target, gboolean external, gboolean thumb, MonoJumpInfo *ji, int *call_size)
1168 {
1169 g_assert (acfg->fp);
1170 emit_unset_mode (acfg);
1171 if (ji && ji->relocation == MONO_R_ARM64_B) {
1172 fprintf (acfg->fp, "b %s\n", target);
1173 } else {
1174 if (ji)
1175 g_assert (ji->relocation == MONO_R_ARM64_BL);
1176 fprintf (acfg->fp, "bl %s\n", target);
1177 }
1178 *call_size = 4;
1179 }
1180
1181 static void
arm64_emit_got_access(MonoAotCompile * acfg,guint8 * code,int got_slot,int * code_size)1182 arm64_emit_got_access (MonoAotCompile *acfg, guint8 *code, int got_slot, int *code_size)
1183 {
1184 int reg;
1185
1186 /* ldr rt, target */
1187 reg = arm_get_ldr_lit_reg (code);
1188 arm64_emit_load_got_slot (acfg, reg, got_slot);
1189 *code_size = 12;
1190 }
1191
1192 static void
arm64_emit_plt_entry(MonoAotCompile * acfg,const char * got_symbol,int offset,int info_offset)1193 arm64_emit_plt_entry (MonoAotCompile *acfg, const char *got_symbol, int offset, int info_offset)
1194 {
1195 arm64_emit_load_got_slot (acfg, ARMREG_R16, offset / sizeof (gpointer));
1196 fprintf (acfg->fp, "br x16\n");
1197 /* Used by mono_aot_get_plt_info_offset () */
1198 fprintf (acfg->fp, "%s %d\n", acfg->inst_directive, info_offset);
1199 }
1200
1201 static void
arm64_emit_tramp_page_common_code(MonoAotCompile * acfg,int pagesize,int arg_reg,int * size)1202 arm64_emit_tramp_page_common_code (MonoAotCompile *acfg, int pagesize, int arg_reg, int *size)
1203 {
1204 guint8 buf [256];
1205 guint8 *code;
1206 int imm;
1207
1208 /* The common code */
1209 code = buf;
1210 imm = pagesize;
1211 /* The trampoline address is in IP0 */
1212 arm_movzx (code, ARMREG_IP1, imm & 0xffff, 0);
1213 arm_movkx (code, ARMREG_IP1, (imm >> 16) & 0xffff, 16);
1214 /* Compute the data slot address */
1215 arm_subx (code, ARMREG_IP0, ARMREG_IP0, ARMREG_IP1);
1216 /* Trampoline argument */
1217 arm_ldrx (code, arg_reg, ARMREG_IP0, 0);
1218 /* Address */
1219 arm_ldrx (code, ARMREG_IP0, ARMREG_IP0, 8);
1220 arm_brx (code, ARMREG_IP0);
1221
1222 /* Emit it */
1223 emit_code_bytes (acfg, buf, code - buf);
1224
1225 *size = code - buf;
1226 }
1227
1228 static void
arm64_emit_tramp_page_specific_code(MonoAotCompile * acfg,int pagesize,int common_tramp_size,int specific_tramp_size)1229 arm64_emit_tramp_page_specific_code (MonoAotCompile *acfg, int pagesize, int common_tramp_size, int specific_tramp_size)
1230 {
1231 guint8 buf [256];
1232 guint8 *code;
1233 int i, count;
1234
1235 count = (pagesize - common_tramp_size) / specific_tramp_size;
1236 for (i = 0; i < count; ++i) {
1237 code = buf;
1238 arm_adrx (code, ARMREG_IP0, code);
1239 /* Branch to the generic code */
1240 arm_b (code, code - 4 - (i * specific_tramp_size) - common_tramp_size);
1241 /* This has to be 2 pointers long */
1242 arm_nop (code);
1243 arm_nop (code);
1244 g_assert (code - buf == specific_tramp_size);
1245 emit_code_bytes (acfg, buf, code - buf);
1246 }
1247 }
1248
1249 static void
arm64_emit_specific_trampoline_pages(MonoAotCompile * acfg)1250 arm64_emit_specific_trampoline_pages (MonoAotCompile *acfg)
1251 {
1252 guint8 buf [128];
1253 guint8 *code;
1254 guint8 *labels [16];
1255 int common_tramp_size;
1256 int specific_tramp_size = 2 * 8;
1257 int imm, pagesize;
1258 char symbol [128];
1259
1260 if (!acfg->aot_opts.use_trampolines_page)
1261 return;
1262
1263 #ifdef TARGET_MACH
1264 /* Have to match the target pagesize */
1265 pagesize = 16384;
1266 #else
1267 pagesize = mono_pagesize ();
1268 #endif
1269 acfg->tramp_page_size = pagesize;
1270
1271 /* The specific trampolines */
1272 sprintf (symbol, "%sspecific_trampolines_page", acfg->user_symbol_prefix);
1273 emit_alignment (acfg, pagesize);
1274 emit_global (acfg, symbol, TRUE);
1275 emit_label (acfg, symbol);
1276
1277 /* The common code */
1278 arm64_emit_tramp_page_common_code (acfg, pagesize, ARMREG_IP1, &common_tramp_size);
1279 acfg->tramp_page_code_offsets [MONO_AOT_TRAMP_SPECIFIC] = common_tramp_size;
1280
1281 arm64_emit_tramp_page_specific_code (acfg, pagesize, common_tramp_size, specific_tramp_size);
1282
1283 /* The rgctx trampolines */
1284 /* These are the same as the specific trampolines, but they load the argument into MONO_ARCH_RGCTX_REG */
1285 sprintf (symbol, "%srgctx_trampolines_page", acfg->user_symbol_prefix);
1286 emit_alignment (acfg, pagesize);
1287 emit_global (acfg, symbol, TRUE);
1288 emit_label (acfg, symbol);
1289
1290 /* The common code */
1291 arm64_emit_tramp_page_common_code (acfg, pagesize, MONO_ARCH_RGCTX_REG, &common_tramp_size);
1292 acfg->tramp_page_code_offsets [MONO_AOT_TRAMP_STATIC_RGCTX] = common_tramp_size;
1293
1294 arm64_emit_tramp_page_specific_code (acfg, pagesize, common_tramp_size, specific_tramp_size);
1295
1296 /* The gsharedvt arg trampolines */
1297 /* These are the same as the specific trampolines */
1298 sprintf (symbol, "%sgsharedvt_arg_trampolines_page", acfg->user_symbol_prefix);
1299 emit_alignment (acfg, pagesize);
1300 emit_global (acfg, symbol, TRUE);
1301 emit_label (acfg, symbol);
1302
1303 arm64_emit_tramp_page_common_code (acfg, pagesize, ARMREG_IP1, &common_tramp_size);
1304 acfg->tramp_page_code_offsets [MONO_AOT_TRAMP_GSHAREDVT_ARG] = common_tramp_size;
1305
1306 arm64_emit_tramp_page_specific_code (acfg, pagesize, common_tramp_size, specific_tramp_size);
1307
1308 /* The IMT trampolines */
1309 sprintf (symbol, "%simt_trampolines_page", acfg->user_symbol_prefix);
1310 emit_alignment (acfg, pagesize);
1311 emit_global (acfg, symbol, TRUE);
1312 emit_label (acfg, symbol);
1313
1314 code = buf;
1315 imm = pagesize;
1316 /* The trampoline address is in IP0 */
1317 arm_movzx (code, ARMREG_IP1, imm & 0xffff, 0);
1318 arm_movkx (code, ARMREG_IP1, (imm >> 16) & 0xffff, 16);
1319 /* Compute the data slot address */
1320 arm_subx (code, ARMREG_IP0, ARMREG_IP0, ARMREG_IP1);
1321 /* Trampoline argument */
1322 arm_ldrx (code, ARMREG_IP1, ARMREG_IP0, 0);
1323
1324 /* Same as arch_emit_imt_trampoline () */
1325 labels [0] = code;
1326 arm_ldrx (code, ARMREG_IP0, ARMREG_IP1, 0);
1327 arm_cmpx (code, ARMREG_IP0, MONO_ARCH_RGCTX_REG);
1328 labels [1] = code;
1329 arm_bcc (code, ARMCOND_EQ, 0);
1330
1331 /* End-of-loop check */
1332 labels [2] = code;
1333 arm_cbzx (code, ARMREG_IP0, 0);
1334
1335 /* Loop footer */
1336 arm_addx_imm (code, ARMREG_IP1, ARMREG_IP1, 2 * 8);
1337 arm_b (code, labels [0]);
1338
1339 /* Match */
1340 mono_arm_patch (labels [1], code, MONO_R_ARM64_BCC);
1341 /* Load vtable slot addr */
1342 arm_ldrx (code, ARMREG_IP0, ARMREG_IP1, 8);
1343 /* Load vtable slot */
1344 arm_ldrx (code, ARMREG_IP0, ARMREG_IP0, 0);
1345 arm_brx (code, ARMREG_IP0);
1346
1347 /* No match */
1348 mono_arm_patch (labels [2], code, MONO_R_ARM64_CBZ);
1349 /* Load fail addr */
1350 arm_ldrx (code, ARMREG_IP0, ARMREG_IP1, 8);
1351 arm_brx (code, ARMREG_IP0);
1352
1353 emit_code_bytes (acfg, buf, code - buf);
1354
1355 common_tramp_size = code - buf;
1356 acfg->tramp_page_code_offsets [MONO_AOT_TRAMP_IMT] = common_tramp_size;
1357
1358 arm64_emit_tramp_page_specific_code (acfg, pagesize, common_tramp_size, specific_tramp_size);
1359 }
1360
1361 static void
arm64_emit_specific_trampoline(MonoAotCompile * acfg,int offset,int * tramp_size)1362 arm64_emit_specific_trampoline (MonoAotCompile *acfg, int offset, int *tramp_size)
1363 {
1364 /* Load argument from second GOT slot */
1365 arm64_emit_load_got_slot (acfg, ARMREG_R17, offset + 1);
1366 /* Load generic trampoline address from first GOT slot */
1367 arm64_emit_load_got_slot (acfg, ARMREG_R16, offset);
1368 fprintf (acfg->fp, "br x16\n");
1369 *tramp_size = 7 * 4;
1370 }
1371
1372 static void
arm64_emit_unbox_trampoline(MonoAotCompile * acfg,MonoCompile * cfg,MonoMethod * method,const char * call_target)1373 arm64_emit_unbox_trampoline (MonoAotCompile *acfg, MonoCompile *cfg, MonoMethod *method, const char *call_target)
1374 {
1375 emit_unset_mode (acfg);
1376 fprintf (acfg->fp, "add x0, x0, %d\n", (int)(sizeof (MonoObject)));
1377 fprintf (acfg->fp, "b %s\n", call_target);
1378 }
1379
1380 static void
arm64_emit_static_rgctx_trampoline(MonoAotCompile * acfg,int offset,int * tramp_size)1381 arm64_emit_static_rgctx_trampoline (MonoAotCompile *acfg, int offset, int *tramp_size)
1382 {
1383 /* Similar to the specific trampolines, but use the rgctx reg instead of ip1 */
1384
1385 /* Load argument from first GOT slot */
1386 arm64_emit_load_got_slot (acfg, MONO_ARCH_RGCTX_REG, offset);
1387 /* Load generic trampoline address from second GOT slot */
1388 arm64_emit_load_got_slot (acfg, ARMREG_R16, offset + 1);
1389 fprintf (acfg->fp, "br x16\n");
1390 *tramp_size = 7 * 4;
1391 }
1392
1393 static void
arm64_emit_imt_trampoline(MonoAotCompile * acfg,int offset,int * tramp_size)1394 arm64_emit_imt_trampoline (MonoAotCompile *acfg, int offset, int *tramp_size)
1395 {
1396 guint8 buf [128];
1397 guint8 *code, *labels [16];
1398
1399 /* Load parameter from GOT slot into ip1 */
1400 arm64_emit_load_got_slot (acfg, ARMREG_R17, offset);
1401
1402 code = buf;
1403 labels [0] = code;
1404 arm_ldrx (code, ARMREG_IP0, ARMREG_IP1, 0);
1405 arm_cmpx (code, ARMREG_IP0, MONO_ARCH_RGCTX_REG);
1406 labels [1] = code;
1407 arm_bcc (code, ARMCOND_EQ, 0);
1408
1409 /* End-of-loop check */
1410 labels [2] = code;
1411 arm_cbzx (code, ARMREG_IP0, 0);
1412
1413 /* Loop footer */
1414 arm_addx_imm (code, ARMREG_IP1, ARMREG_IP1, 2 * 8);
1415 arm_b (code, labels [0]);
1416
1417 /* Match */
1418 mono_arm_patch (labels [1], code, MONO_R_ARM64_BCC);
1419 /* Load vtable slot addr */
1420 arm_ldrx (code, ARMREG_IP0, ARMREG_IP1, 8);
1421 /* Load vtable slot */
1422 arm_ldrx (code, ARMREG_IP0, ARMREG_IP0, 0);
1423 arm_brx (code, ARMREG_IP0);
1424
1425 /* No match */
1426 mono_arm_patch (labels [2], code, MONO_R_ARM64_CBZ);
1427 /* Load fail addr */
1428 arm_ldrx (code, ARMREG_IP0, ARMREG_IP1, 8);
1429 arm_brx (code, ARMREG_IP0);
1430
1431 emit_code_bytes (acfg, buf, code - buf);
1432
1433 *tramp_size = code - buf + (3 * 4);
1434 }
1435
1436 static void
arm64_emit_gsharedvt_arg_trampoline(MonoAotCompile * acfg,int offset,int * tramp_size)1437 arm64_emit_gsharedvt_arg_trampoline (MonoAotCompile *acfg, int offset, int *tramp_size)
1438 {
1439 /* Similar to the specific trampolines, but the address is in the second slot */
1440 /* Load argument from first GOT slot */
1441 arm64_emit_load_got_slot (acfg, ARMREG_R17, offset);
1442 /* Load generic trampoline address from second GOT slot */
1443 arm64_emit_load_got_slot (acfg, ARMREG_R16, offset + 1);
1444 fprintf (acfg->fp, "br x16\n");
1445 *tramp_size = 7 * 4;
1446 }
1447
1448
1449 #endif
1450
1451 #ifdef MONO_ARCH_AOT_SUPPORTED
1452 /*
1453 * arch_emit_direct_call:
1454 *
1455 * Emit a direct call to the symbol TARGET. CALL_SIZE is set to the size of the
1456 * calling code.
1457 */
1458 static void
arch_emit_direct_call(MonoAotCompile * acfg,const char * target,gboolean external,gboolean thumb,MonoJumpInfo * ji,int * call_size)1459 arch_emit_direct_call (MonoAotCompile *acfg, const char *target, gboolean external, gboolean thumb, MonoJumpInfo *ji, int *call_size)
1460 {
1461 #if defined(TARGET_X86) || defined(TARGET_AMD64)
1462 /* Need to make sure this is exactly 5 bytes long */
1463 emit_unset_mode (acfg);
1464 fprintf (acfg->fp, "call %s\n", target);
1465 *call_size = 5;
1466 #elif defined(TARGET_ARM)
1467 emit_unset_mode (acfg);
1468 if (thumb)
1469 fprintf (acfg->fp, "blx %s\n", target);
1470 else
1471 fprintf (acfg->fp, "bl %s\n", target);
1472 *call_size = 4;
1473 #elif defined(TARGET_ARM64)
1474 arm64_emit_direct_call (acfg, target, external, thumb, ji, call_size);
1475 #elif defined(TARGET_POWERPC)
1476 emit_unset_mode (acfg);
1477 fprintf (acfg->fp, "bl %s\n", target);
1478 *call_size = 4;
1479 #else
1480 g_assert_not_reached ();
1481 #endif
1482 }
1483 #endif
1484
1485 /*
1486 * PPC32 design:
1487 * - we use an approach similar to the x86 abi: reserve a register (r30) to hold
1488 * the GOT pointer.
1489 * - The full-aot trampolines need access to the GOT of mscorlib, so we store
1490 * in in the 2. slot of every GOT, and require every method to place the GOT
1491 * address in r30, even when it doesn't access the GOT otherwise. This way,
1492 * the trampolines can compute the mscorlib GOT address by loading 4(r30).
1493 */
1494
1495 /*
1496 * PPC64 design:
1497 * PPC64 uses function descriptors which greatly complicate all code, since
1498 * these are used very inconsistently in the runtime. Some functions like
1499 * mono_compile_method () return ftn descriptors, while others like the
1500 * trampoline creation functions do not.
1501 * We assume that all GOT slots contain function descriptors, and create
1502 * descriptors in aot-runtime.c when needed.
1503 * The ppc64 abi uses r2 to hold the address of the TOC/GOT, which is loaded
1504 * from function descriptors, we could do the same, but it would require
1505 * rewriting all the ppc/aot code to handle function descriptors properly.
1506 * So instead, we use the same approach as on PPC32.
1507 * This is a horrible mess, but fixing it would probably lead to an even bigger
1508 * one.
1509 */
1510
1511 /*
1512 * X86 design:
1513 * - similar to the PPC32 design, we reserve EBX to hold the GOT pointer.
1514 */
1515
1516 #ifdef MONO_ARCH_AOT_SUPPORTED
1517 /*
1518 * arch_emit_got_offset:
1519 *
1520 * The memory pointed to by CODE should hold native code for computing the GOT
1521 * address (OP_LOAD_GOTADDR). Emit this code while patching it with the offset
1522 * between code and the GOT. CODE_SIZE is set to the number of bytes emitted.
1523 */
1524 static void
arch_emit_got_offset(MonoAotCompile * acfg,guint8 * code,int * code_size)1525 arch_emit_got_offset (MonoAotCompile *acfg, guint8 *code, int *code_size)
1526 {
1527 #if defined(TARGET_POWERPC64)
1528 emit_unset_mode (acfg);
1529 /*
1530 * The ppc32 code doesn't seem to work on ppc64, the assembler complains about
1531 * unsupported relocations. So we store the got address into the .Lgot_addr
1532 * symbol which is in the text segment, compute its address, and load it.
1533 */
1534 fprintf (acfg->fp, ".L%d:\n", acfg->label_generator);
1535 fprintf (acfg->fp, "lis 0, (.Lgot_addr + 4 - .L%d)@h\n", acfg->label_generator);
1536 fprintf (acfg->fp, "ori 0, 0, (.Lgot_addr + 4 - .L%d)@l\n", acfg->label_generator);
1537 fprintf (acfg->fp, "add 30, 30, 0\n");
1538 fprintf (acfg->fp, "%s 30, 0(30)\n", PPC_LD_OP);
1539 acfg->label_generator ++;
1540 *code_size = 16;
1541 #elif defined(TARGET_POWERPC)
1542 emit_unset_mode (acfg);
1543 fprintf (acfg->fp, ".L%d:\n", acfg->label_generator);
1544 fprintf (acfg->fp, "lis 0, (%s + 4 - .L%d)@h\n", acfg->got_symbol, acfg->label_generator);
1545 fprintf (acfg->fp, "ori 0, 0, (%s + 4 - .L%d)@l\n", acfg->got_symbol, acfg->label_generator);
1546 acfg->label_generator ++;
1547 *code_size = 8;
1548 #else
1549 guint32 offset = mono_arch_get_patch_offset (code);
1550 emit_bytes (acfg, code, offset);
1551 emit_symbol_diff (acfg, acfg->got_symbol, ".", offset);
1552
1553 *code_size = offset + 4;
1554 #endif
1555 }
1556
1557 /*
1558 * arch_emit_got_access:
1559 *
1560 * The memory pointed to by CODE should hold native code for loading a GOT
1561 * slot (OP_AOTCONST/OP_GOT_ENTRY). Emit this code while patching it so it accesses the
1562 * GOT slot GOT_SLOT. CODE_SIZE is set to the number of bytes emitted.
1563 */
1564 static void
arch_emit_got_access(MonoAotCompile * acfg,const char * got_symbol,guint8 * code,int got_slot,int * code_size)1565 arch_emit_got_access (MonoAotCompile *acfg, const char *got_symbol, guint8 *code, int got_slot, int *code_size)
1566 {
1567 #ifdef TARGET_AMD64
1568 /* mov reg, got+offset(%rip) */
1569 if (acfg->llvm) {
1570 /* The GOT symbol is in the LLVM module, the clang assembler has problems emitting symbol diffs for it */
1571 int dreg;
1572 int rex_r;
1573
1574 /* Decode reg, see amd64_mov_reg_membase () */
1575 rex_r = code [0] & AMD64_REX_R;
1576 g_assert (code [0] == 0x49 + rex_r);
1577 g_assert (code [1] == 0x8b);
1578 dreg = ((code [2] >> 3) & 0x7) + (rex_r ? 8 : 0);
1579
1580 emit_unset_mode (acfg);
1581 fprintf (acfg->fp, "mov %s+%d(%%rip), %s\n", got_symbol, (unsigned int) ((got_slot * sizeof (gpointer))), mono_arch_regname (dreg));
1582 *code_size = 7;
1583 } else {
1584 emit_bytes (acfg, code, mono_arch_get_patch_offset (code));
1585 emit_symbol_diff (acfg, got_symbol, ".", (unsigned int) ((got_slot * sizeof (gpointer)) - 4));
1586 *code_size = mono_arch_get_patch_offset (code) + 4;
1587 }
1588 #elif defined(TARGET_X86)
1589 emit_bytes (acfg, code, mono_arch_get_patch_offset (code));
1590 emit_int32 (acfg, (unsigned int) ((got_slot * sizeof (gpointer))));
1591 *code_size = mono_arch_get_patch_offset (code) + 4;
1592 #elif defined(TARGET_ARM)
1593 emit_bytes (acfg, code, mono_arch_get_patch_offset (code));
1594 emit_symbol_diff (acfg, got_symbol, ".", (unsigned int) ((got_slot * sizeof (gpointer))) - 12);
1595 *code_size = mono_arch_get_patch_offset (code) + 4;
1596 #elif defined(TARGET_ARM64)
1597 emit_bytes (acfg, code, mono_arch_get_patch_offset (code));
1598 arm64_emit_got_access (acfg, code, got_slot, code_size);
1599 #elif defined(TARGET_POWERPC)
1600 {
1601 guint8 buf [32];
1602
1603 emit_bytes (acfg, code, mono_arch_get_patch_offset (code));
1604 code = buf;
1605 ppc_load32 (code, ppc_r0, got_slot * sizeof (gpointer));
1606 g_assert (code - buf == 8);
1607 emit_bytes (acfg, buf, code - buf);
1608 *code_size = code - buf;
1609 }
1610 #else
1611 g_assert_not_reached ();
1612 #endif
1613 }
1614
1615 #endif
1616
1617 #ifdef MONO_ARCH_AOT_SUPPORTED
1618 /*
1619 * arch_emit_objc_selector_ref:
1620 *
1621 * Emit the implementation of OP_OBJC_GET_SELECTOR, which itself implements @selector(foo:) in objective-c.
1622 */
1623 static void
arch_emit_objc_selector_ref(MonoAotCompile * acfg,guint8 * code,int index,int * code_size)1624 arch_emit_objc_selector_ref (MonoAotCompile *acfg, guint8 *code, int index, int *code_size)
1625 {
1626 #if defined(TARGET_ARM)
1627 char symbol1 [MAX_SYMBOL_SIZE];
1628 char symbol2 [MAX_SYMBOL_SIZE];
1629 int lindex = acfg->objc_selector_index_2 ++;
1630
1631 /* Emit ldr.imm/b */
1632 emit_bytes (acfg, code, 8);
1633
1634 sprintf (symbol1, "L_OBJC_SELECTOR_%d", lindex);
1635 sprintf (symbol2, "L_OBJC_SELECTOR_REFERENCES_%d", index);
1636
1637 emit_label (acfg, symbol1);
1638 mono_img_writer_emit_unset_mode (acfg->w);
1639 fprintf (acfg->fp, ".long %s-(%s+12)", symbol2, symbol1);
1640
1641 *code_size = 12;
1642 #elif defined(TARGET_ARM64)
1643 arm64_emit_objc_selector_ref (acfg, code, index, code_size);
1644 #else
1645 g_assert_not_reached ();
1646 #endif
1647 }
1648 #endif
1649
1650 /*
1651 * arch_emit_plt_entry:
1652 *
1653 * Emit code for the PLT entry.
1654 * The plt entry should look like this:
1655 * <indirect jump to GOT_SYMBOL + OFFSET>
1656 * <INFO_OFFSET embedded into the instruction stream>
1657 */
1658 static void
arch_emit_plt_entry(MonoAotCompile * acfg,const char * got_symbol,int offset,int info_offset)1659 arch_emit_plt_entry (MonoAotCompile *acfg, const char *got_symbol, int offset, int info_offset)
1660 {
1661 #if defined(TARGET_X86)
1662 /* jmp *<offset>(%ebx) */
1663 emit_byte (acfg, 0xff);
1664 emit_byte (acfg, 0xa3);
1665 emit_int32 (acfg, offset);
1666 /* Used by mono_aot_get_plt_info_offset */
1667 emit_int32 (acfg, info_offset);
1668 #elif defined(TARGET_AMD64)
1669 emit_unset_mode (acfg);
1670 fprintf (acfg->fp, "jmp *%s+%d(%%rip)\n", got_symbol, offset);
1671 /* Used by mono_aot_get_plt_info_offset */
1672 emit_int32 (acfg, info_offset);
1673 acfg->stats.plt_size += 10;
1674 #elif defined(TARGET_ARM)
1675 guint8 buf [256];
1676 guint8 *code;
1677
1678 code = buf;
1679 ARM_LDR_IMM (code, ARMREG_IP, ARMREG_PC, 0);
1680 ARM_LDR_REG_REG (code, ARMREG_PC, ARMREG_PC, ARMREG_IP);
1681 emit_bytes (acfg, buf, code - buf);
1682 emit_symbol_diff (acfg, got_symbol, ".", offset - 4);
1683 /* Used by mono_aot_get_plt_info_offset */
1684 emit_int32 (acfg, info_offset);
1685 #elif defined(TARGET_ARM64)
1686 arm64_emit_plt_entry (acfg, got_symbol, offset, info_offset);
1687 #elif defined(TARGET_POWERPC)
1688 /* The GOT address is guaranteed to be in r30 by OP_LOAD_GOTADDR */
1689 emit_unset_mode (acfg);
1690 fprintf (acfg->fp, "lis 11, %d@h\n", offset);
1691 fprintf (acfg->fp, "ori 11, 11, %d@l\n", offset);
1692 fprintf (acfg->fp, "add 11, 11, 30\n");
1693 fprintf (acfg->fp, "%s 11, 0(11)\n", PPC_LD_OP);
1694 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
1695 fprintf (acfg->fp, "%s 2, %d(11)\n", PPC_LD_OP, (int)sizeof (gpointer));
1696 fprintf (acfg->fp, "%s 11, 0(11)\n", PPC_LD_OP);
1697 #endif
1698 fprintf (acfg->fp, "mtctr 11\n");
1699 fprintf (acfg->fp, "bctr\n");
1700 emit_int32 (acfg, info_offset);
1701 #else
1702 g_assert_not_reached ();
1703 #endif
1704 }
1705
1706 /*
1707 * arch_emit_llvm_plt_entry:
1708 *
1709 * Same as arch_emit_plt_entry, but handles calls from LLVM generated code.
1710 * This is only needed on arm to handle thumb interop.
1711 */
1712 static void
arch_emit_llvm_plt_entry(MonoAotCompile * acfg,const char * got_symbol,int offset,int info_offset)1713 arch_emit_llvm_plt_entry (MonoAotCompile *acfg, const char *got_symbol, int offset, int info_offset)
1714 {
1715 #if defined(TARGET_ARM)
1716 /* LLVM calls the PLT entries using bl, so these have to be thumb2 */
1717 /* The caller already transitioned to thumb */
1718 /* The code below should be 12 bytes long */
1719 /* clang has trouble encoding these instructions, so emit the binary */
1720 #if 0
1721 fprintf (acfg->fp, "ldr ip, [pc, #8]\n");
1722 /* thumb can't encode ld pc, [pc, ip] */
1723 fprintf (acfg->fp, "add ip, pc, ip\n");
1724 fprintf (acfg->fp, "ldr ip, [ip, #0]\n");
1725 fprintf (acfg->fp, "bx ip\n");
1726 #endif
1727 emit_set_thumb_mode (acfg);
1728 fprintf (acfg->fp, ".4byte 0xc008f8df\n");
1729 fprintf (acfg->fp, ".2byte 0x44fc\n");
1730 fprintf (acfg->fp, ".4byte 0xc000f8dc\n");
1731 fprintf (acfg->fp, ".2byte 0x4760\n");
1732 emit_symbol_diff (acfg, got_symbol, ".", offset + 4);
1733 emit_int32 (acfg, info_offset);
1734 emit_unset_mode (acfg);
1735 emit_set_arm_mode (acfg);
1736 #else
1737 g_assert_not_reached ();
1738 #endif
1739 }
1740
1741 /* Save unwind_info in the module and emit the offset to the information at symbol */
save_unwind_info(MonoAotCompile * acfg,char * symbol,GSList * unwind_ops)1742 static void save_unwind_info (MonoAotCompile *acfg, char *symbol, GSList *unwind_ops)
1743 {
1744 guint32 uw_offset, encoded_len;
1745 guint8 *encoded;
1746
1747 emit_section_change (acfg, RODATA_SECT, 0);
1748 emit_global (acfg, symbol, FALSE);
1749 emit_label (acfg, symbol);
1750
1751 encoded = mono_unwind_ops_encode (unwind_ops, &encoded_len);
1752 uw_offset = get_unwind_info_offset (acfg, encoded, encoded_len);
1753 g_free (encoded);
1754 emit_int32 (acfg, uw_offset);
1755 }
1756
1757 /*
1758 * arch_emit_specific_trampoline_pages:
1759 *
1760 * Emits a page full of trampolines: each trampoline uses its own address to
1761 * lookup both the generic trampoline code and the data argument.
1762 * This page can be remapped in process multiple times so we can get an
1763 * unlimited number of trampolines.
1764 * Specifically this implementation uses the following trick: two memory pages
1765 * are allocated, with the first containing the data and the second containing the trampolines.
1766 * To reduce trampoline size, each trampoline jumps at the start of the page where a common
1767 * implementation does all the lifting.
1768 * Note that the ARM single trampoline size is 8 bytes, exactly like the data that needs to be stored
1769 * on the arm 32 bit system.
1770 */
1771 static void
arch_emit_specific_trampoline_pages(MonoAotCompile * acfg)1772 arch_emit_specific_trampoline_pages (MonoAotCompile *acfg)
1773 {
1774 #if defined(TARGET_ARM)
1775 guint8 buf [128];
1776 guint8 *code;
1777 guint8 *loop_start, *loop_branch_back, *loop_end_check, *imt_found_check;
1778 int i;
1779 int pagesize = MONO_AOT_TRAMP_PAGE_SIZE;
1780 GSList *unwind_ops = NULL;
1781 #define COMMON_TRAMP_SIZE 16
1782 int count = (pagesize - COMMON_TRAMP_SIZE) / 8;
1783 int imm8, rot_amount;
1784 char symbol [128];
1785
1786 if (!acfg->aot_opts.use_trampolines_page)
1787 return;
1788
1789 acfg->tramp_page_size = pagesize;
1790
1791 sprintf (symbol, "%sspecific_trampolines_page", acfg->user_symbol_prefix);
1792 emit_alignment (acfg, pagesize);
1793 emit_global (acfg, symbol, TRUE);
1794 emit_label (acfg, symbol);
1795
1796 /* emit the generic code first, the trampoline address + 8 is in the lr register */
1797 code = buf;
1798 imm8 = mono_arm_is_rotated_imm8 (pagesize, &rot_amount);
1799 ARM_SUB_REG_IMM (code, ARMREG_LR, ARMREG_LR, imm8, rot_amount);
1800 ARM_LDR_IMM (code, ARMREG_R1, ARMREG_LR, -8);
1801 ARM_LDR_IMM (code, ARMREG_PC, ARMREG_LR, -4);
1802 ARM_NOP (code);
1803 g_assert (code - buf == COMMON_TRAMP_SIZE);
1804
1805 /* Emit it */
1806 emit_bytes (acfg, buf, code - buf);
1807
1808 for (i = 0; i < count; ++i) {
1809 code = buf;
1810 ARM_PUSH (code, 0x5fff);
1811 ARM_BL (code, 0);
1812 arm_patch (code - 4, code - COMMON_TRAMP_SIZE - 8 * (i + 1));
1813 g_assert (code - buf == 8);
1814 emit_bytes (acfg, buf, code - buf);
1815 }
1816
1817 /* now the rgctx trampolines: each specific trampolines puts in the ip register
1818 * the instruction pointer address, so the generic trampoline at the start of the page
1819 * subtracts 4096 to get to the data page and loads the values
1820 * We again fit the generic trampiline in 16 bytes.
1821 */
1822 sprintf (symbol, "%srgctx_trampolines_page", acfg->user_symbol_prefix);
1823 emit_global (acfg, symbol, TRUE);
1824 emit_label (acfg, symbol);
1825 code = buf;
1826 imm8 = mono_arm_is_rotated_imm8 (pagesize, &rot_amount);
1827 ARM_SUB_REG_IMM (code, ARMREG_IP, ARMREG_IP, imm8, rot_amount);
1828 ARM_LDR_IMM (code, MONO_ARCH_RGCTX_REG, ARMREG_IP, -8);
1829 ARM_LDR_IMM (code, ARMREG_PC, ARMREG_IP, -4);
1830 ARM_NOP (code);
1831 g_assert (code - buf == COMMON_TRAMP_SIZE);
1832
1833 /* Emit it */
1834 emit_bytes (acfg, buf, code - buf);
1835
1836 for (i = 0; i < count; ++i) {
1837 code = buf;
1838 ARM_MOV_REG_REG (code, ARMREG_IP, ARMREG_PC);
1839 ARM_B (code, 0);
1840 arm_patch (code - 4, code - COMMON_TRAMP_SIZE - 8 * (i + 1));
1841 g_assert (code - buf == 8);
1842 emit_bytes (acfg, buf, code - buf);
1843 }
1844
1845 /*
1846 * gsharedvt arg trampolines: see arch_emit_gsharedvt_arg_trampoline ()
1847 */
1848 sprintf (symbol, "%sgsharedvt_arg_trampolines_page", acfg->user_symbol_prefix);
1849 emit_global (acfg, symbol, TRUE);
1850 emit_label (acfg, symbol);
1851 code = buf;
1852 ARM_PUSH (code, (1 << ARMREG_R0) | (1 << ARMREG_R1) | (1 << ARMREG_R2) | (1 << ARMREG_R3));
1853 imm8 = mono_arm_is_rotated_imm8 (pagesize, &rot_amount);
1854 ARM_SUB_REG_IMM (code, ARMREG_IP, ARMREG_IP, imm8, rot_amount);
1855 ARM_LDR_IMM (code, ARMREG_R0, ARMREG_IP, -8);
1856 ARM_LDR_IMM (code, ARMREG_PC, ARMREG_IP, -4);
1857 g_assert (code - buf == COMMON_TRAMP_SIZE);
1858 /* Emit it */
1859 emit_bytes (acfg, buf, code - buf);
1860
1861 for (i = 0; i < count; ++i) {
1862 code = buf;
1863 ARM_MOV_REG_REG (code, ARMREG_IP, ARMREG_PC);
1864 ARM_B (code, 0);
1865 arm_patch (code - 4, code - COMMON_TRAMP_SIZE - 8 * (i + 1));
1866 g_assert (code - buf == 8);
1867 emit_bytes (acfg, buf, code - buf);
1868 }
1869
1870 /* now the imt trampolines: each specific trampolines puts in the ip register
1871 * the instruction pointer address, so the generic trampoline at the start of the page
1872 * subtracts 4096 to get to the data page and loads the values
1873 */
1874 #define IMT_TRAMP_SIZE 72
1875 sprintf (symbol, "%simt_trampolines_page", acfg->user_symbol_prefix);
1876 emit_global (acfg, symbol, TRUE);
1877 emit_label (acfg, symbol);
1878 code = buf;
1879 /* Need at least two free registers, plus a slot for storing the pc */
1880 ARM_PUSH (code, (1 << ARMREG_R0)|(1 << ARMREG_R1)|(1 << ARMREG_R2));
1881
1882 imm8 = mono_arm_is_rotated_imm8 (pagesize, &rot_amount);
1883 ARM_SUB_REG_IMM (code, ARMREG_IP, ARMREG_IP, imm8, rot_amount);
1884 ARM_LDR_IMM (code, ARMREG_R0, ARMREG_IP, -8);
1885
1886 /* The IMT method is in v5, r0 has the imt array address */
1887
1888 loop_start = code;
1889 ARM_LDR_IMM (code, ARMREG_R1, ARMREG_R0, 0);
1890 ARM_CMP_REG_REG (code, ARMREG_R1, ARMREG_V5);
1891 imt_found_check = code;
1892 ARM_B_COND (code, ARMCOND_EQ, 0);
1893
1894 /* End-of-loop check */
1895 ARM_CMP_REG_IMM (code, ARMREG_R1, 0, 0);
1896 loop_end_check = code;
1897 ARM_B_COND (code, ARMCOND_EQ, 0);
1898
1899 /* Loop footer */
1900 ARM_ADD_REG_IMM8 (code, ARMREG_R0, ARMREG_R0, sizeof (gpointer) * 2);
1901 loop_branch_back = code;
1902 ARM_B (code, 0);
1903 arm_patch (loop_branch_back, loop_start);
1904
1905 /* Match */
1906 arm_patch (imt_found_check, code);
1907 ARM_LDR_IMM (code, ARMREG_R0, ARMREG_R0, 4);
1908 ARM_LDR_IMM (code, ARMREG_R0, ARMREG_R0, 0);
1909 /* Save it to the third stack slot */
1910 ARM_STR_IMM (code, ARMREG_R0, ARMREG_SP, 8);
1911 /* Restore the registers and branch */
1912 ARM_POP (code, (1 << ARMREG_R0)|(1 << ARMREG_R1)|(1 << ARMREG_PC));
1913
1914 /* No match */
1915 arm_patch (loop_end_check, code);
1916 ARM_LDR_IMM (code, ARMREG_R0, ARMREG_R0, 4);
1917 ARM_STR_IMM (code, ARMREG_R0, ARMREG_SP, 8);
1918 ARM_POP (code, (1 << ARMREG_R0)|(1 << ARMREG_R1)|(1 << ARMREG_PC));
1919 ARM_NOP (code);
1920
1921 /* Emit it */
1922 g_assert (code - buf == IMT_TRAMP_SIZE);
1923 emit_bytes (acfg, buf, code - buf);
1924
1925 for (i = 0; i < count; ++i) {
1926 code = buf;
1927 ARM_MOV_REG_REG (code, ARMREG_IP, ARMREG_PC);
1928 ARM_B (code, 0);
1929 arm_patch (code - 4, code - IMT_TRAMP_SIZE - 8 * (i + 1));
1930 g_assert (code - buf == 8);
1931 emit_bytes (acfg, buf, code - buf);
1932 }
1933
1934 acfg->tramp_page_code_offsets [MONO_AOT_TRAMP_SPECIFIC] = 16;
1935 acfg->tramp_page_code_offsets [MONO_AOT_TRAMP_STATIC_RGCTX] = 16;
1936 acfg->tramp_page_code_offsets [MONO_AOT_TRAMP_IMT] = 72;
1937 acfg->tramp_page_code_offsets [MONO_AOT_TRAMP_GSHAREDVT_ARG] = 16;
1938
1939 /* Unwind info for specifc trampolines */
1940 sprintf (symbol, "%sspecific_trampolines_page_gen_p", acfg->user_symbol_prefix);
1941 /* We unwind to the original caller, from the stack, since lr is clobbered */
1942 mono_add_unwind_op_def_cfa (unwind_ops, 0, 0, ARMREG_SP, 14 * sizeof (mgreg_t));
1943 mono_add_unwind_op_offset (unwind_ops, 0, 0, ARMREG_LR, -4);
1944 save_unwind_info (acfg, symbol, unwind_ops);
1945 mono_free_unwind_info (unwind_ops);
1946
1947 sprintf (symbol, "%sspecific_trampolines_page_sp_p", acfg->user_symbol_prefix);
1948 mono_add_unwind_op_def_cfa (unwind_ops, 0, 0, ARMREG_SP, 0);
1949 mono_add_unwind_op_def_cfa_offset (unwind_ops, 4, 0, 14 * sizeof (mgreg_t));
1950 save_unwind_info (acfg, symbol, unwind_ops);
1951 mono_free_unwind_info (unwind_ops);
1952
1953 /* Unwind info for rgctx trampolines */
1954 sprintf (symbol, "%srgctx_trampolines_page_gen_p", acfg->user_symbol_prefix);
1955 mono_add_unwind_op_def_cfa (unwind_ops, 0, 0, ARMREG_SP, 0);
1956 save_unwind_info (acfg, symbol, unwind_ops);
1957
1958 sprintf (symbol, "%srgctx_trampolines_page_sp_p", acfg->user_symbol_prefix);
1959 save_unwind_info (acfg, symbol, unwind_ops);
1960 mono_free_unwind_info (unwind_ops);
1961
1962 /* Unwind info for gsharedvt trampolines */
1963 sprintf (symbol, "%sgsharedvt_trampolines_page_gen_p", acfg->user_symbol_prefix);
1964 mono_add_unwind_op_def_cfa (unwind_ops, 0, 0, ARMREG_SP, 0);
1965 mono_add_unwind_op_def_cfa_offset (unwind_ops, 4, 0, 4 * sizeof (mgreg_t));
1966 save_unwind_info (acfg, symbol, unwind_ops);
1967 mono_free_unwind_info (unwind_ops);
1968
1969 sprintf (symbol, "%sgsharedvt_trampolines_page_sp_p", acfg->user_symbol_prefix);
1970 mono_add_unwind_op_def_cfa (unwind_ops, 0, 0, ARMREG_SP, 0);
1971 save_unwind_info (acfg, symbol, unwind_ops);
1972 mono_free_unwind_info (unwind_ops);
1973
1974 /* Unwind info for imt trampolines */
1975 sprintf (symbol, "%simt_trampolines_page_gen_p", acfg->user_symbol_prefix);
1976 mono_add_unwind_op_def_cfa (unwind_ops, 0, 0, ARMREG_SP, 0);
1977 mono_add_unwind_op_def_cfa_offset (unwind_ops, 4, 0, 3 * sizeof (mgreg_t));
1978 save_unwind_info (acfg, symbol, unwind_ops);
1979 mono_free_unwind_info (unwind_ops);
1980
1981 sprintf (symbol, "%simt_trampolines_page_sp_p", acfg->user_symbol_prefix);
1982 mono_add_unwind_op_def_cfa (unwind_ops, 0, 0, ARMREG_SP, 0);
1983 save_unwind_info (acfg, symbol, unwind_ops);
1984 mono_free_unwind_info (unwind_ops);
1985 #elif defined(TARGET_ARM64)
1986 arm64_emit_specific_trampoline_pages (acfg);
1987 #endif
1988 }
1989
1990 /*
1991 * arch_emit_specific_trampoline:
1992 *
1993 * Emit code for a specific trampoline. OFFSET is the offset of the first of
1994 * two GOT slots which contain the generic trampoline address and the trampoline
1995 * argument. TRAMP_SIZE is set to the size of the emitted trampoline.
1996 */
1997 static void
arch_emit_specific_trampoline(MonoAotCompile * acfg,int offset,int * tramp_size)1998 arch_emit_specific_trampoline (MonoAotCompile *acfg, int offset, int *tramp_size)
1999 {
2000 /*
2001 * The trampolines created here are variations of the specific
2002 * trampolines created in mono_arch_create_specific_trampoline (). The
2003 * differences are:
2004 * - the generic trampoline address is taken from a got slot.
2005 * - the offset of the got slot where the trampoline argument is stored
2006 * is embedded in the instruction stream, and the generic trampoline
2007 * can load the argument by loading the offset, adding it to the
2008 * address of the trampoline to get the address of the got slot, and
2009 * loading the argument from there.
2010 * - all the trampolines should be of the same length.
2011 */
2012 #if defined(TARGET_AMD64)
2013 /* This should be exactly 8 bytes long */
2014 *tramp_size = 8;
2015 /* call *<offset>(%rip) */
2016 if (acfg->llvm) {
2017 emit_unset_mode (acfg);
2018 fprintf (acfg->fp, "call *%s+%d(%%rip)\n", acfg->got_symbol, (int)(offset * sizeof (gpointer)));
2019 emit_zero_bytes (acfg, 2);
2020 } else {
2021 emit_byte (acfg, '\x41');
2022 emit_byte (acfg, '\xff');
2023 emit_byte (acfg, '\x15');
2024 emit_symbol_diff (acfg, acfg->got_symbol, ".", (offset * sizeof (gpointer)) - 4);
2025 emit_zero_bytes (acfg, 1);
2026 }
2027 #elif defined(TARGET_ARM)
2028 guint8 buf [128];
2029 guint8 *code;
2030
2031 /* This should be exactly 20 bytes long */
2032 *tramp_size = 20;
2033 code = buf;
2034 ARM_PUSH (code, 0x5fff);
2035 ARM_LDR_IMM (code, ARMREG_R1, ARMREG_PC, 4);
2036 /* Load the value from the GOT */
2037 ARM_LDR_REG_REG (code, ARMREG_R1, ARMREG_PC, ARMREG_R1);
2038 /* Branch to it */
2039 ARM_BLX_REG (code, ARMREG_R1);
2040
2041 g_assert (code - buf == 16);
2042
2043 /* Emit it */
2044 emit_bytes (acfg, buf, code - buf);
2045 /*
2046 * Only one offset is needed, since the second one would be equal to the
2047 * first one.
2048 */
2049 emit_symbol_diff (acfg, acfg->got_symbol, ".", (offset * sizeof (gpointer)) - 4 + 4);
2050 //emit_symbol_diff (acfg, acfg->got_symbol, ".", ((offset + 1) * sizeof (gpointer)) - 4 + 8);
2051 #elif defined(TARGET_ARM64)
2052 arm64_emit_specific_trampoline (acfg, offset, tramp_size);
2053 #elif defined(TARGET_POWERPC)
2054 guint8 buf [128];
2055 guint8 *code;
2056
2057 *tramp_size = 4;
2058 code = buf;
2059
2060 /*
2061 * PPC has no ip relative addressing, so we need to compute the address
2062 * of the mscorlib got. That is slow and complex, so instead, we store it
2063 * in the second got slot of every aot image. The caller already computed
2064 * the address of its got and placed it into r30.
2065 */
2066 emit_unset_mode (acfg);
2067 /* Load mscorlib got address */
2068 fprintf (acfg->fp, "%s 0, %d(30)\n", PPC_LD_OP, (int)sizeof (gpointer));
2069 /* Load generic trampoline address */
2070 fprintf (acfg->fp, "lis 11, %d@h\n", (int)(offset * sizeof (gpointer)));
2071 fprintf (acfg->fp, "ori 11, 11, %d@l\n", (int)(offset * sizeof (gpointer)));
2072 fprintf (acfg->fp, "%s 11, 11, 0\n", PPC_LDX_OP);
2073 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
2074 fprintf (acfg->fp, "%s 11, 0(11)\n", PPC_LD_OP);
2075 #endif
2076 fprintf (acfg->fp, "mtctr 11\n");
2077 /* Load trampoline argument */
2078 /* On ppc, we pass it normally to the generic trampoline */
2079 fprintf (acfg->fp, "lis 11, %d@h\n", (int)((offset + 1) * sizeof (gpointer)));
2080 fprintf (acfg->fp, "ori 11, 11, %d@l\n", (int)((offset + 1) * sizeof (gpointer)));
2081 fprintf (acfg->fp, "%s 0, 11, 0\n", PPC_LDX_OP);
2082 /* Branch to generic trampoline */
2083 fprintf (acfg->fp, "bctr\n");
2084
2085 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
2086 *tramp_size = 10 * 4;
2087 #else
2088 *tramp_size = 9 * 4;
2089 #endif
2090 #elif defined(TARGET_X86)
2091 guint8 buf [128];
2092 guint8 *code;
2093
2094 /* Similar to the PPC code above */
2095
2096 /* FIXME: Could this clobber the register needed by get_vcall_slot () ? */
2097
2098 code = buf;
2099 /* Load mscorlib got address */
2100 x86_mov_reg_membase (code, X86_ECX, MONO_ARCH_GOT_REG, sizeof (gpointer), 4);
2101 /* Push trampoline argument */
2102 x86_push_membase (code, X86_ECX, (offset + 1) * sizeof (gpointer));
2103 /* Load generic trampoline address */
2104 x86_mov_reg_membase (code, X86_ECX, X86_ECX, offset * sizeof (gpointer), 4);
2105 /* Branch to generic trampoline */
2106 x86_jump_reg (code, X86_ECX);
2107
2108 emit_bytes (acfg, buf, code - buf);
2109
2110 *tramp_size = 17;
2111 g_assert (code - buf == *tramp_size);
2112 #else
2113 g_assert_not_reached ();
2114 #endif
2115 }
2116
2117 /*
2118 * arch_emit_unbox_trampoline:
2119 *
2120 * Emit code for the unbox trampoline for METHOD used in the full-aot case.
2121 * CALL_TARGET is the symbol pointing to the native code of METHOD.
2122 */
2123 static void
arch_emit_unbox_trampoline(MonoAotCompile * acfg,MonoCompile * cfg,MonoMethod * method,const char * call_target)2124 arch_emit_unbox_trampoline (MonoAotCompile *acfg, MonoCompile *cfg, MonoMethod *method, const char *call_target)
2125 {
2126 #if defined(TARGET_AMD64)
2127 guint8 buf [32];
2128 guint8 *code;
2129 int this_reg;
2130
2131 this_reg = mono_arch_get_this_arg_reg (NULL);
2132 code = buf;
2133 amd64_alu_reg_imm (code, X86_ADD, this_reg, sizeof (MonoObject));
2134
2135 emit_bytes (acfg, buf, code - buf);
2136 /* jump <method> */
2137 if (acfg->llvm) {
2138 emit_unset_mode (acfg);
2139 fprintf (acfg->fp, "jmp %s\n", call_target);
2140 } else {
2141 emit_byte (acfg, '\xe9');
2142 emit_symbol_diff (acfg, call_target, ".", -4);
2143 }
2144 #elif defined(TARGET_X86)
2145 guint8 buf [32];
2146 guint8 *code;
2147 int this_pos = 4;
2148
2149 code = buf;
2150
2151 x86_alu_membase_imm (code, X86_ADD, X86_ESP, this_pos, sizeof (MonoObject));
2152
2153 emit_bytes (acfg, buf, code - buf);
2154
2155 /* jump <method> */
2156 emit_byte (acfg, '\xe9');
2157 emit_symbol_diff (acfg, call_target, ".", -4);
2158 #elif defined(TARGET_ARM)
2159 guint8 buf [128];
2160 guint8 *code;
2161
2162 if (acfg->thumb_mixed && cfg->compile_llvm) {
2163 fprintf (acfg->fp, "add r0, r0, #%d\n", (int)sizeof (MonoObject));
2164 fprintf (acfg->fp, "b %s\n", call_target);
2165 fprintf (acfg->fp, ".arm\n");
2166 fprintf (acfg->fp, ".align 2\n");
2167 return;
2168 }
2169
2170 code = buf;
2171
2172 ARM_ADD_REG_IMM8 (code, ARMREG_R0, ARMREG_R0, sizeof (MonoObject));
2173
2174 emit_bytes (acfg, buf, code - buf);
2175 /* jump to method */
2176 if (acfg->thumb_mixed && cfg->compile_llvm)
2177 fprintf (acfg->fp, "\n\tbx %s\n", call_target);
2178 else
2179 fprintf (acfg->fp, "\n\tb %s\n", call_target);
2180 #elif defined(TARGET_ARM64)
2181 arm64_emit_unbox_trampoline (acfg, cfg, method, call_target);
2182 #elif defined(TARGET_POWERPC)
2183 int this_pos = 3;
2184
2185 fprintf (acfg->fp, "\n\taddi %d, %d, %d\n", this_pos, this_pos, (int)sizeof (MonoObject));
2186 fprintf (acfg->fp, "\n\tb %s\n", call_target);
2187 #else
2188 g_assert_not_reached ();
2189 #endif
2190 }
2191
2192 /*
2193 * arch_emit_static_rgctx_trampoline:
2194 *
2195 * Emit code for a static rgctx trampoline. OFFSET is the offset of the first of
2196 * two GOT slots which contain the rgctx argument, and the method to jump to.
2197 * TRAMP_SIZE is set to the size of the emitted trampoline.
2198 * These kinds of trampolines cannot be enumerated statically, since there could
2199 * be one trampoline per method instantiation, so we emit the same code for all
2200 * trampolines, and parameterize them using two GOT slots.
2201 */
2202 static void
arch_emit_static_rgctx_trampoline(MonoAotCompile * acfg,int offset,int * tramp_size)2203 arch_emit_static_rgctx_trampoline (MonoAotCompile *acfg, int offset, int *tramp_size)
2204 {
2205 #if defined(TARGET_AMD64)
2206 /* This should be exactly 13 bytes long */
2207 *tramp_size = 13;
2208
2209 if (acfg->llvm) {
2210 emit_unset_mode (acfg);
2211 fprintf (acfg->fp, "mov %s+%d(%%rip), %%r10\n", acfg->got_symbol, (int)(offset * sizeof (gpointer)));
2212 fprintf (acfg->fp, "jmp *%s+%d(%%rip)\n", acfg->got_symbol, (int)((offset + 1) * sizeof (gpointer)));
2213 } else {
2214 /* mov <OFFSET>(%rip), %r10 */
2215 emit_byte (acfg, '\x4d');
2216 emit_byte (acfg, '\x8b');
2217 emit_byte (acfg, '\x15');
2218 emit_symbol_diff (acfg, acfg->got_symbol, ".", (offset * sizeof (gpointer)) - 4);
2219
2220 /* jmp *<offset>(%rip) */
2221 emit_byte (acfg, '\xff');
2222 emit_byte (acfg, '\x25');
2223 emit_symbol_diff (acfg, acfg->got_symbol, ".", ((offset + 1) * sizeof (gpointer)) - 4);
2224 }
2225 #elif defined(TARGET_ARM)
2226 guint8 buf [128];
2227 guint8 *code;
2228
2229 /* This should be exactly 24 bytes long */
2230 *tramp_size = 24;
2231 code = buf;
2232 /* Load rgctx value */
2233 ARM_LDR_IMM (code, ARMREG_IP, ARMREG_PC, 8);
2234 ARM_LDR_REG_REG (code, MONO_ARCH_RGCTX_REG, ARMREG_PC, ARMREG_IP);
2235 /* Load branch addr + branch */
2236 ARM_LDR_IMM (code, ARMREG_IP, ARMREG_PC, 4);
2237 ARM_LDR_REG_REG (code, ARMREG_PC, ARMREG_PC, ARMREG_IP);
2238
2239 g_assert (code - buf == 16);
2240
2241 /* Emit it */
2242 emit_bytes (acfg, buf, code - buf);
2243 emit_symbol_diff (acfg, acfg->got_symbol, ".", (offset * sizeof (gpointer)) - 4 + 8);
2244 emit_symbol_diff (acfg, acfg->got_symbol, ".", ((offset + 1) * sizeof (gpointer)) - 4 + 4);
2245 #elif defined(TARGET_ARM64)
2246 arm64_emit_static_rgctx_trampoline (acfg, offset, tramp_size);
2247 #elif defined(TARGET_POWERPC)
2248 guint8 buf [128];
2249 guint8 *code;
2250
2251 *tramp_size = 4;
2252 code = buf;
2253
2254 /*
2255 * PPC has no ip relative addressing, so we need to compute the address
2256 * of the mscorlib got. That is slow and complex, so instead, we store it
2257 * in the second got slot of every aot image. The caller already computed
2258 * the address of its got and placed it into r30.
2259 */
2260 emit_unset_mode (acfg);
2261 /* Load mscorlib got address */
2262 fprintf (acfg->fp, "%s 0, %d(30)\n", PPC_LD_OP, (int)sizeof (gpointer));
2263 /* Load rgctx */
2264 fprintf (acfg->fp, "lis 11, %d@h\n", (int)(offset * sizeof (gpointer)));
2265 fprintf (acfg->fp, "ori 11, 11, %d@l\n", (int)(offset * sizeof (gpointer)));
2266 fprintf (acfg->fp, "%s %d, 11, 0\n", PPC_LDX_OP, MONO_ARCH_RGCTX_REG);
2267 /* Load target address */
2268 fprintf (acfg->fp, "lis 11, %d@h\n", (int)((offset + 1) * sizeof (gpointer)));
2269 fprintf (acfg->fp, "ori 11, 11, %d@l\n", (int)((offset + 1) * sizeof (gpointer)));
2270 fprintf (acfg->fp, "%s 11, 11, 0\n", PPC_LDX_OP);
2271 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
2272 fprintf (acfg->fp, "%s 2, %d(11)\n", PPC_LD_OP, (int)sizeof (gpointer));
2273 fprintf (acfg->fp, "%s 11, 0(11)\n", PPC_LD_OP);
2274 #endif
2275 fprintf (acfg->fp, "mtctr 11\n");
2276 /* Branch to the target address */
2277 fprintf (acfg->fp, "bctr\n");
2278
2279 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
2280 *tramp_size = 11 * 4;
2281 #else
2282 *tramp_size = 9 * 4;
2283 #endif
2284
2285 #elif defined(TARGET_X86)
2286 guint8 buf [128];
2287 guint8 *code;
2288
2289 /* Similar to the PPC code above */
2290
2291 g_assert (MONO_ARCH_RGCTX_REG != X86_ECX);
2292
2293 code = buf;
2294 /* Load mscorlib got address */
2295 x86_mov_reg_membase (code, X86_ECX, MONO_ARCH_GOT_REG, sizeof (gpointer), 4);
2296 /* Load arg */
2297 x86_mov_reg_membase (code, MONO_ARCH_RGCTX_REG, X86_ECX, offset * sizeof (gpointer), 4);
2298 /* Branch to the target address */
2299 x86_jump_membase (code, X86_ECX, (offset + 1) * sizeof (gpointer));
2300
2301 emit_bytes (acfg, buf, code - buf);
2302
2303 *tramp_size = 15;
2304 g_assert (code - buf == *tramp_size);
2305 #else
2306 g_assert_not_reached ();
2307 #endif
2308 }
2309
2310 /*
2311 * arch_emit_imt_trampoline:
2312 *
2313 * Emit an IMT trampoline usable in full-aot mode. The trampoline uses 1 got slot which
2314 * points to an array of pointer pairs. The pairs of the form [key, ptr], where
2315 * key is the IMT key, and ptr holds the address of a memory location holding
2316 * the address to branch to if the IMT arg matches the key. The array is
2317 * terminated by a pair whose key is NULL, and whose ptr is the address of the
2318 * fail_tramp.
2319 * TRAMP_SIZE is set to the size of the emitted trampoline.
2320 */
2321 static void
arch_emit_imt_trampoline(MonoAotCompile * acfg,int offset,int * tramp_size)2322 arch_emit_imt_trampoline (MonoAotCompile *acfg, int offset, int *tramp_size)
2323 {
2324 #if defined(TARGET_AMD64)
2325 guint8 *buf, *code;
2326 guint8 *labels [16];
2327 guint8 mov_buf[3];
2328 guint8 *mov_buf_ptr = mov_buf;
2329
2330 const int kSizeOfMove = 7;
2331
2332 code = buf = (guint8 *)g_malloc (256);
2333
2334 /* FIXME: Optimize this, i.e. use binary search etc. */
2335 /* Maybe move the body into a separate function (slower, but much smaller) */
2336
2337 /* MONO_ARCH_IMT_SCRATCH_REG is a free register */
2338
2339 if (acfg->llvm) {
2340 emit_unset_mode (acfg);
2341 fprintf (acfg->fp, "mov %s+%d(%%rip), %s\n", acfg->got_symbol, (int)(offset * sizeof (gpointer)), mono_arch_regname (MONO_ARCH_IMT_SCRATCH_REG));
2342 }
2343
2344 labels [0] = code;
2345 amd64_alu_membase_imm (code, X86_CMP, MONO_ARCH_IMT_SCRATCH_REG, 0, 0);
2346 labels [1] = code;
2347 amd64_branch8 (code, X86_CC_Z, 0, FALSE);
2348
2349 /* Check key */
2350 amd64_alu_membase_reg_size (code, X86_CMP, MONO_ARCH_IMT_SCRATCH_REG, 0, MONO_ARCH_IMT_REG, sizeof (gpointer));
2351 labels [2] = code;
2352 amd64_branch8 (code, X86_CC_Z, 0, FALSE);
2353
2354 /* Loop footer */
2355 amd64_alu_reg_imm (code, X86_ADD, MONO_ARCH_IMT_SCRATCH_REG, 2 * sizeof (gpointer));
2356 amd64_jump_code (code, labels [0]);
2357
2358 /* Match */
2359 mono_amd64_patch (labels [2], code);
2360 amd64_mov_reg_membase (code, MONO_ARCH_IMT_SCRATCH_REG, MONO_ARCH_IMT_SCRATCH_REG, sizeof (gpointer), sizeof (gpointer));
2361 amd64_jump_membase (code, MONO_ARCH_IMT_SCRATCH_REG, 0);
2362
2363 /* No match */
2364 mono_amd64_patch (labels [1], code);
2365 /* Load fail tramp */
2366 amd64_alu_reg_imm (code, X86_ADD, MONO_ARCH_IMT_SCRATCH_REG, sizeof (gpointer));
2367 /* Check if there is a fail tramp */
2368 amd64_alu_membase_imm (code, X86_CMP, MONO_ARCH_IMT_SCRATCH_REG, 0, 0);
2369 labels [3] = code;
2370 amd64_branch8 (code, X86_CC_Z, 0, FALSE);
2371 /* Jump to fail tramp */
2372 amd64_jump_membase (code, MONO_ARCH_IMT_SCRATCH_REG, 0);
2373
2374 /* Fail */
2375 mono_amd64_patch (labels [3], code);
2376 x86_breakpoint (code);
2377
2378 if (!acfg->llvm) {
2379 /* mov <OFFSET>(%rip), MONO_ARCH_IMT_SCRATCH_REG */
2380 amd64_emit_rex (mov_buf_ptr, sizeof(gpointer), MONO_ARCH_IMT_SCRATCH_REG, 0, AMD64_RIP);
2381 *(mov_buf_ptr)++ = (unsigned char)0x8b; /* mov opcode */
2382 x86_address_byte (mov_buf_ptr, 0, MONO_ARCH_IMT_SCRATCH_REG & 0x7, 5);
2383 emit_bytes (acfg, mov_buf, mov_buf_ptr - mov_buf);
2384 emit_symbol_diff (acfg, acfg->got_symbol, ".", (offset * sizeof (gpointer)) - 4);
2385 }
2386 emit_bytes (acfg, buf, code - buf);
2387
2388 *tramp_size = code - buf + kSizeOfMove;
2389
2390 g_free (buf);
2391
2392 #elif defined(TARGET_X86)
2393 guint8 *buf, *code;
2394 guint8 *labels [16];
2395
2396 code = buf = g_malloc (256);
2397
2398 /* Allocate a temporary stack slot */
2399 x86_push_reg (code, X86_EAX);
2400 /* Save EAX */
2401 x86_push_reg (code, X86_EAX);
2402
2403 /* Load mscorlib got address */
2404 x86_mov_reg_membase (code, X86_EAX, MONO_ARCH_GOT_REG, sizeof (gpointer), 4);
2405 /* Load arg */
2406 x86_mov_reg_membase (code, X86_EAX, X86_EAX, offset * sizeof (gpointer), 4);
2407
2408 labels [0] = code;
2409 x86_alu_membase_imm (code, X86_CMP, X86_EAX, 0, 0);
2410 labels [1] = code;
2411 x86_branch8 (code, X86_CC_Z, FALSE, 0);
2412
2413 /* Check key */
2414 x86_alu_membase_reg (code, X86_CMP, X86_EAX, 0, MONO_ARCH_IMT_REG);
2415 labels [2] = code;
2416 x86_branch8 (code, X86_CC_Z, FALSE, 0);
2417
2418 /* Loop footer */
2419 x86_alu_reg_imm (code, X86_ADD, X86_EAX, 2 * sizeof (gpointer));
2420 x86_jump_code (code, labels [0]);
2421
2422 /* Match */
2423 mono_x86_patch (labels [2], code);
2424 x86_mov_reg_membase (code, X86_EAX, X86_EAX, sizeof (gpointer), 4);
2425 x86_mov_reg_membase (code, X86_EAX, X86_EAX, 0, 4);
2426 /* Save the target address to the temporary stack location */
2427 x86_mov_membase_reg (code, X86_ESP, 4, X86_EAX, 4);
2428 /* Restore EAX */
2429 x86_pop_reg (code, X86_EAX);
2430 /* Jump to the target address */
2431 x86_ret (code);
2432
2433 /* No match */
2434 mono_x86_patch (labels [1], code);
2435 /* Load fail tramp */
2436 x86_mov_reg_membase (code, X86_EAX, X86_EAX, sizeof (gpointer), 4);
2437 x86_alu_membase_imm (code, X86_CMP, X86_EAX, 0, 0);
2438 labels [3] = code;
2439 x86_branch8 (code, X86_CC_Z, FALSE, 0);
2440 /* Jump to fail tramp */
2441 x86_mov_membase_reg (code, X86_ESP, 4, X86_EAX, 4);
2442 x86_pop_reg (code, X86_EAX);
2443 x86_ret (code);
2444
2445 /* Fail */
2446 mono_x86_patch (labels [3], code);
2447 x86_breakpoint (code);
2448
2449 emit_bytes (acfg, buf, code - buf);
2450
2451 *tramp_size = code - buf;
2452
2453 g_free (buf);
2454
2455 #elif defined(TARGET_ARM)
2456 guint8 buf [128];
2457 guint8 *code, *code2, *labels [16];
2458
2459 code = buf;
2460
2461 /* The IMT method is in v5 */
2462
2463 /* Need at least two free registers, plus a slot for storing the pc */
2464 ARM_PUSH (code, (1 << ARMREG_R0)|(1 << ARMREG_R1)|(1 << ARMREG_R2));
2465 labels [0] = code;
2466 /* Load the parameter from the GOT */
2467 ARM_LDR_IMM (code, ARMREG_R0, ARMREG_PC, 0);
2468 ARM_LDR_REG_REG (code, ARMREG_R0, ARMREG_PC, ARMREG_R0);
2469
2470 labels [1] = code;
2471 ARM_LDR_IMM (code, ARMREG_R1, ARMREG_R0, 0);
2472 ARM_CMP_REG_REG (code, ARMREG_R1, ARMREG_V5);
2473 labels [2] = code;
2474 ARM_B_COND (code, ARMCOND_EQ, 0);
2475
2476 /* End-of-loop check */
2477 ARM_CMP_REG_IMM (code, ARMREG_R1, 0, 0);
2478 labels [3] = code;
2479 ARM_B_COND (code, ARMCOND_EQ, 0);
2480
2481 /* Loop footer */
2482 ARM_ADD_REG_IMM8 (code, ARMREG_R0, ARMREG_R0, sizeof (gpointer) * 2);
2483 labels [4] = code;
2484 ARM_B (code, 0);
2485 arm_patch (labels [4], labels [1]);
2486
2487 /* Match */
2488 arm_patch (labels [2], code);
2489 ARM_LDR_IMM (code, ARMREG_R0, ARMREG_R0, 4);
2490 ARM_LDR_IMM (code, ARMREG_R0, ARMREG_R0, 0);
2491 /* Save it to the third stack slot */
2492 ARM_STR_IMM (code, ARMREG_R0, ARMREG_SP, 8);
2493 /* Restore the registers and branch */
2494 ARM_POP (code, (1 << ARMREG_R0)|(1 << ARMREG_R1)|(1 << ARMREG_PC));
2495
2496 /* No match */
2497 arm_patch (labels [3], code);
2498 ARM_LDR_IMM (code, ARMREG_R0, ARMREG_R0, 4);
2499 ARM_STR_IMM (code, ARMREG_R0, ARMREG_SP, 8);
2500 ARM_POP (code, (1 << ARMREG_R0)|(1 << ARMREG_R1)|(1 << ARMREG_PC));
2501
2502 /* Fixup offset */
2503 code2 = labels [0];
2504 ARM_LDR_IMM (code2, ARMREG_R0, ARMREG_PC, (code - (labels [0] + 8)));
2505
2506 emit_bytes (acfg, buf, code - buf);
2507 emit_symbol_diff (acfg, acfg->got_symbol, ".", (offset * sizeof (gpointer)) + (code - (labels [0] + 8)) - 4);
2508
2509 *tramp_size = code - buf + 4;
2510 #elif defined(TARGET_ARM64)
2511 arm64_emit_imt_trampoline (acfg, offset, tramp_size);
2512 #elif defined(TARGET_POWERPC)
2513 guint8 buf [128];
2514 guint8 *code, *labels [16];
2515
2516 code = buf;
2517
2518 /* Load the mscorlib got address */
2519 ppc_ldptr (code, ppc_r12, sizeof (gpointer), ppc_r30);
2520 /* Load the parameter from the GOT */
2521 ppc_load (code, ppc_r0, offset * sizeof (gpointer));
2522 ppc_ldptr_indexed (code, ppc_r12, ppc_r12, ppc_r0);
2523
2524 /* Load and check key */
2525 labels [1] = code;
2526 ppc_ldptr (code, ppc_r0, 0, ppc_r12);
2527 ppc_cmp (code, 0, sizeof (gpointer) == 8 ? 1 : 0, ppc_r0, MONO_ARCH_IMT_REG);
2528 labels [2] = code;
2529 ppc_bc (code, PPC_BR_TRUE, PPC_BR_EQ, 0);
2530
2531 /* End-of-loop check */
2532 ppc_cmpi (code, 0, sizeof (gpointer) == 8 ? 1 : 0, ppc_r0, 0);
2533 labels [3] = code;
2534 ppc_bc (code, PPC_BR_TRUE, PPC_BR_EQ, 0);
2535
2536 /* Loop footer */
2537 ppc_addi (code, ppc_r12, ppc_r12, 2 * sizeof (gpointer));
2538 labels [4] = code;
2539 ppc_b (code, 0);
2540 mono_ppc_patch (labels [4], labels [1]);
2541
2542 /* Match */
2543 mono_ppc_patch (labels [2], code);
2544 ppc_ldptr (code, ppc_r12, sizeof (gpointer), ppc_r12);
2545 /* r12 now contains the value of the vtable slot */
2546 /* this is not a function descriptor on ppc64 */
2547 ppc_ldptr (code, ppc_r12, 0, ppc_r12);
2548 ppc_mtctr (code, ppc_r12);
2549 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
2550
2551 /* Fail */
2552 mono_ppc_patch (labels [3], code);
2553 /* FIXME: */
2554 ppc_break (code);
2555
2556 *tramp_size = code - buf;
2557
2558 emit_bytes (acfg, buf, code - buf);
2559 #else
2560 g_assert_not_reached ();
2561 #endif
2562 }
2563
2564
2565 #if defined (TARGET_AMD64)
2566
2567 static void
amd64_emit_load_got_slot(MonoAotCompile * acfg,int dreg,int got_slot)2568 amd64_emit_load_got_slot (MonoAotCompile *acfg, int dreg, int got_slot)
2569 {
2570
2571 g_assert (acfg->fp);
2572 emit_unset_mode (acfg);
2573
2574 fprintf (acfg->fp, "mov %s+%d(%%rip), %s\n", acfg->got_symbol, (unsigned int) ((got_slot * sizeof (gpointer))), mono_arch_regname (dreg));
2575 }
2576
2577 #endif
2578
2579
2580 /*
2581 * arch_emit_gsharedvt_arg_trampoline:
2582 *
2583 * Emit code for a gsharedvt arg trampoline. OFFSET is the offset of the first of
2584 * two GOT slots which contain the argument, and the code to jump to.
2585 * TRAMP_SIZE is set to the size of the emitted trampoline.
2586 * These kinds of trampolines cannot be enumerated statically, since there could
2587 * be one trampoline per method instantiation, so we emit the same code for all
2588 * trampolines, and parameterize them using two GOT slots.
2589 */
2590 static void
arch_emit_gsharedvt_arg_trampoline(MonoAotCompile * acfg,int offset,int * tramp_size)2591 arch_emit_gsharedvt_arg_trampoline (MonoAotCompile *acfg, int offset, int *tramp_size)
2592 {
2593 #if defined(TARGET_X86)
2594 guint8 buf [128];
2595 guint8 *code;
2596
2597 /* Similar to the PPC code above */
2598
2599 g_assert (MONO_ARCH_RGCTX_REG != X86_ECX);
2600
2601 code = buf;
2602 /* Load mscorlib got address */
2603 x86_mov_reg_membase (code, X86_ECX, MONO_ARCH_GOT_REG, sizeof (gpointer), 4);
2604 /* Load arg */
2605 x86_mov_reg_membase (code, X86_EAX, X86_ECX, offset * sizeof (gpointer), 4);
2606 /* Branch to the target address */
2607 x86_jump_membase (code, X86_ECX, (offset + 1) * sizeof (gpointer));
2608
2609 emit_bytes (acfg, buf, code - buf);
2610
2611 *tramp_size = 15;
2612 g_assert (code - buf == *tramp_size);
2613 #elif defined(TARGET_ARM)
2614 guint8 buf [128];
2615 guint8 *code;
2616
2617 /* The same as mono_arch_get_gsharedvt_arg_trampoline (), but for AOT */
2618 /* Similar to arch_emit_specific_trampoline () */
2619 *tramp_size = 24;
2620 code = buf;
2621 ARM_PUSH (code, (1 << ARMREG_R0) | (1 << ARMREG_R1) | (1 << ARMREG_R2) | (1 << ARMREG_R3));
2622 ARM_LDR_IMM (code, ARMREG_R1, ARMREG_PC, 8);
2623 /* Load the arg value from the GOT */
2624 ARM_LDR_REG_REG (code, ARMREG_R0, ARMREG_PC, ARMREG_R1);
2625 /* Load the addr from the GOT */
2626 ARM_LDR_REG_REG (code, ARMREG_R1, ARMREG_PC, ARMREG_R1);
2627 /* Branch to it */
2628 ARM_BX (code, ARMREG_R1);
2629
2630 g_assert (code - buf == 20);
2631
2632 /* Emit it */
2633 emit_bytes (acfg, buf, code - buf);
2634 emit_symbol_diff (acfg, acfg->got_symbol, ".", (offset * sizeof (gpointer)) + 4);
2635 #elif defined(TARGET_ARM64)
2636 arm64_emit_gsharedvt_arg_trampoline (acfg, offset, tramp_size);
2637 #elif defined (TARGET_AMD64)
2638
2639 amd64_emit_load_got_slot (acfg, AMD64_RAX, offset);
2640 amd64_emit_load_got_slot (acfg, MONO_ARCH_IMT_SCRATCH_REG, offset + 1);
2641 g_assert (AMD64_R11 == MONO_ARCH_IMT_SCRATCH_REG);
2642 fprintf (acfg->fp, "jmp *%%r11\n");
2643
2644 *tramp_size = 0x11;
2645 #else
2646 g_assert_not_reached ();
2647 #endif
2648 }
2649
2650 /* END OF ARCH SPECIFIC CODE */
2651
2652 static guint32
mono_get_field_token(MonoClassField * field)2653 mono_get_field_token (MonoClassField *field)
2654 {
2655 MonoClass *klass = field->parent;
2656 int i;
2657
2658 int fcount = mono_class_get_field_count (klass);
2659 for (i = 0; i < fcount; ++i) {
2660 if (field == &klass->fields [i])
2661 return MONO_TOKEN_FIELD_DEF | (mono_class_get_first_field_idx (klass) + 1 + i);
2662 }
2663
2664 g_assert_not_reached ();
2665 return 0;
2666 }
2667
2668 static inline void
encode_value(gint32 value,guint8 * buf,guint8 ** endbuf)2669 encode_value (gint32 value, guint8 *buf, guint8 **endbuf)
2670 {
2671 guint8 *p = buf;
2672
2673 //printf ("ENCODE: %d 0x%x.\n", value, value);
2674
2675 /*
2676 * Same encoding as the one used in the metadata, extended to handle values
2677 * greater than 0x1fffffff.
2678 */
2679 if ((value >= 0) && (value <= 127))
2680 *p++ = value;
2681 else if ((value >= 0) && (value <= 16383)) {
2682 p [0] = 0x80 | (value >> 8);
2683 p [1] = value & 0xff;
2684 p += 2;
2685 } else if ((value >= 0) && (value <= 0x1fffffff)) {
2686 p [0] = (value >> 24) | 0xc0;
2687 p [1] = (value >> 16) & 0xff;
2688 p [2] = (value >> 8) & 0xff;
2689 p [3] = value & 0xff;
2690 p += 4;
2691 }
2692 else {
2693 p [0] = 0xff;
2694 p [1] = (value >> 24) & 0xff;
2695 p [2] = (value >> 16) & 0xff;
2696 p [3] = (value >> 8) & 0xff;
2697 p [4] = value & 0xff;
2698 p += 5;
2699 }
2700 if (endbuf)
2701 *endbuf = p;
2702 }
2703
2704 static void
stream_init(MonoDynamicStream * sh)2705 stream_init (MonoDynamicStream *sh)
2706 {
2707 sh->index = 0;
2708 sh->alloc_size = 4096;
2709 sh->data = (char *)g_malloc (4096);
2710
2711 /* So offsets are > 0 */
2712 sh->data [0] = 0;
2713 sh->index ++;
2714 }
2715
2716 static void
make_room_in_stream(MonoDynamicStream * stream,int size)2717 make_room_in_stream (MonoDynamicStream *stream, int size)
2718 {
2719 if (size <= stream->alloc_size)
2720 return;
2721
2722 while (stream->alloc_size <= size) {
2723 if (stream->alloc_size < 4096)
2724 stream->alloc_size = 4096;
2725 else
2726 stream->alloc_size *= 2;
2727 }
2728
2729 stream->data = (char *)g_realloc (stream->data, stream->alloc_size);
2730 }
2731
2732 static guint32
add_stream_data(MonoDynamicStream * stream,const char * data,guint32 len)2733 add_stream_data (MonoDynamicStream *stream, const char *data, guint32 len)
2734 {
2735 guint32 idx;
2736
2737 make_room_in_stream (stream, stream->index + len);
2738 memcpy (stream->data + stream->index, data, len);
2739 idx = stream->index;
2740 stream->index += len;
2741 return idx;
2742 }
2743
2744 /*
2745 * add_to_blob:
2746 *
2747 * Add data to the binary blob inside the aot image. Returns the offset inside the
2748 * blob where the data was stored.
2749 */
2750 static guint32
add_to_blob(MonoAotCompile * acfg,const guint8 * data,guint32 data_len)2751 add_to_blob (MonoAotCompile *acfg, const guint8 *data, guint32 data_len)
2752 {
2753 g_assert (!acfg->blob_closed);
2754
2755 if (acfg->blob.alloc_size == 0)
2756 stream_init (&acfg->blob);
2757
2758 return add_stream_data (&acfg->blob, (char*)data, data_len);
2759 }
2760
2761 static guint32
add_to_blob_aligned(MonoAotCompile * acfg,const guint8 * data,guint32 data_len,guint32 align)2762 add_to_blob_aligned (MonoAotCompile *acfg, const guint8 *data, guint32 data_len, guint32 align)
2763 {
2764 char buf [4] = {0};
2765 guint32 count;
2766
2767 if (acfg->blob.alloc_size == 0)
2768 stream_init (&acfg->blob);
2769
2770 count = acfg->blob.index % align;
2771
2772 /* we assume the stream data will be aligned */
2773 if (count)
2774 add_stream_data (&acfg->blob, buf, 4 - count);
2775
2776 return add_stream_data (&acfg->blob, (char*)data, data_len);
2777 }
2778
2779 /* Emit a table of data into the aot image */
2780 static void
emit_aot_data(MonoAotCompile * acfg,MonoAotFileTable table,const char * symbol,guint8 * data,int size)2781 emit_aot_data (MonoAotCompile *acfg, MonoAotFileTable table, const char *symbol, guint8 *data, int size)
2782 {
2783 if (acfg->data_outfile) {
2784 acfg->table_offsets [(int)table] = acfg->datafile_offset;
2785 fwrite (data,1, size, acfg->data_outfile);
2786 acfg->datafile_offset += size;
2787 // align the data to 8 bytes. Put zeros in the file (so that every build results in consistent output).
2788 int align = 8 - size % 8;
2789 acfg->datafile_offset += align;
2790 guint8 align_buf [16];
2791 memset (&align_buf, 0, sizeof (align_buf));
2792 fwrite (align_buf, align, 1, acfg->data_outfile);
2793 } else if (acfg->llvm) {
2794 mono_llvm_emit_aot_data (symbol, data, size);
2795 } else {
2796 emit_section_change (acfg, RODATA_SECT, 0);
2797 emit_alignment (acfg, 8);
2798 emit_label (acfg, symbol);
2799 emit_bytes (acfg, data, size);
2800 }
2801 }
2802
2803 /*
2804 * emit_offset_table:
2805 *
2806 * Emit a table of increasing offsets in a compact form using differential encoding.
2807 * There is an index entry for each GROUP_SIZE number of entries. The greater the
2808 * group size, the more compact the table becomes, but the slower it becomes to compute
2809 * a given entry. Returns the size of the table.
2810 */
2811 static guint32
emit_offset_table(MonoAotCompile * acfg,const char * symbol,MonoAotFileTable table,int noffsets,int group_size,gint32 * offsets)2812 emit_offset_table (MonoAotCompile *acfg, const char *symbol, MonoAotFileTable table, int noffsets, int group_size, gint32 *offsets)
2813 {
2814 gint32 current_offset;
2815 int i, buf_size, ngroups, index_entry_size;
2816 guint8 *p, *buf;
2817 guint8 *data_p, *data_buf;
2818 guint32 *index_offsets;
2819
2820 ngroups = (noffsets + (group_size - 1)) / group_size;
2821
2822 index_offsets = g_new0 (guint32, ngroups);
2823
2824 buf_size = noffsets * 4;
2825 p = buf = (guint8 *)g_malloc0 (buf_size);
2826
2827 current_offset = 0;
2828 for (i = 0; i < noffsets; ++i) {
2829 //printf ("D: %d -> %d\n", i, offsets [i]);
2830 if ((i % group_size) == 0) {
2831 index_offsets [i / group_size] = p - buf;
2832 /* Emit the full value for these entries */
2833 encode_value (offsets [i], p, &p);
2834 } else {
2835 /* The offsets are allowed to be non-increasing */
2836 //g_assert (offsets [i] >= current_offset);
2837 encode_value (offsets [i] - current_offset, p, &p);
2838 }
2839 current_offset = offsets [i];
2840 }
2841 data_buf = buf;
2842 data_p = p;
2843
2844 if (ngroups && index_offsets [ngroups - 1] < 65000)
2845 index_entry_size = 2;
2846 else
2847 index_entry_size = 4;
2848
2849 buf_size = (data_p - data_buf) + (ngroups * 4) + 16;
2850 p = buf = (guint8 *)g_malloc0 (buf_size);
2851
2852 /* Emit the header */
2853 encode_int (noffsets, p, &p);
2854 encode_int (group_size, p, &p);
2855 encode_int (ngroups, p, &p);
2856 encode_int (index_entry_size, p, &p);
2857
2858 /* Emit the index */
2859 for (i = 0; i < ngroups; ++i) {
2860 if (index_entry_size == 2)
2861 encode_int16 (index_offsets [i], p, &p);
2862 else
2863 encode_int (index_offsets [i], p, &p);
2864 }
2865 /* Emit the data */
2866 memcpy (p, data_buf, data_p - data_buf);
2867 p += data_p - data_buf;
2868
2869 g_assert (p - buf <= buf_size);
2870
2871 emit_aot_data (acfg, table, symbol, buf, p - buf);
2872
2873 g_free (buf);
2874 g_free (data_buf);
2875
2876 return (int)(p - buf);
2877 }
2878
2879 static guint32
get_image_index(MonoAotCompile * cfg,MonoImage * image)2880 get_image_index (MonoAotCompile *cfg, MonoImage *image)
2881 {
2882 guint32 index;
2883
2884 index = GPOINTER_TO_UINT (g_hash_table_lookup (cfg->image_hash, image));
2885 if (index)
2886 return index - 1;
2887 else {
2888 index = g_hash_table_size (cfg->image_hash);
2889 g_hash_table_insert (cfg->image_hash, image, GUINT_TO_POINTER (index + 1));
2890 g_ptr_array_add (cfg->image_table, image);
2891 return index;
2892 }
2893 }
2894
2895 static guint32
find_typespec_for_class(MonoAotCompile * acfg,MonoClass * klass)2896 find_typespec_for_class (MonoAotCompile *acfg, MonoClass *klass)
2897 {
2898 int i;
2899 int len = acfg->image->tables [MONO_TABLE_TYPESPEC].rows;
2900
2901 /* FIXME: Search referenced images as well */
2902 if (!acfg->typespec_classes) {
2903 acfg->typespec_classes = g_hash_table_new (NULL, NULL);
2904 for (i = 0; i < len; i++) {
2905 MonoError error;
2906 int typespec = MONO_TOKEN_TYPE_SPEC | (i + 1);
2907 MonoClass *klass_key = mono_class_get_and_inflate_typespec_checked (acfg->image, typespec, NULL, &error);
2908 if (!is_ok (&error)) {
2909 mono_error_cleanup (&error);
2910 continue;
2911 }
2912 g_hash_table_insert (acfg->typespec_classes, klass_key, GINT_TO_POINTER (typespec));
2913 }
2914 }
2915 return GPOINTER_TO_INT (g_hash_table_lookup (acfg->typespec_classes, klass));
2916 }
2917
2918 static void
2919 encode_method_ref (MonoAotCompile *acfg, MonoMethod *method, guint8 *buf, guint8 **endbuf);
2920
2921 static void
2922 encode_klass_ref (MonoAotCompile *acfg, MonoClass *klass, guint8 *buf, guint8 **endbuf);
2923
2924 static void
2925 encode_ginst (MonoAotCompile *acfg, MonoGenericInst *inst, guint8 *buf, guint8 **endbuf);
2926
2927 static void
2928 encode_type (MonoAotCompile *acfg, MonoType *t, guint8 *buf, guint8 **endbuf);
2929
2930 static void
encode_klass_ref_inner(MonoAotCompile * acfg,MonoClass * klass,guint8 * buf,guint8 ** endbuf)2931 encode_klass_ref_inner (MonoAotCompile *acfg, MonoClass *klass, guint8 *buf, guint8 **endbuf)
2932 {
2933 guint8 *p = buf;
2934
2935 /*
2936 * The encoding begins with one of the MONO_AOT_TYPEREF values, followed by additional
2937 * information.
2938 */
2939
2940 if (mono_class_is_ginst (klass)) {
2941 guint32 token;
2942 g_assert (klass->type_token);
2943
2944 /* Find a typespec for a class if possible */
2945 token = find_typespec_for_class (acfg, klass);
2946 if (token) {
2947 encode_value (MONO_AOT_TYPEREF_TYPESPEC_TOKEN, p, &p);
2948 encode_value (token, p, &p);
2949 } else {
2950 MonoClass *gclass = mono_class_get_generic_class (klass)->container_class;
2951 MonoGenericInst *inst = mono_class_get_generic_class (klass)->context.class_inst;
2952 static int count = 0;
2953 guint8 *p1 = p;
2954
2955 encode_value (MONO_AOT_TYPEREF_GINST, p, &p);
2956 encode_klass_ref (acfg, gclass, p, &p);
2957 encode_ginst (acfg, inst, p, &p);
2958
2959 count += p - p1;
2960 }
2961 } else if (klass->type_token) {
2962 int iindex = get_image_index (acfg, klass->image);
2963
2964 g_assert (mono_metadata_token_code (klass->type_token) == MONO_TOKEN_TYPE_DEF);
2965 if (iindex == 0) {
2966 encode_value (MONO_AOT_TYPEREF_TYPEDEF_INDEX, p, &p);
2967 encode_value (klass->type_token - MONO_TOKEN_TYPE_DEF, p, &p);
2968 } else {
2969 encode_value (MONO_AOT_TYPEREF_TYPEDEF_INDEX_IMAGE, p, &p);
2970 encode_value (klass->type_token - MONO_TOKEN_TYPE_DEF, p, &p);
2971 encode_value (get_image_index (acfg, klass->image), p, &p);
2972 }
2973 } else if ((klass->byval_arg.type == MONO_TYPE_VAR) || (klass->byval_arg.type == MONO_TYPE_MVAR)) {
2974 MonoGenericContainer *container = mono_type_get_generic_param_owner (&klass->byval_arg);
2975 MonoGenericParam *par = klass->byval_arg.data.generic_param;
2976
2977 encode_value (MONO_AOT_TYPEREF_VAR, p, &p);
2978
2979 encode_value (par->gshared_constraint ? 1 : 0, p, &p);
2980 if (par->gshared_constraint) {
2981 MonoGSharedGenericParam *gpar = (MonoGSharedGenericParam*)par;
2982 encode_type (acfg, par->gshared_constraint, p, &p);
2983 encode_klass_ref (acfg, mono_class_from_generic_parameter_internal (gpar->parent), p, &p);
2984 } else {
2985 encode_value (klass->byval_arg.type, p, &p);
2986 encode_value (mono_type_get_generic_param_num (&klass->byval_arg), p, &p);
2987
2988 encode_value (container->is_anonymous ? 0 : 1, p, &p);
2989
2990 if (!container->is_anonymous) {
2991 encode_value (container->is_method, p, &p);
2992 if (container->is_method)
2993 encode_method_ref (acfg, container->owner.method, p, &p);
2994 else
2995 encode_klass_ref (acfg, container->owner.klass, p, &p);
2996 }
2997 }
2998 } else if (klass->byval_arg.type == MONO_TYPE_PTR) {
2999 encode_value (MONO_AOT_TYPEREF_PTR, p, &p);
3000 encode_type (acfg, &klass->byval_arg, p, &p);
3001 } else {
3002 /* Array class */
3003 g_assert (klass->rank > 0);
3004 encode_value (MONO_AOT_TYPEREF_ARRAY, p, &p);
3005 encode_value (klass->rank, p, &p);
3006 encode_klass_ref (acfg, klass->element_class, p, &p);
3007 }
3008 *endbuf = p;
3009 }
3010
3011 /*
3012 * encode_klass_ref:
3013 *
3014 * Encode a reference to KLASS. We use our home-grown encoding instead of the
3015 * standard metadata encoding.
3016 */
3017 static void
encode_klass_ref(MonoAotCompile * acfg,MonoClass * klass,guint8 * buf,guint8 ** endbuf)3018 encode_klass_ref (MonoAotCompile *acfg, MonoClass *klass, guint8 *buf, guint8 **endbuf)
3019 {
3020 gboolean shared = FALSE;
3021
3022 /*
3023 * The encoding of generic instances is large so emit them only once.
3024 */
3025 if (mono_class_is_ginst (klass)) {
3026 guint32 token;
3027 g_assert (klass->type_token);
3028
3029 /* Find a typespec for a class if possible */
3030 token = find_typespec_for_class (acfg, klass);
3031 if (!token)
3032 shared = TRUE;
3033 } else if ((klass->byval_arg.type == MONO_TYPE_VAR) || (klass->byval_arg.type == MONO_TYPE_MVAR)) {
3034 shared = TRUE;
3035 }
3036
3037 if (shared) {
3038 guint offset = GPOINTER_TO_UINT (g_hash_table_lookup (acfg->klass_blob_hash, klass));
3039 guint8 *buf2, *p;
3040
3041 if (!offset) {
3042 buf2 = (guint8 *)g_malloc (1024);
3043 p = buf2;
3044
3045 encode_klass_ref_inner (acfg, klass, p, &p);
3046 g_assert (p - buf2 < 1024);
3047
3048 offset = add_to_blob (acfg, buf2, p - buf2);
3049 g_free (buf2);
3050
3051 g_hash_table_insert (acfg->klass_blob_hash, klass, GUINT_TO_POINTER (offset + 1));
3052 } else {
3053 offset --;
3054 }
3055
3056 p = buf;
3057 encode_value (MONO_AOT_TYPEREF_BLOB_INDEX, p, &p);
3058 encode_value (offset, p, &p);
3059 *endbuf = p;
3060 return;
3061 }
3062
3063 encode_klass_ref_inner (acfg, klass, buf, endbuf);
3064 }
3065
3066 static void
encode_field_info(MonoAotCompile * cfg,MonoClassField * field,guint8 * buf,guint8 ** endbuf)3067 encode_field_info (MonoAotCompile *cfg, MonoClassField *field, guint8 *buf, guint8 **endbuf)
3068 {
3069 guint32 token = mono_get_field_token (field);
3070 guint8 *p = buf;
3071
3072 encode_klass_ref (cfg, field->parent, p, &p);
3073 g_assert (mono_metadata_token_code (token) == MONO_TOKEN_FIELD_DEF);
3074 encode_value (token - MONO_TOKEN_FIELD_DEF, p, &p);
3075 *endbuf = p;
3076 }
3077
3078 static void
encode_ginst(MonoAotCompile * acfg,MonoGenericInst * inst,guint8 * buf,guint8 ** endbuf)3079 encode_ginst (MonoAotCompile *acfg, MonoGenericInst *inst, guint8 *buf, guint8 **endbuf)
3080 {
3081 guint8 *p = buf;
3082 int i;
3083
3084 encode_value (inst->type_argc, p, &p);
3085 for (i = 0; i < inst->type_argc; ++i)
3086 encode_klass_ref (acfg, mono_class_from_mono_type (inst->type_argv [i]), p, &p);
3087 *endbuf = p;
3088 }
3089
3090 static void
encode_generic_context(MonoAotCompile * acfg,MonoGenericContext * context,guint8 * buf,guint8 ** endbuf)3091 encode_generic_context (MonoAotCompile *acfg, MonoGenericContext *context, guint8 *buf, guint8 **endbuf)
3092 {
3093 guint8 *p = buf;
3094 MonoGenericInst *inst;
3095
3096 inst = context->class_inst;
3097 if (inst) {
3098 g_assert (inst->type_argc);
3099 encode_ginst (acfg, inst, p, &p);
3100 } else {
3101 encode_value (0, p, &p);
3102 }
3103 inst = context->method_inst;
3104 if (inst) {
3105 g_assert (inst->type_argc);
3106 encode_ginst (acfg, inst, p, &p);
3107 } else {
3108 encode_value (0, p, &p);
3109 }
3110 *endbuf = p;
3111 }
3112
3113 static void
encode_type(MonoAotCompile * acfg,MonoType * t,guint8 * buf,guint8 ** endbuf)3114 encode_type (MonoAotCompile *acfg, MonoType *t, guint8 *buf, guint8 **endbuf)
3115 {
3116 guint8 *p = buf;
3117
3118 g_assert (t->num_mods == 0);
3119 /* t->attrs can be ignored */
3120 //g_assert (t->attrs == 0);
3121
3122 if (t->pinned) {
3123 *p = MONO_TYPE_PINNED;
3124 ++p;
3125 }
3126 if (t->byref) {
3127 *p = MONO_TYPE_BYREF;
3128 ++p;
3129 }
3130
3131 *p = t->type;
3132 p ++;
3133
3134 switch (t->type) {
3135 case MONO_TYPE_VOID:
3136 case MONO_TYPE_BOOLEAN:
3137 case MONO_TYPE_CHAR:
3138 case MONO_TYPE_I1:
3139 case MONO_TYPE_U1:
3140 case MONO_TYPE_I2:
3141 case MONO_TYPE_U2:
3142 case MONO_TYPE_I4:
3143 case MONO_TYPE_U4:
3144 case MONO_TYPE_I8:
3145 case MONO_TYPE_U8:
3146 case MONO_TYPE_R4:
3147 case MONO_TYPE_R8:
3148 case MONO_TYPE_I:
3149 case MONO_TYPE_U:
3150 case MONO_TYPE_STRING:
3151 case MONO_TYPE_OBJECT:
3152 case MONO_TYPE_TYPEDBYREF:
3153 break;
3154 case MONO_TYPE_VALUETYPE:
3155 case MONO_TYPE_CLASS:
3156 encode_klass_ref (acfg, mono_class_from_mono_type (t), p, &p);
3157 break;
3158 case MONO_TYPE_SZARRAY:
3159 encode_klass_ref (acfg, t->data.klass, p, &p);
3160 break;
3161 case MONO_TYPE_PTR:
3162 encode_type (acfg, t->data.type, p, &p);
3163 break;
3164 case MONO_TYPE_GENERICINST: {
3165 MonoClass *gclass = t->data.generic_class->container_class;
3166 MonoGenericInst *inst = t->data.generic_class->context.class_inst;
3167
3168 encode_klass_ref (acfg, gclass, p, &p);
3169 encode_ginst (acfg, inst, p, &p);
3170 break;
3171 }
3172 case MONO_TYPE_ARRAY: {
3173 MonoArrayType *array = t->data.array;
3174 int i;
3175
3176 encode_klass_ref (acfg, array->eklass, p, &p);
3177 encode_value (array->rank, p, &p);
3178 encode_value (array->numsizes, p, &p);
3179 for (i = 0; i < array->numsizes; ++i)
3180 encode_value (array->sizes [i], p, &p);
3181 encode_value (array->numlobounds, p, &p);
3182 for (i = 0; i < array->numlobounds; ++i)
3183 encode_value (array->lobounds [i], p, &p);
3184 break;
3185 }
3186 case MONO_TYPE_VAR:
3187 case MONO_TYPE_MVAR:
3188 encode_klass_ref (acfg, mono_class_from_mono_type (t), p, &p);
3189 break;
3190 default:
3191 g_assert_not_reached ();
3192 }
3193
3194 *endbuf = p;
3195 }
3196
3197 static void
encode_signature(MonoAotCompile * acfg,MonoMethodSignature * sig,guint8 * buf,guint8 ** endbuf)3198 encode_signature (MonoAotCompile *acfg, MonoMethodSignature *sig, guint8 *buf, guint8 **endbuf)
3199 {
3200 guint8 *p = buf;
3201 guint32 flags = 0;
3202 int i;
3203
3204 /* Similar to the metadata encoding */
3205 if (sig->generic_param_count)
3206 flags |= 0x10;
3207 if (sig->hasthis)
3208 flags |= 0x20;
3209 if (sig->explicit_this)
3210 flags |= 0x40;
3211 flags |= (sig->call_convention & 0x0F);
3212
3213 *p = flags;
3214 ++p;
3215 if (sig->generic_param_count)
3216 encode_value (sig->generic_param_count, p, &p);
3217 encode_value (sig->param_count, p, &p);
3218
3219 encode_type (acfg, sig->ret, p, &p);
3220 for (i = 0; i < sig->param_count; ++i) {
3221 if (sig->sentinelpos == i) {
3222 *p = MONO_TYPE_SENTINEL;
3223 ++p;
3224 }
3225 encode_type (acfg, sig->params [i], p, &p);
3226 }
3227
3228 *endbuf = p;
3229 }
3230
3231 #define MAX_IMAGE_INDEX 250
3232
3233 static void
encode_method_ref(MonoAotCompile * acfg,MonoMethod * method,guint8 * buf,guint8 ** endbuf)3234 encode_method_ref (MonoAotCompile *acfg, MonoMethod *method, guint8 *buf, guint8 **endbuf)
3235 {
3236 guint32 image_index = get_image_index (acfg, method->klass->image);
3237 guint32 token = method->token;
3238 MonoJumpInfoToken *ji;
3239 guint8 *p = buf;
3240
3241 /*
3242 * The encoding for most methods is as follows:
3243 * - image index encoded as a leb128
3244 * - token index encoded as a leb128
3245 * Values of image index >= MONO_AOT_METHODREF_MIN are used to mark additional
3246 * types of method encodings.
3247 */
3248
3249 /* Mark methods which can't use aot trampolines because they need the further
3250 * processing in mono_magic_trampoline () which requires a MonoMethod*.
3251 */
3252 if ((method->is_generic && (method->flags & METHOD_ATTRIBUTE_VIRTUAL)) ||
3253 (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED))
3254 encode_value ((MONO_AOT_METHODREF_NO_AOT_TRAMPOLINE << 24), p, &p);
3255
3256 if (method->wrapper_type) {
3257 WrapperInfo *info = mono_marshal_get_wrapper_info (method);
3258
3259 encode_value ((MONO_AOT_METHODREF_WRAPPER << 24), p, &p);
3260
3261 encode_value (method->wrapper_type, p, &p);
3262
3263 switch (method->wrapper_type) {
3264 case MONO_WRAPPER_REMOTING_INVOKE:
3265 case MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK:
3266 case MONO_WRAPPER_XDOMAIN_INVOKE: {
3267 MonoMethod *m;
3268
3269 m = mono_marshal_method_from_wrapper (method);
3270 g_assert (m);
3271 encode_method_ref (acfg, m, p, &p);
3272 break;
3273 }
3274 case MONO_WRAPPER_PROXY_ISINST:
3275 case MONO_WRAPPER_LDFLD:
3276 case MONO_WRAPPER_LDFLDA:
3277 case MONO_WRAPPER_STFLD: {
3278 g_assert (info);
3279 encode_klass_ref (acfg, info->d.proxy.klass, p, &p);
3280 break;
3281 }
3282 case MONO_WRAPPER_ALLOC: {
3283 /* The GC name is saved once in MonoAotFileInfo */
3284 g_assert (info->d.alloc.alloc_type != -1);
3285 encode_value (info->d.alloc.alloc_type, p, &p);
3286 break;
3287 }
3288 case MONO_WRAPPER_WRITE_BARRIER: {
3289 g_assert (info);
3290 break;
3291 }
3292 case MONO_WRAPPER_STELEMREF: {
3293 g_assert (info);
3294 encode_value (info->subtype, p, &p);
3295 if (info->subtype == WRAPPER_SUBTYPE_VIRTUAL_STELEMREF)
3296 encode_value (info->d.virtual_stelemref.kind, p, &p);
3297 break;
3298 }
3299 case MONO_WRAPPER_UNKNOWN: {
3300 g_assert (info);
3301 encode_value (info->subtype, p, &p);
3302 if (info->subtype == WRAPPER_SUBTYPE_PTR_TO_STRUCTURE ||
3303 info->subtype == WRAPPER_SUBTYPE_STRUCTURE_TO_PTR)
3304 encode_klass_ref (acfg, method->klass, p, &p);
3305 else if (info->subtype == WRAPPER_SUBTYPE_SYNCHRONIZED_INNER)
3306 encode_method_ref (acfg, info->d.synchronized_inner.method, p, &p);
3307 else if (info->subtype == WRAPPER_SUBTYPE_ARRAY_ACCESSOR)
3308 encode_method_ref (acfg, info->d.array_accessor.method, p, &p);
3309 else if (info->subtype == WRAPPER_SUBTYPE_INTERP_IN)
3310 encode_signature (acfg, info->d.interp_in.sig, p, &p);
3311 else if (info->subtype == WRAPPER_SUBTYPE_GSHAREDVT_IN_SIG)
3312 encode_signature (acfg, info->d.gsharedvt.sig, p, &p);
3313 else if (info->subtype == WRAPPER_SUBTYPE_GSHAREDVT_OUT_SIG)
3314 encode_signature (acfg, info->d.gsharedvt.sig, p, &p);
3315 break;
3316 }
3317 case MONO_WRAPPER_MANAGED_TO_NATIVE: {
3318 g_assert (info);
3319 encode_value (info->subtype, p, &p);
3320 if (info->subtype == WRAPPER_SUBTYPE_ICALL_WRAPPER) {
3321 strcpy ((char*)p, method->name);
3322 p += strlen (method->name) + 1;
3323 } else if (info->subtype == WRAPPER_SUBTYPE_NATIVE_FUNC_AOT) {
3324 encode_method_ref (acfg, info->d.managed_to_native.method, p, &p);
3325 } else {
3326 g_assert (info->subtype == WRAPPER_SUBTYPE_NONE || info->subtype == WRAPPER_SUBTYPE_PINVOKE);
3327 encode_method_ref (acfg, info->d.managed_to_native.method, p, &p);
3328 }
3329 break;
3330 }
3331 case MONO_WRAPPER_SYNCHRONIZED: {
3332 MonoMethod *m;
3333
3334 m = mono_marshal_method_from_wrapper (method);
3335 g_assert (m);
3336 g_assert (m != method);
3337 encode_method_ref (acfg, m, p, &p);
3338 break;
3339 }
3340 case MONO_WRAPPER_MANAGED_TO_MANAGED: {
3341 g_assert (info);
3342 encode_value (info->subtype, p, &p);
3343
3344 if (info->subtype == WRAPPER_SUBTYPE_ELEMENT_ADDR) {
3345 encode_value (info->d.element_addr.rank, p, &p);
3346 encode_value (info->d.element_addr.elem_size, p, &p);
3347 } else if (info->subtype == WRAPPER_SUBTYPE_STRING_CTOR) {
3348 encode_method_ref (acfg, info->d.string_ctor.method, p, &p);
3349 } else {
3350 g_assert_not_reached ();
3351 }
3352 break;
3353 }
3354 case MONO_WRAPPER_CASTCLASS: {
3355 g_assert (info);
3356 encode_value (info->subtype, p, &p);
3357 break;
3358 }
3359 case MONO_WRAPPER_RUNTIME_INVOKE: {
3360 g_assert (info);
3361 encode_value (info->subtype, p, &p);
3362 if (info->subtype == WRAPPER_SUBTYPE_RUNTIME_INVOKE_DIRECT || info->subtype == WRAPPER_SUBTYPE_RUNTIME_INVOKE_VIRTUAL)
3363 encode_method_ref (acfg, info->d.runtime_invoke.method, p, &p);
3364 else if (info->subtype == WRAPPER_SUBTYPE_RUNTIME_INVOKE_NORMAL)
3365 encode_signature (acfg, info->d.runtime_invoke.sig, p, &p);
3366 break;
3367 }
3368 case MONO_WRAPPER_DELEGATE_INVOKE:
3369 case MONO_WRAPPER_DELEGATE_BEGIN_INVOKE:
3370 case MONO_WRAPPER_DELEGATE_END_INVOKE: {
3371 if (method->is_inflated) {
3372 /* These wrappers are identified by their class */
3373 encode_value (1, p, &p);
3374 encode_klass_ref (acfg, method->klass, p, &p);
3375 } else {
3376 MonoMethodSignature *sig = mono_method_signature (method);
3377 WrapperInfo *info = mono_marshal_get_wrapper_info (method);
3378
3379 encode_value (0, p, &p);
3380 if (method->wrapper_type == MONO_WRAPPER_DELEGATE_INVOKE)
3381 encode_value (info ? info->subtype : 0, p, &p);
3382 encode_signature (acfg, sig, p, &p);
3383 }
3384 break;
3385 }
3386 case MONO_WRAPPER_NATIVE_TO_MANAGED: {
3387 g_assert (info);
3388 encode_method_ref (acfg, info->d.native_to_managed.method, p, &p);
3389 encode_klass_ref (acfg, info->d.native_to_managed.klass, p, &p);
3390 break;
3391 }
3392 default:
3393 g_assert_not_reached ();
3394 }
3395 } else if (mono_method_signature (method)->is_inflated) {
3396 /*
3397 * This is a generic method, find the original token which referenced it and
3398 * encode that.
3399 * Obtain the token from information recorded by the JIT.
3400 */
3401 ji = (MonoJumpInfoToken *)g_hash_table_lookup (acfg->token_info_hash, method);
3402 if (ji) {
3403 image_index = get_image_index (acfg, ji->image);
3404 g_assert (image_index < MAX_IMAGE_INDEX);
3405 token = ji->token;
3406
3407 encode_value ((MONO_AOT_METHODREF_METHODSPEC << 24), p, &p);
3408 encode_value (image_index, p, &p);
3409 encode_value (token, p, &p);
3410 } else {
3411 MonoMethod *declaring;
3412 MonoGenericContext *context = mono_method_get_context (method);
3413
3414 g_assert (method->is_inflated);
3415 declaring = ((MonoMethodInflated*)method)->declaring;
3416
3417 /*
3418 * This might be a non-generic method of a generic instance, which
3419 * doesn't have a token since the reference is generated by the JIT
3420 * like Nullable:Box/Unbox, or by generic sharing.
3421 */
3422 encode_value ((MONO_AOT_METHODREF_GINST << 24), p, &p);
3423 /* Encode the klass */
3424 encode_klass_ref (acfg, method->klass, p, &p);
3425 /* Encode the method */
3426 image_index = get_image_index (acfg, method->klass->image);
3427 g_assert (image_index < MAX_IMAGE_INDEX);
3428 g_assert (declaring->token);
3429 token = declaring->token;
3430 g_assert (mono_metadata_token_table (token) == MONO_TABLE_METHOD);
3431 encode_value (image_index, p, &p);
3432 encode_value (token, p, &p);
3433 encode_generic_context (acfg, context, p, &p);
3434 }
3435 } else if (token == 0) {
3436 /* This might be a method of a constructed type like int[,].Set */
3437 /* Obtain the token from information recorded by the JIT */
3438 ji = (MonoJumpInfoToken *)g_hash_table_lookup (acfg->token_info_hash, method);
3439 if (ji) {
3440 image_index = get_image_index (acfg, ji->image);
3441 g_assert (image_index < MAX_IMAGE_INDEX);
3442 token = ji->token;
3443
3444 encode_value ((MONO_AOT_METHODREF_METHODSPEC << 24), p, &p);
3445 encode_value (image_index, p, &p);
3446 encode_value (token, p, &p);
3447 } else {
3448 /* Array methods */
3449 g_assert (method->klass->rank);
3450
3451 /* Encode directly */
3452 encode_value ((MONO_AOT_METHODREF_ARRAY << 24), p, &p);
3453 encode_klass_ref (acfg, method->klass, p, &p);
3454 if (!strcmp (method->name, ".ctor") && mono_method_signature (method)->param_count == method->klass->rank)
3455 encode_value (0, p, &p);
3456 else if (!strcmp (method->name, ".ctor") && mono_method_signature (method)->param_count == method->klass->rank * 2)
3457 encode_value (1, p, &p);
3458 else if (!strcmp (method->name, "Get"))
3459 encode_value (2, p, &p);
3460 else if (!strcmp (method->name, "Address"))
3461 encode_value (3, p, &p);
3462 else if (!strcmp (method->name, "Set"))
3463 encode_value (4, p, &p);
3464 else
3465 g_assert_not_reached ();
3466 }
3467 } else {
3468 g_assert (mono_metadata_token_table (token) == MONO_TABLE_METHOD);
3469
3470 if (image_index >= MONO_AOT_METHODREF_MIN) {
3471 encode_value ((MONO_AOT_METHODREF_LARGE_IMAGE_INDEX << 24), p, &p);
3472 encode_value (image_index, p, &p);
3473 encode_value (mono_metadata_token_index (token), p, &p);
3474 } else {
3475 encode_value ((image_index << 24) | mono_metadata_token_index (token), p, &p);
3476 }
3477 }
3478 *endbuf = p;
3479 }
3480
3481 static gint
compare_patches(gconstpointer a,gconstpointer b)3482 compare_patches (gconstpointer a, gconstpointer b)
3483 {
3484 int i, j;
3485
3486 i = (*(MonoJumpInfo**)a)->ip.i;
3487 j = (*(MonoJumpInfo**)b)->ip.i;
3488
3489 if (i < j)
3490 return -1;
3491 else
3492 if (i > j)
3493 return 1;
3494 else
3495 return 0;
3496 }
3497
3498 static G_GNUC_UNUSED char*
patch_to_string(MonoJumpInfo * patch_info)3499 patch_to_string (MonoJumpInfo *patch_info)
3500 {
3501 GString *str;
3502
3503 str = g_string_new ("");
3504
3505 g_string_append_printf (str, "%s(", get_patch_name (patch_info->type));
3506
3507 switch (patch_info->type) {
3508 case MONO_PATCH_INFO_VTABLE:
3509 mono_type_get_desc (str, &patch_info->data.klass->byval_arg, TRUE);
3510 break;
3511 default:
3512 break;
3513 }
3514 g_string_append_printf (str, ")");
3515 return g_string_free (str, FALSE);
3516 }
3517
3518 /*
3519 * is_plt_patch:
3520 *
3521 * Return whenever PATCH_INFO refers to a direct call, and thus requires a
3522 * PLT entry.
3523 */
3524 static inline gboolean
is_plt_patch(MonoJumpInfo * patch_info)3525 is_plt_patch (MonoJumpInfo *patch_info)
3526 {
3527 switch (patch_info->type) {
3528 case MONO_PATCH_INFO_METHOD:
3529 case MONO_PATCH_INFO_INTERNAL_METHOD:
3530 case MONO_PATCH_INFO_JIT_ICALL_ADDR:
3531 case MONO_PATCH_INFO_ICALL_ADDR_CALL:
3532 case MONO_PATCH_INFO_RGCTX_FETCH:
3533 return TRUE;
3534 default:
3535 return FALSE;
3536 }
3537 }
3538
3539 /*
3540 * get_plt_symbol:
3541 *
3542 * Return the symbol identifying the plt entry PLT_OFFSET.
3543 */
3544 static char*
get_plt_symbol(MonoAotCompile * acfg,int plt_offset,MonoJumpInfo * patch_info)3545 get_plt_symbol (MonoAotCompile *acfg, int plt_offset, MonoJumpInfo *patch_info)
3546 {
3547 #ifdef TARGET_MACH
3548 /*
3549 * The Apple linker reorganizes object files, so it doesn't like branches to local
3550 * labels, since those have no relocations.
3551 */
3552 return g_strdup_printf ("%sp_%d", acfg->llvm_label_prefix, plt_offset);
3553 #else
3554 return g_strdup_printf ("%sp_%d", acfg->temp_prefix, plt_offset);
3555 #endif
3556 }
3557
3558 /*
3559 * get_plt_entry:
3560 *
3561 * Return a PLT entry which belongs to the method identified by PATCH_INFO.
3562 */
3563 static MonoPltEntry*
get_plt_entry(MonoAotCompile * acfg,MonoJumpInfo * patch_info)3564 get_plt_entry (MonoAotCompile *acfg, MonoJumpInfo *patch_info)
3565 {
3566 MonoPltEntry *res;
3567 gboolean synchronized = FALSE;
3568 static int synchronized_symbol_idx;
3569
3570 if (!is_plt_patch (patch_info))
3571 return NULL;
3572
3573 if (!acfg->patch_to_plt_entry [patch_info->type])
3574 acfg->patch_to_plt_entry [patch_info->type] = g_hash_table_new (mono_patch_info_hash, mono_patch_info_equal);
3575 res = (MonoPltEntry *)g_hash_table_lookup (acfg->patch_to_plt_entry [patch_info->type], patch_info);
3576
3577 if (!acfg->llvm && patch_info->type == MONO_PATCH_INFO_METHOD && (patch_info->data.method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)) {
3578 /*
3579 * Allocate a separate PLT slot for each such patch, since some plt
3580 * entries will refer to the method itself, and some will refer to the
3581 * wrapper.
3582 */
3583 res = NULL;
3584 synchronized = TRUE;
3585 }
3586
3587 if (!res) {
3588 MonoJumpInfo *new_ji;
3589
3590 new_ji = mono_patch_info_dup_mp (acfg->mempool, patch_info);
3591
3592 res = (MonoPltEntry *)mono_mempool_alloc0 (acfg->mempool, sizeof (MonoPltEntry));
3593 res->plt_offset = acfg->plt_offset;
3594 res->ji = new_ji;
3595 res->symbol = get_plt_symbol (acfg, res->plt_offset, patch_info);
3596 if (acfg->aot_opts.write_symbols)
3597 res->debug_sym = get_plt_entry_debug_sym (acfg, res->ji, acfg->plt_entry_debug_sym_cache);
3598 if (synchronized) {
3599 /* Avoid duplicate symbols because we don't cache */
3600 res->symbol = g_strdup_printf ("%s_%d", res->symbol, synchronized_symbol_idx);
3601 if (res->debug_sym)
3602 res->debug_sym = g_strdup_printf ("%s_%d", res->debug_sym, synchronized_symbol_idx);
3603 synchronized_symbol_idx ++;
3604 }
3605 if (res->debug_sym)
3606 res->llvm_symbol = g_strdup_printf ("%s_%s_llvm", res->symbol, res->debug_sym);
3607 else
3608 res->llvm_symbol = g_strdup_printf ("%s_llvm", res->symbol);
3609
3610 g_hash_table_insert (acfg->patch_to_plt_entry [new_ji->type], new_ji, res);
3611
3612 g_hash_table_insert (acfg->plt_offset_to_entry, GUINT_TO_POINTER (res->plt_offset), res);
3613
3614 //g_assert (mono_patch_info_equal (patch_info, new_ji));
3615 //mono_print_ji (patch_info); printf ("\n");
3616 //g_hash_table_print_stats (acfg->patch_to_plt_entry);
3617
3618 acfg->plt_offset ++;
3619 }
3620
3621 return res;
3622 }
3623
3624 /**
3625 * get_got_offset:
3626 *
3627 * Returns the offset of the GOT slot where the runtime object resulting from resolving
3628 * JI could be found if it exists, otherwise allocates a new one.
3629 */
3630 static guint32
get_got_offset(MonoAotCompile * acfg,gboolean llvm,MonoJumpInfo * ji)3631 get_got_offset (MonoAotCompile *acfg, gboolean llvm, MonoJumpInfo *ji)
3632 {
3633 guint32 got_offset;
3634 GotInfo *info = llvm ? &acfg->llvm_got_info : &acfg->got_info;
3635
3636 got_offset = GPOINTER_TO_UINT (g_hash_table_lookup (info->patch_to_got_offset_by_type [ji->type], ji));
3637 if (got_offset)
3638 return got_offset - 1;
3639
3640 if (llvm) {
3641 got_offset = acfg->llvm_got_offset;
3642 acfg->llvm_got_offset ++;
3643 } else {
3644 got_offset = acfg->got_offset;
3645 acfg->got_offset ++;
3646 }
3647
3648 acfg->stats.got_slots ++;
3649 acfg->stats.got_slot_types [ji->type] ++;
3650
3651 g_hash_table_insert (info->patch_to_got_offset, ji, GUINT_TO_POINTER (got_offset + 1));
3652 g_hash_table_insert (info->patch_to_got_offset_by_type [ji->type], ji, GUINT_TO_POINTER (got_offset + 1));
3653 g_ptr_array_add (info->got_patches, ji);
3654
3655 return got_offset;
3656 }
3657
3658 /* Add a method to the list of methods which need to be emitted */
3659 static void
add_method_with_index(MonoAotCompile * acfg,MonoMethod * method,int index,gboolean extra)3660 add_method_with_index (MonoAotCompile *acfg, MonoMethod *method, int index, gboolean extra)
3661 {
3662 g_assert (method);
3663 if (!g_hash_table_lookup (acfg->method_indexes, method)) {
3664 g_ptr_array_add (acfg->methods, method);
3665 g_hash_table_insert (acfg->method_indexes, method, GUINT_TO_POINTER (index + 1));
3666 acfg->nmethods = acfg->methods->len + 1;
3667 }
3668
3669 if (method->wrapper_type || extra)
3670 g_ptr_array_add (acfg->extra_methods, method);
3671 }
3672
3673 static gboolean
prefer_gsharedvt_method(MonoAotCompile * acfg,MonoMethod * method)3674 prefer_gsharedvt_method (MonoAotCompile *acfg, MonoMethod *method)
3675 {
3676 /* One instantiation with valuetypes is generated for each async method */
3677 if (method->klass->image == mono_defaults.corlib && (!strcmp (method->klass->name, "AsyncMethodBuilderCore") || !strcmp (method->klass->name, "AsyncVoidMethodBuilder")))
3678 return TRUE;
3679 else
3680 return FALSE;
3681 }
3682
3683 static guint32
get_method_index(MonoAotCompile * acfg,MonoMethod * method)3684 get_method_index (MonoAotCompile *acfg, MonoMethod *method)
3685 {
3686 int index = GPOINTER_TO_UINT (g_hash_table_lookup (acfg->method_indexes, method));
3687
3688 g_assert (index);
3689
3690 return index - 1;
3691 }
3692
3693 static int
add_method_full(MonoAotCompile * acfg,MonoMethod * method,gboolean extra,int depth)3694 add_method_full (MonoAotCompile *acfg, MonoMethod *method, gboolean extra, int depth)
3695 {
3696 int index;
3697
3698 index = GPOINTER_TO_UINT (g_hash_table_lookup (acfg->method_indexes, method));
3699 if (index)
3700 return index - 1;
3701
3702 index = acfg->method_index;
3703 add_method_with_index (acfg, method, index, extra);
3704
3705 g_ptr_array_add (acfg->method_order, GUINT_TO_POINTER (index));
3706
3707 g_hash_table_insert (acfg->method_depth, method, GUINT_TO_POINTER (depth));
3708
3709 acfg->method_index ++;
3710
3711 return index;
3712 }
3713
3714 static int
add_method(MonoAotCompile * acfg,MonoMethod * method)3715 add_method (MonoAotCompile *acfg, MonoMethod *method)
3716 {
3717 return add_method_full (acfg, method, FALSE, 0);
3718 }
3719
3720 static void
mono_dedup_cache_method(MonoAotCompile * acfg,MonoMethod * method)3721 mono_dedup_cache_method (MonoAotCompile *acfg, MonoMethod *method)
3722 {
3723 g_assert (acfg->dedup_stats);
3724
3725 char *name = mono_aot_get_mangled_method_name (method);
3726 g_assert (name);
3727
3728 // For stats
3729 char *stats_name = g_strdup (name);
3730
3731 g_assert (acfg->dedup_cache);
3732
3733 if (!g_hash_table_lookup (acfg->dedup_cache, name)) {
3734 // This AOTCompile owns this method
3735 // We do this to decide whether to write it to disk
3736 // during a dedup run (first phase, where we skip).
3737 //
3738 // If never changed, then maybe can avoid a recompile
3739 // of the cache.
3740 //
3741 // Files not read in during last phase.
3742 acfg->dedup_cache_changed = TRUE;
3743
3744 // owns name
3745 g_hash_table_insert (acfg->dedup_cache, name, method);
3746 } else {
3747 // owns name
3748 g_free (name);
3749 }
3750
3751 guint count = GPOINTER_TO_UINT (g_hash_table_lookup (acfg->dedup_stats, stats_name));
3752 count++;
3753 g_hash_table_insert (acfg->dedup_stats, stats_name, GUINT_TO_POINTER (count));
3754 }
3755
3756 static void
add_extra_method_with_depth(MonoAotCompile * acfg,MonoMethod * method,int depth)3757 add_extra_method_with_depth (MonoAotCompile *acfg, MonoMethod *method, int depth)
3758 {
3759 if (mono_method_is_generic_sharable_full (method, TRUE, TRUE, FALSE))
3760 method = mini_get_shared_method (method);
3761 else if ((acfg->opts & MONO_OPT_GSHAREDVT) && prefer_gsharedvt_method (acfg, method) && mono_method_is_generic_sharable_full (method, FALSE, FALSE, TRUE))
3762 /* Use the gsharedvt version */
3763 method = mini_get_shared_method_full (method, TRUE, TRUE);
3764
3765 if ((acfg->aot_opts.dedup || acfg->aot_opts.dedup_include) && mono_aot_can_dedup (method)) {
3766 mono_dedup_cache_method (acfg, method);
3767
3768 if (!acfg->dedup_emit_mode)
3769 return;
3770 }
3771
3772 if (acfg->aot_opts.log_generics)
3773 aot_printf (acfg, "%*sAdding method %s.\n", depth, "", mono_method_get_full_name (method));
3774
3775 add_method_full (acfg, method, TRUE, depth);
3776 }
3777
3778 static void
add_extra_method(MonoAotCompile * acfg,MonoMethod * method)3779 add_extra_method (MonoAotCompile *acfg, MonoMethod *method)
3780 {
3781 add_extra_method_with_depth (acfg, method, 0);
3782 }
3783
3784 static void
add_jit_icall_wrapper(gpointer key,gpointer value,gpointer user_data)3785 add_jit_icall_wrapper (gpointer key, gpointer value, gpointer user_data)
3786 {
3787 MonoAotCompile *acfg = (MonoAotCompile *)user_data;
3788 MonoJitICallInfo *callinfo = (MonoJitICallInfo *)value;
3789 MonoMethod *wrapper;
3790 char *name;
3791
3792 if (!callinfo->sig)
3793 return;
3794
3795 name = g_strdup_printf ("__icall_wrapper_%s", callinfo->name);
3796 wrapper = mono_marshal_get_icall_wrapper (callinfo->sig, name, callinfo->func, TRUE);
3797 g_free (name);
3798
3799 add_method (acfg, wrapper);
3800 }
3801
3802 static MonoMethod*
get_runtime_invoke_sig(MonoMethodSignature * sig)3803 get_runtime_invoke_sig (MonoMethodSignature *sig)
3804 {
3805 MonoMethodBuilder *mb;
3806 MonoMethod *m;
3807
3808 mb = mono_mb_new (mono_defaults.object_class, "FOO", MONO_WRAPPER_NONE);
3809 m = mono_mb_create_method (mb, sig, 16);
3810 MonoMethod *invoke = mono_marshal_get_runtime_invoke (m, FALSE);
3811 mono_mb_free (mb);
3812 return invoke;
3813 }
3814
3815 static MonoMethod*
get_runtime_invoke(MonoAotCompile * acfg,MonoMethod * method,gboolean virtual_)3816 get_runtime_invoke (MonoAotCompile *acfg, MonoMethod *method, gboolean virtual_)
3817 {
3818 return mono_marshal_get_runtime_invoke (method, virtual_);
3819 }
3820
3821 static gboolean
can_marshal_struct(MonoClass * klass)3822 can_marshal_struct (MonoClass *klass)
3823 {
3824 MonoClassField *field;
3825 gboolean can_marshal = TRUE;
3826 gpointer iter = NULL;
3827 MonoMarshalType *info;
3828 int i;
3829
3830 if (mono_class_is_auto_layout (klass))
3831 return FALSE;
3832
3833 info = mono_marshal_load_type_info (klass);
3834
3835 /* Only allow a few field types to avoid asserts in the marshalling code */
3836 while ((field = mono_class_get_fields (klass, &iter))) {
3837 if ((field->type->attrs & FIELD_ATTRIBUTE_STATIC))
3838 continue;
3839
3840 switch (field->type->type) {
3841 case MONO_TYPE_I4:
3842 case MONO_TYPE_U4:
3843 case MONO_TYPE_I1:
3844 case MONO_TYPE_U1:
3845 case MONO_TYPE_BOOLEAN:
3846 case MONO_TYPE_I2:
3847 case MONO_TYPE_U2:
3848 case MONO_TYPE_CHAR:
3849 case MONO_TYPE_I8:
3850 case MONO_TYPE_U8:
3851 case MONO_TYPE_I:
3852 case MONO_TYPE_U:
3853 case MONO_TYPE_PTR:
3854 case MONO_TYPE_R4:
3855 case MONO_TYPE_R8:
3856 case MONO_TYPE_STRING:
3857 break;
3858 case MONO_TYPE_VALUETYPE:
3859 if (!mono_class_from_mono_type (field->type)->enumtype && !can_marshal_struct (mono_class_from_mono_type (field->type)))
3860 can_marshal = FALSE;
3861 break;
3862 case MONO_TYPE_SZARRAY: {
3863 gboolean has_mspec = FALSE;
3864
3865 if (info) {
3866 for (i = 0; i < info->num_fields; ++i) {
3867 if (info->fields [i].field == field && info->fields [i].mspec)
3868 has_mspec = TRUE;
3869 }
3870 }
3871 if (!has_mspec)
3872 can_marshal = FALSE;
3873 break;
3874 }
3875 default:
3876 can_marshal = FALSE;
3877 break;
3878 }
3879 }
3880
3881 /* Special cases */
3882 /* Its hard to compute whenever these can be marshalled or not */
3883 if (!strcmp (klass->name_space, "System.Net.NetworkInformation.MacOsStructs") && strcmp (klass->name, "sockaddr_dl"))
3884 return TRUE;
3885
3886 return can_marshal;
3887 }
3888
3889 static void
create_gsharedvt_inst(MonoAotCompile * acfg,MonoMethod * method,MonoGenericContext * ctx)3890 create_gsharedvt_inst (MonoAotCompile *acfg, MonoMethod *method, MonoGenericContext *ctx)
3891 {
3892 /* Create a vtype instantiation */
3893 MonoGenericContext shared_context;
3894 MonoType **args;
3895 MonoGenericInst *inst;
3896 MonoGenericContainer *container;
3897 MonoClass **constraints;
3898 int i;
3899
3900 memset (ctx, 0, sizeof (MonoGenericContext));
3901
3902 if (mono_class_is_gtd (method->klass)) {
3903 shared_context = mono_class_get_generic_container (method->klass)->context;
3904 inst = shared_context.class_inst;
3905
3906 args = g_new0 (MonoType*, inst->type_argc);
3907 for (i = 0; i < inst->type_argc; ++i) {
3908 args [i] = &mono_defaults.int_class->byval_arg;
3909 }
3910 ctx->class_inst = mono_metadata_get_generic_inst (inst->type_argc, args);
3911 }
3912 if (method->is_generic) {
3913 container = mono_method_get_generic_container (method);
3914 shared_context = container->context;
3915 inst = shared_context.method_inst;
3916
3917 args = g_new0 (MonoType*, inst->type_argc);
3918 for (i = 0; i < container->type_argc; ++i) {
3919 MonoGenericParamInfo *info = &container->type_params [i].info;
3920 gboolean ref_only = FALSE;
3921
3922 if (info && info->constraints) {
3923 constraints = info->constraints;
3924
3925 while (*constraints) {
3926 MonoClass *cklass = *constraints;
3927 if (!(cklass == mono_defaults.object_class || (cklass->image == mono_defaults.corlib && !strcmp (cklass->name, "ValueType"))))
3928 /* Inflaring the method with our vtype would not be valid */
3929 ref_only = TRUE;
3930 constraints ++;
3931 }
3932 }
3933
3934 if (ref_only)
3935 args [i] = &mono_defaults.object_class->byval_arg;
3936 else
3937 args [i] = &mono_defaults.int_class->byval_arg;
3938 }
3939 ctx->method_inst = mono_metadata_get_generic_inst (inst->type_argc, args);
3940 }
3941 }
3942
3943 static void
add_wrappers(MonoAotCompile * acfg)3944 add_wrappers (MonoAotCompile *acfg)
3945 {
3946 MonoMethod *method, *m;
3947 int i, j;
3948 MonoMethodSignature *sig, *csig;
3949 guint32 token;
3950
3951 /*
3952 * FIXME: Instead of AOTing all the wrappers, it might be better to redesign them
3953 * so there is only one wrapper of a given type, or inlining their contents into their
3954 * callers.
3955 */
3956 for (i = 0; i < acfg->image->tables [MONO_TABLE_METHOD].rows; ++i) {
3957 MonoError error;
3958 MonoMethod *method;
3959 guint32 token = MONO_TOKEN_METHOD_DEF | (i + 1);
3960 gboolean skip = FALSE;
3961
3962 method = mono_get_method_checked (acfg->image, token, NULL, NULL, &error);
3963 report_loader_error (acfg, &error, TRUE, "Failed to load method token 0x%x due to %s\n", i, mono_error_get_message (&error));
3964
3965 if ((method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
3966 (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
3967 (method->flags & METHOD_ATTRIBUTE_ABSTRACT))
3968 skip = TRUE;
3969
3970 /* Skip methods which can not be handled by get_runtime_invoke () */
3971 sig = mono_method_signature (method);
3972 if (!sig)
3973 continue;
3974 if ((sig->ret->type == MONO_TYPE_PTR) ||
3975 (sig->ret->type == MONO_TYPE_TYPEDBYREF))
3976 skip = TRUE;
3977 if (mono_class_is_open_constructed_type (sig->ret))
3978 skip = TRUE;
3979
3980 for (j = 0; j < sig->param_count; j++) {
3981 if (sig->params [j]->type == MONO_TYPE_TYPEDBYREF)
3982 skip = TRUE;
3983 if (mono_class_is_open_constructed_type (sig->params [j]))
3984 skip = TRUE;
3985 }
3986
3987 #ifdef MONO_ARCH_DYN_CALL_SUPPORTED
3988 if (!mono_class_is_contextbound (method->klass)) {
3989 MonoDynCallInfo *info = mono_arch_dyn_call_prepare (sig);
3990 gboolean has_nullable = FALSE;
3991
3992 for (j = 0; j < sig->param_count; j++) {
3993 if (sig->params [j]->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (sig->params [j])))
3994 has_nullable = TRUE;
3995 }
3996
3997 if (info && !has_nullable && !acfg->aot_opts.llvm_only) {
3998 /* Supported by the dynamic runtime-invoke wrapper */
3999 skip = TRUE;
4000 }
4001 if (info)
4002 mono_arch_dyn_call_free (info);
4003 }
4004 #endif
4005
4006 if (acfg->aot_opts.llvm_only)
4007 /* Supported by the gsharedvt based runtime-invoke wrapper */
4008 skip = TRUE;
4009
4010 if (!skip) {
4011 //printf ("%s\n", mono_method_full_name (method, TRUE));
4012 add_method (acfg, get_runtime_invoke (acfg, method, FALSE));
4013 }
4014 }
4015
4016 if (strcmp (acfg->image->assembly->aname.name, "mscorlib") == 0) {
4017 int nallocators;
4018
4019 /* Runtime invoke wrappers */
4020
4021 /* void runtime-invoke () [.cctor] */
4022 csig = mono_metadata_signature_alloc (mono_defaults.corlib, 0);
4023 csig->ret = &mono_defaults.void_class->byval_arg;
4024 add_method (acfg, get_runtime_invoke_sig (csig));
4025
4026 /* void runtime-invoke () [Finalize] */
4027 csig = mono_metadata_signature_alloc (mono_defaults.corlib, 0);
4028 csig->hasthis = 1;
4029 csig->ret = &mono_defaults.void_class->byval_arg;
4030 add_method (acfg, get_runtime_invoke_sig (csig));
4031
4032 /* void runtime-invoke (string) [exception ctor] */
4033 csig = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
4034 csig->hasthis = 1;
4035 csig->ret = &mono_defaults.void_class->byval_arg;
4036 csig->params [0] = &mono_defaults.string_class->byval_arg;
4037 add_method (acfg, get_runtime_invoke_sig (csig));
4038
4039 /* void runtime-invoke (string, string) [exception ctor] */
4040 csig = mono_metadata_signature_alloc (mono_defaults.corlib, 2);
4041 csig->hasthis = 1;
4042 csig->ret = &mono_defaults.void_class->byval_arg;
4043 csig->params [0] = &mono_defaults.string_class->byval_arg;
4044 csig->params [1] = &mono_defaults.string_class->byval_arg;
4045 add_method (acfg, get_runtime_invoke_sig (csig));
4046
4047 /* string runtime-invoke () [Exception.ToString ()] */
4048 csig = mono_metadata_signature_alloc (mono_defaults.corlib, 0);
4049 csig->hasthis = 1;
4050 csig->ret = &mono_defaults.string_class->byval_arg;
4051 add_method (acfg, get_runtime_invoke_sig (csig));
4052
4053 /* void runtime-invoke (string, Exception) [exception ctor] */
4054 csig = mono_metadata_signature_alloc (mono_defaults.corlib, 2);
4055 csig->hasthis = 1;
4056 csig->ret = &mono_defaults.void_class->byval_arg;
4057 csig->params [0] = &mono_defaults.string_class->byval_arg;
4058 csig->params [1] = &mono_defaults.exception_class->byval_arg;
4059 add_method (acfg, get_runtime_invoke_sig (csig));
4060
4061 /* Assembly runtime-invoke (string, Assembly, bool) [DoAssemblyResolve] */
4062 csig = mono_metadata_signature_alloc (mono_defaults.corlib, 3);
4063 csig->hasthis = 1;
4064 csig->ret = &(mono_class_load_from_name (
4065 mono_defaults.corlib, "System.Reflection", "Assembly"))->byval_arg;
4066 csig->params [0] = &mono_defaults.string_class->byval_arg;
4067 csig->params [1] = &(mono_class_load_from_name (mono_defaults.corlib, "System.Reflection", "Assembly"))->byval_arg;
4068 csig->params [2] = &mono_defaults.boolean_class->byval_arg;
4069 add_method (acfg, get_runtime_invoke_sig (csig));
4070
4071 /* runtime-invoke used by finalizers */
4072 add_method (acfg, get_runtime_invoke (acfg, mono_class_get_method_from_name_flags (mono_defaults.object_class, "Finalize", 0, 0), TRUE));
4073
4074 /* This is used by mono_runtime_capture_context () */
4075 method = mono_get_context_capture_method ();
4076 if (method)
4077 add_method (acfg, get_runtime_invoke (acfg, method, FALSE));
4078
4079 #ifdef MONO_ARCH_DYN_CALL_SUPPORTED
4080 if (!acfg->aot_opts.llvm_only)
4081 add_method (acfg, mono_marshal_get_runtime_invoke_dynamic ());
4082 #endif
4083
4084 /* These are used by mono_jit_runtime_invoke () to calls gsharedvt out wrappers */
4085 if (acfg->aot_opts.llvm_only) {
4086 int variants;
4087
4088 /* Create simplified signatures which match the signature used by the gsharedvt out wrappers */
4089 for (variants = 0; variants < 4; ++variants) {
4090 for (i = 0; i < 16; ++i) {
4091 sig = mini_get_gsharedvt_out_sig_wrapper_signature ((variants & 1) > 0, (variants & 2) > 0, i);
4092 add_extra_method (acfg, mono_marshal_get_runtime_invoke_for_sig (sig));
4093
4094 g_free (sig);
4095 }
4096 }
4097 }
4098
4099 /* stelemref */
4100 add_method (acfg, mono_marshal_get_stelemref ());
4101
4102 /* Managed Allocators */
4103 nallocators = mono_gc_get_managed_allocator_types ();
4104 for (i = 0; i < nallocators; ++i) {
4105 if ((m = mono_gc_get_managed_allocator_by_type (i, MANAGED_ALLOCATOR_REGULAR)))
4106 add_method (acfg, m);
4107 if ((m = mono_gc_get_managed_allocator_by_type (i, MANAGED_ALLOCATOR_SLOW_PATH)))
4108 add_method (acfg, m);
4109 if ((m = mono_gc_get_managed_allocator_by_type (i, MANAGED_ALLOCATOR_PROFILER)))
4110 add_method (acfg, m);
4111 }
4112
4113 /* write barriers */
4114 if (mono_gc_is_moving ()) {
4115 add_method (acfg, mono_gc_get_specific_write_barrier (FALSE));
4116 add_method (acfg, mono_gc_get_specific_write_barrier (TRUE));
4117 }
4118
4119 /* Stelemref wrappers */
4120 {
4121 MonoMethod **wrappers;
4122 int nwrappers;
4123
4124 wrappers = mono_marshal_get_virtual_stelemref_wrappers (&nwrappers);
4125 for (i = 0; i < nwrappers; ++i)
4126 add_method (acfg, wrappers [i]);
4127 g_free (wrappers);
4128 }
4129
4130 /* castclass_with_check wrapper */
4131 add_method (acfg, mono_marshal_get_castclass_with_cache ());
4132 /* isinst_with_check wrapper */
4133 add_method (acfg, mono_marshal_get_isinst_with_cache ());
4134
4135 /* JIT icall wrappers */
4136 /* FIXME: locking - this is "safe" as full-AOT threads don't mutate the icall hash*/
4137 g_hash_table_foreach (mono_get_jit_icall_info (), add_jit_icall_wrapper, acfg);
4138 }
4139
4140 /*
4141 * remoting-invoke-with-check wrappers are very frequent, so avoid emitting them,
4142 * we use the original method instead at runtime.
4143 * Since full-aot doesn't support remoting, this is not a problem.
4144 */
4145 #if 0
4146 /* remoting-invoke wrappers */
4147 for (i = 0; i < acfg->image->tables [MONO_TABLE_METHOD].rows; ++i) {
4148 MonoError error;
4149 MonoMethodSignature *sig;
4150
4151 token = MONO_TOKEN_METHOD_DEF | (i + 1);
4152 method = mono_get_method_checked (acfg->image, token, NULL, NULL, &error);
4153 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
4154
4155 sig = mono_method_signature (method);
4156
4157 if (sig->hasthis && (method->klass->marshalbyref || method->klass == mono_defaults.object_class)) {
4158 m = mono_marshal_get_remoting_invoke_with_check (method);
4159
4160 add_method (acfg, m);
4161 }
4162 }
4163 #endif
4164
4165 /* delegate-invoke wrappers */
4166 for (i = 0; i < acfg->image->tables [MONO_TABLE_TYPEDEF].rows; ++i) {
4167 MonoError error;
4168 MonoClass *klass;
4169 MonoCustomAttrInfo *cattr;
4170
4171 token = MONO_TOKEN_TYPE_DEF | (i + 1);
4172 klass = mono_class_get_checked (acfg->image, token, &error);
4173
4174 if (!klass) {
4175 mono_error_cleanup (&error);
4176 continue;
4177 }
4178
4179 if (!klass->delegate || klass == mono_defaults.delegate_class || klass == mono_defaults.multicastdelegate_class)
4180 continue;
4181
4182 if (!mono_class_is_gtd (klass)) {
4183 method = mono_get_delegate_invoke (klass);
4184
4185 m = mono_marshal_get_delegate_invoke (method, NULL);
4186
4187 add_method (acfg, m);
4188
4189 method = mono_class_get_method_from_name_flags (klass, "BeginInvoke", -1, 0);
4190 if (method)
4191 add_method (acfg, mono_marshal_get_delegate_begin_invoke (method));
4192
4193 method = mono_class_get_method_from_name_flags (klass, "EndInvoke", -1, 0);
4194 if (method)
4195 add_method (acfg, mono_marshal_get_delegate_end_invoke (method));
4196
4197 cattr = mono_custom_attrs_from_class_checked (klass, &error);
4198 if (!is_ok (&error)) {
4199 mono_error_cleanup (&error);
4200 continue;
4201 }
4202
4203 if (cattr) {
4204 int j;
4205
4206 for (j = 0; j < cattr->num_attrs; ++j)
4207 if (cattr->attrs [j].ctor && (!strcmp (cattr->attrs [j].ctor->klass->name, "MonoNativeFunctionWrapperAttribute") || !strcmp (cattr->attrs [j].ctor->klass->name, "UnmanagedFunctionPointerAttribute")))
4208 break;
4209 if (j < cattr->num_attrs) {
4210 MonoMethod *invoke;
4211 MonoMethod *wrapper;
4212 MonoMethod *del_invoke;
4213
4214 /* Add wrappers needed by mono_ftnptr_to_delegate () */
4215 invoke = mono_get_delegate_invoke (klass);
4216 wrapper = mono_marshal_get_native_func_wrapper_aot (klass);
4217 del_invoke = mono_marshal_get_delegate_invoke_internal (invoke, FALSE, TRUE, wrapper);
4218 add_method (acfg, wrapper);
4219 add_method (acfg, del_invoke);
4220 }
4221 }
4222 } else if ((acfg->opts & MONO_OPT_GSHAREDVT) && mono_class_is_gtd (klass)) {
4223 MonoError error;
4224 MonoGenericContext ctx;
4225 MonoMethod *inst, *gshared;
4226
4227 /*
4228 * Emit gsharedvt versions of the generic delegate-invoke wrappers
4229 */
4230 /* Invoke */
4231 method = mono_get_delegate_invoke (klass);
4232 create_gsharedvt_inst (acfg, method, &ctx);
4233
4234 inst = mono_class_inflate_generic_method_checked (method, &ctx, &error);
4235 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
4236
4237 m = mono_marshal_get_delegate_invoke (inst, NULL);
4238 g_assert (m->is_inflated);
4239
4240 gshared = mini_get_shared_method_full (m, FALSE, TRUE);
4241 add_extra_method (acfg, gshared);
4242
4243 /* begin-invoke */
4244 method = mono_get_delegate_begin_invoke (klass);
4245 if (method) {
4246 create_gsharedvt_inst (acfg, method, &ctx);
4247
4248 inst = mono_class_inflate_generic_method_checked (method, &ctx, &error);
4249 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
4250
4251 m = mono_marshal_get_delegate_begin_invoke (inst);
4252 g_assert (m->is_inflated);
4253
4254 gshared = mini_get_shared_method_full (m, FALSE, TRUE);
4255 add_extra_method (acfg, gshared);
4256 }
4257
4258 /* end-invoke */
4259 method = mono_get_delegate_end_invoke (klass);
4260 if (method) {
4261 create_gsharedvt_inst (acfg, method, &ctx);
4262
4263 inst = mono_class_inflate_generic_method_checked (method, &ctx, &error);
4264 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
4265
4266 m = mono_marshal_get_delegate_end_invoke (inst);
4267 g_assert (m->is_inflated);
4268
4269 gshared = mini_get_shared_method_full (m, FALSE, TRUE);
4270 add_extra_method (acfg, gshared);
4271 }
4272 }
4273 }
4274
4275 /* array access wrappers */
4276 for (i = 0; i < acfg->image->tables [MONO_TABLE_TYPESPEC].rows; ++i) {
4277 MonoError error;
4278 MonoClass *klass;
4279
4280 token = MONO_TOKEN_TYPE_SPEC | (i + 1);
4281 klass = mono_class_get_checked (acfg->image, token, &error);
4282
4283 if (!klass) {
4284 mono_error_cleanup (&error);
4285 continue;
4286 }
4287
4288 if (klass->rank && MONO_TYPE_IS_PRIMITIVE (&klass->element_class->byval_arg)) {
4289 MonoMethod *m, *wrapper;
4290
4291 /* Add runtime-invoke wrappers too */
4292
4293 m = mono_class_get_method_from_name (klass, "Get", -1);
4294 g_assert (m);
4295 wrapper = mono_marshal_get_array_accessor_wrapper (m);
4296 add_extra_method (acfg, wrapper);
4297 if (!acfg->aot_opts.llvm_only)
4298 add_extra_method (acfg, get_runtime_invoke (acfg, wrapper, FALSE));
4299
4300 m = mono_class_get_method_from_name (klass, "Set", -1);
4301 g_assert (m);
4302 wrapper = mono_marshal_get_array_accessor_wrapper (m);
4303 add_extra_method (acfg, wrapper);
4304 if (!acfg->aot_opts.llvm_only)
4305 add_extra_method (acfg, get_runtime_invoke (acfg, wrapper, FALSE));
4306 }
4307 }
4308
4309 /* Synchronized wrappers */
4310 for (i = 0; i < acfg->image->tables [MONO_TABLE_METHOD].rows; ++i) {
4311 MonoError error;
4312 token = MONO_TOKEN_METHOD_DEF | (i + 1);
4313 method = mono_get_method_checked (acfg->image, token, NULL, NULL, &error);
4314 report_loader_error (acfg, &error, TRUE, "Failed to load method token 0x%x due to %s\n", i, mono_error_get_message (&error));
4315
4316 if (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) {
4317 if (method->is_generic) {
4318 // FIXME:
4319 } else if ((acfg->opts & MONO_OPT_GSHAREDVT) && mono_class_is_gtd (method->klass)) {
4320 MonoError error;
4321 MonoGenericContext ctx;
4322 MonoMethod *inst, *gshared, *m;
4323
4324 /*
4325 * Create a generic wrapper for a generic instance, and AOT that.
4326 */
4327 create_gsharedvt_inst (acfg, method, &ctx);
4328 inst = mono_class_inflate_generic_method_checked (method, &ctx, &error);
4329 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
4330 m = mono_marshal_get_synchronized_wrapper (inst);
4331 g_assert (m->is_inflated);
4332 gshared = mini_get_shared_method_full (m, FALSE, TRUE);
4333 add_method (acfg, gshared);
4334 } else {
4335 add_method (acfg, mono_marshal_get_synchronized_wrapper (method));
4336 }
4337 }
4338 }
4339
4340 /* pinvoke wrappers */
4341 for (i = 0; i < acfg->image->tables [MONO_TABLE_METHOD].rows; ++i) {
4342 MonoError error;
4343 MonoMethod *method;
4344 guint32 token = MONO_TOKEN_METHOD_DEF | (i + 1);
4345
4346 method = mono_get_method_checked (acfg->image, token, NULL, NULL, &error);
4347 report_loader_error (acfg, &error, TRUE, "Failed to load method token 0x%x due to %s\n", i, mono_error_get_message (&error));
4348
4349 if ((method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
4350 (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL)) {
4351 add_method (acfg, mono_marshal_get_native_wrapper (method, TRUE, TRUE));
4352 }
4353
4354 if (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
4355 if (acfg->aot_opts.llvm_only) {
4356 /* The wrappers have a different signature (hasthis is not set) so need to add this too */
4357 add_gsharedvt_wrappers (acfg, mono_method_signature (method), FALSE, TRUE);
4358 }
4359 }
4360 }
4361
4362 /* native-to-managed wrappers */
4363 for (i = 0; i < acfg->image->tables [MONO_TABLE_METHOD].rows; ++i) {
4364 MonoError error;
4365 MonoMethod *method;
4366 guint32 token = MONO_TOKEN_METHOD_DEF | (i + 1);
4367 MonoCustomAttrInfo *cattr;
4368 int j;
4369
4370 method = mono_get_method_checked (acfg->image, token, NULL, NULL, &error);
4371 report_loader_error (acfg, &error, TRUE, "Failed to load method token 0x%x due to %s\n", i, mono_error_get_message (&error));
4372
4373 /*
4374 * Only generate native-to-managed wrappers for methods which have an
4375 * attribute named MonoPInvokeCallbackAttribute. We search for the attribute by
4376 * name to avoid defining a new assembly to contain it.
4377 */
4378 cattr = mono_custom_attrs_from_method_checked (method, &error);
4379 if (!is_ok (&error)) {
4380 char *name = mono_method_get_full_name (method);
4381 report_loader_error (acfg, &error, TRUE, "Failed to load custom attributes from method %s due to %s\n", name, mono_error_get_message (&error));
4382 g_free (name);
4383 }
4384
4385 if (cattr) {
4386 for (j = 0; j < cattr->num_attrs; ++j)
4387 if (cattr->attrs [j].ctor && !strcmp (cattr->attrs [j].ctor->klass->name, "MonoPInvokeCallbackAttribute"))
4388 break;
4389 if (j < cattr->num_attrs) {
4390 MonoCustomAttrEntry *e = &cattr->attrs [j];
4391 MonoMethodSignature *sig = mono_method_signature (e->ctor);
4392 const char *p = (const char*)e->data;
4393 const char *named;
4394 int slen, num_named, named_type;
4395 char *n;
4396 MonoType *t;
4397 MonoClass *klass;
4398 char *export_name = NULL;
4399 MonoMethod *wrapper;
4400
4401 /* this cannot be enforced by the C# compiler so we must give the user some warning before aborting */
4402 if (!(method->flags & METHOD_ATTRIBUTE_STATIC)) {
4403 g_warning ("AOT restriction: Method '%s' must be static since it is decorated with [MonoPInvokeCallback]. See http://ios.xamarin.com/Documentation/Limitations#Reverse_Callbacks",
4404 mono_method_full_name (method, TRUE));
4405 exit (1);
4406 }
4407
4408 g_assert (sig->param_count == 1);
4409 g_assert (sig->params [0]->type == MONO_TYPE_CLASS && !strcmp (mono_class_from_mono_type (sig->params [0])->name, "Type"));
4410
4411 /*
4412 * Decode the cattr manually since we can't create objects
4413 * during aot compilation.
4414 */
4415
4416 /* Skip prolog */
4417 p += 2;
4418
4419 /* From load_cattr_value () in reflection.c */
4420 slen = mono_metadata_decode_value (p, &p);
4421 n = (char *)g_memdup (p, slen + 1);
4422 n [slen] = 0;
4423 t = mono_reflection_type_from_name_checked (n, acfg->image, &error);
4424 g_assert (t);
4425 mono_error_assert_ok (&error);
4426 g_free (n);
4427
4428 klass = mono_class_from_mono_type (t);
4429 g_assert (klass->parent == mono_defaults.multicastdelegate_class);
4430
4431 p += slen;
4432
4433 num_named = read16 (p);
4434 p += 2;
4435
4436 g_assert (num_named < 2);
4437 if (num_named == 1) {
4438 int name_len;
4439 char *name;
4440
4441 /* parse ExportSymbol attribute */
4442 named = p;
4443 named_type = *named;
4444 named += 1;
4445 /* data_type = *named; */
4446 named += 1;
4447
4448 name_len = mono_metadata_decode_blob_size (named, &named);
4449 name = (char *)g_malloc (name_len + 1);
4450 memcpy (name, named, name_len);
4451 name [name_len] = 0;
4452 named += name_len;
4453
4454 g_assert (named_type == 0x54);
4455 g_assert (!strcmp (name, "ExportSymbol"));
4456
4457 /* load_cattr_value (), string case */
4458 g_assert (*named != (char)0xff);
4459 slen = mono_metadata_decode_value (named, &named);
4460 export_name = (char *)g_malloc (slen + 1);
4461 memcpy (export_name, named, slen);
4462 export_name [slen] = 0;
4463 named += slen;
4464 }
4465
4466 wrapper = mono_marshal_get_managed_wrapper (method, klass, 0, &error);
4467 mono_error_assert_ok (&error);
4468
4469 add_method (acfg, wrapper);
4470 if (export_name)
4471 g_hash_table_insert (acfg->export_names, wrapper, export_name);
4472 }
4473 g_free (cattr);
4474 }
4475
4476 if ((method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
4477 (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL)) {
4478 add_method (acfg, mono_marshal_get_native_wrapper (method, TRUE, TRUE));
4479 }
4480 }
4481
4482 /* StructureToPtr/PtrToStructure wrappers */
4483 for (i = 0; i < acfg->image->tables [MONO_TABLE_TYPEDEF].rows; ++i) {
4484 MonoError error;
4485 MonoClass *klass;
4486
4487 token = MONO_TOKEN_TYPE_DEF | (i + 1);
4488 klass = mono_class_get_checked (acfg->image, token, &error);
4489
4490 if (!klass) {
4491 mono_error_cleanup (&error);
4492 continue;
4493 }
4494
4495 if (klass->valuetype && !mono_class_is_gtd (klass) && can_marshal_struct (klass) &&
4496 !(klass->nested_in && strstr (klass->nested_in->name, "<PrivateImplementationDetails>") == klass->nested_in->name)) {
4497 add_method (acfg, mono_marshal_get_struct_to_ptr (klass));
4498 add_method (acfg, mono_marshal_get_ptr_to_struct (klass));
4499 }
4500 }
4501 }
4502
4503 static gboolean
has_type_vars(MonoClass * klass)4504 has_type_vars (MonoClass *klass)
4505 {
4506 if ((klass->byval_arg.type == MONO_TYPE_VAR) || (klass->byval_arg.type == MONO_TYPE_MVAR))
4507 return TRUE;
4508 if (klass->rank)
4509 return has_type_vars (klass->element_class);
4510 if (mono_class_is_ginst (klass)) {
4511 MonoGenericContext *context = &mono_class_get_generic_class (klass)->context;
4512 if (context->class_inst) {
4513 int i;
4514
4515 for (i = 0; i < context->class_inst->type_argc; ++i)
4516 if (has_type_vars (mono_class_from_mono_type (context->class_inst->type_argv [i])))
4517 return TRUE;
4518 }
4519 }
4520 if (mono_class_is_gtd (klass))
4521 return TRUE;
4522 return FALSE;
4523 }
4524
4525 static gboolean
is_vt_inst(MonoGenericInst * inst)4526 is_vt_inst (MonoGenericInst *inst)
4527 {
4528 int i;
4529
4530 for (i = 0; i < inst->type_argc; ++i) {
4531 MonoType *t = inst->type_argv [i];
4532 if (MONO_TYPE_ISSTRUCT (t) || t->type == MONO_TYPE_VALUETYPE)
4533 return TRUE;
4534 }
4535 return FALSE;
4536 }
4537
4538 static gboolean
method_has_type_vars(MonoMethod * method)4539 method_has_type_vars (MonoMethod *method)
4540 {
4541 if (has_type_vars (method->klass))
4542 return TRUE;
4543
4544 if (method->is_inflated) {
4545 MonoGenericContext *context = mono_method_get_context (method);
4546 if (context->method_inst) {
4547 int i;
4548
4549 for (i = 0; i < context->method_inst->type_argc; ++i)
4550 if (has_type_vars (mono_class_from_mono_type (context->method_inst->type_argv [i])))
4551 return TRUE;
4552 }
4553 }
4554 return FALSE;
4555 }
4556
4557 static
mono_aot_mode_is_full(MonoAotOptions * opts)4558 gboolean mono_aot_mode_is_full (MonoAotOptions *opts)
4559 {
4560 return opts->mode == MONO_AOT_MODE_FULL || opts->mode == MONO_AOT_MODE_INTERP;
4561 }
4562
4563 static
mono_aot_mode_is_interp(MonoAotOptions * opts)4564 gboolean mono_aot_mode_is_interp (MonoAotOptions *opts)
4565 {
4566 return opts->mode == MONO_AOT_MODE_INTERP;
4567 }
4568
4569 static
mono_aot_mode_is_hybrid(MonoAotOptions * opts)4570 gboolean mono_aot_mode_is_hybrid (MonoAotOptions *opts)
4571 {
4572 return opts->mode == MONO_AOT_MODE_HYBRID;
4573 }
4574
4575 static void add_generic_class_with_depth (MonoAotCompile *acfg, MonoClass *klass, int depth, const char *ref);
4576
4577 static void
add_generic_class(MonoAotCompile * acfg,MonoClass * klass,gboolean force,const char * ref)4578 add_generic_class (MonoAotCompile *acfg, MonoClass *klass, gboolean force, const char *ref)
4579 {
4580 /* This might lead to a huge code blowup so only do it if neccesary */
4581 if (!mono_aot_mode_is_full (&acfg->aot_opts) && !mono_aot_mode_is_hybrid (&acfg->aot_opts) && !force)
4582 return;
4583
4584 add_generic_class_with_depth (acfg, klass, 0, ref);
4585 }
4586
4587 static gboolean
check_type_depth(MonoType * t,int depth)4588 check_type_depth (MonoType *t, int depth)
4589 {
4590 int i;
4591
4592 if (depth > 8)
4593 return TRUE;
4594
4595 switch (t->type) {
4596 case MONO_TYPE_GENERICINST: {
4597 MonoGenericClass *gklass = t->data.generic_class;
4598 MonoGenericInst *ginst = gklass->context.class_inst;
4599
4600 if (ginst) {
4601 for (i = 0; i < ginst->type_argc; ++i) {
4602 if (check_type_depth (ginst->type_argv [i], depth + 1))
4603 return TRUE;
4604 }
4605 }
4606 break;
4607 }
4608 default:
4609 break;
4610 }
4611
4612 return FALSE;
4613 }
4614
4615 static void
4616 add_types_from_method_header (MonoAotCompile *acfg, MonoMethod *method);
4617
4618 /*
4619 * add_generic_class:
4620 *
4621 * Add all methods of a generic class.
4622 */
4623 static void
add_generic_class_with_depth(MonoAotCompile * acfg,MonoClass * klass,int depth,const char * ref)4624 add_generic_class_with_depth (MonoAotCompile *acfg, MonoClass *klass, int depth, const char *ref)
4625 {
4626 MonoMethod *method;
4627 MonoClassField *field;
4628 gpointer iter;
4629 gboolean use_gsharedvt = FALSE;
4630
4631 if (!acfg->ginst_hash)
4632 acfg->ginst_hash = g_hash_table_new (NULL, NULL);
4633
4634 mono_class_init (klass);
4635
4636 if (mono_class_is_ginst (klass) && mono_class_get_generic_class (klass)->context.class_inst->is_open)
4637 return;
4638
4639 if (has_type_vars (klass))
4640 return;
4641
4642 if (!mono_class_is_ginst (klass) && !klass->rank)
4643 return;
4644
4645 if (mono_class_has_failure (klass))
4646 return;
4647
4648 if (!acfg->ginst_hash)
4649 acfg->ginst_hash = g_hash_table_new (NULL, NULL);
4650
4651 if (g_hash_table_lookup (acfg->ginst_hash, klass))
4652 return;
4653
4654 if (check_type_depth (&klass->byval_arg, 0))
4655 return;
4656
4657 if (acfg->aot_opts.log_generics)
4658 aot_printf (acfg, "%*sAdding generic instance %s [%s].\n", depth, "", mono_type_full_name (&klass->byval_arg), ref);
4659
4660 g_hash_table_insert (acfg->ginst_hash, klass, klass);
4661
4662 /*
4663 * Use gsharedvt for generic collections with vtype arguments to avoid code blowup.
4664 * Enable this only for some classes since gsharedvt might not support all methods.
4665 */
4666 if ((acfg->opts & MONO_OPT_GSHAREDVT) && klass->image == mono_defaults.corlib && mono_class_is_ginst (klass) && mono_class_get_generic_class (klass)->context.class_inst && is_vt_inst (mono_class_get_generic_class (klass)->context.class_inst) &&
4667 (!strcmp (klass->name, "Dictionary`2") || !strcmp (klass->name, "List`1") || !strcmp (klass->name, "ReadOnlyCollection`1")))
4668 use_gsharedvt = TRUE;
4669
4670 iter = NULL;
4671 while ((method = mono_class_get_methods (klass, &iter))) {
4672 if ((acfg->opts & MONO_OPT_GSHAREDVT) && method->is_inflated && mono_method_get_context (method)->method_inst) {
4673 /*
4674 * This is partial sharing, and we can't handle it yet
4675 */
4676 continue;
4677 }
4678
4679 if (mono_method_is_generic_sharable_full (method, FALSE, FALSE, use_gsharedvt)) {
4680 /* Already added */
4681 add_types_from_method_header (acfg, method);
4682 continue;
4683 }
4684
4685 if (method->is_generic)
4686 /* FIXME: */
4687 continue;
4688
4689 /*
4690 * FIXME: Instances which are referenced by these methods are not added,
4691 * for example Array.Resize<int> for List<int>.Add ().
4692 */
4693 add_extra_method_with_depth (acfg, method, depth + 1);
4694 }
4695
4696 iter = NULL;
4697 while ((field = mono_class_get_fields (klass, &iter))) {
4698 if (field->type->type == MONO_TYPE_GENERICINST)
4699 add_generic_class_with_depth (acfg, mono_class_from_mono_type (field->type), depth + 1, "field");
4700 }
4701
4702 if (klass->delegate) {
4703 method = mono_get_delegate_invoke (klass);
4704
4705 method = mono_marshal_get_delegate_invoke (method, NULL);
4706
4707 if (acfg->aot_opts.log_generics)
4708 aot_printf (acfg, "%*sAdding method %s.\n", depth, "", mono_method_get_full_name (method));
4709
4710 add_method (acfg, method);
4711 }
4712
4713 /* Add superclasses */
4714 if (klass->parent)
4715 add_generic_class_with_depth (acfg, klass->parent, depth, "parent");
4716
4717 /*
4718 * For ICollection<T>, add instances of the helper methods
4719 * in Array, since a T[] could be cast to ICollection<T>.
4720 */
4721 if (klass->image == mono_defaults.corlib && !strcmp (klass->name_space, "System.Collections.Generic") &&
4722 (!strcmp(klass->name, "ICollection`1") || !strcmp (klass->name, "IEnumerable`1") || !strcmp (klass->name, "IList`1") || !strcmp (klass->name, "IEnumerator`1") || !strcmp (klass->name, "IReadOnlyList`1"))) {
4723 MonoClass *tclass = mono_class_from_mono_type (mono_class_get_generic_class (klass)->context.class_inst->type_argv [0]);
4724 MonoClass *array_class = mono_bounded_array_class_get (tclass, 1, FALSE);
4725 gpointer iter;
4726 char *name_prefix;
4727
4728 if (!strcmp (klass->name, "IEnumerator`1"))
4729 name_prefix = g_strdup_printf ("%s.%s", klass->name_space, "IEnumerable`1");
4730 else
4731 name_prefix = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
4732
4733 /* Add the T[]/InternalEnumerator class */
4734 if (!strcmp (klass->name, "IEnumerable`1") || !strcmp (klass->name, "IEnumerator`1")) {
4735 MonoError error;
4736 MonoClass *nclass;
4737
4738 iter = NULL;
4739 while ((nclass = mono_class_get_nested_types (array_class->parent, &iter))) {
4740 if (!strcmp (nclass->name, "InternalEnumerator`1"))
4741 break;
4742 }
4743 g_assert (nclass);
4744 nclass = mono_class_inflate_generic_class_checked (nclass, mono_generic_class_get_context (mono_class_get_generic_class (klass)), &error);
4745 mono_error_assert_ok (&error); /* FIXME don't swallow the error */
4746 add_generic_class (acfg, nclass, FALSE, "ICollection<T>");
4747 }
4748
4749 iter = NULL;
4750 while ((method = mono_class_get_methods (array_class, &iter))) {
4751 if (strstr (method->name, name_prefix)) {
4752 MonoMethod *m = mono_aot_get_array_helper_from_wrapper (method);
4753
4754 add_extra_method_with_depth (acfg, m, depth);
4755 }
4756 }
4757
4758 g_free (name_prefix);
4759 }
4760
4761 /* Add an instance of GenericComparer<T> which is created dynamically by Comparer<T> */
4762 if (klass->image == mono_defaults.corlib && !strcmp (klass->name_space, "System.Collections.Generic") && !strcmp (klass->name, "Comparer`1")) {
4763 MonoError error;
4764 MonoClass *tclass = mono_class_from_mono_type (mono_class_get_generic_class (klass)->context.class_inst->type_argv [0]);
4765 MonoClass *icomparable, *gcomparer, *icomparable_inst;
4766 MonoGenericContext ctx;
4767 MonoType *args [16];
4768
4769 memset (&ctx, 0, sizeof (ctx));
4770
4771 icomparable = mono_class_load_from_name (mono_defaults.corlib, "System", "IComparable`1");
4772
4773 args [0] = &tclass->byval_arg;
4774 ctx.class_inst = mono_metadata_get_generic_inst (1, args);
4775
4776 icomparable_inst = mono_class_inflate_generic_class_checked (icomparable, &ctx, &error);
4777 mono_error_assert_ok (&error); /* FIXME don't swallow the error */
4778
4779 if (mono_class_is_assignable_from (icomparable_inst, tclass)) {
4780 MonoClass *gcomparer_inst;
4781 gcomparer = mono_class_load_from_name (mono_defaults.corlib, "System.Collections.Generic", "GenericComparer`1");
4782 gcomparer_inst = mono_class_inflate_generic_class_checked (gcomparer, &ctx, &error);
4783 mono_error_assert_ok (&error); /* FIXME don't swallow the error */
4784
4785 add_generic_class (acfg, gcomparer_inst, FALSE, "Comparer<T>");
4786 }
4787 }
4788
4789 /* Add an instance of GenericEqualityComparer<T> which is created dynamically by EqualityComparer<T> */
4790 if (klass->image == mono_defaults.corlib && !strcmp (klass->name_space, "System.Collections.Generic") && !strcmp (klass->name, "EqualityComparer`1")) {
4791 MonoError error;
4792 MonoClass *tclass = mono_class_from_mono_type (mono_class_get_generic_class (klass)->context.class_inst->type_argv [0]);
4793 MonoClass *iface, *gcomparer, *iface_inst;
4794 MonoGenericContext ctx;
4795 MonoType *args [16];
4796
4797 memset (&ctx, 0, sizeof (ctx));
4798
4799 iface = mono_class_load_from_name (mono_defaults.corlib, "System", "IEquatable`1");
4800 g_assert (iface);
4801 args [0] = &tclass->byval_arg;
4802 ctx.class_inst = mono_metadata_get_generic_inst (1, args);
4803
4804 iface_inst = mono_class_inflate_generic_class_checked (iface, &ctx, &error);
4805 mono_error_assert_ok (&error); /* FIXME don't swallow the error */
4806
4807 if (mono_class_is_assignable_from (iface_inst, tclass)) {
4808 MonoClass *gcomparer_inst;
4809 MonoError error;
4810
4811 gcomparer = mono_class_load_from_name (mono_defaults.corlib, "System.Collections.Generic", "GenericEqualityComparer`1");
4812 gcomparer_inst = mono_class_inflate_generic_class_checked (gcomparer, &ctx, &error);
4813 mono_error_assert_ok (&error); /* FIXME don't swallow the error */
4814 add_generic_class (acfg, gcomparer_inst, FALSE, "EqualityComparer<T>");
4815 }
4816 }
4817
4818 /* Add an instance of EnumComparer<T> which is created dynamically by EqualityComparer<T> for enums */
4819 if (klass->image == mono_defaults.corlib && !strcmp (klass->name_space, "System.Collections.Generic") && !strcmp (klass->name, "EqualityComparer`1")) {
4820 MonoClass *enum_comparer;
4821 MonoClass *tclass = mono_class_from_mono_type (mono_class_get_generic_class (klass)->context.class_inst->type_argv [0]);
4822 MonoGenericContext ctx;
4823 MonoType *args [16];
4824
4825 if (mono_class_is_enum (tclass)) {
4826 MonoClass *enum_comparer_inst;
4827 MonoError error;
4828
4829 memset (&ctx, 0, sizeof (ctx));
4830 args [0] = &tclass->byval_arg;
4831 ctx.class_inst = mono_metadata_get_generic_inst (1, args);
4832
4833 enum_comparer = mono_class_load_from_name (mono_defaults.corlib, "System.Collections.Generic", "EnumEqualityComparer`1");
4834 enum_comparer_inst = mono_class_inflate_generic_class_checked (enum_comparer, &ctx, &error);
4835 mono_error_assert_ok (&error); /* FIXME don't swallow the error */
4836 add_generic_class (acfg, enum_comparer_inst, FALSE, "EqualityComparer<T>");
4837 }
4838 }
4839
4840 /* Add an instance of ObjectComparer<T> which is created dynamically by Comparer<T> for enums */
4841 if (klass->image == mono_defaults.corlib && !strcmp (klass->name_space, "System.Collections.Generic") && !strcmp (klass->name, "Comparer`1")) {
4842 MonoClass *comparer;
4843 MonoClass *tclass = mono_class_from_mono_type (mono_class_get_generic_class (klass)->context.class_inst->type_argv [0]);
4844 MonoGenericContext ctx;
4845 MonoType *args [16];
4846
4847 if (mono_class_is_enum (tclass)) {
4848 MonoClass *comparer_inst;
4849 MonoError error;
4850
4851 memset (&ctx, 0, sizeof (ctx));
4852 args [0] = &tclass->byval_arg;
4853 ctx.class_inst = mono_metadata_get_generic_inst (1, args);
4854
4855 comparer = mono_class_load_from_name (mono_defaults.corlib, "System.Collections.Generic", "ObjectComparer`1");
4856 comparer_inst = mono_class_inflate_generic_class_checked (comparer, &ctx, &error);
4857 mono_error_assert_ok (&error); /* FIXME don't swallow the error */
4858 add_generic_class (acfg, comparer_inst, FALSE, "Comparer<T>");
4859 }
4860 }
4861 }
4862
4863 static void
add_instances_of(MonoAotCompile * acfg,MonoClass * klass,MonoType ** insts,int ninsts,gboolean force)4864 add_instances_of (MonoAotCompile *acfg, MonoClass *klass, MonoType **insts, int ninsts, gboolean force)
4865 {
4866 int i;
4867 MonoGenericContext ctx;
4868 MonoType *args [16];
4869
4870 if (acfg->aot_opts.no_instances)
4871 return;
4872
4873 memset (&ctx, 0, sizeof (ctx));
4874
4875 for (i = 0; i < ninsts; ++i) {
4876 MonoError error;
4877 MonoClass *generic_inst;
4878 args [0] = insts [i];
4879 ctx.class_inst = mono_metadata_get_generic_inst (1, args);
4880 generic_inst = mono_class_inflate_generic_class_checked (klass, &ctx, &error);
4881 mono_error_assert_ok (&error); /* FIXME don't swallow the error */
4882 add_generic_class (acfg, generic_inst, force, "");
4883 }
4884 }
4885
4886 static void
add_types_from_method_header(MonoAotCompile * acfg,MonoMethod * method)4887 add_types_from_method_header (MonoAotCompile *acfg, MonoMethod *method)
4888 {
4889 MonoError error;
4890 MonoMethodHeader *header;
4891 MonoMethodSignature *sig;
4892 int j, depth;
4893
4894 depth = GPOINTER_TO_UINT (g_hash_table_lookup (acfg->method_depth, method));
4895
4896 sig = mono_method_signature (method);
4897
4898 if (sig) {
4899 for (j = 0; j < sig->param_count; ++j)
4900 if (sig->params [j]->type == MONO_TYPE_GENERICINST)
4901 add_generic_class_with_depth (acfg, mono_class_from_mono_type (sig->params [j]), depth + 1, "arg");
4902 }
4903
4904 header = mono_method_get_header_checked (method, &error);
4905
4906 if (header) {
4907 for (j = 0; j < header->num_locals; ++j)
4908 if (header->locals [j]->type == MONO_TYPE_GENERICINST)
4909 add_generic_class_with_depth (acfg, mono_class_from_mono_type (header->locals [j]), depth + 1, "local");
4910 mono_metadata_free_mh (header);
4911 } else {
4912 mono_error_cleanup (&error); /* FIXME report the error */
4913 }
4914
4915 }
4916
4917 /*
4918 * add_generic_instances:
4919 *
4920 * Add instances referenced by the METHODSPEC/TYPESPEC table.
4921 */
4922 static void
add_generic_instances(MonoAotCompile * acfg)4923 add_generic_instances (MonoAotCompile *acfg)
4924 {
4925 int i;
4926 guint32 token;
4927 MonoMethod *method;
4928 MonoGenericContext *context;
4929
4930 if (acfg->aot_opts.no_instances)
4931 return;
4932
4933 for (i = 0; i < acfg->image->tables [MONO_TABLE_METHODSPEC].rows; ++i) {
4934 MonoError error;
4935 token = MONO_TOKEN_METHOD_SPEC | (i + 1);
4936 method = mono_get_method_checked (acfg->image, token, NULL, NULL, &error);
4937
4938 if (!method) {
4939 aot_printerrf (acfg, "Failed to load methodspec 0x%x due to %s.\n", token, mono_error_get_message (&error));
4940 aot_printerrf (acfg, "Run with MONO_LOG_LEVEL=debug for more information.\n");
4941 mono_error_cleanup (&error);
4942 continue;
4943 }
4944
4945 if (method->klass->image != acfg->image)
4946 continue;
4947
4948 context = mono_method_get_context (method);
4949
4950 if (context && ((context->class_inst && context->class_inst->is_open)))
4951 continue;
4952
4953 /*
4954 * For open methods, create an instantiation which can be passed to the JIT.
4955 * FIXME: Handle class_inst as well.
4956 */
4957 if (context && context->method_inst && context->method_inst->is_open) {
4958 MonoError error;
4959 MonoGenericContext shared_context;
4960 MonoGenericInst *inst;
4961 MonoType **type_argv;
4962 int i;
4963 MonoMethod *declaring_method;
4964 gboolean supported = TRUE;
4965
4966 /* Check that the context doesn't contain open constructed types */
4967 if (context->class_inst) {
4968 inst = context->class_inst;
4969 for (i = 0; i < inst->type_argc; ++i) {
4970 if (MONO_TYPE_IS_REFERENCE (inst->type_argv [i]) || inst->type_argv [i]->type == MONO_TYPE_VAR || inst->type_argv [i]->type == MONO_TYPE_MVAR)
4971 continue;
4972 if (mono_class_is_open_constructed_type (inst->type_argv [i]))
4973 supported = FALSE;
4974 }
4975 }
4976 if (context->method_inst) {
4977 inst = context->method_inst;
4978 for (i = 0; i < inst->type_argc; ++i) {
4979 if (MONO_TYPE_IS_REFERENCE (inst->type_argv [i]) || inst->type_argv [i]->type == MONO_TYPE_VAR || inst->type_argv [i]->type == MONO_TYPE_MVAR)
4980 continue;
4981 if (mono_class_is_open_constructed_type (inst->type_argv [i]))
4982 supported = FALSE;
4983 }
4984 }
4985
4986 if (!supported)
4987 continue;
4988
4989 memset (&shared_context, 0, sizeof (MonoGenericContext));
4990
4991 inst = context->class_inst;
4992 if (inst) {
4993 type_argv = g_new0 (MonoType*, inst->type_argc);
4994 for (i = 0; i < inst->type_argc; ++i) {
4995 if (MONO_TYPE_IS_REFERENCE (inst->type_argv [i]) || inst->type_argv [i]->type == MONO_TYPE_VAR || inst->type_argv [i]->type == MONO_TYPE_MVAR)
4996 type_argv [i] = &mono_defaults.object_class->byval_arg;
4997 else
4998 type_argv [i] = inst->type_argv [i];
4999 }
5000
5001 shared_context.class_inst = mono_metadata_get_generic_inst (inst->type_argc, type_argv);
5002 g_free (type_argv);
5003 }
5004
5005 inst = context->method_inst;
5006 if (inst) {
5007 type_argv = g_new0 (MonoType*, inst->type_argc);
5008 for (i = 0; i < inst->type_argc; ++i) {
5009 if (MONO_TYPE_IS_REFERENCE (inst->type_argv [i]) || inst->type_argv [i]->type == MONO_TYPE_VAR || inst->type_argv [i]->type == MONO_TYPE_MVAR)
5010 type_argv [i] = &mono_defaults.object_class->byval_arg;
5011 else
5012 type_argv [i] = inst->type_argv [i];
5013 }
5014
5015 shared_context.method_inst = mono_metadata_get_generic_inst (inst->type_argc, type_argv);
5016 g_free (type_argv);
5017 }
5018
5019 if (method->is_generic || mono_class_is_gtd (method->klass))
5020 declaring_method = method;
5021 else
5022 declaring_method = mono_method_get_declaring_generic_method (method);
5023
5024 method = mono_class_inflate_generic_method_checked (declaring_method, &shared_context, &error);
5025 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
5026 }
5027
5028 /*
5029 * If the method is fully sharable, it was already added in place of its
5030 * generic definition.
5031 */
5032 if (mono_method_is_generic_sharable_full (method, FALSE, FALSE, FALSE))
5033 continue;
5034
5035 /*
5036 * FIXME: Partially shared methods are not shared here, so we end up with
5037 * many identical methods.
5038 */
5039 add_extra_method (acfg, method);
5040 }
5041
5042 for (i = 0; i < acfg->image->tables [MONO_TABLE_TYPESPEC].rows; ++i) {
5043 MonoError error;
5044 MonoClass *klass;
5045
5046 token = MONO_TOKEN_TYPE_SPEC | (i + 1);
5047
5048 klass = mono_class_get_checked (acfg->image, token, &error);
5049 if (!klass || klass->rank) {
5050 mono_error_cleanup (&error);
5051 continue;
5052 }
5053
5054 add_generic_class (acfg, klass, FALSE, "typespec");
5055 }
5056
5057 /* Add types of args/locals */
5058 for (i = 0; i < acfg->methods->len; ++i) {
5059 method = (MonoMethod *)g_ptr_array_index (acfg->methods, i);
5060 add_types_from_method_header (acfg, method);
5061 }
5062
5063 if (acfg->image == mono_defaults.corlib) {
5064 MonoClass *klass;
5065 MonoType *insts [256];
5066 int ninsts = 0;
5067
5068 insts [ninsts ++] = &mono_defaults.byte_class->byval_arg;
5069 insts [ninsts ++] = &mono_defaults.sbyte_class->byval_arg;
5070 insts [ninsts ++] = &mono_defaults.int16_class->byval_arg;
5071 insts [ninsts ++] = &mono_defaults.uint16_class->byval_arg;
5072 insts [ninsts ++] = &mono_defaults.int32_class->byval_arg;
5073 insts [ninsts ++] = &mono_defaults.uint32_class->byval_arg;
5074 insts [ninsts ++] = &mono_defaults.int64_class->byval_arg;
5075 insts [ninsts ++] = &mono_defaults.uint64_class->byval_arg;
5076 insts [ninsts ++] = &mono_defaults.single_class->byval_arg;
5077 insts [ninsts ++] = &mono_defaults.double_class->byval_arg;
5078 insts [ninsts ++] = &mono_defaults.char_class->byval_arg;
5079 insts [ninsts ++] = &mono_defaults.boolean_class->byval_arg;
5080
5081 /* Add GenericComparer<T> instances for primitive types for Enum.ToString () */
5082 klass = mono_class_try_load_from_name (acfg->image, "System.Collections.Generic", "GenericComparer`1");
5083 if (klass)
5084 add_instances_of (acfg, klass, insts, ninsts, TRUE);
5085 klass = mono_class_try_load_from_name (acfg->image, "System.Collections.Generic", "GenericEqualityComparer`1");
5086 if (klass)
5087 add_instances_of (acfg, klass, insts, ninsts, TRUE);
5088
5089 /* Add instances of EnumEqualityComparer which are created by EqualityComparer<T> for enums */
5090 {
5091 MonoClass *enum_comparer;
5092 MonoType *insts [16];
5093 int ninsts;
5094
5095 ninsts = 0;
5096 insts [ninsts ++] = &mono_defaults.int32_class->byval_arg;
5097 insts [ninsts ++] = &mono_defaults.uint32_class->byval_arg;
5098 insts [ninsts ++] = &mono_defaults.uint16_class->byval_arg;
5099 insts [ninsts ++] = &mono_defaults.byte_class->byval_arg;
5100 enum_comparer = mono_class_load_from_name (mono_defaults.corlib, "System.Collections.Generic", "EnumEqualityComparer`1");
5101 add_instances_of (acfg, enum_comparer, insts, ninsts, FALSE);
5102
5103 ninsts = 0;
5104 insts [ninsts ++] = &mono_defaults.int16_class->byval_arg;
5105 enum_comparer = mono_class_load_from_name (mono_defaults.corlib, "System.Collections.Generic", "ShortEnumEqualityComparer`1");
5106 add_instances_of (acfg, enum_comparer, insts, ninsts, FALSE);
5107
5108 ninsts = 0;
5109 insts [ninsts ++] = &mono_defaults.sbyte_class->byval_arg;
5110 enum_comparer = mono_class_load_from_name (mono_defaults.corlib, "System.Collections.Generic", "SByteEnumEqualityComparer`1");
5111 add_instances_of (acfg, enum_comparer, insts, ninsts, FALSE);
5112
5113 enum_comparer = mono_class_load_from_name (mono_defaults.corlib, "System.Collections.Generic", "LongEnumEqualityComparer`1");
5114 ninsts = 0;
5115 insts [ninsts ++] = &mono_defaults.int64_class->byval_arg;
5116 insts [ninsts ++] = &mono_defaults.uint64_class->byval_arg;
5117 add_instances_of (acfg, enum_comparer, insts, ninsts, FALSE);
5118 }
5119
5120 /* Add instances of the array generic interfaces for primitive types */
5121 /* This will add instances of the InternalArray_ helper methods in Array too */
5122 klass = mono_class_try_load_from_name (acfg->image, "System.Collections.Generic", "ICollection`1");
5123 if (klass)
5124 add_instances_of (acfg, klass, insts, ninsts, TRUE);
5125
5126 klass = mono_class_try_load_from_name (acfg->image, "System.Collections.Generic", "IList`1");
5127 if (klass)
5128 add_instances_of (acfg, klass, insts, ninsts, TRUE);
5129
5130 klass = mono_class_try_load_from_name (acfg->image, "System.Collections.Generic", "IEnumerable`1");
5131 if (klass)
5132 add_instances_of (acfg, klass, insts, ninsts, TRUE);
5133
5134 /*
5135 * Add a managed-to-native wrapper of Array.GetGenericValueImpl<object>, which is
5136 * used for all instances of GetGenericValueImpl by the AOT runtime.
5137 */
5138 {
5139 MonoGenericContext ctx;
5140 MonoType *args [16];
5141 MonoMethod *get_method;
5142 MonoClass *array_klass = mono_array_class_get (mono_defaults.object_class, 1)->parent;
5143
5144 get_method = mono_class_get_method_from_name (array_klass, "GetGenericValueImpl", 2);
5145
5146 if (get_method) {
5147 MonoError error;
5148 memset (&ctx, 0, sizeof (ctx));
5149 args [0] = &mono_defaults.object_class->byval_arg;
5150 ctx.method_inst = mono_metadata_get_generic_inst (1, args);
5151 add_extra_method (acfg, mono_marshal_get_native_wrapper (mono_class_inflate_generic_method_checked (get_method, &ctx, &error), TRUE, TRUE));
5152 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
5153 }
5154 }
5155
5156 /* Same for CompareExchange<T>/Exchange<T> */
5157 {
5158 MonoGenericContext ctx;
5159 MonoType *args [16];
5160 MonoMethod *m;
5161 MonoClass *interlocked_klass = mono_class_load_from_name (mono_defaults.corlib, "System.Threading", "Interlocked");
5162 gpointer iter = NULL;
5163
5164 while ((m = mono_class_get_methods (interlocked_klass, &iter))) {
5165 if ((!strcmp (m->name, "CompareExchange") || !strcmp (m->name, "Exchange")) && m->is_generic) {
5166 MonoError error;
5167 memset (&ctx, 0, sizeof (ctx));
5168 args [0] = &mono_defaults.object_class->byval_arg;
5169 ctx.method_inst = mono_metadata_get_generic_inst (1, args);
5170 add_extra_method (acfg, mono_marshal_get_native_wrapper (mono_class_inflate_generic_method_checked (m, &ctx, &error), TRUE, TRUE));
5171 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
5172 }
5173 }
5174 }
5175
5176 /* Same for Volatile.Read/Write<T> */
5177 {
5178 MonoGenericContext ctx;
5179 MonoType *args [16];
5180 MonoMethod *m;
5181 MonoClass *volatile_klass = mono_class_try_load_from_name (mono_defaults.corlib, "System.Threading", "Volatile");
5182 gpointer iter = NULL;
5183
5184 if (volatile_klass) {
5185 while ((m = mono_class_get_methods (volatile_klass, &iter))) {
5186 if ((!strcmp (m->name, "Read") || !strcmp (m->name, "Write")) && m->is_generic) {
5187 MonoError error;
5188 memset (&ctx, 0, sizeof (ctx));
5189 args [0] = &mono_defaults.object_class->byval_arg;
5190 ctx.method_inst = mono_metadata_get_generic_inst (1, args);
5191 add_extra_method (acfg, mono_marshal_get_native_wrapper (mono_class_inflate_generic_method_checked (m, &ctx, &error), TRUE, TRUE));
5192 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
5193 }
5194 }
5195 }
5196 }
5197
5198 /* object[] accessor wrappers. */
5199 for (i = 1; i < 4; ++i) {
5200 MonoClass *obj_array_class = mono_array_class_get (mono_defaults.object_class, i);
5201 MonoMethod *m;
5202
5203 m = mono_class_get_method_from_name (obj_array_class, "Get", i);
5204 g_assert (m);
5205
5206 m = mono_marshal_get_array_accessor_wrapper (m);
5207 add_extra_method (acfg, m);
5208
5209 m = mono_class_get_method_from_name (obj_array_class, "Address", i);
5210 g_assert (m);
5211
5212 m = mono_marshal_get_array_accessor_wrapper (m);
5213 add_extra_method (acfg, m);
5214
5215 m = mono_class_get_method_from_name (obj_array_class, "Set", i + 1);
5216 g_assert (m);
5217
5218 m = mono_marshal_get_array_accessor_wrapper (m);
5219 add_extra_method (acfg, m);
5220 }
5221 }
5222 }
5223
5224 /*
5225 * is_direct_callable:
5226 *
5227 * Return whenever the method identified by JI is directly callable without
5228 * going through the PLT.
5229 */
5230 static gboolean
is_direct_callable(MonoAotCompile * acfg,MonoMethod * method,MonoJumpInfo * patch_info)5231 is_direct_callable (MonoAotCompile *acfg, MonoMethod *method, MonoJumpInfo *patch_info)
5232 {
5233 if ((patch_info->type == MONO_PATCH_INFO_METHOD) && (patch_info->data.method->klass->image == acfg->image)) {
5234 MonoCompile *callee_cfg = (MonoCompile *)g_hash_table_lookup (acfg->method_to_cfg, patch_info->data.method);
5235 if (callee_cfg) {
5236 gboolean direct_callable = TRUE;
5237
5238 if (direct_callable && (acfg->aot_opts.dedup || acfg->aot_opts.dedup_include) && mono_aot_can_dedup (patch_info->data.method))
5239 direct_callable = FALSE;
5240
5241 if (direct_callable && !(!callee_cfg->has_got_slots && mono_class_is_before_field_init (callee_cfg->method->klass)))
5242 direct_callable = FALSE;
5243 if ((callee_cfg->method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) && (!method || method->wrapper_type != MONO_WRAPPER_SYNCHRONIZED))
5244 // FIXME: Maybe call the wrapper directly ?
5245 direct_callable = FALSE;
5246
5247 if (acfg->aot_opts.soft_debug || acfg->aot_opts.no_direct_calls) {
5248 /* Disable this so all calls go through load_method (), see the
5249 * mini_get_debug_options ()->load_aot_jit_info_eagerly = TRUE; line in
5250 * mono_debugger_agent_init ().
5251 */
5252 direct_callable = FALSE;
5253 }
5254
5255 if (callee_cfg->method->wrapper_type == MONO_WRAPPER_ALLOC)
5256 /* sgen does some initialization when the allocator method is created */
5257 direct_callable = FALSE;
5258 if (callee_cfg->method->wrapper_type == MONO_WRAPPER_WRITE_BARRIER)
5259 /* we don't know at compile time whether sgen is concurrent or not */
5260 direct_callable = FALSE;
5261
5262 if (direct_callable)
5263 return TRUE;
5264 }
5265 } else if ((patch_info->type == MONO_PATCH_INFO_ICALL_ADDR_CALL && patch_info->data.method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
5266 if (acfg->aot_opts.direct_pinvoke)
5267 return TRUE;
5268 } else if (patch_info->type == MONO_PATCH_INFO_ICALL_ADDR_CALL) {
5269 if (acfg->aot_opts.direct_icalls)
5270 return TRUE;
5271 return FALSE;
5272 }
5273
5274 return FALSE;
5275 }
5276
5277 #ifdef MONO_ARCH_AOT_SUPPORTED
5278 static const char *
get_pinvoke_import(MonoAotCompile * acfg,MonoMethod * method)5279 get_pinvoke_import (MonoAotCompile *acfg, MonoMethod *method)
5280 {
5281 MonoImage *image = method->klass->image;
5282 MonoMethodPInvoke *piinfo = (MonoMethodPInvoke *) method;
5283 MonoTableInfo *tables = image->tables;
5284 MonoTableInfo *im = &tables [MONO_TABLE_IMPLMAP];
5285 MonoTableInfo *mr = &tables [MONO_TABLE_MODULEREF];
5286 guint32 im_cols [MONO_IMPLMAP_SIZE];
5287 char *import;
5288
5289 import = (char *)g_hash_table_lookup (acfg->method_to_pinvoke_import, method);
5290 if (import != NULL)
5291 return import;
5292
5293 if (!piinfo->implmap_idx || piinfo->implmap_idx > im->rows)
5294 return NULL;
5295
5296 mono_metadata_decode_row (im, piinfo->implmap_idx - 1, im_cols, MONO_IMPLMAP_SIZE);
5297
5298 if (!im_cols [MONO_IMPLMAP_SCOPE] || im_cols [MONO_IMPLMAP_SCOPE] > mr->rows)
5299 return NULL;
5300
5301 import = g_strdup_printf ("%s", mono_metadata_string_heap (image, im_cols [MONO_IMPLMAP_NAME]));
5302
5303 g_hash_table_insert (acfg->method_to_pinvoke_import, method, import);
5304
5305 return import;
5306 }
5307 #else
5308 static const char *
get_pinvoke_import(MonoAotCompile * acfg,MonoMethod * method)5309 get_pinvoke_import (MonoAotCompile *acfg, MonoMethod *method)
5310 {
5311 return NULL;
5312 }
5313 #endif
5314
5315 static gint
compare_lne(MonoDebugLineNumberEntry * a,MonoDebugLineNumberEntry * b)5316 compare_lne (MonoDebugLineNumberEntry *a, MonoDebugLineNumberEntry *b)
5317 {
5318 if (a->native_offset == b->native_offset)
5319 return a->il_offset - b->il_offset;
5320 else
5321 return a->native_offset - b->native_offset;
5322 }
5323
5324 /*
5325 * compute_line_numbers:
5326 *
5327 * Returns a sparse array of size CODE_SIZE containing MonoDebugSourceLocation* entries for the native offsets which have a corresponding line number
5328 * entry.
5329 */
5330 static MonoDebugSourceLocation**
compute_line_numbers(MonoMethod * method,int code_size,MonoDebugMethodJitInfo * debug_info)5331 compute_line_numbers (MonoMethod *method, int code_size, MonoDebugMethodJitInfo *debug_info)
5332 {
5333 MonoDebugMethodInfo *minfo;
5334 MonoDebugLineNumberEntry *ln_array;
5335 MonoDebugSourceLocation *loc;
5336 int i, prev_line, prev_il_offset;
5337 int *native_to_il_offset = NULL;
5338 MonoDebugSourceLocation **res;
5339 gboolean first;
5340
5341 minfo = mono_debug_lookup_method (method);
5342 if (!minfo)
5343 return NULL;
5344 // FIXME: This seems to happen when two methods have the same cfg->method_to_register
5345 if (debug_info->code_size != code_size)
5346 return NULL;
5347
5348 g_assert (code_size);
5349
5350 /* Compute the native->IL offset mapping */
5351
5352 ln_array = g_new0 (MonoDebugLineNumberEntry, debug_info->num_line_numbers);
5353 memcpy (ln_array, debug_info->line_numbers, debug_info->num_line_numbers * sizeof (MonoDebugLineNumberEntry));
5354
5355 qsort (ln_array, debug_info->num_line_numbers, sizeof (MonoDebugLineNumberEntry), (int (*)(const void *, const void *))compare_lne);
5356
5357 native_to_il_offset = g_new0 (int, code_size + 1);
5358
5359 for (i = 0; i < debug_info->num_line_numbers; ++i) {
5360 int j;
5361 MonoDebugLineNumberEntry *lne = &ln_array [i];
5362
5363 if (i == 0) {
5364 for (j = 0; j < lne->native_offset; ++j)
5365 native_to_il_offset [j] = -1;
5366 }
5367
5368 if (i < debug_info->num_line_numbers - 1) {
5369 MonoDebugLineNumberEntry *lne_next = &ln_array [i + 1];
5370
5371 for (j = lne->native_offset; j < lne_next->native_offset; ++j)
5372 native_to_il_offset [j] = lne->il_offset;
5373 } else {
5374 for (j = lne->native_offset; j < code_size; ++j)
5375 native_to_il_offset [j] = lne->il_offset;
5376 }
5377 }
5378 g_free (ln_array);
5379
5380 /* Compute the native->line number mapping */
5381 res = g_new0 (MonoDebugSourceLocation*, code_size);
5382 prev_il_offset = -1;
5383 prev_line = -1;
5384 first = TRUE;
5385 for (i = 0; i < code_size; ++i) {
5386 int il_offset = native_to_il_offset [i];
5387
5388 if (il_offset == -1 || il_offset == prev_il_offset)
5389 continue;
5390 prev_il_offset = il_offset;
5391 loc = mono_debug_method_lookup_location (minfo, il_offset);
5392 if (!(loc && loc->source_file))
5393 continue;
5394 if (loc->row == prev_line) {
5395 mono_debug_free_source_location (loc);
5396 continue;
5397 }
5398 prev_line = loc->row;
5399 //printf ("D: %s:%d il=%x native=%x\n", loc->source_file, loc->row, il_offset, i);
5400 if (first)
5401 /* This will cover the prolog too */
5402 res [0] = loc;
5403 else
5404 res [i] = loc;
5405 first = FALSE;
5406 }
5407 return res;
5408 }
5409
5410 static int
get_file_index(MonoAotCompile * acfg,const char * source_file)5411 get_file_index (MonoAotCompile *acfg, const char *source_file)
5412 {
5413 int findex;
5414
5415 // FIXME: Free these
5416 if (!acfg->dwarf_ln_filenames)
5417 acfg->dwarf_ln_filenames = g_hash_table_new (g_str_hash, g_str_equal);
5418 findex = GPOINTER_TO_INT (g_hash_table_lookup (acfg->dwarf_ln_filenames, source_file));
5419 if (!findex) {
5420 findex = g_hash_table_size (acfg->dwarf_ln_filenames) + 1;
5421 g_hash_table_insert (acfg->dwarf_ln_filenames, g_strdup (source_file), GINT_TO_POINTER (findex));
5422 emit_unset_mode (acfg);
5423 fprintf (acfg->fp, ".file %d \"%s\"\n", findex, mono_dwarf_escape_path (source_file));
5424 }
5425 return findex;
5426 }
5427
5428 #ifdef TARGET_ARM64
5429 #define INST_LEN 4
5430 #else
5431 #define INST_LEN 1
5432 #endif
5433
5434 /*
5435 * emit_and_reloc_code:
5436 *
5437 * Emit the native code in CODE, handling relocations along the way. If GOT_ONLY
5438 * is true, calls are made through the GOT too. This is used for emitting trampolines
5439 * in full-aot mode, since calls made from trampolines couldn't go through the PLT,
5440 * since trampolines are needed to make PTL work.
5441 */
5442 static void
emit_and_reloc_code(MonoAotCompile * acfg,MonoMethod * method,guint8 * code,guint32 code_len,MonoJumpInfo * relocs,gboolean got_only,MonoDebugMethodJitInfo * debug_info)5443 emit_and_reloc_code (MonoAotCompile *acfg, MonoMethod *method, guint8 *code, guint32 code_len, MonoJumpInfo *relocs, gboolean got_only, MonoDebugMethodJitInfo *debug_info)
5444 {
5445 int i, pindex, start_index;
5446 GPtrArray *patches;
5447 MonoJumpInfo *patch_info;
5448 MonoDebugSourceLocation **locs = NULL;
5449 gboolean skip, prologue_end = FALSE;
5450 #ifdef MONO_ARCH_AOT_SUPPORTED
5451 gboolean direct_call, external_call;
5452 guint32 got_slot;
5453 const char *direct_call_target = 0;
5454 const char *direct_pinvoke;
5455 #endif
5456
5457 if (acfg->gas_line_numbers && method && debug_info) {
5458 locs = compute_line_numbers (method, code_len, debug_info);
5459 if (!locs) {
5460 int findex = get_file_index (acfg, "<unknown>");
5461 emit_unset_mode (acfg);
5462 fprintf (acfg->fp, ".loc %d %d 0\n", findex, 1);
5463 }
5464 }
5465
5466 /* Collect and sort relocations */
5467 patches = g_ptr_array_new ();
5468 for (patch_info = relocs; patch_info; patch_info = patch_info->next)
5469 g_ptr_array_add (patches, patch_info);
5470 g_ptr_array_sort (patches, compare_patches);
5471
5472 start_index = 0;
5473 for (i = 0; i < code_len; i += INST_LEN) {
5474 patch_info = NULL;
5475 for (pindex = start_index; pindex < patches->len; ++pindex) {
5476 patch_info = (MonoJumpInfo *)g_ptr_array_index (patches, pindex);
5477 if (patch_info->ip.i >= i)
5478 break;
5479 }
5480
5481 if (locs && locs [i]) {
5482 MonoDebugSourceLocation *loc = locs [i];
5483 int findex;
5484 const char *options;
5485
5486 findex = get_file_index (acfg, loc->source_file);
5487 emit_unset_mode (acfg);
5488 if (!prologue_end)
5489 options = " prologue_end";
5490 else
5491 options = "";
5492 prologue_end = TRUE;
5493 fprintf (acfg->fp, ".loc %d %d 0%s\n", findex, loc->row, options);
5494 mono_debug_free_source_location (loc);
5495 }
5496
5497 skip = FALSE;
5498 #ifdef MONO_ARCH_AOT_SUPPORTED
5499 if (patch_info && (patch_info->ip.i == i) && (pindex < patches->len)) {
5500 start_index = pindex;
5501
5502 switch (patch_info->type) {
5503 case MONO_PATCH_INFO_NONE:
5504 break;
5505 case MONO_PATCH_INFO_GOT_OFFSET: {
5506 int code_size;
5507
5508 arch_emit_got_offset (acfg, code + i, &code_size);
5509 i += code_size - INST_LEN;
5510 skip = TRUE;
5511 patch_info->type = MONO_PATCH_INFO_NONE;
5512 break;
5513 }
5514 case MONO_PATCH_INFO_OBJC_SELECTOR_REF: {
5515 int code_size, index;
5516 char *selector = (char *)patch_info->data.target;
5517
5518 if (!acfg->objc_selector_to_index)
5519 acfg->objc_selector_to_index = g_hash_table_new (g_str_hash, g_str_equal);
5520 if (!acfg->objc_selectors)
5521 acfg->objc_selectors = g_ptr_array_new ();
5522 index = GPOINTER_TO_UINT (g_hash_table_lookup (acfg->objc_selector_to_index, selector));
5523 if (index)
5524 index --;
5525 else {
5526 index = acfg->objc_selector_index;
5527 g_ptr_array_add (acfg->objc_selectors, (void*)patch_info->data.target);
5528 g_hash_table_insert (acfg->objc_selector_to_index, selector, GUINT_TO_POINTER (index + 1));
5529 acfg->objc_selector_index ++;
5530 }
5531
5532 arch_emit_objc_selector_ref (acfg, code + i, index, &code_size);
5533 i += code_size - INST_LEN;
5534 skip = TRUE;
5535 patch_info->type = MONO_PATCH_INFO_NONE;
5536 break;
5537 }
5538 default: {
5539 /*
5540 * If this patch is a call, try emitting a direct call instead of
5541 * through a PLT entry. This is possible if the called method is in
5542 * the same assembly and requires no initialization.
5543 */
5544 direct_call = FALSE;
5545 external_call = FALSE;
5546 if ((patch_info->type == MONO_PATCH_INFO_METHOD) && (patch_info->data.method->klass->image == acfg->image)) {
5547 if (!got_only && is_direct_callable (acfg, method, patch_info)) {
5548 MonoCompile *callee_cfg = (MonoCompile *)g_hash_table_lookup (acfg->method_to_cfg, patch_info->data.method);
5549
5550 // Don't compile inflated methods if we're doing dedup
5551 if (acfg->aot_opts.dedup && !mono_aot_can_dedup (patch_info->data.method)) {
5552 char *name = mono_aot_get_mangled_method_name (patch_info->data.method);
5553 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT, "DIRECT CALL: %s by %s", name, method ? mono_method_full_name (method, TRUE) : "");
5554 g_free (name);
5555
5556 direct_call = TRUE;
5557 direct_call_target = callee_cfg->asm_symbol;
5558 patch_info->type = MONO_PATCH_INFO_NONE;
5559 acfg->stats.direct_calls ++;
5560 }
5561 }
5562
5563 acfg->stats.all_calls ++;
5564 } else if (patch_info->type == MONO_PATCH_INFO_ICALL_ADDR_CALL) {
5565 if (!got_only && is_direct_callable (acfg, method, patch_info)) {
5566 if (!(patch_info->data.method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL))
5567 direct_pinvoke = mono_lookup_icall_symbol (patch_info->data.method);
5568 else
5569 direct_pinvoke = get_pinvoke_import (acfg, patch_info->data.method);
5570 if (direct_pinvoke) {
5571 direct_call = TRUE;
5572 g_assert (strlen (direct_pinvoke) < 1000);
5573 direct_call_target = g_strdup_printf ("%s%s", acfg->user_symbol_prefix, direct_pinvoke);
5574 }
5575 }
5576 } else if (patch_info->type == MONO_PATCH_INFO_JIT_ICALL_ADDR) {
5577 const char *sym = mono_lookup_jit_icall_symbol (patch_info->data.name);
5578 if (!got_only && sym && acfg->aot_opts.direct_icalls) {
5579 /* Call to a C function implementing a jit icall */
5580 direct_call = TRUE;
5581 external_call = TRUE;
5582 g_assert (strlen (sym) < 1000);
5583 direct_call_target = g_strdup_printf ("%s%s", acfg->user_symbol_prefix, sym);
5584 }
5585 } else if (patch_info->type == MONO_PATCH_INFO_INTERNAL_METHOD) {
5586 MonoJitICallInfo *info = mono_find_jit_icall_by_name (patch_info->data.name);
5587 const char *sym = mono_lookup_jit_icall_symbol (patch_info->data.name);
5588 if (!got_only && sym && acfg->aot_opts.direct_icalls && info->func == info->wrapper) {
5589 /* Call to a jit icall without a wrapper */
5590 direct_call = TRUE;
5591 external_call = TRUE;
5592 g_assert (strlen (sym) < 1000);
5593 direct_call_target = g_strdup_printf ("%s%s", acfg->user_symbol_prefix, sym);
5594 }
5595 }
5596
5597 if (direct_call) {
5598 patch_info->type = MONO_PATCH_INFO_NONE;
5599 acfg->stats.direct_calls ++;
5600 }
5601
5602 if (!got_only && !direct_call) {
5603 MonoPltEntry *plt_entry = get_plt_entry (acfg, patch_info);
5604 if (plt_entry) {
5605 /* This patch has a PLT entry, so we must emit a call to the PLT entry */
5606 direct_call = TRUE;
5607 direct_call_target = plt_entry->symbol;
5608
5609 /* Nullify the patch */
5610 patch_info->type = MONO_PATCH_INFO_NONE;
5611 plt_entry->jit_used = TRUE;
5612 }
5613 }
5614
5615 if (direct_call) {
5616 int call_size;
5617
5618 arch_emit_direct_call (acfg, direct_call_target, external_call, FALSE, patch_info, &call_size);
5619 i += call_size - INST_LEN;
5620 } else {
5621 int code_size;
5622
5623 got_slot = get_got_offset (acfg, FALSE, patch_info);
5624
5625 arch_emit_got_access (acfg, acfg->got_symbol, code + i, got_slot, &code_size);
5626 i += code_size - INST_LEN;
5627 }
5628 skip = TRUE;
5629 }
5630 }
5631 }
5632 #endif /* MONO_ARCH_AOT_SUPPORTED */
5633
5634 if (!skip) {
5635 /* Find next patch */
5636 patch_info = NULL;
5637 for (pindex = start_index; pindex < patches->len; ++pindex) {
5638 patch_info = (MonoJumpInfo *)g_ptr_array_index (patches, pindex);
5639 if (patch_info->ip.i >= i)
5640 break;
5641 }
5642
5643 /* Try to emit multiple bytes at once */
5644 if (pindex < patches->len && patch_info->ip.i > i) {
5645 int limit;
5646
5647 for (limit = i + INST_LEN; limit < patch_info->ip.i; limit += INST_LEN) {
5648 if (locs && locs [limit])
5649 break;
5650 }
5651
5652 emit_code_bytes (acfg, code + i, limit - i);
5653 i = limit - INST_LEN;
5654 } else {
5655 emit_code_bytes (acfg, code + i, INST_LEN);
5656 }
5657 }
5658 }
5659
5660 g_ptr_array_free (patches, TRUE);
5661 g_free (locs);
5662 }
5663
5664 /*
5665 * sanitize_symbol:
5666 *
5667 * Return a modified version of S which only includes characters permissible in symbols.
5668 */
5669 static char*
sanitize_symbol(MonoAotCompile * acfg,char * s)5670 sanitize_symbol (MonoAotCompile *acfg, char *s)
5671 {
5672 gboolean process = FALSE;
5673 int i, len;
5674 GString *gs;
5675 char *res;
5676
5677 if (!s)
5678 return s;
5679
5680 len = strlen (s);
5681 for (i = 0; i < len; ++i)
5682 if (!(s [i] <= 0x7f && (isalnum (s [i]) || s [i] == '_')))
5683 process = TRUE;
5684 if (!process)
5685 return s;
5686
5687 gs = g_string_sized_new (len);
5688 for (i = 0; i < len; ++i) {
5689 guint8 c = s [i];
5690 if (c <= 0x7f && (isalnum (c) || c == '_')) {
5691 g_string_append_c (gs, c);
5692 } else if (c > 0x7f) {
5693 /* multi-byte utf8 */
5694 g_string_append_printf (gs, "_0x%x", c);
5695 i ++;
5696 c = s [i];
5697 while (c >> 6 == 0x2) {
5698 g_string_append_printf (gs, "%x", c);
5699 i ++;
5700 c = s [i];
5701 }
5702 g_string_append_printf (gs, "_");
5703 i --;
5704 } else {
5705 g_string_append_c (gs, '_');
5706 }
5707 }
5708
5709 res = mono_mempool_strdup (acfg->mempool, gs->str);
5710 g_string_free (gs, TRUE);
5711 return res;
5712 }
5713
5714 static char*
get_debug_sym(MonoMethod * method,const char * prefix,GHashTable * cache)5715 get_debug_sym (MonoMethod *method, const char *prefix, GHashTable *cache)
5716 {
5717 char *name1, *name2, *cached;
5718 int i, j, len, count;
5719 MonoMethod *cached_method;
5720
5721 name1 = mono_method_full_name (method, TRUE);
5722
5723 #ifdef TARGET_MACH
5724 // This is so that we don't accidentally create a local symbol (which starts with 'L')
5725 if ((!prefix || !*prefix) && name1 [0] == 'L')
5726 prefix = "_";
5727 #endif
5728
5729 #if defined(TARGET_WIN32) && defined(TARGET_X86)
5730 char adjustedPrefix [MAX_SYMBOL_SIZE];
5731 prefix = mangle_symbol (prefix, adjustedPrefix, G_N_ELEMENTS (adjustedPrefix));
5732 #endif
5733
5734 len = strlen (name1);
5735 name2 = (char *)malloc (strlen (prefix) + len + 16);
5736 memcpy (name2, prefix, strlen (prefix));
5737 j = strlen (prefix);
5738 for (i = 0; i < len; ++i) {
5739 if (i == 0 && name1 [0] >= '0' && name1 [0] <= '9') {
5740 name2 [j ++] = '_';
5741 } else if (isalnum (name1 [i])) {
5742 name2 [j ++] = name1 [i];
5743 } else if (name1 [i] == ' ' && name1 [i + 1] == '(' && name1 [i + 2] == ')') {
5744 i += 2;
5745 } else if (name1 [i] == ',' && name1 [i + 1] == ' ') {
5746 name2 [j ++] = '_';
5747 i++;
5748 } else if (name1 [i] == '(' || name1 [i] == ')' || name1 [i] == '>') {
5749 } else
5750 name2 [j ++] = '_';
5751 }
5752 name2 [j] = '\0';
5753
5754 g_free (name1);
5755
5756 count = 0;
5757 while (TRUE) {
5758 cached_method = (MonoMethod *)g_hash_table_lookup (cache, name2);
5759 if (!(cached_method && cached_method != method))
5760 break;
5761 sprintf (name2 + j, "_%d", count);
5762 count ++;
5763 }
5764
5765 cached = g_strdup (name2);
5766 g_hash_table_insert (cache, cached, method);
5767
5768 return name2;
5769 }
5770
5771 static void
emit_method_code(MonoAotCompile * acfg,MonoCompile * cfg)5772 emit_method_code (MonoAotCompile *acfg, MonoCompile *cfg)
5773 {
5774 MonoMethod *method;
5775 int method_index;
5776 guint8 *code;
5777 char *debug_sym = NULL;
5778 char *symbol = NULL;
5779 int func_alignment = AOT_FUNC_ALIGNMENT;
5780 char *export_name;
5781
5782 g_assert (!ignore_cfg (cfg));
5783
5784 method = cfg->orig_method;
5785 code = cfg->native_code;
5786
5787 method_index = get_method_index (acfg, method);
5788 symbol = g_strdup_printf ("%sme_%x", acfg->temp_prefix, method_index);
5789
5790 /* Make the labels local */
5791 emit_section_change (acfg, ".text", 0);
5792 emit_alignment_code (acfg, func_alignment);
5793
5794 if (acfg->global_symbols && acfg->need_no_dead_strip)
5795 fprintf (acfg->fp, " .no_dead_strip %s\n", cfg->asm_symbol);
5796
5797 emit_label (acfg, cfg->asm_symbol);
5798
5799 if (acfg->aot_opts.write_symbols && !acfg->global_symbols && !acfg->llvm) {
5800 /*
5801 * Write a C style symbol for every method, this has two uses:
5802 * - it works on platforms where the dwarf debugging info is not
5803 * yet supported.
5804 * - it allows the setting of breakpoints of aot-ed methods.
5805 */
5806
5807 // Comment out to force dedup to link these symbols and forbid compiling
5808 // in duplicated code. This is an "assert when linking if broken" trick.
5809 /*if (mono_aot_can_dedup (method) && (acfg->aot_opts.dedup || acfg->aot_opts.dedup_include))*/
5810 /*debug_sym = mono_aot_get_mangled_method_name (method);*/
5811 /*else*/
5812 debug_sym = get_debug_sym (method, "", acfg->method_label_hash);
5813
5814 cfg->asm_debug_symbol = g_strdup (debug_sym);
5815
5816 if (acfg->need_no_dead_strip)
5817 fprintf (acfg->fp, " .no_dead_strip %s\n", debug_sym);
5818
5819 // Comment out to force dedup to link these symbols and forbid compiling
5820 // in duplicated code. This is an "assert when linking if broken" trick.
5821 /*if (mono_aot_can_dedup (method) && (acfg->aot_opts.dedup || acfg->aot_opts.dedup_include))*/
5822 /*emit_global_inner (acfg, debug_sym, TRUE);*/
5823 /*else*/
5824 emit_local_symbol (acfg, debug_sym, symbol, TRUE);
5825
5826 emit_label (acfg, debug_sym);
5827 }
5828
5829 export_name = (char *)g_hash_table_lookup (acfg->export_names, method);
5830 if (export_name) {
5831 /* Emit a global symbol for the method */
5832 emit_global_inner (acfg, export_name, TRUE);
5833 emit_label (acfg, export_name);
5834 }
5835
5836 if (cfg->verbose_level > 0 && !ignore_cfg (cfg))
5837 g_print ("Method %s emitted as %s\n", mono_method_get_full_name (method), cfg->asm_symbol);
5838
5839 acfg->stats.code_size += cfg->code_len;
5840
5841 acfg->cfgs [method_index]->got_offset = acfg->got_offset;
5842
5843 emit_and_reloc_code (acfg, method, code, cfg->code_len, cfg->patch_info, FALSE, mono_debug_find_method (cfg->jit_info->d.method, mono_domain_get ()));
5844
5845 emit_line (acfg);
5846
5847 if (acfg->aot_opts.write_symbols) {
5848 if (debug_sym)
5849 emit_symbol_size (acfg, debug_sym, ".");
5850 else
5851 emit_symbol_size (acfg, cfg->asm_symbol, ".");
5852 g_free (debug_sym);
5853 }
5854
5855 emit_label (acfg, symbol);
5856
5857 arch_emit_unwind_info_sections (acfg, cfg->asm_symbol, symbol, cfg->unwind_ops);
5858
5859 g_free (symbol);
5860 }
5861
5862 /**
5863 * encode_patch:
5864 *
5865 * Encode PATCH_INFO into its disk representation.
5866 */
5867 static void
encode_patch(MonoAotCompile * acfg,MonoJumpInfo * patch_info,guint8 * buf,guint8 ** endbuf)5868 encode_patch (MonoAotCompile *acfg, MonoJumpInfo *patch_info, guint8 *buf, guint8 **endbuf)
5869 {
5870 guint8 *p = buf;
5871
5872 switch (patch_info->type) {
5873 case MONO_PATCH_INFO_NONE:
5874 break;
5875 case MONO_PATCH_INFO_IMAGE:
5876 encode_value (get_image_index (acfg, patch_info->data.image), p, &p);
5877 break;
5878 case MONO_PATCH_INFO_MSCORLIB_GOT_ADDR:
5879 case MONO_PATCH_INFO_GC_CARD_TABLE_ADDR:
5880 case MONO_PATCH_INFO_GC_NURSERY_START:
5881 case MONO_PATCH_INFO_GC_NURSERY_BITS:
5882 break;
5883 case MONO_PATCH_INFO_CASTCLASS_CACHE:
5884 encode_value (patch_info->data.index, p, &p);
5885 break;
5886 case MONO_PATCH_INFO_METHOD_REL:
5887 encode_value ((gint)patch_info->data.offset, p, &p);
5888 break;
5889 case MONO_PATCH_INFO_SWITCH: {
5890 gpointer *table = (gpointer *)patch_info->data.table->table;
5891 int k;
5892
5893 encode_value (patch_info->data.table->table_size, p, &p);
5894 for (k = 0; k < patch_info->data.table->table_size; k++)
5895 encode_value ((int)(gssize)table [k], p, &p);
5896 break;
5897 }
5898 case MONO_PATCH_INFO_METHODCONST:
5899 case MONO_PATCH_INFO_METHOD:
5900 case MONO_PATCH_INFO_METHOD_JUMP:
5901 case MONO_PATCH_INFO_ICALL_ADDR:
5902 case MONO_PATCH_INFO_ICALL_ADDR_CALL:
5903 case MONO_PATCH_INFO_METHOD_RGCTX:
5904 case MONO_PATCH_INFO_METHOD_CODE_SLOT:
5905 encode_method_ref (acfg, patch_info->data.method, p, &p);
5906 break;
5907 case MONO_PATCH_INFO_AOT_JIT_INFO:
5908 case MONO_PATCH_INFO_GET_TLS_TRAMP:
5909 case MONO_PATCH_INFO_SET_TLS_TRAMP:
5910 encode_value (patch_info->data.index, p, &p);
5911 break;
5912 case MONO_PATCH_INFO_INTERNAL_METHOD:
5913 case MONO_PATCH_INFO_JIT_ICALL_ADDR:
5914 case MONO_PATCH_INFO_JIT_ICALL_ADDR_NOCALL: {
5915 guint32 len = strlen (patch_info->data.name);
5916
5917 encode_value (len, p, &p);
5918
5919 memcpy (p, patch_info->data.name, len);
5920 p += len;
5921 *p++ = '\0';
5922 break;
5923 }
5924 case MONO_PATCH_INFO_LDSTR: {
5925 guint32 image_index = get_image_index (acfg, patch_info->data.token->image);
5926 guint32 token = patch_info->data.token->token;
5927 g_assert (mono_metadata_token_code (token) == MONO_TOKEN_STRING);
5928 encode_value (image_index, p, &p);
5929 encode_value (patch_info->data.token->token - MONO_TOKEN_STRING, p, &p);
5930 break;
5931 }
5932 case MONO_PATCH_INFO_RVA:
5933 case MONO_PATCH_INFO_DECLSEC:
5934 case MONO_PATCH_INFO_LDTOKEN:
5935 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
5936 encode_value (get_image_index (acfg, patch_info->data.token->image), p, &p);
5937 encode_value (patch_info->data.token->token, p, &p);
5938 encode_value (patch_info->data.token->has_context, p, &p);
5939 if (patch_info->data.token->has_context)
5940 encode_generic_context (acfg, &patch_info->data.token->context, p, &p);
5941 break;
5942 case MONO_PATCH_INFO_EXC_NAME: {
5943 MonoClass *ex_class;
5944
5945 ex_class =
5946 mono_class_load_from_name (mono_defaults.exception_class->image,
5947 "System", (const char *)patch_info->data.target);
5948 encode_klass_ref (acfg, ex_class, p, &p);
5949 break;
5950 }
5951 case MONO_PATCH_INFO_R4:
5952 encode_value (*((guint32 *)patch_info->data.target), p, &p);
5953 break;
5954 case MONO_PATCH_INFO_R8:
5955 encode_value (((guint32 *)patch_info->data.target) [MINI_LS_WORD_IDX], p, &p);
5956 encode_value (((guint32 *)patch_info->data.target) [MINI_MS_WORD_IDX], p, &p);
5957 break;
5958 case MONO_PATCH_INFO_VTABLE:
5959 case MONO_PATCH_INFO_CLASS:
5960 case MONO_PATCH_INFO_IID:
5961 case MONO_PATCH_INFO_ADJUSTED_IID:
5962 encode_klass_ref (acfg, patch_info->data.klass, p, &p);
5963 break;
5964 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE:
5965 encode_klass_ref (acfg, patch_info->data.del_tramp->klass, p, &p);
5966 if (patch_info->data.del_tramp->method) {
5967 encode_value (1, p, &p);
5968 encode_method_ref (acfg, patch_info->data.del_tramp->method, p, &p);
5969 } else {
5970 encode_value (0, p, &p);
5971 }
5972 encode_value (patch_info->data.del_tramp->is_virtual, p, &p);
5973 break;
5974 case MONO_PATCH_INFO_FIELD:
5975 case MONO_PATCH_INFO_SFLDA:
5976 encode_field_info (acfg, patch_info->data.field, p, &p);
5977 break;
5978 case MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG:
5979 break;
5980 case MONO_PATCH_INFO_PROFILER_ALLOCATION_COUNT:
5981 break;
5982 case MONO_PATCH_INFO_RGCTX_FETCH:
5983 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX: {
5984 MonoJumpInfoRgctxEntry *entry = patch_info->data.rgctx_entry;
5985 guint32 offset;
5986 guint8 *buf2, *p2;
5987
5988 /*
5989 * entry->method has a lenghtly encoding and multiple rgctx_fetch entries
5990 * reference the same method, so encode the method only once.
5991 */
5992 offset = GPOINTER_TO_UINT (g_hash_table_lookup (acfg->method_blob_hash, entry->method));
5993 if (!offset) {
5994 buf2 = (guint8 *)g_malloc (1024);
5995 p2 = buf2;
5996
5997 encode_method_ref (acfg, entry->method, p2, &p2);
5998 g_assert (p2 - buf2 < 1024);
5999
6000 offset = add_to_blob (acfg, buf2, p2 - buf2);
6001 g_free (buf2);
6002
6003 g_hash_table_insert (acfg->method_blob_hash, entry->method, GUINT_TO_POINTER (offset + 1));
6004 } else {
6005 offset --;
6006 }
6007
6008 encode_value (offset, p, &p);
6009 g_assert ((int)entry->info_type < 256);
6010 g_assert (entry->data->type < 256);
6011 encode_value ((entry->in_mrgctx ? 1 : 0) | (entry->info_type << 1) | (entry->data->type << 9), p, &p);
6012 encode_patch (acfg, entry->data, p, &p);
6013 break;
6014 }
6015 case MONO_PATCH_INFO_SEQ_POINT_INFO:
6016 case MONO_PATCH_INFO_AOT_MODULE:
6017 break;
6018 case MONO_PATCH_INFO_SIGNATURE:
6019 case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER:
6020 encode_signature (acfg, (MonoMethodSignature*)patch_info->data.target, p, &p);
6021 break;
6022 case MONO_PATCH_INFO_GSHAREDVT_CALL:
6023 encode_signature (acfg, (MonoMethodSignature*)patch_info->data.gsharedvt->sig, p, &p);
6024 encode_method_ref (acfg, patch_info->data.gsharedvt->method, p, &p);
6025 break;
6026 case MONO_PATCH_INFO_GSHAREDVT_METHOD: {
6027 MonoGSharedVtMethodInfo *info = patch_info->data.gsharedvt_method;
6028 int i;
6029
6030 encode_method_ref (acfg, info->method, p, &p);
6031 encode_value (info->num_entries, p, &p);
6032 for (i = 0; i < info->num_entries; ++i) {
6033 MonoRuntimeGenericContextInfoTemplate *template_ = &info->entries [i];
6034
6035 encode_value (template_->info_type, p, &p);
6036 switch (mini_rgctx_info_type_to_patch_info_type (template_->info_type)) {
6037 case MONO_PATCH_INFO_CLASS:
6038 encode_klass_ref (acfg, mono_class_from_mono_type ((MonoType *)template_->data), p, &p);
6039 break;
6040 case MONO_PATCH_INFO_FIELD:
6041 encode_field_info (acfg, (MonoClassField *)template_->data, p, &p);
6042 break;
6043 default:
6044 g_assert_not_reached ();
6045 break;
6046 }
6047 }
6048 break;
6049 }
6050 case MONO_PATCH_INFO_LDSTR_LIT: {
6051 const char *s = (const char *)patch_info->data.target;
6052 int len = strlen (s);
6053
6054 encode_value (len, p, &p);
6055 memcpy (p, s, len + 1);
6056 p += len + 1;
6057 break;
6058 }
6059 case MONO_PATCH_INFO_VIRT_METHOD:
6060 encode_klass_ref (acfg, patch_info->data.virt_method->klass, p, &p);
6061 encode_method_ref (acfg, patch_info->data.virt_method->method, p, &p);
6062 break;
6063 case MONO_PATCH_INFO_GC_SAFE_POINT_FLAG:
6064 case MONO_PATCH_INFO_JIT_THREAD_ATTACH:
6065 break;
6066 default:
6067 g_warning ("unable to handle jump info %d", patch_info->type);
6068 g_assert_not_reached ();
6069 }
6070
6071 *endbuf = p;
6072 }
6073
6074 static void
encode_patch_list(MonoAotCompile * acfg,GPtrArray * patches,int n_patches,gboolean llvm,int first_got_offset,guint8 * buf,guint8 ** endbuf)6075 encode_patch_list (MonoAotCompile *acfg, GPtrArray *patches, int n_patches, gboolean llvm, int first_got_offset, guint8 *buf, guint8 **endbuf)
6076 {
6077 guint8 *p = buf;
6078 guint32 pindex, offset;
6079 MonoJumpInfo *patch_info;
6080
6081 encode_value (n_patches, p, &p);
6082
6083 for (pindex = 0; pindex < patches->len; ++pindex) {
6084 patch_info = (MonoJumpInfo *)g_ptr_array_index (patches, pindex);
6085
6086 if (patch_info->type == MONO_PATCH_INFO_NONE || patch_info->type == MONO_PATCH_INFO_BB)
6087 /* Nothing to do */
6088 continue;
6089
6090 offset = get_got_offset (acfg, llvm, patch_info);
6091 encode_value (offset, p, &p);
6092 }
6093
6094 *endbuf = p;
6095 }
6096
6097 static void
emit_method_info(MonoAotCompile * acfg,MonoCompile * cfg)6098 emit_method_info (MonoAotCompile *acfg, MonoCompile *cfg)
6099 {
6100 MonoMethod *method;
6101 int pindex, buf_size, n_patches;
6102 GPtrArray *patches;
6103 MonoJumpInfo *patch_info;
6104 guint32 method_index;
6105 guint8 *p, *buf;
6106 guint32 first_got_offset;
6107
6108 method = cfg->orig_method;
6109
6110 method_index = get_method_index (acfg, method);
6111
6112 /* Sort relocations */
6113 patches = g_ptr_array_new ();
6114 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next)
6115 g_ptr_array_add (patches, patch_info);
6116 g_ptr_array_sort (patches, compare_patches);
6117
6118 first_got_offset = acfg->cfgs [method_index]->got_offset;
6119
6120 /**********************/
6121 /* Encode method info */
6122 /**********************/
6123
6124 buf_size = (patches->len < 1000) ? 40960 : 40960 + (patches->len * 64);
6125 p = buf = (guint8 *)g_malloc (buf_size);
6126
6127 if (mono_class_get_cctor (method->klass)) {
6128 encode_value (1, p, &p);
6129 encode_klass_ref (acfg, method->klass, p, &p);
6130 } else {
6131 /* Not needed when loading the method */
6132 encode_value (0, p, &p);
6133 }
6134
6135 g_assert (!(cfg->opt & MONO_OPT_SHARED));
6136
6137 n_patches = 0;
6138 for (pindex = 0; pindex < patches->len; ++pindex) {
6139 patch_info = (MonoJumpInfo *)g_ptr_array_index (patches, pindex);
6140
6141 if ((patch_info->type == MONO_PATCH_INFO_GOT_OFFSET) ||
6142 (patch_info->type == MONO_PATCH_INFO_NONE)) {
6143 patch_info->type = MONO_PATCH_INFO_NONE;
6144 /* Nothing to do */
6145 continue;
6146 }
6147
6148 if ((patch_info->type == MONO_PATCH_INFO_IMAGE) && (patch_info->data.image == acfg->image)) {
6149 /* Stored in a GOT slot initialized at module load time */
6150 patch_info->type = MONO_PATCH_INFO_NONE;
6151 continue;
6152 }
6153
6154 if (patch_info->type == MONO_PATCH_INFO_GC_CARD_TABLE_ADDR ||
6155 patch_info->type == MONO_PATCH_INFO_GC_NURSERY_START ||
6156 patch_info->type == MONO_PATCH_INFO_GC_NURSERY_BITS ||
6157 patch_info->type == MONO_PATCH_INFO_AOT_MODULE) {
6158 /* Stored in a GOT slot initialized at module load time */
6159 patch_info->type = MONO_PATCH_INFO_NONE;
6160 continue;
6161 }
6162
6163 if (is_plt_patch (patch_info) && !(cfg->compile_llvm && acfg->aot_opts.llvm_only)) {
6164 /* Calls are made through the PLT */
6165 patch_info->type = MONO_PATCH_INFO_NONE;
6166 continue;
6167 }
6168
6169 n_patches ++;
6170 }
6171
6172 if (n_patches)
6173 g_assert (cfg->has_got_slots);
6174
6175 encode_patch_list (acfg, patches, n_patches, cfg->compile_llvm, first_got_offset, p, &p);
6176
6177 g_ptr_array_free (patches, TRUE);
6178
6179 acfg->stats.info_size += p - buf;
6180
6181 g_assert (p - buf < buf_size);
6182
6183 cfg->method_info_offset = add_to_blob (acfg, buf, p - buf);
6184 g_free (buf);
6185 }
6186
6187 static guint32
get_unwind_info_offset(MonoAotCompile * acfg,guint8 * encoded,guint32 encoded_len)6188 get_unwind_info_offset (MonoAotCompile *acfg, guint8 *encoded, guint32 encoded_len)
6189 {
6190 guint32 cache_index;
6191 guint32 offset;
6192
6193 /* Reuse the unwind module to canonize and store unwind info entries */
6194 cache_index = mono_cache_unwind_info (encoded, encoded_len);
6195
6196 /* Use +/- 1 to distinguish 0s from missing entries */
6197 offset = GPOINTER_TO_UINT (g_hash_table_lookup (acfg->unwind_info_offsets, GUINT_TO_POINTER (cache_index + 1)));
6198 if (offset)
6199 return offset - 1;
6200 else {
6201 guint8 buf [16];
6202 guint8 *p;
6203
6204 /*
6205 * It would be easier to use assembler symbols, but the caller needs an
6206 * offset now.
6207 */
6208 offset = acfg->unwind_info_offset;
6209 g_hash_table_insert (acfg->unwind_info_offsets, GUINT_TO_POINTER (cache_index + 1), GUINT_TO_POINTER (offset + 1));
6210 g_ptr_array_add (acfg->unwind_ops, GUINT_TO_POINTER (cache_index));
6211
6212 p = buf;
6213 encode_value (encoded_len, p, &p);
6214
6215 acfg->unwind_info_offset += encoded_len + (p - buf);
6216 return offset;
6217 }
6218 }
6219
6220 static void
emit_exception_debug_info(MonoAotCompile * acfg,MonoCompile * cfg,gboolean store_seq_points)6221 emit_exception_debug_info (MonoAotCompile *acfg, MonoCompile *cfg, gboolean store_seq_points)
6222 {
6223 int i, k, buf_size;
6224 guint32 debug_info_size, seq_points_size;
6225 guint8 *code;
6226 MonoMethodHeader *header;
6227 guint8 *p, *buf, *debug_info;
6228 MonoJitInfo *jinfo = cfg->jit_info;
6229 guint32 flags;
6230 gboolean use_unwind_ops = FALSE;
6231 MonoSeqPointInfo *seq_points;
6232
6233 code = cfg->native_code;
6234 header = cfg->header;
6235
6236 if (!acfg->aot_opts.nodebug) {
6237 mono_debug_serialize_debug_info (cfg, &debug_info, &debug_info_size);
6238 } else {
6239 debug_info = NULL;
6240 debug_info_size = 0;
6241 }
6242
6243 seq_points = cfg->seq_point_info;
6244 seq_points_size = (store_seq_points)? mono_seq_point_info_get_write_size (seq_points) : 0;
6245
6246 buf_size = header->num_clauses * 256 + debug_info_size + 2048 + seq_points_size + cfg->gc_map_size;
6247 if (jinfo->has_try_block_holes) {
6248 MonoTryBlockHoleTableJitInfo *table = mono_jit_info_get_try_block_hole_table_info (jinfo);
6249 buf_size += table->num_holes * 16;
6250 }
6251
6252 p = buf = (guint8 *)g_malloc (buf_size);
6253
6254 use_unwind_ops = cfg->unwind_ops != NULL;
6255
6256 flags = (jinfo->has_generic_jit_info ? 1 : 0) | (use_unwind_ops ? 2 : 0) | (header->num_clauses ? 4 : 0) | (seq_points_size ? 8 : 0) | (cfg->compile_llvm ? 16 : 0) | (jinfo->has_try_block_holes ? 32 : 0) | (cfg->gc_map ? 64 : 0) | (jinfo->has_arch_eh_info ? 128 : 0);
6257
6258 encode_value (flags, p, &p);
6259
6260 if (use_unwind_ops) {
6261 guint32 encoded_len;
6262 guint8 *encoded;
6263 guint32 unwind_desc;
6264
6265 encoded = mono_unwind_ops_encode (cfg->unwind_ops, &encoded_len);
6266
6267 unwind_desc = get_unwind_info_offset (acfg, encoded, encoded_len);
6268 encode_value (unwind_desc, p, &p);
6269
6270 g_free (encoded);
6271 } else {
6272 encode_value (jinfo->unwind_info, p, &p);
6273 }
6274
6275 /*Encode the number of holes before the number of clauses to make decoding easier*/
6276 if (jinfo->has_try_block_holes) {
6277 MonoTryBlockHoleTableJitInfo *table = mono_jit_info_get_try_block_hole_table_info (jinfo);
6278 encode_value (table->num_holes, p, &p);
6279 }
6280
6281 if (jinfo->has_arch_eh_info) {
6282 /*
6283 * In AOT mode, the code length is calculated from the address of the previous method,
6284 * which could include alignment padding, so calculating the start of the epilog as
6285 * code_len - epilog_size is correct any more. Save the real code len as a workaround.
6286 */
6287 encode_value (jinfo->code_size, p, &p);
6288 }
6289
6290 /* Exception table */
6291 if (cfg->compile_llvm) {
6292 /*
6293 * When using LLVM, we can't emit some data, like pc offsets, this reg/offset etc.,
6294 * since the information is only available to llc. Instead, we let llc save the data
6295 * into the LSDA, and read it from there at runtime.
6296 */
6297 /* The assembly might be CIL stripped so emit the data ourselves */
6298 if (header->num_clauses)
6299 encode_value (header->num_clauses, p, &p);
6300
6301 for (k = 0; k < header->num_clauses; ++k) {
6302 MonoExceptionClause *clause;
6303
6304 clause = &header->clauses [k];
6305
6306 encode_value (clause->flags, p, &p);
6307 if (!(clause->flags == MONO_EXCEPTION_CLAUSE_FILTER || clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY)) {
6308 if (clause->data.catch_class) {
6309 guint8 *buf2, *p2;
6310 int len;
6311
6312 buf2 = (guint8 *)g_malloc (4096);
6313 p2 = buf2;
6314 encode_klass_ref (acfg, clause->data.catch_class, p2, &p2);
6315 len = p2 - buf2;
6316 g_assert (len < 4096);
6317 encode_value (len, p, &p);
6318 memcpy (p, buf2, len);
6319 p += p2 - buf2;
6320 g_free (buf2);
6321 } else {
6322 encode_value (0, p, &p);
6323 }
6324 }
6325
6326 /* Emit the IL ranges too, since they might not be available at runtime */
6327 encode_value (clause->try_offset, p, &p);
6328 encode_value (clause->try_len, p, &p);
6329 encode_value (clause->handler_offset, p, &p);
6330 encode_value (clause->handler_len, p, &p);
6331
6332 /* Emit a list of nesting clauses */
6333 for (i = 0; i < header->num_clauses; ++i) {
6334 gint32 cindex1 = k;
6335 MonoExceptionClause *clause1 = &header->clauses [cindex1];
6336 gint32 cindex2 = i;
6337 MonoExceptionClause *clause2 = &header->clauses [cindex2];
6338
6339 if (cindex1 != cindex2 && clause1->try_offset >= clause2->try_offset && clause1->handler_offset <= clause2->handler_offset)
6340 encode_value (i, p, &p);
6341 }
6342 encode_value (-1, p, &p);
6343 }
6344 } else {
6345 if (jinfo->num_clauses)
6346 encode_value (jinfo->num_clauses, p, &p);
6347
6348 for (k = 0; k < jinfo->num_clauses; ++k) {
6349 MonoJitExceptionInfo *ei = &jinfo->clauses [k];
6350
6351 encode_value (ei->flags, p, &p);
6352 #ifdef MONO_CONTEXT_SET_LLVM_EXC_REG
6353 /* Not used for catch clauses */
6354 if (ei->flags != MONO_EXCEPTION_CLAUSE_NONE)
6355 encode_value (ei->exvar_offset, p, &p);
6356 #else
6357 encode_value (ei->exvar_offset, p, &p);
6358 #endif
6359
6360 if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER || ei->flags == MONO_EXCEPTION_CLAUSE_FINALLY)
6361 encode_value ((gint)((guint8*)ei->data.filter - code), p, &p);
6362 else {
6363 if (ei->data.catch_class) {
6364 guint8 *buf2, *p2;
6365 int len;
6366
6367 buf2 = (guint8 *)g_malloc (4096);
6368 p2 = buf2;
6369 encode_klass_ref (acfg, ei->data.catch_class, p2, &p2);
6370 len = p2 - buf2;
6371 g_assert (len < 4096);
6372 encode_value (len, p, &p);
6373 memcpy (p, buf2, len);
6374 p += p2 - buf2;
6375 g_free (buf2);
6376 } else {
6377 encode_value (0, p, &p);
6378 }
6379 }
6380
6381 encode_value ((gint)((guint8*)ei->try_start - code), p, &p);
6382 encode_value ((gint)((guint8*)ei->try_end - code), p, &p);
6383 encode_value ((gint)((guint8*)ei->handler_start - code), p, &p);
6384 }
6385 }
6386
6387 if (jinfo->has_try_block_holes) {
6388 MonoTryBlockHoleTableJitInfo *table = mono_jit_info_get_try_block_hole_table_info (jinfo);
6389 for (i = 0; i < table->num_holes; ++i) {
6390 MonoTryBlockHoleJitInfo *hole = &table->holes [i];
6391 encode_value (hole->clause, p, &p);
6392 encode_value (hole->length, p, &p);
6393 encode_value (hole->offset, p, &p);
6394 }
6395 }
6396
6397 if (jinfo->has_arch_eh_info) {
6398 MonoArchEHJitInfo *eh_info;
6399
6400 eh_info = mono_jit_info_get_arch_eh_info (jinfo);
6401 encode_value (eh_info->stack_size, p, &p);
6402 encode_value (eh_info->epilog_size, p, &p);
6403 }
6404
6405 if (jinfo->has_generic_jit_info) {
6406 MonoGenericJitInfo *gi = mono_jit_info_get_generic_jit_info (jinfo);
6407 MonoGenericSharingContext* gsctx = gi->generic_sharing_context;
6408 guint8 *buf2, *p2;
6409 int len;
6410
6411 encode_value (gi->nlocs, p, &p);
6412 if (gi->nlocs) {
6413 for (i = 0; i < gi->nlocs; ++i) {
6414 MonoDwarfLocListEntry *entry = &gi->locations [i];
6415
6416 encode_value (entry->is_reg ? 1 : 0, p, &p);
6417 encode_value (entry->reg, p, &p);
6418 if (!entry->is_reg)
6419 encode_value (entry->offset, p, &p);
6420 if (i == 0)
6421 g_assert (entry->from == 0);
6422 else
6423 encode_value (entry->from, p, &p);
6424 encode_value (entry->to, p, &p);
6425 }
6426 } else {
6427 if (!cfg->compile_llvm) {
6428 encode_value (gi->has_this ? 1 : 0, p, &p);
6429 encode_value (gi->this_reg, p, &p);
6430 encode_value (gi->this_offset, p, &p);
6431 }
6432 }
6433
6434 /*
6435 * Need to encode jinfo->method too, since it is not equal to 'method'
6436 * when using generic sharing.
6437 */
6438 buf2 = (guint8 *)g_malloc (4096);
6439 p2 = buf2;
6440 encode_method_ref (acfg, jinfo->d.method, p2, &p2);
6441 len = p2 - buf2;
6442 g_assert (len < 4096);
6443 encode_value (len, p, &p);
6444 memcpy (p, buf2, len);
6445 p += p2 - buf2;
6446 g_free (buf2);
6447
6448 if (gsctx && gsctx->is_gsharedvt) {
6449 encode_value (1, p, &p);
6450 } else {
6451 encode_value (0, p, &p);
6452 }
6453 }
6454
6455 if (seq_points_size)
6456 p += mono_seq_point_info_write (seq_points, p);
6457
6458 g_assert (debug_info_size < buf_size);
6459
6460 encode_value (debug_info_size, p, &p);
6461 if (debug_info_size) {
6462 memcpy (p, debug_info, debug_info_size);
6463 p += debug_info_size;
6464 g_free (debug_info);
6465 }
6466
6467 /* GC Map */
6468 if (cfg->gc_map) {
6469 encode_value (cfg->gc_map_size, p, &p);
6470 /* The GC map requires 4 bytes of alignment */
6471 while ((gsize)p % 4)
6472 p ++;
6473 memcpy (p, cfg->gc_map, cfg->gc_map_size);
6474 p += cfg->gc_map_size;
6475 }
6476
6477 acfg->stats.ex_info_size += p - buf;
6478
6479 g_assert (p - buf < buf_size);
6480
6481 /* Emit info */
6482 /* The GC Map requires 4 byte alignment */
6483 cfg->ex_info_offset = add_to_blob_aligned (acfg, buf, p - buf, cfg->gc_map ? 4 : 1);
6484 g_free (buf);
6485 }
6486
6487 static guint32
emit_klass_info(MonoAotCompile * acfg,guint32 token)6488 emit_klass_info (MonoAotCompile *acfg, guint32 token)
6489 {
6490 MonoError error;
6491 MonoClass *klass = mono_class_get_checked (acfg->image, token, &error);
6492 guint8 *p, *buf;
6493 int i, buf_size, res;
6494 gboolean no_special_static, cant_encode;
6495 gpointer iter = NULL;
6496
6497 if (!klass) {
6498 mono_error_cleanup (&error);
6499
6500 buf_size = 16;
6501
6502 p = buf = (guint8 *)g_malloc (buf_size);
6503
6504 /* Mark as unusable */
6505 encode_value (-1, p, &p);
6506
6507 res = add_to_blob (acfg, buf, p - buf);
6508 g_free (buf);
6509
6510 return res;
6511 }
6512
6513 buf_size = 10240 + (klass->vtable_size * 16);
6514 p = buf = (guint8 *)g_malloc (buf_size);
6515
6516 g_assert (klass);
6517
6518 mono_class_init (klass);
6519
6520 mono_class_get_nested_types (klass, &iter);
6521 g_assert (klass->nested_classes_inited);
6522
6523 mono_class_setup_vtable (klass);
6524
6525 /*
6526 * Emit all the information which is required for creating vtables so
6527 * the runtime does not need to create the MonoMethod structures which
6528 * take up a lot of space.
6529 */
6530
6531 no_special_static = !mono_class_has_special_static_fields (klass);
6532
6533 /* Check whenever we have enough info to encode the vtable */
6534 cant_encode = FALSE;
6535 for (i = 0; i < klass->vtable_size; ++i) {
6536 MonoMethod *cm = klass->vtable [i];
6537
6538 if (cm && mono_method_signature (cm)->is_inflated && !g_hash_table_lookup (acfg->token_info_hash, cm))
6539 cant_encode = TRUE;
6540 }
6541
6542 mono_class_has_finalizer (klass);
6543 if (mono_class_has_failure (klass))
6544 cant_encode = TRUE;
6545
6546 if (mono_class_is_gtd (klass) || cant_encode) {
6547 encode_value (-1, p, &p);
6548 } else {
6549 gboolean has_nested = mono_class_get_nested_classes_property (klass) != NULL;
6550 encode_value (klass->vtable_size, p, &p);
6551 encode_value ((klass->has_weak_fields << 9) | (mono_class_is_gtd (klass) ? (1 << 8) : 0) | (no_special_static << 7) | (klass->has_static_refs << 6) | (klass->has_references << 5) | ((klass->blittable << 4) | (has_nested ? 1 : 0) << 3) | (klass->has_cctor << 2) | (klass->has_finalize << 1) | klass->ghcimpl, p, &p);
6552 if (klass->has_cctor)
6553 encode_method_ref (acfg, mono_class_get_cctor (klass), p, &p);
6554 if (klass->has_finalize)
6555 encode_method_ref (acfg, mono_class_get_finalizer (klass), p, &p);
6556
6557 encode_value (klass->instance_size, p, &p);
6558 encode_value (mono_class_data_size (klass), p, &p);
6559 encode_value (klass->packing_size, p, &p);
6560 encode_value (klass->min_align, p, &p);
6561
6562 for (i = 0; i < klass->vtable_size; ++i) {
6563 MonoMethod *cm = klass->vtable [i];
6564
6565 if (cm)
6566 encode_method_ref (acfg, cm, p, &p);
6567 else
6568 encode_value (0, p, &p);
6569 }
6570 }
6571
6572 acfg->stats.class_info_size += p - buf;
6573
6574 g_assert (p - buf < buf_size);
6575 res = add_to_blob (acfg, buf, p - buf);
6576 g_free (buf);
6577
6578 return res;
6579 }
6580
6581 static char*
get_plt_entry_debug_sym(MonoAotCompile * acfg,MonoJumpInfo * ji,GHashTable * cache)6582 get_plt_entry_debug_sym (MonoAotCompile *acfg, MonoJumpInfo *ji, GHashTable *cache)
6583 {
6584 char *debug_sym = NULL;
6585 char *prefix;
6586
6587 if (acfg->llvm && llvm_acfg->aot_opts.static_link) {
6588 /* Need to add a prefix to create unique symbols */
6589 prefix = g_strdup_printf ("plt_%s_", acfg->assembly_name_sym);
6590 } else {
6591 #if defined(TARGET_WIN32) && defined(TARGET_X86)
6592 prefix = mangle_symbol_alloc ("plt_");
6593 #else
6594 prefix = g_strdup ("plt_");
6595 #endif
6596 }
6597
6598 switch (ji->type) {
6599 case MONO_PATCH_INFO_METHOD:
6600 debug_sym = get_debug_sym (ji->data.method, prefix, cache);
6601 break;
6602 case MONO_PATCH_INFO_INTERNAL_METHOD:
6603 debug_sym = g_strdup_printf ("%s_jit_icall_%s", prefix, ji->data.name);
6604 break;
6605 case MONO_PATCH_INFO_RGCTX_FETCH:
6606 debug_sym = g_strdup_printf ("%s_rgctx_fetch_%d", prefix, acfg->label_generator ++);
6607 break;
6608 case MONO_PATCH_INFO_ICALL_ADDR:
6609 case MONO_PATCH_INFO_ICALL_ADDR_CALL: {
6610 char *s = get_debug_sym (ji->data.method, "", cache);
6611
6612 debug_sym = g_strdup_printf ("%s_icall_native_%s", prefix, s);
6613 g_free (s);
6614 break;
6615 }
6616 case MONO_PATCH_INFO_JIT_ICALL_ADDR:
6617 debug_sym = g_strdup_printf ("%s_jit_icall_native_%s", prefix, ji->data.name);
6618 break;
6619 default:
6620 break;
6621 }
6622
6623 g_free (prefix);
6624
6625 return sanitize_symbol (acfg, debug_sym);
6626 }
6627
6628 /*
6629 * Calls made from AOTed code are routed through a table of jumps similar to the
6630 * ELF PLT (Program Linkage Table). Initially the PLT entries jump to code which transfers
6631 * control to the AOT runtime through a trampoline.
6632 */
6633 static void
emit_plt(MonoAotCompile * acfg)6634 emit_plt (MonoAotCompile *acfg)
6635 {
6636 int i;
6637
6638 if (acfg->aot_opts.llvm_only) {
6639 g_assert (acfg->plt_offset == 1);
6640 return;
6641 }
6642
6643 emit_line (acfg);
6644
6645 emit_section_change (acfg, ".text", 0);
6646 emit_alignment_code (acfg, 16);
6647 emit_info_symbol (acfg, "plt");
6648 emit_label (acfg, acfg->plt_symbol);
6649
6650 for (i = 0; i < acfg->plt_offset; ++i) {
6651 char *debug_sym = NULL;
6652 MonoPltEntry *plt_entry = NULL;
6653
6654 if (i == 0)
6655 /*
6656 * The first plt entry is unused.
6657 */
6658 continue;
6659
6660 plt_entry = (MonoPltEntry *)g_hash_table_lookup (acfg->plt_offset_to_entry, GUINT_TO_POINTER (i));
6661
6662 debug_sym = plt_entry->debug_sym;
6663
6664 if (acfg->thumb_mixed && !plt_entry->jit_used)
6665 /* Emit only a thumb version */
6666 continue;
6667
6668 /* Skip plt entries not actually called */
6669 if (!plt_entry->jit_used && !plt_entry->llvm_used)
6670 continue;
6671
6672 if (acfg->llvm && !acfg->thumb_mixed) {
6673 emit_label (acfg, plt_entry->llvm_symbol);
6674 if (acfg->llvm) {
6675 emit_global_inner (acfg, plt_entry->llvm_symbol, TRUE);
6676 #if defined(TARGET_MACH)
6677 fprintf (acfg->fp, ".private_extern %s\n", plt_entry->llvm_symbol);
6678 #endif
6679 }
6680 }
6681
6682 if (debug_sym) {
6683 if (acfg->need_no_dead_strip) {
6684 emit_unset_mode (acfg);
6685 fprintf (acfg->fp, " .no_dead_strip %s\n", debug_sym);
6686 }
6687 emit_local_symbol (acfg, debug_sym, NULL, TRUE);
6688 emit_label (acfg, debug_sym);
6689 }
6690
6691 emit_label (acfg, plt_entry->symbol);
6692
6693 arch_emit_plt_entry (acfg, acfg->got_symbol, (acfg->plt_got_offset_base + i) * sizeof (gpointer), acfg->plt_got_info_offsets [i]);
6694
6695 if (debug_sym)
6696 emit_symbol_size (acfg, debug_sym, ".");
6697 }
6698
6699 if (acfg->thumb_mixed) {
6700 /* Make sure the ARM symbols don't alias the thumb ones */
6701 emit_zero_bytes (acfg, 16);
6702
6703 /*
6704 * Emit a separate set of PLT entries using thumb2 which is called by LLVM generated
6705 * code.
6706 */
6707 for (i = 0; i < acfg->plt_offset; ++i) {
6708 char *debug_sym = NULL;
6709 MonoPltEntry *plt_entry = NULL;
6710
6711 if (i == 0)
6712 continue;
6713
6714 plt_entry = (MonoPltEntry *)g_hash_table_lookup (acfg->plt_offset_to_entry, GUINT_TO_POINTER (i));
6715
6716 /* Skip plt entries not actually called by LLVM code */
6717 if (!plt_entry->llvm_used)
6718 continue;
6719
6720 if (acfg->aot_opts.write_symbols) {
6721 if (plt_entry->debug_sym)
6722 debug_sym = g_strdup_printf ("%s_thumb", plt_entry->debug_sym);
6723 }
6724
6725 if (debug_sym) {
6726 #if defined(TARGET_MACH)
6727 fprintf (acfg->fp, " .thumb_func %s\n", debug_sym);
6728 fprintf (acfg->fp, " .no_dead_strip %s\n", debug_sym);
6729 #endif
6730 emit_local_symbol (acfg, debug_sym, NULL, TRUE);
6731 emit_label (acfg, debug_sym);
6732 }
6733 fprintf (acfg->fp, "\n.thumb_func\n");
6734
6735 emit_label (acfg, plt_entry->llvm_symbol);
6736
6737 if (acfg->llvm)
6738 emit_global_inner (acfg, plt_entry->llvm_symbol, TRUE);
6739
6740 arch_emit_llvm_plt_entry (acfg, acfg->got_symbol, (acfg->plt_got_offset_base + i) * sizeof (gpointer), acfg->plt_got_info_offsets [i]);
6741
6742 if (debug_sym) {
6743 emit_symbol_size (acfg, debug_sym, ".");
6744 g_free (debug_sym);
6745 }
6746 }
6747 }
6748
6749 emit_symbol_size (acfg, acfg->plt_symbol, ".");
6750
6751 emit_info_symbol (acfg, "plt_end");
6752
6753 arch_emit_unwind_info_sections (acfg, "plt", "plt_end", NULL);
6754 }
6755
6756 /*
6757 * emit_trampoline_full:
6758 *
6759 * If EMIT_TINFO is TRUE, emit additional information which can be used to create a MonoJitInfo for this trampoline by
6760 * create_jit_info_for_trampoline ().
6761 */
6762 static G_GNUC_UNUSED void
emit_trampoline_full(MonoAotCompile * acfg,int got_offset,MonoTrampInfo * info,gboolean emit_tinfo)6763 emit_trampoline_full (MonoAotCompile *acfg, int got_offset, MonoTrampInfo *info, gboolean emit_tinfo)
6764 {
6765 char start_symbol [MAX_SYMBOL_SIZE];
6766 char end_symbol [MAX_SYMBOL_SIZE];
6767 char symbol [MAX_SYMBOL_SIZE];
6768 guint32 buf_size, info_offset;
6769 MonoJumpInfo *patch_info;
6770 guint8 *buf, *p;
6771 GPtrArray *patches;
6772 char *name;
6773 guint8 *code;
6774 guint32 code_size;
6775 MonoJumpInfo *ji;
6776 GSList *unwind_ops;
6777
6778 g_assert (info);
6779
6780 name = info->name;
6781 code = info->code;
6782 code_size = info->code_size;
6783 ji = info->ji;
6784 unwind_ops = info->unwind_ops;
6785
6786 /* Emit code */
6787
6788 sprintf (start_symbol, "%s%s", acfg->user_symbol_prefix, name);
6789
6790 emit_section_change (acfg, ".text", 0);
6791 emit_global (acfg, start_symbol, TRUE);
6792 emit_alignment_code (acfg, AOT_FUNC_ALIGNMENT);
6793 emit_label (acfg, start_symbol);
6794
6795 sprintf (symbol, "%snamed_%s", acfg->temp_prefix, name);
6796 emit_label (acfg, symbol);
6797
6798 /*
6799 * The code should access everything through the GOT, so we pass
6800 * TRUE here.
6801 */
6802 emit_and_reloc_code (acfg, NULL, code, code_size, ji, TRUE, NULL);
6803
6804 emit_symbol_size (acfg, start_symbol, ".");
6805
6806 if (emit_tinfo) {
6807 sprintf (end_symbol, "%snamede_%s", acfg->temp_prefix, name);
6808 emit_label (acfg, end_symbol);
6809 }
6810
6811 /* Emit info */
6812
6813 /* Sort relocations */
6814 patches = g_ptr_array_new ();
6815 for (patch_info = ji; patch_info; patch_info = patch_info->next)
6816 if (patch_info->type != MONO_PATCH_INFO_NONE)
6817 g_ptr_array_add (patches, patch_info);
6818 g_ptr_array_sort (patches, compare_patches);
6819
6820 buf_size = patches->len * 128 + 128;
6821 buf = (guint8 *)g_malloc (buf_size);
6822 p = buf;
6823
6824 encode_patch_list (acfg, patches, patches->len, FALSE, got_offset, p, &p);
6825 g_assert (p - buf < buf_size);
6826 g_ptr_array_free (patches, TRUE);
6827
6828 sprintf (symbol, "%s%s_p", acfg->user_symbol_prefix, name);
6829
6830 info_offset = add_to_blob (acfg, buf, p - buf);
6831
6832 emit_section_change (acfg, RODATA_SECT, 0);
6833 emit_global (acfg, symbol, FALSE);
6834 emit_label (acfg, symbol);
6835
6836 emit_int32 (acfg, info_offset);
6837
6838 if (emit_tinfo) {
6839 guint8 *encoded;
6840 guint32 encoded_len;
6841 guint32 uw_offset;
6842
6843 /*
6844 * Emit additional information which can be used to reconstruct a partial MonoTrampInfo.
6845 */
6846 encoded = mono_unwind_ops_encode (info->unwind_ops, &encoded_len);
6847 uw_offset = get_unwind_info_offset (acfg, encoded, encoded_len);
6848 g_free (encoded);
6849
6850 emit_symbol_diff (acfg, end_symbol, start_symbol, 0);
6851 emit_int32 (acfg, uw_offset);
6852 }
6853
6854 /* Emit debug info */
6855 if (unwind_ops) {
6856 char symbol2 [MAX_SYMBOL_SIZE];
6857
6858 sprintf (symbol, "%s", name);
6859 sprintf (symbol2, "%snamed_%s", acfg->temp_prefix, name);
6860
6861 arch_emit_unwind_info_sections (acfg, start_symbol, end_symbol, unwind_ops);
6862
6863 if (acfg->dwarf)
6864 mono_dwarf_writer_emit_trampoline (acfg->dwarf, symbol, symbol2, NULL, NULL, code_size, unwind_ops);
6865 }
6866
6867 g_free (buf);
6868 }
6869
6870 static G_GNUC_UNUSED void
emit_trampoline(MonoAotCompile * acfg,int got_offset,MonoTrampInfo * info)6871 emit_trampoline (MonoAotCompile *acfg, int got_offset, MonoTrampInfo *info)
6872 {
6873 emit_trampoline_full (acfg, got_offset, info, TRUE);
6874 }
6875
6876 static void
emit_trampolines(MonoAotCompile * acfg)6877 emit_trampolines (MonoAotCompile *acfg)
6878 {
6879 char symbol [MAX_SYMBOL_SIZE];
6880 char end_symbol [MAX_SYMBOL_SIZE];
6881 int i, tramp_got_offset;
6882 int ntype;
6883 #ifdef MONO_ARCH_HAVE_FULL_AOT_TRAMPOLINES
6884 int tramp_type;
6885 #endif
6886
6887 if (!mono_aot_mode_is_full (&acfg->aot_opts) || acfg->aot_opts.llvm_only)
6888 return;
6889
6890 g_assert (acfg->image->assembly);
6891
6892 /* Currently, we emit most trampolines into the mscorlib AOT image. */
6893 if (strcmp (acfg->image->assembly->aname.name, "mscorlib") == 0) {
6894 #ifdef MONO_ARCH_HAVE_FULL_AOT_TRAMPOLINES
6895 MonoTrampInfo *info;
6896
6897 /*
6898 * Emit the generic trampolines.
6899 *
6900 * We could save some code by treating the generic trampolines as a wrapper
6901 * method, but that approach has its own complexities, so we choose the simpler
6902 * method.
6903 */
6904 for (tramp_type = 0; tramp_type < MONO_TRAMPOLINE_NUM; ++tramp_type) {
6905 /* we overload the boolean here to indicate the slightly different trampoline needed, see mono_arch_create_generic_trampoline() */
6906 #ifdef DISABLE_REMOTING
6907 if (tramp_type == MONO_TRAMPOLINE_GENERIC_VIRTUAL_REMOTING)
6908 continue;
6909 #endif
6910 mono_arch_create_generic_trampoline ((MonoTrampolineType)tramp_type, &info, acfg->aot_opts.use_trampolines_page? 2: TRUE);
6911 emit_trampoline (acfg, acfg->got_offset, info);
6912 mono_tramp_info_free (info);
6913 }
6914
6915 /* Emit the exception related code pieces */
6916 mono_arch_get_restore_context (&info, TRUE);
6917 emit_trampoline (acfg, acfg->got_offset, info);
6918 mono_tramp_info_free (info);
6919
6920 mono_arch_get_call_filter (&info, TRUE);
6921 emit_trampoline (acfg, acfg->got_offset, info);
6922 mono_tramp_info_free (info);
6923
6924 mono_arch_get_throw_exception (&info, TRUE);
6925 emit_trampoline (acfg, acfg->got_offset, info);
6926 mono_tramp_info_free (info);
6927
6928 mono_arch_get_rethrow_exception (&info, TRUE);
6929 emit_trampoline (acfg, acfg->got_offset, info);
6930 mono_tramp_info_free (info);
6931
6932 mono_arch_get_throw_corlib_exception (&info, TRUE);
6933 emit_trampoline (acfg, acfg->got_offset, info);
6934 mono_tramp_info_free (info);
6935
6936 #ifdef MONO_ARCH_HAVE_SDB_TRAMPOLINES
6937 mono_arch_create_sdb_trampoline (TRUE, &info, TRUE);
6938 emit_trampoline (acfg, acfg->got_offset, info);
6939 mono_tramp_info_free (info);
6940
6941 mono_arch_create_sdb_trampoline (FALSE, &info, TRUE);
6942 emit_trampoline (acfg, acfg->got_offset, info);
6943 mono_tramp_info_free (info);
6944 #endif
6945
6946 #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
6947 mono_arch_get_gsharedvt_trampoline (&info, TRUE);
6948 if (info) {
6949 emit_trampoline_full (acfg, acfg->got_offset, info, TRUE);
6950
6951 /* Create a separate out trampoline for more information in stack traces */
6952 info->name = g_strdup ("gsharedvt_out_trampoline");
6953 emit_trampoline_full (acfg, acfg->got_offset, info, TRUE);
6954 mono_tramp_info_free (info);
6955 }
6956 #endif
6957
6958 #if defined(MONO_ARCH_HAVE_GET_TRAMPOLINES)
6959 {
6960 GSList *l = mono_arch_get_trampolines (TRUE);
6961
6962 while (l) {
6963 MonoTrampInfo *info = (MonoTrampInfo *)l->data;
6964
6965 emit_trampoline (acfg, acfg->got_offset, info);
6966 l = l->next;
6967 }
6968 }
6969 #endif
6970
6971 for (i = 0; i < acfg->aot_opts.nrgctx_fetch_trampolines; ++i) {
6972 int offset;
6973
6974 offset = MONO_RGCTX_SLOT_MAKE_RGCTX (i);
6975 mono_arch_create_rgctx_lazy_fetch_trampoline (offset, &info, TRUE);
6976 emit_trampoline (acfg, acfg->got_offset, info);
6977 mono_tramp_info_free (info);
6978
6979 offset = MONO_RGCTX_SLOT_MAKE_MRGCTX (i);
6980 mono_arch_create_rgctx_lazy_fetch_trampoline (offset, &info, TRUE);
6981 emit_trampoline (acfg, acfg->got_offset, info);
6982 mono_tramp_info_free (info);
6983 }
6984
6985 #ifdef MONO_ARCH_HAVE_GENERAL_RGCTX_LAZY_FETCH_TRAMPOLINE
6986 mono_arch_create_general_rgctx_lazy_fetch_trampoline (&info, TRUE);
6987 emit_trampoline (acfg, acfg->got_offset, info);
6988 mono_tramp_info_free (info);
6989 #endif
6990
6991 {
6992 GSList *l;
6993
6994 /* delegate_invoke_impl trampolines */
6995 l = mono_arch_get_delegate_invoke_impls ();
6996 while (l) {
6997 MonoTrampInfo *info = (MonoTrampInfo *)l->data;
6998
6999 emit_trampoline (acfg, acfg->got_offset, info);
7000 l = l->next;
7001 }
7002 }
7003
7004 if (mono_aot_mode_is_interp (&acfg->aot_opts)) {
7005 mono_arch_get_enter_icall_trampoline (&info);
7006 emit_trampoline (acfg, acfg->got_offset, info);
7007 }
7008
7009 #endif /* #ifdef MONO_ARCH_HAVE_FULL_AOT_TRAMPOLINES */
7010
7011 /* Emit trampolines which are numerous */
7012
7013 /*
7014 * These include the following:
7015 * - specific trampolines
7016 * - static rgctx invoke trampolines
7017 * - imt trampolines
7018 * These trampolines have the same code, they are parameterized by GOT
7019 * slots.
7020 * They are defined in this file, in the arch_... routines instead of
7021 * in tramp-<ARCH>.c, since it is easier to do it this way.
7022 */
7023
7024 /*
7025 * When running in aot-only mode, we can't create specific trampolines at
7026 * runtime, so we create a few, and save them in the AOT file.
7027 * Normal trampolines embed their argument as a literal inside the
7028 * trampoline code, we can't do that here, so instead we embed an offset
7029 * which needs to be added to the trampoline address to get the address of
7030 * the GOT slot which contains the argument value.
7031 * The generated trampolines jump to the generic trampolines using another
7032 * GOT slot, which will be setup by the AOT loader to point to the
7033 * generic trampoline code of the given type.
7034 */
7035
7036 /*
7037 * FIXME: Maybe we should use more specific trampolines (i.e. one class init for
7038 * each class).
7039 */
7040
7041 emit_section_change (acfg, ".text", 0);
7042
7043 tramp_got_offset = acfg->got_offset;
7044
7045 for (ntype = 0; ntype < MONO_AOT_TRAMP_NUM; ++ntype) {
7046 switch (ntype) {
7047 case MONO_AOT_TRAMP_SPECIFIC:
7048 sprintf (symbol, "specific_trampolines");
7049 break;
7050 case MONO_AOT_TRAMP_STATIC_RGCTX:
7051 sprintf (symbol, "static_rgctx_trampolines");
7052 break;
7053 case MONO_AOT_TRAMP_IMT:
7054 sprintf (symbol, "imt_trampolines");
7055 break;
7056 case MONO_AOT_TRAMP_GSHAREDVT_ARG:
7057 sprintf (symbol, "gsharedvt_arg_trampolines");
7058 break;
7059 default:
7060 g_assert_not_reached ();
7061 }
7062
7063 sprintf (end_symbol, "%s_e", symbol);
7064
7065 if (acfg->aot_opts.write_symbols)
7066 emit_local_symbol (acfg, symbol, end_symbol, TRUE);
7067
7068 emit_alignment_code (acfg, AOT_FUNC_ALIGNMENT);
7069 emit_info_symbol (acfg, symbol);
7070
7071 acfg->trampoline_got_offset_base [ntype] = tramp_got_offset;
7072
7073 for (i = 0; i < acfg->num_trampolines [ntype]; ++i) {
7074 int tramp_size = 0;
7075
7076 switch (ntype) {
7077 case MONO_AOT_TRAMP_SPECIFIC:
7078 arch_emit_specific_trampoline (acfg, tramp_got_offset, &tramp_size);
7079 tramp_got_offset += 2;
7080 break;
7081 case MONO_AOT_TRAMP_STATIC_RGCTX:
7082 arch_emit_static_rgctx_trampoline (acfg, tramp_got_offset, &tramp_size);
7083 tramp_got_offset += 2;
7084 break;
7085 case MONO_AOT_TRAMP_IMT:
7086 arch_emit_imt_trampoline (acfg, tramp_got_offset, &tramp_size);
7087 tramp_got_offset += 1;
7088 break;
7089 case MONO_AOT_TRAMP_GSHAREDVT_ARG:
7090 arch_emit_gsharedvt_arg_trampoline (acfg, tramp_got_offset, &tramp_size);
7091 tramp_got_offset += 2;
7092 break;
7093 default:
7094 g_assert_not_reached ();
7095 }
7096 if (!acfg->trampoline_size [ntype]) {
7097 g_assert (tramp_size);
7098 acfg->trampoline_size [ntype] = tramp_size;
7099 }
7100 }
7101
7102 emit_label (acfg, end_symbol);
7103 emit_int32 (acfg, 0);
7104 }
7105
7106 arch_emit_specific_trampoline_pages (acfg);
7107
7108 /* Reserve some entries at the end of the GOT for our use */
7109 acfg->num_trampoline_got_entries = tramp_got_offset - acfg->got_offset;
7110 }
7111
7112 acfg->got_offset += acfg->num_trampoline_got_entries;
7113 }
7114
7115 static gboolean
str_begins_with(const char * str1,const char * str2)7116 str_begins_with (const char *str1, const char *str2)
7117 {
7118 int len = strlen (str2);
7119 return strncmp (str1, str2, len) == 0;
7120 }
7121
7122 void*
mono_aot_readonly_field_override(MonoClassField * field)7123 mono_aot_readonly_field_override (MonoClassField *field)
7124 {
7125 ReadOnlyValue *rdv;
7126 for (rdv = readonly_values; rdv; rdv = rdv->next) {
7127 char *p = rdv->name;
7128 int len;
7129 len = strlen (field->parent->name_space);
7130 if (strncmp (p, field->parent->name_space, len))
7131 continue;
7132 p += len;
7133 if (*p++ != '.')
7134 continue;
7135 len = strlen (field->parent->name);
7136 if (strncmp (p, field->parent->name, len))
7137 continue;
7138 p += len;
7139 if (*p++ != '.')
7140 continue;
7141 if (strcmp (p, field->name))
7142 continue;
7143 switch (rdv->type) {
7144 case MONO_TYPE_I1:
7145 return &rdv->value.i1;
7146 case MONO_TYPE_I2:
7147 return &rdv->value.i2;
7148 case MONO_TYPE_I4:
7149 return &rdv->value.i4;
7150 default:
7151 break;
7152 }
7153 }
7154 return NULL;
7155 }
7156
7157 static void
add_readonly_value(MonoAotOptions * opts,const char * val)7158 add_readonly_value (MonoAotOptions *opts, const char *val)
7159 {
7160 ReadOnlyValue *rdv;
7161 const char *fval;
7162 const char *tval;
7163 /* the format of val is:
7164 * namespace.typename.fieldname=type/value
7165 * type can be i1 for uint8/int8/boolean, i2 for uint16/int16/char, i4 for uint32/int32
7166 */
7167 fval = strrchr (val, '/');
7168 if (!fval) {
7169 fprintf (stderr, "AOT : invalid format for readonly field '%s', missing /.\n", val);
7170 exit (1);
7171 }
7172 tval = strrchr (val, '=');
7173 if (!tval) {
7174 fprintf (stderr, "AOT : invalid format for readonly field '%s', missing =.\n", val);
7175 exit (1);
7176 }
7177 rdv = g_new0 (ReadOnlyValue, 1);
7178 rdv->name = (char *)g_malloc0 (tval - val + 1);
7179 memcpy (rdv->name, val, tval - val);
7180 tval++;
7181 fval++;
7182 if (strncmp (tval, "i1", 2) == 0) {
7183 rdv->value.i1 = atoi (fval);
7184 rdv->type = MONO_TYPE_I1;
7185 } else if (strncmp (tval, "i2", 2) == 0) {
7186 rdv->value.i2 = atoi (fval);
7187 rdv->type = MONO_TYPE_I2;
7188 } else if (strncmp (tval, "i4", 2) == 0) {
7189 rdv->value.i4 = atoi (fval);
7190 rdv->type = MONO_TYPE_I4;
7191 } else {
7192 fprintf (stderr, "AOT : unsupported type for readonly field '%s'.\n", tval);
7193 exit (1);
7194 }
7195 rdv->next = readonly_values;
7196 readonly_values = rdv;
7197 }
7198
7199 static gchar *
clean_path(gchar * path)7200 clean_path (gchar * path)
7201 {
7202 if (!path)
7203 return NULL;
7204
7205 if (g_str_has_suffix (path, G_DIR_SEPARATOR_S))
7206 return path;
7207
7208 gchar *clean = g_strconcat (path, G_DIR_SEPARATOR_S, NULL);
7209 g_free (path);
7210
7211 return clean;
7212 }
7213
7214 static gchar *
wrap_path(gchar * path)7215 wrap_path (gchar * path)
7216 {
7217 int len;
7218 if (!path)
7219 return NULL;
7220
7221 // If the string contains no spaces, just return the original string.
7222 if (strstr (path, " ") == NULL)
7223 return path;
7224
7225 // If the string is already wrapped in quotes, return it.
7226 len = strlen (path);
7227 if (len >= 2 && path[0] == '\"' && path[len-1] == '\"')
7228 return path;
7229
7230 // If the string contains spaces, then wrap it in quotes.
7231 gchar *clean = g_strdup_printf ("\"%s\"", path);
7232
7233 return clean;
7234 }
7235
7236 // Duplicate a char range and add it to a ptrarray, but only if it is nonempty
7237 static void
ptr_array_add_range_if_nonempty(GPtrArray * args,gchar const * start,gchar const * end)7238 ptr_array_add_range_if_nonempty(GPtrArray *args, gchar const *start, gchar const *end)
7239 {
7240 ptrdiff_t len = end-start;
7241 if (len > 0)
7242 g_ptr_array_add (args, g_strndup (start, len));
7243 }
7244
7245 static GPtrArray *
mono_aot_split_options(const char * aot_options)7246 mono_aot_split_options (const char *aot_options)
7247 {
7248 enum MonoAotOptionState {
7249 MONO_AOT_OPTION_STATE_DEFAULT,
7250 MONO_AOT_OPTION_STATE_STRING,
7251 MONO_AOT_OPTION_STATE_ESCAPE,
7252 };
7253
7254 GPtrArray *args = g_ptr_array_new ();
7255 enum MonoAotOptionState state = MONO_AOT_OPTION_STATE_DEFAULT;
7256 gchar const *opt_start = aot_options;
7257 gboolean end_of_string = FALSE;
7258 gchar cur;
7259
7260 g_return_val_if_fail (aot_options != NULL, NULL);
7261
7262 while ((cur = *aot_options) != '\0') {
7263 if (state == MONO_AOT_OPTION_STATE_ESCAPE)
7264 goto next;
7265
7266 switch (cur) {
7267 case '"':
7268 // If we find a quote, then if we're in the default case then
7269 // it means we've found the start of a string, if not then it
7270 // means we've found the end of the string and should switch
7271 // back to the default case.
7272 switch (state) {
7273 case MONO_AOT_OPTION_STATE_DEFAULT:
7274 state = MONO_AOT_OPTION_STATE_STRING;
7275 break;
7276 case MONO_AOT_OPTION_STATE_STRING:
7277 state = MONO_AOT_OPTION_STATE_DEFAULT;
7278 break;
7279 case MONO_AOT_OPTION_STATE_ESCAPE:
7280 g_assert_not_reached ();
7281 break;
7282 }
7283 break;
7284 case '\\':
7285 // If we've found an escaping operator, then this means we
7286 // should not process the next character if inside a string.
7287 if (state == MONO_AOT_OPTION_STATE_STRING)
7288 state = MONO_AOT_OPTION_STATE_ESCAPE;
7289 break;
7290 case ',':
7291 // If we're in the default state then this means we've found
7292 // an option, store it for later processing.
7293 if (state == MONO_AOT_OPTION_STATE_DEFAULT)
7294 goto new_opt;
7295 break;
7296 }
7297
7298 next:
7299 aot_options++;
7300 restart:
7301 // If the next character is end of string, then process the last option.
7302 if (*(aot_options) == '\0') {
7303 end_of_string = TRUE;
7304 goto new_opt;
7305 }
7306 continue;
7307
7308 new_opt:
7309 ptr_array_add_range_if_nonempty (args, opt_start, aot_options);
7310 opt_start = ++aot_options;
7311 if (end_of_string)
7312 break;
7313 goto restart; // Check for null and continue loop
7314 }
7315
7316 return args;
7317 }
7318
7319 static void
mono_aot_parse_options(const char * aot_options,MonoAotOptions * opts)7320 mono_aot_parse_options (const char *aot_options, MonoAotOptions *opts)
7321 {
7322 GPtrArray* args;
7323
7324 args = mono_aot_split_options (aot_options ? aot_options : "");
7325 for (int i = 0; i < args->len; ++i) {
7326 const char *arg = (const char *)g_ptr_array_index (args, i);
7327
7328 if (str_begins_with (arg, "outfile=")) {
7329 opts->outfile = g_strdup (arg + strlen ("outfile="));
7330 } else if (str_begins_with (arg, "llvm-outfile=")) {
7331 opts->llvm_outfile = g_strdup (arg + strlen ("llvm-outfile="));
7332 } else if (str_begins_with (arg, "temp-path=")) {
7333 opts->temp_path = clean_path (g_strdup (arg + strlen ("temp-path=")));
7334 } else if (str_begins_with (arg, "save-temps")) {
7335 opts->save_temps = TRUE;
7336 } else if (str_begins_with (arg, "keep-temps")) {
7337 opts->save_temps = TRUE;
7338 } else if (str_begins_with (arg, "write-symbols")) {
7339 opts->write_symbols = TRUE;
7340 } else if (str_begins_with (arg, "no-write-symbols")) {
7341 opts->write_symbols = FALSE;
7342 // Intentionally undocumented -- one-off experiment
7343 } else if (str_begins_with (arg, "metadata-only")) {
7344 opts->metadata_only = TRUE;
7345 } else if (str_begins_with (arg, "bind-to-runtime-version")) {
7346 opts->bind_to_runtime_version = TRUE;
7347 } else if (str_begins_with (arg, "full")) {
7348 opts->mode = MONO_AOT_MODE_FULL;
7349 } else if (str_begins_with (arg, "hybrid")) {
7350 opts->mode = MONO_AOT_MODE_HYBRID;
7351 } else if (str_begins_with (arg, "interp")) {
7352 opts->mode = MONO_AOT_MODE_INTERP;
7353 } else if (str_begins_with (arg, "threads=")) {
7354 opts->nthreads = atoi (arg + strlen ("threads="));
7355 } else if (str_begins_with (arg, "static")) {
7356 opts->static_link = TRUE;
7357 opts->no_dlsym = TRUE;
7358 } else if (str_begins_with (arg, "asmonly")) {
7359 opts->asm_only = TRUE;
7360 } else if (str_begins_with (arg, "asmwriter")) {
7361 opts->asm_writer = TRUE;
7362 } else if (str_begins_with (arg, "nodebug")) {
7363 opts->nodebug = TRUE;
7364 } else if (str_begins_with (arg, "dwarfdebug")) {
7365 opts->dwarf_debug = TRUE;
7366 // Intentionally undocumented -- No one remembers what this does. It appears to be ARM-only
7367 } else if (str_begins_with (arg, "nopagetrampolines")) {
7368 opts->use_trampolines_page = FALSE;
7369 } else if (str_begins_with (arg, "ntrampolines=")) {
7370 opts->ntrampolines = atoi (arg + strlen ("ntrampolines="));
7371 } else if (str_begins_with (arg, "nrgctx-trampolines=")) {
7372 opts->nrgctx_trampolines = atoi (arg + strlen ("nrgctx-trampolines="));
7373 } else if (str_begins_with (arg, "nrgctx-fetch-trampolines=")) {
7374 opts->nrgctx_fetch_trampolines = atoi (arg + strlen ("nrgctx-fetch-trampolines="));
7375 } else if (str_begins_with (arg, "nimt-trampolines=")) {
7376 opts->nimt_trampolines = atoi (arg + strlen ("nimt-trampolines="));
7377 } else if (str_begins_with (arg, "ngsharedvt-trampolines=")) {
7378 opts->ngsharedvt_arg_trampolines = atoi (arg + strlen ("ngsharedvt-trampolines="));
7379 } else if (str_begins_with (arg, "tool-prefix=")) {
7380 opts->tool_prefix = g_strdup (arg + strlen ("tool-prefix="));
7381 } else if (str_begins_with (arg, "ld-flags=")) {
7382 opts->ld_flags = g_strdup (arg + strlen ("ld-flags="));
7383 } else if (str_begins_with (arg, "soft-debug")) {
7384 opts->soft_debug = TRUE;
7385 // Intentionally undocumented x2-- deprecated
7386 } else if (str_begins_with (arg, "gen-seq-points-file=")) {
7387 fprintf (stderr, "Mono Warning: aot option gen-seq-points-file= is deprecated.\n");
7388 } else if (str_begins_with (arg, "gen-seq-points-file")) {
7389 fprintf (stderr, "Mono Warning: aot option gen-seq-points-file is deprecated.\n");
7390 } else if (str_begins_with (arg, "msym-dir=")) {
7391 debug_options.no_seq_points_compact_data = FALSE;
7392 opts->gen_msym_dir = TRUE;
7393 opts->gen_msym_dir_path = g_strdup (arg + strlen ("msym_dir="));;
7394 } else if (str_begins_with (arg, "direct-pinvoke")) {
7395 opts->direct_pinvoke = TRUE;
7396 } else if (str_begins_with (arg, "direct-icalls")) {
7397 opts->direct_icalls = TRUE;
7398 } else if (str_begins_with (arg, "no-direct-calls")) {
7399 opts->no_direct_calls = TRUE;
7400 } else if (str_begins_with (arg, "print-skipped")) {
7401 opts->print_skipped_methods = TRUE;
7402 } else if (str_begins_with (arg, "stats")) {
7403 opts->stats = TRUE;
7404 // Intentionally undocumented-- has no known function other than to debug the compiler
7405 } else if (str_begins_with (arg, "no-instances")) {
7406 opts->no_instances = TRUE;
7407 // Intentionally undocumented x4-- Used for internal debugging of compiler
7408 } else if (str_begins_with (arg, "log-generics")) {
7409 opts->log_generics = TRUE;
7410 } else if (str_begins_with (arg, "log-instances=")) {
7411 opts->log_instances = TRUE;
7412 opts->instances_logfile_path = g_strdup (arg + strlen ("log-instances="));
7413 } else if (str_begins_with (arg, "log-instances")) {
7414 opts->log_instances = TRUE;
7415 } else if (str_begins_with (arg, "internal-logfile=")) {
7416 opts->logfile = g_strdup (arg + strlen ("internal-logfile="));
7417 } else if (str_begins_with (arg, "dedup-skip")) {
7418 opts->dedup = TRUE;
7419 } else if (str_begins_with (arg, "dedup-include=")) {
7420 opts->dedup_include = g_strdup (arg + strlen ("dedup-include="));
7421 } else if (str_begins_with (arg, "mtriple=")) {
7422 opts->mtriple = g_strdup (arg + strlen ("mtriple="));
7423 } else if (str_begins_with (arg, "llvm-path=")) {
7424 opts->llvm_path = clean_path (g_strdup (arg + strlen ("llvm-path=")));
7425 } else if (!strcmp (arg, "llvm")) {
7426 opts->llvm = TRUE;
7427 } else if (str_begins_with (arg, "readonly-value=")) {
7428 add_readonly_value (opts, arg + strlen ("readonly-value="));
7429 } else if (str_begins_with (arg, "info")) {
7430 printf ("AOT target setup: %s.\n", AOT_TARGET_STR);
7431 exit (0);
7432 // Intentionally undocumented: Used for precise stack maps, which are not available yet
7433 } else if (str_begins_with (arg, "gc-maps")) {
7434 mini_gc_enable_gc_maps_for_aot ();
7435 // Intentionally undocumented: Used for internal debugging
7436 } else if (str_begins_with (arg, "dump")) {
7437 opts->dump_json = TRUE;
7438 } else if (str_begins_with (arg, "llvmonly")) {
7439 opts->mode = MONO_AOT_MODE_FULL;
7440 opts->llvm = TRUE;
7441 opts->llvm_only = TRUE;
7442 } else if (str_begins_with (arg, "data-outfile=")) {
7443 opts->data_outfile = g_strdup (arg + strlen ("data-outfile="));
7444 } else if (str_begins_with (arg, "profile=")) {
7445 opts->profile_files = g_list_append (opts->profile_files, g_strdup (arg + strlen ("profile=")));
7446 } else if (!strcmp (arg, "profile-only")) {
7447 opts->profile_only = TRUE;
7448 } else if (!strcmp (arg, "verbose")) {
7449 opts->verbose = TRUE;
7450 } else if (str_begins_with (arg, "help") || str_begins_with (arg, "?")) {
7451 printf ("Supported options for --aot:\n");
7452 printf (" asmonly\n");
7453 printf (" bind-to-runtime-version\n");
7454 printf (" bitcode\n");
7455 printf (" data-outfile=\n");
7456 printf (" direct-icalls\n");
7457 printf (" direct-pinvoke\n");
7458 printf (" dwarfdebug\n");
7459 printf (" full\n");
7460 printf (" hybrid\n");
7461 printf (" info\n");
7462 printf (" keep-temps\n");
7463 printf (" llvm\n");
7464 printf (" llvmonly\n");
7465 printf (" llvm-outfile=\n");
7466 printf (" llvm-path=\n");
7467 printf (" msym-dir=\n");
7468 printf (" mtriple\n");
7469 printf (" nimt-trampolines=\n");
7470 printf (" nodebug\n");
7471 printf (" no-direct-calls\n");
7472 printf (" no-write-symbols\n");
7473 printf (" nrgctx-trampolines=\n");
7474 printf (" nrgctx-fetch-trampolines=\n");
7475 printf (" ngsharedvt-trampolines=\n");
7476 printf (" ntrampolines=\n");
7477 printf (" outfile=\n");
7478 printf (" profile=\n");
7479 printf (" profile-only\n");
7480 printf (" print-skipped-methods\n");
7481 printf (" readonly-value=\n");
7482 printf (" save-temps\n");
7483 printf (" soft-debug\n");
7484 printf (" static\n");
7485 printf (" stats\n");
7486 printf (" temp-path=\n");
7487 printf (" tool-prefix=\n");
7488 printf (" threads=\n");
7489 printf (" write-symbols\n");
7490 printf (" verbose\n");
7491 printf (" help/?\n");
7492 exit (0);
7493 } else {
7494 fprintf (stderr, "AOT : Unknown argument '%s'.\n", arg);
7495 exit (1);
7496 }
7497
7498 g_free ((gpointer) arg);
7499 }
7500
7501 if (opts->use_trampolines_page) {
7502 opts->ntrampolines = 0;
7503 opts->nrgctx_trampolines = 0;
7504 opts->nimt_trampolines = 0;
7505 opts->ngsharedvt_arg_trampolines = 0;
7506 }
7507
7508 g_ptr_array_free (args, /*free_seg=*/TRUE);
7509 }
7510
7511 static void
add_token_info_hash(gpointer key,gpointer value,gpointer user_data)7512 add_token_info_hash (gpointer key, gpointer value, gpointer user_data)
7513 {
7514 MonoMethod *method = (MonoMethod*)key;
7515 MonoJumpInfoToken *ji = (MonoJumpInfoToken*)value;
7516 MonoAotCompile *acfg = (MonoAotCompile *)user_data;
7517 MonoJumpInfoToken *new_ji;
7518
7519 new_ji = (MonoJumpInfoToken *)mono_mempool_alloc0 (acfg->mempool, sizeof (MonoJumpInfoToken));
7520 new_ji->image = ji->image;
7521 new_ji->token = ji->token;
7522 g_hash_table_insert (acfg->token_info_hash, method, new_ji);
7523 }
7524
7525 static gboolean
can_encode_class(MonoAotCompile * acfg,MonoClass * klass)7526 can_encode_class (MonoAotCompile *acfg, MonoClass *klass)
7527 {
7528 if (klass->type_token)
7529 return TRUE;
7530 if ((klass->byval_arg.type == MONO_TYPE_VAR) || (klass->byval_arg.type == MONO_TYPE_MVAR) || (klass->byval_arg.type == MONO_TYPE_PTR))
7531 return TRUE;
7532 if (klass->rank)
7533 return can_encode_class (acfg, klass->element_class);
7534 return FALSE;
7535 }
7536
7537 static gboolean
can_encode_method(MonoAotCompile * acfg,MonoMethod * method)7538 can_encode_method (MonoAotCompile *acfg, MonoMethod *method)
7539 {
7540 if (method->wrapper_type) {
7541 switch (method->wrapper_type) {
7542 case MONO_WRAPPER_NONE:
7543 case MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK:
7544 case MONO_WRAPPER_XDOMAIN_INVOKE:
7545 case MONO_WRAPPER_STFLD:
7546 case MONO_WRAPPER_LDFLD:
7547 case MONO_WRAPPER_LDFLDA:
7548 case MONO_WRAPPER_STELEMREF:
7549 case MONO_WRAPPER_PROXY_ISINST:
7550 case MONO_WRAPPER_ALLOC:
7551 case MONO_WRAPPER_REMOTING_INVOKE:
7552 case MONO_WRAPPER_UNKNOWN:
7553 case MONO_WRAPPER_WRITE_BARRIER:
7554 case MONO_WRAPPER_DELEGATE_INVOKE:
7555 case MONO_WRAPPER_DELEGATE_BEGIN_INVOKE:
7556 case MONO_WRAPPER_DELEGATE_END_INVOKE:
7557 case MONO_WRAPPER_SYNCHRONIZED:
7558 break;
7559 case MONO_WRAPPER_MANAGED_TO_MANAGED:
7560 case MONO_WRAPPER_CASTCLASS: {
7561 WrapperInfo *info = mono_marshal_get_wrapper_info (method);
7562
7563 if (info)
7564 return TRUE;
7565 else
7566 return FALSE;
7567 break;
7568 }
7569 default:
7570 //printf ("Skip (wrapper call): %d -> %s\n", patch_info->type, mono_method_full_name (patch_info->data.method, TRUE));
7571 return FALSE;
7572 }
7573 } else {
7574 if (!method->token) {
7575 /* The method is part of a constructed type like Int[,].Set (). */
7576 if (!g_hash_table_lookup (acfg->token_info_hash, method)) {
7577 if (method->klass->rank)
7578 return TRUE;
7579 return FALSE;
7580 }
7581 }
7582 }
7583 return TRUE;
7584 }
7585
7586 static gboolean
can_encode_patch(MonoAotCompile * acfg,MonoJumpInfo * patch_info)7587 can_encode_patch (MonoAotCompile *acfg, MonoJumpInfo *patch_info)
7588 {
7589 switch (patch_info->type) {
7590 case MONO_PATCH_INFO_METHOD:
7591 case MONO_PATCH_INFO_METHODCONST:
7592 case MONO_PATCH_INFO_METHOD_CODE_SLOT: {
7593 MonoMethod *method = patch_info->data.method;
7594
7595 return can_encode_method (acfg, method);
7596 }
7597 case MONO_PATCH_INFO_VTABLE:
7598 case MONO_PATCH_INFO_CLASS:
7599 case MONO_PATCH_INFO_IID:
7600 case MONO_PATCH_INFO_ADJUSTED_IID:
7601 if (!can_encode_class (acfg, patch_info->data.klass)) {
7602 //printf ("Skip: %s\n", mono_type_full_name (&patch_info->data.klass->byval_arg));
7603 return FALSE;
7604 }
7605 break;
7606 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE: {
7607 if (!can_encode_class (acfg, patch_info->data.del_tramp->klass)) {
7608 //printf ("Skip: %s\n", mono_type_full_name (&patch_info->data.klass->byval_arg));
7609 return FALSE;
7610 }
7611 break;
7612 }
7613 case MONO_PATCH_INFO_RGCTX_FETCH:
7614 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX: {
7615 MonoJumpInfoRgctxEntry *entry = patch_info->data.rgctx_entry;
7616
7617 if (!can_encode_method (acfg, entry->method))
7618 return FALSE;
7619 if (!can_encode_patch (acfg, entry->data))
7620 return FALSE;
7621 break;
7622 }
7623 default:
7624 break;
7625 }
7626
7627 return TRUE;
7628 }
7629
7630 static gboolean
is_concrete_type(MonoType * t)7631 is_concrete_type (MonoType *t)
7632 {
7633 MonoClass *klass;
7634 int i;
7635
7636 if (t->type == MONO_TYPE_VAR || t->type == MONO_TYPE_MVAR)
7637 return FALSE;
7638 if (t->type == MONO_TYPE_GENERICINST) {
7639 MonoGenericContext *orig_ctx;
7640 MonoGenericInst *inst;
7641 MonoType *arg;
7642
7643 if (!MONO_TYPE_ISSTRUCT (t))
7644 return TRUE;
7645 klass = mono_class_from_mono_type (t);
7646 orig_ctx = &mono_class_get_generic_class (klass)->context;
7647
7648 inst = orig_ctx->class_inst;
7649 if (inst) {
7650 for (i = 0; i < inst->type_argc; ++i) {
7651 arg = mini_get_underlying_type (inst->type_argv [i]);
7652 if (!is_concrete_type (arg))
7653 return FALSE;
7654 }
7655 }
7656 inst = orig_ctx->method_inst;
7657 if (inst) {
7658 for (i = 0; i < inst->type_argc; ++i) {
7659 arg = mini_get_underlying_type (inst->type_argv [i]);
7660 if (!is_concrete_type (arg))
7661 return FALSE;
7662 }
7663 }
7664 }
7665 return TRUE;
7666 }
7667
7668 /* LOCKING: Assumes the loader lock is held */
7669 static void
add_gsharedvt_wrappers(MonoAotCompile * acfg,MonoMethodSignature * sig,gboolean gsharedvt_in,gboolean gsharedvt_out)7670 add_gsharedvt_wrappers (MonoAotCompile *acfg, MonoMethodSignature *sig, gboolean gsharedvt_in, gboolean gsharedvt_out)
7671 {
7672 MonoMethod *wrapper;
7673 gboolean concrete = TRUE;
7674 gboolean add_in = gsharedvt_in;
7675 gboolean add_out = gsharedvt_out;
7676
7677 if (gsharedvt_in && g_hash_table_lookup (acfg->gsharedvt_in_signatures, sig))
7678 add_in = FALSE;
7679 if (gsharedvt_out && g_hash_table_lookup (acfg->gsharedvt_out_signatures, sig))
7680 add_out = FALSE;
7681
7682 if (!add_in && !add_out)
7683 return;
7684
7685 if (mini_is_gsharedvt_variable_signature (sig))
7686 return;
7687
7688 if (add_in)
7689 g_hash_table_insert (acfg->gsharedvt_in_signatures, sig, sig);
7690 if (add_out)
7691 g_hash_table_insert (acfg->gsharedvt_out_signatures, sig, sig);
7692
7693 if (!sig->has_type_parameters) {
7694 //printf ("%s\n", mono_signature_full_name (sig));
7695
7696 if (gsharedvt_in) {
7697 wrapper = mini_get_gsharedvt_in_sig_wrapper (sig);
7698 add_extra_method (acfg, wrapper);
7699 }
7700 if (gsharedvt_out) {
7701 wrapper = mini_get_gsharedvt_out_sig_wrapper (sig);
7702 add_extra_method (acfg, wrapper);
7703 }
7704 } else {
7705 /* For signatures creared during generic sharing, convert them to a concrete signature if possible */
7706 MonoMethodSignature *copy = mono_metadata_signature_dup (sig);
7707 int i;
7708
7709 //printf ("%s\n", mono_signature_full_name (sig));
7710
7711 copy->ret = mini_get_underlying_type (sig->ret);
7712 if (!is_concrete_type (copy->ret))
7713 concrete = FALSE;
7714 for (i = 0; i < sig->param_count; ++i) {
7715 copy->params [i] = mini_get_underlying_type (sig->params [i]);
7716 if (!is_concrete_type (copy->params [i]))
7717 concrete = FALSE;
7718 }
7719 if (concrete) {
7720 copy->has_type_parameters = 0;
7721
7722 if (gsharedvt_in) {
7723 wrapper = mini_get_gsharedvt_in_sig_wrapper (copy);
7724 add_extra_method (acfg, wrapper);
7725 }
7726
7727 if (gsharedvt_out) {
7728 wrapper = mini_get_gsharedvt_out_sig_wrapper (copy);
7729 add_extra_method (acfg, wrapper);
7730 }
7731
7732 //printf ("%s\n", mono_method_full_name (wrapper, 1));
7733 }
7734 }
7735 }
7736
7737 /*
7738 * compile_method:
7739 *
7740 * AOT compile a given method.
7741 * This function might be called by multiple threads, so it must be thread-safe.
7742 */
7743 static void
compile_method(MonoAotCompile * acfg,MonoMethod * method)7744 compile_method (MonoAotCompile *acfg, MonoMethod *method)
7745 {
7746 MonoCompile *cfg;
7747 MonoJumpInfo *patch_info;
7748 gboolean skip;
7749 int index, depth;
7750 MonoMethod *wrapped;
7751 GTimer *jit_timer;
7752 JitFlags flags;
7753
7754 if (acfg->aot_opts.metadata_only)
7755 return;
7756
7757 mono_acfg_lock (acfg);
7758 index = get_method_index (acfg, method);
7759 mono_acfg_unlock (acfg);
7760
7761 /* fixme: maybe we can also precompile wrapper methods */
7762 if ((method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
7763 (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
7764 (method->flags & METHOD_ATTRIBUTE_ABSTRACT)) {
7765 //printf ("Skip (impossible): %s\n", mono_method_full_name (method, TRUE));
7766 return;
7767 }
7768
7769 if (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL)
7770 return;
7771
7772 wrapped = mono_marshal_method_from_wrapper (method);
7773 if (wrapped && (wrapped->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && wrapped->is_generic)
7774 // FIXME: The wrapper should be generic too, but it is not
7775 return;
7776
7777 if (method->wrapper_type == MONO_WRAPPER_COMINTEROP)
7778 return;
7779
7780 if (acfg->aot_opts.profile_only && !method->is_inflated && !g_hash_table_lookup (acfg->profile_methods, method))
7781 return;
7782
7783 mono_atomic_inc_i32 (&acfg->stats.mcount);
7784
7785 #if 0
7786 if (method->is_generic || mono_class_is_gtd (method->klass)) {
7787 mono_atomic_inc_i32 (&acfg->stats.genericcount);
7788 return;
7789 }
7790 #endif
7791
7792 //acfg->aot_opts.print_skipped_methods = TRUE;
7793
7794 /*
7795 * Since these methods are the only ones which are compiled with
7796 * AOT support, and they are not used by runtime startup/shutdown code,
7797 * the runtime will not see AOT methods during AOT compilation,so it
7798 * does not need to support them by creating a fake GOT etc.
7799 */
7800 flags = JIT_FLAG_AOT;
7801 if (mono_aot_mode_is_full (&acfg->aot_opts))
7802 flags = (JitFlags)(flags | JIT_FLAG_FULL_AOT);
7803 if (acfg->llvm)
7804 flags = (JitFlags)(flags | JIT_FLAG_LLVM);
7805 if (acfg->aot_opts.llvm_only)
7806 flags = (JitFlags)(flags | JIT_FLAG_LLVM_ONLY | JIT_FLAG_EXPLICIT_NULL_CHECKS);
7807 if (acfg->aot_opts.no_direct_calls)
7808 flags = (JitFlags)(flags | JIT_FLAG_NO_DIRECT_ICALLS);
7809 if (acfg->aot_opts.direct_pinvoke)
7810 flags = (JitFlags)(flags | JIT_FLAG_DIRECT_PINVOKE);
7811
7812 jit_timer = mono_time_track_start ();
7813 cfg = mini_method_compile (method, acfg->opts, mono_get_root_domain (), flags, 0, index);
7814 mono_time_track_end (&mono_jit_stats.jit_time, jit_timer);
7815
7816 if (cfg->exception_type == MONO_EXCEPTION_GENERIC_SHARING_FAILED) {
7817 if (acfg->aot_opts.print_skipped_methods)
7818 printf ("Skip (gshared failure): %s (%s)\n", mono_method_get_full_name (method), cfg->exception_message);
7819 mono_atomic_inc_i32 (&acfg->stats.genericcount);
7820 return;
7821 }
7822 if (cfg->exception_type != MONO_EXCEPTION_NONE) {
7823 /* Some instances cannot be JITted due to constraints etc. */
7824 if (!method->is_inflated)
7825 report_loader_error (acfg, &cfg->error, FALSE, "Unable to compile method '%s' due to: '%s'.\n", mono_method_get_full_name (method), mono_error_get_message (&cfg->error));
7826 /* Let the exception happen at runtime */
7827 return;
7828 }
7829
7830 if (cfg->disable_aot) {
7831 if (acfg->aot_opts.print_skipped_methods)
7832 printf ("Skip (disabled): %s\n", mono_method_get_full_name (method));
7833 mono_atomic_inc_i32 (&acfg->stats.ocount);
7834 return;
7835 }
7836 cfg->method_index = index;
7837
7838 /* Nullify patches which need no aot processing */
7839 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
7840 switch (patch_info->type) {
7841 case MONO_PATCH_INFO_LABEL:
7842 case MONO_PATCH_INFO_BB:
7843 patch_info->type = MONO_PATCH_INFO_NONE;
7844 break;
7845 default:
7846 break;
7847 }
7848 }
7849
7850 /* Collect method->token associations from the cfg */
7851 mono_acfg_lock (acfg);
7852 g_hash_table_foreach (cfg->token_info_hash, add_token_info_hash, acfg);
7853 mono_acfg_unlock (acfg);
7854 g_hash_table_destroy (cfg->token_info_hash);
7855 cfg->token_info_hash = NULL;
7856
7857 /*
7858 * Check for absolute addresses.
7859 */
7860 skip = FALSE;
7861 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
7862 switch (patch_info->type) {
7863 case MONO_PATCH_INFO_ABS:
7864 /* unable to handle this */
7865 skip = TRUE;
7866 break;
7867 default:
7868 break;
7869 }
7870 }
7871
7872 if (skip) {
7873 if (acfg->aot_opts.print_skipped_methods)
7874 printf ("Skip (abs call): %s\n", mono_method_get_full_name (method));
7875 mono_atomic_inc_i32 (&acfg->stats.abscount);
7876 return;
7877 }
7878
7879 /* Lock for the rest of the code */
7880 mono_acfg_lock (acfg);
7881
7882 if (cfg->gsharedvt)
7883 acfg->stats.method_categories [METHOD_CAT_GSHAREDVT] ++;
7884 else if (cfg->gshared)
7885 acfg->stats.method_categories [METHOD_CAT_INST] ++;
7886 else if (cfg->method->wrapper_type)
7887 acfg->stats.method_categories [METHOD_CAT_WRAPPER] ++;
7888 else
7889 acfg->stats.method_categories [METHOD_CAT_NORMAL] ++;
7890
7891 /*
7892 * Check for methods/klasses we can't encode.
7893 */
7894 skip = FALSE;
7895 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
7896 if (!can_encode_patch (acfg, patch_info))
7897 skip = TRUE;
7898 }
7899
7900 if (skip) {
7901 if (acfg->aot_opts.print_skipped_methods)
7902 printf ("Skip (patches): %s\n", mono_method_get_full_name (method));
7903 acfg->stats.ocount++;
7904 mono_acfg_unlock (acfg);
7905 return;
7906 }
7907
7908 if (!cfg->compile_llvm)
7909 acfg->has_jitted_code = TRUE;
7910
7911 if (method->is_inflated && acfg->aot_opts.log_instances) {
7912 if (acfg->instances_logfile)
7913 fprintf (acfg->instances_logfile, "%s ### %d\n", mono_method_get_full_name (method), cfg->code_size);
7914 else
7915 printf ("%s ### %d\n", mono_method_get_full_name (method), cfg->code_size);
7916 }
7917
7918 /* Adds generic instances referenced by this method */
7919 /*
7920 * The depth is used to avoid infinite loops when generic virtual recursion is
7921 * encountered.
7922 */
7923 depth = GPOINTER_TO_UINT (g_hash_table_lookup (acfg->method_depth, method));
7924 if (!acfg->aot_opts.no_instances && depth < 32 && (mono_aot_mode_is_full (&acfg->aot_opts) || mono_aot_mode_is_hybrid (&acfg->aot_opts))) {
7925 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
7926 switch (patch_info->type) {
7927 case MONO_PATCH_INFO_RGCTX_FETCH:
7928 case MONO_PATCH_INFO_RGCTX_SLOT_INDEX:
7929 case MONO_PATCH_INFO_METHOD:
7930 case MONO_PATCH_INFO_METHOD_RGCTX: {
7931 MonoMethod *m = NULL;
7932
7933 if (patch_info->type == MONO_PATCH_INFO_RGCTX_FETCH || patch_info->type == MONO_PATCH_INFO_RGCTX_SLOT_INDEX) {
7934 MonoJumpInfoRgctxEntry *e = patch_info->data.rgctx_entry;
7935
7936 if (e->info_type == MONO_RGCTX_INFO_GENERIC_METHOD_CODE)
7937 m = e->data->data.method;
7938 } else {
7939 m = patch_info->data.method;
7940 }
7941
7942 if (!m)
7943 break;
7944 if (m->is_inflated && (mono_aot_mode_is_full (&acfg->aot_opts) || mono_aot_mode_is_hybrid (&acfg->aot_opts))) {
7945 if (!(mono_class_generic_sharing_enabled (m->klass) &&
7946 mono_method_is_generic_sharable_full (m, FALSE, FALSE, FALSE)) &&
7947 (!method_has_type_vars (m) || mono_method_is_generic_sharable_full (m, TRUE, TRUE, FALSE))) {
7948 if (m->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
7949 if (mono_aot_mode_is_full (&acfg->aot_opts) && !method_has_type_vars (m))
7950 add_extra_method_with_depth (acfg, mono_marshal_get_native_wrapper (m, TRUE, TRUE), depth + 1);
7951 } else {
7952 add_extra_method_with_depth (acfg, m, depth + 1);
7953 add_types_from_method_header (acfg, m);
7954 }
7955 }
7956 add_generic_class_with_depth (acfg, m->klass, depth + 5, "method");
7957 }
7958 if (m->wrapper_type == MONO_WRAPPER_MANAGED_TO_MANAGED) {
7959 WrapperInfo *info = mono_marshal_get_wrapper_info (m);
7960
7961 if (info && info->subtype == WRAPPER_SUBTYPE_ELEMENT_ADDR)
7962 add_extra_method_with_depth (acfg, m, depth + 1);
7963 }
7964 break;
7965 }
7966 case MONO_PATCH_INFO_VTABLE: {
7967 MonoClass *klass = patch_info->data.klass;
7968
7969 if (mono_class_is_ginst (klass) && !mini_class_is_generic_sharable (klass))
7970 add_generic_class_with_depth (acfg, klass, depth + 5, "vtable");
7971 break;
7972 }
7973 case MONO_PATCH_INFO_SFLDA: {
7974 MonoClass *klass = patch_info->data.field->parent;
7975
7976 /* The .cctor needs to run at runtime. */
7977 if (mono_class_is_ginst (klass) && !mono_generic_context_is_sharable_full (&mono_class_get_generic_class (klass)->context, FALSE, FALSE) && mono_class_get_cctor (klass))
7978 add_extra_method_with_depth (acfg, mono_class_get_cctor (klass), depth + 1);
7979 break;
7980 }
7981 default:
7982 break;
7983 }
7984 }
7985 }
7986
7987 /* Determine whenever the method has GOT slots */
7988 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
7989 switch (patch_info->type) {
7990 case MONO_PATCH_INFO_GOT_OFFSET:
7991 case MONO_PATCH_INFO_NONE:
7992 case MONO_PATCH_INFO_GC_CARD_TABLE_ADDR:
7993 case MONO_PATCH_INFO_GC_NURSERY_START:
7994 case MONO_PATCH_INFO_GC_NURSERY_BITS:
7995 break;
7996 case MONO_PATCH_INFO_IMAGE:
7997 /* The assembly is stored in GOT slot 0 */
7998 if (patch_info->data.image != acfg->image)
7999 cfg->has_got_slots = TRUE;
8000 break;
8001 default:
8002 if (!is_plt_patch (patch_info) || (cfg->compile_llvm && acfg->aot_opts.llvm_only))
8003 cfg->has_got_slots = TRUE;
8004 break;
8005 }
8006 }
8007
8008 if (!cfg->has_got_slots)
8009 mono_atomic_inc_i32 (&acfg->stats.methods_without_got_slots);
8010
8011 /* Add gsharedvt wrappers for signatures used by the method */
8012 if (acfg->aot_opts.llvm_only) {
8013 GSList *l;
8014
8015 if (!cfg->method->wrapper_type || cfg->method->wrapper_type == MONO_WRAPPER_DELEGATE_INVOKE)
8016 /* These only need out wrappers */
8017 add_gsharedvt_wrappers (acfg, mono_method_signature (cfg->method), FALSE, TRUE);
8018
8019 for (l = cfg->signatures; l; l = l->next) {
8020 MonoMethodSignature *sig = mono_metadata_signature_dup ((MonoMethodSignature*)l->data);
8021
8022 /* These only need in wrappers */
8023 add_gsharedvt_wrappers (acfg, sig, TRUE, FALSE);
8024 }
8025 }
8026
8027 /*
8028 * FIXME: Instead of this mess, allocate the patches from the aot mempool.
8029 */
8030 /* Make a copy of the patch info which is in the mempool */
8031 {
8032 MonoJumpInfo *patches = NULL, *patches_end = NULL;
8033
8034 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
8035 MonoJumpInfo *new_patch_info = mono_patch_info_dup_mp (acfg->mempool, patch_info);
8036
8037 if (!patches)
8038 patches = new_patch_info;
8039 else
8040 patches_end->next = new_patch_info;
8041 patches_end = new_patch_info;
8042 }
8043 cfg->patch_info = patches;
8044 }
8045 /* Make a copy of the unwind info */
8046 {
8047 GSList *l, *unwind_ops;
8048 MonoUnwindOp *op;
8049
8050 unwind_ops = NULL;
8051 for (l = cfg->unwind_ops; l; l = l->next) {
8052 op = (MonoUnwindOp *)mono_mempool_alloc (acfg->mempool, sizeof (MonoUnwindOp));
8053 memcpy (op, l->data, sizeof (MonoUnwindOp));
8054 unwind_ops = g_slist_prepend_mempool (acfg->mempool, unwind_ops, op);
8055 }
8056 cfg->unwind_ops = g_slist_reverse (unwind_ops);
8057 }
8058 /* Make a copy of the argument/local info */
8059 {
8060 MonoError error;
8061 MonoInst **args, **locals;
8062 MonoMethodSignature *sig;
8063 MonoMethodHeader *header;
8064 int i;
8065
8066 sig = mono_method_signature (method);
8067 args = (MonoInst **)mono_mempool_alloc (acfg->mempool, sizeof (MonoInst*) * (sig->param_count + sig->hasthis));
8068 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
8069 args [i] = (MonoInst *)mono_mempool_alloc (acfg->mempool, sizeof (MonoInst));
8070 memcpy (args [i], cfg->args [i], sizeof (MonoInst));
8071 }
8072 cfg->args = args;
8073
8074 header = mono_method_get_header_checked (method, &error);
8075 mono_error_assert_ok (&error); /* FIXME don't swallow the error */
8076 locals = (MonoInst **)mono_mempool_alloc (acfg->mempool, sizeof (MonoInst*) * header->num_locals);
8077 for (i = 0; i < header->num_locals; ++i) {
8078 locals [i] = (MonoInst *)mono_mempool_alloc (acfg->mempool, sizeof (MonoInst));
8079 memcpy (locals [i], cfg->locals [i], sizeof (MonoInst));
8080 }
8081 mono_metadata_free_mh (header);
8082 cfg->locals = locals;
8083 }
8084
8085 /* Free some fields used by cfg to conserve memory */
8086 mono_empty_compile (cfg);
8087
8088 //printf ("Compile: %s\n", mono_method_full_name (method, TRUE));
8089
8090 while (index >= acfg->cfgs_size) {
8091 MonoCompile **new_cfgs;
8092 int new_size;
8093
8094 new_size = acfg->cfgs_size * 2;
8095 new_cfgs = g_new0 (MonoCompile*, new_size);
8096 memcpy (new_cfgs, acfg->cfgs, sizeof (MonoCompile*) * acfg->cfgs_size);
8097 g_free (acfg->cfgs);
8098 acfg->cfgs = new_cfgs;
8099 acfg->cfgs_size = new_size;
8100 }
8101 acfg->cfgs [index] = cfg;
8102
8103 g_hash_table_insert (acfg->method_to_cfg, cfg->orig_method, cfg);
8104
8105 /* Update global stats while holding a lock. */
8106 mono_update_jit_stats (cfg);
8107
8108 /*
8109 if (cfg->orig_method->wrapper_type)
8110 g_ptr_array_add (acfg->extra_methods, cfg->orig_method);
8111 */
8112
8113 mono_acfg_unlock (acfg);
8114
8115 mono_atomic_inc_i32 (&acfg->stats.ccount);
8116 }
8117
8118 static mono_thread_start_return_t WINAPI
compile_thread_main(gpointer user_data)8119 compile_thread_main (gpointer user_data)
8120 {
8121 MonoAotCompile *acfg = ((MonoAotCompile **)user_data) [0];
8122 GPtrArray *methods = ((GPtrArray **)user_data) [1];
8123 int i;
8124
8125 MonoError error;
8126 MonoInternalThread *internal = mono_thread_internal_current ();
8127 MonoString *str = mono_string_new_checked (mono_domain_get (), "AOT compiler", &error);
8128 mono_error_assert_ok (&error);
8129 mono_thread_set_name_internal (internal, str, TRUE, FALSE, &error);
8130 mono_error_assert_ok (&error);
8131
8132 for (i = 0; i < methods->len; ++i)
8133 compile_method (acfg, (MonoMethod *)g_ptr_array_index (methods, i));
8134
8135 return 0;
8136 }
8137
8138 /* Used by the LLVM backend */
8139 guint32
mono_aot_get_got_offset(MonoJumpInfo * ji)8140 mono_aot_get_got_offset (MonoJumpInfo *ji)
8141 {
8142 return get_got_offset (llvm_acfg, TRUE, ji);
8143 }
8144
8145 /*
8146 * mono_aot_is_shared_got_offset:
8147 *
8148 * Return whenever OFFSET refers to a GOT slot which is preinitialized
8149 * when the AOT image is loaded.
8150 */
8151 gboolean
mono_aot_is_shared_got_offset(int offset)8152 mono_aot_is_shared_got_offset (int offset)
8153 {
8154 return offset < llvm_acfg->nshared_got_entries;
8155 }
8156
8157 char*
mono_aot_get_method_name(MonoCompile * cfg)8158 mono_aot_get_method_name (MonoCompile *cfg)
8159 {
8160 if (llvm_acfg->aot_opts.static_link)
8161 /* Include the assembly name too to avoid duplicate symbol errors */
8162 return g_strdup_printf ("%s_%s", llvm_acfg->assembly_name_sym, get_debug_sym (cfg->orig_method, "", llvm_acfg->method_label_hash));
8163 else
8164 return get_debug_sym (cfg->orig_method, "", llvm_acfg->method_label_hash);
8165 }
8166
8167 /*
8168 * mono_aot_is_linkonce_method:
8169 *
8170 * Return whenever METHOD should be emitted with linkonce linkage,
8171 * eliminating duplicate copies when compiling in static mode.
8172 */
8173 gboolean
mono_aot_is_linkonce_method(MonoMethod * method)8174 mono_aot_is_linkonce_method (MonoMethod *method)
8175 {
8176 return FALSE;
8177 #if 0
8178 WrapperInfo *info;
8179
8180 // FIXME: Add more cases
8181 if (method->wrapper_type != MONO_WRAPPER_UNKNOWN)
8182 return FALSE;
8183 info = mono_marshal_get_wrapper_info (method);
8184 if ((info && (info->subtype == WRAPPER_SUBTYPE_GSHAREDVT_IN_SIG || info->subtype == WRAPPER_SUBTYPE_GSHAREDVT_OUT_SIG)))
8185 return TRUE;
8186 return FALSE;
8187 #endif
8188 }
8189
8190 static gboolean
append_mangled_type(GString * s,MonoType * t)8191 append_mangled_type (GString *s, MonoType *t)
8192 {
8193 if (t->byref)
8194 g_string_append_printf (s, "b");
8195 switch (t->type) {
8196 case MONO_TYPE_VOID:
8197 g_string_append_printf (s, "void_");
8198 break;
8199 case MONO_TYPE_I1:
8200 g_string_append_printf (s, "i1");
8201 break;
8202 case MONO_TYPE_U1:
8203 g_string_append_printf (s, "u1");
8204 break;
8205 case MONO_TYPE_I2:
8206 g_string_append_printf (s, "i2");
8207 break;
8208 case MONO_TYPE_U2:
8209 g_string_append_printf (s, "u2");
8210 break;
8211 case MONO_TYPE_I4:
8212 g_string_append_printf (s, "i4");
8213 break;
8214 case MONO_TYPE_U4:
8215 g_string_append_printf (s, "u4");
8216 break;
8217 case MONO_TYPE_I8:
8218 g_string_append_printf (s, "i8");
8219 break;
8220 case MONO_TYPE_U8:
8221 g_string_append_printf (s, "u8");
8222 break;
8223 case MONO_TYPE_I:
8224 g_string_append_printf (s, "ii");
8225 break;
8226 case MONO_TYPE_U:
8227 g_string_append_printf (s, "ui");
8228 break;
8229 case MONO_TYPE_R4:
8230 g_string_append_printf (s, "fl");
8231 break;
8232 case MONO_TYPE_R8:
8233 g_string_append_printf (s, "do");
8234 break;
8235 default: {
8236 char *fullname = mono_type_full_name (t);
8237 GString *temp;
8238 char *temps;
8239 int i, len;
8240
8241 /*
8242 * Have to create a mangled name which is:
8243 * - a valid symbol
8244 * - unique
8245 */
8246 temp = g_string_new ("");
8247 len = strlen (fullname);
8248 for (i = 0; i < len; ++i) {
8249 char c = fullname [i];
8250 if (isalnum (c)) {
8251 g_string_append_c (temp, c);
8252 } else if (c == '_') {
8253 g_string_append_c (temp, '_');
8254 g_string_append_c (temp, '_');
8255 } else {
8256 g_string_append_c (temp, '_');
8257 g_string_append_printf (temp, "%x", (int)c);
8258 }
8259 }
8260 temps = g_string_free (temp, FALSE);
8261 /* Include the length to avoid different length type names aliasing each other */
8262 g_string_append_printf (s, "cl%x_%s_", strlen (temps), temps);
8263 g_free (temps);
8264 }
8265 }
8266 if (t->attrs)
8267 g_string_append_printf (s, "_attrs_%d", t->attrs);
8268 return TRUE;
8269 }
8270
8271 static gboolean
append_mangled_signature(GString * s,MonoMethodSignature * sig)8272 append_mangled_signature (GString *s, MonoMethodSignature *sig)
8273 {
8274 int i;
8275 gboolean supported;
8276
8277 supported = append_mangled_type (s, sig->ret);
8278 if (!supported)
8279 return FALSE;
8280 if (sig->hasthis)
8281 g_string_append_printf (s, "this_");
8282 if (sig->pinvoke)
8283 g_string_append_printf (s, "pinvoke_");
8284 for (i = 0; i < sig->param_count; ++i) {
8285 supported = append_mangled_type (s, sig->params [i]);
8286 if (!supported)
8287 return FALSE;
8288 }
8289
8290 return TRUE;
8291 }
8292
8293 static void
append_mangled_wrapper_type(GString * s,guint32 wrapper_type)8294 append_mangled_wrapper_type (GString *s, guint32 wrapper_type)
8295 {
8296 const char *label;
8297
8298 switch (wrapper_type) {
8299 case MONO_WRAPPER_REMOTING_INVOKE:
8300 label = "remoting_invoke";
8301 break;
8302 case MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK:
8303 label = "remoting_invoke_check";
8304 break;
8305 case MONO_WRAPPER_XDOMAIN_INVOKE:
8306 label = "remoting_invoke_xdomain";
8307 break;
8308 case MONO_WRAPPER_PROXY_ISINST:
8309 label = "proxy_isinst";
8310 break;
8311 case MONO_WRAPPER_LDFLD:
8312 label = "ldfld";
8313 break;
8314 case MONO_WRAPPER_LDFLDA:
8315 label = "ldflda";
8316 break;
8317 case MONO_WRAPPER_STFLD:
8318 label = "stfld";
8319 break;
8320 case MONO_WRAPPER_ALLOC:
8321 label = "alloc";
8322 break;
8323 case MONO_WRAPPER_WRITE_BARRIER:
8324 label = "write_barrier";
8325 break;
8326 case MONO_WRAPPER_STELEMREF:
8327 label = "stelemref";
8328 break;
8329 case MONO_WRAPPER_UNKNOWN:
8330 label = "unknown";
8331 break;
8332 case MONO_WRAPPER_MANAGED_TO_NATIVE:
8333 label = "man2native";
8334 break;
8335 case MONO_WRAPPER_SYNCHRONIZED:
8336 label = "synch";
8337 break;
8338 case MONO_WRAPPER_MANAGED_TO_MANAGED:
8339 label = "man2man";
8340 break;
8341 case MONO_WRAPPER_CASTCLASS:
8342 label = "castclass";
8343 break;
8344 case MONO_WRAPPER_RUNTIME_INVOKE:
8345 label = "run_invoke";
8346 break;
8347 case MONO_WRAPPER_DELEGATE_INVOKE:
8348 label = "del_inv";
8349 break;
8350 case MONO_WRAPPER_DELEGATE_BEGIN_INVOKE:
8351 label = "del_beg_inv";
8352 break;
8353 case MONO_WRAPPER_DELEGATE_END_INVOKE:
8354 label = "del_end_inv";
8355 break;
8356 case MONO_WRAPPER_NATIVE_TO_MANAGED:
8357 label = "native2man";
8358 break;
8359 default:
8360 g_assert_not_reached ();
8361 }
8362
8363 g_string_append_printf (s, "%s_", label);
8364 }
8365
8366 static void
append_mangled_wrapper_subtype(GString * s,WrapperSubtype subtype)8367 append_mangled_wrapper_subtype (GString *s, WrapperSubtype subtype)
8368 {
8369 const char *label;
8370
8371 switch (subtype)
8372 {
8373 case WRAPPER_SUBTYPE_NONE:
8374 return;
8375 case WRAPPER_SUBTYPE_ELEMENT_ADDR:
8376 label = "elem_addr";
8377 break;
8378 case WRAPPER_SUBTYPE_STRING_CTOR:
8379 label = "str_ctor";
8380 break;
8381 case WRAPPER_SUBTYPE_VIRTUAL_STELEMREF:
8382 label = "virt_stelem";
8383 break;
8384 case WRAPPER_SUBTYPE_FAST_MONITOR_ENTER:
8385 label = "fast_mon_enter";
8386 break;
8387 case WRAPPER_SUBTYPE_FAST_MONITOR_ENTER_V4:
8388 label = "fast_mon_enter_4";
8389 break;
8390 case WRAPPER_SUBTYPE_FAST_MONITOR_EXIT:
8391 label = "fast_monitor_exit";
8392 break;
8393 case WRAPPER_SUBTYPE_PTR_TO_STRUCTURE:
8394 label = "ptr2struct";
8395 break;
8396 case WRAPPER_SUBTYPE_STRUCTURE_TO_PTR:
8397 label = "struct2ptr";
8398 break;
8399 case WRAPPER_SUBTYPE_CASTCLASS_WITH_CACHE:
8400 label = "castclass_w_cache";
8401 break;
8402 case WRAPPER_SUBTYPE_ISINST_WITH_CACHE:
8403 label = "isinst_w_cache";
8404 break;
8405 case WRAPPER_SUBTYPE_RUNTIME_INVOKE_NORMAL:
8406 label = "run_inv_norm";
8407 break;
8408 case WRAPPER_SUBTYPE_RUNTIME_INVOKE_DYNAMIC:
8409 label = "run_inv_dyn";
8410 break;
8411 case WRAPPER_SUBTYPE_RUNTIME_INVOKE_DIRECT:
8412 label = "run_inv_dir";
8413 break;
8414 case WRAPPER_SUBTYPE_RUNTIME_INVOKE_VIRTUAL:
8415 label = "run_inv_vir";
8416 break;
8417 case WRAPPER_SUBTYPE_ICALL_WRAPPER:
8418 label = "icall";
8419 break;
8420 case WRAPPER_SUBTYPE_NATIVE_FUNC_AOT:
8421 label = "native_func_aot";
8422 break;
8423 case WRAPPER_SUBTYPE_PINVOKE:
8424 label = "pinvoke";
8425 break;
8426 case WRAPPER_SUBTYPE_SYNCHRONIZED_INNER:
8427 label = "synch_inner";
8428 break;
8429 case WRAPPER_SUBTYPE_GSHAREDVT_IN:
8430 label = "gshared_in";
8431 break;
8432 case WRAPPER_SUBTYPE_GSHAREDVT_OUT:
8433 label = "gshared_out";
8434 break;
8435 case WRAPPER_SUBTYPE_ARRAY_ACCESSOR:
8436 label = "array_acc";
8437 break;
8438 case WRAPPER_SUBTYPE_GENERIC_ARRAY_HELPER:
8439 label = "generic_arry_help";
8440 break;
8441 case WRAPPER_SUBTYPE_DELEGATE_INVOKE_VIRTUAL:
8442 label = "del_inv_virt";
8443 break;
8444 case WRAPPER_SUBTYPE_DELEGATE_INVOKE_BOUND:
8445 label = "del_inv_bound";
8446 break;
8447 case WRAPPER_SUBTYPE_INTERP_IN:
8448 label = "interp_in";
8449 break;
8450 case WRAPPER_SUBTYPE_GSHAREDVT_IN_SIG:
8451 label = "gsharedvt_in_sig";
8452 break;
8453 case WRAPPER_SUBTYPE_GSHAREDVT_OUT_SIG:
8454 label = "gsharedvt_out_sig";
8455 break;
8456 default:
8457 g_assert_not_reached ();
8458 }
8459
8460 g_string_append_printf (s, "%s_", label);
8461 }
8462
8463 static char *
sanitize_mangled_string(const char * input)8464 sanitize_mangled_string (const char *input)
8465 {
8466 GString *s = g_string_new ("");
8467
8468 for (int i=0; input [i] != '\0'; i++) {
8469 char c = input [i];
8470 switch (c) {
8471 case '.':
8472 g_string_append (s, "_dot_");
8473 break;
8474 case ' ':
8475 g_string_append (s, "_");
8476 break;
8477 case '`':
8478 g_string_append (s, "_bt_");
8479 break;
8480 case '<':
8481 g_string_append (s, "_le_");
8482 break;
8483 case '>':
8484 g_string_append (s, "_gt_");
8485 break;
8486 case '/':
8487 g_string_append (s, "_sl_");
8488 break;
8489 case '[':
8490 g_string_append (s, "_lbrack_");
8491 break;
8492 case ']':
8493 g_string_append (s, "_rbrack_");
8494 break;
8495 case '(':
8496 g_string_append (s, "_lparen_");
8497 break;
8498 case '-':
8499 g_string_append (s, "_dash_");
8500 break;
8501 case ')':
8502 g_string_append (s, "_rparen_");
8503 break;
8504 case ',':
8505 g_string_append (s, "_comma_");
8506 break;
8507 case ':':
8508 g_string_append (s, "_colon_");
8509 break;
8510 default:
8511 g_string_append_c (s, c);
8512 }
8513 }
8514
8515 return g_string_free (s, FALSE);
8516 }
8517
8518 static gboolean
append_mangled_klass(GString * s,MonoClass * klass)8519 append_mangled_klass (GString *s, MonoClass *klass)
8520 {
8521 char *klass_desc = mono_class_full_name (klass);
8522 g_string_append_printf (s, "_%s_%s_", klass->name_space, klass_desc);
8523 g_free (klass_desc);
8524
8525 // Success
8526 return TRUE;
8527 }
8528
8529 static gboolean
8530 append_mangled_method (GString *s, MonoMethod *method);
8531
8532 static gboolean
append_mangled_wrapper(GString * s,MonoMethod * method)8533 append_mangled_wrapper (GString *s, MonoMethod *method)
8534 {
8535 gboolean success = TRUE;
8536 WrapperInfo *info = mono_marshal_get_wrapper_info (method);
8537 g_string_append_printf (s, "wrapper_");
8538 g_string_append_printf (s, "%s_", method->klass->image->assembly->aname.name);
8539
8540 append_mangled_wrapper_type (s, method->wrapper_type);
8541
8542 switch (method->wrapper_type) {
8543 case MONO_WRAPPER_REMOTING_INVOKE:
8544 case MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK:
8545 case MONO_WRAPPER_XDOMAIN_INVOKE: {
8546 MonoMethod *m = mono_marshal_method_from_wrapper (method);
8547 g_assert (m);
8548 success = success && append_mangled_method (s, m);
8549 break;
8550 }
8551 case MONO_WRAPPER_PROXY_ISINST:
8552 case MONO_WRAPPER_LDFLD:
8553 case MONO_WRAPPER_LDFLDA:
8554 case MONO_WRAPPER_STFLD: {
8555 g_assert (info);
8556 success = success && append_mangled_klass (s, info->d.proxy.klass);
8557 break;
8558 }
8559 case MONO_WRAPPER_ALLOC: {
8560 /* The GC name is saved once in MonoAotFileInfo */
8561 g_assert (info->d.alloc.alloc_type != -1);
8562 g_string_append_printf (s, "%d_", info->d.alloc.alloc_type);
8563 // SlowAlloc, etc
8564 g_string_append_printf (s, "%s_", method->name);
8565 break;
8566 }
8567 case MONO_WRAPPER_WRITE_BARRIER: {
8568 g_string_append_printf (s, "%s_", method->name);
8569 break;
8570 }
8571 case MONO_WRAPPER_STELEMREF: {
8572 append_mangled_wrapper_subtype (s, info->subtype);
8573 if (info->subtype == WRAPPER_SUBTYPE_VIRTUAL_STELEMREF)
8574 g_string_append_printf (s, "%d", info->d.virtual_stelemref.kind);
8575 break;
8576 }
8577 case MONO_WRAPPER_UNKNOWN: {
8578 append_mangled_wrapper_subtype (s, info->subtype);
8579 if (info->subtype == WRAPPER_SUBTYPE_PTR_TO_STRUCTURE ||
8580 info->subtype == WRAPPER_SUBTYPE_STRUCTURE_TO_PTR)
8581 success = success && append_mangled_klass (s, method->klass);
8582 else if (info->subtype == WRAPPER_SUBTYPE_SYNCHRONIZED_INNER)
8583 success = success && append_mangled_method (s, info->d.synchronized_inner.method);
8584 else if (info->subtype == WRAPPER_SUBTYPE_ARRAY_ACCESSOR)
8585 success = success && append_mangled_method (s, info->d.array_accessor.method);
8586 else if (info->subtype == WRAPPER_SUBTYPE_INTERP_IN)
8587 append_mangled_signature (s, info->d.interp_in.sig);
8588 else if (info->subtype == WRAPPER_SUBTYPE_GSHAREDVT_IN_SIG)
8589 append_mangled_signature (s, info->d.gsharedvt.sig);
8590 else if (info->subtype == WRAPPER_SUBTYPE_GSHAREDVT_OUT_SIG)
8591 append_mangled_signature (s, info->d.gsharedvt.sig);
8592 break;
8593 }
8594 case MONO_WRAPPER_MANAGED_TO_NATIVE: {
8595 append_mangled_wrapper_subtype (s, info->subtype);
8596 if (info->subtype == WRAPPER_SUBTYPE_ICALL_WRAPPER) {
8597 g_string_append_printf (s, "%s", method->name);
8598 } else if (info->subtype == WRAPPER_SUBTYPE_NATIVE_FUNC_AOT) {
8599 success = success && append_mangled_method (s, info->d.managed_to_native.method);
8600 } else {
8601 g_assert (info->subtype == WRAPPER_SUBTYPE_NONE || info->subtype == WRAPPER_SUBTYPE_PINVOKE);
8602 success = success && append_mangled_method (s, info->d.managed_to_native.method);
8603 }
8604 break;
8605 }
8606 case MONO_WRAPPER_SYNCHRONIZED: {
8607 MonoMethod *m;
8608
8609 m = mono_marshal_method_from_wrapper (method);
8610 g_assert (m);
8611 g_assert (m != method);
8612 success = success && append_mangled_method (s, m);
8613 break;
8614 }
8615 case MONO_WRAPPER_MANAGED_TO_MANAGED: {
8616 append_mangled_wrapper_subtype (s, info->subtype);
8617
8618 if (info->subtype == WRAPPER_SUBTYPE_ELEMENT_ADDR) {
8619 g_string_append_printf (s, "%d_", info->d.element_addr.rank);
8620 g_string_append_printf (s, "%d_", info->d.element_addr.elem_size);
8621 } else if (info->subtype == WRAPPER_SUBTYPE_STRING_CTOR) {
8622 success = success && append_mangled_method (s, info->d.string_ctor.method);
8623 } else if (info->subtype == WRAPPER_SUBTYPE_GENERIC_ARRAY_HELPER) {
8624 success = success && append_mangled_method (s, info->d.generic_array_helper.method);
8625 } else {
8626 success = FALSE;
8627 }
8628 break;
8629 }
8630 case MONO_WRAPPER_CASTCLASS: {
8631 append_mangled_wrapper_subtype (s, info->subtype);
8632 break;
8633 }
8634 case MONO_WRAPPER_RUNTIME_INVOKE: {
8635 append_mangled_wrapper_subtype (s, info->subtype);
8636 if (info->subtype == WRAPPER_SUBTYPE_RUNTIME_INVOKE_DIRECT || info->subtype == WRAPPER_SUBTYPE_RUNTIME_INVOKE_VIRTUAL)
8637 success = success && append_mangled_method (s, info->d.runtime_invoke.method);
8638 else if (info->subtype == WRAPPER_SUBTYPE_RUNTIME_INVOKE_NORMAL)
8639 success = success && append_mangled_signature (s, info->d.runtime_invoke.sig);
8640 break;
8641 }
8642 case MONO_WRAPPER_DELEGATE_INVOKE:
8643 case MONO_WRAPPER_DELEGATE_BEGIN_INVOKE:
8644 case MONO_WRAPPER_DELEGATE_END_INVOKE: {
8645 if (method->is_inflated) {
8646 /* These wrappers are identified by their class */
8647 g_string_append_printf (s, "i_");
8648 success = success && append_mangled_klass (s, method->klass);
8649 } else {
8650 WrapperInfo *info = mono_marshal_get_wrapper_info (method);
8651
8652 g_string_append_printf (s, "u_");
8653 if (method->wrapper_type == MONO_WRAPPER_DELEGATE_INVOKE)
8654 append_mangled_wrapper_subtype (s, info->subtype);
8655 g_string_append_printf (s, "u_sigstart");
8656 }
8657 break;
8658 }
8659 case MONO_WRAPPER_NATIVE_TO_MANAGED: {
8660 g_assert (info);
8661 success = success && append_mangled_method (s, info->d.native_to_managed.method);
8662 success = success && append_mangled_klass (s, method->klass);
8663 break;
8664 }
8665 default:
8666 g_assert_not_reached ();
8667 }
8668 return success && append_mangled_signature (s, mono_method_signature (method));
8669 }
8670
8671 static void
append_mangled_ginst(GString * str,MonoGenericInst * ginst)8672 append_mangled_ginst (GString *str, MonoGenericInst *ginst)
8673 {
8674 int i;
8675
8676 for (i = 0; i < ginst->type_argc; ++i) {
8677 if (i > 0)
8678 g_string_append (str, ", ");
8679 MonoType *type = ginst->type_argv [i];
8680 switch (type->type) {
8681 case MONO_TYPE_VAR:
8682 case MONO_TYPE_MVAR: {
8683 MonoType *constraint = NULL;
8684 if (type->data.generic_param)
8685 constraint = type->data.generic_param->gshared_constraint;
8686 if (constraint) {
8687 g_assert (constraint->type != MONO_TYPE_VAR && constraint->type != MONO_TYPE_MVAR);
8688 g_string_append (str, "gshared:");
8689 mono_type_get_desc (str, constraint, TRUE);
8690 break;
8691 }
8692 // Else falls through to common case
8693 }
8694 default:
8695 mono_type_get_desc (str, type, TRUE);
8696 }
8697 }
8698 }
8699
8700 static void
append_mangled_context(GString * str,MonoGenericContext * context)8701 append_mangled_context (GString *str, MonoGenericContext *context)
8702 {
8703 GString *res = g_string_new ("");
8704
8705 g_string_append_printf (res, "gens_");
8706 g_string_append (res, "00");
8707
8708 gboolean good = context->class_inst && context->class_inst->type_argc > 0;
8709 good = good || (context->method_inst && context->method_inst->type_argc > 0);
8710 g_assert (good);
8711
8712 if (context->class_inst)
8713 append_mangled_ginst (res, context->class_inst);
8714 if (context->method_inst) {
8715 if (context->class_inst)
8716 g_string_append (res, "11");
8717 append_mangled_ginst (res, context->method_inst);
8718 }
8719 g_string_append_printf (str, "gens_%s", res->str);
8720 g_free (res);
8721 }
8722
8723 static gboolean
append_mangled_method(GString * s,MonoMethod * method)8724 append_mangled_method (GString *s, MonoMethod *method)
8725 {
8726 if (method->wrapper_type)
8727 return append_mangled_wrapper (s, method);
8728
8729 if (method->is_inflated) {
8730 g_string_append_printf (s, "inflated_");
8731 MonoMethodInflated *imethod = (MonoMethodInflated*) method;
8732 g_assert (imethod->context.class_inst != NULL || imethod->context.method_inst != NULL);
8733
8734 append_mangled_context (s, &imethod->context);
8735 g_string_append_printf (s, "_declared_by_");
8736 append_mangled_method (s, imethod->declaring);
8737 } else if (method->is_generic) {
8738 g_string_append_printf (s, "%s_", method->klass->image->assembly->aname.name);
8739
8740 g_string_append_printf (s, "generic_");
8741 append_mangled_klass (s, method->klass);
8742 g_string_append_printf (s, "_%s_", method->name);
8743
8744 MonoGenericContainer *container = mono_method_get_generic_container (method);
8745 g_string_append_printf (s, "_%s");
8746 append_mangled_context (s, &container->context);
8747
8748 return append_mangled_signature (s, mono_method_signature (method));
8749 } else {
8750 g_string_append_printf (s, "_");
8751 append_mangled_klass (s, method->klass);
8752 g_string_append_printf (s, "_%s_", method->name);
8753 if (!append_mangled_signature (s, mono_method_signature (method))) {
8754 g_string_free (s, TRUE);
8755 return FALSE;
8756 }
8757 }
8758
8759 return TRUE;
8760 }
8761
8762 /*
8763 * mono_aot_get_mangled_method_name:
8764 *
8765 * Return a unique mangled name for METHOD, or NULL.
8766 */
8767 char*
mono_aot_get_mangled_method_name(MonoMethod * method)8768 mono_aot_get_mangled_method_name (MonoMethod *method)
8769 {
8770 // FIXME: use static cache (mempool?)
8771 // We call this a *lot*
8772
8773 GString *s = g_string_new ("aot_");
8774 if (!append_mangled_method (s, method)) {
8775 g_string_free (s, TRUE);
8776 return NULL;
8777 } else {
8778 char *out = g_string_free (s, FALSE);
8779 // Scrub method and class names
8780 char *cleaned = sanitize_mangled_string (out);
8781 g_free (out);
8782 return cleaned;
8783 }
8784 }
8785
8786 gboolean
mono_aot_is_direct_callable(MonoJumpInfo * patch_info)8787 mono_aot_is_direct_callable (MonoJumpInfo *patch_info)
8788 {
8789 return is_direct_callable (llvm_acfg, NULL, patch_info);
8790 }
8791
8792 void
mono_aot_mark_unused_llvm_plt_entry(MonoJumpInfo * patch_info)8793 mono_aot_mark_unused_llvm_plt_entry (MonoJumpInfo *patch_info)
8794 {
8795 MonoPltEntry *plt_entry;
8796
8797 plt_entry = get_plt_entry (llvm_acfg, patch_info);
8798 plt_entry->llvm_used = FALSE;
8799 }
8800
8801 char*
mono_aot_get_direct_call_symbol(MonoJumpInfoType type,gconstpointer data)8802 mono_aot_get_direct_call_symbol (MonoJumpInfoType type, gconstpointer data)
8803 {
8804 const char *sym = NULL;
8805
8806 if (llvm_acfg->aot_opts.direct_icalls) {
8807 if (type == MONO_PATCH_INFO_JIT_ICALL_ADDR) {
8808 /* Call to a C function implementing a jit icall */
8809 sym = mono_lookup_jit_icall_symbol ((const char *)data);
8810 } else if (type == MONO_PATCH_INFO_ICALL_ADDR_CALL) {
8811 MonoMethod *method = (MonoMethod *)data;
8812 if (!(method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL))
8813 sym = mono_lookup_icall_symbol (method);
8814 else if (llvm_acfg->aot_opts.direct_pinvoke)
8815 sym = get_pinvoke_import (llvm_acfg, method);
8816 }
8817 if (sym)
8818 return g_strdup (sym);
8819 }
8820 return NULL;
8821 }
8822
8823 char*
mono_aot_get_plt_symbol(MonoJumpInfoType type,gconstpointer data)8824 mono_aot_get_plt_symbol (MonoJumpInfoType type, gconstpointer data)
8825 {
8826 MonoJumpInfo *ji = (MonoJumpInfo *)mono_mempool_alloc (llvm_acfg->mempool, sizeof (MonoJumpInfo));
8827 MonoPltEntry *plt_entry;
8828 const char *sym = NULL;
8829
8830 ji->type = type;
8831 ji->data.target = data;
8832
8833 if (!can_encode_patch (llvm_acfg, ji))
8834 return NULL;
8835
8836 if (llvm_acfg->aot_opts.direct_icalls) {
8837 if (type == MONO_PATCH_INFO_JIT_ICALL_ADDR) {
8838 /* Call to a C function implementing a jit icall */
8839 sym = mono_lookup_jit_icall_symbol ((const char *)data);
8840 } else if (type == MONO_PATCH_INFO_ICALL_ADDR_CALL) {
8841 MonoMethod *method = (MonoMethod *)data;
8842 if (!(method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL))
8843 sym = mono_lookup_icall_symbol (method);
8844 }
8845 if (sym)
8846 return g_strdup (sym);
8847 }
8848
8849 plt_entry = get_plt_entry (llvm_acfg, ji);
8850 plt_entry->llvm_used = TRUE;
8851
8852 #if defined(TARGET_MACH)
8853 return g_strdup_printf (plt_entry->llvm_symbol + strlen (llvm_acfg->llvm_label_prefix));
8854 #else
8855 return g_strdup_printf (plt_entry->llvm_symbol);
8856 #endif
8857 }
8858
8859 int
mono_aot_get_method_index(MonoMethod * method)8860 mono_aot_get_method_index (MonoMethod *method)
8861 {
8862 g_assert (llvm_acfg);
8863 return get_method_index (llvm_acfg, method);
8864 }
8865
8866 MonoJumpInfo*
mono_aot_patch_info_dup(MonoJumpInfo * ji)8867 mono_aot_patch_info_dup (MonoJumpInfo* ji)
8868 {
8869 MonoJumpInfo *res;
8870
8871 mono_acfg_lock (llvm_acfg);
8872 res = mono_patch_info_dup_mp (llvm_acfg->mempool, ji);
8873 mono_acfg_unlock (llvm_acfg);
8874
8875 return res;
8876 }
8877
8878 static int
execute_system(const char * command)8879 execute_system (const char * command)
8880 {
8881 int status = 0;
8882
8883 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) && defined(HOST_WIN32)
8884 // We need an extra set of quotes around the whole command to properly handle commands
8885 // with spaces since internally the command is called through "cmd /c.
8886 char * quoted_command = g_strdup_printf ("\"%s\"", command);
8887
8888 int size = MultiByteToWideChar (CP_UTF8, 0 , quoted_command , -1, NULL , 0);
8889 wchar_t* wstr = g_malloc (sizeof (wchar_t) * size);
8890 MultiByteToWideChar (CP_UTF8, 0, quoted_command, -1, wstr , size);
8891 status = _wsystem (wstr);
8892 g_free (wstr);
8893
8894 g_free (quoted_command);
8895 #elif defined (HAVE_SYSTEM)
8896 status = system (command);
8897 #else
8898 g_assert_not_reached ();
8899 #endif
8900
8901 return status;
8902 }
8903
8904 #ifdef ENABLE_LLVM
8905
8906 /*
8907 * emit_llvm_file:
8908 *
8909 * Emit the LLVM code into an LLVM bytecode file, and compile it using the LLVM
8910 * tools.
8911 */
8912 static gboolean
emit_llvm_file(MonoAotCompile * acfg)8913 emit_llvm_file (MonoAotCompile *acfg)
8914 {
8915 char *command, *opts, *tempbc, *optbc, *output_fname;
8916
8917 if (acfg->aot_opts.llvm_only && acfg->aot_opts.asm_only) {
8918 tempbc = g_strdup_printf ("%s.bc", acfg->tmpbasename);
8919 optbc = g_strdup (acfg->aot_opts.llvm_outfile);
8920 } else {
8921 tempbc = g_strdup_printf ("%s.bc", acfg->tmpbasename);
8922 optbc = g_strdup_printf ("%s.opt.bc", acfg->tmpbasename);
8923 }
8924
8925 mono_llvm_emit_aot_module (tempbc, g_path_get_basename (acfg->image->name));
8926
8927 /*
8928 * FIXME: Experiment with adding optimizations, the -std-compile-opts set takes
8929 * a lot of time, and doesn't seem to save much space.
8930 * The following optimizations cannot be enabled:
8931 * - 'tailcallelim'
8932 * - 'jump-threading' changes our blockaddress references to int constants.
8933 * - 'basiccg' fails because it contains:
8934 * if (CS && !isa<IntrinsicInst>(II)) {
8935 * and isa<IntrinsicInst> is false for invokes to intrinsics (iltests.exe).
8936 * - 'prune-eh' and 'functionattrs' depend on 'basiccg'.
8937 * The opt list below was produced by taking the output of:
8938 * llvm-as < /dev/null | opt -O2 -disable-output -debug-pass=Arguments
8939 * then removing tailcallelim + the global opts.
8940 * strip-dead-prototypes deletes unused intrinsics definitions.
8941 */
8942 /* The dse pass is disabled because of #13734 and #17616 */
8943 /*
8944 * The dse bug is in DeadStoreElimination.cpp:isOverwrite ():
8945 * // If we have no DataLayout information around, then the size of the store
8946 * // is inferrable from the pointee type. If they are the same type, then
8947 * // we know that the store is safe.
8948 * if (AA.getDataLayout() == 0 &&
8949 * Later.Ptr->getType() == Earlier.Ptr->getType()) {
8950 * return OverwriteComplete;
8951 * Here, if 'Earlier' refers to a memset, and Later has no size info, it mistakenly thinks the memset is redundant.
8952 */
8953 if (acfg->aot_opts.llvm_only)
8954 // FIXME: This doesn't work yet
8955 opts = g_strdup ("");
8956 else
8957 #if LLVM_API_VERSION > 100
8958 opts = g_strdup ("-O2 -disable-tail-calls");
8959 #else
8960 opts = g_strdup ("-targetlibinfo -no-aa -basicaa -notti -instcombine -simplifycfg -inline-cost -inline -sroa -domtree -early-cse -lazy-value-info -correlated-propagation -simplifycfg -instcombine -simplifycfg -reassociate -domtree -loops -loop-simplify -lcssa -loop-rotate -licm -lcssa -loop-unswitch -instcombine -scalar-evolution -loop-simplify -lcssa -indvars -loop-idiom -loop-deletion -loop-unroll -memdep -gvn -memdep -memcpyopt -sccp -instcombine -lazy-value-info -correlated-propagation -domtree -memdep -adce -simplifycfg -instcombine -strip-dead-prototypes -domtree -verify");
8961 #endif
8962 command = g_strdup_printf ("\"%sopt\" -f %s -o \"%s\" \"%s\"", acfg->aot_opts.llvm_path, opts, optbc, tempbc);
8963 aot_printf (acfg, "Executing opt: %s\n", command);
8964 if (execute_system (command) != 0)
8965 return FALSE;
8966 g_free (opts);
8967
8968 if (acfg->aot_opts.llvm_only && acfg->aot_opts.asm_only)
8969 /* Nothing else to do */
8970 return TRUE;
8971
8972 if (acfg->aot_opts.llvm_only) {
8973 /* Use the stock clang from xcode */
8974 // FIXME: arch
8975 command = g_strdup_printf ("clang++ -fexceptions -march=x86-64 -fpic -msse -msse2 -msse3 -msse4 -O2 -fno-optimize-sibling-calls -Wno-override-module -c -o \"%s\" \"%s.opt.bc\"", acfg->llvm_ofile, acfg->tmpbasename);
8976
8977 aot_printf (acfg, "Executing clang: %s\n", command);
8978 if (execute_system (command) != 0)
8979 return FALSE;
8980 return TRUE;
8981 }
8982
8983 if (!acfg->llc_args)
8984 acfg->llc_args = g_string_new ("");
8985
8986 /* Verbose asm slows down llc greatly */
8987 g_string_append (acfg->llc_args, " -asm-verbose=false");
8988
8989 if (acfg->aot_opts.mtriple)
8990 g_string_append_printf (acfg->llc_args, " -mtriple=%s", acfg->aot_opts.mtriple);
8991
8992 g_string_append (acfg->llc_args, " -disable-gnu-eh-frame -enable-mono-eh-frame");
8993
8994 g_string_append_printf (acfg->llc_args, " -mono-eh-frame-symbol=%s%s", acfg->user_symbol_prefix, acfg->llvm_eh_frame_symbol);
8995
8996 #if LLVM_API_VERSION > 100
8997 g_string_append_printf (acfg->llc_args, " -disable-tail-calls");
8998 #endif
8999
9000 #if ( defined(TARGET_MACH) && defined(TARGET_ARM) ) || defined(TARGET_ORBIS)
9001 /* ios requires PIC code now */
9002 g_string_append_printf (acfg->llc_args, " -relocation-model=pic");
9003 #else
9004 if (llvm_acfg->aot_opts.static_link)
9005 g_string_append_printf (acfg->llc_args, " -relocation-model=static");
9006 else
9007 g_string_append_printf (acfg->llc_args, " -relocation-model=pic");
9008 #endif
9009
9010 if (acfg->llvm_owriter) {
9011 /* Emit an object file directly */
9012 output_fname = g_strdup_printf ("%s", acfg->llvm_ofile);
9013 g_string_append_printf (acfg->llc_args, " -filetype=obj");
9014 } else {
9015 output_fname = g_strdup_printf ("%s", acfg->llvm_sfile);
9016 }
9017 command = g_strdup_printf ("\"%sllc\" %s -o \"%s\" \"%s.opt.bc\"", acfg->aot_opts.llvm_path, acfg->llc_args->str, output_fname, acfg->tmpbasename);
9018 g_free (output_fname);
9019
9020 aot_printf (acfg, "Executing llc: %s\n", command);
9021
9022 if (execute_system (command) != 0)
9023 return FALSE;
9024 return TRUE;
9025 }
9026 #endif
9027
9028 static void
emit_code(MonoAotCompile * acfg)9029 emit_code (MonoAotCompile *acfg)
9030 {
9031 int oindex, i, prev_index;
9032 gboolean saved_unbox_info = FALSE;
9033 char symbol [MAX_SYMBOL_SIZE];
9034
9035 if (acfg->aot_opts.llvm_only)
9036 return;
9037
9038 #if defined(TARGET_POWERPC64)
9039 sprintf (symbol, ".Lgot_addr");
9040 emit_section_change (acfg, ".text", 0);
9041 emit_alignment (acfg, 8);
9042 emit_label (acfg, symbol);
9043 emit_pointer (acfg, acfg->got_symbol);
9044 #endif
9045
9046 /*
9047 * This global symbol is used to compute the address of each method using the
9048 * code_offsets array. It is also used to compute the memory ranges occupied by
9049 * AOT code, so it must be equal to the address of the first emitted method.
9050 */
9051 emit_section_change (acfg, ".text", 0);
9052 emit_alignment_code (acfg, 8);
9053 emit_info_symbol (acfg, "jit_code_start");
9054
9055 /*
9056 * Emit some padding so the local symbol for the first method doesn't have the
9057 * same address as 'methods'.
9058 */
9059 emit_padding (acfg, 16);
9060
9061 for (oindex = 0; oindex < acfg->method_order->len; ++oindex) {
9062 MonoCompile *cfg;
9063 MonoMethod *method;
9064
9065 i = GPOINTER_TO_UINT (g_ptr_array_index (acfg->method_order, oindex));
9066
9067 cfg = acfg->cfgs [i];
9068
9069 if (!cfg)
9070 continue;
9071
9072 method = cfg->orig_method;
9073
9074 gboolean dedup_collect = acfg->aot_opts.dedup || (acfg->aot_opts.dedup_include && !acfg->dedup_emit_mode);
9075 gboolean dedupable = mono_aot_can_dedup (method);
9076
9077 // cfg->skip is vital for LLVM to work, can't just continue in this loop
9078 if (dedupable && strcmp (method->name, "wbarrier_conc") && dedup_collect) {
9079 mono_dedup_cache_method (acfg, method);
9080
9081 // Don't compile inflated methods if we're in first phase of
9082 // dedup
9083 //
9084 // In second phase, we emit methods that
9085 // are dedupable. We also emit later methods
9086 // which are referenced by them and added later.
9087 // For this reason, when in the dedup_include mode,
9088 // we never set skip.
9089 if (acfg->aot_opts.dedup)
9090 cfg->skip = TRUE;
9091 }
9092
9093 // Don't compile anything in this mode
9094 if (acfg->aot_opts.dedup_include && !acfg->dedup_emit_mode)
9095 cfg->skip = TRUE;
9096
9097 // Compile everything in this mode
9098 if (acfg->aot_opts.dedup_include && acfg->dedup_emit_mode)
9099 cfg->skip = FALSE;
9100
9101 /*if (dedup_collect) {*/
9102 /*char *name = mono_aot_get_mangled_method_name (method);*/
9103
9104 /*if (ignore_cfg (cfg))*/
9105 /*aot_printf (acfg, "Dedup Skipping %s\n", acfg->image->name, name);*/
9106 /*else*/
9107 /*aot_printf (acfg, "Dedup Keeping %s\n", acfg->image->name, name);*/
9108
9109 /*g_free (name);*/
9110 /*}*/
9111
9112 if (ignore_cfg (cfg))
9113 continue;
9114
9115 /* Emit unbox trampoline */
9116 if (mono_aot_mode_is_full (&acfg->aot_opts) && cfg->orig_method->klass->valuetype) {
9117 sprintf (symbol, "ut_%d", get_method_index (acfg, method));
9118
9119 emit_section_change (acfg, ".text", 0);
9120
9121 if (acfg->thumb_mixed && cfg->compile_llvm) {
9122 emit_set_thumb_mode (acfg);
9123 fprintf (acfg->fp, "\n.thumb_func\n");
9124 }
9125
9126 emit_label (acfg, symbol);
9127
9128 arch_emit_unbox_trampoline (acfg, cfg, cfg->orig_method, cfg->asm_symbol);
9129
9130 if (acfg->thumb_mixed && cfg->compile_llvm)
9131 emit_set_arm_mode (acfg);
9132
9133 if (!saved_unbox_info) {
9134 char user_symbol [128];
9135 GSList *unwind_ops;
9136 sprintf (user_symbol, "%sunbox_trampoline_p", acfg->user_symbol_prefix);
9137
9138 emit_label (acfg, "ut_end");
9139
9140 unwind_ops = mono_unwind_get_cie_program ();
9141 save_unwind_info (acfg, user_symbol, unwind_ops);
9142 mono_free_unwind_info (unwind_ops);
9143
9144 /* Save the unbox trampoline size */
9145 emit_symbol_diff (acfg, "ut_end", symbol, 0);
9146
9147 saved_unbox_info = TRUE;
9148 }
9149 }
9150
9151 if (cfg->compile_llvm) {
9152 acfg->stats.llvm_count ++;
9153 } else {
9154 emit_method_code (acfg, cfg);
9155 }
9156 }
9157
9158 emit_section_change (acfg, ".text", 0);
9159 emit_alignment_code (acfg, 8);
9160 emit_info_symbol (acfg, "jit_code_end");
9161
9162 /* To distinguish it from the next symbol */
9163 emit_padding (acfg, 4);
9164
9165 /*
9166 * Add .no_dead_strip directives for all LLVM methods to prevent the OSX linker
9167 * from optimizing them away, since it doesn't see that code_offsets references them.
9168 * JITted methods don't need this since they are referenced using assembler local
9169 * symbols.
9170 * FIXME: This is why write-symbols doesn't work on OSX ?
9171 */
9172 if (acfg->llvm && acfg->need_no_dead_strip) {
9173 fprintf (acfg->fp, "\n");
9174 for (i = 0; i < acfg->nmethods; ++i) {
9175 if (acfg->cfgs [i] && acfg->cfgs [i]->compile_llvm)
9176 fprintf (acfg->fp, ".no_dead_strip %s\n", acfg->cfgs [i]->asm_symbol);
9177 }
9178 }
9179
9180 /*
9181 * To work around linker issues, we emit a table of branches, and disassemble them at runtime.
9182 * This is PIE code, and the linker can update it if needed.
9183 */
9184
9185 sprintf (symbol, "method_addresses");
9186 emit_section_change (acfg, ".text", 1);
9187 emit_alignment_code (acfg, 8);
9188 emit_info_symbol (acfg, symbol);
9189 if (acfg->aot_opts.write_symbols)
9190 emit_local_symbol (acfg, symbol, "method_addresses_end", TRUE);
9191 emit_unset_mode (acfg);
9192 if (acfg->need_no_dead_strip)
9193 fprintf (acfg->fp, " .no_dead_strip %s\n", symbol);
9194
9195 for (i = 0; i < acfg->nmethods; ++i) {
9196 #ifdef MONO_ARCH_AOT_SUPPORTED
9197 int call_size;
9198
9199 if (!ignore_cfg (acfg->cfgs [i])) {
9200 arch_emit_direct_call (acfg, acfg->cfgs [i]->asm_symbol, FALSE, acfg->thumb_mixed && acfg->cfgs [i]->compile_llvm, NULL, &call_size);
9201 } else {
9202 arch_emit_direct_call (acfg, symbol, FALSE, FALSE, NULL, &call_size);
9203 }
9204 #endif
9205 }
9206
9207 sprintf (symbol, "method_addresses_end");
9208 emit_label (acfg, symbol);
9209 emit_line (acfg);
9210
9211 /* Emit a sorted table mapping methods to the index of their unbox trampolines */
9212 sprintf (symbol, "unbox_trampolines");
9213 emit_section_change (acfg, RODATA_SECT, 0);
9214 emit_alignment (acfg, 8);
9215 emit_info_symbol (acfg, symbol);
9216
9217 prev_index = -1;
9218 for (i = 0; i < acfg->nmethods; ++i) {
9219 MonoCompile *cfg;
9220 MonoMethod *method;
9221 int index;
9222
9223 cfg = acfg->cfgs [i];
9224 if (ignore_cfg (cfg))
9225 continue;
9226
9227 method = cfg->orig_method;
9228
9229 if (mono_aot_mode_is_full (&acfg->aot_opts) && cfg->orig_method->klass->valuetype) {
9230 index = get_method_index (acfg, method);
9231
9232 emit_int32 (acfg, index);
9233 /* Make sure the table is sorted by index */
9234 g_assert (index > prev_index);
9235 prev_index = index;
9236 }
9237 }
9238 sprintf (symbol, "unbox_trampolines_end");
9239 emit_info_symbol (acfg, symbol);
9240 emit_int32 (acfg, 0);
9241
9242 /* Emit a separate table with the trampoline addresses/offsets */
9243 sprintf (symbol, "unbox_trampoline_addresses");
9244 emit_section_change (acfg, ".text", 0);
9245 emit_alignment_code (acfg, 8);
9246 emit_info_symbol (acfg, symbol);
9247
9248 for (i = 0; i < acfg->nmethods; ++i) {
9249 MonoCompile *cfg;
9250 MonoMethod *method;
9251 int index;
9252
9253 cfg = acfg->cfgs [i];
9254 if (ignore_cfg (cfg))
9255 continue;
9256
9257 method = cfg->orig_method;
9258
9259 if (mono_aot_mode_is_full (&acfg->aot_opts) && cfg->orig_method->klass->valuetype) {
9260 #ifdef MONO_ARCH_AOT_SUPPORTED
9261 int call_size;
9262
9263 index = get_method_index (acfg, method);
9264 sprintf (symbol, "ut_%d", index);
9265
9266 arch_emit_direct_call (acfg, symbol, FALSE, acfg->thumb_mixed && cfg->compile_llvm, NULL, &call_size);
9267 #endif
9268 }
9269 }
9270 emit_int32 (acfg, 0);
9271 }
9272
9273 static void
emit_info(MonoAotCompile * acfg)9274 emit_info (MonoAotCompile *acfg)
9275 {
9276 int oindex, i;
9277 gint32 *offsets;
9278
9279 offsets = g_new0 (gint32, acfg->nmethods);
9280
9281 for (oindex = 0; oindex < acfg->method_order->len; ++oindex) {
9282 i = GPOINTER_TO_UINT (g_ptr_array_index (acfg->method_order, oindex));
9283
9284 if (acfg->cfgs [i]) {
9285 emit_method_info (acfg, acfg->cfgs [i]);
9286 offsets [i] = acfg->cfgs [i]->method_info_offset;
9287 } else {
9288 offsets [i] = 0;
9289 }
9290 }
9291
9292 acfg->stats.offsets_size += emit_offset_table (acfg, "method_info_offsets", MONO_AOT_TABLE_METHOD_INFO_OFFSETS, acfg->nmethods, 10, offsets);
9293
9294 g_free (offsets);
9295 }
9296
9297 #endif /* #if !defined(DISABLE_AOT) && !defined(DISABLE_JIT) */
9298
9299 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
9300 #define mix(a,b,c) { \
9301 a -= c; a ^= rot(c, 4); c += b; \
9302 b -= a; b ^= rot(a, 6); a += c; \
9303 c -= b; c ^= rot(b, 8); b += a; \
9304 a -= c; a ^= rot(c,16); c += b; \
9305 b -= a; b ^= rot(a,19); a += c; \
9306 c -= b; c ^= rot(b, 4); b += a; \
9307 }
9308 #define final(a,b,c) { \
9309 c ^= b; c -= rot(b,14); \
9310 a ^= c; a -= rot(c,11); \
9311 b ^= a; b -= rot(a,25); \
9312 c ^= b; c -= rot(b,16); \
9313 a ^= c; a -= rot(c,4); \
9314 b ^= a; b -= rot(a,14); \
9315 c ^= b; c -= rot(b,24); \
9316 }
9317
9318 static guint
mono_aot_type_hash(MonoType * t1)9319 mono_aot_type_hash (MonoType *t1)
9320 {
9321 guint hash = t1->type;
9322
9323 hash |= t1->byref << 6; /* do not collide with t1->type values */
9324 switch (t1->type) {
9325 case MONO_TYPE_VALUETYPE:
9326 case MONO_TYPE_CLASS:
9327 case MONO_TYPE_SZARRAY:
9328 /* check if the distribution is good enough */
9329 return ((hash << 5) - hash) ^ mono_metadata_str_hash (t1->data.klass->name);
9330 case MONO_TYPE_PTR:
9331 return ((hash << 5) - hash) ^ mono_metadata_type_hash (t1->data.type);
9332 case MONO_TYPE_ARRAY:
9333 return ((hash << 5) - hash) ^ mono_metadata_type_hash (&t1->data.array->eklass->byval_arg);
9334 case MONO_TYPE_GENERICINST:
9335 return ((hash << 5) - hash) ^ 0;
9336 default:
9337 return hash;
9338 }
9339 }
9340
9341 /*
9342 * mono_aot_method_hash:
9343 *
9344 * Return a hash code for methods which only depends on metadata.
9345 */
9346 guint32
mono_aot_method_hash(MonoMethod * method)9347 mono_aot_method_hash (MonoMethod *method)
9348 {
9349 MonoMethodSignature *sig;
9350 MonoClass *klass;
9351 int i, hindex;
9352 int hashes_count;
9353 guint32 *hashes_start, *hashes;
9354 guint32 a, b, c;
9355 MonoGenericInst *class_ginst = NULL;
9356 MonoGenericInst *ginst = NULL;
9357
9358 /* Similar to the hash in mono_method_get_imt_slot () */
9359
9360 sig = mono_method_signature (method);
9361
9362 if (mono_class_is_ginst (method->klass))
9363 class_ginst = mono_class_get_generic_class (method->klass)->context.class_inst;
9364 if (method->is_inflated)
9365 ginst = ((MonoMethodInflated*)method)->context.method_inst;
9366
9367 hashes_count = sig->param_count + 5 + (class_ginst ? class_ginst->type_argc : 0) + (ginst ? ginst->type_argc : 0);
9368 hashes_start = (guint32 *)g_malloc0 (hashes_count * sizeof (guint32));
9369 hashes = hashes_start;
9370
9371 /* Some wrappers are assigned to random classes */
9372 if (!method->wrapper_type || method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK)
9373 klass = method->klass;
9374 else
9375 klass = mono_defaults.object_class;
9376
9377 if (!method->wrapper_type) {
9378 char *full_name;
9379
9380 if (mono_class_is_ginst (klass))
9381 full_name = mono_type_full_name (&mono_class_get_generic_class (klass)->container_class->byval_arg);
9382 else
9383 full_name = mono_type_full_name (&klass->byval_arg);
9384
9385 hashes [0] = mono_metadata_str_hash (full_name);
9386 hashes [1] = 0;
9387 g_free (full_name);
9388 } else {
9389 hashes [0] = mono_metadata_str_hash (klass->name);
9390 hashes [1] = mono_metadata_str_hash (klass->name_space);
9391 }
9392 if (method->wrapper_type == MONO_WRAPPER_STFLD || method->wrapper_type == MONO_WRAPPER_LDFLD || method->wrapper_type == MONO_WRAPPER_LDFLDA)
9393 /* The method name includes a stringified pointer */
9394 hashes [2] = 0;
9395 else
9396 hashes [2] = mono_metadata_str_hash (method->name);
9397 hashes [3] = method->wrapper_type;
9398 hashes [4] = mono_aot_type_hash (sig->ret);
9399 hindex = 5;
9400 for (i = 0; i < sig->param_count; i++) {
9401 hashes [hindex ++] = mono_aot_type_hash (sig->params [i]);
9402 }
9403 if (class_ginst) {
9404 for (i = 0; i < class_ginst->type_argc; ++i)
9405 hashes [hindex ++] = mono_aot_type_hash (class_ginst->type_argv [i]);
9406 }
9407 if (ginst) {
9408 for (i = 0; i < ginst->type_argc; ++i)
9409 hashes [hindex ++] = mono_aot_type_hash (ginst->type_argv [i]);
9410 }
9411 g_assert (hindex == hashes_count);
9412
9413 /* Setup internal state */
9414 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
9415
9416 /* Handle most of the hashes */
9417 while (hashes_count > 3) {
9418 a += hashes [0];
9419 b += hashes [1];
9420 c += hashes [2];
9421 mix (a,b,c);
9422 hashes_count -= 3;
9423 hashes += 3;
9424 }
9425
9426 /* Handle the last 3 hashes (all the case statements fall through) */
9427 switch (hashes_count) {
9428 case 3 : c += hashes [2];
9429 case 2 : b += hashes [1];
9430 case 1 : a += hashes [0];
9431 final (a,b,c);
9432 case 0: /* nothing left to add */
9433 break;
9434 }
9435
9436 g_free (hashes_start);
9437
9438 return c;
9439 }
9440 #undef rot
9441 #undef mix
9442 #undef final
9443
9444 /*
9445 * mono_aot_get_array_helper_from_wrapper;
9446 *
9447 * Get the helper method in Array called by an array wrapper method.
9448 */
9449 MonoMethod*
mono_aot_get_array_helper_from_wrapper(MonoMethod * method)9450 mono_aot_get_array_helper_from_wrapper (MonoMethod *method)
9451 {
9452 MonoMethod *m;
9453 const char *prefix;
9454 MonoGenericContext ctx;
9455 MonoType *args [16];
9456 char *mname, *iname, *s, *s2, *helper_name = NULL;
9457
9458 prefix = "System.Collections.Generic";
9459 s = g_strdup_printf ("%s", method->name + strlen (prefix) + 1);
9460 s2 = strstr (s, "`1.");
9461 g_assert (s2);
9462 s2 [0] = '\0';
9463 iname = s;
9464 mname = s2 + 3;
9465
9466 //printf ("X: %s %s\n", iname, mname);
9467
9468 if (!strcmp (iname, "IList"))
9469 helper_name = g_strdup_printf ("InternalArray__%s", mname);
9470 else
9471 helper_name = g_strdup_printf ("InternalArray__%s_%s", iname, mname);
9472 m = mono_class_get_method_from_name (mono_defaults.array_class, helper_name, mono_method_signature (method)->param_count);
9473 g_assert (m);
9474 g_free (helper_name);
9475 g_free (s);
9476
9477 if (m->is_generic) {
9478 MonoError error;
9479 memset (&ctx, 0, sizeof (ctx));
9480 args [0] = &method->klass->element_class->byval_arg;
9481 ctx.method_inst = mono_metadata_get_generic_inst (1, args);
9482 m = mono_class_inflate_generic_method_checked (m, &ctx, &error);
9483 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
9484 }
9485
9486 return m;
9487 }
9488
9489 #if !defined(DISABLE_AOT) && !defined(DISABLE_JIT)
9490
9491 typedef struct HashEntry {
9492 guint32 key, value, index;
9493 struct HashEntry *next;
9494 } HashEntry;
9495
9496 /*
9497 * emit_extra_methods:
9498 *
9499 * Emit methods which are not in the METHOD table, like wrappers.
9500 */
9501 static void
emit_extra_methods(MonoAotCompile * acfg)9502 emit_extra_methods (MonoAotCompile *acfg)
9503 {
9504 int i, table_size, buf_size;
9505 guint8 *p, *buf;
9506 guint32 *info_offsets;
9507 guint32 hash;
9508 GPtrArray *table;
9509 HashEntry *entry, *new_entry;
9510 int nmethods, max_chain_length;
9511 int *chain_lengths;
9512
9513 info_offsets = g_new0 (guint32, acfg->extra_methods->len);
9514
9515 /* Emit method info */
9516 nmethods = 0;
9517 for (i = 0; i < acfg->extra_methods->len; ++i) {
9518 MonoMethod *method = (MonoMethod *)g_ptr_array_index (acfg->extra_methods, i);
9519 MonoCompile *cfg = (MonoCompile *)g_hash_table_lookup (acfg->method_to_cfg, method);
9520
9521 if (ignore_cfg (cfg))
9522 continue;
9523
9524 buf_size = 10240;
9525 p = buf = (guint8 *)g_malloc (buf_size);
9526
9527 nmethods ++;
9528
9529 method = cfg->method_to_register;
9530
9531 encode_method_ref (acfg, method, p, &p);
9532
9533 g_assert ((p - buf) < buf_size);
9534
9535 info_offsets [i] = add_to_blob (acfg, buf, p - buf);
9536 g_free (buf);
9537 }
9538
9539 /*
9540 * Construct a chained hash table for mapping indexes in extra_method_info to
9541 * method indexes.
9542 */
9543 table_size = g_spaced_primes_closest ((int)(nmethods * 1.5));
9544 table = g_ptr_array_sized_new (table_size);
9545 for (i = 0; i < table_size; ++i)
9546 g_ptr_array_add (table, NULL);
9547 chain_lengths = g_new0 (int, table_size);
9548 max_chain_length = 0;
9549 for (i = 0; i < acfg->extra_methods->len; ++i) {
9550 MonoMethod *method = (MonoMethod *)g_ptr_array_index (acfg->extra_methods, i);
9551 MonoCompile *cfg = (MonoCompile *)g_hash_table_lookup (acfg->method_to_cfg, method);
9552 guint32 key, value;
9553
9554 if (ignore_cfg (cfg))
9555 continue;
9556
9557 key = info_offsets [i];
9558 value = get_method_index (acfg, method);
9559
9560 hash = mono_aot_method_hash (method) % table_size;
9561 //printf ("X: %s %x\n", mono_method_get_full_name (method), mono_aot_method_hash (method));
9562
9563 chain_lengths [hash] ++;
9564 max_chain_length = MAX (max_chain_length, chain_lengths [hash]);
9565
9566 new_entry = (HashEntry *)mono_mempool_alloc0 (acfg->mempool, sizeof (HashEntry));
9567 new_entry->key = key;
9568 new_entry->value = value;
9569
9570 entry = (HashEntry *)g_ptr_array_index (table, hash);
9571 if (entry == NULL) {
9572 new_entry->index = hash;
9573 g_ptr_array_index (table, hash) = new_entry;
9574 } else {
9575 while (entry->next)
9576 entry = entry->next;
9577
9578 entry->next = new_entry;
9579 new_entry->index = table->len;
9580 g_ptr_array_add (table, new_entry);
9581 }
9582 }
9583 g_free (chain_lengths);
9584
9585 //printf ("MAX: %d\n", max_chain_length);
9586
9587 buf_size = table->len * 12 + 4;
9588 p = buf = (guint8 *)g_malloc (buf_size);
9589 encode_int (table_size, p, &p);
9590
9591 for (i = 0; i < table->len; ++i) {
9592 HashEntry *entry = (HashEntry *)g_ptr_array_index (table, i);
9593
9594 if (entry == NULL) {
9595 encode_int (0, p, &p);
9596 encode_int (0, p, &p);
9597 encode_int (0, p, &p);
9598 } else {
9599 //g_assert (entry->key > 0);
9600 encode_int (entry->key, p, &p);
9601 encode_int (entry->value, p, &p);
9602 if (entry->next)
9603 encode_int (entry->next->index, p, &p);
9604 else
9605 encode_int (0, p, &p);
9606 }
9607 }
9608 g_assert (p - buf <= buf_size);
9609
9610 /* Emit the table */
9611 emit_aot_data (acfg, MONO_AOT_TABLE_EXTRA_METHOD_TABLE, "extra_method_table", buf, p - buf);
9612
9613 g_free (buf);
9614
9615 /*
9616 * Emit a table reverse mapping method indexes to their index in extra_method_info.
9617 * This is used by mono_aot_find_jit_info ().
9618 */
9619 buf_size = acfg->extra_methods->len * 8 + 4;
9620 p = buf = (guint8 *)g_malloc (buf_size);
9621 encode_int (acfg->extra_methods->len, p, &p);
9622 for (i = 0; i < acfg->extra_methods->len; ++i) {
9623 MonoMethod *method = (MonoMethod *)g_ptr_array_index (acfg->extra_methods, i);
9624
9625 encode_int (get_method_index (acfg, method), p, &p);
9626 encode_int (info_offsets [i], p, &p);
9627 }
9628 emit_aot_data (acfg, MONO_AOT_TABLE_EXTRA_METHOD_INFO_OFFSETS, "extra_method_info_offsets", buf, p - buf);
9629
9630 g_free (buf);
9631 g_free (info_offsets);
9632 g_ptr_array_free (table, TRUE);
9633 }
9634
9635 static void
generate_aotid(guint8 * aotid)9636 generate_aotid (guint8* aotid)
9637 {
9638 gpointer rand_handle;
9639 MonoError error;
9640
9641 mono_rand_open ();
9642 rand_handle = mono_rand_init (NULL, 0);
9643
9644 mono_rand_try_get_bytes (&rand_handle, aotid, 16, &error);
9645 mono_error_assert_ok (&error);
9646
9647 mono_rand_close (rand_handle);
9648 }
9649
9650 static void
emit_exception_info(MonoAotCompile * acfg)9651 emit_exception_info (MonoAotCompile *acfg)
9652 {
9653 int i;
9654 gint32 *offsets;
9655 SeqPointData sp_data;
9656 gboolean seq_points_to_file = FALSE;
9657
9658 offsets = g_new0 (gint32, acfg->nmethods);
9659 for (i = 0; i < acfg->nmethods; ++i) {
9660 if (acfg->cfgs [i]) {
9661 MonoCompile *cfg = acfg->cfgs [i];
9662
9663 // By design aot-runtime decode_exception_debug_info is not able to load sequence point debug data from a file.
9664 // As it is not possible to load debug data from a file its is also not possible to store it in a file.
9665 gboolean method_seq_points_to_file = acfg->aot_opts.gen_msym_dir &&
9666 cfg->gen_seq_points && !cfg->gen_sdb_seq_points;
9667 gboolean method_seq_points_to_binary = cfg->gen_seq_points && !method_seq_points_to_file;
9668
9669 emit_exception_debug_info (acfg, cfg, method_seq_points_to_binary);
9670 offsets [i] = cfg->ex_info_offset;
9671
9672 if (method_seq_points_to_file) {
9673 if (!seq_points_to_file) {
9674 mono_seq_point_data_init (&sp_data, acfg->nmethods);
9675 seq_points_to_file = TRUE;
9676 }
9677 mono_seq_point_data_add (&sp_data, cfg->method->token, cfg->method_index, cfg->seq_point_info);
9678 }
9679 } else {
9680 offsets [i] = 0;
9681 }
9682 }
9683
9684 if (seq_points_to_file) {
9685 char *aotid = mono_guid_to_string_minimal (acfg->image->aotid);
9686 char *dir = g_build_filename (acfg->aot_opts.gen_msym_dir_path, aotid, NULL);
9687 char *image_basename = g_path_get_basename (acfg->image->name);
9688 char *aot_file = g_strdup_printf("%s%s", image_basename, SEQ_POINT_AOT_EXT);
9689 char *aot_file_path = g_build_filename (dir, aot_file, NULL);
9690
9691 if (g_ensure_directory_exists (aot_file_path) == FALSE) {
9692 fprintf (stderr, "AOT : failed to create msym directory: %s\n", aot_file_path);
9693 exit (1);
9694 }
9695
9696 mono_seq_point_data_write (&sp_data, aot_file_path);
9697 mono_seq_point_data_free (&sp_data);
9698
9699 g_free (aotid);
9700 g_free (dir);
9701 g_free (image_basename);
9702 g_free (aot_file);
9703 g_free (aot_file_path);
9704 }
9705
9706 acfg->stats.offsets_size += emit_offset_table (acfg, "ex_info_offsets", MONO_AOT_TABLE_EX_INFO_OFFSETS, acfg->nmethods, 10, offsets);
9707 g_free (offsets);
9708 }
9709
9710 static void
emit_unwind_info(MonoAotCompile * acfg)9711 emit_unwind_info (MonoAotCompile *acfg)
9712 {
9713 int i;
9714 char symbol [128];
9715
9716 if (acfg->aot_opts.llvm_only) {
9717 g_assert (acfg->unwind_ops->len == 0);
9718 return;
9719 }
9720
9721 /*
9722 * The unwind info contains a lot of duplicates so we emit each unique
9723 * entry once, and only store the offset from the start of the table in the
9724 * exception info.
9725 */
9726
9727 sprintf (symbol, "unwind_info");
9728 emit_section_change (acfg, RODATA_SECT, 1);
9729 emit_alignment (acfg, 8);
9730 emit_info_symbol (acfg, symbol);
9731
9732 for (i = 0; i < acfg->unwind_ops->len; ++i) {
9733 guint32 index = GPOINTER_TO_UINT (g_ptr_array_index (acfg->unwind_ops, i));
9734 guint8 *unwind_info;
9735 guint32 unwind_info_len;
9736 guint8 buf [16];
9737 guint8 *p;
9738
9739 unwind_info = mono_get_cached_unwind_info (index, &unwind_info_len);
9740
9741 p = buf;
9742 encode_value (unwind_info_len, p, &p);
9743 emit_bytes (acfg, buf, p - buf);
9744 emit_bytes (acfg, unwind_info, unwind_info_len);
9745
9746 acfg->stats.unwind_info_size += (p - buf) + unwind_info_len;
9747 }
9748 }
9749
9750 static void
emit_class_info(MonoAotCompile * acfg)9751 emit_class_info (MonoAotCompile *acfg)
9752 {
9753 int i;
9754 gint32 *offsets;
9755
9756 offsets = g_new0 (gint32, acfg->image->tables [MONO_TABLE_TYPEDEF].rows);
9757 for (i = 0; i < acfg->image->tables [MONO_TABLE_TYPEDEF].rows; ++i)
9758 offsets [i] = emit_klass_info (acfg, MONO_TOKEN_TYPE_DEF | (i + 1));
9759
9760 acfg->stats.offsets_size += emit_offset_table (acfg, "class_info_offsets", MONO_AOT_TABLE_CLASS_INFO_OFFSETS, acfg->image->tables [MONO_TABLE_TYPEDEF].rows, 10, offsets);
9761 g_free (offsets);
9762 }
9763
9764 typedef struct ClassNameTableEntry {
9765 guint32 token, index;
9766 struct ClassNameTableEntry *next;
9767 } ClassNameTableEntry;
9768
9769 static void
emit_class_name_table(MonoAotCompile * acfg)9770 emit_class_name_table (MonoAotCompile *acfg)
9771 {
9772 int i, table_size, buf_size;
9773 guint32 token, hash;
9774 MonoClass *klass;
9775 GPtrArray *table;
9776 char *full_name;
9777 guint8 *buf, *p;
9778 ClassNameTableEntry *entry, *new_entry;
9779
9780 /*
9781 * Construct a chained hash table for mapping class names to typedef tokens.
9782 */
9783 table_size = g_spaced_primes_closest ((int)(acfg->image->tables [MONO_TABLE_TYPEDEF].rows * 1.5));
9784 table = g_ptr_array_sized_new (table_size);
9785 for (i = 0; i < table_size; ++i)
9786 g_ptr_array_add (table, NULL);
9787 for (i = 0; i < acfg->image->tables [MONO_TABLE_TYPEDEF].rows; ++i) {
9788 MonoError error;
9789 token = MONO_TOKEN_TYPE_DEF | (i + 1);
9790 klass = mono_class_get_checked (acfg->image, token, &error);
9791 if (!klass) {
9792 mono_error_cleanup (&error);
9793 continue;
9794 }
9795 full_name = mono_type_get_name_full (mono_class_get_type (klass), MONO_TYPE_NAME_FORMAT_FULL_NAME);
9796 hash = mono_metadata_str_hash (full_name) % table_size;
9797 g_free (full_name);
9798
9799 /* FIXME: Allocate from the mempool */
9800 new_entry = g_new0 (ClassNameTableEntry, 1);
9801 new_entry->token = token;
9802
9803 entry = (ClassNameTableEntry *)g_ptr_array_index (table, hash);
9804 if (entry == NULL) {
9805 new_entry->index = hash;
9806 g_ptr_array_index (table, hash) = new_entry;
9807 } else {
9808 while (entry->next)
9809 entry = entry->next;
9810
9811 entry->next = new_entry;
9812 new_entry->index = table->len;
9813 g_ptr_array_add (table, new_entry);
9814 }
9815 }
9816
9817 /* Emit the table */
9818 buf_size = table->len * 4 + 4;
9819 p = buf = (guint8 *)g_malloc0 (buf_size);
9820
9821 /* FIXME: Optimize memory usage */
9822 g_assert (table_size < 65000);
9823 encode_int16 (table_size, p, &p);
9824 g_assert (table->len < 65000);
9825 for (i = 0; i < table->len; ++i) {
9826 ClassNameTableEntry *entry = (ClassNameTableEntry *)g_ptr_array_index (table, i);
9827
9828 if (entry == NULL) {
9829 encode_int16 (0, p, &p);
9830 encode_int16 (0, p, &p);
9831 } else {
9832 encode_int16 (mono_metadata_token_index (entry->token), p, &p);
9833 if (entry->next)
9834 encode_int16 (entry->next->index, p, &p);
9835 else
9836 encode_int16 (0, p, &p);
9837 }
9838 g_free (entry);
9839 }
9840 g_assert (p - buf <= buf_size);
9841 g_ptr_array_free (table, TRUE);
9842
9843 emit_aot_data (acfg, MONO_AOT_TABLE_CLASS_NAME, "class_name_table", buf, p - buf);
9844
9845 g_free (buf);
9846 }
9847
9848 static void
emit_image_table(MonoAotCompile * acfg)9849 emit_image_table (MonoAotCompile *acfg)
9850 {
9851 int i, buf_size;
9852 guint8 *buf, *p;
9853
9854 /*
9855 * The image table is small but referenced in a lot of places.
9856 * So we emit it at once, and reference its elements by an index.
9857 */
9858 buf_size = acfg->image_table->len * 28 + 4;
9859 for (i = 0; i < acfg->image_table->len; i++) {
9860 MonoImage *image = (MonoImage*)g_ptr_array_index (acfg->image_table, i);
9861 MonoAssemblyName *aname = &image->assembly->aname;
9862
9863 buf_size += strlen (image->assembly_name) + strlen (image->guid) + (aname->culture ? strlen (aname->culture) : 1) + strlen ((char*)aname->public_key_token) + 4;
9864 }
9865
9866 buf = p = (guint8 *)g_malloc0 (buf_size);
9867 encode_int (acfg->image_table->len, p, &p);
9868 for (i = 0; i < acfg->image_table->len; i++) {
9869 MonoImage *image = (MonoImage*)g_ptr_array_index (acfg->image_table, i);
9870 MonoAssemblyName *aname = &image->assembly->aname;
9871
9872 /* FIXME: Support multi-module assemblies */
9873 g_assert (image->assembly->image == image);
9874
9875 encode_string (image->assembly_name, p, &p);
9876 encode_string (image->guid, p, &p);
9877 encode_string (aname->culture ? aname->culture : "", p, &p);
9878 encode_string ((const char*)aname->public_key_token, p, &p);
9879
9880 while (GPOINTER_TO_UINT (p) % 8 != 0)
9881 p ++;
9882
9883 encode_int (aname->flags, p, &p);
9884 encode_int (aname->major, p, &p);
9885 encode_int (aname->minor, p, &p);
9886 encode_int (aname->build, p, &p);
9887 encode_int (aname->revision, p, &p);
9888 }
9889 g_assert (p - buf <= buf_size);
9890
9891 emit_aot_data (acfg, MONO_AOT_TABLE_IMAGE_TABLE, "image_table", buf, p - buf);
9892
9893 g_free (buf);
9894 }
9895
9896 static void
emit_weak_field_indexes(MonoAotCompile * acfg)9897 emit_weak_field_indexes (MonoAotCompile *acfg)
9898 {
9899 GHashTable *indexes;
9900 GHashTableIter iter;
9901 gpointer key, value;
9902 int buf_size;
9903 guint8 *buf, *p;
9904
9905 /* Emit a table of weak field indexes, since computing these at runtime is expensive */
9906 mono_assembly_init_weak_fields (acfg->image);
9907 indexes = acfg->image->weak_field_indexes;
9908 g_assert (indexes);
9909
9910 buf_size = (g_hash_table_size (indexes) + 1) * 4;
9911 buf = p = (guint8 *)g_malloc0 (buf_size);
9912
9913 encode_int (g_hash_table_size (indexes), p, &p);
9914 g_hash_table_iter_init (&iter, indexes);
9915 while (g_hash_table_iter_next (&iter, &key, &value)) {
9916 guint32 index = GPOINTER_TO_UINT (key);
9917 encode_int (index, p, &p);
9918 }
9919 g_assert (p - buf <= buf_size);
9920
9921 emit_aot_data (acfg, MONO_AOT_TABLE_WEAK_FIELD_INDEXES, "weak_field_indexes", buf, p - buf);
9922
9923 g_free (buf);
9924 }
9925
9926 static void
emit_got_info(MonoAotCompile * acfg,gboolean llvm)9927 emit_got_info (MonoAotCompile *acfg, gboolean llvm)
9928 {
9929 int i, first_plt_got_patch = 0, buf_size;
9930 guint8 *p, *buf;
9931 guint32 *got_info_offsets;
9932 GotInfo *info = llvm ? &acfg->llvm_got_info : &acfg->got_info;
9933
9934 /* Add the patches needed by the PLT to the GOT */
9935 if (!llvm) {
9936 acfg->plt_got_offset_base = acfg->got_offset;
9937 first_plt_got_patch = info->got_patches->len;
9938 for (i = 1; i < acfg->plt_offset; ++i) {
9939 MonoPltEntry *plt_entry = (MonoPltEntry *)g_hash_table_lookup (acfg->plt_offset_to_entry, GUINT_TO_POINTER (i));
9940
9941 g_ptr_array_add (info->got_patches, plt_entry->ji);
9942
9943 acfg->stats.got_slot_types [plt_entry->ji->type] ++;
9944 }
9945
9946 acfg->got_offset += acfg->plt_offset;
9947 }
9948
9949 /**
9950 * FIXME:
9951 * - optimize offsets table.
9952 * - reduce number of exported symbols.
9953 * - emit info for a klass only once.
9954 * - determine when a method uses a GOT slot which is guaranteed to be already
9955 * initialized.
9956 * - clean up and document the code.
9957 * - use String.Empty in class libs.
9958 */
9959
9960 /* Encode info required to decode shared GOT entries */
9961 buf_size = info->got_patches->len * 128;
9962 p = buf = (guint8 *)mono_mempool_alloc (acfg->mempool, buf_size);
9963 got_info_offsets = (guint32 *)mono_mempool_alloc (acfg->mempool, info->got_patches->len * sizeof (guint32));
9964 if (!llvm) {
9965 acfg->plt_got_info_offsets = (guint32 *)mono_mempool_alloc (acfg->mempool, acfg->plt_offset * sizeof (guint32));
9966 /* Unused */
9967 if (acfg->plt_offset)
9968 acfg->plt_got_info_offsets [0] = 0;
9969 }
9970 for (i = 0; i < info->got_patches->len; ++i) {
9971 MonoJumpInfo *ji = (MonoJumpInfo *)g_ptr_array_index (info->got_patches, i);
9972 guint8 *p2;
9973
9974 p = buf;
9975
9976 encode_value (ji->type, p, &p);
9977 p2 = p;
9978 encode_patch (acfg, ji, p, &p);
9979 acfg->stats.got_slot_info_sizes [ji->type] += p - p2;
9980 g_assert (p - buf <= buf_size);
9981 got_info_offsets [i] = add_to_blob (acfg, buf, p - buf);
9982
9983 if (!llvm && i >= first_plt_got_patch)
9984 acfg->plt_got_info_offsets [i - first_plt_got_patch + 1] = got_info_offsets [i];
9985 acfg->stats.got_info_size += p - buf;
9986 }
9987
9988 /* Emit got_info_offsets table */
9989
9990 /* No need to emit offsets for the got plt entries, the plt embeds them directly */
9991 acfg->stats.offsets_size += emit_offset_table (acfg, llvm ? "llvm_got_info_offsets" : "got_info_offsets", llvm ? MONO_AOT_TABLE_LLVM_GOT_INFO_OFFSETS : MONO_AOT_TABLE_GOT_INFO_OFFSETS, llvm ? acfg->llvm_got_offset : first_plt_got_patch, 10, (gint32*)got_info_offsets);
9992 }
9993
9994 static void
emit_got(MonoAotCompile * acfg)9995 emit_got (MonoAotCompile *acfg)
9996 {
9997 char symbol [MAX_SYMBOL_SIZE];
9998
9999 if (acfg->aot_opts.llvm_only)
10000 return;
10001
10002 /* Don't make GOT global so accesses to it don't need relocations */
10003 sprintf (symbol, "%s", acfg->got_symbol);
10004
10005 #ifdef TARGET_MACH
10006 emit_unset_mode (acfg);
10007 fprintf (acfg->fp, ".section __DATA, __bss\n");
10008 emit_alignment (acfg, 8);
10009 if (acfg->llvm)
10010 emit_info_symbol (acfg, "jit_got");
10011 fprintf (acfg->fp, ".lcomm %s, %d\n", acfg->got_symbol, (int)(acfg->got_offset * sizeof (gpointer)));
10012 #else
10013 emit_section_change (acfg, ".bss", 0);
10014 emit_alignment (acfg, 8);
10015 if (acfg->aot_opts.write_symbols)
10016 emit_local_symbol (acfg, symbol, "got_end", FALSE);
10017 emit_label (acfg, symbol);
10018 if (acfg->llvm)
10019 emit_info_symbol (acfg, "jit_got");
10020 if (acfg->got_offset > 0)
10021 emit_zero_bytes (acfg, (int)(acfg->got_offset * sizeof (gpointer)));
10022 #endif
10023
10024 sprintf (symbol, "got_end");
10025 emit_label (acfg, symbol);
10026 }
10027
10028 typedef struct GlobalsTableEntry {
10029 guint32 value, index;
10030 struct GlobalsTableEntry *next;
10031 } GlobalsTableEntry;
10032
10033 #ifdef TARGET_WIN32_MSVC
10034 #define DLL_ENTRY_POINT "DllMain"
10035
10036 static void
emit_library_info(MonoAotCompile * acfg)10037 emit_library_info (MonoAotCompile *acfg)
10038 {
10039 // Only include for shared libraries linked directly from generated object.
10040 if (link_shared_library (acfg)) {
10041 char *name = NULL;
10042 char symbol [MAX_SYMBOL_SIZE];
10043
10044 // Ask linker to export all global symbols.
10045 emit_section_change (acfg, ".drectve", 0);
10046 for (guint i = 0; i < acfg->globals->len; ++i) {
10047 name = (char *)g_ptr_array_index (acfg->globals, i);
10048 g_assert (name != NULL);
10049 sprintf_s (symbol, MAX_SYMBOL_SIZE, " /EXPORT:%s", name);
10050 emit_string (acfg, symbol);
10051 }
10052
10053 // Emit DLLMain function, needed by MSVC linker for DLL's.
10054 // NOTE, DllMain should not go into exports above.
10055 emit_section_change (acfg, ".text", 0);
10056 emit_global (acfg, DLL_ENTRY_POINT, TRUE);
10057 emit_label (acfg, DLL_ENTRY_POINT);
10058
10059 // Simple implementation of DLLMain, just returning TRUE.
10060 // For more information about DLLMain: https://msdn.microsoft.com/en-us/library/windows/desktop/ms682583(v=vs.85).aspx
10061 fprintf (acfg->fp, "movl $1, %%eax\n");
10062 fprintf (acfg->fp, "ret\n");
10063
10064 // Inform linker about our dll entry function.
10065 emit_section_change (acfg, ".drectve", 0);
10066 emit_string (acfg, "/ENTRY:" DLL_ENTRY_POINT);
10067 return;
10068 }
10069 }
10070
10071 #else
10072
10073 static inline void
emit_library_info(MonoAotCompile * acfg)10074 emit_library_info (MonoAotCompile *acfg)
10075 {
10076 return;
10077 }
10078 #endif
10079
10080 static void
emit_globals(MonoAotCompile * acfg)10081 emit_globals (MonoAotCompile *acfg)
10082 {
10083 int i, table_size;
10084 guint32 hash;
10085 GPtrArray *table;
10086 char symbol [1024];
10087 GlobalsTableEntry *entry, *new_entry;
10088
10089 if (!acfg->aot_opts.static_link)
10090 return;
10091
10092 if (acfg->aot_opts.llvm_only) {
10093 g_assert (acfg->globals->len == 0);
10094 return;
10095 }
10096
10097 /*
10098 * When static linking, we emit a table containing our globals.
10099 */
10100
10101 /*
10102 * Construct a chained hash table for mapping global names to their index in
10103 * the globals table.
10104 */
10105 table_size = g_spaced_primes_closest ((int)(acfg->globals->len * 1.5));
10106 table = g_ptr_array_sized_new (table_size);
10107 for (i = 0; i < table_size; ++i)
10108 g_ptr_array_add (table, NULL);
10109 for (i = 0; i < acfg->globals->len; ++i) {
10110 char *name = (char *)g_ptr_array_index (acfg->globals, i);
10111
10112 hash = mono_metadata_str_hash (name) % table_size;
10113
10114 /* FIXME: Allocate from the mempool */
10115 new_entry = g_new0 (GlobalsTableEntry, 1);
10116 new_entry->value = i;
10117
10118 entry = (GlobalsTableEntry *)g_ptr_array_index (table, hash);
10119 if (entry == NULL) {
10120 new_entry->index = hash;
10121 g_ptr_array_index (table, hash) = new_entry;
10122 } else {
10123 while (entry->next)
10124 entry = entry->next;
10125
10126 entry->next = new_entry;
10127 new_entry->index = table->len;
10128 g_ptr_array_add (table, new_entry);
10129 }
10130 }
10131
10132 /* Emit the table */
10133 sprintf (symbol, ".Lglobals_hash");
10134 emit_section_change (acfg, RODATA_SECT, 0);
10135 emit_alignment (acfg, 8);
10136 emit_label (acfg, symbol);
10137
10138 /* FIXME: Optimize memory usage */
10139 g_assert (table_size < 65000);
10140 emit_int16 (acfg, table_size);
10141 for (i = 0; i < table->len; ++i) {
10142 GlobalsTableEntry *entry = (GlobalsTableEntry *)g_ptr_array_index (table, i);
10143
10144 if (entry == NULL) {
10145 emit_int16 (acfg, 0);
10146 emit_int16 (acfg, 0);
10147 } else {
10148 emit_int16 (acfg, entry->value + 1);
10149 if (entry->next)
10150 emit_int16 (acfg, entry->next->index);
10151 else
10152 emit_int16 (acfg, 0);
10153 }
10154 }
10155
10156 /* Emit the names */
10157 for (i = 0; i < acfg->globals->len; ++i) {
10158 char *name = (char *)g_ptr_array_index (acfg->globals, i);
10159
10160 sprintf (symbol, "name_%d", i);
10161 emit_section_change (acfg, RODATA_SECT, 1);
10162 #ifdef TARGET_MACH
10163 emit_alignment (acfg, 4);
10164 #endif
10165 emit_label (acfg, symbol);
10166 emit_string (acfg, name);
10167 }
10168
10169 /* Emit the globals table */
10170 sprintf (symbol, "globals");
10171 emit_section_change (acfg, ".data", 0);
10172 /* This is not a global, since it is accessed by the init function */
10173 emit_alignment (acfg, 8);
10174 emit_info_symbol (acfg, symbol);
10175
10176 sprintf (symbol, "%sglobals_hash", acfg->temp_prefix);
10177 emit_pointer (acfg, symbol);
10178
10179 for (i = 0; i < acfg->globals->len; ++i) {
10180 char *name = (char *)g_ptr_array_index (acfg->globals, i);
10181
10182 sprintf (symbol, "name_%d", i);
10183 emit_pointer (acfg, symbol);
10184
10185 g_assert (strlen (name) < sizeof (symbol));
10186 sprintf (symbol, "%s", name);
10187 emit_pointer (acfg, symbol);
10188 }
10189 /* Null terminate the table */
10190 emit_int32 (acfg, 0);
10191 emit_int32 (acfg, 0);
10192 }
10193
10194 static void
emit_mem_end(MonoAotCompile * acfg)10195 emit_mem_end (MonoAotCompile *acfg)
10196 {
10197 char symbol [128];
10198
10199 if (acfg->aot_opts.llvm_only)
10200 return;
10201
10202 sprintf (symbol, "mem_end");
10203 emit_section_change (acfg, ".text", 1);
10204 emit_alignment_code (acfg, 8);
10205 emit_label (acfg, symbol);
10206 }
10207
10208 static void
init_aot_file_info(MonoAotCompile * acfg,MonoAotFileInfo * info)10209 init_aot_file_info (MonoAotCompile *acfg, MonoAotFileInfo *info)
10210 {
10211 int i;
10212
10213 info->version = MONO_AOT_FILE_VERSION;
10214 info->plt_got_offset_base = acfg->plt_got_offset_base;
10215 info->got_size = acfg->got_offset * sizeof (gpointer);
10216 info->plt_size = acfg->plt_offset;
10217 info->nmethods = acfg->nmethods;
10218 info->flags = acfg->flags;
10219 info->opts = acfg->opts;
10220 info->simd_opts = acfg->simd_opts;
10221 info->gc_name_index = acfg->gc_name_offset;
10222 info->datafile_size = acfg->datafile_offset;
10223 for (i = 0; i < MONO_AOT_TABLE_NUM; ++i)
10224 info->table_offsets [i] = acfg->table_offsets [i];
10225 for (i = 0; i < MONO_AOT_TRAMP_NUM; ++i)
10226 info->num_trampolines [i] = acfg->num_trampolines [i];
10227 for (i = 0; i < MONO_AOT_TRAMP_NUM; ++i)
10228 info->trampoline_got_offset_base [i] = acfg->trampoline_got_offset_base [i];
10229 for (i = 0; i < MONO_AOT_TRAMP_NUM; ++i)
10230 info->trampoline_size [i] = acfg->trampoline_size [i];
10231 info->num_rgctx_fetch_trampolines = acfg->aot_opts.nrgctx_fetch_trampolines;
10232
10233 info->double_align = MONO_ABI_ALIGNOF (double);
10234 info->long_align = MONO_ABI_ALIGNOF (gint64);
10235 info->generic_tramp_num = MONO_TRAMPOLINE_NUM;
10236 info->tramp_page_size = acfg->tramp_page_size;
10237 info->nshared_got_entries = acfg->nshared_got_entries;
10238 for (i = 0; i < MONO_AOT_TRAMP_NUM; ++i)
10239 info->tramp_page_code_offsets [i] = acfg->tramp_page_code_offsets [i];
10240
10241 memcpy(&info->aotid, acfg->image->aotid, 16);
10242 }
10243
10244 static void
emit_aot_file_info(MonoAotCompile * acfg,MonoAotFileInfo * info)10245 emit_aot_file_info (MonoAotCompile *acfg, MonoAotFileInfo *info)
10246 {
10247 char symbol [MAX_SYMBOL_SIZE];
10248 int i, sindex;
10249 const char **symbols;
10250
10251 symbols = g_new0 (const char *, MONO_AOT_FILE_INFO_NUM_SYMBOLS);
10252 sindex = 0;
10253 symbols [sindex ++] = acfg->got_symbol;
10254 if (acfg->llvm) {
10255 symbols [sindex ++] = g_strdup_printf ("%s%s", acfg->user_symbol_prefix, acfg->llvm_got_symbol);
10256 symbols [sindex ++] = acfg->llvm_eh_frame_symbol;
10257 } else {
10258 symbols [sindex ++] = NULL;
10259 symbols [sindex ++] = NULL;
10260 }
10261 /* llvm_get_method */
10262 symbols [sindex ++] = NULL;
10263 /* llvm_get_unbox_tramp */
10264 symbols [sindex ++] = NULL;
10265 if (!acfg->aot_opts.llvm_only) {
10266 symbols [sindex ++] = "jit_code_start";
10267 symbols [sindex ++] = "jit_code_end";
10268 symbols [sindex ++] = "method_addresses";
10269 } else {
10270 symbols [sindex ++] = NULL;
10271 symbols [sindex ++] = NULL;
10272 symbols [sindex ++] = NULL;
10273 }
10274
10275 if (acfg->data_outfile) {
10276 for (i = 0; i < MONO_AOT_TABLE_NUM; ++i)
10277 symbols [sindex ++] = NULL;
10278 } else {
10279 symbols [sindex ++] = "blob";
10280 symbols [sindex ++] = "class_name_table";
10281 symbols [sindex ++] = "class_info_offsets";
10282 symbols [sindex ++] = "method_info_offsets";
10283 symbols [sindex ++] = "ex_info_offsets";
10284 symbols [sindex ++] = "extra_method_info_offsets";
10285 symbols [sindex ++] = "extra_method_table";
10286 symbols [sindex ++] = "got_info_offsets";
10287 if (acfg->llvm)
10288 symbols [sindex ++] = "llvm_got_info_offsets";
10289 else
10290 symbols [sindex ++] = NULL;
10291 symbols [sindex ++] = "image_table";
10292 symbols [sindex ++] = "weak_field_indexes";
10293 }
10294
10295 symbols [sindex ++] = "mem_end";
10296 symbols [sindex ++] = "assembly_guid";
10297 symbols [sindex ++] = "runtime_version";
10298 if (acfg->num_trampoline_got_entries) {
10299 symbols [sindex ++] = "specific_trampolines";
10300 symbols [sindex ++] = "static_rgctx_trampolines";
10301 symbols [sindex ++] = "imt_trampolines";
10302 symbols [sindex ++] = "gsharedvt_arg_trampolines";
10303 } else {
10304 symbols [sindex ++] = NULL;
10305 symbols [sindex ++] = NULL;
10306 symbols [sindex ++] = NULL;
10307 symbols [sindex ++] = NULL;
10308 }
10309 if (acfg->aot_opts.static_link) {
10310 symbols [sindex ++] = "globals";
10311 } else {
10312 symbols [sindex ++] = NULL;
10313 }
10314 symbols [sindex ++] = "assembly_name";
10315 symbols [sindex ++] = "plt";
10316 symbols [sindex ++] = "plt_end";
10317 symbols [sindex ++] = "unwind_info";
10318 if (!acfg->aot_opts.llvm_only) {
10319 symbols [sindex ++] = "unbox_trampolines";
10320 symbols [sindex ++] = "unbox_trampolines_end";
10321 symbols [sindex ++] = "unbox_trampoline_addresses";
10322 } else {
10323 symbols [sindex ++] = NULL;
10324 symbols [sindex ++] = NULL;
10325 symbols [sindex ++] = NULL;
10326 }
10327
10328 g_assert (sindex == MONO_AOT_FILE_INFO_NUM_SYMBOLS);
10329
10330 sprintf (symbol, "%smono_aot_file_info", acfg->user_symbol_prefix);
10331 emit_section_change (acfg, ".data", 0);
10332 emit_alignment (acfg, 8);
10333 emit_label (acfg, symbol);
10334 if (!acfg->aot_opts.static_link)
10335 emit_global (acfg, symbol, FALSE);
10336
10337 /* The data emitted here must match MonoAotFileInfo. */
10338
10339 emit_int32 (acfg, info->version);
10340 emit_int32 (acfg, info->dummy);
10341
10342 /*
10343 * We emit pointers to our data structures instead of emitting global symbols which
10344 * point to them, to reduce the number of globals, and because using globals leads to
10345 * various problems (i.e. arm/thumb).
10346 */
10347 for (i = 0; i < MONO_AOT_FILE_INFO_NUM_SYMBOLS; ++i)
10348 emit_pointer (acfg, symbols [i]);
10349
10350 emit_int32 (acfg, info->plt_got_offset_base);
10351 emit_int32 (acfg, info->got_size);
10352 emit_int32 (acfg, info->plt_size);
10353 emit_int32 (acfg, info->nmethods);
10354 emit_int32 (acfg, info->flags);
10355 emit_int32 (acfg, info->opts);
10356 emit_int32 (acfg, info->simd_opts);
10357 emit_int32 (acfg, info->gc_name_index);
10358 emit_int32 (acfg, info->num_rgctx_fetch_trampolines);
10359 emit_int32 (acfg, info->double_align);
10360 emit_int32 (acfg, info->long_align);
10361 emit_int32 (acfg, info->generic_tramp_num);
10362 emit_int32 (acfg, info->tramp_page_size);
10363 emit_int32 (acfg, info->nshared_got_entries);
10364 emit_int32 (acfg, info->datafile_size);
10365
10366 for (i = 0; i < MONO_AOT_TABLE_NUM; ++i)
10367 emit_int32 (acfg, info->table_offsets [i]);
10368 for (i = 0; i < MONO_AOT_TRAMP_NUM; ++i)
10369 emit_int32 (acfg, info->num_trampolines [i]);
10370 for (i = 0; i < MONO_AOT_TRAMP_NUM; ++i)
10371 emit_int32 (acfg, info->trampoline_got_offset_base [i]);
10372 for (i = 0; i < MONO_AOT_TRAMP_NUM; ++i)
10373 emit_int32 (acfg, info->trampoline_size [i]);
10374 for (i = 0; i < MONO_AOT_TRAMP_NUM; ++i)
10375 emit_int32 (acfg, info->tramp_page_code_offsets [i]);
10376
10377 emit_bytes (acfg, info->aotid, 16);
10378
10379 if (acfg->aot_opts.static_link) {
10380 emit_global_inner (acfg, acfg->static_linking_symbol, FALSE);
10381 emit_alignment (acfg, sizeof (gpointer));
10382 emit_label (acfg, acfg->static_linking_symbol);
10383 emit_pointer_2 (acfg, acfg->user_symbol_prefix, "mono_aot_file_info");
10384 }
10385 }
10386
10387 /*
10388 * Emit a structure containing all the information not stored elsewhere.
10389 */
10390 static void
emit_file_info(MonoAotCompile * acfg)10391 emit_file_info (MonoAotCompile *acfg)
10392 {
10393 char *build_info;
10394 MonoAotFileInfo *info;
10395
10396 if (acfg->aot_opts.bind_to_runtime_version) {
10397 build_info = mono_get_runtime_build_info ();
10398 emit_string_symbol (acfg, "runtime_version", build_info);
10399 g_free (build_info);
10400 } else {
10401 emit_string_symbol (acfg, "runtime_version", "");
10402 }
10403
10404 emit_string_symbol (acfg, "assembly_guid" , acfg->image->guid);
10405
10406 /* Emit a string holding the assembly name */
10407 emit_string_symbol (acfg, "assembly_name", acfg->image->assembly->aname.name);
10408
10409 info = g_new0 (MonoAotFileInfo, 1);
10410 init_aot_file_info (acfg, info);
10411
10412 if (acfg->aot_opts.static_link) {
10413 char symbol [MAX_SYMBOL_SIZE];
10414 char *p;
10415
10416 /*
10417 * Emit a global symbol which can be passed by an embedding app to
10418 * mono_aot_register_module (). The symbol points to a pointer to the the file info
10419 * structure.
10420 */
10421 sprintf (symbol, "%smono_aot_module_%s_info", acfg->user_symbol_prefix, acfg->image->assembly->aname.name);
10422
10423 /* Get rid of characters which cannot occur in symbols */
10424 p = symbol;
10425 for (p = symbol; *p; ++p) {
10426 if (!(isalnum (*p) || *p == '_'))
10427 *p = '_';
10428 }
10429 acfg->static_linking_symbol = g_strdup (symbol);
10430 }
10431
10432 if (acfg->llvm)
10433 mono_llvm_emit_aot_file_info (info, acfg->has_jitted_code);
10434 else
10435 emit_aot_file_info (acfg, info);
10436 }
10437
10438 static void
emit_blob(MonoAotCompile * acfg)10439 emit_blob (MonoAotCompile *acfg)
10440 {
10441 acfg->blob_closed = TRUE;
10442
10443 emit_aot_data (acfg, MONO_AOT_TABLE_BLOB, "blob", (guint8*)acfg->blob.data, acfg->blob.index);
10444 }
10445
10446 static void
emit_objc_selectors(MonoAotCompile * acfg)10447 emit_objc_selectors (MonoAotCompile *acfg)
10448 {
10449 int i;
10450 char symbol [128];
10451
10452 if (!acfg->objc_selectors || acfg->objc_selectors->len == 0)
10453 return;
10454
10455 /*
10456 * From
10457 * cat > foo.m << EOF
10458 * void *ret ()
10459 * {
10460 * return @selector(print:);
10461 * }
10462 * EOF
10463 */
10464
10465 mono_img_writer_emit_unset_mode (acfg->w);
10466 g_assert (acfg->fp);
10467 fprintf (acfg->fp, ".section __DATA,__objc_selrefs,literal_pointers,no_dead_strip\n");
10468 fprintf (acfg->fp, ".align 3\n");
10469 for (i = 0; i < acfg->objc_selectors->len; ++i) {
10470 sprintf (symbol, "L_OBJC_SELECTOR_REFERENCES_%d", i);
10471 emit_label (acfg, symbol);
10472 sprintf (symbol, "L_OBJC_METH_VAR_NAME_%d", i);
10473 emit_pointer (acfg, symbol);
10474
10475 }
10476 fprintf (acfg->fp, ".section __TEXT,__cstring,cstring_literals\n");
10477 for (i = 0; i < acfg->objc_selectors->len; ++i) {
10478 fprintf (acfg->fp, "L_OBJC_METH_VAR_NAME_%d:\n", i);
10479 fprintf (acfg->fp, ".asciz \"%s\"\n", (char*)g_ptr_array_index (acfg->objc_selectors, i));
10480 }
10481
10482 fprintf (acfg->fp, ".section __DATA,__objc_imageinfo,regular,no_dead_strip\n");
10483 fprintf (acfg->fp, ".align 3\n");
10484 fprintf (acfg->fp, "L_OBJC_IMAGE_INFO:\n");
10485 fprintf (acfg->fp, ".long 0\n");
10486 fprintf (acfg->fp, ".long 16\n");
10487 }
10488
10489 static void
emit_dwarf_info(MonoAotCompile * acfg)10490 emit_dwarf_info (MonoAotCompile *acfg)
10491 {
10492 #ifdef EMIT_DWARF_INFO
10493 int i;
10494 char symbol2 [128];
10495
10496 /* DIEs for methods */
10497 for (i = 0; i < acfg->nmethods; ++i) {
10498 MonoCompile *cfg = acfg->cfgs [i];
10499
10500 if (ignore_cfg (cfg))
10501 continue;
10502
10503 // FIXME: LLVM doesn't define .Lme_...
10504 if (cfg->compile_llvm)
10505 continue;
10506
10507 sprintf (symbol2, "%sme_%x", acfg->temp_prefix, i);
10508
10509 mono_dwarf_writer_emit_method (acfg->dwarf, cfg, cfg->method, cfg->asm_symbol, symbol2, cfg->asm_debug_symbol, (guint8 *)cfg->jit_info->code_start, cfg->jit_info->code_size, cfg->args, cfg->locals, cfg->unwind_ops, mono_debug_find_method (cfg->jit_info->d.method, mono_domain_get ()));
10510 }
10511 #endif
10512 }
10513
10514 #ifdef EMIT_WIN32_CODEVIEW_INFO
10515 typedef struct _CodeViewSubSectionData
10516 {
10517 gchar *start_section;
10518 gchar *end_section;
10519 gchar *start_section_record;
10520 gchar *end_section_record;
10521 int section_type;
10522 int section_record_type;
10523 int section_id;
10524 } CodeViewSubsectionData;
10525
10526 typedef struct _CodeViewCompilerVersion
10527 {
10528 gint major;
10529 gint minor;
10530 gint revision;
10531 gint patch;
10532 } CodeViewCompilerVersion;
10533
10534 #define CODEVIEW_SUBSECTION_SYMBOL_TYPE 0xF1
10535 #define CODEVIEW_SUBSECTION_RECORD_COMPILER_TYPE 0x113c
10536 #define CODEVIEW_SUBSECTION_RECORD_FUNCTION_START_TYPE 0x1147
10537 #define CODEVIEW_SUBSECTION_RECORD_FUNCTION_END_TYPE 0x114F
10538 #define CODEVIEW_CSHARP_LANGUAGE_TYPE 0x0A
10539 #define CODEVIEW_CPU_TYPE 0x0
10540 #define CODEVIEW_MAGIC_HEADER 0x4
10541
10542 static void
codeview_clear_subsection_data(CodeViewSubsectionData * section_data)10543 codeview_clear_subsection_data (CodeViewSubsectionData *section_data)
10544 {
10545 g_free (section_data->start_section);
10546 g_free (section_data->end_section);
10547 g_free (section_data->start_section_record);
10548 g_free (section_data->end_section_record);
10549
10550 memset (section_data, 0, sizeof (CodeViewSubsectionData));
10551 }
10552
10553 static void
codeview_parse_compiler_version(gchar * version,CodeViewCompilerVersion * data)10554 codeview_parse_compiler_version (gchar *version, CodeViewCompilerVersion *data)
10555 {
10556 gint values[4] = { 0 };
10557 gint *value = values;
10558
10559 while (*version && (value < values + G_N_ELEMENTS (values))) {
10560 if (isdigit (*version)) {
10561 *value *= 10;
10562 *value += *version - '0';
10563 }
10564 else if (*version == '.') {
10565 value++;
10566 }
10567
10568 version++;
10569 }
10570
10571 data->major = values[0];
10572 data->minor = values[1];
10573 data->revision = values[2];
10574 data->patch = values[3];
10575 }
10576
10577 static void
emit_codeview_start_subsection(MonoAotCompile * acfg,int section_id,int section_type,int section_record_type,CodeViewSubsectionData * section_data)10578 emit_codeview_start_subsection (MonoAotCompile *acfg, int section_id, int section_type, int section_record_type, CodeViewSubsectionData *section_data)
10579 {
10580 // Starting a new subsection, clear old data.
10581 codeview_clear_subsection_data (section_data);
10582
10583 // Keep subsection data.
10584 section_data->section_id = section_id;
10585 section_data->section_type = section_type;
10586 section_data->section_record_type = section_record_type;
10587
10588 // Allocate all labels used in subsection.
10589 section_data->start_section = g_strdup_printf ("%scvs_%d", acfg->temp_prefix, section_data->section_id);
10590 section_data->end_section = g_strdup_printf ("%scvse_%d", acfg->temp_prefix, section_data->section_id);
10591 section_data->start_section_record = g_strdup_printf ("%scvsr_%d", acfg->temp_prefix, section_data->section_id);
10592 section_data->end_section_record = g_strdup_printf ("%scvsre_%d", acfg->temp_prefix, section_data->section_id);
10593
10594 // Subsection type, function symbol.
10595 emit_int32 (acfg, section_data->section_type);
10596
10597 // Subsection size.
10598 emit_symbol_diff (acfg, section_data->end_section, section_data->start_section, 0);
10599 emit_label (acfg, section_data->start_section);
10600
10601 // Subsection record size.
10602 fprintf (acfg->fp, "\t.word %s - %s\n", section_data->end_section_record, section_data->start_section_record);
10603 emit_label (acfg, section_data->start_section_record);
10604
10605 // Subsection record type.
10606 emit_int16 (acfg, section_record_type);
10607 }
10608
10609 static void
emit_codeview_end_subsection(MonoAotCompile * acfg,CodeViewSubsectionData * section_data,int * section_id)10610 emit_codeview_end_subsection (MonoAotCompile *acfg, CodeViewSubsectionData *section_data, int *section_id)
10611 {
10612 g_assert (section_data->start_section);
10613 g_assert (section_data->end_section);
10614 g_assert (section_data->start_section_record);
10615 g_assert (section_data->end_section_record);
10616
10617 emit_label (acfg, section_data->end_section_record);
10618
10619 if (section_data->section_record_type == CODEVIEW_SUBSECTION_RECORD_FUNCTION_START_TYPE) {
10620 // Emit record length.
10621 emit_int16 (acfg, 2);
10622
10623 // Emit specific record type end.
10624 emit_int16 (acfg, CODEVIEW_SUBSECTION_RECORD_FUNCTION_END_TYPE);
10625 }
10626
10627 emit_label (acfg, section_data->end_section);
10628
10629 // Next subsection needs to be 4 byte aligned.
10630 emit_alignment (acfg, 4);
10631
10632 *section_id = section_data->section_id + 1;
10633 codeview_clear_subsection_data (section_data);
10634 }
10635
10636 inline static void
emit_codeview_start_symbol_subsection(MonoAotCompile * acfg,int section_id,int section_record_type,CodeViewSubsectionData * section_data)10637 emit_codeview_start_symbol_subsection (MonoAotCompile *acfg, int section_id, int section_record_type, CodeViewSubsectionData *section_data)
10638 {
10639 emit_codeview_start_subsection (acfg, section_id, CODEVIEW_SUBSECTION_SYMBOL_TYPE, section_record_type, section_data);
10640 }
10641
10642 inline static void
emit_codeview_end_symbol_subsection(MonoAotCompile * acfg,CodeViewSubsectionData * section_data,int * section_id)10643 emit_codeview_end_symbol_subsection (MonoAotCompile *acfg, CodeViewSubsectionData *section_data, int *section_id)
10644 {
10645 emit_codeview_end_subsection (acfg, section_data, section_id);
10646 }
10647
10648 static void
emit_codeview_compiler_info(MonoAotCompile * acfg,int * section_id)10649 emit_codeview_compiler_info (MonoAotCompile *acfg, int *section_id)
10650 {
10651 CodeViewSubsectionData section_data = { 0 };
10652 CodeViewCompilerVersion compiler_version = { 0 };
10653
10654 // Start new compiler record subsection.
10655 emit_codeview_start_symbol_subsection (acfg, *section_id, CODEVIEW_SUBSECTION_RECORD_COMPILER_TYPE, §ion_data);
10656
10657 emit_int32 (acfg, CODEVIEW_CSHARP_LANGUAGE_TYPE);
10658 emit_int16 (acfg, CODEVIEW_CPU_TYPE);
10659
10660 // Get compiler version information.
10661 codeview_parse_compiler_version (VERSION, &compiler_version);
10662
10663 // Compiler frontend version, 4 digits.
10664 emit_int16 (acfg, compiler_version.major);
10665 emit_int16 (acfg, compiler_version.minor);
10666 emit_int16 (acfg, compiler_version.revision);
10667 emit_int16 (acfg, compiler_version.patch);
10668
10669 // Compiler backend version, 4 digits (currently same as frontend).
10670 emit_int16 (acfg, compiler_version.major);
10671 emit_int16 (acfg, compiler_version.minor);
10672 emit_int16 (acfg, compiler_version.revision);
10673 emit_int16 (acfg, compiler_version.patch);
10674
10675 // Compiler string.
10676 emit_string (acfg, "Mono AOT compiler");
10677
10678 // Done with section.
10679 emit_codeview_end_symbol_subsection (acfg, §ion_data, section_id);
10680 }
10681
10682 static void
emit_codeview_function_info(MonoAotCompile * acfg,MonoMethod * method,int * section_id,gchar * symbol,gchar * symbol_start,gchar * symbol_end)10683 emit_codeview_function_info (MonoAotCompile *acfg, MonoMethod *method, int *section_id, gchar *symbol, gchar *symbol_start, gchar *symbol_end)
10684 {
10685 CodeViewSubsectionData section_data = { 0 };
10686 gchar *full_method_name = NULL;
10687
10688 // Start new function record subsection.
10689 emit_codeview_start_symbol_subsection (acfg, *section_id, CODEVIEW_SUBSECTION_RECORD_FUNCTION_START_TYPE, §ion_data);
10690
10691 // Emit 3 int 0 byte padding, currently not used.
10692 emit_zero_bytes (acfg, sizeof (int) * 3);
10693
10694 // Emit size of function.
10695 emit_symbol_diff (acfg, symbol_end, symbol_start, 0);
10696
10697 // Emit 3 int 0 byte padding, currently not used.
10698 emit_zero_bytes (acfg, sizeof (int) * 3);
10699
10700 // Emit reallocation info.
10701 fprintf (acfg->fp, "\t.secrel32 %s\n", symbol);
10702 fprintf (acfg->fp, "\t.secidx %s\n", symbol);
10703
10704 // Emit flag, currently not used.
10705 emit_zero_bytes (acfg, 1);
10706
10707 // Emit function name, exclude signature since it should be described by own metadata.
10708 full_method_name = mono_method_full_name (method, FALSE);
10709 emit_string (acfg, full_method_name ? full_method_name : "");
10710 g_free (full_method_name);
10711
10712 // Done with section.
10713 emit_codeview_end_symbol_subsection (acfg, §ion_data, section_id);
10714 }
10715
10716 static void
emit_codeview_info(MonoAotCompile * acfg)10717 emit_codeview_info (MonoAotCompile *acfg)
10718 {
10719 int i;
10720 int section_id = 0;
10721 gchar symbol_buffer[MAX_SYMBOL_SIZE];
10722
10723 // Emit codeview debug info section
10724 emit_section_change (acfg, ".debug$S", 0);
10725
10726 // Emit magic header.
10727 emit_int32 (acfg, CODEVIEW_MAGIC_HEADER);
10728
10729 emit_codeview_compiler_info (acfg, §ion_id);
10730
10731 for (i = 0; i < acfg->nmethods; ++i) {
10732 MonoCompile *cfg = acfg->cfgs[i];
10733
10734 if (!cfg)
10735 continue;
10736
10737 int ret = g_snprintf (symbol_buffer, G_N_ELEMENTS (symbol_buffer), "%sme_%x", acfg->temp_prefix, i);
10738 if (ret > 0 && ret < G_N_ELEMENTS (symbol_buffer))
10739 emit_codeview_function_info (acfg, cfg->method, §ion_id, cfg->asm_debug_symbol, cfg->asm_symbol, symbol_buffer);
10740 }
10741 }
10742 #else
10743 static void
emit_codeview_info(MonoAotCompile * acfg)10744 emit_codeview_info (MonoAotCompile *acfg)
10745 {
10746 }
10747 #endif /* EMIT_WIN32_CODEVIEW_INFO */
10748
10749 #ifdef EMIT_WIN32_UNWIND_INFO
10750 static UnwindInfoSectionCacheItem *
get_cached_unwind_info_section_item_win32(MonoAotCompile * acfg,const char * function_start,const char * function_end,GSList * unwind_ops)10751 get_cached_unwind_info_section_item_win32 (MonoAotCompile *acfg, const char *function_start, const char *function_end, GSList *unwind_ops)
10752 {
10753 UnwindInfoSectionCacheItem *item = NULL;
10754
10755 if (!acfg->unwind_info_section_cache)
10756 acfg->unwind_info_section_cache = g_list_alloc ();
10757
10758 PUNWIND_INFO unwind_info = mono_arch_unwindinfo_alloc_unwind_info (unwind_ops);
10759
10760 // Search for unwind info in cache.
10761 GList *list = acfg->unwind_info_section_cache;
10762 int list_size = 0;
10763 while (list && list->data) {
10764 item = (UnwindInfoSectionCacheItem*)list->data;
10765 if (!memcmp (unwind_info, item->unwind_info, sizeof (UNWIND_INFO))) {
10766 // Cache hit, return cached item.
10767 return item;
10768 }
10769 list = list->next;
10770 list_size++;
10771 }
10772
10773 // Add to cache.
10774 if (acfg->unwind_info_section_cache) {
10775 item = g_new0 (UnwindInfoSectionCacheItem, 1);
10776 if (item) {
10777 // Format .xdata section label for function, used to get unwind info address RVA.
10778 // Since the unwind info is similar for most functions, the symbol will be reused.
10779 item->xdata_section_label = g_strdup_printf ("%sunwind_%d", acfg->temp_prefix, list_size);
10780
10781 // Cache unwind info data, used when checking cache for matching unwind info. NOTE, cache takes
10782 //over ownership of unwind info.
10783 item->unwind_info = unwind_info;
10784
10785 // Needs to be emitted once.
10786 item->xdata_section_emitted = FALSE;
10787
10788 // Prepend to beginning of list to speed up inserts.
10789 acfg->unwind_info_section_cache = g_list_prepend (acfg->unwind_info_section_cache, (gpointer)item);
10790 }
10791 }
10792
10793 return item;
10794 }
10795
10796 static void
free_unwind_info_section_cache_win32(MonoAotCompile * acfg)10797 free_unwind_info_section_cache_win32 (MonoAotCompile *acfg)
10798 {
10799 GList *list = acfg->unwind_info_section_cache;
10800
10801 while (list) {
10802 UnwindInfoSectionCacheItem *item = (UnwindInfoSectionCacheItem *)list->data;
10803 if (item) {
10804 g_free (item->xdata_section_label);
10805 mono_arch_unwindinfo_free_unwind_info (item->unwind_info);
10806
10807 g_free (item);
10808 list->data = NULL;
10809 }
10810
10811 list = list->next;
10812 }
10813
10814 g_list_free (acfg->unwind_info_section_cache);
10815 acfg->unwind_info_section_cache = NULL;
10816 }
10817
10818 static void
emit_unwind_info_data_win32(MonoAotCompile * acfg,PUNWIND_INFO unwind_info)10819 emit_unwind_info_data_win32 (MonoAotCompile *acfg, PUNWIND_INFO unwind_info)
10820 {
10821 // Emit the unwind info struct.
10822 emit_bytes (acfg, (guint8*)unwind_info, sizeof (UNWIND_INFO) - (sizeof (UNWIND_CODE) * MONO_MAX_UNWIND_CODES));
10823
10824 // Emit all unwind codes encoded in unwind info struct.
10825 PUNWIND_CODE current_unwind_node = &unwind_info->UnwindCode[MONO_MAX_UNWIND_CODES - unwind_info->CountOfCodes];
10826 PUNWIND_CODE last_unwind_node = &unwind_info->UnwindCode[MONO_MAX_UNWIND_CODES];
10827
10828 while (current_unwind_node < last_unwind_node) {
10829 guint8 node_count = 0;
10830 switch (current_unwind_node->UnwindOp) {
10831 case UWOP_PUSH_NONVOL:
10832 case UWOP_ALLOC_SMALL:
10833 case UWOP_SET_FPREG:
10834 case UWOP_PUSH_MACHFRAME:
10835 node_count = 1;
10836 break;
10837 case UWOP_SAVE_NONVOL:
10838 case UWOP_SAVE_XMM128:
10839 node_count = 2;
10840 break;
10841 case UWOP_SAVE_NONVOL_FAR:
10842 case UWOP_SAVE_XMM128_FAR:
10843 node_count = 3;
10844 break;
10845 case UWOP_ALLOC_LARGE:
10846 if (current_unwind_node->OpInfo == 0)
10847 node_count = 2;
10848 else
10849 node_count = 3;
10850 break;
10851 default:
10852 g_assert (!"Unknown unwind opcode.");
10853 }
10854
10855 while (node_count > 0) {
10856 g_assert (current_unwind_node < last_unwind_node);
10857
10858 //Emit current node.
10859 emit_bytes (acfg, (guint8*)current_unwind_node, sizeof (UNWIND_CODE));
10860
10861 node_count--;
10862 current_unwind_node++;
10863 }
10864 }
10865 }
10866
10867 // Emit unwind info sections for each function. Unwind info on Windows x64 is emitted into two different sections.
10868 // .pdata includes the serialized DWORD aligned RVA's of function start, end and address of serialized
10869 // UNWIND_INFO struct emitted into .xdata, see https://msdn.microsoft.com/en-us/library/ft9x1kdx.aspx.
10870 // .xdata section includes DWORD aligned serialized version of UNWIND_INFO struct, https://msdn.microsoft.com/en-us/library/ddssxxy8.aspx.
10871 static void
emit_unwind_info_sections_win32(MonoAotCompile * acfg,const char * function_start,const char * function_end,GSList * unwind_ops)10872 emit_unwind_info_sections_win32 (MonoAotCompile *acfg, const char *function_start, const char *function_end, GSList *unwind_ops)
10873 {
10874 char *pdata_section_label = NULL;
10875
10876 int temp_prefix_len = (acfg->temp_prefix != NULL) ? strlen (acfg->temp_prefix) : 0;
10877 if (strncmp (function_start, acfg->temp_prefix, temp_prefix_len)) {
10878 temp_prefix_len = 0;
10879 }
10880
10881 // Format .pdata section label for function.
10882 pdata_section_label = g_strdup_printf ("%spdata_%s", acfg->temp_prefix, function_start + temp_prefix_len);
10883
10884 UnwindInfoSectionCacheItem *cache_item = get_cached_unwind_info_section_item_win32 (acfg, function_start, function_end, unwind_ops);
10885 g_assert (cache_item && cache_item->xdata_section_label && cache_item->unwind_info);
10886
10887 // Emit .pdata section.
10888 emit_section_change (acfg, ".pdata", 0);
10889 emit_alignment (acfg, sizeof (DWORD));
10890 emit_label (acfg, pdata_section_label);
10891
10892 // Emit function start address RVA.
10893 fprintf (acfg->fp, "\t.long %s@IMGREL\n", function_start);
10894
10895 // Emit function end address RVA.
10896 fprintf (acfg->fp, "\t.long %s@IMGREL\n", function_end);
10897
10898 // Emit unwind info address RVA.
10899 fprintf (acfg->fp, "\t.long %s@IMGREL\n", cache_item->xdata_section_label);
10900
10901 if (!cache_item->xdata_section_emitted) {
10902 // Emit .xdata section.
10903 emit_section_change (acfg, ".xdata", 0);
10904 emit_alignment (acfg, sizeof (DWORD));
10905 emit_label (acfg, cache_item->xdata_section_label);
10906
10907 // Emit unwind info into .xdata section.
10908 emit_unwind_info_data_win32 (acfg, cache_item->unwind_info);
10909 cache_item->xdata_section_emitted = TRUE;
10910 }
10911
10912 g_free (pdata_section_label);
10913 }
10914 #endif
10915
10916 static gboolean
collect_methods(MonoAotCompile * acfg)10917 collect_methods (MonoAotCompile *acfg)
10918 {
10919 int mindex, i;
10920 MonoImage *image = acfg->image;
10921
10922 /* Collect methods */
10923 for (i = 0; i < image->tables [MONO_TABLE_METHOD].rows; ++i) {
10924 MonoError error;
10925 MonoMethod *method;
10926 guint32 token = MONO_TOKEN_METHOD_DEF | (i + 1);
10927
10928 method = mono_get_method_checked (acfg->image, token, NULL, NULL, &error);
10929
10930 if (!method) {
10931 aot_printerrf (acfg, "Failed to load method 0x%x from '%s' due to %s.\n", token, image->name, mono_error_get_message (&error));
10932 aot_printerrf (acfg, "Run with MONO_LOG_LEVEL=debug for more information.\n");
10933 mono_error_cleanup (&error);
10934 return FALSE;
10935 }
10936
10937 /* Load all methods eagerly to skip the slower lazy loading code */
10938 mono_class_setup_methods (method->klass);
10939
10940 if (mono_aot_mode_is_full (&acfg->aot_opts) && method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
10941 /* Compile the wrapper instead */
10942 /* We do this here instead of add_wrappers () because it is easy to do it here */
10943 MonoMethod *wrapper = mono_marshal_get_native_wrapper (method, TRUE, TRUE);
10944 method = wrapper;
10945 }
10946
10947 /* FIXME: Some mscorlib methods don't have debug info */
10948 /*
10949 if (acfg->aot_opts.soft_debug && !method->wrapper_type) {
10950 if (!((method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
10951 (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
10952 (method->flags & METHOD_ATTRIBUTE_ABSTRACT) ||
10953 (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL))) {
10954 if (!mono_debug_lookup_method (method)) {
10955 fprintf (stderr, "Method %s has no debug info, probably the .mdb file for the assembly is missing.\n", mono_method_get_full_name (method));
10956 exit (1);
10957 }
10958 }
10959 }
10960 */
10961
10962 if (method->is_generic || mono_class_is_gtd (method->klass))
10963 /* Compile the ref shared version instead */
10964 method = mini_get_shared_method (method);
10965
10966 /* Since we add the normal methods first, their index will be equal to their zero based token index */
10967 add_method_with_index (acfg, method, i, FALSE);
10968 acfg->method_index ++;
10969 }
10970
10971 /* gsharedvt methods */
10972 for (mindex = 0; mindex < image->tables [MONO_TABLE_METHOD].rows; ++mindex) {
10973 MonoError error;
10974 MonoMethod *method;
10975 guint32 token = MONO_TOKEN_METHOD_DEF | (mindex + 1);
10976
10977 if (!(acfg->opts & MONO_OPT_GSHAREDVT))
10978 continue;
10979
10980 method = mono_get_method_checked (acfg->image, token, NULL, NULL, &error);
10981 report_loader_error (acfg, &error, TRUE, "Failed to load method token 0x%x due to %s\n", i, mono_error_get_message (&error));
10982
10983 if (method->is_generic || mono_class_is_gtd (method->klass)) {
10984 MonoMethod *gshared;
10985
10986 gshared = mini_get_shared_method_full (method, TRUE, TRUE);
10987 add_extra_method (acfg, gshared);
10988 }
10989 }
10990
10991 if (mono_aot_mode_is_full (&acfg->aot_opts) || mono_aot_mode_is_hybrid (&acfg->aot_opts))
10992 add_generic_instances (acfg);
10993
10994 if (mono_aot_mode_is_full (&acfg->aot_opts))
10995 add_wrappers (acfg);
10996 return TRUE;
10997 }
10998
10999 static void
compile_methods(MonoAotCompile * acfg)11000 compile_methods (MonoAotCompile *acfg)
11001 {
11002 int i, methods_len;
11003
11004 if (acfg->aot_opts.nthreads > 0) {
11005 GPtrArray *frag;
11006 int len, j;
11007 GPtrArray *threads;
11008 MonoThreadHandle *thread_handle;
11009 gpointer *user_data;
11010 MonoMethod **methods;
11011
11012 methods_len = acfg->methods->len;
11013
11014 len = acfg->methods->len / acfg->aot_opts.nthreads;
11015 g_assert (len > 0);
11016 /*
11017 * Partition the list of methods into fragments, and hand it to threads to
11018 * process.
11019 */
11020 threads = g_ptr_array_new ();
11021 /* Make a copy since acfg->methods is modified by compile_method () */
11022 methods = g_new0 (MonoMethod*, methods_len);
11023 //memcpy (methods, g_ptr_array_index (acfg->methods, 0), sizeof (MonoMethod*) * methods_len);
11024 for (i = 0; i < methods_len; ++i)
11025 methods [i] = (MonoMethod *)g_ptr_array_index (acfg->methods, i);
11026 i = 0;
11027 while (i < methods_len) {
11028 MonoError error;
11029 MonoInternalThread *thread;
11030
11031 frag = g_ptr_array_new ();
11032 for (j = 0; j < len; ++j) {
11033 if (i < methods_len) {
11034 g_ptr_array_add (frag, methods [i]);
11035 i ++;
11036 }
11037 }
11038
11039 user_data = g_new0 (gpointer, 3);
11040 user_data [0] = acfg;
11041 user_data [1] = frag;
11042
11043 thread = mono_thread_create_internal (mono_domain_get (), compile_thread_main, (gpointer) user_data, MONO_THREAD_CREATE_FLAGS_NONE, &error);
11044 mono_error_assert_ok (&error);
11045
11046 thread_handle = mono_threads_open_thread_handle (thread->handle);
11047 g_ptr_array_add (threads, thread_handle);
11048 }
11049 g_free (methods);
11050
11051 for (i = 0; i < threads->len; ++i) {
11052 mono_thread_info_wait_one_handle (g_ptr_array_index (threads, i), MONO_INFINITE_WAIT, FALSE);
11053 mono_threads_close_thread_handle (g_ptr_array_index (threads, i));
11054 }
11055 } else {
11056 methods_len = 0;
11057 }
11058
11059 /* Compile methods added by compile_method () or all methods if nthreads == 0 */
11060 for (i = methods_len; i < acfg->methods->len; ++i) {
11061 /* This can add new methods to acfg->methods */
11062 compile_method (acfg, (MonoMethod *)g_ptr_array_index (acfg->methods, i));
11063 }
11064 }
11065
11066 static int
compile_asm(MonoAotCompile * acfg)11067 compile_asm (MonoAotCompile *acfg)
11068 {
11069 char *command, *objfile;
11070 char *outfile_name, *tmp_outfile_name, *llvm_ofile;
11071 const char *tool_prefix = acfg->aot_opts.tool_prefix ? acfg->aot_opts.tool_prefix : "";
11072 char *ld_flags = acfg->aot_opts.ld_flags ? acfg->aot_opts.ld_flags : g_strdup("");
11073
11074 #ifdef TARGET_WIN32_MSVC
11075 #define AS_OPTIONS "-c -x assembler"
11076 #elif defined(TARGET_AMD64) && !defined(TARGET_MACH)
11077 #define AS_OPTIONS "--64"
11078 #elif defined(TARGET_POWERPC64)
11079 #define AS_OPTIONS "-a64 -mppc64"
11080 #elif defined(sparc) && SIZEOF_VOID_P == 8
11081 #define AS_OPTIONS "-xarch=v9"
11082 #elif defined(TARGET_X86) && defined(TARGET_MACH)
11083 #define AS_OPTIONS "-arch i386"
11084 #else
11085 #define AS_OPTIONS ""
11086 #endif
11087
11088 #if defined(TARGET_OSX)
11089 #define AS_NAME "clang"
11090 #elif defined(TARGET_WIN32_MSVC)
11091 #define AS_NAME "clang.exe"
11092 #else
11093 #define AS_NAME "as"
11094 #endif
11095
11096 #ifdef TARGET_WIN32_MSVC
11097 #define AS_OBJECT_FILE_SUFFIX "obj"
11098 #else
11099 #define AS_OBJECT_FILE_SUFFIX "o"
11100 #endif
11101
11102 #if defined(sparc)
11103 #define LD_NAME "ld"
11104 #define LD_OPTIONS "-shared -G"
11105 #elif defined(__ppc__) && defined(TARGET_MACH)
11106 #define LD_NAME "gcc"
11107 #define LD_OPTIONS "-dynamiclib"
11108 #elif defined(TARGET_AMD64) && defined(TARGET_MACH)
11109 #define LD_NAME "clang"
11110 #define LD_OPTIONS "--shared"
11111 #elif defined(TARGET_WIN32_MSVC)
11112 #define LD_NAME "link.exe"
11113 #define LD_OPTIONS "/DLL /MACHINE:X64 /NOLOGO /INCREMENTAL:NO"
11114 #define LD_DEBUG_OPTIONS LD_OPTIONS " /DEBUG"
11115 #elif defined(TARGET_WIN32) && !defined(TARGET_ANDROID)
11116 #define LD_NAME "gcc"
11117 #define LD_OPTIONS "-shared"
11118 #elif defined(TARGET_X86) && defined(TARGET_MACH)
11119 #define LD_NAME "clang"
11120 #define LD_OPTIONS "-m32 -dynamiclib"
11121 #elif defined(TARGET_ARM) && !defined(TARGET_ANDROID)
11122 #define LD_NAME "gcc"
11123 #define LD_OPTIONS "--shared"
11124 #elif defined(TARGET_POWERPC64)
11125 #define LD_OPTIONS "-m elf64ppc"
11126 #endif
11127
11128 #ifndef LD_OPTIONS
11129 #define LD_OPTIONS ""
11130 #endif
11131
11132 if (acfg->aot_opts.asm_only) {
11133 aot_printf (acfg, "Output file: '%s'.\n", acfg->tmpfname);
11134 if (acfg->aot_opts.static_link)
11135 aot_printf (acfg, "Linking symbol: '%s'.\n", acfg->static_linking_symbol);
11136 if (acfg->llvm)
11137 aot_printf (acfg, "LLVM output file: '%s'.\n", acfg->llvm_sfile);
11138 return 0;
11139 }
11140
11141 if (acfg->aot_opts.static_link) {
11142 if (acfg->aot_opts.outfile)
11143 objfile = g_strdup_printf ("%s", acfg->aot_opts.outfile);
11144 else
11145 objfile = g_strdup_printf ("%s." AS_OBJECT_FILE_SUFFIX, acfg->image->name);
11146 } else {
11147 objfile = g_strdup_printf ("%s." AS_OBJECT_FILE_SUFFIX, acfg->tmpfname);
11148 }
11149
11150 #ifdef TARGET_OSX
11151 g_string_append (acfg->as_args, "-c -x assembler");
11152 #endif
11153
11154 command = g_strdup_printf ("\"%s%s\" %s %s -o %s %s", tool_prefix, AS_NAME, AS_OPTIONS,
11155 acfg->as_args ? acfg->as_args->str : "",
11156 wrap_path (objfile), wrap_path (acfg->tmpfname));
11157 aot_printf (acfg, "Executing the native assembler: %s\n", command);
11158 if (execute_system (command) != 0) {
11159 g_free (command);
11160 g_free (objfile);
11161 return 1;
11162 }
11163
11164 if (acfg->llvm && !acfg->llvm_owriter) {
11165 command = g_strdup_printf ("\"%s%s\" %s %s -o %s %s", tool_prefix, AS_NAME, AS_OPTIONS,
11166 acfg->as_args ? acfg->as_args->str : "",
11167 wrap_path (acfg->llvm_ofile), wrap_path (acfg->llvm_sfile));
11168 aot_printf (acfg, "Executing the native assembler: %s\n", command);
11169 if (execute_system (command) != 0) {
11170 g_free (command);
11171 g_free (objfile);
11172 return 1;
11173 }
11174 }
11175
11176 g_free (command);
11177
11178 if (acfg->aot_opts.static_link) {
11179 aot_printf (acfg, "Output file: '%s'.\n", objfile);
11180 aot_printf (acfg, "Linking symbol: '%s'.\n", acfg->static_linking_symbol);
11181 g_free (objfile);
11182 return 0;
11183 }
11184
11185 if (acfg->aot_opts.outfile)
11186 outfile_name = g_strdup_printf ("%s", acfg->aot_opts.outfile);
11187 else
11188 outfile_name = g_strdup_printf ("%s%s", acfg->image->name, MONO_SOLIB_EXT);
11189
11190 tmp_outfile_name = g_strdup_printf ("%s.tmp", outfile_name);
11191
11192 if (acfg->llvm) {
11193 llvm_ofile = g_strdup_printf ("\"%s\"", acfg->llvm_ofile);
11194 } else {
11195 llvm_ofile = g_strdup ("");
11196 }
11197
11198 /* replace the ; flags separators with spaces */
11199 g_strdelimit (ld_flags, ";", ' ');
11200
11201 if (acfg->aot_opts.llvm_only)
11202 ld_flags = g_strdup_printf ("%s %s", ld_flags, "-lstdc++");
11203
11204 #ifdef TARGET_WIN32_MSVC
11205 g_assert (tmp_outfile_name != NULL);
11206 g_assert (objfile != NULL);
11207 command = g_strdup_printf ("\"%s%s\" %s %s /OUT:\"%s\" \"%s\"", tool_prefix, LD_NAME,
11208 acfg->aot_opts.nodebug ? LD_OPTIONS : LD_DEBUG_OPTIONS, ld_flags, tmp_outfile_name, objfile);
11209 #elif defined(LD_NAME)
11210 command = g_strdup_printf ("%s%s %s -o %s %s %s %s", tool_prefix, LD_NAME, LD_OPTIONS,
11211 wrap_path (tmp_outfile_name), wrap_path (llvm_ofile),
11212 wrap_path (g_strdup_printf ("%s." AS_OBJECT_FILE_SUFFIX, acfg->tmpfname)), ld_flags);
11213 #else
11214 // Default (linux)
11215 if (acfg->aot_opts.tool_prefix) {
11216 /* Cross compiling */
11217 command = g_strdup_printf ("\"%sld\" %s -shared -o %s %s %s %s", tool_prefix, LD_OPTIONS,
11218 wrap_path (tmp_outfile_name), wrap_path (llvm_ofile),
11219 wrap_path (g_strdup_printf ("%s." AS_OBJECT_FILE_SUFFIX, acfg->tmpfname)), ld_flags);
11220 } else {
11221 char *args = g_strdup_printf ("%s -shared -o %s %s %s %s", LD_OPTIONS,
11222 wrap_path (tmp_outfile_name), wrap_path (llvm_ofile),
11223 wrap_path (g_strdup_printf ("%s." AS_OBJECT_FILE_SUFFIX, acfg->tmpfname)), ld_flags);
11224
11225 if (acfg->aot_opts.llvm_only) {
11226 command = g_strdup_printf ("clang++ %s", args);
11227 } else {
11228 command = g_strdup_printf ("\"%sld\" %s", tool_prefix, args);
11229 }
11230 g_free (args);
11231 }
11232 #endif
11233 aot_printf (acfg, "Executing the native linker: %s\n", command);
11234 if (execute_system (command) != 0) {
11235 g_free (tmp_outfile_name);
11236 g_free (outfile_name);
11237 g_free (command);
11238 g_free (objfile);
11239 g_free (ld_flags);
11240 return 1;
11241 }
11242
11243 g_free (command);
11244
11245 /*com = g_strdup_printf ("strip --strip-unneeded %s%s", acfg->image->name, MONO_SOLIB_EXT);
11246 printf ("Stripping the binary: %s\n", com);
11247 execute_system (com);
11248 g_free (com);*/
11249
11250 #if defined(TARGET_ARM) && !defined(TARGET_MACH)
11251 /*
11252 * gas generates 'mapping symbols' each time code and data is mixed, which
11253 * happens a lot in emit_and_reloc_code (), so we need to get rid of them.
11254 */
11255 command = g_strdup_printf ("\"%sstrip\" --strip-symbol=\\$a --strip-symbol=\\$d %s", wrap_path(tool_prefix), wrap_path(tmp_outfile_name));
11256 aot_printf (acfg, "Stripping the binary: %s\n", command);
11257 if (execute_system (command) != 0) {
11258 g_free (tmp_outfile_name);
11259 g_free (outfile_name);
11260 g_free (command);
11261 g_free (objfile);
11262 return 1;
11263 }
11264 #endif
11265
11266 if (0 != rename (tmp_outfile_name, outfile_name)) {
11267 if (G_FILE_ERROR_EXIST == g_file_error_from_errno (errno)) {
11268 /* Since we are rebuilding the module we need to be able to replace any old copies. Remove old file and retry rename operation. */
11269 unlink (outfile_name);
11270 rename (tmp_outfile_name, outfile_name);
11271 }
11272 }
11273
11274 #if defined(TARGET_MACH)
11275 command = g_strdup_printf ("dsymutil \"%s\"", outfile_name);
11276 aot_printf (acfg, "Executing dsymutil: %s\n", command);
11277 if (execute_system (command) != 0) {
11278 return 1;
11279 }
11280 #endif
11281
11282 if (!acfg->aot_opts.save_temps)
11283 unlink (objfile);
11284
11285 g_free (tmp_outfile_name);
11286 g_free (outfile_name);
11287 g_free (objfile);
11288
11289 if (acfg->aot_opts.save_temps)
11290 aot_printf (acfg, "Retained input file.\n");
11291 else
11292 unlink (acfg->tmpfname);
11293
11294 return 0;
11295 }
11296
11297 static guint8
profread_byte(FILE * infile)11298 profread_byte (FILE *infile)
11299 {
11300 guint8 i;
11301 int res;
11302
11303 res = fread (&i, 1, 1, infile);
11304 g_assert (res == 1);
11305 return i;
11306 }
11307
11308 static int
profread_int(FILE * infile)11309 profread_int (FILE *infile)
11310 {
11311 int i, res;
11312
11313 res = fread (&i, 4, 1, infile);
11314 g_assert (res == 1);
11315 return i;
11316 }
11317
11318 static char*
profread_string(FILE * infile)11319 profread_string (FILE *infile)
11320 {
11321 int len, res;
11322 char buf [1024];
11323 char *pbuf;
11324
11325 len = profread_int (infile);
11326 if (len + 1 > 1024)
11327 pbuf = g_malloc (len + 1);
11328 else
11329 pbuf = buf;
11330 res = fread (pbuf, 1, len, infile);
11331 g_assert (res == len);
11332 pbuf [len] = '\0';
11333 if (pbuf == buf)
11334 return g_strdup (buf);
11335 else
11336 return pbuf;
11337 }
11338
11339 static void
load_profile_file(MonoAotCompile * acfg,char * filename)11340 load_profile_file (MonoAotCompile *acfg, char *filename)
11341 {
11342 FILE *infile;
11343 char buf [1024];
11344 int res, len, version;
11345 char magic [32];
11346
11347 infile = fopen (filename, "r");
11348 if (!infile) {
11349 fprintf (stderr, "Unable to open file '%s': %s.\n", filename, strerror (errno));
11350 exit (1);
11351 }
11352
11353 printf ("Using profile data file '%s'\n", filename);
11354
11355 sprintf (magic, AOT_PROFILER_MAGIC);
11356 len = strlen (magic);
11357 res = fread (buf, 1, len, infile);
11358 magic [len] = '\0';
11359 buf [len] = '\0';
11360 if ((res != len) || strcmp (buf, magic) != 0) {
11361 printf ("Profile file has wrong header: '%s'.\n", buf);
11362 fclose (infile);
11363 exit (1);
11364 }
11365 guint32 expected_version = (AOT_PROFILER_MAJOR_VERSION << 16) | AOT_PROFILER_MINOR_VERSION;
11366 version = profread_int (infile);
11367 if (version != expected_version) {
11368 printf ("Profile file has wrong version 0x%4x, expected 0x%4x.\n", version, expected_version);
11369 fclose (infile);
11370 exit (1);
11371 }
11372
11373 ProfileData *data = g_new0 (ProfileData, 1);
11374 data->images = g_hash_table_new (NULL, NULL);
11375 data->classes = g_hash_table_new (NULL, NULL);
11376 data->ginsts = g_hash_table_new (NULL, NULL);
11377 data->methods = g_hash_table_new (NULL, NULL);
11378
11379 while (TRUE) {
11380 int type = profread_byte (infile);
11381 int id = profread_int (infile);
11382
11383 if (type == AOTPROF_RECORD_NONE)
11384 break;
11385
11386 switch (type) {
11387 case AOTPROF_RECORD_IMAGE: {
11388 ImageProfileData *idata = g_new0 (ImageProfileData, 1);
11389 idata->name = profread_string (infile);
11390 char *mvid = profread_string (infile);
11391 g_free (mvid);
11392 g_hash_table_insert (data->images, GINT_TO_POINTER (id), idata);
11393 break;
11394 }
11395 case AOTPROF_RECORD_GINST: {
11396 int i;
11397 int len = profread_int (infile);
11398
11399 GInstProfileData *gdata = g_new0 (GInstProfileData, 1);
11400 gdata->argc = len;
11401 gdata->argv = g_new0 (ClassProfileData*, len);
11402
11403 for (i = 0; i < len; ++i) {
11404 int class_id = profread_int (infile);
11405
11406 gdata->argv [i] = g_hash_table_lookup (data->classes, GINT_TO_POINTER (class_id));
11407 g_assert (gdata->argv [i]);
11408 }
11409 g_hash_table_insert (data->ginsts, GINT_TO_POINTER (id), gdata);
11410 break;
11411 }
11412 case AOTPROF_RECORD_TYPE: {
11413 int type = profread_byte (infile);
11414
11415 switch (type) {
11416 case MONO_TYPE_CLASS: {
11417 int image_id = profread_int (infile);
11418 int ginst_id = profread_int (infile);
11419 char *class_name = profread_string (infile);
11420
11421 ImageProfileData *image = g_hash_table_lookup (data->images, GINT_TO_POINTER (image_id));
11422 g_assert (image);
11423
11424 char *p = strrchr (class_name, '.');
11425 g_assert (p);
11426 *p = '\0';
11427
11428 ClassProfileData *cdata = g_new0 (ClassProfileData, 1);
11429 cdata->image = image;
11430 cdata->ns = g_strdup (class_name);
11431 cdata->name = g_strdup (p + 1);
11432
11433 if (ginst_id != -1) {
11434 cdata->inst = g_hash_table_lookup (data->ginsts, GINT_TO_POINTER (ginst_id));
11435 g_assert (cdata->inst);
11436 }
11437 g_free (class_name);
11438
11439 g_hash_table_insert (data->classes, GINT_TO_POINTER (id), cdata);
11440 break;
11441 }
11442 #if 0
11443 case MONO_TYPE_SZARRAY: {
11444 int elem_id = profread_int (infile);
11445 // FIXME:
11446 break;
11447 }
11448 #endif
11449 default:
11450 g_assert_not_reached ();
11451 break;
11452 }
11453 break;
11454 }
11455 case AOTPROF_RECORD_METHOD: {
11456 int class_id = profread_int (infile);
11457 int ginst_id = profread_int (infile);
11458 int param_count = profread_int (infile);
11459 char *method_name = profread_string (infile);
11460 char *sig = profread_string (infile);
11461
11462 ClassProfileData *klass = g_hash_table_lookup (data->classes, GINT_TO_POINTER (class_id));
11463 g_assert (klass);
11464
11465 MethodProfileData *mdata = g_new0 (MethodProfileData, 1);
11466 mdata->id = id;
11467 mdata->klass = klass;
11468 mdata->name = method_name;
11469 mdata->signature = sig;
11470 mdata->param_count = param_count;
11471
11472 if (ginst_id != -1) {
11473 mdata->inst = g_hash_table_lookup (data->ginsts, GINT_TO_POINTER (ginst_id));
11474 g_assert (mdata->inst);
11475 }
11476 g_hash_table_insert (data->methods, GINT_TO_POINTER (id), mdata);
11477 break;
11478 }
11479 default:
11480 printf ("%d\n", type);
11481 g_assert_not_reached ();
11482 break;
11483 }
11484 }
11485
11486 fclose (infile);
11487 acfg->profile_data = g_list_append (acfg->profile_data, data);
11488 }
11489
11490 static void
11491 resolve_class (ClassProfileData *cdata);
11492
11493 static void
resolve_ginst(GInstProfileData * inst_data)11494 resolve_ginst (GInstProfileData *inst_data)
11495 {
11496 int i;
11497
11498 if (inst_data->inst)
11499 return;
11500
11501 for (i = 0; i < inst_data->argc; ++i) {
11502 resolve_class (inst_data->argv [i]);
11503 if (!inst_data->argv [i]->klass)
11504 return;
11505 }
11506 MonoType **args = g_new0 (MonoType*, inst_data->argc);
11507 for (i = 0; i < inst_data->argc; ++i)
11508 args [i] = &inst_data->argv [i]->klass->byval_arg;
11509
11510 inst_data->inst = mono_metadata_get_generic_inst (inst_data->argc, args);
11511 }
11512
11513 static void
resolve_class(ClassProfileData * cdata)11514 resolve_class (ClassProfileData *cdata)
11515 {
11516 MonoError error;
11517 MonoClass *klass;
11518
11519 if (!cdata->image->image)
11520 return;
11521
11522 klass = mono_class_from_name_checked (cdata->image->image, cdata->ns, cdata->name, &error);
11523 if (!klass) {
11524 //printf ("[%s] %s.%s\n", cdata->image->name, cdata->ns, cdata->name);
11525 return;
11526 }
11527 if (cdata->inst) {
11528 resolve_ginst (cdata->inst);
11529 if (!cdata->inst->inst)
11530 return;
11531 MonoGenericContext ctx;
11532
11533 memset (&ctx, 0, sizeof (ctx));
11534 ctx.class_inst = cdata->inst->inst;
11535 cdata->klass = mono_class_inflate_generic_class_checked (klass, &ctx, &error);
11536 } else {
11537 cdata->klass = klass;
11538 }
11539 }
11540
11541 /*
11542 * Resolve the profile data to the corresponding loaded classes/methods etc. if possible.
11543 */
11544 static void
resolve_profile_data(MonoAotCompile * acfg,ProfileData * data)11545 resolve_profile_data (MonoAotCompile *acfg, ProfileData *data)
11546 {
11547 GHashTableIter iter;
11548 gpointer key, value;
11549 int i;
11550
11551 if (!data)
11552 return;
11553
11554 /* Images */
11555 GPtrArray *assemblies = mono_domain_get_assemblies (mono_get_root_domain (), FALSE);
11556 g_hash_table_iter_init (&iter, data->images);
11557 while (g_hash_table_iter_next (&iter, &key, &value)) {
11558 ImageProfileData *idata = (ImageProfileData*)value;
11559
11560 for (i = 0; i < assemblies->len; ++i) {
11561 MonoAssembly *ass = g_ptr_array_index (assemblies, i);
11562
11563 if (!strcmp (ass->aname.name, idata->name)) {
11564 idata->image = ass->image;
11565 break;
11566 }
11567 }
11568 }
11569 g_ptr_array_free (assemblies, TRUE);
11570
11571 /* Classes */
11572 g_hash_table_iter_init (&iter, data->classes);
11573 while (g_hash_table_iter_next (&iter, &key, &value)) {
11574 ClassProfileData *cdata = (ClassProfileData*)value;
11575
11576 if (!cdata->image->image) {
11577 if (acfg->aot_opts.verbose)
11578 printf ("Unable to load class '%s.%s' because its image '%s' is not loaded.\n", cdata->ns, cdata->name, cdata->image->name);
11579 continue;
11580 }
11581
11582 resolve_class (cdata);
11583 /*
11584 if (cdata->klass)
11585 printf ("%s %s %s\n", cdata->ns, cdata->name, mono_class_full_name (cdata->klass));
11586 */
11587 }
11588
11589 /* Methods */
11590 g_hash_table_iter_init (&iter, data->methods);
11591 while (g_hash_table_iter_next (&iter, &key, &value)) {
11592 MethodProfileData *mdata = (MethodProfileData*)value;
11593 MonoClass *klass;
11594 MonoMethod *m;
11595 gpointer miter;
11596
11597 resolve_class (mdata->klass);
11598 klass = mdata->klass->klass;
11599 if (!klass) {
11600 if (acfg->aot_opts.verbose)
11601 printf ("Unable to load method '%s' because its class '%s.%s' is not loaded.\n", mdata->name, mdata->klass->ns, mdata->klass->name);
11602 continue;
11603 }
11604 miter = NULL;
11605 while ((m = mono_class_get_methods (klass, &miter))) {
11606 MonoError error;
11607
11608 if (strcmp (m->name, mdata->name))
11609 continue;
11610 MonoMethodSignature *sig = mono_method_signature (m);
11611 if (!sig)
11612 continue;
11613 if (sig->param_count != mdata->param_count)
11614 continue;
11615 if (mdata->inst) {
11616 resolve_ginst (mdata->inst);
11617 if (!mdata->inst->inst)
11618 continue;
11619 MonoGenericContext ctx;
11620
11621 memset (&ctx, 0, sizeof (ctx));
11622 ctx.method_inst = mdata->inst->inst;
11623
11624 m = mono_class_inflate_generic_method_checked (m, &ctx, &error);
11625 if (!m)
11626 continue;
11627 sig = mono_method_signature_checked (m, &error);
11628 if (!is_ok (&error)) {
11629 mono_error_cleanup (&error);
11630 continue;
11631 }
11632 }
11633 char *sig_str = mono_signature_full_name (sig);
11634 gboolean match = !strcmp (sig_str, mdata->signature);
11635 g_free (sig_str);
11636 if (!match)
11637
11638 continue;
11639 //printf ("%s\n", mono_method_full_name (m, 1));
11640 mdata->method = m;
11641 break;
11642 }
11643 if (!mdata->method) {
11644 if (acfg->aot_opts.verbose)
11645 printf ("Unable to load method '%s' from class '%s', not found.\n", mdata->name, mono_class_full_name (klass));
11646 }
11647 }
11648 }
11649
11650 static gboolean
inst_references_image(MonoGenericInst * inst,MonoImage * image)11651 inst_references_image (MonoGenericInst *inst, MonoImage *image)
11652 {
11653 int i;
11654
11655 for (i = 0; i < inst->type_argc; ++i) {
11656 MonoClass *k = mono_class_from_mono_type (inst->type_argv [i]);
11657 if (k->image == image)
11658 return TRUE;
11659 if (mono_class_is_ginst (k)) {
11660 MonoGenericInst *kinst = mono_class_get_context (k)->class_inst;
11661 if (inst_references_image (kinst, image))
11662 return TRUE;
11663 }
11664 }
11665 return FALSE;
11666 }
11667
11668 static gboolean
is_local_inst(MonoGenericInst * inst,MonoImage * image)11669 is_local_inst (MonoGenericInst *inst, MonoImage *image)
11670 {
11671 int i;
11672
11673 for (i = 0; i < inst->type_argc; ++i) {
11674 MonoClass *k = mono_class_from_mono_type (inst->type_argv [i]);
11675 if (!MONO_TYPE_IS_PRIMITIVE (inst->type_argv [i]) && k->image != image)
11676 return FALSE;
11677 }
11678 return TRUE;
11679 }
11680
11681 static void
add_profile_instances(MonoAotCompile * acfg,ProfileData * data)11682 add_profile_instances (MonoAotCompile *acfg, ProfileData *data)
11683 {
11684 GHashTableIter iter;
11685 gpointer key, value;
11686 int count = 0;
11687
11688 if (!data)
11689 return;
11690
11691 if (acfg->aot_opts.profile_only) {
11692 /* Add methods referenced by the profile */
11693 g_hash_table_iter_init (&iter, data->methods);
11694 while (g_hash_table_iter_next (&iter, &key, &value)) {
11695 MethodProfileData *mdata = (MethodProfileData*)value;
11696 MonoMethod *m = mdata->method;
11697
11698 if (!m)
11699 continue;
11700 if (m->is_inflated)
11701 continue;
11702 add_extra_method (acfg, m);
11703 g_hash_table_insert (acfg->profile_methods, m, m);
11704 count ++;
11705 }
11706 }
11707
11708 /*
11709 * Add method instances 'related' to this assembly to the AOT image.
11710 */
11711 g_hash_table_iter_init (&iter, data->methods);
11712 while (g_hash_table_iter_next (&iter, &key, &value)) {
11713 MethodProfileData *mdata = (MethodProfileData*)value;
11714 MonoMethod *m = mdata->method;
11715 MonoGenericContext *ctx;
11716
11717 if (!m)
11718 continue;
11719 if (!m->is_inflated)
11720 continue;
11721
11722 ctx = mono_method_get_context (m);
11723 /* For simplicity, add instances which reference the assembly we are compiling */
11724 if (((ctx->class_inst && inst_references_image (ctx->class_inst, acfg->image)) ||
11725 (ctx->method_inst && inst_references_image (ctx->method_inst, acfg->image))) &&
11726 !mono_method_is_generic_sharable_full (m, FALSE, FALSE, FALSE)) {
11727 //printf ("%s\n", mono_method_full_name (m, TRUE));
11728 add_extra_method (acfg, m);
11729 count ++;
11730 } else if (m->klass->image == acfg->image &&
11731 ((ctx->class_inst && is_local_inst (ctx->class_inst, acfg->image)) ||
11732 (ctx->method_inst && is_local_inst (ctx->method_inst, acfg->image))) &&
11733 !mono_method_is_generic_sharable_full (m, FALSE, FALSE, FALSE)) {
11734 /* Add instances where the gtd is in the assembly and its inflated with types from this assembly or corlib */
11735 //printf ("%s\n", mono_method_full_name (m, TRUE));
11736 add_extra_method (acfg, m);
11737 count ++;
11738 }
11739 /*
11740 * FIXME: We might skip some instances, for example:
11741 * Foo<Bar> won't be compiled when compiling Foo's assembly since it doesn't match the first case,
11742 * and it won't be compiled when compiling Bar's assembly if Foo's assembly is not loaded.
11743 */
11744 }
11745
11746 printf ("Added %d methods from profile.\n", count);
11747 }
11748
11749 static void
init_got_info(GotInfo * info)11750 init_got_info (GotInfo *info)
11751 {
11752 int i;
11753
11754 info->patch_to_got_offset = g_hash_table_new (mono_patch_info_hash, mono_patch_info_equal);
11755 info->patch_to_got_offset_by_type = g_new0 (GHashTable*, MONO_PATCH_INFO_NUM);
11756 for (i = 0; i < MONO_PATCH_INFO_NUM; ++i)
11757 info->patch_to_got_offset_by_type [i] = g_hash_table_new (mono_patch_info_hash, mono_patch_info_equal);
11758 info->got_patches = g_ptr_array_new ();
11759 }
11760
11761 static MonoAotCompile*
acfg_create(MonoAssembly * ass,guint32 opts)11762 acfg_create (MonoAssembly *ass, guint32 opts)
11763 {
11764 MonoImage *image = ass->image;
11765 MonoAotCompile *acfg;
11766
11767 acfg = g_new0 (MonoAotCompile, 1);
11768 acfg->methods = g_ptr_array_new ();
11769 acfg->method_indexes = g_hash_table_new (NULL, NULL);
11770 acfg->method_depth = g_hash_table_new (NULL, NULL);
11771 acfg->plt_offset_to_entry = g_hash_table_new (NULL, NULL);
11772 acfg->patch_to_plt_entry = g_new0 (GHashTable*, MONO_PATCH_INFO_NUM);
11773 acfg->method_to_cfg = g_hash_table_new (NULL, NULL);
11774 acfg->token_info_hash = g_hash_table_new_full (NULL, NULL, NULL, NULL);
11775 acfg->method_to_pinvoke_import = g_hash_table_new_full (NULL, NULL, NULL, g_free);
11776 acfg->image_hash = g_hash_table_new (NULL, NULL);
11777 acfg->image_table = g_ptr_array_new ();
11778 acfg->globals = g_ptr_array_new ();
11779 acfg->image = image;
11780 acfg->opts = opts;
11781 /* TODO: Write out set of SIMD instructions used, rather than just those available */
11782 acfg->simd_opts = mono_arch_cpu_enumerate_simd_versions ();
11783 acfg->mempool = mono_mempool_new ();
11784 acfg->extra_methods = g_ptr_array_new ();
11785 acfg->unwind_info_offsets = g_hash_table_new (NULL, NULL);
11786 acfg->unwind_ops = g_ptr_array_new ();
11787 acfg->method_label_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
11788 acfg->method_order = g_ptr_array_new ();
11789 acfg->export_names = g_hash_table_new (NULL, NULL);
11790 acfg->klass_blob_hash = g_hash_table_new (NULL, NULL);
11791 acfg->method_blob_hash = g_hash_table_new (NULL, NULL);
11792 acfg->plt_entry_debug_sym_cache = g_hash_table_new (g_str_hash, g_str_equal);
11793 acfg->gsharedvt_in_signatures = g_hash_table_new ((GHashFunc)mono_signature_hash, (GEqualFunc)mono_metadata_signature_equal);
11794 acfg->gsharedvt_out_signatures = g_hash_table_new ((GHashFunc)mono_signature_hash, (GEqualFunc)mono_metadata_signature_equal);
11795 acfg->profile_methods = g_hash_table_new (NULL, NULL);
11796 mono_os_mutex_init_recursive (&acfg->mutex);
11797
11798 init_got_info (&acfg->got_info);
11799 init_got_info (&acfg->llvm_got_info);
11800
11801 return acfg;
11802 }
11803
11804 static void
got_info_free(GotInfo * info)11805 got_info_free (GotInfo *info)
11806 {
11807 int i;
11808
11809 for (i = 0; i < MONO_PATCH_INFO_NUM; ++i)
11810 g_hash_table_destroy (info->patch_to_got_offset_by_type [i]);
11811 g_free (info->patch_to_got_offset_by_type);
11812 g_hash_table_destroy (info->patch_to_got_offset);
11813 g_ptr_array_free (info->got_patches, TRUE);
11814 }
11815
11816 static void
acfg_free(MonoAotCompile * acfg)11817 acfg_free (MonoAotCompile *acfg)
11818 {
11819 int i;
11820
11821 mono_img_writer_destroy (acfg->w);
11822 for (i = 0; i < acfg->nmethods; ++i)
11823 if (acfg->cfgs [i])
11824 mono_destroy_compile (acfg->cfgs [i]);
11825
11826 g_free (acfg->cfgs);
11827
11828 g_free (acfg->static_linking_symbol);
11829 g_free (acfg->got_symbol);
11830 g_free (acfg->plt_symbol);
11831 g_ptr_array_free (acfg->methods, TRUE);
11832 g_ptr_array_free (acfg->image_table, TRUE);
11833 g_ptr_array_free (acfg->globals, TRUE);
11834 g_ptr_array_free (acfg->unwind_ops, TRUE);
11835 g_hash_table_destroy (acfg->method_indexes);
11836 g_hash_table_destroy (acfg->method_depth);
11837 g_hash_table_destroy (acfg->plt_offset_to_entry);
11838 for (i = 0; i < MONO_PATCH_INFO_NUM; ++i) {
11839 if (acfg->patch_to_plt_entry [i])
11840 g_hash_table_destroy (acfg->patch_to_plt_entry [i]);
11841 }
11842 g_free (acfg->patch_to_plt_entry);
11843 g_hash_table_destroy (acfg->method_to_cfg);
11844 g_hash_table_destroy (acfg->token_info_hash);
11845 g_hash_table_destroy (acfg->method_to_pinvoke_import);
11846 g_hash_table_destroy (acfg->image_hash);
11847 g_hash_table_destroy (acfg->unwind_info_offsets);
11848 g_hash_table_destroy (acfg->method_label_hash);
11849 if (acfg->typespec_classes)
11850 g_hash_table_destroy (acfg->typespec_classes);
11851 g_hash_table_destroy (acfg->export_names);
11852 g_hash_table_destroy (acfg->plt_entry_debug_sym_cache);
11853 g_hash_table_destroy (acfg->klass_blob_hash);
11854 g_hash_table_destroy (acfg->method_blob_hash);
11855 got_info_free (&acfg->got_info);
11856 got_info_free (&acfg->llvm_got_info);
11857 arch_free_unwind_info_section_cache (acfg);
11858 mono_mempool_destroy (acfg->mempool);
11859 g_free (acfg);
11860 }
11861
11862 #define WRAPPER(e,n) n,
11863 static const char* const
11864 wrapper_type_names [MONO_WRAPPER_NUM + 1] = {
11865 #include "mono/metadata/wrapper-types.h"
11866 NULL
11867 };
11868
11869 static G_GNUC_UNUSED const char*
get_wrapper_type_name(int type)11870 get_wrapper_type_name (int type)
11871 {
11872 return wrapper_type_names [type];
11873 }
11874
11875 //#define DUMP_PLT
11876 //#define DUMP_GOT
11877
aot_dump(MonoAotCompile * acfg)11878 static void aot_dump (MonoAotCompile *acfg)
11879 {
11880 FILE *dumpfile;
11881 char * dumpname;
11882
11883 JsonWriter writer;
11884 mono_json_writer_init (&writer);
11885
11886 mono_json_writer_object_begin(&writer);
11887
11888 // Methods
11889 mono_json_writer_indent (&writer);
11890 mono_json_writer_object_key(&writer, "methods");
11891 mono_json_writer_array_begin (&writer);
11892
11893 int i;
11894 for (i = 0; i < acfg->nmethods; ++i) {
11895 MonoCompile *cfg;
11896 MonoMethod *method;
11897 MonoClass *klass;
11898
11899 cfg = acfg->cfgs [i];
11900 if (ignore_cfg (cfg))
11901 continue;
11902
11903 method = cfg->orig_method;
11904
11905 mono_json_writer_indent (&writer);
11906 mono_json_writer_object_begin(&writer);
11907
11908 mono_json_writer_indent (&writer);
11909 mono_json_writer_object_key(&writer, "name");
11910 mono_json_writer_printf (&writer, "\"%s\",\n", method->name);
11911
11912 mono_json_writer_indent (&writer);
11913 mono_json_writer_object_key(&writer, "signature");
11914 mono_json_writer_printf (&writer, "\"%s\",\n", mono_method_get_full_name (method));
11915
11916 mono_json_writer_indent (&writer);
11917 mono_json_writer_object_key(&writer, "code_size");
11918 mono_json_writer_printf (&writer, "\"%d\",\n", cfg->code_size);
11919
11920 klass = method->klass;
11921
11922 mono_json_writer_indent (&writer);
11923 mono_json_writer_object_key(&writer, "class");
11924 mono_json_writer_printf (&writer, "\"%s\",\n", klass->name);
11925
11926 mono_json_writer_indent (&writer);
11927 mono_json_writer_object_key(&writer, "namespace");
11928 mono_json_writer_printf (&writer, "\"%s\",\n", klass->name_space);
11929
11930 mono_json_writer_indent (&writer);
11931 mono_json_writer_object_key(&writer, "wrapper_type");
11932 mono_json_writer_printf (&writer, "\"%s\",\n", get_wrapper_type_name(method->wrapper_type));
11933
11934 mono_json_writer_indent_pop (&writer);
11935 mono_json_writer_indent (&writer);
11936 mono_json_writer_object_end (&writer);
11937 mono_json_writer_printf (&writer, ",\n");
11938 }
11939
11940 mono_json_writer_indent_pop (&writer);
11941 mono_json_writer_indent (&writer);
11942 mono_json_writer_array_end (&writer);
11943 mono_json_writer_printf (&writer, ",\n");
11944
11945 // PLT entries
11946 #ifdef DUMP_PLT
11947 mono_json_writer_indent_push (&writer);
11948 mono_json_writer_indent (&writer);
11949 mono_json_writer_object_key(&writer, "plt");
11950 mono_json_writer_array_begin (&writer);
11951
11952 for (i = 0; i < acfg->plt_offset; ++i) {
11953 MonoPltEntry *plt_entry = NULL;
11954 MonoJumpInfo *ji;
11955
11956 if (i == 0)
11957 /*
11958 * The first plt entry is unused.
11959 */
11960 continue;
11961
11962 plt_entry = g_hash_table_lookup (acfg->plt_offset_to_entry, GUINT_TO_POINTER (i));
11963 ji = plt_entry->ji;
11964
11965 mono_json_writer_indent (&writer);
11966 mono_json_writer_printf (&writer, "{ ");
11967 mono_json_writer_object_key(&writer, "symbol");
11968 mono_json_writer_printf (&writer, "\"%s\" },\n", plt_entry->symbol);
11969 }
11970
11971 mono_json_writer_indent_pop (&writer);
11972 mono_json_writer_indent (&writer);
11973 mono_json_writer_array_end (&writer);
11974 mono_json_writer_printf (&writer, ",\n");
11975 #endif
11976
11977 // GOT entries
11978 #ifdef DUMP_GOT
11979 mono_json_writer_indent_push (&writer);
11980 mono_json_writer_indent (&writer);
11981 mono_json_writer_object_key(&writer, "got");
11982 mono_json_writer_array_begin (&writer);
11983
11984 mono_json_writer_indent_push (&writer);
11985 for (i = 0; i < acfg->got_info.got_patches->len; ++i) {
11986 MonoJumpInfo *ji = g_ptr_array_index (acfg->got_info.got_patches, i);
11987
11988 mono_json_writer_indent (&writer);
11989 mono_json_writer_printf (&writer, "{ ");
11990 mono_json_writer_object_key(&writer, "patch_name");
11991 mono_json_writer_printf (&writer, "\"%s\" },\n", get_patch_name (ji->type));
11992 }
11993
11994 mono_json_writer_indent_pop (&writer);
11995 mono_json_writer_indent (&writer);
11996 mono_json_writer_array_end (&writer);
11997 mono_json_writer_printf (&writer, ",\n");
11998 #endif
11999
12000 mono_json_writer_indent_pop (&writer);
12001 mono_json_writer_indent (&writer);
12002 mono_json_writer_object_end (&writer);
12003
12004 dumpname = g_strdup_printf ("%s.json", g_path_get_basename (acfg->image->name));
12005 dumpfile = fopen (dumpname, "w+");
12006 g_free (dumpname);
12007
12008 fprintf (dumpfile, "%s", writer.text->str);
12009 fclose (dumpfile);
12010
12011 mono_json_writer_destroy (&writer);
12012 }
12013
12014 static const char *preinited_jit_icalls[] = {
12015 "mono_aot_init_llvm_method",
12016 "mono_aot_init_gshared_method_this",
12017 "mono_aot_init_gshared_method_mrgctx",
12018 "mono_aot_init_gshared_method_vtable",
12019 "mono_llvm_throw_corlib_exception",
12020 "mono_init_vtable_slot",
12021 "mono_helper_ldstr_mscorlib"
12022 };
12023
12024 static void
add_preinit_got_slots(MonoAotCompile * acfg)12025 add_preinit_got_slots (MonoAotCompile *acfg)
12026 {
12027 MonoJumpInfo *ji;
12028 int i;
12029
12030 /*
12031 * Allocate the first few GOT entries to information which is needed frequently, or it is needed
12032 * during method initialization etc.
12033 */
12034
12035 ji = (MonoJumpInfo *)mono_mempool_alloc0 (acfg->mempool, sizeof (MonoJumpInfo));
12036 ji->type = MONO_PATCH_INFO_IMAGE;
12037 ji->data.image = acfg->image;
12038 get_got_offset (acfg, FALSE, ji);
12039 get_got_offset (acfg, TRUE, ji);
12040
12041 ji = (MonoJumpInfo *)mono_mempool_alloc0 (acfg->mempool, sizeof (MonoJumpInfo));
12042 ji->type = MONO_PATCH_INFO_MSCORLIB_GOT_ADDR;
12043 get_got_offset (acfg, FALSE, ji);
12044 get_got_offset (acfg, TRUE, ji);
12045
12046 ji = (MonoJumpInfo *)mono_mempool_alloc0 (acfg->mempool, sizeof (MonoJumpInfo));
12047 ji->type = MONO_PATCH_INFO_GC_CARD_TABLE_ADDR;
12048 get_got_offset (acfg, FALSE, ji);
12049 get_got_offset (acfg, TRUE, ji);
12050
12051 ji = (MonoJumpInfo *)mono_mempool_alloc0 (acfg->mempool, sizeof (MonoJumpInfo));
12052 ji->type = MONO_PATCH_INFO_GC_NURSERY_START;
12053 get_got_offset (acfg, FALSE, ji);
12054 get_got_offset (acfg, TRUE, ji);
12055
12056 ji = (MonoJumpInfo *)mono_mempool_alloc0 (acfg->mempool, sizeof (MonoJumpInfo));
12057 ji->type = MONO_PATCH_INFO_AOT_MODULE;
12058 get_got_offset (acfg, FALSE, ji);
12059 get_got_offset (acfg, TRUE, ji);
12060
12061 ji = (MonoJumpInfo *)mono_mempool_alloc0 (acfg->mempool, sizeof (MonoJumpInfo));
12062 ji->type = MONO_PATCH_INFO_GC_NURSERY_BITS;
12063 get_got_offset (acfg, FALSE, ji);
12064 get_got_offset (acfg, TRUE, ji);
12065
12066 for (i = 0; i < TLS_KEY_NUM; i++) {
12067 ji = (MonoJumpInfo *)mono_mempool_alloc0 (acfg->mempool, sizeof (MonoJumpInfo));
12068 ji->type = MONO_PATCH_INFO_GET_TLS_TRAMP;
12069 ji->data.index = i;
12070 get_got_offset (acfg, FALSE, ji);
12071 get_got_offset (acfg, TRUE, ji);
12072
12073 ji = (MonoJumpInfo *)mono_mempool_alloc0 (acfg->mempool, sizeof (MonoJumpInfo));
12074 ji->type = MONO_PATCH_INFO_SET_TLS_TRAMP;
12075 ji->data.index = i;
12076 get_got_offset (acfg, FALSE, ji);
12077 get_got_offset (acfg, TRUE, ji);
12078 }
12079
12080 ji = (MonoJumpInfo *)mono_mempool_alloc0 (acfg->mempool, sizeof (MonoJumpInfo));
12081 ji->type = MONO_PATCH_INFO_JIT_THREAD_ATTACH;
12082 get_got_offset (acfg, FALSE, ji);
12083 get_got_offset (acfg, TRUE, ji);
12084
12085 /* Called by native-to-managed wrappers on possibly unattached threads */
12086 ji = (MonoJumpInfo *)mono_mempool_alloc0 (acfg->mempool, sizeof (MonoJumpInfo));
12087 ji->type = MONO_PATCH_INFO_JIT_ICALL_ADDR_NOCALL;
12088 ji->data.name = "mono_threads_attach_coop";
12089 get_got_offset (acfg, FALSE, ji);
12090 get_got_offset (acfg, TRUE, ji);
12091
12092 for (i = 0; i < sizeof (preinited_jit_icalls) / sizeof (char*); ++i) {
12093 ji = (MonoJumpInfo *)mono_mempool_alloc0 (acfg->mempool, sizeof (MonoAotCompile));
12094 ji->type = MONO_PATCH_INFO_INTERNAL_METHOD;
12095 ji->data.name = preinited_jit_icalls [i];
12096 get_got_offset (acfg, FALSE, ji);
12097 get_got_offset (acfg, TRUE, ji);
12098 }
12099
12100 acfg->nshared_got_entries = acfg->got_offset;
12101 }
12102
12103 static void
mono_dedup_log_stats(MonoAotCompile * acfg)12104 mono_dedup_log_stats (MonoAotCompile *acfg)
12105 {
12106 GHashTableIter iter;
12107 g_assert (acfg->dedup_stats);
12108
12109 // If dedup_emit_mode, acfg is the dummy dedup module that consolidates
12110 // deduped modules
12111 g_hash_table_iter_init (&iter, acfg->method_to_cfg);
12112 MonoCompile *dcfg = NULL;
12113 MonoMethod *method = NULL;
12114
12115 size_t wrappers_size_saved = 0;
12116 size_t inflated_size_saved = 0;
12117 size_t copied_singles = 0;
12118
12119 while (g_hash_table_iter_next (&iter, (gpointer *) &method, (gpointer *)&dcfg)) {
12120 gchar *dedup_name = mono_aot_get_mangled_method_name (method);
12121 guint count = GPOINTER_TO_UINT(g_hash_table_lookup (acfg->dedup_stats, dedup_name));
12122
12123 if (count == 0)
12124 continue;
12125
12126 if (acfg->dedup_emit_mode) {
12127 // Size *saved* is the size due to things not emitted.
12128 if (count < 2) {
12129 // Just moved, didn't save space / dedup
12130 copied_singles += dcfg->code_len;
12131 } else if (method->wrapper_type != MONO_WRAPPER_NONE) {
12132 wrappers_size_saved += dcfg->code_len * (count - 1);
12133 } else {
12134 inflated_size_saved += dcfg->code_len * (count - 1);
12135 }
12136 }
12137 if (acfg->aot_opts.dedup) {
12138 if (method->wrapper_type != MONO_WRAPPER_NONE) {
12139 wrappers_size_saved += dcfg->code_len * count;
12140 } else {
12141 inflated_size_saved += dcfg->code_len * count;
12142 }
12143 }
12144 }
12145
12146 aot_printf (acfg, "Dedup Pass: Size Saved From Deduped Wrappers:\t%zu bytes\n", wrappers_size_saved);
12147 aot_printf (acfg, "Dedup Pass: Size Saved From Inflated Methods:\t%zu bytes\n", inflated_size_saved);
12148 if (acfg->dedup_emit_mode)
12149 aot_printf (acfg, "Dedup Pass: Size of Moved But Not Deduped (only 1 copy) Methods:\t%zu bytes\n", copied_singles);
12150
12151 g_hash_table_destroy (acfg->dedup_stats);
12152 acfg->dedup_stats = NULL;
12153 }
12154
12155 // Flush the cache to tell future calls what to skip
12156 static void
mono_flush_method_cache(MonoAotCompile * acfg)12157 mono_flush_method_cache (MonoAotCompile *acfg)
12158 {
12159 GHashTable *method_cache = acfg->dedup_cache;
12160 char *filename = g_strdup_printf ("%s.dedup", acfg->image->name);
12161 if (!acfg->dedup_cache_changed || !acfg->aot_opts.dedup) {
12162 g_free (filename);
12163 return;
12164 }
12165
12166 acfg->dedup_cache = NULL;
12167
12168 FILE *cache = fopen (filename, "w");
12169
12170 if (!cache)
12171 g_error ("Could not create cache at %s because of error: %s\n", filename, strerror (errno));
12172
12173 GHashTableIter iter;
12174 gchar *name = NULL;
12175 g_hash_table_iter_init (&iter, method_cache);
12176 gboolean cont = TRUE;
12177 while (cont && g_hash_table_iter_next (&iter, (gpointer *) &name, NULL)) {
12178 int res = fprintf (cache, "%s\n", name);
12179 cont = res >= 0;
12180 }
12181 // FIXME: don't assert if error when flushing
12182 g_assert (cont);
12183
12184 fclose (cache);
12185 g_free (filename);
12186
12187 // The keys are all in the imageset, nothing to free
12188 // Values are just pointers to memory owned elsewhere, or sentinels
12189 g_hash_table_destroy (method_cache);
12190 }
12191
12192 // Read in what has been emitted by previous invocations,
12193 // what can be skipped
12194 static void
mono_read_method_cache(MonoAotCompile * acfg)12195 mono_read_method_cache (MonoAotCompile *acfg)
12196 {
12197 char *filename = g_strdup_printf ("%s.dedup", acfg->image->name);
12198 // Only do once, when dedup_cache is null
12199 if (acfg->dedup_cache)
12200 goto early_exit;
12201
12202 if (acfg->aot_opts.dedup_include || acfg->aot_opts.dedup)
12203 g_assert (acfg->dedup_stats);
12204
12205 // only in skip mode
12206 if (!acfg->aot_opts.dedup)
12207 goto early_exit;
12208
12209 g_assert (acfg->dedup_cache);
12210
12211 FILE *cache = fopen (filename, "r");
12212 if (!cache)
12213 goto early_exit;
12214
12215 // Since we do pointer comparisons, and it can't be allocated at
12216 // the address 0x1 due to alignment, we use this as a sentinel
12217 gpointer other_acfg_sentinel = GINT_TO_POINTER (0x1);
12218
12219 if (fseek (cache, 0L, SEEK_END))
12220 goto cleanup;
12221
12222 size_t fileLength = ftell (cache);
12223 g_assert (fileLength > 0);
12224
12225 if (fseek (cache, 0L, SEEK_SET))
12226 goto cleanup;
12227
12228 // Avoid thousands of new malloc entries
12229 // FIXME: allocate into imageset, so we don't need to free.
12230 // put the other mangled names there too.
12231 char *bulk = g_malloc0 (fileLength * sizeof (char));
12232 size_t offset = 0;
12233
12234 while (fgets (&bulk [offset], fileLength - offset, cache)) {
12235 // strip newline
12236 char *line = &bulk [offset];
12237 size_t len = strlen (line);
12238 if (len == 0)
12239 break;
12240
12241 if (len >= 0 && line [len] == '\n')
12242 line [len] = '\0';
12243 offset += strlen (line) + 1;
12244 g_assert (fileLength >= offset);
12245
12246 g_hash_table_insert (acfg->dedup_cache, line, other_acfg_sentinel);
12247 }
12248
12249 cleanup:
12250 fclose (cache);
12251
12252 early_exit:
12253 g_free (filename);
12254 return;
12255 }
12256
12257 typedef struct {
12258 GHashTable *cache;
12259 GHashTable *stats;
12260 gboolean emit_inflated_methods;
12261 MonoAssembly *inflated_assembly;
12262 } MonoAotState;
12263
12264 static MonoAotState *
alloc_aot_state(void)12265 alloc_aot_state (void)
12266 {
12267 MonoAotState *state = g_malloc (sizeof (MonoAotState));
12268 // FIXME: Should this own the memory?
12269 state->cache = g_hash_table_new (g_str_hash, g_str_equal);
12270 state->stats = g_hash_table_new (g_str_hash, g_str_equal);
12271 // Start in "collect mode"
12272 state->emit_inflated_methods = FALSE;
12273 state->inflated_assembly = NULL;
12274 return state;
12275 }
12276
12277 static void
free_aot_state(MonoAotState * astate)12278 free_aot_state (MonoAotState *astate)
12279 {
12280 g_hash_table_destroy (astate->cache);
12281 g_free (astate);
12282 }
12283
12284 static void
mono_add_deferred_extra_methods(MonoAotCompile * acfg,MonoAotState * astate)12285 mono_add_deferred_extra_methods (MonoAotCompile *acfg, MonoAotState *astate)
12286 {
12287 GHashTableIter iter;
12288 gchar *name = NULL;
12289 MonoMethod *method = NULL;
12290
12291 acfg->dedup_emit_mode = TRUE;
12292
12293 g_hash_table_iter_init (&iter, astate->cache);
12294 while (g_hash_table_iter_next (&iter, (gpointer *) &name, (gpointer *) &method)) {
12295 add_method_full (acfg, method, TRUE, 0);
12296 }
12297 return;
12298 }
12299
12300 static void
mono_setup_dedup_state(MonoAotCompile * acfg,MonoAotState ** global_aot_state,MonoAssembly * ass,MonoAotState ** astate,gboolean * is_dedup_dummy)12301 mono_setup_dedup_state (MonoAotCompile *acfg, MonoAotState **global_aot_state, MonoAssembly *ass, MonoAotState **astate, gboolean *is_dedup_dummy)
12302 {
12303 if (!acfg->aot_opts.dedup_include && !acfg->aot_opts.dedup)
12304 return;
12305
12306 if (global_aot_state && *global_aot_state && acfg->aot_opts.dedup_include) {
12307 // Thread the state through when making the inflate pass
12308 *astate = *global_aot_state;
12309 }
12310
12311 if (!*astate) {
12312 *astate = alloc_aot_state ();
12313 *global_aot_state = *astate;
12314 }
12315
12316 acfg->dedup_cache = (*astate)->cache;
12317 acfg->dedup_stats = (*astate)->stats;
12318
12319 // fills out acfg->dedup_cache
12320 if (acfg->aot_opts.dedup)
12321 mono_read_method_cache (acfg);
12322
12323 if (!(*astate)->inflated_assembly && acfg->aot_opts.dedup_include) {
12324 gchar **asm_path = g_strsplit (ass->image->name, G_DIR_SEPARATOR_S, 0);
12325 gchar *asm_file = NULL;
12326
12327 // Get the last part of the path, the filename
12328 for (int i=0; asm_path [i] != NULL; i++)
12329 asm_file = asm_path [i];
12330
12331 if (!strcmp (acfg->aot_opts.dedup_include, asm_file)) {
12332 // Save
12333 *is_dedup_dummy = TRUE;
12334 (*astate)->inflated_assembly = ass;
12335 }
12336 g_strfreev (asm_path);
12337 } else if ((*astate)->inflated_assembly) {
12338 *is_dedup_dummy = (ass == (*astate)->inflated_assembly);
12339 }
12340 }
12341
12342 int
mono_compile_deferred_assemblies(guint32 opts,const char * aot_options,gpointer ** aot_state)12343 mono_compile_deferred_assemblies (guint32 opts, const char *aot_options, gpointer **aot_state)
12344 {
12345 // create assembly, loop and add extra_methods
12346 // in add_generic_instances , rip out what's in that for loop
12347 // and apply that to this aot_state inside of mono_compile_assembly
12348 MonoAotState *astate;
12349 astate = *(MonoAotState **)aot_state;
12350 g_assert (astate);
12351
12352 // FIXME: allow suffixes?
12353 if (!astate->inflated_assembly) {
12354 char *inflate = strstr (aot_options, "dedup-inflate");
12355 if (!inflate)
12356 return 0;
12357 else
12358 g_error ("Error: mono was not given an assembly with the provided inflate name\n");
12359 }
12360
12361 // Switch modes
12362 astate->emit_inflated_methods = TRUE;
12363
12364 int res = mono_compile_assembly (astate->inflated_assembly, opts, aot_options, aot_state);
12365
12366 *aot_state = NULL;
12367 free_aot_state (astate);
12368
12369 return res;
12370 }
12371
12372 static const char* interp_in_static_sigs[] = {
12373 "bool ptr int32 ptr&",
12374 "bool ptr ptr&",
12375 "int32 int32 ptr&",
12376 "int32 int32 ptr ptr&",
12377 "int32 ptr int32 ptr",
12378 "int32 ptr int32 ptr&",
12379 "int32 ptr ptr&",
12380 "object object ptr ptr ptr",
12381 "ptr int32 ptr&",
12382 "ptr ptr int32 ptr ptr ptr&",
12383 "ptr ptr int32 ptr ptr&",
12384 "ptr ptr int32 ptr&",
12385 "ptr ptr ptr int32 ptr&",
12386 "ptr ptr ptr ptr& ptr&",
12387 "ptr ptr ptr ptr&",
12388 "ptr ptr ptr&",
12389 "ptr ptr uint32 ptr&",
12390 "ptr uint32 ptr&",
12391 "void object ptr ptr ptr",
12392 "void ptr ptr int32 ptr ptr& ptr ptr&",
12393 "void ptr ptr int32 ptr ptr&",
12394 "void ptr ptr ptr&",
12395 "void ptr ptr&",
12396 "void ptr",
12397 "void int32 ptr&",
12398 "void uint32 ptr&",
12399 };
12400
12401 int
mono_compile_assembly(MonoAssembly * ass,guint32 opts,const char * aot_options,gpointer ** global_aot_state)12402 mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options, gpointer **global_aot_state)
12403 {
12404 MonoImage *image = ass->image;
12405 int i, res;
12406 gint64 all_sizes;
12407 MonoAotCompile *acfg;
12408 char *outfile_name, *tmp_outfile_name, *p;
12409 char llvm_stats_msg [256];
12410 TV_DECLARE (atv);
12411 TV_DECLARE (btv);
12412
12413 acfg = acfg_create (ass, opts);
12414
12415 memset (&acfg->aot_opts, 0, sizeof (acfg->aot_opts));
12416 acfg->aot_opts.write_symbols = TRUE;
12417 acfg->aot_opts.ntrampolines = 4096;
12418 acfg->aot_opts.nrgctx_trampolines = 4096;
12419 acfg->aot_opts.nimt_trampolines = 512;
12420 acfg->aot_opts.nrgctx_fetch_trampolines = 128;
12421 acfg->aot_opts.ngsharedvt_arg_trampolines = 512;
12422 acfg->aot_opts.llvm_path = g_strdup ("");
12423 acfg->aot_opts.temp_path = g_strdup ("");
12424 #ifdef MONOTOUCH
12425 acfg->aot_opts.use_trampolines_page = TRUE;
12426 #endif
12427
12428 mono_aot_parse_options (aot_options, &acfg->aot_opts);
12429
12430 // start dedup
12431 MonoAotState *astate = NULL;
12432 gboolean is_dedup_dummy = FALSE;
12433 mono_setup_dedup_state (acfg, (MonoAotState **) global_aot_state, ass, &astate, &is_dedup_dummy);
12434
12435 // Process later
12436 if (is_dedup_dummy && astate && !astate->emit_inflated_methods)
12437 return 0;
12438
12439 // end dedup
12440
12441 if (acfg->aot_opts.logfile) {
12442 acfg->logfile = fopen (acfg->aot_opts.logfile, "a+");
12443 }
12444
12445 if (acfg->aot_opts.data_outfile) {
12446 acfg->data_outfile = fopen (acfg->aot_opts.data_outfile, "w+");
12447 if (!acfg->data_outfile) {
12448 aot_printerrf (acfg, "Unable to create file '%s': %s\n", acfg->aot_opts.data_outfile, strerror (errno));
12449 return 1;
12450 }
12451 acfg->flags = (MonoAotFileFlags)(acfg->flags | MONO_AOT_FILE_FLAG_SEPARATE_DATA);
12452 }
12453
12454 //acfg->aot_opts.print_skipped_methods = TRUE;
12455
12456 #if !defined(MONO_ARCH_GSHAREDVT_SUPPORTED)
12457 if (acfg->opts & MONO_OPT_GSHAREDVT) {
12458 aot_printerrf (acfg, "-O=gsharedvt not supported on this platform.\n");
12459 return 1;
12460 }
12461 if (acfg->aot_opts.llvm_only) {
12462 aot_printerrf (acfg, "--aot=llvmonly requires a runtime that supports gsharedvt.\n");
12463 return 1;
12464 }
12465 #else
12466 if (acfg->aot_opts.llvm_only || mono_aot_mode_is_full (&acfg->aot_opts) || mono_aot_mode_is_hybrid (&acfg->aot_opts))
12467 acfg->opts |= MONO_OPT_GSHAREDVT;
12468 #endif
12469
12470 #if !defined(ENABLE_LLVM)
12471 if (acfg->aot_opts.llvm_only) {
12472 aot_printerrf (acfg, "--aot=llvmonly requires a runtime compiled with llvm support.\n");
12473 return 1;
12474 }
12475 #endif
12476
12477 if (acfg->opts & MONO_OPT_GSHAREDVT)
12478 mono_set_generic_sharing_vt_supported (TRUE);
12479
12480 aot_printf (acfg, "Mono Ahead of Time compiler - compiling assembly %s\n", image->name);
12481
12482 generate_aotid ((guint8*) &acfg->image->aotid);
12483
12484 char *aotid = mono_guid_to_string (acfg->image->aotid);
12485 aot_printf (acfg, "AOTID %s\n", aotid);
12486 g_free (aotid);
12487
12488 #ifndef MONO_ARCH_HAVE_FULL_AOT_TRAMPOLINES
12489 if (mono_aot_mode_is_full (&acfg->aot_opts)) {
12490 aot_printerrf (acfg, "--aot=full is not supported on this platform.\n");
12491 return 1;
12492 }
12493 #endif
12494
12495 if (acfg->aot_opts.direct_pinvoke && !acfg->aot_opts.static_link) {
12496 aot_printerrf (acfg, "The 'direct-pinvoke' AOT option also requires the 'static' AOT option.\n");
12497 return 1;
12498 }
12499
12500 if (acfg->aot_opts.static_link)
12501 acfg->aot_opts.asm_writer = TRUE;
12502
12503 if (acfg->aot_opts.soft_debug) {
12504 MonoDebugOptions *opt = mini_get_debug_options ();
12505
12506 opt->mdb_optimizations = TRUE;
12507 opt->gen_sdb_seq_points = TRUE;
12508
12509 if (!mono_debug_enabled ()) {
12510 aot_printerrf (acfg, "The soft-debug AOT option requires the --debug option.\n");
12511 return 1;
12512 }
12513 acfg->flags = (MonoAotFileFlags)(acfg->flags | MONO_AOT_FILE_FLAG_DEBUG);
12514 }
12515
12516 if (mono_use_llvm || acfg->aot_opts.llvm) {
12517 acfg->llvm = TRUE;
12518 acfg->aot_opts.asm_writer = TRUE;
12519 acfg->flags = (MonoAotFileFlags)(acfg->flags | MONO_AOT_FILE_FLAG_WITH_LLVM);
12520
12521 if (acfg->aot_opts.soft_debug) {
12522 aot_printerrf (acfg, "The 'soft-debug' option is not supported when compiling with LLVM.\n");
12523 return 1;
12524 }
12525
12526 mini_llvm_init ();
12527
12528 if (acfg->aot_opts.asm_only && !acfg->aot_opts.llvm_outfile) {
12529 aot_printerrf (acfg, "Compiling with LLVM and the asm-only option requires the llvm-outfile= option.\n");
12530 return 1;
12531 }
12532 }
12533
12534 if (mono_aot_mode_is_full (&acfg->aot_opts)) {
12535 acfg->flags = (MonoAotFileFlags)(acfg->flags | MONO_AOT_FILE_FLAG_FULL_AOT);
12536 acfg->is_full_aot = TRUE;
12537 }
12538
12539 if (mono_threads_is_coop_enabled ())
12540 acfg->flags = (MonoAotFileFlags)(acfg->flags | MONO_AOT_FILE_FLAG_SAFEPOINTS);
12541
12542 // The methods in dedup-emit amodules must be available on runtime startup
12543 // Note: Only one such amodule can have this attribute
12544 if (astate && astate->emit_inflated_methods)
12545 acfg->flags = (MonoAotFileFlags)(acfg->flags | MONO_AOT_FILE_FLAG_EAGER_LOAD);
12546
12547
12548 if (acfg->aot_opts.instances_logfile_path) {
12549 acfg->instances_logfile = fopen (acfg->aot_opts.instances_logfile_path, "w");
12550 if (!acfg->instances_logfile) {
12551 aot_printerrf (acfg, "Unable to create logfile: '%s'.\n", acfg->aot_opts.instances_logfile_path);
12552 return 1;
12553 }
12554 }
12555
12556 if (acfg->aot_opts.profile_files) {
12557 GList *l;
12558
12559 for (l = acfg->aot_opts.profile_files; l; l = l->next) {
12560 load_profile_file (acfg, (char*)l->data);
12561 }
12562 }
12563
12564 if (!mono_aot_mode_is_interp (&acfg->aot_opts)) {
12565 int method_index;
12566
12567 for (method_index = 0; method_index < acfg->image->tables [MONO_TABLE_METHOD].rows; ++method_index) {
12568 g_ptr_array_add (acfg->method_order,GUINT_TO_POINTER (method_index));
12569 }
12570 }
12571
12572 acfg->num_trampolines [MONO_AOT_TRAMP_SPECIFIC] = mono_aot_mode_is_full (&acfg->aot_opts) ? acfg->aot_opts.ntrampolines : 0;
12573 #ifdef MONO_ARCH_GSHARED_SUPPORTED
12574 acfg->num_trampolines [MONO_AOT_TRAMP_STATIC_RGCTX] = mono_aot_mode_is_full (&acfg->aot_opts) ? acfg->aot_opts.nrgctx_trampolines : 0;
12575 #endif
12576 acfg->num_trampolines [MONO_AOT_TRAMP_IMT] = mono_aot_mode_is_full (&acfg->aot_opts) ? acfg->aot_opts.nimt_trampolines : 0;
12577 #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
12578 if (acfg->opts & MONO_OPT_GSHAREDVT)
12579 acfg->num_trampolines [MONO_AOT_TRAMP_GSHAREDVT_ARG] = mono_aot_mode_is_full (&acfg->aot_opts) ? acfg->aot_opts.ngsharedvt_arg_trampolines : 0;
12580 #endif
12581
12582 acfg->temp_prefix = mono_img_writer_get_temp_label_prefix (NULL);
12583
12584 arch_init (acfg);
12585
12586 if (mono_use_llvm || acfg->aot_opts.llvm) {
12587
12588 /*
12589 * Emit all LLVM code into a separate assembly/object file and link with it
12590 * normally.
12591 */
12592 if (!acfg->aot_opts.asm_only && acfg->llvm_owriter_supported) {
12593 acfg->llvm_owriter = TRUE;
12594 } else if (acfg->aot_opts.llvm_outfile) {
12595 int len = strlen (acfg->aot_opts.llvm_outfile);
12596
12597 if (len >= 2 && acfg->aot_opts.llvm_outfile [len - 2] == '.' && acfg->aot_opts.llvm_outfile [len - 1] == 'o')
12598 acfg->llvm_owriter = TRUE;
12599 }
12600 }
12601
12602 if (acfg->llvm && acfg->thumb_mixed)
12603 acfg->flags = (MonoAotFileFlags)(acfg->flags | MONO_AOT_FILE_FLAG_LLVM_THUMB);
12604 if (acfg->aot_opts.llvm_only)
12605 acfg->flags = (MonoAotFileFlags)(acfg->flags | MONO_AOT_FILE_FLAG_LLVM_ONLY);
12606
12607 acfg->assembly_name_sym = g_strdup (acfg->image->assembly->aname.name);
12608 /* Get rid of characters which cannot occur in symbols */
12609 for (p = acfg->assembly_name_sym; *p; ++p) {
12610 if (!(isalnum (*p) || *p == '_'))
12611 *p = '_';
12612 }
12613
12614 acfg->global_prefix = g_strdup_printf ("mono_aot_%s", acfg->assembly_name_sym);
12615 acfg->plt_symbol = g_strdup_printf ("%s_plt", acfg->global_prefix);
12616 acfg->got_symbol = g_strdup_printf ("%s_got", acfg->global_prefix);
12617 if (acfg->llvm) {
12618 acfg->llvm_got_symbol = g_strdup_printf ("%s_llvm_got", acfg->global_prefix);
12619 acfg->llvm_eh_frame_symbol = g_strdup_printf ("%s_eh_frame", acfg->global_prefix);
12620 }
12621
12622 acfg->method_index = 1;
12623
12624 if (mono_aot_mode_is_full (&acfg->aot_opts) || mono_aot_mode_is_hybrid (&acfg->aot_opts))
12625 mono_set_partial_sharing_supported (TRUE);
12626
12627 if (!mono_aot_mode_is_interp (&acfg->aot_opts)) {
12628 res = collect_methods (acfg);
12629
12630 if (!res)
12631 return 1;
12632 }
12633
12634 // If we're emitting all of the inflated methods into a dummy
12635 // Assembly, then after extra_methods is set up, we're done
12636 // in this function.
12637 if (astate && astate->emit_inflated_methods)
12638 mono_add_deferred_extra_methods (acfg, astate);
12639
12640 {
12641 GList *l;
12642
12643 for (l = acfg->profile_data; l; l = l->next)
12644 resolve_profile_data (acfg, (ProfileData*)l->data);
12645 for (l = acfg->profile_data; l; l = l->next)
12646 add_profile_instances (acfg, (ProfileData*)l->data);
12647 }
12648
12649 acfg->cfgs_size = acfg->methods->len + 32;
12650 acfg->cfgs = g_new0 (MonoCompile*, acfg->cfgs_size);
12651
12652 /* PLT offset 0 is reserved for the PLT trampoline */
12653 acfg->plt_offset = 1;
12654 add_preinit_got_slots (acfg);
12655
12656 #ifdef ENABLE_LLVM
12657 if (acfg->llvm) {
12658 llvm_acfg = acfg;
12659 mono_llvm_create_aot_module (acfg->image->assembly, acfg->global_prefix, acfg->nshared_got_entries, TRUE, acfg->aot_opts.static_link, acfg->aot_opts.llvm_only);
12660 }
12661 #endif
12662
12663 if (mono_aot_mode_is_interp (&acfg->aot_opts)) {
12664 for (int i = 0; i < sizeof (interp_in_static_sigs) / sizeof (const char *); i++) {
12665 MonoMethodSignature *sig = mono_create_icall_signature (interp_in_static_sigs [i]);
12666 MonoMethod *wrapper = mini_get_interp_in_wrapper (sig);
12667 add_method (acfg, wrapper);
12668 }
12669 }
12670
12671 TV_GETTIME (atv);
12672
12673 compile_methods (acfg);
12674
12675 TV_GETTIME (btv);
12676
12677 acfg->stats.jit_time = TV_ELAPSED (atv, btv);
12678
12679 TV_GETTIME (atv);
12680
12681 #ifdef ENABLE_LLVM
12682 if (acfg->llvm) {
12683 if (acfg->aot_opts.asm_only) {
12684 if (acfg->aot_opts.outfile) {
12685 acfg->tmpfname = g_strdup_printf ("%s", acfg->aot_opts.outfile);
12686 acfg->tmpbasename = g_strdup (acfg->tmpfname);
12687 } else {
12688 acfg->tmpbasename = g_strdup_printf ("%s", acfg->image->name);
12689 acfg->tmpfname = g_strdup_printf ("%s.s", acfg->tmpbasename);
12690 }
12691 g_assert (acfg->aot_opts.llvm_outfile);
12692 acfg->llvm_sfile = g_strdup (acfg->aot_opts.llvm_outfile);
12693 if (acfg->llvm_owriter)
12694 acfg->llvm_ofile = g_strdup (acfg->aot_opts.llvm_outfile);
12695 else
12696 acfg->llvm_sfile = g_strdup (acfg->aot_opts.llvm_outfile);
12697 } else {
12698 acfg->tmpbasename = (strcmp (acfg->aot_opts.temp_path, "") == 0) ?
12699 g_strdup_printf ("%s", "temp") :
12700 g_build_filename (acfg->aot_opts.temp_path, "temp", NULL);
12701
12702 acfg->tmpfname = g_strdup_printf ("%s.s", acfg->tmpbasename);
12703 acfg->llvm_sfile = g_strdup_printf ("%s-llvm.s", acfg->tmpbasename);
12704 acfg->llvm_ofile = g_strdup_printf ("%s-llvm.o", acfg->tmpbasename);
12705 }
12706 }
12707 #endif
12708
12709 if (acfg->aot_opts.asm_only && !acfg->aot_opts.llvm_only) {
12710 if (acfg->aot_opts.outfile)
12711 acfg->tmpfname = g_strdup_printf ("%s", acfg->aot_opts.outfile);
12712 else
12713 acfg->tmpfname = g_strdup_printf ("%s.s", acfg->image->name);
12714 acfg->fp = fopen (acfg->tmpfname, "w+");
12715 } else {
12716 if (strcmp (acfg->aot_opts.temp_path, "") == 0) {
12717 int i = g_file_open_tmp ("mono_aot_XXXXXX", &acfg->tmpfname, NULL);
12718 acfg->fp = fdopen (i, "w+");
12719 } else {
12720 acfg->tmpbasename = g_build_filename (acfg->aot_opts.temp_path, "temp", NULL);
12721 acfg->tmpfname = g_strdup_printf ("%s.s", acfg->tmpbasename);
12722 acfg->fp = fopen (acfg->tmpfname, "w+");
12723 }
12724 }
12725 if (acfg->fp == 0 && !acfg->aot_opts.llvm_only) {
12726 aot_printerrf (acfg, "Unable to open file '%s': %s\n", acfg->tmpfname, strerror (errno));
12727 return 1;
12728 }
12729 if (acfg->fp)
12730 acfg->w = mono_img_writer_create (acfg->fp, FALSE);
12731
12732 tmp_outfile_name = NULL;
12733 outfile_name = NULL;
12734
12735 /* Compute symbols for methods */
12736 for (i = 0; i < acfg->nmethods; ++i) {
12737 if (acfg->cfgs [i]) {
12738 MonoCompile *cfg = acfg->cfgs [i];
12739 int method_index = get_method_index (acfg, cfg->orig_method);
12740
12741 if (COMPILE_LLVM (cfg))
12742 cfg->asm_symbol = g_strdup_printf ("%s%s", acfg->llvm_label_prefix, cfg->llvm_method_name);
12743 else if (acfg->global_symbols || acfg->llvm)
12744 cfg->asm_symbol = get_debug_sym (cfg->orig_method, "", acfg->method_label_hash);
12745 else
12746 cfg->asm_symbol = g_strdup_printf ("%s%sm_%x", acfg->temp_prefix, acfg->llvm_label_prefix, method_index);
12747 cfg->asm_debug_symbol = cfg->asm_symbol;
12748 }
12749 }
12750
12751 if (acfg->aot_opts.dwarf_debug && acfg->aot_opts.gnu_asm) {
12752 /*
12753 * CLANG supports GAS .file/.loc directives, so emit line number information this way
12754 */
12755 acfg->gas_line_numbers = TRUE;
12756 }
12757
12758 #ifdef EMIT_DWARF_INFO
12759 if ((!acfg->aot_opts.nodebug || acfg->aot_opts.dwarf_debug) && acfg->has_jitted_code) {
12760 if (acfg->aot_opts.dwarf_debug && !mono_debug_enabled ()) {
12761 aot_printerrf (acfg, "The dwarf AOT option requires the --debug option.\n");
12762 return 1;
12763 }
12764 acfg->dwarf = mono_dwarf_writer_create (acfg->w, NULL, 0, !acfg->gas_line_numbers);
12765 }
12766 #endif /* EMIT_DWARF_INFO */
12767
12768 if (acfg->w)
12769 mono_img_writer_emit_start (acfg->w);
12770
12771 if (acfg->dwarf)
12772 mono_dwarf_writer_emit_base_info (acfg->dwarf, g_path_get_basename (acfg->image->name), mono_unwind_get_cie_program ());
12773
12774 emit_code (acfg);
12775 if (acfg->aot_opts.dedup)
12776 mono_flush_method_cache (acfg);
12777 if (acfg->aot_opts.dedup || acfg->dedup_emit_mode)
12778 mono_dedup_log_stats (acfg);
12779
12780 emit_info (acfg);
12781
12782 emit_extra_methods (acfg);
12783
12784 if (acfg->aot_opts.dedup_include && !is_dedup_dummy)
12785 return 0;
12786
12787 emit_trampolines (acfg);
12788
12789 emit_class_name_table (acfg);
12790
12791 emit_got_info (acfg, FALSE);
12792 if (acfg->llvm)
12793 emit_got_info (acfg, TRUE);
12794
12795 emit_exception_info (acfg);
12796
12797 emit_unwind_info (acfg);
12798
12799 emit_class_info (acfg);
12800
12801 emit_plt (acfg);
12802
12803 emit_image_table (acfg);
12804
12805 emit_weak_field_indexes (acfg);
12806
12807 emit_got (acfg);
12808
12809 {
12810 /*
12811 * The managed allocators are GC specific, so can't use an AOT image created by one GC
12812 * in another.
12813 */
12814 const char *gc_name = mono_gc_get_gc_name ();
12815 acfg->gc_name_offset = add_to_blob (acfg, (guint8*)gc_name, strlen (gc_name) + 1);
12816 }
12817
12818 emit_blob (acfg);
12819
12820 emit_objc_selectors (acfg);
12821
12822 emit_globals (acfg);
12823
12824 emit_file_info (acfg);
12825
12826 emit_library_info (acfg);
12827
12828 if (acfg->dwarf) {
12829 emit_dwarf_info (acfg);
12830 mono_dwarf_writer_close (acfg->dwarf);
12831 } else {
12832 if (!acfg->aot_opts.nodebug)
12833 emit_codeview_info (acfg);
12834 }
12835
12836 emit_mem_end (acfg);
12837
12838 if (acfg->need_pt_gnu_stack) {
12839 /* This is required so the .so doesn't have an executable stack */
12840 /* The bin writer already emits this */
12841 fprintf (acfg->fp, "\n.section .note.GNU-stack,\"\",@progbits\n");
12842 }
12843
12844 if (acfg->aot_opts.data_outfile)
12845 fclose (acfg->data_outfile);
12846
12847 #ifdef ENABLE_LLVM
12848 if (acfg->llvm) {
12849 gboolean res;
12850
12851 res = emit_llvm_file (acfg);
12852 if (!res)
12853 return 1;
12854 }
12855 #endif
12856
12857 TV_GETTIME (btv);
12858
12859 acfg->stats.gen_time = TV_ELAPSED (atv, btv);
12860
12861 if (acfg->llvm)
12862 sprintf (llvm_stats_msg, ", LLVM: %d (%d%%)", acfg->stats.llvm_count, acfg->stats.mcount ? (acfg->stats.llvm_count * 100) / acfg->stats.mcount : 100);
12863 else
12864 strcpy (llvm_stats_msg, "");
12865
12866 all_sizes = acfg->stats.code_size + acfg->stats.info_size + acfg->stats.ex_info_size + acfg->stats.unwind_info_size + acfg->stats.class_info_size + acfg->stats.got_info_size + acfg->stats.offsets_size + acfg->stats.plt_size;
12867
12868 aot_printf (acfg, "Code: %d(%d%%) Info: %d(%d%%) Ex Info: %d(%d%%) Unwind Info: %d(%d%%) Class Info: %d(%d%%) PLT: %d(%d%%) GOT Info: %d(%d%%) Offsets: %d(%d%%) GOT: %d\n",
12869 (int)acfg->stats.code_size, (int)(acfg->stats.code_size * 100 / all_sizes),
12870 (int)acfg->stats.info_size, (int)(acfg->stats.info_size * 100 / all_sizes),
12871 (int)acfg->stats.ex_info_size, (int)(acfg->stats.ex_info_size * 100 / all_sizes),
12872 (int)acfg->stats.unwind_info_size, (int)(acfg->stats.unwind_info_size * 100 / all_sizes),
12873 (int)acfg->stats.class_info_size, (int)(acfg->stats.class_info_size * 100 / all_sizes),
12874 acfg->stats.plt_size ? (int)acfg->stats.plt_size : (int)acfg->plt_offset, acfg->stats.plt_size ? (int)(acfg->stats.plt_size * 100 / all_sizes) : 0,
12875 (int)acfg->stats.got_info_size, (int)(acfg->stats.got_info_size * 100 / all_sizes),
12876 (int)acfg->stats.offsets_size, (int)(acfg->stats.offsets_size * 100 / all_sizes),
12877 (int)(acfg->got_offset * sizeof (gpointer)));
12878 aot_printf (acfg, "Compiled: %d/%d (%d%%)%s, No GOT slots: %d (%d%%), Direct calls: %d (%d%%)\n",
12879 acfg->stats.ccount, acfg->stats.mcount, acfg->stats.mcount ? (acfg->stats.ccount * 100) / acfg->stats.mcount : 100,
12880 llvm_stats_msg,
12881 acfg->stats.methods_without_got_slots, acfg->stats.mcount ? (acfg->stats.methods_without_got_slots * 100) / acfg->stats.mcount : 100,
12882 acfg->stats.direct_calls, acfg->stats.all_calls ? (acfg->stats.direct_calls * 100) / acfg->stats.all_calls : 100);
12883 if (acfg->stats.genericcount)
12884 aot_printf (acfg, "%d methods are generic (%d%%)\n", acfg->stats.genericcount, acfg->stats.mcount ? (acfg->stats.genericcount * 100) / acfg->stats.mcount : 100);
12885 if (acfg->stats.abscount)
12886 aot_printf (acfg, "%d methods contain absolute addresses (%d%%)\n", acfg->stats.abscount, acfg->stats.mcount ? (acfg->stats.abscount * 100) / acfg->stats.mcount : 100);
12887 if (acfg->stats.lmfcount)
12888 aot_printf (acfg, "%d methods contain lmf pointers (%d%%)\n", acfg->stats.lmfcount, acfg->stats.mcount ? (acfg->stats.lmfcount * 100) / acfg->stats.mcount : 100);
12889 if (acfg->stats.ocount)
12890 aot_printf (acfg, "%d methods have other problems (%d%%)\n", acfg->stats.ocount, acfg->stats.mcount ? (acfg->stats.ocount * 100) / acfg->stats.mcount : 100);
12891
12892 TV_GETTIME (atv);
12893 if (acfg->w) {
12894 res = mono_img_writer_emit_writeout (acfg->w);
12895 if (res != 0) {
12896 acfg_free (acfg);
12897 return res;
12898 }
12899 res = compile_asm (acfg);
12900 if (res != 0) {
12901 acfg_free (acfg);
12902 return res;
12903 }
12904 }
12905 TV_GETTIME (btv);
12906 acfg->stats.link_time = TV_ELAPSED (atv, btv);
12907
12908 if (acfg->aot_opts.stats) {
12909 int i;
12910
12911 aot_printf (acfg, "GOT slot distribution:\n");
12912 for (i = 0; i < MONO_PATCH_INFO_NUM; ++i)
12913 if (acfg->stats.got_slot_types [i])
12914 aot_printf (acfg, "\t%s: %d (%d)\n", get_patch_name (i), acfg->stats.got_slot_types [i], acfg->stats.got_slot_info_sizes [i]);
12915 aot_printf (acfg, "\nMethod stats:\n");
12916 aot_printf (acfg, "\tNormal: %d\n", acfg->stats.method_categories [METHOD_CAT_NORMAL]);
12917 aot_printf (acfg, "\tInstance: %d\n", acfg->stats.method_categories [METHOD_CAT_INST]);
12918 aot_printf (acfg, "\tGSharedvt: %d\n", acfg->stats.method_categories [METHOD_CAT_GSHAREDVT]);
12919 aot_printf (acfg, "\tWrapper: %d\n", acfg->stats.method_categories [METHOD_CAT_WRAPPER]);
12920 }
12921
12922 aot_printf (acfg, "JIT time: %d ms, Generation time: %d ms, Assembly+Link time: %d ms.\n", acfg->stats.jit_time / 1000, acfg->stats.gen_time / 1000, acfg->stats.link_time / 1000);
12923
12924 if (acfg->aot_opts.dump_json)
12925 aot_dump (acfg);
12926
12927 acfg_free (acfg);
12928
12929 return 0;
12930 }
12931
12932 #else
12933
12934 /* AOT disabled */
12935
12936 void*
mono_aot_readonly_field_override(MonoClassField * field)12937 mono_aot_readonly_field_override (MonoClassField *field)
12938 {
12939 return NULL;
12940 }
12941
12942 int
mono_compile_assembly(MonoAssembly * ass,guint32 opts,const char * aot_options,gpointer ** aot_state)12943 mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options, gpointer **aot_state)
12944 {
12945 return 0;
12946 }
12947
12948 gboolean
mono_aot_is_shared_got_offset(int offset)12949 mono_aot_is_shared_got_offset (int offset)
12950 {
12951 return FALSE;
12952 }
12953
12954 int
mono_compile_deferred_assemblies(guint32 opts,const char * aot_options,gpointer ** aot_state)12955 mono_compile_deferred_assemblies (guint32 opts, const char *aot_options, gpointer **aot_state)
12956 {
12957 g_assert_not_reached ();
12958 return 0;
12959 }
12960
12961 #endif
12962