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.
16 #ifdef sun // Solaris x86
17 #include <sys/types.h>
18 #include <sys/ucontext.h>
21 #ifdef HAVE_VALGRIND_MEMCHECK_H
22 #include <valgrind/memcheck.h>
25 #include <mono/metadata/assembly.h>
26 #include <mono/metadata/loader.h>
27 #include <mono/metadata/cil-coff.h>
28 #include <mono/metadata/tabledefs.h>
29 #include <mono/metadata/class.h>
30 #include <mono/metadata/object.h>
31 #include <mono/metadata/exception.h>
32 #include <mono/metadata/opcodes.h>
33 #include <mono/metadata/mono-endian.h>
34 #include <mono/metadata/tokentype.h>
35 #include <mono/metadata/tabledefs.h>
36 #include <mono/metadata/threads.h>
37 #include <mono/metadata/marshal.h>
38 #include <mono/metadata/socket-io.h>
39 #include <mono/metadata/appdomain.h>
40 #include <mono/metadata/debug-helpers.h>
41 #include <mono/io-layer/io-layer.h>
42 #include "mono/metadata/profiler.h"
43 #include <mono/metadata/profiler-private.h>
44 #include <mono/metadata/mono-config.h>
45 #include <mono/metadata/environment.h>
46 #include <mono/metadata/mono-debug.h>
47 #include <mono/metadata/mono-debug-debugger.h>
48 #include <mono/metadata/monitor.h>
56 #include "jit-icalls.c"
59 * this is used to determine when some branch optimizations are possible: we exclude FP compares
60 * because they have weird semantics with NaNs.
62 #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))
63 #define MONO_IS_COND_BRANCH_NOFP(ins) (MONO_IS_COND_BRANCH_OP(ins) && (ins)->inst_left->inst_left->type != STACK_R8)
65 #define MONO_CHECK_THIS(ins) (cfg->method->signature->hasthis && (ins)->ssa_op == MONO_SSA_LOAD && (ins)->inst_left->inst_c0 == 0)
67 gboolean mono_arch_print_tree(MonoInst *tree, int arity);
68 static gpointer mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt);
69 static gpointer mono_jit_compile_method (MonoMethod *method);
70 static gpointer mono_jit_find_compiled_method (MonoDomain *domain, MonoMethod *method);
72 static void handle_stobj (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *dest, MonoInst *src,
73 const unsigned char *ip, MonoClass *klass, gboolean to_end, gboolean native);
75 static void dec_foreach (MonoInst *tree, MonoCompile *cfg);
77 static int mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock,
78 int locals_offset, MonoInst *return_var, GList *dont_inline, MonoInst **inline_args,
79 guint inline_offset, gboolean is_virtual_call);
81 extern guint8 mono_burg_arity [];
82 /* helper methods signature */
83 static MonoMethodSignature *helper_sig_long_long_long = NULL;
84 static MonoMethodSignature *helper_sig_long_long_int = NULL;
85 static MonoMethodSignature *helper_sig_newarr = NULL;
86 static MonoMethodSignature *helper_sig_newarr_specific = NULL;
87 static MonoMethodSignature *helper_sig_ldstr = NULL;
88 static MonoMethodSignature *helper_sig_domain_get = NULL;
89 static MonoMethodSignature *helper_sig_object_new = NULL;
90 static MonoMethodSignature *helper_sig_object_new_specific = NULL;
91 static MonoMethodSignature *helper_sig_compile = NULL;
92 static MonoMethodSignature *helper_sig_compile_virt = NULL;
93 static MonoMethodSignature *helper_sig_obj_ptr = NULL;
94 static MonoMethodSignature *helper_sig_obj_ptr_ptr = NULL;
95 static MonoMethodSignature *helper_sig_obj_obj_ptr_ptr = NULL;
96 static MonoMethodSignature *helper_sig_obj_void = NULL;
97 static MonoMethodSignature *helper_sig_ptr_void = NULL;
98 static MonoMethodSignature *helper_sig_void_void = NULL;
99 static MonoMethodSignature *helper_sig_void_ptr = NULL;
100 static MonoMethodSignature *helper_sig_void_obj = NULL;
101 static MonoMethodSignature *helper_sig_void_obj_ptr_int = NULL;
102 static MonoMethodSignature *helper_sig_void_obj_ptr_ptr_obj = NULL;
103 static MonoMethodSignature *helper_sig_void_ptr_ptr = NULL;
104 static MonoMethodSignature *helper_sig_void_ptr_ptr_ptr = NULL;
105 static MonoMethodSignature *helper_sig_ptr_ptr_ptr = NULL;
106 static MonoMethodSignature *helper_sig_ptr_obj = NULL;
107 static MonoMethodSignature *helper_sig_ptr_obj_int = NULL;
108 static MonoMethodSignature *helper_sig_ptr_int = NULL;
109 static MonoMethodSignature *helper_sig_initobj = NULL;
110 static MonoMethodSignature *helper_sig_memcpy = NULL;
111 static MonoMethodSignature *helper_sig_memset = NULL;
112 static MonoMethodSignature *helper_sig_ulong_double = NULL;
113 static MonoMethodSignature *helper_sig_long_double = NULL;
114 static MonoMethodSignature *helper_sig_double_long = NULL;
115 static MonoMethodSignature *helper_sig_double_int = NULL;
116 static MonoMethodSignature *helper_sig_float_long = NULL;
117 static MonoMethodSignature *helper_sig_double_double_double = NULL;
118 static MonoMethodSignature *helper_sig_uint_double = NULL;
119 static MonoMethodSignature *helper_sig_int_double = NULL;
120 static MonoMethodSignature *helper_sig_stelem_ref = NULL;
121 static MonoMethodSignature *helper_sig_stelem_ref_check = NULL;
122 static MonoMethodSignature *helper_sig_class_init_trampoline = NULL;
124 static guint32 default_opt = MONO_OPT_PEEPHOLE;
126 guint32 mono_jit_tls_id = -1;
127 MonoTraceSpec *mono_jit_trace_calls = NULL;
128 gboolean mono_break_on_exc = FALSE;
129 gboolean mono_compile_aot = FALSE;
131 static int mini_verbose = 0;
133 static CRITICAL_SECTION trampoline_hash_mutex;
135 static GHashTable *class_init_hash_addr = NULL;
137 static GHashTable *jump_trampoline_hash = NULL;
140 mono_running_on_valgrind (void)
142 #ifdef HAVE_VALGRIND_MEMCHECK_H
143 if (RUNNING_ON_VALGRIND)
153 G_GNUC_UNUSED static void
154 print_method_from_ip (void *ip)
159 MonoDomain *domain = mono_domain_get ();
161 ji = mono_jit_info_table_find (domain, ip);
163 g_print ("No method at %p\n", ip);
166 method = mono_method_full_name (ji->method, TRUE);
167 source = mono_debug_source_location_from_address (ji->method, (int) ip, NULL, domain);
169 g_print ("IP %p at offset 0x%x of method %s (%p %p)\n", ip, (char*)ip - (char*)ji->code_start, method, ji->code_start, (char*)ji->code_start + ji->code_size);
172 g_print ("%s\n", source);
180 mono_print_method_from_ip (void *ip)
182 print_method_from_ip (ip);
186 * mono_method_same_domain:
188 * Determine whenever two compiled methods are in the same domain, thus
189 * the address of the callee can be embedded in the caller.
191 gboolean mono_method_same_domain (MonoJitInfo *caller, MonoJitInfo *callee)
193 if (!caller || !callee)
197 * If the call was made from domain-neutral to domain-specific
198 * code, we can't patch the call site.
200 if (caller->domain_neutral && !callee->domain_neutral)
203 if ((caller->method->klass == mono_defaults.appdomain_class) &&
204 (strstr (caller->method->name, "InvokeInDomain"))) {
205 /* The InvokeInDomain methods change the current appdomain */
213 mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
215 MonoJumpInfoToken *res = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoToken));
222 #define MONO_INIT_VARINFO(vi,id) do { \
223 (vi)->range.first_use.pos.bid = 0xffff; \
229 * Basic blocks have two numeric identifiers:
230 * dfn: Depth First Number
231 * block_num: unique ID assigned at bblock creation
233 #define NEW_BBLOCK(cfg) (mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock)))
234 #define ADD_BBLOCK(cfg,bbhash,b) do { \
235 g_hash_table_insert (bbhash, (b)->cil_code, (b)); \
236 (b)->block_num = cfg->num_bblocks++; \
237 (b)->real_offset = real_offset; \
240 #define GET_BBLOCK(cfg,bbhash,tblock,ip) do { \
241 (tblock) = g_hash_table_lookup (bbhash, (ip)); \
243 if ((ip) >= end || (ip) < header->code) goto unverified; \
244 (tblock) = NEW_BBLOCK (cfg); \
245 (tblock)->cil_code = (ip); \
246 ADD_BBLOCK (cfg, (bbhash), (tblock)); \
250 #define CHECK_BBLOCK(target,ip,tblock) do { \
251 if ((target) < (ip) && !(tblock)->code) { \
252 bb_recheck = g_list_prepend (bb_recheck, (tblock)); \
253 if (cfg->verbose_level > 2) g_print ("queued block %d for check at IL%04x from IL%04x\n", (tblock)->block_num, (target) - header->code, (ip) - header->code); \
257 #define NEW_ICONST(cfg,dest,val) do { \
258 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
259 (dest)->opcode = OP_ICONST; \
260 (dest)->inst_c0 = (val); \
261 (dest)->type = STACK_I4; \
264 #if SIZEOF_VOID_P == 8
265 #define NEW_PCONST(cfg,dest,val) do { \
266 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
267 (dest)->opcode = OP_I8CONST; \
268 (dest)->inst_p0 = (val); \
269 (dest)->type = STACK_PTR; \
272 #define NEW_PCONST(cfg,dest,val) do { \
273 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
274 (dest)->opcode = OP_ICONST; \
275 (dest)->inst_p0 = (val); \
276 (dest)->type = STACK_PTR; \
280 #if SIZEOF_VOID_P == 8
281 #define OP_PCONST OP_I8CONST
283 #define OP_PCONST OP_ICONST
286 #define NEW_CLASSCONST(cfg,dest,val) do { \
287 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
288 (dest)->opcode = mono_compile_aot ? OP_AOTCONST : OP_PCONST; \
289 (dest)->inst_p0 = (val); \
290 (dest)->inst_i1 = (gpointer)MONO_PATCH_INFO_CLASS; \
291 (dest)->type = STACK_PTR; \
294 #define NEW_IMAGECONST(cfg,dest,val) do { \
295 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
296 (dest)->opcode = mono_compile_aot ? OP_AOTCONST : OP_PCONST; \
297 (dest)->inst_p0 = (val); \
298 (dest)->inst_i1 = (gpointer)MONO_PATCH_INFO_IMAGE; \
299 (dest)->type = STACK_PTR; \
302 #define NEW_FIELDCONST(cfg,dest,field) do { \
303 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
304 (dest)->opcode = mono_compile_aot ? OP_AOTCONST : OP_PCONST; \
305 (dest)->inst_p0 = (field); \
306 (dest)->inst_i1 = (gpointer)MONO_PATCH_INFO_FIELD; \
307 (dest)->type = STACK_PTR; \
310 #define NEW_METHODCONST(cfg,dest,val) do { \
311 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
312 (dest)->opcode = mono_compile_aot ? OP_AOTCONST : OP_PCONST; \
313 (dest)->inst_p0 = (val); \
314 (dest)->inst_i1 = (gpointer)MONO_PATCH_INFO_METHODCONST; \
315 (dest)->type = STACK_PTR; \
318 #define NEW_VTABLECONST(cfg,dest,vtable) do { \
319 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
320 (dest)->opcode = mono_compile_aot ? OP_AOTCONST : OP_PCONST; \
321 (dest)->inst_p0 = mono_compile_aot ? (gpointer)((vtable)->klass) : (vtable); \
322 (dest)->inst_i1 = (gpointer)MONO_PATCH_INFO_VTABLE; \
323 (dest)->type = STACK_PTR; \
326 #define NEW_SFLDACONST(cfg,dest,field) do { \
327 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
328 (dest)->opcode = mono_compile_aot ? OP_AOTCONST : OP_PCONST; \
329 (dest)->inst_p0 = (field); \
330 (dest)->inst_i1 = (gpointer)MONO_PATCH_INFO_SFLDA; \
331 (dest)->type = STACK_PTR; \
334 #define NEW_LDSTRCONST(cfg,dest,image,token) do { \
335 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
336 (dest)->opcode = OP_AOTCONST; \
337 (dest)->inst_p0 = mono_jump_info_token_new ((cfg)->mempool, (image), (token)); \
338 (dest)->inst_i1 = (gpointer)MONO_PATCH_INFO_LDSTR; \
339 (dest)->type = STACK_OBJ; \
342 #define NEW_TYPE_FROM_HANDLE_CONST(cfg,dest,image,token) do { \
343 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
344 (dest)->opcode = OP_AOTCONST; \
345 (dest)->inst_p0 = mono_jump_info_token_new ((cfg)->mempool, (image), (token)); \
346 (dest)->inst_i1 = (gpointer)MONO_PATCH_INFO_TYPE_FROM_HANDLE; \
347 (dest)->type = STACK_OBJ; \
350 #define NEW_LDTOKENCONST(cfg,dest,image,token) do { \
351 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
352 (dest)->opcode = OP_AOTCONST; \
353 (dest)->inst_p0 = mono_jump_info_token_new ((cfg)->mempool, (image), (token)); \
354 (dest)->inst_i1 = (gpointer)MONO_PATCH_INFO_LDTOKEN; \
355 (dest)->type = STACK_PTR; \
358 #define NEW_DOMAINCONST(cfg,dest) do { \
359 if (cfg->opt & MONO_OPT_SHARED) { \
360 NEW_TEMPLOAD (cfg, dest, mono_get_domainvar (cfg)->inst_c0); \
362 NEW_PCONST (cfg, dest, (cfg)->domain); \
366 #define GET_VARINFO_INST(cfg,num) ((cfg)->varinfo [(num)]->inst)
368 #define NEW_ARGLOAD(cfg,dest,num) do { \
369 if (arg_array [(num)]->opcode == OP_ICONST) (dest) = arg_array [(num)]; else { \
370 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
371 (dest)->ssa_op = MONO_SSA_LOAD; \
372 (dest)->inst_i0 = arg_array [(num)]; \
373 (dest)->opcode = mono_type_to_ldind ((dest)->inst_i0->inst_vtype); \
374 type_to_eval_stack_type (param_types [(num)], (dest)); \
375 (dest)->klass = (dest)->inst_i0->klass; \
378 #define NEW_LOCLOAD(cfg,dest,num) do { \
379 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
380 (dest)->ssa_op = MONO_SSA_LOAD; \
381 (dest)->inst_i0 = (cfg)->varinfo [locals_offset + (num)]; \
382 (dest)->opcode = mono_type_to_ldind ((dest)->inst_i0->inst_vtype); \
383 type_to_eval_stack_type (header->locals [(num)], (dest)); \
384 (dest)->klass = (dest)->inst_i0->klass; \
387 #define NEW_LOCLOADA(cfg,dest,num) do { \
388 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
389 (dest)->ssa_op = MONO_SSA_MAYBE_LOAD; \
390 (dest)->inst_i0 = (cfg)->varinfo [locals_offset + (num)]; \
391 (dest)->inst_i0->flags |= MONO_INST_INDIRECT; \
392 (dest)->opcode = OP_LDADDR; \
393 (dest)->type = STACK_MP; \
394 (dest)->klass = (dest)->inst_i0->klass; \
395 if (!MONO_TYPE_ISSTRUCT (header->locals [(num)])) \
396 (cfg)->disable_ssa = TRUE; \
399 #define NEW_RETLOADA(cfg,dest) do { \
400 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
401 (dest)->ssa_op = MONO_SSA_MAYBE_LOAD; \
402 (dest)->inst_i0 = (cfg)->ret; \
403 (dest)->inst_i0->flags |= MONO_INST_INDIRECT; \
404 (dest)->opcode = CEE_LDIND_I; \
405 (dest)->type = STACK_MP; \
406 (dest)->klass = (dest)->inst_i0->klass; \
407 (cfg)->disable_ssa = TRUE; \
410 #define NEW_ARGLOADA(cfg,dest,num) do { \
411 if (arg_array [(num)]->opcode == OP_ICONST) goto inline_failure; \
412 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
413 (dest)->ssa_op = MONO_SSA_MAYBE_LOAD; \
414 (dest)->inst_i0 = arg_array [(num)]; \
415 (dest)->inst_i0->flags |= MONO_INST_INDIRECT; \
416 (dest)->opcode = OP_LDADDR; \
417 (dest)->type = STACK_MP; \
418 (dest)->klass = (dest)->inst_i0->klass; \
419 (cfg)->disable_ssa = TRUE; \
422 #define NEW_TEMPLOAD(cfg,dest,num) do { \
423 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
424 (dest)->ssa_op = MONO_SSA_LOAD; \
425 (dest)->inst_i0 = (cfg)->varinfo [(num)]; \
426 (dest)->opcode = mono_type_to_ldind ((dest)->inst_i0->inst_vtype); \
427 type_to_eval_stack_type ((dest)->inst_i0->inst_vtype, (dest)); \
428 (dest)->klass = (dest)->inst_i0->klass; \
431 #define NEW_TEMPLOADA(cfg,dest,num) do { \
432 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
433 (dest)->ssa_op = MONO_SSA_MAYBE_LOAD; \
434 (dest)->inst_i0 = (cfg)->varinfo [(num)]; \
435 (dest)->inst_i0->flags |= MONO_INST_INDIRECT; \
436 (dest)->opcode = OP_LDADDR; \
437 (dest)->type = STACK_MP; \
438 (dest)->klass = (dest)->inst_i0->klass; \
439 if (!MONO_TYPE_ISSTRUCT (cfg->varinfo [(num)]->inst_vtype)) \
440 (cfg)->disable_ssa = TRUE; \
444 #define NEW_INDLOAD(cfg,dest,addr,vtype) do { \
445 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
446 (dest)->inst_left = addr; \
447 (dest)->opcode = mono_type_to_ldind (vtype); \
448 type_to_eval_stack_type (vtype, (dest)); \
449 /* FIXME: (dest)->klass = (dest)->inst_i0->klass;*/ \
452 #define NEW_INDSTORE(cfg,dest,addr,value,vtype) do { \
453 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
454 (dest)->inst_i0 = addr; \
455 (dest)->opcode = mono_type_to_stind (vtype); \
456 (dest)->inst_i1 = (value); \
457 /* FIXME: (dest)->klass = (dest)->inst_i0->klass;*/ \
460 #define NEW_TEMPSTORE(cfg,dest,num,inst) do { \
461 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
462 (dest)->ssa_op = MONO_SSA_STORE; \
463 (dest)->inst_i0 = (cfg)->varinfo [(num)]; \
464 (dest)->opcode = mono_type_to_stind ((dest)->inst_i0->inst_vtype); \
465 (dest)->inst_i1 = (inst); \
466 (dest)->klass = (dest)->inst_i0->klass; \
469 #define NEW_LOCSTORE(cfg,dest,num,inst) do { \
470 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
471 (dest)->opcode = mono_type_to_stind (header->locals [(num)]); \
472 (dest)->ssa_op = MONO_SSA_STORE; \
473 (dest)->inst_i0 = (cfg)->varinfo [locals_offset + (num)]; \
474 (dest)->inst_i1 = (inst); \
475 (dest)->klass = (dest)->inst_i0->klass; \
478 #define NEW_ARGSTORE(cfg,dest,num,inst) do { \
479 if (arg_array [(num)]->opcode == OP_ICONST) goto inline_failure; \
480 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
481 (dest)->opcode = mono_type_to_stind (param_types [(num)]); \
482 (dest)->ssa_op = MONO_SSA_STORE; \
483 (dest)->inst_i0 = arg_array [(num)]; \
484 (dest)->inst_i1 = (inst); \
485 (dest)->klass = (dest)->inst_i0->klass; \
488 #define ADD_BINOP(op) do { \
489 MONO_INST_NEW (cfg, ins, (op)); \
490 ins->cil_code = ip; \
492 ins->inst_i0 = sp [0]; \
493 ins->inst_i1 = sp [1]; \
495 type_from_op (ins); \
499 #define ADD_UNOP(op) do { \
500 MONO_INST_NEW (cfg, ins, (op)); \
501 ins->cil_code = ip; \
503 ins->inst_i0 = sp [0]; \
505 type_from_op (ins); \
509 #define ADD_BINCOND(next_block) do { \
512 MONO_INST_NEW(cfg, cmp, OP_COMPARE); \
513 cmp->inst_i0 = sp [0]; \
514 cmp->inst_i1 = sp [1]; \
515 cmp->cil_code = ins->cil_code; \
516 type_from_op (cmp); \
518 ins->inst_i0 = cmp; \
519 MONO_ADD_INS (bblock, ins); \
520 ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2); \
521 GET_BBLOCK (cfg, bbhash, tblock, target); \
522 link_bblock (cfg, bblock, tblock); \
523 ins->inst_true_bb = tblock; \
524 CHECK_BBLOCK (target, ip, tblock); \
525 if ((next_block)) { \
526 link_bblock (cfg, bblock, (next_block)); \
527 ins->inst_false_bb = (next_block); \
528 start_new_bblock = 1; \
530 GET_BBLOCK (cfg, bbhash, tblock, ip); \
531 link_bblock (cfg, bblock, tblock); \
532 ins->inst_false_bb = tblock; \
533 start_new_bblock = 2; \
537 /* FIXME: handle float, long ... */
538 #define ADD_UNCOND(istrue) do { \
541 MONO_INST_NEW(cfg, cmp, OP_COMPARE); \
542 cmp->inst_i0 = sp [0]; \
543 switch (cmp->inst_i0->type) { \
545 cmp->inst_i1 = zero_int64; break; \
547 cmp->inst_i1 = zero_r8; break; \
550 cmp->inst_i1 = zero_ptr; break; \
552 cmp->inst_i1 = zero_obj; break; \
554 cmp->inst_i1 = zero_int32; \
556 cmp->cil_code = ins->cil_code; \
557 type_from_op (cmp); \
559 ins->inst_i0 = cmp; \
560 ins->opcode = (istrue)? CEE_BNE_UN: CEE_BEQ; \
561 MONO_ADD_INS (bblock, ins); \
562 ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2); \
563 GET_BBLOCK (cfg, bbhash, tblock, target); \
564 link_bblock (cfg, bblock, tblock); \
565 ins->inst_true_bb = tblock; \
566 CHECK_BBLOCK (target, ip, tblock); \
567 GET_BBLOCK (cfg, bbhash, tblock, ip); \
568 link_bblock (cfg, bblock, tblock); \
569 ins->inst_false_bb = tblock; \
570 start_new_bblock = 2; \
573 #define NEW_LDELEMA(cfg,dest,sp,k) do { \
574 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
575 (dest)->opcode = CEE_LDELEMA; \
576 (dest)->inst_left = (sp) [0]; \
577 (dest)->inst_right = (sp) [1]; \
578 (dest)->type = STACK_MP; \
579 (dest)->klass = (k); \
580 (cfg)->flags |= MONO_CFG_HAS_LDELEMA; \
583 #define NEW_GROUP(cfg,dest,el1,el2) do { \
584 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
585 (dest)->opcode = OP_GROUP; \
586 (dest)->inst_left = (el1); \
587 (dest)->inst_right = (el2); \
592 compare_bblock (gconstpointer a, gconstpointer b)
594 const MonoBasicBlock *b1 = a;
595 const MonoBasicBlock *b2 = b;
597 return b2->cil_code - b1->cil_code;
602 * link_bblock: Links two basic blocks
604 * links two basic blocks in the control flow graph, the 'from'
605 * argument is the starting block and the 'to' argument is the block
606 * the control flow ends to after 'from'.
609 link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
611 MonoBasicBlock **newa;
615 if (from->cil_code) {
617 g_print ("edge from IL%04x to IL_%04x\n", from->cil_code - cfg->cil_code, to->cil_code - cfg->cil_code);
619 g_print ("edge from IL%04x to exit\n", from->cil_code - cfg->cil_code);
622 g_print ("edge from entry to IL_%04x\n", to->cil_code - cfg->cil_code);
624 g_print ("edge from entry to exit\n");
628 for (i = 0; i < from->out_count; ++i) {
629 if (to == from->out_bb [i]) {
635 newa = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (from->out_count + 1));
636 for (i = 0; i < from->out_count; ++i) {
637 newa [i] = from->out_bb [i];
645 for (i = 0; i < to->in_count; ++i) {
646 if (from == to->in_bb [i]) {
652 newa = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (to->in_count + 1));
653 for (i = 0; i < to->in_count; ++i) {
654 newa [i] = to->in_bb [i];
663 * mono_find_block_region:
665 * We mark each basic block with a region ID. We use that to avoid BB
666 * optimizations when blocks are in different regions.
669 * A region token that encodes where this region is, and information
670 * about the clause owner for this block.
672 * The region encodes the try/catch/filter clause that owns this block
673 * as well as the type. -1 is a special value that represents a block
674 * that is in none of try/catch/filter.
677 mono_find_block_region (MonoCompile *cfg, int offset, int *filter_lengths)
679 MonoMethod *method = cfg->method;
680 MonoMethodHeader *header = ((MonoMethodNormal *)method)->header;
681 MonoExceptionClause *clause;
684 /* first search for handlers and filters */
685 for (i = 0; i < header->num_clauses; ++i) {
686 clause = &header->clauses [i];
687 if ((clause->flags & MONO_EXCEPTION_CLAUSE_FILTER) && (offset >= clause->token_or_filter) &&
688 (offset < (clause->token_or_filter + filter_lengths [i])))
689 return ((i + 1) << 8) | MONO_REGION_FILTER | clause->flags;
691 if (MONO_OFFSET_IN_HANDLER (clause, offset)) {
692 if (clause->flags & MONO_EXCEPTION_CLAUSE_FINALLY)
693 return ((i + 1) << 8) | MONO_REGION_FINALLY | clause->flags;
695 return ((i + 1) << 8) | MONO_REGION_CATCH | clause->flags;
699 /* search the try blocks */
700 for (i = 0; i < header->num_clauses; ++i) {
701 clause = &header->clauses [i];
702 if (MONO_OFFSET_IN_CLAUSE (clause, offset))
703 return ((i + 1) << 8) | clause->flags;
710 mono_find_final_block (MonoCompile *cfg, unsigned char *ip, unsigned char *target, int type)
712 MonoMethod *method = cfg->method;
713 MonoMethodHeader *header = ((MonoMethodNormal *)method)->header;
714 MonoExceptionClause *clause;
715 MonoBasicBlock *handler;
719 for (i = 0; i < header->num_clauses; ++i) {
720 clause = &header->clauses [i];
721 if (MONO_OFFSET_IN_CLAUSE (clause, (ip - header->code)) &&
722 (!MONO_OFFSET_IN_CLAUSE (clause, (target - header->code)))) {
723 if (clause->flags == type) {
724 handler = g_hash_table_lookup (cfg->bb_hash, header->code + clause->handler_offset);
726 res = g_list_append (res, handler);
734 mono_find_spvar_for_region (MonoCompile *cfg, int region)
736 return g_hash_table_lookup (cfg->spvars, GINT_TO_POINTER (region));
740 mono_create_spvar_for_region (MonoCompile *cfg, int region)
744 var = g_hash_table_lookup (cfg->spvars, GINT_TO_POINTER (region));
748 var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
749 /* prevent it from being register allocated */
750 var->flags |= MONO_INST_INDIRECT;
752 g_hash_table_insert (cfg->spvars, GINT_TO_POINTER (region), var);
756 df_visit (MonoBasicBlock *start, int *dfn, MonoBasicBlock **array)
760 array [*dfn] = start;
761 /*g_print ("visit %d at %p\n", *dfn, start->cil_code);*/
762 for (i = 0; i < start->out_count; ++i) {
763 if (start->out_bb [i]->dfn)
766 start->out_bb [i]->dfn = *dfn;
767 start->out_bb [i]->df_parent = start;
768 array [*dfn] = start->out_bb [i];
769 df_visit (start->out_bb [i], dfn, array);
775 MonoBasicBlock *best;
779 previous_foreach (gconstpointer key, gpointer val, gpointer data)
781 PrevStruct *p = data;
782 MonoBasicBlock *bb = val;
783 //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,
784 //bb->method == p->best->method, bb->cil_code < p->code, bb->cil_code > p->best->cil_code);
786 if (bb->cil_code && bb->cil_code < p->code && bb->cil_code > p->best->cil_code)
790 static MonoBasicBlock*
791 find_previous (GHashTable *bb_hash, MonoBasicBlock *start, const guchar *code) {
797 g_hash_table_foreach (bb_hash, (GHFunc)previous_foreach, &p);
802 split_bblock (MonoCompile *cfg, MonoBasicBlock *first, MonoBasicBlock *second) {
811 * FIXME: take into account all the details:
812 * second may have been the target of more than one bblock
814 second->out_count = first->out_count;
815 second->out_bb = first->out_bb;
817 for (i = 0; i < first->out_count; ++i) {
818 bb = first->out_bb [i];
819 for (j = 0; j < bb->in_count; ++j) {
820 if (bb->in_bb [j] == first)
821 bb->in_bb [j] = second;
825 first->out_count = 0;
826 first->out_bb = NULL;
827 link_bblock (cfg, first, second);
829 second->last_ins = first->last_ins;
831 /*g_print ("start search at %p for %p\n", first->cil_code, second->cil_code);*/
832 for (inst = first->code; inst && inst->next; inst = inst->next) {
833 /*char *code = mono_disasm_code_one (NULL, cfg->method, inst->next->cil_code, NULL);
834 g_print ("found %p: %s", inst->next->cil_code, code);
836 if (inst->cil_code < second->cil_code && inst->next->cil_code >= second->cil_code) {
837 second->code = inst->next;
839 first->last_ins = inst;
840 second->next_bb = first->next_bb;
841 first->next_bb = second;
846 g_warning ("bblock split failed in %s::%s\n", cfg->method->klass->name, cfg->method->name);
852 mono_type_to_ldind (MonoType *type)
864 case MONO_TYPE_BOOLEAN:
878 case MONO_TYPE_FNPTR:
880 case MONO_TYPE_CLASS:
881 case MONO_TYPE_STRING:
882 case MONO_TYPE_OBJECT:
883 case MONO_TYPE_SZARRAY:
884 case MONO_TYPE_ARRAY:
885 return CEE_LDIND_REF;
893 case MONO_TYPE_VALUETYPE:
894 if (type->data.klass->enumtype) {
895 t = type->data.klass->enum_basetype->type;
899 case MONO_TYPE_TYPEDBYREF:
901 case MONO_TYPE_GENERICINST:
902 if (type->data.generic_inst->generic_type->type == MONO_TYPE_VALUETYPE)
904 return CEE_LDIND_REF;
906 g_error ("unknown type 0x%02x in type_to_ldind", type->type);
912 mono_type_to_stind (MonoType *type)
923 case MONO_TYPE_BOOLEAN:
935 case MONO_TYPE_FNPTR:
937 case MONO_TYPE_CLASS:
938 case MONO_TYPE_STRING:
939 case MONO_TYPE_OBJECT:
940 case MONO_TYPE_SZARRAY:
941 case MONO_TYPE_ARRAY:
942 return CEE_STIND_REF;
950 case MONO_TYPE_VALUETYPE:
951 if (type->data.klass->enumtype) {
952 t = type->data.klass->enum_basetype->type;
956 case MONO_TYPE_TYPEDBYREF:
958 case MONO_TYPE_GENERICINST:
959 if (type->data.generic_inst->generic_type->type == MONO_TYPE_VALUETYPE)
961 return CEE_STIND_REF;
963 g_error ("unknown type 0x%02x in type_to_stind", type->type);
969 * Returns the type used in the eval stack when @type is loaded.
970 * FIXME: return a MonoType/MonoClass for the byref and VALUETYPE cases.
973 type_to_eval_stack_type (MonoType *type, MonoInst *inst) {
977 inst->type = STACK_MP;
985 case MONO_TYPE_BOOLEAN:
991 inst->type = STACK_I4;
996 case MONO_TYPE_FNPTR:
997 inst->type = STACK_PTR;
999 case MONO_TYPE_CLASS:
1000 case MONO_TYPE_STRING:
1001 case MONO_TYPE_OBJECT:
1002 case MONO_TYPE_SZARRAY:
1003 case MONO_TYPE_ARRAY:
1004 inst->type = STACK_OBJ;
1008 inst->type = STACK_I8;
1012 inst->type = STACK_R8;
1014 case MONO_TYPE_VALUETYPE:
1015 if (type->data.klass->enumtype) {
1016 t = type->data.klass->enum_basetype->type;
1019 inst->klass = type->data.klass;
1020 inst->type = STACK_VTYPE;
1023 case MONO_TYPE_TYPEDBYREF:
1024 inst->klass = mono_defaults.typed_reference_class;
1025 inst->type = STACK_VTYPE;
1027 case MONO_TYPE_GENERICINST:
1028 if (type->data.generic_inst->generic_type->type == MONO_TYPE_VALUETYPE) {
1029 inst->klass = mono_class_from_mono_type (type);
1030 inst->type = STACK_VTYPE;
1032 inst->type = STACK_OBJ;
1036 g_error ("unknown type 0x%02x in eval stack type", type->type);
1041 * The following tables are used to quickly validate the IL code in type_from_op ().
1044 bin_num_table [STACK_MAX] [STACK_MAX] = {
1045 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1046 {STACK_INV, STACK_I4, STACK_INV, STACK_PTR, STACK_INV, STACK_MP, STACK_INV, STACK_INV},
1047 {STACK_INV, STACK_INV, STACK_I8, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1048 {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_MP, STACK_INV, STACK_INV},
1049 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_R8, STACK_INV, STACK_INV, STACK_INV},
1050 {STACK_INV, STACK_MP, STACK_INV, STACK_MP, STACK_INV, STACK_PTR, STACK_INV, STACK_INV},
1051 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1052 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
1057 STACK_INV, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_INV, STACK_INV, STACK_INV
1060 /* reduce the size of this table */
1062 bin_int_table [STACK_MAX] [STACK_MAX] = {
1063 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1064 {STACK_INV, STACK_I4, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1065 {STACK_INV, STACK_INV, STACK_I8, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1066 {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1067 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1068 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1069 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1070 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
1074 bin_comp_table [STACK_MAX] [STACK_MAX] = {
1076 {0, 1, 0, 1, 0, 0, 4, 0},
1077 {0, 0, 1, 0, 0, 0, 0, 0},
1078 {0, 1, 0, 1, 0, 2, 4, 0},
1079 {0, 0, 0, 0, 1, 0, 0, 0},
1080 {0, 0, 0, 2, 0, 1, 0, 0},
1081 {0, 4, 0, 4, 0, 0, 3, 0},
1082 {0, 0, 0, 0, 0, 0, 0, 0},
1085 /* reduce the size of this table */
1087 shift_table [STACK_MAX] [STACK_MAX] = {
1088 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1089 {STACK_INV, STACK_I4, STACK_INV, STACK_I4, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1090 {STACK_INV, STACK_I8, STACK_INV, STACK_I8, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1091 {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1092 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1093 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1094 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1095 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
1099 * Tables to map from the non-specific opcode to the matching
1100 * type-specific opcode.
1102 /* handles from CEE_ADD to CEE_SHR_UN (CEE_REM_UN for floats) */
1103 static const guint16
1104 binops_op_map [STACK_MAX] = {
1105 0, 0, OP_LADD-CEE_ADD, OP_PADD-CEE_ADD, OP_FADD-CEE_ADD, OP_PADD-CEE_ADD
1108 /* handles from CEE_NEG to CEE_CONV_U8 */
1109 static const guint16
1110 unops_op_map [STACK_MAX] = {
1111 0, 0, OP_LNEG-CEE_NEG, OP_PNEG-CEE_NEG, OP_FNEG-CEE_NEG, OP_PNEG-CEE_NEG
1114 /* handles from CEE_CONV_U2 to CEE_SUB_OVF_UN */
1115 static const guint16
1116 ovfops_op_map [STACK_MAX] = {
1117 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
1120 /* handles from CEE_CONV_OVF_I1_UN to CEE_CONV_OVF_U_UN */
1121 static const guint16
1122 ovf2ops_op_map [STACK_MAX] = {
1123 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
1126 /* handles from CEE_CONV_OVF_I1 to CEE_CONV_OVF_U8 */
1127 static const guint16
1128 ovf3ops_op_map [STACK_MAX] = {
1129 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
1132 /* handles from CEE_CEQ to CEE_CLT_UN */
1133 static const guint16
1134 ceqops_op_map [STACK_MAX] = {
1135 0, 0, OP_LCEQ-CEE_CEQ, OP_PCEQ-CEE_CEQ, OP_FCEQ-CEE_CEQ, OP_LCEQ-CEE_CEQ
1139 * Sets ins->type (the type on the eval stack) according to the
1140 * type of the opcode and the arguments to it.
1141 * Invalid IL code is marked by setting ins->type to the invalid value STACK_INV.
1143 * FIXME: this function sets ins->type unconditionally in some cases, but
1144 * it should set it to invalid for some types (a conv.x on an object)
1147 type_from_op (MonoInst *ins) {
1148 switch (ins->opcode) {
1155 /* FIXME: check unverifiable args for STACK_MP */
1156 ins->type = bin_num_table [ins->inst_i0->type] [ins->inst_i1->type];
1157 ins->opcode += binops_op_map [ins->type];
1164 ins->type = bin_int_table [ins->inst_i0->type] [ins->inst_i1->type];
1165 ins->opcode += binops_op_map [ins->type];
1170 ins->type = shift_table [ins->inst_i0->type] [ins->inst_i1->type];
1171 ins->opcode += binops_op_map [ins->type];
1175 /* FIXME: handle some specifics with ins->next->type */
1176 ins->type = bin_comp_table [ins->inst_i0->type] [ins->inst_i1->type] ? STACK_I4: STACK_INV;
1177 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))))
1178 ins->opcode = OP_LCOMPARE;
1185 ins->type = bin_comp_table [ins->inst_i0->type] [ins->inst_i1->type] ? STACK_I4: STACK_INV;
1186 ins->opcode += ceqops_op_map [ins->inst_i0->type];
1190 ins->type = neg_table [ins->inst_i0->type];
1191 ins->opcode += unops_op_map [ins->type];
1194 if (ins->inst_i0->type >= STACK_I4 && ins->inst_i0->type <= STACK_PTR)
1195 ins->type = ins->inst_i0->type;
1197 ins->type = STACK_INV;
1198 ins->opcode += unops_op_map [ins->type];
1204 ins->type = STACK_I4;
1205 ins->opcode += unops_op_map [ins->inst_i0->type];
1208 ins->type = STACK_R8;
1209 switch (ins->inst_i0->type) {
1214 ins->opcode = OP_LCONV_TO_R_UN;
1218 case CEE_CONV_OVF_I1:
1219 case CEE_CONV_OVF_U1:
1220 case CEE_CONV_OVF_I2:
1221 case CEE_CONV_OVF_U2:
1222 case CEE_CONV_OVF_I4:
1223 case CEE_CONV_OVF_U4:
1224 ins->type = STACK_I4;
1225 ins->opcode += ovf3ops_op_map [ins->inst_i0->type];
1227 case CEE_CONV_OVF_I_UN:
1228 case CEE_CONV_OVF_U_UN:
1229 ins->type = STACK_PTR;
1230 ins->opcode += ovf2ops_op_map [ins->inst_i0->type];
1232 case CEE_CONV_OVF_I1_UN:
1233 case CEE_CONV_OVF_I2_UN:
1234 case CEE_CONV_OVF_I4_UN:
1235 case CEE_CONV_OVF_U1_UN:
1236 case CEE_CONV_OVF_U2_UN:
1237 case CEE_CONV_OVF_U4_UN:
1238 ins->type = STACK_I4;
1239 ins->opcode += ovf2ops_op_map [ins->inst_i0->type];
1242 ins->type = STACK_PTR;
1243 switch (ins->inst_i0->type) {
1249 ins->opcode = OP_LCONV_TO_U;
1252 ins->opcode = OP_FCONV_TO_U;
1258 ins->type = STACK_I8;
1259 ins->opcode += unops_op_map [ins->inst_i0->type];
1261 case CEE_CONV_OVF_I8:
1262 case CEE_CONV_OVF_U8:
1263 ins->type = STACK_I8;
1264 ins->opcode += ovf3ops_op_map [ins->inst_i0->type];
1266 case CEE_CONV_OVF_U8_UN:
1267 case CEE_CONV_OVF_I8_UN:
1268 ins->type = STACK_I8;
1269 ins->opcode += ovf2ops_op_map [ins->inst_i0->type];
1273 ins->type = STACK_R8;
1274 ins->opcode += unops_op_map [ins->inst_i0->type];
1277 ins->type = STACK_R8;
1281 ins->type = STACK_I4;
1282 ins->opcode += ovfops_op_map [ins->inst_i0->type];
1285 case CEE_CONV_OVF_I:
1286 case CEE_CONV_OVF_U:
1287 ins->type = STACK_PTR;
1288 ins->opcode += ovfops_op_map [ins->inst_i0->type];
1291 case CEE_ADD_OVF_UN:
1293 case CEE_MUL_OVF_UN:
1295 case CEE_SUB_OVF_UN:
1296 ins->type = bin_num_table [ins->inst_i0->type] [ins->inst_i1->type];
1297 ins->opcode += ovfops_op_map [ins->inst_i0->type];
1300 g_error ("opcode 0x%04x not handled in type from op", ins->opcode);
1307 STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I8, STACK_MP, STACK_R8, STACK_R8, STACK_OBJ
1310 /* map ldelem.x to the matching ldind.x opcode */
1312 ldelem_to_ldind [] = {
1326 /* map stelem.x to the matching stind.x opcode */
1328 stelem_to_stind [] = {
1342 param_table [STACK_MAX] [STACK_MAX] = {
1347 check_values_to_signature (MonoInst *args, MonoType *this, MonoMethodSignature *sig) {
1351 switch (args->type) {
1361 for (i = 0; i < sig->param_count; ++i) {
1362 switch (args [i].type) {
1366 if (!sig->params [i]->byref)
1370 if (sig->params [i]->byref)
1372 switch (sig->params [i]->type) {
1373 case MONO_TYPE_CLASS:
1374 case MONO_TYPE_STRING:
1375 case MONO_TYPE_OBJECT:
1376 case MONO_TYPE_SZARRAY:
1377 case MONO_TYPE_ARRAY:
1384 if (sig->params [i]->byref)
1386 if (sig->params [i]->type != MONO_TYPE_R4 && sig->params [i]->type != MONO_TYPE_R8)
1395 /*if (!param_table [args [i].type] [sig->params [i]->type])
1403 * When we need a pointer to the current domain many times in a method, we
1404 * call mono_domain_get() once and we store the result in a local variable.
1405 * This function returns the variable that represents the MonoDomain*.
1407 inline static MonoInst *
1408 mono_get_domainvar (MonoCompile *cfg)
1410 if (!cfg->domainvar)
1411 cfg->domainvar = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1412 return cfg->domainvar;
1416 mono_compile_create_var (MonoCompile *cfg, MonoType *type, int opcode)
1419 int num = cfg->num_varinfo;
1421 if ((num + 1) >= cfg->varinfo_count) {
1422 cfg->varinfo_count = (cfg->varinfo_count + 2) * 2;
1423 cfg->varinfo = (MonoInst **)g_realloc (cfg->varinfo, sizeof (MonoInst*) * cfg->varinfo_count);
1424 cfg->vars = (MonoMethodVar **)g_realloc (cfg->vars, sizeof (MonoMethodVar*) * cfg->varinfo_count);
1427 /*g_print ("created temp %d of type 0x%x\n", num, type->type);*/
1428 mono_jit_stats.allocate_var++;
1430 MONO_INST_NEW (cfg, inst, opcode);
1431 inst->inst_c0 = num;
1432 inst->inst_vtype = type;
1433 inst->klass = mono_class_from_mono_type (type);
1434 /* if set to 1 the variable is native */
1437 cfg->varinfo [num] = inst;
1439 cfg->vars [num] = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoMethodVar));
1440 MONO_INIT_VARINFO (cfg->vars [num], num);
1443 //g_print ("created temp %d of type %s\n", num, mono_type_get_name (type));
1448 type_from_stack_type (MonoInst *ins) {
1449 switch (ins->type) {
1450 case STACK_I4: return &mono_defaults.int32_class->byval_arg;
1451 case STACK_I8: return &mono_defaults.int64_class->byval_arg;
1452 case STACK_PTR: return &mono_defaults.int_class->byval_arg;
1453 case STACK_R8: return &mono_defaults.double_class->byval_arg;
1454 case STACK_MP: return &mono_defaults.int_class->byval_arg;
1455 case STACK_OBJ: return &mono_defaults.object_class->byval_arg;
1456 case STACK_VTYPE: return &ins->klass->byval_arg;
1458 g_error ("stack type %d to montype not handled\n", ins->type);
1464 array_access_to_klass (int opcode)
1468 return mono_defaults.byte_class;
1470 return mono_defaults.uint16_class;
1473 return mono_defaults.int_class;
1476 return mono_defaults.sbyte_class;
1479 return mono_defaults.int16_class;
1482 return mono_defaults.int32_class;
1484 return mono_defaults.uint32_class;
1487 return mono_defaults.int64_class;
1490 return mono_defaults.single_class;
1493 return mono_defaults.double_class;
1494 case CEE_LDELEM_REF:
1495 case CEE_STELEM_REF:
1496 return mono_defaults.object_class;
1498 g_assert_not_reached ();
1504 mono_add_ins_to_end (MonoBasicBlock *bb, MonoInst *inst)
1508 MONO_ADD_INS (bb, inst);
1511 switch (bb->last_ins->opcode) {
1525 while (prev->next && prev->next != bb->last_ins)
1527 if (prev == bb->code) {
1528 if (bb->last_ins == bb->code) {
1529 inst->next = bb->code;
1532 inst->next = prev->next;
1536 inst->next = bb->last_ins;
1540 // g_warning ("handle conditional jump in add_ins_to_end ()\n");
1542 MONO_ADD_INS (bb, inst);
1548 mono_add_varcopy_to_end (MonoCompile *cfg, MonoBasicBlock *bb, int src, int dest)
1550 MonoInst *inst, *load;
1552 NEW_TEMPLOAD (cfg, load, src);
1554 NEW_TEMPSTORE (cfg, inst, dest, load);
1555 if (inst->opcode == CEE_STOBJ) {
1556 NEW_TEMPLOADA (cfg, inst, dest);
1557 handle_stobj (cfg, bb, inst, load, NULL, inst->klass, TRUE, FALSE);
1559 inst->cil_code = NULL;
1560 mono_add_ins_to_end (bb, inst);
1565 * We try to share variables when possible
1568 mono_compile_get_interface_var (MonoCompile *cfg, int slot, MonoInst *ins)
1573 /* inlining can result in deeper stacks */
1574 if (slot >= ((MonoMethodNormal *)cfg->method)->header->max_stack)
1575 return mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1577 pos = ins->type - 1 + slot * STACK_MAX;
1579 switch (ins->type) {
1586 if ((vnum = cfg->intvars [pos]))
1587 return cfg->varinfo [vnum];
1588 res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1589 cfg->intvars [pos] = res->inst_c0;
1592 res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1598 * This function is called to handle items that are left on the evaluation stack
1599 * at basic block boundaries. What happens is that we save the values to local variables
1600 * and we reload them later when first entering the target basic block (with the
1601 * handle_loaded_temps () function).
1602 * It is also used to handle items on the stack in store opcodes, since it is
1603 * possible that the variable to be stored into is already on the stack, in
1604 * which case its old value should be used.
1605 * A single joint point will use the same variables (stored in the array bb->out_stack or
1606 * bb->in_stack, if the basic block is before or after the joint point).
1609 handle_stack_args (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst **sp, int count) {
1611 MonoBasicBlock *outb;
1612 MonoInst *inst, **locals;
1617 if (cfg->verbose_level > 3)
1618 g_print ("%d item(s) on exit from B%d\n", count, bb->block_num);
1619 if (!bb->out_scount) {
1620 bb->out_scount = count;
1621 //g_print ("bblock %d has out:", bb->block_num);
1623 for (i = 0; i < bb->out_count; ++i) {
1624 outb = bb->out_bb [i];
1625 //g_print (" %d", outb->block_num);
1626 if (outb->in_stack) {
1628 bb->out_stack = outb->in_stack;
1634 bb->out_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * count);
1635 for (i = 0; i < count; ++i) {
1637 * try to reuse temps already allocated for this purpouse, if they occupy the same
1638 * stack slot and if they are of the same type.
1639 * This won't cause conflicts since if 'local' is used to
1640 * store one of the values in the in_stack of a bblock, then
1641 * the same variable will be used for the same outgoing stack
1643 * This doesn't work when inlining methods, since the bblocks
1644 * in the inlined methods do not inherit their in_stack from
1645 * the bblock they are inlined to. See bug #58863 for an
1648 if (cfg->inlined_method)
1649 bb->out_stack [i] = mono_compile_create_var (cfg, type_from_stack_type (sp [i]), OP_LOCAL);
1651 bb->out_stack [i] = mono_compile_get_interface_var (cfg, i, sp [i]);
1656 for (i = 0; i < bb->out_count; ++i) {
1657 outb = bb->out_bb [i];
1658 if (outb->in_scount)
1659 continue; /* check they are the same locals */
1660 outb->in_scount = count;
1661 outb->in_stack = bb->out_stack;
1664 locals = bb->out_stack;
1665 for (i = 0; i < count; ++i) {
1666 /* add store ops at the end of the bb, before the branch */
1667 NEW_TEMPSTORE (cfg, inst, locals [i]->inst_c0, sp [i]);
1668 if (inst->opcode == CEE_STOBJ) {
1669 NEW_TEMPLOADA (cfg, inst, locals [i]->inst_c0);
1670 handle_stobj (cfg, bb, inst, sp [i], sp [i]->cil_code, inst->klass, TRUE, FALSE);
1672 inst->cil_code = sp [i]->cil_code;
1673 mono_add_ins_to_end (bb, inst);
1675 if (cfg->verbose_level > 3)
1676 g_print ("storing %d to temp %d\n", i, locals [i]->inst_c0);
1680 * It is possible that the out bblocks already have in_stack assigned, and
1681 * the in_stacks differ. In this case, we will store to all the different
1688 /* Find a bblock which has a different in_stack */
1690 while (bindex < bb->out_count) {
1691 outb = bb->out_bb [bindex];
1692 if (outb->in_stack != locals) {
1694 * Instead of storing sp [i] to locals [i], we need to store
1695 * locals [i] to <new locals>[i], since the sp [i] tree can't
1696 * be shared between trees.
1698 for (i = 0; i < count; ++i)
1699 mono_add_varcopy_to_end (cfg, bb, locals [i]->inst_c0, outb->in_stack [i]->inst_c0);
1700 locals = outb->in_stack;
1712 ret_type_to_call_opcode (MonoType *type, int calli, int virt)
1717 return calli? OP_CALL_REG: virt? CEE_CALLVIRT: CEE_CALL;
1721 case MONO_TYPE_VOID:
1722 return calli? OP_VOIDCALL_REG: virt? OP_VOIDCALLVIRT: OP_VOIDCALL;
1725 case MONO_TYPE_BOOLEAN:
1728 case MONO_TYPE_CHAR:
1731 return calli? OP_CALL_REG: virt? CEE_CALLVIRT: CEE_CALL;
1735 return calli? OP_CALL_REG: virt? CEE_CALLVIRT: CEE_CALL;
1736 case MONO_TYPE_CLASS:
1737 case MONO_TYPE_STRING:
1738 case MONO_TYPE_OBJECT:
1739 case MONO_TYPE_SZARRAY:
1740 case MONO_TYPE_ARRAY:
1741 return calli? OP_CALL_REG: virt? CEE_CALLVIRT: CEE_CALL;
1744 return calli? OP_LCALL_REG: virt? OP_LCALLVIRT: OP_LCALL;
1747 return calli? OP_FCALL_REG: virt? OP_FCALLVIRT: OP_FCALL;
1748 case MONO_TYPE_VALUETYPE:
1749 if (type->data.klass->enumtype) {
1750 t = type->data.klass->enum_basetype->type;
1753 return calli? OP_VCALL_REG: virt? OP_VCALLVIRT: OP_VCALL;
1754 case MONO_TYPE_TYPEDBYREF:
1755 return calli? OP_VCALL_REG: virt? OP_VCALLVIRT: OP_VCALL;
1756 case MONO_TYPE_GENERICINST:
1757 t = type->data.generic_inst->generic_type->type;
1760 g_error ("unknown type 0x%02x in ret_type_to_call_opcode", type->type);
1766 mono_create_jump_table (MonoCompile *cfg, MonoInst *label, MonoBasicBlock **bbs, int num_blocks)
1768 MonoJumpInfo *ji = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfo));
1770 ji->ip.label = label;
1771 ji->type = MONO_PATCH_INFO_SWITCH;
1772 ji->data.table = bbs;
1773 ji->next = cfg->patch_info;
1774 ji->table_size = num_blocks;
1775 cfg->patch_info = ji;
1779 * When we add a tree of instructions, we need to ensure the instructions currently
1780 * on the stack are executed before (like, if we load a value from a local).
1781 * We ensure this by saving the currently loaded values to temps and rewriting the
1782 * instructions to load the values.
1783 * This is not done for opcodes that terminate a basic block (because it's handled already
1784 * by handle_stack_args ()) and for opcodes that can't change values, like POP.
1787 handle_loaded_temps (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst **stack, MonoInst **sp)
1789 MonoInst *load, *store, *temp, *ins;
1791 while (stack < sp) {
1793 /* handle also other constants */
1794 if (ins->opcode != OP_ICONST) {
1795 temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1796 NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
1797 store->cil_code = ins->cil_code;
1798 if (store->opcode == CEE_STOBJ) {
1799 NEW_TEMPLOADA (cfg, store, temp->inst_c0);
1800 handle_stobj (cfg, bblock, store, ins, ins->cil_code, temp->klass, FALSE, FALSE);
1802 MONO_ADD_INS (bblock, store);
1803 NEW_TEMPLOAD (cfg, load, temp->inst_c0);
1804 load->cil_code = ins->cil_code;
1812 * Prepare arguments for passing to a function call.
1813 * Return a non-zero value if the arguments can't be passed to the given
1815 * The type checks are not yet complete and some conversions may need
1816 * casts on 32 or 64 bit architectures.
1819 check_call_signature (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args)
1824 if (args [0]->type != STACK_OBJ && args [0]->type != STACK_MP && args [0]->type != STACK_PTR)
1828 for (i = 0; i < sig->param_count; ++i) {
1829 if (sig->params [i]->byref) {
1831 * check the result of ldelema is only passed as an argument if the byref
1832 * type matches exactly the array element type.
1833 * FIXME: if the argument as been saved on the stack as part of the
1834 * interface variable code (the value was on the stack at a basic block boundary)
1835 * we need to add the check in that case, too.
1837 if (args [i]->opcode == CEE_LDELEMA) {
1839 MonoClass *exact_class = mono_class_from_mono_type (sig->params [i]);
1840 if (!exact_class->valuetype) {
1841 MONO_INST_NEW (cfg, check, OP_CHECK_ARRAY_TYPE);
1842 check->cil_code = args [i]->cil_code;
1843 check->klass = exact_class;
1844 check->inst_left = args [i]->inst_left;
1845 check->type = STACK_OBJ;
1846 args [i]->inst_left = check;
1849 if (args [i]->type != STACK_MP && args [i]->type != STACK_PTR)
1853 simple_type = sig->params [i]->type;
1855 switch (simple_type) {
1856 case MONO_TYPE_VOID:
1861 case MONO_TYPE_BOOLEAN:
1864 case MONO_TYPE_CHAR:
1867 if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR)
1873 if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR && args [i]->type != STACK_MP && args [i]->type != STACK_OBJ)
1876 case MONO_TYPE_CLASS:
1877 case MONO_TYPE_STRING:
1878 case MONO_TYPE_OBJECT:
1879 case MONO_TYPE_SZARRAY:
1880 case MONO_TYPE_ARRAY:
1881 if (args [i]->type != STACK_OBJ)
1886 if (args [i]->type != STACK_I8)
1891 if (args [i]->type != STACK_R8)
1894 case MONO_TYPE_VALUETYPE:
1895 if (sig->params [i]->data.klass->enumtype) {
1896 simple_type = sig->params [i]->data.klass->enum_basetype->type;
1899 if (args [i]->type != STACK_VTYPE)
1902 case MONO_TYPE_TYPEDBYREF:
1903 if (args [i]->type != STACK_VTYPE)
1906 case MONO_TYPE_GENERICINST:
1907 simple_type = sig->params [i]->data.generic_inst->generic_type->type;
1911 g_error ("unknown type 0x%02x in check_call_signature", simple_type);
1918 mono_spill_call (MonoCompile *cfg, MonoBasicBlock *bblock, MonoCallInst *call, MonoMethodSignature *sig, gboolean ret_object,
1919 const guint8 *ip, gboolean to_end)
1921 MonoInst *temp, *store, *ins = (MonoInst*)call;
1922 MonoType *ret = sig->ret;
1924 if (!MONO_TYPE_IS_VOID (ret) || ret_object) {
1926 call->inst.type = STACK_OBJ;
1927 call->inst.opcode = CEE_CALL;
1928 temp = mono_compile_create_var (cfg, &mono_defaults.string_class->byval_arg, OP_LOCAL);
1930 type_to_eval_stack_type (ret, ins);
1931 temp = mono_compile_create_var (cfg, ret, OP_LOCAL);
1934 if (MONO_TYPE_ISSTRUCT (ret)) {
1937 /* we use this to allocate native sized structs */
1938 temp->unused = sig->pinvoke;
1940 NEW_TEMPLOADA (cfg, loada, temp->inst_c0);
1941 if (call->inst.opcode == OP_VCALL)
1942 ins->inst_left = loada;
1944 ins->inst_right = loada; /* a virtual or indirect call */
1947 mono_add_ins_to_end (bblock, ins);
1949 MONO_ADD_INS (bblock, ins);
1951 NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
1952 store->cil_code = ip;
1954 mono_add_ins_to_end (bblock, store);
1956 MONO_ADD_INS (bblock, store);
1958 return temp->inst_c0;
1961 mono_add_ins_to_end (bblock, ins);
1963 MONO_ADD_INS (bblock, ins);
1968 inline static MonoCallInst *
1969 mono_emit_call_args (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethodSignature *sig,
1970 MonoInst **args, int calli, int virtual, const guint8 *ip, gboolean to_end)
1975 MONO_INST_NEW_CALL (cfg, call, ret_type_to_call_opcode (sig->ret, calli, virtual));
1977 call->inst.cil_code = ip;
1979 call->signature = sig;
1980 call = mono_arch_call_opcode (cfg, bblock, call, virtual);
1982 for (arg = call->out_args; arg;) {
1983 MonoInst *narg = arg->next;
1988 mono_add_ins_to_end (bblock, arg);
1990 MONO_ADD_INS (bblock, arg);
1997 mono_emit_calli (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethodSignature *sig,
1998 MonoInst **args, MonoInst *addr, const guint8 *ip)
2000 MonoCallInst *call = mono_emit_call_args (cfg, bblock, sig, args, TRUE, FALSE, ip, FALSE);
2002 call->inst.inst_i0 = addr;
2004 return mono_spill_call (cfg, bblock, call, sig, FALSE, ip, FALSE);
2007 static MonoCallInst*
2008 mono_emit_method_call (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *method, MonoMethodSignature *sig,
2009 MonoInst **args, const guint8 *ip, MonoInst *this)
2011 gboolean virtual = this != NULL;
2014 call = mono_emit_call_args (cfg, bblock, sig, args, FALSE, virtual, ip, FALSE);
2016 if (this && sig->hasthis &&
2017 (method->klass->marshalbyref || method->klass == mono_defaults.object_class) &&
2018 !(method->flags & METHOD_ATTRIBUTE_VIRTUAL) && !MONO_CHECK_THIS (this)) {
2019 call->method = mono_marshal_get_remoting_invoke_with_check (method);
2021 call->method = method;
2023 call->inst.flags |= MONO_INST_HAS_METHOD;
2024 call->inst.inst_left = this;
2030 mono_emit_method_call_spilled (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *method,
2031 MonoMethodSignature *signature, MonoInst **args, const guint8 *ip, MonoInst *this)
2033 MonoCallInst *call = mono_emit_method_call (cfg, bblock, method, signature, args, ip, this);
2035 return mono_spill_call (cfg, bblock, call, signature, method->string_ctor, ip, FALSE);
2039 mono_emit_native_call (MonoCompile *cfg, MonoBasicBlock *bblock, gconstpointer func, MonoMethodSignature *sig,
2040 MonoInst **args, const guint8 *ip, gboolean to_end)
2046 call = mono_emit_call_args (cfg, bblock, sig, args, FALSE, FALSE, ip, to_end);
2048 return mono_spill_call (cfg, bblock, call, sig, func == mono_array_new_va, ip, to_end);
2052 mono_emit_jit_icall (MonoCompile *cfg, MonoBasicBlock *bblock, gconstpointer func, MonoInst **args, const guint8 *ip)
2054 MonoJitICallInfo *info = mono_find_jit_icall_by_addr (func);
2057 g_warning ("unregistered JIT ICall");
2058 g_assert_not_reached ();
2061 return mono_emit_native_call (cfg, bblock, mono_icall_get_wrapper (info), info->sig, args, ip, FALSE);
2065 mono_emulate_opcode (MonoCompile *cfg, MonoInst *tree, MonoInst **iargs, MonoJitICallInfo *info)
2067 MonoInst *ins, *temp = NULL, *store, *load, *begin;
2068 MonoInst *last_arg = NULL;
2072 //g_print ("emulating: ");
2073 //mono_print_tree_nl (tree);
2074 MONO_INST_NEW_CALL (cfg, call, ret_type_to_call_opcode (info->sig->ret, FALSE, FALSE));
2075 ins = (MonoInst*)call;
2077 call->inst.cil_code = tree->cil_code;
2079 call->signature = info->sig;
2081 call = mono_arch_call_opcode (cfg, cfg->cbb, call, FALSE);
2083 if (!MONO_TYPE_IS_VOID (info->sig->ret)) {
2084 temp = mono_compile_create_var (cfg, info->sig->ret, OP_LOCAL);
2085 NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
2086 store->cil_code = tree->cil_code;
2091 nargs = info->sig->param_count + info->sig->hasthis;
2093 for (last_arg = call->out_args; last_arg && last_arg->next; last_arg = last_arg->next) ;
2096 last_arg->next = store;
2099 begin = call->out_args;
2103 if (cfg->prev_ins) {
2105 * This assumes that that in a tree, emulate_opcode is called for a
2106 * node before it is called for its children. dec_foreach needs to
2107 * take this into account.
2109 store->next = cfg->prev_ins->next;
2110 cfg->prev_ins->next = begin;
2112 store->next = cfg->cbb->code;
2113 cfg->cbb->code = begin;
2116 call->fptr = mono_icall_get_wrapper (info);
2118 if (!MONO_TYPE_IS_VOID (info->sig->ret)) {
2119 NEW_TEMPLOAD (cfg, load, temp->inst_c0);
2124 static MonoMethodSignature *
2125 mono_get_element_address_signature (int arity)
2127 static GHashTable *sighash = NULL;
2128 MonoMethodSignature *res;
2131 EnterCriticalSection (&trampoline_hash_mutex);
2133 sighash = g_hash_table_new (NULL, NULL);
2135 else if ((res = g_hash_table_lookup (sighash, (gpointer)arity))) {
2136 LeaveCriticalSection (&trampoline_hash_mutex);
2140 res = mono_metadata_signature_alloc (mono_defaults.corlib, arity + 1);
2143 #ifdef MONO_ARCH_VARARG_ICALLS
2144 /* Only set this only some archs since not all backends can handle varargs+pinvoke */
2145 res->call_convention = MONO_CALL_VARARG;
2147 res->params [0] = &mono_defaults.array_class->byval_arg;
2149 for (i = 1; i <= arity; i++)
2150 res->params [i] = &mono_defaults.int_class->byval_arg;
2152 res->ret = &mono_defaults.int_class->byval_arg;
2154 g_hash_table_insert (sighash, (gpointer)arity, res);
2155 LeaveCriticalSection (&trampoline_hash_mutex);
2160 static MonoMethodSignature *
2161 mono_get_array_new_va_signature (int arity)
2163 static GHashTable *sighash = NULL;
2164 MonoMethodSignature *res;
2167 EnterCriticalSection (&trampoline_hash_mutex);
2169 sighash = g_hash_table_new (NULL, NULL);
2171 else if ((res = g_hash_table_lookup (sighash, (gpointer)arity))) {
2172 LeaveCriticalSection (&trampoline_hash_mutex);
2176 res = mono_metadata_signature_alloc (mono_defaults.corlib, arity + 1);
2179 #ifdef MONO_ARCH_VARARG_ICALLS
2180 /* Only set this only some archs since not all backends can handle varargs+pinvoke */
2181 res->call_convention = MONO_CALL_VARARG;
2184 res->params [0] = &mono_defaults.int_class->byval_arg;
2185 for (i = 0; i < arity; i++)
2186 res->params [i + 1] = &mono_defaults.int_class->byval_arg;
2188 res->ret = &mono_defaults.int_class->byval_arg;
2190 g_hash_table_insert (sighash, (gpointer)arity, res);
2191 LeaveCriticalSection (&trampoline_hash_mutex);
2197 handle_stobj (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *dest, MonoInst *src, const unsigned char *ip, MonoClass *klass, gboolean to_end, gboolean native) {
2198 MonoInst *iargs [3];
2204 * This check breaks with spilled vars... need to handle it during verification anyway.
2205 * g_assert (klass && klass == src->klass && klass == dest->klass);
2209 n = mono_class_native_size (klass, &align);
2211 n = mono_class_value_size (klass, &align);
2213 if ((cfg->opt & MONO_OPT_INTRINS) && !to_end && n <= sizeof (gpointer) * 5) {
2215 MONO_INST_NEW (cfg, inst, OP_MEMCPY);
2216 inst->inst_left = dest;
2217 inst->inst_right = src;
2218 inst->cil_code = ip;
2220 MONO_ADD_INS (bblock, inst);
2225 NEW_ICONST (cfg, iargs [2], n);
2227 mono_emit_native_call (cfg, bblock, helper_memcpy, helper_sig_memcpy, iargs, ip, to_end);
2231 handle_initobj (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *dest, const guchar *ip, MonoClass *klass, MonoInst **stack_start, MonoInst **sp)
2233 MonoInst *iargs [2];
2234 MonoInst *ins, *zero_int32;
2237 NEW_ICONST (cfg, zero_int32, 0);
2239 mono_class_init (klass);
2240 n = mono_class_value_size (klass, NULL);
2241 MONO_INST_NEW (cfg, ins, 0);
2243 ins->inst_left = dest;
2244 ins->inst_right = zero_int32;
2247 ins->opcode = CEE_STIND_I1;
2248 MONO_ADD_INS (bblock, ins);
2251 ins->opcode = CEE_STIND_I2;
2252 MONO_ADD_INS (bblock, ins);
2255 ins->opcode = CEE_STIND_I4;
2256 MONO_ADD_INS (bblock, ins);
2259 if (n <= sizeof (gpointer) * 5) {
2260 ins->opcode = OP_MEMSET;
2263 MONO_ADD_INS (bblock, ins);
2266 handle_loaded_temps (cfg, bblock, stack_start, sp);
2267 NEW_ICONST (cfg, ins, n);
2270 mono_emit_jit_icall (cfg, bblock, helper_initobj, iargs, ip);
2276 handle_box (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *val, const guchar *ip, MonoClass *klass)
2278 MonoInst *iargs [2];
2279 MonoInst *dest, *vtoffset, *add, *vstore;
2282 /* much like NEWOBJ */
2283 if (cfg->opt & MONO_OPT_SHARED) {
2284 NEW_DOMAINCONST (cfg, iargs [0]);
2285 NEW_CLASSCONST (cfg, iargs [1], klass);
2287 temp = mono_emit_jit_icall (cfg, bblock, mono_object_new, iargs, ip);
2289 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
2290 NEW_VTABLECONST (cfg, iargs [0], vtable);
2291 if (klass->has_finalize || (cfg->prof_options & MONO_PROFILE_ALLOCATIONS))
2292 temp = mono_emit_jit_icall (cfg, bblock, mono_object_new_specific, iargs, ip);
2294 temp = mono_emit_jit_icall (cfg, bblock, mono_object_new_fast, iargs, ip);
2296 NEW_TEMPLOAD (cfg, dest, temp);
2297 NEW_ICONST (cfg, vtoffset, sizeof (MonoObject));
2298 MONO_INST_NEW (cfg, add, CEE_ADD);
2299 add->inst_left = dest;
2300 add->inst_right = vtoffset;
2303 MONO_INST_NEW (cfg, vstore, CEE_STIND_I);
2304 vstore->opcode = mono_type_to_stind (&klass->byval_arg);
2305 vstore->cil_code = ip;
2306 vstore->inst_left = add;
2307 vstore->inst_right = val;
2309 if (vstore->opcode == CEE_STOBJ) {
2310 handle_stobj (cfg, bblock, add, val, ip, klass, FALSE, FALSE);
2312 MONO_ADD_INS (bblock, vstore);
2314 NEW_TEMPLOAD (cfg, dest, temp);
2318 #define CODE_IS_STLOC(ip) (((ip) [0] >= CEE_STLOC_0 && (ip) [0] <= CEE_STLOC_3) || ((ip) [0] == CEE_STLOC_S))
2321 mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method)
2323 MonoMethodHeader *header = ((MonoMethodNormal *)method)->header;
2324 MonoMethodSignature *signature = method->signature;
2328 #ifdef MONO_ARCH_HAVE_LMF_OPS
2329 if (((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
2330 (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) &&
2331 !MONO_TYPE_ISSTRUCT (signature->ret) && (method->klass->parent != mono_defaults.array_class))
2335 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
2336 (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
2337 (method->iflags & METHOD_IMPL_ATTRIBUTE_NOINLINING) ||
2338 (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) ||
2339 (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
2340 (method->klass->marshalbyref) ||
2341 !header || header->num_clauses ||
2342 /* fixme: why cant we inline valuetype returns? */
2343 MONO_TYPE_ISSTRUCT (signature->ret))
2346 /* its not worth to inline methods with valuetype arguments?? */
2347 for (i = 0; i < signature->param_count; i++) {
2348 if (MONO_TYPE_ISSTRUCT (signature->params [i])) {
2354 * if we can initialize the class of the method right away, we do,
2355 * otherwise we don't allow inlining if the class needs initialization,
2356 * since it would mean inserting a call to mono_runtime_class_init()
2357 * inside the inlined code
2359 if (!(cfg->opt & MONO_OPT_SHARED)) {
2360 vtable = mono_class_vtable (cfg->domain, method->klass);
2361 if (method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) {
2362 if (cfg->run_cctors)
2363 mono_runtime_class_init (vtable);
2365 else if (!vtable->initialized && mono_class_needs_cctor_run (method->klass, NULL))
2369 * If we're compiling for shared code
2370 * the cctor will need to be run at aot method load time, for example,
2371 * or at the end of the compilation of the inlining method.
2373 if (mono_class_needs_cctor_run (method->klass, NULL) && !((method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT)))
2376 //if (!MONO_TYPE_IS_VOID (signature->ret)) return FALSE;
2378 /* also consider num_locals? */
2379 if (getenv ("MONO_INLINELIMIT"))
2380 if (header->code_size < atoi (getenv ("MONO_INLINELIMIT"))) {
2384 if (header->code_size < 20)
2391 mini_get_ldelema_ins (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *cmethod, MonoInst **sp, unsigned char *ip, gboolean is_set)
2395 MonoMethodSignature *esig;
2396 char icall_name [256];
2397 MonoJitICallInfo *info;
2399 rank = cmethod->signature->param_count - (is_set? 1: 0);
2401 if (rank == 2 && (cfg->opt & MONO_OPT_INTRINS)) {
2403 NEW_GROUP (cfg, indexes, sp [1], sp [2]);
2404 MONO_INST_NEW (cfg, addr, OP_LDELEMA2D);
2405 addr->inst_left = sp [0];
2406 addr->inst_right = indexes;
2407 addr->cil_code = ip;
2408 addr->type = STACK_MP;
2409 addr->klass = cmethod->klass;
2413 /* Need to register the icall so it gets an icall wrapper */
2414 sprintf (icall_name, "ves_array_element_address_%d", rank);
2416 info = mono_find_jit_icall_by_name (icall_name);
2418 esig = mono_get_element_address_signature (rank);
2419 info = mono_register_jit_icall (ves_array_element_address, g_strdup (icall_name), esig, FALSE);
2422 temp = mono_emit_native_call (cfg, bblock, mono_icall_get_wrapper (info), info->sig, sp, ip, FALSE);
2423 cfg->flags |= MONO_CFG_HAS_VARARGS;
2425 NEW_TEMPLOAD (cfg, addr, temp);
2429 static MonoJitICallInfo **emul_opcode_map = NULL;
2431 static inline MonoJitICallInfo *
2432 mono_find_jit_opcode_emulation (int opcode)
2434 if (emul_opcode_map)
2435 return emul_opcode_map [opcode];
2441 mini_get_opcode_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
2446 static MonoClass *runtime_helpers_class = NULL;
2447 if (! runtime_helpers_class)
2448 runtime_helpers_class = mono_class_from_name (mono_defaults.corlib,
2449 "System.Runtime.CompilerServices", "RuntimeHelpers");
2451 if (cmethod->klass == mono_defaults.string_class) {
2452 if (cmethod->name [0] != 'g')
2455 if (strcmp (cmethod->name, "get_Chars") == 0)
2457 else if (strcmp (cmethod->name, "get_Length") == 0)
2460 } else if (cmethod->klass == mono_defaults.object_class) {
2461 if (strcmp (cmethod->name, "GetType") == 0)
2465 } else if (cmethod->klass == mono_defaults.array_class) {
2466 if (strcmp (cmethod->name, "get_Rank") == 0)
2468 else if (strcmp (cmethod->name, "get_Length") == 0)
2472 } else if (cmethod->klass == runtime_helpers_class) {
2473 if (strcmp (cmethod->name, "get_OffsetToStringData") == 0) {
2474 NEW_ICONST (cfg, ins, G_STRUCT_OFFSET (MonoString, chars));
2479 op = mono_arch_get_opcode_for_method (cfg, cmethod, fsig, args);
2483 pc = fsig->param_count + fsig->hasthis;
2484 MONO_INST_NEW (cfg, ins, op);
2487 ins->inst_i0 = args [0];
2489 ins->inst_i1 = args [1];
2496 mono_save_args (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethodSignature *sig, MonoInst **sp, MonoInst **args)
2498 MonoInst *store, *temp;
2501 g_assert (!MONO_TYPE_ISSTRUCT (sig->ret));
2503 if (!sig->hasthis && sig->param_count == 0)
2507 if (sp [0]->opcode == OP_ICONST) {
2510 temp = mono_compile_create_var (cfg, type_from_stack_type (*sp), OP_LOCAL);
2512 NEW_TEMPSTORE (cfg, store, temp->inst_c0, *sp);
2513 store->cil_code = sp [0]->cil_code;
2514 MONO_ADD_INS (bblock, store);
2519 for (i = 0; i < sig->param_count; ++i) {
2520 if (sp [0]->opcode == OP_ICONST) {
2523 temp = mono_compile_create_var (cfg, sig->params [i], OP_LOCAL);
2525 NEW_TEMPSTORE (cfg, store, temp->inst_c0, *sp);
2526 store->cil_code = sp [0]->cil_code;
2527 if (store->opcode == CEE_STOBJ) {
2528 NEW_TEMPLOADA (cfg, store, temp->inst_c0);
2529 handle_stobj (cfg, bblock, store, *sp, sp [0]->cil_code, temp->klass, FALSE, FALSE);
2531 MONO_ADD_INS (bblock, store);
2539 inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoBasicBlock *bblock, MonoInst **sp,
2540 guchar *ip, guint real_offset, GList *dont_inline, MonoBasicBlock **last_b, gboolean inline_allways)
2542 MonoInst *ins, *rvar = NULL;
2543 MonoMethodHeader *cheader;
2544 MonoBasicBlock *ebblock, *sbblock;
2545 int i, costs, new_locals_offset;
2546 MonoMethod *prev_inlined_method;
2548 if (cfg->verbose_level > 2)
2549 g_print ("INLINE START %p %s -> %s\n", cmethod, mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
2551 if (!cmethod->inline_info) {
2552 mono_jit_stats.inlineable_methods++;
2553 cmethod->inline_info = 1;
2555 /* allocate space to store the return value */
2556 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
2557 rvar = mono_compile_create_var (cfg, fsig->ret, OP_LOCAL);
2560 /* allocate local variables */
2561 cheader = ((MonoMethodNormal *)cmethod)->header;
2562 new_locals_offset = cfg->num_varinfo;
2563 for (i = 0; i < cheader->num_locals; ++i)
2564 mono_compile_create_var (cfg, cheader->locals [i], OP_LOCAL);
2566 /* allocate starte and end blocks */
2567 sbblock = NEW_BBLOCK (cfg);
2568 sbblock->block_num = cfg->num_bblocks++;
2569 sbblock->real_offset = real_offset;
2571 ebblock = NEW_BBLOCK (cfg);
2572 ebblock->block_num = cfg->num_bblocks++;
2573 ebblock->real_offset = real_offset;
2575 prev_inlined_method = cfg->inlined_method;
2576 cfg->inlined_method = cmethod;
2578 costs = mono_method_to_ir (cfg, cmethod, sbblock, ebblock, new_locals_offset, rvar, dont_inline, sp, real_offset, *ip == CEE_CALLVIRT);
2580 cfg->inlined_method = prev_inlined_method;
2582 if ((costs >= 0 && costs < 60) || inline_allways) {
2583 if (cfg->verbose_level > 2)
2584 g_print ("INLINE END %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
2586 mono_jit_stats.inlined_methods++;
2588 /* always add some code to avoid block split failures */
2589 MONO_INST_NEW (cfg, ins, CEE_NOP);
2590 MONO_ADD_INS (bblock, ins);
2593 bblock->next_bb = sbblock;
2594 link_bblock (cfg, bblock, sbblock);
2597 NEW_TEMPLOAD (cfg, ins, rvar->inst_c0);
2603 if (cfg->verbose_level > 2)
2604 g_print ("INLINE ABORTED %s\n", mono_method_full_name (cmethod, TRUE));
2610 * Some of these comments may well be out-of-date.
2611 * Design decisions: we do a single pass over the IL code (and we do bblock
2612 * splitting/merging in the few cases when it's required: a back jump to an IL
2613 * address that was not already seen as bblock starting point).
2614 * Code is validated as we go (full verification is still better left to metadata/verify.c).
2615 * Complex operations are decomposed in simpler ones right away. We need to let the
2616 * arch-specific code peek and poke inside this process somehow (except when the
2617 * optimizations can take advantage of the full semantic info of coarse opcodes).
2618 * All the opcodes of the form opcode.s are 'normalized' to opcode.
2619 * MonoInst->opcode initially is the IL opcode or some simplification of that
2620 * (OP_LOAD, OP_STORE). The arch-specific code may rearrange it to an arch-specific
2621 * opcode with value bigger than OP_LAST.
2622 * At this point the IR can be handed over to an interpreter, a dumb code generator
2623 * or to the optimizing code generator that will translate it to SSA form.
2625 * Profiling directed optimizations.
2626 * We may compile by default with few or no optimizations and instrument the code
2627 * or the user may indicate what methods to optimize the most either in a config file
2628 * or through repeated runs where the compiler applies offline the optimizations to
2629 * each method and then decides if it was worth it.
2632 * * consider using an array instead of an hash table (bb_hash)
2635 #define CHECK_TYPE(ins) if (!(ins)->type) goto unverified
2636 #define CHECK_STACK(num) if ((sp - stack_start) < (num)) goto unverified
2637 #define CHECK_STACK_OVF(num) if (((sp - stack_start) + (num)) > header->max_stack) goto unverified
2638 #define CHECK_ARG(num) if ((unsigned)(num) >= (unsigned)num_args) goto unverified
2639 #define CHECK_LOCAL(num) if ((unsigned)(num) >= (unsigned)header->num_locals) goto unverified
2640 #define CHECK_OPSIZE(size) if (ip + size > end) goto unverified
2643 /* offset from br.s -> br like opcodes */
2644 #define BIG_BRANCH_OFFSET 13
2647 get_basic_blocks (MonoCompile *cfg, GHashTable *bbhash, MonoMethodHeader* header, guint real_offset, unsigned char *start, unsigned char *end, unsigned char **pos)
2649 unsigned char *ip = start;
2650 unsigned char *target;
2653 MonoBasicBlock *bblock;
2654 const MonoOpcode *opcode;
2657 cli_addr = ip - start;
2658 i = mono_opcode_value ((const guint8 **)&ip, end);
2661 opcode = &mono_opcodes [i];
2662 switch (opcode->argument) {
2663 case MonoInlineNone:
2666 case MonoInlineString:
2667 case MonoInlineType:
2668 case MonoInlineField:
2669 case MonoInlineMethod:
2672 case MonoShortInlineR:
2679 case MonoShortInlineVar:
2680 case MonoShortInlineI:
2683 case MonoShortInlineBrTarget:
2684 target = start + cli_addr + 2 + (signed char)ip [1];
2685 GET_BBLOCK (cfg, bbhash, bblock, target);
2688 case MonoInlineBrTarget:
2689 target = start + cli_addr + 5 + (gint32)read32 (ip + 1);
2690 GET_BBLOCK (cfg, bbhash, bblock, target);
2693 case MonoInlineSwitch: {
2694 guint32 n = read32 (ip + 1);
2697 cli_addr += 5 + 4 * n;
2698 target = start + cli_addr;
2699 GET_BBLOCK (cfg, bbhash, bblock, target);
2701 for (j = 0; j < n; ++j) {
2702 target = start + cli_addr + (gint32)read32 (ip);
2703 GET_BBLOCK (cfg, bbhash, bblock, target);
2713 g_assert_not_reached ();
2723 emit_tree (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *ins)
2725 MonoInst *store, *temp, *load;
2726 temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
2727 NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
2728 store->cil_code = ins->cil_code;
2729 MONO_ADD_INS (bblock, store);
2730 NEW_TEMPLOAD (cfg, load, temp->inst_c0);
2731 load->cil_code = ins->cil_code;
2736 * mono_method_to_ir: translates IL into basic blocks containing trees
2739 mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock,
2740 int locals_offset, MonoInst *return_var, GList *dont_inline, MonoInst **inline_args,
2741 guint inline_offset, gboolean is_virtual_call)
2743 MonoInst *zero_int32, *zero_int64, *zero_ptr, *zero_obj, *zero_r8;
2744 MonoInst *ins, **sp, **stack_start;
2745 MonoBasicBlock *bblock, *tblock = NULL, *init_localsbb = NULL;
2747 MonoMethod *cmethod;
2748 MonoInst **arg_array;
2749 MonoMethodHeader *header;
2751 guint32 token, ins_flag;
2753 MonoClass *constrained_call = NULL;
2754 unsigned char *ip, *end, *target, *err_pos;
2755 static double r8_0 = 0.0;
2756 MonoMethodSignature *sig;
2757 MonoGenericContext *generic_context = NULL;
2758 MonoType **param_types;
2759 GList *bb_recheck = NULL, *tmp;
2760 int i, n, start_new_bblock, align;
2761 int num_calls = 0, inline_costs = 0;
2762 int *filter_lengths = NULL;
2763 int breakpoint_id = 0;
2764 guint real_offset, num_args;
2766 image = method->klass->image;
2767 header = ((MonoMethodNormal *)method)->header;
2768 sig = method->signature;
2769 num_args = sig->hasthis + sig->param_count;
2770 ip = (unsigned char*)header->code;
2771 end = ip + header->code_size;
2772 mono_jit_stats.cil_code_size += header->code_size;
2774 if (method->signature->is_inflated)
2775 generic_context = ((MonoMethodInflated *) method)->context;
2777 if (cfg->method == method) {
2779 bbhash = cfg->bb_hash;
2781 real_offset = inline_offset;
2782 bbhash = g_hash_table_new (g_direct_hash, NULL);
2785 if (cfg->verbose_level > 2)
2786 g_print ("method to IR %s\n", mono_method_full_name (method, TRUE));
2788 dont_inline = g_list_prepend (dont_inline, method);
2789 if (cfg->method == method) {
2791 if (cfg->prof_options & MONO_PROFILE_INS_COVERAGE)
2792 cfg->coverage_info = mono_profiler_coverage_alloc (cfg->method, header->code_size);
2795 cfg->bb_entry = start_bblock = NEW_BBLOCK (cfg);
2796 start_bblock->cil_code = NULL;
2797 start_bblock->cil_length = 0;
2798 start_bblock->block_num = cfg->num_bblocks++;
2801 cfg->bb_exit = end_bblock = NEW_BBLOCK (cfg);
2802 end_bblock->cil_code = NULL;
2803 end_bblock->cil_length = 0;
2804 end_bblock->block_num = cfg->num_bblocks++;
2805 g_assert (cfg->num_bblocks == 2);
2807 arg_array = alloca (sizeof (MonoInst *) * num_args);
2808 for (i = num_args - 1; i >= 0; i--)
2809 arg_array [i] = cfg->varinfo [i];
2811 if (header->num_clauses) {
2812 int size = sizeof (int) * header->num_clauses;
2813 filter_lengths = alloca (size);
2814 memset (filter_lengths, 0, size);
2816 cfg->spvars = g_hash_table_new (NULL, NULL);
2818 /* handle exception clauses */
2819 for (i = 0; i < header->num_clauses; ++i) {
2820 //unsigned char *p = ip;
2821 MonoExceptionClause *clause = &header->clauses [i];
2822 GET_BBLOCK (cfg, bbhash, tblock, ip + clause->try_offset);
2823 tblock->real_offset = clause->try_offset;
2824 GET_BBLOCK (cfg, bbhash, tblock, ip + clause->handler_offset);
2825 tblock->real_offset = clause->handler_offset;
2827 if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY ||
2828 clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
2829 MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
2830 MONO_ADD_INS (tblock, ins);
2833 /*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);
2835 g_print ("%s", mono_disasm_code_one (NULL, method, p, &p));
2837 /* catch and filter blocks get the exception object on the stack */
2838 if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE ||
2839 clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
2840 /* mostly like handle_stack_args (), but just sets the input args */
2841 /* g_print ("handling clause at IL_%04x\n", clause->handler_offset); */
2843 cfg->exvar = mono_compile_create_var (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL);
2844 /* prevent it from being register allocated */
2845 cfg->exvar->flags |= MONO_INST_INDIRECT;
2847 tblock->in_scount = 1;
2848 tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
2849 tblock->in_stack [0] = cfg->exvar;
2851 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
2852 GET_BBLOCK (cfg, bbhash, tblock, ip + clause->token_or_filter);
2853 tblock->real_offset = clause->token_or_filter;
2854 tblock->in_scount = 1;
2855 tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
2856 tblock->in_stack [0] = cfg->exvar;
2857 MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
2858 MONO_ADD_INS (tblock, ins);
2864 arg_array = alloca (sizeof (MonoInst *) * num_args);
2865 mono_save_args (cfg, start_bblock, sig, inline_args, arg_array);
2868 /* FIRST CODE BLOCK */
2869 bblock = NEW_BBLOCK (cfg);
2870 bblock->cil_code = ip;
2872 ADD_BBLOCK (cfg, bbhash, bblock);
2874 if (cfg->method == method) {
2875 breakpoint_id = mono_debugger_method_has_breakpoint (method);
2876 if (breakpoint_id && (mono_debug_format != MONO_DEBUG_FORMAT_DEBUGGER)) {
2877 MONO_INST_NEW (cfg, ins, CEE_BREAK);
2878 MONO_ADD_INS (bblock, ins);
2882 if ((header->init_locals || (cfg->method == method && (cfg->opt & MONO_OPT_SHARED))) || mono_compile_aot) {
2883 /* we use a separate basic block for the initialization code */
2884 cfg->bb_init = init_localsbb = NEW_BBLOCK (cfg);
2885 init_localsbb->real_offset = real_offset;
2886 start_bblock->next_bb = init_localsbb;
2887 init_localsbb->next_bb = bblock;
2888 link_bblock (cfg, start_bblock, init_localsbb);
2889 link_bblock (cfg, init_localsbb, bblock);
2890 init_localsbb->block_num = cfg->num_bblocks++;
2892 start_bblock->next_bb = bblock;
2893 link_bblock (cfg, start_bblock, bblock);
2896 if (get_basic_blocks (cfg, bbhash, header, real_offset, ip, end, &err_pos)) {
2901 mono_debug_init_method (cfg, bblock, breakpoint_id);
2903 param_types = mono_mempool_alloc (cfg->mempool, sizeof (MonoType*) * num_args);
2905 param_types [0] = method->klass->valuetype?&method->klass->this_arg:&method->klass->byval_arg;
2906 for (n = 0; n < sig->param_count; ++n)
2907 param_types [n + sig->hasthis] = sig->params [n];
2909 /* do this somewhere outside - not here */
2910 NEW_ICONST (cfg, zero_int32, 0);
2911 NEW_ICONST (cfg, zero_int64, 0);
2912 zero_int64->type = STACK_I8;
2913 NEW_PCONST (cfg, zero_ptr, 0);
2914 NEW_PCONST (cfg, zero_obj, 0);
2915 zero_obj->type = STACK_OBJ;
2917 MONO_INST_NEW (cfg, zero_r8, OP_R8CONST);
2918 zero_r8->type = STACK_R8;
2919 zero_r8->inst_p0 = &r8_0;
2921 /* add a check for this != NULL to inlined methods */
2922 if (is_virtual_call) {
2923 MONO_INST_NEW (cfg, ins, OP_CHECK_THIS);
2924 NEW_ARGLOAD (cfg, ins->inst_left, 0);
2926 MONO_ADD_INS (bblock, ins);
2929 /* we use a spare stack slot in SWITCH and NEWOBJ and others */
2930 stack_start = sp = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * (header->max_stack + 1));
2933 start_new_bblock = 0;
2936 if (cfg->method == method)
2937 real_offset = ip - header->code;
2939 real_offset = inline_offset;
2941 if (start_new_bblock) {
2942 bblock->cil_length = ip - bblock->cil_code;
2943 if (start_new_bblock == 2) {
2944 g_assert (ip == tblock->cil_code);
2946 GET_BBLOCK (cfg, bbhash, tblock, ip);
2948 bblock->next_bb = tblock;
2950 start_new_bblock = 0;
2951 for (i = 0; i < bblock->in_scount; ++i) {
2952 if (cfg->verbose_level > 3)
2953 g_print ("loading %d from temp %d\n", i, bblock->in_stack [i]->inst_c0);
2954 NEW_TEMPLOAD (cfg, ins, bblock->in_stack [i]->inst_c0);
2958 if ((tblock = g_hash_table_lookup (bbhash, ip)) && (tblock != bblock)) {
2959 link_bblock (cfg, bblock, tblock);
2960 if (sp != stack_start) {
2961 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
2964 bblock->next_bb = tblock;
2966 for (i = 0; i < bblock->in_scount; ++i) {
2967 if (cfg->verbose_level > 3)
2968 g_print ("loading %d from temp %d\n", i, bblock->in_stack [i]->inst_c0);
2969 NEW_TEMPLOAD (cfg, ins, bblock->in_stack [i]->inst_c0);
2975 bblock->real_offset = real_offset;
2977 if ((cfg->method == method) && cfg->coverage_info) {
2978 MonoInst *store, *one;
2979 guint32 cil_offset = ip - header->code;
2980 cfg->coverage_info->data [cil_offset].cil_code = ip;
2982 /* TODO: Use an increment here */
2983 NEW_ICONST (cfg, one, 1);
2986 NEW_PCONST (cfg, ins, &(cfg->coverage_info->data [cil_offset].count));
2989 MONO_INST_NEW (cfg, store, CEE_STIND_I);
2990 store->cil_code = ip;
2991 store->inst_left = ins;
2992 store->inst_right = one;
2994 MONO_ADD_INS (bblock, store);
2997 if (cfg->verbose_level > 3)
2998 g_print ("converting (in B%d: stack: %d) %s", bblock->block_num, sp-stack_start, mono_disasm_code_one (NULL, method, ip, NULL));
3005 MONO_INST_NEW (cfg, ins, CEE_BREAK);
3006 ins->cil_code = ip++;
3007 MONO_ADD_INS (bblock, ins);
3013 CHECK_STACK_OVF (1);
3014 n = (*ip)-CEE_LDARG_0;
3016 NEW_ARGLOAD (cfg, ins, n);
3017 ins->cil_code = ip++;
3024 CHECK_STACK_OVF (1);
3025 n = (*ip)-CEE_LDLOC_0;
3027 NEW_LOCLOAD (cfg, ins, n);
3028 ins->cil_code = ip++;
3036 n = (*ip)-CEE_STLOC_0;
3039 handle_loaded_temps (cfg, bblock, stack_start, sp);
3040 NEW_LOCSTORE (cfg, ins, n, *sp);
3042 if (ins->opcode == CEE_STOBJ) {
3043 NEW_LOCLOADA (cfg, ins, n);
3044 handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE);
3046 MONO_ADD_INS (bblock, ins);
3052 CHECK_STACK_OVF (1);
3054 NEW_ARGLOAD (cfg, ins, ip [1]);
3061 CHECK_STACK_OVF (1);
3063 NEW_ARGLOADA (cfg, ins, ip [1]);
3073 NEW_ARGSTORE (cfg, ins, ip [1], *sp);
3074 handle_loaded_temps (cfg, bblock, stack_start, sp);
3076 if (ins->opcode == CEE_STOBJ) {
3077 NEW_ARGLOADA (cfg, ins, ip [1]);
3078 handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE);
3080 MONO_ADD_INS (bblock, ins);
3085 CHECK_STACK_OVF (1);
3086 CHECK_LOCAL (ip [1]);
3087 NEW_LOCLOAD (cfg, ins, ip [1]);
3094 CHECK_STACK_OVF (1);
3095 CHECK_LOCAL (ip [1]);
3096 NEW_LOCLOADA (cfg, ins, ip [1]);
3105 handle_loaded_temps (cfg, bblock, stack_start, sp);
3106 CHECK_LOCAL (ip [1]);
3107 NEW_LOCSTORE (cfg, ins, ip [1], *sp);
3109 if (ins->opcode == CEE_STOBJ) {
3110 NEW_LOCLOADA (cfg, ins, ip [1]);
3111 handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE);
3113 MONO_ADD_INS (bblock, ins);
3118 CHECK_STACK_OVF (1);
3119 NEW_PCONST (cfg, ins, NULL);
3121 ins->type = STACK_OBJ;
3126 CHECK_STACK_OVF (1);
3127 NEW_ICONST (cfg, ins, -1);
3141 CHECK_STACK_OVF (1);
3142 NEW_ICONST (cfg, ins, (*ip) - CEE_LDC_I4_0);
3149 CHECK_STACK_OVF (1);
3151 NEW_ICONST (cfg, ins, *((signed char*)ip));
3158 CHECK_STACK_OVF (1);
3159 NEW_ICONST (cfg, ins, (gint32)read32 (ip + 1));
3166 CHECK_STACK_OVF (1);
3167 MONO_INST_NEW (cfg, ins, OP_I8CONST);
3169 ins->type = STACK_I8;
3171 ins->inst_l = (gint64)read64 (ip);
3176 float *f = mono_mempool_alloc (cfg->domain->mp, sizeof (float));
3178 CHECK_STACK_OVF (1);
3179 MONO_INST_NEW (cfg, ins, OP_R4CONST);
3180 ins->type = STACK_R8;
3189 double *d = mono_mempool_alloc (cfg->domain->mp, sizeof (double));
3191 CHECK_STACK_OVF (1);
3192 MONO_INST_NEW (cfg, ins, OP_R8CONST);
3193 ins->type = STACK_R8;
3202 MonoInst *temp, *store;
3204 CHECK_STACK_OVF (1);
3209 * small optimization: if the loaded value was from a local already,
3210 * just load it twice.
3212 if (ins->ssa_op == MONO_SSA_LOAD &&
3213 (ins->inst_i0->opcode == OP_LOCAL || ins->inst_i0->opcode == OP_ARG)) {
3215 MONO_INST_NEW (cfg, temp, 0);
3217 temp->cil_code = ip;
3220 temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
3221 temp->cil_code = ip;
3222 NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
3223 store->cil_code = ip;
3224 MONO_ADD_INS (bblock, store);
3225 NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
3228 NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
3238 MONO_INST_NEW (cfg, ins, CEE_POP);
3239 MONO_ADD_INS (bblock, ins);
3240 ins->cil_code = ip++;
3246 if (stack_start != sp)
3248 MONO_INST_NEW (cfg, ins, CEE_JMP);
3249 token = read32 (ip + 1);
3250 /* FIXME: check the signature matches */
3251 cmethod = mono_get_method_full (image, token, NULL, generic_context);
3252 ins->inst_p0 = cmethod;
3253 MONO_ADD_INS (bblock, ins);
3255 start_new_bblock = 1;
3259 case CEE_CALLVIRT: {
3260 MonoInst *addr = NULL;
3261 MonoMethodSignature *fsig = NULL;
3262 int temp, array_rank = 0;
3263 int virtual = *ip == CEE_CALLVIRT;
3266 token = read32 (ip + 1);
3268 if (*ip == CEE_CALLI) {
3273 if (method->wrapper_type != MONO_WRAPPER_NONE)
3274 fsig = (MonoMethodSignature *)mono_method_get_wrapper_data (method, token);
3276 fsig = mono_metadata_parse_signature (image, token);
3278 n = fsig->param_count + fsig->hasthis;
3280 if (method->wrapper_type != MONO_WRAPPER_NONE) {
3281 cmethod = (MonoMethod *)mono_method_get_wrapper_data (method, token);
3282 } else if (constrained_call) {
3283 cmethod = mono_get_method_constrained (image, token, constrained_call, generic_context);
3285 cmethod = mono_get_method_full (image, token, NULL, generic_context);
3290 if (!cmethod->klass->inited)
3291 mono_class_init (cmethod->klass);
3293 if (cmethod->signature->pinvoke) {
3294 MonoMethod *wrapper = mono_marshal_get_native_wrapper (cmethod);
3295 fsig = wrapper->signature;
3297 fsig = mono_method_get_signature (cmethod, image, token);
3300 n = fsig->param_count + fsig->hasthis;
3302 if (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL &&
3303 cmethod->klass->parent == mono_defaults.array_class) {
3304 array_rank = cmethod->klass->rank;
3307 if (cmethod->string_ctor)
3308 g_assert_not_reached ();
3314 //g_assert (!virtual || fsig->hasthis);
3318 if (constrained_call) {
3320 * We have the `constrained.' prefix opcode.
3322 if (constrained_call->valuetype && !cmethod->klass->valuetype) {
3325 * The type parameter is instantiated as a valuetype,
3326 * but that type doesn't override the method we're
3327 * calling, so we need to box `this'.
3328 * sp [0] is a pointer to the data: we need the value
3329 * in handle_box (), so load it here.
3331 MONO_INST_NEW (cfg, load, mono_type_to_ldind (&constrained_call->byval_arg));
3332 type_to_eval_stack_type (&constrained_call->byval_arg, load);
3333 load->cil_code = ip;
3334 load->inst_left = sp [0];
3335 sp [0] = handle_box (cfg, bblock, load, ip, constrained_call);
3336 } else if (!constrained_call->valuetype) {
3340 * The type parameter is instantiated as a reference
3341 * type. We have a managed pointer on the stack, so
3342 * we need to dereference it here.
3345 MONO_INST_NEW (cfg, ins, CEE_LDIND_REF);
3347 ins->inst_i0 = sp [0];
3348 ins->type = STACK_OBJ;
3350 } else if (cmethod->klass->valuetype)
3352 constrained_call = NULL;
3355 if (*ip != CEE_CALLI && check_call_signature (cfg, fsig, sp))
3358 if ((ins_flag & MONO_INST_TAILCALL) && cmethod && (*ip == CEE_CALL) && (mono_metadata_signature_equal (method->signature, cmethod->signature))) {
3360 /* FIXME: This assumes the two methods has the same number and type of arguments */
3361 for (i = 0; i < n; ++i) {
3362 /* Check if argument is the same */
3363 NEW_ARGLOAD (cfg, ins, i);
3364 if ((ins->opcode == sp [i]->opcode) && (ins->inst_i0 == sp [i]->inst_i0))
3367 /* Prevent argument from being register allocated */
3368 arg_array [i]->flags |= MONO_INST_VOLATILE;
3369 NEW_ARGSTORE (cfg, ins, i, sp [i]);
3371 if (ins->opcode == CEE_STOBJ) {
3372 NEW_ARGLOADA (cfg, ins, i);
3373 handle_stobj (cfg, bblock, ins, sp [i], sp [i]->cil_code, ins->klass, FALSE, FALSE);
3376 MONO_ADD_INS (bblock, ins);
3378 MONO_INST_NEW (cfg, ins, CEE_JMP);
3380 ins->inst_p0 = cmethod;
3381 ins->inst_p1 = arg_array [0];
3382 MONO_ADD_INS (bblock, ins);
3383 start_new_bblock = 1;
3384 /* skip CEE_RET as well */
3389 if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_get_opcode_for_method (cfg, cmethod, fsig, sp))) {
3392 if (MONO_TYPE_IS_VOID (fsig->ret)) {
3393 MONO_ADD_INS (bblock, ins);
3395 type_to_eval_stack_type (fsig->ret, ins);
3404 handle_loaded_temps (cfg, bblock, stack_start, sp);
3406 if ((cfg->opt & MONO_OPT_INLINE) && cmethod &&
3407 (!virtual || !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) || (cmethod->flags & METHOD_ATTRIBUTE_FINAL)) &&
3408 mono_method_check_inlining (cfg, cmethod) &&
3409 !g_list_find (dont_inline, cmethod)) {
3411 MonoBasicBlock *ebblock;
3412 gboolean allways = FALSE;
3414 if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
3415 (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
3416 cmethod = mono_marshal_get_native_wrapper (cmethod);
3420 if ((costs = inline_method (cfg, cmethod, fsig, bblock, sp, ip, real_offset, dont_inline, &ebblock, allways))) {
3424 GET_BBLOCK (cfg, bbhash, bblock, ip);
3425 ebblock->next_bb = bblock;
3426 link_bblock (cfg, ebblock, bblock);
3428 if (!MONO_TYPE_IS_VOID (fsig->ret))
3431 /* indicates start of a new block, and triggers a load of all
3432 stack arguments at bb boundarie */
3435 inline_costs += costs;
3440 inline_costs += 10 * num_calls++;
3442 /* tail recursion elimination */
3443 if ((cfg->opt & MONO_OPT_TAILC) && *ip == CEE_CALL && cmethod == method && ip [5] == CEE_RET) {
3444 gboolean has_vtargs = FALSE;
3447 /* keep it simple */
3448 for (i = fsig->param_count - 1; i >= 0; i--) {
3449 if (MONO_TYPE_ISSTRUCT (cmethod->signature->params [i]))
3454 for (i = 0; i < n; ++i) {
3455 NEW_ARGSTORE (cfg, ins, i, sp [i]);
3457 MONO_ADD_INS (bblock, ins);
3459 MONO_INST_NEW (cfg, ins, CEE_BR);
3461 MONO_ADD_INS (bblock, ins);
3462 tblock = start_bblock->out_bb [0];
3463 link_bblock (cfg, bblock, tblock);
3464 ins->inst_target_bb = tblock;
3465 start_new_bblock = 1;
3468 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
3469 /* just create a dummy - the value is never used */
3470 ins = mono_compile_create_var (cfg, fsig->ret, OP_LOCAL);
3471 NEW_TEMPLOAD (cfg, *sp, ins->inst_c0);
3479 if (*ip == CEE_CALLI) {
3481 if ((temp = mono_emit_calli (cfg, bblock, fsig, sp, addr, ip)) != -1) {
3482 NEW_TEMPLOAD (cfg, *sp, temp);
3486 } else if (array_rank) {
3489 if (strcmp (cmethod->name, "Set") == 0) { /* array Set */
3490 if (sp [fsig->param_count]->type == STACK_OBJ) {
3491 MonoInst *iargs [2];
3492 MonoInst *array, *to_store, *store;
3494 handle_loaded_temps (cfg, bblock, stack_start, sp);
3496 array = mono_compile_create_var (cfg, type_from_stack_type (sp [0]), OP_LOCAL);
3497 NEW_TEMPSTORE (cfg, store, array->inst_c0, sp [0]);
3498 store->cil_code = ip;
3499 MONO_ADD_INS (bblock, store);
3500 NEW_TEMPLOAD (cfg, iargs [0], array->inst_c0);
3502 to_store = mono_compile_create_var (cfg, type_from_stack_type (sp [fsig->param_count]), OP_LOCAL);
3503 NEW_TEMPSTORE (cfg, store, to_store->inst_c0, sp [fsig->param_count]);
3504 store->cil_code = ip;
3505 MONO_ADD_INS (bblock, store);
3506 NEW_TEMPLOAD (cfg, iargs [1], to_store->inst_c0);
3509 * We first save the args for the call so that the args are copied to the stack
3510 * and a new instruction tree for them is created. If we don't do this,
3511 * the same MonoInst is added to two different trees and this is not
3514 mono_emit_jit_icall (cfg, bblock, helper_stelem_ref_check, iargs, ip);
3516 NEW_TEMPLOAD (cfg, sp [0], array->inst_c0);
3517 NEW_TEMPLOAD (cfg, sp [fsig->param_count], to_store->inst_c0);
3520 addr = mini_get_ldelema_ins (cfg, bblock, cmethod, sp, ip, TRUE);
3521 NEW_INDSTORE (cfg, ins, addr, sp [fsig->param_count], fsig->params [fsig->param_count - 1]);
3523 if (ins->opcode == CEE_STOBJ) {
3524 handle_stobj (cfg, bblock, addr, sp [fsig->param_count], ip, mono_class_from_mono_type (fsig->params [fsig->param_count-1]), FALSE, FALSE);
3526 MONO_ADD_INS (bblock, ins);
3529 } else if (strcmp (cmethod->name, "Get") == 0) { /* array Get */
3530 addr = mini_get_ldelema_ins (cfg, bblock, cmethod, sp, ip, FALSE);
3531 NEW_INDLOAD (cfg, ins, addr, fsig->ret);
3535 } else if (strcmp (cmethod->name, "Address") == 0) { /* array Address */
3536 addr = mini_get_ldelema_ins (cfg, bblock, cmethod, sp, ip, FALSE);
3539 g_assert_not_reached ();
3543 if (0 && CODE_IS_STLOC (ip + 5) && (!MONO_TYPE_ISSTRUCT (fsig->ret)) && (!MONO_TYPE_IS_VOID (fsig->ret) || cmethod->string_ctor)) {
3544 /* no need to spill */
3545 ins = (MonoInst*)mono_emit_method_call (cfg, bblock, cmethod, fsig, sp, ip, virtual ? sp [0] : NULL);
3548 if ((temp = mono_emit_method_call_spilled (cfg, bblock, cmethod, fsig, sp, ip, virtual ? sp [0] : NULL)) != -1) {
3549 NEW_TEMPLOAD (cfg, *sp, temp);
3559 if (cfg->method != method) {
3560 /* return from inlined methode */
3565 //g_assert (returnvar != -1);
3566 NEW_TEMPSTORE (cfg, store, return_var->inst_c0, *sp);
3567 store->cil_code = sp [0]->cil_code;
3568 if (store->opcode == CEE_STOBJ) {
3569 g_assert_not_reached ();
3570 NEW_TEMPLOADA (cfg, store, return_var->inst_c0);
3571 handle_stobj (cfg, bblock, store, *sp, sp [0]->cil_code, return_var->klass, FALSE, FALSE);
3573 MONO_ADD_INS (bblock, store);
3577 g_assert (!return_var);
3580 MONO_INST_NEW (cfg, ins, CEE_NOP);
3581 ins->opcode = mono_type_to_stind (method->signature->ret);
3582 if (ins->opcode == CEE_STOBJ) {
3583 NEW_RETLOADA (cfg, ins);
3584 handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE);
3586 ins->opcode = OP_SETRET;
3588 ins->inst_i0 = *sp;;
3589 ins->inst_i1 = NULL;
3590 MONO_ADD_INS (bblock, ins);
3594 if (sp != stack_start)
3596 MONO_INST_NEW (cfg, ins, CEE_BR);
3597 ins->cil_code = ip++;
3598 ins->inst_target_bb = end_bblock;
3599 MONO_ADD_INS (bblock, ins);
3600 link_bblock (cfg, bblock, end_bblock);
3601 start_new_bblock = 1;
3605 MONO_INST_NEW (cfg, ins, CEE_BR);
3606 ins->cil_code = ip++;
3607 MONO_ADD_INS (bblock, ins);
3608 target = ip + 1 + (signed char)(*ip);
3610 GET_BBLOCK (cfg, bbhash, tblock, target);
3611 link_bblock (cfg, bblock, tblock);
3612 CHECK_BBLOCK (target, ip, tblock);
3613 ins->inst_target_bb = tblock;
3614 if (sp != stack_start) {
3615 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
3618 start_new_bblock = 1;
3625 MONO_INST_NEW (cfg, ins, *ip + BIG_BRANCH_OFFSET);
3626 ins->cil_code = ip++;
3627 target = ip + 1 + *(signed char*)ip;
3629 ADD_UNCOND (ins->opcode == CEE_BRTRUE);
3630 if (sp != stack_start) {
3631 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
3648 MONO_INST_NEW (cfg, ins, *ip + BIG_BRANCH_OFFSET);
3649 ins->cil_code = ip++;
3650 target = ip + 1 + *(signed char*)ip;
3653 if (sp != stack_start) {
3654 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
3661 MONO_INST_NEW (cfg, ins, CEE_BR);
3662 ins->cil_code = ip++;
3663 MONO_ADD_INS (bblock, ins);
3664 target = ip + 4 + (gint32)read32(ip);
3666 GET_BBLOCK (cfg, bbhash, tblock, target);
3667 link_bblock (cfg, bblock, tblock);
3668 CHECK_BBLOCK (target, ip, tblock);
3669 ins->inst_target_bb = tblock;
3670 if (sp != stack_start) {
3671 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
3674 start_new_bblock = 1;
3681 MONO_INST_NEW (cfg, ins, *ip);
3682 ins->cil_code = ip++;
3683 target = ip + 4 + (gint32)read32(ip);
3685 ADD_UNCOND(ins->opcode == CEE_BRTRUE);
3686 if (sp != stack_start) {
3687 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
3704 MONO_INST_NEW (cfg, ins, *ip);
3705 ins->cil_code = ip++;
3706 target = ip + 4 + (gint32)read32(ip);
3709 if (sp != stack_start) {
3710 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
3718 n = read32 (ip + 1);
3719 MONO_INST_NEW (cfg, ins, *ip);
3721 ins->inst_left = *sp;
3722 if (ins->inst_left->type != STACK_I4) goto unverified;
3725 CHECK_OPSIZE (n * sizeof (guint32));
3726 target = ip + n * sizeof (guint32);
3727 MONO_ADD_INS (bblock, ins);
3728 GET_BBLOCK (cfg, bbhash, tblock, target);
3729 link_bblock (cfg, bblock, tblock);
3730 ins->klass = GUINT_TO_POINTER (n);
3731 ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * (n + 1));
3732 ins->inst_many_bb [n] = tblock;
3734 for (i = 0; i < n; ++i) {
3735 GET_BBLOCK (cfg, bbhash, tblock, target + (gint32)read32(ip));
3736 link_bblock (cfg, bblock, tblock);
3737 ins->inst_many_bb [i] = tblock;
3740 if (sp != stack_start) {
3741 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
3758 MONO_INST_NEW (cfg, ins, *ip);
3763 ins->type = ldind_type [*ip - CEE_LDIND_I1];
3764 ins->flags |= ins_flag;
3776 MONO_INST_NEW (cfg, ins, *ip);
3777 ins->cil_code = ip++;
3779 handle_loaded_temps (cfg, bblock, stack_start, sp);
3780 MONO_ADD_INS (bblock, ins);
3781 ins->inst_i0 = sp [0];
3782 ins->inst_i1 = sp [1];
3783 ins->flags |= ins_flag;
3802 /* special case that gives a nice speedup and happens to workaorund a ppc jit but (for the release)
3803 * later apply the speedup to the left shift as well
3806 if ((ins->opcode == OP_LSHR_UN) && (ins->type == STACK_I8)
3807 && (ins->inst_right->opcode == OP_ICONST) && (ins->inst_right->inst_c0 == 32)) {
3808 ins->opcode = OP_LONG_SHRUN_32;
3809 /*g_print ("applied long shr speedup to %s\n", cfg->method->name);*/
3813 if (mono_find_jit_opcode_emulation (ins->opcode)) {
3815 *sp++ = emit_tree (cfg, bblock, ins);
3829 case CEE_CONV_OVF_I8:
3830 case CEE_CONV_OVF_U8:
3834 if (mono_find_jit_opcode_emulation (ins->opcode)) {
3836 *sp++ = emit_tree (cfg, bblock, ins);
3840 case CEE_CONV_OVF_I4:
3841 case CEE_CONV_OVF_I1:
3842 case CEE_CONV_OVF_I2:
3843 case CEE_CONV_OVF_I:
3844 case CEE_CONV_OVF_U:
3847 if (sp [-1]->type == STACK_R8) {
3848 ADD_UNOP (CEE_CONV_OVF_I8);
3856 case CEE_CONV_OVF_U1:
3857 case CEE_CONV_OVF_U2:
3858 case CEE_CONV_OVF_U4:
3861 if (sp [-1]->type == STACK_R8) {
3862 ADD_UNOP (CEE_CONV_OVF_U8);
3870 case CEE_CONV_OVF_I1_UN:
3871 case CEE_CONV_OVF_I2_UN:
3872 case CEE_CONV_OVF_I4_UN:
3873 case CEE_CONV_OVF_I8_UN:
3874 case CEE_CONV_OVF_U1_UN:
3875 case CEE_CONV_OVF_U2_UN:
3876 case CEE_CONV_OVF_U4_UN:
3877 case CEE_CONV_OVF_U8_UN:
3878 case CEE_CONV_OVF_I_UN:
3879 case CEE_CONV_OVF_U_UN:
3887 token = read32 (ip + 1);
3888 if (method->wrapper_type != MONO_WRAPPER_NONE)
3889 klass = mono_method_get_wrapper_data (method, token);
3891 klass = mono_class_get_full (image, token, generic_context);
3893 mono_class_init (klass);
3895 if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
3896 MonoInst *store, *load;
3897 MONO_INST_NEW (cfg, load, CEE_LDIND_REF);
3898 load->cil_code = ip;
3899 load->inst_i0 = sp [1];
3900 load->type = ldind_type [CEE_LDIND_REF];
3901 load->flags |= ins_flag;
3902 MONO_INST_NEW (cfg, store, CEE_STIND_REF);
3903 store->cil_code = ip;
3904 handle_loaded_temps (cfg, bblock, stack_start, sp);
3905 MONO_ADD_INS (bblock, store);
3906 store->inst_i0 = sp [0];
3907 store->inst_i1 = load;
3908 store->flags |= ins_flag;
3910 n = mono_class_value_size (klass, NULL);
3911 if ((cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 5) {
3913 MONO_INST_NEW (cfg, copy, OP_MEMCPY);
3914 copy->inst_left = sp [0];
3915 copy->inst_right = sp [1];
3916 copy->cil_code = ip;
3918 MONO_ADD_INS (bblock, copy);
3920 MonoInst *iargs [3];
3923 NEW_ICONST (cfg, iargs [2], n);
3924 iargs [2]->cil_code = ip;
3926 mono_emit_jit_icall (cfg, bblock, helper_memcpy, iargs, ip);
3933 MonoInst *iargs [3];
3937 token = read32 (ip + 1);
3938 if (method->wrapper_type != MONO_WRAPPER_NONE)
3939 klass = mono_method_get_wrapper_data (method, token);
3941 klass = mono_class_get_full (image, token, generic_context);
3943 mono_class_init (klass);
3944 if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
3945 MONO_INST_NEW (cfg, ins, CEE_LDIND_REF);
3947 ins->inst_i0 = sp [0];
3948 ins->type = ldind_type [CEE_LDIND_REF];
3949 ins->flags |= ins_flag;
3955 n = mono_class_value_size (klass, NULL);
3956 ins = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
3957 NEW_TEMPLOADA (cfg, iargs [0], ins->inst_c0);
3958 if ((cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 5) {
3960 MONO_INST_NEW (cfg, copy, OP_MEMCPY);
3961 copy->inst_left = iargs [0];
3962 copy->inst_right = *sp;
3963 copy->cil_code = ip;
3965 MONO_ADD_INS (bblock, copy);
3968 NEW_ICONST (cfg, iargs [2], n);
3969 iargs [2]->cil_code = ip;
3971 mono_emit_jit_icall (cfg, bblock, helper_memcpy, iargs, ip);
3973 NEW_TEMPLOAD (cfg, *sp, ins->inst_c0);
3981 CHECK_STACK_OVF (1);
3983 n = read32 (ip + 1);
3985 if (method->wrapper_type != MONO_WRAPPER_NONE) {
3987 MonoInst *iargs [1];
3989 NEW_PCONST (cfg, iargs [0], mono_method_get_wrapper_data (method, n));
3990 temp = mono_emit_jit_icall (cfg, bblock, mono_string_new_wrapper, iargs, ip);
3991 NEW_TEMPLOAD (cfg, *sp, temp);
3995 if (cfg->opt & MONO_OPT_SHARED) {
3997 MonoInst *iargs [3];
3999 if (mono_compile_aot) {
4000 cfg->ldstr_list = g_list_prepend (cfg->ldstr_list, (gpointer)n);
4003 NEW_TEMPLOAD (cfg, iargs [0], mono_get_domainvar (cfg)->inst_c0);
4004 NEW_IMAGECONST (cfg, iargs [1], image);
4005 NEW_ICONST (cfg, iargs [2], mono_metadata_token_index (n));
4006 temp = mono_emit_jit_icall (cfg, bblock, mono_ldstr, iargs, ip);
4007 NEW_TEMPLOAD (cfg, *sp, temp);
4008 mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
4010 if (mono_compile_aot)
4011 NEW_LDSTRCONST (cfg, ins, image, n);
4013 NEW_PCONST (cfg, ins, NULL);
4015 ins->type = STACK_OBJ;
4016 ins->inst_p0 = mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
4026 MonoInst *iargs [2];
4027 MonoMethodSignature *fsig;
4031 token = read32 (ip + 1);
4032 if (method->wrapper_type != MONO_WRAPPER_NONE) {
4033 cmethod = mono_method_get_wrapper_data (method, token);
4035 cmethod = mono_get_method_full (image, token, NULL, generic_context);
4036 fsig = mono_method_get_signature (cmethod, image, token);
4038 mono_class_init (cmethod->klass);
4040 n = fsig->param_count;
4043 /* move the args to allow room for 'this' in the first position */
4049 handle_loaded_temps (cfg, bblock, stack_start, sp);
4052 if (cmethod->klass->parent == mono_defaults.array_class) {
4053 NEW_METHODCONST (cfg, *sp, cmethod);
4054 temp = mono_emit_native_call (cfg, bblock, mono_array_new_va, mono_get_array_new_va_signature (fsig->param_count), sp, ip, FALSE);
4055 cfg->flags |= MONO_CFG_HAS_VARARGS;
4057 } else if (cmethod->string_ctor) {
4058 /* we simply pass a null pointer */
4059 NEW_PCONST (cfg, *sp, NULL);
4060 /* now call the string ctor */
4061 temp = mono_emit_method_call_spilled (cfg, bblock, cmethod, fsig, sp, ip, NULL);
4063 if (cmethod->klass->valuetype) {
4064 iargs [0] = mono_compile_create_var (cfg, &cmethod->klass->byval_arg, OP_LOCAL);
4065 temp = iargs [0]->inst_c0;
4066 NEW_TEMPLOADA (cfg, *sp, temp);
4068 if (cfg->opt & MONO_OPT_SHARED) {
4069 NEW_DOMAINCONST (cfg, iargs [0]);
4070 NEW_CLASSCONST (cfg, iargs [1], cmethod->klass);
4072 temp = mono_emit_jit_icall (cfg, bblock, mono_object_new, iargs, ip);
4074 MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
4075 NEW_VTABLECONST (cfg, iargs [0], vtable);
4076 if (cmethod->klass->has_finalize || cmethod->klass->marshalbyref || (cfg->prof_options & MONO_PROFILE_ALLOCATIONS))
4077 temp = mono_emit_jit_icall (cfg, bblock, mono_object_new_specific, iargs, ip);
4079 temp = mono_emit_jit_icall (cfg, bblock, mono_object_new_fast, iargs, ip);
4081 NEW_TEMPLOAD (cfg, *sp, temp);
4084 if ((cfg->opt & MONO_OPT_INLINE) && cmethod &&
4085 mono_method_check_inlining (cfg, cmethod) &&
4086 !mono_class_is_subclass_of (cmethod->klass, mono_defaults.exception_class, FALSE) &&
4087 !g_list_find (dont_inline, cmethod)) {
4089 MonoBasicBlock *ebblock;
4090 if ((costs = inline_method (cfg, cmethod, fsig, bblock, sp, ip, real_offset, dont_inline, &ebblock, FALSE))) {
4095 GET_BBLOCK (cfg, bbhash, bblock, ip);
4096 ebblock->next_bb = bblock;
4097 link_bblock (cfg, ebblock, bblock);
4099 NEW_TEMPLOAD (cfg, *sp, temp);
4102 /* indicates start of a new block, and triggers a load
4103 of all stack arguments at bb boundarie */
4106 inline_costs += costs;
4110 mono_emit_method_call_spilled (cfg, bblock, cmethod, fsig, sp, ip, sp[0]);
4113 /* now call the actual ctor */
4114 mono_emit_method_call_spilled (cfg, bblock, cmethod, fsig, sp, ip, sp[0]);
4118 NEW_TEMPLOAD (cfg, *sp, temp);
4129 klass = mono_class_get_full (image, read32 (ip + 1), generic_context);
4130 mono_class_init (klass);
4132 if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4134 MonoMethod *mono_isinst;
4135 MonoInst *iargs [1];
4136 MonoBasicBlock *ebblock;
4140 mono_isinst = mono_marshal_get_isinst (klass);
4143 costs = inline_method (cfg, mono_isinst, mono_isinst->signature, bblock,
4144 iargs, ip, real_offset, dont_inline, &ebblock, TRUE);
4146 g_assert (costs > 0);
4151 GET_BBLOCK (cfg, bbhash, bblock, ip);
4152 ebblock->next_bb = bblock;
4153 link_bblock (cfg, ebblock, bblock);
4155 temp = iargs [0]->inst_i0->inst_c0;
4156 NEW_TEMPLOAD (cfg, *sp, temp);
4160 inline_costs += costs;
4164 MONO_INST_NEW (cfg, ins, *ip);
4165 ins->type = STACK_OBJ;
4166 ins->inst_left = *sp;
4167 ins->inst_newa_class = klass;
4169 *sp++ = emit_tree (cfg, bblock, ins);
4173 case CEE_UNBOX_ANY: {
4174 MonoInst *add, *vtoffset;
4175 MonoInst *iargs [3];
4180 token = read32 (ip + 1);
4181 if (method->wrapper_type != MONO_WRAPPER_NONE)
4182 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
4184 klass = mono_class_get_full (image, token, generic_context);
4185 mono_class_init (klass);
4187 if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
4189 if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4190 MonoMethod *mono_castclass;
4191 MonoInst *iargs [1];
4192 MonoBasicBlock *ebblock;
4196 mono_castclass = mono_marshal_get_castclass (klass);
4199 costs = inline_method (cfg, mono_castclass, mono_castclass->signature, bblock,
4200 iargs, ip, real_offset, dont_inline, &ebblock, TRUE);
4202 g_assert (costs > 0);
4207 GET_BBLOCK (cfg, bbhash, bblock, ip);
4208 ebblock->next_bb = bblock;
4209 link_bblock (cfg, ebblock, bblock);
4211 temp = iargs [0]->inst_i0->inst_c0;
4212 NEW_TEMPLOAD (cfg, *sp, temp);
4216 inline_costs += costs;
4219 MONO_INST_NEW (cfg, ins, CEE_CASTCLASS);
4220 ins->type = STACK_OBJ;
4221 ins->inst_left = *sp;
4223 ins->inst_newa_class = klass;
4231 MONO_INST_NEW (cfg, ins, OP_UNBOXCAST);
4232 ins->type = STACK_OBJ;
4233 ins->inst_left = *sp;
4235 ins->inst_newa_class = klass;
4238 MONO_INST_NEW (cfg, add, CEE_ADD);
4239 NEW_ICONST (cfg, vtoffset, sizeof (MonoObject));
4240 add->inst_left = ins;
4241 add->inst_right = vtoffset;
4242 add->type = STACK_MP;
4246 n = mono_class_value_size (klass, NULL);
4247 ins = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
4248 NEW_TEMPLOADA (cfg, iargs [0], ins->inst_c0);
4249 if ((cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 5) {
4251 MONO_INST_NEW (cfg, copy, OP_MEMCPY);
4252 copy->inst_left = iargs [0];
4253 copy->inst_right = *sp;
4254 copy->cil_code = ip;
4256 MONO_ADD_INS (bblock, copy);
4259 NEW_ICONST (cfg, iargs [2], n);
4260 iargs [2]->cil_code = ip;
4262 mono_emit_jit_icall (cfg, bblock, helper_memcpy, iargs, ip);
4264 NEW_TEMPLOAD (cfg, *sp, ins->inst_c0);
4270 MonoInst *add, *vtoffset;
4275 token = read32 (ip + 1);
4276 if (method->wrapper_type != MONO_WRAPPER_NONE)
4277 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
4279 klass = mono_class_get_full (image, token, generic_context);
4280 mono_class_init (klass);
4282 MONO_INST_NEW (cfg, ins, OP_UNBOXCAST);
4283 ins->type = STACK_OBJ;
4284 ins->inst_left = *sp;
4286 ins->inst_newa_class = klass;
4289 MONO_INST_NEW (cfg, add, CEE_ADD);
4290 NEW_ICONST (cfg, vtoffset, sizeof (MonoObject));
4291 add->inst_left = ins;
4292 add->inst_right = vtoffset;
4293 add->type = STACK_MP;
4303 klass = mono_class_get_full (image, read32 (ip + 1), generic_context);
4304 mono_class_init (klass);
4306 if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4308 MonoMethod *mono_castclass;
4309 MonoInst *iargs [1];
4310 MonoBasicBlock *ebblock;
4314 mono_castclass = mono_marshal_get_castclass (klass);
4317 costs = inline_method (cfg, mono_castclass, mono_castclass->signature, bblock,
4318 iargs, ip, real_offset, dont_inline, &ebblock, TRUE);
4320 g_assert (costs > 0);
4325 GET_BBLOCK (cfg, bbhash, bblock, ip);
4326 ebblock->next_bb = bblock;
4327 link_bblock (cfg, ebblock, bblock);
4329 temp = iargs [0]->inst_i0->inst_c0;
4330 NEW_TEMPLOAD (cfg, *sp, temp);
4334 inline_costs += costs;
4337 MONO_INST_NEW (cfg, ins, *ip);
4338 ins->type = STACK_OBJ;
4339 ins->inst_left = *sp;
4341 ins->inst_newa_class = klass;
4343 *sp++ = emit_tree (cfg, bblock, ins);
4349 MONO_INST_NEW (cfg, ins, *ip);
4351 ins->inst_left = *sp;
4352 ins->cil_code = ip++;
4353 MONO_ADD_INS (bblock, ins);
4355 start_new_bblock = 1;
4360 MonoInst *offset_ins;
4361 MonoClassField *field;
4362 MonoBasicBlock *ebblock;
4366 if (*ip == CEE_STFLD) {
4373 // FIXME: enable this test later.
4374 //if (sp [0]->type != STACK_OBJ && sp [0]->type != STACK_MP)
4377 token = read32 (ip + 1);
4378 field = mono_field_from_token (image, token, &klass, generic_context);
4379 mono_class_init (klass);
4381 foffset = klass->valuetype? field->offset - sizeof (MonoObject): field->offset;
4382 /* FIXME: mark instructions for use in SSA */
4383 if (*ip == CEE_STFLD) {
4384 if ((klass->marshalbyref && !MONO_CHECK_THIS (sp [0])) || klass->contextbound) {
4385 MonoMethod *stfld_wrapper = mono_marshal_get_stfld_wrapper (field->type);
4386 MonoInst *iargs [5];
4389 NEW_CLASSCONST (cfg, iargs [1], klass);
4390 NEW_FIELDCONST (cfg, iargs [2], field);
4391 NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) :
4395 if (cfg->opt & MONO_OPT_INLINE) {
4396 costs = inline_method (cfg, stfld_wrapper, stfld_wrapper->signature, bblock,
4397 iargs, ip, real_offset, dont_inline, &ebblock, TRUE);
4398 g_assert (costs > 0);
4403 GET_BBLOCK (cfg, bbhash, bblock, ip);
4404 ebblock->next_bb = bblock;
4405 link_bblock (cfg, ebblock, bblock);
4407 /* indicates start of a new block, and triggers a load
4408 of all stack arguments at bb boundarie */
4411 inline_costs += costs;
4414 mono_emit_method_call_spilled (cfg, bblock, stfld_wrapper, stfld_wrapper->signature, iargs, ip, NULL);
4418 NEW_ICONST (cfg, offset_ins, foffset);
4419 MONO_INST_NEW (cfg, ins, CEE_ADD);
4421 ins->inst_left = *sp;
4422 ins->inst_right = offset_ins;
4423 ins->type = STACK_MP;
4425 MONO_INST_NEW (cfg, store, mono_type_to_stind (field->type));
4426 store->cil_code = ip;
4427 store->inst_left = ins;
4428 store->inst_right = sp [1];
4429 handle_loaded_temps (cfg, bblock, stack_start, sp);
4430 store->flags |= ins_flag;
4432 if (store->opcode == CEE_STOBJ) {
4433 handle_stobj (cfg, bblock, ins, sp [1], ip,
4434 mono_class_from_mono_type (field->type), FALSE, FALSE);
4436 MONO_ADD_INS (bblock, store);
4439 if ((klass->marshalbyref && !MONO_CHECK_THIS (sp [0])) || klass->contextbound) {
4440 /* fixme: we need to inline that call somehow */
4441 MonoMethod *ldfld_wrapper = mono_marshal_get_ldfld_wrapper (field->type);
4442 MonoInst *iargs [4];
4446 NEW_CLASSCONST (cfg, iargs [1], klass);
4447 NEW_FIELDCONST (cfg, iargs [2], field);
4448 NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : field->offset);
4449 if (cfg->opt & MONO_OPT_INLINE) {
4450 costs = inline_method (cfg, ldfld_wrapper, ldfld_wrapper->signature, bblock,
4451 iargs, ip, real_offset, dont_inline, &ebblock, TRUE);
4452 g_assert (costs > 0);
4457 GET_BBLOCK (cfg, bbhash, bblock, ip);
4458 ebblock->next_bb = bblock;
4459 link_bblock (cfg, ebblock, bblock);
4461 temp = iargs [0]->inst_i0->inst_c0;
4463 if (*ip == CEE_LDFLDA) {
4464 /* not sure howto handle this */
4465 NEW_TEMPLOADA (cfg, *sp, temp);
4467 NEW_TEMPLOAD (cfg, *sp, temp);
4471 /* indicates start of a new block, and triggers a load of
4472 all stack arguments at bb boundarie */
4475 inline_costs += costs;
4478 temp = mono_emit_method_call_spilled (cfg, bblock, ldfld_wrapper, ldfld_wrapper->signature, iargs, ip, NULL);
4479 if (*ip == CEE_LDFLDA) {
4480 /* not sure howto handle this */
4481 NEW_TEMPLOADA (cfg, *sp, temp);
4483 NEW_TEMPLOAD (cfg, *sp, temp);
4488 NEW_ICONST (cfg, offset_ins, foffset);
4489 MONO_INST_NEW (cfg, ins, CEE_ADD);
4491 ins->inst_left = *sp;
4492 ins->inst_right = offset_ins;
4493 ins->type = STACK_MP;
4495 if (*ip == CEE_LDFLDA) {
4499 MONO_INST_NEW (cfg, load, mono_type_to_ldind (field->type));
4500 type_to_eval_stack_type (field->type, load);
4501 load->cil_code = ip;
4502 load->inst_left = ins;
4503 load->flags |= ins_flag;
4515 MonoClassField *field;
4516 gpointer addr = NULL;
4519 token = read32 (ip + 1);
4521 field = mono_field_from_token (image, token, &klass, generic_context);
4522 mono_class_init (klass);
4524 if ((*ip) == CEE_STSFLD)
4525 handle_loaded_temps (cfg, bblock, stack_start, sp);
4527 if (cfg->domain->special_static_fields)
4528 addr = g_hash_table_lookup (cfg->domain->special_static_fields, field);
4530 if ((cfg->opt & MONO_OPT_SHARED) || (mono_compile_aot && addr)) {
4532 MonoInst *iargs [2];
4533 g_assert (field->parent);
4534 NEW_TEMPLOAD (cfg, iargs [0], mono_get_domainvar (cfg)->inst_c0);
4535 NEW_FIELDCONST (cfg, iargs [1], field);
4536 temp = mono_emit_jit_icall (cfg, bblock, mono_class_static_field_address, iargs, ip);
4537 NEW_TEMPLOAD (cfg, ins, temp);
4540 vtable = mono_class_vtable (cfg->domain, klass);
4542 if ((!vtable->initialized || mono_compile_aot) && !(klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) && mono_class_needs_cctor_run (klass, method)) {
4543 guint8 *tramp = mono_create_class_init_trampoline (vtable);
4544 mono_emit_native_call (cfg, bblock, tramp,
4545 helper_sig_class_init_trampoline,
4547 if (cfg->verbose_level > 2)
4548 g_print ("class %s.%s needs init call for %s\n", klass->name_space, klass->name, field->name);
4550 if (cfg->run_cctors)
4551 mono_runtime_class_init (vtable);
4553 addr = (char*)vtable->data + field->offset;
4555 if (mono_compile_aot)
4556 NEW_SFLDACONST (cfg, ins, field);
4558 NEW_PCONST (cfg, ins, addr);
4562 * insert call to mono_threads_get_static_data (GPOINTER_TO_UINT (addr))
4563 * This could be later optimized to do just a couple of
4564 * memory dereferences with constant offsets.
4567 MonoInst *iargs [1];
4568 NEW_ICONST (cfg, iargs [0], GPOINTER_TO_UINT (addr));
4569 temp = mono_emit_jit_icall (cfg, bblock, mono_get_special_static_data, iargs, ip);
4570 NEW_TEMPLOAD (cfg, ins, temp);
4574 /* FIXME: mark instructions for use in SSA */
4575 if (*ip == CEE_LDSFLDA) {
4577 } else if (*ip == CEE_STSFLD) {
4581 MONO_INST_NEW (cfg, store, mono_type_to_stind (field->type));
4582 store->cil_code = ip;
4583 store->inst_left = ins;
4584 store->inst_right = sp [0];
4585 store->flags |= ins_flag;
4588 if (store->opcode == CEE_STOBJ) {
4589 handle_stobj (cfg, bblock, ins, sp [0], ip, mono_class_from_mono_type (field->type), FALSE, FALSE);
4591 MONO_ADD_INS (bblock, store);
4593 gboolean is_const = FALSE;
4594 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
4595 if (!((cfg->opt & MONO_OPT_SHARED) || mono_compile_aot) &&
4596 vtable->initialized && (field->type->attrs & FIELD_ATTRIBUTE_INIT_ONLY)) {
4597 gpointer addr = (char*)vtable->data + field->offset;
4598 /* g_print ("RO-FIELD %s.%s:%s\n", klass->name_space, klass->name, field->name);*/
4600 switch (field->type->type) {
4601 case MONO_TYPE_BOOLEAN:
4603 NEW_ICONST (cfg, *sp, *((guint8 *)addr));
4607 NEW_ICONST (cfg, *sp, *((gint8 *)addr));
4610 case MONO_TYPE_CHAR:
4612 NEW_ICONST (cfg, *sp, *((guint16 *)addr));
4616 NEW_ICONST (cfg, *sp, *((gint16 *)addr));
4621 NEW_ICONST (cfg, *sp, *((gint32 *)addr));
4625 NEW_ICONST (cfg, *sp, *((guint32 *)addr));
4630 case MONO_TYPE_STRING:
4631 case MONO_TYPE_OBJECT:
4632 case MONO_TYPE_CLASS:
4633 case MONO_TYPE_SZARRAY:
4635 case MONO_TYPE_FNPTR:
4636 case MONO_TYPE_ARRAY:
4637 NEW_PCONST (cfg, *sp, *((gpointer *)addr));
4638 type_to_eval_stack_type (field->type, *sp);
4643 MONO_INST_NEW (cfg, *sp, OP_I8CONST);
4644 sp [0]->type = STACK_I8;
4645 sp [0]->inst_l = *((gint64 *)addr);
4650 case MONO_TYPE_VALUETYPE:
4659 CHECK_STACK_OVF (1);
4660 MONO_INST_NEW (cfg, load, mono_type_to_ldind (field->type));
4661 type_to_eval_stack_type (field->type, load);
4662 load->cil_code = ip;
4663 load->inst_left = ins;
4665 load->flags |= ins_flag;
4667 /* fixme: dont see the problem why this does not work */
4668 //cfg->disable_aot = TRUE;
4678 token = read32 (ip + 1);
4679 if (method->wrapper_type != MONO_WRAPPER_NONE)
4680 klass = mono_method_get_wrapper_data (method, token);
4682 klass = mono_class_get_full (image, token, generic_context);
4683 mono_class_init (klass);
4684 n = mono_type_to_stind (&klass->byval_arg);
4685 if (n == CEE_STOBJ) {
4686 handle_stobj (cfg, bblock, sp [0], sp [1], ip, klass, FALSE, FALSE);
4688 /* FIXME: should check item at sp [1] is compatible with the type of the store. */
4690 MONO_INST_NEW (cfg, store, n);
4691 store->cil_code = ip;
4692 store->inst_left = sp [0];
4693 store->inst_right = sp [1];
4694 store->flags |= ins_flag;
4695 MONO_ADD_INS (bblock, store);
4707 token = read32 (ip + 1);
4708 if (method->wrapper_type != MONO_WRAPPER_NONE)
4709 klass = mono_method_get_wrapper_data (method, token);
4711 klass = mono_class_get_full (image, token, generic_context);
4712 mono_class_init (klass);
4714 if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
4719 *sp++ = handle_box (cfg, bblock, val, ip, klass);
4726 MONO_INST_NEW (cfg, ins, *ip);
4731 token = read32 (ip + 1);
4733 /* allocate the domainvar - becaus this is used in decompose_foreach */
4734 if (cfg->opt & MONO_OPT_SHARED)
4735 mono_get_domainvar (cfg);
4737 if (method->wrapper_type != MONO_WRAPPER_NONE)
4738 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
4740 klass = mono_class_get_full (image, token, generic_context);
4742 mono_class_init (klass);
4743 ins->inst_newa_class = klass;
4744 ins->inst_newa_len = *sp;
4745 ins->type = STACK_OBJ;
4749 * we store the object so calls to create the array are not interleaved
4750 * with the arguments of other calls.
4753 MonoInst *store, *temp, *load;
4755 temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
4756 NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
4757 store->cil_code = ins->cil_code;
4758 MONO_ADD_INS (bblock, store);
4759 NEW_TEMPLOAD (cfg, load, temp->inst_c0);
4760 load->cil_code = ins->cil_code;
4767 MONO_INST_NEW (cfg, ins, *ip);
4768 ins->cil_code = ip++;
4770 ins->inst_left = *sp;
4771 ins->type = STACK_PTR;
4779 if (method->wrapper_type != MONO_WRAPPER_NONE)
4780 klass = (MonoClass*)mono_method_get_wrapper_data (method, read32 (ip + 1));
4782 klass = mono_class_get_full (image, read32 (ip + 1), generic_context);
4783 mono_class_init (klass);
4784 NEW_LDELEMA (cfg, ins, sp, klass);
4794 token = read32 (ip + 1);
4795 klass = mono_class_get_full (image, token, generic_context);
4796 mono_class_init (klass);
4797 NEW_LDELEMA (cfg, load, sp, klass);
4798 load->cil_code = ip;
4799 MONO_INST_NEW (cfg, ins, mono_type_to_ldind (&klass->byval_arg));
4801 ins->inst_left = load;
4803 type_to_eval_stack_type (&klass->byval_arg, ins);
4817 case CEE_LDELEM_REF: {
4821 * ldind.x (ldelema (array, index))
4822 * ldelema does the bounds check
4826 klass = array_access_to_klass (*ip);
4827 NEW_LDELEMA (cfg, load, sp, klass);
4828 load->cil_code = ip;
4829 MONO_INST_NEW (cfg, ins, ldelem_to_ldind [*ip - CEE_LDELEM_I1]);
4831 ins->inst_left = load;
4833 ins->type = ldind_type [ins->opcode - CEE_LDIND_I1];
4843 case CEE_STELEM_R8: {
4847 * stind.x (ldelema (array, index), val)
4848 * ldelema does the bounds check
4852 klass = array_access_to_klass (*ip);
4853 NEW_LDELEMA (cfg, load, sp, klass);
4854 load->cil_code = ip;
4855 MONO_INST_NEW (cfg, ins, stelem_to_stind [*ip - CEE_STELEM_I]);
4857 ins->inst_left = load;
4858 ins->inst_right = sp [2];
4860 handle_loaded_temps (cfg, bblock, stack_start, sp);
4861 MONO_ADD_INS (bblock, ins);
4869 * stind.x (ldelema (array, index), val)
4870 * ldelema does the bounds check
4875 token = read32 (ip + 1);
4876 klass = mono_class_get_full (image, token, generic_context);
4877 mono_class_init (klass);
4878 if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
4879 MonoMethod* helper = mono_marshal_get_stelemref ();
4880 MonoInst *iargs [3];
4881 handle_loaded_temps (cfg, bblock, stack_start, sp);
4887 mono_emit_method_call_spilled (cfg, bblock, helper, helper->signature, iargs, ip, NULL);
4889 NEW_LDELEMA (cfg, load, sp, klass);
4890 load->cil_code = ip;
4892 n = mono_type_to_stind (&klass->byval_arg);
4894 handle_stobj (cfg, bblock, load, sp [2], ip, klass, FALSE, FALSE);
4896 MONO_INST_NEW (cfg, ins, n);
4898 ins->inst_left = load;
4899 ins->inst_right = sp [2];
4900 handle_loaded_temps (cfg, bblock, stack_start, sp);
4901 MONO_ADD_INS (bblock, ins);
4908 case CEE_STELEM_REF: {
4909 MonoInst *iargs [3];
4910 MonoMethod* helper = mono_marshal_get_stelemref ();
4915 handle_loaded_temps (cfg, bblock, stack_start, sp);
4921 mono_emit_method_call_spilled (cfg, bblock, helper, helper->signature, iargs, ip, NULL);
4925 NEW_GROUP (cfg, group, sp [0], sp [1]);
4926 MONO_INST_NEW (cfg, ins, CEE_STELEM_REF);
4928 ins->inst_left = group;
4929 ins->inst_right = sp [2];
4930 MONO_ADD_INS (bblock, ins);
4937 case CEE_CKFINITE: {
4938 MonoInst *store, *temp;
4941 /* this instr. can throw exceptions as side effect,
4942 * so we cant eliminate dead code which contains CKFINITE opdodes.
4943 * Spilling to memory makes sure that we always perform
4947 MONO_INST_NEW (cfg, ins, CEE_CKFINITE);
4949 ins->inst_left = sp [-1];
4950 temp = mono_compile_create_var (cfg, &mono_defaults.double_class->byval_arg, OP_LOCAL);
4952 NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
4953 store->cil_code = ip;
4954 MONO_ADD_INS (bblock, store);
4956 NEW_TEMPLOAD (cfg, sp [-1], temp->inst_c0);
4963 MONO_INST_NEW (cfg, ins, *ip);
4966 klass = mono_class_get_full (image, read32 (ip + 1), generic_context);
4967 mono_class_init (klass);
4968 ins->type = STACK_MP;
4969 ins->inst_left = *sp;
4971 ins->inst_newa_class = klass;
4976 case CEE_MKREFANY: {
4977 MonoInst *loc, *klassconst;
4980 MONO_INST_NEW (cfg, ins, *ip);
4983 klass = mono_class_get_full (image, read32 (ip + 1), generic_context);
4984 mono_class_init (klass);
4987 loc = mono_compile_create_var (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL);
4988 NEW_TEMPLOADA (cfg, ins->inst_right, loc->inst_c0);
4990 NEW_PCONST (cfg, klassconst, klass);
4991 NEW_GROUP (cfg, ins->inst_left, *sp, klassconst);
4993 MONO_ADD_INS (bblock, ins);
4995 NEW_TEMPLOAD (cfg, *sp, loc->inst_c0);
5002 MonoClass *handle_class;
5004 CHECK_STACK_OVF (1);
5007 n = read32 (ip + 1);
5009 handle = mono_ldtoken (image, n, &handle_class, generic_context);
5010 mono_class_init (handle_class);
5012 if (cfg->opt & MONO_OPT_SHARED) {
5014 MonoInst *res, *store, *addr, *vtvar, *iargs [2];
5016 vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL);
5018 NEW_IMAGECONST (cfg, iargs [0], image);
5019 NEW_ICONST (cfg, iargs [1], n);
5020 temp = mono_emit_jit_icall (cfg, bblock, mono_ldtoken_wrapper, iargs, ip);
5021 NEW_TEMPLOAD (cfg, res, temp);
5022 NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
5023 NEW_INDSTORE (cfg, store, addr, res, &mono_defaults.int_class->byval_arg);
5024 MONO_ADD_INS (bblock, store);
5025 NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
5027 if ((ip [5] == CEE_CALL) && (cmethod = mono_get_method_full (image, read32 (ip + 6), NULL, generic_context)) &&
5028 (cmethod->klass == mono_defaults.monotype_class->parent) &&
5029 (strcmp (cmethod->name, "GetTypeFromHandle") == 0) &&
5030 ((g_hash_table_lookup (bbhash, ip + 5) == NULL) ||
5031 (g_hash_table_lookup (bbhash, ip + 5) == bblock))) {
5032 MonoClass *tclass = mono_class_from_mono_type (handle);
5033 mono_class_init (tclass);
5034 if (mono_compile_aot)
5035 NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, image, n);
5037 NEW_PCONST (cfg, ins, mono_type_get_object (cfg->domain, handle));
5038 ins->type = STACK_OBJ;
5039 ins->klass = cmethod->klass;
5042 MonoInst *store, *addr, *vtvar;
5044 if (mono_compile_aot)
5045 NEW_LDTOKENCONST (cfg, ins, image, n);
5047 NEW_PCONST (cfg, ins, handle);
5048 vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL);
5049 NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
5050 NEW_INDSTORE (cfg, store, addr, ins, &mono_defaults.int_class->byval_arg);
5051 MONO_ADD_INS (bblock, store);
5052 NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
5068 case CEE_ADD_OVF_UN:
5070 case CEE_MUL_OVF_UN:
5072 case CEE_SUB_OVF_UN:
5075 if (mono_find_jit_opcode_emulation (ins->opcode)) {
5077 *sp++ = emit_tree (cfg, bblock, ins);
5081 case CEE_ENDFINALLY:
5082 MONO_INST_NEW (cfg, ins, *ip);
5083 MONO_ADD_INS (bblock, ins);
5084 ins->cil_code = ip++;
5085 start_new_bblock = 1;
5088 * Control will leave the method so empty the stack, otherwise
5089 * the next basic block will start with a nonempty stack.
5091 while (sp != stack_start) {
5092 MONO_INST_NEW (cfg, ins, CEE_POP);
5096 MONO_ADD_INS (bblock, ins);
5102 if (*ip == CEE_LEAVE) {
5104 target = ip + 5 + (gint32)read32(ip + 1);
5107 target = ip + 2 + (signed char)(ip [1]);
5110 /* empty the stack */
5111 while (sp != stack_start) {
5112 MONO_INST_NEW (cfg, ins, CEE_POP);
5116 MONO_ADD_INS (bblock, ins);
5120 * If this leave statement is in a catch block, check for a
5121 * pending exception, and rethrow it if necessary.
5123 for (i = 0; i < header->num_clauses; ++i) {
5124 MonoExceptionClause *clause = &header->clauses [i];
5125 if (MONO_OFFSET_IN_HANDLER (clause, ip - header->code)) {
5128 temp = mono_emit_jit_icall (cfg, bblock, mono_thread_get_pending_exception, NULL, ip);
5129 NEW_TEMPLOAD (cfg, *sp, temp);
5131 MONO_INST_NEW (cfg, ins, OP_THROW_OR_NULL);
5132 ins->inst_left = *sp;
5134 MONO_ADD_INS (bblock, ins);
5138 /* fixme: call fault handler ? */
5140 if ((handlers = mono_find_final_block (cfg, ip, target, MONO_EXCEPTION_CLAUSE_FINALLY))) {
5142 for (tmp = handlers; tmp; tmp = tmp->next) {
5144 link_bblock (cfg, bblock, tblock);
5145 MONO_INST_NEW (cfg, ins, OP_CALL_HANDLER);
5147 ins->inst_target_bb = tblock;
5148 MONO_ADD_INS (bblock, ins);
5150 g_list_free (handlers);
5153 MONO_INST_NEW (cfg, ins, CEE_BR);
5155 MONO_ADD_INS (bblock, ins);
5156 GET_BBLOCK (cfg, bbhash, tblock, target);
5157 link_bblock (cfg, bblock, tblock);
5158 CHECK_BBLOCK (target, ip, tblock);
5159 ins->inst_target_bb = tblock;
5160 start_new_bblock = 1;
5162 if (*ip == CEE_LEAVE)
5171 MONO_INST_NEW (cfg, ins, *ip);
5173 handle_loaded_temps (cfg, bblock, stack_start, sp);
5174 MONO_ADD_INS (bblock, ins);
5175 ins->cil_code = ip++;
5176 ins->inst_i0 = sp [0];
5177 ins->inst_i1 = sp [1];
5185 /* trampoline mono specific opcodes */
5186 case MONO_CUSTOM_PREFIX: {
5188 g_assert (method->wrapper_type != MONO_WRAPPER_NONE);
5193 case CEE_MONO_ICALL: {
5196 MonoJitICallInfo *info;
5198 token = read32 (ip + 2);
5199 func = mono_method_get_wrapper_data (method, token);
5200 info = mono_find_jit_icall_by_addr (func);
5203 CHECK_STACK (info->sig->param_count);
5204 sp -= info->sig->param_count;
5206 temp = mono_emit_jit_icall (cfg, bblock, info->func, sp, ip);
5207 if (!MONO_TYPE_IS_VOID (info->sig->ret)) {
5208 NEW_TEMPLOAD (cfg, *sp, temp);
5213 inline_costs += 10 * num_calls++;
5217 case CEE_MONO_LDPTR:
5218 CHECK_STACK_OVF (1);
5220 token = read32 (ip + 2);
5221 NEW_PCONST (cfg, ins, mono_method_get_wrapper_data (method, token));
5225 inline_costs += 10 * num_calls++;
5227 case CEE_MONO_VTADDR:
5230 MONO_INST_NEW (cfg, ins, OP_VTADDR);
5232 ins->type = STACK_MP;
5233 ins->inst_left = *sp;
5237 case CEE_MONO_NEWOBJ: {
5238 MonoInst *iargs [2];
5240 CHECK_STACK_OVF (1);
5242 token = read32 (ip + 2);
5243 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
5244 mono_class_init (klass);
5245 NEW_DOMAINCONST (cfg, iargs [0]);
5246 NEW_CLASSCONST (cfg, iargs [1], klass);
5247 temp = mono_emit_jit_icall (cfg, bblock, mono_object_new, iargs, ip);
5248 NEW_TEMPLOAD (cfg, *sp, temp);
5251 inline_costs += 10 * num_calls++;
5254 case CEE_MONO_OBJADDR:
5257 MONO_INST_NEW (cfg, ins, OP_OBJADDR);
5259 ins->type = STACK_MP;
5260 ins->inst_left = *sp;
5264 case CEE_MONO_LDNATIVEOBJ:
5267 token = read32 (ip + 2);
5268 klass = mono_method_get_wrapper_data (method, token);
5269 g_assert (klass->valuetype);
5270 mono_class_init (klass);
5271 NEW_INDLOAD (cfg, ins, sp [-1], &klass->byval_arg);
5275 case CEE_MONO_RETOBJ:
5276 g_assert (cfg->ret);
5277 g_assert (method->signature->pinvoke);
5282 token = read32 (ip + 2);
5283 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
5285 NEW_RETLOADA (cfg, ins);
5286 handle_stobj (cfg, bblock, ins, *sp, ip, klass, FALSE, TRUE);
5288 if (sp != stack_start)
5291 MONO_INST_NEW (cfg, ins, CEE_BR);
5293 ins->inst_target_bb = end_bblock;
5294 MONO_ADD_INS (bblock, ins);
5295 link_bblock (cfg, bblock, end_bblock);
5296 start_new_bblock = 1;
5299 case CEE_MONO_CISINST:
5300 case CEE_MONO_CCASTCLASS: {
5305 token = read32 (ip + 2);
5306 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
5307 MONO_INST_NEW (cfg, ins, (ip [1] == CEE_MONO_CISINST) ? OP_CISINST : OP_CCASTCLASS);
5308 ins->type = STACK_I4;
5309 ins->inst_left = *sp;
5310 ins->inst_newa_class = klass;
5312 *sp++ = emit_tree (cfg, bblock, ins);
5316 case CEE_MONO_SAVE_LMF:
5317 case CEE_MONO_RESTORE_LMF:
5318 #ifdef MONO_ARCH_HAVE_LMF_OPS
5319 MONO_INST_NEW (cfg, ins, (ip [1] == CEE_MONO_SAVE_LMF) ? OP_SAVE_LMF : OP_RESTORE_LMF);
5320 MONO_ADD_INS (bblock, ins);
5321 cfg->need_lmf_area = TRUE;
5326 g_error ("opcode 0x%02x 0x%02x not handled", MONO_CUSTOM_PREFIX, ip [1]);
5335 /* somewhat similar to LDTOKEN */
5336 MonoInst *addr, *vtvar;
5337 CHECK_STACK_OVF (1);
5338 vtvar = mono_compile_create_var (cfg, &mono_defaults.argumenthandle_class->byval_arg, OP_LOCAL);
5340 NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
5341 addr->cil_code = ip;
5342 MONO_INST_NEW (cfg, ins, OP_ARGLIST);
5344 ins->inst_left = addr;
5345 MONO_ADD_INS (bblock, ins);
5346 NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
5360 * The following transforms:
5361 * CEE_CEQ into OP_CEQ
5362 * CEE_CGT into OP_CGT
5363 * CEE_CGT_UN into OP_CGT_UN
5364 * CEE_CLT into OP_CLT
5365 * CEE_CLT_UN into OP_CLT_UN
5367 MONO_INST_NEW (cfg, cmp, 256 + ip [1]);
5369 MONO_INST_NEW (cfg, ins, cmp->opcode);
5371 cmp->inst_i0 = sp [0];
5372 cmp->inst_i1 = sp [1];
5376 if ((sp [0]->type == STACK_I8) || ((sizeof (gpointer) == 8) && ((sp [0]->type == STACK_PTR) || (sp [0]->type == STACK_OBJ) || (sp [0]->type == STACK_MP))))
5377 cmp->opcode = OP_LCOMPARE;
5379 cmp->opcode = OP_COMPARE;
5381 ins->type = STACK_I4;
5384 /* spill it to reduce the expression complexity
5385 * and workaround bug 54209
5387 if (cmp->inst_left->type == STACK_I8) {
5389 *sp++ = emit_tree (cfg, bblock, ins);
5398 CHECK_STACK_OVF (1);
5400 n = read32 (ip + 2);
5401 if (method->wrapper_type != MONO_WRAPPER_NONE)
5402 cmethod = mono_method_get_wrapper_data (method, n);
5404 cmethod = mono_get_method_full (image, n, NULL, generic_context);
5407 mono_class_init (cmethod->klass);
5408 handle_loaded_temps (cfg, bblock, stack_start, sp);
5410 NEW_METHODCONST (cfg, argconst, cmethod);
5411 if (method->wrapper_type != MONO_WRAPPER_SYNCHRONIZED)
5412 temp = mono_emit_jit_icall (cfg, bblock, mono_ldftn, &argconst, ip);
5414 temp = mono_emit_jit_icall (cfg, bblock, mono_ldftn_nosync, &argconst, ip);
5415 NEW_TEMPLOAD (cfg, *sp, temp);
5419 inline_costs += 10 * num_calls++;
5422 case CEE_LDVIRTFTN: {
5428 n = read32 (ip + 2);
5429 if (method->wrapper_type != MONO_WRAPPER_NONE)
5430 cmethod = mono_method_get_wrapper_data (method, n);
5432 cmethod = mono_get_method_full (image, n, NULL, generic_context);
5434 mono_class_init (cmethod->klass);
5435 handle_loaded_temps (cfg, bblock, stack_start, sp);
5439 NEW_METHODCONST (cfg, args [1], cmethod);
5440 temp = mono_emit_jit_icall (cfg, bblock, mono_ldvirtfn, args, ip);
5441 NEW_TEMPLOAD (cfg, *sp, temp);
5445 inline_costs += 10 * num_calls++;
5449 CHECK_STACK_OVF (1);
5451 n = read16 (ip + 2);
5453 NEW_ARGLOAD (cfg, ins, n);
5459 CHECK_STACK_OVF (1);
5461 n = read16 (ip + 2);
5463 NEW_ARGLOADA (cfg, ins, n);
5471 handle_loaded_temps (cfg, bblock, stack_start, sp);
5473 n = read16 (ip + 2);
5475 NEW_ARGSTORE (cfg, ins, n, *sp);
5477 if (ins->opcode == CEE_STOBJ) {
5478 NEW_ARGLOADA (cfg, ins, n);
5479 handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE);
5481 MONO_ADD_INS (bblock, ins);
5485 CHECK_STACK_OVF (1);
5487 n = read16 (ip + 2);
5489 NEW_LOCLOAD (cfg, ins, n);
5495 CHECK_STACK_OVF (1);
5497 n = read16 (ip + 2);
5499 NEW_LOCLOADA (cfg, ins, n);
5508 n = read16 (ip + 2);
5510 handle_loaded_temps (cfg, bblock, stack_start, sp);
5511 NEW_LOCSTORE (cfg, ins, n, *sp);
5513 if (ins->opcode == CEE_STOBJ) {
5514 NEW_LOCLOADA (cfg, ins, n);
5515 handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE);
5517 MONO_ADD_INS (bblock, ins);
5524 if (sp != stack_start)
5526 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
5527 ins->inst_left = *sp;
5530 cfg->flags |= MONO_CFG_HAS_ALLOCA;
5531 if (header->init_locals)
5532 ins->flags |= MONO_INST_INIT;
5536 /* FIXME: set init flag if locals init is set in this method */
5538 case CEE_ENDFILTER: {
5539 MonoExceptionClause *clause, *nearest;
5540 int cc, nearest_num;
5544 if ((sp != stack_start) || (sp [0]->type != STACK_I4))
5546 MONO_INST_NEW (cfg, ins, OP_ENDFILTER);
5547 ins->inst_left = *sp;
5549 MONO_ADD_INS (bblock, ins);
5550 start_new_bblock = 1;
5555 for (cc = 0; cc < header->num_clauses; ++cc) {
5556 clause = &header->clauses [cc];
5557 if ((clause->flags & MONO_EXCEPTION_CLAUSE_FILTER) &&
5558 (!nearest || (clause->token_or_filter > nearest->token_or_filter))) {
5564 filter_lengths [nearest_num] = (ip - header->code) - nearest->token_or_filter;
5568 case CEE_UNALIGNED_:
5569 ins_flag |= MONO_INST_UNALIGNED;
5570 /* FIXME: record alignment? we can assume 1 for now */
5575 ins_flag |= MONO_INST_VOLATILE;
5579 ins_flag |= MONO_INST_TAILCALL;
5580 cfg->flags |= MONO_CFG_HAS_TAIL;
5581 /* Can't inline tail calls at this time */
5582 inline_costs += 100000;
5589 token = read32 (ip + 2);
5590 if (method->wrapper_type != MONO_WRAPPER_NONE)
5591 klass = mono_method_get_wrapper_data (method, token);
5593 klass = mono_class_get_full (image, token, generic_context);
5594 if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
5595 MonoInst *store, *load;
5596 NEW_PCONST (cfg, load, NULL);
5597 load->cil_code = ip;
5598 load->type = STACK_OBJ;
5599 MONO_INST_NEW (cfg, store, CEE_STIND_REF);
5600 store->cil_code = ip;
5601 handle_loaded_temps (cfg, bblock, stack_start, sp);
5602 MONO_ADD_INS (bblock, store);
5603 store->inst_i0 = sp [0];
5604 store->inst_i1 = load;
5606 handle_initobj (cfg, bblock, *sp, NULL, klass, stack_start, sp);
5611 case CEE_CONSTRAINED_:
5612 /* FIXME: implement */
5614 token = read32 (ip + 2);
5615 constrained_call = mono_class_get_full (image, token, generic_context);
5620 MonoInst *iargs [3];
5623 if ((cfg->opt & MONO_OPT_INTRINS) && (ip [1] == CEE_CPBLK) && (sp [2]->opcode == OP_ICONST) && ((n = sp [2]->inst_c0) <= sizeof (gpointer) * 5)) {
5625 MONO_INST_NEW (cfg, copy, OP_MEMCPY);
5626 copy->inst_left = sp [0];
5627 copy->inst_right = sp [1];
5628 copy->cil_code = ip;
5630 MONO_ADD_INS (bblock, copy);
5637 handle_loaded_temps (cfg, bblock, stack_start, sp);
5638 if (ip [1] == CEE_CPBLK) {
5639 mono_emit_jit_icall (cfg, bblock, helper_memcpy, iargs, ip);
5641 mono_emit_jit_icall (cfg, bblock, helper_memset, iargs, ip);
5650 ins_flag |= MONO_INST_NOTYPECHECK;
5652 ins_flag |= MONO_INST_NORANGECHECK;
5653 /* we ignore the no-nullcheck for now since we
5654 * really do it explicitly only when doing callvirt->call
5660 /* FIXME: check we are in a catch handler */
5661 NEW_TEMPLOAD (cfg, load, cfg->exvar->inst_c0);
5662 load->cil_code = ip;
5663 MONO_INST_NEW (cfg, ins, CEE_THROW);
5664 ins->inst_left = load;
5666 MONO_ADD_INS (bblock, ins);
5668 start_new_bblock = 1;
5673 CHECK_STACK_OVF (1);
5675 token = read32 (ip + 2);
5676 /* FIXXME: handle generics. */
5677 if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC) {
5678 MonoType *type = mono_type_create_from_typespec (image, token);
5679 token = mono_type_size (type, &align);
5681 MonoClass *szclass = mono_class_get_full (image, token, generic_context);
5682 mono_class_init (szclass);
5683 token = mono_class_value_size (szclass, &align);
5685 NEW_ICONST (cfg, ins, token);
5690 case CEE_REFANYTYPE:
5692 MONO_INST_NEW (cfg, ins, OP_REFANYTYPE);
5694 ins->type = STACK_MP;
5695 ins->inst_left = *sp;
5696 ins->type = STACK_VTYPE;
5697 ins->klass = mono_defaults.typehandle_class;
5706 g_error ("opcode 0xfe 0x%02x not handled", ip [1]);
5711 g_error ("opcode 0x%02x not handled", *ip);
5714 if (start_new_bblock != 1)
5717 bblock->cil_length = ip - bblock->cil_code;
5718 bblock->next_bb = end_bblock;
5719 link_bblock (cfg, bblock, end_bblock);
5721 if (cfg->method == method && cfg->domainvar) {
5725 MONO_INST_NEW_CALL (cfg, call, CEE_CALL);
5726 call->signature = helper_sig_domain_get;
5727 call->inst.type = STACK_PTR;
5728 call->fptr = mono_domain_get;
5729 NEW_TEMPSTORE (cfg, store, cfg->domainvar->inst_c0, (MonoInst*)call);
5731 MONO_ADD_INS (init_localsbb, store);
5734 if (header->init_locals) {
5736 for (i = 0; i < header->num_locals; ++i) {
5737 int t = header->locals [i]->type;
5738 if (t == MONO_TYPE_VALUETYPE && header->locals [i]->data.klass->enumtype)
5739 t = header->locals [i]->data.klass->enum_basetype->type;
5740 /* FIXME: use initobj for valuetypes, handle pointers, long, float. */
5741 if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
5742 NEW_ICONST (cfg, ins, 0);
5743 NEW_LOCSTORE (cfg, store, i, ins);
5744 MONO_ADD_INS (init_localsbb, store);
5745 } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
5746 MONO_INST_NEW (cfg, ins, OP_I8CONST);
5747 ins->type = STACK_I8;
5749 NEW_LOCSTORE (cfg, store, i, ins);
5750 MONO_ADD_INS (init_localsbb, store);
5751 } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
5752 MONO_INST_NEW (cfg, ins, OP_R8CONST);
5753 ins->type = STACK_R8;
5754 ins->inst_p0 = (void*)&r8_0;
5755 NEW_LOCSTORE (cfg, store, i, ins);
5756 MONO_ADD_INS (init_localsbb, store);
5757 } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF)) {
5758 NEW_LOCLOADA (cfg, ins, i);
5759 handle_initobj (cfg, init_localsbb, ins, NULL, mono_class_from_mono_type (header->locals [i]), NULL, NULL);
5762 NEW_PCONST (cfg, ins, NULL);
5763 NEW_LOCSTORE (cfg, store, i, ins);
5764 MONO_ADD_INS (init_localsbb, store);
5770 /* resolve backward branches in the middle of an existing basic block */
5771 for (tmp = bb_recheck; tmp; tmp = tmp->next) {
5773 /*g_print ("need recheck in %s at IL_%04x\n", method->name, bblock->cil_code - header->code);*/
5774 tblock = find_previous (bbhash, start_bblock, bblock->cil_code);
5775 if (tblock != start_bblock) {
5777 split_bblock (cfg, tblock, bblock);
5778 l = bblock->cil_code - header->code;
5779 bblock->cil_length = tblock->cil_length - l;
5780 tblock->cil_length = l;
5782 g_print ("recheck failed.\n");
5787 * we compute regions here, because the length of filter clauses is not known in advance.
5788 * It is computed in the CEE_ENDFILTER case in the above switch statement
5790 if (cfg->method == method) {
5792 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
5793 bb->region = mono_find_block_region (cfg, bb->real_offset, filter_lengths);
5795 mono_create_spvar_for_region (cfg, bb->region);
5796 if (cfg->verbose_level > 2)
5797 g_print ("REGION BB%d IL_%04x ID_%08X\n", bb->block_num, bb->real_offset, bb->region);
5800 g_hash_table_destroy (bbhash);
5803 dont_inline = g_list_remove (dont_inline, method);
5804 return inline_costs;
5807 if (cfg->method != method)
5808 g_hash_table_destroy (bbhash);
5809 dont_inline = g_list_remove (dont_inline, method);
5813 if (cfg->method != method)
5814 g_hash_table_destroy (bbhash);
5815 g_error ("Invalid IL code at IL%04x in %s: %s\n", ip - header->code,
5816 mono_method_full_name (method, TRUE), mono_disasm_code_one (NULL, method, ip, NULL));
5817 dont_inline = g_list_remove (dont_inline, method);
5822 mono_print_tree (MonoInst *tree) {
5828 arity = mono_burg_arity [tree->opcode];
5830 printf (" %s%s", arity?"(":"", mono_inst_name (tree->opcode));
5832 switch (tree->opcode) {
5834 printf ("[%d]", tree->inst_c0);
5837 printf ("[%lld]", tree->inst_l);
5840 printf ("[%f]", *(double*)tree->inst_p0);
5843 printf ("[%f]", *(float*)tree->inst_p0);
5847 printf ("[%d]", tree->inst_c0);
5850 if (tree->inst_offset < 0)
5851 printf ("[-0x%x(%s)]", -tree->inst_offset, mono_arch_regname (tree->inst_basereg));
5853 printf ("[0x%x(%s)]", tree->inst_offset, mono_arch_regname (tree->inst_basereg));
5856 printf ("[%s]", mono_arch_regname (tree->dreg));
5859 printf ("[%s]", tree->inst_newa_class->name);
5860 mono_print_tree (tree->inst_newa_len);
5871 case OP_VOIDCALLVIRT: {
5872 MonoCallInst *call = (MonoCallInst*)tree;
5874 printf ("[%s]", call->method->name);
5879 printf ("[%d (", tree->inst_c0);
5880 for (i = 0; i < tree->inst_phi_args [0]; i++) {
5883 printf ("%d", tree->inst_phi_args [i + 1]);
5894 case OP_LOAD_MEMBASE:
5895 case OP_LOADI4_MEMBASE:
5896 case OP_LOADU4_MEMBASE:
5897 case OP_LOADU1_MEMBASE:
5898 case OP_LOADI1_MEMBASE:
5899 case OP_LOADU2_MEMBASE:
5900 case OP_LOADI2_MEMBASE:
5901 printf ("[%s] <- [%s + 0x%x]", mono_arch_regname (tree->dreg), mono_arch_regname (tree->inst_basereg), tree->inst_offset);
5904 printf ("[B%d]", tree->inst_target_bb->block_num);
5914 case OP_VOIDCALL_REG:
5915 mono_print_tree (tree->inst_left);
5927 printf ("[B%dB%d]", tree->inst_true_bb->block_num, tree->inst_false_bb->block_num);
5928 mono_print_tree (tree->inst_left);
5931 if (!mono_arch_print_tree(tree, arity)) {
5933 mono_print_tree (tree->inst_left);
5935 mono_print_tree (tree->inst_right);
5946 mono_print_tree_nl (MonoInst *tree)
5948 mono_print_tree (tree);
5952 #define make_icall_sig mono_create_icall_signature
5955 create_helper_signature (void)
5957 /* MonoArray * mono_array_new (MonoDomain *domain, MonoClass *klass, gint32 len) */
5958 helper_sig_newarr = make_icall_sig ("object ptr ptr int32");
5960 /* MonoArray * mono_array_new_specific (MonoVTable *vtable, guint32 len) */
5961 helper_sig_newarr_specific = make_icall_sig ("object ptr int32");
5963 /* MonoObject * mono_object_new (MonoDomain *domain, MonoClass *klass) */
5964 helper_sig_object_new = make_icall_sig ("object ptr ptr");
5966 /* MonoObject * mono_object_new_specific (MonoVTable *vtable) */
5967 helper_sig_object_new_specific = make_icall_sig ("object ptr");
5969 /* void* mono_method_compile (MonoMethod*) */
5970 helper_sig_compile = make_icall_sig ("ptr ptr");
5972 /* void* mono_ldvirtfn (MonoObject *, MonoMethod*) */
5973 helper_sig_compile_virt = make_icall_sig ("ptr object ptr");
5975 /* MonoString* mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 str_index) */
5976 helper_sig_ldstr = make_icall_sig ("object ptr ptr int32");
5978 /* MonoDomain *mono_domain_get (void) */
5979 helper_sig_domain_get = make_icall_sig ("ptr");
5981 /* void stelem_ref (MonoArray *, int index, MonoObject *) */
5982 helper_sig_stelem_ref = make_icall_sig ("void ptr int32 object");
5984 /* void stelem_ref_check (MonoArray *, MonoObject *) */
5985 helper_sig_stelem_ref_check = make_icall_sig ("void object object");
5987 /* long amethod (long, long) */
5988 helper_sig_long_long_long = make_icall_sig ("long long long");
5990 /* object amethod (intptr) */
5991 helper_sig_obj_ptr = make_icall_sig ("object ptr");
5993 helper_sig_obj_ptr_ptr = make_icall_sig ("object ptr ptr");
5995 helper_sig_obj_obj_ptr_ptr = make_icall_sig ("object object ptr ptr");
5997 helper_sig_void_void = make_icall_sig ("void");
5999 /* void amethod (intptr) */
6000 helper_sig_void_ptr = make_icall_sig ("void ptr");
6002 /* void amethod (MonoObject *obj) */
6003 helper_sig_void_obj = make_icall_sig ("void object");
6005 /* void amethod (MonoObject *obj, void *ptr, int i) */
6006 helper_sig_void_obj_ptr_int = make_icall_sig ("void object ptr int");
6008 helper_sig_void_obj_ptr_ptr_obj = make_icall_sig ("void object ptr ptr object");
6010 /* intptr amethod (void) */
6011 helper_sig_ptr_void = make_icall_sig ("ptr");
6013 /* object amethod (void) */
6014 helper_sig_obj_void = make_icall_sig ("object");
6016 /* void amethod (intptr, intptr) */
6017 helper_sig_void_ptr_ptr = make_icall_sig ("void ptr ptr");
6019 /* void amethod (intptr, intptr, intptr) */
6020 helper_sig_void_ptr_ptr_ptr = make_icall_sig ("void ptr ptr ptr");
6022 /* intptr amethod (intptr, intptr) */
6023 helper_sig_ptr_ptr_ptr = make_icall_sig ("ptr ptr ptr");
6025 /* IntPtr amethod (object) */
6026 helper_sig_ptr_obj = make_icall_sig ("ptr object");
6028 /* IntPtr amethod (object, int) */
6029 helper_sig_ptr_obj_int = make_icall_sig ("ptr object int");
6031 /* IntPtr amethod (int) */
6032 helper_sig_ptr_int = make_icall_sig ("ptr int32");
6034 /* long amethod (long, guint32) */
6035 helper_sig_long_long_int = make_icall_sig ("long long int32");
6037 /* ulong amethod (double) */
6038 helper_sig_ulong_double = make_icall_sig ("ulong double");
6040 /* long amethod (double) */
6041 helper_sig_long_double = make_icall_sig ("long double");
6043 /* double amethod (long) */
6044 helper_sig_double_long = make_icall_sig ("double long");
6046 /* double amethod (int) */
6047 helper_sig_double_int = make_icall_sig ("double int32");
6049 /* float amethod (long) */
6050 helper_sig_float_long = make_icall_sig ("float long");
6052 /* double amethod (double, double) */
6053 helper_sig_double_double_double = make_icall_sig ("double double double");
6055 /* uint amethod (double) */
6056 helper_sig_uint_double = make_icall_sig ("uint32 double");
6058 /* int amethod (double) */
6059 helper_sig_int_double = make_icall_sig ("int32 double");
6061 /* void initobj (intptr, int size) */
6062 helper_sig_initobj = make_icall_sig ("void ptr int32");
6064 /* void memcpy (intptr, intptr, int size) */
6065 helper_sig_memcpy = make_icall_sig ("void ptr ptr int32");
6067 /* void memset (intptr, int val, int size) */
6068 helper_sig_memset = make_icall_sig ("void ptr int32 int32");
6070 helper_sig_class_init_trampoline = make_icall_sig ("void");
6074 mono_icall_get_wrapper (MonoJitICallInfo* callinfo)
6077 MonoMethod *wrapper;
6080 if (callinfo->wrapper)
6081 return callinfo->wrapper;
6083 name = g_strdup_printf ("__icall_wrapper_%s", callinfo->name);
6084 wrapper = mono_marshal_get_icall_wrapper (callinfo->sig, name, callinfo->func);
6085 /* Must be domain neutral since there is only one copy */
6086 code = mono_jit_compile_method_with_opt (wrapper, default_opt | MONO_OPT_SHARED);
6088 if (!callinfo->wrapper) {
6089 callinfo->wrapper = code;
6090 mono_register_jit_icall_wrapper (callinfo, code);
6091 mono_debug_add_icall_wrapper (wrapper, callinfo);
6095 return callinfo->wrapper;
6099 mono_create_class_init_trampoline (MonoVTable *vtable)
6103 /* previously created trampoline code */
6104 mono_domain_lock (vtable->domain);
6106 mono_g_hash_table_lookup (vtable->domain->class_init_trampoline_hash,
6108 mono_domain_unlock (vtable->domain);
6112 code = mono_arch_create_class_init_trampoline (vtable);
6114 /* store trampoline address */
6115 mono_domain_lock (vtable->domain);
6116 mono_g_hash_table_insert (vtable->domain->class_init_trampoline_hash,
6118 mono_domain_unlock (vtable->domain);
6120 EnterCriticalSection (&trampoline_hash_mutex);
6121 if (!class_init_hash_addr)
6122 class_init_hash_addr = g_hash_table_new (NULL, NULL);
6123 g_hash_table_insert (class_init_hash_addr, code, vtable);
6124 LeaveCriticalSection (&trampoline_hash_mutex);
6130 mono_create_jump_trampoline (MonoDomain *domain, MonoMethod *method,
6131 gboolean add_sync_wrapper)
6136 if (add_sync_wrapper && method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
6137 return mono_create_jump_trampoline (domain, mono_marshal_get_synchronized_wrapper (method), FALSE);
6139 code = mono_jit_find_compiled_method (domain, method);
6143 EnterCriticalSection (&trampoline_hash_mutex);
6145 if (jump_trampoline_hash) {
6146 code = g_hash_table_lookup (jump_trampoline_hash, method);
6148 LeaveCriticalSection (&trampoline_hash_mutex);
6153 ji = mono_arch_create_jump_trampoline (method);
6156 * mono_delegate_ctor needs to find the method metadata from the
6157 * trampoline address, so we save it here.
6160 mono_jit_info_table_add (mono_get_root_domain (), ji);
6162 if (!jump_trampoline_hash)
6163 jump_trampoline_hash = g_hash_table_new (NULL, NULL);
6164 g_hash_table_insert (jump_trampoline_hash, method, ji->code_start);
6166 LeaveCriticalSection (&trampoline_hash_mutex);
6168 return ji->code_start;
6172 mono_find_class_init_trampoline_by_addr (gconstpointer addr)
6176 EnterCriticalSection (&trampoline_hash_mutex);
6177 if (class_init_hash_addr)
6178 res = g_hash_table_lookup (class_init_hash_addr, addr);
6181 LeaveCriticalSection (&trampoline_hash_mutex);
6186 mono_register_opcode_emulation (int opcode, const char *name, MonoMethodSignature *sig, gpointer func, gboolean no_throw)
6188 MonoJitICallInfo *info;
6190 if (!emul_opcode_map)
6191 emul_opcode_map = g_new0 (MonoJitICallInfo*, OP_LAST + 1);
6193 g_assert (!sig->hasthis);
6194 g_assert (sig->param_count < 3);
6196 info = mono_register_jit_icall (func, name, sig, no_throw);
6198 emul_opcode_map [opcode] = info;
6202 decompose_foreach (MonoInst *tree, gpointer data)
6204 static MonoJitICallInfo *newarr_info = NULL;
6205 static MonoJitICallInfo *newarr_specific_info = NULL;
6206 MonoJitICallInfo *info;
6209 switch (tree->opcode) {
6211 MonoCompile *cfg = data;
6212 MonoInst *iargs [3];
6215 newarr_info = mono_find_jit_icall_by_addr (mono_array_new);
6216 g_assert (newarr_info);
6217 newarr_specific_info = mono_find_jit_icall_by_addr (mono_array_new_specific);
6218 g_assert (newarr_specific_info);
6221 if (cfg->opt & MONO_OPT_SHARED) {
6222 NEW_DOMAINCONST (cfg, iargs [0]);
6223 NEW_CLASSCONST (cfg, iargs [1], tree->inst_newa_class);
6224 iargs [2] = tree->inst_newa_len;
6229 MonoVTable *vtable = mono_class_vtable (cfg->domain, mono_array_class_get (tree->inst_newa_class, 1));
6231 NEW_VTABLECONST (cfg, iargs [0], vtable);
6232 iargs [1] = tree->inst_newa_len;
6234 info = newarr_specific_info;
6237 mono_emulate_opcode (cfg, tree, iargs, info);
6239 /* Need to decompose arguments after the the opcode is decomposed */
6240 for (i = 0; i < info->sig->param_count; ++i)
6241 dec_foreach (iargs [i], cfg);
6251 mono_inst_foreach (MonoInst *tree, MonoInstFunc func, gpointer data) {
6253 switch (mono_burg_arity [tree->opcode]) {
6256 mono_inst_foreach (tree->inst_left, func, data);
6259 mono_inst_foreach (tree->inst_left, func, data);
6260 mono_inst_foreach (tree->inst_right, func, data);
6263 g_assert_not_reached ();
6270 mono_print_bb_code (MonoBasicBlock *bb) {
6272 MonoInst *c = bb->code;
6274 mono_print_tree (c);
6282 print_dfn (MonoCompile *cfg) {
6287 g_print ("IR code for method %s\n", mono_method_full_name (cfg->method, TRUE));
6289 for (i = 0; i < cfg->num_bblocks; ++i) {
6290 bb = cfg->bblocks [i];
6291 /*if (bb->cil_code) {
6292 char* code1, *code2;
6293 code1 = mono_disasm_code_one (NULL, cfg->method, bb->cil_code, NULL);
6294 if (bb->last_ins->cil_code)
6295 code2 = mono_disasm_code_one (NULL, cfg->method, bb->last_ins->cil_code, NULL);
6297 code2 = g_strdup ("");
6299 code1 [strlen (code1) - 1] = 0;
6300 code = g_strdup_printf ("%s -> %s", code1, code2);
6304 code = g_strdup ("\n");
6305 g_print ("\nBB%d DFN%d (len: %d): %s", bb->block_num, i, bb->cil_length, code);
6307 MonoInst *c = bb->code;
6309 mono_print_tree (c);
6317 g_print ("\tprev:");
6318 for (j = 0; j < bb->in_count; ++j) {
6319 g_print (" BB%d", bb->in_bb [j]->block_num);
6321 g_print ("\t\tsucc:");
6322 for (j = 0; j < bb->out_count; ++j) {
6323 g_print (" BB%d", bb->out_bb [j]->block_num);
6325 g_print ("\n\tidom: BB%d\n", bb->idom? bb->idom->block_num: -1);
6328 g_assert (mono_bitset_test_fast (bb->dominators, bb->idom->dfn));
6331 mono_blockset_print (cfg, bb->dominators, "\tdominators", bb->idom? bb->idom->dfn: -1);
6333 mono_blockset_print (cfg, bb->dfrontier, "\tdfrontier", -1);
6341 mono_bblock_add_inst (MonoBasicBlock *bb, MonoInst *inst)
6345 g_assert (bb->code);
6346 bb->last_ins->next = inst;
6347 bb->last_ins = inst;
6349 bb->last_ins = bb->code = inst;
6354 mono_destroy_compile (MonoCompile *cfg)
6356 //mono_mempool_stats (cfg->mempool);
6357 g_hash_table_destroy (cfg->bb_hash);
6358 mono_free_loop_info (cfg);
6360 mono_regstate_free (cfg->rs);
6362 g_hash_table_destroy (cfg->spvars);
6363 mono_mempool_destroy (cfg->mempool);
6364 g_list_free (cfg->ldstr_list);
6366 g_free (cfg->varinfo);
6371 #ifdef HAVE_KW_THREAD
6372 static __thread gpointer mono_lmf_addr;
6376 mono_get_lmf_addr (void)
6378 #ifdef HAVE_KW_THREAD
6379 return mono_lmf_addr;
6381 MonoJitTlsData *jit_tls;
6383 if ((jit_tls = TlsGetValue (mono_jit_tls_id)))
6384 return &jit_tls->lmf;
6386 g_assert_not_reached ();
6392 * mono_thread_abort:
6393 * @obj: exception object
6395 * abort the thread, print exception information and stack trace
6398 mono_thread_abort (MonoObject *obj)
6400 /* MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id); */
6402 /* handle_remove should be eventually called for this thread, too
6409 setup_jit_tls_data (gpointer stack_start, gpointer abort_func)
6411 MonoJitTlsData *jit_tls;
6414 jit_tls = TlsGetValue (mono_jit_tls_id);
6418 jit_tls = g_new0 (MonoJitTlsData, 1);
6420 TlsSetValue (mono_jit_tls_id, jit_tls);
6422 jit_tls->abort_func = abort_func;
6423 jit_tls->end_of_stack = stack_start;
6425 lmf = g_new0 (MonoLMF, 1);
6428 jit_tls->lmf = jit_tls->first_lmf = lmf;
6430 #ifdef HAVE_KW_THREAD
6431 mono_lmf_addr = &jit_tls->lmf;
6434 mono_arch_setup_jit_tls_data (jit_tls);
6440 mono_thread_start_cb (guint32 tid, gpointer stack_start, gpointer func)
6443 void *jit_tls = setup_jit_tls_data (stack_start, mono_thread_abort);
6444 thread = mono_thread_current ();
6446 thread->jit_data = jit_tls;
6449 void (*mono_thread_attach_aborted_cb ) (MonoObject *obj) = NULL;
6452 mono_thread_abort_dummy (MonoObject *obj)
6454 if (mono_thread_attach_aborted_cb)
6455 mono_thread_attach_aborted_cb (obj);
6457 mono_thread_abort (obj);
6461 mono_thread_attach_cb (guint32 tid, gpointer stack_start)
6464 void *jit_tls = setup_jit_tls_data (stack_start, mono_thread_abort_dummy);
6465 thread = mono_thread_current ();
6467 thread->jit_data = jit_tls;
6471 mini_thread_cleanup (MonoThread *thread)
6473 MonoJitTlsData *jit_tls = thread->jit_data;
6476 mono_arch_free_jit_tls_data (jit_tls);
6477 g_free (jit_tls->first_lmf);
6479 thread->jit_data = NULL;
6484 mono_add_patch_info (MonoCompile *cfg, int ip, MonoJumpInfoType type, gconstpointer target)
6486 MonoJumpInfo *ji = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfo));
6490 ji->data.target = target;
6491 ji->next = cfg->patch_info;
6493 cfg->patch_info = ji;
6497 mono_remove_patch_info (MonoCompile *cfg, int ip)
6499 MonoJumpInfo **ji = &cfg->patch_info;
6502 if ((*ji)->ip.i == ip)
6505 ji = &((*ji)->next);
6510 mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *patch_info, gboolean run_cctors)
6512 unsigned char *ip = patch_info->ip.i + code;
6513 gconstpointer target = NULL;
6515 switch (patch_info->type) {
6516 case MONO_PATCH_INFO_BB:
6517 target = patch_info->data.bb->native_offset + code;
6519 case MONO_PATCH_INFO_ABS:
6520 target = patch_info->data.target;
6522 case MONO_PATCH_INFO_LABEL:
6523 target = patch_info->data.inst->inst_c0 + code;
6525 case MONO_PATCH_INFO_IP:
6528 case MONO_PATCH_INFO_METHOD_REL:
6529 target = code + patch_info->data.offset;
6531 case MONO_PATCH_INFO_INTERNAL_METHOD: {
6532 MonoJitICallInfo *mi = mono_find_jit_icall_by_name (patch_info->data.name);
6534 g_warning ("unknown MONO_PATCH_INFO_INTERNAL_METHOD %s", patch_info->data.name);
6535 g_assert_not_reached ();
6537 target = mono_icall_get_wrapper (mi);
6540 case MONO_PATCH_INFO_METHOD_JUMP: {
6543 /* get the trampoline to the method from the domain */
6544 target = mono_create_jump_trampoline (domain, patch_info->data.method, TRUE);
6545 if (!domain->jump_target_hash)
6546 domain->jump_target_hash = g_hash_table_new (NULL, NULL);
6547 list = g_hash_table_lookup (domain->jump_target_hash, patch_info->data.method);
6548 list = g_slist_prepend (list, ip);
6549 g_hash_table_insert (domain->jump_target_hash, patch_info->data.method, list);
6552 case MONO_PATCH_INFO_METHOD:
6553 if (patch_info->data.method == method) {
6556 /* get the trampoline to the method from the domain */
6557 target = mono_arch_create_jit_trampoline (patch_info->data.method);
6559 case MONO_PATCH_INFO_SWITCH: {
6560 gpointer *jump_table;
6563 mono_domain_lock (domain);
6564 jump_table = mono_code_manager_reserve (domain->code_mp, sizeof (gpointer) * patch_info->table_size);
6565 mono_domain_unlock (domain);
6567 for (i = 0; i < patch_info->table_size; i++) {
6568 jump_table [i] = code + (int)patch_info->data.table [i];
6570 target = jump_table;
6573 case MONO_PATCH_INFO_METHODCONST:
6574 case MONO_PATCH_INFO_CLASS:
6575 case MONO_PATCH_INFO_IMAGE:
6576 case MONO_PATCH_INFO_FIELD:
6577 target = patch_info->data.target;
6579 case MONO_PATCH_INFO_IID:
6580 mono_class_init (patch_info->data.klass);
6581 target = (gpointer)patch_info->data.klass->interface_id;
6583 case MONO_PATCH_INFO_VTABLE:
6584 target = mono_class_vtable (domain, patch_info->data.klass);
6586 case MONO_PATCH_INFO_CLASS_INIT:
6587 target = mono_create_class_init_trampoline (mono_class_vtable (domain, patch_info->data.klass));
6589 case MONO_PATCH_INFO_SFLDA: {
6590 MonoVTable *vtable = mono_class_vtable (domain, patch_info->data.field->parent);
6591 if (!vtable->initialized && !(vtable->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) && mono_class_needs_cctor_run (vtable->klass, method))
6592 /* Done by the generated code */
6596 mono_runtime_class_init (vtable);
6598 target = (char*)vtable->data + patch_info->data.field->offset;
6601 case MONO_PATCH_INFO_R4:
6602 case MONO_PATCH_INFO_R8:
6603 target = patch_info->data.target;
6605 case MONO_PATCH_INFO_EXC_NAME:
6606 target = patch_info->data.name;
6608 case MONO_PATCH_INFO_LDSTR:
6610 mono_ldstr (domain, patch_info->data.token->image,
6611 mono_metadata_token_index (patch_info->data.token->token));
6613 case MONO_PATCH_INFO_TYPE_FROM_HANDLE: {
6615 MonoClass *handle_class;
6617 handle = mono_ldtoken (patch_info->data.token->image,
6618 patch_info->data.token->token, &handle_class, NULL);
6619 mono_class_init (handle_class);
6620 mono_class_init (mono_class_from_mono_type (handle));
6623 mono_type_get_object (domain, handle);
6626 case MONO_PATCH_INFO_LDTOKEN: {
6628 MonoClass *handle_class;
6630 handle = mono_ldtoken (patch_info->data.token->image,
6631 patch_info->data.token->token, &handle_class, NULL);
6632 mono_class_init (handle_class);
6637 case MONO_PATCH_INFO_BB_OVF:
6638 case MONO_PATCH_INFO_EXC_OVF:
6641 g_assert_not_reached ();
6644 return (gpointer)target;
6648 dec_foreach (MonoInst *tree, MonoCompile *cfg) {
6649 MonoJitICallInfo *info;
6651 decompose_foreach (tree, cfg);
6653 switch (mono_burg_arity [tree->opcode]) {
6656 dec_foreach (tree->inst_left, cfg);
6658 if ((info = mono_find_jit_opcode_emulation (tree->opcode))) {
6659 MonoInst *iargs [2];
6661 iargs [0] = tree->inst_left;
6663 mono_emulate_opcode (cfg, tree, iargs, info);
6669 #ifdef MONO_ARCH_BIGMUL_INTRINS
6670 if (tree->opcode == OP_LMUL
6671 && (cfg->opt & MONO_OPT_INTRINS)
6672 && (tree->inst_left->opcode == CEE_CONV_I8
6673 || tree->inst_left->opcode == CEE_CONV_U8)
6674 && tree->inst_left->inst_left->type == STACK_I4
6675 && (tree->inst_right->opcode == CEE_CONV_I8
6676 || tree->inst_right->opcode == CEE_CONV_U8)
6677 && tree->inst_right->inst_left->type == STACK_I4
6678 && tree->inst_left->opcode == tree->inst_right->opcode) {
6679 tree->opcode = (tree->inst_left->opcode == CEE_CONV_I8 ? OP_BIGMUL: OP_BIGMUL_UN);
6680 tree->inst_left = tree->inst_left->inst_left;
6681 tree->inst_right = tree->inst_right->inst_left;
6682 dec_foreach (tree, cfg);
6685 if ((info = mono_find_jit_opcode_emulation (tree->opcode))) {
6686 MonoInst *iargs [2];
6688 iargs [0] = tree->inst_i0;
6689 iargs [1] = tree->inst_i1;
6691 mono_emulate_opcode (cfg, tree, iargs, info);
6693 dec_foreach (iargs [0], cfg);
6694 dec_foreach (iargs [1], cfg);
6697 dec_foreach (tree->inst_left, cfg);
6698 dec_foreach (tree->inst_right, cfg);
6702 g_assert_not_reached ();
6707 decompose_pass (MonoCompile *cfg) {
6710 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
6713 cfg->prev_ins = NULL;
6714 for (tree = cfg->cbb->code; tree; tree = tree->next) {
6715 dec_foreach (tree, cfg);
6716 cfg->prev_ins = tree;
6722 nullify_basic_block (MonoBasicBlock *bb)
6729 bb->code = bb->last_ins = NULL;
6730 bb->cil_code = NULL;
6734 replace_out_block (MonoBasicBlock *bb, MonoBasicBlock *orig, MonoBasicBlock *repl)
6738 for (i = 0; i < bb->out_count; i++) {
6739 MonoBasicBlock *ob = bb->out_bb [i];
6742 if (bb->out_count > 1) {
6743 bb->out_bb [i] = bb->out_bb [bb->out_count - 1];
6747 bb->out_bb [i] = repl;
6754 replace_in_block (MonoBasicBlock *bb, MonoBasicBlock *orig, MonoBasicBlock *repl)
6758 for (i = 0; i < bb->in_count; i++) {
6759 MonoBasicBlock *ib = bb->in_bb [i];
6762 if (bb->in_count > 1) {
6763 bb->in_bb [i] = bb->in_bb [bb->in_count - 1];
6767 bb->in_bb [i] = repl;
6774 replace_basic_block (MonoBasicBlock *bb, MonoBasicBlock *orig, MonoBasicBlock *repl)
6778 for (i = 0; i < bb->out_count; i++) {
6779 MonoBasicBlock *ob = bb->out_bb [i];
6780 for (j = 0; j < ob->in_count; j++) {
6781 if (ob->in_bb [j] == orig) {
6782 ob->in_bb [j] = repl;
6791 merge_basic_blocks (MonoBasicBlock *bb, MonoBasicBlock *bbn)
6793 bb->out_count = bbn->out_count;
6794 bb->out_bb = bbn->out_bb;
6796 replace_basic_block (bb, bbn, bb);
6800 bb->last_ins->next = bbn->code;
6801 bb->last_ins = bbn->last_ins;
6804 bb->code = bbn->code;
6805 bb->last_ins = bbn->last_ins;
6807 bb->next_bb = bbn->next_bb;
6808 nullify_basic_block (bbn);
6812 * Optimizes the branches on the Control Flow Graph
6816 optimize_branches (MonoCompile *cfg)
6818 int i, changed = FALSE;
6819 MonoBasicBlock *bb, *bbn;
6820 guint32 niterations;
6823 * Some crazy loops could cause the code below to go into an infinite
6824 * loop, see bug #53003 for an example. To prevent this, we put an upper
6825 * bound on the number of iterations.
6832 /* we skip the entry block (exit is handled specially instead ) */
6833 for (bb = cfg->bb_entry->next_bb; bb; bb = bb->next_bb) {
6835 /* dont touch code inside exception clauses */
6836 if (bb->region != -1)
6839 if ((bbn = bb->next_bb) && bbn->in_count == 0 && bb->region == bbn->region) {
6840 if (cfg->verbose_level > 2)
6841 g_print ("nullify block triggered %d\n", bbn->block_num);
6843 bb->next_bb = bbn->next_bb;
6845 for (i = 0; i < bbn->out_count; i++)
6846 replace_in_block (bbn->out_bb [i], bbn, NULL);
6848 nullify_basic_block (bbn);
6852 if (bb->out_count == 1) {
6853 bbn = bb->out_bb [0];
6855 /* conditional branches where true and false targets are the same can be also replaced with CEE_BR */
6856 if (bb->last_ins && MONO_IS_COND_BRANCH_OP (bb->last_ins)) {
6857 bb->last_ins->opcode = CEE_BR;
6858 bb->last_ins->inst_target_bb = bb->last_ins->inst_true_bb;
6860 if (cfg->verbose_level > 2)
6861 g_print ("cond branch removal triggered in %d %d\n", bb->block_num, bb->out_count);
6864 if (bb->region == bbn->region && bb->next_bb == bbn) {
6865 /* the block are in sequence anyway ... */
6867 /* branches to the following block can be removed */
6868 if (bb->last_ins && bb->last_ins->opcode == CEE_BR) {
6869 bb->last_ins->opcode = CEE_NOP;
6871 if (cfg->verbose_level > 2)
6872 g_print ("br removal triggered %d -> %d\n", bb->block_num, bbn->block_num);
6875 if (bbn->in_count == 1) {
6877 if (bbn != cfg->bb_exit) {
6878 if (cfg->verbose_level > 2)
6879 g_print ("block merge triggered %d -> %d\n", bb->block_num, bbn->block_num);
6880 merge_basic_blocks (bb, bbn);
6884 //mono_print_bb_code (bb);
6889 } while (changed && (niterations > 0));
6896 /* we skip the entry block (exit is handled specially instead ) */
6897 for (bb = cfg->bb_entry->next_bb; bb; bb = bb->next_bb) {
6899 /* dont touch code inside exception clauses */
6900 if (bb->region != -1)
6903 if ((bbn = bb->next_bb) && bbn->in_count == 0 && bb->region == bbn->region) {
6904 if (cfg->verbose_level > 2) {
6905 g_print ("nullify block triggered %d\n", bbn->block_num);
6907 bb->next_bb = bbn->next_bb;
6909 for (i = 0; i < bbn->out_count; i++)
6910 replace_in_block (bbn->out_bb [i], bbn, NULL);
6912 nullify_basic_block (bbn);
6918 if (bb->out_count == 1) {
6919 bbn = bb->out_bb [0];
6921 if (bb->last_ins && bb->last_ins->opcode == CEE_BR) {
6922 bbn = bb->last_ins->inst_target_bb;
6923 if (bb->region == bbn->region && bbn->code && bbn->code->opcode == CEE_BR &&
6924 bbn->code->inst_target_bb->region == bb->region) {
6926 if (cfg->verbose_level > 2)
6927 g_print ("in %s branch to branch triggered %d -> %d -> %d\n", cfg->method->name,
6928 bb->block_num, bbn->block_num, bbn->code->inst_target_bb->block_num);
6930 replace_in_block (bbn, bb, NULL);
6931 replace_out_block (bb, bbn, bbn->code->inst_target_bb);
6932 link_bblock (cfg, bb, bbn->code->inst_target_bb);
6933 bb->last_ins->inst_target_bb = bbn->code->inst_target_bb;
6938 } else if (bb->out_count == 2) {
6939 if (bb->last_ins && MONO_IS_COND_BRANCH_NOFP (bb->last_ins)) {
6940 bbn = bb->last_ins->inst_true_bb;
6941 if (bb->region == bbn->region && bbn->code && bbn->code->opcode == CEE_BR &&
6942 bbn->code->inst_target_bb->region == bb->region) {
6943 if (cfg->verbose_level > 2)
6944 g_print ("cbranch1 to branch triggered %d -> (%d) %d (0x%02x)\n",
6945 bb->block_num, bbn->block_num, bbn->code->inst_target_bb->block_num,
6948 bb->last_ins->inst_true_bb = bbn->code->inst_target_bb;
6950 replace_in_block (bbn, bb, NULL);
6952 replace_in_block (bbn->code->inst_target_bb, bbn, bb);
6953 replace_out_block (bb, bbn, bbn->code->inst_target_bb);
6955 link_bblock (cfg, bb, bbn->code->inst_target_bb);
6961 bbn = bb->last_ins->inst_false_bb;
6962 if (bb->region == bbn->region && bbn->code && bbn->code->opcode == CEE_BR &&
6963 bbn->code->inst_target_bb->region == bb->region) {
6964 if (cfg->verbose_level > 2)
6965 g_print ("cbranch2 to branch triggered %d -> (%d) %d (0x%02x)\n",
6966 bb->block_num, bbn->block_num, bbn->code->inst_target_bb->block_num,
6969 bb->last_ins->inst_false_bb = bbn->code->inst_target_bb;
6971 replace_in_block (bbn, bb, NULL);
6973 replace_in_block (bbn->code->inst_target_bb, bbn, bb);
6974 replace_out_block (bb, bbn, bbn->code->inst_target_bb);
6976 link_bblock (cfg, bb, bbn->code->inst_target_bb);
6984 } while (changed && (niterations > 0));
6989 mono_compile_create_vars (MonoCompile *cfg)
6991 MonoMethodSignature *sig;
6992 MonoMethodHeader *header;
6995 header = ((MonoMethodNormal *)cfg->method)->header;
6997 sig = cfg->method->signature;
6999 if (!MONO_TYPE_IS_VOID (sig->ret)) {
7000 cfg->ret = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst));
7001 cfg->ret->opcode = OP_RETARG;
7002 cfg->ret->inst_vtype = sig->ret;
7003 cfg->ret->klass = mono_class_from_mono_type (sig->ret);
7005 if (cfg->verbose_level > 2)
7006 g_print ("creating vars\n");
7009 mono_compile_create_var (cfg, &cfg->method->klass->this_arg, OP_ARG);
7011 for (i = 0; i < sig->param_count; ++i)
7012 mono_compile_create_var (cfg, sig->params [i], OP_ARG);
7014 cfg->locals_start = cfg->num_varinfo;
7016 if (cfg->verbose_level > 2)
7017 g_print ("creating locals\n");
7018 for (i = 0; i < header->num_locals; ++i)
7019 mono_compile_create_var (cfg, header->locals [i], OP_LOCAL);
7020 if (cfg->verbose_level > 2)
7021 g_print ("locals done\n");
7025 mono_print_code (MonoCompile *cfg)
7029 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
7030 MonoInst *tree = bb->code;
7035 g_print ("CODE BLOCK %d (nesting %d):\n", bb->block_num, bb->nesting);
7037 for (; tree; tree = tree->next) {
7038 mono_print_tree (tree);
7043 bb->last_ins->next = NULL;
7047 extern const char * const mono_burg_rule_string [];
7050 emit_state (MonoCompile *cfg, MBState *state, int goal)
7053 int ern = mono_burg_rule (state, goal);
7054 const guint16 *nts = mono_burg_nts [ern];
7057 //g_print ("rule: %s\n", mono_burg_rule_string [ern]);
7061 // state->reg1 = state->reg2; /* chain rule */
7063 state->reg1 = mono_regstate_next_int (cfg->rs);
7064 //g_print ("alloc symbolic R%d (reg2: R%d) in block %d\n", state->reg1, state->reg2, cfg->cbb->block_num);
7067 state->reg1 = mono_regstate_next_int (cfg->rs);
7068 state->reg2 = mono_regstate_next_int (cfg->rs);
7071 state->reg1 = mono_regstate_next_float (cfg->rs);
7078 mono_burg_kids (state, ern, kids);
7080 emit_state (cfg, kids [0], nts [0]);
7082 emit_state (cfg, kids [1], nts [1]);
7084 g_assert (!nts [3]);
7085 emit_state (cfg, kids [2], nts [2]);
7090 // g_print ("emit: %s (%p)\n", mono_burg_rule_string [ern], state);
7091 if ((emit = mono_burg_func [ern]))
7092 emit (state, state->tree, cfg);
7095 #define DEBUG_SELECTION
7098 mini_select_instructions (MonoCompile *cfg)
7100 static const int reverse_map [] = {
7101 CEE_BNE_UN, CEE_BLT, CEE_BLE, CEE_BGT, CEE_BGE,
7102 CEE_BEQ, CEE_BLT_UN, CEE_BLE_UN, CEE_BGT_UN, CEE_BGE_UN
7104 static const int reverse_fmap [] = {
7105 OP_FBNE_UN, OP_FBLT, OP_FBLE, OP_FBGT, OP_FBGE,
7106 OP_FBEQ, OP_FBLT_UN, OP_FBLE_UN, OP_FBGT_UN, OP_FBGE_UN
7108 static const int reverse_lmap [] = {
7109 OP_LBNE_UN, OP_LBLT, OP_LBLE, OP_LBGT, OP_LBGE,
7110 OP_LBEQ, OP_LBLT_UN, OP_LBLE_UN, OP_LBGT_UN, OP_LBGE_UN
7112 static const int reverse_imap [] = {
7113 OP_IBNE_UN, OP_IBLT, OP_IBLE, OP_IBGT, OP_IBGE,
7114 OP_IBEQ, OP_IBLT_UN, OP_IBLE_UN, OP_IBGT_UN, OP_IBGE_UN
7119 cfg->state_pool = mono_mempool_new ();
7120 cfg->rs = mono_regstate_new ();
7122 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
7123 if (bb->last_ins && MONO_IS_COND_BRANCH_OP (bb->last_ins) &&
7124 bb->next_bb != bb->last_ins->inst_false_bb) {
7126 /* we are careful when inverting, since bugs like #59580
7127 * could show up when dealing with NaNs.
7129 if (MONO_IS_COND_BRANCH_NOFP(bb->last_ins) && bb->next_bb == bb->last_ins->inst_true_bb) {
7130 MonoBasicBlock *tmp = bb->last_ins->inst_true_bb;
7131 bb->last_ins->inst_true_bb = bb->last_ins->inst_false_bb;
7132 bb->last_ins->inst_false_bb = tmp;
7134 if (bb->last_ins->opcode >= CEE_BEQ && bb->last_ins->opcode <= CEE_BLT_UN) {
7135 bb->last_ins->opcode = reverse_map [bb->last_ins->opcode - CEE_BEQ];
7136 } else if (bb->last_ins->opcode >= OP_FBEQ && bb->last_ins->opcode <= OP_FBLT_UN) {
7137 bb->last_ins->opcode = reverse_fmap [bb->last_ins->opcode - OP_FBEQ];
7138 } else if (bb->last_ins->opcode >= OP_LBEQ && bb->last_ins->opcode <= OP_LBLT_UN) {
7139 bb->last_ins->opcode = reverse_lmap [bb->last_ins->opcode - OP_LBEQ];
7140 } else if (bb->last_ins->opcode >= OP_IBEQ && bb->last_ins->opcode <= OP_IBLT_UN) {
7141 bb->last_ins->opcode = reverse_imap [bb->last_ins->opcode - OP_IBEQ];
7144 MonoInst *inst = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst));
7145 inst->opcode = CEE_BR;
7146 inst->inst_target_bb = bb->last_ins->inst_false_bb;
7147 mono_bblock_add_inst (bb, inst);
7152 #ifdef DEBUG_SELECTION
7153 if (cfg->verbose_level >= 4) {
7154 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
7155 MonoInst *tree = bb->code;
7156 g_print ("DUMP BLOCK %d:\n", bb->block_num);
7159 for (; tree; tree = tree->next) {
7160 mono_print_tree (tree);
7167 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
7168 MonoInst *tree = bb->code, *next;
7174 bb->last_ins = NULL;
7177 mono_regstate_reset (cfg->rs);
7179 #ifdef DEBUG_SELECTION
7180 if (cfg->verbose_level >= 3)
7181 g_print ("LABEL BLOCK %d:\n", bb->block_num);
7183 for (; tree; tree = next) {
7185 #ifdef DEBUG_SELECTION
7186 if (cfg->verbose_level >= 3) {
7187 mono_print_tree (tree);
7192 if (!(mbstate = mono_burg_label (tree, cfg))) {
7193 g_warning ("unable to label tree %p", tree);
7194 mono_print_tree (tree);
7196 g_assert_not_reached ();
7198 emit_state (cfg, mbstate, MB_NTERM_stmt);
7200 bb->max_ireg = cfg->rs->next_vireg;
7201 bb->max_freg = cfg->rs->next_vfreg;
7204 bb->last_ins->next = NULL;
7206 mono_mempool_empty (cfg->state_pool);
7208 mono_mempool_destroy (cfg->state_pool);
7212 mono_codegen (MonoCompile *cfg)
7214 MonoJumpInfo *patch_info;
7216 int i, max_epilog_size;
7219 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
7220 cfg->spill_count = 0;
7221 /* we reuse dfn here */
7222 /* bb->dfn = bb_count++; */
7223 mono_arch_local_regalloc (cfg, bb);
7226 if (cfg->prof_options & MONO_PROFILE_COVERAGE)
7227 cfg->coverage_info = mono_profiler_coverage_alloc (cfg->method, cfg->num_bblocks);
7229 code = mono_arch_emit_prolog (cfg);
7231 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
7232 code = mono_arch_instrument_prolog (cfg, mono_profiler_method_enter, code, FALSE);
7234 cfg->code_len = code - cfg->native_code;
7235 cfg->prolog_end = cfg->code_len;
7237 mono_debug_open_method (cfg);
7239 /* emit code all basic blocks */
7240 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
7241 bb->native_offset = cfg->code_len;
7242 mono_arch_output_basic_block (cfg, bb);
7244 cfg->bb_exit->native_offset = cfg->code_len;
7246 code = cfg->native_code + cfg->code_len;
7248 max_epilog_size = mono_arch_max_epilog_size (cfg);
7250 /* we always allocate code in cfg->domain->code_mp to increase locality */
7251 cfg->code_size = cfg->code_len + max_epilog_size;
7252 /* fixme: align to MONO_ARCH_CODE_ALIGNMENT */
7254 mono_domain_lock (cfg->domain);
7255 code = mono_code_manager_reserve (cfg->domain->code_mp, cfg->code_size);
7256 mono_domain_unlock (cfg->domain);
7258 memcpy (code, cfg->native_code, cfg->code_len);
7259 g_free (cfg->native_code);
7260 cfg->native_code = code;
7261 code = cfg->native_code + cfg->code_len;
7263 /* g_assert (((int)cfg->native_code & (MONO_ARCH_CODE_ALIGNMENT - 1)) == 0); */
7265 cfg->epilog_begin = cfg->code_len;
7267 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
7268 code = mono_arch_instrument_epilog (cfg, mono_profiler_method_leave, code, FALSE);
7270 cfg->code_len = code - cfg->native_code;
7272 mono_arch_emit_epilog (cfg);
7274 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
7275 switch (patch_info->type) {
7276 case MONO_PATCH_INFO_ABS: {
7277 MonoJitICallInfo *info = mono_find_jit_icall_by_addr (patch_info->data.target);
7279 //printf ("TEST %s %p\n", info->name, patch_info->data.target);
7280 if ((cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) &&
7281 strstr (cfg->method->name, info->name))
7283 * This is an icall wrapper, and this is a call to the
7288 patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
7289 patch_info->data.name = info->name;
7293 MonoVTable *vtable = mono_find_class_init_trampoline_by_addr (patch_info->data.target);
7295 patch_info->type = MONO_PATCH_INFO_CLASS_INIT;
7296 patch_info->data.klass = vtable->klass;
7301 case MONO_PATCH_INFO_SWITCH: {
7303 mono_domain_lock (cfg->domain);
7304 table = mono_code_manager_reserve (cfg->domain->code_mp, sizeof (gpointer) * patch_info->table_size);
7305 mono_domain_unlock (cfg->domain);
7307 patch_info->ip.i = patch_info->ip.label->inst_c0;
7308 for (i = 0; i < patch_info->table_size; i++) {
7309 table [i] = (gpointer)patch_info->data.table [i]->native_offset;
7311 patch_info->data.target = table;
7320 if (cfg->verbose_level > 0)
7321 g_print ("Method %s emitted at %p to %p [%s]\n",
7322 mono_method_full_name (cfg->method, TRUE),
7323 cfg->native_code, cfg->native_code + cfg->code_len, cfg->domain->friendly_name);
7325 mono_arch_patch_code (cfg->method, cfg->domain, cfg->native_code, cfg->patch_info, cfg->run_cctors);
7327 mono_domain_lock (cfg->domain);
7328 mono_code_manager_commit (cfg->domain->code_mp, cfg->native_code, cfg->code_size, cfg->code_len);
7329 mono_domain_unlock (cfg->domain);
7331 mono_arch_flush_icache (cfg->native_code, cfg->code_len);
7333 mono_debug_close_method (cfg);
7337 mono_cprop_copy_values (MonoCompile *cfg, MonoInst *tree, MonoInst **acp)
7342 if (tree->ssa_op == MONO_SSA_LOAD && (tree->inst_i0->opcode == OP_LOCAL || tree->inst_i0->opcode == OP_ARG) &&
7343 (cp = acp [tree->inst_i0->inst_c0]) && !tree->inst_i0->flags) {
7345 if (cp->opcode == OP_ICONST) {
7346 if (cfg->opt & MONO_OPT_CONSPROP) {
7347 //{ static int c = 0; printf ("CCOPY %d %d %s\n", c++, cp->inst_c0, mono_method_full_name (cfg->method, TRUE)); }
7351 if (tree->inst_i0->inst_vtype->type == cp->inst_vtype->type) {
7352 if (cfg->opt & MONO_OPT_COPYPROP) {
7353 //{ static int c = 0; printf ("VCOPY %d\n", ++c); }
7359 arity = mono_burg_arity [tree->opcode];
7362 mono_cprop_copy_values (cfg, tree->inst_i0, acp);
7363 if (cfg->opt & MONO_OPT_CFOLD)
7364 mono_constant_fold_inst (tree, NULL);
7365 /* The opcode may have changed */
7366 if (mono_burg_arity [tree->opcode] > 1) {
7367 mono_cprop_copy_values (cfg, tree->inst_i1, acp);
7368 if (cfg->opt & MONO_OPT_CFOLD)
7369 mono_constant_fold_inst (tree, NULL);
7371 mono_constant_fold_inst (tree, NULL);
7377 mono_cprop_invalidate_values (MonoInst *tree, MonoInst **acp, int acp_size)
7381 switch (tree->opcode) {
7391 if (tree->ssa_op == MONO_SSA_NOP) {
7392 memset (acp, 0, sizeof (MonoInst *) * acp_size);
7409 case OP_VOIDCALL_REG:
7410 case OP_VOIDCALLVIRT:
7412 MonoCallInst *call = (MonoCallInst *)tree;
7413 MonoMethodSignature *sig = call->signature;
7414 int i, byref = FALSE;
7416 for (i = 0; i < sig->param_count; i++) {
7417 if (sig->params [i]->byref) {
7424 memset (acp, 0, sizeof (MonoInst *) * acp_size);
7432 arity = mono_burg_arity [tree->opcode];
7438 mono_cprop_invalidate_values (tree->inst_i0, acp, acp_size);
7441 mono_cprop_invalidate_values (tree->inst_i0, acp, acp_size);
7442 mono_cprop_invalidate_values (tree->inst_i1, acp, acp_size);
7445 g_assert_not_reached ();
7450 mono_local_cprop_bb (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst **acp, int acp_size)
7452 MonoInst *tree = bb->code;
7458 for (; tree; tree = tree->next) {
7460 mono_cprop_copy_values (cfg, tree, acp);
7462 mono_cprop_invalidate_values (tree, acp, acp_size);
7464 if (tree->ssa_op == MONO_SSA_STORE &&
7465 (tree->inst_i0->opcode == OP_LOCAL || tree->inst_i0->opcode == OP_ARG)) {
7466 MonoInst *i1 = tree->inst_i1;
7468 acp [tree->inst_i0->inst_c0] = NULL;
7470 for (i = 0; i < acp_size; i++) {
7471 if (acp [i] && acp [i]->opcode != OP_ICONST &&
7472 acp [i]->inst_c0 == tree->inst_i0->inst_c0) {
7477 if (i1->opcode == OP_ICONST) {
7478 acp [tree->inst_i0->inst_c0] = i1;
7479 //printf ("DEF1 BB%d %d\n", bb->block_num,tree->inst_i0->inst_c0);
7481 if (i1->ssa_op == MONO_SSA_LOAD &&
7482 (i1->inst_i0->opcode == OP_LOCAL || i1->inst_i0->opcode == OP_ARG) &&
7483 (i1->inst_i0->inst_c0 != tree->inst_i0->inst_c0)) {
7484 acp [tree->inst_i0->inst_c0] = i1->inst_i0;
7485 //printf ("DEF2 BB%d %d %d\n", bb->block_num,tree->inst_i0->inst_c0,i1->inst_i0->inst_c0);
7490 if (tree->opcode == CEE_BEQ) {
7491 g_assert (tree->inst_i0->opcode == OP_COMPARE);
7492 if (tree->inst_i0->inst_i0->opcode == OP_ICONST &&
7493 tree->inst_i0->inst_i1->opcode == OP_ICONST) {
7495 tree->opcode = CEE_BR;
7496 if (tree->inst_i0->inst_i0->opcode == tree->inst_i0->inst_i1->opcode) {
7497 tree->inst_target_bb = tree->inst_true_bb;
7499 tree->inst_target_bb = tree->inst_false_bb;
7508 mono_local_cprop (MonoCompile *cfg)
7513 acp = alloca (sizeof (MonoInst *) * cfg->num_varinfo);
7515 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
7516 memset (acp, 0, sizeof (MonoInst *) * cfg->num_varinfo);
7517 mono_local_cprop_bb (cfg, bb, acp, cfg->num_varinfo);
7522 mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gboolean run_cctors, int parts)
7524 MonoMethodHeader *header = ((MonoMethodNormal *)method)->header;
7525 guint8 *ip = (guint8 *)header->code;
7528 int dfn = 0, i, code_size_ratio;
7530 mono_jit_stats.methods_compiled++;
7531 if (mono_profiler_get_events () & MONO_PROFILE_JIT_COMPILATION)
7532 mono_profiler_method_jit (method);
7534 cfg = g_new0 (MonoCompile, 1);
7535 cfg->method = method;
7536 cfg->mempool = mono_mempool_new ();
7538 cfg->prof_options = mono_profiler_get_events ();
7539 cfg->run_cctors = run_cctors;
7540 cfg->bb_hash = g_hash_table_new (NULL, NULL);
7541 cfg->domain = domain;
7542 cfg->verbose_level = mini_verbose;
7543 cfg->intvars = mono_mempool_alloc0 (cfg->mempool, sizeof (guint16) * STACK_MAX *
7544 ((MonoMethodNormal *)method)->header->max_stack);
7546 if (cfg->verbose_level > 2)
7547 g_print ("converting method %s\n", mono_method_full_name (method, TRUE));
7550 * create MonoInst* which represents arguments and local variables
7552 mono_compile_create_vars (cfg);
7554 if ((i = mono_method_to_ir (cfg, method, NULL, NULL, cfg->locals_start, NULL, NULL, NULL, 0, FALSE)) < 0) {
7555 if (cfg->prof_options & MONO_PROFILE_JIT_COMPILATION)
7556 mono_profiler_method_end_jit (method, MONO_PROFILE_FAILED);
7557 mono_destroy_compile (cfg);
7561 mono_jit_stats.basic_blocks += cfg->num_bblocks;
7562 mono_jit_stats.max_basic_blocks = MAX (cfg->num_bblocks, mono_jit_stats.max_basic_blocks);
7564 if (cfg->num_varinfo > 2000) {
7566 * we disable some optimizations if there are too many variables
7567 * because JIT time may become too expensive. The actual number needs
7568 * to be tweaked and eventually the non-linear algorithms should be fixed.
7570 cfg->opt &= ~ (MONO_OPT_LINEARS | MONO_OPT_COPYPROP | MONO_OPT_CONSPROP);
7571 cfg->disable_ssa = TRUE;
7573 /*g_print ("numblocks = %d\n", cfg->num_bblocks);*/
7575 /* Depth-first ordering on basic blocks */
7576 cfg->bblocks = mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * (cfg->num_bblocks + 1));
7578 if (cfg->opt & MONO_OPT_BRANCH)
7579 optimize_branches (cfg);
7581 df_visit (cfg->bb_entry, &dfn, cfg->bblocks);
7582 if (cfg->num_bblocks != dfn + 1) {
7585 cfg->num_bblocks = dfn + 1;
7587 if (!header->clauses) {
7588 /* remove unreachable code, because the code in them may be
7589 * inconsistent (access to dead variables for example) */
7590 for (bb = cfg->bb_entry; bb;) {
7591 MonoBasicBlock *bbn = bb->next_bb;
7593 if (bbn && bbn->region == -1 && !bbn->dfn) {
7594 if (cfg->verbose_level > 1)
7595 g_print ("found unreachabel code in BB%d\n", bbn->block_num);
7596 bb->next_bb = bbn->next_bb;
7597 nullify_basic_block (bbn);
7605 if (cfg->opt & MONO_OPT_LOOP) {
7606 mono_compile_dominator_info (cfg, MONO_COMP_DOM | MONO_COMP_IDOM);
7607 mono_compute_natural_loops (cfg);
7610 /* after method_to_ir */
7614 //#define DEBUGSSA "logic_run"
7615 #define DEBUGSSA_CLASS "Tests"
7618 if (!header->num_clauses && !cfg->disable_ssa) {
7619 mono_local_cprop (cfg);
7620 mono_ssa_compute (cfg);
7624 /* fixme: add all optimizations which requires SSA */
7625 if (cfg->opt & (MONO_OPT_DEADCE | MONO_OPT_ABCREM)) {
7626 if (!(cfg->comp_done & MONO_COMP_SSA) && !header->num_clauses && !cfg->disable_ssa) {
7627 mono_local_cprop (cfg);
7628 mono_ssa_compute (cfg);
7630 if (cfg->verbose_level >= 2) {
7637 /* after SSA translation */
7641 if ((cfg->opt & MONO_OPT_CONSPROP) || (cfg->opt & MONO_OPT_COPYPROP)) {
7642 if (cfg->comp_done & MONO_COMP_SSA) {
7643 mono_ssa_cprop (cfg);
7645 mono_local_cprop (cfg);
7649 if (cfg->comp_done & MONO_COMP_SSA) {
7650 mono_ssa_deadce (cfg);
7652 //mono_ssa_strength_reduction (cfg);
7654 if ((cfg->flags & MONO_CFG_HAS_LDELEMA) && (cfg->opt & MONO_OPT_ABCREM))
7655 mono_perform_abc_removal (cfg);
7657 mono_ssa_remove (cfg);
7659 if (cfg->opt & MONO_OPT_BRANCH)
7660 optimize_branches (cfg);
7663 /* after SSA removal */
7667 decompose_pass (cfg);
7669 if (cfg->opt & MONO_OPT_LINEARS) {
7672 /* fixme: maybe we can avoid to compute livenesss here if already computed ? */
7673 cfg->comp_done &= ~MONO_COMP_LIVENESS;
7674 if (!(cfg->comp_done & MONO_COMP_LIVENESS))
7675 mono_analyze_liveness (cfg);
7677 if ((vars = mono_arch_get_allocatable_int_vars (cfg))) {
7678 regs = mono_arch_get_global_int_regs (cfg);
7679 mono_linear_scan (cfg, vars, regs, &cfg->used_int_regs);
7683 //mono_print_code (cfg);
7687 /* variables are allocated after decompose, since decompose could create temps */
7688 mono_arch_allocate_vars (cfg);
7690 if (cfg->opt & MONO_OPT_CFOLD)
7691 mono_constant_fold (cfg);
7693 mini_select_instructions (cfg);
7696 if (cfg->verbose_level >= 2) {
7697 char *id = mono_method_full_name (cfg->method, FALSE);
7698 mono_disassemble_code (cfg->native_code, cfg->code_len, id + 3);
7702 jinfo = mono_mempool_alloc0 (cfg->domain->mp, sizeof (MonoJitInfo));
7704 jinfo = g_new0 (MonoJitInfo, 1);
7705 jinfo->method = method;
7706 jinfo->code_start = cfg->native_code;
7707 jinfo->code_size = cfg->code_len;
7708 jinfo->used_regs = cfg->used_int_regs;
7709 jinfo->domain_neutral = (cfg->opt & MONO_OPT_SHARED) != 0;
7711 if (header->num_clauses) {
7714 jinfo->exvar_offset = cfg->exvar? cfg->exvar->inst_offset: 0;
7715 jinfo->num_clauses = header->num_clauses;
7716 jinfo->clauses = mono_mempool_alloc0 (cfg->domain->mp,
7717 sizeof (MonoJitExceptionInfo) * header->num_clauses);
7719 for (i = 0; i < header->num_clauses; i++) {
7720 MonoExceptionClause *ec = &header->clauses [i];
7721 MonoJitExceptionInfo *ei = &jinfo->clauses [i];
7722 MonoBasicBlock *tblock;
7724 ei->flags = ec->flags;
7726 if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
7727 tblock = g_hash_table_lookup (cfg->bb_hash, ip + ec->token_or_filter);
7729 ei->data.filter = cfg->native_code + tblock->native_offset;
7731 ei->data.token = ec->token_or_filter;
7734 tblock = g_hash_table_lookup (cfg->bb_hash, ip + ec->try_offset);
7736 ei->try_start = cfg->native_code + tblock->native_offset;
7737 g_assert (tblock->native_offset);
7738 tblock = g_hash_table_lookup (cfg->bb_hash, ip + ec->try_offset + ec->try_len);
7740 ei->try_end = cfg->native_code + tblock->native_offset;
7741 g_assert (tblock->native_offset);
7742 tblock = g_hash_table_lookup (cfg->bb_hash, ip + ec->handler_offset);
7744 ei->handler_start = cfg->native_code + tblock->native_offset;
7748 cfg->jit_info = jinfo;
7750 mono_jit_info_table_add (cfg->domain, jinfo);
7752 /* collect statistics */
7753 mono_jit_stats.allocated_code_size += cfg->code_len;
7754 code_size_ratio = cfg->code_len;
7755 if (code_size_ratio > mono_jit_stats.biggest_method_size) {
7756 mono_jit_stats.biggest_method_size = code_size_ratio;
7757 mono_jit_stats.biggest_method = method;
7759 code_size_ratio = (code_size_ratio * 100) / ((MonoMethodNormal *)method)->header->code_size;
7760 if (code_size_ratio > mono_jit_stats.max_code_size_ratio) {
7761 mono_jit_stats.max_code_size_ratio = code_size_ratio;
7762 mono_jit_stats.max_ratio_method = method;
7764 mono_jit_stats.native_code_size += cfg->code_len;
7766 if (cfg->prof_options & MONO_PROFILE_JIT_COMPILATION)
7767 mono_profiler_method_end_jit (method, MONO_PROFILE_OK);
7773 mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain)
7776 GHashTable *jit_code_hash;
7777 gpointer code = NULL;
7783 jit_code_hash = target_domain->jit_code_hash;
7785 #ifdef MONO_USE_AOT_COMPILER
7786 if (!mono_compile_aot && (opt & MONO_OPT_AOT)) {
7788 MonoDomain *domain = mono_domain_get ();
7790 mono_domain_lock (domain);
7792 mono_class_init (method->klass);
7793 if ((info = mono_aot_get_method (domain, method))) {
7794 g_hash_table_insert (domain->jit_code_hash, method, info);
7795 mono_domain_unlock (domain);
7796 mono_runtime_class_init (mono_class_vtable (domain, method->klass));
7797 return info->code_start;
7800 mono_domain_unlock (domain);
7804 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
7805 (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
7808 if (!method->addr) {
7809 if (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL)
7810 method->addr = mono_lookup_internal_call (method);
7812 if (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
7813 mono_lookup_pinvoke_call (method, NULL, NULL);
7815 nm = mono_marshal_get_native_wrapper (method);
7816 return mono_compile_method (nm);
7818 //if (mono_debug_format != MONO_DEBUG_FORMAT_NONE)
7819 //mono_debug_add_wrapper (method, nm);
7820 } else if ((method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME)) {
7821 const char *name = method->name;
7824 if (method->klass->parent == mono_defaults.multicastdelegate_class) {
7825 if (*name == '.' && (strcmp (name, ".ctor") == 0)) {
7826 /* FIXME: uhm, we need a wrapper to handle exceptions? */
7827 return (gpointer)mono_delegate_ctor;
7828 } else if (*name == 'I' && (strcmp (name, "Invoke") == 0)) {
7829 nm = mono_marshal_get_delegate_invoke (method);
7830 return mono_jit_compile_method (nm);
7831 } else if (*name == 'B' && (strcmp (name, "BeginInvoke") == 0)) {
7832 nm = mono_marshal_get_delegate_begin_invoke (method);
7833 return mono_jit_compile_method (nm);
7834 } else if (*name == 'E' && (strcmp (name, "EndInvoke") == 0)) {
7835 nm = mono_marshal_get_delegate_end_invoke (method);
7836 return mono_jit_compile_method (nm);
7842 cfg = mini_method_compile (method, opt, target_domain, TRUE, 0);
7844 mono_domain_lock (target_domain);
7846 /* Check if some other thread already did the job. In this case, we can
7847 discard the code this thread generated. */
7849 if ((info = g_hash_table_lookup (target_domain->jit_code_hash, method))) {
7850 /* We can't use a domain specific method in another domain */
7851 if ((target_domain == mono_domain_get ()) || info->domain_neutral) {
7852 code = info->code_start;
7853 // printf("Discarding code for method %s\n", method->name);
7858 g_hash_table_insert (jit_code_hash, method, cfg->jit_info);
7859 code = cfg->native_code;
7862 mono_destroy_compile (cfg);
7864 if (target_domain->jump_target_hash) {
7865 MonoJumpInfo patch_info;
7867 list = g_hash_table_lookup (target_domain->jump_target_hash, method);
7869 patch_info.next = NULL;
7870 patch_info.ip.i = 0;
7871 patch_info.type = MONO_PATCH_INFO_METHOD_JUMP;
7872 patch_info.data.method = method;
7873 g_hash_table_remove (target_domain->jump_target_hash, method);
7875 for (tmp = list; tmp; tmp = tmp->next)
7876 mono_arch_patch_code (NULL, target_domain, tmp->data, &patch_info, TRUE);
7877 g_slist_free (list);
7880 mono_domain_unlock (target_domain);
7882 mono_runtime_class_init (mono_class_vtable (target_domain, method->klass));
7887 mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt)
7889 /* FIXME: later copy the code from mono */
7890 MonoDomain *target_domain, *domain = mono_domain_get ();
7894 if (opt & MONO_OPT_SHARED)
7895 target_domain = mono_get_root_domain ();
7897 target_domain = domain;
7899 mono_domain_lock (target_domain);
7901 if ((info = g_hash_table_lookup (target_domain->jit_code_hash, method))) {
7902 /* We can't use a domain specific method in another domain */
7903 if (! ((domain != target_domain) && !info->domain_neutral)) {
7904 mono_domain_unlock (target_domain);
7905 mono_jit_stats.methods_lookups++;
7906 mono_runtime_class_init (mono_class_vtable (domain, method->klass));
7907 return info->code_start;
7911 mono_domain_unlock (target_domain);
7912 p = mono_jit_compile_method_inner (method, target_domain);
7917 mono_jit_compile_method (MonoMethod *method)
7919 return mono_jit_compile_method_with_opt (method, default_opt);
7923 mono_jit_find_compiled_method (MonoDomain *domain, MonoMethod *method)
7925 MonoDomain *target_domain;
7928 if (default_opt & MONO_OPT_SHARED)
7929 target_domain = mono_get_root_domain ();
7931 target_domain = domain;
7933 mono_domain_lock (target_domain);
7935 if ((info = g_hash_table_lookup (target_domain->jit_code_hash, method))) {
7936 /* We can't use a domain specific method in another domain */
7937 if (! ((domain != target_domain) && !info->domain_neutral)) {
7938 mono_domain_unlock (target_domain);
7939 mono_jit_stats.methods_lookups++;
7940 return info->code_start;
7944 mono_domain_unlock (target_domain);
7950 * mono_jit_runtime_invoke:
7951 * @method: the method to invoke
7952 * @obj: this pointer
7953 * @params: array of parameter values.
7954 * @exc: used to catch exceptions objects
7957 mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
7960 MonoObject *(*runtime_invoke) (MonoObject *this, void **params, MonoObject **exc, void* compiled_method);
7961 void* compiled_method;
7963 if (obj == NULL && !(method->flags & METHOD_ATTRIBUTE_STATIC) && !method->string_ctor && (method->wrapper_type == 0)) {
7964 g_warning ("Ignoring invocation of an instance method on a NULL instance.\n");
7968 invoke = mono_marshal_get_runtime_invoke (method);
7969 runtime_invoke = mono_jit_compile_method (invoke);
7971 /* We need this here becuase mono_marshal_get_runtime_invoke can be place
7972 * the helper method in System.Object and not the target class
7974 mono_runtime_class_init (mono_class_vtable (mono_domain_get (), method->klass));
7976 compiled_method = mono_jit_compile_method (method);
7977 return runtime_invoke (obj, params, exc, compiled_method);
7980 #ifdef PLATFORM_WIN32
7981 #define GET_CONTEXT \
7982 struct sigcontext *ctx = (struct sigcontext*)_dummy;
7985 #define GET_CONTEXT \
7986 void *ctx = context;
7987 #elif defined(sun) // Solaris x86
7988 #define GET_CONTEXT \
7989 ucontext_t *uctx = context; \
7990 struct sigcontext *ctx = (struct sigcontext *)&(uctx->uc_mcontext);
7991 #elif defined(__ppc__) || defined (__powerpc__) || defined (__s390__) || defined (MONO_ARCH_USE_SIGACTION)
7992 #define GET_CONTEXT \
7993 void *ctx = context;
7995 #define GET_CONTEXT \
7996 void **_p = (void **)&_dummy; \
7997 struct sigcontext *ctx = (struct sigcontext *)++_p;
8001 #ifdef MONO_ARCH_USE_SIGACTION
8002 #define SIG_HANDLER_SIGNATURE(ftn) ftn (int _dummy, siginfo_t *info, void *context)
8004 #define SIG_HANDLER_SIGNATURE(ftn) ftn (int _dummy)
8008 SIG_HANDLER_SIGNATURE (sigfpe_signal_handler)
8013 exc = mono_get_exception_divide_by_zero ();
8015 mono_arch_handle_exception (ctx, exc, FALSE);
8019 SIG_HANDLER_SIGNATURE (sigill_signal_handler)
8023 exc = mono_get_exception_execution_engine ("SIGILL");
8025 mono_arch_handle_exception (ctx, exc, FALSE);
8028 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
8031 sigsegv_signal_handler (int _dummy, siginfo_t *info, void *context)
8034 MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
8035 struct sigcontext *ctx = (struct sigcontext *)&(((ucontext_t*)context)->uc_mcontext);
8037 /* Can't allocate memory using Boehm GC on altstack */
8038 if (jit_tls->stack_size &&
8039 ((guint8*)info->si_addr >= (guint8*)jit_tls->end_of_stack - jit_tls->stack_size) &&
8040 ((guint8*)info->si_addr < (guint8*)jit_tls->end_of_stack))
8041 exc = mono_domain_get ()->stack_overflow_ex;
8043 exc = mono_domain_get ()->null_reference_ex;
8045 mono_arch_handle_exception (ctx, exc, FALSE);
8051 SIG_HANDLER_SIGNATURE (sigsegv_signal_handler)
8055 mono_arch_handle_exception (ctx, NULL, FALSE);
8061 SIG_HANDLER_SIGNATURE (sigusr1_signal_handler)
8063 gboolean running_managed;
8068 running_managed = (mono_jit_info_table_find (mono_domain_get (), mono_arch_ip_from_context(ctx)) != NULL);
8070 exc = mono_thread_request_interruption (running_managed);
8073 mono_arch_handle_exception (ctx, exc, FALSE);
8077 SIG_HANDLER_SIGNATURE (sigquit_signal_handler)
8082 exc = mono_get_exception_execution_engine ("Interrupted (SIGQUIT).");
8084 mono_arch_handle_exception (ctx, exc, FALSE);
8088 SIG_HANDLER_SIGNATURE (sigint_signal_handler)
8093 exc = mono_get_exception_execution_engine ("Interrupted (SIGINT).");
8095 mono_arch_handle_exception (ctx, exc, FALSE);
8098 #ifndef PLATFORM_WIN32
8100 add_signal_handler (int signo, gpointer handler)
8102 struct sigaction sa;
8104 #ifdef MONO_ARCH_USE_SIGACTION
8105 sa.sa_sigaction = handler;
8106 sigemptyset (&sa.sa_mask);
8107 sa.sa_flags = SA_SIGINFO;
8109 sa.sa_handler = handler;
8110 sigemptyset (&sa.sa_mask);
8113 g_assert (sigaction (signo, &sa, NULL) != -1);
8118 mono_runtime_install_handlers (void)
8120 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
8121 struct sigaction sa;
8124 #ifdef PLATFORM_WIN32
8126 win32_seh_set_handler(SIGFPE, sigfpe_signal_handler);
8127 win32_seh_set_handler(SIGILL, sigill_signal_handler);
8128 win32_seh_set_handler(SIGSEGV, sigsegv_signal_handler);
8129 if (getenv ("MONO_DEBUG"))
8130 win32_seh_set_handler(SIGINT, sigint_signal_handler);
8131 #else /* !PLATFORM_WIN32 */
8133 /* libpthreads has its own implementation of sigaction(),
8134 * but it seems to work well with our current exception
8135 * handlers. If not we must call syscall directly instead
8138 if (getenv ("MONO_DEBUG")) {
8139 add_signal_handler (SIGINT, sigint_signal_handler);
8142 add_signal_handler (SIGFPE, sigfpe_signal_handler);
8143 add_signal_handler (SIGQUIT, sigquit_signal_handler);
8144 add_signal_handler (SIGILL, sigill_signal_handler);
8145 add_signal_handler (SIGBUS, sigsegv_signal_handler);
8146 add_signal_handler (mono_thread_get_abort_signal (), sigusr1_signal_handler);
8149 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
8150 sa.sa_sigaction = sigsegv_signal_handler;
8151 sigemptyset (&sa.sa_mask);
8152 sa.sa_flags = SA_SIGINFO | SA_ONSTACK;
8153 g_assert (sigaction (SIGSEGV, &sa, NULL) != -1);
8155 add_signal_handler (SIGSEGV, sigsegv_signal_handler);
8158 #endif /* PLATFORM_WIN32 */
8161 /* mono_jit_create_remoting_trampoline:
8162 * @method: pointer to the method info
8164 * Creates a trampoline which calls the remoting functions. This
8165 * is used in the vtable of transparent proxies.
8167 * Returns: a pointer to the newly created code
8170 mono_jit_create_remoting_trampoline (MonoMethod *method)
8173 guint8 *addr = NULL;
8175 if ((method->flags & METHOD_ATTRIBUTE_ABSTRACT) ||
8176 (method->signature->hasthis && (method->klass->marshalbyref || method->klass == mono_defaults.object_class))) {
8177 nm = mono_marshal_get_remoting_invoke (method);
8178 addr = mono_compile_method (nm);
8180 addr = mono_compile_method (method);
8186 mini_init (const char *filename)
8190 mono_arch_cpu_init ();
8192 if (!g_thread_supported ())
8193 g_thread_init (NULL);
8195 mono_jit_tls_id = TlsAlloc ();
8196 setup_jit_tls_data ((gpointer)-1, mono_thread_abort);
8198 InitializeCriticalSection (&trampoline_hash_mutex);
8202 if (default_opt & MONO_OPT_AOT)
8205 mono_runtime_install_handlers ();
8206 mono_threads_install_cleanup (mini_thread_cleanup);
8208 #define JIT_TRAMPOLINES_WORK
8209 #ifdef JIT_TRAMPOLINES_WORK
8210 mono_install_compile_method (mono_jit_compile_method);
8211 mono_install_trampoline (mono_arch_create_jit_trampoline);
8212 mono_install_remoting_trampoline (mono_jit_create_remoting_trampoline);
8214 #define JIT_INVOKE_WORKS
8215 #ifdef JIT_INVOKE_WORKS
8216 mono_install_runtime_invoke (mono_jit_runtime_invoke);
8217 mono_install_handler (mono_arch_get_throw_exception ());
8219 mono_install_stack_walk (mono_jit_walk_stack);
8221 domain = mono_init_from_assembly (filename, filename);
8224 mono_add_internal_call ("System.Diagnostics.StackFrame::get_frame_info",
8225 ves_icall_get_frame_info);
8226 mono_add_internal_call ("System.Diagnostics.StackTrace::get_trace",
8227 ves_icall_get_trace);
8228 mono_add_internal_call ("Mono.Runtime::mono_runtime_install_handlers",
8229 mono_runtime_install_handlers);
8232 create_helper_signature ();
8234 #define JIT_CALLS_WORK
8235 #ifdef JIT_CALLS_WORK
8236 /* Needs to be called here since register_jit_icall depends on it */
8237 mono_marshal_init ();
8239 mono_arch_register_lowlevel_calls ();
8240 mono_register_jit_icall (mono_profiler_method_enter, "mono_profiler_method_enter", NULL, TRUE);
8241 mono_register_jit_icall (mono_profiler_method_leave, "mono_profiler_method_leave", NULL, TRUE);
8242 mono_register_jit_icall (mono_trace_enter_method, "mono_trace_enter_method", NULL, TRUE);
8243 mono_register_jit_icall (mono_trace_leave_method, "mono_trace_leave_method", NULL, TRUE);
8244 mono_register_jit_icall (mono_get_lmf_addr, "mono_get_lmf_addr", helper_sig_ptr_void, TRUE);
8245 mono_register_jit_icall (mono_domain_get, "mono_domain_get", helper_sig_domain_get, TRUE);
8247 /* fixme: we cant handle vararg methods this way, because the signature is not constant */
8248 //mono_register_jit_icall (ves_array_element_address, "ves_array_element_address", NULL);
8249 //mono_register_jit_icall (mono_array_new_va, "mono_array_new_va", NULL);
8251 mono_register_jit_icall (mono_arch_get_throw_exception (), "mono_arch_throw_exception", helper_sig_void_obj, TRUE);
8252 mono_register_jit_icall (mono_arch_get_throw_exception_by_name (), "mono_arch_throw_exception_by_name",
8253 helper_sig_void_ptr, TRUE);
8254 mono_register_jit_icall (mono_thread_get_pending_exception, "mono_thread_get_pending_exception", helper_sig_obj_void, FALSE);
8255 mono_register_jit_icall (mono_thread_interruption_checkpoint, "mono_thread_interruption_checkpoint", helper_sig_void_void, FALSE);
8256 mono_register_jit_icall (mono_load_remote_field_new, "mono_load_remote_field_new", helper_sig_obj_obj_ptr_ptr, FALSE);
8257 mono_register_jit_icall (mono_store_remote_field_new, "mono_store_remote_field_new", helper_sig_void_obj_ptr_ptr_obj, FALSE);
8260 * NOTE, NOTE, NOTE, NOTE:
8261 * when adding emulation for some opcodes, remember to also add a dummy
8262 * rule to the burg files, because we need the arity information to be correct.
8264 mono_register_opcode_emulation (OP_LMUL, "__emul_lmul", helper_sig_long_long_long, mono_llmult, TRUE);
8265 mono_register_opcode_emulation (OP_LMUL_OVF_UN, "__emul_lmul_ovf_un", helper_sig_long_long_long, mono_llmult_ovf_un, FALSE);
8266 mono_register_opcode_emulation (OP_LMUL_OVF, "__emul_lmul_ovf", helper_sig_long_long_long, mono_llmult_ovf, FALSE);
8267 mono_register_opcode_emulation (OP_LDIV, "__emul_ldiv", helper_sig_long_long_long, mono_lldiv, FALSE);
8268 mono_register_opcode_emulation (OP_LDIV_UN, "__emul_ldiv_un", helper_sig_long_long_long, mono_lldiv_un, FALSE);
8269 mono_register_opcode_emulation (OP_LREM, "__emul_lrem", helper_sig_long_long_long, mono_llrem, FALSE);
8270 mono_register_opcode_emulation (OP_LREM_UN, "__emul_lrem_un", helper_sig_long_long_long, mono_llrem_un, FALSE);
8272 #ifndef MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
8273 mono_register_opcode_emulation (OP_LSHL, "__emul_lshl", helper_sig_long_long_int, mono_lshl, TRUE);
8274 mono_register_opcode_emulation (OP_LSHR, "__emul_lshr", helper_sig_long_long_int, mono_lshr, TRUE);
8275 mono_register_opcode_emulation (OP_LSHR_UN, "__emul_lshr_un", helper_sig_long_long_int, mono_lshr_un, TRUE);
8278 mono_register_opcode_emulation (OP_FCONV_TO_U8, "__emul_fconv_to_u8", helper_sig_ulong_double, mono_fconv_u8, FALSE);
8279 mono_register_opcode_emulation (OP_FCONV_TO_U4, "__emul_fconv_to_u4", helper_sig_uint_double, mono_fconv_u4, FALSE);
8280 mono_register_opcode_emulation (OP_FCONV_TO_OVF_I8, "__emul_fconv_to_ovf_i8", helper_sig_long_double, mono_fconv_ovf_i8, FALSE);
8281 mono_register_opcode_emulation (OP_FCONV_TO_OVF_U8, "__emul_fconv_to_ovf_u8", helper_sig_ulong_double, mono_fconv_ovf_u8, FALSE);
8283 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
8284 mono_register_opcode_emulation (OP_FCONV_TO_I8, "__emul_fconv_to_i8", helper_sig_long_double, mono_fconv_i8, FALSE);
8286 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
8287 mono_register_opcode_emulation (CEE_CONV_R_UN, "__emul_conv_r_un", helper_sig_double_int, mono_conv_to_r8_un, FALSE);
8289 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
8290 mono_register_opcode_emulation (OP_LCONV_TO_R8, "__emul_lconv_to_r8", helper_sig_double_long, mono_lconv_to_r8, FALSE);
8292 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
8293 mono_register_opcode_emulation (OP_LCONV_TO_R4, "__emul_lconv_to_r4", helper_sig_float_long, mono_lconv_to_r4, FALSE);
8295 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
8296 mono_register_opcode_emulation (OP_LCONV_TO_R_UN, "__emul_lconv_to_r8_un", helper_sig_double_long, mono_lconv_to_r8_un, FALSE);
8298 #ifdef MONO_ARCH_EMULATE_FREM
8299 mono_register_opcode_emulation (OP_FREM, "__emul_frem", helper_sig_double_double_double, fmod, FALSE);
8302 #if SIZEOF_VOID_P == 4
8303 mono_register_opcode_emulation (OP_FCONV_TO_U, "__emul_fconv_to_u", helper_sig_uint_double, mono_fconv_u4, TRUE);
8306 #warning "fixme: add opcode emulation"
8310 /* other jit icalls */
8311 mono_register_jit_icall (mono_class_static_field_address , "mono_class_static_field_address",
8312 helper_sig_ptr_ptr_ptr, FALSE);
8313 mono_register_jit_icall (mono_ldtoken_wrapper, "mono_ldtoken_wrapper", helper_sig_ptr_ptr_ptr, FALSE);
8314 mono_register_jit_icall (mono_get_special_static_data, "mono_get_special_static_data", helper_sig_ptr_int, FALSE);
8315 mono_register_jit_icall (mono_ldstr, "mono_ldstr", helper_sig_ldstr, FALSE);
8316 mono_register_jit_icall (helper_memcpy, "helper_memcpy", helper_sig_memcpy, FALSE);
8317 mono_register_jit_icall (helper_memset, "helper_memset", helper_sig_memset, FALSE);
8318 mono_register_jit_icall (helper_initobj, "helper_initobj", helper_sig_initobj, FALSE);
8319 mono_register_jit_icall (helper_stelem_ref, "helper_stelem_ref", helper_sig_stelem_ref, FALSE);
8320 mono_register_jit_icall (helper_stelem_ref_check, "helper_stelem_ref_check", helper_sig_stelem_ref_check, FALSE);
8321 mono_register_jit_icall (mono_object_new, "mono_object_new", helper_sig_object_new, FALSE);
8322 mono_register_jit_icall (mono_object_new_specific, "mono_object_new_specific", helper_sig_object_new_specific, FALSE);
8323 mono_register_jit_icall (mono_object_new_fast, "mono_object_new_fast", helper_sig_object_new_specific, FALSE);
8324 mono_register_jit_icall (mono_array_new, "mono_array_new", helper_sig_newarr, FALSE);
8325 mono_register_jit_icall (mono_array_new_specific, "mono_array_new_specific", helper_sig_newarr_specific, FALSE);
8326 mono_register_jit_icall (mono_runtime_class_init, "mono_runtime_class_init", helper_sig_void_ptr, FALSE);
8327 mono_register_jit_icall (mono_ldftn, "mono_ldftn", helper_sig_compile, FALSE);
8328 mono_register_jit_icall (mono_ldftn_nosync, "mono_ldftn_nosync", helper_sig_compile, FALSE);
8329 mono_register_jit_icall (mono_ldvirtfn, "mono_ldvirtfn", helper_sig_compile_virt, FALSE);
8332 #define JIT_RUNTIME_WORKS
8333 #ifdef JIT_RUNTIME_WORKS
8334 mono_runtime_install_cleanup ((MonoDomainFunc)mini_cleanup);
8335 mono_runtime_init (domain, mono_thread_start_cb, mono_thread_attach_cb);
8338 mono_thread_attach (domain);
8342 MonoJitStats mono_jit_stats = {0};
8345 print_jit_stats (void)
8347 if (mono_jit_stats.enabled) {
8348 g_print ("Mono Jit statistics\n");
8349 g_print ("Compiled methods: %ld\n", mono_jit_stats.methods_compiled);
8350 g_print ("Methods from AOT: %ld\n", mono_jit_stats.methods_aot);
8351 g_print ("Methods cache lookup: %ld\n", mono_jit_stats.methods_lookups);
8352 g_print ("Method trampolines: %ld\n", mono_jit_stats.method_trampolines);
8353 g_print ("Basic blocks: %ld\n", mono_jit_stats.basic_blocks);
8354 g_print ("Max basic blocks: %ld\n", mono_jit_stats.max_basic_blocks);
8355 g_print ("Allocated vars: %ld\n", mono_jit_stats.allocate_var);
8356 g_print ("Analyze stack repeat: %ld\n", mono_jit_stats.analyze_stack_repeat);
8357 g_print ("Compiled CIL code size: %ld\n", mono_jit_stats.cil_code_size);
8358 g_print ("Native code size: %ld\n", mono_jit_stats.native_code_size);
8359 g_print ("Max code size ratio: %.2f (%s::%s)\n", mono_jit_stats.max_code_size_ratio/100.0,
8360 mono_jit_stats.max_ratio_method->klass->name, mono_jit_stats.max_ratio_method->name);
8361 g_print ("Biggest method: %ld (%s::%s)\n", mono_jit_stats.biggest_method_size,
8362 mono_jit_stats.biggest_method->klass->name, mono_jit_stats.biggest_method->name);
8363 g_print ("Code reallocs: %ld\n", mono_jit_stats.code_reallocs);
8364 g_print ("Allocated code size: %ld\n", mono_jit_stats.allocated_code_size);
8365 g_print ("Inlineable methods: %ld\n", mono_jit_stats.inlineable_methods);
8366 g_print ("Inlined methods: %ld\n", mono_jit_stats.inlined_methods);
8368 g_print ("\nCreated object count: %ld\n", mono_stats.new_object_count);
8369 g_print ("Initialized classes: %ld\n", mono_stats.initialized_class_count);
8370 g_print ("Used classes: %ld\n", mono_stats.used_class_count);
8371 g_print ("Static data size: %ld\n", mono_stats.class_static_data_size);
8372 g_print ("VTable data size: %ld\n", mono_stats.class_vtable_size);
8374 g_print ("\nGeneric instances: %ld\n", mono_stats.generic_instance_count);
8375 g_print ("Inflated methods: %ld\n", mono_stats.inflated_method_count);
8376 g_print ("Inflated types: %ld\n", mono_stats.inflated_type_count);
8377 g_print ("Generics metadata size: %ld\n", mono_stats.generics_metadata_size);
8382 mini_cleanup (MonoDomain *domain)
8385 * mono_runtime_cleanup() and mono_domain_finalize () need to
8386 * be called early since they need the execution engine still
8387 * fully working (mono_domain_finalize may invoke managed finalizers
8388 * and mono_runtime_cleanup will wait for other threads to finish).
8390 mono_domain_finalize (domain, 2000);
8392 mono_runtime_cleanup (domain);
8394 mono_profiler_shutdown ();
8396 mono_debug_cleanup ();
8398 #ifdef PLATFORM_WIN32
8399 win32_seh_cleanup();
8402 mono_domain_free (domain, TRUE);
8408 mono_set_defaults (int verbose_level, guint32 opts)
8410 mini_verbose = verbose_level;
8415 mono_precompile_assembly (MonoAssembly *ass, void *user_data)
8417 MonoImage *image = mono_assembly_get_image (ass);
8418 MonoMethod *method, *invoke;
8421 if (mini_verbose > 0)
8422 printf ("PRECOMPILE: %s.\n", mono_image_get_filename (image));
8424 for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_METHOD); ++i) {
8425 method = mono_get_method (image, MONO_TOKEN_METHOD_DEF | (i + 1), NULL);
8426 if (method->flags & METHOD_ATTRIBUTE_ABSTRACT)
8430 if (mini_verbose > 1) {
8431 char * desc = mono_method_full_name (method, TRUE);
8432 g_print ("Compiling %d %s\n", count, desc);
8435 mono_compile_method (method);
8436 if (strcmp (method->name, "Finalize") == 0) {
8437 invoke = mono_marshal_get_runtime_invoke (method);
8438 mono_compile_method (invoke);
8440 if (method->klass->marshalbyref && method->signature->hasthis) {
8441 invoke = mono_marshal_get_remoting_invoke_with_check (method);
8442 mono_compile_method (invoke);
8447 void mono_precompile_assemblies ()
8449 mono_assembly_foreach ((GFunc)mono_precompile_assembly, NULL);