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 HAVE_VALGRIND_MEMCHECK_H
17 #include <valgrind/memcheck.h>
20 #include <mono/metadata/assembly.h>
21 #include <mono/metadata/loader.h>
22 #include <mono/metadata/cil-coff.h>
23 #include <mono/metadata/tabledefs.h>
24 #include <mono/metadata/class.h>
25 #include <mono/metadata/object.h>
26 #include <mono/metadata/exception.h>
27 #include <mono/metadata/opcodes.h>
28 #include <mono/metadata/mono-endian.h>
29 #include <mono/metadata/tokentype.h>
30 #include <mono/metadata/tabledefs.h>
31 #include <mono/metadata/threads.h>
32 #include <mono/metadata/marshal.h>
33 #include <mono/metadata/socket-io.h>
34 #include <mono/metadata/appdomain.h>
35 #include <mono/metadata/debug-helpers.h>
36 #include <mono/io-layer/io-layer.h>
37 #include "mono/metadata/profiler.h"
38 #include <mono/metadata/profiler-private.h>
39 #include <mono/metadata/mono-config.h>
40 #include <mono/metadata/environment.h>
41 #include <mono/metadata/mono-debug.h>
42 #include <mono/metadata/mono-debug-debugger.h>
49 #include "jit-icalls.c"
51 #define MONO_IS_COND_BRANCH(op) ((op >= CEE_BEQ && op <= CEE_BLT_UN) || (op >= OP_LBEQ && op <= OP_LBLT_UN) || (op >= OP_FBEQ && op <= OP_FBLT_UN))
53 #define MONO_CHECK_THIS(ins) (cfg->method->signature->hasthis && (ins)->ssa_op == MONO_SSA_LOAD && (ins)->inst_left->inst_c0 == 0)
55 gboolean mono_arch_handle_exception (struct sigcontext *ctx, gpointer obj, gboolean test_only);
56 static gpointer mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt);
57 static gpointer mono_jit_compile_method (MonoMethod *method);
58 static gpointer mono_jit_find_compiled_method (MonoDomain *domain, MonoMethod *method);
60 static void handle_stobj (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *dest, MonoInst *src,
61 const unsigned char *ip, MonoClass *klass, gboolean to_end, gboolean native);
63 static void dec_foreach (MonoInst *tree, MonoCompile *cfg);
65 static int mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock,
66 int locals_offset, MonoInst *return_var, GList *dont_inline, MonoInst **inline_args,
67 guint inline_offset, gboolean is_virtual_call);
69 extern guint8 mono_burg_arity [];
70 /* helper methods signature */
71 static MonoMethodSignature *helper_sig_long_long_long = NULL;
72 static MonoMethodSignature *helper_sig_long_long_int = NULL;
73 static MonoMethodSignature *helper_sig_newarr = NULL;
74 static MonoMethodSignature *helper_sig_newarr_specific = NULL;
75 static MonoMethodSignature *helper_sig_ldstr = NULL;
76 static MonoMethodSignature *helper_sig_domain_get = NULL;
77 static MonoMethodSignature *helper_sig_object_new = NULL;
78 static MonoMethodSignature *helper_sig_object_new_specific = NULL;
79 static MonoMethodSignature *helper_sig_compile = NULL;
80 static MonoMethodSignature *helper_sig_compile_virt = NULL;
81 static MonoMethodSignature *helper_sig_obj_ptr = NULL;
82 static MonoMethodSignature *helper_sig_obj_void = NULL;
83 static MonoMethodSignature *helper_sig_ptr_void = NULL;
84 static MonoMethodSignature *helper_sig_void_ptr = NULL;
85 static MonoMethodSignature *helper_sig_void_obj = NULL;
86 static MonoMethodSignature *helper_sig_void_ptr_ptr = NULL;
87 static MonoMethodSignature *helper_sig_void_ptr_ptr_ptr = NULL;
88 static MonoMethodSignature *helper_sig_ptr_ptr_ptr = NULL;
89 static MonoMethodSignature *helper_sig_ptr_obj = NULL;
90 static MonoMethodSignature *helper_sig_ptr_int = NULL;
91 static MonoMethodSignature *helper_sig_initobj = NULL;
92 static MonoMethodSignature *helper_sig_memcpy = NULL;
93 static MonoMethodSignature *helper_sig_memset = NULL;
94 static MonoMethodSignature *helper_sig_ulong_double = NULL;
95 static MonoMethodSignature *helper_sig_long_double = NULL;
96 static MonoMethodSignature *helper_sig_double_long = NULL;
97 static MonoMethodSignature *helper_sig_float_long = NULL;
98 static MonoMethodSignature *helper_sig_double_double_double = NULL;
99 static MonoMethodSignature *helper_sig_uint_double = NULL;
100 static MonoMethodSignature *helper_sig_int_double = NULL;
101 static MonoMethodSignature *helper_sig_stelem_ref = NULL;
102 static MonoMethodSignature *helper_sig_stelem_ref_check = NULL;
103 static MonoMethodSignature *helper_sig_class_init_trampoline = NULL;
104 static MonoMethodSignature *helper_sig_obj_obj_cls = NULL;
106 static guint32 default_opt = MONO_OPT_PEEPHOLE;
108 guint32 mono_jit_tls_id = -1;
109 MonoTraceSpec *mono_jit_trace_calls = NULL;
110 gboolean mono_break_on_exc = FALSE;
111 gboolean mono_compile_aot = FALSE;
113 static int mini_verbose = 0;
115 static CRITICAL_SECTION trampoline_hash_mutex;
117 static GHashTable *class_init_hash_addr = NULL;
119 static GHashTable *jump_trampoline_hash = NULL;
121 #ifdef MONO_USE_EXC_TABLES
123 mono_type_blittable (MonoType *type)
143 case MONO_TYPE_VALUETYPE:
144 case MONO_TYPE_CLASS:
145 return type->data.klass->blittable;
155 mono_method_blittable (MonoMethod *method)
157 MonoMethodSignature *sig;
163 if (!mono_arch_has_unwind_info (method->addr)) {
167 if (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL)
170 sig = method->signature;
172 if (!mono_type_blittable (sig->ret))
175 for (i = 0; i < sig->param_count; i++)
176 if (!mono_type_blittable (sig->params [i]))
179 if (mono_method_has_marshal_info (method))
182 if ((method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) && ((MonoMethodPInvoke*)method)->piflags & PINVOKE_ATTRIBUTE_SUPPORTS_LAST_ERROR)
190 G_GNUC_UNUSED static void
191 print_method_from_ip (void *ip)
196 MonoDomain *domain = mono_domain_get ();
198 ji = mono_jit_info_table_find (domain, ip);
200 g_print ("No method at %p\n", ip);
203 method = mono_method_full_name (ji->method, TRUE);
204 source = mono_debug_source_location_from_address (ji->method, (int) ip, NULL, domain);
206 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);
209 g_print ("%s\n", source);
217 * mono_method_same_domain:
219 * Determine whenever two compiled methods are in the same domain, thus
220 * the address of the callee can be embedded in the caller.
222 gboolean mono_method_same_domain (MonoJitInfo *caller, MonoJitInfo *callee)
224 if (!caller || !callee)
228 * If the call was made from domain-neutral to domain-specific
229 * code, we can't patch the call site.
231 if (caller->domain_neutral && !callee->domain_neutral)
234 if ((caller->method->klass == mono_defaults.appdomain_class) &&
235 (strstr (caller->method->name, "InvokeInDomain"))) {
236 /* The InvokeInDomain methods change the current appdomain */
244 mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
246 MonoJumpInfoToken *res = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoToken));
253 #define MONO_INIT_VARINFO(vi,id) do { \
254 (vi)->range.first_use.pos.bid = 0xffff; \
260 * Basic blocks have two numeric identifiers:
261 * dfn: Depth First Number
262 * block_num: unique ID assigned at bblock creation
264 #define NEW_BBLOCK(cfg) (mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock)))
265 #define ADD_BBLOCK(cfg,bbhash,b) do { \
266 g_hash_table_insert (bbhash, (b)->cil_code, (b)); \
267 (b)->block_num = cfg->num_bblocks++; \
268 (b)->real_offset = real_offset; \
271 #define GET_BBLOCK(cfg,bbhash,tblock,ip) do { \
272 (tblock) = g_hash_table_lookup (bbhash, (ip)); \
274 if ((ip) >= end || (ip) < header->code) goto unverified; \
275 (tblock) = NEW_BBLOCK (cfg); \
276 (tblock)->cil_code = (ip); \
277 ADD_BBLOCK (cfg, (bbhash), (tblock)); \
279 (tblock)->real_offset = real_offset; \
282 #define CHECK_BBLOCK(target,ip,tblock) do { \
283 if ((target) < (ip) && !(tblock)->code) { \
284 bb_recheck = g_list_prepend (bb_recheck, (tblock)); \
285 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); \
289 #define NEW_ICONST(cfg,dest,val) do { \
290 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
291 (dest)->opcode = OP_ICONST; \
292 (dest)->inst_c0 = (val); \
293 (dest)->type = STACK_I4; \
296 /* FIXME: have a different definition of NEW_PCONST for 64 bit systems */
297 #define NEW_PCONST(cfg,dest,val) do { \
298 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
299 (dest)->opcode = OP_ICONST; \
300 (dest)->inst_p0 = (val); \
301 (dest)->type = STACK_PTR; \
304 #define NEW_CLASSCONST(cfg,dest,val) do { \
305 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
306 (dest)->opcode = mono_compile_aot ? OP_AOTCONST : OP_ICONST; \
307 (dest)->inst_p0 = (val); \
308 (dest)->inst_i1 = (gpointer)MONO_PATCH_INFO_CLASS; \
309 (dest)->type = STACK_PTR; \
312 #define NEW_IMAGECONST(cfg,dest,val) do { \
313 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
314 (dest)->opcode = mono_compile_aot ? OP_AOTCONST : OP_ICONST; \
315 (dest)->inst_p0 = (val); \
316 (dest)->inst_i1 = (gpointer)MONO_PATCH_INFO_IMAGE; \
317 (dest)->type = STACK_PTR; \
320 #define NEW_FIELDCONST(cfg,dest,field) do { \
321 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
322 (dest)->opcode = mono_compile_aot ? OP_AOTCONST : OP_ICONST; \
323 (dest)->inst_p0 = (field); \
324 (dest)->inst_i1 = (gpointer)MONO_PATCH_INFO_FIELD; \
325 (dest)->type = STACK_PTR; \
328 #define NEW_METHODCONST(cfg,dest,val) do { \
329 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
330 (dest)->opcode = mono_compile_aot ? OP_AOTCONST : OP_ICONST; \
331 (dest)->inst_p0 = (val); \
332 (dest)->inst_i1 = (gpointer)MONO_PATCH_INFO_METHODCONST; \
333 (dest)->type = STACK_PTR; \
336 #define NEW_VTABLECONST(cfg,dest,vtable) do { \
337 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
338 (dest)->opcode = mono_compile_aot ? OP_AOTCONST : OP_ICONST; \
339 (dest)->inst_p0 = mono_compile_aot ? (gpointer)((vtable)->klass) : (vtable); \
340 (dest)->inst_i1 = (gpointer)MONO_PATCH_INFO_VTABLE; \
341 (dest)->type = STACK_PTR; \
344 #define NEW_SFLDACONST(cfg,dest,field) do { \
345 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
346 (dest)->opcode = mono_compile_aot ? OP_AOTCONST : OP_ICONST; \
347 (dest)->inst_p0 = (field); \
348 (dest)->inst_i1 = (gpointer)MONO_PATCH_INFO_SFLDA; \
349 (dest)->type = STACK_PTR; \
352 #define NEW_LDSTRCONST(cfg,dest,image,token) do { \
353 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
354 (dest)->opcode = OP_AOTCONST; \
355 (dest)->inst_p0 = mono_jump_info_token_new ((cfg)->mempool, (image), (token)); \
356 (dest)->inst_i1 = (gpointer)MONO_PATCH_INFO_LDSTR; \
357 (dest)->type = STACK_OBJ; \
360 #define NEW_TYPE_FROM_HANDLE_CONST(cfg,dest,image,token) do { \
361 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
362 (dest)->opcode = OP_AOTCONST; \
363 (dest)->inst_p0 = mono_jump_info_token_new ((cfg)->mempool, (image), (token)); \
364 (dest)->inst_i1 = (gpointer)MONO_PATCH_INFO_TYPE_FROM_HANDLE; \
365 (dest)->type = STACK_OBJ; \
368 #define NEW_LDTOKENCONST(cfg,dest,image,token) do { \
369 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
370 (dest)->opcode = OP_AOTCONST; \
371 (dest)->inst_p0 = mono_jump_info_token_new ((cfg)->mempool, (image), (token)); \
372 (dest)->inst_i1 = (gpointer)MONO_PATCH_INFO_LDTOKEN; \
373 (dest)->type = STACK_PTR; \
376 #define NEW_DOMAINCONST(cfg,dest) do { \
377 if (cfg->opt & MONO_OPT_SHARED) { \
378 NEW_TEMPLOAD (cfg, dest, mono_get_domainvar (cfg)->inst_c0); \
380 NEW_PCONST (cfg, dest, (cfg)->domain); \
384 #define GET_VARINFO_INST(cfg,num) ((cfg)->varinfo [(num)]->inst)
386 #define NEW_ARGLOAD(cfg,dest,num) do { \
387 if (arg_array [(num)]->opcode == OP_ICONST) (dest) = arg_array [(num)]; else { \
388 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
389 (dest)->ssa_op = MONO_SSA_LOAD; \
390 (dest)->inst_i0 = arg_array [(num)]; \
391 (dest)->opcode = mono_type_to_ldind ((dest)->inst_i0->inst_vtype); \
392 type_to_eval_stack_type (param_types [(num)], (dest)); \
393 (dest)->klass = (dest)->inst_i0->klass; \
396 #define NEW_LOCLOAD(cfg,dest,num) do { \
397 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
398 (dest)->ssa_op = MONO_SSA_LOAD; \
399 (dest)->inst_i0 = (cfg)->varinfo [locals_offset + (num)]; \
400 (dest)->opcode = mono_type_to_ldind ((dest)->inst_i0->inst_vtype); \
401 type_to_eval_stack_type (header->locals [(num)], (dest)); \
402 (dest)->klass = (dest)->inst_i0->klass; \
405 #define NEW_LOCLOADA(cfg,dest,num) do { \
406 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
407 (dest)->ssa_op = MONO_SSA_MAYBE_LOAD; \
408 (dest)->inst_i0 = (cfg)->varinfo [locals_offset + (num)]; \
409 (dest)->inst_i0->flags |= MONO_INST_INDIRECT; \
410 (dest)->opcode = OP_LDADDR; \
411 (dest)->type = STACK_MP; \
412 (dest)->klass = (dest)->inst_i0->klass; \
413 if (!MONO_TYPE_ISSTRUCT (header->locals [(num)])) \
414 (cfg)->disable_ssa = TRUE; \
417 #define NEW_RETLOADA(cfg,dest) do { \
418 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
419 (dest)->ssa_op = MONO_SSA_MAYBE_LOAD; \
420 (dest)->inst_i0 = (cfg)->ret; \
421 (dest)->inst_i0->flags |= MONO_INST_INDIRECT; \
422 (dest)->opcode = CEE_LDIND_I; \
423 (dest)->type = STACK_MP; \
424 (dest)->klass = (dest)->inst_i0->klass; \
425 (cfg)->disable_ssa = TRUE; \
428 #define NEW_ARGLOADA(cfg,dest,num) do { \
429 if (arg_array [(num)]->opcode == OP_ICONST) goto inline_failure; \
430 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
431 (dest)->ssa_op = MONO_SSA_MAYBE_LOAD; \
432 (dest)->inst_i0 = arg_array [(num)]; \
433 (dest)->inst_i0->flags |= MONO_INST_INDIRECT; \
434 (dest)->opcode = OP_LDADDR; \
435 (dest)->type = STACK_MP; \
436 (dest)->klass = (dest)->inst_i0->klass; \
437 (cfg)->disable_ssa = TRUE; \
440 #define NEW_TEMPLOAD(cfg,dest,num) do { \
441 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
442 (dest)->ssa_op = MONO_SSA_LOAD; \
443 (dest)->inst_i0 = (cfg)->varinfo [(num)]; \
444 (dest)->opcode = mono_type_to_ldind ((dest)->inst_i0->inst_vtype); \
445 type_to_eval_stack_type ((dest)->inst_i0->inst_vtype, (dest)); \
446 (dest)->klass = (dest)->inst_i0->klass; \
449 #define NEW_TEMPLOADA(cfg,dest,num) do { \
450 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
451 (dest)->ssa_op = MONO_SSA_MAYBE_LOAD; \
452 (dest)->inst_i0 = (cfg)->varinfo [(num)]; \
453 (dest)->inst_i0->flags |= MONO_INST_INDIRECT; \
454 (dest)->opcode = OP_LDADDR; \
455 (dest)->type = STACK_MP; \
456 (dest)->klass = (dest)->inst_i0->klass; \
457 if (!MONO_TYPE_ISSTRUCT (cfg->varinfo [(num)]->inst_vtype)) \
458 (cfg)->disable_ssa = TRUE; \
462 #define NEW_INDLOAD(cfg,dest,addr,vtype) do { \
463 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
464 (dest)->inst_left = addr; \
465 (dest)->opcode = mono_type_to_ldind (vtype); \
466 type_to_eval_stack_type (vtype, (dest)); \
467 /* FIXME: (dest)->klass = (dest)->inst_i0->klass;*/ \
470 #define NEW_INDSTORE(cfg,dest,addr,value,vtype) do { \
471 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
472 (dest)->inst_i0 = addr; \
473 (dest)->opcode = mono_type_to_stind (vtype); \
474 (dest)->inst_i1 = (value); \
475 /* FIXME: (dest)->klass = (dest)->inst_i0->klass;*/ \
478 #define NEW_TEMPSTORE(cfg,dest,num,inst) do { \
479 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
480 (dest)->ssa_op = MONO_SSA_STORE; \
481 (dest)->inst_i0 = (cfg)->varinfo [(num)]; \
482 (dest)->opcode = mono_type_to_stind ((dest)->inst_i0->inst_vtype); \
483 (dest)->inst_i1 = (inst); \
484 (dest)->klass = (dest)->inst_i0->klass; \
487 #define NEW_LOCSTORE(cfg,dest,num,inst) do { \
488 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
489 (dest)->opcode = mono_type_to_stind (header->locals [(num)]); \
490 (dest)->ssa_op = MONO_SSA_STORE; \
491 (dest)->inst_i0 = (cfg)->varinfo [locals_offset + (num)]; \
492 (dest)->inst_i1 = (inst); \
493 (dest)->klass = (dest)->inst_i0->klass; \
496 #define NEW_ARGSTORE(cfg,dest,num,inst) do { \
497 if (arg_array [(num)]->opcode == OP_ICONST) goto inline_failure; \
498 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
499 (dest)->opcode = mono_type_to_stind (param_types [(num)]); \
500 (dest)->ssa_op = MONO_SSA_STORE; \
501 (dest)->inst_i0 = arg_array [(num)]; \
502 (dest)->inst_i1 = (inst); \
503 (dest)->klass = (dest)->inst_i0->klass; \
506 #define ADD_BINOP(op) do { \
507 MONO_INST_NEW (cfg, ins, (op)); \
508 ins->cil_code = ip; \
510 ins->inst_i0 = sp [0]; \
511 ins->inst_i1 = sp [1]; \
513 type_from_op (ins); \
517 #define ADD_UNOP(op) do { \
518 MONO_INST_NEW (cfg, ins, (op)); \
519 ins->cil_code = ip; \
521 ins->inst_i0 = sp [0]; \
523 type_from_op (ins); \
527 #define ADD_BINCOND(next_block) do { \
529 MONO_INST_NEW(cfg, cmp, OP_COMPARE); \
531 cmp->inst_i0 = sp [0]; \
532 cmp->inst_i1 = sp [1]; \
533 cmp->cil_code = ins->cil_code; \
534 type_from_op (cmp); \
536 ins->inst_i0 = cmp; \
537 MONO_ADD_INS (bblock, ins); \
538 ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2); \
539 GET_BBLOCK (cfg, bbhash, tblock, target); \
540 link_bblock (cfg, bblock, tblock); \
541 ins->inst_true_bb = tblock; \
542 CHECK_BBLOCK (target, ip, tblock); \
543 if ((next_block)) { \
544 link_bblock (cfg, bblock, (next_block)); \
545 ins->inst_false_bb = (next_block); \
546 start_new_bblock = 1; \
548 GET_BBLOCK (cfg, bbhash, tblock, ip); \
549 link_bblock (cfg, bblock, tblock); \
550 ins->inst_false_bb = tblock; \
551 start_new_bblock = 2; \
555 /* FIXME: handle float, long ... */
556 #define ADD_UNCOND(istrue) do { \
558 MONO_INST_NEW(cfg, cmp, OP_COMPARE); \
560 cmp->inst_i0 = sp [0]; \
561 switch (cmp->inst_i0->type) { \
563 cmp->inst_i1 = zero_int64; break; \
565 cmp->inst_i1 = zero_r8; break; \
568 cmp->inst_i1 = zero_ptr; break; \
570 cmp->inst_i1 = zero_obj; break; \
572 cmp->inst_i1 = zero_int32; \
574 cmp->cil_code = ins->cil_code; \
575 type_from_op (cmp); \
577 ins->inst_i0 = cmp; \
578 ins->opcode = (istrue)? CEE_BNE_UN: CEE_BEQ; \
579 MONO_ADD_INS (bblock, ins); \
580 ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2); \
581 GET_BBLOCK (cfg, bbhash, tblock, target); \
582 link_bblock (cfg, bblock, tblock); \
583 ins->inst_true_bb = tblock; \
584 CHECK_BBLOCK (target, ip, tblock); \
585 GET_BBLOCK (cfg, bbhash, tblock, ip); \
586 link_bblock (cfg, bblock, tblock); \
587 ins->inst_false_bb = tblock; \
588 start_new_bblock = 2; \
591 #define NEW_LDELEMA(cfg,dest,sp,k) do { \
592 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
593 (dest)->opcode = CEE_LDELEMA; \
594 (dest)->inst_left = (sp) [0]; \
595 (dest)->inst_right = (sp) [1]; \
596 (dest)->type = STACK_MP; \
597 (dest)->klass = (k); \
600 #define NEW_GROUP(cfg,dest,el1,el2) do { \
601 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
602 (dest)->opcode = OP_GROUP; \
603 (dest)->inst_left = (el1); \
604 (dest)->inst_right = (el2); \
609 compare_bblock (gconstpointer a, gconstpointer b)
611 const MonoBasicBlock *b1 = a;
612 const MonoBasicBlock *b2 = b;
614 return b2->cil_code - b1->cil_code;
619 * link_bblock: Links two basic blocks
621 * links two basic blocks in the control flow graph, the 'from'
622 * argument is the starting block and the 'to' argument is the block
623 * the control flow ends to after 'from'.
626 link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
628 MonoBasicBlock **newa;
632 if (from->cil_code) {
634 g_print ("edge from IL%04x to IL_%04x\n", from->cil_code - cfg->cil_code, to->cil_code - cfg->cil_code);
636 g_print ("edge from IL%04x to exit\n", from->cil_code - cfg->cil_code);
639 g_print ("edge from entry to IL_%04x\n", to->cil_code - cfg->cil_code);
641 g_print ("edge from entry to exit\n");
645 for (i = 0; i < from->out_count; ++i) {
646 if (to == from->out_bb [i]) {
652 newa = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (from->out_count + 1));
653 for (i = 0; i < from->out_count; ++i) {
654 newa [i] = from->out_bb [i];
662 for (i = 0; i < to->in_count; ++i) {
663 if (from == to->in_bb [i]) {
669 newa = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (to->in_count + 1));
670 for (i = 0; i < to->in_count; ++i) {
671 newa [i] = to->in_bb [i];
680 * mono_find_block_region:
682 * We mark each basic block with a region ID. We use that to avoid BB
683 * optimizations when blocks are in different regions.
686 * A region token that encodes where this region is, and information
687 * about the clause owner for this block.
689 * The region encodes the try/catch/filter clause that owns this block
690 * as well as the type. -1 is a special value that represents a block
691 * that is in none of try/catch/filter.
694 mono_find_block_region (MonoCompile *cfg, int offset, int *filter_lengths)
696 MonoMethod *method = cfg->method;
697 MonoMethodHeader *header = ((MonoMethodNormal *)method)->header;
698 MonoExceptionClause *clause;
701 /* first search for handlers and filters */
702 for (i = 0; i < header->num_clauses; ++i) {
703 clause = &header->clauses [i];
704 if ((clause->flags & MONO_EXCEPTION_CLAUSE_FILTER) && (offset >= clause->token_or_filter) &&
705 (offset < (clause->token_or_filter + filter_lengths [i])))
706 return ((i + 1) << 8) | MONO_REGION_FILTER | clause->flags;
708 if (MONO_OFFSET_IN_HANDLER (clause, offset)) {
709 if (clause->flags & MONO_EXCEPTION_CLAUSE_FINALLY)
710 return ((i + 1) << 8) | MONO_REGION_FINALLY | clause->flags;
712 return ((i + 1) << 8) | MONO_REGION_CATCH | clause->flags;
716 /* search the try blocks */
717 for (i = 0; i < header->num_clauses; ++i) {
718 clause = &header->clauses [i];
719 if (MONO_OFFSET_IN_CLAUSE (clause, offset))
720 return ((i + 1) << 8) | clause->flags;
727 mono_find_final_block (MonoCompile *cfg, unsigned char *ip, unsigned char *target, int type)
729 MonoMethod *method = cfg->method;
730 MonoMethodHeader *header = ((MonoMethodNormal *)method)->header;
731 MonoExceptionClause *clause;
732 MonoBasicBlock *handler;
736 for (i = 0; i < header->num_clauses; ++i) {
737 clause = &header->clauses [i];
738 if (MONO_OFFSET_IN_CLAUSE (clause, (ip - header->code)) &&
739 (!MONO_OFFSET_IN_CLAUSE (clause, (target - header->code)))) {
740 if (clause->flags == type) {
741 handler = g_hash_table_lookup (cfg->bb_hash, header->code + clause->handler_offset);
743 res = g_list_append (res, handler);
751 mono_find_spvar_for_region (MonoCompile *cfg, int region)
753 return g_hash_table_lookup (cfg->spvars, GINT_TO_POINTER (region));
757 mono_create_spvar_for_region (MonoCompile *cfg, int region)
761 var = g_hash_table_lookup (cfg->spvars, GINT_TO_POINTER (region));
765 var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
766 /* prevent it from being register allocated */
767 var->flags |= MONO_INST_INDIRECT;
769 g_hash_table_insert (cfg->spvars, GINT_TO_POINTER (region), var);
773 df_visit (MonoBasicBlock *start, int *dfn, MonoBasicBlock **array)
777 array [*dfn] = start;
778 /*g_print ("visit %d at %p\n", *dfn, start->cil_code);*/
779 for (i = 0; i < start->out_count; ++i) {
780 if (start->out_bb [i]->dfn)
783 start->out_bb [i]->dfn = *dfn;
784 start->out_bb [i]->df_parent = start;
785 array [*dfn] = start->out_bb [i];
786 df_visit (start->out_bb [i], dfn, array);
792 MonoBasicBlock *best;
796 previous_foreach (gconstpointer key, gpointer val, gpointer data)
798 PrevStruct *p = data;
799 MonoBasicBlock *bb = val;
800 //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,
801 //bb->method == p->best->method, bb->cil_code < p->code, bb->cil_code > p->best->cil_code);
803 if (bb->cil_code && bb->cil_code < p->code && bb->cil_code > p->best->cil_code)
807 static MonoBasicBlock*
808 find_previous (GHashTable *bb_hash, MonoBasicBlock *start, const guchar *code) {
814 g_hash_table_foreach (bb_hash, (GHFunc)previous_foreach, &p);
819 split_bblock (MonoCompile *cfg, MonoBasicBlock *first, MonoBasicBlock *second) {
828 * FIXME: take into account all the details:
829 * second may have been the target of more than one bblock
831 second->out_count = first->out_count;
832 second->out_bb = first->out_bb;
834 for (i = 0; i < first->out_count; ++i) {
835 bb = first->out_bb [i];
836 for (j = 0; j < bb->in_count; ++j) {
837 if (bb->in_bb [j] == first)
838 bb->in_bb [j] = second;
842 first->out_count = 0;
843 first->out_bb = NULL;
844 link_bblock (cfg, first, second);
846 second->last_ins = first->last_ins;
848 /*g_print ("start search at %p for %p\n", first->cil_code, second->cil_code);*/
849 for (inst = first->code; inst && inst->next; inst = inst->next) {
850 /*char *code = mono_disasm_code_one (NULL, cfg->method, inst->next->cil_code, NULL);
851 g_print ("found %p: %s", inst->next->cil_code, code);
853 if (inst->cil_code < second->cil_code && inst->next->cil_code >= second->cil_code) {
854 second->code = inst->next;
856 first->last_ins = inst;
857 second->next_bb = first->next_bb;
858 first->next_bb = second;
863 g_warning ("bblock split failed in %s::%s\n", cfg->method->klass->name, cfg->method->name);
869 mono_type_to_ldind (MonoType *type)
881 case MONO_TYPE_BOOLEAN:
895 case MONO_TYPE_FNPTR:
897 case MONO_TYPE_CLASS:
898 case MONO_TYPE_STRING:
899 case MONO_TYPE_OBJECT:
900 case MONO_TYPE_SZARRAY:
901 case MONO_TYPE_ARRAY:
902 return CEE_LDIND_REF;
910 case MONO_TYPE_VALUETYPE:
911 if (type->data.klass->enumtype) {
912 t = type->data.klass->enum_basetype->type;
916 case MONO_TYPE_TYPEDBYREF:
918 case MONO_TYPE_GENERICINST:
919 if (type->data.generic_inst->generic_type->type == MONO_TYPE_VALUETYPE)
921 return CEE_LDIND_REF;
923 g_error ("unknown type 0x%02x in type_to_ldind", type->type);
929 mono_type_to_stind (MonoType *type)
940 case MONO_TYPE_BOOLEAN:
952 case MONO_TYPE_FNPTR:
954 case MONO_TYPE_CLASS:
955 case MONO_TYPE_STRING:
956 case MONO_TYPE_OBJECT:
957 case MONO_TYPE_SZARRAY:
958 case MONO_TYPE_ARRAY:
959 return CEE_STIND_REF;
967 case MONO_TYPE_VALUETYPE:
968 if (type->data.klass->enumtype) {
969 t = type->data.klass->enum_basetype->type;
973 case MONO_TYPE_TYPEDBYREF:
975 case MONO_TYPE_GENERICINST:
976 if (type->data.generic_inst->generic_type->type == MONO_TYPE_VALUETYPE)
978 return CEE_STIND_REF;
980 g_error ("unknown type 0x%02x in type_to_stind", type->type);
986 * Returns the type used in the eval stack when @type is loaded.
987 * FIXME: return a MonoType/MonoClass for the byref and VALUETYPE cases.
990 type_to_eval_stack_type (MonoType *type, MonoInst *inst) {
994 inst->type = STACK_MP;
1002 case MONO_TYPE_BOOLEAN:
1005 case MONO_TYPE_CHAR:
1008 inst->type = STACK_I4;
1013 case MONO_TYPE_FNPTR:
1014 inst->type = STACK_PTR;
1016 case MONO_TYPE_CLASS:
1017 case MONO_TYPE_STRING:
1018 case MONO_TYPE_OBJECT:
1019 case MONO_TYPE_SZARRAY:
1020 case MONO_TYPE_ARRAY:
1021 inst->type = STACK_OBJ;
1025 inst->type = STACK_I8;
1029 inst->type = STACK_R8;
1031 case MONO_TYPE_VALUETYPE:
1032 if (type->data.klass->enumtype) {
1033 t = type->data.klass->enum_basetype->type;
1036 inst->klass = type->data.klass;
1037 inst->type = STACK_VTYPE;
1040 case MONO_TYPE_TYPEDBYREF:
1041 inst->klass = mono_defaults.typed_reference_class;
1042 inst->type = STACK_VTYPE;
1044 case MONO_TYPE_GENERICINST:
1045 if (type->data.generic_inst->generic_type->type == MONO_TYPE_VALUETYPE) {
1046 inst->klass = mono_class_from_mono_type (type);
1047 inst->type = STACK_VTYPE;
1049 inst->type = STACK_OBJ;
1053 g_error ("unknown type 0x%02x in eval stack type", type->type);
1058 * The following tables are used to quickly validate the IL code in type_from_op ().
1061 bin_num_table [STACK_MAX] [STACK_MAX] = {
1062 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1063 {STACK_INV, STACK_I4, STACK_INV, STACK_PTR, STACK_INV, STACK_MP, STACK_INV, STACK_INV},
1064 {STACK_INV, STACK_INV, STACK_I8, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1065 {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_MP, STACK_INV, STACK_INV},
1066 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_R8, STACK_INV, STACK_INV, STACK_INV},
1067 {STACK_INV, STACK_MP, STACK_INV, STACK_MP, STACK_INV, STACK_PTR, 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}
1074 STACK_INV, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_INV, STACK_INV, STACK_INV
1077 /* reduce the size of this table */
1079 bin_int_table [STACK_MAX] [STACK_MAX] = {
1080 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1081 {STACK_INV, STACK_I4, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1082 {STACK_INV, STACK_INV, STACK_I8, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1083 {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1084 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1085 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1086 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1087 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
1091 bin_comp_table [STACK_MAX] [STACK_MAX] = {
1093 {0, 1, 0, 1, 0, 0, 4, 0},
1094 {0, 0, 1, 0, 0, 0, 0, 0},
1095 {0, 1, 0, 1, 0, 2, 4, 0},
1096 {0, 0, 0, 0, 1, 0, 0, 0},
1097 {0, 0, 0, 2, 0, 1, 0, 0},
1098 {0, 4, 0, 4, 0, 0, 3, 0},
1099 {0, 0, 0, 0, 0, 0, 0, 0},
1102 /* reduce the size of this table */
1104 shift_table [STACK_MAX] [STACK_MAX] = {
1105 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1106 {STACK_INV, STACK_I4, STACK_INV, STACK_I4, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1107 {STACK_INV, STACK_I8, STACK_INV, STACK_I8, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1108 {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1109 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1110 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1111 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1112 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
1116 * Tables to map from the non-specific opcode to the matching
1117 * type-specific opcode.
1119 /* handles from CEE_ADD to CEE_SHR_UN (CEE_REM_UN for floats) */
1120 static const guint16
1121 binops_op_map [STACK_MAX] = {
1122 0, 0, OP_LADD-CEE_ADD, OP_PADD-CEE_ADD, OP_FADD-CEE_ADD, 0
1125 /* handles from CEE_NEG to CEE_CONV_U8 */
1126 static const guint16
1127 unops_op_map [STACK_MAX] = {
1128 0, 0, OP_LNEG-CEE_NEG, OP_PNEG-CEE_NEG, OP_FNEG-CEE_NEG, 0
1131 /* handles from CEE_CONV_U2 to CEE_SUB_OVF_UN */
1132 static const guint16
1133 ovfops_op_map [STACK_MAX] = {
1134 0, 0, OP_LCONV_TO_U2-CEE_CONV_U2, OP_PCONV_TO_U2-CEE_CONV_U2, OP_FCONV_TO_U2-CEE_CONV_U2, 0
1137 /* handles from CEE_CONV_OVF_I1_UN to CEE_CONV_OVF_U_UN */
1138 static const guint16
1139 ovf2ops_op_map [STACK_MAX] = {
1140 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, 0
1143 /* handles from CEE_CONV_OVF_I1 to CEE_CONV_OVF_U8 */
1144 static const guint16
1145 ovf3ops_op_map [STACK_MAX] = {
1146 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, 0
1149 /* handles from CEE_CEQ to CEE_CLT_UN */
1150 static const guint16
1151 ceqops_op_map [STACK_MAX] = {
1152 0, 0, OP_LCEQ-CEE_CEQ, OP_PCEQ-CEE_CEQ, OP_FCEQ-CEE_CEQ, 0
1156 * Sets ins->type (the type on the eval stack) according to the
1157 * type of the opcode and the arguments to it.
1158 * Invalid IL code is marked by setting ins->type to the invalid value STACK_INV.
1160 * FIXME: this function sets ins->type unconditionally in some cases, but
1161 * it should set it to invalid for some types (a conv.x on an object)
1164 type_from_op (MonoInst *ins) {
1165 switch (ins->opcode) {
1172 /* FIXME: check unverifiable args for STACK_MP */
1173 ins->type = bin_num_table [ins->inst_i0->type] [ins->inst_i1->type];
1174 ins->opcode += binops_op_map [ins->type];
1181 ins->type = bin_int_table [ins->inst_i0->type] [ins->inst_i1->type];
1182 ins->opcode += binops_op_map [ins->type];
1187 ins->type = shift_table [ins->inst_i0->type] [ins->inst_i1->type];
1188 ins->opcode += binops_op_map [ins->type];
1191 /* FIXME: handle some specifics with ins->next->type */
1192 ins->type = bin_comp_table [ins->inst_i0->type] [ins->inst_i1->type] ? STACK_I4: STACK_INV;
1199 ins->type = bin_comp_table [ins->inst_i0->type] [ins->inst_i1->type] ? STACK_I4: STACK_INV;
1200 ins->opcode += ceqops_op_map [ins->inst_i0->type];
1204 ins->type = neg_table [ins->inst_i0->type];
1205 ins->opcode += unops_op_map [ins->type];
1208 if (ins->inst_i0->type >= STACK_I4 && ins->inst_i0->type <= STACK_PTR)
1209 ins->type = ins->inst_i0->type;
1211 ins->type = STACK_INV;
1212 ins->opcode += unops_op_map [ins->type];
1218 ins->type = STACK_I4;
1219 ins->opcode += unops_op_map [ins->inst_i0->type];
1222 ins->type = STACK_R8;
1223 switch (ins->inst_i0->type) {
1228 ins->opcode = OP_LCONV_TO_R_UN;
1232 case CEE_CONV_OVF_I1:
1233 case CEE_CONV_OVF_U1:
1234 case CEE_CONV_OVF_I2:
1235 case CEE_CONV_OVF_U2:
1236 case CEE_CONV_OVF_I4:
1237 case CEE_CONV_OVF_U4:
1238 ins->type = STACK_I4;
1239 ins->opcode += ovf3ops_op_map [ins->inst_i0->type];
1241 case CEE_CONV_OVF_I_UN:
1242 case CEE_CONV_OVF_U_UN:
1243 ins->type = STACK_PTR;
1244 ins->opcode += ovf2ops_op_map [ins->inst_i0->type];
1246 case CEE_CONV_OVF_I1_UN:
1247 case CEE_CONV_OVF_I2_UN:
1248 case CEE_CONV_OVF_I4_UN:
1249 case CEE_CONV_OVF_U1_UN:
1250 case CEE_CONV_OVF_U2_UN:
1251 case CEE_CONV_OVF_U4_UN:
1252 ins->type = STACK_I4;
1253 ins->opcode += ovf2ops_op_map [ins->inst_i0->type];
1256 ins->type = STACK_PTR;
1257 switch (ins->inst_i0->type) {
1263 ins->opcode = OP_LCONV_TO_U;
1266 ins->opcode = OP_FCONV_TO_U;
1272 ins->type = STACK_I8;
1273 ins->opcode += unops_op_map [ins->inst_i0->type];
1275 case CEE_CONV_OVF_I8:
1276 case CEE_CONV_OVF_U8:
1277 ins->type = STACK_I8;
1278 ins->opcode += ovf3ops_op_map [ins->inst_i0->type];
1280 case CEE_CONV_OVF_U8_UN:
1281 case CEE_CONV_OVF_I8_UN:
1282 ins->type = STACK_I8;
1283 ins->opcode += ovf2ops_op_map [ins->inst_i0->type];
1287 ins->type = STACK_R8;
1288 ins->opcode += unops_op_map [ins->inst_i0->type];
1291 ins->type = STACK_R8;
1295 ins->type = STACK_I4;
1296 ins->opcode += ovfops_op_map [ins->inst_i0->type];
1299 case CEE_CONV_OVF_I:
1300 case CEE_CONV_OVF_U:
1301 ins->type = STACK_PTR;
1302 ins->opcode += ovfops_op_map [ins->inst_i0->type];
1305 case CEE_ADD_OVF_UN:
1307 case CEE_MUL_OVF_UN:
1309 case CEE_SUB_OVF_UN:
1310 ins->type = bin_num_table [ins->inst_i0->type] [ins->inst_i1->type];
1311 ins->opcode += ovfops_op_map [ins->inst_i0->type];
1314 g_error ("opcode 0x%04x not handled in type from op", ins->opcode);
1321 STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I8, STACK_MP, STACK_R8, STACK_R8, STACK_OBJ
1324 /* map ldelem.x to the matching ldind.x opcode */
1326 ldelem_to_ldind [] = {
1340 /* map stelem.x to the matching stind.x opcode */
1342 stelem_to_stind [] = {
1356 param_table [STACK_MAX] [STACK_MAX] = {
1361 check_values_to_signature (MonoInst *args, MonoType *this, MonoMethodSignature *sig) {
1365 switch (args->type) {
1375 for (i = 0; i < sig->param_count; ++i) {
1376 switch (args [i].type) {
1380 if (!sig->params [i]->byref)
1384 if (sig->params [i]->byref)
1386 switch (sig->params [i]->type) {
1387 case MONO_TYPE_CLASS:
1388 case MONO_TYPE_STRING:
1389 case MONO_TYPE_OBJECT:
1390 case MONO_TYPE_SZARRAY:
1391 case MONO_TYPE_ARRAY:
1398 if (sig->params [i]->byref)
1400 if (sig->params [i]->type != MONO_TYPE_R4 && sig->params [i]->type != MONO_TYPE_R8)
1409 /*if (!param_table [args [i].type] [sig->params [i]->type])
1417 * When we need a pointer to the current domain many times in a method, we
1418 * call mono_domain_get() once and we store the result in a local variable.
1419 * This function returns the variable that represents the MonoDomain*.
1421 inline static MonoInst *
1422 mono_get_domainvar (MonoCompile *cfg)
1424 if (!cfg->domainvar)
1425 cfg->domainvar = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1426 return cfg->domainvar;
1430 mono_compile_create_var (MonoCompile *cfg, MonoType *type, int opcode)
1433 int num = cfg->num_varinfo;
1435 if ((num + 1) >= cfg->varinfo_count) {
1436 cfg->varinfo_count = (cfg->varinfo_count + 2) * 2;
1437 cfg->varinfo = (MonoInst **)g_realloc (cfg->varinfo, sizeof (MonoInst*) * cfg->varinfo_count);
1438 cfg->vars = (MonoMethodVar **)g_realloc (cfg->vars, sizeof (MonoMethodVar*) * cfg->varinfo_count);
1441 /*g_print ("created temp %d of type 0x%x\n", num, type->type);*/
1442 mono_jit_stats.allocate_var++;
1444 MONO_INST_NEW (cfg, inst, opcode);
1445 inst->inst_c0 = num;
1446 inst->inst_vtype = type;
1447 inst->klass = mono_class_from_mono_type (type);
1448 /* if set to 1 the variable is native */
1451 cfg->varinfo [num] = inst;
1453 cfg->vars [num] = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoMethodVar));
1454 MONO_INIT_VARINFO (cfg->vars [num], num);
1457 //g_print ("created temp %d of type %s\n", num, mono_type_get_name (type));
1462 type_from_stack_type (MonoInst *ins) {
1463 switch (ins->type) {
1464 case STACK_I4: return &mono_defaults.int32_class->byval_arg;
1465 case STACK_I8: return &mono_defaults.int64_class->byval_arg;
1466 case STACK_PTR: return &mono_defaults.int_class->byval_arg;
1467 case STACK_R8: return &mono_defaults.double_class->byval_arg;
1468 case STACK_MP: return &mono_defaults.int_class->byval_arg;
1469 case STACK_OBJ: return &mono_defaults.object_class->byval_arg;
1470 case STACK_VTYPE: return &ins->klass->byval_arg;
1472 g_error ("stack type %d to montype not handled\n", ins->type);
1478 array_access_to_klass (int opcode)
1482 return mono_defaults.byte_class;
1484 return mono_defaults.uint16_class;
1487 return mono_defaults.int_class;
1490 return mono_defaults.sbyte_class;
1493 return mono_defaults.int16_class;
1496 return mono_defaults.int32_class;
1498 return mono_defaults.uint32_class;
1501 return mono_defaults.int64_class;
1504 return mono_defaults.single_class;
1507 return mono_defaults.double_class;
1508 case CEE_LDELEM_REF:
1509 case CEE_STELEM_REF:
1510 return mono_defaults.object_class;
1512 g_assert_not_reached ();
1518 mono_add_ins_to_end (MonoBasicBlock *bb, MonoInst *inst)
1522 MONO_ADD_INS (bb, inst);
1525 switch (bb->last_ins->opcode) {
1539 while (prev->next && prev->next != bb->last_ins)
1541 if (prev == bb->code) {
1542 if (bb->last_ins == bb->code) {
1543 inst->next = bb->code;
1546 inst->next = prev->next;
1550 inst->next = bb->last_ins;
1554 // g_warning ("handle conditional jump in add_ins_to_end ()\n");
1556 MONO_ADD_INS (bb, inst);
1562 mono_add_varcopy_to_end (MonoCompile *cfg, MonoBasicBlock *bb, int src, int dest)
1564 MonoInst *inst, *load;
1566 NEW_TEMPLOAD (cfg, load, src);
1568 NEW_TEMPSTORE (cfg, inst, dest, load);
1569 if (inst->opcode == CEE_STOBJ) {
1570 NEW_TEMPLOADA (cfg, inst, dest);
1571 handle_stobj (cfg, bb, inst, load, NULL, inst->klass, TRUE, FALSE);
1573 inst->cil_code = NULL;
1574 mono_add_ins_to_end (bb, inst);
1579 * We try to share variables when possible
1582 mono_compile_get_interface_var (MonoCompile *cfg, int slot, MonoInst *ins)
1587 /* inlining can result in deeper stacks */
1588 if (slot >= ((MonoMethodNormal *)cfg->method)->header->max_stack)
1589 return mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1591 pos = ins->type - 1 + slot * STACK_MAX;
1593 switch (ins->type) {
1600 if ((vnum = cfg->intvars [pos]))
1601 return cfg->varinfo [vnum];
1602 res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1603 cfg->intvars [pos] = res->inst_c0;
1606 res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1612 * This function is called to handle items that are left on the evaluation stack
1613 * at basic block boundaries. What happens is that we save the values to local variables
1614 * and we reload them later when first entering the target basic block (with the
1615 * handle_loaded_temps () function).
1616 * A single joint point will use the same variables (stored in the array bb->out_stack or
1617 * bb->in_stack, if the basic block is before or after the joint point).
1620 handle_stack_args (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst **sp, int count) {
1622 MonoBasicBlock *outb;
1623 MonoInst *inst, **locals;
1627 if (cfg->verbose_level > 3)
1628 g_print ("%d item(s) on exit from B%d\n", count, bb->block_num);
1629 if (!bb->out_scount) {
1631 bb->out_scount = count;
1632 //g_print ("bblock %d has out:", bb->block_num);
1633 for (i = 0; i < bb->out_count; ++i) {
1634 outb = bb->out_bb [i];
1635 //g_print (" %d", outb->block_num);
1636 if (outb->in_stack) {
1638 bb->out_stack = outb->in_stack;
1644 bb->out_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * count);
1645 for (i = 0; i < count; ++i) {
1647 /* try to reuse temps already allocated for this purpouse, if they occupy the same
1648 * stack slot and if they are of the same type. */
1649 bb->out_stack [i] = mono_compile_get_interface_var (cfg, i, sp [i]);
1651 bb->out_stack [i] = mono_compile_create_var (cfg, type_from_stack_type (sp [i]), OP_LOCAL);
1656 locals = bb->out_stack;
1657 for (i = 0; i < count; ++i) {
1658 /* add store ops at the end of the bb, before the branch */
1659 NEW_TEMPSTORE (cfg, inst, locals [i]->inst_c0, sp [i]);
1660 if (inst->opcode == CEE_STOBJ) {
1661 NEW_TEMPLOADA (cfg, inst, locals [i]->inst_c0);
1662 handle_stobj (cfg, bb, inst, sp [i], sp [i]->cil_code, inst->klass, TRUE, FALSE);
1664 inst->cil_code = sp [i]->cil_code;
1665 mono_add_ins_to_end (bb, inst);
1667 if (cfg->verbose_level > 3)
1668 g_print ("storing %d to temp %d\n", i, locals [i]->inst_c0);
1671 for (i = 0; i < bb->out_count; ++i) {
1672 outb = bb->out_bb [i];
1673 if (outb->in_scount)
1674 continue; /* check they are the same locals */
1675 outb->in_scount = count;
1676 outb->in_stack = locals;
1682 ret_type_to_call_opcode (MonoType *type, int calli, int virt)
1687 return calli? OP_CALL_REG: virt? CEE_CALLVIRT: CEE_CALL;
1691 case MONO_TYPE_VOID:
1692 return calli? OP_VOIDCALL_REG: virt? OP_VOIDCALLVIRT: OP_VOIDCALL;
1695 case MONO_TYPE_BOOLEAN:
1698 case MONO_TYPE_CHAR:
1701 return calli? OP_CALL_REG: virt? CEE_CALLVIRT: CEE_CALL;
1705 return calli? OP_CALL_REG: virt? CEE_CALLVIRT: CEE_CALL;
1706 case MONO_TYPE_CLASS:
1707 case MONO_TYPE_STRING:
1708 case MONO_TYPE_OBJECT:
1709 case MONO_TYPE_SZARRAY:
1710 case MONO_TYPE_ARRAY:
1711 return calli? OP_CALL_REG: virt? CEE_CALLVIRT: CEE_CALL;
1714 return calli? OP_LCALL_REG: virt? OP_LCALLVIRT: OP_LCALL;
1717 return calli? OP_FCALL_REG: virt? OP_FCALLVIRT: OP_FCALL;
1718 case MONO_TYPE_VALUETYPE:
1719 if (type->data.klass->enumtype) {
1720 t = type->data.klass->enum_basetype->type;
1723 return calli? OP_VCALL_REG: virt? OP_VCALLVIRT: OP_VCALL;
1724 case MONO_TYPE_TYPEDBYREF:
1725 return calli? OP_VCALL_REG: virt? OP_VCALLVIRT: OP_VCALL;
1726 case MONO_TYPE_GENERICINST:
1727 t = type->data.generic_inst->generic_type->type;
1730 g_error ("unknown type 0x%02x in ret_type_to_call_opcode", type->type);
1736 mono_create_jump_table (MonoCompile *cfg, MonoInst *label, MonoBasicBlock **bbs, int num_blocks)
1738 MonoJumpInfo *ji = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfo));
1740 ji->ip.label = label;
1741 ji->type = MONO_PATCH_INFO_SWITCH;
1742 ji->data.table = bbs;
1743 ji->next = cfg->patch_info;
1744 ji->table_size = num_blocks;
1745 cfg->patch_info = ji;
1749 * When we add a tree of instructions, we need to ensure the instructions currently
1750 * on the stack are executed before (like, if we load a value from a local).
1751 * We ensure this by saving the currently loaded values to temps and rewriting the
1752 * instructions to load the values.
1753 * This is not done for opcodes that terminate a basic block (because it's handled already
1754 * by handle_stack_args ()) and for opcodes that can't change values, like POP.
1757 handle_loaded_temps (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst **stack, MonoInst **sp)
1759 MonoInst *load, *store, *temp, *ins;
1761 while (stack < sp) {
1763 /* handle also other constants */
1764 if (ins->opcode != OP_ICONST) {
1765 temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1766 NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
1767 store->cil_code = ins->cil_code;
1768 if (store->opcode == CEE_STOBJ) {
1769 NEW_TEMPLOADA (cfg, store, temp->inst_c0);
1770 handle_stobj (cfg, bblock, store, ins, ins->cil_code, temp->klass, FALSE, FALSE);
1772 MONO_ADD_INS (bblock, store);
1773 NEW_TEMPLOAD (cfg, load, temp->inst_c0);
1774 load->cil_code = ins->cil_code;
1782 * Prepare arguments for passing to a function call.
1783 * Return a non-zero value if the arguments can't be passed to the given
1785 * The type checks are not yet complete and some conversions may need
1786 * casts on 32 or 64 bit architectures.
1789 check_call_signature (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args)
1794 if (args [0]->type != STACK_OBJ && args [0]->type != STACK_MP && args [0]->type != STACK_PTR)
1798 for (i = 0; i < sig->param_count; ++i) {
1799 if (sig->params [i]->byref) {
1801 * check the result of ldelema is only passed as an argument if the byref
1802 * type matches exactly the array element type.
1803 * FIXME: if the argument as been saved on the stack as part of the
1804 * interface variable code (the value was on the stack at a basic block boundary)
1805 * we need to add the check in that case, too.
1807 if (args [i]->opcode == CEE_LDELEMA) {
1809 MonoClass *exact_class = mono_class_from_mono_type (sig->params [i]);
1810 if (!exact_class->valuetype) {
1811 MONO_INST_NEW (cfg, check, OP_CHECK_ARRAY_TYPE);
1812 check->cil_code = args [i]->cil_code;
1813 check->klass = exact_class;
1814 check->inst_left = args [i]->inst_left;
1815 check->type = STACK_OBJ;
1816 args [i]->inst_left = check;
1819 if (args [i]->type != STACK_MP && args [i]->type != STACK_PTR)
1823 simple_type = sig->params [i]->type;
1825 switch (simple_type) {
1826 case MONO_TYPE_VOID:
1831 case MONO_TYPE_BOOLEAN:
1834 case MONO_TYPE_CHAR:
1837 if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR)
1843 if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR && args [i]->type != STACK_MP && args [i]->type != STACK_OBJ)
1846 case MONO_TYPE_CLASS:
1847 case MONO_TYPE_STRING:
1848 case MONO_TYPE_OBJECT:
1849 case MONO_TYPE_SZARRAY:
1850 case MONO_TYPE_ARRAY:
1851 if (args [i]->type != STACK_OBJ)
1856 if (args [i]->type != STACK_I8)
1861 if (args [i]->type != STACK_R8)
1864 case MONO_TYPE_VALUETYPE:
1865 if (sig->params [i]->data.klass->enumtype) {
1866 simple_type = sig->params [i]->data.klass->enum_basetype->type;
1869 if (args [i]->type != STACK_VTYPE)
1872 case MONO_TYPE_TYPEDBYREF:
1873 if (args [i]->type != STACK_VTYPE)
1876 case MONO_TYPE_GENERICINST:
1877 simple_type = sig->params [i]->data.generic_inst->generic_type->type;
1881 g_error ("unknown type 0x%02x in check_call_signature", simple_type);
1888 mono_spill_call (MonoCompile *cfg, MonoBasicBlock *bblock, MonoCallInst *call, MonoMethodSignature *sig, gboolean ret_object,
1889 const guint8 *ip, gboolean to_end)
1891 MonoInst *temp, *store, *ins = (MonoInst*)call;
1892 MonoType *ret = sig->ret;
1894 if (!MONO_TYPE_IS_VOID (ret) || ret_object) {
1896 call->inst.type = STACK_OBJ;
1897 call->inst.opcode = CEE_CALL;
1898 temp = mono_compile_create_var (cfg, &mono_defaults.string_class->byval_arg, OP_LOCAL);
1900 type_to_eval_stack_type (ret, ins);
1901 temp = mono_compile_create_var (cfg, ret, OP_LOCAL);
1904 if (MONO_TYPE_ISSTRUCT (ret)) {
1907 /* we use this to allocate native sized structs */
1908 temp->unused = sig->pinvoke;
1910 NEW_TEMPLOADA (cfg, loada, temp->inst_c0);
1911 if (call->inst.opcode == OP_VCALL)
1912 ins->inst_left = loada;
1914 ins->inst_right = loada; /* a virtual or indirect call */
1917 mono_add_ins_to_end (bblock, ins);
1919 MONO_ADD_INS (bblock, ins);
1921 NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
1922 store->cil_code = ip;
1924 mono_add_ins_to_end (bblock, store);
1926 MONO_ADD_INS (bblock, store);
1928 return temp->inst_c0;
1931 mono_add_ins_to_end (bblock, ins);
1933 MONO_ADD_INS (bblock, ins);
1938 inline static MonoCallInst *
1939 mono_emit_call_args (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethodSignature *sig,
1940 MonoInst **args, int calli, int virtual, const guint8 *ip, gboolean to_end)
1945 MONO_INST_NEW_CALL (cfg, call, ret_type_to_call_opcode (sig->ret, calli, virtual));
1947 call->inst.cil_code = ip;
1949 call->signature = sig;
1950 call = mono_arch_call_opcode (cfg, bblock, call, virtual);
1952 for (arg = call->out_args; arg;) {
1953 MonoInst *narg = arg->next;
1958 mono_add_ins_to_end (bblock, arg);
1960 MONO_ADD_INS (bblock, arg);
1967 mono_emit_calli (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethodSignature *sig,
1968 MonoInst **args, MonoInst *addr, const guint8 *ip)
1970 MonoCallInst *call = mono_emit_call_args (cfg, bblock, sig, args, TRUE, FALSE, ip, FALSE);
1972 call->inst.inst_i0 = addr;
1974 return mono_spill_call (cfg, bblock, call, sig, FALSE, ip, FALSE);
1977 static MonoCallInst*
1978 mono_emit_method_call (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *method, MonoMethodSignature *sig,
1979 MonoInst **args, const guint8 *ip, MonoInst *this)
1981 gboolean virtual = this != NULL;
1984 call = mono_emit_call_args (cfg, bblock, sig, args, FALSE, virtual, ip, FALSE);
1986 if (this && sig->hasthis &&
1987 (method->klass->marshalbyref || method->klass == mono_defaults.object_class) &&
1988 !(method->flags & METHOD_ATTRIBUTE_VIRTUAL) && !MONO_CHECK_THIS (this)) {
1989 call->method = mono_marshal_get_remoting_invoke_with_check (method);
1991 call->method = method;
1993 call->inst.flags |= MONO_INST_HAS_METHOD;
1994 call->inst.inst_left = this;
2000 mono_emit_method_call_spilled (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *method,
2001 MonoMethodSignature *signature, MonoInst **args, const guint8 *ip, MonoInst *this)
2003 MonoCallInst *call = mono_emit_method_call (cfg, bblock, method, signature, args, ip, this);
2005 return mono_spill_call (cfg, bblock, call, signature, method->string_ctor, ip, FALSE);
2009 mono_emit_native_call (MonoCompile *cfg, MonoBasicBlock *bblock, gconstpointer func, MonoMethodSignature *sig,
2010 MonoInst **args, const guint8 *ip, gboolean to_end)
2016 call = mono_emit_call_args (cfg, bblock, sig, args, FALSE, FALSE, ip, to_end);
2018 return mono_spill_call (cfg, bblock, call, sig, func == mono_array_new_va, ip, to_end);
2022 mono_emit_jit_icall (MonoCompile *cfg, MonoBasicBlock *bblock, gconstpointer func, MonoInst **args, const guint8 *ip)
2024 MonoJitICallInfo *info = mono_find_jit_icall_by_addr (func);
2027 g_warning ("unregistered JIT ICall");
2028 g_assert_not_reached ();
2031 return mono_emit_native_call (cfg, bblock, mono_icall_get_wrapper (info), info->sig, args, ip, FALSE);
2035 mono_emulate_opcode (MonoCompile *cfg, MonoInst *tree, MonoInst **iargs, MonoJitICallInfo *info)
2037 MonoInst *ins, *temp = NULL, *store, *load, *begin;
2038 MonoInst *last_arg = NULL;
2042 //g_print ("emulating: ");
2043 //mono_print_tree_nl (tree);
2044 MONO_INST_NEW_CALL (cfg, call, ret_type_to_call_opcode (info->sig->ret, FALSE, FALSE));
2045 ins = (MonoInst*)call;
2047 call->inst.cil_code = tree->cil_code;
2049 call->signature = info->sig;
2051 call = mono_arch_call_opcode (cfg, cfg->cbb, call, FALSE);
2053 if (!MONO_TYPE_IS_VOID (info->sig->ret)) {
2054 temp = mono_compile_create_var (cfg, info->sig->ret, OP_LOCAL);
2055 NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
2056 store->cil_code = tree->cil_code;
2061 nargs = info->sig->param_count + info->sig->hasthis;
2063 for (last_arg = call->out_args; last_arg && last_arg->next; last_arg = last_arg->next) ;
2066 last_arg->next = store;
2069 begin = call->out_args;
2073 if (cfg->prev_ins) {
2075 * This assumes that that in a tree, emulate_opcode is called for a
2076 * node before it is called for its children. dec_foreach needs to
2077 * take this into account.
2079 store->next = cfg->prev_ins->next;
2080 cfg->prev_ins->next = begin;
2082 store->next = cfg->cbb->code;
2083 cfg->cbb->code = begin;
2086 call->fptr = mono_icall_get_wrapper (info);
2088 if (!MONO_TYPE_IS_VOID (info->sig->ret)) {
2089 NEW_TEMPLOAD (cfg, load, temp->inst_c0);
2094 static MonoMethodSignature *
2095 mono_get_element_address_signature (int arity)
2097 static GHashTable *sighash = NULL;
2098 MonoMethodSignature *res;
2102 sighash = g_hash_table_new (NULL, NULL);
2105 if ((res = g_hash_table_lookup (sighash, (gpointer)arity)))
2108 res = mono_metadata_signature_alloc (mono_defaults.corlib, arity + 1);
2110 res->params [0] = &mono_defaults.array_class->byval_arg;
2112 for (i = 1; i <= arity; i++)
2113 res->params [i] = &mono_defaults.int_class->byval_arg;
2115 res->ret = &mono_defaults.int_class->byval_arg;
2117 g_hash_table_insert (sighash, (gpointer)arity, res);
2123 handle_stobj (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *dest, MonoInst *src, const unsigned char *ip, MonoClass *klass, gboolean to_end, gboolean native) {
2124 MonoInst *iargs [3];
2130 * This check breaks with spilled vars... need to handle it during verification anyway.
2131 * g_assert (klass && klass == src->klass && klass == dest->klass);
2135 n = mono_class_native_size (klass, &align);
2137 n = mono_class_value_size (klass, &align);
2139 if ((cfg->opt & MONO_OPT_INTRINS) && !to_end && n <= sizeof (gpointer) * 5) {
2141 MONO_INST_NEW (cfg, inst, OP_MEMCPY);
2142 inst->inst_left = dest;
2143 inst->inst_right = src;
2144 inst->cil_code = ip;
2146 MONO_ADD_INS (bblock, inst);
2151 NEW_ICONST (cfg, iargs [2], n);
2153 mono_emit_native_call (cfg, bblock, helper_memcpy, helper_sig_memcpy, iargs, ip, to_end);
2157 handle_initobj (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *dest, const guchar *ip, MonoClass *klass, MonoInst **stack_start, MonoInst **sp)
2159 MonoInst *iargs [2];
2160 MonoInst *ins, *zero_int32;
2163 NEW_ICONST (cfg, zero_int32, 0);
2165 mono_class_init (klass);
2166 n = mono_class_value_size (klass, NULL);
2167 MONO_INST_NEW (cfg, ins, 0);
2169 ins->inst_left = dest;
2170 ins->inst_right = zero_int32;
2173 ins->opcode = CEE_STIND_I1;
2174 MONO_ADD_INS (bblock, ins);
2177 ins->opcode = CEE_STIND_I2;
2178 MONO_ADD_INS (bblock, ins);
2181 ins->opcode = CEE_STIND_I4;
2182 MONO_ADD_INS (bblock, ins);
2185 if (n <= sizeof (gpointer) * 5) {
2186 ins->opcode = OP_MEMSET;
2189 MONO_ADD_INS (bblock, ins);
2192 handle_loaded_temps (cfg, bblock, stack_start, sp);
2193 NEW_ICONST (cfg, ins, n);
2196 mono_emit_jit_icall (cfg, bblock, helper_initobj, iargs, ip);
2201 #define CODE_IS_STLOC(ip) (((ip) [0] >= CEE_STLOC_0 && (ip) [0] <= CEE_STLOC_3) || ((ip) [0] == CEE_STLOC_S))
2204 mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method)
2206 MonoMethodHeader *header = ((MonoMethodNormal *)method)->header;
2207 MonoMethodSignature *signature = method->signature;
2211 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
2212 (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
2213 (method->iflags & METHOD_IMPL_ATTRIBUTE_NOINLINING) ||
2214 (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) ||
2215 (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
2216 (method->klass->marshalbyref) ||
2217 !header || header->num_clauses ||
2218 /* fixme: why cant we inline valuetype returns? */
2219 MONO_TYPE_ISSTRUCT (signature->ret))
2222 /* its not worth to inline methods with valuetype arguments?? */
2223 for (i = 0; i < signature->param_count; i++) {
2224 if (MONO_TYPE_ISSTRUCT (signature->params [i])) {
2230 * if we can initialize the class of the method right away, we do,
2231 * otherwise we don't allow inlining if the class needs initialization,
2232 * since it would mean inserting a call to mono_runtime_class_init()
2233 * inside the inlined code
2235 if (!(cfg->opt & MONO_OPT_SHARED)) {
2236 vtable = mono_class_vtable (cfg->domain, method->klass);
2237 if (method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) {
2238 if (cfg->run_cctors)
2239 mono_runtime_class_init (vtable);
2241 else if (!vtable->initialized && mono_class_needs_cctor_run (method->klass, NULL))
2245 * If we're compiling for shared code
2246 * the cctor will need to be run at aot method load time, for example,
2247 * or at the end of the compilation of the inlining method.
2249 if (mono_class_needs_cctor_run (method->klass, NULL) && !((method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT)))
2252 //if (!MONO_TYPE_IS_VOID (signature->ret)) return FALSE;
2254 /* also consider num_locals? */
2255 if (getenv ("MONO_INLINELIMIT"))
2256 if (header->code_size < atoi (getenv ("MONO_INLINELIMIT"))) {
2260 if (header->code_size < 20)
2267 mini_get_ldelema_ins (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *cmethod, MonoInst **sp, unsigned char *ip, gboolean is_set)
2271 MonoMethodSignature *esig;
2273 rank = cmethod->signature->param_count - (is_set? 1: 0);
2275 if (rank == 2 && (cfg->opt & MONO_OPT_INTRINS)) {
2277 NEW_GROUP (cfg, indexes, sp [1], sp [2]);
2278 MONO_INST_NEW (cfg, addr, OP_LDELEMA2D);
2279 addr->inst_left = sp [0];
2280 addr->inst_right = indexes;
2281 addr->cil_code = ip;
2282 addr->type = STACK_MP;
2283 addr->klass = cmethod->klass;
2286 esig = mono_get_element_address_signature (rank);
2287 temp = mono_emit_native_call (cfg, bblock, ves_array_element_address, esig, sp, ip, FALSE);
2288 NEW_TEMPLOAD (cfg, addr, temp);
2292 static MonoJitICallInfo **emul_opcode_map = NULL;
2294 static inline MonoJitICallInfo *
2295 mono_find_jit_opcode_emulation (int opcode)
2297 if (emul_opcode_map)
2298 return emul_opcode_map [opcode];
2304 mini_get_opcode_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
2309 if (cmethod->klass == mono_defaults.string_class) {
2310 if (cmethod->name [0] != 'g')
2313 if (strcmp (cmethod->name, "get_Chars") == 0)
2315 else if (strcmp (cmethod->name, "get_Length") == 0)
2318 } else if (cmethod->klass == mono_defaults.object_class) {
2319 if (strcmp (cmethod->name, "GetType") == 0)
2323 } else if (cmethod->klass == mono_defaults.array_class) {
2324 if (strcmp (cmethod->name, "get_Rank") == 0)
2326 else if (strcmp (cmethod->name, "get_Length") == 0)
2331 op = mono_arch_get_opcode_for_method (cfg, cmethod, fsig, args);
2335 pc = fsig->param_count + fsig->hasthis;
2336 MONO_INST_NEW (cfg, ins, op);
2339 ins->inst_i0 = args [0];
2341 ins->inst_i1 = args [1];
2348 mono_save_args (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethodSignature *sig, MonoInst **sp, MonoInst **args)
2350 MonoInst *store, *temp;
2353 g_assert (!MONO_TYPE_ISSTRUCT (sig->ret));
2355 if (!sig->hasthis && sig->param_count == 0)
2359 if (sp [0]->opcode == OP_ICONST) {
2362 temp = mono_compile_create_var (cfg, type_from_stack_type (*sp), OP_LOCAL);
2364 NEW_TEMPSTORE (cfg, store, temp->inst_c0, *sp);
2365 store->cil_code = sp [0]->cil_code;
2366 MONO_ADD_INS (bblock, store);
2371 for (i = 0; i < sig->param_count; ++i) {
2372 if (sp [0]->opcode == OP_ICONST) {
2375 temp = mono_compile_create_var (cfg, sig->params [i], OP_LOCAL);
2377 NEW_TEMPSTORE (cfg, store, temp->inst_c0, *sp);
2378 store->cil_code = sp [0]->cil_code;
2379 if (store->opcode == CEE_STOBJ) {
2380 NEW_TEMPLOADA (cfg, store, temp->inst_c0);
2381 handle_stobj (cfg, bblock, store, *sp, sp [0]->cil_code, temp->klass, FALSE, FALSE);
2383 MONO_ADD_INS (bblock, store);
2391 inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoBasicBlock *bblock, MonoInst **sp,
2392 guchar *ip, guint real_offset, GList *dont_inline, MonoBasicBlock **last_b)
2394 MonoInst *ins, *rvar = NULL;
2395 MonoMethodHeader *cheader;
2396 MonoBasicBlock *ebblock, *sbblock;
2397 int i, costs, new_locals_offset;
2399 if (cfg->verbose_level > 2)
2400 g_print ("INLINE START %p %s -> %s\n", cmethod, mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
2402 cheader = ((MonoMethodNormal *)cmethod)->header;
2404 if (!cmethod->inline_info) {
2405 mono_jit_stats.inlineable_methods++;
2406 cmethod->inline_info = 1;
2408 /* allocate space to store the return value */
2409 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
2410 rvar = mono_compile_create_var (cfg, fsig->ret, OP_LOCAL);
2413 /* allocate local variables */
2414 new_locals_offset = cfg->num_varinfo;
2415 for (i = 0; i < cheader->num_locals; ++i)
2416 mono_compile_create_var (cfg, cheader->locals [i], OP_LOCAL);
2418 /* allocate starte and end blocks */
2419 sbblock = NEW_BBLOCK (cfg);
2420 sbblock->block_num = cfg->num_bblocks++;
2421 sbblock->real_offset = real_offset;
2423 ebblock = NEW_BBLOCK (cfg);
2424 ebblock->block_num = cfg->num_bblocks++;
2425 ebblock->real_offset = real_offset;
2427 costs = mono_method_to_ir (cfg, cmethod, sbblock, ebblock, new_locals_offset, rvar, dont_inline, sp, real_offset, *ip == CEE_CALLVIRT);
2429 if (costs >= 0 && costs < 60) {
2430 if (cfg->verbose_level > 2)
2431 g_print ("INLINE END %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
2433 mono_jit_stats.inlined_methods++;
2435 /* always add some code to avoid block split failures */
2436 MONO_INST_NEW (cfg, ins, CEE_NOP);
2437 MONO_ADD_INS (bblock, ins);
2440 bblock->next_bb = sbblock;
2441 link_bblock (cfg, bblock, sbblock);
2444 NEW_TEMPLOAD (cfg, ins, rvar->inst_c0);
2450 if (cfg->verbose_level > 2)
2451 g_print ("INLINE ABORTED %s\n", mono_method_full_name (cmethod, TRUE));
2457 * Some of these comments may well be out-of-date.
2458 * Design decisions: we do a single pass over the IL code (and we do bblock
2459 * splitting/merging in the few cases when it's required: a back jump to an IL
2460 * address that was not already seen as bblock starting point).
2461 * Code is validated as we go (full verification is still better left to metadata/verify.c).
2462 * Complex operations are decomposed in simpler ones right away. We need to let the
2463 * arch-specific code peek and poke inside this process somehow (except when the
2464 * optimizations can take advantage of the full semantic info of coarse opcodes).
2465 * All the opcodes of the form opcode.s are 'normalized' to opcode.
2466 * MonoInst->opcode initially is the IL opcode or some simplification of that
2467 * (OP_LOAD, OP_STORE). The arch-specific code may rearrange it to an arch-specific
2468 * opcode with value bigger than OP_LAST.
2469 * At this point the IR can be handed over to an interpreter, a dumb code generator
2470 * or to the optimizing code generator that will translate it to SSA form.
2472 * Profiling directed optimizations.
2473 * We may compile by default with few or no optimizations and instrument the code
2474 * or the user may indicate what methods to optimize the most either in a config file
2475 * or through repeated runs where the compiler applies offline the optimizations to
2476 * each method and then decides if it was worth it.
2479 * * consider using an array instead of an hash table (bb_hash)
2482 #define CHECK_TYPE(ins) if (!(ins)->type) goto unverified
2483 #define CHECK_STACK(num) if ((sp - stack_start) < (num)) goto unverified
2484 #define CHECK_STACK_OVF(num) if (((sp - stack_start) + (num)) > header->max_stack) goto unverified
2485 #define CHECK_ARG(num) if ((unsigned)(num) >= (unsigned)num_args) goto unverified
2486 #define CHECK_LOCAL(num) if ((unsigned)(num) >= (unsigned)header->num_locals) goto unverified
2487 #define CHECK_OPSIZE(size) if (ip + size > end) goto unverified
2489 #define TYPE_PARAM_TO_TYPE(num) (method->klass->generic_inst->type_argv [(num)])
2490 #define TYPE_PARAM_TO_CLASS(num) (mono_class_from_mono_type (TYPE_PARAM_TO_TYPE ((num))))
2492 #define MTYPE_PARAM_TO_TYPE(num) (method->signature->gen_method->mtype_argv [(num)])
2493 #define MTYPE_PARAM_TO_CLASS(num) (mono_class_from_mono_type (MTYPE_PARAM_TO_TYPE ((num))))
2496 /* offset from br.s -> br like opcodes */
2497 #define BIG_BRANCH_OFFSET 13
2500 get_basic_blocks (MonoCompile *cfg, GHashTable *bbhash, MonoMethodHeader* header, guint real_offset, unsigned char *start, unsigned char *end, unsigned char **pos)
2502 unsigned char *ip = start;
2503 unsigned char *target;
2506 MonoBasicBlock *bblock;
2507 const MonoOpcode *opcode;
2510 cli_addr = ip - start;
2511 i = mono_opcode_value ((const guint8 **)&ip);
2512 opcode = &mono_opcodes [i];
2513 switch (opcode->argument) {
2514 case MonoInlineNone:
2517 case MonoInlineString:
2518 case MonoInlineType:
2519 case MonoInlineField:
2520 case MonoInlineMethod:
2523 case MonoShortInlineR:
2530 case MonoShortInlineVar:
2531 case MonoShortInlineI:
2534 case MonoShortInlineBrTarget:
2535 target = start + cli_addr + 2 + (signed char)ip [1];
2536 GET_BBLOCK (cfg, bbhash, bblock, target);
2539 case MonoInlineBrTarget:
2540 target = start + cli_addr + 5 + (gint32)read32 (ip + 1);
2541 GET_BBLOCK (cfg, bbhash, bblock, target);
2544 case MonoInlineSwitch: {
2545 guint32 n = read32 (ip + 1);
2548 cli_addr += 5 + 4 * n;
2549 target = start + cli_addr;
2550 GET_BBLOCK (cfg, bbhash, bblock, target);
2552 for (j = 0; j < n; ++j) {
2553 target = start + cli_addr + (gint32)read32 (ip);
2554 GET_BBLOCK (cfg, bbhash, bblock, target);
2564 g_assert_not_reached ();
2573 static MonoClassField *
2574 get_generic_field_inst (MonoClassField *field, MonoClass *klass, MonoClass **retclass)
2577 for (i = 0; i < field->parent->field.count; ++i) {
2578 if (field == &field->parent->fields [i]) {
2580 return &klass->fields [i];
2586 static MonoClassField *
2587 inflate_generic_field (MonoClassField *field, MonoClass *klass, MonoClass **retclass)
2589 MonoGenericInst *ginst;
2590 MonoClassField *res;
2592 res = g_new0 (MonoClassField, 1);
2594 ginst = klass->generic_inst;
2595 res->type = mono_class_inflate_generic_type (field->type, ginst, NULL);
2600 mini_get_method (MonoImage *image, guint32 token, MonoMethod *calling_method)
2602 MonoMethod *method = mono_get_method (image, token, NULL);
2603 MonoGenericMethod *gmethod;
2605 if (!calling_method->signature->gen_method || !method->signature->gen_method)
2608 gmethod = g_new0 (MonoGenericMethod, 1);
2609 *gmethod = *calling_method->signature->gen_method;
2610 gmethod->generic_method = method;
2612 return mono_class_inflate_generic_method (method, gmethod, NULL);
2616 * mono_method_to_ir: translates IL into basic blocks containing trees
2619 mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock,
2620 int locals_offset, MonoInst *return_var, GList *dont_inline, MonoInst **inline_args,
2621 guint inline_offset, gboolean is_virtual_call)
2623 MonoInst *zero_int32, *zero_int64, *zero_ptr, *zero_obj, *zero_r8;
2624 MonoInst *ins, **sp, **stack_start;
2625 MonoBasicBlock *bblock, *tblock = NULL, *init_localsbb = NULL;
2627 MonoMethod *cmethod;
2628 MonoInst **arg_array;
2629 MonoMethodHeader *header;
2631 guint32 token, ins_flag;
2633 unsigned char *ip, *end, *target, *err_pos;
2634 static double r8_0 = 0.0;
2635 MonoMethodSignature *sig;
2636 MonoType **param_types;
2637 GList *bb_recheck = NULL, *tmp;
2638 int i, n, start_new_bblock, align;
2639 int num_calls = 0, inline_costs = 0;
2640 int *filter_lengths = NULL;
2641 int breakpoint_id = 0;
2642 guint real_offset, num_args;
2644 image = method->klass->image;
2645 header = ((MonoMethodNormal *)method)->header;
2646 sig = method->signature;
2647 num_args = sig->hasthis + sig->param_count;
2648 ip = (unsigned char*)header->code;
2649 end = ip + header->code_size;
2650 mono_jit_stats.cil_code_size += header->code_size;
2652 if (cfg->method == method) {
2654 bbhash = cfg->bb_hash;
2656 real_offset = inline_offset;
2657 bbhash = g_hash_table_new (g_direct_hash, NULL);
2660 if (cfg->verbose_level > 2)
2661 g_print ("method to IR %s\n", mono_method_full_name (method, TRUE));
2663 if (cfg->prof_options & MONO_PROFILE_INS_COVERAGE)
2664 cfg->coverage_info = mono_profiler_coverage_alloc (cfg->method, header->code_size);
2666 dont_inline = g_list_prepend (dont_inline, method);
2667 if (cfg->method == method) {
2670 cfg->bb_entry = start_bblock = NEW_BBLOCK (cfg);
2671 start_bblock->cil_code = NULL;
2672 start_bblock->cil_length = 0;
2673 start_bblock->block_num = cfg->num_bblocks++;
2676 cfg->bb_exit = end_bblock = NEW_BBLOCK (cfg);
2677 end_bblock->cil_code = NULL;
2678 end_bblock->cil_length = 0;
2679 end_bblock->block_num = cfg->num_bblocks++;
2680 g_assert (cfg->num_bblocks == 2);
2682 arg_array = alloca (sizeof (MonoInst *) * num_args);
2683 for (i = num_args - 1; i >= 0; i--)
2684 arg_array [i] = cfg->varinfo [i];
2686 if (header->num_clauses) {
2687 int size = sizeof (int) * header->num_clauses;
2688 filter_lengths = alloca (size);
2689 memset (filter_lengths, 0, size);
2691 cfg->spvars = g_hash_table_new (NULL, NULL);
2693 /* handle exception clauses */
2694 for (i = 0; i < header->num_clauses; ++i) {
2695 //unsigned char *p = ip;
2696 MonoExceptionClause *clause = &header->clauses [i];
2697 GET_BBLOCK (cfg, bbhash, tblock, ip + clause->try_offset);
2698 tblock->real_offset = clause->try_offset;
2699 GET_BBLOCK (cfg, bbhash, tblock, ip + clause->handler_offset);
2700 tblock->real_offset = clause->handler_offset;
2702 if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY ||
2703 clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
2704 MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
2705 MONO_ADD_INS (tblock, ins);
2708 /*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);
2710 g_print ("%s", mono_disasm_code_one (NULL, method, p, &p));
2712 /* catch and filter blocks get the exception object on the stack */
2713 if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE ||
2714 clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
2715 /* mostly like handle_stack_args (), but just sets the input args */
2716 /* g_print ("handling clause at IL_%04x\n", clause->handler_offset); */
2718 cfg->exvar = mono_compile_create_var (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL);
2719 /* prevent it from being register allocated */
2720 cfg->exvar->flags |= MONO_INST_INDIRECT;
2722 tblock->in_scount = 1;
2723 tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
2724 tblock->in_stack [0] = cfg->exvar;
2726 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
2727 GET_BBLOCK (cfg, bbhash, tblock, ip + clause->token_or_filter);
2728 tblock->real_offset = clause->token_or_filter;
2729 tblock->in_scount = 1;
2730 tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
2731 tblock->in_stack [0] = cfg->exvar;
2732 MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
2733 MONO_ADD_INS (tblock, ins);
2739 arg_array = alloca (sizeof (MonoInst *) * num_args);
2740 mono_save_args (cfg, start_bblock, sig, inline_args, arg_array);
2743 /* FIRST CODE BLOCK */
2744 bblock = NEW_BBLOCK (cfg);
2745 bblock->cil_code = ip;
2747 ADD_BBLOCK (cfg, bbhash, bblock);
2749 if (cfg->method == method) {
2750 breakpoint_id = mono_debugger_method_has_breakpoint (method);
2751 if (breakpoint_id && (mono_debug_format != MONO_DEBUG_FORMAT_DEBUGGER)) {
2752 MONO_INST_NEW (cfg, ins, CEE_BREAK);
2753 MONO_ADD_INS (bblock, ins);
2757 if ((header->init_locals || (cfg->method == method && (cfg->opt & MONO_OPT_SHARED))) || mono_compile_aot) {
2758 /* we use a separate basic block for the initialization code */
2759 cfg->bb_init = init_localsbb = NEW_BBLOCK (cfg);
2760 init_localsbb->real_offset = real_offset;
2761 start_bblock->next_bb = init_localsbb;
2762 init_localsbb->next_bb = bblock;
2763 link_bblock (cfg, start_bblock, init_localsbb);
2764 link_bblock (cfg, init_localsbb, bblock);
2765 init_localsbb->block_num = cfg->num_bblocks++;
2767 start_bblock->next_bb = bblock;
2768 link_bblock (cfg, start_bblock, bblock);
2771 if (get_basic_blocks (cfg, bbhash, header, real_offset, ip, end, &err_pos)) {
2776 mono_debug_init_method (cfg, bblock, breakpoint_id);
2778 param_types = mono_mempool_alloc (cfg->mempool, sizeof (MonoType*) * num_args);
2780 param_types [0] = method->klass->valuetype?&method->klass->this_arg:&method->klass->byval_arg;
2781 for (n = 0; n < sig->param_count; ++n)
2782 param_types [n + sig->hasthis] = sig->params [n];
2784 /* do this somewhere outside - not here */
2785 NEW_ICONST (cfg, zero_int32, 0);
2786 NEW_ICONST (cfg, zero_int64, 0);
2787 zero_int64->type = STACK_I8;
2788 NEW_PCONST (cfg, zero_ptr, 0);
2789 NEW_PCONST (cfg, zero_obj, 0);
2790 zero_obj->type = STACK_OBJ;
2792 MONO_INST_NEW (cfg, zero_r8, OP_R8CONST);
2793 zero_r8->type = STACK_R8;
2794 zero_r8->inst_p0 = &r8_0;
2796 /* add a check for this != NULL to inlined methods */
2797 if (is_virtual_call) {
2798 MONO_INST_NEW (cfg, ins, OP_CHECK_THIS);
2799 NEW_ARGLOAD (cfg, ins->inst_left, 0);
2801 MONO_ADD_INS (bblock, ins);
2804 /* we use a spare stack slot in SWITCH and NEWOBJ and others */
2805 stack_start = sp = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * (header->max_stack + 1));
2808 start_new_bblock = 0;
2811 if (cfg->method == method)
2812 real_offset = ip - header->code;
2814 real_offset = inline_offset;
2816 if (start_new_bblock) {
2817 bblock->cil_length = ip - bblock->cil_code;
2818 if (start_new_bblock == 2) {
2819 g_assert (ip == tblock->cil_code);
2821 GET_BBLOCK (cfg, bbhash, tblock, ip);
2823 bblock->next_bb = tblock;
2825 start_new_bblock = 0;
2826 for (i = 0; i < bblock->in_scount; ++i) {
2827 NEW_TEMPLOAD (cfg, ins, bblock->in_stack [i]->inst_c0);
2831 if ((tblock = g_hash_table_lookup (bbhash, ip)) && (tblock != bblock)) {
2832 link_bblock (cfg, bblock, tblock);
2833 if (sp != stack_start) {
2834 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
2837 bblock->next_bb = tblock;
2839 for (i = 0; i < bblock->in_scount; ++i) {
2840 NEW_TEMPLOAD (cfg, ins, bblock->in_stack [i]->inst_c0);
2846 if (cfg->coverage_info) {
2847 MonoInst *store, *one;
2848 guint32 cil_offset = ip - header->code;
2849 cfg->coverage_info->data [cil_offset].cil_code = ip;
2851 /* TODO: Use an increment here */
2852 NEW_ICONST (cfg, one, 1);
2855 NEW_PCONST (cfg, ins, &(cfg->coverage_info->data [cil_offset].count));
2858 MONO_INST_NEW (cfg, store, CEE_STIND_I);
2859 store->cil_code = ip;
2860 store->inst_left = ins;
2861 store->inst_right = one;
2863 MONO_ADD_INS (bblock, store);
2866 if (cfg->verbose_level > 3)
2867 g_print ("converting (in B%d: stack: %d) %s", bblock->block_num, sp-stack_start, mono_disasm_code_one (NULL, method, ip, NULL));
2869 /* Workaround for bug #51126 */
2870 bblock->real_offset = real_offset;
2877 MONO_INST_NEW (cfg, ins, CEE_BREAK);
2878 ins->cil_code = ip++;
2879 MONO_ADD_INS (bblock, ins);
2885 CHECK_STACK_OVF (1);
2886 n = (*ip)-CEE_LDARG_0;
2888 NEW_ARGLOAD (cfg, ins, n);
2889 ins->cil_code = ip++;
2896 CHECK_STACK_OVF (1);
2897 n = (*ip)-CEE_LDLOC_0;
2899 NEW_LOCLOAD (cfg, ins, n);
2900 ins->cil_code = ip++;
2908 n = (*ip)-CEE_STLOC_0;
2911 handle_loaded_temps (cfg, bblock, stack_start, sp);
2912 NEW_LOCSTORE (cfg, ins, n, *sp);
2914 if (ins->opcode == CEE_STOBJ) {
2915 NEW_LOCLOADA (cfg, ins, n);
2916 handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE);
2918 MONO_ADD_INS (bblock, ins);
2924 CHECK_STACK_OVF (1);
2926 NEW_ARGLOAD (cfg, ins, ip [1]);
2933 CHECK_STACK_OVF (1);
2935 NEW_ARGLOADA (cfg, ins, ip [1]);
2945 NEW_ARGSTORE (cfg, ins, ip [1], *sp);
2946 handle_loaded_temps (cfg, bblock, stack_start, sp);
2948 if (ins->opcode == CEE_STOBJ) {
2949 NEW_ARGLOADA (cfg, ins, ip [1]);
2950 handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE);
2952 MONO_ADD_INS (bblock, ins);
2957 CHECK_STACK_OVF (1);
2958 CHECK_LOCAL (ip [1]);
2959 NEW_LOCLOAD (cfg, ins, ip [1]);
2966 CHECK_STACK_OVF (1);
2967 CHECK_LOCAL (ip [1]);
2968 NEW_LOCLOADA (cfg, ins, ip [1]);
2977 handle_loaded_temps (cfg, bblock, stack_start, sp);
2978 CHECK_LOCAL (ip [1]);
2979 NEW_LOCSTORE (cfg, ins, ip [1], *sp);
2981 if (ins->opcode == CEE_STOBJ) {
2982 NEW_LOCLOADA (cfg, ins, ip [1]);
2983 handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE);
2985 MONO_ADD_INS (bblock, ins);
2990 CHECK_STACK_OVF (1);
2991 NEW_PCONST (cfg, ins, NULL);
2993 ins->type = STACK_OBJ;
2998 CHECK_STACK_OVF (1);
2999 NEW_ICONST (cfg, ins, -1);
3013 CHECK_STACK_OVF (1);
3014 NEW_ICONST (cfg, ins, (*ip) - CEE_LDC_I4_0);
3021 CHECK_STACK_OVF (1);
3023 NEW_ICONST (cfg, ins, *((signed char*)ip));
3030 CHECK_STACK_OVF (1);
3031 NEW_ICONST (cfg, ins, (gint32)read32 (ip + 1));
3038 CHECK_STACK_OVF (1);
3039 MONO_INST_NEW (cfg, ins, OP_I8CONST);
3041 ins->type = STACK_I8;
3043 ins->inst_l = (gint64)read64 (ip);
3048 float *f = g_malloc (sizeof (float));
3050 CHECK_STACK_OVF (1);
3051 MONO_INST_NEW (cfg, ins, OP_R4CONST);
3052 ins->type = STACK_R8;
3061 double *d = g_malloc (sizeof (double));
3063 CHECK_STACK_OVF (1);
3064 MONO_INST_NEW (cfg, ins, OP_R8CONST);
3065 ins->type = STACK_R8;
3074 MonoInst *temp, *store;
3076 CHECK_STACK_OVF (1);
3081 * small optimization: if the loaded value was from a local already,
3082 * just load it twice.
3084 if (ins->ssa_op == MONO_SSA_LOAD &&
3085 (ins->inst_i0->opcode == OP_LOCAL || ins->inst_i0->opcode == OP_ARG)) {
3087 MONO_INST_NEW (cfg, temp, 0);
3089 temp->cil_code = ip;
3092 temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
3093 temp->cil_code = ip;
3094 NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
3095 store->cil_code = ip;
3096 MONO_ADD_INS (bblock, store);
3097 NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
3100 NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
3110 MONO_INST_NEW (cfg, ins, CEE_POP);
3111 MONO_ADD_INS (bblock, ins);
3112 ins->cil_code = ip++;
3118 if (stack_start != sp)
3120 MONO_INST_NEW (cfg, ins, CEE_JMP);
3121 token = read32 (ip + 1);
3122 /* FIXME: check the signature matches */
3123 cmethod = mini_get_method (image, token, method);
3124 ins->inst_p0 = cmethod;
3125 MONO_ADD_INS (bblock, ins);
3127 start_new_bblock = 1;
3131 case CEE_CALLVIRT: {
3132 MonoInst *addr = NULL;
3133 MonoMethodSignature *fsig = NULL;
3134 int temp, array_rank = 0;
3135 int virtual = *ip == CEE_CALLVIRT;
3138 token = read32 (ip + 1);
3140 if (*ip == CEE_CALLI) {
3145 if (method->wrapper_type != MONO_WRAPPER_NONE)
3146 fsig = (MonoMethodSignature *)mono_method_get_wrapper_data (method, token);
3148 fsig = mono_metadata_parse_signature (image, token);
3150 n = fsig->param_count + fsig->hasthis;
3152 if (method->wrapper_type != MONO_WRAPPER_NONE) {
3153 cmethod = (MonoMethod *)mono_method_get_wrapper_data (method, token);
3155 cmethod = mini_get_method (image, token, method);
3158 if (!cmethod->klass->inited)
3159 mono_class_init (cmethod->klass);
3161 if (cmethod->signature->pinvoke) {
3162 #ifdef MONO_USE_EXC_TABLES
3163 if (mono_method_blittable (cmethod)) {
3164 fsig = cmethod->signature;
3167 MonoMethod *wrapper = mono_marshal_get_native_wrapper (cmethod);
3168 fsig = wrapper->signature;
3169 #ifdef MONO_USE_EXC_TABLES
3173 fsig = mono_method_get_signature (cmethod, image, token);
3176 n = fsig->param_count + fsig->hasthis;
3178 if (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL &&
3179 cmethod->klass->parent == mono_defaults.array_class) {
3180 array_rank = cmethod->klass->rank;
3183 if (cmethod->string_ctor)
3184 g_assert_not_reached ();
3190 //g_assert (!virtual || fsig->hasthis);
3194 if (*ip != CEE_CALLI && check_call_signature (cfg, fsig, sp))
3197 if ((ins_flag & MONO_INST_TAILCALL) && cmethod && (*ip == CEE_CALL) && (mono_metadata_signature_equal (method->signature, cmethod->signature))) {
3199 /* FIXME: This assumes the two methods has the same number and type of arguments */
3200 for (i = 0; i < n; ++i) {
3201 /* Check if argument is the same */
3202 NEW_ARGLOAD (cfg, ins, i);
3203 if ((ins->opcode == sp [i]->opcode) && (ins->inst_i0 == sp [i]->inst_i0))
3206 /* Prevent argument from being register allocated */
3207 arg_array [i]->flags |= MONO_INST_VOLATILE;
3208 NEW_ARGSTORE (cfg, ins, i, sp [i]);
3210 if (ins->opcode == CEE_STOBJ) {
3211 NEW_ARGLOADA (cfg, ins, i);
3212 handle_stobj (cfg, bblock, ins, sp [i], sp [i]->cil_code, ins->klass, FALSE, FALSE);
3215 MONO_ADD_INS (bblock, ins);
3217 MONO_INST_NEW (cfg, ins, CEE_JMP);
3219 ins->inst_p0 = cmethod;
3220 ins->inst_p1 = arg_array [0];
3221 MONO_ADD_INS (bblock, ins);
3222 start_new_bblock = 1;
3223 /* skip CEE_RET as well */
3228 if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_get_opcode_for_method (cfg, cmethod, fsig, sp))) {
3231 if (MONO_TYPE_IS_VOID (fsig->ret)) {
3232 MONO_ADD_INS (bblock, ins);
3234 type_to_eval_stack_type (fsig->ret, ins);
3243 handle_loaded_temps (cfg, bblock, stack_start, sp);
3245 if ((cfg->opt & MONO_OPT_INLINE) && cmethod &&
3246 (!virtual || !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) || (cmethod->flags & METHOD_ATTRIBUTE_FINAL)) &&
3247 mono_method_check_inlining (cfg, cmethod) &&
3248 !g_list_find (dont_inline, cmethod)) {
3250 MonoBasicBlock *ebblock;
3252 if ((costs = inline_method (cfg, cmethod, fsig, bblock, sp, ip, real_offset, dont_inline, &ebblock))) {
3256 GET_BBLOCK (cfg, bbhash, bblock, ip);
3257 ebblock->next_bb = bblock;
3258 link_bblock (cfg, ebblock, bblock);
3260 if (!MONO_TYPE_IS_VOID (fsig->ret))
3263 /* indicates start of a new block, and triggers a load of all
3264 stack arguments at bb boundarie */
3267 inline_costs += costs;
3272 inline_costs += 10 * num_calls++;
3274 /* tail recursion elimination */
3275 if ((cfg->opt & MONO_OPT_TAILC) && *ip == CEE_CALL && cmethod == method && ip [5] == CEE_RET) {
3276 gboolean has_vtargs = FALSE;
3279 /* keep it simple */
3280 for (i = fsig->param_count - 1; i >= 0; i--) {
3281 if (MONO_TYPE_ISSTRUCT (cmethod->signature->params [i]))
3286 for (i = 0; i < n; ++i) {
3287 NEW_ARGSTORE (cfg, ins, i, sp [i]);
3289 MONO_ADD_INS (bblock, ins);
3291 MONO_INST_NEW (cfg, ins, CEE_BR);
3293 MONO_ADD_INS (bblock, ins);
3294 tblock = start_bblock->out_bb [0];
3295 link_bblock (cfg, bblock, tblock);
3296 ins->inst_target_bb = tblock;
3297 start_new_bblock = 1;
3300 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
3301 /* just create a dummy - the value is never used */
3302 ins = mono_compile_create_var (cfg, fsig->ret, OP_LOCAL);
3303 NEW_TEMPLOAD (cfg, *sp, ins->inst_c0);
3311 if (*ip == CEE_CALLI) {
3313 if ((temp = mono_emit_calli (cfg, bblock, fsig, sp, addr, ip)) != -1) {
3314 NEW_TEMPLOAD (cfg, *sp, temp);
3318 } else if (array_rank) {
3321 if (strcmp (cmethod->name, "Set") == 0) { /* array Set */
3322 if (sp [fsig->param_count]->type == STACK_OBJ) {
3323 MonoInst *iargs [2];
3325 handle_loaded_temps (cfg, bblock, stack_start, sp);
3328 iargs [1] = sp [fsig->param_count];
3330 mono_emit_jit_icall (cfg, bblock, helper_stelem_ref_check, iargs, ip);
3333 addr = mini_get_ldelema_ins (cfg, bblock, cmethod, sp, ip, TRUE);
3334 NEW_INDSTORE (cfg, ins, addr, sp [fsig->param_count], fsig->params [fsig->param_count - 1]);
3336 if (ins->opcode == CEE_STOBJ) {
3337 handle_stobj (cfg, bblock, addr, sp [fsig->param_count], ip, mono_class_from_mono_type (fsig->params [fsig->param_count-1]), FALSE, FALSE);
3339 MONO_ADD_INS (bblock, ins);
3342 } else if (strcmp (cmethod->name, "Get") == 0) { /* array Get */
3343 addr = mini_get_ldelema_ins (cfg, bblock, cmethod, sp, ip, FALSE);
3344 NEW_INDLOAD (cfg, ins, addr, fsig->ret);
3348 } else if (strcmp (cmethod->name, "Address") == 0) { /* array Address */
3349 addr = mini_get_ldelema_ins (cfg, bblock, cmethod, sp, ip, FALSE);
3352 g_assert_not_reached ();
3356 if (0 && CODE_IS_STLOC (ip + 5) && (!MONO_TYPE_ISSTRUCT (fsig->ret)) && (!MONO_TYPE_IS_VOID (fsig->ret) || cmethod->string_ctor)) {
3357 /* no need to spill */
3358 ins = (MonoInst*)mono_emit_method_call (cfg, bblock, cmethod, fsig, sp, ip, virtual ? sp [0] : NULL);
3361 if ((temp = mono_emit_method_call_spilled (cfg, bblock, cmethod, fsig, sp, ip, virtual ? sp [0] : NULL)) != -1) {
3362 NEW_TEMPLOAD (cfg, *sp, temp);
3372 if (cfg->method != method) {
3373 /* return from inlined methode */
3378 //g_assert (returnvar != -1);
3379 NEW_TEMPSTORE (cfg, store, return_var->inst_c0, *sp);
3380 store->cil_code = sp [0]->cil_code;
3381 if (store->opcode == CEE_STOBJ) {
3382 g_assert_not_reached ();
3383 NEW_TEMPLOADA (cfg, store, return_var->inst_c0);
3384 handle_stobj (cfg, bblock, store, *sp, sp [0]->cil_code, return_var->klass, FALSE, FALSE);
3386 MONO_ADD_INS (bblock, store);
3390 g_assert (!return_var);
3393 MONO_INST_NEW (cfg, ins, CEE_NOP);
3394 ins->opcode = mono_type_to_stind (method->signature->ret);
3395 if (ins->opcode == CEE_STOBJ) {
3396 NEW_RETLOADA (cfg, ins);
3397 handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE);
3399 ins->opcode = OP_SETRET;
3401 ins->inst_i0 = *sp;;
3402 ins->inst_i1 = NULL;
3403 MONO_ADD_INS (bblock, ins);
3407 if (sp != stack_start)
3409 MONO_INST_NEW (cfg, ins, CEE_BR);
3410 ins->cil_code = ip++;
3411 ins->inst_target_bb = end_bblock;
3412 MONO_ADD_INS (bblock, ins);
3413 link_bblock (cfg, bblock, end_bblock);
3414 start_new_bblock = 1;
3418 MONO_INST_NEW (cfg, ins, CEE_BR);
3419 ins->cil_code = ip++;
3420 MONO_ADD_INS (bblock, ins);
3421 target = ip + 1 + (signed char)(*ip);
3423 GET_BBLOCK (cfg, bbhash, tblock, target);
3424 link_bblock (cfg, bblock, tblock);
3425 CHECK_BBLOCK (target, ip, tblock);
3426 ins->inst_target_bb = tblock;
3427 if (sp != stack_start) {
3428 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
3431 start_new_bblock = 1;
3438 MONO_INST_NEW (cfg, ins, *ip + BIG_BRANCH_OFFSET);
3439 ins->cil_code = ip++;
3440 target = ip + 1 + *(signed char*)ip;
3442 ADD_UNCOND (ins->opcode == CEE_BRTRUE);
3443 if (sp != stack_start) {
3444 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
3461 MONO_INST_NEW (cfg, ins, *ip + BIG_BRANCH_OFFSET);
3462 ins->cil_code = ip++;
3463 target = ip + 1 + *(signed char*)ip;
3466 if (sp != stack_start) {
3467 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
3474 MONO_INST_NEW (cfg, ins, CEE_BR);
3475 ins->cil_code = ip++;
3476 MONO_ADD_INS (bblock, ins);
3477 target = ip + 4 + (gint32)read32(ip);
3479 GET_BBLOCK (cfg, bbhash, tblock, target);
3480 link_bblock (cfg, bblock, tblock);
3481 CHECK_BBLOCK (target, ip, tblock);
3482 ins->inst_target_bb = tblock;
3483 if (sp != stack_start) {
3484 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
3487 start_new_bblock = 1;
3494 MONO_INST_NEW (cfg, ins, *ip);
3495 ins->cil_code = ip++;
3496 target = ip + 4 + (gint32)read32(ip);
3498 ADD_UNCOND(ins->opcode == CEE_BRTRUE);
3499 if (sp != stack_start) {
3500 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
3517 MONO_INST_NEW (cfg, ins, *ip);
3518 ins->cil_code = ip++;
3519 target = ip + 4 + (gint32)read32(ip);
3522 if (sp != stack_start) {
3523 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
3531 n = read32 (ip + 1);
3532 MONO_INST_NEW (cfg, ins, *ip);
3534 ins->inst_left = *sp;
3535 if (ins->inst_left->type != STACK_I4) goto unverified;
3538 CHECK_OPSIZE (n * sizeof (guint32));
3539 target = ip + n * sizeof (guint32);
3540 MONO_ADD_INS (bblock, ins);
3541 GET_BBLOCK (cfg, bbhash, tblock, target);
3542 link_bblock (cfg, bblock, tblock);
3543 ins->klass = GUINT_TO_POINTER (n);
3544 ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * (n + 1));
3545 ins->inst_many_bb [n] = tblock;
3547 for (i = 0; i < n; ++i) {
3548 GET_BBLOCK (cfg, bbhash, tblock, target + (gint32)read32(ip));
3549 link_bblock (cfg, bblock, tblock);
3550 ins->inst_many_bb [i] = tblock;
3553 if (sp != stack_start) {
3554 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
3571 MONO_INST_NEW (cfg, ins, *ip);
3576 ins->type = ldind_type [*ip - CEE_LDIND_I1];
3577 ins->flags |= ins_flag;
3589 MONO_INST_NEW (cfg, ins, *ip);
3590 ins->cil_code = ip++;
3592 handle_loaded_temps (cfg, bblock, stack_start, sp);
3593 MONO_ADD_INS (bblock, ins);
3594 ins->inst_i0 = sp [0];
3595 ins->inst_i1 = sp [1];
3596 ins->flags |= ins_flag;
3615 if (mono_find_jit_opcode_emulation (ins->opcode)) {
3616 MonoInst *store, *temp, *load;
3618 temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
3619 NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
3620 store->cil_code = ins->cil_code;
3621 MONO_ADD_INS (bblock, store);
3622 NEW_TEMPLOAD (cfg, load, temp->inst_c0);
3623 load->cil_code = ins->cil_code;
3625 /*g_print ("found emulation for %d\n", ins->opcode);*/
3639 case CEE_CONV_OVF_I8:
3640 case CEE_CONV_OVF_U8:
3644 if (mono_find_jit_opcode_emulation (ins->opcode)) {
3645 MonoInst *store, *temp, *load;
3647 temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
3648 NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
3649 store->cil_code = ins->cil_code;
3650 MONO_ADD_INS (bblock, store);
3651 NEW_TEMPLOAD (cfg, load, temp->inst_c0);
3652 load->cil_code = ins->cil_code;
3654 /*g_print ("found emulation for %d\n", ins->opcode);*/
3658 case CEE_CONV_OVF_I4:
3659 case CEE_CONV_OVF_I1:
3660 case CEE_CONV_OVF_I2:
3661 case CEE_CONV_OVF_I:
3662 case CEE_CONV_OVF_U:
3665 if (sp [-1]->type == STACK_R8) {
3666 ADD_UNOP (CEE_CONV_OVF_I8);
3674 case CEE_CONV_OVF_U1:
3675 case CEE_CONV_OVF_U2:
3676 case CEE_CONV_OVF_U4:
3679 if (sp [-1]->type == STACK_R8) {
3680 ADD_UNOP (CEE_CONV_OVF_U8);
3688 case CEE_CONV_OVF_I1_UN:
3689 case CEE_CONV_OVF_I2_UN:
3690 case CEE_CONV_OVF_I4_UN:
3691 case CEE_CONV_OVF_I8_UN:
3692 case CEE_CONV_OVF_U1_UN:
3693 case CEE_CONV_OVF_U2_UN:
3694 case CEE_CONV_OVF_U4_UN:
3695 case CEE_CONV_OVF_U8_UN:
3696 case CEE_CONV_OVF_I_UN:
3697 case CEE_CONV_OVF_U_UN:
3705 token = read32 (ip + 1);
3706 if (method->wrapper_type != MONO_WRAPPER_NONE)
3707 klass = mono_method_get_wrapper_data (method, token);
3709 klass = mono_class_get (image, token);
3711 mono_class_init (klass);
3712 if (klass->byval_arg.type == MONO_TYPE_VAR)
3713 klass = TYPE_PARAM_TO_CLASS (klass->byval_arg.data.generic_param->num);
3714 else if (klass->byval_arg.type == MONO_TYPE_MVAR)
3715 klass = MTYPE_PARAM_TO_CLASS (klass->byval_arg.data.generic_param->num);
3717 if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
3718 MonoInst *store, *load;
3719 MONO_INST_NEW (cfg, load, CEE_LDIND_REF);
3720 load->cil_code = ip;
3721 load->inst_i0 = sp [1];
3722 load->type = ldind_type [CEE_LDIND_REF];
3723 load->flags |= ins_flag;
3724 MONO_INST_NEW (cfg, store, CEE_STIND_REF);
3725 store->cil_code = ip;
3726 handle_loaded_temps (cfg, bblock, stack_start, sp);
3727 MONO_ADD_INS (bblock, store);
3728 store->inst_i0 = sp [0];
3729 store->inst_i1 = load;
3730 store->flags |= ins_flag;
3732 n = mono_class_value_size (klass, NULL);
3733 if ((cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 5) {
3735 MONO_INST_NEW (cfg, copy, OP_MEMCPY);
3736 copy->inst_left = sp [0];
3737 copy->inst_right = sp [1];
3738 copy->cil_code = ip;
3740 MONO_ADD_INS (bblock, copy);
3742 MonoInst *iargs [3];
3745 NEW_ICONST (cfg, iargs [2], n);
3746 iargs [2]->cil_code = ip;
3748 mono_emit_jit_icall (cfg, bblock, helper_memcpy, iargs, ip);
3755 MonoInst *iargs [3];
3759 token = read32 (ip + 1);
3760 if (method->wrapper_type != MONO_WRAPPER_NONE)
3761 klass = mono_method_get_wrapper_data (method, token);
3763 klass = mono_class_get (image, token);
3765 mono_class_init (klass);
3766 if (klass->byval_arg.type == MONO_TYPE_VAR)
3767 klass = TYPE_PARAM_TO_CLASS (klass->byval_arg.data.generic_param->num);
3768 else if (klass->byval_arg.type == MONO_TYPE_MVAR)
3769 klass = MTYPE_PARAM_TO_CLASS (klass->byval_arg.data.generic_param->num);
3770 if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
3771 MONO_INST_NEW (cfg, ins, CEE_LDIND_REF);
3773 ins->inst_i0 = sp [0];
3774 ins->type = ldind_type [CEE_LDIND_REF];
3775 ins->flags |= ins_flag;
3781 n = mono_class_value_size (klass, NULL);
3782 ins = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
3783 NEW_TEMPLOADA (cfg, iargs [0], ins->inst_c0);
3784 if ((cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 5) {
3786 MONO_INST_NEW (cfg, copy, OP_MEMCPY);
3787 copy->inst_left = iargs [0];
3788 copy->inst_right = *sp;
3789 copy->cil_code = ip;
3791 MONO_ADD_INS (bblock, copy);
3794 NEW_ICONST (cfg, iargs [2], n);
3795 iargs [2]->cil_code = ip;
3797 mono_emit_jit_icall (cfg, bblock, helper_memcpy, iargs, ip);
3799 NEW_TEMPLOAD (cfg, *sp, ins->inst_c0);
3807 CHECK_STACK_OVF (1);
3809 n = read32 (ip + 1);
3811 if (method->wrapper_type != MONO_WRAPPER_NONE) {
3813 MonoInst *iargs [1];
3815 NEW_PCONST (cfg, iargs [0], mono_method_get_wrapper_data (method, n));
3816 temp = mono_emit_jit_icall (cfg, bblock, mono_string_new_wrapper, iargs, ip);
3817 NEW_TEMPLOAD (cfg, *sp, temp);
3821 if (cfg->opt & MONO_OPT_SHARED) {
3823 MonoInst *iargs [3];
3825 if (mono_compile_aot) {
3826 cfg->ldstr_list = g_list_prepend (cfg->ldstr_list, (gpointer)n);
3829 NEW_TEMPLOAD (cfg, iargs [0], mono_get_domainvar (cfg)->inst_c0);
3830 NEW_IMAGECONST (cfg, iargs [1], image);
3831 NEW_ICONST (cfg, iargs [2], mono_metadata_token_index (n));
3832 temp = mono_emit_jit_icall (cfg, bblock, mono_ldstr, iargs, ip);
3833 NEW_TEMPLOAD (cfg, *sp, temp);
3834 mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
3836 if (mono_compile_aot)
3837 NEW_LDSTRCONST (cfg, ins, image, n);
3839 NEW_PCONST (cfg, ins, NULL);
3841 ins->type = STACK_OBJ;
3842 ins->inst_p0 = mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
3852 MonoInst *iargs [2];
3853 MonoMethodSignature *fsig;
3857 token = read32 (ip + 1);
3858 if (method->wrapper_type != MONO_WRAPPER_NONE) {
3859 cmethod = mono_method_get_wrapper_data (method, token);
3861 cmethod = mini_get_method (image, token, method);
3862 fsig = mono_method_get_signature (cmethod, image, token);
3864 mono_class_init (cmethod->klass);
3866 n = fsig->param_count;
3869 /* move the args to allow room for 'this' in the first position */
3875 handle_loaded_temps (cfg, bblock, stack_start, sp);
3878 if (cmethod->klass->parent == mono_defaults.array_class) {
3879 NEW_METHODCONST (cfg, *sp, cmethod);
3880 temp = mono_emit_native_call (cfg, bblock, mono_array_new_va, fsig, sp, ip, FALSE);
3882 } else if (cmethod->string_ctor) {
3883 /* we simply pass a null pointer */
3884 NEW_PCONST (cfg, *sp, NULL);
3885 /* now call the string ctor */
3886 temp = mono_emit_method_call_spilled (cfg, bblock, cmethod, fsig, sp, ip, NULL);
3888 if (cmethod->klass->valuetype) {
3889 iargs [0] = mono_compile_create_var (cfg, &cmethod->klass->byval_arg, OP_LOCAL);
3890 temp = iargs [0]->inst_c0;
3891 NEW_TEMPLOADA (cfg, *sp, temp);
3893 if (cfg->opt & MONO_OPT_SHARED) {
3894 NEW_DOMAINCONST (cfg, iargs [0]);
3895 NEW_CLASSCONST (cfg, iargs [1], cmethod->klass);
3897 temp = mono_emit_jit_icall (cfg, bblock, mono_object_new, iargs, ip);
3899 MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
3900 NEW_VTABLECONST (cfg, iargs [0], vtable);
3901 if (cmethod->klass->has_finalize || cmethod->klass->marshalbyref || (cfg->prof_options & MONO_PROFILE_ALLOCATIONS))
3902 temp = mono_emit_jit_icall (cfg, bblock, mono_object_new_specific, iargs, ip);
3904 temp = mono_emit_jit_icall (cfg, bblock, mono_object_new_fast, iargs, ip);
3906 NEW_TEMPLOAD (cfg, *sp, temp);
3909 if ((cfg->opt & MONO_OPT_INLINE) && cmethod &&
3910 mono_method_check_inlining (cfg, cmethod) &&
3911 !mono_class_is_subclass_of (cmethod->klass, mono_defaults.exception_class, FALSE) &&
3912 !g_list_find (dont_inline, cmethod)) {
3914 MonoBasicBlock *ebblock;
3915 if ((costs = inline_method (cfg, cmethod, fsig, bblock, sp, ip, real_offset, dont_inline, &ebblock))) {
3920 GET_BBLOCK (cfg, bbhash, bblock, ip);
3921 ebblock->next_bb = bblock;
3922 link_bblock (cfg, ebblock, bblock);
3924 NEW_TEMPLOAD (cfg, *sp, temp);
3927 /* indicates start of a new block, and triggers a load
3928 of all stack arguments at bb boundarie */
3931 inline_costs += costs;
3935 mono_emit_method_call_spilled (cfg, bblock, cmethod, fsig, sp, ip, sp[0]);
3938 /* now call the actual ctor */
3939 mono_emit_method_call_spilled (cfg, bblock, cmethod, fsig, sp, ip, sp[0]);
3943 NEW_TEMPLOAD (cfg, *sp, temp);
3954 klass = mono_class_get (image, read32 (ip + 1));
3955 mono_class_init (klass);
3957 if (klass->marshalbyref) {
3958 MonoInst *iargs [2];
3961 NEW_CLASSCONST (cfg, iargs [1], klass);
3962 temp = mono_emit_native_call (cfg, bblock, mono_object_isinst_mbyref, helper_sig_obj_obj_cls, iargs, ip, FALSE);
3963 NEW_TEMPLOAD (cfg, *sp, temp);
3967 MONO_INST_NEW (cfg, ins, *ip);
3968 ins->type = STACK_OBJ;
3969 ins->inst_left = *sp;
3970 ins->inst_newa_class = klass;
3976 case CEE_UNBOX_ANY: {
3977 MonoInst *add, *vtoffset;
3978 MonoInst *iargs [3];
3983 token = read32 (ip + 1);
3984 if (method->wrapper_type != MONO_WRAPPER_NONE)
3985 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
3987 klass = mono_class_get (image, token);
3988 mono_class_init (klass);
3990 if (klass->byval_arg.type == MONO_TYPE_VAR)
3991 klass = TYPE_PARAM_TO_CLASS (klass->byval_arg.data.generic_param->num);
3992 else if (klass->byval_arg.type == MONO_TYPE_MVAR)
3993 klass = MTYPE_PARAM_TO_CLASS (klass->byval_arg.data.generic_param->num);
3995 if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
3997 if (klass->marshalbyref) {
3998 MonoInst *iargs [2];
4001 NEW_CLASSCONST (cfg, iargs [1], klass);
4002 temp = mono_emit_jit_icall (cfg, bblock, mono_object_castclass_mbyref, iargs, ip);
4003 NEW_TEMPLOAD (cfg, *sp, temp);
4007 MONO_INST_NEW (cfg, ins, CEE_CASTCLASS);
4008 ins->type = STACK_OBJ;
4009 ins->inst_left = *sp;
4011 ins->inst_newa_class = klass;
4019 MONO_INST_NEW (cfg, ins, OP_UNBOXCAST);
4020 ins->type = STACK_OBJ;
4021 ins->inst_left = *sp;
4023 ins->inst_newa_class = klass;
4026 MONO_INST_NEW (cfg, add, CEE_ADD);
4027 NEW_ICONST (cfg, vtoffset, sizeof (MonoObject));
4028 add->inst_left = ins;
4029 add->inst_right = vtoffset;
4030 add->type = STACK_MP;
4034 n = mono_class_value_size (klass, NULL);
4035 ins = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
4036 NEW_TEMPLOADA (cfg, iargs [0], ins->inst_c0);
4037 if ((cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 5) {
4039 MONO_INST_NEW (cfg, copy, OP_MEMCPY);
4040 copy->inst_left = iargs [0];
4041 copy->inst_right = *sp;
4042 copy->cil_code = ip;
4044 MONO_ADD_INS (bblock, copy);
4047 NEW_ICONST (cfg, iargs [2], n);
4048 iargs [2]->cil_code = ip;
4050 mono_emit_jit_icall (cfg, bblock, helper_memcpy, iargs, ip);
4052 NEW_TEMPLOAD (cfg, *sp, ins->inst_c0);
4058 MonoInst *add, *vtoffset;
4063 token = read32 (ip + 1);
4064 if (method->wrapper_type != MONO_WRAPPER_NONE)
4065 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
4067 klass = mono_class_get (image, token);
4068 mono_class_init (klass);
4070 if (klass->byval_arg.type == MONO_TYPE_VAR)
4071 klass = TYPE_PARAM_TO_CLASS (klass->byval_arg.data.generic_param->num);
4072 else if (klass->byval_arg.type == MONO_TYPE_MVAR)
4073 klass = MTYPE_PARAM_TO_CLASS (klass->byval_arg.data.generic_param->num);
4075 MONO_INST_NEW (cfg, ins, OP_UNBOXCAST);
4076 ins->type = STACK_OBJ;
4077 ins->inst_left = *sp;
4079 ins->inst_newa_class = klass;
4082 MONO_INST_NEW (cfg, add, CEE_ADD);
4083 NEW_ICONST (cfg, vtoffset, sizeof (MonoObject));
4084 add->inst_left = ins;
4085 add->inst_right = vtoffset;
4086 add->type = STACK_MP;
4096 klass = mono_class_get (image, read32 (ip + 1));
4097 mono_class_init (klass);
4098 if (klass->byval_arg.type == MONO_TYPE_VAR)
4099 klass = TYPE_PARAM_TO_CLASS (klass->byval_arg.data.generic_param->num);
4100 else if (klass->byval_arg.type == MONO_TYPE_MVAR)
4101 klass = MTYPE_PARAM_TO_CLASS (klass->byval_arg.data.generic_param->num);
4103 if (klass->marshalbyref) {
4104 MonoInst *iargs [2];
4107 NEW_CLASSCONST (cfg, iargs [1], klass);
4108 temp = mono_emit_jit_icall (cfg, bblock, mono_object_castclass_mbyref, iargs, ip);
4109 NEW_TEMPLOAD (cfg, *sp, temp);
4113 MONO_INST_NEW (cfg, ins, *ip);
4114 ins->type = STACK_OBJ;
4115 ins->inst_left = *sp;
4117 ins->inst_newa_class = klass;
4125 MONO_INST_NEW (cfg, ins, *ip);
4127 ins->inst_left = *sp;
4128 ins->cil_code = ip++;
4129 MONO_ADD_INS (bblock, ins);
4131 start_new_bblock = 1;
4136 MonoInst *offset_ins;
4137 MonoClassField *field;
4138 MonoBasicBlock *ebblock;
4142 if (*ip == CEE_STFLD) {
4149 // FIXME: enable this test later.
4150 //if (sp [0]->type != STACK_OBJ && sp [0]->type != STACK_MP)
4153 token = read32 (ip + 1);
4154 field = mono_field_from_token (image, token, &klass);
4155 if (field->parent->gen_params)
4156 field = get_generic_field_inst (field, method->klass, &klass);
4157 else if (field->parent->generic_inst && method->klass->generic_inst)
4158 field = inflate_generic_field (field, method->klass, &klass);
4159 mono_class_init (klass);
4161 foffset = klass->valuetype? field->offset - sizeof (MonoObject): field->offset;
4162 /* FIXME: mark instructions for use in SSA */
4163 if (*ip == CEE_STFLD) {
4164 if (klass->marshalbyref && !MONO_CHECK_THIS (sp [0])) {
4165 MonoMethod *stfld_wrapper = mono_marshal_get_stfld_wrapper (field->type);
4166 MonoInst *iargs [5];
4169 NEW_CLASSCONST (cfg, iargs [1], klass);
4170 NEW_FIELDCONST (cfg, iargs [2], field);
4171 NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) :
4175 if (cfg->opt & MONO_OPT_INLINE) {
4176 costs = inline_method (cfg, stfld_wrapper, stfld_wrapper->signature, bblock,
4177 iargs, ip, real_offset, dont_inline, &ebblock);
4178 g_assert (costs > 0);
4183 GET_BBLOCK (cfg, bbhash, bblock, ip);
4184 ebblock->next_bb = bblock;
4185 link_bblock (cfg, ebblock, bblock);
4187 /* indicates start of a new block, and triggers a load
4188 of all stack arguments at bb boundarie */
4191 inline_costs += costs;
4194 mono_emit_method_call_spilled (cfg, bblock, stfld_wrapper, stfld_wrapper->signature, iargs, ip, NULL);
4198 NEW_ICONST (cfg, offset_ins, foffset);
4199 MONO_INST_NEW (cfg, ins, CEE_ADD);
4201 ins->inst_left = *sp;
4202 ins->inst_right = offset_ins;
4203 ins->type = STACK_MP;
4205 MONO_INST_NEW (cfg, store, mono_type_to_stind (field->type));
4206 store->cil_code = ip;
4207 store->inst_left = ins;
4208 store->inst_right = sp [1];
4209 handle_loaded_temps (cfg, bblock, stack_start, sp);
4210 store->flags |= ins_flag;
4212 if (store->opcode == CEE_STOBJ) {
4213 handle_stobj (cfg, bblock, ins, sp [1], ip,
4214 mono_class_from_mono_type (field->type), FALSE, FALSE);
4216 MONO_ADD_INS (bblock, store);
4219 if (klass->marshalbyref && !MONO_CHECK_THIS (sp [0])) {
4220 /* fixme: we need to inline that call somehow */
4221 MonoMethod *ldfld_wrapper = mono_marshal_get_ldfld_wrapper (field->type);
4222 MonoInst *iargs [4];
4226 NEW_CLASSCONST (cfg, iargs [1], klass);
4227 NEW_FIELDCONST (cfg, iargs [2], field);
4228 NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : field->offset);
4229 if (cfg->opt & MONO_OPT_INLINE) {
4230 costs = inline_method (cfg, ldfld_wrapper, ldfld_wrapper->signature, bblock,
4231 iargs, ip, real_offset, dont_inline, &ebblock);
4232 g_assert (costs > 0);
4237 GET_BBLOCK (cfg, bbhash, bblock, ip);
4238 ebblock->next_bb = bblock;
4239 link_bblock (cfg, ebblock, bblock);
4241 temp = iargs [0]->inst_i0->inst_c0;
4243 if (*ip == CEE_LDFLDA) {
4244 /* not sure howto handle this */
4245 NEW_TEMPLOADA (cfg, *sp, temp);
4247 NEW_TEMPLOAD (cfg, *sp, temp);
4251 /* indicates start of a new block, and triggers a load of
4252 all stack arguments at bb boundarie */
4255 inline_costs += costs;
4258 temp = mono_emit_method_call_spilled (cfg, bblock, ldfld_wrapper, ldfld_wrapper->signature, iargs, ip, NULL);
4259 if (*ip == CEE_LDFLDA) {
4260 /* not sure howto handle this */
4261 NEW_TEMPLOADA (cfg, *sp, temp);
4263 NEW_TEMPLOAD (cfg, *sp, temp);
4268 NEW_ICONST (cfg, offset_ins, foffset);
4269 MONO_INST_NEW (cfg, ins, CEE_ADD);
4271 ins->inst_left = *sp;
4272 ins->inst_right = offset_ins;
4273 ins->type = STACK_MP;
4275 if (*ip == CEE_LDFLDA) {
4279 MONO_INST_NEW (cfg, load, mono_type_to_ldind (field->type));
4280 type_to_eval_stack_type (field->type, load);
4281 load->cil_code = ip;
4282 load->inst_left = ins;
4283 load->flags |= ins_flag;
4295 MonoClassField *field;
4296 gpointer addr = NULL;
4299 token = read32 (ip + 1);
4301 field = mono_field_from_token (image, token, &klass);
4302 if (field->parent->gen_params)
4303 field = get_generic_field_inst (field, method->klass, &klass);
4304 else if (field->parent->generic_inst && method->klass->generic_inst)
4305 field = inflate_generic_field (field, method->klass, &klass);
4306 mono_class_init (klass);
4308 handle_loaded_temps (cfg, bblock, stack_start, sp);
4310 if (cfg->domain->special_static_fields)
4311 addr = g_hash_table_lookup (cfg->domain->special_static_fields, field);
4313 if ((cfg->opt & MONO_OPT_SHARED) || (mono_compile_aot && addr)) {
4315 MonoInst *iargs [2];
4316 g_assert (field->parent);
4317 NEW_TEMPLOAD (cfg, iargs [0], mono_get_domainvar (cfg)->inst_c0);
4318 NEW_FIELDCONST (cfg, iargs [1], field);
4319 temp = mono_emit_jit_icall (cfg, bblock, mono_class_static_field_address, iargs, ip);
4320 NEW_TEMPLOAD (cfg, ins, temp);
4323 vtable = mono_class_vtable (cfg->domain, klass);
4325 if ((!vtable->initialized || mono_compile_aot) && !(klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) && mono_class_needs_cctor_run (klass, method)) {
4326 guint8 *tramp = mono_create_class_init_trampoline (vtable);
4327 mono_emit_native_call (cfg, bblock, tramp,
4328 helper_sig_class_init_trampoline,
4330 if (cfg->verbose_level > 2)
4331 g_print ("class %s.%s needs init call for %s\n", klass->name_space, klass->name, field->name);
4333 if (cfg->run_cctors)
4334 mono_runtime_class_init (vtable);
4336 addr = (char*)vtable->data + field->offset;
4338 if (mono_compile_aot)
4339 NEW_SFLDACONST (cfg, ins, field);
4341 NEW_PCONST (cfg, ins, addr);
4345 * insert call to mono_threads_get_static_data (GPOINTER_TO_UINT (addr))
4346 * This could be later optimized to do just a couple of
4347 * memory dereferences with constant offsets.
4350 MonoInst *iargs [1];
4351 NEW_ICONST (cfg, iargs [0], GPOINTER_TO_UINT (addr));
4352 temp = mono_emit_jit_icall (cfg, bblock, mono_get_special_static_data, iargs, ip);
4353 NEW_TEMPLOAD (cfg, ins, temp);
4357 /* FIXME: mark instructions for use in SSA */
4358 if (*ip == CEE_LDSFLDA) {
4360 } else if (*ip == CEE_STSFLD) {
4364 MONO_INST_NEW (cfg, store, mono_type_to_stind (field->type));
4365 store->cil_code = ip;
4366 store->inst_left = ins;
4367 store->inst_right = sp [0];
4368 store->flags |= ins_flag;
4371 if (store->opcode == CEE_STOBJ) {
4372 handle_stobj (cfg, bblock, ins, sp [0], ip, mono_class_from_mono_type (field->type), FALSE, FALSE);
4374 MONO_ADD_INS (bblock, store);
4376 gboolean is_const = FALSE;
4377 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
4378 if (!((cfg->opt & MONO_OPT_SHARED) || mono_compile_aot) &&
4379 vtable->initialized && (field->type->attrs & FIELD_ATTRIBUTE_INIT_ONLY)) {
4380 gpointer addr = (char*)vtable->data + field->offset;
4381 /* g_print ("RO-FIELD %s.%s:%s\n", klass->name_space, klass->name, field->name);*/
4383 switch (field->type->type) {
4384 case MONO_TYPE_BOOLEAN:
4386 NEW_ICONST (cfg, *sp, *((guint8 *)addr));
4390 NEW_ICONST (cfg, *sp, *((gint8 *)addr));
4393 case MONO_TYPE_CHAR:
4395 NEW_ICONST (cfg, *sp, *((guint16 *)addr));
4399 NEW_ICONST (cfg, *sp, *((gint16 *)addr));
4404 NEW_ICONST (cfg, *sp, *((gint32 *)addr));
4408 NEW_ICONST (cfg, *sp, *((guint32 *)addr));
4413 case MONO_TYPE_STRING:
4414 case MONO_TYPE_OBJECT:
4415 case MONO_TYPE_CLASS:
4416 case MONO_TYPE_SZARRAY:
4418 case MONO_TYPE_FNPTR:
4419 case MONO_TYPE_ARRAY:
4420 NEW_PCONST (cfg, *sp, *((gpointer *)addr));
4421 type_to_eval_stack_type (field->type, *sp);
4426 MONO_INST_NEW (cfg, *sp, OP_I8CONST);
4427 sp [0]->type = STACK_I8;
4428 sp [0]->inst_l = *((gint64 *)addr);
4433 case MONO_TYPE_VALUETYPE:
4442 CHECK_STACK_OVF (1);
4443 MONO_INST_NEW (cfg, load, mono_type_to_ldind (field->type));
4444 type_to_eval_stack_type (field->type, load);
4445 load->cil_code = ip;
4446 load->inst_left = ins;
4448 load->flags |= ins_flag;
4450 /* fixme: dont see the problem why this does not work */
4451 //cfg->disable_aot = TRUE;
4461 token = read32 (ip + 1);
4462 if (method->wrapper_type != MONO_WRAPPER_NONE)
4463 klass = mono_method_get_wrapper_data (method, token);
4465 klass = mono_class_get (image, token);
4466 mono_class_init (klass);
4467 if (klass->byval_arg.type == MONO_TYPE_VAR)
4468 klass = TYPE_PARAM_TO_CLASS (klass->byval_arg.data.generic_param->num);
4469 else if (klass->byval_arg.type == MONO_TYPE_MVAR)
4470 klass = MTYPE_PARAM_TO_CLASS (klass->byval_arg.data.generic_param->num);
4471 n = mono_type_to_stind (&klass->byval_arg);
4472 if (n == CEE_STOBJ) {
4473 handle_stobj (cfg, bblock, sp [0], sp [1], ip, klass, FALSE, FALSE);
4475 /* FIXME: should check item at sp [1] is compatible with the type of the store. */
4477 MONO_INST_NEW (cfg, store, n);
4478 store->cil_code = ip;
4479 store->inst_left = sp [0];
4480 store->inst_right = sp [1];
4481 store->flags |= ins_flag;
4482 MONO_ADD_INS (bblock, store);
4489 MonoInst *iargs [2];
4490 MonoInst *load, *vtoffset, *add, *val, *vstore;
4496 token = read32 (ip + 1);
4497 if (method->wrapper_type != MONO_WRAPPER_NONE)
4498 klass = mono_method_get_wrapper_data (method, token);
4500 klass = mono_class_get (image, token);
4501 mono_class_init (klass);
4502 if (klass->byval_arg.type == MONO_TYPE_VAR)
4503 klass = TYPE_PARAM_TO_CLASS (klass->byval_arg.data.generic_param->num);
4504 else if (klass->byval_arg.type == MONO_TYPE_MVAR)
4505 klass = MTYPE_PARAM_TO_CLASS (klass->byval_arg.data.generic_param->num);
4507 if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
4512 /* much like NEWOBJ */
4513 if (cfg->opt & MONO_OPT_SHARED) {
4514 NEW_DOMAINCONST (cfg, iargs [0]);
4515 NEW_CLASSCONST (cfg, iargs [1], klass);
4517 temp = mono_emit_jit_icall (cfg, bblock, mono_object_new, iargs, ip);
4519 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
4520 NEW_VTABLECONST (cfg, iargs [0], vtable);
4521 if (1 || klass->has_finalize || (cfg->prof_options & MONO_PROFILE_ALLOCATIONS))
4522 temp = mono_emit_jit_icall (cfg, bblock, mono_object_new_specific, iargs, ip);
4524 temp = mono_emit_jit_icall (cfg, bblock, mono_object_new_fast, iargs, ip);
4526 NEW_TEMPLOAD (cfg, load, temp);
4527 NEW_ICONST (cfg, vtoffset, sizeof (MonoObject));
4528 MONO_INST_NEW (cfg, add, CEE_ADD);
4529 add->inst_left = load;
4530 add->inst_right = vtoffset;
4533 MONO_INST_NEW (cfg, vstore, CEE_STIND_I);
4534 vstore->opcode = mono_type_to_stind (&klass->byval_arg);
4535 vstore->cil_code = ip;
4536 vstore->inst_left = add;
4537 vstore->inst_right = val;
4539 if (vstore->opcode == CEE_STOBJ) {
4540 handle_stobj (cfg, bblock, add, val, ip, klass, FALSE, FALSE);
4542 MONO_ADD_INS (bblock, vstore);
4544 NEW_TEMPLOAD (cfg, load, temp);
4552 MONO_INST_NEW (cfg, ins, *ip);
4557 token = read32 (ip + 1);
4559 /* allocate the domainvar - becaus this is used in decompose_foreach */
4560 if (cfg->opt & MONO_OPT_SHARED)
4561 mono_get_domainvar (cfg);
4563 if (method->wrapper_type != MONO_WRAPPER_NONE)
4564 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
4566 klass = mono_class_get (image, token);
4568 mono_class_init (klass);
4569 if (klass->byval_arg.type == MONO_TYPE_VAR)
4570 klass = TYPE_PARAM_TO_CLASS (klass->byval_arg.data.generic_param->num);
4571 else if (klass->byval_arg.type == MONO_TYPE_MVAR)
4572 klass = MTYPE_PARAM_TO_CLASS (klass->byval_arg.data.generic_param->num);
4573 ins->inst_newa_class = klass;
4574 ins->inst_newa_len = *sp;
4575 ins->type = STACK_OBJ;
4579 * we store the object so calls to create the array are not interleaved
4580 * with the arguments of other calls.
4583 MonoInst *store, *temp, *load;
4585 temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
4586 NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
4587 store->cil_code = ins->cil_code;
4588 MONO_ADD_INS (bblock, store);
4589 NEW_TEMPLOAD (cfg, load, temp->inst_c0);
4590 load->cil_code = ins->cil_code;
4597 MONO_INST_NEW (cfg, ins, *ip);
4598 ins->cil_code = ip++;
4600 ins->inst_left = *sp;
4601 ins->type = STACK_PTR;
4609 if (method->wrapper_type != MONO_WRAPPER_NONE)
4610 klass = (MonoClass*)mono_method_get_wrapper_data (method, read32 (ip + 1));
4612 klass = mono_class_get (image, read32 (ip + 1));
4613 mono_class_init (klass);
4614 if (klass->byval_arg.type == MONO_TYPE_VAR)
4615 klass = TYPE_PARAM_TO_CLASS (klass->byval_arg.data.generic_param->num);
4616 else if (klass->byval_arg.type == MONO_TYPE_MVAR)
4617 klass = MTYPE_PARAM_TO_CLASS (klass->byval_arg.data.generic_param->num);
4618 NEW_LDELEMA (cfg, ins, sp, klass);
4628 token = read32 (ip + 1);
4629 klass = mono_class_get (image, token);
4630 mono_class_init (klass);
4631 if (klass->byval_arg.type == MONO_TYPE_VAR)
4632 klass = TYPE_PARAM_TO_CLASS (klass->byval_arg.data.generic_param->num);
4633 else if (klass->byval_arg.type == MONO_TYPE_MVAR)
4634 klass = MTYPE_PARAM_TO_CLASS (klass->byval_arg.data.generic_param->num);
4635 NEW_LDELEMA (cfg, load, sp, klass);
4636 load->cil_code = ip;
4637 MONO_INST_NEW (cfg, ins, mono_type_to_ldind (&klass->byval_arg));
4639 ins->inst_left = load;
4641 type_to_eval_stack_type (&klass->byval_arg, ins);
4655 case CEE_LDELEM_REF: {
4659 * ldind.x (ldelema (array, index))
4660 * ldelema does the bounds check
4664 klass = array_access_to_klass (*ip);
4665 NEW_LDELEMA (cfg, load, sp, klass);
4666 load->cil_code = ip;
4667 MONO_INST_NEW (cfg, ins, ldelem_to_ldind [*ip - CEE_LDELEM_I1]);
4669 ins->inst_left = load;
4671 ins->type = ldind_type [ins->opcode - CEE_LDIND_I1];
4681 case CEE_STELEM_R8: {
4685 * stind.x (ldelema (array, index), val)
4686 * ldelema does the bounds check
4690 klass = array_access_to_klass (*ip);
4691 NEW_LDELEMA (cfg, load, sp, klass);
4692 load->cil_code = ip;
4693 MONO_INST_NEW (cfg, ins, stelem_to_stind [*ip - CEE_STELEM_I]);
4695 ins->inst_left = load;
4696 ins->inst_right = sp [2];
4698 handle_loaded_temps (cfg, bblock, stack_start, sp);
4699 MONO_ADD_INS (bblock, ins);
4707 * stind.x (ldelema (array, index), val)
4708 * ldelema does the bounds check
4713 token = read32 (ip + 1);
4714 klass = mono_class_get (image, token);
4715 mono_class_init (klass);
4716 if (klass->byval_arg.type == MONO_TYPE_VAR)
4717 klass = TYPE_PARAM_TO_CLASS (klass->byval_arg.data.generic_param->num);
4718 else if (klass->byval_arg.type == MONO_TYPE_MVAR)
4719 klass = MTYPE_PARAM_TO_CLASS (klass->byval_arg.data.generic_param->num);
4720 if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
4721 MonoInst *iargs [3];
4722 handle_loaded_temps (cfg, bblock, stack_start, sp);
4728 mono_emit_jit_icall (cfg, bblock, helper_stelem_ref, iargs, ip);
4730 NEW_LDELEMA (cfg, load, sp, klass);
4731 load->cil_code = ip;
4732 MONO_INST_NEW (cfg, ins, mono_type_to_stind (&klass->byval_arg));
4734 ins->inst_left = load;
4735 ins->inst_right = sp [2];
4736 handle_loaded_temps (cfg, bblock, stack_start, sp);
4737 MONO_ADD_INS (bblock, ins);
4743 case CEE_STELEM_REF: {
4744 MonoInst *iargs [3];
4749 handle_loaded_temps (cfg, bblock, stack_start, sp);
4755 mono_emit_jit_icall (cfg, bblock, helper_stelem_ref, iargs, ip);
4759 NEW_GROUP (cfg, group, sp [0], sp [1]);
4760 MONO_INST_NEW (cfg, ins, CEE_STELEM_REF);
4762 ins->inst_left = group;
4763 ins->inst_right = sp [2];
4764 MONO_ADD_INS (bblock, ins);
4771 case CEE_CKFINITE: {
4772 MonoInst *store, *temp;
4775 /* this instr. can throw exceptions as side effect,
4776 * so we cant eliminate dead code which contains CKFINITE opdodes.
4777 * Spilling to memory makes sure that we always perform
4781 MONO_INST_NEW (cfg, ins, CEE_CKFINITE);
4783 ins->inst_left = sp [-1];
4784 temp = mono_compile_create_var (cfg, &mono_defaults.double_class->byval_arg, OP_LOCAL);
4786 NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
4787 store->cil_code = ip;
4788 MONO_ADD_INS (bblock, store);
4790 NEW_TEMPLOAD (cfg, sp [-1], temp->inst_c0);
4797 MONO_INST_NEW (cfg, ins, *ip);
4800 klass = mono_class_get (image, read32 (ip + 1));
4801 mono_class_init (klass);
4802 if (klass->byval_arg.type == MONO_TYPE_VAR)
4803 klass = TYPE_PARAM_TO_CLASS (klass->byval_arg.data.generic_param->num);
4804 else if (klass->byval_arg.type == MONO_TYPE_MVAR)
4805 klass = MTYPE_PARAM_TO_CLASS (klass->byval_arg.data.generic_param->num);
4806 ins->type = STACK_MP;
4807 ins->inst_left = *sp;
4809 ins->inst_newa_class = klass;
4814 case CEE_MKREFANY: {
4815 MonoInst *loc, *klassconst;
4818 MONO_INST_NEW (cfg, ins, *ip);
4821 klass = mono_class_get (image, read32 (ip + 1));
4822 mono_class_init (klass);
4823 if (klass->byval_arg.type == MONO_TYPE_VAR)
4824 klass = TYPE_PARAM_TO_CLASS (klass->byval_arg.data.generic_param->num);
4825 else if (klass->byval_arg.type == MONO_TYPE_MVAR)
4826 klass = MTYPE_PARAM_TO_CLASS (klass->byval_arg.data.generic_param->num);
4829 loc = mono_compile_create_var (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL);
4830 NEW_TEMPLOADA (cfg, ins->inst_right, loc->inst_c0);
4832 NEW_PCONST (cfg, klassconst, klass);
4833 NEW_GROUP (cfg, ins->inst_left, *sp, klassconst);
4835 MONO_ADD_INS (bblock, ins);
4837 NEW_TEMPLOAD (cfg, *sp, loc->inst_c0);
4844 MonoClass *handle_class;
4846 CHECK_STACK_OVF (1);
4849 n = read32 (ip + 1);
4851 handle = mono_ldtoken (image, n, &handle_class);
4852 mono_class_init (handle_class);
4854 if (cfg->opt & MONO_OPT_SHARED) {
4856 MonoInst *res, *store, *addr, *vtvar, *iargs [2];
4858 vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL);
4860 NEW_IMAGECONST (cfg, iargs [0], image);
4861 NEW_ICONST (cfg, iargs [1], n);
4862 temp = mono_emit_jit_icall (cfg, bblock, mono_ldtoken_wrapper, iargs, ip);
4863 NEW_TEMPLOAD (cfg, res, temp);
4864 NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
4865 NEW_INDSTORE (cfg, store, addr, res, &mono_defaults.int_class->byval_arg);
4866 MONO_ADD_INS (bblock, store);
4867 NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
4869 if ((ip [5] == CEE_CALL) && (cmethod = mini_get_method (image, read32 (ip + 6), method)) &&
4870 (cmethod->klass == mono_defaults.monotype_class->parent) &&
4871 (strcmp (cmethod->name, "GetTypeFromHandle") == 0)) {
4872 MonoClass *tclass = mono_class_from_mono_type (handle);
4873 mono_class_init (tclass);
4874 if (mono_compile_aot)
4875 NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, image, n);
4877 NEW_PCONST (cfg, ins, mono_type_get_object (cfg->domain, handle));
4878 ins->type = STACK_OBJ;
4879 ins->klass = cmethod->klass;
4882 if (mono_compile_aot)
4883 NEW_LDTOKENCONST (cfg, ins, image, n);
4885 NEW_PCONST (cfg, ins, handle);
4886 ins->type = STACK_VTYPE;
4887 ins->klass = handle_class;
4903 case CEE_ADD_OVF_UN:
4905 case CEE_MUL_OVF_UN:
4907 case CEE_SUB_OVF_UN:
4912 case CEE_ENDFINALLY:
4913 /* FIXME: check stack state */
4914 MONO_INST_NEW (cfg, ins, *ip);
4915 MONO_ADD_INS (bblock, ins);
4916 ins->cil_code = ip++;
4917 start_new_bblock = 1;
4922 if (*ip == CEE_LEAVE) {
4924 target = ip + 5 + (gint32)read32(ip + 1);
4927 target = ip + 2 + (signed char)(ip [1]);
4930 /* empty the stack */
4931 while (sp != stack_start) {
4932 MONO_INST_NEW (cfg, ins, CEE_POP);
4936 MONO_ADD_INS (bblock, ins);
4940 * If this leave statement is in a catch block, check for a
4941 * pending exception, and rethrow it if necessary.
4943 for (i = 0; i < header->num_clauses; ++i) {
4944 MonoExceptionClause *clause = &header->clauses [i];
4945 if (MONO_OFFSET_IN_HANDLER (clause, ip - header->code)) {
4948 temp = mono_emit_jit_icall (cfg, bblock, mono_thread_get_pending_exception, NULL, ip);
4949 NEW_TEMPLOAD (cfg, *sp, temp);
4951 MONO_INST_NEW (cfg, ins, OP_THROW_OR_NULL);
4952 ins->inst_left = *sp;
4954 MONO_ADD_INS (bblock, ins);
4958 /* fixme: call fault handler ? */
4960 if ((handlers = mono_find_final_block (cfg, ip, target, MONO_EXCEPTION_CLAUSE_FINALLY))) {
4962 for (tmp = handlers; tmp; tmp = tmp->next) {
4964 link_bblock (cfg, bblock, tblock);
4965 MONO_INST_NEW (cfg, ins, OP_CALL_HANDLER);
4967 ins->inst_target_bb = tblock;
4968 MONO_ADD_INS (bblock, ins);
4970 g_list_free (handlers);
4973 MONO_INST_NEW (cfg, ins, CEE_BR);
4975 MONO_ADD_INS (bblock, ins);
4976 GET_BBLOCK (cfg, bbhash, tblock, target);
4977 link_bblock (cfg, bblock, tblock);
4978 CHECK_BBLOCK (target, ip, tblock);
4979 ins->inst_target_bb = tblock;
4980 start_new_bblock = 1;
4982 if (*ip == CEE_LEAVE)
4991 MONO_INST_NEW (cfg, ins, *ip);
4993 handle_loaded_temps (cfg, bblock, stack_start, sp);
4994 MONO_ADD_INS (bblock, ins);
4995 ins->cil_code = ip++;
4996 ins->inst_i0 = sp [0];
4997 ins->inst_i1 = sp [1];
5005 /* trampoline mono specific opcodes */
5006 case MONO_CUSTOM_PREFIX: {
5008 g_assert (method->wrapper_type != MONO_WRAPPER_NONE);
5013 case CEE_MONO_FUNC1: {
5015 gpointer func = NULL;
5021 case MONO_MARSHAL_CONV_STR_LPWSTR:
5022 func = mono_string_to_utf16;
5024 case MONO_MARSHAL_CONV_LPWSTR_STR:
5025 func = mono_string_from_utf16;
5027 case MONO_MARSHAL_CONV_LPSTR_STR:
5028 func = mono_string_new_wrapper;
5030 case MONO_MARSHAL_CONV_STR_LPTSTR:
5031 case MONO_MARSHAL_CONV_STR_LPSTR:
5032 func = mono_string_to_utf8;
5034 case MONO_MARSHAL_CONV_STR_BSTR:
5035 func = mono_string_to_bstr;
5037 case MONO_MARSHAL_CONV_STR_TBSTR:
5038 case MONO_MARSHAL_CONV_STR_ANSIBSTR:
5039 func = mono_string_to_ansibstr;
5041 case MONO_MARSHAL_CONV_SB_LPSTR:
5042 case MONO_MARSHAL_CONV_SB_LPTSTR:
5043 func = mono_string_builder_to_utf8;
5045 case MONO_MARSHAL_CONV_SB_LPWSTR:
5046 func = mono_string_builder_to_utf16;
5048 case MONO_MARSHAL_CONV_ARRAY_SAVEARRAY:
5049 func = mono_array_to_savearray;
5051 case MONO_MARSHAL_CONV_ARRAY_LPARRAY:
5052 func = mono_array_to_lparray;
5054 case MONO_MARSHAL_CONV_DEL_FTN:
5055 func = mono_delegate_to_ftnptr;
5057 case MONO_MARSHAL_CONV_STRARRAY_STRLPARRAY:
5058 func = mono_marshal_string_array;
5061 g_warning ("unknown conversion %d\n", ip [2]);
5062 g_assert_not_reached ();
5065 temp = mono_emit_jit_icall (cfg, bblock, func, sp, ip);
5066 NEW_TEMPLOAD (cfg, *sp, temp);
5070 inline_costs += 10 * num_calls++;
5073 case CEE_MONO_PROC2: {
5074 gpointer func = NULL;
5080 case MONO_MARSHAL_CONV_LPSTR_SB:
5081 case MONO_MARSHAL_CONV_LPTSTR_SB:
5082 func = mono_string_utf8_to_builder;
5084 case MONO_MARSHAL_CONV_LPWSTR_SB:
5085 func = mono_string_utf16_to_builder;
5087 case MONO_MARSHAL_FREE_ARRAY:
5088 func = mono_marshal_free_array;
5091 g_assert_not_reached ();
5094 mono_emit_jit_icall (cfg, bblock, func, sp, ip);
5096 inline_costs += 10 * num_calls++;
5099 case CEE_MONO_PROC3: {
5100 gpointer func = NULL;
5106 case MONO_MARSHAL_CONV_STR_BYVALSTR:
5107 func = mono_string_to_byvalstr;
5109 case MONO_MARSHAL_CONV_STR_BYVALWSTR:
5110 func = mono_string_to_byvalwstr;
5113 g_assert_not_reached ();
5116 mono_emit_jit_icall (cfg, bblock, func, sp, ip);
5118 inline_costs += 10 * num_calls++;
5124 mono_emit_jit_icall (cfg, bblock, g_free, sp, ip);
5126 inline_costs += 10 * num_calls++;
5128 case CEE_MONO_LDPTR:
5129 CHECK_STACK_OVF (1);
5131 token = read32 (ip + 2);
5132 NEW_PCONST (cfg, ins, mono_method_get_wrapper_data (method, token));
5136 inline_costs += 10 * num_calls++;
5138 case CEE_MONO_VTADDR:
5141 MONO_INST_NEW (cfg, ins, OP_VTADDR);
5143 ins->type = STACK_MP;
5144 ins->inst_left = *sp;
5148 case CEE_MONO_NEWOBJ: {
5149 MonoInst *iargs [2];
5151 CHECK_STACK_OVF (1);
5153 token = read32 (ip + 2);
5154 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
5155 mono_class_init (klass);
5156 NEW_DOMAINCONST (cfg, iargs [0]);
5157 NEW_CLASSCONST (cfg, iargs [1], klass);
5158 temp = mono_emit_jit_icall (cfg, bblock, mono_object_new, iargs, ip);
5159 NEW_TEMPLOAD (cfg, *sp, temp);
5162 inline_costs += 10 * num_calls++;
5165 case CEE_MONO_OBJADDR:
5168 MONO_INST_NEW (cfg, ins, OP_OBJADDR);
5170 ins->type = STACK_MP;
5171 ins->inst_left = *sp;
5175 case CEE_MONO_LDNATIVEOBJ:
5178 token = read32 (ip + 2);
5179 klass = mono_method_get_wrapper_data (method, token);
5180 g_assert (klass->valuetype);
5181 mono_class_init (klass);
5182 NEW_INDLOAD (cfg, ins, sp [-1], &klass->byval_arg);
5186 case CEE_MONO_RETOBJ:
5187 g_assert (cfg->ret);
5188 g_assert (method->signature->pinvoke);
5193 token = read32 (ip + 2);
5194 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
5196 NEW_RETLOADA (cfg, ins);
5197 handle_stobj (cfg, bblock, ins, *sp, ip, klass, FALSE, TRUE);
5199 if (sp != stack_start)
5202 MONO_INST_NEW (cfg, ins, CEE_BR);
5204 ins->inst_target_bb = end_bblock;
5205 MONO_ADD_INS (bblock, ins);
5206 link_bblock (cfg, bblock, end_bblock);
5207 start_new_bblock = 1;
5211 g_error ("opcode 0x%02x 0x%02x not handled", MONO_CUSTOM_PREFIX, ip [1]);
5220 /* somewhat similar to LDTOKEN */
5221 MonoInst *addr, *vtvar;
5222 CHECK_STACK_OVF (1);
5223 vtvar = mono_compile_create_var (cfg, &mono_defaults.argumenthandle_class->byval_arg, OP_LOCAL);
5225 NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
5226 addr->cil_code = ip;
5227 MONO_INST_NEW (cfg, ins, OP_ARGLIST);
5229 ins->inst_left = addr;
5230 MONO_ADD_INS (bblock, ins);
5231 NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
5245 * The following transforms:
5246 * CEE_CEQ into OP_CEQ
5247 * CEE_CGT into OP_CGT
5248 * CEE_CGT_UN into OP_CGT_UN
5249 * CEE_CLT into OP_CLT
5250 * CEE_CLT_UN into OP_CLT_UN
5252 MONO_INST_NEW (cfg, cmp, 256 + ip [1]);
5254 MONO_INST_NEW (cfg, ins, cmp->opcode);
5256 cmp->inst_i0 = sp [0];
5257 cmp->inst_i1 = sp [1];
5261 cmp->opcode = OP_COMPARE;
5263 ins->type = STACK_I4;
5273 CHECK_STACK_OVF (1);
5275 n = read32 (ip + 2);
5276 if (method->wrapper_type != MONO_WRAPPER_NONE)
5277 cmethod = mono_method_get_wrapper_data (method, n);
5279 cmethod = mini_get_method (image, n, method);
5282 mono_class_init (cmethod->klass);
5283 handle_loaded_temps (cfg, bblock, stack_start, sp);
5285 NEW_METHODCONST (cfg, argconst, cmethod);
5286 if (method->wrapper_type != MONO_WRAPPER_SYNCHRONIZED)
5287 temp = mono_emit_jit_icall (cfg, bblock, mono_ldftn, &argconst, ip);
5289 temp = mono_emit_jit_icall (cfg, bblock, mono_ldftn_nosync, &argconst, ip);
5290 NEW_TEMPLOAD (cfg, *sp, temp);
5294 inline_costs += 10 * num_calls++;
5297 case CEE_LDVIRTFTN: {
5303 n = read32 (ip + 2);
5304 if (method->wrapper_type != MONO_WRAPPER_NONE)
5305 cmethod = mono_method_get_wrapper_data (method, n);
5307 cmethod = mini_get_method (image, n, method);
5309 mono_class_init (cmethod->klass);
5310 handle_loaded_temps (cfg, bblock, stack_start, sp);
5314 NEW_METHODCONST (cfg, args [1], cmethod);
5315 temp = mono_emit_jit_icall (cfg, bblock, mono_ldvirtfn, args, ip);
5316 NEW_TEMPLOAD (cfg, *sp, temp);
5320 inline_costs += 10 * num_calls++;
5324 CHECK_STACK_OVF (1);
5326 n = read16 (ip + 2);
5328 NEW_ARGLOAD (cfg, ins, n);
5334 CHECK_STACK_OVF (1);
5336 n = read16 (ip + 2);
5338 NEW_ARGLOADA (cfg, ins, n);
5346 handle_loaded_temps (cfg, bblock, stack_start, sp);
5348 n = read16 (ip + 2);
5350 NEW_ARGSTORE (cfg, ins, n, *sp);
5352 if (ins->opcode == CEE_STOBJ) {
5353 NEW_ARGLOADA (cfg, ins, n);
5354 handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE);
5356 MONO_ADD_INS (bblock, ins);
5360 CHECK_STACK_OVF (1);
5362 n = read16 (ip + 2);
5364 NEW_LOCLOAD (cfg, ins, n);
5370 CHECK_STACK_OVF (1);
5372 n = read16 (ip + 2);
5374 NEW_LOCLOADA (cfg, ins, n);
5383 n = read16 (ip + 2);
5385 handle_loaded_temps (cfg, bblock, stack_start, sp);
5386 NEW_LOCSTORE (cfg, ins, n, *sp);
5388 if (ins->opcode == CEE_STOBJ) {
5389 NEW_LOCLOADA (cfg, ins, n);
5390 handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE);
5392 MONO_ADD_INS (bblock, ins);
5399 if (sp != stack_start)
5401 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
5402 ins->inst_left = *sp;
5405 cfg->flags |= MONO_CFG_HAS_ALLOCA;
5406 if (header->init_locals)
5407 ins->flags |= MONO_INST_INIT;
5411 /* FIXME: set init flag if locals init is set in this method */
5413 case CEE_ENDFILTER: {
5414 MonoExceptionClause *clause, *nearest;
5415 int cc, nearest_num;
5419 if ((sp != stack_start) || (sp [0]->type != STACK_I4))
5421 MONO_INST_NEW (cfg, ins, OP_ENDFILTER);
5422 ins->inst_left = *sp;
5424 MONO_ADD_INS (bblock, ins);
5425 start_new_bblock = 1;
5430 for (cc = 0; cc < header->num_clauses; ++cc) {
5431 clause = &header->clauses [cc];
5432 if ((clause->flags & MONO_EXCEPTION_CLAUSE_FILTER) &&
5433 (!nearest || (clause->token_or_filter > nearest->token_or_filter))) {
5439 filter_lengths [nearest_num] = (ip - header->code) - nearest->token_or_filter;
5443 case CEE_UNALIGNED_:
5444 ins_flag |= MONO_INST_UNALIGNED;
5445 /* FIXME: record alignment? we can assume 1 for now */
5450 ins_flag |= MONO_INST_VOLATILE;
5454 ins_flag |= MONO_INST_TAILCALL;
5455 /* Can't inline tail calls at this time */
5456 inline_costs += 100000;
5463 token = read32 (ip + 2);
5464 if (method->wrapper_type != MONO_WRAPPER_NONE)
5465 klass = mono_method_get_wrapper_data (method, token);
5467 klass = mono_class_get (image, token);
5468 if (klass->byval_arg.type == MONO_TYPE_VAR)
5469 klass = TYPE_PARAM_TO_CLASS (klass->byval_arg.data.generic_param->num);
5470 else if (klass->byval_arg.type == MONO_TYPE_MVAR)
5471 klass = MTYPE_PARAM_TO_CLASS (klass->byval_arg.data.generic_param->num);
5473 if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
5474 MonoInst *store, *load;
5475 NEW_PCONST (cfg, load, NULL);
5476 load->cil_code = ip;
5477 load->type = STACK_OBJ;
5478 MONO_INST_NEW (cfg, store, CEE_STIND_REF);
5479 store->cil_code = ip;
5480 handle_loaded_temps (cfg, bblock, stack_start, sp);
5481 MONO_ADD_INS (bblock, store);
5482 store->inst_i0 = sp [0];
5483 store->inst_i1 = load;
5485 handle_initobj (cfg, bblock, *sp, NULL, klass, stack_start, sp);
5490 case CEE_CONSTRAINED_:
5491 /* FIXME: implement */
5493 token = read32 (ip + 2);
5498 MonoInst *iargs [3];
5504 handle_loaded_temps (cfg, bblock, stack_start, sp);
5505 if (ip [1] == CEE_CPBLK) {
5506 mono_emit_jit_icall (cfg, bblock, helper_memcpy, iargs, ip);
5508 mono_emit_jit_icall (cfg, bblock, helper_memset, iargs, ip);
5517 ins_flag |= MONO_INST_NOTYPECHECK;
5519 ins_flag |= MONO_INST_NORANGECHECK;
5520 /* we ignore the no-nullcheck for now since we
5521 * really do it explicitly only when doing callvirt->call
5527 /* FIXME: check we are in a catch handler */
5528 NEW_TEMPLOAD (cfg, load, cfg->exvar->inst_c0);
5529 load->cil_code = ip;
5530 MONO_INST_NEW (cfg, ins, CEE_THROW);
5531 ins->inst_left = load;
5533 MONO_ADD_INS (bblock, ins);
5535 start_new_bblock = 1;
5540 CHECK_STACK_OVF (1);
5542 token = read32 (ip + 2);
5543 /* FIXXME: handle generics. */
5544 if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC) {
5545 MonoType *type = mono_type_create_from_typespec (image, token);
5546 token = mono_type_size (type, &align);
5548 MonoClass *szclass = mono_class_get (image, token);
5549 mono_class_init (szclass);
5550 token = mono_class_value_size (szclass, &align);
5552 NEW_ICONST (cfg, ins, token);
5557 case CEE_REFANYTYPE:
5559 MONO_INST_NEW (cfg, ins, ip [1]);
5561 ins->type = STACK_MP;
5562 ins->inst_left = *sp;
5563 ins->type = STACK_VTYPE;
5564 ins->klass = mono_defaults.typehandle_class;
5573 g_error ("opcode 0xfe 0x%02x not handled", ip [1]);
5578 g_error ("opcode 0x%02x not handled", *ip);
5581 if (start_new_bblock != 1)
5584 bblock->cil_length = ip - bblock->cil_code;
5585 bblock->next_bb = end_bblock;
5586 link_bblock (cfg, bblock, end_bblock);
5588 if (cfg->method == method && cfg->domainvar) {
5592 MONO_INST_NEW_CALL (cfg, call, CEE_CALL);
5593 call->signature = helper_sig_domain_get;
5594 call->inst.type = STACK_PTR;
5595 call->fptr = mono_domain_get;
5596 NEW_TEMPSTORE (cfg, store, cfg->domainvar->inst_c0, (MonoInst*)call);
5598 MONO_ADD_INS (init_localsbb, store);
5601 if (header->init_locals) {
5603 for (i = 0; i < header->num_locals; ++i) {
5604 int t = header->locals [i]->type;
5605 if (t == MONO_TYPE_VALUETYPE && header->locals [i]->data.klass->enumtype)
5606 t = header->locals [i]->data.klass->enum_basetype->type;
5607 /* FIXME: use initobj for valuetypes, handle pointers, long, float. */
5608 if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
5609 NEW_ICONST (cfg, ins, 0);
5610 NEW_LOCSTORE (cfg, store, i, ins);
5611 MONO_ADD_INS (init_localsbb, store);
5612 } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
5613 MONO_INST_NEW (cfg, ins, OP_I8CONST);
5614 ins->type = STACK_I8;
5616 NEW_LOCSTORE (cfg, store, i, ins);
5617 MONO_ADD_INS (init_localsbb, store);
5618 } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
5619 MONO_INST_NEW (cfg, ins, OP_R8CONST);
5620 ins->type = STACK_R8;
5621 ins->inst_p0 = (void*)&r8_0;
5622 NEW_LOCSTORE (cfg, store, i, ins);
5623 MONO_ADD_INS (init_localsbb, store);
5624 } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF)) {
5625 NEW_LOCLOADA (cfg, ins, i);
5626 handle_initobj (cfg, init_localsbb, ins, NULL, mono_class_from_mono_type (header->locals [i]), NULL, NULL);
5629 NEW_PCONST (cfg, ins, NULL);
5630 NEW_LOCSTORE (cfg, store, i, ins);
5631 MONO_ADD_INS (init_localsbb, store);
5637 /* resolve backward branches in the middle of an existing basic block */
5638 for (tmp = bb_recheck; tmp; tmp = tmp->next) {
5640 /*g_print ("need recheck in %s at IL_%04x\n", method->name, bblock->cil_code - header->code);*/
5641 tblock = find_previous (bbhash, start_bblock, bblock->cil_code);
5642 if (tblock != start_bblock) {
5644 split_bblock (cfg, tblock, bblock);
5645 l = bblock->cil_code - header->code;
5646 bblock->cil_length = tblock->cil_length - l;
5647 tblock->cil_length = l;
5649 g_print ("recheck failed.\n");
5654 * we compute regions here, because the length of filter clauses is not known in advance.
5655 * It is computed in the CEE_ENDFILTER case in the above switch statement
5657 if (cfg->method == method) {
5659 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
5660 bb->region = mono_find_block_region (cfg, bb->real_offset, filter_lengths);
5662 mono_create_spvar_for_region (cfg, bb->region);
5663 if (cfg->verbose_level > 2)
5664 g_print ("REGION BB%d IL_%04x ID_%08X\n", bb->block_num, bb->real_offset, bb->region);
5667 g_hash_table_destroy (bbhash);
5670 dont_inline = g_list_remove (dont_inline, method);
5671 return inline_costs;
5674 if (cfg->method != method)
5675 g_hash_table_destroy (bbhash);
5676 dont_inline = g_list_remove (dont_inline, method);
5680 if (cfg->method != method)
5681 g_hash_table_destroy (bbhash);
5682 g_error ("Invalid IL code at IL%04x in %s: %s\n", ip - header->code,
5683 mono_method_full_name (method, TRUE), mono_disasm_code_one (NULL, method, ip, NULL));
5684 dont_inline = g_list_remove (dont_inline, method);
5689 mono_print_tree (MonoInst *tree) {
5695 arity = mono_burg_arity [tree->opcode];
5697 printf (" %s%s", arity?"(":"", mono_inst_name (tree->opcode));
5699 switch (tree->opcode) {
5701 printf ("[%d]", tree->inst_c0);
5704 printf ("[%lld]", tree->inst_l);
5707 printf ("[%f]", *(double*)tree->inst_p0);
5710 printf ("[%f]", *(float*)tree->inst_p0);
5714 printf ("[%d]", tree->inst_c0);
5717 printf ("[0x%x(%s)]", tree->inst_offset, mono_arch_regname (tree->inst_basereg));
5720 printf ("[%s]", mono_arch_regname (tree->dreg));
5723 printf ("[%s]", tree->inst_newa_class->name);
5724 mono_print_tree (tree->inst_newa_len);
5735 case OP_VOIDCALLVIRT: {
5736 MonoCallInst *call = (MonoCallInst*)tree;
5738 printf ("[%s]", call->method->name);
5743 printf ("[%d (", tree->inst_c0);
5744 for (i = 0; i < tree->inst_phi_args [0]; i++) {
5747 printf ("%d", tree->inst_phi_args [i + 1]);
5759 printf ("[B%d]", tree->inst_target_bb->block_num);
5769 case OP_VOIDCALL_REG:
5770 mono_print_tree (tree->inst_left);
5782 printf ("[B%dB%d]", tree->inst_true_bb->block_num, tree->inst_false_bb->block_num);
5783 mono_print_tree (tree->inst_left);
5787 mono_print_tree (tree->inst_left);
5789 mono_print_tree (tree->inst_right);
5799 mono_print_tree_nl (MonoInst *tree)
5801 mono_print_tree (tree);
5806 create_helper_signature (void)
5808 /* FIXME: set call conv */
5809 /* MonoArray * mono_array_new (MonoDomain *domain, MonoClass *klass, gint32 len) */
5810 helper_sig_newarr = mono_metadata_signature_alloc (mono_defaults.corlib, 3);
5811 helper_sig_newarr->params [0] = helper_sig_newarr->params [1] = &mono_defaults.int_class->byval_arg;
5812 helper_sig_newarr->ret = &mono_defaults.object_class->byval_arg;
5813 helper_sig_newarr->params [2] = &mono_defaults.int32_class->byval_arg;
5814 helper_sig_newarr->pinvoke = 1;
5816 /* MonoArray * mono_array_new_specific (MonoVTable *vtable, guint32 len) */
5817 helper_sig_newarr_specific = mono_metadata_signature_alloc (mono_defaults.corlib, 2);
5818 helper_sig_newarr_specific->params [0] = &mono_defaults.int_class->byval_arg;
5819 helper_sig_newarr_specific->params [1] = &mono_defaults.int32_class->byval_arg;
5820 helper_sig_newarr_specific->ret = &mono_defaults.object_class->byval_arg;
5821 helper_sig_newarr_specific->pinvoke = 1;
5823 /* MonoObject * mono_object_new (MonoDomain *domain, MonoClass *klass) */
5824 helper_sig_object_new = mono_metadata_signature_alloc (mono_defaults.corlib, 2);
5825 helper_sig_object_new->params [0] = helper_sig_object_new->params [1] = &mono_defaults.int_class->byval_arg;
5826 helper_sig_object_new->ret = &mono_defaults.object_class->byval_arg;
5827 helper_sig_object_new->pinvoke = 1;
5829 /* MonoObject * mono_object_new_specific (MonoVTable *vtable) */
5830 helper_sig_object_new_specific = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
5831 helper_sig_object_new_specific->params [0] = &mono_defaults.int_class->byval_arg;
5832 helper_sig_object_new_specific->ret = &mono_defaults.object_class->byval_arg;
5833 helper_sig_object_new_specific->pinvoke = 1;
5835 /* void* mono_method_compile (MonoMethod*) */
5836 helper_sig_compile = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
5837 helper_sig_compile->params [0] = helper_sig_compile->ret = &mono_defaults.int_class->byval_arg;
5838 helper_sig_compile->pinvoke = 1;
5840 /* void* mono_ldvirtfn (MonoObject *, MonoMethod*) */
5841 helper_sig_compile_virt = mono_metadata_signature_alloc (mono_defaults.corlib, 2);
5842 helper_sig_compile_virt->params [0] = &mono_defaults.object_class->byval_arg;
5843 helper_sig_compile_virt->params [1] = helper_sig_compile_virt->ret = &mono_defaults.int_class->byval_arg;
5844 helper_sig_compile_virt->pinvoke = 1;
5846 /* MonoString* mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 str_index) */
5847 helper_sig_ldstr = mono_metadata_signature_alloc (mono_defaults.corlib, 3);
5848 helper_sig_ldstr->params [0] = helper_sig_ldstr->params [1] = &mono_defaults.int_class->byval_arg;
5849 helper_sig_ldstr->params [2] = &mono_defaults.int32_class->byval_arg;
5850 helper_sig_ldstr->ret = &mono_defaults.object_class->byval_arg;
5851 helper_sig_ldstr->pinvoke = 1;
5853 /* MonoDomain *mono_domain_get (void) */
5854 helper_sig_domain_get = mono_metadata_signature_alloc (mono_defaults.corlib, 0);
5855 helper_sig_domain_get->ret = &mono_defaults.int_class->byval_arg;
5856 helper_sig_domain_get->pinvoke = 1;
5858 /* void* stelem_ref (MonoArray *, int index, MonoObject *) */
5859 helper_sig_stelem_ref = mono_metadata_signature_alloc (mono_defaults.corlib, 3);
5860 helper_sig_stelem_ref->params [0] = &mono_defaults.array_class->byval_arg;
5861 helper_sig_stelem_ref->params [1] = &mono_defaults.int32_class->byval_arg;
5862 helper_sig_stelem_ref->params [2] = &mono_defaults.object_class->byval_arg;
5863 helper_sig_stelem_ref->ret = &mono_defaults.void_class->byval_arg;
5864 helper_sig_stelem_ref->pinvoke = 1;
5866 /* void* stelem_ref_check (MonoArray *, MonoObject *) */
5867 helper_sig_stelem_ref_check = mono_metadata_signature_alloc (mono_defaults.corlib, 2);
5868 helper_sig_stelem_ref_check->params [0] = &mono_defaults.array_class->byval_arg;
5869 helper_sig_stelem_ref_check->params [1] = &mono_defaults.object_class->byval_arg;
5870 helper_sig_stelem_ref_check->ret = &mono_defaults.void_class->byval_arg;
5871 helper_sig_stelem_ref_check->pinvoke = 1;
5873 /* long amethod (long, long) */
5874 helper_sig_long_long_long = mono_metadata_signature_alloc (mono_defaults.corlib, 2);
5875 helper_sig_long_long_long->params [0] = helper_sig_long_long_long->params [1] =
5876 &mono_defaults.int64_class->byval_arg;
5877 helper_sig_long_long_long->ret = &mono_defaults.int64_class->byval_arg;
5878 helper_sig_long_long_long->pinvoke = 1;
5880 /* object amethod (intptr) */
5881 helper_sig_obj_ptr = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
5882 helper_sig_obj_ptr->params [0] = &mono_defaults.int_class->byval_arg;
5883 helper_sig_obj_ptr->ret = &mono_defaults.object_class->byval_arg;
5884 helper_sig_obj_ptr->pinvoke = 1;
5886 /* void amethod (intptr) */
5887 helper_sig_void_ptr = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
5888 helper_sig_void_ptr->params [0] = &mono_defaults.int_class->byval_arg;
5889 helper_sig_void_ptr->ret = &mono_defaults.void_class->byval_arg;
5890 helper_sig_void_ptr->pinvoke = 1;
5892 /* void amethod (MonoObject *obj) */
5893 helper_sig_void_obj = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
5894 helper_sig_void_obj->params [0] = &mono_defaults.object_class->byval_arg;
5895 helper_sig_void_obj->ret = &mono_defaults.void_class->byval_arg;
5896 helper_sig_void_obj->pinvoke = 1;
5898 /* intptr amethod (void) */
5899 helper_sig_ptr_void = mono_metadata_signature_alloc (mono_defaults.corlib, 0);
5900 helper_sig_ptr_void->ret = &mono_defaults.int_class->byval_arg;
5901 helper_sig_ptr_void->pinvoke = 1;
5903 /* object amethod (void) */
5904 helper_sig_obj_void = mono_metadata_signature_alloc (mono_defaults.corlib, 0);
5905 helper_sig_obj_void->ret = &mono_defaults.object_class->byval_arg;
5906 helper_sig_obj_void->pinvoke = 1;
5908 /* void amethod (intptr, intptr) */
5909 helper_sig_void_ptr_ptr = mono_metadata_signature_alloc (mono_defaults.corlib, 2);
5910 helper_sig_void_ptr_ptr->params [0] = &mono_defaults.int_class->byval_arg;
5911 helper_sig_void_ptr_ptr->params [1] = &mono_defaults.int_class->byval_arg;
5912 helper_sig_void_ptr_ptr->ret = &mono_defaults.void_class->byval_arg;
5913 helper_sig_void_ptr_ptr->pinvoke = 1;
5915 /* void amethod (intptr, intptr, intptr) */
5916 helper_sig_void_ptr_ptr_ptr = mono_metadata_signature_alloc (mono_defaults.corlib, 3);
5917 helper_sig_void_ptr_ptr_ptr->params [0] = &mono_defaults.int_class->byval_arg;
5918 helper_sig_void_ptr_ptr_ptr->params [1] = &mono_defaults.int_class->byval_arg;
5919 helper_sig_void_ptr_ptr_ptr->params [2] = &mono_defaults.int_class->byval_arg;
5920 helper_sig_void_ptr_ptr_ptr->ret = &mono_defaults.void_class->byval_arg;
5921 helper_sig_void_ptr_ptr_ptr->pinvoke = 1;
5923 /* intptr amethod (intptr, intptr) */
5924 helper_sig_ptr_ptr_ptr = mono_metadata_signature_alloc (mono_defaults.corlib, 2);
5925 helper_sig_ptr_ptr_ptr->params [0] = &mono_defaults.int_class->byval_arg;
5926 helper_sig_ptr_ptr_ptr->params [1] = &mono_defaults.int_class->byval_arg;
5927 helper_sig_ptr_ptr_ptr->ret = &mono_defaults.int_class->byval_arg;
5928 helper_sig_ptr_ptr_ptr->pinvoke = 1;
5930 /* IntPtr amethod (object) */
5931 helper_sig_ptr_obj = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
5932 helper_sig_ptr_obj->params [0] = &mono_defaults.object_class->byval_arg;
5933 helper_sig_ptr_obj->ret = &mono_defaults.int_class->byval_arg;
5934 helper_sig_ptr_obj->pinvoke = 1;
5936 /* IntPtr amethod (int) */
5937 helper_sig_ptr_int = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
5938 helper_sig_ptr_int->params [0] = &mono_defaults.int32_class->byval_arg;
5939 helper_sig_ptr_int->ret = &mono_defaults.int_class->byval_arg;
5940 helper_sig_ptr_int->pinvoke = 1;
5942 /* long amethod (long, guint32) */
5943 helper_sig_long_long_int = mono_metadata_signature_alloc (mono_defaults.corlib, 2);
5944 helper_sig_long_long_int->params [0] = &mono_defaults.int64_class->byval_arg;
5945 helper_sig_long_long_int->params [1] = &mono_defaults.int32_class->byval_arg;
5946 helper_sig_long_long_int->ret = &mono_defaults.int64_class->byval_arg;
5947 helper_sig_long_long_int->pinvoke = 1;
5949 /* ulong amethod (double) */
5950 helper_sig_ulong_double = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
5951 helper_sig_ulong_double->params [0] = &mono_defaults.double_class->byval_arg;
5952 helper_sig_ulong_double->ret = &mono_defaults.uint64_class->byval_arg;
5953 helper_sig_ulong_double->pinvoke = 1;
5955 /* long amethod (double) */
5956 helper_sig_long_double = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
5957 helper_sig_long_double->params [0] = &mono_defaults.double_class->byval_arg;
5958 helper_sig_long_double->ret = &mono_defaults.int64_class->byval_arg;
5959 helper_sig_long_double->pinvoke = 1;
5961 /* double amethod (long) */
5962 helper_sig_double_long = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
5963 helper_sig_double_long->params [0] = &mono_defaults.int64_class->byval_arg;
5964 helper_sig_double_long->ret = &mono_defaults.double_class->byval_arg;
5965 helper_sig_double_long->pinvoke = 1;
5967 /* float amethod (long) */
5968 helper_sig_float_long = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
5969 helper_sig_float_long->params [0] = &mono_defaults.int64_class->byval_arg;
5970 helper_sig_float_long->ret = &mono_defaults.single_class->byval_arg;
5971 helper_sig_float_long->pinvoke = 1;
5973 /* double amethod (double, double) */
5974 helper_sig_double_double_double = mono_metadata_signature_alloc (mono_defaults.corlib, 2);
5975 helper_sig_double_double_double->params [0] = &mono_defaults.double_class->byval_arg;
5976 helper_sig_double_double_double->params [1] = &mono_defaults.double_class->byval_arg;
5977 helper_sig_double_double_double->ret = &mono_defaults.double_class->byval_arg;
5978 helper_sig_double_double_double->pinvoke = 1;
5980 /* uint amethod (double) */
5981 helper_sig_uint_double = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
5982 helper_sig_uint_double->params [0] = &mono_defaults.double_class->byval_arg;
5983 helper_sig_uint_double->ret = &mono_defaults.uint32_class->byval_arg;
5984 helper_sig_uint_double->pinvoke = 1;
5986 /* int amethod (double) */
5987 helper_sig_int_double = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
5988 helper_sig_int_double->params [0] = &mono_defaults.double_class->byval_arg;
5989 helper_sig_int_double->ret = &mono_defaults.int32_class->byval_arg;
5990 helper_sig_int_double->pinvoke = 1;
5992 /* void initobj (intptr, int size) */
5993 helper_sig_initobj = mono_metadata_signature_alloc (mono_defaults.corlib, 2);
5994 helper_sig_initobj->params [0] = &mono_defaults.int_class->byval_arg;
5995 helper_sig_initobj->params [1] = &mono_defaults.int32_class->byval_arg;
5996 helper_sig_initobj->ret = &mono_defaults.void_class->byval_arg;
5997 helper_sig_initobj->pinvoke = 1;
5999 /* void memcpy (intptr, intptr, int size) */
6000 helper_sig_memcpy = mono_metadata_signature_alloc (mono_defaults.corlib, 3);
6001 helper_sig_memcpy->params [0] = &mono_defaults.int_class->byval_arg;
6002 helper_sig_memcpy->params [1] = &mono_defaults.int_class->byval_arg;
6003 helper_sig_memcpy->params [2] = &mono_defaults.int32_class->byval_arg;
6004 helper_sig_memcpy->ret = &mono_defaults.void_class->byval_arg;
6005 helper_sig_memcpy->pinvoke = 1;
6007 /* void memset (intptr, int val, int size) */
6008 helper_sig_memset = mono_metadata_signature_alloc (mono_defaults.corlib, 3);
6009 helper_sig_memset->params [0] = &mono_defaults.int_class->byval_arg;
6010 helper_sig_memset->params [1] = &mono_defaults.int32_class->byval_arg;
6011 helper_sig_memset->params [2] = &mono_defaults.int32_class->byval_arg;
6012 helper_sig_memset->ret = &mono_defaults.void_class->byval_arg;
6013 helper_sig_memset->pinvoke = 1;
6015 helper_sig_class_init_trampoline = mono_metadata_signature_alloc (mono_defaults.corlib, 0);
6016 helper_sig_class_init_trampoline->ret = &mono_defaults.void_class->byval_arg;
6017 helper_sig_class_init_trampoline->pinvoke = 1;
6019 /* MonoObject * amethod (MonoObject *obj, MonoClass *klass) */
6020 helper_sig_obj_obj_cls = mono_metadata_signature_alloc (mono_defaults.corlib, 2);
6021 helper_sig_obj_obj_cls->params [0] = &mono_defaults.object_class->byval_arg;
6022 helper_sig_obj_obj_cls->params [1] = &mono_defaults.int_class->byval_arg;
6023 helper_sig_obj_obj_cls->ret = &mono_defaults.object_class->byval_arg;
6024 helper_sig_obj_obj_cls->pinvoke = 1;
6027 static GHashTable *jit_icall_hash_name = NULL;
6028 static GHashTable *jit_icall_hash_addr = NULL;
6031 mono_find_jit_icall_by_name (const char *name)
6033 g_assert (jit_icall_hash_name);
6035 //printf ("lookup addr %s %p\n", name, g_hash_table_lookup (jit_icall_hash_name, name));
6036 return g_hash_table_lookup (jit_icall_hash_name, name);
6040 mono_find_jit_icall_by_addr (gconstpointer addr)
6042 g_assert (jit_icall_hash_addr);
6044 return g_hash_table_lookup (jit_icall_hash_addr, (gpointer)addr);
6048 mono_icall_get_wrapper (MonoJitICallInfo* callinfo)
6051 MonoMethod *wrapper;
6053 if (callinfo->wrapper)
6054 return callinfo->wrapper;
6055 name = g_strdup_printf ("__icall_wrapper_%s", callinfo->name);
6056 wrapper = mono_marshal_get_icall_wrapper (callinfo->sig, name, callinfo->func);
6057 /* Must be domain neutral since there is only one copy */
6058 callinfo->wrapper = mono_jit_compile_method_with_opt (wrapper, default_opt | MONO_OPT_SHARED);
6060 g_hash_table_insert (jit_icall_hash_addr, (gpointer)callinfo->wrapper, callinfo);
6063 return callinfo->wrapper;
6067 mono_register_jit_icall (gconstpointer func, const char *name, MonoMethodSignature *sig, gboolean is_save)
6069 MonoJitICallInfo *info;
6074 if (!jit_icall_hash_name) {
6075 jit_icall_hash_name = g_hash_table_new (g_str_hash, g_str_equal);
6076 jit_icall_hash_addr = g_hash_table_new (NULL, NULL);
6079 if (g_hash_table_lookup (jit_icall_hash_name, name)) {
6080 g_warning ("jit icall already defined \"%s\"\n", name);
6081 g_assert_not_reached ();
6084 info = g_new (MonoJitICallInfo, 1);
6091 #ifdef MONO_USE_EXC_TABLES
6092 || mono_arch_has_unwind_info (func)
6095 info->wrapper = func;
6097 info->wrapper = NULL;
6100 g_hash_table_insert (jit_icall_hash_name, (gpointer)info->name, info);
6101 g_hash_table_insert (jit_icall_hash_addr, (gpointer)func, info);
6107 mono_create_class_init_trampoline (MonoVTable *vtable)
6111 /* previously created trampoline code */
6112 mono_domain_lock (vtable->domain);
6114 mono_g_hash_table_lookup (vtable->domain->class_init_trampoline_hash,
6116 mono_domain_unlock (vtable->domain);
6120 code = mono_arch_create_class_init_trampoline (vtable);
6122 /* store trampoline address */
6123 mono_domain_lock (vtable->domain);
6124 mono_g_hash_table_insert (vtable->domain->class_init_trampoline_hash,
6126 mono_domain_unlock (vtable->domain);
6128 EnterCriticalSection (&trampoline_hash_mutex);
6129 if (!class_init_hash_addr)
6130 class_init_hash_addr = g_hash_table_new (NULL, NULL);
6131 g_hash_table_insert (class_init_hash_addr, code, vtable);
6132 LeaveCriticalSection (&trampoline_hash_mutex);
6138 mono_create_jump_trampoline (MonoDomain *domain, MonoMethod *method,
6139 gboolean add_sync_wrapper)
6144 if (add_sync_wrapper && method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
6145 return mono_create_jump_trampoline (domain, mono_marshal_get_synchronized_wrapper (method), FALSE);
6147 code = mono_jit_find_compiled_method (domain, method);
6151 EnterCriticalSection (&trampoline_hash_mutex);
6153 if (jump_trampoline_hash) {
6154 code = g_hash_table_lookup (jump_trampoline_hash, method);
6156 LeaveCriticalSection (&trampoline_hash_mutex);
6161 ji = mono_arch_create_jump_trampoline (method);
6164 * mono_delegate_ctor needs to find the method metadata from the
6165 * trampoline address, so we save it here.
6168 mono_jit_info_table_add (mono_root_domain, ji);
6170 if (!jump_trampoline_hash)
6171 jump_trampoline_hash = g_hash_table_new (NULL, NULL);
6172 g_hash_table_insert (jump_trampoline_hash, method, ji->code_start);
6174 LeaveCriticalSection (&trampoline_hash_mutex);
6176 return ji->code_start;
6180 mono_find_class_init_trampoline_by_addr (gconstpointer addr)
6184 EnterCriticalSection (&trampoline_hash_mutex);
6185 if (class_init_hash_addr)
6186 res = g_hash_table_lookup (class_init_hash_addr, addr);
6189 LeaveCriticalSection (&trampoline_hash_mutex);
6194 mono_register_opcode_emulation (int opcode, const char *name, MonoMethodSignature *sig, gpointer func, gboolean no_throw)
6196 MonoJitICallInfo *info;
6198 if (!emul_opcode_map)
6199 emul_opcode_map = g_new0 (MonoJitICallInfo*, OP_LAST + 1);
6201 g_assert (!sig->hasthis);
6202 g_assert (sig->param_count < 3);
6204 info = mono_register_jit_icall (func, name, sig, no_throw);
6206 emul_opcode_map [opcode] = info;
6210 decompose_foreach (MonoInst *tree, gpointer data)
6212 static MonoJitICallInfo *newarr_info = NULL;
6213 static MonoJitICallInfo *newarr_specific_info = NULL;
6214 MonoJitICallInfo *info;
6217 switch (tree->opcode) {
6219 MonoCompile *cfg = data;
6220 MonoInst *iargs [3];
6223 newarr_info = mono_find_jit_icall_by_addr (mono_array_new);
6224 g_assert (newarr_info);
6225 newarr_specific_info = mono_find_jit_icall_by_addr (mono_array_new_specific);
6226 g_assert (newarr_specific_info);
6229 if (cfg->opt & MONO_OPT_SHARED) {
6230 NEW_DOMAINCONST (cfg, iargs [0]);
6231 NEW_CLASSCONST (cfg, iargs [1], tree->inst_newa_class);
6232 iargs [2] = tree->inst_newa_len;
6237 MonoVTable *vtable = mono_class_vtable (cfg->domain, mono_array_class_get (tree->inst_newa_class, 1));
6239 NEW_VTABLECONST (cfg, iargs [0], vtable);
6240 iargs [1] = tree->inst_newa_len;
6242 info = newarr_specific_info;
6245 mono_emulate_opcode (cfg, tree, iargs, info);
6247 /* Need to decompose arguments after the the opcode is decomposed */
6248 for (i = 0; i < info->sig->param_count; ++i)
6249 dec_foreach (iargs [i], cfg);
6259 mono_inst_foreach (MonoInst *tree, MonoInstFunc func, gpointer data) {
6261 switch (mono_burg_arity [tree->opcode]) {
6264 mono_inst_foreach (tree->inst_left, func, data);
6267 mono_inst_foreach (tree->inst_left, func, data);
6268 mono_inst_foreach (tree->inst_right, func, data);
6271 g_assert_not_reached ();
6278 mono_print_bb_code (MonoBasicBlock *bb) {
6280 MonoInst *c = bb->code;
6282 mono_print_tree (c);
6290 print_dfn (MonoCompile *cfg) {
6295 g_print ("IR code for method %s\n", mono_method_full_name (cfg->method, TRUE));
6297 for (i = 0; i < cfg->num_bblocks; ++i) {
6298 bb = cfg->bblocks [i];
6300 char* code1, *code2;
6301 code1 = mono_disasm_code_one (NULL, cfg->method, bb->cil_code, NULL);
6302 if (bb->last_ins->cil_code)
6303 code2 = mono_disasm_code_one (NULL, cfg->method, bb->last_ins->cil_code, NULL);
6305 code2 = g_strdup ("");
6307 code1 [strlen (code1) - 1] = 0;
6308 code = g_strdup_printf ("%s -> %s", code1, code2);
6312 code = g_strdup ("\n");
6313 g_print ("\nBB%d DFN%d (len: %d): %s", bb->block_num, i, bb->cil_length, code);
6315 MonoInst *c = bb->code;
6317 mono_print_tree (c);
6325 g_print ("\tprev:");
6326 for (j = 0; j < bb->in_count; ++j) {
6327 g_print (" BB%d", bb->in_bb [j]->block_num);
6329 g_print ("\t\tsucc:");
6330 for (j = 0; j < bb->out_count; ++j) {
6331 g_print (" BB%d", bb->out_bb [j]->block_num);
6333 g_print ("\n\tidom: BB%d\n", bb->idom? bb->idom->block_num: -1);
6336 g_assert (mono_bitset_test_fast (bb->dominators, bb->idom->dfn));
6339 mono_blockset_print (cfg, bb->dominators, "\tdominators", bb->idom? bb->idom->dfn: -1);
6341 mono_blockset_print (cfg, bb->dfrontier, "\tdfrontier", -1);
6349 mono_bblock_add_inst (MonoBasicBlock *bb, MonoInst *inst)
6353 g_assert (bb->code);
6354 bb->last_ins->next = inst;
6355 bb->last_ins = inst;
6357 bb->last_ins = bb->code = inst;
6362 mono_destroy_compile (MonoCompile *cfg)
6364 //mono_mempool_stats (cfg->mempool);
6365 g_hash_table_destroy (cfg->bb_hash);
6367 mono_regstate_free (cfg->rs);
6369 g_hash_table_destroy (cfg->spvars);
6370 mono_mempool_destroy (cfg->mempool);
6371 g_list_free (cfg->ldstr_list);
6373 g_free (cfg->varinfo);
6379 mono_get_lmf_addr (void)
6381 MonoJitTlsData *jit_tls;
6383 if ((jit_tls = TlsGetValue (mono_jit_tls_id)))
6384 return &jit_tls->lmf;
6386 g_assert_not_reached ();
6391 * mono_thread_abort:
6392 * @obj: exception object
6394 * abort the thread, print exception information and stack trace
6397 mono_thread_abort (MonoObject *obj)
6399 /* MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id); */
6401 /* handle_remove should be eventually called for this thread, too
6408 setup_jit_tls_data (gpointer stack_start, gpointer abort_func)
6410 MonoJitTlsData *jit_tls;
6413 jit_tls = g_new0 (MonoJitTlsData, 1);
6415 TlsSetValue (mono_jit_tls_id, jit_tls);
6417 jit_tls->abort_func = abort_func;
6418 jit_tls->end_of_stack = stack_start;
6420 lmf = g_new0 (MonoLMF, 1);
6423 jit_tls->lmf = jit_tls->first_lmf = lmf;
6425 mono_arch_setup_jit_tls_data (jit_tls);
6431 mono_thread_start_cb (guint32 tid, gpointer stack_start, gpointer func)
6434 void *jit_tls = setup_jit_tls_data (stack_start, mono_thread_abort);
6435 thread = mono_thread_current ();
6437 thread->jit_data = jit_tls;
6440 void (*mono_thread_attach_aborted_cb ) (MonoObject *obj) = NULL;
6443 mono_thread_abort_dummy (MonoObject *obj)
6445 if (mono_thread_attach_aborted_cb)
6446 mono_thread_attach_aborted_cb (obj);
6448 mono_thread_abort (obj);
6452 mono_thread_attach_cb (guint32 tid, gpointer stack_start)
6455 void *jit_tls = setup_jit_tls_data (stack_start, mono_thread_abort_dummy);
6456 thread = mono_thread_current ();
6458 thread->jit_data = jit_tls;
6462 mini_thread_cleanup (MonoThread *thread)
6464 MonoJitTlsData *jit_tls = thread->jit_data;
6467 g_free (jit_tls->first_lmf);
6469 thread->jit_data = NULL;
6474 mono_add_patch_info (MonoCompile *cfg, int ip, MonoJumpInfoType type, gconstpointer target)
6476 MonoJumpInfo *ji = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfo));
6480 ji->data.target = target;
6481 ji->next = cfg->patch_info;
6483 cfg->patch_info = ji;
6487 mono_remove_patch_info (MonoCompile *cfg, int ip)
6489 MonoJumpInfo **ji = &cfg->patch_info;
6492 if ((*ji)->ip.i == ip)
6495 ji = &((*ji)->next);
6500 dec_foreach (MonoInst *tree, MonoCompile *cfg) {
6501 MonoJitICallInfo *info;
6503 decompose_foreach (tree, cfg);
6505 switch (mono_burg_arity [tree->opcode]) {
6508 dec_foreach (tree->inst_left, cfg);
6510 if ((info = mono_find_jit_opcode_emulation (tree->opcode))) {
6511 MonoInst *iargs [2];
6513 iargs [0] = tree->inst_left;
6515 mono_emulate_opcode (cfg, tree, iargs, info);
6521 #ifdef MONO_ARCH_BIGMUL_INTRINS
6522 if (tree->opcode == OP_LMUL
6523 && (cfg->opt & MONO_OPT_INTRINS)
6524 && (tree->inst_left->opcode == CEE_CONV_I8
6525 || tree->inst_left->opcode == CEE_CONV_U8)
6526 && tree->inst_left->inst_left->type == STACK_I4
6527 && (tree->inst_right->opcode == CEE_CONV_I8
6528 || tree->inst_right->opcode == CEE_CONV_U8)
6529 && tree->inst_right->inst_left->type == STACK_I4) {
6530 tree->opcode = (tree->inst_left->opcode == CEE_CONV_I8 ? OP_BIGMUL: OP_BIGMUL_UN);
6531 tree->inst_left = tree->inst_left->inst_left;
6532 tree->inst_right = tree->inst_right->inst_left;
6533 dec_foreach (tree, cfg);
6536 if ((info = mono_find_jit_opcode_emulation (tree->opcode))) {
6537 MonoInst *iargs [2];
6539 iargs [0] = tree->inst_i0;
6540 iargs [1] = tree->inst_i1;
6542 mono_emulate_opcode (cfg, tree, iargs, info);
6544 dec_foreach (iargs [0], cfg);
6545 dec_foreach (iargs [1], cfg);
6548 dec_foreach (tree->inst_left, cfg);
6549 dec_foreach (tree->inst_right, cfg);
6553 g_assert_not_reached ();
6558 decompose_pass (MonoCompile *cfg) {
6561 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
6564 cfg->prev_ins = NULL;
6565 for (tree = cfg->cbb->code; tree; tree = tree->next) {
6566 dec_foreach (tree, cfg);
6567 cfg->prev_ins = tree;
6573 nullify_basic_block (MonoBasicBlock *bb)
6580 bb->code = bb->last_ins = NULL;
6581 bb->cil_code = NULL;
6585 replace_out_block (MonoBasicBlock *bb, MonoBasicBlock *orig, MonoBasicBlock *repl)
6589 for (i = 0; i < bb->out_count; i++) {
6590 MonoBasicBlock *ob = bb->out_bb [i];
6593 if (bb->out_count > 1) {
6594 bb->out_bb [i] = bb->out_bb [bb->out_count - 1];
6598 bb->out_bb [i] = repl;
6605 replace_in_block (MonoBasicBlock *bb, MonoBasicBlock *orig, MonoBasicBlock *repl)
6609 for (i = 0; i < bb->in_count; i++) {
6610 MonoBasicBlock *ib = bb->in_bb [i];
6613 if (bb->in_count > 1) {
6614 bb->in_bb [i] = bb->in_bb [bb->in_count - 1];
6618 bb->in_bb [i] = repl;
6625 replace_basic_block (MonoBasicBlock *bb, MonoBasicBlock *orig, MonoBasicBlock *repl)
6629 for (i = 0; i < bb->out_count; i++) {
6630 MonoBasicBlock *ob = bb->out_bb [i];
6631 for (j = 0; j < ob->in_count; j++) {
6632 if (ob->in_bb [j] == orig) {
6633 ob->in_bb [j] = repl;
6642 merge_basic_blocks (MonoBasicBlock *bb, MonoBasicBlock *bbn)
6644 bb->out_count = bbn->out_count;
6645 bb->out_bb = bbn->out_bb;
6647 replace_basic_block (bb, bbn, bb);
6651 bb->last_ins->next = bbn->code;
6652 bb->last_ins = bbn->last_ins;
6655 bb->code = bbn->code;
6656 bb->last_ins = bbn->last_ins;
6658 bb->next_bb = bbn->next_bb;
6659 nullify_basic_block (bbn);
6663 * Optimizes the branches on the Control Flow Graph
6667 optimize_branches (MonoCompile *cfg)
6669 int i, changed = FALSE;
6670 MonoBasicBlock *bb, *bbn;
6671 guint32 niterations;
6674 * Some crazy loops could cause the code below to go into an infinite
6675 * loop, see bug #53003 for an example. To prevent this, we put an upper
6676 * bound on the number of iterations.
6683 /* we skip the entry block (exit is handled specially instead ) */
6684 for (bb = cfg->bb_entry->next_bb; bb; bb = bb->next_bb) {
6686 /* dont touch code inside exception clauses */
6687 if (bb->region != -1)
6690 if ((bbn = bb->next_bb) && bbn->in_count == 0 && bb->region == bbn->region) {
6691 if (cfg->verbose_level > 2)
6692 g_print ("nullify block triggered %d\n", bbn->block_num);
6694 bb->next_bb = bbn->next_bb;
6696 for (i = 0; i < bbn->out_count; i++)
6697 replace_in_block (bbn->out_bb [i], bbn, NULL);
6699 nullify_basic_block (bbn);
6703 if (bb->out_count == 1) {
6704 bbn = bb->out_bb [0];
6706 /* conditional branches where true and false targets are the same can be also replaced with CEE_BR */
6707 if (bb->last_ins && MONO_IS_COND_BRANCH (bb->last_ins->opcode)) {
6708 bb->last_ins->opcode = CEE_BR;
6709 bb->last_ins->inst_target_bb = bb->last_ins->inst_true_bb;
6711 if (cfg->verbose_level > 2)
6712 g_print ("cond branch removal triggered in %d %d\n", bb->block_num, bb->out_count);
6715 if (bb->region == bbn->region && bb->next_bb == bbn) {
6716 /* the block are in sequence anyway ... */
6718 /* branches to the following block can be removed */
6719 if (bb->last_ins && bb->last_ins->opcode == CEE_BR) {
6720 bb->last_ins->opcode = CEE_NOP;
6722 if (cfg->verbose_level > 2)
6723 g_print ("br removal triggered %d -> %d\n", bb->block_num, bbn->block_num);
6726 if (bbn->in_count == 1) {
6728 if (bbn != cfg->bb_exit) {
6729 if (cfg->verbose_level > 2)
6730 g_print ("block merge triggered %d -> %d\n", bb->block_num, bbn->block_num);
6731 merge_basic_blocks (bb, bbn);
6735 //mono_print_bb_code (bb);
6740 } while (changed && (niterations > 0));
6747 /* we skip the entry block (exit is handled specially instead ) */
6748 for (bb = cfg->bb_entry->next_bb; bb; bb = bb->next_bb) {
6750 /* dont touch code inside exception clauses */
6751 if (bb->region != -1)
6754 if ((bbn = bb->next_bb) && bbn->in_count == 0 && bb->region == bbn->region) {
6755 if (cfg->verbose_level > 2) {
6756 g_print ("nullify block triggered %d\n", bbn->block_num);
6758 bb->next_bb = bbn->next_bb;
6760 for (i = 0; i < bbn->out_count; i++)
6761 replace_in_block (bbn->out_bb [i], bbn, NULL);
6763 nullify_basic_block (bbn);
6769 if (bb->out_count == 1) {
6770 bbn = bb->out_bb [0];
6772 if (bb->last_ins && bb->last_ins->opcode == CEE_BR) {
6773 bbn = bb->last_ins->inst_target_bb;
6774 if (bb->region == bbn->region && bbn->code && bbn->code->opcode == CEE_BR &&
6775 bbn->code->inst_target_bb->region == bb->region) {
6777 if (cfg->verbose_level > 2)
6778 g_print ("in %s branch to branch triggered %d -> %d\n", cfg->method->name,
6779 bb->block_num, bbn->block_num);
6781 replace_basic_block (bb, bb->out_bb [0], bbn->code->inst_target_bb);
6782 bb->last_ins->inst_target_bb = bbn->code->inst_target_bb;
6787 } else if (bb->out_count == 2) {
6788 if (bb->last_ins && MONO_IS_COND_BRANCH (bb->last_ins->opcode)) {
6789 bbn = bb->last_ins->inst_true_bb;
6790 if (bb->region == bbn->region && bbn->code && bbn->code->opcode == CEE_BR &&
6791 bbn->code->inst_target_bb->region == bb->region) {
6792 if (cfg->verbose_level > 2)
6793 g_print ("cbranch1 to branch triggered %d -> (%d) %d (0x%02x)\n",
6794 bb->block_num, bbn->block_num, bbn->code->inst_target_bb->block_num,
6797 bb->last_ins->inst_true_bb = bbn->code->inst_target_bb;
6799 replace_in_block (bbn, bb, NULL);
6801 replace_in_block (bbn->code->inst_target_bb, bbn, bb);
6802 replace_out_block (bb, bbn, bbn->code->inst_target_bb);
6804 link_bblock (cfg, bb, bbn->code->inst_target_bb);
6810 bbn = bb->last_ins->inst_false_bb;
6811 if (bb->region == bbn->region && bbn->code && bbn->code->opcode == CEE_BR &&
6812 bbn->code->inst_target_bb->region == bb->region) {
6813 if (cfg->verbose_level > 2)
6814 g_print ("cbranch2 to branch triggered %d -> (%d) %d (0x%02x)\n",
6815 bb->block_num, bbn->block_num, bbn->code->inst_target_bb->block_num,
6818 bb->last_ins->inst_false_bb = bbn->code->inst_target_bb;
6820 replace_in_block (bbn, bb, NULL);
6822 replace_in_block (bbn->code->inst_target_bb, bbn, bb);
6823 replace_out_block (bb, bbn, bbn->code->inst_target_bb);
6825 link_bblock (cfg, bb, bbn->code->inst_target_bb);
6833 } while (changed && (niterations > 0));
6838 mono_compile_create_vars (MonoCompile *cfg)
6840 MonoMethodSignature *sig;
6841 MonoMethodHeader *header;
6844 header = ((MonoMethodNormal *)cfg->method)->header;
6846 sig = cfg->method->signature;
6848 if (!MONO_TYPE_IS_VOID (sig->ret)) {
6849 cfg->ret = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst));
6850 cfg->ret->opcode = OP_RETARG;
6851 cfg->ret->inst_vtype = sig->ret;
6852 cfg->ret->klass = mono_class_from_mono_type (sig->ret);
6854 if (cfg->verbose_level > 2)
6855 g_print ("creating vars\n");
6858 mono_compile_create_var (cfg, &cfg->method->klass->this_arg, OP_ARG);
6860 for (i = 0; i < sig->param_count; ++i)
6861 mono_compile_create_var (cfg, sig->params [i], OP_ARG);
6863 cfg->locals_start = cfg->num_varinfo;
6865 if (cfg->verbose_level > 2)
6866 g_print ("creating locals\n");
6867 for (i = 0; i < header->num_locals; ++i)
6868 mono_compile_create_var (cfg, header->locals [i], OP_LOCAL);
6869 if (cfg->verbose_level > 2)
6870 g_print ("locals done\n");
6874 mono_print_code (MonoCompile *cfg)
6878 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
6879 MonoInst *tree = bb->code;
6884 g_print ("CODE BLOCK %d (nesting %d):\n", bb->block_num, bb->nesting);
6886 for (; tree; tree = tree->next) {
6887 mono_print_tree (tree);
6892 bb->last_ins->next = NULL;
6896 extern const char * const mono_burg_rule_string [];
6899 emit_state (MonoCompile *cfg, MBState *state, int goal)
6902 int ern = mono_burg_rule (state, goal);
6903 const guint16 *nts = mono_burg_nts [ern];
6906 //g_print ("rule: %s\n", mono_burg_rule_string [ern]);
6910 // state->reg1 = state->reg2; /* chain rule */
6912 state->reg1 = mono_regstate_next_int (cfg->rs);
6913 //g_print ("alloc symbolic R%d (reg2: R%d) in block %d\n", state->reg1, state->reg2, cfg->cbb->block_num);
6916 state->reg1 = mono_regstate_next_int (cfg->rs);
6917 state->reg2 = mono_regstate_next_int (cfg->rs);
6920 state->reg1 = mono_regstate_next_float (cfg->rs);
6927 mono_burg_kids (state, ern, kids);
6929 emit_state (cfg, kids [0], nts [0]);
6931 emit_state (cfg, kids [1], nts [1]);
6933 g_assert (!nts [3]);
6934 emit_state (cfg, kids [2], nts [2]);
6939 // g_print ("emit: %s (%p)\n", mono_burg_rule_string [ern], state);
6940 if ((emit = mono_burg_func [ern]))
6941 emit (state, state->tree, cfg);
6944 #define DEBUG_SELECTION
6947 mini_select_instructions (MonoCompile *cfg)
6949 static int reverse_map [] = {
6950 CEE_BNE_UN, CEE_BLT, CEE_BLE, CEE_BGT, CEE_BGE,
6951 CEE_BEQ, CEE_BLT_UN, CEE_BLE_UN, CEE_BGT_UN, CEE_BGE_UN
6953 static int reverse_fmap [] = {
6954 OP_FBNE_UN, OP_FBLT, OP_FBLE, OP_FBGT, OP_FBGE,
6955 OP_FBEQ, OP_FBLT_UN, OP_FBLE_UN, OP_FBGT_UN, OP_FBGE_UN
6957 static int reverse_lmap [] = {
6958 OP_LBNE_UN, OP_LBLT, OP_LBLE, OP_LBGT, OP_LBGE,
6959 OP_LBEQ, OP_LBLT_UN, OP_LBLE_UN, OP_LBGT_UN, OP_LBGE_UN
6964 cfg->state_pool = mono_mempool_new ();
6965 cfg->rs = mono_regstate_new ();
6967 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
6968 if (bb->last_ins && MONO_IS_COND_BRANCH (bb->last_ins->opcode) &&
6969 bb->next_bb != bb->last_ins->inst_false_bb) {
6971 if (bb->next_bb == bb->last_ins->inst_true_bb) {
6972 MonoBasicBlock *tmp = bb->last_ins->inst_true_bb;
6973 bb->last_ins->inst_true_bb = bb->last_ins->inst_false_bb;
6974 bb->last_ins->inst_false_bb = tmp;
6976 if (bb->last_ins->opcode >= CEE_BEQ && bb->last_ins->opcode <= CEE_BLT_UN) {
6977 bb->last_ins->opcode = reverse_map [bb->last_ins->opcode - CEE_BEQ];
6978 } else if (bb->last_ins->opcode >= OP_FBEQ && bb->last_ins->opcode <= OP_FBLT_UN) {
6979 bb->last_ins->opcode = reverse_fmap [bb->last_ins->opcode - OP_FBEQ];
6980 } else if (bb->last_ins->opcode >= OP_LBEQ && bb->last_ins->opcode <= OP_LBLT_UN) {
6981 bb->last_ins->opcode = reverse_lmap [bb->last_ins->opcode - OP_LBEQ];
6984 MonoInst *inst = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst));
6985 inst->opcode = CEE_BR;
6986 inst->inst_target_bb = bb->last_ins->inst_false_bb;
6987 mono_bblock_add_inst (bb, inst);
6992 #ifdef DEBUG_SELECTION
6993 if (cfg->verbose_level >= 4) {
6994 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
6995 MonoInst *tree = bb->code;
6996 g_print ("DUMP BLOCK %d:\n", bb->block_num);
6999 for (; tree; tree = tree->next) {
7000 mono_print_tree (tree);
7007 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
7008 MonoInst *tree = bb->code, *next;
7014 bb->last_ins = NULL;
7017 mono_regstate_reset (cfg->rs);
7019 #ifdef DEBUG_SELECTION
7020 if (cfg->verbose_level >= 3)
7021 g_print ("LABEL BLOCK %d:\n", bb->block_num);
7023 for (; tree; tree = next) {
7025 #ifdef DEBUG_SELECTION
7026 if (cfg->verbose_level >= 3) {
7027 mono_print_tree (tree);
7032 if (!(mbstate = mono_burg_label (tree, cfg))) {
7033 g_warning ("unable to label tree %p", tree);
7034 mono_print_tree (tree);
7036 g_assert_not_reached ();
7038 emit_state (cfg, mbstate, MB_NTERM_stmt);
7040 bb->max_ireg = cfg->rs->next_vireg;
7041 bb->max_freg = cfg->rs->next_vfreg;
7044 bb->last_ins->next = NULL;
7046 mono_mempool_empty (cfg->state_pool);
7048 mono_mempool_destroy (cfg->state_pool);
7052 mono_codegen (MonoCompile *cfg)
7054 MonoJumpInfo *patch_info;
7056 int i, max_epilog_size;
7059 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
7060 cfg->spill_count = 0;
7061 /* we reuse dfn here */
7062 /* bb->dfn = bb_count++; */
7063 mono_arch_local_regalloc (cfg, bb);
7066 if (cfg->prof_options & MONO_PROFILE_COVERAGE)
7067 cfg->coverage_info = mono_profiler_coverage_alloc (cfg->method, cfg->num_bblocks);
7069 code = mono_arch_emit_prolog (cfg);
7071 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
7072 code = mono_arch_instrument_prolog (cfg, mono_profiler_method_enter, code, FALSE);
7074 cfg->code_len = code - cfg->native_code;
7075 cfg->prolog_end = cfg->code_len;
7077 mono_debug_open_method (cfg);
7079 /* emit code all basic blocks */
7080 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
7081 bb->native_offset = cfg->code_len;
7082 mono_arch_output_basic_block (cfg, bb);
7084 cfg->bb_exit->native_offset = cfg->code_len;
7086 code = cfg->native_code + cfg->code_len;
7088 max_epilog_size = mono_arch_max_epilog_size (cfg);
7090 /* we always allocate code in cfg->domain->code_mp to increase locality */
7091 cfg->code_size = cfg->code_len + max_epilog_size;
7092 /* fixme: align to MONO_ARCH_CODE_ALIGNMENT */
7093 code = mono_code_manager_reserve (cfg->domain->code_mp, cfg->code_size);
7094 memcpy (code, cfg->native_code, cfg->code_len);
7095 g_free (cfg->native_code);
7096 cfg->native_code = code;
7097 code = cfg->native_code + cfg->code_len;
7099 /* g_assert (((int)cfg->native_code & (MONO_ARCH_CODE_ALIGNMENT - 1)) == 0); */
7101 cfg->epilog_begin = cfg->code_len;
7103 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
7104 code = mono_arch_instrument_epilog (cfg, mono_profiler_method_leave, code, FALSE);
7106 cfg->code_len = code - cfg->native_code;
7108 mono_arch_emit_epilog (cfg);
7110 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
7111 switch (patch_info->type) {
7112 case MONO_PATCH_INFO_ABS: {
7113 MonoJitICallInfo *info = mono_find_jit_icall_by_addr (patch_info->data.target);
7115 //printf ("TEST %s %p\n", info->name, patch_info->data.target);
7116 if ((cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) &&
7117 strstr (cfg->method->name, info->name))
7119 * This is an icall wrapper, and this is a call to the
7124 patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
7125 patch_info->data.name = info->name;
7129 MonoVTable *vtable = mono_find_class_init_trampoline_by_addr (patch_info->data.target);
7131 patch_info->type = MONO_PATCH_INFO_CLASS_INIT;
7132 patch_info->data.klass = vtable->klass;
7137 case MONO_PATCH_INFO_SWITCH: {
7138 gpointer *table = mono_code_manager_reserve (cfg->domain->code_mp, sizeof (gpointer) * patch_info->table_size);
7139 patch_info->ip.i = patch_info->ip.label->inst_c0;
7140 for (i = 0; i < patch_info->table_size; i++) {
7141 table [i] = (gpointer)patch_info->data.table [i]->native_offset;
7143 patch_info->data.target = table;
7152 if (cfg->verbose_level > 0)
7153 g_print ("Method %s emitted at %p to %p [%s]\n",
7154 mono_method_full_name (cfg->method, TRUE),
7155 cfg->native_code, cfg->native_code + cfg->code_len, cfg->domain->friendly_name);
7157 mono_arch_patch_code (cfg->method, cfg->domain, cfg->native_code, cfg->patch_info, cfg->run_cctors);
7159 mono_code_manager_commit (cfg->domain->code_mp, cfg->native_code, cfg->code_size, cfg->code_len);
7160 mono_arch_flush_icache (cfg->native_code, cfg->code_len);
7162 mono_debug_close_method (cfg);
7166 mono_cprop_copy_values (MonoCompile *cfg, MonoInst *tree, MonoInst **acp)
7171 if (tree->ssa_op == MONO_SSA_LOAD && (tree->inst_i0->opcode == OP_LOCAL || tree->inst_i0->opcode == OP_ARG) &&
7172 (cp = acp [tree->inst_i0->inst_c0]) && !tree->inst_i0->flags) {
7174 if (cp->opcode == OP_ICONST) {
7175 if (cfg->opt & MONO_OPT_CONSPROP) {
7176 //{ static int c = 0; printf ("CCOPY %d %d %s\n", c++, cp->inst_c0, mono_method_full_name (cfg->method, TRUE)); }
7180 if (tree->inst_i0->inst_vtype->type == cp->inst_vtype->type) {
7181 if (cfg->opt & MONO_OPT_COPYPROP) {
7182 //{ static int c = 0; printf ("VCOPY %d\n", ++c); }
7188 arity = mono_burg_arity [tree->opcode];
7191 mono_cprop_copy_values (cfg, tree->inst_i0, acp);
7192 if (cfg->opt & MONO_OPT_CFOLD)
7193 mono_constant_fold_inst (tree, NULL);
7194 /* The opcode may have changed */
7195 if (mono_burg_arity [tree->opcode] > 1) {
7196 mono_cprop_copy_values (cfg, tree->inst_i1, acp);
7197 if (cfg->opt & MONO_OPT_CFOLD)
7198 mono_constant_fold_inst (tree, NULL);
7200 mono_constant_fold_inst (tree, NULL);
7206 mono_cprop_invalidate_values (MonoInst *tree, MonoInst **acp, int acp_size)
7210 switch (tree->opcode) {
7220 if (tree->ssa_op == MONO_SSA_NOP) {
7221 memset (acp, 0, sizeof (MonoInst *) * acp_size);
7238 case OP_VOIDCALL_REG:
7239 case OP_VOIDCALLVIRT:
7241 MonoCallInst *call = (MonoCallInst *)tree;
7242 MonoMethodSignature *sig = call->signature;
7243 int i, byref = FALSE;
7245 for (i = 0; i < sig->param_count; i++) {
7246 if (sig->params [i]->byref) {
7253 memset (acp, 0, sizeof (MonoInst *) * acp_size);
7261 arity = mono_burg_arity [tree->opcode];
7267 mono_cprop_invalidate_values (tree->inst_i0, acp, acp_size);
7270 mono_cprop_invalidate_values (tree->inst_i0, acp, acp_size);
7271 mono_cprop_invalidate_values (tree->inst_i1, acp, acp_size);
7274 g_assert_not_reached ();
7279 mono_local_cprop_bb (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst **acp, int acp_size)
7281 MonoInst *tree = bb->code;
7287 for (; tree; tree = tree->next) {
7289 mono_cprop_copy_values (cfg, tree, acp);
7291 mono_cprop_invalidate_values (tree, acp, acp_size);
7293 if (tree->ssa_op == MONO_SSA_STORE &&
7294 (tree->inst_i0->opcode == OP_LOCAL || tree->inst_i0->opcode == OP_ARG)) {
7295 MonoInst *i1 = tree->inst_i1;
7297 acp [tree->inst_i0->inst_c0] = NULL;
7299 for (i = 0; i < acp_size; i++) {
7300 if (acp [i] && acp [i]->opcode != OP_ICONST &&
7301 acp [i]->inst_c0 == tree->inst_i0->inst_c0) {
7306 if (i1->opcode == OP_ICONST) {
7307 acp [tree->inst_i0->inst_c0] = i1;
7308 //printf ("DEF1 BB%d %d\n", bb->block_num,tree->inst_i0->inst_c0);
7310 if (i1->ssa_op == MONO_SSA_LOAD &&
7311 (i1->inst_i0->opcode == OP_LOCAL || i1->inst_i0->opcode == OP_ARG) &&
7312 (i1->inst_i0->inst_c0 != tree->inst_i0->inst_c0)) {
7313 acp [tree->inst_i0->inst_c0] = i1->inst_i0;
7314 //printf ("DEF2 BB%d %d %d\n", bb->block_num,tree->inst_i0->inst_c0,i1->inst_i0->inst_c0);
7319 if (tree->opcode == CEE_BEQ) {
7320 g_assert (tree->inst_i0->opcode == OP_COMPARE);
7321 if (tree->inst_i0->inst_i0->opcode == OP_ICONST &&
7322 tree->inst_i0->inst_i1->opcode == OP_ICONST) {
7324 tree->opcode = CEE_BR;
7325 if (tree->inst_i0->inst_i0->opcode == tree->inst_i0->inst_i1->opcode) {
7326 tree->inst_target_bb = tree->inst_true_bb;
7328 tree->inst_target_bb = tree->inst_false_bb;
7337 mono_local_cprop (MonoCompile *cfg)
7342 acp = alloca (sizeof (MonoInst *) * cfg->num_varinfo);
7344 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
7345 memset (acp, 0, sizeof (MonoInst *) * cfg->num_varinfo);
7346 mono_local_cprop_bb (cfg, bb, acp, cfg->num_varinfo);
7351 mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gboolean run_cctors, int parts)
7353 MonoMethodHeader *header = ((MonoMethodNormal *)method)->header;
7354 guint8 *ip = (guint8 *)header->code;
7357 int dfn = 0, i, code_size_ratio;
7359 mono_jit_stats.methods_compiled++;
7360 if (mono_profiler_get_events () & MONO_PROFILE_JIT_COMPILATION)
7361 mono_profiler_method_jit (method);
7363 cfg = g_new0 (MonoCompile, 1);
7364 cfg->method = method;
7365 cfg->mempool = mono_mempool_new ();
7367 cfg->prof_options = mono_profiler_get_events ();
7368 cfg->run_cctors = run_cctors;
7369 cfg->bb_hash = g_hash_table_new (NULL, NULL);
7370 cfg->domain = domain;
7371 cfg->verbose_level = mini_verbose;
7372 cfg->intvars = mono_mempool_alloc0 (cfg->mempool, sizeof (guint16) * STACK_MAX *
7373 ((MonoMethodNormal *)method)->header->max_stack);
7375 if (cfg->verbose_level > 2)
7376 g_print ("converting method %s\n", mono_method_full_name (method, TRUE));
7379 * create MonoInst* which represents arguments and local variables
7381 mono_compile_create_vars (cfg);
7383 if ((i = mono_method_to_ir (cfg, method, NULL, NULL, cfg->locals_start, NULL, NULL, NULL, 0, FALSE)) < 0) {
7384 if (cfg->prof_options & MONO_PROFILE_JIT_COMPILATION)
7385 mono_profiler_method_end_jit (method, MONO_PROFILE_FAILED);
7386 mono_destroy_compile (cfg);
7390 mono_jit_stats.basic_blocks += cfg->num_bblocks;
7391 mono_jit_stats.max_basic_blocks = MAX (cfg->num_bblocks, mono_jit_stats.max_basic_blocks);
7393 if (cfg->num_varinfo > 2000) {
7395 * we disable some optimizations if there are too many variables
7396 * because JIT time may become too expensive. The actual number needs
7397 * to be tweaked and eventually the non-linear algorithms should be fixed.
7399 cfg->opt &= ~ (MONO_OPT_LINEARS | MONO_OPT_COPYPROP | MONO_OPT_CONSPROP);
7400 cfg->disable_ssa = TRUE;
7402 /*g_print ("numblocks = %d\n", cfg->num_bblocks);*/
7404 /* Depth-first ordering on basic blocks */
7405 cfg->bblocks = mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * (cfg->num_bblocks + 1));
7407 if (cfg->opt & MONO_OPT_BRANCH)
7408 optimize_branches (cfg);
7410 df_visit (cfg->bb_entry, &dfn, cfg->bblocks);
7411 if (cfg->num_bblocks != dfn + 1) {
7414 cfg->num_bblocks = dfn + 1;
7416 if (!header->clauses) {
7417 /* remove unreachable code, because the code in them may be
7418 * inconsistent (access to dead variables for example) */
7419 for (bb = cfg->bb_entry; bb;) {
7420 MonoBasicBlock *bbn = bb->next_bb;
7422 if (bbn && bbn->region == -1 && !bbn->dfn) {
7423 if (cfg->verbose_level > 1)
7424 g_print ("found unreachabel code in BB%d\n", bbn->block_num);
7425 bb->next_bb = bbn->next_bb;
7426 nullify_basic_block (bbn);
7434 if (cfg->opt & MONO_OPT_LOOP) {
7435 mono_compile_dominator_info (cfg, MONO_COMP_DOM | MONO_COMP_IDOM);
7436 mono_compute_natural_loops (cfg);
7439 /* after method_to_ir */
7443 //#define DEBUGSSA "logic_run"
7444 #define DEBUGSSA_CLASS "Tests"
7447 if (!header->num_clauses && !cfg->disable_ssa) {
7448 mono_local_cprop (cfg);
7449 mono_ssa_compute (cfg);
7453 /* fixme: add all optimizations which requires SSA */
7454 if (cfg->opt & (MONO_OPT_DEADCE)) {
7455 if (!(cfg->comp_done & MONO_COMP_SSA) && !header->num_clauses && !cfg->disable_ssa) {
7456 mono_local_cprop (cfg);
7457 mono_ssa_compute (cfg);
7459 if (cfg->verbose_level >= 2) {
7466 /* after SSA translation */
7470 if ((cfg->opt & MONO_OPT_CONSPROP) || (cfg->opt & MONO_OPT_COPYPROP)) {
7471 if (cfg->comp_done & MONO_COMP_SSA) {
7472 mono_ssa_cprop (cfg);
7474 mono_local_cprop (cfg);
7478 if (cfg->comp_done & MONO_COMP_SSA) {
7479 mono_ssa_deadce (cfg);
7481 //mono_ssa_strength_reduction (cfg);
7483 mono_ssa_remove (cfg);
7485 if (cfg->opt & MONO_OPT_BRANCH)
7486 optimize_branches (cfg);
7489 /* after SSA removal */
7493 decompose_pass (cfg);
7495 /* FIXME: disabled with exception clauses: bug #42136 */
7496 if ((!header->num_clauses) && (cfg->opt & MONO_OPT_LINEARS)) {
7499 /* fixme: maybe we can avoid to compute livenesss here if already computed ? */
7500 cfg->comp_done &= ~MONO_COMP_LIVENESS;
7501 if (!(cfg->comp_done & MONO_COMP_LIVENESS))
7502 mono_analyze_liveness (cfg);
7504 if ((vars = mono_arch_get_allocatable_int_vars (cfg))) {
7505 regs = mono_arch_get_global_int_regs (cfg);
7506 mono_linear_scan (cfg, vars, regs, &cfg->used_int_regs);
7510 //mono_print_code (cfg);
7514 /* variables are allocated after decompose, since decompose could create temps */
7515 mono_arch_allocate_vars (cfg);
7517 if (cfg->opt & MONO_OPT_CFOLD)
7518 mono_constant_fold (cfg);
7520 mini_select_instructions (cfg);
7523 if (cfg->verbose_level >= 2) {
7524 char *id = mono_method_full_name (cfg->method, FALSE);
7525 mono_disassemble_code (cfg->native_code, cfg->code_len, id + 3);
7529 jinfo = mono_mempool_alloc0 (cfg->domain->mp, sizeof (MonoJitInfo));
7531 jinfo = g_new0 (MonoJitInfo, 1);
7532 jinfo->method = method;
7533 jinfo->code_start = cfg->native_code;
7534 jinfo->code_size = cfg->code_len;
7535 jinfo->used_regs = cfg->used_int_regs;
7536 jinfo->domain_neutral = (cfg->opt & MONO_OPT_SHARED) != 0;
7538 if (header->num_clauses) {
7541 jinfo->exvar_offset = cfg->exvar? cfg->exvar->inst_offset: 0;
7542 jinfo->num_clauses = header->num_clauses;
7543 jinfo->clauses = mono_mempool_alloc0 (cfg->domain->mp,
7544 sizeof (MonoJitExceptionInfo) * header->num_clauses);
7546 for (i = 0; i < header->num_clauses; i++) {
7547 MonoExceptionClause *ec = &header->clauses [i];
7548 MonoJitExceptionInfo *ei = &jinfo->clauses [i];
7549 MonoBasicBlock *tblock;
7551 ei->flags = ec->flags;
7553 if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
7554 tblock = g_hash_table_lookup (cfg->bb_hash, ip + ec->token_or_filter);
7556 ei->data.filter = cfg->native_code + tblock->native_offset;
7558 ei->data.token = ec->token_or_filter;
7561 tblock = g_hash_table_lookup (cfg->bb_hash, ip + ec->try_offset);
7563 ei->try_start = cfg->native_code + tblock->native_offset;
7564 g_assert (tblock->native_offset);
7565 tblock = g_hash_table_lookup (cfg->bb_hash, ip + ec->try_offset + ec->try_len);
7567 ei->try_end = cfg->native_code + tblock->native_offset;
7568 g_assert (tblock->native_offset);
7569 tblock = g_hash_table_lookup (cfg->bb_hash, ip + ec->handler_offset);
7571 ei->handler_start = cfg->native_code + tblock->native_offset;
7575 cfg->jit_info = jinfo;
7577 mono_jit_info_table_add (cfg->domain, jinfo);
7579 /* collect statistics */
7580 mono_jit_stats.allocated_code_size += cfg->code_len;
7581 code_size_ratio = cfg->code_len;
7582 if (code_size_ratio > mono_jit_stats.biggest_method_size) {
7583 mono_jit_stats.biggest_method_size = code_size_ratio;
7584 mono_jit_stats.biggest_method = method;
7586 code_size_ratio = (code_size_ratio * 100) / ((MonoMethodNormal *)method)->header->code_size;
7587 if (code_size_ratio > mono_jit_stats.max_code_size_ratio) {
7588 mono_jit_stats.max_code_size_ratio = code_size_ratio;
7589 mono_jit_stats.max_ratio_method = method;
7591 mono_jit_stats.native_code_size += cfg->code_len;
7593 if (cfg->prof_options & MONO_PROFILE_JIT_COMPILATION)
7594 mono_profiler_method_end_jit (method, MONO_PROFILE_OK);
7600 mono_jit_compile_method_inner (MonoMethod *method)
7602 /* FIXME: later copy the code from mono */
7603 MonoDomain *target_domain, *domain = mono_domain_get ();
7605 GHashTable *jit_code_hash;
7611 if (opt & MONO_OPT_SHARED)
7612 target_domain = mono_root_domain;
7614 target_domain = domain;
7616 jit_code_hash = target_domain->jit_code_hash;
7618 #ifdef MONO_USE_AOT_COMPILER
7619 if (!mono_compile_aot && (opt & MONO_OPT_AOT)) {
7622 mono_domain_lock (domain);
7624 mono_class_init (method->klass);
7625 if ((info = mono_aot_get_method (domain, method))) {
7627 g_hash_table_insert (domain->jit_code_hash, method, info);
7629 mono_domain_unlock (domain);
7631 /* make sure runtime_init is called */
7632 mono_runtime_class_init (mono_class_vtable (domain, method->klass));
7634 return info->code_start;
7637 mono_domain_unlock (domain);
7641 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
7642 (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
7645 if (!method->addr) {
7646 if (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL)
7647 method->addr = mono_lookup_internal_call (method);
7649 if (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
7650 mono_lookup_pinvoke_call (method, NULL, NULL);
7652 #ifdef MONO_USE_EXC_TABLES
7653 if (mono_method_blittable (method)) {
7654 return method->addr;
7657 nm = mono_marshal_get_native_wrapper (method);
7658 return mono_compile_method (nm);
7660 //if (mono_debug_format != MONO_DEBUG_FORMAT_NONE)
7661 //mono_debug_add_wrapper (method, nm);
7662 #ifdef MONO_USE_EXC_TABLES
7665 } else if ((method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME)) {
7666 const char *name = method->name;
7669 if (method->klass->parent == mono_defaults.multicastdelegate_class) {
7670 if (*name == '.' && (strcmp (name, ".ctor") == 0)) {
7671 /* FIXME: uhm, we need a wrapper to handle exceptions? */
7672 return (gpointer)mono_delegate_ctor;
7673 } else if (*name == 'I' && (strcmp (name, "Invoke") == 0)) {
7674 nm = mono_marshal_get_delegate_invoke (method);
7675 return mono_jit_compile_method (nm);
7676 } else if (*name == 'B' && (strcmp (name, "BeginInvoke") == 0)) {
7677 nm = mono_marshal_get_delegate_begin_invoke (method);
7678 return mono_jit_compile_method (nm);
7679 } else if (*name == 'E' && (strcmp (name, "EndInvoke") == 0)) {
7680 nm = mono_marshal_get_delegate_end_invoke (method);
7681 return mono_jit_compile_method (nm);
7687 cfg = mini_method_compile (method, opt, target_domain, TRUE, 0);
7688 code = cfg->native_code;
7690 g_hash_table_insert (jit_code_hash, method, cfg->jit_info);
7692 mono_destroy_compile (cfg);
7694 if (target_domain->jump_target_hash) {
7695 MonoJumpInfo patch_info;
7697 list = g_hash_table_lookup (target_domain->jump_target_hash, method);
7699 patch_info.next = NULL;
7700 patch_info.ip.i = 0;
7701 patch_info.type = MONO_PATCH_INFO_METHOD_JUMP;
7702 patch_info.data.method = method;
7703 g_hash_table_remove (target_domain->jump_target_hash, method);
7705 for (tmp = list; tmp; tmp = tmp->next)
7706 mono_arch_patch_code (NULL, target_domain, tmp->data, &patch_info, TRUE);
7707 g_slist_free (list);
7709 /* make sure runtime_init is called */
7710 mono_runtime_class_init (mono_class_vtable (target_domain, method->klass));
7716 mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt)
7718 /* FIXME: later copy the code from mono */
7719 MonoDomain *target_domain, *domain = mono_domain_get ();
7723 if (default_opt & MONO_OPT_SHARED)
7724 target_domain = mono_root_domain;
7726 target_domain = domain;
7728 mono_domain_lock (target_domain);
7730 if ((info = g_hash_table_lookup (target_domain->jit_code_hash, method))) {
7731 /* We can't use a domain specific method in another domain */
7732 if (! ((domain != target_domain) && !info->domain_neutral)) {
7733 mono_domain_unlock (target_domain);
7734 mono_jit_stats.methods_lookups++;
7735 return info->code_start;
7739 code = mono_jit_compile_method_inner (method);
7741 mono_domain_unlock (target_domain);
7747 mono_jit_compile_method (MonoMethod *method)
7749 return mono_jit_compile_method_with_opt (method, default_opt);
7753 mono_jit_find_compiled_method (MonoDomain *domain, MonoMethod *method)
7755 MonoDomain *target_domain;
7758 if (default_opt & MONO_OPT_SHARED)
7759 target_domain = mono_root_domain;
7761 target_domain = domain;
7763 mono_domain_lock (target_domain);
7765 if ((info = g_hash_table_lookup (target_domain->jit_code_hash, method))) {
7766 /* We can't use a domain specific method in another domain */
7767 if (! ((domain != target_domain) && !info->domain_neutral)) {
7768 mono_domain_unlock (target_domain);
7769 mono_jit_stats.methods_lookups++;
7770 return info->code_start;
7774 mono_domain_unlock (target_domain);
7780 * mono_jit_runtime_invoke:
7781 * @method: the method to invoke
7782 * @obj: this pointer
7783 * @params: array of parameter values.
7784 * @exc: used to catch exceptions objects
7787 mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
7790 MonoObject *(*runtime_invoke) (MonoObject *this, void **params, MonoObject **exc);
7792 if (obj == NULL && !(method->flags & METHOD_ATTRIBUTE_STATIC) && !method->string_ctor && (method->wrapper_type == 0)) {
7793 g_warning ("Ignoring invocation of an instance method on a NULL instance.\n");
7797 invoke = mono_marshal_get_runtime_invoke (method);
7798 runtime_invoke = mono_jit_compile_method (invoke);
7799 return runtime_invoke (obj, params, exc);
7802 #ifdef PLATFORM_WIN32
7803 #define GET_CONTEXT \
7804 struct sigcontext *ctx = (struct sigcontext*)_dummy;
7806 #define GET_CONTEXT \
7807 void **_p = (void **)&_dummy; \
7808 struct sigcontext *ctx = (struct sigcontext *)++_p;
7812 sigfpe_signal_handler (int _dummy)
7817 exc = mono_get_exception_divide_by_zero ();
7819 mono_arch_handle_exception (ctx, exc, FALSE);
7823 sigill_signal_handler (int _dummy)
7827 exc = mono_get_exception_execution_engine ("SIGILL");
7829 mono_arch_handle_exception (ctx, exc, FALSE);
7833 sigsegv_signal_handler (int _dummy)
7838 exc = mono_get_exception_null_reference ();
7840 mono_arch_handle_exception (ctx, exc, FALSE);
7844 sigusr1_signal_handler (int _dummy)
7849 thread = mono_thread_current ();
7851 thread->abort_exc = mono_get_exception_thread_abort ();
7853 mono_arch_handle_exception (ctx, thread->abort_exc, FALSE);
7857 sigquit_signal_handler (int _dummy)
7862 exc = mono_get_exception_execution_engine ("Interrupted (SIGQUIT).");
7864 mono_arch_handle_exception (ctx, exc, FALSE);
7868 sigint_signal_handler (int _dummy)
7873 exc = mono_get_exception_execution_engine ("Interrupted (SIGINT).");
7875 mono_arch_handle_exception (ctx, exc, FALSE);
7879 mono_runtime_install_handlers (void)
7881 #ifndef PLATFORM_WIN32
7882 struct sigaction sa;
7885 #ifdef PLATFORM_WIN32
7887 win32_seh_set_handler(SIGFPE, sigfpe_signal_handler);
7888 win32_seh_set_handler(SIGILL, sigill_signal_handler);
7889 win32_seh_set_handler(SIGSEGV, sigsegv_signal_handler);
7890 if (getenv ("MONO_DEBUG"))
7891 win32_seh_set_handler(SIGINT, sigint_signal_handler);
7892 #else /* !PLATFORM_WIN32 */
7894 /* libpthreads has its own implementation of sigaction(),
7895 * but it seems to work well with our current exception
7896 * handlers. If not we must call syscall directly instead
7899 if (getenv ("MONO_DEBUG")) {
7901 sa.sa_handler = sigint_signal_handler;
7902 sigemptyset (&sa.sa_mask);
7904 //g_assert (syscall (SYS_sigaction, SIGINT, &sa, NULL) != -1);
7905 g_assert (sigaction (SIGINT, &sa, NULL) != -1);
7909 sa.sa_handler = sigfpe_signal_handler;
7910 sigemptyset (&sa.sa_mask);
7912 //g_assert (syscall (SYS_sigaction, SIGFPE, &sa, NULL) != -1);
7913 g_assert (sigaction (SIGFPE, &sa, NULL) != -1);
7916 sa.sa_handler = sigquit_signal_handler;
7917 sigemptyset (&sa.sa_mask);
7919 g_assert (sigaction (SIGQUIT, &sa, NULL) != -1);
7922 sa.sa_handler = sigill_signal_handler;
7923 sigemptyset (&sa.sa_mask);
7925 //g_assert (syscall (SYS_sigaction, SIGILL, &sa, NULL) != -1);
7926 g_assert (sigaction (SIGILL, &sa, NULL) != -1);
7928 /* catch thread abort signal */
7929 sa.sa_handler = sigusr1_signal_handler;
7930 sigemptyset (&sa.sa_mask);
7932 //g_assert (syscall (SYS_sigaction, SIGILL, &sa, NULL) != -1);
7934 g_assert (sigaction (mono_thread_get_abort_signal (), &sa, NULL) != -1);
7938 sa.sa_handler = sigsegv_signal_handler;
7939 sigemptyset (&sa.sa_mask);
7941 //g_assert (syscall (SYS_sigaction, SIGSEGV, &sa, NULL) != -1);
7942 g_assert (sigaction (SIGSEGV, &sa, NULL) != -1);
7944 #endif /* PLATFORM_WIN32 */
7947 /* mono_jit_create_remoting_trampoline:
7948 * @method: pointer to the method info
7950 * Creates a trampoline which calls the remoting functions. This
7951 * is used in the vtable of transparent proxies.
7953 * Returns: a pointer to the newly created code
7956 mono_jit_create_remoting_trampoline (MonoMethod *method)
7959 guint8 *addr = NULL;
7961 if ((method->flags & METHOD_ATTRIBUTE_ABSTRACT) ||
7962 (method->signature->hasthis && (method->klass->marshalbyref || method->klass == mono_defaults.object_class))) {
7963 nm = mono_marshal_get_remoting_invoke (method);
7964 addr = mono_compile_method (nm);
7966 addr = mono_compile_method (method);
7972 mini_init (const char *filename)
7976 mono_arch_cpu_init ();
7978 if (!g_thread_supported ())
7979 g_thread_init (NULL);
7981 mono_jit_tls_id = TlsAlloc ();
7982 setup_jit_tls_data ((gpointer)-1, mono_thread_abort);
7984 InitializeCriticalSection (&trampoline_hash_mutex);
7988 if (default_opt & MONO_OPT_AOT)
7991 mono_runtime_install_handlers ();
7992 mono_threads_install_cleanup (mini_thread_cleanup);
7994 #define JIT_TRAMPOLINES_WORK
7995 #ifdef JIT_TRAMPOLINES_WORK
7996 mono_install_compile_method (mono_jit_compile_method);
7997 mono_install_trampoline (mono_arch_create_jit_trampoline);
7998 mono_install_remoting_trampoline (mono_jit_create_remoting_trampoline);
8000 #define JIT_INVOKE_WORKS
8001 #ifdef JIT_INVOKE_WORKS
8002 mono_install_runtime_invoke (mono_jit_runtime_invoke);
8003 mono_install_handler (mono_arch_get_throw_exception ());
8005 mono_install_stack_walk (mono_jit_walk_stack);
8006 mono_install_get_config_dir ();
8008 domain = mono_init (filename);
8011 mono_add_internal_call ("System.Diagnostics.StackFrame::get_frame_info",
8012 ves_icall_get_frame_info);
8013 mono_add_internal_call ("System.Diagnostics.StackTrace::get_trace",
8014 ves_icall_get_trace);
8015 mono_add_internal_call ("Mono.Runtime::mono_runtime_install_handlers",
8016 mono_runtime_install_handlers);
8019 create_helper_signature ();
8021 #define JIT_CALLS_WORK
8022 #ifdef JIT_CALLS_WORK
8023 /* Needs to be called here since register_jit_icall depends on it */
8024 mono_marshal_init ();
8026 mono_arch_register_lowlevel_calls ();
8027 mono_register_jit_icall (mono_profiler_method_enter, "mono_profiler_method_enter", NULL, TRUE);
8028 mono_register_jit_icall (mono_profiler_method_leave, "mono_profiler_method_leave", NULL, TRUE);
8030 mono_register_jit_icall (mono_get_lmf_addr, "mono_get_lmf_addr", helper_sig_ptr_void, TRUE);
8031 mono_register_jit_icall (mono_domain_get, "mono_domain_get", helper_sig_domain_get, TRUE);
8033 /* fixme: we cant hanlde vararg methods this way, because the signature is not constant */
8034 //mono_register_jit_icall (ves_array_element_address, "ves_array_element_address", NULL);
8035 //mono_register_jit_icall (mono_array_new_va, "mono_array_new_va", NULL);
8037 mono_register_jit_icall (mono_arch_get_throw_exception (), "mono_arch_throw_exception", helper_sig_void_obj, TRUE);
8038 mono_register_jit_icall (mono_arch_get_throw_exception_by_name (), "mono_arch_throw_exception_by_name",
8039 helper_sig_void_ptr, TRUE);
8040 mono_register_jit_icall (mono_thread_get_pending_exception, "mono_thread_get_pending_exception", helper_sig_obj_void, FALSE);
8043 * NOTE, NOTE, NOTE, NOTE:
8044 * when adding emulation for some opcodes, remember to also add a dummy
8045 * rule to the burg files, because we need the arity information to be correct.
8047 mono_register_opcode_emulation (OP_LMUL, "__emul_lmul", helper_sig_long_long_long, mono_llmult, TRUE);
8048 mono_register_opcode_emulation (OP_LMUL_OVF_UN, "__emul_lmul_ovf_un", helper_sig_long_long_long, mono_llmult_ovf_un, FALSE);
8049 mono_register_opcode_emulation (OP_LMUL_OVF, "__emul_lmul_ovf", helper_sig_long_long_long, mono_llmult_ovf, FALSE);
8050 mono_register_opcode_emulation (OP_LDIV, "__emul_ldiv", helper_sig_long_long_long, mono_lldiv, FALSE);
8051 mono_register_opcode_emulation (OP_LDIV_UN, "__emul_ldiv_un", helper_sig_long_long_long, mono_lldiv_un, FALSE);
8052 mono_register_opcode_emulation (OP_LREM, "__emul_lrem", helper_sig_long_long_long, mono_llrem, FALSE);
8053 mono_register_opcode_emulation (OP_LREM_UN, "__emul_lrem_un", helper_sig_long_long_long, mono_llrem_un, FALSE);
8055 mono_register_opcode_emulation (OP_LSHL, "__emul_lshl", helper_sig_long_long_int, mono_lshl, TRUE);
8056 mono_register_opcode_emulation (OP_LSHR, "__emul_lshr", helper_sig_long_long_int, mono_lshr, TRUE);
8057 mono_register_opcode_emulation (OP_LSHR_UN, "__emul_lshr_un", helper_sig_long_long_int, mono_lshr_un, TRUE);
8059 mono_register_opcode_emulation (OP_FCONV_TO_U8, "__emul_fconv_to_u8", helper_sig_ulong_double, mono_fconv_u8, FALSE);
8060 mono_register_opcode_emulation (OP_FCONV_TO_U4, "__emul_fconv_to_u4", helper_sig_uint_double, mono_fconv_u4, FALSE);
8061 mono_register_opcode_emulation (OP_FCONV_TO_OVF_I8, "__emul_fconv_to_ovf_i8", helper_sig_long_double, mono_fconv_ovf_i8, TRUE);
8062 mono_register_opcode_emulation (OP_FCONV_TO_OVF_U8, "__emul_fconv_to_ovf_u8", helper_sig_ulong_double, mono_fconv_ovf_u8, TRUE);
8064 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
8065 mono_register_opcode_emulation (OP_FCONV_TO_I8, "__emul_fconv_to_i8", helper_sig_long_double, mono_fconv_i8, FALSE);
8067 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
8068 mono_register_opcode_emulation (OP_LCONV_TO_R8, "__emul_lconv_to_r8", helper_sig_double_long, mono_lconv_to_r8, FALSE);
8070 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
8071 mono_register_opcode_emulation (OP_LCONV_TO_R4, "__emul_lconv_to_r4", helper_sig_float_long, mono_lconv_to_r4, FALSE);
8073 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
8074 mono_register_opcode_emulation (OP_LCONV_TO_R_UN, "__emul_lconv_to_r8_un", helper_sig_double_long, mono_lconv_to_r8_un, FALSE);
8076 #ifdef MONO_ARCH_EMULATE_FREM
8077 mono_register_opcode_emulation (OP_FREM, "__emul_frem", helper_sig_double_double_double, fmod, FALSE);
8080 #if SIZEOF_VOID_P == 4
8081 mono_register_opcode_emulation (OP_FCONV_TO_U, "__emul_fconv_to_u", helper_sig_uint_double, mono_fconv_u4, TRUE);
8083 #warning "fixme: add opcode emulation"
8086 /* other jit icalls */
8087 mono_register_jit_icall (mono_class_static_field_address , "mono_class_static_field_address",
8088 helper_sig_ptr_ptr_ptr, FALSE);
8089 mono_register_jit_icall (mono_ldtoken_wrapper, "mono_ldtoken_wrapper", helper_sig_ptr_ptr_ptr, FALSE);
8090 mono_register_jit_icall (mono_get_special_static_data, "mono_get_special_static_data", helper_sig_ptr_int, FALSE);
8091 mono_register_jit_icall (mono_ldstr, "mono_ldstr", helper_sig_ldstr, FALSE);
8092 mono_register_jit_icall (helper_memcpy, "helper_memcpy", helper_sig_memcpy, FALSE);
8093 mono_register_jit_icall (helper_memset, "helper_memset", helper_sig_memset, FALSE);
8094 mono_register_jit_icall (helper_initobj, "helper_initobj", helper_sig_initobj, FALSE);
8095 mono_register_jit_icall (helper_stelem_ref, "helper_stelem_ref", helper_sig_stelem_ref, FALSE);
8096 mono_register_jit_icall (helper_stelem_ref_check, "helper_stelem_ref_check", helper_sig_stelem_ref_check, FALSE);
8097 mono_register_jit_icall (mono_object_new, "mono_object_new", helper_sig_object_new, FALSE);
8098 mono_register_jit_icall (mono_object_new_specific, "mono_object_new_specific", helper_sig_object_new_specific, FALSE);
8099 mono_register_jit_icall (mono_object_new_fast, "mono_object_new_fast", helper_sig_object_new_specific, FALSE);
8100 mono_register_jit_icall (mono_array_new, "mono_array_new", helper_sig_newarr, FALSE);
8101 mono_register_jit_icall (mono_array_new_specific, "mono_array_new_specific", helper_sig_newarr_specific, FALSE);
8102 mono_register_jit_icall (mono_string_to_utf16, "mono_string_to_utf16", helper_sig_ptr_obj, FALSE);
8103 mono_register_jit_icall (mono_string_from_utf16, "mono_string_from_utf16", helper_sig_obj_ptr, FALSE);
8104 mono_register_jit_icall (mono_string_new_wrapper, "mono_string_new_wrapper", helper_sig_obj_ptr, FALSE);
8105 mono_register_jit_icall (mono_string_to_utf8, "mono_string_to_utf8", helper_sig_ptr_obj, FALSE);
8106 mono_register_jit_icall (mono_string_to_bstr, "mono_string_to_bstr", helper_sig_ptr_obj, FALSE);
8107 mono_register_jit_icall (mono_string_to_ansibstr, "mono_string_to_ansibstr", helper_sig_ptr_obj, FALSE);
8108 mono_register_jit_icall (mono_string_builder_to_utf8, "mono_string_builder_to_utf8", helper_sig_ptr_obj, FALSE);
8109 mono_register_jit_icall (mono_string_builder_to_utf16, "mono_string_builder_to_utf16", helper_sig_ptr_obj, FALSE);
8110 mono_register_jit_icall (mono_array_to_savearray, "mono_array_to_savearray", helper_sig_ptr_obj, FALSE);
8111 mono_register_jit_icall (mono_array_to_lparray, "mono_array_to_lparray", helper_sig_ptr_obj, FALSE);
8112 mono_register_jit_icall (mono_delegate_to_ftnptr, "mono_delegate_to_ftnptr", helper_sig_ptr_obj, FALSE);
8113 mono_register_jit_icall (mono_marshal_string_array, "mono_marshal_string_array", helper_sig_ptr_obj, FALSE);
8114 mono_register_jit_icall (mono_string_utf8_to_builder, "mono_string_utf8_to_builder", helper_sig_void_ptr_ptr, FALSE);
8115 mono_register_jit_icall (mono_string_utf16_to_builder, "mono_string_utf16_to_builder", helper_sig_void_ptr_ptr, FALSE);
8116 mono_register_jit_icall (mono_marshal_free_array, "mono_marshal_free_array", helper_sig_void_ptr_ptr, FALSE);
8117 mono_register_jit_icall (mono_string_to_byvalstr, "mono_string_to_byvalstr", helper_sig_void_ptr_ptr_ptr, FALSE);
8118 mono_register_jit_icall (mono_string_to_byvalwstr, "mono_string_to_byvalwstr", helper_sig_void_ptr_ptr_ptr, FALSE);
8119 mono_register_jit_icall (g_free, "g_free", helper_sig_void_ptr, FALSE);
8120 mono_register_jit_icall (mono_runtime_class_init, "mono_runtime_class_init", helper_sig_void_ptr, FALSE);
8121 mono_register_jit_icall (mono_ldftn, "mono_ldftn", helper_sig_compile, FALSE);
8122 mono_register_jit_icall (mono_ldftn_nosync, "mono_ldftn_nosync", helper_sig_compile, FALSE);
8123 mono_register_jit_icall (mono_ldvirtfn, "mono_ldvirtfn", helper_sig_compile_virt, FALSE);
8124 mono_register_jit_icall (mono_object_castclass_mbyref, "mono_object_castclass", helper_sig_obj_obj_cls, FALSE);
8127 #define JIT_RUNTIME_WORKS
8128 #ifdef JIT_RUNTIME_WORKS
8129 mono_runtime_install_cleanup ((MonoDomainFunc)mini_cleanup);
8130 mono_runtime_init (domain, mono_thread_start_cb, mono_thread_attach_cb);
8133 mono_thread_attach (domain);
8137 MonoJitStats mono_jit_stats = {0};
8140 print_jit_stats (void)
8142 if (mono_jit_stats.enabled) {
8143 g_print ("Mono Jit statistics\n");
8144 g_print ("Compiled methods: %ld\n", mono_jit_stats.methods_compiled);
8145 g_print ("Methods from AOT: %ld\n", mono_jit_stats.methods_aot);
8146 g_print ("Methods cache lookup: %ld\n", mono_jit_stats.methods_lookups);
8147 g_print ("Method trampolines: %ld\n", mono_jit_stats.method_trampolines);
8148 g_print ("Basic blocks: %ld\n", mono_jit_stats.basic_blocks);
8149 g_print ("Max basic blocks: %ld\n", mono_jit_stats.max_basic_blocks);
8150 g_print ("Allocated vars: %ld\n", mono_jit_stats.allocate_var);
8151 g_print ("Analyze stack repeat: %ld\n", mono_jit_stats.analyze_stack_repeat);
8152 g_print ("Compiled CIL code size: %ld\n", mono_jit_stats.cil_code_size);
8153 g_print ("Native code size: %ld\n", mono_jit_stats.native_code_size);
8154 g_print ("Max code size ratio: %.2f (%s::%s)\n", mono_jit_stats.max_code_size_ratio/100.0,
8155 mono_jit_stats.max_ratio_method->klass->name, mono_jit_stats.max_ratio_method->name);
8156 g_print ("Biggest method: %ld (%s::%s)\n", mono_jit_stats.biggest_method_size,
8157 mono_jit_stats.biggest_method->klass->name, mono_jit_stats.biggest_method->name);
8158 g_print ("Code reallocs: %ld\n", mono_jit_stats.code_reallocs);
8159 g_print ("Allocated code size: %ld\n", mono_jit_stats.allocated_code_size);
8160 g_print ("Inlineable methods: %ld\n", mono_jit_stats.inlineable_methods);
8161 g_print ("Inlined methods: %ld\n", mono_jit_stats.inlined_methods);
8163 g_print ("\nCreated object count: %ld\n", mono_stats.new_object_count);
8164 g_print ("Initialized classes: %ld\n", mono_stats.initialized_class_count);
8165 g_print ("Used classes: %ld\n", mono_stats.used_class_count);
8166 g_print ("Static data size: %ld\n", mono_stats.class_static_data_size);
8167 g_print ("VTable data size: %ld\n", mono_stats.class_vtable_size);
8172 mini_cleanup (MonoDomain *domain)
8175 * mono_runtime_cleanup() and mono_domain_finalize () need to
8176 * be called early since they need the execution engine still
8177 * fully working (mono_domain_finalize may invoke managed finalizers
8178 * and mono_runtime_cleanup will wait for other threads to finish).
8180 mono_domain_finalize (domain, -1);
8182 mono_runtime_cleanup (domain);
8184 mono_profiler_shutdown ();
8186 mono_debug_cleanup ();
8188 #ifdef PLATFORM_WIN32
8189 win32_seh_cleanup();
8192 mono_domain_free (domain, TRUE);
8198 mono_set_defaults (int verbose_level, guint32 opts)
8200 mini_verbose = verbose_level;
8205 mono_precompile_assembly (MonoAssembly *ass, void *user_data)
8207 MonoImage *image = ass->image;
8211 if (mini_verbose > 0)
8212 printf ("PRECOMPILE: %s.\n", ass->image->name);
8214 for (i = 0; i < image->tables [MONO_TABLE_METHOD].rows; ++i) {
8215 method = mono_get_method (image, MONO_TOKEN_METHOD_DEF | (i + 1), NULL);
8216 if (method->flags & METHOD_ATTRIBUTE_ABSTRACT)
8218 if (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL)
8222 if (mini_verbose > 1) {
8223 char * desc = mono_method_full_name (method, TRUE);
8224 g_print ("Compiling %d %s\n", count, desc);
8227 mono_compile_method (method);
8231 void mono_precompile_assemblies ()
8233 mono_assembly_foreach ((GFunc)mono_precompile_assembly, NULL);