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_CHECK_THIS(ins) (cfg->method->signature->hasthis && (ins)->ssa_op == MONO_SSA_LOAD && (ins)->inst_left->inst_c0 == 0)
48 static gpointer mono_jit_compile_method (MonoMethod *method);
50 static void handle_stobj (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *dest, MonoInst *src,
51 const unsigned char *ip, MonoClass *klass, gboolean to_end, gboolean native);
53 static int mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock,
54 int locals_offset, MonoInst *return_var, GList *dont_inline, MonoInst **inline_args,
55 guint inline_offset, gboolean is_virtual_call);
57 extern guint8 mono_burg_arity [];
58 /* helper methods signature */
59 static MonoMethodSignature *helper_sig_long_long_long = NULL;
60 static MonoMethodSignature *helper_sig_long_long_int = NULL;
61 static MonoMethodSignature *helper_sig_newarr = NULL;
62 static MonoMethodSignature *helper_sig_ldstr = NULL;
63 static MonoMethodSignature *helper_sig_domain_get = NULL;
64 static MonoMethodSignature *helper_sig_object_new = NULL;
65 static MonoMethodSignature *helper_sig_compile = NULL;
66 static MonoMethodSignature *helper_sig_compile_virt = NULL;
67 static MonoMethodSignature *helper_sig_obj_ptr = NULL;
68 static MonoMethodSignature *helper_sig_ptr_void = NULL;
69 static MonoMethodSignature *helper_sig_void_ptr = NULL;
70 static MonoMethodSignature *helper_sig_void_obj = NULL;
71 static MonoMethodSignature *helper_sig_void_ptr_ptr = NULL;
72 static MonoMethodSignature *helper_sig_void_ptr_ptr_ptr = NULL;
73 static MonoMethodSignature *helper_sig_ptr_ptr_ptr = NULL;
74 static MonoMethodSignature *helper_sig_ptr_obj = NULL;
75 static MonoMethodSignature *helper_sig_initobj = NULL;
76 static MonoMethodSignature *helper_sig_memcpy = NULL;
77 static MonoMethodSignature *helper_sig_memset = NULL;
78 static MonoMethodSignature *helper_sig_ulong_double = NULL;
79 static MonoMethodSignature *helper_sig_long_double = NULL;
80 static MonoMethodSignature *helper_sig_uint_double = NULL;
81 static MonoMethodSignature *helper_sig_int_double = NULL;
82 static MonoMethodSignature *helper_sig_stelem_ref = NULL;
84 static guint32 default_opt = MONO_OPT_PEEPHOLE;
86 guint32 mono_jit_tls_id = 0;
87 gboolean mono_jit_trace_calls = FALSE;
88 gboolean mono_break_on_exc = FALSE;
89 gboolean mono_compile_aot = FALSE;
90 gboolean mono_trace_coverage = FALSE;
91 gboolean mono_jit_profile = FALSE;
92 MonoDebugFormat mono_debug_format = MONO_DEBUG_FORMAT_NONE;
94 CRITICAL_SECTION *metadata_section = NULL;
96 static int mini_verbose = 0;
98 #ifdef MONO_USE_EXC_TABLES
100 mono_type_blittable (MonoType *type)
119 case MONO_TYPE_OBJECT:
121 case MONO_TYPE_VALUETYPE:
122 case MONO_TYPE_CLASS:
123 return type->data.klass->blittable;
133 mono_method_blittable (MonoMethod *method)
135 MonoMethodSignature *sig;
141 if (!mono_arch_has_unwind_info (method->addr)) {
145 if (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL)
148 sig = method->signature;
150 if (!mono_type_blittable (sig->ret))
153 for (i = 0; i < sig->param_count; i++)
154 if (!mono_type_blittable (sig->params [i]))
163 print_method_from_ip (void *ip)
168 ji = mono_jit_info_table_find (mono_domain_get (), ip);
170 g_print ("No method at %p\n", ip);
173 method = mono_method_full_name (ji->method, TRUE);
174 g_print ("IP at offset 0x%x of method %s (%p %p)\n", (char*)ip - (char*)ji->code_start, method, ji->code_start, (char*)ji->code_start + ji->code_size);
179 #define MONO_INIT_VARINFO(vi,id) do { \
180 (vi)->range.first_use.pos.bid = 0xffff; \
186 * Basic blocks have two numeric identifiers:
187 * dfn: Depth First Number
188 * block_num: unique ID assigned at bblock creation
190 #define NEW_BBLOCK(cfg) (mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock)))
191 #define ADD_BBLOCK(cfg,bbhash,b) do { \
192 g_hash_table_insert (bbhash, (b)->cil_code, (b)); \
193 (b)->block_num = cfg->num_bblocks++; \
194 (b)->real_offset = real_offset; \
197 #define GET_BBLOCK(cfg,bbhash,tblock,ip) do { \
198 (tblock) = g_hash_table_lookup (bbhash, (ip)); \
200 if ((ip) >= end || (ip) < header->code) goto unverified; \
201 (tblock) = NEW_BBLOCK (cfg); \
202 (tblock)->cil_code = (ip); \
203 ADD_BBLOCK (cfg, (bbhash), (tblock)); \
205 (tblock)->real_offset = real_offset; \
208 #define CHECK_BBLOCK(target,ip,tblock) do { \
209 if ((target) < (ip) && !(tblock)->code) { \
210 bb_recheck = g_list_prepend (bb_recheck, (tblock)); \
211 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); \
215 #define NEW_ICONST(cfg,dest,val) do { \
216 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
217 (dest)->opcode = OP_ICONST; \
218 (dest)->inst_c0 = (val); \
219 (dest)->type = STACK_I4; \
222 /* FIXME: have a different definition of NEW_PCONST for 64 bit systems */
223 #define NEW_PCONST(cfg,dest,val) do { \
224 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
225 (dest)->opcode = OP_ICONST; \
226 (dest)->inst_p0 = (val); \
227 (dest)->type = STACK_PTR; \
230 #define NEW_CLASSCONST(cfg,dest,val) do { \
231 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
232 (dest)->opcode = mono_compile_aot ? OP_AOTCONST : OP_ICONST; \
233 (dest)->inst_p0 = (val); \
234 (dest)->inst_i1 = (gpointer)MONO_PATCH_INFO_CLASS; \
235 (dest)->type = STACK_PTR; \
238 #define NEW_IMAGECONST(cfg,dest,val) do { \
239 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
240 (dest)->opcode = mono_compile_aot ? OP_AOTCONST : OP_ICONST; \
241 (dest)->inst_p0 = (val); \
242 (dest)->inst_i1 = (gpointer)MONO_PATCH_INFO_IMAGE; \
243 (dest)->type = STACK_PTR; \
246 #define NEW_FIELDCONST(cfg,dest,field) do { \
247 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
248 (dest)->opcode = mono_compile_aot ? OP_AOTCONST : OP_ICONST; \
249 (dest)->inst_p0 = (field); \
250 (dest)->inst_i1 = (gpointer)MONO_PATCH_INFO_FIELD; \
251 (dest)->type = STACK_PTR; \
254 #define NEW_METHODCONST(cfg,dest,val) do { \
255 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
256 (dest)->opcode = mono_compile_aot ? OP_AOTCONST : OP_ICONST; \
257 (dest)->inst_p0 = (val); \
258 (dest)->inst_i1 = (gpointer)MONO_PATCH_INFO_METHODCONST; \
259 (dest)->type = STACK_PTR; \
262 #define NEW_DOMAINCONST(cfg,dest) do { \
263 if ((cfg->opt & MONO_OPT_SAHRED) || mono_compile_aot) { \
264 NEW_TEMPLOAD (cfg, dest, mono_get_domainvar (cfg)->inst_c0); \
266 NEW_PCONST (cfg, dest, (cfg)->domain); \
270 #define GET_VARINFO_INST(cfg,num) ((cfg)->varinfo [(num)]->inst)
272 #define NEW_ARGLOAD(cfg,dest,num) do { \
273 if (arg_array [(num)]->opcode == OP_ICONST) (dest) = arg_array [(num)]; else { \
274 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
275 (dest)->ssa_op = MONO_SSA_LOAD; \
276 (dest)->inst_i0 = arg_array [(num)]; \
277 (dest)->opcode = mono_type_to_ldind ((dest)->inst_i0->inst_vtype); \
278 type_to_eval_stack_type (param_types [(num)], (dest)); \
279 (dest)->klass = (dest)->inst_i0->klass; \
282 #define NEW_LOCLOAD(cfg,dest,num) do { \
283 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
284 (dest)->ssa_op = MONO_SSA_LOAD; \
285 (dest)->inst_i0 = (cfg)->varinfo [locals_offset + (num)]; \
286 (dest)->opcode = mono_type_to_ldind ((dest)->inst_i0->inst_vtype); \
287 type_to_eval_stack_type (header->locals [(num)], (dest)); \
288 (dest)->klass = (dest)->inst_i0->klass; \
291 #define NEW_LOCLOADA(cfg,dest,num) do { \
292 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
293 (dest)->ssa_op = MONO_SSA_MAYBE_LOAD; \
294 (dest)->inst_i0 = (cfg)->varinfo [locals_offset + (num)]; \
295 (dest)->inst_i0->flags |= MONO_INST_INDIRECT; \
296 (dest)->opcode = OP_LDADDR; \
297 (dest)->type = STACK_MP; \
298 (dest)->klass = (dest)->inst_i0->klass; \
299 (cfg)->disable_ssa = TRUE; \
302 #define NEW_RETLOADA(cfg,dest) do { \
303 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
304 (dest)->ssa_op = MONO_SSA_MAYBE_LOAD; \
305 (dest)->inst_i0 = (cfg)->ret; \
306 (dest)->inst_i0->flags |= MONO_INST_INDIRECT; \
307 (dest)->opcode = CEE_LDIND_I; \
308 (dest)->type = STACK_MP; \
309 (dest)->klass = (dest)->inst_i0->klass; \
310 (cfg)->disable_ssa = TRUE; \
313 #define NEW_ARGLOADA(cfg,dest,num) do { \
314 if (arg_array [(num)]->opcode == OP_ICONST) goto inline_failure; \
315 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
316 (dest)->ssa_op = MONO_SSA_MAYBE_LOAD; \
317 (dest)->inst_i0 = arg_array [(num)]; \
318 (dest)->inst_i0->flags |= MONO_INST_INDIRECT; \
319 (dest)->opcode = OP_LDADDR; \
320 (dest)->type = STACK_MP; \
321 (dest)->klass = (dest)->inst_i0->klass; \
322 (cfg)->disable_ssa = TRUE; \
325 #define NEW_TEMPLOAD(cfg,dest,num) do { \
326 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
327 (dest)->ssa_op = MONO_SSA_LOAD; \
328 (dest)->inst_i0 = (cfg)->varinfo [(num)]; \
329 (dest)->opcode = mono_type_to_ldind ((dest)->inst_i0->inst_vtype); \
330 type_to_eval_stack_type ((dest)->inst_i0->inst_vtype, (dest)); \
331 (dest)->klass = (dest)->inst_i0->klass; \
334 #define NEW_TEMPLOADA(cfg,dest,num) do { \
335 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
336 (dest)->ssa_op = MONO_SSA_MAYBE_LOAD; \
337 (dest)->inst_i0 = (cfg)->varinfo [(num)]; \
338 (dest)->inst_i0->flags |= MONO_INST_INDIRECT; \
339 (dest)->opcode = OP_LDADDR; \
340 (dest)->type = STACK_MP; \
341 (dest)->klass = (dest)->inst_i0->klass; \
342 (cfg)->disable_ssa = TRUE; \
346 #define NEW_INDLOAD(cfg,dest,addr,vtype) do { \
347 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
348 (dest)->inst_left = addr; \
349 (dest)->opcode = mono_type_to_ldind (vtype); \
350 type_to_eval_stack_type (vtype, (dest)); \
351 /* FIXME: (dest)->klass = (dest)->inst_i0->klass;*/ \
354 #define NEW_INDSTORE(cfg,dest,addr,value,vtype) do { \
355 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
356 (dest)->inst_i0 = addr; \
357 (dest)->opcode = mono_type_to_stind (vtype); \
358 (dest)->inst_i1 = (value); \
359 /* FIXME: (dest)->klass = (dest)->inst_i0->klass;*/ \
362 #define NEW_TEMPSTORE(cfg,dest,num,inst) do { \
363 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
364 (dest)->ssa_op = MONO_SSA_STORE; \
365 (dest)->inst_i0 = (cfg)->varinfo [(num)]; \
366 (dest)->opcode = mono_type_to_stind ((dest)->inst_i0->inst_vtype); \
367 (dest)->inst_i1 = (inst); \
368 (dest)->klass = (dest)->inst_i0->klass; \
371 #define NEW_LOCSTORE(cfg,dest,num,inst) do { \
372 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
373 (dest)->opcode = mono_type_to_stind (header->locals [(num)]); \
374 (dest)->ssa_op = MONO_SSA_STORE; \
375 (dest)->inst_i0 = (cfg)->varinfo [locals_offset + (num)]; \
376 (dest)->inst_i1 = (inst); \
377 (dest)->klass = (dest)->inst_i0->klass; \
380 #define NEW_ARGSTORE(cfg,dest,num,inst) do { \
381 if (arg_array [(num)]->opcode == OP_ICONST) goto inline_failure; \
382 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
383 (dest)->opcode = mono_type_to_stind (param_types [(num)]); \
384 (dest)->ssa_op = MONO_SSA_STORE; \
385 (dest)->inst_i0 = arg_array [(num)]; \
386 (dest)->inst_i1 = (inst); \
387 (dest)->klass = (dest)->inst_i0->klass; \
390 #define ADD_BINOP(op) do { \
391 MONO_INST_NEW (cfg, ins, (op)); \
392 ins->cil_code = ip; \
394 ins->inst_i0 = sp [0]; \
395 ins->inst_i1 = sp [1]; \
397 type_from_op (ins); \
401 #define ADD_UNOP(op) do { \
402 MONO_INST_NEW (cfg, ins, (op)); \
403 ins->cil_code = ip; \
405 ins->inst_i0 = sp [0]; \
407 type_from_op (ins); \
411 #define ADD_BINCOND(next_block) do { \
413 MONO_INST_NEW(cfg, cmp, OP_COMPARE); \
415 cmp->inst_i0 = sp [0]; \
416 cmp->inst_i1 = sp [1]; \
417 cmp->cil_code = ins->cil_code; \
418 type_from_op (cmp); \
420 ins->inst_i0 = cmp; \
421 MONO_ADD_INS (bblock, ins); \
422 ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2); \
423 GET_BBLOCK (cfg, bbhash, tblock, target); \
424 link_bblock (cfg, bblock, tblock); \
425 ins->inst_true_bb = tblock; \
426 CHECK_BBLOCK (target, ip, tblock); \
427 if ((next_block)) { \
428 link_bblock (cfg, bblock, (next_block)); \
429 ins->inst_false_bb = (next_block); \
430 start_new_bblock = 1; \
432 GET_BBLOCK (cfg, bbhash, tblock, ip); \
433 link_bblock (cfg, bblock, tblock); \
434 ins->inst_false_bb = tblock; \
435 start_new_bblock = 2; \
439 /* FIXME: handle float, long ... */
440 #define ADD_UNCOND(istrue) do { \
442 MONO_INST_NEW(cfg, cmp, OP_COMPARE); \
444 cmp->inst_i0 = sp [0]; \
445 switch (cmp->inst_i0->type) { \
447 cmp->inst_i1 = zero_int64; break; \
449 cmp->inst_i1 = zero_r8; break; \
452 cmp->inst_i1 = zero_ptr; break; \
454 cmp->inst_i1 = zero_obj; break; \
456 cmp->inst_i1 = zero_int32; \
458 cmp->cil_code = ins->cil_code; \
459 type_from_op (cmp); \
461 ins->inst_i0 = cmp; \
462 ins->opcode = (istrue)? CEE_BNE_UN: CEE_BEQ; \
463 MONO_ADD_INS (bblock, ins); \
464 ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2); \
465 GET_BBLOCK (cfg, bbhash, tblock, target); \
466 link_bblock (cfg, bblock, tblock); \
467 ins->inst_true_bb = tblock; \
468 CHECK_BBLOCK (target, ip, tblock); \
469 GET_BBLOCK (cfg, bbhash, tblock, ip); \
470 link_bblock (cfg, bblock, tblock); \
471 ins->inst_false_bb = tblock; \
472 start_new_bblock = 2; \
475 #define NEW_LDELEMA(cfg,dest,sp,k) do { \
476 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
477 (dest)->opcode = CEE_LDELEMA; \
478 (dest)->inst_left = (sp) [0]; \
479 (dest)->inst_right = (sp) [1]; \
480 (dest)->type = STACK_MP; \
481 (dest)->klass = (k); \
484 #define NEW_GROUP(cfg,dest,el1,el2) do { \
485 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
486 (dest)->opcode = OP_GROUP; \
487 (dest)->inst_left = (el1); \
488 (dest)->inst_right = (el2); \
491 static GHashTable *coverage_hash = NULL;
494 mono_allocate_coverage_info (MonoMethod *method, int size)
496 MonoCoverageInfo *res;
499 coverage_hash = g_hash_table_new (NULL, NULL);
501 res = g_malloc0 (sizeof (MonoCoverageInfo) + sizeof (int) * size * 2);
505 g_hash_table_insert (coverage_hash, method, res);
511 mono_get_coverage_info (MonoMethod *method)
516 return g_hash_table_lookup (coverage_hash, method);
521 compare_bblock (gconstpointer a, gconstpointer b)
523 const MonoBasicBlock *b1 = a;
524 const MonoBasicBlock *b2 = b;
526 return b2->cil_code - b1->cil_code;
531 * link_bblock: Links two basic blocks
533 * links two basic blocks in the control flow graph, the 'from'
534 * argument is the starting block and the 'to' argument is the block
535 * the control flow ends to after 'from'.
538 link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
540 MonoBasicBlock **newa;
544 if (from->cil_code) {
546 g_print ("edge from IL%04x to IL_%04x\n", from->cil_code - cfg->cil_code, to->cil_code - cfg->cil_code);
548 g_print ("edge from IL%04x to exit\n", from->cil_code - cfg->cil_code);
551 g_print ("edge from entry to IL_%04x\n", to->cil_code - cfg->cil_code);
553 g_print ("edge from entry to exit\n");
557 for (i = 0; i < from->out_count; ++i) {
558 if (to == from->out_bb [i]) {
564 newa = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (from->out_count + 1));
565 for (i = 0; i < from->out_count; ++i) {
566 newa [i] = from->out_bb [i];
574 for (i = 0; i < to->in_count; ++i) {
575 if (from == to->in_bb [i]) {
581 newa = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (to->in_count + 1));
582 for (i = 0; i < to->in_count; ++i) {
583 newa [i] = to->in_bb [i];
592 * We mark each basic block with a region ID. We use that to avoid BB
593 * optimizations when blocks are in different regions.
596 mono_find_block_region (MonoCompile *cfg, int offset, int *filter_lengths)
598 MonoMethod *method = cfg->method;
599 MonoMethodHeader *header = ((MonoMethodNormal *)method)->header;
600 MonoExceptionClause *clause;
603 /* first search for handlers and filters */
604 for (i = 0; i < header->num_clauses; ++i) {
605 clause = &header->clauses [i];
606 if ((clause->flags & MONO_EXCEPTION_CLAUSE_FILTER) && (offset >= clause->token_or_filter) &&
607 (offset < (clause->token_or_filter + filter_lengths [i])))
608 return (i << 8) | 128 | clause->flags;
610 if (MONO_OFFSET_IN_HANDLER (clause, offset)) {
611 return (i << 8) | 64 | clause->flags;
615 /* search the try blocks */
616 for (i = 0; i < header->num_clauses; ++i) {
617 clause = &header->clauses [i];
618 if (MONO_OFFSET_IN_CLAUSE (clause, offset))
619 return (i << 8) | clause->flags;
626 mono_find_final_block (MonoCompile *cfg, unsigned char *ip, unsigned char *target, int type)
628 MonoMethod *method = cfg->method;
629 MonoMethodHeader *header = ((MonoMethodNormal *)method)->header;
630 MonoExceptionClause *clause;
631 MonoBasicBlock *handler;
635 for (i = 0; i < header->num_clauses; ++i) {
636 clause = &header->clauses [i];
637 if (MONO_OFFSET_IN_CLAUSE (clause, (ip - header->code)) &&
638 (!MONO_OFFSET_IN_CLAUSE (clause, (target - header->code)))) {
639 if (clause->flags == type) {
640 handler = g_hash_table_lookup (cfg->bb_hash, header->code + clause->handler_offset);
642 res = g_list_append (res, handler);
651 df_visit (MonoBasicBlock *start, int *dfn, MonoBasicBlock **array)
655 array [*dfn] = start;
656 /*g_print ("visit %d at %p\n", *dfn, start->cil_code);*/
657 for (i = 0; i < start->out_count; ++i) {
658 if (start->out_bb [i]->dfn)
661 start->out_bb [i]->dfn = *dfn;
662 start->out_bb [i]->df_parent = start;
663 array [*dfn] = start->out_bb [i];
664 df_visit (start->out_bb [i], dfn, array);
670 MonoBasicBlock *best;
674 previous_foreach (gconstpointer key, gpointer val, gpointer data)
676 PrevStruct *p = data;
677 MonoBasicBlock *bb = val;
678 //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,
679 //bb->method == p->best->method, bb->cil_code < p->code, bb->cil_code > p->best->cil_code);
681 if (bb->cil_code && bb->cil_code < p->code && bb->cil_code > p->best->cil_code)
685 static MonoBasicBlock*
686 find_previous (GHashTable *bb_hash, MonoBasicBlock *start, const guchar *code) {
692 g_hash_table_foreach (bb_hash, (GHFunc)previous_foreach, &p);
697 split_bblock (MonoCompile *cfg, MonoBasicBlock *first, MonoBasicBlock *second) {
706 * FIXME: take into account all the details:
707 * second may have been the target of more than one bblock
709 second->out_count = first->out_count;
710 second->out_bb = first->out_bb;
712 for (i = 0; i < first->out_count; ++i) {
713 bb = first->out_bb [i];
714 for (j = 0; j < bb->in_count; ++j) {
715 if (bb->in_bb [j] == first)
716 bb->in_bb [j] = second;
720 first->out_count = 0;
721 first->out_bb = NULL;
722 link_bblock (cfg, first, second);
724 second->last_ins = first->last_ins;
726 /*g_print ("start search at %p for %p\n", first->cil_code, second->cil_code);*/
727 for (inst = first->code; inst && inst->next; inst = inst->next) {
728 /*char *code = mono_disasm_code_one (NULL, cfg->method, inst->next->cil_code, NULL);
729 g_print ("found %p: %s", inst->next->cil_code, code);
731 if (inst->cil_code < second->cil_code && inst->next->cil_code >= second->cil_code) {
732 second->code = inst->next;
734 first->last_ins = inst;
735 second->next_bb = first->next_bb;
736 first->next_bb = second;
741 g_warning ("bblock split failed in %s::%s\n", cfg->method->klass->name, cfg->method->name);
747 mono_type_to_ldind (MonoType *type)
759 case MONO_TYPE_BOOLEAN:
773 case MONO_TYPE_FNPTR:
775 case MONO_TYPE_CLASS:
776 case MONO_TYPE_STRING:
777 case MONO_TYPE_OBJECT:
778 case MONO_TYPE_SZARRAY:
779 case MONO_TYPE_ARRAY:
780 return CEE_LDIND_REF;
788 case MONO_TYPE_VALUETYPE:
789 if (type->data.klass->enumtype) {
790 t = type->data.klass->enum_basetype->type;
795 g_error ("unknown type 0x%02x in type_to_ldind", type->type);
801 mono_type_to_stind (MonoType *type)
812 case MONO_TYPE_BOOLEAN:
824 case MONO_TYPE_FNPTR:
826 case MONO_TYPE_CLASS:
827 case MONO_TYPE_STRING:
828 case MONO_TYPE_OBJECT:
829 case MONO_TYPE_SZARRAY:
830 case MONO_TYPE_ARRAY:
831 return CEE_STIND_REF;
839 case MONO_TYPE_VALUETYPE:
840 if (type->data.klass->enumtype) {
841 t = type->data.klass->enum_basetype->type;
847 g_error ("unknown type %02x in type_to_stind", type->type);
853 * Returns the type used in the eval stack when @type is loaded.
854 * FIXME: return a MonoType/MonoClass for the byref and VALUETYPE cases.
857 type_to_eval_stack_type (MonoType *type, MonoInst *inst) {
861 inst->type = STACK_MP;
869 case MONO_TYPE_BOOLEAN:
875 inst->type = STACK_I4;
880 case MONO_TYPE_FNPTR:
881 inst->type = STACK_PTR;
883 case MONO_TYPE_CLASS:
884 case MONO_TYPE_STRING:
885 case MONO_TYPE_OBJECT:
886 case MONO_TYPE_SZARRAY:
887 case MONO_TYPE_ARRAY:
888 inst->type = STACK_OBJ;
892 inst->type = STACK_I8;
896 inst->type = STACK_R8;
898 case MONO_TYPE_VALUETYPE:
899 if (type->data.klass->enumtype) {
900 t = type->data.klass->enum_basetype->type;
903 inst->klass = type->data.klass;
904 inst->type = STACK_VTYPE;
908 g_error ("unknown type 0x%02x in eval stack type", type->type);
913 * The following tables are used to quickly validate the IL code in type_from_op ().
916 bin_num_table [STACK_MAX] [STACK_MAX] = {
917 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
918 {STACK_INV, STACK_I4, STACK_INV, STACK_PTR, STACK_INV, STACK_MP, STACK_INV, STACK_INV},
919 {STACK_INV, STACK_INV, STACK_I8, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
920 {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_MP, STACK_INV, STACK_INV},
921 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_R8, STACK_INV, STACK_INV, STACK_INV},
922 {STACK_INV, STACK_MP, STACK_INV, STACK_MP, STACK_INV, STACK_PTR, STACK_INV, STACK_INV},
923 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
924 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
929 STACK_INV, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_INV, STACK_INV, STACK_INV
932 /* reduce the size of this table */
934 bin_int_table [STACK_MAX] [STACK_MAX] = {
935 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
936 {STACK_INV, STACK_I4, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
937 {STACK_INV, STACK_INV, STACK_I8, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
938 {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
939 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
940 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
941 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
942 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
946 bin_comp_table [STACK_MAX] [STACK_MAX] = {
948 {0, 1, 0, 1, 0, 0, 4, 0},
949 {0, 0, 1, 0, 0, 0, 0, 0},
950 {0, 1, 0, 1, 0, 2, 4, 0},
951 {0, 0, 0, 0, 1, 0, 0, 0},
952 {0, 0, 0, 2, 0, 1, 0, 0},
953 {0, 4, 0, 4, 0, 0, 3, 0},
954 {0, 0, 0, 0, 0, 0, 0, 0},
957 /* reduce the size of this table */
959 shift_table [STACK_MAX] [STACK_MAX] = {
960 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
961 {STACK_INV, STACK_I4, STACK_INV, STACK_I4, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
962 {STACK_INV, STACK_I8, STACK_INV, STACK_I8, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
963 {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
964 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
965 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
966 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
967 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
971 * Tables to map from the non-specific opcode to the matching
972 * type-specific opcode.
974 /* handles from CEE_ADD to CEE_SHR_UN (CEE_REM_UN for floats) */
976 binops_op_map [STACK_MAX] = {
977 0, 0, OP_LADD-CEE_ADD, OP_PADD-CEE_ADD, OP_FADD-CEE_ADD, 0
980 /* handles from CEE_NEG to CEE_CONV_U8 */
982 unops_op_map [STACK_MAX] = {
983 0, 0, OP_LNEG-CEE_NEG, OP_PNEG-CEE_NEG, OP_FNEG-CEE_NEG, 0
986 /* handles from CEE_CONV_U2 to CEE_SUB_OVF_UN */
988 ovfops_op_map [STACK_MAX] = {
989 0, 0, OP_LCONV_TO_U2-CEE_CONV_U2, OP_PCONV_TO_U2-CEE_CONV_U2, OP_FCONV_TO_U2-CEE_CONV_U2, 0
992 /* handles from CEE_CONV_OVF_I1_UN to CEE_CONV_OVF_U_UN */
994 ovf2ops_op_map [STACK_MAX] = {
995 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
998 /* handles from CEE_CONV_OVF_I1 to CEE_CONV_OVF_U8 */
1000 ovf3ops_op_map [STACK_MAX] = {
1001 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
1004 /* handles from CEE_CEQ to CEE_CLT_UN */
1005 static const guint16
1006 ceqops_op_map [STACK_MAX] = {
1007 0, 0, OP_LCEQ-CEE_CEQ, OP_PCEQ-CEE_CEQ, OP_FCEQ-CEE_CEQ, 0
1011 * Sets ins->type (the type on the eval stack) according to the
1012 * type of the opcode and the arguments to it.
1013 * Invalid IL code is marked by setting ins->type to the invalid value STACK_INV.
1015 * FIXME: this function sets ins->type unconditionally in some cases, but
1016 * it should set it to invalid for some types (a conv.x on an object)
1019 type_from_op (MonoInst *ins) {
1020 switch (ins->opcode) {
1027 /* FIXME: check unverifiable args for STACK_MP */
1028 ins->type = bin_num_table [ins->inst_i0->type] [ins->inst_i1->type];
1029 ins->opcode += binops_op_map [ins->type];
1036 ins->type = bin_int_table [ins->inst_i0->type] [ins->inst_i1->type];
1037 ins->opcode += binops_op_map [ins->type];
1042 ins->type = shift_table [ins->inst_i0->type] [ins->inst_i1->type];
1043 ins->opcode += binops_op_map [ins->type];
1046 /* FIXME: handle some specifics with ins->next->type */
1047 ins->type = bin_comp_table [ins->inst_i0->type] [ins->inst_i1->type] ? STACK_I4: STACK_INV;
1051 case 256+CEE_CGT_UN:
1053 case 256+CEE_CLT_UN:
1054 ins->type = bin_comp_table [ins->inst_i0->type] [ins->inst_i1->type] ? STACK_I4: STACK_INV;
1055 ins->opcode += ceqops_op_map [ins->inst_i0->type];
1059 ins->type = neg_table [ins->inst_i0->type];
1060 ins->opcode += unops_op_map [ins->type];
1063 if (ins->inst_i0->type >= STACK_I4 && ins->inst_i0->type <= STACK_PTR)
1064 ins->type = ins->inst_i0->type;
1066 ins->type = STACK_INV;
1067 ins->opcode += unops_op_map [ins->type];
1073 ins->type = STACK_I4;
1074 ins->opcode += unops_op_map [ins->inst_i0->type];
1077 ins->type = STACK_R8;
1078 switch (ins->inst_i0->type) {
1083 ins->opcode = OP_LCONV_TO_R_UN;
1087 case CEE_CONV_OVF_I1:
1088 case CEE_CONV_OVF_U1:
1089 case CEE_CONV_OVF_I2:
1090 case CEE_CONV_OVF_U2:
1091 case CEE_CONV_OVF_I4:
1092 case CEE_CONV_OVF_U4:
1093 ins->type = STACK_I4;
1094 ins->opcode += ovf3ops_op_map [ins->inst_i0->type];
1096 case CEE_CONV_OVF_I_UN:
1097 case CEE_CONV_OVF_U_UN:
1098 ins->type = STACK_PTR;
1099 ins->opcode += ovf2ops_op_map [ins->inst_i0->type];
1101 case CEE_CONV_OVF_I1_UN:
1102 case CEE_CONV_OVF_I2_UN:
1103 case CEE_CONV_OVF_I4_UN:
1104 case CEE_CONV_OVF_U1_UN:
1105 case CEE_CONV_OVF_U2_UN:
1106 case CEE_CONV_OVF_U4_UN:
1107 ins->type = STACK_I4;
1108 ins->opcode += ovf2ops_op_map [ins->inst_i0->type];
1111 ins->type = STACK_PTR;
1112 switch (ins->inst_i0->type) {
1118 ins->opcode = OP_LCONV_TO_U;
1121 ins->opcode = OP_FCONV_TO_U;
1127 ins->type = STACK_I8;
1128 ins->opcode += unops_op_map [ins->inst_i0->type];
1130 case CEE_CONV_OVF_I8:
1131 case CEE_CONV_OVF_U8:
1132 ins->type = STACK_I8;
1133 ins->opcode += ovf3ops_op_map [ins->inst_i0->type];
1135 case CEE_CONV_OVF_U8_UN:
1136 case CEE_CONV_OVF_I8_UN:
1137 ins->type = STACK_I8;
1138 ins->opcode += ovf2ops_op_map [ins->inst_i0->type];
1142 ins->type = STACK_R8;
1143 ins->opcode += unops_op_map [ins->inst_i0->type];
1146 ins->type = STACK_R8;
1150 ins->type = STACK_I4;
1151 ins->opcode += ovfops_op_map [ins->inst_i0->type];
1154 case CEE_CONV_OVF_I:
1155 case CEE_CONV_OVF_U:
1156 ins->type = STACK_PTR;
1157 ins->opcode += ovfops_op_map [ins->inst_i0->type];
1160 case CEE_ADD_OVF_UN:
1162 case CEE_MUL_OVF_UN:
1164 case CEE_SUB_OVF_UN:
1165 ins->type = bin_num_table [ins->inst_i0->type] [ins->inst_i1->type];
1166 ins->opcode += ovfops_op_map [ins->inst_i0->type];
1169 g_error ("opcode 0x%04x not handled in type from op", ins->opcode);
1176 STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I8, STACK_MP, STACK_R8, STACK_R8, STACK_OBJ
1179 /* map ldelem.x to the matching ldind.x opcode */
1181 ldelem_to_ldind [] = {
1195 /* map stelem.x to the matching stind.x opcode */
1197 stelem_to_stind [] = {
1211 param_table [STACK_MAX] [STACK_MAX] = {
1216 check_values_to_signature (MonoInst *args, MonoType *this, MonoMethodSignature *sig) {
1220 switch (args->type) {
1230 for (i = 0; i < sig->param_count; ++i) {
1231 switch (args [i].type) {
1235 if (!sig->params [i]->byref)
1239 if (sig->params [i]->byref)
1241 switch (sig->params [i]->type) {
1242 case MONO_TYPE_CLASS:
1243 case MONO_TYPE_STRING:
1244 case MONO_TYPE_OBJECT:
1245 case MONO_TYPE_SZARRAY:
1246 case MONO_TYPE_ARRAY:
1253 if (sig->params [i]->byref)
1255 if (sig->params [i]->type != MONO_TYPE_R4 && sig->params [i]->type != MONO_TYPE_R8)
1264 /*if (!param_table [args [i].type] [sig->params [i]->type])
1272 * When we need a pointer to the current domain many times in a method, we
1273 * call mono_domain_get() once and we store the result in a local variable.
1274 * This function returns the variable that represents the MonoDomain*.
1276 inline static MonoInst *
1277 mono_get_domainvar (MonoCompile *cfg)
1279 if (!cfg->domainvar)
1280 cfg->domainvar = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1281 return cfg->domainvar;
1285 mono_compile_create_var (MonoCompile *cfg, MonoType *type, int opcode)
1288 int num = cfg->num_varinfo;
1290 if ((num + 1) >= cfg->varinfo_count) {
1291 cfg->varinfo_count = (cfg->varinfo_count + 2) * 2;
1292 cfg->varinfo = (MonoInst **)g_realloc (cfg->varinfo, sizeof (MonoInst*) * cfg->varinfo_count);
1293 cfg->vars = (MonoMethodVar **)g_realloc (cfg->vars, sizeof (MonoMethodVar*) * cfg->varinfo_count);
1296 mono_jit_stats.allocate_var++;
1298 MONO_INST_NEW (cfg, inst, opcode);
1299 inst->inst_c0 = num;
1300 inst->inst_vtype = type;
1301 inst->klass = mono_class_from_mono_type (type);
1302 /* if set to 1 the variable is native */
1305 cfg->varinfo [num] = inst;
1307 cfg->vars [num] = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoMethodVar));
1308 MONO_INIT_VARINFO (cfg->vars [num], num);
1311 //g_print ("created temp %d of type %s\n", num, mono_type_get_name (type));
1316 type_from_stack_type (MonoInst *ins) {
1317 switch (ins->type) {
1318 case STACK_I4: return &mono_defaults.int32_class->byval_arg;
1319 case STACK_I8: return &mono_defaults.int64_class->byval_arg;
1320 case STACK_PTR: return &mono_defaults.int_class->byval_arg;
1321 case STACK_R8: return &mono_defaults.double_class->byval_arg;
1322 case STACK_MP: return &mono_defaults.int_class->byval_arg;
1323 case STACK_OBJ: return &mono_defaults.object_class->byval_arg;
1324 case STACK_VTYPE: return &ins->klass->byval_arg;
1326 g_error ("stack type %d to montype not handled\n", ins->type);
1332 array_access_to_klass (int opcode)
1336 return mono_defaults.byte_class;
1338 return mono_defaults.uint16_class;
1341 return mono_defaults.int_class;
1344 return mono_defaults.sbyte_class;
1347 return mono_defaults.int16_class;
1350 return mono_defaults.int32_class;
1352 return mono_defaults.uint32_class;
1355 return mono_defaults.int64_class;
1358 return mono_defaults.single_class;
1361 return mono_defaults.double_class;
1362 case CEE_LDELEM_REF:
1363 case CEE_STELEM_REF:
1364 return mono_defaults.object_class;
1366 g_assert_not_reached ();
1372 mono_add_ins_to_end (MonoBasicBlock *bb, MonoInst *inst)
1376 MONO_ADD_INS (bb, inst);
1379 switch (bb->last_ins->opcode) {
1392 while (prev->next && prev->next != bb->last_ins)
1394 if (prev == bb->code) {
1395 if (bb->last_ins == bb->code) {
1396 inst->next = bb->code;
1399 inst->next = prev->next;
1403 inst->next = bb->last_ins;
1407 // g_warning ("handle conditional jump in add_ins_to_end ()\n");
1409 MONO_ADD_INS (bb, inst);
1415 mono_add_varcopy_to_end (MonoCompile *cfg, MonoBasicBlock *bb, int src, int dest)
1417 MonoInst *inst, *load;
1419 NEW_TEMPLOAD (cfg, load, src);
1421 NEW_TEMPSTORE (cfg, inst, dest, load);
1422 if (inst->opcode == CEE_STOBJ) {
1423 NEW_TEMPLOADA (cfg, inst, dest);
1424 handle_stobj (cfg, bb, inst, load, NULL, inst->klass, TRUE, FALSE);
1426 inst->cil_code = NULL;
1427 mono_add_ins_to_end (bb, inst);
1432 * This function is called to handle items that are left on the evaluation stack
1433 * at basic block boundaries. What happens is that we save the values to local variables
1434 * and we reload them later when first entering the target basic block (with the
1435 * handle_loaded_temps () function).
1436 * A single joint point will use the same variables (stored in the array bb->out_stack or
1437 * bb->in_stack, if the basic block is before or after the joint point).
1440 handle_stack_args (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst **sp, int count) {
1442 MonoBasicBlock *outb;
1443 MonoInst *inst, **locals;
1447 if (cfg->verbose_level > 3)
1448 g_print ("%d item(s) on exit from B%d\n", count, bb->block_num);
1449 if (!bb->out_scount) {
1451 bb->out_scount = count;
1452 //g_print ("bblock %d has out:", bb->block_num);
1453 for (i = 0; i < bb->out_count; ++i) {
1454 outb = bb->out_bb [i];
1455 //g_print (" %d", outb->block_num);
1456 if (outb->in_stack) {
1458 bb->out_stack = outb->in_stack;
1464 bb->out_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * count);
1465 for (i = 0; i < count; ++i) {
1467 * dietmar suggests that we can reuse temps already allocated
1468 * for this purpouse, if they occupy the same stack slot and if
1469 * they are of the same type.
1471 bb->out_stack [i] = mono_compile_create_var (cfg, type_from_stack_type (sp [i]), OP_LOCAL);
1475 locals = bb->out_stack;
1476 for (i = 0; i < count; ++i) {
1477 /* add store ops at the end of the bb, before the branch */
1478 NEW_TEMPSTORE (cfg, inst, locals [i]->inst_c0, sp [i]);
1479 if (inst->opcode == CEE_STOBJ) {
1480 NEW_TEMPLOADA (cfg, inst, locals [i]->inst_c0);
1481 handle_stobj (cfg, bb, inst, sp [i], sp [i]->cil_code, inst->klass, TRUE, FALSE);
1483 inst->cil_code = sp [i]->cil_code;
1484 mono_add_ins_to_end (bb, inst);
1486 if (cfg->verbose_level > 3)
1487 g_print ("storing %d to temp %d\n", i, locals [i]->inst_c0);
1490 for (i = 0; i < bb->out_count; ++i) {
1491 outb = bb->out_bb [i];
1492 if (outb->in_scount)
1493 continue; /* check they are the same locals */
1494 outb->in_scount = count;
1495 outb->in_stack = locals;
1501 ret_type_to_call_opcode (MonoType *type, int calli, int virt)
1506 return calli? OP_CALL_REG: virt? CEE_CALLVIRT: CEE_CALL;
1510 case MONO_TYPE_VOID:
1511 return calli? OP_VOIDCALL_REG: virt? OP_VOIDCALLVIRT: OP_VOIDCALL;
1514 case MONO_TYPE_BOOLEAN:
1517 case MONO_TYPE_CHAR:
1520 return calli? OP_CALL_REG: virt? CEE_CALLVIRT: CEE_CALL;
1524 return calli? OP_CALL_REG: virt? CEE_CALLVIRT: CEE_CALL;
1525 case MONO_TYPE_CLASS:
1526 case MONO_TYPE_STRING:
1527 case MONO_TYPE_OBJECT:
1528 case MONO_TYPE_SZARRAY:
1529 case MONO_TYPE_ARRAY:
1530 return calli? OP_CALL_REG: virt? CEE_CALLVIRT: CEE_CALL;
1533 return calli? OP_LCALL_REG: virt? OP_LCALLVIRT: OP_LCALL;
1536 return calli? OP_FCALL_REG: virt? OP_FCALLVIRT: OP_FCALL;
1537 case MONO_TYPE_VALUETYPE:
1538 if (type->data.klass->enumtype) {
1539 t = type->data.klass->enum_basetype->type;
1542 return calli? OP_VCALL_REG: virt? OP_VCALLVIRT: OP_VCALL;
1544 g_error ("unknown type %02x in ret_type_to_call_opcode", type->type);
1550 mono_create_jump_table (MonoCompile *cfg, MonoInst *label, MonoBasicBlock **bbs, int num_blocks)
1552 MonoJumpInfo *ji = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfo));
1554 ji->ip.label = label;
1555 ji->type = MONO_PATCH_INFO_SWITCH;
1556 ji->data.table = bbs;
1557 ji->next = cfg->patch_info;
1558 ji->table_size = num_blocks;
1559 cfg->patch_info = ji;
1563 * When we add a tree of instructions, we need to ensure the instructions currently
1564 * on the stack are executed before (like, if we load a value from a local).
1565 * We ensure this by saving the currently loaded values to temps and rewriting the
1566 * instructions to load the values.
1567 * This is not done for opcodes that terminate a basic block (because it's handled already
1568 * by handle_stack_args ()) and for opcodes that can't change values, like POP.
1571 handle_loaded_temps (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst **stack, MonoInst **sp)
1573 MonoInst *load, *store, *temp, *ins;
1575 while (stack < sp) {
1577 /* handle also other constants */
1578 if (ins->opcode != OP_ICONST) {
1579 temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1580 NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
1581 store->cil_code = ins->cil_code;
1582 if (store->opcode == CEE_STOBJ) {
1583 NEW_TEMPLOADA (cfg, store, temp->inst_c0);
1584 handle_stobj (cfg, bblock, store, ins, ins->cil_code, temp->klass, FALSE, FALSE);
1586 MONO_ADD_INS (bblock, store);
1587 NEW_TEMPLOAD (cfg, load, temp->inst_c0);
1588 load->cil_code = ins->cil_code;
1596 mono_spill_call (MonoCompile *cfg, MonoBasicBlock *bblock, MonoCallInst *call, MonoMethodSignature *sig, gboolean ret_object,
1597 const guint8 *ip, gboolean to_end)
1599 MonoInst *temp, *store, *ins = (MonoInst*)call;
1600 MonoType *ret = sig->ret;
1602 if (!MONO_TYPE_IS_VOID (ret) || ret_object) {
1604 call->inst.type = STACK_OBJ;
1605 call->inst.opcode = CEE_CALL;
1606 temp = mono_compile_create_var (cfg, &mono_defaults.string_class->byval_arg, OP_LOCAL);
1608 type_to_eval_stack_type (ret, ins);
1609 temp = mono_compile_create_var (cfg, ret, OP_LOCAL);
1612 if (MONO_TYPE_ISSTRUCT (ret)) {
1615 /* we use this to allocate native sized structs */
1616 temp->unused = sig->pinvoke;
1618 NEW_TEMPLOADA (cfg, loada, temp->inst_c0);
1619 if (call->inst.opcode == OP_VCALL)
1620 ins->inst_left = loada;
1622 ins->inst_right = loada; /* a virtual or indirect call */
1625 mono_add_ins_to_end (bblock, ins);
1627 MONO_ADD_INS (bblock, ins);
1629 NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
1630 store->cil_code = ip;
1632 mono_add_ins_to_end (bblock, store);
1634 MONO_ADD_INS (bblock, store);
1636 return temp->inst_c0;
1639 mono_add_ins_to_end (bblock, ins);
1641 MONO_ADD_INS (bblock, ins);
1646 inline static MonoCallInst *
1647 mono_emit_call_args (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethodSignature *sig,
1648 MonoInst **args, int calli, int virtual, const guint8 *ip, gboolean to_end)
1653 MONO_INST_NEW_CALL (cfg, call, ret_type_to_call_opcode (sig->ret, calli, virtual));
1655 call->inst.cil_code = ip;
1657 call->signature = sig;
1658 call = mono_arch_call_opcode (cfg, bblock, call, virtual);
1660 for (i = 0; i < (sig->param_count + sig->hasthis); ++i) {
1661 if (call->args [i]) {
1663 mono_add_ins_to_end (bblock, call->args [i]);
1665 MONO_ADD_INS (bblock, call->args [i]);
1672 mono_emit_calli (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethodSignature *sig,
1673 MonoInst **args, MonoInst *addr, const guint8 *ip)
1675 MonoCallInst *call = mono_emit_call_args (cfg, bblock, sig, args, TRUE, FALSE, ip, FALSE);
1677 call->inst.inst_i0 = addr;
1679 return mono_spill_call (cfg, bblock, call, sig, FALSE, ip, FALSE);
1682 static MonoCallInst*
1683 mono_emit_method_call (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *method, MonoMethodSignature *sig,
1684 MonoInst **args, const guint8 *ip, MonoInst *this)
1686 gboolean virtual = this != NULL;
1689 call = mono_emit_call_args (cfg, bblock, sig, args, FALSE, virtual, ip, FALSE);
1691 if (this && sig->hasthis &&
1692 (method->klass->marshalbyref || method->klass == mono_defaults.object_class) &&
1693 !(method->flags & METHOD_ATTRIBUTE_VIRTUAL) && !MONO_CHECK_THIS (this)) {
1694 call->method = mono_marshal_get_remoting_invoke_with_check (method);
1696 call->method = method;
1698 call->inst.flags |= MONO_INST_HAS_METHOD;
1699 call->inst.inst_left = this;
1705 mono_emit_method_call_spilled (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *method,
1706 MonoInst **args, const guint8 *ip, MonoInst *this)
1708 MonoCallInst *call = mono_emit_method_call (cfg, bblock, method, method->signature, args, ip, this);
1710 return mono_spill_call (cfg, bblock, call, method->signature, method->string_ctor, ip, FALSE);
1714 mono_emit_native_call (MonoCompile *cfg, MonoBasicBlock *bblock, gconstpointer func, MonoMethodSignature *sig,
1715 MonoInst **args, const guint8 *ip, gboolean to_end)
1721 call = mono_emit_call_args (cfg, bblock, sig, args, FALSE, FALSE, ip, to_end);
1723 return mono_spill_call (cfg, bblock, call, sig, func == mono_array_new_va, ip, to_end);
1727 mono_emit_jit_icall (MonoCompile *cfg, MonoBasicBlock *bblock, gconstpointer func, MonoInst **args, const guint8 *ip)
1729 MonoJitICallInfo *info = mono_find_jit_icall_by_addr (func);
1732 g_warning ("unregistered JIT ICall");
1733 g_assert_not_reached ();
1736 return mono_emit_native_call (cfg, bblock, info->wrapper, info->sig, args, ip, FALSE);
1740 mono_emulate_opcode (MonoCompile *cfg, MonoInst *tree, MonoInst **iargs, MonoJitICallInfo *info)
1742 MonoInst *ins, *temp = NULL, *store, *load;
1746 /*g_print ("emulating: ");
1747 mono_print_tree (tree);
1749 MONO_INST_NEW_CALL (cfg, call, ret_type_to_call_opcode (info->sig->ret, FALSE, FALSE));
1750 ins = (MonoInst*)call;
1752 call->inst.cil_code = tree->cil_code;
1754 call->signature = info->sig;
1756 call = mono_arch_call_opcode (cfg, cfg->cbb, call, FALSE);
1758 if (!MONO_TYPE_IS_VOID (info->sig->ret)) {
1759 temp = mono_compile_create_var (cfg, info->sig->ret, OP_LOCAL);
1760 NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
1761 store->cil_code = tree->cil_code;
1766 nargs = info->sig->param_count + info->sig->hasthis;
1768 for (i = 1; i < nargs; i++) {
1769 call->args [i - 1]->next = call->args [i];
1773 call->args [nargs - 1]->next = store;
1775 if (cfg->prev_ins) {
1776 store->next = cfg->prev_ins->next;
1778 cfg->prev_ins->next = call->args [0];
1780 cfg->prev_ins->next = store;
1782 store->next = cfg->cbb->code;
1784 cfg->cbb->code = call->args [0];
1786 cfg->cbb->code = store;
1790 call->fptr = info->wrapper;
1792 if (!MONO_TYPE_IS_VOID (info->sig->ret)) {
1793 NEW_TEMPLOAD (cfg, load, temp->inst_c0);
1798 static MonoMethodSignature *
1799 mono_get_element_address_signature (int arity)
1801 static GHashTable *sighash = NULL;
1802 MonoMethodSignature *res;
1806 sighash = g_hash_table_new (NULL, NULL);
1809 if ((res = g_hash_table_lookup (sighash, (gpointer)arity)))
1812 res = mono_metadata_signature_alloc (mono_defaults.corlib, arity + 1);
1814 res->params [0] = &mono_defaults.array_class->byval_arg;
1816 for (i = 1; i <= arity; i++)
1817 res->params [i] = &mono_defaults.int_class->byval_arg;
1819 res->ret = &mono_defaults.int_class->byval_arg;
1821 g_hash_table_insert (sighash, (gpointer)arity, res);
1827 handle_stobj (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *dest, MonoInst *src, const unsigned char *ip, MonoClass *klass, gboolean to_end, gboolean native) {
1828 MonoInst *iargs [3];
1833 * This check breaks with spilled vars... need to handle it during verification anyway.
1834 * g_assert (klass && klass == src->klass && klass == dest->klass);
1838 n = mono_class_native_size (klass, NULL);
1840 n = mono_class_value_size (klass, NULL);
1844 NEW_ICONST (cfg, iargs [2], n);
1846 mono_emit_native_call (cfg, bblock, helper_memcpy, helper_sig_memcpy, iargs, ip, to_end);
1850 handle_initobj (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *dest, const guchar *ip, MonoClass *klass, MonoInst **stack_start, MonoInst **sp)
1852 MonoInst *iargs [2];
1853 MonoInst *ins, *zero_int32;
1856 NEW_ICONST (cfg, zero_int32, 0);
1858 mono_class_init (klass);
1859 n = mono_class_value_size (klass, NULL);
1860 MONO_INST_NEW (cfg, ins, 0);
1862 ins->inst_left = dest;
1863 ins->inst_right = zero_int32;
1866 ins->opcode = CEE_STIND_I1;
1867 MONO_ADD_INS (bblock, ins);
1870 ins->opcode = CEE_STIND_I2;
1871 MONO_ADD_INS (bblock, ins);
1874 ins->opcode = CEE_STIND_I4;
1875 MONO_ADD_INS (bblock, ins);
1878 handle_loaded_temps (cfg, bblock, stack_start, sp);
1879 NEW_ICONST (cfg, ins, n);
1882 mono_emit_jit_icall (cfg, bblock, helper_initobj, iargs, ip);
1887 #define CODE_IS_STLOC(ip) (((ip) [0] >= CEE_STLOC_0 && (ip) [0] <= CEE_STLOC_3) || ((ip) [0] == CEE_STLOC_S))
1890 mono_method_check_inlining (MonoMethod *method)
1892 MonoMethodHeader *header = ((MonoMethodNormal *)method)->header;
1893 MonoMethodSignature *signature = method->signature;
1896 /* fixme: we should inline wrappers */
1897 if (method->wrapper_type != MONO_WRAPPER_NONE)
1900 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
1901 (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
1902 (method->iflags & METHOD_IMPL_ATTRIBUTE_NOINLINING) ||
1903 (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) ||
1904 (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
1905 (method->klass->marshalbyref) ||
1906 !header || header->num_clauses ||
1907 /* fixme: why cant we inline valuetype returns? */
1908 MONO_TYPE_ISSTRUCT (signature->ret))
1911 /* its not worth to inline methods with valuetype arguments?? */
1912 for (i = 0; i < signature->param_count; i++) {
1913 if (MONO_TYPE_ISSTRUCT (signature->params [i])) {
1918 //if (!MONO_TYPE_IS_VOID (signature->ret)) return FALSE;
1920 /* also consider num_locals? */
1921 if (header->code_size < 20)
1928 mini_get_opcode_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
1933 if (cmethod->klass == mono_defaults.string_class) {
1934 if (cmethod->name [0] != 'g' || strcmp (cmethod->name, "get_Chars"))
1937 } else if (cmethod->klass == mono_defaults.math_class) {
1938 if (strcmp (cmethod->name, "Sin") == 0)
1940 else if (strcmp (cmethod->name, "Cos") == 0)
1942 else if (strcmp (cmethod->name, "Tan") == 0)
1944 else if (strcmp (cmethod->name, "Atan") == 0)
1946 else if (strcmp (cmethod->name, "Sqrt") == 0)
1948 else if (strcmp (cmethod->name, "Abs") == 0 && fsig->params [0]->type == MONO_TYPE_R8)
1955 pc = fsig->param_count + fsig->hasthis;
1956 MONO_INST_NEW (cfg, ins, op);
1959 ins->inst_i0 = args [0];
1961 ins->inst_i1 = args [1];
1968 mono_save_args (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethodSignature *sig, MonoInst **sp, MonoInst **args)
1970 MonoInst *store, *temp;
1973 g_assert (!MONO_TYPE_ISSTRUCT (sig->ret));
1975 if (!sig->hasthis && sig->param_count == 0)
1979 if (sp [0]->opcode == OP_ICONST) {
1982 temp = mono_compile_create_var (cfg, type_from_stack_type (*sp), OP_LOCAL);
1984 NEW_TEMPSTORE (cfg, store, temp->inst_c0, *sp);
1985 store->cil_code = sp [0]->cil_code;
1986 MONO_ADD_INS (bblock, store);
1991 for (i = 0; i < sig->param_count; ++i) {
1992 if (sp [0]->opcode == OP_ICONST) {
1995 temp = mono_compile_create_var (cfg, sig->params [i], OP_LOCAL);
1997 NEW_TEMPSTORE (cfg, store, temp->inst_c0, *sp);
1998 store->cil_code = sp [0]->cil_code;
1999 if (store->opcode == CEE_STOBJ) {
2000 NEW_TEMPLOADA (cfg, store, temp->inst_c0);
2001 handle_stobj (cfg, bblock, store, *sp, sp [0]->cil_code, temp->klass, FALSE, FALSE);
2003 MONO_ADD_INS (bblock, store);
2011 inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoBasicBlock *bblock, MonoInst **sp,
2012 guchar *ip, guint real_offset, GList *dont_inline, MonoBasicBlock **last_b)
2014 MonoInst *ins, *rvar = NULL;
2015 MonoMethodHeader *cheader;
2016 MonoBasicBlock *ebblock, *sbblock;
2017 int i, costs, new_locals_offset;
2019 if (cfg->verbose_level > 2)
2020 g_print ("INLINE START %p %s\n", cmethod, mono_method_full_name (cmethod, TRUE));
2022 cheader = ((MonoMethodNormal *)cmethod)->header;
2024 if (!cmethod->inline_info) {
2025 mono_jit_stats.inlineable_methods++;
2026 cmethod->inline_info = 1;
2028 /* allocate space to store the return value */
2029 if (!MONO_TYPE_IS_VOID (fsig->ret))
2030 rvar = mono_compile_create_var (cfg, fsig->ret, OP_LOCAL);
2032 /* allocate local variables */
2033 new_locals_offset = cfg->num_varinfo;
2034 for (i = 0; i < cheader->num_locals; ++i)
2035 mono_compile_create_var (cfg, cheader->locals [i], OP_LOCAL);
2037 /* allocate starte and end blocks */
2038 sbblock = NEW_BBLOCK (cfg);
2039 sbblock->block_num = cfg->num_bblocks++;
2040 sbblock->real_offset = real_offset;
2042 ebblock = NEW_BBLOCK (cfg);
2043 ebblock->block_num = cfg->num_bblocks++;
2044 ebblock->real_offset = real_offset;
2046 costs = mono_method_to_ir (cfg, cmethod, sbblock, ebblock, new_locals_offset, rvar, dont_inline, sp, real_offset, *ip == CEE_CALLVIRT);
2048 if (costs >= 0 && costs < 60) {
2049 if (cfg->verbose_level > 2)
2050 g_print ("INLINE END %s\n", mono_method_full_name (cmethod, TRUE));
2052 mono_jit_stats.inlined_methods++;
2054 /* always add some code to avoid block split failures */
2055 MONO_INST_NEW (cfg, ins, CEE_NOP);
2056 MONO_ADD_INS (bblock, ins);
2059 bblock->next_bb = sbblock;
2060 link_bblock (cfg, bblock, sbblock);
2063 NEW_TEMPLOAD (cfg, ins, rvar->inst_c0);
2069 if (cfg->verbose_level > 2)
2070 g_print ("INLINE ABORTED %s\n", mono_method_full_name (cmethod, TRUE));
2076 * Some of these comments may well be out-of-date.
2077 * Design decisions: we do a single pass over the IL code (and we do bblock
2078 * splitting/merging in the few cases when it's required: a back jump to an IL
2079 * address that was not already seen as bblock starting point).
2080 * Code is validated as we go (full verification is still better left to metadata/verify.c).
2081 * Complex operations are decomposed in simpler ones right away. We need to let the
2082 * arch-specific code peek and poke inside this process somehow (except when the
2083 * optimizations can take advantage of the full semantic info of coarse opcodes).
2084 * All the opcodes of the form opcode.s are 'normalized' to opcode.
2085 * MonoInst->opcode initially is the IL opcode or some simplification of that
2086 * (OP_LOAD, OP_STORE). The arch-specific code may rearrange it to an arch-specific
2087 * opcode with value bigger than OP_LAST.
2088 * At this point the IR can be handed over to an interpreter, a dumb code generator
2089 * or to the optimizing code generator that will translate it to SSA form.
2091 * Profiling directed optimizations.
2092 * We may compile by default with few or no optimizations and instrument the code
2093 * or the user may indicate what methods to optimize the most either in a config file
2094 * or through repeated runs where the compiler applies offline the optimizations to
2095 * each method and then decides if it was worth it.
2098 * * consider using an array instead of an hash table (bb_hash)
2101 #define CHECK_TYPE(ins) if (!(ins)->type) goto unverified
2102 #define CHECK_STACK(num) if ((sp - stack_start) < (num)) goto unverified
2103 #define CHECK_STACK_OVF(num) if (((sp - stack_start) + (num)) > header->max_stack) goto unverified
2105 /* offset from br.s -> br like opcodes */
2106 #define BIG_BRANCH_OFFSET 13
2109 * mono_method_to_ir: translates IL into basic blocks containing trees
2112 mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock,
2113 int locals_offset, MonoInst *return_var, GList *dont_inline, MonoInst **inline_args,
2114 guint inline_offset, gboolean is_virtual_call)
2116 MonoInst *zero_int32, *zero_int64, *zero_ptr, *zero_obj, *zero_r8;
2117 MonoInst *ins, **sp, **stack_start;
2118 MonoBasicBlock *bblock, *tblock = NULL, *init_localsbb = NULL;
2120 MonoMethod *cmethod;
2121 MonoInst **arg_array;
2122 MonoMethodHeader *header;
2124 guint32 token, ins_flag;
2126 unsigned char *ip, *end, *target;
2127 static double r8_0 = 0.0;
2128 MonoMethodSignature *sig;
2129 MonoType **param_types;
2130 GList *bb_recheck = NULL, *tmp;
2131 int i, n, start_new_bblock, align;
2132 int num_calls = 0, inline_costs = 0;
2133 int *filter_lengths = NULL;
2134 int breakpoint_id = 0;
2137 image = method->klass->image;
2138 header = ((MonoMethodNormal *)method)->header;
2139 sig = method->signature;
2140 ip = (unsigned char*)header->code;
2141 end = ip + header->code_size;
2142 mono_jit_stats.cil_code_size += header->code_size;
2144 if (cfg->method == method) {
2146 bbhash = cfg->bb_hash;
2148 real_offset = inline_offset;
2149 bbhash = g_hash_table_new (g_direct_hash, NULL);
2152 dont_inline = g_list_prepend (dont_inline, method);
2153 if (cfg->method == method) {
2156 cfg->bb_entry = start_bblock = NEW_BBLOCK (cfg);
2157 start_bblock->cil_code = NULL;
2158 start_bblock->cil_length = 0;
2159 start_bblock->block_num = cfg->num_bblocks++;
2162 cfg->bb_exit = end_bblock = NEW_BBLOCK (cfg);
2163 end_bblock->cil_code = NULL;
2164 end_bblock->cil_length = 0;
2165 end_bblock->block_num = cfg->num_bblocks++;
2166 g_assert (cfg->num_bblocks == 2);
2168 arg_array = alloca (sizeof (MonoInst *) * (sig->hasthis + sig->param_count));
2169 for (i = sig->hasthis + sig->param_count - 1; i >= 0; i--)
2170 arg_array [i] = cfg->varinfo [i];
2172 if (mono_compile_aot)
2173 cfg->opt |= MONO_OPT_SAHRED;
2175 if (header->num_clauses) {
2176 int size = sizeof (int) * header->num_clauses;
2177 filter_lengths = alloca (size);
2178 memset (filter_lengths, 0, size);
2180 /* handle exception clauses */
2181 for (i = 0; i < header->num_clauses; ++i) {
2182 //unsigned char *p = ip;
2183 MonoExceptionClause *clause = &header->clauses [i];
2184 GET_BBLOCK (cfg, bbhash, tblock, ip + clause->try_offset);
2185 tblock->real_offset = clause->try_offset;
2186 GET_BBLOCK (cfg, bbhash, tblock, ip + clause->handler_offset);
2187 tblock->real_offset = clause->handler_offset;
2188 /*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);
2190 g_print ("%s", mono_disasm_code_one (NULL, method, p, &p));
2192 /* catch and filter blocks get the exception object on the stack */
2193 if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE ||
2194 clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
2195 /* mostly like handle_stack_args (), but just sets the input args */
2196 /* g_print ("handling clause at IL_%04x\n", clause->handler_offset); */
2198 cfg->exvar = mono_compile_create_var (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL);
2199 /* prevent it from being register allocated */
2200 cfg->exvar->flags |= MONO_INST_INDIRECT;
2202 tblock->in_scount = 1;
2203 tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
2204 tblock->in_stack [0] = cfg->exvar;
2205 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
2206 GET_BBLOCK (cfg, bbhash, tblock, ip + clause->token_or_filter);
2207 tblock->real_offset = clause->token_or_filter;
2208 tblock->in_scount = 1;
2209 tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
2210 tblock->in_stack [0] = cfg->exvar;
2216 arg_array = alloca (sizeof (MonoInst *) * (sig->hasthis + sig->param_count));
2217 mono_save_args (cfg, start_bblock, sig, inline_args, arg_array);
2220 /* FIRST CODE BLOCK */
2221 bblock = NEW_BBLOCK (cfg);
2222 bblock->cil_code = ip;
2224 ADD_BBLOCK (cfg, bbhash, bblock);
2226 if (cfg->method == method) {
2227 breakpoint_id = mono_debugger_method_has_breakpoint (method);
2228 if (breakpoint_id && (mono_debug_format != MONO_DEBUG_FORMAT_DEBUGGER)) {
2229 MONO_INST_NEW (cfg, ins, CEE_BREAK);
2230 MONO_ADD_INS (bblock, ins);
2234 if ((header->init_locals || (cfg->method == method && (cfg->opt & MONO_OPT_SAHRED)))) {
2235 /* we use a separate basic block for the initialization code */
2236 cfg->bb_init = init_localsbb = NEW_BBLOCK (cfg);
2237 init_localsbb->real_offset = real_offset;
2238 start_bblock->next_bb = init_localsbb;
2239 init_localsbb->next_bb = bblock;
2240 link_bblock (cfg, start_bblock, init_localsbb);
2241 link_bblock (cfg, init_localsbb, bblock);
2242 init_localsbb->block_num = cfg->num_bblocks++;
2244 start_bblock->next_bb = bblock;
2245 link_bblock (cfg, start_bblock, bblock);
2248 mono_debug_init_method (cfg, bblock, breakpoint_id);
2250 param_types = mono_mempool_alloc (cfg->mempool, sizeof (MonoType*) * (sig->hasthis + sig->param_count));
2252 param_types [0] = method->klass->valuetype?&method->klass->this_arg:&method->klass->byval_arg;
2253 for (n = 0; n < sig->param_count; ++n)
2254 param_types [n + sig->hasthis] = sig->params [n];
2256 /* do this somewhere outside - not here */
2257 NEW_ICONST (cfg, zero_int32, 0);
2258 NEW_ICONST (cfg, zero_int64, 0);
2259 zero_int64->type = STACK_I8;
2260 NEW_PCONST (cfg, zero_ptr, 0);
2261 NEW_PCONST (cfg, zero_obj, 0);
2262 zero_obj->type = STACK_OBJ;
2264 MONO_INST_NEW (cfg, zero_r8, OP_R8CONST);
2265 zero_r8->type = STACK_R8;
2266 zero_r8->inst_p0 = &r8_0;
2268 /* add a check for this != NULL to inlined methods */
2269 if (is_virtual_call) {
2270 MONO_INST_NEW (cfg, ins, OP_CHECK_THIS);
2271 NEW_ARGLOAD (cfg, ins->inst_left, 0);
2273 MONO_ADD_INS (bblock, ins);
2276 /* we use a spare stack slot in SWITCH and NEWOBJ and others */
2277 stack_start = sp = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * (header->max_stack + 1));
2280 start_new_bblock = 0;
2283 if (cfg->method == method)
2284 real_offset = ip - header->code;
2286 real_offset = inline_offset;
2288 if (start_new_bblock) {
2289 bblock->cil_length = ip - bblock->cil_code;
2290 if (start_new_bblock == 2) {
2291 g_assert (ip == tblock->cil_code);
2293 GET_BBLOCK (cfg, bbhash, tblock, ip);
2295 bblock->next_bb = tblock;
2297 start_new_bblock = 0;
2298 for (i = 0; i < bblock->in_scount; ++i) {
2299 NEW_TEMPLOAD (cfg, ins, bblock->in_stack [i]->inst_c0);
2303 if ((tblock = g_hash_table_lookup (bbhash, ip)) && (tblock != bblock)) {
2304 link_bblock (cfg, bblock, tblock);
2305 if (sp != stack_start) {
2306 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
2309 bblock->next_bb = tblock;
2311 for (i = 0; i < bblock->in_scount; ++i) {
2312 NEW_TEMPLOAD (cfg, ins, bblock->in_stack [i]->inst_c0);
2318 if (cfg->verbose_level > 3)
2319 g_print ("converting (in B%d: stack: %d) %s", bblock->block_num, sp-stack_start, mono_disasm_code_one (NULL, method, ip, NULL));
2326 MONO_INST_NEW (cfg, ins, CEE_BREAK);
2327 ins->cil_code = ip++;
2328 MONO_ADD_INS (bblock, ins);
2334 CHECK_STACK_OVF (1);
2335 n = (*ip)-CEE_LDARG_0;
2336 NEW_ARGLOAD (cfg, ins, n);
2337 ins->cil_code = ip++;
2344 CHECK_STACK_OVF (1);
2345 n = (*ip)-CEE_LDLOC_0;
2346 NEW_LOCLOAD (cfg, ins, n);
2347 ins->cil_code = ip++;
2355 n = (*ip)-CEE_STLOC_0;
2357 handle_loaded_temps (cfg, bblock, stack_start, sp);
2358 NEW_LOCSTORE (cfg, ins, n, *sp);
2360 if (ins->opcode == CEE_STOBJ) {
2361 NEW_LOCLOADA (cfg, ins, n);
2362 handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE);
2364 MONO_ADD_INS (bblock, ins);
2369 CHECK_STACK_OVF (1);
2370 NEW_ARGLOAD (cfg, ins, ip [1]);
2376 CHECK_STACK_OVF (1);
2377 NEW_ARGLOADA (cfg, ins, ip [1]);
2385 NEW_ARGSTORE (cfg, ins, ip [1], *sp);
2386 handle_loaded_temps (cfg, bblock, stack_start, sp);
2388 if (ins->opcode == CEE_STOBJ) {
2389 NEW_ARGLOADA (cfg, ins, ip [1]);
2390 handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE);
2392 MONO_ADD_INS (bblock, ins);
2396 CHECK_STACK_OVF (1);
2397 NEW_LOCLOAD (cfg, ins, ip [1]);
2403 CHECK_STACK_OVF (1);
2404 NEW_LOCLOADA (cfg, ins, ip [1]);
2412 handle_loaded_temps (cfg, bblock, stack_start, sp);
2413 NEW_LOCSTORE (cfg, ins, ip [1], *sp);
2415 if (ins->opcode == CEE_STOBJ) {
2416 NEW_LOCLOADA (cfg, ins, ip [1]);
2417 handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE);
2419 MONO_ADD_INS (bblock, ins);
2424 CHECK_STACK_OVF (1);
2425 NEW_PCONST (cfg, ins, NULL);
2427 ins->type = STACK_OBJ;
2432 CHECK_STACK_OVF (1);
2433 NEW_ICONST (cfg, ins, -1);
2447 CHECK_STACK_OVF (1);
2448 NEW_ICONST (cfg, ins, (*ip) - CEE_LDC_I4_0);
2454 CHECK_STACK_OVF (1);
2456 NEW_ICONST (cfg, ins, *((signed char*)ip));
2462 CHECK_STACK_OVF (1);
2463 NEW_ICONST (cfg, ins, (gint32)read32 (ip + 1));
2469 CHECK_STACK_OVF (1);
2470 MONO_INST_NEW (cfg, ins, OP_I8CONST);
2472 ins->type = STACK_I8;
2474 ins->inst_l = (gint64)read64 (ip);
2479 float *f = g_malloc (sizeof (float));
2480 CHECK_STACK_OVF (1);
2481 MONO_INST_NEW (cfg, ins, OP_R4CONST);
2482 ins->type = STACK_R8;
2491 double *d = g_malloc (sizeof (double));
2492 CHECK_STACK_OVF (1);
2493 MONO_INST_NEW (cfg, ins, OP_R8CONST);
2494 ins->type = STACK_R8;
2503 MonoInst *temp, *store;
2505 CHECK_STACK_OVF (1);
2510 * small optimization: if the loaded value was from a local already,
2511 * just load it twice.
2513 if (ins->ssa_op == MONO_SSA_LOAD &&
2514 (ins->inst_i0->opcode == OP_LOCAL || ins->inst_i0->opcode == OP_ARG)) {
2516 MONO_INST_NEW (cfg, temp, 0);
2518 temp->cil_code = ip;
2521 temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
2522 temp->cil_code = ip;
2523 NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
2524 store->cil_code = ip;
2525 MONO_ADD_INS (bblock, store);
2526 NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
2529 NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
2539 MONO_INST_NEW (cfg, ins, CEE_POP);
2540 MONO_ADD_INS (bblock, ins);
2541 ins->cil_code = ip++;
2546 if (stack_start != sp)
2548 MONO_INST_NEW (cfg, ins, CEE_JMP);
2549 token = read32 (ip + 1);
2550 /* FIXME: check the signature matches */
2551 cmethod = mono_get_method (image, token, NULL);
2553 * The current magic trampoline can't handle this
2554 * apparently, so we compile the method right away.
2555 * Later, we may need to fix the trampoline or use a different one.
2557 ins->inst_p0 = mono_compile_method (cmethod);
2558 MONO_ADD_INS (bblock, ins);
2560 start_new_bblock = 1;
2564 case CEE_CALLVIRT: {
2565 MonoInst *addr = NULL;
2566 MonoMethodSignature *fsig = NULL;
2567 int temp, array_rank = 0;
2568 int virtual = *ip == CEE_CALLVIRT;
2570 token = read32 (ip + 1);
2572 if (*ip == CEE_CALLI) {
2577 if (method->wrapper_type != MONO_WRAPPER_NONE)
2578 fsig = (MonoMethodSignature *)mono_method_get_wrapper_data (method, token);
2580 fsig = mono_metadata_parse_signature (image, token);
2582 n = fsig->param_count + fsig->hasthis;
2585 cmethod = mono_get_method (image, token, NULL);
2587 if (!cmethod->klass->inited)
2588 mono_class_init (cmethod->klass);
2590 if (cmethod->signature->pinvoke) {
2591 #ifdef MONO_USE_EXC_TABLES
2592 if (mono_method_blittable (cmethod)) {
2593 fsig = cmethod->signature;
2596 MonoMethod *wrapper = mono_marshal_get_native_wrapper (cmethod);
2597 fsig = wrapper->signature;
2598 #ifdef MONO_USE_EXC_TABLES
2602 fsig = cmethod->signature;
2605 n = fsig->param_count + fsig->hasthis;
2607 if (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL &&
2608 cmethod->klass->parent == mono_defaults.array_class) {
2609 array_rank = cmethod->klass->rank;
2612 if (cmethod->string_ctor)
2613 g_assert_not_reached ();
2619 //g_assert (!virtual || fsig->hasthis);
2623 if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_get_opcode_for_method (cfg, cmethod, fsig, sp))) {
2626 if (MONO_TYPE_IS_VOID (fsig->ret)) {
2627 MONO_ADD_INS (bblock, ins);
2629 type_to_eval_stack_type (fsig->ret, ins);
2638 if ((cfg->opt & MONO_OPT_INLINE) && cmethod &&
2639 (!virtual || !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) || (cmethod->flags & METHOD_ATTRIBUTE_FINAL)) &&
2640 mono_method_check_inlining (cmethod) &&
2641 !g_list_find (dont_inline, cmethod)) {
2643 MonoBasicBlock *ebblock;
2645 if ((costs = inline_method (cfg, cmethod, fsig, bblock, sp, ip, real_offset, dont_inline, &ebblock))) {
2649 GET_BBLOCK (cfg, bbhash, bblock, ip);
2650 ebblock->next_bb = bblock;
2651 link_bblock (cfg, ebblock, bblock);
2652 if (!MONO_TYPE_IS_VOID (fsig->ret))
2655 if (sp != stack_start) {
2656 handle_stack_args (cfg, ebblock, stack_start, sp - stack_start);
2659 start_new_bblock = 1;
2661 inline_costs += costs;
2666 inline_costs += 10 * num_calls++;
2667 handle_loaded_temps (cfg, bblock, stack_start, sp);
2669 /* tail recursion elimination */
2670 if ((cfg->opt & MONO_OPT_TAILC) && *ip == CEE_CALL && cmethod == cfg->method && ip [5] == CEE_RET) {
2671 gboolean has_vtargs = FALSE;
2674 /* keep it simple */
2675 for (i = fsig->param_count - 1; i >= 0; i--) {
2676 if (MONO_TYPE_ISSTRUCT (cmethod->signature->params [i]))
2681 for (i = 0; i < n; ++i) {
2682 NEW_ARGSTORE (cfg, ins, i, sp [i]);
2684 MONO_ADD_INS (bblock, ins);
2686 MONO_INST_NEW (cfg, ins, CEE_BR);
2688 MONO_ADD_INS (bblock, ins);
2689 tblock = start_bblock->out_bb [0];
2690 link_bblock (cfg, bblock, tblock);
2691 ins->inst_target_bb = tblock;
2692 start_new_bblock = 1;
2695 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
2696 /* just create a dummy - the value is never used */
2697 ins = mono_compile_create_var (cfg, fsig->ret, OP_LOCAL);
2698 NEW_TEMPLOAD (cfg, *sp, ins->inst_c0);
2706 if (*ip == CEE_CALLI) {
2708 if ((temp = mono_emit_calli (cfg, bblock, fsig, sp, addr, ip)) != -1) {
2709 NEW_TEMPLOAD (cfg, *sp, temp);
2713 } else if (array_rank) {
2714 MonoMethodSignature *esig;
2717 if (strcmp (cmethod->name, "Set") == 0) { /* array Set */
2718 esig = mono_get_element_address_signature (fsig->param_count - 1);
2720 temp = mono_emit_native_call (cfg, bblock, ves_array_element_address, esig, sp, ip, FALSE);
2721 NEW_TEMPLOAD (cfg, addr, temp);
2722 NEW_INDSTORE (cfg, ins, addr, sp [fsig->param_count], fsig->params [fsig->param_count - 1]);
2724 if (ins->opcode == CEE_STOBJ) {
2725 handle_stobj (cfg, bblock, addr, sp [fsig->param_count], ip, mono_class_from_mono_type (fsig->params [fsig->param_count-1]), FALSE, FALSE);
2727 MONO_ADD_INS (bblock, ins);
2730 } else if (strcmp (cmethod->name, "Get") == 0) { /* array Get */
2731 esig = mono_get_element_address_signature (fsig->param_count);
2733 temp = mono_emit_native_call (cfg, bblock, ves_array_element_address, esig, sp, ip, FALSE);
2734 NEW_TEMPLOAD (cfg, addr, temp);
2735 NEW_INDLOAD (cfg, ins, addr, fsig->ret);
2739 } else if (strcmp (cmethod->name, "Address") == 0) { /* array Address */
2741 esig = mono_get_element_address_signature (fsig->param_count);
2743 temp = mono_emit_native_call (cfg, bblock, ves_array_element_address, esig, sp, ip, FALSE);
2744 NEW_TEMPLOAD (cfg, *sp, temp);
2747 g_assert_not_reached ();
2751 if (0 && CODE_IS_STLOC (ip + 5) && (!MONO_TYPE_ISSTRUCT (fsig->ret)) && (!MONO_TYPE_IS_VOID (fsig->ret) || cmethod->string_ctor)) {
2752 /* no need to spill */
2753 ins = (MonoInst*)mono_emit_method_call (cfg, bblock, cmethod, fsig, sp, ip, virtual ? sp [0] : NULL);
2756 if ((temp = mono_emit_method_call_spilled (cfg, bblock, cmethod, sp, ip, virtual ? sp [0] : NULL)) != -1) {
2757 NEW_TEMPLOAD (cfg, *sp, temp);
2767 if (cfg->method != method) {
2768 /* return from inlined methode */
2773 //g_assert (returnvar != -1);
2774 NEW_TEMPSTORE (cfg, store, return_var->inst_c0, *sp);
2775 store->cil_code = sp [0]->cil_code;
2776 if (store->opcode == CEE_STOBJ) {
2777 g_assert_not_reached ();
2778 NEW_TEMPLOADA (cfg, store, return_var->inst_c0);
2779 handle_stobj (cfg, bblock, store, *sp, sp [0]->cil_code, return_var->klass, FALSE, FALSE);
2781 MONO_ADD_INS (bblock, store);
2785 g_assert (!return_var);
2788 MONO_INST_NEW (cfg, ins, CEE_NOP);
2789 ins->opcode = mono_type_to_stind (method->signature->ret);
2790 if (ins->opcode == CEE_STOBJ) {
2791 NEW_RETLOADA (cfg, ins);
2792 handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE);
2794 ins->opcode = OP_SETRET;
2796 ins->inst_i0 = *sp;;
2797 ins->inst_i1 = NULL;
2798 MONO_ADD_INS (bblock, ins);
2802 if (sp != stack_start)
2804 MONO_INST_NEW (cfg, ins, CEE_BR);
2805 ins->cil_code = ip++;
2806 ins->inst_target_bb = end_bblock;
2807 MONO_ADD_INS (bblock, ins);
2808 link_bblock (cfg, bblock, end_bblock);
2809 start_new_bblock = 1;
2812 MONO_INST_NEW (cfg, ins, CEE_BR);
2813 ins->cil_code = ip++;
2814 MONO_ADD_INS (bblock, ins);
2815 target = ip + 1 + (signed char)(*ip);
2817 GET_BBLOCK (cfg, bbhash, tblock, target);
2818 link_bblock (cfg, bblock, tblock);
2819 CHECK_BBLOCK (target, ip, tblock);
2820 ins->inst_target_bb = tblock;
2821 if (sp != stack_start) {
2822 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
2825 start_new_bblock = 1;
2831 MONO_INST_NEW (cfg, ins, *ip + BIG_BRANCH_OFFSET);
2832 ins->cil_code = ip++;
2833 target = ip + 1 + *(signed char*)ip;
2835 ADD_UNCOND (ins->opcode == CEE_BRTRUE);
2836 if (sp != stack_start) {
2837 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
2853 MONO_INST_NEW (cfg, ins, *ip + BIG_BRANCH_OFFSET);
2854 ins->cil_code = ip++;
2855 target = ip + 1 + *(signed char*)ip;
2858 if (sp != stack_start) {
2859 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
2865 MONO_INST_NEW (cfg, ins, CEE_BR);
2866 ins->cil_code = ip++;
2867 MONO_ADD_INS (bblock, ins);
2868 target = ip + 4 + (gint32)read32(ip);
2870 GET_BBLOCK (cfg, bbhash, tblock, target);
2871 link_bblock (cfg, bblock, tblock);
2872 CHECK_BBLOCK (target, ip, tblock);
2873 ins->inst_target_bb = tblock;
2874 if (sp != stack_start) {
2875 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
2878 start_new_bblock = 1;
2884 MONO_INST_NEW (cfg, ins, *ip);
2885 ins->cil_code = ip++;
2886 target = ip + 4 + (gint32)read32(ip);
2888 ADD_UNCOND(ins->opcode == CEE_BRTRUE);
2889 if (sp != stack_start) {
2890 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
2906 MONO_INST_NEW (cfg, ins, *ip);
2907 ins->cil_code = ip++;
2908 target = ip + 4 + (gint32)read32(ip);
2911 if (sp != stack_start) {
2912 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
2919 n = read32 (ip + 1);
2920 MONO_INST_NEW (cfg, ins, *ip);
2922 ins->inst_left = *sp;
2923 if (ins->inst_left->type != STACK_I4) goto unverified;
2926 target = ip + n * sizeof (guint32);
2927 MONO_ADD_INS (bblock, ins);
2928 GET_BBLOCK (cfg, bbhash, tblock, target);
2929 link_bblock (cfg, bblock, tblock);
2930 ins->klass = GUINT_TO_POINTER (n);
2931 ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * (n + 1));
2932 ins->inst_many_bb [n] = tblock;
2934 for (i = 0; i < n; ++i) {
2935 GET_BBLOCK (cfg, bbhash, tblock, target + (gint32)read32(ip));
2936 link_bblock (cfg, bblock, tblock);
2937 ins->inst_many_bb [i] = tblock;
2940 /* FIXME: handle stack args */
2955 MONO_INST_NEW (cfg, ins, *ip);
2960 ins->type = ldind_type [*ip - CEE_LDIND_I1];
2961 ins->flags |= ins_flag;
2973 MONO_INST_NEW (cfg, ins, *ip);
2974 ins->cil_code = ip++;
2976 handle_loaded_temps (cfg, bblock, stack_start, sp);
2977 MONO_ADD_INS (bblock, ins);
2978 ins->inst_i0 = sp [0];
2979 ins->inst_i1 = sp [1];
2980 ins->flags |= ins_flag;
3011 case CEE_CONV_OVF_I8:
3012 case CEE_CONV_OVF_U8:
3018 case CEE_CONV_OVF_I4:
3019 case CEE_CONV_OVF_I1:
3020 case CEE_CONV_OVF_I2:
3021 case CEE_CONV_OVF_I:
3022 case CEE_CONV_OVF_U:
3025 if (sp [-1]->type == STACK_R8) {
3026 ADD_UNOP (CEE_CONV_OVF_I8);
3034 case CEE_CONV_OVF_U1:
3035 case CEE_CONV_OVF_U2:
3036 case CEE_CONV_OVF_U4:
3039 if (sp [-1]->type == STACK_R8) {
3040 ADD_UNOP (CEE_CONV_OVF_U8);
3048 case CEE_CONV_OVF_I1_UN:
3049 case CEE_CONV_OVF_I2_UN:
3050 case CEE_CONV_OVF_I4_UN:
3051 case CEE_CONV_OVF_I8_UN:
3052 case CEE_CONV_OVF_U1_UN:
3053 case CEE_CONV_OVF_U2_UN:
3054 case CEE_CONV_OVF_U4_UN:
3055 case CEE_CONV_OVF_U8_UN:
3056 case CEE_CONV_OVF_I_UN:
3057 case CEE_CONV_OVF_U_UN:
3063 g_error ("opcode 0x%02x not handled", *ip);
3066 MonoInst *iargs [3];
3069 token = read32 (ip + 1);
3070 if (method->wrapper_type != MONO_WRAPPER_NONE)
3071 klass = mono_method_get_wrapper_data (method, token);
3073 klass = mono_class_get (image, token);
3075 mono_class_init (klass);
3076 n = mono_class_value_size (klass, NULL);
3077 ins = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
3078 NEW_TEMPLOADA (cfg, iargs [0], ins->inst_c0);
3080 NEW_ICONST (cfg, iargs [2], n);
3081 iargs [2]->cil_code = ip;
3083 mono_emit_jit_icall (cfg, bblock, helper_memcpy, iargs, ip);
3084 NEW_TEMPLOAD (cfg, *sp, ins->inst_c0);
3091 CHECK_STACK_OVF (1);
3092 n = read32 (ip + 1);
3094 if (mono_compile_aot) {
3095 cfg->ldstr_list = g_list_prepend (cfg->ldstr_list, (gpointer)n);
3098 if ((cfg->opt & MONO_OPT_SAHRED) || mono_compile_aot) {
3100 MonoInst *iargs [3];
3101 NEW_TEMPLOAD (cfg, iargs [0], mono_get_domainvar (cfg)->inst_c0);
3102 NEW_IMAGECONST (cfg, iargs [1], image);
3103 NEW_ICONST (cfg, iargs [2], mono_metadata_token_index (n));
3104 temp = mono_emit_jit_icall (cfg, bblock, mono_ldstr, iargs, ip);
3105 NEW_TEMPLOAD (cfg, *sp, temp);
3106 mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
3108 NEW_PCONST (cfg, ins, NULL);
3110 ins->type = STACK_OBJ;
3111 ins->inst_p0 = mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
3118 MonoInst *iargs [2];
3121 token = read32 (ip + 1);
3122 if (method->wrapper_type != MONO_WRAPPER_NONE) {
3123 cmethod = mono_method_get_wrapper_data (method, token);
3125 cmethod = mono_get_method (image, token, NULL);
3127 mono_class_init (cmethod->klass);
3129 n = cmethod->signature->param_count;
3132 /* move the args to allow room for 'this' in the first position */
3138 handle_loaded_temps (cfg, bblock, stack_start, sp);
3141 if (cmethod->klass->parent == mono_defaults.array_class) {
3142 NEW_METHODCONST (cfg, *sp, cmethod);
3143 temp = mono_emit_native_call (cfg, bblock, mono_array_new_va, cmethod->signature, sp, ip, FALSE);
3145 } else if (cmethod->string_ctor) {
3146 /* we simply pass a null pointer */
3147 NEW_PCONST (cfg, *sp, NULL);
3148 /* now call the string ctor */
3149 temp = mono_emit_method_call_spilled (cfg, bblock, cmethod, sp, ip, NULL);
3151 if (cmethod->klass->valuetype) {
3152 iargs [0] = mono_compile_create_var (cfg, &cmethod->klass->byval_arg, OP_LOCAL);
3153 temp = iargs [0]->inst_c0;
3154 NEW_TEMPLOADA (cfg, *sp, temp);
3156 NEW_DOMAINCONST (cfg, iargs [0]);
3157 NEW_CLASSCONST (cfg, iargs [1], cmethod->klass);
3159 temp = mono_emit_jit_icall (cfg, bblock, mono_object_new, iargs, ip);
3160 NEW_TEMPLOAD (cfg, *sp, temp);
3163 if ((cfg->opt & MONO_OPT_INLINE) && cmethod &&
3164 mono_method_check_inlining (cmethod) &&
3165 !mono_class_is_subclass_of (cmethod->klass, mono_defaults.exception_class, FALSE) &&
3166 !g_list_find (dont_inline, cmethod)) {
3168 MonoBasicBlock *ebblock;
3169 if ((costs = inline_method (cfg, cmethod, cmethod->signature, bblock, sp, ip, real_offset, dont_inline, &ebblock))) {
3171 GET_BBLOCK (cfg, bbhash, bblock, ip + 5);
3172 ebblock->next_bb = bblock;
3173 link_bblock (cfg, ebblock, bblock);
3175 /*if (sp != stack_start) {
3176 handle_stack_args (cfg, ebblock, stack_start, sp - stack_start);
3179 start_new_bblock = 1;*/
3181 inline_costs += costs;
3182 /*g_print ("inlined newobj for %s\n", cmethod->klass->name);*/
3185 /* now call the actual ctor */
3186 mono_emit_method_call_spilled (cfg, bblock, cmethod, sp, ip, NULL);
3190 NEW_TEMPLOAD (cfg, *sp, temp);
3199 MONO_INST_NEW (cfg, ins, *ip);
3201 klass = mono_class_get (image, read32 (ip + 1));
3202 mono_class_init (klass);
3203 ins->type = STACK_OBJ;
3204 ins->inst_left = *sp;
3205 ins->inst_newa_class = klass;
3211 MonoInst *add, *vtoffset;
3215 token = read32 (ip + 1);
3216 if (method->wrapper_type != MONO_WRAPPER_NONE)
3217 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
3219 klass = mono_class_get (image, token);
3220 mono_class_init (klass);
3223 MONO_INST_NEW (cfg, ins, OP_UNBOXCAST);
3224 ins->type = STACK_OBJ;
3225 ins->inst_left = *sp;
3227 ins->inst_newa_class = klass;
3230 MONO_INST_NEW (cfg, add, CEE_ADD);
3231 NEW_ICONST (cfg, vtoffset, sizeof (MonoObject));
3232 add->inst_left = ins;
3233 add->inst_right = vtoffset;
3234 add->type = STACK_MP;
3242 MONO_INST_NEW (cfg, ins, *ip);
3244 klass = mono_class_get (image, read32 (ip + 1));
3245 mono_class_init (klass);
3246 ins->type = STACK_OBJ;
3247 ins->inst_left = *sp;
3249 ins->inst_newa_class = klass;
3256 MONO_INST_NEW (cfg, ins, *ip);
3258 ins->inst_left = *sp;
3259 ins->cil_code = ip++;
3260 MONO_ADD_INS (bblock, ins);
3262 start_new_bblock = 1;
3267 MonoInst *offset_ins;
3268 MonoClassField *field;
3271 if (*ip == CEE_STFLD) {
3278 // FIXME: enable this test later.
3279 //if (sp [0]->type != STACK_OBJ && sp [0]->type != STACK_MP)
3281 token = read32 (ip + 1);
3282 field = mono_field_from_token (image, token, &klass);
3283 mono_class_init (klass);
3284 foffset = klass->valuetype? field->offset - sizeof (MonoObject): field->offset;
3285 /* FIXME: mark instructions for use in SSA */
3286 if (*ip == CEE_STFLD) {
3287 if (klass->marshalbyref && !MONO_CHECK_THIS (sp [0])) {
3288 /* fixme: we need to inline that call somehow */
3289 MonoMethod *stfld_wrapper = mono_marshal_get_stfld_wrapper (field->type);
3290 MonoInst *iargs [5];
3292 NEW_CLASSCONST (cfg, iargs [1], klass);
3293 NEW_FIELDCONST (cfg, iargs [2], field);
3294 NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : field->offset);
3296 mono_emit_method_call_spilled (cfg, bblock, stfld_wrapper, iargs, ip, NULL);
3299 NEW_ICONST (cfg, offset_ins, foffset);
3300 MONO_INST_NEW (cfg, ins, CEE_ADD);
3302 ins->inst_left = *sp;
3303 ins->inst_right = offset_ins;
3304 ins->type = STACK_MP;
3306 MONO_INST_NEW (cfg, store, mono_type_to_stind (field->type));
3307 store->cil_code = ip;
3308 store->inst_left = ins;
3309 store->inst_right = sp [1];
3310 handle_loaded_temps (cfg, bblock, stack_start, sp);
3311 store->flags |= ins_flag;
3313 if (store->opcode == CEE_STOBJ) {
3314 handle_stobj (cfg, bblock, ins, sp [1], ip,
3315 mono_class_from_mono_type (field->type), FALSE, FALSE);
3317 MONO_ADD_INS (bblock, store);
3320 if (klass->marshalbyref && !MONO_CHECK_THIS (sp [0])) {
3321 /* fixme: we need to inline that call somehow */
3322 MonoMethod *ldfld_wrapper = mono_marshal_get_ldfld_wrapper (field->type);
3323 MonoInst *iargs [4];
3326 NEW_CLASSCONST (cfg, iargs [1], klass);
3327 NEW_FIELDCONST (cfg, iargs [2], field);
3328 NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : field->offset);
3329 temp = mono_emit_method_call_spilled (cfg, bblock, ldfld_wrapper, iargs, ip, NULL);
3330 if (*ip == CEE_LDFLDA) {
3331 /* not sure howto handle this */
3332 NEW_TEMPLOADA (cfg, *sp, temp);
3334 NEW_TEMPLOAD (cfg, *sp, temp);
3338 NEW_ICONST (cfg, offset_ins, foffset);
3339 MONO_INST_NEW (cfg, ins, CEE_ADD);
3341 ins->inst_left = *sp;
3342 ins->inst_right = offset_ins;
3343 ins->type = STACK_MP;
3345 if (*ip == CEE_LDFLDA) {
3349 MONO_INST_NEW (cfg, load, mono_type_to_ldind (field->type));
3350 type_to_eval_stack_type (field->type, load);
3351 load->cil_code = ip;
3352 load->inst_left = ins;
3353 load->flags |= ins_flag;
3365 MonoClassField *field;
3368 token = read32 (ip + 1);
3370 field = mono_field_from_token (image, token, &klass);
3371 mono_class_init (klass);
3373 handle_loaded_temps (cfg, bblock, stack_start, sp);
3375 if (((cfg->opt & MONO_OPT_SAHRED) || mono_compile_aot)) {
3377 MonoInst *iargs [2];
3378 g_assert (field->parent);
3379 NEW_TEMPLOAD (cfg, iargs [0], mono_get_domainvar (cfg)->inst_c0);
3380 NEW_FIELDCONST (cfg, iargs [1], field);
3381 temp = mono_emit_jit_icall (cfg, bblock, mono_class_static_field_address, iargs, ip);
3382 NEW_TEMPLOAD (cfg, ins, temp);
3384 vtable = mono_class_vtable (cfg->domain, klass);
3385 NEW_PCONST (cfg, ins, (char*)vtable->data + field->offset);
3389 /* FIXME: mark instructions for use in SSA */
3390 if (*ip == CEE_LDSFLDA) {
3392 } else if (*ip == CEE_STSFLD) {
3396 MONO_INST_NEW (cfg, store, mono_type_to_stind (field->type));
3397 store->cil_code = ip;
3398 store->inst_left = ins;
3399 store->inst_right = sp [0];
3400 store->flags |= ins_flag;
3403 if (store->opcode == CEE_STOBJ) {
3404 handle_stobj (cfg, bblock, ins, sp [0], ip, mono_class_from_mono_type (field->type), FALSE, FALSE);
3406 MONO_ADD_INS (bblock, store);
3409 CHECK_STACK_OVF (1);
3410 MONO_INST_NEW (cfg, load, mono_type_to_ldind (field->type));
3411 type_to_eval_stack_type (field->type, load);
3412 load->cil_code = ip;
3413 load->inst_left = ins;
3415 load->flags |= ins_flag;
3417 /* fixme: dont see the problem why this does not work */
3418 //cfg->disable_aot = TRUE;
3426 token = read32 (ip + 1);
3427 if (method->wrapper_type != MONO_WRAPPER_NONE)
3428 klass = mono_method_get_wrapper_data (method, token);
3430 klass = mono_class_get (image, token);
3431 mono_class_init (klass);
3432 handle_stobj (cfg, bblock, sp [0], sp [1], ip, klass, FALSE, FALSE);
3437 MonoInst *iargs [2];
3438 MonoInst *load, *vtoffset, *add, *val, *vstore;
3443 token = read32 (ip + 1);
3444 if (method->wrapper_type != MONO_WRAPPER_NONE)
3445 klass = mono_method_get_wrapper_data (method, token);
3447 klass = mono_class_get (image, token);
3448 mono_class_init (klass);
3450 /* much like NEWOBJ */
3451 NEW_DOMAINCONST (cfg, iargs [0]);
3452 NEW_CLASSCONST (cfg, iargs [1], klass);
3454 temp = mono_emit_jit_icall (cfg, bblock, mono_object_new, iargs, ip);
3455 NEW_TEMPLOAD (cfg, load, temp);
3456 NEW_ICONST (cfg, vtoffset, sizeof (MonoObject));
3457 MONO_INST_NEW (cfg, add, CEE_ADD);
3458 add->inst_left = load;
3459 add->inst_right = vtoffset;
3462 MONO_INST_NEW (cfg, vstore, CEE_STIND_I);
3463 vstore->opcode = mono_type_to_stind (&klass->byval_arg);
3464 vstore->cil_code = ip;
3465 vstore->inst_left = add;
3466 vstore->inst_right = val;
3468 if (vstore->opcode == CEE_STOBJ) {
3469 handle_stobj (cfg, bblock, add, val, ip, klass, FALSE, FALSE);
3471 MONO_ADD_INS (bblock, vstore);
3473 NEW_TEMPLOAD (cfg, load, temp);
3481 MONO_INST_NEW (cfg, ins, *ip);
3485 token = read32 (ip + 1);
3487 /* allocate the domainvar - becaus this is used in decompose_foreach */
3488 if ((cfg->opt & MONO_OPT_SAHRED) || mono_compile_aot)
3489 mono_get_domainvar (cfg);
3491 if (method->wrapper_type != MONO_WRAPPER_NONE)
3492 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
3494 klass = mono_class_get (image, token);
3496 mono_class_init (klass);
3497 ins->inst_newa_class = klass;
3498 ins->inst_newa_len = *sp;
3499 ins->type = STACK_OBJ;
3506 MONO_INST_NEW (cfg, ins, *ip);
3507 ins->cil_code = ip++;
3509 ins->inst_left = *sp;
3510 ins->type = STACK_PTR;
3516 klass = mono_class_get (image, read32 (ip + 1));
3517 mono_class_init (klass);
3518 NEW_LDELEMA (cfg, ins, sp, klass);
3533 case CEE_LDELEM_REF: {
3537 * ldind.x (ldelema (array, index))
3538 * ldelema does the bounds check
3542 klass = array_access_to_klass (*ip);
3543 NEW_LDELEMA (cfg, load, sp, klass);
3544 load->cil_code = ip;
3545 MONO_INST_NEW (cfg, ins, ldelem_to_ldind [*ip - CEE_LDELEM_I1]);
3547 ins->inst_left = load;
3549 ins->type = ldind_type [ins->opcode - CEE_LDIND_I1];
3559 case CEE_STELEM_R8: {
3563 * stind.x (ldelema (array, index), val)
3564 * ldelema does the bounds check
3568 klass = array_access_to_klass (*ip);
3569 NEW_LDELEMA (cfg, load, sp, klass);
3570 load->cil_code = ip;
3571 MONO_INST_NEW (cfg, ins, stelem_to_stind [*ip - CEE_STELEM_I]);
3573 ins->inst_left = load;
3574 ins->inst_right = sp [2];
3576 handle_loaded_temps (cfg, bblock, stack_start, sp);
3577 MONO_ADD_INS (bblock, ins);
3578 /* FIXME: add the implicit STELEM_REF castclass */
3580 cfg->disable_ssa = TRUE;
3583 case CEE_STELEM_REF: {
3584 MonoInst *iargs [3];
3589 handle_loaded_temps (cfg, bblock, stack_start, sp);
3595 mono_emit_jit_icall (cfg, bblock, helper_stelem_ref, iargs, ip);
3599 NEW_GROUP (cfg, group, sp [0], sp [1]);
3600 MONO_INST_NEW (cfg, ins, CEE_STELEM_REF);
3602 ins->inst_left = group;
3603 ins->inst_right = sp [2];
3604 MONO_ADD_INS (bblock, ins);
3609 cfg->disable_ssa = TRUE;
3612 case CEE_CKFINITE: {
3613 MonoInst *store, *temp;
3616 /* this instr. can throw exceptions as side effect,
3617 * so we cant eliminate dead code which contains CKFINITE opdodes.
3618 * Spilling to memory makes sure that we always perform
3622 MONO_INST_NEW (cfg, ins, CEE_CKFINITE);
3624 ins->inst_left = sp [-1];
3625 temp = mono_compile_create_var (cfg, &mono_defaults.double_class->byval_arg, OP_LOCAL);
3627 NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
3628 store->cil_code = ip;
3629 MONO_ADD_INS (bblock, store);
3631 NEW_TEMPLOAD (cfg, sp [-1], temp->inst_c0);
3638 g_error ("opcode 0x%02x not handled", *ip);
3642 MonoClass *handle_class;
3644 CHECK_STACK_OVF (1);
3646 n = read32 (ip + 1);
3648 handle = mono_ldtoken (image, n, &handle_class);
3649 mono_class_init (handle_class);
3651 if (((cfg->opt & MONO_OPT_SAHRED) || mono_compile_aot)) {
3653 MonoInst *res, *store, *addr, *vtvar, *iargs [2];
3655 vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL);
3657 NEW_IMAGECONST (cfg, iargs [0], image);
3658 NEW_ICONST (cfg, iargs [1], n);
3659 temp = mono_emit_jit_icall (cfg, bblock, mono_ldtoken_wrapper, iargs, ip);
3660 NEW_TEMPLOAD (cfg, res, temp);
3661 NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
3662 NEW_INDSTORE (cfg, store, addr, res, &mono_defaults.int_class->byval_arg);
3663 MONO_ADD_INS (bblock, store);
3664 NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
3666 if ((ip [5] == CEE_CALL) && (cmethod = mono_get_method (image, read32 (ip + 6), NULL)) &&
3667 (cmethod->klass == mono_defaults.monotype_class->parent) &&
3668 (strcmp (cmethod->name, "GetTypeFromHandle") == 0)) {
3669 MonoClass *tclass = mono_class_from_mono_type (handle);
3670 mono_class_init (tclass);
3671 NEW_PCONST (cfg, ins, mono_type_get_object (cfg->domain, handle));
3672 ins->type = STACK_OBJ;
3673 ins->klass = cmethod->klass;
3676 NEW_PCONST (cfg, ins, handle);
3677 ins->type = STACK_VTYPE;
3678 ins->klass = handle_class;
3694 case CEE_ADD_OVF_UN:
3696 case CEE_MUL_OVF_UN:
3698 case CEE_SUB_OVF_UN:
3703 case CEE_ENDFINALLY:
3704 /* FIXME: check stack state */
3705 MONO_INST_NEW (cfg, ins, *ip);
3706 MONO_ADD_INS (bblock, ins);
3707 ins->cil_code = ip++;
3708 start_new_bblock = 1;
3713 if (*ip == CEE_LEAVE) {
3714 target = ip + 5 + (gint32)read32(ip + 1);
3716 target = ip + 2 + (signed char)(ip [1]);
3719 /* empty the stack */
3720 while (sp != stack_start) {
3721 MONO_INST_NEW (cfg, ins, CEE_POP);
3725 MONO_ADD_INS (bblock, ins);
3728 /* fixme: call fault handler ? */
3730 if ((handlers = mono_find_final_block (cfg, ip, target, MONO_EXCEPTION_CLAUSE_FINALLY))) {
3732 for (tmp = handlers; tmp; tmp = tmp->next) {
3734 link_bblock (cfg, bblock, tblock);
3735 MONO_INST_NEW (cfg, ins, OP_HANDLER);
3737 ins->inst_target_bb = tblock;
3738 MONO_ADD_INS (bblock, ins);
3740 g_list_free (handlers);
3743 MONO_INST_NEW (cfg, ins, CEE_BR);
3745 MONO_ADD_INS (bblock, ins);
3746 GET_BBLOCK (cfg, bbhash, tblock, target);
3747 link_bblock (cfg, bblock, tblock);
3748 CHECK_BBLOCK (target, ip, tblock);
3749 ins->inst_target_bb = tblock;
3750 start_new_bblock = 1;
3752 if (*ip == CEE_LEAVE)
3761 MONO_INST_NEW (cfg, ins, *ip);
3763 handle_loaded_temps (cfg, bblock, stack_start, sp);
3764 MONO_ADD_INS (bblock, ins);
3765 ins->cil_code = ip++;
3766 ins->inst_i0 = sp [0];
3767 ins->inst_i1 = sp [1];
3775 /* trampoline mono specific opcodes */
3776 case MONO_CUSTOM_PREFIX: {
3778 g_assert (method->wrapper_type != MONO_WRAPPER_NONE);
3782 case CEE_MONO_FUNC1: {
3784 gpointer func = NULL;
3789 case MONO_MARSHAL_CONV_STR_LPWSTR:
3790 func = mono_string_to_utf16;
3792 case MONO_MARSHAL_CONV_LPWSTR_STR:
3793 func = mono_string_from_utf16;
3795 case MONO_MARSHAL_CONV_LPSTR_STR:
3796 func = mono_string_new_wrapper;
3798 case MONO_MARSHAL_CONV_STR_LPTSTR:
3799 case MONO_MARSHAL_CONV_STR_LPSTR:
3800 func = mono_string_to_utf8;
3802 case MONO_MARSHAL_CONV_STR_BSTR:
3803 func = mono_string_to_bstr;
3805 case MONO_MARSHAL_CONV_STR_TBSTR:
3806 case MONO_MARSHAL_CONV_STR_ANSIBSTR:
3807 func = mono_string_to_ansibstr;
3809 case MONO_MARSHAL_CONV_SB_LPSTR:
3810 func = mono_string_builder_to_utf8;
3812 case MONO_MARSHAL_CONV_ARRAY_SAVEARRAY:
3813 func = mono_array_to_savearray;
3815 case MONO_MARSHAL_CONV_ARRAY_LPARRAY:
3816 func = mono_array_to_lparray;
3818 case MONO_MARSHAL_CONV_DEL_FTN:
3819 func = mono_delegate_to_ftnptr;
3821 case MONO_MARSHAL_CONV_STRARRAY_STRLPARRAY:
3822 func = mono_marshal_string_array;
3825 g_warning ("unknown conversion %d\n", ip [2]);
3826 g_assert_not_reached ();
3829 temp = mono_emit_jit_icall (cfg, bblock, func, sp, ip);
3830 NEW_TEMPLOAD (cfg, *sp, temp);
3834 inline_costs += 10 * num_calls++;
3837 case CEE_MONO_PROC2: {
3838 gpointer func = NULL;
3843 case MONO_MARSHAL_CONV_LPSTR_SB:
3844 func = mono_string_utf8_to_builder;
3846 case MONO_MARSHAL_FREE_ARRAY:
3847 func = mono_marshal_free_array;
3850 g_assert_not_reached ();
3853 mono_emit_jit_icall (cfg, bblock, func, sp, ip);
3855 inline_costs += 10 * num_calls++;
3858 case CEE_MONO_PROC3: {
3859 gpointer func = NULL;
3864 case MONO_MARSHAL_CONV_STR_BYVALSTR:
3865 func = mono_string_to_byvalstr;
3867 case MONO_MARSHAL_CONV_STR_BYVALWSTR:
3868 func = mono_string_to_byvalwstr;
3871 g_assert_not_reached ();
3874 mono_emit_jit_icall (cfg, bblock, func, sp, ip);
3876 inline_costs += 10 * num_calls++;
3882 mono_emit_jit_icall (cfg, bblock, g_free, sp, ip);
3884 inline_costs += 10 * num_calls++;
3886 case CEE_MONO_LDPTR:
3887 CHECK_STACK_OVF (1);
3888 token = read32 (ip + 2);
3889 NEW_PCONST (cfg, ins, mono_method_get_wrapper_data (method, token));
3893 inline_costs += 10 * num_calls++;
3895 case CEE_MONO_VTADDR:
3898 MONO_INST_NEW (cfg, ins, OP_VTADDR);
3900 ins->type = STACK_MP;
3901 ins->inst_left = *sp;
3905 case CEE_MONO_NEWOBJ: {
3906 MonoInst *iargs [2];
3908 CHECK_STACK_OVF (1);
3909 token = read32 (ip + 2);
3910 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
3911 mono_class_init (klass);
3912 NEW_DOMAINCONST (cfg, iargs [0]);
3913 NEW_CLASSCONST (cfg, iargs [1], klass);
3914 temp = mono_emit_jit_icall (cfg, bblock, mono_object_new, iargs, ip);
3915 NEW_TEMPLOAD (cfg, *sp, temp);
3918 inline_costs += 10 * num_calls++;
3921 case CEE_MONO_OBJADDR:
3924 MONO_INST_NEW (cfg, ins, OP_OBJADDR);
3926 ins->type = STACK_MP;
3927 ins->inst_left = *sp;
3931 case CEE_MONO_LDNATIVEOBJ:
3933 token = read32 (ip + 2);
3934 klass = mono_method_get_wrapper_data (method, token);
3935 g_assert (klass->valuetype);
3936 mono_class_init (klass);
3937 NEW_INDLOAD (cfg, ins, sp [-1], &klass->byval_arg);
3941 case CEE_MONO_RETOBJ:
3942 g_assert (cfg->ret);
3943 g_assert (method->signature->pinvoke);
3947 token = read32 (ip + 2);
3948 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
3950 NEW_RETLOADA (cfg, ins);
3951 handle_stobj (cfg, bblock, ins, *sp, ip, klass, FALSE, TRUE);
3953 if (sp != stack_start)
3956 MONO_INST_NEW (cfg, ins, CEE_BR);
3958 ins->inst_target_bb = end_bblock;
3959 MONO_ADD_INS (bblock, ins);
3960 link_bblock (cfg, bblock, end_bblock);
3961 start_new_bblock = 1;
3965 g_error ("opcode 0x%02x 0x%02x not handled", MONO_CUSTOM_PREFIX, ip [1]);
3973 g_error ("opcode 0xfe 0x%02x not handled", ip [1]);
3982 MONO_INST_NEW (cfg, cmp, 256 + ip [1]);
3983 MONO_INST_NEW (cfg, ins, cmp->opcode);
3985 cmp->inst_i0 = sp [0];
3986 cmp->inst_i1 = sp [1];
3990 cmp->opcode = OP_COMPARE;
3992 ins->type = STACK_I4;
4002 CHECK_STACK_OVF (1);
4003 n = read32 (ip + 2);
4004 if (method->wrapper_type != MONO_WRAPPER_NONE)
4005 cmethod = mono_method_get_wrapper_data (method, n);
4007 cmethod = mono_get_method (image, n, NULL);
4010 * We can't do this in mono_ldftn, since it is used in
4011 * the synchronized wrapper, leading to an infinite loop.
4013 if (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
4014 cmethod = mono_marshal_get_synchronized_wrapper (cmethod);
4017 mono_class_init (cmethod->klass);
4018 handle_loaded_temps (cfg, bblock, stack_start, sp);
4020 NEW_METHODCONST (cfg, argconst, cmethod);
4021 temp = mono_emit_jit_icall (cfg, bblock, mono_ldftn, &argconst, ip);
4022 NEW_TEMPLOAD (cfg, *sp, temp);
4026 inline_costs += 10 * num_calls++;
4029 case CEE_LDVIRTFTN: {
4034 n = read32 (ip + 2);
4035 if (method->wrapper_type != MONO_WRAPPER_NONE)
4036 cmethod = mono_method_get_wrapper_data (method, n);
4038 cmethod = mono_get_method (image, n, NULL);
4040 mono_class_init (cmethod->klass);
4041 handle_loaded_temps (cfg, bblock, stack_start, sp);
4045 NEW_METHODCONST (cfg, args [1], cmethod);
4046 temp = mono_emit_jit_icall (cfg, bblock, mono_ldvirtfn, args, ip);
4047 NEW_TEMPLOAD (cfg, *sp, temp);
4051 inline_costs += 10 * num_calls++;
4055 CHECK_STACK_OVF (1);
4056 NEW_ARGLOAD (cfg, ins, read16 (ip + 2));
4062 CHECK_STACK_OVF (1);
4063 NEW_ARGLOADA (cfg, ins, read16 (ip + 2));
4071 handle_loaded_temps (cfg, bblock, stack_start, sp);
4072 n = read16 (ip + 2);
4073 NEW_ARGSTORE (cfg, ins, n, *sp);
4075 if (ins->opcode == CEE_STOBJ) {
4076 NEW_ARGLOADA (cfg, ins, n);
4077 handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE);
4079 MONO_ADD_INS (bblock, ins);
4083 CHECK_STACK_OVF (1);
4084 NEW_LOCLOAD (cfg, ins, read16 (ip + 2));
4090 CHECK_STACK_OVF (1);
4091 NEW_LOCLOADA (cfg, ins, read16 (ip + 2));
4099 n = read16 (ip + 2);
4100 handle_loaded_temps (cfg, bblock, stack_start, sp);
4101 NEW_LOCSTORE (cfg, ins, n, *sp);
4103 if (ins->opcode == CEE_STOBJ) {
4104 NEW_LOCLOADA (cfg, ins, n);
4105 handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE);
4107 MONO_ADD_INS (bblock, ins);
4114 if (sp != stack_start)
4116 MONO_INST_NEW (cfg, ins, 256 + ip [1]);
4117 ins->inst_left = *sp;
4120 if (header->init_locals)
4121 ins->flags |= MONO_INST_INIT;
4125 /* FIXME: set init flag if locals init is set in this method */
4127 case CEE_ENDFILTER: {
4128 MonoExceptionClause *clause, *nearest;
4129 int cc, nearest_num;
4133 if ((sp != stack_start) || (sp [0]->type != STACK_I4))
4135 MONO_INST_NEW (cfg, ins, OP_ENDFILTER);
4136 ins->inst_left = *sp;
4138 MONO_ADD_INS (bblock, ins);
4139 start_new_bblock = 1;
4143 for (cc = 0; cc < header->num_clauses; ++cc) {
4144 clause = &header->clauses [cc];
4145 if ((clause->flags & MONO_EXCEPTION_CLAUSE_FILTER) &&
4146 (!nearest || (clause->token_or_filter > nearest->token_or_filter))) {
4152 filter_lengths [nearest_num] = (ip - header->code) - nearest->token_or_filter;
4156 case CEE_UNALIGNED_:
4157 ins_flag |= MONO_INST_UNALIGNED;
4161 ins_flag |= MONO_INST_VOLATILE;
4165 ins_flag |= MONO_INST_TAILCALL;
4171 token = read32 (ip + 2);
4172 if (method->wrapper_type != MONO_WRAPPER_NONE)
4173 klass = mono_method_get_wrapper_data (method, token);
4175 klass = mono_class_get (image, token);
4176 handle_initobj (cfg, bblock, *sp, NULL, klass, stack_start, sp);
4182 MonoInst *iargs [3];
4188 handle_loaded_temps (cfg, bblock, stack_start, sp);
4189 if (ip [1] == CEE_CPBLK) {
4190 mono_emit_jit_icall (cfg, bblock, helper_memcpy, iargs, ip);
4192 mono_emit_jit_icall (cfg, bblock, helper_memset, iargs, ip);
4200 /* FIXME: check we are in a catch handler */
4201 NEW_TEMPLOAD (cfg, load, cfg->exvar->inst_c0);
4202 load->cil_code = ip;
4203 MONO_INST_NEW (cfg, ins, CEE_THROW);
4204 ins->inst_left = load;
4206 MONO_ADD_INS (bblock, ins);
4208 start_new_bblock = 1;
4213 CHECK_STACK_OVF (1);
4214 token = read32 (ip + 2);
4215 if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC) {
4216 MonoType *type = mono_type_create_from_typespec (image, token);
4217 token = mono_type_size (type, &align);
4218 mono_metadata_free_type (type);
4220 MonoClass *szclass = mono_class_get (image, token);
4221 mono_class_init (szclass);
4222 token = mono_class_value_size (szclass, &align);
4224 NEW_ICONST (cfg, ins, token);
4229 case CEE_REFANYTYPE:
4230 g_error ("opcode 0xfe 0x%02x not handled", ip [1]);
4233 g_error ("opcode 0xfe 0x%02x not handled", ip [1]);
4238 g_error ("opcode 0x%02x not handled", *ip);
4241 if (start_new_bblock != 1)
4244 bblock->cil_length = ip - bblock->cil_code;
4245 bblock->next_bb = end_bblock;
4246 link_bblock (cfg, bblock, end_bblock);
4248 if (cfg->method == method && cfg->domainvar) {
4252 MONO_INST_NEW_CALL (cfg, call, CEE_CALL);
4253 call->signature = helper_sig_domain_get;
4254 call->inst.type = STACK_PTR;
4255 call->fptr = mono_domain_get;
4256 NEW_TEMPSTORE (cfg, store, cfg->domainvar->inst_c0, (MonoInst*)call);
4258 MONO_ADD_INS (init_localsbb, store);
4261 if (header->init_locals) {
4263 for (i = 0; i < header->num_locals; ++i) {
4264 int t = header->locals [i]->type;
4265 if (t == MONO_TYPE_VALUETYPE && header->locals [i]->data.klass->enumtype)
4266 t = header->locals [i]->data.klass->enum_basetype->type;
4267 /* FIXME: use initobj for valuetypes, handle pointers, long, float. */
4268 if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
4269 NEW_ICONST (cfg, ins, 0);
4270 NEW_LOCSTORE (cfg, store, i, ins);
4271 MONO_ADD_INS (init_localsbb, store);
4272 } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
4273 MONO_INST_NEW (cfg, ins, OP_I8CONST);
4274 ins->type = STACK_I8;
4276 NEW_LOCSTORE (cfg, store, i, ins);
4277 MONO_ADD_INS (init_localsbb, store);
4278 } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
4279 MONO_INST_NEW (cfg, ins, OP_R8CONST);
4280 ins->type = STACK_R8;
4281 ins->inst_p0 = (void*)&r8_0;
4282 NEW_LOCSTORE (cfg, store, i, ins);
4283 MONO_ADD_INS (init_localsbb, store);
4284 } else if (t == MONO_TYPE_VALUETYPE) {
4285 NEW_LOCLOADA (cfg, ins, i);
4286 handle_initobj (cfg, init_localsbb, ins, NULL, mono_class_from_mono_type (header->locals [i]), NULL, NULL);
4289 NEW_PCONST (cfg, ins, NULL);
4290 NEW_LOCSTORE (cfg, store, i, ins);
4291 MONO_ADD_INS (init_localsbb, store);
4297 /* resolve backward branches in the middle of an existing basic block */
4298 for (tmp = bb_recheck; tmp; tmp = tmp->next) {
4300 /*g_print ("need recheck in %s at IL_%04x\n", method->name, bblock->cil_code - header->code);*/
4301 tblock = find_previous (bbhash, start_bblock, bblock->cil_code);
4302 if (tblock != start_bblock) {
4304 split_bblock (cfg, tblock, bblock);
4305 l = bblock->cil_code - header->code;
4306 bblock->cil_length = tblock->cil_length - l;
4307 tblock->cil_length = l;
4309 g_print ("recheck failed.\n");
4313 /* we compute regions here, because the length of filter clauses is not known in advance.
4314 * It is computed in the CEE_ENDFILTER case in the above switch statement*/
4315 if (cfg->method == method) {
4317 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4318 bb->region = mono_find_block_region (cfg, bb->real_offset, filter_lengths);
4319 if (cfg->verbose_level > 2)
4320 g_print ("REGION BB%d IL_%04x ID_%08X\n", bb->block_num, bb->real_offset, bb->region);
4323 g_hash_table_destroy (bbhash);
4326 dont_inline = g_list_remove (dont_inline, method);
4327 return inline_costs;
4330 if (cfg->method != method)
4331 g_hash_table_destroy (bbhash);
4332 dont_inline = g_list_remove (dont_inline, method);
4336 if (cfg->method != method)
4337 g_hash_table_destroy (bbhash);
4338 g_error ("Invalid IL code at IL%04x in %s: %s\n", ip - header->code,
4339 mono_method_full_name (method, TRUE), mono_disasm_code_one (NULL, method, ip, NULL));
4340 dont_inline = g_list_remove (dont_inline, method);
4345 mono_print_tree (MonoInst *tree) {
4351 arity = mono_burg_arity [tree->opcode];
4353 printf (" %s%s", arity?"(":"", mono_inst_name (tree->opcode));
4355 switch (tree->opcode) {
4357 printf ("[%d]", tree->inst_c0);
4360 printf ("[%lld]", tree->inst_l);
4363 printf ("[%f]", *(double*)tree->inst_p0);
4366 printf ("[%f]", *(float*)tree->inst_p0);
4370 printf ("[%d]", tree->inst_c0);
4373 printf ("[0x%x(%s)]", tree->inst_offset, mono_arch_regname (tree->inst_basereg));
4376 printf ("[%s]", mono_arch_regname (tree->dreg));
4379 printf ("[%s]", tree->inst_newa_class->name);
4380 mono_print_tree (tree->inst_newa_len);
4391 case OP_VOIDCALLVIRT: {
4392 MonoCallInst *call = (MonoCallInst*)tree;
4394 printf ("[%s]", call->method->name);
4399 printf ("[%d (", tree->inst_c0);
4400 for (i = 0; i < tree->inst_phi_args [0]; i++) {
4403 printf ("%d", tree->inst_phi_args [i + 1]);
4415 printf ("[B%d]", tree->inst_target_bb->block_num);
4425 case OP_VOIDCALL_REG:
4426 mono_print_tree (tree->inst_left);
4438 printf ("[B%dB%d]", tree->inst_true_bb->block_num, tree->inst_false_bb->block_num);
4439 mono_print_tree (tree->inst_left);
4443 mono_print_tree (tree->inst_left);
4445 mono_print_tree (tree->inst_right);
4455 create_helper_signature (void)
4457 /* FIXME: set call conv */
4458 /* MonoArray * mono_array_new (MonoDomain *domain, MonoClass *klass, gint32 len) */
4459 helper_sig_newarr = mono_metadata_signature_alloc (mono_defaults.corlib, 3);
4460 helper_sig_newarr->params [0] = helper_sig_newarr->params [1] = &mono_defaults.int_class->byval_arg;
4461 helper_sig_newarr->ret = &mono_defaults.object_class->byval_arg;
4462 helper_sig_newarr->params [2] = &mono_defaults.int32_class->byval_arg;
4463 helper_sig_newarr->pinvoke = 1;
4465 /* MonoObject * mono_object_new (MonoDomain *domain, MonoClass *klass) */
4466 helper_sig_object_new = mono_metadata_signature_alloc (mono_defaults.corlib, 2);
4467 helper_sig_object_new->params [0] = helper_sig_object_new->params [1] = &mono_defaults.int_class->byval_arg;
4468 helper_sig_object_new->ret = &mono_defaults.object_class->byval_arg;
4469 helper_sig_object_new->pinvoke = 1;
4471 /* void* mono_method_compile (MonoMethod*) */
4472 helper_sig_compile = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
4473 helper_sig_compile->params [0] = helper_sig_compile->ret = &mono_defaults.int_class->byval_arg;
4474 helper_sig_compile->pinvoke = 1;
4476 /* void* mono_ldvirtfn (MonoObject *, MonoMethod*) */
4477 helper_sig_compile_virt = mono_metadata_signature_alloc (mono_defaults.corlib, 2);
4478 helper_sig_compile_virt->params [0] = &mono_defaults.object_class->byval_arg;
4479 helper_sig_compile_virt->params [1] = helper_sig_compile_virt->ret = &mono_defaults.int_class->byval_arg;
4480 helper_sig_compile_virt->pinvoke = 1;
4482 /* MonoString* mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 str_index) */
4483 helper_sig_ldstr = mono_metadata_signature_alloc (mono_defaults.corlib, 3);
4484 helper_sig_ldstr->params [0] = helper_sig_ldstr->params [1] = &mono_defaults.int_class->byval_arg;
4485 helper_sig_ldstr->params [2] = &mono_defaults.int32_class->byval_arg;
4486 helper_sig_ldstr->ret = &mono_defaults.object_class->byval_arg;
4487 helper_sig_ldstr->pinvoke = 1;
4489 /* MonoDomain *mono_domain_get (void) */
4490 helper_sig_domain_get = mono_metadata_signature_alloc (mono_defaults.corlib, 0);
4491 helper_sig_domain_get->ret = &mono_defaults.int_class->byval_arg;
4492 helper_sig_domain_get->pinvoke = 1;
4494 /* void* stelem_ref (MonoArray *, int index, MonoObject *) */
4495 helper_sig_stelem_ref = mono_metadata_signature_alloc (mono_defaults.corlib, 3);
4496 helper_sig_stelem_ref->params [0] = &mono_defaults.array_class->byval_arg;
4497 helper_sig_stelem_ref->params [1] = &mono_defaults.int32_class->byval_arg;
4498 helper_sig_stelem_ref->params [2] = &mono_defaults.object_class->byval_arg;
4499 helper_sig_stelem_ref->ret = &mono_defaults.void_class->byval_arg;
4500 helper_sig_stelem_ref->pinvoke = 1;
4502 /* long amethod (long, long) */
4503 helper_sig_long_long_long = mono_metadata_signature_alloc (mono_defaults.corlib, 2);
4504 helper_sig_long_long_long->params [0] = helper_sig_long_long_long->params [1] =
4505 &mono_defaults.int64_class->byval_arg;
4506 helper_sig_long_long_long->ret = &mono_defaults.int64_class->byval_arg;
4507 helper_sig_long_long_long->pinvoke = 1;
4509 /* object amethod (intptr) */
4510 helper_sig_obj_ptr = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
4511 helper_sig_obj_ptr->params [0] = &mono_defaults.int_class->byval_arg;
4512 helper_sig_obj_ptr->ret = &mono_defaults.object_class->byval_arg;
4513 helper_sig_obj_ptr->pinvoke = 1;
4515 /* void amethod (intptr) */
4516 helper_sig_void_ptr = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
4517 helper_sig_void_ptr->params [0] = &mono_defaults.int_class->byval_arg;
4518 helper_sig_void_ptr->ret = &mono_defaults.void_class->byval_arg;
4519 helper_sig_void_ptr->pinvoke = 1;
4521 /* void amethod (MonoObject *obj) */
4522 helper_sig_void_obj = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
4523 helper_sig_void_obj->params [0] = &mono_defaults.object_class->byval_arg;
4524 helper_sig_void_obj->ret = &mono_defaults.void_class->byval_arg;
4525 helper_sig_void_obj->pinvoke = 1;
4527 /* intptr amethod (void) */
4528 helper_sig_ptr_void = mono_metadata_signature_alloc (mono_defaults.corlib, 0);
4529 helper_sig_ptr_void->ret = &mono_defaults.int_class->byval_arg;
4530 helper_sig_ptr_void->pinvoke = 1;
4532 /* void amethod (intptr, intptr) */
4533 helper_sig_void_ptr_ptr = mono_metadata_signature_alloc (mono_defaults.corlib, 2);
4534 helper_sig_void_ptr_ptr->params [0] = &mono_defaults.int_class->byval_arg;
4535 helper_sig_void_ptr_ptr->params [1] = &mono_defaults.int_class->byval_arg;
4536 helper_sig_void_ptr_ptr->ret = &mono_defaults.void_class->byval_arg;
4537 helper_sig_void_ptr_ptr->pinvoke = 1;
4539 /* void amethod (intptr, intptr, intptr) */
4540 helper_sig_void_ptr_ptr_ptr = mono_metadata_signature_alloc (mono_defaults.corlib, 3);
4541 helper_sig_void_ptr_ptr_ptr->params [0] = &mono_defaults.int_class->byval_arg;
4542 helper_sig_void_ptr_ptr_ptr->params [1] = &mono_defaults.int_class->byval_arg;
4543 helper_sig_void_ptr_ptr_ptr->params [2] = &mono_defaults.int_class->byval_arg;
4544 helper_sig_void_ptr_ptr_ptr->ret = &mono_defaults.void_class->byval_arg;
4545 helper_sig_void_ptr_ptr_ptr->pinvoke = 1;
4547 /* intptr amethod (intptr, intptr) */
4548 helper_sig_ptr_ptr_ptr = mono_metadata_signature_alloc (mono_defaults.corlib, 2);
4549 helper_sig_ptr_ptr_ptr->params [0] = &mono_defaults.int_class->byval_arg;
4550 helper_sig_ptr_ptr_ptr->params [1] = &mono_defaults.int_class->byval_arg;
4551 helper_sig_ptr_ptr_ptr->ret = &mono_defaults.int_class->byval_arg;
4552 helper_sig_ptr_ptr_ptr->pinvoke = 1;
4554 /* IntPtr amethod (object) */
4555 helper_sig_ptr_obj = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
4556 helper_sig_ptr_obj->params [0] = &mono_defaults.object_class->byval_arg;
4557 helper_sig_ptr_obj->ret = &mono_defaults.int_class->byval_arg;
4558 helper_sig_ptr_obj->pinvoke = 1;
4560 /* long amethod (long, guint32) */
4561 helper_sig_long_long_int = mono_metadata_signature_alloc (mono_defaults.corlib, 2);
4562 helper_sig_long_long_int->params [0] = &mono_defaults.int64_class->byval_arg;
4563 helper_sig_long_long_int->params [1] = &mono_defaults.int32_class->byval_arg;
4564 helper_sig_long_long_int->ret = &mono_defaults.int64_class->byval_arg;
4565 helper_sig_long_long_int->pinvoke = 1;
4567 /* ulong amethod (double) */
4568 helper_sig_ulong_double = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
4569 helper_sig_ulong_double->params [0] = &mono_defaults.double_class->byval_arg;
4570 helper_sig_ulong_double->ret = &mono_defaults.uint64_class->byval_arg;
4571 helper_sig_ulong_double->pinvoke = 1;
4573 /* long amethod (double) */
4574 helper_sig_long_double = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
4575 helper_sig_long_double->params [0] = &mono_defaults.double_class->byval_arg;
4576 helper_sig_long_double->ret = &mono_defaults.int64_class->byval_arg;
4577 helper_sig_long_double->pinvoke = 1;
4579 /* uint amethod (double) */
4580 helper_sig_uint_double = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
4581 helper_sig_uint_double->params [0] = &mono_defaults.double_class->byval_arg;
4582 helper_sig_uint_double->ret = &mono_defaults.uint32_class->byval_arg;
4583 helper_sig_uint_double->pinvoke = 1;
4585 /* int amethod (double) */
4586 helper_sig_int_double = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
4587 helper_sig_int_double->params [0] = &mono_defaults.double_class->byval_arg;
4588 helper_sig_int_double->ret = &mono_defaults.int32_class->byval_arg;
4589 helper_sig_int_double->pinvoke = 1;
4591 /* void initobj (intptr, int size) */
4592 helper_sig_initobj = mono_metadata_signature_alloc (mono_defaults.corlib, 2);
4593 helper_sig_initobj->params [0] = &mono_defaults.int_class->byval_arg;
4594 helper_sig_initobj->params [1] = &mono_defaults.int32_class->byval_arg;
4595 helper_sig_initobj->ret = &mono_defaults.void_class->byval_arg;
4596 helper_sig_initobj->pinvoke = 1;
4598 /* void memcpy (intptr, intptr, int size) */
4599 helper_sig_memcpy = mono_metadata_signature_alloc (mono_defaults.corlib, 3);
4600 helper_sig_memcpy->params [0] = &mono_defaults.int_class->byval_arg;
4601 helper_sig_memcpy->params [1] = &mono_defaults.int_class->byval_arg;
4602 helper_sig_memcpy->params [2] = &mono_defaults.int32_class->byval_arg;
4603 helper_sig_memcpy->ret = &mono_defaults.void_class->byval_arg;
4604 helper_sig_memcpy->pinvoke = 1;
4606 /* void memset (intptr, int val, int size) */
4607 helper_sig_memset = mono_metadata_signature_alloc (mono_defaults.corlib, 3);
4608 helper_sig_memset->params [0] = &mono_defaults.int_class->byval_arg;
4609 helper_sig_memset->params [1] = &mono_defaults.int32_class->byval_arg;
4610 helper_sig_memset->params [2] = &mono_defaults.int32_class->byval_arg;
4611 helper_sig_memset->ret = &mono_defaults.void_class->byval_arg;
4612 helper_sig_memset->pinvoke = 1;
4615 static GHashTable *jit_icall_hash_name = NULL;
4616 static GHashTable *jit_icall_hash_addr = NULL;
4619 mono_find_jit_icall_by_name (const char *name)
4621 g_assert (jit_icall_hash_name);
4623 //printf ("lookup addr %s %p\n", name, g_hash_table_lookup (jit_icall_hash_name, name));
4624 return g_hash_table_lookup (jit_icall_hash_name, name);
4628 mono_find_jit_icall_by_addr (gconstpointer addr)
4630 g_assert (jit_icall_hash_addr);
4632 return g_hash_table_lookup (jit_icall_hash_addr, (gpointer)addr);
4636 mono_register_jit_icall (gconstpointer func, const char *name, MonoMethodSignature *sig, gboolean is_save)
4638 MonoJitICallInfo *info;
4639 MonoMethod *wrapper;
4645 if (!jit_icall_hash_name) {
4646 jit_icall_hash_name = g_hash_table_new (g_str_hash, g_str_equal);
4647 jit_icall_hash_addr = g_hash_table_new (NULL, NULL);
4650 if (g_hash_table_lookup (jit_icall_hash_name, name)) {
4651 g_warning ("jit icall already defined \"%s\"\n", name);
4652 g_assert_not_reached ();
4655 info = g_new (MonoJitICallInfo, 1);
4657 info->name = g_strdup (name);
4662 #ifdef MONO_USE_EXC_TABLES
4663 || mono_arch_has_unwind_info (func)
4666 info->wrapper = func;
4669 n = g_strdup_printf ("__icall_wrapper_%s", name);
4670 wrapper = mono_marshal_get_icall_wrapper (sig, n, func);
4671 info->wrapper = mono_jit_compile_method (wrapper);
4675 g_hash_table_insert (jit_icall_hash_name, info->name, info);
4676 g_hash_table_insert (jit_icall_hash_addr, (gpointer)func, info);
4677 if (func != info->wrapper)
4678 g_hash_table_insert (jit_icall_hash_addr, (gpointer)info->wrapper, info);
4683 static GHashTable *emul_opcode_hash = NULL;
4685 static MonoJitICallInfo *
4686 mono_find_jit_opcode_emulation (int opcode)
4688 if (emul_opcode_hash)
4689 return g_hash_table_lookup (emul_opcode_hash, (gpointer)opcode);
4695 mono_register_opcode_emulation (int opcode, MonoMethodSignature *sig, gpointer func)
4697 MonoJitICallInfo *info;
4700 if (!emul_opcode_hash)
4701 emul_opcode_hash = g_hash_table_new (NULL, NULL);
4703 g_assert (!sig->hasthis);
4704 g_assert (sig->param_count < 3);
4706 name = g_strdup_printf ("__emulate_%s", mono_inst_name (opcode));
4708 info = mono_register_jit_icall (func, name, sig, FALSE);
4712 g_hash_table_insert (emul_opcode_hash, (gpointer)opcode, info);
4716 decompose_foreach (MonoInst *tree, gpointer data)
4718 static MonoJitICallInfo *newarr_info = NULL;
4720 switch (tree->opcode) {
4722 MonoCompile *cfg = data;
4723 MonoInst *iargs [3];
4725 NEW_DOMAINCONST (cfg, iargs [0]);
4726 NEW_CLASSCONST (cfg, iargs [1], tree->inst_newa_class);
4727 iargs [2] = tree->inst_newa_len;
4730 newarr_info = mono_find_jit_icall_by_addr (mono_array_new);
4731 g_assert (newarr_info);
4734 mono_emulate_opcode (cfg, tree, iargs, newarr_info);
4744 mono_inst_foreach (MonoInst *tree, MonoInstFunc func, gpointer data) {
4746 switch (mono_burg_arity [tree->opcode]) {
4749 mono_inst_foreach (tree->inst_left, func, data);
4752 mono_inst_foreach (tree->inst_left, func, data);
4753 mono_inst_foreach (tree->inst_right, func, data);
4756 g_assert_not_reached ();
4763 mono_print_bb_code (MonoBasicBlock *bb) {
4765 MonoInst *c = bb->code;
4767 mono_print_tree (c);
4776 print_dfn (MonoCompile *cfg) {
4781 g_print ("IR code for method %s\n", mono_method_full_name (cfg->method, TRUE));
4783 for (i = 0; i < cfg->num_bblocks; ++i) {
4784 bb = cfg->bblocks [i];
4786 char* code1, *code2;
4787 code1 = mono_disasm_code_one (NULL, cfg->method, bb->cil_code, NULL);
4788 if (bb->last_ins->cil_code)
4789 code2 = mono_disasm_code_one (NULL, cfg->method, bb->last_ins->cil_code, NULL);
4791 code2 = g_strdup ("");
4793 code1 [strlen (code1) - 1] = 0;
4794 code = g_strdup_printf ("%s -> %s", code1, code2);
4798 code = g_strdup ("\n");
4799 g_print ("\nBB%d DFN%d (len: %d): %s", bb->block_num, i, bb->cil_length, code);
4801 MonoInst *c = bb->code;
4803 mono_print_tree (c);
4811 g_print ("\tprev:");
4812 for (j = 0; j < bb->in_count; ++j) {
4813 g_print (" BB%d", bb->in_bb [j]->block_num);
4815 g_print ("\t\tsucc:");
4816 for (j = 0; j < bb->out_count; ++j) {
4817 g_print (" BB%d", bb->out_bb [j]->block_num);
4819 g_print ("\n\tidom: BB%d\n", bb->idom? bb->idom->block_num: -1);
4822 g_assert (mono_bitset_test_fast (bb->dominators, bb->idom->dfn));
4825 mono_blockset_print (cfg, bb->dominators, "\tdominators", bb->idom? bb->idom->dfn: -1);
4827 mono_blockset_print (cfg, bb->dfrontier, "\tdfrontier", -1);
4835 * returns the offset used by spillvar. It allocates a new
4836 * spill variable if necessary.
4839 mono_spillvar_offset (MonoCompile *cfg, int spillvar)
4841 MonoSpillInfo **si, *info;
4844 si = &cfg->spill_info;
4846 while (i <= spillvar) {
4849 *si = info = mono_mempool_alloc (cfg->mempool, sizeof (MonoSpillInfo));
4851 cfg->stack_offset -= sizeof (gpointer);
4852 info->offset = cfg->stack_offset;
4856 return (*si)->offset;
4862 g_assert_not_reached ();
4867 mono_bblock_add_inst (MonoBasicBlock *bb, MonoInst *inst)
4871 g_assert (bb->code);
4872 bb->last_ins->next = inst;
4873 bb->last_ins = inst;
4875 bb->last_ins = bb->code = inst;
4880 mono_destroy_compile (MonoCompile *cfg)
4882 //mono_mempool_stats (cfg->mempool);
4883 g_hash_table_destroy (cfg->bb_hash);
4885 mono_regstate_free (cfg->rs);
4886 mono_mempool_destroy (cfg->mempool);
4887 g_list_free (cfg->ldstr_list);
4889 g_free (cfg->varinfo);
4895 mono_get_lmf_addr (void)
4897 MonoJitTlsData *jit_tls;
4899 if ((jit_tls = TlsGetValue (mono_jit_tls_id)))
4900 return &jit_tls->lmf;
4902 g_assert_not_reached ();
4907 * mono_thread_abort:
4908 * @obj: exception object
4910 * abort the thread, print exception information and stack trace
4913 mono_thread_abort (MonoObject *obj)
4915 MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
4923 mono_thread_start_cb (guint32 tid, gpointer stack_start, gpointer func)
4925 MonoJitTlsData *jit_tls;
4928 jit_tls = g_new0 (MonoJitTlsData, 1);
4930 TlsSetValue (mono_jit_tls_id, jit_tls);
4932 jit_tls->abort_func = mono_thread_abort;
4933 jit_tls->end_of_stack = stack_start;
4935 lmf = g_new0 (MonoLMF, 1);
4941 void (*mono_thread_attach_aborted_cb ) (MonoObject *obj) = NULL;
4944 mono_thread_abort_dummy (MonoObject *obj)
4946 if (mono_thread_attach_aborted_cb)
4947 mono_thread_attach_aborted_cb (obj);
4949 mono_thread_abort (obj);
4953 mono_thread_attach_cb (guint32 tid, gpointer stack_start)
4955 MonoJitTlsData *jit_tls;
4958 jit_tls = g_new0 (MonoJitTlsData, 1);
4960 TlsSetValue (mono_jit_tls_id, jit_tls);
4962 jit_tls->abort_func = mono_thread_abort_dummy;
4963 jit_tls->end_of_stack = stack_start;
4965 lmf = g_new0 (MonoLMF, 1);
4972 mono_add_patch_info (MonoCompile *cfg, int ip, MonoJumpInfoType type, gconstpointer target)
4974 MonoJumpInfo *ji = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfo));
4978 ji->data.target = target;
4979 ji->next = cfg->patch_info;
4981 cfg->patch_info = ji;
4985 mono_remove_patch_info (MonoCompile *cfg, int ip)
4987 MonoJumpInfo **ji = &cfg->patch_info;
4990 if ((*ji)->ip.i == ip)
4993 ji = &((*ji)->next);
4998 dec_foreach (MonoInst *tree, MonoCompile *cfg) {
4999 MonoJitICallInfo *info;
5001 switch (mono_burg_arity [tree->opcode]) {
5004 dec_foreach (tree->inst_left, cfg);
5006 if ((info = mono_find_jit_opcode_emulation (tree->opcode))) {
5007 MonoInst *iargs [2];
5009 iargs [0] = tree->inst_left;
5011 mono_emulate_opcode (cfg, tree, iargs, info);
5017 if ((info = mono_find_jit_opcode_emulation (tree->opcode))) {
5018 MonoInst *iargs [2];
5020 iargs [0] = tree->inst_i0;
5021 iargs [1] = tree->inst_i1;
5023 mono_emulate_opcode (cfg, tree, iargs, info);
5025 dec_foreach (iargs [0], cfg);
5026 dec_foreach (iargs [1], cfg);
5029 dec_foreach (tree->inst_left, cfg);
5030 dec_foreach (tree->inst_right, cfg);
5034 g_assert_not_reached ();
5036 decompose_foreach (tree, cfg);
5040 decompose_pass (MonoCompile *cfg) {
5043 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
5046 cfg->prev_ins = NULL;
5047 for (tree = cfg->cbb->code; tree; tree = tree->next) {
5048 dec_foreach (tree, cfg);
5049 cfg->prev_ins = tree;
5055 nullify_basic_block (MonoBasicBlock *bb)
5062 bb->code = bb->last_ins = NULL;
5066 replace_basic_block (MonoBasicBlock *bb, MonoBasicBlock *orig, MonoBasicBlock *repl)
5070 for (i = 0; i < bb->out_count; i++) {
5071 MonoBasicBlock *ob = bb->out_bb [i];
5072 for (j = 0; j < ob->in_count; j++) {
5073 if (ob->in_bb [j] == orig)
5074 ob->in_bb [j] = repl;
5081 merge_basic_blocks (MonoBasicBlock *bb, MonoBasicBlock *bbn)
5083 bb->out_count = bbn->out_count;
5084 bb->out_bb = bbn->out_bb;
5086 replace_basic_block (bb, bbn, bb);
5090 bb->last_ins->next = bbn->code;
5091 bb->last_ins = bbn->last_ins;
5094 bb->code = bbn->code;
5095 bb->last_ins = bbn->last_ins;
5097 bb->next_bb = bbn->next_bb;
5098 nullify_basic_block (bbn);
5102 optimize_branches (MonoCompile *cfg) {
5103 int changed = FALSE;
5104 MonoBasicBlock *bb, *bbn;
5109 /* we skip the entry block (exit is handled specially instead ) */
5110 for (bb = cfg->bb_entry->next_bb; bb; bb = bb->next_bb) {
5112 if (bb->out_count == 1) {
5113 bbn = bb->out_bb [0];
5115 if (bb->region == bbn->region && bb->next_bb == bbn) {
5116 /* the block are in sequence anyway ... */
5119 * miguel: I do not understand what the test below does, could we
5120 * use a macro, or a comment here? opcode > CEE_BEQ && <= BLT_UN
5122 * It could also test for bb->last_in only once, and the value
5123 * could be cached (last_ins->opcode)
5125 if (bb->last_ins && (bb->last_ins->opcode == CEE_BR || (
5126 (bb->last_ins && bb->last_ins->opcode >= CEE_BEQ && bb->last_ins->opcode <= CEE_BLT_UN)))) {
5127 bb->last_ins->opcode = CEE_NOP;
5129 if (cfg->verbose_level > 2)
5130 g_print ("br removal triggered %d -> %d\n", bb->block_num, bbn->block_num);
5132 /* fixme: this causes problems with inlining */
5133 if (bbn->in_count == 1) {
5135 if (bbn != cfg->bb_exit) {
5136 if (cfg->verbose_level > 2)
5137 g_print ("block merge triggered %d -> %d\n", bb->block_num, bbn->block_num);
5138 merge_basic_blocks (bb, bbn);
5142 //mono_print_bb_code (bb);
5145 if (bb->last_ins && bb->last_ins->opcode == CEE_BR) {
5146 bbn = bb->last_ins->inst_target_bb;
5147 if (bb->region == bbn->region && bbn->code && bbn->code->opcode == CEE_BR) {
5149 if (cfg->verbose_level > 2)
5150 g_print ("in %s branch to branch triggered %d -> %d\n", cfg->method->name, bb->block_num, bbn->block_num);
5151 bb->out_bb [0] = bb->last_ins->inst_target_bb = bbn->code->inst_target_bb;
5156 } else if (bb->out_count == 2) {
5157 /* fixme: this does not correctly unlink the blocks, so we get serious problems in idom code */
5158 if (0 && bb->last_ins && bb->last_ins->opcode >= CEE_BEQ && bb->last_ins->opcode <= CEE_BLT_UN) {
5159 bbn = bb->last_ins->inst_true_bb;
5160 if (bb->region == bbn->region && bbn->code && bbn->code->opcode == CEE_BR) {
5161 if (cfg->verbose_level > 2)
5162 g_print ("cbranch to branch triggered %d -> %d (0x%02x)\n", bb->block_num,
5163 bbn->block_num, bbn->code->opcode);
5165 if (bb->out_bb [0] == bbn) {
5166 bb->out_bb [0] = bbn->code->inst_target_bb;
5167 } else if (bb->out_bb [1] == bbn) {
5168 bb->out_bb [1] = bbn->code->inst_target_bb;
5170 bb->last_ins->inst_true_bb = bbn->code->inst_target_bb;
5180 mono_compile_create_vars (MonoCompile *cfg)
5182 MonoMethodSignature *sig;
5183 MonoMethodHeader *header;
5186 header = ((MonoMethodNormal *)cfg->method)->header;
5188 sig = cfg->method->signature;
5190 if (!MONO_TYPE_IS_VOID (sig->ret)) {
5191 cfg->ret = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst));
5192 cfg->ret->opcode = OP_RETARG;
5193 cfg->ret->inst_vtype = sig->ret;
5194 cfg->ret->klass = mono_class_from_mono_type (sig->ret);
5198 mono_compile_create_var (cfg, &cfg->method->klass->this_arg, OP_ARG);
5200 for (i = 0; i < sig->param_count; ++i)
5201 mono_compile_create_var (cfg, sig->params [i], OP_ARG);
5203 cfg->locals_start = cfg->num_varinfo;
5205 for (i = 0; i < header->num_locals; ++i)
5206 mono_compile_create_var (cfg, header->locals [i], OP_LOCAL);
5211 mono_print_code (MonoCompile *cfg)
5215 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
5216 MonoInst *tree = bb->code;
5221 g_print ("CODE BLOCK %d (nesting %d):\n", bb->block_num, bb->nesting);
5223 for (; tree; tree = tree->next) {
5224 mono_print_tree (tree);
5229 bb->last_ins->next = NULL;
5234 extern const char * const mono_burg_rule_string [];
5237 emit_state (MonoCompile *cfg, MBState *state, int goal)
5240 int ern = mono_burg_rule (state, goal);
5241 const guint16 *nts = mono_burg_nts [ern];
5244 //g_print ("rule: %s\n", mono_burg_rule_string [ern]);
5248 // state->reg1 = state->reg2; /* chain rule */
5250 state->reg1 = mono_regstate_next_int (cfg->rs);
5251 //g_print ("alloc symbolic R%d (reg2: R%d) in block %d\n", state->reg1, state->reg2, cfg->cbb->block_num);
5254 state->reg1 = mono_regstate_next_int (cfg->rs);
5255 state->reg2 = mono_regstate_next_int (cfg->rs);
5258 state->reg1 = mono_regstate_next_float (cfg->rs);
5265 mono_burg_kids (state, ern, kids);
5267 emit_state (cfg, kids [0], nts [0]);
5269 emit_state (cfg, kids [1], nts [1]);
5271 g_assert (!nts [3]);
5272 emit_state (cfg, kids [2], nts [2]);
5277 // g_print ("emit: %s (%p)\n", mono_burg_rule_string [ern], state);
5278 if ((emit = mono_burg_func [ern]))
5279 emit (state, state->tree, cfg);
5282 #define DEBUG_SELECTION
5285 mini_select_instructions (MonoCompile *cfg)
5289 cfg->state_pool = mono_mempool_new ();
5290 cfg->rs = mono_regstate_new ();
5292 #ifdef DEBUG_SELECTION
5293 if (cfg->verbose_level >= 4) {
5294 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
5295 MonoInst *tree = bb->code;
5296 g_print ("DUMP BLOCK %d:\n", bb->block_num);
5299 for (; tree; tree = tree->next) {
5300 mono_print_tree (tree);
5307 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
5308 MonoInst *tree = bb->code, *next;
5314 bb->last_ins = NULL;
5317 mono_regstate_reset (cfg->rs);
5319 #ifdef DEBUG_SELECTION
5320 if (cfg->verbose_level >= 3)
5321 g_print ("LABEL BLOCK %d:\n", bb->block_num);
5323 for (; tree; tree = next) {
5325 #ifdef DEBUG_SELECTION
5326 if (cfg->verbose_level >= 3) {
5327 mono_print_tree (tree);
5332 if (!(mbstate = mono_burg_label (tree, cfg))) {
5333 g_warning ("unabled to label tree %p", tree);
5334 mono_print_tree (tree);
5336 g_assert_not_reached ();
5338 emit_state (cfg, mbstate, MB_NTERM_stmt);
5340 bb->max_ireg = cfg->rs->next_vireg;
5341 bb->max_freg = cfg->rs->next_vfreg;
5344 bb->last_ins->next = NULL;
5346 mono_mempool_empty (cfg->state_pool);
5348 mono_mempool_destroy (cfg->state_pool);
5352 mono_codegen (MonoCompile *cfg)
5354 MonoJumpInfo *patch_info;
5356 int i, max_epilog_size;
5359 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
5360 cfg->spill_count = 0;
5361 /* we reuse dfn here */
5362 /* bb->dfn = bb_count++; */
5363 mono_arch_local_regalloc (cfg, bb);
5366 if (mono_trace_coverage)
5367 mono_allocate_coverage_info (cfg->method, cfg->num_bblocks);
5369 code = mono_arch_emit_prolog (cfg);
5371 if (mono_jit_profile)
5372 code = mono_arch_instrument_prolog (cfg, mono_profiler_method_enter, code, FALSE);
5374 cfg->code_len = code - cfg->native_code;
5375 cfg->prolog_end = cfg->code_len;
5377 mono_debug_open_method (cfg);
5379 /* emit code all basic blocks */
5380 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
5381 bb->native_offset = cfg->code_len;
5382 mono_arch_output_basic_block (cfg, bb);
5384 cfg->bb_exit->native_offset = cfg->code_len;
5386 code = cfg->native_code + cfg->code_len;
5388 max_epilog_size = mono_arch_max_epilog_size (cfg);
5390 /* we always allocate code in cfg->domain->code_mp to increase locality */
5391 cfg->code_size = cfg->code_len + max_epilog_size;
5392 /* fixme: align to MONO_ARCH_CODE_ALIGNMENT */
5393 code = mono_mempool_alloc (cfg->domain->code_mp, cfg->code_size);
5394 memcpy (code, cfg->native_code, cfg->code_len);
5395 g_free (cfg->native_code);
5396 cfg->native_code = code;
5397 code = cfg->native_code + cfg->code_len;
5399 /* g_assert (((int)cfg->native_code & (MONO_ARCH_CODE_ALIGNMENT - 1)) == 0); */
5401 cfg->epilog_begin = cfg->code_len;
5403 if (mono_jit_profile)
5404 code = mono_arch_instrument_epilog (cfg, mono_profiler_method_leave, code, FALSE);
5406 cfg->code_len = code - cfg->native_code;
5408 mono_arch_emit_epilog (cfg);
5410 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5411 switch (patch_info->type) {
5412 case MONO_PATCH_INFO_ABS: {
5413 MonoJitICallInfo *info = mono_find_jit_icall_by_addr (patch_info->data.target);
5415 //printf ("TEST %s %p\n", info->name, patch_info->data.target);
5416 patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
5417 patch_info->data.name = info->name;
5421 case MONO_PATCH_INFO_SWITCH: {
5422 gpointer *table = g_new (gpointer, patch_info->table_size);
5423 patch_info->ip.i = patch_info->ip.label->inst_c0;
5424 for (i = 0; i < patch_info->table_size; i++) {
5425 table [i] = (gpointer)patch_info->data.table [i]->native_offset;
5427 patch_info->data.target = table;
5436 if (cfg->verbose_level > 1)
5437 g_print ("Method %s::%s emmitted at %p to %p\n", cfg->method->klass->name,
5438 cfg->method->name, cfg->native_code, cfg->native_code + cfg->code_len);
5440 mono_arch_patch_code (cfg->method, cfg->domain, cfg->native_code, cfg->patch_info);
5442 mono_debug_close_method (cfg);
5446 mono_cprop_copy_values (MonoCompile *cfg, MonoInst *tree, MonoInst **acp)
5451 if (tree->ssa_op == MONO_SSA_LOAD && (tree->inst_i0->opcode == OP_LOCAL || tree->inst_i0->opcode == OP_ARG) &&
5452 (cp = acp [tree->inst_i0->inst_c0]) && !tree->inst_i0->flags) {
5454 if (cp->opcode == OP_ICONST) {
5455 if (cfg->opt & MONO_OPT_CONSPROP) {
5456 //{ static int c = 0; printf ("CCOPY %d %d %s\n", c++, cp->inst_c0, mono_method_full_name (cfg->method, TRUE)); }
5460 if (tree->inst_i0->inst_vtype->type == cp->inst_vtype->type) {
5461 if (cfg->opt & MONO_OPT_COPYPROP) {
5462 //{ static int c = 0; printf ("VCOPY %d\n", ++c); }
5468 arity = mono_burg_arity [tree->opcode];
5471 mono_cprop_copy_values (cfg, tree->inst_i0, acp);
5472 if (cfg->opt & MONO_OPT_CFOLD)
5473 mono_constant_fold_inst (tree, NULL);
5475 mono_cprop_copy_values (cfg, tree->inst_i1, acp);
5476 if (cfg->opt & MONO_OPT_CFOLD)
5477 mono_constant_fold_inst (tree, NULL);
5479 mono_constant_fold_inst (tree, NULL);
5485 mono_cprop_invalidate_values (MonoInst *tree, MonoInst **acp, int acp_size)
5489 switch (tree->opcode) {
5499 if (tree->ssa_op == MONO_SSA_NOP) {
5500 memset (acp, 0, sizeof (MonoInst *) * acp_size);
5517 case OP_VOIDCALL_REG:
5518 case OP_VOIDCALLVIRT:
5520 MonoCallInst *call = (MonoCallInst *)tree;
5521 MonoMethodSignature *sig = call->signature;
5522 int i, byref = FALSE;
5524 for (i = 0; i < sig->param_count; i++) {
5525 if (sig->params [i]->byref) {
5532 memset (acp, 0, sizeof (MonoInst *) * acp_size);
5540 arity = mono_burg_arity [tree->opcode];
5546 mono_cprop_invalidate_values (tree->inst_i0, acp, acp_size);
5549 mono_cprop_invalidate_values (tree->inst_i0, acp, acp_size);
5550 mono_cprop_invalidate_values (tree->inst_i1, acp, acp_size);
5553 g_assert_not_reached ();
5558 mono_local_cprop_bb (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst **acp, int acp_size)
5560 MonoInst *tree = bb->code;
5566 for (; tree; tree = tree->next) {
5568 mono_cprop_copy_values (cfg, tree, acp);
5570 mono_cprop_invalidate_values (tree, acp, acp_size);
5572 if (tree->ssa_op == MONO_SSA_STORE &&
5573 (tree->inst_i0->opcode == OP_LOCAL || tree->inst_i0->opcode == OP_ARG)) {
5574 MonoInst *i1 = tree->inst_i1;
5576 acp [tree->inst_i0->inst_c0] = NULL;
5578 for (i = 0; i < acp_size; i++) {
5579 if (acp [i] && acp [i]->opcode != OP_ICONST &&
5580 acp [i]->inst_c0 == tree->inst_i0->inst_c0) {
5585 if (i1->opcode == OP_ICONST) {
5586 acp [tree->inst_i0->inst_c0] = i1;
5587 //printf ("DEF1 BB%d %d\n", bb->block_num,tree->inst_i0->inst_c0);
5589 if (i1->ssa_op == MONO_SSA_LOAD &&
5590 (i1->inst_i0->opcode == OP_LOCAL || i1->inst_i0->opcode == OP_ARG) &&
5591 (i1->inst_i0->inst_c0 != tree->inst_i0->inst_c0)) {
5592 acp [tree->inst_i0->inst_c0] = i1->inst_i0;
5593 //printf ("DEF2 BB%d %d %d\n", bb->block_num,tree->inst_i0->inst_c0,i1->inst_i0->inst_c0);
5598 if (tree->opcode == CEE_BEQ) {
5599 g_assert (tree->inst_i0->opcode == OP_COMPARE);
5600 if (tree->inst_i0->inst_i0->opcode == OP_ICONST &&
5601 tree->inst_i0->inst_i1->opcode == OP_ICONST) {
5603 tree->opcode = CEE_BR;
5604 if (tree->inst_i0->inst_i0->opcode == tree->inst_i0->inst_i1->opcode) {
5605 tree->inst_target_bb = tree->inst_true_bb;
5607 tree->inst_target_bb = tree->inst_false_bb;
5616 mono_local_cprop (MonoCompile *cfg)
5621 acp = alloca (sizeof (MonoInst *) * cfg->num_varinfo);
5623 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
5624 memset (acp, 0, sizeof (MonoInst *) * cfg->num_varinfo);
5625 mono_local_cprop_bb (cfg, bb, acp, cfg->num_varinfo);
5630 mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, int parts)
5632 MonoMethodHeader *header = ((MonoMethodNormal *)method)->header;
5633 guint8 *ip = (guint8 *)header->code;
5636 int dfn = 0, i, code_size_ratio;
5638 mono_jit_stats.methods_compiled++;
5639 if (mono_jit_profile)
5640 mono_profiler_method_jit (method);
5642 cfg = g_new0 (MonoCompile, 1);
5643 cfg->method = method;
5644 cfg->mempool = mono_mempool_new ();
5646 cfg->bb_hash = g_hash_table_new (g_direct_hash, NULL);
5647 cfg->domain = domain;
5648 cfg->verbose_level = mini_verbose;
5651 * create MonoInst* which represents arguments and local variables
5653 mono_compile_create_vars (cfg);
5655 if (cfg->verbose_level > 2)
5656 g_print ("converting method %s\n", mono_method_full_name (method, TRUE));
5658 if ((i = mono_method_to_ir (cfg, method, NULL, NULL, cfg->locals_start, NULL, NULL, NULL, 0, FALSE)) < 0) {
5659 mono_destroy_compile (cfg);
5660 if (mono_jit_profile)
5661 mono_profiler_method_end_jit (method, MONO_PROFILE_FAILED);
5665 mono_jit_stats.basic_blocks += cfg->num_bblocks;
5666 mono_jit_stats.max_basic_blocks = MAX (cfg->num_bblocks, mono_jit_stats.max_basic_blocks);
5668 /*g_print ("numblocks = %d\n", cfg->num_bblocks);*/
5670 /* Depth-first ordering on basic blocks */
5671 cfg->bblocks = mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * (cfg->num_bblocks + 1));
5673 if (cfg->opt & MONO_OPT_BRANCH)
5674 optimize_branches (cfg);
5676 df_visit (cfg->bb_entry, &dfn, cfg->bblocks);
5677 if (cfg->num_bblocks != dfn + 1) {
5678 if (cfg->verbose_level > 1)
5679 g_print ("unreachable code?\n");
5680 cfg->num_bblocks = dfn + 1;
5683 if (cfg->opt & MONO_OPT_LOOP) {
5684 mono_compile_dominator_info (cfg, MONO_COMP_DOM | MONO_COMP_IDOM);
5685 mono_compute_natural_loops (cfg);
5689 /* after method_to_ir */
5693 //#define DEBUGSSA "logic_run"
5694 #define DEBUGSSA_CLASS "Tests"
5698 if (!header->num_clauses && !cfg->disable_ssa) {
5699 mono_local_cprop (cfg);
5700 mono_ssa_compute (cfg);
5704 /* fixme: add all optimizations which requires SSA */
5705 if (cfg->opt & (MONO_OPT_DEADCE)) {
5706 if (!(cfg->comp_done & MONO_COMP_SSA) && !header->num_clauses && !cfg->disable_ssa) {
5707 mono_local_cprop (cfg);
5708 mono_ssa_compute (cfg);
5710 if (cfg->verbose_level >= 2) {
5717 /* after SSA translation */
5721 if ((cfg->opt & MONO_OPT_CONSPROP) || (cfg->opt & MONO_OPT_COPYPROP)) {
5722 if (cfg->comp_done & MONO_COMP_SSA) {
5723 mono_ssa_cprop (cfg);
5725 mono_local_cprop (cfg);
5729 if (cfg->comp_done & MONO_COMP_SSA) {
5730 mono_ssa_deadce (cfg);
5732 //mono_ssa_strength_reduction (cfg);
5734 mono_ssa_remove (cfg);
5736 if (cfg->opt & MONO_OPT_BRANCH)
5737 optimize_branches (cfg);
5740 /* after SSA removal */
5744 decompose_pass (cfg);
5746 if (cfg->opt & MONO_OPT_LINEARS) {
5749 /* fixme: maybe we can avoid to compute livenesss here if already computed ? */
5750 cfg->comp_done &= ~MONO_COMP_LIVENESS;
5751 if (!(cfg->comp_done & MONO_COMP_LIVENESS))
5752 mono_analyze_liveness (cfg);
5754 if ((vars = mono_arch_get_allocatable_int_vars (cfg))) {
5755 regs = mono_arch_get_global_int_regs (cfg);
5756 mono_linear_scan (cfg, vars, regs, &cfg->used_int_regs);
5760 //mono_print_code (cfg);
5764 /* variables are allocated after decompose, since decompose could create temps */
5765 mono_arch_allocate_vars (cfg);
5767 if (cfg->opt & MONO_OPT_CFOLD)
5768 mono_constant_fold (cfg);
5770 mini_select_instructions (cfg);
5773 if (cfg->verbose_level >= 2) {
5774 char *id = mono_method_full_name (cfg->method, FALSE);
5775 mono_disassemble_code (cfg->native_code, cfg->code_len, id + 3);
5779 jinfo = mono_mempool_alloc0 (cfg->domain->mp, sizeof (MonoJitInfo));
5781 jinfo = g_new0 (MonoJitInfo, 1);
5782 jinfo->method = method;
5783 jinfo->code_start = cfg->native_code;
5784 jinfo->code_size = cfg->code_len;
5785 jinfo->used_regs = cfg->used_int_regs;
5787 if (header->num_clauses) {
5790 jinfo->exvar_offset = cfg->exvar? cfg->exvar->inst_offset: 0;
5791 jinfo->num_clauses = header->num_clauses;
5792 jinfo->clauses = mono_mempool_alloc0 (cfg->domain->mp,
5793 sizeof (MonoJitExceptionInfo) * header->num_clauses);
5795 for (i = 0; i < header->num_clauses; i++) {
5796 MonoExceptionClause *ec = &header->clauses [i];
5797 MonoJitExceptionInfo *ei = &jinfo->clauses [i];
5798 MonoBasicBlock *tblock;
5800 ei->flags = ec->flags;
5802 if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
5803 tblock = g_hash_table_lookup (cfg->bb_hash, ip + ec->token_or_filter);
5805 ei->data.filter = cfg->native_code + tblock->native_offset;
5807 ei->data.token = ec->token_or_filter;
5810 tblock = g_hash_table_lookup (cfg->bb_hash, ip + ec->try_offset);
5812 ei->try_start = cfg->native_code + tblock->native_offset;
5813 tblock = g_hash_table_lookup (cfg->bb_hash, ip + ec->try_offset + ec->try_len);
5815 ei->try_end = cfg->native_code + tblock->native_offset;
5816 tblock = g_hash_table_lookup (cfg->bb_hash, ip + ec->handler_offset);
5818 ei->handler_start = cfg->native_code + tblock->native_offset;
5823 mono_jit_info_table_add (cfg->domain, jinfo);
5825 /* collect statistics */
5826 mono_jit_stats.allocated_code_size += cfg->code_len;
5827 code_size_ratio = cfg->code_len;
5828 if (code_size_ratio > mono_jit_stats.biggest_method_size) {
5829 mono_jit_stats.biggest_method_size = code_size_ratio;
5830 mono_jit_stats.biggest_method = method;
5832 code_size_ratio = (code_size_ratio * 100) / ((MonoMethodNormal *)method)->header->code_size;
5833 if (code_size_ratio > mono_jit_stats.max_code_size_ratio) {
5834 mono_jit_stats.max_code_size_ratio = code_size_ratio;
5835 mono_jit_stats.max_ratio_method = method;
5837 mono_jit_stats.native_code_size += cfg->code_len;
5839 if (mono_jit_profile)
5840 mono_profiler_method_end_jit (method, MONO_PROFILE_OK);
5846 mono_jit_compile_method (MonoMethod *method)
5848 /* FIXME: later copy the code from mono */
5849 MonoDomain *target_domain, *domain = mono_domain_get ();
5851 GHashTable *jit_code_hash;
5854 if (default_opt & MONO_OPT_SAHRED)
5855 target_domain = mono_root_domain;
5857 target_domain = domain;
5859 jit_code_hash = target_domain->jit_code_hash;
5861 if ((code = g_hash_table_lookup (jit_code_hash, method))) {
5862 mono_jit_stats.methods_lookups++;
5866 #ifdef MONO_USE_AOT_COMPILER
5867 if (!mono_compile_aot) {
5868 mono_class_init (method->klass);
5869 if ((code = mono_aot_get_method (method))) {
5870 g_hash_table_insert (jit_code_hash, method, code);
5876 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
5877 (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
5878 if (!method->info) {
5881 if (!method->addr && (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL))
5882 mono_lookup_pinvoke_call (method);
5883 #ifdef MONO_USE_EXC_TABLES
5884 if (mono_method_blittable (method)) {
5885 method->info = method->addr;
5888 nm = mono_marshal_get_native_wrapper (method);
5889 method->info = mono_compile_method (nm);
5891 //if (mono_debug_format != MONO_DEBUG_FORMAT_NONE)
5892 //mono_debug_add_wrapper (method, nm);
5893 #ifdef MONO_USE_EXC_TABLES
5897 return method->info;
5898 } else if ((method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME)) {
5899 const char *name = method->name;
5902 if (method->klass->parent == mono_defaults.multicastdelegate_class) {
5903 if (*name == '.' && (strcmp (name, ".ctor") == 0)) {
5904 /* FIXME: uhm, we need a wrapper to handle exceptions? */
5905 return (gpointer)mono_delegate_ctor;
5906 } else if (*name == 'I' && (strcmp (name, "Invoke") == 0)) {
5907 nm = mono_marshal_get_delegate_invoke (method);
5908 return mono_jit_compile_method (nm);
5909 } else if (*name == 'B' && (strcmp (name, "BeginInvoke") == 0)) {
5910 nm = mono_marshal_get_delegate_begin_invoke (method);
5911 return mono_jit_compile_method (nm);
5912 } else if (*name == 'E' && (strcmp (name, "EndInvoke") == 0)) {
5913 nm = mono_marshal_get_delegate_end_invoke (method);
5914 return mono_jit_compile_method (nm);
5920 cfg = mini_method_compile (method, default_opt, target_domain, 0);
5921 code = cfg->native_code;
5922 mono_destroy_compile (cfg);
5924 g_hash_table_insert (jit_code_hash, method, code);
5926 /* make sure runtime_init is called */
5927 mono_class_vtable (target_domain, method->klass);
5933 * mono_jit_runtime_invoke:
5934 * @method: the method to invoke
5935 * @obj: this pointer
5936 * @params: array of parameter values.
5937 * @exc: used to catch exceptions objects
5940 mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
5943 MonoObject *(*runtime_invoke) (MonoObject *this, void **params, MonoObject **exc);
5944 invoke = mono_marshal_get_runtime_invoke (method);
5945 runtime_invoke = mono_jit_compile_method (invoke);
5946 return runtime_invoke (obj, params, exc);
5949 #ifdef PLATFORM_WIN32
5950 #define GET_CONTEXT \
5951 struct sigcontext *ctx = (struct sigcontext*)_dummy;
5953 #define GET_CONTEXT \
5954 void **_p = (void **)&_dummy; \
5955 struct sigcontext *ctx = (struct sigcontext *)++_p;
5959 sigfpe_signal_handler (int _dummy)
5964 exc = mono_get_exception_divide_by_zero ();
5966 mono_arch_handle_exception (ctx, exc, FALSE);
5970 sigill_signal_handler (int _dummy)
5974 exc = mono_get_exception_execution_engine ("SIGILL");
5976 mono_arch_handle_exception (ctx, exc, FALSE);
5980 sigsegv_signal_handler (int _dummy)
5985 exc = mono_get_exception_null_reference ();
5987 mono_arch_handle_exception (ctx, exc, FALSE);
5991 sigusr1_signal_handler (int _dummy)
5996 thread = mono_thread_current ();
5998 g_assert (thread->abort_exc);
6000 mono_arch_handle_exception (ctx, thread->abort_exc, FALSE);
6004 mono_runtime_install_handlers (void)
6006 #ifndef PLATFORM_WIN32
6007 struct sigaction sa;
6010 #ifdef PLATFORM_WIN32
6012 win32_seh_set_handler(SIGFPE, sigfpe_signal_handler);
6013 win32_seh_set_handler(SIGILL, sigill_signal_handler);
6014 win32_seh_set_handler(SIGSEGV, sigsegv_signal_handler);
6015 #else /* !PLATFORM_WIN32 */
6017 /* libpthreads has its own implementation of sigaction(),
6018 * but it seems to work well with our current exception
6019 * handlers. If not we must call syscall directly instead
6023 sa.sa_handler = sigfpe_signal_handler;
6024 sigemptyset (&sa.sa_mask);
6026 //g_assert (syscall (SYS_sigaction, SIGFPE, &sa, NULL) != -1);
6027 g_assert (sigaction (SIGFPE, &sa, NULL) != -1);
6030 sa.sa_handler = sigill_signal_handler;
6031 sigemptyset (&sa.sa_mask);
6033 //g_assert (syscall (SYS_sigaction, SIGILL, &sa, NULL) != -1);
6034 g_assert (sigaction (SIGILL, &sa, NULL) != -1);
6036 /* catch thread abort signal */
6037 sa.sa_handler = sigusr1_signal_handler;
6038 sigemptyset (&sa.sa_mask);
6040 //g_assert (syscall (SYS_sigaction, SIGILL, &sa, NULL) != -1);
6041 g_assert (sigaction (mono_thread_get_abort_signal (), &sa, NULL) != -1);
6045 sa.sa_handler = sigsegv_signal_handler;
6046 sigemptyset (&sa.sa_mask);
6048 //g_assert (syscall (SYS_sigaction, SIGSEGV, &sa, NULL) != -1);
6049 g_assert (sigaction (SIGSEGV, &sa, NULL) != -1);
6051 #endif /* PLATFORM_WIN32 */
6054 /* mono_jit_create_remoting_trampoline:
6055 * @method: pointer to the method info
6057 * Creates a trampoline which calls the remoting functions. This
6058 * is used in the vtable of transparent proxies.
6060 * Returns: a pointer to the newly created code
6063 mono_jit_create_remoting_trampoline (MonoMethod *method)
6066 guint8 *addr = NULL;
6068 if (method->signature->hasthis && (method->klass->marshalbyref || method->klass == mono_defaults.object_class)) {
6069 nm = mono_marshal_get_remoting_invoke (method);
6070 addr = mono_compile_method (nm);
6072 addr = mono_compile_method (method);
6077 static CRITICAL_SECTION ms;
6080 mini_init (const char *filename)
6084 metadata_section = &ms;
6085 InitializeCriticalSection (metadata_section);
6087 mono_jit_tls_id = TlsAlloc ();
6088 mono_thread_start_cb (GetCurrentThreadId (), (gpointer)-1, NULL);
6092 mono_runtime_install_handlers ();
6094 mono_install_compile_method (mono_jit_compile_method);
6095 mono_install_trampoline (mono_arch_create_jit_trampoline);
6096 mono_install_remoting_trampoline (mono_jit_create_remoting_trampoline);
6097 mono_install_runtime_invoke (mono_jit_runtime_invoke);
6098 mono_install_handler (mono_arch_get_throw_exception ());
6099 mono_install_stack_walk (mono_jit_walk_stack);
6100 mono_install_get_config_dir ();
6102 domain = mono_init (filename);
6105 mono_add_internal_call ("System.Diagnostics.StackFrame::get_frame_info",
6106 ves_icall_get_frame_info);
6107 mono_add_internal_call ("System.Diagnostics.StackTrace::get_trace",
6108 ves_icall_get_trace);
6109 mono_add_internal_call ("Mono.Runtime::mono_runtime_install_handlers",
6110 mono_runtime_install_handlers);
6113 create_helper_signature ();
6115 mono_arch_register_lowlevel_calls ();
6116 mono_register_jit_icall (mono_profiler_method_enter, "mono_profiler_method_enter", NULL, TRUE);
6117 mono_register_jit_icall (mono_profiler_method_leave, "mono_profiler_method_leave", NULL, TRUE);
6119 mono_register_jit_icall (mono_get_lmf_addr, "mono_get_lmf_addr", helper_sig_ptr_void, TRUE);
6120 mono_register_jit_icall (mono_domain_get, "mono_domain_get", helper_sig_domain_get, TRUE);
6122 /* fixme: we cant hanlde vararg methods this way, because the signature is not constant */
6123 //mono_register_jit_icall (ves_array_element_address, "ves_array_element_address", NULL);
6124 //mono_register_jit_icall (mono_array_new_va, "mono_array_new_va", NULL);
6126 mono_register_jit_icall (mono_arch_get_throw_exception (), "mono_arch_throw_exception", helper_sig_void_obj, TRUE);
6127 mono_register_jit_icall (mono_arch_get_throw_exception_by_name (), "mono_arch_throw_exception_by_name",
6128 helper_sig_void_ptr, TRUE);
6131 * NOTE, NOTE, NOTE, NOTE:
6132 * when adding emulation for some opcodes, remember to also add a dummy
6133 * rule to the burg files, because we need the arity information to be correct.
6135 mono_register_opcode_emulation (OP_LMUL, helper_sig_long_long_long, mono_llmult);
6136 mono_register_opcode_emulation (OP_LMUL_OVF_UN, helper_sig_long_long_long, mono_llmult_ovf_un);
6137 mono_register_opcode_emulation (OP_LMUL_OVF, helper_sig_long_long_long, mono_llmult_ovf);
6138 mono_register_opcode_emulation (OP_LDIV, helper_sig_long_long_long, mono_lldiv);
6139 mono_register_opcode_emulation (OP_LDIV_UN, helper_sig_long_long_long, mono_lldiv_un);
6140 mono_register_opcode_emulation (OP_LREM, helper_sig_long_long_long, mono_llrem);
6141 mono_register_opcode_emulation (OP_LREM_UN, helper_sig_long_long_long, mono_llrem_un);
6143 mono_register_opcode_emulation (OP_LSHL, helper_sig_long_long_int, mono_lshl);
6144 mono_register_opcode_emulation (OP_LSHR, helper_sig_long_long_int, mono_lshr);
6145 mono_register_opcode_emulation (OP_LSHR_UN, helper_sig_long_long_int, mono_lshr_un);
6147 mono_register_opcode_emulation (OP_FCONV_TO_U8, helper_sig_ulong_double, mono_fconv_u8);
6148 mono_register_opcode_emulation (OP_FCONV_TO_U4, helper_sig_uint_double, mono_fconv_u4);
6149 mono_register_opcode_emulation (OP_FCONV_TO_OVF_I8, helper_sig_long_double, mono_fconv_ovf_i8);
6150 mono_register_opcode_emulation (OP_FCONV_TO_OVF_U8, helper_sig_ulong_double, mono_fconv_ovf_u8);
6152 #if SIZEOF_VOID_P == 4
6153 mono_register_opcode_emulation (OP_FCONV_TO_U, helper_sig_uint_double, mono_fconv_u4);
6155 #warning "fixme: add opcode emulation"
6158 /* other jit icalls */
6159 mono_register_jit_icall (mono_class_static_field_address , "mono_class_static_field_address",
6160 helper_sig_ptr_ptr_ptr, FALSE);
6161 mono_register_jit_icall (mono_ldtoken_wrapper, "mono_ldtoken_wrapper", helper_sig_ptr_ptr_ptr, FALSE);
6162 mono_register_jit_icall (mono_ldstr, "mono_ldstr", helper_sig_ldstr, FALSE);
6163 mono_register_jit_icall (helper_memcpy, "helper_memcpy", helper_sig_memcpy, FALSE);
6164 mono_register_jit_icall (helper_memset, "helper_memset", helper_sig_memset, FALSE);
6165 mono_register_jit_icall (helper_initobj, "helper_initobj", helper_sig_initobj, FALSE);
6166 mono_register_jit_icall (helper_stelem_ref, "helper_stelem_ref", helper_sig_stelem_ref, FALSE);
6167 mono_register_jit_icall (mono_object_new, "mono_object_new", helper_sig_object_new, FALSE);
6168 mono_register_jit_icall (mono_array_new, "mono_array_new", helper_sig_newarr, FALSE);
6169 mono_register_jit_icall (mono_string_to_utf16, "mono_string_to_utf16", helper_sig_ptr_obj, FALSE);
6170 mono_register_jit_icall (mono_string_from_utf16, "mono_string_from_utf16", helper_sig_obj_ptr, FALSE);
6171 mono_register_jit_icall (mono_string_new_wrapper, "mono_string_new_wrapper", helper_sig_obj_ptr, FALSE);
6172 mono_register_jit_icall (mono_string_to_utf8, "mono_string_to_utf8", helper_sig_ptr_obj, FALSE);
6173 mono_register_jit_icall (mono_string_to_bstr, "mono_string_to_bstr", helper_sig_ptr_obj, FALSE);
6174 mono_register_jit_icall (mono_string_to_ansibstr, "mono_string_to_ansibstr", helper_sig_ptr_obj, FALSE);
6175 mono_register_jit_icall (mono_string_builder_to_utf8, "mono_string_builder_to_utf8", helper_sig_ptr_obj, FALSE);
6176 mono_register_jit_icall (mono_array_to_savearray, "mono_array_to_savearray", helper_sig_ptr_obj, FALSE);
6177 mono_register_jit_icall (mono_array_to_lparray, "mono_array_to_lparray", helper_sig_ptr_obj, FALSE);
6178 mono_register_jit_icall (mono_delegate_to_ftnptr, "mono_delegate_to_ftnptr", helper_sig_ptr_obj, FALSE);
6179 mono_register_jit_icall (mono_marshal_string_array, "mono_marshal_string_array", helper_sig_ptr_obj, FALSE);
6180 mono_register_jit_icall (mono_string_utf8_to_builder, "mono_string_utf8_to_builder", helper_sig_void_ptr_ptr, FALSE);
6181 mono_register_jit_icall (mono_marshal_free_array, "mono_marshal_free_array", helper_sig_void_ptr_ptr, FALSE);
6182 mono_register_jit_icall (mono_string_to_byvalstr, "mono_string_to_byvalstr", helper_sig_void_ptr_ptr_ptr, FALSE);
6183 mono_register_jit_icall (mono_string_to_byvalwstr, "mono_string_to_byvalwstr", helper_sig_void_ptr_ptr_ptr, FALSE);
6184 mono_register_jit_icall (g_free, "g_free", helper_sig_void_ptr, FALSE);
6185 mono_register_jit_icall (mono_ldftn, "mono_ldftn", helper_sig_compile, FALSE);
6186 mono_register_jit_icall (mono_ldvirtfn, "mono_ldvirtfn", helper_sig_compile_virt, FALSE);
6188 mono_runtime_init (domain, mono_thread_start_cb,
6189 mono_thread_attach_cb);
6191 //mono_thread_attach (domain);
6195 MonoJitStats mono_jit_stats = {0};
6198 print_jit_stats (void)
6200 if (mono_jit_stats.enabled) {
6201 g_print ("Mono Jit statistics\n");
6202 g_print ("Compiled methods: %ld\n", mono_jit_stats.methods_compiled);
6203 g_print ("Methods from AOT: %ld\n", mono_jit_stats.methods_aot);
6204 g_print ("Methods cache lookup: %ld\n", mono_jit_stats.methods_lookups);
6205 g_print ("Method trampolines: %ld\n", mono_jit_stats.method_trampolines);
6206 g_print ("Basic blocks: %ld\n", mono_jit_stats.basic_blocks);
6207 g_print ("Max basic blocks: %ld\n", mono_jit_stats.max_basic_blocks);
6208 g_print ("Allocated vars: %ld\n", mono_jit_stats.allocate_var);
6209 g_print ("Analyze stack repeat: %ld\n", mono_jit_stats.analyze_stack_repeat);
6210 g_print ("Compiled CIL code size: %ld\n", mono_jit_stats.cil_code_size);
6211 g_print ("Native code size: %ld\n", mono_jit_stats.native_code_size);
6212 g_print ("Max code size ratio: %.2f (%s::%s)\n", mono_jit_stats.max_code_size_ratio/100.0,
6213 mono_jit_stats.max_ratio_method->klass->name, mono_jit_stats.max_ratio_method->name);
6214 g_print ("Biggest method: %ld (%s::%s)\n", mono_jit_stats.biggest_method_size,
6215 mono_jit_stats.biggest_method->klass->name, mono_jit_stats.biggest_method->name);
6216 g_print ("Code reallocs: %ld\n", mono_jit_stats.code_reallocs);
6217 g_print ("Allocated code size: %ld\n", mono_jit_stats.allocated_code_size);
6218 g_print ("Inlineable methods: %ld\n", mono_jit_stats.inlineable_methods);
6219 g_print ("Inlined methods: %ld\n", mono_jit_stats.inlined_methods);
6221 g_print ("\nCreated object count: %ld\n", mono_stats.new_object_count);
6222 g_print ("Initialized classes: %ld\n", mono_stats.initialized_class_count);
6223 g_print ("Used classes: %ld\n", mono_stats.used_class_count);
6224 g_print ("Static data size: %ld\n", mono_stats.class_static_data_size);
6225 g_print ("VTable data size: %ld\n", mono_stats.class_vtable_size);
6230 mini_cleanup (MonoDomain *domain)
6233 * mono_runtime_cleanup() and mono_domain_finalize () need to
6234 * be called early since they need the execution engine still
6235 * fully working (mono_domain_finalize may invoke managed finalizers
6236 * and mono_runtime_cleanup will wait for other threads to finish).
6238 mono_domain_finalize (domain);
6240 mono_runtime_cleanup (domain);
6242 mono_profiler_shutdown ();
6244 mono_debug_cleanup ();
6245 #ifdef PLATFORM_WIN32
6246 win32_seh_cleanup();
6249 mono_domain_unload (domain, TRUE);
6252 DeleteCriticalSection (metadata_section);
6256 mini_set_defaults (int verbose_level, guint32 opts)
6258 mini_verbose = verbose_level;