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.
17 #ifdef PLATFORM_MACOSX
18 #include <mach/mach.h>
19 #include <mach/mach_error.h>
20 #include <mach/exception.h>
21 #include <mach/task.h>
25 #ifdef HAVE_VALGRIND_MEMCHECK_H
26 #include <valgrind/memcheck.h>
29 #include <mono/metadata/assembly.h>
30 #include <mono/metadata/loader.h>
31 #include <mono/metadata/cil-coff.h>
32 #include <mono/metadata/tabledefs.h>
33 #include <mono/metadata/class.h>
34 #include <mono/metadata/object.h>
35 #include <mono/metadata/exception.h>
36 #include <mono/metadata/opcodes.h>
37 #include <mono/metadata/mono-endian.h>
38 #include <mono/metadata/tokentype.h>
39 #include <mono/metadata/tabledefs.h>
40 #include <mono/metadata/threads.h>
41 #include <mono/metadata/marshal.h>
42 #include <mono/metadata/socket-io.h>
43 #include <mono/metadata/appdomain.h>
44 #include <mono/metadata/debug-helpers.h>
45 #include <mono/io-layer/io-layer.h>
46 #include "mono/metadata/profiler.h"
47 #include <mono/metadata/profiler-private.h>
48 #include <mono/metadata/mono-config.h>
49 #include <mono/metadata/environment.h>
50 #include <mono/metadata/mono-debug.h>
51 #include <mono/metadata/monitor.h>
52 #include <mono/metadata/security-manager.h>
53 #include <mono/metadata/threads-types.h>
54 #include <mono/metadata/rawbuffer.h>
55 #include <mono/utils/mono-math.h>
56 #include <mono/utils/mono-compiler.h>
57 #include <mono/utils/mono-counters.h>
58 #include <mono/utils/mono-logger.h>
59 #include <mono/os/gc_wrapper.h>
67 #include "jit-icalls.h"
71 #define BRANCH_COST 100
72 #define INLINE_LENGTH_LIMIT 20
73 #define INLINE_FAILURE do {\
74 if ((cfg->method != method) && (method->wrapper_type == MONO_WRAPPER_NONE))\
79 * this is used to determine when some branch optimizations are possible: we exclude FP compares
80 * because they have weird semantics with NaNs.
82 #define MONO_IS_COND_BRANCH_OP(ins) (((ins)->opcode >= CEE_BEQ && (ins)->opcode <= CEE_BLT_UN) || ((ins)->opcode >= OP_LBEQ && (ins)->opcode <= OP_LBLT_UN) || ((ins)->opcode >= OP_FBEQ && (ins)->opcode <= OP_FBLT_UN) || ((ins)->opcode >= OP_IBEQ && (ins)->opcode <= OP_IBLT_UN))
83 #define MONO_IS_COND_BRANCH_NOFP(ins) (MONO_IS_COND_BRANCH_OP(ins) && (ins)->inst_left->inst_left->type != STACK_R8)
85 #define MONO_IS_BRANCH_OP(ins) (MONO_IS_COND_BRANCH_OP(ins) || ((ins)->opcode == CEE_BR) || ((ins)->opcode == OP_BR_REG) || ((ins)->opcode == CEE_SWITCH))
87 #define MONO_CHECK_THIS(ins) (mono_method_signature (cfg->method)->hasthis && (ins)->ssa_op == MONO_SSA_LOAD && (ins)->inst_left->inst_c0 == 0)
89 static void setup_stat_profiler (void);
90 gboolean
mono_arch_print_tree(MonoInst
*tree
, int arity
);
91 static gpointer
mono_jit_compile_method_with_opt (MonoMethod
*method
, guint32 opt
);
92 static gpointer
mono_jit_compile_method (MonoMethod
*method
);
93 static gpointer
mono_jit_find_compiled_method (MonoDomain
*domain
, MonoMethod
*method
);
94 static gpointer
mono_create_jit_trampoline_in_domain (MonoDomain
*domain
, MonoMethod
*method
);
96 static void handle_stobj (MonoCompile
*cfg
, MonoBasicBlock
*bblock
, MonoInst
*dest
, MonoInst
*src
,
97 const unsigned char *ip
, MonoClass
*klass
, gboolean to_end
, gboolean native
, gboolean write_barrier
);
99 static void dec_foreach (MonoInst
*tree
, MonoCompile
*cfg
);
101 static int mono_method_to_ir (MonoCompile
*cfg
, MonoMethod
*method
, MonoBasicBlock
*start_bblock
, MonoBasicBlock
*end_bblock
,
102 int locals_offset
, MonoInst
*return_var
, GList
*dont_inline
, MonoInst
**inline_args
,
103 guint inline_offset
, gboolean is_virtual_call
);
105 /* helper methods signature */
106 static MonoMethodSignature
*helper_sig_class_init_trampoline
= NULL
;
107 static MonoMethodSignature
*helper_sig_domain_get
= NULL
;
109 static guint32 default_opt
= 0;
110 static gboolean default_opt_set
= FALSE
;
112 guint32 mono_jit_tls_id
= -1;
113 MonoTraceSpec
*mono_jit_trace_calls
= NULL
;
114 gboolean mono_break_on_exc
= FALSE
;
116 gboolean mono_compile_aot
= FALSE
;
118 gboolean mono_use_security_manager
= FALSE
;
120 static int mini_verbose
= 0;
122 #define mono_jit_lock() EnterCriticalSection (&jit_mutex)
123 #define mono_jit_unlock() LeaveCriticalSection (&jit_mutex)
124 static CRITICAL_SECTION jit_mutex
;
126 static GHashTable
*class_init_hash_addr
= NULL
;
128 static MonoCodeManager
*global_codeman
= NULL
;
130 static GHashTable
*jit_icall_name_hash
= NULL
;
132 static MonoDebugOptions debug_options
;
135 * Address of the trampoline code. This is used by the debugger to check
136 * whether a method is a trampoline.
138 guint8
* mono_trampoline_code
[MONO_TRAMPOLINE_NUM
];
141 mono_running_on_valgrind (void)
143 #ifdef HAVE_VALGRIND_MEMCHECK_H
144 if (RUNNING_ON_VALGRIND
)
154 * mono_create_ftnptr:
156 * Given a function address, create a function descriptor for it.
157 * This is only needed on IA64.
160 mono_create_ftnptr (MonoDomain
*domain
, gpointer addr
)
165 mono_domain_lock (domain
);
166 desc
= mono_code_manager_reserve (domain
->code_mp
, 2 * sizeof (gpointer
));
167 mono_domain_unlock (domain
);
184 find_tramp (gpointer key
, gpointer value
, gpointer user_data
)
186 FindTrampUserData
*ud
= (FindTrampUserData
*)user_data
;
189 ud
->method
= (MonoMethod
*)key
;
193 G_GNUC_UNUSED
static char*
194 get_method_from_ip (void *ip
)
199 MonoDomain
*domain
= mono_domain_get ();
200 MonoDebugSourceLocation
*location
;
201 FindTrampUserData user_data
;
203 ji
= mono_jit_info_table_find (domain
, ip
);
206 user_data
.method
= NULL
;
207 mono_domain_lock (domain
);
208 g_hash_table_foreach (domain
->jit_trampoline_hash
, find_tramp
, &user_data
);
209 mono_domain_unlock (domain
);
210 if (user_data
.method
) {
211 char *mname
= mono_method_full_name (user_data
.method
, TRUE
);
212 res
= g_strdup_printf ("<%p - JIT trampoline for %s>", ip
, mname
);
219 method
= mono_method_full_name (ji
->method
, TRUE
);
220 /* FIXME: unused ? */
221 location
= mono_debug_lookup_source_location (ji
->method
, (guint32
)((guint8
*)ip
- (guint8
*)ji
->code_start
), domain
);
223 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
);
225 mono_debug_free_source_location (location
);
234 return get_method_from_ip (ip
);
239 mono_print_method_from_ip (void *ip
)
243 MonoDebugSourceLocation
*source
;
244 MonoDomain
*domain
= mono_domain_get ();
245 FindTrampUserData user_data
;
247 ji
= mono_jit_info_table_find (domain
, ip
);
250 user_data
.method
= NULL
;
251 mono_domain_lock (domain
);
252 g_hash_table_foreach (domain
->jit_trampoline_hash
, find_tramp
, &user_data
);
253 mono_domain_unlock (domain
);
254 if (user_data
.method
) {
255 char *mname
= mono_method_full_name (user_data
.method
, TRUE
);
256 printf ("IP %p is a JIT trampoline for %s\n", ip
, mname
);
260 g_print ("No method at %p\n", ip
);
263 method
= mono_method_full_name (ji
->method
, TRUE
);
264 source
= mono_debug_lookup_source_location (ji
->method
, (guint32
)((guint8
*)ip
- (guint8
*)ji
->code_start
), domain
);
266 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
);
269 g_print ("%s:%d\n", source
->source_file
, source
->row
);
271 mono_debug_free_source_location (source
);
276 * mono_method_same_domain:
278 * Determine whenever two compiled methods are in the same domain, thus
279 * the address of the callee can be embedded in the caller.
281 gboolean
mono_method_same_domain (MonoJitInfo
*caller
, MonoJitInfo
*callee
)
283 if (!caller
|| !callee
)
287 * If the call was made from domain-neutral to domain-specific
288 * code, we can't patch the call site.
290 if (caller
->domain_neutral
&& !callee
->domain_neutral
)
293 if ((caller
->method
->klass
== mono_defaults
.appdomain_class
) &&
294 (strstr (caller
->method
->name
, "InvokeInDomain"))) {
295 /* The InvokeInDomain methods change the current appdomain */
303 * mono_global_codeman_reserve:
305 * Allocate code memory from the global code manager.
307 void *mono_global_codeman_reserve (int size
)
311 if (!global_codeman
) {
312 /* This can happen during startup */
313 global_codeman
= mono_code_manager_new ();
314 return mono_code_manager_reserve (global_codeman
, size
);
318 ptr
= mono_code_manager_reserve (global_codeman
, size
);
325 mono_jump_info_token_new (MonoMemPool
*mp
, MonoImage
*image
, guint32 token
)
327 MonoJumpInfoToken
*res
= mono_mempool_alloc0 (mp
, sizeof (MonoJumpInfoToken
));
334 #define MONO_INIT_VARINFO(vi,id) do { \
335 (vi)->range.first_use.pos.bid = 0xffff; \
340 //#define UNVERIFIED do { G_BREAKPOINT (); goto unverified; } while (0)
341 #define UNVERIFIED do { if (debug_options.break_on_unverified) G_BREAKPOINT (); else goto unverified; } while (0)
344 * Basic blocks have two numeric identifiers:
345 * dfn: Depth First Number
346 * block_num: unique ID assigned at bblock creation
348 #define NEW_BBLOCK(cfg) (mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock)))
349 #define ADD_BBLOCK(cfg,bbhash,b) do { \
350 g_hash_table_insert (bbhash, (b)->cil_code, (b)); \
351 (b)->block_num = cfg->num_bblocks++; \
352 (b)->real_offset = real_offset; \
355 #define GET_BBLOCK(cfg,bbhash,tblock,ip) do { \
356 (tblock) = g_hash_table_lookup (bbhash, (ip)); \
358 if ((ip) >= end || (ip) < header->code) UNVERIFIED; \
359 (tblock) = NEW_BBLOCK (cfg); \
360 (tblock)->cil_code = (ip); \
361 ADD_BBLOCK (cfg, (bbhash), (tblock)); \
365 #define CHECK_BBLOCK(target,ip,tblock) do { \
366 if ((target) < (ip) && !(tblock)->code) { \
367 bb_recheck = g_list_prepend (bb_recheck, (tblock)); \
368 if (cfg->verbose_level > 2) g_print ("queued block %d for check at IL%04x from IL%04x\n", (tblock)->block_num, (int)((target) - header->code), (int)((ip) - header->code)); \
372 #define NEW_ICONST(cfg,dest,val) do { \
373 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
374 (dest)->opcode = OP_ICONST; \
375 (dest)->inst_c0 = (val); \
376 (dest)->type = STACK_I4; \
379 #define NEW_PCONST(cfg,dest,val) do { \
380 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
381 (dest)->opcode = OP_PCONST; \
382 (dest)->inst_p0 = (val); \
383 (dest)->type = STACK_PTR; \
387 #ifdef MONO_ARCH_NEED_GOT_VAR
389 #define NEW_PATCH_INFO(cfg,dest,el1,el2) do { \
390 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
391 (dest)->opcode = OP_PATCH_INFO; \
392 (dest)->inst_left = (gpointer)(el1); \
393 (dest)->inst_right = (gpointer)(el2); \
396 #define NEW_AOTCONST(cfg,dest,patch_type,cons) do { \
397 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
398 (dest)->opcode = cfg->compile_aot ? OP_GOT_ENTRY : OP_PCONST; \
399 if (cfg->compile_aot) { \
400 MonoInst *group, *got_var, *got_loc; \
401 got_loc = mono_get_got_var (cfg); \
402 NEW_TEMPLOAD ((cfg), got_var, got_loc->inst_c0); \
403 NEW_PATCH_INFO ((cfg), group, cons, patch_type); \
404 (dest)->inst_p0 = got_var; \
405 (dest)->inst_p1 = group; \
407 (dest)->inst_p0 = (cons); \
408 (dest)->inst_i1 = (gpointer)(patch_type); \
410 (dest)->type = STACK_PTR; \
413 #define NEW_AOTCONST_TOKEN(cfg,dest,patch_type,image,token,stack_type,stack_class) do { \
414 MonoInst *group, *got_var, *got_loc; \
415 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
416 (dest)->opcode = OP_GOT_ENTRY; \
417 got_loc = mono_get_got_var (cfg); \
418 NEW_TEMPLOAD ((cfg), got_var, got_loc->inst_c0); \
419 NEW_PATCH_INFO ((cfg), group, NULL, patch_type); \
420 group->inst_p0 = mono_jump_info_token_new ((cfg)->mempool, (image), (token)); \
421 (dest)->inst_p0 = got_var; \
422 (dest)->inst_p1 = group; \
423 (dest)->type = (stack_type); \
424 (dest)->klass = (stack_class); \
429 #define NEW_AOTCONST(cfg,dest,patch_type,cons) do { \
430 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
431 (dest)->opcode = cfg->compile_aot ? OP_AOTCONST : OP_PCONST; \
432 (dest)->inst_p0 = (cons); \
433 (dest)->inst_i1 = (gpointer)(patch_type); \
434 (dest)->type = STACK_PTR; \
437 #define NEW_AOTCONST_TOKEN(cfg,dest,patch_type,image,token,stack_type,stack_class) do { \
438 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
439 (dest)->opcode = OP_AOTCONST; \
440 (dest)->inst_p0 = mono_jump_info_token_new ((cfg)->mempool, (image), (token)); \
441 (dest)->inst_p1 = (gpointer)(patch_type); \
442 (dest)->type = (stack_type); \
443 (dest)->klass = (stack_class); \
448 #define NEW_CLASSCONST(cfg,dest,val) NEW_AOTCONST ((cfg), (dest), MONO_PATCH_INFO_CLASS, (val))
450 #define NEW_IMAGECONST(cfg,dest,val) NEW_AOTCONST ((cfg), (dest), MONO_PATCH_INFO_IMAGE, (val))
452 #define NEW_FIELDCONST(cfg,dest,val) NEW_AOTCONST ((cfg), (dest), MONO_PATCH_INFO_FIELD, (val))
454 #define NEW_METHODCONST(cfg,dest,val) NEW_AOTCONST ((cfg), (dest), MONO_PATCH_INFO_METHODCONST, (val))
456 #define NEW_VTABLECONST(cfg,dest,vtable) NEW_AOTCONST ((cfg), (dest), MONO_PATCH_INFO_VTABLE, cfg->compile_aot ? (gpointer)((vtable)->klass) : (vtable))
458 #define NEW_SFLDACONST(cfg,dest,val) NEW_AOTCONST ((cfg), (dest), MONO_PATCH_INFO_SFLDA, (val))
460 #define NEW_LDSTRCONST(cfg,dest,image,token) NEW_AOTCONST_TOKEN ((cfg), (dest), MONO_PATCH_INFO_LDSTR, (image), (token), STACK_OBJ, mono_defaults.string_class)
462 #define NEW_TYPE_FROM_HANDLE_CONST(cfg,dest,image,token) NEW_AOTCONST_TOKEN ((cfg), (dest), MONO_PATCH_INFO_TYPE_FROM_HANDLE, (image), (token), STACK_OBJ, mono_defaults.monotype_class)
464 #define NEW_LDTOKENCONST(cfg,dest,image,token) NEW_AOTCONST_TOKEN ((cfg), (dest), MONO_PATCH_INFO_LDTOKEN, (image), (token), STACK_PTR, NULL)
466 #define NEW_DECLSECCONST(cfg,dest,image,entry) do { \
467 if (cfg->compile_aot) { \
468 NEW_AOTCONST_TOKEN (cfg, dest, MONO_PATCH_INFO_DECLSEC, image, (entry).index, STACK_OBJ, NULL); \
470 NEW_PCONST (cfg, args [0], (entry).blob); \
474 #define NEW_DOMAINCONST(cfg,dest) do { \
475 if (cfg->opt & MONO_OPT_SHARED) { \
476 /* avoid depending on undefined C behavior in sequence points */ \
477 MonoInst* __domain_var = mono_get_domainvar (cfg); \
478 NEW_TEMPLOAD (cfg, dest, __domain_var->inst_c0); \
480 NEW_PCONST (cfg, dest, (cfg)->domain); \
484 #define GET_VARINFO_INST(cfg,num) ((cfg)->varinfo [(num)]->inst)
486 #define NEW_ARGLOAD(cfg,dest,num) do { \
487 if (arg_array [(num)]->opcode == OP_ICONST) (dest) = arg_array [(num)]; else { \
488 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
489 (dest)->ssa_op = MONO_SSA_LOAD; \
490 (dest)->inst_i0 = arg_array [(num)]; \
491 (dest)->opcode = mono_type_to_ldind ((dest)->inst_i0->inst_vtype); \
492 type_to_eval_stack_type (param_types [(num)], (dest)); \
493 (dest)->klass = (dest)->inst_i0->klass; \
496 #define NEW_LOCLOAD(cfg,dest,num) do { \
497 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
498 (dest)->ssa_op = MONO_SSA_LOAD; \
499 (dest)->inst_i0 = (cfg)->varinfo [locals_offset + (num)]; \
500 (dest)->opcode = mono_type_to_ldind ((dest)->inst_i0->inst_vtype); \
501 type_to_eval_stack_type (header->locals [(num)], (dest)); \
502 (dest)->klass = (dest)->inst_i0->klass; \
505 #define NEW_LOCLOADA(cfg,dest,num) do { \
506 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
507 (dest)->ssa_op = MONO_SSA_ADDRESS_TAKEN; \
508 (dest)->inst_i0 = (cfg)->varinfo [locals_offset + (num)]; \
509 (dest)->inst_i0->flags |= MONO_INST_INDIRECT; \
510 (dest)->opcode = OP_LDADDR; \
511 (dest)->type = STACK_MP; \
512 (dest)->klass = (dest)->inst_i0->klass; \
513 if (!MONO_TYPE_ISSTRUCT (header->locals [(num)])) \
514 (cfg)->disable_ssa = TRUE; \
517 #define NEW_RETLOADA(cfg,dest) do { \
518 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
519 (dest)->ssa_op = MONO_SSA_ADDRESS_TAKEN; \
520 (dest)->inst_i0 = (cfg)->ret; \
521 (dest)->inst_i0->flags |= MONO_INST_INDIRECT; \
522 (dest)->opcode = cfg->ret_var_is_local ? OP_LDADDR : CEE_LDIND_I; \
523 (dest)->type = STACK_MP; \
524 (dest)->klass = (dest)->inst_i0->klass; \
525 (cfg)->disable_ssa = TRUE; \
528 #define NEW_ARGLOADA(cfg,dest,num) do { \
529 if (arg_array [(num)]->opcode == OP_ICONST) goto inline_failure; \
530 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
531 (dest)->ssa_op = MONO_SSA_ADDRESS_TAKEN; \
532 (dest)->inst_i0 = arg_array [(num)]; \
533 (dest)->inst_i0->flags |= MONO_INST_INDIRECT; \
534 (dest)->opcode = OP_LDADDR; \
535 (dest)->type = STACK_MP; \
536 (dest)->klass = (dest)->inst_i0->klass; \
537 (cfg)->disable_ssa = TRUE; \
540 #define NEW_TEMPLOAD(cfg,dest,num) do { \
541 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
542 (dest)->ssa_op = MONO_SSA_LOAD; \
543 (dest)->inst_i0 = (cfg)->varinfo [(num)]; \
544 (dest)->opcode = mono_type_to_ldind ((dest)->inst_i0->inst_vtype); \
545 type_to_eval_stack_type ((dest)->inst_i0->inst_vtype, (dest)); \
546 (dest)->klass = (dest)->inst_i0->klass; \
549 #define NEW_TEMPLOADA(cfg,dest,num) do { \
550 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
551 (dest)->ssa_op = MONO_SSA_ADDRESS_TAKEN; \
552 (dest)->inst_i0 = (cfg)->varinfo [(num)]; \
553 (dest)->inst_i0->flags |= MONO_INST_INDIRECT; \
554 (dest)->opcode = OP_LDADDR; \
555 (dest)->type = STACK_MP; \
556 (dest)->klass = (dest)->inst_i0->klass; \
557 if (!MONO_TYPE_ISSTRUCT (cfg->varinfo [(num)]->inst_vtype)) \
558 (cfg)->disable_ssa = TRUE; \
562 #define NEW_INDLOAD(cfg,dest,addr,vtype) do { \
563 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
564 (dest)->inst_left = addr; \
565 (dest)->opcode = mono_type_to_ldind (vtype); \
566 type_to_eval_stack_type (vtype, (dest)); \
567 /* FIXME: (dest)->klass = (dest)->inst_i0->klass;*/ \
570 #define NEW_INDSTORE(cfg,dest,addr,value,vtype) do { \
571 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
572 (dest)->inst_i0 = addr; \
573 (dest)->opcode = mono_type_to_stind (vtype); \
574 (dest)->inst_i1 = (value); \
575 /* FIXME: (dest)->klass = (dest)->inst_i0->klass;*/ \
578 #define NEW_TEMPSTORE(cfg,dest,num,inst) do { \
579 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
580 (dest)->ssa_op = MONO_SSA_STORE; \
581 (dest)->inst_i0 = (cfg)->varinfo [(num)]; \
582 (dest)->opcode = mono_type_to_stind ((dest)->inst_i0->inst_vtype); \
583 (dest)->inst_i1 = (inst); \
584 (dest)->klass = (dest)->inst_i0->klass; \
587 #define NEW_LOCSTORE(cfg,dest,num,inst) do { \
588 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
589 (dest)->opcode = mono_type_to_stind (header->locals [(num)]); \
590 (dest)->ssa_op = MONO_SSA_STORE; \
591 (dest)->inst_i0 = (cfg)->varinfo [locals_offset + (num)]; \
592 (dest)->inst_i1 = (inst); \
593 (dest)->klass = (dest)->inst_i0->klass; \
596 #define NEW_ARGSTORE(cfg,dest,num,inst) do { \
597 if (arg_array [(num)]->opcode == OP_ICONST) goto inline_failure; \
598 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
599 (dest)->opcode = mono_type_to_stind (param_types [(num)]); \
600 (dest)->ssa_op = MONO_SSA_STORE; \
601 (dest)->inst_i0 = arg_array [(num)]; \
602 (dest)->inst_i1 = (inst); \
603 (dest)->klass = (dest)->inst_i0->klass; \
606 #define NEW_DUMMY_USE(cfg,dest,load) do { \
607 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
608 (dest)->opcode = OP_DUMMY_USE; \
609 (dest)->inst_left = (load); \
612 #define NEW_DUMMY_STORE(cfg,dest,num) do { \
613 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
614 (dest)->inst_i0 = (cfg)->varinfo [(num)]; \
615 (dest)->opcode = OP_DUMMY_STORE; \
616 (dest)->klass = (dest)->inst_i0->klass; \
619 #define ADD_BINOP(op) do { \
620 MONO_INST_NEW (cfg, ins, (op)); \
621 ins->cil_code = ip; \
623 ins->inst_i0 = sp [0]; \
624 ins->inst_i1 = sp [1]; \
626 type_from_op (ins); \
630 #define ADD_UNOP(op) do { \
631 MONO_INST_NEW (cfg, ins, (op)); \
632 ins->cil_code = ip; \
634 ins->inst_i0 = sp [0]; \
636 type_from_op (ins); \
640 #define ADD_BINCOND(next_block) do { \
643 MONO_INST_NEW(cfg, cmp, OP_COMPARE); \
644 cmp->inst_i0 = sp [0]; \
645 cmp->inst_i1 = sp [1]; \
646 cmp->cil_code = ins->cil_code; \
647 type_from_op (cmp); \
649 ins->inst_i0 = cmp; \
650 MONO_ADD_INS (bblock, ins); \
651 ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2); \
652 GET_BBLOCK (cfg, bbhash, tblock, target); \
653 link_bblock (cfg, bblock, tblock); \
654 ins->inst_true_bb = tblock; \
655 CHECK_BBLOCK (target, ip, tblock); \
656 if ((next_block)) { \
657 link_bblock (cfg, bblock, (next_block)); \
658 ins->inst_false_bb = (next_block); \
659 start_new_bblock = 1; \
661 GET_BBLOCK (cfg, bbhash, tblock, ip); \
662 link_bblock (cfg, bblock, tblock); \
663 ins->inst_false_bb = tblock; \
664 start_new_bblock = 2; \
668 /* FIXME: handle float, long ... */
669 #define ADD_UNCOND(istrue) do { \
672 MONO_INST_NEW(cfg, cmp, OP_COMPARE); \
673 cmp->inst_i0 = sp [0]; \
674 switch (cmp->inst_i0->type) { \
676 cmp->inst_i1 = zero_int64; break; \
678 cmp->inst_i1 = zero_r8; break; \
681 cmp->inst_i1 = zero_ptr; break; \
683 cmp->inst_i1 = zero_obj; break; \
685 cmp->inst_i1 = zero_int32; \
687 cmp->cil_code = ins->cil_code; \
688 type_from_op (cmp); \
690 ins->inst_i0 = cmp; \
691 ins->opcode = (istrue)? CEE_BNE_UN: CEE_BEQ; \
692 MONO_ADD_INS (bblock, ins); \
693 ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2); \
694 GET_BBLOCK (cfg, bbhash, tblock, target); \
695 link_bblock (cfg, bblock, tblock); \
696 ins->inst_true_bb = tblock; \
697 CHECK_BBLOCK (target, ip, tblock); \
698 GET_BBLOCK (cfg, bbhash, tblock, ip); \
699 link_bblock (cfg, bblock, tblock); \
700 ins->inst_false_bb = tblock; \
701 start_new_bblock = 2; \
704 #define NEW_LDELEMA(cfg,dest,sp,k) do { \
705 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
706 (dest)->opcode = CEE_LDELEMA; \
707 (dest)->inst_left = (sp) [0]; \
708 (dest)->inst_right = (sp) [1]; \
709 (dest)->type = STACK_MP; \
710 (dest)->klass = (k); \
711 (cfg)->flags |= MONO_CFG_HAS_LDELEMA; \
714 #define NEW_GROUP(cfg,dest,el1,el2) do { \
715 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
716 (dest)->opcode = OP_GROUP; \
717 (dest)->inst_left = (el1); \
718 (dest)->inst_right = (el2); \
723 compare_bblock (gconstpointer a
, gconstpointer b
)
725 const MonoBasicBlock
*b1
= a
;
726 const MonoBasicBlock
*b2
= b
;
728 return b2
->cil_code
- b1
->cil_code
;
733 * link_bblock: Links two basic blocks
735 * links two basic blocks in the control flow graph, the 'from'
736 * argument is the starting block and the 'to' argument is the block
737 * the control flow ends to after 'from'.
740 link_bblock (MonoCompile
*cfg
, MonoBasicBlock
*from
, MonoBasicBlock
* to
)
742 MonoBasicBlock
**newa
;
746 if (from
->cil_code
) {
748 g_print ("edge from IL%04x to IL_%04x\n", from
->cil_code
- cfg
->cil_code
, to
->cil_code
- cfg
->cil_code
);
750 g_print ("edge from IL%04x to exit\n", from
->cil_code
- cfg
->cil_code
);
753 g_print ("edge from entry to IL_%04x\n", to
->cil_code
- cfg
->cil_code
);
755 g_print ("edge from entry to exit\n");
759 for (i
= 0; i
< from
->out_count
; ++i
) {
760 if (to
== from
->out_bb
[i
]) {
766 newa
= mono_mempool_alloc (cfg
->mempool
, sizeof (gpointer
) * (from
->out_count
+ 1));
767 for (i
= 0; i
< from
->out_count
; ++i
) {
768 newa
[i
] = from
->out_bb
[i
];
776 for (i
= 0; i
< to
->in_count
; ++i
) {
777 if (from
== to
->in_bb
[i
]) {
783 newa
= mono_mempool_alloc (cfg
->mempool
, sizeof (gpointer
) * (to
->in_count
+ 1));
784 for (i
= 0; i
< to
->in_count
; ++i
) {
785 newa
[i
] = to
->in_bb
[i
];
794 * mono_unlink_bblock:
796 * Unlink two basic blocks.
799 mono_unlink_bblock (MonoCompile
*cfg
, MonoBasicBlock
*from
, MonoBasicBlock
* to
)
805 for (i
= 0; i
< from
->out_count
; ++i
) {
806 if (to
== from
->out_bb
[i
]) {
813 for (i
= 0; i
< from
->out_count
; ++i
) {
814 if (from
->out_bb
[i
] != to
)
815 from
->out_bb
[pos
++] = from
->out_bb
[i
];
817 g_assert (pos
== from
->out_count
- 1);
822 for (i
= 0; i
< to
->in_count
; ++i
) {
823 if (from
== to
->in_bb
[i
]) {
830 for (i
= 0; i
< to
->in_count
; ++i
) {
831 if (to
->in_bb
[i
] != from
)
832 to
->in_bb
[pos
++] = to
->in_bb
[i
];
834 g_assert (pos
== to
->in_count
- 1);
840 * mono_find_block_region:
842 * We mark each basic block with a region ID. We use that to avoid BB
843 * optimizations when blocks are in different regions.
846 * A region token that encodes where this region is, and information
847 * about the clause owner for this block.
849 * The region encodes the try/catch/filter clause that owns this block
850 * as well as the type. -1 is a special value that represents a block
851 * that is in none of try/catch/filter.
854 mono_find_block_region (MonoCompile
*cfg
, int offset
)
856 MonoMethod
*method
= cfg
->method
;
857 MonoMethodHeader
*header
= mono_method_get_header (method
);
858 MonoExceptionClause
*clause
;
861 /* first search for handlers and filters */
862 for (i
= 0; i
< header
->num_clauses
; ++i
) {
863 clause
= &header
->clauses
[i
];
864 if ((clause
->flags
== MONO_EXCEPTION_CLAUSE_FILTER
) && (offset
>= clause
->data
.filter_offset
) &&
865 (offset
< (clause
->handler_offset
)))
866 return ((i
+ 1) << 8) | MONO_REGION_FILTER
| clause
->flags
;
868 if (MONO_OFFSET_IN_HANDLER (clause
, offset
)) {
869 if (clause
->flags
& MONO_EXCEPTION_CLAUSE_FINALLY
)
870 return ((i
+ 1) << 8) | MONO_REGION_FINALLY
| clause
->flags
;
872 return ((i
+ 1) << 8) | MONO_REGION_CATCH
| clause
->flags
;
876 /* search the try blocks */
877 for (i
= 0; i
< header
->num_clauses
; ++i
) {
878 clause
= &header
->clauses
[i
];
879 if (MONO_OFFSET_IN_CLAUSE (clause
, offset
))
880 return ((i
+ 1) << 8) | clause
->flags
;
887 mono_find_final_block (MonoCompile
*cfg
, unsigned char *ip
, unsigned char *target
, int type
)
889 MonoMethod
*method
= cfg
->method
;
890 MonoMethodHeader
*header
= mono_method_get_header (method
);
891 MonoExceptionClause
*clause
;
892 MonoBasicBlock
*handler
;
896 for (i
= 0; i
< header
->num_clauses
; ++i
) {
897 clause
= &header
->clauses
[i
];
898 if (MONO_OFFSET_IN_CLAUSE (clause
, (ip
- header
->code
)) &&
899 (!MONO_OFFSET_IN_CLAUSE (clause
, (target
- header
->code
)))) {
900 if (clause
->flags
== type
) {
901 handler
= g_hash_table_lookup (cfg
->bb_hash
, header
->code
+ clause
->handler_offset
);
903 res
= g_list_append (res
, handler
);
911 mono_find_spvar_for_region (MonoCompile
*cfg
, int region
)
913 return g_hash_table_lookup (cfg
->spvars
, GINT_TO_POINTER (region
));
917 mono_create_spvar_for_region (MonoCompile
*cfg
, int region
)
921 var
= g_hash_table_lookup (cfg
->spvars
, GINT_TO_POINTER (region
));
925 var
= mono_compile_create_var (cfg
, &mono_defaults
.int_class
->byval_arg
, OP_LOCAL
);
926 /* prevent it from being register allocated */
927 var
->flags
|= MONO_INST_INDIRECT
;
929 g_hash_table_insert (cfg
->spvars
, GINT_TO_POINTER (region
), var
);
933 mono_find_exvar_for_offset (MonoCompile
*cfg
, int offset
)
935 return g_hash_table_lookup (cfg
->exvars
, GINT_TO_POINTER (offset
));
939 mono_create_exvar_for_offset (MonoCompile
*cfg
, int offset
)
943 var
= g_hash_table_lookup (cfg
->exvars
, GINT_TO_POINTER (offset
));
947 var
= mono_compile_create_var (cfg
, &mono_defaults
.object_class
->byval_arg
, OP_LOCAL
);
948 /* prevent it from being register allocated */
949 var
->flags
|= MONO_INST_INDIRECT
;
951 g_hash_table_insert (cfg
->exvars
, GINT_TO_POINTER (offset
), var
);
957 df_visit (MonoBasicBlock
*start
, int *dfn
, MonoBasicBlock
**array
)
961 array
[*dfn
] = start
;
962 /*g_print ("visit %d at %p (BB%ld)\n", *dfn, start->cil_code, start->block_num);*/
963 for (i
= 0; i
< start
->out_count
; ++i
) {
964 if (start
->out_bb
[i
]->dfn
)
967 start
->out_bb
[i
]->dfn
= *dfn
;
968 start
->out_bb
[i
]->df_parent
= start
;
969 array
[*dfn
] = start
->out_bb
[i
];
970 df_visit (start
->out_bb
[i
], dfn
, array
);
976 MonoBasicBlock
*best
;
980 previous_foreach (gconstpointer key
, gpointer val
, gpointer data
)
982 PrevStruct
*p
= data
;
983 MonoBasicBlock
*bb
= val
;
984 //printf ("FIDPREV %d %p %p %p %p %p %d %d %d\n", bb->block_num, p->code, bb, p->best, bb->cil_code, p->best->cil_code,
985 //bb->method == p->best->method, bb->cil_code < p->code, bb->cil_code > p->best->cil_code);
987 if (bb
->cil_code
&& bb
->cil_code
< p
->code
&& bb
->cil_code
> p
->best
->cil_code
)
991 static MonoBasicBlock
*
992 find_previous (GHashTable
*bb_hash
, MonoBasicBlock
*start
, const guchar
*code
) {
998 g_hash_table_foreach (bb_hash
, (GHFunc
)previous_foreach
, &p
);
1003 split_bblock (MonoCompile
*cfg
, MonoBasicBlock
*first
, MonoBasicBlock
*second
) {
1012 * FIXME: take into account all the details:
1013 * second may have been the target of more than one bblock
1015 second
->out_count
= first
->out_count
;
1016 second
->out_bb
= first
->out_bb
;
1018 for (i
= 0; i
< first
->out_count
; ++i
) {
1019 bb
= first
->out_bb
[i
];
1020 for (j
= 0; j
< bb
->in_count
; ++j
) {
1021 if (bb
->in_bb
[j
] == first
)
1022 bb
->in_bb
[j
] = second
;
1026 first
->out_count
= 0;
1027 first
->out_bb
= NULL
;
1028 link_bblock (cfg
, first
, second
);
1030 second
->last_ins
= first
->last_ins
;
1032 /*g_print ("start search at %p for %p\n", first->cil_code, second->cil_code);*/
1033 for (inst
= first
->code
; inst
&& inst
->next
; inst
= inst
->next
) {
1034 /*char *code = mono_disasm_code_one (NULL, cfg->method, inst->next->cil_code, NULL);
1035 g_print ("found %p: %s", inst->next->cil_code, code);
1037 if (inst
->cil_code
< second
->cil_code
&& inst
->next
->cil_code
>= second
->cil_code
) {
1038 second
->code
= inst
->next
;
1040 first
->last_ins
= inst
;
1041 second
->next_bb
= first
->next_bb
;
1042 first
->next_bb
= second
;
1046 if (!second
->code
) {
1047 g_warning ("bblock split failed in %s::%s\n", cfg
->method
->klass
->name
, cfg
->method
->name
);
1053 reverse_branch_op (guint32 opcode
)
1055 static const int reverse_map
[] = {
1056 CEE_BNE_UN
, CEE_BLT
, CEE_BLE
, CEE_BGT
, CEE_BGE
,
1057 CEE_BEQ
, CEE_BLT_UN
, CEE_BLE_UN
, CEE_BGT_UN
, CEE_BGE_UN
1059 static const int reverse_fmap
[] = {
1060 OP_FBNE_UN
, OP_FBLT
, OP_FBLE
, OP_FBGT
, OP_FBGE
,
1061 OP_FBEQ
, OP_FBLT_UN
, OP_FBLE_UN
, OP_FBGT_UN
, OP_FBGE_UN
1063 static const int reverse_lmap
[] = {
1064 OP_LBNE_UN
, OP_LBLT
, OP_LBLE
, OP_LBGT
, OP_LBGE
,
1065 OP_LBEQ
, OP_LBLT_UN
, OP_LBLE_UN
, OP_LBGT_UN
, OP_LBGE_UN
1067 static const int reverse_imap
[] = {
1068 OP_IBNE_UN
, OP_IBLT
, OP_IBLE
, OP_IBGT
, OP_IBGE
,
1069 OP_IBEQ
, OP_IBLT_UN
, OP_IBLE_UN
, OP_IBGT_UN
, OP_IBGE_UN
1072 if (opcode
>= CEE_BEQ
&& opcode
<= CEE_BLT_UN
) {
1073 opcode
= reverse_map
[opcode
- CEE_BEQ
];
1074 } else if (opcode
>= OP_FBEQ
&& opcode
<= OP_FBLT_UN
) {
1075 opcode
= reverse_fmap
[opcode
- OP_FBEQ
];
1076 } else if (opcode
>= OP_LBEQ
&& opcode
<= OP_LBLT_UN
) {
1077 opcode
= reverse_lmap
[opcode
- OP_LBEQ
];
1078 } else if (opcode
>= OP_IBEQ
&& opcode
<= OP_IBLT_UN
) {
1079 opcode
= reverse_imap
[opcode
- OP_IBEQ
];
1081 g_assert_not_reached ();
1086 #ifdef MONO_ARCH_SOFT_FLOAT
1088 condbr_to_fp_br (int opcode
)
1091 case CEE_BEQ
: return OP_FBEQ
;
1092 case CEE_BGE
: return OP_FBGE
;
1093 case CEE_BGT
: return OP_FBGT
;
1094 case CEE_BLE
: return OP_FBLE
;
1095 case CEE_BLT
: return OP_FBLT
;
1096 case CEE_BNE_UN
: return OP_FBNE_UN
;
1097 case CEE_BGE_UN
: return OP_FBGE_UN
;
1098 case CEE_BGT_UN
: return OP_FBGT_UN
;
1099 case CEE_BLE_UN
: return OP_FBLE_UN
;
1100 case CEE_BLT_UN
: return OP_FBLT_UN
;
1102 g_assert_not_reached ();
1108 * Returns the type used in the eval stack when @type is loaded.
1109 * FIXME: return a MonoType/MonoClass for the byref and VALUETYPE cases.
1112 type_to_eval_stack_type (MonoType
*type
, MonoInst
*inst
)
1116 inst
->klass
= klass
= mono_class_from_mono_type (type
);
1118 inst
->type
= STACK_MP
;
1123 switch (type
->type
) {
1124 case MONO_TYPE_VOID
:
1125 inst
->type
= STACK_INV
;
1129 case MONO_TYPE_BOOLEAN
:
1132 case MONO_TYPE_CHAR
:
1135 inst
->type
= STACK_I4
;
1140 case MONO_TYPE_FNPTR
:
1141 inst
->type
= STACK_PTR
;
1143 case MONO_TYPE_CLASS
:
1144 case MONO_TYPE_STRING
:
1145 case MONO_TYPE_OBJECT
:
1146 case MONO_TYPE_SZARRAY
:
1147 case MONO_TYPE_ARRAY
:
1148 inst
->type
= STACK_OBJ
;
1152 inst
->type
= STACK_I8
;
1156 inst
->type
= STACK_R8
;
1158 case MONO_TYPE_VALUETYPE
:
1159 if (type
->data
.klass
->enumtype
) {
1160 type
= type
->data
.klass
->enum_basetype
;
1163 inst
->klass
= klass
;
1164 inst
->type
= STACK_VTYPE
;
1167 case MONO_TYPE_TYPEDBYREF
:
1168 inst
->klass
= mono_defaults
.typed_reference_class
;
1169 inst
->type
= STACK_VTYPE
;
1171 case MONO_TYPE_GENERICINST
:
1172 type
= &type
->data
.generic_class
->container_class
->byval_arg
;
1175 g_error ("unknown type 0x%02x in eval stack type", type
->type
);
1180 * The following tables are used to quickly validate the IL code in type_from_op ().
1183 bin_num_table
[STACK_MAX
] [STACK_MAX
] = {
1184 {STACK_INV
, STACK_INV
, STACK_INV
, STACK_INV
, STACK_INV
, STACK_INV
, STACK_INV
, STACK_INV
},
1185 {STACK_INV
, STACK_I4
, STACK_INV
, STACK_PTR
, STACK_INV
, STACK_MP
, STACK_INV
, STACK_INV
},
1186 {STACK_INV
, STACK_INV
, STACK_I8
, STACK_INV
, STACK_INV
, STACK_INV
, STACK_INV
, STACK_INV
},
1187 {STACK_INV
, STACK_PTR
, STACK_INV
, STACK_PTR
, STACK_INV
, STACK_MP
, STACK_INV
, STACK_INV
},
1188 {STACK_INV
, STACK_INV
, STACK_INV
, STACK_INV
, STACK_R8
, STACK_INV
, STACK_INV
, STACK_INV
},
1189 {STACK_INV
, STACK_MP
, STACK_INV
, STACK_MP
, STACK_INV
, STACK_PTR
, STACK_INV
, STACK_INV
},
1190 {STACK_INV
, STACK_INV
, STACK_INV
, STACK_INV
, STACK_INV
, STACK_INV
, STACK_INV
, STACK_INV
},
1191 {STACK_INV
, STACK_INV
, STACK_INV
, STACK_INV
, STACK_INV
, STACK_INV
, STACK_INV
, STACK_INV
}
1196 STACK_INV
, STACK_I4
, STACK_I8
, STACK_PTR
, STACK_R8
, STACK_INV
, STACK_INV
, STACK_INV
1199 /* reduce the size of this table */
1201 bin_int_table
[STACK_MAX
] [STACK_MAX
] = {
1202 {STACK_INV
, STACK_INV
, STACK_INV
, STACK_INV
, STACK_INV
, STACK_INV
, STACK_INV
, STACK_INV
},
1203 {STACK_INV
, STACK_I4
, STACK_INV
, STACK_PTR
, STACK_INV
, STACK_INV
, STACK_INV
, STACK_INV
},
1204 {STACK_INV
, STACK_INV
, STACK_I8
, STACK_INV
, STACK_INV
, STACK_INV
, STACK_INV
, STACK_INV
},
1205 {STACK_INV
, STACK_PTR
, STACK_INV
, STACK_PTR
, STACK_INV
, STACK_INV
, STACK_INV
, STACK_INV
},
1206 {STACK_INV
, STACK_INV
, STACK_INV
, STACK_INV
, STACK_INV
, STACK_INV
, STACK_INV
, STACK_INV
},
1207 {STACK_INV
, STACK_INV
, STACK_INV
, STACK_INV
, STACK_INV
, STACK_INV
, STACK_INV
, STACK_INV
},
1208 {STACK_INV
, STACK_INV
, STACK_INV
, STACK_INV
, STACK_INV
, STACK_INV
, STACK_INV
, STACK_INV
},
1209 {STACK_INV
, STACK_INV
, STACK_INV
, STACK_INV
, STACK_INV
, STACK_INV
, STACK_INV
, STACK_INV
}
1213 bin_comp_table
[STACK_MAX
] [STACK_MAX
] = {
1214 /* Inv i L p F & O vt */
1216 {0, 1, 0, 1, 0, 0, 0, 0}, /* i, int32 */
1217 {0, 0, 1, 0, 0, 0, 0, 0}, /* L, int64 */
1218 {0, 1, 0, 1, 0, 2, 4, 0}, /* p, ptr */
1219 {0, 0, 0, 0, 1, 0, 0, 0}, /* F, R8 */
1220 {0, 0, 0, 2, 0, 1, 0, 0}, /* &, managed pointer */
1221 {0, 0, 0, 4, 0, 0, 3, 0}, /* O, reference */
1222 {0, 0, 0, 0, 0, 0, 0, 0}, /* vt value type */
1225 /* reduce the size of this table */
1227 shift_table
[STACK_MAX
] [STACK_MAX
] = {
1228 {STACK_INV
, STACK_INV
, STACK_INV
, STACK_INV
, STACK_INV
, STACK_INV
, STACK_INV
, STACK_INV
},
1229 {STACK_INV
, STACK_I4
, STACK_INV
, STACK_I4
, STACK_INV
, STACK_INV
, STACK_INV
, STACK_INV
},
1230 {STACK_INV
, STACK_I8
, STACK_INV
, STACK_I8
, STACK_INV
, STACK_INV
, STACK_INV
, STACK_INV
},
1231 {STACK_INV
, STACK_PTR
, STACK_INV
, STACK_PTR
, STACK_INV
, STACK_INV
, STACK_INV
, STACK_INV
},
1232 {STACK_INV
, STACK_INV
, STACK_INV
, STACK_INV
, STACK_INV
, STACK_INV
, STACK_INV
, STACK_INV
},
1233 {STACK_INV
, STACK_INV
, STACK_INV
, STACK_INV
, STACK_INV
, STACK_INV
, STACK_INV
, STACK_INV
},
1234 {STACK_INV
, STACK_INV
, STACK_INV
, STACK_INV
, STACK_INV
, STACK_INV
, STACK_INV
, STACK_INV
},
1235 {STACK_INV
, STACK_INV
, STACK_INV
, STACK_INV
, STACK_INV
, STACK_INV
, STACK_INV
, STACK_INV
}
1239 * Tables to map from the non-specific opcode to the matching
1240 * type-specific opcode.
1242 /* handles from CEE_ADD to CEE_SHR_UN (CEE_REM_UN for floats) */
1243 static const guint16
1244 binops_op_map
[STACK_MAX
] = {
1245 0, 0, OP_LADD
-CEE_ADD
, OP_PADD
-CEE_ADD
, OP_FADD
-CEE_ADD
, OP_PADD
-CEE_ADD
1248 /* handles from CEE_NEG to CEE_CONV_U8 */
1249 static const guint16
1250 unops_op_map
[STACK_MAX
] = {
1251 0, 0, OP_LNEG
-CEE_NEG
, OP_PNEG
-CEE_NEG
, OP_FNEG
-CEE_NEG
, OP_PNEG
-CEE_NEG
1254 /* handles from CEE_CONV_U2 to CEE_SUB_OVF_UN */
1255 static const guint16
1256 ovfops_op_map
[STACK_MAX
] = {
1257 0, 0, OP_LCONV_TO_U2
-CEE_CONV_U2
, OP_PCONV_TO_U2
-CEE_CONV_U2
, OP_FCONV_TO_U2
-CEE_CONV_U2
, OP_PCONV_TO_U2
-CEE_CONV_U2
, OP_PCONV_TO_U2
-CEE_CONV_U2
1260 /* handles from CEE_CONV_OVF_I1_UN to CEE_CONV_OVF_U_UN */
1261 static const guint16
1262 ovf2ops_op_map
[STACK_MAX
] = {
1263 0, 0, OP_LCONV_TO_OVF_I1_UN
-CEE_CONV_OVF_I1_UN
, OP_PCONV_TO_OVF_I1_UN
-CEE_CONV_OVF_I1_UN
, OP_FCONV_TO_OVF_I1_UN
-CEE_CONV_OVF_I1_UN
, OP_PCONV_TO_OVF_I1_UN
-CEE_CONV_OVF_I1_UN
1266 /* handles from CEE_CONV_OVF_I1 to CEE_CONV_OVF_U8 */
1267 static const guint16
1268 ovf3ops_op_map
[STACK_MAX
] = {
1269 0, 0, OP_LCONV_TO_OVF_I1
-CEE_CONV_OVF_I1
, OP_PCONV_TO_OVF_I1
-CEE_CONV_OVF_I1
, OP_FCONV_TO_OVF_I1
-CEE_CONV_OVF_I1
, OP_PCONV_TO_OVF_I1
-CEE_CONV_OVF_I1
1272 /* handles from CEE_CEQ to CEE_CLT_UN */
1273 static const guint16
1274 ceqops_op_map
[STACK_MAX
] = {
1275 0, 0, OP_LCEQ
-OP_CEQ
, OP_PCEQ
-OP_CEQ
, OP_FCEQ
-OP_CEQ
, OP_LCEQ
-OP_CEQ
1279 * Sets ins->type (the type on the eval stack) according to the
1280 * type of the opcode and the arguments to it.
1281 * Invalid IL code is marked by setting ins->type to the invalid value STACK_INV.
1283 * FIXME: this function sets ins->type unconditionally in some cases, but
1284 * it should set it to invalid for some types (a conv.x on an object)
1287 type_from_op (MonoInst
*ins
) {
1288 switch (ins
->opcode
) {
1295 /* FIXME: check unverifiable args for STACK_MP */
1296 ins
->type
= bin_num_table
[ins
->inst_i0
->type
] [ins
->inst_i1
->type
];
1297 ins
->opcode
+= binops_op_map
[ins
->type
];
1304 ins
->type
= bin_int_table
[ins
->inst_i0
->type
] [ins
->inst_i1
->type
];
1305 ins
->opcode
+= binops_op_map
[ins
->type
];
1310 ins
->type
= shift_table
[ins
->inst_i0
->type
] [ins
->inst_i1
->type
];
1311 ins
->opcode
+= binops_op_map
[ins
->type
];
1315 /* FIXME: handle some specifics with ins->next->type */
1316 ins
->type
= bin_comp_table
[ins
->inst_i0
->type
] [ins
->inst_i1
->type
] ? STACK_I4
: STACK_INV
;
1317 if ((ins
->inst_i0
->type
== STACK_I8
) || ((sizeof (gpointer
) == 8) && ((ins
->inst_i0
->type
== STACK_PTR
) || (ins
->inst_i0
->type
== STACK_OBJ
) || (ins
->inst_i0
->type
== STACK_MP
))))
1318 ins
->opcode
= OP_LCOMPARE
;
1325 ins
->type
= bin_comp_table
[ins
->inst_i0
->type
] [ins
->inst_i1
->type
] ? STACK_I4
: STACK_INV
;
1326 ins
->opcode
+= ceqops_op_map
[ins
->inst_i0
->type
];
1330 ins
->type
= neg_table
[ins
->inst_i0
->type
];
1331 ins
->opcode
+= unops_op_map
[ins
->type
];
1334 if (ins
->inst_i0
->type
>= STACK_I4
&& ins
->inst_i0
->type
<= STACK_PTR
)
1335 ins
->type
= ins
->inst_i0
->type
;
1337 ins
->type
= STACK_INV
;
1338 ins
->opcode
+= unops_op_map
[ins
->type
];
1344 ins
->type
= STACK_I4
;
1345 ins
->opcode
+= unops_op_map
[ins
->inst_i0
->type
];
1348 ins
->type
= STACK_R8
;
1349 switch (ins
->inst_i0
->type
) {
1354 ins
->opcode
= OP_LCONV_TO_R_UN
;
1358 case CEE_CONV_OVF_I1
:
1359 case CEE_CONV_OVF_U1
:
1360 case CEE_CONV_OVF_I2
:
1361 case CEE_CONV_OVF_U2
:
1362 case CEE_CONV_OVF_I4
:
1363 case CEE_CONV_OVF_U4
:
1364 ins
->type
= STACK_I4
;
1365 ins
->opcode
+= ovf3ops_op_map
[ins
->inst_i0
->type
];
1367 case CEE_CONV_OVF_I_UN
:
1368 case CEE_CONV_OVF_U_UN
:
1369 ins
->type
= STACK_PTR
;
1370 ins
->opcode
+= ovf2ops_op_map
[ins
->inst_i0
->type
];
1372 case CEE_CONV_OVF_I1_UN
:
1373 case CEE_CONV_OVF_I2_UN
:
1374 case CEE_CONV_OVF_I4_UN
:
1375 case CEE_CONV_OVF_U1_UN
:
1376 case CEE_CONV_OVF_U2_UN
:
1377 case CEE_CONV_OVF_U4_UN
:
1378 ins
->type
= STACK_I4
;
1379 ins
->opcode
+= ovf2ops_op_map
[ins
->inst_i0
->type
];
1382 ins
->type
= STACK_PTR
;
1383 switch (ins
->inst_i0
->type
) {
1389 ins
->opcode
= OP_LCONV_TO_U
;
1392 ins
->opcode
= OP_FCONV_TO_U
;
1398 ins
->type
= STACK_I8
;
1399 ins
->opcode
+= unops_op_map
[ins
->inst_i0
->type
];
1401 case CEE_CONV_OVF_I8
:
1402 case CEE_CONV_OVF_U8
:
1403 ins
->type
= STACK_I8
;
1404 ins
->opcode
+= ovf3ops_op_map
[ins
->inst_i0
->type
];
1406 case CEE_CONV_OVF_U8_UN
:
1407 case CEE_CONV_OVF_I8_UN
:
1408 ins
->type
= STACK_I8
;
1409 ins
->opcode
+= ovf2ops_op_map
[ins
->inst_i0
->type
];
1413 ins
->type
= STACK_R8
;
1414 ins
->opcode
+= unops_op_map
[ins
->inst_i0
->type
];
1417 ins
->type
= STACK_R8
;
1421 ins
->type
= STACK_I4
;
1422 ins
->opcode
+= ovfops_op_map
[ins
->inst_i0
->type
];
1425 case CEE_CONV_OVF_I
:
1426 case CEE_CONV_OVF_U
:
1427 ins
->type
= STACK_PTR
;
1428 ins
->opcode
+= ovfops_op_map
[ins
->inst_i0
->type
];
1431 case CEE_ADD_OVF_UN
:
1433 case CEE_MUL_OVF_UN
:
1435 case CEE_SUB_OVF_UN
:
1436 ins
->type
= bin_num_table
[ins
->inst_i0
->type
] [ins
->inst_i1
->type
];
1437 ins
->opcode
+= ovfops_op_map
[ins
->inst_i0
->type
];
1440 g_error ("opcode 0x%04x not handled in type from op", ins
->opcode
);
1447 STACK_I4
, STACK_I4
, STACK_I4
, STACK_I4
, STACK_I4
, STACK_I4
, STACK_I8
, STACK_PTR
, STACK_R8
, STACK_R8
, STACK_OBJ
1450 /* map ldelem.x to the matching ldind.x opcode */
1452 ldelem_to_ldind
[] = {
1466 /* map stelem.x to the matching stind.x opcode */
1468 stelem_to_stind
[] = {
1482 param_table
[STACK_MAX
] [STACK_MAX
] = {
1487 check_values_to_signature (MonoInst
*args
, MonoType
*this, MonoMethodSignature
*sig
) {
1491 switch (args
->type
) {
1501 for (i
= 0; i
< sig
->param_count
; ++i
) {
1502 switch (args
[i
].type
) {
1506 if (!sig
->params
[i
]->byref
)
1510 if (sig
->params
[i
]->byref
)
1512 switch (sig
->params
[i
]->type
) {
1513 case MONO_TYPE_CLASS
:
1514 case MONO_TYPE_STRING
:
1515 case MONO_TYPE_OBJECT
:
1516 case MONO_TYPE_SZARRAY
:
1517 case MONO_TYPE_ARRAY
:
1524 if (sig
->params
[i
]->byref
)
1526 if (sig
->params
[i
]->type
!= MONO_TYPE_R4
&& sig
->params
[i
]->type
!= MONO_TYPE_R8
)
1535 /*if (!param_table [args [i].type] [sig->params [i]->type])
1543 * When we need a pointer to the current domain many times in a method, we
1544 * call mono_domain_get() once and we store the result in a local variable.
1545 * This function returns the variable that represents the MonoDomain*.
1547 inline static MonoInst
*
1548 mono_get_domainvar (MonoCompile
*cfg
)
1550 if (!cfg
->domainvar
)
1551 cfg
->domainvar
= mono_compile_create_var (cfg
, &mono_defaults
.int_class
->byval_arg
, OP_LOCAL
);
1552 return cfg
->domainvar
;
1556 * The got_var contains the address of the Global Offset Table when AOT
1559 inline static MonoInst
*
1560 mono_get_got_var (MonoCompile
*cfg
)
1562 #ifdef MONO_ARCH_NEED_GOT_VAR
1563 if (!cfg
->compile_aot
)
1565 if (!cfg
->got_var
) {
1566 cfg
->got_var
= mono_compile_create_var (cfg
, &mono_defaults
.int_class
->byval_arg
, OP_LOCAL
);
1568 return cfg
->got_var
;
1575 mono_compile_create_var (MonoCompile
*cfg
, MonoType
*type
, int opcode
)
1578 int num
= cfg
->num_varinfo
;
1580 if ((num
+ 1) >= cfg
->varinfo_count
) {
1581 cfg
->varinfo_count
= (cfg
->varinfo_count
+ 2) * 2;
1582 cfg
->varinfo
= (MonoInst
**)g_realloc (cfg
->varinfo
, sizeof (MonoInst
*) * cfg
->varinfo_count
);
1583 cfg
->vars
= (MonoMethodVar
**)g_realloc (cfg
->vars
, sizeof (MonoMethodVar
*) * cfg
->varinfo_count
);
1586 /*g_print ("created temp %d of type 0x%x\n", num, type->type);*/
1587 mono_jit_stats
.allocate_var
++;
1589 MONO_INST_NEW (cfg
, inst
, opcode
);
1590 inst
->inst_c0
= num
;
1591 inst
->inst_vtype
= type
;
1592 inst
->klass
= mono_class_from_mono_type (type
);
1593 /* if set to 1 the variable is native */
1594 inst
->backend
.is_pinvoke
= 0;
1596 cfg
->varinfo
[num
] = inst
;
1598 cfg
->vars
[num
] = mono_mempool_alloc0 (cfg
->mempool
, sizeof (MonoMethodVar
));
1599 MONO_INIT_VARINFO (cfg
->vars
[num
], num
);
1602 //g_print ("created temp %d of type %s\n", num, mono_type_get_name (type));
1607 * Transform a MonoInst into a load from the variable of index var_index.
1610 mono_compile_make_var_load (MonoCompile
*cfg
, MonoInst
*dest
, gssize var_index
) {
1611 memset (dest
, 0, sizeof (MonoInst
));
1612 dest
->ssa_op
= MONO_SSA_LOAD
;
1613 dest
->inst_i0
= cfg
->varinfo
[var_index
];
1614 dest
->opcode
= mono_type_to_ldind (dest
->inst_i0
->inst_vtype
);
1615 type_to_eval_stack_type (dest
->inst_i0
->inst_vtype
, dest
);
1616 dest
->klass
= dest
->inst_i0
->klass
;
1620 * Create a MonoInst that is a load from the variable of index var_index.
1623 mono_compile_create_var_load (MonoCompile
*cfg
, gssize var_index
) {
1625 NEW_TEMPLOAD (cfg
,dest
,var_index
);
1630 * Create a MonoInst that is a store of the given value into the variable of index var_index.
1633 mono_compile_create_var_store (MonoCompile
*cfg
, gssize var_index
, MonoInst
*value
) {
1635 NEW_TEMPSTORE (cfg
, dest
, var_index
, value
);
1640 type_from_stack_type (MonoInst
*ins
) {
1641 switch (ins
->type
) {
1642 case STACK_I4
: return &mono_defaults
.int32_class
->byval_arg
;
1643 case STACK_I8
: return &mono_defaults
.int64_class
->byval_arg
;
1644 case STACK_PTR
: return &mono_defaults
.int_class
->byval_arg
;
1645 case STACK_R8
: return &mono_defaults
.double_class
->byval_arg
;
1648 * FIXME: This doesn't work because mono_class_from_mono_type ()
1649 * returns the original klass for a byref type, not a 'byref' class,
1650 * causing the JIT to create variables with the wrong type, for
1655 return &ins->klass->this_arg;
1658 return &mono_defaults
.object_class
->this_arg
;
1659 case STACK_OBJ
: return &mono_defaults
.object_class
->byval_arg
;
1660 case STACK_VTYPE
: return &ins
->klass
->byval_arg
;
1662 g_error ("stack type %d to montype not handled\n", ins
->type
);
1668 mono_type_from_stack_type (MonoInst
*ins
) {
1669 return type_from_stack_type (ins
);
1673 array_access_to_klass (int opcode
)
1677 return mono_defaults
.byte_class
;
1679 return mono_defaults
.uint16_class
;
1682 return mono_defaults
.int_class
;
1685 return mono_defaults
.sbyte_class
;
1688 return mono_defaults
.int16_class
;
1691 return mono_defaults
.int32_class
;
1693 return mono_defaults
.uint32_class
;
1696 return mono_defaults
.int64_class
;
1699 return mono_defaults
.single_class
;
1702 return mono_defaults
.double_class
;
1703 case CEE_LDELEM_REF
:
1704 case CEE_STELEM_REF
:
1705 return mono_defaults
.object_class
;
1707 g_assert_not_reached ();
1713 mono_add_ins_to_end (MonoBasicBlock
*bb
, MonoInst
*inst
)
1717 MONO_ADD_INS (bb
, inst
);
1720 switch (bb
->last_ins
->opcode
) {
1734 while (prev
->next
&& prev
->next
!= bb
->last_ins
)
1736 if (prev
== bb
->code
) {
1737 if (bb
->last_ins
== bb
->code
) {
1738 inst
->next
= bb
->code
;
1741 inst
->next
= prev
->next
;
1745 inst
->next
= bb
->last_ins
;
1749 // g_warning ("handle conditional jump in add_ins_to_end ()\n");
1751 MONO_ADD_INS (bb
, inst
);
1757 mono_add_varcopy_to_end (MonoCompile
*cfg
, MonoBasicBlock
*bb
, int src
, int dest
)
1759 MonoInst
*inst
, *load
;
1761 NEW_TEMPLOAD (cfg
, load
, src
);
1763 NEW_TEMPSTORE (cfg
, inst
, dest
, load
);
1764 if (inst
->opcode
== CEE_STOBJ
) {
1765 NEW_TEMPLOADA (cfg
, inst
, dest
);
1766 handle_stobj (cfg
, bb
, inst
, load
, NULL
, inst
->klass
, TRUE
, FALSE
, FALSE
);
1768 inst
->cil_code
= NULL
;
1769 mono_add_ins_to_end (bb
, inst
);
1774 * We try to share variables when possible
1777 mono_compile_get_interface_var (MonoCompile
*cfg
, int slot
, MonoInst
*ins
)
1782 /* inlining can result in deeper stacks */
1783 if (slot
>= mono_method_get_header (cfg
->method
)->max_stack
)
1784 return mono_compile_create_var (cfg
, type_from_stack_type (ins
), OP_LOCAL
);
1786 pos
= ins
->type
- 1 + slot
* STACK_MAX
;
1788 switch (ins
->type
) {
1795 if ((vnum
= cfg
->intvars
[pos
]))
1796 return cfg
->varinfo
[vnum
];
1797 res
= mono_compile_create_var (cfg
, type_from_stack_type (ins
), OP_LOCAL
);
1798 cfg
->intvars
[pos
] = res
->inst_c0
;
1801 res
= mono_compile_create_var (cfg
, type_from_stack_type (ins
), OP_LOCAL
);
1809 * Merge stack state between two basic blocks according to Ecma 335, Partition III,
1810 * section 1.8.1.1. Store the resulting stack state into stack_2.
1811 * Returns: TRUE, if verification succeeds, FALSE otherwise.
1812 * FIXME: We should store the stack state in a dedicated structure instead of in
1816 merge_stacks (MonoCompile
*cfg
, MonoStackSlot
*state_1
, MonoStackSlot
*state_2
, guint32 size
)
1820 if (cfg
->dont_verify_stack_merge
)
1823 /* FIXME: Implement all checks from the spec */
1825 for (i
= 0; i
< size
; ++i
) {
1826 MonoStackSlot
*slot1
= &state_1
[i
];
1827 MonoStackSlot
*slot2
= &state_2
[i
];
1829 if (slot1
->type
!= slot2
->type
)
1832 switch (slot1
->type
) {
1834 /* FIXME: Perform merge ? */
1835 /* klass == NULL means a native int */
1836 if (slot1
->klass
&& slot2
->klass
) {
1837 if (slot1
->klass
!= slot2
->klass
)
1842 /* FIXME: Change this to an assert and fix the JIT to allways fill this */
1843 if (slot1
->klass
&& slot2
->klass
) {
1844 if (slot1
->klass
!= slot2
->klass
)
1849 MonoClass
*klass1
= slot1
->klass
;
1850 MonoClass
*klass2
= slot2
->klass
;
1853 /* slot1 is ldnull */
1854 } else if (!klass2
) {
1855 /* slot2 is ldnull */
1856 slot2
->klass
= slot1
->klass
;
1867 * This function is called to handle items that are left on the evaluation stack
1868 * at basic block boundaries. What happens is that we save the values to local variables
1869 * and we reload them later when first entering the target basic block (with the
1870 * handle_loaded_temps () function).
1871 * It is also used to handle items on the stack in store opcodes, since it is
1872 * possible that the variable to be stored into is already on the stack, in
1873 * which case its old value should be used.
1874 * A single joint point will use the same variables (stored in the array bb->out_stack or
1875 * bb->in_stack, if the basic block is before or after the joint point).
1876 * If the stack merge fails at a join point, cfg->unverifiable is set.
1879 handle_stack_args (MonoCompile
*cfg
, MonoBasicBlock
*bb
, MonoInst
**sp
, int count
) {
1881 MonoBasicBlock
*outb
;
1882 MonoInst
*inst
, **locals
;
1883 MonoStackSlot
*stack_state
;
1888 if (cfg
->verbose_level
> 3)
1889 g_print ("%d item(s) on exit from B%d\n", count
, bb
->block_num
);
1891 stack_state
= mono_mempool_alloc (cfg
->mempool
, sizeof (MonoStackSlot
) * count
);
1892 for (i
= 0; i
< count
; ++i
) {
1893 stack_state
[i
].type
= sp
[i
]->type
;
1894 stack_state
[i
].klass
= sp
[i
]->klass
;
1896 /* Check that instructions other than ldnull have ins->klass set */
1897 if (!cfg
->dont_verify_stack_merge
&& (sp
[i
]->type
== STACK_OBJ
) && !((sp
[i
]->opcode
== OP_PCONST
) && sp
[i
]->inst_c0
== 0))
1898 g_assert (sp
[i
]->klass
);
1901 /* Perform verification and stack state merge */
1902 for (i
= 0; i
< bb
->out_count
; ++i
) {
1903 outb
= bb
->out_bb
[i
];
1905 /* exception handlers are linked, but they should not be considered for stack args */
1906 if (outb
->flags
& BB_EXCEPTION_HANDLER
)
1908 if (outb
->stack_state
) {
1911 if (count
!= outb
->in_scount
) {
1912 cfg
->unverifiable
= TRUE
;
1915 verified
= merge_stacks (cfg
, stack_state
, outb
->stack_state
, count
);
1917 cfg
->unverifiable
= TRUE
;
1921 if (cfg
->verbose_level
> 3) {
1924 for (j
= 0; j
< count
; ++j
)
1925 printf ("\tStack state of BB%d, slot %d=%d\n", outb
->block_num
, j
, outb
->stack_state
[j
].type
);
1928 /* Make a copy of the stack state */
1929 outb
->stack_state
= mono_mempool_alloc (cfg
->mempool
, sizeof (MonoStackSlot
) * count
);
1930 memcpy (outb
->stack_state
, stack_state
, sizeof (MonoStackSlot
) * count
);
1934 if (!bb
->out_scount
) {
1935 bb
->out_scount
= count
;
1936 //g_print ("bblock %d has out:", bb->block_num);
1938 for (i
= 0; i
< bb
->out_count
; ++i
) {
1939 outb
= bb
->out_bb
[i
];
1940 /* exception handlers are linked, but they should not be considered for stack args */
1941 if (outb
->flags
& BB_EXCEPTION_HANDLER
)
1943 //g_print (" %d", outb->block_num);
1944 if (outb
->in_stack
) {
1946 bb
->out_stack
= outb
->in_stack
;
1952 bb
->out_stack
= mono_mempool_alloc (cfg
->mempool
, sizeof (MonoInst
*) * count
);
1953 for (i
= 0; i
< count
; ++i
) {
1955 * try to reuse temps already allocated for this purpouse, if they occupy the same
1956 * stack slot and if they are of the same type.
1957 * This won't cause conflicts since if 'local' is used to
1958 * store one of the values in the in_stack of a bblock, then
1959 * the same variable will be used for the same outgoing stack
1961 * This doesn't work when inlining methods, since the bblocks
1962 * in the inlined methods do not inherit their in_stack from
1963 * the bblock they are inlined to. See bug #58863 for an
1966 if (cfg
->inlined_method
)
1967 bb
->out_stack
[i
] = mono_compile_create_var (cfg
, type_from_stack_type (sp
[i
]), OP_LOCAL
);
1969 bb
->out_stack
[i
] = mono_compile_get_interface_var (cfg
, i
, sp
[i
]);
1974 for (i
= 0; i
< bb
->out_count
; ++i
) {
1975 outb
= bb
->out_bb
[i
];
1976 /* exception handlers are linked, but they should not be considered for stack args */
1977 if (outb
->flags
& BB_EXCEPTION_HANDLER
)
1979 if (outb
->in_scount
) {
1980 if (outb
->in_scount
!= bb
->out_scount
)
1982 continue; /* check they are the same locals */
1984 outb
->in_scount
= count
;
1985 outb
->in_stack
= bb
->out_stack
;
1988 locals
= bb
->out_stack
;
1989 for (i
= 0; i
< count
; ++i
) {
1990 /* add store ops at the end of the bb, before the branch */
1991 NEW_TEMPSTORE (cfg
, inst
, locals
[i
]->inst_c0
, sp
[i
]);
1992 if (inst
->opcode
== CEE_STOBJ
) {
1993 NEW_TEMPLOADA (cfg
, inst
, locals
[i
]->inst_c0
);
1994 handle_stobj (cfg
, bb
, inst
, sp
[i
], sp
[i
]->cil_code
, inst
->klass
, TRUE
, FALSE
, FALSE
);
1996 inst
->cil_code
= sp
[i
]->cil_code
;
1997 mono_add_ins_to_end (bb
, inst
);
1999 if (cfg
->verbose_level
> 3)
2000 g_print ("storing %d to temp %d\n", i
, (int)locals
[i
]->inst_c0
);
2004 * It is possible that the out bblocks already have in_stack assigned, and
2005 * the in_stacks differ. In this case, we will store to all the different
2012 /* Find a bblock which has a different in_stack */
2014 while (bindex
< bb
->out_count
) {
2015 outb
= bb
->out_bb
[bindex
];
2016 /* exception handlers are linked, but they should not be considered for stack args */
2017 if (outb
->flags
& BB_EXCEPTION_HANDLER
) {
2021 if (outb
->in_stack
!= locals
) {
2023 * Instead of storing sp [i] to locals [i], we need to store
2024 * locals [i] to <new locals>[i], since the sp [i] tree can't
2025 * be shared between trees.
2027 for (i
= 0; i
< count
; ++i
)
2028 mono_add_varcopy_to_end (cfg
, bb
, locals
[i
]->inst_c0
, outb
->in_stack
[i
]->inst_c0
);
2029 locals
= outb
->in_stack
;
2041 ret_type_to_call_opcode (MonoType
*type
, int calli
, int virt
)
2044 return calli
? OP_CALL_REG
: virt
? CEE_CALLVIRT
: CEE_CALL
;
2047 switch (type
->type
) {
2048 case MONO_TYPE_VOID
:
2049 return calli
? OP_VOIDCALL_REG
: virt
? OP_VOIDCALLVIRT
: OP_VOIDCALL
;
2052 case MONO_TYPE_BOOLEAN
:
2055 case MONO_TYPE_CHAR
:
2058 return calli
? OP_CALL_REG
: virt
? CEE_CALLVIRT
: CEE_CALL
;
2062 case MONO_TYPE_FNPTR
:
2063 return calli
? OP_CALL_REG
: virt
? CEE_CALLVIRT
: CEE_CALL
;
2064 case MONO_TYPE_CLASS
:
2065 case MONO_TYPE_STRING
:
2066 case MONO_TYPE_OBJECT
:
2067 case MONO_TYPE_SZARRAY
:
2068 case MONO_TYPE_ARRAY
:
2069 return calli
? OP_CALL_REG
: virt
? CEE_CALLVIRT
: CEE_CALL
;
2072 return calli
? OP_LCALL_REG
: virt
? OP_LCALLVIRT
: OP_LCALL
;
2075 return calli
? OP_FCALL_REG
: virt
? OP_FCALLVIRT
: OP_FCALL
;
2076 case MONO_TYPE_VALUETYPE
:
2077 if (type
->data
.klass
->enumtype
) {
2078 type
= type
->data
.klass
->enum_basetype
;
2081 return calli
? OP_VCALL_REG
: virt
? OP_VCALLVIRT
: OP_VCALL
;
2082 case MONO_TYPE_TYPEDBYREF
:
2083 return calli
? OP_VCALL_REG
: virt
? OP_VCALLVIRT
: OP_VCALL
;
2084 case MONO_TYPE_GENERICINST
:
2085 type
= &type
->data
.generic_class
->container_class
->byval_arg
;
2088 g_error ("unknown type 0x%02x in ret_type_to_call_opcode", type
->type
);
2094 mono_create_jump_table (MonoCompile
*cfg
, MonoInst
*label
, MonoBasicBlock
**bbs
, int num_blocks
)
2096 MonoJumpInfo
*ji
= mono_mempool_alloc (cfg
->mempool
, sizeof (MonoJumpInfo
));
2097 MonoJumpInfoBBTable
*table
;
2099 table
= mono_mempool_alloc (cfg
->mempool
, sizeof (MonoJumpInfoBBTable
));
2101 table
->table_size
= num_blocks
;
2103 ji
->ip
.label
= label
;
2104 ji
->type
= MONO_PATCH_INFO_SWITCH
;
2105 ji
->data
.table
= table
;
2106 ji
->next
= cfg
->patch_info
;
2107 cfg
->patch_info
= ji
;
2111 * When we add a tree of instructions, we need to ensure the instructions currently
2112 * on the stack are executed before (like, if we load a value from a local).
2113 * We ensure this by saving the currently loaded values to temps and rewriting the
2114 * instructions to load the values.
2115 * This is not done for opcodes that terminate a basic block (because it's handled already
2116 * by handle_stack_args ()) and for opcodes that can't change values, like POP.
2119 handle_loaded_temps (MonoCompile
*cfg
, MonoBasicBlock
*bblock
, MonoInst
**stack
, MonoInst
**sp
)
2121 MonoInst
*load
, *store
, *temp
, *ins
;
2123 while (stack
< sp
) {
2125 /* handle also other constants */
2126 if ((ins
->opcode
!= OP_ICONST
) &&
2127 /* temps never get written to again, so we can safely avoid duplicating them */
2128 !(ins
->ssa_op
== MONO_SSA_LOAD
&& ins
->inst_i0
->opcode
== OP_LOCAL
&& ins
->inst_i0
->flags
& MONO_INST_IS_TEMP
)) {
2129 temp
= mono_compile_create_var (cfg
, type_from_stack_type (ins
), OP_LOCAL
);
2130 temp
->flags
|= MONO_INST_IS_TEMP
;
2131 NEW_TEMPSTORE (cfg
, store
, temp
->inst_c0
, ins
);
2132 store
->cil_code
= ins
->cil_code
;
2133 if (store
->opcode
== CEE_STOBJ
) {
2134 NEW_TEMPLOADA (cfg
, store
, temp
->inst_c0
);
2135 handle_stobj (cfg
, bblock
, store
, ins
, ins
->cil_code
, temp
->klass
, FALSE
, FALSE
, FALSE
);
2137 MONO_ADD_INS (bblock
, store
);
2138 NEW_TEMPLOAD (cfg
, load
, temp
->inst_c0
);
2139 load
->cil_code
= ins
->cil_code
;
2147 * target_type_is_incompatible:
2148 * @cfg: MonoCompile context
2150 * Check that the item @arg on the evaluation stack can be stored
2151 * in the target type (can be a local, or field, etc).
2152 * The cfg arg can be used to check if we need verification or just
2155 * Returns: non-0 value if arg can't be stored on a target.
2158 target_type_is_incompatible (MonoCompile
*cfg
, MonoType
*target
, MonoInst
*arg
)
2160 MonoType
*simple_type
;
2163 if (target
->byref
) {
2164 /* FIXME: check that the pointed to types match */
2165 if (arg
->type
== STACK_MP
)
2166 return arg
->klass
!= mono_class_from_mono_type (target
);
2167 if (arg
->type
== STACK_PTR
)
2171 simple_type
= mono_type_get_underlying_type (target
);
2172 switch (simple_type
->type
) {
2173 case MONO_TYPE_VOID
:
2177 case MONO_TYPE_BOOLEAN
:
2180 case MONO_TYPE_CHAR
:
2183 if (arg
->type
!= STACK_I4
&& arg
->type
!= STACK_PTR
)
2187 /* STACK_MP is needed when setting pinned locals */
2188 if (arg
->type
!= STACK_I4
&& arg
->type
!= STACK_PTR
&& arg
->type
!= STACK_MP
)
2193 case MONO_TYPE_FNPTR
:
2194 if (arg
->type
!= STACK_I4
&& arg
->type
!= STACK_PTR
)
2197 case MONO_TYPE_CLASS
:
2198 case MONO_TYPE_STRING
:
2199 case MONO_TYPE_OBJECT
:
2200 case MONO_TYPE_SZARRAY
:
2201 case MONO_TYPE_ARRAY
:
2202 if (arg
->type
!= STACK_OBJ
)
2204 /* FIXME: check type compatibility */
2208 if (arg
->type
!= STACK_I8
)
2213 if (arg
->type
!= STACK_R8
)
2216 case MONO_TYPE_VALUETYPE
:
2217 if (arg
->type
!= STACK_VTYPE
)
2219 klass
= mono_class_from_mono_type (simple_type
);
2220 if (klass
!= arg
->klass
)
2223 case MONO_TYPE_TYPEDBYREF
:
2224 if (arg
->type
!= STACK_VTYPE
)
2226 klass
= mono_class_from_mono_type (simple_type
);
2227 if (klass
!= arg
->klass
)
2230 case MONO_TYPE_GENERICINST
:
2231 if (mono_type_generic_inst_is_valuetype (simple_type
)) {
2232 if (arg
->type
!= STACK_VTYPE
)
2234 klass
= mono_class_from_mono_type (simple_type
);
2235 if (klass
!= arg
->klass
)
2239 if (arg
->type
!= STACK_OBJ
)
2241 /* FIXME: check type compatibility */
2245 g_error ("unknown type 0x%02x in target_type_is_incompatible", simple_type
->type
);
2251 * Prepare arguments for passing to a function call.
2252 * Return a non-zero value if the arguments can't be passed to the given
2254 * The type checks are not yet complete and some conversions may need
2255 * casts on 32 or 64 bit architectures.
2257 * FIXME: implement this using target_type_is_incompatible ()
2260 check_call_signature (MonoCompile
*cfg
, MonoMethodSignature
*sig
, MonoInst
**args
)
2262 MonoType
*simple_type
;
2266 if (args
[0]->type
!= STACK_OBJ
&& args
[0]->type
!= STACK_MP
&& args
[0]->type
!= STACK_PTR
)
2270 for (i
= 0; i
< sig
->param_count
; ++i
) {
2271 if (sig
->params
[i
]->byref
) {
2272 if (args
[i
]->type
!= STACK_MP
&& args
[i
]->type
!= STACK_PTR
)
2276 simple_type
= sig
->params
[i
];
2278 switch (simple_type
->type
) {
2279 case MONO_TYPE_VOID
:
2284 case MONO_TYPE_BOOLEAN
:
2287 case MONO_TYPE_CHAR
:
2290 if (args
[i
]->type
!= STACK_I4
&& args
[i
]->type
!= STACK_PTR
)
2296 case MONO_TYPE_FNPTR
:
2297 if (args
[i
]->type
!= STACK_I4
&& args
[i
]->type
!= STACK_PTR
&& args
[i
]->type
!= STACK_MP
&& args
[i
]->type
!= STACK_OBJ
)
2300 case MONO_TYPE_CLASS
:
2301 case MONO_TYPE_STRING
:
2302 case MONO_TYPE_OBJECT
:
2303 case MONO_TYPE_SZARRAY
:
2304 case MONO_TYPE_ARRAY
:
2305 if (args
[i
]->type
!= STACK_OBJ
)
2310 if (args
[i
]->type
!= STACK_I8
)
2315 if (args
[i
]->type
!= STACK_R8
)
2318 case MONO_TYPE_VALUETYPE
:
2319 if (simple_type
->data
.klass
->enumtype
) {
2320 simple_type
= simple_type
->data
.klass
->enum_basetype
;
2323 if (args
[i
]->type
!= STACK_VTYPE
)
2326 case MONO_TYPE_TYPEDBYREF
:
2327 if (args
[i
]->type
!= STACK_VTYPE
)
2330 case MONO_TYPE_GENERICINST
:
2331 simple_type
= &simple_type
->data
.generic_class
->container_class
->byval_arg
;
2335 g_error ("unknown type 0x%02x in check_call_signature",
2343 mono_spill_call (MonoCompile
*cfg
, MonoBasicBlock
*bblock
, MonoCallInst
*call
, MonoMethodSignature
*sig
, gboolean ret_object
,
2344 const guint8
*ip
, gboolean to_end
)
2346 MonoInst
*temp
, *store
, *ins
= (MonoInst
*)call
;
2347 MonoType
*ret
= sig
->ret
;
2349 if (!MONO_TYPE_IS_VOID (ret
) || ret_object
) {
2351 call
->inst
.type
= STACK_OBJ
;
2352 call
->inst
.opcode
= CEE_CALL
;
2353 temp
= mono_compile_create_var (cfg
, &mono_defaults
.string_class
->byval_arg
, OP_LOCAL
);
2355 type_to_eval_stack_type (ret
, ins
);
2356 temp
= mono_compile_create_var (cfg
, ret
, OP_LOCAL
);
2359 temp
->flags
|= MONO_INST_IS_TEMP
;
2361 if (MONO_TYPE_ISSTRUCT (ret
)) {
2362 MonoInst
*loada
, *dummy_store
;
2365 * Emit a dummy store to the local holding the result so the
2366 * liveness info remains correct.
2368 NEW_DUMMY_STORE (cfg
, dummy_store
, temp
->inst_c0
);
2370 mono_add_ins_to_end (bblock
, dummy_store
);
2372 MONO_ADD_INS (bblock
, dummy_store
);
2374 /* we use this to allocate native sized structs */
2375 temp
->backend
.is_pinvoke
= sig
->pinvoke
;
2377 NEW_TEMPLOADA (cfg
, loada
, temp
->inst_c0
);
2378 if (call
->inst
.opcode
== OP_VCALL
)
2379 ins
->inst_left
= loada
;
2381 ins
->inst_right
= loada
; /* a virtual or indirect call */
2384 mono_add_ins_to_end (bblock
, ins
);
2386 MONO_ADD_INS (bblock
, ins
);
2388 NEW_TEMPSTORE (cfg
, store
, temp
->inst_c0
, ins
);
2389 store
->cil_code
= ip
;
2391 mono_add_ins_to_end (bblock
, store
);
2393 MONO_ADD_INS (bblock
, store
);
2395 return temp
->inst_c0
;
2398 mono_add_ins_to_end (bblock
, ins
);
2400 MONO_ADD_INS (bblock
, ins
);
2405 inline static MonoCallInst
*
2406 mono_emit_call_args (MonoCompile
*cfg
, MonoBasicBlock
*bblock
, MonoMethodSignature
*sig
,
2407 MonoInst
**args
, int calli
, int virtual, const guint8
*ip
, gboolean to_end
)
2412 MONO_INST_NEW_CALL (cfg
, call
, ret_type_to_call_opcode (sig
->ret
, calli
, virtual));
2414 call
->inst
.cil_code
= ip
;
2416 call
->signature
= sig
;
2417 call
= mono_arch_call_opcode (cfg
, bblock
, call
, virtual);
2418 type_to_eval_stack_type (sig
->ret
, &call
->inst
);
2420 for (arg
= call
->out_args
; arg
;) {
2421 MonoInst
*narg
= arg
->next
;
2426 mono_add_ins_to_end (bblock
, arg
);
2428 MONO_ADD_INS (bblock
, arg
);
2435 mono_emit_calli (MonoCompile
*cfg
, MonoBasicBlock
*bblock
, MonoMethodSignature
*sig
,
2436 MonoInst
**args
, MonoInst
*addr
, const guint8
*ip
)
2438 MonoCallInst
*call
= mono_emit_call_args (cfg
, bblock
, sig
, args
, TRUE
, FALSE
, ip
, FALSE
);
2440 call
->inst
.inst_i0
= addr
;
2442 return mono_spill_call (cfg
, bblock
, call
, sig
, FALSE
, ip
, FALSE
);
2445 static MonoCallInst
*
2446 mono_emit_method_call_full (MonoCompile
*cfg
, MonoBasicBlock
*bblock
, MonoMethod
*method
, MonoMethodSignature
*sig
,
2447 MonoInst
**args
, const guint8
*ip
, MonoInst
*this, gboolean to_end
)
2449 gboolean
virtual = this != NULL
;
2452 call
= mono_emit_call_args (cfg
, bblock
, sig
, args
, FALSE
, virtual, ip
, to_end
);
2454 if (this && sig
->hasthis
&&
2455 (method
->klass
->marshalbyref
|| method
->klass
== mono_defaults
.object_class
) &&
2456 !(method
->flags
& METHOD_ATTRIBUTE_VIRTUAL
) && !MONO_CHECK_THIS (this)) {
2457 call
->method
= mono_marshal_get_remoting_invoke_with_check (method
);
2459 call
->method
= method
;
2461 call
->inst
.flags
|= MONO_INST_HAS_METHOD
;
2462 call
->inst
.inst_left
= this;
2464 if (call
->method
->klass
->flags
& TYPE_ATTRIBUTE_INTERFACE
)
2465 /* Needed by the code generated in inssel.brg */
2466 mono_get_got_var (cfg
);
2471 static MonoCallInst
*
2472 mono_emit_method_call (MonoCompile
*cfg
, MonoBasicBlock
*bblock
, MonoMethod
*method
, MonoMethodSignature
*sig
,
2473 MonoInst
**args
, const guint8
*ip
, MonoInst
*this)
2475 return mono_emit_method_call_full (cfg
, bblock
, method
, sig
, args
, ip
, this, FALSE
);
2479 mono_emit_method_call_spilled (MonoCompile
*cfg
, MonoBasicBlock
*bblock
, MonoMethod
*method
,
2480 MonoMethodSignature
*signature
, MonoInst
**args
, const guint8
*ip
, MonoInst
*this)
2482 MonoCallInst
*call
= mono_emit_method_call (cfg
, bblock
, method
, signature
, args
, ip
, this);
2484 return mono_spill_call (cfg
, bblock
, call
, signature
, method
->string_ctor
, ip
, FALSE
);
2488 mono_emit_method_call_spilled_full (MonoCompile
*cfg
, MonoBasicBlock
*bblock
, MonoMethod
*method
,
2489 MonoMethodSignature
*signature
, MonoInst
**args
, const guint8
*ip
, MonoInst
*this,
2490 gboolean ret_object
, gboolean to_end
)
2492 MonoCallInst
*call
= mono_emit_method_call_full (cfg
, bblock
, method
, signature
, args
, ip
, this, to_end
);
2494 return mono_spill_call (cfg
, bblock
, call
, signature
, ret_object
, ip
, to_end
);
2498 mono_emit_native_call (MonoCompile
*cfg
, MonoBasicBlock
*bblock
, gconstpointer func
, MonoMethodSignature
*sig
,
2499 MonoInst
**args
, const guint8
*ip
, gboolean ret_object
, gboolean to_end
)
2505 call
= mono_emit_call_args (cfg
, bblock
, sig
, args
, FALSE
, FALSE
, ip
, to_end
);
2508 return mono_spill_call (cfg
, bblock
, call
, sig
, ret_object
, ip
, to_end
);
2512 mono_emit_jit_icall (MonoCompile
*cfg
, MonoBasicBlock
*bblock
, gconstpointer func
, MonoInst
**args
, const guint8
*ip
)
2514 MonoJitICallInfo
*info
= mono_find_jit_icall_by_addr (func
);
2517 g_warning ("unregistered JIT ICall");
2518 g_assert_not_reached ();
2521 return mono_emit_native_call (cfg
, bblock
, mono_icall_get_wrapper (info
), info
->sig
, args
, ip
, FALSE
, FALSE
);
2525 mono_emulate_opcode (MonoCompile
*cfg
, MonoInst
*tree
, MonoInst
**iargs
, MonoJitICallInfo
*info
)
2527 MonoInst
*ins
, *temp
= NULL
, *store
, *load
, *begin
;
2528 MonoInst
*last_arg
= NULL
;
2532 //g_print ("emulating: ");
2533 //mono_print_tree_nl (tree);
2534 MONO_INST_NEW_CALL (cfg
, call
, ret_type_to_call_opcode (info
->sig
->ret
, FALSE
, FALSE
));
2535 ins
= (MonoInst
*)call
;
2537 call
->inst
.cil_code
= tree
->cil_code
;
2539 call
->signature
= info
->sig
;
2541 call
= mono_arch_call_opcode (cfg
, cfg
->cbb
, call
, FALSE
);
2543 if (!MONO_TYPE_IS_VOID (info
->sig
->ret
)) {
2544 temp
= mono_compile_create_var (cfg
, info
->sig
->ret
, OP_LOCAL
);
2545 temp
->flags
|= MONO_INST_IS_TEMP
;
2546 NEW_TEMPSTORE (cfg
, store
, temp
->inst_c0
, ins
);
2547 store
->cil_code
= tree
->cil_code
;
2552 nargs
= info
->sig
->param_count
+ info
->sig
->hasthis
;
2554 for (last_arg
= call
->out_args
; last_arg
&& last_arg
->next
; last_arg
= last_arg
->next
) ;
2557 last_arg
->next
= store
;
2560 begin
= call
->out_args
;
2564 if (cfg
->prev_ins
) {
2566 * This assumes that that in a tree, emulate_opcode is called for a
2567 * node before it is called for its children. dec_foreach needs to
2568 * take this into account.
2570 store
->next
= cfg
->prev_ins
->next
;
2571 cfg
->prev_ins
->next
= begin
;
2573 store
->next
= cfg
->cbb
->code
;
2574 cfg
->cbb
->code
= begin
;
2577 call
->fptr
= mono_icall_get_wrapper (info
);
2579 if (!MONO_TYPE_IS_VOID (info
->sig
->ret
)) {
2580 NEW_TEMPLOAD (cfg
, load
, temp
->inst_c0
);
2585 static MonoMethodSignature
*
2586 mono_get_element_address_signature (int arity
)
2588 static GHashTable
*sighash
= NULL
;
2589 MonoMethodSignature
*res
;
2594 sighash
= g_hash_table_new (NULL
, NULL
);
2596 else if ((res
= g_hash_table_lookup (sighash
, GINT_TO_POINTER (arity
)))) {
2597 LeaveCriticalSection (&jit_mutex
);
2601 res
= mono_metadata_signature_alloc (mono_defaults
.corlib
, arity
+ 1);
2604 #ifdef MONO_ARCH_VARARG_ICALLS
2605 /* Only set this only some archs since not all backends can handle varargs+pinvoke */
2606 res
->call_convention
= MONO_CALL_VARARG
;
2608 res
->params
[0] = &mono_defaults
.array_class
->byval_arg
;
2610 #ifdef PLATFORM_WIN32
2612 * The default pinvoke calling convention is STDCALL but we need CDECL.
2614 res
->call_convention
= MONO_CALL_C
;
2617 for (i
= 1; i
<= arity
; i
++)
2618 res
->params
[i
] = &mono_defaults
.int_class
->byval_arg
;
2620 res
->ret
= &mono_defaults
.int_class
->byval_arg
;
2622 g_hash_table_insert (sighash
, GINT_TO_POINTER (arity
), res
);
2628 static MonoMethodSignature
*
2629 mono_get_array_new_va_signature (int arity
)
2631 static GHashTable
*sighash
= NULL
;
2632 MonoMethodSignature
*res
;
2637 sighash
= g_hash_table_new (NULL
, NULL
);
2639 else if ((res
= g_hash_table_lookup (sighash
, GINT_TO_POINTER (arity
)))) {
2644 res
= mono_metadata_signature_alloc (mono_defaults
.corlib
, arity
+ 1);
2647 #ifdef MONO_ARCH_VARARG_ICALLS
2648 /* Only set this only some archs since not all backends can handle varargs+pinvoke */
2649 res
->call_convention
= MONO_CALL_VARARG
;
2652 #ifdef PLATFORM_WIN32
2653 res
->call_convention
= MONO_CALL_C
;
2656 res
->params
[0] = &mono_defaults
.int_class
->byval_arg
;
2657 for (i
= 0; i
< arity
; i
++)
2658 res
->params
[i
+ 1] = &mono_defaults
.int_class
->byval_arg
;
2660 res
->ret
= &mono_defaults
.int_class
->byval_arg
;
2662 g_hash_table_insert (sighash
, GINT_TO_POINTER (arity
), res
);
2668 #ifdef MONO_ARCH_SOFT_FLOAT
2670 handle_store_float (MonoCompile
*cfg
, MonoBasicBlock
*bblock
, MonoInst
*ptr
, MonoInst
*val
, const unsigned char *ip
)
2672 MonoInst
*iargs
[2];
2676 mono_emit_jit_icall (cfg
, bblock
, mono_fstore_r4
, iargs
, ip
);
2680 handle_load_float (MonoCompile
*cfg
, MonoBasicBlock
*bblock
, MonoInst
*ptr
, const unsigned char *ip
)
2682 MonoInst
*iargs
[1];
2685 return mono_emit_jit_icall (cfg
, bblock
, mono_fload_r4
, iargs
, ip
);
2688 #define LDLOC_SOFT_FLOAT(cfg,ins,idx,ip) do {\
2689 if (header->locals [(idx)]->type == MONO_TYPE_R4) { \
2691 NEW_LOCLOADA (cfg, (ins), (idx)); \
2692 temp = handle_load_float (cfg, bblock, (ins), (ip)); \
2693 NEW_TEMPLOAD (cfg, (ins), temp); \
2696 #define STLOC_SOFT_FLOAT(cfg,ins,idx,ip) do {\
2697 if (header->locals [(idx)]->type == MONO_TYPE_R4) { \
2699 NEW_LOCLOADA (cfg, (ins), (idx)); \
2700 handle_store_float (cfg, bblock, (ins), *sp, (ip)); \
2701 MONO_INST_NEW (cfg, (ins), CEE_NOP); \
2704 #define LDARG_SOFT_FLOAT(cfg,ins,idx,ip) do {\
2705 if (param_types [(idx)]->type == MONO_TYPE_R4) { \
2707 NEW_ARGLOADA (cfg, (ins), (idx)); \
2708 temp = handle_load_float (cfg, bblock, (ins), (ip)); \
2709 NEW_TEMPLOAD (cfg, (ins), temp); \
2713 #define LDLOC_SOFT_FLOAT(cfg,ins,idx,ip)
2714 #define STLOC_SOFT_FLOAT(cfg,ins,idx,ip)
2715 #define LDARG_SOFT_FLOAT(cfg,ins,idx,ip)
2719 get_memcpy_method (void)
2721 static MonoMethod
*memcpy_method
= NULL
;
2722 if (!memcpy_method
) {
2723 memcpy_method
= mono_class_get_method_from_name (mono_defaults
.string_class
, "memcpy", 3);
2725 g_error ("Old corlib found. Install a new one");
2727 return memcpy_method
;
2731 handle_stobj (MonoCompile
*cfg
, MonoBasicBlock
*bblock
, MonoInst
*dest
, MonoInst
*src
, const unsigned char *ip
, MonoClass
*klass
, gboolean to_end
, gboolean native
, gboolean write_barrier
) {
2732 MonoInst
*iargs
[3];
2735 MonoMethod
*memcpy_method
;
2739 * This check breaks with spilled vars... need to handle it during verification anyway.
2740 * g_assert (klass && klass == src->klass && klass == dest->klass);
2744 n
= mono_class_native_size (klass
, &align
);
2746 n
= mono_class_value_size (klass
, &align
);
2748 #if HAVE_WRITE_BARRIERS
2749 /* if native is true there should be no references in the struct */
2750 if (write_barrier
&& klass
->has_references
&& !native
) {
2753 NEW_PCONST (cfg
, iargs
[2], klass
);
2755 mono_emit_jit_icall (cfg
, bblock
, mono_value_copy
, iargs
, ip
);
2760 /* FIXME: add write barrier handling */
2761 if ((cfg
->opt
& MONO_OPT_INTRINS
) && !to_end
&& n
<= sizeof (gpointer
) * 5) {
2763 if (dest
->opcode
== OP_LDADDR
) {
2764 /* Keep liveness info correct */
2765 NEW_DUMMY_STORE (cfg
, inst
, dest
->inst_i0
->inst_c0
);
2766 MONO_ADD_INS (bblock
, inst
);
2768 MONO_INST_NEW (cfg
, inst
, OP_MEMCPY
);
2769 inst
->inst_left
= dest
;
2770 inst
->inst_right
= src
;
2771 inst
->cil_code
= ip
;
2772 inst
->backend
.size
= n
;
2773 MONO_ADD_INS (bblock
, inst
);
2778 NEW_ICONST (cfg
, iargs
[2], n
);
2780 memcpy_method
= get_memcpy_method ();
2781 mono_emit_method_call_spilled_full (cfg
, bblock
, memcpy_method
, memcpy_method
->signature
, iargs
, ip
, NULL
, FALSE
, to_end
);
2785 get_memset_method (void)
2787 static MonoMethod
*memset_method
= NULL
;
2788 if (!memset_method
) {
2789 memset_method
= mono_class_get_method_from_name (mono_defaults
.string_class
, "memset", 3);
2791 g_error ("Old corlib found. Install a new one");
2793 return memset_method
;
2797 handle_initobj (MonoCompile
*cfg
, MonoBasicBlock
*bblock
, MonoInst
*dest
, const guchar
*ip
, MonoClass
*klass
, MonoInst
**stack_start
, MonoInst
**sp
)
2799 MonoInst
*iargs
[3];
2800 MonoInst
*ins
, *zero_int32
;
2802 MonoMethod
*memset_method
;
2804 NEW_ICONST (cfg
, zero_int32
, 0);
2806 mono_class_init (klass
);
2807 n
= mono_class_value_size (klass
, NULL
);
2808 MONO_INST_NEW (cfg
, ins
, 0);
2810 ins
->inst_left
= dest
;
2811 ins
->inst_right
= zero_int32
;
2814 ins
->opcode
= CEE_STIND_I1
;
2815 MONO_ADD_INS (bblock
, ins
);
2818 ins
->opcode
= CEE_STIND_I2
;
2819 MONO_ADD_INS (bblock
, ins
);
2822 ins
->opcode
= CEE_STIND_I4
;
2823 MONO_ADD_INS (bblock
, ins
);
2826 if (n
<= sizeof (gpointer
) * 5) {
2827 ins
->opcode
= OP_MEMSET
;
2829 ins
->backend
.size
= n
;
2830 MONO_ADD_INS (bblock
, ins
);
2833 memset_method
= get_memset_method ();
2834 handle_loaded_temps (cfg
, bblock
, stack_start
, sp
);
2836 NEW_ICONST (cfg
, iargs
[1], 0);
2837 NEW_ICONST (cfg
, iargs
[2], n
);
2838 mono_emit_method_call_spilled (cfg
, bblock
, memset_method
, memset_method
->signature
, iargs
, ip
, NULL
);
2844 handle_alloc (MonoCompile
*cfg
, MonoBasicBlock
*bblock
, MonoClass
*klass
, gboolean for_box
, const guchar
*ip
)
2846 MonoInst
*iargs
[2];
2849 if (cfg
->opt
& MONO_OPT_SHARED
) {
2850 NEW_DOMAINCONST (cfg
, iargs
[0]);
2851 NEW_CLASSCONST (cfg
, iargs
[1], klass
);
2853 alloc_ftn
= mono_object_new
;
2854 } else if (cfg
->compile_aot
&& bblock
->out_of_line
&& klass
->type_token
&& klass
->image
== mono_defaults
.corlib
) {
2855 /* This happens often in argument checking code, eg. throw new FooException... */
2856 /* Avoid relocations by calling a helper function specialized to mscorlib */
2857 NEW_ICONST (cfg
, iargs
[0], mono_metadata_token_index (klass
->type_token
));
2858 return mono_emit_jit_icall (cfg
, bblock
, mono_helper_newobj_mscorlib
, iargs
, ip
);
2860 MonoVTable
*vtable
= mono_class_vtable (cfg
->domain
, klass
);
2863 alloc_ftn
= mono_class_get_allocation_ftn (vtable
, for_box
, &pass_lw
);
2865 guint32 lw
= vtable
->klass
->instance_size
;
2866 lw
= ((lw
+ (sizeof (gpointer
) - 1)) & ~(sizeof (gpointer
) - 1)) / sizeof (gpointer
);
2867 NEW_ICONST (cfg
, iargs
[0], lw
);
2868 NEW_VTABLECONST (cfg
, iargs
[1], vtable
);
2871 NEW_VTABLECONST (cfg
, iargs
[0], vtable
);
2874 return mono_emit_jit_icall (cfg
, bblock
, alloc_ftn
, iargs
, ip
);
2878 * Handles unbox of a Nullable<T>, returning a temp variable
2879 * where the result is stored
2882 handle_unbox_nullable (MonoCompile
* cfg
, MonoBasicBlock
* bblock
, MonoInst
* val
, const guchar
*ip
, MonoClass
* klass
)
2884 MonoMethod
* method
= mono_class_get_method_from_name (klass
, "Unbox", 1);
2885 return mono_emit_method_call_spilled (cfg
, bblock
, method
, mono_method_signature (method
), &val
, ip
, NULL
);
2892 handle_box (MonoCompile
*cfg
, MonoBasicBlock
*bblock
, MonoInst
*val
, const guchar
*ip
, MonoClass
*klass
)
2894 MonoInst
*dest
, *vtoffset
, *add
, *vstore
;
2897 if (mono_class_is_nullable (klass
)) {
2898 MonoMethod
* method
= mono_class_get_method_from_name (klass
, "Box", 1);
2899 temp
= mono_emit_method_call_spilled (cfg
, bblock
, method
, mono_method_signature (method
), &val
, ip
, NULL
);
2900 NEW_TEMPLOAD (cfg
, dest
, temp
);
2905 temp
= handle_alloc (cfg
, bblock
, klass
, TRUE
, ip
);
2906 NEW_TEMPLOAD (cfg
, dest
, temp
);
2907 NEW_ICONST (cfg
, vtoffset
, sizeof (MonoObject
));
2908 MONO_INST_NEW (cfg
, add
, OP_PADD
);
2909 add
->inst_left
= dest
;
2910 add
->inst_right
= vtoffset
;
2913 MONO_INST_NEW (cfg
, vstore
, CEE_STIND_I
);
2914 vstore
->opcode
= mono_type_to_stind (&klass
->byval_arg
);
2915 vstore
->cil_code
= ip
;
2916 vstore
->inst_left
= add
;
2917 vstore
->inst_right
= val
;
2919 if (vstore
->opcode
== CEE_STOBJ
) {
2920 handle_stobj (cfg
, bblock
, add
, val
, ip
, klass
, FALSE
, FALSE
, TRUE
);
2922 MONO_ADD_INS (bblock
, vstore
);
2924 NEW_TEMPLOAD (cfg
, dest
, temp
);
2929 handle_array_new (MonoCompile
*cfg
, MonoBasicBlock
*bblock
, int rank
, MonoInst
**sp
, unsigned char *ip
)
2931 MonoMethodSignature
*esig
;
2932 char icall_name
[256];
2934 MonoJitICallInfo
*info
;
2936 /* Need to register the icall so it gets an icall wrapper */
2937 sprintf (icall_name
, "ves_array_new_va_%d", rank
);
2940 info
= mono_find_jit_icall_by_name (icall_name
);
2942 esig
= mono_get_array_new_va_signature (rank
);
2943 name
= g_strdup (icall_name
);
2944 info
= mono_register_jit_icall (mono_array_new_va
, name
, esig
, FALSE
);
2946 g_hash_table_insert (jit_icall_name_hash
, name
, name
);
2950 cfg
->flags
|= MONO_CFG_HAS_VARARGS
;
2952 /* FIXME: This uses info->sig, but it should use the signature of the wrapper */
2953 return mono_emit_native_call (cfg
, bblock
, mono_icall_get_wrapper (info
), info
->sig
, sp
, ip
, TRUE
, FALSE
);
2957 mono_emit_load_got_addr (MonoCompile
*cfg
)
2959 MonoInst
*load
, *store
, *dummy_use
;
2962 if (!cfg
->got_var
|| cfg
->got_var_allocated
)
2965 MONO_INST_NEW (cfg
, get_got
, OP_LOAD_GOTADDR
);
2966 NEW_TEMPSTORE (cfg
, store
, cfg
->got_var
->inst_c0
, get_got
);
2968 /* Add it to the start of the first bblock */
2969 if (cfg
->bb_entry
->code
) {
2970 store
->next
= cfg
->bb_entry
->code
;
2971 cfg
->bb_entry
->code
= store
;
2974 MONO_ADD_INS (cfg
->bb_entry
, store
);
2976 cfg
->got_var_allocated
= TRUE
;
2979 * Add a dummy use to keep the got_var alive, since real uses might
2980 * only be generated in the decompose or instruction selection phases.
2981 * Add it to end_bblock, so the variable's lifetime covers the whole
2984 NEW_TEMPLOAD (cfg
, load
, cfg
->got_var
->inst_c0
);
2985 NEW_DUMMY_USE (cfg
, dummy_use
, load
);
2986 MONO_ADD_INS (cfg
->bb_exit
, dummy_use
);
2989 #define CODE_IS_STLOC(ip) (((ip) [0] >= CEE_STLOC_0 && (ip) [0] <= CEE_STLOC_3) || ((ip) [0] == CEE_STLOC_S))
2992 mini_class_is_system_array (MonoClass
*klass
)
2994 if (klass
->parent
== mono_defaults
.array_class
)
3001 mono_method_check_inlining (MonoCompile
*cfg
, MonoMethod
*method
)
3003 MonoMethodHeader
*header
= mono_method_get_header (method
);
3004 MonoMethodSignature
*signature
= mono_method_signature (method
);
3008 #ifdef MONO_ARCH_HAVE_LMF_OPS
3009 if (((method
->iflags
& METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
) ||
3010 (method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
)) &&
3011 !MONO_TYPE_ISSTRUCT (signature
->ret
) && !mini_class_is_system_array (method
->klass
))
3015 if ((method
->iflags
& METHOD_IMPL_ATTRIBUTE_RUNTIME
) ||
3016 (method
->iflags
& METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
) ||
3017 (method
->iflags
& METHOD_IMPL_ATTRIBUTE_NOINLINING
) ||
3018 (method
->iflags
& METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED
) ||
3019 (method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
) ||
3020 (method
->klass
->marshalbyref
) ||
3021 !header
|| header
->num_clauses
||
3022 /* fixme: why cant we inline valuetype returns? */
3023 MONO_TYPE_ISSTRUCT (signature
->ret
))
3026 /* its not worth to inline methods with valuetype arguments?? */
3027 for (i
= 0; i
< signature
->param_count
; i
++) {
3028 if (MONO_TYPE_ISSTRUCT (signature
->params
[i
])) {
3034 * if we can initialize the class of the method right away, we do,
3035 * otherwise we don't allow inlining if the class needs initialization,
3036 * since it would mean inserting a call to mono_runtime_class_init()
3037 * inside the inlined code
3039 if (!(cfg
->opt
& MONO_OPT_SHARED
)) {
3040 vtable
= mono_class_vtable (cfg
->domain
, method
->klass
);
3041 if (method
->klass
->flags
& TYPE_ATTRIBUTE_BEFORE_FIELD_INIT
) {
3042 if (cfg
->run_cctors
) {
3043 /* This makes so that inline cannot trigger */
3044 /* .cctors: too many apps depend on them */
3045 /* running with a specific order... */
3046 if (! vtable
->initialized
)
3048 mono_runtime_class_init (vtable
);
3051 else if (!vtable
->initialized
&& mono_class_needs_cctor_run (method
->klass
, NULL
))
3055 * If we're compiling for shared code
3056 * the cctor will need to be run at aot method load time, for example,
3057 * or at the end of the compilation of the inlining method.
3059 if (mono_class_needs_cctor_run (method
->klass
, NULL
) && !((method
->klass
->flags
& TYPE_ATTRIBUTE_BEFORE_FIELD_INIT
)))
3062 //if (!MONO_TYPE_IS_VOID (signature->ret)) return FALSE;
3065 * CAS - do not inline methods with declarative security
3066 * Note: this has to be before any possible return TRUE;
3068 if (mono_method_has_declsec (method
))
3071 /* also consider num_locals? */
3072 if (getenv ("MONO_INLINELIMIT")) {
3073 if (header
->code_size
< atoi (getenv ("MONO_INLINELIMIT"))) {
3076 } else if (header
->code_size
< INLINE_LENGTH_LIMIT
)
3083 mini_field_access_needs_cctor_run (MonoCompile
*cfg
, MonoMethod
*method
, MonoVTable
*vtable
)
3085 if (vtable
->initialized
&& !cfg
->compile_aot
)
3088 if (vtable
->klass
->flags
& TYPE_ATTRIBUTE_BEFORE_FIELD_INIT
)
3091 if (!mono_class_needs_cctor_run (vtable
->klass
, method
))
3094 if (! (method
->flags
& METHOD_ATTRIBUTE_STATIC
) && (vtable
->klass
== method
->klass
))
3095 /* The initialization is already done before the method is called */
3102 mini_get_ldelema_ins (MonoCompile
*cfg
, MonoBasicBlock
*bblock
, MonoMethod
*cmethod
, MonoInst
**sp
, unsigned char *ip
, gboolean is_set
)
3106 MonoMethodSignature
*esig
;
3107 char icall_name
[256];
3109 MonoJitICallInfo
*info
;
3111 rank
= mono_method_signature (cmethod
)->param_count
- (is_set
? 1: 0);
3114 MONO_INST_NEW (cfg
, addr
, CEE_LDELEMA
);
3115 addr
->inst_left
= sp
[0];
3116 addr
->inst_right
= sp
[1];
3117 addr
->cil_code
= ip
;
3118 addr
->type
= STACK_MP
;
3119 addr
->klass
= cmethod
->klass
->element_class
;
3123 if (rank
== 2 && (cfg
->opt
& MONO_OPT_INTRINS
)) {
3124 #if defined(MONO_ARCH_EMULATE_MUL_DIV) && !defined(MONO_ARCH_NO_EMULATE_MUL)
3125 /* OP_LDELEMA2D depends on OP_LMUL */
3128 NEW_GROUP (cfg
, indexes
, sp
[1], sp
[2]);
3129 MONO_INST_NEW (cfg
, addr
, OP_LDELEMA2D
);
3130 addr
->inst_left
= sp
[0];
3131 addr
->inst_right
= indexes
;
3132 addr
->cil_code
= ip
;
3133 addr
->type
= STACK_MP
;
3134 addr
->klass
= cmethod
->klass
->element_class
;
3139 /* Need to register the icall so it gets an icall wrapper */
3140 sprintf (icall_name
, "ves_array_element_address_%d", rank
);
3143 info
= mono_find_jit_icall_by_name (icall_name
);
3145 esig
= mono_get_element_address_signature (rank
);
3146 name
= g_strdup (icall_name
);
3147 info
= mono_register_jit_icall (ves_array_element_address
, name
, esig
, FALSE
);
3149 g_hash_table_insert (jit_icall_name_hash
, name
, name
);
3153 /* FIXME: This uses info->sig, but it should use the signature of the wrapper */
3154 temp
= mono_emit_native_call (cfg
, bblock
, mono_icall_get_wrapper (info
), info
->sig
, sp
, ip
, FALSE
, FALSE
);
3155 cfg
->flags
|= MONO_CFG_HAS_VARARGS
;
3157 NEW_TEMPLOAD (cfg
, addr
, temp
);
3161 static MonoJitICallInfo
**emul_opcode_map
= NULL
;
3164 mono_find_jit_opcode_emulation (int opcode
)
3166 g_assert (opcode
>= 0 && opcode
<= OP_LAST
);
3167 if (emul_opcode_map
)
3168 return emul_opcode_map
[opcode
];
3174 mini_get_inst_for_method (MonoCompile
*cfg
, MonoMethod
*cmethod
, MonoMethodSignature
*fsig
, MonoInst
**args
)
3176 MonoInst
*ins
= NULL
;
3178 static MonoClass
*runtime_helpers_class
= NULL
;
3179 if (! runtime_helpers_class
)
3180 runtime_helpers_class
= mono_class_from_name (mono_defaults
.corlib
,
3181 "System.Runtime.CompilerServices", "RuntimeHelpers");
3183 if (cmethod
->klass
== mono_defaults
.string_class
) {
3184 if (strcmp (cmethod
->name
, "get_Chars") == 0) {
3185 MONO_INST_NEW (cfg
, ins
, OP_GETCHR
);
3186 ins
->inst_i0
= args
[0];
3187 ins
->inst_i1
= args
[1];
3189 } else if (strcmp (cmethod
->name
, "get_Length") == 0) {
3190 MONO_INST_NEW (cfg
, ins
, OP_STRLEN
);
3191 ins
->inst_i0
= args
[0];
3193 } else if (strcmp (cmethod
->name
, "InternalSetChar") == 0) {
3195 MONO_INST_NEW (cfg
, get_addr
, OP_STR_CHAR_ADDR
);
3196 get_addr
->inst_i0
= args
[0];
3197 get_addr
->inst_i1
= args
[1];
3198 MONO_INST_NEW (cfg
, ins
, CEE_STIND_I2
);
3199 ins
->inst_i0
= get_addr
;
3200 ins
->inst_i1
= args
[2];
3204 } else if (cmethod
->klass
== mono_defaults
.object_class
) {
3205 if (strcmp (cmethod
->name
, "GetType") == 0) {
3206 MONO_INST_NEW (cfg
, ins
, OP_GETTYPE
);
3207 ins
->inst_i0
= args
[0];
3209 /* The OP_GETHASHCODE rule depends on OP_MUL */
3210 #if !defined(MONO_ARCH_EMULATE_MUL_DIV) && !defined(HAVE_MOVING_COLLECTOR)
3211 } else if (strcmp (cmethod
->name
, "InternalGetHashCode") == 0) {
3212 MONO_INST_NEW (cfg
, ins
, OP_GETHASHCODE
);
3213 ins
->inst_i0
= args
[0];
3216 } else if (strcmp (cmethod
->name
, ".ctor") == 0) {
3217 MONO_INST_NEW (cfg
, ins
, CEE_NOP
);
3221 } else if (cmethod
->klass
== mono_defaults
.array_class
) {
3222 if (cmethod
->name
[0] != 'g')
3225 if (strcmp (cmethod
->name
, "get_Rank") == 0) {
3226 MONO_INST_NEW (cfg
, ins
, OP_ARRAY_RANK
);
3227 ins
->inst_i0
= args
[0];
3229 } else if (strcmp (cmethod
->name
, "get_Length") == 0) {
3230 MONO_INST_NEW (cfg
, ins
, CEE_LDLEN
);
3231 ins
->inst_i0
= args
[0];
3235 } else if (cmethod
->klass
== runtime_helpers_class
) {
3236 if (strcmp (cmethod
->name
, "get_OffsetToStringData") == 0) {
3237 NEW_ICONST (cfg
, ins
, G_STRUCT_OFFSET (MonoString
, chars
));
3241 } else if (cmethod
->klass
== mono_defaults
.thread_class
) {
3242 if (strcmp (cmethod
->name
, "get_CurrentThread") == 0 && (ins
= mono_arch_get_thread_intrinsic (cfg
)))
3244 } else if (mini_class_is_system_array (cmethod
->klass
) &&
3245 strcmp (cmethod
->name
, "GetGenericValueImpl") == 0) {
3247 MonoInst
*ldelem
, *store
, *load
;
3248 MonoClass
*eklass
= mono_class_from_mono_type (fsig
->params
[1]);
3250 n
= mono_type_to_stind (&eklass
->byval_arg
);
3255 NEW_LDELEMA (cfg
, ldelem
, sp
, eklass
);
3256 ldelem
->flags
|= MONO_INST_NORANGECHECK
;
3257 MONO_INST_NEW (cfg
, store
, n
);
3258 n
= mono_type_to_ldind (&eklass
->byval_arg
);
3259 MONO_INST_NEW (cfg
, load
, mono_type_to_ldind (&eklass
->byval_arg
));
3260 type_to_eval_stack_type (&eklass
->byval_arg
, load
);
3261 load
->inst_left
= ldelem
;
3262 store
->inst_left
= args
[2];
3263 store
->inst_right
= load
;
3267 return mono_arch_get_inst_for_method (cfg
, cmethod
, fsig
, args
);
3271 mono_save_args (MonoCompile
*cfg
, MonoBasicBlock
*bblock
, MonoMethodSignature
*sig
, MonoInst
**sp
, MonoInst
**args
)
3273 MonoInst
*store
, *temp
;
3276 g_assert (!MONO_TYPE_ISSTRUCT (sig
->ret
));
3278 if (!sig
->hasthis
&& sig
->param_count
== 0)
3282 if (sp
[0]->opcode
== OP_ICONST
) {
3285 temp
= mono_compile_create_var (cfg
, type_from_stack_type (*sp
), OP_LOCAL
);
3287 NEW_TEMPSTORE (cfg
, store
, temp
->inst_c0
, *sp
);
3288 store
->cil_code
= sp
[0]->cil_code
;
3289 MONO_ADD_INS (bblock
, store
);
3294 for (i
= 0; i
< sig
->param_count
; ++i
) {
3295 if (sp
[0]->opcode
== OP_ICONST
) {
3298 temp
= mono_compile_create_var (cfg
, sig
->params
[i
], OP_LOCAL
);
3300 NEW_TEMPSTORE (cfg
, store
, temp
->inst_c0
, *sp
);
3301 store
->cil_code
= sp
[0]->cil_code
;
3302 if (store
->opcode
== CEE_STOBJ
) {
3303 NEW_TEMPLOADA (cfg
, store
, temp
->inst_c0
);
3304 handle_stobj (cfg
, bblock
, store
, *sp
, sp
[0]->cil_code
, temp
->klass
, FALSE
, FALSE
, FALSE
);
3306 MONO_ADD_INS (bblock
, store
);
3312 #define MONO_INLINE_CALLED_LIMITED_METHODS 0
3313 #define MONO_INLINE_CALLER_LIMITED_METHODS 0
3315 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
3317 mono_inline_called_method_name_limit
= NULL
;
3318 static gboolean
check_inline_called_method_name_limit (MonoMethod
*called_method
) {
3319 char *called_method_name
= mono_method_full_name (called_method
, TRUE
);
3322 if (mono_inline_called_method_name_limit
== NULL
) {
3323 char *limit_string
= getenv ("MONO_INLINE_CALLED_METHOD_NAME_LIMIT");
3324 if (limit_string
!= NULL
) {
3325 mono_inline_called_method_name_limit
= limit_string
;
3327 mono_inline_called_method_name_limit
= (char *) "";
3331 strncmp_result
= strncmp (called_method_name
, mono_inline_called_method_name_limit
, strlen (mono_inline_called_method_name_limit
));
3332 g_free (called_method_name
);
3334 //return (strncmp_result <= 0);
3335 return (strncmp_result
== 0);
3339 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
3341 mono_inline_caller_method_name_limit
= NULL
;
3342 static gboolean
check_inline_caller_method_name_limit (MonoMethod
*caller_method
) {
3343 char *caller_method_name
= mono_method_full_name (caller_method
, TRUE
);
3346 if (mono_inline_caller_method_name_limit
== NULL
) {
3347 char *limit_string
= getenv ("MONO_INLINE_CALLER_METHOD_NAME_LIMIT");
3348 if (limit_string
!= NULL
) {
3349 mono_inline_caller_method_name_limit
= limit_string
;
3351 mono_inline_caller_method_name_limit
= (char *) "";
3355 strncmp_result
= strncmp (caller_method_name
, mono_inline_caller_method_name_limit
, strlen (mono_inline_caller_method_name_limit
));
3356 g_free (caller_method_name
);
3358 //return (strncmp_result <= 0);
3359 return (strncmp_result
== 0);
3364 inline_method (MonoCompile
*cfg
, MonoMethod
*cmethod
, MonoMethodSignature
*fsig
, MonoBasicBlock
*bblock
, MonoInst
**sp
,
3365 guchar
*ip
, guint real_offset
, GList
*dont_inline
, MonoBasicBlock
**last_b
, gboolean inline_allways
)
3367 MonoInst
*ins
, *rvar
= NULL
;
3368 MonoMethodHeader
*cheader
;
3369 MonoBasicBlock
*ebblock
, *sbblock
;
3370 int i
, costs
, new_locals_offset
;
3371 MonoMethod
*prev_inlined_method
;
3372 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
3373 if ((! inline_allways
) && ! check_inline_called_method_name_limit (cmethod
))
3376 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
3377 if ((! inline_allways
) && ! check_inline_caller_method_name_limit (cfg
->method
))
3381 if (bblock
->out_of_line
&& !inline_allways
)
3384 if (cfg
->verbose_level
> 2)
3385 g_print ("INLINE START %p %s -> %s\n", cmethod
, mono_method_full_name (cfg
->method
, TRUE
), mono_method_full_name (cmethod
, TRUE
));
3387 if (!cmethod
->inline_info
) {
3388 mono_jit_stats
.inlineable_methods
++;
3389 cmethod
->inline_info
= 1;
3391 /* allocate space to store the return value */
3392 if (!MONO_TYPE_IS_VOID (fsig
->ret
)) {
3393 rvar
= mono_compile_create_var (cfg
, fsig
->ret
, OP_LOCAL
);
3396 /* allocate local variables */
3397 cheader
= mono_method_get_header (cmethod
);
3398 new_locals_offset
= cfg
->num_varinfo
;
3399 for (i
= 0; i
< cheader
->num_locals
; ++i
)
3400 mono_compile_create_var (cfg
, cheader
->locals
[i
], OP_LOCAL
);
3402 /* allocate starte and end blocks */
3403 sbblock
= NEW_BBLOCK (cfg
);
3404 sbblock
->block_num
= cfg
->num_bblocks
++;
3405 sbblock
->real_offset
= real_offset
;
3407 ebblock
= NEW_BBLOCK (cfg
);
3408 ebblock
->block_num
= cfg
->num_bblocks
++;
3409 ebblock
->real_offset
= real_offset
;
3411 prev_inlined_method
= cfg
->inlined_method
;
3412 cfg
->inlined_method
= cmethod
;
3414 costs
= mono_method_to_ir (cfg
, cmethod
, sbblock
, ebblock
, new_locals_offset
, rvar
, dont_inline
, sp
, real_offset
, *ip
== CEE_CALLVIRT
);
3416 cfg
->inlined_method
= prev_inlined_method
;
3418 if ((costs
>= 0 && costs
< 60) || inline_allways
) {
3419 if (cfg
->verbose_level
> 2)
3420 g_print ("INLINE END %s -> %s\n", mono_method_full_name (cfg
->method
, TRUE
), mono_method_full_name (cmethod
, TRUE
));
3422 mono_jit_stats
.inlined_methods
++;
3424 /* always add some code to avoid block split failures */
3425 MONO_INST_NEW (cfg
, ins
, CEE_NOP
);
3426 MONO_ADD_INS (bblock
, ins
);
3429 bblock
->next_bb
= sbblock
;
3430 link_bblock (cfg
, bblock
, sbblock
);
3433 NEW_TEMPLOAD (cfg
, ins
, rvar
->inst_c0
);
3439 if (cfg
->verbose_level
> 2)
3440 g_print ("INLINE ABORTED %s\n", mono_method_full_name (cmethod
, TRUE
));
3446 * Some of these comments may well be out-of-date.
3447 * Design decisions: we do a single pass over the IL code (and we do bblock
3448 * splitting/merging in the few cases when it's required: a back jump to an IL
3449 * address that was not already seen as bblock starting point).
3450 * Code is validated as we go (full verification is still better left to metadata/verify.c).
3451 * Complex operations are decomposed in simpler ones right away. We need to let the
3452 * arch-specific code peek and poke inside this process somehow (except when the
3453 * optimizations can take advantage of the full semantic info of coarse opcodes).
3454 * All the opcodes of the form opcode.s are 'normalized' to opcode.
3455 * MonoInst->opcode initially is the IL opcode or some simplification of that
3456 * (OP_LOAD, OP_STORE). The arch-specific code may rearrange it to an arch-specific
3457 * opcode with value bigger than OP_LAST.
3458 * At this point the IR can be handed over to an interpreter, a dumb code generator
3459 * or to the optimizing code generator that will translate it to SSA form.
3461 * Profiling directed optimizations.
3462 * We may compile by default with few or no optimizations and instrument the code
3463 * or the user may indicate what methods to optimize the most either in a config file
3464 * or through repeated runs where the compiler applies offline the optimizations to
3465 * each method and then decides if it was worth it.
3468 * * consider using an array instead of an hash table (bb_hash)
3471 #define CHECK_TYPE(ins) if (!(ins)->type) UNVERIFIED
3472 #define CHECK_STACK(num) if ((sp - stack_start) < (num)) UNVERIFIED
3473 #define CHECK_STACK_OVF(num) if (((sp - stack_start) + (num)) > header->max_stack) UNVERIFIED
3474 #define CHECK_ARG(num) if ((unsigned)(num) >= (unsigned)num_args) UNVERIFIED
3475 #define CHECK_LOCAL(num) if ((unsigned)(num) >= (unsigned)header->num_locals) UNVERIFIED
3476 #define CHECK_OPSIZE(size) if (ip + size > end) UNVERIFIED
3477 #define CHECK_UNVERIFIABLE(cfg) if (cfg->unverifiable) UNVERIFIED
3478 #define CHECK_TYPELOAD(klass) if (!(klass) || (klass)->exception_type) {cfg->exception_ptr = klass; goto load_error;}
3480 /* offset from br.s -> br like opcodes */
3481 #define BIG_BRANCH_OFFSET 13
3484 ip_in_bb (MonoCompile
*cfg
, MonoBasicBlock
*bb
, const guint8
* ip
)
3486 MonoBasicBlock
*b
= g_hash_table_lookup (cfg
->bb_hash
, ip
);
3488 return b
== NULL
|| b
== bb
;
3492 get_basic_blocks (MonoCompile
*cfg
, GHashTable
*bbhash
, MonoMethodHeader
* header
, guint real_offset
, unsigned char *start
, unsigned char *end
, unsigned char **pos
)
3494 unsigned char *ip
= start
;
3495 unsigned char *target
;
3498 MonoBasicBlock
*bblock
;
3499 const MonoOpcode
*opcode
;
3502 cli_addr
= ip
- start
;
3503 i
= mono_opcode_value ((const guint8
**)&ip
, end
);
3506 opcode
= &mono_opcodes
[i
];
3507 switch (opcode
->argument
) {
3508 case MonoInlineNone
:
3511 case MonoInlineString
:
3512 case MonoInlineType
:
3513 case MonoInlineField
:
3514 case MonoInlineMethod
:
3517 case MonoShortInlineR
:
3524 case MonoShortInlineVar
:
3525 case MonoShortInlineI
:
3528 case MonoShortInlineBrTarget
:
3529 target
= start
+ cli_addr
+ 2 + (signed char)ip
[1];
3530 GET_BBLOCK (cfg
, bbhash
, bblock
, target
);
3533 GET_BBLOCK (cfg
, bbhash
, bblock
, ip
);
3535 case MonoInlineBrTarget
:
3536 target
= start
+ cli_addr
+ 5 + (gint32
)read32 (ip
+ 1);
3537 GET_BBLOCK (cfg
, bbhash
, bblock
, target
);
3540 GET_BBLOCK (cfg
, bbhash
, bblock
, ip
);
3542 case MonoInlineSwitch
: {
3543 guint32 n
= read32 (ip
+ 1);
3546 cli_addr
+= 5 + 4 * n
;
3547 target
= start
+ cli_addr
;
3548 GET_BBLOCK (cfg
, bbhash
, bblock
, target
);
3550 for (j
= 0; j
< n
; ++j
) {
3551 target
= start
+ cli_addr
+ (gint32
)read32 (ip
);
3552 GET_BBLOCK (cfg
, bbhash
, bblock
, target
);
3562 g_assert_not_reached ();
3565 if (i
== CEE_THROW
) {
3566 unsigned char *bb_start
= ip
- 1;
3568 /* Find the start of the bblock containing the throw */
3570 while ((bb_start
>= start
) && !bblock
) {
3571 bblock
= g_hash_table_lookup (bbhash
, (bb_start
));
3575 bblock
->out_of_line
= 1;
3585 emit_tree (MonoCompile
*cfg
, MonoBasicBlock
*bblock
, MonoInst
*ins
, const guint8
* ip_next
)
3587 MonoInst
*store
, *temp
, *load
;
3589 if (ip_in_bb (cfg
, bblock
, ip_next
) &&
3590 (CODE_IS_STLOC (ip_next
) || *ip_next
== CEE_RET
))
3593 temp
= mono_compile_create_var (cfg
, type_from_stack_type (ins
), OP_LOCAL
);
3594 temp
->flags
|= MONO_INST_IS_TEMP
;
3595 NEW_TEMPSTORE (cfg
, store
, temp
->inst_c0
, ins
);
3596 store
->cil_code
= ins
->cil_code
;
3597 MONO_ADD_INS (bblock
, store
);
3598 NEW_TEMPLOAD (cfg
, load
, temp
->inst_c0
);
3599 load
->cil_code
= ins
->cil_code
;
3603 static inline MonoMethod
*
3604 mini_get_method (MonoMethod
*m
, guint32 token
, MonoClass
*klass
, MonoGenericContext
*context
)
3608 if (m
->wrapper_type
!= MONO_WRAPPER_NONE
)
3609 return mono_method_get_wrapper_data (m
, token
);
3611 method
= mono_get_method_full (m
->klass
->image
, token
, klass
, context
);
3613 if (method
&& method
->is_inflated
)
3614 method
= mono_get_inflated_method (method
);
3619 static inline MonoClass
*
3620 mini_get_class (MonoMethod
*method
, guint32 token
, MonoGenericContext
*context
)
3624 if (method
->wrapper_type
!= MONO_WRAPPER_NONE
)
3625 klass
= mono_method_get_wrapper_data (method
, token
);
3627 klass
= mono_class_get_full (method
->klass
->image
, token
, context
);
3629 mono_class_init (klass
);
3634 * Returns TRUE if the JIT should abort inlining because "callee"
3635 * is influenced by security attributes.
3638 gboolean
check_linkdemand (MonoCompile
*cfg
, MonoMethod
*caller
, MonoMethod
*callee
, MonoBasicBlock
*bblock
, unsigned char *ip
)
3642 if ((cfg
->method
!= caller
) && mono_method_has_declsec (callee
)) {
3646 result
= mono_declsec_linkdemand (cfg
->domain
, caller
, callee
);
3647 if (result
== MONO_JIT_SECURITY_OK
)
3650 if (result
== MONO_JIT_LINKDEMAND_ECMA
) {
3651 /* Generate code to throw a SecurityException before the actual call/link */
3652 MonoAssembly
*assembly
= mono_image_get_assembly (caller
->klass
->image
);
3653 MonoReflectionAssembly
*refass
= (MonoReflectionAssembly
*) mono_assembly_get_object (cfg
->domain
, assembly
);
3654 MonoReflectionMethod
*refmet
= mono_method_get_object (cfg
->domain
, caller
, NULL
);
3655 MonoSecurityManager
*secman
= mono_security_manager_get_methods ();
3658 NEW_ICONST (cfg
, args
[0], 4);
3659 NEW_PCONST (cfg
, args
[1], refass
);
3660 NEW_PCONST (cfg
, args
[2], refmet
);
3661 mono_emit_method_call_spilled (cfg
, bblock
, secman
->linkdemandsecurityexception
, mono_method_signature (secman
->linkdemandsecurityexception
), args
, ip
, NULL
);
3662 } else if (cfg
->exception_type
== MONO_EXCEPTION_NONE
) {
3663 /* don't hide previous results */
3664 cfg
->exception_type
= MONO_EXCEPTION_SECURITY_LINKDEMAND
;
3665 cfg
->exception_data
= result
;
3672 can_access_internals (MonoAssembly
*accessing
, MonoAssembly
* accessed
)
3675 if (accessing
== accessed
)
3677 if (!accessed
|| !accessing
)
3679 for (tmp
= accessed
->friend_assembly_names
; tmp
; tmp
= tmp
->next
) {
3680 MonoAssemblyName
*friend = tmp
->data
;
3681 /* Be conservative with checks */
3684 if (strcmp (accessing
->aname
.name
, friend->name
))
3686 if (friend->public_key_token
[0]) {
3687 if (!accessing
->aname
.public_key_token
[0])
3689 if (strcmp ((char*)friend->public_key_token
, (char*)accessing
->aname
.public_key_token
))
3697 /* FIXME: check visibility of type, too */
3699 can_access_member (MonoClass
*access_klass
, MonoClass
*member_klass
, int access_level
)
3701 /* Partition I 8.5.3.2 */
3702 /* the access level values are the same for fields and methods */
3703 switch (access_level
) {
3704 case FIELD_ATTRIBUTE_COMPILER_CONTROLLED
:
3705 /* same compilation unit */
3706 return access_klass
->image
== member_klass
->image
;
3707 case FIELD_ATTRIBUTE_PRIVATE
:
3708 return access_klass
== member_klass
;
3709 case FIELD_ATTRIBUTE_FAM_AND_ASSEM
:
3710 if (mono_class_has_parent (access_klass
, member_klass
) &&
3711 can_access_internals (access_klass
->image
->assembly
, member_klass
->image
->assembly
))
3714 case FIELD_ATTRIBUTE_ASSEMBLY
:
3715 return can_access_internals (access_klass
->image
->assembly
, member_klass
->image
->assembly
);
3716 case FIELD_ATTRIBUTE_FAMILY
:
3717 if (mono_class_has_parent (access_klass
, member_klass
))
3720 case FIELD_ATTRIBUTE_FAM_OR_ASSEM
:
3721 if (mono_class_has_parent (access_klass
, member_klass
))
3723 return can_access_internals (access_klass
->image
->assembly
, member_klass
->image
->assembly
);
3724 case FIELD_ATTRIBUTE_PUBLIC
:
3731 can_access_field (MonoMethod
*method
, MonoClassField
*field
)
3733 /* FIXME: check all overlapping fields */
3734 int can
= can_access_member (method
->klass
, field
->parent
, field
->type
->attrs
& FIELD_ATTRIBUTE_FIELD_ACCESS_MASK
);
3736 MonoClass
*nested
= method
->klass
->nested_in
;
3738 can
= can_access_member (nested
, field
->parent
, field
->type
->attrs
& FIELD_ATTRIBUTE_FIELD_ACCESS_MASK
);
3741 nested
= nested
->nested_in
;
3748 can_access_method (MonoMethod
*method
, MonoMethod
*called
)
3750 int can
= can_access_member (method
->klass
, called
->klass
, called
->flags
& METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK
);
3752 MonoClass
*nested
= method
->klass
->nested_in
;
3754 can
= can_access_member (nested
, called
->klass
, called
->flags
& METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK
);
3757 nested
= nested
->nested_in
;
3762 * with generics calls to explicit interface implementations can be expressed
3763 * directly: the method is private, but we must allow it. This may be opening
3764 * a hole or the generics code should handle this differently.
3765 * Maybe just ensure the interface type is public.
3767 if ((called
->flags
& METHOD_ATTRIBUTE_VIRTUAL
) && (called
->flags
& METHOD_ATTRIBUTE_FINAL
))
3773 * mono_method_to_ir: translates IL into basic blocks containing trees
3776 mono_method_to_ir (MonoCompile
*cfg
, MonoMethod
*method
, MonoBasicBlock
*start_bblock
, MonoBasicBlock
*end_bblock
,
3777 int locals_offset
, MonoInst
*return_var
, GList
*dont_inline
, MonoInst
**inline_args
,
3778 guint inline_offset
, gboolean is_virtual_call
)
3780 MonoInst
*zero_int32
, *zero_int64
, *zero_ptr
, *zero_obj
, *zero_r8
;
3781 MonoInst
*ins
, **sp
, **stack_start
;
3782 MonoBasicBlock
*bblock
, *tblock
= NULL
, *init_localsbb
= NULL
;
3784 MonoMethod
*cmethod
;
3785 MonoInst
**arg_array
;
3786 MonoMethodHeader
*header
;
3788 guint32 token
, ins_flag
;
3790 MonoClass
*constrained_call
= NULL
;
3791 unsigned char *ip
, *end
, *target
, *err_pos
;
3792 static double r8_0
= 0.0;
3793 MonoMethodSignature
*sig
;
3794 MonoGenericContext
*generic_context
= NULL
;
3795 MonoGenericContainer
*generic_container
= NULL
;
3796 MonoType
**param_types
;
3797 GList
*bb_recheck
= NULL
, *tmp
;
3798 int i
, n
, start_new_bblock
, ialign
;
3799 int num_calls
= 0, inline_costs
= 0;
3800 int breakpoint_id
= 0;
3802 guint real_offset
, num_args
;
3803 MonoBoolean security
, pinvoke
;
3804 MonoSecurityManager
* secman
= NULL
;
3805 MonoDeclSecurityActions actions
;
3806 GSList
*class_inits
= NULL
;
3807 gboolean dont_verify
, dont_verify_stloc
;
3809 /* serialization and xdomain stuff may need access to private fields and methods */
3810 dont_verify
= method
->klass
->image
->assembly
->corlib_internal
? TRUE
: FALSE
;
3811 dont_verify
|= method
->wrapper_type
== MONO_WRAPPER_XDOMAIN_INVOKE
;
3812 dont_verify
|= method
->wrapper_type
== MONO_WRAPPER_XDOMAIN_DISPATCH
;
3813 dont_verify
|= method
->wrapper_type
== MONO_WRAPPER_MANAGED_TO_NATIVE
; /* bug #77896 */
3814 dont_verify
|= method
->wrapper_type
== MONO_WRAPPER_COMINTEROP
;
3815 dont_verify
|= method
->wrapper_type
== MONO_WRAPPER_COMINTEROP_INVOKE
;
3817 /* still some type unsafety issues in marshal wrappers... (unknown is PtrToStructure) */
3818 dont_verify_stloc
= method
->wrapper_type
== MONO_WRAPPER_MANAGED_TO_NATIVE
;
3819 dont_verify_stloc
|= method
->wrapper_type
== MONO_WRAPPER_UNKNOWN
;
3820 dont_verify_stloc
|= method
->wrapper_type
== MONO_WRAPPER_NATIVE_TO_MANAGED
;
3822 /* Not turned on yet */
3823 cfg
->dont_verify_stack_merge
= TRUE
;
3825 image
= method
->klass
->image
;
3826 header
= mono_method_get_header (method
);
3827 generic_container
= method
->generic_container
;
3828 sig
= mono_method_signature (method
);
3829 num_args
= sig
->hasthis
+ sig
->param_count
;
3830 ip
= (unsigned char*)header
->code
;
3831 end
= ip
+ header
->code_size
;
3832 mono_jit_stats
.cil_code_size
+= header
->code_size
;
3834 if (sig
->is_inflated
)
3835 generic_context
= ((MonoMethodInflated
*) method
)->context
;
3836 else if (generic_container
)
3837 generic_context
= &generic_container
->context
;
3839 g_assert (!sig
->has_type_parameters
);
3841 if (cfg
->method
== method
) {
3843 bbhash
= cfg
->bb_hash
;
3845 real_offset
= inline_offset
;
3846 bbhash
= g_hash_table_new (g_direct_hash
, NULL
);
3849 if (cfg
->verbose_level
> 2)
3850 g_print ("method to IR %s\n", mono_method_full_name (method
, TRUE
));
3852 dont_inline
= g_list_prepend (dont_inline
, method
);
3853 if (cfg
->method
== method
) {
3855 if (cfg
->prof_options
& MONO_PROFILE_INS_COVERAGE
)
3856 cfg
->coverage_info
= mono_profiler_coverage_alloc (cfg
->method
, header
->code_size
);
3859 cfg
->bb_entry
= start_bblock
= NEW_BBLOCK (cfg
);
3860 start_bblock
->cil_code
= NULL
;
3861 start_bblock
->cil_length
= 0;
3862 start_bblock
->block_num
= cfg
->num_bblocks
++;
3865 cfg
->bb_exit
= end_bblock
= NEW_BBLOCK (cfg
);
3866 end_bblock
->cil_code
= NULL
;
3867 end_bblock
->cil_length
= 0;
3868 end_bblock
->block_num
= cfg
->num_bblocks
++;
3869 g_assert (cfg
->num_bblocks
== 2);
3871 arg_array
= alloca (sizeof (MonoInst
*) * num_args
);
3872 for (i
= num_args
- 1; i
>= 0; i
--)
3873 arg_array
[i
] = cfg
->varinfo
[i
];
3875 if (header
->num_clauses
) {
3876 cfg
->spvars
= g_hash_table_new (NULL
, NULL
);
3877 cfg
->exvars
= g_hash_table_new (NULL
, NULL
);
3879 /* handle exception clauses */
3880 for (i
= 0; i
< header
->num_clauses
; ++i
) {
3881 MonoBasicBlock
*try_bb
;
3882 MonoExceptionClause
*clause
= &header
->clauses
[i
];
3883 GET_BBLOCK (cfg
, bbhash
, try_bb
, ip
+ clause
->try_offset
);
3884 try_bb
->real_offset
= clause
->try_offset
;
3885 GET_BBLOCK (cfg
, bbhash
, tblock
, ip
+ clause
->handler_offset
);
3886 tblock
->real_offset
= clause
->handler_offset
;
3887 tblock
->flags
|= BB_EXCEPTION_HANDLER
;
3889 link_bblock (cfg
, try_bb
, tblock
);
3891 if (*(ip
+ clause
->handler_offset
) == CEE_POP
)
3892 tblock
->flags
|= BB_EXCEPTION_DEAD_OBJ
;
3894 if (clause
->flags
== MONO_EXCEPTION_CLAUSE_FINALLY
||
3895 clause
->flags
== MONO_EXCEPTION_CLAUSE_FILTER
) {
3896 MONO_INST_NEW (cfg
, ins
, OP_START_HANDLER
);
3897 MONO_ADD_INS (tblock
, ins
);
3899 /* todo: is a fault block unsafe to optimize? */
3900 if (clause
->flags
== MONO_EXCEPTION_CLAUSE_FAULT
)
3901 tblock
->flags
|= BB_EXCEPTION_UNSAFE
;
3905 /*g_print ("clause try IL_%04x to IL_%04x handler %d at IL_%04x to IL_%04x\n", clause->try_offset, clause->try_offset + clause->try_len, clause->flags, clause->handler_offset, clause->handler_offset + clause->handler_len);
3907 g_print ("%s", mono_disasm_code_one (NULL, method, p, &p));
3909 /* catch and filter blocks get the exception object on the stack */
3910 if (clause
->flags
== MONO_EXCEPTION_CLAUSE_NONE
||
3911 clause
->flags
== MONO_EXCEPTION_CLAUSE_FILTER
) {
3912 MonoInst
*load
, *dummy_use
;
3914 /* mostly like handle_stack_args (), but just sets the input args */
3915 /* g_print ("handling clause at IL_%04x\n", clause->handler_offset); */
3916 tblock
->in_scount
= 1;
3917 tblock
->in_stack
= mono_mempool_alloc (cfg
->mempool
, sizeof (MonoInst
*));
3918 tblock
->in_stack
[0] = mono_create_exvar_for_offset (cfg
, clause
->handler_offset
);
3919 tblock
->stack_state
= mono_mempool_alloc (cfg
->mempool
, sizeof (MonoStackSlot
));
3920 tblock
->stack_state
[0].type
= STACK_OBJ
;
3922 tblock
->stack_state
[0].klass
= mono_defaults
.object_class
;
3925 * Add a dummy use for the exvar so its liveness info will be
3928 NEW_TEMPLOAD (cfg
, load
, tblock
->in_stack
[0]->inst_c0
);
3929 NEW_DUMMY_USE (cfg
, dummy_use
, load
);
3930 MONO_ADD_INS (tblock
, dummy_use
);
3932 if (clause
->flags
== MONO_EXCEPTION_CLAUSE_FILTER
) {
3933 GET_BBLOCK (cfg
, bbhash
, tblock
, ip
+ clause
->data
.filter_offset
);
3934 tblock
->real_offset
= clause
->data
.filter_offset
;
3935 tblock
->in_scount
= 1;
3936 tblock
->in_stack
= mono_mempool_alloc (cfg
->mempool
, sizeof (MonoInst
*));
3937 tblock
->stack_state
= mono_mempool_alloc (cfg
->mempool
, sizeof (MonoStackSlot
));
3938 tblock
->stack_state
[0].type
= STACK_OBJ
;
3940 tblock
->stack_state
[0].klass
= mono_defaults
.object_class
;
3942 /* The filter block shares the exvar with the handler block */
3943 tblock
->in_stack
[0] = mono_create_exvar_for_offset (cfg
, clause
->handler_offset
);
3944 MONO_INST_NEW (cfg
, ins
, OP_START_HANDLER
);
3945 MONO_ADD_INS (tblock
, ins
);
3950 arg_array
= alloca (sizeof (MonoInst
*) * num_args
);
3951 mono_save_args (cfg
, start_bblock
, sig
, inline_args
, arg_array
);
3954 /* FIRST CODE BLOCK */
3955 bblock
= NEW_BBLOCK (cfg
);
3956 bblock
->cil_code
= ip
;
3958 ADD_BBLOCK (cfg
, bbhash
, bblock
);
3960 if (cfg
->method
== method
) {
3961 breakpoint_id
= mono_debugger_method_has_breakpoint (method
);
3962 if (breakpoint_id
&& (mono_debug_format
!= MONO_DEBUG_FORMAT_DEBUGGER
)) {
3963 MONO_INST_NEW (cfg
, ins
, CEE_BREAK
);
3964 MONO_ADD_INS (bblock
, ins
);
3968 if (mono_use_security_manager
)
3969 secman
= mono_security_manager_get_methods ();
3971 security
= (secman
&& mono_method_has_declsec (method
));
3972 /* at this point having security doesn't mean we have any code to generate */
3973 if (security
&& (cfg
->method
== method
)) {
3974 /* Only Demand, NonCasDemand and DemandChoice requires code generation.
3975 * And we do not want to enter the next section (with allocation) if we
3976 * have nothing to generate */
3977 security
= mono_declsec_get_demands (method
, &actions
);
3980 /* we must Demand SecurityPermission.Unmanaged before P/Invoking */
3981 pinvoke
= (secman
&& (method
->wrapper_type
== MONO_WRAPPER_MANAGED_TO_NATIVE
));
3983 MonoMethod
*wrapped
= mono_marshal_method_from_wrapper (method
);
3984 if (wrapped
&& (wrapped
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
)) {
3985 MonoCustomAttrInfo
* custom
= mono_custom_attrs_from_method (wrapped
);
3987 /* unless the method or it's class has the [SuppressUnmanagedCodeSecurity] attribute */
3988 if (custom
&& mono_custom_attrs_has_attr (custom
, secman
->suppressunmanagedcodesecurity
)) {
3993 custom
= mono_custom_attrs_from_class (wrapped
->klass
);
3994 if (custom
&& mono_custom_attrs_has_attr (custom
, secman
->suppressunmanagedcodesecurity
)) {
3999 /* not a P/Invoke after all */
4004 if ((header
->init_locals
|| (cfg
->method
== method
&& (cfg
->opt
& MONO_OPT_SHARED
))) || cfg
->compile_aot
|| security
|| pinvoke
) {
4005 /* we use a separate basic block for the initialization code */
4006 cfg
->bb_init
= init_localsbb
= NEW_BBLOCK (cfg
);
4007 init_localsbb
->real_offset
= real_offset
;
4008 start_bblock
->next_bb
= init_localsbb
;
4009 init_localsbb
->next_bb
= bblock
;
4010 link_bblock (cfg
, start_bblock
, init_localsbb
);
4011 link_bblock (cfg
, init_localsbb
, bblock
);
4012 init_localsbb
->block_num
= cfg
->num_bblocks
++;
4014 start_bblock
->next_bb
= bblock
;
4015 link_bblock (cfg
, start_bblock
, bblock
);
4018 /* at this point we know, if security is TRUE, that some code needs to be generated */
4019 if (security
&& (cfg
->method
== method
)) {
4022 mono_jit_stats
.cas_demand_generation
++;
4024 if (actions
.demand
.blob
) {
4025 /* Add code for SecurityAction.Demand */
4026 NEW_DECLSECCONST (cfg
, args
[0], image
, actions
.demand
);
4027 NEW_ICONST (cfg
, args
[1], actions
.demand
.size
);
4028 /* Calls static void SecurityManager.InternalDemand (byte* permissions, int size); */
4029 mono_emit_method_call_spilled (cfg
, init_localsbb
, secman
->demand
, mono_method_signature (secman
->demand
), args
, ip
, NULL
);
4031 if (actions
.noncasdemand
.blob
) {
4032 /* CLR 1.x uses a .noncasdemand (but 2.x doesn't) */
4033 /* For Mono we re-route non-CAS Demand to Demand (as the managed code must deal with it anyway) */
4034 NEW_DECLSECCONST (cfg
, args
[0], image
, actions
.noncasdemand
);
4035 NEW_ICONST (cfg
, args
[1], actions
.noncasdemand
.size
);
4036 /* Calls static void SecurityManager.InternalDemand (byte* permissions, int size); */
4037 mono_emit_method_call_spilled (cfg
, init_localsbb
, secman
->demand
, mono_method_signature (secman
->demand
), args
, ip
, NULL
);
4039 if (actions
.demandchoice
.blob
) {
4040 /* New in 2.0, Demand must succeed for one of the permissions (i.e. not all) */
4041 NEW_DECLSECCONST (cfg
, args
[0], image
, actions
.demandchoice
);
4042 NEW_ICONST (cfg
, args
[1], actions
.demandchoice
.size
);
4043 /* Calls static void SecurityManager.InternalDemandChoice (byte* permissions, int size); */
4044 mono_emit_method_call_spilled (cfg
, init_localsbb
, secman
->demandchoice
, mono_method_signature (secman
->demandchoice
), args
, ip
, NULL
);
4048 /* we must Demand SecurityPermission.Unmanaged before p/invoking */
4050 mono_emit_method_call_spilled (cfg
, init_localsbb
, secman
->demandunmanaged
, mono_method_signature (secman
->demandunmanaged
), NULL
, ip
, NULL
);
4053 if (get_basic_blocks (cfg
, bbhash
, header
, real_offset
, ip
, end
, &err_pos
)) {
4058 if (cfg
->method
== method
)
4059 mono_debug_init_method (cfg
, bblock
, breakpoint_id
);
4061 param_types
= mono_mempool_alloc (cfg
->mempool
, sizeof (MonoType
*) * num_args
);
4063 param_types
[0] = method
->klass
->valuetype
?&method
->klass
->this_arg
:&method
->klass
->byval_arg
;
4064 for (n
= 0; n
< sig
->param_count
; ++n
)
4065 param_types
[n
+ sig
->hasthis
] = sig
->params
[n
];
4066 for (n
= 0; n
< header
->num_locals
; ++n
) {
4067 if (header
->locals
[n
]->type
== MONO_TYPE_VOID
&& !header
->locals
[n
]->byref
)
4072 /* do this somewhere outside - not here */
4073 NEW_ICONST (cfg
, zero_int32
, 0);
4074 NEW_ICONST (cfg
, zero_int64
, 0);
4075 zero_int64
->type
= STACK_I8
;
4076 NEW_PCONST (cfg
, zero_ptr
, 0);
4077 NEW_PCONST (cfg
, zero_obj
, 0);
4078 zero_obj
->type
= STACK_OBJ
;
4080 MONO_INST_NEW (cfg
, zero_r8
, OP_R8CONST
);
4081 zero_r8
->type
= STACK_R8
;
4082 zero_r8
->inst_p0
= &r8_0
;
4084 /* add a check for this != NULL to inlined methods */
4085 if (is_virtual_call
) {
4086 MONO_INST_NEW (cfg
, ins
, OP_CHECK_THIS
);
4087 NEW_ARGLOAD (cfg
, ins
->inst_left
, 0);
4089 MONO_ADD_INS (bblock
, ins
);
4092 /* we use a spare stack slot in SWITCH and NEWOBJ and others */
4093 stack_start
= sp
= mono_mempool_alloc0 (cfg
->mempool
, sizeof (MonoInst
*) * (header
->max_stack
+ 1));
4096 start_new_bblock
= 0;
4099 if (cfg
->method
== method
)
4100 real_offset
= ip
- header
->code
;
4102 real_offset
= inline_offset
;
4104 if (start_new_bblock
) {
4105 bblock
->cil_length
= ip
- bblock
->cil_code
;
4106 if (start_new_bblock
== 2) {
4107 g_assert (ip
== tblock
->cil_code
);
4109 GET_BBLOCK (cfg
, bbhash
, tblock
, ip
);
4111 bblock
->next_bb
= tblock
;
4113 start_new_bblock
= 0;
4114 for (i
= 0; i
< bblock
->in_scount
; ++i
) {
4115 if (cfg
->verbose_level
> 3)
4116 g_print ("loading %d from temp %d\n", i
, (int)bblock
->in_stack
[i
]->inst_c0
);
4117 NEW_TEMPLOAD (cfg
, ins
, bblock
->in_stack
[i
]->inst_c0
);
4120 g_slist_free (class_inits
);
4123 if ((tblock
= g_hash_table_lookup (bbhash
, ip
)) && (tblock
!= bblock
)) {
4124 link_bblock (cfg
, bblock
, tblock
);
4125 if (sp
!= stack_start
) {
4126 handle_stack_args (cfg
, bblock
, stack_start
, sp
- stack_start
);
4128 CHECK_UNVERIFIABLE (cfg
);
4130 bblock
->next_bb
= tblock
;
4132 for (i
= 0; i
< bblock
->in_scount
; ++i
) {
4133 if (cfg
->verbose_level
> 3)
4134 g_print ("loading %d from temp %d\n", i
, (int)bblock
->in_stack
[i
]->inst_c0
);
4135 NEW_TEMPLOAD (cfg
, ins
, bblock
->in_stack
[i
]->inst_c0
);
4138 g_slist_free (class_inits
);
4143 bblock
->real_offset
= real_offset
;
4145 if ((cfg
->method
== method
) && cfg
->coverage_info
) {
4146 MonoInst
*store
, *one
;
4147 guint32 cil_offset
= ip
- header
->code
;
4148 cfg
->coverage_info
->data
[cil_offset
].cil_code
= ip
;
4150 /* TODO: Use an increment here */
4151 NEW_ICONST (cfg
, one
, 1);
4154 NEW_PCONST (cfg
, ins
, &(cfg
->coverage_info
->data
[cil_offset
].count
));
4157 MONO_INST_NEW (cfg
, store
, CEE_STIND_I
);
4158 store
->cil_code
= ip
;
4159 store
->inst_left
= ins
;
4160 store
->inst_right
= one
;
4162 MONO_ADD_INS (bblock
, store
);
4165 if (cfg
->verbose_level
> 3)
4166 g_print ("converting (in B%d: stack: %d) %s", bblock
->block_num
, (int)(sp
- stack_start
), mono_disasm_code_one (NULL
, method
, ip
, NULL
));
4171 MONO_INST_NEW (cfg
, ins
, *ip
);
4172 ins
->cil_code
= ip
++;
4173 MONO_ADD_INS (bblock
, ins
);
4179 CHECK_STACK_OVF (1);
4180 n
= (*ip
)-CEE_LDARG_0
;
4182 NEW_ARGLOAD (cfg
, ins
, n
);
4183 LDARG_SOFT_FLOAT (cfg
, ins
, n
, ip
);
4184 ins
->cil_code
= ip
++;
4191 CHECK_STACK_OVF (1);
4192 n
= (*ip
)-CEE_LDLOC_0
;
4194 NEW_LOCLOAD (cfg
, ins
, n
);
4195 LDLOC_SOFT_FLOAT (cfg
, ins
, n
, ip
);
4196 ins
->cil_code
= ip
++;
4204 n
= (*ip
)-CEE_STLOC_0
;
4207 handle_loaded_temps (cfg
, bblock
, stack_start
, sp
);
4208 NEW_LOCSTORE (cfg
, ins
, n
, *sp
);
4210 if (!dont_verify_stloc
&& target_type_is_incompatible (cfg
, header
->locals
[n
], *sp
))
4212 STLOC_SOFT_FLOAT (cfg
, ins
, n
, ip
);
4213 if (ins
->opcode
== CEE_STOBJ
) {
4214 NEW_LOCLOADA (cfg
, ins
, n
);
4215 handle_stobj (cfg
, bblock
, ins
, *sp
, ip
, ins
->klass
, FALSE
, FALSE
, FALSE
);
4217 MONO_ADD_INS (bblock
, ins
);
4223 CHECK_STACK_OVF (1);
4225 NEW_ARGLOAD (cfg
, ins
, ip
[1]);
4226 LDARG_SOFT_FLOAT (cfg
, ins
, ip
[1], ip
);
4233 CHECK_STACK_OVF (1);
4235 NEW_ARGLOADA (cfg
, ins
, ip
[1]);
4245 NEW_ARGSTORE (cfg
, ins
, ip
[1], *sp
);
4246 handle_loaded_temps (cfg
, bblock
, stack_start
, sp
);
4248 if (!dont_verify_stloc
&& target_type_is_incompatible (cfg
, param_types
[ip
[1]], *sp
))
4250 if (ins
->opcode
== CEE_STOBJ
) {
4251 NEW_ARGLOADA (cfg
, ins
, ip
[1]);
4252 handle_stobj (cfg
, bblock
, ins
, *sp
, ip
, ins
->klass
, FALSE
, FALSE
, FALSE
);
4254 MONO_ADD_INS (bblock
, ins
);
4259 CHECK_STACK_OVF (1);
4260 CHECK_LOCAL (ip
[1]);
4261 NEW_LOCLOAD (cfg
, ins
, ip
[1]);
4262 LDLOC_SOFT_FLOAT (cfg
, ins
, ip
[1], ip
);
4269 CHECK_STACK_OVF (1);
4270 CHECK_LOCAL (ip
[1]);
4271 NEW_LOCLOADA (cfg
, ins
, ip
[1]);
4280 handle_loaded_temps (cfg
, bblock
, stack_start
, sp
);
4281 CHECK_LOCAL (ip
[1]);
4282 NEW_LOCSTORE (cfg
, ins
, ip
[1], *sp
);
4284 if (!dont_verify_stloc
&& target_type_is_incompatible (cfg
, header
->locals
[ip
[1]], *sp
))
4286 STLOC_SOFT_FLOAT (cfg
, ins
, ip
[1], ip
);
4287 if (ins
->opcode
== CEE_STOBJ
) {
4288 NEW_LOCLOADA (cfg
, ins
, ip
[1]);
4289 handle_stobj (cfg
, bblock
, ins
, *sp
, ip
, ins
->klass
, FALSE
, FALSE
, FALSE
);
4291 MONO_ADD_INS (bblock
, ins
);
4296 CHECK_STACK_OVF (1);
4297 NEW_PCONST (cfg
, ins
, NULL
);
4299 ins
->type
= STACK_OBJ
;
4304 CHECK_STACK_OVF (1);
4305 NEW_ICONST (cfg
, ins
, -1);
4319 CHECK_STACK_OVF (1);
4320 NEW_ICONST (cfg
, ins
, (*ip
) - CEE_LDC_I4_0
);
4327 CHECK_STACK_OVF (1);
4329 NEW_ICONST (cfg
, ins
, *((signed char*)ip
));
4336 CHECK_STACK_OVF (1);
4337 NEW_ICONST (cfg
, ins
, (gint32
)read32 (ip
+ 1));
4344 CHECK_STACK_OVF (1);
4345 MONO_INST_NEW (cfg
, ins
, OP_I8CONST
);
4347 ins
->type
= STACK_I8
;
4349 ins
->inst_l
= (gint64
)read64 (ip
);
4355 /* we should really allocate this only late in the compilation process */
4356 mono_domain_lock (cfg
->domain
);
4357 f
= mono_mempool_alloc (cfg
->domain
->mp
, sizeof (float));
4358 mono_domain_unlock (cfg
->domain
);
4360 CHECK_STACK_OVF (1);
4361 MONO_INST_NEW (cfg
, ins
, OP_R4CONST
);
4362 ins
->type
= STACK_R8
;
4373 mono_domain_lock (cfg
->domain
);
4374 d
= mono_mempool_alloc (cfg
->domain
->mp
, sizeof (double));
4375 mono_domain_unlock (cfg
->domain
);
4377 CHECK_STACK_OVF (1);
4378 MONO_INST_NEW (cfg
, ins
, OP_R8CONST
);
4379 ins
->type
= STACK_R8
;
4389 MonoInst
*temp
, *store
;
4391 CHECK_STACK_OVF (1);
4396 * small optimization: if the loaded value was from a local already,
4397 * just load it twice.
4399 if (ins
->ssa_op
== MONO_SSA_LOAD
&&
4400 (ins
->inst_i0
->opcode
== OP_LOCAL
|| ins
->inst_i0
->opcode
== OP_ARG
)) {
4402 MONO_INST_NEW (cfg
, temp
, 0);
4404 temp
->cil_code
= ip
;
4407 temp
= mono_compile_create_var (cfg
, type_from_stack_type (ins
), OP_LOCAL
);
4408 temp
->flags
|= MONO_INST_IS_TEMP
;
4409 temp
->cil_code
= ip
;
4410 NEW_TEMPSTORE (cfg
, store
, temp
->inst_c0
, ins
);
4411 store
->cil_code
= ip
;
4412 if (store
->opcode
== CEE_STOBJ
) {
4413 NEW_TEMPLOADA (cfg
, store
, temp
->inst_c0
);
4414 handle_stobj (cfg
, bblock
, store
, sp
[0], sp
[0]->cil_code
, store
->klass
, TRUE
, FALSE
, FALSE
);
4416 MONO_ADD_INS (bblock
, store
);
4418 NEW_TEMPLOAD (cfg
, ins
, temp
->inst_c0
);
4421 NEW_TEMPLOAD (cfg
, ins
, temp
->inst_c0
);
4431 MONO_INST_NEW (cfg
, ins
, CEE_POP
);
4432 MONO_ADD_INS (bblock
, ins
);
4433 ins
->cil_code
= ip
++;
4439 if (stack_start
!= sp
)
4441 MONO_INST_NEW (cfg
, ins
, CEE_JMP
);
4442 token
= read32 (ip
+ 1);
4443 /* FIXME: check the signature matches */
4444 cmethod
= mini_get_method (method
, token
, NULL
, generic_context
);
4449 if (mono_use_security_manager
) {
4450 if (check_linkdemand (cfg
, method
, cmethod
, bblock
, ip
))
4454 ins
->inst_p0
= cmethod
;
4455 MONO_ADD_INS (bblock
, ins
);
4457 start_new_bblock
= 1;
4461 case CEE_CALLVIRT
: {
4462 MonoInst
*addr
= NULL
;
4463 MonoMethodSignature
*fsig
= NULL
;
4464 int temp
, array_rank
= 0;
4465 int virtual = *ip
== CEE_CALLVIRT
;
4468 token
= read32 (ip
+ 1);
4470 if (*ip
== CEE_CALLI
) {
4475 if (method
->wrapper_type
!= MONO_WRAPPER_NONE
)
4476 fsig
= (MonoMethodSignature
*)mono_method_get_wrapper_data (method
, token
);
4478 fsig
= mono_metadata_parse_signature (image
, token
);
4480 n
= fsig
->param_count
+ fsig
->hasthis
;
4482 MonoMethod
*cil_method
;
4484 if (method
->wrapper_type
!= MONO_WRAPPER_NONE
) {
4485 cmethod
= (MonoMethod
*)mono_method_get_wrapper_data (method
, token
);
4486 cil_method
= cmethod
;
4487 } else if (constrained_call
) {
4488 cmethod
= mono_get_method_constrained (image
, token
, constrained_call
, generic_context
, &cil_method
);
4489 cmethod
= mono_get_inflated_method (cmethod
);
4491 cmethod
= mini_get_method (method
, token
, NULL
, generic_context
);
4492 cil_method
= cmethod
;
4497 if (!dont_verify
&& !cfg
->skip_visibility
&& !can_access_method (method
, cil_method
))
4500 if (!virtual && (cmethod
->flags
& METHOD_ATTRIBUTE_ABSTRACT
))
4501 /* MS.NET seems to silently convert this to a callvirt */
4504 if (!cmethod
->klass
->inited
){
4505 if (!mono_class_init (cmethod
->klass
))
4509 if (mono_method_signature (cmethod
)->pinvoke
) {
4510 MonoMethod
*wrapper
= mono_marshal_get_native_wrapper (cmethod
);
4511 fsig
= mono_method_signature (wrapper
);
4512 } else if (constrained_call
) {
4513 fsig
= mono_method_signature (cmethod
);
4515 fsig
= mono_method_get_signature_full (cmethod
, image
, token
, generic_context
);
4518 n
= fsig
->param_count
+ fsig
->hasthis
;
4520 if (mono_use_security_manager
) {
4521 if (check_linkdemand (cfg
, method
, cmethod
, bblock
, ip
))
4525 if (cmethod
->iflags
& METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
&&
4526 mini_class_is_system_array (cmethod
->klass
)) {
4527 array_rank
= cmethod
->klass
->rank
;
4530 if (cmethod
->string_ctor
)
4531 g_assert_not_reached ();
4535 if (cmethod
&& cmethod
->klass
->generic_container
)
4540 //g_assert (!virtual || fsig->hasthis);
4544 if (constrained_call
) {
4546 * We have the `constrained.' prefix opcode.
4548 if (constrained_call
->valuetype
&& !cmethod
->klass
->valuetype
) {
4551 * The type parameter is instantiated as a valuetype,
4552 * but that type doesn't override the method we're
4553 * calling, so we need to box `this'.
4554 * sp [0] is a pointer to the data: we need the value
4555 * in handle_box (), so load it here.
4557 MONO_INST_NEW (cfg
, load
, mono_type_to_ldind (&constrained_call
->byval_arg
));
4558 type_to_eval_stack_type (&constrained_call
->byval_arg
, load
);
4559 load
->cil_code
= ip
;
4560 load
->inst_left
= sp
[0];
4561 sp
[0] = handle_box (cfg
, bblock
, load
, ip
, constrained_call
);
4562 } else if (!constrained_call
->valuetype
) {
4566 * The type parameter is instantiated as a reference
4567 * type. We have a managed pointer on the stack, so
4568 * we need to dereference it here.
4571 MONO_INST_NEW (cfg
, ins
, CEE_LDIND_REF
);
4573 ins
->inst_i0
= sp
[0];
4574 ins
->type
= STACK_OBJ
;
4575 ins
->klass
= mono_class_from_mono_type (&constrained_call
->byval_arg
);
4577 } else if (cmethod
->klass
->valuetype
)
4579 constrained_call
= NULL
;
4582 if (*ip
!= CEE_CALLI
&& check_call_signature (cfg
, fsig
, sp
))
4585 if (cmethod
&& virtual &&
4586 (cmethod
->flags
& METHOD_ATTRIBUTE_VIRTUAL
) &&
4587 !((cmethod
->flags
& METHOD_ATTRIBUTE_FINAL
) &&
4588 cmethod
->wrapper_type
!= MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK
) &&
4589 mono_method_signature (cmethod
)->generic_param_count
) {
4590 MonoInst
*this_temp
, *this_arg_temp
, *store
;
4591 MonoInst
*iargs
[4];
4593 g_assert (mono_method_signature (cmethod
)->is_inflated
);
4594 /* Prevent inlining of methods that contain indirect calls */
4597 this_temp
= mono_compile_create_var (cfg
, type_from_stack_type (sp
[0]), OP_LOCAL
);
4598 this_temp
->cil_code
= ip
;
4599 NEW_TEMPSTORE (cfg
, store
, this_temp
->inst_c0
, sp
[0]);
4601 store
->cil_code
= ip
;
4602 MONO_ADD_INS (bblock
, store
);
4604 /* FIXME: This should be a managed pointer */
4605 this_arg_temp
= mono_compile_create_var (cfg
, &mono_defaults
.int_class
->byval_arg
, OP_LOCAL
);
4606 this_arg_temp
->cil_code
= ip
;
4608 NEW_TEMPLOAD (cfg
, iargs
[0], this_temp
->inst_c0
);
4609 NEW_PCONST (cfg
, iargs
[1], cmethod
);
4610 NEW_PCONST (cfg
, iargs
[2], ((MonoMethodInflated
*) cmethod
)->context
);
4611 NEW_TEMPLOADA (cfg
, iargs
[3], this_arg_temp
->inst_c0
);
4612 temp
= mono_emit_jit_icall (cfg
, bblock
, mono_helper_compile_generic_method
, iargs
, ip
);
4614 NEW_TEMPLOAD (cfg
, addr
, temp
);
4615 NEW_TEMPLOAD (cfg
, sp
[0], this_arg_temp
->inst_c0
);
4617 if ((temp
= mono_emit_calli (cfg
, bblock
, fsig
, sp
, addr
, ip
)) != -1) {
4618 NEW_TEMPLOAD (cfg
, *sp
, temp
);
4627 if ((ins_flag
& MONO_INST_TAILCALL
) && cmethod
&& (*ip
== CEE_CALL
) &&
4628 (mono_metadata_signature_equal (mono_method_signature (method
), mono_method_signature (cmethod
)))) {
4631 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
4633 /* FIXME: This assumes the two methods has the same number and type of arguments */
4635 * We implement tail calls by storing the actual arguments into the
4636 * argument variables, then emitting a CEE_JMP. Since the actual arguments
4637 * can refer to the arg variables, we have to spill them.
4639 handle_loaded_temps (cfg
, bblock
, sp
, sp
+ n
);
4640 for (i
= 0; i
< n
; ++i
) {
4641 /* Prevent argument from being register allocated */
4642 arg_array
[i
]->flags
|= MONO_INST_VOLATILE
;
4644 /* Check if argument is the same */
4646 * FIXME: This loses liveness info, so it can only be done if the
4647 * argument is not register allocated.
4649 NEW_ARGLOAD (cfg
, ins
, i
);
4650 if ((ins
->opcode
== sp
[i
]->opcode
) && (ins
->inst_i0
== sp
[i
]->inst_i0
))
4653 NEW_ARGSTORE (cfg
, ins
, i
, sp
[i
]);
4655 if (ins
->opcode
== CEE_STOBJ
) {
4656 NEW_ARGLOADA (cfg
, ins
, i
);
4657 handle_stobj (cfg
, bblock
, ins
, sp
[i
], sp
[i
]->cil_code
, ins
->klass
, FALSE
, FALSE
, FALSE
);
4660 MONO_ADD_INS (bblock
, ins
);
4662 MONO_INST_NEW (cfg
, ins
, CEE_JMP
);
4664 ins
->inst_p0
= cmethod
;
4665 ins
->inst_p1
= arg_array
[0];
4666 MONO_ADD_INS (bblock
, ins
);
4667 link_bblock (cfg
, bblock
, end_bblock
);
4668 start_new_bblock
= 1;
4669 /* skip CEE_RET as well */
4674 if (cmethod
&& (cfg
->opt
& MONO_OPT_INTRINS
) && (ins
= mini_get_inst_for_method (cfg
, cmethod
, fsig
, sp
))) {
4677 if (MONO_TYPE_IS_VOID (fsig
->ret
)) {
4678 MONO_ADD_INS (bblock
, ins
);
4680 type_to_eval_stack_type (fsig
->ret
, ins
);
4690 handle_loaded_temps (cfg
, bblock
, stack_start
, sp
);
4692 if ((cfg
->opt
& MONO_OPT_INLINE
) && cmethod
&&
4693 (!virtual || !(cmethod
->flags
& METHOD_ATTRIBUTE_VIRTUAL
) || (cmethod
->flags
& METHOD_ATTRIBUTE_FINAL
)) &&
4694 mono_method_check_inlining (cfg
, cmethod
) &&
4695 !g_list_find (dont_inline
, cmethod
)) {
4697 MonoBasicBlock
*ebblock
;
4698 gboolean allways
= FALSE
;
4700 if ((cmethod
->iflags
& METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
) ||
4701 (cmethod
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
)) {
4702 /* Prevent inlining of methods that call wrappers */
4704 cmethod
= mono_marshal_get_native_wrapper (cmethod
);
4708 if ((costs
= inline_method (cfg
, cmethod
, fsig
, bblock
, sp
, ip
, real_offset
, dont_inline
, &ebblock
, allways
))) {
4712 GET_BBLOCK (cfg
, bbhash
, bblock
, ip
);
4713 ebblock
->next_bb
= bblock
;
4714 link_bblock (cfg
, ebblock
, bblock
);
4716 if (!MONO_TYPE_IS_VOID (fsig
->ret
))
4719 /* indicates start of a new block, and triggers a load of all
4720 stack arguments at bb boundarie */
4723 inline_costs
+= costs
;
4729 inline_costs
+= 10 * num_calls
++;
4731 /* tail recursion elimination */
4732 if ((cfg
->opt
& MONO_OPT_TAILC
) && *ip
== CEE_CALL
&& cmethod
== method
&& ip
[5] == CEE_RET
) {
4733 gboolean has_vtargs
= FALSE
;
4736 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
4738 /* keep it simple */
4739 for (i
= fsig
->param_count
- 1; i
>= 0; i
--) {
4740 if (MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod
)->params
[i
]))
4745 for (i
= 0; i
< n
; ++i
) {
4746 NEW_ARGSTORE (cfg
, ins
, i
, sp
[i
]);
4748 MONO_ADD_INS (bblock
, ins
);
4750 MONO_INST_NEW (cfg
, ins
, CEE_BR
);
4752 MONO_ADD_INS (bblock
, ins
);
4753 tblock
= start_bblock
->out_bb
[0];
4754 link_bblock (cfg
, bblock
, tblock
);
4755 ins
->inst_target_bb
= tblock
;
4756 start_new_bblock
= 1;
4758 /* skip the CEE_RET, too */
4759 if (ip_in_bb (cfg
, bblock
, ip
+ 5))
4768 if (*ip
== CEE_CALLI
) {
4769 /* Prevent inlining of methods with indirect calls */
4771 if ((temp
= mono_emit_calli (cfg
, bblock
, fsig
, sp
, addr
, ip
)) != -1) {
4772 NEW_TEMPLOAD (cfg
, *sp
, temp
);
4775 } else if (array_rank
) {
4778 if (strcmp (cmethod
->name
, "Set") == 0) { /* array Set */
4779 if (sp
[fsig
->param_count
]->type
== STACK_OBJ
) {
4780 MonoInst
*iargs
[2];
4781 MonoInst
*array
, *to_store
, *store
;
4783 handle_loaded_temps (cfg
, bblock
, stack_start
, sp
);
4785 array
= mono_compile_create_var (cfg
, type_from_stack_type (sp
[0]), OP_LOCAL
);
4786 NEW_TEMPSTORE (cfg
, store
, array
->inst_c0
, sp
[0]);
4787 store
->cil_code
= ip
;
4788 MONO_ADD_INS (bblock
, store
);
4789 NEW_TEMPLOAD (cfg
, iargs
[0], array
->inst_c0
);
4791 to_store
= mono_compile_create_var (cfg
, type_from_stack_type (sp
[fsig
->param_count
]), OP_LOCAL
);
4792 NEW_TEMPSTORE (cfg
, store
, to_store
->inst_c0
, sp
[fsig
->param_count
]);
4793 store
->cil_code
= ip
;
4794 MONO_ADD_INS (bblock
, store
);
4795 NEW_TEMPLOAD (cfg
, iargs
[1], to_store
->inst_c0
);
4798 * We first save the args for the call so that the args are copied to the stack
4799 * and a new instruction tree for them is created. If we don't do this,
4800 * the same MonoInst is added to two different trees and this is not
4803 mono_emit_jit_icall (cfg
, bblock
, mono_helper_stelem_ref_check
, iargs
, ip
);
4805 NEW_TEMPLOAD (cfg
, sp
[0], array
->inst_c0
);
4806 NEW_TEMPLOAD (cfg
, sp
[fsig
->param_count
], to_store
->inst_c0
);
4809 addr
= mini_get_ldelema_ins (cfg
, bblock
, cmethod
, sp
, ip
, TRUE
);
4810 NEW_INDSTORE (cfg
, ins
, addr
, sp
[fsig
->param_count
], fsig
->params
[fsig
->param_count
- 1]);
4812 if (ins
->opcode
== CEE_STOBJ
) {
4813 handle_stobj (cfg
, bblock
, addr
, sp
[fsig
->param_count
], ip
, mono_class_from_mono_type (fsig
->params
[fsig
->param_count
-1]), FALSE
, FALSE
, TRUE
);
4815 MONO_ADD_INS (bblock
, ins
);
4818 } else if (strcmp (cmethod
->name
, "Get") == 0) { /* array Get */
4819 addr
= mini_get_ldelema_ins (cfg
, bblock
, cmethod
, sp
, ip
, FALSE
);
4820 NEW_INDLOAD (cfg
, ins
, addr
, fsig
->ret
);
4824 } else if (strcmp (cmethod
->name
, "Address") == 0) { /* array Address */
4825 addr
= mini_get_ldelema_ins (cfg
, bblock
, cmethod
, sp
, ip
, FALSE
);
4828 g_assert_not_reached ();
4832 /* Prevent inlining of methods which call other methods */
4834 if (ip_in_bb (cfg
, bblock
, ip
+ 5)
4835 && (!MONO_TYPE_ISSTRUCT (fsig
->ret
))
4836 && (!MONO_TYPE_IS_VOID (fsig
->ret
) || cmethod
->string_ctor
)
4837 && (CODE_IS_STLOC (ip
+ 5) || ip
[5] == CEE_POP
|| ip
[5] == CEE_RET
)) {
4838 /* no need to spill */
4839 ins
= (MonoInst
*)mono_emit_method_call (cfg
, bblock
, cmethod
, fsig
, sp
, ip
, virtual ? sp
[0] : NULL
);
4842 if ((temp
= mono_emit_method_call_spilled (cfg
, bblock
, cmethod
, fsig
, sp
, ip
, virtual ? sp
[0] : NULL
)) != -1) {
4843 NEW_TEMPLOAD (cfg
, *sp
, temp
);
4854 if (cfg
->method
!= method
) {
4855 /* return from inlined methode */
4860 //g_assert (returnvar != -1);
4861 NEW_TEMPSTORE (cfg
, store
, return_var
->inst_c0
, *sp
);
4862 store
->cil_code
= sp
[0]->cil_code
;
4863 if (store
->opcode
== CEE_STOBJ
) {
4864 g_assert_not_reached ();
4865 NEW_TEMPLOADA (cfg
, store
, return_var
->inst_c0
);
4866 /* FIXME: it is possible some optimization will pass the a heap pointer for the struct address, so we'll need the write barrier */
4867 handle_stobj (cfg
, bblock
, store
, *sp
, sp
[0]->cil_code
, return_var
->klass
, FALSE
, FALSE
, FALSE
);
4869 MONO_ADD_INS (bblock
, store
);
4873 g_assert (!return_var
);
4876 MONO_INST_NEW (cfg
, ins
, CEE_NOP
);
4877 ins
->opcode
= mono_type_to_stind (mono_method_signature (method
)->ret
);
4878 if (ins
->opcode
== CEE_STOBJ
) {
4879 NEW_RETLOADA (cfg
, ins
);
4880 /* FIXME: it is possible some optimization will pass the a heap pointer for the struct address, so we'll need the write barrier */
4881 handle_stobj (cfg
, bblock
, ins
, *sp
, ip
, ins
->klass
, FALSE
, FALSE
, FALSE
);
4883 ins
->opcode
= OP_SETRET
;
4885 ins
->inst_i0
= *sp
;;
4886 ins
->inst_i1
= NULL
;
4887 MONO_ADD_INS (bblock
, ins
);
4891 if (sp
!= stack_start
)
4893 MONO_INST_NEW (cfg
, ins
, CEE_BR
);
4894 ins
->cil_code
= ip
++;
4895 ins
->inst_target_bb
= end_bblock
;
4896 MONO_ADD_INS (bblock
, ins
);
4897 link_bblock (cfg
, bblock
, end_bblock
);
4898 start_new_bblock
= 1;
4902 MONO_INST_NEW (cfg
, ins
, CEE_BR
);
4903 ins
->cil_code
= ip
++;
4904 MONO_ADD_INS (bblock
, ins
);
4905 target
= ip
+ 1 + (signed char)(*ip
);
4907 GET_BBLOCK (cfg
, bbhash
, tblock
, target
);
4908 link_bblock (cfg
, bblock
, tblock
);
4909 CHECK_BBLOCK (target
, ip
, tblock
);
4910 ins
->inst_target_bb
= tblock
;
4911 if (sp
!= stack_start
) {
4912 handle_stack_args (cfg
, bblock
, stack_start
, sp
- stack_start
);
4914 CHECK_UNVERIFIABLE (cfg
);
4916 start_new_bblock
= 1;
4917 inline_costs
+= BRANCH_COST
;
4923 if (sp
[-1]->type
== STACK_VTYPE
|| sp
[-1]->type
== STACK_R8
)
4925 MONO_INST_NEW (cfg
, ins
, *ip
+ BIG_BRANCH_OFFSET
);
4926 ins
->cil_code
= ip
++;
4927 target
= ip
+ 1 + *(signed char*)ip
;
4929 ADD_UNCOND (ins
->opcode
== CEE_BRTRUE
);
4930 if (sp
!= stack_start
) {
4931 handle_stack_args (cfg
, bblock
, stack_start
, sp
- stack_start
);
4933 CHECK_UNVERIFIABLE (cfg
);
4935 inline_costs
+= BRANCH_COST
;
4949 MONO_INST_NEW (cfg
, ins
, *ip
+ BIG_BRANCH_OFFSET
);
4950 ins
->cil_code
= ip
++;
4951 target
= ip
+ 1 + *(signed char*)ip
;
4953 #ifdef MONO_ARCH_SOFT_FLOAT
4954 if (sp
[-1]->type
== STACK_R8
|| sp
[-2]->type
== STACK_R8
) {
4955 ins
->opcode
= condbr_to_fp_br (ins
->opcode
);
4957 ins
->inst_left
= sp
[0];
4958 ins
->inst_right
= sp
[1];
4959 ins
->type
= STACK_I4
;
4960 *sp
++ = emit_tree (cfg
, bblock
, ins
, ins
->cil_code
);
4961 MONO_INST_NEW (cfg
, ins
, CEE_BRTRUE
);
4969 if (sp
!= stack_start
) {
4970 handle_stack_args (cfg
, bblock
, stack_start
, sp
- stack_start
);
4972 CHECK_UNVERIFIABLE (cfg
);
4974 inline_costs
+= BRANCH_COST
;
4978 MONO_INST_NEW (cfg
, ins
, CEE_BR
);
4979 ins
->cil_code
= ip
++;
4980 MONO_ADD_INS (bblock
, ins
);
4981 target
= ip
+ 4 + (gint32
)read32(ip
);
4983 GET_BBLOCK (cfg
, bbhash
, tblock
, target
);
4984 link_bblock (cfg
, bblock
, tblock
);
4985 CHECK_BBLOCK (target
, ip
, tblock
);
4986 ins
->inst_target_bb
= tblock
;
4987 if (sp
!= stack_start
) {
4988 handle_stack_args (cfg
, bblock
, stack_start
, sp
- stack_start
);
4990 CHECK_UNVERIFIABLE (cfg
);
4992 start_new_bblock
= 1;
4993 inline_costs
+= BRANCH_COST
;
4999 if (sp
[-1]->type
== STACK_VTYPE
|| sp
[-1]->type
== STACK_R8
)
5001 MONO_INST_NEW (cfg
, ins
, *ip
);
5002 ins
->cil_code
= ip
++;
5003 target
= ip
+ 4 + (gint32
)read32(ip
);
5005 ADD_UNCOND(ins
->opcode
== CEE_BRTRUE
);
5006 if (sp
!= stack_start
) {
5007 handle_stack_args (cfg
, bblock
, stack_start
, sp
- stack_start
);
5009 CHECK_UNVERIFIABLE (cfg
);
5011 inline_costs
+= BRANCH_COST
;
5025 MONO_INST_NEW (cfg
, ins
, *ip
);
5026 ins
->cil_code
= ip
++;
5027 target
= ip
+ 4 + (gint32
)read32(ip
);
5029 #ifdef MONO_ARCH_SOFT_FLOAT
5030 if (sp
[-1]->type
== STACK_R8
|| sp
[-2]->type
== STACK_R8
) {
5031 ins
->opcode
= condbr_to_fp_br (ins
->opcode
);
5033 ins
->inst_left
= sp
[0];
5034 ins
->inst_right
= sp
[1];
5035 ins
->type
= STACK_I4
;
5036 *sp
++ = emit_tree (cfg
, bblock
, ins
, ins
->cil_code
);
5037 MONO_INST_NEW (cfg
, ins
, CEE_BRTRUE
);
5045 if (sp
!= stack_start
) {
5046 handle_stack_args (cfg
, bblock
, stack_start
, sp
- stack_start
);
5048 CHECK_UNVERIFIABLE (cfg
);
5050 inline_costs
+= BRANCH_COST
;
5055 n
= read32 (ip
+ 1);
5056 MONO_INST_NEW (cfg
, ins
, *ip
);
5058 ins
->inst_left
= *sp
;
5059 if ((ins
->inst_left
->type
!= STACK_I4
) && (ins
->inst_left
->type
!= STACK_PTR
))
5063 CHECK_OPSIZE (n
* sizeof (guint32
));
5064 target
= ip
+ n
* sizeof (guint32
);
5065 MONO_ADD_INS (bblock
, ins
);
5066 GET_BBLOCK (cfg
, bbhash
, tblock
, target
);
5067 link_bblock (cfg
, bblock
, tblock
);
5068 ins
->klass
= GUINT_TO_POINTER (n
);
5069 ins
->inst_many_bb
= mono_mempool_alloc (cfg
->mempool
, sizeof (MonoBasicBlock
*) * (n
+ 1));
5070 ins
->inst_many_bb
[n
] = tblock
;
5072 for (i
= 0; i
< n
; ++i
) {
5073 GET_BBLOCK (cfg
, bbhash
, tblock
, target
+ (gint32
)read32(ip
));
5074 link_bblock (cfg
, bblock
, tblock
);
5075 ins
->inst_many_bb
[i
] = tblock
;
5078 if (sp
!= stack_start
) {
5079 handle_stack_args (cfg
, bblock
, stack_start
, sp
- stack_start
);
5081 CHECK_UNVERIFIABLE (cfg
);
5083 /* Needed by the code generated in inssel.brg */
5084 mono_get_got_var (cfg
);
5085 inline_costs
+= (BRANCH_COST
* 2);
5099 MONO_INST_NEW (cfg
, ins
, *ip
);
5104 ins
->type
= ldind_type
[*ip
- CEE_LDIND_I1
];
5105 ins
->flags
|= ins_flag
;
5107 if (ins
->type
== STACK_OBJ
)
5108 ins
->klass
= mono_defaults
.object_class
;
5109 #ifdef MONO_ARCH_SOFT_FLOAT
5110 if (*ip
== CEE_LDIND_R4
) {
5113 temp
= handle_load_float (cfg
, bblock
, ins
->inst_i0
, ip
);
5114 NEW_TEMPLOAD (cfg
, *sp
, temp
);
5128 #ifdef MONO_ARCH_SOFT_FLOAT
5129 if (*ip
== CEE_STIND_R4
) {
5131 handle_store_float (cfg
, bblock
, sp
[0], sp
[1], ip
);
5136 #if HAVE_WRITE_BARRIERS
5137 if (*ip
== CEE_STIND_REF
&& method
->wrapper_type
!= MONO_WRAPPER_WRITE_BARRIER
) {
5138 /* insert call to write barrier */
5139 MonoMethod
*write_barrier
= mono_marshal_get_write_barrier ();
5141 mono_emit_method_call_spilled (cfg
, bblock
, write_barrier
, mono_method_signature (write_barrier
), sp
, ip
, NULL
);
5146 MONO_INST_NEW (cfg
, ins
, *ip
);
5147 ins
->cil_code
= ip
++;
5149 handle_loaded_temps (cfg
, bblock
, stack_start
, sp
);
5150 MONO_ADD_INS (bblock
, ins
);
5151 ins
->inst_i0
= sp
[0];
5152 ins
->inst_i1
= sp
[1];
5153 ins
->flags
|= ins_flag
;
5161 #ifdef MONO_ARCH_NO_EMULATE_MUL_IMM
5162 /* FIXME: This breaks with ssapre (mono -O=ssapre loader.exe) */
5163 if ((ins
->inst_right
->opcode
== OP_ICONST
) && !(cfg
->opt
& MONO_OPT_SSAPRE
)) {
5164 switch (ins
->opcode
) {
5166 ins
->opcode
= OP_IMUL_IMM
;
5167 ins
->inst_imm
= ins
->inst_right
->inst_c0
;
5170 ins
->opcode
= OP_LMUL_IMM
;
5171 ins
->inst_imm
= ins
->inst_right
->inst_c0
;
5174 g_assert_not_reached ();
5179 if (mono_find_jit_opcode_emulation (ins
->opcode
)) {
5181 *sp
++ = emit_tree (cfg
, bblock
, ins
, ip
+ 1);
5199 /* special case that gives a nice speedup and happens to workaorund a ppc jit but (for the release)
5200 * later apply the speedup to the left shift as well
5203 if ((ins
->opcode
== OP_LSHR_UN
) && (ins
->type
== STACK_I8
)
5204 && (ins
->inst_right
->opcode
== OP_ICONST
) && (ins
->inst_right
->inst_c0
== 32)) {
5205 ins
->opcode
= OP_LONG_SHRUN_32
;
5206 /*g_print ("applied long shr speedup to %s\n", cfg->method->name);*/
5210 if (mono_find_jit_opcode_emulation (ins
->opcode
)) {
5212 *sp
++ = emit_tree (cfg
, bblock
, ins
, ip
+ 1);
5226 case CEE_CONV_OVF_I8
:
5227 case CEE_CONV_OVF_U8
:
5231 if (mono_find_jit_opcode_emulation (ins
->opcode
)) {
5233 *sp
++ = emit_tree (cfg
, bblock
, ins
, ip
+ 1);
5237 case CEE_CONV_OVF_I4
:
5238 case CEE_CONV_OVF_I1
:
5239 case CEE_CONV_OVF_I2
:
5240 case CEE_CONV_OVF_I
:
5241 case CEE_CONV_OVF_U
:
5244 if (sp
[-1]->type
== STACK_R8
) {
5245 ADD_UNOP (CEE_CONV_OVF_I8
);
5253 case CEE_CONV_OVF_U1
:
5254 case CEE_CONV_OVF_U2
:
5255 case CEE_CONV_OVF_U4
:
5258 if (sp
[-1]->type
== STACK_R8
) {
5259 ADD_UNOP (CEE_CONV_OVF_U8
);
5267 case CEE_CONV_OVF_I1_UN
:
5268 case CEE_CONV_OVF_I2_UN
:
5269 case CEE_CONV_OVF_I4_UN
:
5270 case CEE_CONV_OVF_I8_UN
:
5271 case CEE_CONV_OVF_U1_UN
:
5272 case CEE_CONV_OVF_U2_UN
:
5273 case CEE_CONV_OVF_U4_UN
:
5274 case CEE_CONV_OVF_U8_UN
:
5275 case CEE_CONV_OVF_I_UN
:
5276 case CEE_CONV_OVF_U_UN
:
5284 token
= read32 (ip
+ 1);
5285 klass
= mini_get_class (method
, token
, generic_context
);
5286 CHECK_TYPELOAD (klass
);
5288 if (MONO_TYPE_IS_REFERENCE (&klass
->byval_arg
)) {
5289 MonoInst
*store
, *load
;
5290 MONO_INST_NEW (cfg
, load
, CEE_LDIND_REF
);
5291 load
->cil_code
= ip
;
5292 load
->inst_i0
= sp
[1];
5293 load
->type
= STACK_OBJ
;
5294 load
->klass
= klass
;
5295 load
->flags
|= ins_flag
;
5296 MONO_INST_NEW (cfg
, store
, CEE_STIND_REF
);
5297 store
->cil_code
= ip
;
5298 handle_loaded_temps (cfg
, bblock
, stack_start
, sp
);
5299 MONO_ADD_INS (bblock
, store
);
5300 store
->inst_i0
= sp
[0];
5301 store
->inst_i1
= load
;
5302 store
->flags
|= ins_flag
;
5304 n
= mono_class_value_size (klass
, NULL
);
5305 if ((cfg
->opt
& MONO_OPT_INTRINS
) && n
<= sizeof (gpointer
) * 5) {
5307 MONO_INST_NEW (cfg
, copy
, OP_MEMCPY
);
5308 copy
->inst_left
= sp
[0];
5309 copy
->inst_right
= sp
[1];
5310 copy
->cil_code
= ip
;
5311 copy
->backend
.size
= n
;
5312 MONO_ADD_INS (bblock
, copy
);
5314 MonoMethod
*memcpy_method
= get_memcpy_method ();
5315 MonoInst
*iargs
[3];
5318 NEW_ICONST (cfg
, iargs
[2], n
);
5319 iargs
[2]->cil_code
= ip
;
5321 mono_emit_method_call_spilled (cfg
, bblock
, memcpy_method
, memcpy_method
->signature
, iargs
, ip
, NULL
);
5328 MonoInst
*iargs
[3];
5334 token
= read32 (ip
+ 1);
5335 klass
= mini_get_class (method
, token
, generic_context
);
5336 CHECK_TYPELOAD (klass
);
5337 if (MONO_TYPE_IS_REFERENCE (&klass
->byval_arg
)) {
5338 MONO_INST_NEW (cfg
, ins
, CEE_LDIND_REF
);
5340 ins
->inst_i0
= sp
[0];
5341 ins
->type
= STACK_OBJ
;
5343 ins
->flags
|= ins_flag
;
5350 /* Optimize the common ldobj+stloc combination */
5360 loc_index
= ip
[5] - CEE_STLOC_0
;
5367 if ((loc_index
!= -1) && ip_in_bb (cfg
, bblock
, ip
+ 5)) {
5368 CHECK_LOCAL (loc_index
);
5369 NEW_LOCSTORE (cfg
, ins
, loc_index
, *sp
);
5371 if (ins
->opcode
== CEE_STOBJ
) {
5372 handle_loaded_temps (cfg
, bblock
, stack_start
, sp
);
5374 g_assert (ins
->opcode
== CEE_STOBJ
);
5375 NEW_LOCLOADA (cfg
, ins
, loc_index
);
5376 handle_stobj (cfg
, bblock
, ins
, *sp
, ip
, ins
->klass
, FALSE
, FALSE
, FALSE
);
5383 n
= mono_class_value_size (klass
, NULL
);
5384 ins
= mono_compile_create_var (cfg
, &klass
->byval_arg
, OP_LOCAL
);
5385 NEW_TEMPLOADA (cfg
, iargs
[0], ins
->inst_c0
);
5386 if ((cfg
->opt
& MONO_OPT_INTRINS
) && n
<= sizeof (gpointer
) * 5) {
5388 MONO_INST_NEW (cfg
, copy
, OP_MEMCPY
);
5389 copy
->inst_left
= iargs
[0];
5390 copy
->inst_right
= *sp
;
5391 copy
->cil_code
= ip
;
5392 copy
->backend
.size
= n
;
5393 MONO_ADD_INS (bblock
, copy
);
5395 MonoMethod
*memcpy_method
= get_memcpy_method ();
5397 NEW_ICONST (cfg
, iargs
[2], n
);
5398 iargs
[2]->cil_code
= ip
;
5400 mono_emit_method_call_spilled (cfg
, bblock
, memcpy_method
, memcpy_method
->signature
, iargs
, ip
, NULL
);
5402 NEW_TEMPLOAD (cfg
, *sp
, ins
->inst_c0
);
5410 CHECK_STACK_OVF (1);
5412 n
= read32 (ip
+ 1);
5414 if (method
->wrapper_type
== MONO_WRAPPER_DYNAMIC_METHOD
) {
5415 NEW_PCONST (cfg
, ins
, mono_method_get_wrapper_data (method
, n
));
5417 ins
->type
= STACK_OBJ
;
5418 ins
->klass
= mono_defaults
.string_class
;
5421 else if (method
->wrapper_type
!= MONO_WRAPPER_NONE
) {
5423 MonoInst
*iargs
[1];
5425 NEW_PCONST (cfg
, iargs
[0], mono_method_get_wrapper_data (method
, n
));
5426 temp
= mono_emit_jit_icall (cfg
, bblock
, mono_string_new_wrapper
, iargs
, ip
);
5427 NEW_TEMPLOAD (cfg
, *sp
, temp
);
5431 if (cfg
->opt
& MONO_OPT_SHARED
) {
5433 MonoInst
*iargs
[3];
5434 MonoInst
* domain_var
;
5436 if (cfg
->compile_aot
) {
5437 cfg
->ldstr_list
= g_list_prepend (cfg
->ldstr_list
, GINT_TO_POINTER (n
));
5439 /* avoid depending on undefined C behavior in sequence points */
5440 domain_var
= mono_get_domainvar (cfg
);
5441 NEW_TEMPLOAD (cfg
, iargs
[0], domain_var
->inst_c0
);
5442 NEW_IMAGECONST (cfg
, iargs
[1], image
);
5443 NEW_ICONST (cfg
, iargs
[2], mono_metadata_token_index (n
));
5444 temp
= mono_emit_jit_icall (cfg
, bblock
, mono_ldstr
, iargs
, ip
);
5445 NEW_TEMPLOAD (cfg
, *sp
, temp
);
5446 mono_ldstr (cfg
->domain
, image
, mono_metadata_token_index (n
));
5448 if (bblock
->out_of_line
) {
5449 MonoInst
*iargs
[2];
5452 if (cfg
->compile_aot
&& cfg
->method
->klass
->image
== mono_defaults
.corlib
) {
5454 * Avoid relocations by using a version of helper_ldstr
5455 * specialized to mscorlib.
5457 NEW_ICONST (cfg
, iargs
[0], mono_metadata_token_index (n
));
5458 temp
= mono_emit_jit_icall (cfg
, bblock
, mono_helper_ldstr_mscorlib
, iargs
, ip
);
5460 /* Avoid creating the string object */
5461 NEW_IMAGECONST (cfg
, iargs
[0], image
);
5462 NEW_ICONST (cfg
, iargs
[1], mono_metadata_token_index (n
));
5463 temp
= mono_emit_jit_icall (cfg
, bblock
, mono_helper_ldstr
, iargs
, ip
);
5465 NEW_TEMPLOAD (cfg
, *sp
, temp
);
5468 if (cfg
->compile_aot
) {
5469 NEW_LDSTRCONST (cfg
, ins
, image
, n
);
5473 NEW_PCONST (cfg
, ins
, NULL
);
5475 ins
->type
= STACK_OBJ
;
5476 ins
->inst_p0
= mono_ldstr (cfg
->domain
, image
, mono_metadata_token_index (n
));
5477 ins
->klass
= mono_defaults
.string_class
;
5487 MonoInst
*iargs
[2];
5488 MonoMethodSignature
*fsig
;
5492 token
= read32 (ip
+ 1);
5493 cmethod
= mini_get_method (method
, token
, NULL
, generic_context
);
5496 fsig
= mono_method_get_signature (cmethod
, image
, token
);
5498 if (!mono_class_init (cmethod
->klass
))
5501 if (mono_use_security_manager
) {
5502 if (check_linkdemand (cfg
, method
, cmethod
, bblock
, ip
))
5506 n
= fsig
->param_count
;
5509 /* move the args to allow room for 'this' in the first position */
5515 handle_loaded_temps (cfg
, bblock
, stack_start
, sp
);
5517 if (mini_class_is_system_array (cmethod
->klass
)) {
5518 NEW_METHODCONST (cfg
, *sp
, cmethod
);
5519 temp
= handle_array_new (cfg
, bblock
, fsig
->param_count
, sp
, ip
);
5520 } else if (cmethod
->string_ctor
) {
5521 /* we simply pass a null pointer */
5522 NEW_PCONST (cfg
, *sp
, NULL
);
5523 /* now call the string ctor */
5524 temp
= mono_emit_method_call_spilled (cfg
, bblock
, cmethod
, fsig
, sp
, ip
, NULL
);
5526 MonoInst
* callvirt_this_arg
= NULL
;
5528 if (cmethod
->klass
->valuetype
) {
5529 iargs
[0] = mono_compile_create_var (cfg
, &cmethod
->klass
->byval_arg
, OP_LOCAL
);
5530 temp
= iargs
[0]->inst_c0
;
5532 NEW_TEMPLOADA (cfg
, *sp
, temp
);
5534 handle_initobj (cfg
, bblock
, *sp
, NULL
, cmethod
->klass
, stack_start
, sp
);
5536 NEW_TEMPLOADA (cfg
, *sp
, temp
);
5539 * The code generated by mini_emit_virtual_call () expects
5540 * iargs [0] to be a boxed instance, but luckily the vcall
5541 * will be transformed into a normal call there.
5544 temp
= handle_alloc (cfg
, bblock
, cmethod
->klass
, FALSE
, ip
);
5545 NEW_TEMPLOAD (cfg
, *sp
, temp
);
5548 /* Avoid virtual calls to ctors if possible */
5549 if (cmethod
->klass
->marshalbyref
)
5550 callvirt_this_arg
= sp
[0];
5552 if ((cfg
->opt
& MONO_OPT_INLINE
) && cmethod
&&
5553 mono_method_check_inlining (cfg
, cmethod
) &&
5554 !mono_class_is_subclass_of (cmethod
->klass
, mono_defaults
.exception_class
, FALSE
) &&
5555 !g_list_find (dont_inline
, cmethod
)) {
5557 MonoBasicBlock
*ebblock
;
5558 if ((costs
= inline_method (cfg
, cmethod
, fsig
, bblock
, sp
, ip
, real_offset
, dont_inline
, &ebblock
, FALSE
))) {
5563 GET_BBLOCK (cfg
, bbhash
, bblock
, ip
);
5564 ebblock
->next_bb
= bblock
;
5565 link_bblock (cfg
, ebblock
, bblock
);
5567 NEW_TEMPLOAD (cfg
, *sp
, temp
);
5570 /* indicates start of a new block, and triggers a load
5571 of all stack arguments at bb boundarie */
5574 inline_costs
+= costs
;
5578 /* Prevent inlining of methods which call other methods */
5580 mono_emit_method_call_spilled (cfg
, bblock
, cmethod
, fsig
, sp
, ip
, callvirt_this_arg
);
5583 /* Prevent inlining of methods which call other methods */
5585 /* now call the actual ctor */
5586 mono_emit_method_call_spilled (cfg
, bblock
, cmethod
, fsig
, sp
, ip
, callvirt_this_arg
);
5590 NEW_TEMPLOAD (cfg
, *sp
, temp
);
5601 token
= read32 (ip
+ 1);
5602 klass
= mini_get_class (method
, token
, generic_context
);
5603 CHECK_TYPELOAD (klass
);
5604 if (sp
[0]->type
!= STACK_OBJ
)
5607 /* Needed by the code generated in inssel.brg */
5608 mono_get_got_var (cfg
);
5610 if (klass
->marshalbyref
|| klass
->flags
& TYPE_ATTRIBUTE_INTERFACE
) {
5612 MonoMethod
*mono_isinst
;
5613 MonoInst
*iargs
[1];
5614 MonoBasicBlock
*ebblock
;
5618 mono_isinst
= mono_marshal_get_isinst (klass
);
5621 costs
= inline_method (cfg
, mono_isinst
, mono_method_signature (mono_isinst
), bblock
,
5622 iargs
, ip
, real_offset
, dont_inline
, &ebblock
, TRUE
);
5624 g_assert (costs
> 0);
5629 GET_BBLOCK (cfg
, bbhash
, bblock
, ip
);
5630 ebblock
->next_bb
= bblock
;
5631 link_bblock (cfg
, ebblock
, bblock
);
5633 temp
= iargs
[0]->inst_i0
->inst_c0
;
5634 NEW_TEMPLOAD (cfg
, *sp
, temp
);
5638 inline_costs
+= costs
;
5640 MONO_INST_NEW (cfg
, ins
, *ip
);
5641 ins
->type
= STACK_OBJ
;
5642 ins
->inst_left
= *sp
;
5643 ins
->inst_newa_class
= klass
;
5646 *sp
++ = emit_tree (cfg
, bblock
, ins
, ip
+ 5);
5650 case CEE_UNBOX_ANY
: {
5651 MonoInst
*add
, *vtoffset
;
5652 MonoInst
*iargs
[3];
5657 token
= read32 (ip
+ 1);
5658 klass
= mini_get_class (method
, token
, generic_context
);
5659 CHECK_TYPELOAD (klass
);
5661 if (MONO_TYPE_IS_REFERENCE (&klass
->byval_arg
)) {
5663 if (klass
->marshalbyref
|| klass
->flags
& TYPE_ATTRIBUTE_INTERFACE
) {
5664 MonoMethod
*mono_castclass
;
5665 MonoInst
*iargs
[1];
5666 MonoBasicBlock
*ebblock
;
5670 mono_castclass
= mono_marshal_get_castclass (klass
);
5673 costs
= inline_method (cfg
, mono_castclass
, mono_method_signature (mono_castclass
), bblock
,
5674 iargs
, ip
, real_offset
, dont_inline
, &ebblock
, TRUE
);
5676 g_assert (costs
> 0);
5681 GET_BBLOCK (cfg
, bbhash
, bblock
, ip
);
5682 ebblock
->next_bb
= bblock
;
5683 link_bblock (cfg
, ebblock
, bblock
);
5685 temp
= iargs
[0]->inst_i0
->inst_c0
;
5686 NEW_TEMPLOAD (cfg
, *sp
, temp
);
5690 inline_costs
+= costs
;
5692 MONO_INST_NEW (cfg
, ins
, CEE_CASTCLASS
);
5693 ins
->type
= STACK_OBJ
;
5694 ins
->inst_left
= *sp
;
5696 ins
->inst_newa_class
= klass
;
5704 if (mono_class_is_nullable (klass
)) {
5705 int v
= handle_unbox_nullable (cfg
, bblock
, *sp
, ip
, klass
);
5706 NEW_TEMPLOAD (cfg
, *sp
, v
);
5712 MONO_INST_NEW (cfg
, ins
, OP_UNBOXCAST
);
5713 ins
->type
= STACK_OBJ
;
5714 ins
->inst_left
= *sp
;
5716 ins
->inst_newa_class
= klass
;
5719 MONO_INST_NEW (cfg
, add
, OP_PADD
);
5720 NEW_ICONST (cfg
, vtoffset
, sizeof (MonoObject
));
5721 add
->inst_left
= ins
;
5722 add
->inst_right
= vtoffset
;
5723 add
->type
= STACK_MP
;
5724 add
->klass
= mono_defaults
.object_class
;
5728 n
= mono_class_value_size (klass
, NULL
);
5729 ins
= mono_compile_create_var (cfg
, &klass
->byval_arg
, OP_LOCAL
);
5730 NEW_TEMPLOADA (cfg
, iargs
[0], ins
->inst_c0
);
5731 if ((cfg
->opt
& MONO_OPT_INTRINS
) && n
<= sizeof (gpointer
) * 5) {
5733 MONO_INST_NEW (cfg
, copy
, OP_MEMCPY
);
5734 copy
->inst_left
= iargs
[0];
5735 copy
->inst_right
= *sp
;
5736 copy
->cil_code
= ip
;
5737 copy
->backend
.size
= n
;
5738 MONO_ADD_INS (bblock
, copy
);
5740 MonoMethod
*memcpy_method
= get_memcpy_method ();
5742 NEW_ICONST (cfg
, iargs
[2], n
);
5743 iargs
[2]->cil_code
= ip
;
5745 mono_emit_method_call_spilled (cfg
, bblock
, memcpy_method
, memcpy_method
->signature
, iargs
, ip
, NULL
);
5747 NEW_TEMPLOAD (cfg
, *sp
, ins
->inst_c0
);
5753 MonoInst
*add
, *vtoffset
;
5758 token
= read32 (ip
+ 1);
5759 klass
= mini_get_class (method
, token
, generic_context
);
5760 CHECK_TYPELOAD (klass
);
5762 if (mono_class_is_nullable (klass
)) {
5763 int v
= handle_unbox_nullable (cfg
, bblock
, *sp
, ip
, klass
);
5764 NEW_TEMPLOAD (cfg
, *sp
, v
);
5770 /* Needed by the code generated in inssel.brg */
5771 mono_get_got_var (cfg
);
5773 MONO_INST_NEW (cfg
, ins
, OP_UNBOXCAST
);
5774 ins
->type
= STACK_OBJ
;
5775 ins
->inst_left
= *sp
;
5777 ins
->inst_newa_class
= klass
;
5780 MONO_INST_NEW (cfg
, add
, OP_PADD
);
5781 NEW_ICONST (cfg
, vtoffset
, sizeof (MonoObject
));
5782 add
->inst_left
= ins
;
5783 add
->inst_right
= vtoffset
;
5784 add
->type
= STACK_MP
;
5795 token
= read32 (ip
+ 1);
5796 klass
= mini_get_class (method
, token
, generic_context
);
5797 CHECK_TYPELOAD (klass
);
5798 if (sp
[0]->type
!= STACK_OBJ
)
5801 /* Needed by the code generated in inssel.brg */
5802 mono_get_got_var (cfg
);
5804 if (klass
->marshalbyref
|| klass
->flags
& TYPE_ATTRIBUTE_INTERFACE
) {
5806 MonoMethod
*mono_castclass
;
5807 MonoInst
*iargs
[1];
5808 MonoBasicBlock
*ebblock
;
5812 mono_castclass
= mono_marshal_get_castclass (klass
);
5815 costs
= inline_method (cfg
, mono_castclass
, mono_method_signature (mono_castclass
), bblock
,
5816 iargs
, ip
, real_offset
, dont_inline
, &ebblock
, TRUE
);
5818 g_assert (costs
> 0);
5823 GET_BBLOCK (cfg
, bbhash
, bblock
, ip
);
5824 ebblock
->next_bb
= bblock
;
5825 link_bblock (cfg
, ebblock
, bblock
);
5827 temp
= iargs
[0]->inst_i0
->inst_c0
;
5828 NEW_TEMPLOAD (cfg
, *sp
, temp
);
5832 inline_costs
+= costs
;
5834 MONO_INST_NEW (cfg
, ins
, *ip
);
5835 ins
->type
= STACK_OBJ
;
5836 ins
->inst_left
= *sp
;
5838 ins
->inst_newa_class
= klass
;
5840 *sp
++ = emit_tree (cfg
, bblock
, ins
, ip
+ 5);
5846 MONO_INST_NEW (cfg
, ins
, *ip
);
5848 ins
->inst_left
= *sp
;
5849 ins
->cil_code
= ip
++;
5850 bblock
->out_of_line
= TRUE
;
5851 MONO_ADD_INS (bblock
, ins
);
5852 MONO_INST_NEW (cfg
, ins
, OP_NOT_REACHED
);
5853 ins
->cil_code
= ip
- 1;
5854 MONO_ADD_INS (bblock
, ins
);
5857 link_bblock (cfg
, bblock
, end_bblock
);
5858 start_new_bblock
= 1;
5863 MonoInst
*offset_ins
;
5864 MonoClassField
*field
;
5865 MonoBasicBlock
*ebblock
;
5869 if (*ip
== CEE_STFLD
) {
5876 if (sp
[0]->type
== STACK_I4
|| sp
[0]->type
== STACK_I8
|| sp
[0]->type
== STACK_R8
)
5878 if (*ip
!= CEE_LDFLD
&& sp
[0]->type
== STACK_VTYPE
)
5881 token
= read32 (ip
+ 1);
5882 if (method
->wrapper_type
!= MONO_WRAPPER_NONE
) {
5883 field
= mono_method_get_wrapper_data (method
, token
);
5884 klass
= field
->parent
;
5886 field
= mono_field_from_token (image
, token
, &klass
, generic_context
);
5890 mono_class_init (klass
);
5891 if (!dont_verify
&& !cfg
->skip_visibility
&& !can_access_field (method
, field
))
5894 foffset
= klass
->valuetype
? field
->offset
- sizeof (MonoObject
): field
->offset
;
5895 /* FIXME: mark instructions for use in SSA */
5896 if (*ip
== CEE_STFLD
) {
5897 if (target_type_is_incompatible (cfg
, field
->type
, sp
[1]))
5899 if ((klass
->marshalbyref
&& !MONO_CHECK_THIS (sp
[0])) || klass
->contextbound
|| klass
== mono_defaults
.marshalbyrefobject_class
) {
5900 MonoMethod
*stfld_wrapper
= mono_marshal_get_stfld_wrapper (field
->type
);
5901 MonoInst
*iargs
[5];
5904 NEW_CLASSCONST (cfg
, iargs
[1], klass
);
5905 NEW_FIELDCONST (cfg
, iargs
[2], field
);
5906 NEW_ICONST (cfg
, iargs
[3], klass
->valuetype
? field
->offset
- sizeof (MonoObject
) :
5910 if (cfg
->opt
& MONO_OPT_INLINE
) {
5911 costs
= inline_method (cfg
, stfld_wrapper
, mono_method_signature (stfld_wrapper
), bblock
,
5912 iargs
, ip
, real_offset
, dont_inline
, &ebblock
, TRUE
);
5913 g_assert (costs
> 0);
5918 GET_BBLOCK (cfg
, bbhash
, bblock
, ip
);
5919 ebblock
->next_bb
= bblock
;
5920 link_bblock (cfg
, ebblock
, bblock
);
5922 /* indicates start of a new block, and triggers a load
5923 of all stack arguments at bb boundarie */
5926 inline_costs
+= costs
;
5929 mono_emit_method_call_spilled (cfg
, bblock
, stfld_wrapper
, mono_method_signature (stfld_wrapper
), iargs
, ip
, NULL
);
5931 #if HAVE_WRITE_BARRIERS
5932 } else if (mono_type_to_stind (field
->type
) == CEE_STIND_REF
) {
5933 /* insert call to write barrier */
5934 MonoMethod
*write_barrier
= mono_marshal_get_write_barrier ();
5935 MonoInst
*iargs
[2];
5936 NEW_ICONST (cfg
, offset_ins
, foffset
);
5937 MONO_INST_NEW (cfg
, ins
, OP_PADD
);
5939 ins
->inst_left
= *sp
;
5940 ins
->inst_right
= offset_ins
;
5941 ins
->type
= STACK_MP
;
5942 ins
->klass
= mono_defaults
.object_class
;
5945 mono_emit_method_call_spilled (cfg
, bblock
, write_barrier
, mono_method_signature (write_barrier
), iargs
, ip
, NULL
);
5947 #ifdef MONO_ARCH_SOFT_FLOAT
5948 } else if (mono_type_to_stind (field
->type
) == CEE_STIND_R4
) {
5949 NEW_ICONST (cfg
, offset_ins
, foffset
);
5950 MONO_INST_NEW (cfg
, ins
, OP_PADD
);
5952 ins
->inst_left
= *sp
;
5953 ins
->inst_right
= offset_ins
;
5954 ins
->type
= STACK_MP
;
5955 ins
->klass
= mono_defaults
.object_class
;
5956 handle_store_float (cfg
, bblock
, ins
, sp
[1], ip
);
5960 NEW_ICONST (cfg
, offset_ins
, foffset
);
5961 MONO_INST_NEW (cfg
, ins
, OP_PADD
);
5963 ins
->inst_left
= *sp
;
5964 ins
->inst_right
= offset_ins
;
5965 ins
->type
= STACK_MP
;
5967 MONO_INST_NEW (cfg
, store
, mono_type_to_stind (field
->type
));
5968 store
->cil_code
= ip
;
5969 store
->inst_left
= ins
;
5970 store
->inst_right
= sp
[1];
5971 handle_loaded_temps (cfg
, bblock
, stack_start
, sp
);
5972 store
->flags
|= ins_flag
;
5974 if (store
->opcode
== CEE_STOBJ
) {
5975 handle_stobj (cfg
, bblock
, ins
, sp
[1], ip
,
5976 mono_class_from_mono_type (field
->type
), FALSE
, FALSE
, TRUE
);
5978 MONO_ADD_INS (bblock
, store
);
5981 if ((klass
->marshalbyref
&& !MONO_CHECK_THIS (sp
[0])) || klass
->contextbound
|| klass
== mono_defaults
.marshalbyrefobject_class
) {
5982 MonoMethod
*wrapper
= (*ip
== CEE_LDFLDA
) ? mono_marshal_get_ldflda_wrapper (field
->type
) : mono_marshal_get_ldfld_wrapper (field
->type
);
5983 MonoInst
*iargs
[4];
5987 NEW_CLASSCONST (cfg
, iargs
[1], klass
);
5988 NEW_FIELDCONST (cfg
, iargs
[2], field
);
5989 NEW_ICONST (cfg
, iargs
[3], klass
->valuetype
? field
->offset
- sizeof (MonoObject
) : field
->offset
);
5990 if ((cfg
->opt
& MONO_OPT_INLINE
) && !MONO_TYPE_ISSTRUCT (mono_method_signature (wrapper
)->ret
)) {
5991 costs
= inline_method (cfg
, wrapper
, mono_method_signature (wrapper
), bblock
,
5992 iargs
, ip
, real_offset
, dont_inline
, &ebblock
, TRUE
);
5993 g_assert (costs
> 0);
5998 GET_BBLOCK (cfg
, bbhash
, bblock
, ip
);
5999 ebblock
->next_bb
= bblock
;
6000 link_bblock (cfg
, ebblock
, bblock
);
6002 temp
= iargs
[0]->inst_i0
->inst_c0
;
6004 NEW_TEMPLOAD (cfg
, *sp
, temp
);
6007 /* indicates start of a new block, and triggers a load of
6008 all stack arguments at bb boundarie */
6011 inline_costs
+= costs
;
6014 temp
= mono_emit_method_call_spilled (cfg
, bblock
, wrapper
, mono_method_signature (wrapper
), iargs
, ip
, NULL
);
6015 NEW_TEMPLOAD (cfg
, *sp
, temp
);
6019 NEW_ICONST (cfg
, offset_ins
, foffset
);
6020 MONO_INST_NEW (cfg
, ins
, OP_PADD
);
6022 ins
->inst_left
= *sp
;
6023 ins
->inst_right
= offset_ins
;
6024 ins
->type
= STACK_MP
;
6026 if (*ip
== CEE_LDFLDA
) {
6027 ins
->klass
= mono_class_from_mono_type (field
->type
);
6031 MONO_INST_NEW (cfg
, load
, mono_type_to_ldind (field
->type
));
6032 type_to_eval_stack_type (field
->type
, load
);
6033 load
->cil_code
= ip
;
6034 load
->inst_left
= ins
;
6035 load
->flags
|= ins_flag
;
6037 #ifdef MONO_ARCH_SOFT_FLOAT
6038 if (mono_type_to_ldind (field
->type
) == CEE_LDIND_R4
) {
6040 temp
= handle_load_float (cfg
, bblock
, ins
, ip
);
6041 NEW_TEMPLOAD (cfg
, *sp
, temp
);
6055 MonoClassField
*field
;
6056 gpointer addr
= NULL
;
6059 token
= read32 (ip
+ 1);
6060 if (method
->wrapper_type
!= MONO_WRAPPER_NONE
) {
6061 field
= mono_method_get_wrapper_data (method
, token
);
6062 klass
= field
->parent
;
6065 field
= mono_field_from_token (image
, token
, &klass
, generic_context
);
6068 mono_class_init (klass
);
6070 g_assert (!(field
->type
->attrs
& FIELD_ATTRIBUTE_LITERAL
));
6072 if ((*ip
) == CEE_STSFLD
)
6073 handle_loaded_temps (cfg
, bblock
, stack_start
, sp
);
6075 /* The special_static_fields field is init'd in mono_class_vtable, so it needs
6076 * to be called here.
6078 if (!(cfg
->opt
& MONO_OPT_SHARED
))
6079 mono_class_vtable (cfg
->domain
, klass
);
6080 mono_domain_lock (cfg
->domain
);
6081 if (cfg
->domain
->special_static_fields
)
6082 addr
= g_hash_table_lookup (cfg
->domain
->special_static_fields
, field
);
6083 mono_domain_unlock (cfg
->domain
);
6085 if ((cfg
->opt
& MONO_OPT_SHARED
) || (cfg
->compile_aot
&& addr
)) {
6087 MonoInst
*iargs
[2];
6088 MonoInst
*domain_var
;
6090 g_assert (field
->parent
);
6091 /* avoid depending on undefined C behavior in sequence points */
6092 domain_var
= mono_get_domainvar (cfg
);
6093 NEW_TEMPLOAD (cfg
, iargs
[0], domain_var
->inst_c0
);
6094 NEW_FIELDCONST (cfg
, iargs
[1], field
);
6095 temp
= mono_emit_jit_icall (cfg
, bblock
, mono_class_static_field_address
, iargs
, ip
);
6096 NEW_TEMPLOAD (cfg
, ins
, temp
);
6099 vtable
= mono_class_vtable (cfg
->domain
, klass
);
6101 if (mini_field_access_needs_cctor_run (cfg
, method
, vtable
) && !(g_slist_find (class_inits
, vtable
))) {
6102 guint8
*tramp
= mono_create_class_init_trampoline (vtable
);
6103 mono_emit_native_call (cfg
, bblock
, tramp
,
6104 helper_sig_class_init_trampoline
,
6105 NULL
, ip
, FALSE
, FALSE
);
6106 if (cfg
->verbose_level
> 2)
6107 g_print ("class %s.%s needs init call for %s\n", klass
->name_space
, klass
->name
, field
->name
);
6108 class_inits
= g_slist_prepend (class_inits
, vtable
);
6110 if (cfg
->run_cctors
) {
6111 /* This makes so that inline cannot trigger */
6112 /* .cctors: too many apps depend on them */
6113 /* running with a specific order... */
6114 if (! vtable
->initialized
)
6116 mono_runtime_class_init (vtable
);
6119 addr
= (char*)vtable
->data
+ field
->offset
;
6121 if (cfg
->compile_aot
)
6122 NEW_SFLDACONST (cfg
, ins
, field
);
6124 NEW_PCONST (cfg
, ins
, addr
);
6128 * insert call to mono_threads_get_static_data (GPOINTER_TO_UINT (addr))
6129 * This could be later optimized to do just a couple of
6130 * memory dereferences with constant offsets.
6133 MonoInst
*iargs
[1];
6134 NEW_ICONST (cfg
, iargs
[0], GPOINTER_TO_UINT (addr
));
6135 temp
= mono_emit_jit_icall (cfg
, bblock
, mono_get_special_static_data
, iargs
, ip
);
6136 NEW_TEMPLOAD (cfg
, ins
, temp
);
6140 /* FIXME: mark instructions for use in SSA */
6141 if (*ip
== CEE_LDSFLDA
) {
6142 ins
->klass
= mono_class_from_mono_type (field
->type
);
6144 } else if (*ip
== CEE_STSFLD
) {
6148 MONO_INST_NEW (cfg
, store
, mono_type_to_stind (field
->type
));
6149 store
->cil_code
= ip
;
6150 store
->inst_left
= ins
;
6151 store
->inst_right
= sp
[0];
6152 store
->flags
|= ins_flag
;
6155 if (store
->opcode
== CEE_STOBJ
) {
6156 handle_stobj (cfg
, bblock
, ins
, sp
[0], ip
, mono_class_from_mono_type (field
->type
), FALSE
, FALSE
, FALSE
);
6158 MONO_ADD_INS (bblock
, store
);
6160 gboolean is_const
= FALSE
;
6161 MonoVTable
*vtable
= mono_class_vtable (cfg
->domain
, klass
);
6162 if (!((cfg
->opt
& MONO_OPT_SHARED
) || cfg
->compile_aot
) &&
6163 vtable
->initialized
&& (field
->type
->attrs
& FIELD_ATTRIBUTE_INIT_ONLY
)) {
6164 gpointer addr
= (char*)vtable
->data
+ field
->offset
;
6165 int ro_type
= field
->type
->type
;
6166 if (ro_type
== MONO_TYPE_VALUETYPE
&& field
->type
->data
.klass
->enumtype
) {
6167 ro_type
= field
->type
->data
.klass
->enum_basetype
->type
;
6169 /* g_print ("RO-FIELD %s.%s:%s\n", klass->name_space, klass->name, field->name);*/
6172 case MONO_TYPE_BOOLEAN
:
6174 NEW_ICONST (cfg
, *sp
, *((guint8
*)addr
));
6178 NEW_ICONST (cfg
, *sp
, *((gint8
*)addr
));
6181 case MONO_TYPE_CHAR
:
6183 NEW_ICONST (cfg
, *sp
, *((guint16
*)addr
));
6187 NEW_ICONST (cfg
, *sp
, *((gint16
*)addr
));
6192 NEW_ICONST (cfg
, *sp
, *((gint32
*)addr
));
6196 NEW_ICONST (cfg
, *sp
, *((guint32
*)addr
));
6199 #ifndef HAVE_MOVING_COLLECTOR
6202 case MONO_TYPE_STRING
:
6203 case MONO_TYPE_OBJECT
:
6204 case MONO_TYPE_CLASS
:
6205 case MONO_TYPE_SZARRAY
:
6207 case MONO_TYPE_FNPTR
:
6208 case MONO_TYPE_ARRAY
:
6209 NEW_PCONST (cfg
, *sp
, *((gpointer
*)addr
));
6210 type_to_eval_stack_type (field
->type
, *sp
);
6216 MONO_INST_NEW (cfg
, *sp
, OP_I8CONST
);
6217 sp
[0]->type
= STACK_I8
;
6218 sp
[0]->inst_l
= *((gint64
*)addr
);
6223 case MONO_TYPE_VALUETYPE
:
6232 CHECK_STACK_OVF (1);
6233 MONO_INST_NEW (cfg
, load
, mono_type_to_ldind (field
->type
));
6234 type_to_eval_stack_type (field
->type
, load
);
6235 load
->cil_code
= ip
;
6236 load
->inst_left
= ins
;
6238 load
->flags
|= ins_flag
;
6240 /* fixme: dont see the problem why this does not work */
6241 //cfg->disable_aot = TRUE;
6251 token
= read32 (ip
+ 1);
6252 klass
= mini_get_class (method
, token
, generic_context
);
6253 CHECK_TYPELOAD (klass
);
6254 n
= mono_type_to_stind (&klass
->byval_arg
);
6255 if (n
== CEE_STOBJ
) {
6256 handle_stobj (cfg
, bblock
, sp
[0], sp
[1], ip
, klass
, FALSE
, FALSE
, TRUE
);
6258 /* FIXME: should check item at sp [1] is compatible with the type of the store. */
6260 MONO_INST_NEW (cfg
, store
, n
);
6261 store
->cil_code
= ip
;
6262 store
->inst_left
= sp
[0];
6263 store
->inst_right
= sp
[1];
6264 store
->flags
|= ins_flag
;
6265 MONO_ADD_INS (bblock
, store
);
6277 token
= read32 (ip
+ 1);
6278 klass
= mini_get_class (method
, token
, generic_context
);
6279 CHECK_TYPELOAD (klass
);
6281 if (MONO_TYPE_IS_REFERENCE (&klass
->byval_arg
)) {
6286 if (klass
== mono_defaults
.void_class
)
6288 if (target_type_is_incompatible (cfg
, &klass
->byval_arg
, *sp
))
6290 /* frequent check in generic code: box (struct), brtrue */
6291 if (!mono_class_is_nullable (klass
) &&
6292 ip
+ 5 < end
&& ip_in_bb (cfg
, bblock
, ip
+ 5) && (ip
[5] == CEE_BRTRUE
|| ip
[5] == CEE_BRTRUE_S
)) {
6293 /*g_print ("box-brtrue opt at 0x%04x in %s\n", real_offset, method->name);*/
6294 MONO_INST_NEW (cfg
, ins
, CEE_POP
);
6295 MONO_ADD_INS (bblock
, ins
);
6299 MONO_INST_NEW (cfg
, ins
, CEE_BR
);
6301 MONO_ADD_INS (bblock
, ins
);
6302 if (*ip
== CEE_BRTRUE_S
) {
6305 target
= ip
+ 1 + (signed char)(*ip
);
6310 target
= ip
+ 4 + (gint
)(read32 (ip
));
6313 GET_BBLOCK (cfg
, bbhash
, tblock
, target
);
6314 link_bblock (cfg
, bblock
, tblock
);
6315 CHECK_BBLOCK (target
, ip
, tblock
);
6316 ins
->inst_target_bb
= tblock
;
6317 if (sp
!= stack_start
) {
6318 handle_stack_args (cfg
, bblock
, stack_start
, sp
- stack_start
);
6320 CHECK_UNVERIFIABLE (cfg
);
6322 start_new_bblock
= 1;
6325 *sp
++ = handle_box (cfg
, bblock
, val
, ip
, klass
);
6332 MONO_INST_NEW (cfg
, ins
, *ip
);
6337 token
= read32 (ip
+ 1);
6339 /* allocate the domainvar - becaus this is used in decompose_foreach */
6340 if (cfg
->opt
& MONO_OPT_SHARED
) {
6341 mono_get_domainvar (cfg
);
6342 /* LAME-IR: Mark it as used since otherwise it will be optimized away */
6343 cfg
->domainvar
->flags
|= MONO_INST_VOLATILE
;
6347 mono_get_got_var (cfg
);
6349 klass
= mini_get_class (method
, token
, generic_context
);
6350 CHECK_TYPELOAD (klass
);
6351 ins
->inst_newa_class
= klass
;
6352 ins
->inst_newa_len
= *sp
;
6353 ins
->type
= STACK_OBJ
;
6358 * we store the object so calls to create the array are not interleaved
6359 * with the arguments of other calls.
6362 MonoInst
*store
, *temp
, *load
;
6364 temp
= mono_compile_create_var (cfg
, type_from_stack_type (ins
), OP_LOCAL
);
6365 NEW_TEMPSTORE (cfg
, store
, temp
->inst_c0
, ins
);
6366 store
->cil_code
= ins
->cil_code
;
6367 MONO_ADD_INS (bblock
, store
);
6368 NEW_TEMPLOAD (cfg
, load
, temp
->inst_c0
);
6369 load
->cil_code
= ins
->cil_code
;
6377 if (sp
[0]->type
!= STACK_OBJ
)
6379 MONO_INST_NEW (cfg
, ins
, *ip
);
6380 ins
->cil_code
= ip
++;
6381 ins
->inst_left
= *sp
;
6382 ins
->type
= STACK_PTR
;
6389 if (sp
[0]->type
!= STACK_OBJ
)
6392 klass
= mini_get_class (method
, read32 (ip
+ 1), generic_context
);
6393 CHECK_TYPELOAD (klass
);
6394 /* we need to make sure that this array is exactly the type it needs
6395 * to be for correctness. the wrappers are lax with their usage
6396 * so we need to ignore them here
6398 if (!klass
->valuetype
&& method
->wrapper_type
== MONO_WRAPPER_NONE
) {
6400 MONO_INST_NEW (cfg
, check
, OP_CHECK_ARRAY_TYPE
);
6401 check
->cil_code
= ip
;
6402 check
->klass
= klass
;
6403 check
->inst_left
= sp
[0];
6404 check
->type
= STACK_OBJ
;
6405 check
->klass
= klass
;
6409 mono_class_init (klass
);
6410 NEW_LDELEMA (cfg
, ins
, sp
, klass
);
6415 case CEE_LDELEM_ANY
: {
6419 if (sp
[0]->type
!= STACK_OBJ
)
6422 token
= read32 (ip
+ 1);
6423 klass
= mono_class_get_full (image
, token
, generic_context
);
6424 CHECK_TYPELOAD (klass
);
6425 mono_class_init (klass
);
6426 NEW_LDELEMA (cfg
, load
, sp
, klass
);
6427 load
->cil_code
= ip
;
6428 MONO_INST_NEW (cfg
, ins
, mono_type_to_ldind (&klass
->byval_arg
));
6430 ins
->inst_left
= load
;
6432 type_to_eval_stack_type (&klass
->byval_arg
, ins
);
6446 case CEE_LDELEM_REF
: {
6450 * ldind.x (ldelema (array, index))
6451 * ldelema does the bounds check
6455 if (sp
[0]->type
!= STACK_OBJ
)
6457 klass
= array_access_to_klass (*ip
);
6458 NEW_LDELEMA (cfg
, load
, sp
, klass
);
6459 load
->cil_code
= ip
;
6460 #ifdef MONO_ARCH_SOFT_FLOAT
6461 if (*ip
== CEE_LDELEM_R4
) {
6463 temp
= handle_load_float (cfg
, bblock
, load
, ip
);
6464 NEW_TEMPLOAD (cfg
, *sp
, temp
);
6470 MONO_INST_NEW (cfg
, ins
, ldelem_to_ldind
[*ip
- CEE_LDELEM_I1
]);
6472 ins
->inst_left
= load
;
6474 ins
->type
= ldind_type
[ins
->opcode
- CEE_LDIND_I1
];
6485 case CEE_STELEM_R8
: {
6489 * stind.x (ldelema (array, index), val)
6490 * ldelema does the bounds check
6494 if (sp
[0]->type
!= STACK_OBJ
)
6496 klass
= array_access_to_klass (*ip
);
6497 NEW_LDELEMA (cfg
, load
, sp
, klass
);
6498 load
->cil_code
= ip
;
6499 #ifdef MONO_ARCH_SOFT_FLOAT
6500 if (*ip
== CEE_STELEM_R4
) {
6501 handle_store_float (cfg
, bblock
, load
, sp
[2], ip
);
6506 MONO_INST_NEW (cfg
, ins
, stelem_to_stind
[*ip
- CEE_STELEM_I
]);
6508 ins
->inst_left
= load
;
6509 ins
->inst_right
= sp
[2];
6511 handle_loaded_temps (cfg
, bblock
, stack_start
, sp
);
6512 MONO_ADD_INS (bblock
, ins
);
6516 case CEE_STELEM_ANY
: {
6520 * stind.x (ldelema (array, index), val)
6521 * ldelema does the bounds check
6525 if (sp
[0]->type
!= STACK_OBJ
)
6528 token
= read32 (ip
+ 1);
6529 klass
= mono_class_get_full (image
, token
, generic_context
);
6530 CHECK_TYPELOAD (klass
);
6531 mono_class_init (klass
);
6532 if (MONO_TYPE_IS_REFERENCE (&klass
->byval_arg
)) {
6533 MonoMethod
* helper
= mono_marshal_get_stelemref ();
6534 MonoInst
*iargs
[3];
6535 handle_loaded_temps (cfg
, bblock
, stack_start
, sp
);
6541 mono_emit_method_call_spilled (cfg
, bblock
, helper
, mono_method_signature (helper
), iargs
, ip
, NULL
);
6543 NEW_LDELEMA (cfg
, load
, sp
, klass
);
6544 load
->cil_code
= ip
;
6546 n
= mono_type_to_stind (&klass
->byval_arg
);
6548 handle_stobj (cfg
, bblock
, load
, sp
[2], ip
, klass
, FALSE
, FALSE
, TRUE
);
6550 MONO_INST_NEW (cfg
, ins
, n
);
6552 ins
->inst_left
= load
;
6553 ins
->inst_right
= sp
[2];
6554 handle_loaded_temps (cfg
, bblock
, stack_start
, sp
);
6555 MONO_ADD_INS (bblock
, ins
);
6562 case CEE_STELEM_REF
: {
6563 MonoInst
*iargs
[3];
6564 MonoMethod
* helper
= mono_marshal_get_stelemref ();
6568 if (sp
[0]->type
!= STACK_OBJ
)
6570 if (sp
[2]->type
!= STACK_OBJ
)
6573 handle_loaded_temps (cfg
, bblock
, stack_start
, sp
);
6579 mono_emit_method_call_spilled (cfg
, bblock
, helper
, mono_method_signature (helper
), iargs
, ip
, NULL
);
6583 NEW_GROUP (cfg, group, sp [0], sp [1]);
6584 MONO_INST_NEW (cfg, ins, CEE_STELEM_REF);
6586 ins->inst_left = group;
6587 ins->inst_right = sp [2];
6588 MONO_ADD_INS (bblock, ins);
6595 case CEE_CKFINITE
: {
6596 MonoInst
*store
, *temp
;
6599 /* this instr. can throw exceptions as side effect,
6600 * so we cant eliminate dead code which contains CKFINITE opdodes.
6601 * Spilling to memory makes sure that we always perform
6605 MONO_INST_NEW (cfg
, ins
, CEE_CKFINITE
);
6607 ins
->inst_left
= sp
[-1];
6608 temp
= mono_compile_create_var (cfg
, &mono_defaults
.double_class
->byval_arg
, OP_LOCAL
);
6610 NEW_TEMPSTORE (cfg
, store
, temp
->inst_c0
, ins
);
6611 store
->cil_code
= ip
;
6612 MONO_ADD_INS (bblock
, store
);
6614 NEW_TEMPLOAD (cfg
, sp
[-1], temp
->inst_c0
);
6621 MONO_INST_NEW (cfg
, ins
, *ip
);
6624 klass
= mono_class_get_full (image
, read32 (ip
+ 1), generic_context
);
6625 CHECK_TYPELOAD (klass
);
6626 mono_class_init (klass
);
6627 ins
->type
= STACK_MP
;
6628 ins
->inst_left
= *sp
;
6630 ins
->inst_newa_class
= klass
;
6635 case CEE_MKREFANY
: {
6636 MonoInst
*loc
, *klassconst
;
6639 MONO_INST_NEW (cfg
, ins
, *ip
);
6642 klass
= mono_class_get_full (image
, read32 (ip
+ 1), generic_context
);
6643 CHECK_TYPELOAD (klass
);
6644 mono_class_init (klass
);
6647 loc
= mono_compile_create_var (cfg
, &mono_defaults
.typed_reference_class
->byval_arg
, OP_LOCAL
);
6648 NEW_TEMPLOADA (cfg
, ins
->inst_right
, loc
->inst_c0
);
6650 NEW_PCONST (cfg
, klassconst
, klass
);
6651 NEW_GROUP (cfg
, ins
->inst_left
, *sp
, klassconst
);
6653 MONO_ADD_INS (bblock
, ins
);
6655 NEW_TEMPLOAD (cfg
, *sp
, loc
->inst_c0
);
6662 MonoClass
*handle_class
;
6664 CHECK_STACK_OVF (1);
6667 n
= read32 (ip
+ 1);
6669 if (method
->wrapper_type
== MONO_WRAPPER_DYNAMIC_METHOD
) {
6670 handle
= mono_method_get_wrapper_data (method
, n
);
6671 handle_class
= mono_method_get_wrapper_data (method
, n
+ 1);
6672 if (handle_class
== mono_defaults
.typehandle_class
)
6673 handle
= &((MonoClass
*)handle
)->byval_arg
;
6676 handle
= mono_ldtoken (image
, n
, &handle_class
, generic_context
);
6680 mono_class_init (handle_class
);
6682 if (cfg
->opt
& MONO_OPT_SHARED
) {
6684 MonoInst
*res
, *store
, *addr
, *vtvar
, *iargs
[3];
6686 vtvar
= mono_compile_create_var (cfg
, &handle_class
->byval_arg
, OP_LOCAL
);
6688 NEW_IMAGECONST (cfg
, iargs
[0], image
);
6689 NEW_ICONST (cfg
, iargs
[1], n
);
6690 NEW_PCONST (cfg
, iargs
[2], generic_context
);
6691 temp
= mono_emit_jit_icall (cfg
, bblock
, mono_ldtoken_wrapper
, iargs
, ip
);
6692 NEW_TEMPLOAD (cfg
, res
, temp
);
6693 NEW_TEMPLOADA (cfg
, addr
, vtvar
->inst_c0
);
6694 NEW_INDSTORE (cfg
, store
, addr
, res
, &mono_defaults
.int_class
->byval_arg
);
6695 MONO_ADD_INS (bblock
, store
);
6696 NEW_TEMPLOAD (cfg
, ins
, vtvar
->inst_c0
);
6698 if ((ip
[5] == CEE_CALL
) && (cmethod
= mini_get_method (method
, read32 (ip
+ 6), NULL
, generic_context
)) &&
6699 (cmethod
->klass
== mono_defaults
.monotype_class
->parent
) &&
6700 (strcmp (cmethod
->name
, "GetTypeFromHandle") == 0) && ip_in_bb (cfg
, bblock
, ip
+ 5)) {
6701 MonoClass
*tclass
= mono_class_from_mono_type (handle
);
6702 mono_class_init (tclass
);
6703 if (cfg
->compile_aot
)
6704 NEW_TYPE_FROM_HANDLE_CONST (cfg
, ins
, image
, n
);
6706 NEW_PCONST (cfg
, ins
, mono_type_get_object (cfg
->domain
, handle
));
6707 ins
->type
= STACK_OBJ
;
6708 ins
->klass
= cmethod
->klass
;
6711 MonoInst
*store
, *addr
, *vtvar
;
6713 if (cfg
->compile_aot
)
6714 NEW_LDTOKENCONST (cfg
, ins
, image
, n
);
6716 NEW_PCONST (cfg
, ins
, handle
);
6717 vtvar
= mono_compile_create_var (cfg
, &handle_class
->byval_arg
, OP_LOCAL
);
6718 NEW_TEMPLOADA (cfg
, addr
, vtvar
->inst_c0
);
6719 NEW_INDSTORE (cfg
, store
, addr
, ins
, &mono_defaults
.int_class
->byval_arg
);
6720 MONO_ADD_INS (bblock
, store
);
6721 NEW_TEMPLOAD (cfg
, ins
, vtvar
->inst_c0
);
6737 case CEE_ADD_OVF_UN
:
6739 case CEE_MUL_OVF_UN
:
6741 case CEE_SUB_OVF_UN
:
6744 if (mono_find_jit_opcode_emulation (ins
->opcode
)) {
6746 *sp
++ = emit_tree (cfg
, bblock
, ins
, ip
+ 1);
6750 case CEE_ENDFINALLY
:
6751 MONO_INST_NEW (cfg
, ins
, *ip
);
6752 MONO_ADD_INS (bblock
, ins
);
6753 ins
->cil_code
= ip
++;
6754 start_new_bblock
= 1;
6757 * Control will leave the method so empty the stack, otherwise
6758 * the next basic block will start with a nonempty stack.
6760 while (sp
!= stack_start
) {
6761 MONO_INST_NEW (cfg
, ins
, CEE_POP
);
6765 MONO_ADD_INS (bblock
, ins
);
6772 if (*ip
== CEE_LEAVE
) {
6774 target
= ip
+ 5 + (gint32
)read32(ip
+ 1);
6777 target
= ip
+ 2 + (signed char)(ip
[1]);
6780 /* empty the stack */
6781 while (sp
!= stack_start
) {
6782 MONO_INST_NEW (cfg
, ins
, CEE_POP
);
6786 MONO_ADD_INS (bblock
, ins
);
6790 * If this leave statement is in a catch block, check for a
6791 * pending exception, and rethrow it if necessary.
6793 for (i
= 0; i
< header
->num_clauses
; ++i
) {
6794 MonoExceptionClause
*clause
= &header
->clauses
[i
];
6797 * Use <= in the final comparison to handle clauses with multiple
6798 * leave statements, like in bug #78024.
6799 * The ordering of the exception clauses guarantees that we find the
6802 if (MONO_OFFSET_IN_HANDLER (clause
, ip
- header
->code
) && (clause
->flags
== MONO_EXCEPTION_CLAUSE_NONE
) && (ip
- header
->code
+ ((*ip
== CEE_LEAVE
) ? 5 : 2)) <= (clause
->handler_offset
+ clause
->handler_len
)) {
6806 NEW_TEMPLOAD (cfg
, load
, mono_find_exvar_for_offset (cfg
, clause
->handler_offset
)->inst_c0
);
6807 load
->cil_code
= ip
;
6809 temp
= mono_emit_jit_icall (cfg
, bblock
, mono_thread_get_pending_exception
, NULL
, ip
);
6810 NEW_TEMPLOAD (cfg
, *sp
, temp
);
6812 MONO_INST_NEW (cfg
, ins
, OP_THROW_OR_NULL
);
6813 ins
->inst_left
= *sp
;
6814 ins
->inst_right
= load
;
6816 MONO_ADD_INS (bblock
, ins
);
6820 /* fixme: call fault handler ? */
6822 if ((handlers
= mono_find_final_block (cfg
, ip
, target
, MONO_EXCEPTION_CLAUSE_FINALLY
))) {
6824 for (tmp
= handlers
; tmp
; tmp
= tmp
->next
) {
6826 link_bblock (cfg
, bblock
, tblock
);
6827 MONO_INST_NEW (cfg
, ins
, OP_CALL_HANDLER
);
6829 ins
->inst_target_bb
= tblock
;
6830 MONO_ADD_INS (bblock
, ins
);
6832 g_list_free (handlers
);
6835 MONO_INST_NEW (cfg
, ins
, CEE_BR
);
6837 MONO_ADD_INS (bblock
, ins
);
6838 GET_BBLOCK (cfg
, bbhash
, tblock
, target
);
6839 link_bblock (cfg
, bblock
, tblock
);
6840 CHECK_BBLOCK (target
, ip
, tblock
);
6841 ins
->inst_target_bb
= tblock
;
6842 start_new_bblock
= 1;
6844 if (*ip
== CEE_LEAVE
)
6853 MONO_INST_NEW (cfg
, ins
, *ip
);
6855 handle_loaded_temps (cfg
, bblock
, stack_start
, sp
);
6856 MONO_ADD_INS (bblock
, ins
);
6857 ins
->cil_code
= ip
++;
6858 ins
->inst_i0
= sp
[0];
6859 ins
->inst_i1
= sp
[1];
6867 /* trampoline mono specific opcodes */
6868 case MONO_CUSTOM_PREFIX
: {
6870 g_assert (method
->wrapper_type
!= MONO_WRAPPER_NONE
);
6875 case CEE_MONO_ICALL
: {
6878 MonoJitICallInfo
*info
;
6880 token
= read32 (ip
+ 2);
6881 func
= mono_method_get_wrapper_data (method
, token
);
6882 info
= mono_find_jit_icall_by_addr (func
);
6885 CHECK_STACK (info
->sig
->param_count
);
6886 sp
-= info
->sig
->param_count
;
6888 temp
= mono_emit_jit_icall (cfg
, bblock
, info
->func
, sp
, ip
);
6889 if (!MONO_TYPE_IS_VOID (info
->sig
->ret
)) {
6890 NEW_TEMPLOAD (cfg
, *sp
, temp
);
6895 inline_costs
+= 10 * num_calls
++;
6899 case CEE_MONO_LDPTR
:
6900 CHECK_STACK_OVF (1);
6902 token
= read32 (ip
+ 2);
6903 NEW_PCONST (cfg
, ins
, mono_method_get_wrapper_data (method
, token
));
6907 inline_costs
+= 10 * num_calls
++;
6908 /* Can't embed random pointers into AOT code */
6909 cfg
->disable_aot
= 1;
6911 case CEE_MONO_VTADDR
:
6914 MONO_INST_NEW (cfg
, ins
, OP_VTADDR
);
6916 ins
->type
= STACK_MP
;
6917 ins
->inst_left
= *sp
;
6921 case CEE_MONO_NEWOBJ
: {
6922 MonoInst
*iargs
[2];
6924 CHECK_STACK_OVF (1);
6926 token
= read32 (ip
+ 2);
6927 klass
= (MonoClass
*)mono_method_get_wrapper_data (method
, token
);
6928 mono_class_init (klass
);
6929 NEW_DOMAINCONST (cfg
, iargs
[0]);
6930 NEW_CLASSCONST (cfg
, iargs
[1], klass
);
6931 temp
= mono_emit_jit_icall (cfg
, bblock
, mono_object_new
, iargs
, ip
);
6932 NEW_TEMPLOAD (cfg
, *sp
, temp
);
6935 inline_costs
+= 10 * num_calls
++;
6938 case CEE_MONO_OBJADDR
:
6941 MONO_INST_NEW (cfg
, ins
, OP_OBJADDR
);
6943 ins
->type
= STACK_MP
;
6944 ins
->inst_left
= *sp
;
6948 case CEE_MONO_LDNATIVEOBJ
:
6951 token
= read32 (ip
+ 2);
6952 klass
= mono_method_get_wrapper_data (method
, token
);
6953 g_assert (klass
->valuetype
);
6954 mono_class_init (klass
);
6955 NEW_INDLOAD (cfg
, ins
, sp
[-1], &klass
->byval_arg
);
6959 case CEE_MONO_RETOBJ
:
6960 g_assert (cfg
->ret
);
6961 g_assert (mono_method_signature (method
)->pinvoke
);
6966 token
= read32 (ip
+ 2);
6967 klass
= (MonoClass
*)mono_method_get_wrapper_data (method
, token
);
6969 NEW_RETLOADA (cfg
, ins
);
6970 handle_stobj (cfg
, bblock
, ins
, *sp
, ip
, klass
, FALSE
, TRUE
, FALSE
);
6972 if (sp
!= stack_start
)
6975 MONO_INST_NEW (cfg
, ins
, CEE_BR
);
6977 ins
->inst_target_bb
= end_bblock
;
6978 MONO_ADD_INS (bblock
, ins
);
6979 link_bblock (cfg
, bblock
, end_bblock
);
6980 start_new_bblock
= 1;
6983 case CEE_MONO_CISINST
:
6984 case CEE_MONO_CCASTCLASS
: {
6989 token
= read32 (ip
+ 2);
6990 klass
= (MonoClass
*)mono_method_get_wrapper_data (method
, token
);
6991 MONO_INST_NEW (cfg
, ins
, (ip
[1] == CEE_MONO_CISINST
) ? OP_CISINST
: OP_CCASTCLASS
);
6992 ins
->type
= STACK_I4
;
6993 ins
->inst_left
= *sp
;
6994 ins
->inst_newa_class
= klass
;
6996 *sp
++ = emit_tree (cfg
, bblock
, ins
, ip
+ 6);
7000 case CEE_MONO_SAVE_LMF
:
7001 case CEE_MONO_RESTORE_LMF
:
7002 #ifdef MONO_ARCH_HAVE_LMF_OPS
7003 MONO_INST_NEW (cfg
, ins
, (ip
[1] == CEE_MONO_SAVE_LMF
) ? OP_SAVE_LMF
: OP_RESTORE_LMF
);
7004 MONO_ADD_INS (bblock
, ins
);
7005 cfg
->need_lmf_area
= TRUE
;
7009 case CEE_MONO_CLASSCONST
:
7010 CHECK_STACK_OVF (1);
7012 token
= read32 (ip
+ 2);
7013 NEW_CLASSCONST (cfg
, ins
, mono_method_get_wrapper_data (method
, token
));
7017 inline_costs
+= 10 * num_calls
++;
7019 case CEE_MONO_NOT_TAKEN
:
7020 bblock
->out_of_line
= TRUE
;
7024 g_error ("opcode 0x%02x 0x%02x not handled", MONO_CUSTOM_PREFIX
, ip
[1]);
7033 /* somewhat similar to LDTOKEN */
7034 MonoInst
*addr
, *vtvar
;
7035 CHECK_STACK_OVF (1);
7036 vtvar
= mono_compile_create_var (cfg
, &mono_defaults
.argumenthandle_class
->byval_arg
, OP_LOCAL
);
7038 NEW_TEMPLOADA (cfg
, addr
, vtvar
->inst_c0
);
7039 addr
->cil_code
= ip
;
7040 MONO_INST_NEW (cfg
, ins
, OP_ARGLIST
);
7042 ins
->inst_left
= addr
;
7043 MONO_ADD_INS (bblock
, ins
);
7044 NEW_TEMPLOAD (cfg
, ins
, vtvar
->inst_c0
);
7058 * The following transforms:
7059 * CEE_CEQ into OP_CEQ
7060 * CEE_CGT into OP_CGT
7061 * CEE_CGT_UN into OP_CGT_UN
7062 * CEE_CLT into OP_CLT
7063 * CEE_CLT_UN into OP_CLT_UN
7065 MONO_INST_NEW (cfg
, cmp
, 256 + ip
[1]);
7067 MONO_INST_NEW (cfg
, ins
, cmp
->opcode
);
7069 cmp
->inst_i0
= sp
[0];
7070 cmp
->inst_i1
= sp
[1];
7075 ins
->type
= STACK_I4
;
7077 #if MONO_ARCH_SOFT_FLOAT
7078 if (sp
[0]->type
== STACK_R8
) {
7079 cmp
->type
= STACK_I4
;
7080 *sp
++ = emit_tree (cfg
, bblock
, cmp
, ip
+ 2);
7085 if ((sp
[0]->type
== STACK_I8
) || ((sizeof (gpointer
) == 8) && ((sp
[0]->type
== STACK_PTR
) || (sp
[0]->type
== STACK_OBJ
) || (sp
[0]->type
== STACK_MP
))))
7086 cmp
->opcode
= OP_LCOMPARE
;
7088 cmp
->opcode
= OP_COMPARE
;
7090 /* spill it to reduce the expression complexity
7091 * and workaround bug 54209
7093 if (cmp
->inst_left
->type
== STACK_I8
) {
7095 *sp
++ = emit_tree (cfg
, bblock
, ins
, ip
+ 2);
7104 CHECK_STACK_OVF (1);
7106 n
= read32 (ip
+ 2);
7107 cmethod
= mini_get_method (method
, n
, NULL
, generic_context
);
7110 mono_class_init (cmethod
->klass
);
7112 if (mono_use_security_manager
) {
7113 if (check_linkdemand (cfg
, method
, cmethod
, bblock
, ip
))
7117 handle_loaded_temps (cfg
, bblock
, stack_start
, sp
);
7119 NEW_METHODCONST (cfg
, argconst
, cmethod
);
7120 if (method
->wrapper_type
!= MONO_WRAPPER_SYNCHRONIZED
)
7121 temp
= mono_emit_jit_icall (cfg
, bblock
, mono_ldftn
, &argconst
, ip
);
7123 temp
= mono_emit_jit_icall (cfg
, bblock
, mono_ldftn_nosync
, &argconst
, ip
);
7124 NEW_TEMPLOAD (cfg
, *sp
, temp
);
7128 inline_costs
+= 10 * num_calls
++;
7131 case CEE_LDVIRTFTN
: {
7137 n
= read32 (ip
+ 2);
7138 cmethod
= mini_get_method (method
, n
, NULL
, generic_context
);
7141 mono_class_init (cmethod
->klass
);
7143 if (mono_use_security_manager
) {
7144 if (check_linkdemand (cfg
, method
, cmethod
, bblock
, ip
))
7148 handle_loaded_temps (cfg
, bblock
, stack_start
, sp
);
7152 NEW_METHODCONST (cfg
, args
[1], cmethod
);
7153 temp
= mono_emit_jit_icall (cfg
, bblock
, mono_ldvirtfn
, args
, ip
);
7154 NEW_TEMPLOAD (cfg
, *sp
, temp
);
7158 inline_costs
+= 10 * num_calls
++;
7162 CHECK_STACK_OVF (1);
7164 n
= read16 (ip
+ 2);
7166 NEW_ARGLOAD (cfg
, ins
, n
);
7167 LDARG_SOFT_FLOAT (cfg
, ins
, n
, ip
);
7173 CHECK_STACK_OVF (1);
7175 n
= read16 (ip
+ 2);
7177 NEW_ARGLOADA (cfg
, ins
, n
);
7185 handle_loaded_temps (cfg
, bblock
, stack_start
, sp
);
7187 n
= read16 (ip
+ 2);
7189 NEW_ARGSTORE (cfg
, ins
, n
, *sp
);
7191 if (!dont_verify_stloc
&& target_type_is_incompatible (cfg
, param_types
[n
], *sp
))
7193 if (ins
->opcode
== CEE_STOBJ
) {
7194 NEW_ARGLOADA (cfg
, ins
, n
);
7195 handle_stobj (cfg
, bblock
, ins
, *sp
, ip
, ins
->klass
, FALSE
, FALSE
, FALSE
);
7197 MONO_ADD_INS (bblock
, ins
);
7201 CHECK_STACK_OVF (1);
7203 n
= read16 (ip
+ 2);
7205 NEW_LOCLOAD (cfg
, ins
, n
);
7206 LDLOC_SOFT_FLOAT (cfg
, ins
, n
, ip
);
7212 CHECK_STACK_OVF (1);
7214 n
= read16 (ip
+ 2);
7216 NEW_LOCLOADA (cfg
, ins
, n
);
7225 n
= read16 (ip
+ 2);
7227 handle_loaded_temps (cfg
, bblock
, stack_start
, sp
);
7228 NEW_LOCSTORE (cfg
, ins
, n
, *sp
);
7229 if (!dont_verify_stloc
&& target_type_is_incompatible (cfg
, header
->locals
[n
], *sp
))
7232 STLOC_SOFT_FLOAT (cfg
, ins
, n
, ip
);
7233 if (ins
->opcode
== CEE_STOBJ
) {
7234 NEW_LOCLOADA (cfg
, ins
, n
);
7235 handle_stobj (cfg
, bblock
, ins
, *sp
, ip
, ins
->klass
, FALSE
, FALSE
, FALSE
);
7237 MONO_ADD_INS (bblock
, ins
);
7244 if (sp
!= stack_start
)
7246 if (cfg
->method
!= method
)
7248 * Inlining this into a loop in a parent could lead to
7249 * stack overflows which is different behavior than the
7250 * non-inlined case, thus disable inlining in this case.
7252 goto inline_failure
;
7253 MONO_INST_NEW (cfg
, ins
, OP_LOCALLOC
);
7254 ins
->inst_left
= *sp
;
7256 ins
->type
= STACK_PTR
;
7258 cfg
->flags
|= MONO_CFG_HAS_ALLOCA
;
7259 if (header
->init_locals
)
7260 ins
->flags
|= MONO_INST_INIT
;
7264 /* FIXME: set init flag if locals init is set in this method */
7266 case CEE_ENDFILTER
: {
7267 MonoExceptionClause
*clause
, *nearest
;
7268 int cc
, nearest_num
;
7272 if ((sp
!= stack_start
) || (sp
[0]->type
!= STACK_I4
))
7274 MONO_INST_NEW (cfg
, ins
, OP_ENDFILTER
);
7275 ins
->inst_left
= *sp
;
7277 MONO_ADD_INS (bblock
, ins
);
7278 start_new_bblock
= 1;
7283 for (cc
= 0; cc
< header
->num_clauses
; ++cc
) {
7284 clause
= &header
->clauses
[cc
];
7285 if ((clause
->flags
& MONO_EXCEPTION_CLAUSE_FILTER
) &&
7286 ((ip
- header
->code
) > clause
->data
.filter_offset
&& (ip
- header
->code
) <= clause
->handler_offset
) &&
7287 (!nearest
|| (clause
->data
.filter_offset
< nearest
->data
.filter_offset
))) {
7293 if ((ip
- header
->code
) != nearest
->handler_offset
)
7298 case CEE_UNALIGNED_
:
7299 ins_flag
|= MONO_INST_UNALIGNED
;
7300 /* FIXME: record alignment? we can assume 1 for now */
7305 ins_flag
|= MONO_INST_VOLATILE
;
7309 ins_flag
|= MONO_INST_TAILCALL
;
7310 cfg
->flags
|= MONO_CFG_HAS_TAIL
;
7311 /* Can't inline tail calls at this time */
7312 inline_costs
+= 100000;
7319 token
= read32 (ip
+ 2);
7320 klass
= mini_get_class (method
, token
, generic_context
);
7321 CHECK_TYPELOAD (klass
);
7322 if (MONO_TYPE_IS_REFERENCE (&klass
->byval_arg
)) {
7323 MonoInst
*store
, *load
;
7324 NEW_PCONST (cfg
, load
, NULL
);
7325 load
->cil_code
= ip
;
7326 load
->type
= STACK_OBJ
;
7327 load
->klass
= klass
;
7328 MONO_INST_NEW (cfg
, store
, CEE_STIND_REF
);
7329 store
->cil_code
= ip
;
7330 handle_loaded_temps (cfg
, bblock
, stack_start
, sp
);
7331 MONO_ADD_INS (bblock
, store
);
7332 store
->inst_i0
= sp
[0];
7333 store
->inst_i1
= load
;
7335 handle_initobj (cfg
, bblock
, *sp
, NULL
, klass
, stack_start
, sp
);
7340 case CEE_CONSTRAINED_
:
7341 /* FIXME: implement */
7343 token
= read32 (ip
+ 2);
7344 constrained_call
= mono_class_get_full (image
, token
, generic_context
);
7345 CHECK_TYPELOAD (constrained_call
);
7350 MonoInst
*iargs
[3];
7353 if ((cfg
->opt
& MONO_OPT_INTRINS
) && (ip
[1] == CEE_CPBLK
) && (sp
[2]->opcode
== OP_ICONST
) && ((n
= sp
[2]->inst_c0
) <= sizeof (gpointer
) * 5)) {
7355 MONO_INST_NEW (cfg
, copy
, OP_MEMCPY
);
7356 copy
->inst_left
= sp
[0];
7357 copy
->inst_right
= sp
[1];
7358 copy
->cil_code
= ip
;
7359 copy
->backend
.size
= n
;
7360 MONO_ADD_INS (bblock
, copy
);
7367 handle_loaded_temps (cfg
, bblock
, stack_start
, sp
);
7368 if (ip
[1] == CEE_CPBLK
) {
7369 MonoMethod
*memcpy_method
= get_memcpy_method ();
7370 mono_emit_method_call_spilled (cfg
, bblock
, memcpy_method
, memcpy_method
->signature
, iargs
, ip
, NULL
);
7372 MonoMethod
*memset_method
= get_memset_method ();
7373 mono_emit_method_call_spilled (cfg
, bblock
, memset_method
, memset_method
->signature
, iargs
, ip
, NULL
);
7382 ins_flag
|= MONO_INST_NOTYPECHECK
;
7384 ins_flag
|= MONO_INST_NORANGECHECK
;
7385 /* we ignore the no-nullcheck for now since we
7386 * really do it explicitly only when doing callvirt->call
7392 int handler_offset
= -1;
7394 for (i
= 0; i
< header
->num_clauses
; ++i
) {
7395 MonoExceptionClause
*clause
= &header
->clauses
[i
];
7396 if (MONO_OFFSET_IN_HANDLER (clause
, ip
- header
->code
) && !(clause
->flags
& MONO_EXCEPTION_CLAUSE_FINALLY
))
7397 handler_offset
= clause
->handler_offset
;
7400 bblock
->flags
|= BB_EXCEPTION_UNSAFE
;
7402 g_assert (handler_offset
!= -1);
7404 NEW_TEMPLOAD (cfg
, load
, mono_find_exvar_for_offset (cfg
, handler_offset
)->inst_c0
);
7405 load
->cil_code
= ip
;
7406 MONO_INST_NEW (cfg
, ins
, OP_RETHROW
);
7407 ins
->inst_left
= load
;
7409 MONO_ADD_INS (bblock
, ins
);
7411 link_bblock (cfg
, bblock
, end_bblock
);
7412 start_new_bblock
= 1;
7417 CHECK_STACK_OVF (1);
7419 token
= read32 (ip
+ 2);
7420 /* FIXXME: handle generics. */
7421 if (mono_metadata_token_table (token
) == MONO_TABLE_TYPESPEC
) {
7422 MonoType
*type
= mono_type_create_from_typespec (image
, token
);
7423 token
= mono_type_size (type
, &ialign
);
7425 MonoClass
*klass
= mono_class_get_full (image
, token
, generic_context
);
7426 CHECK_TYPELOAD (klass
);
7427 mono_class_init (klass
);
7428 token
= mono_class_value_size (klass
, &align
);
7430 NEW_ICONST (cfg
, ins
, token
);
7435 case CEE_REFANYTYPE
:
7437 MONO_INST_NEW (cfg
, ins
, OP_REFANYTYPE
);
7439 ins
->type
= STACK_MP
;
7440 ins
->inst_left
= *sp
;
7441 ins
->type
= STACK_VTYPE
;
7442 ins
->klass
= mono_defaults
.typehandle_class
;
7451 g_error ("opcode 0xfe 0x%02x not handled", ip
[1]);
7456 g_error ("opcode 0x%02x not handled", *ip
);
7459 if (start_new_bblock
!= 1)
7462 bblock
->cil_length
= ip
- bblock
->cil_code
;
7463 bblock
->next_bb
= end_bblock
;
7465 if (cfg
->method
== method
&& cfg
->domainvar
) {
7467 MonoInst
*get_domain
;
7469 if (! (get_domain
= mono_arch_get_domain_intrinsic (cfg
))) {
7472 MONO_INST_NEW_CALL (cfg
, call
, CEE_CALL
);
7473 call
->signature
= helper_sig_domain_get
;
7474 call
->inst
.type
= STACK_PTR
;
7475 call
->fptr
= mono_domain_get
;
7476 get_domain
= (MonoInst
*)call
;
7479 NEW_TEMPSTORE (cfg
, store
, cfg
->domainvar
->inst_c0
, get_domain
);
7480 MONO_ADD_INS (init_localsbb
, store
);
7483 if (cfg
->method
== method
&& cfg
->got_var
)
7484 mono_emit_load_got_addr (cfg
);
7486 if (header
->init_locals
) {
7488 for (i
= 0; i
< header
->num_locals
; ++i
) {
7489 MonoType
*ptype
= header
->locals
[i
];
7490 int t
= ptype
->type
;
7491 if (t
== MONO_TYPE_VALUETYPE
&& ptype
->data
.klass
->enumtype
)
7492 t
= ptype
->data
.klass
->enum_basetype
->type
;
7494 NEW_PCONST (cfg
, ins
, NULL
);
7495 NEW_LOCSTORE (cfg
, store
, i
, ins
);
7496 MONO_ADD_INS (init_localsbb
, store
);
7497 } else if (t
>= MONO_TYPE_BOOLEAN
&& t
<= MONO_TYPE_U4
) {
7498 NEW_ICONST (cfg
, ins
, 0);
7499 NEW_LOCSTORE (cfg
, store
, i
, ins
);
7500 MONO_ADD_INS (init_localsbb
, store
);
7501 } else if (t
== MONO_TYPE_I8
|| t
== MONO_TYPE_U8
) {
7502 MONO_INST_NEW (cfg
, ins
, OP_I8CONST
);
7503 ins
->type
= STACK_I8
;
7505 NEW_LOCSTORE (cfg
, store
, i
, ins
);
7506 MONO_ADD_INS (init_localsbb
, store
);
7507 } else if (t
== MONO_TYPE_R4
|| t
== MONO_TYPE_R8
) {
7508 #ifdef MONO_ARCH_SOFT_FLOAT
7509 /* FIXME: handle init of R4 */
7511 MONO_INST_NEW (cfg
, ins
, OP_R8CONST
);
7512 ins
->type
= STACK_R8
;
7513 ins
->inst_p0
= (void*)&r8_0
;
7514 NEW_LOCSTORE (cfg
, store
, i
, ins
);
7515 MONO_ADD_INS (init_localsbb
, store
);
7517 } else if ((t
== MONO_TYPE_VALUETYPE
) || (t
== MONO_TYPE_TYPEDBYREF
) ||
7518 ((t
== MONO_TYPE_GENERICINST
) && mono_type_generic_inst_is_valuetype (ptype
))) {
7519 NEW_LOCLOADA (cfg
, ins
, i
);
7520 handle_initobj (cfg
, init_localsbb
, ins
, NULL
, mono_class_from_mono_type (ptype
), NULL
, NULL
);
7522 NEW_PCONST (cfg
, ins
, NULL
);
7523 NEW_LOCSTORE (cfg
, store
, i
, ins
);
7524 MONO_ADD_INS (init_localsbb
, store
);
7529 /* resolve backward branches in the middle of an existing basic block */
7530 for (tmp
= bb_recheck
; tmp
; tmp
= tmp
->next
) {
7532 /*g_print ("need recheck in %s at IL_%04x\n", method->name, bblock->cil_code - header->code);*/
7533 tblock
= find_previous (bbhash
, start_bblock
, bblock
->cil_code
);
7534 if (tblock
!= start_bblock
) {
7536 split_bblock (cfg
, tblock
, bblock
);
7537 l
= bblock
->cil_code
- header
->code
;
7538 bblock
->cil_length
= tblock
->cil_length
- l
;
7539 tblock
->cil_length
= l
;
7541 g_print ("recheck failed.\n");
7545 if (cfg
->method
== method
) {
7547 for (bb
= cfg
->bb_entry
; bb
; bb
= bb
->next_bb
) {
7548 bb
->region
= mono_find_block_region (cfg
, bb
->real_offset
);
7550 mono_create_spvar_for_region (cfg
, bb
->region
);
7551 if (cfg
->verbose_level
> 2)
7552 g_print ("REGION BB%d IL_%04x ID_%08X\n", bb
->block_num
, bb
->real_offset
, bb
->region
);
7555 g_hash_table_destroy (bbhash
);
7558 g_slist_free (class_inits
);
7559 dont_inline
= g_list_remove (dont_inline
, method
);
7561 if (inline_costs
< 0) {
7564 /* Method is too large */
7565 mname
= mono_method_full_name (method
, TRUE
);
7566 cfg
->exception_type
= MONO_EXCEPTION_INVALID_PROGRAM
;
7567 cfg
->exception_message
= g_strdup_printf ("Method %s is too complex.", mname
);
7572 return inline_costs
;
7575 if (cfg
->method
!= method
)
7576 g_hash_table_destroy (bbhash
);
7577 g_slist_free (class_inits
);
7578 dont_inline
= g_list_remove (dont_inline
, method
);
7582 if (cfg
->method
!= method
)
7583 g_hash_table_destroy (bbhash
);
7584 g_slist_free (class_inits
);
7585 dont_inline
= g_list_remove (dont_inline
, method
);
7586 cfg
->exception_type
= MONO_EXCEPTION_TYPE_LOAD
;
7590 if (cfg
->method
!= method
)
7591 g_hash_table_destroy (bbhash
);
7592 g_slist_free (class_inits
);
7593 dont_inline
= g_list_remove (dont_inline
, method
);
7594 cfg
->exception_type
= MONO_EXCEPTION_INVALID_PROGRAM
;
7595 cfg
->exception_message
= g_strdup_printf ("Invalid IL code in %s: %s\n",
7596 mono_method_full_name (method
, TRUE
), mono_disasm_code_one (NULL
, method
, ip
, NULL
));
7601 mono_print_tree (MonoInst
*tree
) {
7607 arity
= mono_burg_arity
[tree
->opcode
];
7609 printf (" %s%s", arity
?"(":"", mono_inst_name (tree
->opcode
));
7611 switch (tree
->opcode
) {
7613 printf ("[%d]", (int)tree
->inst_c0
);
7616 printf ("[%lld]", (long long)tree
->inst_l
);
7619 printf ("[%f]", *(double*)tree
->inst_p0
);
7622 printf ("[%f]", *(float*)tree
->inst_p0
);
7626 printf ("[%d]", (int)tree
->inst_c0
);
7629 if (tree
->inst_offset
< 0)
7630 printf ("[-0x%x(%s)]", (int)(-tree
->inst_offset
), mono_arch_regname (tree
->inst_basereg
));
7632 printf ("[0x%x(%s)]", (int)(tree
->inst_offset
), mono_arch_regname (tree
->inst_basereg
));
7635 printf ("[%s]", mono_arch_regname (tree
->dreg
));
7638 printf ("[%s]", tree
->inst_newa_class
->name
);
7639 mono_print_tree (tree
->inst_newa_len
);
7650 case OP_VOIDCALLVIRT
: {
7651 MonoCallInst
*call
= (MonoCallInst
*)tree
;
7653 printf ("[%s]", call
->method
->name
);
7654 else if (call
->fptr
) {
7655 MonoJitICallInfo
*info
= mono_find_jit_icall_by_addr (call
->fptr
);
7657 printf ("[%s]", info
->name
);
7663 printf ("[%d (", (int)tree
->inst_c0
);
7664 for (i
= 0; i
< tree
->inst_phi_args
[0]; i
++) {
7667 printf ("%d", tree
->inst_phi_args
[i
+ 1]);
7678 case OP_LOAD_MEMBASE
:
7679 case OP_LOADI4_MEMBASE
:
7680 case OP_LOADU4_MEMBASE
:
7681 case OP_LOADU1_MEMBASE
:
7682 case OP_LOADI1_MEMBASE
:
7683 case OP_LOADU2_MEMBASE
:
7684 case OP_LOADI2_MEMBASE
:
7685 printf ("[%s] <- [%s + 0x%x]", mono_arch_regname (tree
->dreg
), mono_arch_regname (tree
->inst_basereg
), (int)tree
->inst_offset
);
7688 case OP_CALL_HANDLER
:
7689 printf ("[B%d]", tree
->inst_target_bb
->block_num
);
7699 case OP_VOIDCALL_REG
:
7700 mono_print_tree (tree
->inst_left
);
7712 printf ("[B%dB%d]", tree
->inst_true_bb
->block_num
, tree
->inst_false_bb
->block_num
);
7713 mono_print_tree (tree
->inst_left
);
7716 if (!mono_arch_print_tree(tree
, arity
)) {
7718 mono_print_tree (tree
->inst_left
);
7720 mono_print_tree (tree
->inst_right
);
7731 mono_print_tree_nl (MonoInst
*tree
)
7733 mono_print_tree (tree
);
7738 create_helper_signature (void)
7740 helper_sig_domain_get
= mono_create_icall_signature ("ptr");
7741 helper_sig_class_init_trampoline
= mono_create_icall_signature ("void");
7745 mono_icall_get_wrapper (MonoJitICallInfo
* callinfo
)
7748 MonoMethod
*wrapper
;
7749 gconstpointer trampoline
;
7750 MonoDomain
*domain
= mono_get_root_domain ();
7752 if (callinfo
->wrapper
) {
7753 return callinfo
->wrapper
;
7756 if (callinfo
->trampoline
)
7757 return callinfo
->trampoline
;
7760 * We use the lock on the root domain instead of the JIT lock to protect
7761 * callinfo->trampoline, since we do a lot of stuff inside the critical section.
7763 mono_domain_lock (domain
);
7765 if (callinfo
->trampoline
) {
7766 mono_domain_unlock (domain
);
7767 return callinfo
->trampoline
;
7770 name
= g_strdup_printf ("__icall_wrapper_%s", callinfo
->name
);
7771 wrapper
= mono_marshal_get_icall_wrapper (callinfo
->sig
, name
, callinfo
->func
);
7774 trampoline
= mono_create_ftnptr (domain
, mono_create_jit_trampoline_in_domain (domain
, wrapper
));
7775 mono_register_jit_icall_wrapper (callinfo
, trampoline
);
7777 callinfo
->trampoline
= trampoline
;
7779 mono_domain_unlock (domain
);
7781 return callinfo
->trampoline
;
7785 mono_init_trampolines (void)
7787 mono_trampoline_code
[MONO_TRAMPOLINE_GENERIC
] = mono_arch_create_trampoline_code (MONO_TRAMPOLINE_GENERIC
);
7788 mono_trampoline_code
[MONO_TRAMPOLINE_JUMP
] = mono_arch_create_trampoline_code (MONO_TRAMPOLINE_JUMP
);
7789 mono_trampoline_code
[MONO_TRAMPOLINE_CLASS_INIT
] = mono_arch_create_trampoline_code (MONO_TRAMPOLINE_CLASS_INIT
);
7790 #ifdef MONO_ARCH_HAVE_PIC_AOT
7791 mono_trampoline_code
[MONO_TRAMPOLINE_AOT
] = mono_arch_create_trampoline_code (MONO_TRAMPOLINE_AOT
);
7792 mono_trampoline_code
[MONO_TRAMPOLINE_AOT_PLT
] = mono_arch_create_trampoline_code (MONO_TRAMPOLINE_AOT_PLT
);
7794 #ifdef MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE
7795 mono_trampoline_code
[MONO_TRAMPOLINE_DELEGATE
] = mono_arch_create_trampoline_code (MONO_TRAMPOLINE_DELEGATE
);
7800 mono_init_exceptions (void)
7802 #ifndef CUSTOM_EXCEPTION_HANDLING
7803 mono_arch_get_restore_context ();
7804 mono_arch_get_call_filter ();
7805 mono_arch_get_throw_exception ();
7806 mono_arch_get_rethrow_exception ();
7811 mono_get_trampoline_code (MonoTrampolineType tramp_type
)
7813 return mono_trampoline_code
[tramp_type
];
7817 mono_create_class_init_trampoline (MonoVTable
*vtable
)
7821 /* previously created trampoline code */
7822 mono_domain_lock (vtable
->domain
);
7824 g_hash_table_lookup (vtable
->domain
->class_init_trampoline_hash
,
7826 mono_domain_unlock (vtable
->domain
);
7830 #ifdef MONO_ARCH_HAVE_CREATE_SPECIFIC_TRAMPOLINE
7831 code
= mono_arch_create_specific_trampoline (vtable
, MONO_TRAMPOLINE_CLASS_INIT
, vtable
->domain
, NULL
);
7833 code
= mono_arch_create_class_init_trampoline (vtable
);
7836 ptr
= mono_create_ftnptr (vtable
->domain
, code
);
7838 /* store trampoline address */
7839 mono_domain_lock (vtable
->domain
);
7840 g_hash_table_insert (vtable
->domain
->class_init_trampoline_hash
,
7842 mono_domain_unlock (vtable
->domain
);
7845 if (!class_init_hash_addr
)
7846 class_init_hash_addr
= g_hash_table_new (NULL
, NULL
);
7847 g_hash_table_insert (class_init_hash_addr
, ptr
, vtable
);
7854 mono_create_jump_trampoline (MonoDomain
*domain
, MonoMethod
*method
,
7855 gboolean add_sync_wrapper
)
7859 #ifdef MONO_ARCH_HAVE_CREATE_SPECIFIC_TRAMPOLINE
7863 if (add_sync_wrapper
&& method
->iflags
& METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED
)
7864 return mono_create_jump_trampoline (domain
, mono_marshal_get_synchronized_wrapper (method
), FALSE
);
7866 code
= mono_jit_find_compiled_method (domain
, method
);
7870 mono_domain_lock (domain
);
7871 code
= g_hash_table_lookup (domain
->jump_trampoline_hash
, method
);
7872 mono_domain_unlock (domain
);
7876 #ifdef MONO_ARCH_HAVE_CREATE_SPECIFIC_TRAMPOLINE
7877 code
= mono_arch_create_specific_trampoline (method
, MONO_TRAMPOLINE_JUMP
, mono_domain_get (), &code_size
);
7879 mono_domain_lock (domain
);
7880 ji
= mono_mempool_alloc0 (domain
->mp
, sizeof (MonoJitInfo
));
7881 mono_domain_unlock (domain
);
7882 ji
->code_start
= code
;
7883 ji
->code_size
= code_size
;
7884 ji
->method
= method
;
7886 ji
= mono_arch_create_jump_trampoline (method
);
7890 * mono_delegate_ctor needs to find the method metadata from the
7891 * trampoline address, so we save it here.
7894 mono_jit_info_table_add (domain
, ji
);
7896 mono_domain_lock (domain
);
7897 g_hash_table_insert (domain
->jump_trampoline_hash
, method
, ji
->code_start
);
7898 mono_domain_unlock (domain
);
7900 return ji
->code_start
;
7904 mono_create_jit_trampoline_in_domain (MonoDomain
*domain
, MonoMethod
*method
)
7908 mono_domain_lock (domain
);
7909 tramp
= g_hash_table_lookup (domain
->jit_trampoline_hash
, method
);
7910 mono_domain_unlock (domain
);
7914 if (method
->iflags
& METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED
)
7915 return mono_create_jit_trampoline (mono_marshal_get_synchronized_wrapper (method
));
7917 #ifdef MONO_ARCH_HAVE_CREATE_SPECIFIC_TRAMPOLINE
7918 tramp
= mono_arch_create_specific_trampoline (method
, MONO_TRAMPOLINE_GENERIC
, domain
, NULL
);
7920 tramp
= mono_arch_create_jit_trampoline (method
);
7923 mono_domain_lock (domain
);
7924 g_hash_table_insert (domain
->jit_trampoline_hash
, method
, tramp
);
7925 mono_domain_unlock (domain
);
7927 mono_jit_stats
.method_trampolines
++;
7933 mono_create_jit_trampoline (MonoMethod
*method
)
7935 return mono_create_jit_trampoline_in_domain (mono_domain_get (), method
);
7938 #ifdef MONO_ARCH_HAVE_CREATE_TRAMPOLINE_FROM_TOKEN
7940 mono_create_jit_trampoline_from_token (MonoImage
*image
, guint32 token
)
7944 MonoDomain
*domain
= mono_domain_get ();
7945 guint8
*buf
, *start
;
7947 mono_domain_lock (domain
);
7948 buf
= start
= mono_code_manager_reserve (domain
->code_mp
, 2 * sizeof (gpointer
));
7949 mono_domain_unlock (domain
);
7951 *(gpointer
*)(gpointer
)buf
= image
;
7952 buf
+= sizeof (gpointer
);
7953 *(guint32
*)(gpointer
)buf
= token
;
7955 tramp
= mono_arch_create_specific_trampoline (start
, MONO_TRAMPOLINE_AOT
, domain
, NULL
);
7957 mono_jit_stats
.method_trampolines
++;
7964 mono_create_delegate_trampoline (MonoMethod
*method
, gpointer addr
)
7966 #ifdef MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE
7969 MonoDomain
*domain
= mono_domain_get ();
7972 code
= mono_jit_find_compiled_method (domain
, method
);
7977 * FIXME: We should return a function descriptor here but it is not stored
7978 * anywhere so it would be leaked.
7982 mono_domain_lock (domain
);
7983 ptr
= g_hash_table_lookup (domain
->delegate_trampoline_hash
, method
);
7984 mono_domain_unlock (domain
);
7988 code
= mono_arch_create_specific_trampoline (method
, MONO_TRAMPOLINE_DELEGATE
, domain
, &code_size
);
7990 ptr
= mono_create_ftnptr (domain
, code
);
7992 /* store trampoline address */
7993 mono_domain_lock (domain
);
7994 g_hash_table_insert (domain
->delegate_trampoline_hash
,
7996 mono_domain_unlock (domain
);
8005 mono_find_class_init_trampoline_by_addr (gconstpointer addr
)
8010 if (class_init_hash_addr
)
8011 res
= g_hash_table_lookup (class_init_hash_addr
, addr
);
8019 mono_dynamic_code_hash_insert (MonoDomain
*domain
, MonoMethod
*method
, MonoJitDynamicMethodInfo
*ji
)
8021 if (!domain
->dynamic_code_hash
)
8022 domain
->dynamic_code_hash
= g_hash_table_new (NULL
, NULL
);
8023 g_hash_table_insert (domain
->dynamic_code_hash
, method
, ji
);
8026 static MonoJitDynamicMethodInfo
*
8027 mono_dynamic_code_hash_lookup (MonoDomain
*domain
, MonoMethod
*method
)
8029 MonoJitDynamicMethodInfo
*res
;
8031 if (domain
->dynamic_code_hash
)
8032 res
= g_hash_table_lookup (domain
->dynamic_code_hash
, method
);
8045 * mono_allocate_stack_slots_full:
8047 * Allocate stack slots for all non register allocated variables using a
8048 * linear scan algorithm.
8049 * Returns: an array of stack offsets which the caller should free.
8050 * STACK_SIZE is set to the amount of stack space needed.
8051 * STACK_ALIGN is set to the alignment needed by the locals area.
8054 mono_allocate_stack_slots_full (MonoCompile
*m
, gboolean backward
, guint32
*stack_size
, guint32
*stack_align
)
8056 int i
, slot
, offset
, size
;
8061 GList
*vars
= NULL
, *l
;
8062 StackSlotInfo
*scalar_stack_slots
, *vtype_stack_slots
, *slot_info
;
8066 scalar_stack_slots
= g_new0 (StackSlotInfo
, MONO_TYPE_PINNED
);
8067 vtype_stack_slots
= g_new0 (StackSlotInfo
, 256);
8070 offsets
= g_new (gint32
, m
->num_varinfo
);
8071 for (i
= 0; i
< m
->num_varinfo
; ++i
)
8074 for (i
= m
->locals_start
; i
< m
->num_varinfo
; i
++) {
8075 inst
= m
->varinfo
[i
];
8076 vmv
= MONO_VARINFO (m
, i
);
8078 if ((inst
->flags
& MONO_INST_IS_DEAD
) || inst
->opcode
== OP_REGVAR
|| inst
->opcode
== OP_REGOFFSET
)
8081 vars
= g_list_prepend (vars
, vmv
);
8084 vars
= mono_varlist_sort (m
, vars
, 0);
8087 for (l
= vars
; l
; l
= l
->next
) {
8089 inst
= m
->varinfo
[vmv
->idx
];
8091 /* inst->backend.is_pinvoke indicates native sized value types, this is used by the
8092 * pinvoke wrappers when they call functions returning structures */
8093 if (inst
->backend
.is_pinvoke
&& MONO_TYPE_ISSTRUCT (inst
->inst_vtype
) && inst
->inst_vtype
->type
!= MONO_TYPE_TYPEDBYREF
)
8094 size
= mono_class_native_size (inst
->inst_vtype
->data
.klass
, &align
);
8098 size
= mono_type_size (inst
->inst_vtype
, &ialign
);
8102 t
= mono_type_get_underlying_type (inst
->inst_vtype
);
8104 slot_info
= &scalar_stack_slots
[MONO_TYPE_I
];
8107 case MONO_TYPE_GENERICINST
:
8108 if (!mono_type_generic_inst_is_valuetype (t
)) {
8109 slot_info
= &scalar_stack_slots
[t
->type
];
8113 case MONO_TYPE_VALUETYPE
:
8114 for (i
= 0; i
< nvtypes
; ++i
)
8115 if (t
->data
.klass
== vtype_stack_slots
[i
].vtype
)
8118 slot_info
= &vtype_stack_slots
[i
];
8120 g_assert (nvtypes
< 256);
8121 vtype_stack_slots
[nvtypes
].vtype
= t
->data
.klass
;
8122 slot_info
= &vtype_stack_slots
[nvtypes
];
8127 slot_info
= &scalar_stack_slots
[t
->type
];
8132 if (m
->comp_done
& MONO_COMP_LIVENESS
) {
8133 //printf ("START %2d %08x %08x\n", vmv->idx, vmv->range.first_use.abs_pos, vmv->range.last_use.abs_pos);
8135 /* expire old intervals in active */
8136 while (slot_info
->active
) {
8137 MonoMethodVar
*amv
= (MonoMethodVar
*)slot_info
->active
->data
;
8139 if (amv
->range
.last_use
.abs_pos
> vmv
->range
.first_use
.abs_pos
)
8142 //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);
8144 slot_info
->active
= g_list_delete_link (slot_info
->active
, slot_info
->active
);
8145 slot_info
->slots
= g_list_prepend (slot_info
->slots
, GINT_TO_POINTER (offsets
[amv
->idx
]));
8149 * This also handles the case when the variable is used in an
8150 * exception region, as liveness info is not computed there.
8153 * FIXME: All valuetypes are marked as INDIRECT because of LDADDR
8156 if (! (inst
->flags
& (MONO_INST_VOLATILE
|MONO_INST_INDIRECT
))) {
8157 if (slot_info
->slots
) {
8158 slot
= GPOINTER_TO_INT (slot_info
->slots
->data
);
8160 slot_info
->slots
= g_list_delete_link (slot_info
->slots
, slot_info
->slots
);
8163 slot_info
->active
= mono_varlist_insert_sorted (m
, slot_info
->active
, vmv
, TRUE
);
8168 static int count
= 0;
8172 if (count == atoi (getenv ("COUNT")))
8173 printf ("LAST: %s\n", mono_method_full_name (m->method, TRUE));
8174 if (count > atoi (getenv ("COUNT")))
8177 mono_print_tree_nl (inst);
8181 if (slot
== 0xffffff) {
8183 * Allways allocate valuetypes to sizeof (gpointer) to allow more
8184 * efficient copying (and to work around the fact that OP_MEMCPY
8185 * and OP_MEMSET ignores alignment).
8187 if (MONO_TYPE_ISSTRUCT (t
))
8188 align
= sizeof (gpointer
);
8192 offset
+= align
- 1;
8193 offset
&= ~(align
- 1);
8197 offset
+= align
- 1;
8198 offset
&= ~(align
- 1);
8203 if (*stack_align
== 0)
8204 *stack_align
= align
;
8207 offsets
[vmv
->idx
] = slot
;
8210 for (i
= 0; i
< MONO_TYPE_PINNED
; ++i
) {
8211 g_list_free (scalar_stack_slots
[i
].active
);
8212 g_list_free (scalar_stack_slots
[i
].slots
);
8214 for (i
= 0; i
< nvtypes
; ++i
) {
8215 g_list_free (vtype_stack_slots
[i
].active
);
8216 g_list_free (vtype_stack_slots
[i
].slots
);
8218 g_free (scalar_stack_slots
);
8219 g_free (vtype_stack_slots
);
8221 *stack_size
= offset
;
8226 mono_allocate_stack_slots (MonoCompile
*m
, guint32
*stack_size
, guint32
*stack_align
)
8228 return mono_allocate_stack_slots_full (m
, TRUE
, stack_size
, stack_align
);
8232 mono_register_opcode_emulation (int opcode
, const char *name
, const char *sigstr
, gpointer func
, gboolean no_throw
)
8234 MonoJitICallInfo
*info
;
8235 MonoMethodSignature
*sig
= mono_create_icall_signature (sigstr
);
8237 if (!emul_opcode_map
)
8238 emul_opcode_map
= g_new0 (MonoJitICallInfo
*, OP_LAST
+ 1);
8240 g_assert (!sig
->hasthis
);
8241 g_assert (sig
->param_count
< 3);
8243 info
= mono_register_jit_icall (func
, name
, sig
, no_throw
);
8245 emul_opcode_map
[opcode
] = info
;
8249 register_icall (gpointer func
, const char *name
, const char *sigstr
, gboolean save
)
8251 MonoMethodSignature
*sig
;
8254 sig
= mono_create_icall_signature (sigstr
);
8258 mono_register_jit_icall (func
, name
, sig
, save
);
8262 decompose_foreach (MonoInst
*tree
, gpointer data
)
8264 static MonoJitICallInfo
*newarr_info
= NULL
;
8265 static MonoJitICallInfo
*newarr_specific_info
= NULL
;
8266 MonoJitICallInfo
*info
;
8269 switch (tree
->opcode
) {
8271 MonoCompile
*cfg
= data
;
8272 MonoInst
*iargs
[3];
8275 newarr_info
= mono_find_jit_icall_by_addr (mono_array_new
);
8276 g_assert (newarr_info
);
8277 newarr_specific_info
= mono_find_jit_icall_by_addr (mono_array_new_specific
);
8278 g_assert (newarr_specific_info
);
8281 if (cfg
->opt
& MONO_OPT_SHARED
) {
8282 NEW_DOMAINCONST (cfg
, iargs
[0]);
8283 NEW_CLASSCONST (cfg
, iargs
[1], tree
->inst_newa_class
);
8284 iargs
[2] = tree
->inst_newa_len
;
8289 MonoVTable
*vtable
= mono_class_vtable (cfg
->domain
, mono_array_class_get (tree
->inst_newa_class
, 1));
8291 NEW_VTABLECONST (cfg
, iargs
[0], vtable
);
8292 iargs
[1] = tree
->inst_newa_len
;
8294 info
= newarr_specific_info
;
8297 mono_emulate_opcode (cfg
, tree
, iargs
, info
);
8299 /* Need to decompose arguments after the the opcode is decomposed */
8300 for (i
= 0; i
< info
->sig
->param_count
; ++i
)
8301 dec_foreach (iargs
[i
], cfg
);
8304 #ifdef MONO_ARCH_SOFT_FLOAT
8315 if ((info
= mono_find_jit_opcode_emulation (tree
->opcode
))) {
8316 MonoCompile
*cfg
= data
;
8317 MonoInst
*iargs
[2];
8319 iargs
[0] = tree
->inst_i0
;
8320 iargs
[1] = tree
->inst_i1
;
8322 mono_emulate_opcode (cfg
, tree
, iargs
, info
);
8324 dec_foreach (iargs
[0], cfg
);
8325 dec_foreach (iargs
[1], cfg
);
8328 g_assert_not_reached ();
8337 if ((info
= mono_find_jit_opcode_emulation (tree
->opcode
))) {
8338 MonoCompile
*cfg
= data
;
8339 MonoInst
*iargs
[2];
8341 /* the args are in the compare opcode ... */
8342 iargs
[0] = tree
->inst_i0
;
8343 iargs
[1] = tree
->inst_i1
;
8345 mono_emulate_opcode (cfg
, tree
, iargs
, info
);
8347 dec_foreach (iargs
[0], cfg
);
8348 dec_foreach (iargs
[1], cfg
);
8351 g_assert_not_reached ();
8363 mono_inst_foreach (MonoInst
*tree
, MonoInstFunc func
, gpointer data
) {
8365 switch (mono_burg_arity
[tree
->opcode
]) {
8368 mono_inst_foreach (tree
->inst_left
, func
, data
);
8371 mono_inst_foreach (tree
->inst_left
, func
, data
);
8372 mono_inst_foreach (tree
->inst_right
, func
, data
);
8375 g_assert_not_reached ();
8382 mono_print_bb_code (MonoBasicBlock
*bb
) {
8384 MonoInst
*c
= bb
->code
;
8386 mono_print_tree (c
);
8394 print_dfn (MonoCompile
*cfg
) {
8399 g_print ("IR code for method %s\n", mono_method_full_name (cfg
->method
, TRUE
));
8401 for (i
= 0; i
< cfg
->num_bblocks
; ++i
) {
8402 bb
= cfg
->bblocks
[i
];
8403 /*if (bb->cil_code) {
8404 char* code1, *code2;
8405 code1 = mono_disasm_code_one (NULL, cfg->method, bb->cil_code, NULL);
8406 if (bb->last_ins->cil_code)
8407 code2 = mono_disasm_code_one (NULL, cfg->method, bb->last_ins->cil_code, NULL);
8409 code2 = g_strdup ("");
8411 code1 [strlen (code1) - 1] = 0;
8412 code = g_strdup_printf ("%s -> %s", code1, code2);
8416 code
= g_strdup ("\n");
8417 g_print ("\nBB%d DFN%d (len: %d): %s", bb
->block_num
, i
, bb
->cil_length
, code
);
8419 MonoInst
*c
= bb
->code
;
8421 mono_print_tree (c
);
8429 g_print ("\tprev:");
8430 for (j
= 0; j
< bb
->in_count
; ++j
) {
8431 g_print (" BB%d", bb
->in_bb
[j
]->block_num
);
8433 g_print ("\t\tsucc:");
8434 for (j
= 0; j
< bb
->out_count
; ++j
) {
8435 g_print (" BB%d", bb
->out_bb
[j
]->block_num
);
8437 g_print ("\n\tidom: BB%d\n", bb
->idom
? bb
->idom
->block_num
: -1);
8440 g_assert (mono_bitset_test_fast (bb
->dominators
, bb
->idom
->dfn
));
8443 mono_blockset_print (cfg
, bb
->dominators
, "\tdominators", bb
->idom
? bb
->idom
->dfn
: -1);
8445 mono_blockset_print (cfg
, bb
->dfrontier
, "\tdfrontier", -1);
8453 mono_bblock_add_inst (MonoBasicBlock
*bb
, MonoInst
*inst
)
8457 g_assert (bb
->code
);
8458 bb
->last_ins
->next
= inst
;
8459 bb
->last_ins
= inst
;
8461 bb
->last_ins
= bb
->code
= inst
;
8466 mono_destroy_compile (MonoCompile
*cfg
)
8468 //mono_mempool_stats (cfg->mempool);
8469 g_hash_table_destroy (cfg
->bb_hash
);
8470 mono_free_loop_info (cfg
);
8472 mono_regstate_free (cfg
->rs
);
8474 g_hash_table_destroy (cfg
->spvars
);
8476 g_hash_table_destroy (cfg
->exvars
);
8477 mono_mempool_destroy (cfg
->mempool
);
8478 g_list_free (cfg
->ldstr_list
);
8480 g_free (cfg
->varinfo
);
8482 g_free (cfg
->exception_message
);
8486 #ifdef HAVE_KW_THREAD
8487 static __thread gpointer mono_lmf_addr MONO_TLS_FAST
;
8488 #ifdef MONO_ARCH_ENABLE_MONO_LMF_VAR
8490 * When this is defined, the current lmf is stored in this tls variable instead of in
8493 static __thread gpointer mono_lmf MONO_TLS_FAST
;
8498 mono_get_jit_tls_key (void)
8500 return mono_jit_tls_id
;
8504 mono_get_lmf_tls_offset (void)
8506 #if defined(HAVE_KW_THREAD) && defined(MONO_ARCH_ENABLE_MONO_LMF_VAR)
8508 MONO_THREAD_VAR_OFFSET(mono_lmf
,offset
);
8516 mono_get_lmf_addr_tls_offset (void)
8519 MONO_THREAD_VAR_OFFSET(mono_lmf_addr
,offset
);
8526 #if defined(HAVE_KW_THREAD) && defined(MONO_ARCH_ENABLE_MONO_LMF_VAR)
8529 MonoJitTlsData
*jit_tls
;
8531 if ((jit_tls
= TlsGetValue (mono_jit_tls_id
)))
8532 return jit_tls
->lmf
;
8534 g_assert_not_reached ();
8540 mono_get_lmf_addr (void)
8542 #ifdef HAVE_KW_THREAD
8543 return mono_lmf_addr
;
8545 MonoJitTlsData
*jit_tls
;
8547 if ((jit_tls
= TlsGetValue (mono_jit_tls_id
)))
8548 return &jit_tls
->lmf
;
8550 g_assert_not_reached ();
8555 /* Called by native->managed wrappers */
8557 mono_jit_thread_attach (MonoDomain
*domain
)
8559 #ifdef HAVE_KW_THREAD
8560 if (!mono_lmf_addr
) {
8561 mono_thread_attach (domain
);
8564 if (!TlsGetValue (mono_jit_tls_id
))
8565 mono_thread_attach (domain
);
8570 * mono_thread_abort:
8571 * @obj: exception object
8573 * abort the thread, print exception information and stack trace
8576 mono_thread_abort (MonoObject
*obj
)
8578 /* MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id); */
8580 /* handle_remove should be eventually called for this thread, too
8583 mono_thread_exit ();
8587 setup_jit_tls_data (gpointer stack_start
, gpointer abort_func
)
8589 MonoJitTlsData
*jit_tls
;
8592 jit_tls
= TlsGetValue (mono_jit_tls_id
);
8596 jit_tls
= g_new0 (MonoJitTlsData
, 1);
8598 TlsSetValue (mono_jit_tls_id
, jit_tls
);
8600 jit_tls
->abort_func
= abort_func
;
8601 jit_tls
->end_of_stack
= stack_start
;
8603 lmf
= g_new0 (MonoLMF
, 1);
8606 jit_tls
->first_lmf
= lmf
;
8608 #if defined(HAVE_KW_THREAD) && defined(MONO_ARCH_ENABLE_MONO_LMF_VAR)
8609 /* jit_tls->lmf is unused */
8611 mono_lmf_addr
= &mono_lmf
;
8613 #if defined(HAVE_KW_THREAD)
8614 mono_lmf_addr
= &jit_tls
->lmf
;
8620 mono_arch_setup_jit_tls_data (jit_tls
);
8622 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
8623 mono_setup_altstack (jit_tls
);
8630 mono_thread_start_cb (gsize tid
, gpointer stack_start
, gpointer func
)
8633 void *jit_tls
= setup_jit_tls_data (stack_start
, mono_thread_abort
);
8634 thread
= mono_thread_current ();
8636 thread
->jit_data
= jit_tls
;
8639 void (*mono_thread_attach_aborted_cb
) (MonoObject
*obj
) = NULL
;
8642 mono_thread_abort_dummy (MonoObject
*obj
)
8644 if (mono_thread_attach_aborted_cb
)
8645 mono_thread_attach_aborted_cb (obj
);
8647 mono_thread_abort (obj
);
8651 mono_thread_attach_cb (gsize tid
, gpointer stack_start
)
8654 void *jit_tls
= setup_jit_tls_data (stack_start
, mono_thread_abort_dummy
);
8655 thread
= mono_thread_current ();
8657 thread
->jit_data
= jit_tls
;
8658 if (mono_profiler_get_events () & MONO_PROFILE_STATISTICAL
)
8659 setup_stat_profiler ();
8663 mini_thread_cleanup (MonoThread
*thread
)
8665 MonoJitTlsData
*jit_tls
= thread
->jit_data
;
8668 mono_arch_free_jit_tls_data (jit_tls
);
8670 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
8671 mono_free_altstack (jit_tls
);
8673 g_free (jit_tls
->first_lmf
);
8675 thread
->jit_data
= NULL
;
8676 TlsSetValue (mono_jit_tls_id
, NULL
);
8681 mono_add_patch_info (MonoCompile
*cfg
, int ip
, MonoJumpInfoType type
, gconstpointer target
)
8683 MonoJumpInfo
*ji
= mono_mempool_alloc (cfg
->mempool
, sizeof (MonoJumpInfo
));
8687 ji
->data
.target
= target
;
8688 ji
->next
= cfg
->patch_info
;
8690 cfg
->patch_info
= ji
;
8694 mono_remove_patch_info (MonoCompile
*cfg
, int ip
)
8696 MonoJumpInfo
**ji
= &cfg
->patch_info
;
8699 if ((*ji
)->ip
.i
== ip
)
8702 ji
= &((*ji
)->next
);
8707 * mono_patch_info_dup_mp:
8709 * Make a copy of PATCH_INFO, allocating memory from the mempool MP.
8712 mono_patch_info_dup_mp (MonoMemPool
*mp
, MonoJumpInfo
*patch_info
)
8714 MonoJumpInfo
*res
= mono_mempool_alloc (mp
, sizeof (MonoJumpInfo
));
8715 memcpy (res
, patch_info
, sizeof (MonoJumpInfo
));
8717 switch (patch_info
->type
) {
8718 case MONO_PATCH_INFO_LDSTR
:
8719 case MONO_PATCH_INFO_TYPE_FROM_HANDLE
:
8720 case MONO_PATCH_INFO_LDTOKEN
:
8721 case MONO_PATCH_INFO_DECLSEC
:
8722 res
->data
.token
= mono_mempool_alloc (mp
, sizeof (MonoJumpInfoToken
));
8723 memcpy (res
->data
.token
, patch_info
->data
.token
, sizeof (MonoJumpInfoToken
));
8725 case MONO_PATCH_INFO_SWITCH
:
8726 res
->data
.table
= mono_mempool_alloc (mp
, sizeof (MonoJumpInfoBBTable
));
8727 memcpy (res
->data
.table
, patch_info
->data
.table
, sizeof (MonoJumpInfoBBTable
));
8737 mono_patch_info_hash (gconstpointer data
)
8739 const MonoJumpInfo
*ji
= (MonoJumpInfo
*)data
;
8742 case MONO_PATCH_INFO_LDSTR
:
8743 case MONO_PATCH_INFO_TYPE_FROM_HANDLE
:
8744 case MONO_PATCH_INFO_LDTOKEN
:
8745 case MONO_PATCH_INFO_DECLSEC
:
8746 return (ji
->type
<< 8) | ji
->data
.token
->token
;
8748 return (ji
->type
<< 8);
8753 * mono_patch_info_equal:
8755 * This might fail to recognize equivalent patches, i.e. floats, so its only
8756 * usable in those cases where this is not a problem, i.e. sharing GOT slots
8760 mono_patch_info_equal (gconstpointer ka
, gconstpointer kb
)
8762 const MonoJumpInfo
*ji1
= (MonoJumpInfo
*)ka
;
8763 const MonoJumpInfo
*ji2
= (MonoJumpInfo
*)kb
;
8765 if (ji1
->type
!= ji2
->type
)
8768 switch (ji1
->type
) {
8769 case MONO_PATCH_INFO_LDSTR
:
8770 case MONO_PATCH_INFO_TYPE_FROM_HANDLE
:
8771 case MONO_PATCH_INFO_LDTOKEN
:
8772 case MONO_PATCH_INFO_DECLSEC
:
8773 if ((ji1
->data
.token
->image
!= ji2
->data
.token
->image
) ||
8774 (ji1
->data
.token
->token
!= ji2
->data
.token
->token
))
8778 if (ji1
->data
.name
!= ji2
->data
.name
)
8787 mono_resolve_patch_target (MonoMethod
*method
, MonoDomain
*domain
, guint8
*code
, MonoJumpInfo
*patch_info
, gboolean run_cctors
)
8789 unsigned char *ip
= patch_info
->ip
.i
+ code
;
8790 gconstpointer target
= NULL
;
8792 switch (patch_info
->type
) {
8793 case MONO_PATCH_INFO_BB
:
8794 target
= patch_info
->data
.bb
->native_offset
+ code
;
8796 case MONO_PATCH_INFO_ABS
:
8797 target
= patch_info
->data
.target
;
8799 case MONO_PATCH_INFO_LABEL
:
8800 target
= patch_info
->data
.inst
->inst_c0
+ code
;
8802 case MONO_PATCH_INFO_IP
:
8805 case MONO_PATCH_INFO_METHOD_REL
:
8806 target
= code
+ patch_info
->data
.offset
;
8808 case MONO_PATCH_INFO_INTERNAL_METHOD
: {
8809 MonoJitICallInfo
*mi
= mono_find_jit_icall_by_name (patch_info
->data
.name
);
8811 g_warning ("unknown MONO_PATCH_INFO_INTERNAL_METHOD %s", patch_info
->data
.name
);
8812 g_assert_not_reached ();
8814 target
= mono_icall_get_wrapper (mi
);
8817 case MONO_PATCH_INFO_METHOD_JUMP
: {
8820 /* get the trampoline to the method from the domain */
8821 target
= mono_create_jump_trampoline (domain
, patch_info
->data
.method
, TRUE
);
8822 if (!domain
->jump_target_hash
)
8823 domain
->jump_target_hash
= g_hash_table_new (NULL
, NULL
);
8824 list
= g_hash_table_lookup (domain
->jump_target_hash
, patch_info
->data
.method
);
8825 list
= g_slist_prepend (list
, ip
);
8826 g_hash_table_insert (domain
->jump_target_hash
, patch_info
->data
.method
, list
);
8829 case MONO_PATCH_INFO_METHOD
:
8830 if (patch_info
->data
.method
== method
) {
8833 /* get the trampoline to the method from the domain */
8834 target
= mono_create_jit_trampoline (patch_info
->data
.method
);
8836 case MONO_PATCH_INFO_SWITCH
: {
8837 gpointer
*jump_table
;
8840 if (method
&& method
->dynamic
) {
8841 jump_table
= mono_code_manager_reserve (mono_dynamic_code_hash_lookup (domain
, method
)->code_mp
, sizeof (gpointer
) * patch_info
->data
.table
->table_size
);
8843 mono_domain_lock (domain
);
8844 jump_table
= mono_code_manager_reserve (domain
->code_mp
, sizeof (gpointer
) * patch_info
->data
.table
->table_size
);
8845 mono_domain_unlock (domain
);
8848 for (i
= 0; i
< patch_info
->data
.table
->table_size
; i
++) {
8849 jump_table
[i
] = code
+ GPOINTER_TO_INT (patch_info
->data
.table
->table
[i
]);
8851 target
= jump_table
;
8854 case MONO_PATCH_INFO_METHODCONST
:
8855 case MONO_PATCH_INFO_CLASS
:
8856 case MONO_PATCH_INFO_IMAGE
:
8857 case MONO_PATCH_INFO_FIELD
:
8858 target
= patch_info
->data
.target
;
8860 case MONO_PATCH_INFO_IID
:
8861 mono_class_init (patch_info
->data
.klass
);
8862 target
= GINT_TO_POINTER ((int)patch_info
->data
.klass
->interface_id
);
8864 case MONO_PATCH_INFO_ADJUSTED_IID
:
8865 mono_class_init (patch_info
->data
.klass
);
8866 target
= GINT_TO_POINTER ((int)(-((patch_info
->data
.klass
->interface_id
+ 1) * SIZEOF_VOID_P
)));
8868 case MONO_PATCH_INFO_VTABLE
:
8869 target
= mono_class_vtable (domain
, patch_info
->data
.klass
);
8871 case MONO_PATCH_INFO_CLASS_INIT
:
8872 target
= mono_create_class_init_trampoline (mono_class_vtable (domain
, patch_info
->data
.klass
));
8874 case MONO_PATCH_INFO_SFLDA
: {
8875 MonoVTable
*vtable
= mono_class_vtable (domain
, patch_info
->data
.field
->parent
);
8876 if (!vtable
->initialized
&& !(vtable
->klass
->flags
& TYPE_ATTRIBUTE_BEFORE_FIELD_INIT
) && (method
&& mono_class_needs_cctor_run (vtable
->klass
, method
)))
8877 /* Done by the generated code */
8881 mono_runtime_class_init (vtable
);
8883 target
= (char*)vtable
->data
+ patch_info
->data
.field
->offset
;
8886 case MONO_PATCH_INFO_R4
:
8887 case MONO_PATCH_INFO_R8
:
8888 target
= patch_info
->data
.target
;
8890 case MONO_PATCH_INFO_EXC_NAME
:
8891 target
= patch_info
->data
.name
;
8893 case MONO_PATCH_INFO_LDSTR
:
8895 mono_ldstr (domain
, patch_info
->data
.token
->image
,
8896 mono_metadata_token_index (patch_info
->data
.token
->token
));
8898 case MONO_PATCH_INFO_TYPE_FROM_HANDLE
: {
8900 MonoClass
*handle_class
;
8902 handle
= mono_ldtoken (patch_info
->data
.token
->image
,
8903 patch_info
->data
.token
->token
, &handle_class
, NULL
);
8904 mono_class_init (handle_class
);
8905 mono_class_init (mono_class_from_mono_type (handle
));
8908 mono_type_get_object (domain
, handle
);
8911 case MONO_PATCH_INFO_LDTOKEN
: {
8913 MonoClass
*handle_class
;
8915 handle
= mono_ldtoken (patch_info
->data
.token
->image
,
8916 patch_info
->data
.token
->token
, &handle_class
, NULL
);
8917 mono_class_init (handle_class
);
8922 case MONO_PATCH_INFO_DECLSEC
:
8923 target
= (mono_metadata_blob_heap (patch_info
->data
.token
->image
, patch_info
->data
.token
->token
) + 2);
8925 case MONO_PATCH_INFO_BB_OVF
:
8926 case MONO_PATCH_INFO_EXC_OVF
:
8927 case MONO_PATCH_INFO_GOT_OFFSET
:
8928 case MONO_PATCH_INFO_NONE
:
8931 g_assert_not_reached ();
8934 return (gpointer
)target
;
8938 dec_foreach (MonoInst
*tree
, MonoCompile
*cfg
) {
8939 MonoJitICallInfo
*info
;
8941 decompose_foreach (tree
, cfg
);
8943 switch (mono_burg_arity
[tree
->opcode
]) {
8946 dec_foreach (tree
->inst_left
, cfg
);
8948 if ((info
= mono_find_jit_opcode_emulation (tree
->opcode
))) {
8949 MonoInst
*iargs
[2];
8951 iargs
[0] = tree
->inst_left
;
8953 mono_emulate_opcode (cfg
, tree
, iargs
, info
);
8959 #ifdef MONO_ARCH_BIGMUL_INTRINS
8960 if (tree
->opcode
== OP_LMUL
8961 && (cfg
->opt
& MONO_OPT_INTRINS
)
8962 && (tree
->inst_left
->opcode
== CEE_CONV_I8
8963 || tree
->inst_left
->opcode
== CEE_CONV_U8
)
8964 && tree
->inst_left
->inst_left
->type
== STACK_I4
8965 && (tree
->inst_right
->opcode
== CEE_CONV_I8
8966 || tree
->inst_right
->opcode
== CEE_CONV_U8
)
8967 && tree
->inst_right
->inst_left
->type
== STACK_I4
8968 && tree
->inst_left
->opcode
== tree
->inst_right
->opcode
) {
8969 tree
->opcode
= (tree
->inst_left
->opcode
== CEE_CONV_I8
? OP_BIGMUL
: OP_BIGMUL_UN
);
8970 tree
->inst_left
= tree
->inst_left
->inst_left
;
8971 tree
->inst_right
= tree
->inst_right
->inst_left
;
8972 dec_foreach (tree
, cfg
);
8975 if ((info
= mono_find_jit_opcode_emulation (tree
->opcode
))) {
8976 MonoInst
*iargs
[2];
8978 iargs
[0] = tree
->inst_i0
;
8979 iargs
[1] = tree
->inst_i1
;
8981 mono_emulate_opcode (cfg
, tree
, iargs
, info
);
8983 dec_foreach (iargs
[0], cfg
);
8984 dec_foreach (iargs
[1], cfg
);
8987 dec_foreach (tree
->inst_left
, cfg
);
8988 dec_foreach (tree
->inst_right
, cfg
);
8992 g_assert_not_reached ();
8997 decompose_pass (MonoCompile
*cfg
) {
9000 for (bb
= cfg
->bb_entry
; bb
; bb
= bb
->next_bb
) {
9003 cfg
->prev_ins
= NULL
;
9004 for (tree
= cfg
->cbb
->code
; tree
; tree
= tree
->next
) {
9005 dec_foreach (tree
, cfg
);
9006 cfg
->prev_ins
= tree
;
9012 nullify_basic_block (MonoBasicBlock
*bb
)
9019 bb
->code
= bb
->last_ins
= NULL
;
9020 bb
->cil_code
= NULL
;
9024 replace_out_block (MonoBasicBlock
*bb
, MonoBasicBlock
*orig
, MonoBasicBlock
*repl
)
9028 for (i
= 0; i
< bb
->out_count
; i
++) {
9029 MonoBasicBlock
*ob
= bb
->out_bb
[i
];
9032 if (bb
->out_count
> 1) {
9033 bb
->out_bb
[i
] = bb
->out_bb
[bb
->out_count
- 1];
9037 bb
->out_bb
[i
] = repl
;
9044 replace_in_block (MonoBasicBlock
*bb
, MonoBasicBlock
*orig
, MonoBasicBlock
*repl
)
9048 for (i
= 0; i
< bb
->in_count
; i
++) {
9049 MonoBasicBlock
*ib
= bb
->in_bb
[i
];
9052 if (bb
->in_count
> 1) {
9053 bb
->in_bb
[i
] = bb
->in_bb
[bb
->in_count
- 1];
9057 bb
->in_bb
[i
] = repl
;
9064 replace_out_block_in_code (MonoBasicBlock
*bb
, MonoBasicBlock
*orig
, MonoBasicBlock
*repl
) {
9067 for (inst
= bb
->code
; inst
!= NULL
; inst
= inst
->next
) {
9068 if (inst
->opcode
== OP_CALL_HANDLER
) {
9069 if (inst
->inst_target_bb
== orig
) {
9070 inst
->inst_target_bb
= repl
;
9074 if (bb
->last_ins
!= NULL
) {
9075 switch (bb
->last_ins
->opcode
) {
9077 if (bb
->last_ins
->inst_target_bb
== orig
) {
9078 bb
->last_ins
->inst_target_bb
= repl
;
9083 int n
= GPOINTER_TO_INT (bb
->last_ins
->klass
);
9084 for (i
= 0; i
< n
; i
++ ) {
9085 if (bb
->last_ins
->inst_many_bb
[i
] == orig
) {
9086 bb
->last_ins
->inst_many_bb
[i
] = repl
;
9101 if (bb
->last_ins
->inst_true_bb
== orig
) {
9102 bb
->last_ins
->inst_true_bb
= repl
;
9104 if (bb
->last_ins
->inst_false_bb
== orig
) {
9105 bb
->last_ins
->inst_false_bb
= repl
;
9115 replace_basic_block (MonoBasicBlock
*bb
, MonoBasicBlock
*orig
, MonoBasicBlock
*repl
)
9119 for (i
= 0; i
< bb
->out_count
; i
++) {
9120 MonoBasicBlock
*ob
= bb
->out_bb
[i
];
9121 for (j
= 0; j
< ob
->in_count
; j
++) {
9122 if (ob
->in_bb
[j
] == orig
) {
9123 ob
->in_bb
[j
] = repl
;
9131 * Check if a bb is useless (is just made of NOPs and ends with an
9132 * unconditional branch, or nothing).
9133 * If it is so, unlink it from the CFG and nullify it, and return TRUE.
9134 * Otherwise, return FALSE;
9137 remove_block_if_useless (MonoCompile
*cfg
, MonoBasicBlock
*bb
, MonoBasicBlock
*previous_bb
) {
9138 MonoBasicBlock
*target_bb
= NULL
;
9141 /* Do not touch handlers */
9142 if (bb
->region
!= -1) {
9143 bb
->not_useless
= TRUE
;
9147 for (inst
= bb
->code
; inst
!= NULL
; inst
= inst
->next
) {
9148 switch (inst
->opcode
) {
9152 target_bb
= inst
->inst_target_bb
;
9155 bb
->not_useless
= TRUE
;
9160 if (target_bb
== NULL
) {
9161 if ((bb
->out_count
== 1) && (bb
->out_bb
[0] == bb
->next_bb
)) {
9162 target_bb
= bb
->next_bb
;
9164 /* Do not touch empty BBs that do not "fall through" to their next BB (like the exit BB) */
9169 /* Do not touch BBs following a switch (they are the "default" branch) */
9170 if ((previous_bb
->last_ins
!= NULL
) && (previous_bb
->last_ins
->opcode
== CEE_SWITCH
)) {
9174 /* Do not touch BBs following the entry BB and jumping to something that is not */
9175 /* thiry "next" bb (the entry BB cannot contain the branch) */
9176 if ((previous_bb
== cfg
->bb_entry
) && (bb
->next_bb
!= target_bb
)) {
9181 * Do not touch BBs following a try block as the code in
9182 * mini_method_compile needs them to compute the length of the try block.
9184 if (MONO_BBLOCK_IS_IN_REGION (previous_bb
, MONO_REGION_TRY
))
9187 /* Check that there is a target BB, and that bb is not an empty loop (Bug 75061) */
9188 if ((target_bb
!= NULL
) && (target_bb
!= bb
)) {
9191 if (cfg
->verbose_level
> 1) {
9192 printf ("remove_block_if_useless %s, removed BB%d\n", mono_method_full_name (cfg
->method
, TRUE
), bb
->block_num
);
9195 /* unlink_bblock () modifies the bb->in_bb array so can't use a for loop here */
9196 while (bb
->in_count
) {
9197 MonoBasicBlock
*in_bb
= bb
->in_bb
[0];
9198 mono_unlink_bblock (cfg
, in_bb
, bb
);
9199 link_bblock (cfg
, in_bb
, target_bb
);
9200 replace_out_block_in_code (in_bb
, bb
, target_bb
);
9203 mono_unlink_bblock (cfg
, bb
, target_bb
);
9205 if ((previous_bb
!= cfg
->bb_entry
) &&
9206 (previous_bb
->region
== bb
->region
) &&
9207 ((previous_bb
->last_ins
== NULL
) ||
9208 ((previous_bb
->last_ins
->opcode
!= CEE_BR
) &&
9209 (! (MONO_IS_COND_BRANCH_OP (previous_bb
->last_ins
))) &&
9210 (previous_bb
->last_ins
->opcode
!= CEE_SWITCH
)))) {
9211 for (i
= 0; i
< previous_bb
->out_count
; i
++) {
9212 if (previous_bb
->out_bb
[i
] == target_bb
) {
9214 MONO_INST_NEW (cfg
, jump
, CEE_BR
);
9215 MONO_ADD_INS (previous_bb
, jump
);
9216 jump
->cil_code
= previous_bb
->cil_code
;
9217 jump
->inst_target_bb
= target_bb
;
9223 previous_bb
->next_bb
= bb
->next_bb
;
9224 nullify_basic_block (bb
);
9233 merge_basic_blocks (MonoBasicBlock
*bb
, MonoBasicBlock
*bbn
)
9235 bb
->out_count
= bbn
->out_count
;
9236 bb
->out_bb
= bbn
->out_bb
;
9238 replace_basic_block (bb
, bbn
, bb
);
9240 /* Nullify branch at the end of bb */
9241 if (bb
->last_ins
&& MONO_IS_BRANCH_OP (bb
->last_ins
)) {
9242 bb
->last_ins
->opcode
= CEE_NOP
;
9247 bb
->last_ins
->next
= bbn
->code
;
9248 bb
->last_ins
= bbn
->last_ins
;
9251 bb
->code
= bbn
->code
;
9252 bb
->last_ins
= bbn
->last_ins
;
9254 bb
->next_bb
= bbn
->next_bb
;
9255 nullify_basic_block (bbn
);
9259 move_basic_block_to_end (MonoCompile
*cfg
, MonoBasicBlock
*bb
)
9261 MonoBasicBlock
*bbn
, *next
;
9265 /* Find the previous */
9266 for (bbn
= cfg
->bb_entry
; bbn
->next_bb
&& bbn
->next_bb
!= bb
; bbn
= bbn
->next_bb
)
9269 bbn
->next_bb
= bb
->next_bb
;
9273 for (bbn
= cfg
->bb_entry
; bbn
->next_bb
; bbn
= bbn
->next_bb
)
9279 if (next
&& (!bb
->last_ins
|| (bb
->last_ins
->opcode
!= OP_NOT_REACHED
))) {
9282 MONO_INST_NEW (cfg
, ins
, CEE_BR
);
9283 MONO_ADD_INS (bb
, ins
);
9284 link_bblock (cfg
, bb
, next
);
9285 ins
->inst_target_bb
= next
;
9289 /* checks that a and b represent the same instructions, conservatively,
9290 * it can return FALSE also for two trees that are equal.
9291 * FIXME: also make sure there are no side effects.
9294 same_trees (MonoInst
*a
, MonoInst
*b
)
9297 if (a
->opcode
!= b
->opcode
)
9299 arity
= mono_burg_arity
[a
->opcode
];
9301 if (a
->ssa_op
== b
->ssa_op
&& a
->ssa_op
== MONO_SSA_LOAD
&& a
->inst_i0
== b
->inst_i0
)
9303 return same_trees (a
->inst_left
, b
->inst_left
);
9304 } else if (arity
== 2) {
9305 return same_trees (a
->inst_left
, b
->inst_left
) && same_trees (a
->inst_right
, b
->inst_right
);
9306 } else if (arity
== 0) {
9307 switch (a
->opcode
) {
9309 return a
->inst_c0
== b
->inst_c0
;
9318 get_unsigned_condbranch (int opcode
)
9321 case CEE_BLE
: return CEE_BLE_UN
;
9322 case CEE_BLT
: return CEE_BLT_UN
;
9323 case CEE_BGE
: return CEE_BGE_UN
;
9324 case CEE_BGT
: return CEE_BGT_UN
;
9326 g_assert_not_reached ();
9331 tree_is_unsigned (MonoInst
* ins
) {
9332 switch (ins
->opcode
) {
9334 return (int)ins
->inst_c0
>= 0;
9335 /* array lengths are positive as are string sizes */
9342 case CEE_CONV_OVF_U1
:
9343 case CEE_CONV_OVF_U2
:
9344 case CEE_CONV_OVF_U4
:
9355 /* check if an unsigned compare can be used instead of two signed compares
9356 * for (val < 0 || val > limit) conditionals.
9357 * Returns TRUE if the optimization has been applied.
9358 * Note that this can't be applied if the second arg is not positive...
9361 try_unsigned_compare (MonoCompile
*cfg
, MonoBasicBlock
*bb
)
9363 MonoBasicBlock
*truet
, *falset
;
9364 MonoInst
*cmp_inst
= bb
->last_ins
->inst_left
;
9366 if (!cmp_inst
->inst_right
->inst_c0
== 0)
9368 truet
= bb
->last_ins
->inst_true_bb
;
9369 falset
= bb
->last_ins
->inst_false_bb
;
9370 if (falset
->in_count
!= 1)
9372 condb
= falset
->last_ins
;
9373 /* target bb must have one instruction */
9374 if (!condb
|| (condb
!= falset
->code
))
9376 if ((((condb
->opcode
== CEE_BLE
|| condb
->opcode
== CEE_BLT
) && (condb
->inst_false_bb
== truet
))
9377 || ((condb
->opcode
== CEE_BGE
|| condb
->opcode
== CEE_BGT
) && (condb
->inst_true_bb
== truet
)))
9378 && same_trees (cmp_inst
->inst_left
, condb
->inst_left
->inst_left
)) {
9379 if (!tree_is_unsigned (condb
->inst_left
->inst_right
))
9381 condb
->opcode
= get_unsigned_condbranch (condb
->opcode
);
9382 /* change the original condbranch to just point to the new unsigned check */
9383 bb
->last_ins
->opcode
= CEE_BR
;
9384 bb
->last_ins
->inst_target_bb
= falset
;
9385 replace_out_block (bb
, truet
, NULL
);
9386 replace_in_block (truet
, bb
, NULL
);
9393 * Optimizes the branches on the Control Flow Graph
9397 optimize_branches (MonoCompile
*cfg
)
9399 int i
, changed
= FALSE
;
9400 MonoBasicBlock
*bb
, *bbn
;
9401 guint32 niterations
;
9404 * Some crazy loops could cause the code below to go into an infinite
9405 * loop, see bug #53003 for an example. To prevent this, we put an upper
9406 * bound on the number of iterations.
9408 if (cfg
->num_bblocks
> 1000)
9409 niterations
= cfg
->num_bblocks
* 2;
9414 MonoBasicBlock
*previous_bb
;
9418 /* we skip the entry block (exit is handled specially instead ) */
9419 for (previous_bb
= cfg
->bb_entry
, bb
= cfg
->bb_entry
->next_bb
; bb
; previous_bb
= bb
, bb
= bb
->next_bb
) {
9421 /* dont touch code inside exception clauses */
9422 if (bb
->region
!= -1)
9425 if (!bb
->not_useless
&& remove_block_if_useless (cfg
, bb
, previous_bb
)) {
9430 if ((bbn
= bb
->next_bb
) && bbn
->in_count
== 0 && bb
->region
== bbn
->region
) {
9431 if (cfg
->verbose_level
> 2)
9432 g_print ("nullify block triggered %d\n", bbn
->block_num
);
9434 bb
->next_bb
= bbn
->next_bb
;
9436 for (i
= 0; i
< bbn
->out_count
; i
++)
9437 replace_in_block (bbn
->out_bb
[i
], bbn
, NULL
);
9439 nullify_basic_block (bbn
);
9443 if (bb
->out_count
== 1) {
9444 bbn
= bb
->out_bb
[0];
9446 /* conditional branches where true and false targets are the same can be also replaced with CEE_BR */
9447 if (bb
->last_ins
&& MONO_IS_COND_BRANCH_OP (bb
->last_ins
)) {
9449 MONO_INST_NEW (cfg
, pop
, CEE_POP
);
9450 pop
->inst_left
= bb
->last_ins
->inst_left
->inst_left
;
9451 mono_add_ins_to_end (bb
, pop
);
9452 MONO_INST_NEW (cfg
, pop
, CEE_POP
);
9453 pop
->inst_left
= bb
->last_ins
->inst_left
->inst_right
;
9454 mono_add_ins_to_end (bb
, pop
);
9455 bb
->last_ins
->opcode
= CEE_BR
;
9456 bb
->last_ins
->inst_target_bb
= bb
->last_ins
->inst_true_bb
;
9458 if (cfg
->verbose_level
> 2)
9459 g_print ("cond branch removal triggered in %d %d\n", bb
->block_num
, bb
->out_count
);
9462 if (bb
->region
== bbn
->region
&& bb
->next_bb
== bbn
) {
9463 /* the block are in sequence anyway ... */
9465 /* branches to the following block can be removed */
9466 if (bb
->last_ins
&& bb
->last_ins
->opcode
== CEE_BR
) {
9467 bb
->last_ins
->opcode
= CEE_NOP
;
9469 if (cfg
->verbose_level
> 2)
9470 g_print ("br removal triggered %d -> %d\n", bb
->block_num
, bbn
->block_num
);
9473 if (bbn
->in_count
== 1) {
9475 if (bbn
!= cfg
->bb_exit
) {
9476 if (cfg
->verbose_level
> 2)
9477 g_print ("block merge triggered %d -> %d\n", bb
->block_num
, bbn
->block_num
);
9478 merge_basic_blocks (bb
, bbn
);
9483 //mono_print_bb_code (bb);
9487 if ((bbn
= bb
->next_bb
) && bbn
->in_count
== 0 && bb
->region
== bbn
->region
) {
9488 if (cfg
->verbose_level
> 2) {
9489 g_print ("nullify block triggered %d\n", bbn
->block_num
);
9491 bb
->next_bb
= bbn
->next_bb
;
9493 for (i
= 0; i
< bbn
->out_count
; i
++)
9494 replace_in_block (bbn
->out_bb
[i
], bbn
, NULL
);
9496 nullify_basic_block (bbn
);
9501 if (bb
->out_count
== 1) {
9502 bbn
= bb
->out_bb
[0];
9504 if (bb
->last_ins
&& bb
->last_ins
->opcode
== CEE_BR
) {
9505 bbn
= bb
->last_ins
->inst_target_bb
;
9506 if (bb
->region
== bbn
->region
&& bbn
->code
&& bbn
->code
->opcode
== CEE_BR
&&
9507 bbn
->code
->inst_target_bb
->region
== bb
->region
) {
9509 if (cfg
->verbose_level
> 2)
9510 g_print ("in %s branch to branch triggered %d -> %d -> %d\n", cfg
->method
->name
,
9511 bb
->block_num
, bbn
->block_num
, bbn
->code
->inst_target_bb
->block_num
);
9513 replace_in_block (bbn
, bb
, NULL
);
9514 replace_out_block (bb
, bbn
, bbn
->code
->inst_target_bb
);
9515 link_bblock (cfg
, bb
, bbn
->code
->inst_target_bb
);
9516 bb
->last_ins
->inst_target_bb
= bbn
->code
->inst_target_bb
;
9521 } else if (bb
->out_count
== 2) {
9522 if (bb
->last_ins
&& MONO_IS_COND_BRANCH_NOFP (bb
->last_ins
)) {
9523 int branch_result
= mono_eval_cond_branch (bb
->last_ins
);
9524 MonoBasicBlock
*taken_branch_target
= NULL
, *untaken_branch_target
= NULL
;
9525 if (branch_result
== BRANCH_TAKEN
) {
9526 taken_branch_target
= bb
->last_ins
->inst_true_bb
;
9527 untaken_branch_target
= bb
->last_ins
->inst_false_bb
;
9528 } else if (branch_result
== BRANCH_NOT_TAKEN
) {
9529 taken_branch_target
= bb
->last_ins
->inst_false_bb
;
9530 untaken_branch_target
= bb
->last_ins
->inst_true_bb
;
9532 if (taken_branch_target
) {
9533 /* if mono_eval_cond_branch () is ever taken to handle
9534 * non-constant values to compare, issue a pop here.
9536 bb
->last_ins
->opcode
= CEE_BR
;
9537 bb
->last_ins
->inst_target_bb
= taken_branch_target
;
9538 mono_unlink_bblock (cfg
, bb
, untaken_branch_target
);
9542 bbn
= bb
->last_ins
->inst_true_bb
;
9543 if (bb
->region
== bbn
->region
&& bbn
->code
&& bbn
->code
->opcode
== CEE_BR
&&
9544 bbn
->code
->inst_target_bb
->region
== bb
->region
) {
9545 if (cfg
->verbose_level
> 2)
9546 g_print ("cbranch1 to branch triggered %d -> (%d) %d (0x%02x)\n",
9547 bb
->block_num
, bbn
->block_num
, bbn
->code
->inst_target_bb
->block_num
,
9551 * Unlink, then relink bblocks to avoid various
9552 * tricky situations when the two targets of the branch
9553 * are equal, or will become equal after the change.
9555 mono_unlink_bblock (cfg
, bb
, bb
->last_ins
->inst_true_bb
);
9556 mono_unlink_bblock (cfg
, bb
, bb
->last_ins
->inst_false_bb
);
9558 bb
->last_ins
->inst_true_bb
= bbn
->code
->inst_target_bb
;
9560 link_bblock (cfg
, bb
, bb
->last_ins
->inst_true_bb
);
9561 link_bblock (cfg
, bb
, bb
->last_ins
->inst_false_bb
);
9567 bbn
= bb
->last_ins
->inst_false_bb
;
9568 if (bb
->region
== bbn
->region
&& bbn
->code
&& bbn
->code
->opcode
== CEE_BR
&&
9569 bbn
->code
->inst_target_bb
->region
== bb
->region
) {
9570 if (cfg
->verbose_level
> 2)
9571 g_print ("cbranch2 to branch triggered %d -> (%d) %d (0x%02x)\n",
9572 bb
->block_num
, bbn
->block_num
, bbn
->code
->inst_target_bb
->block_num
,
9575 mono_unlink_bblock (cfg
, bb
, bb
->last_ins
->inst_true_bb
);
9576 mono_unlink_bblock (cfg
, bb
, bb
->last_ins
->inst_false_bb
);
9578 bb
->last_ins
->inst_false_bb
= bbn
->code
->inst_target_bb
;
9580 link_bblock (cfg
, bb
, bb
->last_ins
->inst_true_bb
);
9581 link_bblock (cfg
, bb
, bb
->last_ins
->inst_false_bb
);
9588 /* detect and optimize to unsigned compares checks like: if (v < 0 || v > limit */
9589 if (bb
->last_ins
&& bb
->last_ins
->opcode
== CEE_BLT
&& bb
->last_ins
->inst_left
->inst_right
->opcode
== OP_ICONST
) {
9590 if (try_unsigned_compare (cfg
, bb
)) {
9591 /*g_print ("applied in bb %d (->%d) %s\n", bb->block_num, bb->last_ins->inst_target_bb->block_num, mono_method_full_name (cfg->method, TRUE));*/
9597 if (bb
->last_ins
&& MONO_IS_COND_BRANCH_NOFP (bb
->last_ins
)) {
9598 if (bb
->last_ins
->inst_false_bb
->out_of_line
&& (bb
->region
== bb
->last_ins
->inst_false_bb
->region
)) {
9599 /* Reverse the branch */
9600 bb
->last_ins
->opcode
= reverse_branch_op (bb
->last_ins
->opcode
);
9601 bbn
= bb
->last_ins
->inst_false_bb
;
9602 bb
->last_ins
->inst_false_bb
= bb
->last_ins
->inst_true_bb
;
9603 bb
->last_ins
->inst_true_bb
= bbn
;
9605 move_basic_block_to_end (cfg
, bb
->last_ins
->inst_true_bb
);
9606 if (cfg
->verbose_level
> 2)
9607 g_print ("cbranch to throw block triggered %d.\n",
9613 } while (changed
&& (niterations
> 0));
9618 mono_compile_create_vars (MonoCompile
*cfg
)
9620 MonoMethodSignature
*sig
;
9621 MonoMethodHeader
*header
;
9624 header
= mono_method_get_header (cfg
->method
);
9626 sig
= mono_method_signature (cfg
->method
);
9628 if (!MONO_TYPE_IS_VOID (sig
->ret
)) {
9629 cfg
->ret
= mono_mempool_alloc0 (cfg
->mempool
, sizeof (MonoInst
));
9630 cfg
->ret
->opcode
= OP_RETARG
;
9631 cfg
->ret
->inst_vtype
= sig
->ret
;
9632 cfg
->ret
->klass
= mono_class_from_mono_type (sig
->ret
);
9634 if (cfg
->verbose_level
> 2)
9635 g_print ("creating vars\n");
9638 mono_compile_create_var (cfg
, &cfg
->method
->klass
->this_arg
, OP_ARG
);
9640 for (i
= 0; i
< sig
->param_count
; ++i
) {
9641 mono_compile_create_var (cfg
, sig
->params
[i
], OP_ARG
);
9642 if (sig
->params
[i
]->byref
) {
9643 cfg
->disable_ssa
= TRUE
;
9647 cfg
->locals_start
= cfg
->num_varinfo
;
9649 if (cfg
->verbose_level
> 2)
9650 g_print ("creating locals\n");
9651 for (i
= 0; i
< header
->num_locals
; ++i
)
9652 mono_compile_create_var (cfg
, header
->locals
[i
], OP_LOCAL
);
9653 if (cfg
->verbose_level
> 2)
9654 g_print ("locals done\n");
9656 #ifdef MONO_ARCH_HAVE_CREATE_VARS
9657 mono_arch_create_vars (cfg
);
9662 mono_print_code (MonoCompile
*cfg
)
9666 for (bb
= cfg
->bb_entry
; bb
; bb
= bb
->next_bb
) {
9667 MonoInst
*tree
= bb
->code
;
9672 g_print ("CODE BLOCK %d (nesting %d):\n", bb
->block_num
, bb
->nesting
);
9674 for (; tree
; tree
= tree
->next
) {
9675 mono_print_tree (tree
);
9680 bb
->last_ins
->next
= NULL
;
9684 extern const char * const mono_burg_rule_string
[];
9687 emit_state (MonoCompile
*cfg
, MBState
*state
, int goal
)
9690 int ern
= mono_burg_rule (state
, goal
);
9691 const guint16
*nts
= mono_burg_nts_data
+ mono_burg_nts
[ern
];
9693 //g_print ("rule: %s\n", mono_burg_rule_string [ern]);
9697 // state->reg1 = state->reg2; /* chain rule */
9699 #ifdef MONO_ARCH_ENABLE_EMIT_STATE_OPT
9702 state
->reg1
= mono_regstate_next_int (cfg
->rs
);
9703 //g_print ("alloc symbolic R%d (reg2: R%d) in block %d\n", state->reg1, state->reg2, cfg->cbb->block_num);
9706 state
->reg1
= mono_regstate_next_int (cfg
->rs
);
9707 state
->reg2
= mono_regstate_next_int (cfg
->rs
);
9710 #ifdef MONO_ARCH_SOFT_FLOAT
9711 state
->reg1
= mono_regstate_next_int (cfg
->rs
);
9712 state
->reg2
= mono_regstate_next_int (cfg
->rs
);
9714 state
->reg1
= mono_regstate_next_float (cfg
->rs
);
9718 #ifdef MONO_ARCH_ENABLE_EMIT_STATE_OPT
9720 * Enabling this might cause bugs to surface in the local register
9721 * allocators on some architectures like x86.
9723 if ((state
->tree
->ssa_op
== MONO_SSA_STORE
) && (state
->left
->tree
->opcode
== OP_REGVAR
)) {
9724 /* Do not optimize away reg-reg moves */
9725 if (! ((state
->right
->tree
->ssa_op
== MONO_SSA_LOAD
) && (state
->right
->left
->tree
->opcode
== OP_REGVAR
))) {
9726 state
->right
->reg1
= state
->left
->tree
->dreg
;
9735 mono_burg_kids (state
, ern
, kids
);
9737 emit_state (cfg
, kids
[0], nts
[0]);
9739 emit_state (cfg
, kids
[1], nts
[1]);
9741 g_assert (!nts
[3]);
9742 emit_state (cfg
, kids
[2], nts
[2]);
9747 // g_print ("emit: %s (%p)\n", mono_burg_rule_string [ern], state);
9748 mono_burg_emit (ern
, state
, state
->tree
, cfg
);
9751 #define DEBUG_SELECTION
9754 mini_select_instructions (MonoCompile
*cfg
)
9758 cfg
->state_pool
= mono_mempool_new ();
9759 cfg
->rs
= mono_regstate_new ();
9761 for (bb
= cfg
->bb_entry
; bb
; bb
= bb
->next_bb
) {
9762 if (bb
->last_ins
&& MONO_IS_COND_BRANCH_OP (bb
->last_ins
) &&
9763 bb
->next_bb
!= bb
->last_ins
->inst_false_bb
) {
9765 /* we are careful when inverting, since bugs like #59580
9766 * could show up when dealing with NaNs.
9768 if (MONO_IS_COND_BRANCH_NOFP(bb
->last_ins
) && bb
->next_bb
== bb
->last_ins
->inst_true_bb
) {
9769 MonoBasicBlock
*tmp
= bb
->last_ins
->inst_true_bb
;
9770 bb
->last_ins
->inst_true_bb
= bb
->last_ins
->inst_false_bb
;
9771 bb
->last_ins
->inst_false_bb
= tmp
;
9773 bb
->last_ins
->opcode
= reverse_branch_op (bb
->last_ins
->opcode
);
9775 MonoInst
*inst
= mono_mempool_alloc0 (cfg
->mempool
, sizeof (MonoInst
));
9776 inst
->opcode
= CEE_BR
;
9777 inst
->inst_target_bb
= bb
->last_ins
->inst_false_bb
;
9778 mono_bblock_add_inst (bb
, inst
);
9783 #ifdef DEBUG_SELECTION
9784 if (cfg
->verbose_level
>= 4) {
9785 for (bb
= cfg
->bb_entry
; bb
; bb
= bb
->next_bb
) {
9786 MonoInst
*tree
= bb
->code
;
9787 g_print ("DUMP BLOCK %d:\n", bb
->block_num
);
9790 for (; tree
; tree
= tree
->next
) {
9791 mono_print_tree (tree
);
9798 for (bb
= cfg
->bb_entry
; bb
; bb
= bb
->next_bb
) {
9799 MonoInst
*tree
= bb
->code
, *next
;
9805 bb
->last_ins
= NULL
;
9808 mono_regstate_reset (cfg
->rs
);
9810 #ifdef DEBUG_SELECTION
9811 if (cfg
->verbose_level
>= 3)
9812 g_print ("LABEL BLOCK %d:\n", bb
->block_num
);
9814 for (; tree
; tree
= next
) {
9816 #ifdef DEBUG_SELECTION
9817 if (cfg
->verbose_level
>= 3) {
9818 mono_print_tree (tree
);
9823 if (!(mbstate
= mono_burg_label (tree
, cfg
))) {
9824 g_warning ("unable to label tree %p", tree
);
9825 mono_print_tree (tree
);
9827 g_assert_not_reached ();
9829 emit_state (cfg
, mbstate
, MB_NTERM_stmt
);
9831 bb
->max_ireg
= cfg
->rs
->next_vireg
;
9832 bb
->max_freg
= cfg
->rs
->next_vfreg
;
9835 bb
->last_ins
->next
= NULL
;
9837 mono_mempool_empty (cfg
->state_pool
);
9839 mono_mempool_destroy (cfg
->state_pool
);
9843 mono_codegen (MonoCompile
*cfg
)
9845 MonoJumpInfo
*patch_info
;
9847 int i
, max_epilog_size
;
9850 for (bb
= cfg
->bb_entry
; bb
; bb
= bb
->next_bb
) {
9851 cfg
->spill_count
= 0;
9852 /* we reuse dfn here */
9853 /* bb->dfn = bb_count++; */
9854 mono_arch_local_regalloc (cfg
, bb
);
9857 if (cfg
->prof_options
& MONO_PROFILE_COVERAGE
)
9858 cfg
->coverage_info
= mono_profiler_coverage_alloc (cfg
->method
, cfg
->num_bblocks
);
9860 code
= mono_arch_emit_prolog (cfg
);
9862 if (cfg
->prof_options
& MONO_PROFILE_ENTER_LEAVE
)
9863 code
= mono_arch_instrument_prolog (cfg
, mono_profiler_method_enter
, code
, FALSE
);
9865 cfg
->code_len
= code
- cfg
->native_code
;
9866 cfg
->prolog_end
= cfg
->code_len
;
9868 mono_debug_open_method (cfg
);
9870 /* emit code all basic blocks */
9871 for (bb
= cfg
->bb_entry
; bb
; bb
= bb
->next_bb
) {
9872 bb
->native_offset
= cfg
->code_len
;
9873 mono_arch_output_basic_block (cfg
, bb
);
9875 if (bb
== cfg
->bb_exit
) {
9876 cfg
->epilog_begin
= cfg
->code_len
;
9878 if (cfg
->prof_options
& MONO_PROFILE_ENTER_LEAVE
) {
9879 code
= cfg
->native_code
+ cfg
->code_len
;
9880 code
= mono_arch_instrument_epilog (cfg
, mono_profiler_method_leave
, code
, FALSE
);
9881 cfg
->code_len
= code
- cfg
->native_code
;
9884 mono_arch_emit_epilog (cfg
);
9888 mono_arch_emit_exceptions (cfg
);
9890 max_epilog_size
= 0;
9892 code
= cfg
->native_code
+ cfg
->code_len
;
9894 /* we always allocate code in cfg->domain->code_mp to increase locality */
9895 cfg
->code_size
= cfg
->code_len
+ max_epilog_size
;
9896 /* fixme: align to MONO_ARCH_CODE_ALIGNMENT */
9898 if (cfg
->method
->dynamic
) {
9899 /* Allocate the code into a separate memory pool so it can be freed */
9900 cfg
->dynamic_info
= g_new0 (MonoJitDynamicMethodInfo
, 1);
9901 cfg
->dynamic_info
->code_mp
= mono_code_manager_new_dynamic ();
9902 mono_domain_lock (cfg
->domain
);
9903 mono_dynamic_code_hash_insert (cfg
->domain
, cfg
->method
, cfg
->dynamic_info
);
9904 mono_domain_unlock (cfg
->domain
);
9906 code
= mono_code_manager_reserve (cfg
->dynamic_info
->code_mp
, cfg
->code_size
);
9908 mono_domain_lock (cfg
->domain
);
9909 code
= mono_code_manager_reserve (cfg
->domain
->code_mp
, cfg
->code_size
);
9910 mono_domain_unlock (cfg
->domain
);
9913 memcpy (code
, cfg
->native_code
, cfg
->code_len
);
9914 g_free (cfg
->native_code
);
9915 cfg
->native_code
= code
;
9916 code
= cfg
->native_code
+ cfg
->code_len
;
9918 /* g_assert (((int)cfg->native_code & (MONO_ARCH_CODE_ALIGNMENT - 1)) == 0); */
9919 for (patch_info
= cfg
->patch_info
; patch_info
; patch_info
= patch_info
->next
) {
9920 switch (patch_info
->type
) {
9921 case MONO_PATCH_INFO_ABS
: {
9922 MonoJitICallInfo
*info
= mono_find_jit_icall_by_addr (patch_info
->data
.target
);
9924 //printf ("TEST %s %p\n", info->name, patch_info->data.target);
9925 if ((cfg
->method
->wrapper_type
== MONO_WRAPPER_MANAGED_TO_NATIVE
) &&
9926 strstr (cfg
->method
->name
, info
->name
))
9928 * This is an icall wrapper, and this is a call to the
9933 /* for these array methods we currently register the same function pointer
9934 * since it's a vararg function. But this means that mono_find_jit_icall_by_addr ()
9935 * will return the incorrect one depending on the order they are registered.
9936 * See tests/test-arr.cs
9938 if (strstr (info
->name
, "ves_array_new_va_") == NULL
&& strstr (info
->name
, "ves_array_element_address_") == NULL
) {
9939 patch_info
->type
= MONO_PATCH_INFO_INTERNAL_METHOD
;
9940 patch_info
->data
.name
= info
->name
;
9945 MonoVTable
*vtable
= mono_find_class_init_trampoline_by_addr (patch_info
->data
.target
);
9947 patch_info
->type
= MONO_PATCH_INFO_CLASS_INIT
;
9948 patch_info
->data
.klass
= vtable
->klass
;
9953 case MONO_PATCH_INFO_SWITCH
: {
9955 if (cfg
->method
->dynamic
) {
9956 table
= mono_code_manager_reserve (cfg
->dynamic_info
->code_mp
, sizeof (gpointer
) * patch_info
->data
.table
->table_size
);
9958 mono_domain_lock (cfg
->domain
);
9959 table
= mono_code_manager_reserve (cfg
->domain
->code_mp
, sizeof (gpointer
) * patch_info
->data
.table
->table_size
);
9960 mono_domain_unlock (cfg
->domain
);
9963 if (!cfg
->compile_aot
)
9964 /* In the aot case, the patch already points to the correct location */
9965 patch_info
->ip
.i
= patch_info
->ip
.label
->inst_c0
;
9966 for (i
= 0; i
< patch_info
->data
.table
->table_size
; i
++) {
9967 table
[i
] = GINT_TO_POINTER (patch_info
->data
.table
->table
[i
]->native_offset
);
9969 patch_info
->data
.table
->table
= (MonoBasicBlock
**)table
;
9978 if (cfg
->verbose_level
> 0) {
9979 char* nm
= mono_method_full_name (cfg
->method
, TRUE
);
9980 g_print ("Method %s emitted at %p to %p (code length %d) [%s]\n",
9982 cfg
->native_code
, cfg
->native_code
+ cfg
->code_len
, cfg
->code_len
, cfg
->domain
->friendly_name
);
9986 #ifdef MONO_ARCH_HAVE_SAVE_UNWIND_INFO
9987 mono_arch_save_unwind_info (cfg
);
9990 mono_arch_patch_code (cfg
->method
, cfg
->domain
, cfg
->native_code
, cfg
->patch_info
, cfg
->run_cctors
);
9992 if (cfg
->method
->dynamic
) {
9993 mono_code_manager_commit (cfg
->dynamic_info
->code_mp
, cfg
->native_code
, cfg
->code_size
, cfg
->code_len
);
9995 mono_domain_lock (cfg
->domain
);
9996 mono_code_manager_commit (cfg
->domain
->code_mp
, cfg
->native_code
, cfg
->code_size
, cfg
->code_len
);
9997 mono_domain_unlock (cfg
->domain
);
10000 mono_arch_flush_icache (cfg
->native_code
, cfg
->code_len
);
10002 mono_debug_close_method (cfg
);
10008 remove_critical_edges (MonoCompile
*cfg
) {
10009 MonoBasicBlock
*bb
;
10010 MonoBasicBlock
*previous_bb
;
10012 if (cfg
->verbose_level
> 3) {
10013 for (bb
= cfg
->bb_entry
; bb
; bb
= bb
->next_bb
) {
10015 printf ("remove_critical_edges %s, BEFORE BB%d (in:", mono_method_full_name (cfg
->method
, TRUE
), bb
->block_num
);
10016 for (i
= 0; i
< bb
->in_count
; i
++) {
10017 printf (" %d", bb
->in_bb
[i
]->block_num
);
10019 printf (") (out:");
10020 for (i
= 0; i
< bb
->out_count
; i
++) {
10021 printf (" %d", bb
->out_bb
[i
]->block_num
);
10024 if (bb
->last_ins
!= NULL
) {
10026 mono_print_tree (bb
->last_ins
);
10032 for (previous_bb
= cfg
->bb_entry
, bb
= previous_bb
->next_bb
; bb
!= NULL
; previous_bb
= previous_bb
->next_bb
, bb
= bb
->next_bb
) {
10033 if (bb
->in_count
> 1) {
10035 for (in_bb_index
= 0; in_bb_index
< bb
->in_count
; in_bb_index
++) {
10036 MonoBasicBlock
*in_bb
= bb
->in_bb
[in_bb_index
];
10037 if (in_bb
->out_count
> 1) {
10038 MonoBasicBlock
*new_bb
= mono_mempool_alloc0 ((cfg
)->mempool
, sizeof (MonoBasicBlock
));
10039 new_bb
->block_num
= cfg
->num_bblocks
++;
10040 // new_bb->real_offset = bb->real_offset;
10041 new_bb
->region
= bb
->region
;
10043 /* Do not alter the CFG while altering the BB list */
10044 if (previous_bb
->region
== bb
->region
) {
10045 if (previous_bb
!= cfg
->bb_entry
) {
10046 /* If previous_bb "followed through" to bb, */
10047 /* keep it linked with a CEE_BR */
10048 if ((previous_bb
->last_ins
== NULL
) ||
10049 ((previous_bb
->last_ins
->opcode
!= CEE_BR
) &&
10050 (! (MONO_IS_COND_BRANCH_OP (previous_bb
->last_ins
))) &&
10051 (previous_bb
->last_ins
->opcode
!= CEE_SWITCH
))) {
10053 /* Make sure previous_bb really falls through bb */
10054 for (i
= 0; i
< previous_bb
->out_count
; i
++) {
10055 if (previous_bb
->out_bb
[i
] == bb
) {
10057 MONO_INST_NEW (cfg
, jump
, CEE_BR
);
10058 MONO_ADD_INS (previous_bb
, jump
);
10059 jump
->cil_code
= previous_bb
->cil_code
;
10060 jump
->inst_target_bb
= bb
;
10066 /* We cannot add any inst to the entry BB, so we must */
10067 /* put a new BB in the middle to hold the CEE_BR */
10069 MonoBasicBlock
*new_bb_after_entry
= mono_mempool_alloc0 ((cfg
)->mempool
, sizeof (MonoBasicBlock
));
10070 new_bb_after_entry
->block_num
= cfg
->num_bblocks
++;
10071 // new_bb_after_entry->real_offset = bb->real_offset;
10072 new_bb_after_entry
->region
= bb
->region
;
10074 MONO_INST_NEW (cfg
, jump
, CEE_BR
);
10075 MONO_ADD_INS (new_bb_after_entry
, jump
);
10076 jump
->cil_code
= bb
->cil_code
;
10077 jump
->inst_target_bb
= bb
;
10079 previous_bb
->next_bb
= new_bb_after_entry
;
10080 previous_bb
= new_bb_after_entry
;
10082 if (cfg
->verbose_level
> 2) {
10083 printf ("remove_critical_edges %s, added helper BB%d jumping to BB%d\n", mono_method_full_name (cfg
->method
, TRUE
), new_bb_after_entry
->block_num
, bb
->block_num
);
10088 /* Insert new_bb in the BB list */
10089 previous_bb
->next_bb
= new_bb
;
10090 new_bb
->next_bb
= bb
;
10091 previous_bb
= new_bb
;
10093 /* Setup in_bb and out_bb */
10094 new_bb
->in_bb
= mono_mempool_alloc ((cfg
)->mempool
, sizeof (MonoBasicBlock
*));
10095 new_bb
->in_bb
[0] = in_bb
;
10096 new_bb
->in_count
= 1;
10097 new_bb
->out_bb
= mono_mempool_alloc ((cfg
)->mempool
, sizeof (MonoBasicBlock
*));
10098 new_bb
->out_bb
[0] = bb
;
10099 new_bb
->out_count
= 1;
10101 /* Relink in_bb and bb to (from) new_bb */
10102 replace_out_block (in_bb
, bb
, new_bb
);
10103 replace_out_block_in_code (in_bb
, bb
, new_bb
);
10104 replace_in_block (bb
, in_bb
, new_bb
);
10106 if (cfg
->verbose_level
> 2) {
10107 printf ("remove_critical_edges %s, removed critical edge from BB%d to BB%d (added BB%d)\n", mono_method_full_name (cfg
->method
, TRUE
), in_bb
->block_num
, bb
->block_num
, new_bb
->block_num
);
10114 if (cfg
->verbose_level
> 3) {
10115 for (bb
= cfg
->bb_entry
; bb
; bb
= bb
->next_bb
) {
10117 printf ("remove_critical_edges %s, AFTER BB%d (in:", mono_method_full_name (cfg
->method
, TRUE
), bb
->block_num
);
10118 for (i
= 0; i
< bb
->in_count
; i
++) {
10119 printf (" %d", bb
->in_bb
[i
]->block_num
);
10121 printf (") (out:");
10122 for (i
= 0; i
< bb
->out_count
; i
++) {
10123 printf (" %d", bb
->out_bb
[i
]->block_num
);
10126 if (bb
->last_ins
!= NULL
) {
10128 mono_print_tree (bb
->last_ins
);
10136 * mini_method_compile:
10137 * @method: the method to compile
10138 * @opts: the optimization flags to use
10139 * @domain: the domain where the method will be compiled in
10140 * @run_cctors: whether we should run type ctors if possible
10141 * @compile_aot: whether this is an AOT compilation
10142 * @parts: debug flag
10144 * Returns: a MonoCompile* pointer. Caller must check the exception_type
10145 * field in the returned struct to see if compilation succeded.
10148 mini_method_compile (MonoMethod
*method
, guint32 opts
, MonoDomain
*domain
, gboolean run_cctors
, gboolean compile_aot
, int parts
)
10150 MonoMethodHeader
*header
= mono_method_get_header (method
);
10153 MonoJitInfo
*jinfo
;
10154 int dfn
= 0, i
, code_size_ratio
;
10155 gboolean deadce_has_run
= FALSE
;
10157 mono_jit_stats
.methods_compiled
++;
10158 if (mono_profiler_get_events () & MONO_PROFILE_JIT_COMPILATION
)
10159 mono_profiler_method_jit (method
);
10161 cfg
= g_new0 (MonoCompile
, 1);
10162 cfg
->method
= method
;
10163 cfg
->mempool
= mono_mempool_new ();
10165 cfg
->prof_options
= mono_profiler_get_events ();
10166 cfg
->run_cctors
= run_cctors
;
10167 cfg
->bb_hash
= g_hash_table_new (NULL
, NULL
);
10168 cfg
->domain
= domain
;
10169 cfg
->verbose_level
= mini_verbose
;
10170 cfg
->compile_aot
= compile_aot
;
10171 cfg
->skip_visibility
= method
->skip_visibility
;
10173 cfg
->exception_type
= MONO_EXCEPTION_INVALID_PROGRAM
;
10174 cfg
->exception_message
= g_strdup_printf ("Missing or incorrect header for method %s", cfg
->method
->name
);
10175 if (cfg
->prof_options
& MONO_PROFILE_JIT_COMPILATION
)
10176 mono_profiler_method_end_jit (method
, NULL
, MONO_PROFILE_FAILED
);
10180 ip
= (guint8
*)header
->code
;
10182 cfg
->intvars
= mono_mempool_alloc0 (cfg
->mempool
, sizeof (guint16
) * STACK_MAX
* header
->max_stack
);
10183 cfg
->aliasing_info
= NULL
;
10185 if (cfg
->verbose_level
> 2)
10186 g_print ("converting method %s\n", mono_method_full_name (method
, TRUE
));
10189 * create MonoInst* which represents arguments and local variables
10191 mono_compile_create_vars (cfg
);
10193 if ((i
= mono_method_to_ir (cfg
, method
, NULL
, NULL
, cfg
->locals_start
, NULL
, NULL
, NULL
, 0, FALSE
)) < 0) {
10194 if (cfg
->prof_options
& MONO_PROFILE_JIT_COMPILATION
)
10195 mono_profiler_method_end_jit (method
, NULL
, MONO_PROFILE_FAILED
);
10196 /* cfg contains the details of the failure, so let the caller cleanup */
10200 mono_jit_stats
.basic_blocks
+= cfg
->num_bblocks
;
10201 mono_jit_stats
.max_basic_blocks
= MAX (cfg
->num_bblocks
, mono_jit_stats
.max_basic_blocks
);
10203 if ((cfg
->num_varinfo
> 2000) && !cfg
->compile_aot
) {
10205 * we disable some optimizations if there are too many variables
10206 * because JIT time may become too expensive. The actual number needs
10207 * to be tweaked and eventually the non-linear algorithms should be fixed.
10209 cfg
->opt
&= ~ (MONO_OPT_LINEARS
| MONO_OPT_COPYPROP
| MONO_OPT_CONSPROP
);
10210 cfg
->disable_ssa
= TRUE
;
10213 /*g_print ("numblocks = %d\n", cfg->num_bblocks);*/
10215 if (cfg
->opt
& MONO_OPT_BRANCH
)
10216 optimize_branches (cfg
);
10218 if (cfg
->opt
& MONO_OPT_SSAPRE
) {
10219 remove_critical_edges (cfg
);
10222 /* Depth-first ordering on basic blocks */
10223 cfg
->bblocks
= mono_mempool_alloc (cfg
->mempool
, sizeof (MonoBasicBlock
*) * (cfg
->num_bblocks
+ 1));
10225 df_visit (cfg
->bb_entry
, &dfn
, cfg
->bblocks
);
10226 if (cfg
->num_bblocks
!= dfn
+ 1) {
10227 MonoBasicBlock
*bb
;
10229 cfg
->num_bblocks
= dfn
+ 1;
10231 if (!header
->clauses
) {
10232 /* remove unreachable code, because the code in them may be
10233 * inconsistent (access to dead variables for example) */
10234 for (bb
= cfg
->bb_entry
; bb
;) {
10235 MonoBasicBlock
*bbn
= bb
->next_bb
;
10237 if (bbn
&& bbn
->region
== -1 && !bbn
->dfn
) {
10238 if (cfg
->verbose_level
> 1)
10239 g_print ("found unreachable code in BB%d\n", bbn
->block_num
);
10240 bb
->next_bb
= bbn
->next_bb
;
10241 nullify_basic_block (bbn
);
10249 if (cfg
->opt
& MONO_OPT_LOOP
) {
10250 mono_compile_dominator_info (cfg
, MONO_COMP_DOM
| MONO_COMP_IDOM
);
10251 mono_compute_natural_loops (cfg
);
10254 /* after method_to_ir */
10258 //#define DEBUGSSA "logic_run"
10259 #define DEBUGSSA_CLASS "Tests"
10262 if (!header
->num_clauses
&& !cfg
->disable_ssa
) {
10263 mono_local_cprop (cfg
);
10264 mono_ssa_compute (cfg
);
10268 /* fixme: add all optimizations which requires SSA */
10269 if (cfg
->opt
& (MONO_OPT_SSA
| MONO_OPT_ABCREM
| MONO_OPT_SSAPRE
)) {
10270 if (!(cfg
->comp_done
& MONO_COMP_SSA
) && !header
->num_clauses
&& !cfg
->disable_ssa
) {
10271 mono_local_cprop (cfg
);
10272 mono_ssa_compute (cfg
);
10274 if (cfg
->verbose_level
>= 2) {
10281 /* after SSA translation */
10285 if ((cfg
->opt
& MONO_OPT_CONSPROP
) || (cfg
->opt
& MONO_OPT_COPYPROP
)) {
10286 if (cfg
->comp_done
& MONO_COMP_SSA
) {
10287 mono_ssa_cprop (cfg
);
10289 mono_local_cprop (cfg
);
10293 if (cfg
->comp_done
& MONO_COMP_SSA
) {
10294 //mono_ssa_deadce (cfg);
10296 //mono_ssa_strength_reduction (cfg);
10298 if (cfg
->opt
& MONO_OPT_SSAPRE
) {
10299 mono_perform_ssapre (cfg
);
10300 //mono_local_cprop (cfg);
10303 if (cfg
->opt
& MONO_OPT_DEADCE
) {
10304 mono_ssa_deadce (cfg
);
10305 deadce_has_run
= TRUE
;
10308 if ((cfg
->flags
& MONO_CFG_HAS_LDELEMA
) && (cfg
->opt
& MONO_OPT_ABCREM
))
10309 mono_perform_abc_removal (cfg
);
10311 mono_ssa_remove (cfg
);
10313 if (cfg
->opt
& MONO_OPT_BRANCH
)
10314 optimize_branches (cfg
);
10317 /* after SSA removal */
10321 if (cfg
->verbose_level
> 4) {
10322 printf ("BEFORE DECOMPSE START\n");
10323 mono_print_code (cfg
);
10324 printf ("BEFORE DECOMPSE END\n");
10327 decompose_pass (cfg
);
10329 if (cfg
->got_var
) {
10332 g_assert (cfg
->got_var_allocated
);
10335 * Allways allocate the GOT var to a register, because keeping it
10336 * in memory will increase the number of live temporaries in some
10337 * code created by inssel.brg, leading to the well known spills+
10338 * branches problem. Testcase: mcs crash in
10339 * System.MonoCustomAttrs:GetCustomAttributes.
10341 regs
= mono_arch_get_global_int_regs (cfg
);
10343 cfg
->got_var
->opcode
= OP_REGVAR
;
10344 cfg
->got_var
->dreg
= GPOINTER_TO_INT (regs
->data
);
10345 cfg
->used_int_regs
|= 1LL << cfg
->got_var
->dreg
;
10347 g_list_free (regs
);
10350 if (cfg
->opt
& MONO_OPT_LINEARS
) {
10351 GList
*vars
, *regs
;
10353 /* For now, compute aliasing info only if needed for deadce... */
10354 if ((cfg
->opt
& MONO_OPT_DEADCE
) && (! deadce_has_run
) && (header
->num_clauses
== 0)) {
10355 cfg
->aliasing_info
= mono_build_aliasing_information (cfg
);
10358 /* fixme: maybe we can avoid to compute livenesss here if already computed ? */
10359 cfg
->comp_done
&= ~MONO_COMP_LIVENESS
;
10360 if (!(cfg
->comp_done
& MONO_COMP_LIVENESS
))
10361 mono_analyze_liveness (cfg
);
10363 if (cfg
->aliasing_info
!= NULL
) {
10364 mono_aliasing_deadce (cfg
->aliasing_info
);
10365 deadce_has_run
= TRUE
;
10368 if ((vars
= mono_arch_get_allocatable_int_vars (cfg
))) {
10369 regs
= mono_arch_get_global_int_regs (cfg
);
10371 regs
= g_list_delete_link (regs
, regs
);
10372 mono_linear_scan (cfg
, vars
, regs
, &cfg
->used_int_regs
);
10375 if (cfg
->aliasing_info
!= NULL
) {
10376 mono_destroy_aliasing_information (cfg
->aliasing_info
);
10377 cfg
->aliasing_info
= NULL
;
10381 //mono_print_code (cfg);
10385 /* variables are allocated after decompose, since decompose could create temps */
10386 mono_arch_allocate_vars (cfg
);
10388 if (cfg
->opt
& MONO_OPT_CFOLD
)
10389 mono_constant_fold (cfg
);
10391 mini_select_instructions (cfg
);
10393 mono_codegen (cfg
);
10394 if (cfg
->verbose_level
>= 2) {
10395 char *id
= mono_method_full_name (cfg
->method
, FALSE
);
10396 mono_disassemble_code (cfg
, cfg
->native_code
, cfg
->code_len
, id
+ 3);
10400 if (cfg
->method
->dynamic
) {
10401 jinfo
= g_malloc0 (sizeof (MonoJitInfo
) + (header
->num_clauses
* sizeof (MonoJitExceptionInfo
)));
10403 /* we access cfg->domain->mp */
10404 mono_domain_lock (cfg
->domain
);
10405 jinfo
= mono_mempool_alloc0 (cfg
->domain
->mp
, sizeof (MonoJitInfo
) + (header
->num_clauses
* sizeof (MonoJitExceptionInfo
)));
10406 mono_domain_unlock (cfg
->domain
);
10409 jinfo
->method
= method
;
10410 jinfo
->code_start
= cfg
->native_code
;
10411 jinfo
->code_size
= cfg
->code_len
;
10412 jinfo
->used_regs
= cfg
->used_int_regs
;
10413 jinfo
->domain_neutral
= (cfg
->opt
& MONO_OPT_SHARED
) != 0;
10414 jinfo
->cas_inited
= FALSE
; /* initialization delayed at the first stalk walk using this method */
10416 if (header
->num_clauses
) {
10419 jinfo
->num_clauses
= header
->num_clauses
;
10421 for (i
= 0; i
< header
->num_clauses
; i
++) {
10422 MonoExceptionClause
*ec
= &header
->clauses
[i
];
10423 MonoJitExceptionInfo
*ei
= &jinfo
->clauses
[i
];
10424 MonoBasicBlock
*tblock
;
10427 ei
->flags
= ec
->flags
;
10429 exvar
= mono_find_exvar_for_offset (cfg
, ec
->handler_offset
);
10430 ei
->exvar_offset
= exvar
? exvar
->inst_offset
: 0;
10432 if (ei
->flags
== MONO_EXCEPTION_CLAUSE_FILTER
) {
10433 tblock
= g_hash_table_lookup (cfg
->bb_hash
, ip
+ ec
->data
.filter_offset
);
10435 ei
->data
.filter
= cfg
->native_code
+ tblock
->native_offset
;
10437 ei
->data
.catch_class
= ec
->data
.catch_class
;
10440 tblock
= g_hash_table_lookup (cfg
->bb_hash
, ip
+ ec
->try_offset
);
10442 ei
->try_start
= cfg
->native_code
+ tblock
->native_offset
;
10443 g_assert (tblock
->native_offset
);
10444 tblock
= g_hash_table_lookup (cfg
->bb_hash
, ip
+ ec
->try_offset
+ ec
->try_len
);
10446 ei
->try_end
= cfg
->native_code
+ tblock
->native_offset
;
10447 g_assert (tblock
->native_offset
);
10448 tblock
= g_hash_table_lookup (cfg
->bb_hash
, ip
+ ec
->handler_offset
);
10450 ei
->handler_start
= cfg
->native_code
+ tblock
->native_offset
;
10454 cfg
->jit_info
= jinfo
;
10455 #if defined(__arm__)
10456 mono_arch_fixup_jinfo (cfg
);
10459 mono_domain_lock (cfg
->domain
);
10460 mono_jit_info_table_add (cfg
->domain
, jinfo
);
10462 if (cfg
->method
->dynamic
)
10463 mono_dynamic_code_hash_lookup (cfg
->domain
, cfg
->method
)->ji
= jinfo
;
10464 mono_domain_unlock (cfg
->domain
);
10466 /* collect statistics */
10467 mono_jit_stats
.allocated_code_size
+= cfg
->code_len
;
10468 code_size_ratio
= cfg
->code_len
;
10469 if (code_size_ratio
> mono_jit_stats
.biggest_method_size
) {
10470 mono_jit_stats
.biggest_method_size
= code_size_ratio
;
10471 mono_jit_stats
.biggest_method
= method
;
10473 code_size_ratio
= (code_size_ratio
* 100) / mono_method_get_header (method
)->code_size
;
10474 if (code_size_ratio
> mono_jit_stats
.max_code_size_ratio
) {
10475 mono_jit_stats
.max_code_size_ratio
= code_size_ratio
;
10476 mono_jit_stats
.max_ratio_method
= method
;
10478 mono_jit_stats
.native_code_size
+= cfg
->code_len
;
10480 if (cfg
->prof_options
& MONO_PROFILE_JIT_COMPILATION
)
10481 mono_profiler_method_end_jit (method
, jinfo
, MONO_PROFILE_OK
);
10487 mono_jit_compile_method_inner (MonoMethod
*method
, MonoDomain
*target_domain
, int opt
)
10490 GHashTable
*jit_code_hash
;
10491 gpointer code
= NULL
;
10494 jit_code_hash
= target_domain
->jit_code_hash
;
10496 method
= mono_get_inflated_method (method
);
10498 #ifdef MONO_USE_AOT_COMPILER
10499 if ((opt
& MONO_OPT_AOT
) && !(mono_profiler_get_events () & MONO_PROFILE_JIT_COMPILATION
)) {
10500 MonoDomain
*domain
= mono_domain_get ();
10502 mono_class_init (method
->klass
);
10504 mono_domain_lock (domain
);
10505 if ((code
= mono_aot_get_method (domain
, method
))) {
10506 mono_domain_unlock (domain
);
10507 mono_runtime_class_init (mono_class_vtable (domain
, method
->klass
));
10511 mono_domain_unlock (domain
);
10515 if ((method
->iflags
& METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
) ||
10516 (method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
)) {
10518 MonoMethodPInvoke
* piinfo
= (MonoMethodPInvoke
*) method
;
10520 if (method
->iflags
& METHOD_IMPL_ATTRIBUTE_NATIVE
&& !MONO_CLASS_IS_IMPORT(method
->klass
))
10521 g_error ("Method '%s' in assembly '%s' contains native code and mono can't run it. The assembly was probably created by Managed C++.\n", mono_method_full_name (method
, TRUE
), method
->klass
->image
->name
);
10523 if (!piinfo
->addr
) {
10524 if (method
->iflags
& METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
)
10525 piinfo
->addr
= mono_lookup_internal_call (method
);
10527 if (method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
)
10528 mono_lookup_pinvoke_call (method
, NULL
, NULL
);
10530 nm
= mono_marshal_get_native_wrapper (method
);
10531 return mono_get_addr_from_ftnptr (mono_compile_method (nm
));
10533 //if (mono_debug_format != MONO_DEBUG_FORMAT_NONE)
10534 //mono_debug_add_wrapper (method, nm);
10535 } else if ((method
->iflags
& METHOD_IMPL_ATTRIBUTE_RUNTIME
)) {
10536 const char *name
= method
->name
;
10539 if (method
->klass
->parent
== mono_defaults
.multicastdelegate_class
) {
10540 if (*name
== '.' && (strcmp (name
, ".ctor") == 0)) {
10541 MonoJitICallInfo
*mi
= mono_find_jit_icall_by_name ("mono_delegate_ctor");
10543 return mono_get_addr_from_ftnptr ((gpointer
)mono_icall_get_wrapper (mi
));
10544 } else if (*name
== 'I' && (strcmp (name
, "Invoke") == 0)) {
10545 nm
= mono_marshal_get_delegate_invoke (method
);
10546 return mono_get_addr_from_ftnptr (mono_compile_method (nm
));
10547 } else if (*name
== 'B' && (strcmp (name
, "BeginInvoke") == 0)) {
10548 nm
= mono_marshal_get_delegate_begin_invoke (method
);
10549 return mono_get_addr_from_ftnptr (mono_compile_method (nm
));
10550 } else if (*name
== 'E' && (strcmp (name
, "EndInvoke") == 0)) {
10551 nm
= mono_marshal_get_delegate_end_invoke (method
);
10552 return mono_get_addr_from_ftnptr (mono_compile_method (nm
));
10558 cfg
= mini_method_compile (method
, opt
, target_domain
, TRUE
, FALSE
, 0);
10560 switch (cfg
->exception_type
) {
10561 case MONO_EXCEPTION_NONE
: break;
10562 case MONO_EXCEPTION_TYPE_LOAD
:
10563 case MONO_EXCEPTION_MISSING_FIELD
:
10564 case MONO_EXCEPTION_MISSING_METHOD
: {
10565 /* Throw a type load exception if needed */
10566 MonoLoaderError
*error
= mono_loader_get_last_error ();
10569 MonoException
*ex
= mono_loader_error_prepare_exception (error
);
10570 mono_destroy_compile (cfg
);
10571 mono_raise_exception (ex
);
10573 if (cfg
->exception_ptr
) {
10574 MonoException
*ex
= mono_class_get_exception_for_failure (cfg
->exception_ptr
);
10575 mono_destroy_compile (cfg
);
10576 mono_raise_exception (ex
);
10578 g_assert_not_reached ();
10581 case MONO_EXCEPTION_INVALID_PROGRAM
: {
10582 MonoException
*ex
= mono_exception_from_name_msg (mono_defaults
.corlib
, "System", "InvalidProgramException", cfg
->exception_message
);
10583 mono_destroy_compile (cfg
);
10584 mono_raise_exception (ex
);
10587 case MONO_EXCEPTION_UNVERIFIABLE_IL
: {
10588 MonoException
*ex
= mono_exception_from_name_msg (mono_defaults
.corlib
, "System.Security", "VerificationException", cfg
->exception_message
);
10589 mono_destroy_compile (cfg
);
10590 mono_raise_exception (ex
);
10593 /* this can only be set if the security manager is active */
10594 case MONO_EXCEPTION_SECURITY_LINKDEMAND
: {
10595 MonoAssembly
*assembly
= mono_image_get_assembly (method
->klass
->image
);
10596 MonoReflectionAssembly
*refass
= (MonoReflectionAssembly
*) mono_assembly_get_object (target_domain
, assembly
);
10597 MonoReflectionMethod
*refmet
= mono_method_get_object (target_domain
, method
, NULL
);
10598 MonoSecurityManager
* secman
= mono_security_manager_get_methods ();
10599 MonoObject
*exc
= NULL
;
10602 args
[0] = &cfg
->exception_data
;
10605 mono_runtime_invoke (secman
->linkdemandsecurityexception
, NULL
, args
, &exc
);
10607 mono_destroy_compile (cfg
);
10610 mono_raise_exception ((MonoException
*)exc
);
10613 g_assert_not_reached ();
10616 mono_domain_lock (target_domain
);
10618 /* Check if some other thread already did the job. In this case, we can
10619 discard the code this thread generated. */
10621 if ((info
= g_hash_table_lookup (target_domain
->jit_code_hash
, method
))) {
10622 /* We can't use a domain specific method in another domain */
10623 if ((target_domain
== mono_domain_get ()) || info
->domain_neutral
) {
10624 code
= info
->code_start
;
10625 // printf("Discarding code for method %s\n", method->name);
10629 if (code
== NULL
) {
10630 g_hash_table_insert (jit_code_hash
, method
, cfg
->jit_info
);
10631 code
= cfg
->native_code
;
10634 mono_destroy_compile (cfg
);
10636 if (target_domain
->jump_target_hash
) {
10637 MonoJumpInfo patch_info
;
10638 GSList
*list
, *tmp
;
10639 list
= g_hash_table_lookup (target_domain
->jump_target_hash
, method
);
10641 patch_info
.next
= NULL
;
10642 patch_info
.ip
.i
= 0;
10643 patch_info
.type
= MONO_PATCH_INFO_METHOD_JUMP
;
10644 patch_info
.data
.method
= method
;
10645 g_hash_table_remove (target_domain
->jump_target_hash
, method
);
10647 for (tmp
= list
; tmp
; tmp
= tmp
->next
)
10648 mono_arch_patch_code (NULL
, target_domain
, tmp
->data
, &patch_info
, TRUE
);
10649 g_slist_free (list
);
10652 mono_domain_unlock (target_domain
);
10654 mono_runtime_class_init (mono_class_vtable (target_domain
, method
->klass
));
10659 mono_jit_compile_method_with_opt (MonoMethod
*method
, guint32 opt
)
10661 MonoDomain
*target_domain
, *domain
= mono_domain_get ();
10664 MonoJitICallInfo
*callinfo
= NULL
;
10667 * ICALL wrappers are handled specially, since there is only one copy of them
10668 * shared by all appdomains.
10670 if ((method
->wrapper_type
== MONO_WRAPPER_MANAGED_TO_NATIVE
) && (strstr (method
->name
, "__icall_wrapper_") == method
->name
)) {
10671 const char *icall_name
;
10673 icall_name
= method
->name
+ strlen ("__icall_wrapper_");
10674 g_assert (icall_name
);
10675 callinfo
= mono_find_jit_icall_by_name (icall_name
);
10676 g_assert (callinfo
);
10678 /* Must be domain neutral since there is only one copy */
10679 opt
|= MONO_OPT_SHARED
;
10682 if (opt
& MONO_OPT_SHARED
)
10683 target_domain
= mono_get_root_domain ();
10685 target_domain
= domain
;
10687 mono_domain_lock (target_domain
);
10689 if ((info
= g_hash_table_lookup (target_domain
->jit_code_hash
, method
))) {
10690 /* We can't use a domain specific method in another domain */
10691 if (! ((domain
!= target_domain
) && !info
->domain_neutral
)) {
10692 mono_domain_unlock (target_domain
);
10693 mono_jit_stats
.methods_lookups
++;
10694 mono_runtime_class_init (mono_class_vtable (domain
, method
->klass
));
10695 return mono_create_ftnptr (target_domain
, info
->code_start
);
10699 mono_domain_unlock (target_domain
);
10700 p
= mono_create_ftnptr (target_domain
, mono_jit_compile_method_inner (method
, target_domain
, opt
));
10704 if (!callinfo
->wrapper
) {
10705 callinfo
->wrapper
= p
;
10706 mono_register_jit_icall_wrapper (callinfo
, p
);
10707 mono_debug_add_icall_wrapper (method
, callinfo
);
10709 mono_jit_unlock ();
10716 mono_jit_compile_method (MonoMethod
*method
)
10718 return mono_jit_compile_method_with_opt (method
, default_opt
);
10722 invalidated_delegate_trampoline (char *desc
)
10724 g_error ("Unmanaged code called delegate of type %s which was already garbage collected.\n"
10725 "See http://www.go-mono.com/delegate.html for an explanation and ways to fix this.",
10730 * mono_jit_free_method:
10732 * Free all memory allocated by the JIT for METHOD.
10735 mono_jit_free_method (MonoDomain
*domain
, MonoMethod
*method
)
10737 MonoJitDynamicMethodInfo
*ji
;
10738 gboolean destroy
= TRUE
;
10740 g_assert (method
->dynamic
);
10742 mono_domain_lock (domain
);
10743 ji
= mono_dynamic_code_hash_lookup (domain
, method
);
10744 mono_domain_unlock (domain
);
10748 mono_domain_lock (domain
);
10749 g_hash_table_remove (domain
->dynamic_code_hash
, method
);
10750 g_hash_table_remove (domain
->jit_code_hash
, method
);
10751 g_hash_table_remove (domain
->jump_trampoline_hash
, method
);
10752 mono_domain_unlock (domain
);
10754 #ifdef MONO_ARCH_HAVE_INVALIDATE_METHOD
10755 if (debug_options
.keep_delegates
&& method
->wrapper_type
== MONO_WRAPPER_NATIVE_TO_MANAGED
) {
10757 * Instead of freeing the code, change it to call an error routine
10758 * so people can fix their code.
10760 char *type
= mono_type_full_name (&method
->klass
->byval_arg
);
10761 char *type_and_method
= g_strdup_printf ("%s.%s", type
, method
->name
);
10764 mono_arch_invalidate_method (ji
->ji
, invalidated_delegate_trampoline
, type_and_method
);
10770 * This needs to be done before freeing code_mp, since the code address is the
10771 * key in the table, so if we the code_mp first, another thread can grab the
10772 * same code address and replace our entry in the table.
10774 mono_jit_info_table_remove (domain
, ji
->ji
);
10777 mono_code_manager_destroy (ji
->code_mp
);
10783 mono_jit_find_compiled_method (MonoDomain
*domain
, MonoMethod
*method
)
10785 MonoDomain
*target_domain
;
10788 if (default_opt
& MONO_OPT_SHARED
)
10789 target_domain
= mono_get_root_domain ();
10791 target_domain
= domain
;
10793 mono_domain_lock (target_domain
);
10795 if ((info
= g_hash_table_lookup (target_domain
->jit_code_hash
, method
))) {
10796 /* We can't use a domain specific method in another domain */
10797 if (! ((domain
!= target_domain
) && !info
->domain_neutral
)) {
10798 mono_domain_unlock (target_domain
);
10799 mono_jit_stats
.methods_lookups
++;
10800 return info
->code_start
;
10804 mono_domain_unlock (target_domain
);
10810 * mono_jit_runtime_invoke:
10811 * @method: the method to invoke
10812 * @obj: this pointer
10813 * @params: array of parameter values.
10814 * @exc: used to catch exceptions objects
10817 mono_jit_runtime_invoke (MonoMethod
*method
, void *obj
, void **params
, MonoObject
**exc
)
10819 MonoMethod
*invoke
;
10820 MonoObject
*(*runtime_invoke
) (MonoObject
*this, void **params
, MonoObject
**exc
, void* compiled_method
);
10821 void* compiled_method
;
10823 if (obj
== NULL
&& !(method
->flags
& METHOD_ATTRIBUTE_STATIC
) && !method
->string_ctor
&& (method
->wrapper_type
== 0)) {
10824 g_warning ("Ignoring invocation of an instance method on a NULL instance.\n");
10828 method
= mono_get_inflated_method (method
);
10829 invoke
= mono_marshal_get_runtime_invoke (method
);
10830 runtime_invoke
= mono_jit_compile_method (invoke
);
10832 /* We need this here becuase mono_marshal_get_runtime_invoke can be place
10833 * the helper method in System.Object and not the target class
10835 mono_runtime_class_init (mono_class_vtable (mono_domain_get (), method
->klass
));
10837 compiled_method
= mono_jit_compile_method (method
);
10838 return runtime_invoke (obj
, params
, exc
, compiled_method
);
10841 #ifdef PLATFORM_WIN32
10842 #define GET_CONTEXT \
10843 struct sigcontext *ctx = (struct sigcontext*)_dummy;
10845 #ifdef MONO_ARCH_USE_SIGACTION
10846 #define GET_CONTEXT \
10847 void *ctx = context;
10848 #elif defined(__sparc__)
10849 #define GET_CONTEXT \
10850 void *ctx = sigctx;
10852 #define GET_CONTEXT \
10853 void **_p = (void **)&_dummy; \
10854 struct sigcontext *ctx = (struct sigcontext *)++_p;
10858 #ifdef MONO_ARCH_USE_SIGACTION
10859 #define SIG_HANDLER_SIGNATURE(ftn) ftn (int _dummy, siginfo_t *info, void *context)
10860 #elif defined(__sparc__)
10861 #define SIG_HANDLER_SIGNATURE(ftn) ftn (int _dummy, void *sigctx)
10863 #define SIG_HANDLER_SIGNATURE(ftn) ftn (int _dummy)
10867 SIG_HANDLER_SIGNATURE (sigfpe_signal_handler
)
10869 MonoException
*exc
= NULL
;
10870 #ifndef MONO_ARCH_USE_SIGACTION
10875 #if defined(MONO_ARCH_HAVE_IS_INT_OVERFLOW)
10876 if (mono_arch_is_int_overflow (ctx
, info
))
10877 exc
= mono_get_exception_arithmetic ();
10879 exc
= mono_get_exception_divide_by_zero ();
10881 exc
= mono_get_exception_divide_by_zero ();
10884 mono_arch_handle_exception (ctx
, exc
, FALSE
);
10888 SIG_HANDLER_SIGNATURE (sigill_signal_handler
)
10890 MonoException
*exc
;
10893 exc
= mono_get_exception_execution_engine ("SIGILL");
10895 mono_arch_handle_exception (ctx
, exc
, FALSE
);
10898 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
10900 #ifndef MONO_ARCH_USE_SIGACTION
10901 #error "Can't use sigaltstack without sigaction"
10907 SIG_HANDLER_SIGNATURE (sigsegv_signal_handler
)
10909 MonoException
*exc
= NULL
;
10912 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
10913 MonoJitTlsData
*jit_tls
= TlsGetValue (mono_jit_tls_id
);
10917 #ifdef MONO_ARCH_USE_SIGACTION
10918 if (debug_options
.collect_pagefault_stats
) {
10919 if (mono_raw_buffer_is_pagefault (info
->si_addr
)) {
10920 mono_raw_buffer_handle_pagefault (info
->si_addr
);
10923 if (mono_aot_is_pagefault (info
->si_addr
)) {
10924 mono_aot_handle_pagefault (info
->si_addr
);
10930 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
10931 /* Can't allocate memory using Boehm GC on altstack */
10932 if (jit_tls
->stack_size
&&
10933 ((guint8
*)info
->si_addr
>= (guint8
*)jit_tls
->end_of_stack
- jit_tls
->stack_size
) &&
10934 ((guint8
*)info
->si_addr
< (guint8
*)jit_tls
->end_of_stack
))
10935 exc
= mono_domain_get ()->stack_overflow_ex
;
10937 exc
= mono_domain_get ()->null_reference_ex
;
10940 ji
= mono_jit_info_table_find (mono_domain_get (), mono_arch_ip_from_context(ctx
));
10942 mono_handle_native_sigsegv (SIGSEGV
, ctx
);
10945 mono_arch_handle_exception (ctx
, exc
, FALSE
);
10949 SIG_HANDLER_SIGNATURE (sigabrt_signal_handler
)
10954 ji
= mono_jit_info_table_find (mono_domain_get (), mono_arch_ip_from_context(ctx
));
10956 mono_handle_native_sigsegv (SIGABRT
, ctx
);
10961 SIG_HANDLER_SIGNATURE (sigusr1_signal_handler
)
10963 gboolean running_managed
;
10964 MonoException
*exc
;
10965 MonoThread
*thread
= mono_thread_current ();
10970 if (thread
->thread_dump_requested
) {
10971 thread
->thread_dump_requested
= FALSE
;
10973 mono_print_thread_dump (ctx
);
10978 * This is an async signal, so the code below must not call anything which
10979 * is not async safe. That includes the pthread locking functions. If we
10980 * know that we interrupted managed code, then locking is safe.
10982 ji
= mono_jit_info_table_find (mono_domain_get (), mono_arch_ip_from_context(ctx
));
10983 running_managed
= ji
!= NULL
;
10985 exc
= mono_thread_request_interruption (running_managed
);
10988 mono_arch_handle_exception (ctx
, exc
, FALSE
);
10992 SIG_HANDLER_SIGNATURE (sigprof_signal_handler
)
10996 mono_profiler_stat_hit (mono_arch_ip_from_context (ctx
), ctx
);
11000 SIG_HANDLER_SIGNATURE (sigquit_signal_handler
)
11004 printf ("Full thread dump:\n");
11006 mono_threads_request_thread_dump ();
11009 * print_thread_dump () skips the current thread, since sending a signal
11010 * to it would invoke the signal handler below the sigquit signal handler,
11011 * and signal handlers don't create an lmf, so the stack walk could not
11014 mono_print_thread_dump (ctx
);
11018 SIG_HANDLER_SIGNATURE (sigint_signal_handler
)
11020 MonoException
*exc
;
11023 exc
= mono_get_exception_execution_engine ("Interrupted (SIGINT).");
11025 mono_arch_handle_exception (ctx
, exc
, FALSE
);
11029 SIG_HANDLER_SIGNATURE (sigusr2_signal_handler
)
11031 gboolean enabled
= mono_trace_is_enabled ();
11033 mono_trace_enable (!enabled
);
11036 #ifdef PLATFORM_MACOSX
11039 * This code disables the CrashReporter of MacOS X by installing
11040 * a dummy Mach exception handler.
11044 * http://darwinsource.opendarwin.org/10.4.3/xnu-792.6.22/osfmk/man/exc_server.html
11048 exc_server (mach_msg_header_t
*request_msg
,
11049 mach_msg_header_t
*reply_msg
);
11052 * The exception message
11055 mach_msg_base_t msg
; /* common mach message header */
11056 char payload
[1024]; /* opaque */
11057 } mach_exception_msg_t
;
11059 /* The exception port */
11060 static mach_port_t mach_exception_port
= VM_MAP_NULL
;
11063 * Implicitly called by exc_server. Must be public.
11065 * http://darwinsource.opendarwin.org/10.4.3/xnu-792.6.22/osfmk/man/catch_exception_raise.html
11068 catch_exception_raise (
11069 mach_port_t exception_port
,
11070 mach_port_t thread
,
11072 exception_type_t exception
,
11073 exception_data_t code
,
11074 mach_msg_type_number_t code_count
)
11076 /* consume the exception */
11077 return KERN_FAILURE
;
11081 * Exception thread handler.
11085 mach_exception_thread (void *arg
)
11088 mach_exception_msg_t request
;
11089 mach_exception_msg_t reply
;
11090 mach_msg_return_t result
;
11092 /* receive from "mach_exception_port" */
11093 result
= mach_msg (&request
.msg
.header
,
11094 MACH_RCV_MSG
| MACH_RCV_LARGE
,
11097 mach_exception_port
,
11098 MACH_MSG_TIMEOUT_NONE
,
11101 g_assert (result
== MACH_MSG_SUCCESS
);
11103 /* dispatch to catch_exception_raise () */
11104 exc_server (&request
.msg
.header
, &reply
.msg
.header
);
11106 /* send back to sender */
11107 result
= mach_msg (&reply
.msg
.header
,
11109 reply
.msg
.header
.msgh_size
,
11112 MACH_MSG_TIMEOUT_NONE
,
11115 g_assert (result
== MACH_MSG_SUCCESS
);
11121 macosx_register_exception_handler ()
11124 pthread_attr_t attr
;
11127 if (mach_exception_port
!= VM_MAP_NULL
)
11130 task
= mach_task_self ();
11132 /* create the "mach_exception_port" with send & receive rights */
11133 g_assert (mach_port_allocate (task
, MACH_PORT_RIGHT_RECEIVE
,
11134 &mach_exception_port
) == KERN_SUCCESS
);
11135 g_assert (mach_port_insert_right (task
, mach_exception_port
, mach_exception_port
,
11136 MACH_MSG_TYPE_MAKE_SEND
) == KERN_SUCCESS
);
11138 /* create the exception handler thread */
11139 g_assert (!pthread_attr_init (&attr
));
11140 g_assert (!pthread_attr_setdetachstate (&attr
, PTHREAD_CREATE_DETACHED
));
11141 g_assert (!pthread_create (&thread
, &attr
, mach_exception_thread
, NULL
));
11142 pthread_attr_destroy (&attr
);
11145 * register "mach_exception_port" as a receiver for the
11146 * EXC_BAD_ACCESS exception
11148 * http://darwinsource.opendarwin.org/10.4.3/xnu-792.6.22/osfmk/man/task_set_exception_ports.html
11150 g_assert (task_set_exception_ports (task
, EXC_MASK_BAD_ACCESS
,
11151 mach_exception_port
,
11153 MACHINE_THREAD_STATE
) == KERN_SUCCESS
);
11157 #ifndef PLATFORM_WIN32
11159 add_signal_handler (int signo
, gpointer handler
)
11161 struct sigaction sa
;
11163 #ifdef MONO_ARCH_USE_SIGACTION
11164 sa
.sa_sigaction
= handler
;
11165 sigemptyset (&sa
.sa_mask
);
11166 sa
.sa_flags
= SA_SIGINFO
;
11168 sa
.sa_handler
= handler
;
11169 sigemptyset (&sa
.sa_mask
);
11172 g_assert (sigaction (signo
, &sa
, NULL
) != -1);
11176 remove_signal_handler (int signo
)
11178 struct sigaction sa
;
11180 sa
.sa_handler
= SIG_DFL
;
11181 sigemptyset (&sa
.sa_mask
);
11184 g_assert (sigaction (signo
, &sa
, NULL
) != -1);
11189 mono_runtime_install_handlers (void)
11191 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
11192 struct sigaction sa
;
11195 #ifdef PLATFORM_WIN32
11197 win32_seh_set_handler(SIGFPE
, sigfpe_signal_handler
);
11198 win32_seh_set_handler(SIGILL
, sigill_signal_handler
);
11199 win32_seh_set_handler(SIGSEGV
, sigsegv_signal_handler
);
11200 if (debug_options
.handle_sigint
)
11201 win32_seh_set_handler(SIGINT
, sigint_signal_handler
);
11203 #else /* !PLATFORM_WIN32 */
11206 #ifdef PLATFORM_MACOSX
11207 macosx_register_exception_handler ();
11210 if (debug_options
.handle_sigint
)
11211 add_signal_handler (SIGINT
, sigint_signal_handler
);
11213 add_signal_handler (SIGFPE
, sigfpe_signal_handler
);
11214 add_signal_handler (SIGQUIT
, sigquit_signal_handler
);
11215 add_signal_handler (SIGILL
, sigill_signal_handler
);
11216 add_signal_handler (SIGBUS
, sigsegv_signal_handler
);
11217 if (mono_jit_trace_calls
!= NULL
)
11218 add_signal_handler (SIGUSR2
, sigusr2_signal_handler
);
11220 add_signal_handler (mono_thread_get_abort_signal (), sigusr1_signal_handler
);
11221 signal (SIGPIPE
, SIG_IGN
);
11223 add_signal_handler (SIGABRT
, sigabrt_signal_handler
);
11225 /* catch SIGSEGV */
11226 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
11227 sa
.sa_sigaction
= sigsegv_signal_handler
;
11228 sigemptyset (&sa
.sa_mask
);
11229 sa
.sa_flags
= SA_SIGINFO
| SA_ONSTACK
;
11230 g_assert (sigaction (SIGSEGV
, &sa
, NULL
) != -1);
11232 add_signal_handler (SIGSEGV
, sigsegv_signal_handler
);
11234 #endif /* PLATFORM_WIN32 */
11238 mono_runtime_cleanup_handlers (void)
11240 #ifdef PLATFORM_WIN32
11241 win32_seh_cleanup();
11243 if (debug_options
.handle_sigint
)
11244 remove_signal_handler (SIGINT
);
11246 remove_signal_handler (SIGFPE
);
11247 remove_signal_handler (SIGQUIT
);
11248 remove_signal_handler (SIGILL
);
11249 remove_signal_handler (SIGBUS
);
11250 if (mono_jit_trace_calls
!= NULL
)
11251 remove_signal_handler (SIGUSR2
);
11253 remove_signal_handler (mono_thread_get_abort_signal ());
11255 remove_signal_handler (SIGABRT
);
11257 remove_signal_handler (SIGSEGV
);
11258 #endif /* PLATFORM_WIN32 */
11262 #ifdef HAVE_LINUX_RTC_H
11263 #include <linux/rtc.h>
11264 #include <sys/ioctl.h>
11266 static int rtc_fd
= -1;
11269 enable_rtc_timer (gboolean enable
)
11272 flags
= fcntl (rtc_fd
, F_GETFL
);
11274 perror ("getflags");
11281 if (fcntl (rtc_fd
, F_SETFL
, flags
) == -1) {
11282 perror ("setflags");
11290 setup_stat_profiler (void)
11293 struct itimerval itval
;
11294 static int inited
= 0;
11295 #ifdef HAVE_LINUX_RTC_H
11296 const char *rtc_freq
;
11297 if (!inited
&& (rtc_freq
= g_getenv ("MONO_RTC"))) {
11301 freq
= atoi (rtc_freq
);
11304 rtc_fd
= open ("/dev/rtc", O_RDONLY
);
11305 if (rtc_fd
== -1) {
11306 perror ("open /dev/rtc");
11309 add_signal_handler (SIGPROF
, sigprof_signal_handler
);
11310 if (ioctl (rtc_fd
, RTC_IRQP_SET
, freq
) == -1) {
11311 perror ("set rtc freq");
11314 if (ioctl (rtc_fd
, RTC_PIE_ON
, 0) == -1) {
11315 perror ("start rtc");
11318 if (fcntl (rtc_fd
, F_SETSIG
, SIGPROF
) == -1) {
11322 if (fcntl (rtc_fd
, F_SETOWN
, getpid ()) == -1) {
11326 enable_rtc_timer (TRUE
);
11333 itval
.it_interval
.tv_usec
= 999;
11334 itval
.it_interval
.tv_sec
= 0;
11335 itval
.it_value
= itval
.it_interval
;
11336 setitimer (ITIMER_PROF
, &itval
, NULL
);
11340 add_signal_handler (SIGPROF
, sigprof_signal_handler
);
11344 /* mono_jit_create_remoting_trampoline:
11345 * @method: pointer to the method info
11347 * Creates a trampoline which calls the remoting functions. This
11348 * is used in the vtable of transparent proxies.
11350 * Returns: a pointer to the newly created code
11353 mono_jit_create_remoting_trampoline (MonoMethod
*method
, MonoRemotingTarget target
)
11356 guint8
*addr
= NULL
;
11358 if ((method
->flags
& METHOD_ATTRIBUTE_ABSTRACT
) ||
11359 (mono_method_signature (method
)->hasthis
&& (method
->klass
->marshalbyref
|| method
->klass
== mono_defaults
.object_class
))) {
11360 nm
= mono_marshal_get_remoting_invoke_for_target (method
, target
);
11361 addr
= mono_compile_method (nm
);
11363 addr
= mono_compile_method (method
);
11365 return mono_get_addr_from_ftnptr (addr
);
11369 mini_parse_debug_options (void)
11371 char *options
= getenv ("MONO_DEBUG");
11372 gchar
**args
, **ptr
;
11377 args
= g_strsplit (options
, ",", -1);
11379 for (ptr
= args
; ptr
&& *ptr
; ptr
++) {
11380 const char *arg
= *ptr
;
11382 if (!strcmp (arg
, "handle-sigint"))
11383 debug_options
.handle_sigint
= TRUE
;
11384 else if (!strcmp (arg
, "keep-delegates"))
11385 debug_options
.keep_delegates
= TRUE
;
11386 else if (!strcmp (arg
, "collect-pagefault-stats"))
11387 debug_options
.collect_pagefault_stats
= TRUE
;
11388 else if (!strcmp (arg
, "break-on-unverified"))
11389 debug_options
.break_on_unverified
= TRUE
;
11391 fprintf (stderr
, "Invalid option for the MONO_DEBUG env variable: %s\n", arg
);
11392 fprintf (stderr
, "Available options: 'handle-sigint', 'keep-delegates', 'collect-pagefault-stats', 'break-on-unverified'\n");
11399 mini_init (const char *filename
)
11401 MonoDomain
*domain
;
11404 if (access ("/proc/self/maps", F_OK
) != 0) {
11405 g_print ("Mono requires /proc to be mounted.\n");
11410 /* Happens when using the embedding interface */
11411 if (!default_opt_set
)
11412 default_opt
= mono_parse_default_optimizations (NULL
);
11414 InitializeCriticalSection (&jit_mutex
);
11416 global_codeman
= mono_code_manager_new ();
11417 jit_icall_name_hash
= g_hash_table_new_full (g_str_hash
, g_str_equal
, g_free
, NULL
);
11419 mono_arch_cpu_init ();
11421 mono_init_trampolines ();
11423 mono_init_exceptions ();
11425 if (!g_thread_supported ())
11426 g_thread_init (NULL
);
11428 if (getenv ("MONO_DEBUG") != NULL
)
11429 mini_parse_debug_options ();
11432 * Handle the case when we are called from a thread different from the main thread,
11434 * FIXME: Move this to libgc where it belongs.
11436 * we used to do this only when running on valgrind,
11437 * but it happens also in other setups.
11439 #if defined(HAVE_BOEHM_GC)
11440 #if defined(HAVE_PTHREAD_GETATTR_NP) && defined(HAVE_PTHREAD_ATTR_GETSTACK)
11444 pthread_attr_t attr
;
11445 pthread_getattr_np (pthread_self (), &attr
);
11446 pthread_attr_getstack (&attr
, &sstart
, &size
);
11447 pthread_attr_destroy (&attr
);
11448 /*g_print ("stackbottom pth is: %p\n", (char*)sstart + size);*/
11451 * The calculation above doesn't seem to work on ia64, also we need to set
11452 * GC_register_stackbottom as well, but don't know how.
11455 /* apparently with some linuxthreads implementations sstart can be NULL,
11456 * fallback to the more imprecise method (bug# 78096).
11459 GC_stackbottom
= (char*)sstart
+ size
;
11461 gsize stack_bottom
= (gsize
)&domain
;
11462 stack_bottom
+= 4095;
11463 stack_bottom
&= ~4095;
11464 GC_stackbottom
= (char*)stack_bottom
;
11468 #elif defined(HAVE_PTHREAD_GET_STACKSIZE_NP) && defined(HAVE_PTHREAD_GET_STACKADDR_NP)
11469 GC_stackbottom
= (char*)pthread_get_stackaddr_np (pthread_self ());
11472 gsize stack_bottom
= (gsize
)&domain
;
11473 stack_bottom
+= 4095;
11474 stack_bottom
&= ~4095;
11475 /*g_print ("stackbottom is: %p\n", (char*)stack_bottom);*/
11476 GC_stackbottom
= (char*)stack_bottom
;
11480 MONO_GC_PRE_INIT ();
11482 mono_jit_tls_id
= TlsAlloc ();
11483 setup_jit_tls_data ((gpointer
)-1, mono_thread_abort
);
11487 if (default_opt
& MONO_OPT_AOT
)
11490 mono_runtime_install_handlers ();
11491 mono_threads_install_cleanup (mini_thread_cleanup
);
11493 #define JIT_TRAMPOLINES_WORK
11494 #ifdef JIT_TRAMPOLINES_WORK
11495 mono_install_compile_method (mono_jit_compile_method
);
11496 mono_install_free_method (mono_jit_free_method
);
11497 mono_install_trampoline (mono_create_jit_trampoline
);
11498 mono_install_remoting_trampoline (mono_jit_create_remoting_trampoline
);
11499 mono_install_delegate_trampoline (mono_create_delegate_trampoline
);
11501 #define JIT_INVOKE_WORKS
11502 #ifdef JIT_INVOKE_WORKS
11503 mono_install_runtime_invoke (mono_jit_runtime_invoke
);
11504 mono_install_handler (mono_arch_get_throw_exception ());
11506 mono_install_stack_walk (mono_jit_walk_stack
);
11507 mono_install_init_vtable (mono_aot_init_vtable
);
11508 mono_install_get_cached_class_info (mono_aot_get_cached_class_info
);
11509 mono_install_get_class_from_name (mono_aot_get_class_from_name
);
11510 mono_install_jit_info_find_in_aot (mono_aot_find_jit_info
);
11512 if (debug_options
.collect_pagefault_stats
) {
11513 mono_raw_buffer_set_make_unreadable (TRUE
);
11514 mono_aot_set_make_unreadable (TRUE
);
11517 domain
= mono_init_from_assembly (filename
, filename
);
11518 mono_icall_init ();
11520 mono_add_internal_call ("System.Diagnostics.StackFrame::get_frame_info",
11521 ves_icall_get_frame_info
);
11522 mono_add_internal_call ("System.Diagnostics.StackTrace::get_trace",
11523 ves_icall_get_trace
);
11524 mono_add_internal_call ("System.Exception::get_trace",
11525 ves_icall_System_Exception_get_trace
);
11526 mono_add_internal_call ("System.Security.SecurityFrame::_GetSecurityFrame",
11527 ves_icall_System_Security_SecurityFrame_GetSecurityFrame
);
11528 mono_add_internal_call ("System.Security.SecurityFrame::_GetSecurityStack",
11529 ves_icall_System_Security_SecurityFrame_GetSecurityStack
);
11530 mono_add_internal_call ("Mono.Runtime::mono_runtime_install_handlers",
11531 mono_runtime_install_handlers
);
11534 create_helper_signature ();
11536 #define JIT_CALLS_WORK
11537 #ifdef JIT_CALLS_WORK
11538 /* Needs to be called here since register_jit_icall depends on it */
11539 mono_marshal_init ();
11541 mono_arch_register_lowlevel_calls ();
11542 register_icall (mono_profiler_method_enter
, "mono_profiler_method_enter", NULL
, TRUE
);
11543 register_icall (mono_profiler_method_leave
, "mono_profiler_method_leave", NULL
, TRUE
);
11544 register_icall (mono_trace_enter_method
, "mono_trace_enter_method", NULL
, TRUE
);
11545 register_icall (mono_trace_leave_method
, "mono_trace_leave_method", NULL
, TRUE
);
11546 register_icall (mono_get_lmf_addr
, "mono_get_lmf_addr", "ptr", TRUE
);
11547 register_icall (mono_jit_thread_attach
, "mono_jit_thread_attach", "void", TRUE
);
11548 register_icall (mono_domain_get
, "mono_domain_get", "ptr", TRUE
);
11550 register_icall (mono_arch_get_throw_exception (), "mono_arch_throw_exception", "void object", TRUE
);
11551 register_icall (mono_arch_get_rethrow_exception (), "mono_arch_rethrow_exception", "void object", TRUE
);
11552 register_icall (mono_arch_get_throw_exception_by_name (), "mono_arch_throw_exception_by_name", "void ptr", TRUE
);
11553 #if MONO_ARCH_HAVE_THROW_CORLIB_EXCEPTION
11554 register_icall (mono_arch_get_throw_corlib_exception (), "mono_arch_throw_corlib_exception",
11557 register_icall (mono_thread_get_pending_exception
, "mono_thread_get_pending_exception", "object", FALSE
);
11558 register_icall (mono_thread_interruption_checkpoint
, "mono_thread_interruption_checkpoint", "void", FALSE
);
11559 register_icall (mono_thread_force_interruption_checkpoint
, "mono_thread_force_interruption_checkpoint", "void", FALSE
);
11560 register_icall (mono_load_remote_field_new
, "mono_load_remote_field_new", "object object ptr ptr", FALSE
);
11561 register_icall (mono_store_remote_field_new
, "mono_store_remote_field_new", "void object ptr ptr object", FALSE
);
11564 * NOTE, NOTE, NOTE, NOTE:
11565 * when adding emulation for some opcodes, remember to also add a dummy
11566 * rule to the burg files, because we need the arity information to be correct.
11568 #ifndef MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS
11569 mono_register_opcode_emulation (OP_LMUL
, "__emul_lmul", "long long long", mono_llmult
, TRUE
);
11570 mono_register_opcode_emulation (OP_LDIV
, "__emul_ldiv", "long long long", mono_lldiv
, FALSE
);
11571 mono_register_opcode_emulation (OP_LDIV_UN
, "__emul_ldiv_un", "long long long", mono_lldiv_un
, FALSE
);
11572 mono_register_opcode_emulation (OP_LREM
, "__emul_lrem", "long long long", mono_llrem
, FALSE
);
11573 mono_register_opcode_emulation (OP_LREM_UN
, "__emul_lrem_un", "long long long", mono_llrem_un
, FALSE
);
11574 mono_register_opcode_emulation (OP_LMUL_OVF_UN
, "__emul_lmul_ovf_un", "long long long", mono_llmult_ovf_un
, FALSE
);
11575 mono_register_opcode_emulation (OP_LMUL_OVF
, "__emul_lmul_ovf", "long long long", mono_llmult_ovf
, FALSE
);
11578 #ifndef MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
11579 mono_register_opcode_emulation (OP_LSHL
, "__emul_lshl", "long long int32", mono_lshl
, TRUE
);
11580 mono_register_opcode_emulation (OP_LSHR
, "__emul_lshr", "long long int32", mono_lshr
, TRUE
);
11581 mono_register_opcode_emulation (OP_LSHR_UN
, "__emul_lshr_un", "long long int32", mono_lshr_un
, TRUE
);
11584 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
11585 mono_register_opcode_emulation (CEE_DIV
, "__emul_idiv", "int32 int32 int32", mono_idiv
, FALSE
);
11586 mono_register_opcode_emulation (CEE_DIV_UN
, "__emul_idiv_un", "int32 int32 int32", mono_idiv_un
, FALSE
);
11587 mono_register_opcode_emulation (CEE_REM
, "__emul_irem", "int32 int32 int32", mono_irem
, FALSE
);
11588 mono_register_opcode_emulation (CEE_REM_UN
, "__emul_irem_un", "int32 int32 int32", mono_irem_un
, FALSE
);
11591 #ifdef MONO_ARCH_EMULATE_MUL_DIV
11592 mono_register_opcode_emulation (CEE_MUL_OVF
, "__emul_imul_ovf", "int32 int32 int32", mono_imul_ovf
, FALSE
);
11593 mono_register_opcode_emulation (CEE_MUL_OVF_UN
, "__emul_imul_ovf_un", "int32 int32 int32", mono_imul_ovf_un
, FALSE
);
11594 mono_register_opcode_emulation (CEE_MUL
, "__emul_imul", "int32 int32 int32", mono_imul
, TRUE
);
11596 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_SOFT_FLOAT)
11597 mono_register_opcode_emulation (OP_FDIV
, "__emul_fdiv", "double double double", mono_fdiv
, FALSE
);
11600 mono_register_opcode_emulation (OP_FCONV_TO_U8
, "__emul_fconv_to_u8", "ulong double", mono_fconv_u8
, FALSE
);
11601 mono_register_opcode_emulation (OP_FCONV_TO_U4
, "__emul_fconv_to_u4", "uint32 double", mono_fconv_u4
, FALSE
);
11602 mono_register_opcode_emulation (OP_FCONV_TO_OVF_I8
, "__emul_fconv_to_ovf_i8", "long double", mono_fconv_ovf_i8
, FALSE
);
11603 mono_register_opcode_emulation (OP_FCONV_TO_OVF_U8
, "__emul_fconv_to_ovf_u8", "ulong double", mono_fconv_ovf_u8
, FALSE
);
11605 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
11606 mono_register_opcode_emulation (OP_FCONV_TO_I8
, "__emul_fconv_to_i8", "long double", mono_fconv_i8
, FALSE
);
11608 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
11609 mono_register_opcode_emulation (CEE_CONV_R_UN
, "__emul_conv_r_un", "double int32", mono_conv_to_r8_un
, FALSE
);
11611 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
11612 mono_register_opcode_emulation (OP_LCONV_TO_R8
, "__emul_lconv_to_r8", "double long", mono_lconv_to_r8
, FALSE
);
11614 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
11615 mono_register_opcode_emulation (OP_LCONV_TO_R4
, "__emul_lconv_to_r4", "float long", mono_lconv_to_r4
, FALSE
);
11617 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
11618 mono_register_opcode_emulation (OP_LCONV_TO_R_UN
, "__emul_lconv_to_r8_un", "double long", mono_lconv_to_r8_un
, FALSE
);
11620 #ifdef MONO_ARCH_EMULATE_FREM
11621 mono_register_opcode_emulation (OP_FREM
, "__emul_frem", "double double double", fmod
, FALSE
);
11624 #ifdef MONO_ARCH_SOFT_FLOAT
11625 mono_register_opcode_emulation (OP_FSUB
, "__emul_fsub", "double double double", mono_fsub
, FALSE
);
11626 mono_register_opcode_emulation (OP_FADD
, "__emul_fadd", "double double double", mono_fadd
, FALSE
);
11627 mono_register_opcode_emulation (OP_FMUL
, "__emul_fmul", "double double double", mono_fmul
, FALSE
);
11628 mono_register_opcode_emulation (OP_FNEG
, "__emul_fneg", "double double", mono_fneg
, FALSE
);
11629 mono_register_opcode_emulation (CEE_CONV_R8
, "__emul_conv_r8", "double int32", mono_conv_to_r8
, FALSE
);
11630 mono_register_opcode_emulation (OP_FCONV_TO_R4
, "__emul_fconv_to_r4", "double double", mono_fconv_r4
, FALSE
);
11631 mono_register_opcode_emulation (OP_FCONV_TO_I1
, "__emul_fconv_to_i1", "int8 double", mono_fconv_i1
, FALSE
);
11632 mono_register_opcode_emulation (OP_FCONV_TO_I2
, "__emul_fconv_to_i2", "int16 double", mono_fconv_i2
, FALSE
);
11633 mono_register_opcode_emulation (OP_FCONV_TO_I4
, "__emul_fconv_to_i4", "int32 double", mono_fconv_i4
, FALSE
);
11634 mono_register_opcode_emulation (OP_FCONV_TO_U1
, "__emul_fconv_to_u1", "uint8 double", mono_fconv_u1
, FALSE
);
11635 mono_register_opcode_emulation (OP_FCONV_TO_U2
, "__emul_fconv_to_u2", "uint16 double", mono_fconv_u2
, FALSE
);
11637 mono_register_opcode_emulation (OP_FBEQ
, "__emul_fcmp_eq", "uint32 double double", mono_fcmp_eq
, FALSE
);
11638 mono_register_opcode_emulation (OP_FBLT
, "__emul_fcmp_lt", "uint32 double double", mono_fcmp_lt
, FALSE
);
11639 mono_register_opcode_emulation (OP_FBGT
, "__emul_fcmp_gt", "uint32 double double", mono_fcmp_gt
, FALSE
);
11640 mono_register_opcode_emulation (OP_FBLE
, "__emul_fcmp_le", "uint32 double double", mono_fcmp_le
, FALSE
);
11641 mono_register_opcode_emulation (OP_FBGE
, "__emul_fcmp_ge", "uint32 double double", mono_fcmp_ge
, FALSE
);
11642 mono_register_opcode_emulation (OP_FBNE_UN
, "__emul_fcmp_ne_un", "uint32 double double", mono_fcmp_ne_un
, FALSE
);
11643 mono_register_opcode_emulation (OP_FBLT_UN
, "__emul_fcmp_lt_un", "uint32 double double", mono_fcmp_lt_un
, FALSE
);
11644 mono_register_opcode_emulation (OP_FBGT_UN
, "__emul_fcmp_gt_un", "uint32 double double", mono_fcmp_gt_un
, FALSE
);
11645 mono_register_opcode_emulation (OP_FBLE_UN
, "__emul_fcmp_le_un", "uint32 double double", mono_fcmp_le_un
, FALSE
);
11646 mono_register_opcode_emulation (OP_FBGE_UN
, "__emul_fcmp_ge_un", "uint32 double double", mono_fcmp_ge_un
, FALSE
);
11648 mono_register_opcode_emulation (OP_FCEQ
, "__emul_fcmp_ceq", "uint32 double double", mono_fceq
, FALSE
);
11649 mono_register_opcode_emulation (OP_FCGT
, "__emul_fcmp_cgt", "uint32 double double", mono_fcgt
, FALSE
);
11650 mono_register_opcode_emulation (OP_FCGT_UN
, "__emul_fcmp_cgt_un", "uint32 double double", mono_fcgt_un
, FALSE
);
11651 mono_register_opcode_emulation (OP_FCLT
, "__emul_fcmp_clt", "uint32 double double", mono_fclt
, FALSE
);
11652 mono_register_opcode_emulation (OP_FCLT_UN
, "__emul_fcmp_clt_un", "uint32 double double", mono_fclt_un
, FALSE
);
11654 register_icall (mono_fload_r4
, "mono_fload_r4", "double ptr", FALSE
);
11655 register_icall (mono_fstore_r4
, "mono_fstore_r4", "void double ptr", FALSE
);
11658 #if SIZEOF_VOID_P == 4
11659 mono_register_opcode_emulation (OP_FCONV_TO_U
, "__emul_fconv_to_u", "uint32 double", mono_fconv_u4
, TRUE
);
11662 /* other jit icalls */
11663 register_icall (mono_delegate_ctor
, "mono_delegate_ctor", "void object object ptr", FALSE
);
11664 register_icall (mono_class_static_field_address
, "mono_class_static_field_address",
11665 "ptr ptr ptr", FALSE
);
11666 register_icall (mono_ldtoken_wrapper
, "mono_ldtoken_wrapper", "ptr ptr ptr ptr", FALSE
);
11667 register_icall (mono_get_special_static_data
, "mono_get_special_static_data", "ptr int", FALSE
);
11668 register_icall (mono_ldstr
, "mono_ldstr", "object ptr ptr int32", FALSE
);
11669 register_icall (mono_helper_stelem_ref_check
, "helper_stelem_ref_check", "void object object", FALSE
);
11670 register_icall (mono_object_new
, "mono_object_new", "object ptr ptr", FALSE
);
11671 register_icall (mono_object_new_specific
, "mono_object_new_specific", "object ptr", FALSE
);
11672 register_icall (mono_array_new
, "mono_array_new", "object ptr ptr int32", FALSE
);
11673 register_icall (mono_array_new_specific
, "mono_array_new_specific", "object ptr int32", FALSE
);
11674 register_icall (mono_runtime_class_init
, "mono_runtime_class_init", "void ptr", FALSE
);
11675 register_icall (mono_ldftn
, "mono_ldftn", "ptr ptr", FALSE
);
11676 register_icall (mono_ldftn_nosync
, "mono_ldftn_nosync", "ptr ptr", FALSE
);
11677 register_icall (mono_ldvirtfn
, "mono_ldvirtfn", "ptr object ptr", FALSE
);
11678 register_icall (mono_helper_compile_generic_method
, "compile_generic_method", "ptr object ptr ptr ptr", FALSE
);
11679 register_icall (mono_helper_ldstr
, "helper_ldstr", "object ptr int", FALSE
);
11680 register_icall (mono_helper_ldstr_mscorlib
, "helper_ldstr_mscorlib", "object int", FALSE
);
11681 register_icall (mono_helper_newobj_mscorlib
, "helper_newobj_mscorlib", "object int", FALSE
);
11682 register_icall (mono_value_copy
, "mono_value_copy", "void ptr ptr ptr", FALSE
);
11685 #define JIT_RUNTIME_WORKS
11686 #ifdef JIT_RUNTIME_WORKS
11687 mono_install_runtime_cleanup ((MonoDomainFunc
)mini_cleanup
);
11688 mono_runtime_init (domain
, mono_thread_start_cb
, mono_thread_attach_cb
);
11691 mono_thread_attach (domain
);
11695 MonoJitStats mono_jit_stats
= {0};
11698 print_jit_stats (void)
11700 if (mono_jit_stats
.enabled
) {
11701 g_print ("Mono Jit statistics\n");
11702 g_print ("Compiled methods: %ld\n", mono_jit_stats
.methods_compiled
);
11703 g_print ("Methods from AOT: %ld\n", mono_jit_stats
.methods_aot
);
11704 g_print ("Methods cache lookup: %ld\n", mono_jit_stats
.methods_lookups
);
11705 g_print ("Method trampolines: %ld\n", mono_jit_stats
.method_trampolines
);
11706 g_print ("Basic blocks: %ld\n", mono_jit_stats
.basic_blocks
);
11707 g_print ("Max basic blocks: %ld\n", mono_jit_stats
.max_basic_blocks
);
11708 g_print ("Allocated vars: %ld\n", mono_jit_stats
.allocate_var
);
11709 g_print ("Analyze stack repeat: %ld\n", mono_jit_stats
.analyze_stack_repeat
);
11710 g_print ("Compiled CIL code size: %ld\n", mono_jit_stats
.cil_code_size
);
11711 g_print ("Native code size: %ld\n", mono_jit_stats
.native_code_size
);
11712 g_print ("Max code size ratio: %.2f (%s::%s)\n", mono_jit_stats
.max_code_size_ratio
/100.0,
11713 mono_jit_stats
.max_ratio_method
->klass
->name
, mono_jit_stats
.max_ratio_method
->name
);
11714 g_print ("Biggest method: %ld (%s::%s)\n", mono_jit_stats
.biggest_method_size
,
11715 mono_jit_stats
.biggest_method
->klass
->name
, mono_jit_stats
.biggest_method
->name
);
11716 g_print ("Code reallocs: %ld\n", mono_jit_stats
.code_reallocs
);
11717 g_print ("Allocated code size: %ld\n", mono_jit_stats
.allocated_code_size
);
11718 g_print ("Inlineable methods: %ld\n", mono_jit_stats
.inlineable_methods
);
11719 g_print ("Inlined methods: %ld\n", mono_jit_stats
.inlined_methods
);
11721 g_print ("\nCreated object count: %ld\n", mono_stats
.new_object_count
);
11722 g_print ("Initialized classes: %ld\n", mono_stats
.initialized_class_count
);
11723 g_print ("Used classes: %ld\n", mono_stats
.used_class_count
);
11724 g_print ("Generic vtables: %ld\n", mono_stats
.generic_vtable_count
);
11725 g_print ("Methods: %ld\n", mono_stats
.method_count
);
11726 g_print ("Static data size: %ld\n", mono_stats
.class_static_data_size
);
11727 g_print ("VTable data size: %ld\n", mono_stats
.class_vtable_size
);
11728 g_print ("Mscorlib mempool size: %d\n", mono_mempool_get_allocated (mono_defaults
.corlib
->mempool
));
11730 g_print ("\nGeneric instances: %ld\n", mono_stats
.generic_instance_count
);
11731 g_print ("Initialized classes: %ld\n", mono_stats
.generic_class_count
);
11732 g_print ("Inflated methods: %ld / %ld\n", mono_stats
.inflated_method_count_2
,
11733 mono_stats
.inflated_method_count
);
11734 g_print ("Inflated types: %ld\n", mono_stats
.inflated_type_count
);
11735 g_print ("Generics metadata size: %ld\n", mono_stats
.generics_metadata_size
);
11737 if (mono_use_security_manager
) {
11738 g_print ("\nDecl security check : %ld\n", mono_jit_stats
.cas_declsec_check
);
11739 g_print ("LinkDemand (user) : %ld\n", mono_jit_stats
.cas_linkdemand
);
11740 g_print ("LinkDemand (icall) : %ld\n", mono_jit_stats
.cas_linkdemand_icall
);
11741 g_print ("LinkDemand (pinvoke) : %ld\n", mono_jit_stats
.cas_linkdemand_pinvoke
);
11742 g_print ("LinkDemand (aptc) : %ld\n", mono_jit_stats
.cas_linkdemand_aptc
);
11743 g_print ("Demand (code gen) : %ld\n", mono_jit_stats
.cas_demand_generation
);
11745 if (debug_options
.collect_pagefault_stats
) {
11746 g_print ("Metadata pagefaults : %d\n", mono_raw_buffer_get_n_pagefaults ());
11747 g_print ("AOT pagefaults : %d\n", mono_aot_get_n_pagefaults ());
11753 mini_cleanup (MonoDomain
*domain
)
11755 #ifdef HAVE_LINUX_RTC_H
11757 enable_rtc_timer (FALSE
);
11761 * mono_runtime_cleanup() and mono_domain_finalize () need to
11762 * be called early since they need the execution engine still
11763 * fully working (mono_domain_finalize may invoke managed finalizers
11764 * and mono_runtime_cleanup will wait for other threads to finish).
11766 mono_domain_finalize (domain
, 2000);
11768 /* This accesses metadata so needs to be called before runtime shutdown */
11769 print_jit_stats ();
11771 mono_runtime_cleanup (domain
);
11773 mono_profiler_shutdown ();
11775 mono_debug_cleanup ();
11777 mono_icall_cleanup ();
11779 mono_runtime_cleanup_handlers ();
11781 mono_domain_free (domain
, TRUE
);
11783 mono_code_manager_destroy (global_codeman
);
11784 g_hash_table_destroy (jit_icall_name_hash
);
11785 if (class_init_hash_addr
)
11786 g_hash_table_destroy (class_init_hash_addr
);
11787 g_free (emul_opcode_map
);
11791 mono_trace_cleanup ();
11793 mono_counters_dump (-1, stdout
);
11795 TlsFree(mono_jit_tls_id
);
11797 DeleteCriticalSection (&jit_mutex
);
11799 DeleteCriticalSection (&mono_delegate_section
);
11803 mono_set_defaults (int verbose_level
, guint32 opts
)
11805 mini_verbose
= verbose_level
;
11806 default_opt
= opts
;
11807 default_opt_set
= TRUE
;
11811 mono_precompile_assembly (MonoAssembly
*ass
, void *user_data
)
11813 GHashTable
*assemblies
= (GHashTable
*)user_data
;
11814 MonoImage
*image
= mono_assembly_get_image (ass
);
11815 MonoMethod
*method
, *invoke
;
11818 if (g_hash_table_lookup (assemblies
, ass
))
11821 g_hash_table_insert (assemblies
, ass
, ass
);
11823 if (mini_verbose
> 0)
11824 printf ("PRECOMPILE: %s.\n", mono_image_get_filename (image
));
11826 for (i
= 0; i
< mono_image_get_table_rows (image
, MONO_TABLE_METHOD
); ++i
) {
11827 method
= mono_get_method (image
, MONO_TOKEN_METHOD_DEF
| (i
+ 1), NULL
);
11828 if (method
->flags
& METHOD_ATTRIBUTE_ABSTRACT
)
11832 if (mini_verbose
> 1) {
11833 char * desc
= mono_method_full_name (method
, TRUE
);
11834 g_print ("Compiling %d %s\n", count
, desc
);
11837 mono_compile_method (method
);
11838 if (strcmp (method
->name
, "Finalize") == 0) {
11839 invoke
= mono_marshal_get_runtime_invoke (method
);
11840 mono_compile_method (invoke
);
11842 if (method
->klass
->marshalbyref
&& mono_method_signature (method
)->hasthis
) {
11843 invoke
= mono_marshal_get_remoting_invoke_with_check (method
);
11844 mono_compile_method (invoke
);
11848 /* Load and precompile referenced assemblies as well */
11849 for (i
= 0; i
< mono_image_get_table_rows (image
, MONO_TABLE_ASSEMBLYREF
); ++i
) {
11850 mono_assembly_load_reference (image
, i
);
11851 if (image
->references
[i
])
11852 mono_precompile_assembly (image
->references
[i
], assemblies
);
11856 void mono_precompile_assemblies ()
11858 GHashTable
*assemblies
= g_hash_table_new (NULL
, NULL
);
11860 mono_assembly_foreach ((GFunc
)mono_precompile_assembly
, assemblies
);
11862 g_hash_table_destroy (assemblies
);