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 gboolean mono_arch_handle_exception (struct sigcontext *ctx, gpointer obj, gboolean test_only);
49 static gpointer mono_jit_compile_method (MonoMethod *method);
51 static void handle_stobj (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *dest, MonoInst *src,
52 const unsigned char *ip, MonoClass *klass, gboolean to_end, gboolean native);
54 static int mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock,
55 int locals_offset, MonoInst *return_var, GList *dont_inline, MonoInst **inline_args,
56 guint inline_offset, gboolean is_virtual_call);
58 extern guint8 mono_burg_arity [];
59 /* helper methods signature */
60 static MonoMethodSignature *helper_sig_long_long_long = NULL;
61 static MonoMethodSignature *helper_sig_long_long_int = NULL;
62 static MonoMethodSignature *helper_sig_newarr = NULL;
63 static MonoMethodSignature *helper_sig_newarr_specific = NULL;
64 static MonoMethodSignature *helper_sig_ldstr = NULL;
65 static MonoMethodSignature *helper_sig_domain_get = NULL;
66 static MonoMethodSignature *helper_sig_object_new = NULL;
67 static MonoMethodSignature *helper_sig_object_new_specific = NULL;
68 static MonoMethodSignature *helper_sig_compile = NULL;
69 static MonoMethodSignature *helper_sig_compile_virt = NULL;
70 static MonoMethodSignature *helper_sig_obj_ptr = NULL;
71 static MonoMethodSignature *helper_sig_ptr_void = NULL;
72 static MonoMethodSignature *helper_sig_void_ptr = NULL;
73 static MonoMethodSignature *helper_sig_void_obj = NULL;
74 static MonoMethodSignature *helper_sig_void_ptr_ptr = NULL;
75 static MonoMethodSignature *helper_sig_void_ptr_ptr_ptr = NULL;
76 static MonoMethodSignature *helper_sig_ptr_ptr_ptr = NULL;
77 static MonoMethodSignature *helper_sig_ptr_obj = NULL;
78 static MonoMethodSignature *helper_sig_initobj = NULL;
79 static MonoMethodSignature *helper_sig_memcpy = NULL;
80 static MonoMethodSignature *helper_sig_memset = NULL;
81 static MonoMethodSignature *helper_sig_ulong_double = NULL;
82 static MonoMethodSignature *helper_sig_long_double = NULL;
83 static MonoMethodSignature *helper_sig_uint_double = NULL;
84 static MonoMethodSignature *helper_sig_int_double = NULL;
85 static MonoMethodSignature *helper_sig_stelem_ref = NULL;
87 static guint32 default_opt = MONO_OPT_PEEPHOLE;
89 guint32 mono_jit_tls_id = 0;
90 gboolean mono_jit_trace_calls = FALSE;
91 gboolean mono_break_on_exc = FALSE;
92 gboolean mono_compile_aot = FALSE;
93 gboolean mono_trace_coverage = FALSE;
94 gboolean mono_jit_profile = FALSE;
95 MonoDebugFormat mono_debug_format = MONO_DEBUG_FORMAT_NONE;
97 CRITICAL_SECTION *metadata_section = NULL;
99 static int mini_verbose = 0;
101 #ifdef MONO_USE_EXC_TABLES
103 mono_type_blittable (MonoType *type)
122 case MONO_TYPE_OBJECT:
124 case MONO_TYPE_VALUETYPE:
125 case MONO_TYPE_CLASS:
126 return type->data.klass->blittable;
136 mono_method_blittable (MonoMethod *method)
138 MonoMethodSignature *sig;
144 if (!mono_arch_has_unwind_info (method->addr)) {
148 if (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL)
151 sig = method->signature;
153 if (!mono_type_blittable (sig->ret))
156 for (i = 0; i < sig->param_count; i++)
157 if (!mono_type_blittable (sig->params [i]))
166 print_method_from_ip (void *ip)
171 ji = mono_jit_info_table_find (mono_domain_get (), ip);
173 g_print ("No method at %p\n", ip);
176 method = mono_method_full_name (ji->method, TRUE);
177 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);
182 #define MONO_INIT_VARINFO(vi,id) do { \
183 (vi)->range.first_use.pos.bid = 0xffff; \
189 * Basic blocks have two numeric identifiers:
190 * dfn: Depth First Number
191 * block_num: unique ID assigned at bblock creation
193 #define NEW_BBLOCK(cfg) (mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock)))
194 #define ADD_BBLOCK(cfg,bbhash,b) do { \
195 g_hash_table_insert (bbhash, (b)->cil_code, (b)); \
196 (b)->block_num = cfg->num_bblocks++; \
197 (b)->real_offset = real_offset; \
200 #define GET_BBLOCK(cfg,bbhash,tblock,ip) do { \
201 (tblock) = g_hash_table_lookup (bbhash, (ip)); \
203 if ((ip) >= end || (ip) < header->code) goto unverified; \
204 (tblock) = NEW_BBLOCK (cfg); \
205 (tblock)->cil_code = (ip); \
206 ADD_BBLOCK (cfg, (bbhash), (tblock)); \
208 (tblock)->real_offset = real_offset; \
211 #define CHECK_BBLOCK(target,ip,tblock) do { \
212 if ((target) < (ip) && !(tblock)->code) { \
213 bb_recheck = g_list_prepend (bb_recheck, (tblock)); \
214 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); \
218 #define NEW_ICONST(cfg,dest,val) do { \
219 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
220 (dest)->opcode = OP_ICONST; \
221 (dest)->inst_c0 = (val); \
222 (dest)->type = STACK_I4; \
225 /* FIXME: have a different definition of NEW_PCONST for 64 bit systems */
226 #define NEW_PCONST(cfg,dest,val) do { \
227 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
228 (dest)->opcode = OP_ICONST; \
229 (dest)->inst_p0 = (val); \
230 (dest)->type = STACK_PTR; \
233 #define NEW_CLASSCONST(cfg,dest,val) do { \
234 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
235 (dest)->opcode = mono_compile_aot ? OP_AOTCONST : OP_ICONST; \
236 (dest)->inst_p0 = (val); \
237 (dest)->inst_i1 = (gpointer)MONO_PATCH_INFO_CLASS; \
238 (dest)->type = STACK_PTR; \
241 #define NEW_IMAGECONST(cfg,dest,val) do { \
242 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
243 (dest)->opcode = mono_compile_aot ? OP_AOTCONST : OP_ICONST; \
244 (dest)->inst_p0 = (val); \
245 (dest)->inst_i1 = (gpointer)MONO_PATCH_INFO_IMAGE; \
246 (dest)->type = STACK_PTR; \
249 #define NEW_FIELDCONST(cfg,dest,field) do { \
250 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
251 (dest)->opcode = mono_compile_aot ? OP_AOTCONST : OP_ICONST; \
252 (dest)->inst_p0 = (field); \
253 (dest)->inst_i1 = (gpointer)MONO_PATCH_INFO_FIELD; \
254 (dest)->type = STACK_PTR; \
257 #define NEW_METHODCONST(cfg,dest,val) do { \
258 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
259 (dest)->opcode = mono_compile_aot ? OP_AOTCONST : OP_ICONST; \
260 (dest)->inst_p0 = (val); \
261 (dest)->inst_i1 = (gpointer)MONO_PATCH_INFO_METHODCONST; \
262 (dest)->type = STACK_PTR; \
265 #define NEW_DOMAINCONST(cfg,dest) do { \
266 if ((cfg->opt & MONO_OPT_SHARED) || mono_compile_aot) { \
267 NEW_TEMPLOAD (cfg, dest, mono_get_domainvar (cfg)->inst_c0); \
269 NEW_PCONST (cfg, dest, (cfg)->domain); \
273 #define GET_VARINFO_INST(cfg,num) ((cfg)->varinfo [(num)]->inst)
275 #define NEW_ARGLOAD(cfg,dest,num) do { \
276 if (arg_array [(num)]->opcode == OP_ICONST) (dest) = arg_array [(num)]; else { \
277 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
278 (dest)->ssa_op = MONO_SSA_LOAD; \
279 (dest)->inst_i0 = arg_array [(num)]; \
280 (dest)->opcode = mono_type_to_ldind ((dest)->inst_i0->inst_vtype); \
281 type_to_eval_stack_type (param_types [(num)], (dest)); \
282 (dest)->klass = (dest)->inst_i0->klass; \
285 #define NEW_LOCLOAD(cfg,dest,num) do { \
286 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
287 (dest)->ssa_op = MONO_SSA_LOAD; \
288 (dest)->inst_i0 = (cfg)->varinfo [locals_offset + (num)]; \
289 (dest)->opcode = mono_type_to_ldind ((dest)->inst_i0->inst_vtype); \
290 type_to_eval_stack_type (header->locals [(num)], (dest)); \
291 (dest)->klass = (dest)->inst_i0->klass; \
294 #define NEW_LOCLOADA(cfg,dest,num) do { \
295 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
296 (dest)->ssa_op = MONO_SSA_MAYBE_LOAD; \
297 (dest)->inst_i0 = (cfg)->varinfo [locals_offset + (num)]; \
298 (dest)->inst_i0->flags |= MONO_INST_INDIRECT; \
299 (dest)->opcode = OP_LDADDR; \
300 (dest)->type = STACK_MP; \
301 (dest)->klass = (dest)->inst_i0->klass; \
302 (cfg)->disable_ssa = TRUE; \
305 #define NEW_RETLOADA(cfg,dest) do { \
306 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
307 (dest)->ssa_op = MONO_SSA_MAYBE_LOAD; \
308 (dest)->inst_i0 = (cfg)->ret; \
309 (dest)->inst_i0->flags |= MONO_INST_INDIRECT; \
310 (dest)->opcode = CEE_LDIND_I; \
311 (dest)->type = STACK_MP; \
312 (dest)->klass = (dest)->inst_i0->klass; \
313 (cfg)->disable_ssa = TRUE; \
316 #define NEW_ARGLOADA(cfg,dest,num) do { \
317 if (arg_array [(num)]->opcode == OP_ICONST) goto inline_failure; \
318 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
319 (dest)->ssa_op = MONO_SSA_MAYBE_LOAD; \
320 (dest)->inst_i0 = arg_array [(num)]; \
321 (dest)->inst_i0->flags |= MONO_INST_INDIRECT; \
322 (dest)->opcode = OP_LDADDR; \
323 (dest)->type = STACK_MP; \
324 (dest)->klass = (dest)->inst_i0->klass; \
325 (cfg)->disable_ssa = TRUE; \
328 #define NEW_TEMPLOAD(cfg,dest,num) do { \
329 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
330 (dest)->ssa_op = MONO_SSA_LOAD; \
331 (dest)->inst_i0 = (cfg)->varinfo [(num)]; \
332 (dest)->opcode = mono_type_to_ldind ((dest)->inst_i0->inst_vtype); \
333 type_to_eval_stack_type ((dest)->inst_i0->inst_vtype, (dest)); \
334 (dest)->klass = (dest)->inst_i0->klass; \
337 #define NEW_TEMPLOADA(cfg,dest,num) do { \
338 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
339 (dest)->ssa_op = MONO_SSA_MAYBE_LOAD; \
340 (dest)->inst_i0 = (cfg)->varinfo [(num)]; \
341 (dest)->inst_i0->flags |= MONO_INST_INDIRECT; \
342 (dest)->opcode = OP_LDADDR; \
343 (dest)->type = STACK_MP; \
344 (dest)->klass = (dest)->inst_i0->klass; \
345 (cfg)->disable_ssa = TRUE; \
349 #define NEW_INDLOAD(cfg,dest,addr,vtype) do { \
350 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
351 (dest)->inst_left = addr; \
352 (dest)->opcode = mono_type_to_ldind (vtype); \
353 type_to_eval_stack_type (vtype, (dest)); \
354 /* FIXME: (dest)->klass = (dest)->inst_i0->klass;*/ \
357 #define NEW_INDSTORE(cfg,dest,addr,value,vtype) do { \
358 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
359 (dest)->inst_i0 = addr; \
360 (dest)->opcode = mono_type_to_stind (vtype); \
361 (dest)->inst_i1 = (value); \
362 /* FIXME: (dest)->klass = (dest)->inst_i0->klass;*/ \
365 #define NEW_TEMPSTORE(cfg,dest,num,inst) do { \
366 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
367 (dest)->ssa_op = MONO_SSA_STORE; \
368 (dest)->inst_i0 = (cfg)->varinfo [(num)]; \
369 (dest)->opcode = mono_type_to_stind ((dest)->inst_i0->inst_vtype); \
370 (dest)->inst_i1 = (inst); \
371 (dest)->klass = (dest)->inst_i0->klass; \
374 #define NEW_LOCSTORE(cfg,dest,num,inst) do { \
375 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
376 (dest)->opcode = mono_type_to_stind (header->locals [(num)]); \
377 (dest)->ssa_op = MONO_SSA_STORE; \
378 (dest)->inst_i0 = (cfg)->varinfo [locals_offset + (num)]; \
379 (dest)->inst_i1 = (inst); \
380 (dest)->klass = (dest)->inst_i0->klass; \
383 #define NEW_ARGSTORE(cfg,dest,num,inst) do { \
384 if (arg_array [(num)]->opcode == OP_ICONST) goto inline_failure; \
385 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
386 (dest)->opcode = mono_type_to_stind (param_types [(num)]); \
387 (dest)->ssa_op = MONO_SSA_STORE; \
388 (dest)->inst_i0 = arg_array [(num)]; \
389 (dest)->inst_i1 = (inst); \
390 (dest)->klass = (dest)->inst_i0->klass; \
393 #define ADD_BINOP(op) do { \
394 MONO_INST_NEW (cfg, ins, (op)); \
395 ins->cil_code = ip; \
397 ins->inst_i0 = sp [0]; \
398 ins->inst_i1 = sp [1]; \
400 type_from_op (ins); \
404 #define ADD_UNOP(op) do { \
405 MONO_INST_NEW (cfg, ins, (op)); \
406 ins->cil_code = ip; \
408 ins->inst_i0 = sp [0]; \
410 type_from_op (ins); \
414 #define ADD_BINCOND(next_block) do { \
416 MONO_INST_NEW(cfg, cmp, OP_COMPARE); \
418 cmp->inst_i0 = sp [0]; \
419 cmp->inst_i1 = sp [1]; \
420 cmp->cil_code = ins->cil_code; \
421 type_from_op (cmp); \
423 ins->inst_i0 = cmp; \
424 MONO_ADD_INS (bblock, ins); \
425 ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2); \
426 GET_BBLOCK (cfg, bbhash, tblock, target); \
427 link_bblock (cfg, bblock, tblock); \
428 ins->inst_true_bb = tblock; \
429 CHECK_BBLOCK (target, ip, tblock); \
430 if ((next_block)) { \
431 link_bblock (cfg, bblock, (next_block)); \
432 ins->inst_false_bb = (next_block); \
433 start_new_bblock = 1; \
435 GET_BBLOCK (cfg, bbhash, tblock, ip); \
436 link_bblock (cfg, bblock, tblock); \
437 ins->inst_false_bb = tblock; \
438 start_new_bblock = 2; \
442 /* FIXME: handle float, long ... */
443 #define ADD_UNCOND(istrue) do { \
445 MONO_INST_NEW(cfg, cmp, OP_COMPARE); \
447 cmp->inst_i0 = sp [0]; \
448 switch (cmp->inst_i0->type) { \
450 cmp->inst_i1 = zero_int64; break; \
452 cmp->inst_i1 = zero_r8; break; \
455 cmp->inst_i1 = zero_ptr; break; \
457 cmp->inst_i1 = zero_obj; break; \
459 cmp->inst_i1 = zero_int32; \
461 cmp->cil_code = ins->cil_code; \
462 type_from_op (cmp); \
464 ins->inst_i0 = cmp; \
465 ins->opcode = (istrue)? CEE_BNE_UN: CEE_BEQ; \
466 MONO_ADD_INS (bblock, ins); \
467 ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2); \
468 GET_BBLOCK (cfg, bbhash, tblock, target); \
469 link_bblock (cfg, bblock, tblock); \
470 ins->inst_true_bb = tblock; \
471 CHECK_BBLOCK (target, ip, tblock); \
472 GET_BBLOCK (cfg, bbhash, tblock, ip); \
473 link_bblock (cfg, bblock, tblock); \
474 ins->inst_false_bb = tblock; \
475 start_new_bblock = 2; \
478 #define NEW_LDELEMA(cfg,dest,sp,k) do { \
479 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
480 (dest)->opcode = CEE_LDELEMA; \
481 (dest)->inst_left = (sp) [0]; \
482 (dest)->inst_right = (sp) [1]; \
483 (dest)->type = STACK_MP; \
484 (dest)->klass = (k); \
487 #define NEW_GROUP(cfg,dest,el1,el2) do { \
488 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
489 (dest)->opcode = OP_GROUP; \
490 (dest)->inst_left = (el1); \
491 (dest)->inst_right = (el2); \
494 static GHashTable *coverage_hash = NULL;
497 mono_allocate_coverage_info (MonoMethod *method, int size)
499 MonoCoverageInfo *res;
502 coverage_hash = g_hash_table_new (NULL, NULL);
504 res = g_malloc0 (sizeof (MonoCoverageInfo) + sizeof (int) * size * 2);
508 g_hash_table_insert (coverage_hash, method, res);
514 mono_get_coverage_info (MonoMethod *method)
519 return g_hash_table_lookup (coverage_hash, method);
524 compare_bblock (gconstpointer a, gconstpointer b)
526 const MonoBasicBlock *b1 = a;
527 const MonoBasicBlock *b2 = b;
529 return b2->cil_code - b1->cil_code;
534 * link_bblock: Links two basic blocks
536 * links two basic blocks in the control flow graph, the 'from'
537 * argument is the starting block and the 'to' argument is the block
538 * the control flow ends to after 'from'.
541 link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
543 MonoBasicBlock **newa;
547 if (from->cil_code) {
549 g_print ("edge from IL%04x to IL_%04x\n", from->cil_code - cfg->cil_code, to->cil_code - cfg->cil_code);
551 g_print ("edge from IL%04x to exit\n", from->cil_code - cfg->cil_code);
554 g_print ("edge from entry to IL_%04x\n", to->cil_code - cfg->cil_code);
556 g_print ("edge from entry to exit\n");
560 for (i = 0; i < from->out_count; ++i) {
561 if (to == from->out_bb [i]) {
567 newa = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (from->out_count + 1));
568 for (i = 0; i < from->out_count; ++i) {
569 newa [i] = from->out_bb [i];
577 for (i = 0; i < to->in_count; ++i) {
578 if (from == to->in_bb [i]) {
584 newa = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (to->in_count + 1));
585 for (i = 0; i < to->in_count; ++i) {
586 newa [i] = to->in_bb [i];
595 * We mark each basic block with a region ID. We use that to avoid BB
596 * optimizations when blocks are in different regions.
599 mono_find_block_region (MonoCompile *cfg, int offset, int *filter_lengths)
601 MonoMethod *method = cfg->method;
602 MonoMethodHeader *header = ((MonoMethodNormal *)method)->header;
603 MonoExceptionClause *clause;
606 /* first search for handlers and filters */
607 for (i = 0; i < header->num_clauses; ++i) {
608 clause = &header->clauses [i];
609 if ((clause->flags & MONO_EXCEPTION_CLAUSE_FILTER) && (offset >= clause->token_or_filter) &&
610 (offset < (clause->token_or_filter + filter_lengths [i])))
611 return (i << 8) | 128 | clause->flags;
613 if (MONO_OFFSET_IN_HANDLER (clause, offset)) {
614 return (i << 8) | 64 | clause->flags;
618 /* search the try blocks */
619 for (i = 0; i < header->num_clauses; ++i) {
620 clause = &header->clauses [i];
621 if (MONO_OFFSET_IN_CLAUSE (clause, offset))
622 return (i << 8) | clause->flags;
629 mono_find_final_block (MonoCompile *cfg, unsigned char *ip, unsigned char *target, int type)
631 MonoMethod *method = cfg->method;
632 MonoMethodHeader *header = ((MonoMethodNormal *)method)->header;
633 MonoExceptionClause *clause;
634 MonoBasicBlock *handler;
638 for (i = 0; i < header->num_clauses; ++i) {
639 clause = &header->clauses [i];
640 if (MONO_OFFSET_IN_CLAUSE (clause, (ip - header->code)) &&
641 (!MONO_OFFSET_IN_CLAUSE (clause, (target - header->code)))) {
642 if (clause->flags == type) {
643 handler = g_hash_table_lookup (cfg->bb_hash, header->code + clause->handler_offset);
645 res = g_list_append (res, handler);
654 df_visit (MonoBasicBlock *start, int *dfn, MonoBasicBlock **array)
658 array [*dfn] = start;
659 /*g_print ("visit %d at %p\n", *dfn, start->cil_code);*/
660 for (i = 0; i < start->out_count; ++i) {
661 if (start->out_bb [i]->dfn)
664 start->out_bb [i]->dfn = *dfn;
665 start->out_bb [i]->df_parent = start;
666 array [*dfn] = start->out_bb [i];
667 df_visit (start->out_bb [i], dfn, array);
673 MonoBasicBlock *best;
677 previous_foreach (gconstpointer key, gpointer val, gpointer data)
679 PrevStruct *p = data;
680 MonoBasicBlock *bb = val;
681 //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,
682 //bb->method == p->best->method, bb->cil_code < p->code, bb->cil_code > p->best->cil_code);
684 if (bb->cil_code && bb->cil_code < p->code && bb->cil_code > p->best->cil_code)
688 static MonoBasicBlock*
689 find_previous (GHashTable *bb_hash, MonoBasicBlock *start, const guchar *code) {
695 g_hash_table_foreach (bb_hash, (GHFunc)previous_foreach, &p);
700 split_bblock (MonoCompile *cfg, MonoBasicBlock *first, MonoBasicBlock *second) {
709 * FIXME: take into account all the details:
710 * second may have been the target of more than one bblock
712 second->out_count = first->out_count;
713 second->out_bb = first->out_bb;
715 for (i = 0; i < first->out_count; ++i) {
716 bb = first->out_bb [i];
717 for (j = 0; j < bb->in_count; ++j) {
718 if (bb->in_bb [j] == first)
719 bb->in_bb [j] = second;
723 first->out_count = 0;
724 first->out_bb = NULL;
725 link_bblock (cfg, first, second);
727 second->last_ins = first->last_ins;
729 /*g_print ("start search at %p for %p\n", first->cil_code, second->cil_code);*/
730 for (inst = first->code; inst && inst->next; inst = inst->next) {
731 /*char *code = mono_disasm_code_one (NULL, cfg->method, inst->next->cil_code, NULL);
732 g_print ("found %p: %s", inst->next->cil_code, code);
734 if (inst->cil_code < second->cil_code && inst->next->cil_code >= second->cil_code) {
735 second->code = inst->next;
737 first->last_ins = inst;
738 second->next_bb = first->next_bb;
739 first->next_bb = second;
744 g_warning ("bblock split failed in %s::%s\n", cfg->method->klass->name, cfg->method->name);
750 mono_type_to_ldind (MonoType *type)
762 case MONO_TYPE_BOOLEAN:
776 case MONO_TYPE_FNPTR:
778 case MONO_TYPE_CLASS:
779 case MONO_TYPE_STRING:
780 case MONO_TYPE_OBJECT:
781 case MONO_TYPE_SZARRAY:
782 case MONO_TYPE_ARRAY:
783 return CEE_LDIND_REF;
791 case MONO_TYPE_VALUETYPE:
792 if (type->data.klass->enumtype) {
793 t = type->data.klass->enum_basetype->type;
798 g_error ("unknown type 0x%02x in type_to_ldind", type->type);
804 mono_type_to_stind (MonoType *type)
815 case MONO_TYPE_BOOLEAN:
827 case MONO_TYPE_FNPTR:
829 case MONO_TYPE_CLASS:
830 case MONO_TYPE_STRING:
831 case MONO_TYPE_OBJECT:
832 case MONO_TYPE_SZARRAY:
833 case MONO_TYPE_ARRAY:
834 return CEE_STIND_REF;
842 case MONO_TYPE_VALUETYPE:
843 if (type->data.klass->enumtype) {
844 t = type->data.klass->enum_basetype->type;
850 g_error ("unknown type %02x in type_to_stind", type->type);
856 * Returns the type used in the eval stack when @type is loaded.
857 * FIXME: return a MonoType/MonoClass for the byref and VALUETYPE cases.
860 type_to_eval_stack_type (MonoType *type, MonoInst *inst) {
864 inst->type = STACK_MP;
872 case MONO_TYPE_BOOLEAN:
878 inst->type = STACK_I4;
883 case MONO_TYPE_FNPTR:
884 inst->type = STACK_PTR;
886 case MONO_TYPE_CLASS:
887 case MONO_TYPE_STRING:
888 case MONO_TYPE_OBJECT:
889 case MONO_TYPE_SZARRAY:
890 case MONO_TYPE_ARRAY:
891 inst->type = STACK_OBJ;
895 inst->type = STACK_I8;
899 inst->type = STACK_R8;
901 case MONO_TYPE_VALUETYPE:
902 if (type->data.klass->enumtype) {
903 t = type->data.klass->enum_basetype->type;
906 inst->klass = type->data.klass;
907 inst->type = STACK_VTYPE;
911 g_error ("unknown type 0x%02x in eval stack type", type->type);
916 * The following tables are used to quickly validate the IL code in type_from_op ().
919 bin_num_table [STACK_MAX] [STACK_MAX] = {
920 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
921 {STACK_INV, STACK_I4, STACK_INV, STACK_PTR, STACK_INV, STACK_MP, STACK_INV, STACK_INV},
922 {STACK_INV, STACK_INV, STACK_I8, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
923 {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_MP, STACK_INV, STACK_INV},
924 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_R8, STACK_INV, STACK_INV, STACK_INV},
925 {STACK_INV, STACK_MP, STACK_INV, STACK_MP, STACK_INV, STACK_PTR, STACK_INV, STACK_INV},
926 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
927 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
932 STACK_INV, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_INV, STACK_INV, STACK_INV
935 /* reduce the size of this table */
937 bin_int_table [STACK_MAX] [STACK_MAX] = {
938 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
939 {STACK_INV, STACK_I4, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
940 {STACK_INV, STACK_INV, STACK_I8, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
941 {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, 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},
943 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
944 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
945 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
949 bin_comp_table [STACK_MAX] [STACK_MAX] = {
951 {0, 1, 0, 1, 0, 0, 4, 0},
952 {0, 0, 1, 0, 0, 0, 0, 0},
953 {0, 1, 0, 1, 0, 2, 4, 0},
954 {0, 0, 0, 0, 1, 0, 0, 0},
955 {0, 0, 0, 2, 0, 1, 0, 0},
956 {0, 4, 0, 4, 0, 0, 3, 0},
957 {0, 0, 0, 0, 0, 0, 0, 0},
960 /* reduce the size of this table */
962 shift_table [STACK_MAX] [STACK_MAX] = {
963 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
964 {STACK_INV, STACK_I4, STACK_INV, STACK_I4, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
965 {STACK_INV, STACK_I8, STACK_INV, STACK_I8, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
966 {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, 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},
968 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
969 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
970 {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
974 * Tables to map from the non-specific opcode to the matching
975 * type-specific opcode.
977 /* handles from CEE_ADD to CEE_SHR_UN (CEE_REM_UN for floats) */
979 binops_op_map [STACK_MAX] = {
980 0, 0, OP_LADD-CEE_ADD, OP_PADD-CEE_ADD, OP_FADD-CEE_ADD, 0
983 /* handles from CEE_NEG to CEE_CONV_U8 */
985 unops_op_map [STACK_MAX] = {
986 0, 0, OP_LNEG-CEE_NEG, OP_PNEG-CEE_NEG, OP_FNEG-CEE_NEG, 0
989 /* handles from CEE_CONV_U2 to CEE_SUB_OVF_UN */
991 ovfops_op_map [STACK_MAX] = {
992 0, 0, OP_LCONV_TO_U2-CEE_CONV_U2, OP_PCONV_TO_U2-CEE_CONV_U2, OP_FCONV_TO_U2-CEE_CONV_U2, 0
995 /* handles from CEE_CONV_OVF_I1_UN to CEE_CONV_OVF_U_UN */
997 ovf2ops_op_map [STACK_MAX] = {
998 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
1001 /* handles from CEE_CONV_OVF_I1 to CEE_CONV_OVF_U8 */
1002 static const guint16
1003 ovf3ops_op_map [STACK_MAX] = {
1004 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
1007 /* handles from CEE_CEQ to CEE_CLT_UN */
1008 static const guint16
1009 ceqops_op_map [STACK_MAX] = {
1010 0, 0, OP_LCEQ-CEE_CEQ, OP_PCEQ-CEE_CEQ, OP_FCEQ-CEE_CEQ, 0
1014 * Sets ins->type (the type on the eval stack) according to the
1015 * type of the opcode and the arguments to it.
1016 * Invalid IL code is marked by setting ins->type to the invalid value STACK_INV.
1018 * FIXME: this function sets ins->type unconditionally in some cases, but
1019 * it should set it to invalid for some types (a conv.x on an object)
1022 type_from_op (MonoInst *ins) {
1023 switch (ins->opcode) {
1030 /* FIXME: check unverifiable args for STACK_MP */
1031 ins->type = bin_num_table [ins->inst_i0->type] [ins->inst_i1->type];
1032 ins->opcode += binops_op_map [ins->type];
1039 ins->type = bin_int_table [ins->inst_i0->type] [ins->inst_i1->type];
1040 ins->opcode += binops_op_map [ins->type];
1045 ins->type = shift_table [ins->inst_i0->type] [ins->inst_i1->type];
1046 ins->opcode += binops_op_map [ins->type];
1049 /* FIXME: handle some specifics with ins->next->type */
1050 ins->type = bin_comp_table [ins->inst_i0->type] [ins->inst_i1->type] ? STACK_I4: STACK_INV;
1054 case 256+CEE_CGT_UN:
1056 case 256+CEE_CLT_UN:
1057 ins->type = bin_comp_table [ins->inst_i0->type] [ins->inst_i1->type] ? STACK_I4: STACK_INV;
1058 ins->opcode += ceqops_op_map [ins->inst_i0->type];
1062 ins->type = neg_table [ins->inst_i0->type];
1063 ins->opcode += unops_op_map [ins->type];
1066 if (ins->inst_i0->type >= STACK_I4 && ins->inst_i0->type <= STACK_PTR)
1067 ins->type = ins->inst_i0->type;
1069 ins->type = STACK_INV;
1070 ins->opcode += unops_op_map [ins->type];
1076 ins->type = STACK_I4;
1077 ins->opcode += unops_op_map [ins->inst_i0->type];
1080 ins->type = STACK_R8;
1081 switch (ins->inst_i0->type) {
1086 ins->opcode = OP_LCONV_TO_R_UN;
1090 case CEE_CONV_OVF_I1:
1091 case CEE_CONV_OVF_U1:
1092 case CEE_CONV_OVF_I2:
1093 case CEE_CONV_OVF_U2:
1094 case CEE_CONV_OVF_I4:
1095 case CEE_CONV_OVF_U4:
1096 ins->type = STACK_I4;
1097 ins->opcode += ovf3ops_op_map [ins->inst_i0->type];
1099 case CEE_CONV_OVF_I_UN:
1100 case CEE_CONV_OVF_U_UN:
1101 ins->type = STACK_PTR;
1102 ins->opcode += ovf2ops_op_map [ins->inst_i0->type];
1104 case CEE_CONV_OVF_I1_UN:
1105 case CEE_CONV_OVF_I2_UN:
1106 case CEE_CONV_OVF_I4_UN:
1107 case CEE_CONV_OVF_U1_UN:
1108 case CEE_CONV_OVF_U2_UN:
1109 case CEE_CONV_OVF_U4_UN:
1110 ins->type = STACK_I4;
1111 ins->opcode += ovf2ops_op_map [ins->inst_i0->type];
1114 ins->type = STACK_PTR;
1115 switch (ins->inst_i0->type) {
1121 ins->opcode = OP_LCONV_TO_U;
1124 ins->opcode = OP_FCONV_TO_U;
1130 ins->type = STACK_I8;
1131 ins->opcode += unops_op_map [ins->inst_i0->type];
1133 case CEE_CONV_OVF_I8:
1134 case CEE_CONV_OVF_U8:
1135 ins->type = STACK_I8;
1136 ins->opcode += ovf3ops_op_map [ins->inst_i0->type];
1138 case CEE_CONV_OVF_U8_UN:
1139 case CEE_CONV_OVF_I8_UN:
1140 ins->type = STACK_I8;
1141 ins->opcode += ovf2ops_op_map [ins->inst_i0->type];
1145 ins->type = STACK_R8;
1146 ins->opcode += unops_op_map [ins->inst_i0->type];
1149 ins->type = STACK_R8;
1153 ins->type = STACK_I4;
1154 ins->opcode += ovfops_op_map [ins->inst_i0->type];
1157 case CEE_CONV_OVF_I:
1158 case CEE_CONV_OVF_U:
1159 ins->type = STACK_PTR;
1160 ins->opcode += ovfops_op_map [ins->inst_i0->type];
1163 case CEE_ADD_OVF_UN:
1165 case CEE_MUL_OVF_UN:
1167 case CEE_SUB_OVF_UN:
1168 ins->type = bin_num_table [ins->inst_i0->type] [ins->inst_i1->type];
1169 ins->opcode += ovfops_op_map [ins->inst_i0->type];
1172 g_error ("opcode 0x%04x not handled in type from op", ins->opcode);
1179 STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I8, STACK_MP, STACK_R8, STACK_R8, STACK_OBJ
1182 /* map ldelem.x to the matching ldind.x opcode */
1184 ldelem_to_ldind [] = {
1198 /* map stelem.x to the matching stind.x opcode */
1200 stelem_to_stind [] = {
1214 param_table [STACK_MAX] [STACK_MAX] = {
1219 check_values_to_signature (MonoInst *args, MonoType *this, MonoMethodSignature *sig) {
1223 switch (args->type) {
1233 for (i = 0; i < sig->param_count; ++i) {
1234 switch (args [i].type) {
1238 if (!sig->params [i]->byref)
1242 if (sig->params [i]->byref)
1244 switch (sig->params [i]->type) {
1245 case MONO_TYPE_CLASS:
1246 case MONO_TYPE_STRING:
1247 case MONO_TYPE_OBJECT:
1248 case MONO_TYPE_SZARRAY:
1249 case MONO_TYPE_ARRAY:
1256 if (sig->params [i]->byref)
1258 if (sig->params [i]->type != MONO_TYPE_R4 && sig->params [i]->type != MONO_TYPE_R8)
1267 /*if (!param_table [args [i].type] [sig->params [i]->type])
1275 * When we need a pointer to the current domain many times in a method, we
1276 * call mono_domain_get() once and we store the result in a local variable.
1277 * This function returns the variable that represents the MonoDomain*.
1279 inline static MonoInst *
1280 mono_get_domainvar (MonoCompile *cfg)
1282 if (!cfg->domainvar)
1283 cfg->domainvar = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1284 return cfg->domainvar;
1288 mono_compile_create_var (MonoCompile *cfg, MonoType *type, int opcode)
1291 int num = cfg->num_varinfo;
1293 if ((num + 1) >= cfg->varinfo_count) {
1294 cfg->varinfo_count = (cfg->varinfo_count + 2) * 2;
1295 cfg->varinfo = (MonoInst **)g_realloc (cfg->varinfo, sizeof (MonoInst*) * cfg->varinfo_count);
1296 cfg->vars = (MonoMethodVar **)g_realloc (cfg->vars, sizeof (MonoMethodVar*) * cfg->varinfo_count);
1299 mono_jit_stats.allocate_var++;
1301 MONO_INST_NEW (cfg, inst, opcode);
1302 inst->inst_c0 = num;
1303 inst->inst_vtype = type;
1304 inst->klass = mono_class_from_mono_type (type);
1305 /* if set to 1 the variable is native */
1308 cfg->varinfo [num] = inst;
1310 cfg->vars [num] = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoMethodVar));
1311 MONO_INIT_VARINFO (cfg->vars [num], num);
1314 //g_print ("created temp %d of type %s\n", num, mono_type_get_name (type));
1319 type_from_stack_type (MonoInst *ins) {
1320 switch (ins->type) {
1321 case STACK_I4: return &mono_defaults.int32_class->byval_arg;
1322 case STACK_I8: return &mono_defaults.int64_class->byval_arg;
1323 case STACK_PTR: return &mono_defaults.int_class->byval_arg;
1324 case STACK_R8: return &mono_defaults.double_class->byval_arg;
1325 case STACK_MP: return &mono_defaults.int_class->byval_arg;
1326 case STACK_OBJ: return &mono_defaults.object_class->byval_arg;
1327 case STACK_VTYPE: return &ins->klass->byval_arg;
1329 g_error ("stack type %d to montype not handled\n", ins->type);
1335 array_access_to_klass (int opcode)
1339 return mono_defaults.byte_class;
1341 return mono_defaults.uint16_class;
1344 return mono_defaults.int_class;
1347 return mono_defaults.sbyte_class;
1350 return mono_defaults.int16_class;
1353 return mono_defaults.int32_class;
1355 return mono_defaults.uint32_class;
1358 return mono_defaults.int64_class;
1361 return mono_defaults.single_class;
1364 return mono_defaults.double_class;
1365 case CEE_LDELEM_REF:
1366 case CEE_STELEM_REF:
1367 return mono_defaults.object_class;
1369 g_assert_not_reached ();
1375 mono_add_ins_to_end (MonoBasicBlock *bb, MonoInst *inst)
1379 MONO_ADD_INS (bb, inst);
1382 switch (bb->last_ins->opcode) {
1395 while (prev->next && prev->next != bb->last_ins)
1397 if (prev == bb->code) {
1398 if (bb->last_ins == bb->code) {
1399 inst->next = bb->code;
1402 inst->next = prev->next;
1406 inst->next = bb->last_ins;
1410 // g_warning ("handle conditional jump in add_ins_to_end ()\n");
1412 MONO_ADD_INS (bb, inst);
1418 mono_add_varcopy_to_end (MonoCompile *cfg, MonoBasicBlock *bb, int src, int dest)
1420 MonoInst *inst, *load;
1422 NEW_TEMPLOAD (cfg, load, src);
1424 NEW_TEMPSTORE (cfg, inst, dest, load);
1425 if (inst->opcode == CEE_STOBJ) {
1426 NEW_TEMPLOADA (cfg, inst, dest);
1427 handle_stobj (cfg, bb, inst, load, NULL, inst->klass, TRUE, FALSE);
1429 inst->cil_code = NULL;
1430 mono_add_ins_to_end (bb, inst);
1435 * This function is called to handle items that are left on the evaluation stack
1436 * at basic block boundaries. What happens is that we save the values to local variables
1437 * and we reload them later when first entering the target basic block (with the
1438 * handle_loaded_temps () function).
1439 * A single joint point will use the same variables (stored in the array bb->out_stack or
1440 * bb->in_stack, if the basic block is before or after the joint point).
1443 handle_stack_args (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst **sp, int count) {
1445 MonoBasicBlock *outb;
1446 MonoInst *inst, **locals;
1450 if (cfg->verbose_level > 3)
1451 g_print ("%d item(s) on exit from B%d\n", count, bb->block_num);
1452 if (!bb->out_scount) {
1454 bb->out_scount = count;
1455 //g_print ("bblock %d has out:", bb->block_num);
1456 for (i = 0; i < bb->out_count; ++i) {
1457 outb = bb->out_bb [i];
1458 //g_print (" %d", outb->block_num);
1459 if (outb->in_stack) {
1461 bb->out_stack = outb->in_stack;
1467 bb->out_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * count);
1468 for (i = 0; i < count; ++i) {
1470 * dietmar suggests that we can reuse temps already allocated
1471 * for this purpouse, if they occupy the same stack slot and if
1472 * they are of the same type.
1474 bb->out_stack [i] = mono_compile_create_var (cfg, type_from_stack_type (sp [i]), OP_LOCAL);
1478 locals = bb->out_stack;
1479 for (i = 0; i < count; ++i) {
1480 /* add store ops at the end of the bb, before the branch */
1481 NEW_TEMPSTORE (cfg, inst, locals [i]->inst_c0, sp [i]);
1482 if (inst->opcode == CEE_STOBJ) {
1483 NEW_TEMPLOADA (cfg, inst, locals [i]->inst_c0);
1484 handle_stobj (cfg, bb, inst, sp [i], sp [i]->cil_code, inst->klass, TRUE, FALSE);
1486 inst->cil_code = sp [i]->cil_code;
1487 mono_add_ins_to_end (bb, inst);
1489 if (cfg->verbose_level > 3)
1490 g_print ("storing %d to temp %d\n", i, locals [i]->inst_c0);
1493 for (i = 0; i < bb->out_count; ++i) {
1494 outb = bb->out_bb [i];
1495 if (outb->in_scount)
1496 continue; /* check they are the same locals */
1497 outb->in_scount = count;
1498 outb->in_stack = locals;
1504 ret_type_to_call_opcode (MonoType *type, int calli, int virt)
1509 return calli? OP_CALL_REG: virt? CEE_CALLVIRT: CEE_CALL;
1513 case MONO_TYPE_VOID:
1514 return calli? OP_VOIDCALL_REG: virt? OP_VOIDCALLVIRT: OP_VOIDCALL;
1517 case MONO_TYPE_BOOLEAN:
1520 case MONO_TYPE_CHAR:
1523 return calli? OP_CALL_REG: virt? CEE_CALLVIRT: CEE_CALL;
1527 return calli? OP_CALL_REG: virt? CEE_CALLVIRT: CEE_CALL;
1528 case MONO_TYPE_CLASS:
1529 case MONO_TYPE_STRING:
1530 case MONO_TYPE_OBJECT:
1531 case MONO_TYPE_SZARRAY:
1532 case MONO_TYPE_ARRAY:
1533 return calli? OP_CALL_REG: virt? CEE_CALLVIRT: CEE_CALL;
1536 return calli? OP_LCALL_REG: virt? OP_LCALLVIRT: OP_LCALL;
1539 return calli? OP_FCALL_REG: virt? OP_FCALLVIRT: OP_FCALL;
1540 case MONO_TYPE_VALUETYPE:
1541 if (type->data.klass->enumtype) {
1542 t = type->data.klass->enum_basetype->type;
1545 return calli? OP_VCALL_REG: virt? OP_VCALLVIRT: OP_VCALL;
1547 g_error ("unknown type %02x in ret_type_to_call_opcode", type->type);
1553 mono_create_jump_table (MonoCompile *cfg, MonoInst *label, MonoBasicBlock **bbs, int num_blocks)
1555 MonoJumpInfo *ji = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfo));
1557 ji->ip.label = label;
1558 ji->type = MONO_PATCH_INFO_SWITCH;
1559 ji->data.table = bbs;
1560 ji->next = cfg->patch_info;
1561 ji->table_size = num_blocks;
1562 cfg->patch_info = ji;
1566 * When we add a tree of instructions, we need to ensure the instructions currently
1567 * on the stack are executed before (like, if we load a value from a local).
1568 * We ensure this by saving the currently loaded values to temps and rewriting the
1569 * instructions to load the values.
1570 * This is not done for opcodes that terminate a basic block (because it's handled already
1571 * by handle_stack_args ()) and for opcodes that can't change values, like POP.
1574 handle_loaded_temps (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst **stack, MonoInst **sp)
1576 MonoInst *load, *store, *temp, *ins;
1578 while (stack < sp) {
1580 /* handle also other constants */
1581 if (ins->opcode != OP_ICONST) {
1582 temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1583 NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
1584 store->cil_code = ins->cil_code;
1585 if (store->opcode == CEE_STOBJ) {
1586 NEW_TEMPLOADA (cfg, store, temp->inst_c0);
1587 handle_stobj (cfg, bblock, store, ins, ins->cil_code, temp->klass, FALSE, FALSE);
1589 MONO_ADD_INS (bblock, store);
1590 NEW_TEMPLOAD (cfg, load, temp->inst_c0);
1591 load->cil_code = ins->cil_code;
1599 mono_spill_call (MonoCompile *cfg, MonoBasicBlock *bblock, MonoCallInst *call, MonoMethodSignature *sig, gboolean ret_object,
1600 const guint8 *ip, gboolean to_end)
1602 MonoInst *temp, *store, *ins = (MonoInst*)call;
1603 MonoType *ret = sig->ret;
1605 if (!MONO_TYPE_IS_VOID (ret) || ret_object) {
1607 call->inst.type = STACK_OBJ;
1608 call->inst.opcode = CEE_CALL;
1609 temp = mono_compile_create_var (cfg, &mono_defaults.string_class->byval_arg, OP_LOCAL);
1611 type_to_eval_stack_type (ret, ins);
1612 temp = mono_compile_create_var (cfg, ret, OP_LOCAL);
1615 if (MONO_TYPE_ISSTRUCT (ret)) {
1618 /* we use this to allocate native sized structs */
1619 temp->unused = sig->pinvoke;
1621 NEW_TEMPLOADA (cfg, loada, temp->inst_c0);
1622 if (call->inst.opcode == OP_VCALL)
1623 ins->inst_left = loada;
1625 ins->inst_right = loada; /* a virtual or indirect call */
1628 mono_add_ins_to_end (bblock, ins);
1630 MONO_ADD_INS (bblock, ins);
1632 NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
1633 store->cil_code = ip;
1635 mono_add_ins_to_end (bblock, store);
1637 MONO_ADD_INS (bblock, store);
1639 return temp->inst_c0;
1642 mono_add_ins_to_end (bblock, ins);
1644 MONO_ADD_INS (bblock, ins);
1649 inline static MonoCallInst *
1650 mono_emit_call_args (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethodSignature *sig,
1651 MonoInst **args, int calli, int virtual, const guint8 *ip, gboolean to_end)
1656 MONO_INST_NEW_CALL (cfg, call, ret_type_to_call_opcode (sig->ret, calli, virtual));
1658 call->inst.cil_code = ip;
1660 call->signature = sig;
1661 call = mono_arch_call_opcode (cfg, bblock, call, virtual);
1663 for (i = 0; i < (sig->param_count + sig->hasthis); ++i) {
1664 if (call->args [i]) {
1666 mono_add_ins_to_end (bblock, call->args [i]);
1668 MONO_ADD_INS (bblock, call->args [i]);
1675 mono_emit_calli (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethodSignature *sig,
1676 MonoInst **args, MonoInst *addr, const guint8 *ip)
1678 MonoCallInst *call = mono_emit_call_args (cfg, bblock, sig, args, TRUE, FALSE, ip, FALSE);
1680 call->inst.inst_i0 = addr;
1682 return mono_spill_call (cfg, bblock, call, sig, FALSE, ip, FALSE);
1685 static MonoCallInst*
1686 mono_emit_method_call (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *method, MonoMethodSignature *sig,
1687 MonoInst **args, const guint8 *ip, MonoInst *this)
1689 gboolean virtual = this != NULL;
1692 call = mono_emit_call_args (cfg, bblock, sig, args, FALSE, virtual, ip, FALSE);
1694 if (this && sig->hasthis &&
1695 (method->klass->marshalbyref || method->klass == mono_defaults.object_class) &&
1696 !(method->flags & METHOD_ATTRIBUTE_VIRTUAL) && !MONO_CHECK_THIS (this)) {
1697 call->method = mono_marshal_get_remoting_invoke_with_check (method);
1699 call->method = method;
1701 call->inst.flags |= MONO_INST_HAS_METHOD;
1702 call->inst.inst_left = this;
1708 mono_emit_method_call_spilled (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *method,
1709 MonoInst **args, const guint8 *ip, MonoInst *this)
1711 MonoCallInst *call = mono_emit_method_call (cfg, bblock, method, method->signature, args, ip, this);
1713 return mono_spill_call (cfg, bblock, call, method->signature, method->string_ctor, ip, FALSE);
1717 mono_emit_native_call (MonoCompile *cfg, MonoBasicBlock *bblock, gconstpointer func, MonoMethodSignature *sig,
1718 MonoInst **args, const guint8 *ip, gboolean to_end)
1724 call = mono_emit_call_args (cfg, bblock, sig, args, FALSE, FALSE, ip, to_end);
1726 return mono_spill_call (cfg, bblock, call, sig, func == mono_array_new_va, ip, to_end);
1730 mono_emit_jit_icall (MonoCompile *cfg, MonoBasicBlock *bblock, gconstpointer func, MonoInst **args, const guint8 *ip)
1732 MonoJitICallInfo *info = mono_find_jit_icall_by_addr (func);
1735 g_warning ("unregistered JIT ICall");
1736 g_assert_not_reached ();
1739 return mono_emit_native_call (cfg, bblock, info->wrapper, info->sig, args, ip, FALSE);
1743 mono_emulate_opcode (MonoCompile *cfg, MonoInst *tree, MonoInst **iargs, MonoJitICallInfo *info)
1745 MonoInst *ins, *temp = NULL, *store, *load;
1749 /*g_print ("emulating: ");
1750 mono_print_tree (tree);
1752 MONO_INST_NEW_CALL (cfg, call, ret_type_to_call_opcode (info->sig->ret, FALSE, FALSE));
1753 ins = (MonoInst*)call;
1755 call->inst.cil_code = tree->cil_code;
1757 call->signature = info->sig;
1759 call = mono_arch_call_opcode (cfg, cfg->cbb, call, FALSE);
1761 if (!MONO_TYPE_IS_VOID (info->sig->ret)) {
1762 temp = mono_compile_create_var (cfg, info->sig->ret, OP_LOCAL);
1763 NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
1764 store->cil_code = tree->cil_code;
1769 nargs = info->sig->param_count + info->sig->hasthis;
1771 for (i = 1; i < nargs; i++) {
1772 call->args [i - 1]->next = call->args [i];
1776 call->args [nargs - 1]->next = store;
1778 if (cfg->prev_ins) {
1779 store->next = cfg->prev_ins->next;
1781 cfg->prev_ins->next = call->args [0];
1783 cfg->prev_ins->next = store;
1785 store->next = cfg->cbb->code;
1787 cfg->cbb->code = call->args [0];
1789 cfg->cbb->code = store;
1793 call->fptr = info->wrapper;
1795 if (!MONO_TYPE_IS_VOID (info->sig->ret)) {
1796 NEW_TEMPLOAD (cfg, load, temp->inst_c0);
1801 static MonoMethodSignature *
1802 mono_get_element_address_signature (int arity)
1804 static GHashTable *sighash = NULL;
1805 MonoMethodSignature *res;
1809 sighash = g_hash_table_new (NULL, NULL);
1812 if ((res = g_hash_table_lookup (sighash, (gpointer)arity)))
1815 res = mono_metadata_signature_alloc (mono_defaults.corlib, arity + 1);
1817 res->params [0] = &mono_defaults.array_class->byval_arg;
1819 for (i = 1; i <= arity; i++)
1820 res->params [i] = &mono_defaults.int_class->byval_arg;
1822 res->ret = &mono_defaults.int_class->byval_arg;
1824 g_hash_table_insert (sighash, (gpointer)arity, res);
1830 handle_stobj (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *dest, MonoInst *src, const unsigned char *ip, MonoClass *klass, gboolean to_end, gboolean native) {
1831 MonoInst *iargs [3];
1836 * This check breaks with spilled vars... need to handle it during verification anyway.
1837 * g_assert (klass && klass == src->klass && klass == dest->klass);
1841 n = mono_class_native_size (klass, NULL);
1843 n = mono_class_value_size (klass, NULL);
1847 NEW_ICONST (cfg, iargs [2], n);
1849 mono_emit_native_call (cfg, bblock, helper_memcpy, helper_sig_memcpy, iargs, ip, to_end);
1853 handle_initobj (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *dest, const guchar *ip, MonoClass *klass, MonoInst **stack_start, MonoInst **sp)
1855 MonoInst *iargs [2];
1856 MonoInst *ins, *zero_int32;
1859 NEW_ICONST (cfg, zero_int32, 0);
1861 mono_class_init (klass);
1862 n = mono_class_value_size (klass, NULL);
1863 MONO_INST_NEW (cfg, ins, 0);
1865 ins->inst_left = dest;
1866 ins->inst_right = zero_int32;
1869 ins->opcode = CEE_STIND_I1;
1870 MONO_ADD_INS (bblock, ins);
1873 ins->opcode = CEE_STIND_I2;
1874 MONO_ADD_INS (bblock, ins);
1877 ins->opcode = CEE_STIND_I4;
1878 MONO_ADD_INS (bblock, ins);
1881 handle_loaded_temps (cfg, bblock, stack_start, sp);
1882 NEW_ICONST (cfg, ins, n);
1885 mono_emit_jit_icall (cfg, bblock, helper_initobj, iargs, ip);
1890 #define CODE_IS_STLOC(ip) (((ip) [0] >= CEE_STLOC_0 && (ip) [0] <= CEE_STLOC_3) || ((ip) [0] == CEE_STLOC_S))
1893 mono_method_check_inlining (MonoMethod *method)
1895 MonoMethodHeader *header = ((MonoMethodNormal *)method)->header;
1896 MonoMethodSignature *signature = method->signature;
1899 /* fixme: we should inline wrappers */
1900 if (method->wrapper_type != MONO_WRAPPER_NONE)
1903 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
1904 (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
1905 (method->iflags & METHOD_IMPL_ATTRIBUTE_NOINLINING) ||
1906 (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) ||
1907 (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
1908 (method->klass->marshalbyref) ||
1909 !header || header->num_clauses ||
1910 /* fixme: why cant we inline valuetype returns? */
1911 MONO_TYPE_ISSTRUCT (signature->ret))
1914 /* its not worth to inline methods with valuetype arguments?? */
1915 for (i = 0; i < signature->param_count; i++) {
1916 if (MONO_TYPE_ISSTRUCT (signature->params [i])) {
1921 //if (!MONO_TYPE_IS_VOID (signature->ret)) return FALSE;
1923 /* also consider num_locals? */
1924 if (header->code_size < 20)
1931 mini_get_opcode_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
1936 if (cmethod->klass == mono_defaults.string_class) {
1937 if (cmethod->name [0] != 'g' || strcmp (cmethod->name, "get_Chars"))
1940 } else if (cmethod->klass == mono_defaults.math_class) {
1941 if (strcmp (cmethod->name, "Sin") == 0)
1943 else if (strcmp (cmethod->name, "Cos") == 0)
1945 else if (strcmp (cmethod->name, "Tan") == 0)
1947 else if (strcmp (cmethod->name, "Atan") == 0)
1949 else if (strcmp (cmethod->name, "Sqrt") == 0)
1951 else if (strcmp (cmethod->name, "Abs") == 0 && fsig->params [0]->type == MONO_TYPE_R8)
1958 pc = fsig->param_count + fsig->hasthis;
1959 MONO_INST_NEW (cfg, ins, op);
1962 ins->inst_i0 = args [0];
1964 ins->inst_i1 = args [1];
1971 mono_save_args (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethodSignature *sig, MonoInst **sp, MonoInst **args)
1973 MonoInst *store, *temp;
1976 g_assert (!MONO_TYPE_ISSTRUCT (sig->ret));
1978 if (!sig->hasthis && sig->param_count == 0)
1982 if (sp [0]->opcode == OP_ICONST) {
1985 temp = mono_compile_create_var (cfg, type_from_stack_type (*sp), OP_LOCAL);
1987 NEW_TEMPSTORE (cfg, store, temp->inst_c0, *sp);
1988 store->cil_code = sp [0]->cil_code;
1989 MONO_ADD_INS (bblock, store);
1994 for (i = 0; i < sig->param_count; ++i) {
1995 if (sp [0]->opcode == OP_ICONST) {
1998 temp = mono_compile_create_var (cfg, sig->params [i], OP_LOCAL);
2000 NEW_TEMPSTORE (cfg, store, temp->inst_c0, *sp);
2001 store->cil_code = sp [0]->cil_code;
2002 if (store->opcode == CEE_STOBJ) {
2003 NEW_TEMPLOADA (cfg, store, temp->inst_c0);
2004 handle_stobj (cfg, bblock, store, *sp, sp [0]->cil_code, temp->klass, FALSE, FALSE);
2006 MONO_ADD_INS (bblock, store);
2014 inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoBasicBlock *bblock, MonoInst **sp,
2015 guchar *ip, guint real_offset, GList *dont_inline, MonoBasicBlock **last_b)
2017 MonoInst *ins, *rvar = NULL;
2018 MonoMethodHeader *cheader;
2019 MonoBasicBlock *ebblock, *sbblock;
2020 int i, costs, new_locals_offset;
2022 if (cfg->verbose_level > 2)
2023 g_print ("INLINE START %p %s\n", cmethod, mono_method_full_name (cmethod, TRUE));
2025 cheader = ((MonoMethodNormal *)cmethod)->header;
2027 if (!cmethod->inline_info) {
2028 mono_jit_stats.inlineable_methods++;
2029 cmethod->inline_info = 1;
2031 /* allocate space to store the return value */
2032 if (!MONO_TYPE_IS_VOID (fsig->ret))
2033 rvar = mono_compile_create_var (cfg, fsig->ret, OP_LOCAL);
2035 /* allocate local variables */
2036 new_locals_offset = cfg->num_varinfo;
2037 for (i = 0; i < cheader->num_locals; ++i)
2038 mono_compile_create_var (cfg, cheader->locals [i], OP_LOCAL);
2040 /* allocate starte and end blocks */
2041 sbblock = NEW_BBLOCK (cfg);
2042 sbblock->block_num = cfg->num_bblocks++;
2043 sbblock->real_offset = real_offset;
2045 ebblock = NEW_BBLOCK (cfg);
2046 ebblock->block_num = cfg->num_bblocks++;
2047 ebblock->real_offset = real_offset;
2049 costs = mono_method_to_ir (cfg, cmethod, sbblock, ebblock, new_locals_offset, rvar, dont_inline, sp, real_offset, *ip == CEE_CALLVIRT);
2051 if (costs >= 0 && costs < 60) {
2052 if (cfg->verbose_level > 2)
2053 g_print ("INLINE END %s\n", mono_method_full_name (cmethod, TRUE));
2055 mono_jit_stats.inlined_methods++;
2057 /* always add some code to avoid block split failures */
2058 MONO_INST_NEW (cfg, ins, CEE_NOP);
2059 MONO_ADD_INS (bblock, ins);
2062 bblock->next_bb = sbblock;
2063 link_bblock (cfg, bblock, sbblock);
2066 NEW_TEMPLOAD (cfg, ins, rvar->inst_c0);
2072 if (cfg->verbose_level > 2)
2073 g_print ("INLINE ABORTED %s\n", mono_method_full_name (cmethod, TRUE));
2079 * Some of these comments may well be out-of-date.
2080 * Design decisions: we do a single pass over the IL code (and we do bblock
2081 * splitting/merging in the few cases when it's required: a back jump to an IL
2082 * address that was not already seen as bblock starting point).
2083 * Code is validated as we go (full verification is still better left to metadata/verify.c).
2084 * Complex operations are decomposed in simpler ones right away. We need to let the
2085 * arch-specific code peek and poke inside this process somehow (except when the
2086 * optimizations can take advantage of the full semantic info of coarse opcodes).
2087 * All the opcodes of the form opcode.s are 'normalized' to opcode.
2088 * MonoInst->opcode initially is the IL opcode or some simplification of that
2089 * (OP_LOAD, OP_STORE). The arch-specific code may rearrange it to an arch-specific
2090 * opcode with value bigger than OP_LAST.
2091 * At this point the IR can be handed over to an interpreter, a dumb code generator
2092 * or to the optimizing code generator that will translate it to SSA form.
2094 * Profiling directed optimizations.
2095 * We may compile by default with few or no optimizations and instrument the code
2096 * or the user may indicate what methods to optimize the most either in a config file
2097 * or through repeated runs where the compiler applies offline the optimizations to
2098 * each method and then decides if it was worth it.
2101 * * consider using an array instead of an hash table (bb_hash)
2104 #define CHECK_TYPE(ins) if (!(ins)->type) goto unverified
2105 #define CHECK_STACK(num) if ((sp - stack_start) < (num)) goto unverified
2106 #define CHECK_STACK_OVF(num) if (((sp - stack_start) + (num)) > header->max_stack) goto unverified
2108 /* offset from br.s -> br like opcodes */
2109 #define BIG_BRANCH_OFFSET 13
2112 * mono_method_to_ir: translates IL into basic blocks containing trees
2115 mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock,
2116 int locals_offset, MonoInst *return_var, GList *dont_inline, MonoInst **inline_args,
2117 guint inline_offset, gboolean is_virtual_call)
2119 MonoInst *zero_int32, *zero_int64, *zero_ptr, *zero_obj, *zero_r8;
2120 MonoInst *ins, **sp, **stack_start;
2121 MonoBasicBlock *bblock, *tblock = NULL, *init_localsbb = NULL;
2123 MonoMethod *cmethod;
2124 MonoInst **arg_array;
2125 MonoMethodHeader *header;
2127 guint32 token, ins_flag;
2129 unsigned char *ip, *end, *target;
2130 static double r8_0 = 0.0;
2131 MonoMethodSignature *sig;
2132 MonoType **param_types;
2133 GList *bb_recheck = NULL, *tmp;
2134 int i, n, start_new_bblock, align;
2135 int num_calls = 0, inline_costs = 0;
2136 int *filter_lengths = NULL;
2137 int breakpoint_id = 0;
2140 image = method->klass->image;
2141 header = ((MonoMethodNormal *)method)->header;
2142 sig = method->signature;
2143 ip = (unsigned char*)header->code;
2144 end = ip + header->code_size;
2145 mono_jit_stats.cil_code_size += header->code_size;
2147 if (cfg->method == method) {
2149 bbhash = cfg->bb_hash;
2151 real_offset = inline_offset;
2152 bbhash = g_hash_table_new (g_direct_hash, NULL);
2155 dont_inline = g_list_prepend (dont_inline, method);
2156 if (cfg->method == method) {
2159 cfg->bb_entry = start_bblock = NEW_BBLOCK (cfg);
2160 start_bblock->cil_code = NULL;
2161 start_bblock->cil_length = 0;
2162 start_bblock->block_num = cfg->num_bblocks++;
2165 cfg->bb_exit = end_bblock = NEW_BBLOCK (cfg);
2166 end_bblock->cil_code = NULL;
2167 end_bblock->cil_length = 0;
2168 end_bblock->block_num = cfg->num_bblocks++;
2169 g_assert (cfg->num_bblocks == 2);
2171 arg_array = alloca (sizeof (MonoInst *) * (sig->hasthis + sig->param_count));
2172 for (i = sig->hasthis + sig->param_count - 1; i >= 0; i--)
2173 arg_array [i] = cfg->varinfo [i];
2175 if (mono_compile_aot)
2176 cfg->opt |= MONO_OPT_SHARED;
2178 if (header->num_clauses) {
2179 int size = sizeof (int) * header->num_clauses;
2180 filter_lengths = alloca (size);
2181 memset (filter_lengths, 0, size);
2183 /* handle exception clauses */
2184 for (i = 0; i < header->num_clauses; ++i) {
2185 //unsigned char *p = ip;
2186 MonoExceptionClause *clause = &header->clauses [i];
2187 GET_BBLOCK (cfg, bbhash, tblock, ip + clause->try_offset);
2188 tblock->real_offset = clause->try_offset;
2189 GET_BBLOCK (cfg, bbhash, tblock, ip + clause->handler_offset);
2190 tblock->real_offset = clause->handler_offset;
2191 /*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);
2193 g_print ("%s", mono_disasm_code_one (NULL, method, p, &p));
2195 /* catch and filter blocks get the exception object on the stack */
2196 if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE ||
2197 clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
2198 /* mostly like handle_stack_args (), but just sets the input args */
2199 /* g_print ("handling clause at IL_%04x\n", clause->handler_offset); */
2201 cfg->exvar = mono_compile_create_var (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL);
2202 /* prevent it from being register allocated */
2203 cfg->exvar->flags |= MONO_INST_INDIRECT;
2205 tblock->in_scount = 1;
2206 tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
2207 tblock->in_stack [0] = cfg->exvar;
2208 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
2209 GET_BBLOCK (cfg, bbhash, tblock, ip + clause->token_or_filter);
2210 tblock->real_offset = clause->token_or_filter;
2211 tblock->in_scount = 1;
2212 tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
2213 tblock->in_stack [0] = cfg->exvar;
2219 arg_array = alloca (sizeof (MonoInst *) * (sig->hasthis + sig->param_count));
2220 mono_save_args (cfg, start_bblock, sig, inline_args, arg_array);
2223 /* FIRST CODE BLOCK */
2224 bblock = NEW_BBLOCK (cfg);
2225 bblock->cil_code = ip;
2227 ADD_BBLOCK (cfg, bbhash, bblock);
2229 if (cfg->method == method) {
2230 breakpoint_id = mono_debugger_method_has_breakpoint (method);
2231 if (breakpoint_id && (mono_debug_format != MONO_DEBUG_FORMAT_DEBUGGER)) {
2232 MONO_INST_NEW (cfg, ins, CEE_BREAK);
2233 MONO_ADD_INS (bblock, ins);
2237 if ((header->init_locals || (cfg->method == method && (cfg->opt & MONO_OPT_SHARED)))) {
2238 /* we use a separate basic block for the initialization code */
2239 cfg->bb_init = init_localsbb = NEW_BBLOCK (cfg);
2240 init_localsbb->real_offset = real_offset;
2241 start_bblock->next_bb = init_localsbb;
2242 init_localsbb->next_bb = bblock;
2243 link_bblock (cfg, start_bblock, init_localsbb);
2244 link_bblock (cfg, init_localsbb, bblock);
2245 init_localsbb->block_num = cfg->num_bblocks++;
2247 start_bblock->next_bb = bblock;
2248 link_bblock (cfg, start_bblock, bblock);
2251 mono_debug_init_method (cfg, bblock, breakpoint_id);
2253 param_types = mono_mempool_alloc (cfg->mempool, sizeof (MonoType*) * (sig->hasthis + sig->param_count));
2255 param_types [0] = method->klass->valuetype?&method->klass->this_arg:&method->klass->byval_arg;
2256 for (n = 0; n < sig->param_count; ++n)
2257 param_types [n + sig->hasthis] = sig->params [n];
2259 /* do this somewhere outside - not here */
2260 NEW_ICONST (cfg, zero_int32, 0);
2261 NEW_ICONST (cfg, zero_int64, 0);
2262 zero_int64->type = STACK_I8;
2263 NEW_PCONST (cfg, zero_ptr, 0);
2264 NEW_PCONST (cfg, zero_obj, 0);
2265 zero_obj->type = STACK_OBJ;
2267 MONO_INST_NEW (cfg, zero_r8, OP_R8CONST);
2268 zero_r8->type = STACK_R8;
2269 zero_r8->inst_p0 = &r8_0;
2271 /* add a check for this != NULL to inlined methods */
2272 if (is_virtual_call) {
2273 MONO_INST_NEW (cfg, ins, OP_CHECK_THIS);
2274 NEW_ARGLOAD (cfg, ins->inst_left, 0);
2276 MONO_ADD_INS (bblock, ins);
2279 /* we use a spare stack slot in SWITCH and NEWOBJ and others */
2280 stack_start = sp = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * (header->max_stack + 1));
2283 start_new_bblock = 0;
2286 if (cfg->method == method)
2287 real_offset = ip - header->code;
2289 real_offset = inline_offset;
2291 if (start_new_bblock) {
2292 bblock->cil_length = ip - bblock->cil_code;
2293 if (start_new_bblock == 2) {
2294 g_assert (ip == tblock->cil_code);
2296 GET_BBLOCK (cfg, bbhash, tblock, ip);
2298 bblock->next_bb = tblock;
2300 start_new_bblock = 0;
2301 for (i = 0; i < bblock->in_scount; ++i) {
2302 NEW_TEMPLOAD (cfg, ins, bblock->in_stack [i]->inst_c0);
2306 if ((tblock = g_hash_table_lookup (bbhash, ip)) && (tblock != bblock)) {
2307 link_bblock (cfg, bblock, tblock);
2308 if (sp != stack_start) {
2309 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
2312 bblock->next_bb = tblock;
2314 for (i = 0; i < bblock->in_scount; ++i) {
2315 NEW_TEMPLOAD (cfg, ins, bblock->in_stack [i]->inst_c0);
2321 if (cfg->verbose_level > 3)
2322 g_print ("converting (in B%d: stack: %d) %s", bblock->block_num, sp-stack_start, mono_disasm_code_one (NULL, method, ip, NULL));
2329 MONO_INST_NEW (cfg, ins, CEE_BREAK);
2330 ins->cil_code = ip++;
2331 MONO_ADD_INS (bblock, ins);
2337 CHECK_STACK_OVF (1);
2338 n = (*ip)-CEE_LDARG_0;
2339 NEW_ARGLOAD (cfg, ins, n);
2340 ins->cil_code = ip++;
2347 CHECK_STACK_OVF (1);
2348 n = (*ip)-CEE_LDLOC_0;
2349 NEW_LOCLOAD (cfg, ins, n);
2350 ins->cil_code = ip++;
2358 n = (*ip)-CEE_STLOC_0;
2360 handle_loaded_temps (cfg, bblock, stack_start, sp);
2361 NEW_LOCSTORE (cfg, ins, n, *sp);
2363 if (ins->opcode == CEE_STOBJ) {
2364 NEW_LOCLOADA (cfg, ins, n);
2365 handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE);
2367 MONO_ADD_INS (bblock, ins);
2372 CHECK_STACK_OVF (1);
2373 NEW_ARGLOAD (cfg, ins, ip [1]);
2379 CHECK_STACK_OVF (1);
2380 NEW_ARGLOADA (cfg, ins, ip [1]);
2388 NEW_ARGSTORE (cfg, ins, ip [1], *sp);
2389 handle_loaded_temps (cfg, bblock, stack_start, sp);
2391 if (ins->opcode == CEE_STOBJ) {
2392 NEW_ARGLOADA (cfg, ins, ip [1]);
2393 handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE);
2395 MONO_ADD_INS (bblock, ins);
2399 CHECK_STACK_OVF (1);
2400 NEW_LOCLOAD (cfg, ins, ip [1]);
2406 CHECK_STACK_OVF (1);
2407 NEW_LOCLOADA (cfg, ins, ip [1]);
2415 handle_loaded_temps (cfg, bblock, stack_start, sp);
2416 NEW_LOCSTORE (cfg, ins, ip [1], *sp);
2418 if (ins->opcode == CEE_STOBJ) {
2419 NEW_LOCLOADA (cfg, ins, ip [1]);
2420 handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE);
2422 MONO_ADD_INS (bblock, ins);
2427 CHECK_STACK_OVF (1);
2428 NEW_PCONST (cfg, ins, NULL);
2430 ins->type = STACK_OBJ;
2435 CHECK_STACK_OVF (1);
2436 NEW_ICONST (cfg, ins, -1);
2450 CHECK_STACK_OVF (1);
2451 NEW_ICONST (cfg, ins, (*ip) - CEE_LDC_I4_0);
2457 CHECK_STACK_OVF (1);
2459 NEW_ICONST (cfg, ins, *((signed char*)ip));
2465 CHECK_STACK_OVF (1);
2466 NEW_ICONST (cfg, ins, (gint32)read32 (ip + 1));
2472 CHECK_STACK_OVF (1);
2473 MONO_INST_NEW (cfg, ins, OP_I8CONST);
2475 ins->type = STACK_I8;
2477 ins->inst_l = (gint64)read64 (ip);
2482 float *f = g_malloc (sizeof (float));
2483 CHECK_STACK_OVF (1);
2484 MONO_INST_NEW (cfg, ins, OP_R4CONST);
2485 ins->type = STACK_R8;
2494 double *d = g_malloc (sizeof (double));
2495 CHECK_STACK_OVF (1);
2496 MONO_INST_NEW (cfg, ins, OP_R8CONST);
2497 ins->type = STACK_R8;
2506 MonoInst *temp, *store;
2508 CHECK_STACK_OVF (1);
2513 * small optimization: if the loaded value was from a local already,
2514 * just load it twice.
2516 if (ins->ssa_op == MONO_SSA_LOAD &&
2517 (ins->inst_i0->opcode == OP_LOCAL || ins->inst_i0->opcode == OP_ARG)) {
2519 MONO_INST_NEW (cfg, temp, 0);
2521 temp->cil_code = ip;
2524 temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
2525 temp->cil_code = ip;
2526 NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
2527 store->cil_code = ip;
2528 MONO_ADD_INS (bblock, store);
2529 NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
2532 NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
2542 MONO_INST_NEW (cfg, ins, CEE_POP);
2543 MONO_ADD_INS (bblock, ins);
2544 ins->cil_code = ip++;
2549 if (stack_start != sp)
2551 MONO_INST_NEW (cfg, ins, CEE_JMP);
2552 token = read32 (ip + 1);
2553 /* FIXME: check the signature matches */
2554 cmethod = mono_get_method (image, token, NULL);
2556 * The current magic trampoline can't handle this
2557 * apparently, so we compile the method right away.
2558 * Later, we may need to fix the trampoline or use a different one.
2560 ins->inst_p0 = mono_compile_method (cmethod);
2561 MONO_ADD_INS (bblock, ins);
2563 start_new_bblock = 1;
2567 case CEE_CALLVIRT: {
2568 MonoInst *addr = NULL;
2569 MonoMethodSignature *fsig = NULL;
2570 int temp, array_rank = 0;
2571 int virtual = *ip == CEE_CALLVIRT;
2573 token = read32 (ip + 1);
2575 if (*ip == CEE_CALLI) {
2580 if (method->wrapper_type != MONO_WRAPPER_NONE)
2581 fsig = (MonoMethodSignature *)mono_method_get_wrapper_data (method, token);
2583 fsig = mono_metadata_parse_signature (image, token);
2585 n = fsig->param_count + fsig->hasthis;
2588 cmethod = mono_get_method (image, token, NULL);
2590 if (!cmethod->klass->inited)
2591 mono_class_init (cmethod->klass);
2593 if (cmethod->signature->pinvoke) {
2594 #ifdef MONO_USE_EXC_TABLES
2595 if (mono_method_blittable (cmethod)) {
2596 fsig = cmethod->signature;
2599 MonoMethod *wrapper = mono_marshal_get_native_wrapper (cmethod);
2600 fsig = wrapper->signature;
2601 #ifdef MONO_USE_EXC_TABLES
2605 fsig = cmethod->signature;
2608 n = fsig->param_count + fsig->hasthis;
2610 if (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL &&
2611 cmethod->klass->parent == mono_defaults.array_class) {
2612 array_rank = cmethod->klass->rank;
2615 if (cmethod->string_ctor)
2616 g_assert_not_reached ();
2622 //g_assert (!virtual || fsig->hasthis);
2626 if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_get_opcode_for_method (cfg, cmethod, fsig, sp))) {
2629 if (MONO_TYPE_IS_VOID (fsig->ret)) {
2630 MONO_ADD_INS (bblock, ins);
2632 type_to_eval_stack_type (fsig->ret, ins);
2641 if ((cfg->opt & MONO_OPT_INLINE) && cmethod &&
2642 (!virtual || !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) || (cmethod->flags & METHOD_ATTRIBUTE_FINAL)) &&
2643 mono_method_check_inlining (cmethod) &&
2644 !g_list_find (dont_inline, cmethod)) {
2646 MonoBasicBlock *ebblock;
2648 if ((costs = inline_method (cfg, cmethod, fsig, bblock, sp, ip, real_offset, dont_inline, &ebblock))) {
2652 GET_BBLOCK (cfg, bbhash, bblock, ip);
2653 ebblock->next_bb = bblock;
2654 link_bblock (cfg, ebblock, bblock);
2655 if (!MONO_TYPE_IS_VOID (fsig->ret))
2658 if (sp != stack_start) {
2659 handle_stack_args (cfg, ebblock, stack_start, sp - stack_start);
2662 start_new_bblock = 1;
2664 inline_costs += costs;
2669 inline_costs += 10 * num_calls++;
2670 handle_loaded_temps (cfg, bblock, stack_start, sp);
2672 /* tail recursion elimination */
2673 if ((cfg->opt & MONO_OPT_TAILC) && *ip == CEE_CALL && cmethod == cfg->method && ip [5] == CEE_RET) {
2674 gboolean has_vtargs = FALSE;
2677 /* keep it simple */
2678 for (i = fsig->param_count - 1; i >= 0; i--) {
2679 if (MONO_TYPE_ISSTRUCT (cmethod->signature->params [i]))
2684 for (i = 0; i < n; ++i) {
2685 NEW_ARGSTORE (cfg, ins, i, sp [i]);
2687 MONO_ADD_INS (bblock, ins);
2689 MONO_INST_NEW (cfg, ins, CEE_BR);
2691 MONO_ADD_INS (bblock, ins);
2692 tblock = start_bblock->out_bb [0];
2693 link_bblock (cfg, bblock, tblock);
2694 ins->inst_target_bb = tblock;
2695 start_new_bblock = 1;
2698 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
2699 /* just create a dummy - the value is never used */
2700 ins = mono_compile_create_var (cfg, fsig->ret, OP_LOCAL);
2701 NEW_TEMPLOAD (cfg, *sp, ins->inst_c0);
2709 if (*ip == CEE_CALLI) {
2711 if ((temp = mono_emit_calli (cfg, bblock, fsig, sp, addr, ip)) != -1) {
2712 NEW_TEMPLOAD (cfg, *sp, temp);
2716 } else if (array_rank) {
2717 MonoMethodSignature *esig;
2720 if (strcmp (cmethod->name, "Set") == 0) { /* array Set */
2721 esig = mono_get_element_address_signature (fsig->param_count - 1);
2723 temp = mono_emit_native_call (cfg, bblock, ves_array_element_address, esig, sp, ip, FALSE);
2724 NEW_TEMPLOAD (cfg, addr, temp);
2725 NEW_INDSTORE (cfg, ins, addr, sp [fsig->param_count], fsig->params [fsig->param_count - 1]);
2727 if (ins->opcode == CEE_STOBJ) {
2728 handle_stobj (cfg, bblock, addr, sp [fsig->param_count], ip, mono_class_from_mono_type (fsig->params [fsig->param_count-1]), FALSE, FALSE);
2730 MONO_ADD_INS (bblock, ins);
2733 } else if (strcmp (cmethod->name, "Get") == 0) { /* array Get */
2734 esig = mono_get_element_address_signature (fsig->param_count);
2736 temp = mono_emit_native_call (cfg, bblock, ves_array_element_address, esig, sp, ip, FALSE);
2737 NEW_TEMPLOAD (cfg, addr, temp);
2738 NEW_INDLOAD (cfg, ins, addr, fsig->ret);
2742 } else if (strcmp (cmethod->name, "Address") == 0) { /* array Address */
2744 esig = mono_get_element_address_signature (fsig->param_count);
2746 temp = mono_emit_native_call (cfg, bblock, ves_array_element_address, esig, sp, ip, FALSE);
2747 NEW_TEMPLOAD (cfg, *sp, temp);
2750 g_assert_not_reached ();
2754 if (0 && CODE_IS_STLOC (ip + 5) && (!MONO_TYPE_ISSTRUCT (fsig->ret)) && (!MONO_TYPE_IS_VOID (fsig->ret) || cmethod->string_ctor)) {
2755 /* no need to spill */
2756 ins = (MonoInst*)mono_emit_method_call (cfg, bblock, cmethod, fsig, sp, ip, virtual ? sp [0] : NULL);
2759 if ((temp = mono_emit_method_call_spilled (cfg, bblock, cmethod, sp, ip, virtual ? sp [0] : NULL)) != -1) {
2760 NEW_TEMPLOAD (cfg, *sp, temp);
2770 if (cfg->method != method) {
2771 /* return from inlined methode */
2776 //g_assert (returnvar != -1);
2777 NEW_TEMPSTORE (cfg, store, return_var->inst_c0, *sp);
2778 store->cil_code = sp [0]->cil_code;
2779 if (store->opcode == CEE_STOBJ) {
2780 g_assert_not_reached ();
2781 NEW_TEMPLOADA (cfg, store, return_var->inst_c0);
2782 handle_stobj (cfg, bblock, store, *sp, sp [0]->cil_code, return_var->klass, FALSE, FALSE);
2784 MONO_ADD_INS (bblock, store);
2788 g_assert (!return_var);
2791 MONO_INST_NEW (cfg, ins, CEE_NOP);
2792 ins->opcode = mono_type_to_stind (method->signature->ret);
2793 if (ins->opcode == CEE_STOBJ) {
2794 NEW_RETLOADA (cfg, ins);
2795 handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE);
2797 ins->opcode = OP_SETRET;
2799 ins->inst_i0 = *sp;;
2800 ins->inst_i1 = NULL;
2801 MONO_ADD_INS (bblock, ins);
2805 if (sp != stack_start)
2807 MONO_INST_NEW (cfg, ins, CEE_BR);
2808 ins->cil_code = ip++;
2809 ins->inst_target_bb = end_bblock;
2810 MONO_ADD_INS (bblock, ins);
2811 link_bblock (cfg, bblock, end_bblock);
2812 start_new_bblock = 1;
2815 MONO_INST_NEW (cfg, ins, CEE_BR);
2816 ins->cil_code = ip++;
2817 MONO_ADD_INS (bblock, ins);
2818 target = ip + 1 + (signed char)(*ip);
2820 GET_BBLOCK (cfg, bbhash, tblock, target);
2821 link_bblock (cfg, bblock, tblock);
2822 CHECK_BBLOCK (target, ip, tblock);
2823 ins->inst_target_bb = tblock;
2824 if (sp != stack_start) {
2825 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
2828 start_new_bblock = 1;
2834 MONO_INST_NEW (cfg, ins, *ip + BIG_BRANCH_OFFSET);
2835 ins->cil_code = ip++;
2836 target = ip + 1 + *(signed char*)ip;
2838 ADD_UNCOND (ins->opcode == CEE_BRTRUE);
2839 if (sp != stack_start) {
2840 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
2856 MONO_INST_NEW (cfg, ins, *ip + BIG_BRANCH_OFFSET);
2857 ins->cil_code = ip++;
2858 target = ip + 1 + *(signed char*)ip;
2861 if (sp != stack_start) {
2862 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
2868 MONO_INST_NEW (cfg, ins, CEE_BR);
2869 ins->cil_code = ip++;
2870 MONO_ADD_INS (bblock, ins);
2871 target = ip + 4 + (gint32)read32(ip);
2873 GET_BBLOCK (cfg, bbhash, tblock, target);
2874 link_bblock (cfg, bblock, tblock);
2875 CHECK_BBLOCK (target, ip, tblock);
2876 ins->inst_target_bb = tblock;
2877 if (sp != stack_start) {
2878 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
2881 start_new_bblock = 1;
2887 MONO_INST_NEW (cfg, ins, *ip);
2888 ins->cil_code = ip++;
2889 target = ip + 4 + (gint32)read32(ip);
2891 ADD_UNCOND(ins->opcode == CEE_BRTRUE);
2892 if (sp != stack_start) {
2893 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
2909 MONO_INST_NEW (cfg, ins, *ip);
2910 ins->cil_code = ip++;
2911 target = ip + 4 + (gint32)read32(ip);
2914 if (sp != stack_start) {
2915 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
2922 n = read32 (ip + 1);
2923 MONO_INST_NEW (cfg, ins, *ip);
2925 ins->inst_left = *sp;
2926 if (ins->inst_left->type != STACK_I4) goto unverified;
2929 target = ip + n * sizeof (guint32);
2930 MONO_ADD_INS (bblock, ins);
2931 GET_BBLOCK (cfg, bbhash, tblock, target);
2932 link_bblock (cfg, bblock, tblock);
2933 ins->klass = GUINT_TO_POINTER (n);
2934 ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * (n + 1));
2935 ins->inst_many_bb [n] = tblock;
2937 for (i = 0; i < n; ++i) {
2938 GET_BBLOCK (cfg, bbhash, tblock, target + (gint32)read32(ip));
2939 link_bblock (cfg, bblock, tblock);
2940 ins->inst_many_bb [i] = tblock;
2943 /* FIXME: handle stack args */
2958 MONO_INST_NEW (cfg, ins, *ip);
2963 ins->type = ldind_type [*ip - CEE_LDIND_I1];
2964 ins->flags |= ins_flag;
2976 MONO_INST_NEW (cfg, ins, *ip);
2977 ins->cil_code = ip++;
2979 handle_loaded_temps (cfg, bblock, stack_start, sp);
2980 MONO_ADD_INS (bblock, ins);
2981 ins->inst_i0 = sp [0];
2982 ins->inst_i1 = sp [1];
2983 ins->flags |= ins_flag;
3014 case CEE_CONV_OVF_I8:
3015 case CEE_CONV_OVF_U8:
3021 case CEE_CONV_OVF_I4:
3022 case CEE_CONV_OVF_I1:
3023 case CEE_CONV_OVF_I2:
3024 case CEE_CONV_OVF_I:
3025 case CEE_CONV_OVF_U:
3028 if (sp [-1]->type == STACK_R8) {
3029 ADD_UNOP (CEE_CONV_OVF_I8);
3037 case CEE_CONV_OVF_U1:
3038 case CEE_CONV_OVF_U2:
3039 case CEE_CONV_OVF_U4:
3042 if (sp [-1]->type == STACK_R8) {
3043 ADD_UNOP (CEE_CONV_OVF_U8);
3051 case CEE_CONV_OVF_I1_UN:
3052 case CEE_CONV_OVF_I2_UN:
3053 case CEE_CONV_OVF_I4_UN:
3054 case CEE_CONV_OVF_I8_UN:
3055 case CEE_CONV_OVF_U1_UN:
3056 case CEE_CONV_OVF_U2_UN:
3057 case CEE_CONV_OVF_U4_UN:
3058 case CEE_CONV_OVF_U8_UN:
3059 case CEE_CONV_OVF_I_UN:
3060 case CEE_CONV_OVF_U_UN:
3066 g_error ("opcode 0x%02x not handled", *ip);
3069 MonoInst *iargs [3];
3072 token = read32 (ip + 1);
3073 if (method->wrapper_type != MONO_WRAPPER_NONE)
3074 klass = mono_method_get_wrapper_data (method, token);
3076 klass = mono_class_get (image, token);
3078 mono_class_init (klass);
3079 n = mono_class_value_size (klass, NULL);
3080 ins = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
3081 NEW_TEMPLOADA (cfg, iargs [0], ins->inst_c0);
3083 NEW_ICONST (cfg, iargs [2], n);
3084 iargs [2]->cil_code = ip;
3086 mono_emit_jit_icall (cfg, bblock, helper_memcpy, iargs, ip);
3087 NEW_TEMPLOAD (cfg, *sp, ins->inst_c0);
3094 CHECK_STACK_OVF (1);
3095 n = read32 (ip + 1);
3097 if (mono_compile_aot) {
3098 cfg->ldstr_list = g_list_prepend (cfg->ldstr_list, (gpointer)n);
3101 if ((cfg->opt & MONO_OPT_SHARED) || mono_compile_aot) {
3103 MonoInst *iargs [3];
3104 NEW_TEMPLOAD (cfg, iargs [0], mono_get_domainvar (cfg)->inst_c0);
3105 NEW_IMAGECONST (cfg, iargs [1], image);
3106 NEW_ICONST (cfg, iargs [2], mono_metadata_token_index (n));
3107 temp = mono_emit_jit_icall (cfg, bblock, mono_ldstr, iargs, ip);
3108 NEW_TEMPLOAD (cfg, *sp, temp);
3109 mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
3111 NEW_PCONST (cfg, ins, NULL);
3113 ins->type = STACK_OBJ;
3114 ins->inst_p0 = mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
3121 MonoInst *iargs [2];
3124 token = read32 (ip + 1);
3125 if (method->wrapper_type != MONO_WRAPPER_NONE) {
3126 cmethod = mono_method_get_wrapper_data (method, token);
3128 cmethod = mono_get_method (image, token, NULL);
3130 mono_class_init (cmethod->klass);
3132 n = cmethod->signature->param_count;
3135 /* move the args to allow room for 'this' in the first position */
3141 handle_loaded_temps (cfg, bblock, stack_start, sp);
3144 if (cmethod->klass->parent == mono_defaults.array_class) {
3145 NEW_METHODCONST (cfg, *sp, cmethod);
3146 temp = mono_emit_native_call (cfg, bblock, mono_array_new_va, cmethod->signature, sp, ip, FALSE);
3148 } else if (cmethod->string_ctor) {
3149 /* we simply pass a null pointer */
3150 NEW_PCONST (cfg, *sp, NULL);
3151 /* now call the string ctor */
3152 temp = mono_emit_method_call_spilled (cfg, bblock, cmethod, sp, ip, NULL);
3154 if (cmethod->klass->valuetype) {
3155 iargs [0] = mono_compile_create_var (cfg, &cmethod->klass->byval_arg, OP_LOCAL);
3156 temp = iargs [0]->inst_c0;
3157 NEW_TEMPLOADA (cfg, *sp, temp);
3159 if ((cfg->opt & MONO_OPT_SHARED) || mono_compile_aot) {
3160 NEW_DOMAINCONST (cfg, iargs [0]);
3161 NEW_CLASSCONST (cfg, iargs [1], cmethod->klass);
3163 temp = mono_emit_jit_icall (cfg, bblock, mono_object_new, iargs, ip);
3165 MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
3166 NEW_PCONST (cfg, iargs [0], vtable);
3167 temp = mono_emit_jit_icall (cfg, bblock, mono_object_new_specific, iargs, ip);
3169 NEW_TEMPLOAD (cfg, *sp, temp);
3172 /* FIXME: currently disabled because of bug #42175 */
3173 if (0 && (cfg->opt & MONO_OPT_INLINE) && cmethod &&
3174 mono_method_check_inlining (cmethod) &&
3175 !mono_class_is_subclass_of (cmethod->klass, mono_defaults.exception_class, FALSE) &&
3176 !g_list_find (dont_inline, cmethod)) {
3178 MonoBasicBlock *ebblock;
3179 if ((costs = inline_method (cfg, cmethod, cmethod->signature, bblock, sp, ip, real_offset, dont_inline, &ebblock))) {
3181 GET_BBLOCK (cfg, bbhash, bblock, ip + 5);
3182 ebblock->next_bb = bblock;
3183 link_bblock (cfg, ebblock, bblock);
3185 /*if (sp != stack_start) {
3186 handle_stack_args (cfg, ebblock, stack_start, sp - stack_start);
3189 start_new_bblock = 1;*/
3191 inline_costs += costs;
3192 /*g_print ("inlined newobj for %s\n", cmethod->klass->name);*/
3195 /* now call the actual ctor */
3196 mono_emit_method_call_spilled (cfg, bblock, cmethod, sp, ip, NULL);
3200 NEW_TEMPLOAD (cfg, *sp, temp);
3209 MONO_INST_NEW (cfg, ins, *ip);
3211 klass = mono_class_get (image, read32 (ip + 1));
3212 mono_class_init (klass);
3213 ins->type = STACK_OBJ;
3214 ins->inst_left = *sp;
3215 ins->inst_newa_class = klass;
3221 MonoInst *add, *vtoffset;
3225 token = read32 (ip + 1);
3226 if (method->wrapper_type != MONO_WRAPPER_NONE)
3227 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
3229 klass = mono_class_get (image, token);
3230 mono_class_init (klass);
3233 MONO_INST_NEW (cfg, ins, OP_UNBOXCAST);
3234 ins->type = STACK_OBJ;
3235 ins->inst_left = *sp;
3237 ins->inst_newa_class = klass;
3240 MONO_INST_NEW (cfg, add, CEE_ADD);
3241 NEW_ICONST (cfg, vtoffset, sizeof (MonoObject));
3242 add->inst_left = ins;
3243 add->inst_right = vtoffset;
3244 add->type = STACK_MP;
3252 MONO_INST_NEW (cfg, ins, *ip);
3254 klass = mono_class_get (image, read32 (ip + 1));
3255 mono_class_init (klass);
3256 ins->type = STACK_OBJ;
3257 ins->inst_left = *sp;
3259 ins->inst_newa_class = klass;
3266 MONO_INST_NEW (cfg, ins, *ip);
3268 ins->inst_left = *sp;
3269 ins->cil_code = ip++;
3270 MONO_ADD_INS (bblock, ins);
3272 start_new_bblock = 1;
3277 MonoInst *offset_ins;
3278 MonoClassField *field;
3281 if (*ip == CEE_STFLD) {
3288 // FIXME: enable this test later.
3289 //if (sp [0]->type != STACK_OBJ && sp [0]->type != STACK_MP)
3291 token = read32 (ip + 1);
3292 field = mono_field_from_token (image, token, &klass);
3293 mono_class_init (klass);
3294 foffset = klass->valuetype? field->offset - sizeof (MonoObject): field->offset;
3295 /* FIXME: mark instructions for use in SSA */
3296 if (*ip == CEE_STFLD) {
3297 if (klass->marshalbyref && !MONO_CHECK_THIS (sp [0])) {
3298 /* fixme: we need to inline that call somehow */
3299 MonoMethod *stfld_wrapper = mono_marshal_get_stfld_wrapper (field->type);
3300 MonoInst *iargs [5];
3302 NEW_CLASSCONST (cfg, iargs [1], klass);
3303 NEW_FIELDCONST (cfg, iargs [2], field);
3304 NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : field->offset);
3306 mono_emit_method_call_spilled (cfg, bblock, stfld_wrapper, iargs, ip, NULL);
3309 NEW_ICONST (cfg, offset_ins, foffset);
3310 MONO_INST_NEW (cfg, ins, CEE_ADD);
3312 ins->inst_left = *sp;
3313 ins->inst_right = offset_ins;
3314 ins->type = STACK_MP;
3316 MONO_INST_NEW (cfg, store, mono_type_to_stind (field->type));
3317 store->cil_code = ip;
3318 store->inst_left = ins;
3319 store->inst_right = sp [1];
3320 handle_loaded_temps (cfg, bblock, stack_start, sp);
3321 store->flags |= ins_flag;
3323 if (store->opcode == CEE_STOBJ) {
3324 handle_stobj (cfg, bblock, ins, sp [1], ip,
3325 mono_class_from_mono_type (field->type), FALSE, FALSE);
3327 MONO_ADD_INS (bblock, store);
3330 if (klass->marshalbyref && !MONO_CHECK_THIS (sp [0])) {
3331 /* fixme: we need to inline that call somehow */
3332 MonoMethod *ldfld_wrapper = mono_marshal_get_ldfld_wrapper (field->type);
3333 MonoInst *iargs [4];
3336 NEW_CLASSCONST (cfg, iargs [1], klass);
3337 NEW_FIELDCONST (cfg, iargs [2], field);
3338 NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : field->offset);
3339 temp = mono_emit_method_call_spilled (cfg, bblock, ldfld_wrapper, iargs, ip, NULL);
3340 if (*ip == CEE_LDFLDA) {
3341 /* not sure howto handle this */
3342 NEW_TEMPLOADA (cfg, *sp, temp);
3344 NEW_TEMPLOAD (cfg, *sp, temp);
3348 NEW_ICONST (cfg, offset_ins, foffset);
3349 MONO_INST_NEW (cfg, ins, CEE_ADD);
3351 ins->inst_left = *sp;
3352 ins->inst_right = offset_ins;
3353 ins->type = STACK_MP;
3355 if (*ip == CEE_LDFLDA) {
3359 MONO_INST_NEW (cfg, load, mono_type_to_ldind (field->type));
3360 type_to_eval_stack_type (field->type, load);
3361 load->cil_code = ip;
3362 load->inst_left = ins;
3363 load->flags |= ins_flag;
3375 MonoClassField *field;
3378 token = read32 (ip + 1);
3380 field = mono_field_from_token (image, token, &klass);
3381 mono_class_init (klass);
3383 handle_loaded_temps (cfg, bblock, stack_start, sp);
3385 if (((cfg->opt & MONO_OPT_SHARED) || mono_compile_aot)) {
3387 MonoInst *iargs [2];
3388 g_assert (field->parent);
3389 NEW_TEMPLOAD (cfg, iargs [0], mono_get_domainvar (cfg)->inst_c0);
3390 NEW_FIELDCONST (cfg, iargs [1], field);
3391 temp = mono_emit_jit_icall (cfg, bblock, mono_class_static_field_address, iargs, ip);
3392 NEW_TEMPLOAD (cfg, ins, temp);
3394 vtable = mono_class_vtable (cfg->domain, klass);
3395 NEW_PCONST (cfg, ins, (char*)vtable->data + field->offset);
3399 /* FIXME: mark instructions for use in SSA */
3400 if (*ip == CEE_LDSFLDA) {
3402 } else if (*ip == CEE_STSFLD) {
3406 MONO_INST_NEW (cfg, store, mono_type_to_stind (field->type));
3407 store->cil_code = ip;
3408 store->inst_left = ins;
3409 store->inst_right = sp [0];
3410 store->flags |= ins_flag;
3413 if (store->opcode == CEE_STOBJ) {
3414 handle_stobj (cfg, bblock, ins, sp [0], ip, mono_class_from_mono_type (field->type), FALSE, FALSE);
3416 MONO_ADD_INS (bblock, store);
3419 CHECK_STACK_OVF (1);
3420 MONO_INST_NEW (cfg, load, mono_type_to_ldind (field->type));
3421 type_to_eval_stack_type (field->type, load);
3422 load->cil_code = ip;
3423 load->inst_left = ins;
3425 load->flags |= ins_flag;
3427 /* fixme: dont see the problem why this does not work */
3428 //cfg->disable_aot = TRUE;
3436 token = read32 (ip + 1);
3437 if (method->wrapper_type != MONO_WRAPPER_NONE)
3438 klass = mono_method_get_wrapper_data (method, token);
3440 klass = mono_class_get (image, token);
3441 mono_class_init (klass);
3442 handle_stobj (cfg, bblock, sp [0], sp [1], ip, klass, FALSE, FALSE);
3447 MonoInst *iargs [2];
3448 MonoInst *load, *vtoffset, *add, *val, *vstore;
3453 token = read32 (ip + 1);
3454 if (method->wrapper_type != MONO_WRAPPER_NONE)
3455 klass = mono_method_get_wrapper_data (method, token);
3457 klass = mono_class_get (image, token);
3458 mono_class_init (klass);
3460 /* much like NEWOBJ */
3461 NEW_DOMAINCONST (cfg, iargs [0]);
3462 NEW_CLASSCONST (cfg, iargs [1], klass);
3464 temp = mono_emit_jit_icall (cfg, bblock, mono_object_new, iargs, ip);
3465 NEW_TEMPLOAD (cfg, load, temp);
3466 NEW_ICONST (cfg, vtoffset, sizeof (MonoObject));
3467 MONO_INST_NEW (cfg, add, CEE_ADD);
3468 add->inst_left = load;
3469 add->inst_right = vtoffset;
3472 MONO_INST_NEW (cfg, vstore, CEE_STIND_I);
3473 vstore->opcode = mono_type_to_stind (&klass->byval_arg);
3474 vstore->cil_code = ip;
3475 vstore->inst_left = add;
3476 vstore->inst_right = val;
3478 if (vstore->opcode == CEE_STOBJ) {
3479 handle_stobj (cfg, bblock, add, val, ip, klass, FALSE, FALSE);
3481 MONO_ADD_INS (bblock, vstore);
3483 NEW_TEMPLOAD (cfg, load, temp);
3491 MONO_INST_NEW (cfg, ins, *ip);
3495 token = read32 (ip + 1);
3497 /* allocate the domainvar - becaus this is used in decompose_foreach */
3498 if ((cfg->opt & MONO_OPT_SHARED) || mono_compile_aot)
3499 mono_get_domainvar (cfg);
3501 if (method->wrapper_type != MONO_WRAPPER_NONE)
3502 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
3504 klass = mono_class_get (image, token);
3506 mono_class_init (klass);
3507 ins->inst_newa_class = klass;
3508 ins->inst_newa_len = *sp;
3509 ins->type = STACK_OBJ;
3516 MONO_INST_NEW (cfg, ins, *ip);
3517 ins->cil_code = ip++;
3519 ins->inst_left = *sp;
3520 ins->type = STACK_PTR;
3526 klass = mono_class_get (image, read32 (ip + 1));
3527 mono_class_init (klass);
3528 NEW_LDELEMA (cfg, ins, sp, klass);
3543 case CEE_LDELEM_REF: {
3547 * ldind.x (ldelema (array, index))
3548 * ldelema does the bounds check
3552 klass = array_access_to_klass (*ip);
3553 NEW_LDELEMA (cfg, load, sp, klass);
3554 load->cil_code = ip;
3555 MONO_INST_NEW (cfg, ins, ldelem_to_ldind [*ip - CEE_LDELEM_I1]);
3557 ins->inst_left = load;
3559 ins->type = ldind_type [ins->opcode - CEE_LDIND_I1];
3569 case CEE_STELEM_R8: {
3573 * stind.x (ldelema (array, index), val)
3574 * ldelema does the bounds check
3578 klass = array_access_to_klass (*ip);
3579 NEW_LDELEMA (cfg, load, sp, klass);
3580 load->cil_code = ip;
3581 MONO_INST_NEW (cfg, ins, stelem_to_stind [*ip - CEE_STELEM_I]);
3583 ins->inst_left = load;
3584 ins->inst_right = sp [2];
3586 handle_loaded_temps (cfg, bblock, stack_start, sp);
3587 MONO_ADD_INS (bblock, ins);
3588 /* FIXME: add the implicit STELEM_REF castclass */
3590 cfg->disable_ssa = TRUE;
3593 case CEE_STELEM_REF: {
3594 MonoInst *iargs [3];
3599 handle_loaded_temps (cfg, bblock, stack_start, sp);
3605 mono_emit_jit_icall (cfg, bblock, helper_stelem_ref, iargs, ip);
3609 NEW_GROUP (cfg, group, sp [0], sp [1]);
3610 MONO_INST_NEW (cfg, ins, CEE_STELEM_REF);
3612 ins->inst_left = group;
3613 ins->inst_right = sp [2];
3614 MONO_ADD_INS (bblock, ins);
3619 cfg->disable_ssa = TRUE;
3622 case CEE_CKFINITE: {
3623 MonoInst *store, *temp;
3626 /* this instr. can throw exceptions as side effect,
3627 * so we cant eliminate dead code which contains CKFINITE opdodes.
3628 * Spilling to memory makes sure that we always perform
3632 MONO_INST_NEW (cfg, ins, CEE_CKFINITE);
3634 ins->inst_left = sp [-1];
3635 temp = mono_compile_create_var (cfg, &mono_defaults.double_class->byval_arg, OP_LOCAL);
3637 NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
3638 store->cil_code = ip;
3639 MONO_ADD_INS (bblock, store);
3641 NEW_TEMPLOAD (cfg, sp [-1], temp->inst_c0);
3648 g_error ("opcode 0x%02x not handled", *ip);
3652 MonoClass *handle_class;
3654 CHECK_STACK_OVF (1);
3656 n = read32 (ip + 1);
3658 handle = mono_ldtoken (image, n, &handle_class);
3659 mono_class_init (handle_class);
3661 if (((cfg->opt & MONO_OPT_SHARED) || mono_compile_aot)) {
3663 MonoInst *res, *store, *addr, *vtvar, *iargs [2];
3665 vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL);
3667 NEW_IMAGECONST (cfg, iargs [0], image);
3668 NEW_ICONST (cfg, iargs [1], n);
3669 temp = mono_emit_jit_icall (cfg, bblock, mono_ldtoken_wrapper, iargs, ip);
3670 NEW_TEMPLOAD (cfg, res, temp);
3671 NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
3672 NEW_INDSTORE (cfg, store, addr, res, &mono_defaults.int_class->byval_arg);
3673 MONO_ADD_INS (bblock, store);
3674 NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
3676 if ((ip [5] == CEE_CALL) && (cmethod = mono_get_method (image, read32 (ip + 6), NULL)) &&
3677 (cmethod->klass == mono_defaults.monotype_class->parent) &&
3678 (strcmp (cmethod->name, "GetTypeFromHandle") == 0)) {
3679 MonoClass *tclass = mono_class_from_mono_type (handle);
3680 mono_class_init (tclass);
3681 NEW_PCONST (cfg, ins, mono_type_get_object (cfg->domain, handle));
3682 ins->type = STACK_OBJ;
3683 ins->klass = cmethod->klass;
3686 NEW_PCONST (cfg, ins, handle);
3687 ins->type = STACK_VTYPE;
3688 ins->klass = handle_class;
3704 case CEE_ADD_OVF_UN:
3706 case CEE_MUL_OVF_UN:
3708 case CEE_SUB_OVF_UN:
3713 case CEE_ENDFINALLY:
3714 /* FIXME: check stack state */
3715 MONO_INST_NEW (cfg, ins, *ip);
3716 MONO_ADD_INS (bblock, ins);
3717 ins->cil_code = ip++;
3718 start_new_bblock = 1;
3723 if (*ip == CEE_LEAVE) {
3724 target = ip + 5 + (gint32)read32(ip + 1);
3726 target = ip + 2 + (signed char)(ip [1]);
3729 /* empty the stack */
3730 while (sp != stack_start) {
3731 MONO_INST_NEW (cfg, ins, CEE_POP);
3735 MONO_ADD_INS (bblock, ins);
3738 /* fixme: call fault handler ? */
3740 if ((handlers = mono_find_final_block (cfg, ip, target, MONO_EXCEPTION_CLAUSE_FINALLY))) {
3742 for (tmp = handlers; tmp; tmp = tmp->next) {
3744 link_bblock (cfg, bblock, tblock);
3745 MONO_INST_NEW (cfg, ins, OP_HANDLER);
3747 ins->inst_target_bb = tblock;
3748 MONO_ADD_INS (bblock, ins);
3750 g_list_free (handlers);
3753 MONO_INST_NEW (cfg, ins, CEE_BR);
3755 MONO_ADD_INS (bblock, ins);
3756 GET_BBLOCK (cfg, bbhash, tblock, target);
3757 link_bblock (cfg, bblock, tblock);
3758 CHECK_BBLOCK (target, ip, tblock);
3759 ins->inst_target_bb = tblock;
3760 start_new_bblock = 1;
3762 if (*ip == CEE_LEAVE)
3771 MONO_INST_NEW (cfg, ins, *ip);
3773 handle_loaded_temps (cfg, bblock, stack_start, sp);
3774 MONO_ADD_INS (bblock, ins);
3775 ins->cil_code = ip++;
3776 ins->inst_i0 = sp [0];
3777 ins->inst_i1 = sp [1];
3785 /* trampoline mono specific opcodes */
3786 case MONO_CUSTOM_PREFIX: {
3788 g_assert (method->wrapper_type != MONO_WRAPPER_NONE);
3792 case CEE_MONO_FUNC1: {
3794 gpointer func = NULL;
3799 case MONO_MARSHAL_CONV_STR_LPWSTR:
3800 func = mono_string_to_utf16;
3802 case MONO_MARSHAL_CONV_LPWSTR_STR:
3803 func = mono_string_from_utf16;
3805 case MONO_MARSHAL_CONV_LPSTR_STR:
3806 func = mono_string_new_wrapper;
3808 case MONO_MARSHAL_CONV_STR_LPTSTR:
3809 case MONO_MARSHAL_CONV_STR_LPSTR:
3810 func = mono_string_to_utf8;
3812 case MONO_MARSHAL_CONV_STR_BSTR:
3813 func = mono_string_to_bstr;
3815 case MONO_MARSHAL_CONV_STR_TBSTR:
3816 case MONO_MARSHAL_CONV_STR_ANSIBSTR:
3817 func = mono_string_to_ansibstr;
3819 case MONO_MARSHAL_CONV_SB_LPSTR:
3820 func = mono_string_builder_to_utf8;
3822 case MONO_MARSHAL_CONV_ARRAY_SAVEARRAY:
3823 func = mono_array_to_savearray;
3825 case MONO_MARSHAL_CONV_ARRAY_LPARRAY:
3826 func = mono_array_to_lparray;
3828 case MONO_MARSHAL_CONV_DEL_FTN:
3829 func = mono_delegate_to_ftnptr;
3831 case MONO_MARSHAL_CONV_STRARRAY_STRLPARRAY:
3832 func = mono_marshal_string_array;
3835 g_warning ("unknown conversion %d\n", ip [2]);
3836 g_assert_not_reached ();
3839 temp = mono_emit_jit_icall (cfg, bblock, func, sp, ip);
3840 NEW_TEMPLOAD (cfg, *sp, temp);
3844 inline_costs += 10 * num_calls++;
3847 case CEE_MONO_PROC2: {
3848 gpointer func = NULL;
3853 case MONO_MARSHAL_CONV_LPSTR_SB:
3854 func = mono_string_utf8_to_builder;
3856 case MONO_MARSHAL_FREE_ARRAY:
3857 func = mono_marshal_free_array;
3860 g_assert_not_reached ();
3863 mono_emit_jit_icall (cfg, bblock, func, sp, ip);
3865 inline_costs += 10 * num_calls++;
3868 case CEE_MONO_PROC3: {
3869 gpointer func = NULL;
3874 case MONO_MARSHAL_CONV_STR_BYVALSTR:
3875 func = mono_string_to_byvalstr;
3877 case MONO_MARSHAL_CONV_STR_BYVALWSTR:
3878 func = mono_string_to_byvalwstr;
3881 g_assert_not_reached ();
3884 mono_emit_jit_icall (cfg, bblock, func, sp, ip);
3886 inline_costs += 10 * num_calls++;
3892 mono_emit_jit_icall (cfg, bblock, g_free, sp, ip);
3894 inline_costs += 10 * num_calls++;
3896 case CEE_MONO_LDPTR:
3897 CHECK_STACK_OVF (1);
3898 token = read32 (ip + 2);
3899 NEW_PCONST (cfg, ins, mono_method_get_wrapper_data (method, token));
3903 inline_costs += 10 * num_calls++;
3905 case CEE_MONO_VTADDR:
3908 MONO_INST_NEW (cfg, ins, OP_VTADDR);
3910 ins->type = STACK_MP;
3911 ins->inst_left = *sp;
3915 case CEE_MONO_NEWOBJ: {
3916 MonoInst *iargs [2];
3918 CHECK_STACK_OVF (1);
3919 token = read32 (ip + 2);
3920 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
3921 mono_class_init (klass);
3922 NEW_DOMAINCONST (cfg, iargs [0]);
3923 NEW_CLASSCONST (cfg, iargs [1], klass);
3924 temp = mono_emit_jit_icall (cfg, bblock, mono_object_new, iargs, ip);
3925 NEW_TEMPLOAD (cfg, *sp, temp);
3928 inline_costs += 10 * num_calls++;
3931 case CEE_MONO_OBJADDR:
3934 MONO_INST_NEW (cfg, ins, OP_OBJADDR);
3936 ins->type = STACK_MP;
3937 ins->inst_left = *sp;
3941 case CEE_MONO_LDNATIVEOBJ:
3943 token = read32 (ip + 2);
3944 klass = mono_method_get_wrapper_data (method, token);
3945 g_assert (klass->valuetype);
3946 mono_class_init (klass);
3947 NEW_INDLOAD (cfg, ins, sp [-1], &klass->byval_arg);
3951 case CEE_MONO_RETOBJ:
3952 g_assert (cfg->ret);
3953 g_assert (method->signature->pinvoke);
3957 token = read32 (ip + 2);
3958 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
3960 NEW_RETLOADA (cfg, ins);
3961 handle_stobj (cfg, bblock, ins, *sp, ip, klass, FALSE, TRUE);
3963 if (sp != stack_start)
3966 MONO_INST_NEW (cfg, ins, CEE_BR);
3968 ins->inst_target_bb = end_bblock;
3969 MONO_ADD_INS (bblock, ins);
3970 link_bblock (cfg, bblock, end_bblock);
3971 start_new_bblock = 1;
3975 g_error ("opcode 0x%02x 0x%02x not handled", MONO_CUSTOM_PREFIX, ip [1]);
3983 g_error ("opcode 0xfe 0x%02x not handled", ip [1]);
3992 MONO_INST_NEW (cfg, cmp, 256 + ip [1]);
3993 MONO_INST_NEW (cfg, ins, cmp->opcode);
3995 cmp->inst_i0 = sp [0];
3996 cmp->inst_i1 = sp [1];
4000 cmp->opcode = OP_COMPARE;
4002 ins->type = STACK_I4;
4012 CHECK_STACK_OVF (1);
4013 n = read32 (ip + 2);
4014 if (method->wrapper_type != MONO_WRAPPER_NONE)
4015 cmethod = mono_method_get_wrapper_data (method, n);
4017 cmethod = mono_get_method (image, n, NULL);
4020 * We can't do this in mono_ldftn, since it is used in
4021 * the synchronized wrapper, leading to an infinite loop.
4023 if (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
4024 cmethod = mono_marshal_get_synchronized_wrapper (cmethod);
4027 mono_class_init (cmethod->klass);
4028 handle_loaded_temps (cfg, bblock, stack_start, sp);
4030 NEW_METHODCONST (cfg, argconst, cmethod);
4031 temp = mono_emit_jit_icall (cfg, bblock, mono_ldftn, &argconst, ip);
4032 NEW_TEMPLOAD (cfg, *sp, temp);
4036 inline_costs += 10 * num_calls++;
4039 case CEE_LDVIRTFTN: {
4044 n = read32 (ip + 2);
4045 if (method->wrapper_type != MONO_WRAPPER_NONE)
4046 cmethod = mono_method_get_wrapper_data (method, n);
4048 cmethod = mono_get_method (image, n, NULL);
4050 mono_class_init (cmethod->klass);
4051 handle_loaded_temps (cfg, bblock, stack_start, sp);
4055 NEW_METHODCONST (cfg, args [1], cmethod);
4056 temp = mono_emit_jit_icall (cfg, bblock, mono_ldvirtfn, args, ip);
4057 NEW_TEMPLOAD (cfg, *sp, temp);
4061 inline_costs += 10 * num_calls++;
4065 CHECK_STACK_OVF (1);
4066 NEW_ARGLOAD (cfg, ins, read16 (ip + 2));
4072 CHECK_STACK_OVF (1);
4073 NEW_ARGLOADA (cfg, ins, read16 (ip + 2));
4081 handle_loaded_temps (cfg, bblock, stack_start, sp);
4082 n = read16 (ip + 2);
4083 NEW_ARGSTORE (cfg, ins, n, *sp);
4085 if (ins->opcode == CEE_STOBJ) {
4086 NEW_ARGLOADA (cfg, ins, n);
4087 handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE);
4089 MONO_ADD_INS (bblock, ins);
4093 CHECK_STACK_OVF (1);
4094 NEW_LOCLOAD (cfg, ins, read16 (ip + 2));
4100 CHECK_STACK_OVF (1);
4101 NEW_LOCLOADA (cfg, ins, read16 (ip + 2));
4109 n = read16 (ip + 2);
4110 handle_loaded_temps (cfg, bblock, stack_start, sp);
4111 NEW_LOCSTORE (cfg, ins, n, *sp);
4113 if (ins->opcode == CEE_STOBJ) {
4114 NEW_LOCLOADA (cfg, ins, n);
4115 handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE);
4117 MONO_ADD_INS (bblock, ins);
4124 if (sp != stack_start)
4126 MONO_INST_NEW (cfg, ins, 256 + ip [1]);
4127 ins->inst_left = *sp;
4130 if (header->init_locals)
4131 ins->flags |= MONO_INST_INIT;
4135 /* FIXME: set init flag if locals init is set in this method */
4137 case CEE_ENDFILTER: {
4138 MonoExceptionClause *clause, *nearest;
4139 int cc, nearest_num;
4143 if ((sp != stack_start) || (sp [0]->type != STACK_I4))
4145 MONO_INST_NEW (cfg, ins, OP_ENDFILTER);
4146 ins->inst_left = *sp;
4148 MONO_ADD_INS (bblock, ins);
4149 start_new_bblock = 1;
4153 for (cc = 0; cc < header->num_clauses; ++cc) {
4154 clause = &header->clauses [cc];
4155 if ((clause->flags & MONO_EXCEPTION_CLAUSE_FILTER) &&
4156 (!nearest || (clause->token_or_filter > nearest->token_or_filter))) {
4162 filter_lengths [nearest_num] = (ip - header->code) - nearest->token_or_filter;
4166 case CEE_UNALIGNED_:
4167 ins_flag |= MONO_INST_UNALIGNED;
4171 ins_flag |= MONO_INST_VOLATILE;
4175 ins_flag |= MONO_INST_TAILCALL;
4181 token = read32 (ip + 2);
4182 if (method->wrapper_type != MONO_WRAPPER_NONE)
4183 klass = mono_method_get_wrapper_data (method, token);
4185 klass = mono_class_get (image, token);
4186 handle_initobj (cfg, bblock, *sp, NULL, klass, stack_start, sp);
4192 MonoInst *iargs [3];
4198 handle_loaded_temps (cfg, bblock, stack_start, sp);
4199 if (ip [1] == CEE_CPBLK) {
4200 mono_emit_jit_icall (cfg, bblock, helper_memcpy, iargs, ip);
4202 mono_emit_jit_icall (cfg, bblock, helper_memset, iargs, ip);
4210 /* FIXME: check we are in a catch handler */
4211 NEW_TEMPLOAD (cfg, load, cfg->exvar->inst_c0);
4212 load->cil_code = ip;
4213 MONO_INST_NEW (cfg, ins, CEE_THROW);
4214 ins->inst_left = load;
4216 MONO_ADD_INS (bblock, ins);
4218 start_new_bblock = 1;
4223 CHECK_STACK_OVF (1);
4224 token = read32 (ip + 2);
4225 if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC) {
4226 MonoType *type = mono_type_create_from_typespec (image, token);
4227 token = mono_type_size (type, &align);
4228 mono_metadata_free_type (type);
4230 MonoClass *szclass = mono_class_get (image, token);
4231 mono_class_init (szclass);
4232 token = mono_class_value_size (szclass, &align);
4234 NEW_ICONST (cfg, ins, token);
4239 case CEE_REFANYTYPE:
4240 g_error ("opcode 0xfe 0x%02x not handled", ip [1]);
4243 g_error ("opcode 0xfe 0x%02x not handled", ip [1]);
4248 g_error ("opcode 0x%02x not handled", *ip);
4251 if (start_new_bblock != 1)
4254 bblock->cil_length = ip - bblock->cil_code;
4255 bblock->next_bb = end_bblock;
4256 link_bblock (cfg, bblock, end_bblock);
4258 if (cfg->method == method && cfg->domainvar) {
4262 MONO_INST_NEW_CALL (cfg, call, CEE_CALL);
4263 call->signature = helper_sig_domain_get;
4264 call->inst.type = STACK_PTR;
4265 call->fptr = mono_domain_get;
4266 NEW_TEMPSTORE (cfg, store, cfg->domainvar->inst_c0, (MonoInst*)call);
4268 MONO_ADD_INS (init_localsbb, store);
4271 if (header->init_locals) {
4273 for (i = 0; i < header->num_locals; ++i) {
4274 int t = header->locals [i]->type;
4275 if (t == MONO_TYPE_VALUETYPE && header->locals [i]->data.klass->enumtype)
4276 t = header->locals [i]->data.klass->enum_basetype->type;
4277 /* FIXME: use initobj for valuetypes, handle pointers, long, float. */
4278 if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
4279 NEW_ICONST (cfg, ins, 0);
4280 NEW_LOCSTORE (cfg, store, i, ins);
4281 MONO_ADD_INS (init_localsbb, store);
4282 } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
4283 MONO_INST_NEW (cfg, ins, OP_I8CONST);
4284 ins->type = STACK_I8;
4286 NEW_LOCSTORE (cfg, store, i, ins);
4287 MONO_ADD_INS (init_localsbb, store);
4288 } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
4289 MONO_INST_NEW (cfg, ins, OP_R8CONST);
4290 ins->type = STACK_R8;
4291 ins->inst_p0 = (void*)&r8_0;
4292 NEW_LOCSTORE (cfg, store, i, ins);
4293 MONO_ADD_INS (init_localsbb, store);
4294 } else if (t == MONO_TYPE_VALUETYPE) {
4295 NEW_LOCLOADA (cfg, ins, i);
4296 handle_initobj (cfg, init_localsbb, ins, NULL, mono_class_from_mono_type (header->locals [i]), NULL, NULL);
4299 NEW_PCONST (cfg, ins, NULL);
4300 NEW_LOCSTORE (cfg, store, i, ins);
4301 MONO_ADD_INS (init_localsbb, store);
4307 /* resolve backward branches in the middle of an existing basic block */
4308 for (tmp = bb_recheck; tmp; tmp = tmp->next) {
4310 /*g_print ("need recheck in %s at IL_%04x\n", method->name, bblock->cil_code - header->code);*/
4311 tblock = find_previous (bbhash, start_bblock, bblock->cil_code);
4312 if (tblock != start_bblock) {
4314 split_bblock (cfg, tblock, bblock);
4315 l = bblock->cil_code - header->code;
4316 bblock->cil_length = tblock->cil_length - l;
4317 tblock->cil_length = l;
4319 g_print ("recheck failed.\n");
4323 /* we compute regions here, because the length of filter clauses is not known in advance.
4324 * It is computed in the CEE_ENDFILTER case in the above switch statement*/
4325 if (cfg->method == method) {
4327 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4328 bb->region = mono_find_block_region (cfg, bb->real_offset, filter_lengths);
4329 if (cfg->verbose_level > 2)
4330 g_print ("REGION BB%d IL_%04x ID_%08X\n", bb->block_num, bb->real_offset, bb->region);
4333 g_hash_table_destroy (bbhash);
4336 dont_inline = g_list_remove (dont_inline, method);
4337 return inline_costs;
4340 if (cfg->method != method)
4341 g_hash_table_destroy (bbhash);
4342 dont_inline = g_list_remove (dont_inline, method);
4346 if (cfg->method != method)
4347 g_hash_table_destroy (bbhash);
4348 g_error ("Invalid IL code at IL%04x in %s: %s\n", ip - header->code,
4349 mono_method_full_name (method, TRUE), mono_disasm_code_one (NULL, method, ip, NULL));
4350 dont_inline = g_list_remove (dont_inline, method);
4355 mono_print_tree (MonoInst *tree) {
4361 arity = mono_burg_arity [tree->opcode];
4363 printf (" %s%s", arity?"(":"", mono_inst_name (tree->opcode));
4365 switch (tree->opcode) {
4367 printf ("[%d]", tree->inst_c0);
4370 printf ("[%lld]", tree->inst_l);
4373 printf ("[%f]", *(double*)tree->inst_p0);
4376 printf ("[%f]", *(float*)tree->inst_p0);
4380 printf ("[%d]", tree->inst_c0);
4383 printf ("[0x%x(%s)]", tree->inst_offset, mono_arch_regname (tree->inst_basereg));
4386 printf ("[%s]", mono_arch_regname (tree->dreg));
4389 printf ("[%s]", tree->inst_newa_class->name);
4390 mono_print_tree (tree->inst_newa_len);
4401 case OP_VOIDCALLVIRT: {
4402 MonoCallInst *call = (MonoCallInst*)tree;
4404 printf ("[%s]", call->method->name);
4409 printf ("[%d (", tree->inst_c0);
4410 for (i = 0; i < tree->inst_phi_args [0]; i++) {
4413 printf ("%d", tree->inst_phi_args [i + 1]);
4425 printf ("[B%d]", tree->inst_target_bb->block_num);
4435 case OP_VOIDCALL_REG:
4436 mono_print_tree (tree->inst_left);
4448 printf ("[B%dB%d]", tree->inst_true_bb->block_num, tree->inst_false_bb->block_num);
4449 mono_print_tree (tree->inst_left);
4453 mono_print_tree (tree->inst_left);
4455 mono_print_tree (tree->inst_right);
4465 create_helper_signature (void)
4467 /* FIXME: set call conv */
4468 /* MonoArray * mono_array_new (MonoDomain *domain, MonoClass *klass, gint32 len) */
4469 helper_sig_newarr = mono_metadata_signature_alloc (mono_defaults.corlib, 3);
4470 helper_sig_newarr->params [0] = helper_sig_newarr->params [1] = &mono_defaults.int_class->byval_arg;
4471 helper_sig_newarr->ret = &mono_defaults.object_class->byval_arg;
4472 helper_sig_newarr->params [2] = &mono_defaults.int32_class->byval_arg;
4473 helper_sig_newarr->pinvoke = 1;
4475 /* MonoArray * mono_array_new_specific (MonoVTable *vtable, guint32 len) */
4476 helper_sig_newarr_specific = mono_metadata_signature_alloc (mono_defaults.corlib, 2);
4477 helper_sig_newarr_specific->params [0] = &mono_defaults.int_class->byval_arg;
4478 helper_sig_newarr_specific->params [1] = &mono_defaults.int32_class->byval_arg;
4479 helper_sig_newarr_specific->ret = &mono_defaults.object_class->byval_arg;
4480 helper_sig_newarr_specific->pinvoke = 1;
4482 /* MonoObject * mono_object_new (MonoDomain *domain, MonoClass *klass) */
4483 helper_sig_object_new = mono_metadata_signature_alloc (mono_defaults.corlib, 2);
4484 helper_sig_object_new->params [0] = helper_sig_object_new->params [1] = &mono_defaults.int_class->byval_arg;
4485 helper_sig_object_new->ret = &mono_defaults.object_class->byval_arg;
4486 helper_sig_object_new->pinvoke = 1;
4488 /* MonoObject * mono_object_new_specific (MonoVTable *vtable) */
4489 helper_sig_object_new_specific = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
4490 helper_sig_object_new_specific->params [0] = &mono_defaults.int_class->byval_arg;
4491 helper_sig_object_new_specific->ret = &mono_defaults.object_class->byval_arg;
4492 helper_sig_object_new_specific->pinvoke = 1;
4494 /* void* mono_method_compile (MonoMethod*) */
4495 helper_sig_compile = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
4496 helper_sig_compile->params [0] = helper_sig_compile->ret = &mono_defaults.int_class->byval_arg;
4497 helper_sig_compile->pinvoke = 1;
4499 /* void* mono_ldvirtfn (MonoObject *, MonoMethod*) */
4500 helper_sig_compile_virt = mono_metadata_signature_alloc (mono_defaults.corlib, 2);
4501 helper_sig_compile_virt->params [0] = &mono_defaults.object_class->byval_arg;
4502 helper_sig_compile_virt->params [1] = helper_sig_compile_virt->ret = &mono_defaults.int_class->byval_arg;
4503 helper_sig_compile_virt->pinvoke = 1;
4505 /* MonoString* mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 str_index) */
4506 helper_sig_ldstr = mono_metadata_signature_alloc (mono_defaults.corlib, 3);
4507 helper_sig_ldstr->params [0] = helper_sig_ldstr->params [1] = &mono_defaults.int_class->byval_arg;
4508 helper_sig_ldstr->params [2] = &mono_defaults.int32_class->byval_arg;
4509 helper_sig_ldstr->ret = &mono_defaults.object_class->byval_arg;
4510 helper_sig_ldstr->pinvoke = 1;
4512 /* MonoDomain *mono_domain_get (void) */
4513 helper_sig_domain_get = mono_metadata_signature_alloc (mono_defaults.corlib, 0);
4514 helper_sig_domain_get->ret = &mono_defaults.int_class->byval_arg;
4515 helper_sig_domain_get->pinvoke = 1;
4517 /* void* stelem_ref (MonoArray *, int index, MonoObject *) */
4518 helper_sig_stelem_ref = mono_metadata_signature_alloc (mono_defaults.corlib, 3);
4519 helper_sig_stelem_ref->params [0] = &mono_defaults.array_class->byval_arg;
4520 helper_sig_stelem_ref->params [1] = &mono_defaults.int32_class->byval_arg;
4521 helper_sig_stelem_ref->params [2] = &mono_defaults.object_class->byval_arg;
4522 helper_sig_stelem_ref->ret = &mono_defaults.void_class->byval_arg;
4523 helper_sig_stelem_ref->pinvoke = 1;
4525 /* long amethod (long, long) */
4526 helper_sig_long_long_long = mono_metadata_signature_alloc (mono_defaults.corlib, 2);
4527 helper_sig_long_long_long->params [0] = helper_sig_long_long_long->params [1] =
4528 &mono_defaults.int64_class->byval_arg;
4529 helper_sig_long_long_long->ret = &mono_defaults.int64_class->byval_arg;
4530 helper_sig_long_long_long->pinvoke = 1;
4532 /* object amethod (intptr) */
4533 helper_sig_obj_ptr = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
4534 helper_sig_obj_ptr->params [0] = &mono_defaults.int_class->byval_arg;
4535 helper_sig_obj_ptr->ret = &mono_defaults.object_class->byval_arg;
4536 helper_sig_obj_ptr->pinvoke = 1;
4538 /* void amethod (intptr) */
4539 helper_sig_void_ptr = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
4540 helper_sig_void_ptr->params [0] = &mono_defaults.int_class->byval_arg;
4541 helper_sig_void_ptr->ret = &mono_defaults.void_class->byval_arg;
4542 helper_sig_void_ptr->pinvoke = 1;
4544 /* void amethod (MonoObject *obj) */
4545 helper_sig_void_obj = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
4546 helper_sig_void_obj->params [0] = &mono_defaults.object_class->byval_arg;
4547 helper_sig_void_obj->ret = &mono_defaults.void_class->byval_arg;
4548 helper_sig_void_obj->pinvoke = 1;
4550 /* intptr amethod (void) */
4551 helper_sig_ptr_void = mono_metadata_signature_alloc (mono_defaults.corlib, 0);
4552 helper_sig_ptr_void->ret = &mono_defaults.int_class->byval_arg;
4553 helper_sig_ptr_void->pinvoke = 1;
4555 /* void amethod (intptr, intptr) */
4556 helper_sig_void_ptr_ptr = mono_metadata_signature_alloc (mono_defaults.corlib, 2);
4557 helper_sig_void_ptr_ptr->params [0] = &mono_defaults.int_class->byval_arg;
4558 helper_sig_void_ptr_ptr->params [1] = &mono_defaults.int_class->byval_arg;
4559 helper_sig_void_ptr_ptr->ret = &mono_defaults.void_class->byval_arg;
4560 helper_sig_void_ptr_ptr->pinvoke = 1;
4562 /* void amethod (intptr, intptr, intptr) */
4563 helper_sig_void_ptr_ptr_ptr = mono_metadata_signature_alloc (mono_defaults.corlib, 3);
4564 helper_sig_void_ptr_ptr_ptr->params [0] = &mono_defaults.int_class->byval_arg;
4565 helper_sig_void_ptr_ptr_ptr->params [1] = &mono_defaults.int_class->byval_arg;
4566 helper_sig_void_ptr_ptr_ptr->params [2] = &mono_defaults.int_class->byval_arg;
4567 helper_sig_void_ptr_ptr_ptr->ret = &mono_defaults.void_class->byval_arg;
4568 helper_sig_void_ptr_ptr_ptr->pinvoke = 1;
4570 /* intptr amethod (intptr, intptr) */
4571 helper_sig_ptr_ptr_ptr = mono_metadata_signature_alloc (mono_defaults.corlib, 2);
4572 helper_sig_ptr_ptr_ptr->params [0] = &mono_defaults.int_class->byval_arg;
4573 helper_sig_ptr_ptr_ptr->params [1] = &mono_defaults.int_class->byval_arg;
4574 helper_sig_ptr_ptr_ptr->ret = &mono_defaults.int_class->byval_arg;
4575 helper_sig_ptr_ptr_ptr->pinvoke = 1;
4577 /* IntPtr amethod (object) */
4578 helper_sig_ptr_obj = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
4579 helper_sig_ptr_obj->params [0] = &mono_defaults.object_class->byval_arg;
4580 helper_sig_ptr_obj->ret = &mono_defaults.int_class->byval_arg;
4581 helper_sig_ptr_obj->pinvoke = 1;
4583 /* long amethod (long, guint32) */
4584 helper_sig_long_long_int = mono_metadata_signature_alloc (mono_defaults.corlib, 2);
4585 helper_sig_long_long_int->params [0] = &mono_defaults.int64_class->byval_arg;
4586 helper_sig_long_long_int->params [1] = &mono_defaults.int32_class->byval_arg;
4587 helper_sig_long_long_int->ret = &mono_defaults.int64_class->byval_arg;
4588 helper_sig_long_long_int->pinvoke = 1;
4590 /* ulong amethod (double) */
4591 helper_sig_ulong_double = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
4592 helper_sig_ulong_double->params [0] = &mono_defaults.double_class->byval_arg;
4593 helper_sig_ulong_double->ret = &mono_defaults.uint64_class->byval_arg;
4594 helper_sig_ulong_double->pinvoke = 1;
4596 /* long amethod (double) */
4597 helper_sig_long_double = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
4598 helper_sig_long_double->params [0] = &mono_defaults.double_class->byval_arg;
4599 helper_sig_long_double->ret = &mono_defaults.int64_class->byval_arg;
4600 helper_sig_long_double->pinvoke = 1;
4602 /* uint amethod (double) */
4603 helper_sig_uint_double = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
4604 helper_sig_uint_double->params [0] = &mono_defaults.double_class->byval_arg;
4605 helper_sig_uint_double->ret = &mono_defaults.uint32_class->byval_arg;
4606 helper_sig_uint_double->pinvoke = 1;
4608 /* int amethod (double) */
4609 helper_sig_int_double = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
4610 helper_sig_int_double->params [0] = &mono_defaults.double_class->byval_arg;
4611 helper_sig_int_double->ret = &mono_defaults.int32_class->byval_arg;
4612 helper_sig_int_double->pinvoke = 1;
4614 /* void initobj (intptr, int size) */
4615 helper_sig_initobj = mono_metadata_signature_alloc (mono_defaults.corlib, 2);
4616 helper_sig_initobj->params [0] = &mono_defaults.int_class->byval_arg;
4617 helper_sig_initobj->params [1] = &mono_defaults.int32_class->byval_arg;
4618 helper_sig_initobj->ret = &mono_defaults.void_class->byval_arg;
4619 helper_sig_initobj->pinvoke = 1;
4621 /* void memcpy (intptr, intptr, int size) */
4622 helper_sig_memcpy = mono_metadata_signature_alloc (mono_defaults.corlib, 3);
4623 helper_sig_memcpy->params [0] = &mono_defaults.int_class->byval_arg;
4624 helper_sig_memcpy->params [1] = &mono_defaults.int_class->byval_arg;
4625 helper_sig_memcpy->params [2] = &mono_defaults.int32_class->byval_arg;
4626 helper_sig_memcpy->ret = &mono_defaults.void_class->byval_arg;
4627 helper_sig_memcpy->pinvoke = 1;
4629 /* void memset (intptr, int val, int size) */
4630 helper_sig_memset = mono_metadata_signature_alloc (mono_defaults.corlib, 3);
4631 helper_sig_memset->params [0] = &mono_defaults.int_class->byval_arg;
4632 helper_sig_memset->params [1] = &mono_defaults.int32_class->byval_arg;
4633 helper_sig_memset->params [2] = &mono_defaults.int32_class->byval_arg;
4634 helper_sig_memset->ret = &mono_defaults.void_class->byval_arg;
4635 helper_sig_memset->pinvoke = 1;
4638 static GHashTable *jit_icall_hash_name = NULL;
4639 static GHashTable *jit_icall_hash_addr = NULL;
4642 mono_find_jit_icall_by_name (const char *name)
4644 g_assert (jit_icall_hash_name);
4646 //printf ("lookup addr %s %p\n", name, g_hash_table_lookup (jit_icall_hash_name, name));
4647 return g_hash_table_lookup (jit_icall_hash_name, name);
4651 mono_find_jit_icall_by_addr (gconstpointer addr)
4653 g_assert (jit_icall_hash_addr);
4655 return g_hash_table_lookup (jit_icall_hash_addr, (gpointer)addr);
4659 mono_register_jit_icall (gconstpointer func, const char *name, MonoMethodSignature *sig, gboolean is_save)
4661 MonoJitICallInfo *info;
4662 MonoMethod *wrapper;
4668 if (!jit_icall_hash_name) {
4669 jit_icall_hash_name = g_hash_table_new (g_str_hash, g_str_equal);
4670 jit_icall_hash_addr = g_hash_table_new (NULL, NULL);
4673 if (g_hash_table_lookup (jit_icall_hash_name, name)) {
4674 g_warning ("jit icall already defined \"%s\"\n", name);
4675 g_assert_not_reached ();
4678 info = g_new (MonoJitICallInfo, 1);
4680 info->name = g_strdup (name);
4685 #ifdef MONO_USE_EXC_TABLES
4686 || mono_arch_has_unwind_info (func)
4689 info->wrapper = func;
4692 n = g_strdup_printf ("__icall_wrapper_%s", name);
4693 wrapper = mono_marshal_get_icall_wrapper (sig, n, func);
4694 info->wrapper = mono_jit_compile_method (wrapper);
4698 g_hash_table_insert (jit_icall_hash_name, info->name, info);
4699 g_hash_table_insert (jit_icall_hash_addr, (gpointer)func, info);
4700 if (func != info->wrapper)
4701 g_hash_table_insert (jit_icall_hash_addr, (gpointer)info->wrapper, info);
4706 static GHashTable *emul_opcode_hash = NULL;
4708 static MonoJitICallInfo *
4709 mono_find_jit_opcode_emulation (int opcode)
4711 if (emul_opcode_hash)
4712 return g_hash_table_lookup (emul_opcode_hash, (gpointer)opcode);
4718 mono_register_opcode_emulation (int opcode, MonoMethodSignature *sig, gpointer func)
4720 MonoJitICallInfo *info;
4723 if (!emul_opcode_hash)
4724 emul_opcode_hash = g_hash_table_new (NULL, NULL);
4726 g_assert (!sig->hasthis);
4727 g_assert (sig->param_count < 3);
4729 name = g_strdup_printf ("__emulate_%s", mono_inst_name (opcode));
4731 info = mono_register_jit_icall (func, name, sig, FALSE);
4735 g_hash_table_insert (emul_opcode_hash, (gpointer)opcode, info);
4739 decompose_foreach (MonoInst *tree, gpointer data)
4741 static MonoJitICallInfo *newarr_info = NULL;
4742 static MonoJitICallInfo *newarr_specific_info = NULL;
4743 MonoJitICallInfo *info;
4745 switch (tree->opcode) {
4747 MonoCompile *cfg = data;
4748 MonoInst *iargs [3];
4751 newarr_info = mono_find_jit_icall_by_addr (mono_array_new);
4752 g_assert (newarr_info);
4753 newarr_specific_info = mono_find_jit_icall_by_addr (mono_array_new_specific);
4754 g_assert (newarr_specific_info);
4757 if ((cfg->opt & MONO_OPT_SHARED) || mono_compile_aot) {
4758 NEW_DOMAINCONST (cfg, iargs [0]);
4759 NEW_CLASSCONST (cfg, iargs [1], tree->inst_newa_class);
4760 iargs [2] = tree->inst_newa_len;
4765 MonoVTable *vtable = mono_class_vtable (cfg->domain,
4766 mono_array_class_get (&tree->inst_newa_class->byval_arg, 1));
4768 NEW_PCONST (cfg, iargs [0], vtable);
4769 iargs [1] = tree->inst_newa_len;
4771 info = newarr_specific_info;
4774 mono_emulate_opcode (cfg, tree, iargs, info);
4784 mono_inst_foreach (MonoInst *tree, MonoInstFunc func, gpointer data) {
4786 switch (mono_burg_arity [tree->opcode]) {
4789 mono_inst_foreach (tree->inst_left, func, data);
4792 mono_inst_foreach (tree->inst_left, func, data);
4793 mono_inst_foreach (tree->inst_right, func, data);
4796 g_assert_not_reached ();
4803 mono_print_bb_code (MonoBasicBlock *bb) {
4805 MonoInst *c = bb->code;
4807 mono_print_tree (c);
4816 print_dfn (MonoCompile *cfg) {
4821 g_print ("IR code for method %s\n", mono_method_full_name (cfg->method, TRUE));
4823 for (i = 0; i < cfg->num_bblocks; ++i) {
4824 bb = cfg->bblocks [i];
4826 char* code1, *code2;
4827 code1 = mono_disasm_code_one (NULL, cfg->method, bb->cil_code, NULL);
4828 if (bb->last_ins->cil_code)
4829 code2 = mono_disasm_code_one (NULL, cfg->method, bb->last_ins->cil_code, NULL);
4831 code2 = g_strdup ("");
4833 code1 [strlen (code1) - 1] = 0;
4834 code = g_strdup_printf ("%s -> %s", code1, code2);
4838 code = g_strdup ("\n");
4839 g_print ("\nBB%d DFN%d (len: %d): %s", bb->block_num, i, bb->cil_length, code);
4841 MonoInst *c = bb->code;
4843 mono_print_tree (c);
4851 g_print ("\tprev:");
4852 for (j = 0; j < bb->in_count; ++j) {
4853 g_print (" BB%d", bb->in_bb [j]->block_num);
4855 g_print ("\t\tsucc:");
4856 for (j = 0; j < bb->out_count; ++j) {
4857 g_print (" BB%d", bb->out_bb [j]->block_num);
4859 g_print ("\n\tidom: BB%d\n", bb->idom? bb->idom->block_num: -1);
4862 g_assert (mono_bitset_test_fast (bb->dominators, bb->idom->dfn));
4865 mono_blockset_print (cfg, bb->dominators, "\tdominators", bb->idom? bb->idom->dfn: -1);
4867 mono_blockset_print (cfg, bb->dfrontier, "\tdfrontier", -1);
4875 * returns the offset used by spillvar. It allocates a new
4876 * spill variable if necessary.
4879 mono_spillvar_offset (MonoCompile *cfg, int spillvar)
4881 MonoSpillInfo **si, *info;
4884 si = &cfg->spill_info;
4886 while (i <= spillvar) {
4889 *si = info = mono_mempool_alloc (cfg->mempool, sizeof (MonoSpillInfo));
4891 cfg->stack_offset -= sizeof (gpointer);
4892 info->offset = cfg->stack_offset;
4896 return (*si)->offset;
4902 g_assert_not_reached ();
4907 mono_bblock_add_inst (MonoBasicBlock *bb, MonoInst *inst)
4911 g_assert (bb->code);
4912 bb->last_ins->next = inst;
4913 bb->last_ins = inst;
4915 bb->last_ins = bb->code = inst;
4920 mono_destroy_compile (MonoCompile *cfg)
4922 //mono_mempool_stats (cfg->mempool);
4923 g_hash_table_destroy (cfg->bb_hash);
4925 mono_regstate_free (cfg->rs);
4926 mono_mempool_destroy (cfg->mempool);
4927 g_list_free (cfg->ldstr_list);
4929 g_free (cfg->varinfo);
4935 mono_get_lmf_addr (void)
4937 MonoJitTlsData *jit_tls;
4939 if ((jit_tls = TlsGetValue (mono_jit_tls_id)))
4940 return &jit_tls->lmf;
4942 g_assert_not_reached ();
4947 * mono_thread_abort:
4948 * @obj: exception object
4950 * abort the thread, print exception information and stack trace
4953 mono_thread_abort (MonoObject *obj)
4955 MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
4963 mono_thread_start_cb (guint32 tid, gpointer stack_start, gpointer func)
4965 MonoJitTlsData *jit_tls;
4968 jit_tls = g_new0 (MonoJitTlsData, 1);
4970 TlsSetValue (mono_jit_tls_id, jit_tls);
4972 jit_tls->abort_func = mono_thread_abort;
4973 jit_tls->end_of_stack = stack_start;
4975 lmf = g_new0 (MonoLMF, 1);
4981 void (*mono_thread_attach_aborted_cb ) (MonoObject *obj) = NULL;
4984 mono_thread_abort_dummy (MonoObject *obj)
4986 if (mono_thread_attach_aborted_cb)
4987 mono_thread_attach_aborted_cb (obj);
4989 mono_thread_abort (obj);
4993 mono_thread_attach_cb (guint32 tid, gpointer stack_start)
4995 MonoJitTlsData *jit_tls;
4998 jit_tls = g_new0 (MonoJitTlsData, 1);
5000 TlsSetValue (mono_jit_tls_id, jit_tls);
5002 jit_tls->abort_func = mono_thread_abort_dummy;
5003 jit_tls->end_of_stack = stack_start;
5005 lmf = g_new0 (MonoLMF, 1);
5012 mono_add_patch_info (MonoCompile *cfg, int ip, MonoJumpInfoType type, gconstpointer target)
5014 MonoJumpInfo *ji = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfo));
5018 ji->data.target = target;
5019 ji->next = cfg->patch_info;
5021 cfg->patch_info = ji;
5025 mono_remove_patch_info (MonoCompile *cfg, int ip)
5027 MonoJumpInfo **ji = &cfg->patch_info;
5030 if ((*ji)->ip.i == ip)
5033 ji = &((*ji)->next);
5038 dec_foreach (MonoInst *tree, MonoCompile *cfg) {
5039 MonoJitICallInfo *info;
5041 switch (mono_burg_arity [tree->opcode]) {
5044 dec_foreach (tree->inst_left, cfg);
5046 if ((info = mono_find_jit_opcode_emulation (tree->opcode))) {
5047 MonoInst *iargs [2];
5049 iargs [0] = tree->inst_left;
5051 mono_emulate_opcode (cfg, tree, iargs, info);
5057 if ((info = mono_find_jit_opcode_emulation (tree->opcode))) {
5058 MonoInst *iargs [2];
5060 iargs [0] = tree->inst_i0;
5061 iargs [1] = tree->inst_i1;
5063 mono_emulate_opcode (cfg, tree, iargs, info);
5065 dec_foreach (iargs [0], cfg);
5066 dec_foreach (iargs [1], cfg);
5069 dec_foreach (tree->inst_left, cfg);
5070 dec_foreach (tree->inst_right, cfg);
5074 g_assert_not_reached ();
5076 decompose_foreach (tree, cfg);
5080 decompose_pass (MonoCompile *cfg) {
5083 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
5086 cfg->prev_ins = NULL;
5087 for (tree = cfg->cbb->code; tree; tree = tree->next) {
5088 dec_foreach (tree, cfg);
5089 cfg->prev_ins = tree;
5095 nullify_basic_block (MonoBasicBlock *bb)
5102 bb->code = bb->last_ins = NULL;
5106 replace_basic_block (MonoBasicBlock *bb, MonoBasicBlock *orig, MonoBasicBlock *repl)
5110 for (i = 0; i < bb->out_count; i++) {
5111 MonoBasicBlock *ob = bb->out_bb [i];
5112 for (j = 0; j < ob->in_count; j++) {
5113 if (ob->in_bb [j] == orig)
5114 ob->in_bb [j] = repl;
5121 merge_basic_blocks (MonoBasicBlock *bb, MonoBasicBlock *bbn)
5123 bb->out_count = bbn->out_count;
5124 bb->out_bb = bbn->out_bb;
5126 replace_basic_block (bb, bbn, bb);
5130 bb->last_ins->next = bbn->code;
5131 bb->last_ins = bbn->last_ins;
5134 bb->code = bbn->code;
5135 bb->last_ins = bbn->last_ins;
5137 bb->next_bb = bbn->next_bb;
5138 nullify_basic_block (bbn);
5142 optimize_branches (MonoCompile *cfg) {
5143 int changed = FALSE;
5144 MonoBasicBlock *bb, *bbn;
5149 /* we skip the entry block (exit is handled specially instead ) */
5150 for (bb = cfg->bb_entry->next_bb; bb; bb = bb->next_bb) {
5152 /* dont touch code inside exception clauses */
5153 if (bb->region != -1)
5156 if (bb->out_count == 1) {
5157 bbn = bb->out_bb [0];
5159 if (bb->region == bbn->region && bb->next_bb == bbn) {
5160 /* the block are in sequence anyway ... */
5163 * miguel: I do not understand what the test below does, could we
5164 * use a macro, or a comment here? opcode > CEE_BEQ && <= BLT_UN
5166 * It could also test for bb->last_in only once, and the value
5167 * could be cached (last_ins->opcode)
5169 if (bb->last_ins && (bb->last_ins->opcode == CEE_BR || (
5170 (bb->last_ins && bb->last_ins->opcode >= CEE_BEQ && bb->last_ins->opcode <= CEE_BLT_UN)))) {
5171 bb->last_ins->opcode = CEE_NOP;
5173 if (cfg->verbose_level > 2)
5174 g_print ("br removal triggered %d -> %d\n", bb->block_num, bbn->block_num);
5176 /* fixme: this causes problems with inlining */
5177 if (bbn->in_count == 1) {
5179 if (bbn != cfg->bb_exit) {
5180 if (cfg->verbose_level > 2)
5181 g_print ("block merge triggered %d -> %d\n", bb->block_num, bbn->block_num);
5182 merge_basic_blocks (bb, bbn);
5186 //mono_print_bb_code (bb);
5189 if (bb->last_ins && bb->last_ins->opcode == CEE_BR) {
5190 bbn = bb->last_ins->inst_target_bb;
5191 if (bb->region == bbn->region && bbn->code && bbn->code->opcode == CEE_BR) {
5193 if (cfg->verbose_level > 2)
5194 g_print ("in %s branch to branch triggered %d -> %d\n", cfg->method->name, bb->block_num, bbn->block_num);
5195 bb->out_bb [0] = bb->last_ins->inst_target_bb = bbn->code->inst_target_bb;
5200 } else if (bb->out_count == 2) {
5201 /* fixme: this does not correctly unlink the blocks, so we get serious problems in idom code */
5202 if (0 && bb->last_ins && bb->last_ins->opcode >= CEE_BEQ && bb->last_ins->opcode <= CEE_BLT_UN) {
5203 bbn = bb->last_ins->inst_true_bb;
5204 if (bb->region == bbn->region && bbn->code && bbn->code->opcode == CEE_BR) {
5205 if (cfg->verbose_level > 2)
5206 g_print ("cbranch to branch triggered %d -> %d (0x%02x)\n", bb->block_num,
5207 bbn->block_num, bbn->code->opcode);
5209 if (bb->out_bb [0] == bbn) {
5210 bb->out_bb [0] = bbn->code->inst_target_bb;
5211 } else if (bb->out_bb [1] == bbn) {
5212 bb->out_bb [1] = bbn->code->inst_target_bb;
5214 bb->last_ins->inst_true_bb = bbn->code->inst_target_bb;
5224 mono_compile_create_vars (MonoCompile *cfg)
5226 MonoMethodSignature *sig;
5227 MonoMethodHeader *header;
5230 header = ((MonoMethodNormal *)cfg->method)->header;
5232 sig = cfg->method->signature;
5234 if (!MONO_TYPE_IS_VOID (sig->ret)) {
5235 cfg->ret = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst));
5236 cfg->ret->opcode = OP_RETARG;
5237 cfg->ret->inst_vtype = sig->ret;
5238 cfg->ret->klass = mono_class_from_mono_type (sig->ret);
5242 mono_compile_create_var (cfg, &cfg->method->klass->this_arg, OP_ARG);
5244 for (i = 0; i < sig->param_count; ++i)
5245 mono_compile_create_var (cfg, sig->params [i], OP_ARG);
5247 cfg->locals_start = cfg->num_varinfo;
5249 for (i = 0; i < header->num_locals; ++i)
5250 mono_compile_create_var (cfg, header->locals [i], OP_LOCAL);
5255 mono_print_code (MonoCompile *cfg)
5259 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
5260 MonoInst *tree = bb->code;
5265 g_print ("CODE BLOCK %d (nesting %d):\n", bb->block_num, bb->nesting);
5267 for (; tree; tree = tree->next) {
5268 mono_print_tree (tree);
5273 bb->last_ins->next = NULL;
5278 extern const char * const mono_burg_rule_string [];
5281 emit_state (MonoCompile *cfg, MBState *state, int goal)
5284 int ern = mono_burg_rule (state, goal);
5285 const guint16 *nts = mono_burg_nts [ern];
5288 //g_print ("rule: %s\n", mono_burg_rule_string [ern]);
5292 // state->reg1 = state->reg2; /* chain rule */
5294 state->reg1 = mono_regstate_next_int (cfg->rs);
5295 //g_print ("alloc symbolic R%d (reg2: R%d) in block %d\n", state->reg1, state->reg2, cfg->cbb->block_num);
5298 state->reg1 = mono_regstate_next_int (cfg->rs);
5299 state->reg2 = mono_regstate_next_int (cfg->rs);
5302 state->reg1 = mono_regstate_next_float (cfg->rs);
5309 mono_burg_kids (state, ern, kids);
5311 emit_state (cfg, kids [0], nts [0]);
5313 emit_state (cfg, kids [1], nts [1]);
5315 g_assert (!nts [3]);
5316 emit_state (cfg, kids [2], nts [2]);
5321 // g_print ("emit: %s (%p)\n", mono_burg_rule_string [ern], state);
5322 if ((emit = mono_burg_func [ern]))
5323 emit (state, state->tree, cfg);
5326 #define DEBUG_SELECTION
5329 mini_select_instructions (MonoCompile *cfg)
5333 cfg->state_pool = mono_mempool_new ();
5334 cfg->rs = mono_regstate_new ();
5336 #ifdef DEBUG_SELECTION
5337 if (cfg->verbose_level >= 4) {
5338 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
5339 MonoInst *tree = bb->code;
5340 g_print ("DUMP BLOCK %d:\n", bb->block_num);
5343 for (; tree; tree = tree->next) {
5344 mono_print_tree (tree);
5351 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
5352 MonoInst *tree = bb->code, *next;
5358 bb->last_ins = NULL;
5361 mono_regstate_reset (cfg->rs);
5363 #ifdef DEBUG_SELECTION
5364 if (cfg->verbose_level >= 3)
5365 g_print ("LABEL BLOCK %d:\n", bb->block_num);
5367 for (; tree; tree = next) {
5369 #ifdef DEBUG_SELECTION
5370 if (cfg->verbose_level >= 3) {
5371 mono_print_tree (tree);
5376 if (!(mbstate = mono_burg_label (tree, cfg))) {
5377 g_warning ("unabled to label tree %p", tree);
5378 mono_print_tree (tree);
5380 g_assert_not_reached ();
5382 emit_state (cfg, mbstate, MB_NTERM_stmt);
5384 bb->max_ireg = cfg->rs->next_vireg;
5385 bb->max_freg = cfg->rs->next_vfreg;
5388 bb->last_ins->next = NULL;
5390 mono_mempool_empty (cfg->state_pool);
5392 mono_mempool_destroy (cfg->state_pool);
5396 mono_codegen (MonoCompile *cfg)
5398 MonoJumpInfo *patch_info;
5400 int i, max_epilog_size;
5403 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
5404 cfg->spill_count = 0;
5405 /* we reuse dfn here */
5406 /* bb->dfn = bb_count++; */
5407 mono_arch_local_regalloc (cfg, bb);
5410 if (mono_trace_coverage)
5411 mono_allocate_coverage_info (cfg->method, cfg->num_bblocks);
5413 code = mono_arch_emit_prolog (cfg);
5415 if (mono_jit_profile)
5416 code = mono_arch_instrument_prolog (cfg, mono_profiler_method_enter, code, FALSE);
5418 cfg->code_len = code - cfg->native_code;
5419 cfg->prolog_end = cfg->code_len;
5421 mono_debug_open_method (cfg);
5423 /* emit code all basic blocks */
5424 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
5425 bb->native_offset = cfg->code_len;
5426 mono_arch_output_basic_block (cfg, bb);
5428 cfg->bb_exit->native_offset = cfg->code_len;
5430 code = cfg->native_code + cfg->code_len;
5432 max_epilog_size = mono_arch_max_epilog_size (cfg);
5434 /* we always allocate code in cfg->domain->code_mp to increase locality */
5435 cfg->code_size = cfg->code_len + max_epilog_size;
5436 /* fixme: align to MONO_ARCH_CODE_ALIGNMENT */
5437 code = mono_mempool_alloc (cfg->domain->code_mp, cfg->code_size);
5438 memcpy (code, cfg->native_code, cfg->code_len);
5439 g_free (cfg->native_code);
5440 cfg->native_code = code;
5441 code = cfg->native_code + cfg->code_len;
5443 /* g_assert (((int)cfg->native_code & (MONO_ARCH_CODE_ALIGNMENT - 1)) == 0); */
5445 cfg->epilog_begin = cfg->code_len;
5447 if (mono_jit_profile)
5448 code = mono_arch_instrument_epilog (cfg, mono_profiler_method_leave, code, FALSE);
5450 cfg->code_len = code - cfg->native_code;
5452 mono_arch_emit_epilog (cfg);
5454 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5455 switch (patch_info->type) {
5456 case MONO_PATCH_INFO_ABS: {
5457 MonoJitICallInfo *info = mono_find_jit_icall_by_addr (patch_info->data.target);
5459 //printf ("TEST %s %p\n", info->name, patch_info->data.target);
5460 patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
5461 patch_info->data.name = info->name;
5465 case MONO_PATCH_INFO_SWITCH: {
5466 gpointer *table = g_new (gpointer, patch_info->table_size);
5467 patch_info->ip.i = patch_info->ip.label->inst_c0;
5468 for (i = 0; i < patch_info->table_size; i++) {
5469 table [i] = (gpointer)patch_info->data.table [i]->native_offset;
5471 patch_info->data.target = table;
5480 if (cfg->verbose_level > 1)
5481 g_print ("Method %s::%s emmitted at %p to %p\n", cfg->method->klass->name,
5482 cfg->method->name, cfg->native_code, cfg->native_code + cfg->code_len);
5484 mono_arch_patch_code (cfg->method, cfg->domain, cfg->native_code, cfg->patch_info);
5486 mono_debug_close_method (cfg);
5490 mono_cprop_copy_values (MonoCompile *cfg, MonoInst *tree, MonoInst **acp)
5495 if (tree->ssa_op == MONO_SSA_LOAD && (tree->inst_i0->opcode == OP_LOCAL || tree->inst_i0->opcode == OP_ARG) &&
5496 (cp = acp [tree->inst_i0->inst_c0]) && !tree->inst_i0->flags) {
5498 if (cp->opcode == OP_ICONST) {
5499 if (cfg->opt & MONO_OPT_CONSPROP) {
5500 //{ static int c = 0; printf ("CCOPY %d %d %s\n", c++, cp->inst_c0, mono_method_full_name (cfg->method, TRUE)); }
5504 if (tree->inst_i0->inst_vtype->type == cp->inst_vtype->type) {
5505 if (cfg->opt & MONO_OPT_COPYPROP) {
5506 //{ static int c = 0; printf ("VCOPY %d\n", ++c); }
5512 arity = mono_burg_arity [tree->opcode];
5515 mono_cprop_copy_values (cfg, tree->inst_i0, acp);
5516 if (cfg->opt & MONO_OPT_CFOLD)
5517 mono_constant_fold_inst (tree, NULL);
5519 mono_cprop_copy_values (cfg, tree->inst_i1, acp);
5520 if (cfg->opt & MONO_OPT_CFOLD)
5521 mono_constant_fold_inst (tree, NULL);
5523 mono_constant_fold_inst (tree, NULL);
5529 mono_cprop_invalidate_values (MonoInst *tree, MonoInst **acp, int acp_size)
5533 switch (tree->opcode) {
5543 if (tree->ssa_op == MONO_SSA_NOP) {
5544 memset (acp, 0, sizeof (MonoInst *) * acp_size);
5561 case OP_VOIDCALL_REG:
5562 case OP_VOIDCALLVIRT:
5564 MonoCallInst *call = (MonoCallInst *)tree;
5565 MonoMethodSignature *sig = call->signature;
5566 int i, byref = FALSE;
5568 for (i = 0; i < sig->param_count; i++) {
5569 if (sig->params [i]->byref) {
5576 memset (acp, 0, sizeof (MonoInst *) * acp_size);
5584 arity = mono_burg_arity [tree->opcode];
5590 mono_cprop_invalidate_values (tree->inst_i0, acp, acp_size);
5593 mono_cprop_invalidate_values (tree->inst_i0, acp, acp_size);
5594 mono_cprop_invalidate_values (tree->inst_i1, acp, acp_size);
5597 g_assert_not_reached ();
5602 mono_local_cprop_bb (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst **acp, int acp_size)
5604 MonoInst *tree = bb->code;
5610 for (; tree; tree = tree->next) {
5612 mono_cprop_copy_values (cfg, tree, acp);
5614 mono_cprop_invalidate_values (tree, acp, acp_size);
5616 if (tree->ssa_op == MONO_SSA_STORE &&
5617 (tree->inst_i0->opcode == OP_LOCAL || tree->inst_i0->opcode == OP_ARG)) {
5618 MonoInst *i1 = tree->inst_i1;
5620 acp [tree->inst_i0->inst_c0] = NULL;
5622 for (i = 0; i < acp_size; i++) {
5623 if (acp [i] && acp [i]->opcode != OP_ICONST &&
5624 acp [i]->inst_c0 == tree->inst_i0->inst_c0) {
5629 if (i1->opcode == OP_ICONST) {
5630 acp [tree->inst_i0->inst_c0] = i1;
5631 //printf ("DEF1 BB%d %d\n", bb->block_num,tree->inst_i0->inst_c0);
5633 if (i1->ssa_op == MONO_SSA_LOAD &&
5634 (i1->inst_i0->opcode == OP_LOCAL || i1->inst_i0->opcode == OP_ARG) &&
5635 (i1->inst_i0->inst_c0 != tree->inst_i0->inst_c0)) {
5636 acp [tree->inst_i0->inst_c0] = i1->inst_i0;
5637 //printf ("DEF2 BB%d %d %d\n", bb->block_num,tree->inst_i0->inst_c0,i1->inst_i0->inst_c0);
5642 if (tree->opcode == CEE_BEQ) {
5643 g_assert (tree->inst_i0->opcode == OP_COMPARE);
5644 if (tree->inst_i0->inst_i0->opcode == OP_ICONST &&
5645 tree->inst_i0->inst_i1->opcode == OP_ICONST) {
5647 tree->opcode = CEE_BR;
5648 if (tree->inst_i0->inst_i0->opcode == tree->inst_i0->inst_i1->opcode) {
5649 tree->inst_target_bb = tree->inst_true_bb;
5651 tree->inst_target_bb = tree->inst_false_bb;
5660 mono_local_cprop (MonoCompile *cfg)
5665 acp = alloca (sizeof (MonoInst *) * cfg->num_varinfo);
5667 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
5668 memset (acp, 0, sizeof (MonoInst *) * cfg->num_varinfo);
5669 mono_local_cprop_bb (cfg, bb, acp, cfg->num_varinfo);
5674 mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, int parts)
5676 MonoMethodHeader *header = ((MonoMethodNormal *)method)->header;
5677 guint8 *ip = (guint8 *)header->code;
5680 int dfn = 0, i, code_size_ratio;
5682 mono_jit_stats.methods_compiled++;
5683 if (mono_jit_profile)
5684 mono_profiler_method_jit (method);
5686 cfg = g_new0 (MonoCompile, 1);
5687 cfg->method = method;
5688 cfg->mempool = mono_mempool_new ();
5690 cfg->bb_hash = g_hash_table_new (g_direct_hash, NULL);
5691 cfg->domain = domain;
5692 cfg->verbose_level = mini_verbose;
5695 * create MonoInst* which represents arguments and local variables
5697 mono_compile_create_vars (cfg);
5699 if (cfg->verbose_level > 2)
5700 g_print ("converting method %s\n", mono_method_full_name (method, TRUE));
5702 if ((i = mono_method_to_ir (cfg, method, NULL, NULL, cfg->locals_start, NULL, NULL, NULL, 0, FALSE)) < 0) {
5703 mono_destroy_compile (cfg);
5704 if (mono_jit_profile)
5705 mono_profiler_method_end_jit (method, MONO_PROFILE_FAILED);
5709 mono_jit_stats.basic_blocks += cfg->num_bblocks;
5710 mono_jit_stats.max_basic_blocks = MAX (cfg->num_bblocks, mono_jit_stats.max_basic_blocks);
5712 /*g_print ("numblocks = %d\n", cfg->num_bblocks);*/
5714 /* Depth-first ordering on basic blocks */
5715 cfg->bblocks = mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * (cfg->num_bblocks + 1));
5717 if (cfg->opt & MONO_OPT_BRANCH)
5718 optimize_branches (cfg);
5720 df_visit (cfg->bb_entry, &dfn, cfg->bblocks);
5721 if (cfg->num_bblocks != dfn + 1) {
5722 if (cfg->verbose_level > 1)
5723 g_print ("unreachable code?\n");
5724 cfg->num_bblocks = dfn + 1;
5727 if (cfg->opt & MONO_OPT_LOOP) {
5728 mono_compile_dominator_info (cfg, MONO_COMP_DOM | MONO_COMP_IDOM);
5729 mono_compute_natural_loops (cfg);
5733 /* after method_to_ir */
5737 //#define DEBUGSSA "logic_run"
5738 #define DEBUGSSA_CLASS "Tests"
5742 if (!header->num_clauses && !cfg->disable_ssa) {
5743 mono_local_cprop (cfg);
5744 mono_ssa_compute (cfg);
5748 /* fixme: add all optimizations which requires SSA */
5749 if (cfg->opt & (MONO_OPT_DEADCE)) {
5750 if (!(cfg->comp_done & MONO_COMP_SSA) && !header->num_clauses && !cfg->disable_ssa) {
5751 mono_local_cprop (cfg);
5752 mono_ssa_compute (cfg);
5754 if (cfg->verbose_level >= 2) {
5761 /* after SSA translation */
5765 if ((cfg->opt & MONO_OPT_CONSPROP) || (cfg->opt & MONO_OPT_COPYPROP)) {
5766 if (cfg->comp_done & MONO_COMP_SSA) {
5767 mono_ssa_cprop (cfg);
5769 mono_local_cprop (cfg);
5773 if (cfg->comp_done & MONO_COMP_SSA) {
5774 mono_ssa_deadce (cfg);
5776 //mono_ssa_strength_reduction (cfg);
5778 mono_ssa_remove (cfg);
5780 if (cfg->opt & MONO_OPT_BRANCH)
5781 optimize_branches (cfg);
5784 /* after SSA removal */
5788 decompose_pass (cfg);
5790 /* FIXME: disabled with exception clauses: bug #42136 */
5791 if ((!header->num_clauses) && (cfg->opt & MONO_OPT_LINEARS)) {
5794 /* fixme: maybe we can avoid to compute livenesss here if already computed ? */
5795 cfg->comp_done &= ~MONO_COMP_LIVENESS;
5796 if (!(cfg->comp_done & MONO_COMP_LIVENESS))
5797 mono_analyze_liveness (cfg);
5799 if ((vars = mono_arch_get_allocatable_int_vars (cfg))) {
5800 regs = mono_arch_get_global_int_regs (cfg);
5801 mono_linear_scan (cfg, vars, regs, &cfg->used_int_regs);
5805 //mono_print_code (cfg);
5809 /* variables are allocated after decompose, since decompose could create temps */
5810 mono_arch_allocate_vars (cfg);
5812 if (cfg->opt & MONO_OPT_CFOLD)
5813 mono_constant_fold (cfg);
5815 mini_select_instructions (cfg);
5818 if (cfg->verbose_level >= 2) {
5819 char *id = mono_method_full_name (cfg->method, FALSE);
5820 mono_disassemble_code (cfg->native_code, cfg->code_len, id + 3);
5824 jinfo = mono_mempool_alloc0 (cfg->domain->mp, sizeof (MonoJitInfo));
5826 jinfo = g_new0 (MonoJitInfo, 1);
5827 jinfo->method = method;
5828 jinfo->code_start = cfg->native_code;
5829 jinfo->code_size = cfg->code_len;
5830 jinfo->used_regs = cfg->used_int_regs;
5832 if (header->num_clauses) {
5835 jinfo->exvar_offset = cfg->exvar? cfg->exvar->inst_offset: 0;
5836 jinfo->num_clauses = header->num_clauses;
5837 jinfo->clauses = mono_mempool_alloc0 (cfg->domain->mp,
5838 sizeof (MonoJitExceptionInfo) * header->num_clauses);
5840 for (i = 0; i < header->num_clauses; i++) {
5841 MonoExceptionClause *ec = &header->clauses [i];
5842 MonoJitExceptionInfo *ei = &jinfo->clauses [i];
5843 MonoBasicBlock *tblock;
5845 ei->flags = ec->flags;
5847 if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
5848 tblock = g_hash_table_lookup (cfg->bb_hash, ip + ec->token_or_filter);
5850 ei->data.filter = cfg->native_code + tblock->native_offset;
5852 ei->data.token = ec->token_or_filter;
5855 tblock = g_hash_table_lookup (cfg->bb_hash, ip + ec->try_offset);
5857 ei->try_start = cfg->native_code + tblock->native_offset;
5858 g_assert (tblock->native_offset);
5859 tblock = g_hash_table_lookup (cfg->bb_hash, ip + ec->try_offset + ec->try_len);
5861 ei->try_end = cfg->native_code + tblock->native_offset;
5862 g_assert (tblock->native_offset);
5863 tblock = g_hash_table_lookup (cfg->bb_hash, ip + ec->handler_offset);
5865 ei->handler_start = cfg->native_code + tblock->native_offset;
5869 mono_jit_info_table_add (cfg->domain, jinfo);
5871 /* collect statistics */
5872 mono_jit_stats.allocated_code_size += cfg->code_len;
5873 code_size_ratio = cfg->code_len;
5874 if (code_size_ratio > mono_jit_stats.biggest_method_size) {
5875 mono_jit_stats.biggest_method_size = code_size_ratio;
5876 mono_jit_stats.biggest_method = method;
5878 code_size_ratio = (code_size_ratio * 100) / ((MonoMethodNormal *)method)->header->code_size;
5879 if (code_size_ratio > mono_jit_stats.max_code_size_ratio) {
5880 mono_jit_stats.max_code_size_ratio = code_size_ratio;
5881 mono_jit_stats.max_ratio_method = method;
5883 mono_jit_stats.native_code_size += cfg->code_len;
5885 if (mono_jit_profile)
5886 mono_profiler_method_end_jit (method, MONO_PROFILE_OK);
5892 mono_jit_compile_method (MonoMethod *method)
5894 /* FIXME: later copy the code from mono */
5895 MonoDomain *target_domain, *domain = mono_domain_get ();
5897 GHashTable *jit_code_hash;
5900 if (default_opt & MONO_OPT_SHARED)
5901 target_domain = mono_root_domain;
5903 target_domain = domain;
5905 jit_code_hash = target_domain->jit_code_hash;
5907 if ((code = g_hash_table_lookup (jit_code_hash, method))) {
5908 mono_jit_stats.methods_lookups++;
5912 #ifdef MONO_USE_AOT_COMPILER
5913 if (!mono_compile_aot) {
5914 mono_class_init (method->klass);
5915 if ((code = mono_aot_get_method (method))) {
5916 g_hash_table_insert (jit_code_hash, method, code);
5922 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
5923 (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
5924 if (!method->info) {
5927 if (!method->addr && (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL))
5928 mono_lookup_pinvoke_call (method);
5929 #ifdef MONO_USE_EXC_TABLES
5930 if (mono_method_blittable (method)) {
5931 method->info = method->addr;
5934 nm = mono_marshal_get_native_wrapper (method);
5935 method->info = mono_compile_method (nm);
5937 //if (mono_debug_format != MONO_DEBUG_FORMAT_NONE)
5938 //mono_debug_add_wrapper (method, nm);
5939 #ifdef MONO_USE_EXC_TABLES
5943 return method->info;
5944 } else if ((method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME)) {
5945 const char *name = method->name;
5948 if (method->klass->parent == mono_defaults.multicastdelegate_class) {
5949 if (*name == '.' && (strcmp (name, ".ctor") == 0)) {
5950 /* FIXME: uhm, we need a wrapper to handle exceptions? */
5951 return (gpointer)mono_delegate_ctor;
5952 } else if (*name == 'I' && (strcmp (name, "Invoke") == 0)) {
5953 nm = mono_marshal_get_delegate_invoke (method);
5954 return mono_jit_compile_method (nm);
5955 } else if (*name == 'B' && (strcmp (name, "BeginInvoke") == 0)) {
5956 nm = mono_marshal_get_delegate_begin_invoke (method);
5957 return mono_jit_compile_method (nm);
5958 } else if (*name == 'E' && (strcmp (name, "EndInvoke") == 0)) {
5959 nm = mono_marshal_get_delegate_end_invoke (method);
5960 return mono_jit_compile_method (nm);
5966 cfg = mini_method_compile (method, default_opt, target_domain, 0);
5967 code = cfg->native_code;
5968 mono_destroy_compile (cfg);
5970 g_hash_table_insert (jit_code_hash, method, code);
5972 /* make sure runtime_init is called */
5973 mono_class_vtable (target_domain, method->klass);
5979 * mono_jit_runtime_invoke:
5980 * @method: the method to invoke
5981 * @obj: this pointer
5982 * @params: array of parameter values.
5983 * @exc: used to catch exceptions objects
5986 mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
5989 MonoObject *(*runtime_invoke) (MonoObject *this, void **params, MonoObject **exc);
5990 invoke = mono_marshal_get_runtime_invoke (method);
5991 runtime_invoke = mono_jit_compile_method (invoke);
5992 return runtime_invoke (obj, params, exc);
5995 #ifdef PLATFORM_WIN32
5996 #define GET_CONTEXT \
5997 struct sigcontext *ctx = (struct sigcontext*)_dummy;
5999 #define GET_CONTEXT \
6000 void **_p = (void **)&_dummy; \
6001 struct sigcontext *ctx = (struct sigcontext *)++_p;
6005 sigfpe_signal_handler (int _dummy)
6010 exc = mono_get_exception_divide_by_zero ();
6012 mono_arch_handle_exception (ctx, exc, FALSE);
6016 sigill_signal_handler (int _dummy)
6020 exc = mono_get_exception_execution_engine ("SIGILL");
6022 mono_arch_handle_exception (ctx, exc, FALSE);
6026 sigsegv_signal_handler (int _dummy)
6031 exc = mono_get_exception_null_reference ();
6033 mono_arch_handle_exception (ctx, exc, FALSE);
6037 sigusr1_signal_handler (int _dummy)
6042 thread = mono_thread_current ();
6044 g_assert (thread->abort_exc);
6046 mono_arch_handle_exception (ctx, thread->abort_exc, FALSE);
6050 mono_runtime_install_handlers (void)
6052 #ifndef PLATFORM_WIN32
6053 struct sigaction sa;
6056 #ifdef PLATFORM_WIN32
6058 win32_seh_set_handler(SIGFPE, sigfpe_signal_handler);
6059 win32_seh_set_handler(SIGILL, sigill_signal_handler);
6060 win32_seh_set_handler(SIGSEGV, sigsegv_signal_handler);
6061 #else /* !PLATFORM_WIN32 */
6063 /* libpthreads has its own implementation of sigaction(),
6064 * but it seems to work well with our current exception
6065 * handlers. If not we must call syscall directly instead
6069 sa.sa_handler = sigfpe_signal_handler;
6070 sigemptyset (&sa.sa_mask);
6072 //g_assert (syscall (SYS_sigaction, SIGFPE, &sa, NULL) != -1);
6073 g_assert (sigaction (SIGFPE, &sa, NULL) != -1);
6076 sa.sa_handler = sigill_signal_handler;
6077 sigemptyset (&sa.sa_mask);
6079 //g_assert (syscall (SYS_sigaction, SIGILL, &sa, NULL) != -1);
6080 g_assert (sigaction (SIGILL, &sa, NULL) != -1);
6082 /* catch thread abort signal */
6083 sa.sa_handler = sigusr1_signal_handler;
6084 sigemptyset (&sa.sa_mask);
6086 //g_assert (syscall (SYS_sigaction, SIGILL, &sa, NULL) != -1);
6087 g_assert (sigaction (mono_thread_get_abort_signal (), &sa, NULL) != -1);
6091 sa.sa_handler = sigsegv_signal_handler;
6092 sigemptyset (&sa.sa_mask);
6094 //g_assert (syscall (SYS_sigaction, SIGSEGV, &sa, NULL) != -1);
6095 g_assert (sigaction (SIGSEGV, &sa, NULL) != -1);
6097 #endif /* PLATFORM_WIN32 */
6100 /* mono_jit_create_remoting_trampoline:
6101 * @method: pointer to the method info
6103 * Creates a trampoline which calls the remoting functions. This
6104 * is used in the vtable of transparent proxies.
6106 * Returns: a pointer to the newly created code
6109 mono_jit_create_remoting_trampoline (MonoMethod *method)
6112 guint8 *addr = NULL;
6114 if (method->signature->hasthis && (method->klass->marshalbyref || method->klass == mono_defaults.object_class)) {
6115 nm = mono_marshal_get_remoting_invoke (method);
6116 addr = mono_compile_method (nm);
6118 addr = mono_compile_method (method);
6123 static CRITICAL_SECTION ms;
6126 mini_init (const char *filename)
6130 metadata_section = &ms;
6131 InitializeCriticalSection (metadata_section);
6133 mono_jit_tls_id = TlsAlloc ();
6134 mono_thread_start_cb (GetCurrentThreadId (), (gpointer)-1, NULL);
6138 mono_runtime_install_handlers ();
6140 mono_install_compile_method (mono_jit_compile_method);
6141 mono_install_trampoline (mono_arch_create_jit_trampoline);
6142 mono_install_remoting_trampoline (mono_jit_create_remoting_trampoline);
6143 mono_install_runtime_invoke (mono_jit_runtime_invoke);
6144 mono_install_handler (mono_arch_get_throw_exception ());
6145 mono_install_stack_walk (mono_jit_walk_stack);
6146 mono_install_get_config_dir ();
6148 domain = mono_init (filename);
6151 mono_add_internal_call ("System.Diagnostics.StackFrame::get_frame_info",
6152 ves_icall_get_frame_info);
6153 mono_add_internal_call ("System.Diagnostics.StackTrace::get_trace",
6154 ves_icall_get_trace);
6155 mono_add_internal_call ("Mono.Runtime::mono_runtime_install_handlers",
6156 mono_runtime_install_handlers);
6159 create_helper_signature ();
6161 mono_arch_register_lowlevel_calls ();
6162 mono_register_jit_icall (mono_profiler_method_enter, "mono_profiler_method_enter", NULL, TRUE);
6163 mono_register_jit_icall (mono_profiler_method_leave, "mono_profiler_method_leave", NULL, TRUE);
6165 mono_register_jit_icall (mono_get_lmf_addr, "mono_get_lmf_addr", helper_sig_ptr_void, TRUE);
6166 mono_register_jit_icall (mono_domain_get, "mono_domain_get", helper_sig_domain_get, TRUE);
6168 /* fixme: we cant hanlde vararg methods this way, because the signature is not constant */
6169 //mono_register_jit_icall (ves_array_element_address, "ves_array_element_address", NULL);
6170 //mono_register_jit_icall (mono_array_new_va, "mono_array_new_va", NULL);
6172 mono_register_jit_icall (mono_arch_get_throw_exception (), "mono_arch_throw_exception", helper_sig_void_obj, TRUE);
6173 mono_register_jit_icall (mono_arch_get_throw_exception_by_name (), "mono_arch_throw_exception_by_name",
6174 helper_sig_void_ptr, TRUE);
6177 * NOTE, NOTE, NOTE, NOTE:
6178 * when adding emulation for some opcodes, remember to also add a dummy
6179 * rule to the burg files, because we need the arity information to be correct.
6181 mono_register_opcode_emulation (OP_LMUL, helper_sig_long_long_long, mono_llmult);
6182 mono_register_opcode_emulation (OP_LMUL_OVF_UN, helper_sig_long_long_long, mono_llmult_ovf_un);
6183 mono_register_opcode_emulation (OP_LMUL_OVF, helper_sig_long_long_long, mono_llmult_ovf);
6184 mono_register_opcode_emulation (OP_LDIV, helper_sig_long_long_long, mono_lldiv);
6185 mono_register_opcode_emulation (OP_LDIV_UN, helper_sig_long_long_long, mono_lldiv_un);
6186 mono_register_opcode_emulation (OP_LREM, helper_sig_long_long_long, mono_llrem);
6187 mono_register_opcode_emulation (OP_LREM_UN, helper_sig_long_long_long, mono_llrem_un);
6189 mono_register_opcode_emulation (OP_LSHL, helper_sig_long_long_int, mono_lshl);
6190 mono_register_opcode_emulation (OP_LSHR, helper_sig_long_long_int, mono_lshr);
6191 mono_register_opcode_emulation (OP_LSHR_UN, helper_sig_long_long_int, mono_lshr_un);
6193 mono_register_opcode_emulation (OP_FCONV_TO_U8, helper_sig_ulong_double, mono_fconv_u8);
6194 mono_register_opcode_emulation (OP_FCONV_TO_U4, helper_sig_uint_double, mono_fconv_u4);
6195 mono_register_opcode_emulation (OP_FCONV_TO_OVF_I8, helper_sig_long_double, mono_fconv_ovf_i8);
6196 mono_register_opcode_emulation (OP_FCONV_TO_OVF_U8, helper_sig_ulong_double, mono_fconv_ovf_u8);
6198 #if SIZEOF_VOID_P == 4
6199 mono_register_opcode_emulation (OP_FCONV_TO_U, helper_sig_uint_double, mono_fconv_u4);
6201 #warning "fixme: add opcode emulation"
6204 /* other jit icalls */
6205 mono_register_jit_icall (mono_class_static_field_address , "mono_class_static_field_address",
6206 helper_sig_ptr_ptr_ptr, FALSE);
6207 mono_register_jit_icall (mono_ldtoken_wrapper, "mono_ldtoken_wrapper", helper_sig_ptr_ptr_ptr, FALSE);
6208 mono_register_jit_icall (mono_ldstr, "mono_ldstr", helper_sig_ldstr, FALSE);
6209 mono_register_jit_icall (helper_memcpy, "helper_memcpy", helper_sig_memcpy, FALSE);
6210 mono_register_jit_icall (helper_memset, "helper_memset", helper_sig_memset, FALSE);
6211 mono_register_jit_icall (helper_initobj, "helper_initobj", helper_sig_initobj, FALSE);
6212 mono_register_jit_icall (helper_stelem_ref, "helper_stelem_ref", helper_sig_stelem_ref, FALSE);
6213 mono_register_jit_icall (mono_object_new, "mono_object_new", helper_sig_object_new, FALSE);
6214 mono_register_jit_icall (mono_object_new_specific, "mono_object_new_specific", helper_sig_object_new_specific, FALSE);
6215 mono_register_jit_icall (mono_array_new, "mono_array_new", helper_sig_newarr, FALSE);
6216 mono_register_jit_icall (mono_array_new_specific, "mono_array_new_specific", helper_sig_newarr_specific, FALSE);
6217 mono_register_jit_icall (mono_string_to_utf16, "mono_string_to_utf16", helper_sig_ptr_obj, FALSE);
6218 mono_register_jit_icall (mono_string_from_utf16, "mono_string_from_utf16", helper_sig_obj_ptr, FALSE);
6219 mono_register_jit_icall (mono_string_new_wrapper, "mono_string_new_wrapper", helper_sig_obj_ptr, FALSE);
6220 mono_register_jit_icall (mono_string_to_utf8, "mono_string_to_utf8", helper_sig_ptr_obj, FALSE);
6221 mono_register_jit_icall (mono_string_to_bstr, "mono_string_to_bstr", helper_sig_ptr_obj, FALSE);
6222 mono_register_jit_icall (mono_string_to_ansibstr, "mono_string_to_ansibstr", helper_sig_ptr_obj, FALSE);
6223 mono_register_jit_icall (mono_string_builder_to_utf8, "mono_string_builder_to_utf8", helper_sig_ptr_obj, FALSE);
6224 mono_register_jit_icall (mono_array_to_savearray, "mono_array_to_savearray", helper_sig_ptr_obj, FALSE);
6225 mono_register_jit_icall (mono_array_to_lparray, "mono_array_to_lparray", helper_sig_ptr_obj, FALSE);
6226 mono_register_jit_icall (mono_delegate_to_ftnptr, "mono_delegate_to_ftnptr", helper_sig_ptr_obj, FALSE);
6227 mono_register_jit_icall (mono_marshal_string_array, "mono_marshal_string_array", helper_sig_ptr_obj, FALSE);
6228 mono_register_jit_icall (mono_string_utf8_to_builder, "mono_string_utf8_to_builder", helper_sig_void_ptr_ptr, FALSE);
6229 mono_register_jit_icall (mono_marshal_free_array, "mono_marshal_free_array", helper_sig_void_ptr_ptr, FALSE);
6230 mono_register_jit_icall (mono_string_to_byvalstr, "mono_string_to_byvalstr", helper_sig_void_ptr_ptr_ptr, FALSE);
6231 mono_register_jit_icall (mono_string_to_byvalwstr, "mono_string_to_byvalwstr", helper_sig_void_ptr_ptr_ptr, FALSE);
6232 mono_register_jit_icall (g_free, "g_free", helper_sig_void_ptr, FALSE);
6233 mono_register_jit_icall (mono_ldftn, "mono_ldftn", helper_sig_compile, FALSE);
6234 mono_register_jit_icall (mono_ldvirtfn, "mono_ldvirtfn", helper_sig_compile_virt, FALSE);
6236 mono_runtime_init (domain, mono_thread_start_cb,
6237 mono_thread_attach_cb);
6239 //mono_thread_attach (domain);
6243 MonoJitStats mono_jit_stats = {0};
6246 print_jit_stats (void)
6248 if (mono_jit_stats.enabled) {
6249 g_print ("Mono Jit statistics\n");
6250 g_print ("Compiled methods: %ld\n", mono_jit_stats.methods_compiled);
6251 g_print ("Methods from AOT: %ld\n", mono_jit_stats.methods_aot);
6252 g_print ("Methods cache lookup: %ld\n", mono_jit_stats.methods_lookups);
6253 g_print ("Method trampolines: %ld\n", mono_jit_stats.method_trampolines);
6254 g_print ("Basic blocks: %ld\n", mono_jit_stats.basic_blocks);
6255 g_print ("Max basic blocks: %ld\n", mono_jit_stats.max_basic_blocks);
6256 g_print ("Allocated vars: %ld\n", mono_jit_stats.allocate_var);
6257 g_print ("Analyze stack repeat: %ld\n", mono_jit_stats.analyze_stack_repeat);
6258 g_print ("Compiled CIL code size: %ld\n", mono_jit_stats.cil_code_size);
6259 g_print ("Native code size: %ld\n", mono_jit_stats.native_code_size);
6260 g_print ("Max code size ratio: %.2f (%s::%s)\n", mono_jit_stats.max_code_size_ratio/100.0,
6261 mono_jit_stats.max_ratio_method->klass->name, mono_jit_stats.max_ratio_method->name);
6262 g_print ("Biggest method: %ld (%s::%s)\n", mono_jit_stats.biggest_method_size,
6263 mono_jit_stats.biggest_method->klass->name, mono_jit_stats.biggest_method->name);
6264 g_print ("Code reallocs: %ld\n", mono_jit_stats.code_reallocs);
6265 g_print ("Allocated code size: %ld\n", mono_jit_stats.allocated_code_size);
6266 g_print ("Inlineable methods: %ld\n", mono_jit_stats.inlineable_methods);
6267 g_print ("Inlined methods: %ld\n", mono_jit_stats.inlined_methods);
6269 g_print ("\nCreated object count: %ld\n", mono_stats.new_object_count);
6270 g_print ("Initialized classes: %ld\n", mono_stats.initialized_class_count);
6271 g_print ("Used classes: %ld\n", mono_stats.used_class_count);
6272 g_print ("Static data size: %ld\n", mono_stats.class_static_data_size);
6273 g_print ("VTable data size: %ld\n", mono_stats.class_vtable_size);
6278 mini_cleanup (MonoDomain *domain)
6281 * mono_runtime_cleanup() and mono_domain_finalize () need to
6282 * be called early since they need the execution engine still
6283 * fully working (mono_domain_finalize may invoke managed finalizers
6284 * and mono_runtime_cleanup will wait for other threads to finish).
6286 mono_domain_finalize (domain);
6288 mono_runtime_cleanup (domain);
6290 mono_profiler_shutdown ();
6292 mono_debug_cleanup ();
6293 #ifdef PLATFORM_WIN32
6294 win32_seh_cleanup();
6297 mono_domain_unload (domain, TRUE);
6300 DeleteCriticalSection (metadata_section);
6304 mono_set_defaults (int verbose_level, guint32 opts)
6306 mini_verbose = verbose_level;