2 * aot-runtime.c: mono Ahead of Time compiler
5 * Dietmar Maurer (dietmar@ximian.com)
6 * Zoltan Varga (vargaz@gmail.com)
8 * (C) 2002 Ximian, Inc.
12 #include <sys/types.h>
18 #ifdef HAVE_SYS_MMAN_H
27 #ifdef HAVE_EXECINFO_H
34 #ifdef HAVE_SYS_WAIT_H
35 #include <sys/wait.h> /* for WIFEXITED, WEXITSTATUS */
38 #ifdef HAVE_DL_ITERATE_PHDR
42 #include <mono/metadata/tabledefs.h>
43 #include <mono/metadata/class.h>
44 #include <mono/metadata/object.h>
45 #include <mono/metadata/tokentype.h>
46 #include <mono/metadata/appdomain.h>
47 #include <mono/metadata/debug-helpers.h>
48 #include <mono/metadata/assembly.h>
49 #include <mono/metadata/metadata-internals.h>
50 #include <mono/metadata/marshal.h>
51 #include <mono/metadata/gc-internal.h>
52 #include <mono/metadata/monitor.h>
53 #include <mono/metadata/threads-types.h>
54 #include <mono/utils/mono-logger.h>
55 #include <mono/utils/mono-mmap.h>
56 #include "mono/utils/mono-compiler.h"
57 #include <mono/utils/mono-counters.h>
65 #define SHARED_EXT ".dll"
66 #elif ((defined(__ppc__) || defined(__powerpc__) || defined(__ppc64__)) || defined(__MACH__)) && !defined(__linux__)
67 #define SHARED_EXT ".dylib"
69 #define SHARED_EXT ".so"
72 #define ALIGN_PTR_TO(ptr,align) (gpointer)((((gssize)(ptr)) + (align - 1)) & (~(align - 1)))
73 #define ROUND_DOWN(VALUE,SIZE) ((VALUE) & ~((SIZE) - 1))
75 typedef struct MonoAotModule
{
77 /* Pointer to the Global Offset Table */
79 GHashTable
*name_cache
;
80 GHashTable
*extra_methods
;
81 /* Maps methods to their code */
82 GHashTable
*method_to_code
;
83 /* Maps pointers into the method info to the methods themselves */
84 GHashTable
*method_ref_to_method
;
85 MonoAssemblyName
*image_names
;
87 MonoAssembly
*assembly
;
88 MonoImage
**image_table
;
89 guint32 image_table_len
;
100 /* This contains <offset, index> pairs sorted by offset */
101 /* This is needed because LLVM emitted methods can be in any order */
102 gint32
*sorted_code_offsets
;
103 guint32
*method_info_offsets
;
104 guint32
*got_info_offsets
;
105 guint32
*ex_info_offsets
;
106 guint32
*class_info_offsets
;
107 guint32
*methods_loaded
;
108 guint16
*class_name_table
;
109 guint32
*extra_method_table
;
110 guint32
*extra_method_info_offsets
;
113 /* Points to the GNU .eh_frame_hdr section, if it exists */
114 guint8
*eh_frame_hdr
;
116 /* Points to the .ARM.exidx section, if it exists */
118 guint32 arm_exidx_size
;
120 /* Points to the trampolines */
121 guint8
*trampolines
[MONO_AOT_TRAMP_NUM
];
122 /* The first unused trampoline of each kind */
123 guint32 trampoline_index
[MONO_AOT_TRAMP_NUM
];
125 MonoAotFileInfo info
;
131 static GHashTable
*aot_modules
;
132 #define mono_aot_lock() EnterCriticalSection (&aot_mutex)
133 #define mono_aot_unlock() LeaveCriticalSection (&aot_mutex)
134 static CRITICAL_SECTION aot_mutex
;
137 * Maps assembly names to the mono_aot_module_<NAME>_info symbols in the
138 * AOT modules registered by mono_aot_register_module ().
140 static GHashTable
*static_aot_modules
;
143 * Maps MonoJitInfo* to the aot module they belong to, this can be different
144 * from ji->method->klass->image's aot module for generic instances.
146 static GHashTable
*ji_to_amodule
;
149 * Whenever to AOT compile loaded assemblies on demand and store them in
150 * a cache under $HOME/.mono/aot-cache.
152 static gboolean use_aot_cache
= FALSE
;
155 * Whenever to spawn a new process to AOT a file or do it in-process. Only relevant if
156 * use_aot_cache is TRUE.
158 static gboolean spawn_compiler
= TRUE
;
161 static gint32 mono_last_aot_method
= -1;
163 static gboolean make_unreadable
= FALSE
;
164 static guint32 name_table_accesses
= 0;
166 /* Used to speed-up find_aot_module () */
167 static gsize aot_code_low_addr
= (gssize
)-1;
168 static gsize aot_code_high_addr
= 0;
171 init_plt (MonoAotModule
*info
);
173 /*****************************************************/
175 /*****************************************************/
180 * Load one of the images referenced by AMODULE. Returns NULL if the image is not
181 * found, and sets the loader error if SET_ERROR is TRUE.
184 load_image (MonoAotModule
*amodule
, int index
, gboolean set_error
)
186 MonoAssembly
*assembly
;
187 MonoImageOpenStatus status
;
189 g_assert (index
< amodule
->image_table_len
);
191 if (amodule
->image_table
[index
])
192 return amodule
->image_table
[index
];
193 if (amodule
->out_of_date
)
196 assembly
= mono_assembly_load (&amodule
->image_names
[index
], NULL
, &status
);
198 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_AOT
, "AOT module %s is unusable because dependency %s is not found.\n", amodule
->aot_name
, amodule
->image_names
[index
].name
);
199 amodule
->out_of_date
= TRUE
;
202 char *full_name
= mono_stringify_assembly_name (&amodule
->image_names
[index
]);
203 mono_loader_set_error_assembly_load (full_name
, FALSE
);
209 if (strcmp (assembly
->image
->guid
, amodule
->image_guids
[index
])) {
210 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_AOT
, "AOT module %s is out of date (Older than dependency %s).\n", amodule
->aot_name
, amodule
->image_names
[index
].name
);
211 amodule
->out_of_date
= TRUE
;
215 amodule
->image_table
[index
] = assembly
->image
;
216 return assembly
->image
;
220 decode_value (guint8
*ptr
, guint8
**rptr
)
225 if ((b
& 0x80) == 0){
228 } else if ((b
& 0x40) == 0){
229 len
= ((b
& 0x3f) << 8 | ptr
[1]);
231 } else if (b
!= 0xff) {
232 len
= ((b
& 0x1f) << 24) |
239 len
= (ptr
[1] << 24) | (ptr
[2] << 16) | (ptr
[3] << 8) | ptr
[4];
245 //printf ("DECODE: %d.\n", len);
250 * mono_aot_get_method:
252 * Decode an offset table emitted by emit_offset_table (), returning the INDEXth
256 mono_aot_get_offset (guint32
*table
, int index
)
258 int i
, group
, ngroups
, index_entry_size
;
259 int start_offset
, offset
, noffsets
, group_size
;
260 guint8
*data_start
, *p
;
261 guint32
*index32
= NULL
;
262 guint16
*index16
= NULL
;
264 noffsets
= table
[0];
265 group_size
= table
[1];
267 index_entry_size
= table
[3];
268 group
= index
/ group_size
;
270 if (index_entry_size
== 2) {
271 index16
= (guint16
*)&table
[4];
272 data_start
= (guint8
*)&index16
[ngroups
];
273 p
= data_start
+ index16
[group
];
275 index32
= (guint32
*)&table
[4];
276 data_start
= (guint8
*)&index32
[ngroups
];
277 p
= data_start
+ index32
[group
];
280 /* offset will contain the value of offsets [group * group_size] */
281 offset
= start_offset
= decode_value (p
, &p
);
282 for (i
= group
* group_size
+ 1; i
<= index
; ++i
) {
283 offset
+= decode_value (p
, &p
);
286 //printf ("Offset lookup: %d -> %d, start=%d, p=%d\n", index, offset, start_offset, table [3 + group]);
292 decode_method_ref_2 (MonoAotModule
*module
, guint8
*buf
, guint8
**endbuf
);
295 decode_klass_ref (MonoAotModule
*module
, guint8
*buf
, guint8
**endbuf
);
297 static MonoGenericInst
*
298 decode_generic_inst (MonoAotModule
*module
, guint8
*buf
, guint8
**endbuf
)
301 MonoType
**type_argv
;
302 MonoGenericInst
*inst
;
305 type_argc
= decode_value (p
, &p
);
306 type_argv
= g_new0 (MonoType
*, type_argc
);
308 for (i
= 0; i
< type_argc
; ++i
) {
309 MonoClass
*pclass
= decode_klass_ref (module
, p
, &p
);
314 type_argv
[i
] = &pclass
->byval_arg
;
317 inst
= mono_metadata_get_generic_inst (type_argc
, type_argv
);
326 decode_generic_context (MonoAotModule
*module
, MonoGenericContext
*ctx
, guint8
*buf
, guint8
**endbuf
)
328 gboolean has_class_inst
, has_method_inst
;
331 has_class_inst
= decode_value (p
, &p
);
332 if (has_class_inst
) {
333 ctx
->class_inst
= decode_generic_inst (module
, p
, &p
);
334 if (!ctx
->class_inst
)
337 has_method_inst
= decode_value (p
, &p
);
338 if (has_method_inst
) {
339 ctx
->method_inst
= decode_generic_inst (module
, p
, &p
);
340 if (!ctx
->method_inst
)
349 decode_klass_ref (MonoAotModule
*module
, guint8
*buf
, guint8
**endbuf
)
352 MonoClass
*klass
, *eklass
;
356 token
= decode_value (p
, &p
);
361 if (mono_metadata_token_table (token
) == 0) {
362 image
= load_image (module
, decode_value (p
, &p
), TRUE
);
365 klass
= mono_class_get (image
, MONO_TOKEN_TYPE_DEF
+ token
);
366 } else if (mono_metadata_token_table (token
) == MONO_TABLE_TYPESPEC
) {
367 if (token
== MONO_TOKEN_TYPE_SPEC
) {
368 MonoTypeEnum type
= decode_value (p
, &p
);
370 if (type
== MONO_TYPE_GENERICINST
) {
372 MonoGenericContext ctx
;
375 gclass
= decode_klass_ref (module
, p
, &p
);
378 g_assert (gclass
->generic_container
);
380 memset (&ctx
, 0, sizeof (ctx
));
381 ctx
.class_inst
= decode_generic_inst (module
, p
, &p
);
384 type
= mono_class_inflate_generic_type (&gclass
->byval_arg
, &ctx
);
385 klass
= mono_class_from_mono_type (type
);
386 mono_metadata_free_type (type
);
387 } else if ((type
== MONO_TYPE_VAR
) || (type
== MONO_TYPE_MVAR
)) {
389 MonoGenericContainer
*container
;
391 int num
= decode_value (p
, &p
);
392 gboolean is_method
= decode_value (p
, &p
);
395 MonoMethod
*method_def
;
396 g_assert (type
== MONO_TYPE_MVAR
);
397 method_def
= decode_method_ref_2 (module
, p
, &p
);
401 container
= mono_method_get_generic_container (method_def
);
403 MonoClass
*class_def
;
404 g_assert (type
== MONO_TYPE_VAR
);
405 class_def
= decode_klass_ref (module
, p
, &p
);
409 container
= class_def
->generic_container
;
412 g_assert (container
);
414 // FIXME: Memory management
415 t
= g_new0 (MonoType
, 1);
417 t
->data
.generic_param
= mono_generic_container_get_param (container
, num
);
419 // FIXME: Maybe use types directly to avoid
420 // the overhead of creating MonoClass-es
421 klass
= mono_class_from_mono_type (t
);
425 g_assert_not_reached ();
428 image
= load_image (module
, decode_value (p
, &p
), TRUE
);
431 klass
= mono_class_get (image
, token
);
433 } else if (token
== MONO_TOKEN_TYPE_DEF
) {
435 image
= load_image (module
, decode_value (p
, &p
), TRUE
);
438 rank
= decode_value (p
, &p
);
439 eklass
= decode_klass_ref (module
, p
, &p
);
440 klass
= mono_array_class_get (eklass
, rank
);
442 g_assert_not_reached ();
450 static MonoClassField
*
451 decode_field_info (MonoAotModule
*module
, guint8
*buf
, guint8
**endbuf
)
453 MonoClass
*klass
= decode_klass_ref (module
, buf
, &buf
);
460 token
= MONO_TOKEN_FIELD_DEF
+ decode_value (p
, &p
);
464 return mono_class_get_field (klass
, token
);
468 * can_method_ref_match_method:
470 * Determine if calling decode_method_ref_2 on P could return the same method as
471 * METHOD. This is an optimization to avoid calling decode_method_ref_2 () which
472 * would create MonoMethods which are not needed etc.
475 can_method_ref_match_method (MonoAotModule
*module
, guint8
*buf
, MonoMethod
*method
)
478 guint32 image_index
, value
;
480 /* Keep this in sync with decode_method_ref () */
481 value
= decode_value (p
, &p
);
482 image_index
= value
>> 24;
484 if (image_index
== MONO_AOT_METHODREF_WRAPPER
) {
485 guint32 wrapper_type
;
487 if (!method
->wrapper_type
)
490 wrapper_type
= decode_value (p
, &p
);
492 if (method
->wrapper_type
!= wrapper_type
)
494 } else if (image_index
== MONO_AOT_METHODREF_WRAPPER_NAME
) {
496 } else if (image_index
< MONO_AOT_METHODREF_MIN
|| image_index
== MONO_AOT_METHODREF_METHODSPEC
|| image_index
== MONO_AOT_METHODREF_GINST
) {
497 if (method
->wrapper_type
)
507 * Decode a method reference, and return its image and token. This avoids loading
508 * metadata for the method if the caller does not need it. If the method has no token,
509 * then it is loaded from metadata and METHOD is set to the method instance.
512 decode_method_ref (MonoAotModule
*module
, guint32
*token
, MonoMethod
**method
, gboolean
*no_aot_trampoline
, guint8
*buf
, guint8
**endbuf
)
514 guint32 image_index
, value
;
515 MonoImage
*image
= NULL
;
520 if (no_aot_trampoline
)
521 *no_aot_trampoline
= FALSE
;
523 value
= decode_value (p
, &p
);
524 image_index
= value
>> 24;
526 if (image_index
== MONO_AOT_METHODREF_NO_AOT_TRAMPOLINE
) {
527 if (no_aot_trampoline
)
528 *no_aot_trampoline
= TRUE
;
529 value
= decode_value (p
, &p
);
530 image_index
= value
>> 24;
533 if (image_index
== MONO_AOT_METHODREF_WRAPPER
) {
534 guint32 wrapper_type
;
536 wrapper_type
= decode_value (p
, &p
);
539 image
= mono_defaults
.corlib
;
541 switch (wrapper_type
) {
542 case MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK
: {
543 MonoMethod
*m
= decode_method_ref_2 (module
, p
, &p
);
547 mono_class_init (m
->klass
);
548 *method
= mono_marshal_get_remoting_invoke_with_check (m
);
551 case MONO_WRAPPER_PROXY_ISINST
: {
552 MonoClass
*klass
= decode_klass_ref (module
, p
, &p
);
555 *method
= mono_marshal_get_proxy_cancast (klass
);
558 case MONO_WRAPPER_LDFLD
:
559 case MONO_WRAPPER_LDFLDA
:
560 case MONO_WRAPPER_STFLD
:
561 case MONO_WRAPPER_ISINST
: {
562 MonoClass
*klass
= decode_klass_ref (module
, p
, &p
);
565 if (wrapper_type
== MONO_WRAPPER_LDFLD
)
566 *method
= mono_marshal_get_ldfld_wrapper (&klass
->byval_arg
);
567 else if (wrapper_type
== MONO_WRAPPER_LDFLDA
)
568 *method
= mono_marshal_get_ldflda_wrapper (&klass
->byval_arg
);
569 else if (wrapper_type
== MONO_WRAPPER_STFLD
)
570 *method
= mono_marshal_get_stfld_wrapper (&klass
->byval_arg
);
571 else if (wrapper_type
== MONO_WRAPPER_ISINST
)
572 *method
= mono_marshal_get_isinst (klass
);
574 g_assert_not_reached ();
577 case MONO_WRAPPER_LDFLD_REMOTE
:
578 *method
= mono_marshal_get_ldfld_remote_wrapper (NULL
);
580 case MONO_WRAPPER_STFLD_REMOTE
:
581 *method
= mono_marshal_get_stfld_remote_wrapper (NULL
);
583 case MONO_WRAPPER_ALLOC
: {
584 int atype
= decode_value (p
, &p
);
586 *method
= mono_gc_get_managed_allocator_by_type (atype
);
589 case MONO_WRAPPER_STELEMREF
:
590 *method
= mono_marshal_get_stelemref ();
592 case MONO_WRAPPER_SYNCHRONIZED
: {
593 MonoMethod
*m
= decode_method_ref_2 (module
, p
, &p
);
597 *method
= mono_marshal_get_synchronized_wrapper (m
);
600 case MONO_WRAPPER_UNKNOWN
: {
601 MonoMethodDesc
*desc
;
602 MonoMethod
*orig_method
;
603 int subtype
= decode_value (p
, &p
);
605 if (subtype
== MONO_AOT_WRAPPER_MONO_ENTER
)
606 desc
= mono_method_desc_new ("Monitor:Enter", FALSE
);
607 else if (subtype
== MONO_AOT_WRAPPER_MONO_EXIT
)
608 desc
= mono_method_desc_new ("Monitor:Exit", FALSE
);
610 g_assert_not_reached ();
611 orig_method
= mono_method_desc_search_in_class (desc
, mono_defaults
.monitor_class
);
612 g_assert (orig_method
);
613 mono_method_desc_free (desc
);
614 *method
= mono_monitor_get_fast_path (orig_method
);
617 case MONO_WRAPPER_RUNTIME_INVOKE
: {
619 MonoMethod
*m
= decode_method_ref_2 (module
, p
, &p
);
623 *method
= mono_marshal_get_runtime_invoke (m
, FALSE
);
627 g_assert_not_reached ();
629 } else if (image_index
== MONO_AOT_METHODREF_WRAPPER_NAME
) {
630 /* Can't decode these */
631 g_assert_not_reached ();
632 } else if (image_index
== MONO_AOT_METHODREF_METHODSPEC
) {
633 image_index
= decode_value (p
, &p
);
634 *token
= decode_value (p
, &p
);
636 image
= load_image (module
, image_index
, TRUE
);
639 } else if (image_index
== MONO_AOT_METHODREF_GINST
) {
641 MonoGenericContext ctx
;
644 * These methods do not have a token which resolves them, so we
645 * resolve them immediately.
647 klass
= decode_klass_ref (module
, p
, &p
);
651 image_index
= decode_value (p
, &p
);
652 *token
= decode_value (p
, &p
);
654 image
= load_image (module
, image_index
, TRUE
);
658 *method
= mono_get_method_full (image
, *token
, NULL
, NULL
);
662 memset (&ctx
, 0, sizeof (ctx
));
664 if (FALSE
&& klass
->generic_class
) {
665 ctx
.class_inst
= klass
->generic_class
->context
.class_inst
;
666 ctx
.method_inst
= NULL
;
668 *method
= mono_class_inflate_generic_method_full (*method
, klass
, &ctx
);
671 memset (&ctx
, 0, sizeof (ctx
));
673 if (!decode_generic_context (module
, &ctx
, p
, &p
))
676 *method
= mono_class_inflate_generic_method_full (*method
, klass
, &ctx
);
677 } else if (image_index
== MONO_AOT_METHODREF_ARRAY
) {
681 klass
= decode_klass_ref (module
, p
, &p
);
684 method_type
= decode_value (p
, &p
);
686 switch (method_type
) {
688 *method
= mono_class_get_method_from_name (klass
, ".ctor", klass
->rank
);
691 *method
= mono_class_get_method_from_name (klass
, ".ctor", klass
->rank
* 2);
694 *method
= mono_class_get_method_from_name (klass
, "Get", -1);
697 *method
= mono_class_get_method_from_name (klass
, "Address", -1);
700 *method
= mono_class_get_method_from_name (klass
, "Set", -1);
703 g_assert_not_reached ();
706 g_assert (image_index
< MONO_AOT_METHODREF_MIN
);
707 *token
= MONO_TOKEN_METHOD_DEF
| (value
& 0xffffff);
709 image
= load_image (module
, image_index
, TRUE
);
720 * decode_method_ref_2:
722 * Similar to decode_method_ref, but resolve and return the method itself.
725 decode_method_ref_2 (MonoAotModule
*module
, guint8
*buf
, guint8
**endbuf
)
729 MonoImage
*image
= decode_method_ref (module
, &token
, &method
, NULL
, buf
, endbuf
);
735 method
= mono_get_method (image
, token
, NULL
);
741 make_writable (guint8
* addr
, guint32 len
)
747 g_error ("Attempt to make AOT memory writable while running in aot-only mode.\n");
749 page_start
= (guint8
*) (((gssize
) (addr
)) & ~ (mono_pagesize () - 1));
750 pages
= (addr
+ len
- page_start
+ mono_pagesize () - 1) / mono_pagesize ();
752 err
= mono_mprotect (page_start
, pages
* mono_pagesize (), MONO_MMAP_READ
| MONO_MMAP_WRITE
| MONO_MMAP_EXEC
);
757 create_cache_structure (void)
763 home
= g_get_home_dir ();
767 tmp
= g_build_filename (home
, ".mono", NULL
);
768 if (!g_file_test (tmp
, G_FILE_TEST_IS_DIR
)) {
769 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_AOT
, "AOT creating directory %s", tmp
);
773 err
= mkdir (tmp
, 0777);
776 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_AOT
, "AOT failed: %s", g_strerror (errno
));
782 tmp
= g_build_filename (home
, ".mono", "aot-cache", NULL
);
783 if (!g_file_test (tmp
, G_FILE_TEST_IS_DIR
)) {
784 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_AOT
, "AOT creating directory %s", tmp
);
788 err
= mkdir (tmp
, 0777);
791 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_AOT
, "AOT failed: %s", g_strerror (errno
));
800 * load_aot_module_from_cache:
802 * Experimental code to AOT compile loaded assemblies on demand.
805 * - Add environment variable MONO_AOT_CACHE_OPTIONS
806 * - Add options for controlling the cache size
807 * - Handle full cache by deleting old assemblies lru style
808 * - Add options for excluding assemblies during development
809 * - Maybe add a threshold after an assembly is AOT compiled
810 * - invoking a new mono process is a security risk
811 * - recompile the AOT module if one of its dependencies changes
814 load_aot_module_from_cache (MonoAssembly
*assembly
, char **aot_name
)
816 char *fname
, *cmd
, *tmp2
, *aot_options
;
825 if (assembly
->image
->dynamic
)
828 create_cache_structure ();
830 home
= g_get_home_dir ();
832 tmp2
= g_strdup_printf ("%s-%s%s", assembly
->image
->assembly_name
, assembly
->image
->guid
, SHARED_EXT
);
833 fname
= g_build_filename (home
, ".mono", "aot-cache", tmp2
, NULL
);
837 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_AOT
, "AOT trying to load from cache: '%s'.", fname
);
838 module
= mono_dl_open (fname
, MONO_DL_LAZY
, NULL
);
841 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_AOT
, "AOT not found.");
843 mono_trace (G_LOG_LEVEL_MESSAGE
, MONO_TRACE_AOT
, "AOT precompiling assembly '%s'... ", assembly
->image
->name
);
845 aot_options
= g_strdup_printf ("outfile=%s", fname
);
847 if (spawn_compiler
) {
848 /* FIXME: security */
849 /* FIXME: Has to pass the assembly loading path to the child process */
850 cmd
= g_strdup_printf ("mono -O=all --aot=%s %s", aot_options
, assembly
->image
->name
);
852 res
= g_spawn_command_line_sync (cmd
, &out
, &err
, &exit_status
, NULL
);
854 #if !defined(HOST_WIN32) && !defined(__ppc__) && !defined(__ppc64__) && !defined(__powerpc__)
856 if (!WIFEXITED (exit_status
) && (WEXITSTATUS (exit_status
) == 0))
857 mono_trace (G_LOG_LEVEL_MESSAGE
, MONO_TRACE_AOT
, "AOT failed: %s.", err
);
859 mono_trace (G_LOG_LEVEL_MESSAGE
, MONO_TRACE_AOT
, "AOT succeeded.");
866 res
= mono_compile_assembly (assembly
, mono_parse_default_optimizations (NULL
), aot_options
);
868 mono_trace (G_LOG_LEVEL_MESSAGE
, MONO_TRACE_AOT
, "AOT failed.");
870 mono_trace (G_LOG_LEVEL_MESSAGE
, MONO_TRACE_AOT
, "AOT succeeded.");
874 module
= mono_dl_open (fname
, MONO_DL_LAZY
, NULL
);
876 g_free (aot_options
);
883 find_symbol (MonoDl
*module
, gpointer
*globals
, const char *name
, gpointer
*value
)
887 guint16
*table
, *entry
;
891 /* The first entry points to the hash */
895 table_size
= table
[0];
898 hash
= mono_metadata_str_hash (name
) % table_size
;
900 entry
= &table
[hash
* 2];
902 /* Search the hash for the index into the globals table */
904 while (entry
[0] != 0) {
905 guint32 index
= entry
[0] - 1;
906 guint32 next
= entry
[1];
908 //printf ("X: %s %s\n", (char*)globals [index * 2], name);
910 if (!strcmp (globals
[index
* 2], name
)) {
911 global_index
= index
;
916 entry
= &table
[next
* 2];
922 if (global_index
!= -1)
923 *value
= globals
[global_index
* 2 + 1];
927 mono_dl_symbol (module
, name
, value
);
931 #ifndef SHT_ARM_EXIDX
932 #define SHT_ARM_EXIDX 0x70000001
935 #ifdef HAVE_DL_ITERATE_PHDR
937 dl_callback (struct dl_phdr_info
*info
, size_t size
, void *data
)
940 MonoAotModule
*amodule
= data
;
942 if (!strcmp (amodule
->aot_name
, info
->dlpi_name
)) {
943 for (j
= 0; j
< info
->dlpi_phnum
; j
++) {
944 if (info
->dlpi_phdr
[j
].p_type
== PT_GNU_EH_FRAME
)
945 amodule
->eh_frame_hdr
= (guint8
*)(info
->dlpi_addr
+ info
->dlpi_phdr
[j
].p_vaddr
);
946 if (info
->dlpi_phdr
[j
].p_type
== SHT_ARM_EXIDX
) {
947 amodule
->arm_exidx
= (guint8
*)(info
->dlpi_addr
+ info
->dlpi_phdr
[j
].p_vaddr
);
948 amodule
->arm_exidx_size
= info
->dlpi_phdr
[j
].p_filesz
;
959 load_aot_module (MonoAssembly
*assembly
, gpointer user_data
)
962 MonoAotModule
*amodule
;
964 gboolean usable
= TRUE
;
965 char *saved_guid
= NULL
;
966 char *aot_version
= NULL
;
967 char *runtime_version
, *build_info
;
968 char *opt_flags
= NULL
;
970 gboolean full_aot
= FALSE
;
971 MonoAotFileInfo
*file_info
= NULL
;
975 if (mono_compile_aot
)
978 if (assembly
->image
->aot_module
)
980 * Already loaded. This can happen because the assembly loading code might invoke
981 * the assembly load hooks multiple times for the same assembly.
985 if (assembly
->image
->dynamic
)
988 if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS
)
992 if (static_aot_modules
)
993 globals
= g_hash_table_lookup (static_aot_modules
, assembly
->aname
.name
);
999 /* Statically linked AOT module */
1001 aot_name
= g_strdup_printf ("%s", assembly
->aname
.name
);
1002 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_AOT
, "Found statically linked AOT module '%s'.\n", aot_name
);
1005 sofile
= load_aot_module_from_cache (assembly
, &aot_name
);
1008 aot_name
= g_strdup_printf ("%s%s", assembly
->image
->name
, SHARED_EXT
);
1010 sofile
= mono_dl_open (aot_name
, MONO_DL_LAZY
, &err
);
1013 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_AOT
, "AOT failed to load AOT module %s: %s\n", aot_name
, err
);
1019 if (!sofile
&& !globals
) {
1020 if (mono_aot_only
) {
1021 fprintf (stderr
, "Failed to load AOT module '%s' in aot-only mode.\n", aot_name
);
1028 find_symbol (sofile
, globals
, "mono_assembly_guid", (gpointer
*) &saved_guid
);
1029 find_symbol (sofile
, globals
, "mono_aot_version", (gpointer
*) &aot_version
);
1030 find_symbol (sofile
, globals
, "mono_aot_opt_flags", (gpointer
*)&opt_flags
);
1031 find_symbol (sofile
, globals
, "mono_runtime_version", (gpointer
*)&runtime_version
);
1032 find_symbol (sofile
, globals
, "mono_aot_got_addr", (gpointer
*)&got_addr
);
1034 if (!aot_version
|| strcmp (aot_version
, MONO_AOT_FILE_VERSION
)) {
1035 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_AOT
, "AOT module %s has wrong file format version (expected %s got %s)\n", aot_name
, MONO_AOT_FILE_VERSION
, aot_version
);
1039 if (!saved_guid
|| strcmp (assembly
->image
->guid
, saved_guid
)) {
1040 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_AOT
, "AOT module %s is out of date.\n", aot_name
);
1045 build_info
= mono_get_runtime_build_info ();
1046 if (!runtime_version
|| ((strlen (runtime_version
) > 0 && strcmp (runtime_version
, build_info
)))) {
1047 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_AOT
, "AOT module %s is compiled against runtime version '%s' while this runtime has version '%s'.\n", aot_name
, runtime_version
, build_info
);
1050 g_free (build_info
);
1052 find_symbol (sofile
, globals
, "mono_aot_file_info", (gpointer
*)&file_info
);
1053 g_assert (file_info
);
1055 full_aot
= ((MonoAotFileInfo
*)file_info
)->flags
& MONO_AOT_FILE_FLAG_FULL_AOT
;
1057 if (mono_aot_only
&& !full_aot
) {
1058 fprintf (stderr
, "Can't use AOT image '%s' in aot-only mode because it is not compiled with --aot=full.\n", aot_name
);
1061 if (!mono_aot_only
&& full_aot
) {
1062 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_AOT
, "AOT module %s is compiled with --aot=full.\n", aot_name
);
1066 if ((((MonoAotFileInfo
*)file_info
)->flags
& MONO_AOT_FILE_FLAG_WITH_LLVM
) && !mono_use_llvm
) {
1067 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_AOT
, "AOT module %s is compiled with LLVM.\n", aot_name
);
1072 if (mono_aot_only
) {
1073 fprintf (stderr
, "Failed to load AOT module '%s' while running in aot-only mode.\n", aot_name
);
1078 mono_dl_close (sofile
);
1079 assembly
->image
->aot_module
= NULL
;
1083 amodule
= g_new0 (MonoAotModule
, 1);
1084 amodule
->aot_name
= aot_name
;
1085 amodule
->assembly
= assembly
;
1087 memcpy (&amodule
->info
, file_info
, sizeof (*file_info
));
1089 amodule
->got
= *got_addr
;
1090 amodule
->got
[0] = assembly
->image
;
1091 amodule
->globals
= globals
;
1092 amodule
->sofile
= sofile
;
1093 amodule
->method_to_code
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
1095 /* Read image table */
1097 guint32 table_len
, i
;
1100 find_symbol (sofile
, globals
, "mono_image_table", (gpointer
*)&table
);
1103 table_len
= *(guint32
*)table
;
1104 table
+= sizeof (guint32
);
1105 amodule
->image_table
= g_new0 (MonoImage
*, table_len
);
1106 amodule
->image_names
= g_new0 (MonoAssemblyName
, table_len
);
1107 amodule
->image_guids
= g_new0 (char*, table_len
);
1108 amodule
->image_table_len
= table_len
;
1109 for (i
= 0; i
< table_len
; ++i
) {
1110 MonoAssemblyName
*aname
= &(amodule
->image_names
[i
]);
1112 aname
->name
= g_strdup (table
);
1113 table
+= strlen (table
) + 1;
1114 amodule
->image_guids
[i
] = g_strdup (table
);
1115 table
+= strlen (table
) + 1;
1117 aname
->culture
= g_strdup (table
);
1118 table
+= strlen (table
) + 1;
1119 memcpy (aname
->public_key_token
, table
, strlen (table
) + 1);
1120 table
+= strlen (table
) + 1;
1122 table
= ALIGN_PTR_TO (table
, 8);
1123 aname
->flags
= *(guint32
*)table
;
1125 aname
->major
= *(guint32
*)table
;
1127 aname
->minor
= *(guint32
*)table
;
1129 aname
->build
= *(guint32
*)table
;
1131 aname
->revision
= *(guint32
*)table
;
1136 /* Read method and method_info tables */
1137 find_symbol (sofile
, globals
, "code_offsets", (gpointer
*)&amodule
->code_offsets
);
1138 find_symbol (sofile
, globals
, "methods", (gpointer
*)&amodule
->code
);
1139 find_symbol (sofile
, globals
, "methods_end", (gpointer
*)&amodule
->code_end
);
1140 find_symbol (sofile
, globals
, "method_info_offsets", (gpointer
*)&amodule
->method_info_offsets
);
1141 find_symbol (sofile
, globals
, "ex_info_offsets", (gpointer
*)&amodule
->ex_info_offsets
);
1142 find_symbol (sofile
, globals
, "blob", (gpointer
*)&amodule
->blob
);
1143 find_symbol (sofile
, globals
, "class_info_offsets", (gpointer
*)&amodule
->class_info_offsets
);
1144 find_symbol (sofile
, globals
, "class_name_table", (gpointer
*)&amodule
->class_name_table
);
1145 find_symbol (sofile
, globals
, "extra_method_table", (gpointer
*)&amodule
->extra_method_table
);
1146 find_symbol (sofile
, globals
, "extra_method_info_offsets", (gpointer
*)&amodule
->extra_method_info_offsets
);
1147 find_symbol (sofile
, globals
, "got_info_offsets", (gpointer
*)&amodule
->got_info_offsets
);
1148 find_symbol (sofile
, globals
, "specific_trampolines", (gpointer
*)&(amodule
->trampolines
[MONO_AOT_TRAMP_SPECIFIC
]));
1149 find_symbol (sofile
, globals
, "static_rgctx_trampolines", (gpointer
*)&(amodule
->trampolines
[MONO_AOT_TRAMP_STATIC_RGCTX
]));
1150 find_symbol (sofile
, globals
, "imt_thunks", (gpointer
*)&(amodule
->trampolines
[MONO_AOT_TRAMP_IMT_THUNK
]));
1151 find_symbol (sofile
, globals
, "unwind_info", (gpointer
)&amodule
->unwind_info
);
1152 find_symbol (sofile
, globals
, "mem_end", (gpointer
*)&amodule
->mem_end
);
1154 amodule
->mem_begin
= amodule
->code
;
1156 find_symbol (sofile
, globals
, "plt", (gpointer
*)&amodule
->plt
);
1157 find_symbol (sofile
, globals
, "plt_end", (gpointer
*)&amodule
->plt_end
);
1159 if (make_unreadable
) {
1160 #ifndef TARGET_WIN32
1163 int pages
, err
, len
;
1165 addr
= amodule
->mem_begin
;
1166 len
= amodule
->mem_end
- amodule
->mem_begin
;
1168 /* Round down in both directions to avoid modifying data which is not ours */
1169 page_start
= (guint8
*) (((gssize
) (addr
)) & ~ (mono_pagesize () - 1)) + mono_pagesize ();
1170 pages
= ((addr
+ len
- page_start
+ mono_pagesize () - 1) / mono_pagesize ()) - 1;
1171 err
= mono_mprotect (page_start
, pages
* mono_pagesize (), MONO_MMAP_NONE
);
1172 g_assert (err
== 0);
1178 aot_code_low_addr
= MIN (aot_code_low_addr
, (gsize
)amodule
->code
);
1179 aot_code_high_addr
= MAX (aot_code_high_addr
, (gsize
)amodule
->code_end
);
1181 g_hash_table_insert (aot_modules
, assembly
, amodule
);
1184 mono_jit_info_add_aot_module (assembly
->image
, amodule
->code
, amodule
->code_end
);
1186 assembly
->image
->aot_module
= amodule
;
1188 #ifdef HAVE_DL_ITERATE_PHDR
1189 /* Lookup the address of the .eh_frame_hdr () section if available */
1190 dl_iterate_phdr (dl_callback
, amodule
);
1193 if (mono_aot_only
) {
1194 if (mono_defaults
.corlib
) {
1195 /* The second got slot contains the mscorlib got addr */
1196 MonoAotModule
*mscorlib_amodule
= mono_defaults
.corlib
->aot_module
;
1198 amodule
->got
[1] = mscorlib_amodule
->got
;
1200 amodule
->got
[1] = amodule
->got
;
1205 * Since we store methoddef and classdef tokens when referring to methods/classes in
1206 * referenced assemblies, we depend on the exact versions of the referenced assemblies.
1207 * MS calls this 'hard binding'. This means we have to load all referenced assemblies
1208 * non-lazily, since we can't handle out-of-date errors later.
1209 * The cached class info also depends on the exact assemblies.
1211 for (i
= 0; i
< amodule
->image_table_len
; ++i
)
1212 load_image (amodule
, i
, FALSE
);
1214 if (amodule
->out_of_date
) {
1215 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_AOT
, "AOT Module %s is unusable because a dependency is out-of-date.\n", assembly
->image
->name
);
1216 if (mono_aot_only
) {
1217 fprintf (stderr
, "Failed to load AOT module '%s' while running in aot-only mode because a dependency cannot be found or it is out of date.\n", aot_name
);
1222 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_AOT
, "AOT loaded AOT Module for %s.\n", assembly
->image
->name
);
1226 * mono_aot_register_globals:
1228 * This is called by the ctor function in AOT images compiled with the
1229 * 'no-dlsym' option.
1232 mono_aot_register_globals (gpointer
*globals
)
1234 g_assert_not_reached ();
1238 * mono_aot_register_module:
1240 * This should be called by embedding code to register AOT modules statically linked
1241 * into the executable. AOT_INFO should be the value of the
1242 * 'mono_aot_module_<ASSEMBLY_NAME>_info' global symbol from the AOT module.
1245 mono_aot_register_module (gpointer
*aot_info
)
1253 /* Determine the assembly name */
1254 find_symbol (NULL
, globals
, "mono_aot_assembly_name", (gpointer
*)&aname
);
1257 /* This could be called before startup */
1261 if (!static_aot_modules
)
1262 static_aot_modules
= g_hash_table_new (g_str_hash
, g_str_equal
);
1264 g_hash_table_insert (static_aot_modules
, aname
, globals
);
1271 mono_aot_init (void)
1273 InitializeCriticalSection (&aot_mutex
);
1274 aot_modules
= g_hash_table_new (NULL
, NULL
);
1276 mono_install_assembly_load_hook (load_aot_module
, NULL
);
1278 if (g_getenv ("MONO_LASTAOT"))
1279 mono_last_aot_method
= atoi (g_getenv ("MONO_LASTAOT"));
1280 if (g_getenv ("MONO_AOT_CACHE"))
1281 use_aot_cache
= TRUE
;
1285 decode_cached_class_info (MonoAotModule
*module
, MonoCachedClassInfo
*info
, guint8
*buf
, guint8
**endbuf
)
1289 info
->vtable_size
= decode_value (buf
, &buf
);
1290 if (info
->vtable_size
== -1)
1293 flags
= decode_value (buf
, &buf
);
1294 info
->ghcimpl
= (flags
>> 0) & 0x1;
1295 info
->has_finalize
= (flags
>> 1) & 0x1;
1296 info
->has_cctor
= (flags
>> 2) & 0x1;
1297 info
->has_nested_classes
= (flags
>> 3) & 0x1;
1298 info
->blittable
= (flags
>> 4) & 0x1;
1299 info
->has_references
= (flags
>> 5) & 0x1;
1300 info
->has_static_refs
= (flags
>> 6) & 0x1;
1301 info
->no_special_static_fields
= (flags
>> 7) & 0x1;
1302 info
->is_generic_container
= (flags
>> 8) & 0x1;
1304 if (info
->has_cctor
) {
1305 MonoImage
*cctor_image
= decode_method_ref (module
, &info
->cctor_token
, NULL
, NULL
, buf
, &buf
);
1309 if (info
->has_finalize
) {
1310 info
->finalize_image
= decode_method_ref (module
, &info
->finalize_token
, NULL
, NULL
, buf
, &buf
);
1311 if (!info
->finalize_image
)
1315 info
->instance_size
= decode_value (buf
, &buf
);
1316 info
->class_size
= decode_value (buf
, &buf
);
1317 info
->packing_size
= decode_value (buf
, &buf
);
1318 info
->min_align
= decode_value (buf
, &buf
);
1326 mono_aot_get_method_from_vt_slot (MonoDomain
*domain
, MonoVTable
*vtable
, int slot
)
1329 MonoClass
*klass
= vtable
->klass
;
1330 MonoAotModule
*aot_module
= klass
->image
->aot_module
;
1332 MonoCachedClassInfo class_info
;
1336 gboolean no_aot_trampoline
;
1338 if (MONO_CLASS_IS_INTERFACE (klass
) || klass
->rank
|| !aot_module
)
1341 info
= &aot_module
->blob
[mono_aot_get_offset (aot_module
->class_info_offsets
, mono_metadata_token_index (klass
->type_token
) - 1)];
1344 err
= decode_cached_class_info (aot_module
, &class_info
, p
, &p
);
1348 for (i
= 0; i
< slot
; ++i
)
1349 decode_method_ref (aot_module
, &token
, NULL
, NULL
, p
, &p
);
1351 image
= decode_method_ref (aot_module
, &token
, NULL
, &no_aot_trampoline
, p
, &p
);
1354 if (no_aot_trampoline
)
1357 if (mono_metadata_token_index (token
) == 0)
1360 return mono_aot_get_method_from_token (domain
, image
, token
);
1364 mono_aot_get_cached_class_info (MonoClass
*klass
, MonoCachedClassInfo
*res
)
1366 MonoAotModule
*aot_module
= klass
->image
->aot_module
;
1370 if (klass
->rank
|| !aot_module
)
1373 p
= (guint8
*)&aot_module
->blob
[mono_aot_get_offset (aot_module
->class_info_offsets
, mono_metadata_token_index (klass
->type_token
) - 1)];
1375 err
= decode_cached_class_info (aot_module
, res
, p
, &p
);
1383 * mono_aot_get_class_from_name:
1385 * Obtains a MonoClass with a given namespace and a given name which is located in IMAGE,
1386 * using a cache stored in the AOT file.
1387 * Stores the resulting class in *KLASS if found, stores NULL otherwise.
1389 * Returns: TRUE if the klass was found/not found in the cache, FALSE if no aot file was
1393 mono_aot_get_class_from_name (MonoImage
*image
, const char *name_space
, const char *name
, MonoClass
**klass
)
1395 MonoAotModule
*aot_module
= image
->aot_module
;
1396 guint16
*table
, *entry
;
1399 char full_name_buf
[1024];
1401 const char *name2
, *name_space2
;
1403 guint32 cols
[MONO_TYPEDEF_SIZE
];
1404 GHashTable
*nspace_table
;
1406 if (!aot_module
|| !aot_module
->class_name_table
)
1413 /* First look in the cache */
1414 if (!aot_module
->name_cache
)
1415 aot_module
->name_cache
= g_hash_table_new (g_str_hash
, g_str_equal
);
1416 nspace_table
= g_hash_table_lookup (aot_module
->name_cache
, name_space
);
1418 *klass
= g_hash_table_lookup (nspace_table
, name
);
1425 table_size
= aot_module
->class_name_table
[0];
1426 table
= aot_module
->class_name_table
+ 1;
1428 if (name_space
[0] == '\0')
1429 full_name
= g_strdup_printf ("%s", name
);
1431 if (strlen (name_space
) + strlen (name
) < 1000) {
1432 sprintf (full_name_buf
, "%s.%s", name_space
, name
);
1433 full_name
= full_name_buf
;
1435 full_name
= g_strdup_printf ("%s.%s", name_space
, name
);
1438 hash
= mono_metadata_str_hash (full_name
) % table_size
;
1439 if (full_name
!= full_name_buf
)
1442 entry
= &table
[hash
* 2];
1444 if (entry
[0] != 0) {
1445 t
= &image
->tables
[MONO_TABLE_TYPEDEF
];
1448 guint32 index
= entry
[0];
1449 guint32 next
= entry
[1];
1450 guint32 token
= mono_metadata_make_token (MONO_TABLE_TYPEDEF
, index
);
1452 name_table_accesses
++;
1454 mono_metadata_decode_row (t
, index
- 1, cols
, MONO_TYPEDEF_SIZE
);
1456 name2
= mono_metadata_string_heap (image
, cols
[MONO_TYPEDEF_NAME
]);
1457 name_space2
= mono_metadata_string_heap (image
, cols
[MONO_TYPEDEF_NAMESPACE
]);
1459 if (!strcmp (name
, name2
) && !strcmp (name_space
, name_space2
)) {
1461 *klass
= mono_class_get (image
, token
);
1466 nspace_table
= g_hash_table_lookup (aot_module
->name_cache
, name_space
);
1467 if (!nspace_table
) {
1468 nspace_table
= g_hash_table_new (g_str_hash
, g_str_equal
);
1469 g_hash_table_insert (aot_module
->name_cache
, (char*)name_space2
, nspace_table
);
1471 g_hash_table_insert (nspace_table
, (char*)name2
, *klass
);
1478 entry
= &table
[next
* 2];
1490 #define DW_EH_PE_omit 0xff
1491 #define DW_EH_PE_uleb128 0x01
1492 #define DW_EH_PE_udata2 0x02
1493 #define DW_EH_PE_udata4 0x03
1494 #define DW_EH_PE_udata8 0x04
1495 #define DW_EH_PE_sleb128 0x09
1496 #define DW_EH_PE_sdata2 0x0A
1497 #define DW_EH_PE_sdata4 0x0B
1498 #define DW_EH_PE_sdata8 0x0C
1500 #define DW_EH_PE_absptr 0x00
1501 #define DW_EH_PE_pcrel 0x10
1502 #define DW_EH_PE_datarel 0x30
1503 #define DW_EH_PE_omit 0xff
1508 guint8 eh_frame_ptr_enc
;
1509 guint8 fde_count_enc
;
1517 * Decode the exception handling information in the .eh_frame section of the AOT
1518 * file belong to CODE, and construct a MonoJitInfo structure from it.
1519 * LOCKING: Acquires the domain lock.
1521 static G_GNUC_UNUSED
void
1522 decode_eh_frame (MonoAotModule
*amodule
, MonoDomain
*domain
,
1523 MonoMethod
*method
, guint8
*code
, MonoJitInfo
*jinfo
)
1527 guint8
*eh_frame
, *unwind_info
;
1528 guint32 eh_frame_ptr
;
1531 int i
, pos
, left
, right
, offset
, offset1
, offset2
;
1532 guint32 unw_len
, code_len
;
1533 MonoJitExceptionInfo
*ei
;
1536 g_assert (amodule
->eh_frame_hdr
);
1538 // http://refspecs.freestandards.org/LSB_1.3.0/gLSB/gLSB/ehframehdr.html
1539 hdr
= (eh_frame_hdr
*)amodule
->eh_frame_hdr
;
1540 g_assert (hdr
->version
== 1);
1541 g_assert (hdr
->eh_frame_ptr_enc
== (DW_EH_PE_pcrel
| DW_EH_PE_sdata4
));
1542 g_assert (hdr
->fde_count_enc
== DW_EH_PE_udata4
);
1543 g_assert (hdr
->table_enc
== (DW_EH_PE_datarel
| DW_EH_PE_sdata4
));
1546 eh_frame_ptr
= *(guint32
*)p
;
1548 fde_count
= *(guint32
*)p
;
1552 /* Binary search in the table to find the entry for code */
1553 offset
= code
- amodule
->eh_frame_hdr
;
1558 pos
= (left
+ right
) / 2;
1560 offset1
= table
[(pos
* 2)];
1561 if (pos
+ 1 == fde_count
)
1563 offset2
= amodule
->code_end
- amodule
->code
;
1565 offset2
= table
[(pos
+ 1) * 2];
1567 if (offset
< offset1
)
1569 else if (offset
>= offset2
)
1575 g_assert (code
>= amodule
->eh_frame_hdr
+ table
[(pos
* 2)]);
1576 if (pos
< fde_count
)
1577 g_assert (code
< amodule
->eh_frame_hdr
+ table
[(pos
* 2) + 2]);
1579 eh_frame
= amodule
->eh_frame_hdr
+ table
[(pos
* 2) + 1];
1581 unwind_info
= mono_unwind_decode_fde (eh_frame
, &unw_len
, &code_len
, &ei
, &ei_len
, NULL
);
1583 jinfo
->code_size
= code_len
;
1584 jinfo
->used_regs
= mono_cache_unwind_info (unwind_info
, unw_len
);
1585 jinfo
->method
= method
;
1586 jinfo
->code_start
= code
;
1587 jinfo
->domain_neutral
= 0;
1588 /* This signals that used_regs points to a normal cached unwind info */
1589 jinfo
->from_aot
= 0;
1591 g_assert (ei_len
== jinfo
->num_clauses
);
1592 for (i
= 0; i
< jinfo
->num_clauses
; ++i
) {
1593 MonoJitExceptionInfo
*jei
= &jinfo
->clauses
[i
];
1595 jei
->try_start
= ei
[i
].try_start
;
1596 jei
->try_end
= ei
[i
].try_end
;
1597 jei
->handler_start
= ei
[i
].handler_start
;
1603 /* The offsets in the table are 31 bits long, have to extend them to 32 */
1604 #define EXTEND_PREL31(val) ((((gint32)(val)) << 1) >> 1)
1606 static inline guint32
1607 decode_uleb128 (guint8
*buf
, guint8
**endbuf
)
1617 res
= res
| (((int)(b
& 0x7f)) << shift
);
1629 decode_arm_eh_ops (guint8
*unwind_ops
, int nops
)
1631 int i
, vsp_reg
, vsp_offset
;
1633 gint32
*reg_offsets
;
1636 * Have to convert the ARM unwind info into DWARF unwind info.
1637 * The ARM unwind info specifies a simple set of instructions which need to be
1638 * executed during unwinding. It manipulates a virtual stack pointer (vsp). The
1639 * connection with DWARF unwind info is the following: after all ARM unwind
1640 * opcodes have been executed, the stack should be completely unwound, i.e.
1641 * vsp == DWARF CFA. This allows us to construct the DWARF opcodes corresponding
1642 * to the ARM opcodes.
1643 * The ARM unwind info is not instruction precise, i. e. it can't handle
1644 * async exceptions etc.
1646 /* The reg used to compute the initial value of vsp */
1647 vsp_reg
= ARMREG_SP
;
1648 /* The offset between vsp_reg and the CFA */
1651 /* The register save offsets from the initial value of vsp */
1652 reg_offsets
= g_new0 (gint32
, 16);
1653 for (i
= 0; i
< 16; ++i
)
1654 reg_offsets
[i
] = -1;
1656 /* section 9.3 in the ehabi doc */
1657 for (i
= 0; i
< nops
; ++i
) {
1658 guint8 op
= unwind_ops
[i
];
1660 if ((op
>> 6) == 0) {
1661 /* vsp = vsp + (xxxxxx << 2) + 4. */
1662 vsp_offset
+= ((op
& 0x3f) << 2) + 4;
1663 } else if ((op
>> 6) == 1) {
1664 /* vsp = vsp - (xxxxxx << 2) - 4. */
1665 vsp_offset
-= ((op
& 0x3f) << 2) + 4;
1666 } else if (op
== 0xb2) {
1667 /* vsp = vsp = vsp + 0x204 + (uleb128 << 2) */
1668 guint8
*p
= unwind_ops
+ i
+ 1;
1669 guint32 v
= decode_uleb128 (p
, &p
);
1671 vsp_offset
+= 0x204 + (v
<< 2);
1672 i
= (p
- unwind_ops
) - 1;
1673 } else if (op
>= 0x80 && op
<= 0x8f) {
1679 g_assert (i
+ 1 < nops
);
1680 op2
= unwind_ops
[i
+ 1];
1683 for (j
= 0; j
< 8; ++j
)
1684 if (op2
& (0x1 << j
))
1685 regs
= g_slist_append (regs
, GUINT_TO_POINTER (ARMREG_R4
+ j
));
1686 for (j
= 0; j
< 4; ++j
)
1687 if (op
& (0x1 << j
))
1688 regs
= g_slist_append (regs
, GUINT_TO_POINTER (ARMREG_R12
+ j
));
1691 for (j
= 0; j
< g_slist_length (regs
); ++j
)
1692 reg_offsets
[GPOINTER_TO_UINT (g_slist_nth (regs
, j
)->data
)] = vsp_offset
+ (j
* 4);
1694 vsp_offset
+= g_slist_length (regs
) * 4;
1696 g_slist_free (regs
);
1699 } else if (op
>= 0xa8 && op
<= 0xaf) {
1703 /* pop r4-r[4 + nnn], r14 */
1706 for (j
= 0; j
<= (op
& 0x7); ++j
)
1707 regs
= g_slist_append (regs
, GUINT_TO_POINTER (ARMREG_R4
+ j
));
1708 regs
= g_slist_append (regs
, GUINT_TO_POINTER (ARMREG_R14
));
1710 for (j
= 0; j
< g_slist_length (regs
); ++j
)
1711 reg_offsets
[GPOINTER_TO_UINT (g_slist_nth (regs
, j
)->data
)] = vsp_offset
+ (j
* 4);
1713 vsp_offset
+= g_slist_length (regs
) * 4;
1715 g_slist_free (regs
);
1716 } else if (op
== 0xb0) {
1719 } else if (op
>= 0x90 && op
<= 0x9f && op
!= 0x9d && op
!= 0x9f) {
1726 for (j
= 0; j
< nops
; ++j
)
1727 printf ("%x ", unwind_ops
[j
]);
1728 printf (" / %d\n", i
);
1729 g_assert_not_reached ();
1735 /* vsp_reg + vsp_offset = CFA */
1736 mono_add_unwind_op_def_cfa (ops
, (guint8
*)NULL
, (guint8
*)NULL
, vsp_reg
, vsp_offset
);
1738 for (i
= 0; i
< 16; ++i
) {
1739 if (reg_offsets
[i
] != -1)
1740 /* The reg is saved at vsp_reg + reg_offset [i] == CFA - (vsp_offset - reg_offset [i]) */
1741 mono_add_unwind_op_offset (ops
, (guint8
*)NULL
, (guint8
*)NULL
, i
, - (vsp_offset
- reg_offsets
[i
]));
1750 * Decode the exception handling information in the .ARM.exidx section of the AOT
1751 * file belong to CODE, and construct a MonoJitInfo structure from it.
1752 * LOCKING: Acquires the domain lock.
1755 decode_arm_exidx (MonoAotModule
*amodule
, MonoDomain
*domain
,
1756 MonoMethod
*method
, guint8
*code
, guint32 code_len
, MonoJitInfo
*jinfo
)
1759 guint8
*base
, *code1
, *code2
;
1760 int i
, pos
, left
, right
, offset
, offset1
, offset2
, count
, nwords
, nops
;
1762 guint8 unwind_ops
[64];
1764 guint8
*unwind_info
;
1767 g_assert (amodule
->arm_exidx
);
1769 table
= (guint32
*)amodule
->arm_exidx
;
1772 * The table format is described in:
1773 * infocenter.arm.com/help/topic/com.arm.doc.../IHI0038A_ehabi.pdf
1776 base
= amodule
->arm_exidx
;
1777 count
= amodule
->arm_exidx_size
/ 8;
1779 /* Binary search in the table to find the entry for code */
1780 offset
= code
- base
;
1785 pos
= (left
+ right
) / 2;
1790 offset1
= EXTEND_PREL31 (table
[(pos
* 2)]);
1791 code1
= (guint8
*)&(table
[pos
* 2]) + offset1
;
1792 if (pos
+ 1 == count
)
1794 offset2
= amodule
->code_end
- amodule
->code
;
1796 offset2
= EXTEND_PREL31 (table
[(pos
+ 1) * 2]);
1797 code2
= (guint8
*)&(table
[(pos
+ 1) * 2]) + offset2
;
1801 else if (code
>= code2
)
1807 if (code
>= code1
) {
1809 * The linker might merge duplicate unwind table entries, so
1810 * offset1 and offset2 might point to another method, but this is not a problem.
1812 code1
= (guint8
*)&(table
[pos
* 2]) + offset1
;
1813 code2
= (guint8
*)&(table
[(pos
+ 1) * 2]) + offset2
;
1815 g_assert (code
>= code1
);
1817 g_assert (code
< code2
);
1819 entry
= table
[(pos
* 2) + 1];
1821 /* inline entry, compact model, personality routine 0 */
1822 if ((entry
& 0xff000000) == 0x80000000) {
1824 unwind_ops
[0] = (entry
& 0x00ff0000) >> 16;
1825 unwind_ops
[1] = (entry
& 0x0000ff00) >> 8;
1826 unwind_ops
[2] = (entry
& 0x000000ff) >> 0;
1828 ops
= decode_arm_eh_ops (unwind_ops
, nops
);
1829 } else if ((entry
& 0x80000000) == 0) {
1830 /* non-inline entry */
1831 guint8
*data
= (guint8
*)&table
[(pos
* 2) + 1] + EXTEND_PREL31 (entry
);
1833 entry
= ((guint32
*)data
) [0];
1835 /* compact model, personality routine 1 */
1836 g_assert ((entry
& 0xff000000) == 0x81000000);
1838 nwords
= (entry
& 0x00ff0000) >> 16;
1839 nops
= nwords
* 4 + 2;
1840 g_assert (nops
< 64);
1842 unwind_ops
[0] = (entry
& 0x0000ff00) >> 8;
1843 unwind_ops
[1] = (entry
& 0x000000ff) >> 0;
1845 for (i
= 0; i
< nwords
; ++i
) {
1846 entry
= ((guint32
*)data
) [1 + i
];
1847 unwind_ops
[(i
* 4) + 2] = (entry
& 0xff000000) >> 24;
1848 unwind_ops
[(i
* 4) + 2 + 1] = (entry
& 0x00ff0000) >> 16;
1849 unwind_ops
[(i
* 4) + 2 + 2] = (entry
& 0x0000ff00) >> 8;
1850 unwind_ops
[(i
* 4) + 2 + 3] = (entry
& 0x000000ff) >> 0;
1853 ops
= decode_arm_eh_ops (unwind_ops
, nops
);
1858 unwind_info
= mono_unwind_ops_encode (ops
, &unw_len
);
1860 /* The method has no unwind info */
1865 jinfo
->code_size
= code_len
;
1866 jinfo
->used_regs
= mono_cache_unwind_info (unwind_info
, unw_len
);
1867 jinfo
->method
= method
;
1868 jinfo
->code_start
= code
;
1869 jinfo
->domain_neutral
= 0;
1870 /* This signals that used_regs points to a normal cached unwind info */
1871 jinfo
->from_aot
= 0;
1876 * LOCKING: Acquires the domain lock.
1879 decode_exception_debug_info (MonoAotModule
*amodule
, MonoDomain
*domain
,
1880 MonoMethod
*method
, guint8
* ex_info
, guint8
*addr
,
1881 guint8
*code
, guint32 code_len
)
1885 guint used_int_regs
, flags
;
1886 gboolean has_generic_jit_info
, has_dwarf_unwind_info
, has_clauses
, has_seq_points
;
1889 int generic_info_size
;
1891 /* Load the method info from the AOT file */
1894 flags
= decode_value (p
, &p
);
1895 has_generic_jit_info
= (flags
& 1) != 0;
1896 has_dwarf_unwind_info
= (flags
& 2) != 0;
1897 has_clauses
= (flags
& 4) != 0;
1898 has_seq_points
= (flags
& 8) != 0;
1899 from_llvm
= (flags
& 16) != 0;
1900 if (has_dwarf_unwind_info
) {
1903 offset
= decode_value (p
, &p
);
1904 g_assert (offset
< (1 << 30));
1905 used_int_regs
= offset
;
1907 used_int_regs
= decode_value (p
, &p
);
1909 if (has_generic_jit_info
)
1910 generic_info_size
= sizeof (MonoGenericJitInfo
);
1912 generic_info_size
= 0;
1914 /* Exception table */
1916 int num_clauses
= decode_value (p
, &p
);
1919 mono_domain_alloc0 (domain
, MONO_SIZEOF_JIT_INFO
+ (sizeof (MonoJitExceptionInfo
) * num_clauses
) + generic_info_size
);
1920 jinfo
->num_clauses
= num_clauses
;
1922 for (i
= 0; i
< num_clauses
; ++i
) {
1923 MonoJitExceptionInfo
*ei
= &jinfo
->clauses
[i
];
1925 ei
->flags
= decode_value (p
, &p
);
1926 ei
->exvar_offset
= decode_value (p
, &p
);
1928 if (ei
->flags
== MONO_EXCEPTION_CLAUSE_FILTER
)
1929 ei
->data
.filter
= code
+ decode_value (p
, &p
);
1931 if (decode_value (p
, &p
))
1932 ei
->data
.catch_class
= decode_klass_ref (amodule
, p
, &p
);
1935 ei
->try_start
= code
+ decode_value (p
, &p
);
1936 ei
->try_end
= code
+ decode_value (p
, &p
);
1937 ei
->handler_start
= code
+ decode_value (p
, &p
);
1941 jinfo
= mono_domain_alloc0 (domain
, MONO_SIZEOF_JIT_INFO
+ generic_info_size
);
1945 /* LLVM compiled method */
1946 /* The info is in the .eh_frame section */
1948 decode_arm_exidx (amodule
, domain
, method
, code
, code_len
, jinfo
);
1950 decode_eh_frame (amodule
, domain
, method
, code
, jinfo
);
1952 jinfo
->from_llvm
= 1;
1954 jinfo
->code_size
= code_len
;
1955 jinfo
->used_regs
= used_int_regs
;
1956 jinfo
->method
= method
;
1957 jinfo
->code_start
= code
;
1958 jinfo
->domain_neutral
= 0;
1959 jinfo
->from_aot
= 1;
1962 if (has_generic_jit_info
) {
1963 MonoGenericJitInfo
*gi
;
1965 jinfo
->has_generic_jit_info
= 1;
1967 gi
= mono_jit_info_get_generic_jit_info (jinfo
);
1970 gi
->has_this
= decode_value (p
, &p
);
1971 gi
->this_reg
= decode_value (p
, &p
);
1972 gi
->this_offset
= decode_value (p
, &p
);
1974 /* This currently contains no data */
1975 gi
->generic_sharing_context
= g_new0 (MonoGenericSharingContext
, 1);
1977 jinfo
->method
= decode_method_ref_2 (amodule
, p
, &p
);
1980 if (has_seq_points
) {
1981 MonoSeqPointInfo
*seq_points
;
1982 int il_offset
, native_offset
, last_il_offset
, last_native_offset
, j
;
1984 int len
= decode_value (p
, &p
);
1986 seq_points
= g_malloc0 (sizeof (MonoSeqPointInfo
) + (len
- MONO_ZERO_LEN_ARRAY
) * sizeof (SeqPoint
));
1987 last_il_offset
= last_native_offset
= 0;
1988 for (i
= 0; i
< len
; ++i
) {
1989 SeqPoint
*sp
= &seq_points
->seq_points
[i
];
1990 il_offset
= last_il_offset
+ decode_value (p
, &p
);
1991 native_offset
= last_native_offset
+ decode_value (p
, &p
);
1993 sp
->il_offset
= il_offset
;
1994 sp
->native_offset
= native_offset
;
1996 sp
->next_len
= decode_value (p
, &p
);
1997 sp
->next
= g_new (int, sp
->next_len
);
1998 for (j
= 0; j
< sp
->next_len
; ++j
)
1999 sp
->next
[j
] = decode_value (p
, &p
);
2001 last_il_offset
= il_offset
;
2002 last_native_offset
= native_offset
;
2005 mono_domain_lock (domain
);
2006 g_hash_table_insert (domain_jit_info (domain
)->seq_points
, method
, seq_points
);
2007 mono_domain_unlock (domain
);
2010 /* Load debug info */
2011 buf_len
= decode_value (p
, &p
);
2012 mono_debug_add_aot_method (domain
, method
, code
, p
, buf_len
);
2014 if (amodule
!= jinfo
->method
->klass
->image
->aot_module
) {
2017 ji_to_amodule
= g_hash_table_new (NULL
, NULL
);
2018 g_hash_table_insert (ji_to_amodule
, jinfo
, amodule
);
2026 * mono_aot_get_unwind_info:
2028 * Return a pointer to the DWARF unwind info belonging to JI.
2031 mono_aot_get_unwind_info (MonoJitInfo
*ji
, guint32
*unwind_info_len
)
2033 MonoAotModule
*amodule
= ji
->method
->klass
->image
->aot_module
;
2035 guint8
*code
= ji
->code_start
;
2038 g_assert (ji
->from_aot
);
2040 if (!(code
>= amodule
->code
&& code
<= amodule
->code_end
)) {
2041 /* ji belongs to a different aot module than amodule */
2043 g_assert (ji_to_amodule
);
2044 amodule
= g_hash_table_lookup (ji_to_amodule
, ji
);
2046 g_assert (code
>= amodule
->code
&& code
<= amodule
->code_end
);
2049 p
= amodule
->unwind_info
+ ji
->used_regs
;
2050 *unwind_info_len
= decode_value (p
, &p
);
2055 compare_ints (const void *a
, const void *b
)
2057 return *(gint32
*)a
- *(gint32
*)b
;
2061 mono_aot_find_jit_info (MonoDomain
*domain
, MonoImage
*image
, gpointer addr
)
2063 int pos
, left
, right
, offset
, offset1
, offset2
, code_len
;
2064 int method_index
, table_len
, is_wrapper
;
2066 MonoAotModule
*amodule
= image
->aot_module
;
2069 guint8
*code
, *ex_info
, *p
;
2071 int nmethods
= amodule
->info
.nmethods
;
2072 gint32
*code_offsets
;
2078 if (domain
!= mono_get_root_domain ())
2082 offset
= (guint8
*)addr
- amodule
->code
;
2084 /* Compute a sorted table mapping code offsets to method indexes. */
2085 if (!amodule
->sorted_code_offsets
) {
2086 code_offsets
= g_new0 (gint32
, nmethods
* 2);
2087 for (i
= 0; i
< nmethods
; ++i
) {
2088 code_offsets
[(i
* 2)] = amodule
->code_offsets
[i
];
2089 code_offsets
[(i
*2) + 1] = i
;
2091 /* FIXME: Use a merge sort as this is mostly sorted */
2092 qsort (code_offsets
, nmethods
, sizeof (gint32
) * 2, compare_ints
);
2093 for (i
= 0; i
< nmethods
-1; ++i
)
2094 g_assert (code_offsets
[(i
* 2)] <= code_offsets
[(i
+ 1) * 2]);
2096 if (InterlockedCompareExchangePointer ((gpointer
*)&amodule
->sorted_code_offsets
, code_offsets
, NULL
) != NULL
)
2097 /* Somebody got in before us */
2098 g_free (code_offsets
);
2101 code_offsets
= amodule
->sorted_code_offsets
;
2103 /* Binary search in the sorted_code_offsets table */
2107 pos
= (left
+ right
) / 2;
2109 offset1
= code_offsets
[(pos
* 2)];
2110 if (pos
+ 1 == nmethods
)
2111 offset2
= amodule
->code_end
- amodule
->code
;
2113 offset2
= code_offsets
[(pos
+ 1) * 2];
2115 if (offset
< offset1
)
2117 else if (offset
>= offset2
)
2123 g_assert (offset
>= code_offsets
[(pos
* 2)]);
2124 if (pos
+ 1 < nmethods
)
2125 g_assert (offset
< code_offsets
[((pos
+ 1) * 2)]);
2126 method_index
= code_offsets
[(pos
* 2) + 1];
2128 code
= &amodule
->code
[amodule
->code_offsets
[method_index
]];
2129 ex_info
= &amodule
->blob
[mono_aot_get_offset (amodule
->ex_info_offsets
, method_index
)];
2131 if (pos
== nmethods
- 1)
2132 code_len
= amodule
->code_end
- code
;
2134 code_len
= code_offsets
[(pos
+ 1) * 2] - code_offsets
[pos
* 2];
2136 g_assert ((guint8
*)code
<= (guint8
*)addr
&& (guint8
*)addr
< (guint8
*)code
+ code_len
);
2138 /* Might be a wrapper/extra method */
2139 if (amodule
->extra_methods
) {
2141 method
= g_hash_table_lookup (amodule
->extra_methods
, GUINT_TO_POINTER (method_index
));
2148 if (method_index
>= image
->tables
[MONO_TABLE_METHOD
].rows
) {
2150 * This is hit for extra methods which are called directly, so they are
2151 * not in amodule->extra_methods.
2153 table_len
= amodule
->extra_method_info_offsets
[0];
2154 table
= amodule
->extra_method_info_offsets
+ 1;
2161 pos
= ((left
+ right
) / 2);
2163 g_assert (pos
< table_len
);
2165 if (table
[pos
* 2] < method_index
)
2167 else if (table
[pos
* 2] > method_index
)
2173 p
= amodule
->blob
+ table
[(pos
* 2) + 1];
2174 is_wrapper
= decode_value (p
, &p
);
2175 g_assert (!is_wrapper
);
2176 method
= decode_method_ref_2 (amodule
, p
, &p
);
2179 token
= mono_metadata_make_token (MONO_TABLE_METHOD
, method_index
+ 1);
2180 method
= mono_get_method (image
, token
, NULL
);
2187 //printf ("F: %s\n", mono_method_full_name (method, TRUE));
2189 jinfo
= decode_exception_debug_info (amodule
, domain
, method
, ex_info
, addr
, code
, code_len
);
2191 g_assert ((guint8
*)addr
>= (guint8
*)jinfo
->code_start
);
2192 g_assert ((guint8
*)addr
< (guint8
*)jinfo
->code_start
+ jinfo
->code_size
);
2194 /* Add it to the normal JitInfo tables */
2195 mono_jit_info_table_add (domain
, jinfo
);
2201 decode_patch (MonoAotModule
*aot_module
, MonoMemPool
*mp
, MonoJumpInfo
*ji
, guint8
*buf
, guint8
**endbuf
)
2209 case MONO_PATCH_INFO_METHOD
:
2210 case MONO_PATCH_INFO_METHOD_JUMP
:
2211 case MONO_PATCH_INFO_ICALL_ADDR
:
2212 case MONO_PATCH_INFO_METHOD_RGCTX
: {
2215 gboolean no_aot_trampoline
;
2217 image
= decode_method_ref (aot_module
, &token
, &method
, &no_aot_trampoline
, p
, &p
);
2221 if (!method
&& !mono_aot_only
&& !no_aot_trampoline
&& (ji
->type
== MONO_PATCH_INFO_METHOD
) && (mono_metadata_token_table (token
) == MONO_TABLE_METHOD
)) {
2222 ji
->data
.target
= mono_create_ftnptr (mono_domain_get (), mono_create_jit_trampoline_from_token (image
, token
));
2223 ji
->type
= MONO_PATCH_INFO_ABS
;
2227 ji
->data
.method
= method
;
2229 ji
->data
.method
= mono_get_method (image
, token
, NULL
);
2230 g_assert (ji
->data
.method
);
2231 mono_class_init (ji
->data
.method
->klass
);
2235 case MONO_PATCH_INFO_INTERNAL_METHOD
:
2236 case MONO_PATCH_INFO_JIT_ICALL_ADDR
: {
2237 guint32 len
= decode_value (p
, &p
);
2239 ji
->data
.name
= (char*)p
;
2243 case MONO_PATCH_INFO_METHODCONST
:
2245 ji
->data
.method
= decode_method_ref_2 (aot_module
, p
, &p
);
2246 if (!ji
->data
.method
)
2249 case MONO_PATCH_INFO_VTABLE
:
2250 case MONO_PATCH_INFO_CLASS
:
2251 case MONO_PATCH_INFO_IID
:
2252 case MONO_PATCH_INFO_ADJUSTED_IID
:
2254 ji
->data
.klass
= decode_klass_ref (aot_module
, p
, &p
);
2255 if (!ji
->data
.klass
)
2258 case MONO_PATCH_INFO_CLASS_INIT
:
2259 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE
:
2260 ji
->data
.klass
= decode_klass_ref (aot_module
, p
, &p
);
2261 if (!ji
->data
.klass
)
2264 case MONO_PATCH_INFO_IMAGE
:
2265 ji
->data
.image
= load_image (aot_module
, decode_value (p
, &p
), TRUE
);
2266 if (!ji
->data
.image
)
2269 case MONO_PATCH_INFO_FIELD
:
2270 case MONO_PATCH_INFO_SFLDA
:
2272 ji
->data
.field
= decode_field_info (aot_module
, p
, &p
);
2273 if (!ji
->data
.field
)
2276 case MONO_PATCH_INFO_SWITCH
:
2277 ji
->data
.table
= mono_mempool_alloc0 (mp
, sizeof (MonoJumpInfoBBTable
));
2278 ji
->data
.table
->table_size
= decode_value (p
, &p
);
2279 table
= g_new (gpointer
, ji
->data
.table
->table_size
);
2280 ji
->data
.table
->table
= (MonoBasicBlock
**)table
;
2281 for (i
= 0; i
< ji
->data
.table
->table_size
; i
++)
2282 table
[i
] = (gpointer
)(gssize
)decode_value (p
, &p
);
2284 case MONO_PATCH_INFO_R4
: {
2287 ji
->data
.target
= mono_domain_alloc0 (mono_domain_get (), sizeof (float));
2288 val
= decode_value (p
, &p
);
2289 *(float*)ji
->data
.target
= *(float*)&val
;
2292 case MONO_PATCH_INFO_R8
: {
2296 ji
->data
.target
= mono_domain_alloc0 (mono_domain_get (), sizeof (double));
2298 val
[0] = decode_value (p
, &p
);
2299 val
[1] = decode_value (p
, &p
);
2300 v
= ((guint64
)val
[1] << 32) | ((guint64
)val
[0]);
2301 *(double*)ji
->data
.target
= *(double*)&v
;
2304 case MONO_PATCH_INFO_LDSTR
:
2305 image
= load_image (aot_module
, decode_value (p
, &p
), TRUE
);
2308 ji
->data
.token
= mono_jump_info_token_new (mp
, image
, MONO_TOKEN_STRING
+ decode_value (p
, &p
));
2310 case MONO_PATCH_INFO_RVA
:
2311 case MONO_PATCH_INFO_DECLSEC
:
2312 case MONO_PATCH_INFO_LDTOKEN
:
2313 case MONO_PATCH_INFO_TYPE_FROM_HANDLE
:
2315 image
= load_image (aot_module
, decode_value (p
, &p
), TRUE
);
2318 ji
->data
.token
= mono_jump_info_token_new (mp
, image
, decode_value (p
, &p
));
2320 ji
->data
.token
->has_context
= decode_value (p
, &p
);
2321 if (ji
->data
.token
->has_context
) {
2322 gboolean res
= decode_generic_context (aot_module
, &ji
->data
.token
->context
, p
, &p
);
2327 case MONO_PATCH_INFO_EXC_NAME
:
2328 ji
->data
.klass
= decode_klass_ref (aot_module
, p
, &p
);
2329 if (!ji
->data
.klass
)
2331 ji
->data
.name
= ji
->data
.klass
->name
;
2333 case MONO_PATCH_INFO_METHOD_REL
:
2334 ji
->data
.offset
= decode_value (p
, &p
);
2336 case MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG
:
2337 case MONO_PATCH_INFO_GENERIC_CLASS_INIT
:
2338 case MONO_PATCH_INFO_MONITOR_ENTER
:
2339 case MONO_PATCH_INFO_MONITOR_EXIT
:
2341 case MONO_PATCH_INFO_RGCTX_FETCH
: {
2343 MonoJumpInfoRgctxEntry
*entry
;
2345 entry
= mono_mempool_alloc0 (mp
, sizeof (MonoJumpInfoRgctxEntry
));
2346 entry
->method
= decode_method_ref_2 (aot_module
, p
, &p
);
2347 entry
->in_mrgctx
= decode_value (p
, &p
);
2348 entry
->info_type
= decode_value (p
, &p
);
2349 entry
->data
= mono_mempool_alloc0 (mp
, sizeof (MonoJumpInfo
));
2350 entry
->data
->type
= decode_value (p
, &p
);
2352 res
= decode_patch (aot_module
, mp
, entry
->data
, p
, &p
);
2355 ji
->data
.rgctx_entry
= entry
;
2358 case MONO_PATCH_INFO_SEQ_POINT_INFO
:
2360 case MONO_PATCH_INFO_LLVM_IMT_TRAMPOLINE
: {
2361 MonoJumpInfoImtTramp
*imt_tramp
= mono_mempool_alloc0 (mp
, sizeof (MonoJumpInfoImtTramp
));
2363 imt_tramp
->method
= decode_method_ref_2 (aot_module
, p
, &p
);
2364 imt_tramp
->vt_offset
= decode_value (p
, &p
);
2366 ji
->data
.imt_tramp
= imt_tramp
;
2370 g_warning ("unhandled type %d", ji
->type
);
2371 g_assert_not_reached ();
2382 static MonoJumpInfo
*
2383 load_patch_info (MonoAotModule
*aot_module
, MonoMemPool
*mp
, int n_patches
,
2384 guint32
**got_slots
,
2385 guint8
*buf
, guint8
**endbuf
)
2387 MonoJumpInfo
*patches
;
2393 patches
= mono_mempool_alloc0 (mp
, sizeof (MonoJumpInfo
) * n_patches
);
2395 *got_slots
= g_malloc (sizeof (guint32
) * n_patches
);
2397 for (pindex
= 0; pindex
< n_patches
; ++pindex
) {
2398 MonoJumpInfo
*ji
= &patches
[pindex
];
2403 got_offset
= decode_value (p
, &p
);
2405 if (aot_module
->got
[got_offset
]) {
2406 /* Already loaded */
2407 //printf ("HIT!\n");
2409 shared_p
= aot_module
->blob
+ mono_aot_get_offset (aot_module
->got_info_offsets
, got_offset
);
2411 ji
->type
= decode_value (shared_p
, &shared_p
);
2413 res
= decode_patch (aot_module
, mp
, ji
, shared_p
, &shared_p
);
2418 (*got_slots
) [pindex
] = got_offset
;
2425 g_free (*got_slots
);
2432 register_jump_target_got_slot (MonoDomain
*domain
, MonoMethod
*method
, gpointer
*got_slot
)
2435 * Jump addresses cannot be patched by the trampoline code since it
2436 * does not have access to the caller's address. Instead, we collect
2437 * the addresses of the GOT slots pointing to a method, and patch
2438 * them after the method has been compiled.
2440 MonoJitDomainInfo
*info
= domain_jit_info (domain
);
2443 mono_domain_lock (domain
);
2444 if (!info
->jump_target_got_slot_hash
)
2445 info
->jump_target_got_slot_hash
= g_hash_table_new (NULL
, NULL
);
2446 list
= g_hash_table_lookup (info
->jump_target_got_slot_hash
, method
);
2447 list
= g_slist_prepend (list
, got_slot
);
2448 g_hash_table_insert (info
->jump_target_got_slot_hash
, method
, list
);
2449 mono_domain_unlock (domain
);
2455 * Load the method identified by METHOD_INDEX from the AOT image. Return a
2456 * pointer to the native code of the method, or NULL if not found.
2457 * METHOD might not be set if the caller only has the image/token info.
2460 load_method (MonoDomain
*domain
, MonoAotModule
*amodule
, MonoImage
*image
, MonoMethod
*method
, guint32 token
, int method_index
)
2463 gboolean from_plt
= method
== NULL
;
2465 int i
, pindex
, n_patches
, used_strings
;
2466 gboolean keep_patches
= TRUE
;
2468 MonoJitInfo
*jinfo
= NULL
;
2469 guint8
*code
, *info
;
2471 if (mono_profiler_get_events () & MONO_PROFILE_ENTER_LEAVE
)
2474 if ((domain
!= mono_get_root_domain ()) && (!(amodule
->info
.opts
& MONO_OPT_SHARED
)))
2475 /* Non shared AOT code can't be used in other appdomains */
2478 if (amodule
->out_of_date
)
2481 if (amodule
->code_offsets
[method_index
] == 0xffffffff) {
2482 if (mono_trace_is_traced (G_LOG_LEVEL_DEBUG
, MONO_TRACE_AOT
)) {
2486 method
= mono_get_method (image
, token
, NULL
);
2487 full_name
= mono_method_full_name (method
, TRUE
);
2488 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_AOT
, "AOT NOT FOUND: %s.\n", full_name
);
2494 code
= &amodule
->code
[amodule
->code_offsets
[method_index
]];
2496 info
= &amodule
->blob
[mono_aot_get_offset (amodule
->method_info_offsets
, method_index
)];
2499 if (!amodule
->methods_loaded
)
2500 amodule
->methods_loaded
= g_new0 (guint32
, amodule
->info
.nmethods
+ 1);
2503 if ((amodule
->methods_loaded
[method_index
/ 32] >> (method_index
% 32)) & 0x1)
2506 if (mono_last_aot_method
!= -1) {
2507 if (mono_jit_stats
.methods_aot
>= mono_last_aot_method
)
2509 else if (mono_jit_stats
.methods_aot
== mono_last_aot_method
- 1) {
2511 printf ("LAST AOT METHOD: %s%s%s.%s.\n", method
->klass
->name_space
, method
->klass
->name_space
[0] ? "." : "", method
->klass
->name
, method
->name
);
2513 printf ("LAST AOT METHOD: %p %d\n", code
, method_index
);
2520 klass
= method
->klass
;
2521 decode_klass_ref (amodule
, p
, &p
);
2523 klass
= decode_klass_ref (amodule
, p
, &p
);
2526 if (amodule
->info
.opts
& MONO_OPT_SHARED
)
2527 used_strings
= decode_value (p
, &p
);
2531 for (i
= 0; i
< used_strings
; i
++) {
2532 guint token
= decode_value (p
, &p
);
2533 mono_ldstr (mono_get_root_domain (), image
, mono_metadata_token_index (token
));
2536 if (amodule
->info
.opts
& MONO_OPT_SHARED
)
2537 keep_patches
= FALSE
;
2539 n_patches
= decode_value (p
, &p
);
2541 keep_patches
= FALSE
;
2544 MonoJumpInfo
*patches
;
2550 mp
= mono_mempool_new ();
2552 patches
= load_patch_info (amodule
, mp
, n_patches
, &got_slots
, p
, &p
);
2553 if (patches
== NULL
)
2556 for (pindex
= 0; pindex
< n_patches
; ++pindex
) {
2557 MonoJumpInfo
*ji
= &patches
[pindex
];
2559 if (!amodule
->got
[got_slots
[pindex
]]) {
2560 amodule
->got
[got_slots
[pindex
]] = mono_resolve_patch_target (method
, domain
, code
, ji
, TRUE
);
2561 if (ji
->type
== MONO_PATCH_INFO_METHOD_JUMP
)
2562 amodule
->got
[got_slots
[pindex
]] = mono_create_ftnptr (domain
, amodule
->got
[got_slots
[pindex
]]);
2563 if (ji
->type
== MONO_PATCH_INFO_METHOD_JUMP
)
2564 register_jump_target_got_slot (domain
, ji
->data
.method
, &(amodule
->got
[got_slots
[pindex
]]));
2566 ji
->type
= MONO_PATCH_INFO_NONE
;
2572 mono_mempool_destroy (mp
);
2575 if (mono_trace_is_traced (G_LOG_LEVEL_DEBUG
, MONO_TRACE_AOT
)) {
2579 method
= mono_get_method (image
, token
, NULL
);
2581 full_name
= mono_method_full_name (method
, TRUE
);
2584 jinfo
= mono_aot_find_jit_info (domain
, amodule
->assembly
->image
, code
);
2586 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_AOT
, "AOT FOUND AOT compiled code for %s %p - %p %p\n", full_name
, code
, code
+ jinfo
->code_size
, info
);
2592 mono_jit_stats
.methods_aot
++;
2594 amodule
->methods_loaded
[method_index
/ 32] |= 1 << (method_index
% 32);
2598 if (method
&& method
->wrapper_type
)
2599 g_hash_table_insert (amodule
->method_to_code
, method
, code
);
2603 if (mono_profiler_get_events () & MONO_PROFILE_JIT_COMPILATION
) {
2607 method
= mono_get_method (image
, token
, NULL
);
2610 mono_profiler_method_jit (method
);
2611 jinfo
= mono_jit_info_table_find (domain
, (char*)code
);
2613 mono_profiler_method_end_jit (method
, jinfo
, MONO_PROFILE_OK
);
2616 if (from_plt
&& klass
&& !klass
->generic_container
)
2617 mono_runtime_class_init (mono_class_vtable (domain
, klass
));
2622 /* FIXME: The space in domain->mp is wasted */
2623 if (amodule
->info
.opts
& MONO_OPT_SHARED
)
2624 /* No need to cache patches */
2625 mono_mempool_destroy (mp
);
2634 find_extra_method_in_amodule (MonoAotModule
*amodule
, MonoMethod
*method
, const char *name
)
2636 guint32 table_size
, entry_size
, hash
;
2637 guint32
*table
, *entry
;
2639 static guint32 n_extra_decodes
;
2644 table_size
= amodule
->extra_method_table
[0];
2645 table
= amodule
->extra_method_table
+ 1;
2648 hash
= mono_aot_method_hash (method
) % table_size
;
2650 entry
= &table
[hash
* entry_size
];
2657 guint32 key
= entry
[0];
2658 guint32 value
= entry
[1];
2659 guint32 next
= entry
[entry_size
- 1];
2662 int is_wrapper_name
;
2664 p
= amodule
->blob
+ key
;
2665 is_wrapper_name
= decode_value (p
, &p
);
2666 if (is_wrapper_name
) {
2667 int wrapper_type
= decode_value (p
, &p
);
2668 if (wrapper_type
== method
->wrapper_type
&& !strcmp (name
, (char*)p
)) {
2672 } else if (can_method_ref_match_method (amodule
, p
, method
)) {
2674 if (!amodule
->method_ref_to_method
)
2675 amodule
->method_ref_to_method
= g_hash_table_new (NULL
, NULL
);
2676 m
= g_hash_table_lookup (amodule
->method_ref_to_method
, p
);
2680 m
= decode_method_ref_2 (amodule
, p
, &p
);
2683 g_hash_table_insert (amodule
->method_ref_to_method
, orig_p
, m
);
2692 /* Special case: wrappers of shared generic methods */
2693 if (m
&& method
->wrapper_type
&& m
->wrapper_type
== m
->wrapper_type
&&
2694 method
->wrapper_type
== MONO_WRAPPER_SYNCHRONIZED
) {
2695 MonoMethod
*w1
= mono_marshal_method_from_wrapper (method
);
2696 MonoMethod
*w2
= mono_marshal_method_from_wrapper (m
);
2698 if (w1
->is_inflated
&& ((MonoMethodInflated
*)w1
)->declaring
== w2
) {
2704 /* Methods decoded needlessly */
2707 printf ("%d %s %s\n", n_extra_decodes, mono_method_full_name (method, TRUE), mono_method_full_name (m, TRUE));
2713 entry
= &table
[next
* entry_size
];
2722 add_module_cb (gpointer key
, gpointer value
, gpointer user_data
)
2724 g_ptr_array_add ((GPtrArray
*)user_data
, value
);
2728 * find_extra_method:
2730 * Try finding METHOD in the extra_method table in all AOT images.
2731 * Return its method index, or 0xffffff if not found. Set OUT_AMODULE to the AOT
2732 * module where the method was found.
2735 find_extra_method (MonoMethod
*method
, MonoAotModule
**out_amodule
)
2742 if (method
->wrapper_type
)
2743 name
= mono_aot_wrapper_name (method
);
2745 /* Try the method's module first */
2746 *out_amodule
= method
->klass
->image
->aot_module
;
2747 index
= find_extra_method_in_amodule (method
->klass
->image
->aot_module
, method
, name
);
2748 if (index
!= 0xffffff) {
2754 * Try all other modules.
2755 * This is needed because generic instances klass->image points to the image
2756 * containing the generic definition, but the native code is generated to the
2757 * AOT image which contains the reference.
2760 /* Make a copy to avoid doing the search inside the aot lock */
2761 modules
= g_ptr_array_new ();
2763 g_hash_table_foreach (aot_modules
, add_module_cb
, modules
);
2767 for (i
= 0; i
< modules
->len
; ++i
) {
2768 MonoAotModule
*amodule
= g_ptr_array_index (modules
, i
);
2770 if (amodule
!= method
->klass
->image
->aot_module
)
2771 index
= find_extra_method_in_amodule (amodule
, method
, name
);
2772 if (index
!= 0xffffff) {
2773 *out_amodule
= amodule
;
2778 g_ptr_array_free (modules
, TRUE
);
2785 * mono_aot_get_method:
2787 * Return a pointer to the AOTed native code for METHOD if it can be found,
2789 * On platforms with function pointers, this doesn't return a function pointer.
2792 mono_aot_get_method (MonoDomain
*domain
, MonoMethod
*method
)
2794 MonoClass
*klass
= method
->klass
;
2795 guint32 method_index
;
2796 MonoAotModule
*amodule
= klass
->image
->aot_module
;
2802 if (amodule
->out_of_date
)
2805 if ((method
->iflags
& METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
) ||
2806 (method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
) ||
2807 (method
->iflags
& METHOD_IMPL_ATTRIBUTE_RUNTIME
) ||
2808 (method
->flags
& METHOD_ATTRIBUTE_ABSTRACT
))
2812 * Use the original method instead of its invoke-with-check wrapper.
2813 * This is not a problem when using full-aot, since it doesn't support
2816 if (mono_aot_only
&& method
->wrapper_type
== MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK
)
2817 return mono_aot_get_method (domain
, mono_marshal_method_from_wrapper (method
));
2819 g_assert (klass
->inited
);
2821 /* Find method index */
2822 if (method
->is_inflated
&& mono_method_is_generic_sharable_impl (method
, FALSE
)) {
2823 method
= mono_method_get_declaring_generic_method (method
);
2824 method_index
= mono_metadata_token_index (method
->token
) - 1;
2825 } else if (method
->is_inflated
|| !method
->token
) {
2826 /* This hash table is used to avoid the slower search in the extra_method_table in the AOT image */
2828 code
= g_hash_table_lookup (amodule
->method_to_code
, method
);
2833 method_index
= find_extra_method (method
, &amodule
);
2835 * Special case the ICollection<T> wrappers for arrays, as they cannot
2836 * be statically enumerated, and each wrapper ends up calling the same
2839 if (method_index
== 0xffffff && method
->wrapper_type
== MONO_WRAPPER_MANAGED_TO_MANAGED
&& method
->klass
->rank
&& strstr (method
->name
, "System.Collections.Generic")) {
2840 MonoMethod
*m
= mono_aot_get_array_helper_from_wrapper (method
);
2842 code
= mono_aot_get_method (domain
, m
);
2844 if (mono_method_needs_static_rgctx_invoke (m
, FALSE
)) {
2845 code
= mono_create_static_rgctx_trampoline (m
, mono_create_ftnptr (domain
, code
));
2846 /* The call above returns an ftnptr */
2847 code
= mono_get_addr_from_ftnptr (code
);
2855 * Special case Array.GetGenericValueImpl which is a generic icall.
2856 * Generic sharing currently can't handle it, but the icall returns data using
2857 * an out parameter, so the managed-to-native wrappers can share the same code.
2859 if (method_index
== 0xffffff && method
->wrapper_type
== MONO_WRAPPER_MANAGED_TO_NATIVE
&& method
->klass
== mono_defaults
.array_class
&& !strcmp (method
->name
, "GetGenericValueImpl")) {
2861 MonoGenericContext ctx
;
2862 MonoType
*args
[16];
2864 if (mono_method_signature (method
)->params
[1]->type
== MONO_TYPE_OBJECT
)
2865 /* Avoid recursion */
2868 m
= mono_class_get_method_from_name (mono_defaults
.array_class
, "GetGenericValueImpl", 2);
2871 memset (&ctx
, 0, sizeof (ctx
));
2872 args
[0] = &mono_defaults
.object_class
->byval_arg
;
2873 ctx
.method_inst
= mono_metadata_get_generic_inst (1, args
);
2875 m
= mono_marshal_get_native_wrapper (mono_class_inflate_generic_method (m
, &ctx
), TRUE
, TRUE
);
2878 * Get the code for the <object> instantiation which should be emitted into
2879 * the mscorlib aot image by the AOT compiler.
2881 code
= mono_aot_get_method (domain
, m
);
2886 if (method_index
== 0xffffff) {
2887 if (mono_aot_only
&& mono_trace_is_traced (G_LOG_LEVEL_DEBUG
, MONO_TRACE_AOT
)) {
2890 full_name
= mono_method_full_name (method
, TRUE
);
2891 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_AOT
, "AOT NOT FOUND: %s.\n", full_name
);
2897 if (method_index
== 0xffffff)
2900 /* Needed by find_jit_info */
2902 if (!amodule
->extra_methods
)
2903 amodule
->extra_methods
= g_hash_table_new (NULL
, NULL
);
2904 g_hash_table_insert (amodule
->extra_methods
, GUINT_TO_POINTER (method_index
), method
);
2908 method_index
= mono_metadata_token_index (method
->token
) - 1;
2911 return load_method (domain
, amodule
, klass
->image
, method
, method
->token
, method_index
);
2915 * Same as mono_aot_get_method, but we try to avoid loading any metadata from the
2919 mono_aot_get_method_from_token (MonoDomain
*domain
, MonoImage
*image
, guint32 token
)
2921 MonoAotModule
*aot_module
= image
->aot_module
;
2927 method_index
= mono_metadata_token_index (token
) - 1;
2929 return load_method (domain
, aot_module
, image
, NULL
, token
, method_index
);
2935 } IsGotEntryUserData
;
2938 check_is_got_entry (gpointer key
, gpointer value
, gpointer user_data
)
2940 IsGotEntryUserData
*data
= (IsGotEntryUserData
*)user_data
;
2941 MonoAotModule
*aot_module
= (MonoAotModule
*)value
;
2943 if (aot_module
->got
&& (data
->addr
>= (guint8
*)(aot_module
->got
)) && (data
->addr
< (guint8
*)(aot_module
->got
+ aot_module
->info
.got_size
)))
2948 mono_aot_is_got_entry (guint8
*code
, guint8
*addr
)
2950 IsGotEntryUserData user_data
;
2955 user_data
.addr
= addr
;
2956 user_data
.res
= FALSE
;
2958 g_hash_table_foreach (aot_modules
, check_is_got_entry
, &user_data
);
2961 return user_data
.res
;
2966 MonoAotModule
*module
;
2967 } FindAotModuleUserData
;
2970 find_aot_module_cb (gpointer key
, gpointer value
, gpointer user_data
)
2972 FindAotModuleUserData
*data
= (FindAotModuleUserData
*)user_data
;
2973 MonoAotModule
*aot_module
= (MonoAotModule
*)value
;
2975 if ((data
->addr
>= (guint8
*)(aot_module
->code
)) && (data
->addr
< (guint8
*)(aot_module
->code_end
)))
2976 data
->module
= aot_module
;
2979 static inline MonoAotModule
*
2980 find_aot_module (guint8
*code
)
2982 FindAotModuleUserData user_data
;
2987 /* Reading these need no locking */
2988 if (((gsize
)code
< aot_code_low_addr
) || ((gsize
)code
> aot_code_high_addr
))
2991 user_data
.addr
= code
;
2992 user_data
.module
= NULL
;
2995 g_hash_table_foreach (aot_modules
, find_aot_module_cb
, &user_data
);
2998 return user_data
.module
;
3002 * mono_aot_plt_resolve:
3004 * This function is called by the entries in the PLT to resolve the actual method that
3005 * needs to be called. It returns a trampoline to the method and patches the PLT entry.
3006 * Returns NULL if the something cannot be loaded.
3009 mono_aot_plt_resolve (gpointer aot_module
, guint32 plt_info_offset
, guint8
*code
)
3011 #ifdef MONO_ARCH_AOT_SUPPORTED
3012 guint8
*p
, *target
, *plt_entry
;
3014 MonoAotModule
*module
= (MonoAotModule
*)aot_module
;
3015 gboolean res
, no_ftnptr
= FALSE
;
3018 //printf ("DYN: %p %d\n", aot_module, plt_info_offset);
3020 p
= &module
->blob
[plt_info_offset
];
3022 ji
.type
= decode_value (p
, &p
);
3024 mp
= mono_mempool_new_size (512);
3025 res
= decode_patch (module
, mp
, &ji
, p
, &p
);
3028 mono_mempool_destroy (mp
);
3033 * Avoid calling resolve_patch_target in the full-aot case if possible, since
3034 * it would create a trampoline, and we don't need that.
3035 * We could do this only if the method does not need the special handling
3036 * in mono_magic_trampoline ().
3038 if (mono_aot_only
&& ji
.type
== MONO_PATCH_INFO_METHOD
&& !ji
.data
.method
->is_generic
&& !mono_method_check_context_used (ji
.data
.method
) && !(ji
.data
.method
->iflags
& METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED
) &&
3039 !mono_method_needs_static_rgctx_invoke (ji
.data
.method
, FALSE
)) {
3040 target
= mono_jit_compile_method (ji
.data
.method
);
3043 target
= mono_resolve_patch_target (NULL
, mono_domain_get (), NULL
, &ji
, TRUE
);
3047 * The trampoline expects us to return a function descriptor on platforms which use
3048 * it, but resolve_patch_target returns a direct function pointer for some type of
3049 * patches, so have to translate between the two.
3050 * FIXME: Clean this up, but how ?
3052 if (ji
.type
== MONO_PATCH_INFO_ABS
|| ji
.type
== MONO_PATCH_INFO_INTERNAL_METHOD
|| ji
.type
== MONO_PATCH_INFO_CLASS_INIT
|| ji
.type
== MONO_PATCH_INFO_ICALL_ADDR
|| ji
.type
== MONO_PATCH_INFO_JIT_ICALL_ADDR
|| ji
.type
== MONO_PATCH_INFO_RGCTX_FETCH
) {
3053 /* These should already have a function descriptor */
3054 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
3055 /* Our function descriptors have a 0 environment, gcc created ones don't */
3056 if (ji
.type
!= MONO_PATCH_INFO_INTERNAL_METHOD
&& ji
.type
!= MONO_PATCH_INFO_JIT_ICALL_ADDR
&& ji
.type
!= MONO_PATCH_INFO_ICALL_ADDR
)
3057 g_assert (((gpointer
*)target
) [2] == 0);
3060 } else if (!no_ftnptr
) {
3061 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
3062 g_assert (((gpointer
*)target
) [2] != 0);
3064 target
= mono_create_ftnptr (mono_domain_get (), target
);
3067 mono_mempool_destroy (mp
);
3069 /* Patch the PLT entry with target which might be the actual method not a trampoline */
3070 plt_entry
= mono_aot_get_plt_entry (code
);
3071 g_assert (plt_entry
);
3072 mono_arch_patch_plt_entry (plt_entry
, module
->got
, NULL
, target
);
3076 g_assert_not_reached ();
3084 * Initialize the PLT table of the AOT module. Called lazily when the first AOT
3085 * method in the module is loaded to avoid committing memory by writing to it.
3086 * LOCKING: Assumes the AOT lock is held.
3089 init_plt (MonoAotModule
*amodule
)
3091 #ifndef MONO_CROSS_COMPILE
3093 #ifdef MONO_ARCH_AOT_SUPPORTED
3095 guint8
*buf
= amodule
->plt
;
3096 #elif defined(__x86_64__) || defined(__arm__) || defined(__mono_ppc__)
3102 if (amodule
->plt_inited
)
3105 tramp
= mono_create_specific_trampoline (amodule
, MONO_TRAMPOLINE_AOT_PLT
, mono_get_root_domain (), NULL
);
3108 /* Initialize the first PLT entry */
3109 make_writable (amodule
->plt
, amodule
->plt_end
- amodule
->plt
);
3110 x86_jump_code (buf
, tramp
);
3111 #elif defined(__x86_64__) || defined(__arm__) || defined(__mono_ppc__)
3113 * Initialize the PLT entries in the GOT to point to the default targets.
3116 tramp
= mono_create_ftnptr (mono_domain_get (), tramp
);
3117 plt_0
= mono_create_ftnptr (mono_domain_get (), amodule
->plt
);
3118 /* The first entry points to the AOT trampoline */
3119 ((gpointer
*)amodule
->got
)[amodule
->info
.plt_got_offset_base
] = tramp
;
3120 for (i
= 1; i
< amodule
->info
.plt_size
; ++i
)
3121 /* All the default entries point to the first entry */
3122 ((gpointer
*)amodule
->got
)[amodule
->info
.plt_got_offset_base
+ i
] = plt_0
;
3124 g_assert_not_reached ();
3127 amodule
->plt_inited
= TRUE
;
3130 #endif /* MONO_CROSS_COMPILE */
3134 * mono_aot_get_plt_entry:
3136 * Return the address of the PLT entry called by the code at CODE if exists.
3139 mono_aot_get_plt_entry (guint8
*code
)
3141 MonoAotModule
*aot_module
= find_aot_module (code
);
3142 #if defined(__arm__) || defined(__mono_ppc__)
3149 #if defined(__i386__) || defined(__x86_64__)
3150 if (code
[-5] == 0xe8) {
3151 guint32 disp
= *(guint32
*)(code
- 4);
3152 guint8
*target
= code
+ disp
;
3154 if ((target
>= (guint8
*)(aot_module
->plt
)) && (target
< (guint8
*)(aot_module
->plt_end
)))
3157 #elif defined(__arm__)
3158 ins
= ((guint32
*)(gpointer
)code
) [-1];
3160 /* Should be a 'bl' */
3161 if ((((ins
>> 25) & 0x7) == 0x5) && (((ins
>> 24) & 0x1) == 0x1)) {
3162 gint32 disp
= ((gint32
)ins
) & 0xffffff;
3163 guint8
*target
= code
- 4 + 8 + (disp
* 4);
3165 if ((target
>= (guint8
*)(aot_module
->plt
)) && (target
< (guint8
*)(aot_module
->plt_end
)))
3168 #elif defined(__mono_ppc__)
3169 /* Should be a bl */
3170 ins
= ((guint32
*)(gpointer
)code
) [-1];
3172 if ((ins
>> 26 == 18) && ((ins
& 1) == 1) && ((ins
& 2) == 0)) {
3173 gint32 disp
= (((gint32
)ins
) >> 2) & 0xffffff;
3174 guint8
*target
= code
- 4 + (disp
* 4);
3176 if ((target
>= (guint8
*)(aot_module
->plt
)) && (target
< (guint8
*)(aot_module
->plt_end
)))
3180 g_assert_not_reached ();
3187 * mono_aot_get_plt_info_offset:
3189 * Return the PLT info offset belonging to the plt entry called by CODE.
3192 mono_aot_get_plt_info_offset (mgreg_t
*regs
, guint8
*code
)
3194 guint8
*plt_entry
= mono_aot_get_plt_entry (code
);
3196 g_assert (plt_entry
);
3198 /* The offset is embedded inside the code after the plt entry */
3199 #if defined(__i386__)
3200 return *(guint32
*)(plt_entry
+ 5);
3201 #elif defined(__x86_64__)
3202 return *(guint32
*)(plt_entry
+ 6);
3203 #elif defined(__arm__)
3204 /* The offset is stored as the 4th word of the plt entry */
3205 return ((guint32
*)plt_entry
) [3];
3206 #elif defined(__mono_ppc__)
3207 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
3208 return ((guint32
*)plt_entry
) [8];
3210 return ((guint32
*)plt_entry
) [6];
3213 g_assert_not_reached ();
3219 mono_create_ftnptr_malloc (guint8
*code
)
3221 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
3222 MonoPPCFunctionDescriptor
*ftnptr
= g_malloc0 (sizeof (MonoPPCFunctionDescriptor
));
3224 ftnptr
->code
= code
;
3237 * Load the function named NAME from the aot image.
3240 load_function (MonoAotModule
*amodule
, const char *name
)
3244 int n_patches
, pindex
;
3250 symbol
= g_strdup_printf ("%s", name
);
3251 find_symbol (amodule
->sofile
, amodule
->globals
, symbol
, (gpointer
*)&code
);
3254 g_error ("Symbol '%s' not found in AOT file '%s'.\n", name
, amodule
->aot_name
);
3256 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_AOT
, "AOT FOUND function '%s' in AOT file '%s'.\n", name
, amodule
->aot_name
);
3260 symbol
= g_strdup_printf ("%s_p", name
);
3261 find_symbol (amodule
->sofile
, amodule
->globals
, symbol
, (gpointer
*)&p
);
3264 /* Nothing to patch */
3267 p
= amodule
->blob
+ *(guint32
*)p
;
3269 /* Similar to mono_aot_load_method () */
3271 n_patches
= decode_value (p
, &p
);
3274 MonoJumpInfo
*patches
;
3277 mp
= mono_mempool_new ();
3279 patches
= load_patch_info (amodule
, mp
, n_patches
, &got_slots
, p
, &p
);
3282 for (pindex
= 0; pindex
< n_patches
; ++pindex
) {
3283 MonoJumpInfo
*ji
= &patches
[pindex
];
3286 if (amodule
->got
[got_slots
[pindex
]])
3290 * When this code is executed, the runtime may not be initalized yet, so
3291 * resolve the patch info by hand.
3293 if (ji
->type
== MONO_PATCH_INFO_JIT_ICALL_ADDR
) {
3294 if (!strcmp (ji
->data
.name
, "mono_get_lmf_addr")) {
3295 target
= mono_get_lmf_addr
;
3296 } else if (!strcmp (ji
->data
.name
, "mono_thread_force_interruption_checkpoint")) {
3297 target
= mono_thread_force_interruption_checkpoint
;
3298 } else if (!strcmp (ji
->data
.name
, "mono_exception_from_token")) {
3299 target
= mono_exception_from_token
;
3300 } else if (!strcmp (ji
->data
.name
, "mono_throw_exception")) {
3301 target
= mono_get_throw_exception ();
3303 } else if (!strcmp (ji
->data
.name
, "mono_amd64_throw_exception")) {
3304 target
= mono_amd64_throw_exception
;
3307 } else if (!strcmp (ji
->data
.name
, "mono_amd64_get_original_ip")) {
3308 target
= mono_amd64_get_original_ip
;
3311 } else if (!strcmp (ji
->data
.name
, "mono_arm_throw_exception")) {
3312 target
= mono_arm_throw_exception
;
3313 } else if (!strcmp (ji
->data
.name
, "mono_arm_throw_exception_by_token")) {
3314 target
= mono_arm_throw_exception_by_token
;
3317 } else if (!strcmp (ji
->data
.name
, "mono_ppc_throw_exception")) {
3318 target
= mono_ppc_throw_exception
;
3320 } else if (strstr (ji
->data
.name
, "trampoline_func_") == ji
->data
.name
) {
3321 int tramp_type2
= atoi (ji
->data
.name
+ strlen ("trampoline_func_"));
3322 target
= (gpointer
)mono_get_trampoline_func (tramp_type2
);
3323 } else if (strstr (ji
->data
.name
, "specific_trampoline_lazy_fetch_") == ji
->data
.name
) {
3324 /* atoll is needed because the the offset is unsigned */
3328 res
= sscanf (ji
->data
.name
, "specific_trampoline_lazy_fetch_%u", &slot
);
3329 g_assert (res
== 1);
3330 target
= mono_create_specific_trampoline (GUINT_TO_POINTER (slot
), MONO_TRAMPOLINE_RGCTX_LAZY_FETCH
, mono_get_root_domain (), NULL
);
3331 target
= mono_create_ftnptr_malloc (target
);
3332 } else if (!strcmp (ji
->data
.name
, "specific_trampoline_monitor_enter")) {
3333 target
= mono_create_specific_trampoline (NULL
, MONO_TRAMPOLINE_MONITOR_ENTER
, mono_get_root_domain (), NULL
);
3334 target
= mono_create_ftnptr_malloc (target
);
3335 } else if (!strcmp (ji
->data
.name
, "specific_trampoline_monitor_exit")) {
3336 target
= mono_create_specific_trampoline (NULL
, MONO_TRAMPOLINE_MONITOR_EXIT
, mono_get_root_domain (), NULL
);
3337 target
= mono_create_ftnptr_malloc (target
);
3338 } else if (!strcmp (ji
->data
.name
, "specific_trampoline_generic_class_init")) {
3339 target
= mono_create_specific_trampoline (NULL
, MONO_TRAMPOLINE_GENERIC_CLASS_INIT
, mono_get_root_domain (), NULL
);
3340 target
= mono_create_ftnptr_malloc (target
);
3341 } else if (!strcmp (ji
->data
.name
, "mono_thread_get_and_clear_pending_exception")) {
3342 target
= mono_thread_get_and_clear_pending_exception
;
3344 fprintf (stderr
, "Unknown relocation '%s'\n", ji
->data
.name
);
3345 g_assert_not_reached ();
3349 /* Hopefully the code doesn't have patches which need method or
3352 target
= mono_resolve_patch_target (NULL
, NULL
, code
, ji
, FALSE
);
3356 amodule
->got
[got_slots
[pindex
]] = target
;
3361 mono_mempool_destroy (mp
);
3368 * Return the piece of code identified by NAME from the mscorlib AOT file.
3369 * On ppc64, this returns a function descriptor.
3372 mono_aot_get_named_code (const char *name
)
3375 MonoAotModule
*amodule
;
3377 image
= mono_defaults
.corlib
;
3380 amodule
= image
->aot_module
;
3383 return mono_create_ftnptr_malloc (load_function (amodule
, name
));
3386 /* Return a given kind of trampoline */
3388 get_numerous_trampoline (MonoAotTrampoline tramp_type
, int n_got_slots
, MonoAotModule
**out_amodule
, guint32
*got_offset
, guint32
*out_tramp_size
)
3390 MonoAotModule
*amodule
;
3391 int index
, tramp_size
;
3394 /* Currently, we keep all trampolines in the mscorlib AOT image */
3395 image
= mono_defaults
.corlib
;
3400 amodule
= image
->aot_module
;
3403 *out_amodule
= amodule
;
3405 if (amodule
->trampoline_index
[tramp_type
] == amodule
->info
.num_trampolines
[tramp_type
])
3406 g_error ("Ran out of trampolines of type %d in '%s' (%d)\n", tramp_type
, image
->name
, amodule
->info
.num_trampolines
[tramp_type
]);
3408 index
= amodule
->trampoline_index
[tramp_type
] ++;
3412 *got_offset
= amodule
->info
.trampoline_got_offset_base
[tramp_type
] + (index
* n_got_slots
);
3414 tramp_size
= amodule
->info
.trampoline_size
[tramp_type
];
3417 *out_tramp_size
= tramp_size
;
3419 return amodule
->trampolines
[tramp_type
] + (index
* tramp_size
);
3423 * Return a specific trampoline from the AOT file.
3426 mono_aot_create_specific_trampoline (MonoImage
*image
, gpointer arg1
, MonoTrampolineType tramp_type
, MonoDomain
*domain
, guint32
*code_len
)
3428 MonoAotModule
*amodule
;
3429 guint32 got_offset
, tramp_size
;
3430 guint8
*code
, *tramp
;
3431 static gpointer generic_trampolines
[MONO_TRAMPOLINE_NUM
];
3432 static gboolean inited
;
3433 static guint32 num_trampolines
;
3439 mono_counters_register ("Specific trampolines", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &num_trampolines
);
3448 if (!generic_trampolines
[tramp_type
]) {
3451 symbol
= g_strdup_printf ("generic_trampoline_%d", tramp_type
);
3452 generic_trampolines
[tramp_type
] = mono_aot_get_named_code (symbol
);
3456 tramp
= generic_trampolines
[tramp_type
];
3459 code
= get_numerous_trampoline (MONO_AOT_TRAMP_SPECIFIC
, 2, &amodule
, &got_offset
, &tramp_size
);
3461 amodule
->got
[got_offset
] = tramp
;
3462 amodule
->got
[got_offset
+ 1] = arg1
;
3465 *code_len
= tramp_size
;
3471 mono_aot_get_static_rgctx_trampoline (gpointer ctx
, gpointer addr
)
3473 MonoAotModule
*amodule
;
3477 code
= get_numerous_trampoline (MONO_AOT_TRAMP_STATIC_RGCTX
, 2, &amodule
, &got_offset
, NULL
);
3479 amodule
->got
[got_offset
] = ctx
;
3480 amodule
->got
[got_offset
+ 1] = addr
;
3482 /* The caller expects an ftnptr */
3483 return mono_create_ftnptr (mono_domain_get (), code
);
3487 mono_aot_get_unbox_trampoline (MonoMethod
*method
)
3489 guint32 method_index
= mono_metadata_token_index (method
->token
) - 1;
3490 MonoAotModule
*amodule
;
3494 if (method
->is_inflated
&& !mono_method_is_generic_sharable_impl (method
, FALSE
)) {
3495 guint32 index
= find_extra_method (method
, &amodule
);
3496 g_assert (index
!= 0xffffff);
3498 symbol
= g_strdup_printf ("ut_e_%d", index
);
3500 amodule
= method
->klass
->image
->aot_module
;
3503 symbol
= g_strdup_printf ("ut_%d", method_index
);
3505 code
= load_function (amodule
, symbol
);
3508 /* The caller expects an ftnptr */
3509 return mono_create_ftnptr (mono_domain_get (), code
);
3513 mono_aot_get_lazy_fetch_trampoline (guint32 slot
)
3518 symbol
= g_strdup_printf ("rgctx_fetch_trampoline_%u", slot
);
3519 code
= load_function (mono_defaults
.corlib
->aot_module
, symbol
);
3521 /* The caller expects an ftnptr */
3522 return mono_create_ftnptr (mono_domain_get (), code
);
3526 mono_aot_get_imt_thunk (MonoVTable
*vtable
, MonoDomain
*domain
, MonoIMTCheckItem
**imt_entries
, int count
, gpointer fail_tramp
)
3532 MonoAotModule
*amodule
;
3534 code
= get_numerous_trampoline (MONO_AOT_TRAMP_IMT_THUNK
, 1, &amodule
, &got_offset
, NULL
);
3536 /* Save the entries into an array */
3537 buf
= mono_domain_alloc (domain
, (count
+ 1) * 2 * sizeof (gpointer
));
3538 for (i
= 0; i
< count
; ++i
) {
3539 MonoIMTCheckItem
*item
= imt_entries
[i
];
3541 g_assert (item
->key
);
3543 g_assert (!item
->has_target_code
);
3545 buf
[(i
* 2)] = item
->key
;
3546 buf
[(i
* 2) + 1] = &(vtable
->vtable
[item
->value
.vtable_slot
]);
3548 buf
[(count
* 2)] = NULL
;
3549 buf
[(count
* 2) + 1] = fail_tramp
;
3551 amodule
->got
[got_offset
] = buf
;
3560 mono_aot_init (void)
3565 mono_aot_get_method (MonoDomain
*domain
, MonoMethod
*method
)
3571 mono_aot_is_got_entry (guint8
*code
, guint8
*addr
)
3577 mono_aot_get_cached_class_info (MonoClass
*klass
, MonoCachedClassInfo
*res
)
3583 mono_aot_get_class_from_name (MonoImage
*image
, const char *name_space
, const char *name
, MonoClass
**klass
)
3589 mono_aot_find_jit_info (MonoDomain
*domain
, MonoImage
*image
, gpointer addr
)
3595 mono_aot_get_method_from_token (MonoDomain
*domain
, MonoImage
*image
, guint32 token
)
3601 mono_aot_get_plt_entry (guint8
*code
)
3607 mono_aot_plt_resolve (gpointer aot_module
, guint32 plt_info_offset
, guint8
*code
)
3613 mono_aot_get_method_from_vt_slot (MonoDomain
*domain
, MonoVTable
*vtable
, int slot
)
3619 mono_aot_get_plt_info_offset (mgreg_t
*regs
, guint8
*code
)
3621 g_assert_not_reached ();
3627 mono_aot_create_specific_trampoline (MonoImage
*image
, gpointer arg1
, MonoTrampolineType tramp_type
, MonoDomain
*domain
, guint32
*code_len
)
3629 g_assert_not_reached ();
3634 mono_aot_get_static_rgctx_trampoline (gpointer ctx
, gpointer addr
)
3636 g_assert_not_reached ();
3641 mono_aot_get_named_code (const char *name
)
3643 g_assert_not_reached ();
3648 mono_aot_get_unbox_trampoline (MonoMethod
*method
)
3650 g_assert_not_reached ();
3655 mono_aot_get_lazy_fetch_trampoline (guint32 slot
)
3657 g_assert_not_reached ();
3662 mono_aot_get_imt_thunk (MonoVTable
*vtable
, MonoDomain
*domain
, MonoIMTCheckItem
**imt_entries
, int count
, gpointer fail_tramp
)
3664 g_assert_not_reached ();
3669 mono_aot_get_unwind_info (MonoJitInfo
*ji
, guint32
*unwind_info_len
)
3671 g_assert_not_reached ();