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/metadata/security-manager.h>
51 #include <mono/metadata/threads-types.h>
52 #include <mono/metadata/rawbuffer.h>
53 #include <mono/utils/mono-math.h>
54 #include <mono/utils/mono-compiler.h>
55 #include <mono/os/gc_wrapper.h>
63 #include "jit-icalls.c"
66 * this is used to determine when some branch optimizations are possible: we exclude FP compares
67 * because they have weird semantics with NaNs.
69 #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))
70 #define MONO_IS_COND_BRANCH_NOFP(ins) (MONO_IS_COND_BRANCH_OP(ins) && (ins)->inst_left->inst_left->type != STACK_R8)
72 #define MONO_CHECK_THIS(ins) (mono_method_signature (cfg->method)->hasthis && (ins)->ssa_op == MONO_SSA_LOAD && (ins)->inst_left->inst_c0 == 0)
74 static void setup_stat_profiler (void);
75 gboolean mono_arch_print_tree(MonoInst *tree, int arity);
76 static gpointer mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt);
77 static gpointer mono_jit_compile_method (MonoMethod *method);
78 static gpointer mono_jit_find_compiled_method (MonoDomain *domain, MonoMethod *method);
80 static void handle_stobj (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *dest, MonoInst *src,
81 const unsigned char *ip, MonoClass *klass, gboolean to_end, gboolean native);
83 static void dec_foreach (MonoInst *tree, MonoCompile *cfg);
85 static int mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock,
86 int locals_offset, MonoInst *return_var, GList *dont_inline, MonoInst **inline_args,
87 guint inline_offset, gboolean is_virtual_call);
89 extern guint8 mono_burg_arity [];
90 /* helper methods signature */
91 static MonoMethodSignature *helper_sig_class_init_trampoline = NULL;
92 static MonoMethodSignature *helper_sig_domain_get = NULL;
94 static guint32 default_opt = 0;
96 guint32 mono_jit_tls_id = -1;
97 MonoTraceSpec *mono_jit_trace_calls = NULL;
98 gboolean mono_break_on_exc = FALSE;
100 gboolean mono_compile_aot = FALSE;
102 gboolean mono_use_security_manager = FALSE;
104 static int mini_verbose = 0;
106 static CRITICAL_SECTION jit_mutex;
108 static GHashTable *class_init_hash_addr = NULL;
110 static MonoCodeManager *global_codeman = NULL;
112 static GHashTable *jit_icall_name_hash = NULL;
114 static MonoDebugOptions debug_options;
117 * Address of the trampoline code. This is used by the debugger to check
118 * whether a method is a trampoline.
120 guint8* mono_trampoline_code [MONO_TRAMPOLINE_NUM];
123 mono_running_on_valgrind (void)
125 #ifdef HAVE_VALGRIND_MEMCHECK_H
126 if (RUNNING_ON_VALGRIND)
136 * mono_create_ftnptr:
138 * Given a function address, create a function descriptor for it.
139 * This is only needed on IA64.
142 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
147 mono_domain_lock (domain);
148 desc = mono_code_manager_reserve (domain->code_mp, 2 * sizeof (gpointer));
149 mono_domain_unlock (domain);
161 G_GNUC_UNUSED static char*
162 get_method_from_ip (void *ip)
168 MonoDomain *domain = mono_domain_get ();
170 ji = mono_jit_info_table_find (domain, ip);
174 method = mono_method_full_name (ji->method, TRUE);
175 source = mono_debug_source_location_from_address (ji->method, (guint32)((guint8*)ip - (guint8*)ji->code_start), NULL, domain);
177 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);
186 G_GNUC_UNUSED static void
187 print_method_from_ip (void *ip)
192 MonoDomain *domain = mono_domain_get ();
194 ji = mono_jit_info_table_find (domain, ip);
196 g_print ("No method at %p\n", ip);
199 method = mono_method_full_name (ji->method, TRUE);
200 source = mono_debug_source_location_from_address (ji->method, (guint32)((guint8*)ip - (guint8*)ji->code_start), NULL, domain);
202 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);
205 g_print ("%s\n", source);
212 mono_print_method_from_ip (void *ip)
214 print_method_from_ip (ip);
218 * mono_method_same_domain:
220 * Determine whenever two compiled methods are in the same domain, thus
221 * the address of the callee can be embedded in the caller.
223 gboolean mono_method_same_domain (MonoJitInfo *caller, MonoJitInfo *callee)
225 if (!caller || !callee)
229 * If the call was made from domain-neutral to domain-specific
230 * code, we can't patch the call site.
232 if (caller->domain_neutral && !callee->domain_neutral)
235 if ((caller->method->klass == mono_defaults.appdomain_class) &&
236 (strstr (caller->method->name, "InvokeInDomain"))) {
237 /* The InvokeInDomain methods change the current appdomain */
245 * mono_global_codeman_reserve:
247 * Allocate code memory from the global code manager.
249 void *mono_global_codeman_reserve (int size)
253 if (!global_codeman) {
254 /* This can happen during startup */
255 global_codeman = mono_code_manager_new ();
256 return mono_code_manager_reserve (global_codeman, size);
259 EnterCriticalSection (&jit_mutex);
260 ptr = mono_code_manager_reserve (global_codeman, size);
261 LeaveCriticalSection (&jit_mutex);
267 mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
269 MonoJumpInfoToken *res = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoToken));
276 #define MONO_INIT_VARINFO(vi,id) do { \
277 (vi)->range.first_use.pos.bid = 0xffff; \
283 * Basic blocks have two numeric identifiers:
284 * dfn: Depth First Number
285 * block_num: unique ID assigned at bblock creation
287 #define NEW_BBLOCK(cfg) (mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock)))
288 #define ADD_BBLOCK(cfg,bbhash,b) do { \
289 g_hash_table_insert (bbhash, (b)->cil_code, (b)); \
290 (b)->block_num = cfg->num_bblocks++; \
291 (b)->real_offset = real_offset; \
294 #define GET_BBLOCK(cfg,bbhash,tblock,ip) do { \
295 (tblock) = g_hash_table_lookup (bbhash, (ip)); \
297 if ((ip) >= end || (ip) < header->code) goto unverified; \
298 (tblock) = NEW_BBLOCK (cfg); \
299 (tblock)->cil_code = (ip); \
300 ADD_BBLOCK (cfg, (bbhash), (tblock)); \
304 #define CHECK_BBLOCK(target,ip,tblock) do { \
305 if ((target) < (ip) && !(tblock)->code) { \
306 bb_recheck = g_list_prepend (bb_recheck, (tblock)); \
307 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)); \
311 #define NEW_ICONST(cfg,dest,val) do { \
312 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
313 (dest)->opcode = OP_ICONST; \
314 (dest)->inst_c0 = (val); \
315 (dest)->type = STACK_I4; \
318 #define NEW_PCONST(cfg,dest,val) do { \
319 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
320 (dest)->opcode = OP_PCONST; \
321 (dest)->inst_p0 = (val); \
322 (dest)->type = STACK_PTR; \
326 #ifdef MONO_ARCH_NEED_GOT_VAR
328 #define NEW_PATCH_INFO(cfg,dest,el1,el2) do { \
329 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
330 (dest)->opcode = OP_PATCH_INFO; \
331 (dest)->inst_left = (gpointer)(el1); \
332 (dest)->inst_right = (gpointer)(el2); \
335 #define NEW_AOTCONST(cfg,dest,patch_type,cons) do { \
336 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
337 (dest)->opcode = cfg->compile_aot ? OP_GOT_ENTRY : OP_PCONST; \
338 if (cfg->compile_aot) { \
339 MonoInst *group, *got_var, *got_loc; \
340 got_loc = mono_get_got_var (cfg); \
341 NEW_TEMPLOAD ((cfg), got_var, got_loc->inst_c0); \
342 NEW_PATCH_INFO ((cfg), group, cons, patch_type); \
343 (dest)->inst_p0 = got_var; \
344 (dest)->inst_p1 = group; \
346 (dest)->inst_p0 = (cons); \
347 (dest)->inst_i1 = (gpointer)(patch_type); \
349 (dest)->type = STACK_PTR; \
352 #define NEW_AOTCONST_TOKEN(cfg,dest,patch_type,image,token,stack_type) do { \
353 MonoInst *group, *got_var, *got_loc; \
354 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
355 (dest)->opcode = OP_GOT_ENTRY; \
356 got_loc = mono_get_got_var (cfg); \
357 NEW_TEMPLOAD ((cfg), got_var, got_loc->inst_c0); \
358 NEW_PATCH_INFO ((cfg), group, NULL, patch_type); \
359 group->inst_p0 = mono_jump_info_token_new ((cfg)->mempool, (image), (token)); \
360 (dest)->inst_p0 = got_var; \
361 (dest)->inst_p1 = group; \
362 (dest)->type = (stack_type); \
367 #define NEW_AOTCONST(cfg,dest,patch_type,cons) do { \
368 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
369 (dest)->opcode = cfg->compile_aot ? OP_AOTCONST : OP_PCONST; \
370 (dest)->inst_p0 = (cons); \
371 (dest)->inst_i1 = (gpointer)(patch_type); \
372 (dest)->type = STACK_PTR; \
375 #define NEW_AOTCONST_TOKEN(cfg,dest,patch_type,image,token,stack_type) do { \
376 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
377 (dest)->opcode = OP_AOTCONST; \
378 (dest)->inst_p0 = mono_jump_info_token_new ((cfg)->mempool, (image), (token)); \
379 (dest)->inst_p1 = (gpointer)(patch_type); \
380 (dest)->type = (stack_type); \
385 #define NEW_CLASSCONST(cfg,dest,val) NEW_AOTCONST ((cfg), (dest), MONO_PATCH_INFO_CLASS, (val))
387 #define NEW_IMAGECONST(cfg,dest,val) NEW_AOTCONST ((cfg), (dest), MONO_PATCH_INFO_IMAGE, (val))
389 #define NEW_FIELDCONST(cfg,dest,val) NEW_AOTCONST ((cfg), (dest), MONO_PATCH_INFO_FIELD, (val))
391 #define NEW_METHODCONST(cfg,dest,val) NEW_AOTCONST ((cfg), (dest), MONO_PATCH_INFO_METHODCONST, (val))
393 #define NEW_VTABLECONST(cfg,dest,vtable) NEW_AOTCONST ((cfg), (dest), MONO_PATCH_INFO_VTABLE, cfg->compile_aot ? (gpointer)((vtable)->klass) : (vtable))
395 #define NEW_SFLDACONST(cfg,dest,val) NEW_AOTCONST ((cfg), (dest), MONO_PATCH_INFO_SFLDA, (val))
397 #define NEW_LDSTRCONST(cfg,dest,image,token) NEW_AOTCONST_TOKEN ((cfg), (dest), MONO_PATCH_INFO_LDSTR, (image), (token), STACK_OBJ)
399 #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)
401 #define NEW_LDTOKENCONST(cfg,dest,image,token) NEW_AOTCONST_TOKEN ((cfg), (dest), MONO_PATCH_INFO_LDTOKEN, (image), (token), STACK_PTR)
403 #define NEW_DECLSECCONST(cfg,dest,image,entry) do { \
404 if (cfg->compile_aot) { \
405 NEW_AOTCONST_TOKEN (cfg, dest, MONO_PATCH_INFO_DECLSEC, image, (entry).index, STACK_OBJ); \
407 NEW_PCONST (cfg, args [0], (entry).blob); \
411 #define NEW_DOMAINCONST(cfg,dest) do { \
412 if (cfg->opt & MONO_OPT_SHARED) { \
413 /* avoid depending on undefined C behavior in sequence points */ \
414 MonoInst* __domain_var = mono_get_domainvar (cfg); \
415 NEW_TEMPLOAD (cfg, dest, __domain_var->inst_c0); \
417 NEW_PCONST (cfg, dest, (cfg)->domain); \
421 #define GET_VARINFO_INST(cfg,num) ((cfg)->varinfo [(num)]->inst)
423 #define NEW_ARGLOAD(cfg,dest,num) do { \
424 if (arg_array [(num)]->opcode == OP_ICONST) (dest) = arg_array [(num)]; else { \
425 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
426 (dest)->ssa_op = MONO_SSA_LOAD; \
427 (dest)->inst_i0 = arg_array [(num)]; \
428 (dest)->opcode = mono_type_to_ldind ((dest)->inst_i0->inst_vtype); \
429 type_to_eval_stack_type (param_types [(num)], (dest)); \
430 (dest)->klass = (dest)->inst_i0->klass; \
433 #define NEW_LOCLOAD(cfg,dest,num) do { \
434 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
435 (dest)->ssa_op = MONO_SSA_LOAD; \
436 (dest)->inst_i0 = (cfg)->varinfo [locals_offset + (num)]; \
437 (dest)->opcode = mono_type_to_ldind ((dest)->inst_i0->inst_vtype); \
438 type_to_eval_stack_type (header->locals [(num)], (dest)); \
439 (dest)->klass = (dest)->inst_i0->klass; \
442 #define NEW_LOCLOADA(cfg,dest,num) do { \
443 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
444 (dest)->ssa_op = MONO_SSA_MAYBE_LOAD; \
445 (dest)->inst_i0 = (cfg)->varinfo [locals_offset + (num)]; \
446 (dest)->inst_i0->flags |= MONO_INST_INDIRECT; \
447 (dest)->opcode = OP_LDADDR; \
448 (dest)->type = STACK_MP; \
449 (dest)->klass = (dest)->inst_i0->klass; \
450 if (!MONO_TYPE_ISSTRUCT (header->locals [(num)])) \
451 (cfg)->disable_ssa = TRUE; \
454 #define NEW_RETLOADA(cfg,dest) do { \
455 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
456 (dest)->ssa_op = MONO_SSA_MAYBE_LOAD; \
457 (dest)->inst_i0 = (cfg)->ret; \
458 (dest)->inst_i0->flags |= MONO_INST_INDIRECT; \
459 (dest)->opcode = cfg->ret_var_is_local ? OP_LDADDR : CEE_LDIND_I; \
460 (dest)->type = STACK_MP; \
461 (dest)->klass = (dest)->inst_i0->klass; \
462 (cfg)->disable_ssa = TRUE; \
465 #define NEW_ARGLOADA(cfg,dest,num) do { \
466 if (arg_array [(num)]->opcode == OP_ICONST) goto inline_failure; \
467 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
468 (dest)->ssa_op = MONO_SSA_MAYBE_LOAD; \
469 (dest)->inst_i0 = arg_array [(num)]; \
470 (dest)->inst_i0->flags |= MONO_INST_INDIRECT; \
471 (dest)->opcode = OP_LDADDR; \
472 (dest)->type = STACK_MP; \
473 (dest)->klass = (dest)->inst_i0->klass; \
474 (cfg)->disable_ssa = TRUE; \
477 #define NEW_TEMPLOAD(cfg,dest,num) do { \
478 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
479 (dest)->ssa_op = MONO_SSA_LOAD; \
480 (dest)->inst_i0 = (cfg)->varinfo [(num)]; \
481 (dest)->opcode = mono_type_to_ldind ((dest)->inst_i0->inst_vtype); \
482 type_to_eval_stack_type ((dest)->inst_i0->inst_vtype, (dest)); \
483 (dest)->klass = (dest)->inst_i0->klass; \
486 #define NEW_TEMPLOADA(cfg,dest,num) do { \
487 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
488 (dest)->ssa_op = MONO_SSA_MAYBE_LOAD; \
489 (dest)->inst_i0 = (cfg)->varinfo [(num)]; \
490 (dest)->inst_i0->flags |= MONO_INST_INDIRECT; \
491 (dest)->opcode = OP_LDADDR; \
492 (dest)->type = STACK_MP; \
493 (dest)->klass = (dest)->inst_i0->klass; \
494 if (!MONO_TYPE_ISSTRUCT (cfg->varinfo [(num)]->inst_vtype)) \
495 (cfg)->disable_ssa = TRUE; \
499 #define NEW_INDLOAD(cfg,dest,addr,vtype) do { \
500 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
501 (dest)->inst_left = addr; \
502 (dest)->opcode = mono_type_to_ldind (vtype); \
503 type_to_eval_stack_type (vtype, (dest)); \
504 /* FIXME: (dest)->klass = (dest)->inst_i0->klass;*/ \
507 #define NEW_INDSTORE(cfg,dest,addr,value,vtype) do { \
508 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
509 (dest)->inst_i0 = addr; \
510 (dest)->opcode = mono_type_to_stind (vtype); \
511 (dest)->inst_i1 = (value); \
512 /* FIXME: (dest)->klass = (dest)->inst_i0->klass;*/ \
515 #define NEW_TEMPSTORE(cfg,dest,num,inst) do { \
516 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
517 (dest)->ssa_op = MONO_SSA_STORE; \
518 (dest)->inst_i0 = (cfg)->varinfo [(num)]; \
519 (dest)->opcode = mono_type_to_stind ((dest)->inst_i0->inst_vtype); \
520 (dest)->inst_i1 = (inst); \
521 (dest)->klass = (dest)->inst_i0->klass; \
524 #define NEW_LOCSTORE(cfg,dest,num,inst) do { \
525 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
526 (dest)->opcode = mono_type_to_stind (header->locals [(num)]); \
527 (dest)->ssa_op = MONO_SSA_STORE; \
528 (dest)->inst_i0 = (cfg)->varinfo [locals_offset + (num)]; \
529 (dest)->inst_i1 = (inst); \
530 (dest)->klass = (dest)->inst_i0->klass; \
533 #define NEW_ARGSTORE(cfg,dest,num,inst) do { \
534 if (arg_array [(num)]->opcode == OP_ICONST) goto inline_failure; \
535 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
536 (dest)->opcode = mono_type_to_stind (param_types [(num)]); \
537 (dest)->ssa_op = MONO_SSA_STORE; \
538 (dest)->inst_i0 = arg_array [(num)]; \
539 (dest)->inst_i1 = (inst); \
540 (dest)->klass = (dest)->inst_i0->klass; \
543 #define NEW_DUMMY_USE(cfg,dest,load) do { \
544 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
545 (dest)->opcode = OP_DUMMY_USE; \
546 (dest)->inst_left = (load); \
549 #define NEW_DUMMY_STORE(cfg,dest,num) do { \
550 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
551 (dest)->inst_i0 = (cfg)->varinfo [(num)]; \
552 (dest)->opcode = OP_DUMMY_STORE; \
553 (dest)->klass = (dest)->inst_i0->klass; \
556 #define ADD_BINOP(op) do { \
557 MONO_INST_NEW (cfg, ins, (op)); \
558 ins->cil_code = ip; \
560 ins->inst_i0 = sp [0]; \
561 ins->inst_i1 = sp [1]; \
563 type_from_op (ins); \
567 #define ADD_UNOP(op) do { \
568 MONO_INST_NEW (cfg, ins, (op)); \
569 ins->cil_code = ip; \
571 ins->inst_i0 = sp [0]; \
573 type_from_op (ins); \
577 #define ADD_BINCOND(next_block) do { \
580 MONO_INST_NEW(cfg, cmp, OP_COMPARE); \
581 cmp->inst_i0 = sp [0]; \
582 cmp->inst_i1 = sp [1]; \
583 cmp->cil_code = ins->cil_code; \
584 type_from_op (cmp); \
586 ins->inst_i0 = cmp; \
587 MONO_ADD_INS (bblock, ins); \
588 ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2); \
589 GET_BBLOCK (cfg, bbhash, tblock, target); \
590 link_bblock (cfg, bblock, tblock); \
591 ins->inst_true_bb = tblock; \
592 CHECK_BBLOCK (target, ip, tblock); \
593 if ((next_block)) { \
594 link_bblock (cfg, bblock, (next_block)); \
595 ins->inst_false_bb = (next_block); \
596 start_new_bblock = 1; \
598 GET_BBLOCK (cfg, bbhash, tblock, ip); \
599 link_bblock (cfg, bblock, tblock); \
600 ins->inst_false_bb = tblock; \
601 start_new_bblock = 2; \
605 /* FIXME: handle float, long ... */
606 #define ADD_UNCOND(istrue) do { \
609 MONO_INST_NEW(cfg, cmp, OP_COMPARE); \
610 cmp->inst_i0 = sp [0]; \
611 switch (cmp->inst_i0->type) { \
613 cmp->inst_i1 = zero_int64; break; \
615 cmp->inst_i1 = zero_r8; break; \
618 cmp->inst_i1 = zero_ptr; break; \
620 cmp->inst_i1 = zero_obj; break; \
622 cmp->inst_i1 = zero_int32; \
624 cmp->cil_code = ins->cil_code; \
625 type_from_op (cmp); \
627 ins->inst_i0 = cmp; \
628 ins->opcode = (istrue)? CEE_BNE_UN: CEE_BEQ; \
629 MONO_ADD_INS (bblock, ins); \
630 ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2); \
631 GET_BBLOCK (cfg, bbhash, tblock, target); \
632 link_bblock (cfg, bblock, tblock); \
633 ins->inst_true_bb = tblock; \
634 CHECK_BBLOCK (target, ip, tblock); \
635 GET_BBLOCK (cfg, bbhash, tblock, ip); \
636 link_bblock (cfg, bblock, tblock); \
637 ins->inst_false_bb = tblock; \
638 start_new_bblock = 2; \
641 #define NEW_LDELEMA(cfg,dest,sp,k) do { \
642 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
643 (dest)->opcode = CEE_LDELEMA; \
644 (dest)->inst_left = (sp) [0]; \
645 (dest)->inst_right = (sp) [1]; \
646 (dest)->type = STACK_MP; \
647 (dest)->klass = (k); \
648 (cfg)->flags |= MONO_CFG_HAS_LDELEMA; \
651 #define NEW_GROUP(cfg,dest,el1,el2) do { \
652 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
653 (dest)->opcode = OP_GROUP; \
654 (dest)->inst_left = (el1); \
655 (dest)->inst_right = (el2); \
660 compare_bblock (gconstpointer a, gconstpointer b)
662 const MonoBasicBlock *b1 = a;
663 const MonoBasicBlock *b2 = b;
665 return b2->cil_code - b1->cil_code;
670 * link_bblock: Links two basic blocks
672 * links two basic blocks in the control flow graph, the 'from'
673 * argument is the starting block and the 'to' argument is the block
674 * the control flow ends to after 'from'.
677 link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
679 MonoBasicBlock **newa;
683 if (from->cil_code) {
685 g_print ("edge from IL%04x to IL_%04x\n", from->cil_code - cfg->cil_code, to->cil_code - cfg->cil_code);
687 g_print ("edge from IL%04x to exit\n", from->cil_code - cfg->cil_code);
690 g_print ("edge from entry to IL_%04x\n", to->cil_code - cfg->cil_code);
692 g_print ("edge from entry to exit\n");
696 for (i = 0; i < from->out_count; ++i) {
697 if (to == from->out_bb [i]) {
703 newa = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (from->out_count + 1));
704 for (i = 0; i < from->out_count; ++i) {
705 newa [i] = from->out_bb [i];
713 for (i = 0; i < to->in_count; ++i) {
714 if (from == to->in_bb [i]) {
720 newa = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (to->in_count + 1));
721 for (i = 0; i < to->in_count; ++i) {
722 newa [i] = to->in_bb [i];
731 * mono_find_block_region:
733 * We mark each basic block with a region ID. We use that to avoid BB
734 * optimizations when blocks are in different regions.
737 * A region token that encodes where this region is, and information
738 * about the clause owner for this block.
740 * The region encodes the try/catch/filter clause that owns this block
741 * as well as the type. -1 is a special value that represents a block
742 * that is in none of try/catch/filter.
745 mono_find_block_region (MonoCompile *cfg, int offset)
747 MonoMethod *method = cfg->method;
748 MonoMethodHeader *header = mono_method_get_header (method);
749 MonoExceptionClause *clause;
752 /* first search for handlers and filters */
753 for (i = 0; i < header->num_clauses; ++i) {
754 clause = &header->clauses [i];
755 if ((clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) && (offset >= clause->data.filter_offset) &&
756 (offset < (clause->handler_offset)))
757 return ((i + 1) << 8) | MONO_REGION_FILTER | clause->flags;
759 if (MONO_OFFSET_IN_HANDLER (clause, offset)) {
760 if (clause->flags & MONO_EXCEPTION_CLAUSE_FINALLY)
761 return ((i + 1) << 8) | MONO_REGION_FINALLY | clause->flags;
763 return ((i + 1) << 8) | MONO_REGION_CATCH | clause->flags;
767 /* search the try blocks */
768 for (i = 0; i < header->num_clauses; ++i) {
769 clause = &header->clauses [i];
770 if (MONO_OFFSET_IN_CLAUSE (clause, offset))
771 return ((i + 1) << 8) | clause->flags;
778 mono_find_final_block (MonoCompile *cfg, unsigned char *ip, unsigned char *target, int type)
780 MonoMethod *method = cfg->method;
781 MonoMethodHeader *header = mono_method_get_header (method);
782 MonoExceptionClause *clause;
783 MonoBasicBlock *handler;
787 for (i = 0; i < header->num_clauses; ++i) {
788 clause = &header->clauses [i];
789 if (MONO_OFFSET_IN_CLAUSE (clause, (ip - header->code)) &&
790 (!MONO_OFFSET_IN_CLAUSE (clause, (target - header->code)))) {
791 if (clause->flags == type) {
792 handler = g_hash_table_lookup (cfg->bb_hash, header->code + clause->handler_offset);
794 res = g_list_append (res, handler);
802 mono_find_spvar_for_region (MonoCompile *cfg, int region)
804 return g_hash_table_lookup (cfg->spvars, GINT_TO_POINTER (region));
808 mono_create_spvar_for_region (MonoCompile *cfg, int region)
812 var = g_hash_table_lookup (cfg->spvars, GINT_TO_POINTER (region));
816 var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
817 /* prevent it from being register allocated */
818 var->flags |= MONO_INST_INDIRECT;
820 g_hash_table_insert (cfg->spvars, GINT_TO_POINTER (region), var);
824 mono_find_exvar_for_offset (MonoCompile *cfg, int offset)
826 return g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
830 mono_create_exvar_for_offset (MonoCompile *cfg, int offset)
834 var = g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
838 var = mono_compile_create_var (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL);
839 /* prevent it from being register allocated */
840 var->flags |= MONO_INST_INDIRECT;
842 g_hash_table_insert (cfg->exvars, GINT_TO_POINTER (offset), var);
848 df_visit (MonoBasicBlock *start, int *dfn, MonoBasicBlock **array)
852 array [*dfn] = start;
853 /*g_print ("visit %d at %p\n", *dfn, start->cil_code);*/
854 for (i = 0; i < start->out_count; ++i) {
855 if (start->out_bb [i]->dfn)
858 start->out_bb [i]->dfn = *dfn;
859 start->out_bb [i]->df_parent = start;
860 array [*dfn] = start->out_bb [i];
861 df_visit (start->out_bb [i], dfn, array);
867 MonoBasicBlock *best;
871 previous_foreach (gconstpointer key, gpointer val, gpointer data)
873 PrevStruct *p = data;
874 MonoBasicBlock *bb = val;
875 //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,
876 //bb->method == p->best->method, bb->cil_code < p->code, bb->cil_code > p->best->cil_code);
878 if (bb->cil_code && bb->cil_code < p->code && bb->cil_code > p->best->cil_code)
882 static MonoBasicBlock*
883 find_previous (GHashTable *bb_hash, MonoBasicBlock *start, const guchar *code) {
889 g_hash_table_foreach (bb_hash, (GHFunc)previous_foreach, &p);
894 split_bblock (MonoCompile *cfg, MonoBasicBlock *first, MonoBasicBlock *second) {
903 * FIXME: take into account all the details:
904 * second may have been the target of more than one bblock
906 second->out_count = first->out_count;
907 second->out_bb = first->out_bb;
909 for (i = 0; i < first->out_count; ++i) {
910 bb = first->out_bb [i];
911 for (j = 0; j < bb->in_count; ++j) {
912 if (bb->in_bb [j] == first)
913 bb->in_bb [j] = second;
917 first->out_count = 0;
918 first->out_bb = NULL;
919 link_bblock (cfg, first, second);
921 second->last_ins = first->last_ins;
923 /*g_print ("start search at %p for %p\n", first->cil_code, second->cil_code);*/
924 for (inst = first->code; inst && inst->next; inst = inst->next) {
925 /*char *code = mono_disasm_code_one (NULL, cfg->method, inst->next->cil_code, NULL);
926 g_print ("found %p: %s", inst->next->cil_code, code);
928 if (inst->cil_code < second->cil_code && inst->next->cil_code >= second->cil_code) {
929 second->code = inst->next;
931 first->last_ins = inst;
932 second->next_bb = first->next_bb;
933 first->next_bb = second;
938 g_warning ("bblock split failed in %s::%s\n", cfg->method->klass->name, cfg->method->name);
944 reverse_branch_op (guint32 opcode)
946 static const int reverse_map [] = {
947 CEE_BNE_UN, CEE_BLT, CEE_BLE, CEE_BGT, CEE_BGE,
948 CEE_BEQ, CEE_BLT_UN, CEE_BLE_UN, CEE_BGT_UN, CEE_BGE_UN
950 static const int reverse_fmap [] = {
951 OP_FBNE_UN, OP_FBLT, OP_FBLE, OP_FBGT, OP_FBGE,
952 OP_FBEQ, OP_FBLT_UN, OP_FBLE_UN, OP_FBGT_UN, OP_FBGE_UN
954 static const int reverse_lmap [] = {
955 OP_LBNE_UN, OP_LBLT, OP_LBLE, OP_LBGT, OP_LBGE,
956 OP_LBEQ, OP_LBLT_UN, OP_LBLE_UN, OP_LBGT_UN, OP_LBGE_UN
958 static const int reverse_imap [] = {
959 OP_IBNE_UN, OP_IBLT, OP_IBLE, OP_IBGT, OP_IBGE,
960 OP_IBEQ, OP_IBLT_UN, OP_IBLE_UN, OP_IBGT_UN, OP_IBGE_UN
963 if (opcode >= CEE_BEQ && opcode <= CEE_BLT_UN) {
964 opcode = reverse_map [opcode - CEE_BEQ];
965 } else if (opcode >= OP_FBEQ && opcode <= OP_FBLT_UN) {
966 opcode = reverse_fmap [opcode - OP_FBEQ];
967 } else if (opcode >= OP_LBEQ && opcode <= OP_LBLT_UN) {
968 opcode = reverse_lmap [opcode - OP_LBEQ];
969 } else if (opcode >= OP_IBEQ && opcode <= OP_IBLT_UN) {
970 opcode = reverse_imap [opcode - OP_IBEQ];
972 g_assert_not_reached ();
978 mono_type_to_ldind (MonoType *type)
984 switch (type->type) {
988 case MONO_TYPE_BOOLEAN:
1002 case MONO_TYPE_FNPTR:
1004 case MONO_TYPE_CLASS:
1005 case MONO_TYPE_STRING:
1006 case MONO_TYPE_OBJECT:
1007 case MONO_TYPE_SZARRAY:
1008 case MONO_TYPE_ARRAY:
1009 return CEE_LDIND_REF;
1012 return CEE_LDIND_I8;
1014 return CEE_LDIND_R4;
1016 return CEE_LDIND_R8;
1017 case MONO_TYPE_VALUETYPE:
1018 if (type->data.klass->enumtype) {
1019 type = type->data.klass->enum_basetype;
1023 case MONO_TYPE_TYPEDBYREF:
1025 case MONO_TYPE_GENERICINST:
1026 type = &type->data.generic_class->container_class->byval_arg;
1029 g_error ("unknown type 0x%02x in type_to_ldind", type->type);
1035 mono_type_to_stind (MonoType *type)
1041 switch (type->type) {
1044 case MONO_TYPE_BOOLEAN:
1045 return CEE_STIND_I1;
1048 case MONO_TYPE_CHAR:
1049 return CEE_STIND_I2;
1052 return CEE_STIND_I4;
1056 case MONO_TYPE_FNPTR:
1058 case MONO_TYPE_CLASS:
1059 case MONO_TYPE_STRING:
1060 case MONO_TYPE_OBJECT:
1061 case MONO_TYPE_SZARRAY:
1062 case MONO_TYPE_ARRAY:
1063 return CEE_STIND_REF;
1066 return CEE_STIND_I8;
1068 return CEE_STIND_R4;
1070 return CEE_STIND_R8;
1071 case MONO_TYPE_VALUETYPE:
1072 if (type->data.klass->enumtype) {
1073 type = type->data.klass->enum_basetype;
1077 case MONO_TYPE_TYPEDBYREF:
1079 case MONO_TYPE_GENERICINST:
1080 type = &type->data.generic_class->container_class->byval_arg;
1083 g_error ("unknown type 0x%02x in type_to_stind", type->type);
1089 * Returns the type used in the eval stack when @type is loaded.
1090 * FIXME: return a MonoType/MonoClass for the byref and VALUETYPE cases.
1093 type_to_eval_stack_type (MonoType *type, MonoInst *inst)
1098 inst->type = STACK_MP;
1102 klass = mono_class_from_mono_type (type);
1105 switch (type->type) {
1106 case MONO_TYPE_VOID:
1107 inst->type = STACK_INV;
1111 case MONO_TYPE_BOOLEAN:
1114 case MONO_TYPE_CHAR:
1117 inst->type = STACK_I4;
1122 case MONO_TYPE_FNPTR:
1123 inst->type = STACK_PTR;
1125 case MONO_TYPE_CLASS:
1126 case MONO_TYPE_STRING:
1127 case MONO_TYPE_OBJECT:
1128 case MONO_TYPE_SZARRAY:
1129 case MONO_TYPE_ARRAY:
1130 inst->type = STACK_OBJ;
1134 inst->type = STACK_I8;
1138 inst->type = STACK_R8;
1140 case MONO_TYPE_VALUETYPE:
1141 if (type->data.klass->enumtype) {
1142 type = type->data.klass->enum_basetype;
1145 inst->klass = klass;
1146 inst->type = STACK_VTYPE;
1149 case MONO_TYPE_TYPEDBYREF:
1150 inst->klass = mono_defaults.typed_reference_class;
1151 inst->type = STACK_VTYPE;
1153 case MONO_TYPE_GENERICINST:
1154 type = &type->data.generic_class->container_class->byval_arg;
1157 g_error ("unknown type 0x%02x in eval stack type", type->type);
1162 * The following tables are used to quickly validate the IL code in type_from_op ().
1165 bin_num_table [STACK_MAX] [STACK_MAX] = {
1166 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1167 {STACK_INV, STACK_I4, STACK_INV, STACK_PTR, STACK_INV, STACK_MP, STACK_INV, STACK_INV},
1168 {STACK_INV, STACK_INV, STACK_I8, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1169 {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_MP, STACK_INV, STACK_INV},
1170 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_R8, STACK_INV, STACK_INV, STACK_INV},
1171 {STACK_INV, STACK_MP, STACK_INV, STACK_MP, STACK_INV, STACK_PTR, STACK_INV, STACK_INV},
1172 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1173 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
1178 STACK_INV, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_INV, STACK_INV, STACK_INV
1181 /* reduce the size of this table */
1183 bin_int_table [STACK_MAX] [STACK_MAX] = {
1184 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1185 {STACK_INV, STACK_I4, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1186 {STACK_INV, STACK_INV, STACK_I8, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1187 {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1188 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1189 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1190 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1191 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
1195 bin_comp_table [STACK_MAX] [STACK_MAX] = {
1197 {0, 1, 0, 1, 0, 0, 4, 0},
1198 {0, 0, 1, 0, 0, 0, 0, 0},
1199 {0, 1, 0, 1, 0, 2, 4, 0},
1200 {0, 0, 0, 0, 1, 0, 0, 0},
1201 {0, 0, 0, 2, 0, 1, 0, 0},
1202 {0, 4, 0, 4, 0, 0, 3, 0},
1203 {0, 0, 0, 0, 0, 0, 0, 0},
1206 /* reduce the size of this table */
1208 shift_table [STACK_MAX] [STACK_MAX] = {
1209 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1210 {STACK_INV, STACK_I4, STACK_INV, STACK_I4, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1211 {STACK_INV, STACK_I8, STACK_INV, STACK_I8, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1212 {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1213 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1214 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1215 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1216 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
1220 * Tables to map from the non-specific opcode to the matching
1221 * type-specific opcode.
1223 /* handles from CEE_ADD to CEE_SHR_UN (CEE_REM_UN for floats) */
1224 static const guint16
1225 binops_op_map [STACK_MAX] = {
1226 0, 0, OP_LADD-CEE_ADD, OP_PADD-CEE_ADD, OP_FADD-CEE_ADD, OP_PADD-CEE_ADD
1229 /* handles from CEE_NEG to CEE_CONV_U8 */
1230 static const guint16
1231 unops_op_map [STACK_MAX] = {
1232 0, 0, OP_LNEG-CEE_NEG, OP_PNEG-CEE_NEG, OP_FNEG-CEE_NEG, OP_PNEG-CEE_NEG
1235 /* handles from CEE_CONV_U2 to CEE_SUB_OVF_UN */
1236 static const guint16
1237 ovfops_op_map [STACK_MAX] = {
1238 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
1241 /* handles from CEE_CONV_OVF_I1_UN to CEE_CONV_OVF_U_UN */
1242 static const guint16
1243 ovf2ops_op_map [STACK_MAX] = {
1244 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
1247 /* handles from CEE_CONV_OVF_I1 to CEE_CONV_OVF_U8 */
1248 static const guint16
1249 ovf3ops_op_map [STACK_MAX] = {
1250 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
1253 /* handles from CEE_CEQ to CEE_CLT_UN */
1254 static const guint16
1255 ceqops_op_map [STACK_MAX] = {
1256 0, 0, OP_LCEQ-CEE_CEQ, OP_PCEQ-CEE_CEQ, OP_FCEQ-CEE_CEQ, OP_LCEQ-CEE_CEQ
1260 * Sets ins->type (the type on the eval stack) according to the
1261 * type of the opcode and the arguments to it.
1262 * Invalid IL code is marked by setting ins->type to the invalid value STACK_INV.
1264 * FIXME: this function sets ins->type unconditionally in some cases, but
1265 * it should set it to invalid for some types (a conv.x on an object)
1268 type_from_op (MonoInst *ins) {
1269 switch (ins->opcode) {
1276 /* FIXME: check unverifiable args for STACK_MP */
1277 ins->type = bin_num_table [ins->inst_i0->type] [ins->inst_i1->type];
1278 ins->opcode += binops_op_map [ins->type];
1285 ins->type = bin_int_table [ins->inst_i0->type] [ins->inst_i1->type];
1286 ins->opcode += binops_op_map [ins->type];
1291 ins->type = shift_table [ins->inst_i0->type] [ins->inst_i1->type];
1292 ins->opcode += binops_op_map [ins->type];
1296 /* FIXME: handle some specifics with ins->next->type */
1297 ins->type = bin_comp_table [ins->inst_i0->type] [ins->inst_i1->type] ? STACK_I4: STACK_INV;
1298 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))))
1299 ins->opcode = OP_LCOMPARE;
1306 ins->type = bin_comp_table [ins->inst_i0->type] [ins->inst_i1->type] ? STACK_I4: STACK_INV;
1307 ins->opcode += ceqops_op_map [ins->inst_i0->type];
1311 ins->type = neg_table [ins->inst_i0->type];
1312 ins->opcode += unops_op_map [ins->type];
1315 if (ins->inst_i0->type >= STACK_I4 && ins->inst_i0->type <= STACK_PTR)
1316 ins->type = ins->inst_i0->type;
1318 ins->type = STACK_INV;
1319 ins->opcode += unops_op_map [ins->type];
1325 ins->type = STACK_I4;
1326 ins->opcode += unops_op_map [ins->inst_i0->type];
1329 ins->type = STACK_R8;
1330 switch (ins->inst_i0->type) {
1335 ins->opcode = OP_LCONV_TO_R_UN;
1339 case CEE_CONV_OVF_I1:
1340 case CEE_CONV_OVF_U1:
1341 case CEE_CONV_OVF_I2:
1342 case CEE_CONV_OVF_U2:
1343 case CEE_CONV_OVF_I4:
1344 case CEE_CONV_OVF_U4:
1345 ins->type = STACK_I4;
1346 ins->opcode += ovf3ops_op_map [ins->inst_i0->type];
1348 case CEE_CONV_OVF_I_UN:
1349 case CEE_CONV_OVF_U_UN:
1350 ins->type = STACK_PTR;
1351 ins->opcode += ovf2ops_op_map [ins->inst_i0->type];
1353 case CEE_CONV_OVF_I1_UN:
1354 case CEE_CONV_OVF_I2_UN:
1355 case CEE_CONV_OVF_I4_UN:
1356 case CEE_CONV_OVF_U1_UN:
1357 case CEE_CONV_OVF_U2_UN:
1358 case CEE_CONV_OVF_U4_UN:
1359 ins->type = STACK_I4;
1360 ins->opcode += ovf2ops_op_map [ins->inst_i0->type];
1363 ins->type = STACK_PTR;
1364 switch (ins->inst_i0->type) {
1370 ins->opcode = OP_LCONV_TO_U;
1373 ins->opcode = OP_FCONV_TO_U;
1379 ins->type = STACK_I8;
1380 ins->opcode += unops_op_map [ins->inst_i0->type];
1382 case CEE_CONV_OVF_I8:
1383 case CEE_CONV_OVF_U8:
1384 ins->type = STACK_I8;
1385 ins->opcode += ovf3ops_op_map [ins->inst_i0->type];
1387 case CEE_CONV_OVF_U8_UN:
1388 case CEE_CONV_OVF_I8_UN:
1389 ins->type = STACK_I8;
1390 ins->opcode += ovf2ops_op_map [ins->inst_i0->type];
1394 ins->type = STACK_R8;
1395 ins->opcode += unops_op_map [ins->inst_i0->type];
1398 ins->type = STACK_R8;
1402 ins->type = STACK_I4;
1403 ins->opcode += ovfops_op_map [ins->inst_i0->type];
1406 case CEE_CONV_OVF_I:
1407 case CEE_CONV_OVF_U:
1408 ins->type = STACK_PTR;
1409 ins->opcode += ovfops_op_map [ins->inst_i0->type];
1412 case CEE_ADD_OVF_UN:
1414 case CEE_MUL_OVF_UN:
1416 case CEE_SUB_OVF_UN:
1417 ins->type = bin_num_table [ins->inst_i0->type] [ins->inst_i1->type];
1418 ins->opcode += ovfops_op_map [ins->inst_i0->type];
1421 g_error ("opcode 0x%04x not handled in type from op", ins->opcode);
1428 STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I8, STACK_MP, STACK_R8, STACK_R8, STACK_OBJ
1431 /* map ldelem.x to the matching ldind.x opcode */
1433 ldelem_to_ldind [] = {
1447 /* map stelem.x to the matching stind.x opcode */
1449 stelem_to_stind [] = {
1463 param_table [STACK_MAX] [STACK_MAX] = {
1468 check_values_to_signature (MonoInst *args, MonoType *this, MonoMethodSignature *sig) {
1472 switch (args->type) {
1482 for (i = 0; i < sig->param_count; ++i) {
1483 switch (args [i].type) {
1487 if (!sig->params [i]->byref)
1491 if (sig->params [i]->byref)
1493 switch (sig->params [i]->type) {
1494 case MONO_TYPE_CLASS:
1495 case MONO_TYPE_STRING:
1496 case MONO_TYPE_OBJECT:
1497 case MONO_TYPE_SZARRAY:
1498 case MONO_TYPE_ARRAY:
1505 if (sig->params [i]->byref)
1507 if (sig->params [i]->type != MONO_TYPE_R4 && sig->params [i]->type != MONO_TYPE_R8)
1516 /*if (!param_table [args [i].type] [sig->params [i]->type])
1524 * When we need a pointer to the current domain many times in a method, we
1525 * call mono_domain_get() once and we store the result in a local variable.
1526 * This function returns the variable that represents the MonoDomain*.
1528 inline static MonoInst *
1529 mono_get_domainvar (MonoCompile *cfg)
1531 if (!cfg->domainvar)
1532 cfg->domainvar = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1533 return cfg->domainvar;
1537 * The got_var contains the address of the Global Offset Table when AOT
1540 inline static MonoInst *
1541 mono_get_got_var (MonoCompile *cfg)
1543 #ifdef MONO_ARCH_NEED_GOT_VAR
1544 if (!cfg->compile_aot)
1546 if (!cfg->got_var) {
1547 cfg->got_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1549 return cfg->got_var;
1556 mono_compile_create_var (MonoCompile *cfg, MonoType *type, int opcode)
1559 int num = cfg->num_varinfo;
1561 if ((num + 1) >= cfg->varinfo_count) {
1562 cfg->varinfo_count = (cfg->varinfo_count + 2) * 2;
1563 cfg->varinfo = (MonoInst **)g_realloc (cfg->varinfo, sizeof (MonoInst*) * cfg->varinfo_count);
1564 cfg->vars = (MonoMethodVar **)g_realloc (cfg->vars, sizeof (MonoMethodVar*) * cfg->varinfo_count);
1567 /*g_print ("created temp %d of type 0x%x\n", num, type->type);*/
1568 mono_jit_stats.allocate_var++;
1570 MONO_INST_NEW (cfg, inst, opcode);
1571 inst->inst_c0 = num;
1572 inst->inst_vtype = type;
1573 inst->klass = mono_class_from_mono_type (type);
1574 /* if set to 1 the variable is native */
1577 cfg->varinfo [num] = inst;
1579 cfg->vars [num] = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoMethodVar));
1580 MONO_INIT_VARINFO (cfg->vars [num], num);
1583 //g_print ("created temp %d of type %s\n", num, mono_type_get_name (type));
1588 * Transform a MonoInst into a load from the variable of index var_index.
1591 mono_compile_make_var_load (MonoCompile *cfg, MonoInst *dest, gssize var_index) {
1592 memset (dest, 0, sizeof (MonoInst));
1593 dest->ssa_op = MONO_SSA_LOAD;
1594 dest->inst_i0 = cfg->varinfo [var_index];
1595 dest->opcode = mono_type_to_ldind (dest->inst_i0->inst_vtype);
1596 type_to_eval_stack_type (dest->inst_i0->inst_vtype, dest);
1597 dest->klass = dest->inst_i0->klass;
1601 * Create a MonoInst that is a load from the variable of index var_index.
1604 mono_compile_create_var_load (MonoCompile *cfg, gssize var_index) {
1606 NEW_TEMPLOAD (cfg,dest,var_index);
1611 * Create a MonoInst that is a store of the given value into the variable of index var_index.
1614 mono_compile_create_var_store (MonoCompile *cfg, gssize var_index, MonoInst *value) {
1616 NEW_TEMPSTORE (cfg, dest, var_index, value);
1621 type_from_stack_type (MonoInst *ins) {
1622 switch (ins->type) {
1623 case STACK_I4: return &mono_defaults.int32_class->byval_arg;
1624 case STACK_I8: return &mono_defaults.int64_class->byval_arg;
1625 case STACK_PTR: return &mono_defaults.int_class->byval_arg;
1626 case STACK_R8: return &mono_defaults.double_class->byval_arg;
1627 case STACK_MP: return &mono_defaults.int_class->byval_arg;
1628 case STACK_OBJ: return &mono_defaults.object_class->byval_arg;
1629 case STACK_VTYPE: return &ins->klass->byval_arg;
1631 g_error ("stack type %d to montype not handled\n", ins->type);
1637 mono_type_from_stack_type (MonoInst *ins) {
1638 return type_from_stack_type (ins);
1642 array_access_to_klass (int opcode)
1646 return mono_defaults.byte_class;
1648 return mono_defaults.uint16_class;
1651 return mono_defaults.int_class;
1654 return mono_defaults.sbyte_class;
1657 return mono_defaults.int16_class;
1660 return mono_defaults.int32_class;
1662 return mono_defaults.uint32_class;
1665 return mono_defaults.int64_class;
1668 return mono_defaults.single_class;
1671 return mono_defaults.double_class;
1672 case CEE_LDELEM_REF:
1673 case CEE_STELEM_REF:
1674 return mono_defaults.object_class;
1676 g_assert_not_reached ();
1682 mono_add_ins_to_end (MonoBasicBlock *bb, MonoInst *inst)
1686 MONO_ADD_INS (bb, inst);
1689 switch (bb->last_ins->opcode) {
1703 while (prev->next && prev->next != bb->last_ins)
1705 if (prev == bb->code) {
1706 if (bb->last_ins == bb->code) {
1707 inst->next = bb->code;
1710 inst->next = prev->next;
1714 inst->next = bb->last_ins;
1718 // g_warning ("handle conditional jump in add_ins_to_end ()\n");
1720 MONO_ADD_INS (bb, inst);
1726 mono_add_varcopy_to_end (MonoCompile *cfg, MonoBasicBlock *bb, int src, int dest)
1728 MonoInst *inst, *load;
1730 NEW_TEMPLOAD (cfg, load, src);
1732 NEW_TEMPSTORE (cfg, inst, dest, load);
1733 if (inst->opcode == CEE_STOBJ) {
1734 NEW_TEMPLOADA (cfg, inst, dest);
1735 handle_stobj (cfg, bb, inst, load, NULL, inst->klass, TRUE, FALSE);
1737 inst->cil_code = NULL;
1738 mono_add_ins_to_end (bb, inst);
1743 * We try to share variables when possible
1746 mono_compile_get_interface_var (MonoCompile *cfg, int slot, MonoInst *ins)
1751 /* inlining can result in deeper stacks */
1752 if (slot >= mono_method_get_header (cfg->method)->max_stack)
1753 return mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1755 pos = ins->type - 1 + slot * STACK_MAX;
1757 switch (ins->type) {
1764 if ((vnum = cfg->intvars [pos]))
1765 return cfg->varinfo [vnum];
1766 res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1767 cfg->intvars [pos] = res->inst_c0;
1770 res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1776 * This function is called to handle items that are left on the evaluation stack
1777 * at basic block boundaries. What happens is that we save the values to local variables
1778 * and we reload them later when first entering the target basic block (with the
1779 * handle_loaded_temps () function).
1780 * It is also used to handle items on the stack in store opcodes, since it is
1781 * possible that the variable to be stored into is already on the stack, in
1782 * which case its old value should be used.
1783 * A single joint point will use the same variables (stored in the array bb->out_stack or
1784 * bb->in_stack, if the basic block is before or after the joint point).
1787 handle_stack_args (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst **sp, int count) {
1789 MonoBasicBlock *outb;
1790 MonoInst *inst, **locals;
1795 if (cfg->verbose_level > 3)
1796 g_print ("%d item(s) on exit from B%d\n", count, bb->block_num);
1797 if (!bb->out_scount) {
1798 bb->out_scount = count;
1799 //g_print ("bblock %d has out:", bb->block_num);
1801 for (i = 0; i < bb->out_count; ++i) {
1802 outb = bb->out_bb [i];
1803 //g_print (" %d", outb->block_num);
1804 if (outb->in_stack) {
1806 bb->out_stack = outb->in_stack;
1812 bb->out_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * count);
1813 for (i = 0; i < count; ++i) {
1815 * try to reuse temps already allocated for this purpouse, if they occupy the same
1816 * stack slot and if they are of the same type.
1817 * This won't cause conflicts since if 'local' is used to
1818 * store one of the values in the in_stack of a bblock, then
1819 * the same variable will be used for the same outgoing stack
1821 * This doesn't work when inlining methods, since the bblocks
1822 * in the inlined methods do not inherit their in_stack from
1823 * the bblock they are inlined to. See bug #58863 for an
1826 if (cfg->inlined_method)
1827 bb->out_stack [i] = mono_compile_create_var (cfg, type_from_stack_type (sp [i]), OP_LOCAL);
1829 bb->out_stack [i] = mono_compile_get_interface_var (cfg, i, sp [i]);
1834 for (i = 0; i < bb->out_count; ++i) {
1835 outb = bb->out_bb [i];
1836 if (outb->in_scount)
1837 continue; /* check they are the same locals */
1838 outb->in_scount = count;
1839 outb->in_stack = bb->out_stack;
1842 locals = bb->out_stack;
1843 for (i = 0; i < count; ++i) {
1844 /* add store ops at the end of the bb, before the branch */
1845 NEW_TEMPSTORE (cfg, inst, locals [i]->inst_c0, sp [i]);
1846 if (inst->opcode == CEE_STOBJ) {
1847 NEW_TEMPLOADA (cfg, inst, locals [i]->inst_c0);
1848 handle_stobj (cfg, bb, inst, sp [i], sp [i]->cil_code, inst->klass, TRUE, FALSE);
1850 inst->cil_code = sp [i]->cil_code;
1851 mono_add_ins_to_end (bb, inst);
1853 if (cfg->verbose_level > 3)
1854 g_print ("storing %d to temp %d\n", i, (int)locals [i]->inst_c0);
1858 * It is possible that the out bblocks already have in_stack assigned, and
1859 * the in_stacks differ. In this case, we will store to all the different
1866 /* Find a bblock which has a different in_stack */
1868 while (bindex < bb->out_count) {
1869 outb = bb->out_bb [bindex];
1870 if (outb->in_stack != locals) {
1872 * Instead of storing sp [i] to locals [i], we need to store
1873 * locals [i] to <new locals>[i], since the sp [i] tree can't
1874 * be shared between trees.
1876 for (i = 0; i < count; ++i)
1877 mono_add_varcopy_to_end (cfg, bb, locals [i]->inst_c0, outb->in_stack [i]->inst_c0);
1878 locals = outb->in_stack;
1890 ret_type_to_call_opcode (MonoType *type, int calli, int virt)
1893 return calli? OP_CALL_REG: virt? CEE_CALLVIRT: CEE_CALL;
1896 switch (type->type) {
1897 case MONO_TYPE_VOID:
1898 return calli? OP_VOIDCALL_REG: virt? OP_VOIDCALLVIRT: OP_VOIDCALL;
1901 case MONO_TYPE_BOOLEAN:
1904 case MONO_TYPE_CHAR:
1907 return calli? OP_CALL_REG: virt? CEE_CALLVIRT: CEE_CALL;
1911 case MONO_TYPE_FNPTR:
1912 return calli? OP_CALL_REG: virt? CEE_CALLVIRT: CEE_CALL;
1913 case MONO_TYPE_CLASS:
1914 case MONO_TYPE_STRING:
1915 case MONO_TYPE_OBJECT:
1916 case MONO_TYPE_SZARRAY:
1917 case MONO_TYPE_ARRAY:
1918 return calli? OP_CALL_REG: virt? CEE_CALLVIRT: CEE_CALL;
1921 return calli? OP_LCALL_REG: virt? OP_LCALLVIRT: OP_LCALL;
1924 return calli? OP_FCALL_REG: virt? OP_FCALLVIRT: OP_FCALL;
1925 case MONO_TYPE_VALUETYPE:
1926 if (type->data.klass->enumtype) {
1927 type = type->data.klass->enum_basetype;
1930 return calli? OP_VCALL_REG: virt? OP_VCALLVIRT: OP_VCALL;
1931 case MONO_TYPE_TYPEDBYREF:
1932 return calli? OP_VCALL_REG: virt? OP_VCALLVIRT: OP_VCALL;
1933 case MONO_TYPE_GENERICINST:
1934 type = &type->data.generic_class->container_class->byval_arg;
1937 g_error ("unknown type 0x%02x in ret_type_to_call_opcode", type->type);
1943 mono_create_jump_table (MonoCompile *cfg, MonoInst *label, MonoBasicBlock **bbs, int num_blocks)
1945 MonoJumpInfo *ji = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfo));
1946 MonoJumpInfoBBTable *table;
1948 table = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfoBBTable));
1950 table->table_size = num_blocks;
1952 ji->ip.label = label;
1953 ji->type = MONO_PATCH_INFO_SWITCH;
1954 ji->data.table = table;
1955 ji->next = cfg->patch_info;
1956 cfg->patch_info = ji;
1960 * When we add a tree of instructions, we need to ensure the instructions currently
1961 * on the stack are executed before (like, if we load a value from a local).
1962 * We ensure this by saving the currently loaded values to temps and rewriting the
1963 * instructions to load the values.
1964 * This is not done for opcodes that terminate a basic block (because it's handled already
1965 * by handle_stack_args ()) and for opcodes that can't change values, like POP.
1968 handle_loaded_temps (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst **stack, MonoInst **sp)
1970 MonoInst *load, *store, *temp, *ins;
1972 while (stack < sp) {
1974 /* handle also other constants */
1975 if ((ins->opcode != OP_ICONST) &&
1976 /* temps never get written to again, so we can safely avoid duplicating them */
1977 !(ins->ssa_op == MONO_SSA_LOAD && ins->inst_i0->opcode == OP_LOCAL && ins->inst_i0->flags & MONO_INST_IS_TEMP)) {
1978 temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1979 temp->flags |= MONO_INST_IS_TEMP;
1980 NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
1981 store->cil_code = ins->cil_code;
1982 if (store->opcode == CEE_STOBJ) {
1983 NEW_TEMPLOADA (cfg, store, temp->inst_c0);
1984 handle_stobj (cfg, bblock, store, ins, ins->cil_code, temp->klass, FALSE, FALSE);
1986 MONO_ADD_INS (bblock, store);
1987 NEW_TEMPLOAD (cfg, load, temp->inst_c0);
1988 load->cil_code = ins->cil_code;
1996 * Prepare arguments for passing to a function call.
1997 * Return a non-zero value if the arguments can't be passed to the given
1999 * The type checks are not yet complete and some conversions may need
2000 * casts on 32 or 64 bit architectures.
2003 check_call_signature (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args)
2005 MonoType *simple_type;
2009 if (args [0]->type != STACK_OBJ && args [0]->type != STACK_MP && args [0]->type != STACK_PTR)
2013 for (i = 0; i < sig->param_count; ++i) {
2014 if (sig->params [i]->byref) {
2015 if (args [i]->type != STACK_MP && args [i]->type != STACK_PTR)
2019 simple_type = sig->params [i];
2021 switch (simple_type->type) {
2022 case MONO_TYPE_VOID:
2027 case MONO_TYPE_BOOLEAN:
2030 case MONO_TYPE_CHAR:
2033 if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR)
2039 case MONO_TYPE_FNPTR:
2040 if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR && args [i]->type != STACK_MP && args [i]->type != STACK_OBJ)
2043 case MONO_TYPE_CLASS:
2044 case MONO_TYPE_STRING:
2045 case MONO_TYPE_OBJECT:
2046 case MONO_TYPE_SZARRAY:
2047 case MONO_TYPE_ARRAY:
2048 if (args [i]->type != STACK_OBJ)
2053 if (args [i]->type != STACK_I8)
2058 if (args [i]->type != STACK_R8)
2061 case MONO_TYPE_VALUETYPE:
2062 if (simple_type->data.klass->enumtype) {
2063 simple_type = simple_type->data.klass->enum_basetype;
2066 if (args [i]->type != STACK_VTYPE)
2069 case MONO_TYPE_TYPEDBYREF:
2070 if (args [i]->type != STACK_VTYPE)
2073 case MONO_TYPE_GENERICINST:
2074 simple_type = &simple_type->data.generic_class->container_class->byval_arg;
2078 g_error ("unknown type 0x%02x in check_call_signature",
2086 mono_spill_call (MonoCompile *cfg, MonoBasicBlock *bblock, MonoCallInst *call, MonoMethodSignature *sig, gboolean ret_object,
2087 const guint8 *ip, gboolean to_end)
2089 MonoInst *temp, *store, *ins = (MonoInst*)call;
2090 MonoType *ret = sig->ret;
2092 if (!MONO_TYPE_IS_VOID (ret) || ret_object) {
2094 call->inst.type = STACK_OBJ;
2095 call->inst.opcode = CEE_CALL;
2096 temp = mono_compile_create_var (cfg, &mono_defaults.string_class->byval_arg, OP_LOCAL);
2098 type_to_eval_stack_type (ret, ins);
2099 temp = mono_compile_create_var (cfg, ret, OP_LOCAL);
2102 temp->flags |= MONO_INST_IS_TEMP;
2104 if (MONO_TYPE_ISSTRUCT (ret)) {
2105 MonoInst *loada, *dummy_store;
2108 * Emit a dummy store to the local holding the result so the
2109 * liveness info remains correct.
2111 NEW_DUMMY_STORE (cfg, dummy_store, temp->inst_c0);
2113 mono_add_ins_to_end (bblock, dummy_store);
2115 MONO_ADD_INS (bblock, dummy_store);
2117 /* we use this to allocate native sized structs */
2118 temp->unused = sig->pinvoke;
2120 NEW_TEMPLOADA (cfg, loada, temp->inst_c0);
2121 if (call->inst.opcode == OP_VCALL)
2122 ins->inst_left = loada;
2124 ins->inst_right = loada; /* a virtual or indirect call */
2127 mono_add_ins_to_end (bblock, ins);
2129 MONO_ADD_INS (bblock, ins);
2131 NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
2132 store->cil_code = ip;
2134 mono_add_ins_to_end (bblock, store);
2136 MONO_ADD_INS (bblock, store);
2138 return temp->inst_c0;
2141 mono_add_ins_to_end (bblock, ins);
2143 MONO_ADD_INS (bblock, ins);
2148 inline static MonoCallInst *
2149 mono_emit_call_args (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethodSignature *sig,
2150 MonoInst **args, int calli, int virtual, const guint8 *ip, gboolean to_end)
2155 MONO_INST_NEW_CALL (cfg, call, ret_type_to_call_opcode (sig->ret, calli, virtual));
2157 call->inst.cil_code = ip;
2159 call->signature = sig;
2160 call = mono_arch_call_opcode (cfg, bblock, call, virtual);
2161 type_to_eval_stack_type (sig->ret, &call->inst);
2163 for (arg = call->out_args; arg;) {
2164 MonoInst *narg = arg->next;
2169 mono_add_ins_to_end (bblock, arg);
2171 MONO_ADD_INS (bblock, arg);
2178 mono_emit_calli (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethodSignature *sig,
2179 MonoInst **args, MonoInst *addr, const guint8 *ip)
2181 MonoCallInst *call = mono_emit_call_args (cfg, bblock, sig, args, TRUE, FALSE, ip, FALSE);
2183 call->inst.inst_i0 = addr;
2185 return mono_spill_call (cfg, bblock, call, sig, FALSE, ip, FALSE);
2188 static MonoCallInst*
2189 mono_emit_method_call_full (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *method, MonoMethodSignature *sig,
2190 MonoInst **args, const guint8 *ip, MonoInst *this, gboolean to_end)
2192 gboolean virtual = this != NULL;
2195 call = mono_emit_call_args (cfg, bblock, sig, args, FALSE, virtual, ip, to_end);
2197 if (this && sig->hasthis &&
2198 (method->klass->marshalbyref || method->klass == mono_defaults.object_class) &&
2199 !(method->flags & METHOD_ATTRIBUTE_VIRTUAL) && !MONO_CHECK_THIS (this)) {
2200 call->method = mono_marshal_get_remoting_invoke_with_check (method);
2202 call->method = method;
2204 call->inst.flags |= MONO_INST_HAS_METHOD;
2205 call->inst.inst_left = this;
2208 mono_get_got_var (cfg);
2209 else if (call->method->klass->flags & TYPE_ATTRIBUTE_INTERFACE)
2210 /* Needed by the code generated in inssel.brg */
2211 mono_get_got_var (cfg);
2216 static MonoCallInst*
2217 mono_emit_method_call (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *method, MonoMethodSignature *sig,
2218 MonoInst **args, const guint8 *ip, MonoInst *this)
2220 return mono_emit_method_call_full (cfg, bblock, method, sig, args, ip, this, FALSE);
2224 mono_emit_method_call_spilled (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *method,
2225 MonoMethodSignature *signature, MonoInst **args, const guint8 *ip, MonoInst *this)
2227 MonoCallInst *call = mono_emit_method_call (cfg, bblock, method, signature, args, ip, this);
2229 return mono_spill_call (cfg, bblock, call, signature, method->string_ctor, ip, FALSE);
2233 mono_emit_method_call_spilled_full (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *method,
2234 MonoMethodSignature *signature, MonoInst **args, const guint8 *ip, MonoInst *this,
2235 gboolean ret_object, gboolean to_end)
2237 MonoCallInst *call = mono_emit_method_call_full (cfg, bblock, method, signature, args, ip, this, to_end);
2239 return mono_spill_call (cfg, bblock, call, signature, ret_object, ip, to_end);
2243 mono_emit_native_call (MonoCompile *cfg, MonoBasicBlock *bblock, gconstpointer func, MonoMethodSignature *sig,
2244 MonoInst **args, const guint8 *ip, gboolean ret_object, gboolean to_end)
2250 call = mono_emit_call_args (cfg, bblock, sig, args, FALSE, FALSE, ip, to_end);
2253 mono_get_got_var (cfg);
2255 return mono_spill_call (cfg, bblock, call, sig, ret_object, ip, to_end);
2259 mono_emit_jit_icall (MonoCompile *cfg, MonoBasicBlock *bblock, gconstpointer func, MonoInst **args, const guint8 *ip)
2261 MonoJitICallInfo *info = mono_find_jit_icall_by_addr (func);
2264 g_warning ("unregistered JIT ICall");
2265 g_assert_not_reached ();
2268 mono_get_got_var (cfg);
2269 return mono_emit_native_call (cfg, bblock, mono_icall_get_wrapper (info), info->sig, args, ip, FALSE, FALSE);
2273 mono_emulate_opcode (MonoCompile *cfg, MonoInst *tree, MonoInst **iargs, MonoJitICallInfo *info)
2275 MonoInst *ins, *temp = NULL, *store, *load, *begin;
2276 MonoInst *last_arg = NULL;
2280 //g_print ("emulating: ");
2281 //mono_print_tree_nl (tree);
2282 MONO_INST_NEW_CALL (cfg, call, ret_type_to_call_opcode (info->sig->ret, FALSE, FALSE));
2283 ins = (MonoInst*)call;
2285 call->inst.cil_code = tree->cil_code;
2287 call->signature = info->sig;
2289 call = mono_arch_call_opcode (cfg, cfg->cbb, call, FALSE);
2291 mono_get_got_var (cfg);
2293 if (!MONO_TYPE_IS_VOID (info->sig->ret)) {
2294 temp = mono_compile_create_var (cfg, info->sig->ret, OP_LOCAL);
2295 temp->flags |= MONO_INST_IS_TEMP;
2296 NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
2297 store->cil_code = tree->cil_code;
2302 nargs = info->sig->param_count + info->sig->hasthis;
2304 for (last_arg = call->out_args; last_arg && last_arg->next; last_arg = last_arg->next) ;
2307 last_arg->next = store;
2310 begin = call->out_args;
2314 if (cfg->prev_ins) {
2316 * This assumes that that in a tree, emulate_opcode is called for a
2317 * node before it is called for its children. dec_foreach needs to
2318 * take this into account.
2320 store->next = cfg->prev_ins->next;
2321 cfg->prev_ins->next = begin;
2323 store->next = cfg->cbb->code;
2324 cfg->cbb->code = begin;
2327 call->fptr = mono_icall_get_wrapper (info);
2329 if (!MONO_TYPE_IS_VOID (info->sig->ret)) {
2330 NEW_TEMPLOAD (cfg, load, temp->inst_c0);
2335 static MonoMethodSignature *
2336 mono_get_element_address_signature (int arity)
2338 static GHashTable *sighash = NULL;
2339 MonoMethodSignature *res;
2342 EnterCriticalSection (&jit_mutex);
2344 sighash = g_hash_table_new (NULL, NULL);
2346 else if ((res = g_hash_table_lookup (sighash, GINT_TO_POINTER (arity)))) {
2347 LeaveCriticalSection (&jit_mutex);
2351 res = mono_metadata_signature_alloc (mono_defaults.corlib, arity + 1);
2354 #ifdef MONO_ARCH_VARARG_ICALLS
2355 /* Only set this only some archs since not all backends can handle varargs+pinvoke */
2356 res->call_convention = MONO_CALL_VARARG;
2358 res->params [0] = &mono_defaults.array_class->byval_arg;
2360 for (i = 1; i <= arity; i++)
2361 res->params [i] = &mono_defaults.int_class->byval_arg;
2363 res->ret = &mono_defaults.int_class->byval_arg;
2365 g_hash_table_insert (sighash, GINT_TO_POINTER (arity), res);
2366 LeaveCriticalSection (&jit_mutex);
2371 static MonoMethodSignature *
2372 mono_get_array_new_va_signature (int arity)
2374 static GHashTable *sighash = NULL;
2375 MonoMethodSignature *res;
2378 EnterCriticalSection (&jit_mutex);
2380 sighash = g_hash_table_new (NULL, NULL);
2382 else if ((res = g_hash_table_lookup (sighash, GINT_TO_POINTER (arity)))) {
2383 LeaveCriticalSection (&jit_mutex);
2387 res = mono_metadata_signature_alloc (mono_defaults.corlib, arity + 1);
2390 #ifdef MONO_ARCH_VARARG_ICALLS
2391 /* Only set this only some archs since not all backends can handle varargs+pinvoke */
2392 res->call_convention = MONO_CALL_VARARG;
2395 res->params [0] = &mono_defaults.int_class->byval_arg;
2396 for (i = 0; i < arity; i++)
2397 res->params [i + 1] = &mono_defaults.int_class->byval_arg;
2399 res->ret = &mono_defaults.int_class->byval_arg;
2401 g_hash_table_insert (sighash, GINT_TO_POINTER (arity), res);
2402 LeaveCriticalSection (&jit_mutex);
2408 get_memcpy_method (void)
2410 static MonoMethod *memcpy_method = NULL;
2411 if (!memcpy_method) {
2412 memcpy_method = mono_class_get_method_from_name (mono_defaults.string_class, "memcpy", 3);
2414 g_error ("Old corlib found. Install a new one");
2416 return memcpy_method;
2420 handle_stobj (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *dest, MonoInst *src, const unsigned char *ip, MonoClass *klass, gboolean to_end, gboolean native) {
2421 MonoInst *iargs [3];
2424 MonoMethod *memcpy_method;
2428 * This check breaks with spilled vars... need to handle it during verification anyway.
2429 * g_assert (klass && klass == src->klass && klass == dest->klass);
2433 n = mono_class_native_size (klass, &align);
2435 n = mono_class_value_size (klass, &align);
2437 if ((cfg->opt & MONO_OPT_INTRINS) && !to_end && n <= sizeof (gpointer) * 5) {
2439 if (dest->opcode == OP_LDADDR) {
2440 /* Keep liveness info correct */
2441 NEW_DUMMY_STORE (cfg, inst, dest->inst_i0->inst_c0);
2442 MONO_ADD_INS (bblock, inst);
2444 MONO_INST_NEW (cfg, inst, OP_MEMCPY);
2445 inst->inst_left = dest;
2446 inst->inst_right = src;
2447 inst->cil_code = ip;
2449 MONO_ADD_INS (bblock, inst);
2454 NEW_ICONST (cfg, iargs [2], n);
2456 memcpy_method = get_memcpy_method ();
2457 mono_emit_method_call_spilled_full (cfg, bblock, memcpy_method, memcpy_method->signature, iargs, ip, NULL, FALSE, to_end);
2461 get_memset_method (void)
2463 static MonoMethod *memset_method = NULL;
2464 if (!memset_method) {
2465 memset_method = mono_class_get_method_from_name (mono_defaults.string_class, "memset", 3);
2467 g_error ("Old corlib found. Install a new one");
2469 return memset_method;
2473 handle_initobj (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *dest, const guchar *ip, MonoClass *klass, MonoInst **stack_start, MonoInst **sp)
2475 MonoInst *iargs [3];
2476 MonoInst *ins, *zero_int32;
2478 MonoMethod *memset_method;
2480 NEW_ICONST (cfg, zero_int32, 0);
2482 mono_class_init (klass);
2483 n = mono_class_value_size (klass, NULL);
2484 MONO_INST_NEW (cfg, ins, 0);
2486 ins->inst_left = dest;
2487 ins->inst_right = zero_int32;
2490 ins->opcode = CEE_STIND_I1;
2491 MONO_ADD_INS (bblock, ins);
2494 ins->opcode = CEE_STIND_I2;
2495 MONO_ADD_INS (bblock, ins);
2498 ins->opcode = CEE_STIND_I4;
2499 MONO_ADD_INS (bblock, ins);
2502 if (n <= sizeof (gpointer) * 5) {
2503 ins->opcode = OP_MEMSET;
2506 MONO_ADD_INS (bblock, ins);
2509 memset_method = get_memset_method ();
2510 handle_loaded_temps (cfg, bblock, stack_start, sp);
2512 NEW_ICONST (cfg, iargs [1], 0);
2513 NEW_ICONST (cfg, iargs [2], n);
2514 mono_emit_method_call_spilled (cfg, bblock, memset_method, memset_method->signature, iargs, ip, NULL);
2520 handle_alloc (MonoCompile *cfg, MonoBasicBlock *bblock, MonoClass *klass, gboolean for_box, const guchar *ip)
2522 MonoInst *iargs [2];
2525 if (cfg->opt & MONO_OPT_SHARED) {
2526 NEW_DOMAINCONST (cfg, iargs [0]);
2527 NEW_CLASSCONST (cfg, iargs [1], klass);
2529 alloc_ftn = mono_object_new;
2531 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
2534 alloc_ftn = mono_class_get_allocation_ftn (vtable, for_box, &pass_lw);
2536 guint32 lw = vtable->klass->instance_size;
2537 lw = ((lw + (sizeof (gpointer) - 1)) & ~(sizeof (gpointer) - 1)) / sizeof (gpointer);
2538 NEW_ICONST (cfg, iargs [0], lw);
2539 NEW_VTABLECONST (cfg, iargs [1], vtable);
2542 NEW_VTABLECONST (cfg, iargs [0], vtable);
2545 return mono_emit_jit_icall (cfg, bblock, alloc_ftn, iargs, ip);
2549 handle_box (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *val, const guchar *ip, MonoClass *klass)
2551 MonoInst *dest, *vtoffset, *add, *vstore;
2554 temp = handle_alloc (cfg, bblock, klass, TRUE, ip);
2555 NEW_TEMPLOAD (cfg, dest, temp);
2556 NEW_ICONST (cfg, vtoffset, sizeof (MonoObject));
2557 MONO_INST_NEW (cfg, add, OP_PADD);
2558 add->inst_left = dest;
2559 add->inst_right = vtoffset;
2562 MONO_INST_NEW (cfg, vstore, CEE_STIND_I);
2563 vstore->opcode = mono_type_to_stind (&klass->byval_arg);
2564 vstore->cil_code = ip;
2565 vstore->inst_left = add;
2566 vstore->inst_right = val;
2568 if (vstore->opcode == CEE_STOBJ) {
2569 handle_stobj (cfg, bblock, add, val, ip, klass, FALSE, FALSE);
2571 MONO_ADD_INS (bblock, vstore);
2573 NEW_TEMPLOAD (cfg, dest, temp);
2578 handle_array_new (MonoCompile *cfg, MonoBasicBlock *bblock, int rank, MonoInst **sp, unsigned char *ip)
2580 MonoMethodSignature *esig;
2581 char icall_name [256];
2583 MonoJitICallInfo *info;
2585 /* Need to register the icall so it gets an icall wrapper */
2586 sprintf (icall_name, "ves_array_new_va_%d", rank);
2588 info = mono_find_jit_icall_by_name (icall_name);
2590 esig = mono_get_array_new_va_signature (rank);
2591 name = g_strdup (icall_name);
2592 info = mono_register_jit_icall (mono_array_new_va, name, esig, FALSE);
2594 EnterCriticalSection (&jit_mutex);
2595 g_hash_table_insert (jit_icall_name_hash, name, name);
2596 LeaveCriticalSection (&jit_mutex);
2599 cfg->flags |= MONO_CFG_HAS_VARARGS;
2601 return mono_emit_native_call (cfg, bblock, mono_icall_get_wrapper (info), info->sig, sp, ip, TRUE, FALSE);
2605 mono_emit_load_got_addr (MonoCompile *cfg)
2607 MonoInst *load, *store, *dummy_use;
2610 if (!cfg->got_var || cfg->got_var_allocated)
2613 MONO_INST_NEW (cfg, get_got, OP_LOAD_GOTADDR);
2614 NEW_TEMPSTORE (cfg, store, cfg->got_var->inst_c0, get_got);
2616 /* Add it to the start of the first bblock */
2617 if (cfg->bb_entry->code) {
2618 store->next = cfg->bb_entry->code;
2619 cfg->bb_entry->code = store;
2622 MONO_ADD_INS (cfg->bb_entry, store);
2624 cfg->got_var_allocated = TRUE;
2627 * Add a dummy use to keep the got_var alive, since real uses might
2628 * only be generated in the decompose or instruction selection phases.
2629 * Add it to end_bblock, so the variable's lifetime covers the whole
2632 NEW_TEMPLOAD (cfg, load, cfg->got_var->inst_c0);
2633 NEW_DUMMY_USE (cfg, dummy_use, load);
2634 MONO_ADD_INS (cfg->bb_exit, dummy_use);
2637 #define CODE_IS_STLOC(ip) (((ip) [0] >= CEE_STLOC_0 && (ip) [0] <= CEE_STLOC_3) || ((ip) [0] == CEE_STLOC_S))
2640 mini_class_is_system_array (MonoClass *klass)
2642 if (klass->parent == mono_defaults.array_class)
2644 else if (mono_defaults.generic_array_class && klass->parent && klass->parent->generic_class)
2645 return klass->parent->generic_class->container_class == mono_defaults.generic_array_class;
2651 mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method)
2653 MonoMethodHeader *header = mono_method_get_header (method);
2654 MonoMethodSignature *signature = mono_method_signature (method);
2658 #ifdef MONO_ARCH_HAVE_LMF_OPS
2659 if (((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
2660 (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) &&
2661 !MONO_TYPE_ISSTRUCT (signature->ret) && !mini_class_is_system_array (method->klass))
2665 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
2666 (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
2667 (method->iflags & METHOD_IMPL_ATTRIBUTE_NOINLINING) ||
2668 (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) ||
2669 (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
2670 (method->klass->marshalbyref) ||
2671 !header || header->num_clauses ||
2672 /* fixme: why cant we inline valuetype returns? */
2673 MONO_TYPE_ISSTRUCT (signature->ret))
2676 /* its not worth to inline methods with valuetype arguments?? */
2677 for (i = 0; i < signature->param_count; i++) {
2678 if (MONO_TYPE_ISSTRUCT (signature->params [i])) {
2684 * if we can initialize the class of the method right away, we do,
2685 * otherwise we don't allow inlining if the class needs initialization,
2686 * since it would mean inserting a call to mono_runtime_class_init()
2687 * inside the inlined code
2689 if (!(cfg->opt & MONO_OPT_SHARED)) {
2690 vtable = mono_class_vtable (cfg->domain, method->klass);
2691 if (method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) {
2692 if (cfg->run_cctors)
2693 mono_runtime_class_init (vtable);
2695 else if (!vtable->initialized && mono_class_needs_cctor_run (method->klass, NULL))
2699 * If we're compiling for shared code
2700 * the cctor will need to be run at aot method load time, for example,
2701 * or at the end of the compilation of the inlining method.
2703 if (mono_class_needs_cctor_run (method->klass, NULL) && !((method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT)))
2706 //if (!MONO_TYPE_IS_VOID (signature->ret)) return FALSE;
2709 * CAS - do not inline methods with declarative security
2710 * Note: this has to be before any possible return TRUE;
2712 if (mono_method_has_declsec (method))
2715 /* also consider num_locals? */
2716 if (getenv ("MONO_INLINELIMIT")) {
2717 if (header->code_size < atoi (getenv ("MONO_INLINELIMIT"))) {
2720 } else if (header->code_size < 20)
2727 mini_field_access_needs_cctor_run (MonoCompile *cfg, MonoMethod *method, MonoVTable *vtable)
2729 if (vtable->initialized && !cfg->compile_aot)
2732 if (vtable->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT)
2735 if (!mono_class_needs_cctor_run (vtable->klass, method))
2738 if (! (method->flags & METHOD_ATTRIBUTE_STATIC) && (vtable->klass == method->klass))
2739 /* The initialization is already done before the method is called */
2746 mini_get_ldelema_ins (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *cmethod, MonoInst **sp, unsigned char *ip, gboolean is_set)
2750 MonoMethodSignature *esig;
2751 char icall_name [256];
2753 MonoJitICallInfo *info;
2755 rank = mono_method_signature (cmethod)->param_count - (is_set? 1: 0);
2757 if (rank == 2 && (cfg->opt & MONO_OPT_INTRINS)) {
2758 #ifdef MONO_ARCH_EMULATE_MUL_DIV
2759 /* OP_LDELEMA2D depends on OP_LMUL */
2762 NEW_GROUP (cfg, indexes, sp [1], sp [2]);
2763 MONO_INST_NEW (cfg, addr, OP_LDELEMA2D);
2764 addr->inst_left = sp [0];
2765 addr->inst_right = indexes;
2766 addr->cil_code = ip;
2767 addr->type = STACK_MP;
2768 addr->klass = cmethod->klass;
2773 /* Need to register the icall so it gets an icall wrapper */
2774 sprintf (icall_name, "ves_array_element_address_%d", rank);
2776 info = mono_find_jit_icall_by_name (icall_name);
2778 esig = mono_get_element_address_signature (rank);
2779 name = g_strdup (icall_name);
2780 info = mono_register_jit_icall (ves_array_element_address, name, esig, FALSE);
2782 EnterCriticalSection (&jit_mutex);
2783 g_hash_table_insert (jit_icall_name_hash, name, name);
2784 LeaveCriticalSection (&jit_mutex);
2787 temp = mono_emit_native_call (cfg, bblock, mono_icall_get_wrapper (info), info->sig, sp, ip, FALSE, FALSE);
2788 cfg->flags |= MONO_CFG_HAS_VARARGS;
2790 NEW_TEMPLOAD (cfg, addr, temp);
2794 static MonoJitICallInfo **emul_opcode_map = NULL;
2796 static inline MonoJitICallInfo *
2797 mono_find_jit_opcode_emulation (int opcode)
2799 if (emul_opcode_map)
2800 return emul_opcode_map [opcode];
2805 static MonoException*
2806 mini_loader_error_to_exception (MonoLoaderError *error)
2808 MonoException *ex = NULL;
2810 switch (error->kind) {
2811 case MONO_LOADER_ERROR_TYPE: {
2812 MonoString *class_name = mono_string_new (mono_domain_get (), error->class_name);
2814 ex = mono_get_exception_type_load (class_name, error->assembly_name);
2817 case MONO_LOADER_ERROR_METHOD:
2818 case MONO_LOADER_ERROR_FIELD: {
2821 class_name = g_strdup_printf ("%s%s%s", error->klass->name_space, *error->klass->name_space ? "." : "", error->klass->name);
2823 if (error->kind == MONO_LOADER_ERROR_METHOD)
2824 ex = mono_get_exception_missing_method (class_name, error->member_name);
2826 ex = mono_get_exception_missing_field (class_name, error->member_name);
2827 g_free (class_name);
2831 g_assert_not_reached ();
2838 mini_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
2840 MonoInst *ins = NULL;
2842 static MonoClass *runtime_helpers_class = NULL;
2843 if (! runtime_helpers_class)
2844 runtime_helpers_class = mono_class_from_name (mono_defaults.corlib,
2845 "System.Runtime.CompilerServices", "RuntimeHelpers");
2847 if (cmethod->klass == mono_defaults.string_class) {
2848 if (cmethod->name [0] != 'g')
2851 if (strcmp (cmethod->name, "get_Chars") == 0) {
2852 MONO_INST_NEW (cfg, ins, OP_GETCHR);
2853 ins->inst_i0 = args [0];
2854 ins->inst_i1 = args [1];
2856 } else if (strcmp (cmethod->name, "get_Length") == 0) {
2857 MONO_INST_NEW (cfg, ins, OP_STRLEN);
2858 ins->inst_i0 = args [0];
2862 } else if (cmethod->klass == mono_defaults.object_class) {
2863 if (strcmp (cmethod->name, "GetType") == 0) {
2864 MONO_INST_NEW (cfg, ins, OP_GETTYPE);
2865 ins->inst_i0 = args [0];
2867 } else if (strcmp (cmethod->name, "InternalGetHashCode") == 0) {
2868 #ifdef MONO_ARCH_EMULATE_MUL_DIV
2869 /* The OP_GETHASHCODE rule depends on OP_MUL */
2871 MONO_INST_NEW (cfg, ins, OP_GETHASHCODE);
2872 ins->inst_i0 = args [0];
2875 } else if (strcmp (cmethod->name, ".ctor") == 0) {
2876 MONO_INST_NEW (cfg, ins, CEE_NOP);
2880 } else if (mini_class_is_system_array (cmethod->klass)) {
2881 if (cmethod->name [0] != 'g')
2884 if (strcmp (cmethod->name, "get_Rank") == 0) {
2885 MONO_INST_NEW (cfg, ins, OP_ARRAY_RANK);
2886 ins->inst_i0 = args [0];
2888 } else if (strcmp (cmethod->name, "get_Length") == 0) {
2889 MONO_INST_NEW (cfg, ins, CEE_LDLEN);
2890 ins->inst_i0 = args [0];
2894 } else if (cmethod->klass == runtime_helpers_class) {
2895 if (strcmp (cmethod->name, "get_OffsetToStringData") == 0) {
2896 NEW_ICONST (cfg, ins, G_STRUCT_OFFSET (MonoString, chars));
2900 } else if (cmethod->klass == mono_defaults.thread_class) {
2901 if (strcmp (cmethod->name, "get_CurrentThread") == 0 && (ins = mono_arch_get_thread_intrinsic (cfg)))
2905 return mono_arch_get_inst_for_method (cfg, cmethod, fsig, args);
2909 mono_save_args (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethodSignature *sig, MonoInst **sp, MonoInst **args)
2911 MonoInst *store, *temp;
2914 g_assert (!MONO_TYPE_ISSTRUCT (sig->ret));
2916 if (!sig->hasthis && sig->param_count == 0)
2920 if (sp [0]->opcode == OP_ICONST) {
2923 temp = mono_compile_create_var (cfg, type_from_stack_type (*sp), OP_LOCAL);
2925 NEW_TEMPSTORE (cfg, store, temp->inst_c0, *sp);
2926 store->cil_code = sp [0]->cil_code;
2927 MONO_ADD_INS (bblock, store);
2932 for (i = 0; i < sig->param_count; ++i) {
2933 if (sp [0]->opcode == OP_ICONST) {
2936 temp = mono_compile_create_var (cfg, sig->params [i], OP_LOCAL);
2938 NEW_TEMPSTORE (cfg, store, temp->inst_c0, *sp);
2939 store->cil_code = sp [0]->cil_code;
2940 if (store->opcode == CEE_STOBJ) {
2941 NEW_TEMPLOADA (cfg, store, temp->inst_c0);
2942 handle_stobj (cfg, bblock, store, *sp, sp [0]->cil_code, temp->klass, FALSE, FALSE);
2944 MONO_ADD_INS (bblock, store);
2952 inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoBasicBlock *bblock, MonoInst **sp,
2953 guchar *ip, guint real_offset, GList *dont_inline, MonoBasicBlock **last_b, gboolean inline_allways)
2955 MonoInst *ins, *rvar = NULL;
2956 MonoMethodHeader *cheader;
2957 MonoBasicBlock *ebblock, *sbblock;
2958 int i, costs, new_locals_offset;
2959 MonoMethod *prev_inlined_method;
2961 if (cfg->verbose_level > 2)
2962 g_print ("INLINE START %p %s -> %s\n", cmethod, mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
2964 if (!cmethod->inline_info) {
2965 mono_jit_stats.inlineable_methods++;
2966 cmethod->inline_info = 1;
2968 /* allocate space to store the return value */
2969 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
2970 rvar = mono_compile_create_var (cfg, fsig->ret, OP_LOCAL);
2973 /* allocate local variables */
2974 cheader = mono_method_get_header (cmethod);
2975 new_locals_offset = cfg->num_varinfo;
2976 for (i = 0; i < cheader->num_locals; ++i)
2977 mono_compile_create_var (cfg, cheader->locals [i], OP_LOCAL);
2979 /* allocate starte and end blocks */
2980 sbblock = NEW_BBLOCK (cfg);
2981 sbblock->block_num = cfg->num_bblocks++;
2982 sbblock->real_offset = real_offset;
2984 ebblock = NEW_BBLOCK (cfg);
2985 ebblock->block_num = cfg->num_bblocks++;
2986 ebblock->real_offset = real_offset;
2988 prev_inlined_method = cfg->inlined_method;
2989 cfg->inlined_method = cmethod;
2991 costs = mono_method_to_ir (cfg, cmethod, sbblock, ebblock, new_locals_offset, rvar, dont_inline, sp, real_offset, *ip == CEE_CALLVIRT);
2993 cfg->inlined_method = prev_inlined_method;
2995 if ((costs >= 0 && costs < 60) || inline_allways) {
2996 if (cfg->verbose_level > 2)
2997 g_print ("INLINE END %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
2999 mono_jit_stats.inlined_methods++;
3001 /* always add some code to avoid block split failures */
3002 MONO_INST_NEW (cfg, ins, CEE_NOP);
3003 MONO_ADD_INS (bblock, ins);
3006 bblock->next_bb = sbblock;
3007 link_bblock (cfg, bblock, sbblock);
3010 NEW_TEMPLOAD (cfg, ins, rvar->inst_c0);
3016 if (cfg->verbose_level > 2)
3017 g_print ("INLINE ABORTED %s\n", mono_method_full_name (cmethod, TRUE));
3023 * Some of these comments may well be out-of-date.
3024 * Design decisions: we do a single pass over the IL code (and we do bblock
3025 * splitting/merging in the few cases when it's required: a back jump to an IL
3026 * address that was not already seen as bblock starting point).
3027 * Code is validated as we go (full verification is still better left to metadata/verify.c).
3028 * Complex operations are decomposed in simpler ones right away. We need to let the
3029 * arch-specific code peek and poke inside this process somehow (except when the
3030 * optimizations can take advantage of the full semantic info of coarse opcodes).
3031 * All the opcodes of the form opcode.s are 'normalized' to opcode.
3032 * MonoInst->opcode initially is the IL opcode or some simplification of that
3033 * (OP_LOAD, OP_STORE). The arch-specific code may rearrange it to an arch-specific
3034 * opcode with value bigger than OP_LAST.
3035 * At this point the IR can be handed over to an interpreter, a dumb code generator
3036 * or to the optimizing code generator that will translate it to SSA form.
3038 * Profiling directed optimizations.
3039 * We may compile by default with few or no optimizations and instrument the code
3040 * or the user may indicate what methods to optimize the most either in a config file
3041 * or through repeated runs where the compiler applies offline the optimizations to
3042 * each method and then decides if it was worth it.
3045 * * consider using an array instead of an hash table (bb_hash)
3048 #define CHECK_TYPE(ins) if (!(ins)->type) goto unverified
3049 #define CHECK_STACK(num) if ((sp - stack_start) < (num)) goto unverified
3050 #define CHECK_STACK_OVF(num) if (((sp - stack_start) + (num)) > header->max_stack) goto unverified
3051 #define CHECK_ARG(num) if ((unsigned)(num) >= (unsigned)num_args) goto unverified
3052 #define CHECK_LOCAL(num) if ((unsigned)(num) >= (unsigned)header->num_locals) goto unverified
3053 #define CHECK_OPSIZE(size) if (ip + size > end) goto unverified
3056 /* offset from br.s -> br like opcodes */
3057 #define BIG_BRANCH_OFFSET 13
3060 ip_in_bb (MonoCompile *cfg, MonoBasicBlock *bb, const guint8* ip)
3062 MonoBasicBlock *b = g_hash_table_lookup (cfg->bb_hash, ip);
3064 return b == NULL || b == bb;
3068 get_basic_blocks (MonoCompile *cfg, GHashTable *bbhash, MonoMethodHeader* header, guint real_offset, unsigned char *start, unsigned char *end, unsigned char **pos)
3070 unsigned char *ip = start;
3071 unsigned char *target;
3074 MonoBasicBlock *bblock;
3075 const MonoOpcode *opcode;
3078 cli_addr = ip - start;
3079 i = mono_opcode_value ((const guint8 **)&ip, end);
3082 opcode = &mono_opcodes [i];
3083 switch (opcode->argument) {
3084 case MonoInlineNone:
3087 case MonoInlineString:
3088 case MonoInlineType:
3089 case MonoInlineField:
3090 case MonoInlineMethod:
3093 case MonoShortInlineR:
3100 case MonoShortInlineVar:
3101 case MonoShortInlineI:
3104 case MonoShortInlineBrTarget:
3105 target = start + cli_addr + 2 + (signed char)ip [1];
3106 GET_BBLOCK (cfg, bbhash, bblock, target);
3109 GET_BBLOCK (cfg, bbhash, bblock, ip);
3111 case MonoInlineBrTarget:
3112 target = start + cli_addr + 5 + (gint32)read32 (ip + 1);
3113 GET_BBLOCK (cfg, bbhash, bblock, target);
3116 GET_BBLOCK (cfg, bbhash, bblock, ip);
3118 case MonoInlineSwitch: {
3119 guint32 n = read32 (ip + 1);
3122 cli_addr += 5 + 4 * n;
3123 target = start + cli_addr;
3124 GET_BBLOCK (cfg, bbhash, bblock, target);
3126 for (j = 0; j < n; ++j) {
3127 target = start + cli_addr + (gint32)read32 (ip);
3128 GET_BBLOCK (cfg, bbhash, bblock, target);
3138 g_assert_not_reached ();
3141 if (i == CEE_THROW) {
3142 unsigned char *bb_start = ip - 1;
3144 /* Find the start of the bblock containing the throw */
3146 while ((bb_start > start) && !bblock) {
3147 bblock = g_hash_table_lookup (bbhash, (bb_start));
3151 bblock->out_of_line = 1;
3161 emit_tree (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *ins, const guint8* ip_next)
3163 MonoInst *store, *temp, *load;
3165 if (ip_in_bb (cfg, bblock, ip_next) &&
3166 (CODE_IS_STLOC (ip_next) || *ip_next == CEE_RET))
3169 temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
3170 temp->flags |= MONO_INST_IS_TEMP;
3171 NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
3172 store->cil_code = ins->cil_code;
3173 MONO_ADD_INS (bblock, store);
3174 NEW_TEMPLOAD (cfg, load, temp->inst_c0);
3175 load->cil_code = ins->cil_code;
3179 static inline MonoMethod *
3180 mini_get_method (MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
3184 if (m->wrapper_type != MONO_WRAPPER_NONE)
3185 return mono_method_get_wrapper_data (m, token);
3187 method = mono_get_method_full (m->klass->image, token, klass, context);
3189 if (method && method->is_inflated)
3190 method = mono_get_inflated_method (method);
3195 static inline MonoClass*
3196 mini_get_class (MonoMethod *method, guint32 token, MonoGenericContext *context)
3200 if (method->wrapper_type != MONO_WRAPPER_NONE)
3201 klass = mono_method_get_wrapper_data (method, token);
3203 klass = mono_class_get_full (method->klass->image, token, context);
3205 mono_class_init (klass);
3210 void check_linkdemand (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee, MonoBasicBlock *bblock, unsigned char *ip)
3212 guint32 result = mono_declsec_linkdemand (cfg->domain, caller, callee);
3213 if (result == MONO_JIT_SECURITY_OK)
3216 if (result == MONO_JIT_LINKDEMAND_ECMA) {
3217 /* Generate code to throw a SecurityException before the actual call/link */
3218 MonoAssembly *assembly = mono_image_get_assembly (caller->klass->image);
3219 MonoReflectionAssembly *refass = (MonoReflectionAssembly*) mono_assembly_get_object (cfg->domain, assembly);
3220 MonoReflectionMethod *refmet = mono_method_get_object (cfg->domain, caller, NULL);
3221 MonoSecurityManager *secman = mono_security_manager_get_methods ();
3224 NEW_ICONST (cfg, args [0], 4);
3225 NEW_PCONST (cfg, args [1], refass);
3226 NEW_PCONST (cfg, args [2], refmet);
3227 mono_emit_method_call_spilled (cfg, bblock, secman->linkdemandsecurityexception, mono_method_signature (secman->linkdemandsecurityexception), args, ip, NULL);
3228 } else if (cfg->exception_type == MONO_EXCEPTION_NONE) {
3229 /* don't hide previous results */
3230 cfg->exception_type = MONO_EXCEPTION_SECURITY_LINKDEMAND;
3231 cfg->exception_data = result;
3237 * mono_method_to_ir: translates IL into basic blocks containing trees
3240 mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock,
3241 int locals_offset, MonoInst *return_var, GList *dont_inline, MonoInst **inline_args,
3242 guint inline_offset, gboolean is_virtual_call)
3244 MonoInst *zero_int32, *zero_int64, *zero_ptr, *zero_obj, *zero_r8;
3245 MonoInst *ins, **sp, **stack_start;
3246 MonoBasicBlock *bblock, *tblock = NULL, *init_localsbb = NULL;
3248 MonoMethod *cmethod;
3249 MonoInst **arg_array;
3250 MonoMethodHeader *header;
3252 guint32 token, ins_flag;
3254 MonoClass *constrained_call = NULL;
3255 unsigned char *ip, *end, *target, *err_pos;
3256 static double r8_0 = 0.0;
3257 MonoMethodSignature *sig;
3258 MonoGenericContext *generic_context = NULL;
3259 MonoGenericContainer *generic_container = NULL;
3260 MonoType **param_types;
3261 GList *bb_recheck = NULL, *tmp;
3262 int i, n, start_new_bblock, align;
3263 int num_calls = 0, inline_costs = 0;
3264 int breakpoint_id = 0;
3265 guint real_offset, num_args;
3266 MonoBoolean security, pinvoke;
3267 MonoSecurityManager* secman = NULL;
3268 MonoDeclSecurityActions actions;
3269 GSList *class_inits = NULL;
3271 image = method->klass->image;
3272 header = mono_method_get_header (method);
3273 generic_container = ((MonoMethodNormal *)method)->generic_container;
3274 sig = mono_method_signature (method);
3275 num_args = sig->hasthis + sig->param_count;
3276 ip = (unsigned char*)header->code;
3277 end = ip + header->code_size;
3278 mono_jit_stats.cil_code_size += header->code_size;
3280 if (sig->is_inflated)
3281 generic_context = ((MonoMethodInflated *) method)->context;
3282 else if (generic_container)
3283 generic_context = &generic_container->context;
3285 g_assert (!sig->has_type_parameters);
3287 if (cfg->method == method) {
3289 bbhash = cfg->bb_hash;
3291 real_offset = inline_offset;
3292 bbhash = g_hash_table_new (g_direct_hash, NULL);
3295 if (cfg->verbose_level > 2)
3296 g_print ("method to IR %s\n", mono_method_full_name (method, TRUE));
3298 dont_inline = g_list_prepend (dont_inline, method);
3299 if (cfg->method == method) {
3301 if (cfg->method->save_lmf)
3302 /* Needed by the prolog code */
3303 mono_get_got_var (cfg);
3305 if (cfg->prof_options & MONO_PROFILE_INS_COVERAGE)
3306 cfg->coverage_info = mono_profiler_coverage_alloc (cfg->method, header->code_size);
3309 cfg->bb_entry = start_bblock = NEW_BBLOCK (cfg);
3310 start_bblock->cil_code = NULL;
3311 start_bblock->cil_length = 0;
3312 start_bblock->block_num = cfg->num_bblocks++;
3315 cfg->bb_exit = end_bblock = NEW_BBLOCK (cfg);
3316 end_bblock->cil_code = NULL;
3317 end_bblock->cil_length = 0;
3318 end_bblock->block_num = cfg->num_bblocks++;
3319 g_assert (cfg->num_bblocks == 2);
3321 arg_array = alloca (sizeof (MonoInst *) * num_args);
3322 for (i = num_args - 1; i >= 0; i--)
3323 arg_array [i] = cfg->varinfo [i];
3325 if (header->num_clauses) {
3326 cfg->spvars = g_hash_table_new (NULL, NULL);
3327 cfg->exvars = g_hash_table_new (NULL, NULL);
3329 /* handle exception clauses */
3330 for (i = 0; i < header->num_clauses; ++i) {
3331 //unsigned char *p = ip;
3332 MonoExceptionClause *clause = &header->clauses [i];
3333 GET_BBLOCK (cfg, bbhash, tblock, ip + clause->try_offset);
3334 tblock->real_offset = clause->try_offset;
3335 GET_BBLOCK (cfg, bbhash, tblock, ip + clause->handler_offset);
3336 tblock->real_offset = clause->handler_offset;
3338 if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY ||
3339 clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
3340 MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
3341 MONO_ADD_INS (tblock, ins);
3344 /*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);
3346 g_print ("%s", mono_disasm_code_one (NULL, method, p, &p));
3348 /* catch and filter blocks get the exception object on the stack */
3349 if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE ||
3350 clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
3351 MonoInst *load, *dummy_use;
3353 /* mostly like handle_stack_args (), but just sets the input args */
3354 /* g_print ("handling clause at IL_%04x\n", clause->handler_offset); */
3355 tblock->in_scount = 1;
3356 tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
3357 tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
3360 * Add a dummy use for the exvar so its liveness info will be
3363 NEW_TEMPLOAD (cfg, load, tblock->in_stack [0]->inst_c0);
3364 NEW_DUMMY_USE (cfg, dummy_use, load);
3365 MONO_ADD_INS (tblock, dummy_use);
3367 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
3368 GET_BBLOCK (cfg, bbhash, tblock, ip + clause->data.filter_offset);
3369 tblock->real_offset = clause->data.filter_offset;
3370 tblock->in_scount = 1;
3371 tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
3372 /* The filter block shares the exvar with the handler block */
3373 tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
3374 MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
3375 MONO_ADD_INS (tblock, ins);
3380 arg_array = alloca (sizeof (MonoInst *) * num_args);
3381 mono_save_args (cfg, start_bblock, sig, inline_args, arg_array);
3384 /* FIRST CODE BLOCK */
3385 bblock = NEW_BBLOCK (cfg);
3386 bblock->cil_code = ip;
3388 ADD_BBLOCK (cfg, bbhash, bblock);
3390 if (cfg->method == method) {
3391 breakpoint_id = mono_debugger_method_has_breakpoint (method);
3392 if (breakpoint_id && (mono_debug_format != MONO_DEBUG_FORMAT_DEBUGGER)) {
3393 MONO_INST_NEW (cfg, ins, CEE_BREAK);
3394 MONO_ADD_INS (bblock, ins);
3398 if (mono_use_security_manager)
3399 secman = mono_security_manager_get_methods ();
3401 security = (secman && mono_method_has_declsec (method));
3402 /* at this point having security doesn't mean we have any code to generate */
3403 if (security && (cfg->method == method)) {
3404 /* Only Demand, NonCasDemand and DemandChoice requires code generation.
3405 * And we do not want to enter the next section (with allocation) if we
3406 * have nothing to generate */
3407 security = mono_declsec_get_demands (method, &actions);
3410 /* we must Demand SecurityPermission.Unmanaged before P/Invoking */
3411 pinvoke = (secman && (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE));
3413 MonoMethod *wrapped = mono_marshal_method_from_wrapper (method);
3414 if (wrapped && (wrapped->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
3415 MonoCustomAttrInfo* custom = mono_custom_attrs_from_method (wrapped);
3417 /* unless the method or it's class has the [SuppressUnmanagedCodeSecurity] attribute */
3418 if (custom && mono_custom_attrs_has_attr (custom, secman->suppressunmanagedcodesecurity)) {
3423 custom = mono_custom_attrs_from_class (wrapped->klass);
3424 if (custom && mono_custom_attrs_has_attr (custom, secman->suppressunmanagedcodesecurity)) {
3429 /* not a P/Invoke after all */
3434 if ((header->init_locals || (cfg->method == method && (cfg->opt & MONO_OPT_SHARED))) || mono_compile_aot || security || pinvoke) {
3435 /* we use a separate basic block for the initialization code */
3436 cfg->bb_init = init_localsbb = NEW_BBLOCK (cfg);
3437 init_localsbb->real_offset = real_offset;
3438 start_bblock->next_bb = init_localsbb;
3439 init_localsbb->next_bb = bblock;
3440 link_bblock (cfg, start_bblock, init_localsbb);
3441 link_bblock (cfg, init_localsbb, bblock);
3442 init_localsbb->block_num = cfg->num_bblocks++;
3444 start_bblock->next_bb = bblock;
3445 link_bblock (cfg, start_bblock, bblock);
3448 /* at this point we know, if security is TRUE, that some code needs to be generated */
3449 if (security && (cfg->method == method)) {
3452 mono_jit_stats.cas_demand_generation++;
3454 if (actions.demand.blob) {
3455 /* Add code for SecurityAction.Demand */
3456 NEW_DECLSECCONST (cfg, args[0], image, actions.demand);
3457 NEW_ICONST (cfg, args [1], actions.demand.size);
3458 /* Calls static void SecurityManager.InternalDemand (byte* permissions, int size); */
3459 mono_emit_method_call_spilled (cfg, init_localsbb, secman->demand, mono_method_signature (secman->demand), args, ip, NULL);
3461 if (actions.noncasdemand.blob) {
3462 /* CLR 1.x uses a .noncasdemand (but 2.x doesn't) */
3463 /* For Mono we re-route non-CAS Demand to Demand (as the managed code must deal with it anyway) */
3464 NEW_DECLSECCONST (cfg, args[0], image, actions.noncasdemand);
3465 NEW_ICONST (cfg, args [1], actions.noncasdemand.size);
3466 /* Calls static void SecurityManager.InternalDemand (byte* permissions, int size); */
3467 mono_emit_method_call_spilled (cfg, init_localsbb, secman->demand, mono_method_signature (secman->demand), args, ip, NULL);
3469 if (actions.demandchoice.blob) {
3470 /* New in 2.0, Demand must succeed for one of the permissions (i.e. not all) */
3471 NEW_DECLSECCONST (cfg, args[0], image, actions.demandchoice);
3472 NEW_ICONST (cfg, args [1], actions.demandchoice.size);
3473 /* Calls static void SecurityManager.InternalDemandChoice (byte* permissions, int size); */
3474 mono_emit_method_call_spilled (cfg, init_localsbb, secman->demandchoice, mono_method_signature (secman->demandchoice), args, ip, NULL);
3478 /* we must Demand SecurityPermission.Unmanaged before p/invoking */
3480 mono_emit_method_call_spilled (cfg, init_localsbb, secman->demandunmanaged, mono_method_signature (secman->demandunmanaged), NULL, ip, NULL);
3483 if (get_basic_blocks (cfg, bbhash, header, real_offset, ip, end, &err_pos)) {
3488 if (cfg->method == method)
3489 mono_debug_init_method (cfg, bblock, breakpoint_id);
3491 param_types = mono_mempool_alloc (cfg->mempool, sizeof (MonoType*) * num_args);
3493 param_types [0] = method->klass->valuetype?&method->klass->this_arg:&method->klass->byval_arg;
3494 for (n = 0; n < sig->param_count; ++n)
3495 param_types [n + sig->hasthis] = sig->params [n];
3498 /* do this somewhere outside - not here */
3499 NEW_ICONST (cfg, zero_int32, 0);
3500 NEW_ICONST (cfg, zero_int64, 0);
3501 zero_int64->type = STACK_I8;
3502 NEW_PCONST (cfg, zero_ptr, 0);
3503 NEW_PCONST (cfg, zero_obj, 0);
3504 zero_obj->type = STACK_OBJ;
3506 MONO_INST_NEW (cfg, zero_r8, OP_R8CONST);
3507 zero_r8->type = STACK_R8;
3508 zero_r8->inst_p0 = &r8_0;
3510 /* add a check for this != NULL to inlined methods */
3511 if (is_virtual_call) {
3512 MONO_INST_NEW (cfg, ins, OP_CHECK_THIS);
3513 NEW_ARGLOAD (cfg, ins->inst_left, 0);
3515 MONO_ADD_INS (bblock, ins);
3518 /* we use a spare stack slot in SWITCH and NEWOBJ and others */
3519 stack_start = sp = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * (header->max_stack + 1));
3522 start_new_bblock = 0;
3525 if (cfg->method == method)
3526 real_offset = ip - header->code;
3528 real_offset = inline_offset;
3530 if (start_new_bblock) {
3531 bblock->cil_length = ip - bblock->cil_code;
3532 if (start_new_bblock == 2) {
3533 g_assert (ip == tblock->cil_code);
3535 GET_BBLOCK (cfg, bbhash, tblock, ip);
3537 bblock->next_bb = tblock;
3539 start_new_bblock = 0;
3540 for (i = 0; i < bblock->in_scount; ++i) {
3541 if (cfg->verbose_level > 3)
3542 g_print ("loading %d from temp %d\n", i, (int)bblock->in_stack [i]->inst_c0);
3543 NEW_TEMPLOAD (cfg, ins, bblock->in_stack [i]->inst_c0);
3546 g_slist_free (class_inits);
3549 if ((tblock = g_hash_table_lookup (bbhash, ip)) && (tblock != bblock)) {
3550 link_bblock (cfg, bblock, tblock);
3551 if (sp != stack_start) {
3552 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
3555 bblock->next_bb = tblock;
3557 for (i = 0; i < bblock->in_scount; ++i) {
3558 if (cfg->verbose_level > 3)
3559 g_print ("loading %d from temp %d\n", i, (int)bblock->in_stack [i]->inst_c0);
3560 NEW_TEMPLOAD (cfg, ins, bblock->in_stack [i]->inst_c0);
3563 g_slist_free (class_inits);
3568 bblock->real_offset = real_offset;
3570 if ((cfg->method == method) && cfg->coverage_info) {
3571 MonoInst *store, *one;
3572 guint32 cil_offset = ip - header->code;
3573 cfg->coverage_info->data [cil_offset].cil_code = ip;
3575 /* TODO: Use an increment here */
3576 NEW_ICONST (cfg, one, 1);
3579 NEW_PCONST (cfg, ins, &(cfg->coverage_info->data [cil_offset].count));
3582 MONO_INST_NEW (cfg, store, CEE_STIND_I);
3583 store->cil_code = ip;
3584 store->inst_left = ins;
3585 store->inst_right = one;
3587 MONO_ADD_INS (bblock, store);
3590 if (cfg->verbose_level > 3)
3591 g_print ("converting (in B%d: stack: %d) %s", bblock->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
3596 MONO_INST_NEW (cfg, ins, *ip);
3597 ins->cil_code = ip++;
3598 MONO_ADD_INS (bblock, ins);
3604 CHECK_STACK_OVF (1);
3605 n = (*ip)-CEE_LDARG_0;
3607 NEW_ARGLOAD (cfg, ins, n);
3608 ins->cil_code = ip++;
3615 CHECK_STACK_OVF (1);
3616 n = (*ip)-CEE_LDLOC_0;
3618 NEW_LOCLOAD (cfg, ins, n);
3619 ins->cil_code = ip++;
3627 n = (*ip)-CEE_STLOC_0;
3630 handle_loaded_temps (cfg, bblock, stack_start, sp);
3631 NEW_LOCSTORE (cfg, ins, n, *sp);
3633 if (ins->opcode == CEE_STOBJ) {
3634 NEW_LOCLOADA (cfg, ins, n);
3635 handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE);
3637 MONO_ADD_INS (bblock, ins);
3643 CHECK_STACK_OVF (1);
3645 NEW_ARGLOAD (cfg, ins, ip [1]);
3652 CHECK_STACK_OVF (1);
3654 NEW_ARGLOADA (cfg, ins, ip [1]);
3664 NEW_ARGSTORE (cfg, ins, ip [1], *sp);
3665 handle_loaded_temps (cfg, bblock, stack_start, sp);
3667 if (ins->opcode == CEE_STOBJ) {
3668 NEW_ARGLOADA (cfg, ins, ip [1]);
3669 handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE);
3671 MONO_ADD_INS (bblock, ins);
3676 CHECK_STACK_OVF (1);
3677 CHECK_LOCAL (ip [1]);
3678 NEW_LOCLOAD (cfg, ins, ip [1]);
3685 CHECK_STACK_OVF (1);
3686 CHECK_LOCAL (ip [1]);
3687 NEW_LOCLOADA (cfg, ins, ip [1]);
3696 handle_loaded_temps (cfg, bblock, stack_start, sp);
3697 CHECK_LOCAL (ip [1]);
3698 NEW_LOCSTORE (cfg, ins, ip [1], *sp);
3700 if (ins->opcode == CEE_STOBJ) {
3701 NEW_LOCLOADA (cfg, ins, ip [1]);
3702 handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE);
3704 MONO_ADD_INS (bblock, ins);
3709 CHECK_STACK_OVF (1);
3710 NEW_PCONST (cfg, ins, NULL);
3712 ins->type = STACK_OBJ;
3717 CHECK_STACK_OVF (1);
3718 NEW_ICONST (cfg, ins, -1);
3732 CHECK_STACK_OVF (1);
3733 NEW_ICONST (cfg, ins, (*ip) - CEE_LDC_I4_0);
3740 CHECK_STACK_OVF (1);
3742 NEW_ICONST (cfg, ins, *((signed char*)ip));
3749 CHECK_STACK_OVF (1);
3750 NEW_ICONST (cfg, ins, (gint32)read32 (ip + 1));
3757 CHECK_STACK_OVF (1);
3758 MONO_INST_NEW (cfg, ins, OP_I8CONST);
3760 ins->type = STACK_I8;
3762 ins->inst_l = (gint64)read64 (ip);
3768 /* we should really allocate this only late in the compilation process */
3769 mono_domain_lock (cfg->domain);
3770 f = mono_mempool_alloc (cfg->domain->mp, sizeof (float));
3771 mono_domain_unlock (cfg->domain);
3773 CHECK_STACK_OVF (1);
3774 MONO_INST_NEW (cfg, ins, OP_R4CONST);
3775 ins->type = STACK_R8;
3786 mono_domain_lock (cfg->domain);
3787 d = mono_mempool_alloc (cfg->domain->mp, sizeof (double));
3788 mono_domain_unlock (cfg->domain);
3790 CHECK_STACK_OVF (1);
3791 MONO_INST_NEW (cfg, ins, OP_R8CONST);
3792 ins->type = STACK_R8;
3802 MonoInst *temp, *store;
3804 CHECK_STACK_OVF (1);
3809 * small optimization: if the loaded value was from a local already,
3810 * just load it twice.
3812 if (ins->ssa_op == MONO_SSA_LOAD &&
3813 (ins->inst_i0->opcode == OP_LOCAL || ins->inst_i0->opcode == OP_ARG)) {
3815 MONO_INST_NEW (cfg, temp, 0);
3817 temp->cil_code = ip;
3820 temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
3821 temp->flags |= MONO_INST_IS_TEMP;
3822 temp->cil_code = ip;
3823 NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
3824 store->cil_code = ip;
3825 if (store->opcode == CEE_STOBJ) {
3826 NEW_TEMPLOADA (cfg, store, temp->inst_c0);
3827 handle_stobj (cfg, bblock, store, sp [0], sp [0]->cil_code, store->klass, TRUE, FALSE);
3829 MONO_ADD_INS (bblock, store);
3831 NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
3834 NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
3844 MONO_INST_NEW (cfg, ins, CEE_POP);
3845 MONO_ADD_INS (bblock, ins);
3846 ins->cil_code = ip++;
3852 if (stack_start != sp)
3854 MONO_INST_NEW (cfg, ins, CEE_JMP);
3855 token = read32 (ip + 1);
3856 /* FIXME: check the signature matches */
3857 cmethod = mini_get_method (method, token, NULL, generic_context);
3862 if (mono_use_security_manager) {
3863 check_linkdemand (cfg, method, cmethod, bblock, ip);
3866 ins->inst_p0 = cmethod;
3867 MONO_ADD_INS (bblock, ins);
3869 start_new_bblock = 1;
3873 case CEE_CALLVIRT: {
3874 MonoInst *addr = NULL;
3875 MonoMethodSignature *fsig = NULL;
3876 int temp, array_rank = 0;
3877 int virtual = *ip == CEE_CALLVIRT;
3880 token = read32 (ip + 1);
3882 if (*ip == CEE_CALLI) {
3887 if (method->wrapper_type != MONO_WRAPPER_NONE)
3888 fsig = (MonoMethodSignature *)mono_method_get_wrapper_data (method, token);
3890 fsig = mono_metadata_parse_signature (image, token);
3892 n = fsig->param_count + fsig->hasthis;
3894 if (method->wrapper_type != MONO_WRAPPER_NONE) {
3895 cmethod = (MonoMethod *)mono_method_get_wrapper_data (method, token);
3896 } else if (constrained_call) {
3897 cmethod = mono_get_method_constrained (image, token, constrained_call, generic_context);
3898 cmethod = mono_get_inflated_method (cmethod);
3900 cmethod = mini_get_method (method, token, NULL, generic_context);
3906 if (!virtual && (cmethod->flags & METHOD_ATTRIBUTE_ABSTRACT))
3907 /* MS.NET seems to silently convert this to a callvirt */
3910 if (!cmethod->klass->inited)
3911 mono_class_init (cmethod->klass);
3913 if (mono_method_signature (cmethod)->pinvoke) {
3914 MonoMethod *wrapper = mono_marshal_get_native_wrapper (cmethod);
3915 fsig = mono_method_signature (wrapper);
3916 } else if (constrained_call) {
3917 fsig = mono_method_signature (cmethod);
3919 fsig = mono_method_get_signature_full (cmethod, image, token, generic_context);
3922 n = fsig->param_count + fsig->hasthis;
3924 if (mono_use_security_manager) {
3925 check_linkdemand (cfg, method, cmethod, bblock, ip);
3928 if (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL &&
3929 mini_class_is_system_array (cmethod->klass)) {
3930 array_rank = cmethod->klass->rank;
3933 if (cmethod->string_ctor)
3934 g_assert_not_reached ();
3939 mono_get_got_var (cfg);
3941 /* code in inssel.brg might transform a virtual call to a normal call */
3942 if (!(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
3943 ((cmethod->flags & METHOD_ATTRIBUTE_FINAL) &&
3944 cmethod->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK))
3945 mono_get_got_var (cfg);
3948 if (cmethod && cmethod->klass->generic_container) {
3955 //g_assert (!virtual || fsig->hasthis);
3959 if (constrained_call) {
3961 * We have the `constrained.' prefix opcode.
3963 if (constrained_call->valuetype && !cmethod->klass->valuetype) {
3966 * The type parameter is instantiated as a valuetype,
3967 * but that type doesn't override the method we're
3968 * calling, so we need to box `this'.
3969 * sp [0] is a pointer to the data: we need the value
3970 * in handle_box (), so load it here.
3972 MONO_INST_NEW (cfg, load, mono_type_to_ldind (&constrained_call->byval_arg));
3973 type_to_eval_stack_type (&constrained_call->byval_arg, load);
3974 load->cil_code = ip;
3975 load->inst_left = sp [0];
3976 sp [0] = handle_box (cfg, bblock, load, ip, constrained_call);
3977 } else if (!constrained_call->valuetype) {
3981 * The type parameter is instantiated as a reference
3982 * type. We have a managed pointer on the stack, so
3983 * we need to dereference it here.
3986 MONO_INST_NEW (cfg, ins, CEE_LDIND_REF);
3988 ins->inst_i0 = sp [0];
3989 ins->type = STACK_OBJ;
3991 } else if (cmethod->klass->valuetype)
3993 constrained_call = NULL;
3996 if (*ip != CEE_CALLI && check_call_signature (cfg, fsig, sp)) {
4001 if (cmethod && virtual &&
4002 (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) &&
4003 !((cmethod->flags & METHOD_ATTRIBUTE_FINAL) &&
4004 cmethod->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK) &&
4005 mono_method_signature (cmethod)->generic_param_count) {
4006 MonoInst *this_temp, *store;
4007 MonoInst *iargs [3];
4009 g_assert (mono_method_signature (cmethod)->is_inflated);
4011 this_temp = mono_compile_create_var (cfg, type_from_stack_type (sp [0]), OP_LOCAL);
4012 this_temp->cil_code = ip;
4013 NEW_TEMPSTORE (cfg, store, this_temp->inst_c0, sp [0]);
4015 store->cil_code = ip;
4016 MONO_ADD_INS (bblock, store);
4018 NEW_TEMPLOAD (cfg, iargs [0], this_temp->inst_c0);
4019 NEW_PCONST (cfg, iargs [1], cmethod);
4020 NEW_PCONST (cfg, iargs [2], ((MonoMethodInflated *) cmethod)->context);
4021 temp = mono_emit_jit_icall (cfg, bblock, helper_compile_generic_method, iargs, ip);
4023 NEW_TEMPLOAD (cfg, addr, temp);
4024 NEW_TEMPLOAD (cfg, sp [0], this_temp->inst_c0);
4026 if ((temp = mono_emit_calli (cfg, bblock, fsig, sp, addr, ip)) != -1) {
4027 NEW_TEMPLOAD (cfg, *sp, temp);
4035 if ((ins_flag & MONO_INST_TAILCALL) && cmethod && (*ip == CEE_CALL) &&
4036 (mono_metadata_signature_equal (mono_method_signature (method), mono_method_signature (cmethod)))) {
4038 /* FIXME: This assumes the two methods has the same number and type of arguments */
4039 for (i = 0; i < n; ++i) {
4040 /* Check if argument is the same */
4041 NEW_ARGLOAD (cfg, ins, i);
4042 if ((ins->opcode == sp [i]->opcode) && (ins->inst_i0 == sp [i]->inst_i0))
4045 /* Prevent argument from being register allocated */
4046 arg_array [i]->flags |= MONO_INST_VOLATILE;
4047 NEW_ARGSTORE (cfg, ins, i, sp [i]);
4049 if (ins->opcode == CEE_STOBJ) {
4050 NEW_ARGLOADA (cfg, ins, i);
4051 handle_stobj (cfg, bblock, ins, sp [i], sp [i]->cil_code, ins->klass, FALSE, FALSE);
4054 MONO_ADD_INS (bblock, ins);
4056 MONO_INST_NEW (cfg, ins, CEE_JMP);
4058 ins->inst_p0 = cmethod;
4059 ins->inst_p1 = arg_array [0];
4060 MONO_ADD_INS (bblock, ins);
4061 link_bblock (cfg, bblock, end_bblock);
4062 start_new_bblock = 1;
4063 /* skip CEE_RET as well */
4068 if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_get_inst_for_method (cfg, cmethod, fsig, sp))) {
4071 if (MONO_TYPE_IS_VOID (fsig->ret)) {
4072 MONO_ADD_INS (bblock, ins);
4074 type_to_eval_stack_type (fsig->ret, ins);
4083 handle_loaded_temps (cfg, bblock, stack_start, sp);
4085 if ((cfg->opt & MONO_OPT_INLINE) && cmethod &&
4086 (!virtual || !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) || (cmethod->flags & METHOD_ATTRIBUTE_FINAL)) &&
4087 mono_method_check_inlining (cfg, cmethod) &&
4088 !g_list_find (dont_inline, cmethod)) {
4090 MonoBasicBlock *ebblock;
4091 gboolean allways = FALSE;
4093 if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
4094 (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
4095 cmethod = mono_marshal_get_native_wrapper (cmethod);
4099 if ((costs = inline_method (cfg, cmethod, fsig, bblock, sp, ip, real_offset, dont_inline, &ebblock, allways))) {
4103 GET_BBLOCK (cfg, bbhash, bblock, ip);
4104 ebblock->next_bb = bblock;
4105 link_bblock (cfg, ebblock, bblock);
4107 if (!MONO_TYPE_IS_VOID (fsig->ret))
4110 /* indicates start of a new block, and triggers a load of all
4111 stack arguments at bb boundarie */
4114 inline_costs += costs;
4119 inline_costs += 10 * num_calls++;
4121 /* tail recursion elimination */
4122 if ((cfg->opt & MONO_OPT_TAILC) && *ip == CEE_CALL && cmethod == method && ip [5] == CEE_RET) {
4123 gboolean has_vtargs = FALSE;
4126 /* keep it simple */
4127 for (i = fsig->param_count - 1; i >= 0; i--) {
4128 if (MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->params [i]))
4133 for (i = 0; i < n; ++i) {
4134 NEW_ARGSTORE (cfg, ins, i, sp [i]);
4136 MONO_ADD_INS (bblock, ins);
4138 MONO_INST_NEW (cfg, ins, CEE_BR);
4140 MONO_ADD_INS (bblock, ins);
4141 tblock = start_bblock->out_bb [0];
4142 link_bblock (cfg, bblock, tblock);
4143 ins->inst_target_bb = tblock;
4144 start_new_bblock = 1;
4146 /* skip the CEE_RET, too */
4147 if (ip_in_bb (cfg, bblock, ip + 5))
4156 if (*ip == CEE_CALLI) {
4158 if ((temp = mono_emit_calli (cfg, bblock, fsig, sp, addr, ip)) != -1) {
4159 NEW_TEMPLOAD (cfg, *sp, temp);
4163 } else if (array_rank) {
4166 if (strcmp (cmethod->name, "Set") == 0) { /* array Set */
4167 if (sp [fsig->param_count]->type == STACK_OBJ) {
4168 MonoInst *iargs [2];
4169 MonoInst *array, *to_store, *store;
4171 handle_loaded_temps (cfg, bblock, stack_start, sp);
4173 array = mono_compile_create_var (cfg, type_from_stack_type (sp [0]), OP_LOCAL);
4174 NEW_TEMPSTORE (cfg, store, array->inst_c0, sp [0]);
4175 store->cil_code = ip;
4176 MONO_ADD_INS (bblock, store);
4177 NEW_TEMPLOAD (cfg, iargs [0], array->inst_c0);
4179 to_store = mono_compile_create_var (cfg, type_from_stack_type (sp [fsig->param_count]), OP_LOCAL);
4180 NEW_TEMPSTORE (cfg, store, to_store->inst_c0, sp [fsig->param_count]);
4181 store->cil_code = ip;
4182 MONO_ADD_INS (bblock, store);
4183 NEW_TEMPLOAD (cfg, iargs [1], to_store->inst_c0);
4186 * We first save the args for the call so that the args are copied to the stack
4187 * and a new instruction tree for them is created. If we don't do this,
4188 * the same MonoInst is added to two different trees and this is not
4191 mono_emit_jit_icall (cfg, bblock, helper_stelem_ref_check, iargs, ip);
4193 NEW_TEMPLOAD (cfg, sp [0], array->inst_c0);
4194 NEW_TEMPLOAD (cfg, sp [fsig->param_count], to_store->inst_c0);
4197 addr = mini_get_ldelema_ins (cfg, bblock, cmethod, sp, ip, TRUE);
4198 NEW_INDSTORE (cfg, ins, addr, sp [fsig->param_count], fsig->params [fsig->param_count - 1]);
4200 if (ins->opcode == CEE_STOBJ) {
4201 handle_stobj (cfg, bblock, addr, sp [fsig->param_count], ip, mono_class_from_mono_type (fsig->params [fsig->param_count-1]), FALSE, FALSE);
4203 MONO_ADD_INS (bblock, ins);
4206 } else if (strcmp (cmethod->name, "Get") == 0) { /* array Get */
4207 addr = mini_get_ldelema_ins (cfg, bblock, cmethod, sp, ip, FALSE);
4208 NEW_INDLOAD (cfg, ins, addr, fsig->ret);
4212 } else if (strcmp (cmethod->name, "Address") == 0) { /* array Address */
4213 addr = mini_get_ldelema_ins (cfg, bblock, cmethod, sp, ip, FALSE);
4216 g_assert_not_reached ();
4220 if (ip_in_bb (cfg, bblock, ip + 5)
4221 && (!MONO_TYPE_ISSTRUCT (fsig->ret))
4222 && (!MONO_TYPE_IS_VOID (fsig->ret) || cmethod->string_ctor)
4223 && (CODE_IS_STLOC (ip + 5) || ip [5] == CEE_POP || ip [5] == CEE_RET)) {
4224 /* no need to spill */
4225 ins = (MonoInst*)mono_emit_method_call (cfg, bblock, cmethod, fsig, sp, ip, virtual ? sp [0] : NULL);
4228 if ((temp = mono_emit_method_call_spilled (cfg, bblock, cmethod, fsig, sp, ip, virtual ? sp [0] : NULL)) != -1) {
4229 NEW_TEMPLOAD (cfg, *sp, temp);
4239 if (cfg->method != method) {
4240 /* return from inlined methode */
4245 //g_assert (returnvar != -1);
4246 NEW_TEMPSTORE (cfg, store, return_var->inst_c0, *sp);
4247 store->cil_code = sp [0]->cil_code;
4248 if (store->opcode == CEE_STOBJ) {
4249 g_assert_not_reached ();
4250 NEW_TEMPLOADA (cfg, store, return_var->inst_c0);
4251 handle_stobj (cfg, bblock, store, *sp, sp [0]->cil_code, return_var->klass, FALSE, FALSE);
4253 MONO_ADD_INS (bblock, store);
4257 g_assert (!return_var);
4260 MONO_INST_NEW (cfg, ins, CEE_NOP);
4261 ins->opcode = mono_type_to_stind (mono_method_signature (method)->ret);
4262 if (ins->opcode == CEE_STOBJ) {
4263 NEW_RETLOADA (cfg, ins);
4264 handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE);
4266 ins->opcode = OP_SETRET;
4268 ins->inst_i0 = *sp;;
4269 ins->inst_i1 = NULL;
4270 MONO_ADD_INS (bblock, ins);
4274 if (sp != stack_start)
4276 MONO_INST_NEW (cfg, ins, CEE_BR);
4277 ins->cil_code = ip++;
4278 ins->inst_target_bb = end_bblock;
4279 MONO_ADD_INS (bblock, ins);
4280 link_bblock (cfg, bblock, end_bblock);
4281 start_new_bblock = 1;
4285 MONO_INST_NEW (cfg, ins, CEE_BR);
4286 ins->cil_code = ip++;
4287 MONO_ADD_INS (bblock, ins);
4288 target = ip + 1 + (signed char)(*ip);
4290 GET_BBLOCK (cfg, bbhash, tblock, target);
4291 link_bblock (cfg, bblock, tblock);
4292 CHECK_BBLOCK (target, ip, tblock);
4293 ins->inst_target_bb = tblock;
4294 if (sp != stack_start) {
4295 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
4298 start_new_bblock = 1;
4305 MONO_INST_NEW (cfg, ins, *ip + BIG_BRANCH_OFFSET);
4306 ins->cil_code = ip++;
4307 target = ip + 1 + *(signed char*)ip;
4309 ADD_UNCOND (ins->opcode == CEE_BRTRUE);
4310 if (sp != stack_start) {
4311 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
4328 MONO_INST_NEW (cfg, ins, *ip + BIG_BRANCH_OFFSET);
4329 ins->cil_code = ip++;
4330 target = ip + 1 + *(signed char*)ip;
4333 if (sp != stack_start) {
4334 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
4341 MONO_INST_NEW (cfg, ins, CEE_BR);
4342 ins->cil_code = ip++;
4343 MONO_ADD_INS (bblock, ins);
4344 target = ip + 4 + (gint32)read32(ip);
4346 GET_BBLOCK (cfg, bbhash, tblock, target);
4347 link_bblock (cfg, bblock, tblock);
4348 CHECK_BBLOCK (target, ip, tblock);
4349 ins->inst_target_bb = tblock;
4350 if (sp != stack_start) {
4351 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
4354 start_new_bblock = 1;
4361 MONO_INST_NEW (cfg, ins, *ip);
4362 ins->cil_code = ip++;
4363 target = ip + 4 + (gint32)read32(ip);
4365 ADD_UNCOND(ins->opcode == CEE_BRTRUE);
4366 if (sp != stack_start) {
4367 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
4384 MONO_INST_NEW (cfg, ins, *ip);
4385 ins->cil_code = ip++;
4386 target = ip + 4 + (gint32)read32(ip);
4389 if (sp != stack_start) {
4390 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
4398 n = read32 (ip + 1);
4399 MONO_INST_NEW (cfg, ins, *ip);
4401 ins->inst_left = *sp;
4402 if ((ins->inst_left->type != STACK_I4) && (ins->inst_left->type != STACK_PTR))
4406 CHECK_OPSIZE (n * sizeof (guint32));
4407 target = ip + n * sizeof (guint32);
4408 MONO_ADD_INS (bblock, ins);
4409 GET_BBLOCK (cfg, bbhash, tblock, target);
4410 link_bblock (cfg, bblock, tblock);
4411 ins->klass = GUINT_TO_POINTER (n);
4412 ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * (n + 1));
4413 ins->inst_many_bb [n] = tblock;
4415 for (i = 0; i < n; ++i) {
4416 GET_BBLOCK (cfg, bbhash, tblock, target + (gint32)read32(ip));
4417 link_bblock (cfg, bblock, tblock);
4418 ins->inst_many_bb [i] = tblock;
4421 if (sp != stack_start) {
4422 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
4425 /* Needed by the code generated in inssel.brg */
4426 mono_get_got_var (cfg);
4441 MONO_INST_NEW (cfg, ins, *ip);
4446 ins->type = ldind_type [*ip - CEE_LDIND_I1];
4447 ins->flags |= ins_flag;
4459 MONO_INST_NEW (cfg, ins, *ip);
4460 ins->cil_code = ip++;
4462 handle_loaded_temps (cfg, bblock, stack_start, sp);
4463 MONO_ADD_INS (bblock, ins);
4464 ins->inst_i0 = sp [0];
4465 ins->inst_i1 = sp [1];
4466 ins->flags |= ins_flag;
4474 #ifdef MONO_ARCH_NO_EMULATE_MUL_IMM
4475 /* FIXME: This breaks with ssapre (mono -O=ssapre loader.exe) */
4476 if ((ins->inst_right->opcode == OP_ICONST) && !(cfg->opt & MONO_OPT_SSAPRE)) {
4477 switch (ins->opcode) {
4479 ins->opcode = OP_IMUL_IMM;
4480 ins->inst_imm = ins->inst_right->inst_c0;
4483 ins->opcode = OP_LMUL_IMM;
4484 ins->inst_imm = ins->inst_right->inst_c0;
4487 g_assert_not_reached ();
4492 if (mono_find_jit_opcode_emulation (ins->opcode)) {
4494 *sp++ = emit_tree (cfg, bblock, ins, ip + 1);
4495 mono_get_got_var (cfg);
4513 /* special case that gives a nice speedup and happens to workaorund a ppc jit but (for the release)
4514 * later apply the speedup to the left shift as well
4517 if ((ins->opcode == OP_LSHR_UN) && (ins->type == STACK_I8)
4518 && (ins->inst_right->opcode == OP_ICONST) && (ins->inst_right->inst_c0 == 32)) {
4519 ins->opcode = OP_LONG_SHRUN_32;
4520 /*g_print ("applied long shr speedup to %s\n", cfg->method->name);*/
4524 if (mono_find_jit_opcode_emulation (ins->opcode)) {
4526 *sp++ = emit_tree (cfg, bblock, ins, ip + 1);
4527 mono_get_got_var (cfg);
4541 case CEE_CONV_OVF_I8:
4542 case CEE_CONV_OVF_U8:
4546 if (mono_find_jit_opcode_emulation (ins->opcode)) {
4548 *sp++ = emit_tree (cfg, bblock, ins, ip + 1);
4549 mono_get_got_var (cfg);
4553 case CEE_CONV_OVF_I4:
4554 case CEE_CONV_OVF_I1:
4555 case CEE_CONV_OVF_I2:
4556 case CEE_CONV_OVF_I:
4557 case CEE_CONV_OVF_U:
4560 if (sp [-1]->type == STACK_R8) {
4561 ADD_UNOP (CEE_CONV_OVF_I8);
4569 case CEE_CONV_OVF_U1:
4570 case CEE_CONV_OVF_U2:
4571 case CEE_CONV_OVF_U4:
4574 if (sp [-1]->type == STACK_R8) {
4575 ADD_UNOP (CEE_CONV_OVF_U8);
4583 case CEE_CONV_OVF_I1_UN:
4584 case CEE_CONV_OVF_I2_UN:
4585 case CEE_CONV_OVF_I4_UN:
4586 case CEE_CONV_OVF_I8_UN:
4587 case CEE_CONV_OVF_U1_UN:
4588 case CEE_CONV_OVF_U2_UN:
4589 case CEE_CONV_OVF_U4_UN:
4590 case CEE_CONV_OVF_U8_UN:
4591 case CEE_CONV_OVF_I_UN:
4592 case CEE_CONV_OVF_U_UN:
4600 token = read32 (ip + 1);
4601 klass = mini_get_class (method, token, generic_context);
4605 if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
4606 MonoInst *store, *load;
4607 MONO_INST_NEW (cfg, load, CEE_LDIND_REF);
4608 load->cil_code = ip;
4609 load->inst_i0 = sp [1];
4610 load->type = STACK_OBJ;
4611 load->flags |= ins_flag;
4612 MONO_INST_NEW (cfg, store, CEE_STIND_REF);
4613 store->cil_code = ip;
4614 handle_loaded_temps (cfg, bblock, stack_start, sp);
4615 MONO_ADD_INS (bblock, store);
4616 store->inst_i0 = sp [0];
4617 store->inst_i1 = load;
4618 store->flags |= ins_flag;
4620 n = mono_class_value_size (klass, NULL);
4621 if ((cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 5) {
4623 MONO_INST_NEW (cfg, copy, OP_MEMCPY);
4624 copy->inst_left = sp [0];
4625 copy->inst_right = sp [1];
4626 copy->cil_code = ip;
4628 MONO_ADD_INS (bblock, copy);
4630 MonoMethod *memcpy_method = get_memcpy_method ();
4631 MonoInst *iargs [3];
4634 NEW_ICONST (cfg, iargs [2], n);
4635 iargs [2]->cil_code = ip;
4637 mono_emit_method_call_spilled (cfg, bblock, memcpy_method, memcpy_method->signature, iargs, ip, NULL);
4644 MonoInst *iargs [3];
4650 token = read32 (ip + 1);
4651 klass = mini_get_class (method, token, generic_context);
4654 if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
4655 MONO_INST_NEW (cfg, ins, CEE_LDIND_REF);
4657 ins->inst_i0 = sp [0];
4658 ins->type = STACK_OBJ;
4659 ins->flags |= ins_flag;
4666 /* Optimize the common ldobj+stloc combination */
4676 loc_index = ip [5] - CEE_STLOC_0;
4683 if ((loc_index != -1) && ip_in_bb (cfg, bblock, ip + 5)) {
4684 CHECK_LOCAL (loc_index);
4685 NEW_LOCSTORE (cfg, ins, loc_index, *sp);
4687 if (ins->opcode == CEE_STOBJ) {
4688 handle_loaded_temps (cfg, bblock, stack_start, sp);
4690 g_assert (ins->opcode == CEE_STOBJ);
4691 NEW_LOCLOADA (cfg, ins, loc_index);
4692 handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE);
4699 n = mono_class_value_size (klass, NULL);
4700 ins = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
4701 NEW_TEMPLOADA (cfg, iargs [0], ins->inst_c0);
4702 if ((cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 5) {
4704 MONO_INST_NEW (cfg, copy, OP_MEMCPY);
4705 copy->inst_left = iargs [0];
4706 copy->inst_right = *sp;
4707 copy->cil_code = ip;
4709 MONO_ADD_INS (bblock, copy);
4711 MonoMethod *memcpy_method = get_memcpy_method ();
4713 NEW_ICONST (cfg, iargs [2], n);
4714 iargs [2]->cil_code = ip;
4716 mono_emit_method_call_spilled (cfg, bblock, memcpy_method, memcpy_method->signature, iargs, ip, NULL);
4718 NEW_TEMPLOAD (cfg, *sp, ins->inst_c0);
4726 CHECK_STACK_OVF (1);
4728 n = read32 (ip + 1);
4730 if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
4731 NEW_PCONST (cfg, ins, mono_method_get_wrapper_data (method, n));
4733 ins->type = STACK_OBJ;
4736 else if (method->wrapper_type != MONO_WRAPPER_NONE) {
4738 MonoInst *iargs [1];
4740 NEW_PCONST (cfg, iargs [0], mono_method_get_wrapper_data (method, n));
4741 temp = mono_emit_jit_icall (cfg, bblock, mono_string_new_wrapper, iargs, ip);
4742 NEW_TEMPLOAD (cfg, *sp, temp);
4746 if (cfg->opt & MONO_OPT_SHARED) {
4748 MonoInst *iargs [3];
4749 MonoInst* domain_var;
4751 if (cfg->compile_aot) {
4752 cfg->ldstr_list = g_list_prepend (cfg->ldstr_list, GINT_TO_POINTER (n));
4754 /* avoid depending on undefined C behavior in sequence points */
4755 domain_var = mono_get_domainvar (cfg);
4756 NEW_TEMPLOAD (cfg, iargs [0], domain_var->inst_c0);
4757 NEW_IMAGECONST (cfg, iargs [1], image);
4758 NEW_ICONST (cfg, iargs [2], mono_metadata_token_index (n));
4759 temp = mono_emit_jit_icall (cfg, bblock, mono_ldstr, iargs, ip);
4760 NEW_TEMPLOAD (cfg, *sp, temp);
4761 mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
4763 if (bblock->out_of_line) {
4764 MonoInst *iargs [2];
4767 /* Avoid creating the string object */
4768 NEW_IMAGECONST (cfg, iargs [0], image);
4769 NEW_ICONST (cfg, iargs [1], mono_metadata_token_index (n));
4770 temp = mono_emit_jit_icall (cfg, bblock, helper_ldstr, iargs, ip);
4771 NEW_TEMPLOAD (cfg, *sp, temp);
4774 if (cfg->compile_aot) {
4775 NEW_LDSTRCONST (cfg, ins, image, n);
4779 NEW_PCONST (cfg, ins, NULL);
4781 ins->type = STACK_OBJ;
4782 ins->inst_p0 = mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
4792 MonoInst *iargs [2];
4793 MonoMethodSignature *fsig;
4797 token = read32 (ip + 1);
4798 cmethod = mini_get_method (method, token, NULL, generic_context);
4801 fsig = mono_method_get_signature (cmethod, image, token);
4803 mono_class_init (cmethod->klass);
4805 if (mono_use_security_manager) {
4806 check_linkdemand (cfg, method, cmethod, bblock, ip);
4809 n = fsig->param_count;
4812 /* move the args to allow room for 'this' in the first position */
4818 handle_loaded_temps (cfg, bblock, stack_start, sp);
4820 if (mini_class_is_system_array (cmethod->klass)) {
4821 NEW_METHODCONST (cfg, *sp, cmethod);
4822 temp = handle_array_new (cfg, bblock, fsig->param_count, sp, ip);
4823 } else if (cmethod->string_ctor) {
4824 /* we simply pass a null pointer */
4825 NEW_PCONST (cfg, *sp, NULL);
4826 /* now call the string ctor */
4827 temp = mono_emit_method_call_spilled (cfg, bblock, cmethod, fsig, sp, ip, NULL);
4829 MonoInst* callvirt_this_arg = NULL;
4831 if (cmethod->klass->valuetype) {
4832 iargs [0] = mono_compile_create_var (cfg, &cmethod->klass->byval_arg, OP_LOCAL);
4833 temp = iargs [0]->inst_c0;
4835 NEW_TEMPLOADA (cfg, *sp, temp);
4837 handle_initobj (cfg, bblock, *sp, NULL, cmethod->klass, stack_start, sp);
4839 NEW_TEMPLOADA (cfg, *sp, temp);
4842 * The code generated by mini_emit_virtual_call () expects
4843 * iargs [0] to be a boxed instance, but luckily the vcall
4844 * will be transformed into a normal call there. The AOT
4845 * case needs an already allocate got_var.
4847 mono_get_got_var (cfg);
4849 temp = handle_alloc (cfg, bblock, cmethod->klass, FALSE, ip);
4850 NEW_TEMPLOAD (cfg, *sp, temp);
4853 /* Avoid virtual calls to ctors if possible */
4854 if (cmethod->klass->marshalbyref)
4855 callvirt_this_arg = sp [0];
4857 if ((cfg->opt & MONO_OPT_INLINE) && cmethod &&
4858 mono_method_check_inlining (cfg, cmethod) &&
4859 !mono_class_is_subclass_of (cmethod->klass, mono_defaults.exception_class, FALSE) &&
4860 !g_list_find (dont_inline, cmethod)) {
4862 MonoBasicBlock *ebblock;
4863 if ((costs = inline_method (cfg, cmethod, fsig, bblock, sp, ip, real_offset, dont_inline, &ebblock, FALSE))) {
4868 GET_BBLOCK (cfg, bbhash, bblock, ip);
4869 ebblock->next_bb = bblock;
4870 link_bblock (cfg, ebblock, bblock);
4872 NEW_TEMPLOAD (cfg, *sp, temp);
4875 /* indicates start of a new block, and triggers a load
4876 of all stack arguments at bb boundarie */
4879 inline_costs += costs;
4883 mono_emit_method_call_spilled (cfg, bblock, cmethod, fsig, sp, ip, callvirt_this_arg);
4886 /* now call the actual ctor */
4887 mono_emit_method_call_spilled (cfg, bblock, cmethod, fsig, sp, ip, callvirt_this_arg);
4891 NEW_TEMPLOAD (cfg, *sp, temp);
4902 token = read32 (ip + 1);
4903 klass = mini_get_class (method, token, generic_context);
4907 /* Needed by the code generated in inssel.brg */
4908 mono_get_got_var (cfg);
4910 if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4912 MonoMethod *mono_isinst;
4913 MonoInst *iargs [1];
4914 MonoBasicBlock *ebblock;
4918 mono_isinst = mono_marshal_get_isinst (klass);
4921 costs = inline_method (cfg, mono_isinst, mono_method_signature (mono_isinst), bblock,
4922 iargs, ip, real_offset, dont_inline, &ebblock, TRUE);
4924 g_assert (costs > 0);
4929 GET_BBLOCK (cfg, bbhash, bblock, ip);
4930 ebblock->next_bb = bblock;
4931 link_bblock (cfg, ebblock, bblock);
4933 temp = iargs [0]->inst_i0->inst_c0;
4934 NEW_TEMPLOAD (cfg, *sp, temp);
4938 inline_costs += costs;
4942 MONO_INST_NEW (cfg, ins, *ip);
4943 ins->type = STACK_OBJ;
4944 ins->inst_left = *sp;
4945 ins->inst_newa_class = klass;
4947 *sp++ = emit_tree (cfg, bblock, ins, ip + 5);
4951 case CEE_UNBOX_ANY: {
4952 MonoInst *add, *vtoffset;
4953 MonoInst *iargs [3];
4958 token = read32 (ip + 1);
4959 klass = mini_get_class (method, token, generic_context);
4963 if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
4965 if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4966 MonoMethod *mono_castclass;
4967 MonoInst *iargs [1];
4968 MonoBasicBlock *ebblock;
4972 mono_castclass = mono_marshal_get_castclass (klass);
4975 costs = inline_method (cfg, mono_castclass, mono_method_signature (mono_castclass), bblock,
4976 iargs, ip, real_offset, dont_inline, &ebblock, TRUE);
4978 g_assert (costs > 0);
4983 GET_BBLOCK (cfg, bbhash, bblock, ip);
4984 ebblock->next_bb = bblock;
4985 link_bblock (cfg, ebblock, bblock);
4987 temp = iargs [0]->inst_i0->inst_c0;
4988 NEW_TEMPLOAD (cfg, *sp, temp);
4992 inline_costs += costs;
4995 MONO_INST_NEW (cfg, ins, CEE_CASTCLASS);
4996 ins->type = STACK_OBJ;
4997 ins->inst_left = *sp;
4999 ins->inst_newa_class = klass;
5007 MONO_INST_NEW (cfg, ins, OP_UNBOXCAST);
5008 ins->type = STACK_OBJ;
5009 ins->inst_left = *sp;
5011 ins->inst_newa_class = klass;
5014 MONO_INST_NEW (cfg, add, OP_PADD);
5015 NEW_ICONST (cfg, vtoffset, sizeof (MonoObject));
5016 add->inst_left = ins;
5017 add->inst_right = vtoffset;
5018 add->type = STACK_MP;
5022 n = mono_class_value_size (klass, NULL);
5023 ins = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
5024 NEW_TEMPLOADA (cfg, iargs [0], ins->inst_c0);
5025 if ((cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 5) {
5027 MONO_INST_NEW (cfg, copy, OP_MEMCPY);
5028 copy->inst_left = iargs [0];
5029 copy->inst_right = *sp;
5030 copy->cil_code = ip;
5032 MONO_ADD_INS (bblock, copy);
5034 MonoMethod *memcpy_method = get_memcpy_method ();
5036 NEW_ICONST (cfg, iargs [2], n);
5037 iargs [2]->cil_code = ip;
5039 mono_emit_method_call_spilled (cfg, bblock, memcpy_method, memcpy_method->signature, iargs, ip, NULL);
5041 NEW_TEMPLOAD (cfg, *sp, ins->inst_c0);
5047 MonoInst *add, *vtoffset;
5052 token = read32 (ip + 1);
5053 klass = mini_get_class (method, token, generic_context);
5057 /* Needed by the code generated in inssel.brg */
5058 mono_get_got_var (cfg);
5060 MONO_INST_NEW (cfg, ins, OP_UNBOXCAST);
5061 ins->type = STACK_OBJ;
5062 ins->inst_left = *sp;
5064 ins->inst_newa_class = klass;
5067 MONO_INST_NEW (cfg, add, OP_PADD);
5068 NEW_ICONST (cfg, vtoffset, sizeof (MonoObject));
5069 add->inst_left = ins;
5070 add->inst_right = vtoffset;
5071 add->type = STACK_MP;
5081 token = read32 (ip + 1);
5082 klass = mini_get_class (method, token, generic_context);
5086 /* Needed by the code generated in inssel.brg */
5087 mono_get_got_var (cfg);
5089 if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
5091 MonoMethod *mono_castclass;
5092 MonoInst *iargs [1];
5093 MonoBasicBlock *ebblock;
5097 mono_castclass = mono_marshal_get_castclass (klass);
5100 costs = inline_method (cfg, mono_castclass, mono_method_signature (mono_castclass), bblock,
5101 iargs, ip, real_offset, dont_inline, &ebblock, TRUE);
5103 g_assert (costs > 0);
5108 GET_BBLOCK (cfg, bbhash, bblock, ip);
5109 ebblock->next_bb = bblock;
5110 link_bblock (cfg, ebblock, bblock);
5112 temp = iargs [0]->inst_i0->inst_c0;
5113 NEW_TEMPLOAD (cfg, *sp, temp);
5117 inline_costs += costs;
5120 MONO_INST_NEW (cfg, ins, *ip);
5121 ins->type = STACK_OBJ;
5122 ins->inst_left = *sp;
5124 ins->inst_newa_class = klass;
5126 *sp++ = emit_tree (cfg, bblock, ins, ip + 5);
5132 MONO_INST_NEW (cfg, ins, *ip);
5134 ins->inst_left = *sp;
5135 ins->cil_code = ip++;
5136 bblock->out_of_line = TRUE;
5137 MONO_ADD_INS (bblock, ins);
5138 MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
5139 ins->cil_code = ip - 1;
5140 MONO_ADD_INS (bblock, ins);
5142 link_bblock (cfg, bblock, end_bblock);
5143 start_new_bblock = 1;
5144 mono_get_got_var (cfg);
5149 MonoInst *offset_ins;
5150 MonoClassField *field;
5151 MonoBasicBlock *ebblock;
5155 if (*ip == CEE_STFLD) {
5162 // FIXME: enable this test later.
5163 //if (sp [0]->type != STACK_OBJ && sp [0]->type != STACK_MP)
5166 token = read32 (ip + 1);
5167 field = mono_field_from_token (image, token, &klass, generic_context);
5170 mono_class_init (klass);
5172 foffset = klass->valuetype? field->offset - sizeof (MonoObject): field->offset;
5173 /* FIXME: mark instructions for use in SSA */
5174 if (*ip == CEE_STFLD) {
5175 if ((klass->marshalbyref && !MONO_CHECK_THIS (sp [0])) || klass->contextbound || klass == mono_defaults.marshalbyrefobject_class) {
5176 MonoMethod *stfld_wrapper = mono_marshal_get_stfld_wrapper (field->type);
5177 MonoInst *iargs [5];
5180 NEW_CLASSCONST (cfg, iargs [1], klass);
5181 NEW_FIELDCONST (cfg, iargs [2], field);
5182 NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) :
5186 if (cfg->opt & MONO_OPT_INLINE) {
5187 costs = inline_method (cfg, stfld_wrapper, mono_method_signature (stfld_wrapper), bblock,
5188 iargs, ip, real_offset, dont_inline, &ebblock, TRUE);
5189 g_assert (costs > 0);
5194 GET_BBLOCK (cfg, bbhash, bblock, ip);
5195 ebblock->next_bb = bblock;
5196 link_bblock (cfg, ebblock, bblock);
5198 /* indicates start of a new block, and triggers a load
5199 of all stack arguments at bb boundarie */
5202 inline_costs += costs;
5205 mono_emit_method_call_spilled (cfg, bblock, stfld_wrapper, mono_method_signature (stfld_wrapper), iargs, ip, NULL);
5209 NEW_ICONST (cfg, offset_ins, foffset);
5210 MONO_INST_NEW (cfg, ins, OP_PADD);
5212 ins->inst_left = *sp;
5213 ins->inst_right = offset_ins;
5214 ins->type = STACK_MP;
5216 MONO_INST_NEW (cfg, store, mono_type_to_stind (field->type));
5217 store->cil_code = ip;
5218 store->inst_left = ins;
5219 store->inst_right = sp [1];
5220 handle_loaded_temps (cfg, bblock, stack_start, sp);
5221 store->flags |= ins_flag;
5223 if (store->opcode == CEE_STOBJ) {
5224 handle_stobj (cfg, bblock, ins, sp [1], ip,
5225 mono_class_from_mono_type (field->type), FALSE, FALSE);
5227 MONO_ADD_INS (bblock, store);
5230 if ((klass->marshalbyref && !MONO_CHECK_THIS (sp [0])) || klass->contextbound || klass == mono_defaults.marshalbyrefobject_class) {
5231 MonoMethod *ldfld_wrapper = mono_marshal_get_ldfld_wrapper (field->type);
5232 MonoInst *iargs [4];
5236 NEW_CLASSCONST (cfg, iargs [1], klass);
5237 NEW_FIELDCONST (cfg, iargs [2], field);
5238 NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : field->offset);
5239 if ((cfg->opt & MONO_OPT_INLINE) && !MONO_TYPE_ISSTRUCT (mono_method_signature (ldfld_wrapper)->ret)) {
5240 costs = inline_method (cfg, ldfld_wrapper, mono_method_signature (ldfld_wrapper), bblock,
5241 iargs, ip, real_offset, dont_inline, &ebblock, TRUE);
5242 g_assert (costs > 0);
5247 GET_BBLOCK (cfg, bbhash, bblock, ip);
5248 ebblock->next_bb = bblock;
5249 link_bblock (cfg, ebblock, bblock);
5251 temp = iargs [0]->inst_i0->inst_c0;
5253 if (*ip == CEE_LDFLDA) {
5254 /* not sure howto handle this */
5255 NEW_TEMPLOADA (cfg, *sp, temp);
5257 NEW_TEMPLOAD (cfg, *sp, temp);
5261 /* indicates start of a new block, and triggers a load of
5262 all stack arguments at bb boundarie */
5265 inline_costs += costs;
5268 temp = mono_emit_method_call_spilled (cfg, bblock, ldfld_wrapper, mono_method_signature (ldfld_wrapper), iargs, ip, NULL);
5269 if (*ip == CEE_LDFLDA) {
5270 /* not sure howto handle this */
5271 NEW_TEMPLOADA (cfg, *sp, temp);
5273 NEW_TEMPLOAD (cfg, *sp, temp);
5278 NEW_ICONST (cfg, offset_ins, foffset);
5279 MONO_INST_NEW (cfg, ins, OP_PADD);
5281 ins->inst_left = *sp;
5282 ins->inst_right = offset_ins;
5283 ins->type = STACK_MP;
5285 if (*ip == CEE_LDFLDA) {
5289 MONO_INST_NEW (cfg, load, mono_type_to_ldind (field->type));
5290 type_to_eval_stack_type (field->type, load);
5291 load->cil_code = ip;
5292 load->inst_left = ins;
5293 load->flags |= ins_flag;
5305 MonoClassField *field;
5306 gpointer addr = NULL;
5309 token = read32 (ip + 1);
5311 field = mono_field_from_token (image, token, &klass, generic_context);
5314 mono_class_init (klass);
5316 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
5318 if ((*ip) == CEE_STSFLD)
5319 handle_loaded_temps (cfg, bblock, stack_start, sp);
5321 /* The special_static_fields field is init'd in mono_class_vtable, so it needs
5322 * to be called here.
5324 if (!(cfg->opt & MONO_OPT_SHARED))
5325 mono_class_vtable (cfg->domain, klass);
5326 mono_domain_lock (cfg->domain);
5327 if (cfg->domain->special_static_fields)
5328 addr = g_hash_table_lookup (cfg->domain->special_static_fields, field);
5329 mono_domain_unlock (cfg->domain);
5331 if ((cfg->opt & MONO_OPT_SHARED) || (cfg->compile_aot && addr)) {
5333 MonoInst *iargs [2];
5334 MonoInst *domain_var;
5336 g_assert (field->parent);
5337 /* avoid depending on undefined C behavior in sequence points */
5338 domain_var = mono_get_domainvar (cfg);
5339 NEW_TEMPLOAD (cfg, iargs [0], domain_var->inst_c0);
5340 NEW_FIELDCONST (cfg, iargs [1], field);
5341 temp = mono_emit_jit_icall (cfg, bblock, mono_class_static_field_address, iargs, ip);
5342 NEW_TEMPLOAD (cfg, ins, temp);
5345 vtable = mono_class_vtable (cfg->domain, klass);
5347 if (mini_field_access_needs_cctor_run (cfg, method, vtable) && !(g_slist_find (class_inits, vtable))) {
5348 guint8 *tramp = mono_create_class_init_trampoline (vtable);
5349 mono_emit_native_call (cfg, bblock, tramp,
5350 helper_sig_class_init_trampoline,
5351 NULL, ip, FALSE, FALSE);
5352 if (cfg->verbose_level > 2)
5353 g_print ("class %s.%s needs init call for %s\n", klass->name_space, klass->name, field->name);
5354 class_inits = g_slist_prepend (class_inits, vtable);
5356 if (cfg->run_cctors)
5357 mono_runtime_class_init (vtable);
5359 addr = (char*)vtable->data + field->offset;
5361 if (cfg->compile_aot)
5362 NEW_SFLDACONST (cfg, ins, field);
5364 NEW_PCONST (cfg, ins, addr);
5368 * insert call to mono_threads_get_static_data (GPOINTER_TO_UINT (addr))
5369 * This could be later optimized to do just a couple of
5370 * memory dereferences with constant offsets.
5373 MonoInst *iargs [1];
5374 NEW_ICONST (cfg, iargs [0], GPOINTER_TO_UINT (addr));
5375 temp = mono_emit_jit_icall (cfg, bblock, mono_get_special_static_data, iargs, ip);
5376 NEW_TEMPLOAD (cfg, ins, temp);
5380 /* FIXME: mark instructions for use in SSA */
5381 if (*ip == CEE_LDSFLDA) {
5383 } else if (*ip == CEE_STSFLD) {
5387 MONO_INST_NEW (cfg, store, mono_type_to_stind (field->type));
5388 store->cil_code = ip;
5389 store->inst_left = ins;
5390 store->inst_right = sp [0];
5391 store->flags |= ins_flag;
5394 if (store->opcode == CEE_STOBJ) {
5395 handle_stobj (cfg, bblock, ins, sp [0], ip, mono_class_from_mono_type (field->type), FALSE, FALSE);
5397 MONO_ADD_INS (bblock, store);
5399 gboolean is_const = FALSE;
5400 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
5401 if (!((cfg->opt & MONO_OPT_SHARED) || cfg->compile_aot) &&
5402 vtable->initialized && (field->type->attrs & FIELD_ATTRIBUTE_INIT_ONLY)) {
5403 gpointer addr = (char*)vtable->data + field->offset;
5404 int ro_type = field->type->type;
5405 if (ro_type == MONO_TYPE_VALUETYPE && field->type->data.klass->enumtype) {
5406 ro_type = field->type->data.klass->enum_basetype->type;
5408 /* g_print ("RO-FIELD %s.%s:%s\n", klass->name_space, klass->name, field->name);*/
5411 case MONO_TYPE_BOOLEAN:
5413 NEW_ICONST (cfg, *sp, *((guint8 *)addr));
5417 NEW_ICONST (cfg, *sp, *((gint8 *)addr));
5420 case MONO_TYPE_CHAR:
5422 NEW_ICONST (cfg, *sp, *((guint16 *)addr));
5426 NEW_ICONST (cfg, *sp, *((gint16 *)addr));
5431 NEW_ICONST (cfg, *sp, *((gint32 *)addr));
5435 NEW_ICONST (cfg, *sp, *((guint32 *)addr));
5440 case MONO_TYPE_STRING:
5441 case MONO_TYPE_OBJECT:
5442 case MONO_TYPE_CLASS:
5443 case MONO_TYPE_SZARRAY:
5445 case MONO_TYPE_FNPTR:
5446 case MONO_TYPE_ARRAY:
5447 NEW_PCONST (cfg, *sp, *((gpointer *)addr));
5448 type_to_eval_stack_type (field->type, *sp);
5453 MONO_INST_NEW (cfg, *sp, OP_I8CONST);
5454 sp [0]->type = STACK_I8;
5455 sp [0]->inst_l = *((gint64 *)addr);
5460 case MONO_TYPE_VALUETYPE:
5469 CHECK_STACK_OVF (1);
5470 MONO_INST_NEW (cfg, load, mono_type_to_ldind (field->type));
5471 type_to_eval_stack_type (field->type, load);
5472 load->cil_code = ip;
5473 load->inst_left = ins;
5475 load->flags |= ins_flag;
5477 /* fixme: dont see the problem why this does not work */
5478 //cfg->disable_aot = TRUE;
5488 token = read32 (ip + 1);
5489 klass = mini_get_class (method, token, generic_context);
5492 n = mono_type_to_stind (&klass->byval_arg);
5493 if (n == CEE_STOBJ) {
5494 handle_stobj (cfg, bblock, sp [0], sp [1], ip, klass, FALSE, FALSE);
5496 /* FIXME: should check item at sp [1] is compatible with the type of the store. */
5498 MONO_INST_NEW (cfg, store, n);
5499 store->cil_code = ip;
5500 store->inst_left = sp [0];
5501 store->inst_right = sp [1];
5502 store->flags |= ins_flag;
5503 MONO_ADD_INS (bblock, store);
5515 token = read32 (ip + 1);
5516 klass = mini_get_class (method, token, generic_context);
5520 if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
5525 *sp++ = handle_box (cfg, bblock, val, ip, klass);
5532 MONO_INST_NEW (cfg, ins, *ip);
5537 token = read32 (ip + 1);
5539 /* allocate the domainvar - becaus this is used in decompose_foreach */
5540 if (cfg->opt & MONO_OPT_SHARED) {
5541 mono_get_domainvar (cfg);
5542 /* LAME-IR: Mark it as used since otherwise it will be optimized away */
5543 cfg->domainvar->flags |= MONO_INST_VOLATILE;
5547 mono_get_got_var (cfg);
5549 klass = mini_get_class (method, token, generic_context);
5552 ins->inst_newa_class = klass;
5553 ins->inst_newa_len = *sp;
5554 ins->type = STACK_OBJ;
5558 * we store the object so calls to create the array are not interleaved
5559 * with the arguments of other calls.
5562 MonoInst *store, *temp, *load;
5564 temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
5565 NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
5566 store->cil_code = ins->cil_code;
5567 MONO_ADD_INS (bblock, store);
5568 NEW_TEMPLOAD (cfg, load, temp->inst_c0);
5569 load->cil_code = ins->cil_code;
5576 MONO_INST_NEW (cfg, ins, *ip);
5577 ins->cil_code = ip++;
5579 ins->inst_left = *sp;
5580 ins->type = STACK_PTR;
5588 klass = mini_get_class (method, read32 (ip + 1), generic_context);
5591 /* we need to make sure that this array is exactly the type it needs
5592 * to be for correctness. the wrappers are lax with their usage
5593 * so we need to ignore them here
5595 if (!klass->valuetype && method->wrapper_type == MONO_WRAPPER_NONE) {
5597 MONO_INST_NEW (cfg, check, OP_CHECK_ARRAY_TYPE);
5598 check->cil_code = ip;
5599 check->klass = klass;
5600 check->inst_left = sp [0];
5601 check->type = STACK_OBJ;
5605 mono_class_init (klass);
5606 NEW_LDELEMA (cfg, ins, sp, klass);
5611 case CEE_LDELEM_ANY: {
5616 token = read32 (ip + 1);
5617 klass = mono_class_get_full (image, token, generic_context);
5620 mono_class_init (klass);
5621 NEW_LDELEMA (cfg, load, sp, klass);
5622 load->cil_code = ip;
5623 MONO_INST_NEW (cfg, ins, mono_type_to_ldind (&klass->byval_arg));
5625 ins->inst_left = load;
5627 type_to_eval_stack_type (&klass->byval_arg, ins);
5641 case CEE_LDELEM_REF: {
5645 * ldind.x (ldelema (array, index))
5646 * ldelema does the bounds check
5650 klass = array_access_to_klass (*ip);
5651 NEW_LDELEMA (cfg, load, sp, klass);
5652 load->cil_code = ip;
5653 MONO_INST_NEW (cfg, ins, ldelem_to_ldind [*ip - CEE_LDELEM_I1]);
5655 ins->inst_left = load;
5657 ins->type = ldind_type [ins->opcode - CEE_LDIND_I1];
5667 case CEE_STELEM_R8: {
5671 * stind.x (ldelema (array, index), val)
5672 * ldelema does the bounds check
5676 klass = array_access_to_klass (*ip);
5677 NEW_LDELEMA (cfg, load, sp, klass);
5678 load->cil_code = ip;
5679 MONO_INST_NEW (cfg, ins, stelem_to_stind [*ip - CEE_STELEM_I]);
5681 ins->inst_left = load;
5682 ins->inst_right = sp [2];
5684 handle_loaded_temps (cfg, bblock, stack_start, sp);
5685 MONO_ADD_INS (bblock, ins);
5689 case CEE_STELEM_ANY: {
5693 * stind.x (ldelema (array, index), val)
5694 * ldelema does the bounds check
5699 token = read32 (ip + 1);
5700 klass = mono_class_get_full (image, token, generic_context);
5703 mono_class_init (klass);
5704 if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
5705 MonoMethod* helper = mono_marshal_get_stelemref ();
5706 MonoInst *iargs [3];
5707 handle_loaded_temps (cfg, bblock, stack_start, sp);
5713 mono_emit_method_call_spilled (cfg, bblock, helper, mono_method_signature (helper), iargs, ip, NULL);
5715 NEW_LDELEMA (cfg, load, sp, klass);
5716 load->cil_code = ip;
5718 n = mono_type_to_stind (&klass->byval_arg);
5720 handle_stobj (cfg, bblock, load, sp [2], ip, klass, FALSE, FALSE);
5722 MONO_INST_NEW (cfg, ins, n);
5724 ins->inst_left = load;
5725 ins->inst_right = sp [2];
5726 handle_loaded_temps (cfg, bblock, stack_start, sp);
5727 MONO_ADD_INS (bblock, ins);
5734 case CEE_STELEM_REF: {
5735 MonoInst *iargs [3];
5736 MonoMethod* helper = mono_marshal_get_stelemref ();
5741 handle_loaded_temps (cfg, bblock, stack_start, sp);
5747 mono_emit_method_call_spilled (cfg, bblock, helper, mono_method_signature (helper), iargs, ip, NULL);
5751 NEW_GROUP (cfg, group, sp [0], sp [1]);
5752 MONO_INST_NEW (cfg, ins, CEE_STELEM_REF);
5754 ins->inst_left = group;
5755 ins->inst_right = sp [2];
5756 MONO_ADD_INS (bblock, ins);
5763 case CEE_CKFINITE: {
5764 MonoInst *store, *temp;
5767 /* this instr. can throw exceptions as side effect,
5768 * so we cant eliminate dead code which contains CKFINITE opdodes.
5769 * Spilling to memory makes sure that we always perform
5773 MONO_INST_NEW (cfg, ins, CEE_CKFINITE);
5775 ins->inst_left = sp [-1];
5776 temp = mono_compile_create_var (cfg, &mono_defaults.double_class->byval_arg, OP_LOCAL);
5778 NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
5779 store->cil_code = ip;
5780 MONO_ADD_INS (bblock, store);
5782 NEW_TEMPLOAD (cfg, sp [-1], temp->inst_c0);
5789 MONO_INST_NEW (cfg, ins, *ip);
5792 klass = mono_class_get_full (image, read32 (ip + 1), generic_context);
5795 mono_class_init (klass);
5796 ins->type = STACK_MP;
5797 ins->inst_left = *sp;
5799 ins->inst_newa_class = klass;
5804 case CEE_MKREFANY: {
5805 MonoInst *loc, *klassconst;
5808 MONO_INST_NEW (cfg, ins, *ip);
5811 klass = mono_class_get_full (image, read32 (ip + 1), generic_context);
5814 mono_class_init (klass);
5817 loc = mono_compile_create_var (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL);
5818 NEW_TEMPLOADA (cfg, ins->inst_right, loc->inst_c0);
5820 NEW_PCONST (cfg, klassconst, klass);
5821 NEW_GROUP (cfg, ins->inst_left, *sp, klassconst);
5823 MONO_ADD_INS (bblock, ins);
5825 NEW_TEMPLOAD (cfg, *sp, loc->inst_c0);
5832 MonoClass *handle_class;
5834 CHECK_STACK_OVF (1);
5837 n = read32 (ip + 1);
5839 if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
5840 handle = mono_method_get_wrapper_data (method, n);
5841 handle_class = mono_method_get_wrapper_data (method, n + 1);
5844 handle = mono_ldtoken (image, n, &handle_class, generic_context);
5848 mono_class_init (handle_class);
5850 if (cfg->opt & MONO_OPT_SHARED) {
5852 MonoInst *res, *store, *addr, *vtvar, *iargs [3];
5854 vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL);
5856 NEW_IMAGECONST (cfg, iargs [0], image);
5857 NEW_ICONST (cfg, iargs [1], n);
5858 NEW_PCONST (cfg, iargs [2], generic_context);
5859 temp = mono_emit_jit_icall (cfg, bblock, mono_ldtoken_wrapper, iargs, ip);
5860 NEW_TEMPLOAD (cfg, res, temp);
5861 NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
5862 NEW_INDSTORE (cfg, store, addr, res, &mono_defaults.int_class->byval_arg);
5863 MONO_ADD_INS (bblock, store);
5864 NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
5866 if ((ip [5] == CEE_CALL) && (cmethod = mini_get_method (method, read32 (ip + 6), NULL, generic_context)) &&
5867 (cmethod->klass == mono_defaults.monotype_class->parent) &&
5868 (strcmp (cmethod->name, "GetTypeFromHandle") == 0) && ip_in_bb (cfg, bblock, ip + 5)) {
5869 MonoClass *tclass = mono_class_from_mono_type (handle);
5870 mono_class_init (tclass);
5871 if (cfg->compile_aot)
5872 NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, image, n);
5874 NEW_PCONST (cfg, ins, mono_type_get_object (cfg->domain, handle));
5875 ins->type = STACK_OBJ;
5876 ins->klass = cmethod->klass;
5879 MonoInst *store, *addr, *vtvar;
5881 if (cfg->compile_aot)
5882 NEW_LDTOKENCONST (cfg, ins, image, n);
5884 NEW_PCONST (cfg, ins, handle);
5885 vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL);
5886 NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
5887 NEW_INDSTORE (cfg, store, addr, ins, &mono_defaults.int_class->byval_arg);
5888 MONO_ADD_INS (bblock, store);
5889 NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
5905 case CEE_ADD_OVF_UN:
5907 case CEE_MUL_OVF_UN:
5909 case CEE_SUB_OVF_UN:
5912 if (mono_find_jit_opcode_emulation (ins->opcode)) {
5914 *sp++ = emit_tree (cfg, bblock, ins, ip + 1);
5915 mono_get_got_var (cfg);
5919 case CEE_ENDFINALLY:
5920 MONO_INST_NEW (cfg, ins, *ip);
5921 MONO_ADD_INS (bblock, ins);
5922 ins->cil_code = ip++;
5923 start_new_bblock = 1;
5926 * Control will leave the method so empty the stack, otherwise
5927 * the next basic block will start with a nonempty stack.
5929 while (sp != stack_start) {
5930 MONO_INST_NEW (cfg, ins, CEE_POP);
5934 MONO_ADD_INS (bblock, ins);
5941 if (*ip == CEE_LEAVE) {
5943 target = ip + 5 + (gint32)read32(ip + 1);
5946 target = ip + 2 + (signed char)(ip [1]);
5949 /* empty the stack */
5950 while (sp != stack_start) {
5951 MONO_INST_NEW (cfg, ins, CEE_POP);
5955 MONO_ADD_INS (bblock, ins);
5959 * If this leave statement is in a catch block, check for a
5960 * pending exception, and rethrow it if necessary.
5962 for (i = 0; i < header->num_clauses; ++i) {
5963 MonoExceptionClause *clause = &header->clauses [i];
5965 if (MONO_OFFSET_IN_HANDLER (clause, ip - header->code) && (clause->flags == MONO_EXCEPTION_CLAUSE_NONE) && (ip - header->code + ((*ip == CEE_LEAVE) ? 5 : 2)) == (clause->handler_offset + clause->handler_len)) {
5969 NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, clause->handler_offset)->inst_c0);
5970 load->cil_code = ip;
5972 temp = mono_emit_jit_icall (cfg, bblock, mono_thread_get_pending_exception, NULL, ip);
5973 NEW_TEMPLOAD (cfg, *sp, temp);
5975 MONO_INST_NEW (cfg, ins, OP_THROW_OR_NULL);
5976 ins->inst_left = *sp;
5977 ins->inst_right = load;
5979 MONO_ADD_INS (bblock, ins);
5983 /* fixme: call fault handler ? */
5985 if ((handlers = mono_find_final_block (cfg, ip, target, MONO_EXCEPTION_CLAUSE_FINALLY))) {
5987 for (tmp = handlers; tmp; tmp = tmp->next) {
5989 link_bblock (cfg, bblock, tblock);
5990 MONO_INST_NEW (cfg, ins, OP_CALL_HANDLER);
5992 ins->inst_target_bb = tblock;
5993 MONO_ADD_INS (bblock, ins);
5995 g_list_free (handlers);
5998 MONO_INST_NEW (cfg, ins, CEE_BR);
6000 MONO_ADD_INS (bblock, ins);
6001 GET_BBLOCK (cfg, bbhash, tblock, target);
6002 link_bblock (cfg, bblock, tblock);
6003 CHECK_BBLOCK (target, ip, tblock);
6004 ins->inst_target_bb = tblock;
6005 start_new_bblock = 1;
6007 if (*ip == CEE_LEAVE)
6016 MONO_INST_NEW (cfg, ins, *ip);
6018 handle_loaded_temps (cfg, bblock, stack_start, sp);
6019 MONO_ADD_INS (bblock, ins);
6020 ins->cil_code = ip++;
6021 ins->inst_i0 = sp [0];
6022 ins->inst_i1 = sp [1];
6030 /* trampoline mono specific opcodes */
6031 case MONO_CUSTOM_PREFIX: {
6033 g_assert (method->wrapper_type != MONO_WRAPPER_NONE);
6038 case CEE_MONO_ICALL: {
6041 MonoJitICallInfo *info;
6043 token = read32 (ip + 2);
6044 func = mono_method_get_wrapper_data (method, token);
6045 info = mono_find_jit_icall_by_addr (func);
6048 CHECK_STACK (info->sig->param_count);
6049 sp -= info->sig->param_count;
6051 temp = mono_emit_jit_icall (cfg, bblock, info->func, sp, ip);
6052 if (!MONO_TYPE_IS_VOID (info->sig->ret)) {
6053 NEW_TEMPLOAD (cfg, *sp, temp);
6058 inline_costs += 10 * num_calls++;
6062 case CEE_MONO_LDPTR:
6063 CHECK_STACK_OVF (1);
6065 token = read32 (ip + 2);
6066 NEW_PCONST (cfg, ins, mono_method_get_wrapper_data (method, token));
6070 inline_costs += 10 * num_calls++;
6071 /* Can't embed random pointers into AOT code */
6072 cfg->disable_aot = 1;
6074 case CEE_MONO_VTADDR:
6077 MONO_INST_NEW (cfg, ins, OP_VTADDR);
6079 ins->type = STACK_MP;
6080 ins->inst_left = *sp;
6084 case CEE_MONO_NEWOBJ: {
6085 MonoInst *iargs [2];
6087 CHECK_STACK_OVF (1);
6089 token = read32 (ip + 2);
6090 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
6091 mono_class_init (klass);
6092 NEW_DOMAINCONST (cfg, iargs [0]);
6093 NEW_CLASSCONST (cfg, iargs [1], klass);
6094 temp = mono_emit_jit_icall (cfg, bblock, mono_object_new, iargs, ip);
6095 NEW_TEMPLOAD (cfg, *sp, temp);
6098 inline_costs += 10 * num_calls++;
6101 case CEE_MONO_OBJADDR:
6104 MONO_INST_NEW (cfg, ins, OP_OBJADDR);
6106 ins->type = STACK_MP;
6107 ins->inst_left = *sp;
6111 case CEE_MONO_LDNATIVEOBJ:
6114 token = read32 (ip + 2);
6115 klass = mono_method_get_wrapper_data (method, token);
6116 g_assert (klass->valuetype);
6117 mono_class_init (klass);
6118 NEW_INDLOAD (cfg, ins, sp [-1], &klass->byval_arg);
6122 case CEE_MONO_RETOBJ:
6123 g_assert (cfg->ret);
6124 g_assert (mono_method_signature (method)->pinvoke);
6129 token = read32 (ip + 2);
6130 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
6132 NEW_RETLOADA (cfg, ins);
6133 handle_stobj (cfg, bblock, ins, *sp, ip, klass, FALSE, TRUE);
6135 if (sp != stack_start)
6138 MONO_INST_NEW (cfg, ins, CEE_BR);
6140 ins->inst_target_bb = end_bblock;
6141 MONO_ADD_INS (bblock, ins);
6142 link_bblock (cfg, bblock, end_bblock);
6143 start_new_bblock = 1;
6146 case CEE_MONO_CISINST:
6147 case CEE_MONO_CCASTCLASS: {
6152 token = read32 (ip + 2);
6153 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
6154 MONO_INST_NEW (cfg, ins, (ip [1] == CEE_MONO_CISINST) ? OP_CISINST : OP_CCASTCLASS);
6155 ins->type = STACK_I4;
6156 ins->inst_left = *sp;
6157 ins->inst_newa_class = klass;
6159 *sp++ = emit_tree (cfg, bblock, ins, ip + 6);
6163 case CEE_MONO_SAVE_LMF:
6164 case CEE_MONO_RESTORE_LMF:
6165 #ifdef MONO_ARCH_HAVE_LMF_OPS
6166 MONO_INST_NEW (cfg, ins, (ip [1] == CEE_MONO_SAVE_LMF) ? OP_SAVE_LMF : OP_RESTORE_LMF);
6167 MONO_ADD_INS (bblock, ins);
6168 cfg->need_lmf_area = TRUE;
6172 case CEE_MONO_CLASSCONST:
6173 CHECK_STACK_OVF (1);
6175 token = read32 (ip + 2);
6176 NEW_CLASSCONST (cfg, ins, mono_method_get_wrapper_data (method, token));
6180 inline_costs += 10 * num_calls++;
6182 case CEE_MONO_NOT_TAKEN:
6183 bblock->out_of_line = TRUE;
6187 g_error ("opcode 0x%02x 0x%02x not handled", MONO_CUSTOM_PREFIX, ip [1]);
6196 /* somewhat similar to LDTOKEN */
6197 MonoInst *addr, *vtvar;
6198 CHECK_STACK_OVF (1);
6199 vtvar = mono_compile_create_var (cfg, &mono_defaults.argumenthandle_class->byval_arg, OP_LOCAL);
6201 NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
6202 addr->cil_code = ip;
6203 MONO_INST_NEW (cfg, ins, OP_ARGLIST);
6205 ins->inst_left = addr;
6206 MONO_ADD_INS (bblock, ins);
6207 NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
6221 * The following transforms:
6222 * CEE_CEQ into OP_CEQ
6223 * CEE_CGT into OP_CGT
6224 * CEE_CGT_UN into OP_CGT_UN
6225 * CEE_CLT into OP_CLT
6226 * CEE_CLT_UN into OP_CLT_UN
6228 MONO_INST_NEW (cfg, cmp, 256 + ip [1]);
6230 MONO_INST_NEW (cfg, ins, cmp->opcode);
6232 cmp->inst_i0 = sp [0];
6233 cmp->inst_i1 = sp [1];
6237 if ((sp [0]->type == STACK_I8) || ((sizeof (gpointer) == 8) && ((sp [0]->type == STACK_PTR) || (sp [0]->type == STACK_OBJ) || (sp [0]->type == STACK_MP))))
6238 cmp->opcode = OP_LCOMPARE;
6240 cmp->opcode = OP_COMPARE;
6242 ins->type = STACK_I4;
6245 /* spill it to reduce the expression complexity
6246 * and workaround bug 54209
6248 if (cmp->inst_left->type == STACK_I8) {
6250 *sp++ = emit_tree (cfg, bblock, ins, ip + 2);
6259 CHECK_STACK_OVF (1);
6261 n = read32 (ip + 2);
6262 cmethod = mini_get_method (method, n, NULL, generic_context);
6265 mono_class_init (cmethod->klass);
6267 if (mono_use_security_manager) {
6268 check_linkdemand (cfg, method, cmethod, bblock, ip);
6271 handle_loaded_temps (cfg, bblock, stack_start, sp);
6273 NEW_METHODCONST (cfg, argconst, cmethod);
6274 if (method->wrapper_type != MONO_WRAPPER_SYNCHRONIZED)
6275 temp = mono_emit_jit_icall (cfg, bblock, mono_ldftn, &argconst, ip);
6277 temp = mono_emit_jit_icall (cfg, bblock, mono_ldftn_nosync, &argconst, ip);
6278 NEW_TEMPLOAD (cfg, *sp, temp);
6282 inline_costs += 10 * num_calls++;
6285 case CEE_LDVIRTFTN: {
6291 n = read32 (ip + 2);
6292 cmethod = mini_get_method (method, n, NULL, generic_context);
6295 mono_class_init (cmethod->klass);
6297 if (mono_use_security_manager) {
6298 check_linkdemand (cfg, method, cmethod, bblock, ip);
6301 handle_loaded_temps (cfg, bblock, stack_start, sp);
6305 NEW_METHODCONST (cfg, args [1], cmethod);
6306 temp = mono_emit_jit_icall (cfg, bblock, mono_ldvirtfn, args, ip);
6307 NEW_TEMPLOAD (cfg, *sp, temp);
6311 inline_costs += 10 * num_calls++;
6315 CHECK_STACK_OVF (1);
6317 n = read16 (ip + 2);
6319 NEW_ARGLOAD (cfg, ins, n);
6325 CHECK_STACK_OVF (1);
6327 n = read16 (ip + 2);
6329 NEW_ARGLOADA (cfg, ins, n);
6337 handle_loaded_temps (cfg, bblock, stack_start, sp);
6339 n = read16 (ip + 2);
6341 NEW_ARGSTORE (cfg, ins, n, *sp);
6343 if (ins->opcode == CEE_STOBJ) {
6344 NEW_ARGLOADA (cfg, ins, n);
6345 handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE);
6347 MONO_ADD_INS (bblock, ins);
6351 CHECK_STACK_OVF (1);
6353 n = read16 (ip + 2);
6355 NEW_LOCLOAD (cfg, ins, n);
6361 CHECK_STACK_OVF (1);
6363 n = read16 (ip + 2);
6365 NEW_LOCLOADA (cfg, ins, n);
6374 n = read16 (ip + 2);
6376 handle_loaded_temps (cfg, bblock, stack_start, sp);
6377 NEW_LOCSTORE (cfg, ins, n, *sp);
6379 if (ins->opcode == CEE_STOBJ) {
6380 NEW_LOCLOADA (cfg, ins, n);
6381 handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE);
6383 MONO_ADD_INS (bblock, ins);
6390 if (sp != stack_start)
6392 if (cfg->method != method)
6394 * Inlining this into a loop in a parent could lead to
6395 * stack overflows which is different behavior than the
6396 * non-inlined case, thus disable inlining in this case.
6398 goto inline_failure;
6399 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
6400 ins->inst_left = *sp;
6402 ins->type = STACK_MP;
6404 cfg->flags |= MONO_CFG_HAS_ALLOCA;
6405 if (header->init_locals)
6406 ins->flags |= MONO_INST_INIT;
6410 /* FIXME: set init flag if locals init is set in this method */
6412 case CEE_ENDFILTER: {
6413 MonoExceptionClause *clause, *nearest;
6414 int cc, nearest_num;
6418 if ((sp != stack_start) || (sp [0]->type != STACK_I4))
6420 MONO_INST_NEW (cfg, ins, OP_ENDFILTER);
6421 ins->inst_left = *sp;
6423 MONO_ADD_INS (bblock, ins);
6424 start_new_bblock = 1;
6429 for (cc = 0; cc < header->num_clauses; ++cc) {
6430 clause = &header->clauses [cc];
6431 if ((clause->flags & MONO_EXCEPTION_CLAUSE_FILTER) &&
6432 ((ip - header->code) > clause->data.filter_offset && (ip - header->code) <= clause->handler_offset) &&
6433 (!nearest || (clause->data.filter_offset < nearest->data.filter_offset))) {
6439 if ((ip - header->code) != nearest->handler_offset)
6444 case CEE_UNALIGNED_:
6445 ins_flag |= MONO_INST_UNALIGNED;
6446 /* FIXME: record alignment? we can assume 1 for now */
6451 ins_flag |= MONO_INST_VOLATILE;
6455 ins_flag |= MONO_INST_TAILCALL;
6456 cfg->flags |= MONO_CFG_HAS_TAIL;
6457 /* Can't inline tail calls at this time */
6458 inline_costs += 100000;
6465 token = read32 (ip + 2);
6466 klass = mini_get_class (method, token, generic_context);
6469 if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
6470 MonoInst *store, *load;
6471 NEW_PCONST (cfg, load, NULL);
6472 load->cil_code = ip;
6473 load->type = STACK_OBJ;
6474 MONO_INST_NEW (cfg, store, CEE_STIND_REF);
6475 store->cil_code = ip;
6476 handle_loaded_temps (cfg, bblock, stack_start, sp);
6477 MONO_ADD_INS (bblock, store);
6478 store->inst_i0 = sp [0];
6479 store->inst_i1 = load;
6481 handle_initobj (cfg, bblock, *sp, NULL, klass, stack_start, sp);
6486 case CEE_CONSTRAINED_:
6487 /* FIXME: implement */
6489 token = read32 (ip + 2);
6490 constrained_call = mono_class_get_full (image, token, generic_context);
6491 if (!constrained_call)
6497 MonoInst *iargs [3];
6500 if ((cfg->opt & MONO_OPT_INTRINS) && (ip [1] == CEE_CPBLK) && (sp [2]->opcode == OP_ICONST) && ((n = sp [2]->inst_c0) <= sizeof (gpointer) * 5)) {
6502 MONO_INST_NEW (cfg, copy, OP_MEMCPY);
6503 copy->inst_left = sp [0];
6504 copy->inst_right = sp [1];
6505 copy->cil_code = ip;
6507 MONO_ADD_INS (bblock, copy);
6514 handle_loaded_temps (cfg, bblock, stack_start, sp);
6515 if (ip [1] == CEE_CPBLK) {
6516 MonoMethod *memcpy_method = get_memcpy_method ();
6517 mono_emit_method_call_spilled (cfg, bblock, memcpy_method, memcpy_method->signature, iargs, ip, NULL);
6519 MonoMethod *memset_method = get_memset_method ();
6520 mono_emit_method_call_spilled (cfg, bblock, memset_method, memset_method->signature, iargs, ip, NULL);
6529 ins_flag |= MONO_INST_NOTYPECHECK;
6531 ins_flag |= MONO_INST_NORANGECHECK;
6532 /* we ignore the no-nullcheck for now since we
6533 * really do it explicitly only when doing callvirt->call
6539 int handler_offset = -1;
6541 for (i = 0; i < header->num_clauses; ++i) {
6542 MonoExceptionClause *clause = &header->clauses [i];
6543 if (MONO_OFFSET_IN_HANDLER (clause, ip - header->code) && !(clause->flags & MONO_EXCEPTION_CLAUSE_FINALLY))
6544 handler_offset = clause->handler_offset;
6547 g_assert (handler_offset != -1);
6549 NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, handler_offset)->inst_c0);
6550 load->cil_code = ip;
6551 MONO_INST_NEW (cfg, ins, OP_RETHROW);
6552 ins->inst_left = load;
6554 MONO_ADD_INS (bblock, ins);
6556 link_bblock (cfg, bblock, end_bblock);
6557 start_new_bblock = 1;
6559 mono_get_got_var (cfg);
6563 CHECK_STACK_OVF (1);
6565 token = read32 (ip + 2);
6566 /* FIXXME: handle generics. */
6567 if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC) {
6568 MonoType *type = mono_type_create_from_typespec (image, token);
6569 token = mono_type_size (type, &align);
6571 MonoClass *klass = mono_class_get_full (image, token, generic_context);
6574 mono_class_init (klass);
6575 token = mono_class_value_size (klass, &align);
6577 NEW_ICONST (cfg, ins, token);
6582 case CEE_REFANYTYPE:
6584 MONO_INST_NEW (cfg, ins, OP_REFANYTYPE);
6586 ins->type = STACK_MP;
6587 ins->inst_left = *sp;
6588 ins->type = STACK_VTYPE;
6589 ins->klass = mono_defaults.typehandle_class;
6598 g_error ("opcode 0xfe 0x%02x not handled", ip [1]);
6603 g_error ("opcode 0x%02x not handled", *ip);
6606 if (start_new_bblock != 1)
6609 bblock->cil_length = ip - bblock->cil_code;
6610 bblock->next_bb = end_bblock;
6612 if (cfg->method == method && cfg->domainvar) {
6614 MonoInst *get_domain;
6616 if (! (get_domain = mono_arch_get_domain_intrinsic (cfg))) {
6619 MONO_INST_NEW_CALL (cfg, call, CEE_CALL);
6620 call->signature = helper_sig_domain_get;
6621 call->inst.type = STACK_PTR;
6622 call->fptr = mono_domain_get;
6623 get_domain = (MonoInst*)call;
6626 NEW_TEMPSTORE (cfg, store, cfg->domainvar->inst_c0, get_domain);
6627 MONO_ADD_INS (init_localsbb, store);
6630 if (cfg->method == method && cfg->got_var)
6631 mono_emit_load_got_addr (cfg);
6633 if (header->init_locals) {
6635 for (i = 0; i < header->num_locals; ++i) {
6636 MonoType *ptype = header->locals [i];
6637 int t = ptype->type;
6638 if (t == MONO_TYPE_VALUETYPE && ptype->data.klass->enumtype)
6639 t = ptype->data.klass->enum_basetype->type;
6641 NEW_PCONST (cfg, ins, NULL);
6642 NEW_LOCSTORE (cfg, store, i, ins);
6643 MONO_ADD_INS (init_localsbb, store);
6644 } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
6645 NEW_ICONST (cfg, ins, 0);
6646 NEW_LOCSTORE (cfg, store, i, ins);
6647 MONO_ADD_INS (init_localsbb, store);
6648 } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
6649 MONO_INST_NEW (cfg, ins, OP_I8CONST);
6650 ins->type = STACK_I8;
6652 NEW_LOCSTORE (cfg, store, i, ins);
6653 MONO_ADD_INS (init_localsbb, store);
6654 } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
6655 MONO_INST_NEW (cfg, ins, OP_R8CONST);
6656 ins->type = STACK_R8;
6657 ins->inst_p0 = (void*)&r8_0;
6658 NEW_LOCSTORE (cfg, store, i, ins);
6659 MONO_ADD_INS (init_localsbb, store);
6660 } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
6661 ((t == MONO_TYPE_GENERICINST) && mono_metadata_generic_class_is_valuetype (ptype->data.generic_class))) {
6662 NEW_LOCLOADA (cfg, ins, i);
6663 handle_initobj (cfg, init_localsbb, ins, NULL, mono_class_from_mono_type (ptype), NULL, NULL);
6665 NEW_PCONST (cfg, ins, NULL);
6666 NEW_LOCSTORE (cfg, store, i, ins);
6667 MONO_ADD_INS (init_localsbb, store);
6672 /* resolve backward branches in the middle of an existing basic block */
6673 for (tmp = bb_recheck; tmp; tmp = tmp->next) {
6675 /*g_print ("need recheck in %s at IL_%04x\n", method->name, bblock->cil_code - header->code);*/
6676 tblock = find_previous (bbhash, start_bblock, bblock->cil_code);
6677 if (tblock != start_bblock) {
6679 split_bblock (cfg, tblock, bblock);
6680 l = bblock->cil_code - header->code;
6681 bblock->cil_length = tblock->cil_length - l;
6682 tblock->cil_length = l;
6684 g_print ("recheck failed.\n");
6688 if (cfg->method == method) {
6690 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
6691 bb->region = mono_find_block_region (cfg, bb->real_offset);
6693 mono_create_spvar_for_region (cfg, bb->region);
6694 if (cfg->verbose_level > 2)
6695 g_print ("REGION BB%d IL_%04x ID_%08X\n", bb->block_num, bb->real_offset, bb->region);
6698 g_hash_table_destroy (bbhash);
6701 g_slist_free (class_inits);
6702 dont_inline = g_list_remove (dont_inline, method);
6703 return inline_costs;
6706 if (cfg->method != method)
6707 g_hash_table_destroy (bbhash);
6708 g_slist_free (class_inits);
6709 dont_inline = g_list_remove (dont_inline, method);
6713 if (cfg->method != method)
6714 g_hash_table_destroy (bbhash);
6715 g_slist_free (class_inits);
6716 dont_inline = g_list_remove (dont_inline, method);
6720 if (cfg->method != method)
6721 g_hash_table_destroy (bbhash);
6722 g_slist_free (class_inits);
6723 g_error ("Invalid IL code at IL%04x in %s: %s\n", (int)(ip - header->code),
6724 mono_method_full_name (method, TRUE), mono_disasm_code_one (NULL, method, ip, NULL));
6725 dont_inline = g_list_remove (dont_inline, method);
6730 mono_print_tree (MonoInst *tree) {
6736 arity = mono_burg_arity [tree->opcode];
6738 printf (" %s%s", arity?"(":"", mono_inst_name (tree->opcode));
6740 switch (tree->opcode) {
6742 printf ("[%d]", (int)tree->inst_c0);
6745 printf ("[%lld]", (long long)tree->inst_l);
6748 printf ("[%f]", *(double*)tree->inst_p0);
6751 printf ("[%f]", *(float*)tree->inst_p0);
6755 printf ("[%d]", (int)tree->inst_c0);
6758 if (tree->inst_offset < 0)
6759 printf ("[-0x%x(%s)]", (int)(-tree->inst_offset), mono_arch_regname (tree->inst_basereg));
6761 printf ("[0x%x(%s)]", (int)(tree->inst_offset), mono_arch_regname (tree->inst_basereg));
6764 printf ("[%s]", mono_arch_regname (tree->dreg));
6767 printf ("[%s]", tree->inst_newa_class->name);
6768 mono_print_tree (tree->inst_newa_len);
6779 case OP_VOIDCALLVIRT: {
6780 MonoCallInst *call = (MonoCallInst*)tree;
6782 printf ("[%s]", call->method->name);
6783 else if (call->fptr) {
6784 MonoJitICallInfo *info = mono_find_jit_icall_by_addr (call->fptr);
6786 printf ("[%s]", info->name);
6792 printf ("[%d (", (int)tree->inst_c0);
6793 for (i = 0; i < tree->inst_phi_args [0]; i++) {
6796 printf ("%d", tree->inst_phi_args [i + 1]);
6807 case OP_LOAD_MEMBASE:
6808 case OP_LOADI4_MEMBASE:
6809 case OP_LOADU4_MEMBASE:
6810 case OP_LOADU1_MEMBASE:
6811 case OP_LOADI1_MEMBASE:
6812 case OP_LOADU2_MEMBASE:
6813 case OP_LOADI2_MEMBASE:
6814 printf ("[%s] <- [%s + 0x%x]", mono_arch_regname (tree->dreg), mono_arch_regname (tree->inst_basereg), (int)tree->inst_offset);
6817 case OP_CALL_HANDLER:
6818 printf ("[B%d]", tree->inst_target_bb->block_num);
6828 case OP_VOIDCALL_REG:
6829 mono_print_tree (tree->inst_left);
6841 printf ("[B%dB%d]", tree->inst_true_bb->block_num, tree->inst_false_bb->block_num);
6842 mono_print_tree (tree->inst_left);
6845 if (!mono_arch_print_tree(tree, arity)) {
6847 mono_print_tree (tree->inst_left);
6849 mono_print_tree (tree->inst_right);
6860 mono_print_tree_nl (MonoInst *tree)
6862 mono_print_tree (tree);
6867 create_helper_signature (void)
6869 helper_sig_domain_get = mono_create_icall_signature ("ptr");
6870 helper_sig_class_init_trampoline = mono_create_icall_signature ("void");
6874 mono_icall_get_wrapper (MonoJitICallInfo* callinfo)
6877 MonoMethod *wrapper;
6880 if (callinfo->wrapper)
6881 return callinfo->wrapper;
6883 name = g_strdup_printf ("__icall_wrapper_%s", callinfo->name);
6884 wrapper = mono_marshal_get_icall_wrapper (callinfo->sig, name, callinfo->func);
6885 /* Must be domain neutral since there is only one copy */
6886 code = mono_jit_compile_method_with_opt (wrapper, default_opt | MONO_OPT_SHARED);
6888 if (!callinfo->wrapper) {
6889 callinfo->wrapper = code;
6890 mono_register_jit_icall_wrapper (callinfo, code);
6891 mono_debug_add_icall_wrapper (wrapper, callinfo);
6895 return callinfo->wrapper;
6899 mono_init_trampolines (void)
6901 mono_trampoline_code [MONO_TRAMPOLINE_GENERIC] = mono_arch_create_trampoline_code (MONO_TRAMPOLINE_GENERIC);
6902 mono_trampoline_code [MONO_TRAMPOLINE_JUMP] = mono_arch_create_trampoline_code (MONO_TRAMPOLINE_JUMP);
6903 mono_trampoline_code [MONO_TRAMPOLINE_CLASS_INIT] = mono_arch_create_trampoline_code (MONO_TRAMPOLINE_CLASS_INIT);
6904 #ifdef MONO_ARCH_HAVE_PIC_AOT
6905 mono_trampoline_code [MONO_TRAMPOLINE_AOT] = mono_arch_create_trampoline_code (MONO_TRAMPOLINE_AOT);
6907 #ifdef MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE
6908 mono_trampoline_code [MONO_TRAMPOLINE_DELEGATE] = mono_arch_create_trampoline_code (MONO_TRAMPOLINE_DELEGATE);
6913 mono_init_exceptions (void)
6915 #ifndef CUSTOM_EXCEPTION_HANDLING
6916 mono_arch_get_restore_context ();
6917 mono_arch_get_call_filter ();
6918 mono_arch_get_throw_exception ();
6919 mono_arch_get_rethrow_exception ();
6924 mono_get_trampoline_code (MonoTrampolineType tramp_type)
6926 return mono_trampoline_code [tramp_type];
6930 mono_create_class_init_trampoline (MonoVTable *vtable)
6934 /* previously created trampoline code */
6935 mono_domain_lock (vtable->domain);
6937 g_hash_table_lookup (vtable->domain->class_init_trampoline_hash,
6939 mono_domain_unlock (vtable->domain);
6943 #ifdef MONO_ARCH_HAVE_CREATE_SPECIFIC_TRAMPOLINE
6944 code = mono_arch_create_specific_trampoline (vtable, MONO_TRAMPOLINE_CLASS_INIT, vtable->domain, NULL);
6946 code = mono_arch_create_class_init_trampoline (vtable);
6949 ptr = mono_create_ftnptr (vtable->domain, code);
6951 /* store trampoline address */
6952 mono_domain_lock (vtable->domain);
6953 g_hash_table_insert (vtable->domain->class_init_trampoline_hash,
6955 mono_domain_unlock (vtable->domain);
6957 EnterCriticalSection (&jit_mutex);
6958 if (!class_init_hash_addr)
6959 class_init_hash_addr = g_hash_table_new (NULL, NULL);
6960 g_hash_table_insert (class_init_hash_addr, ptr, vtable);
6961 LeaveCriticalSection (&jit_mutex);
6967 mono_create_jump_trampoline (MonoDomain *domain, MonoMethod *method,
6968 gboolean add_sync_wrapper)
6972 #ifdef MONO_ARCH_HAVE_CREATE_SPECIFIC_TRAMPOLINE
6976 if (add_sync_wrapper && method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
6977 return mono_create_jump_trampoline (domain, mono_marshal_get_synchronized_wrapper (method), FALSE);
6979 code = mono_jit_find_compiled_method (domain, method);
6983 mono_domain_lock (domain);
6984 code = g_hash_table_lookup (domain->jump_trampoline_hash, method);
6985 mono_domain_unlock (domain);
6989 #ifdef MONO_ARCH_HAVE_CREATE_SPECIFIC_TRAMPOLINE
6990 code = mono_arch_create_specific_trampoline (method, MONO_TRAMPOLINE_JUMP, mono_domain_get (), &code_size);
6992 ji = g_new0 (MonoJitInfo, 1);
6993 ji->code_start = code;
6994 ji->code_size = code_size;
6995 ji->method = method;
6997 ji = mono_arch_create_jump_trampoline (method);
7001 * mono_delegate_ctor needs to find the method metadata from the
7002 * trampoline address, so we save it here.
7005 mono_jit_info_table_add (domain, ji);
7007 mono_domain_lock (domain);
7008 g_hash_table_insert (domain->jump_trampoline_hash, method, ji->code_start);
7009 mono_domain_unlock (domain);
7011 return ji->code_start;
7015 mono_create_jit_trampoline (MonoMethod *method)
7017 MonoDomain *domain = mono_domain_get ();
7020 mono_domain_lock (domain);
7021 tramp = g_hash_table_lookup (domain->jit_trampoline_hash, method);
7022 mono_domain_unlock (domain);
7026 if (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
7027 return mono_create_jit_trampoline (mono_marshal_get_synchronized_wrapper (method));
7029 #ifdef MONO_ARCH_HAVE_CREATE_SPECIFIC_TRAMPOLINE
7030 tramp = mono_arch_create_specific_trampoline (method, MONO_TRAMPOLINE_GENERIC, mono_domain_get (), NULL);
7032 tramp = mono_arch_create_jit_trampoline (method);
7035 mono_domain_lock (domain);
7036 g_hash_table_insert (domain->jit_trampoline_hash, method, tramp);
7037 mono_domain_unlock (domain);
7039 mono_jit_stats.method_trampolines++;
7044 #ifdef MONO_ARCH_HAVE_CREATE_TRAMPOLINE_FROM_TOKEN
7046 mono_create_jit_trampoline_from_token (MonoImage *image, guint32 token)
7050 MonoDomain *domain = mono_domain_get ();
7051 guint8 *buf, *start;
7053 mono_domain_lock (domain);
7054 buf = start = mono_code_manager_reserve (domain->code_mp, 2 * sizeof (gpointer));
7055 mono_domain_unlock (domain);
7057 *(gpointer*)(gpointer)buf = image;
7058 buf += sizeof (gpointer);
7059 *(guint32*)(gpointer)buf = token;
7061 tramp = mono_arch_create_specific_trampoline (start, MONO_TRAMPOLINE_AOT, domain, NULL);
7063 mono_jit_stats.method_trampolines++;
7070 mono_create_delegate_trampoline (MonoMethod *method, gpointer addr)
7072 #ifdef MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE
7075 MonoDomain *domain = mono_domain_get ();
7078 code = mono_jit_find_compiled_method (domain, method);
7083 * FIXME: We should return a function descriptor here but it is not stored
7084 * anywhere so it would be leaked.
7088 mono_domain_lock (domain);
7089 ptr = g_hash_table_lookup (domain->delegate_trampoline_hash, method);
7090 mono_domain_unlock (domain);
7094 code = mono_arch_create_specific_trampoline (method, MONO_TRAMPOLINE_DELEGATE, domain, &code_size);
7096 ptr = mono_create_ftnptr (domain, code);
7098 /* store trampoline address */
7099 mono_domain_lock (domain);
7100 g_hash_table_insert (domain->delegate_trampoline_hash,
7102 mono_domain_unlock (domain);
7111 mono_find_class_init_trampoline_by_addr (gconstpointer addr)
7115 EnterCriticalSection (&jit_mutex);
7116 if (class_init_hash_addr)
7117 res = g_hash_table_lookup (class_init_hash_addr, addr);
7120 LeaveCriticalSection (&jit_mutex);
7125 mono_dynamic_code_hash_insert (MonoDomain *domain, MonoMethod *method, MonoJitDynamicMethodInfo *ji)
7127 if (!domain->dynamic_code_hash)
7128 domain->dynamic_code_hash = g_hash_table_new (NULL, NULL);
7129 g_hash_table_insert (domain->dynamic_code_hash, method, ji);
7132 static MonoJitDynamicMethodInfo*
7133 mono_dynamic_code_hash_lookup (MonoDomain *domain, MonoMethod *method)
7135 MonoJitDynamicMethodInfo *res;
7137 if (domain->dynamic_code_hash)
7138 res = g_hash_table_lookup (domain->dynamic_code_hash, method);
7151 * mono_allocate_stack_slots_full:
7153 * Allocate stack slots for all non register allocated variables using a
7154 * linear scan algorithm.
7155 * Returns: an array of stack offsets which the caller should free.
7156 * STACK_SIZE is set to the amount of stack space needed.
7157 * STACK_ALIGN is set to the alignment needed by the locals area.
7160 mono_allocate_stack_slots_full (MonoCompile *m, gboolean backward, guint32 *stack_size, guint32 *stack_align)
7162 int i, slot, offset, size, align;
7166 GList *vars = NULL, *l;
7167 StackSlotInfo *scalar_stack_slots, *vtype_stack_slots, *slot_info;
7171 scalar_stack_slots = g_new0 (StackSlotInfo, MONO_TYPE_PINNED);
7172 vtype_stack_slots = g_new0 (StackSlotInfo, 256);
7175 offsets = g_new (gint32, m->num_varinfo);
7176 for (i = 0; i < m->num_varinfo; ++i)
7179 for (i = m->locals_start; i < m->num_varinfo; i++) {
7180 inst = m->varinfo [i];
7181 vmv = MONO_VARINFO (m, i);
7183 if ((inst->flags & MONO_INST_IS_DEAD) || inst->opcode == OP_REGVAR || inst->opcode == OP_REGOFFSET)
7186 vars = g_list_prepend (vars, vmv);
7189 vars = mono_varlist_sort (m, vars, 0);
7192 for (l = vars; l; l = l->next) {
7194 inst = m->varinfo [vmv->idx];
7196 /* inst->unused indicates native sized value types, this is used by the
7197 * pinvoke wrappers when they call functions returning structures */
7198 if (inst->unused && MONO_TYPE_ISSTRUCT (inst->inst_vtype) && inst->inst_vtype->type != MONO_TYPE_TYPEDBYREF)
7199 size = mono_class_native_size (inst->inst_vtype->data.klass, &align);
7201 size = mono_type_size (inst->inst_vtype, &align);
7203 t = mono_type_get_underlying_type (inst->inst_vtype);
7205 case MONO_TYPE_VALUETYPE:
7206 for (i = 0; i < nvtypes; ++i)
7207 if (t->data.klass == vtype_stack_slots [i].vtype)
7210 slot_info = &vtype_stack_slots [i];
7212 g_assert (nvtypes < 256);
7213 vtype_stack_slots [nvtypes].vtype = t->data.klass;
7214 slot_info = &vtype_stack_slots [nvtypes];
7219 slot_info = &scalar_stack_slots [t->type];
7223 if (m->comp_done & MONO_COMP_LIVENESS) {
7224 //printf ("START %2d %08x %08x\n", vmv->idx, vmv->range.first_use.abs_pos, vmv->range.last_use.abs_pos);
7226 /* expire old intervals in active */
7227 while (slot_info->active) {
7228 MonoMethodVar *amv = (MonoMethodVar *)slot_info->active->data;
7230 if (amv->range.last_use.abs_pos > vmv->range.first_use.abs_pos)
7233 //printf ("EXPIR %2d %08x %08x C%d R%d\n", amv->idx, amv->range.first_use.abs_pos, amv->range.last_use.abs_pos, amv->spill_costs, amv->reg);
7235 slot_info->active = g_list_delete_link (slot_info->active, slot_info->active);
7236 slot_info->slots = g_list_prepend (slot_info->slots, GINT_TO_POINTER (offsets [amv->idx]));
7240 * This also handles the case when the variable is used in an
7241 * exception region, as liveness info is not computed there.
7244 * FIXME: All valuetypes are marked as INDIRECT because of LDADDR
7247 if (! (inst->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT))) {
7248 if (slot_info->slots) {
7249 slot = GPOINTER_TO_INT (slot_info->slots->data);
7251 slot_info->slots = g_list_delete_link (slot_info->slots, slot_info->slots);
7254 slot_info->active = mono_varlist_insert_sorted (m, slot_info->active, vmv, TRUE);
7259 static int count = 0;
7263 if (count == atoi (getenv ("COUNT")))
7264 printf ("LAST: %s\n", mono_method_full_name (m->method, TRUE));
7265 if (count > atoi (getenv ("COUNT")))
7268 mono_print_tree_nl (inst);
7272 if (slot == 0xffffff) {
7274 * Allways allocate valuetypes to sizeof (gpointer) to allow more
7275 * efficient copying (and to work around the fact that OP_MEMCPY
7276 * and OP_MEMSET ignores alignment).
7278 if (t->type == MONO_TYPE_VALUETYPE)
7279 align = sizeof (gpointer);
7283 offset += align - 1;
7284 offset &= ~(align - 1);
7288 offset += align - 1;
7289 offset &= ~(align - 1);
7294 if (*stack_align == 0)
7295 *stack_align = align;
7298 offsets [vmv->idx] = slot;
7301 for (i = 0; i < MONO_TYPE_PINNED; ++i) {
7302 g_list_free (scalar_stack_slots [i].active);
7303 g_list_free (scalar_stack_slots [i].slots);
7305 for (i = 0; i < nvtypes; ++i) {
7306 g_list_free (vtype_stack_slots [i].active);
7307 g_list_free (vtype_stack_slots [i].slots);
7309 g_free (scalar_stack_slots);
7310 g_free (vtype_stack_slots);
7312 *stack_size = offset;
7317 mono_allocate_stack_slots (MonoCompile *m, guint32 *stack_size, guint32 *stack_align)
7319 return mono_allocate_stack_slots_full (m, TRUE, stack_size, stack_align);
7323 mono_register_opcode_emulation (int opcode, const char *name, const char *sigstr, gpointer func, gboolean no_throw)
7325 MonoJitICallInfo *info;
7326 MonoMethodSignature *sig = mono_create_icall_signature (sigstr);
7328 if (!emul_opcode_map)
7329 emul_opcode_map = g_new0 (MonoJitICallInfo*, OP_LAST + 1);
7331 g_assert (!sig->hasthis);
7332 g_assert (sig->param_count < 3);
7334 info = mono_register_jit_icall (func, name, sig, no_throw);
7336 emul_opcode_map [opcode] = info;
7340 register_icall (gpointer func, const char *name, const char *sigstr, gboolean save)
7342 MonoMethodSignature *sig;
7345 sig = mono_create_icall_signature (sigstr);
7349 mono_register_jit_icall (func, name, sig, save);
7353 decompose_foreach (MonoInst *tree, gpointer data)
7355 static MonoJitICallInfo *newarr_info = NULL;
7356 static MonoJitICallInfo *newarr_specific_info = NULL;
7357 MonoJitICallInfo *info;
7360 switch (tree->opcode) {
7362 MonoCompile *cfg = data;
7363 MonoInst *iargs [3];
7366 newarr_info = mono_find_jit_icall_by_addr (mono_array_new);
7367 g_assert (newarr_info);
7368 newarr_specific_info = mono_find_jit_icall_by_addr (mono_array_new_specific);
7369 g_assert (newarr_specific_info);
7372 if (cfg->opt & MONO_OPT_SHARED) {
7373 NEW_DOMAINCONST (cfg, iargs [0]);
7374 NEW_CLASSCONST (cfg, iargs [1], tree->inst_newa_class);
7375 iargs [2] = tree->inst_newa_len;
7380 MonoVTable *vtable = mono_class_vtable (cfg->domain, mono_array_class_get (tree->inst_newa_class, 1));
7382 NEW_VTABLECONST (cfg, iargs [0], vtable);
7383 iargs [1] = tree->inst_newa_len;
7385 info = newarr_specific_info;
7388 mono_emulate_opcode (cfg, tree, iargs, info);
7390 /* Need to decompose arguments after the the opcode is decomposed */
7391 for (i = 0; i < info->sig->param_count; ++i)
7392 dec_foreach (iargs [i], cfg);
7402 mono_inst_foreach (MonoInst *tree, MonoInstFunc func, gpointer data) {
7404 switch (mono_burg_arity [tree->opcode]) {
7407 mono_inst_foreach (tree->inst_left, func, data);
7410 mono_inst_foreach (tree->inst_left, func, data);
7411 mono_inst_foreach (tree->inst_right, func, data);
7414 g_assert_not_reached ();
7421 mono_print_bb_code (MonoBasicBlock *bb) {
7423 MonoInst *c = bb->code;
7425 mono_print_tree (c);
7433 print_dfn (MonoCompile *cfg) {
7438 g_print ("IR code for method %s\n", mono_method_full_name (cfg->method, TRUE));
7440 for (i = 0; i < cfg->num_bblocks; ++i) {
7441 bb = cfg->bblocks [i];
7442 /*if (bb->cil_code) {
7443 char* code1, *code2;
7444 code1 = mono_disasm_code_one (NULL, cfg->method, bb->cil_code, NULL);
7445 if (bb->last_ins->cil_code)
7446 code2 = mono_disasm_code_one (NULL, cfg->method, bb->last_ins->cil_code, NULL);
7448 code2 = g_strdup ("");
7450 code1 [strlen (code1) - 1] = 0;
7451 code = g_strdup_printf ("%s -> %s", code1, code2);
7455 code = g_strdup ("\n");
7456 g_print ("\nBB%d DFN%d (len: %d): %s", bb->block_num, i, bb->cil_length, code);
7458 MonoInst *c = bb->code;
7460 mono_print_tree (c);
7468 g_print ("\tprev:");
7469 for (j = 0; j < bb->in_count; ++j) {
7470 g_print (" BB%d", bb->in_bb [j]->block_num);
7472 g_print ("\t\tsucc:");
7473 for (j = 0; j < bb->out_count; ++j) {
7474 g_print (" BB%d", bb->out_bb [j]->block_num);
7476 g_print ("\n\tidom: BB%d\n", bb->idom? bb->idom->block_num: -1);
7479 g_assert (mono_bitset_test_fast (bb->dominators, bb->idom->dfn));
7482 mono_blockset_print (cfg, bb->dominators, "\tdominators", bb->idom? bb->idom->dfn: -1);
7484 mono_blockset_print (cfg, bb->dfrontier, "\tdfrontier", -1);
7492 mono_bblock_add_inst (MonoBasicBlock *bb, MonoInst *inst)
7496 g_assert (bb->code);
7497 bb->last_ins->next = inst;
7498 bb->last_ins = inst;
7500 bb->last_ins = bb->code = inst;
7505 mono_destroy_compile (MonoCompile *cfg)
7507 //mono_mempool_stats (cfg->mempool);
7508 g_hash_table_destroy (cfg->bb_hash);
7509 mono_free_loop_info (cfg);
7511 mono_regstate_free (cfg->rs);
7513 g_hash_table_destroy (cfg->spvars);
7515 g_hash_table_destroy (cfg->exvars);
7516 mono_mempool_destroy (cfg->mempool);
7517 g_list_free (cfg->ldstr_list);
7519 g_free (cfg->varinfo);
7524 #ifdef HAVE_KW_THREAD
7525 static __thread gpointer mono_lmf_addr MONO_TLS_FAST;
7529 mono_get_jit_tls_key (void)
7531 return mono_jit_tls_id;
7535 mono_get_lmf_tls_offset (void)
7538 MONO_THREAD_VAR_OFFSET(mono_lmf_addr,offset);
7543 mono_get_lmf_addr (void)
7545 #ifdef HAVE_KW_THREAD
7546 return mono_lmf_addr;
7548 MonoJitTlsData *jit_tls;
7550 if ((jit_tls = TlsGetValue (mono_jit_tls_id)))
7551 return &jit_tls->lmf;
7553 g_assert_not_reached ();
7558 /* Called by native->managed wrappers */
7560 mono_jit_thread_attach (MonoDomain *domain)
7562 #ifdef HAVE_KW_THREAD
7563 if (!mono_lmf_addr) {
7564 mono_thread_attach (domain);
7567 if (!TlsGetValue (mono_jit_tls_id))
7568 mono_thread_attach (domain);
7573 * mono_thread_abort:
7574 * @obj: exception object
7576 * abort the thread, print exception information and stack trace
7579 mono_thread_abort (MonoObject *obj)
7581 /* MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id); */
7583 /* handle_remove should be eventually called for this thread, too
7586 mono_thread_exit ();
7590 setup_jit_tls_data (gpointer stack_start, gpointer abort_func)
7592 MonoJitTlsData *jit_tls;
7595 jit_tls = TlsGetValue (mono_jit_tls_id);
7599 jit_tls = g_new0 (MonoJitTlsData, 1);
7601 TlsSetValue (mono_jit_tls_id, jit_tls);
7603 jit_tls->abort_func = abort_func;
7604 jit_tls->end_of_stack = stack_start;
7606 lmf = g_new0 (MonoLMF, 1);
7609 jit_tls->lmf = jit_tls->first_lmf = lmf;
7611 #ifdef HAVE_KW_THREAD
7612 mono_lmf_addr = &jit_tls->lmf;
7615 mono_arch_setup_jit_tls_data (jit_tls);
7617 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
7618 mono_setup_altstack (jit_tls);
7625 mono_thread_start_cb (gsize tid, gpointer stack_start, gpointer func)
7628 void *jit_tls = setup_jit_tls_data (stack_start, mono_thread_abort);
7629 thread = mono_thread_current ();
7631 thread->jit_data = jit_tls;
7634 void (*mono_thread_attach_aborted_cb ) (MonoObject *obj) = NULL;
7637 mono_thread_abort_dummy (MonoObject *obj)
7639 if (mono_thread_attach_aborted_cb)
7640 mono_thread_attach_aborted_cb (obj);
7642 mono_thread_abort (obj);
7646 mono_thread_attach_cb (gsize tid, gpointer stack_start)
7649 void *jit_tls = setup_jit_tls_data (stack_start, mono_thread_abort_dummy);
7650 thread = mono_thread_current ();
7652 thread->jit_data = jit_tls;
7653 if (mono_profiler_get_events () & MONO_PROFILE_STATISTICAL)
7654 setup_stat_profiler ();
7658 mini_thread_cleanup (MonoThread *thread)
7660 MonoJitTlsData *jit_tls = thread->jit_data;
7663 mono_arch_free_jit_tls_data (jit_tls);
7664 g_free (jit_tls->first_lmf);
7666 thread->jit_data = NULL;
7668 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
7669 mono_free_altstack (jit_tls);
7675 mono_add_patch_info (MonoCompile *cfg, int ip, MonoJumpInfoType type, gconstpointer target)
7677 MonoJumpInfo *ji = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfo));
7681 ji->data.target = target;
7682 ji->next = cfg->patch_info;
7684 cfg->patch_info = ji;
7688 mono_remove_patch_info (MonoCompile *cfg, int ip)
7690 MonoJumpInfo **ji = &cfg->patch_info;
7693 if ((*ji)->ip.i == ip)
7696 ji = &((*ji)->next);
7701 mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *patch_info, gboolean run_cctors)
7703 unsigned char *ip = patch_info->ip.i + code;
7704 gconstpointer target = NULL;
7706 switch (patch_info->type) {
7707 case MONO_PATCH_INFO_BB:
7708 target = patch_info->data.bb->native_offset + code;
7710 case MONO_PATCH_INFO_ABS:
7711 target = patch_info->data.target;
7713 case MONO_PATCH_INFO_LABEL:
7714 target = patch_info->data.inst->inst_c0 + code;
7716 case MONO_PATCH_INFO_IP:
7719 case MONO_PATCH_INFO_METHOD_REL:
7720 target = code + patch_info->data.offset;
7722 case MONO_PATCH_INFO_INTERNAL_METHOD: {
7723 MonoJitICallInfo *mi = mono_find_jit_icall_by_name (patch_info->data.name);
7725 g_warning ("unknown MONO_PATCH_INFO_INTERNAL_METHOD %s", patch_info->data.name);
7726 g_assert_not_reached ();
7728 target = mono_icall_get_wrapper (mi);
7731 case MONO_PATCH_INFO_METHOD_JUMP: {
7734 /* get the trampoline to the method from the domain */
7735 target = mono_create_jump_trampoline (domain, patch_info->data.method, TRUE);
7736 if (!domain->jump_target_hash)
7737 domain->jump_target_hash = g_hash_table_new (NULL, NULL);
7738 list = g_hash_table_lookup (domain->jump_target_hash, patch_info->data.method);
7739 list = g_slist_prepend (list, ip);
7740 g_hash_table_insert (domain->jump_target_hash, patch_info->data.method, list);
7743 case MONO_PATCH_INFO_METHOD:
7744 if (patch_info->data.method == method) {
7747 /* get the trampoline to the method from the domain */
7748 target = mono_create_jit_trampoline (patch_info->data.method);
7750 case MONO_PATCH_INFO_SWITCH: {
7751 gpointer *jump_table;
7754 if (method && method->dynamic) {
7755 jump_table = mono_code_manager_reserve (mono_dynamic_code_hash_lookup (domain, method)->code_mp, sizeof (gpointer) * patch_info->data.table->table_size);
7757 mono_domain_lock (domain);
7758 jump_table = mono_code_manager_reserve (domain->code_mp, sizeof (gpointer) * patch_info->data.table->table_size);
7759 mono_domain_unlock (domain);
7762 for (i = 0; i < patch_info->data.table->table_size; i++) {
7763 jump_table [i] = code + GPOINTER_TO_INT (patch_info->data.table->table [i]);
7765 target = jump_table;
7768 case MONO_PATCH_INFO_METHODCONST:
7769 case MONO_PATCH_INFO_CLASS:
7770 case MONO_PATCH_INFO_IMAGE:
7771 case MONO_PATCH_INFO_FIELD:
7772 target = patch_info->data.target;
7774 case MONO_PATCH_INFO_IID:
7775 mono_class_init (patch_info->data.klass);
7776 target = GINT_TO_POINTER ((int)patch_info->data.klass->interface_id);
7778 case MONO_PATCH_INFO_VTABLE:
7779 target = mono_class_vtable (domain, patch_info->data.klass);
7781 case MONO_PATCH_INFO_CLASS_INIT:
7782 target = mono_create_class_init_trampoline (mono_class_vtable (domain, patch_info->data.klass));
7784 case MONO_PATCH_INFO_SFLDA: {
7785 MonoVTable *vtable = mono_class_vtable (domain, patch_info->data.field->parent);
7786 if (!vtable->initialized && !(vtable->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) && (method && mono_class_needs_cctor_run (vtable->klass, method)))
7787 /* Done by the generated code */
7791 mono_runtime_class_init (vtable);
7793 target = (char*)vtable->data + patch_info->data.field->offset;
7796 case MONO_PATCH_INFO_R4:
7797 case MONO_PATCH_INFO_R8:
7798 target = patch_info->data.target;
7800 case MONO_PATCH_INFO_EXC_NAME:
7801 target = patch_info->data.name;
7803 case MONO_PATCH_INFO_LDSTR:
7805 mono_ldstr (domain, patch_info->data.token->image,
7806 mono_metadata_token_index (patch_info->data.token->token));
7808 case MONO_PATCH_INFO_TYPE_FROM_HANDLE: {
7810 MonoClass *handle_class;
7812 handle = mono_ldtoken (patch_info->data.token->image,
7813 patch_info->data.token->token, &handle_class, NULL);
7814 mono_class_init (handle_class);
7815 mono_class_init (mono_class_from_mono_type (handle));
7818 mono_type_get_object (domain, handle);
7821 case MONO_PATCH_INFO_LDTOKEN: {
7823 MonoClass *handle_class;
7825 handle = mono_ldtoken (patch_info->data.token->image,
7826 patch_info->data.token->token, &handle_class, NULL);
7827 mono_class_init (handle_class);
7832 case MONO_PATCH_INFO_DECLSEC:
7833 target = (mono_metadata_blob_heap (patch_info->data.token->image, patch_info->data.token->token) + 2);
7835 case MONO_PATCH_INFO_BB_OVF:
7836 case MONO_PATCH_INFO_EXC_OVF:
7837 case MONO_PATCH_INFO_GOT_OFFSET:
7838 case MONO_PATCH_INFO_NONE:
7841 g_assert_not_reached ();
7844 return (gpointer)target;
7848 dec_foreach (MonoInst *tree, MonoCompile *cfg) {
7849 MonoJitICallInfo *info;
7851 decompose_foreach (tree, cfg);
7853 switch (mono_burg_arity [tree->opcode]) {
7856 dec_foreach (tree->inst_left, cfg);
7858 if ((info = mono_find_jit_opcode_emulation (tree->opcode))) {
7859 MonoInst *iargs [2];
7861 iargs [0] = tree->inst_left;
7863 mono_emulate_opcode (cfg, tree, iargs, info);
7869 #ifdef MONO_ARCH_BIGMUL_INTRINS
7870 if (tree->opcode == OP_LMUL
7871 && (cfg->opt & MONO_OPT_INTRINS)
7872 && (tree->inst_left->opcode == CEE_CONV_I8
7873 || tree->inst_left->opcode == CEE_CONV_U8)
7874 && tree->inst_left->inst_left->type == STACK_I4
7875 && (tree->inst_right->opcode == CEE_CONV_I8
7876 || tree->inst_right->opcode == CEE_CONV_U8)
7877 && tree->inst_right->inst_left->type == STACK_I4
7878 && tree->inst_left->opcode == tree->inst_right->opcode) {
7879 tree->opcode = (tree->inst_left->opcode == CEE_CONV_I8 ? OP_BIGMUL: OP_BIGMUL_UN);
7880 tree->inst_left = tree->inst_left->inst_left;
7881 tree->inst_right = tree->inst_right->inst_left;
7882 dec_foreach (tree, cfg);
7885 if ((info = mono_find_jit_opcode_emulation (tree->opcode))) {
7886 MonoInst *iargs [2];
7888 iargs [0] = tree->inst_i0;
7889 iargs [1] = tree->inst_i1;
7891 mono_emulate_opcode (cfg, tree, iargs, info);
7893 dec_foreach (iargs [0], cfg);
7894 dec_foreach (iargs [1], cfg);
7897 dec_foreach (tree->inst_left, cfg);
7898 dec_foreach (tree->inst_right, cfg);
7902 g_assert_not_reached ();
7907 decompose_pass (MonoCompile *cfg) {
7910 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
7913 cfg->prev_ins = NULL;
7914 for (tree = cfg->cbb->code; tree; tree = tree->next) {
7915 dec_foreach (tree, cfg);
7916 cfg->prev_ins = tree;
7922 nullify_basic_block (MonoBasicBlock *bb)
7929 bb->code = bb->last_ins = NULL;
7930 bb->cil_code = NULL;
7934 replace_out_block (MonoBasicBlock *bb, MonoBasicBlock *orig, MonoBasicBlock *repl)
7938 for (i = 0; i < bb->out_count; i++) {
7939 MonoBasicBlock *ob = bb->out_bb [i];
7942 if (bb->out_count > 1) {
7943 bb->out_bb [i] = bb->out_bb [bb->out_count - 1];
7947 bb->out_bb [i] = repl;
7954 replace_in_block (MonoBasicBlock *bb, MonoBasicBlock *orig, MonoBasicBlock *repl)
7958 for (i = 0; i < bb->in_count; i++) {
7959 MonoBasicBlock *ib = bb->in_bb [i];
7962 if (bb->in_count > 1) {
7963 bb->in_bb [i] = bb->in_bb [bb->in_count - 1];
7967 bb->in_bb [i] = repl;
7974 replace_or_add_in_block (MonoCompile *cfg, MonoBasicBlock *bb, MonoBasicBlock *orig, MonoBasicBlock *repl)
7976 gboolean found = FALSE;
7979 for (i = 0; i < bb->in_count; i++) {
7980 MonoBasicBlock *ib = bb->in_bb [i];
7983 if (bb->in_count > 1) {
7984 bb->in_bb [i] = bb->in_bb [bb->in_count - 1];
7988 bb->in_bb [i] = repl;
7995 MonoBasicBlock **new_in_bb = mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * (bb->in_count + 1));
7996 for (i = 0; i < bb->in_count; i++) {
7997 new_in_bb [i] = bb->in_bb [i];
7999 new_in_bb [i] = repl;
8001 bb->in_bb = new_in_bb;
8007 replace_out_block_in_code (MonoBasicBlock *bb, MonoBasicBlock *orig, MonoBasicBlock *repl) {
8010 for (inst = bb->code; inst != NULL; inst = inst->next) {
8011 if (inst->opcode == OP_CALL_HANDLER) {
8012 if (inst->inst_target_bb == orig) {
8013 inst->inst_target_bb = repl;
8017 if (bb->last_ins != NULL) {
8018 switch (bb->last_ins->opcode) {
8020 if (bb->last_ins->inst_target_bb == orig) {
8021 bb->last_ins->inst_target_bb = repl;
8026 int n = GPOINTER_TO_INT (bb->last_ins->klass);
8027 for (i = 0; i < n; i++ ) {
8028 if (bb->last_ins->inst_many_bb [i] == orig) {
8029 bb->last_ins->inst_many_bb [i] = repl;
8044 if (bb->last_ins->inst_true_bb == orig) {
8045 bb->last_ins->inst_true_bb = repl;
8047 if (bb->last_ins->inst_false_bb == orig) {
8048 bb->last_ins->inst_false_bb = repl;
8058 replace_basic_block (MonoBasicBlock *bb, MonoBasicBlock *orig, MonoBasicBlock *repl)
8062 for (i = 0; i < bb->out_count; i++) {
8063 MonoBasicBlock *ob = bb->out_bb [i];
8064 for (j = 0; j < ob->in_count; j++) {
8065 if (ob->in_bb [j] == orig) {
8066 ob->in_bb [j] = repl;
8074 * Check if a bb is useless (is just made of NOPs and ends with an
8075 * unconditional branch, or nothing).
8076 * If it is so, unlink it from the CFG and nullify it, and return TRUE.
8077 * Otherwise, return FALSE;
8080 remove_block_if_useless (MonoCompile *cfg, MonoBasicBlock *bb, MonoBasicBlock *previous_bb) {
8081 MonoBasicBlock *target_bb = NULL;
8084 /* Do not touch handlers */
8085 if (bb->region != -1) return FALSE;
8087 for (inst = bb->code; inst != NULL; inst = inst->next) {
8088 switch (inst->opcode) {
8092 target_bb = inst->inst_target_bb;
8099 if (target_bb == NULL) {
8100 if ((bb->out_count == 1) && (bb->out_bb [0] == bb->next_bb)) {
8101 target_bb = bb->next_bb;
8103 /* Do not touch empty BBs that do not "fall through" to their next BB (like the exit BB) */
8108 /* Do not touch BBs following a switch (they are the "default" branch) */
8109 if ((previous_bb->last_ins != NULL) && (previous_bb->last_ins->opcode == CEE_SWITCH)) {
8113 /* Do not touch BBs following the entry BB and jumping to something that is not */
8114 /* thiry "next" bb (the entry BB cannot contain the branch) */
8115 if ((previous_bb == cfg->bb_entry) && (bb->next_bb != target_bb)) {
8119 /* Check that there is a target BB, and that bb is not an empty loop (Bug 75061) */
8120 if ((target_bb != NULL) && (target_bb != bb)) {
8123 if (cfg->verbose_level > 1) {
8124 printf ("remove_block_if_useless %s, removed BB%d\n", mono_method_full_name (cfg->method, TRUE), bb->block_num);
8127 for (i = 0; i < bb->in_count; i++) {
8128 MonoBasicBlock *in_bb = bb->in_bb [i];
8129 replace_out_block (in_bb, bb, target_bb);
8130 replace_out_block_in_code (in_bb, bb, target_bb);
8131 if (bb->in_count == 1) {
8132 replace_in_block (target_bb, bb, in_bb);
8134 replace_or_add_in_block (cfg, target_bb, bb, in_bb);
8138 if ((previous_bb != cfg->bb_entry) &&
8139 (previous_bb->region == bb->region) &&
8140 ((previous_bb->last_ins == NULL) ||
8141 ((previous_bb->last_ins->opcode != CEE_BR) &&
8142 (! (MONO_IS_COND_BRANCH_OP (previous_bb->last_ins))) &&
8143 (previous_bb->last_ins->opcode != CEE_SWITCH)))) {
8144 for (i = 0; i < previous_bb->out_count; i++) {
8145 if (previous_bb->out_bb [i] == target_bb) {
8147 MONO_INST_NEW (cfg, jump, CEE_BR);
8148 MONO_ADD_INS (previous_bb, jump);
8149 jump->cil_code = previous_bb->cil_code;
8150 jump->inst_target_bb = target_bb;
8156 previous_bb->next_bb = bb->next_bb;
8157 nullify_basic_block (bb);
8166 merge_basic_blocks (MonoBasicBlock *bb, MonoBasicBlock *bbn)
8168 bb->out_count = bbn->out_count;
8169 bb->out_bb = bbn->out_bb;
8171 replace_basic_block (bb, bbn, bb);
8175 bb->last_ins->next = bbn->code;
8176 bb->last_ins = bbn->last_ins;
8179 bb->code = bbn->code;
8180 bb->last_ins = bbn->last_ins;
8182 bb->next_bb = bbn->next_bb;
8183 nullify_basic_block (bbn);
8187 move_basic_block_to_end (MonoCompile *cfg, MonoBasicBlock *bb)
8189 MonoBasicBlock *bbn, *next;
8193 /* Find the previous */
8194 for (bbn = cfg->bb_entry; bbn->next_bb && bbn->next_bb != bb; bbn = bbn->next_bb)
8197 bbn->next_bb = bb->next_bb;
8201 for (bbn = cfg->bb_entry; bbn->next_bb; bbn = bbn->next_bb)
8207 if (next && (!bb->last_ins || (bb->last_ins->opcode != OP_NOT_REACHED))) {
8210 MONO_INST_NEW (cfg, ins, CEE_BR);
8211 MONO_ADD_INS (bb, ins);
8212 link_bblock (cfg, bb, next);
8213 ins->inst_target_bb = next;
8218 * Optimizes the branches on the Control Flow Graph
8222 optimize_branches (MonoCompile *cfg)
8224 int i, changed = FALSE;
8225 MonoBasicBlock *bb, *bbn;
8226 guint32 niterations;
8229 * Some crazy loops could cause the code below to go into an infinite
8230 * loop, see bug #53003 for an example. To prevent this, we put an upper
8231 * bound on the number of iterations.
8233 if (cfg->num_bblocks > 1000)
8234 niterations = cfg->num_bblocks * 2;
8238 MonoBasicBlock *previous_bb;
8242 /* we skip the entry block (exit is handled specially instead ) */
8243 for (previous_bb = cfg->bb_entry, bb = cfg->bb_entry->next_bb; bb; previous_bb = bb, bb = bb->next_bb) {
8245 /* dont touch code inside exception clauses */
8246 if (bb->region != -1)
8249 if (remove_block_if_useless (cfg, bb, previous_bb)) {
8254 if ((bbn = bb->next_bb) && bbn->in_count == 0 && bb->region == bbn->region) {
8255 if (cfg->verbose_level > 2)
8256 g_print ("nullify block triggered %d\n", bbn->block_num);
8258 bb->next_bb = bbn->next_bb;
8260 for (i = 0; i < bbn->out_count; i++)
8261 replace_in_block (bbn->out_bb [i], bbn, NULL);
8263 nullify_basic_block (bbn);
8267 if (bb->out_count == 1) {
8268 bbn = bb->out_bb [0];
8270 /* conditional branches where true and false targets are the same can be also replaced with CEE_BR */
8271 if (bb->last_ins && MONO_IS_COND_BRANCH_OP (bb->last_ins)) {
8273 MONO_INST_NEW (cfg, pop, CEE_POP);
8274 pop->inst_left = bb->last_ins->inst_left->inst_left;
8275 mono_add_ins_to_end (bb, pop);
8276 MONO_INST_NEW (cfg, pop, CEE_POP);
8277 pop->inst_left = bb->last_ins->inst_left->inst_right;
8278 mono_add_ins_to_end (bb, pop);
8279 bb->last_ins->opcode = CEE_BR;
8280 bb->last_ins->inst_target_bb = bb->last_ins->inst_true_bb;
8282 if (cfg->verbose_level > 2)
8283 g_print ("cond branch removal triggered in %d %d\n", bb->block_num, bb->out_count);
8286 if (bb->region == bbn->region && bb->next_bb == bbn) {
8287 /* the block are in sequence anyway ... */
8289 /* branches to the following block can be removed */
8290 if (bb->last_ins && bb->last_ins->opcode == CEE_BR) {
8291 bb->last_ins->opcode = CEE_NOP;
8293 if (cfg->verbose_level > 2)
8294 g_print ("br removal triggered %d -> %d\n", bb->block_num, bbn->block_num);
8297 if (bbn->in_count == 1) {
8299 if (bbn != cfg->bb_exit) {
8300 if (cfg->verbose_level > 2)
8301 g_print ("block merge triggered %d -> %d\n", bb->block_num, bbn->block_num);
8302 merge_basic_blocks (bb, bbn);
8306 //mono_print_bb_code (bb);
8311 } while (changed && (niterations > 0));
8318 /* we skip the entry block (exit is handled specially instead ) */
8319 for (bb = cfg->bb_entry->next_bb; bb; bb = bb->next_bb) {
8321 /* dont touch code inside exception clauses */
8322 if (bb->region != -1)
8325 if ((bbn = bb->next_bb) && bbn->in_count == 0 && bb->region == bbn->region) {
8326 if (cfg->verbose_level > 2) {
8327 g_print ("nullify block triggered %d\n", bbn->block_num);
8329 bb->next_bb = bbn->next_bb;
8331 for (i = 0; i < bbn->out_count; i++)
8332 replace_in_block (bbn->out_bb [i], bbn, NULL);
8334 nullify_basic_block (bbn);
8340 if (bb->out_count == 1) {
8341 bbn = bb->out_bb [0];
8343 if (bb->last_ins && bb->last_ins->opcode == CEE_BR) {
8344 bbn = bb->last_ins->inst_target_bb;
8345 if (bb->region == bbn->region && bbn->code && bbn->code->opcode == CEE_BR &&
8346 bbn->code->inst_target_bb->region == bb->region) {
8348 if (cfg->verbose_level > 2)
8349 g_print ("in %s branch to branch triggered %d -> %d -> %d\n", cfg->method->name,
8350 bb->block_num, bbn->block_num, bbn->code->inst_target_bb->block_num);
8352 replace_in_block (bbn, bb, NULL);
8353 replace_out_block (bb, bbn, bbn->code->inst_target_bb);
8354 link_bblock (cfg, bb, bbn->code->inst_target_bb);
8355 bb->last_ins->inst_target_bb = bbn->code->inst_target_bb;
8360 } else if (bb->out_count == 2) {
8361 if (bb->last_ins && MONO_IS_COND_BRANCH_NOFP (bb->last_ins)) {
8362 int branch_result = mono_eval_cond_branch (bb->last_ins);
8363 MonoBasicBlock *taken_branch_target = NULL, *untaken_branch_target = NULL;
8364 if (branch_result == BRANCH_TAKEN) {
8365 taken_branch_target = bb->last_ins->inst_true_bb;
8366 untaken_branch_target = bb->last_ins->inst_false_bb;
8367 } else if (branch_result == BRANCH_NOT_TAKEN) {
8368 taken_branch_target = bb->last_ins->inst_false_bb;
8369 untaken_branch_target = bb->last_ins->inst_true_bb;
8371 if (taken_branch_target) {
8372 /* if mono_eval_cond_branch () is ever taken to handle
8373 * non-constant values to compare, issue a pop here.
8375 bb->last_ins->opcode = CEE_BR;
8376 bb->last_ins->inst_target_bb = taken_branch_target;
8377 replace_out_block (bb, untaken_branch_target, NULL);
8378 replace_in_block (untaken_branch_target, bb, NULL);
8382 bbn = bb->last_ins->inst_true_bb;
8383 if (bb->region == bbn->region && bbn->code && bbn->code->opcode == CEE_BR &&
8384 bbn->code->inst_target_bb->region == bb->region) {
8385 if (cfg->verbose_level > 2)
8386 g_print ("cbranch1 to branch triggered %d -> (%d) %d (0x%02x)\n",
8387 bb->block_num, bbn->block_num, bbn->code->inst_target_bb->block_num,
8390 bb->last_ins->inst_true_bb = bbn->code->inst_target_bb;
8392 replace_in_block (bbn, bb, NULL);
8394 replace_in_block (bbn->code->inst_target_bb, bbn, bb);
8395 replace_out_block (bb, bbn, bbn->code->inst_target_bb);
8397 link_bblock (cfg, bb, bbn->code->inst_target_bb);
8403 bbn = bb->last_ins->inst_false_bb;
8404 if (bb->region == bbn->region && bbn->code && bbn->code->opcode == CEE_BR &&
8405 bbn->code->inst_target_bb->region == bb->region) {
8406 if (cfg->verbose_level > 2)
8407 g_print ("cbranch2 to branch triggered %d -> (%d) %d (0x%02x)\n",
8408 bb->block_num, bbn->block_num, bbn->code->inst_target_bb->block_num,
8411 bb->last_ins->inst_false_bb = bbn->code->inst_target_bb;
8413 replace_in_block (bbn, bb, NULL);
8415 replace_in_block (bbn->code->inst_target_bb, bbn, bb);
8416 replace_out_block (bb, bbn, bbn->code->inst_target_bb);
8418 link_bblock (cfg, bb, bbn->code->inst_target_bb);
8425 if (bb->last_ins && MONO_IS_COND_BRANCH_NOFP (bb->last_ins)) {
8426 if (bb->last_ins->inst_false_bb->out_of_line && (bb->region == bb->last_ins->inst_false_bb->region)) {
8427 /* Reverse the branch */
8428 bb->last_ins->opcode = reverse_branch_op (bb->last_ins->opcode);
8429 bbn = bb->last_ins->inst_false_bb;
8430 bb->last_ins->inst_false_bb = bb->last_ins->inst_true_bb;
8431 bb->last_ins->inst_true_bb = bbn;
8433 move_basic_block_to_end (cfg, bb->last_ins->inst_true_bb);
8434 if (cfg->verbose_level > 2)
8435 g_print ("cbranch to throw block triggered %d.\n",
8441 } while (changed && (niterations > 0));
8446 mono_compile_create_vars (MonoCompile *cfg)
8448 MonoMethodSignature *sig;
8449 MonoMethodHeader *header;
8452 header = mono_method_get_header (cfg->method);
8454 sig = mono_method_signature (cfg->method);
8456 if (!MONO_TYPE_IS_VOID (sig->ret)) {
8457 cfg->ret = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst));
8458 cfg->ret->opcode = OP_RETARG;
8459 cfg->ret->inst_vtype = sig->ret;
8460 cfg->ret->klass = mono_class_from_mono_type (sig->ret);
8462 if (cfg->verbose_level > 2)
8463 g_print ("creating vars\n");
8466 mono_compile_create_var (cfg, &cfg->method->klass->this_arg, OP_ARG);
8468 for (i = 0; i < sig->param_count; ++i) {
8469 mono_compile_create_var (cfg, sig->params [i], OP_ARG);
8470 if (sig->params [i]->byref) {
8471 cfg->disable_ssa = TRUE;
8475 cfg->locals_start = cfg->num_varinfo;
8477 if (cfg->verbose_level > 2)
8478 g_print ("creating locals\n");
8479 for (i = 0; i < header->num_locals; ++i)
8480 mono_compile_create_var (cfg, header->locals [i], OP_LOCAL);
8481 if (cfg->verbose_level > 2)
8482 g_print ("locals done\n");
8484 #ifdef MONO_ARCH_HAVE_CREATE_VARS
8485 mono_arch_create_vars (cfg);
8490 mono_print_code (MonoCompile *cfg)
8494 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
8495 MonoInst *tree = bb->code;
8500 g_print ("CODE BLOCK %d (nesting %d):\n", bb->block_num, bb->nesting);
8502 for (; tree; tree = tree->next) {
8503 mono_print_tree (tree);
8508 bb->last_ins->next = NULL;
8512 extern const char * const mono_burg_rule_string [];
8515 emit_state (MonoCompile *cfg, MBState *state, int goal)
8518 int ern = mono_burg_rule (state, goal);
8519 const guint16 *nts = mono_burg_nts [ern];
8522 //g_print ("rule: %s\n", mono_burg_rule_string [ern]);
8526 // state->reg1 = state->reg2; /* chain rule */
8528 #ifdef MONO_ARCH_ENABLE_EMIT_STATE_OPT
8531 state->reg1 = mono_regstate_next_int (cfg->rs);
8532 //g_print ("alloc symbolic R%d (reg2: R%d) in block %d\n", state->reg1, state->reg2, cfg->cbb->block_num);
8535 state->reg1 = mono_regstate_next_int (cfg->rs);
8536 state->reg2 = mono_regstate_next_int (cfg->rs);
8539 state->reg1 = mono_regstate_next_float (cfg->rs);
8542 #ifdef MONO_ARCH_ENABLE_EMIT_STATE_OPT
8544 * Enabling this might cause bugs to surface in the local register
8545 * allocators on some architectures like x86.
8547 if ((state->tree->ssa_op == MONO_SSA_STORE) && (state->left->tree->opcode == OP_REGVAR)) {
8548 /* Do not optimize away reg-reg moves */
8549 if (! ((state->right->tree->ssa_op == MONO_SSA_LOAD) && (state->right->left->tree->opcode == OP_REGVAR))) {
8550 state->right->reg1 = state->left->tree->dreg;
8559 mono_burg_kids (state, ern, kids);
8561 emit_state (cfg, kids [0], nts [0]);
8563 emit_state (cfg, kids [1], nts [1]);
8565 g_assert (!nts [3]);
8566 emit_state (cfg, kids [2], nts [2]);
8571 // g_print ("emit: %s (%p)\n", mono_burg_rule_string [ern], state);
8572 if ((emit = mono_burg_func [ern]))
8573 emit (state, state->tree, cfg);
8576 #define DEBUG_SELECTION
8579 mini_select_instructions (MonoCompile *cfg)
8583 cfg->state_pool = mono_mempool_new ();
8584 cfg->rs = mono_regstate_new ();
8586 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
8587 if (bb->last_ins && MONO_IS_COND_BRANCH_OP (bb->last_ins) &&
8588 bb->next_bb != bb->last_ins->inst_false_bb) {
8590 /* we are careful when inverting, since bugs like #59580
8591 * could show up when dealing with NaNs.
8593 if (MONO_IS_COND_BRANCH_NOFP(bb->last_ins) && bb->next_bb == bb->last_ins->inst_true_bb) {
8594 MonoBasicBlock *tmp = bb->last_ins->inst_true_bb;
8595 bb->last_ins->inst_true_bb = bb->last_ins->inst_false_bb;
8596 bb->last_ins->inst_false_bb = tmp;
8598 bb->last_ins->opcode = reverse_branch_op (bb->last_ins->opcode);
8600 MonoInst *inst = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst));
8601 inst->opcode = CEE_BR;
8602 inst->inst_target_bb = bb->last_ins->inst_false_bb;
8603 mono_bblock_add_inst (bb, inst);
8608 #ifdef DEBUG_SELECTION
8609 if (cfg->verbose_level >= 4) {
8610 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
8611 MonoInst *tree = bb->code;
8612 g_print ("DUMP BLOCK %d:\n", bb->block_num);
8615 for (; tree; tree = tree->next) {
8616 mono_print_tree (tree);
8623 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
8624 MonoInst *tree = bb->code, *next;
8630 bb->last_ins = NULL;
8633 mono_regstate_reset (cfg->rs);
8635 #ifdef DEBUG_SELECTION
8636 if (cfg->verbose_level >= 3)
8637 g_print ("LABEL BLOCK %d:\n", bb->block_num);
8639 for (; tree; tree = next) {
8641 #ifdef DEBUG_SELECTION
8642 if (cfg->verbose_level >= 3) {
8643 mono_print_tree (tree);
8648 if (!(mbstate = mono_burg_label (tree, cfg))) {
8649 g_warning ("unable to label tree %p", tree);
8650 mono_print_tree (tree);
8652 g_assert_not_reached ();
8654 emit_state (cfg, mbstate, MB_NTERM_stmt);
8656 bb->max_ireg = cfg->rs->next_vireg;
8657 bb->max_freg = cfg->rs->next_vfreg;
8660 bb->last_ins->next = NULL;
8662 mono_mempool_empty (cfg->state_pool);
8664 mono_mempool_destroy (cfg->state_pool);
8668 mono_codegen (MonoCompile *cfg)
8670 MonoJumpInfo *patch_info;
8672 int i, max_epilog_size;
8675 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
8676 cfg->spill_count = 0;
8677 /* we reuse dfn here */
8678 /* bb->dfn = bb_count++; */
8679 mono_arch_local_regalloc (cfg, bb);
8682 if (cfg->prof_options & MONO_PROFILE_COVERAGE)
8683 cfg->coverage_info = mono_profiler_coverage_alloc (cfg->method, cfg->num_bblocks);
8685 code = mono_arch_emit_prolog (cfg);
8687 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
8688 code = mono_arch_instrument_prolog (cfg, mono_profiler_method_enter, code, FALSE);
8690 cfg->code_len = code - cfg->native_code;
8691 cfg->prolog_end = cfg->code_len;
8693 mono_debug_open_method (cfg);
8695 /* emit code all basic blocks */
8696 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
8697 bb->native_offset = cfg->code_len;
8698 mono_arch_output_basic_block (cfg, bb);
8700 if (bb == cfg->bb_exit) {
8701 cfg->epilog_begin = cfg->code_len;
8703 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE) {
8704 code = cfg->native_code + cfg->code_len;
8705 code = mono_arch_instrument_epilog (cfg, mono_profiler_method_leave, code, FALSE);
8706 cfg->code_len = code - cfg->native_code;
8709 mono_arch_emit_epilog (cfg);
8713 mono_arch_emit_exceptions (cfg);
8715 max_epilog_size = 0;
8717 code = cfg->native_code + cfg->code_len;
8719 /* we always allocate code in cfg->domain->code_mp to increase locality */
8720 cfg->code_size = cfg->code_len + max_epilog_size;
8721 /* fixme: align to MONO_ARCH_CODE_ALIGNMENT */
8723 if (cfg->method->dynamic) {
8724 /* Allocate the code into a separate memory pool so it can be freed */
8725 cfg->dynamic_info = g_new0 (MonoJitDynamicMethodInfo, 1);
8726 cfg->dynamic_info->code_mp = mono_code_manager_new_dynamic ();
8727 mono_domain_lock (cfg->domain);
8728 mono_dynamic_code_hash_insert (cfg->domain, cfg->method, cfg->dynamic_info);
8729 mono_domain_unlock (cfg->domain);
8731 code = mono_code_manager_reserve (cfg->dynamic_info->code_mp, cfg->code_size);
8733 mono_domain_lock (cfg->domain);
8734 code = mono_code_manager_reserve (cfg->domain->code_mp, cfg->code_size);
8735 mono_domain_unlock (cfg->domain);
8738 memcpy (code, cfg->native_code, cfg->code_len);
8739 g_free (cfg->native_code);
8740 cfg->native_code = code;
8741 code = cfg->native_code + cfg->code_len;
8743 /* g_assert (((int)cfg->native_code & (MONO_ARCH_CODE_ALIGNMENT - 1)) == 0); */
8744 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
8745 switch (patch_info->type) {
8746 case MONO_PATCH_INFO_ABS: {
8747 MonoJitICallInfo *info = mono_find_jit_icall_by_addr (patch_info->data.target);
8749 //printf ("TEST %s %p\n", info->name, patch_info->data.target);
8750 if ((cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) &&
8751 strstr (cfg->method->name, info->name))
8753 * This is an icall wrapper, and this is a call to the
8758 patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
8759 patch_info->data.name = info->name;
8763 MonoVTable *vtable = mono_find_class_init_trampoline_by_addr (patch_info->data.target);
8765 patch_info->type = MONO_PATCH_INFO_CLASS_INIT;
8766 patch_info->data.klass = vtable->klass;
8771 case MONO_PATCH_INFO_SWITCH: {
8773 if (cfg->method->dynamic) {
8774 table = mono_code_manager_reserve (cfg->dynamic_info->code_mp, sizeof (gpointer) * patch_info->data.table->table_size);
8776 mono_domain_lock (cfg->domain);
8777 table = mono_code_manager_reserve (cfg->domain->code_mp, sizeof (gpointer) * patch_info->data.table->table_size);
8778 mono_domain_unlock (cfg->domain);
8781 if (!cfg->compile_aot)
8782 /* In the aot case, the patch already points to the correct location */
8783 patch_info->ip.i = patch_info->ip.label->inst_c0;
8784 for (i = 0; i < patch_info->data.table->table_size; i++) {
8785 table [i] = GINT_TO_POINTER (patch_info->data.table->table [i]->native_offset);
8787 patch_info->data.table->table = (MonoBasicBlock**)table;
8796 if (cfg->verbose_level > 0) {
8797 char* nm = mono_method_full_name (cfg->method, TRUE);
8798 g_print ("Method %s emitted at %p to %p [%s]\n",
8800 cfg->native_code, cfg->native_code + cfg->code_len, cfg->domain->friendly_name);
8804 #ifdef MONO_ARCH_HAVE_SAVE_UNWIND_INFO
8805 mono_arch_save_unwind_info (cfg);
8808 mono_arch_patch_code (cfg->method, cfg->domain, cfg->native_code, cfg->patch_info, cfg->run_cctors);
8810 if (cfg->method->dynamic) {
8811 mono_code_manager_commit (cfg->dynamic_info->code_mp, cfg->native_code, cfg->code_size, cfg->code_len);
8813 mono_domain_lock (cfg->domain);
8814 mono_code_manager_commit (cfg->domain->code_mp, cfg->native_code, cfg->code_size, cfg->code_len);
8815 mono_domain_unlock (cfg->domain);
8818 mono_arch_flush_icache (cfg->native_code, cfg->code_len);
8820 mono_debug_close_method (cfg);
8824 mono_cprop_copy_values (MonoCompile *cfg, MonoInst *tree, MonoInst **acp)
8829 if (tree->ssa_op == MONO_SSA_LOAD && (tree->inst_i0->opcode == OP_LOCAL || tree->inst_i0->opcode == OP_ARG) &&
8830 (cp = acp [tree->inst_i0->inst_c0]) && !tree->inst_i0->flags) {
8832 if (cp->opcode == OP_ICONST) {
8833 if (cfg->opt & MONO_OPT_CONSPROP) {
8834 //{ static int c = 0; printf ("CCOPY %d %d %s\n", c++, cp->inst_c0, mono_method_full_name (cfg->method, TRUE)); }
8838 if (tree->inst_i0->inst_vtype->type == cp->inst_vtype->type) {
8839 if (cfg->opt & MONO_OPT_COPYPROP) {
8840 //{ static int c = 0; printf ("VCOPY %d\n", ++c); }
8846 arity = mono_burg_arity [tree->opcode];
8849 mono_cprop_copy_values (cfg, tree->inst_i0, acp);
8850 if (cfg->opt & MONO_OPT_CFOLD)
8851 mono_constant_fold_inst (tree, NULL);
8852 /* The opcode may have changed */
8853 if (mono_burg_arity [tree->opcode] > 1) {
8854 mono_cprop_copy_values (cfg, tree->inst_i1, acp);
8855 if (cfg->opt & MONO_OPT_CFOLD)
8856 mono_constant_fold_inst (tree, NULL);
8858 mono_constant_fold_inst (tree, NULL);
8864 mono_cprop_invalidate_values (MonoInst *tree, MonoInst **acp, int acp_size)
8868 switch (tree->opcode) {
8878 if (tree->ssa_op == MONO_SSA_NOP) {
8879 memset (acp, 0, sizeof (MonoInst *) * acp_size);
8896 case OP_VOIDCALL_REG:
8897 case OP_VOIDCALLVIRT:
8899 MonoCallInst *call = (MonoCallInst *)tree;
8900 MonoMethodSignature *sig = call->signature;
8901 int i, byref = FALSE;
8903 for (i = 0; i < sig->param_count; i++) {
8904 if (sig->params [i]->byref) {
8911 memset (acp, 0, sizeof (MonoInst *) * acp_size);
8919 arity = mono_burg_arity [tree->opcode];
8925 mono_cprop_invalidate_values (tree->inst_i0, acp, acp_size);
8928 mono_cprop_invalidate_values (tree->inst_i0, acp, acp_size);
8929 mono_cprop_invalidate_values (tree->inst_i1, acp, acp_size);
8932 g_assert_not_reached ();
8937 mono_local_cprop_bb (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst **acp, int acp_size)
8939 MonoInst *tree = bb->code;
8945 for (; tree; tree = tree->next) {
8947 mono_cprop_copy_values (cfg, tree, acp);
8949 mono_cprop_invalidate_values (tree, acp, acp_size);
8951 if (tree->ssa_op == MONO_SSA_STORE &&
8952 (tree->inst_i0->opcode == OP_LOCAL || tree->inst_i0->opcode == OP_ARG)) {
8953 MonoInst *i1 = tree->inst_i1;
8955 acp [tree->inst_i0->inst_c0] = NULL;
8957 for (i = 0; i < acp_size; i++) {
8958 if (acp [i] && acp [i]->opcode != OP_ICONST &&
8959 acp [i]->inst_c0 == tree->inst_i0->inst_c0) {
8964 if (i1->opcode == OP_ICONST) {
8965 acp [tree->inst_i0->inst_c0] = i1;
8966 //printf ("DEF1 BB%d %d\n", bb->block_num,tree->inst_i0->inst_c0);
8968 if (i1->ssa_op == MONO_SSA_LOAD &&
8969 (i1->inst_i0->opcode == OP_LOCAL || i1->inst_i0->opcode == OP_ARG) &&
8970 (i1->inst_i0->inst_c0 != tree->inst_i0->inst_c0)) {
8971 acp [tree->inst_i0->inst_c0] = i1->inst_i0;
8972 //printf ("DEF2 BB%d %d %d\n", bb->block_num,tree->inst_i0->inst_c0,i1->inst_i0->inst_c0);
8977 if (tree->opcode == CEE_BEQ) {
8978 g_assert (tree->inst_i0->opcode == OP_COMPARE);
8979 if (tree->inst_i0->inst_i0->opcode == OP_ICONST &&
8980 tree->inst_i0->inst_i1->opcode == OP_ICONST) {
8982 tree->opcode = CEE_BR;
8983 if (tree->inst_i0->inst_i0->opcode == tree->inst_i0->inst_i1->opcode) {
8984 tree->inst_target_bb = tree->inst_true_bb;
8986 tree->inst_target_bb = tree->inst_false_bb;
8995 mono_local_cprop (MonoCompile *cfg)
9000 acp = alloca (sizeof (MonoInst *) * cfg->num_varinfo);
9002 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
9003 memset (acp, 0, sizeof (MonoInst *) * cfg->num_varinfo);
9004 mono_local_cprop_bb (cfg, bb, acp, cfg->num_varinfo);
9009 remove_critical_edges (MonoCompile *cfg) {
9011 MonoBasicBlock *previous_bb;
9013 if (cfg->verbose_level > 3) {
9014 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
9016 printf ("remove_critical_edges %s, BEFORE BB%d (in:", mono_method_full_name (cfg->method, TRUE), bb->block_num);
9017 for (i = 0; i < bb->in_count; i++) {
9018 printf (" %d", bb->in_bb [i]->block_num);
9021 for (i = 0; i < bb->out_count; i++) {
9022 printf (" %d", bb->out_bb [i]->block_num);
9025 if (bb->last_ins != NULL) {
9027 mono_print_tree (bb->last_ins);
9033 for (previous_bb = cfg->bb_entry, bb = previous_bb->next_bb; bb != NULL; previous_bb = previous_bb->next_bb, bb = bb->next_bb) {
9034 if (bb->in_count > 1) {
9036 for (in_bb_index = 0; in_bb_index < bb->in_count; in_bb_index++) {
9037 MonoBasicBlock *in_bb = bb->in_bb [in_bb_index];
9038 if (in_bb->out_count > 1) {
9039 MonoBasicBlock *new_bb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
9040 new_bb->block_num = cfg->num_bblocks++;
9041 // new_bb->real_offset = bb->real_offset;
9042 new_bb->region = bb->region;
9044 /* Do not alter the CFG while altering the BB list */
9045 if (previous_bb->region == bb->region) {
9046 if (previous_bb != cfg->bb_entry) {
9047 /* If previous_bb "followed through" to bb, */
9048 /* keep it linked with a CEE_BR */
9049 if ((previous_bb->last_ins == NULL) ||
9050 ((previous_bb->last_ins->opcode != CEE_BR) &&
9051 (! (MONO_IS_COND_BRANCH_OP (previous_bb->last_ins))) &&
9052 (previous_bb->last_ins->opcode != CEE_SWITCH))) {
9054 /* Make sure previous_bb really falls through bb */
9055 for (i = 0; i < previous_bb->out_count; i++) {
9056 if (previous_bb->out_bb [i] == bb) {
9058 MONO_INST_NEW (cfg, jump, CEE_BR);
9059 MONO_ADD_INS (previous_bb, jump);
9060 jump->cil_code = previous_bb->cil_code;
9061 jump->inst_target_bb = bb;
9067 /* We cannot add any inst to the entry BB, so we must */
9068 /* put a new BB in the middle to hold the CEE_BR */
9070 MonoBasicBlock *new_bb_after_entry = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
9071 new_bb_after_entry->block_num = cfg->num_bblocks++;
9072 // new_bb_after_entry->real_offset = bb->real_offset;
9073 new_bb_after_entry->region = bb->region;
9075 MONO_INST_NEW (cfg, jump, CEE_BR);
9076 MONO_ADD_INS (new_bb_after_entry, jump);
9077 jump->cil_code = bb->cil_code;
9078 jump->inst_target_bb = bb;
9080 previous_bb->next_bb = new_bb_after_entry;
9081 previous_bb = new_bb_after_entry;
9083 if (cfg->verbose_level > 2) {
9084 printf ("remove_critical_edges %s, added helper BB%d jumping to BB%d\n", mono_method_full_name (cfg->method, TRUE), new_bb_after_entry->block_num, bb->block_num);
9089 /* Insert new_bb in the BB list */
9090 previous_bb->next_bb = new_bb;
9091 new_bb->next_bb = bb;
9092 previous_bb = new_bb;
9094 /* Setup in_bb and out_bb */
9095 new_bb->in_bb = mono_mempool_alloc ((cfg)->mempool, sizeof (MonoBasicBlock*));
9096 new_bb->in_bb [0] = in_bb;
9097 new_bb->in_count = 1;
9098 new_bb->out_bb = mono_mempool_alloc ((cfg)->mempool, sizeof (MonoBasicBlock*));
9099 new_bb->out_bb [0] = bb;
9100 new_bb->out_count = 1;
9102 /* Relink in_bb and bb to (from) new_bb */
9103 replace_out_block (in_bb, bb, new_bb);
9104 replace_out_block_in_code (in_bb, bb, new_bb);
9105 replace_in_block (bb, in_bb, new_bb);
9107 if (cfg->verbose_level > 2) {
9108 printf ("remove_critical_edges %s, removed critical edge from BB%d to BB%d (added BB%d)\n", mono_method_full_name (cfg->method, TRUE), in_bb->block_num, bb->block_num, new_bb->block_num);
9115 if (cfg->verbose_level > 3) {
9116 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
9118 printf ("remove_critical_edges %s, AFTER BB%d (in:", mono_method_full_name (cfg->method, TRUE), bb->block_num);
9119 for (i = 0; i < bb->in_count; i++) {
9120 printf (" %d", bb->in_bb [i]->block_num);
9123 for (i = 0; i < bb->out_count; i++) {
9124 printf (" %d", bb->out_bb [i]->block_num);
9127 if (bb->last_ins != NULL) {
9129 mono_print_tree (bb->last_ins);
9137 mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gboolean run_cctors, gboolean compile_aot, int parts)
9139 MonoMethodHeader *header = mono_method_get_header (method);
9143 int dfn = 0, i, code_size_ratio;
9148 ip = (guint8 *)header->code;
9150 mono_jit_stats.methods_compiled++;
9151 if (mono_profiler_get_events () & MONO_PROFILE_JIT_COMPILATION)
9152 mono_profiler_method_jit (method);
9154 cfg = g_new0 (MonoCompile, 1);
9155 cfg->method = method;
9156 cfg->mempool = mono_mempool_new ();
9158 cfg->prof_options = mono_profiler_get_events ();
9159 cfg->run_cctors = run_cctors;
9160 cfg->bb_hash = g_hash_table_new (NULL, NULL);
9161 cfg->domain = domain;
9162 cfg->verbose_level = mini_verbose;
9163 cfg->compile_aot = compile_aot;
9164 cfg->intvars = mono_mempool_alloc0 (cfg->mempool, sizeof (guint16) * STACK_MAX *
9165 mono_method_get_header (method)->max_stack);
9167 if (cfg->verbose_level > 2)
9168 g_print ("converting method %s\n", mono_method_full_name (method, TRUE));
9171 * create MonoInst* which represents arguments and local variables
9173 mono_compile_create_vars (cfg);
9175 if ((i = mono_method_to_ir (cfg, method, NULL, NULL, cfg->locals_start, NULL, NULL, NULL, 0, FALSE)) < 0) {
9176 if (cfg->prof_options & MONO_PROFILE_JIT_COMPILATION)
9177 mono_profiler_method_end_jit (method, MONO_PROFILE_FAILED);
9178 mono_destroy_compile (cfg);
9182 mono_jit_stats.basic_blocks += cfg->num_bblocks;
9183 mono_jit_stats.max_basic_blocks = MAX (cfg->num_bblocks, mono_jit_stats.max_basic_blocks);
9185 if ((cfg->num_varinfo > 2000) && !mono_compile_aot) {
9187 * we disable some optimizations if there are too many variables
9188 * because JIT time may become too expensive. The actual number needs
9189 * to be tweaked and eventually the non-linear algorithms should be fixed.
9191 cfg->opt &= ~ (MONO_OPT_LINEARS | MONO_OPT_COPYPROP | MONO_OPT_CONSPROP);
9192 cfg->disable_ssa = TRUE;
9195 /*g_print ("numblocks = %d\n", cfg->num_bblocks);*/
9197 if (cfg->opt & MONO_OPT_BRANCH)
9198 optimize_branches (cfg);
9200 if (cfg->opt & MONO_OPT_SSAPRE) {
9201 remove_critical_edges (cfg);
9204 /* Depth-first ordering on basic blocks */
9205 cfg->bblocks = mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * (cfg->num_bblocks + 1));
9207 df_visit (cfg->bb_entry, &dfn, cfg->bblocks);
9208 if (cfg->num_bblocks != dfn + 1) {
9211 cfg->num_bblocks = dfn + 1;
9213 if (!header->clauses) {
9214 /* remove unreachable code, because the code in them may be
9215 * inconsistent (access to dead variables for example) */
9216 for (bb = cfg->bb_entry; bb;) {
9217 MonoBasicBlock *bbn = bb->next_bb;
9219 if (bbn && bbn->region == -1 && !bbn->dfn) {
9220 if (cfg->verbose_level > 1)
9221 g_print ("found unreachabel code in BB%d\n", bbn->block_num);
9222 bb->next_bb = bbn->next_bb;
9223 nullify_basic_block (bbn);
9231 if (cfg->opt & MONO_OPT_LOOP) {
9232 mono_compile_dominator_info (cfg, MONO_COMP_DOM | MONO_COMP_IDOM);
9233 mono_compute_natural_loops (cfg);
9236 /* after method_to_ir */
9240 //#define DEBUGSSA "logic_run"
9241 #define DEBUGSSA_CLASS "Tests"
9244 if (!header->num_clauses && !cfg->disable_ssa) {
9245 mono_local_cprop (cfg);
9246 mono_ssa_compute (cfg);
9250 /* fixme: add all optimizations which requires SSA */
9251 if (cfg->opt & (MONO_OPT_DEADCE | MONO_OPT_ABCREM | MONO_OPT_SSAPRE)) {
9252 if (!(cfg->comp_done & MONO_COMP_SSA) && !header->num_clauses && !cfg->disable_ssa) {
9253 mono_local_cprop (cfg);
9254 mono_ssa_compute (cfg);
9256 if (cfg->verbose_level >= 2) {
9263 /* after SSA translation */
9267 if ((cfg->opt & MONO_OPT_CONSPROP) || (cfg->opt & MONO_OPT_COPYPROP)) {
9268 if (cfg->comp_done & MONO_COMP_SSA) {
9269 mono_ssa_cprop (cfg);
9271 mono_local_cprop (cfg);
9275 if (cfg->comp_done & MONO_COMP_SSA) {
9276 mono_ssa_deadce (cfg);
9278 //mono_ssa_strength_reduction (cfg);
9280 if ((cfg->flags & MONO_CFG_HAS_LDELEMA) && (cfg->opt & MONO_OPT_ABCREM))
9281 mono_perform_abc_removal (cfg);
9283 if (cfg->opt & MONO_OPT_SSAPRE)
9284 mono_perform_ssapre (cfg);
9286 mono_ssa_remove (cfg);
9288 if (cfg->opt & MONO_OPT_BRANCH)
9289 optimize_branches (cfg);
9292 /* after SSA removal */
9296 decompose_pass (cfg);
9301 g_assert (cfg->got_var_allocated);
9304 * Allways allocate the GOT var to a register, because keeping it
9305 * in memory will increase the number of live temporaries in some
9306 * code created by inssel.brg, leading to the well known spills+
9307 * branches problem. Testcase: mcs crash in
9308 * System.MonoCustomAttrs:GetCustomAttributes.
9310 regs = mono_arch_get_global_int_regs (cfg);
9312 cfg->got_var->opcode = OP_REGVAR;
9313 cfg->got_var->dreg = GPOINTER_TO_INT (regs->data);
9314 cfg->used_int_regs |= 1LL << cfg->got_var->dreg;
9319 if (cfg->opt & MONO_OPT_LINEARS) {
9322 /* fixme: maybe we can avoid to compute livenesss here if already computed ? */
9323 cfg->comp_done &= ~MONO_COMP_LIVENESS;
9324 if (!(cfg->comp_done & MONO_COMP_LIVENESS))
9325 mono_analyze_liveness (cfg);
9327 if ((vars = mono_arch_get_allocatable_int_vars (cfg))) {
9328 regs = mono_arch_get_global_int_regs (cfg);
9330 regs = g_list_delete_link (regs, regs);
9331 mono_linear_scan (cfg, vars, regs, &cfg->used_int_regs);
9335 //mono_print_code (cfg);
9339 /* variables are allocated after decompose, since decompose could create temps */
9340 mono_arch_allocate_vars (cfg);
9342 if (cfg->opt & MONO_OPT_CFOLD)
9343 mono_constant_fold (cfg);
9345 mini_select_instructions (cfg);
9348 if (cfg->verbose_level >= 2) {
9349 char *id = mono_method_full_name (cfg->method, FALSE);
9350 mono_disassemble_code (cfg, cfg->native_code, cfg->code_len, id + 3);
9354 if (cfg->method->dynamic) {
9355 jinfo = g_malloc0 (sizeof (MonoJitInfo) + (header->num_clauses * sizeof (MonoJitExceptionInfo)));
9357 /* we access cfg->domain->mp */
9358 mono_domain_lock (cfg->domain);
9359 jinfo = mono_mempool_alloc0 (cfg->domain->mp, sizeof (MonoJitInfo) + (header->num_clauses * sizeof (MonoJitExceptionInfo)));
9360 mono_domain_unlock (cfg->domain);
9363 jinfo->method = method;
9364 jinfo->code_start = cfg->native_code;
9365 jinfo->code_size = cfg->code_len;
9366 jinfo->used_regs = cfg->used_int_regs;
9367 jinfo->domain_neutral = (cfg->opt & MONO_OPT_SHARED) != 0;
9368 jinfo->cas_inited = FALSE; /* initialization delayed at the first stalk walk using this method */
9370 if (header->num_clauses) {
9373 jinfo->num_clauses = header->num_clauses;
9375 for (i = 0; i < header->num_clauses; i++) {
9376 MonoExceptionClause *ec = &header->clauses [i];
9377 MonoJitExceptionInfo *ei = &jinfo->clauses [i];
9378 MonoBasicBlock *tblock;
9381 ei->flags = ec->flags;
9383 exvar = mono_find_exvar_for_offset (cfg, ec->handler_offset);
9384 ei->exvar_offset = exvar ? exvar->inst_offset : 0;
9386 if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
9387 tblock = g_hash_table_lookup (cfg->bb_hash, ip + ec->data.filter_offset);
9389 ei->data.filter = cfg->native_code + tblock->native_offset;
9391 ei->data.catch_class = ec->data.catch_class;
9394 tblock = g_hash_table_lookup (cfg->bb_hash, ip + ec->try_offset);
9396 ei->try_start = cfg->native_code + tblock->native_offset;
9397 g_assert (tblock->native_offset);
9398 tblock = g_hash_table_lookup (cfg->bb_hash, ip + ec->try_offset + ec->try_len);
9400 ei->try_end = cfg->native_code + tblock->native_offset;
9401 g_assert (tblock->native_offset);
9402 tblock = g_hash_table_lookup (cfg->bb_hash, ip + ec->handler_offset);
9404 ei->handler_start = cfg->native_code + tblock->native_offset;
9408 cfg->jit_info = jinfo;
9409 #if defined(__arm__)
9410 mono_arch_fixup_jinfo (cfg);
9413 mono_domain_lock (cfg->domain);
9414 mono_jit_info_table_add (cfg->domain, jinfo);
9416 if (cfg->method->dynamic)
9417 mono_dynamic_code_hash_lookup (cfg->domain, cfg->method)->ji = jinfo;
9418 mono_domain_unlock (cfg->domain);
9420 /* collect statistics */
9421 mono_jit_stats.allocated_code_size += cfg->code_len;
9422 code_size_ratio = cfg->code_len;
9423 if (code_size_ratio > mono_jit_stats.biggest_method_size) {
9424 mono_jit_stats.biggest_method_size = code_size_ratio;
9425 mono_jit_stats.biggest_method = method;
9427 code_size_ratio = (code_size_ratio * 100) / mono_method_get_header (method)->code_size;
9428 if (code_size_ratio > mono_jit_stats.max_code_size_ratio) {
9429 mono_jit_stats.max_code_size_ratio = code_size_ratio;
9430 mono_jit_stats.max_ratio_method = method;
9432 mono_jit_stats.native_code_size += cfg->code_len;
9434 if (cfg->prof_options & MONO_PROFILE_JIT_COMPILATION)
9435 mono_profiler_method_end_jit (method, MONO_PROFILE_OK);
9437 /* this can only be set if the security manager is active */
9438 if (cfg->exception_type == MONO_EXCEPTION_SECURITY_LINKDEMAND) {
9439 MonoAssembly *assembly = mono_image_get_assembly (method->klass->image);
9440 MonoReflectionAssembly *refass = (MonoReflectionAssembly*) mono_assembly_get_object (domain, assembly);
9441 MonoReflectionMethod *refmet = mono_method_get_object (domain, method, NULL);
9442 MonoSecurityManager* secman = mono_security_manager_get_methods ();
9443 MonoObject *exc = NULL;
9446 args [0] = &cfg->exception_data;
9449 mono_runtime_invoke (secman->linkdemandsecurityexception, NULL, args, &exc);
9451 mono_destroy_compile (cfg);
9454 mono_raise_exception ((MonoException*)exc);
9461 mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain)
9464 GHashTable *jit_code_hash;
9465 gpointer code = NULL;
9471 jit_code_hash = target_domain->jit_code_hash;
9473 method = mono_get_inflated_method (method);
9475 #ifdef MONO_USE_AOT_COMPILER
9476 if (!mono_compile_aot && (opt & MONO_OPT_AOT)) {
9478 MonoDomain *domain = mono_domain_get ();
9480 mono_domain_lock (domain);
9482 mono_class_init (method->klass);
9483 if ((info = mono_aot_get_method (domain, method))) {
9484 g_hash_table_insert (domain->jit_code_hash, method, info);
9485 mono_domain_unlock (domain);
9486 mono_runtime_class_init (mono_class_vtable (domain, method->klass));
9487 return info->code_start;
9490 mono_domain_unlock (domain);
9494 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
9495 (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
9497 MonoMethodPInvoke* piinfo = (MonoMethodPInvoke *) method;
9499 if (method->iflags & METHOD_IMPL_ATTRIBUTE_NATIVE)
9500 g_error ("Method '%s' in assembly '%s' contains native code and mono can't run it. The assembly was probably created by Managed C++.\n", mono_method_full_name (method, TRUE), method->klass->image->name);
9502 if (!piinfo->addr) {
9503 if (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL)
9504 piinfo->addr = mono_lookup_internal_call (method);
9506 if (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
9507 mono_lookup_pinvoke_call (method, NULL, NULL);
9509 nm = mono_marshal_get_native_wrapper (method);
9510 return mono_get_addr_from_ftnptr (mono_compile_method (nm));
9512 //if (mono_debug_format != MONO_DEBUG_FORMAT_NONE)
9513 //mono_debug_add_wrapper (method, nm);
9514 } else if ((method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME)) {
9515 const char *name = method->name;
9518 if (method->klass->parent == mono_defaults.multicastdelegate_class) {
9519 if (*name == '.' && (strcmp (name, ".ctor") == 0)) {
9520 MonoJitICallInfo *mi = mono_find_jit_icall_by_name ("mono_delegate_ctor");
9522 return mono_get_addr_from_ftnptr ((gpointer)mono_icall_get_wrapper (mi));
9523 } else if (*name == 'I' && (strcmp (name, "Invoke") == 0)) {
9524 nm = mono_marshal_get_delegate_invoke (method);
9525 return mono_get_addr_from_ftnptr (mono_compile_method (nm));
9526 } else if (*name == 'B' && (strcmp (name, "BeginInvoke") == 0)) {
9527 nm = mono_marshal_get_delegate_begin_invoke (method);
9528 return mono_get_addr_from_ftnptr (mono_compile_method (nm));
9529 } else if (*name == 'E' && (strcmp (name, "EndInvoke") == 0)) {
9530 nm = mono_marshal_get_delegate_end_invoke (method);
9531 return mono_get_addr_from_ftnptr (mono_compile_method (nm));
9537 cfg = mini_method_compile (method, opt, target_domain, TRUE, FALSE, 0);
9540 /* Throw a type load exception if needed */
9541 MonoLoaderError *error = mono_loader_get_last_error ();
9544 MonoException *ex = mini_loader_error_to_exception (error);
9545 mono_loader_clear_error ();
9546 mono_raise_exception (ex);
9549 g_assert_not_reached ();
9552 mono_domain_lock (target_domain);
9554 /* Check if some other thread already did the job. In this case, we can
9555 discard the code this thread generated. */
9557 if ((info = g_hash_table_lookup (target_domain->jit_code_hash, method))) {
9558 /* We can't use a domain specific method in another domain */
9559 if ((target_domain == mono_domain_get ()) || info->domain_neutral) {
9560 code = info->code_start;
9561 // printf("Discarding code for method %s\n", method->name);
9566 g_hash_table_insert (jit_code_hash, method, cfg->jit_info);
9567 code = cfg->native_code;
9570 mono_destroy_compile (cfg);
9572 if (target_domain->jump_target_hash) {
9573 MonoJumpInfo patch_info;
9575 list = g_hash_table_lookup (target_domain->jump_target_hash, method);
9577 patch_info.next = NULL;
9578 patch_info.ip.i = 0;
9579 patch_info.type = MONO_PATCH_INFO_METHOD_JUMP;
9580 patch_info.data.method = method;
9581 g_hash_table_remove (target_domain->jump_target_hash, method);
9583 for (tmp = list; tmp; tmp = tmp->next)
9584 mono_arch_patch_code (NULL, target_domain, tmp->data, &patch_info, TRUE);
9585 g_slist_free (list);
9588 mono_domain_unlock (target_domain);
9590 mono_runtime_class_init (mono_class_vtable (target_domain, method->klass));
9595 mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt)
9597 /* FIXME: later copy the code from mono */
9598 MonoDomain *target_domain, *domain = mono_domain_get ();
9602 if (opt & MONO_OPT_SHARED)
9603 target_domain = mono_get_root_domain ();
9605 target_domain = domain;
9607 mono_domain_lock (target_domain);
9609 if ((info = g_hash_table_lookup (target_domain->jit_code_hash, method))) {
9610 /* We can't use a domain specific method in another domain */
9611 if (! ((domain != target_domain) && !info->domain_neutral)) {
9612 mono_domain_unlock (target_domain);
9613 mono_jit_stats.methods_lookups++;
9614 mono_runtime_class_init (mono_class_vtable (domain, method->klass));
9615 return mono_create_ftnptr (domain, info->code_start);
9619 mono_domain_unlock (target_domain);
9620 p = mono_jit_compile_method_inner (method, target_domain);
9621 return mono_create_ftnptr (domain, p);
9625 mono_jit_compile_method (MonoMethod *method)
9627 return mono_jit_compile_method_with_opt (method, default_opt);
9631 invalidated_delegate_trampoline (char *desc)
9633 g_error ("Unmanaged code called delegate of type %s which was already garbage collected.\n"
9634 "See http://www.go-mono.com/delegate.html for an explanation and ways to fix this.",
9639 * mono_jit_free_method:
9641 * Free all memory allocated by the JIT for METHOD.
9644 mono_jit_free_method (MonoDomain *domain, MonoMethod *method)
9646 MonoJitDynamicMethodInfo *ji;
9647 gboolean destroy = TRUE;
9649 g_assert (method->dynamic);
9651 mono_domain_lock (domain);
9652 ji = mono_dynamic_code_hash_lookup (domain, method);
9653 mono_domain_unlock (domain);
9657 mono_domain_lock (domain);
9658 g_hash_table_remove (domain->dynamic_code_hash, method);
9659 g_hash_table_remove (domain->jit_code_hash, method);
9660 mono_domain_unlock (domain);
9662 #ifdef MONO_ARCH_HAVE_INVALIDATE_METHOD
9663 if (debug_options.keep_delegates && method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
9665 * Instead of freeing the code, change it to call an error routine
9666 * so people can fix their code.
9668 char *type = mono_type_full_name (&method->klass->byval_arg);
9669 char *type_and_method = g_strdup_printf ("%s.%s", type, method->name);
9672 mono_arch_invalidate_method (ji->ji, invalidated_delegate_trampoline, type_and_method);
9678 * This needs to be done before freeing code_mp, since the code address is the
9679 * key in the table, so if we the code_mp first, another thread can grab the
9680 * same code address and replace our entry in the table.
9682 mono_jit_info_table_remove (domain, ji->ji);
9685 mono_code_manager_destroy (ji->code_mp);
9691 mono_jit_find_compiled_method (MonoDomain *domain, MonoMethod *method)
9693 MonoDomain *target_domain;
9696 if (default_opt & MONO_OPT_SHARED)
9697 target_domain = mono_get_root_domain ();
9699 target_domain = domain;
9701 mono_domain_lock (target_domain);
9703 if ((info = g_hash_table_lookup (target_domain->jit_code_hash, method))) {
9704 /* We can't use a domain specific method in another domain */
9705 if (! ((domain != target_domain) && !info->domain_neutral)) {
9706 mono_domain_unlock (target_domain);
9707 mono_jit_stats.methods_lookups++;
9708 return info->code_start;
9712 mono_domain_unlock (target_domain);
9718 * mono_jit_runtime_invoke:
9719 * @method: the method to invoke
9720 * @obj: this pointer
9721 * @params: array of parameter values.
9722 * @exc: used to catch exceptions objects
9725 mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
9728 MonoObject *(*runtime_invoke) (MonoObject *this, void **params, MonoObject **exc, void* compiled_method);
9729 void* compiled_method;
9731 if (obj == NULL && !(method->flags & METHOD_ATTRIBUTE_STATIC) && !method->string_ctor && (method->wrapper_type == 0)) {
9732 g_warning ("Ignoring invocation of an instance method on a NULL instance.\n");
9736 method = mono_get_inflated_method (method);
9737 invoke = mono_marshal_get_runtime_invoke (method);
9738 runtime_invoke = mono_jit_compile_method (invoke);
9740 /* We need this here becuase mono_marshal_get_runtime_invoke can be place
9741 * the helper method in System.Object and not the target class
9743 mono_runtime_class_init (mono_class_vtable (mono_domain_get (), method->klass));
9745 compiled_method = mono_jit_compile_method (method);
9746 return runtime_invoke (obj, params, exc, compiled_method);
9749 #ifdef PLATFORM_WIN32
9750 #define GET_CONTEXT \
9751 struct sigcontext *ctx = (struct sigcontext*)_dummy;
9754 #define GET_CONTEXT \
9755 void *ctx = context;
9756 #elif defined(sun) // Solaris x86
9757 #define GET_CONTEXT \
9758 ucontext_t *uctx = context; \
9759 struct sigcontext *ctx = (struct sigcontext *)&(uctx->uc_mcontext);
9760 #elif defined(__ppc__) || defined (__powerpc__) || defined (__s390__) || defined (MONO_ARCH_USE_SIGACTION)
9761 #define GET_CONTEXT \
9762 void *ctx = context;
9764 #define GET_CONTEXT \
9765 void **_p = (void **)&_dummy; \
9766 struct sigcontext *ctx = (struct sigcontext *)++_p;
9770 #ifdef MONO_ARCH_USE_SIGACTION
9771 #define SIG_HANDLER_SIGNATURE(ftn) ftn (int _dummy, siginfo_t *info, void *context)
9773 #define SIG_HANDLER_SIGNATURE(ftn) ftn (int _dummy)
9777 SIG_HANDLER_SIGNATURE (sigfpe_signal_handler)
9779 MonoException *exc = NULL;
9780 #ifndef MONO_ARCH_USE_SIGACTION
9785 #if defined(MONO_ARCH_HAVE_IS_INT_OVERFLOW)
9786 if (mono_arch_is_int_overflow (ctx, info))
9787 exc = mono_get_exception_arithmetic ();
9789 exc = mono_get_exception_divide_by_zero ();
9791 exc = mono_get_exception_divide_by_zero ();
9794 mono_arch_handle_exception (ctx, exc, FALSE);
9798 SIG_HANDLER_SIGNATURE (sigill_signal_handler)
9802 exc = mono_get_exception_execution_engine ("SIGILL");
9804 mono_arch_handle_exception (ctx, exc, FALSE);
9807 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
9809 #ifndef MONO_ARCH_USE_SIGACTION
9810 #error "Can't use sigaltstack without sigaction"
9816 SIG_HANDLER_SIGNATURE (sigsegv_signal_handler)
9818 MonoException *exc = NULL;
9819 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
9820 MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
9824 if (debug_options.collect_pagefault_stats) {
9825 if (mono_raw_buffer_is_pagefault (info->si_addr)) {
9826 mono_raw_buffer_handle_pagefault (info->si_addr);
9831 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
9832 /* Can't allocate memory using Boehm GC on altstack */
9833 if (jit_tls->stack_size &&
9834 ((guint8*)info->si_addr >= (guint8*)jit_tls->end_of_stack - jit_tls->stack_size) &&
9835 ((guint8*)info->si_addr < (guint8*)jit_tls->end_of_stack))
9836 exc = mono_domain_get ()->stack_overflow_ex;
9838 exc = mono_domain_get ()->null_reference_ex;
9841 if (debug_options.abort_on_sigsegv) {
9842 MonoJitInfo *ji = mono_jit_info_table_find (mono_domain_get (), mono_arch_ip_from_context(ctx));
9844 fprintf (stderr, "Got SIGSEGV while in unmanaged code, and the 'abort-on-sigsegv' MONO_DEBUG option is set. Aborting...\n");
9845 /* Segfault in unmanaged code */
9850 mono_arch_handle_exception (ctx, exc, FALSE);
9854 SIG_HANDLER_SIGNATURE (sigusr1_signal_handler)
9856 gboolean running_managed;
9864 * This is an async signal, so the code below must not call anything which
9865 * is not async safe. That includes the pthread locking functions. If we
9866 * know that we interrupted managed code, then locking is safe.
9868 ji = mono_jit_info_table_find (mono_domain_get (), mono_arch_ip_from_context(ctx));
9869 running_managed = ji != NULL;
9871 exc = mono_thread_request_interruption (running_managed);
9874 mono_arch_handle_exception (ctx, exc, FALSE);
9878 SIG_HANDLER_SIGNATURE (sigprof_signal_handler)
9882 mono_profiler_stat_hit (mono_arch_ip_from_context (ctx), ctx);
9886 SIG_HANDLER_SIGNATURE (sigquit_signal_handler)
9891 exc = mono_get_exception_execution_engine ("Interrupted (SIGQUIT).");
9893 mono_arch_handle_exception (ctx, exc, FALSE);
9897 SIG_HANDLER_SIGNATURE (sigint_signal_handler)
9902 exc = mono_get_exception_execution_engine ("Interrupted (SIGINT).");
9904 mono_arch_handle_exception (ctx, exc, FALSE);
9908 SIG_HANDLER_SIGNATURE (sigusr2_signal_handler)
9910 gboolean enabled = mono_trace_is_enabled ();
9912 mono_trace_enable (!enabled);
9915 #ifndef PLATFORM_WIN32
9917 add_signal_handler (int signo, gpointer handler)
9919 struct sigaction sa;
9921 #ifdef MONO_ARCH_USE_SIGACTION
9922 sa.sa_sigaction = handler;
9923 sigemptyset (&sa.sa_mask);
9924 sa.sa_flags = SA_SIGINFO;
9926 sa.sa_handler = handler;
9927 sigemptyset (&sa.sa_mask);
9930 g_assert (sigaction (signo, &sa, NULL) != -1);
9935 mono_runtime_install_handlers (void)
9937 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
9938 struct sigaction sa;
9941 #ifdef PLATFORM_WIN32
9943 win32_seh_set_handler(SIGFPE, sigfpe_signal_handler);
9944 win32_seh_set_handler(SIGILL, sigill_signal_handler);
9945 win32_seh_set_handler(SIGSEGV, sigsegv_signal_handler);
9946 if (debug_options.handle_sigint)
9947 win32_seh_set_handler(SIGINT, sigint_signal_handler);
9949 #else /* !PLATFORM_WIN32 */
9951 /* libpthreads has its own implementation of sigaction(),
9952 * but it seems to work well with our current exception
9953 * handlers. If not we must call syscall directly instead
9956 if (debug_options.handle_sigint)
9957 add_signal_handler (SIGINT, sigint_signal_handler);
9959 add_signal_handler (SIGFPE, sigfpe_signal_handler);
9960 add_signal_handler (SIGQUIT, sigquit_signal_handler);
9961 add_signal_handler (SIGILL, sigill_signal_handler);
9962 add_signal_handler (SIGBUS, sigsegv_signal_handler);
9963 if (mono_jit_trace_calls != NULL)
9964 add_signal_handler (SIGUSR2, sigusr2_signal_handler);
9966 add_signal_handler (mono_thread_get_abort_signal (), sigusr1_signal_handler);
9967 signal (SIGPIPE, SIG_IGN);
9970 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
9971 sa.sa_sigaction = sigsegv_signal_handler;
9972 sigemptyset (&sa.sa_mask);
9973 sa.sa_flags = SA_SIGINFO | SA_ONSTACK;
9974 g_assert (sigaction (SIGSEGV, &sa, NULL) != -1);
9976 add_signal_handler (SIGSEGV, sigsegv_signal_handler);
9979 #endif /* PLATFORM_WIN32 */
9983 #ifdef HAVE_LINUX_RTC_H
9984 #include <linux/rtc.h>
9985 #include <sys/ioctl.h>
9987 static int rtc_fd = -1;
9990 enable_rtc_timer (gboolean enable)
9993 flags = fcntl (rtc_fd, F_GETFL);
9995 perror ("getflags");
10002 if (fcntl (rtc_fd, F_SETFL, flags) == -1) {
10003 perror ("setflags");
10011 setup_stat_profiler (void)
10014 struct itimerval itval;
10015 static int inited = 0;
10016 #ifdef HAVE_LINUX_RTC_H
10017 const char *rtc_freq;
10018 if (!inited && (rtc_freq = g_getenv ("MONO_RTC"))) {
10022 freq = atoi (rtc_freq);
10025 rtc_fd = open ("/dev/rtc", O_RDONLY);
10026 if (rtc_fd == -1) {
10027 perror ("open /dev/rtc");
10030 add_signal_handler (SIGPROF, sigprof_signal_handler);
10031 if (ioctl (rtc_fd, RTC_IRQP_SET, freq) == -1) {
10032 perror ("set rtc freq");
10035 if (ioctl (rtc_fd, RTC_PIE_ON, 0) == -1) {
10036 perror ("start rtc");
10039 if (fcntl (rtc_fd, F_SETSIG, SIGPROF) == -1) {
10043 if (fcntl (rtc_fd, F_SETOWN, getpid ()) == -1) {
10047 enable_rtc_timer (TRUE);
10054 itval.it_interval.tv_usec = 999;
10055 itval.it_interval.tv_sec = 0;
10056 itval.it_value = itval.it_interval;
10057 setitimer (ITIMER_PROF, &itval, NULL);
10061 add_signal_handler (SIGPROF, sigprof_signal_handler);
10065 /* mono_jit_create_remoting_trampoline:
10066 * @method: pointer to the method info
10068 * Creates a trampoline which calls the remoting functions. This
10069 * is used in the vtable of transparent proxies.
10071 * Returns: a pointer to the newly created code
10074 mono_jit_create_remoting_trampoline (MonoMethod *method, MonoRemotingTarget target)
10077 guint8 *addr = NULL;
10079 if ((method->flags & METHOD_ATTRIBUTE_ABSTRACT) ||
10080 (mono_method_signature (method)->hasthis && (method->klass->marshalbyref || method->klass == mono_defaults.object_class))) {
10081 nm = mono_marshal_get_remoting_invoke_for_target (method, target);
10082 addr = mono_compile_method (nm);
10084 addr = mono_compile_method (method);
10086 return mono_get_addr_from_ftnptr (addr);
10090 mini_parse_debug_options (void)
10092 char *options = getenv ("MONO_DEBUG");
10093 gchar **args, **ptr;
10098 args = g_strsplit (options, ",", -1);
10100 for (ptr = args; ptr && *ptr; ptr++) {
10101 const char *arg = *ptr;
10103 if (!strcmp (arg, "handle-sigint"))
10104 debug_options.handle_sigint = TRUE;
10105 else if (!strcmp (arg, "keep-delegates"))
10106 debug_options.keep_delegates = TRUE;
10107 else if (!strcmp (arg, "abort-on-sigsegv"))
10108 debug_options.abort_on_sigsegv = TRUE;
10109 else if (!strcmp (arg, "collect-pagefault-stats"))
10110 debug_options.collect_pagefault_stats = TRUE;
10112 fprintf (stderr, "Invalid option for the MONO_DEBUG env variable: %s\n", arg);
10113 fprintf (stderr, "Available options: 'handle-sigint', 'keep-delegates', 'abort-on-sigsegv', 'collect-pagefault-stats'\n");
10120 mini_init (const char *filename)
10122 MonoDomain *domain;
10124 /* Happens when using the embedding interface */
10125 if (default_opt == 0)
10126 default_opt = mono_parse_default_optimizations (NULL);
10128 InitializeCriticalSection (&jit_mutex);
10130 global_codeman = mono_code_manager_new ();
10131 jit_icall_name_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
10133 mono_arch_cpu_init ();
10135 mono_init_trampolines ();
10137 mono_init_exceptions ();
10139 if (!g_thread_supported ())
10140 g_thread_init (NULL);
10142 if (getenv ("MONO_DEBUG") != NULL)
10143 mini_parse_debug_options ();
10145 if (mono_running_on_valgrind ()) {
10146 gsize stack_bottom = (gsize)&domain;
10147 stack_bottom += 4095;
10148 stack_bottom &= ~4095;
10149 GC_stackbottom = (char*)stack_bottom;
10151 MONO_GC_PRE_INIT ();
10153 mono_jit_tls_id = TlsAlloc ();
10154 setup_jit_tls_data ((gpointer)-1, mono_thread_abort);
10158 if (default_opt & MONO_OPT_AOT)
10161 mono_runtime_install_handlers ();
10162 mono_threads_install_cleanup (mini_thread_cleanup);
10164 #define JIT_TRAMPOLINES_WORK
10165 #ifdef JIT_TRAMPOLINES_WORK
10166 mono_install_compile_method (mono_jit_compile_method);
10167 mono_install_free_method (mono_jit_free_method);
10168 mono_install_trampoline (mono_create_jit_trampoline);
10169 mono_install_remoting_trampoline (mono_jit_create_remoting_trampoline);
10170 mono_install_delegate_trampoline (mono_create_delegate_trampoline);
10172 #define JIT_INVOKE_WORKS
10173 #ifdef JIT_INVOKE_WORKS
10174 mono_install_runtime_invoke (mono_jit_runtime_invoke);
10175 mono_install_handler (mono_arch_get_throw_exception ());
10177 mono_install_stack_walk (mono_jit_walk_stack);
10178 mono_install_init_vtable (mono_aot_init_vtable);
10179 mono_install_get_cached_class_info (mono_aot_get_cached_class_info);
10180 mono_install_jit_info_find_in_aot (mono_aot_find_jit_info);
10182 if (debug_options.collect_pagefault_stats)
10183 mono_raw_buffer_set_make_unreadable (TRUE);
10185 domain = mono_init_from_assembly (filename, filename);
10186 mono_icall_init ();
10188 mono_add_internal_call ("System.Diagnostics.StackFrame::get_frame_info",
10189 ves_icall_get_frame_info);
10190 mono_add_internal_call ("System.Diagnostics.StackTrace::get_trace",
10191 ves_icall_get_trace);
10192 mono_add_internal_call ("System.Exception::get_trace",
10193 ves_icall_System_Exception_get_trace);
10194 mono_add_internal_call ("System.Security.SecurityFrame::_GetSecurityFrame",
10195 ves_icall_System_Security_SecurityFrame_GetSecurityFrame);
10196 mono_add_internal_call ("System.Security.SecurityFrame::_GetSecurityStack",
10197 ves_icall_System_Security_SecurityFrame_GetSecurityStack);
10198 mono_add_internal_call ("Mono.Runtime::mono_runtime_install_handlers",
10199 mono_runtime_install_handlers);
10202 create_helper_signature ();
10204 #define JIT_CALLS_WORK
10205 #ifdef JIT_CALLS_WORK
10206 /* Needs to be called here since register_jit_icall depends on it */
10207 mono_marshal_init ();
10209 mono_arch_register_lowlevel_calls ();
10210 register_icall (mono_profiler_method_enter, "mono_profiler_method_enter", NULL, TRUE);
10211 register_icall (mono_profiler_method_leave, "mono_profiler_method_leave", NULL, TRUE);
10212 register_icall (mono_trace_enter_method, "mono_trace_enter_method", NULL, TRUE);
10213 register_icall (mono_trace_leave_method, "mono_trace_leave_method", NULL, TRUE);
10214 register_icall (mono_get_lmf_addr, "mono_get_lmf_addr", "ptr", TRUE);
10215 register_icall (mono_jit_thread_attach, "mono_jit_thread_attach", "void", TRUE);
10216 register_icall (mono_domain_get, "mono_domain_get", "ptr", TRUE);
10218 register_icall (mono_arch_get_throw_exception (), "mono_arch_throw_exception", "void object", TRUE);
10219 register_icall (mono_arch_get_rethrow_exception (), "mono_arch_rethrow_exception", "void object", TRUE);
10220 register_icall (mono_arch_get_throw_exception_by_name (), "mono_arch_throw_exception_by_name", "void ptr", TRUE);
10221 #if MONO_ARCH_HAVE_THROW_CORLIB_EXCEPTION
10222 register_icall (mono_arch_get_throw_corlib_exception (), "mono_arch_throw_corlib_exception",
10225 register_icall (mono_thread_get_pending_exception, "mono_thread_get_pending_exception", "object", FALSE);
10226 register_icall (mono_thread_interruption_checkpoint, "mono_thread_interruption_checkpoint", "void", FALSE);
10227 register_icall (mono_thread_force_interruption_checkpoint, "mono_thread_force_interruption_checkpoint", "void", FALSE);
10228 register_icall (mono_load_remote_field_new, "mono_load_remote_field_new", "object object ptr ptr", FALSE);
10229 register_icall (mono_store_remote_field_new, "mono_store_remote_field_new", "void object ptr ptr object", FALSE);
10232 * NOTE, NOTE, NOTE, NOTE:
10233 * when adding emulation for some opcodes, remember to also add a dummy
10234 * rule to the burg files, because we need the arity information to be correct.
10236 #ifndef MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS
10237 mono_register_opcode_emulation (OP_LMUL, "__emul_lmul", "long long long", mono_llmult, TRUE);
10238 mono_register_opcode_emulation (OP_LDIV, "__emul_ldiv", "long long long", mono_lldiv, FALSE);
10239 mono_register_opcode_emulation (OP_LDIV_UN, "__emul_ldiv_un", "long long long", mono_lldiv_un, FALSE);
10240 mono_register_opcode_emulation (OP_LREM, "__emul_lrem", "long long long", mono_llrem, FALSE);
10241 mono_register_opcode_emulation (OP_LREM_UN, "__emul_lrem_un", "long long long", mono_llrem_un, FALSE);
10242 mono_register_opcode_emulation (OP_LMUL_OVF_UN, "__emul_lmul_ovf_un", "long long long", mono_llmult_ovf_un, FALSE);
10243 mono_register_opcode_emulation (OP_LMUL_OVF, "__emul_lmul_ovf", "long long long", mono_llmult_ovf, FALSE);
10246 #ifndef MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
10247 mono_register_opcode_emulation (OP_LSHL, "__emul_lshl", "long long int32", mono_lshl, TRUE);
10248 mono_register_opcode_emulation (OP_LSHR, "__emul_lshr", "long long int32", mono_lshr, TRUE);
10249 mono_register_opcode_emulation (OP_LSHR_UN, "__emul_lshr_un", "long long int32", mono_lshr_un, TRUE);
10252 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
10253 mono_register_opcode_emulation (CEE_DIV, "__emul_idiv", "int32 int32 int32", mono_idiv, TRUE);
10254 mono_register_opcode_emulation (CEE_DIV_UN, "__emul_idiv_un", "int32 int32 int32", mono_idiv_un, TRUE);
10255 mono_register_opcode_emulation (CEE_REM, "__emul_irem", "int32 int32 int32", mono_irem, TRUE);
10256 mono_register_opcode_emulation (CEE_REM_UN, "__emul_irem_un", "int32 int32 int32", mono_irem_un, TRUE);
10259 #ifdef MONO_ARCH_EMULATE_MUL_DIV
10260 mono_register_opcode_emulation (CEE_MUL_OVF, "__emul_imul_ovf", "int32 int32 int32", mono_imul_ovf, TRUE);
10261 mono_register_opcode_emulation (CEE_MUL_OVF_UN, "__emul_imul_ovf_un", "int32 int32 int32", mono_imul_ovf_un, TRUE);
10262 mono_register_opcode_emulation (CEE_MUL, "__emul_imul", "int32 int32 int32", mono_imul, TRUE);
10263 mono_register_opcode_emulation (OP_FDIV, "__emul_fdiv", "double double double", mono_fdiv, TRUE);
10266 mono_register_opcode_emulation (OP_FCONV_TO_U8, "__emul_fconv_to_u8", "ulong double", mono_fconv_u8, FALSE);
10267 mono_register_opcode_emulation (OP_FCONV_TO_U4, "__emul_fconv_to_u4", "uint32 double", mono_fconv_u4, FALSE);
10268 mono_register_opcode_emulation (OP_FCONV_TO_OVF_I8, "__emul_fconv_to_ovf_i8", "long double", mono_fconv_ovf_i8, FALSE);
10269 mono_register_opcode_emulation (OP_FCONV_TO_OVF_U8, "__emul_fconv_to_ovf_u8", "ulong double", mono_fconv_ovf_u8, FALSE);
10271 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
10272 mono_register_opcode_emulation (OP_FCONV_TO_I8, "__emul_fconv_to_i8", "long double", mono_fconv_i8, FALSE);
10274 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
10275 mono_register_opcode_emulation (CEE_CONV_R_UN, "__emul_conv_r_un", "double int32", mono_conv_to_r8_un, FALSE);
10277 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
10278 mono_register_opcode_emulation (OP_LCONV_TO_R8, "__emul_lconv_to_r8", "double long", mono_lconv_to_r8, FALSE);
10280 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
10281 mono_register_opcode_emulation (OP_LCONV_TO_R4, "__emul_lconv_to_r4", "float long", mono_lconv_to_r4, FALSE);
10283 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
10284 mono_register_opcode_emulation (OP_LCONV_TO_R_UN, "__emul_lconv_to_r8_un", "double long", mono_lconv_to_r8_un, FALSE);
10286 #ifdef MONO_ARCH_EMULATE_FREM
10287 mono_register_opcode_emulation (OP_FREM, "__emul_frem", "double double double", fmod, FALSE);
10290 #if SIZEOF_VOID_P == 4
10291 mono_register_opcode_emulation (OP_FCONV_TO_U, "__emul_fconv_to_u", "uint32 double", mono_fconv_u4, TRUE);
10294 /* other jit icalls */
10295 register_icall (mono_delegate_ctor, "mono_delegate_ctor", "void object object ptr", FALSE);
10296 register_icall (mono_class_static_field_address , "mono_class_static_field_address",
10297 "ptr ptr ptr", FALSE);
10298 register_icall (mono_ldtoken_wrapper, "mono_ldtoken_wrapper", "ptr ptr ptr ptr", FALSE);
10299 register_icall (mono_get_special_static_data, "mono_get_special_static_data", "ptr int", FALSE);
10300 register_icall (mono_ldstr, "mono_ldstr", "object ptr ptr int32", FALSE);
10301 register_icall (helper_stelem_ref, "helper_stelem_ref", "void ptr int32 object", FALSE);
10302 register_icall (helper_stelem_ref_check, "helper_stelem_ref_check", "void object object", FALSE);
10303 register_icall (mono_object_new, "mono_object_new", "object ptr ptr", FALSE);
10304 register_icall (mono_object_new_specific, "mono_object_new_specific", "object ptr", FALSE);
10305 register_icall (mono_array_new, "mono_array_new", "object ptr ptr int32", FALSE);
10306 register_icall (mono_array_new_specific, "mono_array_new_specific", "object ptr int32", FALSE);
10307 register_icall (mono_runtime_class_init, "mono_runtime_class_init", "void ptr", FALSE);
10308 register_icall (mono_ldftn, "mono_ldftn", "ptr ptr", FALSE);
10309 register_icall (mono_ldftn_nosync, "mono_ldftn_nosync", "ptr ptr", FALSE);
10310 register_icall (mono_ldvirtfn, "mono_ldvirtfn", "ptr object ptr", FALSE);
10311 register_icall (helper_compile_generic_method, "compile_generic_method", "ptr object ptr ptr", FALSE);
10312 register_icall (helper_ldstr, "helper_ldstr", "object ptr int", FALSE);
10315 #define JIT_RUNTIME_WORKS
10316 #ifdef JIT_RUNTIME_WORKS
10317 mono_install_runtime_cleanup ((MonoDomainFunc)mini_cleanup);
10318 mono_runtime_init (domain, mono_thread_start_cb, mono_thread_attach_cb);
10321 mono_thread_attach (domain);
10325 MonoJitStats mono_jit_stats = {0};
10328 print_jit_stats (void)
10330 if (mono_jit_stats.enabled) {
10331 g_print ("Mono Jit statistics\n");
10332 g_print ("Compiled methods: %ld\n", mono_jit_stats.methods_compiled);
10333 g_print ("Methods from AOT: %ld\n", mono_jit_stats.methods_aot);
10334 g_print ("Methods cache lookup: %ld\n", mono_jit_stats.methods_lookups);
10335 g_print ("Method trampolines: %ld\n", mono_jit_stats.method_trampolines);
10336 g_print ("Basic blocks: %ld\n", mono_jit_stats.basic_blocks);
10337 g_print ("Max basic blocks: %ld\n", mono_jit_stats.max_basic_blocks);
10338 g_print ("Allocated vars: %ld\n", mono_jit_stats.allocate_var);
10339 g_print ("Analyze stack repeat: %ld\n", mono_jit_stats.analyze_stack_repeat);
10340 g_print ("Compiled CIL code size: %ld\n", mono_jit_stats.cil_code_size);
10341 g_print ("Native code size: %ld\n", mono_jit_stats.native_code_size);
10342 g_print ("Max code size ratio: %.2f (%s::%s)\n", mono_jit_stats.max_code_size_ratio/100.0,
10343 mono_jit_stats.max_ratio_method->klass->name, mono_jit_stats.max_ratio_method->name);
10344 g_print ("Biggest method: %ld (%s::%s)\n", mono_jit_stats.biggest_method_size,
10345 mono_jit_stats.biggest_method->klass->name, mono_jit_stats.biggest_method->name);
10346 g_print ("Code reallocs: %ld\n", mono_jit_stats.code_reallocs);
10347 g_print ("Allocated code size: %ld\n", mono_jit_stats.allocated_code_size);
10348 g_print ("Inlineable methods: %ld\n", mono_jit_stats.inlineable_methods);
10349 g_print ("Inlined methods: %ld\n", mono_jit_stats.inlined_methods);
10351 g_print ("\nCreated object count: %ld\n", mono_stats.new_object_count);
10352 g_print ("Initialized classes: %ld\n", mono_stats.initialized_class_count);
10353 g_print ("Used classes: %ld\n", mono_stats.used_class_count);
10354 g_print ("Static data size: %ld\n", mono_stats.class_static_data_size);
10355 g_print ("VTable data size: %ld\n", mono_stats.class_vtable_size);
10357 g_print ("\nGeneric instances: %ld\n", mono_stats.generic_instance_count);
10358 g_print ("Initialized classes: %ld\n", mono_stats.generic_class_count);
10359 g_print ("Inflated methods: %ld / %ld\n", mono_stats.inflated_method_count_2,
10360 mono_stats.inflated_method_count);
10361 g_print ("Inflated types: %ld\n", mono_stats.inflated_type_count);
10362 g_print ("Generics metadata size: %ld\n", mono_stats.generics_metadata_size);
10364 if (mono_use_security_manager) {
10365 g_print ("\nDecl security check : %ld\n", mono_jit_stats.cas_declsec_check);
10366 g_print ("LinkDemand (user) : %ld\n", mono_jit_stats.cas_linkdemand);
10367 g_print ("LinkDemand (icall) : %ld\n", mono_jit_stats.cas_linkdemand_icall);
10368 g_print ("LinkDemand (pinvoke) : %ld\n", mono_jit_stats.cas_linkdemand_pinvoke);
10369 g_print ("LinkDemand (aptc) : %ld\n", mono_jit_stats.cas_linkdemand_aptc);
10370 g_print ("Demand (code gen) : %ld\n", mono_jit_stats.cas_demand_generation);
10372 if (debug_options.collect_pagefault_stats)
10373 g_print ("Metadata pagefaults : %d\n", mono_raw_buffer_get_n_pagefaults ());
10378 mini_cleanup (MonoDomain *domain)
10380 #ifdef HAVE_LINUX_RTC_H
10382 enable_rtc_timer (FALSE);
10386 * mono_runtime_cleanup() and mono_domain_finalize () need to
10387 * be called early since they need the execution engine still
10388 * fully working (mono_domain_finalize may invoke managed finalizers
10389 * and mono_runtime_cleanup will wait for other threads to finish).
10391 mono_domain_finalize (domain, 2000);
10393 mono_runtime_cleanup (domain);
10395 mono_profiler_shutdown ();
10397 mono_debug_cleanup ();
10399 mono_icall_cleanup ();
10401 #ifdef PLATFORM_WIN32
10402 win32_seh_cleanup();
10405 mono_domain_free (domain, TRUE);
10407 mono_code_manager_destroy (global_codeman);
10408 g_hash_table_destroy (jit_icall_name_hash);
10409 if (class_init_hash_addr)
10410 g_hash_table_destroy (class_init_hash_addr);
10412 print_jit_stats ();
10416 mono_set_defaults (int verbose_level, guint32 opts)
10418 mini_verbose = verbose_level;
10419 default_opt = opts;
10423 mono_precompile_assembly (MonoAssembly *ass, void *user_data)
10425 GHashTable *assemblies = (GHashTable*)user_data;
10426 MonoImage *image = mono_assembly_get_image (ass);
10427 MonoMethod *method, *invoke;
10430 if (g_hash_table_lookup (assemblies, ass))
10433 g_hash_table_insert (assemblies, ass, ass);
10435 if (mini_verbose > 0)
10436 printf ("PRECOMPILE: %s.\n", mono_image_get_filename (image));
10438 for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_METHOD); ++i) {
10439 method = mono_get_method (image, MONO_TOKEN_METHOD_DEF | (i + 1), NULL);
10440 if (method->flags & METHOD_ATTRIBUTE_ABSTRACT)
10444 if (mini_verbose > 1) {
10445 char * desc = mono_method_full_name (method, TRUE);
10446 g_print ("Compiling %d %s\n", count, desc);
10449 mono_compile_method (method);
10450 if (strcmp (method->name, "Finalize") == 0) {
10451 invoke = mono_marshal_get_runtime_invoke (method);
10452 mono_compile_method (invoke);
10454 if (method->klass->marshalbyref && mono_method_signature (method)->hasthis) {
10455 invoke = mono_marshal_get_remoting_invoke_with_check (method);
10456 mono_compile_method (invoke);
10460 /* Load and precompile referenced assemblies as well */
10461 for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_ASSEMBLYREF); ++i) {
10462 mono_assembly_load_reference (image, i);
10463 if (image->references [i])
10464 mono_precompile_assembly (image->references [i], assemblies);
10468 void mono_precompile_assemblies ()
10470 GHashTable *assemblies = g_hash_table_new (NULL, NULL);
10472 mono_assembly_foreach ((GFunc)mono_precompile_assembly, assemblies);
10474 g_hash_table_destroy (assemblies);