2 * aot-compiler.c: mono Ahead of Time compiler
5 * Dietmar Maurer (dietmar@ximian.com)
6 * Zoltan Varga (vargaz@gmail.com)
8 * (C) 2002 Ximian, Inc.
11 /* Remaining AOT-only work:
12 * - reduce the length of the wrapper names.
13 * - aot IMT tables, so we don't have two kinds of aot code.
14 * - optimize the trampolines, generate more code in the arch files.
15 * - make things more consistent with how elf works, for example, use ELF
17 * Remaining generics sharing work:
18 * - optimize the size of the data which is encoded.
19 * - optimize the runtime loading of data:
20 * - the trampoline code calls mono_jit_info_table_find () to find the rgctx,
21 * which loads the debugging+exception handling info for the method. This is a
22 * huge waste of time and code, since the rgctx structure is currently empty.
23 * - every shared method has a MonoGenericJitInfo structure which is only really
24 * used for handling catch clauses with open types, not a very common use case.
28 #include <sys/types.h>
38 #ifndef PLATFORM_WIN32
47 #include <limits.h> /* for PAGESIZE */
52 #include <mono/metadata/tabledefs.h>
53 #include <mono/metadata/class.h>
54 #include <mono/metadata/object.h>
55 #include <mono/metadata/tokentype.h>
56 #include <mono/metadata/appdomain.h>
57 #include <mono/metadata/debug-helpers.h>
58 #include <mono/metadata/assembly.h>
59 #include <mono/metadata/metadata-internals.h>
60 #include <mono/metadata/marshal.h>
61 #include <mono/metadata/gc-internal.h>
62 #include <mono/metadata/monitor.h>
63 #include <mono/metadata/mempool-internals.h>
64 #include <mono/metadata/mono-endian.h>
65 #include <mono/utils/mono-logger.h>
66 #include <mono/utils/mono-compiler.h>
67 #include <mono/utils/mono-time.h>
70 #include "image-writer.h"
71 #include "dwarfwriter.h"
75 #define TV_DECLARE(name) gint64 name
76 #define TV_GETTIME(tv) tv = mono_100ns_ticks ()
77 #define TV_ELAPSED(start,end) (((end) - (start)) / 10)
80 #define SHARED_EXT ".dll"
81 #elif defined(__ppc__) && defined(__MACH__)
82 #define SHARED_EXT ".dylib"
84 #define SHARED_EXT ".so"
87 #define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1))
88 #define ALIGN_PTR_TO(ptr,align) (gpointer)((((gssize)(ptr)) + (align - 1)) & (~(align - 1)))
89 #define ROUND_DOWN(VALUE,SIZE) ((VALUE) & ~((SIZE) - 1))
91 typedef struct MonoAotOptions
{
94 gboolean write_symbols
;
95 gboolean metadata_only
;
96 gboolean bind_to_runtime_version
;
103 gboolean print_skipped_methods
;
106 typedef struct MonoAotStats
{
107 int ccount
, mcount
, lmfcount
, abscount
, gcount
, ocount
, genericcount
;
108 int code_size
, info_size
, ex_info_size
, got_size
, class_info_size
, got_info_size
, got_info_offsets_size
;
109 int methods_without_got_slots
, direct_calls
, all_calls
;
111 int got_slot_types
[MONO_PATCH_INFO_NONE
];
112 int jit_time
, gen_time
, link_time
;
115 typedef struct MonoAotCompile
{
118 GHashTable
*method_indexes
;
121 GHashTable
*patch_to_plt_offset
;
122 GHashTable
*plt_offset_to_patch
;
123 GHashTable
*patch_to_shared_got_offset
;
124 GPtrArray
*shared_patches
;
125 GHashTable
*image_hash
;
126 GHashTable
*method_to_cfg
;
127 GHashTable
*token_info_hash
;
128 GPtrArray
*extra_methods
;
129 GPtrArray
*image_table
;
132 guint32
*plt_got_info_offsets
;
133 /* Number of trampolines emitted into the AOT file */
134 guint32 num_aot_trampolines
;
135 guint32 got_offset
, plt_offset
, plt_got_offset_base
;
136 /* Number of GOT entries reserved for trampolines */
137 guint32 num_trampoline_got_entries
;
138 guint32 trampoline_got_offset_base
;
139 guint32 specific_trampoline_size
;
140 MonoAotOptions aot_opts
;
143 MonoMemPool
*mempool
;
146 char *static_linking_symbol
;
147 CRITICAL_SECTION mutex
;
148 gboolean use_bin_writer
;
150 MonoDwarfWriter
*dwarf
;
156 #define mono_acfg_lock(acfg) EnterCriticalSection (&((acfg)->mutex))
157 #define mono_acfg_unlock(acfg) LeaveCriticalSection (&((acfg)->mutex))
159 #ifdef HAVE_ARRAY_ELEM_INIT
160 #define MSGSTRFIELD(line) MSGSTRFIELD1(line)
161 #define MSGSTRFIELD1(line) str##line
162 static const struct msgstr_t
{
163 #define PATCH_INFO(a,b) char MSGSTRFIELD(__LINE__) [sizeof (b)];
164 #include "patch-info.h"
167 #define PATCH_INFO(a,b) b,
168 #include "patch-info.h"
171 static const gint16 opidx
[] = {
172 #define PATCH_INFO(a,b) [MONO_PATCH_INFO_ ## a] = offsetof (struct msgstr_t, MSGSTRFIELD(__LINE__)),
173 #include "patch-info.h"
178 get_patch_name (int info
)
180 return (const char*)&opstr
+ opidx
[info
];
184 #define PATCH_INFO(a,b) b,
185 static const char* const
186 patch_types
[MONO_PATCH_INFO_NUM
+ 1] = {
187 #include "patch-info.h"
192 get_patch_name (int info
)
194 return patch_types
[info
];
200 emit_global (MonoAotCompile
*acfg
, const char *name
, gboolean func
);
202 /* Wrappers around the image writer functions */
205 emit_section_change (MonoAotCompile
*acfg
, const char *section_name
, int subsection_index
)
207 img_writer_emit_section_change (acfg
->w
, section_name
, subsection_index
);
211 emit_push_section (MonoAotCompile
*acfg
, const char *section_name
, int subsection
)
213 img_writer_emit_push_section (acfg
->w
, section_name
, subsection
);
217 emit_pop_section (MonoAotCompile
*acfg
)
219 img_writer_emit_pop_section (acfg
->w
);
223 emit_local_symbol (MonoAotCompile
*acfg
, const char *name
, const char *end_label
, gboolean func
)
225 img_writer_emit_local_symbol (acfg
->w
, name
, end_label
, func
);
229 emit_label (MonoAotCompile
*acfg
, const char *name
)
231 img_writer_emit_label (acfg
->w
, name
);
235 emit_bytes (MonoAotCompile
*acfg
, const guint8
* buf
, int size
)
237 img_writer_emit_bytes (acfg
->w
, buf
, size
);
241 emit_string (MonoAotCompile
*acfg
, const char *value
)
243 img_writer_emit_string (acfg
->w
, value
);
247 emit_line (MonoAotCompile
*acfg
)
249 img_writer_emit_line (acfg
->w
);
253 emit_alignment (MonoAotCompile
*acfg
, int size
)
255 img_writer_emit_alignment (acfg
->w
, size
);
259 emit_pointer_unaligned (MonoAotCompile
*acfg
, const char *target
)
261 img_writer_emit_pointer_unaligned (acfg
->w
, target
);
265 emit_pointer (MonoAotCompile
*acfg
, const char *target
)
267 img_writer_emit_pointer (acfg
->w
, target
);
271 emit_int16 (MonoAotCompile
*acfg
, int value
)
273 img_writer_emit_int16 (acfg
->w
, value
);
277 emit_int32 (MonoAotCompile
*acfg
, int value
)
279 img_writer_emit_int32 (acfg
->w
, value
);
283 emit_symbol_diff (MonoAotCompile
*acfg
, const char *end
, const char* start
, int offset
)
285 img_writer_emit_symbol_diff (acfg
->w
, end
, start
, offset
);
289 emit_zero_bytes (MonoAotCompile
*acfg
, int num
)
291 img_writer_emit_zero_bytes (acfg
->w
, num
);
295 emit_byte (MonoAotCompile
*acfg
, guint8 val
)
297 img_writer_emit_byte (acfg
->w
, val
);
300 static G_GNUC_UNUSED
void
301 emit_global_inner (MonoAotCompile
*acfg
, const char *name
, gboolean func
)
303 img_writer_emit_global (acfg
->w
, name
, func
);
307 emit_global (MonoAotCompile
*acfg
, const char *name
, gboolean func
)
309 if (acfg
->aot_opts
.no_dlsym
) {
310 g_ptr_array_add (acfg
->globals
, g_strdup (name
));
312 img_writer_emit_global (acfg
->w
, name
, func
);
317 emit_string_symbol (MonoAotCompile
*acfg
, const char *name
, const char *value
)
319 img_writer_emit_section_change (acfg
->w
, ".text", 1);
320 emit_global (acfg
, name
, FALSE
);
321 img_writer_emit_label (acfg
->w
, name
);
322 img_writer_emit_string (acfg
->w
, value
);
325 static G_GNUC_UNUSED
void
326 emit_uleb128 (MonoAotCompile
*acfg
, guint32 value
)
329 guint8 b
= value
& 0x7f;
331 if (value
!= 0) /* more bytes to come */
337 static G_GNUC_UNUSED
void
338 emit_sleb128 (MonoAotCompile
*acfg
, gint64 value
)
341 gboolean negative
= (value
< 0);
348 /* the following is unnecessary if the
349 * implementation of >>= uses an arithmetic rather
350 * than logical shift for a signed left operand
354 value
|= - ((gint64
)1 <<(size
- 7));
355 /* sign bit of byte is second high order bit (0x40) */
356 if ((value
== 0 && !(byte
& 0x40)) ||
357 (value
== -1 && (byte
& 0x40)))
361 emit_byte (acfg
, byte
);
365 static G_GNUC_UNUSED
void
366 encode_uleb128 (guint32 value
, guint8
*buf
, guint8
**endbuf
)
371 guint8 b
= value
& 0x7f;
373 if (value
!= 0) /* more bytes to come */
381 static G_GNUC_UNUSED
void
382 encode_sleb128 (gint32 value
, guint8
*buf
, guint8
**endbuf
)
385 gboolean negative
= (value
< 0);
393 /* the following is unnecessary if the
394 * implementation of >>= uses an arithmetic rather
395 * than logical shift for a signed left operand
399 value
|= - (1 <<(size
- 7));
400 /* sign bit of byte is second high order bit (0x40) */
401 if ((value
== 0 && !(byte
& 0x40)) ||
402 (value
== -1 && (byte
& 0x40)))
412 /* ARCHITECTURE SPECIFIC CODE */
414 #if defined(__i386__) || defined(__x86_64__) || defined(__arm__)
415 #define EMIT_DWARF_INFO 1
419 * arch_emit_direct_call:
421 * Emit a direct call to the symbol TARGET. CALL_SIZE is set to the size of the
425 arch_emit_direct_call (MonoAotCompile
*acfg
, const char *target
, int *call_size
)
427 #if defined(__i386__) || defined(__x86_64__)
428 /* Need to make sure this is exactly 5 bytes long */
429 emit_byte (acfg
, '\xe8');
430 emit_symbol_diff (acfg
, target
, ".", -4);
432 #elif defined(__arm__)
433 if (acfg
->use_bin_writer
) {
440 img_writer_emit_reloc (acfg
->w
, R_ARM_CALL
, target
, -8);
441 emit_bytes (acfg
, buf
, 4);
443 img_writer_emit_unset_mode (acfg
->w
);
444 fprintf (acfg
->fp
, "bl %s\n", target
);
448 g_assert_not_reached ();
453 * arch_emit_got_access:
455 * The memory pointed to by CODE should hold native code for loading a GOT
456 * slot. Emit this code while patching it so it accesses the GOT slot GOT_SLOT.
457 * CODE_SIZE is set to the number of bytes emitted.
460 arch_emit_got_access (MonoAotCompile
*acfg
, guint8
*code
, int got_slot
, int *code_size
)
462 /* Emit beginning of instruction */
463 emit_bytes (acfg
, code
, mono_arch_get_patch_offset (code
));
465 /* Emit the offset */
467 emit_symbol_diff (acfg
, "got", ".", (unsigned int) ((got_slot
* sizeof (gpointer
)) - 4));
468 #elif defined(__i386__)
469 emit_int32 (acfg
, (unsigned int) ((got_slot
* sizeof (gpointer
))));
470 #elif defined(__arm__)
471 emit_symbol_diff (acfg
, "got", ".", (unsigned int) ((got_slot
* sizeof (gpointer
))) - 12);
473 g_assert_not_reached ();
476 *code_size
= mono_arch_get_patch_offset (code
) + 4;
480 * arch_emit_plt_entry:
482 * Emit code for the PLT entry with index INDEX.
485 arch_emit_plt_entry (MonoAotCompile
*acfg
, int index
)
487 #if defined(__i386__)
489 /* It is filled up during loading by the AOT loader. */
490 emit_zero_bytes (acfg
, 16);
492 /* Need to make sure this is 9 bytes long */
493 emit_byte (acfg
, '\xe9');
494 emit_symbol_diff (acfg
, "plt", ".", -4);
495 emit_int32 (acfg
, acfg
->plt_got_info_offsets
[index
]);
497 #elif defined(__x86_64__)
499 * We can't emit jumps because they are 32 bits only so they can't be patched.
500 * So we make indirect calls through GOT entries which are patched by the AOT
501 * loader to point to .Lpd entries.
502 * An x86_64 plt entry is 10 bytes long, init_plt () depends on this.
504 /* jmpq *<offset>(%rip) */
505 emit_byte (acfg
, '\xff');
506 emit_byte (acfg
, '\x25');
507 emit_symbol_diff (acfg
, "got", ".", ((acfg
->plt_got_offset_base
+ index
) * sizeof (gpointer
)) -4);
508 /* Used by mono_aot_get_plt_info_offset */
509 emit_int32 (acfg
, acfg
->plt_got_info_offsets
[index
]);
510 #elif defined(__arm__)
515 * - optimize OP_AOTCONST implementation
516 * - optimize the PLT entries
517 * - optimize SWITCH AOT implementation
518 * - implement IMT support
521 if (acfg
->use_bin_writer
) {
522 /* We only emit 1 relocation since we implement it ourselves anyway */
523 img_writer_emit_reloc (acfg
->w
, R_ARM_ALU_PC_G0_NC
, "got", ((acfg
->plt_got_offset_base
+ index
) * sizeof (gpointer
)) - 8);
524 /* FIXME: A 2 instruction encoding is sufficient in most cases */
525 ARM_ADD_REG_IMM (code
, ARMREG_IP
, ARMREG_PC
, 0, 0);
526 ARM_ADD_REG_IMM (code
, ARMREG_IP
, ARMREG_IP
, 0, 0);
527 ARM_LDR_IMM (code
, ARMREG_PC
, ARMREG_IP
, 0);
528 emit_bytes (acfg
, buf
, code
- buf
);
529 /* FIXME: Get rid of this */
530 emit_symbol_diff (acfg
, "got", ".", ((acfg
->plt_got_offset_base
+ index
) * sizeof (gpointer
)));
531 /* Used by mono_aot_get_plt_info_offset */
532 emit_int32 (acfg
, acfg
->plt_got_info_offsets
[index
]);
534 ARM_LDR_IMM (code
, ARMREG_IP
, ARMREG_PC
, 4);
535 ARM_ADD_REG_REG (code
, ARMREG_IP
, ARMREG_PC
, ARMREG_IP
);
536 ARM_LDR_IMM (code
, ARMREG_PC
, ARMREG_IP
, 0);
537 emit_bytes (acfg
, buf
, code
- buf
);
538 emit_symbol_diff (acfg
, "got", ".", ((acfg
->plt_got_offset_base
+ index
) * sizeof (gpointer
)));
539 /* Used by mono_aot_get_plt_info_offset */
540 emit_int32 (acfg
, acfg
->plt_got_info_offsets
[index
]);
543 g_assert_not_reached ();
548 * arch_emit_specific_trampoline:
550 * Emit code for a specific trampoline. OFFSET is the offset of the first of
551 * two GOT slots which contain the generic trampoline address and the trampoline
552 * argument. TRAMP_SIZE is set to the size of the emitted trampoline.
555 arch_emit_specific_trampoline (MonoAotCompile
*acfg
, int offset
, int *tramp_size
)
558 * The trampolines created here are variations of the specific
559 * trampolines created in mono_arch_create_specific_trampoline (). The
561 * - the generic trampoline address is taken from a got slot.
562 * - the offset of the got slot where the trampoline argument is stored
563 * is embedded in the instruction stream, and the generic trampoline
564 * can load the argument by loading the offset, adding it to the
565 * address of the trampoline to get the address of the got slot, and
566 * loading the argument from there.
567 * - all the trampolines should be of the same length.
569 #if defined(__x86_64__)
570 /* This should be exactly 16 bytes long */
572 /* call *<offset>(%rip) */
573 emit_byte (acfg
, '\x41');
574 emit_byte (acfg
, '\xff');
575 emit_byte (acfg
, '\x15');
576 emit_symbol_diff (acfg
, "got", ".", (offset
* sizeof (gpointer
)) - 4);
577 /* This should be relative to the start of the trampoline */
578 emit_symbol_diff (acfg
, "got", ".", (offset
* sizeof (gpointer
)) - 4 + 19);
579 emit_zero_bytes (acfg
, 5);
580 #elif defined(__arm__)
584 /* This should be exactly 28 bytes long */
587 ARM_PUSH (code
, 0x5fff);
588 ARM_LDR_IMM (code
, ARMREG_R1
, ARMREG_PC
, 8);
589 /* Load the value from the GOT */
590 ARM_LDR_REG_REG (code
, ARMREG_R1
, ARMREG_PC
, ARMREG_R1
);
592 ARM_MOV_REG_REG (code
, ARMREG_LR
, ARMREG_PC
);
593 ARM_MOV_REG_REG (code
, ARMREG_PC
, ARMREG_R1
);
595 g_assert (code
- buf
== 20);
598 emit_bytes (acfg
, buf
, code
- buf
);
599 emit_symbol_diff (acfg
, "got", ".", (offset
* sizeof (gpointer
)) - 4 + 8);
600 emit_symbol_diff (acfg
, "got", ".", ((offset
+ 1) * sizeof (gpointer
)) - 4 + 8);
602 g_assert_not_reached ();
607 * arch_emit_unbox_trampoline:
609 * Emit code for the unbox trampoline for METHOD used in the full-aot case.
610 * CALL_TARGET is the symbol pointing to the native code of METHOD.
613 arch_emit_unbox_trampoline (MonoAotCompile
*acfg
, MonoMethod
*method
, MonoGenericSharingContext
*gsctx
, const char *call_target
)
615 #if defined(__x86_64__)
620 this_reg
= mono_arch_get_this_arg_reg (mono_method_signature (method
), gsctx
, NULL
);
622 amd64_alu_reg_imm (code
, X86_ADD
, this_reg
, sizeof (MonoObject
));
624 emit_bytes (acfg
, buf
, code
- buf
);
626 emit_byte (acfg
, '\xe9');
627 emit_symbol_diff (acfg
, call_target
, ".", -4);
628 #elif defined(__arm__)
635 if (MONO_TYPE_ISSTRUCT (mono_method_signature (method
)->ret
))
638 ARM_ADD_REG_IMM8 (code
, this_pos
, this_pos
, sizeof (MonoObject
));
640 emit_bytes (acfg
, buf
, code
- buf
);
642 if (acfg
->use_bin_writer
)
643 g_assert_not_reached ();
645 fprintf (acfg
->fp
, "\n\tb %s\n", call_target
);
647 g_assert_not_reached ();
652 * arch_get_cie_program:
654 * Get the unwind bytecode for the DWARF CIE.
657 arch_get_cie_program (void)
662 mono_add_unwind_op_def_cfa (l
, (guint8
*)NULL
, (guint8
*)NULL
, AMD64_RSP
, 8);
663 mono_add_unwind_op_offset (l
, (guint8
*)NULL
, (guint8
*)NULL
, AMD64_RIP
, -8);
671 /* END OF ARCH SPECIFIC CODE */
674 mono_get_field_token (MonoClassField
*field
)
676 MonoClass
*klass
= field
->parent
;
679 for (i
= 0; i
< klass
->field
.count
; ++i
) {
680 if (field
== &klass
->fields
[i
])
681 return MONO_TOKEN_FIELD_DEF
| (klass
->field
.first
+ 1 + i
);
684 g_assert_not_reached ();
689 encode_value (gint32 value
, guint8
*buf
, guint8
**endbuf
)
693 //printf ("ENCODE: %d 0x%x.\n", value, value);
696 * Same encoding as the one used in the metadata, extended to handle values
697 * greater than 0x1fffffff.
699 if ((value
>= 0) && (value
<= 127))
701 else if ((value
>= 0) && (value
<= 16383)) {
702 p
[0] = 0x80 | (value
>> 8);
703 p
[1] = value
& 0xff;
705 } else if ((value
>= 0) && (value
<= 0x1fffffff)) {
706 p
[0] = (value
>> 24) | 0xc0;
707 p
[1] = (value
>> 16) & 0xff;
708 p
[2] = (value
>> 8) & 0xff;
709 p
[3] = value
& 0xff;
714 p
[1] = (value
>> 24) & 0xff;
715 p
[2] = (value
>> 16) & 0xff;
716 p
[3] = (value
>> 8) & 0xff;
717 p
[4] = value
& 0xff;
725 get_image_index (MonoAotCompile
*cfg
, MonoImage
*image
)
729 index
= GPOINTER_TO_UINT (g_hash_table_lookup (cfg
->image_hash
, image
));
733 index
= g_hash_table_size (cfg
->image_hash
);
734 g_hash_table_insert (cfg
->image_hash
, image
, GUINT_TO_POINTER (index
+ 1));
735 g_ptr_array_add (cfg
->image_table
, image
);
741 find_typespec_for_class (MonoAotCompile
*acfg
, MonoClass
*klass
)
746 /* FIXME: Search referenced images as well */
747 for (i
= 0; i
< acfg
->image
->tables
[MONO_TABLE_TYPESPEC
].rows
; ++i
) {
748 k
= mono_class_get_full (acfg
->image
, MONO_TOKEN_TYPE_SPEC
| (i
+ 1), NULL
);
753 if (i
< acfg
->image
->tables
[MONO_TABLE_TYPESPEC
].rows
)
754 return MONO_TOKEN_TYPE_SPEC
| (i
+ 1);
760 encode_method_ref (MonoAotCompile
*acfg
, MonoMethod
*method
, guint8
*buf
, guint8
**endbuf
);
765 * Encode a reference to KLASS. We use our home-grown encoding instead of the
766 * standard metadata encoding.
769 encode_klass_ref (MonoAotCompile
*acfg
, MonoClass
*klass
, guint8
*buf
, guint8
**endbuf
)
773 if (klass
->generic_class
) {
775 g_assert (klass
->type_token
);
777 /* Find a typespec for a class if possible */
778 token
= find_typespec_for_class (acfg
, klass
);
780 encode_value (token
, p
, &p
);
781 encode_value (get_image_index (acfg
, acfg
->image
), p
, &p
);
783 MonoClass
*gclass
= klass
->generic_class
->container_class
;
784 MonoGenericInst
*inst
= klass
->generic_class
->context
.class_inst
;
787 /* Encode it ourselves */
789 encode_value (MONO_TOKEN_TYPE_SPEC
, p
, &p
);
790 encode_value (MONO_TYPE_GENERICINST
, p
, &p
);
791 encode_klass_ref (acfg
, gclass
, p
, &p
);
792 encode_value (inst
->type_argc
, p
, &p
);
793 for (i
= 0; i
< inst
->type_argc
; ++i
)
794 encode_klass_ref (acfg
, mono_class_from_mono_type (inst
->type_argv
[i
]), p
, &p
);
796 } else if (klass
->type_token
) {
797 g_assert (mono_metadata_token_code (klass
->type_token
) == MONO_TOKEN_TYPE_DEF
);
798 encode_value (klass
->type_token
- MONO_TOKEN_TYPE_DEF
, p
, &p
);
799 encode_value (get_image_index (acfg
, klass
->image
), p
, &p
);
800 } else if ((klass
->byval_arg
.type
== MONO_TYPE_VAR
) || (klass
->byval_arg
.type
== MONO_TYPE_MVAR
)) {
801 MonoGenericParam
*param
= klass
->byval_arg
.data
.generic_param
;
804 encode_value (MONO_TOKEN_TYPE_SPEC
, p
, &p
);
805 encode_value (klass
->byval_arg
.type
, p
, &p
);
807 encode_value (param
->num
, p
, &p
);
809 g_assert (param
->owner
);
810 encode_value (param
->owner
->is_method
, p
, &p
);
811 if (param
->owner
->is_method
)
812 encode_method_ref (acfg
, param
->owner
->owner
.method
, p
, &p
);
814 encode_klass_ref (acfg
, param
->owner
->owner
.klass
, p
, &p
);
817 g_assert (klass
->rank
> 0);
818 encode_value (MONO_TOKEN_TYPE_DEF
, p
, &p
);
819 encode_value (get_image_index (acfg
, klass
->image
), p
, &p
);
820 encode_value (klass
->rank
, p
, &p
);
821 encode_klass_ref (acfg
, klass
->element_class
, p
, &p
);
827 encode_field_info (MonoAotCompile
*cfg
, MonoClassField
*field
, guint8
*buf
, guint8
**endbuf
)
829 guint32 token
= mono_get_field_token (field
);
832 encode_klass_ref (cfg
, field
->parent
, p
, &p
);
833 g_assert (mono_metadata_token_code (token
) == MONO_TOKEN_FIELD_DEF
);
834 encode_value (token
- MONO_TOKEN_FIELD_DEF
, p
, &p
);
839 encode_generic_context (MonoAotCompile
*acfg
, MonoGenericContext
*context
, guint8
*buf
, guint8
**endbuf
)
843 MonoGenericInst
*inst
;
845 /* Encode the context */
846 inst
= context
->class_inst
;
847 encode_value (inst
? 1 : 0, p
, &p
);
849 encode_value (inst
->type_argc
, p
, &p
);
850 for (i
= 0; i
< inst
->type_argc
; ++i
)
851 encode_klass_ref (acfg
, mono_class_from_mono_type (inst
->type_argv
[i
]), p
, &p
);
853 inst
= context
->method_inst
;
854 encode_value (inst
? 1 : 0, p
, &p
);
856 encode_value (inst
->type_argc
, p
, &p
);
857 for (i
= 0; i
< inst
->type_argc
; ++i
)
858 encode_klass_ref (acfg
, mono_class_from_mono_type (inst
->type_argv
[i
]), p
, &p
);
864 #define MAX_IMAGE_INDEX 250
867 encode_method_ref (MonoAotCompile
*acfg
, MonoMethod
*method
, guint8
*buf
, guint8
**endbuf
)
869 guint32 image_index
= get_image_index (acfg
, method
->klass
->image
);
870 guint32 token
= method
->token
;
871 MonoJumpInfoToken
*ji
;
876 * The encoding for most methods is as follows:
877 * - image index encoded as a leb128
878 * - token index encoded as a leb128
879 * Values of image index >= MONO_AOT_METHODREF_MIN are used to mark additional
880 * types of method encodings.
883 g_assert (image_index
< MONO_AOT_METHODREF_MIN
);
885 /* Mark methods which can't use aot trampolines because they need the further
886 * processing in mono_magic_trampoline () which requires a MonoMethod*.
888 if ((method
->is_generic
&& (method
->flags
& METHOD_ATTRIBUTE_VIRTUAL
)) ||
889 (method
->iflags
& METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED
))
890 encode_value ((MONO_AOT_METHODREF_NO_AOT_TRAMPOLINE
<< 24), p
, &p
);
893 * Some wrapper methods are shared using their signature, encode their
894 * stringified signature instead.
895 * FIXME: Optimize disk usage
898 if (method
->wrapper_type
) {
899 if (method
->wrapper_type
== MONO_WRAPPER_RUNTIME_INVOKE
) {
900 char *tmpsig
= mono_signature_get_desc (mono_method_signature (method
), TRUE
);
901 name
= g_strdup_printf ("(wrapper runtime-invoke):%s (%s)", method
->name
, tmpsig
);
903 } else if (method
->wrapper_type
== MONO_WRAPPER_DELEGATE_INVOKE
) {
904 char *tmpsig
= mono_signature_get_desc (mono_method_signature (method
), TRUE
);
905 name
= g_strdup_printf ("(wrapper delegate-invoke):%s (%s)", method
->name
, tmpsig
);
907 } else if (method
->wrapper_type
== MONO_WRAPPER_DELEGATE_BEGIN_INVOKE
) {
908 char *tmpsig
= mono_signature_get_desc (mono_method_signature (method
), TRUE
);
909 name
= g_strdup_printf ("(wrapper delegate-begin-invoke):%s (%s)", method
->name
, tmpsig
);
911 } else if (method
->wrapper_type
== MONO_WRAPPER_DELEGATE_END_INVOKE
) {
912 char *tmpsig
= mono_signature_get_desc (mono_method_signature (method
), TRUE
);
913 name
= g_strdup_printf ("(wrapper delegate-end-invoke):%s (%s)", method
->name
, tmpsig
);
919 encode_value ((MONO_AOT_METHODREF_WRAPPER_NAME
<< 24), p
, &p
);
920 strcpy ((char*)p
, name
);
921 p
+= strlen (name
) + 1;
923 } else if (method
->wrapper_type
) {
924 encode_value ((MONO_AOT_METHODREF_WRAPPER
<< 24), p
, &p
);
926 encode_value (method
->wrapper_type
, p
, &p
);
928 switch (method
->wrapper_type
) {
929 case MONO_WRAPPER_REMOTING_INVOKE
:
930 case MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK
:
931 case MONO_WRAPPER_XDOMAIN_INVOKE
: {
934 m
= mono_marshal_method_from_wrapper (method
);
936 encode_method_ref (acfg
, m
, p
, &p
);
939 case MONO_WRAPPER_PROXY_ISINST
:
940 case MONO_WRAPPER_LDFLD
:
941 case MONO_WRAPPER_LDFLDA
:
942 case MONO_WRAPPER_STFLD
:
943 case MONO_WRAPPER_ISINST
: {
944 MonoClass
*proxy_class
= (MonoClass
*)mono_marshal_method_from_wrapper (method
);
945 encode_klass_ref (acfg
, proxy_class
, p
, &p
);
948 case MONO_WRAPPER_LDFLD_REMOTE
:
949 case MONO_WRAPPER_STFLD_REMOTE
:
951 case MONO_WRAPPER_ALLOC
: {
952 int alloc_type
= mono_gc_get_managed_allocator_type (method
);
953 g_assert (alloc_type
!= -1);
954 encode_value (alloc_type
, p
, &p
);
957 case MONO_WRAPPER_STELEMREF
:
959 case MONO_WRAPPER_UNKNOWN
:
960 if (strcmp (method
->name
, "FastMonitorEnter") == 0)
961 encode_value (MONO_AOT_WRAPPER_MONO_ENTER
, p
, &p
);
962 else if (strcmp (method
->name
, "FastMonitorExit") == 0)
963 encode_value (MONO_AOT_WRAPPER_MONO_EXIT
, p
, &p
);
965 g_assert_not_reached ();
967 case MONO_WRAPPER_STATIC_RGCTX_INVOKE
:
968 case MONO_WRAPPER_SYNCHRONIZED
: {
971 m
= mono_marshal_method_from_wrapper (method
);
973 encode_method_ref (acfg
, m
, p
, &p
);
977 g_assert_not_reached ();
979 } else if (mono_method_signature (method
)->is_inflated
) {
981 * This is a generic method, find the original token which referenced it and
983 * Obtain the token from information recorded by the JIT.
985 ji
= g_hash_table_lookup (acfg
->token_info_hash
, method
);
987 image_index
= get_image_index (acfg
, ji
->image
);
988 g_assert (image_index
< MAX_IMAGE_INDEX
);
991 encode_value ((MONO_AOT_METHODREF_METHODSPEC
<< 24), p
, &p
);
992 encode_value (image_index
, p
, &p
);
993 encode_value (token
, p
, &p
);
995 MonoMethod
*declaring
;
996 MonoGenericContext
*context
= mono_method_get_context (method
);
998 g_assert (method
->is_inflated
);
999 declaring
= ((MonoMethodInflated
*)method
)->declaring
;
1002 * This might be a non-generic method of a generic instance, which
1003 * doesn't have a token since the reference is generated by the JIT
1004 * like Nullable:Box/Unbox, or by generic sharing.
1007 encode_value ((MONO_AOT_METHODREF_GINST
<< 24), p
, &p
);
1008 /* Encode the klass */
1009 encode_klass_ref (acfg
, method
->klass
, p
, &p
);
1010 /* Encode the method */
1011 image_index
= get_image_index (acfg
, method
->klass
->image
);
1012 g_assert (image_index
< MAX_IMAGE_INDEX
);
1013 g_assert (declaring
->token
);
1014 token
= declaring
->token
;
1015 g_assert (mono_metadata_token_table (token
) == MONO_TABLE_METHOD
);
1016 encode_value (image_index
, p
, &p
);
1017 encode_value (token
, p
, &p
);
1018 encode_generic_context (acfg
, context
, p
, &p
);
1020 } else if (token
== 0) {
1021 /* This might be a method of a constructed type like int[,].Set */
1022 /* Obtain the token from information recorded by the JIT */
1023 ji
= g_hash_table_lookup (acfg
->token_info_hash
, method
);
1025 image_index
= get_image_index (acfg
, ji
->image
);
1026 g_assert (image_index
< MAX_IMAGE_INDEX
);
1029 encode_value ((MONO_AOT_METHODREF_METHODSPEC
<< 24), p
, &p
);
1030 encode_value (image_index
, p
, &p
);
1031 encode_value (token
, p
, &p
);
1034 g_assert (method
->klass
->rank
);
1036 /* Encode directly */
1037 encode_value ((MONO_AOT_METHODREF_ARRAY
<< 24), p
, &p
);
1038 encode_klass_ref (acfg
, method
->klass
, p
, &p
);
1039 if (!strcmp (method
->name
, ".ctor") && mono_method_signature (method
)->param_count
== method
->klass
->rank
)
1040 encode_value (0, p
, &p
);
1041 else if (!strcmp (method
->name
, ".ctor") && mono_method_signature (method
)->param_count
== method
->klass
->rank
* 2)
1042 encode_value (1, p
, &p
);
1043 else if (!strcmp (method
->name
, "Get"))
1044 encode_value (2, p
, &p
);
1045 else if (!strcmp (method
->name
, "Address"))
1046 encode_value (3, p
, &p
);
1047 else if (!strcmp (method
->name
, "Set"))
1048 encode_value (4, p
, &p
);
1050 g_assert_not_reached ();
1053 g_assert (mono_metadata_token_table (token
) == MONO_TABLE_METHOD
);
1054 encode_value ((image_index
<< 24) | mono_metadata_token_index (token
), p
, &p
);
1060 compare_patches (gconstpointer a
, gconstpointer b
)
1064 i
= (*(MonoJumpInfo
**)a
)->ip
.i
;
1065 j
= (*(MonoJumpInfo
**)b
)->ip
.i
;
1079 * Return whenever PATCH_INFO refers to a direct call, and thus requires a
1082 static inline gboolean
1083 is_plt_patch (MonoJumpInfo
*patch_info
)
1085 switch (patch_info
->type
) {
1086 case MONO_PATCH_INFO_METHOD
:
1087 case MONO_PATCH_INFO_INTERNAL_METHOD
:
1088 case MONO_PATCH_INFO_JIT_ICALL_ADDR
:
1089 case MONO_PATCH_INFO_ICALL_ADDR
:
1090 case MONO_PATCH_INFO_CLASS_INIT
:
1091 case MONO_PATCH_INFO_RGCTX_FETCH
:
1092 case MONO_PATCH_INFO_GENERIC_CLASS_INIT
:
1093 case MONO_PATCH_INFO_MONITOR_ENTER
:
1094 case MONO_PATCH_INFO_MONITOR_EXIT
:
1102 is_got_patch (MonoJumpInfoType patch_type
)
1108 * is_shared_got_patch:
1110 * Return whenever PATCH_INFO refers to a patch which needs a shared GOT
1112 * Keep it in sync with the version in aot-runtime.c.
1114 static inline gboolean
1115 is_shared_got_patch (MonoJumpInfo
*patch_info
)
1117 switch (patch_info
->type
) {
1118 case MONO_PATCH_INFO_VTABLE
:
1119 case MONO_PATCH_INFO_CLASS
:
1120 case MONO_PATCH_INFO_IID
:
1121 case MONO_PATCH_INFO_ADJUSTED_IID
:
1122 case MONO_PATCH_INFO_FIELD
:
1123 case MONO_PATCH_INFO_SFLDA
:
1124 case MONO_PATCH_INFO_DECLSEC
:
1125 case MONO_PATCH_INFO_LDTOKEN
:
1126 case MONO_PATCH_INFO_TYPE_FROM_HANDLE
:
1127 case MONO_PATCH_INFO_RVA
:
1128 case MONO_PATCH_INFO_METHODCONST
:
1129 case MONO_PATCH_INFO_IMAGE
:
1137 get_plt_offset (MonoAotCompile
*acfg
, MonoJumpInfo
*patch_info
)
1141 if (is_plt_patch (patch_info
)) {
1142 int idx
= GPOINTER_TO_UINT (g_hash_table_lookup (acfg
->patch_to_plt_offset
, patch_info
));
1144 if (patch_info
->type
== MONO_PATCH_INFO_METHOD
&& (patch_info
->data
.method
->iflags
& METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED
)) {
1146 * Allocate a separate PLT slot for each such patch, since some plt
1147 * entries will refer to the method itself, and some will refer to
1156 MonoJumpInfo
*new_ji
= mono_patch_info_dup_mp (acfg
->mempool
, patch_info
);
1158 res
= acfg
->plt_offset
;
1159 g_hash_table_insert (acfg
->plt_offset_to_patch
, GUINT_TO_POINTER (res
), new_ji
);
1160 g_hash_table_insert (acfg
->patch_to_plt_offset
, new_ji
, GUINT_TO_POINTER (res
));
1161 acfg
->plt_offset
++;
1171 * Returns the offset of the GOT slot where the runtime object resulting from resolving
1172 * JI could be found if it exists, otherwise allocates a new one.
1175 get_got_offset (MonoAotCompile
*acfg
, MonoJumpInfo
*ji
)
1179 got_offset
= GPOINTER_TO_UINT (g_hash_table_lookup (acfg
->patch_to_shared_got_offset
, ji
));
1181 return got_offset
- 1;
1183 got_offset
= acfg
->got_offset
;
1184 acfg
->got_offset
++;
1186 acfg
->stats
.got_slots
++;
1187 acfg
->stats
.got_slot_types
[ji
->type
] ++;
1193 get_shared_got_offset (MonoAotCompile
*acfg
, MonoJumpInfo
*ji
)
1198 if (!g_hash_table_lookup (acfg
->patch_to_shared_got_offset
, ji
)) {
1199 got_offset
= get_got_offset (acfg
, ji
);
1200 copy
= mono_patch_info_dup_mp (acfg
->mempool
, ji
);
1201 g_hash_table_insert (acfg
->patch_to_shared_got_offset
, copy
, GUINT_TO_POINTER (got_offset
+ 1));
1202 g_ptr_array_add (acfg
->shared_patches
, copy
);
1205 return get_got_offset (acfg
, ji
);
1208 /* Add a method to the list of methods which need to be emitted */
1210 add_method_with_index (MonoAotCompile
*acfg
, MonoMethod
*method
, int index
)
1213 if (!g_hash_table_lookup (acfg
->method_indexes
, method
)) {
1214 g_ptr_array_add (acfg
->methods
, method
);
1215 g_hash_table_insert (acfg
->method_indexes
, method
, GUINT_TO_POINTER (index
+ 1));
1216 acfg
->nmethods
= acfg
->methods
->len
+ 1;
1221 get_method_index (MonoAotCompile
*acfg
, MonoMethod
*method
)
1223 int index
= GPOINTER_TO_UINT (g_hash_table_lookup (acfg
->method_indexes
, method
));
1231 add_method (MonoAotCompile
*acfg
, MonoMethod
*method
)
1235 index
= GPOINTER_TO_UINT (g_hash_table_lookup (acfg
->method_indexes
, method
));
1239 index
= acfg
->method_index
;
1240 add_method_with_index (acfg
, method
, index
);
1242 /* FIXME: Fix quadratic behavior */
1243 acfg
->method_order
= g_list_append (acfg
->method_order
, GUINT_TO_POINTER (index
));
1245 acfg
->method_index
++;
1251 add_extra_method (MonoAotCompile
*acfg
, MonoMethod
*method
)
1255 index
= GPOINTER_TO_UINT (g_hash_table_lookup (acfg
->method_indexes
, method
));
1258 add_method (acfg
, method
);
1259 g_ptr_array_add (acfg
->extra_methods
, method
);
1263 add_jit_icall_wrapper (gpointer key
, gpointer value
, gpointer user_data
)
1265 MonoAotCompile
*acfg
= user_data
;
1266 MonoJitICallInfo
*callinfo
= value
;
1267 MonoMethod
*wrapper
;
1273 name
= g_strdup_printf ("__icall_wrapper_%s", callinfo
->name
);
1274 wrapper
= mono_marshal_get_icall_wrapper (callinfo
->sig
, name
, callinfo
->func
, check_for_pending_exc
);
1277 add_method (acfg
, wrapper
);
1281 get_runtime_invoke_sig (MonoMethodSignature
*sig
)
1283 MonoMethodBuilder
*mb
;
1286 mb
= mono_mb_new (mono_defaults
.object_class
, "FOO", MONO_WRAPPER_NONE
);
1287 m
= mono_mb_create_method (mb
, sig
, 16);
1288 return mono_marshal_get_runtime_invoke (m
, FALSE
);
1292 add_wrappers (MonoAotCompile
*acfg
)
1294 MonoMethod
*method
, *m
;
1295 int i
, j
, nallocators
;
1296 MonoMethodSignature
*sig
, *csig
;
1300 * FIXME: Instead of AOTing all the wrappers, it might be better to redesign them
1301 * so there is only one wrapper of a given type, or inlining their contents into their
1306 * FIXME: This depends on the fact that different wrappers have different
1310 /* FIXME: Collect these automatically */
1312 /* Runtime invoke wrappers */
1314 /* void runtime-invoke () [.cctor] */
1315 csig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 0);
1316 csig
->ret
= &mono_defaults
.void_class
->byval_arg
;
1317 add_method (acfg
, get_runtime_invoke_sig (csig
));
1319 /* void runtime-invoke () [Finalize] */
1320 csig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 0);
1322 csig
->ret
= &mono_defaults
.void_class
->byval_arg
;
1323 add_method (acfg
, get_runtime_invoke_sig (csig
));
1325 /* void runtime-invoke (string) [exception ctor] */
1326 csig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 1);
1328 csig
->ret
= &mono_defaults
.void_class
->byval_arg
;
1329 csig
->params
[0] = &mono_defaults
.string_class
->byval_arg
;
1330 add_method (acfg
, get_runtime_invoke_sig (csig
));
1332 /* void runtime-invoke (string, string) [exception ctor] */
1333 csig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 2);
1335 csig
->ret
= &mono_defaults
.void_class
->byval_arg
;
1336 csig
->params
[0] = &mono_defaults
.string_class
->byval_arg
;
1337 csig
->params
[1] = &mono_defaults
.string_class
->byval_arg
;
1338 add_method (acfg
, get_runtime_invoke_sig (csig
));
1340 /* string runtime-invoke () [Exception.ToString ()] */
1341 csig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 0);
1343 csig
->ret
= &mono_defaults
.string_class
->byval_arg
;
1344 add_method (acfg
, get_runtime_invoke_sig (csig
));
1346 /* void runtime-invoke (string, Exception) [exception ctor] */
1347 csig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 2);
1349 csig
->ret
= &mono_defaults
.void_class
->byval_arg
;
1350 csig
->params
[0] = &mono_defaults
.string_class
->byval_arg
;
1351 csig
->params
[1] = &mono_defaults
.exception_class
->byval_arg
;
1352 add_method (acfg
, get_runtime_invoke_sig (csig
));
1354 /* Assembly runtime-invoke (string, bool) [DoAssemblyResolve] */
1355 csig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 2);
1357 csig
->ret
= &(mono_class_from_name (
1358 mono_defaults
.corlib
, "System.Reflection", "Assembly"))->byval_arg
;
1359 csig
->params
[0] = &mono_defaults
.string_class
->byval_arg
;
1360 csig
->params
[1] = &mono_defaults
.boolean_class
->byval_arg
;
1361 add_method (acfg
, get_runtime_invoke_sig (csig
));
1363 /* runtime-invoke used by finalizers */
1364 add_method (acfg
, mono_marshal_get_runtime_invoke (mono_class_get_method_from_name_flags (mono_defaults
.object_class
, "Finalize", 0, 0), TRUE
));
1366 for (i
= 0; i
< acfg
->image
->tables
[MONO_TABLE_METHOD
].rows
; ++i
) {
1368 guint32 token
= MONO_TOKEN_METHOD_DEF
| (i
+ 1);
1369 gboolean skip
= FALSE
;
1371 method
= mono_get_method (acfg
->image
, token
, NULL
);
1373 if ((method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
) ||
1374 (method
->iflags
& METHOD_IMPL_ATTRIBUTE_RUNTIME
) ||
1375 (method
->flags
& METHOD_ATTRIBUTE_ABSTRACT
))
1378 if (method
->is_generic
|| method
->klass
->generic_container
)
1381 /* Skip methods which can not be handled by get_runtime_invoke () */
1382 sig
= mono_method_signature (method
);
1383 if ((sig
->ret
->type
== MONO_TYPE_PTR
) ||
1384 (sig
->ret
->type
== MONO_TYPE_TYPEDBYREF
))
1387 for (j
= 0; j
< sig
->param_count
; j
++) {
1388 if (sig
->params
[j
]->type
== MONO_TYPE_TYPEDBYREF
)
1393 add_method (acfg
, mono_marshal_get_runtime_invoke (method
, FALSE
));
1396 if (strcmp (acfg
->image
->assembly
->aname
.name
, "mscorlib") == 0) {
1397 MonoMethodDesc
*desc
;
1398 MonoMethod
*orig_method
;
1400 /* JIT icall wrappers */
1401 /* FIXME: locking */
1402 g_hash_table_foreach (mono_get_jit_icall_info (), add_jit_icall_wrapper
, acfg
);
1404 /* Managed Allocators */
1405 nallocators
= mono_gc_get_managed_allocator_types ();
1406 for (i
= 0; i
< nallocators
; ++i
) {
1407 m
= mono_gc_get_managed_allocator_by_type (i
);
1409 add_method (acfg
, m
);
1413 add_method (acfg
, mono_marshal_get_stelemref ());
1415 /* Monitor Enter/Exit */
1416 desc
= mono_method_desc_new ("Monitor:Enter", FALSE
);
1417 orig_method
= mono_method_desc_search_in_class (desc
, mono_defaults
.monitor_class
);
1418 g_assert (orig_method
);
1419 mono_method_desc_free (desc
);
1420 method
= mono_monitor_get_fast_path (orig_method
);
1422 add_method (acfg
, method
);
1424 desc
= mono_method_desc_new ("Monitor:Exit", FALSE
);
1425 orig_method
= mono_method_desc_search_in_class (desc
, mono_defaults
.monitor_class
);
1426 g_assert (orig_method
);
1427 mono_method_desc_free (desc
);
1428 method
= mono_monitor_get_fast_path (orig_method
);
1430 add_method (acfg
, method
);
1433 /* remoting-invoke wrappers */
1434 for (i
= 0; i
< acfg
->image
->tables
[MONO_TABLE_METHOD
].rows
; ++i
) {
1435 MonoMethodSignature
*sig
;
1437 token
= MONO_TOKEN_METHOD_DEF
| (i
+ 1);
1438 method
= mono_get_method (acfg
->image
, token
, NULL
);
1440 sig
= mono_method_signature (method
);
1442 if (sig
->hasthis
&& (method
->klass
->marshalbyref
|| method
->klass
== mono_defaults
.object_class
) &&
1443 !(method
->flags
& METHOD_ATTRIBUTE_VIRTUAL
)) {
1444 m
= mono_marshal_get_remoting_invoke_with_check (method
);
1446 add_method (acfg
, m
);
1450 /* delegate-invoke wrappers */
1451 for (i
= 0; i
< acfg
->image
->tables
[MONO_TABLE_TYPEDEF
].rows
; ++i
) {
1454 token
= MONO_TOKEN_TYPE_DEF
| (i
+ 1);
1455 klass
= mono_class_get (acfg
->image
, token
);
1457 if (klass
->delegate
&& klass
!= mono_defaults
.delegate_class
&& klass
!= mono_defaults
.multicastdelegate_class
&& !klass
->generic_container
) {
1458 method
= mono_get_delegate_invoke (klass
);
1460 m
= mono_marshal_get_delegate_invoke (method
, NULL
);
1462 add_method (acfg
, m
);
1464 method
= mono_class_get_method_from_name_flags (klass
, "BeginInvoke", -1, 0);
1465 add_method (acfg
, mono_marshal_get_delegate_begin_invoke (method
));
1467 method
= mono_class_get_method_from_name_flags (klass
, "EndInvoke", -1, 0);
1468 add_method (acfg
, mono_marshal_get_delegate_end_invoke (method
));
1472 /* Synchronized wrappers */
1473 for (i
= 0; i
< acfg
->image
->tables
[MONO_TABLE_METHOD
].rows
; ++i
) {
1474 token
= MONO_TOKEN_METHOD_DEF
| (i
+ 1);
1475 method
= mono_get_method (acfg
->image
, token
, NULL
);
1477 if (method
->iflags
& METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED
)
1478 add_method (acfg
, mono_marshal_get_synchronized_wrapper (method
));
1482 /* static rgctx wrappers */
1483 /* FIXME: Each wrapper belongs to a given instantiation of a generic method */
1484 for (i
= 0; i
< acfg
->image
->tables
[MONO_TABLE_METHOD
].rows
; ++i
) {
1485 token
= MONO_TOKEN_METHOD_DEF
| (i
+ 1);
1486 method
= mono_get_method (acfg
->image
, token
, NULL
);
1488 if (((method
->flags
& METHOD_ATTRIBUTE_STATIC
) ||
1489 (method
->is_inflated
&& mono_method_get_context (method
)->method_inst
)) &&
1490 mono_class_generic_sharing_enabled (method
->klass
) &&
1491 mono_method_is_generic_sharable_impl (method
, FALSE
)) {
1492 m
= mono_marshal_get_static_rgctx_invoke (method
);
1493 add_method (acfg
, m
);
1498 /* pinvoke wrappers */
1499 for (i
= 0; i
< acfg
->image
->tables
[MONO_TABLE_METHOD
].rows
; ++i
) {
1501 guint32 token
= MONO_TOKEN_METHOD_DEF
| (i
+ 1);
1503 method
= mono_get_method (acfg
->image
, token
, NULL
);
1505 if ((method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
) ||
1506 (method
->iflags
& METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
)) {
1507 add_method (acfg
, mono_marshal_get_native_wrapper (method
, TRUE
, TRUE
));
1513 has_type_vars (MonoClass
*klass
)
1515 if ((klass
->byval_arg
.type
== MONO_TYPE_VAR
) || (klass
->byval_arg
.type
== MONO_TYPE_MVAR
))
1518 return has_type_vars (klass
->element_class
);
1519 if (klass
->generic_class
) {
1520 MonoGenericContext
*context
= &klass
->generic_class
->context
;
1521 if (context
->class_inst
) {
1524 for (i
= 0; i
< context
->class_inst
->type_argc
; ++i
)
1525 if (has_type_vars (mono_class_from_mono_type (context
->class_inst
->type_argv
[i
])))
1533 method_has_type_vars (MonoMethod
*method
)
1535 if (has_type_vars (method
->klass
))
1538 if (method
->is_inflated
) {
1539 MonoGenericContext
*context
= mono_method_get_context (method
);
1540 if (context
->method_inst
) {
1543 for (i
= 0; i
< context
->method_inst
->type_argc
; ++i
)
1544 if (has_type_vars (mono_class_from_mono_type (context
->method_inst
->type_argv
[i
])))
1552 * add_generic_class:
1554 * Add all methods of a generic class.
1557 add_generic_class (MonoAotCompile
*acfg
, MonoClass
*klass
)
1562 mono_class_init (klass
);
1564 if (klass
->generic_class
&& klass
->generic_class
->context
.class_inst
->is_open
)
1567 if (has_type_vars (klass
))
1570 if (!klass
->generic_class
&& !klass
->rank
)
1574 * Add rgctx wrappers for cctors since those are called by the runtime, so
1575 * there is no methodspec for them. This is needed even for shared classes,
1576 * since rgctx wrappers belong to inflated methods.
1578 method
= mono_class_get_cctor (klass
);
1579 if (method
&& mono_method_needs_static_rgctx_invoke (method
, FALSE
))
1580 add_extra_method (acfg
, mono_marshal_get_static_rgctx_invoke (method
));
1583 while ((method
= mono_class_get_methods (klass
, &iter
))) {
1584 if (mono_method_is_generic_sharable_impl (method
, FALSE
))
1588 if (method
->is_generic
)
1593 * FIXME: Instances which are referenced by these methods are not added,
1594 * for example Array.Resize<int> for List<int>.Add ().
1596 add_extra_method (acfg
, method
);
1601 * add_generic_instances:
1603 * Add instances referenced by the METHODSPEC/TYPESPEC table.
1606 add_generic_instances (MonoAotCompile
*acfg
)
1611 MonoGenericContext
*context
;
1613 for (i
= 0; i
< acfg
->image
->tables
[MONO_TABLE_METHODSPEC
].rows
; ++i
) {
1614 token
= MONO_TOKEN_METHOD_SPEC
| (i
+ 1);
1615 method
= mono_get_method (acfg
->image
, token
, NULL
);
1617 context
= mono_method_get_context (method
);
1618 if (context
&& ((context
->class_inst
&& context
->class_inst
->is_open
) ||
1619 (context
->method_inst
&& context
->method_inst
->is_open
)))
1622 if (method
->klass
->image
!= acfg
->image
)
1625 if (mono_method_is_generic_sharable_impl (method
, FALSE
))
1629 add_extra_method (acfg
, method
);
1632 for (i
= 0; i
< acfg
->image
->tables
[MONO_TABLE_TYPESPEC
].rows
; ++i
) {
1635 token
= MONO_TOKEN_TYPE_SPEC
| (i
+ 1);
1637 klass
= mono_class_get (acfg
->image
, token
);
1641 add_generic_class (acfg
, klass
);
1646 * emit_and_reloc_code:
1648 * Emit the native code in CODE, handling relocations along the way. If GOT_ONLY
1649 * is true, calls are made through the GOT too. This is used for emitting trampolines
1650 * in full-aot mode, since calls made from trampolines couldn't go through the PLT,
1651 * since trampolines are needed to make PTL work.
1654 emit_and_reloc_code (MonoAotCompile
*acfg
, MonoMethod
*method
, guint8
*code
, guint32 code_len
, MonoJumpInfo
*relocs
, gboolean got_only
)
1656 int i
, pindex
, start_index
, method_index
;
1658 MonoJumpInfo
*patch_info
;
1659 MonoMethodHeader
*header
;
1660 gboolean skip
, direct_call
;
1662 char direct_call_target
[128];
1665 header
= mono_method_get_header (method
);
1667 method_index
= get_method_index (acfg
, method
);
1670 /* Collect and sort relocations */
1671 patches
= g_ptr_array_new ();
1672 for (patch_info
= relocs
; patch_info
; patch_info
= patch_info
->next
)
1673 g_ptr_array_add (patches
, patch_info
);
1674 g_ptr_array_sort (patches
, compare_patches
);
1677 for (i
= 0; i
< code_len
; i
++) {
1679 for (pindex
= start_index
; pindex
< patches
->len
; ++pindex
) {
1680 patch_info
= g_ptr_array_index (patches
, pindex
);
1681 if (patch_info
->ip
.i
>= i
)
1685 #ifdef MONO_ARCH_AOT_SUPPORTED
1687 if (patch_info
&& (patch_info
->ip
.i
== i
) && (pindex
< patches
->len
)) {
1688 start_index
= pindex
;
1690 switch (patch_info
->type
) {
1691 case MONO_PATCH_INFO_NONE
:
1693 case MONO_PATCH_INFO_GOT_OFFSET
: {
1694 guint32 offset
= mono_arch_get_patch_offset (code
+ i
);
1695 emit_bytes (acfg
, code
+ i
, offset
);
1696 emit_symbol_diff (acfg
, "got", ".", offset
);
1698 i
+= offset
+ 4 - 1;
1703 if (!is_got_patch (patch_info
->type
))
1707 * If this patch is a call, try emitting a direct call instead of
1708 * through a PLT entry. This is possible if the called method is in
1709 * the same assembly and requires no initialization.
1711 direct_call
= FALSE
;
1712 if (!got_only
&& (patch_info
->type
== MONO_PATCH_INFO_METHOD
) && (patch_info
->data
.method
->klass
->image
== method
->klass
->image
)) {
1713 MonoCompile
*callee_cfg
= g_hash_table_lookup (acfg
->method_to_cfg
, patch_info
->data
.method
);
1715 gboolean direct_callable
= TRUE
;
1717 if (direct_callable
&& !(!callee_cfg
->has_got_slots
&& (callee_cfg
->method
->klass
->flags
& TYPE_ATTRIBUTE_BEFORE_FIELD_INIT
)))
1718 direct_callable
= FALSE
;
1719 if ((callee_cfg
->method
->iflags
& METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED
) && method
->wrapper_type
!= MONO_WRAPPER_SYNCHRONIZED
)
1720 // FIXME: Maybe call the wrapper directly ?
1721 direct_callable
= FALSE
;
1722 if (direct_callable
) {
1723 //printf ("DIRECT: %s %s\n", method ? mono_method_full_name (method, TRUE) : "", mono_method_full_name (callee_cfg->method, TRUE));
1725 sprintf (direct_call_target
, ".Lm_%x", get_method_index (acfg
, callee_cfg
->orig_method
));
1726 patch_info
->type
= MONO_PATCH_INFO_NONE
;
1727 acfg
->stats
.direct_calls
++;
1731 acfg
->stats
.all_calls
++;
1734 if (!got_only
&& !direct_call
) {
1735 int plt_offset
= get_plt_offset (acfg
, patch_info
);
1736 if (plt_offset
!= -1) {
1737 /* This patch has a PLT entry, so we must emit a call to the PLT entry */
1739 sprintf (direct_call_target
, ".Lp_%d", plt_offset
);
1741 /* Nullify the patch */
1742 patch_info
->type
= MONO_PATCH_INFO_NONE
;
1749 arch_emit_direct_call (acfg
, direct_call_target
, &call_size
);
1754 got_slot
= get_got_offset (acfg
, patch_info
);
1756 arch_emit_got_access (acfg
, code
+ i
, got_slot
, &code_size
);
1763 #endif /* MONO_ARCH_AOT_SUPPORTED */
1766 /* Find next patch */
1768 for (pindex
= start_index
; pindex
< patches
->len
; ++pindex
) {
1769 patch_info
= g_ptr_array_index (patches
, pindex
);
1770 if (patch_info
->ip
.i
>= i
)
1774 /* Try to emit multiple bytes at once */
1775 if (pindex
< patches
->len
&& patch_info
->ip
.i
> i
) {
1776 emit_bytes (acfg
, code
+ i
, patch_info
->ip
.i
- i
);
1777 i
= patch_info
->ip
.i
- 1;
1779 emit_bytes (acfg
, code
+ i
, 1);
1786 emit_method_code (MonoAotCompile
*acfg
, MonoCompile
*cfg
)
1792 int func_alignment
= 16;
1793 MonoMethodHeader
*header
;
1795 method
= cfg
->orig_method
;
1796 code
= cfg
->native_code
;
1797 header
= mono_method_get_header (method
);
1799 method_index
= get_method_index (acfg
, method
);
1801 /* Make the labels local */
1802 sprintf (symbol
, ".Lm_%x", method_index
);
1804 emit_alignment (acfg
, func_alignment
);
1805 emit_label (acfg
, symbol
);
1807 if (acfg
->aot_opts
.write_symbols
&& acfg
->use_bin_writer
) {
1809 /* Emit a local symbol into the symbol table */
1810 full_name
= mono_method_full_name (method
, TRUE
);
1811 sprintf (symbol
, ".Lme_%x", method_index
);
1812 emit_local_symbol (acfg
, full_name
, symbol
, TRUE
);
1813 emit_label (acfg
, full_name
);
1817 if (cfg
->verbose_level
> 0)
1818 g_print ("Method %s emitted as %s\n", mono_method_full_name (method
, TRUE
), symbol
);
1820 acfg
->stats
.code_size
+= cfg
->code_len
;
1822 acfg
->cfgs
[method_index
]->got_offset
= acfg
->got_offset
;
1824 emit_and_reloc_code (acfg
, method
, code
, cfg
->code_len
, cfg
->patch_info
, FALSE
);
1828 sprintf (symbol
, ".Lme_%x", method_index
);
1829 emit_label (acfg
, symbol
);
1835 * Encode PATCH_INFO into its disk representation.
1838 encode_patch (MonoAotCompile
*acfg
, MonoJumpInfo
*patch_info
, guint8
*buf
, guint8
**endbuf
)
1842 switch (patch_info
->type
) {
1843 case MONO_PATCH_INFO_NONE
:
1845 case MONO_PATCH_INFO_IMAGE
:
1846 encode_value (get_image_index (acfg
, patch_info
->data
.image
), p
, &p
);
1848 case MONO_PATCH_INFO_METHOD_REL
:
1849 encode_value ((gint
)patch_info
->data
.offset
, p
, &p
);
1851 case MONO_PATCH_INFO_SWITCH
: {
1852 gpointer
*table
= (gpointer
*)patch_info
->data
.table
->table
;
1855 encode_value (patch_info
->data
.table
->table_size
, p
, &p
);
1856 for (k
= 0; k
< patch_info
->data
.table
->table_size
; k
++)
1857 encode_value ((int)(gssize
)table
[k
], p
, &p
);
1860 case MONO_PATCH_INFO_METHODCONST
:
1861 case MONO_PATCH_INFO_METHOD
:
1862 case MONO_PATCH_INFO_METHOD_JUMP
:
1863 case MONO_PATCH_INFO_ICALL_ADDR
:
1864 case MONO_PATCH_INFO_METHOD_RGCTX
:
1865 encode_method_ref (acfg
, patch_info
->data
.method
, p
, &p
);
1867 case MONO_PATCH_INFO_INTERNAL_METHOD
:
1868 case MONO_PATCH_INFO_JIT_ICALL_ADDR
: {
1869 guint32 len
= strlen (patch_info
->data
.name
);
1871 encode_value (len
, p
, &p
);
1873 memcpy (p
, patch_info
->data
.name
, len
);
1878 case MONO_PATCH_INFO_LDSTR
: {
1879 guint32 image_index
= get_image_index (acfg
, patch_info
->data
.token
->image
);
1880 guint32 token
= patch_info
->data
.token
->token
;
1881 g_assert (mono_metadata_token_code (token
) == MONO_TOKEN_STRING
);
1882 encode_value (image_index
, p
, &p
);
1883 encode_value (patch_info
->data
.token
->token
- MONO_TOKEN_STRING
, p
, &p
);
1886 case MONO_PATCH_INFO_RVA
:
1887 case MONO_PATCH_INFO_DECLSEC
:
1888 case MONO_PATCH_INFO_LDTOKEN
:
1889 case MONO_PATCH_INFO_TYPE_FROM_HANDLE
:
1890 encode_value (get_image_index (acfg
, patch_info
->data
.token
->image
), p
, &p
);
1891 encode_value (patch_info
->data
.token
->token
, p
, &p
);
1892 encode_value (patch_info
->data
.token
->has_context
, p
, &p
);
1893 if (patch_info
->data
.token
->has_context
)
1894 encode_generic_context (acfg
, &patch_info
->data
.token
->context
, p
, &p
);
1896 case MONO_PATCH_INFO_EXC_NAME
: {
1897 MonoClass
*ex_class
;
1900 mono_class_from_name (mono_defaults
.exception_class
->image
,
1901 "System", patch_info
->data
.target
);
1902 g_assert (ex_class
);
1903 encode_klass_ref (acfg
, ex_class
, p
, &p
);
1906 case MONO_PATCH_INFO_R4
:
1907 encode_value (*((guint32
*)patch_info
->data
.target
), p
, &p
);
1909 case MONO_PATCH_INFO_R8
:
1910 encode_value (*((guint32
*)patch_info
->data
.target
), p
, &p
);
1911 encode_value (*(((guint32
*)patch_info
->data
.target
) + 1), p
, &p
);
1913 case MONO_PATCH_INFO_VTABLE
:
1914 case MONO_PATCH_INFO_CLASS
:
1915 case MONO_PATCH_INFO_IID
:
1916 case MONO_PATCH_INFO_ADJUSTED_IID
:
1917 encode_klass_ref (acfg
, patch_info
->data
.klass
, p
, &p
);
1919 case MONO_PATCH_INFO_CLASS_INIT
:
1920 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE
:
1921 encode_klass_ref (acfg
, patch_info
->data
.klass
, p
, &p
);
1923 case MONO_PATCH_INFO_FIELD
:
1924 case MONO_PATCH_INFO_SFLDA
:
1925 encode_field_info (acfg
, patch_info
->data
.field
, p
, &p
);
1927 case MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG
:
1929 case MONO_PATCH_INFO_RGCTX_FETCH
: {
1930 MonoJumpInfoRgctxEntry
*entry
= patch_info
->data
.rgctx_entry
;
1932 encode_method_ref (acfg
, entry
->method
, p
, &p
);
1933 encode_value (entry
->in_mrgctx
, p
, &p
);
1934 encode_value (entry
->info_type
, p
, &p
);
1935 encode_value (entry
->data
->type
, p
, &p
);
1936 encode_patch (acfg
, entry
->data
, p
, &p
);
1939 case MONO_PATCH_INFO_GENERIC_CLASS_INIT
:
1940 case MONO_PATCH_INFO_MONITOR_ENTER
:
1941 case MONO_PATCH_INFO_MONITOR_EXIT
:
1944 g_warning ("unable to handle jump info %d", patch_info
->type
);
1945 g_assert_not_reached ();
1952 encode_patch_list (MonoAotCompile
*acfg
, GPtrArray
*patches
, int n_patches
, int first_got_offset
, guint8
*buf
, guint8
**endbuf
)
1955 guint32 last_offset
, j
, pindex
;
1956 MonoJumpInfo
*patch_info
;
1958 encode_value (n_patches
, p
, &p
);
1961 encode_value (first_got_offset
, p
, &p
);
1963 /* First encode the type+position table */
1966 for (pindex
= 0; pindex
< patches
->len
; ++pindex
) {
1968 patch_info
= g_ptr_array_index (patches
, pindex
);
1970 if (patch_info
->type
== MONO_PATCH_INFO_NONE
)
1975 //printf ("T: %d O: %d.\n", patch_info->type, patch_info->ip.i);
1976 offset
= patch_info
->ip
.i
- last_offset
;
1977 last_offset
= patch_info
->ip
.i
;
1979 /* Only the type is needed */
1980 *p
= patch_info
->type
;
1984 /* Then encode the other info */
1985 for (pindex
= 0; pindex
< patches
->len
; ++pindex
) {
1986 patch_info
= g_ptr_array_index (patches
, pindex
);
1988 if (is_shared_got_patch (patch_info
)) {
1989 guint32 offset
= get_got_offset (acfg
, patch_info
);
1990 encode_value (offset
, p
, &p
);
1992 encode_patch (acfg
, patch_info
, p
, &p
);
2000 emit_method_info (MonoAotCompile
*acfg
, MonoCompile
*cfg
)
2004 int pindex
, buf_size
, n_patches
;
2008 MonoJumpInfo
*patch_info
;
2009 MonoMethodHeader
*header
;
2010 guint32 method_index
;
2012 guint32 first_got_offset
;
2014 method
= cfg
->orig_method
;
2015 code
= cfg
->native_code
;
2016 header
= mono_method_get_header (method
);
2018 method_index
= get_method_index (acfg
, method
);
2020 /* Make the labels local */
2021 sprintf (symbol
, ".Lm_%x_p", method_index
);
2023 /* Sort relocations */
2024 patches
= g_ptr_array_new ();
2025 for (patch_info
= cfg
->patch_info
; patch_info
; patch_info
= patch_info
->next
)
2026 g_ptr_array_add (patches
, patch_info
);
2027 g_ptr_array_sort (patches
, compare_patches
);
2029 first_got_offset
= acfg
->cfgs
[method_index
]->got_offset
;
2031 /**********************/
2032 /* Encode method info */
2033 /**********************/
2035 buf_size
= (patches
->len
< 1000) ? 40960 : 40960 + (patches
->len
* 64);
2036 p
= buf
= g_malloc (buf_size
);
2038 if (mono_class_get_cctor (method
->klass
))
2039 encode_klass_ref (acfg
, method
->klass
, p
, &p
);
2041 /* Not needed when loading the method */
2042 encode_value (0, p
, &p
);
2045 if (cfg
->opt
& MONO_OPT_SHARED
) {
2046 encode_value (g_list_length (cfg
->ldstr_list
), p
, &p
);
2047 for (l
= cfg
->ldstr_list
; l
; l
= l
->next
) {
2048 encode_value ((long)l
->data
, p
, &p
);
2052 /* Used only in shared mode */
2053 g_assert (!cfg
->ldstr_list
);
2056 for (pindex
= 0; pindex
< patches
->len
; ++pindex
) {
2057 patch_info
= g_ptr_array_index (patches
, pindex
);
2059 if ((patch_info
->type
== MONO_PATCH_INFO_GOT_OFFSET
) ||
2060 (patch_info
->type
== MONO_PATCH_INFO_NONE
)) {
2061 patch_info
->type
= MONO_PATCH_INFO_NONE
;
2066 if ((patch_info
->type
== MONO_PATCH_INFO_IMAGE
) && (patch_info
->data
.image
== acfg
->image
)) {
2067 /* Stored in a GOT slot initialized at module load time */
2068 patch_info
->type
= MONO_PATCH_INFO_NONE
;
2072 if (is_plt_patch (patch_info
)) {
2073 /* Calls are made through the PLT */
2074 patch_info
->type
= MONO_PATCH_INFO_NONE
;
2082 g_assert (cfg
->has_got_slots
);
2084 encode_patch_list (acfg
, patches
, n_patches
, first_got_offset
, p
, &p
);
2086 acfg
->stats
.info_size
+= p
- buf
;
2088 /* Emit method info */
2090 emit_label (acfg
, symbol
);
2092 g_assert (p
- buf
< buf_size
);
2093 emit_bytes (acfg
, buf
, p
- buf
);
2098 emit_exception_debug_info (MonoAotCompile
*acfg
, MonoCompile
*cfg
)
2101 int k
, buf_size
, method_index
;
2102 guint32 debug_info_size
;
2105 MonoMethodHeader
*header
;
2106 guint8
*p
, *buf
, *debug_info
;
2107 MonoJitInfo
*jinfo
= cfg
->jit_info
;
2109 gboolean use_unwind_ops
= FALSE
;
2111 method
= cfg
->orig_method
;
2112 code
= cfg
->native_code
;
2113 header
= mono_method_get_header (method
);
2115 method_index
= get_method_index (acfg
, method
);
2117 /* Make the labels local */
2118 sprintf (symbol
, ".Le_%x_p", method_index
);
2120 mono_debug_serialize_debug_info (cfg
, &debug_info
, &debug_info_size
);
2122 buf_size
= header
->num_clauses
* 256 + debug_info_size
+ 1024;
2123 p
= buf
= g_malloc (buf_size
);
2125 #ifdef MONO_ARCH_HAVE_XP_UNWIND
2126 use_unwind_ops
= cfg
->unwind_ops
!= NULL
;
2129 flags
= (jinfo
->has_generic_jit_info
? 1 : 0) | (use_unwind_ops
? 2 : 0);
2131 encode_value (jinfo
->code_size
, p
, &p
);
2132 encode_value (flags
, p
, &p
);
2134 if (use_unwind_ops
) {
2135 guint32 encoded_len
;
2139 * This is a duplicate of the data in the .debug_frame section, but that
2140 * section cannot be accessed using the dl interface.
2142 encoded
= mono_unwind_ops_encode (cfg
->unwind_ops
, &encoded_len
);
2143 encode_value (encoded_len
, p
, &p
);
2144 memcpy (p
, encoded
, encoded_len
);
2148 encode_value (jinfo
->used_regs
, p
, &p
);
2151 /* Exception table */
2152 if (header
->num_clauses
) {
2153 for (k
= 0; k
< header
->num_clauses
; ++k
) {
2154 MonoJitExceptionInfo
*ei
= &jinfo
->clauses
[k
];
2156 encode_value (ei
->exvar_offset
, p
, &p
);
2158 if (ei
->flags
== MONO_EXCEPTION_CLAUSE_FILTER
)
2159 encode_value ((gint
)((guint8
*)ei
->data
.filter
- code
), p
, &p
);
2161 encode_value ((gint
)((guint8
*)ei
->try_start
- code
), p
, &p
);
2162 encode_value ((gint
)((guint8
*)ei
->try_end
- code
), p
, &p
);
2163 encode_value ((gint
)((guint8
*)ei
->handler_start
- code
), p
, &p
);
2167 if (jinfo
->has_generic_jit_info
) {
2168 MonoGenericJitInfo
*gi
= mono_jit_info_get_generic_jit_info (jinfo
);
2170 encode_value (gi
->has_this
? 1 : 0, p
, &p
);
2171 encode_value (gi
->this_reg
, p
, &p
);
2172 encode_value (gi
->this_offset
, p
, &p
);
2175 * Need to encode jinfo->method too, since it is not equal to 'method'
2176 * when using generic sharing.
2178 encode_method_ref (acfg
, jinfo
->method
, p
, &p
);
2181 g_assert (debug_info_size
< buf_size
);
2183 encode_value (debug_info_size
, p
, &p
);
2184 if (debug_info_size
) {
2185 memcpy (p
, debug_info
, debug_info_size
);
2186 p
+= debug_info_size
;
2187 g_free (debug_info
);
2190 acfg
->stats
.ex_info_size
+= p
- buf
;
2194 emit_label (acfg
, symbol
);
2196 g_assert (p
- buf
< buf_size
);
2197 emit_bytes (acfg
, buf
, p
- buf
);
2202 emit_klass_info (MonoAotCompile
*acfg
, guint32 token
)
2204 MonoClass
*klass
= mono_class_get (acfg
->image
, token
);
2208 gboolean no_special_static
, cant_encode
;
2209 gpointer iter
= NULL
;
2211 buf_size
= 10240 + (klass
->vtable_size
* 16);
2212 p
= buf
= g_malloc (buf_size
);
2216 mono_class_init (klass
);
2218 mono_class_get_nested_types (klass
, &iter
);
2219 g_assert (klass
->nested_classes_inited
);
2221 mono_class_setup_vtable (klass
);
2224 * Emit all the information which is required for creating vtables so
2225 * the runtime does not need to create the MonoMethod structures which
2226 * take up a lot of space.
2229 no_special_static
= !mono_class_has_special_static_fields (klass
);
2231 /* Check whenever we have enough info to encode the vtable */
2232 cant_encode
= FALSE
;
2233 for (i
= 0; i
< klass
->vtable_size
; ++i
) {
2234 MonoMethod
*cm
= klass
->vtable
[i
];
2236 if (cm
&& mono_method_signature (cm
)->is_inflated
&& !g_hash_table_lookup (acfg
->token_info_hash
, cm
))
2240 if (klass
->generic_container
|| cant_encode
) {
2241 encode_value (-1, p
, &p
);
2243 encode_value (klass
->vtable_size
, p
, &p
);
2244 encode_value ((no_special_static
<< 7) | (klass
->has_static_refs
<< 6) | (klass
->has_references
<< 5) | ((klass
->blittable
<< 4) | ((klass
->ext
&& klass
->ext
->nested_classes
) ? 1 : 0) << 3) | (klass
->has_cctor
<< 2) | (klass
->has_finalize
<< 1) | klass
->ghcimpl
, p
, &p
);
2245 if (klass
->has_cctor
)
2246 encode_method_ref (acfg
, mono_class_get_cctor (klass
), p
, &p
);
2247 if (klass
->has_finalize
)
2248 encode_method_ref (acfg
, mono_class_get_finalizer (klass
), p
, &p
);
2250 encode_value (klass
->instance_size
, p
, &p
);
2251 encode_value (mono_class_data_size (klass
), p
, &p
);
2252 encode_value (klass
->packing_size
, p
, &p
);
2253 encode_value (klass
->min_align
, p
, &p
);
2255 for (i
= 0; i
< klass
->vtable_size
; ++i
) {
2256 MonoMethod
*cm
= klass
->vtable
[i
];
2259 encode_method_ref (acfg
, cm
, p
, &p
);
2261 encode_value (0, p
, &p
);
2265 acfg
->stats
.class_info_size
+= p
- buf
;
2268 sprintf (symbol
, ".LK_I_%x", token
- MONO_TOKEN_TYPE_DEF
- 1);
2269 emit_label (acfg
, symbol
);
2271 g_assert (p
- buf
< buf_size
);
2272 emit_bytes (acfg
, buf
, p
- buf
);
2277 * Calls made from AOTed code are routed through a table of jumps similar to the
2278 * ELF PLT (Program Linkage Table). The differences are the following:
2279 * - the ELF PLT entries make an indirect jump though the GOT so they expect the
2280 * GOT pointer to be in EBX. We want to avoid this, so our table contains direct
2281 * jumps. This means the jumps need to be patched when the address of the callee is
2282 * known. Initially the PLT entries jump to code which transfers control to the
2283 * AOT runtime through the first PLT entry.
2286 emit_plt (MonoAotCompile
*acfg
)
2292 sprintf (symbol
, "plt");
2294 emit_section_change (acfg
, ".text", 0);
2295 emit_global (acfg
, symbol
, TRUE
);
2297 /* This section will be made read-write by the AOT loader */
2298 emit_alignment (acfg
, PAGESIZE
);
2300 emit_alignment (acfg
, 16);
2302 emit_label (acfg
, symbol
);
2304 for (i
= 0; i
< acfg
->plt_offset
; ++i
) {
2307 sprintf (label
, ".Lp_%d", i
);
2308 emit_label (acfg
, label
);
2311 * The first plt entry is used to transfer code to the AOT loader.
2313 arch_emit_plt_entry (acfg
, i
);
2316 sprintf (symbol
, "plt_end");
2317 emit_global (acfg
, symbol
, TRUE
);
2318 emit_label (acfg
, symbol
);
2321 static G_GNUC_UNUSED
void
2322 emit_named_code (MonoAotCompile
*acfg
, const char *name
, guint8
*code
,
2323 guint32 code_size
, int got_offset
, MonoJumpInfo
*ji
, GSList
*unwind_ops
)
2327 MonoJumpInfo
*patch_info
;
2333 sprintf (symbol
, "%s", name
);
2335 emit_section_change (acfg
, ".text", 0);
2336 emit_global (acfg
, symbol
, TRUE
);
2337 emit_alignment (acfg
, 16);
2338 emit_label (acfg
, symbol
);
2340 sprintf (symbol
, ".Lnamed_%s", name
);
2341 emit_label (acfg
, symbol
);
2344 * The code should access everything through the GOT, so we pass
2347 emit_and_reloc_code (acfg
, NULL
, code
, code_size
, ji
, TRUE
);
2351 /* Sort relocations */
2352 patches
= g_ptr_array_new ();
2353 for (patch_info
= ji
; patch_info
; patch_info
= patch_info
->next
)
2354 g_ptr_array_add (patches
, patch_info
);
2355 g_ptr_array_sort (patches
, compare_patches
);
2357 buf_size
= patches
->len
* 128 + 128;
2358 buf
= g_malloc (buf_size
);
2361 encode_patch_list (acfg
, patches
, patches
->len
, got_offset
, p
, &p
);
2362 g_assert (p
- buf
< buf_size
);
2364 sprintf (symbol
, "%s_p", name
);
2366 emit_section_change (acfg
, ".text", 0);
2367 emit_global (acfg
, symbol
, FALSE
);
2368 emit_label (acfg
, symbol
);
2370 emit_bytes (acfg
, buf
, p
- buf
);
2372 /* Emit debug info */
2376 sprintf (symbol
, "%s", name
);
2377 sprintf (symbol2
, ".Lnamed_%s", name
);
2379 mono_dwarf_writer_emit_trampoline (acfg
->dwarf
, symbol
, symbol2
, NULL
, NULL
, code_size
, unwind_ops
);
2384 * When running in aot-only mode, we can't create trampolines at runtime, so we create
2385 * a few, and save them in the AOT file. Normal trampolines embed their argument as a
2386 * literal inside the trampoline code, we can't do that here, so instead we embed an offset
2387 * which needs to be added to the trampoline address to get the address of the GOT slot
2388 * which contains the argument value.
2389 * The generated trampolines jump to the generic trampolines using another GOT slot, which
2390 * will be setup by the AOT loader to point to the generic trampoline code of the given
2394 emit_trampolines (MonoAotCompile
*acfg
)
2398 #ifdef MONO_ARCH_HAVE_FULL_AOT_TRAMPOLINES
2406 if (!acfg
->aot_opts
.full_aot
)
2409 g_assert (acfg
->image
->assembly
);
2411 /* Currently, we only emit most trampolines into the mscorlib AOT image. */
2412 if (strcmp (acfg
->image
->assembly
->aname
.name
, "mscorlib") == 0) {
2413 #ifdef MONO_ARCH_HAVE_FULL_AOT_TRAMPOLINES
2415 * Emit the generic trampolines.
2417 * We could save some code by treating the generic trampolines as a wrapper
2418 * method, but that approach has its own complexities, so we choose the simpler
2421 for (tramp_type
= 0; tramp_type
< MONO_TRAMPOLINE_NUM
; ++tramp_type
) {
2422 code
= mono_arch_create_trampoline_code_full (tramp_type
, &code_size
, &ji
, &unwind_ops
, TRUE
);
2424 /* Emit trampoline code */
2426 sprintf (symbol
, "generic_trampoline_%d", tramp_type
);
2428 emit_named_code (acfg
, symbol
, code
, code_size
, acfg
->got_offset
, ji
, unwind_ops
);
2431 code
= mono_arch_get_nullified_class_init_trampoline (&code_size
);
2432 emit_named_code (acfg
, "nullified_class_init_trampoline", code
, code_size
, acfg
->got_offset
, NULL
, NULL
);
2433 #if defined(__x86_64__) && defined(MONO_ARCH_MONITOR_OBJECT_REG)
2434 code
= mono_arch_create_monitor_enter_trampoline_full (&code_size
, &ji
, TRUE
);
2435 emit_named_code (acfg
, "monitor_enter_trampoline", code
, code_size
, acfg
->got_offset
, ji
, NULL
);
2436 code
= mono_arch_create_monitor_exit_trampoline_full (&code_size
, &ji
, TRUE
);
2437 emit_named_code (acfg
, "monitor_exit_trampoline", code
, code_size
, acfg
->got_offset
, ji
, NULL
);
2440 code
= mono_arch_create_generic_class_init_trampoline_full (&code_size
, &ji
, TRUE
);
2441 emit_named_code (acfg
, "generic_class_init_trampoline", code
, code_size
, acfg
->got_offset
, ji
, NULL
);
2443 /* Emit the exception related code pieces */
2444 code
= mono_arch_get_restore_context_full (&code_size
, &ji
, TRUE
);
2445 emit_named_code (acfg
, "restore_context", code
, code_size
, acfg
->got_offset
, ji
, NULL
);
2446 code
= mono_arch_get_call_filter_full (&code_size
, &ji
, TRUE
);
2447 emit_named_code (acfg
, "call_filter", code
, code_size
, acfg
->got_offset
, ji
, NULL
);
2448 code
= mono_arch_get_throw_exception_full (&code_size
, &ji
, TRUE
);
2449 emit_named_code (acfg
, "throw_exception", code
, code_size
, acfg
->got_offset
, ji
, NULL
);
2450 code
= mono_arch_get_rethrow_exception_full (&code_size
, &ji
, TRUE
);
2451 emit_named_code (acfg
, "rethrow_exception", code
, code_size
, acfg
->got_offset
, ji
, NULL
);
2452 code
= mono_arch_get_throw_exception_by_name_full (&code_size
, &ji
, TRUE
);
2453 emit_named_code (acfg
, "throw_exception_by_name", code
, code_size
, acfg
->got_offset
, ji
, NULL
);
2454 code
= mono_arch_get_throw_corlib_exception_full (&code_size
, &ji
, TRUE
);
2455 emit_named_code (acfg
, "throw_corlib_exception", code
, code_size
, acfg
->got_offset
, ji
, NULL
);
2457 #if defined(__x86_64__)
2458 code
= mono_arch_get_throw_pending_exception_full (&code_size
, &ji
, TRUE
);
2459 emit_named_code (acfg
, "throw_pending_exception", code
, code_size
, acfg
->got_offset
, ji
, NULL
);
2462 #if defined(__x86_64__) || defined(__arm__)
2463 for (i
= 0; i
< 128; ++i
) {
2466 offset
= MONO_RGCTX_SLOT_MAKE_RGCTX (i
);
2467 code
= mono_arch_create_rgctx_lazy_fetch_trampoline_full (offset
, &code_size
, &ji
, TRUE
);
2468 sprintf (symbol
, "rgctx_fetch_trampoline_%u", offset
);
2469 emit_named_code (acfg
, symbol
, code
, code_size
, acfg
->got_offset
, ji
, NULL
);
2471 offset
= MONO_RGCTX_SLOT_MAKE_MRGCTX (i
);
2472 code
= mono_arch_create_rgctx_lazy_fetch_trampoline_full (offset
, &code_size
, &ji
, TRUE
);
2473 sprintf (symbol
, "rgctx_fetch_trampoline_%u", offset
);
2474 emit_named_code (acfg
, symbol
, code
, code_size
, acfg
->got_offset
, ji
, NULL
);
2480 * FIXME: Maybe we should use more specific trampolines (i.e. one class init for
2484 /* Reserve some entries at the end of the GOT for our use */
2485 acfg
->num_trampoline_got_entries
= acfg
->num_aot_trampolines
* 2;
2487 sprintf (symbol
, "trampolines");
2489 emit_section_change (acfg
, ".text", 0);
2490 emit_global (acfg
, symbol
, TRUE
);
2491 emit_alignment (acfg
, 16);
2492 emit_label (acfg
, symbol
);
2494 for (i
= 0; i
< acfg
->num_aot_trampolines
; ++i
) {
2497 offset
= acfg
->got_offset
+ (i
* 2);
2499 arch_emit_specific_trampoline (acfg
, offset
, &tramp_size
);
2500 if (!acfg
->specific_trampoline_size
) {
2501 g_assert (tramp_size
);
2502 acfg
->specific_trampoline_size
= tramp_size
;
2507 /* Unbox trampolines */
2509 for (i
= 0; i
< acfg
->image
->tables
[MONO_TABLE_METHOD
].rows
; ++i
) {
2511 guint32 token
= MONO_TOKEN_METHOD_DEF
| (i
+ 1);
2513 char call_target
[256];
2515 method
= mono_get_method (acfg
->image
, token
, NULL
);
2517 cfg
= g_hash_table_lookup (acfg
->method_to_cfg
, method
);
2518 if (!cfg
|| !cfg
->orig_method
->klass
->valuetype
|| !(method
->flags
& METHOD_ATTRIBUTE_VIRTUAL
))
2521 sprintf (symbol
, "unbox_trampoline_%d", i
);
2523 emit_section_change (acfg
, ".text", 0);
2524 emit_global (acfg
, symbol
, TRUE
);
2525 emit_label (acfg
, symbol
);
2527 sprintf (call_target
, ".Lm_%x", get_method_index (acfg
, cfg
->orig_method
));
2529 arch_emit_unbox_trampoline (acfg
, cfg
->orig_method
, cfg
->generic_sharing_context
, call_target
);
2532 acfg
->trampoline_got_offset_base
= acfg
->got_offset
;
2534 acfg
->got_offset
+= acfg
->num_trampoline_got_entries
;
2538 str_begins_with (const char *str1
, const char *str2
)
2540 int len
= strlen (str2
);
2541 return strncmp (str1
, str2
, len
) == 0;
2545 mono_aot_parse_options (const char *aot_options
, MonoAotOptions
*opts
)
2547 gchar
**args
, **ptr
;
2549 args
= g_strsplit (aot_options
? aot_options
: "", ",", -1);
2550 for (ptr
= args
; ptr
&& *ptr
; ptr
++) {
2551 const char *arg
= *ptr
;
2553 if (str_begins_with (arg
, "outfile=")) {
2554 opts
->outfile
= g_strdup (arg
+ strlen ("outfile="));
2555 } else if (str_begins_with (arg
, "save-temps")) {
2556 opts
->save_temps
= TRUE
;
2557 } else if (str_begins_with (arg
, "keep-temps")) {
2558 opts
->save_temps
= TRUE
;
2559 } else if (str_begins_with (arg
, "write-symbols")) {
2560 opts
->write_symbols
= TRUE
;
2561 } else if (str_begins_with (arg
, "metadata-only")) {
2562 opts
->metadata_only
= TRUE
;
2563 } else if (str_begins_with (arg
, "bind-to-runtime-version")) {
2564 opts
->bind_to_runtime_version
= TRUE
;
2565 } else if (str_begins_with (arg
, "full")) {
2566 opts
->full_aot
= TRUE
;
2568 * The no-dlsym option is only useful on the iphone, and even there,
2569 * do to other limitations of the dynamic linker, it doesn't seem to
2570 * work. So disable it for now so we don't have to support it.
2573 } else if (str_begins_with (arg, "no-dlsym")) {
2574 opts->no_dlsym = TRUE;
2576 } else if (str_begins_with (arg
, "threads=")) {
2577 opts
->nthreads
= atoi (arg
+ strlen ("threads="));
2578 } else if (str_begins_with (arg
, "static")) {
2579 opts
->static_link
= TRUE
;
2580 opts
->no_dlsym
= TRUE
;
2581 } else if (str_begins_with (arg
, "asmonly")) {
2582 opts
->asm_only
= TRUE
;
2583 } else if (str_begins_with (arg
, "asmwriter")) {
2584 opts
->asm_writer
= TRUE
;
2586 fprintf (stderr
, "AOT : Unknown argument '%s'.\n", arg
);
2595 add_token_info_hash (gpointer key
, gpointer value
, gpointer user_data
)
2597 MonoMethod
*method
= (MonoMethod
*)key
;
2598 MonoJumpInfoToken
*ji
= (MonoJumpInfoToken
*)value
;
2599 MonoJumpInfoToken
*new_ji
= g_new0 (MonoJumpInfoToken
, 1);
2600 MonoAotCompile
*acfg
= user_data
;
2602 new_ji
->image
= ji
->image
;
2603 new_ji
->token
= ji
->token
;
2604 g_hash_table_insert (acfg
->token_info_hash
, method
, new_ji
);
2608 can_encode_class (MonoAotCompile
*acfg
, MonoClass
*klass
)
2610 if (klass
->type_token
)
2612 if ((klass
->byval_arg
.type
== MONO_TYPE_VAR
) || (klass
->byval_arg
.type
== MONO_TYPE_MVAR
))
2615 return can_encode_class (acfg
, klass
->element_class
);
2620 can_encode_patch (MonoAotCompile
*acfg
, MonoJumpInfo
*patch_info
)
2622 switch (patch_info
->type
) {
2623 case MONO_PATCH_INFO_METHOD
:
2624 case MONO_PATCH_INFO_METHODCONST
: {
2625 MonoMethod
*method
= patch_info
->data
.method
;
2627 if (method
->wrapper_type
) {
2628 switch (method
->wrapper_type
) {
2629 case MONO_WRAPPER_NONE
:
2630 case MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK
:
2631 case MONO_WRAPPER_XDOMAIN_INVOKE
:
2632 case MONO_WRAPPER_STFLD
:
2633 case MONO_WRAPPER_LDFLD
:
2634 case MONO_WRAPPER_LDFLDA
:
2635 case MONO_WRAPPER_LDFLD_REMOTE
:
2636 case MONO_WRAPPER_STFLD_REMOTE
:
2637 case MONO_WRAPPER_STELEMREF
:
2638 case MONO_WRAPPER_ISINST
:
2639 case MONO_WRAPPER_PROXY_ISINST
:
2640 case MONO_WRAPPER_ALLOC
:
2641 case MONO_WRAPPER_REMOTING_INVOKE
:
2642 case MONO_WRAPPER_STATIC_RGCTX_INVOKE
:
2643 case MONO_WRAPPER_UNKNOWN
:
2646 //printf ("Skip (wrapper call): %d -> %s\n", patch_info->type, mono_method_full_name (patch_info->data.method, TRUE));
2650 if (!method
->token
) {
2651 /* The method is part of a constructed type like Int[,].Set (). */
2652 if (!g_hash_table_lookup (acfg
->token_info_hash
, method
)) {
2653 if (method
->klass
->rank
)
2661 case MONO_PATCH_INFO_VTABLE
:
2662 case MONO_PATCH_INFO_CLASS_INIT
:
2663 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE
:
2664 case MONO_PATCH_INFO_CLASS
:
2665 case MONO_PATCH_INFO_IID
:
2666 case MONO_PATCH_INFO_ADJUSTED_IID
:
2667 if (!can_encode_class (acfg
, patch_info
->data
.klass
)) {
2668 //printf ("Skip: %s\n", mono_type_full_name (&patch_info->data.klass->byval_arg));
2672 case MONO_PATCH_INFO_RGCTX_FETCH
: {
2673 MonoJumpInfoRgctxEntry
*entry
= patch_info
->data
.rgctx_entry
;
2675 if (!can_encode_patch (acfg
, entry
->data
))
2687 add_generic_class (MonoAotCompile
*acfg
, MonoClass
*klass
);
2692 * AOT compile a given method.
2693 * This function might be called by multiple threads, so it must be thread-safe.
2696 compile_method (MonoAotCompile
*acfg
, MonoMethod
*method
)
2699 MonoJumpInfo
*patch_info
;
2702 MonoMethod
*wrapped
;
2704 if (acfg
->aot_opts
.metadata_only
)
2707 mono_acfg_lock (acfg
);
2708 index
= get_method_index (acfg
, method
);
2709 mono_acfg_unlock (acfg
);
2711 /* fixme: maybe we can also precompile wrapper methods */
2712 if ((method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
) ||
2713 (method
->iflags
& METHOD_IMPL_ATTRIBUTE_RUNTIME
) ||
2714 (method
->flags
& METHOD_ATTRIBUTE_ABSTRACT
)) {
2715 //printf ("Skip (impossible): %s\n", mono_method_full_name (method, TRUE));
2719 if (method
->iflags
& METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
)
2722 wrapped
= mono_marshal_method_from_wrapper (method
);
2723 if (wrapped
&& (wrapped
->iflags
& METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
) && wrapped
->is_generic
)
2724 // FIXME: The wrapper should be generic too, but it is not
2727 InterlockedIncrement (&acfg
->stats
.mcount
);
2730 if (method
->is_generic
|| method
->klass
->generic_container
) {
2731 InterlockedIncrement (&acfg
->stats
.genericcount
);
2736 //acfg->aot_opts.print_skipped_methods = TRUE;
2738 if (acfg
->aot_opts
.full_aot
)
2739 mono_use_imt
= FALSE
;
2742 * Since these methods are the only ones which are compiled with
2743 * AOT support, and they are not used by runtime startup/shutdown code,
2744 * the runtime will not see AOT methods during AOT compilation,so it
2745 * does not need to support them by creating a fake GOT etc.
2747 cfg
= mini_method_compile (method
, acfg
->opts
, mono_get_root_domain (), FALSE
, TRUE
, 0);
2748 if (cfg
->exception_type
== MONO_EXCEPTION_GENERIC_SHARING_FAILED
) {
2749 //printf ("F: %s\n", mono_method_full_name (method, TRUE));
2750 InterlockedIncrement (&acfg
->stats
.genericcount
);
2753 if (cfg
->exception_type
!= MONO_EXCEPTION_NONE
) {
2754 /* Let the exception happen at runtime */
2758 if (cfg
->disable_aot
) {
2759 if (acfg
->aot_opts
.print_skipped_methods
)
2760 printf ("Skip (disabled): %s\n", mono_method_full_name (method
, TRUE
));
2761 InterlockedIncrement (&acfg
->stats
.ocount
);
2762 mono_destroy_compile (cfg
);
2766 /* Nullify patches which need no aot processing */
2767 for (patch_info
= cfg
->patch_info
; patch_info
; patch_info
= patch_info
->next
) {
2768 switch (patch_info
->type
) {
2769 case MONO_PATCH_INFO_LABEL
:
2770 case MONO_PATCH_INFO_BB
:
2771 patch_info
->type
= MONO_PATCH_INFO_NONE
;
2778 /* Collect method->token associations from the cfg */
2779 mono_acfg_lock (acfg
);
2780 g_hash_table_foreach (cfg
->token_info_hash
, add_token_info_hash
, acfg
);
2781 mono_acfg_unlock (acfg
);
2784 * Check for absolute addresses.
2787 for (patch_info
= cfg
->patch_info
; patch_info
; patch_info
= patch_info
->next
) {
2788 switch (patch_info
->type
) {
2789 case MONO_PATCH_INFO_ABS
:
2790 /* unable to handle this */
2799 if (acfg
->aot_opts
.print_skipped_methods
)
2800 printf ("Skip (abs call): %s\n", mono_method_full_name (method
, TRUE
));
2801 InterlockedIncrement (&acfg
->stats
.abscount
);
2802 mono_destroy_compile (cfg
);
2806 /* Lock for the rest of the code */
2807 mono_acfg_lock (acfg
);
2810 * Check for methods/klasses we can't encode.
2813 for (patch_info
= cfg
->patch_info
; patch_info
; patch_info
= patch_info
->next
) {
2814 if (!can_encode_patch (acfg
, patch_info
))
2819 if (acfg
->aot_opts
.print_skipped_methods
)
2820 printf ("Skip (patches): %s\n", mono_method_full_name (method
, TRUE
));
2821 acfg
->stats
.ocount
++;
2822 mono_destroy_compile (cfg
);
2823 mono_acfg_unlock (acfg
);
2827 /* Adds generic instances referenced by this method */
2828 for (patch_info
= cfg
->patch_info
; patch_info
; patch_info
= patch_info
->next
) {
2829 switch (patch_info
->type
) {
2830 case MONO_PATCH_INFO_METHOD
: {
2831 MonoMethod
*m
= patch_info
->data
.method
;
2832 if (m
->is_inflated
) {
2833 if (!(mono_class_generic_sharing_enabled (m
->klass
) &&
2834 mono_method_is_generic_sharable_impl (m
, FALSE
)) &&
2835 !method_has_type_vars (m
)) {
2836 if (m
->iflags
& METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
) {
2837 if (acfg
->aot_opts
.full_aot
)
2838 add_extra_method (acfg
, mono_marshal_get_native_wrapper (m
, TRUE
, TRUE
));
2840 add_extra_method (acfg
, m
);
2843 add_generic_class (acfg
, m
->klass
);
2852 /* Determine whenever the method has GOT slots */
2853 for (patch_info
= cfg
->patch_info
; patch_info
; patch_info
= patch_info
->next
) {
2854 switch (patch_info
->type
) {
2855 case MONO_PATCH_INFO_GOT_OFFSET
:
2856 case MONO_PATCH_INFO_NONE
:
2858 case MONO_PATCH_INFO_IMAGE
:
2859 /* The assembly is stored in GOT slot 0 */
2860 if (patch_info
->data
.image
!= acfg
->image
)
2861 cfg
->has_got_slots
= TRUE
;
2864 if (!is_plt_patch (patch_info
))
2865 cfg
->has_got_slots
= TRUE
;
2870 if (!cfg
->has_got_slots
)
2871 InterlockedIncrement (&acfg
->stats
.methods_without_got_slots
);
2873 /* Make a copy of the patch info which is in the mempool */
2875 MonoJumpInfo
*patches
= NULL
, *patches_end
= NULL
;
2877 for (patch_info
= cfg
->patch_info
; patch_info
; patch_info
= patch_info
->next
) {
2878 MonoJumpInfo
*new_patch_info
= mono_patch_info_dup_mp (acfg
->mempool
, patch_info
);
2881 patches
= new_patch_info
;
2883 patches_end
->next
= new_patch_info
;
2884 patches_end
= new_patch_info
;
2886 cfg
->patch_info
= patches
;
2888 /* Make a copy of the unwind info */
2890 GSList
*l
, *unwind_ops
;
2894 for (l
= cfg
->unwind_ops
; l
; l
= l
->next
) {
2895 op
= mono_mempool_alloc (acfg
->mempool
, sizeof (MonoUnwindOp
));
2896 memcpy (op
, l
->data
, sizeof (MonoUnwindOp
));
2897 unwind_ops
= g_slist_prepend_mempool (acfg
->mempool
, unwind_ops
, op
);
2899 cfg
->unwind_ops
= g_slist_reverse (unwind_ops
);
2901 /* Make a copy of the argument/local info */
2903 MonoInst
**args
, **locals
;
2904 MonoMethodSignature
*sig
;
2905 MonoMethodHeader
*header
;
2908 sig
= mono_method_signature (method
);
2909 args
= mono_mempool_alloc (acfg
->mempool
, sizeof (MonoInst
*) * (sig
->param_count
+ sig
->hasthis
));
2910 for (i
= 0; i
< sig
->param_count
+ sig
->hasthis
; ++i
) {
2911 args
[i
] = mono_mempool_alloc (acfg
->mempool
, sizeof (MonoInst
));
2912 memcpy (args
[i
], cfg
->args
[i
], sizeof (MonoInst
));
2916 header
= mono_method_get_header (method
);
2917 locals
= mono_mempool_alloc (acfg
->mempool
, sizeof (MonoInst
*) * header
->num_locals
);
2918 for (i
= 0; i
< header
->num_locals
; ++i
) {
2919 locals
[i
] = mono_mempool_alloc (acfg
->mempool
, sizeof (MonoInst
));
2920 memcpy (locals
[i
], cfg
->locals
[i
], sizeof (MonoInst
));
2922 cfg
->locals
= locals
;
2925 /* Free some fields used by cfg to conserve memory */
2926 mono_mempool_destroy (cfg
->mempool
);
2927 cfg
->mempool
= NULL
;
2928 g_free (cfg
->varinfo
);
2929 cfg
->varinfo
= NULL
;
2933 mono_regstate_free (cfg
->rs
);
2937 //printf ("Compile: %s\n", mono_method_full_name (method, TRUE));
2939 while (index
>= acfg
->cfgs_size
) {
2940 MonoCompile
**new_cfgs
;
2943 new_size
= acfg
->cfgs_size
* 2;
2944 new_cfgs
= g_new0 (MonoCompile
*, new_size
);
2945 memcpy (new_cfgs
, acfg
->cfgs
, sizeof (MonoCompile
*) * acfg
->cfgs_size
);
2946 g_free (acfg
->cfgs
);
2947 acfg
->cfgs
= new_cfgs
;
2948 acfg
->cfgs_size
= new_size
;
2950 acfg
->cfgs
[index
] = cfg
;
2952 g_hash_table_insert (acfg
->method_to_cfg
, cfg
->orig_method
, cfg
);
2954 if (cfg
->orig_method
->wrapper_type
)
2955 g_ptr_array_add (acfg
->extra_methods
, cfg
->orig_method
);
2957 mono_acfg_unlock (acfg
);
2959 InterlockedIncrement (&acfg
->stats
.ccount
);
2963 compile_thread_main (gpointer
*user_data
)
2965 MonoDomain
*domain
= user_data
[0];
2966 MonoAotCompile
*acfg
= user_data
[1];
2967 GPtrArray
*methods
= user_data
[2];
2970 mono_thread_attach (domain
);
2972 for (i
= 0; i
< methods
->len
; ++i
)
2973 compile_method (acfg
, g_ptr_array_index (methods
, i
));
2977 load_profile_files (MonoAotCompile
*acfg
)
2981 int file_index
, res
, method_index
, i
;
2988 tmp
= g_strdup_printf ("%s/.mono/aot-profile-data/%s-%s-%d", g_get_home_dir (), acfg
->image
->assembly_name
, acfg
->image
->guid
, file_index
);
2990 if (!g_file_test (tmp
, G_FILE_TEST_IS_REGULAR
)) {
2995 infile
= fopen (tmp
, "r");
2998 printf ("Using profile data file '%s'\n", tmp
);
3003 res
= fscanf (infile
, "%32s\n", ver
);
3004 if ((res
!= 1) || strcmp (ver
, "#VER:1") != 0) {
3005 printf ("Profile file has wrong version or invalid.\n");
3011 res
= fscanf (infile
, "%d\n", &token
);
3015 method_index
= mono_metadata_token_index (token
) - 1;
3017 if (!g_list_find (acfg
->method_order
, GUINT_TO_POINTER (method_index
)))
3018 acfg
->method_order
= g_list_append (acfg
->method_order
, GUINT_TO_POINTER (method_index
));
3023 /* Add missing methods */
3025 for (i
= 0; i
< acfg
->image
->tables
[MONO_TABLE_METHOD
].rows
; ++i
) {
3026 if (!g_list_find (acfg
->method_order
, GUINT_TO_POINTER (i
)))
3027 unordered
= g_list_prepend (unordered
, GUINT_TO_POINTER (i
));
3029 unordered
= g_list_reverse (unordered
);
3030 if (acfg
->method_order
)
3031 g_list_last (acfg
->method_order
)->next
= unordered
;
3033 acfg
->method_order
= unordered
;
3039 * Collect all patches which have shared GOT entries and alloc entries for them. The
3040 * rest will get entries allocated during emit_code ().
3043 alloc_got_slots (MonoAotCompile
*acfg
)
3049 /* Slot 0 is reserved for the address of the current assembly */
3050 ji
= mono_mempool_alloc0 (acfg
->mempool
, sizeof (MonoAotCompile
));
3051 ji
->type
= MONO_PATCH_INFO_IMAGE
;
3052 ji
->data
.image
= acfg
->image
;
3054 get_shared_got_offset (acfg
, ji
);
3056 for (l
= acfg
->method_order
; l
!= NULL
; l
= l
->next
) {
3057 i
= GPOINTER_TO_UINT (l
->data
);
3059 if (acfg
->cfgs
[i
]) {
3060 MonoCompile
*cfg
= acfg
->cfgs
[i
];
3062 for (ji
= cfg
->patch_info
; ji
; ji
= ji
->next
) {
3063 if (is_shared_got_patch (ji
))
3064 get_shared_got_offset (acfg
, ji
);
3071 emit_code (MonoAotCompile
*acfg
)
3077 sprintf (symbol
, "methods");
3078 emit_section_change (acfg
, ".text", 0);
3079 emit_global (acfg
, symbol
, TRUE
);
3080 emit_alignment (acfg
, 8);
3081 emit_label (acfg
, symbol
);
3084 * Emit some padding so the local symbol for the first method doesn't have the
3085 * same address as 'methods'.
3087 emit_zero_bytes (acfg
, 16);
3089 for (l
= acfg
->method_order
; l
!= NULL
; l
= l
->next
) {
3090 i
= GPOINTER_TO_UINT (l
->data
);
3093 emit_method_code (acfg
, acfg
->cfgs
[i
]);
3096 sprintf (symbol
, "methods_end");
3097 emit_section_change (acfg
, ".text", 0);
3098 emit_global (acfg
, symbol
, FALSE
);
3099 emit_alignment (acfg
, 8);
3100 emit_label (acfg
, symbol
);
3102 sprintf (symbol
, "method_offsets");
3103 emit_section_change (acfg
, ".text", 1);
3104 emit_global (acfg
, symbol
, FALSE
);
3105 emit_alignment (acfg
, 8);
3106 emit_label (acfg
, symbol
);
3108 for (i
= 0; i
< acfg
->nmethods
; ++i
) {
3109 if (acfg
->cfgs
[i
]) {
3110 sprintf (symbol
, ".Lm_%x", i
);
3111 emit_symbol_diff (acfg
, symbol
, "methods", 0);
3113 emit_int32 (acfg
, 0xffffffff);
3120 emit_info (MonoAotCompile
*acfg
)
3126 /* Emit method info */
3127 sprintf (symbol
, "method_info");
3128 emit_section_change (acfg
, ".text", 1);
3129 emit_global (acfg
, symbol
, FALSE
);
3130 emit_alignment (acfg
, 8);
3131 emit_label (acfg
, symbol
);
3133 /* To reduce size of generated assembly code */
3134 sprintf (symbol
, "mi");
3135 emit_label (acfg
, symbol
);
3137 for (l
= acfg
->method_order
; l
!= NULL
; l
= l
->next
) {
3138 i
= GPOINTER_TO_UINT (l
->data
);
3141 emit_method_info (acfg
, acfg
->cfgs
[i
]);
3144 sprintf (symbol
, "method_info_offsets");
3145 emit_section_change (acfg
, ".text", 1);
3146 emit_global (acfg
, symbol
, FALSE
);
3147 emit_alignment (acfg
, 8);
3148 emit_label (acfg
, symbol
);
3150 for (i
= 0; i
< acfg
->nmethods
; ++i
) {
3151 if (acfg
->cfgs
[i
]) {
3152 sprintf (symbol
, ".Lm_%x_p", i
);
3153 emit_symbol_diff (acfg
, symbol
, "mi", 0);
3155 emit_int32 (acfg
, 0);
3162 * mono_aot_method_hash:
3164 * Return a hash code for methods which only depends on metadata.
3167 mono_aot_method_hash (MonoMethod
*method
)
3171 if (method
->wrapper_type
) {
3172 hash
= g_str_hash (method
->name
);
3174 char *full_name
= mono_method_full_name (method
, TRUE
);
3175 // FIXME: Improve this (changing this requires bumping MONO_AOT_FILE_VERSION)
3176 hash
= g_str_hash (full_name
);
3183 typedef struct HashEntry
{
3184 guint32 key
, value
, index
;
3185 struct HashEntry
*next
;
3189 * emit_extra_methods:
3191 * Emit methods which are not in the METHOD table, like wrappers.
3194 emit_extra_methods (MonoAotCompile
*acfg
)
3196 int i
, table_size
, buf_size
;
3199 guint32
*info_offsets
;
3202 HashEntry
*entry
, *new_entry
;
3203 int nmethods
, max_chain_length
;
3206 info_offsets
= g_new0 (guint32
, acfg
->extra_methods
->len
);
3208 buf_size
= acfg
->extra_methods
->len
* 256 + 256;
3209 p
= buf
= g_malloc (buf_size
);
3211 /* Encode method info */
3213 /* So offsets are > 0 */
3216 for (i
= 0; i
< acfg
->extra_methods
->len
; ++i
) {
3217 MonoMethod
*method
= g_ptr_array_index (acfg
->extra_methods
, i
);
3218 MonoCompile
*cfg
= g_hash_table_lookup (acfg
->method_to_cfg
, method
);
3224 info_offsets
[i
] = p
- buf
;
3226 if (method
->wrapper_type
) {
3229 // FIXME: Optimize disk usage
3230 if (method
->wrapper_type
== MONO_WRAPPER_RUNTIME_INVOKE
) {
3231 char *tmpsig
= mono_signature_get_desc (mono_method_signature (method
), TRUE
);
3232 name
= g_strdup_printf ("(wrapper runtime-invoke):%s (%s)", method
->name
, tmpsig
);
3234 } else if (method
->wrapper_type
== MONO_WRAPPER_DELEGATE_INVOKE
) {
3235 char *tmpsig
= mono_signature_get_desc (mono_method_signature (method
), TRUE
);
3236 name
= g_strdup_printf ("(wrapper delegate-invoke):%s (%s)", method
->name
, tmpsig
);
3238 } else if (method
->wrapper_type
== MONO_WRAPPER_DELEGATE_BEGIN_INVOKE
) {
3239 char *tmpsig
= mono_signature_get_desc (mono_method_signature (method
), TRUE
);
3240 name
= g_strdup_printf ("(wrapper delegate-begin-invoke):%s (%s)", method
->name
, tmpsig
);
3242 } else if (method
->wrapper_type
== MONO_WRAPPER_DELEGATE_END_INVOKE
) {
3243 char *tmpsig
= mono_signature_get_desc (mono_method_signature (method
), TRUE
);
3244 name
= g_strdup_printf ("(wrapper delegate-end-invoke):%s (%s)", method
->name
, tmpsig
);
3247 name
= mono_method_full_name (cfg
->orig_method
, TRUE
);
3250 encode_value (1, p
, &p
);
3251 strcpy ((char*)p
, name
);
3252 p
+= strlen (name
) + 1;
3255 encode_value (0, p
, &p
);
3256 encode_method_ref (acfg
, method
, p
, &p
);
3259 g_assert ((p
- buf
) < buf_size
);
3262 g_assert ((p
- buf
) < buf_size
);
3264 /* Emit method info */
3265 sprintf (symbol
, "extra_method_info");
3266 emit_section_change (acfg
, ".text", 1);
3267 emit_global (acfg
, symbol
, FALSE
);
3268 emit_alignment (acfg
, 8);
3269 emit_label (acfg
, symbol
);
3271 emit_bytes (acfg
, buf
, p
- buf
);
3276 * Construct a chained hash table for mapping indexes in extra_method_info to
3279 table_size
= g_spaced_primes_closest ((int)(nmethods
* 1.5));
3280 table
= g_ptr_array_sized_new (table_size
);
3281 for (i
= 0; i
< table_size
; ++i
)
3282 g_ptr_array_add (table
, NULL
);
3283 chain_lengths
= g_new0 (int, table_size
);
3284 max_chain_length
= 0;
3285 for (i
= 0; i
< acfg
->extra_methods
->len
; ++i
) {
3286 MonoMethod
*method
= g_ptr_array_index (acfg
->extra_methods
, i
);
3287 MonoCompile
*cfg
= g_hash_table_lookup (acfg
->method_to_cfg
, method
);
3293 key
= info_offsets
[i
];
3294 value
= get_method_index (acfg
, method
);
3296 hash
= mono_aot_method_hash (method
) % table_size
;
3298 chain_lengths
[hash
] ++;
3299 max_chain_length
= MAX (max_chain_length
, chain_lengths
[hash
]);
3301 /* FIXME: Allocate from the mempool */
3302 new_entry
= g_new0 (HashEntry
, 1);
3303 new_entry
->key
= key
;
3304 new_entry
->value
= value
;
3306 entry
= g_ptr_array_index (table
, hash
);
3307 if (entry
== NULL
) {
3308 new_entry
->index
= hash
;
3309 g_ptr_array_index (table
, hash
) = new_entry
;
3312 entry
= entry
->next
;
3314 entry
->next
= new_entry
;
3315 new_entry
->index
= table
->len
;
3316 g_ptr_array_add (table
, new_entry
);
3320 //printf ("MAX: %d\n", max_chain_length);
3322 /* Emit the table */
3323 sprintf (symbol
, "extra_method_table");
3324 emit_section_change (acfg
, ".text", 0);
3325 emit_global (acfg
, symbol
, FALSE
);
3326 emit_alignment (acfg
, 8);
3327 emit_label (acfg
, symbol
);
3329 g_assert (table_size
< 65000);
3330 emit_int32 (acfg
, table_size
);
3331 g_assert (table
->len
< 65000);
3332 for (i
= 0; i
< table
->len
; ++i
) {
3333 HashEntry
*entry
= g_ptr_array_index (table
, i
);
3335 if (entry
== NULL
) {
3336 emit_int32 (acfg
, 0);
3337 emit_int32 (acfg
, 0);
3338 emit_int32 (acfg
, 0);
3340 g_assert (entry
->key
> 0);
3341 emit_int32 (acfg
, entry
->key
);
3342 emit_int32 (acfg
, entry
->value
);
3344 emit_int32 (acfg
, entry
->next
->index
);
3346 emit_int32 (acfg
, 0);
3351 * Emit a table reverse mapping method indexes to their index in extra_method_info.
3352 * This is used by mono_aot_find_jit_info ().
3354 sprintf (symbol
, "extra_method_info_offsets");
3355 emit_section_change (acfg
, ".text", 0);
3356 emit_global (acfg
, symbol
, FALSE
);
3357 emit_alignment (acfg
, 8);
3358 emit_label (acfg
, symbol
);
3360 emit_int32 (acfg
, acfg
->extra_methods
->len
);
3361 for (i
= 0; i
< acfg
->extra_methods
->len
; ++i
) {
3362 MonoMethod
*method
= g_ptr_array_index (acfg
->extra_methods
, i
);
3364 emit_int32 (acfg
, get_method_index (acfg
, method
));
3365 emit_int32 (acfg
, info_offsets
[i
]);
3370 emit_method_order (MonoAotCompile
*acfg
)
3376 sprintf (symbol
, "method_order");
3377 emit_section_change (acfg
, ".text", 1);
3378 emit_global (acfg
, symbol
, FALSE
);
3379 emit_alignment (acfg
, 8);
3380 emit_label (acfg
, symbol
);
3382 /* First emit an index table */
3385 for (l
= acfg
->method_order
; l
!= NULL
; l
= l
->next
) {
3386 i
= GPOINTER_TO_UINT (l
->data
);
3388 if (acfg
->cfgs
[i
]) {
3389 if ((index
% 1024) == 0) {
3390 emit_int32 (acfg
, i
);
3398 emit_int32 (acfg
, 0xffffff);
3400 /* Then emit the whole method order */
3401 for (l
= acfg
->method_order
; l
!= NULL
; l
= l
->next
) {
3402 i
= GPOINTER_TO_UINT (l
->data
);
3404 if (acfg
->cfgs
[i
]) {
3405 emit_int32 (acfg
, i
);
3410 sprintf (symbol
, "method_order_end");
3411 emit_section_change (acfg
, ".text", 1);
3412 emit_global (acfg
, symbol
, FALSE
);
3413 emit_label (acfg
, symbol
);
3417 emit_exception_info (MonoAotCompile
*acfg
)
3422 sprintf (symbol
, "ex_info");
3423 emit_section_change (acfg
, ".text", 1);
3424 emit_global (acfg
, symbol
, FALSE
);
3425 emit_alignment (acfg
, 8);
3426 emit_label (acfg
, symbol
);
3428 /* To reduce size of generated assembly */
3429 sprintf (symbol
, "ex");
3430 emit_label (acfg
, symbol
);
3432 for (i
= 0; i
< acfg
->nmethods
; ++i
) {
3434 emit_exception_debug_info (acfg
, acfg
->cfgs
[i
]);
3437 sprintf (symbol
, "ex_info_offsets");
3438 emit_section_change (acfg
, ".text", 1);
3439 emit_global (acfg
, symbol
, FALSE
);
3440 emit_alignment (acfg
, 8);
3441 emit_label (acfg
, symbol
);
3443 for (i
= 0; i
< acfg
->nmethods
; ++i
) {
3444 if (acfg
->cfgs
[i
]) {
3445 sprintf (symbol
, ".Le_%x_p", i
);
3446 emit_symbol_diff (acfg
, symbol
, "ex", 0);
3448 emit_int32 (acfg
, 0);
3455 emit_class_info (MonoAotCompile
*acfg
)
3460 sprintf (symbol
, "class_info");
3461 emit_section_change (acfg
, ".text", 1);
3462 emit_global (acfg
, symbol
, FALSE
);
3463 emit_alignment (acfg
, 8);
3464 emit_label (acfg
, symbol
);
3466 for (i
= 0; i
< acfg
->image
->tables
[MONO_TABLE_TYPEDEF
].rows
; ++i
)
3467 emit_klass_info (acfg
, MONO_TOKEN_TYPE_DEF
| (i
+ 1));
3469 sprintf (symbol
, "class_info_offsets");
3470 emit_section_change (acfg
, ".text", 1);
3471 emit_global (acfg
, symbol
, FALSE
);
3472 emit_alignment (acfg
, 8);
3473 emit_label (acfg
, symbol
);
3475 for (i
= 0; i
< acfg
->image
->tables
[MONO_TABLE_TYPEDEF
].rows
; ++i
) {
3476 sprintf (symbol
, ".LK_I_%x", i
);
3477 emit_symbol_diff (acfg
, symbol
, "class_info", 0);
3482 typedef struct ClassNameTableEntry
{
3483 guint32 token
, index
;
3484 struct ClassNameTableEntry
*next
;
3485 } ClassNameTableEntry
;
3488 emit_class_name_table (MonoAotCompile
*acfg
)
3491 guint32 token
, hash
;
3496 ClassNameTableEntry
*entry
, *new_entry
;
3499 * Construct a chained hash table for mapping class names to typedef tokens.
3501 table_size
= g_spaced_primes_closest ((int)(acfg
->image
->tables
[MONO_TABLE_TYPEDEF
].rows
* 1.5));
3502 table
= g_ptr_array_sized_new (table_size
);
3503 for (i
= 0; i
< table_size
; ++i
)
3504 g_ptr_array_add (table
, NULL
);
3505 for (i
= 0; i
< acfg
->image
->tables
[MONO_TABLE_TYPEDEF
].rows
; ++i
) {
3506 token
= MONO_TOKEN_TYPE_DEF
| (i
+ 1);
3507 klass
= mono_class_get (acfg
->image
, token
);
3508 full_name
= mono_type_get_name_full (mono_class_get_type (klass
), MONO_TYPE_NAME_FORMAT_FULL_NAME
);
3509 hash
= g_str_hash (full_name
) % table_size
;
3512 /* FIXME: Allocate from the mempool */
3513 new_entry
= g_new0 (ClassNameTableEntry
, 1);
3514 new_entry
->token
= token
;
3516 entry
= g_ptr_array_index (table
, hash
);
3517 if (entry
== NULL
) {
3518 new_entry
->index
= hash
;
3519 g_ptr_array_index (table
, hash
) = new_entry
;
3522 entry
= entry
->next
;
3524 entry
->next
= new_entry
;
3525 new_entry
->index
= table
->len
;
3526 g_ptr_array_add (table
, new_entry
);
3530 /* Emit the table */
3531 sprintf (symbol
, "class_name_table");
3532 emit_section_change (acfg
, ".text", 0);
3533 emit_global (acfg
, symbol
, FALSE
);
3534 emit_alignment (acfg
, 8);
3535 emit_label (acfg
, symbol
);
3537 /* FIXME: Optimize memory usage */
3538 g_assert (table_size
< 65000);
3539 emit_int16 (acfg
, table_size
);
3540 g_assert (table
->len
< 65000);
3541 for (i
= 0; i
< table
->len
; ++i
) {
3542 ClassNameTableEntry
*entry
= g_ptr_array_index (table
, i
);
3544 if (entry
== NULL
) {
3545 emit_int16 (acfg
, 0);
3546 emit_int16 (acfg
, 0);
3548 emit_int16 (acfg
, mono_metadata_token_index (entry
->token
));
3550 emit_int16 (acfg
, entry
->next
->index
);
3552 emit_int16 (acfg
, 0);
3558 emit_image_table (MonoAotCompile
*acfg
)
3564 * The image table is small but referenced in a lot of places.
3565 * So we emit it at once, and reference its elements by an index.
3568 sprintf (symbol
, "mono_image_table");
3569 emit_section_change (acfg
, ".text", 1);
3570 emit_global (acfg
, symbol
, FALSE
);
3571 emit_alignment (acfg
, 8);
3572 emit_label (acfg
, symbol
);
3574 emit_int32 (acfg
, acfg
->image_table
->len
);
3575 for (i
= 0; i
< acfg
->image_table
->len
; i
++) {
3576 MonoImage
*image
= (MonoImage
*)g_ptr_array_index (acfg
->image_table
, i
);
3577 MonoAssemblyName
*aname
= &image
->assembly
->aname
;
3579 /* FIXME: Support multi-module assemblies */
3580 g_assert (image
->assembly
->image
== image
);
3582 emit_string (acfg
, image
->assembly_name
);
3583 emit_string (acfg
, image
->guid
);
3584 emit_string (acfg
, aname
->culture
? aname
->culture
: "");
3585 emit_string (acfg
, (const char*)aname
->public_key_token
);
3587 emit_alignment (acfg
, 8);
3588 emit_int32 (acfg
, aname
->flags
);
3589 emit_int32 (acfg
, aname
->major
);
3590 emit_int32 (acfg
, aname
->minor
);
3591 emit_int32 (acfg
, aname
->build
);
3592 emit_int32 (acfg
, aname
->revision
);
3597 emit_got_info (MonoAotCompile
*acfg
)
3600 int i
, first_plt_got_patch
, buf_size
;
3602 guint32
*got_info_offsets
;
3604 /* Add the patches needed by the PLT to the GOT */
3605 acfg
->plt_got_offset_base
= acfg
->got_offset
;
3606 first_plt_got_patch
= acfg
->shared_patches
->len
;
3607 for (i
= 1; i
< acfg
->plt_offset
; ++i
) {
3608 MonoJumpInfo
*patch_info
= g_hash_table_lookup (acfg
->plt_offset_to_patch
, GUINT_TO_POINTER (i
));
3610 g_ptr_array_add (acfg
->shared_patches
, patch_info
);
3613 acfg
->got_offset
+= acfg
->plt_offset
;
3617 * - optimize offsets table.
3618 * - reduce number of exported symbols.
3619 * - emit info for a klass only once.
3620 * - determine when a method uses a GOT slot which is guaranteed to be already
3622 * - clean up and document the code.
3623 * - use String.Empty in class libs.
3626 /* Encode info required to decode shared GOT entries */
3627 buf_size
= acfg
->shared_patches
->len
* 64;
3628 p
= buf
= mono_mempool_alloc (acfg
->mempool
, buf_size
);
3629 got_info_offsets
= mono_mempool_alloc (acfg
->mempool
, acfg
->shared_patches
->len
* sizeof (guint32
));
3630 acfg
->plt_got_info_offsets
= mono_mempool_alloc (acfg
->mempool
, acfg
->plt_offset
* sizeof (guint32
));
3631 for (i
= 0; i
< acfg
->shared_patches
->len
; ++i
) {
3632 MonoJumpInfo
*ji
= g_ptr_array_index (acfg
->shared_patches
, i
);
3634 got_info_offsets
[i
] = p
- buf
;
3635 /* No need to encode the patch type for non-PLT patches */
3636 if (i
>= first_plt_got_patch
) {
3637 acfg
->plt_got_info_offsets
[i
- first_plt_got_patch
+ 1] = got_info_offsets
[i
];
3638 encode_value (ji
->type
, p
, &p
);
3640 encode_patch (acfg
, ji
, p
, &p
);
3643 g_assert (p
- buf
<= buf_size
);
3645 acfg
->stats
.got_info_size
= p
- buf
;
3647 /* Emit got_info table */
3648 sprintf (symbol
, "got_info");
3649 emit_section_change (acfg
, ".text", 1);
3650 emit_global (acfg
, symbol
, FALSE
);
3651 emit_alignment (acfg
, 8);
3652 emit_label (acfg
, symbol
);
3654 emit_bytes (acfg
, buf
, p
- buf
);
3656 /* Emit got_info_offsets table */
3657 sprintf (symbol
, "got_info_offsets");
3658 emit_section_change (acfg
, ".text", 1);
3659 emit_global (acfg
, symbol
, FALSE
);
3660 emit_alignment (acfg
, 8);
3661 emit_label (acfg
, symbol
);
3663 for (i
= 0; i
< acfg
->shared_patches
->len
; ++i
)
3664 emit_int32 (acfg
, got_info_offsets
[i
]);
3666 acfg
->stats
.got_info_offsets_size
= acfg
->shared_patches
->len
* 4;
3670 emit_got (MonoAotCompile
*acfg
)
3674 /* Don't make GOT global so accesses to it don't need relocations */
3675 sprintf (symbol
, "got");
3676 emit_section_change (acfg
, ".bss", 0);
3677 emit_alignment (acfg
, 8);
3678 emit_label (acfg
, symbol
);
3679 if (acfg
->got_offset
> 0)
3680 emit_zero_bytes (acfg
, (int)(acfg
->got_offset
* sizeof (gpointer
)));
3684 emit_globals (MonoAotCompile
*acfg
)
3689 emit_string_symbol (acfg
, "mono_assembly_guid" , acfg
->image
->guid
);
3691 emit_string_symbol (acfg
, "mono_aot_version", MONO_AOT_FILE_VERSION
);
3693 opts_str
= g_strdup_printf ("%d", acfg
->opts
);
3694 emit_string_symbol (acfg
, "mono_aot_opt_flags", opts_str
);
3697 emit_string_symbol (acfg
, "mono_aot_full_aot", acfg
->aot_opts
.full_aot
? "TRUE" : "FALSE");
3699 if (acfg
->aot_opts
.bind_to_runtime_version
) {
3700 build_info
= mono_get_runtime_build_info ();
3701 emit_string_symbol (acfg
, "mono_runtime_version", build_info
);
3702 g_free (build_info
);
3704 emit_string_symbol (acfg
, "mono_runtime_version", "");
3708 * Some platforms like the iphone have no working dlsym (). To work around this,
3709 * we create an ELF ctor function which will be invoked by dlopen, and which
3710 * will call a function in the AOT loader to register the symbols used by the
3712 * When static linking, we emit a global which will point to the symbol table.
3714 if (acfg
->aot_opts
.no_dlsym
) {
3718 if (acfg
->aot_opts
.static_link
)
3719 /* Emit a string holding the assembly name */
3720 emit_string_symbol (acfg
, "mono_aot_assembly_name", acfg
->image
->assembly
->aname
.name
);
3722 /* Emit the names */
3723 for (i
= 0; i
< acfg
->globals
->len
; ++i
) {
3724 char *name
= g_ptr_array_index (acfg
->globals
, i
);
3726 sprintf (symbol
, "name_%d", i
);
3727 emit_section_change (acfg
, ".text", 1);
3728 emit_label (acfg
, symbol
);
3729 emit_string (acfg
, name
);
3732 /* Emit the globals table */
3733 sprintf (symbol
, "globals");
3734 emit_section_change (acfg
, ".data", 0);
3735 /* This is not a global, since it is accessed by the init function */
3736 emit_alignment (acfg
, 8);
3737 emit_label (acfg
, symbol
);
3739 for (i
= 0; i
< acfg
->globals
->len
; ++i
) {
3740 char *name
= g_ptr_array_index (acfg
->globals
, i
);
3742 sprintf (symbol
, "name_%d", i
);
3743 emit_pointer (acfg
, symbol
);
3745 sprintf (symbol
, "%s", name
);
3746 emit_pointer (acfg
, symbol
);
3748 /* Null terminate the table */
3749 emit_pointer (acfg
, NULL
);
3750 emit_pointer (acfg
, NULL
);
3753 if (acfg
->aot_opts
.static_link
) {
3757 * Emit a global symbol which can be passed by an embedding app to
3758 * mono_aot_register_module ().
3760 #if defined(__MACH__)
3761 sprintf (symbol
, "_mono_aot_module_%s_info", acfg
->image
->assembly
->aname
.name
);
3763 sprintf (symbol
, "mono_aot_module_%s_info", acfg
->image
->assembly
->aname
.name
);
3766 /* Get rid of characters which cannot occur in symbols */
3768 for (p
= symbol
; *p
; ++p
) {
3769 if (!(isalnum (*p
) || *p
== '_'))
3772 acfg
->static_linking_symbol
= g_strdup (symbol
);
3773 emit_global_inner (acfg
, symbol
, FALSE
);
3774 emit_alignment (acfg
, 8);
3775 emit_label (acfg
, symbol
);
3776 emit_pointer (acfg
, "globals");
3778 sprintf (symbol
, "init_%s", acfg
->image
->assembly
->aname
.name
);
3779 emit_section_change (acfg
, ".text", 1);
3780 emit_alignment (acfg
, 8);
3781 emit_label (acfg
, symbol
);
3782 if (acfg
->use_bin_writer
)
3783 g_assert_not_reached ();
3785 fprintf (acfg
->fp
, "leaq globals(%%rip), %%rdi\n");
3786 fprintf (acfg
->fp
, "call mono_aot_register_globals@PLT\n");
3787 fprintf (acfg
->fp
, "ret\n");
3788 fprintf (acfg
->fp
, ".section .ctors,\"aw\",@progbits\n");
3789 emit_alignment (acfg
, 8);
3790 emit_pointer (acfg
, symbol
);
3791 #elif defined(__arm__) && defined(__MACH__)
3793 fprintf (acfg
->fp
, ".text\n");
3794 fprintf (acfg
->fp
, ".align 3\n");
3796 fprintf (acfg
->fp
, "ldr r0, .L5\n");
3797 fprintf (acfg
->fp
, ".LPIC0:\n");
3798 fprintf (acfg
->fp
, "add r0, pc, r0\n");
3799 fprintf (acfg
->fp
, "ldr r0, [r0]\n");
3800 fprintf (acfg
->fp
, "b _mono_aot_register_globals@PLT\n");
3801 fprintf (acfg
->fp
, ".align 2\n");
3803 fprintf (acfg
->fp
, ".L5:\n");
3804 fprintf (acfg
->fp
, ".long globals_ptr-(.LPIC0+8)\n");
3806 fprintf (acfg
->fp
, ".data\n");
3807 fprintf (acfg
->fp
, ".align 2\n");
3808 fprintf (acfg
->fp
, "globals_ptr:\n");
3809 fprintf (acfg
->fp
, ".long globals\n");
3811 fprintf (acfg
->fp
, ".mod_init_func\n");
3812 fprintf (acfg
->fp
, ".align 2\n");
3813 fprintf (acfg
->fp
, ".long %s@target1\n", symbol
);
3815 #elif defined(__arm__)
3817 * Taken from gcc generated code for:
3819 * void foo () { bar (&i); }
3820 * gcc --shared -fPIC -O2
3822 fprintf (acfg
->fp
, "ldr r3, .L5\n");
3823 fprintf (acfg
->fp
, "ldr r0, .L5+4\n");
3824 fprintf (acfg
->fp
, ".LPIC0:\n");
3825 fprintf (acfg
->fp
, "add r3, pc, r3\n");
3826 fprintf (acfg
->fp
, "add r0, r3, r0\n");
3827 fprintf (acfg
->fp
, "b mono_aot_register_globals(PLT)\n");
3829 fprintf (acfg
->fp
, ".L5:\n");
3830 fprintf (acfg
->fp
, ".word _GLOBAL_OFFSET_TABLE_-(.LPIC0+8)\n");
3831 fprintf (acfg
->fp
, ".word globals(GOTOFF)\n");
3833 fprintf (acfg
->fp
, ".section .init_array,\"aw\",%%init_array\n");
3834 fprintf (acfg
->fp
, ".align 2\n");
3835 fprintf (acfg
->fp
, ".word %s(target1)\n", symbol
);
3837 g_assert_not_reached ();
3845 * Emit a structure containing all the information not stored elsewhere.
3848 emit_file_info (MonoAotCompile
*acfg
)
3852 sprintf (symbol
, "mono_aot_file_info");
3853 emit_section_change (acfg
, ".data", 0);
3854 emit_alignment (acfg
, 8);
3855 emit_label (acfg
, symbol
);
3856 emit_global (acfg
, symbol
, FALSE
);
3858 /* The data emitted here must match MonoAotFileInfo in aot-runtime.c. */
3859 emit_int32 (acfg
, acfg
->plt_got_offset_base
);
3860 emit_int32 (acfg
, acfg
->trampoline_got_offset_base
);
3861 emit_int32 (acfg
, acfg
->num_aot_trampolines
);
3862 emit_int32 (acfg
, (int)(acfg
->got_offset
* sizeof (gpointer
)));
3863 emit_int32 (acfg
, acfg
->plt_offset
);
3864 emit_int32 (acfg
, acfg
->specific_trampoline_size
);
3865 emit_pointer (acfg
, "got");
3868 /*****************************************/
3869 /* Emitting DWARF debug information */
3870 /*****************************************/
3873 emit_dwarf_info (MonoAotCompile
*acfg
)
3875 #ifdef EMIT_DWARF_INFO
3877 char symbol
[128], symbol2
[128];
3879 /* DIEs for methods */
3880 for (i
= 0; i
< acfg
->nmethods
; ++i
) {
3881 MonoCompile
*cfg
= acfg
->cfgs
[i
];
3886 sprintf (symbol
, ".Lm_%x", i
);
3887 sprintf (symbol2
, ".Lme_%x", i
);
3889 mono_dwarf_writer_emit_method (acfg
->dwarf
, cfg
, cfg
->method
, symbol
, symbol2
, NULL
, 0, cfg
->args
, cfg
->locals
, cfg
->unwind_ops
, NULL
);
3895 compile_asm (MonoAotCompile
*acfg
)
3897 char *command
, *objfile
;
3898 char *outfile_name
, *tmp_outfile_name
;
3900 #if defined(__x86_64__)
3901 #define AS_OPTIONS "--64"
3902 #elif defined(sparc) && SIZEOF_VOID_P == 8
3903 #define AS_OPTIONS "-xarch=v9"
3905 #define AS_OPTIONS ""
3908 if (acfg
->aot_opts
.asm_only
) {
3909 printf ("Output file: '%s'.\n", acfg
->tmpfname
);
3910 if (acfg
->aot_opts
.static_link
)
3911 printf ("Linking symbol: '%s'.\n", acfg
->static_linking_symbol
);
3915 if (acfg
->aot_opts
.static_link
) {
3916 if (acfg
->aot_opts
.outfile
)
3917 objfile
= g_strdup_printf ("%s", acfg
->aot_opts
.outfile
);
3919 objfile
= g_strdup_printf ("%s.o", acfg
->image
->name
);
3921 objfile
= g_strdup_printf ("%s.o", acfg
->tmpfname
);
3923 command
= g_strdup_printf ("as %s %s -o %s", AS_OPTIONS
, acfg
->tmpfname
, objfile
);
3924 printf ("Executing the native assembler: %s\n", command
);
3925 if (system (command
) != 0) {
3933 if (acfg
->aot_opts
.static_link
) {
3934 printf ("Output file: '%s'.\n", objfile
);
3935 printf ("Linking symbol: '%s'.\n", acfg
->static_linking_symbol
);
3940 if (acfg
->aot_opts
.outfile
)
3941 outfile_name
= g_strdup_printf ("%s", acfg
->aot_opts
.outfile
);
3943 outfile_name
= g_strdup_printf ("%s%s", acfg
->image
->name
, SHARED_EXT
);
3945 tmp_outfile_name
= g_strdup_printf ("%s.tmp", outfile_name
);
3948 command
= g_strdup_printf ("ld -shared -G -o %s %s.o", outfile_name
, acfg
->tmpfname
);
3949 #elif defined(__ppc__) && defined(__MACH__)
3950 command
= g_strdup_printf ("gcc -dynamiclib -o %s %s.o", outfile_name
, acfg
->tmpfname
);
3951 #elif defined(PLATFORM_WIN32)
3952 command
= g_strdup_printf ("gcc -shared --dll -mno-cygwin -o %s %s.o", outfile_name
, acfg
->tmpfname
);
3954 if (acfg
->aot_opts
.no_dlsym
) {
3956 * Need to link using gcc so our ctor function gets called.
3958 command
= g_strdup_printf ("gcc -shared -o %s %s.o", outfile_name
, acfg
->tmpfname
);
3960 command
= g_strdup_printf ("ld -shared -o %s %s.o", outfile_name
, acfg
->tmpfname
);
3963 printf ("Executing the native linker: %s\n", command
);
3964 if (system (command
) != 0) {
3965 g_free (tmp_outfile_name
);
3966 g_free (outfile_name
);
3974 /*com = g_strdup_printf ("strip --strip-unneeded %s%s", acfg->image->name, SHARED_EXT);
3975 printf ("Stripping the binary: %s\n", com);
3979 rename (tmp_outfile_name
, outfile_name
);
3981 g_free (tmp_outfile_name
);
3982 g_free (outfile_name
);
3985 if (acfg
->aot_opts
.save_temps
)
3986 printf ("Retained input file.\n");
3988 unlink (acfg
->tmpfname
);
3994 acfg_free (MonoAotCompile
*acfg
)
3998 img_writer_destroy (acfg
->w
);
3999 for (i
= 0; i
< acfg
->nmethods
; ++i
)
4001 g_free (acfg
->cfgs
[i
]);
4002 g_free (acfg
->cfgs
);
4003 g_free (acfg
->static_linking_symbol
);
4004 g_ptr_array_free (acfg
->methods
, TRUE
);
4005 g_ptr_array_free (acfg
->shared_patches
, TRUE
);
4006 g_ptr_array_free (acfg
->image_table
, TRUE
);
4007 g_ptr_array_free (acfg
->globals
, TRUE
);
4008 g_hash_table_destroy (acfg
->method_indexes
);
4009 g_hash_table_destroy (acfg
->plt_offset_to_patch
);
4010 g_hash_table_destroy (acfg
->patch_to_plt_offset
);
4011 g_hash_table_destroy (acfg
->patch_to_shared_got_offset
);
4012 g_hash_table_destroy (acfg
->method_to_cfg
);
4013 g_hash_table_destroy (acfg
->token_info_hash
);
4014 g_hash_table_destroy (acfg
->image_hash
);
4015 mono_mempool_destroy (acfg
->mempool
);
4020 mono_compile_assembly (MonoAssembly
*ass
, guint32 opts
, const char *aot_options
)
4022 MonoImage
*image
= ass
->image
;
4024 int i
, res
, methods_len
;
4025 MonoAotCompile
*acfg
;
4026 char *outfile_name
, *tmp_outfile_name
;
4030 printf ("Mono Ahead of Time compiler - compiling assembly %s\n", image
->name
);
4032 acfg
= g_new0 (MonoAotCompile
, 1);
4033 acfg
->methods
= g_ptr_array_new ();
4034 acfg
->method_indexes
= g_hash_table_new (NULL
, NULL
);
4035 acfg
->plt_offset_to_patch
= g_hash_table_new (NULL
, NULL
);
4036 acfg
->patch_to_plt_offset
= g_hash_table_new (mono_patch_info_hash
, mono_patch_info_equal
);
4037 acfg
->patch_to_shared_got_offset
= g_hash_table_new (mono_patch_info_hash
, mono_patch_info_equal
);
4038 acfg
->shared_patches
= g_ptr_array_new ();
4039 acfg
->method_to_cfg
= g_hash_table_new (NULL
, NULL
);
4040 acfg
->token_info_hash
= g_hash_table_new_full (NULL
, NULL
, NULL
, g_free
);
4041 acfg
->image_hash
= g_hash_table_new (NULL
, NULL
);
4042 acfg
->image_table
= g_ptr_array_new ();
4043 acfg
->globals
= g_ptr_array_new ();
4044 acfg
->image
= image
;
4046 acfg
->mempool
= mono_mempool_new ();
4047 acfg
->extra_methods
= g_ptr_array_new ();
4048 InitializeCriticalSection (&acfg
->mutex
);
4050 memset (&acfg
->aot_opts
, 0, sizeof (acfg
->aot_opts
));
4051 acfg
->aot_opts
.write_symbols
= TRUE
;
4053 mono_aot_parse_options (aot_options
, &acfg
->aot_opts
);
4055 //acfg->aot_opts.print_skipped_methods = TRUE;
4058 if (acfg
->aot_opts
.full_aot
)
4059 /* arch_emit_unbox_trampoline () etc only works with the asm writer */
4060 acfg
->aot_opts
.asm_writer
= TRUE
;
4063 #ifndef MONO_ARCH_HAVE_FULL_AOT_TRAMPOLINES
4064 if (acfg
->aot_opts
.full_aot
) {
4065 printf ("--aot=full is not supported on this platform.\n");
4070 if (!acfg
->aot_opts
.asm_only
&& !acfg
->aot_opts
.asm_writer
&& bin_writer_supported ()) {
4071 if (acfg
->aot_opts
.outfile
)
4072 outfile_name
= g_strdup_printf ("%s", acfg
->aot_opts
.outfile
);
4074 outfile_name
= g_strdup_printf ("%s%s", acfg
->image
->name
, SHARED_EXT
);
4076 tmp_outfile_name
= g_strdup_printf ("%s.tmp", outfile_name
);
4078 acfg
->fp
= fopen (tmp_outfile_name
, "w");
4079 g_assert (acfg
->fp
);
4081 acfg
->w
= img_writer_create (acfg
->fp
, TRUE
);
4082 acfg
->use_bin_writer
= TRUE
;
4084 if (acfg
->aot_opts
.asm_only
) {
4085 if (acfg
->aot_opts
.outfile
)
4086 acfg
->tmpfname
= g_strdup_printf ("%s", acfg
->aot_opts
.outfile
);
4088 acfg
->tmpfname
= g_strdup_printf ("%s.s", acfg
->image
->name
);
4089 acfg
->fp
= fopen (acfg
->tmpfname
, "w+");
4091 int i
= g_file_open_tmp ("mono_aot_XXXXXX", &acfg
->tmpfname
, NULL
);
4092 acfg
->fp
= fdopen (i
, "w+");
4094 g_assert (acfg
->fp
);
4096 acfg
->w
= img_writer_create (acfg
->fp
, FALSE
);
4098 /* hush compiler warnings about these being possibly uninitialized */
4099 tmp_outfile_name
= NULL
;
4100 outfile_name
= NULL
;
4103 load_profile_files (acfg
);
4105 img_writer_emit_start (acfg
->w
);
4107 acfg
->dwarf
= mono_dwarf_writer_create (acfg
->w
, NULL
);
4109 acfg
->num_aot_trampolines
= acfg
->aot_opts
.full_aot
? 10240 : 0;
4111 acfg
->method_index
= 1;
4113 /* Collect methods */
4114 for (i
= 0; i
< image
->tables
[MONO_TABLE_METHOD
].rows
; ++i
) {
4116 guint32 token
= MONO_TOKEN_METHOD_DEF
| (i
+ 1);
4118 method
= mono_get_method (acfg
->image
, token
, NULL
);
4121 printf ("Failed to load method 0x%x from '%s'.\n", token
, image
->name
);
4125 /* Load all methods eagerly to skip the slower lazy loading code */
4126 mono_class_setup_methods (method
->klass
);
4128 if (acfg
->aot_opts
.full_aot
&& method
->iflags
& METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
) {
4129 /* Compile the wrapper instead */
4130 /* We do this here instead of add_wrappers () because it is easy to do it here */
4131 MonoMethod
*wrapper
= mono_marshal_get_native_wrapper (method
, check_for_pending_exc
, TRUE
);
4135 /* Since we add the normal methods first, their index will be equal to their zero based token index */
4136 add_method_with_index (acfg
, method
, i
);
4137 acfg
->method_index
++;
4140 add_generic_instances (acfg
);
4142 if (acfg
->aot_opts
.full_aot
)
4143 add_wrappers (acfg
);
4145 acfg
->cfgs_size
= acfg
->methods
->len
+ 32;
4146 acfg
->cfgs
= g_new0 (MonoCompile
*, acfg
->cfgs_size
);
4148 /* PLT offset 0 is reserved for the PLT trampoline */
4149 acfg
->plt_offset
= 1;
4151 /* Compile methods */
4154 if (acfg
->aot_opts
.nthreads
> 0) {
4159 gpointer
*user_data
;
4160 MonoMethod
**methods
;
4162 methods_len
= acfg
->methods
->len
;
4164 len
= acfg
->methods
->len
/ acfg
->aot_opts
.nthreads
;
4167 * Partition the list of methods into fragments, and hand it to threads to
4170 threads
= g_ptr_array_new ();
4171 /* Make a copy since acfg->methods is modified by compile_method () */
4172 methods
= g_new0 (MonoMethod
*, methods_len
);
4173 //memcpy (methods, g_ptr_array_index (acfg->methods, 0), sizeof (MonoMethod*) * methods_len);
4174 for (i
= 0; i
< methods_len
; ++i
)
4175 methods
[i
] = g_ptr_array_index (acfg
->methods
, i
);
4177 while (i
< methods_len
) {
4178 frag
= g_ptr_array_new ();
4179 for (j
= 0; j
< len
; ++j
) {
4180 if (i
< methods_len
) {
4181 g_ptr_array_add (frag
, methods
[i
]);
4186 user_data
= g_new0 (gpointer
, 3);
4187 user_data
[0] = mono_domain_get ();
4188 user_data
[1] = acfg
;
4189 user_data
[2] = frag
;
4191 handle
= CreateThread (NULL
, 0, (gpointer
)compile_thread_main
, user_data
, 0, NULL
);
4192 g_ptr_array_add (threads
, handle
);
4196 for (i
= 0; i
< threads
->len
; ++i
) {
4197 WaitForSingleObjectEx (g_ptr_array_index (threads
, i
), INFINITE
, FALSE
);
4203 /* Compile methods added by compile_method () or all methods if nthreads == 0 */
4204 for (i
= methods_len
; i
< acfg
->methods
->len
; ++i
) {
4205 /* This can new methods to acfg->methods */
4206 compile_method (acfg
, g_ptr_array_index (acfg
->methods
, i
));
4211 acfg
->stats
.jit_time
= TV_ELAPSED (atv
, btv
);
4215 mono_dwarf_writer_emit_base_info (acfg
->dwarf
, arch_get_cie_program ());
4217 alloc_got_slots (acfg
);
4223 emit_extra_methods (acfg
);
4225 emit_method_order (acfg
);
4227 emit_trampolines (acfg
);
4229 emit_class_name_table (acfg
);
4231 emit_got_info (acfg
);
4233 emit_exception_info (acfg
);
4235 emit_class_info (acfg
);
4239 emit_image_table (acfg
);
4243 emit_file_info (acfg
);
4245 emit_globals (acfg
);
4247 emit_dwarf_info (acfg
);
4249 sprintf (symbol
, "mem_end");
4250 emit_section_change (acfg
, ".text", 1);
4251 emit_global (acfg
, symbol
, FALSE
);
4252 emit_alignment (acfg
, 8);
4253 emit_label (acfg
, symbol
);
4257 acfg
->stats
.gen_time
= TV_ELAPSED (atv
, btv
);
4259 printf ("Code: %d Info: %d Ex Info: %d Class Info: %d PLT: %d GOT Info: %d GOT Info Offsets: %d GOT: %d\n", acfg
->stats
.code_size
, acfg
->stats
.info_size
, acfg
->stats
.ex_info_size
, acfg
->stats
.class_info_size
, acfg
->plt_offset
, acfg
->stats
.got_info_size
, acfg
->stats
.got_info_offsets_size
, (int)(acfg
->got_offset
* sizeof (gpointer
)));
4262 res
= img_writer_emit_writeout (acfg
->w
);
4267 if (acfg
->use_bin_writer
) {
4268 rename (tmp_outfile_name
, outfile_name
);
4270 res
= compile_asm (acfg
);
4277 acfg
->stats
.link_time
= TV_ELAPSED (atv
, btv
);
4279 printf ("Compiled %d out of %d methods (%d%%)\n", acfg
->stats
.ccount
, acfg
->stats
.mcount
, acfg
->stats
.mcount
? (acfg
->stats
.ccount
* 100) / acfg
->stats
.mcount
: 100);
4280 if (acfg
->stats
.genericcount
)
4281 printf ("%d methods are generic (%d%%)\n", acfg
->stats
.genericcount
, acfg
->stats
.mcount
? (acfg
->stats
.genericcount
* 100) / acfg
->stats
.mcount
: 100);
4282 if (acfg
->stats
.abscount
)
4283 printf ("%d methods contain absolute addresses (%d%%)\n", acfg
->stats
.abscount
, acfg
->stats
.mcount
? (acfg
->stats
.abscount
* 100) / acfg
->stats
.mcount
: 100);
4284 if (acfg
->stats
.lmfcount
)
4285 printf ("%d methods contain lmf pointers (%d%%)\n", acfg
->stats
.lmfcount
, acfg
->stats
.mcount
? (acfg
->stats
.lmfcount
* 100) / acfg
->stats
.mcount
: 100);
4286 if (acfg
->stats
.ocount
)
4287 printf ("%d methods have other problems (%d%%)\n", acfg
->stats
.ocount
, acfg
->stats
.mcount
? (acfg
->stats
.ocount
* 100) / acfg
->stats
.mcount
: 100);
4288 printf ("Methods without GOT slots: %d (%d%%)\n", acfg
->stats
.methods_without_got_slots
, acfg
->stats
.mcount
? (acfg
->stats
.methods_without_got_slots
* 100) / acfg
->stats
.mcount
: 100);
4289 printf ("Direct calls: %d (%d%%)\n", acfg
->stats
.direct_calls
, acfg
->stats
.all_calls
? (acfg
->stats
.direct_calls
* 100) / acfg
->stats
.all_calls
: 100);
4292 printf ("GOT slot distribution:\n");
4293 for (i = 0; i < MONO_PATCH_INFO_NONE; ++i)
4294 if (acfg->stats.got_slot_types [i])
4295 printf ("\t%s: %d\n", get_patch_name (i), acfg->stats.got_slot_types [i]);
4298 printf ("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);
4306 * Support for emitting debug info for JITted code.
4308 * This works as follows:
4309 * - the runtime writes out an xdb.s file containing DWARF debug info.
4310 * - the user calls a gdb macro
4311 * - the macro compiles and loads this shared library using add-symbol-file.
4313 * This is based on the xdebug functionality in the Kaffe Java VM.
4315 * We emit assembly code instead of using the ELF writer, so we can emit debug info
4316 * incrementally as each method is JITted, and the debugger doesn't have to call
4317 * into the runtime to emit the shared library, which would cause all kinds of
4318 * complications, like threading issues, and the fact that the ELF writer's
4319 * emit_writeout () function cannot be called more than once.
4322 /* The recommended gdb macro is: */
4325 shell rm -f xdb.so && as --64 -o xdb.o xdb.s && ld -shared -o xdb.so xdb.o
4326 add-symbol-file xdb.so 0
4330 static MonoDwarfWriter
*xdebug_writer
;
4331 static CRITICAL_SECTION xdebug_mutex
;
4332 static FILE *xdebug_fp
;
4334 #define mono_xdebug_lock(acfg) EnterCriticalSection (&xdebug_mutex)
4335 #define mono_xdebug_unlock(acfg) LeaveCriticalSection (&xdebug_mutex)
4338 mono_xdebug_init (void)
4343 InitializeCriticalSection (&xdebug_mutex
);
4346 xdebug_fp
= fopen ("xdb.s", "w");
4348 w
= img_writer_create (xdebug_fp
, FALSE
);
4350 img_writer_emit_start (w
);
4352 /* This file will contain the IL code for methods which don't have debug info */
4353 il_file
= fopen ("xdb.il", "w");
4355 xdebug_writer
= mono_dwarf_writer_create (w
, il_file
);
4357 /* Emit something so the file has a text segment */
4358 img_writer_emit_section_change (w
, ".text", 0);
4359 img_writer_emit_string (w
, "");
4361 mono_dwarf_writer_emit_base_info (xdebug_writer
, arch_get_cie_program ());
4365 * mono_save_xdebug_info:
4367 * Emit debugging info for METHOD into an assembly file which can be assembled
4368 * and loaded into gdb to provide debugging info for JITted code.
4371 mono_save_xdebug_info (MonoCompile
*cfg
)
4376 mono_xdebug_lock ();
4377 mono_dwarf_writer_emit_method (xdebug_writer
, cfg
, cfg
->jit_info
->method
, NULL
, NULL
, cfg
->jit_info
->code_start
, cfg
->jit_info
->code_size
, cfg
->args
, cfg
->locals
, cfg
->unwind_ops
, mono_debug_find_method (cfg
->jit_info
->method
, mono_domain_get ()));
4379 mono_xdebug_unlock ();
4383 * mono_save_trampoline_xdebug_info:
4385 * Same as mono_save_xdebug_info, but for trampolines.
4388 mono_save_trampoline_xdebug_info (const char *tramp_name
, guint8
*code
, guint32 code_size
, GSList
*unwind_info
)
4393 mono_xdebug_lock ();
4394 mono_dwarf_writer_emit_trampoline (xdebug_writer
, tramp_name
, NULL
, NULL
, code
, code_size
, unwind_info
);
4396 mono_xdebug_unlock ();
4404 mono_compile_assembly (MonoAssembly
*ass
, guint32 opts
, const char *aot_options
)
4410 mono_xdebug_init (void)
4415 mono_save_xdebug_info (MonoCompile
*cfg
)
4420 mono_save_trampoline_xdebug_info (const char *tramp_name
, guint8
*code
, guint32 code_size
, GSList
*unwind_info
)