2 * mini.c: The new Mono code generator.
5 * Paolo Molaro (lupus@ximian.com)
6 * Dietmar Maurer (dietmar@ximian.com)
8 * (C) 2002 Ximian, Inc.
20 #ifdef HAVE_SYS_TIME_H
24 #ifdef HAVE_VALGRIND_MEMCHECK_H
25 #include <valgrind/memcheck.h>
28 #include <mono/metadata/assembly.h>
29 #include <mono/metadata/loader.h>
30 #include <mono/metadata/tabledefs.h>
31 #include <mono/metadata/class.h>
32 #include <mono/metadata/object.h>
33 #include <mono/metadata/tokentype.h>
34 #include <mono/metadata/tabledefs.h>
35 #include <mono/metadata/threads.h>
36 #include <mono/metadata/appdomain.h>
37 #include <mono/metadata/debug-helpers.h>
38 #include <mono/io-layer/io-layer.h>
39 #include "mono/metadata/profiler.h"
40 #include <mono/metadata/profiler-private.h>
41 #include <mono/metadata/mono-config.h>
42 #include <mono/metadata/environment.h>
43 #include <mono/metadata/mono-debug.h>
44 #include <mono/metadata/gc-internal.h>
45 #include <mono/metadata/threads-types.h>
46 #include <mono/metadata/verify.h>
47 #include <mono/metadata/verify-internals.h>
48 #include <mono/metadata/mempool-internals.h>
49 #include <mono/metadata/attach.h>
50 #include <mono/utils/mono-math.h>
51 #include <mono/utils/mono-compiler.h>
52 #include <mono/utils/mono-counters.h>
53 #include <mono/utils/mono-logger.h>
54 #include <mono/utils/mono-mmap.h>
55 #include <mono/utils/dtrace.h>
63 #include "jit-icalls.h"
65 #include "debug-mini.h"
67 static gpointer
mono_jit_compile_method_with_opt (MonoMethod
*method
, guint32 opt
);
68 static gpointer
mono_jit_compile_method (MonoMethod
*method
);
70 /* helper methods signature */
71 /* FIXME: Make these static again */
72 MonoMethodSignature
*helper_sig_class_init_trampoline
= NULL
;
73 MonoMethodSignature
*helper_sig_domain_get
= NULL
;
74 MonoMethodSignature
*helper_sig_generic_class_init_trampoline
= NULL
;
75 MonoMethodSignature
*helper_sig_rgctx_lazy_fetch_trampoline
= NULL
;
76 MonoMethodSignature
*helper_sig_monitor_enter_exit_trampoline
= NULL
;
78 static guint32 default_opt
= 0;
79 static gboolean default_opt_set
= FALSE
;
81 guint32 mono_jit_tls_id
= -1;
84 static __thread gpointer mono_jit_tls MONO_TLS_FAST
;
87 MonoTraceSpec
*mono_jit_trace_calls
= NULL
;
88 gboolean mono_break_on_exc
= FALSE
;
89 gboolean mono_compile_aot
= FALSE
;
90 /* If this is set, no code is generated dynamically, everything is taken from AOT files */
91 gboolean mono_aot_only
= FALSE
;
92 /* Whenever to use IMT */
93 #ifdef MONO_ARCH_HAVE_IMT
94 gboolean mono_use_imt
= TRUE
;
96 gboolean mono_use_imt
= FALSE
;
98 MonoMethodDesc
*mono_inject_async_exc_method
= NULL
;
99 int mono_inject_async_exc_pos
;
100 MonoMethodDesc
*mono_break_at_bb_method
= NULL
;
101 int mono_break_at_bb_bb_num
;
102 gboolean mono_do_x86_stack_align
= TRUE
;
103 const char *mono_build_date
;
104 gboolean mono_do_signal_chaining
;
106 static int mini_verbose
= 0;
108 #define mono_jit_lock() EnterCriticalSection (&jit_mutex)
109 #define mono_jit_unlock() LeaveCriticalSection (&jit_mutex)
110 static CRITICAL_SECTION jit_mutex
;
112 static MonoCodeManager
*global_codeman
= NULL
;
114 /* FIXME: Make this static again */
115 GHashTable
*jit_icall_name_hash
= NULL
;
117 static MonoDebugOptions debug_options
;
119 #ifdef VALGRIND_JIT_REGISTER_MAP
120 static int valgrind_register
= 0;
124 * Table written to by the debugger with a 1-based index into the
125 * mono_breakpoint_info table, which contains changes made to
126 * the JIT instructions by the debugger.
129 mono_breakpoint_info_index
[MONO_BREAKPOINT_ARRAY_SIZE
];
131 /* Whenever to check for pending exceptions in managed-to-native wrappers */
132 gboolean check_for_pending_exc
= TRUE
;
134 /* Whenever to disable passing/returning small valuetypes in registers for managed methods */
135 gboolean disable_vtypes_in_regs
= FALSE
;
137 gboolean mono_dont_free_global_codeman
;
140 mono_running_on_valgrind (void)
142 #ifdef HAVE_VALGRIND_MEMCHECK_H
143 if (RUNNING_ON_VALGRIND
){
144 #ifdef VALGRIND_JIT_REGISTER_MAP
145 valgrind_register
= TRUE
;
161 find_tramp (gpointer key
, gpointer value
, gpointer user_data
)
163 FindTrampUserData
*ud
= (FindTrampUserData
*)user_data
;
166 ud
->method
= (MonoMethod
*)key
;
170 G_GNUC_UNUSED
static char*
171 get_method_from_ip (void *ip
)
176 MonoDomain
*domain
= mono_domain_get ();
177 MonoDebugSourceLocation
*location
;
178 FindTrampUserData user_data
;
180 ji
= mono_jit_info_table_find (domain
, ip
);
183 user_data
.method
= NULL
;
184 mono_domain_lock (domain
);
185 g_hash_table_foreach (domain_jit_info (domain
)->jit_trampoline_hash
, find_tramp
, &user_data
);
186 mono_domain_unlock (domain
);
187 if (user_data
.method
) {
188 char *mname
= mono_method_full_name (user_data
.method
, TRUE
);
189 res
= g_strdup_printf ("<%p - JIT trampoline for %s>", ip
, mname
);
196 method
= mono_method_full_name (ji
->method
, TRUE
);
197 /* FIXME: unused ? */
198 location
= mono_debug_lookup_source_location (ji
->method
, (guint32
)((guint8
*)ip
- (guint8
*)ji
->code_start
), domain
);
200 res
= g_strdup_printf (" %s + 0x%x (%p %p) [%p - %s]", method
, (int)((char*)ip
- (char*)ji
->code_start
), ji
->code_start
, (char*)ji
->code_start
+ ji
->code_size
, domain
, domain
->friendly_name
);
202 mono_debug_free_source_location (location
);
210 * @ip: an instruction pointer address
212 * This method is used from a debugger to get the name of the
213 * method at address @ip. This routine is typically invoked from
214 * a debugger like this:
216 * (gdb) print mono_pmip ($pc)
218 * Returns: the name of the method at address @ip.
223 return get_method_from_ip (ip
);
227 * mono_print_method_from_ip
228 * @ip: an instruction pointer address
230 * This method is used from a debugger to get the name of the
231 * method at address @ip.
233 * This prints the name of the method at address @ip in the standard
234 * output. Unlike mono_pmip which returns a string, this routine
235 * prints the value on the standard output.
238 mono_print_method_from_ip (void *ip
)
242 MonoDebugSourceLocation
*source
;
243 MonoDomain
*domain
= mono_domain_get ();
244 FindTrampUserData user_data
;
246 ji
= mono_jit_info_table_find (domain
, ip
);
249 user_data
.method
= NULL
;
250 mono_domain_lock (domain
);
251 g_hash_table_foreach (domain_jit_info (domain
)->jit_trampoline_hash
, find_tramp
, &user_data
);
252 mono_domain_unlock (domain
);
253 if (user_data
.method
) {
254 char *mname
= mono_method_full_name (user_data
.method
, TRUE
);
255 printf ("IP %p is a JIT trampoline for %s\n", ip
, mname
);
259 g_print ("No method at %p\n", ip
);
262 method
= mono_method_full_name (ji
->method
, TRUE
);
263 source
= mono_debug_lookup_source_location (ji
->method
, (guint32
)((guint8
*)ip
- (guint8
*)ji
->code_start
), domain
);
265 g_print ("IP %p at offset 0x%x of method %s (%p %p)[domain %p - %s]\n", ip
, (int)((char*)ip
- (char*)ji
->code_start
), method
, ji
->code_start
, (char*)ji
->code_start
+ ji
->code_size
, domain
, domain
->friendly_name
);
268 g_print ("%s:%d\n", source
->source_file
, source
->row
);
270 mono_debug_free_source_location (source
);
275 * mono_method_same_domain:
277 * Determine whenever two compiled methods are in the same domain, thus
278 * the address of the callee can be embedded in the caller.
280 gboolean
mono_method_same_domain (MonoJitInfo
*caller
, MonoJitInfo
*callee
)
282 if (!caller
|| !callee
)
286 * If the call was made from domain-neutral to domain-specific
287 * code, we can't patch the call site.
289 if (caller
->domain_neutral
&& !callee
->domain_neutral
)
292 if ((caller
->method
->klass
== mono_defaults
.appdomain_class
) &&
293 (strstr (caller
->method
->name
, "InvokeInDomain"))) {
294 /* The InvokeInDomain methods change the current appdomain */
302 * mono_global_codeman_reserve:
304 * Allocate code memory from the global code manager.
306 void *mono_global_codeman_reserve (int size
)
311 g_error ("Attempting to allocate from the global code manager while running with --aot-only.\n");
313 if (!global_codeman
) {
314 /* This can happen during startup */
315 global_codeman
= mono_code_manager_new ();
316 return mono_code_manager_reserve (global_codeman
, size
);
320 ptr
= mono_code_manager_reserve (global_codeman
, size
);
327 * mono_create_unwind_op:
329 * Create an unwind op with the given parameters.
332 mono_create_unwind_op (int when
, int tag
, int reg
, int val
)
334 MonoUnwindOp
*op
= g_new0 (MonoUnwindOp
, 1);
345 * mono_emit_unwind_op:
347 * Add an unwind op with the given parameters for the list of unwind ops stored in
351 mono_emit_unwind_op (MonoCompile
*cfg
, int when
, int tag
, int reg
, int val
)
353 MonoUnwindOp
*op
= mono_mempool_alloc0 (cfg
->mempool
, sizeof (MonoUnwindOp
));
360 cfg
->unwind_ops
= g_slist_append_mempool (cfg
->mempool
, cfg
->unwind_ops
, op
);
364 mono_jump_info_token_new2 (MonoMemPool
*mp
, MonoImage
*image
, guint32 token
, MonoGenericContext
*context
)
366 MonoJumpInfoToken
*res
= mono_mempool_alloc0 (mp
, sizeof (MonoJumpInfoToken
));
369 res
->has_context
= context
!= NULL
;
371 memcpy (&res
->context
, context
, sizeof (MonoGenericContext
));
377 mono_jump_info_token_new (MonoMemPool
*mp
, MonoImage
*image
, guint32 token
)
379 return mono_jump_info_token_new2 (mp
, image
, token
, NULL
);
382 #define MONO_INIT_VARINFO(vi,id) do { \
383 (vi)->range.first_use.pos.bid = 0xffff; \
389 * mono_unlink_bblock:
391 * Unlink two basic blocks.
394 mono_unlink_bblock (MonoCompile
*cfg
, MonoBasicBlock
*from
, MonoBasicBlock
* to
)
400 for (i
= 0; i
< from
->out_count
; ++i
) {
401 if (to
== from
->out_bb
[i
]) {
408 for (i
= 0; i
< from
->out_count
; ++i
) {
409 if (from
->out_bb
[i
] != to
)
410 from
->out_bb
[pos
++] = from
->out_bb
[i
];
412 g_assert (pos
== from
->out_count
- 1);
417 for (i
= 0; i
< to
->in_count
; ++i
) {
418 if (from
== to
->in_bb
[i
]) {
425 for (i
= 0; i
< to
->in_count
; ++i
) {
426 if (to
->in_bb
[i
] != from
)
427 to
->in_bb
[pos
++] = to
->in_bb
[i
];
429 g_assert (pos
== to
->in_count
- 1);
435 * mono_bblocks_linked:
437 * Return whenever BB1 and BB2 are linked in the CFG.
440 mono_bblocks_linked (MonoBasicBlock
*bb1
, MonoBasicBlock
*bb2
)
444 for (i
= 0; i
< bb1
->out_count
; ++i
) {
445 if (bb1
->out_bb
[i
] == bb2
)
453 mono_find_spvar_for_region (MonoCompile
*cfg
, int region
)
455 return g_hash_table_lookup (cfg
->spvars
, GINT_TO_POINTER (region
));
459 mono_find_exvar_for_offset (MonoCompile
*cfg
, int offset
)
461 return g_hash_table_lookup (cfg
->exvars
, GINT_TO_POINTER (offset
));
465 df_visit (MonoBasicBlock
*start
, int *dfn
, MonoBasicBlock
**array
)
469 array
[*dfn
] = start
;
470 /* g_print ("visit %d at %p (BB%ld)\n", *dfn, start->cil_code, start->block_num); */
471 for (i
= 0; i
< start
->out_count
; ++i
) {
472 if (start
->out_bb
[i
]->dfn
)
475 start
->out_bb
[i
]->dfn
= *dfn
;
476 start
->out_bb
[i
]->df_parent
= start
;
477 array
[*dfn
] = start
->out_bb
[i
];
478 df_visit (start
->out_bb
[i
], dfn
, array
);
483 mono_reverse_branch_op (guint32 opcode
)
485 static const int reverse_map
[] = {
486 CEE_BNE_UN
, CEE_BLT
, CEE_BLE
, CEE_BGT
, CEE_BGE
,
487 CEE_BEQ
, CEE_BLT_UN
, CEE_BLE_UN
, CEE_BGT_UN
, CEE_BGE_UN
489 static const int reverse_fmap
[] = {
490 OP_FBNE_UN
, OP_FBLT
, OP_FBLE
, OP_FBGT
, OP_FBGE
,
491 OP_FBEQ
, OP_FBLT_UN
, OP_FBLE_UN
, OP_FBGT_UN
, OP_FBGE_UN
493 static const int reverse_lmap
[] = {
494 OP_LBNE_UN
, OP_LBLT
, OP_LBLE
, OP_LBGT
, OP_LBGE
,
495 OP_LBEQ
, OP_LBLT_UN
, OP_LBLE_UN
, OP_LBGT_UN
, OP_LBGE_UN
497 static const int reverse_imap
[] = {
498 OP_IBNE_UN
, OP_IBLT
, OP_IBLE
, OP_IBGT
, OP_IBGE
,
499 OP_IBEQ
, OP_IBLT_UN
, OP_IBLE_UN
, OP_IBGT_UN
, OP_IBGE_UN
502 if (opcode
>= CEE_BEQ
&& opcode
<= CEE_BLT_UN
) {
503 opcode
= reverse_map
[opcode
- CEE_BEQ
];
504 } else if (opcode
>= OP_FBEQ
&& opcode
<= OP_FBLT_UN
) {
505 opcode
= reverse_fmap
[opcode
- OP_FBEQ
];
506 } else if (opcode
>= OP_LBEQ
&& opcode
<= OP_LBLT_UN
) {
507 opcode
= reverse_lmap
[opcode
- OP_LBEQ
];
508 } else if (opcode
>= OP_IBEQ
&& opcode
<= OP_IBLT_UN
) {
509 opcode
= reverse_imap
[opcode
- OP_IBEQ
];
511 g_assert_not_reached ();
517 mono_type_to_store_membase (MonoCompile
*cfg
, MonoType
*type
)
520 return OP_STORE_MEMBASE_REG
;
523 switch (type
->type
) {
526 case MONO_TYPE_BOOLEAN
:
527 return OP_STOREI1_MEMBASE_REG
;
531 return OP_STOREI2_MEMBASE_REG
;
534 return OP_STOREI4_MEMBASE_REG
;
538 case MONO_TYPE_FNPTR
:
539 return OP_STORE_MEMBASE_REG
;
540 case MONO_TYPE_CLASS
:
541 case MONO_TYPE_STRING
:
542 case MONO_TYPE_OBJECT
:
543 case MONO_TYPE_SZARRAY
:
544 case MONO_TYPE_ARRAY
:
545 return OP_STORE_MEMBASE_REG
;
548 return OP_STOREI8_MEMBASE_REG
;
550 return OP_STORER4_MEMBASE_REG
;
552 return OP_STORER8_MEMBASE_REG
;
553 case MONO_TYPE_VALUETYPE
:
554 if (type
->data
.klass
->enumtype
) {
555 type
= mono_class_enum_basetype (type
->data
.klass
);
558 if (MONO_CLASS_IS_SIMD (cfg
, mono_class_from_mono_type (type
)))
559 return OP_STOREX_MEMBASE
;
560 return OP_STOREV_MEMBASE
;
561 case MONO_TYPE_TYPEDBYREF
:
562 return OP_STOREV_MEMBASE
;
563 case MONO_TYPE_GENERICINST
:
564 type
= &type
->data
.generic_class
->container_class
->byval_arg
;
568 /* FIXME: all the arguments must be references for now,
569 * later look inside cfg and see if the arg num is
572 g_assert (cfg
->generic_sharing_context
);
573 return OP_STORE_MEMBASE_REG
;
575 g_error ("unknown type 0x%02x in type_to_store_membase", type
->type
);
581 mono_type_to_load_membase (MonoCompile
*cfg
, MonoType
*type
)
584 return OP_LOAD_MEMBASE
;
586 switch (mono_type_get_underlying_type (type
)->type
) {
588 return OP_LOADI1_MEMBASE
;
590 case MONO_TYPE_BOOLEAN
:
591 return OP_LOADU1_MEMBASE
;
593 return OP_LOADI2_MEMBASE
;
596 return OP_LOADU2_MEMBASE
;
598 return OP_LOADI4_MEMBASE
;
600 return OP_LOADU4_MEMBASE
;
604 case MONO_TYPE_FNPTR
:
605 return OP_LOAD_MEMBASE
;
606 case MONO_TYPE_CLASS
:
607 case MONO_TYPE_STRING
:
608 case MONO_TYPE_OBJECT
:
609 case MONO_TYPE_SZARRAY
:
610 case MONO_TYPE_ARRAY
:
611 return OP_LOAD_MEMBASE
;
614 return OP_LOADI8_MEMBASE
;
616 return OP_LOADR4_MEMBASE
;
618 return OP_LOADR8_MEMBASE
;
619 case MONO_TYPE_VALUETYPE
:
620 if (MONO_CLASS_IS_SIMD (cfg
, mono_class_from_mono_type (type
)))
621 return OP_LOADX_MEMBASE
;
622 case MONO_TYPE_TYPEDBYREF
:
623 return OP_LOADV_MEMBASE
;
624 case MONO_TYPE_GENERICINST
:
625 if (mono_type_generic_inst_is_valuetype (type
))
626 return OP_LOADV_MEMBASE
;
628 return OP_LOAD_MEMBASE
;
632 /* FIXME: all the arguments must be references for now,
633 * later look inside cfg and see if the arg num is
636 g_assert (cfg
->generic_sharing_context
);
637 return OP_LOAD_MEMBASE
;
639 g_error ("unknown type 0x%02x in type_to_load_membase", type
->type
);
645 mini_type_to_ldind (MonoCompile
* cfg
, MonoType
*type
)
647 if (cfg
->generic_sharing_context
&& !type
->byref
) {
648 /* FIXME: all the arguments must be references for now,
649 * later look inside cfg and see if the arg num is
652 if (type
->type
== MONO_TYPE_VAR
|| type
->type
== MONO_TYPE_MVAR
)
653 return CEE_LDIND_REF
;
655 return mono_type_to_ldind (type
);
659 mini_type_to_stind (MonoCompile
* cfg
, MonoType
*type
)
661 if (cfg
->generic_sharing_context
&& !type
->byref
) {
662 /* FIXME: all the arguments must be references for now,
663 * later look inside cfg and see if the arg num is
666 if (type
->type
== MONO_TYPE_VAR
|| type
->type
== MONO_TYPE_MVAR
)
667 return CEE_STIND_REF
;
669 return mono_type_to_stind (type
);
673 mono_op_imm_to_op (int opcode
)
677 #if SIZEOF_REGISTER == 4
693 #if SIZEOF_REGISTER == 4
731 #if SIZEOF_REGISTER == 4
737 #if SIZEOF_REGISTER == 4
756 case OP_ICOMPARE_IMM
:
758 case OP_LOCALLOC_IMM
:
761 printf ("%s\n", mono_inst_name (opcode
));
762 g_assert_not_reached ();
768 * mono_decompose_op_imm:
770 * Replace the OP_.._IMM INS with its non IMM variant.
773 mono_decompose_op_imm (MonoCompile
*cfg
, MonoBasicBlock
*bb
, MonoInst
*ins
)
777 MONO_INST_NEW (cfg
, temp
, OP_ICONST
);
778 temp
->inst_c0
= ins
->inst_imm
;
779 temp
->dreg
= mono_alloc_ireg (cfg
);
780 mono_bblock_insert_before_ins (bb
, ins
, temp
);
781 ins
->opcode
= mono_op_imm_to_op (ins
->opcode
);
782 if (ins
->opcode
== OP_LOCALLOC
)
783 ins
->sreg1
= temp
->dreg
;
785 ins
->sreg2
= temp
->dreg
;
787 bb
->max_vreg
= MAX (bb
->max_vreg
, cfg
->next_vreg
);
791 set_vreg_to_inst (MonoCompile
*cfg
, int vreg
, MonoInst
*inst
)
793 if (vreg
>= cfg
->vreg_to_inst_len
) {
794 MonoInst
**tmp
= cfg
->vreg_to_inst
;
795 int size
= cfg
->vreg_to_inst_len
;
797 while (vreg
>= cfg
->vreg_to_inst_len
)
798 cfg
->vreg_to_inst_len
= cfg
->vreg_to_inst_len
? cfg
->vreg_to_inst_len
* 2 : 32;
799 cfg
->vreg_to_inst
= mono_mempool_alloc0 (cfg
->mempool
, sizeof (MonoInst
*) * cfg
->vreg_to_inst_len
);
801 memcpy (cfg
->vreg_to_inst
, tmp
, size
* sizeof (MonoInst
*));
803 cfg
->vreg_to_inst
[vreg
] = inst
;
806 #define mono_type_is_long(type) (!(type)->byref && ((mono_type_get_underlying_type (type)->type == MONO_TYPE_I8) || (mono_type_get_underlying_type (type)->type == MONO_TYPE_U8)))
807 #define mono_type_is_float(type) (!(type)->byref && (((type)->type == MONO_TYPE_R8) || ((type)->type == MONO_TYPE_R4)))
812 mono_compile_create_var (MonoCompile
*cfg
, MonoType
*type
, int opcode
)
820 mono_compile_create_var_for_vreg (MonoCompile
*cfg
, MonoType
*type
, int opcode
, int vreg
)
823 int num
= cfg
->num_varinfo
;
826 if ((num
+ 1) >= cfg
->varinfo_count
) {
827 int orig_count
= cfg
->varinfo_count
;
828 cfg
->varinfo_count
= cfg
->varinfo_count
? (cfg
->varinfo_count
* 2) : 64;
829 cfg
->varinfo
= (MonoInst
**)g_realloc (cfg
->varinfo
, sizeof (MonoInst
*) * cfg
->varinfo_count
);
830 cfg
->vars
= (MonoMethodVar
*)g_realloc (cfg
->vars
, sizeof (MonoMethodVar
) * cfg
->varinfo_count
);
831 memset (&cfg
->vars
[orig_count
], 0, (cfg
->varinfo_count
- orig_count
) * sizeof (MonoMethodVar
));
834 mono_jit_stats
.allocate_var
++;
836 MONO_INST_NEW (cfg
, inst
, opcode
);
838 inst
->inst_vtype
= type
;
839 inst
->klass
= mono_class_from_mono_type (type
);
840 type_to_eval_stack_type (cfg
, type
, inst
);
841 /* if set to 1 the variable is native */
842 inst
->backend
.is_pinvoke
= 0;
845 cfg
->varinfo
[num
] = inst
;
847 MONO_INIT_VARINFO (&cfg
->vars
[num
], num
);
848 MONO_VARINFO (cfg
, num
)->vreg
= vreg
;
851 set_vreg_to_inst (cfg
, vreg
, inst
);
853 #if SIZEOF_REGISTER == 4
854 #ifdef MONO_ARCH_SOFT_FLOAT
855 regpair
= mono_type_is_long (type
) || mono_type_is_float (type
);
857 regpair
= mono_type_is_long (type
);
867 * These two cannot be allocated using create_var_for_vreg since that would
868 * put it into the cfg->varinfo array, confusing many parts of the JIT.
872 * Set flags to VOLATILE so SSA skips it.
875 if (cfg
->verbose_level
>= 4) {
876 printf (" Create LVAR R%d (R%d, R%d)\n", inst
->dreg
, inst
->dreg
+ 1, inst
->dreg
+ 2);
879 #ifdef MONO_ARCH_SOFT_FLOAT
880 if (cfg
->opt
& MONO_OPT_SSA
) {
881 if (mono_type_is_float (type
))
882 inst
->flags
= MONO_INST_VOLATILE
;
886 /* Allocate a dummy MonoInst for the first vreg */
887 MONO_INST_NEW (cfg
, tree
, OP_LOCAL
);
888 tree
->dreg
= inst
->dreg
+ 1;
889 if (cfg
->opt
& MONO_OPT_SSA
)
890 tree
->flags
= MONO_INST_VOLATILE
;
892 tree
->type
= STACK_I4
;
893 tree
->inst_vtype
= &mono_defaults
.int32_class
->byval_arg
;
894 tree
->klass
= mono_class_from_mono_type (tree
->inst_vtype
);
896 set_vreg_to_inst (cfg
, inst
->dreg
+ 1, tree
);
898 /* Allocate a dummy MonoInst for the second vreg */
899 MONO_INST_NEW (cfg
, tree
, OP_LOCAL
);
900 tree
->dreg
= inst
->dreg
+ 2;
901 if (cfg
->opt
& MONO_OPT_SSA
)
902 tree
->flags
= MONO_INST_VOLATILE
;
904 tree
->type
= STACK_I4
;
905 tree
->inst_vtype
= &mono_defaults
.int32_class
->byval_arg
;
906 tree
->klass
= mono_class_from_mono_type (tree
->inst_vtype
);
908 set_vreg_to_inst (cfg
, inst
->dreg
+ 2, tree
);
912 if (cfg
->verbose_level
> 2)
913 g_print ("created temp %d (R%d) of type %s\n", num
, vreg
, mono_type_get_name (type
));
918 mono_compile_create_var (MonoCompile
*cfg
, MonoType
*type
, int opcode
)
922 if (mono_type_is_long (type
))
923 dreg
= mono_alloc_dreg (cfg
, STACK_I8
);
924 #ifdef MONO_ARCH_SOFT_FLOAT
925 else if (mono_type_is_float (type
))
926 dreg
= mono_alloc_dreg (cfg
, STACK_R8
);
929 /* All the others are unified */
930 dreg
= mono_alloc_preg (cfg
);
932 return mono_compile_create_var_for_vreg (cfg
, type
, opcode
, dreg
);
936 * Transform a MonoInst into a load from the variable of index var_index.
939 mono_compile_make_var_load (MonoCompile
*cfg
, MonoInst
*dest
, gssize var_index
) {
940 memset (dest
, 0, sizeof (MonoInst
));
941 dest
->ssa_op
= MONO_SSA_LOAD
;
942 dest
->inst_i0
= cfg
->varinfo
[var_index
];
943 dest
->opcode
= mini_type_to_ldind (cfg
, dest
->inst_i0
->inst_vtype
);
944 type_to_eval_stack_type (cfg
, dest
->inst_i0
->inst_vtype
, dest
);
945 dest
->klass
= dest
->inst_i0
->klass
;
951 type_from_stack_type (MonoInst
*ins
) {
953 case STACK_I4
: return &mono_defaults
.int32_class
->byval_arg
;
954 case STACK_I8
: return &mono_defaults
.int64_class
->byval_arg
;
955 case STACK_PTR
: return &mono_defaults
.int_class
->byval_arg
;
956 case STACK_R8
: return &mono_defaults
.double_class
->byval_arg
;
959 * this if used to be commented without any specific reason, but
960 * it breaks #80235 when commented
963 return &ins
->klass
->this_arg
;
965 return &mono_defaults
.object_class
->this_arg
;
967 /* ins->klass may not be set for ldnull.
968 * Also, if we have a boxed valuetype, we want an object lass,
969 * not the valuetype class
971 if (ins
->klass
&& !ins
->klass
->valuetype
)
972 return &ins
->klass
->byval_arg
;
973 return &mono_defaults
.object_class
->byval_arg
;
974 case STACK_VTYPE
: return &ins
->klass
->byval_arg
;
976 g_error ("stack type %d to montype not handled\n", ins
->type
);
982 mono_type_from_stack_type (MonoInst
*ins
) {
983 return type_from_stack_type (ins
);
987 * mono_add_ins_to_end:
989 * Same as MONO_ADD_INS, but add INST before any branches at the end of BB.
992 mono_add_ins_to_end (MonoBasicBlock
*bb
, MonoInst
*inst
)
997 MONO_ADD_INS (bb
, inst
);
1001 switch (bb
->last_ins
->opcode
) {
1015 mono_bblock_insert_before_ins (bb
, bb
->last_ins
, inst
);
1018 if (MONO_IS_COND_BRANCH_OP (bb
->last_ins
)) {
1019 /* Need to insert the ins before the compare */
1020 if (bb
->code
== bb
->last_ins
) {
1021 mono_bblock_insert_before_ins (bb
, bb
->last_ins
, inst
);
1025 if (bb
->code
->next
== bb
->last_ins
) {
1026 /* Only two instructions */
1027 opcode
= bb
->code
->opcode
;
1029 if ((opcode
== OP_COMPARE
) || (opcode
== OP_COMPARE_IMM
) || (opcode
== OP_ICOMPARE
) || (opcode
== OP_ICOMPARE_IMM
) || (opcode
== OP_FCOMPARE
) || (opcode
== OP_LCOMPARE
) || (opcode
== OP_LCOMPARE_IMM
)) {
1031 mono_bblock_insert_before_ins (bb
, bb
->code
, inst
);
1033 mono_bblock_insert_before_ins (bb
, bb
->last_ins
, inst
);
1036 opcode
= bb
->last_ins
->prev
->opcode
;
1038 if ((opcode
== OP_COMPARE
) || (opcode
== OP_COMPARE_IMM
) || (opcode
== OP_ICOMPARE
) || (opcode
== OP_ICOMPARE_IMM
) || (opcode
== OP_FCOMPARE
) || (opcode
== OP_LCOMPARE
) || (opcode
== OP_LCOMPARE_IMM
)) {
1040 mono_bblock_insert_before_ins (bb
, bb
->last_ins
->prev
, inst
);
1042 mono_bblock_insert_before_ins (bb
, bb
->last_ins
, inst
);
1047 MONO_ADD_INS (bb
, inst
);
1053 mono_create_jump_table (MonoCompile
*cfg
, MonoInst
*label
, MonoBasicBlock
**bbs
, int num_blocks
)
1055 MonoJumpInfo
*ji
= mono_mempool_alloc (cfg
->mempool
, sizeof (MonoJumpInfo
));
1056 MonoJumpInfoBBTable
*table
;
1058 table
= mono_mempool_alloc (cfg
->mempool
, sizeof (MonoJumpInfoBBTable
));
1060 table
->table_size
= num_blocks
;
1062 ji
->ip
.label
= label
;
1063 ji
->type
= MONO_PATCH_INFO_SWITCH
;
1064 ji
->data
.table
= table
;
1065 ji
->next
= cfg
->patch_info
;
1066 cfg
->patch_info
= ji
;
1069 static MonoMethodSignature
*
1070 mono_get_array_new_va_signature (int arity
)
1072 static GHashTable
*sighash
= NULL
;
1073 MonoMethodSignature
*res
;
1078 sighash
= g_hash_table_new (NULL
, NULL
);
1080 else if ((res
= g_hash_table_lookup (sighash
, GINT_TO_POINTER (arity
)))) {
1085 res
= mono_metadata_signature_alloc (mono_defaults
.corlib
, arity
+ 1);
1088 #ifdef MONO_ARCH_VARARG_ICALLS
1089 /* Only set this only some archs since not all backends can handle varargs+pinvoke */
1090 res
->call_convention
= MONO_CALL_VARARG
;
1093 #ifdef PLATFORM_WIN32
1094 res
->call_convention
= MONO_CALL_C
;
1097 res
->params
[0] = &mono_defaults
.int_class
->byval_arg
;
1098 for (i
= 0; i
< arity
; i
++)
1099 res
->params
[i
+ 1] = &mono_defaults
.int_class
->byval_arg
;
1101 res
->ret
= &mono_defaults
.object_class
->byval_arg
;
1103 g_hash_table_insert (sighash
, GINT_TO_POINTER (arity
), res
);
1110 mono_get_array_new_va_icall (int rank
)
1112 MonoMethodSignature
*esig
;
1113 char icall_name
[256];
1115 MonoJitICallInfo
*info
;
1117 /* Need to register the icall so it gets an icall wrapper */
1118 sprintf (icall_name
, "ves_array_new_va_%d", rank
);
1121 info
= mono_find_jit_icall_by_name (icall_name
);
1123 esig
= mono_get_array_new_va_signature (rank
);
1124 name
= g_strdup (icall_name
);
1125 info
= mono_register_jit_icall (mono_array_new_va
, name
, esig
, FALSE
);
1127 g_hash_table_insert (jit_icall_name_hash
, name
, name
);
1135 mini_class_is_system_array (MonoClass
*klass
)
1137 if (klass
->parent
== mono_defaults
.array_class
)
1143 static MonoJitICallInfo
**emul_opcode_map
= NULL
;
1146 mono_find_jit_opcode_emulation (int opcode
)
1148 g_assert (opcode
>= 0 && opcode
<= OP_LAST
);
1149 if (emul_opcode_map
)
1150 return emul_opcode_map
[opcode
];
1156 mini_assembly_can_skip_verification (MonoDomain
*domain
, MonoMethod
*method
)
1158 MonoAssembly
*assembly
= method
->klass
->image
->assembly
;
1159 if (method
->wrapper_type
!= MONO_WRAPPER_NONE
)
1161 if (assembly
->in_gac
|| assembly
->image
== mono_defaults
.corlib
)
1163 if (mono_security_get_mode () != MONO_SECURITY_MODE_NONE
)
1165 return mono_assembly_has_skip_verification (assembly
);
1169 * mini_method_verify:
1171 * Verify the method using the new verfier.
1173 * Returns true if the method is invalid.
1176 mini_method_verify (MonoCompile
*cfg
, MonoMethod
*method
)
1179 gboolean is_fulltrust
;
1180 MonoLoaderError
*error
;
1182 if (method
->verification_success
)
1185 is_fulltrust
= mono_verifier_is_method_full_trust (method
);
1187 if (!mono_verifier_is_enabled_for_method (method
))
1190 res
= mono_method_verify_with_current_settings (method
, cfg
->skip_visibility
);
1192 if ((error
= mono_loader_get_last_error ())) {
1193 cfg
->exception_type
= error
->exception_type
;
1195 mono_free_verify_list (res
);
1200 for (tmp
= res
; tmp
; tmp
= tmp
->next
) {
1201 MonoVerifyInfoExtended
*info
= (MonoVerifyInfoExtended
*)tmp
->data
;
1202 if (info
->info
.status
== MONO_VERIFY_ERROR
) {
1203 cfg
->exception_type
= info
->exception_type
;
1204 cfg
->exception_message
= g_strdup (info
->info
.message
);
1205 mono_free_verify_list (res
);
1208 if (info
->info
.status
== MONO_VERIFY_NOT_VERIFIABLE
&& !is_fulltrust
) {
1209 cfg
->exception_type
= info
->exception_type
;
1210 cfg
->exception_message
= g_strdup (info
->info
.message
);
1211 mono_free_verify_list (res
);
1215 mono_free_verify_list (res
);
1217 method
->verification_success
= 1;
1222 create_helper_signature (void)
1224 helper_sig_domain_get
= mono_create_icall_signature ("ptr");
1225 helper_sig_class_init_trampoline
= mono_create_icall_signature ("void");
1226 helper_sig_generic_class_init_trampoline
= mono_create_icall_signature ("void");
1227 helper_sig_rgctx_lazy_fetch_trampoline
= mono_create_icall_signature ("ptr ptr");
1228 helper_sig_monitor_enter_exit_trampoline
= mono_create_icall_signature ("void");
1231 static gconstpointer
1232 mono_icall_get_wrapper_full (MonoJitICallInfo
* callinfo
, gboolean do_compile
)
1235 MonoMethod
*wrapper
;
1236 gconstpointer trampoline
;
1237 MonoDomain
*domain
= mono_get_root_domain ();
1239 if (callinfo
->wrapper
) {
1240 return callinfo
->wrapper
;
1243 if (callinfo
->trampoline
)
1244 return callinfo
->trampoline
;
1247 * We use the lock on the root domain instead of the JIT lock to protect
1248 * callinfo->trampoline, since we do a lot of stuff inside the critical section.
1250 mono_loader_lock (); /*FIXME mono_compile_method requires the loader lock, by large.*/
1251 mono_domain_lock (domain
);
1253 if (callinfo
->trampoline
) {
1254 mono_domain_unlock (domain
);
1255 mono_loader_unlock ();
1256 return callinfo
->trampoline
;
1259 name
= g_strdup_printf ("__icall_wrapper_%s", callinfo
->name
);
1260 wrapper
= mono_marshal_get_icall_wrapper (callinfo
->sig
, name
, callinfo
->func
, check_for_pending_exc
);
1264 trampoline
= mono_compile_method (wrapper
);
1266 trampoline
= mono_create_ftnptr (domain
, mono_create_jit_trampoline_in_domain (domain
, wrapper
));
1267 mono_register_jit_icall_wrapper (callinfo
, trampoline
);
1269 callinfo
->trampoline
= trampoline
;
1271 mono_domain_unlock (domain
);
1272 mono_loader_unlock ();
1274 return callinfo
->trampoline
;
1278 mono_icall_get_wrapper (MonoJitICallInfo
* callinfo
)
1280 return mono_icall_get_wrapper_full (callinfo
, FALSE
);
1284 mono_dynamic_code_hash_insert (MonoDomain
*domain
, MonoMethod
*method
, MonoJitDynamicMethodInfo
*ji
)
1286 if (!domain_jit_info (domain
)->dynamic_code_hash
)
1287 domain_jit_info (domain
)->dynamic_code_hash
= g_hash_table_new (NULL
, NULL
);
1288 g_hash_table_insert (domain_jit_info (domain
)->dynamic_code_hash
, method
, ji
);
1291 static MonoJitDynamicMethodInfo
*
1292 mono_dynamic_code_hash_lookup (MonoDomain
*domain
, MonoMethod
*method
)
1294 MonoJitDynamicMethodInfo
*res
;
1296 if (domain_jit_info (domain
)->dynamic_code_hash
)
1297 res
= g_hash_table_lookup (domain_jit_info (domain
)->dynamic_code_hash
, method
);
1305 GList
*active
, *inactive
;
1310 compare_by_interval_start_pos_func (gconstpointer a
, gconstpointer b
)
1312 MonoMethodVar
*v1
= (MonoMethodVar
*)a
;
1313 MonoMethodVar
*v2
= (MonoMethodVar
*)b
;
1317 else if (v1
->interval
->range
&& v2
->interval
->range
)
1318 return v1
->interval
->range
->from
- v2
->interval
->range
->from
;
1319 else if (v1
->interval
->range
)
1328 #define LSCAN_DEBUG(a) do { a; } while (0)
1330 #define LSCAN_DEBUG(a)
1334 mono_allocate_stack_slots_full2 (MonoCompile
*cfg
, gboolean backward
, guint32
*stack_size
, guint32
*stack_align
)
1336 int i
, slot
, offset
, size
;
1341 GList
*vars
= NULL
, *l
, *unhandled
;
1342 StackSlotInfo
*scalar_stack_slots
, *vtype_stack_slots
, *slot_info
;
1346 LSCAN_DEBUG (printf ("Allocate Stack Slots 2 for %s:\n", mono_method_full_name (cfg
->method
, TRUE
)));
1348 scalar_stack_slots
= mono_mempool_alloc0 (cfg
->mempool
, sizeof (StackSlotInfo
) * MONO_TYPE_PINNED
);
1349 vtype_stack_slots
= NULL
;
1352 offsets
= mono_mempool_alloc (cfg
->mempool
, sizeof (gint32
) * cfg
->num_varinfo
);
1353 for (i
= 0; i
< cfg
->num_varinfo
; ++i
)
1356 for (i
= cfg
->locals_start
; i
< cfg
->num_varinfo
; i
++) {
1357 inst
= cfg
->varinfo
[i
];
1358 vmv
= MONO_VARINFO (cfg
, i
);
1360 if ((inst
->flags
& MONO_INST_IS_DEAD
) || inst
->opcode
== OP_REGVAR
|| inst
->opcode
== OP_REGOFFSET
)
1363 vars
= g_list_prepend (vars
, vmv
);
1366 vars
= g_list_sort (g_list_copy (vars
), compare_by_interval_start_pos_func
);
1371 for (unhandled = vars; unhandled; unhandled = unhandled->next) {
1372 MonoMethodVar *current = unhandled->data;
1374 if (current->interval->range) {
1375 g_assert (current->interval->range->from >= i);
1376 i = current->interval->range->from;
1383 for (unhandled
= vars
; unhandled
; unhandled
= unhandled
->next
) {
1384 MonoMethodVar
*current
= unhandled
->data
;
1387 inst
= cfg
->varinfo
[vmv
->idx
];
1389 /* inst->backend.is_pinvoke indicates native sized value types, this is used by the
1390 * pinvoke wrappers when they call functions returning structures */
1391 if (inst
->backend
.is_pinvoke
&& MONO_TYPE_ISSTRUCT (inst
->inst_vtype
) && inst
->inst_vtype
->type
!= MONO_TYPE_TYPEDBYREF
) {
1392 size
= mono_class_native_size (mono_class_from_mono_type (inst
->inst_vtype
), &align
);
1397 size
= mono_type_size (inst
->inst_vtype
, &ialign
);
1401 t
= mono_type_get_underlying_type (inst
->inst_vtype
);
1403 case MONO_TYPE_GENERICINST
:
1404 if (!mono_type_generic_inst_is_valuetype (t
)) {
1405 slot_info
= &scalar_stack_slots
[t
->type
];
1409 case MONO_TYPE_VALUETYPE
:
1410 if (!vtype_stack_slots
)
1411 vtype_stack_slots
= mono_mempool_alloc0 (cfg
->mempool
, sizeof (StackSlotInfo
) * 256);
1412 for (i
= 0; i
< nvtypes
; ++i
)
1413 if (t
->data
.klass
== vtype_stack_slots
[i
].vtype
)
1416 slot_info
= &vtype_stack_slots
[i
];
1418 g_assert (nvtypes
< 256);
1419 vtype_stack_slots
[nvtypes
].vtype
= t
->data
.klass
;
1420 slot_info
= &vtype_stack_slots
[nvtypes
];
1424 case MONO_TYPE_CLASS
:
1425 case MONO_TYPE_OBJECT
:
1426 case MONO_TYPE_ARRAY
:
1427 case MONO_TYPE_SZARRAY
:
1428 case MONO_TYPE_STRING
:
1432 #if SIZEOF_REGISTER == 4
1436 /* Share non-float stack slots of the same size */
1437 slot_info
= &scalar_stack_slots
[MONO_TYPE_CLASS
];
1441 slot_info
= &scalar_stack_slots
[t
->type
];
1445 if (cfg
->comp_done
& MONO_COMP_LIVENESS
) {
1449 //printf ("START %2d %08x %08x\n", vmv->idx, vmv->range.first_use.abs_pos, vmv->range.last_use.abs_pos);
1451 if (!current
->interval
->range
) {
1452 if (inst
->flags
& (MONO_INST_VOLATILE
|MONO_INST_INDIRECT
))
1456 inst
->flags
|= MONO_INST_IS_DEAD
;
1461 pos
= current
->interval
->range
->from
;
1463 LSCAN_DEBUG (printf ("process R%d ", inst
->dreg
));
1464 if (current
->interval
->range
)
1465 LSCAN_DEBUG (mono_linterval_print (current
->interval
));
1466 LSCAN_DEBUG (printf ("\n"));
1468 /* Check for intervals in active which expired or inactive */
1470 /* FIXME: Optimize this */
1473 for (l
= slot_info
->active
; l
!= NULL
; l
= l
->next
) {
1474 MonoMethodVar
*v
= (MonoMethodVar
*)l
->data
;
1476 if (v
->interval
->last_range
->to
< pos
) {
1477 slot_info
->active
= g_list_delete_link (slot_info
->active
, l
);
1478 slot_info
->slots
= g_slist_prepend_mempool (cfg
->mempool
, slot_info
->slots
, GINT_TO_POINTER (offsets
[v
->idx
]));
1479 LSCAN_DEBUG (printf ("Interval R%d has expired, adding 0x%x to slots\n", cfg
->varinfo
[v
->idx
]->dreg
, offsets
[v
->idx
]));
1483 else if (!mono_linterval_covers (v
->interval
, pos
)) {
1484 slot_info
->inactive
= g_list_append (slot_info
->inactive
, v
);
1485 slot_info
->active
= g_list_delete_link (slot_info
->active
, l
);
1486 LSCAN_DEBUG (printf ("Interval R%d became inactive\n", cfg
->varinfo
[v
->idx
]->dreg
));
1493 /* Check for intervals in inactive which expired or active */
1495 /* FIXME: Optimize this */
1498 for (l
= slot_info
->inactive
; l
!= NULL
; l
= l
->next
) {
1499 MonoMethodVar
*v
= (MonoMethodVar
*)l
->data
;
1501 if (v
->interval
->last_range
->to
< pos
) {
1502 slot_info
->inactive
= g_list_delete_link (slot_info
->inactive
, l
);
1503 // FIXME: Enabling this seems to cause impossible to debug crashes
1504 //slot_info->slots = g_slist_prepend_mempool (cfg->mempool, slot_info->slots, GINT_TO_POINTER (offsets [v->idx]));
1505 LSCAN_DEBUG (printf ("Interval R%d has expired, adding 0x%x to slots\n", cfg
->varinfo
[v
->idx
]->dreg
, offsets
[v
->idx
]));
1509 else if (mono_linterval_covers (v
->interval
, pos
)) {
1510 slot_info
->active
= g_list_append (slot_info
->active
, v
);
1511 slot_info
->inactive
= g_list_delete_link (slot_info
->inactive
, l
);
1512 LSCAN_DEBUG (printf ("\tInterval R%d became active\n", cfg
->varinfo
[v
->idx
]->dreg
));
1520 * This also handles the case when the variable is used in an
1521 * exception region, as liveness info is not computed there.
1524 * FIXME: All valuetypes are marked as INDIRECT because of LDADDR
1527 if (! (inst
->flags
& (MONO_INST_VOLATILE
|MONO_INST_INDIRECT
))) {
1528 if (slot_info
->slots
) {
1529 slot
= GPOINTER_TO_INT (slot_info
->slots
->data
);
1531 slot_info
->slots
= slot_info
->slots
->next
;
1534 /* FIXME: We might want to consider the inactive intervals as well if slot_info->slots is empty */
1536 slot_info
->active
= mono_varlist_insert_sorted (cfg
, slot_info
->active
, vmv
, TRUE
);
1542 static int count
= 0;
1545 if (count
== atoi (getenv ("COUNT3")))
1546 printf ("LAST: %s\n", mono_method_full_name (cfg
->method
, TRUE
));
1547 if (count
> atoi (getenv ("COUNT3")))
1550 mono_print_ins (inst
);
1555 LSCAN_DEBUG (printf ("R%d %s -> 0x%x\n", inst
->dreg
, mono_type_full_name (t
), slot
));
1557 if (slot
== 0xffffff) {
1559 * Allways allocate valuetypes to sizeof (gpointer) to allow more
1560 * efficient copying (and to work around the fact that OP_MEMCPY
1561 * and OP_MEMSET ignores alignment).
1563 if (MONO_TYPE_ISSTRUCT (t
))
1564 align
= MAX (sizeof (gpointer
), mono_class_min_align (mono_class_from_mono_type (t
)));
1568 offset
+= align
- 1;
1569 offset
&= ~(align
- 1);
1573 offset
+= align
- 1;
1574 offset
&= ~(align
- 1);
1579 if (*stack_align
== 0)
1580 *stack_align
= align
;
1583 offsets
[vmv
->idx
] = slot
;
1586 for (i
= 0; i
< MONO_TYPE_PINNED
; ++i
) {
1587 if (scalar_stack_slots
[i
].active
)
1588 g_list_free (scalar_stack_slots
[i
].active
);
1590 for (i
= 0; i
< nvtypes
; ++i
) {
1591 if (vtype_stack_slots
[i
].active
)
1592 g_list_free (vtype_stack_slots
[i
].active
);
1595 mono_jit_stats
.locals_stack_size
+= offset
;
1597 *stack_size
= offset
;
1602 * mono_allocate_stack_slots_full:
1604 * Allocate stack slots for all non register allocated variables using a
1605 * linear scan algorithm.
1606 * Returns: an array of stack offsets.
1607 * STACK_SIZE is set to the amount of stack space needed.
1608 * STACK_ALIGN is set to the alignment needed by the locals area.
1611 mono_allocate_stack_slots_full (MonoCompile
*cfg
, gboolean backward
, guint32
*stack_size
, guint32
*stack_align
)
1613 int i
, slot
, offset
, size
;
1618 GList
*vars
= NULL
, *l
;
1619 StackSlotInfo
*scalar_stack_slots
, *vtype_stack_slots
, *slot_info
;
1623 if ((cfg
->num_varinfo
> 0) && MONO_VARINFO (cfg
, 0)->interval
)
1624 return mono_allocate_stack_slots_full2 (cfg
, backward
, stack_size
, stack_align
);
1626 scalar_stack_slots
= mono_mempool_alloc0 (cfg
->mempool
, sizeof (StackSlotInfo
) * MONO_TYPE_PINNED
);
1627 vtype_stack_slots
= NULL
;
1630 offsets
= mono_mempool_alloc (cfg
->mempool
, sizeof (gint32
) * cfg
->num_varinfo
);
1631 for (i
= 0; i
< cfg
->num_varinfo
; ++i
)
1634 for (i
= cfg
->locals_start
; i
< cfg
->num_varinfo
; i
++) {
1635 inst
= cfg
->varinfo
[i
];
1636 vmv
= MONO_VARINFO (cfg
, i
);
1638 if ((inst
->flags
& MONO_INST_IS_DEAD
) || inst
->opcode
== OP_REGVAR
|| inst
->opcode
== OP_REGOFFSET
)
1641 vars
= g_list_prepend (vars
, vmv
);
1644 vars
= mono_varlist_sort (cfg
, vars
, 0);
1646 *stack_align
= sizeof (gpointer
);
1647 for (l
= vars
; l
; l
= l
->next
) {
1649 inst
= cfg
->varinfo
[vmv
->idx
];
1651 /* inst->backend.is_pinvoke indicates native sized value types, this is used by the
1652 * pinvoke wrappers when they call functions returning structures */
1653 if (inst
->backend
.is_pinvoke
&& MONO_TYPE_ISSTRUCT (inst
->inst_vtype
) && inst
->inst_vtype
->type
!= MONO_TYPE_TYPEDBYREF
) {
1654 size
= mono_class_native_size (mono_class_from_mono_type (inst
->inst_vtype
), &align
);
1658 size
= mono_type_size (inst
->inst_vtype
, &ialign
);
1662 t
= mono_type_get_underlying_type (inst
->inst_vtype
);
1664 slot_info
= &scalar_stack_slots
[MONO_TYPE_I
];
1667 case MONO_TYPE_GENERICINST
:
1668 if (!mono_type_generic_inst_is_valuetype (t
)) {
1669 slot_info
= &scalar_stack_slots
[t
->type
];
1673 case MONO_TYPE_VALUETYPE
:
1674 if (!vtype_stack_slots
)
1675 vtype_stack_slots
= mono_mempool_alloc0 (cfg
->mempool
, sizeof (StackSlotInfo
) * 256);
1676 for (i
= 0; i
< nvtypes
; ++i
)
1677 if (t
->data
.klass
== vtype_stack_slots
[i
].vtype
)
1680 slot_info
= &vtype_stack_slots
[i
];
1682 g_assert (nvtypes
< 256);
1683 vtype_stack_slots
[nvtypes
].vtype
= t
->data
.klass
;
1684 slot_info
= &vtype_stack_slots
[nvtypes
];
1688 case MONO_TYPE_CLASS
:
1689 case MONO_TYPE_OBJECT
:
1690 case MONO_TYPE_ARRAY
:
1691 case MONO_TYPE_SZARRAY
:
1692 case MONO_TYPE_STRING
:
1696 #if SIZEOF_REGISTER == 4
1701 /* Share non-float stack slots of the same size */
1702 slot_info
= &scalar_stack_slots
[MONO_TYPE_CLASS
];
1705 slot_info
= &scalar_stack_slots
[t
->type
];
1710 if (cfg
->comp_done
& MONO_COMP_LIVENESS
) {
1711 //printf ("START %2d %08x %08x\n", vmv->idx, vmv->range.first_use.abs_pos, vmv->range.last_use.abs_pos);
1713 /* expire old intervals in active */
1714 while (slot_info
->active
) {
1715 MonoMethodVar
*amv
= (MonoMethodVar
*)slot_info
->active
->data
;
1717 if (amv
->range
.last_use
.abs_pos
> vmv
->range
.first_use
.abs_pos
)
1720 //printf ("EXPIR %2d %08x %08x C%d R%d\n", amv->idx, amv->range.first_use.abs_pos, amv->range.last_use.abs_pos, amv->spill_costs, amv->reg);
1722 slot_info
->active
= g_list_delete_link (slot_info
->active
, slot_info
->active
);
1723 slot_info
->slots
= g_slist_prepend_mempool (cfg
->mempool
, slot_info
->slots
, GINT_TO_POINTER (offsets
[amv
->idx
]));
1727 * This also handles the case when the variable is used in an
1728 * exception region, as liveness info is not computed there.
1731 * FIXME: All valuetypes are marked as INDIRECT because of LDADDR
1734 if (! (inst
->flags
& (MONO_INST_VOLATILE
|MONO_INST_INDIRECT
))) {
1735 if (slot_info
->slots
) {
1736 slot
= GPOINTER_TO_INT (slot_info
->slots
->data
);
1738 slot_info
->slots
= slot_info
->slots
->next
;
1741 slot_info
->active
= mono_varlist_insert_sorted (cfg
, slot_info
->active
, vmv
, TRUE
);
1746 static int count
= 0;
1750 if (count == atoi (getenv ("COUNT")))
1751 printf ("LAST: %s\n", mono_method_full_name (cfg->method, TRUE));
1752 if (count > atoi (getenv ("COUNT")))
1755 mono_print_ins (inst);
1760 if (cfg
->disable_reuse_stack_slots
)
1763 if (slot
== 0xffffff) {
1765 * Allways allocate valuetypes to sizeof (gpointer) to allow more
1766 * efficient copying (and to work around the fact that OP_MEMCPY
1767 * and OP_MEMSET ignores alignment).
1769 if (MONO_TYPE_ISSTRUCT (t
)) {
1770 align
= MAX (sizeof (gpointer
), mono_class_min_align (mono_class_from_mono_type (t
)));
1772 * Align the size too so the code generated for passing vtypes in
1773 * registers doesn't overwrite random locals.
1775 size
= (size
+ (align
- 1)) & ~(align
-1);
1780 offset
+= align
- 1;
1781 offset
&= ~(align
- 1);
1785 offset
+= align
- 1;
1786 offset
&= ~(align
- 1);
1791 *stack_align
= MAX (*stack_align
, align
);
1794 offsets
[vmv
->idx
] = slot
;
1797 for (i
= 0; i
< MONO_TYPE_PINNED
; ++i
) {
1798 if (scalar_stack_slots
[i
].active
)
1799 g_list_free (scalar_stack_slots
[i
].active
);
1801 for (i
= 0; i
< nvtypes
; ++i
) {
1802 if (vtype_stack_slots
[i
].active
)
1803 g_list_free (vtype_stack_slots
[i
].active
);
1806 mono_jit_stats
.locals_stack_size
+= offset
;
1808 *stack_size
= offset
;
1815 mono_allocate_stack_slots_full (MonoCompile
*cfg
, gboolean backward
, guint32
*stack_size
, guint32
*stack_align
)
1817 g_assert_not_reached ();
1821 #endif /* DISABLE_JIT */
1824 mono_allocate_stack_slots (MonoCompile
*m
, guint32
*stack_size
, guint32
*stack_align
)
1826 return mono_allocate_stack_slots_full (m
, TRUE
, stack_size
, stack_align
);
1830 mono_register_opcode_emulation (int opcode
, const char *name
, const char *sigstr
, gpointer func
, gboolean no_throw
)
1832 MonoJitICallInfo
*info
;
1833 MonoMethodSignature
*sig
= mono_create_icall_signature (sigstr
);
1835 if (!emul_opcode_map
)
1836 emul_opcode_map
= g_new0 (MonoJitICallInfo
*, OP_LAST
+ 1);
1838 g_assert (!sig
->hasthis
);
1839 g_assert (sig
->param_count
< 3);
1841 info
= mono_register_jit_icall (func
, name
, sig
, no_throw
);
1843 emul_opcode_map
[opcode
] = info
;
1847 register_icall (gpointer func
, const char *name
, const char *sigstr
, gboolean save
)
1849 MonoMethodSignature
*sig
;
1852 sig
= mono_create_icall_signature (sigstr
);
1856 mono_register_jit_icall (func
, name
, sig
, save
);
1860 print_dfn (MonoCompile
*cfg
) {
1866 g_print ("IR code for method %s\n", mono_method_full_name (cfg
->method
, TRUE
));
1868 for (i
= 0; i
< cfg
->num_bblocks
; ++i
) {
1869 bb
= cfg
->bblocks
[i
];
1870 /*if (bb->cil_code) {
1871 char* code1, *code2;
1872 code1 = mono_disasm_code_one (NULL, cfg->method, bb->cil_code, NULL);
1873 if (bb->last_ins->cil_code)
1874 code2 = mono_disasm_code_one (NULL, cfg->method, bb->last_ins->cil_code, NULL);
1876 code2 = g_strdup ("");
1878 code1 [strlen (code1) - 1] = 0;
1879 code = g_strdup_printf ("%s -> %s", code1, code2);
1883 code
= g_strdup ("\n");
1884 g_print ("\nBB%d (%d) (len: %d): %s", bb
->block_num
, i
, bb
->cil_length
, code
);
1885 MONO_BB_FOR_EACH_INS (bb
, c
) {
1886 mono_print_ins_index (-1, c
);
1889 g_print ("\tprev:");
1890 for (j
= 0; j
< bb
->in_count
; ++j
) {
1891 g_print (" BB%d", bb
->in_bb
[j
]->block_num
);
1893 g_print ("\t\tsucc:");
1894 for (j
= 0; j
< bb
->out_count
; ++j
) {
1895 g_print (" BB%d", bb
->out_bb
[j
]->block_num
);
1897 g_print ("\n\tidom: BB%d\n", bb
->idom
? bb
->idom
->block_num
: -1);
1900 g_assert (mono_bitset_test_fast (bb
->dominators
, bb
->idom
->dfn
));
1903 mono_blockset_print (cfg
, bb
->dominators
, "\tdominators", bb
->idom
? bb
->idom
->dfn
: -1);
1905 mono_blockset_print (cfg
, bb
->dfrontier
, "\tdfrontier", -1);
1913 mono_bblock_add_inst (MonoBasicBlock
*bb
, MonoInst
*inst
)
1915 MONO_ADD_INS (bb
, inst
);
1919 mono_bblock_insert_after_ins (MonoBasicBlock
*bb
, MonoInst
*ins
, MonoInst
*ins_to_insert
)
1923 bb
->code
= ins_to_insert
;
1925 /* Link with next */
1926 ins_to_insert
->next
= ins
;
1928 ins
->prev
= ins_to_insert
;
1930 if (bb
->last_ins
== NULL
)
1931 bb
->last_ins
= ins_to_insert
;
1933 /* Link with next */
1934 ins_to_insert
->next
= ins
->next
;
1936 ins
->next
->prev
= ins_to_insert
;
1938 /* Link with previous */
1939 ins
->next
= ins_to_insert
;
1940 ins_to_insert
->prev
= ins
;
1942 if (bb
->last_ins
== ins
)
1943 bb
->last_ins
= ins_to_insert
;
1948 mono_bblock_insert_before_ins (MonoBasicBlock
*bb
, MonoInst
*ins
, MonoInst
*ins_to_insert
)
1952 bb
->code
= ins_to_insert
;
1953 ins_to_insert
->next
= ins
;
1954 if (bb
->last_ins
== NULL
)
1955 bb
->last_ins
= ins_to_insert
;
1957 /* Link with previous */
1959 ins
->prev
->next
= ins_to_insert
;
1960 ins_to_insert
->prev
= ins
->prev
;
1962 /* Link with next */
1963 ins
->prev
= ins_to_insert
;
1964 ins_to_insert
->next
= ins
;
1966 if (bb
->code
== ins
)
1967 bb
->code
= ins_to_insert
;
1972 * mono_verify_bblock:
1974 * Verify that the next and prev pointers are consistent inside the instructions in BB.
1977 mono_verify_bblock (MonoBasicBlock
*bb
)
1979 MonoInst
*ins
, *prev
;
1982 for (ins
= bb
->code
; ins
; ins
= ins
->next
) {
1983 g_assert (ins
->prev
== prev
);
1987 g_assert (!bb
->last_ins
->next
);
1993 * Perform consistency checks on the JIT data structures and the IR
1996 mono_verify_cfg (MonoCompile
*cfg
)
2000 for (bb
= cfg
->bb_entry
; bb
; bb
= bb
->next_bb
)
2001 mono_verify_bblock (bb
);
2005 mono_destroy_compile (MonoCompile
*cfg
)
2007 //mono_mempool_stats (cfg->mempool);
2008 mono_free_loop_info (cfg
);
2010 mono_regstate_free (cfg
->rs
);
2012 g_hash_table_destroy (cfg
->spvars
);
2014 g_hash_table_destroy (cfg
->exvars
);
2015 mono_mempool_destroy (cfg
->mempool
);
2016 g_list_free (cfg
->ldstr_list
);
2017 g_hash_table_destroy (cfg
->token_info_hash
);
2018 if (cfg
->abs_patches
)
2019 g_hash_table_destroy (cfg
->abs_patches
);
2021 g_free (cfg
->varinfo
);
2023 g_free (cfg
->exception_message
);
2027 #ifdef HAVE_KW_THREAD
2028 static __thread gpointer mono_lmf_addr MONO_TLS_FAST
;
2029 #ifdef MONO_ARCH_ENABLE_MONO_LMF_VAR
2031 * When this is defined, the current lmf is stored in this tls variable instead of in
2034 static __thread gpointer mono_lmf MONO_TLS_FAST
;
2039 mono_get_jit_tls_key (void)
2041 return mono_jit_tls_id
;
2045 mono_get_jit_tls_offset (void)
2047 #ifdef HAVE_KW_THREAD
2049 MONO_THREAD_VAR_OFFSET (mono_jit_tls
, offset
);
2057 mono_get_lmf_tls_offset (void)
2059 #if defined(HAVE_KW_THREAD) && defined(MONO_ARCH_ENABLE_MONO_LMF_VAR)
2061 MONO_THREAD_VAR_OFFSET(mono_lmf
,offset
);
2069 mono_get_lmf_addr_tls_offset (void)
2072 MONO_THREAD_VAR_OFFSET(mono_lmf_addr
,offset
);
2079 #if defined(HAVE_KW_THREAD) && defined(MONO_ARCH_ENABLE_MONO_LMF_VAR)
2082 MonoJitTlsData
*jit_tls
;
2084 if ((jit_tls
= TlsGetValue (mono_jit_tls_id
)))
2085 return jit_tls
->lmf
;
2087 g_assert_not_reached ();
2093 mono_get_lmf_addr (void)
2095 #ifdef HAVE_KW_THREAD
2096 return mono_lmf_addr
;
2098 MonoJitTlsData
*jit_tls
;
2100 if ((jit_tls
= TlsGetValue (mono_jit_tls_id
)))
2101 return &jit_tls
->lmf
;
2103 g_assert_not_reached ();
2108 /* Called by native->managed wrappers */
2110 mono_jit_thread_attach (MonoDomain
*domain
)
2112 #ifdef HAVE_KW_THREAD
2113 if (!mono_lmf_addr
) {
2114 mono_thread_attach (domain
);
2117 if (!TlsGetValue (mono_jit_tls_id
))
2118 mono_thread_attach (domain
);
2120 if (mono_domain_get () != domain
)
2121 mono_domain_set (domain
, TRUE
);
2125 * mono_thread_abort:
2126 * @obj: exception object
2128 * abort the thread, print exception information and stack trace
2131 mono_thread_abort (MonoObject
*obj
)
2133 /* MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id); */
2135 /* handle_remove should be eventually called for this thread, too
2138 if ((mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_LEGACY
) ||
2139 (obj
->vtable
->klass
== mono_defaults
.threadabortexception_class
)) {
2140 mono_thread_exit ();
2142 exit (mono_environment_exitcode_get ());
2147 setup_jit_tls_data (gpointer stack_start
, gpointer abort_func
)
2149 MonoJitTlsData
*jit_tls
;
2152 jit_tls
= TlsGetValue (mono_jit_tls_id
);
2156 jit_tls
= g_new0 (MonoJitTlsData
, 1);
2158 TlsSetValue (mono_jit_tls_id
, jit_tls
);
2160 #ifdef HAVE_KW_THREAD
2161 mono_jit_tls
= jit_tls
;
2164 jit_tls
->abort_func
= abort_func
;
2165 jit_tls
->end_of_stack
= stack_start
;
2167 lmf
= g_new0 (MonoLMF
, 1);
2168 #ifdef MONO_ARCH_INIT_TOP_LMF_ENTRY
2169 MONO_ARCH_INIT_TOP_LMF_ENTRY (lmf
);
2174 jit_tls
->first_lmf
= lmf
;
2176 #if defined(HAVE_KW_THREAD) && defined(MONO_ARCH_ENABLE_MONO_LMF_VAR)
2177 /* jit_tls->lmf is unused */
2179 mono_lmf_addr
= &mono_lmf
;
2181 #if defined(HAVE_KW_THREAD)
2182 mono_lmf_addr
= &jit_tls
->lmf
;
2188 mono_arch_setup_jit_tls_data (jit_tls
);
2189 mono_setup_altstack (jit_tls
);
2195 mono_thread_start_cb (gsize tid
, gpointer stack_start
, gpointer func
)
2198 void *jit_tls
= setup_jit_tls_data (stack_start
, mono_thread_abort
);
2199 thread
= mono_thread_current ();
2200 mono_debugger_thread_created (tid
, thread
, jit_tls
);
2202 thread
->jit_data
= jit_tls
;
2205 void (*mono_thread_attach_aborted_cb
) (MonoObject
*obj
) = NULL
;
2208 mono_thread_abort_dummy (MonoObject
*obj
)
2210 if (mono_thread_attach_aborted_cb
)
2211 mono_thread_attach_aborted_cb (obj
);
2213 mono_thread_abort (obj
);
2217 mono_thread_attach_cb (gsize tid
, gpointer stack_start
)
2220 void *jit_tls
= setup_jit_tls_data (stack_start
, mono_thread_abort_dummy
);
2221 thread
= mono_thread_current ();
2222 mono_debugger_thread_created (tid
, thread
, (MonoJitTlsData
*) jit_tls
);
2224 thread
->jit_data
= jit_tls
;
2225 if (mono_profiler_get_events () & MONO_PROFILE_STATISTICAL
)
2226 mono_runtime_setup_stat_profiler ();
2230 mini_thread_cleanup (MonoThread
*thread
)
2232 MonoJitTlsData
*jit_tls
= thread
->jit_data
;
2235 mono_debugger_thread_cleanup (jit_tls
);
2236 mono_arch_free_jit_tls_data (jit_tls
);
2238 mono_free_altstack (jit_tls
);
2239 g_free (jit_tls
->first_lmf
);
2241 thread
->jit_data
= NULL
;
2243 /* We can't clean up tls information if we are on another thread, it will clean up the wrong stuff
2244 * It would be nice to issue a warning when this happens outside of the shutdown sequence. but it's
2245 * not a trivial thing.
2247 * The current offender is mono_thread_manage which cleanup threads from the outside.
2249 if (thread
== mono_thread_current ()) {
2250 TlsSetValue (mono_jit_tls_id
, NULL
);
2252 #ifdef HAVE_KW_THREAD
2253 mono_jit_tls
= NULL
;
2254 mono_lmf_addr
= NULL
;
2255 #if defined(MONO_ARCH_ENABLE_MONO_LMF_VAR)
2264 mono_create_tls_get (MonoCompile
*cfg
, int offset
)
2266 #ifdef MONO_ARCH_HAVE_TLS_GET
2272 MONO_INST_NEW (cfg
, ins
, OP_TLS_GET
);
2273 ins
->dreg
= mono_alloc_preg (cfg
);
2274 ins
->inst_offset
= offset
;
2282 mono_get_jit_tls_intrinsic (MonoCompile
*cfg
)
2284 return mono_create_tls_get (cfg
, mono_get_jit_tls_offset ());
2288 mono_get_domain_intrinsic (MonoCompile
* cfg
)
2290 return mono_create_tls_get (cfg
, mono_domain_get_tls_offset ());
2294 mono_get_thread_intrinsic (MonoCompile
* cfg
)
2296 return mono_create_tls_get (cfg
, mono_thread_get_tls_offset ());
2300 mono_add_patch_info (MonoCompile
*cfg
, int ip
, MonoJumpInfoType type
, gconstpointer target
)
2302 MonoJumpInfo
*ji
= mono_mempool_alloc (cfg
->mempool
, sizeof (MonoJumpInfo
));
2306 ji
->data
.target
= target
;
2307 ji
->next
= cfg
->patch_info
;
2309 cfg
->patch_info
= ji
;
2313 mono_patch_info_list_prepend (MonoJumpInfo
*list
, int ip
, MonoJumpInfoType type
, gconstpointer target
)
2315 MonoJumpInfo
*ji
= g_new0 (MonoJumpInfo
, 1);
2319 ji
->data
.target
= target
;
2326 mono_remove_patch_info (MonoCompile
*cfg
, int ip
)
2328 MonoJumpInfo
**ji
= &cfg
->patch_info
;
2331 if ((*ji
)->ip
.i
== ip
)
2334 ji
= &((*ji
)->next
);
2339 * mono_patch_info_dup_mp:
2341 * Make a copy of PATCH_INFO, allocating memory from the mempool MP.
2344 mono_patch_info_dup_mp (MonoMemPool
*mp
, MonoJumpInfo
*patch_info
)
2346 MonoJumpInfo
*res
= mono_mempool_alloc (mp
, sizeof (MonoJumpInfo
));
2347 memcpy (res
, patch_info
, sizeof (MonoJumpInfo
));
2349 switch (patch_info
->type
) {
2350 case MONO_PATCH_INFO_RVA
:
2351 case MONO_PATCH_INFO_LDSTR
:
2352 case MONO_PATCH_INFO_TYPE_FROM_HANDLE
:
2353 case MONO_PATCH_INFO_LDTOKEN
:
2354 case MONO_PATCH_INFO_DECLSEC
:
2355 res
->data
.token
= mono_mempool_alloc (mp
, sizeof (MonoJumpInfoToken
));
2356 memcpy (res
->data
.token
, patch_info
->data
.token
, sizeof (MonoJumpInfoToken
));
2358 case MONO_PATCH_INFO_SWITCH
:
2359 res
->data
.table
= mono_mempool_alloc (mp
, sizeof (MonoJumpInfoBBTable
));
2360 memcpy (res
->data
.table
, patch_info
->data
.table
, sizeof (MonoJumpInfoBBTable
));
2362 case MONO_PATCH_INFO_RGCTX_FETCH
:
2363 res
->data
.rgctx_entry
= mono_mempool_alloc (mp
, sizeof (MonoJumpInfoRgctxEntry
));
2364 memcpy (res
->data
.rgctx_entry
, patch_info
->data
.rgctx_entry
, sizeof (MonoJumpInfoRgctxEntry
));
2365 res
->data
.rgctx_entry
->data
= mono_patch_info_dup_mp (mp
, res
->data
.rgctx_entry
->data
);
2375 mono_patch_info_hash (gconstpointer data
)
2377 const MonoJumpInfo
*ji
= (MonoJumpInfo
*)data
;
2380 case MONO_PATCH_INFO_RVA
:
2381 case MONO_PATCH_INFO_LDSTR
:
2382 case MONO_PATCH_INFO_TYPE_FROM_HANDLE
:
2383 case MONO_PATCH_INFO_LDTOKEN
:
2384 case MONO_PATCH_INFO_DECLSEC
:
2385 return (ji
->type
<< 8) | ji
->data
.token
->token
;
2386 case MONO_PATCH_INFO_VTABLE
:
2387 case MONO_PATCH_INFO_CLASS
:
2388 case MONO_PATCH_INFO_IID
:
2389 case MONO_PATCH_INFO_ADJUSTED_IID
:
2390 case MONO_PATCH_INFO_CLASS_INIT
:
2391 case MONO_PATCH_INFO_METHODCONST
:
2392 case MONO_PATCH_INFO_METHOD
:
2393 case MONO_PATCH_INFO_METHOD_JUMP
:
2394 case MONO_PATCH_INFO_IMAGE
:
2395 case MONO_PATCH_INFO_INTERNAL_METHOD
:
2396 case MONO_PATCH_INFO_JIT_ICALL_ADDR
:
2397 case MONO_PATCH_INFO_FIELD
:
2398 case MONO_PATCH_INFO_SFLDA
:
2399 return (ji
->type
<< 8) | (gssize
)ji
->data
.target
;
2401 return (ji
->type
<< 8);
2406 * mono_patch_info_equal:
2408 * This might fail to recognize equivalent patches, i.e. floats, so its only
2409 * usable in those cases where this is not a problem, i.e. sharing GOT slots
2413 mono_patch_info_equal (gconstpointer ka
, gconstpointer kb
)
2415 const MonoJumpInfo
*ji1
= (MonoJumpInfo
*)ka
;
2416 const MonoJumpInfo
*ji2
= (MonoJumpInfo
*)kb
;
2418 if (ji1
->type
!= ji2
->type
)
2421 switch (ji1
->type
) {
2422 case MONO_PATCH_INFO_RVA
:
2423 case MONO_PATCH_INFO_LDSTR
:
2424 case MONO_PATCH_INFO_TYPE_FROM_HANDLE
:
2425 case MONO_PATCH_INFO_LDTOKEN
:
2426 case MONO_PATCH_INFO_DECLSEC
:
2427 if ((ji1
->data
.token
->image
!= ji2
->data
.token
->image
) ||
2428 (ji1
->data
.token
->token
!= ji2
->data
.token
->token
) ||
2429 (ji1
->data
.token
->has_context
!= ji2
->data
.token
->has_context
) ||
2430 (ji1
->data
.token
->context
.class_inst
!= ji2
->data
.token
->context
.class_inst
) ||
2431 (ji1
->data
.token
->context
.method_inst
!= ji2
->data
.token
->context
.method_inst
))
2435 if (ji1
->data
.target
!= ji2
->data
.target
)
2444 mono_resolve_patch_target (MonoMethod
*method
, MonoDomain
*domain
, guint8
*code
, MonoJumpInfo
*patch_info
, gboolean run_cctors
)
2446 unsigned char *ip
= patch_info
->ip
.i
+ code
;
2447 gconstpointer target
= NULL
;
2449 switch (patch_info
->type
) {
2450 case MONO_PATCH_INFO_BB
:
2451 g_assert (patch_info
->data
.bb
->native_offset
);
2452 target
= patch_info
->data
.bb
->native_offset
+ code
;
2454 case MONO_PATCH_INFO_ABS
:
2455 target
= patch_info
->data
.target
;
2457 case MONO_PATCH_INFO_LABEL
:
2458 target
= patch_info
->data
.inst
->inst_c0
+ code
;
2460 case MONO_PATCH_INFO_IP
:
2463 case MONO_PATCH_INFO_METHOD_REL
:
2464 target
= code
+ patch_info
->data
.offset
;
2466 case MONO_PATCH_INFO_INTERNAL_METHOD
: {
2467 MonoJitICallInfo
*mi
= mono_find_jit_icall_by_name (patch_info
->data
.name
);
2469 g_warning ("unknown MONO_PATCH_INFO_INTERNAL_METHOD %s", patch_info
->data
.name
);
2470 g_assert_not_reached ();
2472 target
= mono_icall_get_wrapper (mi
);
2475 case MONO_PATCH_INFO_METHOD_JUMP
:
2476 target
= mono_create_jump_trampoline (domain
, patch_info
->data
.method
, FALSE
);
2478 case MONO_PATCH_INFO_METHOD
:
2479 if (patch_info
->data
.method
== method
) {
2482 /* get the trampoline to the method from the domain */
2483 if (method
&& method
->wrapper_type
== MONO_WRAPPER_STATIC_RGCTX_INVOKE
) {
2484 target
= mono_create_jit_trampoline_in_domain (mono_domain_get (),
2485 patch_info
->data
.method
);
2487 target
= mono_create_jit_trampoline (patch_info
->data
.method
);
2491 case MONO_PATCH_INFO_SWITCH
: {
2492 gpointer
*jump_table
;
2495 if (method
&& method
->dynamic
) {
2496 jump_table
= mono_code_manager_reserve (mono_dynamic_code_hash_lookup (domain
, method
)->code_mp
, sizeof (gpointer
) * patch_info
->data
.table
->table_size
);
2498 if (mono_aot_only
) {
2499 jump_table
= mono_domain_alloc (domain
, sizeof (gpointer
) * patch_info
->data
.table
->table_size
);
2501 jump_table
= mono_domain_code_reserve (domain
, sizeof (gpointer
) * patch_info
->data
.table
->table_size
);
2505 for (i
= 0; i
< patch_info
->data
.table
->table_size
; i
++)
2506 jump_table
[i
] = code
+ GPOINTER_TO_INT (patch_info
->data
.table
->table
[i
]);
2507 target
= jump_table
;
2510 case MONO_PATCH_INFO_METHODCONST
:
2511 case MONO_PATCH_INFO_CLASS
:
2512 case MONO_PATCH_INFO_IMAGE
:
2513 case MONO_PATCH_INFO_FIELD
:
2514 target
= patch_info
->data
.target
;
2516 case MONO_PATCH_INFO_IID
:
2517 mono_class_init (patch_info
->data
.klass
);
2518 target
= GINT_TO_POINTER ((int)patch_info
->data
.klass
->interface_id
);
2520 case MONO_PATCH_INFO_ADJUSTED_IID
:
2521 mono_class_init (patch_info
->data
.klass
);
2522 target
= GINT_TO_POINTER ((int)(-((patch_info
->data
.klass
->interface_id
+ 1) * SIZEOF_VOID_P
)));
2524 case MONO_PATCH_INFO_VTABLE
:
2525 target
= mono_class_vtable (domain
, patch_info
->data
.klass
);
2528 case MONO_PATCH_INFO_CLASS_INIT
: {
2529 MonoVTable
*vtable
= mono_class_vtable (domain
, patch_info
->data
.klass
);
2532 target
= mono_create_class_init_trampoline (vtable
);
2535 case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE
:
2536 target
= mono_create_delegate_trampoline (patch_info
->data
.klass
);
2538 case MONO_PATCH_INFO_SFLDA
: {
2539 MonoVTable
*vtable
= mono_class_vtable (domain
, patch_info
->data
.field
->parent
);
2542 if (!vtable
->initialized
&& !(vtable
->klass
->flags
& TYPE_ATTRIBUTE_BEFORE_FIELD_INIT
) && (method
&& mono_class_needs_cctor_run (vtable
->klass
, method
)))
2543 /* Done by the generated code */
2547 mono_runtime_class_init (vtable
);
2549 target
= (char*)vtable
->data
+ patch_info
->data
.field
->offset
;
2552 case MONO_PATCH_INFO_RVA
: {
2553 guint32 field_index
= mono_metadata_token_index (patch_info
->data
.token
->token
);
2556 mono_metadata_field_info (patch_info
->data
.token
->image
, field_index
- 1, NULL
, &rva
, NULL
);
2557 target
= mono_image_rva_map (patch_info
->data
.token
->image
, rva
);
2560 case MONO_PATCH_INFO_R4
:
2561 case MONO_PATCH_INFO_R8
:
2562 target
= patch_info
->data
.target
;
2564 case MONO_PATCH_INFO_EXC_NAME
:
2565 target
= patch_info
->data
.name
;
2567 case MONO_PATCH_INFO_LDSTR
:
2569 mono_ldstr (domain
, patch_info
->data
.token
->image
,
2570 mono_metadata_token_index (patch_info
->data
.token
->token
));
2572 case MONO_PATCH_INFO_TYPE_FROM_HANDLE
: {
2574 MonoClass
*handle_class
;
2576 handle
= mono_ldtoken (patch_info
->data
.token
->image
,
2577 patch_info
->data
.token
->token
, &handle_class
, patch_info
->data
.token
->has_context
? &patch_info
->data
.token
->context
: NULL
);
2578 mono_class_init (handle_class
);
2579 mono_class_init (mono_class_from_mono_type (handle
));
2582 mono_type_get_object (domain
, handle
);
2585 case MONO_PATCH_INFO_LDTOKEN
: {
2587 MonoClass
*handle_class
;
2589 handle
= mono_ldtoken (patch_info
->data
.token
->image
,
2590 patch_info
->data
.token
->token
, &handle_class
, NULL
);
2591 mono_class_init (handle_class
);
2596 case MONO_PATCH_INFO_DECLSEC
:
2597 target
= (mono_metadata_blob_heap (patch_info
->data
.token
->image
, patch_info
->data
.token
->token
) + 2);
2599 case MONO_PATCH_INFO_ICALL_ADDR
:
2600 /* run_cctors == 0 -> AOT */
2601 if (patch_info
->data
.method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
) {
2603 target
= mono_lookup_pinvoke_call (patch_info
->data
.method
, NULL
, NULL
);
2605 g_error ("Unable to resolve pinvoke method '%s' Re-run with MONO_LOG_LEVEL=debug for more information.\n", mono_method_full_name (patch_info
->data
.method
, TRUE
));
2610 target
= mono_lookup_internal_call (patch_info
->data
.method
);
2612 if (!target
&& run_cctors
)
2613 g_error ("Unregistered icall '%s'\n", mono_method_full_name (patch_info
->data
.method
, TRUE
));
2616 case MONO_PATCH_INFO_JIT_ICALL_ADDR
: {
2617 MonoJitICallInfo
*mi
= mono_find_jit_icall_by_name (patch_info
->data
.name
);
2619 g_warning ("unknown MONO_PATCH_INFO_JIT_ICALL_ADDR %s", patch_info
->data
.name
);
2620 g_assert_not_reached ();
2625 case MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG
:
2626 target
= mono_thread_interruption_request_flag ();
2628 case MONO_PATCH_INFO_METHOD_RGCTX
:
2629 target
= mono_method_lookup_rgctx (mono_class_vtable (domain
, patch_info
->data
.method
->klass
), mini_method_get_context (patch_info
->data
.method
)->method_inst
);
2631 case MONO_PATCH_INFO_BB_OVF
:
2632 case MONO_PATCH_INFO_EXC_OVF
:
2633 case MONO_PATCH_INFO_GOT_OFFSET
:
2634 case MONO_PATCH_INFO_NONE
:
2636 case MONO_PATCH_INFO_RGCTX_FETCH
: {
2637 MonoJumpInfoRgctxEntry
*entry
= patch_info
->data
.rgctx_entry
;
2640 switch (entry
->data
->type
) {
2641 case MONO_PATCH_INFO_CLASS
:
2642 slot
= mono_method_lookup_or_register_other_info (entry
->method
, entry
->in_mrgctx
, &entry
->data
->data
.klass
->byval_arg
, entry
->info_type
, mono_method_get_context (entry
->method
));
2644 case MONO_PATCH_INFO_METHOD
:
2645 case MONO_PATCH_INFO_METHODCONST
:
2646 slot
= mono_method_lookup_or_register_other_info (entry
->method
, entry
->in_mrgctx
, entry
->data
->data
.method
, entry
->info_type
, mono_method_get_context (entry
->method
));
2648 case MONO_PATCH_INFO_FIELD
:
2649 slot
= mono_method_lookup_or_register_other_info (entry
->method
, entry
->in_mrgctx
, entry
->data
->data
.field
, entry
->info_type
, mono_method_get_context (entry
->method
));
2652 g_assert_not_reached ();
2656 target
= mono_create_rgctx_lazy_fetch_trampoline (slot
);
2659 case MONO_PATCH_INFO_GENERIC_CLASS_INIT
:
2660 target
= mono_create_generic_class_init_trampoline ();
2662 case MONO_PATCH_INFO_MONITOR_ENTER
:
2663 target
= mono_create_monitor_enter_trampoline ();
2665 case MONO_PATCH_INFO_MONITOR_EXIT
:
2666 target
= mono_create_monitor_exit_trampoline ();
2669 g_assert_not_reached ();
2672 return (gpointer
)target
;
2676 mono_compile_create_vars (MonoCompile
*cfg
)
2678 MonoMethodSignature
*sig
;
2679 MonoMethodHeader
*header
;
2682 header
= mono_method_get_header (cfg
->method
);
2684 sig
= mono_method_signature (cfg
->method
);
2686 if (!MONO_TYPE_IS_VOID (sig
->ret
)) {
2687 cfg
->ret
= mono_compile_create_var (cfg
, sig
->ret
, OP_ARG
);
2688 /* Inhibit optimizations */
2689 cfg
->ret
->flags
|= MONO_INST_VOLATILE
;
2691 if (cfg
->verbose_level
> 2)
2692 g_print ("creating vars\n");
2694 cfg
->args
= mono_mempool_alloc0 (cfg
->mempool
, (sig
->param_count
+ sig
->hasthis
) * sizeof (MonoInst
*));
2697 cfg
->args
[0] = mono_compile_create_var (cfg
, &cfg
->method
->klass
->this_arg
, OP_ARG
);
2699 for (i
= 0; i
< sig
->param_count
; ++i
) {
2700 cfg
->args
[i
+ sig
->hasthis
] = mono_compile_create_var (cfg
, sig
->params
[i
], OP_ARG
);
2703 if (cfg
->verbose_level
> 2) {
2705 printf ("\treturn : ");
2706 mono_print_ins (cfg
->ret
);
2710 printf ("\tthis: ");
2711 mono_print_ins (cfg
->args
[0]);
2714 for (i
= 0; i
< sig
->param_count
; ++i
) {
2715 printf ("\targ [%d]: ", i
);
2716 mono_print_ins (cfg
->args
[i
+ sig
->hasthis
]);
2720 cfg
->locals_start
= cfg
->num_varinfo
;
2721 cfg
->locals
= mono_mempool_alloc0 (cfg
->mempool
, header
->num_locals
* sizeof (MonoInst
*));
2723 if (cfg
->verbose_level
> 2)
2724 g_print ("creating locals\n");
2726 for (i
= 0; i
< header
->num_locals
; ++i
)
2727 cfg
->locals
[i
] = mono_compile_create_var (cfg
, header
->locals
[i
], OP_LOCAL
);
2729 if (cfg
->verbose_level
> 2)
2730 g_print ("locals done\n");
2732 mono_arch_create_vars (cfg
);
2736 mono_print_code (MonoCompile
*cfg
, const char* msg
)
2740 for (bb
= cfg
->bb_entry
; bb
; bb
= bb
->next_bb
)
2741 mono_print_bb (bb
, msg
);
2747 mono_codegen (MonoCompile
*cfg
)
2749 MonoJumpInfo
*patch_info
;
2751 int i
, max_epilog_size
;
2754 for (bb
= cfg
->bb_entry
; bb
; bb
= bb
->next_bb
) {
2755 cfg
->spill_count
= 0;
2756 /* we reuse dfn here */
2757 /* bb->dfn = bb_count++; */
2759 mono_arch_lowering_pass (cfg
, bb
);
2761 if (cfg
->opt
& MONO_OPT_PEEPHOLE
)
2762 mono_arch_peephole_pass_1 (cfg
, bb
);
2765 mono_local_regalloc (cfg
, bb
);
2767 if (cfg
->opt
& MONO_OPT_PEEPHOLE
)
2768 mono_arch_peephole_pass_2 (cfg
, bb
);
2771 if (cfg
->prof_options
& MONO_PROFILE_COVERAGE
)
2772 cfg
->coverage_info
= mono_profiler_coverage_alloc (cfg
->method
, cfg
->num_bblocks
);
2774 code
= mono_arch_emit_prolog (cfg
);
2776 if (cfg
->prof_options
& MONO_PROFILE_ENTER_LEAVE
)
2777 code
= mono_arch_instrument_prolog (cfg
, mono_profiler_method_enter
, code
, FALSE
);
2779 cfg
->code_len
= code
- cfg
->native_code
;
2780 cfg
->prolog_end
= cfg
->code_len
;
2782 mono_debug_open_method (cfg
);
2784 /* emit code all basic blocks */
2785 for (bb
= cfg
->bb_entry
; bb
; bb
= bb
->next_bb
) {
2786 bb
->native_offset
= cfg
->code_len
;
2787 //if ((bb == cfg->bb_entry) || !(bb->region == -1 && !bb->dfn))
2788 mono_arch_output_basic_block (cfg
, bb
);
2790 if (bb
== cfg
->bb_exit
) {
2791 cfg
->epilog_begin
= cfg
->code_len
;
2793 if (cfg
->prof_options
& MONO_PROFILE_ENTER_LEAVE
) {
2794 code
= cfg
->native_code
+ cfg
->code_len
;
2795 code
= mono_arch_instrument_epilog (cfg
, mono_profiler_method_leave
, code
, FALSE
);
2796 cfg
->code_len
= code
- cfg
->native_code
;
2797 g_assert (cfg
->code_len
< cfg
->code_size
);
2800 mono_arch_emit_epilog (cfg
);
2804 mono_arch_emit_exceptions (cfg
);
2806 max_epilog_size
= 0;
2808 code
= cfg
->native_code
+ cfg
->code_len
;
2810 /* we always allocate code in cfg->domain->code_mp to increase locality */
2811 cfg
->code_size
= cfg
->code_len
+ max_epilog_size
;
2812 /* fixme: align to MONO_ARCH_CODE_ALIGNMENT */
2814 if (cfg
->method
->dynamic
) {
2815 guint unwindlen
= 0;
2816 #ifdef MONO_ARCH_HAVE_UNWIND_TABLE
2817 unwindlen
= mono_arch_unwindinfo_get_size (cfg
->arch
.unwindinfo
);
2819 /* Allocate the code into a separate memory pool so it can be freed */
2820 cfg
->dynamic_info
= g_new0 (MonoJitDynamicMethodInfo
, 1);
2821 cfg
->dynamic_info
->code_mp
= mono_code_manager_new_dynamic ();
2822 mono_domain_lock (cfg
->domain
);
2823 mono_dynamic_code_hash_insert (cfg
->domain
, cfg
->method
, cfg
->dynamic_info
);
2824 mono_domain_unlock (cfg
->domain
);
2826 code
= mono_code_manager_reserve (cfg
->dynamic_info
->code_mp
, cfg
->code_size
+ unwindlen
);
2828 guint unwindlen
= 0;
2829 #ifdef MONO_ARCH_HAVE_UNWIND_TABLE
2830 unwindlen
= mono_arch_unwindinfo_get_size (cfg
->arch
.unwindinfo
);
2832 code
= mono_domain_code_reserve (cfg
->domain
, cfg
->code_size
+ unwindlen
);
2835 memcpy (code
, cfg
->native_code
, cfg
->code_len
);
2836 g_free (cfg
->native_code
);
2837 cfg
->native_code
= code
;
2838 code
= cfg
->native_code
+ cfg
->code_len
;
2840 /* g_assert (((int)cfg->native_code & (MONO_ARCH_CODE_ALIGNMENT - 1)) == 0); */
2841 for (patch_info
= cfg
->patch_info
; patch_info
; patch_info
= patch_info
->next
) {
2842 switch (patch_info
->type
) {
2843 case MONO_PATCH_INFO_ABS
: {
2844 MonoJitICallInfo
*info
= mono_find_jit_icall_by_addr (patch_info
->data
.target
);
2847 * Change patches of type MONO_PATCH_INFO_ABS into patches describing the
2851 //printf ("TEST %s %p\n", info->name, patch_info->data.target);
2852 // FIXME: CLEAN UP THIS MESS.
2853 if ((cfg
->method
->wrapper_type
== MONO_WRAPPER_MANAGED_TO_NATIVE
) &&
2854 strstr (cfg
->method
->name
, info
->name
)) {
2856 * This is an icall wrapper, and this is a call to the
2859 if (cfg
->compile_aot
) {
2860 patch_info
->type
= MONO_PATCH_INFO_JIT_ICALL_ADDR
;
2861 patch_info
->data
.name
= info
->name
;
2864 /* for these array methods we currently register the same function pointer
2865 * since it's a vararg function. But this means that mono_find_jit_icall_by_addr ()
2866 * will return the incorrect one depending on the order they are registered.
2867 * See tests/test-arr.cs
2869 if (strstr (info
->name
, "ves_array_new_va_") == NULL
&& strstr (info
->name
, "ves_array_element_address_") == NULL
) {
2870 patch_info
->type
= MONO_PATCH_INFO_INTERNAL_METHOD
;
2871 patch_info
->data
.name
= info
->name
;
2876 if (patch_info
->type
== MONO_PATCH_INFO_ABS
) {
2877 if (cfg
->abs_patches
) {
2878 MonoJumpInfo
*abs_ji
= g_hash_table_lookup (cfg
->abs_patches
, patch_info
->data
.target
);
2880 patch_info
->type
= abs_ji
->type
;
2881 patch_info
->data
.target
= abs_ji
->data
.target
;
2888 case MONO_PATCH_INFO_SWITCH
: {
2890 if (cfg
->method
->dynamic
) {
2891 table
= mono_code_manager_reserve (cfg
->dynamic_info
->code_mp
, sizeof (gpointer
) * patch_info
->data
.table
->table_size
);
2893 table
= mono_domain_code_reserve (cfg
->domain
, sizeof (gpointer
) * patch_info
->data
.table
->table_size
);
2896 for (i
= 0; i
< patch_info
->data
.table
->table_size
; i
++) {
2897 /* Might be NULL if the switch is eliminated */
2898 if (patch_info
->data
.table
->table
[i
]) {
2899 g_assert (patch_info
->data
.table
->table
[i
]->native_offset
);
2900 table
[i
] = GINT_TO_POINTER (patch_info
->data
.table
->table
[i
]->native_offset
);
2905 patch_info
->data
.table
->table
= (MonoBasicBlock
**)table
;
2908 case MONO_PATCH_INFO_METHOD_JUMP
: {
2910 MonoDomain
*domain
= cfg
->domain
;
2911 unsigned char *ip
= cfg
->native_code
+ patch_info
->ip
.i
;
2913 mono_domain_lock (domain
);
2914 if (!domain_jit_info (domain
)->jump_target_hash
)
2915 domain_jit_info (domain
)->jump_target_hash
= g_hash_table_new (NULL
, NULL
);
2916 list
= g_hash_table_lookup (domain_jit_info (domain
)->jump_target_hash
, patch_info
->data
.method
);
2917 list
= g_slist_prepend (list
, ip
);
2918 g_hash_table_insert (domain_jit_info (domain
)->jump_target_hash
, patch_info
->data
.method
, list
);
2919 mono_domain_unlock (domain
);
2928 #ifdef VALGRIND_JIT_REGISTER_MAP
2929 if (valgrind_register
){
2930 char* nm
= mono_method_full_name (cfg
->method
, TRUE
);
2931 VALGRIND_JIT_REGISTER_MAP (nm
, cfg
->native_code
, cfg
->native_code
+ cfg
->code_len
);
2936 if (cfg
->verbose_level
> 0) {
2937 char* nm
= mono_method_full_name (cfg
->method
, TRUE
);
2938 g_print ("Method %s emitted at %p to %p (code length %d) [%s]\n",
2940 cfg
->native_code
, cfg
->native_code
+ cfg
->code_len
, cfg
->code_len
, cfg
->domain
->friendly_name
);
2945 gboolean is_generic
= FALSE
;
2947 if (cfg
->method
->is_inflated
|| mono_method_get_generic_container (cfg
->method
) ||
2948 cfg
->method
->klass
->generic_container
|| cfg
->method
->klass
->generic_class
) {
2952 if (cfg
->generic_sharing_context
)
2953 g_assert (is_generic
);
2956 #ifdef MONO_ARCH_HAVE_SAVE_UNWIND_INFO
2957 mono_arch_save_unwind_info (cfg
);
2960 mono_arch_patch_code (cfg
->method
, cfg
->domain
, cfg
->native_code
, cfg
->patch_info
, cfg
->run_cctors
);
2962 if (cfg
->method
->dynamic
) {
2963 mono_code_manager_commit (cfg
->dynamic_info
->code_mp
, cfg
->native_code
, cfg
->code_size
, cfg
->code_len
);
2965 mono_domain_code_commit (cfg
->domain
, cfg
->native_code
, cfg
->code_size
, cfg
->code_len
);
2968 mono_arch_flush_icache (cfg
->native_code
, cfg
->code_len
);
2970 mono_debug_close_method (cfg
);
2971 #ifdef MONO_ARCH_HAVE_UNWIND_TABLE
2972 mono_arch_unwindinfo_install_unwind_info (&cfg
->arch
.unwindinfo
, cfg
->native_code
, cfg
->code_len
);
2977 compute_reachable (MonoBasicBlock
*bb
)
2981 if (!(bb
->flags
& BB_VISITED
)) {
2982 bb
->flags
|= BB_VISITED
;
2983 for (i
= 0; i
< bb
->out_count
; ++i
)
2984 compute_reachable (bb
->out_bb
[i
]);
2989 * mini_method_compile:
2990 * @method: the method to compile
2991 * @opts: the optimization flags to use
2992 * @domain: the domain where the method will be compiled in
2993 * @run_cctors: whether we should run type ctors if possible
2994 * @compile_aot: whether this is an AOT compilation
2995 * @parts: debug flag
2997 * Returns: a MonoCompile* pointer. Caller must check the exception_type
2998 * field in the returned struct to see if compilation succeded.
3001 mini_method_compile (MonoMethod
*method
, guint32 opts
, MonoDomain
*domain
, gboolean run_cctors
, gboolean compile_aot
, int parts
)
3003 MonoMethodHeader
*header
;
3007 int dfn
, i
, code_size_ratio
;
3008 gboolean deadce_has_run
= FALSE
;
3009 gboolean try_generic_shared
;
3010 MonoMethod
*method_to_compile
, *method_to_register
;
3011 int generic_info_size
;
3013 mono_jit_stats
.methods_compiled
++;
3014 if (mono_profiler_get_events () & MONO_PROFILE_JIT_COMPILATION
)
3015 mono_profiler_method_jit (method
);
3016 if (MONO_PROBE_METHOD_COMPILE_BEGIN_ENABLED ())
3017 MONO_PROBE_METHOD_COMPILE_BEGIN (method
);
3020 /* We are passed the original generic method definition */
3021 try_generic_shared
= mono_class_generic_sharing_enabled (method
->klass
) &&
3022 (opts
& MONO_OPT_GSHARED
) && (method
->is_generic
|| method
->klass
->generic_container
);
3024 try_generic_shared
= mono_class_generic_sharing_enabled (method
->klass
) &&
3025 (opts
& MONO_OPT_GSHARED
) && mono_method_is_generic_sharable_impl (method
, FALSE
);
3027 if (opts
& MONO_OPT_GSHARED
) {
3028 if (try_generic_shared
)
3029 mono_stats
.generics_sharable_methods
++;
3030 else if (mono_method_is_generic_impl (method
))
3031 mono_stats
.generics_unsharable_methods
++;
3035 if (try_generic_shared
) {
3036 MonoMethod
*declaring_method
;
3037 MonoGenericContext
*shared_context
;
3040 declaring_method
= method
;
3042 declaring_method
= mono_method_get_declaring_generic_method (method
);
3043 if (method
->klass
->generic_class
)
3044 g_assert (method
->klass
->generic_class
->container_class
== declaring_method
->klass
);
3046 g_assert (method
->klass
== declaring_method
->klass
);
3049 if (declaring_method
->is_generic
)
3050 shared_context
= &(mono_method_get_generic_container (declaring_method
)->context
);
3052 shared_context
= &declaring_method
->klass
->generic_container
->context
;
3054 method_to_compile
= mono_class_inflate_generic_method (declaring_method
, shared_context
);
3055 g_assert (method_to_compile
);
3057 method_to_compile
= method
;
3060 cfg
= g_new0 (MonoCompile
, 1);
3061 cfg
->method
= method_to_compile
;
3062 cfg
->mempool
= mono_mempool_new ();
3064 cfg
->prof_options
= mono_profiler_get_events ();
3065 cfg
->run_cctors
= run_cctors
;
3066 cfg
->domain
= domain
;
3067 cfg
->verbose_level
= mini_verbose
;
3068 cfg
->compile_aot
= compile_aot
;
3069 cfg
->skip_visibility
= method
->skip_visibility
;
3070 cfg
->orig_method
= method
;
3071 if (try_generic_shared
)
3072 cfg
->generic_sharing_context
= (MonoGenericSharingContext
*)&cfg
->generic_sharing_context
;
3073 cfg
->token_info_hash
= g_hash_table_new (NULL
, NULL
);
3075 if (cfg
->compile_aot
&& !try_generic_shared
&& (method
->is_generic
|| method
->klass
->generic_container
)) {
3076 cfg
->exception_type
= MONO_EXCEPTION_GENERIC_SHARING_FAILED
;
3080 /* The debugger has no liveness information, so avoid sharing registers/stack slots */
3081 if (mono_debug_using_mono_debugger () || debug_options
.mdb_optimizations
) {
3082 cfg
->disable_reuse_registers
= TRUE
;
3083 cfg
->disable_reuse_stack_slots
= TRUE
;
3085 * This decreases the change the debugger will read registers/stack slots which are
3086 * not yet initialized.
3088 cfg
->disable_initlocals_opt
= TRUE
;
3090 /* Temporarily disable this when running in the debugger until we have support
3091 * for this in the debugger. */
3092 cfg
->disable_omit_fp
= TRUE
;
3094 /* The debugger needs all locals to be on the stack or in a global register */
3095 cfg
->disable_vreg_to_lvreg
= TRUE
;
3097 /* Don't remove unused variables when running inside the debugger since the user
3098 * may still want to view them. */
3099 cfg
->disable_deadce_vars
= TRUE
;
3101 // cfg->opt |= MONO_OPT_SHARED;
3102 cfg
->opt
&= ~MONO_OPT_DEADCE
;
3103 cfg
->opt
&= ~MONO_OPT_INLINE
;
3104 cfg
->opt
&= ~MONO_OPT_COPYPROP
;
3105 cfg
->opt
&= ~MONO_OPT_CONSPROP
;
3106 cfg
->opt
&= ~MONO_OPT_GSHARED
;
3109 header
= mono_method_get_header (method_to_compile
);
3111 cfg
->exception_type
= MONO_EXCEPTION_INVALID_PROGRAM
;
3112 cfg
->exception_message
= g_strdup_printf ("Missing or incorrect header for method %s", cfg
->method
->name
);
3113 if (MONO_PROBE_METHOD_COMPILE_END_ENABLED ())
3114 MONO_PROBE_METHOD_COMPILE_END (method
, FALSE
);
3115 if (cfg
->prof_options
& MONO_PROFILE_JIT_COMPILATION
)
3116 mono_profiler_method_end_jit (method
, NULL
, MONO_PROFILE_FAILED
);
3120 if (getenv ("MONO_VERBOSE_METHOD")) {
3121 if (strcmp (cfg
->method
->name
, getenv ("MONO_VERBOSE_METHOD")) == 0)
3122 cfg
->verbose_level
= 4;
3125 ip
= (guint8
*)header
->code
;
3127 cfg
->intvars
= mono_mempool_alloc0 (cfg
->mempool
, sizeof (guint16
) * STACK_MAX
* header
->max_stack
);
3129 if (cfg
->verbose_level
> 2) {
3130 if (cfg
->generic_sharing_context
)
3131 g_print ("converting shared method %s\n", mono_method_full_name (method
, TRUE
));
3133 g_print ("converting method %s\n", mono_method_full_name (method
, TRUE
));
3136 if (cfg
->opt
& (MONO_OPT_ABCREM
| MONO_OPT_SSAPRE
))
3137 cfg
->opt
|= MONO_OPT_SSA
;
3140 if ((cfg->method->klass->image != mono_defaults.corlib) || (strstr (cfg->method->klass->name, "StackOverflowException") && strstr (cfg->method->name, ".ctor")) || (strstr (cfg->method->klass->name, "OutOfMemoryException") && strstr (cfg->method->name, ".ctor")))
3141 cfg->globalra = TRUE;
3144 //cfg->globalra = TRUE;
3146 //if (!strcmp (cfg->method->klass->name, "Tests") && !cfg->method->wrapper_type)
3147 // cfg->globalra = TRUE;
3150 static int count
= 0;
3154 if (getenv ("COUNT2")) {
3155 cfg->globalra = TRUE;
3156 if (count == atoi (getenv ("COUNT2")))
3157 printf ("LAST: %s\n", mono_method_full_name (cfg->method, TRUE));
3158 if (count > atoi (getenv ("COUNT2")))
3159 cfg->globalra = FALSE;
3164 if (header
->clauses
)
3165 cfg
->globalra
= FALSE
;
3167 if (cfg
->method
->wrapper_type
== MONO_WRAPPER_NATIVE_TO_MANAGED
)
3168 /* The code in the prolog clobbers caller saved registers */
3169 cfg
->globalra
= FALSE
;
3171 // FIXME: Disable globalra in case of tracing/profiling
3173 if (cfg
->method
->save_lmf
)
3174 /* The LMF saving code might clobber caller saved registers */
3175 cfg
->globalra
= FALSE
;
3177 if (header
->code_size
> 5000)
3179 /* Too large bblocks could overflow the ins positions */
3180 cfg
->globalra
= FALSE
;
3182 cfg
->rs
= mono_regstate_new ();
3184 cfg
->rs
->next_vreg
= MONO_MAX_IREGS
+ MONO_MAX_FREGS
;
3185 cfg
->next_vreg
= cfg
->rs
->next_vreg
;
3187 /* FIXME: Fix SSA to handle branches inside bblocks */
3188 if (cfg
->opt
& MONO_OPT_SSA
)
3189 cfg
->enable_extended_bblocks
= FALSE
;
3192 * FIXME: This confuses liveness analysis because variables which are assigned after
3193 * a branch inside a bblock become part of the kill set, even though the assignment
3194 * might not get executed. This causes the optimize_initlocals pass to delete some
3195 * assignments which are needed.
3196 * Also, the mono_if_conversion pass needs to be modified to recognize the code
3199 //cfg->enable_extended_bblocks = TRUE;
3202 * create MonoInst* which represents arguments and local variables
3204 mono_compile_create_vars (cfg
);
3206 /* SSAPRE is not supported on linear IR */
3207 cfg
->opt
&= ~MONO_OPT_SSAPRE
;
3209 i
= mono_method_to_ir (cfg
, method_to_compile
, NULL
, NULL
, NULL
, NULL
, NULL
, 0, FALSE
);
3212 if (try_generic_shared
&& cfg
->exception_type
== MONO_EXCEPTION_GENERIC_SHARING_FAILED
) {
3214 if (MONO_PROBE_METHOD_COMPILE_END_ENABLED ())
3215 MONO_PROBE_METHOD_COMPILE_END (method
, FALSE
);
3218 mono_destroy_compile (cfg
);
3219 try_generic_shared
= FALSE
;
3220 goto restart_compile
;
3222 g_assert (cfg
->exception_type
!= MONO_EXCEPTION_GENERIC_SHARING_FAILED
);
3224 if (MONO_PROBE_METHOD_COMPILE_END_ENABLED ())
3225 MONO_PROBE_METHOD_COMPILE_END (method
, FALSE
);
3226 if (cfg
->prof_options
& MONO_PROFILE_JIT_COMPILATION
)
3227 mono_profiler_method_end_jit (method
, NULL
, MONO_PROFILE_FAILED
);
3228 /* cfg contains the details of the failure, so let the caller cleanup */
3232 mono_jit_stats
.basic_blocks
+= cfg
->num_bblocks
;
3233 mono_jit_stats
.max_basic_blocks
= MAX (cfg
->num_bblocks
, mono_jit_stats
.max_basic_blocks
);
3235 /*g_print ("numblocks = %d\n", cfg->num_bblocks);*/
3237 mono_decompose_long_opts (cfg
);
3239 /* Should be done before branch opts */
3240 if (cfg
->opt
& (MONO_OPT_CONSPROP
| MONO_OPT_COPYPROP
))
3241 mono_local_cprop (cfg
);
3243 if (cfg
->opt
& MONO_OPT_BRANCH
)
3244 mono_optimize_branches (cfg
);
3246 /* This must be done _before_ global reg alloc and _after_ decompose */
3247 mono_handle_global_vregs (cfg
);
3248 if (cfg
->opt
& MONO_OPT_DEADCE
)
3249 mono_local_deadce (cfg
);
3250 mono_if_conversion (cfg
);
3252 if ((cfg
->opt
& MONO_OPT_SSAPRE
) || cfg
->globalra
)
3253 mono_remove_critical_edges (cfg
);
3255 /* Depth-first ordering on basic blocks */
3256 cfg
->bblocks
= mono_mempool_alloc (cfg
->mempool
, sizeof (MonoBasicBlock
*) * (cfg
->num_bblocks
+ 1));
3259 df_visit (cfg
->bb_entry
, &dfn
, cfg
->bblocks
);
3260 if (cfg
->num_bblocks
!= dfn
+ 1) {
3263 cfg
->num_bblocks
= dfn
+ 1;
3265 /* remove unreachable code, because the code in them may be
3266 * inconsistent (access to dead variables for example) */
3267 for (bb
= cfg
->bb_entry
; bb
; bb
= bb
->next_bb
)
3268 bb
->flags
&= ~BB_VISITED
;
3269 compute_reachable (cfg
->bb_entry
);
3270 for (bb
= cfg
->bb_entry
; bb
; bb
= bb
->next_bb
)
3271 if (bb
->flags
& BB_EXCEPTION_HANDLER
)
3272 compute_reachable (bb
);
3273 for (bb
= cfg
->bb_entry
; bb
; bb
= bb
->next_bb
) {
3274 if (!(bb
->flags
& BB_VISITED
)) {
3275 if (cfg
->verbose_level
> 1)
3276 g_print ("found unreachable code in BB%d\n", bb
->block_num
);
3277 bb
->code
= bb
->last_ins
= NULL
;
3280 for (bb
= cfg
->bb_entry
; bb
; bb
= bb
->next_bb
)
3281 bb
->flags
&= ~BB_VISITED
;
3284 if (((cfg
->num_varinfo
> 2000) || (cfg
->num_bblocks
> 1000)) && !cfg
->compile_aot
) {
3286 * we disable some optimizations if there are too many variables
3287 * because JIT time may become too expensive. The actual number needs
3288 * to be tweaked and eventually the non-linear algorithms should be fixed.
3290 cfg
->opt
&= ~ (MONO_OPT_LINEARS
| MONO_OPT_COPYPROP
| MONO_OPT_CONSPROP
);
3291 cfg
->disable_ssa
= TRUE
;
3294 if (cfg
->opt
& MONO_OPT_LOOP
) {
3295 mono_compile_dominator_info (cfg
, MONO_COMP_DOM
| MONO_COMP_IDOM
);
3296 mono_compute_natural_loops (cfg
);
3299 /* after method_to_ir */
3301 if (MONO_PROBE_METHOD_COMPILE_END_ENABLED ())
3302 MONO_PROBE_METHOD_COMPILE_END (method
, TRUE
);
3306 //#define DEBUGSSA "logic_run"
3307 #define DEBUGSSA_CLASS "Tests"
3310 if (!header
->num_clauses
&& !cfg
->disable_ssa
) {
3311 mono_local_cprop (cfg
);
3314 mono_ssa_compute (cfg
);
3318 if (cfg
->opt
& MONO_OPT_SSA
) {
3319 if (!(cfg
->comp_done
& MONO_COMP_SSA
) && !header
->num_clauses
&& !cfg
->disable_ssa
) {
3321 mono_ssa_compute (cfg
);
3324 if (cfg
->verbose_level
>= 2) {
3331 /* after SSA translation */
3333 if (MONO_PROBE_METHOD_COMPILE_END_ENABLED ())
3334 MONO_PROBE_METHOD_COMPILE_END (method
, TRUE
);
3338 if ((cfg
->opt
& MONO_OPT_CONSPROP
) || (cfg
->opt
& MONO_OPT_COPYPROP
)) {
3339 if (cfg
->comp_done
& MONO_COMP_SSA
) {
3341 mono_ssa_cprop (cfg
);
3347 if (cfg
->comp_done
& MONO_COMP_SSA
) {
3348 //mono_ssa_strength_reduction (cfg);
3350 if (cfg
->opt
& MONO_OPT_SSAPRE
) {
3351 mono_perform_ssapre (cfg
);
3352 //mono_local_cprop (cfg);
3355 if (cfg
->opt
& MONO_OPT_DEADCE
) {
3356 mono_ssa_deadce (cfg
);
3357 deadce_has_run
= TRUE
;
3360 if ((cfg
->flags
& (MONO_CFG_HAS_LDELEMA
|MONO_CFG_HAS_CHECK_THIS
)) && (cfg
->opt
& MONO_OPT_ABCREM
))
3361 mono_perform_abc_removal (cfg
);
3363 mono_ssa_remove (cfg
);
3364 mono_local_cprop (cfg
);
3365 mono_handle_global_vregs (cfg
);
3366 if (cfg
->opt
& MONO_OPT_DEADCE
)
3367 mono_local_deadce (cfg
);
3369 if (cfg
->opt
& MONO_OPT_BRANCH
) {
3372 mono_optimize_branches (cfg
);
3374 /* Have to recompute cfg->bblocks and bb->dfn */
3375 if (cfg
->globalra
) {
3376 mono_remove_critical_edges (cfg
);
3378 for (bb
= cfg
->bb_entry
; bb
; bb
= bb
->next_bb
)
3381 /* Depth-first ordering on basic blocks */
3382 cfg
->bblocks
= mono_mempool_alloc (cfg
->mempool
, sizeof (MonoBasicBlock
*) * (cfg
->num_bblocks
+ 1));
3385 df_visit (cfg
->bb_entry
, &dfn
, cfg
->bblocks
);
3386 cfg
->num_bblocks
= dfn
+ 1;
3392 /* after SSA removal */
3394 if (MONO_PROBE_METHOD_COMPILE_END_ENABLED ())
3395 MONO_PROBE_METHOD_COMPILE_END (method
, TRUE
);
3399 #ifdef MONO_ARCH_SOFT_FLOAT
3400 mono_decompose_soft_float (cfg
);
3402 mono_decompose_vtype_opts (cfg
);
3403 if (cfg
->flags
& MONO_CFG_HAS_ARRAY_ACCESS
)
3404 mono_decompose_array_access_opts (cfg
);
3409 g_assert (cfg
->got_var_allocated
);
3412 * Allways allocate the GOT var to a register, because keeping it
3413 * in memory will increase the number of live temporaries in some
3414 * code created by inssel.brg, leading to the well known spills+
3415 * branches problem. Testcase: mcs crash in
3416 * System.MonoCustomAttrs:GetCustomAttributes.
3418 regs
= mono_arch_get_global_int_regs (cfg
);
3420 cfg
->got_var
->opcode
= OP_REGVAR
;
3421 cfg
->got_var
->dreg
= GPOINTER_TO_INT (regs
->data
);
3422 cfg
->used_int_regs
|= 1LL << cfg
->got_var
->dreg
;
3427 /* todo: remove code when we have verified that the liveness for try/catch blocks
3431 * Currently, this can't be commented out since exception blocks are not
3432 * processed during liveness analysis.
3434 mono_liveness_handle_exception_clauses (cfg
);
3436 if (cfg
->globalra
) {
3439 /* Have to do this before regalloc since it can create vregs */
3440 for (bb
= cfg
->bb_entry
; bb
; bb
= bb
->next_bb
)
3441 mono_arch_lowering_pass (cfg
, bb
);
3443 mono_global_regalloc (cfg
);
3446 if ((cfg
->opt
& MONO_OPT_LINEARS
) && !cfg
->globalra
) {
3449 /* fixme: maybe we can avoid to compute livenesss here if already computed ? */
3450 cfg
->comp_done
&= ~MONO_COMP_LIVENESS
;
3451 if (!(cfg
->comp_done
& MONO_COMP_LIVENESS
))
3452 mono_analyze_liveness (cfg
);
3454 if ((vars
= mono_arch_get_allocatable_int_vars (cfg
))) {
3455 regs
= mono_arch_get_global_int_regs (cfg
);
3457 regs
= g_list_delete_link (regs
, regs
);
3458 mono_linear_scan (cfg
, vars
, regs
, &cfg
->used_int_regs
);
3462 //mono_print_code (cfg);
3466 /* variables are allocated after decompose, since decompose could create temps */
3468 mono_arch_allocate_vars (cfg
);
3472 gboolean need_local_opts
;
3474 if (!cfg
->globalra
) {
3475 mono_spill_global_vars (cfg
, &need_local_opts
);
3477 if (need_local_opts
|| cfg
->compile_aot
) {
3478 /* To optimize code created by spill_global_vars */
3479 mono_local_cprop (cfg
);
3480 if (cfg
->opt
& MONO_OPT_DEADCE
)
3481 mono_local_deadce (cfg
);
3485 /* Add branches between non-consecutive bblocks */
3486 for (bb
= cfg
->bb_entry
; bb
; bb
= bb
->next_bb
) {
3487 if (bb
->last_ins
&& MONO_IS_COND_BRANCH_OP (bb
->last_ins
) &&
3488 bb
->last_ins
->inst_false_bb
&& bb
->next_bb
!= bb
->last_ins
->inst_false_bb
) {
3489 /* we are careful when inverting, since bugs like #59580
3490 * could show up when dealing with NaNs.
3492 if (MONO_IS_COND_BRANCH_NOFP(bb
->last_ins
) && bb
->next_bb
== bb
->last_ins
->inst_true_bb
) {
3493 MonoBasicBlock
*tmp
= bb
->last_ins
->inst_true_bb
;
3494 bb
->last_ins
->inst_true_bb
= bb
->last_ins
->inst_false_bb
;
3495 bb
->last_ins
->inst_false_bb
= tmp
;
3497 bb
->last_ins
->opcode
= mono_reverse_branch_op (bb
->last_ins
->opcode
);
3499 MonoInst
*inst
= mono_mempool_alloc0 (cfg
->mempool
, sizeof (MonoInst
));
3500 inst
->opcode
= OP_BR
;
3501 inst
->inst_target_bb
= bb
->last_ins
->inst_false_bb
;
3502 mono_bblock_add_inst (bb
, inst
);
3507 if (cfg
->verbose_level
>= 4 && !cfg
->globalra
) {
3508 for (bb
= cfg
->bb_entry
; bb
; bb
= bb
->next_bb
) {
3509 MonoInst
*tree
= bb
->code
;
3510 g_print ("DUMP BLOCK %d:\n", bb
->block_num
);
3513 for (; tree
; tree
= tree
->next
) {
3514 mono_print_ins_index (-1, tree
);
3520 for (bb
= cfg
->bb_entry
; bb
; bb
= bb
->next_bb
) {
3521 bb
->max_vreg
= cfg
->next_vreg
;
3526 if (cfg
->verbose_level
>= 2) {
3527 char *id
= mono_method_full_name (cfg
->method
, FALSE
);
3528 mono_disassemble_code (cfg
, cfg
->native_code
, cfg
->code_len
, id
+ 3);
3532 if (cfg
->generic_sharing_context
)
3533 generic_info_size
= sizeof (MonoGenericJitInfo
);
3535 generic_info_size
= 0;
3537 if (cfg
->method
->dynamic
) {
3538 jinfo
= g_malloc0 (sizeof (MonoJitInfo
) + (header
->num_clauses
* sizeof (MonoJitExceptionInfo
)) +
3541 jinfo
= mono_domain_alloc0 (cfg
->domain
, sizeof (MonoJitInfo
) +
3542 (header
->num_clauses
* sizeof (MonoJitExceptionInfo
)) +
3546 if (cfg
->generic_sharing_context
) {
3547 MonoGenericContext object_context
= mono_method_construct_object_context (method_to_compile
);
3549 method_to_register
= mono_class_inflate_generic_method (method_to_compile
, &object_context
);
3551 g_assert (method
== method_to_compile
);
3552 method_to_register
= method
;
3555 jinfo
->method
= method_to_register
;
3556 jinfo
->code_start
= cfg
->native_code
;
3557 jinfo
->code_size
= cfg
->code_len
;
3558 jinfo
->used_regs
= cfg
->used_int_regs
;
3559 jinfo
->domain_neutral
= (cfg
->opt
& MONO_OPT_SHARED
) != 0;
3560 jinfo
->cas_inited
= FALSE
; /* initialization delayed at the first stalk walk using this method */
3561 jinfo
->num_clauses
= header
->num_clauses
;
3563 if (cfg
->generic_sharing_context
) {
3565 MonoGenericJitInfo
*gi
;
3567 jinfo
->has_generic_jit_info
= 1;
3569 gi
= mono_jit_info_get_generic_jit_info (jinfo
);
3572 gi
->generic_sharing_context
= cfg
->generic_sharing_context
;
3574 if ((method_to_compile
->flags
& METHOD_ATTRIBUTE_STATIC
) ||
3575 mini_method_get_context (method_to_compile
)->method_inst
||
3576 method_to_compile
->klass
->valuetype
) {
3577 g_assert (cfg
->rgctx_var
);
3582 if ((method_to_compile
->flags
& METHOD_ATTRIBUTE_STATIC
) ||
3583 mini_method_get_context (method_to_compile
)->method_inst
||
3584 method_to_compile
->klass
->valuetype
) {
3585 inst
= cfg
->rgctx_var
;
3586 g_assert (inst
->opcode
== OP_REGOFFSET
);
3588 inst
= cfg
->args
[0];
3591 if (inst
->opcode
== OP_REGVAR
) {
3592 gi
->this_in_reg
= 1;
3593 gi
->this_reg
= inst
->dreg
;
3595 g_assert (inst
->opcode
== OP_REGOFFSET
);
3597 g_assert (inst
->inst_basereg
== X86_EBP
);
3598 #elif defined(__x86_64__)
3599 g_assert (inst
->inst_basereg
== X86_EBP
|| inst
->inst_basereg
== X86_ESP
);
3601 g_assert (inst
->inst_offset
>= G_MININT32
&& inst
->inst_offset
<= G_MAXINT32
);
3603 gi
->this_in_reg
= 0;
3604 gi
->this_reg
= inst
->inst_basereg
;
3605 gi
->this_offset
= inst
->inst_offset
;
3609 if (header
->num_clauses
) {
3612 for (i
= 0; i
< header
->num_clauses
; i
++) {
3613 MonoExceptionClause
*ec
= &header
->clauses
[i
];
3614 MonoJitExceptionInfo
*ei
= &jinfo
->clauses
[i
];
3615 MonoBasicBlock
*tblock
;
3618 ei
->flags
= ec
->flags
;
3620 exvar
= mono_find_exvar_for_offset (cfg
, ec
->handler_offset
);
3621 ei
->exvar_offset
= exvar
? exvar
->inst_offset
: 0;
3623 if (ei
->flags
== MONO_EXCEPTION_CLAUSE_FILTER
) {
3624 tblock
= cfg
->cil_offset_to_bb
[ec
->data
.filter_offset
];
3626 ei
->data
.filter
= cfg
->native_code
+ tblock
->native_offset
;
3628 ei
->data
.catch_class
= ec
->data
.catch_class
;
3631 tblock
= cfg
->cil_offset_to_bb
[ec
->try_offset
];
3633 ei
->try_start
= cfg
->native_code
+ tblock
->native_offset
;
3634 g_assert (tblock
->native_offset
);
3635 tblock
= cfg
->cil_offset_to_bb
[ec
->try_offset
+ ec
->try_len
];
3637 ei
->try_end
= cfg
->native_code
+ tblock
->native_offset
;
3638 g_assert (tblock
->native_offset
);
3639 tblock
= cfg
->cil_offset_to_bb
[ec
->handler_offset
];
3641 ei
->handler_start
= cfg
->native_code
+ tblock
->native_offset
;
3646 * Its possible to generate dwarf unwind info for xdebug etc, but not actually
3647 * using it during runtime, hence the define.
3649 #ifdef MONO_ARCH_HAVE_XP_UNWIND
3650 if (cfg
->unwind_ops
) {
3652 guint8
*unwind_info
= mono_unwind_ops_encode (cfg
->unwind_ops
, &info_len
);
3654 jinfo
->used_regs
= mono_cache_unwind_info (unwind_info
, info_len
);
3655 g_free (unwind_info
);
3659 cfg
->jit_info
= jinfo
;
3660 #if defined(__arm__)
3661 mono_arch_fixup_jinfo (cfg
);
3664 mono_save_xdebug_info (cfg
);
3666 if (!cfg
->compile_aot
) {
3667 mono_domain_lock (cfg
->domain
);
3668 mono_jit_info_table_add (cfg
->domain
, jinfo
);
3670 if (cfg
->method
->dynamic
)
3671 mono_dynamic_code_hash_lookup (cfg
->domain
, cfg
->method
)->ji
= jinfo
;
3672 mono_domain_unlock (cfg
->domain
);
3675 /* collect statistics */
3676 mono_perfcounters
->jit_methods
++;
3677 mono_perfcounters
->jit_bytes
+= header
->code_size
;
3678 mono_jit_stats
.allocated_code_size
+= cfg
->code_len
;
3679 code_size_ratio
= cfg
->code_len
;
3680 if (code_size_ratio
> mono_jit_stats
.biggest_method_size
&& mono_jit_stats
.enabled
) {
3681 mono_jit_stats
.biggest_method_size
= code_size_ratio
;
3682 g_free (mono_jit_stats
.biggest_method
);
3683 mono_jit_stats
.biggest_method
= g_strdup_printf ("%s::%s)", method
->klass
->name
, method
->name
);
3685 code_size_ratio
= (code_size_ratio
* 100) / mono_method_get_header (method
)->code_size
;
3686 if (code_size_ratio
> mono_jit_stats
.max_code_size_ratio
&& mono_jit_stats
.enabled
) {
3687 mono_jit_stats
.max_code_size_ratio
= code_size_ratio
;
3688 g_free (mono_jit_stats
.max_ratio_method
);
3689 mono_jit_stats
.max_ratio_method
= g_strdup_printf ("%s::%s)", method
->klass
->name
, method
->name
);
3691 mono_jit_stats
.native_code_size
+= cfg
->code_len
;
3693 if (MONO_PROBE_METHOD_COMPILE_END_ENABLED ())
3694 MONO_PROBE_METHOD_COMPILE_END (method
, TRUE
);
3695 if (cfg
->prof_options
& MONO_PROFILE_JIT_COMPILATION
)
3696 mono_profiler_method_end_jit (method
, jinfo
, MONO_PROFILE_OK
);
3704 mini_method_compile (MonoMethod
*method
, guint32 opts
, MonoDomain
*domain
, gboolean run_cctors
, gboolean compile_aot
, int parts
)
3706 g_assert_not_reached ();
3710 #endif /* DISABLE_JIT */
3713 lookup_generic_method (MonoDomain
*domain
, MonoMethod
*method
)
3715 MonoMethod
*open_method
;
3717 if (!mono_method_is_generic_sharable_impl (method
, FALSE
))
3720 open_method
= mono_method_get_declaring_generic_method (method
);
3722 return mono_domain_lookup_shared_generic (domain
, open_method
);
3726 * LOCKING: Assumes domain->jit_code_hash_lock is held.
3729 lookup_method_inner (MonoDomain
*domain
, MonoMethod
*method
)
3731 MonoJitInfo
*ji
= mono_internal_hash_table_lookup (&domain
->jit_code_hash
, method
);
3736 return lookup_generic_method (domain
, method
);
3740 lookup_method (MonoDomain
*domain
, MonoMethod
*method
)
3744 mono_loader_lock (); /*FIXME lookup_method_inner acquired it*/
3745 mono_domain_jit_code_hash_lock (domain
);
3746 info
= lookup_method_inner (domain
, method
);
3747 mono_domain_jit_code_hash_unlock (domain
);
3748 mono_loader_unlock ();
3754 mono_jit_compile_method_inner (MonoMethod
*method
, MonoDomain
*target_domain
, int opt
)
3757 gpointer code
= NULL
;
3761 #ifdef MONO_USE_AOT_COMPILER
3762 if ((opt
& MONO_OPT_AOT
) && !(mono_profiler_get_events () & MONO_PROFILE_JIT_COMPILATION
)) {
3763 MonoDomain
*domain
= mono_domain_get ();
3765 mono_class_init (method
->klass
);
3767 if ((code
= mono_aot_get_method (domain
, method
))) {
3768 vtable
= mono_class_vtable (domain
, method
->klass
);
3770 mono_runtime_class_init (vtable
);
3776 if ((method
->iflags
& METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
) ||
3777 (method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
)) {
3779 MonoMethodPInvoke
* piinfo
= (MonoMethodPInvoke
*) method
;
3781 if (!piinfo
->addr
) {
3782 if (method
->iflags
& METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
)
3783 piinfo
->addr
= mono_lookup_internal_call (method
);
3784 else if (method
->iflags
& METHOD_IMPL_ATTRIBUTE_NATIVE
)
3785 #ifdef PLATFORM_WIN32
3786 g_warning ("Method '%s' in assembly '%s' contains native code that cannot be executed by Mono in modules loaded from byte arrays. The assembly was probably created using C++/CLI.\n", mono_method_full_name (method
, TRUE
), method
->klass
->image
->name
);
3788 g_warning ("Method '%s' in assembly '%s' contains native code that cannot be executed by Mono on this platform. The assembly was probably created using C++/CLI.\n", mono_method_full_name (method
, TRUE
), method
->klass
->image
->name
);
3791 mono_lookup_pinvoke_call (method
, NULL
, NULL
);
3793 nm
= mono_marshal_get_native_wrapper (method
, check_for_pending_exc
, FALSE
);
3794 return mono_get_addr_from_ftnptr (mono_compile_method (nm
));
3796 //if (mono_debug_format != MONO_DEBUG_FORMAT_NONE)
3797 //mono_debug_add_wrapper (method, nm);
3798 } else if ((method
->iflags
& METHOD_IMPL_ATTRIBUTE_RUNTIME
)) {
3799 const char *name
= method
->name
;
3802 if (method
->klass
->parent
== mono_defaults
.multicastdelegate_class
) {
3803 if (*name
== '.' && (strcmp (name
, ".ctor") == 0)) {
3804 MonoJitICallInfo
*mi
= mono_find_jit_icall_by_name ("mono_delegate_ctor");
3807 * We need to make sure this wrapper
3808 * is compiled because it might end up
3809 * in an (M)RGCTX if generic sharing
3810 * is enabled, and would be called
3811 * indirectly. If it were a
3812 * trampoline we'd try to patch that
3813 * indirect call, which is not
3816 return mono_get_addr_from_ftnptr ((gpointer
)mono_icall_get_wrapper_full (mi
, TRUE
));
3817 } else if (*name
== 'I' && (strcmp (name
, "Invoke") == 0)) {
3818 #ifdef MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE
3819 return mono_create_delegate_trampoline (method
->klass
);
3821 nm
= mono_marshal_get_delegate_invoke (method
, NULL
);
3822 return mono_get_addr_from_ftnptr (mono_compile_method (nm
));
3824 } else if (*name
== 'B' && (strcmp (name
, "BeginInvoke") == 0)) {
3825 nm
= mono_marshal_get_delegate_begin_invoke (method
);
3826 return mono_get_addr_from_ftnptr (mono_compile_method (nm
));
3827 } else if (*name
== 'E' && (strcmp (name
, "EndInvoke") == 0)) {
3828 nm
= mono_marshal_get_delegate_end_invoke (method
);
3829 return mono_get_addr_from_ftnptr (mono_compile_method (nm
));
3836 g_error ("Attempting to JIT compile method '%s' while running with --aot-only.\n", mono_method_full_name (method
, TRUE
));
3838 cfg
= mini_method_compile (method
, opt
, target_domain
, TRUE
, FALSE
, 0);
3840 switch (cfg
->exception_type
) {
3841 case MONO_EXCEPTION_NONE
:
3843 case MONO_EXCEPTION_TYPE_LOAD
:
3844 case MONO_EXCEPTION_MISSING_FIELD
:
3845 case MONO_EXCEPTION_MISSING_METHOD
:
3846 case MONO_EXCEPTION_FILE_NOT_FOUND
:
3847 case MONO_EXCEPTION_BAD_IMAGE
: {
3848 /* Throw a type load exception if needed */
3849 MonoLoaderError
*error
= mono_loader_get_last_error ();
3853 ex
= mono_loader_error_prepare_exception (error
);
3855 if (cfg
->exception_ptr
) {
3856 ex
= mono_class_get_exception_for_failure (cfg
->exception_ptr
);
3858 if (cfg
->exception_type
== MONO_EXCEPTION_MISSING_FIELD
)
3859 ex
= mono_exception_from_name_msg (mono_defaults
.corlib
, "System", "MissingFieldException", cfg
->exception_message
);
3860 else if (cfg
->exception_type
== MONO_EXCEPTION_MISSING_METHOD
)
3861 ex
= mono_exception_from_name_msg (mono_defaults
.corlib
, "System", "MissingMethodException", cfg
->exception_message
);
3862 else if (cfg
->exception_type
== MONO_EXCEPTION_TYPE_LOAD
)
3863 ex
= mono_exception_from_name_msg (mono_defaults
.corlib
, "System", "TypeLoadException", cfg
->exception_message
);
3864 else if (cfg
->exception_type
== MONO_EXCEPTION_FILE_NOT_FOUND
)
3865 ex
= mono_exception_from_name_msg (mono_defaults
.corlib
, "System", "FileNotFoundException", cfg
->exception_message
);
3866 else if (cfg
->exception_type
== MONO_EXCEPTION_BAD_IMAGE
)
3867 ex
= mono_get_exception_bad_image_format (cfg
->exception_message
);
3869 g_assert_not_reached ();
3872 mono_destroy_compile (cfg
);
3873 mono_raise_exception (ex
);
3876 case MONO_EXCEPTION_INVALID_PROGRAM
: {
3877 MonoException
*ex
= mono_exception_from_name_msg (mono_defaults
.corlib
, "System", "InvalidProgramException", cfg
->exception_message
);
3878 mono_destroy_compile (cfg
);
3879 mono_raise_exception (ex
);
3882 case MONO_EXCEPTION_UNVERIFIABLE_IL
: {
3883 MonoException
*ex
= mono_exception_from_name_msg (mono_defaults
.corlib
, "System.Security", "VerificationException", cfg
->exception_message
);
3884 mono_destroy_compile (cfg
);
3885 mono_raise_exception (ex
);
3888 case MONO_EXCEPTION_METHOD_ACCESS
: {
3889 MonoException
*ex
= mono_exception_from_name_msg (mono_defaults
.corlib
, "System", "MethodAccessException", cfg
->exception_message
);
3890 mono_destroy_compile (cfg
);
3891 mono_raise_exception (ex
);
3894 case MONO_EXCEPTION_FIELD_ACCESS
: {
3895 MonoException
*ex
= mono_exception_from_name_msg (mono_defaults
.corlib
, "System", "FieldAccessException", cfg
->exception_message
);
3896 mono_destroy_compile (cfg
);
3897 mono_raise_exception (ex
);
3900 /* this can only be set if the security manager is active */
3901 case MONO_EXCEPTION_SECURITY_LINKDEMAND
: {
3902 MonoSecurityManager
* secman
= mono_security_manager_get_methods ();
3903 MonoObject
*exc
= NULL
;
3906 args
[0] = &cfg
->exception_data
;
3908 mono_runtime_invoke (secman
->linkdemandsecurityexception
, NULL
, args
, &exc
);
3910 mono_destroy_compile (cfg
);
3913 mono_raise_exception ((MonoException
*)exc
);
3915 case MONO_EXCEPTION_OBJECT_SUPPLIED
: {
3916 MonoException
*exp
= cfg
->exception_ptr
;
3917 MONO_GC_UNREGISTER_ROOT (cfg
->exception_ptr
);
3918 mono_destroy_compile (cfg
);
3919 mono_raise_exception (exp
);
3923 g_assert_not_reached ();
3926 mono_loader_lock (); /*FIXME lookup_method_inner requires the loader lock*/
3927 mono_domain_lock (target_domain
);
3929 /* Check if some other thread already did the job. In this case, we can
3930 discard the code this thread generated. */
3932 mono_domain_jit_code_hash_lock (target_domain
);
3934 info
= lookup_method_inner (target_domain
, method
);
3936 /* We can't use a domain specific method in another domain */
3937 if ((target_domain
== mono_domain_get ()) || info
->domain_neutral
) {
3938 code
= info
->code_start
;
3939 // printf("Discarding code for method %s\n", method->name);
3944 mono_internal_hash_table_insert (&target_domain
->jit_code_hash
, cfg
->jit_info
->method
, cfg
->jit_info
);
3945 mono_domain_jit_code_hash_unlock (target_domain
);
3946 code
= cfg
->native_code
;
3948 if (cfg
->generic_sharing_context
&& mono_method_is_generic_sharable_impl (method
, FALSE
))
3949 mono_stats
.generics_shared_methods
++;
3951 mono_domain_jit_code_hash_unlock (target_domain
);
3954 mono_destroy_compile (cfg
);
3956 if (domain_jit_info (target_domain
)->jump_target_hash
) {
3957 MonoJumpInfo patch_info
;
3959 list
= g_hash_table_lookup (domain_jit_info (target_domain
)->jump_target_hash
, method
);
3961 patch_info
.next
= NULL
;
3962 patch_info
.ip
.i
= 0;
3963 patch_info
.type
= MONO_PATCH_INFO_METHOD_JUMP
;
3964 patch_info
.data
.method
= method
;
3965 g_hash_table_remove (domain_jit_info (target_domain
)->jump_target_hash
, method
);
3967 for (tmp
= list
; tmp
; tmp
= tmp
->next
)
3968 mono_arch_patch_code (NULL
, target_domain
, tmp
->data
, &patch_info
, TRUE
);
3969 g_slist_free (list
);
3972 mono_domain_unlock (target_domain
);
3973 mono_loader_unlock ();
3975 vtable
= mono_class_vtable (target_domain
, method
->klass
);
3978 exc
= mono_class_get_exception_for_failure (method
->klass
);
3980 mono_raise_exception (exc
);
3982 mono_runtime_class_init (vtable
);
3987 mono_jit_compile_method_with_opt (MonoMethod
*method
, guint32 opt
)
3989 MonoDomain
*target_domain
, *domain
= mono_domain_get ();
3992 MonoJitICallInfo
*callinfo
= NULL
;
3995 * ICALL wrappers are handled specially, since there is only one copy of them
3996 * shared by all appdomains.
3998 if ((method
->wrapper_type
== MONO_WRAPPER_MANAGED_TO_NATIVE
) && (strstr (method
->name
, "__icall_wrapper_") == method
->name
)) {
3999 const char *icall_name
;
4001 icall_name
= method
->name
+ strlen ("__icall_wrapper_");
4002 g_assert (icall_name
);
4003 callinfo
= mono_find_jit_icall_by_name (icall_name
);
4004 g_assert (callinfo
);
4006 /* Must be domain neutral since there is only one copy */
4007 opt
|= MONO_OPT_SHARED
;
4010 if (opt
& MONO_OPT_SHARED
)
4011 target_domain
= mono_get_root_domain ();
4013 target_domain
= domain
;
4015 info
= lookup_method (target_domain
, method
);
4017 /* We can't use a domain specific method in another domain */
4018 if (! ((domain
!= target_domain
) && !info
->domain_neutral
)) {
4021 mono_jit_stats
.methods_lookups
++;
4022 vtable
= mono_class_vtable (domain
, method
->klass
);
4023 mono_runtime_class_init (vtable
);
4024 return mono_create_ftnptr (target_domain
, info
->code_start
);
4028 p
= mono_create_ftnptr (target_domain
, mono_jit_compile_method_inner (method
, target_domain
, opt
));
4032 if (!callinfo
->wrapper
) {
4033 callinfo
->wrapper
= p
;
4034 mono_register_jit_icall_wrapper (callinfo
, p
);
4035 mono_debug_add_icall_wrapper (method
, callinfo
);
4044 mono_jit_compile_method (MonoMethod
*method
)
4046 return mono_jit_compile_method_with_opt (method
, default_opt
);
4049 #ifdef MONO_ARCH_HAVE_INVALIDATE_METHOD
4051 invalidated_delegate_trampoline (char *desc
)
4053 g_error ("Unmanaged code called delegate of type %s which was already garbage collected.\n"
4054 "See http://www.go-mono.com/delegate.html for an explanation and ways to fix this.",
4060 * mono_jit_free_method:
4062 * Free all memory allocated by the JIT for METHOD.
4065 mono_jit_free_method (MonoDomain
*domain
, MonoMethod
*method
)
4067 MonoJitDynamicMethodInfo
*ji
;
4068 gboolean destroy
= TRUE
;
4070 g_assert (method
->dynamic
);
4072 mono_domain_lock (domain
);
4073 ji
= mono_dynamic_code_hash_lookup (domain
, method
);
4074 mono_domain_unlock (domain
);
4078 mono_domain_lock (domain
);
4079 g_hash_table_remove (domain_jit_info (domain
)->dynamic_code_hash
, method
);
4080 mono_internal_hash_table_remove (&domain
->jit_code_hash
, method
);
4081 g_hash_table_remove (domain_jit_info (domain
)->jump_trampoline_hash
, method
);
4082 mono_domain_unlock (domain
);
4084 #ifdef MONO_ARCH_HAVE_INVALIDATE_METHOD
4085 if (debug_options
.keep_delegates
&& method
->wrapper_type
== MONO_WRAPPER_NATIVE_TO_MANAGED
) {
4087 * Instead of freeing the code, change it to call an error routine
4088 * so people can fix their code.
4090 char *type
= mono_type_full_name (&method
->klass
->byval_arg
);
4091 char *type_and_method
= g_strdup_printf ("%s.%s", type
, method
->name
);
4094 mono_arch_invalidate_method (ji
->ji
, invalidated_delegate_trampoline
, type_and_method
);
4100 * This needs to be done before freeing code_mp, since the code address is the
4101 * key in the table, so if we free the code_mp first, another thread can grab the
4102 * same code address and replace our entry in the table.
4104 mono_jit_info_table_remove (domain
, ji
->ji
);
4107 mono_code_manager_destroy (ji
->code_mp
);
4112 mono_jit_find_compiled_method_with_jit_info (MonoDomain
*domain
, MonoMethod
*method
, MonoJitInfo
**ji
)
4114 MonoDomain
*target_domain
;
4117 if (default_opt
& MONO_OPT_SHARED
)
4118 target_domain
= mono_get_root_domain ();
4120 target_domain
= domain
;
4122 info
= lookup_method (target_domain
, method
);
4124 /* We can't use a domain specific method in another domain */
4125 if (! ((domain
!= target_domain
) && !info
->domain_neutral
)) {
4126 mono_jit_stats
.methods_lookups
++;
4129 return info
->code_start
;
4139 mono_jit_find_compiled_method (MonoDomain
*domain
, MonoMethod
*method
)
4141 return mono_jit_find_compiled_method_with_jit_info (domain
, method
, NULL
);
4145 * mono_jit_runtime_invoke:
4146 * @method: the method to invoke
4147 * @obj: this pointer
4148 * @params: array of parameter values.
4149 * @exc: used to catch exceptions objects
4152 mono_jit_runtime_invoke (MonoMethod
*method
, void *obj
, void **params
, MonoObject
**exc
)
4154 MonoMethod
*to_compile
;
4156 MonoObject
*(*runtime_invoke
) (MonoObject
*this, void **params
, MonoObject
**exc
, void* compiled_method
);
4157 void* compiled_method
;
4160 if (obj
== NULL
&& !(method
->flags
& METHOD_ATTRIBUTE_STATIC
) && !method
->string_ctor
&& (method
->wrapper_type
== 0)) {
4161 g_warning ("Ignoring invocation of an instance method on a NULL instance.\n");
4165 if (mono_method_needs_static_rgctx_invoke (method
, FALSE
))
4166 to_compile
= mono_marshal_get_static_rgctx_invoke (method
);
4168 to_compile
= method
;
4170 /* Special case parameterless ctors to speed up Activator.CreateInstance () */
4171 if (method
->flags
& (METHOD_ATTRIBUTE_SPECIAL_NAME
| METHOD_ATTRIBUTE_RT_SPECIAL_NAME
) && !strcmp (method
->name
, ".ctor") && mono_method_signature (method
)->param_count
== 0 && !method
->klass
->valuetype
) {
4172 MonoJitDomainInfo
*domain_info
= domain_jit_info (mono_domain_get ());
4174 if (!domain_info
->ctor_runtime_invoke
) {
4175 invoke
= mono_marshal_get_runtime_invoke (method
, FALSE
);
4176 domain_info
->ctor_runtime_invoke
= mono_jit_compile_method (invoke
);
4179 runtime_invoke
= domain_info
->ctor_runtime_invoke
;
4181 invoke
= mono_marshal_get_runtime_invoke (method
, FALSE
);
4182 runtime_invoke
= mono_jit_compile_method (invoke
);
4185 /* We need this here becuase mono_marshal_get_runtime_invoke can be place
4186 * the helper method in System.Object and not the target class
4188 vtable
= mono_class_vtable (mono_domain_get (), method
->klass
);
4190 mono_runtime_class_init (vtable
);
4192 if (method
->klass
->rank
&& (method
->iflags
& METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
) &&
4193 (method
->iflags
& METHOD_IMPL_ATTRIBUTE_NATIVE
)) {
4195 * Array Get/Set/Address methods. The JIT implements them using inline code
4196 * inside the runtime invoke wrappers, so no need to compile them.
4198 compiled_method
= NULL
;
4200 compiled_method
= mono_jit_compile_method (to_compile
);
4202 return runtime_invoke (obj
, params
, exc
, compiled_method
);
4206 SIG_HANDLER_SIGNATURE (mono_sigfpe_signal_handler
)
4208 MonoException
*exc
= NULL
;
4209 #ifndef MONO_ARCH_USE_SIGACTION
4214 if (mono_chain_signal (SIG_HANDLER_PARAMS
))
4217 #if defined(MONO_ARCH_HAVE_IS_INT_OVERFLOW)
4218 if (mono_arch_is_int_overflow (ctx
, info
))
4219 exc
= mono_get_exception_arithmetic ();
4221 exc
= mono_get_exception_divide_by_zero ();
4223 exc
= mono_get_exception_divide_by_zero ();
4226 mono_arch_handle_exception (ctx
, exc
, FALSE
);
4230 SIG_HANDLER_SIGNATURE (mono_sigill_signal_handler
)
4235 exc
= mono_get_exception_execution_engine ("SIGILL");
4237 mono_arch_handle_exception (ctx
, exc
, FALSE
);
4241 SIG_HANDLER_SIGNATURE (mono_sigsegv_signal_handler
)
4243 #ifndef MONO_ARCH_SIGSEGV_ON_ALTSTACK
4244 MonoException
*exc
= NULL
;
4247 MonoJitTlsData
*jit_tls
= TlsGetValue (mono_jit_tls_id
);
4251 /* The thread might no be registered with the runtime */
4252 if (!mono_domain_get () || !jit_tls
) {
4253 if (mono_chain_signal (SIG_HANDLER_PARAMS
))
4255 mono_handle_native_sigsegv (SIGSEGV
, ctx
);
4258 ji
= mono_jit_info_table_find (mono_domain_get (), mono_arch_ip_from_context (ctx
));
4260 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
4261 if (mono_handle_soft_stack_ovf (jit_tls
, ji
, ctx
, (guint8
*)info
->si_addr
))
4264 /* The hard-guard page has been hit: there is not much we can do anymore
4265 * Print a hopefully clear message and abort.
4267 if (jit_tls
->stack_size
&&
4268 ABS ((guint8
*)info
->si_addr
- ((guint8
*)jit_tls
->end_of_stack
- jit_tls
->stack_size
)) < 32768) {
4270 /* we don't do much now, but we can warn the user with a useful message */
4271 fprintf (stderr
, "Stack overflow: IP: %p, fault addr: %p\n", mono_arch_ip_from_context (ctx
), (gpointer
)info
->si_addr
);
4272 if (ji
&& ji
->method
)
4273 method
= mono_method_full_name (ji
->method
, TRUE
);
4275 method
= "Unmanaged";
4276 fprintf (stderr
, "At %s\n", method
);
4279 /* The original handler might not like that it is executed on an altstack... */
4280 if (!ji
&& mono_chain_signal (SIG_HANDLER_PARAMS
))
4283 mono_arch_handle_altstack_exception (ctx
, info
->si_addr
, FALSE
);
4288 if (mono_chain_signal (SIG_HANDLER_PARAMS
))
4291 mono_handle_native_sigsegv (SIGSEGV
, ctx
);
4294 mono_arch_handle_exception (ctx
, exc
, FALSE
);
4299 SIG_HANDLER_SIGNATURE (mono_sigint_signal_handler
)
4304 exc
= mono_get_exception_execution_engine ("Interrupted (SIGINT).");
4306 mono_arch_handle_exception (ctx
, exc
, FALSE
);
4309 /* mono_jit_create_remoting_trampoline:
4310 * @method: pointer to the method info
4312 * Creates a trampoline which calls the remoting functions. This
4313 * is used in the vtable of transparent proxies.
4315 * Returns: a pointer to the newly created code
4318 mono_jit_create_remoting_trampoline (MonoDomain
*domain
, MonoMethod
*method
, MonoRemotingTarget target
)
4321 guint8
*addr
= NULL
;
4323 if ((method
->flags
& METHOD_ATTRIBUTE_VIRTUAL
) && mono_method_signature (method
)->generic_param_count
) {
4324 return mono_arch_create_specific_trampoline (method
, MONO_TRAMPOLINE_GENERIC_VIRTUAL_REMOTING
,
4328 if ((method
->flags
& METHOD_ATTRIBUTE_ABSTRACT
) ||
4329 (mono_method_signature (method
)->hasthis
&& (method
->klass
->marshalbyref
|| method
->klass
== mono_defaults
.object_class
))) {
4330 nm
= mono_marshal_get_remoting_invoke_for_target (method
, target
);
4331 addr
= mono_compile_method (nm
);
4333 addr
= mono_compile_method (method
);
4335 return mono_get_addr_from_ftnptr (addr
);
4338 #ifdef MONO_ARCH_HAVE_IMT
4340 mini_get_imt_trampoline (void)
4342 static gpointer tramp
= NULL
;
4344 tramp
= mono_create_specific_trampoline (MONO_FAKE_IMT_METHOD
, MONO_TRAMPOLINE_JIT
, mono_get_root_domain (), NULL
);
4349 #ifdef MONO_ARCH_COMMON_VTABLE_TRAMPOLINE
4351 mini_get_vtable_trampoline (void)
4353 static gpointer tramp
= NULL
;
4355 tramp
= mono_create_specific_trampoline (MONO_FAKE_VTABLE_METHOD
, MONO_TRAMPOLINE_JIT
, mono_get_root_domain (), NULL
);
4361 mini_parse_debug_options (void)
4363 char *options
= getenv ("MONO_DEBUG");
4364 gchar
**args
, **ptr
;
4369 args
= g_strsplit (options
, ",", -1);
4371 for (ptr
= args
; ptr
&& *ptr
; ptr
++) {
4372 const char *arg
= *ptr
;
4374 if (!strcmp (arg
, "handle-sigint"))
4375 debug_options
.handle_sigint
= TRUE
;
4376 else if (!strcmp (arg
, "keep-delegates"))
4377 debug_options
.keep_delegates
= TRUE
;
4378 else if (!strcmp (arg
, "collect-pagefault-stats"))
4379 debug_options
.collect_pagefault_stats
= TRUE
;
4380 else if (!strcmp (arg
, "break-on-unverified"))
4381 debug_options
.break_on_unverified
= TRUE
;
4382 else if (!strcmp (arg
, "no-gdb-backtrace"))
4383 debug_options
.no_gdb_backtrace
= TRUE
;
4384 else if (!strcmp (arg
, "suspend-on-sigsegv"))
4385 debug_options
.suspend_on_sigsegv
= TRUE
;
4386 else if (!strcmp (arg
, "dont-free-domains"))
4387 mono_dont_free_domains
= TRUE
;
4389 fprintf (stderr
, "Invalid option for the MONO_DEBUG env variable: %s\n", arg
);
4390 fprintf (stderr
, "Available options: 'handle-sigint', 'keep-delegates', 'collect-pagefault-stats', 'break-on-unverified', 'no-gdb-backtrace', 'dont-free-domains', 'suspend-on-sigsegv'\n");
4399 mini_get_debug_options (void)
4401 return &debug_options
;
4405 mini_create_jit_domain_info (MonoDomain
*domain
)
4407 MonoJitDomainInfo
*info
= g_new0 (MonoJitDomainInfo
, 1);
4409 info
->class_init_trampoline_hash
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
4410 info
->jump_trampoline_hash
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
4411 info
->jit_trampoline_hash
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
4412 info
->delegate_trampoline_hash
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
4414 domain
->runtime_info
= info
;
4418 delete_jump_list (gpointer key
, gpointer value
, gpointer user_data
)
4420 g_slist_free (value
);
4424 dynamic_method_info_free (gpointer key
, gpointer value
, gpointer user_data
)
4426 MonoJitDynamicMethodInfo
*di
= value
;
4427 mono_code_manager_destroy (di
->code_mp
);
4432 mini_free_jit_domain_info (MonoDomain
*domain
)
4434 MonoJitDomainInfo
*info
= domain_jit_info (domain
);
4436 if (info
->jump_target_hash
) {
4437 g_hash_table_foreach (info
->jump_target_hash
, delete_jump_list
, NULL
);
4438 g_hash_table_destroy (info
->jump_target_hash
);
4440 if (info
->jump_target_got_slot_hash
) {
4441 g_hash_table_foreach (info
->jump_target_got_slot_hash
, delete_jump_list
, NULL
);
4442 g_hash_table_destroy (info
->jump_target_got_slot_hash
);
4444 if (info
->dynamic_code_hash
) {
4445 g_hash_table_foreach (info
->dynamic_code_hash
, dynamic_method_info_free
, NULL
);
4446 g_hash_table_destroy (info
->dynamic_code_hash
);
4448 if (info
->method_code_hash
)
4449 g_hash_table_destroy (info
->method_code_hash
);
4450 g_hash_table_destroy (info
->class_init_trampoline_hash
);
4451 g_hash_table_destroy (info
->jump_trampoline_hash
);
4452 g_hash_table_destroy (info
->jit_trampoline_hash
);
4453 g_hash_table_destroy (info
->delegate_trampoline_hash
);
4455 g_free (domain
->runtime_info
);
4456 domain
->runtime_info
= NULL
;
4460 mini_init (const char *filename
, const char *runtime_version
)
4464 MONO_PROBE_VES_INIT_BEGIN ();
4467 if (access ("/proc/self/maps", F_OK
) != 0) {
4468 g_print ("Mono requires /proc to be mounted.\n");
4473 /* Happens when using the embedding interface */
4474 if (!default_opt_set
)
4475 default_opt
= mono_parse_default_optimizations (NULL
);
4477 InitializeCriticalSection (&jit_mutex
);
4479 if (!global_codeman
)
4480 global_codeman
= mono_code_manager_new ();
4481 jit_icall_name_hash
= g_hash_table_new_full (g_str_hash
, g_str_equal
, g_free
, NULL
);
4483 mono_arch_cpu_init ();
4487 mono_unwind_init ();
4489 if (getenv ("MONO_XDEBUG")) {
4490 mono_xdebug_init ();
4491 /* So methods for multiple domains don't have the same address */
4492 mono_dont_free_domains
= TRUE
;
4495 mono_trampolines_init ();
4497 if (!g_thread_supported ())
4498 g_thread_init (NULL
);
4500 if (getenv ("MONO_DEBUG") != NULL
)
4501 mini_parse_debug_options ();
4503 mono_gc_base_init ();
4505 mono_jit_tls_id
= TlsAlloc ();
4506 setup_jit_tls_data ((gpointer
)-1, mono_thread_abort
);
4508 if (default_opt
& MONO_OPT_AOT
)
4511 mono_runtime_install_handlers ();
4512 mono_threads_install_cleanup (mini_thread_cleanup
);
4514 #ifdef MONO_ARCH_HAVE_NOTIFY_PENDING_EXC
4515 // This is experimental code so provide an env var to switch it off
4516 if (getenv ("MONO_DISABLE_PENDING_EXCEPTIONS")) {
4517 printf ("MONO_DISABLE_PENDING_EXCEPTIONS env var set.\n");
4519 check_for_pending_exc
= FALSE
;
4520 mono_threads_install_notify_pending_exc (mono_arch_notify_pending_exc
);
4524 #define JIT_TRAMPOLINES_WORK
4525 #ifdef JIT_TRAMPOLINES_WORK
4526 mono_install_compile_method (mono_jit_compile_method
);
4527 mono_install_free_method (mono_jit_free_method
);
4528 mono_install_trampoline (mono_create_jit_trampoline
);
4529 mono_install_jump_trampoline (mono_create_jump_trampoline
);
4530 mono_install_remoting_trampoline (mono_jit_create_remoting_trampoline
);
4531 mono_install_delegate_trampoline (mono_create_delegate_trampoline
);
4532 mono_install_create_domain_hook (mini_create_jit_domain_info
);
4533 mono_install_free_domain_hook (mini_free_jit_domain_info
);
4535 #define JIT_INVOKE_WORKS
4536 #ifdef JIT_INVOKE_WORKS
4537 mono_install_runtime_invoke (mono_jit_runtime_invoke
);
4539 mono_install_stack_walk (mono_jit_walk_stack
);
4540 mono_install_get_cached_class_info (mono_aot_get_cached_class_info
);
4541 mono_install_get_class_from_name (mono_aot_get_class_from_name
);
4542 mono_install_jit_info_find_in_aot (mono_aot_find_jit_info
);
4544 if (runtime_version
)
4545 domain
= mono_init_version (filename
, runtime_version
);
4547 domain
= mono_init_from_assembly (filename
, filename
);
4549 if (mono_aot_only
) {
4550 /* The IMT tables are very dynamic thus they are hard to AOT */
4551 mono_use_imt
= FALSE
;
4552 /* This helps catch code allocation requests */
4553 mono_code_manager_set_read_only (domain
->code_mp
);
4556 #ifdef MONO_ARCH_HAVE_IMT
4558 mono_install_imt_thunk_builder (mono_arch_build_imt_thunk
);
4559 mono_install_imt_trampoline (mini_get_imt_trampoline ());
4560 #if MONO_ARCH_COMMON_VTABLE_TRAMPOLINE
4561 mono_install_vtable_trampoline (mini_get_vtable_trampoline ());
4566 /* This must come after mono_init () in the aot-only case */
4567 mono_exceptions_init ();
4568 mono_install_handler (mono_get_throw_exception ());
4572 mono_add_internal_call ("System.Diagnostics.StackFrame::get_frame_info",
4573 ves_icall_get_frame_info
);
4574 mono_add_internal_call ("System.Diagnostics.StackTrace::get_trace",
4575 ves_icall_get_trace
);
4576 mono_add_internal_call ("System.Exception::get_trace",
4577 ves_icall_System_Exception_get_trace
);
4578 mono_add_internal_call ("System.Security.SecurityFrame::_GetSecurityFrame",
4579 ves_icall_System_Security_SecurityFrame_GetSecurityFrame
);
4580 mono_add_internal_call ("System.Security.SecurityFrame::_GetSecurityStack",
4581 ves_icall_System_Security_SecurityFrame_GetSecurityStack
);
4582 mono_add_internal_call ("Mono.Runtime::mono_runtime_install_handlers",
4583 mono_runtime_install_handlers
);
4586 create_helper_signature ();
4588 #define JIT_CALLS_WORK
4589 #ifdef JIT_CALLS_WORK
4590 /* Needs to be called here since register_jit_icall depends on it */
4591 mono_marshal_init ();
4593 mono_arch_register_lowlevel_calls ();
4594 register_icall (mono_profiler_method_enter
, "mono_profiler_method_enter", NULL
, TRUE
);
4595 register_icall (mono_profiler_method_leave
, "mono_profiler_method_leave", NULL
, TRUE
);
4596 register_icall (mono_trace_enter_method
, "mono_trace_enter_method", NULL
, TRUE
);
4597 register_icall (mono_trace_leave_method
, "mono_trace_leave_method", NULL
, TRUE
);
4598 register_icall (mono_get_lmf_addr
, "mono_get_lmf_addr", "ptr", TRUE
);
4599 register_icall (mono_jit_thread_attach
, "mono_jit_thread_attach", "void", TRUE
);
4600 register_icall (mono_domain_get
, "mono_domain_get", "ptr", TRUE
);
4602 register_icall (mono_get_throw_exception (), "mono_arch_throw_exception", "void object", TRUE
);
4603 register_icall (mono_get_rethrow_exception (), "mono_arch_rethrow_exception", "void object", TRUE
);
4604 register_icall (mono_get_throw_exception_by_name (), "mono_arch_throw_exception_by_name", "void ptr", TRUE
);
4605 #if MONO_ARCH_HAVE_THROW_CORLIB_EXCEPTION
4606 register_icall (mono_get_throw_corlib_exception (), "mono_arch_throw_corlib_exception",
4609 register_icall (mono_thread_get_undeniable_exception
, "mono_thread_get_undeniable_exception", "object", FALSE
);
4610 register_icall (mono_thread_interruption_checkpoint
, "mono_thread_interruption_checkpoint", "void", FALSE
);
4611 register_icall (mono_thread_force_interruption_checkpoint
, "mono_thread_force_interruption_checkpoint", "void", FALSE
);
4612 register_icall (mono_load_remote_field_new
, "mono_load_remote_field_new", "object object ptr ptr", FALSE
);
4613 register_icall (mono_store_remote_field_new
, "mono_store_remote_field_new", "void object ptr ptr object", FALSE
);
4616 * NOTE, NOTE, NOTE, NOTE:
4617 * when adding emulation for some opcodes, remember to also add a dummy
4618 * rule to the burg files, because we need the arity information to be correct.
4620 #ifndef MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS
4621 mono_register_opcode_emulation (OP_LMUL
, "__emul_lmul", "long long long", mono_llmult
, TRUE
);
4622 mono_register_opcode_emulation (OP_LDIV
, "__emul_ldiv", "long long long", mono_lldiv
, FALSE
);
4623 mono_register_opcode_emulation (OP_LDIV_UN
, "__emul_ldiv_un", "long long long", mono_lldiv_un
, FALSE
);
4624 mono_register_opcode_emulation (OP_LREM
, "__emul_lrem", "long long long", mono_llrem
, FALSE
);
4625 mono_register_opcode_emulation (OP_LREM_UN
, "__emul_lrem_un", "long long long", mono_llrem_un
, FALSE
);
4626 mono_register_opcode_emulation (OP_LMUL_OVF_UN
, "__emul_lmul_ovf_un", "long long long", mono_llmult_ovf_un
, FALSE
);
4627 mono_register_opcode_emulation (OP_LMUL_OVF
, "__emul_lmul_ovf", "long long long", mono_llmult_ovf
, FALSE
);
4630 #ifndef MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
4631 mono_register_opcode_emulation (OP_LSHL
, "__emul_lshl", "long long int32", mono_lshl
, TRUE
);
4632 mono_register_opcode_emulation (OP_LSHR
, "__emul_lshr", "long long int32", mono_lshr
, TRUE
);
4633 mono_register_opcode_emulation (OP_LSHR_UN
, "__emul_lshr_un", "long long int32", mono_lshr_un
, TRUE
);
4636 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
4637 mono_register_opcode_emulation (CEE_DIV
, "__emul_idiv", "int32 int32 int32", mono_idiv
, FALSE
);
4638 mono_register_opcode_emulation (CEE_DIV_UN
, "__emul_idiv_un", "int32 int32 int32", mono_idiv_un
, FALSE
);
4639 mono_register_opcode_emulation (CEE_REM
, "__emul_irem", "int32 int32 int32", mono_irem
, FALSE
);
4640 mono_register_opcode_emulation (CEE_REM_UN
, "__emul_irem_un", "int32 int32 int32", mono_irem_un
, FALSE
);
4641 mono_register_opcode_emulation (OP_IDIV
, "__emul_op_idiv", "int32 int32 int32", mono_idiv
, FALSE
);
4642 mono_register_opcode_emulation (OP_IDIV_UN
, "__emul_op_idiv_un", "int32 int32 int32", mono_idiv_un
, FALSE
);
4643 mono_register_opcode_emulation (OP_IREM
, "__emul_op_irem", "int32 int32 int32", mono_irem
, FALSE
);
4644 mono_register_opcode_emulation (OP_IREM_UN
, "__emul_op_irem_un", "int32 int32 int32", mono_irem_un
, FALSE
);
4647 #ifdef MONO_ARCH_EMULATE_MUL_DIV
4648 mono_register_opcode_emulation (CEE_MUL
, "__emul_imul", "int32 int32 int32", mono_imul
, TRUE
);
4649 mono_register_opcode_emulation (OP_IMUL
, "__emul_op_imul", "int32 int32 int32", mono_imul
, TRUE
);
4652 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_MUL_OVF)
4653 mono_register_opcode_emulation (CEE_MUL_OVF
, "__emul_imul_ovf", "int32 int32 int32", mono_imul_ovf
, FALSE
);
4654 mono_register_opcode_emulation (CEE_MUL_OVF_UN
, "__emul_imul_ovf_un", "int32 int32 int32", mono_imul_ovf_un
, FALSE
);
4655 mono_register_opcode_emulation (OP_IMUL_OVF
, "__emul_op_imul_ovf", "int32 int32 int32", mono_imul_ovf
, FALSE
);
4656 mono_register_opcode_emulation (OP_IMUL_OVF_UN
, "__emul_op_imul_ovf_un", "int32 int32 int32", mono_imul_ovf_un
, FALSE
);
4659 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_SOFT_FLOAT)
4660 mono_register_opcode_emulation (OP_FDIV
, "__emul_fdiv", "double double double", mono_fdiv
, FALSE
);
4663 mono_register_opcode_emulation (OP_FCONV_TO_U8
, "__emul_fconv_to_u8", "ulong double", mono_fconv_u8
, FALSE
);
4664 mono_register_opcode_emulation (OP_FCONV_TO_U4
, "__emul_fconv_to_u4", "uint32 double", mono_fconv_u4
, FALSE
);
4665 mono_register_opcode_emulation (OP_FCONV_TO_OVF_I8
, "__emul_fconv_to_ovf_i8", "long double", mono_fconv_ovf_i8
, FALSE
);
4666 mono_register_opcode_emulation (OP_FCONV_TO_OVF_U8
, "__emul_fconv_to_ovf_u8", "ulong double", mono_fconv_ovf_u8
, FALSE
);
4668 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
4669 mono_register_opcode_emulation (OP_FCONV_TO_I8
, "__emul_fconv_to_i8", "long double", mono_fconv_i8
, FALSE
);
4671 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
4672 mono_register_opcode_emulation (CEE_CONV_R_UN
, "__emul_conv_r_un", "double int32", mono_conv_to_r8_un
, FALSE
);
4673 mono_register_opcode_emulation (OP_ICONV_TO_R_UN
, "__emul_iconv_to_r_un", "double int32", mono_conv_to_r8_un
, FALSE
);
4675 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
4676 mono_register_opcode_emulation (OP_LCONV_TO_R8
, "__emul_lconv_to_r8", "double long", mono_lconv_to_r8
, FALSE
);
4678 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
4679 mono_register_opcode_emulation (OP_LCONV_TO_R4
, "__emul_lconv_to_r4", "float long", mono_lconv_to_r4
, FALSE
);
4681 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
4682 mono_register_opcode_emulation (OP_LCONV_TO_R_UN
, "__emul_lconv_to_r8_un", "double long", mono_lconv_to_r8_un
, FALSE
);
4684 #ifdef MONO_ARCH_EMULATE_FREM
4685 mono_register_opcode_emulation (OP_FREM
, "__emul_frem", "double double double", fmod
, FALSE
);
4688 #ifdef MONO_ARCH_SOFT_FLOAT
4689 mono_register_opcode_emulation (OP_FSUB
, "__emul_fsub", "double double double", mono_fsub
, FALSE
);
4690 mono_register_opcode_emulation (OP_FADD
, "__emul_fadd", "double double double", mono_fadd
, FALSE
);
4691 mono_register_opcode_emulation (OP_FMUL
, "__emul_fmul", "double double double", mono_fmul
, FALSE
);
4692 mono_register_opcode_emulation (OP_FNEG
, "__emul_fneg", "double double", mono_fneg
, FALSE
);
4693 mono_register_opcode_emulation (CEE_CONV_R8
, "__emul_conv_r8", "double int32", mono_conv_to_r8
, FALSE
);
4694 mono_register_opcode_emulation (OP_ICONV_TO_R8
, "__emul_iconv_to_r8", "double int32", mono_conv_to_r8
, FALSE
);
4695 mono_register_opcode_emulation (CEE_CONV_R4
, "__emul_conv_r4", "double int32", mono_conv_to_r4
, FALSE
);
4696 mono_register_opcode_emulation (OP_ICONV_TO_R4
, "__emul_iconv_to_r4", "double int32", mono_conv_to_r4
, FALSE
);
4697 mono_register_opcode_emulation (OP_FCONV_TO_R4
, "__emul_fconv_to_r4", "double double", mono_fconv_r4
, FALSE
);
4698 mono_register_opcode_emulation (OP_FCONV_TO_I1
, "__emul_fconv_to_i1", "int8 double", mono_fconv_i1
, FALSE
);
4699 mono_register_opcode_emulation (OP_FCONV_TO_I2
, "__emul_fconv_to_i2", "int16 double", mono_fconv_i2
, FALSE
);
4700 mono_register_opcode_emulation (OP_FCONV_TO_I4
, "__emul_fconv_to_i4", "int32 double", mono_fconv_i4
, FALSE
);
4701 mono_register_opcode_emulation (OP_FCONV_TO_U1
, "__emul_fconv_to_u1", "uint8 double", mono_fconv_u1
, FALSE
);
4702 mono_register_opcode_emulation (OP_FCONV_TO_U2
, "__emul_fconv_to_u2", "uint16 double", mono_fconv_u2
, FALSE
);
4703 #if SIZEOF_VOID_P == 4
4704 mono_register_opcode_emulation (OP_FCONV_TO_I
, "__emul_fconv_to_i", "int32 double", mono_fconv_i4
, FALSE
);
4707 mono_register_opcode_emulation (OP_FBEQ
, "__emul_fcmp_eq", "uint32 double double", mono_fcmp_eq
, FALSE
);
4708 mono_register_opcode_emulation (OP_FBLT
, "__emul_fcmp_lt", "uint32 double double", mono_fcmp_lt
, FALSE
);
4709 mono_register_opcode_emulation (OP_FBGT
, "__emul_fcmp_gt", "uint32 double double", mono_fcmp_gt
, FALSE
);
4710 mono_register_opcode_emulation (OP_FBLE
, "__emul_fcmp_le", "uint32 double double", mono_fcmp_le
, FALSE
);
4711 mono_register_opcode_emulation (OP_FBGE
, "__emul_fcmp_ge", "uint32 double double", mono_fcmp_ge
, FALSE
);
4712 mono_register_opcode_emulation (OP_FBNE_UN
, "__emul_fcmp_ne_un", "uint32 double double", mono_fcmp_ne_un
, FALSE
);
4713 mono_register_opcode_emulation (OP_FBLT_UN
, "__emul_fcmp_lt_un", "uint32 double double", mono_fcmp_lt_un
, FALSE
);
4714 mono_register_opcode_emulation (OP_FBGT_UN
, "__emul_fcmp_gt_un", "uint32 double double", mono_fcmp_gt_un
, FALSE
);
4715 mono_register_opcode_emulation (OP_FBLE_UN
, "__emul_fcmp_le_un", "uint32 double double", mono_fcmp_le_un
, FALSE
);
4716 mono_register_opcode_emulation (OP_FBGE_UN
, "__emul_fcmp_ge_un", "uint32 double double", mono_fcmp_ge_un
, FALSE
);
4718 mono_register_opcode_emulation (OP_FCEQ
, "__emul_fcmp_ceq", "uint32 double double", mono_fceq
, FALSE
);
4719 mono_register_opcode_emulation (OP_FCGT
, "__emul_fcmp_cgt", "uint32 double double", mono_fcgt
, FALSE
);
4720 mono_register_opcode_emulation (OP_FCGT_UN
, "__emul_fcmp_cgt_un", "uint32 double double", mono_fcgt_un
, FALSE
);
4721 mono_register_opcode_emulation (OP_FCLT
, "__emul_fcmp_clt", "uint32 double double", mono_fclt
, FALSE
);
4722 mono_register_opcode_emulation (OP_FCLT_UN
, "__emul_fcmp_clt_un", "uint32 double double", mono_fclt_un
, FALSE
);
4724 register_icall (mono_fload_r4
, "mono_fload_r4", "double ptr", FALSE
);
4725 register_icall (mono_fstore_r4
, "mono_fstore_r4", "void double ptr", FALSE
);
4726 register_icall (mono_fload_r4_arg
, "mono_fload_r4_arg", "uint32 double", FALSE
);
4727 register_icall (mono_isfinite
, "mono_isfinite", "uint32 double", FALSE
);
4730 #if SIZEOF_REGISTER == 4
4731 mono_register_opcode_emulation (OP_FCONV_TO_U
, "__emul_fconv_to_u", "uint32 double", mono_fconv_u4
, TRUE
);
4734 /* other jit icalls */
4735 register_icall (mono_delegate_ctor
, "mono_delegate_ctor", "void object object ptr", FALSE
);
4736 register_icall (mono_class_static_field_address
, "mono_class_static_field_address",
4737 "ptr ptr ptr", FALSE
);
4738 register_icall (mono_ldtoken_wrapper
, "mono_ldtoken_wrapper", "ptr ptr ptr ptr", FALSE
);
4739 register_icall (mono_ldtoken_wrapper_generic_shared
, "mono_ldtoken_wrapper_generic_shared",
4740 "ptr ptr ptr ptr", FALSE
);
4741 register_icall (mono_get_special_static_data
, "mono_get_special_static_data", "ptr int", FALSE
);
4742 register_icall (mono_ldstr
, "mono_ldstr", "object ptr ptr int32", FALSE
);
4743 register_icall (mono_helper_stelem_ref_check
, "helper_stelem_ref_check", "void object object", FALSE
);
4744 register_icall (mono_object_new
, "mono_object_new", "object ptr ptr", FALSE
);
4745 register_icall (mono_object_new_specific
, "mono_object_new_specific", "object ptr", FALSE
);
4746 register_icall (mono_array_new
, "mono_array_new", "object ptr ptr int32", FALSE
);
4747 register_icall (mono_array_new_specific
, "mono_array_new_specific", "object ptr int32", FALSE
);
4748 register_icall (mono_runtime_class_init
, "mono_runtime_class_init", "void ptr", FALSE
);
4749 register_icall (mono_ldftn
, "mono_ldftn", "ptr ptr", FALSE
);
4750 register_icall (mono_ldvirtfn
, "mono_ldvirtfn", "ptr object ptr", FALSE
);
4751 register_icall (mono_ldvirtfn_gshared
, "mono_ldvirtfn_gshared", "ptr object ptr", FALSE
);
4752 register_icall (mono_helper_compile_generic_method
, "compile_generic_method", "ptr object ptr ptr", FALSE
);
4753 register_icall (mono_helper_ldstr
, "helper_ldstr", "object ptr int", FALSE
);
4754 register_icall (mono_helper_ldstr_mscorlib
, "helper_ldstr_mscorlib", "object int", FALSE
);
4755 register_icall (mono_helper_newobj_mscorlib
, "helper_newobj_mscorlib", "object int", FALSE
);
4756 register_icall (mono_value_copy
, "mono_value_copy", "void ptr ptr ptr", FALSE
);
4757 register_icall (mono_object_castclass
, "mono_object_castclass", "object object ptr", FALSE
);
4758 register_icall (mono_break
, "mono_break", NULL
, TRUE
);
4759 register_icall (mono_create_corlib_exception_0
, "mono_create_corlib_exception_0", "object int", TRUE
);
4760 register_icall (mono_create_corlib_exception_1
, "mono_create_corlib_exception_1", "object int object", TRUE
);
4761 register_icall (mono_create_corlib_exception_2
, "mono_create_corlib_exception_2", "object int object object", TRUE
);
4762 register_icall (mono_array_new_1
, "mono_array_new_1", "object ptr int", FALSE
);
4763 register_icall (mono_array_new_2
, "mono_array_new_2", "object ptr int int", FALSE
);
4766 mono_generic_sharing_init ();
4768 #ifdef MONO_ARCH_SIMD_INTRINSICS
4769 mono_simd_intrinsics_init ();
4772 if (mono_compile_aot
)
4774 * Avoid running managed code when AOT compiling, since the platform
4775 * might only support aot-only execution.
4777 mono_runtime_set_no_exec (TRUE
);
4779 #define JIT_RUNTIME_WORKS
4780 #ifdef JIT_RUNTIME_WORKS
4781 mono_install_runtime_cleanup ((MonoDomainFunc
)mini_cleanup
);
4782 mono_runtime_init (domain
, mono_thread_start_cb
, mono_thread_attach_cb
);
4783 mono_thread_attach (domain
);
4786 mono_profiler_runtime_initialized ();
4788 MONO_PROBE_VES_INIT_END ();
4793 MonoJitStats mono_jit_stats
= {0};
4796 print_jit_stats (void)
4798 if (mono_jit_stats
.enabled
) {
4799 g_print ("Mono Jit statistics\n");
4800 g_print ("Compiled methods: %ld\n", mono_jit_stats
.methods_compiled
);
4801 g_print ("Methods from AOT: %ld\n", mono_jit_stats
.methods_aot
);
4802 g_print ("Methods cache lookup: %ld\n", mono_jit_stats
.methods_lookups
);
4803 g_print ("Method trampolines: %ld\n", mono_jit_stats
.method_trampolines
);
4804 g_print ("Basic blocks: %ld\n", mono_jit_stats
.basic_blocks
);
4805 g_print ("Max basic blocks: %ld\n", mono_jit_stats
.max_basic_blocks
);
4806 g_print ("Allocated vars: %ld\n", mono_jit_stats
.allocate_var
);
4807 g_print ("Compiled CIL code size: %ld\n", mono_jit_stats
.cil_code_size
);
4808 g_print ("Native code size: %ld\n", mono_jit_stats
.native_code_size
);
4809 g_print ("Max code size ratio: %.2f (%s)\n", mono_jit_stats
.max_code_size_ratio
/100.0,
4810 mono_jit_stats
.max_ratio_method
);
4811 g_print ("Biggest method: %ld (%s)\n", mono_jit_stats
.biggest_method_size
,
4812 mono_jit_stats
.biggest_method
);
4813 g_print ("Code reallocs: %ld\n", mono_jit_stats
.code_reallocs
);
4814 g_print ("Allocated code size: %ld\n", mono_jit_stats
.allocated_code_size
);
4815 g_print ("Inlineable methods: %ld\n", mono_jit_stats
.inlineable_methods
);
4816 g_print ("Inlined methods: %ld\n", mono_jit_stats
.inlined_methods
);
4817 g_print ("Regvars: %ld\n", mono_jit_stats
.regvars
);
4818 g_print ("Locals stack size: %ld\n", mono_jit_stats
.locals_stack_size
);
4820 g_print ("\nCreated object count: %ld\n", mono_stats
.new_object_count
);
4821 g_print ("Delegates created: %ld\n", mono_stats
.delegate_creations
);
4822 g_print ("Initialized classes: %ld\n", mono_stats
.initialized_class_count
);
4823 g_print ("Used classes: %ld\n", mono_stats
.used_class_count
);
4824 g_print ("Generic vtables: %ld\n", mono_stats
.generic_vtable_count
);
4825 g_print ("Methods: %ld\n", mono_stats
.method_count
);
4826 g_print ("Static data size: %ld\n", mono_stats
.class_static_data_size
);
4827 g_print ("VTable data size: %ld\n", mono_stats
.class_vtable_size
);
4828 g_print ("Mscorlib mempool size: %d\n", mono_mempool_get_allocated (mono_defaults
.corlib
->mempool
));
4830 g_print ("\nInitialized classes: %ld\n", mono_stats
.generic_class_count
);
4831 g_print ("Inflated types: %ld\n", mono_stats
.inflated_type_count
);
4832 g_print ("Generics virtual invokes: %ld\n", mono_jit_stats
.generic_virtual_invocations
);
4834 g_print ("Sharable generic methods: %ld\n", mono_stats
.generics_sharable_methods
);
4835 g_print ("Unsharable generic methods: %ld\n", mono_stats
.generics_unsharable_methods
);
4836 g_print ("Shared generic methods: %ld\n", mono_stats
.generics_shared_methods
);
4838 g_print ("Dynamic code allocs: %ld\n", mono_stats
.dynamic_code_alloc_count
);
4839 g_print ("Dynamic code bytes: %ld\n", mono_stats
.dynamic_code_bytes_count
);
4840 g_print ("Dynamic code frees: %ld\n", mono_stats
.dynamic_code_frees_count
);
4842 g_print ("IMT tables size: %ld\n", mono_stats
.imt_tables_size
);
4843 g_print ("IMT number of tables: %ld\n", mono_stats
.imt_number_of_tables
);
4844 g_print ("IMT number of methods: %ld\n", mono_stats
.imt_number_of_methods
);
4845 g_print ("IMT used slots: %ld\n", mono_stats
.imt_used_slots
);
4846 g_print ("IMT colliding slots: %ld\n", mono_stats
.imt_slots_with_collisions
);
4847 g_print ("IMT max collisions: %ld\n", mono_stats
.imt_max_collisions_in_slot
);
4848 g_print ("IMT methods at max col: %ld\n", mono_stats
.imt_method_count_when_max_collisions
);
4849 g_print ("IMT thunks size: %ld\n", mono_stats
.imt_thunks_size
);
4851 g_print ("JIT info table inserts: %ld\n", mono_stats
.jit_info_table_insert_count
);
4852 g_print ("JIT info table removes: %ld\n", mono_stats
.jit_info_table_remove_count
);
4853 g_print ("JIT info table lookups: %ld\n", mono_stats
.jit_info_table_lookup_count
);
4855 g_print ("Hazardous pointers: %ld\n", mono_stats
.hazardous_pointer_count
);
4857 g_print ("Minor GC collections: %ld\n", mono_stats
.minor_gc_count
);
4859 g_print ("Major GC collections: %ld\n", mono_stats
.major_gc_count
);
4861 g_print ("Minor GC time in msecs: %lf\n", (double)mono_stats
.minor_gc_time_usecs
/ 1000.0);
4863 g_print ("Major GC time in msecs: %lf\n", (double)mono_stats
.major_gc_time_usecs
/ 1000.0);
4864 if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS
) {
4865 g_print ("\nDecl security check : %ld\n", mono_jit_stats
.cas_declsec_check
);
4866 g_print ("LinkDemand (user) : %ld\n", mono_jit_stats
.cas_linkdemand
);
4867 g_print ("LinkDemand (icall) : %ld\n", mono_jit_stats
.cas_linkdemand_icall
);
4868 g_print ("LinkDemand (pinvoke) : %ld\n", mono_jit_stats
.cas_linkdemand_pinvoke
);
4869 g_print ("LinkDemand (aptc) : %ld\n", mono_jit_stats
.cas_linkdemand_aptc
);
4870 g_print ("Demand (code gen) : %ld\n", mono_jit_stats
.cas_demand_generation
);
4873 g_free (mono_jit_stats
.max_ratio_method
);
4874 mono_jit_stats
.max_ratio_method
= NULL
;
4875 g_free (mono_jit_stats
.biggest_method
);
4876 mono_jit_stats
.biggest_method
= NULL
;
4881 mini_cleanup (MonoDomain
*domain
)
4883 mono_runtime_shutdown_stat_profiler ();
4886 cominterop_release_all_rcws ();
4890 * mono_runtime_cleanup() and mono_domain_finalize () need to
4891 * be called early since they need the execution engine still
4892 * fully working (mono_domain_finalize may invoke managed finalizers
4893 * and mono_runtime_cleanup will wait for other threads to finish).
4895 mono_domain_finalize (domain
, 2000);
4897 /* This accesses metadata so needs to be called before runtime shutdown */
4900 mono_runtime_cleanup (domain
);
4902 mono_profiler_shutdown ();
4904 mono_icall_cleanup ();
4906 mono_runtime_cleanup_handlers ();
4908 mono_domain_free (domain
, TRUE
);
4910 mono_debugger_cleanup ();
4912 mono_trampolines_cleanup ();
4914 mono_unwind_cleanup ();
4916 if (!mono_dont_free_global_codeman
)
4917 mono_code_manager_destroy (global_codeman
);
4918 g_hash_table_destroy (jit_icall_name_hash
);
4919 g_free (emul_opcode_map
);
4921 mono_arch_cleanup ();
4925 mono_trace_cleanup ();
4927 mono_counters_dump (-1, stdout
);
4929 if (mono_inject_async_exc_method
)
4930 mono_method_desc_free (mono_inject_async_exc_method
);
4932 TlsFree(mono_jit_tls_id
);
4934 DeleteCriticalSection (&jit_mutex
);
4936 DeleteCriticalSection (&mono_delegate_section
);
4940 mono_set_defaults (int verbose_level
, guint32 opts
)
4942 mini_verbose
= verbose_level
;
4944 default_opt_set
= TRUE
;
4948 * mono_get_runtime_build_info:
4950 * Return the runtime version + build date in string format.
4951 * The returned string is owned by the caller.
4954 mono_get_runtime_build_info (void)
4956 if (mono_build_date
)
4957 return g_strdup_printf ("%s %s", FULL_VERSION
, mono_build_date
);
4959 return g_strdup_printf ("%s", FULL_VERSION
);
4963 mono_precompile_assembly (MonoAssembly
*ass
, void *user_data
)
4965 GHashTable
*assemblies
= (GHashTable
*)user_data
;
4966 MonoImage
*image
= mono_assembly_get_image (ass
);
4967 MonoMethod
*method
, *invoke
;
4970 if (g_hash_table_lookup (assemblies
, ass
))
4973 g_hash_table_insert (assemblies
, ass
, ass
);
4975 if (mini_verbose
> 0)
4976 printf ("PRECOMPILE: %s.\n", mono_image_get_filename (image
));
4978 for (i
= 0; i
< mono_image_get_table_rows (image
, MONO_TABLE_METHOD
); ++i
) {
4979 method
= mono_get_method (image
, MONO_TOKEN_METHOD_DEF
| (i
+ 1), NULL
);
4980 if (method
->flags
& METHOD_ATTRIBUTE_ABSTRACT
)
4984 if (mini_verbose
> 1) {
4985 char * desc
= mono_method_full_name (method
, TRUE
);
4986 g_print ("Compiling %d %s\n", count
, desc
);
4989 mono_compile_method (method
);
4990 if (strcmp (method
->name
, "Finalize") == 0) {
4991 invoke
= mono_marshal_get_runtime_invoke (method
, FALSE
);
4992 mono_compile_method (invoke
);
4994 if (method
->klass
->marshalbyref
&& mono_method_signature (method
)->hasthis
) {
4995 invoke
= mono_marshal_get_remoting_invoke_with_check (method
);
4996 mono_compile_method (invoke
);
5000 /* Load and precompile referenced assemblies as well */
5001 for (i
= 0; i
< mono_image_get_table_rows (image
, MONO_TABLE_ASSEMBLYREF
); ++i
) {
5002 mono_assembly_load_reference (image
, i
);
5003 if (image
->references
[i
])
5004 mono_precompile_assembly (image
->references
[i
], assemblies
);
5008 void mono_precompile_assemblies ()
5010 GHashTable
*assemblies
= g_hash_table_new (NULL
, NULL
);
5012 mono_assembly_foreach ((GFunc
)mono_precompile_assembly
, assemblies
);
5014 g_hash_table_destroy (assemblies
);