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 sun // Solaris x86
18 #include <sys/types.h>
19 #include <sys/ucontext.h>
22 #ifdef HAVE_VALGRIND_MEMCHECK_H
23 #include <valgrind/memcheck.h>
26 #include <mono/metadata/assembly.h>
27 #include <mono/metadata/loader.h>
28 #include <mono/metadata/cil-coff.h>
29 #include <mono/metadata/tabledefs.h>
30 #include <mono/metadata/class.h>
31 #include <mono/metadata/object.h>
32 #include <mono/metadata/exception.h>
33 #include <mono/metadata/opcodes.h>
34 #include <mono/metadata/mono-endian.h>
35 #include <mono/metadata/tokentype.h>
36 #include <mono/metadata/tabledefs.h>
37 #include <mono/metadata/threads.h>
38 #include <mono/metadata/marshal.h>
39 #include <mono/metadata/socket-io.h>
40 #include <mono/metadata/appdomain.h>
41 #include <mono/metadata/debug-helpers.h>
42 #include <mono/io-layer/io-layer.h>
43 #include "mono/metadata/profiler.h"
44 #include <mono/metadata/profiler-private.h>
45 #include <mono/metadata/mono-config.h>
46 #include <mono/metadata/environment.h>
47 #include <mono/metadata/mono-debug.h>
48 #include <mono/metadata/mono-debug-debugger.h>
49 #include <mono/metadata/monitor.h>
50 #include <mono/utils/mono-math.h>
51 #include <mono/os/gc_wrapper.h>
59 #include "jit-icalls.c"
62 * this is used to determine when some branch optimizations are possible: we exclude FP compares
63 * because they have weird semantics with NaNs.
65 #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))
66 #define MONO_IS_COND_BRANCH_NOFP(ins) (MONO_IS_COND_BRANCH_OP(ins) && (ins)->inst_left->inst_left->type != STACK_R8)
68 #define MONO_CHECK_THIS(ins) (cfg->method->signature->hasthis && (ins)->ssa_op == MONO_SSA_LOAD && (ins)->inst_left->inst_c0 == 0)
70 static void setup_stat_profiler (void);
71 gboolean mono_arch_print_tree(MonoInst *tree, int arity);
72 static gpointer mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt);
73 static gpointer mono_jit_compile_method (MonoMethod *method);
74 static gpointer mono_jit_find_compiled_method (MonoDomain *domain, MonoMethod *method);
76 static void handle_stobj (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *dest, MonoInst *src,
77 const unsigned char *ip, MonoClass *klass, gboolean to_end, gboolean native);
79 static void dec_foreach (MonoInst *tree, MonoCompile *cfg);
81 static int mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock,
82 int locals_offset, MonoInst *return_var, GList *dont_inline, MonoInst **inline_args,
83 guint inline_offset, gboolean is_virtual_call);
85 extern guint8 mono_burg_arity [];
86 /* helper methods signature */
87 static MonoMethodSignature *helper_sig_long_long_long = NULL;
88 static MonoMethodSignature *helper_sig_long_long_int = NULL;
89 static MonoMethodSignature *helper_sig_newarr = NULL;
90 static MonoMethodSignature *helper_sig_newarr_specific = NULL;
91 static MonoMethodSignature *helper_sig_ldstr = NULL;
92 static MonoMethodSignature *helper_sig_domain_get = NULL;
93 static MonoMethodSignature *helper_sig_object_new = NULL;
94 static MonoMethodSignature *helper_sig_object_new_specific = NULL;
95 static MonoMethodSignature *helper_sig_compile = NULL;
96 static MonoMethodSignature *helper_sig_compile_virt = NULL;
97 static MonoMethodSignature *helper_sig_obj_ptr = NULL;
98 static MonoMethodSignature *helper_sig_obj_ptr_ptr = NULL;
99 static MonoMethodSignature *helper_sig_obj_obj_ptr_ptr = NULL;
100 static MonoMethodSignature *helper_sig_obj_void = NULL;
101 static MonoMethodSignature *helper_sig_ptr_void = NULL;
102 static MonoMethodSignature *helper_sig_void_void = NULL;
103 static MonoMethodSignature *helper_sig_void_ptr = NULL;
104 static MonoMethodSignature *helper_sig_void_obj = NULL;
105 static MonoMethodSignature *helper_sig_void_obj_ptr_int = NULL;
106 static MonoMethodSignature *helper_sig_void_obj_ptr_ptr_obj = NULL;
107 static MonoMethodSignature *helper_sig_void_ptr_ptr = NULL;
108 static MonoMethodSignature *helper_sig_void_ptr_ptr_ptr = NULL;
109 static MonoMethodSignature *helper_sig_ptr_ptr_ptr = NULL;
110 static MonoMethodSignature *helper_sig_ptr_ptr_ptr_ptr = NULL;
111 static MonoMethodSignature *helper_sig_ptr_obj = NULL;
112 static MonoMethodSignature *helper_sig_ptr_obj_int = NULL;
113 static MonoMethodSignature *helper_sig_ptr_int = NULL;
114 static MonoMethodSignature *helper_sig_initobj = NULL;
115 static MonoMethodSignature *helper_sig_memcpy = NULL;
116 static MonoMethodSignature *helper_sig_memset = NULL;
117 static MonoMethodSignature *helper_sig_ulong_double = NULL;
118 static MonoMethodSignature *helper_sig_long_double = NULL;
119 static MonoMethodSignature *helper_sig_double_long = NULL;
120 static MonoMethodSignature *helper_sig_double_int = NULL;
121 static MonoMethodSignature *helper_sig_float_long = NULL;
122 static MonoMethodSignature *helper_sig_double_double_double = NULL;
123 static MonoMethodSignature *helper_sig_uint_double = NULL;
124 static MonoMethodSignature *helper_sig_int_double = NULL;
125 static MonoMethodSignature *helper_sig_stelem_ref = NULL;
126 static MonoMethodSignature *helper_sig_stelem_ref_check = NULL;
127 static MonoMethodSignature *helper_sig_class_init_trampoline = NULL;
128 static MonoMethodSignature *helper_sig_compile_generic_method = NULL;
130 static guint32 default_opt = MONO_OPT_PEEPHOLE;
132 guint32 mono_jit_tls_id = -1;
133 MonoTraceSpec *mono_jit_trace_calls = NULL;
134 gboolean mono_break_on_exc = FALSE;
136 gboolean mono_compile_aot = FALSE;
139 static int mini_verbose = 0;
141 static CRITICAL_SECTION jit_mutex;
143 static GHashTable *class_init_hash_addr = NULL;
146 mono_running_on_valgrind (void)
148 #ifdef HAVE_VALGRIND_MEMCHECK_H
149 if (RUNNING_ON_VALGRIND)
159 G_GNUC_UNUSED static char*
160 get_method_from_ip (void *ip)
166 MonoDomain *domain = mono_domain_get ();
168 ji = mono_jit_info_table_find (domain, ip);
172 method = mono_method_full_name (ji->method, TRUE);
173 source = mono_debug_source_location_from_address (ji->method, (int) ip, NULL, domain);
175 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);
184 G_GNUC_UNUSED static void
185 print_method_from_ip (void *ip)
190 MonoDomain *domain = mono_domain_get ();
192 ji = mono_jit_info_table_find (domain, ip);
194 g_print ("No method at %p\n", ip);
197 method = mono_method_full_name (ji->method, TRUE);
198 source = mono_debug_source_location_from_address (ji->method, (int) ip, NULL, domain);
200 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);
203 g_print ("%s\n", source);
210 mono_print_method_from_ip (void *ip)
212 print_method_from_ip (ip);
216 * mono_method_same_domain:
218 * Determine whenever two compiled methods are in the same domain, thus
219 * the address of the callee can be embedded in the caller.
221 gboolean mono_method_same_domain (MonoJitInfo *caller, MonoJitInfo *callee)
223 if (!caller || !callee)
227 * If the call was made from domain-neutral to domain-specific
228 * code, we can't patch the call site.
230 if (caller->domain_neutral && !callee->domain_neutral)
233 if ((caller->method->klass == mono_defaults.appdomain_class) &&
234 (strstr (caller->method->name, "InvokeInDomain"))) {
235 /* The InvokeInDomain methods change the current appdomain */
243 mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
245 MonoJumpInfoToken *res = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoToken));
252 #define MONO_INIT_VARINFO(vi,id) do { \
253 (vi)->range.first_use.pos.bid = 0xffff; \
259 * Basic blocks have two numeric identifiers:
260 * dfn: Depth First Number
261 * block_num: unique ID assigned at bblock creation
263 #define NEW_BBLOCK(cfg) (mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock)))
264 #define ADD_BBLOCK(cfg,bbhash,b) do { \
265 g_hash_table_insert (bbhash, (b)->cil_code, (b)); \
266 (b)->block_num = cfg->num_bblocks++; \
267 (b)->real_offset = real_offset; \
270 #define GET_BBLOCK(cfg,bbhash,tblock,ip) do { \
271 (tblock) = g_hash_table_lookup (bbhash, (ip)); \
273 if ((ip) >= end || (ip) < header->code) goto unverified; \
274 (tblock) = NEW_BBLOCK (cfg); \
275 (tblock)->cil_code = (ip); \
276 ADD_BBLOCK (cfg, (bbhash), (tblock)); \
280 #define CHECK_BBLOCK(target,ip,tblock) do { \
281 if ((target) < (ip) && !(tblock)->code) { \
282 bb_recheck = g_list_prepend (bb_recheck, (tblock)); \
283 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)); \
287 #define NEW_ICONST(cfg,dest,val) do { \
288 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
289 (dest)->opcode = OP_ICONST; \
290 (dest)->inst_c0 = (val); \
291 (dest)->type = STACK_I4; \
294 #if SIZEOF_VOID_P == 8
295 #define OP_PCONST OP_I8CONST
297 #define OP_PCONST OP_ICONST
300 #define NEW_PCONST(cfg,dest,val) do { \
301 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
302 (dest)->opcode = OP_PCONST; \
303 (dest)->inst_p0 = (val); \
304 (dest)->type = STACK_PTR; \
308 #ifdef MONO_ARCH_NEED_GOT_VAR
310 #define NEW_PATCH_INFO(cfg,dest,el1,el2) do { \
311 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
312 (dest)->opcode = OP_PATCH_INFO; \
313 (dest)->inst_left = (gpointer)(el1); \
314 (dest)->inst_right = (gpointer)(el2); \
317 #define NEW_AOTCONST(cfg,dest,patch_type,cons) do { \
318 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
319 (dest)->opcode = cfg->compile_aot ? OP_GOT_ENTRY : OP_PCONST; \
320 if (cfg->compile_aot) { \
321 MonoInst *group, *got_var; \
322 NEW_TEMPLOAD ((cfg), got_var, mono_get_got_var (cfg)->inst_c0); \
323 NEW_PATCH_INFO ((cfg), group, cons, patch_type); \
324 (dest)->inst_p0 = got_var; \
325 (dest)->inst_p1 = group; \
327 (dest)->inst_p0 = (cons); \
328 (dest)->inst_i1 = (gpointer)(patch_type); \
330 (dest)->type = STACK_PTR; \
333 #define NEW_AOTCONST_TOKEN(cfg,dest,patch_type,image,token,stack_type) do { \
334 MonoInst *group, *got_var; \
335 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
336 (dest)->opcode = OP_GOT_ENTRY; \
337 NEW_TEMPLOAD ((cfg), got_var, mono_get_got_var (cfg)->inst_c0); \
338 NEW_PATCH_INFO ((cfg), group, NULL, patch_type); \
339 group->inst_p0 = mono_jump_info_token_new ((cfg)->mempool, (image), (token)); \
340 (dest)->inst_p0 = got_var; \
341 (dest)->inst_p1 = group; \
342 (dest)->type = (stack_type); \
347 #define NEW_AOTCONST(cfg,dest,patch_type,cons) do { \
348 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
349 (dest)->opcode = cfg->compile_aot ? OP_AOTCONST : OP_PCONST; \
350 (dest)->inst_p0 = (cons); \
351 (dest)->inst_i1 = (gpointer)(patch_type); \
352 (dest)->type = STACK_PTR; \
355 #define NEW_AOTCONST_TOKEN(cfg,dest,patch_type,image,token,stack_type) do { \
356 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
357 (dest)->opcode = OP_AOTCONST; \
358 (dest)->inst_p0 = mono_jump_info_token_new ((cfg)->mempool, (image), (token)); \
359 (dest)->inst_p1 = (gpointer)(patch_type); \
360 (dest)->type = (stack_type); \
365 #define NEW_CLASSCONST(cfg,dest,val) NEW_AOTCONST ((cfg), (dest), MONO_PATCH_INFO_CLASS, (val))
367 #define NEW_IMAGECONST(cfg,dest,val) NEW_AOTCONST ((cfg), (dest), MONO_PATCH_INFO_IMAGE, (val))
369 #define NEW_FIELDCONST(cfg,dest,val) NEW_AOTCONST ((cfg), (dest), MONO_PATCH_INFO_FIELD, (val))
371 #define NEW_METHODCONST(cfg,dest,val) NEW_AOTCONST ((cfg), (dest), MONO_PATCH_INFO_METHODCONST, (val))
373 #define NEW_VTABLECONST(cfg,dest,vtable) NEW_AOTCONST ((cfg), (dest), MONO_PATCH_INFO_VTABLE, cfg->compile_aot ? (gpointer)((vtable)->klass) : (vtable))
375 #define NEW_SFLDACONST(cfg,dest,val) NEW_AOTCONST ((cfg), (dest), MONO_PATCH_INFO_SFLDA, (val))
377 #define NEW_LDSTRCONST(cfg,dest,image,token) NEW_AOTCONST_TOKEN ((cfg), (dest), MONO_PATCH_INFO_LDSTR, (image), (token), STACK_OBJ)
379 #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)
381 #define NEW_LDTOKENCONST(cfg,dest,image,token) NEW_AOTCONST_TOKEN ((cfg), (dest), MONO_PATCH_INFO_LDTOKEN, (image), (token), STACK_PTR)
383 #define NEW_DOMAINCONST(cfg,dest) do { \
384 if (cfg->opt & MONO_OPT_SHARED) { \
385 NEW_TEMPLOAD (cfg, dest, mono_get_domainvar (cfg)->inst_c0); \
387 NEW_PCONST (cfg, dest, (cfg)->domain); \
391 #define GET_VARINFO_INST(cfg,num) ((cfg)->varinfo [(num)]->inst)
393 #define NEW_ARGLOAD(cfg,dest,num) do { \
394 if (arg_array [(num)]->opcode == OP_ICONST) (dest) = arg_array [(num)]; else { \
395 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
396 (dest)->ssa_op = MONO_SSA_LOAD; \
397 (dest)->inst_i0 = arg_array [(num)]; \
398 (dest)->opcode = mono_type_to_ldind ((dest)->inst_i0->inst_vtype); \
399 type_to_eval_stack_type (param_types [(num)], (dest)); \
400 (dest)->klass = (dest)->inst_i0->klass; \
403 #define NEW_LOCLOAD(cfg,dest,num) do { \
404 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
405 (dest)->ssa_op = MONO_SSA_LOAD; \
406 (dest)->inst_i0 = (cfg)->varinfo [locals_offset + (num)]; \
407 (dest)->opcode = mono_type_to_ldind ((dest)->inst_i0->inst_vtype); \
408 type_to_eval_stack_type (header->locals [(num)], (dest)); \
409 (dest)->klass = (dest)->inst_i0->klass; \
412 #define NEW_LOCLOADA(cfg,dest,num) do { \
413 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
414 (dest)->ssa_op = MONO_SSA_MAYBE_LOAD; \
415 (dest)->inst_i0 = (cfg)->varinfo [locals_offset + (num)]; \
416 (dest)->inst_i0->flags |= MONO_INST_INDIRECT; \
417 (dest)->opcode = OP_LDADDR; \
418 (dest)->type = STACK_MP; \
419 (dest)->klass = (dest)->inst_i0->klass; \
420 if (!MONO_TYPE_ISSTRUCT (header->locals [(num)])) \
421 (cfg)->disable_ssa = TRUE; \
424 #define NEW_RETLOADA(cfg,dest) do { \
425 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
426 (dest)->ssa_op = MONO_SSA_MAYBE_LOAD; \
427 (dest)->inst_i0 = (cfg)->ret; \
428 (dest)->inst_i0->flags |= MONO_INST_INDIRECT; \
429 (dest)->opcode = CEE_LDIND_I; \
430 (dest)->type = STACK_MP; \
431 (dest)->klass = (dest)->inst_i0->klass; \
432 (cfg)->disable_ssa = TRUE; \
435 #define NEW_ARGLOADA(cfg,dest,num) do { \
436 if (arg_array [(num)]->opcode == OP_ICONST) goto inline_failure; \
437 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
438 (dest)->ssa_op = MONO_SSA_MAYBE_LOAD; \
439 (dest)->inst_i0 = arg_array [(num)]; \
440 (dest)->inst_i0->flags |= MONO_INST_INDIRECT; \
441 (dest)->opcode = OP_LDADDR; \
442 (dest)->type = STACK_MP; \
443 (dest)->klass = (dest)->inst_i0->klass; \
444 (cfg)->disable_ssa = TRUE; \
447 #define NEW_TEMPLOAD(cfg,dest,num) do { \
448 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
449 (dest)->ssa_op = MONO_SSA_LOAD; \
450 (dest)->inst_i0 = (cfg)->varinfo [(num)]; \
451 (dest)->opcode = mono_type_to_ldind ((dest)->inst_i0->inst_vtype); \
452 type_to_eval_stack_type ((dest)->inst_i0->inst_vtype, (dest)); \
453 (dest)->klass = (dest)->inst_i0->klass; \
456 #define NEW_TEMPLOADA(cfg,dest,num) do { \
457 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
458 (dest)->ssa_op = MONO_SSA_MAYBE_LOAD; \
459 (dest)->inst_i0 = (cfg)->varinfo [(num)]; \
460 (dest)->inst_i0->flags |= MONO_INST_INDIRECT; \
461 (dest)->opcode = OP_LDADDR; \
462 (dest)->type = STACK_MP; \
463 (dest)->klass = (dest)->inst_i0->klass; \
464 if (!MONO_TYPE_ISSTRUCT (cfg->varinfo [(num)]->inst_vtype)) \
465 (cfg)->disable_ssa = TRUE; \
469 #define NEW_INDLOAD(cfg,dest,addr,vtype) do { \
470 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
471 (dest)->inst_left = addr; \
472 (dest)->opcode = mono_type_to_ldind (vtype); \
473 type_to_eval_stack_type (vtype, (dest)); \
474 /* FIXME: (dest)->klass = (dest)->inst_i0->klass;*/ \
477 #define NEW_INDSTORE(cfg,dest,addr,value,vtype) do { \
478 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
479 (dest)->inst_i0 = addr; \
480 (dest)->opcode = mono_type_to_stind (vtype); \
481 (dest)->inst_i1 = (value); \
482 /* FIXME: (dest)->klass = (dest)->inst_i0->klass;*/ \
485 #define NEW_TEMPSTORE(cfg,dest,num,inst) do { \
486 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
487 (dest)->ssa_op = MONO_SSA_STORE; \
488 (dest)->inst_i0 = (cfg)->varinfo [(num)]; \
489 (dest)->opcode = mono_type_to_stind ((dest)->inst_i0->inst_vtype); \
490 (dest)->inst_i1 = (inst); \
491 (dest)->klass = (dest)->inst_i0->klass; \
494 #define NEW_LOCSTORE(cfg,dest,num,inst) do { \
495 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
496 (dest)->opcode = mono_type_to_stind (header->locals [(num)]); \
497 (dest)->ssa_op = MONO_SSA_STORE; \
498 (dest)->inst_i0 = (cfg)->varinfo [locals_offset + (num)]; \
499 (dest)->inst_i1 = (inst); \
500 (dest)->klass = (dest)->inst_i0->klass; \
503 #define NEW_ARGSTORE(cfg,dest,num,inst) do { \
504 if (arg_array [(num)]->opcode == OP_ICONST) goto inline_failure; \
505 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
506 (dest)->opcode = mono_type_to_stind (param_types [(num)]); \
507 (dest)->ssa_op = MONO_SSA_STORE; \
508 (dest)->inst_i0 = arg_array [(num)]; \
509 (dest)->inst_i1 = (inst); \
510 (dest)->klass = (dest)->inst_i0->klass; \
513 #define NEW_DUMMY_USE(cfg,dest,load) do { \
514 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
515 (dest)->opcode = OP_DUMMY_USE; \
516 (dest)->inst_left = (load); \
519 #define ADD_BINOP(op) do { \
520 MONO_INST_NEW (cfg, ins, (op)); \
521 ins->cil_code = ip; \
523 ins->inst_i0 = sp [0]; \
524 ins->inst_i1 = sp [1]; \
526 type_from_op (ins); \
530 #define ADD_UNOP(op) do { \
531 MONO_INST_NEW (cfg, ins, (op)); \
532 ins->cil_code = ip; \
534 ins->inst_i0 = sp [0]; \
536 type_from_op (ins); \
540 #define ADD_BINCOND(next_block) do { \
543 MONO_INST_NEW(cfg, cmp, OP_COMPARE); \
544 cmp->inst_i0 = sp [0]; \
545 cmp->inst_i1 = sp [1]; \
546 cmp->cil_code = ins->cil_code; \
547 type_from_op (cmp); \
549 ins->inst_i0 = cmp; \
550 MONO_ADD_INS (bblock, ins); \
551 ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2); \
552 GET_BBLOCK (cfg, bbhash, tblock, target); \
553 link_bblock (cfg, bblock, tblock); \
554 ins->inst_true_bb = tblock; \
555 CHECK_BBLOCK (target, ip, tblock); \
556 if ((next_block)) { \
557 link_bblock (cfg, bblock, (next_block)); \
558 ins->inst_false_bb = (next_block); \
559 start_new_bblock = 1; \
561 GET_BBLOCK (cfg, bbhash, tblock, ip); \
562 link_bblock (cfg, bblock, tblock); \
563 ins->inst_false_bb = tblock; \
564 start_new_bblock = 2; \
568 /* FIXME: handle float, long ... */
569 #define ADD_UNCOND(istrue) do { \
572 MONO_INST_NEW(cfg, cmp, OP_COMPARE); \
573 cmp->inst_i0 = sp [0]; \
574 switch (cmp->inst_i0->type) { \
576 cmp->inst_i1 = zero_int64; break; \
578 cmp->inst_i1 = zero_r8; break; \
581 cmp->inst_i1 = zero_ptr; break; \
583 cmp->inst_i1 = zero_obj; break; \
585 cmp->inst_i1 = zero_int32; \
587 cmp->cil_code = ins->cil_code; \
588 type_from_op (cmp); \
590 ins->inst_i0 = cmp; \
591 ins->opcode = (istrue)? CEE_BNE_UN: CEE_BEQ; \
592 MONO_ADD_INS (bblock, ins); \
593 ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2); \
594 GET_BBLOCK (cfg, bbhash, tblock, target); \
595 link_bblock (cfg, bblock, tblock); \
596 ins->inst_true_bb = tblock; \
597 CHECK_BBLOCK (target, ip, tblock); \
598 GET_BBLOCK (cfg, bbhash, tblock, ip); \
599 link_bblock (cfg, bblock, tblock); \
600 ins->inst_false_bb = tblock; \
601 start_new_bblock = 2; \
604 #define NEW_LDELEMA(cfg,dest,sp,k) do { \
605 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
606 (dest)->opcode = CEE_LDELEMA; \
607 (dest)->inst_left = (sp) [0]; \
608 (dest)->inst_right = (sp) [1]; \
609 (dest)->type = STACK_MP; \
610 (dest)->klass = (k); \
611 (cfg)->flags |= MONO_CFG_HAS_LDELEMA; \
614 #define NEW_GROUP(cfg,dest,el1,el2) do { \
615 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
616 (dest)->opcode = OP_GROUP; \
617 (dest)->inst_left = (el1); \
618 (dest)->inst_right = (el2); \
623 compare_bblock (gconstpointer a, gconstpointer b)
625 const MonoBasicBlock *b1 = a;
626 const MonoBasicBlock *b2 = b;
628 return b2->cil_code - b1->cil_code;
633 * link_bblock: Links two basic blocks
635 * links two basic blocks in the control flow graph, the 'from'
636 * argument is the starting block and the 'to' argument is the block
637 * the control flow ends to after 'from'.
640 link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
642 MonoBasicBlock **newa;
646 if (from->cil_code) {
648 g_print ("edge from IL%04x to IL_%04x\n", from->cil_code - cfg->cil_code, to->cil_code - cfg->cil_code);
650 g_print ("edge from IL%04x to exit\n", from->cil_code - cfg->cil_code);
653 g_print ("edge from entry to IL_%04x\n", to->cil_code - cfg->cil_code);
655 g_print ("edge from entry to exit\n");
659 for (i = 0; i < from->out_count; ++i) {
660 if (to == from->out_bb [i]) {
666 newa = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (from->out_count + 1));
667 for (i = 0; i < from->out_count; ++i) {
668 newa [i] = from->out_bb [i];
676 for (i = 0; i < to->in_count; ++i) {
677 if (from == to->in_bb [i]) {
683 newa = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (to->in_count + 1));
684 for (i = 0; i < to->in_count; ++i) {
685 newa [i] = to->in_bb [i];
694 * mono_find_block_region:
696 * We mark each basic block with a region ID. We use that to avoid BB
697 * optimizations when blocks are in different regions.
700 * A region token that encodes where this region is, and information
701 * about the clause owner for this block.
703 * The region encodes the try/catch/filter clause that owns this block
704 * as well as the type. -1 is a special value that represents a block
705 * that is in none of try/catch/filter.
708 mono_find_block_region (MonoCompile *cfg, int offset, int *filter_lengths)
710 MonoMethod *method = cfg->method;
711 MonoMethodHeader *header = mono_method_get_header (method);
712 MonoExceptionClause *clause;
715 /* first search for handlers and filters */
716 for (i = 0; i < header->num_clauses; ++i) {
717 clause = &header->clauses [i];
718 if ((clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) && (offset >= clause->data.filter_offset) &&
719 (offset < (clause->data.filter_offset + filter_lengths [i])))
720 return ((i + 1) << 8) | MONO_REGION_FILTER | clause->flags;
722 if (MONO_OFFSET_IN_HANDLER (clause, offset)) {
723 if (clause->flags & MONO_EXCEPTION_CLAUSE_FINALLY)
724 return ((i + 1) << 8) | MONO_REGION_FINALLY | clause->flags;
726 return ((i + 1) << 8) | MONO_REGION_CATCH | clause->flags;
730 /* search the try blocks */
731 for (i = 0; i < header->num_clauses; ++i) {
732 clause = &header->clauses [i];
733 if (MONO_OFFSET_IN_CLAUSE (clause, offset))
734 return ((i + 1) << 8) | clause->flags;
741 mono_find_final_block (MonoCompile *cfg, unsigned char *ip, unsigned char *target, int type)
743 MonoMethod *method = cfg->method;
744 MonoMethodHeader *header = mono_method_get_header (method);
745 MonoExceptionClause *clause;
746 MonoBasicBlock *handler;
750 for (i = 0; i < header->num_clauses; ++i) {
751 clause = &header->clauses [i];
752 if (MONO_OFFSET_IN_CLAUSE (clause, (ip - header->code)) &&
753 (!MONO_OFFSET_IN_CLAUSE (clause, (target - header->code)))) {
754 if (clause->flags == type) {
755 handler = g_hash_table_lookup (cfg->bb_hash, header->code + clause->handler_offset);
757 res = g_list_append (res, handler);
765 mono_find_spvar_for_region (MonoCompile *cfg, int region)
767 return g_hash_table_lookup (cfg->spvars, GINT_TO_POINTER (region));
771 mono_create_spvar_for_region (MonoCompile *cfg, int region)
775 var = g_hash_table_lookup (cfg->spvars, GINT_TO_POINTER (region));
779 var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
780 /* prevent it from being register allocated */
781 var->flags |= MONO_INST_INDIRECT;
783 g_hash_table_insert (cfg->spvars, GINT_TO_POINTER (region), var);
787 df_visit (MonoBasicBlock *start, int *dfn, MonoBasicBlock **array)
791 array [*dfn] = start;
792 /*g_print ("visit %d at %p\n", *dfn, start->cil_code);*/
793 for (i = 0; i < start->out_count; ++i) {
794 if (start->out_bb [i]->dfn)
797 start->out_bb [i]->dfn = *dfn;
798 start->out_bb [i]->df_parent = start;
799 array [*dfn] = start->out_bb [i];
800 df_visit (start->out_bb [i], dfn, array);
806 MonoBasicBlock *best;
810 previous_foreach (gconstpointer key, gpointer val, gpointer data)
812 PrevStruct *p = data;
813 MonoBasicBlock *bb = val;
814 //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,
815 //bb->method == p->best->method, bb->cil_code < p->code, bb->cil_code > p->best->cil_code);
817 if (bb->cil_code && bb->cil_code < p->code && bb->cil_code > p->best->cil_code)
821 static MonoBasicBlock*
822 find_previous (GHashTable *bb_hash, MonoBasicBlock *start, const guchar *code) {
828 g_hash_table_foreach (bb_hash, (GHFunc)previous_foreach, &p);
833 split_bblock (MonoCompile *cfg, MonoBasicBlock *first, MonoBasicBlock *second) {
842 * FIXME: take into account all the details:
843 * second may have been the target of more than one bblock
845 second->out_count = first->out_count;
846 second->out_bb = first->out_bb;
848 for (i = 0; i < first->out_count; ++i) {
849 bb = first->out_bb [i];
850 for (j = 0; j < bb->in_count; ++j) {
851 if (bb->in_bb [j] == first)
852 bb->in_bb [j] = second;
856 first->out_count = 0;
857 first->out_bb = NULL;
858 link_bblock (cfg, first, second);
860 second->last_ins = first->last_ins;
862 /*g_print ("start search at %p for %p\n", first->cil_code, second->cil_code);*/
863 for (inst = first->code; inst && inst->next; inst = inst->next) {
864 /*char *code = mono_disasm_code_one (NULL, cfg->method, inst->next->cil_code, NULL);
865 g_print ("found %p: %s", inst->next->cil_code, code);
867 if (inst->cil_code < second->cil_code && inst->next->cil_code >= second->cil_code) {
868 second->code = inst->next;
870 first->last_ins = inst;
871 second->next_bb = first->next_bb;
872 first->next_bb = second;
877 g_warning ("bblock split failed in %s::%s\n", cfg->method->klass->name, cfg->method->name);
883 reverse_branch_op (guint32 opcode)
885 static const int reverse_map [] = {
886 CEE_BNE_UN, CEE_BLT, CEE_BLE, CEE_BGT, CEE_BGE,
887 CEE_BEQ, CEE_BLT_UN, CEE_BLE_UN, CEE_BGT_UN, CEE_BGE_UN
889 static const int reverse_fmap [] = {
890 OP_FBNE_UN, OP_FBLT, OP_FBLE, OP_FBGT, OP_FBGE,
891 OP_FBEQ, OP_FBLT_UN, OP_FBLE_UN, OP_FBGT_UN, OP_FBGE_UN
893 static const int reverse_lmap [] = {
894 OP_LBNE_UN, OP_LBLT, OP_LBLE, OP_LBGT, OP_LBGE,
895 OP_LBEQ, OP_LBLT_UN, OP_LBLE_UN, OP_LBGT_UN, OP_LBGE_UN
897 static const int reverse_imap [] = {
898 OP_IBNE_UN, OP_IBLT, OP_IBLE, OP_IBGT, OP_IBGE,
899 OP_IBEQ, OP_IBLT_UN, OP_IBLE_UN, OP_IBGT_UN, OP_IBGE_UN
902 if (opcode >= CEE_BEQ && opcode <= CEE_BLT_UN) {
903 opcode = reverse_map [opcode - CEE_BEQ];
904 } else if (opcode >= OP_FBEQ && opcode <= OP_FBLT_UN) {
905 opcode = reverse_fmap [opcode - OP_FBEQ];
906 } else if (opcode >= OP_LBEQ && opcode <= OP_LBLT_UN) {
907 opcode = reverse_lmap [opcode - OP_LBEQ];
908 } else if (opcode >= OP_IBEQ && opcode <= OP_IBLT_UN) {
909 opcode = reverse_imap [opcode - OP_IBEQ];
911 g_assert_not_reached ();
917 mono_type_to_ldind (MonoType *type)
923 switch (type->type) {
927 case MONO_TYPE_BOOLEAN:
941 case MONO_TYPE_FNPTR:
943 case MONO_TYPE_CLASS:
944 case MONO_TYPE_STRING:
945 case MONO_TYPE_OBJECT:
946 case MONO_TYPE_SZARRAY:
947 case MONO_TYPE_ARRAY:
948 return CEE_LDIND_REF;
956 case MONO_TYPE_VALUETYPE:
957 if (type->data.klass->enumtype) {
958 type = type->data.klass->enum_basetype;
962 case MONO_TYPE_TYPEDBYREF:
964 case MONO_TYPE_GENERICINST:
965 type = &type->data.generic_class->container_class->byval_arg;
968 g_error ("unknown type 0x%02x in type_to_ldind", type->type);
974 mono_type_to_stind (MonoType *type)
980 switch (type->type) {
983 case MONO_TYPE_BOOLEAN:
995 case MONO_TYPE_FNPTR:
997 case MONO_TYPE_CLASS:
998 case MONO_TYPE_STRING:
999 case MONO_TYPE_OBJECT:
1000 case MONO_TYPE_SZARRAY:
1001 case MONO_TYPE_ARRAY:
1002 return CEE_STIND_REF;
1005 return CEE_STIND_I8;
1007 return CEE_STIND_R4;
1009 return CEE_STIND_R8;
1010 case MONO_TYPE_VALUETYPE:
1011 if (type->data.klass->enumtype) {
1012 type = type->data.klass->enum_basetype;
1016 case MONO_TYPE_TYPEDBYREF:
1018 case MONO_TYPE_GENERICINST:
1019 type = &type->data.generic_class->container_class->byval_arg;
1022 g_error ("unknown type 0x%02x in type_to_stind", type->type);
1028 * Returns the type used in the eval stack when @type is loaded.
1029 * FIXME: return a MonoType/MonoClass for the byref and VALUETYPE cases.
1032 type_to_eval_stack_type (MonoType *type, MonoInst *inst)
1037 inst->type = STACK_MP;
1041 klass = mono_class_from_mono_type (type);
1044 switch (type->type) {
1045 case MONO_TYPE_VOID:
1046 inst->type = STACK_INV;
1050 case MONO_TYPE_BOOLEAN:
1053 case MONO_TYPE_CHAR:
1056 inst->type = STACK_I4;
1061 case MONO_TYPE_FNPTR:
1062 inst->type = STACK_PTR;
1064 case MONO_TYPE_CLASS:
1065 case MONO_TYPE_STRING:
1066 case MONO_TYPE_OBJECT:
1067 case MONO_TYPE_SZARRAY:
1068 case MONO_TYPE_ARRAY:
1069 inst->type = STACK_OBJ;
1073 inst->type = STACK_I8;
1077 inst->type = STACK_R8;
1079 case MONO_TYPE_VALUETYPE:
1080 if (type->data.klass->enumtype) {
1081 type = type->data.klass->enum_basetype;
1084 inst->klass = klass;
1085 inst->type = STACK_VTYPE;
1088 case MONO_TYPE_TYPEDBYREF:
1089 inst->klass = mono_defaults.typed_reference_class;
1090 inst->type = STACK_VTYPE;
1092 case MONO_TYPE_GENERICINST:
1093 type = &type->data.generic_class->container_class->byval_arg;
1096 g_error ("unknown type 0x%02x in eval stack type", type->type);
1101 * The following tables are used to quickly validate the IL code in type_from_op ().
1104 bin_num_table [STACK_MAX] [STACK_MAX] = {
1105 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1106 {STACK_INV, STACK_I4, STACK_INV, STACK_PTR, STACK_INV, STACK_MP, STACK_INV, STACK_INV},
1107 {STACK_INV, STACK_INV, STACK_I8, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1108 {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_MP, STACK_INV, STACK_INV},
1109 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_R8, STACK_INV, STACK_INV, STACK_INV},
1110 {STACK_INV, STACK_MP, STACK_INV, STACK_MP, STACK_INV, STACK_PTR, STACK_INV, STACK_INV},
1111 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1112 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
1117 STACK_INV, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_INV, STACK_INV, STACK_INV
1120 /* reduce the size of this table */
1122 bin_int_table [STACK_MAX] [STACK_MAX] = {
1123 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1124 {STACK_INV, STACK_I4, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1125 {STACK_INV, STACK_INV, STACK_I8, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1126 {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1127 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1128 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1129 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1130 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
1134 bin_comp_table [STACK_MAX] [STACK_MAX] = {
1136 {0, 1, 0, 1, 0, 0, 4, 0},
1137 {0, 0, 1, 0, 0, 0, 0, 0},
1138 {0, 1, 0, 1, 0, 2, 4, 0},
1139 {0, 0, 0, 0, 1, 0, 0, 0},
1140 {0, 0, 0, 2, 0, 1, 0, 0},
1141 {0, 4, 0, 4, 0, 0, 3, 0},
1142 {0, 0, 0, 0, 0, 0, 0, 0},
1145 /* reduce the size of this table */
1147 shift_table [STACK_MAX] [STACK_MAX] = {
1148 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1149 {STACK_INV, STACK_I4, STACK_INV, STACK_I4, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1150 {STACK_INV, STACK_I8, STACK_INV, STACK_I8, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1151 {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1152 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1153 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1154 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1155 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
1159 * Tables to map from the non-specific opcode to the matching
1160 * type-specific opcode.
1162 /* handles from CEE_ADD to CEE_SHR_UN (CEE_REM_UN for floats) */
1163 static const guint16
1164 binops_op_map [STACK_MAX] = {
1165 0, 0, OP_LADD-CEE_ADD, OP_PADD-CEE_ADD, OP_FADD-CEE_ADD, OP_PADD-CEE_ADD
1168 /* handles from CEE_NEG to CEE_CONV_U8 */
1169 static const guint16
1170 unops_op_map [STACK_MAX] = {
1171 0, 0, OP_LNEG-CEE_NEG, OP_PNEG-CEE_NEG, OP_FNEG-CEE_NEG, OP_PNEG-CEE_NEG
1174 /* handles from CEE_CONV_U2 to CEE_SUB_OVF_UN */
1175 static const guint16
1176 ovfops_op_map [STACK_MAX] = {
1177 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
1180 /* handles from CEE_CONV_OVF_I1_UN to CEE_CONV_OVF_U_UN */
1181 static const guint16
1182 ovf2ops_op_map [STACK_MAX] = {
1183 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
1186 /* handles from CEE_CONV_OVF_I1 to CEE_CONV_OVF_U8 */
1187 static const guint16
1188 ovf3ops_op_map [STACK_MAX] = {
1189 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
1192 /* handles from CEE_CEQ to CEE_CLT_UN */
1193 static const guint16
1194 ceqops_op_map [STACK_MAX] = {
1195 0, 0, OP_LCEQ-CEE_CEQ, OP_PCEQ-CEE_CEQ, OP_FCEQ-CEE_CEQ, OP_LCEQ-CEE_CEQ
1199 * Sets ins->type (the type on the eval stack) according to the
1200 * type of the opcode and the arguments to it.
1201 * Invalid IL code is marked by setting ins->type to the invalid value STACK_INV.
1203 * FIXME: this function sets ins->type unconditionally in some cases, but
1204 * it should set it to invalid for some types (a conv.x on an object)
1207 type_from_op (MonoInst *ins) {
1208 switch (ins->opcode) {
1215 /* FIXME: check unverifiable args for STACK_MP */
1216 ins->type = bin_num_table [ins->inst_i0->type] [ins->inst_i1->type];
1217 ins->opcode += binops_op_map [ins->type];
1224 ins->type = bin_int_table [ins->inst_i0->type] [ins->inst_i1->type];
1225 ins->opcode += binops_op_map [ins->type];
1230 ins->type = shift_table [ins->inst_i0->type] [ins->inst_i1->type];
1231 ins->opcode += binops_op_map [ins->type];
1235 /* FIXME: handle some specifics with ins->next->type */
1236 ins->type = bin_comp_table [ins->inst_i0->type] [ins->inst_i1->type] ? STACK_I4: STACK_INV;
1237 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))))
1238 ins->opcode = OP_LCOMPARE;
1245 ins->type = bin_comp_table [ins->inst_i0->type] [ins->inst_i1->type] ? STACK_I4: STACK_INV;
1246 ins->opcode += ceqops_op_map [ins->inst_i0->type];
1250 ins->type = neg_table [ins->inst_i0->type];
1251 ins->opcode += unops_op_map [ins->type];
1254 if (ins->inst_i0->type >= STACK_I4 && ins->inst_i0->type <= STACK_PTR)
1255 ins->type = ins->inst_i0->type;
1257 ins->type = STACK_INV;
1258 ins->opcode += unops_op_map [ins->type];
1264 ins->type = STACK_I4;
1265 ins->opcode += unops_op_map [ins->inst_i0->type];
1268 ins->type = STACK_R8;
1269 switch (ins->inst_i0->type) {
1274 ins->opcode = OP_LCONV_TO_R_UN;
1278 case CEE_CONV_OVF_I1:
1279 case CEE_CONV_OVF_U1:
1280 case CEE_CONV_OVF_I2:
1281 case CEE_CONV_OVF_U2:
1282 case CEE_CONV_OVF_I4:
1283 case CEE_CONV_OVF_U4:
1284 ins->type = STACK_I4;
1285 ins->opcode += ovf3ops_op_map [ins->inst_i0->type];
1287 case CEE_CONV_OVF_I_UN:
1288 case CEE_CONV_OVF_U_UN:
1289 ins->type = STACK_PTR;
1290 ins->opcode += ovf2ops_op_map [ins->inst_i0->type];
1292 case CEE_CONV_OVF_I1_UN:
1293 case CEE_CONV_OVF_I2_UN:
1294 case CEE_CONV_OVF_I4_UN:
1295 case CEE_CONV_OVF_U1_UN:
1296 case CEE_CONV_OVF_U2_UN:
1297 case CEE_CONV_OVF_U4_UN:
1298 ins->type = STACK_I4;
1299 ins->opcode += ovf2ops_op_map [ins->inst_i0->type];
1302 ins->type = STACK_PTR;
1303 switch (ins->inst_i0->type) {
1309 ins->opcode = OP_LCONV_TO_U;
1312 ins->opcode = OP_FCONV_TO_U;
1318 ins->type = STACK_I8;
1319 ins->opcode += unops_op_map [ins->inst_i0->type];
1321 case CEE_CONV_OVF_I8:
1322 case CEE_CONV_OVF_U8:
1323 ins->type = STACK_I8;
1324 ins->opcode += ovf3ops_op_map [ins->inst_i0->type];
1326 case CEE_CONV_OVF_U8_UN:
1327 case CEE_CONV_OVF_I8_UN:
1328 ins->type = STACK_I8;
1329 ins->opcode += ovf2ops_op_map [ins->inst_i0->type];
1333 ins->type = STACK_R8;
1334 ins->opcode += unops_op_map [ins->inst_i0->type];
1337 ins->type = STACK_R8;
1341 ins->type = STACK_I4;
1342 ins->opcode += ovfops_op_map [ins->inst_i0->type];
1345 case CEE_CONV_OVF_I:
1346 case CEE_CONV_OVF_U:
1347 ins->type = STACK_PTR;
1348 ins->opcode += ovfops_op_map [ins->inst_i0->type];
1351 case CEE_ADD_OVF_UN:
1353 case CEE_MUL_OVF_UN:
1355 case CEE_SUB_OVF_UN:
1356 ins->type = bin_num_table [ins->inst_i0->type] [ins->inst_i1->type];
1357 ins->opcode += ovfops_op_map [ins->inst_i0->type];
1360 g_error ("opcode 0x%04x not handled in type from op", ins->opcode);
1367 STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I8, STACK_MP, STACK_R8, STACK_R8, STACK_OBJ
1370 /* map ldelem.x to the matching ldind.x opcode */
1372 ldelem_to_ldind [] = {
1386 /* map stelem.x to the matching stind.x opcode */
1388 stelem_to_stind [] = {
1402 param_table [STACK_MAX] [STACK_MAX] = {
1407 check_values_to_signature (MonoInst *args, MonoType *this, MonoMethodSignature *sig) {
1411 switch (args->type) {
1421 for (i = 0; i < sig->param_count; ++i) {
1422 switch (args [i].type) {
1426 if (!sig->params [i]->byref)
1430 if (sig->params [i]->byref)
1432 switch (sig->params [i]->type) {
1433 case MONO_TYPE_CLASS:
1434 case MONO_TYPE_STRING:
1435 case MONO_TYPE_OBJECT:
1436 case MONO_TYPE_SZARRAY:
1437 case MONO_TYPE_ARRAY:
1444 if (sig->params [i]->byref)
1446 if (sig->params [i]->type != MONO_TYPE_R4 && sig->params [i]->type != MONO_TYPE_R8)
1455 /*if (!param_table [args [i].type] [sig->params [i]->type])
1463 * When we need a pointer to the current domain many times in a method, we
1464 * call mono_domain_get() once and we store the result in a local variable.
1465 * This function returns the variable that represents the MonoDomain*.
1467 inline static MonoInst *
1468 mono_get_domainvar (MonoCompile *cfg)
1470 if (!cfg->domainvar)
1471 cfg->domainvar = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1472 return cfg->domainvar;
1476 * The got_var contains the address of the Global Offset Table when AOT
1479 inline static MonoInst *
1480 mono_get_got_var (MonoCompile *cfg)
1482 #ifdef MONO_ARCH_NEED_GOT_VAR
1483 if (!cfg->compile_aot)
1485 if (!cfg->got_var) {
1486 cfg->got_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1488 return cfg->got_var;
1495 mono_compile_create_var (MonoCompile *cfg, MonoType *type, int opcode)
1498 int num = cfg->num_varinfo;
1500 if ((num + 1) >= cfg->varinfo_count) {
1501 cfg->varinfo_count = (cfg->varinfo_count + 2) * 2;
1502 cfg->varinfo = (MonoInst **)g_realloc (cfg->varinfo, sizeof (MonoInst*) * cfg->varinfo_count);
1503 cfg->vars = (MonoMethodVar **)g_realloc (cfg->vars, sizeof (MonoMethodVar*) * cfg->varinfo_count);
1506 /*g_print ("created temp %d of type 0x%x\n", num, type->type);*/
1507 mono_jit_stats.allocate_var++;
1509 MONO_INST_NEW (cfg, inst, opcode);
1510 inst->inst_c0 = num;
1511 inst->inst_vtype = type;
1512 inst->klass = mono_class_from_mono_type (type);
1513 /* if set to 1 the variable is native */
1516 cfg->varinfo [num] = inst;
1518 cfg->vars [num] = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoMethodVar));
1519 MONO_INIT_VARINFO (cfg->vars [num], num);
1522 //g_print ("created temp %d of type %s\n", num, mono_type_get_name (type));
1527 * Transform a MonoInst into a load from the variable of index var_index.
1530 mono_compile_make_var_load (MonoCompile *cfg, MonoInst *dest, gssize var_index) {
1531 memset (dest, 0, sizeof (MonoInst));
1532 dest->ssa_op = MONO_SSA_LOAD;
1533 dest->inst_i0 = cfg->varinfo [var_index];
1534 dest->opcode = mono_type_to_ldind (dest->inst_i0->inst_vtype);
1535 type_to_eval_stack_type (dest->inst_i0->inst_vtype, dest);
1536 dest->klass = dest->inst_i0->klass;
1540 * Create a MonoInst that is a load from the variable of index var_index.
1543 mono_compile_create_var_load (MonoCompile *cfg, gssize var_index) {
1545 NEW_TEMPLOAD (cfg,dest,var_index);
1550 * Create a MonoInst that is a store of the given value into the variable of index var_index.
1553 mono_compile_create_var_store (MonoCompile *cfg, gssize var_index, MonoInst *value) {
1555 NEW_TEMPSTORE (cfg, dest, var_index, value);
1560 type_from_stack_type (MonoInst *ins) {
1561 switch (ins->type) {
1562 case STACK_I4: return &mono_defaults.int32_class->byval_arg;
1563 case STACK_I8: return &mono_defaults.int64_class->byval_arg;
1564 case STACK_PTR: return &mono_defaults.int_class->byval_arg;
1565 case STACK_R8: return &mono_defaults.double_class->byval_arg;
1566 case STACK_MP: return &mono_defaults.int_class->byval_arg;
1567 case STACK_OBJ: return &mono_defaults.object_class->byval_arg;
1568 case STACK_VTYPE: return &ins->klass->byval_arg;
1570 g_error ("stack type %d to montype not handled\n", ins->type);
1576 mono_type_from_stack_type (MonoInst *ins) {
1577 return type_from_stack_type (ins);
1581 array_access_to_klass (int opcode)
1585 return mono_defaults.byte_class;
1587 return mono_defaults.uint16_class;
1590 return mono_defaults.int_class;
1593 return mono_defaults.sbyte_class;
1596 return mono_defaults.int16_class;
1599 return mono_defaults.int32_class;
1601 return mono_defaults.uint32_class;
1604 return mono_defaults.int64_class;
1607 return mono_defaults.single_class;
1610 return mono_defaults.double_class;
1611 case CEE_LDELEM_REF:
1612 case CEE_STELEM_REF:
1613 return mono_defaults.object_class;
1615 g_assert_not_reached ();
1621 mono_add_ins_to_end (MonoBasicBlock *bb, MonoInst *inst)
1625 MONO_ADD_INS (bb, inst);
1628 switch (bb->last_ins->opcode) {
1642 while (prev->next && prev->next != bb->last_ins)
1644 if (prev == bb->code) {
1645 if (bb->last_ins == bb->code) {
1646 inst->next = bb->code;
1649 inst->next = prev->next;
1653 inst->next = bb->last_ins;
1657 // g_warning ("handle conditional jump in add_ins_to_end ()\n");
1659 MONO_ADD_INS (bb, inst);
1665 mono_add_varcopy_to_end (MonoCompile *cfg, MonoBasicBlock *bb, int src, int dest)
1667 MonoInst *inst, *load;
1669 NEW_TEMPLOAD (cfg, load, src);
1671 NEW_TEMPSTORE (cfg, inst, dest, load);
1672 if (inst->opcode == CEE_STOBJ) {
1673 NEW_TEMPLOADA (cfg, inst, dest);
1674 handle_stobj (cfg, bb, inst, load, NULL, inst->klass, TRUE, FALSE);
1676 inst->cil_code = NULL;
1677 mono_add_ins_to_end (bb, inst);
1682 * We try to share variables when possible
1685 mono_compile_get_interface_var (MonoCompile *cfg, int slot, MonoInst *ins)
1690 /* inlining can result in deeper stacks */
1691 if (slot >= mono_method_get_header (cfg->method)->max_stack)
1692 return mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1694 pos = ins->type - 1 + slot * STACK_MAX;
1696 switch (ins->type) {
1703 if ((vnum = cfg->intvars [pos]))
1704 return cfg->varinfo [vnum];
1705 res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1706 cfg->intvars [pos] = res->inst_c0;
1709 res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1715 * This function is called to handle items that are left on the evaluation stack
1716 * at basic block boundaries. What happens is that we save the values to local variables
1717 * and we reload them later when first entering the target basic block (with the
1718 * handle_loaded_temps () function).
1719 * It is also used to handle items on the stack in store opcodes, since it is
1720 * possible that the variable to be stored into is already on the stack, in
1721 * which case its old value should be used.
1722 * A single joint point will use the same variables (stored in the array bb->out_stack or
1723 * bb->in_stack, if the basic block is before or after the joint point).
1726 handle_stack_args (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst **sp, int count) {
1728 MonoBasicBlock *outb;
1729 MonoInst *inst, **locals;
1734 if (cfg->verbose_level > 3)
1735 g_print ("%d item(s) on exit from B%d\n", count, bb->block_num);
1736 if (!bb->out_scount) {
1737 bb->out_scount = count;
1738 //g_print ("bblock %d has out:", bb->block_num);
1740 for (i = 0; i < bb->out_count; ++i) {
1741 outb = bb->out_bb [i];
1742 //g_print (" %d", outb->block_num);
1743 if (outb->in_stack) {
1745 bb->out_stack = outb->in_stack;
1751 bb->out_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * count);
1752 for (i = 0; i < count; ++i) {
1754 * try to reuse temps already allocated for this purpouse, if they occupy the same
1755 * stack slot and if they are of the same type.
1756 * This won't cause conflicts since if 'local' is used to
1757 * store one of the values in the in_stack of a bblock, then
1758 * the same variable will be used for the same outgoing stack
1760 * This doesn't work when inlining methods, since the bblocks
1761 * in the inlined methods do not inherit their in_stack from
1762 * the bblock they are inlined to. See bug #58863 for an
1765 if (cfg->inlined_method)
1766 bb->out_stack [i] = mono_compile_create_var (cfg, type_from_stack_type (sp [i]), OP_LOCAL);
1768 bb->out_stack [i] = mono_compile_get_interface_var (cfg, i, sp [i]);
1773 for (i = 0; i < bb->out_count; ++i) {
1774 outb = bb->out_bb [i];
1775 if (outb->in_scount)
1776 continue; /* check they are the same locals */
1777 outb->in_scount = count;
1778 outb->in_stack = bb->out_stack;
1781 locals = bb->out_stack;
1782 for (i = 0; i < count; ++i) {
1783 /* add store ops at the end of the bb, before the branch */
1784 NEW_TEMPSTORE (cfg, inst, locals [i]->inst_c0, sp [i]);
1785 if (inst->opcode == CEE_STOBJ) {
1786 NEW_TEMPLOADA (cfg, inst, locals [i]->inst_c0);
1787 handle_stobj (cfg, bb, inst, sp [i], sp [i]->cil_code, inst->klass, TRUE, FALSE);
1789 inst->cil_code = sp [i]->cil_code;
1790 mono_add_ins_to_end (bb, inst);
1792 if (cfg->verbose_level > 3)
1793 g_print ("storing %d to temp %d\n", i, (int)locals [i]->inst_c0);
1797 * It is possible that the out bblocks already have in_stack assigned, and
1798 * the in_stacks differ. In this case, we will store to all the different
1805 /* Find a bblock which has a different in_stack */
1807 while (bindex < bb->out_count) {
1808 outb = bb->out_bb [bindex];
1809 if (outb->in_stack != locals) {
1811 * Instead of storing sp [i] to locals [i], we need to store
1812 * locals [i] to <new locals>[i], since the sp [i] tree can't
1813 * be shared between trees.
1815 for (i = 0; i < count; ++i)
1816 mono_add_varcopy_to_end (cfg, bb, locals [i]->inst_c0, outb->in_stack [i]->inst_c0);
1817 locals = outb->in_stack;
1829 ret_type_to_call_opcode (MonoType *type, int calli, int virt)
1832 return calli? OP_CALL_REG: virt? CEE_CALLVIRT: CEE_CALL;
1835 switch (type->type) {
1836 case MONO_TYPE_VOID:
1837 return calli? OP_VOIDCALL_REG: virt? OP_VOIDCALLVIRT: OP_VOIDCALL;
1840 case MONO_TYPE_BOOLEAN:
1843 case MONO_TYPE_CHAR:
1846 return calli? OP_CALL_REG: virt? CEE_CALLVIRT: CEE_CALL;
1850 return calli? OP_CALL_REG: virt? CEE_CALLVIRT: CEE_CALL;
1851 case MONO_TYPE_CLASS:
1852 case MONO_TYPE_STRING:
1853 case MONO_TYPE_OBJECT:
1854 case MONO_TYPE_SZARRAY:
1855 case MONO_TYPE_ARRAY:
1856 return calli? OP_CALL_REG: virt? CEE_CALLVIRT: CEE_CALL;
1859 return calli? OP_LCALL_REG: virt? OP_LCALLVIRT: OP_LCALL;
1862 return calli? OP_FCALL_REG: virt? OP_FCALLVIRT: OP_FCALL;
1863 case MONO_TYPE_VALUETYPE:
1864 if (type->data.klass->enumtype) {
1865 type = type->data.klass->enum_basetype;
1868 return calli? OP_VCALL_REG: virt? OP_VCALLVIRT: OP_VCALL;
1869 case MONO_TYPE_TYPEDBYREF:
1870 return calli? OP_VCALL_REG: virt? OP_VCALLVIRT: OP_VCALL;
1871 case MONO_TYPE_GENERICINST:
1872 type = &type->data.generic_class->container_class->byval_arg;
1875 g_error ("unknown type 0x%02x in ret_type_to_call_opcode", type->type);
1881 mono_create_jump_table (MonoCompile *cfg, MonoInst *label, MonoBasicBlock **bbs, int num_blocks)
1883 MonoJumpInfo *ji = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfo));
1884 MonoJumpInfoBBTable *table;
1886 table = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfoBBTable));
1888 table->table_size = num_blocks;
1890 ji->ip.label = label;
1891 ji->type = MONO_PATCH_INFO_SWITCH;
1892 ji->data.table = table;
1893 ji->next = cfg->patch_info;
1894 cfg->patch_info = ji;
1898 * When we add a tree of instructions, we need to ensure the instructions currently
1899 * on the stack are executed before (like, if we load a value from a local).
1900 * We ensure this by saving the currently loaded values to temps and rewriting the
1901 * instructions to load the values.
1902 * This is not done for opcodes that terminate a basic block (because it's handled already
1903 * by handle_stack_args ()) and for opcodes that can't change values, like POP.
1906 handle_loaded_temps (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst **stack, MonoInst **sp)
1908 MonoInst *load, *store, *temp, *ins;
1910 while (stack < sp) {
1912 /* handle also other constants */
1913 if ((ins->opcode != OP_ICONST) &&
1914 /* temps never get written to again, so we can safely avoid duplicating them */
1915 !(ins->ssa_op == MONO_SSA_LOAD && ins->inst_i0->opcode == OP_LOCAL && ins->inst_i0->flags & MONO_INST_IS_TEMP)) {
1916 temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1917 temp->flags |= MONO_INST_IS_TEMP;
1918 NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
1919 store->cil_code = ins->cil_code;
1920 if (store->opcode == CEE_STOBJ) {
1921 NEW_TEMPLOADA (cfg, store, temp->inst_c0);
1922 handle_stobj (cfg, bblock, store, ins, ins->cil_code, temp->klass, FALSE, FALSE);
1924 MONO_ADD_INS (bblock, store);
1925 NEW_TEMPLOAD (cfg, load, temp->inst_c0);
1926 load->cil_code = ins->cil_code;
1934 * Prepare arguments for passing to a function call.
1935 * Return a non-zero value if the arguments can't be passed to the given
1937 * The type checks are not yet complete and some conversions may need
1938 * casts on 32 or 64 bit architectures.
1941 check_call_signature (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args)
1943 MonoType *simple_type;
1947 if (args [0]->type != STACK_OBJ && args [0]->type != STACK_MP && args [0]->type != STACK_PTR)
1951 for (i = 0; i < sig->param_count; ++i) {
1952 if (sig->params [i]->byref) {
1953 if (args [i]->type != STACK_MP && args [i]->type != STACK_PTR)
1957 simple_type = sig->params [i];
1959 switch (simple_type->type) {
1960 case MONO_TYPE_VOID:
1965 case MONO_TYPE_BOOLEAN:
1968 case MONO_TYPE_CHAR:
1971 if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR)
1977 if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR && args [i]->type != STACK_MP && args [i]->type != STACK_OBJ)
1980 case MONO_TYPE_CLASS:
1981 case MONO_TYPE_STRING:
1982 case MONO_TYPE_OBJECT:
1983 case MONO_TYPE_SZARRAY:
1984 case MONO_TYPE_ARRAY:
1985 if (args [i]->type != STACK_OBJ)
1990 if (args [i]->type != STACK_I8)
1995 if (args [i]->type != STACK_R8)
1998 case MONO_TYPE_VALUETYPE:
1999 if (simple_type->data.klass->enumtype) {
2000 simple_type = simple_type->data.klass->enum_basetype;
2003 if (args [i]->type != STACK_VTYPE)
2006 case MONO_TYPE_TYPEDBYREF:
2007 if (args [i]->type != STACK_VTYPE)
2010 case MONO_TYPE_GENERICINST:
2011 simple_type = &simple_type->data.generic_class->container_class->byval_arg;
2015 g_error ("unknown type 0x%02x in check_call_signature",
2023 mono_spill_call (MonoCompile *cfg, MonoBasicBlock *bblock, MonoCallInst *call, MonoMethodSignature *sig, gboolean ret_object,
2024 const guint8 *ip, gboolean to_end)
2026 MonoInst *temp, *store, *ins = (MonoInst*)call;
2027 MonoType *ret = sig->ret;
2029 if (!MONO_TYPE_IS_VOID (ret) || ret_object) {
2031 call->inst.type = STACK_OBJ;
2032 call->inst.opcode = CEE_CALL;
2033 temp = mono_compile_create_var (cfg, &mono_defaults.string_class->byval_arg, OP_LOCAL);
2035 type_to_eval_stack_type (ret, ins);
2036 temp = mono_compile_create_var (cfg, ret, OP_LOCAL);
2039 temp->flags |= MONO_INST_IS_TEMP;
2041 if (MONO_TYPE_ISSTRUCT (ret)) {
2044 /* we use this to allocate native sized structs */
2045 temp->unused = sig->pinvoke;
2047 NEW_TEMPLOADA (cfg, loada, temp->inst_c0);
2048 if (call->inst.opcode == OP_VCALL)
2049 ins->inst_left = loada;
2051 ins->inst_right = loada; /* a virtual or indirect call */
2054 mono_add_ins_to_end (bblock, ins);
2056 MONO_ADD_INS (bblock, ins);
2058 NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
2059 store->cil_code = ip;
2061 mono_add_ins_to_end (bblock, store);
2063 MONO_ADD_INS (bblock, store);
2065 return temp->inst_c0;
2068 mono_add_ins_to_end (bblock, ins);
2070 MONO_ADD_INS (bblock, ins);
2075 inline static MonoCallInst *
2076 mono_emit_call_args (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethodSignature *sig,
2077 MonoInst **args, int calli, int virtual, const guint8 *ip, gboolean to_end)
2082 MONO_INST_NEW_CALL (cfg, call, ret_type_to_call_opcode (sig->ret, calli, virtual));
2084 call->inst.cil_code = ip;
2086 call->signature = sig;
2087 call = mono_arch_call_opcode (cfg, bblock, call, virtual);
2088 type_to_eval_stack_type (sig->ret, &call->inst);
2090 for (arg = call->out_args; arg;) {
2091 MonoInst *narg = arg->next;
2096 mono_add_ins_to_end (bblock, arg);
2098 MONO_ADD_INS (bblock, arg);
2105 mono_emit_calli (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethodSignature *sig,
2106 MonoInst **args, MonoInst *addr, const guint8 *ip)
2108 MonoCallInst *call = mono_emit_call_args (cfg, bblock, sig, args, TRUE, FALSE, ip, FALSE);
2110 call->inst.inst_i0 = addr;
2112 return mono_spill_call (cfg, bblock, call, sig, FALSE, ip, FALSE);
2115 static MonoCallInst*
2116 mono_emit_method_call (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *method, MonoMethodSignature *sig,
2117 MonoInst **args, const guint8 *ip, MonoInst *this)
2119 gboolean virtual = this != NULL;
2122 call = mono_emit_call_args (cfg, bblock, sig, args, FALSE, virtual, ip, FALSE);
2124 if (this && sig->hasthis &&
2125 (method->klass->marshalbyref || method->klass == mono_defaults.object_class) &&
2126 !(method->flags & METHOD_ATTRIBUTE_VIRTUAL) && !MONO_CHECK_THIS (this)) {
2127 call->method = mono_marshal_get_remoting_invoke_with_check (method);
2129 call->method = method;
2131 call->inst.flags |= MONO_INST_HAS_METHOD;
2132 call->inst.inst_left = this;
2135 mono_get_got_var (cfg);
2136 else if (call->method->klass->flags & TYPE_ATTRIBUTE_INTERFACE)
2137 /* Needed by the code generated in inssel.brg */
2138 mono_get_got_var (cfg);
2144 mono_emit_method_call_spilled (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *method,
2145 MonoMethodSignature *signature, MonoInst **args, const guint8 *ip, MonoInst *this)
2147 MonoCallInst *call = mono_emit_method_call (cfg, bblock, method, signature, args, ip, this);
2149 return mono_spill_call (cfg, bblock, call, signature, method->string_ctor, ip, FALSE);
2153 mono_emit_native_call (MonoCompile *cfg, MonoBasicBlock *bblock, gconstpointer func, MonoMethodSignature *sig,
2154 MonoInst **args, const guint8 *ip, gboolean ret_object, gboolean to_end)
2160 call = mono_emit_call_args (cfg, bblock, sig, args, FALSE, FALSE, ip, to_end);
2162 return mono_spill_call (cfg, bblock, call, sig, ret_object, ip, to_end);
2166 mono_emit_jit_icall (MonoCompile *cfg, MonoBasicBlock *bblock, gconstpointer func, MonoInst **args, const guint8 *ip)
2168 MonoJitICallInfo *info = mono_find_jit_icall_by_addr (func);
2171 g_warning ("unregistered JIT ICall");
2172 g_assert_not_reached ();
2175 mono_get_got_var (cfg);
2176 return mono_emit_native_call (cfg, bblock, mono_icall_get_wrapper (info), info->sig, args, ip, FALSE, FALSE);
2180 mono_emulate_opcode (MonoCompile *cfg, MonoInst *tree, MonoInst **iargs, MonoJitICallInfo *info)
2182 MonoInst *ins, *temp = NULL, *store, *load, *begin;
2183 MonoInst *last_arg = NULL;
2187 //g_print ("emulating: ");
2188 //mono_print_tree_nl (tree);
2189 MONO_INST_NEW_CALL (cfg, call, ret_type_to_call_opcode (info->sig->ret, FALSE, FALSE));
2190 ins = (MonoInst*)call;
2192 call->inst.cil_code = tree->cil_code;
2194 call->signature = info->sig;
2196 call = mono_arch_call_opcode (cfg, cfg->cbb, call, FALSE);
2198 mono_get_got_var (cfg);
2200 if (!MONO_TYPE_IS_VOID (info->sig->ret)) {
2201 temp = mono_compile_create_var (cfg, info->sig->ret, OP_LOCAL);
2202 temp->flags |= MONO_INST_IS_TEMP;
2203 NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
2204 store->cil_code = tree->cil_code;
2209 nargs = info->sig->param_count + info->sig->hasthis;
2211 for (last_arg = call->out_args; last_arg && last_arg->next; last_arg = last_arg->next) ;
2214 last_arg->next = store;
2217 begin = call->out_args;
2221 if (cfg->prev_ins) {
2223 * This assumes that that in a tree, emulate_opcode is called for a
2224 * node before it is called for its children. dec_foreach needs to
2225 * take this into account.
2227 store->next = cfg->prev_ins->next;
2228 cfg->prev_ins->next = begin;
2230 store->next = cfg->cbb->code;
2231 cfg->cbb->code = begin;
2234 call->fptr = mono_icall_get_wrapper (info);
2236 if (!MONO_TYPE_IS_VOID (info->sig->ret)) {
2237 NEW_TEMPLOAD (cfg, load, temp->inst_c0);
2242 static MonoMethodSignature *
2243 mono_get_element_address_signature (int arity)
2245 static GHashTable *sighash = NULL;
2246 MonoMethodSignature *res;
2249 EnterCriticalSection (&jit_mutex);
2251 sighash = g_hash_table_new (NULL, NULL);
2253 else if ((res = g_hash_table_lookup (sighash, GINT_TO_POINTER (arity)))) {
2254 LeaveCriticalSection (&jit_mutex);
2258 res = mono_metadata_signature_alloc (mono_defaults.corlib, arity + 1);
2261 #ifdef MONO_ARCH_VARARG_ICALLS
2262 /* Only set this only some archs since not all backends can handle varargs+pinvoke */
2263 res->call_convention = MONO_CALL_VARARG;
2265 res->params [0] = &mono_defaults.array_class->byval_arg;
2267 for (i = 1; i <= arity; i++)
2268 res->params [i] = &mono_defaults.int_class->byval_arg;
2270 res->ret = &mono_defaults.int_class->byval_arg;
2272 g_hash_table_insert (sighash, GINT_TO_POINTER (arity), res);
2273 LeaveCriticalSection (&jit_mutex);
2278 static MonoMethodSignature *
2279 mono_get_array_new_va_signature (int arity)
2281 static GHashTable *sighash = NULL;
2282 MonoMethodSignature *res;
2285 EnterCriticalSection (&jit_mutex);
2287 sighash = g_hash_table_new (NULL, NULL);
2289 else if ((res = g_hash_table_lookup (sighash, GINT_TO_POINTER (arity)))) {
2290 LeaveCriticalSection (&jit_mutex);
2294 res = mono_metadata_signature_alloc (mono_defaults.corlib, arity + 1);
2297 #ifdef MONO_ARCH_VARARG_ICALLS
2298 /* Only set this only some archs since not all backends can handle varargs+pinvoke */
2299 res->call_convention = MONO_CALL_VARARG;
2302 res->params [0] = &mono_defaults.int_class->byval_arg;
2303 for (i = 0; i < arity; i++)
2304 res->params [i + 1] = &mono_defaults.int_class->byval_arg;
2306 res->ret = &mono_defaults.int_class->byval_arg;
2308 g_hash_table_insert (sighash, GINT_TO_POINTER (arity), res);
2309 LeaveCriticalSection (&jit_mutex);
2315 handle_stobj (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *dest, MonoInst *src, const unsigned char *ip, MonoClass *klass, gboolean to_end, gboolean native) {
2316 MonoInst *iargs [3];
2322 * This check breaks with spilled vars... need to handle it during verification anyway.
2323 * g_assert (klass && klass == src->klass && klass == dest->klass);
2327 n = mono_class_native_size (klass, &align);
2329 n = mono_class_value_size (klass, &align);
2331 if ((cfg->opt & MONO_OPT_INTRINS) && !to_end && n <= sizeof (gpointer) * 5) {
2333 MONO_INST_NEW (cfg, inst, OP_MEMCPY);
2334 inst->inst_left = dest;
2335 inst->inst_right = src;
2336 inst->cil_code = ip;
2338 MONO_ADD_INS (bblock, inst);
2343 NEW_ICONST (cfg, iargs [2], n);
2345 mono_emit_native_call (cfg, bblock, helper_memcpy, helper_sig_memcpy, iargs, ip, FALSE, to_end);
2349 handle_initobj (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *dest, const guchar *ip, MonoClass *klass, MonoInst **stack_start, MonoInst **sp)
2351 MonoInst *iargs [2];
2352 MonoInst *ins, *zero_int32;
2355 NEW_ICONST (cfg, zero_int32, 0);
2357 mono_class_init (klass);
2358 n = mono_class_value_size (klass, NULL);
2359 MONO_INST_NEW (cfg, ins, 0);
2361 ins->inst_left = dest;
2362 ins->inst_right = zero_int32;
2365 ins->opcode = CEE_STIND_I1;
2366 MONO_ADD_INS (bblock, ins);
2369 ins->opcode = CEE_STIND_I2;
2370 MONO_ADD_INS (bblock, ins);
2373 ins->opcode = CEE_STIND_I4;
2374 MONO_ADD_INS (bblock, ins);
2377 if (n <= sizeof (gpointer) * 5) {
2378 ins->opcode = OP_MEMSET;
2381 MONO_ADD_INS (bblock, ins);
2384 handle_loaded_temps (cfg, bblock, stack_start, sp);
2385 NEW_ICONST (cfg, ins, n);
2388 mono_emit_jit_icall (cfg, bblock, helper_initobj, iargs, ip);
2394 handle_alloc (MonoCompile *cfg, MonoBasicBlock *bblock, MonoClass *klass, const guchar *ip)
2396 MonoInst *iargs [2];
2399 if (cfg->opt & MONO_OPT_SHARED) {
2400 NEW_DOMAINCONST (cfg, iargs [0]);
2401 NEW_CLASSCONST (cfg, iargs [1], klass);
2403 alloc_ftn = mono_object_new;
2405 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
2408 alloc_ftn = mono_class_get_allocation_ftn (vtable, &pass_lw);
2410 guint32 lw = vtable->klass->instance_size;
2411 lw = ((lw + (sizeof (gpointer) - 1)) & ~(sizeof (gpointer) - 1)) / sizeof (gpointer);
2412 NEW_ICONST (cfg, iargs [0], lw);
2413 NEW_VTABLECONST (cfg, iargs [1], vtable);
2416 NEW_VTABLECONST (cfg, iargs [0], vtable);
2419 return mono_emit_jit_icall (cfg, bblock, alloc_ftn, iargs, ip);
2423 handle_box (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *val, const guchar *ip, MonoClass *klass)
2425 MonoInst *dest, *vtoffset, *add, *vstore;
2428 temp = handle_alloc (cfg, bblock, klass, ip);
2429 NEW_TEMPLOAD (cfg, dest, temp);
2430 NEW_ICONST (cfg, vtoffset, sizeof (MonoObject));
2431 MONO_INST_NEW (cfg, add, OP_PADD);
2432 add->inst_left = dest;
2433 add->inst_right = vtoffset;
2436 MONO_INST_NEW (cfg, vstore, CEE_STIND_I);
2437 vstore->opcode = mono_type_to_stind (&klass->byval_arg);
2438 vstore->cil_code = ip;
2439 vstore->inst_left = add;
2440 vstore->inst_right = val;
2442 if (vstore->opcode == CEE_STOBJ) {
2443 handle_stobj (cfg, bblock, add, val, ip, klass, FALSE, FALSE);
2445 MONO_ADD_INS (bblock, vstore);
2447 NEW_TEMPLOAD (cfg, dest, temp);
2452 handle_array_new (MonoCompile *cfg, MonoBasicBlock *bblock, int rank, MonoInst **sp, unsigned char *ip)
2454 MonoMethodSignature *esig;
2455 char icall_name [256];
2456 MonoJitICallInfo *info;
2458 /* Need to register the icall so it gets an icall wrapper */
2459 sprintf (icall_name, "ves_array_new_va_%d", rank);
2461 info = mono_find_jit_icall_by_name (icall_name);
2463 esig = mono_get_array_new_va_signature (rank);
2464 info = mono_register_jit_icall (mono_array_new_va, g_strdup (icall_name), esig, FALSE);
2467 cfg->flags |= MONO_CFG_HAS_VARARGS;
2469 return mono_emit_native_call (cfg, bblock, mono_icall_get_wrapper (info), info->sig, sp, ip, TRUE, FALSE);
2473 mono_emit_load_got_addr (MonoCompile *cfg)
2475 MonoInst *load, *store, *dummy_use;
2478 if (!cfg->got_var || cfg->got_var_allocated)
2481 MONO_INST_NEW (cfg, get_got, OP_LOAD_GOTADDR);
2482 NEW_TEMPSTORE (cfg, store, cfg->got_var->inst_c0, get_got);
2484 /* Add it to the start of the first bblock */
2485 if (cfg->bb_entry->code) {
2486 store->next = cfg->bb_entry->code;
2487 cfg->bb_entry->code = store;
2490 MONO_ADD_INS (cfg->bb_entry, store);
2492 cfg->got_var_allocated = TRUE;
2495 * Add a dummy use to keep the got_var alive, since real uses might
2496 * only be generated in the decompose or instruction selection phases.
2497 * Add it to end_bblock, so the variable's lifetime covers the whole
2500 NEW_TEMPLOAD (cfg, load, cfg->got_var->inst_c0);
2501 NEW_DUMMY_USE (cfg, dummy_use, load);
2502 MONO_ADD_INS (cfg->bb_exit, dummy_use);
2505 #define CODE_IS_STLOC(ip) (((ip) [0] >= CEE_STLOC_0 && (ip) [0] <= CEE_STLOC_3) || ((ip) [0] == CEE_STLOC_S))
2508 mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method)
2510 MonoMethodHeader *header = mono_method_get_header (method);
2511 MonoMethodSignature *signature = method->signature;
2515 #ifdef MONO_ARCH_HAVE_LMF_OPS
2516 if (((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
2517 (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) &&
2518 !MONO_TYPE_ISSTRUCT (signature->ret) && (method->klass->parent != mono_defaults.array_class))
2522 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
2523 (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
2524 (method->iflags & METHOD_IMPL_ATTRIBUTE_NOINLINING) ||
2525 (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) ||
2526 (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
2527 (method->klass->marshalbyref) ||
2528 !header || header->num_clauses ||
2529 /* fixme: why cant we inline valuetype returns? */
2530 MONO_TYPE_ISSTRUCT (signature->ret))
2533 /* its not worth to inline methods with valuetype arguments?? */
2534 for (i = 0; i < signature->param_count; i++) {
2535 if (MONO_TYPE_ISSTRUCT (signature->params [i])) {
2541 * if we can initialize the class of the method right away, we do,
2542 * otherwise we don't allow inlining if the class needs initialization,
2543 * since it would mean inserting a call to mono_runtime_class_init()
2544 * inside the inlined code
2546 if (!(cfg->opt & MONO_OPT_SHARED)) {
2547 vtable = mono_class_vtable (cfg->domain, method->klass);
2548 if (method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) {
2549 if (cfg->run_cctors)
2550 mono_runtime_class_init (vtable);
2552 else if (!vtable->initialized && mono_class_needs_cctor_run (method->klass, NULL))
2556 * If we're compiling for shared code
2557 * the cctor will need to be run at aot method load time, for example,
2558 * or at the end of the compilation of the inlining method.
2560 if (mono_class_needs_cctor_run (method->klass, NULL) && !((method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT)))
2563 //if (!MONO_TYPE_IS_VOID (signature->ret)) return FALSE;
2566 * CAS - do not inline methods with declarative security
2567 * Note: this has to be before any possible return TRUE;
2569 if (mono_method_has_declsec (method))
2572 /* also consider num_locals? */
2573 if (getenv ("MONO_INLINELIMIT")) {
2574 if (header->code_size < atoi (getenv ("MONO_INLINELIMIT"))) {
2577 } else if (header->code_size < 20)
2584 mini_get_ldelema_ins (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *cmethod, MonoInst **sp, unsigned char *ip, gboolean is_set)
2588 MonoMethodSignature *esig;
2589 char icall_name [256];
2590 MonoJitICallInfo *info;
2592 rank = cmethod->signature->param_count - (is_set? 1: 0);
2594 if (rank == 2 && (cfg->opt & MONO_OPT_INTRINS)) {
2596 NEW_GROUP (cfg, indexes, sp [1], sp [2]);
2597 MONO_INST_NEW (cfg, addr, OP_LDELEMA2D);
2598 addr->inst_left = sp [0];
2599 addr->inst_right = indexes;
2600 addr->cil_code = ip;
2601 addr->type = STACK_MP;
2602 addr->klass = cmethod->klass;
2606 /* Need to register the icall so it gets an icall wrapper */
2607 sprintf (icall_name, "ves_array_element_address_%d", rank);
2609 info = mono_find_jit_icall_by_name (icall_name);
2611 esig = mono_get_element_address_signature (rank);
2612 info = mono_register_jit_icall (ves_array_element_address, g_strdup (icall_name), esig, FALSE);
2615 temp = mono_emit_native_call (cfg, bblock, mono_icall_get_wrapper (info), info->sig, sp, ip, FALSE, FALSE);
2616 cfg->flags |= MONO_CFG_HAS_VARARGS;
2618 NEW_TEMPLOAD (cfg, addr, temp);
2622 static MonoJitICallInfo **emul_opcode_map = NULL;
2624 static inline MonoJitICallInfo *
2625 mono_find_jit_opcode_emulation (int opcode)
2627 if (emul_opcode_map)
2628 return emul_opcode_map [opcode];
2634 mini_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
2636 MonoInst *ins = NULL;
2638 static MonoClass *runtime_helpers_class = NULL;
2639 if (! runtime_helpers_class)
2640 runtime_helpers_class = mono_class_from_name (mono_defaults.corlib,
2641 "System.Runtime.CompilerServices", "RuntimeHelpers");
2643 if (cmethod->klass == mono_defaults.string_class) {
2644 if (cmethod->name [0] != 'g')
2647 if (strcmp (cmethod->name, "get_Chars") == 0) {
2648 MONO_INST_NEW (cfg, ins, OP_GETCHR);
2649 ins->inst_i0 = args [0];
2650 ins->inst_i1 = args [1];
2652 } else if (strcmp (cmethod->name, "get_Length") == 0) {
2653 MONO_INST_NEW (cfg, ins, OP_STRLEN);
2654 ins->inst_i0 = args [0];
2658 } else if (cmethod->klass == mono_defaults.object_class) {
2659 if (strcmp (cmethod->name, "GetType") == 0) {
2660 MONO_INST_NEW (cfg, ins, OP_GETTYPE);
2661 ins->inst_i0 = args [0];
2663 } else if (strcmp (cmethod->name, "InternalGetHashCode") == 0) {
2664 MONO_INST_NEW (cfg, ins, OP_GETHASHCODE);
2665 ins->inst_i0 = args [0];
2669 } else if (cmethod->klass == mono_defaults.array_class) {
2670 if (cmethod->name [0] != 'g')
2673 if (strcmp (cmethod->name, "get_Rank") == 0) {
2674 MONO_INST_NEW (cfg, ins, OP_ARRAY_RANK);
2675 ins->inst_i0 = args [0];
2677 } else if (strcmp (cmethod->name, "get_Length") == 0) {
2678 MONO_INST_NEW (cfg, ins, CEE_LDLEN);
2679 ins->inst_i0 = args [0];
2683 } else if (cmethod->klass == runtime_helpers_class) {
2684 if (strcmp (cmethod->name, "get_OffsetToStringData") == 0) {
2685 NEW_ICONST (cfg, ins, G_STRUCT_OFFSET (MonoString, chars));
2689 } else if (cmethod->klass == mono_defaults.thread_class) {
2690 if (strcmp (cmethod->name, "get_CurrentThread") == 0 && (ins = mono_arch_get_thread_intrinsic (cfg)))
2695 return mono_arch_get_inst_for_method (cfg, cmethod, fsig, args);
2699 mono_save_args (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethodSignature *sig, MonoInst **sp, MonoInst **args)
2701 MonoInst *store, *temp;
2704 g_assert (!MONO_TYPE_ISSTRUCT (sig->ret));
2706 if (!sig->hasthis && sig->param_count == 0)
2710 if (sp [0]->opcode == OP_ICONST) {
2713 temp = mono_compile_create_var (cfg, type_from_stack_type (*sp), OP_LOCAL);
2715 NEW_TEMPSTORE (cfg, store, temp->inst_c0, *sp);
2716 store->cil_code = sp [0]->cil_code;
2717 MONO_ADD_INS (bblock, store);
2722 for (i = 0; i < sig->param_count; ++i) {
2723 if (sp [0]->opcode == OP_ICONST) {
2726 temp = mono_compile_create_var (cfg, sig->params [i], OP_LOCAL);
2728 NEW_TEMPSTORE (cfg, store, temp->inst_c0, *sp);
2729 store->cil_code = sp [0]->cil_code;
2730 if (store->opcode == CEE_STOBJ) {
2731 NEW_TEMPLOADA (cfg, store, temp->inst_c0);
2732 handle_stobj (cfg, bblock, store, *sp, sp [0]->cil_code, temp->klass, FALSE, FALSE);
2734 MONO_ADD_INS (bblock, store);
2742 inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoBasicBlock *bblock, MonoInst **sp,
2743 guchar *ip, guint real_offset, GList *dont_inline, MonoBasicBlock **last_b, gboolean inline_allways)
2745 MonoInst *ins, *rvar = NULL;
2746 MonoMethodHeader *cheader;
2747 MonoBasicBlock *ebblock, *sbblock;
2748 int i, costs, new_locals_offset;
2749 MonoMethod *prev_inlined_method;
2751 if (cfg->verbose_level > 2)
2752 g_print ("INLINE START %p %s -> %s\n", cmethod, mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
2754 if (!cmethod->inline_info) {
2755 mono_jit_stats.inlineable_methods++;
2756 cmethod->inline_info = 1;
2758 /* allocate space to store the return value */
2759 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
2760 rvar = mono_compile_create_var (cfg, fsig->ret, OP_LOCAL);
2763 /* allocate local variables */
2764 cheader = mono_method_get_header (cmethod);
2765 new_locals_offset = cfg->num_varinfo;
2766 for (i = 0; i < cheader->num_locals; ++i)
2767 mono_compile_create_var (cfg, cheader->locals [i], OP_LOCAL);
2769 /* allocate starte and end blocks */
2770 sbblock = NEW_BBLOCK (cfg);
2771 sbblock->block_num = cfg->num_bblocks++;
2772 sbblock->real_offset = real_offset;
2774 ebblock = NEW_BBLOCK (cfg);
2775 ebblock->block_num = cfg->num_bblocks++;
2776 ebblock->real_offset = real_offset;
2778 prev_inlined_method = cfg->inlined_method;
2779 cfg->inlined_method = cmethod;
2781 costs = mono_method_to_ir (cfg, cmethod, sbblock, ebblock, new_locals_offset, rvar, dont_inline, sp, real_offset, *ip == CEE_CALLVIRT);
2783 cfg->inlined_method = prev_inlined_method;
2785 if ((costs >= 0 && costs < 60) || inline_allways) {
2786 if (cfg->verbose_level > 2)
2787 g_print ("INLINE END %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
2789 mono_jit_stats.inlined_methods++;
2791 /* always add some code to avoid block split failures */
2792 MONO_INST_NEW (cfg, ins, CEE_NOP);
2793 MONO_ADD_INS (bblock, ins);
2796 bblock->next_bb = sbblock;
2797 link_bblock (cfg, bblock, sbblock);
2800 NEW_TEMPLOAD (cfg, ins, rvar->inst_c0);
2806 if (cfg->verbose_level > 2)
2807 g_print ("INLINE ABORTED %s\n", mono_method_full_name (cmethod, TRUE));
2813 * Some of these comments may well be out-of-date.
2814 * Design decisions: we do a single pass over the IL code (and we do bblock
2815 * splitting/merging in the few cases when it's required: a back jump to an IL
2816 * address that was not already seen as bblock starting point).
2817 * Code is validated as we go (full verification is still better left to metadata/verify.c).
2818 * Complex operations are decomposed in simpler ones right away. We need to let the
2819 * arch-specific code peek and poke inside this process somehow (except when the
2820 * optimizations can take advantage of the full semantic info of coarse opcodes).
2821 * All the opcodes of the form opcode.s are 'normalized' to opcode.
2822 * MonoInst->opcode initially is the IL opcode or some simplification of that
2823 * (OP_LOAD, OP_STORE). The arch-specific code may rearrange it to an arch-specific
2824 * opcode with value bigger than OP_LAST.
2825 * At this point the IR can be handed over to an interpreter, a dumb code generator
2826 * or to the optimizing code generator that will translate it to SSA form.
2828 * Profiling directed optimizations.
2829 * We may compile by default with few or no optimizations and instrument the code
2830 * or the user may indicate what methods to optimize the most either in a config file
2831 * or through repeated runs where the compiler applies offline the optimizations to
2832 * each method and then decides if it was worth it.
2835 * * consider using an array instead of an hash table (bb_hash)
2838 #define CHECK_TYPE(ins) if (!(ins)->type) goto unverified
2839 #define CHECK_STACK(num) if ((sp - stack_start) < (num)) goto unverified
2840 #define CHECK_STACK_OVF(num) if (((sp - stack_start) + (num)) > header->max_stack) goto unverified
2841 #define CHECK_ARG(num) if ((unsigned)(num) >= (unsigned)num_args) goto unverified
2842 #define CHECK_LOCAL(num) if ((unsigned)(num) >= (unsigned)header->num_locals) goto unverified
2843 #define CHECK_OPSIZE(size) if (ip + size > end) goto unverified
2846 /* offset from br.s -> br like opcodes */
2847 #define BIG_BRANCH_OFFSET 13
2850 ip_in_bb (MonoCompile *cfg, MonoBasicBlock *bb, const guint8* ip)
2852 MonoBasicBlock *b = g_hash_table_lookup (cfg->bb_hash, ip);
2854 return b == NULL || b == bb;
2858 get_basic_blocks (MonoCompile *cfg, GHashTable *bbhash, MonoMethodHeader* header, guint real_offset, unsigned char *start, unsigned char *end, unsigned char **pos)
2860 unsigned char *ip = start;
2861 unsigned char *target;
2864 MonoBasicBlock *bblock;
2865 const MonoOpcode *opcode;
2868 cli_addr = ip - start;
2869 i = mono_opcode_value ((const guint8 **)&ip, end);
2872 opcode = &mono_opcodes [i];
2873 switch (opcode->argument) {
2874 case MonoInlineNone:
2877 case MonoInlineString:
2878 case MonoInlineType:
2879 case MonoInlineField:
2880 case MonoInlineMethod:
2883 case MonoShortInlineR:
2890 case MonoShortInlineVar:
2891 case MonoShortInlineI:
2894 case MonoShortInlineBrTarget:
2895 target = start + cli_addr + 2 + (signed char)ip [1];
2896 GET_BBLOCK (cfg, bbhash, bblock, target);
2899 case MonoInlineBrTarget:
2900 target = start + cli_addr + 5 + (gint32)read32 (ip + 1);
2901 GET_BBLOCK (cfg, bbhash, bblock, target);
2904 case MonoInlineSwitch: {
2905 guint32 n = read32 (ip + 1);
2908 cli_addr += 5 + 4 * n;
2909 target = start + cli_addr;
2910 GET_BBLOCK (cfg, bbhash, bblock, target);
2912 for (j = 0; j < n; ++j) {
2913 target = start + cli_addr + (gint32)read32 (ip);
2914 GET_BBLOCK (cfg, bbhash, bblock, target);
2924 g_assert_not_reached ();
2934 emit_tree (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *ins, const guint8* ip_next)
2936 MonoInst *store, *temp, *load;
2938 if (ip_in_bb (cfg, bblock, ip_next) &&
2939 (CODE_IS_STLOC (ip_next) || *ip_next == CEE_BRTRUE || *ip_next == CEE_BRFALSE ||
2940 *ip_next == CEE_BRTRUE_S || *ip_next == CEE_BRFALSE_S || *ip_next == CEE_RET))
2943 temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
2944 temp->flags |= MONO_INST_IS_TEMP;
2945 NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
2946 store->cil_code = ins->cil_code;
2947 MONO_ADD_INS (bblock, store);
2948 NEW_TEMPLOAD (cfg, load, temp->inst_c0);
2949 load->cil_code = ins->cil_code;
2953 static inline MonoMethod *
2954 mini_get_method (MonoImage *image, guint32 token, MonoClass *klass, MonoGenericContext *context)
2956 MonoMethod *method = mono_get_method_full (image, token, klass, context);
2958 if (method->is_inflated)
2959 method = mono_get_inflated_method (method);
2965 * mono_method_to_ir: translates IL into basic blocks containing trees
2968 mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock,
2969 int locals_offset, MonoInst *return_var, GList *dont_inline, MonoInst **inline_args,
2970 guint inline_offset, gboolean is_virtual_call)
2972 MonoInst *zero_int32, *zero_int64, *zero_ptr, *zero_obj, *zero_r8;
2973 MonoInst *ins, **sp, **stack_start;
2974 MonoBasicBlock *bblock, *tblock = NULL, *init_localsbb = NULL;
2976 MonoMethod *cmethod;
2977 MonoInst **arg_array;
2978 MonoMethodHeader *header;
2980 guint32 token, ins_flag;
2982 MonoClass *constrained_call = NULL;
2983 unsigned char *ip, *end, *target, *err_pos;
2984 static double r8_0 = 0.0;
2985 MonoMethodSignature *sig;
2986 MonoGenericContext *generic_context = NULL;
2987 MonoGenericContainer *generic_container = NULL;
2988 MonoType **param_types;
2989 GList *bb_recheck = NULL, *tmp;
2990 int i, n, start_new_bblock, align;
2991 int num_calls = 0, inline_costs = 0;
2992 int *filter_lengths = NULL;
2993 int breakpoint_id = 0;
2994 guint real_offset, num_args;
2996 image = method->klass->image;
2997 header = mono_method_get_header (method);
2998 generic_container = ((MonoMethodNormal *)method)->generic_container;
2999 sig = method->signature;
3000 num_args = sig->hasthis + sig->param_count;
3001 ip = (unsigned char*)header->code;
3002 end = ip + header->code_size;
3003 mono_jit_stats.cil_code_size += header->code_size;
3005 if (method->signature->is_inflated)
3006 generic_context = ((MonoMethodInflated *) method)->context;
3007 else if (generic_container)
3008 generic_context = &generic_container->context;
3010 g_assert (!method->signature->has_type_parameters);
3012 if (cfg->method == method) {
3014 bbhash = cfg->bb_hash;
3016 real_offset = inline_offset;
3017 bbhash = g_hash_table_new (g_direct_hash, NULL);
3020 if (cfg->verbose_level > 2)
3021 g_print ("method to IR %s\n", mono_method_full_name (method, TRUE));
3023 dont_inline = g_list_prepend (dont_inline, method);
3024 if (cfg->method == method) {
3026 if (cfg->method->save_lmf)
3027 /* Needed by the prolog code */
3028 mono_get_got_var (cfg);
3030 if (cfg->prof_options & MONO_PROFILE_INS_COVERAGE)
3031 cfg->coverage_info = mono_profiler_coverage_alloc (cfg->method, header->code_size);
3034 cfg->bb_entry = start_bblock = NEW_BBLOCK (cfg);
3035 start_bblock->cil_code = NULL;
3036 start_bblock->cil_length = 0;
3037 start_bblock->block_num = cfg->num_bblocks++;
3040 cfg->bb_exit = end_bblock = NEW_BBLOCK (cfg);
3041 end_bblock->cil_code = NULL;
3042 end_bblock->cil_length = 0;
3043 end_bblock->block_num = cfg->num_bblocks++;
3044 g_assert (cfg->num_bblocks == 2);
3046 arg_array = alloca (sizeof (MonoInst *) * num_args);
3047 for (i = num_args - 1; i >= 0; i--)
3048 arg_array [i] = cfg->varinfo [i];
3050 if (header->num_clauses) {
3051 int size = sizeof (int) * header->num_clauses;
3052 filter_lengths = alloca (size);
3053 memset (filter_lengths, 0, size);
3055 cfg->spvars = g_hash_table_new (NULL, NULL);
3057 /* handle exception clauses */
3058 for (i = 0; i < header->num_clauses; ++i) {
3059 //unsigned char *p = ip;
3060 MonoExceptionClause *clause = &header->clauses [i];
3061 GET_BBLOCK (cfg, bbhash, tblock, ip + clause->try_offset);
3062 tblock->real_offset = clause->try_offset;
3063 GET_BBLOCK (cfg, bbhash, tblock, ip + clause->handler_offset);
3064 tblock->real_offset = clause->handler_offset;
3066 if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY ||
3067 clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
3068 MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
3069 MONO_ADD_INS (tblock, ins);
3072 /*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);
3074 g_print ("%s", mono_disasm_code_one (NULL, method, p, &p));
3076 /* catch and filter blocks get the exception object on the stack */
3077 if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE ||
3078 clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
3079 /* mostly like handle_stack_args (), but just sets the input args */
3080 /* g_print ("handling clause at IL_%04x\n", clause->handler_offset); */
3082 cfg->exvar = mono_compile_create_var (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL);
3083 /* prevent it from being register allocated */
3084 cfg->exvar->flags |= MONO_INST_INDIRECT;
3086 tblock->in_scount = 1;
3087 tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
3088 tblock->in_stack [0] = cfg->exvar;
3090 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
3091 GET_BBLOCK (cfg, bbhash, tblock, ip + clause->data.filter_offset);
3092 tblock->real_offset = clause->data.filter_offset;
3093 tblock->in_scount = 1;
3094 tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
3095 tblock->in_stack [0] = cfg->exvar;
3096 MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
3097 MONO_ADD_INS (tblock, ins);
3102 arg_array = alloca (sizeof (MonoInst *) * num_args);
3103 mono_save_args (cfg, start_bblock, sig, inline_args, arg_array);
3106 /* FIRST CODE BLOCK */
3107 bblock = NEW_BBLOCK (cfg);
3108 bblock->cil_code = ip;
3110 ADD_BBLOCK (cfg, bbhash, bblock);
3112 if (cfg->method == method) {
3113 breakpoint_id = mono_debugger_method_has_breakpoint (method);
3114 if (breakpoint_id && (mono_debug_format != MONO_DEBUG_FORMAT_DEBUGGER)) {
3115 MONO_INST_NEW (cfg, ins, CEE_BREAK);
3116 MONO_ADD_INS (bblock, ins);
3120 if ((header->init_locals || (cfg->method == method && (cfg->opt & MONO_OPT_SHARED))) || cfg->compile_aot) {
3121 /* we use a separate basic block for the initialization code */
3122 cfg->bb_init = init_localsbb = NEW_BBLOCK (cfg);
3123 init_localsbb->real_offset = real_offset;
3124 start_bblock->next_bb = init_localsbb;
3125 init_localsbb->next_bb = bblock;
3126 link_bblock (cfg, start_bblock, init_localsbb);
3127 link_bblock (cfg, init_localsbb, bblock);
3128 init_localsbb->block_num = cfg->num_bblocks++;
3130 start_bblock->next_bb = bblock;
3131 link_bblock (cfg, start_bblock, bblock);
3134 if (get_basic_blocks (cfg, bbhash, header, real_offset, ip, end, &err_pos)) {
3139 if (cfg->method == method)
3140 mono_debug_init_method (cfg, bblock, breakpoint_id);
3142 param_types = mono_mempool_alloc (cfg->mempool, sizeof (MonoType*) * num_args);
3144 param_types [0] = method->klass->valuetype?&method->klass->this_arg:&method->klass->byval_arg;
3145 for (n = 0; n < sig->param_count; ++n)
3146 param_types [n + sig->hasthis] = sig->params [n];
3148 /* do this somewhere outside - not here */
3149 NEW_ICONST (cfg, zero_int32, 0);
3150 NEW_ICONST (cfg, zero_int64, 0);
3151 zero_int64->type = STACK_I8;
3152 NEW_PCONST (cfg, zero_ptr, 0);
3153 NEW_PCONST (cfg, zero_obj, 0);
3154 zero_obj->type = STACK_OBJ;
3156 MONO_INST_NEW (cfg, zero_r8, OP_R8CONST);
3157 zero_r8->type = STACK_R8;
3158 zero_r8->inst_p0 = &r8_0;
3160 /* add a check for this != NULL to inlined methods */
3161 if (is_virtual_call) {
3162 MONO_INST_NEW (cfg, ins, OP_CHECK_THIS);
3163 NEW_ARGLOAD (cfg, ins->inst_left, 0);
3165 MONO_ADD_INS (bblock, ins);
3168 /* we use a spare stack slot in SWITCH and NEWOBJ and others */
3169 stack_start = sp = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * (header->max_stack + 1));
3172 start_new_bblock = 0;
3175 if (cfg->method == method)
3176 real_offset = ip - header->code;
3178 real_offset = inline_offset;
3180 if (start_new_bblock) {
3181 bblock->cil_length = ip - bblock->cil_code;
3182 if (start_new_bblock == 2) {
3183 g_assert (ip == tblock->cil_code);
3185 GET_BBLOCK (cfg, bbhash, tblock, ip);
3187 bblock->next_bb = tblock;
3189 start_new_bblock = 0;
3190 for (i = 0; i < bblock->in_scount; ++i) {
3191 if (cfg->verbose_level > 3)
3192 g_print ("loading %d from temp %d\n", i, (int)bblock->in_stack [i]->inst_c0);
3193 NEW_TEMPLOAD (cfg, ins, bblock->in_stack [i]->inst_c0);
3197 if ((tblock = g_hash_table_lookup (bbhash, ip)) && (tblock != bblock)) {
3198 link_bblock (cfg, bblock, tblock);
3199 if (sp != stack_start) {
3200 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
3203 bblock->next_bb = tblock;
3205 for (i = 0; i < bblock->in_scount; ++i) {
3206 if (cfg->verbose_level > 3)
3207 g_print ("loading %d from temp %d\n", i, (int)bblock->in_stack [i]->inst_c0);
3208 NEW_TEMPLOAD (cfg, ins, bblock->in_stack [i]->inst_c0);
3214 bblock->real_offset = real_offset;
3216 if ((cfg->method == method) && cfg->coverage_info) {
3217 MonoInst *store, *one;
3218 guint32 cil_offset = ip - header->code;
3219 cfg->coverage_info->data [cil_offset].cil_code = ip;
3221 /* TODO: Use an increment here */
3222 NEW_ICONST (cfg, one, 1);
3225 NEW_PCONST (cfg, ins, &(cfg->coverage_info->data [cil_offset].count));
3228 MONO_INST_NEW (cfg, store, CEE_STIND_I);
3229 store->cil_code = ip;
3230 store->inst_left = ins;
3231 store->inst_right = one;
3233 MONO_ADD_INS (bblock, store);
3236 if (cfg->verbose_level > 3)
3237 g_print ("converting (in B%d: stack: %d) %s", bblock->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
3244 MONO_INST_NEW (cfg, ins, CEE_BREAK);
3245 ins->cil_code = ip++;
3246 MONO_ADD_INS (bblock, ins);
3252 CHECK_STACK_OVF (1);
3253 n = (*ip)-CEE_LDARG_0;
3255 NEW_ARGLOAD (cfg, ins, n);
3256 ins->cil_code = ip++;
3263 CHECK_STACK_OVF (1);
3264 n = (*ip)-CEE_LDLOC_0;
3266 NEW_LOCLOAD (cfg, ins, n);
3267 ins->cil_code = ip++;
3275 n = (*ip)-CEE_STLOC_0;
3278 handle_loaded_temps (cfg, bblock, stack_start, sp);
3279 NEW_LOCSTORE (cfg, ins, n, *sp);
3281 if (ins->opcode == CEE_STOBJ) {
3282 NEW_LOCLOADA (cfg, ins, n);
3283 handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE);
3285 MONO_ADD_INS (bblock, ins);
3291 CHECK_STACK_OVF (1);
3293 NEW_ARGLOAD (cfg, ins, ip [1]);
3300 CHECK_STACK_OVF (1);
3302 NEW_ARGLOADA (cfg, ins, ip [1]);
3312 NEW_ARGSTORE (cfg, ins, ip [1], *sp);
3313 handle_loaded_temps (cfg, bblock, stack_start, sp);
3315 if (ins->opcode == CEE_STOBJ) {
3316 NEW_ARGLOADA (cfg, ins, ip [1]);
3317 handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE);
3319 MONO_ADD_INS (bblock, ins);
3324 CHECK_STACK_OVF (1);
3325 CHECK_LOCAL (ip [1]);
3326 NEW_LOCLOAD (cfg, ins, ip [1]);
3333 CHECK_STACK_OVF (1);
3334 CHECK_LOCAL (ip [1]);
3335 NEW_LOCLOADA (cfg, ins, ip [1]);
3344 handle_loaded_temps (cfg, bblock, stack_start, sp);
3345 CHECK_LOCAL (ip [1]);
3346 NEW_LOCSTORE (cfg, ins, ip [1], *sp);
3348 if (ins->opcode == CEE_STOBJ) {
3349 NEW_LOCLOADA (cfg, ins, ip [1]);
3350 handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE);
3352 MONO_ADD_INS (bblock, ins);
3357 CHECK_STACK_OVF (1);
3358 NEW_PCONST (cfg, ins, NULL);
3360 ins->type = STACK_OBJ;
3365 CHECK_STACK_OVF (1);
3366 NEW_ICONST (cfg, ins, -1);
3380 CHECK_STACK_OVF (1);
3381 NEW_ICONST (cfg, ins, (*ip) - CEE_LDC_I4_0);
3388 CHECK_STACK_OVF (1);
3390 NEW_ICONST (cfg, ins, *((signed char*)ip));
3397 CHECK_STACK_OVF (1);
3398 NEW_ICONST (cfg, ins, (gint32)read32 (ip + 1));
3405 CHECK_STACK_OVF (1);
3406 MONO_INST_NEW (cfg, ins, OP_I8CONST);
3408 ins->type = STACK_I8;
3410 ins->inst_l = (gint64)read64 (ip);
3415 float *f = mono_mempool_alloc (cfg->domain->mp, sizeof (float));
3417 CHECK_STACK_OVF (1);
3418 MONO_INST_NEW (cfg, ins, OP_R4CONST);
3419 ins->type = STACK_R8;
3429 double *d = mono_mempool_alloc (cfg->domain->mp, sizeof (double));
3431 CHECK_STACK_OVF (1);
3432 MONO_INST_NEW (cfg, ins, OP_R8CONST);
3433 ins->type = STACK_R8;
3443 MonoInst *temp, *store;
3445 CHECK_STACK_OVF (1);
3450 * small optimization: if the loaded value was from a local already,
3451 * just load it twice.
3453 if (ins->ssa_op == MONO_SSA_LOAD &&
3454 (ins->inst_i0->opcode == OP_LOCAL || ins->inst_i0->opcode == OP_ARG)) {
3456 MONO_INST_NEW (cfg, temp, 0);
3458 temp->cil_code = ip;
3461 /* Common idiom: ... / dup / stloc.x */
3463 if (ip_in_bb (cfg, bblock, ip + 1)) {
3469 n = (ip [1]) - CEE_STLOC_0;
3479 if (ip [2] == CEE_LDLOC) {
3480 n = read16 (ip + 3);
3488 handle_loaded_temps (cfg, bblock, stack_start, sp - 1);
3489 NEW_LOCSTORE (cfg, ins, n, *sp);
3491 if (ins->opcode == CEE_STOBJ) {
3492 NEW_LOCLOADA (cfg, ins, n);
3493 handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE);
3495 MONO_ADD_INS (bblock, ins);
3497 NEW_LOCLOAD (cfg, *sp, n);
3498 (*sp)->cil_code = ip;
3502 temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
3503 temp->flags |= MONO_INST_IS_TEMP;
3504 temp->cil_code = ip;
3505 NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
3506 store->cil_code = ip;
3507 MONO_ADD_INS (bblock, store);
3508 NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
3511 NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
3522 MONO_INST_NEW (cfg, ins, CEE_POP);
3523 MONO_ADD_INS (bblock, ins);
3524 ins->cil_code = ip++;
3530 if (stack_start != sp)
3532 MONO_INST_NEW (cfg, ins, CEE_JMP);
3533 token = read32 (ip + 1);
3534 /* FIXME: check the signature matches */
3535 cmethod = mini_get_method (image, token, NULL, generic_context);
3536 ins->inst_p0 = cmethod;
3537 MONO_ADD_INS (bblock, ins);
3539 start_new_bblock = 1;
3543 case CEE_CALLVIRT: {
3544 MonoInst *addr = NULL;
3545 MonoMethodSignature *fsig = NULL;
3546 int temp, array_rank = 0;
3547 int virtual = *ip == CEE_CALLVIRT;
3550 token = read32 (ip + 1);
3552 if (*ip == CEE_CALLI) {
3557 if (method->wrapper_type != MONO_WRAPPER_NONE)
3558 fsig = (MonoMethodSignature *)mono_method_get_wrapper_data (method, token);
3560 fsig = mono_metadata_parse_signature (image, token);
3562 n = fsig->param_count + fsig->hasthis;
3564 if (method->wrapper_type != MONO_WRAPPER_NONE) {
3565 cmethod = (MonoMethod *)mono_method_get_wrapper_data (method, token);
3566 } else if (constrained_call) {
3567 cmethod = mono_get_method_constrained (image, token, constrained_call, generic_context);
3569 cmethod = mini_get_method (image, token, NULL, generic_context);
3574 if (!cmethod->klass->inited)
3575 mono_class_init (cmethod->klass);
3577 if (cmethod->signature->pinvoke) {
3578 MonoMethod *wrapper = mono_marshal_get_native_wrapper (cmethod);
3579 fsig = wrapper->signature;
3580 } else if (constrained_call) {
3581 fsig = cmethod->signature;
3583 fsig = mono_method_get_signature_full (cmethod, image, token, generic_context);
3586 n = fsig->param_count + fsig->hasthis;
3588 if (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL &&
3589 cmethod->klass->parent == mono_defaults.array_class) {
3590 array_rank = cmethod->klass->rank;
3593 if (cmethod->string_ctor)
3594 g_assert_not_reached ();
3599 mono_get_got_var (cfg);
3601 /* code in inssel.brg might transform a virtual call to a normal call */
3602 if (!(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
3603 ((cmethod->flags & METHOD_ATTRIBUTE_FINAL) &&
3604 cmethod->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK))
3605 mono_get_got_var (cfg);
3608 if (cmethod && cmethod->klass->generic_container) {
3615 //g_assert (!virtual || fsig->hasthis);
3619 if (constrained_call) {
3621 * We have the `constrained.' prefix opcode.
3623 if (constrained_call->valuetype && !cmethod->klass->valuetype) {
3626 * The type parameter is instantiated as a valuetype,
3627 * but that type doesn't override the method we're
3628 * calling, so we need to box `this'.
3629 * sp [0] is a pointer to the data: we need the value
3630 * in handle_box (), so load it here.
3632 MONO_INST_NEW (cfg, load, mono_type_to_ldind (&constrained_call->byval_arg));
3633 type_to_eval_stack_type (&constrained_call->byval_arg, load);
3634 load->cil_code = ip;
3635 load->inst_left = sp [0];
3636 sp [0] = handle_box (cfg, bblock, load, ip, constrained_call);
3637 } else if (!constrained_call->valuetype) {
3641 * The type parameter is instantiated as a reference
3642 * type. We have a managed pointer on the stack, so
3643 * we need to dereference it here.
3646 MONO_INST_NEW (cfg, ins, CEE_LDIND_REF);
3648 ins->inst_i0 = sp [0];
3649 ins->type = STACK_OBJ;
3651 } else if (cmethod->klass->valuetype)
3653 constrained_call = NULL;
3656 if (*ip != CEE_CALLI && check_call_signature (cfg, fsig, sp)) {
3661 if (cmethod && virtual && cmethod->signature->generic_param_count) {
3662 MonoInst *this_temp, *store;
3663 MonoInst *iargs [3];
3665 g_assert (cmethod->signature->is_inflated);
3667 this_temp = mono_compile_create_var (cfg, type_from_stack_type (sp [0]), OP_LOCAL);
3668 this_temp->cil_code = ip;
3669 NEW_TEMPSTORE (cfg, store, this_temp->inst_c0, sp [0]);
3671 store->cil_code = ip;
3672 MONO_ADD_INS (bblock, store);
3674 NEW_TEMPLOAD (cfg, iargs [0], this_temp->inst_c0);
3675 NEW_PCONST (cfg, iargs [1], cmethod);
3676 NEW_PCONST (cfg, iargs [2], ((MonoMethodInflated *) cmethod)->context);
3677 temp = mono_emit_jit_icall (cfg, bblock, helper_compile_generic_method, iargs, ip);
3679 NEW_TEMPLOAD (cfg, addr, temp);
3680 NEW_TEMPLOAD (cfg, sp [0], this_temp->inst_c0);
3682 if ((temp = mono_emit_calli (cfg, bblock, fsig, sp, addr, ip)) != -1) {
3683 NEW_TEMPLOAD (cfg, *sp, temp);
3691 if ((ins_flag & MONO_INST_TAILCALL) && cmethod && (*ip == CEE_CALL) && (mono_metadata_signature_equal (method->signature, cmethod->signature))) {
3693 /* FIXME: This assumes the two methods has the same number and type of arguments */
3694 for (i = 0; i < n; ++i) {
3695 /* Check if argument is the same */
3696 NEW_ARGLOAD (cfg, ins, i);
3697 if ((ins->opcode == sp [i]->opcode) && (ins->inst_i0 == sp [i]->inst_i0))
3700 /* Prevent argument from being register allocated */
3701 arg_array [i]->flags |= MONO_INST_VOLATILE;
3702 NEW_ARGSTORE (cfg, ins, i, sp [i]);
3704 if (ins->opcode == CEE_STOBJ) {
3705 NEW_ARGLOADA (cfg, ins, i);
3706 handle_stobj (cfg, bblock, ins, sp [i], sp [i]->cil_code, ins->klass, FALSE, FALSE);
3709 MONO_ADD_INS (bblock, ins);
3711 MONO_INST_NEW (cfg, ins, CEE_JMP);
3713 ins->inst_p0 = cmethod;
3714 ins->inst_p1 = arg_array [0];
3715 MONO_ADD_INS (bblock, ins);
3716 link_bblock (cfg, bblock, end_bblock);
3717 start_new_bblock = 1;
3718 /* skip CEE_RET as well */
3723 if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_get_inst_for_method (cfg, cmethod, fsig, sp))) {
3726 if (MONO_TYPE_IS_VOID (fsig->ret)) {
3727 MONO_ADD_INS (bblock, ins);
3729 type_to_eval_stack_type (fsig->ret, ins);
3738 handle_loaded_temps (cfg, bblock, stack_start, sp);
3740 if ((cfg->opt & MONO_OPT_INLINE) && cmethod &&
3741 (!virtual || !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) || (cmethod->flags & METHOD_ATTRIBUTE_FINAL)) &&
3742 mono_method_check_inlining (cfg, cmethod) &&
3743 !g_list_find (dont_inline, cmethod)) {
3745 MonoBasicBlock *ebblock;
3746 gboolean allways = FALSE;
3748 if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
3749 (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
3750 cmethod = mono_marshal_get_native_wrapper (cmethod);
3754 if ((costs = inline_method (cfg, cmethod, fsig, bblock, sp, ip, real_offset, dont_inline, &ebblock, allways))) {
3758 GET_BBLOCK (cfg, bbhash, bblock, ip);
3759 ebblock->next_bb = bblock;
3760 link_bblock (cfg, ebblock, bblock);
3762 if (!MONO_TYPE_IS_VOID (fsig->ret))
3765 /* indicates start of a new block, and triggers a load of all
3766 stack arguments at bb boundarie */
3769 inline_costs += costs;
3774 inline_costs += 10 * num_calls++;
3776 /* tail recursion elimination */
3777 if ((cfg->opt & MONO_OPT_TAILC) && *ip == CEE_CALL && cmethod == method && ip [5] == CEE_RET) {
3778 gboolean has_vtargs = FALSE;
3781 /* keep it simple */
3782 for (i = fsig->param_count - 1; i >= 0; i--) {
3783 if (MONO_TYPE_ISSTRUCT (cmethod->signature->params [i]))
3788 for (i = 0; i < n; ++i) {
3789 NEW_ARGSTORE (cfg, ins, i, sp [i]);
3791 MONO_ADD_INS (bblock, ins);
3793 MONO_INST_NEW (cfg, ins, CEE_BR);
3795 MONO_ADD_INS (bblock, ins);
3796 tblock = start_bblock->out_bb [0];
3797 link_bblock (cfg, bblock, tblock);
3798 ins->inst_target_bb = tblock;
3799 start_new_bblock = 1;
3802 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
3803 /* just create a dummy - the value is never used */
3804 ins = mono_compile_create_var (cfg, fsig->ret, OP_LOCAL);
3805 NEW_TEMPLOAD (cfg, *sp, ins->inst_c0);
3813 if (*ip == CEE_CALLI) {
3815 if ((temp = mono_emit_calli (cfg, bblock, fsig, sp, addr, ip)) != -1) {
3816 NEW_TEMPLOAD (cfg, *sp, temp);
3820 } else if (array_rank) {
3823 if (strcmp (cmethod->name, "Set") == 0) { /* array Set */
3824 if (sp [fsig->param_count]->type == STACK_OBJ) {
3825 MonoInst *iargs [2];
3826 MonoInst *array, *to_store, *store;
3828 handle_loaded_temps (cfg, bblock, stack_start, sp);
3830 array = mono_compile_create_var (cfg, type_from_stack_type (sp [0]), OP_LOCAL);
3831 NEW_TEMPSTORE (cfg, store, array->inst_c0, sp [0]);
3832 store->cil_code = ip;
3833 MONO_ADD_INS (bblock, store);
3834 NEW_TEMPLOAD (cfg, iargs [0], array->inst_c0);
3836 to_store = mono_compile_create_var (cfg, type_from_stack_type (sp [fsig->param_count]), OP_LOCAL);
3837 NEW_TEMPSTORE (cfg, store, to_store->inst_c0, sp [fsig->param_count]);
3838 store->cil_code = ip;
3839 MONO_ADD_INS (bblock, store);
3840 NEW_TEMPLOAD (cfg, iargs [1], to_store->inst_c0);
3843 * We first save the args for the call so that the args are copied to the stack
3844 * and a new instruction tree for them is created. If we don't do this,
3845 * the same MonoInst is added to two different trees and this is not
3848 mono_emit_jit_icall (cfg, bblock, helper_stelem_ref_check, iargs, ip);
3850 NEW_TEMPLOAD (cfg, sp [0], array->inst_c0);
3851 NEW_TEMPLOAD (cfg, sp [fsig->param_count], to_store->inst_c0);
3854 addr = mini_get_ldelema_ins (cfg, bblock, cmethod, sp, ip, TRUE);
3855 NEW_INDSTORE (cfg, ins, addr, sp [fsig->param_count], fsig->params [fsig->param_count - 1]);
3857 if (ins->opcode == CEE_STOBJ) {
3858 handle_stobj (cfg, bblock, addr, sp [fsig->param_count], ip, mono_class_from_mono_type (fsig->params [fsig->param_count-1]), FALSE, FALSE);
3860 MONO_ADD_INS (bblock, ins);
3863 } else if (strcmp (cmethod->name, "Get") == 0) { /* array Get */
3864 addr = mini_get_ldelema_ins (cfg, bblock, cmethod, sp, ip, FALSE);
3865 NEW_INDLOAD (cfg, ins, addr, fsig->ret);
3869 } else if (strcmp (cmethod->name, "Address") == 0) { /* array Address */
3870 addr = mini_get_ldelema_ins (cfg, bblock, cmethod, sp, ip, FALSE);
3873 g_assert_not_reached ();
3877 if (ip_in_bb (cfg, bblock, ip + 5)
3878 && (!MONO_TYPE_ISSTRUCT (fsig->ret))
3879 && (!MONO_TYPE_IS_VOID (fsig->ret) || cmethod->string_ctor)
3880 && (CODE_IS_STLOC (ip + 5) || ip [5] == CEE_POP || ip [5] == CEE_BRTRUE || ip [5] == CEE_BRFALSE ||
3881 ip [5] == CEE_BRTRUE_S || ip [5] == CEE_BRFALSE_S || ip [5] == CEE_RET)) {
3882 /* no need to spill */
3883 ins = (MonoInst*)mono_emit_method_call (cfg, bblock, cmethod, fsig, sp, ip, virtual ? sp [0] : NULL);
3886 if ((temp = mono_emit_method_call_spilled (cfg, bblock, cmethod, fsig, sp, ip, virtual ? sp [0] : NULL)) != -1) {
3887 NEW_TEMPLOAD (cfg, *sp, temp);
3897 if (cfg->method != method) {
3898 /* return from inlined methode */
3903 //g_assert (returnvar != -1);
3904 NEW_TEMPSTORE (cfg, store, return_var->inst_c0, *sp);
3905 store->cil_code = sp [0]->cil_code;
3906 if (store->opcode == CEE_STOBJ) {
3907 g_assert_not_reached ();
3908 NEW_TEMPLOADA (cfg, store, return_var->inst_c0);
3909 handle_stobj (cfg, bblock, store, *sp, sp [0]->cil_code, return_var->klass, FALSE, FALSE);
3911 MONO_ADD_INS (bblock, store);
3915 g_assert (!return_var);
3918 MONO_INST_NEW (cfg, ins, CEE_NOP);
3919 ins->opcode = mono_type_to_stind (method->signature->ret);
3920 if (ins->opcode == CEE_STOBJ) {
3921 NEW_RETLOADA (cfg, ins);
3922 handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE);
3924 ins->opcode = OP_SETRET;
3926 ins->inst_i0 = *sp;;
3927 ins->inst_i1 = NULL;
3928 MONO_ADD_INS (bblock, ins);
3932 if (sp != stack_start)
3934 MONO_INST_NEW (cfg, ins, CEE_BR);
3935 ins->cil_code = ip++;
3936 ins->inst_target_bb = end_bblock;
3937 MONO_ADD_INS (bblock, ins);
3938 link_bblock (cfg, bblock, end_bblock);
3939 start_new_bblock = 1;
3943 MONO_INST_NEW (cfg, ins, CEE_BR);
3944 ins->cil_code = ip++;
3945 MONO_ADD_INS (bblock, ins);
3946 target = ip + 1 + (signed char)(*ip);
3948 GET_BBLOCK (cfg, bbhash, tblock, target);
3949 link_bblock (cfg, bblock, tblock);
3950 CHECK_BBLOCK (target, ip, tblock);
3951 ins->inst_target_bb = tblock;
3952 if (sp != stack_start) {
3953 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
3956 start_new_bblock = 1;
3963 MONO_INST_NEW (cfg, ins, *ip + BIG_BRANCH_OFFSET);
3964 ins->cil_code = ip++;
3965 target = ip + 1 + *(signed char*)ip;
3967 ADD_UNCOND (ins->opcode == CEE_BRTRUE);
3968 if (sp != stack_start) {
3969 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
3986 MONO_INST_NEW (cfg, ins, *ip + BIG_BRANCH_OFFSET);
3987 ins->cil_code = ip++;
3988 target = ip + 1 + *(signed char*)ip;
3991 if (sp != stack_start) {
3992 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
3999 MONO_INST_NEW (cfg, ins, CEE_BR);
4000 ins->cil_code = ip++;
4001 MONO_ADD_INS (bblock, ins);
4002 target = ip + 4 + (gint32)read32(ip);
4004 GET_BBLOCK (cfg, bbhash, tblock, target);
4005 link_bblock (cfg, bblock, tblock);
4006 CHECK_BBLOCK (target, ip, tblock);
4007 ins->inst_target_bb = tblock;
4008 if (sp != stack_start) {
4009 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
4012 start_new_bblock = 1;
4019 MONO_INST_NEW (cfg, ins, *ip);
4020 ins->cil_code = ip++;
4021 target = ip + 4 + (gint32)read32(ip);
4023 ADD_UNCOND(ins->opcode == CEE_BRTRUE);
4024 if (sp != stack_start) {
4025 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
4042 MONO_INST_NEW (cfg, ins, *ip);
4043 ins->cil_code = ip++;
4044 target = ip + 4 + (gint32)read32(ip);
4047 if (sp != stack_start) {
4048 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
4056 n = read32 (ip + 1);
4057 MONO_INST_NEW (cfg, ins, *ip);
4059 ins->inst_left = *sp;
4060 if (ins->inst_left->type != STACK_I4) goto unverified;
4063 CHECK_OPSIZE (n * sizeof (guint32));
4064 target = ip + n * sizeof (guint32);
4065 MONO_ADD_INS (bblock, ins);
4066 GET_BBLOCK (cfg, bbhash, tblock, target);
4067 link_bblock (cfg, bblock, tblock);
4068 ins->klass = GUINT_TO_POINTER (n);
4069 ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * (n + 1));
4070 ins->inst_many_bb [n] = tblock;
4072 for (i = 0; i < n; ++i) {
4073 GET_BBLOCK (cfg, bbhash, tblock, target + (gint32)read32(ip));
4074 link_bblock (cfg, bblock, tblock);
4075 ins->inst_many_bb [i] = tblock;
4078 if (sp != stack_start) {
4079 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
4082 /* Needed by the code generated in inssel.brg */
4083 mono_get_got_var (cfg);
4098 MONO_INST_NEW (cfg, ins, *ip);
4103 ins->type = ldind_type [*ip - CEE_LDIND_I1];
4104 ins->flags |= ins_flag;
4116 MONO_INST_NEW (cfg, ins, *ip);
4117 ins->cil_code = ip++;
4119 handle_loaded_temps (cfg, bblock, stack_start, sp);
4120 MONO_ADD_INS (bblock, ins);
4121 ins->inst_i0 = sp [0];
4122 ins->inst_i1 = sp [1];
4123 ins->flags |= ins_flag;
4142 /* special case that gives a nice speedup and happens to workaorund a ppc jit but (for the release)
4143 * later apply the speedup to the left shift as well
4146 if ((ins->opcode == OP_LSHR_UN) && (ins->type == STACK_I8)
4147 && (ins->inst_right->opcode == OP_ICONST) && (ins->inst_right->inst_c0 == 32)) {
4148 ins->opcode = OP_LONG_SHRUN_32;
4149 /*g_print ("applied long shr speedup to %s\n", cfg->method->name);*/
4153 if (mono_find_jit_opcode_emulation (ins->opcode)) {
4155 *sp++ = emit_tree (cfg, bblock, ins, ip + 1);
4169 case CEE_CONV_OVF_I8:
4170 case CEE_CONV_OVF_U8:
4174 if (mono_find_jit_opcode_emulation (ins->opcode)) {
4176 *sp++ = emit_tree (cfg, bblock, ins, ip + 1);
4180 case CEE_CONV_OVF_I4:
4181 case CEE_CONV_OVF_I1:
4182 case CEE_CONV_OVF_I2:
4183 case CEE_CONV_OVF_I:
4184 case CEE_CONV_OVF_U:
4187 if (sp [-1]->type == STACK_R8) {
4188 ADD_UNOP (CEE_CONV_OVF_I8);
4196 case CEE_CONV_OVF_U1:
4197 case CEE_CONV_OVF_U2:
4198 case CEE_CONV_OVF_U4:
4201 if (sp [-1]->type == STACK_R8) {
4202 ADD_UNOP (CEE_CONV_OVF_U8);
4210 case CEE_CONV_OVF_I1_UN:
4211 case CEE_CONV_OVF_I2_UN:
4212 case CEE_CONV_OVF_I4_UN:
4213 case CEE_CONV_OVF_I8_UN:
4214 case CEE_CONV_OVF_U1_UN:
4215 case CEE_CONV_OVF_U2_UN:
4216 case CEE_CONV_OVF_U4_UN:
4217 case CEE_CONV_OVF_U8_UN:
4218 case CEE_CONV_OVF_I_UN:
4219 case CEE_CONV_OVF_U_UN:
4227 token = read32 (ip + 1);
4228 if (method->wrapper_type != MONO_WRAPPER_NONE)
4229 klass = mono_method_get_wrapper_data (method, token);
4231 klass = mono_class_get_full (image, token, generic_context);
4233 mono_class_init (klass);
4235 if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
4236 MonoInst *store, *load;
4237 MONO_INST_NEW (cfg, load, CEE_LDIND_REF);
4238 load->cil_code = ip;
4239 load->inst_i0 = sp [1];
4240 load->type = STACK_OBJ;
4241 load->flags |= ins_flag;
4242 MONO_INST_NEW (cfg, store, CEE_STIND_REF);
4243 store->cil_code = ip;
4244 handle_loaded_temps (cfg, bblock, stack_start, sp);
4245 MONO_ADD_INS (bblock, store);
4246 store->inst_i0 = sp [0];
4247 store->inst_i1 = load;
4248 store->flags |= ins_flag;
4250 n = mono_class_value_size (klass, NULL);
4251 if ((cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 5) {
4253 MONO_INST_NEW (cfg, copy, OP_MEMCPY);
4254 copy->inst_left = sp [0];
4255 copy->inst_right = sp [1];
4256 copy->cil_code = ip;
4258 MONO_ADD_INS (bblock, copy);
4260 MonoInst *iargs [3];
4263 NEW_ICONST (cfg, iargs [2], n);
4264 iargs [2]->cil_code = ip;
4266 mono_emit_jit_icall (cfg, bblock, helper_memcpy, iargs, ip);
4273 MonoInst *iargs [3];
4279 token = read32 (ip + 1);
4280 if (method->wrapper_type != MONO_WRAPPER_NONE)
4281 klass = mono_method_get_wrapper_data (method, token);
4283 klass = mono_class_get_full (image, token, generic_context);
4285 mono_class_init (klass);
4286 if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
4287 MONO_INST_NEW (cfg, ins, CEE_LDIND_REF);
4289 ins->inst_i0 = sp [0];
4290 ins->type = STACK_OBJ;
4291 ins->flags |= ins_flag;
4298 /* Optimize the common ldobj+stloc combination */
4308 loc_index = ip [5] - CEE_STLOC_0;
4315 if ((loc_index != -1) && ip_in_bb (cfg, bblock, ip + 5)) {
4316 CHECK_LOCAL (loc_index);
4317 NEW_LOCSTORE (cfg, ins, loc_index, *sp);
4319 if (ins->opcode == CEE_STOBJ) {
4320 handle_loaded_temps (cfg, bblock, stack_start, sp);
4322 g_assert (ins->opcode == CEE_STOBJ);
4323 NEW_LOCLOADA (cfg, ins, loc_index);
4324 handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE);
4331 n = mono_class_value_size (klass, NULL);
4332 ins = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
4333 NEW_TEMPLOADA (cfg, iargs [0], ins->inst_c0);
4334 if ((cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 5) {
4336 MONO_INST_NEW (cfg, copy, OP_MEMCPY);
4337 copy->inst_left = iargs [0];
4338 copy->inst_right = *sp;
4339 copy->cil_code = ip;
4341 MONO_ADD_INS (bblock, copy);
4344 NEW_ICONST (cfg, iargs [2], n);
4345 iargs [2]->cil_code = ip;
4347 mono_emit_jit_icall (cfg, bblock, helper_memcpy, iargs, ip);
4349 NEW_TEMPLOAD (cfg, *sp, ins->inst_c0);
4357 CHECK_STACK_OVF (1);
4359 n = read32 (ip + 1);
4361 if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
4362 NEW_PCONST (cfg, ins, mono_method_get_wrapper_data (method, n));
4364 ins->type = STACK_OBJ;
4367 else if (method->wrapper_type != MONO_WRAPPER_NONE) {
4369 MonoInst *iargs [1];
4371 NEW_PCONST (cfg, iargs [0], mono_method_get_wrapper_data (method, n));
4372 temp = mono_emit_jit_icall (cfg, bblock, mono_string_new_wrapper, iargs, ip);
4373 NEW_TEMPLOAD (cfg, *sp, temp);
4377 if (cfg->opt & MONO_OPT_SHARED) {
4379 MonoInst *iargs [3];
4381 if (cfg->compile_aot) {
4382 cfg->ldstr_list = g_list_prepend (cfg->ldstr_list, GINT_TO_POINTER (n));
4385 NEW_TEMPLOAD (cfg, iargs [0], mono_get_domainvar (cfg)->inst_c0);
4386 NEW_IMAGECONST (cfg, iargs [1], image);
4387 NEW_ICONST (cfg, iargs [2], mono_metadata_token_index (n));
4388 temp = mono_emit_jit_icall (cfg, bblock, mono_ldstr, iargs, ip);
4389 NEW_TEMPLOAD (cfg, *sp, temp);
4390 mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
4392 if (cfg->compile_aot)
4393 NEW_LDSTRCONST (cfg, ins, image, n);
4395 NEW_PCONST (cfg, ins, NULL);
4397 ins->type = STACK_OBJ;
4398 ins->inst_p0 = mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
4408 MonoInst *iargs [2];
4409 MonoMethodSignature *fsig;
4413 token = read32 (ip + 1);
4414 if (method->wrapper_type != MONO_WRAPPER_NONE) {
4415 cmethod = mono_method_get_wrapper_data (method, token);
4417 cmethod = mini_get_method (image, token, NULL, generic_context);
4418 fsig = mono_method_get_signature (cmethod, image, token);
4420 mono_class_init (cmethod->klass);
4422 n = fsig->param_count;
4425 /* move the args to allow room for 'this' in the first position */
4431 handle_loaded_temps (cfg, bblock, stack_start, sp);
4434 if (cmethod->klass->parent == mono_defaults.array_class) {
4435 NEW_METHODCONST (cfg, *sp, cmethod);
4436 temp = handle_array_new (cfg, bblock, fsig->param_count, sp, ip);
4437 } else if (cmethod->string_ctor) {
4438 /* we simply pass a null pointer */
4439 NEW_PCONST (cfg, *sp, NULL);
4440 /* now call the string ctor */
4441 temp = mono_emit_method_call_spilled (cfg, bblock, cmethod, fsig, sp, ip, NULL);
4443 if (cmethod->klass->valuetype) {
4444 iargs [0] = mono_compile_create_var (cfg, &cmethod->klass->byval_arg, OP_LOCAL);
4445 temp = iargs [0]->inst_c0;
4446 NEW_TEMPLOADA (cfg, *sp, temp);
4448 temp = handle_alloc (cfg, bblock, cmethod->klass, ip);
4449 NEW_TEMPLOAD (cfg, *sp, temp);
4452 if ((cfg->opt & MONO_OPT_INLINE) && cmethod &&
4453 mono_method_check_inlining (cfg, cmethod) &&
4454 !mono_class_is_subclass_of (cmethod->klass, mono_defaults.exception_class, FALSE) &&
4455 !g_list_find (dont_inline, cmethod)) {
4457 MonoBasicBlock *ebblock;
4458 if ((costs = inline_method (cfg, cmethod, fsig, bblock, sp, ip, real_offset, dont_inline, &ebblock, FALSE))) {
4463 GET_BBLOCK (cfg, bbhash, bblock, ip);
4464 ebblock->next_bb = bblock;
4465 link_bblock (cfg, ebblock, bblock);
4467 NEW_TEMPLOAD (cfg, *sp, temp);
4470 /* indicates start of a new block, and triggers a load
4471 of all stack arguments at bb boundarie */
4474 inline_costs += costs;
4478 mono_emit_method_call_spilled (cfg, bblock, cmethod, fsig, sp, ip, sp[0]);
4481 /* now call the actual ctor */
4482 mono_emit_method_call_spilled (cfg, bblock, cmethod, fsig, sp, ip, sp[0]);
4486 NEW_TEMPLOAD (cfg, *sp, temp);
4497 token = read32 (ip + 1);
4498 if (method->wrapper_type != MONO_WRAPPER_NONE)
4499 klass = mono_method_get_wrapper_data (method, token);
4501 klass = mono_class_get_full (image, token, generic_context);
4502 mono_class_init (klass);
4504 /* Needed by the code generated in inssel.brg */
4505 mono_get_got_var (cfg);
4507 if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4509 MonoMethod *mono_isinst;
4510 MonoInst *iargs [1];
4511 MonoBasicBlock *ebblock;
4515 mono_isinst = mono_marshal_get_isinst (klass);
4518 costs = inline_method (cfg, mono_isinst, mono_isinst->signature, bblock,
4519 iargs, ip, real_offset, dont_inline, &ebblock, TRUE);
4521 g_assert (costs > 0);
4526 GET_BBLOCK (cfg, bbhash, bblock, ip);
4527 ebblock->next_bb = bblock;
4528 link_bblock (cfg, ebblock, bblock);
4530 temp = iargs [0]->inst_i0->inst_c0;
4531 NEW_TEMPLOAD (cfg, *sp, temp);
4535 inline_costs += costs;
4539 MONO_INST_NEW (cfg, ins, *ip);
4540 ins->type = STACK_OBJ;
4541 ins->inst_left = *sp;
4542 ins->inst_newa_class = klass;
4544 *sp++ = emit_tree (cfg, bblock, ins, ip + 5);
4548 case CEE_UNBOX_ANY: {
4549 MonoInst *add, *vtoffset;
4550 MonoInst *iargs [3];
4555 token = read32 (ip + 1);
4556 if (method->wrapper_type != MONO_WRAPPER_NONE)
4557 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
4559 klass = mono_class_get_full (image, token, generic_context);
4560 mono_class_init (klass);
4562 if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
4564 if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4565 MonoMethod *mono_castclass;
4566 MonoInst *iargs [1];
4567 MonoBasicBlock *ebblock;
4571 mono_castclass = mono_marshal_get_castclass (klass);
4574 costs = inline_method (cfg, mono_castclass, mono_castclass->signature, bblock,
4575 iargs, ip, real_offset, dont_inline, &ebblock, TRUE);
4577 g_assert (costs > 0);
4582 GET_BBLOCK (cfg, bbhash, bblock, ip);
4583 ebblock->next_bb = bblock;
4584 link_bblock (cfg, ebblock, bblock);
4586 temp = iargs [0]->inst_i0->inst_c0;
4587 NEW_TEMPLOAD (cfg, *sp, temp);
4591 inline_costs += costs;
4594 MONO_INST_NEW (cfg, ins, CEE_CASTCLASS);
4595 ins->type = STACK_OBJ;
4596 ins->inst_left = *sp;
4598 ins->inst_newa_class = klass;
4606 MONO_INST_NEW (cfg, ins, OP_UNBOXCAST);
4607 ins->type = STACK_OBJ;
4608 ins->inst_left = *sp;
4610 ins->inst_newa_class = klass;
4613 MONO_INST_NEW (cfg, add, OP_PADD);
4614 NEW_ICONST (cfg, vtoffset, sizeof (MonoObject));
4615 add->inst_left = ins;
4616 add->inst_right = vtoffset;
4617 add->type = STACK_MP;
4621 n = mono_class_value_size (klass, NULL);
4622 ins = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
4623 NEW_TEMPLOADA (cfg, iargs [0], ins->inst_c0);
4624 if ((cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 5) {
4626 MONO_INST_NEW (cfg, copy, OP_MEMCPY);
4627 copy->inst_left = iargs [0];
4628 copy->inst_right = *sp;
4629 copy->cil_code = ip;
4631 MONO_ADD_INS (bblock, copy);
4634 NEW_ICONST (cfg, iargs [2], n);
4635 iargs [2]->cil_code = ip;
4637 mono_emit_jit_icall (cfg, bblock, helper_memcpy, iargs, ip);
4639 NEW_TEMPLOAD (cfg, *sp, ins->inst_c0);
4645 MonoInst *add, *vtoffset;
4650 token = read32 (ip + 1);
4651 if (method->wrapper_type != MONO_WRAPPER_NONE)
4652 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
4654 klass = mono_class_get_full (image, token, generic_context);
4655 mono_class_init (klass);
4657 /* Needed by the code generated in inssel.brg */
4658 mono_get_got_var (cfg);
4660 MONO_INST_NEW (cfg, ins, OP_UNBOXCAST);
4661 ins->type = STACK_OBJ;
4662 ins->inst_left = *sp;
4664 ins->inst_newa_class = klass;
4667 MONO_INST_NEW (cfg, add, OP_PADD);
4668 NEW_ICONST (cfg, vtoffset, sizeof (MonoObject));
4669 add->inst_left = ins;
4670 add->inst_right = vtoffset;
4671 add->type = STACK_MP;
4681 token = read32 (ip + 1);
4682 if (method->wrapper_type != MONO_WRAPPER_NONE)
4683 klass = mono_method_get_wrapper_data (method, token);
4685 klass = mono_class_get_full (image, token, generic_context);
4686 mono_class_init (klass);
4688 /* Needed by the code generated in inssel.brg */
4689 mono_get_got_var (cfg);
4691 if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4693 MonoMethod *mono_castclass;
4694 MonoInst *iargs [1];
4695 MonoBasicBlock *ebblock;
4699 mono_castclass = mono_marshal_get_castclass (klass);
4702 costs = inline_method (cfg, mono_castclass, mono_castclass->signature, bblock,
4703 iargs, ip, real_offset, dont_inline, &ebblock, TRUE);
4705 g_assert (costs > 0);
4710 GET_BBLOCK (cfg, bbhash, bblock, ip);
4711 ebblock->next_bb = bblock;
4712 link_bblock (cfg, ebblock, bblock);
4714 temp = iargs [0]->inst_i0->inst_c0;
4715 NEW_TEMPLOAD (cfg, *sp, temp);
4719 inline_costs += costs;
4722 MONO_INST_NEW (cfg, ins, *ip);
4723 ins->type = STACK_OBJ;
4724 ins->inst_left = *sp;
4726 ins->inst_newa_class = klass;
4728 *sp++ = emit_tree (cfg, bblock, ins, ip + 5);
4734 MONO_INST_NEW (cfg, ins, *ip);
4736 ins->inst_left = *sp;
4737 ins->cil_code = ip++;
4738 bblock->out_of_line = TRUE;
4739 MONO_ADD_INS (bblock, ins);
4741 link_bblock (cfg, bblock, end_bblock);
4742 start_new_bblock = 1;
4747 MonoInst *offset_ins;
4748 MonoClassField *field;
4749 MonoBasicBlock *ebblock;
4753 if (*ip == CEE_STFLD) {
4760 // FIXME: enable this test later.
4761 //if (sp [0]->type != STACK_OBJ && sp [0]->type != STACK_MP)
4764 token = read32 (ip + 1);
4765 field = mono_field_from_token (image, token, &klass, generic_context);
4766 mono_class_init (klass);
4768 foffset = klass->valuetype? field->offset - sizeof (MonoObject): field->offset;
4769 /* FIXME: mark instructions for use in SSA */
4770 if (*ip == CEE_STFLD) {
4771 if ((klass->marshalbyref && !MONO_CHECK_THIS (sp [0])) || klass->contextbound || klass == mono_defaults.marshalbyrefobject_class) {
4772 MonoMethod *stfld_wrapper = mono_marshal_get_stfld_wrapper (field->type);
4773 MonoInst *iargs [5];
4776 NEW_CLASSCONST (cfg, iargs [1], klass);
4777 NEW_FIELDCONST (cfg, iargs [2], field);
4778 NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) :
4782 if (cfg->opt & MONO_OPT_INLINE) {
4783 costs = inline_method (cfg, stfld_wrapper, stfld_wrapper->signature, bblock,
4784 iargs, ip, real_offset, dont_inline, &ebblock, TRUE);
4785 g_assert (costs > 0);
4790 GET_BBLOCK (cfg, bbhash, bblock, ip);
4791 ebblock->next_bb = bblock;
4792 link_bblock (cfg, ebblock, bblock);
4794 /* indicates start of a new block, and triggers a load
4795 of all stack arguments at bb boundarie */
4798 inline_costs += costs;
4801 mono_emit_method_call_spilled (cfg, bblock, stfld_wrapper, stfld_wrapper->signature, iargs, ip, NULL);
4805 NEW_ICONST (cfg, offset_ins, foffset);
4806 MONO_INST_NEW (cfg, ins, OP_PADD);
4808 ins->inst_left = *sp;
4809 ins->inst_right = offset_ins;
4810 ins->type = STACK_MP;
4812 MONO_INST_NEW (cfg, store, mono_type_to_stind (field->type));
4813 store->cil_code = ip;
4814 store->inst_left = ins;
4815 store->inst_right = sp [1];
4816 handle_loaded_temps (cfg, bblock, stack_start, sp);
4817 store->flags |= ins_flag;
4819 if (store->opcode == CEE_STOBJ) {
4820 handle_stobj (cfg, bblock, ins, sp [1], ip,
4821 mono_class_from_mono_type (field->type), FALSE, FALSE);
4823 MONO_ADD_INS (bblock, store);
4826 if ((klass->marshalbyref && !MONO_CHECK_THIS (sp [0])) || klass->contextbound || klass == mono_defaults.marshalbyrefobject_class) {
4827 /* fixme: we need to inline that call somehow */
4828 MonoMethod *ldfld_wrapper = mono_marshal_get_ldfld_wrapper (field->type);
4829 MonoInst *iargs [4];
4833 NEW_CLASSCONST (cfg, iargs [1], klass);
4834 NEW_FIELDCONST (cfg, iargs [2], field);
4835 NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : field->offset);
4836 if (cfg->opt & MONO_OPT_INLINE) {
4837 costs = inline_method (cfg, ldfld_wrapper, ldfld_wrapper->signature, bblock,
4838 iargs, ip, real_offset, dont_inline, &ebblock, TRUE);
4839 g_assert (costs > 0);
4844 GET_BBLOCK (cfg, bbhash, bblock, ip);
4845 ebblock->next_bb = bblock;
4846 link_bblock (cfg, ebblock, bblock);
4848 temp = iargs [0]->inst_i0->inst_c0;
4850 if (*ip == CEE_LDFLDA) {
4851 /* not sure howto handle this */
4852 NEW_TEMPLOADA (cfg, *sp, temp);
4854 NEW_TEMPLOAD (cfg, *sp, temp);
4858 /* indicates start of a new block, and triggers a load of
4859 all stack arguments at bb boundarie */
4862 inline_costs += costs;
4865 temp = mono_emit_method_call_spilled (cfg, bblock, ldfld_wrapper, ldfld_wrapper->signature, iargs, ip, NULL);
4866 if (*ip == CEE_LDFLDA) {
4867 /* not sure howto handle this */
4868 NEW_TEMPLOADA (cfg, *sp, temp);
4870 NEW_TEMPLOAD (cfg, *sp, temp);
4875 NEW_ICONST (cfg, offset_ins, foffset);
4876 MONO_INST_NEW (cfg, ins, OP_PADD);
4878 ins->inst_left = *sp;
4879 ins->inst_right = offset_ins;
4880 ins->type = STACK_MP;
4882 if (*ip == CEE_LDFLDA) {
4886 MONO_INST_NEW (cfg, load, mono_type_to_ldind (field->type));
4887 type_to_eval_stack_type (field->type, load);
4888 load->cil_code = ip;
4889 load->inst_left = ins;
4890 load->flags |= ins_flag;
4902 MonoClassField *field;
4903 gpointer addr = NULL;
4906 token = read32 (ip + 1);
4908 field = mono_field_from_token (image, token, &klass, generic_context);
4909 mono_class_init (klass);
4911 if ((*ip) == CEE_STSFLD)
4912 handle_loaded_temps (cfg, bblock, stack_start, sp);
4914 /* The special_static_fields field is init'd in mono_class_vtable, so it needs
4915 * to be called here.
4917 if (!(cfg->opt & MONO_OPT_SHARED))
4918 mono_class_vtable (cfg->domain, klass);
4920 if (cfg->domain->special_static_fields)
4921 addr = g_hash_table_lookup (cfg->domain->special_static_fields, field);
4923 if ((cfg->opt & MONO_OPT_SHARED) || (cfg->compile_aot && addr)) {
4925 MonoInst *iargs [2];
4926 g_assert (field->parent);
4927 NEW_TEMPLOAD (cfg, iargs [0], mono_get_domainvar (cfg)->inst_c0);
4928 NEW_FIELDCONST (cfg, iargs [1], field);
4929 temp = mono_emit_jit_icall (cfg, bblock, mono_class_static_field_address, iargs, ip);
4930 NEW_TEMPLOAD (cfg, ins, temp);
4933 vtable = mono_class_vtable (cfg->domain, klass);
4935 if ((!vtable->initialized || cfg->compile_aot) && !(klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) && mono_class_needs_cctor_run (klass, method)) {
4936 guint8 *tramp = mono_create_class_init_trampoline (vtable);
4937 mono_emit_native_call (cfg, bblock, tramp,
4938 helper_sig_class_init_trampoline,
4939 NULL, ip, FALSE, FALSE);
4940 if (cfg->verbose_level > 2)
4941 g_print ("class %s.%s needs init call for %s\n", klass->name_space, klass->name, field->name);
4943 if (cfg->run_cctors)
4944 mono_runtime_class_init (vtable);
4946 addr = (char*)vtable->data + field->offset;
4948 if (cfg->compile_aot)
4949 NEW_SFLDACONST (cfg, ins, field);
4951 NEW_PCONST (cfg, ins, addr);
4955 * insert call to mono_threads_get_static_data (GPOINTER_TO_UINT (addr))
4956 * This could be later optimized to do just a couple of
4957 * memory dereferences with constant offsets.
4960 MonoInst *iargs [1];
4961 NEW_ICONST (cfg, iargs [0], GPOINTER_TO_UINT (addr));
4962 temp = mono_emit_jit_icall (cfg, bblock, mono_get_special_static_data, iargs, ip);
4963 NEW_TEMPLOAD (cfg, ins, temp);
4967 /* FIXME: mark instructions for use in SSA */
4968 if (*ip == CEE_LDSFLDA) {
4970 } else if (*ip == CEE_STSFLD) {
4974 MONO_INST_NEW (cfg, store, mono_type_to_stind (field->type));
4975 store->cil_code = ip;
4976 store->inst_left = ins;
4977 store->inst_right = sp [0];
4978 store->flags |= ins_flag;
4981 if (store->opcode == CEE_STOBJ) {
4982 handle_stobj (cfg, bblock, ins, sp [0], ip, mono_class_from_mono_type (field->type), FALSE, FALSE);
4984 MONO_ADD_INS (bblock, store);
4986 gboolean is_const = FALSE;
4987 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
4988 if (!((cfg->opt & MONO_OPT_SHARED) || cfg->compile_aot) &&
4989 vtable->initialized && (field->type->attrs & FIELD_ATTRIBUTE_INIT_ONLY)) {
4990 gpointer addr = (char*)vtable->data + field->offset;
4991 /* g_print ("RO-FIELD %s.%s:%s\n", klass->name_space, klass->name, field->name);*/
4993 switch (field->type->type) {
4994 case MONO_TYPE_BOOLEAN:
4996 NEW_ICONST (cfg, *sp, *((guint8 *)addr));
5000 NEW_ICONST (cfg, *sp, *((gint8 *)addr));
5003 case MONO_TYPE_CHAR:
5005 NEW_ICONST (cfg, *sp, *((guint16 *)addr));
5009 NEW_ICONST (cfg, *sp, *((gint16 *)addr));
5014 NEW_ICONST (cfg, *sp, *((gint32 *)addr));
5018 NEW_ICONST (cfg, *sp, *((guint32 *)addr));
5023 case MONO_TYPE_STRING:
5024 case MONO_TYPE_OBJECT:
5025 case MONO_TYPE_CLASS:
5026 case MONO_TYPE_SZARRAY:
5028 case MONO_TYPE_FNPTR:
5029 case MONO_TYPE_ARRAY:
5030 NEW_PCONST (cfg, *sp, *((gpointer *)addr));
5031 type_to_eval_stack_type (field->type, *sp);
5036 MONO_INST_NEW (cfg, *sp, OP_I8CONST);
5037 sp [0]->type = STACK_I8;
5038 sp [0]->inst_l = *((gint64 *)addr);
5043 case MONO_TYPE_VALUETYPE:
5052 CHECK_STACK_OVF (1);
5053 MONO_INST_NEW (cfg, load, mono_type_to_ldind (field->type));
5054 type_to_eval_stack_type (field->type, load);
5055 load->cil_code = ip;
5056 load->inst_left = ins;
5058 load->flags |= ins_flag;
5060 /* fixme: dont see the problem why this does not work */
5061 //cfg->disable_aot = TRUE;
5071 token = read32 (ip + 1);
5072 if (method->wrapper_type != MONO_WRAPPER_NONE)
5073 klass = mono_method_get_wrapper_data (method, token);
5075 klass = mono_class_get_full (image, token, generic_context);
5076 mono_class_init (klass);
5077 n = mono_type_to_stind (&klass->byval_arg);
5078 if (n == CEE_STOBJ) {
5079 handle_stobj (cfg, bblock, sp [0], sp [1], ip, klass, FALSE, FALSE);
5081 /* FIXME: should check item at sp [1] is compatible with the type of the store. */
5083 MONO_INST_NEW (cfg, store, n);
5084 store->cil_code = ip;
5085 store->inst_left = sp [0];
5086 store->inst_right = sp [1];
5087 store->flags |= ins_flag;
5088 MONO_ADD_INS (bblock, store);
5100 token = read32 (ip + 1);
5101 if (method->wrapper_type != MONO_WRAPPER_NONE)
5102 klass = mono_method_get_wrapper_data (method, token);
5104 klass = mono_class_get_full (image, token, generic_context);
5105 mono_class_init (klass);
5107 if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
5112 *sp++ = handle_box (cfg, bblock, val, ip, klass);
5119 MONO_INST_NEW (cfg, ins, *ip);
5124 token = read32 (ip + 1);
5126 /* allocate the domainvar - becaus this is used in decompose_foreach */
5127 if (cfg->opt & MONO_OPT_SHARED) {
5128 mono_get_domainvar (cfg);
5129 /* LAME-IR: Mark it as used since otherwise it will be optimized away */
5130 cfg->domainvar->flags |= MONO_INST_VOLATILE;
5134 mono_get_got_var (cfg);
5136 if (method->wrapper_type != MONO_WRAPPER_NONE)
5137 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
5139 klass = mono_class_get_full (image, token, generic_context);
5141 mono_class_init (klass);
5142 ins->inst_newa_class = klass;
5143 ins->inst_newa_len = *sp;
5144 ins->type = STACK_OBJ;
5148 * we store the object so calls to create the array are not interleaved
5149 * with the arguments of other calls.
5152 MonoInst *store, *temp, *load;
5154 temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
5155 NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
5156 store->cil_code = ins->cil_code;
5157 MONO_ADD_INS (bblock, store);
5158 NEW_TEMPLOAD (cfg, load, temp->inst_c0);
5159 load->cil_code = ins->cil_code;
5166 MONO_INST_NEW (cfg, ins, *ip);
5167 ins->cil_code = ip++;
5169 ins->inst_left = *sp;
5170 ins->type = STACK_PTR;
5178 if (method->wrapper_type != MONO_WRAPPER_NONE)
5179 klass = (MonoClass*)mono_method_get_wrapper_data (method, read32 (ip + 1));
5181 klass = mono_class_get_full (image, read32 (ip + 1), generic_context);
5183 /* we need to make sure that this array is exactly the type it needs
5184 * to be for correctness. the wrappers are lax with their usage
5185 * so we need to ignore them here
5187 if (!klass->valuetype && method->wrapper_type == MONO_WRAPPER_NONE) {
5189 MONO_INST_NEW (cfg, check, OP_CHECK_ARRAY_TYPE);
5190 check->cil_code = ip;
5191 check->klass = klass;
5192 check->inst_left = sp [0];
5193 check->type = STACK_OBJ;
5197 mono_class_init (klass);
5198 NEW_LDELEMA (cfg, ins, sp, klass);
5203 case CEE_LDELEM_ANY: {
5208 token = read32 (ip + 1);
5209 klass = mono_class_get_full (image, token, generic_context);
5210 mono_class_init (klass);
5211 NEW_LDELEMA (cfg, load, sp, klass);
5212 load->cil_code = ip;
5213 MONO_INST_NEW (cfg, ins, mono_type_to_ldind (&klass->byval_arg));
5215 ins->inst_left = load;
5217 type_to_eval_stack_type (&klass->byval_arg, ins);
5231 case CEE_LDELEM_REF: {
5235 * ldind.x (ldelema (array, index))
5236 * ldelema does the bounds check
5240 klass = array_access_to_klass (*ip);
5241 NEW_LDELEMA (cfg, load, sp, klass);
5242 load->cil_code = ip;
5243 MONO_INST_NEW (cfg, ins, ldelem_to_ldind [*ip - CEE_LDELEM_I1]);
5245 ins->inst_left = load;
5247 ins->type = ldind_type [ins->opcode - CEE_LDIND_I1];
5257 case CEE_STELEM_R8: {
5261 * stind.x (ldelema (array, index), val)
5262 * ldelema does the bounds check
5266 klass = array_access_to_klass (*ip);
5267 NEW_LDELEMA (cfg, load, sp, klass);
5268 load->cil_code = ip;
5269 MONO_INST_NEW (cfg, ins, stelem_to_stind [*ip - CEE_STELEM_I]);
5271 ins->inst_left = load;
5272 ins->inst_right = sp [2];
5274 handle_loaded_temps (cfg, bblock, stack_start, sp);
5275 MONO_ADD_INS (bblock, ins);
5279 case CEE_STELEM_ANY: {
5283 * stind.x (ldelema (array, index), val)
5284 * ldelema does the bounds check
5289 token = read32 (ip + 1);
5290 klass = mono_class_get_full (image, token, generic_context);
5291 mono_class_init (klass);
5292 if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
5293 MonoMethod* helper = mono_marshal_get_stelemref ();
5294 MonoInst *iargs [3];
5295 handle_loaded_temps (cfg, bblock, stack_start, sp);
5301 mono_emit_method_call_spilled (cfg, bblock, helper, helper->signature, iargs, ip, NULL);
5303 NEW_LDELEMA (cfg, load, sp, klass);
5304 load->cil_code = ip;
5306 n = mono_type_to_stind (&klass->byval_arg);
5308 handle_stobj (cfg, bblock, load, sp [2], ip, klass, FALSE, FALSE);
5310 MONO_INST_NEW (cfg, ins, n);
5312 ins->inst_left = load;
5313 ins->inst_right = sp [2];
5314 handle_loaded_temps (cfg, bblock, stack_start, sp);
5315 MONO_ADD_INS (bblock, ins);
5322 case CEE_STELEM_REF: {
5323 MonoInst *iargs [3];
5324 MonoMethod* helper = mono_marshal_get_stelemref ();
5329 handle_loaded_temps (cfg, bblock, stack_start, sp);
5335 mono_emit_method_call_spilled (cfg, bblock, helper, helper->signature, iargs, ip, NULL);
5339 NEW_GROUP (cfg, group, sp [0], sp [1]);
5340 MONO_INST_NEW (cfg, ins, CEE_STELEM_REF);
5342 ins->inst_left = group;
5343 ins->inst_right = sp [2];
5344 MONO_ADD_INS (bblock, ins);
5351 case CEE_CKFINITE: {
5352 MonoInst *store, *temp;
5355 /* this instr. can throw exceptions as side effect,
5356 * so we cant eliminate dead code which contains CKFINITE opdodes.
5357 * Spilling to memory makes sure that we always perform
5361 MONO_INST_NEW (cfg, ins, CEE_CKFINITE);
5363 ins->inst_left = sp [-1];
5364 temp = mono_compile_create_var (cfg, &mono_defaults.double_class->byval_arg, OP_LOCAL);
5366 NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
5367 store->cil_code = ip;
5368 MONO_ADD_INS (bblock, store);
5370 NEW_TEMPLOAD (cfg, sp [-1], temp->inst_c0);
5377 MONO_INST_NEW (cfg, ins, *ip);
5380 klass = mono_class_get_full (image, read32 (ip + 1), generic_context);
5381 mono_class_init (klass);
5382 ins->type = STACK_MP;
5383 ins->inst_left = *sp;
5385 ins->inst_newa_class = klass;
5390 case CEE_MKREFANY: {
5391 MonoInst *loc, *klassconst;
5394 MONO_INST_NEW (cfg, ins, *ip);
5397 klass = mono_class_get_full (image, read32 (ip + 1), generic_context);
5398 mono_class_init (klass);
5401 loc = mono_compile_create_var (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL);
5402 NEW_TEMPLOADA (cfg, ins->inst_right, loc->inst_c0);
5404 NEW_PCONST (cfg, klassconst, klass);
5405 NEW_GROUP (cfg, ins->inst_left, *sp, klassconst);
5407 MONO_ADD_INS (bblock, ins);
5409 NEW_TEMPLOAD (cfg, *sp, loc->inst_c0);
5416 MonoClass *handle_class;
5418 CHECK_STACK_OVF (1);
5421 n = read32 (ip + 1);
5423 handle = mono_ldtoken (image, n, &handle_class, generic_context);
5424 mono_class_init (handle_class);
5426 if (cfg->opt & MONO_OPT_SHARED) {
5428 MonoInst *res, *store, *addr, *vtvar, *iargs [3];
5430 vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL);
5432 NEW_IMAGECONST (cfg, iargs [0], image);
5433 NEW_ICONST (cfg, iargs [1], n);
5434 NEW_PCONST (cfg, iargs [2], generic_context);
5435 temp = mono_emit_jit_icall (cfg, bblock, mono_ldtoken_wrapper, iargs, ip);
5436 NEW_TEMPLOAD (cfg, res, temp);
5437 NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
5438 NEW_INDSTORE (cfg, store, addr, res, &mono_defaults.int_class->byval_arg);
5439 MONO_ADD_INS (bblock, store);
5440 NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
5442 if ((ip [5] == CEE_CALL) && (cmethod = mini_get_method (image, read32 (ip + 6), NULL, generic_context)) &&
5443 (cmethod->klass == mono_defaults.monotype_class->parent) &&
5444 (strcmp (cmethod->name, "GetTypeFromHandle") == 0) && ip_in_bb (cfg, bblock, ip + 5)) {
5445 MonoClass *tclass = mono_class_from_mono_type (handle);
5446 mono_class_init (tclass);
5447 if (cfg->compile_aot)
5448 NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, image, n);
5450 NEW_PCONST (cfg, ins, mono_type_get_object (cfg->domain, handle));
5451 ins->type = STACK_OBJ;
5452 ins->klass = cmethod->klass;
5455 MonoInst *store, *addr, *vtvar;
5457 if (cfg->compile_aot)
5458 NEW_LDTOKENCONST (cfg, ins, image, n);
5460 NEW_PCONST (cfg, ins, handle);
5461 vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL);
5462 NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
5463 NEW_INDSTORE (cfg, store, addr, ins, &mono_defaults.int_class->byval_arg);
5464 MONO_ADD_INS (bblock, store);
5465 NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
5481 case CEE_ADD_OVF_UN:
5483 case CEE_MUL_OVF_UN:
5485 case CEE_SUB_OVF_UN:
5488 if (mono_find_jit_opcode_emulation (ins->opcode)) {
5490 *sp++ = emit_tree (cfg, bblock, ins, ip + 1);
5494 case CEE_ENDFINALLY:
5495 MONO_INST_NEW (cfg, ins, *ip);
5496 MONO_ADD_INS (bblock, ins);
5497 ins->cil_code = ip++;
5498 start_new_bblock = 1;
5501 * Control will leave the method so empty the stack, otherwise
5502 * the next basic block will start with a nonempty stack.
5504 while (sp != stack_start) {
5505 MONO_INST_NEW (cfg, ins, CEE_POP);
5509 MONO_ADD_INS (bblock, ins);
5515 if (*ip == CEE_LEAVE) {
5517 target = ip + 5 + (gint32)read32(ip + 1);
5520 target = ip + 2 + (signed char)(ip [1]);
5523 /* empty the stack */
5524 while (sp != stack_start) {
5525 MONO_INST_NEW (cfg, ins, CEE_POP);
5529 MONO_ADD_INS (bblock, ins);
5533 * If this leave statement is in a catch block, check for a
5534 * pending exception, and rethrow it if necessary.
5536 for (i = 0; i < header->num_clauses; ++i) {
5537 MonoExceptionClause *clause = &header->clauses [i];
5538 if (MONO_OFFSET_IN_HANDLER (clause, ip - header->code)) {
5541 temp = mono_emit_jit_icall (cfg, bblock, mono_thread_get_pending_exception, NULL, ip);
5542 NEW_TEMPLOAD (cfg, *sp, temp);
5544 MONO_INST_NEW (cfg, ins, OP_THROW_OR_NULL);
5545 ins->inst_left = *sp;
5547 MONO_ADD_INS (bblock, ins);
5551 /* fixme: call fault handler ? */
5553 if ((handlers = mono_find_final_block (cfg, ip, target, MONO_EXCEPTION_CLAUSE_FINALLY))) {
5555 for (tmp = handlers; tmp; tmp = tmp->next) {
5557 link_bblock (cfg, bblock, tblock);
5558 MONO_INST_NEW (cfg, ins, OP_CALL_HANDLER);
5560 ins->inst_target_bb = tblock;
5561 MONO_ADD_INS (bblock, ins);
5563 g_list_free (handlers);
5566 MONO_INST_NEW (cfg, ins, CEE_BR);
5568 MONO_ADD_INS (bblock, ins);
5569 GET_BBLOCK (cfg, bbhash, tblock, target);
5570 link_bblock (cfg, bblock, tblock);
5571 CHECK_BBLOCK (target, ip, tblock);
5572 ins->inst_target_bb = tblock;
5573 start_new_bblock = 1;
5575 if (*ip == CEE_LEAVE)
5584 MONO_INST_NEW (cfg, ins, *ip);
5586 handle_loaded_temps (cfg, bblock, stack_start, sp);
5587 MONO_ADD_INS (bblock, ins);
5588 ins->cil_code = ip++;
5589 ins->inst_i0 = sp [0];
5590 ins->inst_i1 = sp [1];
5598 /* trampoline mono specific opcodes */
5599 case MONO_CUSTOM_PREFIX: {
5601 g_assert (method->wrapper_type != MONO_WRAPPER_NONE);
5606 case CEE_MONO_ICALL: {
5609 MonoJitICallInfo *info;
5611 token = read32 (ip + 2);
5612 func = mono_method_get_wrapper_data (method, token);
5613 info = mono_find_jit_icall_by_addr (func);
5616 CHECK_STACK (info->sig->param_count);
5617 sp -= info->sig->param_count;
5619 temp = mono_emit_jit_icall (cfg, bblock, info->func, sp, ip);
5620 if (!MONO_TYPE_IS_VOID (info->sig->ret)) {
5621 NEW_TEMPLOAD (cfg, *sp, temp);
5626 inline_costs += 10 * num_calls++;
5630 case CEE_MONO_LDPTR:
5631 CHECK_STACK_OVF (1);
5633 token = read32 (ip + 2);
5634 NEW_PCONST (cfg, ins, mono_method_get_wrapper_data (method, token));
5638 inline_costs += 10 * num_calls++;
5639 /* Can't embed random pointers into AOT code */
5640 cfg->disable_aot = 1;
5642 case CEE_MONO_VTADDR:
5645 MONO_INST_NEW (cfg, ins, OP_VTADDR);
5647 ins->type = STACK_MP;
5648 ins->inst_left = *sp;
5652 case CEE_MONO_NEWOBJ: {
5653 MonoInst *iargs [2];
5655 CHECK_STACK_OVF (1);
5657 token = read32 (ip + 2);
5658 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
5659 mono_class_init (klass);
5660 NEW_DOMAINCONST (cfg, iargs [0]);
5661 NEW_CLASSCONST (cfg, iargs [1], klass);
5662 temp = mono_emit_jit_icall (cfg, bblock, mono_object_new, iargs, ip);
5663 NEW_TEMPLOAD (cfg, *sp, temp);
5666 inline_costs += 10 * num_calls++;
5669 case CEE_MONO_OBJADDR:
5672 MONO_INST_NEW (cfg, ins, OP_OBJADDR);
5674 ins->type = STACK_MP;
5675 ins->inst_left = *sp;
5679 case CEE_MONO_LDNATIVEOBJ:
5682 token = read32 (ip + 2);
5683 klass = mono_method_get_wrapper_data (method, token);
5684 g_assert (klass->valuetype);
5685 mono_class_init (klass);
5686 NEW_INDLOAD (cfg, ins, sp [-1], &klass->byval_arg);
5690 case CEE_MONO_RETOBJ:
5691 g_assert (cfg->ret);
5692 g_assert (method->signature->pinvoke);
5697 token = read32 (ip + 2);
5698 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
5700 NEW_RETLOADA (cfg, ins);
5701 handle_stobj (cfg, bblock, ins, *sp, ip, klass, FALSE, TRUE);
5703 if (sp != stack_start)
5706 MONO_INST_NEW (cfg, ins, CEE_BR);
5708 ins->inst_target_bb = end_bblock;
5709 MONO_ADD_INS (bblock, ins);
5710 link_bblock (cfg, bblock, end_bblock);
5711 start_new_bblock = 1;
5714 case CEE_MONO_CISINST:
5715 case CEE_MONO_CCASTCLASS: {
5720 token = read32 (ip + 2);
5721 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
5722 MONO_INST_NEW (cfg, ins, (ip [1] == CEE_MONO_CISINST) ? OP_CISINST : OP_CCASTCLASS);
5723 ins->type = STACK_I4;
5724 ins->inst_left = *sp;
5725 ins->inst_newa_class = klass;
5727 *sp++ = emit_tree (cfg, bblock, ins, ip + 6);
5731 case CEE_MONO_SAVE_LMF:
5732 case CEE_MONO_RESTORE_LMF:
5733 #ifdef MONO_ARCH_HAVE_LMF_OPS
5734 MONO_INST_NEW (cfg, ins, (ip [1] == CEE_MONO_SAVE_LMF) ? OP_SAVE_LMF : OP_RESTORE_LMF);
5735 MONO_ADD_INS (bblock, ins);
5736 cfg->need_lmf_area = TRUE;
5740 case CEE_MONO_CLASSCONST:
5741 CHECK_STACK_OVF (1);
5743 token = read32 (ip + 2);
5744 NEW_CLASSCONST (cfg, ins, mono_method_get_wrapper_data (method, token));
5748 inline_costs += 10 * num_calls++;
5751 g_error ("opcode 0x%02x 0x%02x not handled", MONO_CUSTOM_PREFIX, ip [1]);
5760 /* somewhat similar to LDTOKEN */
5761 MonoInst *addr, *vtvar;
5762 CHECK_STACK_OVF (1);
5763 vtvar = mono_compile_create_var (cfg, &mono_defaults.argumenthandle_class->byval_arg, OP_LOCAL);
5765 NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
5766 addr->cil_code = ip;
5767 MONO_INST_NEW (cfg, ins, OP_ARGLIST);
5769 ins->inst_left = addr;
5770 MONO_ADD_INS (bblock, ins);
5771 NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
5785 * The following transforms:
5786 * CEE_CEQ into OP_CEQ
5787 * CEE_CGT into OP_CGT
5788 * CEE_CGT_UN into OP_CGT_UN
5789 * CEE_CLT into OP_CLT
5790 * CEE_CLT_UN into OP_CLT_UN
5792 MONO_INST_NEW (cfg, cmp, 256 + ip [1]);
5794 MONO_INST_NEW (cfg, ins, cmp->opcode);
5796 cmp->inst_i0 = sp [0];
5797 cmp->inst_i1 = sp [1];
5801 if ((sp [0]->type == STACK_I8) || ((sizeof (gpointer) == 8) && ((sp [0]->type == STACK_PTR) || (sp [0]->type == STACK_OBJ) || (sp [0]->type == STACK_MP))))
5802 cmp->opcode = OP_LCOMPARE;
5804 cmp->opcode = OP_COMPARE;
5806 ins->type = STACK_I4;
5809 /* spill it to reduce the expression complexity
5810 * and workaround bug 54209
5812 if (cmp->inst_left->type == STACK_I8) {
5814 *sp++ = emit_tree (cfg, bblock, ins, ip + 2);
5823 CHECK_STACK_OVF (1);
5825 n = read32 (ip + 2);
5826 if (method->wrapper_type != MONO_WRAPPER_NONE)
5827 cmethod = mono_method_get_wrapper_data (method, n);
5829 cmethod = mini_get_method (image, n, NULL, generic_context);
5832 mono_class_init (cmethod->klass);
5833 handle_loaded_temps (cfg, bblock, stack_start, sp);
5835 NEW_METHODCONST (cfg, argconst, cmethod);
5836 if (method->wrapper_type != MONO_WRAPPER_SYNCHRONIZED)
5837 temp = mono_emit_jit_icall (cfg, bblock, mono_ldftn, &argconst, ip);
5839 temp = mono_emit_jit_icall (cfg, bblock, mono_ldftn_nosync, &argconst, ip);
5840 NEW_TEMPLOAD (cfg, *sp, temp);
5844 inline_costs += 10 * num_calls++;
5847 case CEE_LDVIRTFTN: {
5853 n = read32 (ip + 2);
5854 if (method->wrapper_type != MONO_WRAPPER_NONE)
5855 cmethod = mono_method_get_wrapper_data (method, n);
5857 cmethod = mini_get_method (image, n, NULL, generic_context);
5859 mono_class_init (cmethod->klass);
5860 handle_loaded_temps (cfg, bblock, stack_start, sp);
5864 NEW_METHODCONST (cfg, args [1], cmethod);
5865 temp = mono_emit_jit_icall (cfg, bblock, mono_ldvirtfn, args, ip);
5866 NEW_TEMPLOAD (cfg, *sp, temp);
5870 inline_costs += 10 * num_calls++;
5874 CHECK_STACK_OVF (1);
5876 n = read16 (ip + 2);
5878 NEW_ARGLOAD (cfg, ins, n);
5884 CHECK_STACK_OVF (1);
5886 n = read16 (ip + 2);
5888 NEW_ARGLOADA (cfg, ins, n);
5896 handle_loaded_temps (cfg, bblock, stack_start, sp);
5898 n = read16 (ip + 2);
5900 NEW_ARGSTORE (cfg, ins, n, *sp);
5902 if (ins->opcode == CEE_STOBJ) {
5903 NEW_ARGLOADA (cfg, ins, n);
5904 handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE);
5906 MONO_ADD_INS (bblock, ins);
5910 CHECK_STACK_OVF (1);
5912 n = read16 (ip + 2);
5914 NEW_LOCLOAD (cfg, ins, n);
5920 CHECK_STACK_OVF (1);
5922 n = read16 (ip + 2);
5924 NEW_LOCLOADA (cfg, ins, n);
5933 n = read16 (ip + 2);
5935 handle_loaded_temps (cfg, bblock, stack_start, sp);
5936 NEW_LOCSTORE (cfg, ins, n, *sp);
5938 if (ins->opcode == CEE_STOBJ) {
5939 NEW_LOCLOADA (cfg, ins, n);
5940 handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE);
5942 MONO_ADD_INS (bblock, ins);
5949 if (sp != stack_start)
5951 if (cfg->method != method)
5953 * Inlining this into a loop in a parent could lead to
5954 * stack overflows which is different behavior than the
5955 * non-inlined case, thus disable inlining in this case.
5957 goto inline_failure;
5958 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
5959 ins->inst_left = *sp;
5961 ins->type = STACK_MP;
5963 cfg->flags |= MONO_CFG_HAS_ALLOCA;
5964 if (header->init_locals)
5965 ins->flags |= MONO_INST_INIT;
5969 /* FIXME: set init flag if locals init is set in this method */
5971 case CEE_ENDFILTER: {
5972 MonoExceptionClause *clause, *nearest;
5973 int cc, nearest_num;
5977 if ((sp != stack_start) || (sp [0]->type != STACK_I4))
5979 MONO_INST_NEW (cfg, ins, OP_ENDFILTER);
5980 ins->inst_left = *sp;
5982 MONO_ADD_INS (bblock, ins);
5983 start_new_bblock = 1;
5988 for (cc = 0; cc < header->num_clauses; ++cc) {
5989 clause = &header->clauses [cc];
5990 if ((clause->flags & MONO_EXCEPTION_CLAUSE_FILTER) &&
5991 (!nearest || (clause->data.filter_offset > nearest->data.filter_offset))) {
5997 filter_lengths [nearest_num] = (ip - header->code) - nearest->data.filter_offset;
6001 case CEE_UNALIGNED_:
6002 ins_flag |= MONO_INST_UNALIGNED;
6003 /* FIXME: record alignment? we can assume 1 for now */
6008 ins_flag |= MONO_INST_VOLATILE;
6012 ins_flag |= MONO_INST_TAILCALL;
6013 cfg->flags |= MONO_CFG_HAS_TAIL;
6014 /* Can't inline tail calls at this time */
6015 inline_costs += 100000;
6022 token = read32 (ip + 2);
6023 if (method->wrapper_type != MONO_WRAPPER_NONE)
6024 klass = mono_method_get_wrapper_data (method, token);
6026 klass = mono_class_get_full (image, token, generic_context);
6027 if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
6028 MonoInst *store, *load;
6029 NEW_PCONST (cfg, load, NULL);
6030 load->cil_code = ip;
6031 load->type = STACK_OBJ;
6032 MONO_INST_NEW (cfg, store, CEE_STIND_REF);
6033 store->cil_code = ip;
6034 handle_loaded_temps (cfg, bblock, stack_start, sp);
6035 MONO_ADD_INS (bblock, store);
6036 store->inst_i0 = sp [0];
6037 store->inst_i1 = load;
6039 handle_initobj (cfg, bblock, *sp, NULL, klass, stack_start, sp);
6044 case CEE_CONSTRAINED_:
6045 /* FIXME: implement */
6047 token = read32 (ip + 2);
6048 constrained_call = mono_class_get_full (image, token, generic_context);
6053 MonoInst *iargs [3];
6056 if ((cfg->opt & MONO_OPT_INTRINS) && (ip [1] == CEE_CPBLK) && (sp [2]->opcode == OP_ICONST) && ((n = sp [2]->inst_c0) <= sizeof (gpointer) * 5)) {
6058 MONO_INST_NEW (cfg, copy, OP_MEMCPY);
6059 copy->inst_left = sp [0];
6060 copy->inst_right = sp [1];
6061 copy->cil_code = ip;
6063 MONO_ADD_INS (bblock, copy);
6070 handle_loaded_temps (cfg, bblock, stack_start, sp);
6071 if (ip [1] == CEE_CPBLK) {
6072 mono_emit_jit_icall (cfg, bblock, helper_memcpy, iargs, ip);
6074 mono_emit_jit_icall (cfg, bblock, helper_memset, iargs, ip);
6083 ins_flag |= MONO_INST_NOTYPECHECK;
6085 ins_flag |= MONO_INST_NORANGECHECK;
6086 /* we ignore the no-nullcheck for now since we
6087 * really do it explicitly only when doing callvirt->call
6093 /* FIXME: check we are in a catch handler */
6094 NEW_TEMPLOAD (cfg, load, cfg->exvar->inst_c0);
6095 load->cil_code = ip;
6096 MONO_INST_NEW (cfg, ins, OP_RETHROW);
6097 ins->inst_left = load;
6099 MONO_ADD_INS (bblock, ins);
6101 link_bblock (cfg, bblock, end_bblock);
6102 start_new_bblock = 1;
6107 CHECK_STACK_OVF (1);
6109 token = read32 (ip + 2);
6110 /* FIXXME: handle generics. */
6111 if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC) {
6112 MonoType *type = mono_type_create_from_typespec (image, token);
6113 token = mono_type_size (type, &align);
6115 MonoClass *szclass = mono_class_get_full (image, token, generic_context);
6116 mono_class_init (szclass);
6117 token = mono_class_value_size (szclass, &align);
6119 NEW_ICONST (cfg, ins, token);
6124 case CEE_REFANYTYPE:
6126 MONO_INST_NEW (cfg, ins, OP_REFANYTYPE);
6128 ins->type = STACK_MP;
6129 ins->inst_left = *sp;
6130 ins->type = STACK_VTYPE;
6131 ins->klass = mono_defaults.typehandle_class;
6140 g_error ("opcode 0xfe 0x%02x not handled", ip [1]);
6145 g_error ("opcode 0x%02x not handled", *ip);
6148 if (start_new_bblock != 1)
6151 bblock->cil_length = ip - bblock->cil_code;
6152 bblock->next_bb = end_bblock;
6154 if (cfg->method == method && cfg->domainvar) {
6156 MonoInst *get_domain;
6158 if (! (get_domain = mono_arch_get_domain_intrinsic (cfg))) {
6161 MONO_INST_NEW_CALL (cfg, call, CEE_CALL);
6162 call->signature = helper_sig_domain_get;
6163 call->inst.type = STACK_PTR;
6164 call->fptr = mono_domain_get;
6165 get_domain = (MonoInst*)call;
6168 NEW_TEMPSTORE (cfg, store, cfg->domainvar->inst_c0, get_domain);
6169 MONO_ADD_INS (init_localsbb, store);
6172 if (cfg->method == method && cfg->got_var)
6173 mono_emit_load_got_addr (cfg);
6175 if (header->init_locals) {
6177 for (i = 0; i < header->num_locals; ++i) {
6178 MonoType *ptype = header->locals [i];
6179 int t = ptype->type;
6180 if (t == MONO_TYPE_VALUETYPE && ptype->data.klass->enumtype)
6181 t = ptype->data.klass->enum_basetype->type;
6182 /* FIXME: use initobj for valuetypes, handle pointers, long, float. */
6183 if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
6184 NEW_ICONST (cfg, ins, 0);
6185 NEW_LOCSTORE (cfg, store, i, ins);
6186 MONO_ADD_INS (init_localsbb, store);
6187 } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
6188 MONO_INST_NEW (cfg, ins, OP_I8CONST);
6189 ins->type = STACK_I8;
6191 NEW_LOCSTORE (cfg, store, i, ins);
6192 MONO_ADD_INS (init_localsbb, store);
6193 } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
6194 MONO_INST_NEW (cfg, ins, OP_R8CONST);
6195 ins->type = STACK_R8;
6196 ins->inst_p0 = (void*)&r8_0;
6197 NEW_LOCSTORE (cfg, store, i, ins);
6198 MONO_ADD_INS (init_localsbb, store);
6199 } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
6200 ((t == MONO_TYPE_GENERICINST) && mono_metadata_generic_class_is_valuetype (ptype->data.generic_class))) {
6201 NEW_LOCLOADA (cfg, ins, i);
6202 handle_initobj (cfg, init_localsbb, ins, NULL, mono_class_from_mono_type (ptype), NULL, NULL);
6205 NEW_PCONST (cfg, ins, NULL);
6206 NEW_LOCSTORE (cfg, store, i, ins);
6207 MONO_ADD_INS (init_localsbb, store);
6212 /* resolve backward branches in the middle of an existing basic block */
6213 for (tmp = bb_recheck; tmp; tmp = tmp->next) {
6215 /*g_print ("need recheck in %s at IL_%04x\n", method->name, bblock->cil_code - header->code);*/
6216 tblock = find_previous (bbhash, start_bblock, bblock->cil_code);
6217 if (tblock != start_bblock) {
6219 split_bblock (cfg, tblock, bblock);
6220 l = bblock->cil_code - header->code;
6221 bblock->cil_length = tblock->cil_length - l;
6222 tblock->cil_length = l;
6224 g_print ("recheck failed.\n");
6229 * we compute regions here, because the length of filter clauses is not known in advance.
6230 * It is computed in the CEE_ENDFILTER case in the above switch statement
6232 if (cfg->method == method) {
6234 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
6235 bb->region = mono_find_block_region (cfg, bb->real_offset, filter_lengths);
6237 mono_create_spvar_for_region (cfg, bb->region);
6238 if (cfg->verbose_level > 2)
6239 g_print ("REGION BB%d IL_%04x ID_%08X\n", bb->block_num, bb->real_offset, bb->region);
6242 g_hash_table_destroy (bbhash);
6245 dont_inline = g_list_remove (dont_inline, method);
6246 return inline_costs;
6249 if (cfg->method != method)
6250 g_hash_table_destroy (bbhash);
6251 dont_inline = g_list_remove (dont_inline, method);
6255 if (cfg->method != method)
6256 g_hash_table_destroy (bbhash);
6257 g_error ("Invalid IL code at IL%04x in %s: %s\n", (int)(ip - header->code),
6258 mono_method_full_name (method, TRUE), mono_disasm_code_one (NULL, method, ip, NULL));
6259 dont_inline = g_list_remove (dont_inline, method);
6264 mono_print_tree (MonoInst *tree) {
6270 arity = mono_burg_arity [tree->opcode];
6272 printf (" %s%s", arity?"(":"", mono_inst_name (tree->opcode));
6274 switch (tree->opcode) {
6276 printf ("[%d]", (int)tree->inst_c0);
6279 printf ("[%lld]", (long long)tree->inst_l);
6282 printf ("[%f]", *(double*)tree->inst_p0);
6285 printf ("[%f]", *(float*)tree->inst_p0);
6289 printf ("[%d]", (int)tree->inst_c0);
6292 if (tree->inst_offset < 0)
6293 printf ("[-0x%x(%s)]", (int)(-tree->inst_offset), mono_arch_regname (tree->inst_basereg));
6295 printf ("[0x%x(%s)]", (int)(tree->inst_offset), mono_arch_regname (tree->inst_basereg));
6298 printf ("[%s]", mono_arch_regname (tree->dreg));
6301 printf ("[%s]", tree->inst_newa_class->name);
6302 mono_print_tree (tree->inst_newa_len);
6313 case OP_VOIDCALLVIRT: {
6314 MonoCallInst *call = (MonoCallInst*)tree;
6316 printf ("[%s]", call->method->name);
6321 printf ("[%d (", (int)tree->inst_c0);
6322 for (i = 0; i < tree->inst_phi_args [0]; i++) {
6325 printf ("%d", tree->inst_phi_args [i + 1]);
6336 case OP_LOAD_MEMBASE:
6337 case OP_LOADI4_MEMBASE:
6338 case OP_LOADU4_MEMBASE:
6339 case OP_LOADU1_MEMBASE:
6340 case OP_LOADI1_MEMBASE:
6341 case OP_LOADU2_MEMBASE:
6342 case OP_LOADI2_MEMBASE:
6343 printf ("[%s] <- [%s + 0x%x]", mono_arch_regname (tree->dreg), mono_arch_regname (tree->inst_basereg), (int)tree->inst_offset);
6346 case OP_CALL_HANDLER:
6347 printf ("[B%d]", tree->inst_target_bb->block_num);
6357 case OP_VOIDCALL_REG:
6358 mono_print_tree (tree->inst_left);
6370 printf ("[B%dB%d]", tree->inst_true_bb->block_num, tree->inst_false_bb->block_num);
6371 mono_print_tree (tree->inst_left);
6374 if (!mono_arch_print_tree(tree, arity)) {
6376 mono_print_tree (tree->inst_left);
6378 mono_print_tree (tree->inst_right);
6389 mono_print_tree_nl (MonoInst *tree)
6391 mono_print_tree (tree);
6395 #define make_icall_sig mono_create_icall_signature
6398 create_helper_signature (void)
6400 /* MonoArray * mono_array_new (MonoDomain *domain, MonoClass *klass, gint32 len) */
6401 helper_sig_newarr = make_icall_sig ("object ptr ptr int32");
6403 /* MonoArray * mono_array_new_specific (MonoVTable *vtable, guint32 len) */
6404 helper_sig_newarr_specific = make_icall_sig ("object ptr int32");
6406 /* MonoObject * mono_object_new (MonoDomain *domain, MonoClass *klass) */
6407 helper_sig_object_new = make_icall_sig ("object ptr ptr");
6409 /* MonoObject * mono_object_new_specific (MonoVTable *vtable) */
6410 helper_sig_object_new_specific = make_icall_sig ("object ptr");
6412 /* void* mono_method_compile (MonoMethod*) */
6413 helper_sig_compile = make_icall_sig ("ptr ptr");
6415 /* void* mono_ldvirtfn (MonoObject *, MonoMethod*) */
6416 helper_sig_compile_virt = make_icall_sig ("ptr object ptr");
6418 /* MonoString* mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 str_index) */
6419 helper_sig_ldstr = make_icall_sig ("object ptr ptr int32");
6421 /* MonoDomain *mono_domain_get (void) */
6422 helper_sig_domain_get = make_icall_sig ("ptr");
6424 /* void stelem_ref (MonoArray *, int index, MonoObject *) */
6425 helper_sig_stelem_ref = make_icall_sig ("void ptr int32 object");
6427 /* void stelem_ref_check (MonoArray *, MonoObject *) */
6428 helper_sig_stelem_ref_check = make_icall_sig ("void object object");
6430 /* void *helper_compile_generic_method (MonoObject *, MonoMethod *, MonoGenericContext *) */
6431 helper_sig_compile_generic_method = make_icall_sig ("ptr object ptr ptr");
6433 /* long amethod (long, long) */
6434 helper_sig_long_long_long = make_icall_sig ("long long long");
6436 /* object amethod (intptr) */
6437 helper_sig_obj_ptr = make_icall_sig ("object ptr");
6439 helper_sig_obj_ptr_ptr = make_icall_sig ("object ptr ptr");
6441 helper_sig_obj_obj_ptr_ptr = make_icall_sig ("object object ptr ptr");
6443 helper_sig_void_void = make_icall_sig ("void");
6445 /* void amethod (intptr) */
6446 helper_sig_void_ptr = make_icall_sig ("void ptr");
6448 /* void amethod (MonoObject *obj) */
6449 helper_sig_void_obj = make_icall_sig ("void object");
6451 /* void amethod (MonoObject *obj, void *ptr, int i) */
6452 helper_sig_void_obj_ptr_int = make_icall_sig ("void object ptr int");
6454 helper_sig_void_obj_ptr_ptr_obj = make_icall_sig ("void object ptr ptr object");
6456 /* intptr amethod (void) */
6457 helper_sig_ptr_void = make_icall_sig ("ptr");
6459 /* object amethod (void) */
6460 helper_sig_obj_void = make_icall_sig ("object");
6462 /* void amethod (intptr, intptr) */
6463 helper_sig_void_ptr_ptr = make_icall_sig ("void ptr ptr");
6465 /* void amethod (intptr, intptr, intptr) */
6466 helper_sig_void_ptr_ptr_ptr = make_icall_sig ("void ptr ptr ptr");
6468 /* intptr amethod (intptr, intptr) */
6469 helper_sig_ptr_ptr_ptr = make_icall_sig ("ptr ptr ptr");
6471 helper_sig_ptr_ptr_ptr_ptr = make_icall_sig ("ptr ptr ptr ptr");
6473 /* IntPtr amethod (object) */
6474 helper_sig_ptr_obj = make_icall_sig ("ptr object");
6476 /* IntPtr amethod (object, int) */
6477 helper_sig_ptr_obj_int = make_icall_sig ("ptr object int");
6479 /* IntPtr amethod (int) */
6480 helper_sig_ptr_int = make_icall_sig ("ptr int32");
6482 /* long amethod (long, guint32) */
6483 helper_sig_long_long_int = make_icall_sig ("long long int32");
6485 /* ulong amethod (double) */
6486 helper_sig_ulong_double = make_icall_sig ("ulong double");
6488 /* long amethod (double) */
6489 helper_sig_long_double = make_icall_sig ("long double");
6491 /* double amethod (long) */
6492 helper_sig_double_long = make_icall_sig ("double long");
6494 /* double amethod (int) */
6495 helper_sig_double_int = make_icall_sig ("double int32");
6497 /* float amethod (long) */
6498 helper_sig_float_long = make_icall_sig ("float long");
6500 /* double amethod (double, double) */
6501 helper_sig_double_double_double = make_icall_sig ("double double double");
6503 /* uint amethod (double) */
6504 helper_sig_uint_double = make_icall_sig ("uint32 double");
6506 /* int amethod (double) */
6507 helper_sig_int_double = make_icall_sig ("int32 double");
6509 /* void initobj (intptr, int size) */
6510 helper_sig_initobj = make_icall_sig ("void ptr int32");
6512 /* void memcpy (intptr, intptr, int size) */
6513 helper_sig_memcpy = make_icall_sig ("void ptr ptr int32");
6515 /* void memset (intptr, int val, int size) */
6516 helper_sig_memset = make_icall_sig ("void ptr int32 int32");
6518 helper_sig_class_init_trampoline = make_icall_sig ("void");
6522 mono_icall_get_wrapper (MonoJitICallInfo* callinfo)
6525 MonoMethod *wrapper;
6528 if (callinfo->wrapper)
6529 return callinfo->wrapper;
6531 name = g_strdup_printf ("__icall_wrapper_%s", callinfo->name);
6532 wrapper = mono_marshal_get_icall_wrapper (callinfo->sig, name, callinfo->func);
6533 /* Must be domain neutral since there is only one copy */
6534 code = mono_jit_compile_method_with_opt (wrapper, default_opt | MONO_OPT_SHARED);
6536 if (!callinfo->wrapper) {
6537 callinfo->wrapper = code;
6538 mono_register_jit_icall_wrapper (callinfo, code);
6539 mono_debug_add_icall_wrapper (wrapper, callinfo);
6543 return callinfo->wrapper;
6547 mono_create_class_init_trampoline (MonoVTable *vtable)
6551 /* previously created trampoline code */
6552 mono_domain_lock (vtable->domain);
6554 g_hash_table_lookup (vtable->domain->class_init_trampoline_hash,
6556 mono_domain_unlock (vtable->domain);
6560 code = mono_arch_create_class_init_trampoline (vtable);
6562 /* store trampoline address */
6563 mono_domain_lock (vtable->domain);
6564 g_hash_table_insert (vtable->domain->class_init_trampoline_hash,
6566 mono_domain_unlock (vtable->domain);
6568 EnterCriticalSection (&jit_mutex);
6569 if (!class_init_hash_addr)
6570 class_init_hash_addr = g_hash_table_new (NULL, NULL);
6571 g_hash_table_insert (class_init_hash_addr, code, vtable);
6572 LeaveCriticalSection (&jit_mutex);
6578 mono_create_jump_trampoline (MonoDomain *domain, MonoMethod *method,
6579 gboolean add_sync_wrapper)
6584 if (add_sync_wrapper && method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
6585 return mono_create_jump_trampoline (domain, mono_marshal_get_synchronized_wrapper (method), FALSE);
6587 code = mono_jit_find_compiled_method (domain, method);
6591 mono_domain_lock (domain);
6592 code = g_hash_table_lookup (domain->jump_trampoline_hash, method);
6593 mono_domain_unlock (domain);
6597 ji = mono_arch_create_jump_trampoline (method);
6600 * mono_delegate_ctor needs to find the method metadata from the
6601 * trampoline address, so we save it here.
6604 mono_jit_info_table_add (mono_get_root_domain (), ji);
6606 mono_domain_lock (domain);
6607 g_hash_table_insert (domain->jump_trampoline_hash, method, ji->code_start);
6608 mono_domain_unlock (domain);
6610 return ji->code_start;
6614 mono_create_jit_trampoline (MonoMethod *method)
6616 MonoDomain *domain = mono_domain_get ();
6619 /* Trampoline are domain specific, so cache only the one used in the root domain */
6620 if ((domain == mono_get_root_domain ()) && method->info)
6621 return method->info;
6623 if (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
6624 return mono_create_jit_trampoline (mono_marshal_get_synchronized_wrapper (method));
6626 tramp = mono_arch_create_jit_trampoline (method);
6627 if (domain == mono_get_root_domain ())
6628 method->info = tramp;
6630 mono_jit_stats.method_trampolines++;
6636 mono_find_class_init_trampoline_by_addr (gconstpointer addr)
6640 EnterCriticalSection (&jit_mutex);
6641 if (class_init_hash_addr)
6642 res = g_hash_table_lookup (class_init_hash_addr, addr);
6645 LeaveCriticalSection (&jit_mutex);
6650 mono_dynamic_code_hash_insert (MonoDomain *domain, MonoMethod *method, MonoJitDynamicMethodInfo *ji)
6652 if (!domain->dynamic_code_hash)
6653 domain->dynamic_code_hash = g_hash_table_new (NULL, NULL);
6654 g_hash_table_insert (domain->dynamic_code_hash, method, ji);
6657 static MonoJitDynamicMethodInfo*
6658 mono_dynamic_code_hash_lookup (MonoDomain *domain, MonoMethod *method)
6660 MonoJitDynamicMethodInfo *res;
6662 if (domain->dynamic_code_hash)
6663 res = g_hash_table_lookup (domain->dynamic_code_hash, method);
6670 mono_register_opcode_emulation (int opcode, const char *name, MonoMethodSignature *sig, gpointer func, gboolean no_throw)
6672 MonoJitICallInfo *info;
6674 if (!emul_opcode_map)
6675 emul_opcode_map = g_new0 (MonoJitICallInfo*, OP_LAST + 1);
6677 g_assert (!sig->hasthis);
6678 g_assert (sig->param_count < 3);
6680 info = mono_register_jit_icall (func, name, sig, no_throw);
6682 emul_opcode_map [opcode] = info;
6686 decompose_foreach (MonoInst *tree, gpointer data)
6688 static MonoJitICallInfo *newarr_info = NULL;
6689 static MonoJitICallInfo *newarr_specific_info = NULL;
6690 MonoJitICallInfo *info;
6693 switch (tree->opcode) {
6695 MonoCompile *cfg = data;
6696 MonoInst *iargs [3];
6699 newarr_info = mono_find_jit_icall_by_addr (mono_array_new);
6700 g_assert (newarr_info);
6701 newarr_specific_info = mono_find_jit_icall_by_addr (mono_array_new_specific);
6702 g_assert (newarr_specific_info);
6705 if (cfg->opt & MONO_OPT_SHARED) {
6706 NEW_DOMAINCONST (cfg, iargs [0]);
6707 NEW_CLASSCONST (cfg, iargs [1], tree->inst_newa_class);
6708 iargs [2] = tree->inst_newa_len;
6713 MonoVTable *vtable = mono_class_vtable (cfg->domain, mono_array_class_get (tree->inst_newa_class, 1));
6715 NEW_VTABLECONST (cfg, iargs [0], vtable);
6716 iargs [1] = tree->inst_newa_len;
6718 info = newarr_specific_info;
6721 mono_emulate_opcode (cfg, tree, iargs, info);
6723 /* Need to decompose arguments after the the opcode is decomposed */
6724 for (i = 0; i < info->sig->param_count; ++i)
6725 dec_foreach (iargs [i], cfg);
6735 mono_inst_foreach (MonoInst *tree, MonoInstFunc func, gpointer data) {
6737 switch (mono_burg_arity [tree->opcode]) {
6740 mono_inst_foreach (tree->inst_left, func, data);
6743 mono_inst_foreach (tree->inst_left, func, data);
6744 mono_inst_foreach (tree->inst_right, func, data);
6747 g_assert_not_reached ();
6754 mono_print_bb_code (MonoBasicBlock *bb) {
6756 MonoInst *c = bb->code;
6758 mono_print_tree (c);
6766 print_dfn (MonoCompile *cfg) {
6771 g_print ("IR code for method %s\n", mono_method_full_name (cfg->method, TRUE));
6773 for (i = 0; i < cfg->num_bblocks; ++i) {
6774 bb = cfg->bblocks [i];
6775 /*if (bb->cil_code) {
6776 char* code1, *code2;
6777 code1 = mono_disasm_code_one (NULL, cfg->method, bb->cil_code, NULL);
6778 if (bb->last_ins->cil_code)
6779 code2 = mono_disasm_code_one (NULL, cfg->method, bb->last_ins->cil_code, NULL);
6781 code2 = g_strdup ("");
6783 code1 [strlen (code1) - 1] = 0;
6784 code = g_strdup_printf ("%s -> %s", code1, code2);
6788 code = g_strdup ("\n");
6789 g_print ("\nBB%d DFN%d (len: %d): %s", bb->block_num, i, bb->cil_length, code);
6791 MonoInst *c = bb->code;
6793 mono_print_tree (c);
6801 g_print ("\tprev:");
6802 for (j = 0; j < bb->in_count; ++j) {
6803 g_print (" BB%d", bb->in_bb [j]->block_num);
6805 g_print ("\t\tsucc:");
6806 for (j = 0; j < bb->out_count; ++j) {
6807 g_print (" BB%d", bb->out_bb [j]->block_num);
6809 g_print ("\n\tidom: BB%d\n", bb->idom? bb->idom->block_num: -1);
6812 g_assert (mono_bitset_test_fast (bb->dominators, bb->idom->dfn));
6815 mono_blockset_print (cfg, bb->dominators, "\tdominators", bb->idom? bb->idom->dfn: -1);
6817 mono_blockset_print (cfg, bb->dfrontier, "\tdfrontier", -1);
6825 mono_bblock_add_inst (MonoBasicBlock *bb, MonoInst *inst)
6829 g_assert (bb->code);
6830 bb->last_ins->next = inst;
6831 bb->last_ins = inst;
6833 bb->last_ins = bb->code = inst;
6838 mono_destroy_compile (MonoCompile *cfg)
6840 //mono_mempool_stats (cfg->mempool);
6841 g_hash_table_destroy (cfg->bb_hash);
6842 mono_free_loop_info (cfg);
6844 mono_regstate_free (cfg->rs);
6846 g_hash_table_destroy (cfg->spvars);
6847 mono_mempool_destroy (cfg->mempool);
6848 g_list_free (cfg->ldstr_list);
6850 g_free (cfg->varinfo);
6855 #ifdef HAVE_KW_THREAD
6856 static __thread gpointer mono_lmf_addr;
6860 mono_get_lmf_addr (void)
6862 #ifdef HAVE_KW_THREAD
6863 return mono_lmf_addr;
6865 MonoJitTlsData *jit_tls;
6867 if ((jit_tls = TlsGetValue (mono_jit_tls_id)))
6868 return &jit_tls->lmf;
6870 g_assert_not_reached ();
6876 * mono_thread_abort:
6877 * @obj: exception object
6879 * abort the thread, print exception information and stack trace
6882 mono_thread_abort (MonoObject *obj)
6884 /* MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id); */
6886 /* handle_remove should be eventually called for this thread, too
6889 mono_thread_exit ();
6893 setup_jit_tls_data (gpointer stack_start, gpointer abort_func)
6895 MonoJitTlsData *jit_tls;
6898 jit_tls = TlsGetValue (mono_jit_tls_id);
6902 jit_tls = g_new0 (MonoJitTlsData, 1);
6904 TlsSetValue (mono_jit_tls_id, jit_tls);
6906 jit_tls->abort_func = abort_func;
6907 jit_tls->end_of_stack = stack_start;
6909 lmf = g_new0 (MonoLMF, 1);
6912 jit_tls->lmf = jit_tls->first_lmf = lmf;
6914 #ifdef HAVE_KW_THREAD
6915 mono_lmf_addr = &jit_tls->lmf;
6918 mono_arch_setup_jit_tls_data (jit_tls);
6924 mono_thread_start_cb (guint32 tid, gpointer stack_start, gpointer func)
6927 void *jit_tls = setup_jit_tls_data (stack_start, mono_thread_abort);
6928 thread = mono_thread_current ();
6930 thread->jit_data = jit_tls;
6931 if (mono_profiler_get_events () & MONO_PROFILE_STATISTICAL)
6932 setup_stat_profiler ();
6935 void (*mono_thread_attach_aborted_cb ) (MonoObject *obj) = NULL;
6938 mono_thread_abort_dummy (MonoObject *obj)
6940 if (mono_thread_attach_aborted_cb)
6941 mono_thread_attach_aborted_cb (obj);
6943 mono_thread_abort (obj);
6947 mono_thread_attach_cb (guint32 tid, gpointer stack_start)
6950 void *jit_tls = setup_jit_tls_data (stack_start, mono_thread_abort_dummy);
6951 thread = mono_thread_current ();
6953 thread->jit_data = jit_tls;
6957 mini_thread_cleanup (MonoThread *thread)
6959 MonoJitTlsData *jit_tls = thread->jit_data;
6962 mono_arch_free_jit_tls_data (jit_tls);
6963 g_free (jit_tls->first_lmf);
6965 thread->jit_data = NULL;
6970 mono_add_patch_info (MonoCompile *cfg, int ip, MonoJumpInfoType type, gconstpointer target)
6972 MonoJumpInfo *ji = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfo));
6976 ji->data.target = target;
6977 ji->next = cfg->patch_info;
6979 cfg->patch_info = ji;
6983 mono_remove_patch_info (MonoCompile *cfg, int ip)
6985 MonoJumpInfo **ji = &cfg->patch_info;
6988 if ((*ji)->ip.i == ip)
6991 ji = &((*ji)->next);
6996 mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *patch_info, gboolean run_cctors)
6998 unsigned char *ip = patch_info->ip.i + code;
6999 gconstpointer target = NULL;
7001 switch (patch_info->type) {
7002 case MONO_PATCH_INFO_BB:
7003 target = patch_info->data.bb->native_offset + code;
7005 case MONO_PATCH_INFO_ABS:
7006 target = patch_info->data.target;
7008 case MONO_PATCH_INFO_LABEL:
7009 target = patch_info->data.inst->inst_c0 + code;
7011 case MONO_PATCH_INFO_IP:
7014 case MONO_PATCH_INFO_METHOD_REL:
7015 target = code + patch_info->data.offset;
7017 case MONO_PATCH_INFO_INTERNAL_METHOD: {
7018 MonoJitICallInfo *mi = mono_find_jit_icall_by_name (patch_info->data.name);
7020 g_warning ("unknown MONO_PATCH_INFO_INTERNAL_METHOD %s", patch_info->data.name);
7021 g_assert_not_reached ();
7023 target = mono_icall_get_wrapper (mi);
7026 case MONO_PATCH_INFO_METHOD_JUMP: {
7029 /* get the trampoline to the method from the domain */
7030 target = mono_create_jump_trampoline (domain, patch_info->data.method, TRUE);
7031 if (!domain->jump_target_hash)
7032 domain->jump_target_hash = g_hash_table_new (NULL, NULL);
7033 list = g_hash_table_lookup (domain->jump_target_hash, patch_info->data.method);
7034 list = g_slist_prepend (list, ip);
7035 g_hash_table_insert (domain->jump_target_hash, patch_info->data.method, list);
7038 case MONO_PATCH_INFO_METHOD:
7039 if (patch_info->data.method == method) {
7042 /* get the trampoline to the method from the domain */
7043 target = mono_create_jit_trampoline (patch_info->data.method);
7045 case MONO_PATCH_INFO_SWITCH: {
7046 gpointer *jump_table;
7049 if (method->dynamic) {
7050 jump_table = mono_code_manager_reserve (mono_dynamic_code_hash_lookup (domain, method)->code_mp, sizeof (gpointer) * patch_info->data.table->table_size);
7052 mono_domain_lock (domain);
7053 jump_table = mono_code_manager_reserve (domain->code_mp, sizeof (gpointer) * patch_info->data.table->table_size);
7054 mono_domain_unlock (domain);
7057 for (i = 0; i < patch_info->data.table->table_size; i++) {
7058 jump_table [i] = code + GPOINTER_TO_INT (patch_info->data.table->table [i]);
7060 target = jump_table;
7063 case MONO_PATCH_INFO_METHODCONST:
7064 case MONO_PATCH_INFO_CLASS:
7065 case MONO_PATCH_INFO_IMAGE:
7066 case MONO_PATCH_INFO_FIELD:
7067 target = patch_info->data.target;
7069 case MONO_PATCH_INFO_IID:
7070 mono_class_init (patch_info->data.klass);
7071 target = GINT_TO_POINTER (patch_info->data.klass->interface_id);
7073 case MONO_PATCH_INFO_VTABLE:
7074 target = mono_class_vtable (domain, patch_info->data.klass);
7076 case MONO_PATCH_INFO_CLASS_INIT:
7077 target = mono_create_class_init_trampoline (mono_class_vtable (domain, patch_info->data.klass));
7079 case MONO_PATCH_INFO_SFLDA: {
7080 MonoVTable *vtable = mono_class_vtable (domain, patch_info->data.field->parent);
7081 if (!vtable->initialized && !(vtable->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) && mono_class_needs_cctor_run (vtable->klass, method))
7082 /* Done by the generated code */
7086 mono_runtime_class_init (vtable);
7088 target = (char*)vtable->data + patch_info->data.field->offset;
7091 case MONO_PATCH_INFO_R4:
7092 case MONO_PATCH_INFO_R8:
7093 target = patch_info->data.target;
7095 case MONO_PATCH_INFO_EXC_NAME:
7096 target = patch_info->data.name;
7098 case MONO_PATCH_INFO_LDSTR:
7100 mono_ldstr (domain, patch_info->data.token->image,
7101 mono_metadata_token_index (patch_info->data.token->token));
7103 case MONO_PATCH_INFO_TYPE_FROM_HANDLE: {
7105 MonoClass *handle_class;
7107 handle = mono_ldtoken (patch_info->data.token->image,
7108 patch_info->data.token->token, &handle_class, NULL);
7109 mono_class_init (handle_class);
7110 mono_class_init (mono_class_from_mono_type (handle));
7113 mono_type_get_object (domain, handle);
7116 case MONO_PATCH_INFO_LDTOKEN: {
7118 MonoClass *handle_class;
7120 handle = mono_ldtoken (patch_info->data.token->image,
7121 patch_info->data.token->token, &handle_class, NULL);
7122 mono_class_init (handle_class);
7127 case MONO_PATCH_INFO_BB_OVF:
7128 case MONO_PATCH_INFO_EXC_OVF:
7129 case MONO_PATCH_INFO_GOT_OFFSET:
7130 case MONO_PATCH_INFO_NONE:
7133 g_assert_not_reached ();
7136 return (gpointer)target;
7140 dec_foreach (MonoInst *tree, MonoCompile *cfg) {
7141 MonoJitICallInfo *info;
7143 decompose_foreach (tree, cfg);
7145 switch (mono_burg_arity [tree->opcode]) {
7148 dec_foreach (tree->inst_left, cfg);
7150 if ((info = mono_find_jit_opcode_emulation (tree->opcode))) {
7151 MonoInst *iargs [2];
7153 iargs [0] = tree->inst_left;
7155 mono_emulate_opcode (cfg, tree, iargs, info);
7161 #ifdef MONO_ARCH_BIGMUL_INTRINS
7162 if (tree->opcode == OP_LMUL
7163 && (cfg->opt & MONO_OPT_INTRINS)
7164 && (tree->inst_left->opcode == CEE_CONV_I8
7165 || tree->inst_left->opcode == CEE_CONV_U8)
7166 && tree->inst_left->inst_left->type == STACK_I4
7167 && (tree->inst_right->opcode == CEE_CONV_I8
7168 || tree->inst_right->opcode == CEE_CONV_U8)
7169 && tree->inst_right->inst_left->type == STACK_I4
7170 && tree->inst_left->opcode == tree->inst_right->opcode) {
7171 tree->opcode = (tree->inst_left->opcode == CEE_CONV_I8 ? OP_BIGMUL: OP_BIGMUL_UN);
7172 tree->inst_left = tree->inst_left->inst_left;
7173 tree->inst_right = tree->inst_right->inst_left;
7174 dec_foreach (tree, cfg);
7177 if ((info = mono_find_jit_opcode_emulation (tree->opcode))) {
7178 MonoInst *iargs [2];
7180 iargs [0] = tree->inst_i0;
7181 iargs [1] = tree->inst_i1;
7183 mono_emulate_opcode (cfg, tree, iargs, info);
7185 dec_foreach (iargs [0], cfg);
7186 dec_foreach (iargs [1], cfg);
7189 dec_foreach (tree->inst_left, cfg);
7190 dec_foreach (tree->inst_right, cfg);
7194 g_assert_not_reached ();
7199 decompose_pass (MonoCompile *cfg) {
7202 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
7205 cfg->prev_ins = NULL;
7206 for (tree = cfg->cbb->code; tree; tree = tree->next) {
7207 dec_foreach (tree, cfg);
7208 cfg->prev_ins = tree;
7214 nullify_basic_block (MonoBasicBlock *bb)
7221 bb->code = bb->last_ins = NULL;
7222 bb->cil_code = NULL;
7226 replace_out_block (MonoBasicBlock *bb, MonoBasicBlock *orig, MonoBasicBlock *repl)
7230 for (i = 0; i < bb->out_count; i++) {
7231 MonoBasicBlock *ob = bb->out_bb [i];
7234 if (bb->out_count > 1) {
7235 bb->out_bb [i] = bb->out_bb [bb->out_count - 1];
7239 bb->out_bb [i] = repl;
7246 replace_in_block (MonoBasicBlock *bb, MonoBasicBlock *orig, MonoBasicBlock *repl)
7250 for (i = 0; i < bb->in_count; i++) {
7251 MonoBasicBlock *ib = bb->in_bb [i];
7254 if (bb->in_count > 1) {
7255 bb->in_bb [i] = bb->in_bb [bb->in_count - 1];
7259 bb->in_bb [i] = repl;
7266 replace_basic_block (MonoBasicBlock *bb, MonoBasicBlock *orig, MonoBasicBlock *repl)
7270 for (i = 0; i < bb->out_count; i++) {
7271 MonoBasicBlock *ob = bb->out_bb [i];
7272 for (j = 0; j < ob->in_count; j++) {
7273 if (ob->in_bb [j] == orig) {
7274 ob->in_bb [j] = repl;
7283 merge_basic_blocks (MonoBasicBlock *bb, MonoBasicBlock *bbn)
7285 bb->out_count = bbn->out_count;
7286 bb->out_bb = bbn->out_bb;
7288 replace_basic_block (bb, bbn, bb);
7292 bb->last_ins->next = bbn->code;
7293 bb->last_ins = bbn->last_ins;
7296 bb->code = bbn->code;
7297 bb->last_ins = bbn->last_ins;
7299 bb->next_bb = bbn->next_bb;
7300 nullify_basic_block (bbn);
7304 move_basic_block_to_end (MonoCompile *cfg, MonoBasicBlock *bb)
7306 MonoBasicBlock *bbn;
7308 /* Find the previous */
7309 for (bbn = cfg->bb_entry; bbn->next_bb && bbn->next_bb != bb; bbn = bbn->next_bb)
7312 bbn->next_bb = bb->next_bb;
7316 for (bbn = cfg->bb_entry; bbn->next_bb; bbn = bbn->next_bb)
7323 * Optimizes the branches on the Control Flow Graph
7327 optimize_branches (MonoCompile *cfg)
7329 int i, changed = FALSE;
7330 MonoBasicBlock *bb, *bbn;
7331 guint32 niterations;
7334 * Some crazy loops could cause the code below to go into an infinite
7335 * loop, see bug #53003 for an example. To prevent this, we put an upper
7336 * bound on the number of iterations.
7343 /* we skip the entry block (exit is handled specially instead ) */
7344 for (bb = cfg->bb_entry->next_bb; bb; bb = bb->next_bb) {
7346 /* dont touch code inside exception clauses */
7347 if (bb->region != -1)
7350 if ((bbn = bb->next_bb) && bbn->in_count == 0 && bb->region == bbn->region) {
7351 if (cfg->verbose_level > 2)
7352 g_print ("nullify block triggered %d\n", bbn->block_num);
7354 bb->next_bb = bbn->next_bb;
7356 for (i = 0; i < bbn->out_count; i++)
7357 replace_in_block (bbn->out_bb [i], bbn, NULL);
7359 nullify_basic_block (bbn);
7363 if (bb->out_count == 1) {
7364 bbn = bb->out_bb [0];
7366 /* conditional branches where true and false targets are the same can be also replaced with CEE_BR */
7367 if (bb->last_ins && MONO_IS_COND_BRANCH_OP (bb->last_ins)) {
7368 bb->last_ins->opcode = CEE_BR;
7369 bb->last_ins->inst_target_bb = bb->last_ins->inst_true_bb;
7371 if (cfg->verbose_level > 2)
7372 g_print ("cond branch removal triggered in %d %d\n", bb->block_num, bb->out_count);
7375 if (bb->region == bbn->region && bb->next_bb == bbn) {
7376 /* the block are in sequence anyway ... */
7378 /* branches to the following block can be removed */
7379 if (bb->last_ins && bb->last_ins->opcode == CEE_BR) {
7380 bb->last_ins->opcode = CEE_NOP;
7382 if (cfg->verbose_level > 2)
7383 g_print ("br removal triggered %d -> %d\n", bb->block_num, bbn->block_num);
7386 if (bbn->in_count == 1) {
7388 if (bbn != cfg->bb_exit) {
7389 if (cfg->verbose_level > 2)
7390 g_print ("block merge triggered %d -> %d\n", bb->block_num, bbn->block_num);
7391 merge_basic_blocks (bb, bbn);
7395 //mono_print_bb_code (bb);
7400 } while (changed && (niterations > 0));
7407 /* we skip the entry block (exit is handled specially instead ) */
7408 for (bb = cfg->bb_entry->next_bb; bb; bb = bb->next_bb) {
7410 /* dont touch code inside exception clauses */
7411 if (bb->region != -1)
7414 if ((bbn = bb->next_bb) && bbn->in_count == 0 && bb->region == bbn->region) {
7415 if (cfg->verbose_level > 2) {
7416 g_print ("nullify block triggered %d\n", bbn->block_num);
7418 bb->next_bb = bbn->next_bb;
7420 for (i = 0; i < bbn->out_count; i++)
7421 replace_in_block (bbn->out_bb [i], bbn, NULL);
7423 nullify_basic_block (bbn);
7429 if (bb->out_count == 1) {
7430 bbn = bb->out_bb [0];
7432 if (bb->last_ins && bb->last_ins->opcode == CEE_BR) {
7433 bbn = bb->last_ins->inst_target_bb;
7434 if (bb->region == bbn->region && bbn->code && bbn->code->opcode == CEE_BR &&
7435 bbn->code->inst_target_bb->region == bb->region) {
7437 if (cfg->verbose_level > 2)
7438 g_print ("in %s branch to branch triggered %d -> %d -> %d\n", cfg->method->name,
7439 bb->block_num, bbn->block_num, bbn->code->inst_target_bb->block_num);
7441 replace_in_block (bbn, bb, NULL);
7442 replace_out_block (bb, bbn, bbn->code->inst_target_bb);
7443 link_bblock (cfg, bb, bbn->code->inst_target_bb);
7444 bb->last_ins->inst_target_bb = bbn->code->inst_target_bb;
7449 } else if (bb->out_count == 2) {
7450 if (bb->last_ins && MONO_IS_COND_BRANCH_NOFP (bb->last_ins)) {
7451 bbn = bb->last_ins->inst_true_bb;
7452 if (bb->region == bbn->region && bbn->code && bbn->code->opcode == CEE_BR &&
7453 bbn->code->inst_target_bb->region == bb->region) {
7454 if (cfg->verbose_level > 2)
7455 g_print ("cbranch1 to branch triggered %d -> (%d) %d (0x%02x)\n",
7456 bb->block_num, bbn->block_num, bbn->code->inst_target_bb->block_num,
7459 bb->last_ins->inst_true_bb = bbn->code->inst_target_bb;
7461 replace_in_block (bbn, bb, NULL);
7463 replace_in_block (bbn->code->inst_target_bb, bbn, bb);
7464 replace_out_block (bb, bbn, bbn->code->inst_target_bb);
7466 link_bblock (cfg, bb, bbn->code->inst_target_bb);
7472 bbn = bb->last_ins->inst_false_bb;
7473 if (bb->region == bbn->region && bbn->code && bbn->code->opcode == CEE_BR &&
7474 bbn->code->inst_target_bb->region == bb->region) {
7475 if (cfg->verbose_level > 2)
7476 g_print ("cbranch2 to branch triggered %d -> (%d) %d (0x%02x)\n",
7477 bb->block_num, bbn->block_num, bbn->code->inst_target_bb->block_num,
7480 bb->last_ins->inst_false_bb = bbn->code->inst_target_bb;
7482 replace_in_block (bbn, bb, NULL);
7484 replace_in_block (bbn->code->inst_target_bb, bbn, bb);
7485 replace_out_block (bb, bbn, bbn->code->inst_target_bb);
7487 link_bblock (cfg, bb, bbn->code->inst_target_bb);
7494 #ifdef MONO_ARCH_HAVE_OUT_OF_LINE_BBLOCKS
7495 if (bb->last_ins && MONO_IS_COND_BRANCH_NOFP (bb->last_ins)) {
7496 if (bb->last_ins->inst_false_bb->out_of_line) {
7497 /* Reverse the branch */
7498 bb->last_ins->opcode = reverse_branch_op (bb->last_ins->opcode);
7499 bbn = bb->last_ins->inst_false_bb;
7500 bb->last_ins->inst_false_bb = bb->last_ins->inst_true_bb;
7501 bb->last_ins->inst_true_bb = bbn;
7503 move_basic_block_to_end (cfg, bb->last_ins->inst_true_bb);
7504 if (cfg->verbose_level > 2)
7505 g_print ("cbranch to throw block triggered %d.\n",
7512 } while (changed && (niterations > 0));
7517 mono_compile_create_vars (MonoCompile *cfg)
7519 MonoMethodSignature *sig;
7520 MonoMethodHeader *header;
7523 header = mono_method_get_header (cfg->method);
7525 sig = cfg->method->signature;
7527 if (!MONO_TYPE_IS_VOID (sig->ret)) {
7528 cfg->ret = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst));
7529 cfg->ret->opcode = OP_RETARG;
7530 cfg->ret->inst_vtype = sig->ret;
7531 cfg->ret->klass = mono_class_from_mono_type (sig->ret);
7533 if (cfg->verbose_level > 2)
7534 g_print ("creating vars\n");
7537 mono_compile_create_var (cfg, &cfg->method->klass->this_arg, OP_ARG);
7539 for (i = 0; i < sig->param_count; ++i) {
7540 mono_compile_create_var (cfg, sig->params [i], OP_ARG);
7541 if (sig->params [i]->byref) {
7542 cfg->disable_ssa = TRUE;
7546 cfg->locals_start = cfg->num_varinfo;
7548 if (cfg->verbose_level > 2)
7549 g_print ("creating locals\n");
7550 for (i = 0; i < header->num_locals; ++i)
7551 mono_compile_create_var (cfg, header->locals [i], OP_LOCAL);
7552 if (cfg->verbose_level > 2)
7553 g_print ("locals done\n");
7557 mono_print_code (MonoCompile *cfg)
7561 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
7562 MonoInst *tree = bb->code;
7567 g_print ("CODE BLOCK %d (nesting %d):\n", bb->block_num, bb->nesting);
7569 for (; tree; tree = tree->next) {
7570 mono_print_tree (tree);
7575 bb->last_ins->next = NULL;
7579 extern const char * const mono_burg_rule_string [];
7582 emit_state (MonoCompile *cfg, MBState *state, int goal)
7585 int ern = mono_burg_rule (state, goal);
7586 const guint16 *nts = mono_burg_nts [ern];
7589 //g_print ("rule: %s\n", mono_burg_rule_string [ern]);
7593 // state->reg1 = state->reg2; /* chain rule */
7595 #ifdef MONO_ARCH_ENABLE_EMIT_STATE_OPT
7598 state->reg1 = mono_regstate_next_int (cfg->rs);
7599 //g_print ("alloc symbolic R%d (reg2: R%d) in block %d\n", state->reg1, state->reg2, cfg->cbb->block_num);
7602 state->reg1 = mono_regstate_next_int (cfg->rs);
7603 state->reg2 = mono_regstate_next_int (cfg->rs);
7606 state->reg1 = mono_regstate_next_float (cfg->rs);
7609 #ifdef MONO_ARCH_ENABLE_EMIT_STATE_OPT
7611 * Enabling this might cause bugs to surface in the local register
7612 * allocators on some architectures like x86.
7614 if ((state->tree->ssa_op == MONO_SSA_STORE) && (state->left->tree->opcode == OP_REGVAR)) {
7615 /* Do not optimize away reg-reg moves */
7616 if (! ((state->right->tree->ssa_op == MONO_SSA_LOAD) && (state->right->left->tree->opcode == OP_REGVAR))) {
7617 state->right->reg1 = state->left->tree->dreg;
7626 mono_burg_kids (state, ern, kids);
7628 emit_state (cfg, kids [0], nts [0]);
7630 emit_state (cfg, kids [1], nts [1]);
7632 g_assert (!nts [3]);
7633 emit_state (cfg, kids [2], nts [2]);
7638 // g_print ("emit: %s (%p)\n", mono_burg_rule_string [ern], state);
7639 if ((emit = mono_burg_func [ern]))
7640 emit (state, state->tree, cfg);
7643 #define DEBUG_SELECTION
7646 mini_select_instructions (MonoCompile *cfg)
7650 cfg->state_pool = mono_mempool_new ();
7651 cfg->rs = mono_regstate_new ();
7653 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
7654 if (bb->last_ins && MONO_IS_COND_BRANCH_OP (bb->last_ins) &&
7655 bb->next_bb != bb->last_ins->inst_false_bb) {
7657 /* we are careful when inverting, since bugs like #59580
7658 * could show up when dealing with NaNs.
7660 if (MONO_IS_COND_BRANCH_NOFP(bb->last_ins) && bb->next_bb == bb->last_ins->inst_true_bb) {
7661 MonoBasicBlock *tmp = bb->last_ins->inst_true_bb;
7662 bb->last_ins->inst_true_bb = bb->last_ins->inst_false_bb;
7663 bb->last_ins->inst_false_bb = tmp;
7665 bb->last_ins->opcode = reverse_branch_op (bb->last_ins->opcode);
7667 MonoInst *inst = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst));
7668 inst->opcode = CEE_BR;
7669 inst->inst_target_bb = bb->last_ins->inst_false_bb;
7670 mono_bblock_add_inst (bb, inst);
7675 #ifdef DEBUG_SELECTION
7676 if (cfg->verbose_level >= 4) {
7677 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
7678 MonoInst *tree = bb->code;
7679 g_print ("DUMP BLOCK %d:\n", bb->block_num);
7682 for (; tree; tree = tree->next) {
7683 mono_print_tree (tree);
7690 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
7691 MonoInst *tree = bb->code, *next;
7697 bb->last_ins = NULL;
7700 mono_regstate_reset (cfg->rs);
7702 #ifdef DEBUG_SELECTION
7703 if (cfg->verbose_level >= 3)
7704 g_print ("LABEL BLOCK %d:\n", bb->block_num);
7706 for (; tree; tree = next) {
7708 #ifdef DEBUG_SELECTION
7709 if (cfg->verbose_level >= 3) {
7710 mono_print_tree (tree);
7715 if (!(mbstate = mono_burg_label (tree, cfg))) {
7716 g_warning ("unable to label tree %p", tree);
7717 mono_print_tree (tree);
7719 g_assert_not_reached ();
7721 emit_state (cfg, mbstate, MB_NTERM_stmt);
7723 bb->max_ireg = cfg->rs->next_vireg;
7724 bb->max_freg = cfg->rs->next_vfreg;
7727 bb->last_ins->next = NULL;
7729 mono_mempool_empty (cfg->state_pool);
7731 mono_mempool_destroy (cfg->state_pool);
7735 mono_codegen (MonoCompile *cfg)
7737 MonoJumpInfo *patch_info;
7739 int i, max_epilog_size;
7742 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
7743 cfg->spill_count = 0;
7744 /* we reuse dfn here */
7745 /* bb->dfn = bb_count++; */
7746 mono_arch_local_regalloc (cfg, bb);
7749 if (cfg->prof_options & MONO_PROFILE_COVERAGE)
7750 cfg->coverage_info = mono_profiler_coverage_alloc (cfg->method, cfg->num_bblocks);
7752 code = mono_arch_emit_prolog (cfg);
7754 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
7755 code = mono_arch_instrument_prolog (cfg, mono_profiler_method_enter, code, FALSE);
7757 cfg->code_len = code - cfg->native_code;
7758 cfg->prolog_end = cfg->code_len;
7760 mono_debug_open_method (cfg);
7762 /* emit code all basic blocks */
7763 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
7764 bb->native_offset = cfg->code_len;
7765 mono_arch_output_basic_block (cfg, bb);
7767 #ifdef MONO_ARCH_HAVE_OUT_OF_LINE_BBLOCKS
7768 if (bb == cfg->bb_exit) {
7769 cfg->epilog_begin = cfg->code_len;
7771 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE) {
7772 code = mono_arch_instrument_epilog (cfg, mono_profiler_method_leave, cfg->native_code, FALSE);
7773 cfg->code_len = code - cfg->native_code;
7776 mono_arch_emit_epilog (cfg);
7781 #ifndef MONO_ARCH_HAVE_OUT_OF_LINE_BBLOCKS
7782 cfg->bb_exit->native_offset = cfg->code_len;
7783 max_epilog_size = mono_arch_max_epilog_size (cfg);
7785 mono_arch_emit_exceptions (cfg);
7787 max_epilog_size = 0;
7790 code = cfg->native_code + cfg->code_len;
7792 /* we always allocate code in cfg->domain->code_mp to increase locality */
7793 cfg->code_size = cfg->code_len + max_epilog_size;
7794 /* fixme: align to MONO_ARCH_CODE_ALIGNMENT */
7796 if (cfg->method->dynamic) {
7797 /* Allocate the code into a separate memory pool so it can be freed */
7798 cfg->dynamic_info = g_new0 (MonoJitDynamicMethodInfo, 1);
7799 cfg->dynamic_info->code_mp = mono_code_manager_new_dynamic ();
7800 mono_domain_lock (cfg->domain);
7801 mono_dynamic_code_hash_insert (cfg->domain, cfg->method, cfg->dynamic_info);
7802 mono_domain_unlock (cfg->domain);
7804 code = mono_code_manager_reserve (cfg->dynamic_info->code_mp, cfg->code_size);
7806 mono_domain_lock (cfg->domain);
7807 code = mono_code_manager_reserve (cfg->domain->code_mp, cfg->code_size);
7808 mono_domain_unlock (cfg->domain);
7811 memcpy (code, cfg->native_code, cfg->code_len);
7812 g_free (cfg->native_code);
7813 cfg->native_code = code;
7814 code = cfg->native_code + cfg->code_len;
7816 /* g_assert (((int)cfg->native_code & (MONO_ARCH_CODE_ALIGNMENT - 1)) == 0); */
7818 #ifndef MONO_ARCH_HAVE_OUT_OF_LINE_BBLOCKS
7819 cfg->epilog_begin = cfg->code_len;
7821 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
7822 code = mono_arch_instrument_epilog (cfg, mono_profiler_method_leave, code, FALSE);
7824 cfg->code_len = code - cfg->native_code;
7826 mono_arch_emit_epilog (cfg);
7829 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
7830 switch (patch_info->type) {
7831 case MONO_PATCH_INFO_ABS: {
7832 MonoJitICallInfo *info = mono_find_jit_icall_by_addr (patch_info->data.target);
7834 //printf ("TEST %s %p\n", info->name, patch_info->data.target);
7835 if ((cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) &&
7836 strstr (cfg->method->name, info->name))
7838 * This is an icall wrapper, and this is a call to the
7843 patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
7844 patch_info->data.name = info->name;
7848 MonoVTable *vtable = mono_find_class_init_trampoline_by_addr (patch_info->data.target);
7850 patch_info->type = MONO_PATCH_INFO_CLASS_INIT;
7851 patch_info->data.klass = vtable->klass;
7856 case MONO_PATCH_INFO_SWITCH: {
7858 if (cfg->method->dynamic) {
7859 table = mono_code_manager_reserve (cfg->dynamic_info->code_mp, sizeof (gpointer) * patch_info->data.table->table_size);
7861 mono_domain_lock (cfg->domain);
7862 table = mono_code_manager_reserve (cfg->domain->code_mp, sizeof (gpointer) * patch_info->data.table->table_size);
7863 mono_domain_unlock (cfg->domain);
7866 if (!cfg->compile_aot)
7867 /* In the aot case, the patch already points to the correct location */
7868 patch_info->ip.i = patch_info->ip.label->inst_c0;
7869 for (i = 0; i < patch_info->data.table->table_size; i++) {
7870 table [i] = GINT_TO_POINTER (patch_info->data.table->table [i]->native_offset);
7872 patch_info->data.table->table = (MonoBasicBlock**)table;
7881 if (cfg->verbose_level > 0)
7882 g_print ("Method %s emitted at %p to %p [%s]\n",
7883 mono_method_full_name (cfg->method, TRUE),
7884 cfg->native_code, cfg->native_code + cfg->code_len, cfg->domain->friendly_name);
7886 mono_arch_patch_code (cfg->method, cfg->domain, cfg->native_code, cfg->patch_info, cfg->run_cctors);
7888 if (cfg->method->dynamic) {
7889 mono_code_manager_commit (cfg->dynamic_info->code_mp, cfg->native_code, cfg->code_size, cfg->code_len);
7891 mono_domain_lock (cfg->domain);
7892 mono_code_manager_commit (cfg->domain->code_mp, cfg->native_code, cfg->code_size, cfg->code_len);
7893 mono_domain_unlock (cfg->domain);
7896 mono_arch_flush_icache (cfg->native_code, cfg->code_len);
7898 mono_debug_close_method (cfg);
7902 mono_cprop_copy_values (MonoCompile *cfg, MonoInst *tree, MonoInst **acp)
7907 if (tree->ssa_op == MONO_SSA_LOAD && (tree->inst_i0->opcode == OP_LOCAL || tree->inst_i0->opcode == OP_ARG) &&
7908 (cp = acp [tree->inst_i0->inst_c0]) && !tree->inst_i0->flags) {
7910 if (cp->opcode == OP_ICONST) {
7911 if (cfg->opt & MONO_OPT_CONSPROP) {
7912 //{ static int c = 0; printf ("CCOPY %d %d %s\n", c++, cp->inst_c0, mono_method_full_name (cfg->method, TRUE)); }
7916 if (tree->inst_i0->inst_vtype->type == cp->inst_vtype->type) {
7917 if (cfg->opt & MONO_OPT_COPYPROP) {
7918 //{ static int c = 0; printf ("VCOPY %d\n", ++c); }
7924 arity = mono_burg_arity [tree->opcode];
7927 mono_cprop_copy_values (cfg, tree->inst_i0, acp);
7928 if (cfg->opt & MONO_OPT_CFOLD)
7929 mono_constant_fold_inst (tree, NULL);
7930 /* The opcode may have changed */
7931 if (mono_burg_arity [tree->opcode] > 1) {
7932 mono_cprop_copy_values (cfg, tree->inst_i1, acp);
7933 if (cfg->opt & MONO_OPT_CFOLD)
7934 mono_constant_fold_inst (tree, NULL);
7936 mono_constant_fold_inst (tree, NULL);
7942 mono_cprop_invalidate_values (MonoInst *tree, MonoInst **acp, int acp_size)
7946 switch (tree->opcode) {
7956 if (tree->ssa_op == MONO_SSA_NOP) {
7957 memset (acp, 0, sizeof (MonoInst *) * acp_size);
7974 case OP_VOIDCALL_REG:
7975 case OP_VOIDCALLVIRT:
7977 MonoCallInst *call = (MonoCallInst *)tree;
7978 MonoMethodSignature *sig = call->signature;
7979 int i, byref = FALSE;
7981 for (i = 0; i < sig->param_count; i++) {
7982 if (sig->params [i]->byref) {
7989 memset (acp, 0, sizeof (MonoInst *) * acp_size);
7997 arity = mono_burg_arity [tree->opcode];
8003 mono_cprop_invalidate_values (tree->inst_i0, acp, acp_size);
8006 mono_cprop_invalidate_values (tree->inst_i0, acp, acp_size);
8007 mono_cprop_invalidate_values (tree->inst_i1, acp, acp_size);
8010 g_assert_not_reached ();
8015 mono_local_cprop_bb (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst **acp, int acp_size)
8017 MonoInst *tree = bb->code;
8023 for (; tree; tree = tree->next) {
8025 mono_cprop_copy_values (cfg, tree, acp);
8027 mono_cprop_invalidate_values (tree, acp, acp_size);
8029 if (tree->ssa_op == MONO_SSA_STORE &&
8030 (tree->inst_i0->opcode == OP_LOCAL || tree->inst_i0->opcode == OP_ARG)) {
8031 MonoInst *i1 = tree->inst_i1;
8033 acp [tree->inst_i0->inst_c0] = NULL;
8035 for (i = 0; i < acp_size; i++) {
8036 if (acp [i] && acp [i]->opcode != OP_ICONST &&
8037 acp [i]->inst_c0 == tree->inst_i0->inst_c0) {
8042 if (i1->opcode == OP_ICONST) {
8043 acp [tree->inst_i0->inst_c0] = i1;
8044 //printf ("DEF1 BB%d %d\n", bb->block_num,tree->inst_i0->inst_c0);
8046 if (i1->ssa_op == MONO_SSA_LOAD &&
8047 (i1->inst_i0->opcode == OP_LOCAL || i1->inst_i0->opcode == OP_ARG) &&
8048 (i1->inst_i0->inst_c0 != tree->inst_i0->inst_c0)) {
8049 acp [tree->inst_i0->inst_c0] = i1->inst_i0;
8050 //printf ("DEF2 BB%d %d %d\n", bb->block_num,tree->inst_i0->inst_c0,i1->inst_i0->inst_c0);
8055 if (tree->opcode == CEE_BEQ) {
8056 g_assert (tree->inst_i0->opcode == OP_COMPARE);
8057 if (tree->inst_i0->inst_i0->opcode == OP_ICONST &&
8058 tree->inst_i0->inst_i1->opcode == OP_ICONST) {
8060 tree->opcode = CEE_BR;
8061 if (tree->inst_i0->inst_i0->opcode == tree->inst_i0->inst_i1->opcode) {
8062 tree->inst_target_bb = tree->inst_true_bb;
8064 tree->inst_target_bb = tree->inst_false_bb;
8073 mono_local_cprop (MonoCompile *cfg)
8078 acp = alloca (sizeof (MonoInst *) * cfg->num_varinfo);
8080 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
8081 memset (acp, 0, sizeof (MonoInst *) * cfg->num_varinfo);
8082 mono_local_cprop_bb (cfg, bb, acp, cfg->num_varinfo);
8087 remove_critical_edges (MonoCompile *cfg) {
8090 if (cfg->verbose_level > 3) {
8091 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
8093 printf ("remove_critical_edges %s, BEFORE BB%d (in:", mono_method_full_name (cfg->method, TRUE), bb->block_num);
8094 for (i = 0; i < bb->in_count; i++) {
8095 printf (" %d", bb->in_bb [i]->block_num);
8098 for (i = 0; i < bb->out_count; i++) {
8099 printf (" %d", bb->out_bb [i]->block_num);
8102 if (bb->last_ins != NULL) {
8104 mono_print_tree (bb->last_ins);
8110 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
8111 if (bb->out_count > 1) {
8113 for (out_bb_index = 0; out_bb_index < bb->out_count; out_bb_index++) {
8114 MonoBasicBlock *out_bb = bb->out_bb [out_bb_index];
8115 if (out_bb->in_count > 1) {
8117 MonoBasicBlock *new_bb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
8118 new_bb->block_num = cfg->num_bblocks++;
8119 new_bb->next_bb = bb->next_bb;
8120 bb->next_bb = new_bb;
8121 new_bb->in_bb = mono_mempool_alloc ((cfg)->mempool, sizeof (MonoBasicBlock*));
8122 new_bb->in_bb [0] = bb;
8123 new_bb->in_count = 1;
8124 new_bb->out_bb = mono_mempool_alloc ((cfg)->mempool, sizeof (MonoBasicBlock*));
8125 new_bb->out_bb [0] = out_bb;
8126 new_bb->out_count = 1;
8127 replace_out_block (bb, out_bb, new_bb);
8128 replace_in_block (out_bb, bb, new_bb);
8129 for (inst = bb->code; inst != NULL; inst = inst->next) {
8130 if (inst->opcode == OP_CALL_HANDLER) {
8131 if (inst->inst_target_bb == out_bb) {
8132 inst->inst_target_bb = new_bb;
8136 if (bb->last_ins != NULL) {
8137 switch (bb->last_ins->opcode) {
8139 if (bb->last_ins->inst_target_bb == out_bb) {
8140 bb->last_ins->inst_target_bb = new_bb;
8145 int n = GPOINTER_TO_INT (bb->last_ins->klass);
8146 for (i = 0; i < n; i++ ) {
8147 if (bb->last_ins->inst_many_bb [i] == out_bb) {
8148 bb->last_ins->inst_many_bb [i] = new_bb;
8164 if (bb->last_ins->inst_true_bb == out_bb) {
8165 bb->last_ins->inst_true_bb = new_bb;
8167 if (bb->last_ins->inst_false_bb == out_bb) {
8168 bb->last_ins->inst_false_bb = new_bb;
8175 // new_bb->real_offset = bb->real_offset;
8176 new_bb->region = bb->region;
8178 if (new_bb->next_bb != out_bb) {
8180 MONO_INST_NEW (cfg, jump, CEE_BR);
8181 MONO_ADD_INS (new_bb, jump);
8182 jump->cil_code = bb->cil_code;
8183 jump->inst_target_bb = out_bb;
8186 if (cfg->verbose_level > 2) {
8187 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), bb->block_num, out_bb->block_num, new_bb->block_num);
8194 if (cfg->verbose_level > 3) {
8195 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
8197 printf ("remove_critical_edges %s, AFTER BB%d (in:", mono_method_full_name (cfg->method, TRUE), bb->block_num);
8198 for (i = 0; i < bb->in_count; i++) {
8199 printf (" %d", bb->in_bb [i]->block_num);
8202 for (i = 0; i < bb->out_count; i++) {
8203 printf (" %d", bb->out_bb [i]->block_num);
8206 if (bb->last_ins != NULL) {
8208 mono_print_tree (bb->last_ins);
8217 mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gboolean run_cctors, gboolean compile_aot, int parts)
8219 MonoMethodHeader *header = mono_method_get_header (method);
8220 guint8 *ip = (guint8 *)header->code;
8223 int dfn = 0, i, code_size_ratio;
8225 mono_jit_stats.methods_compiled++;
8226 if (mono_profiler_get_events () & MONO_PROFILE_JIT_COMPILATION)
8227 mono_profiler_method_jit (method);
8229 cfg = g_new0 (MonoCompile, 1);
8230 cfg->method = method;
8231 cfg->mempool = mono_mempool_new ();
8233 cfg->prof_options = mono_profiler_get_events ();
8234 cfg->run_cctors = run_cctors;
8235 cfg->bb_hash = g_hash_table_new (NULL, NULL);
8236 cfg->domain = domain;
8237 cfg->verbose_level = mini_verbose;
8238 cfg->compile_aot = compile_aot;
8239 cfg->intvars = mono_mempool_alloc0 (cfg->mempool, sizeof (guint16) * STACK_MAX *
8240 mono_method_get_header (method)->max_stack);
8242 if (cfg->verbose_level > 2)
8243 g_print ("converting method %s\n", mono_method_full_name (method, TRUE));
8246 * create MonoInst* which represents arguments and local variables
8248 mono_compile_create_vars (cfg);
8250 if ((i = mono_method_to_ir (cfg, method, NULL, NULL, cfg->locals_start, NULL, NULL, NULL, 0, FALSE)) < 0) {
8251 if (cfg->prof_options & MONO_PROFILE_JIT_COMPILATION)
8252 mono_profiler_method_end_jit (method, MONO_PROFILE_FAILED);
8253 mono_destroy_compile (cfg);
8257 mono_jit_stats.basic_blocks += cfg->num_bblocks;
8258 mono_jit_stats.max_basic_blocks = MAX (cfg->num_bblocks, mono_jit_stats.max_basic_blocks);
8260 if (cfg->num_varinfo > 2000) {
8262 * we disable some optimizations if there are too many variables
8263 * because JIT time may become too expensive. The actual number needs
8264 * to be tweaked and eventually the non-linear algorithms should be fixed.
8266 cfg->opt &= ~ (MONO_OPT_LINEARS | MONO_OPT_COPYPROP | MONO_OPT_CONSPROP);
8267 cfg->disable_ssa = TRUE;
8269 /*g_print ("numblocks = %d\n", cfg->num_bblocks);*/
8271 if (cfg->opt & MONO_OPT_BRANCH)
8272 optimize_branches (cfg);
8274 if (cfg->opt & MONO_OPT_SSAPRE) {
8275 remove_critical_edges (cfg);
8278 /* Depth-first ordering on basic blocks */
8279 cfg->bblocks = mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * (cfg->num_bblocks + 1));
8281 df_visit (cfg->bb_entry, &dfn, cfg->bblocks);
8282 if (cfg->num_bblocks != dfn + 1) {
8285 cfg->num_bblocks = dfn + 1;
8287 if (!header->clauses) {
8288 /* remove unreachable code, because the code in them may be
8289 * inconsistent (access to dead variables for example) */
8290 for (bb = cfg->bb_entry; bb;) {
8291 MonoBasicBlock *bbn = bb->next_bb;
8293 if (bbn && bbn->region == -1 && !bbn->dfn) {
8294 if (cfg->verbose_level > 1)
8295 g_print ("found unreachabel code in BB%d\n", bbn->block_num);
8296 bb->next_bb = bbn->next_bb;
8297 nullify_basic_block (bbn);
8305 if (cfg->opt & MONO_OPT_LOOP) {
8306 mono_compile_dominator_info (cfg, MONO_COMP_DOM | MONO_COMP_IDOM);
8307 mono_compute_natural_loops (cfg);
8310 /* after method_to_ir */
8314 //#define DEBUGSSA "logic_run"
8315 #define DEBUGSSA_CLASS "Tests"
8318 if (!header->num_clauses && !cfg->disable_ssa) {
8319 mono_local_cprop (cfg);
8320 mono_ssa_compute (cfg);
8324 /* fixme: add all optimizations which requires SSA */
8325 if (cfg->opt & (MONO_OPT_DEADCE | MONO_OPT_ABCREM | MONO_OPT_SSAPRE)) {
8326 if (!(cfg->comp_done & MONO_COMP_SSA) && !header->num_clauses && !cfg->disable_ssa) {
8327 mono_local_cprop (cfg);
8328 mono_ssa_compute (cfg);
8330 if (cfg->verbose_level >= 2) {
8337 /* after SSA translation */
8341 if ((cfg->opt & MONO_OPT_CONSPROP) || (cfg->opt & MONO_OPT_COPYPROP)) {
8342 if (cfg->comp_done & MONO_COMP_SSA) {
8343 mono_ssa_cprop (cfg);
8345 mono_local_cprop (cfg);
8349 if (cfg->comp_done & MONO_COMP_SSA) {
8350 mono_ssa_deadce (cfg);
8352 //mono_ssa_strength_reduction (cfg);
8354 if ((cfg->flags & MONO_CFG_HAS_LDELEMA) && (cfg->opt & MONO_OPT_ABCREM))
8355 mono_perform_abc_removal (cfg);
8357 if (cfg->opt & MONO_OPT_SSAPRE)
8358 mono_perform_ssapre (cfg);
8360 mono_ssa_remove (cfg);
8362 if (cfg->opt & MONO_OPT_BRANCH)
8363 optimize_branches (cfg);
8366 /* after SSA removal */
8370 decompose_pass (cfg);
8375 /* The decompose pass may create calls which need the got var */
8376 mono_emit_load_got_addr (cfg);
8379 * Allways allocate the GOT var to a register, because keeping it
8380 * in memory will increase the number of live temporaries in some
8381 * code created by inssel.brg, leading to the well known spills+
8382 * branches problem. Testcase: mcs crash in
8383 * System.MonoCustomAttrs:GetCustomAttributes.
8385 regs = mono_arch_get_global_int_regs (cfg);
8387 cfg->got_var->opcode = OP_REGVAR;
8388 cfg->got_var->dreg = GPOINTER_TO_INT (regs->data);
8389 cfg->used_int_regs |= 1LL << cfg->got_var->dreg;
8394 if (cfg->opt & MONO_OPT_LINEARS) {
8397 /* fixme: maybe we can avoid to compute livenesss here if already computed ? */
8398 cfg->comp_done &= ~MONO_COMP_LIVENESS;
8399 if (!(cfg->comp_done & MONO_COMP_LIVENESS))
8400 mono_analyze_liveness (cfg);
8402 if ((vars = mono_arch_get_allocatable_int_vars (cfg))) {
8403 regs = mono_arch_get_global_int_regs (cfg);
8405 regs = g_list_delete_link (regs, regs);
8406 mono_linear_scan (cfg, vars, regs, &cfg->used_int_regs);
8410 //mono_print_code (cfg);
8414 /* variables are allocated after decompose, since decompose could create temps */
8415 mono_arch_allocate_vars (cfg);
8417 if (cfg->opt & MONO_OPT_CFOLD)
8418 mono_constant_fold (cfg);
8420 mini_select_instructions (cfg);
8423 if (cfg->verbose_level >= 2) {
8424 char *id = mono_method_full_name (cfg->method, FALSE);
8425 mono_disassemble_code (cfg->native_code, cfg->code_len, id + 3);
8429 if (cfg->method->dynamic)
8430 jinfo = g_new0 (MonoJitInfo, 1);
8432 jinfo = mono_mempool_alloc0 (cfg->domain->mp, sizeof (MonoJitInfo));
8434 jinfo->method = method;
8435 jinfo->code_start = cfg->native_code;
8436 jinfo->code_size = cfg->code_len;
8437 jinfo->used_regs = cfg->used_int_regs;
8438 jinfo->domain_neutral = (cfg->opt & MONO_OPT_SHARED) != 0;
8439 jinfo->cas_inited = FALSE; /* initialization delayed at the first stalk walk using this method */
8441 if (header->num_clauses) {
8444 jinfo->exvar_offset = cfg->exvar? cfg->exvar->inst_offset: 0;
8445 jinfo->num_clauses = header->num_clauses;
8446 jinfo->clauses = mono_mempool_alloc0 (cfg->domain->mp,
8447 sizeof (MonoJitExceptionInfo) * header->num_clauses);
8449 for (i = 0; i < header->num_clauses; i++) {
8450 MonoExceptionClause *ec = &header->clauses [i];
8451 MonoJitExceptionInfo *ei = &jinfo->clauses [i];
8452 MonoBasicBlock *tblock;
8454 ei->flags = ec->flags;
8456 if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
8457 tblock = g_hash_table_lookup (cfg->bb_hash, ip + ec->data.filter_offset);
8459 ei->data.filter = cfg->native_code + tblock->native_offset;
8461 ei->data.catch_class = ec->data.catch_class;
8464 tblock = g_hash_table_lookup (cfg->bb_hash, ip + ec->try_offset);
8466 ei->try_start = cfg->native_code + tblock->native_offset;
8467 g_assert (tblock->native_offset);
8468 tblock = g_hash_table_lookup (cfg->bb_hash, ip + ec->try_offset + ec->try_len);
8470 ei->try_end = cfg->native_code + tblock->native_offset;
8471 g_assert (tblock->native_offset);
8472 tblock = g_hash_table_lookup (cfg->bb_hash, ip + ec->handler_offset);
8474 ei->handler_start = cfg->native_code + tblock->native_offset;
8478 cfg->jit_info = jinfo;
8480 mono_jit_info_table_add (cfg->domain, jinfo);
8482 if (cfg->method->dynamic)
8483 mono_dynamic_code_hash_lookup (cfg->domain, cfg->method)->ji = jinfo;
8485 /* collect statistics */
8486 mono_jit_stats.allocated_code_size += cfg->code_len;
8487 code_size_ratio = cfg->code_len;
8488 if (code_size_ratio > mono_jit_stats.biggest_method_size) {
8489 mono_jit_stats.biggest_method_size = code_size_ratio;
8490 mono_jit_stats.biggest_method = method;
8492 code_size_ratio = (code_size_ratio * 100) / mono_method_get_header (method)->code_size;
8493 if (code_size_ratio > mono_jit_stats.max_code_size_ratio) {
8494 mono_jit_stats.max_code_size_ratio = code_size_ratio;
8495 mono_jit_stats.max_ratio_method = method;
8497 mono_jit_stats.native_code_size += cfg->code_len;
8499 if (cfg->prof_options & MONO_PROFILE_JIT_COMPILATION)
8500 mono_profiler_method_end_jit (method, MONO_PROFILE_OK);
8506 mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain)
8509 GHashTable *jit_code_hash;
8510 gpointer code = NULL;
8516 jit_code_hash = target_domain->jit_code_hash;
8518 #ifdef MONO_USE_AOT_COMPILER
8519 if (!mono_compile_aot && (opt & MONO_OPT_AOT)) {
8521 MonoDomain *domain = mono_domain_get ();
8523 mono_domain_lock (domain);
8525 mono_class_init (method->klass);
8526 if ((info = mono_aot_get_method (domain, method))) {
8527 g_hash_table_insert (domain->jit_code_hash, method, info);
8528 mono_domain_unlock (domain);
8529 mono_runtime_class_init (mono_class_vtable (domain, method->klass));
8530 return info->code_start;
8533 mono_domain_unlock (domain);
8537 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
8538 (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
8540 MonoMethodPInvoke* piinfo = (MonoMethodPInvoke *) method;
8542 if (!piinfo->addr) {
8543 if (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL)
8544 piinfo->addr = mono_lookup_internal_call (method);
8546 if (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
8547 mono_lookup_pinvoke_call (method, NULL, NULL);
8549 nm = mono_marshal_get_native_wrapper (method);
8550 return mono_compile_method (nm);
8552 //if (mono_debug_format != MONO_DEBUG_FORMAT_NONE)
8553 //mono_debug_add_wrapper (method, nm);
8554 } else if ((method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME)) {
8555 const char *name = method->name;
8558 if (method->klass->parent == mono_defaults.multicastdelegate_class) {
8559 if (*name == '.' && (strcmp (name, ".ctor") == 0)) {
8560 /* FIXME: uhm, we need a wrapper to handle exceptions? */
8561 return (gpointer)mono_delegate_ctor;
8562 } else if (*name == 'I' && (strcmp (name, "Invoke") == 0)) {
8563 nm = mono_marshal_get_delegate_invoke (method);
8564 return mono_jit_compile_method (nm);
8565 } else if (*name == 'B' && (strcmp (name, "BeginInvoke") == 0)) {
8566 nm = mono_marshal_get_delegate_begin_invoke (method);
8567 return mono_jit_compile_method (nm);
8568 } else if (*name == 'E' && (strcmp (name, "EndInvoke") == 0)) {
8569 nm = mono_marshal_get_delegate_end_invoke (method);
8570 return mono_jit_compile_method (nm);
8576 cfg = mini_method_compile (method, opt, target_domain, TRUE, FALSE, 0);
8578 mono_domain_lock (target_domain);
8580 /* Check if some other thread already did the job. In this case, we can
8581 discard the code this thread generated. */
8583 if ((info = g_hash_table_lookup (target_domain->jit_code_hash, method))) {
8584 /* We can't use a domain specific method in another domain */
8585 if ((target_domain == mono_domain_get ()) || info->domain_neutral) {
8586 code = info->code_start;
8587 // printf("Discarding code for method %s\n", method->name);
8592 g_hash_table_insert (jit_code_hash, method, cfg->jit_info);
8593 code = cfg->native_code;
8596 mono_destroy_compile (cfg);
8598 if (target_domain->jump_target_hash) {
8599 MonoJumpInfo patch_info;
8601 list = g_hash_table_lookup (target_domain->jump_target_hash, method);
8603 patch_info.next = NULL;
8604 patch_info.ip.i = 0;
8605 patch_info.type = MONO_PATCH_INFO_METHOD_JUMP;
8606 patch_info.data.method = method;
8607 g_hash_table_remove (target_domain->jump_target_hash, method);
8609 for (tmp = list; tmp; tmp = tmp->next)
8610 mono_arch_patch_code (NULL, target_domain, tmp->data, &patch_info, TRUE);
8611 g_slist_free (list);
8614 mono_domain_unlock (target_domain);
8616 mono_runtime_class_init (mono_class_vtable (target_domain, method->klass));
8621 mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt)
8623 /* FIXME: later copy the code from mono */
8624 MonoDomain *target_domain, *domain = mono_domain_get ();
8628 if (opt & MONO_OPT_SHARED)
8629 target_domain = mono_get_root_domain ();
8631 target_domain = domain;
8633 mono_domain_lock (target_domain);
8635 if ((info = g_hash_table_lookup (target_domain->jit_code_hash, method))) {
8636 /* We can't use a domain specific method in another domain */
8637 if (! ((domain != target_domain) && !info->domain_neutral)) {
8638 mono_domain_unlock (target_domain);
8639 mono_jit_stats.methods_lookups++;
8640 mono_runtime_class_init (mono_class_vtable (domain, method->klass));
8641 return info->code_start;
8645 mono_domain_unlock (target_domain);
8646 p = mono_jit_compile_method_inner (method, target_domain);
8651 mono_jit_compile_method (MonoMethod *method)
8653 return mono_jit_compile_method_with_opt (method, default_opt);
8657 invalidated_delegate_trampoline (MonoClass *klass)
8659 g_error ("Unmanaged code called delegate of type %s which was already garbage collected.\n"
8660 "See http://www.go-mono.com/delegate.html for an explanation and ways to fix this.",
8661 mono_type_full_name (&klass->byval_arg));
8665 * mono_jit_free_method:
8667 * Free all memory allocated by the JIT for METHOD.
8670 mono_jit_free_method (MonoDomain *domain, MonoMethod *method)
8672 MonoJitDynamicMethodInfo *ji;
8674 g_assert (method->dynamic);
8676 mono_domain_lock (domain);
8677 ji = mono_dynamic_code_hash_lookup (domain, method);
8678 mono_domain_unlock (domain);
8679 #ifdef MONO_ARCH_HAVE_INVALIDATE_METHOD
8680 /* FIXME: only enable this with a env var */
8681 if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
8683 * Instead of freeing the code, change it to call an error routine
8684 * so people can fix their code.
8687 char *type = mono_type_full_name (&method->klass->byval_arg);
8688 char *type_and_method = g_strdup_printf ("%s.%s", type, method->name);
8691 mono_arch_invalidate_method (ji->ji, invalidated_delegate_trampoline, type_and_method);
8699 mono_domain_lock (domain);
8700 g_hash_table_remove (domain->dynamic_code_hash, ji);
8701 mono_domain_unlock (domain);
8703 mono_code_manager_destroy (ji->code_mp);
8704 mono_jit_info_table_remove (domain, ji->ji);
8710 mono_jit_find_compiled_method (MonoDomain *domain, MonoMethod *method)
8712 MonoDomain *target_domain;
8715 if (default_opt & MONO_OPT_SHARED)
8716 target_domain = mono_get_root_domain ();
8718 target_domain = domain;
8720 mono_domain_lock (target_domain);
8722 if ((info = g_hash_table_lookup (target_domain->jit_code_hash, method))) {
8723 /* We can't use a domain specific method in another domain */
8724 if (! ((domain != target_domain) && !info->domain_neutral)) {
8725 mono_domain_unlock (target_domain);
8726 mono_jit_stats.methods_lookups++;
8727 return info->code_start;
8731 mono_domain_unlock (target_domain);
8737 * mono_jit_runtime_invoke:
8738 * @method: the method to invoke
8739 * @obj: this pointer
8740 * @params: array of parameter values.
8741 * @exc: used to catch exceptions objects
8744 mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
8747 MonoObject *(*runtime_invoke) (MonoObject *this, void **params, MonoObject **exc, void* compiled_method);
8748 void* compiled_method;
8750 if (obj == NULL && !(method->flags & METHOD_ATTRIBUTE_STATIC) && !method->string_ctor && (method->wrapper_type == 0)) {
8751 g_warning ("Ignoring invocation of an instance method on a NULL instance.\n");
8755 invoke = mono_marshal_get_runtime_invoke (method);
8756 runtime_invoke = mono_jit_compile_method (invoke);
8758 /* We need this here becuase mono_marshal_get_runtime_invoke can be place
8759 * the helper method in System.Object and not the target class
8761 mono_runtime_class_init (mono_class_vtable (mono_domain_get (), method->klass));
8763 compiled_method = mono_jit_compile_method (method);
8764 return runtime_invoke (obj, params, exc, compiled_method);
8767 #ifdef PLATFORM_WIN32
8768 #define GET_CONTEXT \
8769 struct sigcontext *ctx = (struct sigcontext*)_dummy;
8772 #define GET_CONTEXT \
8773 void *ctx = context;
8774 #elif defined(sun) // Solaris x86
8775 #define GET_CONTEXT \
8776 ucontext_t *uctx = context; \
8777 struct sigcontext *ctx = (struct sigcontext *)&(uctx->uc_mcontext);
8778 #elif defined(__ppc__) || defined (__powerpc__) || defined (__s390__) || defined (MONO_ARCH_USE_SIGACTION)
8779 #define GET_CONTEXT \
8780 void *ctx = context;
8782 #define GET_CONTEXT \
8783 void **_p = (void **)&_dummy; \
8784 struct sigcontext *ctx = (struct sigcontext *)++_p;
8788 #ifdef MONO_ARCH_USE_SIGACTION
8789 #define SIG_HANDLER_SIGNATURE(ftn) ftn (int _dummy, siginfo_t *info, void *context)
8791 #define SIG_HANDLER_SIGNATURE(ftn) ftn (int _dummy)
8795 SIG_HANDLER_SIGNATURE (sigfpe_signal_handler)
8797 MonoException *exc = NULL;
8798 #ifndef MONO_ARCH_USE_SIGACTION
8803 #if defined(MONO_ARCH_HAVE_IS_INT_OVERFLOW)
8804 if (mono_arch_is_int_overflow (ctx, info))
8805 exc = mono_get_exception_arithmetic ();
8807 exc = mono_get_exception_divide_by_zero ();
8809 exc = mono_get_exception_divide_by_zero ();
8812 mono_arch_handle_exception (ctx, exc, FALSE);
8816 SIG_HANDLER_SIGNATURE (sigill_signal_handler)
8820 exc = mono_get_exception_execution_engine ("SIGILL");
8822 mono_arch_handle_exception (ctx, exc, FALSE);
8825 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
8828 sigsegv_signal_handler (int _dummy, siginfo_t *info, void *context)
8831 MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
8832 struct sigcontext *ctx = (struct sigcontext *)&(((ucontext_t*)context)->uc_mcontext);
8834 /* Can't allocate memory using Boehm GC on altstack */
8835 if (jit_tls->stack_size &&
8836 ((guint8*)info->si_addr >= (guint8*)jit_tls->end_of_stack - jit_tls->stack_size) &&
8837 ((guint8*)info->si_addr < (guint8*)jit_tls->end_of_stack))
8838 exc = mono_domain_get ()->stack_overflow_ex;
8840 exc = mono_domain_get ()->null_reference_ex;
8842 mono_arch_handle_exception (ctx, exc, FALSE);
8848 SIG_HANDLER_SIGNATURE (sigsegv_signal_handler)
8852 mono_arch_handle_exception (ctx, NULL, FALSE);
8858 SIG_HANDLER_SIGNATURE (sigusr1_signal_handler)
8860 gboolean running_managed;
8865 running_managed = (mono_jit_info_table_find (mono_domain_get (), mono_arch_ip_from_context(ctx)) != NULL);
8867 exc = mono_thread_request_interruption (running_managed);
8870 mono_arch_handle_exception (ctx, exc, FALSE);
8874 SIG_HANDLER_SIGNATURE (sigprof_signal_handler)
8878 mono_profiler_stat_hit (mono_arch_ip_from_context (ctx), ctx);
8882 SIG_HANDLER_SIGNATURE (sigquit_signal_handler)
8887 exc = mono_get_exception_execution_engine ("Interrupted (SIGQUIT).");
8889 mono_arch_handle_exception (ctx, exc, FALSE);
8893 SIG_HANDLER_SIGNATURE (sigint_signal_handler)
8898 exc = mono_get_exception_execution_engine ("Interrupted (SIGINT).");
8900 mono_arch_handle_exception (ctx, exc, FALSE);
8903 #ifndef PLATFORM_WIN32
8905 add_signal_handler (int signo, gpointer handler)
8907 struct sigaction sa;
8909 #ifdef MONO_ARCH_USE_SIGACTION
8910 sa.sa_sigaction = handler;
8911 sigemptyset (&sa.sa_mask);
8912 sa.sa_flags = SA_SIGINFO;
8914 sa.sa_handler = handler;
8915 sigemptyset (&sa.sa_mask);
8918 g_assert (sigaction (signo, &sa, NULL) != -1);
8923 mono_runtime_install_handlers (void)
8925 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
8926 struct sigaction sa;
8929 #ifdef PLATFORM_WIN32
8931 win32_seh_set_handler(SIGFPE, sigfpe_signal_handler);
8932 win32_seh_set_handler(SIGILL, sigill_signal_handler);
8933 win32_seh_set_handler(SIGSEGV, sigsegv_signal_handler);
8934 if (getenv ("MONO_DEBUG"))
8935 win32_seh_set_handler(SIGINT, sigint_signal_handler);
8936 #else /* !PLATFORM_WIN32 */
8938 /* libpthreads has its own implementation of sigaction(),
8939 * but it seems to work well with our current exception
8940 * handlers. If not we must call syscall directly instead
8943 if (getenv ("MONO_DEBUG")) {
8944 add_signal_handler (SIGINT, sigint_signal_handler);
8947 add_signal_handler (SIGFPE, sigfpe_signal_handler);
8948 add_signal_handler (SIGQUIT, sigquit_signal_handler);
8949 add_signal_handler (SIGILL, sigill_signal_handler);
8950 add_signal_handler (SIGBUS, sigsegv_signal_handler);
8951 add_signal_handler (mono_thread_get_abort_signal (), sigusr1_signal_handler);
8954 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
8955 sa.sa_sigaction = sigsegv_signal_handler;
8956 sigemptyset (&sa.sa_mask);
8957 sa.sa_flags = SA_SIGINFO | SA_ONSTACK;
8958 g_assert (sigaction (SIGSEGV, &sa, NULL) != -1);
8960 add_signal_handler (SIGSEGV, sigsegv_signal_handler);
8963 #endif /* PLATFORM_WIN32 */
8967 setup_stat_profiler (void)
8970 struct itimerval itval;
8971 static int inited = 0;
8973 itval.it_interval.tv_usec = 1000;
8974 itval.it_interval.tv_sec = 0;
8975 itval.it_value = itval.it_interval;
8976 setitimer (ITIMER_PROF, &itval, NULL);
8980 add_signal_handler (SIGPROF, sigprof_signal_handler);
8984 /* mono_jit_create_remoting_trampoline:
8985 * @method: pointer to the method info
8987 * Creates a trampoline which calls the remoting functions. This
8988 * is used in the vtable of transparent proxies.
8990 * Returns: a pointer to the newly created code
8993 mono_jit_create_remoting_trampoline (MonoMethod *method, MonoRemotingTarget target)
8996 guint8 *addr = NULL;
8998 if ((method->flags & METHOD_ATTRIBUTE_ABSTRACT) ||
8999 (method->signature->hasthis && (method->klass->marshalbyref || method->klass == mono_defaults.object_class))) {
9000 nm = mono_marshal_get_remoting_invoke_for_target (method, target);
9001 addr = mono_compile_method (nm);
9003 addr = mono_compile_method (method);
9009 mini_init (const char *filename)
9013 mono_arch_cpu_init ();
9015 if (!g_thread_supported ())
9016 g_thread_init (NULL);
9018 MONO_GC_PRE_INIT ();
9020 mono_jit_tls_id = TlsAlloc ();
9021 setup_jit_tls_data ((gpointer)-1, mono_thread_abort);
9023 InitializeCriticalSection (&jit_mutex);
9027 if (default_opt & MONO_OPT_AOT)
9030 mono_runtime_install_handlers ();
9031 mono_threads_install_cleanup (mini_thread_cleanup);
9033 #define JIT_TRAMPOLINES_WORK
9034 #ifdef JIT_TRAMPOLINES_WORK
9035 mono_install_compile_method (mono_jit_compile_method);
9036 mono_install_free_method (mono_jit_free_method);
9037 mono_install_trampoline (mono_create_jit_trampoline);
9038 mono_install_remoting_trampoline (mono_jit_create_remoting_trampoline);
9040 #define JIT_INVOKE_WORKS
9041 #ifdef JIT_INVOKE_WORKS
9042 mono_install_runtime_invoke (mono_jit_runtime_invoke);
9043 mono_install_handler (mono_arch_get_throw_exception ());
9045 mono_install_stack_walk (mono_jit_walk_stack);
9047 domain = mono_init_from_assembly (filename, filename);
9050 mono_add_internal_call ("System.Diagnostics.StackFrame::get_frame_info",
9051 ves_icall_get_frame_info);
9052 mono_add_internal_call ("System.Diagnostics.StackTrace::get_trace",
9053 ves_icall_get_trace);
9054 mono_add_internal_call ("System.Security.SecurityFrame::_GetSecurityFrame",
9055 ves_icall_System_Security_SecurityFrame_GetSecurityFrame);
9056 mono_add_internal_call ("System.Security.SecurityFrame::_GetSecurityStack",
9057 ves_icall_System_Security_SecurityFrame_GetSecurityStack);
9058 mono_add_internal_call ("Mono.Runtime::mono_runtime_install_handlers",
9059 mono_runtime_install_handlers);
9062 create_helper_signature ();
9064 #define JIT_CALLS_WORK
9065 #ifdef JIT_CALLS_WORK
9066 /* Needs to be called here since register_jit_icall depends on it */
9067 mono_marshal_init ();
9069 mono_arch_register_lowlevel_calls ();
9070 mono_register_jit_icall (mono_profiler_method_enter, "mono_profiler_method_enter", NULL, TRUE);
9071 mono_register_jit_icall (mono_profiler_method_leave, "mono_profiler_method_leave", NULL, TRUE);
9072 mono_register_jit_icall (mono_trace_enter_method, "mono_trace_enter_method", NULL, TRUE);
9073 mono_register_jit_icall (mono_trace_leave_method, "mono_trace_leave_method", NULL, TRUE);
9074 mono_register_jit_icall (mono_get_lmf_addr, "mono_get_lmf_addr", helper_sig_ptr_void, TRUE);
9075 mono_register_jit_icall (mono_domain_get, "mono_domain_get", helper_sig_domain_get, TRUE);
9077 mono_register_jit_icall (mono_arch_get_throw_exception (), "mono_arch_throw_exception", helper_sig_void_obj, TRUE);
9078 mono_register_jit_icall (mono_arch_get_rethrow_exception (), "mono_arch_rethrow_exception", helper_sig_void_obj, TRUE);
9079 mono_register_jit_icall (mono_arch_get_throw_exception_by_name (), "mono_arch_throw_exception_by_name",
9080 helper_sig_void_ptr, TRUE);
9081 #if MONO_ARCH_HAVE_THROW_CORLIB_EXCEPTION
9082 mono_register_jit_icall (mono_arch_get_throw_corlib_exception (), "mono_arch_throw_corlib_exception",
9083 helper_sig_void_ptr, TRUE);
9085 mono_register_jit_icall (mono_thread_get_pending_exception, "mono_thread_get_pending_exception", helper_sig_obj_void, FALSE);
9086 mono_register_jit_icall (mono_thread_interruption_checkpoint, "mono_thread_interruption_checkpoint", helper_sig_void_void, FALSE);
9087 mono_register_jit_icall (mono_thread_force_interruption_checkpoint, "mono_thread_force_interruption_checkpoint", helper_sig_void_void, FALSE);
9088 mono_register_jit_icall (mono_load_remote_field_new, "mono_load_remote_field_new", helper_sig_obj_obj_ptr_ptr, FALSE);
9089 mono_register_jit_icall (mono_store_remote_field_new, "mono_store_remote_field_new", helper_sig_void_obj_ptr_ptr_obj, FALSE);
9092 * NOTE, NOTE, NOTE, NOTE:
9093 * when adding emulation for some opcodes, remember to also add a dummy
9094 * rule to the burg files, because we need the arity information to be correct.
9096 mono_register_opcode_emulation (OP_LMUL, "__emul_lmul", helper_sig_long_long_long, mono_llmult, TRUE);
9097 mono_register_opcode_emulation (OP_LMUL_OVF_UN, "__emul_lmul_ovf_un", helper_sig_long_long_long, mono_llmult_ovf_un, FALSE);
9098 mono_register_opcode_emulation (OP_LMUL_OVF, "__emul_lmul_ovf", helper_sig_long_long_long, mono_llmult_ovf, FALSE);
9099 mono_register_opcode_emulation (OP_LDIV, "__emul_ldiv", helper_sig_long_long_long, mono_lldiv, FALSE);
9100 mono_register_opcode_emulation (OP_LDIV_UN, "__emul_ldiv_un", helper_sig_long_long_long, mono_lldiv_un, FALSE);
9101 mono_register_opcode_emulation (OP_LREM, "__emul_lrem", helper_sig_long_long_long, mono_llrem, FALSE);
9102 mono_register_opcode_emulation (OP_LREM_UN, "__emul_lrem_un", helper_sig_long_long_long, mono_llrem_un, FALSE);
9104 #ifndef MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
9105 mono_register_opcode_emulation (OP_LSHL, "__emul_lshl", helper_sig_long_long_int, mono_lshl, TRUE);
9106 mono_register_opcode_emulation (OP_LSHR, "__emul_lshr", helper_sig_long_long_int, mono_lshr, TRUE);
9107 mono_register_opcode_emulation (OP_LSHR_UN, "__emul_lshr_un", helper_sig_long_long_int, mono_lshr_un, TRUE);
9110 mono_register_opcode_emulation (OP_FCONV_TO_U8, "__emul_fconv_to_u8", helper_sig_ulong_double, mono_fconv_u8, FALSE);
9111 mono_register_opcode_emulation (OP_FCONV_TO_U4, "__emul_fconv_to_u4", helper_sig_uint_double, mono_fconv_u4, FALSE);
9112 mono_register_opcode_emulation (OP_FCONV_TO_OVF_I8, "__emul_fconv_to_ovf_i8", helper_sig_long_double, mono_fconv_ovf_i8, FALSE);
9113 mono_register_opcode_emulation (OP_FCONV_TO_OVF_U8, "__emul_fconv_to_ovf_u8", helper_sig_ulong_double, mono_fconv_ovf_u8, FALSE);
9115 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
9116 mono_register_opcode_emulation (OP_FCONV_TO_I8, "__emul_fconv_to_i8", helper_sig_long_double, mono_fconv_i8, FALSE);
9118 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
9119 mono_register_opcode_emulation (CEE_CONV_R_UN, "__emul_conv_r_un", helper_sig_double_int, mono_conv_to_r8_un, FALSE);
9121 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
9122 mono_register_opcode_emulation (OP_LCONV_TO_R8, "__emul_lconv_to_r8", helper_sig_double_long, mono_lconv_to_r8, FALSE);
9124 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
9125 mono_register_opcode_emulation (OP_LCONV_TO_R4, "__emul_lconv_to_r4", helper_sig_float_long, mono_lconv_to_r4, FALSE);
9127 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
9128 mono_register_opcode_emulation (OP_LCONV_TO_R_UN, "__emul_lconv_to_r8_un", helper_sig_double_long, mono_lconv_to_r8_un, FALSE);
9130 #ifdef MONO_ARCH_EMULATE_FREM
9131 mono_register_opcode_emulation (OP_FREM, "__emul_frem", helper_sig_double_double_double, fmod, FALSE);
9134 #if SIZEOF_VOID_P == 4
9135 mono_register_opcode_emulation (OP_FCONV_TO_U, "__emul_fconv_to_u", helper_sig_uint_double, mono_fconv_u4, TRUE);
9138 #warning "fixme: add opcode emulation"
9142 /* other jit icalls */
9143 mono_register_jit_icall (mono_class_static_field_address , "mono_class_static_field_address",
9144 helper_sig_ptr_ptr_ptr, FALSE);
9145 mono_register_jit_icall (mono_ldtoken_wrapper, "mono_ldtoken_wrapper", helper_sig_ptr_ptr_ptr_ptr, FALSE);
9146 mono_register_jit_icall (mono_get_special_static_data, "mono_get_special_static_data", helper_sig_ptr_int, FALSE);
9147 mono_register_jit_icall (mono_ldstr, "mono_ldstr", helper_sig_ldstr, FALSE);
9148 mono_register_jit_icall (helper_memcpy, "helper_memcpy", helper_sig_memcpy, FALSE);
9149 mono_register_jit_icall (helper_memset, "helper_memset", helper_sig_memset, FALSE);
9150 mono_register_jit_icall (helper_initobj, "helper_initobj", helper_sig_initobj, FALSE);
9151 mono_register_jit_icall (helper_stelem_ref, "helper_stelem_ref", helper_sig_stelem_ref, FALSE);
9152 mono_register_jit_icall (helper_stelem_ref_check, "helper_stelem_ref_check", helper_sig_stelem_ref_check, FALSE);
9153 mono_register_jit_icall (mono_object_new, "mono_object_new", helper_sig_object_new, FALSE);
9154 mono_register_jit_icall (mono_object_new_specific, "mono_object_new_specific", helper_sig_object_new_specific, FALSE);
9155 mono_register_jit_icall (mono_array_new, "mono_array_new", helper_sig_newarr, FALSE);
9156 mono_register_jit_icall (mono_array_new_specific, "mono_array_new_specific", helper_sig_newarr_specific, FALSE);
9157 mono_register_jit_icall (mono_runtime_class_init, "mono_runtime_class_init", helper_sig_void_ptr, FALSE);
9158 mono_register_jit_icall (mono_ldftn, "mono_ldftn", helper_sig_compile, FALSE);
9159 mono_register_jit_icall (mono_ldftn_nosync, "mono_ldftn_nosync", helper_sig_compile, FALSE);
9160 mono_register_jit_icall (mono_ldvirtfn, "mono_ldvirtfn", helper_sig_compile_virt, FALSE);
9161 mono_register_jit_icall (helper_compile_generic_method, "compile_generic_method", helper_sig_compile_generic_method, FALSE);
9164 #define JIT_RUNTIME_WORKS
9165 #ifdef JIT_RUNTIME_WORKS
9166 mono_install_runtime_cleanup ((MonoDomainFunc)mini_cleanup);
9167 mono_runtime_init (domain, mono_thread_start_cb, mono_thread_attach_cb);
9170 mono_thread_attach (domain);
9174 MonoJitStats mono_jit_stats = {0};
9177 print_jit_stats (void)
9179 if (mono_jit_stats.enabled) {
9180 g_print ("Mono Jit statistics\n");
9181 g_print ("Compiled methods: %ld\n", mono_jit_stats.methods_compiled);
9182 g_print ("Methods from AOT: %ld\n", mono_jit_stats.methods_aot);
9183 g_print ("Methods cache lookup: %ld\n", mono_jit_stats.methods_lookups);
9184 g_print ("Method trampolines: %ld\n", mono_jit_stats.method_trampolines);
9185 g_print ("Basic blocks: %ld\n", mono_jit_stats.basic_blocks);
9186 g_print ("Max basic blocks: %ld\n", mono_jit_stats.max_basic_blocks);
9187 g_print ("Allocated vars: %ld\n", mono_jit_stats.allocate_var);
9188 g_print ("Analyze stack repeat: %ld\n", mono_jit_stats.analyze_stack_repeat);
9189 g_print ("Compiled CIL code size: %ld\n", mono_jit_stats.cil_code_size);
9190 g_print ("Native code size: %ld\n", mono_jit_stats.native_code_size);
9191 g_print ("Max code size ratio: %.2f (%s::%s)\n", mono_jit_stats.max_code_size_ratio/100.0,
9192 mono_jit_stats.max_ratio_method->klass->name, mono_jit_stats.max_ratio_method->name);
9193 g_print ("Biggest method: %ld (%s::%s)\n", mono_jit_stats.biggest_method_size,
9194 mono_jit_stats.biggest_method->klass->name, mono_jit_stats.biggest_method->name);
9195 g_print ("Code reallocs: %ld\n", mono_jit_stats.code_reallocs);
9196 g_print ("Allocated code size: %ld\n", mono_jit_stats.allocated_code_size);
9197 g_print ("Inlineable methods: %ld\n", mono_jit_stats.inlineable_methods);
9198 g_print ("Inlined methods: %ld\n", mono_jit_stats.inlined_methods);
9200 g_print ("\nCreated object count: %ld\n", mono_stats.new_object_count);
9201 g_print ("Initialized classes: %ld\n", mono_stats.initialized_class_count);
9202 g_print ("Used classes: %ld\n", mono_stats.used_class_count);
9203 g_print ("Static data size: %ld\n", mono_stats.class_static_data_size);
9204 g_print ("VTable data size: %ld\n", mono_stats.class_vtable_size);
9206 g_print ("\nGeneric instances: %ld\n", mono_stats.generic_instance_count);
9207 g_print ("Initialized classes: %ld\n", mono_stats.generic_class_count);
9208 g_print ("Inflated methods: %ld / %ld\n", mono_stats.inflated_method_count_2,
9209 mono_stats.inflated_method_count);
9210 g_print ("Inflated types: %ld\n", mono_stats.inflated_type_count);
9211 g_print ("Generics metadata size: %ld\n", mono_stats.generics_metadata_size);
9216 mini_cleanup (MonoDomain *domain)
9219 * mono_runtime_cleanup() and mono_domain_finalize () need to
9220 * be called early since they need the execution engine still
9221 * fully working (mono_domain_finalize may invoke managed finalizers
9222 * and mono_runtime_cleanup will wait for other threads to finish).
9224 mono_domain_finalize (domain, 2000);
9226 mono_runtime_cleanup (domain);
9228 mono_profiler_shutdown ();
9230 mono_debug_cleanup ();
9232 #ifdef PLATFORM_WIN32
9233 win32_seh_cleanup();
9236 mono_domain_free (domain, TRUE);
9242 mono_set_defaults (int verbose_level, guint32 opts)
9244 mini_verbose = verbose_level;
9249 mono_precompile_assembly (MonoAssembly *ass, void *user_data)
9251 MonoImage *image = mono_assembly_get_image (ass);
9252 MonoMethod *method, *invoke;
9255 if (mini_verbose > 0)
9256 printf ("PRECOMPILE: %s.\n", mono_image_get_filename (image));
9258 for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_METHOD); ++i) {
9259 method = mono_get_method (image, MONO_TOKEN_METHOD_DEF | (i + 1), NULL);
9260 if (method->flags & METHOD_ATTRIBUTE_ABSTRACT)
9264 if (mini_verbose > 1) {
9265 char * desc = mono_method_full_name (method, TRUE);
9266 g_print ("Compiling %d %s\n", count, desc);
9269 mono_compile_method (method);
9270 if (strcmp (method->name, "Finalize") == 0) {
9271 invoke = mono_marshal_get_runtime_invoke (method);
9272 mono_compile_method (invoke);
9274 if (method->klass->marshalbyref && method->signature->hasthis) {
9275 invoke = mono_marshal_get_remoting_invoke_with_check (method);
9276 mono_compile_method (invoke);
9281 void mono_precompile_assemblies ()
9283 mono_assembly_foreach ((GFunc)mono_precompile_assembly, NULL);