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.
15 #include <mono/metadata/assembly.h>
16 #include <mono/metadata/loader.h>
17 #include <mono/metadata/cil-coff.h>
18 #include <mono/metadata/tabledefs.h>
19 #include <mono/metadata/class.h>
20 #include <mono/metadata/object.h>
21 #include <mono/metadata/exception.h>
22 #include <mono/metadata/opcodes.h>
23 #include <mono/metadata/mono-endian.h>
24 #include <mono/metadata/tokentype.h>
25 #include <mono/metadata/tabledefs.h>
26 #include <mono/metadata/threads.h>
27 #include <mono/metadata/marshal.h>
28 #include <mono/metadata/socket-io.h>
29 #include <mono/metadata/appdomain.h>
30 #include <mono/metadata/debug-helpers.h>
31 #include <mono/io-layer/io-layer.h>
32 #include "mono/metadata/profiler.h"
33 #include <mono/metadata/profiler-private.h>
34 #include <mono/metadata/mono-config.h>
35 #include <mono/metadata/environment.h>
36 #include <mono/metadata/mono-debug.h>
37 #include <mono/metadata/mono-debug-debugger.h>
44 #include "jit-icalls.c"
46 #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))
48 #define MONO_CHECK_THIS(ins) (cfg->method->signature->hasthis && (ins)->ssa_op == MONO_SSA_LOAD && (ins)->inst_left->inst_c0 == 0)
50 gboolean mono_arch_handle_exception (struct sigcontext *ctx, gpointer obj, gboolean test_only);
51 static gpointer mono_jit_compile_method (MonoMethod *method);
53 static void handle_stobj (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *dest, MonoInst *src,
54 const unsigned char *ip, MonoClass *klass, gboolean to_end, gboolean native);
56 static void dec_foreach (MonoInst *tree, MonoCompile *cfg);
58 static int mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock,
59 int locals_offset, MonoInst *return_var, GList *dont_inline, MonoInst **inline_args,
60 guint inline_offset, gboolean is_virtual_call);
62 extern guint8 mono_burg_arity [];
63 /* helper methods signature */
64 static MonoMethodSignature *helper_sig_long_long_long = NULL;
65 static MonoMethodSignature *helper_sig_long_long_int = NULL;
66 static MonoMethodSignature *helper_sig_newarr = NULL;
67 static MonoMethodSignature *helper_sig_newarr_specific = NULL;
68 static MonoMethodSignature *helper_sig_ldstr = NULL;
69 static MonoMethodSignature *helper_sig_domain_get = NULL;
70 static MonoMethodSignature *helper_sig_object_new = NULL;
71 static MonoMethodSignature *helper_sig_object_new_specific = NULL;
72 static MonoMethodSignature *helper_sig_compile = NULL;
73 static MonoMethodSignature *helper_sig_compile_virt = NULL;
74 static MonoMethodSignature *helper_sig_obj_ptr = NULL;
75 static MonoMethodSignature *helper_sig_ptr_void = NULL;
76 static MonoMethodSignature *helper_sig_void_ptr = NULL;
77 static MonoMethodSignature *helper_sig_void_obj = NULL;
78 static MonoMethodSignature *helper_sig_void_ptr_ptr = NULL;
79 static MonoMethodSignature *helper_sig_void_ptr_ptr_ptr = NULL;
80 static MonoMethodSignature *helper_sig_ptr_ptr_ptr = NULL;
81 static MonoMethodSignature *helper_sig_ptr_obj = NULL;
82 static MonoMethodSignature *helper_sig_ptr_int = NULL;
83 static MonoMethodSignature *helper_sig_initobj = NULL;
84 static MonoMethodSignature *helper_sig_memcpy = NULL;
85 static MonoMethodSignature *helper_sig_memset = NULL;
86 static MonoMethodSignature *helper_sig_ulong_double = NULL;
87 static MonoMethodSignature *helper_sig_long_double = NULL;
88 static MonoMethodSignature *helper_sig_uint_double = NULL;
89 static MonoMethodSignature *helper_sig_int_double = NULL;
90 static MonoMethodSignature *helper_sig_stelem_ref = NULL;
91 static MonoMethodSignature *helper_sig_class_init_trampoline = NULL;
93 static guint32 default_opt = MONO_OPT_PEEPHOLE;
95 guint32 mono_jit_tls_id = -1;
96 gboolean mono_jit_trace_calls = FALSE;
97 gboolean mono_break_on_exc = FALSE;
98 gboolean mono_compile_aot = FALSE;
99 gboolean mono_no_aot = FALSE;
101 static int mini_verbose = 0;
103 static CRITICAL_SECTION class_init_hash_mutex;
105 static GHashTable *class_init_hash_addr = NULL;
107 #ifdef MONO_USE_EXC_TABLES
109 mono_type_blittable (MonoType *type)
129 case MONO_TYPE_VALUETYPE:
130 case MONO_TYPE_CLASS:
131 case MONO_TYPE_OBJECT:
132 return type->data.klass->blittable;
142 mono_method_blittable (MonoMethod *method)
144 MonoMethodSignature *sig;
150 if (!mono_arch_has_unwind_info (method->addr)) {
154 if (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL)
157 sig = method->signature;
159 if (!mono_type_blittable (sig->ret))
162 for (i = 0; i < sig->param_count; i++)
163 if (!mono_type_blittable (sig->params [i]))
166 if (mono_method_has_marshal_info (method))
174 G_GNUC_UNUSED static void
175 print_method_from_ip (void *ip)
180 MonoDomain *domain = mono_domain_get ();
182 ji = mono_jit_info_table_find (domain, ip);
184 g_print ("No method at %p\n", ip);
187 method = mono_method_full_name (ji->method, TRUE);
188 source = mono_debug_source_location_from_address (ji->method, (int) ip, NULL, domain);
190 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);
193 g_print ("%s\n", source);
201 mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
203 MonoJumpInfoToken *res = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoToken));
210 #define MONO_INIT_VARINFO(vi,id) do { \
211 (vi)->range.first_use.pos.bid = 0xffff; \
217 * Basic blocks have two numeric identifiers:
218 * dfn: Depth First Number
219 * block_num: unique ID assigned at bblock creation
221 #define NEW_BBLOCK(cfg) (mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock)))
222 #define ADD_BBLOCK(cfg,bbhash,b) do { \
223 g_hash_table_insert (bbhash, (b)->cil_code, (b)); \
224 (b)->block_num = cfg->num_bblocks++; \
225 (b)->real_offset = real_offset; \
228 #define GET_BBLOCK(cfg,bbhash,tblock,ip) do { \
229 (tblock) = g_hash_table_lookup (bbhash, (ip)); \
231 if ((ip) >= end || (ip) < header->code) goto unverified; \
232 (tblock) = NEW_BBLOCK (cfg); \
233 (tblock)->cil_code = (ip); \
234 ADD_BBLOCK (cfg, (bbhash), (tblock)); \
236 (tblock)->real_offset = real_offset; \
239 #define CHECK_BBLOCK(target,ip,tblock) do { \
240 if ((target) < (ip) && !(tblock)->code) { \
241 bb_recheck = g_list_prepend (bb_recheck, (tblock)); \
242 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); \
246 #define NEW_ICONST(cfg,dest,val) do { \
247 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
248 (dest)->opcode = OP_ICONST; \
249 (dest)->inst_c0 = (val); \
250 (dest)->type = STACK_I4; \
253 /* FIXME: have a different definition of NEW_PCONST for 64 bit systems */
254 #define NEW_PCONST(cfg,dest,val) do { \
255 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
256 (dest)->opcode = OP_ICONST; \
257 (dest)->inst_p0 = (val); \
258 (dest)->type = STACK_PTR; \
261 #define NEW_CLASSCONST(cfg,dest,val) do { \
262 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
263 (dest)->opcode = mono_compile_aot ? OP_AOTCONST : OP_ICONST; \
264 (dest)->inst_p0 = (val); \
265 (dest)->inst_i1 = (gpointer)MONO_PATCH_INFO_CLASS; \
266 (dest)->type = STACK_PTR; \
269 #define NEW_IMAGECONST(cfg,dest,val) do { \
270 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
271 (dest)->opcode = mono_compile_aot ? OP_AOTCONST : OP_ICONST; \
272 (dest)->inst_p0 = (val); \
273 (dest)->inst_i1 = (gpointer)MONO_PATCH_INFO_IMAGE; \
274 (dest)->type = STACK_PTR; \
277 #define NEW_FIELDCONST(cfg,dest,field) do { \
278 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
279 (dest)->opcode = mono_compile_aot ? OP_AOTCONST : OP_ICONST; \
280 (dest)->inst_p0 = (field); \
281 (dest)->inst_i1 = (gpointer)MONO_PATCH_INFO_FIELD; \
282 (dest)->type = STACK_PTR; \
285 #define NEW_METHODCONST(cfg,dest,val) do { \
286 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
287 (dest)->opcode = mono_compile_aot ? OP_AOTCONST : OP_ICONST; \
288 (dest)->inst_p0 = (val); \
289 (dest)->inst_i1 = (gpointer)MONO_PATCH_INFO_METHODCONST; \
290 (dest)->type = STACK_PTR; \
293 #define NEW_VTABLECONST(cfg,dest,vtable) do { \
294 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
295 (dest)->opcode = mono_compile_aot ? OP_AOTCONST : OP_ICONST; \
296 (dest)->inst_p0 = mono_compile_aot ? (gpointer)((vtable)->klass) : (vtable); \
297 (dest)->inst_i1 = (gpointer)MONO_PATCH_INFO_VTABLE; \
298 (dest)->type = STACK_PTR; \
301 #define NEW_SFLDACONST(cfg,dest,field) do { \
302 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
303 (dest)->opcode = mono_compile_aot ? OP_AOTCONST : OP_ICONST; \
304 (dest)->inst_p0 = (field); \
305 (dest)->inst_i1 = (gpointer)MONO_PATCH_INFO_SFLDA; \
306 (dest)->type = STACK_PTR; \
309 #define NEW_LDSTRCONST(cfg,dest,image,token) do { \
310 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
311 (dest)->opcode = OP_AOTCONST; \
312 (dest)->inst_p0 = mono_jump_info_token_new ((cfg)->mempool, (image), (token)); \
313 (dest)->inst_i1 = (gpointer)MONO_PATCH_INFO_LDSTR; \
314 (dest)->type = STACK_OBJ; \
317 #define NEW_TYPE_FROM_HANDLE_CONST(cfg,dest,image,token) do { \
318 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
319 (dest)->opcode = OP_AOTCONST; \
320 (dest)->inst_p0 = mono_jump_info_token_new ((cfg)->mempool, (image), (token)); \
321 (dest)->inst_i1 = (gpointer)MONO_PATCH_INFO_TYPE_FROM_HANDLE; \
322 (dest)->type = STACK_OBJ; \
325 #define NEW_LDTOKENCONST(cfg,dest,image,token) do { \
326 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
327 (dest)->opcode = OP_AOTCONST; \
328 (dest)->inst_p0 = mono_jump_info_token_new ((cfg)->mempool, (image), (token)); \
329 (dest)->inst_i1 = (gpointer)MONO_PATCH_INFO_LDTOKEN; \
330 (dest)->type = STACK_PTR; \
333 #define NEW_DOMAINCONST(cfg,dest) do { \
334 if (cfg->opt & MONO_OPT_SHARED) { \
335 NEW_TEMPLOAD (cfg, dest, mono_get_domainvar (cfg)->inst_c0); \
337 NEW_PCONST (cfg, dest, (cfg)->domain); \
341 #define GET_VARINFO_INST(cfg,num) ((cfg)->varinfo [(num)]->inst)
343 #define NEW_ARGLOAD(cfg,dest,num) do { \
344 if (arg_array [(num)]->opcode == OP_ICONST) (dest) = arg_array [(num)]; else { \
345 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
346 (dest)->ssa_op = MONO_SSA_LOAD; \
347 (dest)->inst_i0 = arg_array [(num)]; \
348 (dest)->opcode = mono_type_to_ldind ((dest)->inst_i0->inst_vtype); \
349 type_to_eval_stack_type (param_types [(num)], (dest)); \
350 (dest)->klass = (dest)->inst_i0->klass; \
353 #define NEW_LOCLOAD(cfg,dest,num) do { \
354 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
355 (dest)->ssa_op = MONO_SSA_LOAD; \
356 (dest)->inst_i0 = (cfg)->varinfo [locals_offset + (num)]; \
357 (dest)->opcode = mono_type_to_ldind ((dest)->inst_i0->inst_vtype); \
358 type_to_eval_stack_type (header->locals [(num)], (dest)); \
359 (dest)->klass = (dest)->inst_i0->klass; \
362 #define NEW_LOCLOADA(cfg,dest,num) do { \
363 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
364 (dest)->ssa_op = MONO_SSA_MAYBE_LOAD; \
365 (dest)->inst_i0 = (cfg)->varinfo [locals_offset + (num)]; \
366 (dest)->inst_i0->flags |= MONO_INST_INDIRECT; \
367 (dest)->opcode = OP_LDADDR; \
368 (dest)->type = STACK_MP; \
369 (dest)->klass = (dest)->inst_i0->klass; \
370 (cfg)->disable_ssa = TRUE; \
373 #define NEW_RETLOADA(cfg,dest) do { \
374 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
375 (dest)->ssa_op = MONO_SSA_MAYBE_LOAD; \
376 (dest)->inst_i0 = (cfg)->ret; \
377 (dest)->inst_i0->flags |= MONO_INST_INDIRECT; \
378 (dest)->opcode = CEE_LDIND_I; \
379 (dest)->type = STACK_MP; \
380 (dest)->klass = (dest)->inst_i0->klass; \
381 (cfg)->disable_ssa = TRUE; \
384 #define NEW_ARGLOADA(cfg,dest,num) do { \
385 if (arg_array [(num)]->opcode == OP_ICONST) goto inline_failure; \
386 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
387 (dest)->ssa_op = MONO_SSA_MAYBE_LOAD; \
388 (dest)->inst_i0 = arg_array [(num)]; \
389 (dest)->inst_i0->flags |= MONO_INST_INDIRECT; \
390 (dest)->opcode = OP_LDADDR; \
391 (dest)->type = STACK_MP; \
392 (dest)->klass = (dest)->inst_i0->klass; \
393 (cfg)->disable_ssa = TRUE; \
396 #define NEW_TEMPLOAD(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 [(num)]; \
400 (dest)->opcode = mono_type_to_ldind ((dest)->inst_i0->inst_vtype); \
401 type_to_eval_stack_type ((dest)->inst_i0->inst_vtype, (dest)); \
402 (dest)->klass = (dest)->inst_i0->klass; \
405 #define NEW_TEMPLOADA(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 [(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 (cfg)->disable_ssa = TRUE; \
417 #define NEW_INDLOAD(cfg,dest,addr,vtype) do { \
418 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
419 (dest)->inst_left = addr; \
420 (dest)->opcode = mono_type_to_ldind (vtype); \
421 type_to_eval_stack_type (vtype, (dest)); \
422 /* FIXME: (dest)->klass = (dest)->inst_i0->klass;*/ \
425 #define NEW_INDSTORE(cfg,dest,addr,value,vtype) do { \
426 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
427 (dest)->inst_i0 = addr; \
428 (dest)->opcode = mono_type_to_stind (vtype); \
429 (dest)->inst_i1 = (value); \
430 /* FIXME: (dest)->klass = (dest)->inst_i0->klass;*/ \
433 #define NEW_TEMPSTORE(cfg,dest,num,inst) do { \
434 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
435 (dest)->ssa_op = MONO_SSA_STORE; \
436 (dest)->inst_i0 = (cfg)->varinfo [(num)]; \
437 (dest)->opcode = mono_type_to_stind ((dest)->inst_i0->inst_vtype); \
438 (dest)->inst_i1 = (inst); \
439 (dest)->klass = (dest)->inst_i0->klass; \
442 #define NEW_LOCSTORE(cfg,dest,num,inst) do { \
443 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
444 (dest)->opcode = mono_type_to_stind (header->locals [(num)]); \
445 (dest)->ssa_op = MONO_SSA_STORE; \
446 (dest)->inst_i0 = (cfg)->varinfo [locals_offset + (num)]; \
447 (dest)->inst_i1 = (inst); \
448 (dest)->klass = (dest)->inst_i0->klass; \
451 #define NEW_ARGSTORE(cfg,dest,num,inst) do { \
452 if (arg_array [(num)]->opcode == OP_ICONST) goto inline_failure; \
453 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
454 (dest)->opcode = mono_type_to_stind (param_types [(num)]); \
455 (dest)->ssa_op = MONO_SSA_STORE; \
456 (dest)->inst_i0 = arg_array [(num)]; \
457 (dest)->inst_i1 = (inst); \
458 (dest)->klass = (dest)->inst_i0->klass; \
461 #define ADD_BINOP(op) do { \
462 MONO_INST_NEW (cfg, ins, (op)); \
463 ins->cil_code = ip; \
465 ins->inst_i0 = sp [0]; \
466 ins->inst_i1 = sp [1]; \
468 type_from_op (ins); \
472 #define ADD_UNOP(op) do { \
473 MONO_INST_NEW (cfg, ins, (op)); \
474 ins->cil_code = ip; \
476 ins->inst_i0 = sp [0]; \
478 type_from_op (ins); \
482 #define ADD_BINCOND(next_block) do { \
484 MONO_INST_NEW(cfg, cmp, OP_COMPARE); \
486 cmp->inst_i0 = sp [0]; \
487 cmp->inst_i1 = sp [1]; \
488 cmp->cil_code = ins->cil_code; \
489 type_from_op (cmp); \
491 ins->inst_i0 = cmp; \
492 MONO_ADD_INS (bblock, ins); \
493 ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2); \
494 GET_BBLOCK (cfg, bbhash, tblock, target); \
495 link_bblock (cfg, bblock, tblock); \
496 ins->inst_true_bb = tblock; \
497 CHECK_BBLOCK (target, ip, tblock); \
498 if ((next_block)) { \
499 link_bblock (cfg, bblock, (next_block)); \
500 ins->inst_false_bb = (next_block); \
501 start_new_bblock = 1; \
503 GET_BBLOCK (cfg, bbhash, tblock, ip); \
504 link_bblock (cfg, bblock, tblock); \
505 ins->inst_false_bb = tblock; \
506 start_new_bblock = 2; \
510 /* FIXME: handle float, long ... */
511 #define ADD_UNCOND(istrue) do { \
513 MONO_INST_NEW(cfg, cmp, OP_COMPARE); \
515 cmp->inst_i0 = sp [0]; \
516 switch (cmp->inst_i0->type) { \
518 cmp->inst_i1 = zero_int64; break; \
520 cmp->inst_i1 = zero_r8; break; \
523 cmp->inst_i1 = zero_ptr; break; \
525 cmp->inst_i1 = zero_obj; break; \
527 cmp->inst_i1 = zero_int32; \
529 cmp->cil_code = ins->cil_code; \
530 type_from_op (cmp); \
532 ins->inst_i0 = cmp; \
533 ins->opcode = (istrue)? CEE_BNE_UN: CEE_BEQ; \
534 MONO_ADD_INS (bblock, ins); \
535 ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2); \
536 GET_BBLOCK (cfg, bbhash, tblock, target); \
537 link_bblock (cfg, bblock, tblock); \
538 ins->inst_true_bb = tblock; \
539 CHECK_BBLOCK (target, ip, tblock); \
540 GET_BBLOCK (cfg, bbhash, tblock, ip); \
541 link_bblock (cfg, bblock, tblock); \
542 ins->inst_false_bb = tblock; \
543 start_new_bblock = 2; \
546 #define NEW_LDELEMA(cfg,dest,sp,k) do { \
547 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
548 (dest)->opcode = CEE_LDELEMA; \
549 (dest)->inst_left = (sp) [0]; \
550 (dest)->inst_right = (sp) [1]; \
551 (dest)->type = STACK_MP; \
552 (dest)->klass = (k); \
555 #define NEW_GROUP(cfg,dest,el1,el2) do { \
556 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
557 (dest)->opcode = OP_GROUP; \
558 (dest)->inst_left = (el1); \
559 (dest)->inst_right = (el2); \
564 compare_bblock (gconstpointer a, gconstpointer b)
566 const MonoBasicBlock *b1 = a;
567 const MonoBasicBlock *b2 = b;
569 return b2->cil_code - b1->cil_code;
574 * link_bblock: Links two basic blocks
576 * links two basic blocks in the control flow graph, the 'from'
577 * argument is the starting block and the 'to' argument is the block
578 * the control flow ends to after 'from'.
581 link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
583 MonoBasicBlock **newa;
587 if (from->cil_code) {
589 g_print ("edge from IL%04x to IL_%04x\n", from->cil_code - cfg->cil_code, to->cil_code - cfg->cil_code);
591 g_print ("edge from IL%04x to exit\n", from->cil_code - cfg->cil_code);
594 g_print ("edge from entry to IL_%04x\n", to->cil_code - cfg->cil_code);
596 g_print ("edge from entry to exit\n");
600 for (i = 0; i < from->out_count; ++i) {
601 if (to == from->out_bb [i]) {
607 newa = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (from->out_count + 1));
608 for (i = 0; i < from->out_count; ++i) {
609 newa [i] = from->out_bb [i];
617 for (i = 0; i < to->in_count; ++i) {
618 if (from == to->in_bb [i]) {
624 newa = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (to->in_count + 1));
625 for (i = 0; i < to->in_count; ++i) {
626 newa [i] = to->in_bb [i];
635 * We mark each basic block with a region ID. We use that to avoid BB
636 * optimizations when blocks are in different regions.
639 mono_find_block_region (MonoCompile *cfg, int offset, int *filter_lengths)
641 MonoMethod *method = cfg->method;
642 MonoMethodHeader *header = ((MonoMethodNormal *)method)->header;
643 MonoExceptionClause *clause;
646 /* first search for handlers and filters */
647 for (i = 0; i < header->num_clauses; ++i) {
648 clause = &header->clauses [i];
649 if ((clause->flags & MONO_EXCEPTION_CLAUSE_FILTER) && (offset >= clause->token_or_filter) &&
650 (offset < (clause->token_or_filter + filter_lengths [i])))
651 return ((i + 1) << 8) | MONO_REGION_FILTER | clause->flags;
653 if (MONO_OFFSET_IN_HANDLER (clause, offset)) {
654 if (clause->flags & MONO_EXCEPTION_CLAUSE_FINALLY)
655 return ((i + 1) << 8) | MONO_REGION_FINALLY | clause->flags;
657 return ((i + 1) << 8) | MONO_REGION_CATCH | clause->flags;
661 /* search the try blocks */
662 for (i = 0; i < header->num_clauses; ++i) {
663 clause = &header->clauses [i];
664 if (MONO_OFFSET_IN_CLAUSE (clause, offset))
665 return ((i + 1) << 8) | clause->flags;
672 mono_find_final_block (MonoCompile *cfg, unsigned char *ip, unsigned char *target, int type)
674 MonoMethod *method = cfg->method;
675 MonoMethodHeader *header = ((MonoMethodNormal *)method)->header;
676 MonoExceptionClause *clause;
677 MonoBasicBlock *handler;
681 for (i = 0; i < header->num_clauses; ++i) {
682 clause = &header->clauses [i];
683 if (MONO_OFFSET_IN_CLAUSE (clause, (ip - header->code)) &&
684 (!MONO_OFFSET_IN_CLAUSE (clause, (target - header->code)))) {
685 if (clause->flags == type) {
686 handler = g_hash_table_lookup (cfg->bb_hash, header->code + clause->handler_offset);
688 res = g_list_append (res, handler);
696 mono_find_spvar_for_region (MonoCompile *cfg, int region)
698 return g_hash_table_lookup (cfg->spvars, GINT_TO_POINTER (region));
702 mono_create_spvar_for_region (MonoCompile *cfg, int region)
706 var = g_hash_table_lookup (cfg->spvars, GINT_TO_POINTER (region));
710 var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
711 /* prevent it from being register allocated */
712 var->flags |= MONO_INST_INDIRECT;
714 g_hash_table_insert (cfg->spvars, GINT_TO_POINTER (region), var);
718 df_visit (MonoBasicBlock *start, int *dfn, MonoBasicBlock **array)
722 array [*dfn] = start;
723 /*g_print ("visit %d at %p\n", *dfn, start->cil_code);*/
724 for (i = 0; i < start->out_count; ++i) {
725 if (start->out_bb [i]->dfn)
728 start->out_bb [i]->dfn = *dfn;
729 start->out_bb [i]->df_parent = start;
730 array [*dfn] = start->out_bb [i];
731 df_visit (start->out_bb [i], dfn, array);
737 MonoBasicBlock *best;
741 previous_foreach (gconstpointer key, gpointer val, gpointer data)
743 PrevStruct *p = data;
744 MonoBasicBlock *bb = val;
745 //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,
746 //bb->method == p->best->method, bb->cil_code < p->code, bb->cil_code > p->best->cil_code);
748 if (bb->cil_code && bb->cil_code < p->code && bb->cil_code > p->best->cil_code)
752 static MonoBasicBlock*
753 find_previous (GHashTable *bb_hash, MonoBasicBlock *start, const guchar *code) {
759 g_hash_table_foreach (bb_hash, (GHFunc)previous_foreach, &p);
764 split_bblock (MonoCompile *cfg, MonoBasicBlock *first, MonoBasicBlock *second) {
773 * FIXME: take into account all the details:
774 * second may have been the target of more than one bblock
776 second->out_count = first->out_count;
777 second->out_bb = first->out_bb;
779 for (i = 0; i < first->out_count; ++i) {
780 bb = first->out_bb [i];
781 for (j = 0; j < bb->in_count; ++j) {
782 if (bb->in_bb [j] == first)
783 bb->in_bb [j] = second;
787 first->out_count = 0;
788 first->out_bb = NULL;
789 link_bblock (cfg, first, second);
791 second->last_ins = first->last_ins;
793 /*g_print ("start search at %p for %p\n", first->cil_code, second->cil_code);*/
794 for (inst = first->code; inst && inst->next; inst = inst->next) {
795 /*char *code = mono_disasm_code_one (NULL, cfg->method, inst->next->cil_code, NULL);
796 g_print ("found %p: %s", inst->next->cil_code, code);
798 if (inst->cil_code < second->cil_code && inst->next->cil_code >= second->cil_code) {
799 second->code = inst->next;
801 first->last_ins = inst;
802 second->next_bb = first->next_bb;
803 first->next_bb = second;
808 g_warning ("bblock split failed in %s::%s\n", cfg->method->klass->name, cfg->method->name);
814 mono_type_to_ldind (MonoType *type)
826 case MONO_TYPE_BOOLEAN:
840 case MONO_TYPE_FNPTR:
842 case MONO_TYPE_CLASS:
843 case MONO_TYPE_STRING:
844 case MONO_TYPE_OBJECT:
845 case MONO_TYPE_SZARRAY:
846 case MONO_TYPE_ARRAY:
847 return CEE_LDIND_REF;
855 case MONO_TYPE_VALUETYPE:
856 if (type->data.klass->enumtype) {
857 t = type->data.klass->enum_basetype->type;
861 case MONO_TYPE_TYPEDBYREF:
863 case MONO_TYPE_GENERICINST:
864 if (type->data.generic_inst->generic_type->type == MONO_TYPE_VALUETYPE)
866 return CEE_LDIND_REF;
868 g_error ("unknown type 0x%02x in type_to_ldind", type->type);
874 mono_type_to_stind (MonoType *type)
885 case MONO_TYPE_BOOLEAN:
897 case MONO_TYPE_FNPTR:
899 case MONO_TYPE_CLASS:
900 case MONO_TYPE_STRING:
901 case MONO_TYPE_OBJECT:
902 case MONO_TYPE_SZARRAY:
903 case MONO_TYPE_ARRAY:
904 return CEE_STIND_REF;
912 case MONO_TYPE_VALUETYPE:
913 if (type->data.klass->enumtype) {
914 t = type->data.klass->enum_basetype->type;
918 case MONO_TYPE_TYPEDBYREF:
920 case MONO_TYPE_GENERICINST:
921 if (type->data.generic_inst->generic_type->type == MONO_TYPE_VALUETYPE)
923 return CEE_STIND_REF;
925 g_error ("unknown type 0x%02x in type_to_stind", type->type);
931 * Returns the type used in the eval stack when @type is loaded.
932 * FIXME: return a MonoType/MonoClass for the byref and VALUETYPE cases.
935 type_to_eval_stack_type (MonoType *type, MonoInst *inst) {
939 inst->type = STACK_MP;
947 case MONO_TYPE_BOOLEAN:
953 inst->type = STACK_I4;
958 case MONO_TYPE_FNPTR:
959 inst->type = STACK_PTR;
961 case MONO_TYPE_CLASS:
962 case MONO_TYPE_STRING:
963 case MONO_TYPE_OBJECT:
964 case MONO_TYPE_SZARRAY:
965 case MONO_TYPE_ARRAY:
966 inst->type = STACK_OBJ;
970 inst->type = STACK_I8;
974 inst->type = STACK_R8;
976 case MONO_TYPE_VALUETYPE:
977 if (type->data.klass->enumtype) {
978 t = type->data.klass->enum_basetype->type;
981 inst->klass = type->data.klass;
982 inst->type = STACK_VTYPE;
985 case MONO_TYPE_TYPEDBYREF:
986 inst->klass = mono_defaults.typed_reference_class;
987 inst->type = STACK_VTYPE;
989 case MONO_TYPE_GENERICINST:
990 if (type->data.generic_inst->generic_type->type == MONO_TYPE_VALUETYPE) {
991 inst->klass = mono_class_from_mono_type (type);
992 inst->type = STACK_VTYPE;
994 inst->type = STACK_OBJ;
998 g_error ("unknown type 0x%02x in eval stack type", type->type);
1003 * The following tables are used to quickly validate the IL code in type_from_op ().
1006 bin_num_table [STACK_MAX] [STACK_MAX] = {
1007 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1008 {STACK_INV, STACK_I4, STACK_INV, STACK_PTR, STACK_INV, STACK_MP, STACK_INV, STACK_INV},
1009 {STACK_INV, STACK_INV, STACK_I8, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1010 {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_MP, STACK_INV, STACK_INV},
1011 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_R8, STACK_INV, STACK_INV, STACK_INV},
1012 {STACK_INV, STACK_MP, STACK_INV, STACK_MP, STACK_INV, STACK_PTR, STACK_INV, STACK_INV},
1013 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1014 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
1019 STACK_INV, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_INV, STACK_INV, STACK_INV
1022 /* reduce the size of this table */
1024 bin_int_table [STACK_MAX] [STACK_MAX] = {
1025 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1026 {STACK_INV, STACK_I4, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1027 {STACK_INV, STACK_INV, STACK_I8, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1028 {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1029 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1030 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1031 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1032 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
1036 bin_comp_table [STACK_MAX] [STACK_MAX] = {
1038 {0, 1, 0, 1, 0, 0, 4, 0},
1039 {0, 0, 1, 0, 0, 0, 0, 0},
1040 {0, 1, 0, 1, 0, 2, 4, 0},
1041 {0, 0, 0, 0, 1, 0, 0, 0},
1042 {0, 0, 0, 2, 0, 1, 0, 0},
1043 {0, 4, 0, 4, 0, 0, 3, 0},
1044 {0, 0, 0, 0, 0, 0, 0, 0},
1047 /* reduce the size of this table */
1049 shift_table [STACK_MAX] [STACK_MAX] = {
1050 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1051 {STACK_INV, STACK_I4, STACK_INV, STACK_I4, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1052 {STACK_INV, STACK_I8, STACK_INV, STACK_I8, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1053 {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1054 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1055 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1056 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1057 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
1061 * Tables to map from the non-specific opcode to the matching
1062 * type-specific opcode.
1064 /* handles from CEE_ADD to CEE_SHR_UN (CEE_REM_UN for floats) */
1065 static const guint16
1066 binops_op_map [STACK_MAX] = {
1067 0, 0, OP_LADD-CEE_ADD, OP_PADD-CEE_ADD, OP_FADD-CEE_ADD, 0
1070 /* handles from CEE_NEG to CEE_CONV_U8 */
1071 static const guint16
1072 unops_op_map [STACK_MAX] = {
1073 0, 0, OP_LNEG-CEE_NEG, OP_PNEG-CEE_NEG, OP_FNEG-CEE_NEG, 0
1076 /* handles from CEE_CONV_U2 to CEE_SUB_OVF_UN */
1077 static const guint16
1078 ovfops_op_map [STACK_MAX] = {
1079 0, 0, OP_LCONV_TO_U2-CEE_CONV_U2, OP_PCONV_TO_U2-CEE_CONV_U2, OP_FCONV_TO_U2-CEE_CONV_U2, 0
1082 /* handles from CEE_CONV_OVF_I1_UN to CEE_CONV_OVF_U_UN */
1083 static const guint16
1084 ovf2ops_op_map [STACK_MAX] = {
1085 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
1088 /* handles from CEE_CONV_OVF_I1 to CEE_CONV_OVF_U8 */
1089 static const guint16
1090 ovf3ops_op_map [STACK_MAX] = {
1091 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
1094 /* handles from CEE_CEQ to CEE_CLT_UN */
1095 static const guint16
1096 ceqops_op_map [STACK_MAX] = {
1097 0, 0, OP_LCEQ-CEE_CEQ, OP_PCEQ-CEE_CEQ, OP_FCEQ-CEE_CEQ, 0
1101 * Sets ins->type (the type on the eval stack) according to the
1102 * type of the opcode and the arguments to it.
1103 * Invalid IL code is marked by setting ins->type to the invalid value STACK_INV.
1105 * FIXME: this function sets ins->type unconditionally in some cases, but
1106 * it should set it to invalid for some types (a conv.x on an object)
1109 type_from_op (MonoInst *ins) {
1110 switch (ins->opcode) {
1117 /* FIXME: check unverifiable args for STACK_MP */
1118 ins->type = bin_num_table [ins->inst_i0->type] [ins->inst_i1->type];
1119 ins->opcode += binops_op_map [ins->type];
1126 ins->type = bin_int_table [ins->inst_i0->type] [ins->inst_i1->type];
1127 ins->opcode += binops_op_map [ins->type];
1132 ins->type = shift_table [ins->inst_i0->type] [ins->inst_i1->type];
1133 ins->opcode += binops_op_map [ins->type];
1136 /* FIXME: handle some specifics with ins->next->type */
1137 ins->type = bin_comp_table [ins->inst_i0->type] [ins->inst_i1->type] ? STACK_I4: STACK_INV;
1141 case 256+CEE_CGT_UN:
1143 case 256+CEE_CLT_UN:
1144 ins->type = bin_comp_table [ins->inst_i0->type] [ins->inst_i1->type] ? STACK_I4: STACK_INV;
1145 ins->opcode += ceqops_op_map [ins->inst_i0->type];
1149 ins->type = neg_table [ins->inst_i0->type];
1150 ins->opcode += unops_op_map [ins->type];
1153 if (ins->inst_i0->type >= STACK_I4 && ins->inst_i0->type <= STACK_PTR)
1154 ins->type = ins->inst_i0->type;
1156 ins->type = STACK_INV;
1157 ins->opcode += unops_op_map [ins->type];
1163 ins->type = STACK_I4;
1164 ins->opcode += unops_op_map [ins->inst_i0->type];
1167 ins->type = STACK_R8;
1168 switch (ins->inst_i0->type) {
1173 ins->opcode = OP_LCONV_TO_R_UN;
1177 case CEE_CONV_OVF_I1:
1178 case CEE_CONV_OVF_U1:
1179 case CEE_CONV_OVF_I2:
1180 case CEE_CONV_OVF_U2:
1181 case CEE_CONV_OVF_I4:
1182 case CEE_CONV_OVF_U4:
1183 ins->type = STACK_I4;
1184 ins->opcode += ovf3ops_op_map [ins->inst_i0->type];
1186 case CEE_CONV_OVF_I_UN:
1187 case CEE_CONV_OVF_U_UN:
1188 ins->type = STACK_PTR;
1189 ins->opcode += ovf2ops_op_map [ins->inst_i0->type];
1191 case CEE_CONV_OVF_I1_UN:
1192 case CEE_CONV_OVF_I2_UN:
1193 case CEE_CONV_OVF_I4_UN:
1194 case CEE_CONV_OVF_U1_UN:
1195 case CEE_CONV_OVF_U2_UN:
1196 case CEE_CONV_OVF_U4_UN:
1197 ins->type = STACK_I4;
1198 ins->opcode += ovf2ops_op_map [ins->inst_i0->type];
1201 ins->type = STACK_PTR;
1202 switch (ins->inst_i0->type) {
1208 ins->opcode = OP_LCONV_TO_U;
1211 ins->opcode = OP_FCONV_TO_U;
1217 ins->type = STACK_I8;
1218 ins->opcode += unops_op_map [ins->inst_i0->type];
1220 case CEE_CONV_OVF_I8:
1221 case CEE_CONV_OVF_U8:
1222 ins->type = STACK_I8;
1223 ins->opcode += ovf3ops_op_map [ins->inst_i0->type];
1225 case CEE_CONV_OVF_U8_UN:
1226 case CEE_CONV_OVF_I8_UN:
1227 ins->type = STACK_I8;
1228 ins->opcode += ovf2ops_op_map [ins->inst_i0->type];
1232 ins->type = STACK_R8;
1233 ins->opcode += unops_op_map [ins->inst_i0->type];
1236 ins->type = STACK_R8;
1240 ins->type = STACK_I4;
1241 ins->opcode += ovfops_op_map [ins->inst_i0->type];
1244 case CEE_CONV_OVF_I:
1245 case CEE_CONV_OVF_U:
1246 ins->type = STACK_PTR;
1247 ins->opcode += ovfops_op_map [ins->inst_i0->type];
1250 case CEE_ADD_OVF_UN:
1252 case CEE_MUL_OVF_UN:
1254 case CEE_SUB_OVF_UN:
1255 ins->type = bin_num_table [ins->inst_i0->type] [ins->inst_i1->type];
1256 ins->opcode += ovfops_op_map [ins->inst_i0->type];
1259 g_error ("opcode 0x%04x not handled in type from op", ins->opcode);
1266 STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I8, STACK_MP, STACK_R8, STACK_R8, STACK_OBJ
1269 /* map ldelem.x to the matching ldind.x opcode */
1271 ldelem_to_ldind [] = {
1285 /* map stelem.x to the matching stind.x opcode */
1287 stelem_to_stind [] = {
1301 param_table [STACK_MAX] [STACK_MAX] = {
1306 check_values_to_signature (MonoInst *args, MonoType *this, MonoMethodSignature *sig) {
1310 switch (args->type) {
1320 for (i = 0; i < sig->param_count; ++i) {
1321 switch (args [i].type) {
1325 if (!sig->params [i]->byref)
1329 if (sig->params [i]->byref)
1331 switch (sig->params [i]->type) {
1332 case MONO_TYPE_CLASS:
1333 case MONO_TYPE_STRING:
1334 case MONO_TYPE_OBJECT:
1335 case MONO_TYPE_SZARRAY:
1336 case MONO_TYPE_ARRAY:
1343 if (sig->params [i]->byref)
1345 if (sig->params [i]->type != MONO_TYPE_R4 && sig->params [i]->type != MONO_TYPE_R8)
1354 /*if (!param_table [args [i].type] [sig->params [i]->type])
1362 * When we need a pointer to the current domain many times in a method, we
1363 * call mono_domain_get() once and we store the result in a local variable.
1364 * This function returns the variable that represents the MonoDomain*.
1366 inline static MonoInst *
1367 mono_get_domainvar (MonoCompile *cfg)
1369 if (!cfg->domainvar)
1370 cfg->domainvar = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1371 return cfg->domainvar;
1375 mono_compile_create_var (MonoCompile *cfg, MonoType *type, int opcode)
1378 int num = cfg->num_varinfo;
1380 if ((num + 1) >= cfg->varinfo_count) {
1381 cfg->varinfo_count = (cfg->varinfo_count + 2) * 2;
1382 cfg->varinfo = (MonoInst **)g_realloc (cfg->varinfo, sizeof (MonoInst*) * cfg->varinfo_count);
1383 cfg->vars = (MonoMethodVar **)g_realloc (cfg->vars, sizeof (MonoMethodVar*) * cfg->varinfo_count);
1386 /*g_print ("created temp %d of type 0x%x\n", num, type->type);*/
1387 mono_jit_stats.allocate_var++;
1389 MONO_INST_NEW (cfg, inst, opcode);
1390 inst->inst_c0 = num;
1391 inst->inst_vtype = type;
1392 inst->klass = mono_class_from_mono_type (type);
1393 /* if set to 1 the variable is native */
1396 cfg->varinfo [num] = inst;
1398 cfg->vars [num] = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoMethodVar));
1399 MONO_INIT_VARINFO (cfg->vars [num], num);
1402 //g_print ("created temp %d of type %s\n", num, mono_type_get_name (type));
1407 type_from_stack_type (MonoInst *ins) {
1408 switch (ins->type) {
1409 case STACK_I4: return &mono_defaults.int32_class->byval_arg;
1410 case STACK_I8: return &mono_defaults.int64_class->byval_arg;
1411 case STACK_PTR: return &mono_defaults.int_class->byval_arg;
1412 case STACK_R8: return &mono_defaults.double_class->byval_arg;
1413 case STACK_MP: return &mono_defaults.int_class->byval_arg;
1414 case STACK_OBJ: return &mono_defaults.object_class->byval_arg;
1415 case STACK_VTYPE: return &ins->klass->byval_arg;
1417 g_error ("stack type %d to montype not handled\n", ins->type);
1423 array_access_to_klass (int opcode)
1427 return mono_defaults.byte_class;
1429 return mono_defaults.uint16_class;
1432 return mono_defaults.int_class;
1435 return mono_defaults.sbyte_class;
1438 return mono_defaults.int16_class;
1441 return mono_defaults.int32_class;
1443 return mono_defaults.uint32_class;
1446 return mono_defaults.int64_class;
1449 return mono_defaults.single_class;
1452 return mono_defaults.double_class;
1453 case CEE_LDELEM_REF:
1454 case CEE_STELEM_REF:
1455 return mono_defaults.object_class;
1457 g_assert_not_reached ();
1463 mono_add_ins_to_end (MonoBasicBlock *bb, MonoInst *inst)
1467 MONO_ADD_INS (bb, inst);
1470 switch (bb->last_ins->opcode) {
1483 while (prev->next && prev->next != bb->last_ins)
1485 if (prev == bb->code) {
1486 if (bb->last_ins == bb->code) {
1487 inst->next = bb->code;
1490 inst->next = prev->next;
1494 inst->next = bb->last_ins;
1498 // g_warning ("handle conditional jump in add_ins_to_end ()\n");
1500 MONO_ADD_INS (bb, inst);
1506 mono_add_varcopy_to_end (MonoCompile *cfg, MonoBasicBlock *bb, int src, int dest)
1508 MonoInst *inst, *load;
1510 NEW_TEMPLOAD (cfg, load, src);
1512 NEW_TEMPSTORE (cfg, inst, dest, load);
1513 if (inst->opcode == CEE_STOBJ) {
1514 NEW_TEMPLOADA (cfg, inst, dest);
1515 handle_stobj (cfg, bb, inst, load, NULL, inst->klass, TRUE, FALSE);
1517 inst->cil_code = NULL;
1518 mono_add_ins_to_end (bb, inst);
1523 * We try to share variables when possible
1526 mono_compile_get_interface_var (MonoCompile *cfg, int slot, MonoInst *ins)
1531 /* inlining can result in deeper stacks */
1532 if (slot >= ((MonoMethodNormal *)cfg->method)->header->max_stack)
1533 return mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1535 pos = ins->type - 1 + slot * STACK_MAX;
1537 switch (ins->type) {
1544 if ((vnum = cfg->intvars [pos]))
1545 return cfg->varinfo [vnum];
1546 res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1547 cfg->intvars [pos] = res->inst_c0;
1550 res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1556 * This function is called to handle items that are left on the evaluation stack
1557 * at basic block boundaries. What happens is that we save the values to local variables
1558 * and we reload them later when first entering the target basic block (with the
1559 * handle_loaded_temps () function).
1560 * A single joint point will use the same variables (stored in the array bb->out_stack or
1561 * bb->in_stack, if the basic block is before or after the joint point).
1564 handle_stack_args (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst **sp, int count) {
1566 MonoBasicBlock *outb;
1567 MonoInst *inst, **locals;
1571 if (cfg->verbose_level > 3)
1572 g_print ("%d item(s) on exit from B%d\n", count, bb->block_num);
1573 if (!bb->out_scount) {
1575 bb->out_scount = count;
1576 //g_print ("bblock %d has out:", bb->block_num);
1577 for (i = 0; i < bb->out_count; ++i) {
1578 outb = bb->out_bb [i];
1579 //g_print (" %d", outb->block_num);
1580 if (outb->in_stack) {
1582 bb->out_stack = outb->in_stack;
1588 bb->out_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * count);
1589 for (i = 0; i < count; ++i) {
1591 /* try to reuse temps already allocated for this purpouse, if they occupy the same
1592 * stack slot and if they are of the same type. */
1593 bb->out_stack [i] = mono_compile_get_interface_var (cfg, i, sp [i]);
1595 bb->out_stack [i] = mono_compile_create_var (cfg, type_from_stack_type (sp [i]), OP_LOCAL);
1600 locals = bb->out_stack;
1601 for (i = 0; i < count; ++i) {
1602 /* add store ops at the end of the bb, before the branch */
1603 NEW_TEMPSTORE (cfg, inst, locals [i]->inst_c0, sp [i]);
1604 if (inst->opcode == CEE_STOBJ) {
1605 NEW_TEMPLOADA (cfg, inst, locals [i]->inst_c0);
1606 handle_stobj (cfg, bb, inst, sp [i], sp [i]->cil_code, inst->klass, TRUE, FALSE);
1608 inst->cil_code = sp [i]->cil_code;
1609 mono_add_ins_to_end (bb, inst);
1611 if (cfg->verbose_level > 3)
1612 g_print ("storing %d to temp %d\n", i, locals [i]->inst_c0);
1615 for (i = 0; i < bb->out_count; ++i) {
1616 outb = bb->out_bb [i];
1617 if (outb->in_scount)
1618 continue; /* check they are the same locals */
1619 outb->in_scount = count;
1620 outb->in_stack = locals;
1626 ret_type_to_call_opcode (MonoType *type, int calli, int virt)
1631 return calli? OP_CALL_REG: virt? CEE_CALLVIRT: CEE_CALL;
1635 case MONO_TYPE_VOID:
1636 return calli? OP_VOIDCALL_REG: virt? OP_VOIDCALLVIRT: OP_VOIDCALL;
1639 case MONO_TYPE_BOOLEAN:
1642 case MONO_TYPE_CHAR:
1645 return calli? OP_CALL_REG: virt? CEE_CALLVIRT: CEE_CALL;
1649 return calli? OP_CALL_REG: virt? CEE_CALLVIRT: CEE_CALL;
1650 case MONO_TYPE_CLASS:
1651 case MONO_TYPE_STRING:
1652 case MONO_TYPE_OBJECT:
1653 case MONO_TYPE_SZARRAY:
1654 case MONO_TYPE_ARRAY:
1655 return calli? OP_CALL_REG: virt? CEE_CALLVIRT: CEE_CALL;
1658 return calli? OP_LCALL_REG: virt? OP_LCALLVIRT: OP_LCALL;
1661 return calli? OP_FCALL_REG: virt? OP_FCALLVIRT: OP_FCALL;
1662 case MONO_TYPE_VALUETYPE:
1663 if (type->data.klass->enumtype) {
1664 t = type->data.klass->enum_basetype->type;
1667 return calli? OP_VCALL_REG: virt? OP_VCALLVIRT: OP_VCALL;
1668 case MONO_TYPE_TYPEDBYREF:
1669 return calli? OP_VCALL_REG: virt? OP_VCALLVIRT: OP_VCALL;
1671 g_error ("unknown type 0x%02x in ret_type_to_call_opcode", type->type);
1677 mono_create_jump_table (MonoCompile *cfg, MonoInst *label, MonoBasicBlock **bbs, int num_blocks)
1679 MonoJumpInfo *ji = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfo));
1681 ji->ip.label = label;
1682 ji->type = MONO_PATCH_INFO_SWITCH;
1683 ji->data.table = bbs;
1684 ji->next = cfg->patch_info;
1685 ji->table_size = num_blocks;
1686 cfg->patch_info = ji;
1690 * When we add a tree of instructions, we need to ensure the instructions currently
1691 * on the stack are executed before (like, if we load a value from a local).
1692 * We ensure this by saving the currently loaded values to temps and rewriting the
1693 * instructions to load the values.
1694 * This is not done for opcodes that terminate a basic block (because it's handled already
1695 * by handle_stack_args ()) and for opcodes that can't change values, like POP.
1698 handle_loaded_temps (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst **stack, MonoInst **sp)
1700 MonoInst *load, *store, *temp, *ins;
1702 while (stack < sp) {
1704 /* handle also other constants */
1705 if (ins->opcode != OP_ICONST) {
1706 temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1707 NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
1708 store->cil_code = ins->cil_code;
1709 if (store->opcode == CEE_STOBJ) {
1710 NEW_TEMPLOADA (cfg, store, temp->inst_c0);
1711 handle_stobj (cfg, bblock, store, ins, ins->cil_code, temp->klass, FALSE, FALSE);
1713 MONO_ADD_INS (bblock, store);
1714 NEW_TEMPLOAD (cfg, load, temp->inst_c0);
1715 load->cil_code = ins->cil_code;
1723 * Prepare arguments for passing to a function call.
1724 * Return a non-zero value if the arguments can't be passed to the given
1726 * The type checks are not yet complete and some conversions may need
1727 * casts on 32 or 64 bit architectures.
1730 check_call_signature (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args)
1735 if (args [0]->type != STACK_OBJ && args [0]->type != STACK_MP && args [0]->type != STACK_PTR)
1739 for (i = 0; i < sig->param_count; ++i) {
1740 if (sig->params [i]->byref) {
1742 * check the result of ldelema is only passed as an argument if the byref
1743 * type matches exactly the array element type.
1744 * FIXME: if the argument as been saved on the stack as part of the
1745 * interface variable code (the value was on the stack at a basic block boundary)
1746 * we need to add the check in that case, too.
1748 if (args [i]->opcode == CEE_LDELEMA) {
1750 MonoClass *exact_class = mono_class_from_mono_type (sig->params [i]);
1751 if (!exact_class->valuetype) {
1752 MONO_INST_NEW (cfg, check, OP_CHECK_ARRAY_TYPE);
1753 check->cil_code = args [i]->cil_code;
1754 check->klass = exact_class;
1755 check->inst_left = args [i]->inst_left;
1756 check->type = STACK_OBJ;
1757 args [i]->inst_left = check;
1760 if (args [i]->type != STACK_MP && args [i]->type != STACK_PTR)
1764 simple_type = sig->params [i]->type;
1766 switch (simple_type) {
1767 case MONO_TYPE_VOID:
1772 case MONO_TYPE_BOOLEAN:
1775 case MONO_TYPE_CHAR:
1778 if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR)
1784 if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR && args [i]->type != STACK_MP && args [i]->type != STACK_OBJ)
1787 case MONO_TYPE_CLASS:
1788 case MONO_TYPE_STRING:
1789 case MONO_TYPE_OBJECT:
1790 case MONO_TYPE_SZARRAY:
1791 case MONO_TYPE_ARRAY:
1792 if (args [i]->type != STACK_OBJ)
1797 if (args [i]->type != STACK_I8)
1802 if (args [i]->type != STACK_R8)
1805 case MONO_TYPE_VALUETYPE:
1806 if (sig->params [i]->data.klass->enumtype) {
1807 simple_type = sig->params [i]->data.klass->enum_basetype->type;
1810 if (args [i]->type != STACK_VTYPE)
1813 case MONO_TYPE_TYPEDBYREF:
1814 if (args [i]->type != STACK_VTYPE)
1817 case MONO_TYPE_GENERICINST:
1818 simple_type = sig->params [i]->data.generic_inst->generic_type->type;
1822 g_error ("unknown type 0x%02x in check_call_signature", simple_type);
1829 mono_spill_call (MonoCompile *cfg, MonoBasicBlock *bblock, MonoCallInst *call, MonoMethodSignature *sig, gboolean ret_object,
1830 const guint8 *ip, gboolean to_end)
1832 MonoInst *temp, *store, *ins = (MonoInst*)call;
1833 MonoType *ret = sig->ret;
1835 if (!MONO_TYPE_IS_VOID (ret) || ret_object) {
1837 call->inst.type = STACK_OBJ;
1838 call->inst.opcode = CEE_CALL;
1839 temp = mono_compile_create_var (cfg, &mono_defaults.string_class->byval_arg, OP_LOCAL);
1841 type_to_eval_stack_type (ret, ins);
1842 temp = mono_compile_create_var (cfg, ret, OP_LOCAL);
1845 if (MONO_TYPE_ISSTRUCT (ret)) {
1848 /* we use this to allocate native sized structs */
1849 temp->unused = sig->pinvoke;
1851 NEW_TEMPLOADA (cfg, loada, temp->inst_c0);
1852 if (call->inst.opcode == OP_VCALL)
1853 ins->inst_left = loada;
1855 ins->inst_right = loada; /* a virtual or indirect call */
1858 mono_add_ins_to_end (bblock, ins);
1860 MONO_ADD_INS (bblock, ins);
1862 NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
1863 store->cil_code = ip;
1865 mono_add_ins_to_end (bblock, store);
1867 MONO_ADD_INS (bblock, store);
1869 return temp->inst_c0;
1872 mono_add_ins_to_end (bblock, ins);
1874 MONO_ADD_INS (bblock, ins);
1879 inline static MonoCallInst *
1880 mono_emit_call_args (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethodSignature *sig,
1881 MonoInst **args, int calli, int virtual, const guint8 *ip, gboolean to_end)
1886 MONO_INST_NEW_CALL (cfg, call, ret_type_to_call_opcode (sig->ret, calli, virtual));
1888 call->inst.cil_code = ip;
1890 call->signature = sig;
1891 call = mono_arch_call_opcode (cfg, bblock, call, virtual);
1893 for (arg = call->out_args; arg;) {
1894 MonoInst *narg = arg->next;
1899 mono_add_ins_to_end (bblock, arg);
1901 MONO_ADD_INS (bblock, arg);
1908 mono_emit_calli (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethodSignature *sig,
1909 MonoInst **args, MonoInst *addr, const guint8 *ip)
1911 MonoCallInst *call = mono_emit_call_args (cfg, bblock, sig, args, TRUE, FALSE, ip, FALSE);
1913 call->inst.inst_i0 = addr;
1915 return mono_spill_call (cfg, bblock, call, sig, FALSE, ip, FALSE);
1918 static MonoCallInst*
1919 mono_emit_method_call (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *method, MonoMethodSignature *sig,
1920 MonoInst **args, const guint8 *ip, MonoInst *this)
1922 gboolean virtual = this != NULL;
1925 call = mono_emit_call_args (cfg, bblock, sig, args, FALSE, virtual, ip, FALSE);
1927 if (this && sig->hasthis &&
1928 (method->klass->marshalbyref || method->klass == mono_defaults.object_class) &&
1929 !(method->flags & METHOD_ATTRIBUTE_VIRTUAL) && !MONO_CHECK_THIS (this)) {
1930 call->method = mono_marshal_get_remoting_invoke_with_check (method);
1932 call->method = method;
1934 call->inst.flags |= MONO_INST_HAS_METHOD;
1935 call->inst.inst_left = this;
1941 mono_emit_method_call_spilled (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *method,
1942 MonoMethodSignature *signature, MonoInst **args, const guint8 *ip, MonoInst *this)
1944 MonoCallInst *call = mono_emit_method_call (cfg, bblock, method, signature, args, ip, this);
1946 return mono_spill_call (cfg, bblock, call, signature, method->string_ctor, ip, FALSE);
1950 mono_emit_native_call (MonoCompile *cfg, MonoBasicBlock *bblock, gconstpointer func, MonoMethodSignature *sig,
1951 MonoInst **args, const guint8 *ip, gboolean to_end)
1957 call = mono_emit_call_args (cfg, bblock, sig, args, FALSE, FALSE, ip, to_end);
1959 return mono_spill_call (cfg, bblock, call, sig, func == mono_array_new_va, ip, to_end);
1963 mono_emit_jit_icall (MonoCompile *cfg, MonoBasicBlock *bblock, gconstpointer func, MonoInst **args, const guint8 *ip)
1965 MonoJitICallInfo *info = mono_find_jit_icall_by_addr (func);
1968 g_warning ("unregistered JIT ICall");
1969 g_assert_not_reached ();
1972 return mono_emit_native_call (cfg, bblock, info->wrapper, info->sig, args, ip, FALSE);
1976 mono_emulate_opcode (MonoCompile *cfg, MonoInst *tree, MonoInst **iargs, MonoJitICallInfo *info)
1978 MonoInst *ins, *temp = NULL, *store, *load, *begin;
1979 MonoInst *last_arg = NULL;
1983 //g_print ("emulating: ");
1984 //mono_print_tree_nl (tree);
1985 MONO_INST_NEW_CALL (cfg, call, ret_type_to_call_opcode (info->sig->ret, FALSE, FALSE));
1986 ins = (MonoInst*)call;
1988 call->inst.cil_code = tree->cil_code;
1990 call->signature = info->sig;
1992 call = mono_arch_call_opcode (cfg, cfg->cbb, call, FALSE);
1994 if (!MONO_TYPE_IS_VOID (info->sig->ret)) {
1995 temp = mono_compile_create_var (cfg, info->sig->ret, OP_LOCAL);
1996 NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
1997 store->cil_code = tree->cil_code;
2002 nargs = info->sig->param_count + info->sig->hasthis;
2004 for (last_arg = call->out_args; last_arg && last_arg->next; last_arg = last_arg->next) ;
2007 last_arg->next = store;
2010 begin = call->out_args;
2014 if (cfg->prev_ins) {
2016 * This assumes that that in a tree, emulate_opcode is called for a
2017 * node before it is called for its children. dec_foreach needs to
2018 * take this into account.
2020 store->next = cfg->prev_ins->next;
2021 cfg->prev_ins->next = begin;
2023 store->next = cfg->cbb->code;
2024 cfg->cbb->code = begin;
2027 call->fptr = info->wrapper;
2029 if (!MONO_TYPE_IS_VOID (info->sig->ret)) {
2030 NEW_TEMPLOAD (cfg, load, temp->inst_c0);
2035 static MonoMethodSignature *
2036 mono_get_element_address_signature (int arity)
2038 static GHashTable *sighash = NULL;
2039 MonoMethodSignature *res;
2043 sighash = g_hash_table_new (NULL, NULL);
2046 if ((res = g_hash_table_lookup (sighash, (gpointer)arity)))
2049 res = mono_metadata_signature_alloc (mono_defaults.corlib, arity + 1);
2051 res->params [0] = &mono_defaults.array_class->byval_arg;
2053 for (i = 1; i <= arity; i++)
2054 res->params [i] = &mono_defaults.int_class->byval_arg;
2056 res->ret = &mono_defaults.int_class->byval_arg;
2058 g_hash_table_insert (sighash, (gpointer)arity, res);
2064 handle_stobj (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *dest, MonoInst *src, const unsigned char *ip, MonoClass *klass, gboolean to_end, gboolean native) {
2065 MonoInst *iargs [3];
2071 * This check breaks with spilled vars... need to handle it during verification anyway.
2072 * g_assert (klass && klass == src->klass && klass == dest->klass);
2076 n = mono_class_native_size (klass, &align);
2078 n = mono_class_value_size (klass, &align);
2080 if ((cfg->opt & MONO_OPT_INTRINS) && !to_end && n <= sizeof (gpointer) * 5) {
2082 MONO_INST_NEW (cfg, inst, OP_MEMCPY);
2083 inst->inst_left = dest;
2084 inst->inst_right = src;
2085 inst->cil_code = ip;
2087 MONO_ADD_INS (bblock, inst);
2092 NEW_ICONST (cfg, iargs [2], n);
2094 mono_emit_native_call (cfg, bblock, helper_memcpy, helper_sig_memcpy, iargs, ip, to_end);
2098 handle_initobj (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *dest, const guchar *ip, MonoClass *klass, MonoInst **stack_start, MonoInst **sp)
2100 MonoInst *iargs [2];
2101 MonoInst *ins, *zero_int32;
2104 NEW_ICONST (cfg, zero_int32, 0);
2106 mono_class_init (klass);
2107 n = mono_class_value_size (klass, NULL);
2108 MONO_INST_NEW (cfg, ins, 0);
2110 ins->inst_left = dest;
2111 ins->inst_right = zero_int32;
2114 ins->opcode = CEE_STIND_I1;
2115 MONO_ADD_INS (bblock, ins);
2118 ins->opcode = CEE_STIND_I2;
2119 MONO_ADD_INS (bblock, ins);
2122 ins->opcode = CEE_STIND_I4;
2123 MONO_ADD_INS (bblock, ins);
2126 if (n <= sizeof (gpointer) * 5) {
2127 ins->opcode = OP_MEMSET;
2130 MONO_ADD_INS (bblock, ins);
2133 handle_loaded_temps (cfg, bblock, stack_start, sp);
2134 NEW_ICONST (cfg, ins, n);
2137 mono_emit_jit_icall (cfg, bblock, helper_initobj, iargs, ip);
2142 #define CODE_IS_STLOC(ip) (((ip) [0] >= CEE_STLOC_0 && (ip) [0] <= CEE_STLOC_3) || ((ip) [0] == CEE_STLOC_S))
2145 mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method)
2147 MonoMethodHeader *header = ((MonoMethodNormal *)method)->header;
2148 MonoMethodSignature *signature = method->signature;
2152 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
2153 (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
2154 (method->iflags & METHOD_IMPL_ATTRIBUTE_NOINLINING) ||
2155 (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) ||
2156 (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
2157 (method->klass->marshalbyref) ||
2158 !header || header->num_clauses ||
2159 /* fixme: why cant we inline valuetype returns? */
2160 MONO_TYPE_ISSTRUCT (signature->ret))
2163 /* its not worth to inline methods with valuetype arguments?? */
2164 for (i = 0; i < signature->param_count; i++) {
2165 if (MONO_TYPE_ISSTRUCT (signature->params [i])) {
2171 * if we can initialize the class of the method right away, we do,
2172 * otherwise we don't allow inlining if the class needs initialization,
2173 * since it would mean inserting a call to mono_runtime_class_init()
2174 * inside the inlined code
2176 if (!(cfg->opt & MONO_OPT_SHARED)) {
2177 vtable = mono_class_vtable (cfg->domain, method->klass);
2178 if (method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT)
2179 mono_runtime_class_init (vtable);
2180 else if (!vtable->initialized && mono_class_needs_cctor_run (method->klass, NULL))
2184 * If we're compiling for shared code
2185 * the cctor will need to be run at aot method load time, for example,
2186 * or at the end of the compilation of the inlining method.
2188 if (mono_class_needs_cctor_run (method->klass, NULL) && !((method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT)))
2191 //if (!MONO_TYPE_IS_VOID (signature->ret)) return FALSE;
2193 /* also consider num_locals? */
2194 if (getenv ("MONO_INLINELIMIT"))
2195 if (header->code_size < atoi (getenv ("MONO_INLINELIMIT"))) {
2199 if (header->code_size < 20)
2206 mini_get_ldelema_ins (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *cmethod, MonoInst **sp, unsigned char *ip, gboolean is_set)
2210 MonoMethodSignature *esig;
2212 rank = cmethod->signature->param_count - (is_set? 1: 0);
2214 * FIXME: handle TypeMismatch for set or use the slow path
2217 if (rank == 2 && (cfg->opt & MONO_OPT_INTRINS)) {
2219 NEW_GROUP (cfg, indexes, sp [1], sp [2]);
2220 MONO_INST_NEW (cfg, addr, OP_LDELEMA2D);
2221 addr->inst_left = sp [0];
2222 addr->inst_right = indexes;
2223 addr->cil_code = ip;
2224 addr->type = STACK_MP;
2225 addr->klass = cmethod->klass;
2228 esig = mono_get_element_address_signature (rank);
2229 temp = mono_emit_native_call (cfg, bblock, ves_array_element_address, esig, sp, ip, FALSE);
2230 NEW_TEMPLOAD (cfg, addr, temp);
2235 mini_get_opcode_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
2240 if (cmethod->klass == mono_defaults.string_class) {
2241 if (cmethod->name [0] != 'g' || strcmp (cmethod->name, "get_Chars"))
2244 } else if (cmethod->klass == mono_defaults.math_class) {
2245 if (strcmp (cmethod->name, "Sin") == 0)
2247 else if (strcmp (cmethod->name, "Cos") == 0)
2249 else if (strcmp (cmethod->name, "Tan") == 0)
2251 else if (strcmp (cmethod->name, "Atan") == 0)
2253 else if (strcmp (cmethod->name, "Sqrt") == 0)
2255 else if (strcmp (cmethod->name, "Abs") == 0 && fsig->params [0]->type == MONO_TYPE_R8)
2258 /* OP_FREM is not IEEE compatible */
2259 else if (strcmp (cmethod->name, "IEEERemainder") == 0)
2264 } else if (cmethod->klass == mono_defaults.array_class) {
2265 if (strcmp (cmethod->name, "get_Rank") == 0)
2267 else if (strcmp (cmethod->name, "get_Length") == 0)
2274 pc = fsig->param_count + fsig->hasthis;
2275 MONO_INST_NEW (cfg, ins, op);
2278 ins->inst_i0 = args [0];
2280 ins->inst_i1 = args [1];
2287 mono_save_args (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethodSignature *sig, MonoInst **sp, MonoInst **args)
2289 MonoInst *store, *temp;
2292 g_assert (!MONO_TYPE_ISSTRUCT (sig->ret));
2294 if (!sig->hasthis && sig->param_count == 0)
2298 if (sp [0]->opcode == OP_ICONST) {
2301 temp = mono_compile_create_var (cfg, type_from_stack_type (*sp), OP_LOCAL);
2303 NEW_TEMPSTORE (cfg, store, temp->inst_c0, *sp);
2304 store->cil_code = sp [0]->cil_code;
2305 MONO_ADD_INS (bblock, store);
2310 for (i = 0; i < sig->param_count; ++i) {
2311 if (sp [0]->opcode == OP_ICONST) {
2314 temp = mono_compile_create_var (cfg, sig->params [i], OP_LOCAL);
2316 NEW_TEMPSTORE (cfg, store, temp->inst_c0, *sp);
2317 store->cil_code = sp [0]->cil_code;
2318 if (store->opcode == CEE_STOBJ) {
2319 NEW_TEMPLOADA (cfg, store, temp->inst_c0);
2320 handle_stobj (cfg, bblock, store, *sp, sp [0]->cil_code, temp->klass, FALSE, FALSE);
2322 MONO_ADD_INS (bblock, store);
2330 inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoBasicBlock *bblock, MonoInst **sp,
2331 guchar *ip, guint real_offset, GList *dont_inline, MonoBasicBlock **last_b)
2333 MonoInst *ins, *rvar = NULL;
2334 MonoMethodHeader *cheader;
2335 MonoBasicBlock *ebblock, *sbblock;
2336 int i, costs, new_locals_offset;
2338 if (cfg->verbose_level > 2)
2339 g_print ("INLINE START %p %s -> %s\n", cmethod, mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
2341 cheader = ((MonoMethodNormal *)cmethod)->header;
2343 if (!cmethod->inline_info) {
2344 mono_jit_stats.inlineable_methods++;
2345 cmethod->inline_info = 1;
2347 /* allocate space to store the return value */
2348 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
2349 rvar = mono_compile_create_var (cfg, fsig->ret, OP_LOCAL);
2352 /* allocate local variables */
2353 new_locals_offset = cfg->num_varinfo;
2354 for (i = 0; i < cheader->num_locals; ++i)
2355 mono_compile_create_var (cfg, cheader->locals [i], OP_LOCAL);
2357 /* allocate starte and end blocks */
2358 sbblock = NEW_BBLOCK (cfg);
2359 sbblock->block_num = cfg->num_bblocks++;
2360 sbblock->real_offset = real_offset;
2362 ebblock = NEW_BBLOCK (cfg);
2363 ebblock->block_num = cfg->num_bblocks++;
2364 ebblock->real_offset = real_offset;
2366 costs = mono_method_to_ir (cfg, cmethod, sbblock, ebblock, new_locals_offset, rvar, dont_inline, sp, real_offset, *ip == CEE_CALLVIRT);
2368 if (costs >= 0 && costs < 60) {
2369 if (cfg->verbose_level > 2)
2370 g_print ("INLINE END %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
2372 mono_jit_stats.inlined_methods++;
2374 /* always add some code to avoid block split failures */
2375 MONO_INST_NEW (cfg, ins, CEE_NOP);
2376 MONO_ADD_INS (bblock, ins);
2379 bblock->next_bb = sbblock;
2380 link_bblock (cfg, bblock, sbblock);
2383 NEW_TEMPLOAD (cfg, ins, rvar->inst_c0);
2389 if (cfg->verbose_level > 2)
2390 g_print ("INLINE ABORTED %s\n", mono_method_full_name (cmethod, TRUE));
2396 * Some of these comments may well be out-of-date.
2397 * Design decisions: we do a single pass over the IL code (and we do bblock
2398 * splitting/merging in the few cases when it's required: a back jump to an IL
2399 * address that was not already seen as bblock starting point).
2400 * Code is validated as we go (full verification is still better left to metadata/verify.c).
2401 * Complex operations are decomposed in simpler ones right away. We need to let the
2402 * arch-specific code peek and poke inside this process somehow (except when the
2403 * optimizations can take advantage of the full semantic info of coarse opcodes).
2404 * All the opcodes of the form opcode.s are 'normalized' to opcode.
2405 * MonoInst->opcode initially is the IL opcode or some simplification of that
2406 * (OP_LOAD, OP_STORE). The arch-specific code may rearrange it to an arch-specific
2407 * opcode with value bigger than OP_LAST.
2408 * At this point the IR can be handed over to an interpreter, a dumb code generator
2409 * or to the optimizing code generator that will translate it to SSA form.
2411 * Profiling directed optimizations.
2412 * We may compile by default with few or no optimizations and instrument the code
2413 * or the user may indicate what methods to optimize the most either in a config file
2414 * or through repeated runs where the compiler applies offline the optimizations to
2415 * each method and then decides if it was worth it.
2418 * * consider using an array instead of an hash table (bb_hash)
2421 #define CHECK_TYPE(ins) if (!(ins)->type) goto unverified
2422 #define CHECK_STACK(num) if ((sp - stack_start) < (num)) goto unverified
2423 #define CHECK_STACK_OVF(num) if (((sp - stack_start) + (num)) > header->max_stack) goto unverified
2425 #define TYPE_PARAM_TO_TYPE(num) (method->klass->generic_inst->data.generic_inst->type_argv [(num)])
2426 #define TYPE_PARAM_TO_CLASS(num) (mono_class_from_mono_type (TYPE_PARAM_TO_TYPE ((num))))
2428 /* offset from br.s -> br like opcodes */
2429 #define BIG_BRANCH_OFFSET 13
2432 get_basic_blocks (MonoCompile *cfg, GHashTable *bbhash, MonoMethodHeader* header, guint real_offset, unsigned char *start, unsigned char *end, unsigned char **pos)
2434 unsigned char *ip = start;
2435 unsigned char *target;
2438 MonoBasicBlock *bblock;
2439 const MonoOpcode *opcode;
2442 cli_addr = ip - start;
2443 i = mono_opcode_value ((const guint8 **)&ip);
2444 opcode = &mono_opcodes [i];
2445 switch (opcode->argument) {
2446 case MonoInlineNone:
2449 case MonoInlineString:
2450 case MonoInlineType:
2451 case MonoInlineField:
2452 case MonoInlineMethod:
2455 case MonoShortInlineR:
2462 case MonoShortInlineVar:
2463 case MonoShortInlineI:
2466 case MonoShortInlineBrTarget:
2467 target = start + cli_addr + 2 + (signed char)ip [1];
2468 GET_BBLOCK (cfg, bbhash, bblock, target);
2471 case MonoInlineBrTarget:
2472 target = start + cli_addr + 5 + (gint32)read32 (ip + 1);
2473 GET_BBLOCK (cfg, bbhash, bblock, target);
2476 case MonoInlineSwitch: {
2477 guint32 n = read32 (ip + 1);
2480 cli_addr += 5 + 4 * n;
2481 target = start + cli_addr;
2482 GET_BBLOCK (cfg, bbhash, bblock, target);
2484 for (j = 0; j < n; ++j) {
2485 target = start + cli_addr + (gint32)read32 (ip);
2486 GET_BBLOCK (cfg, bbhash, bblock, target);
2496 g_assert_not_reached ();
2505 static MonoClassField *
2506 get_generic_field_inst (MonoClassField *field, MonoClass *klass, MonoClass **retclass)
2509 for (i = 0; i < field->parent->field.count; ++i) {
2510 if (field == &field->parent->fields [i]) {
2512 return &klass->fields [i];
2519 * mono_method_to_ir: translates IL into basic blocks containing trees
2522 mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock,
2523 int locals_offset, MonoInst *return_var, GList *dont_inline, MonoInst **inline_args,
2524 guint inline_offset, gboolean is_virtual_call)
2526 MonoInst *zero_int32, *zero_int64, *zero_ptr, *zero_obj, *zero_r8;
2527 MonoInst *ins, **sp, **stack_start;
2528 MonoBasicBlock *bblock, *tblock = NULL, *init_localsbb = NULL;
2530 MonoMethod *cmethod;
2531 MonoInst **arg_array;
2532 MonoMethodHeader *header;
2534 guint32 token, ins_flag;
2536 unsigned char *ip, *end, *target, *err_pos;
2537 static double r8_0 = 0.0;
2538 MonoMethodSignature *sig;
2539 MonoType **param_types;
2540 GList *bb_recheck = NULL, *tmp;
2541 int i, n, start_new_bblock, align;
2542 int num_calls = 0, inline_costs = 0;
2543 int *filter_lengths = NULL;
2544 int breakpoint_id = 0;
2547 image = method->klass->image;
2548 header = ((MonoMethodNormal *)method)->header;
2549 sig = method->signature;
2550 ip = (unsigned char*)header->code;
2551 end = ip + header->code_size;
2552 mono_jit_stats.cil_code_size += header->code_size;
2554 if (cfg->method == method) {
2556 bbhash = cfg->bb_hash;
2558 real_offset = inline_offset;
2559 bbhash = g_hash_table_new (g_direct_hash, NULL);
2562 if (cfg->verbose_level > 2)
2563 g_print ("method to IR %s\n", mono_method_full_name (method, TRUE));
2565 if (cfg->prof_options & MONO_PROFILE_INS_COVERAGE)
2566 cfg->coverage_info = mono_profiler_coverage_alloc (cfg->method, header->code_size);
2568 dont_inline = g_list_prepend (dont_inline, method);
2569 if (cfg->method == method) {
2572 cfg->bb_entry = start_bblock = NEW_BBLOCK (cfg);
2573 start_bblock->cil_code = NULL;
2574 start_bblock->cil_length = 0;
2575 start_bblock->block_num = cfg->num_bblocks++;
2578 cfg->bb_exit = end_bblock = NEW_BBLOCK (cfg);
2579 end_bblock->cil_code = NULL;
2580 end_bblock->cil_length = 0;
2581 end_bblock->block_num = cfg->num_bblocks++;
2582 g_assert (cfg->num_bblocks == 2);
2584 arg_array = alloca (sizeof (MonoInst *) * (sig->hasthis + sig->param_count));
2585 for (i = sig->hasthis + sig->param_count - 1; i >= 0; i--)
2586 arg_array [i] = cfg->varinfo [i];
2588 if (header->num_clauses) {
2589 int size = sizeof (int) * header->num_clauses;
2590 filter_lengths = alloca (size);
2591 memset (filter_lengths, 0, size);
2593 cfg->spvars = g_hash_table_new (NULL, NULL);
2595 /* handle exception clauses */
2596 for (i = 0; i < header->num_clauses; ++i) {
2597 //unsigned char *p = ip;
2598 MonoExceptionClause *clause = &header->clauses [i];
2599 GET_BBLOCK (cfg, bbhash, tblock, ip + clause->try_offset);
2600 tblock->real_offset = clause->try_offset;
2601 GET_BBLOCK (cfg, bbhash, tblock, ip + clause->handler_offset);
2602 tblock->real_offset = clause->handler_offset;
2604 if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY ||
2605 clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
2606 MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
2607 MONO_ADD_INS (tblock, ins);
2610 /*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);
2612 g_print ("%s", mono_disasm_code_one (NULL, method, p, &p));
2614 /* catch and filter blocks get the exception object on the stack */
2615 if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE ||
2616 clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
2617 /* mostly like handle_stack_args (), but just sets the input args */
2618 /* g_print ("handling clause at IL_%04x\n", clause->handler_offset); */
2620 cfg->exvar = mono_compile_create_var (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL);
2621 /* prevent it from being register allocated */
2622 cfg->exvar->flags |= MONO_INST_INDIRECT;
2624 tblock->in_scount = 1;
2625 tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
2626 tblock->in_stack [0] = cfg->exvar;
2628 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
2629 GET_BBLOCK (cfg, bbhash, tblock, ip + clause->token_or_filter);
2630 tblock->real_offset = clause->token_or_filter;
2631 tblock->in_scount = 1;
2632 tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
2633 tblock->in_stack [0] = cfg->exvar;
2634 MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
2635 MONO_ADD_INS (tblock, ins);
2641 arg_array = alloca (sizeof (MonoInst *) * (sig->hasthis + sig->param_count));
2642 mono_save_args (cfg, start_bblock, sig, inline_args, arg_array);
2645 /* FIRST CODE BLOCK */
2646 bblock = NEW_BBLOCK (cfg);
2647 bblock->cil_code = ip;
2649 ADD_BBLOCK (cfg, bbhash, bblock);
2651 if (cfg->method == method) {
2652 breakpoint_id = mono_debugger_method_has_breakpoint (method);
2653 if (breakpoint_id && (mono_debug_format != MONO_DEBUG_FORMAT_DEBUGGER)) {
2654 MONO_INST_NEW (cfg, ins, CEE_BREAK);
2655 MONO_ADD_INS (bblock, ins);
2659 if ((header->init_locals || (cfg->method == method && (cfg->opt & MONO_OPT_SHARED))) || mono_compile_aot) {
2660 /* we use a separate basic block for the initialization code */
2661 cfg->bb_init = init_localsbb = NEW_BBLOCK (cfg);
2662 init_localsbb->real_offset = real_offset;
2663 start_bblock->next_bb = init_localsbb;
2664 init_localsbb->next_bb = bblock;
2665 link_bblock (cfg, start_bblock, init_localsbb);
2666 link_bblock (cfg, init_localsbb, bblock);
2667 init_localsbb->block_num = cfg->num_bblocks++;
2669 start_bblock->next_bb = bblock;
2670 link_bblock (cfg, start_bblock, bblock);
2673 if (get_basic_blocks (cfg, bbhash, header, real_offset, ip, end, &err_pos)) {
2678 mono_debug_init_method (cfg, bblock, breakpoint_id);
2680 param_types = mono_mempool_alloc (cfg->mempool, sizeof (MonoType*) * (sig->hasthis + sig->param_count));
2682 param_types [0] = method->klass->valuetype?&method->klass->this_arg:&method->klass->byval_arg;
2683 for (n = 0; n < sig->param_count; ++n)
2684 param_types [n + sig->hasthis] = sig->params [n];
2686 /* do this somewhere outside - not here */
2687 NEW_ICONST (cfg, zero_int32, 0);
2688 NEW_ICONST (cfg, zero_int64, 0);
2689 zero_int64->type = STACK_I8;
2690 NEW_PCONST (cfg, zero_ptr, 0);
2691 NEW_PCONST (cfg, zero_obj, 0);
2692 zero_obj->type = STACK_OBJ;
2694 MONO_INST_NEW (cfg, zero_r8, OP_R8CONST);
2695 zero_r8->type = STACK_R8;
2696 zero_r8->inst_p0 = &r8_0;
2698 /* add a check for this != NULL to inlined methods */
2699 if (is_virtual_call) {
2700 MONO_INST_NEW (cfg, ins, OP_CHECK_THIS);
2701 NEW_ARGLOAD (cfg, ins->inst_left, 0);
2703 MONO_ADD_INS (bblock, ins);
2706 /* we use a spare stack slot in SWITCH and NEWOBJ and others */
2707 stack_start = sp = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * (header->max_stack + 1));
2710 start_new_bblock = 0;
2713 if (cfg->method == method)
2714 real_offset = ip - header->code;
2716 real_offset = inline_offset;
2718 if (start_new_bblock) {
2719 bblock->cil_length = ip - bblock->cil_code;
2720 if (start_new_bblock == 2) {
2721 g_assert (ip == tblock->cil_code);
2723 GET_BBLOCK (cfg, bbhash, tblock, ip);
2725 bblock->next_bb = tblock;
2727 start_new_bblock = 0;
2728 for (i = 0; i < bblock->in_scount; ++i) {
2729 NEW_TEMPLOAD (cfg, ins, bblock->in_stack [i]->inst_c0);
2733 if ((tblock = g_hash_table_lookup (bbhash, ip)) && (tblock != bblock)) {
2734 link_bblock (cfg, bblock, tblock);
2735 if (sp != stack_start) {
2736 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
2739 bblock->next_bb = tblock;
2741 for (i = 0; i < bblock->in_scount; ++i) {
2742 NEW_TEMPLOAD (cfg, ins, bblock->in_stack [i]->inst_c0);
2748 if (cfg->coverage_info) {
2749 MonoInst *store, *one;
2750 guint32 cil_offset = ip - header->code;
2751 cfg->coverage_info->data [cil_offset].cil_code = ip;
2753 /* TODO: Use an increment here */
2754 NEW_ICONST (cfg, one, 1);
2757 NEW_PCONST (cfg, ins, &(cfg->coverage_info->data [cil_offset].count));
2760 MONO_INST_NEW (cfg, store, CEE_STIND_I);
2761 store->cil_code = ip;
2762 store->inst_left = ins;
2763 store->inst_right = one;
2765 MONO_ADD_INS (bblock, store);
2768 if (cfg->verbose_level > 3)
2769 g_print ("converting (in B%d: stack: %d) %s", bblock->block_num, sp-stack_start, mono_disasm_code_one (NULL, method, ip, NULL));
2776 MONO_INST_NEW (cfg, ins, CEE_BREAK);
2777 ins->cil_code = ip++;
2778 MONO_ADD_INS (bblock, ins);
2784 CHECK_STACK_OVF (1);
2785 n = (*ip)-CEE_LDARG_0;
2786 NEW_ARGLOAD (cfg, ins, n);
2787 ins->cil_code = ip++;
2794 CHECK_STACK_OVF (1);
2795 n = (*ip)-CEE_LDLOC_0;
2796 NEW_LOCLOAD (cfg, ins, n);
2797 ins->cil_code = ip++;
2805 n = (*ip)-CEE_STLOC_0;
2807 handle_loaded_temps (cfg, bblock, stack_start, sp);
2808 NEW_LOCSTORE (cfg, ins, n, *sp);
2810 if (ins->opcode == CEE_STOBJ) {
2811 NEW_LOCLOADA (cfg, ins, n);
2812 handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE);
2814 MONO_ADD_INS (bblock, ins);
2819 CHECK_STACK_OVF (1);
2820 NEW_ARGLOAD (cfg, ins, ip [1]);
2826 CHECK_STACK_OVF (1);
2827 NEW_ARGLOADA (cfg, ins, ip [1]);
2835 NEW_ARGSTORE (cfg, ins, ip [1], *sp);
2836 handle_loaded_temps (cfg, bblock, stack_start, sp);
2838 if (ins->opcode == CEE_STOBJ) {
2839 NEW_ARGLOADA (cfg, ins, ip [1]);
2840 handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE);
2842 MONO_ADD_INS (bblock, ins);
2846 CHECK_STACK_OVF (1);
2847 NEW_LOCLOAD (cfg, ins, ip [1]);
2853 CHECK_STACK_OVF (1);
2854 NEW_LOCLOADA (cfg, ins, ip [1]);
2862 handle_loaded_temps (cfg, bblock, stack_start, sp);
2863 NEW_LOCSTORE (cfg, ins, ip [1], *sp);
2865 if (ins->opcode == CEE_STOBJ) {
2866 NEW_LOCLOADA (cfg, ins, ip [1]);
2867 handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE);
2869 MONO_ADD_INS (bblock, ins);
2874 CHECK_STACK_OVF (1);
2875 NEW_PCONST (cfg, ins, NULL);
2877 ins->type = STACK_OBJ;
2882 CHECK_STACK_OVF (1);
2883 NEW_ICONST (cfg, ins, -1);
2897 CHECK_STACK_OVF (1);
2898 NEW_ICONST (cfg, ins, (*ip) - CEE_LDC_I4_0);
2904 CHECK_STACK_OVF (1);
2906 NEW_ICONST (cfg, ins, *((signed char*)ip));
2912 CHECK_STACK_OVF (1);
2913 NEW_ICONST (cfg, ins, (gint32)read32 (ip + 1));
2919 CHECK_STACK_OVF (1);
2920 MONO_INST_NEW (cfg, ins, OP_I8CONST);
2922 ins->type = STACK_I8;
2924 ins->inst_l = (gint64)read64 (ip);
2929 float *f = g_malloc (sizeof (float));
2930 CHECK_STACK_OVF (1);
2931 MONO_INST_NEW (cfg, ins, OP_R4CONST);
2932 ins->type = STACK_R8;
2941 double *d = g_malloc (sizeof (double));
2942 CHECK_STACK_OVF (1);
2943 MONO_INST_NEW (cfg, ins, OP_R8CONST);
2944 ins->type = STACK_R8;
2953 MonoInst *temp, *store;
2955 CHECK_STACK_OVF (1);
2960 * small optimization: if the loaded value was from a local already,
2961 * just load it twice.
2963 if (ins->ssa_op == MONO_SSA_LOAD &&
2964 (ins->inst_i0->opcode == OP_LOCAL || ins->inst_i0->opcode == OP_ARG)) {
2966 MONO_INST_NEW (cfg, temp, 0);
2968 temp->cil_code = ip;
2971 temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
2972 temp->cil_code = ip;
2973 NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
2974 store->cil_code = ip;
2975 MONO_ADD_INS (bblock, store);
2976 NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
2979 NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
2989 MONO_INST_NEW (cfg, ins, CEE_POP);
2990 MONO_ADD_INS (bblock, ins);
2991 ins->cil_code = ip++;
2996 if (stack_start != sp)
2998 MONO_INST_NEW (cfg, ins, CEE_JMP);
2999 token = read32 (ip + 1);
3000 /* FIXME: check the signature matches */
3001 cmethod = mono_get_method (image, token, NULL);
3002 ins->inst_p0 = cmethod;
3003 MONO_ADD_INS (bblock, ins);
3005 start_new_bblock = 1;
3009 case CEE_CALLVIRT: {
3010 MonoInst *addr = NULL;
3011 MonoMethodSignature *fsig = NULL;
3012 int temp, array_rank = 0;
3013 int virtual = *ip == CEE_CALLVIRT;
3015 token = read32 (ip + 1);
3017 if (*ip == CEE_CALLI) {
3022 if (method->wrapper_type != MONO_WRAPPER_NONE)
3023 fsig = (MonoMethodSignature *)mono_method_get_wrapper_data (method, token);
3025 fsig = mono_metadata_parse_signature (image, token);
3027 n = fsig->param_count + fsig->hasthis;
3030 if (method->wrapper_type != MONO_WRAPPER_NONE) {
3031 cmethod = (MonoMethod *)mono_method_get_wrapper_data (method, token);
3033 cmethod = mono_get_method (image, token, NULL);
3036 if (!cmethod->klass->inited)
3037 mono_class_init (cmethod->klass);
3039 if (cmethod->signature->pinvoke) {
3040 #ifdef MONO_USE_EXC_TABLES
3041 if (mono_method_blittable (cmethod)) {
3042 fsig = cmethod->signature;
3045 MonoMethod *wrapper = mono_marshal_get_native_wrapper (cmethod);
3046 fsig = wrapper->signature;
3047 #ifdef MONO_USE_EXC_TABLES
3051 fsig = mono_method_get_signature (cmethod, image, token);
3054 n = fsig->param_count + fsig->hasthis;
3056 if (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL &&
3057 cmethod->klass->parent == mono_defaults.array_class) {
3058 array_rank = cmethod->klass->rank;
3061 if (cmethod->string_ctor)
3062 g_assert_not_reached ();
3068 //g_assert (!virtual || fsig->hasthis);
3072 if (*ip != CEE_CALLI && check_call_signature (cfg, fsig, sp))
3075 if ((ins_flag & MONO_INST_TAILCALL) && cmethod && (*ip == CEE_CALL)) {
3077 for (i = 0; i < n; ++i) {
3078 NEW_ARGSTORE (cfg, ins, i, sp [i]);
3080 MONO_ADD_INS (bblock, ins);
3082 MONO_INST_NEW (cfg, ins, CEE_JMP);
3084 ins->inst_p0 = cmethod;
3085 MONO_ADD_INS (bblock, ins);
3086 start_new_bblock = 1;
3087 /* skip CEE_RET as well */
3092 if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_get_opcode_for_method (cfg, cmethod, fsig, sp))) {
3095 if (MONO_TYPE_IS_VOID (fsig->ret)) {
3096 MONO_ADD_INS (bblock, ins);
3098 type_to_eval_stack_type (fsig->ret, ins);
3107 handle_loaded_temps (cfg, bblock, stack_start, sp);
3109 if ((cfg->opt & MONO_OPT_INLINE) && cmethod &&
3110 (!virtual || !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) || (cmethod->flags & METHOD_ATTRIBUTE_FINAL)) &&
3111 mono_method_check_inlining (cfg, cmethod) &&
3112 !g_list_find (dont_inline, cmethod)) {
3114 MonoBasicBlock *ebblock;
3116 if ((costs = inline_method (cfg, cmethod, fsig, bblock, sp, ip, real_offset, dont_inline, &ebblock))) {
3120 GET_BBLOCK (cfg, bbhash, bblock, ip);
3121 ebblock->next_bb = bblock;
3122 link_bblock (cfg, ebblock, bblock);
3124 if (!MONO_TYPE_IS_VOID (fsig->ret))
3127 /* indicates start of a new block, and triggers a load of all
3128 stack arguments at bb boundarie */
3131 inline_costs += costs;
3136 inline_costs += 10 * num_calls++;
3138 /* tail recursion elimination */
3139 if ((cfg->opt & MONO_OPT_TAILC) && *ip == CEE_CALL && cmethod == method && ip [5] == CEE_RET) {
3140 gboolean has_vtargs = FALSE;
3143 /* keep it simple */
3144 for (i = fsig->param_count - 1; i >= 0; i--) {
3145 if (MONO_TYPE_ISSTRUCT (cmethod->signature->params [i]))
3150 for (i = 0; i < n; ++i) {
3151 NEW_ARGSTORE (cfg, ins, i, sp [i]);
3153 MONO_ADD_INS (bblock, ins);
3155 MONO_INST_NEW (cfg, ins, CEE_BR);
3157 MONO_ADD_INS (bblock, ins);
3158 tblock = start_bblock->out_bb [0];
3159 link_bblock (cfg, bblock, tblock);
3160 ins->inst_target_bb = tblock;
3161 start_new_bblock = 1;
3164 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
3165 /* just create a dummy - the value is never used */
3166 ins = mono_compile_create_var (cfg, fsig->ret, OP_LOCAL);
3167 NEW_TEMPLOAD (cfg, *sp, ins->inst_c0);
3175 if (*ip == CEE_CALLI) {
3177 if ((temp = mono_emit_calli (cfg, bblock, fsig, sp, addr, ip)) != -1) {
3178 NEW_TEMPLOAD (cfg, *sp, temp);
3182 } else if (array_rank) {
3185 if (strcmp (cmethod->name, "Set") == 0) { /* array Set */
3186 addr = mini_get_ldelema_ins (cfg, bblock, cmethod, sp, ip, TRUE);
3187 NEW_INDSTORE (cfg, ins, addr, sp [fsig->param_count], fsig->params [fsig->param_count - 1]);
3189 if (ins->opcode == CEE_STOBJ) {
3190 handle_stobj (cfg, bblock, addr, sp [fsig->param_count], ip, mono_class_from_mono_type (fsig->params [fsig->param_count-1]), FALSE, FALSE);
3192 MONO_ADD_INS (bblock, ins);
3195 } else if (strcmp (cmethod->name, "Get") == 0) { /* array Get */
3196 addr = mini_get_ldelema_ins (cfg, bblock, cmethod, sp, ip, FALSE);
3197 NEW_INDLOAD (cfg, ins, addr, fsig->ret);
3201 } else if (strcmp (cmethod->name, "Address") == 0) { /* array Address */
3202 addr = mini_get_ldelema_ins (cfg, bblock, cmethod, sp, ip, FALSE);
3205 g_assert_not_reached ();
3209 if (0 && CODE_IS_STLOC (ip + 5) && (!MONO_TYPE_ISSTRUCT (fsig->ret)) && (!MONO_TYPE_IS_VOID (fsig->ret) || cmethod->string_ctor)) {
3210 /* no need to spill */
3211 ins = (MonoInst*)mono_emit_method_call (cfg, bblock, cmethod, fsig, sp, ip, virtual ? sp [0] : NULL);
3214 if ((temp = mono_emit_method_call_spilled (cfg, bblock, cmethod, fsig, sp, ip, virtual ? sp [0] : NULL)) != -1) {
3215 NEW_TEMPLOAD (cfg, *sp, temp);
3225 if (cfg->method != method) {
3226 /* return from inlined methode */
3231 //g_assert (returnvar != -1);
3232 NEW_TEMPSTORE (cfg, store, return_var->inst_c0, *sp);
3233 store->cil_code = sp [0]->cil_code;
3234 if (store->opcode == CEE_STOBJ) {
3235 g_assert_not_reached ();
3236 NEW_TEMPLOADA (cfg, store, return_var->inst_c0);
3237 handle_stobj (cfg, bblock, store, *sp, sp [0]->cil_code, return_var->klass, FALSE, FALSE);
3239 MONO_ADD_INS (bblock, store);
3243 g_assert (!return_var);
3246 MONO_INST_NEW (cfg, ins, CEE_NOP);
3247 ins->opcode = mono_type_to_stind (method->signature->ret);
3248 if (ins->opcode == CEE_STOBJ) {
3249 NEW_RETLOADA (cfg, ins);
3250 handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE);
3252 ins->opcode = OP_SETRET;
3254 ins->inst_i0 = *sp;;
3255 ins->inst_i1 = NULL;
3256 MONO_ADD_INS (bblock, ins);
3260 if (sp != stack_start)
3262 MONO_INST_NEW (cfg, ins, CEE_BR);
3263 ins->cil_code = ip++;
3264 ins->inst_target_bb = end_bblock;
3265 MONO_ADD_INS (bblock, ins);
3266 link_bblock (cfg, bblock, end_bblock);
3267 start_new_bblock = 1;
3270 MONO_INST_NEW (cfg, ins, CEE_BR);
3271 ins->cil_code = ip++;
3272 MONO_ADD_INS (bblock, ins);
3273 target = ip + 1 + (signed char)(*ip);
3275 GET_BBLOCK (cfg, bbhash, tblock, target);
3276 link_bblock (cfg, bblock, tblock);
3277 CHECK_BBLOCK (target, ip, tblock);
3278 ins->inst_target_bb = tblock;
3279 if (sp != stack_start) {
3280 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
3283 start_new_bblock = 1;
3289 MONO_INST_NEW (cfg, ins, *ip + BIG_BRANCH_OFFSET);
3290 ins->cil_code = ip++;
3291 target = ip + 1 + *(signed char*)ip;
3293 ADD_UNCOND (ins->opcode == CEE_BRTRUE);
3294 if (sp != stack_start) {
3295 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
3311 MONO_INST_NEW (cfg, ins, *ip + BIG_BRANCH_OFFSET);
3312 ins->cil_code = ip++;
3313 target = ip + 1 + *(signed char*)ip;
3316 if (sp != stack_start) {
3317 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
3323 MONO_INST_NEW (cfg, ins, CEE_BR);
3324 ins->cil_code = ip++;
3325 MONO_ADD_INS (bblock, ins);
3326 target = ip + 4 + (gint32)read32(ip);
3328 GET_BBLOCK (cfg, bbhash, tblock, target);
3329 link_bblock (cfg, bblock, tblock);
3330 CHECK_BBLOCK (target, ip, tblock);
3331 ins->inst_target_bb = tblock;
3332 if (sp != stack_start) {
3333 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
3336 start_new_bblock = 1;
3342 MONO_INST_NEW (cfg, ins, *ip);
3343 ins->cil_code = ip++;
3344 target = ip + 4 + (gint32)read32(ip);
3346 ADD_UNCOND(ins->opcode == CEE_BRTRUE);
3347 if (sp != stack_start) {
3348 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
3364 MONO_INST_NEW (cfg, ins, *ip);
3365 ins->cil_code = ip++;
3366 target = ip + 4 + (gint32)read32(ip);
3369 if (sp != stack_start) {
3370 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
3377 n = read32 (ip + 1);
3378 MONO_INST_NEW (cfg, ins, *ip);
3380 ins->inst_left = *sp;
3381 if (ins->inst_left->type != STACK_I4) goto unverified;
3384 target = ip + n * sizeof (guint32);
3385 MONO_ADD_INS (bblock, ins);
3386 GET_BBLOCK (cfg, bbhash, tblock, target);
3387 link_bblock (cfg, bblock, tblock);
3388 ins->klass = GUINT_TO_POINTER (n);
3389 ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * (n + 1));
3390 ins->inst_many_bb [n] = tblock;
3392 for (i = 0; i < n; ++i) {
3393 GET_BBLOCK (cfg, bbhash, tblock, target + (gint32)read32(ip));
3394 link_bblock (cfg, bblock, tblock);
3395 ins->inst_many_bb [i] = tblock;
3398 /* FIXME: handle stack args */
3413 MONO_INST_NEW (cfg, ins, *ip);
3418 ins->type = ldind_type [*ip - CEE_LDIND_I1];
3419 ins->flags |= ins_flag;
3431 MONO_INST_NEW (cfg, ins, *ip);
3432 ins->cil_code = ip++;
3434 handle_loaded_temps (cfg, bblock, stack_start, sp);
3435 MONO_ADD_INS (bblock, ins);
3436 ins->inst_i0 = sp [0];
3437 ins->inst_i1 = sp [1];
3438 ins->flags |= ins_flag;
3469 case CEE_CONV_OVF_I8:
3470 case CEE_CONV_OVF_U8:
3476 case CEE_CONV_OVF_I4:
3477 case CEE_CONV_OVF_I1:
3478 case CEE_CONV_OVF_I2:
3479 case CEE_CONV_OVF_I:
3480 case CEE_CONV_OVF_U:
3483 if (sp [-1]->type == STACK_R8) {
3484 ADD_UNOP (CEE_CONV_OVF_I8);
3492 case CEE_CONV_OVF_U1:
3493 case CEE_CONV_OVF_U2:
3494 case CEE_CONV_OVF_U4:
3497 if (sp [-1]->type == STACK_R8) {
3498 ADD_UNOP (CEE_CONV_OVF_U8);
3506 case CEE_CONV_OVF_I1_UN:
3507 case CEE_CONV_OVF_I2_UN:
3508 case CEE_CONV_OVF_I4_UN:
3509 case CEE_CONV_OVF_I8_UN:
3510 case CEE_CONV_OVF_U1_UN:
3511 case CEE_CONV_OVF_U2_UN:
3512 case CEE_CONV_OVF_U4_UN:
3513 case CEE_CONV_OVF_U8_UN:
3514 case CEE_CONV_OVF_I_UN:
3515 case CEE_CONV_OVF_U_UN:
3522 token = read32 (ip + 1);
3523 if (method->wrapper_type != MONO_WRAPPER_NONE)
3524 klass = mono_method_get_wrapper_data (method, token);
3526 klass = mono_class_get (image, token);
3528 mono_class_init (klass);
3529 if (klass->byval_arg.type == MONO_TYPE_VAR)
3530 klass = TYPE_PARAM_TO_CLASS (klass->byval_arg.data.generic_param->num);
3532 if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
3533 MonoInst *store, *load;
3534 MONO_INST_NEW (cfg, load, CEE_LDIND_REF);
3535 load->cil_code = ip;
3536 load->inst_i0 = sp [1];
3537 load->type = ldind_type [CEE_LDIND_REF];
3538 load->flags |= ins_flag;
3539 MONO_INST_NEW (cfg, store, CEE_STIND_REF);
3540 store->cil_code = ip;
3541 handle_loaded_temps (cfg, bblock, stack_start, sp);
3542 MONO_ADD_INS (bblock, store);
3543 store->inst_i0 = sp [0];
3544 store->inst_i1 = load;
3545 store->flags |= ins_flag;
3547 n = mono_class_value_size (klass, NULL);
3548 if ((cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 5) {
3550 MONO_INST_NEW (cfg, copy, OP_MEMCPY);
3551 copy->inst_left = sp [0];
3552 copy->inst_right = sp [1];
3553 copy->cil_code = ip;
3555 MONO_ADD_INS (bblock, copy);
3557 MonoInst *iargs [3];
3560 NEW_ICONST (cfg, iargs [2], n);
3561 iargs [2]->cil_code = ip;
3563 mono_emit_jit_icall (cfg, bblock, helper_memcpy, iargs, ip);
3570 MonoInst *iargs [3];
3573 token = read32 (ip + 1);
3574 if (method->wrapper_type != MONO_WRAPPER_NONE)
3575 klass = mono_method_get_wrapper_data (method, token);
3577 klass = mono_class_get (image, token);
3579 mono_class_init (klass);
3580 if (klass->byval_arg.type == MONO_TYPE_VAR)
3581 klass = TYPE_PARAM_TO_CLASS (klass->byval_arg.data.generic_param->num);
3582 if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
3583 MONO_INST_NEW (cfg, ins, CEE_LDIND_REF);
3585 ins->inst_i0 = sp [0];
3586 ins->type = ldind_type [CEE_LDIND_REF];
3587 ins->flags |= ins_flag;
3593 n = mono_class_value_size (klass, NULL);
3594 ins = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
3595 NEW_TEMPLOADA (cfg, iargs [0], ins->inst_c0);
3596 if ((cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 5) {
3598 MONO_INST_NEW (cfg, copy, OP_MEMCPY);
3599 copy->inst_left = iargs [0];
3600 copy->inst_right = *sp;
3601 copy->cil_code = ip;
3603 MONO_ADD_INS (bblock, copy);
3606 NEW_ICONST (cfg, iargs [2], n);
3607 iargs [2]->cil_code = ip;
3609 mono_emit_jit_icall (cfg, bblock, helper_memcpy, iargs, ip);
3611 NEW_TEMPLOAD (cfg, *sp, ins->inst_c0);
3619 CHECK_STACK_OVF (1);
3620 n = read32 (ip + 1);
3622 if (method->wrapper_type != MONO_WRAPPER_NONE) {
3624 MonoInst *iargs [1];
3626 NEW_PCONST (cfg, iargs [0], mono_method_get_wrapper_data (method, n));
3627 temp = mono_emit_jit_icall (cfg, bblock, mono_string_new_wrapper, iargs, ip);
3628 NEW_TEMPLOAD (cfg, *sp, temp);
3632 if (cfg->opt & MONO_OPT_SHARED) {
3634 MonoInst *iargs [3];
3636 if (mono_compile_aot) {
3637 cfg->ldstr_list = g_list_prepend (cfg->ldstr_list, (gpointer)n);
3640 NEW_TEMPLOAD (cfg, iargs [0], mono_get_domainvar (cfg)->inst_c0);
3641 NEW_IMAGECONST (cfg, iargs [1], image);
3642 NEW_ICONST (cfg, iargs [2], mono_metadata_token_index (n));
3643 temp = mono_emit_jit_icall (cfg, bblock, mono_ldstr, iargs, ip);
3644 NEW_TEMPLOAD (cfg, *sp, temp);
3645 mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
3647 if (mono_compile_aot)
3648 NEW_LDSTRCONST (cfg, ins, image, n);
3650 NEW_PCONST (cfg, ins, NULL);
3652 ins->type = STACK_OBJ;
3653 ins->inst_p0 = mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
3663 MonoInst *iargs [2];
3664 MonoMethodSignature *fsig;
3667 token = read32 (ip + 1);
3668 if (method->wrapper_type != MONO_WRAPPER_NONE) {
3669 cmethod = mono_method_get_wrapper_data (method, token);
3671 cmethod = mono_get_method (image, token, NULL);
3672 fsig = mono_method_get_signature (cmethod, image, token);
3674 mono_class_init (cmethod->klass);
3676 n = fsig->param_count;
3679 /* move the args to allow room for 'this' in the first position */
3685 handle_loaded_temps (cfg, bblock, stack_start, sp);
3688 if (cmethod->klass->parent == mono_defaults.array_class) {
3689 NEW_METHODCONST (cfg, *sp, cmethod);
3690 temp = mono_emit_native_call (cfg, bblock, mono_array_new_va, fsig, sp, ip, FALSE);
3692 } else if (cmethod->string_ctor) {
3693 /* we simply pass a null pointer */
3694 NEW_PCONST (cfg, *sp, NULL);
3695 /* now call the string ctor */
3696 temp = mono_emit_method_call_spilled (cfg, bblock, cmethod, fsig, sp, ip, NULL);
3698 if (cmethod->klass->valuetype) {
3699 iargs [0] = mono_compile_create_var (cfg, &cmethod->klass->byval_arg, OP_LOCAL);
3700 temp = iargs [0]->inst_c0;
3701 NEW_TEMPLOADA (cfg, *sp, temp);
3703 if (cfg->opt & MONO_OPT_SHARED) {
3704 NEW_DOMAINCONST (cfg, iargs [0]);
3705 NEW_CLASSCONST (cfg, iargs [1], cmethod->klass);
3707 temp = mono_emit_jit_icall (cfg, bblock, mono_object_new, iargs, ip);
3709 MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
3710 NEW_VTABLECONST (cfg, iargs [0], vtable);
3711 if (cmethod->klass->has_finalize || cmethod->klass->marshalbyref || (cfg->prof_options & MONO_PROFILE_ALLOCATIONS))
3712 temp = mono_emit_jit_icall (cfg, bblock, mono_object_new_specific, iargs, ip);
3714 temp = mono_emit_jit_icall (cfg, bblock, mono_object_new_fast, iargs, ip);
3716 NEW_TEMPLOAD (cfg, *sp, temp);
3719 if ((cfg->opt & MONO_OPT_INLINE) && cmethod &&
3720 mono_method_check_inlining (cfg, cmethod) &&
3721 !mono_class_is_subclass_of (cmethod->klass, mono_defaults.exception_class, FALSE) &&
3722 !g_list_find (dont_inline, cmethod)) {
3724 MonoBasicBlock *ebblock;
3725 if ((costs = inline_method (cfg, cmethod, fsig, bblock, sp, ip, real_offset, dont_inline, &ebblock))) {
3730 GET_BBLOCK (cfg, bbhash, bblock, ip);
3731 ebblock->next_bb = bblock;
3732 link_bblock (cfg, ebblock, bblock);
3734 NEW_TEMPLOAD (cfg, *sp, temp);
3737 /* indicates start of a new block, and triggers a load
3738 of all stack arguments at bb boundarie */
3741 inline_costs += costs;
3745 mono_emit_method_call_spilled (cfg, bblock, cmethod, fsig, sp, ip, sp[0]);
3748 /* now call the actual ctor */
3749 mono_emit_method_call_spilled (cfg, bblock, cmethod, fsig, sp, ip, sp[0]);
3753 NEW_TEMPLOAD (cfg, *sp, temp);
3762 MONO_INST_NEW (cfg, ins, *ip);
3764 klass = mono_class_get (image, read32 (ip + 1));
3765 mono_class_init (klass);
3766 ins->type = STACK_OBJ;
3767 ins->inst_left = *sp;
3768 ins->inst_newa_class = klass;
3773 case CEE_UNBOX_ANY: {
3774 MonoInst *add, *vtoffset;
3775 MonoInst *iargs [3];
3779 token = read32 (ip + 1);
3780 if (method->wrapper_type != MONO_WRAPPER_NONE)
3781 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
3783 klass = mono_class_get (image, token);
3784 mono_class_init (klass);
3786 if (klass->byval_arg.type == MONO_TYPE_VAR)
3787 klass = TYPE_PARAM_TO_CLASS (klass->byval_arg.data.generic_param->num);
3789 if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
3791 MONO_INST_NEW (cfg, ins, CEE_CASTCLASS);
3792 ins->type = STACK_OBJ;
3793 ins->inst_left = *sp;
3795 ins->inst_newa_class = klass;
3802 MONO_INST_NEW (cfg, ins, OP_UNBOXCAST);
3803 ins->type = STACK_OBJ;
3804 ins->inst_left = *sp;
3806 ins->inst_newa_class = klass;
3809 MONO_INST_NEW (cfg, add, CEE_ADD);
3810 NEW_ICONST (cfg, vtoffset, sizeof (MonoObject));
3811 add->inst_left = ins;
3812 add->inst_right = vtoffset;
3813 add->type = STACK_MP;
3817 n = mono_class_value_size (klass, NULL);
3818 ins = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
3819 NEW_TEMPLOADA (cfg, iargs [0], ins->inst_c0);
3820 if ((cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 5) {
3822 MONO_INST_NEW (cfg, copy, OP_MEMCPY);
3823 copy->inst_left = iargs [0];
3824 copy->inst_right = *sp;
3825 copy->cil_code = ip;
3827 MONO_ADD_INS (bblock, copy);
3830 NEW_ICONST (cfg, iargs [2], n);
3831 iargs [2]->cil_code = ip;
3833 mono_emit_jit_icall (cfg, bblock, helper_memcpy, iargs, ip);
3835 NEW_TEMPLOAD (cfg, *sp, ins->inst_c0);
3841 MonoInst *add, *vtoffset;
3845 token = read32 (ip + 1);
3846 if (method->wrapper_type != MONO_WRAPPER_NONE)
3847 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
3849 klass = mono_class_get (image, token);
3850 mono_class_init (klass);
3852 if (klass->byval_arg.type == MONO_TYPE_VAR)
3853 klass = TYPE_PARAM_TO_CLASS (klass->byval_arg.data.generic_param->num);
3855 MONO_INST_NEW (cfg, ins, OP_UNBOXCAST);
3856 ins->type = STACK_OBJ;
3857 ins->inst_left = *sp;
3859 ins->inst_newa_class = klass;
3862 MONO_INST_NEW (cfg, add, CEE_ADD);
3863 NEW_ICONST (cfg, vtoffset, sizeof (MonoObject));
3864 add->inst_left = ins;
3865 add->inst_right = vtoffset;
3866 add->type = STACK_MP;
3874 MONO_INST_NEW (cfg, ins, *ip);
3876 klass = mono_class_get (image, read32 (ip + 1));
3877 mono_class_init (klass);
3878 if (klass->byval_arg.type == MONO_TYPE_VAR)
3879 klass = TYPE_PARAM_TO_CLASS (klass->byval_arg.data.generic_param->num);
3880 ins->type = STACK_OBJ;
3881 ins->inst_left = *sp;
3883 ins->inst_newa_class = klass;
3890 MONO_INST_NEW (cfg, ins, *ip);
3892 ins->inst_left = *sp;
3893 ins->cil_code = ip++;
3894 MONO_ADD_INS (bblock, ins);
3896 start_new_bblock = 1;
3901 MonoInst *offset_ins;
3902 MonoClassField *field;
3903 MonoBasicBlock *ebblock;
3907 if (*ip == CEE_STFLD) {
3914 // FIXME: enable this test later.
3915 //if (sp [0]->type != STACK_OBJ && sp [0]->type != STACK_MP)
3917 token = read32 (ip + 1);
3918 field = mono_field_from_token (image, token, &klass);
3919 if (field->parent->gen_params)
3920 field = get_generic_field_inst (field, method->klass, &klass);
3921 mono_class_init (klass);
3923 foffset = klass->valuetype? field->offset - sizeof (MonoObject): field->offset;
3924 /* FIXME: mark instructions for use in SSA */
3925 if (*ip == CEE_STFLD) {
3926 if (klass->marshalbyref && !MONO_CHECK_THIS (sp [0])) {
3927 MonoMethod *stfld_wrapper = mono_marshal_get_stfld_wrapper (field->type);
3928 MonoInst *iargs [5];
3931 NEW_CLASSCONST (cfg, iargs [1], klass);
3932 NEW_FIELDCONST (cfg, iargs [2], field);
3933 NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) :
3937 if (cfg->opt & MONO_OPT_INLINE) {
3938 costs = inline_method (cfg, stfld_wrapper, stfld_wrapper->signature, bblock,
3939 iargs, ip, real_offset, dont_inline, &ebblock);
3940 g_assert (costs > 0);
3945 GET_BBLOCK (cfg, bbhash, bblock, ip);
3946 ebblock->next_bb = bblock;
3947 link_bblock (cfg, ebblock, bblock);
3949 /* indicates start of a new block, and triggers a load
3950 of all stack arguments at bb boundarie */
3953 inline_costs += costs;
3956 mono_emit_method_call_spilled (cfg, bblock, stfld_wrapper, stfld_wrapper->signature, iargs, ip, NULL);
3960 NEW_ICONST (cfg, offset_ins, foffset);
3961 MONO_INST_NEW (cfg, ins, CEE_ADD);
3963 ins->inst_left = *sp;
3964 ins->inst_right = offset_ins;
3965 ins->type = STACK_MP;
3967 MONO_INST_NEW (cfg, store, mono_type_to_stind (field->type));
3968 store->cil_code = ip;
3969 store->inst_left = ins;
3970 store->inst_right = sp [1];
3971 handle_loaded_temps (cfg, bblock, stack_start, sp);
3972 store->flags |= ins_flag;
3974 if (store->opcode == CEE_STOBJ) {
3975 handle_stobj (cfg, bblock, ins, sp [1], ip,
3976 mono_class_from_mono_type (field->type), FALSE, FALSE);
3978 MONO_ADD_INS (bblock, store);
3981 if (klass->marshalbyref && !MONO_CHECK_THIS (sp [0])) {
3982 /* fixme: we need to inline that call somehow */
3983 MonoMethod *ldfld_wrapper = mono_marshal_get_ldfld_wrapper (field->type);
3984 MonoInst *iargs [4];
3988 NEW_CLASSCONST (cfg, iargs [1], klass);
3989 NEW_FIELDCONST (cfg, iargs [2], field);
3990 NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : field->offset);
3991 if (cfg->opt & MONO_OPT_INLINE) {
3992 costs = inline_method (cfg, ldfld_wrapper, ldfld_wrapper->signature, bblock,
3993 iargs, ip, real_offset, dont_inline, &ebblock);
3994 g_assert (costs > 0);
3999 GET_BBLOCK (cfg, bbhash, bblock, ip);
4000 ebblock->next_bb = bblock;
4001 link_bblock (cfg, ebblock, bblock);
4003 temp = iargs [0]->inst_i0->inst_c0;
4005 if (*ip == CEE_LDFLDA) {
4006 /* not sure howto handle this */
4007 NEW_TEMPLOADA (cfg, *sp, temp);
4009 NEW_TEMPLOAD (cfg, *sp, temp);
4013 /* indicates start of a new block, and triggers a load of
4014 all stack arguments at bb boundarie */
4017 inline_costs += costs;
4020 temp = mono_emit_method_call_spilled (cfg, bblock, ldfld_wrapper, ldfld_wrapper->signature, iargs, ip, NULL);
4021 if (*ip == CEE_LDFLDA) {
4022 /* not sure howto handle this */
4023 NEW_TEMPLOADA (cfg, *sp, temp);
4025 NEW_TEMPLOAD (cfg, *sp, temp);
4030 NEW_ICONST (cfg, offset_ins, foffset);
4031 MONO_INST_NEW (cfg, ins, CEE_ADD);
4033 ins->inst_left = *sp;
4034 ins->inst_right = offset_ins;
4035 ins->type = STACK_MP;
4037 if (*ip == CEE_LDFLDA) {
4041 MONO_INST_NEW (cfg, load, mono_type_to_ldind (field->type));
4042 type_to_eval_stack_type (field->type, load);
4043 load->cil_code = ip;
4044 load->inst_left = ins;
4045 load->flags |= ins_flag;
4057 MonoClassField *field;
4058 gpointer addr = NULL;
4060 token = read32 (ip + 1);
4062 field = mono_field_from_token (image, token, &klass);
4063 mono_class_init (klass);
4065 handle_loaded_temps (cfg, bblock, stack_start, sp);
4067 if (cfg->domain->thread_static_fields)
4068 addr = g_hash_table_lookup (cfg->domain->thread_static_fields, field);
4070 if ((cfg->opt & MONO_OPT_SHARED) || (mono_compile_aot && addr)) {
4072 MonoInst *iargs [2];
4073 g_assert (field->parent);
4074 NEW_TEMPLOAD (cfg, iargs [0], mono_get_domainvar (cfg)->inst_c0);
4075 NEW_FIELDCONST (cfg, iargs [1], field);
4076 temp = mono_emit_jit_icall (cfg, bblock, mono_class_static_field_address, iargs, ip);
4077 NEW_TEMPLOAD (cfg, ins, temp);
4080 vtable = mono_class_vtable (cfg->domain, klass);
4082 if ((!vtable->initialized || mono_compile_aot) && !(klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) && mono_class_needs_cctor_run (klass, method)) {
4083 guint8 *tramp = mono_create_class_init_trampoline (vtable);
4084 mono_emit_native_call (cfg, bblock, tramp,
4085 helper_sig_class_init_trampoline,
4087 if (cfg->verbose_level > 2)
4088 g_print ("class %s.%s needs init call for %s\n", klass->name_space, klass->name, field->name);
4090 mono_runtime_class_init (vtable);
4092 addr = (char*)vtable->data + field->offset;
4094 if (mono_compile_aot)
4095 NEW_SFLDACONST (cfg, ins, field);
4097 NEW_PCONST (cfg, ins, addr);
4101 * insert call to mono_threads_get_static_data (GPOINTER_TO_UINT (addr))
4102 * This could be later optimized to do just a couple of
4103 * memory dereferences with constant offsets.
4106 MonoInst *iargs [1];
4107 NEW_ICONST (cfg, iargs [0], GPOINTER_TO_UINT (addr));
4108 temp = mono_emit_jit_icall (cfg, bblock, mono_threads_get_static_data, iargs, ip);
4109 NEW_TEMPLOAD (cfg, ins, temp);
4113 /* FIXME: mark instructions for use in SSA */
4114 if (*ip == CEE_LDSFLDA) {
4116 } else if (*ip == CEE_STSFLD) {
4120 MONO_INST_NEW (cfg, store, mono_type_to_stind (field->type));
4121 store->cil_code = ip;
4122 store->inst_left = ins;
4123 store->inst_right = sp [0];
4124 store->flags |= ins_flag;
4127 if (store->opcode == CEE_STOBJ) {
4128 handle_stobj (cfg, bblock, ins, sp [0], ip, mono_class_from_mono_type (field->type), FALSE, FALSE);
4130 MONO_ADD_INS (bblock, store);
4132 gboolean is_const = FALSE;
4133 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
4134 if (!((cfg->opt & MONO_OPT_SHARED) || mono_compile_aot) &&
4135 vtable->initialized && (field->type->attrs & FIELD_ATTRIBUTE_INIT_ONLY)) {
4136 gpointer addr = (char*)vtable->data + field->offset;
4137 /* g_print ("RO-FIELD %s.%s:%s\n", klass->name_space, klass->name, field->name);*/
4139 switch (field->type->type) {
4140 case MONO_TYPE_BOOLEAN:
4142 NEW_ICONST (cfg, *sp, *((guint8 *)addr));
4146 NEW_ICONST (cfg, *sp, *((gint8 *)addr));
4149 case MONO_TYPE_CHAR:
4151 NEW_ICONST (cfg, *sp, *((guint16 *)addr));
4155 NEW_ICONST (cfg, *sp, *((gint16 *)addr));
4160 NEW_ICONST (cfg, *sp, *((gint32 *)addr));
4164 NEW_ICONST (cfg, *sp, *((guint32 *)addr));
4169 case MONO_TYPE_STRING:
4170 case MONO_TYPE_OBJECT:
4171 case MONO_TYPE_CLASS:
4172 case MONO_TYPE_SZARRAY:
4174 case MONO_TYPE_FNPTR:
4175 case MONO_TYPE_ARRAY:
4176 NEW_PCONST (cfg, *sp, *((gpointer *)addr));
4177 type_to_eval_stack_type (field->type, *sp);
4182 MONO_INST_NEW (cfg, *sp, OP_I8CONST);
4183 sp [0]->type = STACK_I8;
4184 sp [0]->inst_l = *((gint64 *)addr);
4189 case MONO_TYPE_VALUETYPE:
4198 CHECK_STACK_OVF (1);
4199 MONO_INST_NEW (cfg, load, mono_type_to_ldind (field->type));
4200 type_to_eval_stack_type (field->type, load);
4201 load->cil_code = ip;
4202 load->inst_left = ins;
4204 load->flags |= ins_flag;
4206 /* fixme: dont see the problem why this does not work */
4207 //cfg->disable_aot = TRUE;
4216 token = read32 (ip + 1);
4217 if (method->wrapper_type != MONO_WRAPPER_NONE)
4218 klass = mono_method_get_wrapper_data (method, token);
4220 klass = mono_class_get (image, token);
4221 mono_class_init (klass);
4222 if (klass->byval_arg.type == MONO_TYPE_VAR)
4223 klass = TYPE_PARAM_TO_CLASS (klass->byval_arg.data.generic_param->num);
4224 n = mono_type_to_stind (&klass->byval_arg);
4225 if (n == CEE_STOBJ) {
4226 handle_stobj (cfg, bblock, sp [0], sp [1], ip, klass, FALSE, FALSE);
4228 /* FIXME: should check item at sp [1] is compatible with the type of the store. */
4230 MONO_INST_NEW (cfg, store, n);
4231 store->cil_code = ip;
4232 store->inst_left = sp [0];
4233 store->inst_right = sp [1];
4234 store->flags |= ins_flag;
4235 MONO_ADD_INS (bblock, store);
4242 MonoInst *iargs [2];
4243 MonoInst *load, *vtoffset, *add, *val, *vstore;
4248 token = read32 (ip + 1);
4249 if (method->wrapper_type != MONO_WRAPPER_NONE)
4250 klass = mono_method_get_wrapper_data (method, token);
4252 klass = mono_class_get (image, token);
4253 mono_class_init (klass);
4254 if (klass->byval_arg.type == MONO_TYPE_VAR)
4255 klass = TYPE_PARAM_TO_CLASS (klass->byval_arg.data.generic_param->num);
4257 if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
4262 /* much like NEWOBJ */
4263 if (cfg->opt & MONO_OPT_SHARED) {
4264 NEW_DOMAINCONST (cfg, iargs [0]);
4265 NEW_CLASSCONST (cfg, iargs [1], klass);
4267 temp = mono_emit_jit_icall (cfg, bblock, mono_object_new, iargs, ip);
4269 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
4270 NEW_VTABLECONST (cfg, iargs [0], vtable);
4271 if (1 || klass->has_finalize || (cfg->prof_options & MONO_PROFILE_ALLOCATIONS))
4272 temp = mono_emit_jit_icall (cfg, bblock, mono_object_new_specific, iargs, ip);
4274 temp = mono_emit_jit_icall (cfg, bblock, mono_object_new_fast, iargs, ip);
4276 NEW_TEMPLOAD (cfg, load, temp);
4277 NEW_ICONST (cfg, vtoffset, sizeof (MonoObject));
4278 MONO_INST_NEW (cfg, add, CEE_ADD);
4279 add->inst_left = load;
4280 add->inst_right = vtoffset;
4283 MONO_INST_NEW (cfg, vstore, CEE_STIND_I);
4284 vstore->opcode = mono_type_to_stind (&klass->byval_arg);
4285 vstore->cil_code = ip;
4286 vstore->inst_left = add;
4287 vstore->inst_right = val;
4289 if (vstore->opcode == CEE_STOBJ) {
4290 handle_stobj (cfg, bblock, add, val, ip, klass, FALSE, FALSE);
4292 MONO_ADD_INS (bblock, vstore);
4294 NEW_TEMPLOAD (cfg, load, temp);
4302 MONO_INST_NEW (cfg, ins, *ip);
4306 token = read32 (ip + 1);
4308 /* allocate the domainvar - becaus this is used in decompose_foreach */
4309 if (cfg->opt & MONO_OPT_SHARED)
4310 mono_get_domainvar (cfg);
4312 if (method->wrapper_type != MONO_WRAPPER_NONE)
4313 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
4315 klass = mono_class_get (image, token);
4317 mono_class_init (klass);
4318 if (klass->byval_arg.type == MONO_TYPE_VAR)
4319 klass = TYPE_PARAM_TO_CLASS (klass->byval_arg.data.generic_param->num);
4320 ins->inst_newa_class = klass;
4321 ins->inst_newa_len = *sp;
4322 ins->type = STACK_OBJ;
4329 MONO_INST_NEW (cfg, ins, *ip);
4330 ins->cil_code = ip++;
4332 ins->inst_left = *sp;
4333 ins->type = STACK_PTR;
4340 if (method->wrapper_type != MONO_WRAPPER_NONE)
4341 klass = (MonoClass*)mono_method_get_wrapper_data (method, read32 (ip + 1));
4343 klass = mono_class_get (image, read32 (ip + 1));
4344 mono_class_init (klass);
4345 if (klass->byval_arg.type == MONO_TYPE_VAR)
4346 klass = TYPE_PARAM_TO_CLASS (klass->byval_arg.data.generic_param->num);
4347 NEW_LDELEMA (cfg, ins, sp, klass);
4356 token = read32 (ip + 1);
4357 klass = mono_class_get (image, token);
4358 mono_class_init (klass);
4359 if (klass->byval_arg.type == MONO_TYPE_VAR)
4360 klass = TYPE_PARAM_TO_CLASS (klass->byval_arg.data.generic_param->num);
4361 NEW_LDELEMA (cfg, load, sp, klass);
4362 load->cil_code = ip;
4363 MONO_INST_NEW (cfg, ins, mono_type_to_ldind (&klass->byval_arg));
4365 ins->inst_left = load;
4367 type_to_eval_stack_type (&klass->byval_arg, ins);
4381 case CEE_LDELEM_REF: {
4385 * ldind.x (ldelema (array, index))
4386 * ldelema does the bounds check
4390 klass = array_access_to_klass (*ip);
4391 NEW_LDELEMA (cfg, load, sp, klass);
4392 load->cil_code = ip;
4393 MONO_INST_NEW (cfg, ins, ldelem_to_ldind [*ip - CEE_LDELEM_I1]);
4395 ins->inst_left = load;
4397 ins->type = ldind_type [ins->opcode - CEE_LDIND_I1];
4407 case CEE_STELEM_R8: {
4411 * stind.x (ldelema (array, index), val)
4412 * ldelema does the bounds check
4416 klass = array_access_to_klass (*ip);
4417 NEW_LDELEMA (cfg, load, sp, klass);
4418 load->cil_code = ip;
4419 MONO_INST_NEW (cfg, ins, stelem_to_stind [*ip - CEE_STELEM_I]);
4421 ins->inst_left = load;
4422 ins->inst_right = sp [2];
4424 handle_loaded_temps (cfg, bblock, stack_start, sp);
4425 MONO_ADD_INS (bblock, ins);
4427 cfg->disable_ssa = TRUE;
4434 * stind.x (ldelema (array, index), val)
4435 * ldelema does the bounds check
4439 token = read32 (ip + 1);
4440 klass = mono_class_get (image, token);
4441 mono_class_init (klass);
4442 if (klass->byval_arg.type == MONO_TYPE_VAR)
4443 klass = TYPE_PARAM_TO_CLASS (klass->byval_arg.data.generic_param->num);
4444 if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
4445 MonoInst *iargs [3];
4446 handle_loaded_temps (cfg, bblock, stack_start, sp);
4452 mono_emit_jit_icall (cfg, bblock, helper_stelem_ref, iargs, ip);
4454 NEW_LDELEMA (cfg, load, sp, klass);
4455 load->cil_code = ip;
4456 MONO_INST_NEW (cfg, ins, mono_type_to_stind (&klass->byval_arg));
4458 ins->inst_left = load;
4459 ins->inst_right = sp [2];
4460 handle_loaded_temps (cfg, bblock, stack_start, sp);
4461 MONO_ADD_INS (bblock, ins);
4465 cfg->disable_ssa = TRUE;
4468 case CEE_STELEM_REF: {
4469 MonoInst *iargs [3];
4474 handle_loaded_temps (cfg, bblock, stack_start, sp);
4480 mono_emit_jit_icall (cfg, bblock, helper_stelem_ref, iargs, ip);
4484 NEW_GROUP (cfg, group, sp [0], sp [1]);
4485 MONO_INST_NEW (cfg, ins, CEE_STELEM_REF);
4487 ins->inst_left = group;
4488 ins->inst_right = sp [2];
4489 MONO_ADD_INS (bblock, ins);
4494 cfg->disable_ssa = TRUE;
4497 case CEE_CKFINITE: {
4498 MonoInst *store, *temp;
4501 /* this instr. can throw exceptions as side effect,
4502 * so we cant eliminate dead code which contains CKFINITE opdodes.
4503 * Spilling to memory makes sure that we always perform
4507 MONO_INST_NEW (cfg, ins, CEE_CKFINITE);
4509 ins->inst_left = sp [-1];
4510 temp = mono_compile_create_var (cfg, &mono_defaults.double_class->byval_arg, OP_LOCAL);
4512 NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
4513 store->cil_code = ip;
4514 MONO_ADD_INS (bblock, store);
4516 NEW_TEMPLOAD (cfg, sp [-1], temp->inst_c0);
4523 g_error ("opcode 0x%02x not handled", *ip);
4527 MonoClass *handle_class;
4529 CHECK_STACK_OVF (1);
4531 n = read32 (ip + 1);
4533 handle = mono_ldtoken (image, n, &handle_class);
4534 mono_class_init (handle_class);
4536 if (cfg->opt & MONO_OPT_SHARED) {
4538 MonoInst *res, *store, *addr, *vtvar, *iargs [2];
4540 vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL);
4542 NEW_IMAGECONST (cfg, iargs [0], image);
4543 NEW_ICONST (cfg, iargs [1], n);
4544 temp = mono_emit_jit_icall (cfg, bblock, mono_ldtoken_wrapper, iargs, ip);
4545 NEW_TEMPLOAD (cfg, res, temp);
4546 NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
4547 NEW_INDSTORE (cfg, store, addr, res, &mono_defaults.int_class->byval_arg);
4548 MONO_ADD_INS (bblock, store);
4549 NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
4551 if ((ip [5] == CEE_CALL) && (cmethod = mono_get_method (image, read32 (ip + 6), NULL)) &&
4552 (cmethod->klass == mono_defaults.monotype_class->parent) &&
4553 (strcmp (cmethod->name, "GetTypeFromHandle") == 0)) {
4554 MonoClass *tclass = mono_class_from_mono_type (handle);
4555 mono_class_init (tclass);
4556 if (mono_compile_aot)
4557 NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, image, n);
4559 NEW_PCONST (cfg, ins, mono_type_get_object (cfg->domain, handle));
4560 ins->type = STACK_OBJ;
4561 ins->klass = cmethod->klass;
4564 if (mono_compile_aot)
4565 NEW_LDTOKENCONST (cfg, ins, image, n);
4567 NEW_PCONST (cfg, ins, handle);
4568 ins->type = STACK_VTYPE;
4569 ins->klass = handle_class;
4585 case CEE_ADD_OVF_UN:
4587 case CEE_MUL_OVF_UN:
4589 case CEE_SUB_OVF_UN:
4594 case CEE_ENDFINALLY:
4595 /* FIXME: check stack state */
4596 MONO_INST_NEW (cfg, ins, *ip);
4597 MONO_ADD_INS (bblock, ins);
4598 ins->cil_code = ip++;
4599 start_new_bblock = 1;
4604 if (*ip == CEE_LEAVE) {
4605 target = ip + 5 + (gint32)read32(ip + 1);
4607 target = ip + 2 + (signed char)(ip [1]);
4610 /* empty the stack */
4611 while (sp != stack_start) {
4612 MONO_INST_NEW (cfg, ins, CEE_POP);
4616 MONO_ADD_INS (bblock, ins);
4619 /* fixme: call fault handler ? */
4621 if ((handlers = mono_find_final_block (cfg, ip, target, MONO_EXCEPTION_CLAUSE_FINALLY))) {
4623 for (tmp = handlers; tmp; tmp = tmp->next) {
4625 link_bblock (cfg, bblock, tblock);
4626 MONO_INST_NEW (cfg, ins, OP_CALL_HANDLER);
4628 ins->inst_target_bb = tblock;
4629 MONO_ADD_INS (bblock, ins);
4631 g_list_free (handlers);
4634 MONO_INST_NEW (cfg, ins, CEE_BR);
4636 MONO_ADD_INS (bblock, ins);
4637 GET_BBLOCK (cfg, bbhash, tblock, target);
4638 link_bblock (cfg, bblock, tblock);
4639 CHECK_BBLOCK (target, ip, tblock);
4640 ins->inst_target_bb = tblock;
4641 start_new_bblock = 1;
4643 if (*ip == CEE_LEAVE)
4652 MONO_INST_NEW (cfg, ins, *ip);
4654 handle_loaded_temps (cfg, bblock, stack_start, sp);
4655 MONO_ADD_INS (bblock, ins);
4656 ins->cil_code = ip++;
4657 ins->inst_i0 = sp [0];
4658 ins->inst_i1 = sp [1];
4666 /* trampoline mono specific opcodes */
4667 case MONO_CUSTOM_PREFIX: {
4669 g_assert (method->wrapper_type != MONO_WRAPPER_NONE);
4673 case CEE_MONO_FUNC1: {
4675 gpointer func = NULL;
4680 case MONO_MARSHAL_CONV_STR_LPWSTR:
4681 func = mono_string_to_utf16;
4683 case MONO_MARSHAL_CONV_LPWSTR_STR:
4684 func = mono_string_from_utf16;
4686 case MONO_MARSHAL_CONV_LPSTR_STR:
4687 func = mono_string_new_wrapper;
4689 case MONO_MARSHAL_CONV_STR_LPTSTR:
4690 case MONO_MARSHAL_CONV_STR_LPSTR:
4691 func = mono_string_to_utf8;
4693 case MONO_MARSHAL_CONV_STR_BSTR:
4694 func = mono_string_to_bstr;
4696 case MONO_MARSHAL_CONV_STR_TBSTR:
4697 case MONO_MARSHAL_CONV_STR_ANSIBSTR:
4698 func = mono_string_to_ansibstr;
4700 case MONO_MARSHAL_CONV_SB_LPSTR:
4701 func = mono_string_builder_to_utf8;
4703 case MONO_MARSHAL_CONV_ARRAY_SAVEARRAY:
4704 func = mono_array_to_savearray;
4706 case MONO_MARSHAL_CONV_ARRAY_LPARRAY:
4707 func = mono_array_to_lparray;
4709 case MONO_MARSHAL_CONV_DEL_FTN:
4710 func = mono_delegate_to_ftnptr;
4712 case MONO_MARSHAL_CONV_STRARRAY_STRLPARRAY:
4713 func = mono_marshal_string_array;
4716 g_warning ("unknown conversion %d\n", ip [2]);
4717 g_assert_not_reached ();
4720 temp = mono_emit_jit_icall (cfg, bblock, func, sp, ip);
4721 NEW_TEMPLOAD (cfg, *sp, temp);
4725 inline_costs += 10 * num_calls++;
4728 case CEE_MONO_PROC2: {
4729 gpointer func = NULL;
4734 case MONO_MARSHAL_CONV_LPSTR_SB:
4735 func = mono_string_utf8_to_builder;
4737 case MONO_MARSHAL_FREE_ARRAY:
4738 func = mono_marshal_free_array;
4741 g_assert_not_reached ();
4744 mono_emit_jit_icall (cfg, bblock, func, sp, ip);
4746 inline_costs += 10 * num_calls++;
4749 case CEE_MONO_PROC3: {
4750 gpointer func = NULL;
4755 case MONO_MARSHAL_CONV_STR_BYVALSTR:
4756 func = mono_string_to_byvalstr;
4758 case MONO_MARSHAL_CONV_STR_BYVALWSTR:
4759 func = mono_string_to_byvalwstr;
4762 g_assert_not_reached ();
4765 mono_emit_jit_icall (cfg, bblock, func, sp, ip);
4767 inline_costs += 10 * num_calls++;
4773 mono_emit_jit_icall (cfg, bblock, g_free, sp, ip);
4775 inline_costs += 10 * num_calls++;
4777 case CEE_MONO_LDPTR:
4778 CHECK_STACK_OVF (1);
4779 token = read32 (ip + 2);
4780 NEW_PCONST (cfg, ins, mono_method_get_wrapper_data (method, token));
4784 inline_costs += 10 * num_calls++;
4786 case CEE_MONO_VTADDR:
4789 MONO_INST_NEW (cfg, ins, OP_VTADDR);
4791 ins->type = STACK_MP;
4792 ins->inst_left = *sp;
4796 case CEE_MONO_NEWOBJ: {
4797 MonoInst *iargs [2];
4799 CHECK_STACK_OVF (1);
4800 token = read32 (ip + 2);
4801 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
4802 mono_class_init (klass);
4803 NEW_DOMAINCONST (cfg, iargs [0]);
4804 NEW_CLASSCONST (cfg, iargs [1], klass);
4805 temp = mono_emit_jit_icall (cfg, bblock, mono_object_new, iargs, ip);
4806 NEW_TEMPLOAD (cfg, *sp, temp);
4809 inline_costs += 10 * num_calls++;
4812 case CEE_MONO_OBJADDR:
4815 MONO_INST_NEW (cfg, ins, OP_OBJADDR);
4817 ins->type = STACK_MP;
4818 ins->inst_left = *sp;
4822 case CEE_MONO_LDNATIVEOBJ:
4824 token = read32 (ip + 2);
4825 klass = mono_method_get_wrapper_data (method, token);
4826 g_assert (klass->valuetype);
4827 mono_class_init (klass);
4828 NEW_INDLOAD (cfg, ins, sp [-1], &klass->byval_arg);
4832 case CEE_MONO_RETOBJ:
4833 g_assert (cfg->ret);
4834 g_assert (method->signature->pinvoke);
4838 token = read32 (ip + 2);
4839 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
4841 NEW_RETLOADA (cfg, ins);
4842 handle_stobj (cfg, bblock, ins, *sp, ip, klass, FALSE, TRUE);
4844 if (sp != stack_start)
4847 MONO_INST_NEW (cfg, ins, CEE_BR);
4849 ins->inst_target_bb = end_bblock;
4850 MONO_ADD_INS (bblock, ins);
4851 link_bblock (cfg, bblock, end_bblock);
4852 start_new_bblock = 1;
4856 g_error ("opcode 0x%02x 0x%02x not handled", MONO_CUSTOM_PREFIX, ip [1]);
4864 /* somewhat similar to LDTOKEN */
4865 MonoInst *addr, *vtvar;
4866 CHECK_STACK_OVF (1);
4867 vtvar = mono_compile_create_var (cfg, &mono_defaults.argumenthandle_class->byval_arg, OP_LOCAL);
4869 NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
4870 addr->cil_code = ip;
4871 MONO_INST_NEW (cfg, ins, OP_ARGLIST);
4873 ins->inst_left = addr;
4874 MONO_ADD_INS (bblock, ins);
4875 NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
4888 MONO_INST_NEW (cfg, cmp, 256 + ip [1]);
4889 MONO_INST_NEW (cfg, ins, cmp->opcode);
4891 cmp->inst_i0 = sp [0];
4892 cmp->inst_i1 = sp [1];
4896 cmp->opcode = OP_COMPARE;
4898 ins->type = STACK_I4;
4908 CHECK_STACK_OVF (1);
4909 n = read32 (ip + 2);
4910 if (method->wrapper_type != MONO_WRAPPER_NONE)
4911 cmethod = mono_method_get_wrapper_data (method, n);
4913 cmethod = mono_get_method (image, n, NULL);
4916 * We can't do this in mono_ldftn, since it is used in
4917 * the synchronized wrapper, leading to an infinite loop.
4919 if (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
4920 cmethod = mono_marshal_get_synchronized_wrapper (cmethod);
4923 mono_class_init (cmethod->klass);
4924 handle_loaded_temps (cfg, bblock, stack_start, sp);
4926 NEW_METHODCONST (cfg, argconst, cmethod);
4927 temp = mono_emit_jit_icall (cfg, bblock, mono_ldftn, &argconst, ip);
4928 NEW_TEMPLOAD (cfg, *sp, temp);
4932 inline_costs += 10 * num_calls++;
4935 case CEE_LDVIRTFTN: {
4940 n = read32 (ip + 2);
4941 if (method->wrapper_type != MONO_WRAPPER_NONE)
4942 cmethod = mono_method_get_wrapper_data (method, n);
4944 cmethod = mono_get_method (image, n, NULL);
4946 mono_class_init (cmethod->klass);
4947 handle_loaded_temps (cfg, bblock, stack_start, sp);
4951 NEW_METHODCONST (cfg, args [1], cmethod);
4952 temp = mono_emit_jit_icall (cfg, bblock, mono_ldvirtfn, args, ip);
4953 NEW_TEMPLOAD (cfg, *sp, temp);
4957 inline_costs += 10 * num_calls++;
4961 CHECK_STACK_OVF (1);
4962 NEW_ARGLOAD (cfg, ins, read16 (ip + 2));
4968 CHECK_STACK_OVF (1);
4969 NEW_ARGLOADA (cfg, ins, read16 (ip + 2));
4977 handle_loaded_temps (cfg, bblock, stack_start, sp);
4978 n = read16 (ip + 2);
4979 NEW_ARGSTORE (cfg, ins, n, *sp);
4981 if (ins->opcode == CEE_STOBJ) {
4982 NEW_ARGLOADA (cfg, ins, n);
4983 handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE);
4985 MONO_ADD_INS (bblock, ins);
4989 CHECK_STACK_OVF (1);
4990 NEW_LOCLOAD (cfg, ins, read16 (ip + 2));
4996 CHECK_STACK_OVF (1);
4997 NEW_LOCLOADA (cfg, ins, read16 (ip + 2));
5005 n = read16 (ip + 2);
5006 handle_loaded_temps (cfg, bblock, stack_start, sp);
5007 NEW_LOCSTORE (cfg, ins, n, *sp);
5009 if (ins->opcode == CEE_STOBJ) {
5010 NEW_LOCLOADA (cfg, ins, n);
5011 handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE);
5013 MONO_ADD_INS (bblock, ins);
5020 if (sp != stack_start)
5022 MONO_INST_NEW (cfg, ins, 256 + ip [1]);
5023 ins->inst_left = *sp;
5026 if (header->init_locals)
5027 ins->flags |= MONO_INST_INIT;
5031 /* FIXME: set init flag if locals init is set in this method */
5033 case CEE_ENDFILTER: {
5034 MonoExceptionClause *clause, *nearest;
5035 int cc, nearest_num;
5039 if ((sp != stack_start) || (sp [0]->type != STACK_I4))
5041 MONO_INST_NEW (cfg, ins, OP_ENDFILTER);
5042 ins->inst_left = *sp;
5044 MONO_ADD_INS (bblock, ins);
5045 start_new_bblock = 1;
5049 for (cc = 0; cc < header->num_clauses; ++cc) {
5050 clause = &header->clauses [cc];
5051 if ((clause->flags & MONO_EXCEPTION_CLAUSE_FILTER) &&
5052 (!nearest || (clause->token_or_filter > nearest->token_or_filter))) {
5058 filter_lengths [nearest_num] = (ip - header->code) - nearest->token_or_filter;
5062 case CEE_UNALIGNED_:
5063 ins_flag |= MONO_INST_UNALIGNED;
5067 ins_flag |= MONO_INST_VOLATILE;
5071 ins_flag |= MONO_INST_TAILCALL;
5072 /* Can't inline tail calls at this time */
5073 inline_costs += 100000;
5079 token = read32 (ip + 2);
5080 if (method->wrapper_type != MONO_WRAPPER_NONE)
5081 klass = mono_method_get_wrapper_data (method, token);
5083 klass = mono_class_get (image, token);
5084 if (klass->byval_arg.type == MONO_TYPE_VAR)
5085 klass = TYPE_PARAM_TO_CLASS (klass->byval_arg.data.generic_param->num);
5086 if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
5087 MonoInst *store, *load;
5088 NEW_PCONST (cfg, load, NULL);
5089 load->cil_code = ip;
5090 load->type = STACK_OBJ;
5091 MONO_INST_NEW (cfg, store, CEE_STIND_REF);
5092 store->cil_code = ip;
5093 handle_loaded_temps (cfg, bblock, stack_start, sp);
5094 MONO_ADD_INS (bblock, store);
5095 store->inst_i0 = sp [0];
5096 store->inst_i1 = load;
5099 handle_initobj (cfg, bblock, *sp, NULL, klass, stack_start, sp);
5104 case CEE_CONSTRAINED_:
5105 /* FIXME: implement */
5106 token = read32 (ip + 2);
5111 MonoInst *iargs [3];
5117 handle_loaded_temps (cfg, bblock, stack_start, sp);
5118 if (ip [1] == CEE_CPBLK) {
5119 mono_emit_jit_icall (cfg, bblock, helper_memcpy, iargs, ip);
5121 mono_emit_jit_icall (cfg, bblock, helper_memset, iargs, ip);
5129 ins_flag |= MONO_INST_NOTYPECHECK;
5131 ins_flag |= MONO_INST_NORANGECHECK;
5132 /* we ignore the no-nullcheck for now since we
5133 * really do it explicitly only when doing callvirt->call
5139 /* FIXME: check we are in a catch handler */
5140 NEW_TEMPLOAD (cfg, load, cfg->exvar->inst_c0);
5141 load->cil_code = ip;
5142 MONO_INST_NEW (cfg, ins, CEE_THROW);
5143 ins->inst_left = load;
5145 MONO_ADD_INS (bblock, ins);
5147 start_new_bblock = 1;
5152 CHECK_STACK_OVF (1);
5153 token = read32 (ip + 2);
5154 /* FIXXME: handle generics. */
5155 if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC) {
5156 MonoType *type = mono_type_create_from_typespec (image, token);
5157 token = mono_type_size (type, &align);
5158 mono_metadata_free_type (type);
5160 MonoClass *szclass = mono_class_get (image, token);
5161 mono_class_init (szclass);
5162 token = mono_class_value_size (szclass, &align);
5164 NEW_ICONST (cfg, ins, token);
5169 case CEE_REFANYTYPE:
5170 g_error ("opcode 0xfe 0x%02x not handled", ip [1]);
5176 g_error ("opcode 0xfe 0x%02x not handled", ip [1]);
5181 g_error ("opcode 0x%02x not handled", *ip);
5184 if (start_new_bblock != 1)
5187 bblock->cil_length = ip - bblock->cil_code;
5188 bblock->next_bb = end_bblock;
5189 link_bblock (cfg, bblock, end_bblock);
5191 if (cfg->method == method && cfg->domainvar) {
5195 MONO_INST_NEW_CALL (cfg, call, CEE_CALL);
5196 call->signature = helper_sig_domain_get;
5197 call->inst.type = STACK_PTR;
5198 call->fptr = mono_domain_get;
5199 NEW_TEMPSTORE (cfg, store, cfg->domainvar->inst_c0, (MonoInst*)call);
5201 MONO_ADD_INS (init_localsbb, store);
5204 if (header->init_locals) {
5206 for (i = 0; i < header->num_locals; ++i) {
5207 int t = header->locals [i]->type;
5208 if (t == MONO_TYPE_VALUETYPE && header->locals [i]->data.klass->enumtype)
5209 t = header->locals [i]->data.klass->enum_basetype->type;
5210 /* FIXME: use initobj for valuetypes, handle pointers, long, float. */
5211 if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
5212 NEW_ICONST (cfg, ins, 0);
5213 NEW_LOCSTORE (cfg, store, i, ins);
5214 MONO_ADD_INS (init_localsbb, store);
5215 } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
5216 MONO_INST_NEW (cfg, ins, OP_I8CONST);
5217 ins->type = STACK_I8;
5219 NEW_LOCSTORE (cfg, store, i, ins);
5220 MONO_ADD_INS (init_localsbb, store);
5221 } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
5222 MONO_INST_NEW (cfg, ins, OP_R8CONST);
5223 ins->type = STACK_R8;
5224 ins->inst_p0 = (void*)&r8_0;
5225 NEW_LOCSTORE (cfg, store, i, ins);
5226 MONO_ADD_INS (init_localsbb, store);
5227 } else if (t == MONO_TYPE_VALUETYPE) {
5228 NEW_LOCLOADA (cfg, ins, i);
5229 handle_initobj (cfg, init_localsbb, ins, NULL, mono_class_from_mono_type (header->locals [i]), NULL, NULL);
5232 NEW_PCONST (cfg, ins, NULL);
5233 NEW_LOCSTORE (cfg, store, i, ins);
5234 MONO_ADD_INS (init_localsbb, store);
5240 /* resolve backward branches in the middle of an existing basic block */
5241 for (tmp = bb_recheck; tmp; tmp = tmp->next) {
5243 /*g_print ("need recheck in %s at IL_%04x\n", method->name, bblock->cil_code - header->code);*/
5244 tblock = find_previous (bbhash, start_bblock, bblock->cil_code);
5245 if (tblock != start_bblock) {
5247 split_bblock (cfg, tblock, bblock);
5248 l = bblock->cil_code - header->code;
5249 bblock->cil_length = tblock->cil_length - l;
5250 tblock->cil_length = l;
5252 g_print ("recheck failed.\n");
5256 /* we compute regions here, because the length of filter clauses is not known in advance.
5257 * It is computed in the CEE_ENDFILTER case in the above switch statement*/
5258 if (cfg->method == method) {
5260 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
5261 bb->region = mono_find_block_region (cfg, bb->real_offset, filter_lengths);
5263 mono_create_spvar_for_region (cfg, bb->region);
5264 if (cfg->verbose_level > 2)
5265 g_print ("REGION BB%d IL_%04x ID_%08X\n", bb->block_num, bb->real_offset, bb->region);
5268 g_hash_table_destroy (bbhash);
5271 dont_inline = g_list_remove (dont_inline, method);
5272 return inline_costs;
5275 if (cfg->method != method)
5276 g_hash_table_destroy (bbhash);
5277 dont_inline = g_list_remove (dont_inline, method);
5281 if (cfg->method != method)
5282 g_hash_table_destroy (bbhash);
5283 g_error ("Invalid IL code at IL%04x in %s: %s\n", ip - header->code,
5284 mono_method_full_name (method, TRUE), mono_disasm_code_one (NULL, method, ip, NULL));
5285 dont_inline = g_list_remove (dont_inline, method);
5290 mono_print_tree (MonoInst *tree) {
5296 arity = mono_burg_arity [tree->opcode];
5298 printf (" %s%s", arity?"(":"", mono_inst_name (tree->opcode));
5300 switch (tree->opcode) {
5302 printf ("[%d]", tree->inst_c0);
5305 printf ("[%lld]", tree->inst_l);
5308 printf ("[%f]", *(double*)tree->inst_p0);
5311 printf ("[%f]", *(float*)tree->inst_p0);
5315 printf ("[%d]", tree->inst_c0);
5318 printf ("[0x%x(%s)]", tree->inst_offset, mono_arch_regname (tree->inst_basereg));
5321 printf ("[%s]", mono_arch_regname (tree->dreg));
5324 printf ("[%s]", tree->inst_newa_class->name);
5325 mono_print_tree (tree->inst_newa_len);
5336 case OP_VOIDCALLVIRT: {
5337 MonoCallInst *call = (MonoCallInst*)tree;
5339 printf ("[%s]", call->method->name);
5344 printf ("[%d (", tree->inst_c0);
5345 for (i = 0; i < tree->inst_phi_args [0]; i++) {
5348 printf ("%d", tree->inst_phi_args [i + 1]);
5360 printf ("[B%d]", tree->inst_target_bb->block_num);
5370 case OP_VOIDCALL_REG:
5371 mono_print_tree (tree->inst_left);
5383 printf ("[B%dB%d]", tree->inst_true_bb->block_num, tree->inst_false_bb->block_num);
5384 mono_print_tree (tree->inst_left);
5388 mono_print_tree (tree->inst_left);
5390 mono_print_tree (tree->inst_right);
5400 mono_print_tree_nl (MonoInst *tree)
5402 mono_print_tree (tree);
5407 create_helper_signature (void)
5409 /* FIXME: set call conv */
5410 /* MonoArray * mono_array_new (MonoDomain *domain, MonoClass *klass, gint32 len) */
5411 helper_sig_newarr = mono_metadata_signature_alloc (mono_defaults.corlib, 3);
5412 helper_sig_newarr->params [0] = helper_sig_newarr->params [1] = &mono_defaults.int_class->byval_arg;
5413 helper_sig_newarr->ret = &mono_defaults.object_class->byval_arg;
5414 helper_sig_newarr->params [2] = &mono_defaults.int32_class->byval_arg;
5415 helper_sig_newarr->pinvoke = 1;
5417 /* MonoArray * mono_array_new_specific (MonoVTable *vtable, guint32 len) */
5418 helper_sig_newarr_specific = mono_metadata_signature_alloc (mono_defaults.corlib, 2);
5419 helper_sig_newarr_specific->params [0] = &mono_defaults.int_class->byval_arg;
5420 helper_sig_newarr_specific->params [1] = &mono_defaults.int32_class->byval_arg;
5421 helper_sig_newarr_specific->ret = &mono_defaults.object_class->byval_arg;
5422 helper_sig_newarr_specific->pinvoke = 1;
5424 /* MonoObject * mono_object_new (MonoDomain *domain, MonoClass *klass) */
5425 helper_sig_object_new = mono_metadata_signature_alloc (mono_defaults.corlib, 2);
5426 helper_sig_object_new->params [0] = helper_sig_object_new->params [1] = &mono_defaults.int_class->byval_arg;
5427 helper_sig_object_new->ret = &mono_defaults.object_class->byval_arg;
5428 helper_sig_object_new->pinvoke = 1;
5430 /* MonoObject * mono_object_new_specific (MonoVTable *vtable) */
5431 helper_sig_object_new_specific = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
5432 helper_sig_object_new_specific->params [0] = &mono_defaults.int_class->byval_arg;
5433 helper_sig_object_new_specific->ret = &mono_defaults.object_class->byval_arg;
5434 helper_sig_object_new_specific->pinvoke = 1;
5436 /* void* mono_method_compile (MonoMethod*) */
5437 helper_sig_compile = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
5438 helper_sig_compile->params [0] = helper_sig_compile->ret = &mono_defaults.int_class->byval_arg;
5439 helper_sig_compile->pinvoke = 1;
5441 /* void* mono_ldvirtfn (MonoObject *, MonoMethod*) */
5442 helper_sig_compile_virt = mono_metadata_signature_alloc (mono_defaults.corlib, 2);
5443 helper_sig_compile_virt->params [0] = &mono_defaults.object_class->byval_arg;
5444 helper_sig_compile_virt->params [1] = helper_sig_compile_virt->ret = &mono_defaults.int_class->byval_arg;
5445 helper_sig_compile_virt->pinvoke = 1;
5447 /* MonoString* mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 str_index) */
5448 helper_sig_ldstr = mono_metadata_signature_alloc (mono_defaults.corlib, 3);
5449 helper_sig_ldstr->params [0] = helper_sig_ldstr->params [1] = &mono_defaults.int_class->byval_arg;
5450 helper_sig_ldstr->params [2] = &mono_defaults.int32_class->byval_arg;
5451 helper_sig_ldstr->ret = &mono_defaults.object_class->byval_arg;
5452 helper_sig_ldstr->pinvoke = 1;
5454 /* MonoDomain *mono_domain_get (void) */
5455 helper_sig_domain_get = mono_metadata_signature_alloc (mono_defaults.corlib, 0);
5456 helper_sig_domain_get->ret = &mono_defaults.int_class->byval_arg;
5457 helper_sig_domain_get->pinvoke = 1;
5459 /* void* stelem_ref (MonoArray *, int index, MonoObject *) */
5460 helper_sig_stelem_ref = mono_metadata_signature_alloc (mono_defaults.corlib, 3);
5461 helper_sig_stelem_ref->params [0] = &mono_defaults.array_class->byval_arg;
5462 helper_sig_stelem_ref->params [1] = &mono_defaults.int32_class->byval_arg;
5463 helper_sig_stelem_ref->params [2] = &mono_defaults.object_class->byval_arg;
5464 helper_sig_stelem_ref->ret = &mono_defaults.void_class->byval_arg;
5465 helper_sig_stelem_ref->pinvoke = 1;
5467 /* long amethod (long, long) */
5468 helper_sig_long_long_long = mono_metadata_signature_alloc (mono_defaults.corlib, 2);
5469 helper_sig_long_long_long->params [0] = helper_sig_long_long_long->params [1] =
5470 &mono_defaults.int64_class->byval_arg;
5471 helper_sig_long_long_long->ret = &mono_defaults.int64_class->byval_arg;
5472 helper_sig_long_long_long->pinvoke = 1;
5474 /* object amethod (intptr) */
5475 helper_sig_obj_ptr = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
5476 helper_sig_obj_ptr->params [0] = &mono_defaults.int_class->byval_arg;
5477 helper_sig_obj_ptr->ret = &mono_defaults.object_class->byval_arg;
5478 helper_sig_obj_ptr->pinvoke = 1;
5480 /* void amethod (intptr) */
5481 helper_sig_void_ptr = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
5482 helper_sig_void_ptr->params [0] = &mono_defaults.int_class->byval_arg;
5483 helper_sig_void_ptr->ret = &mono_defaults.void_class->byval_arg;
5484 helper_sig_void_ptr->pinvoke = 1;
5486 /* void amethod (MonoObject *obj) */
5487 helper_sig_void_obj = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
5488 helper_sig_void_obj->params [0] = &mono_defaults.object_class->byval_arg;
5489 helper_sig_void_obj->ret = &mono_defaults.void_class->byval_arg;
5490 helper_sig_void_obj->pinvoke = 1;
5492 /* intptr amethod (void) */
5493 helper_sig_ptr_void = mono_metadata_signature_alloc (mono_defaults.corlib, 0);
5494 helper_sig_ptr_void->ret = &mono_defaults.int_class->byval_arg;
5495 helper_sig_ptr_void->pinvoke = 1;
5497 /* void amethod (intptr, intptr) */
5498 helper_sig_void_ptr_ptr = mono_metadata_signature_alloc (mono_defaults.corlib, 2);
5499 helper_sig_void_ptr_ptr->params [0] = &mono_defaults.int_class->byval_arg;
5500 helper_sig_void_ptr_ptr->params [1] = &mono_defaults.int_class->byval_arg;
5501 helper_sig_void_ptr_ptr->ret = &mono_defaults.void_class->byval_arg;
5502 helper_sig_void_ptr_ptr->pinvoke = 1;
5504 /* void amethod (intptr, intptr, intptr) */
5505 helper_sig_void_ptr_ptr_ptr = mono_metadata_signature_alloc (mono_defaults.corlib, 3);
5506 helper_sig_void_ptr_ptr_ptr->params [0] = &mono_defaults.int_class->byval_arg;
5507 helper_sig_void_ptr_ptr_ptr->params [1] = &mono_defaults.int_class->byval_arg;
5508 helper_sig_void_ptr_ptr_ptr->params [2] = &mono_defaults.int_class->byval_arg;
5509 helper_sig_void_ptr_ptr_ptr->ret = &mono_defaults.void_class->byval_arg;
5510 helper_sig_void_ptr_ptr_ptr->pinvoke = 1;
5512 /* intptr amethod (intptr, intptr) */
5513 helper_sig_ptr_ptr_ptr = mono_metadata_signature_alloc (mono_defaults.corlib, 2);
5514 helper_sig_ptr_ptr_ptr->params [0] = &mono_defaults.int_class->byval_arg;
5515 helper_sig_ptr_ptr_ptr->params [1] = &mono_defaults.int_class->byval_arg;
5516 helper_sig_ptr_ptr_ptr->ret = &mono_defaults.int_class->byval_arg;
5517 helper_sig_ptr_ptr_ptr->pinvoke = 1;
5519 /* IntPtr amethod (object) */
5520 helper_sig_ptr_obj = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
5521 helper_sig_ptr_obj->params [0] = &mono_defaults.object_class->byval_arg;
5522 helper_sig_ptr_obj->ret = &mono_defaults.int_class->byval_arg;
5523 helper_sig_ptr_obj->pinvoke = 1;
5525 /* IntPtr amethod (int) */
5526 helper_sig_ptr_int = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
5527 helper_sig_ptr_int->params [0] = &mono_defaults.int32_class->byval_arg;
5528 helper_sig_ptr_int->ret = &mono_defaults.int_class->byval_arg;
5529 helper_sig_ptr_int->pinvoke = 1;
5531 /* long amethod (long, guint32) */
5532 helper_sig_long_long_int = mono_metadata_signature_alloc (mono_defaults.corlib, 2);
5533 helper_sig_long_long_int->params [0] = &mono_defaults.int64_class->byval_arg;
5534 helper_sig_long_long_int->params [1] = &mono_defaults.int32_class->byval_arg;
5535 helper_sig_long_long_int->ret = &mono_defaults.int64_class->byval_arg;
5536 helper_sig_long_long_int->pinvoke = 1;
5538 /* ulong amethod (double) */
5539 helper_sig_ulong_double = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
5540 helper_sig_ulong_double->params [0] = &mono_defaults.double_class->byval_arg;
5541 helper_sig_ulong_double->ret = &mono_defaults.uint64_class->byval_arg;
5542 helper_sig_ulong_double->pinvoke = 1;
5544 /* long amethod (double) */
5545 helper_sig_long_double = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
5546 helper_sig_long_double->params [0] = &mono_defaults.double_class->byval_arg;
5547 helper_sig_long_double->ret = &mono_defaults.int64_class->byval_arg;
5548 helper_sig_long_double->pinvoke = 1;
5550 /* uint amethod (double) */
5551 helper_sig_uint_double = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
5552 helper_sig_uint_double->params [0] = &mono_defaults.double_class->byval_arg;
5553 helper_sig_uint_double->ret = &mono_defaults.uint32_class->byval_arg;
5554 helper_sig_uint_double->pinvoke = 1;
5556 /* int amethod (double) */
5557 helper_sig_int_double = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
5558 helper_sig_int_double->params [0] = &mono_defaults.double_class->byval_arg;
5559 helper_sig_int_double->ret = &mono_defaults.int32_class->byval_arg;
5560 helper_sig_int_double->pinvoke = 1;
5562 /* void initobj (intptr, int size) */
5563 helper_sig_initobj = mono_metadata_signature_alloc (mono_defaults.corlib, 2);
5564 helper_sig_initobj->params [0] = &mono_defaults.int_class->byval_arg;
5565 helper_sig_initobj->params [1] = &mono_defaults.int32_class->byval_arg;
5566 helper_sig_initobj->ret = &mono_defaults.void_class->byval_arg;
5567 helper_sig_initobj->pinvoke = 1;
5569 /* void memcpy (intptr, intptr, int size) */
5570 helper_sig_memcpy = mono_metadata_signature_alloc (mono_defaults.corlib, 3);
5571 helper_sig_memcpy->params [0] = &mono_defaults.int_class->byval_arg;
5572 helper_sig_memcpy->params [1] = &mono_defaults.int_class->byval_arg;
5573 helper_sig_memcpy->params [2] = &mono_defaults.int32_class->byval_arg;
5574 helper_sig_memcpy->ret = &mono_defaults.void_class->byval_arg;
5575 helper_sig_memcpy->pinvoke = 1;
5577 /* void memset (intptr, int val, int size) */
5578 helper_sig_memset = mono_metadata_signature_alloc (mono_defaults.corlib, 3);
5579 helper_sig_memset->params [0] = &mono_defaults.int_class->byval_arg;
5580 helper_sig_memset->params [1] = &mono_defaults.int32_class->byval_arg;
5581 helper_sig_memset->params [2] = &mono_defaults.int32_class->byval_arg;
5582 helper_sig_memset->ret = &mono_defaults.void_class->byval_arg;
5583 helper_sig_memset->pinvoke = 1;
5585 helper_sig_class_init_trampoline = mono_metadata_signature_alloc (mono_defaults.corlib, 0);
5586 helper_sig_class_init_trampoline->ret = &mono_defaults.void_class->byval_arg;
5587 helper_sig_class_init_trampoline->pinvoke = 1;
5590 static GHashTable *jit_icall_hash_name = NULL;
5591 static GHashTable *jit_icall_hash_addr = NULL;
5594 mono_find_jit_icall_by_name (const char *name)
5596 g_assert (jit_icall_hash_name);
5598 //printf ("lookup addr %s %p\n", name, g_hash_table_lookup (jit_icall_hash_name, name));
5599 return g_hash_table_lookup (jit_icall_hash_name, name);
5603 mono_find_jit_icall_by_addr (gconstpointer addr)
5605 g_assert (jit_icall_hash_addr);
5607 return g_hash_table_lookup (jit_icall_hash_addr, (gpointer)addr);
5611 mono_icall_get_wrapper (MonoJitICallInfo* callinfo)
5614 MonoMethod *wrapper;
5616 if (callinfo->wrapper)
5617 return callinfo->wrapper;
5618 name = g_strdup_printf ("__icall_wrapper_%s", callinfo->name);
5619 wrapper = mono_marshal_get_icall_wrapper (callinfo->sig, name, callinfo->func);
5620 callinfo->wrapper = mono_jit_compile_method (wrapper);
5622 return callinfo->wrapper;
5626 mono_register_jit_icall (gconstpointer func, const char *name, MonoMethodSignature *sig, gboolean is_save)
5628 MonoJitICallInfo *info;
5633 if (!jit_icall_hash_name) {
5634 jit_icall_hash_name = g_hash_table_new (g_str_hash, g_str_equal);
5635 jit_icall_hash_addr = g_hash_table_new (NULL, NULL);
5638 if (g_hash_table_lookup (jit_icall_hash_name, name)) {
5639 g_warning ("jit icall already defined \"%s\"\n", name);
5640 g_assert_not_reached ();
5643 info = g_new (MonoJitICallInfo, 1);
5650 #ifdef MONO_USE_EXC_TABLES
5651 || mono_arch_has_unwind_info (func)
5654 info->wrapper = func;
5656 info->wrapper = NULL;
5657 mono_icall_get_wrapper (info);
5660 g_hash_table_insert (jit_icall_hash_name, (gpointer)info->name, info);
5661 g_hash_table_insert (jit_icall_hash_addr, (gpointer)func, info);
5662 if (func != info->wrapper)
5663 g_hash_table_insert (jit_icall_hash_addr, (gpointer)info->wrapper, info);
5669 mono_create_class_init_trampoline (MonoVTable *vtable)
5673 /* previously created trampoline code */
5674 mono_domain_lock (vtable->domain);
5676 mono_g_hash_table_lookup (vtable->domain->class_init_trampoline_hash,
5678 mono_domain_unlock (vtable->domain);
5682 code = mono_arch_create_class_init_trampoline (vtable);
5684 /* store trampoline address */
5685 mono_domain_lock (vtable->domain);
5686 mono_g_hash_table_insert (vtable->domain->class_init_trampoline_hash,
5688 mono_domain_unlock (vtable->domain);
5690 EnterCriticalSection (&class_init_hash_mutex);
5691 if (!class_init_hash_addr)
5692 class_init_hash_addr = g_hash_table_new (NULL, NULL);
5693 g_hash_table_insert (class_init_hash_addr, code, vtable);
5694 LeaveCriticalSection (&class_init_hash_mutex);
5700 mono_find_class_init_trampoline_by_addr (gconstpointer addr)
5702 if (class_init_hash_addr)
5703 return g_hash_table_lookup (class_init_hash_addr, addr);
5708 static GHashTable *emul_opcode_hash = NULL;
5710 static MonoJitICallInfo *
5711 mono_find_jit_opcode_emulation (int opcode)
5713 if (emul_opcode_hash)
5714 return g_hash_table_lookup (emul_opcode_hash, (gpointer)opcode);
5720 mono_register_opcode_emulation (int opcode, const char *name, MonoMethodSignature *sig, gpointer func, gboolean no_throw)
5722 MonoJitICallInfo *info;
5724 if (!emul_opcode_hash)
5725 emul_opcode_hash = g_hash_table_new (NULL, NULL);
5727 g_assert (!sig->hasthis);
5728 g_assert (sig->param_count < 3);
5730 info = mono_register_jit_icall (func, name, sig, no_throw);
5732 g_hash_table_insert (emul_opcode_hash, (gpointer)opcode, info);
5736 decompose_foreach (MonoInst *tree, gpointer data)
5738 static MonoJitICallInfo *newarr_info = NULL;
5739 static MonoJitICallInfo *newarr_specific_info = NULL;
5740 MonoJitICallInfo *info;
5743 switch (tree->opcode) {
5745 MonoCompile *cfg = data;
5746 MonoInst *iargs [3];
5749 newarr_info = mono_find_jit_icall_by_addr (mono_array_new);
5750 g_assert (newarr_info);
5751 newarr_specific_info = mono_find_jit_icall_by_addr (mono_array_new_specific);
5752 g_assert (newarr_specific_info);
5755 if (cfg->opt & MONO_OPT_SHARED) {
5756 NEW_DOMAINCONST (cfg, iargs [0]);
5757 NEW_CLASSCONST (cfg, iargs [1], tree->inst_newa_class);
5758 iargs [2] = tree->inst_newa_len;
5763 MonoVTable *vtable = mono_class_vtable (cfg->domain, mono_array_class_get (tree->inst_newa_class, 1));
5765 NEW_VTABLECONST (cfg, iargs [0], vtable);
5766 iargs [1] = tree->inst_newa_len;
5768 info = newarr_specific_info;
5771 mono_emulate_opcode (cfg, tree, iargs, info);
5773 /* Need to decompose arguments after the the opcode is decomposed */
5774 for (i = 0; i < info->sig->param_count; ++i)
5775 dec_foreach (iargs [i], cfg);
5785 mono_inst_foreach (MonoInst *tree, MonoInstFunc func, gpointer data) {
5787 switch (mono_burg_arity [tree->opcode]) {
5790 mono_inst_foreach (tree->inst_left, func, data);
5793 mono_inst_foreach (tree->inst_left, func, data);
5794 mono_inst_foreach (tree->inst_right, func, data);
5797 g_assert_not_reached ();
5804 mono_print_bb_code (MonoBasicBlock *bb) {
5806 MonoInst *c = bb->code;
5808 mono_print_tree (c);
5817 print_dfn (MonoCompile *cfg) {
5822 g_print ("IR code for method %s\n", mono_method_full_name (cfg->method, TRUE));
5824 for (i = 0; i < cfg->num_bblocks; ++i) {
5825 bb = cfg->bblocks [i];
5827 char* code1, *code2;
5828 code1 = mono_disasm_code_one (NULL, cfg->method, bb->cil_code, NULL);
5829 if (bb->last_ins->cil_code)
5830 code2 = mono_disasm_code_one (NULL, cfg->method, bb->last_ins->cil_code, NULL);
5832 code2 = g_strdup ("");
5834 code1 [strlen (code1) - 1] = 0;
5835 code = g_strdup_printf ("%s -> %s", code1, code2);
5839 code = g_strdup ("\n");
5840 g_print ("\nBB%d DFN%d (len: %d): %s", bb->block_num, i, bb->cil_length, code);
5842 MonoInst *c = bb->code;
5844 mono_print_tree (c);
5852 g_print ("\tprev:");
5853 for (j = 0; j < bb->in_count; ++j) {
5854 g_print (" BB%d", bb->in_bb [j]->block_num);
5856 g_print ("\t\tsucc:");
5857 for (j = 0; j < bb->out_count; ++j) {
5858 g_print (" BB%d", bb->out_bb [j]->block_num);
5860 g_print ("\n\tidom: BB%d\n", bb->idom? bb->idom->block_num: -1);
5863 g_assert (mono_bitset_test_fast (bb->dominators, bb->idom->dfn));
5866 mono_blockset_print (cfg, bb->dominators, "\tdominators", bb->idom? bb->idom->dfn: -1);
5868 mono_blockset_print (cfg, bb->dfrontier, "\tdfrontier", -1);
5876 * returns the offset used by spillvar. It allocates a new
5877 * spill variable if necessary.
5880 mono_spillvar_offset (MonoCompile *cfg, int spillvar)
5882 MonoSpillInfo **si, *info;
5885 si = &cfg->spill_info;
5887 while (i <= spillvar) {
5890 *si = info = mono_mempool_alloc (cfg->mempool, sizeof (MonoSpillInfo));
5892 cfg->stack_offset -= sizeof (gpointer);
5893 info->offset = cfg->stack_offset;
5897 return (*si)->offset;
5903 g_assert_not_reached ();
5908 mono_bblock_add_inst (MonoBasicBlock *bb, MonoInst *inst)
5912 g_assert (bb->code);
5913 bb->last_ins->next = inst;
5914 bb->last_ins = inst;
5916 bb->last_ins = bb->code = inst;
5921 mono_destroy_compile (MonoCompile *cfg)
5923 //mono_mempool_stats (cfg->mempool);
5924 g_hash_table_destroy (cfg->bb_hash);
5926 mono_regstate_free (cfg->rs);
5928 g_hash_table_destroy (cfg->spvars);
5929 mono_mempool_destroy (cfg->mempool);
5930 g_list_free (cfg->ldstr_list);
5932 g_free (cfg->varinfo);
5938 mono_get_lmf_addr (void)
5940 MonoJitTlsData *jit_tls;
5942 if ((jit_tls = TlsGetValue (mono_jit_tls_id)))
5943 return &jit_tls->lmf;
5945 g_assert_not_reached ();
5950 * mono_thread_abort:
5951 * @obj: exception object
5953 * abort the thread, print exception information and stack trace
5956 mono_thread_abort (MonoObject *obj)
5958 /* MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id); */
5960 /* handle_remove should be eventually called for this thread, too
5967 setup_jit_tls_data (gpointer stack_start, gpointer abort_func)
5969 MonoJitTlsData *jit_tls;
5972 jit_tls = g_new0 (MonoJitTlsData, 1);
5974 TlsSetValue (mono_jit_tls_id, jit_tls);
5976 jit_tls->abort_func = abort_func;
5977 jit_tls->end_of_stack = stack_start;
5979 lmf = g_new0 (MonoLMF, 1);
5982 jit_tls->lmf = jit_tls->first_lmf = lmf;
5987 mono_thread_start_cb (guint32 tid, gpointer stack_start, gpointer func)
5990 void *jit_tls = setup_jit_tls_data (stack_start, mono_thread_abort);
5991 thread = mono_thread_current ();
5993 thread->jit_data = jit_tls;
5996 void (*mono_thread_attach_aborted_cb ) (MonoObject *obj) = NULL;
5999 mono_thread_abort_dummy (MonoObject *obj)
6001 if (mono_thread_attach_aborted_cb)
6002 mono_thread_attach_aborted_cb (obj);
6004 mono_thread_abort (obj);
6008 mono_thread_attach_cb (guint32 tid, gpointer stack_start)
6011 void *jit_tls = setup_jit_tls_data (stack_start, mono_thread_abort_dummy);
6012 thread = mono_thread_current ();
6014 thread->jit_data = jit_tls;
6018 mini_thread_cleanup (MonoThread *thread)
6020 MonoJitTlsData *jit_tls = thread->jit_data;
6023 g_free (jit_tls->first_lmf);
6025 thread->jit_data = NULL;
6030 mono_add_patch_info (MonoCompile *cfg, int ip, MonoJumpInfoType type, gconstpointer target)
6032 MonoJumpInfo *ji = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfo));
6036 ji->data.target = target;
6037 ji->next = cfg->patch_info;
6039 cfg->patch_info = ji;
6043 mono_remove_patch_info (MonoCompile *cfg, int ip)
6045 MonoJumpInfo **ji = &cfg->patch_info;
6048 if ((*ji)->ip.i == ip)
6051 ji = &((*ji)->next);
6056 dec_foreach (MonoInst *tree, MonoCompile *cfg) {
6057 MonoJitICallInfo *info;
6059 decompose_foreach (tree, cfg);
6061 switch (mono_burg_arity [tree->opcode]) {
6064 dec_foreach (tree->inst_left, cfg);
6066 if ((info = mono_find_jit_opcode_emulation (tree->opcode))) {
6067 MonoInst *iargs [2];
6069 iargs [0] = tree->inst_left;
6071 mono_emulate_opcode (cfg, tree, iargs, info);
6077 if (tree->opcode == OP_LMUL
6078 && (cfg->opt & MONO_OPT_INTRINS)
6079 && (tree->inst_left->opcode == CEE_CONV_I8
6080 || tree->inst_left->opcode == CEE_CONV_U8)
6081 && tree->inst_left->inst_left->type == STACK_I4
6082 && (tree->inst_right->opcode == CEE_CONV_I8
6083 || tree->inst_right->opcode == CEE_CONV_U8)
6084 && tree->inst_right->inst_left->type == STACK_I4) {
6085 tree->opcode = (tree->inst_left->opcode == CEE_CONV_I8 ? OP_BIGMUL: OP_BIGMUL_UN);
6086 tree->inst_left = tree->inst_left->inst_left;
6087 tree->inst_right = tree->inst_right->inst_left;
6088 dec_foreach (tree, cfg);
6089 } else if ((info = mono_find_jit_opcode_emulation (tree->opcode))) {
6090 MonoInst *iargs [2];
6092 iargs [0] = tree->inst_i0;
6093 iargs [1] = tree->inst_i1;
6095 mono_emulate_opcode (cfg, tree, iargs, info);
6097 dec_foreach (iargs [0], cfg);
6098 dec_foreach (iargs [1], cfg);
6101 dec_foreach (tree->inst_left, cfg);
6102 dec_foreach (tree->inst_right, cfg);
6106 g_assert_not_reached ();
6111 decompose_pass (MonoCompile *cfg) {
6114 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
6117 cfg->prev_ins = NULL;
6118 for (tree = cfg->cbb->code; tree; tree = tree->next) {
6119 dec_foreach (tree, cfg);
6120 cfg->prev_ins = tree;
6126 nullify_basic_block (MonoBasicBlock *bb)
6133 bb->code = bb->last_ins = NULL;
6134 bb->cil_code = NULL;
6138 replace_out_block (MonoBasicBlock *bb, MonoBasicBlock *orig, MonoBasicBlock *repl)
6142 for (i = 0; i < bb->out_count; i++) {
6143 MonoBasicBlock *ob = bb->out_bb [i];
6146 if (bb->out_count > 1) {
6147 bb->out_bb [i] = bb->out_bb [bb->out_count - 1];
6151 bb->out_bb [i] = repl;
6158 replace_in_block (MonoBasicBlock *bb, MonoBasicBlock *orig, MonoBasicBlock *repl)
6162 for (i = 0; i < bb->in_count; i++) {
6163 MonoBasicBlock *ib = bb->in_bb [i];
6166 if (bb->in_count > 1) {
6167 bb->in_bb [i] = bb->in_bb [bb->in_count - 1];
6171 bb->in_bb [i] = repl;
6178 replace_basic_block (MonoBasicBlock *bb, MonoBasicBlock *orig, MonoBasicBlock *repl)
6182 for (i = 0; i < bb->out_count; i++) {
6183 MonoBasicBlock *ob = bb->out_bb [i];
6184 for (j = 0; j < ob->in_count; j++) {
6185 if (ob->in_bb [j] == orig) {
6186 ob->in_bb [j] = repl;
6195 merge_basic_blocks (MonoBasicBlock *bb, MonoBasicBlock *bbn)
6197 bb->out_count = bbn->out_count;
6198 bb->out_bb = bbn->out_bb;
6200 replace_basic_block (bb, bbn, bb);
6204 bb->last_ins->next = bbn->code;
6205 bb->last_ins = bbn->last_ins;
6208 bb->code = bbn->code;
6209 bb->last_ins = bbn->last_ins;
6211 bb->next_bb = bbn->next_bb;
6212 nullify_basic_block (bbn);
6216 optimize_branches (MonoCompile *cfg) {
6217 int i, changed = FALSE;
6218 MonoBasicBlock *bb, *bbn;
6223 /* we skip the entry block (exit is handled specially instead ) */
6224 for (bb = cfg->bb_entry->next_bb; bb; bb = bb->next_bb) {
6226 /* dont touch code inside exception clauses */
6227 if (bb->region != -1)
6230 if ((bbn = bb->next_bb) && bbn->in_count == 0 && bb->region == bbn->region) {
6231 if (cfg->verbose_level > 2)
6232 g_print ("nullify block triggered %d\n", bbn->block_num);
6234 bb->next_bb = bbn->next_bb;
6236 for (i = 0; i < bbn->out_count; i++)
6237 replace_in_block (bbn->out_bb [i], bbn, NULL);
6239 nullify_basic_block (bbn);
6243 if (bb->out_count == 1) {
6244 bbn = bb->out_bb [0];
6246 /* conditional branches where true and false targets are the same can be also replaced with CEE_BR */
6247 if (bb->last_ins && MONO_IS_COND_BRANCH (bb->last_ins->opcode)) {
6248 bb->last_ins->opcode = CEE_BR;
6249 bb->last_ins->inst_target_bb = bb->last_ins->inst_true_bb;
6251 if (cfg->verbose_level > 2)
6252 g_print ("cond branch removal triggered in %d %d\n", bb->block_num, bb->out_count);
6255 if (bb->region == bbn->region && bb->next_bb == bbn) {
6256 /* the block are in sequence anyway ... */
6258 /* branches to the following block can be removed */
6259 if (bb->last_ins && bb->last_ins->opcode == CEE_BR) {
6260 bb->last_ins->opcode = CEE_NOP;
6262 if (cfg->verbose_level > 2)
6263 g_print ("br removal triggered %d -> %d\n", bb->block_num, bbn->block_num);
6266 if (bbn->in_count == 1) {
6268 if (bbn != cfg->bb_exit) {
6269 if (cfg->verbose_level > 2)
6270 g_print ("block merge triggered %d -> %d\n", bb->block_num, bbn->block_num);
6271 merge_basic_blocks (bb, bbn);
6275 //mono_print_bb_code (bb);
6285 /* we skip the entry block (exit is handled specially instead ) */
6286 for (bb = cfg->bb_entry->next_bb; bb; bb = bb->next_bb) {
6288 /* dont touch code inside exception clauses */
6289 if (bb->region != -1)
6292 if ((bbn = bb->next_bb) && bbn->in_count == 0 && bb->region == bbn->region) {
6293 if (cfg->verbose_level > 2) {
6294 g_print ("nullify block triggered %d\n", bbn->block_num);
6296 bb->next_bb = bbn->next_bb;
6298 for (i = 0; i < bbn->out_count; i++)
6299 replace_in_block (bbn->out_bb [i], bbn, NULL);
6301 nullify_basic_block (bbn);
6307 if (bb->out_count == 1) {
6308 bbn = bb->out_bb [0];
6310 if (bb->last_ins && bb->last_ins->opcode == CEE_BR) {
6311 bbn = bb->last_ins->inst_target_bb;
6312 if (bb->region == bbn->region && bbn->code && bbn->code->opcode == CEE_BR &&
6313 bbn->code->inst_target_bb->region == bb->region) {
6315 if (cfg->verbose_level > 2)
6316 g_print ("in %s branch to branch triggered %d -> %d\n", cfg->method->name,
6317 bb->block_num, bbn->block_num);
6319 replace_basic_block (bb, bb->out_bb [0], bbn->code->inst_target_bb);
6320 bb->last_ins->inst_target_bb = bbn->code->inst_target_bb;
6325 } else if (bb->out_count == 2) {
6326 if (bb->last_ins && MONO_IS_COND_BRANCH (bb->last_ins->opcode)) {
6327 bbn = bb->last_ins->inst_true_bb;
6328 if (bb->region == bbn->region && bbn->code && bbn->code->opcode == CEE_BR &&
6329 bbn->code->inst_target_bb->region == bb->region) {
6330 if (cfg->verbose_level > 2)
6331 g_print ("cbranch1 to branch triggered %d -> (%d) %d (0x%02x)\n",
6332 bb->block_num, bbn->block_num, bbn->code->inst_target_bb->block_num,
6335 bb->last_ins->inst_true_bb = bbn->code->inst_target_bb;
6337 replace_in_block (bbn, bb, NULL);
6339 replace_in_block (bbn->code->inst_target_bb, bbn, bb);
6340 replace_out_block (bb, bbn, bbn->code->inst_target_bb);
6342 link_bblock (cfg, bb, bbn->code->inst_target_bb);
6348 bbn = bb->last_ins->inst_false_bb;
6349 if (bb->region == bbn->region && bbn->code && bbn->code->opcode == CEE_BR &&
6350 bbn->code->inst_target_bb->region == bb->region) {
6351 if (cfg->verbose_level > 2)
6352 g_print ("cbranch2 to branch triggered %d -> (%d) %d (0x%02x)\n",
6353 bb->block_num, bbn->block_num, bbn->code->inst_target_bb->block_num,
6356 bb->last_ins->inst_false_bb = bbn->code->inst_target_bb;
6358 replace_in_block (bbn, bb, NULL);
6360 replace_in_block (bbn->code->inst_target_bb, bbn, bb);
6361 replace_out_block (bb, bbn, bbn->code->inst_target_bb);
6363 link_bblock (cfg, bb, bbn->code->inst_target_bb);
6376 mono_compile_create_vars (MonoCompile *cfg)
6378 MonoMethodSignature *sig;
6379 MonoMethodHeader *header;
6382 header = ((MonoMethodNormal *)cfg->method)->header;
6384 sig = cfg->method->signature;
6386 if (!MONO_TYPE_IS_VOID (sig->ret)) {
6387 cfg->ret = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst));
6388 cfg->ret->opcode = OP_RETARG;
6389 cfg->ret->inst_vtype = sig->ret;
6390 cfg->ret->klass = mono_class_from_mono_type (sig->ret);
6392 if (cfg->verbose_level > 2)
6393 g_print ("creating vars\n");
6396 mono_compile_create_var (cfg, &cfg->method->klass->this_arg, OP_ARG);
6398 for (i = 0; i < sig->param_count; ++i)
6399 mono_compile_create_var (cfg, sig->params [i], OP_ARG);
6401 cfg->locals_start = cfg->num_varinfo;
6403 if (cfg->verbose_level > 2)
6404 g_print ("creating locals\n");
6405 for (i = 0; i < header->num_locals; ++i)
6406 mono_compile_create_var (cfg, header->locals [i], OP_LOCAL);
6407 if (cfg->verbose_level > 2)
6408 g_print ("locals done\n");
6412 mono_print_code (MonoCompile *cfg)
6416 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
6417 MonoInst *tree = bb->code;
6422 g_print ("CODE BLOCK %d (nesting %d):\n", bb->block_num, bb->nesting);
6424 for (; tree; tree = tree->next) {
6425 mono_print_tree (tree);
6430 bb->last_ins->next = NULL;
6434 extern const char * const mono_burg_rule_string [];
6437 emit_state (MonoCompile *cfg, MBState *state, int goal)
6440 int ern = mono_burg_rule (state, goal);
6441 const guint16 *nts = mono_burg_nts [ern];
6444 //g_print ("rule: %s\n", mono_burg_rule_string [ern]);
6448 // state->reg1 = state->reg2; /* chain rule */
6450 state->reg1 = mono_regstate_next_int (cfg->rs);
6451 //g_print ("alloc symbolic R%d (reg2: R%d) in block %d\n", state->reg1, state->reg2, cfg->cbb->block_num);
6454 state->reg1 = mono_regstate_next_int (cfg->rs);
6455 state->reg2 = mono_regstate_next_int (cfg->rs);
6458 state->reg1 = mono_regstate_next_float (cfg->rs);
6465 mono_burg_kids (state, ern, kids);
6467 emit_state (cfg, kids [0], nts [0]);
6469 emit_state (cfg, kids [1], nts [1]);
6471 g_assert (!nts [3]);
6472 emit_state (cfg, kids [2], nts [2]);
6477 // g_print ("emit: %s (%p)\n", mono_burg_rule_string [ern], state);
6478 if ((emit = mono_burg_func [ern]))
6479 emit (state, state->tree, cfg);
6482 #define DEBUG_SELECTION
6485 mini_select_instructions (MonoCompile *cfg)
6487 static int reverse_map [] = {
6488 CEE_BNE_UN, CEE_BLT, CEE_BLE, CEE_BGT, CEE_BGE,
6489 CEE_BEQ, CEE_BLT_UN, CEE_BLE_UN, CEE_BGT_UN, CEE_BGE_UN
6491 static int reverse_fmap [] = {
6492 OP_FBNE_UN, OP_FBLT, OP_FBLE, OP_FBGT, OP_FBGE,
6493 OP_FBEQ, OP_FBLT_UN, OP_FBLE_UN, OP_FBGT_UN, OP_FBGE_UN
6495 static int reverse_lmap [] = {
6496 OP_LBNE_UN, OP_LBLT, OP_LBLE, OP_LBGT, OP_LBGE,
6497 OP_LBEQ, OP_LBLT_UN, OP_LBLE_UN, OP_LBGT_UN, OP_LBGE_UN
6502 cfg->state_pool = mono_mempool_new ();
6503 cfg->rs = mono_regstate_new ();
6505 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
6506 if (bb->last_ins && MONO_IS_COND_BRANCH (bb->last_ins->opcode) &&
6507 bb->next_bb != bb->last_ins->inst_false_bb) {
6509 if (bb->next_bb == bb->last_ins->inst_true_bb) {
6510 MonoBasicBlock *tmp = bb->last_ins->inst_true_bb;
6511 bb->last_ins->inst_true_bb = bb->last_ins->inst_false_bb;
6512 bb->last_ins->inst_false_bb = tmp;
6514 if (bb->last_ins->opcode >= CEE_BEQ && bb->last_ins->opcode <= CEE_BLT_UN) {
6515 bb->last_ins->opcode = reverse_map [bb->last_ins->opcode - CEE_BEQ];
6516 } else if (bb->last_ins->opcode >= OP_FBEQ && bb->last_ins->opcode <= OP_FBLT_UN) {
6517 bb->last_ins->opcode = reverse_fmap [bb->last_ins->opcode - OP_FBEQ];
6518 } else if (bb->last_ins->opcode >= OP_LBEQ && bb->last_ins->opcode <= OP_LBLT_UN) {
6519 bb->last_ins->opcode = reverse_lmap [bb->last_ins->opcode - OP_LBEQ];
6522 MonoInst *inst = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst));
6523 inst->opcode = CEE_BR;
6524 inst->inst_target_bb = bb->last_ins->inst_false_bb;
6525 mono_bblock_add_inst (bb, inst);
6530 #ifdef DEBUG_SELECTION
6531 if (cfg->verbose_level >= 4) {
6532 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
6533 MonoInst *tree = bb->code;
6534 g_print ("DUMP BLOCK %d:\n", bb->block_num);
6537 for (; tree; tree = tree->next) {
6538 mono_print_tree (tree);
6545 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
6546 MonoInst *tree = bb->code, *next;
6552 bb->last_ins = NULL;
6555 mono_regstate_reset (cfg->rs);
6557 #ifdef DEBUG_SELECTION
6558 if (cfg->verbose_level >= 3)
6559 g_print ("LABEL BLOCK %d:\n", bb->block_num);
6561 for (; tree; tree = next) {
6563 #ifdef DEBUG_SELECTION
6564 if (cfg->verbose_level >= 3) {
6565 mono_print_tree (tree);
6570 if (!(mbstate = mono_burg_label (tree, cfg))) {
6571 g_warning ("unable to label tree %p", tree);
6572 mono_print_tree (tree);
6574 g_assert_not_reached ();
6576 emit_state (cfg, mbstate, MB_NTERM_stmt);
6578 bb->max_ireg = cfg->rs->next_vireg;
6579 bb->max_freg = cfg->rs->next_vfreg;
6582 bb->last_ins->next = NULL;
6584 mono_mempool_empty (cfg->state_pool);
6586 mono_mempool_destroy (cfg->state_pool);
6590 mono_codegen (MonoCompile *cfg)
6592 MonoJumpInfo *patch_info;
6594 int i, max_epilog_size;
6597 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
6598 cfg->spill_count = 0;
6599 /* we reuse dfn here */
6600 /* bb->dfn = bb_count++; */
6601 mono_arch_local_regalloc (cfg, bb);
6604 if (cfg->prof_options & MONO_PROFILE_COVERAGE)
6605 cfg->coverage_info = mono_profiler_coverage_alloc (cfg->method, cfg->num_bblocks);
6607 code = mono_arch_emit_prolog (cfg);
6609 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
6610 code = mono_arch_instrument_prolog (cfg, mono_profiler_method_enter, code, FALSE);
6612 cfg->code_len = code - cfg->native_code;
6613 cfg->prolog_end = cfg->code_len;
6615 mono_debug_open_method (cfg);
6617 /* emit code all basic blocks */
6618 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
6619 bb->native_offset = cfg->code_len;
6620 mono_arch_output_basic_block (cfg, bb);
6622 cfg->bb_exit->native_offset = cfg->code_len;
6624 code = cfg->native_code + cfg->code_len;
6626 max_epilog_size = mono_arch_max_epilog_size (cfg);
6628 /* we always allocate code in cfg->domain->code_mp to increase locality */
6629 cfg->code_size = cfg->code_len + max_epilog_size;
6630 /* fixme: align to MONO_ARCH_CODE_ALIGNMENT */
6631 code = mono_mempool_alloc (cfg->domain->code_mp, cfg->code_size);
6632 memcpy (code, cfg->native_code, cfg->code_len);
6633 g_free (cfg->native_code);
6634 cfg->native_code = code;
6635 code = cfg->native_code + cfg->code_len;
6637 /* g_assert (((int)cfg->native_code & (MONO_ARCH_CODE_ALIGNMENT - 1)) == 0); */
6639 cfg->epilog_begin = cfg->code_len;
6641 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
6642 code = mono_arch_instrument_epilog (cfg, mono_profiler_method_leave, code, FALSE);
6644 cfg->code_len = code - cfg->native_code;
6646 mono_arch_emit_epilog (cfg);
6648 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
6649 switch (patch_info->type) {
6650 case MONO_PATCH_INFO_ABS: {
6651 MonoJitICallInfo *info = mono_find_jit_icall_by_addr (patch_info->data.target);
6653 //printf ("TEST %s %p\n", info->name, patch_info->data.target);
6654 patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
6655 patch_info->data.name = info->name;
6658 MonoVTable *vtable = mono_find_class_init_trampoline_by_addr (patch_info->data.target);
6660 patch_info->type = MONO_PATCH_INFO_CLASS_INIT;
6661 patch_info->data.klass = vtable->klass;
6666 case MONO_PATCH_INFO_SWITCH: {
6667 gpointer *table = mono_mempool_alloc (cfg->domain->code_mp, sizeof (gpointer) * patch_info->table_size);
6668 patch_info->ip.i = patch_info->ip.label->inst_c0;
6669 for (i = 0; i < patch_info->table_size; i++) {
6670 table [i] = (gpointer)patch_info->data.table [i]->native_offset;
6672 patch_info->data.target = table;
6681 if (cfg->verbose_level > 1)
6682 g_print ("Method %s emmitted at %p to %p\n",
6683 mono_method_full_name (cfg->method, TRUE),
6684 cfg->native_code, cfg->native_code + cfg->code_len);
6686 mono_arch_patch_code (cfg->method, cfg->domain, cfg->native_code, cfg->patch_info);
6688 mono_debug_close_method (cfg);
6692 mono_cprop_copy_values (MonoCompile *cfg, MonoInst *tree, MonoInst **acp)
6697 if (tree->ssa_op == MONO_SSA_LOAD && (tree->inst_i0->opcode == OP_LOCAL || tree->inst_i0->opcode == OP_ARG) &&
6698 (cp = acp [tree->inst_i0->inst_c0]) && !tree->inst_i0->flags) {
6700 if (cp->opcode == OP_ICONST) {
6701 if (cfg->opt & MONO_OPT_CONSPROP) {
6702 //{ static int c = 0; printf ("CCOPY %d %d %s\n", c++, cp->inst_c0, mono_method_full_name (cfg->method, TRUE)); }
6706 if (tree->inst_i0->inst_vtype->type == cp->inst_vtype->type) {
6707 if (cfg->opt & MONO_OPT_COPYPROP) {
6708 //{ static int c = 0; printf ("VCOPY %d\n", ++c); }
6714 arity = mono_burg_arity [tree->opcode];
6717 mono_cprop_copy_values (cfg, tree->inst_i0, acp);
6718 if (cfg->opt & MONO_OPT_CFOLD)
6719 mono_constant_fold_inst (tree, NULL);
6721 mono_cprop_copy_values (cfg, tree->inst_i1, acp);
6722 if (cfg->opt & MONO_OPT_CFOLD)
6723 mono_constant_fold_inst (tree, NULL);
6725 mono_constant_fold_inst (tree, NULL);
6731 mono_cprop_invalidate_values (MonoInst *tree, MonoInst **acp, int acp_size)
6735 switch (tree->opcode) {
6745 if (tree->ssa_op == MONO_SSA_NOP) {
6746 memset (acp, 0, sizeof (MonoInst *) * acp_size);
6763 case OP_VOIDCALL_REG:
6764 case OP_VOIDCALLVIRT:
6766 MonoCallInst *call = (MonoCallInst *)tree;
6767 MonoMethodSignature *sig = call->signature;
6768 int i, byref = FALSE;
6770 for (i = 0; i < sig->param_count; i++) {
6771 if (sig->params [i]->byref) {
6778 memset (acp, 0, sizeof (MonoInst *) * acp_size);
6786 arity = mono_burg_arity [tree->opcode];
6792 mono_cprop_invalidate_values (tree->inst_i0, acp, acp_size);
6795 mono_cprop_invalidate_values (tree->inst_i0, acp, acp_size);
6796 mono_cprop_invalidate_values (tree->inst_i1, acp, acp_size);
6799 g_assert_not_reached ();
6804 mono_local_cprop_bb (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst **acp, int acp_size)
6806 MonoInst *tree = bb->code;
6812 for (; tree; tree = tree->next) {
6814 mono_cprop_copy_values (cfg, tree, acp);
6816 mono_cprop_invalidate_values (tree, acp, acp_size);
6818 if (tree->ssa_op == MONO_SSA_STORE &&
6819 (tree->inst_i0->opcode == OP_LOCAL || tree->inst_i0->opcode == OP_ARG)) {
6820 MonoInst *i1 = tree->inst_i1;
6822 acp [tree->inst_i0->inst_c0] = NULL;
6824 for (i = 0; i < acp_size; i++) {
6825 if (acp [i] && acp [i]->opcode != OP_ICONST &&
6826 acp [i]->inst_c0 == tree->inst_i0->inst_c0) {
6831 if (i1->opcode == OP_ICONST) {
6832 acp [tree->inst_i0->inst_c0] = i1;
6833 //printf ("DEF1 BB%d %d\n", bb->block_num,tree->inst_i0->inst_c0);
6835 if (i1->ssa_op == MONO_SSA_LOAD &&
6836 (i1->inst_i0->opcode == OP_LOCAL || i1->inst_i0->opcode == OP_ARG) &&
6837 (i1->inst_i0->inst_c0 != tree->inst_i0->inst_c0)) {
6838 acp [tree->inst_i0->inst_c0] = i1->inst_i0;
6839 //printf ("DEF2 BB%d %d %d\n", bb->block_num,tree->inst_i0->inst_c0,i1->inst_i0->inst_c0);
6844 if (tree->opcode == CEE_BEQ) {
6845 g_assert (tree->inst_i0->opcode == OP_COMPARE);
6846 if (tree->inst_i0->inst_i0->opcode == OP_ICONST &&
6847 tree->inst_i0->inst_i1->opcode == OP_ICONST) {
6849 tree->opcode = CEE_BR;
6850 if (tree->inst_i0->inst_i0->opcode == tree->inst_i0->inst_i1->opcode) {
6851 tree->inst_target_bb = tree->inst_true_bb;
6853 tree->inst_target_bb = tree->inst_false_bb;
6862 mono_local_cprop (MonoCompile *cfg)
6867 acp = alloca (sizeof (MonoInst *) * cfg->num_varinfo);
6869 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
6870 memset (acp, 0, sizeof (MonoInst *) * cfg->num_varinfo);
6871 mono_local_cprop_bb (cfg, bb, acp, cfg->num_varinfo);
6876 mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, int parts)
6878 MonoMethodHeader *header = ((MonoMethodNormal *)method)->header;
6879 guint8 *ip = (guint8 *)header->code;
6882 int dfn = 0, i, code_size_ratio;
6884 mono_jit_stats.methods_compiled++;
6885 if (mono_profiler_get_events () & MONO_PROFILE_JIT_COMPILATION)
6886 mono_profiler_method_jit (method);
6888 cfg = g_new0 (MonoCompile, 1);
6889 cfg->method = method;
6890 cfg->mempool = mono_mempool_new ();
6892 cfg->prof_options = mono_profiler_get_events ();
6893 cfg->bb_hash = g_hash_table_new (NULL, NULL);
6894 cfg->domain = domain;
6895 cfg->verbose_level = mini_verbose;
6896 cfg->intvars = mono_mempool_alloc0 (cfg->mempool, sizeof (guint16) * STACK_MAX *
6897 ((MonoMethodNormal *)method)->header->max_stack);
6899 if (cfg->verbose_level > 2)
6900 g_print ("converting method %s\n", mono_method_full_name (method, TRUE));
6903 * create MonoInst* which represents arguments and local variables
6905 mono_compile_create_vars (cfg);
6907 if ((i = mono_method_to_ir (cfg, method, NULL, NULL, cfg->locals_start, NULL, NULL, NULL, 0, FALSE)) < 0) {
6908 if (cfg->prof_options & MONO_PROFILE_JIT_COMPILATION)
6909 mono_profiler_method_end_jit (method, MONO_PROFILE_FAILED);
6910 mono_destroy_compile (cfg);
6914 mono_jit_stats.basic_blocks += cfg->num_bblocks;
6915 mono_jit_stats.max_basic_blocks = MAX (cfg->num_bblocks, mono_jit_stats.max_basic_blocks);
6917 if (cfg->num_varinfo > 2000) {
6919 * we disable some optimizations if there are too many variables
6920 * because JIT time may become too expensive. The actual number needs
6921 * to be tweaked and eventually the non-linear algorithms should be fixed.
6923 cfg->opt &= ~ (MONO_OPT_LINEARS | MONO_OPT_COPYPROP | MONO_OPT_CONSPROP);
6924 cfg->disable_ssa = TRUE;
6926 /*g_print ("numblocks = %d\n", cfg->num_bblocks);*/
6928 /* Depth-first ordering on basic blocks */
6929 cfg->bblocks = mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * (cfg->num_bblocks + 1));
6931 if (cfg->opt & MONO_OPT_BRANCH)
6932 optimize_branches (cfg);
6934 df_visit (cfg->bb_entry, &dfn, cfg->bblocks);
6935 if (cfg->num_bblocks != dfn + 1) {
6938 cfg->num_bblocks = dfn + 1;
6940 if (!header->clauses) {
6941 /* remove unreachable code, because the code in them may be
6942 * inconsistent (access to dead variables for example) */
6943 for (bb = cfg->bb_entry; bb;) {
6944 MonoBasicBlock *bbn = bb->next_bb;
6946 if (bbn && bbn->region == -1 && !bbn->dfn) {
6947 if (cfg->verbose_level > 1)
6948 g_print ("found unreachabel code in BB%d\n", bbn->block_num);
6949 bb->next_bb = bbn->next_bb;
6950 nullify_basic_block (bbn);
6958 if (cfg->opt & MONO_OPT_LOOP) {
6959 mono_compile_dominator_info (cfg, MONO_COMP_DOM | MONO_COMP_IDOM);
6960 mono_compute_natural_loops (cfg);
6964 /* after method_to_ir */
6968 //#define DEBUGSSA "logic_run"
6969 #define DEBUGSSA_CLASS "Tests"
6972 if (!header->num_clauses && !cfg->disable_ssa) {
6973 mono_local_cprop (cfg);
6974 mono_ssa_compute (cfg);
6978 /* fixme: add all optimizations which requires SSA */
6979 if (cfg->opt & (MONO_OPT_DEADCE)) {
6980 if (!(cfg->comp_done & MONO_COMP_SSA) && !header->num_clauses && !cfg->disable_ssa) {
6981 mono_local_cprop (cfg);
6982 mono_ssa_compute (cfg);
6984 if (cfg->verbose_level >= 2) {
6991 /* after SSA translation */
6995 if ((cfg->opt & MONO_OPT_CONSPROP) || (cfg->opt & MONO_OPT_COPYPROP)) {
6996 if (cfg->comp_done & MONO_COMP_SSA) {
6997 mono_ssa_cprop (cfg);
6999 mono_local_cprop (cfg);
7003 if (cfg->comp_done & MONO_COMP_SSA) {
7004 mono_ssa_deadce (cfg);
7006 //mono_ssa_strength_reduction (cfg);
7008 mono_ssa_remove (cfg);
7010 if (cfg->opt & MONO_OPT_BRANCH)
7011 optimize_branches (cfg);
7014 /* after SSA removal */
7018 decompose_pass (cfg);
7020 /* FIXME: disabled with exception clauses: bug #42136 */
7021 if ((!header->num_clauses) && (cfg->opt & MONO_OPT_LINEARS)) {
7024 /* fixme: maybe we can avoid to compute livenesss here if already computed ? */
7025 cfg->comp_done &= ~MONO_COMP_LIVENESS;
7026 if (!(cfg->comp_done & MONO_COMP_LIVENESS))
7027 mono_analyze_liveness (cfg);
7029 if ((vars = mono_arch_get_allocatable_int_vars (cfg))) {
7030 regs = mono_arch_get_global_int_regs (cfg);
7031 mono_linear_scan (cfg, vars, regs, &cfg->used_int_regs);
7035 //mono_print_code (cfg);
7039 /* variables are allocated after decompose, since decompose could create temps */
7040 mono_arch_allocate_vars (cfg);
7042 if (cfg->opt & MONO_OPT_CFOLD)
7043 mono_constant_fold (cfg);
7045 mini_select_instructions (cfg);
7048 if (cfg->verbose_level >= 2) {
7049 char *id = mono_method_full_name (cfg->method, FALSE);
7050 mono_disassemble_code (cfg->native_code, cfg->code_len, id + 3);
7054 jinfo = mono_mempool_alloc0 (cfg->domain->mp, sizeof (MonoJitInfo));
7056 jinfo = g_new0 (MonoJitInfo, 1);
7057 jinfo->method = method;
7058 jinfo->code_start = cfg->native_code;
7059 jinfo->code_size = cfg->code_len;
7060 jinfo->used_regs = cfg->used_int_regs;
7061 jinfo->domain_neutral = (cfg->opt & MONO_OPT_SHARED) != 0;
7063 if (header->num_clauses) {
7066 jinfo->exvar_offset = cfg->exvar? cfg->exvar->inst_offset: 0;
7067 jinfo->num_clauses = header->num_clauses;
7068 jinfo->clauses = mono_mempool_alloc0 (cfg->domain->mp,
7069 sizeof (MonoJitExceptionInfo) * header->num_clauses);
7071 for (i = 0; i < header->num_clauses; i++) {
7072 MonoExceptionClause *ec = &header->clauses [i];
7073 MonoJitExceptionInfo *ei = &jinfo->clauses [i];
7074 MonoBasicBlock *tblock;
7076 ei->flags = ec->flags;
7078 if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
7079 tblock = g_hash_table_lookup (cfg->bb_hash, ip + ec->token_or_filter);
7081 ei->data.filter = cfg->native_code + tblock->native_offset;
7083 ei->data.token = ec->token_or_filter;
7086 tblock = g_hash_table_lookup (cfg->bb_hash, ip + ec->try_offset);
7088 ei->try_start = cfg->native_code + tblock->native_offset;
7089 g_assert (tblock->native_offset);
7090 tblock = g_hash_table_lookup (cfg->bb_hash, ip + ec->try_offset + ec->try_len);
7092 ei->try_end = cfg->native_code + tblock->native_offset;
7093 g_assert (tblock->native_offset);
7094 tblock = g_hash_table_lookup (cfg->bb_hash, ip + ec->handler_offset);
7096 ei->handler_start = cfg->native_code + tblock->native_offset;
7100 cfg->jit_info = jinfo;
7102 mono_jit_info_table_add (cfg->domain, jinfo);
7104 /* collect statistics */
7105 mono_jit_stats.allocated_code_size += cfg->code_len;
7106 code_size_ratio = cfg->code_len;
7107 if (code_size_ratio > mono_jit_stats.biggest_method_size) {
7108 mono_jit_stats.biggest_method_size = code_size_ratio;
7109 mono_jit_stats.biggest_method = method;
7111 code_size_ratio = (code_size_ratio * 100) / ((MonoMethodNormal *)method)->header->code_size;
7112 if (code_size_ratio > mono_jit_stats.max_code_size_ratio) {
7113 mono_jit_stats.max_code_size_ratio = code_size_ratio;
7114 mono_jit_stats.max_ratio_method = method;
7116 mono_jit_stats.native_code_size += cfg->code_len;
7118 if (cfg->prof_options & MONO_PROFILE_JIT_COMPILATION)
7119 mono_profiler_method_end_jit (method, MONO_PROFILE_OK);
7125 mono_jit_compile_method (MonoMethod *method)
7127 /* FIXME: later copy the code from mono */
7128 MonoDomain *target_domain, *domain = mono_domain_get ();
7130 GHashTable *jit_code_hash;
7134 if (default_opt & MONO_OPT_SHARED)
7135 target_domain = mono_root_domain;
7137 target_domain = domain;
7139 jit_code_hash = target_domain->jit_code_hash;
7141 if ((info = g_hash_table_lookup (jit_code_hash, method))) {
7142 /* We can't use a domain specific method in another domain */
7143 if (! ((domain != target_domain) && !info->domain_neutral)) {
7144 mono_jit_stats.methods_lookups++;
7145 return info->code_start;
7149 #ifdef MONO_USE_AOT_COMPILER
7150 if (!mono_compile_aot && (default_opt & MONO_OPT_AOT)) {
7153 mono_class_init (method->klass);
7154 if ((info = mono_aot_get_method (domain, method))) {
7156 g_hash_table_insert (domain->jit_code_hash, method, info);
7158 /* make sure runtime_init is called */
7159 mono_runtime_class_init (mono_class_vtable (domain, method->klass));
7161 return info->code_start;
7166 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
7167 (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
7168 if (!method->info) {
7171 if (!method->addr && (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL))
7172 mono_lookup_pinvoke_call (method);
7173 #ifdef MONO_USE_EXC_TABLES
7174 if (mono_method_blittable (method)) {
7175 method->info = method->addr;
7178 nm = mono_marshal_get_native_wrapper (method);
7179 method->info = mono_compile_method (nm);
7181 //if (mono_debug_format != MONO_DEBUG_FORMAT_NONE)
7182 //mono_debug_add_wrapper (method, nm);
7183 #ifdef MONO_USE_EXC_TABLES
7187 return method->info;
7188 } else if ((method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME)) {
7189 const char *name = method->name;
7192 if (method->klass->parent == mono_defaults.multicastdelegate_class) {
7193 if (*name == '.' && (strcmp (name, ".ctor") == 0)) {
7194 /* FIXME: uhm, we need a wrapper to handle exceptions? */
7195 return (gpointer)mono_delegate_ctor;
7196 } else if (*name == 'I' && (strcmp (name, "Invoke") == 0)) {
7197 nm = mono_marshal_get_delegate_invoke (method);
7198 return mono_jit_compile_method (nm);
7199 } else if (*name == 'B' && (strcmp (name, "BeginInvoke") == 0)) {
7200 nm = mono_marshal_get_delegate_begin_invoke (method);
7201 return mono_jit_compile_method (nm);
7202 } else if (*name == 'E' && (strcmp (name, "EndInvoke") == 0)) {
7203 nm = mono_marshal_get_delegate_end_invoke (method);
7204 return mono_jit_compile_method (nm);
7210 cfg = mini_method_compile (method, default_opt, target_domain, 0);
7211 code = cfg->native_code;
7213 g_hash_table_insert (jit_code_hash, method, cfg->jit_info);
7215 mono_destroy_compile (cfg);
7217 if (target_domain->jump_target_hash) {
7218 MonoJumpInfo patch_info;
7220 list = g_hash_table_lookup (target_domain->jump_target_hash, method);
7222 patch_info.next = NULL;
7223 patch_info.ip.i = 0;
7224 patch_info.type = MONO_PATCH_INFO_METHOD_JUMP;
7225 patch_info.data.method = method;
7226 g_hash_table_remove (target_domain->jump_target_hash, method);
7228 for (tmp = list; tmp; tmp = tmp->next)
7229 mono_arch_patch_code (NULL, target_domain, tmp->data, &patch_info);
7230 g_slist_free (list);
7232 /* make sure runtime_init is called */
7233 mono_runtime_class_init (mono_class_vtable (target_domain, method->klass));
7239 * mono_jit_runtime_invoke:
7240 * @method: the method to invoke
7241 * @obj: this pointer
7242 * @params: array of parameter values.
7243 * @exc: used to catch exceptions objects
7246 mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
7249 MonoObject *(*runtime_invoke) (MonoObject *this, void **params, MonoObject **exc);
7251 if (obj == NULL && !(method->flags & METHOD_ATTRIBUTE_STATIC) && !method->string_ctor && (method->wrapper_type == 0)) {
7252 g_warning ("Ignoring invocation of an instance method on a NULL instance.\n");
7256 invoke = mono_marshal_get_runtime_invoke (method);
7257 runtime_invoke = mono_jit_compile_method (invoke);
7258 return runtime_invoke (obj, params, exc);
7261 #ifdef PLATFORM_WIN32
7262 #define GET_CONTEXT \
7263 struct sigcontext *ctx = (struct sigcontext*)_dummy;
7265 #define GET_CONTEXT \
7266 void **_p = (void **)&_dummy; \
7267 struct sigcontext *ctx = (struct sigcontext *)++_p;
7271 sigfpe_signal_handler (int _dummy)
7276 exc = mono_get_exception_divide_by_zero ();
7278 mono_arch_handle_exception (ctx, exc, FALSE);
7282 sigill_signal_handler (int _dummy)
7286 exc = mono_get_exception_execution_engine ("SIGILL");
7288 mono_arch_handle_exception (ctx, exc, FALSE);
7292 sigsegv_signal_handler (int _dummy)
7297 exc = mono_get_exception_null_reference ();
7299 mono_arch_handle_exception (ctx, exc, FALSE);
7303 sigusr1_signal_handler (int _dummy)
7308 thread = mono_thread_current ();
7310 g_assert (thread->abort_exc);
7312 mono_arch_handle_exception (ctx, thread->abort_exc, FALSE);
7316 sigquit_signal_handler (int _dummy)
7321 exc = mono_get_exception_execution_engine ("Interrupted (SIGQUIT).");
7323 mono_arch_handle_exception (ctx, exc, FALSE);
7328 sigint_signal_handler (int _dummy)
7333 exc = mono_get_exception_execution_engine ("Interrupted (SIGINT).");
7335 mono_arch_handle_exception (ctx, exc, FALSE);
7339 mono_runtime_install_handlers (void)
7341 #ifndef PLATFORM_WIN32
7342 struct sigaction sa;
7345 #ifdef PLATFORM_WIN32
7347 win32_seh_set_handler(SIGFPE, sigfpe_signal_handler);
7348 win32_seh_set_handler(SIGILL, sigill_signal_handler);
7349 win32_seh_set_handler(SIGSEGV, sigsegv_signal_handler);
7350 if (getenv ("MONO_DEBUG"))
7351 win32_seh_set_handler(SIGINT, sigint_signal_handler);
7352 #else /* !PLATFORM_WIN32 */
7354 /* libpthreads has its own implementation of sigaction(),
7355 * but it seems to work well with our current exception
7356 * handlers. If not we must call syscall directly instead
7359 if (getenv ("MONO_DEBUG")) {
7361 sa.sa_handler = sigint_signal_handler;
7362 sigemptyset (&sa.sa_mask);
7364 //g_assert (syscall (SYS_sigaction, SIGINT, &sa, NULL) != -1);
7365 g_assert (sigaction (SIGINT, &sa, NULL) != -1);
7369 sa.sa_handler = sigfpe_signal_handler;
7370 sigemptyset (&sa.sa_mask);
7372 //g_assert (syscall (SYS_sigaction, SIGFPE, &sa, NULL) != -1);
7373 g_assert (sigaction (SIGFPE, &sa, NULL) != -1);
7376 sa.sa_handler = sigquit_signal_handler;
7377 sigemptyset (&sa.sa_mask);
7379 g_assert (sigaction (SIGQUIT, &sa, NULL) != -1);
7382 sa.sa_handler = sigill_signal_handler;
7383 sigemptyset (&sa.sa_mask);
7385 //g_assert (syscall (SYS_sigaction, SIGILL, &sa, NULL) != -1);
7386 g_assert (sigaction (SIGILL, &sa, NULL) != -1);
7388 /* catch thread abort signal */
7389 sa.sa_handler = sigusr1_signal_handler;
7390 sigemptyset (&sa.sa_mask);
7392 //g_assert (syscall (SYS_sigaction, SIGILL, &sa, NULL) != -1);
7393 if (!getenv ("MONO_VALGRIND"))
7394 /* valgrind 20030725 and earlier aborts on this call so we skip it */
7395 g_assert (sigaction (mono_thread_get_abort_signal (), &sa, NULL) != -1);
7399 sa.sa_handler = sigsegv_signal_handler;
7400 sigemptyset (&sa.sa_mask);
7402 //g_assert (syscall (SYS_sigaction, SIGSEGV, &sa, NULL) != -1);
7403 g_assert (sigaction (SIGSEGV, &sa, NULL) != -1);
7405 #endif /* PLATFORM_WIN32 */
7408 /* mono_jit_create_remoting_trampoline:
7409 * @method: pointer to the method info
7411 * Creates a trampoline which calls the remoting functions. This
7412 * is used in the vtable of transparent proxies.
7414 * Returns: a pointer to the newly created code
7417 mono_jit_create_remoting_trampoline (MonoMethod *method)
7420 guint8 *addr = NULL;
7422 if ((method->flags & METHOD_ATTRIBUTE_ABSTRACT) ||
7423 (method->signature->hasthis && (method->klass->marshalbyref || method->klass == mono_defaults.object_class))) {
7424 nm = mono_marshal_get_remoting_invoke (method);
7425 addr = mono_compile_method (nm);
7427 addr = mono_compile_method (method);
7433 mini_init (const char *filename)
7437 mono_arch_cpu_init ();
7439 g_thread_init (NULL);
7441 mono_jit_tls_id = TlsAlloc ();
7442 setup_jit_tls_data ((gpointer)-1, mono_thread_abort);
7444 InitializeCriticalSection (&class_init_hash_mutex);
7448 if (default_opt & MONO_OPT_AOT)
7451 mono_runtime_install_handlers ();
7452 mono_threads_install_cleanup (mini_thread_cleanup);
7454 mono_install_compile_method (mono_jit_compile_method);
7455 mono_install_trampoline (mono_arch_create_jit_trampoline);
7456 mono_install_remoting_trampoline (mono_jit_create_remoting_trampoline);
7457 mono_install_runtime_invoke (mono_jit_runtime_invoke);
7458 mono_install_handler (mono_arch_get_throw_exception ());
7459 mono_install_stack_walk (mono_jit_walk_stack);
7460 mono_install_get_config_dir ();
7462 domain = mono_init (filename);
7465 mono_add_internal_call ("System.Diagnostics.StackFrame::get_frame_info",
7466 ves_icall_get_frame_info);
7467 mono_add_internal_call ("System.Diagnostics.StackTrace::get_trace",
7468 ves_icall_get_trace);
7469 mono_add_internal_call ("Mono.Runtime::mono_runtime_install_handlers",
7470 mono_runtime_install_handlers);
7473 create_helper_signature ();
7475 /* Needs to be called here since register_jit_icall depends on it */
7476 mono_marshal_init ();
7478 mono_arch_register_lowlevel_calls ();
7479 mono_register_jit_icall (mono_profiler_method_enter, "mono_profiler_method_enter", NULL, TRUE);
7480 mono_register_jit_icall (mono_profiler_method_leave, "mono_profiler_method_leave", NULL, TRUE);
7482 mono_register_jit_icall (mono_get_lmf_addr, "mono_get_lmf_addr", helper_sig_ptr_void, TRUE);
7483 mono_register_jit_icall (mono_domain_get, "mono_domain_get", helper_sig_domain_get, TRUE);
7485 /* fixme: we cant hanlde vararg methods this way, because the signature is not constant */
7486 //mono_register_jit_icall (ves_array_element_address, "ves_array_element_address", NULL);
7487 //mono_register_jit_icall (mono_array_new_va, "mono_array_new_va", NULL);
7489 mono_register_jit_icall (mono_arch_get_throw_exception (), "mono_arch_throw_exception", helper_sig_void_obj, TRUE);
7490 mono_register_jit_icall (mono_arch_get_throw_exception_by_name (), "mono_arch_throw_exception_by_name",
7491 helper_sig_void_ptr, TRUE);
7494 * NOTE, NOTE, NOTE, NOTE:
7495 * when adding emulation for some opcodes, remember to also add a dummy
7496 * rule to the burg files, because we need the arity information to be correct.
7498 mono_register_opcode_emulation (OP_LMUL, "__emul_lmul", helper_sig_long_long_long, mono_llmult, TRUE);
7499 mono_register_opcode_emulation (OP_LMUL_OVF_UN, "__emul_lmul_ovf_un", helper_sig_long_long_long, mono_llmult_ovf_un, FALSE);
7500 mono_register_opcode_emulation (OP_LMUL_OVF, "__emul_lmul_ovf", helper_sig_long_long_long, mono_llmult_ovf, FALSE);
7501 mono_register_opcode_emulation (OP_LDIV, "__emul_ldiv", helper_sig_long_long_long, mono_lldiv, FALSE);
7502 mono_register_opcode_emulation (OP_LDIV_UN, "__emul_ldiv_un", helper_sig_long_long_long, mono_lldiv_un, FALSE);
7503 mono_register_opcode_emulation (OP_LREM, "__emul_lrem", helper_sig_long_long_long, mono_llrem, FALSE);
7504 mono_register_opcode_emulation (OP_LREM_UN, "__emul_lrem_un", helper_sig_long_long_long, mono_llrem_un, FALSE);
7506 mono_register_opcode_emulation (OP_LSHL, "__emul_lshl", helper_sig_long_long_int, mono_lshl, TRUE);
7507 mono_register_opcode_emulation (OP_LSHR, "__emul_lshr", helper_sig_long_long_int, mono_lshr, TRUE);
7508 mono_register_opcode_emulation (OP_LSHR_UN, "__emul_lshr_un", helper_sig_long_long_int, mono_lshr_un, TRUE);
7510 mono_register_opcode_emulation (OP_FCONV_TO_U8, "__emul_fconv_to_u8", helper_sig_ulong_double, mono_fconv_u8, FALSE);
7511 mono_register_opcode_emulation (OP_FCONV_TO_U4, "__emul_fconv_to_u4", helper_sig_uint_double, mono_fconv_u4, FALSE);
7512 mono_register_opcode_emulation (OP_FCONV_TO_OVF_I8, "__emul_fconv_to_ovf_i8", helper_sig_long_double, mono_fconv_ovf_i8, TRUE);
7513 mono_register_opcode_emulation (OP_FCONV_TO_OVF_U8, "__emul_fconv_to_ovf_u8", helper_sig_ulong_double, mono_fconv_ovf_u8, TRUE);
7515 #if SIZEOF_VOID_P == 4
7516 mono_register_opcode_emulation (OP_FCONV_TO_U, "__emul_fconv_to_u", helper_sig_uint_double, mono_fconv_u4, TRUE);
7518 #warning "fixme: add opcode emulation"
7521 /* other jit icalls */
7522 mono_register_jit_icall (mono_class_static_field_address , "mono_class_static_field_address",
7523 helper_sig_ptr_ptr_ptr, FALSE);
7524 mono_register_jit_icall (mono_ldtoken_wrapper, "mono_ldtoken_wrapper", helper_sig_ptr_ptr_ptr, FALSE);
7525 mono_register_jit_icall (mono_threads_get_static_data, "mono_threads_get_static_data", helper_sig_ptr_int, FALSE);
7526 mono_register_jit_icall (mono_ldstr, "mono_ldstr", helper_sig_ldstr, FALSE);
7527 mono_register_jit_icall (helper_memcpy, "helper_memcpy", helper_sig_memcpy, FALSE);
7528 mono_register_jit_icall (helper_memset, "helper_memset", helper_sig_memset, FALSE);
7529 mono_register_jit_icall (helper_initobj, "helper_initobj", helper_sig_initobj, FALSE);
7530 mono_register_jit_icall (helper_stelem_ref, "helper_stelem_ref", helper_sig_stelem_ref, FALSE);
7531 mono_register_jit_icall (mono_object_new, "mono_object_new", helper_sig_object_new, FALSE);
7532 mono_register_jit_icall (mono_object_new_specific, "mono_object_new_specific", helper_sig_object_new_specific, FALSE);
7533 mono_register_jit_icall (mono_object_new_fast, "mono_object_new_fast", helper_sig_object_new_specific, FALSE);
7534 mono_register_jit_icall (mono_array_new, "mono_array_new", helper_sig_newarr, FALSE);
7535 mono_register_jit_icall (mono_array_new_specific, "mono_array_new_specific", helper_sig_newarr_specific, FALSE);
7536 mono_register_jit_icall (mono_string_to_utf16, "mono_string_to_utf16", helper_sig_ptr_obj, FALSE);
7537 mono_register_jit_icall (mono_string_from_utf16, "mono_string_from_utf16", helper_sig_obj_ptr, FALSE);
7538 mono_register_jit_icall (mono_string_new_wrapper, "mono_string_new_wrapper", helper_sig_obj_ptr, FALSE);
7539 mono_register_jit_icall (mono_string_to_utf8, "mono_string_to_utf8", helper_sig_ptr_obj, FALSE);
7540 mono_register_jit_icall (mono_string_to_bstr, "mono_string_to_bstr", helper_sig_ptr_obj, FALSE);
7541 mono_register_jit_icall (mono_string_to_ansibstr, "mono_string_to_ansibstr", helper_sig_ptr_obj, FALSE);
7542 mono_register_jit_icall (mono_string_builder_to_utf8, "mono_string_builder_to_utf8", helper_sig_ptr_obj, FALSE);
7543 mono_register_jit_icall (mono_array_to_savearray, "mono_array_to_savearray", helper_sig_ptr_obj, FALSE);
7544 mono_register_jit_icall (mono_array_to_lparray, "mono_array_to_lparray", helper_sig_ptr_obj, FALSE);
7545 mono_register_jit_icall (mono_delegate_to_ftnptr, "mono_delegate_to_ftnptr", helper_sig_ptr_obj, FALSE);
7546 mono_register_jit_icall (mono_marshal_string_array, "mono_marshal_string_array", helper_sig_ptr_obj, FALSE);
7547 mono_register_jit_icall (mono_string_utf8_to_builder, "mono_string_utf8_to_builder", helper_sig_void_ptr_ptr, FALSE);
7548 mono_register_jit_icall (mono_marshal_free_array, "mono_marshal_free_array", helper_sig_void_ptr_ptr, FALSE);
7549 mono_register_jit_icall (mono_string_to_byvalstr, "mono_string_to_byvalstr", helper_sig_void_ptr_ptr_ptr, FALSE);
7550 mono_register_jit_icall (mono_string_to_byvalwstr, "mono_string_to_byvalwstr", helper_sig_void_ptr_ptr_ptr, FALSE);
7551 mono_register_jit_icall (g_free, "g_free", helper_sig_void_ptr, FALSE);
7552 mono_register_jit_icall (mono_runtime_class_init, "mono_runtime_class_init", helper_sig_void_ptr, FALSE);
7553 mono_register_jit_icall (mono_ldftn, "mono_ldftn", helper_sig_compile, FALSE);
7554 mono_register_jit_icall (mono_ldvirtfn, "mono_ldvirtfn", helper_sig_compile_virt, FALSE);
7556 mono_runtime_install_cleanup ((MonoDomainFunc)mini_cleanup);
7557 mono_runtime_init (domain, mono_thread_start_cb, mono_thread_attach_cb);
7559 //mono_thread_attach (domain);
7563 MonoJitStats mono_jit_stats = {0};
7566 print_jit_stats (void)
7568 if (mono_jit_stats.enabled) {
7569 g_print ("Mono Jit statistics\n");
7570 g_print ("Compiled methods: %ld\n", mono_jit_stats.methods_compiled);
7571 g_print ("Methods from AOT: %ld\n", mono_jit_stats.methods_aot);
7572 g_print ("Methods cache lookup: %ld\n", mono_jit_stats.methods_lookups);
7573 g_print ("Method trampolines: %ld\n", mono_jit_stats.method_trampolines);
7574 g_print ("Basic blocks: %ld\n", mono_jit_stats.basic_blocks);
7575 g_print ("Max basic blocks: %ld\n", mono_jit_stats.max_basic_blocks);
7576 g_print ("Allocated vars: %ld\n", mono_jit_stats.allocate_var);
7577 g_print ("Analyze stack repeat: %ld\n", mono_jit_stats.analyze_stack_repeat);
7578 g_print ("Compiled CIL code size: %ld\n", mono_jit_stats.cil_code_size);
7579 g_print ("Native code size: %ld\n", mono_jit_stats.native_code_size);
7580 g_print ("Max code size ratio: %.2f (%s::%s)\n", mono_jit_stats.max_code_size_ratio/100.0,
7581 mono_jit_stats.max_ratio_method->klass->name, mono_jit_stats.max_ratio_method->name);
7582 g_print ("Biggest method: %ld (%s::%s)\n", mono_jit_stats.biggest_method_size,
7583 mono_jit_stats.biggest_method->klass->name, mono_jit_stats.biggest_method->name);
7584 g_print ("Code reallocs: %ld\n", mono_jit_stats.code_reallocs);
7585 g_print ("Allocated code size: %ld\n", mono_jit_stats.allocated_code_size);
7586 g_print ("Inlineable methods: %ld\n", mono_jit_stats.inlineable_methods);
7587 g_print ("Inlined methods: %ld\n", mono_jit_stats.inlined_methods);
7589 g_print ("\nCreated object count: %ld\n", mono_stats.new_object_count);
7590 g_print ("Initialized classes: %ld\n", mono_stats.initialized_class_count);
7591 g_print ("Used classes: %ld\n", mono_stats.used_class_count);
7592 g_print ("Static data size: %ld\n", mono_stats.class_static_data_size);
7593 g_print ("VTable data size: %ld\n", mono_stats.class_vtable_size);
7598 mini_cleanup (MonoDomain *domain)
7601 * mono_runtime_cleanup() and mono_domain_finalize () need to
7602 * be called early since they need the execution engine still
7603 * fully working (mono_domain_finalize may invoke managed finalizers
7604 * and mono_runtime_cleanup will wait for other threads to finish).
7606 mono_domain_finalize (domain);
7608 mono_runtime_cleanup (domain);
7610 mono_profiler_shutdown ();
7612 mono_debug_cleanup ();
7614 #ifdef PLATFORM_WIN32
7615 win32_seh_cleanup();
7618 mono_domain_unload (domain, TRUE);
7624 mono_set_defaults (int verbose_level, guint32 opts)
7626 mini_verbose = verbose_level;
7631 mono_precompile_assembly (MonoAssembly *ass, void *user_data)
7633 MonoImage *image = ass->image;
7637 if (mini_verbose > 0)
7638 printf ("PRECOMPILE: %s.\n", ass->image->name);
7640 for (i = 0; i < image->tables [MONO_TABLE_METHOD].rows; ++i) {
7641 method = mono_get_method (image, MONO_TOKEN_METHOD_DEF | (i + 1), NULL);
7642 if (method->flags & METHOD_ATTRIBUTE_ABSTRACT)
7644 if (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL)
7648 if (mini_verbose > 1) {
7649 char * desc = mono_method_full_name (method, TRUE);
7650 g_print ("Compiling %d %s\n", count, desc);
7653 mono_compile_method (method);
7657 void mono_precompile_assemblies ()
7659 mono_assembly_foreach ((GFunc)mono_precompile_assembly, NULL);