e687586446956e49f6c7bf515c78d480e090fcc2
[mono.git] / mono / mini / mini.c
1 /*
2  * mini.c: The new Mono code generator.
3  *
4  * Author:
5  *   Paolo Molaro (lupus@ximian.com)
6  *   Dietmar Maurer (dietmar@ximian.com)
7  *
8  * (C) 2002 Ximian, Inc.
9  */
10
11 #include <config.h>
12 #include <signal.h>
13 #include <unistd.h>
14
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>
38
39 #include "mini.h"
40 #include <string.h>
41 #include <ctype.h>
42 #include "inssel.h"
43
44 #include "jit-icalls.c"
45
46 #define MONO_CHECK_THIS(ins) (cfg->method->signature->hasthis && (ins)->ssa_op == MONO_SSA_LOAD && (ins)->inst_left->inst_c0 == 0)
47
48 static gpointer mono_jit_compile_method (MonoMethod *method);
49
50 static void handle_stobj (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *dest, MonoInst *src, 
51                           const unsigned char *ip, MonoClass *klass, gboolean to_end, gboolean native);
52
53 static int mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock, 
54                    int locals_offset, MonoInst *return_var, GList *dont_inline, MonoInst **inline_args, 
55                    guint inline_offset);
56
57 extern guint8 mono_burg_arity [];
58 /* helper methods signature */
59 static MonoMethodSignature *helper_sig_long_long_long = NULL;
60 static MonoMethodSignature *helper_sig_long_long_int = NULL;
61 static MonoMethodSignature *helper_sig_newarr = NULL;
62 static MonoMethodSignature *helper_sig_ldstr = NULL;
63 static MonoMethodSignature *helper_sig_domain_get = NULL;
64 static MonoMethodSignature *helper_sig_object_new = NULL;
65 static MonoMethodSignature *helper_sig_compile = NULL;
66 static MonoMethodSignature *helper_sig_compile_virt = NULL;
67 static MonoMethodSignature *helper_sig_obj_ptr = NULL;
68 static MonoMethodSignature *helper_sig_ptr_void = NULL;
69 static MonoMethodSignature *helper_sig_void_ptr = NULL;
70 static MonoMethodSignature *helper_sig_void_obj = NULL;
71 static MonoMethodSignature *helper_sig_void_ptr_ptr = NULL;
72 static MonoMethodSignature *helper_sig_void_ptr_ptr_ptr = NULL;
73 static MonoMethodSignature *helper_sig_ptr_ptr_ptr = NULL;
74 static MonoMethodSignature *helper_sig_ptr_obj = NULL;
75 static MonoMethodSignature *helper_sig_initobj = NULL;
76 static MonoMethodSignature *helper_sig_memcpy = NULL;
77 static MonoMethodSignature *helper_sig_memset = NULL;
78 static MonoMethodSignature *helper_sig_ulong_double = NULL;
79 static MonoMethodSignature *helper_sig_long_double = NULL;
80 static MonoMethodSignature *helper_sig_uint_double = NULL;
81 static MonoMethodSignature *helper_sig_int_double = NULL;
82 static MonoMethodSignature *helper_sig_stelem_ref = NULL;
83
84 static guint32 default_opt = MONO_OPT_PEEPHOLE;
85
86 guint32 mono_jit_tls_id = 0;
87 gboolean mono_jit_trace_calls = FALSE;
88 gboolean mono_break_on_exc = FALSE;
89 gboolean mono_compile_aot = FALSE;
90 gboolean mono_trace_coverage = FALSE;
91 gboolean mono_jit_profile = FALSE;
92 MonoDebugFormat mono_debug_format = MONO_DEBUG_FORMAT_NONE;
93
94 CRITICAL_SECTION *metadata_section = NULL;
95
96 static int mini_verbose = 0;
97
98 #ifdef MONO_USE_EXC_TABLES
99 static gboolean
100 mono_type_blittable (MonoType *type)
101 {
102         if (type->byref)
103                 return FALSE;
104
105         switch (type->type){
106         case MONO_TYPE_VOID:
107         case MONO_TYPE_I1:
108         case MONO_TYPE_U1:
109         case MONO_TYPE_I2:
110         case MONO_TYPE_U2:
111         case MONO_TYPE_I4:
112         case MONO_TYPE_U4:
113         case MONO_TYPE_I8:
114         case MONO_TYPE_U8:
115         case MONO_TYPE_R4:
116         case MONO_TYPE_R8:
117         case MONO_TYPE_I:
118         case MONO_TYPE_U:
119         case MONO_TYPE_OBJECT:
120                 return TRUE;
121         case MONO_TYPE_VALUETYPE:
122         case MONO_TYPE_CLASS:
123                 return type->data.klass->blittable;
124                 break;
125         default:
126                 break;
127         }
128
129         return FALSE;
130 }
131
132 gboolean
133 mono_method_blittable (MonoMethod *method)
134 {
135         MonoMethodSignature *sig;
136         int i;
137
138         if (!method->addr)
139                 return FALSE;
140
141         if (!mono_arch_has_unwind_info (method->addr)) {
142                 return FALSE;
143         }
144
145         if (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL)
146                 return TRUE;
147
148         sig = method->signature;
149
150         if (!mono_type_blittable (sig->ret))
151                 return FALSE;
152
153         for (i = 0; i < sig->param_count; i++)
154                 if (!mono_type_blittable (sig->params [i]))
155                         return FALSE;
156
157         return TRUE;
158 }
159 #endif
160
161 /* debug function */
162 static void
163 print_method_from_ip (void *ip)
164 {
165         MonoJitInfo *ji;
166         char *method;
167         
168         ji = mono_jit_info_table_find (mono_domain_get (), ip);
169         if (!ji) {
170                 g_print ("No method at %p\n", ip);
171                 return;
172         }
173         method = mono_method_full_name (ji->method, TRUE);
174         g_print ("IP at offset 0x%x of method %s (%p %p)\n", (char*)ip - (char*)ji->code_start, method, ji->code_start, (char*)ji->code_start + ji->code_size);
175         g_free (method);
176
177 }
178
179 #define MONO_INIT_VARINFO(vi,id) do { \
180         (vi)->range.first_use.pos.bid = 0xffff; \
181         (vi)->reg = -1; \
182         (vi)->idx = (id); \
183 } while (0)
184
185 /*
186  * Basic blocks have two numeric identifiers:
187  * dfn: Depth First Number
188  * block_num: unique ID assigned at bblock creation
189  */
190 #define NEW_BBLOCK(cfg) (mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock)))
191 #define ADD_BBLOCK(cfg,bbhash,b) do {   \
192                 g_hash_table_insert (bbhash, (b)->cil_code, (b));       \
193                 (b)->block_num = cfg->num_bblocks++;    \
194                 (b)->real_offset = real_offset; \
195         } while (0)
196
197 #define GET_BBLOCK(cfg,bbhash,tblock,ip) do {   \
198                 (tblock) = g_hash_table_lookup (bbhash, (ip));  \
199                 if (!(tblock)) {        \
200                         if ((ip) >= end || (ip) < header->code) goto unverified; \
201                         (tblock) = NEW_BBLOCK (cfg);    \
202                         (tblock)->cil_code = (ip);      \
203                         ADD_BBLOCK (cfg, (bbhash), (tblock));   \
204                 }       \
205                 (tblock)->real_offset = real_offset; \
206         } while (0)
207
208 #define CHECK_BBLOCK(target,ip,tblock) do {     \
209                 if ((target) < (ip) && !(tblock)->code) {       \
210                         bb_recheck = g_list_prepend (bb_recheck, (tblock));     \
211                         if (cfg->verbose_level > 2) g_print ("queued block %d for check at IL%04x from IL%04x\n", (tblock)->block_num, (target) - header->code, (ip) - header->code);   \
212                 }       \
213         } while (0)
214
215 #define NEW_ICONST(cfg,dest,val) do {   \
216                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
217                 (dest)->opcode = OP_ICONST;     \
218                 (dest)->inst_c0 = (val);        \
219                 (dest)->type = STACK_I4;        \
220         } while (0)
221
222 /* FIXME: have a different definition of NEW_PCONST for 64 bit systems */
223 #define NEW_PCONST(cfg,dest,val) do {   \
224                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
225                 (dest)->opcode = OP_ICONST;     \
226                 (dest)->inst_p0 = (val);        \
227                 (dest)->type = STACK_PTR;       \
228         } while (0)
229
230 #define NEW_CLASSCONST(cfg,dest,val) do {       \
231                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
232                 (dest)->opcode = mono_compile_aot ? OP_AOTCONST : OP_ICONST;    \
233                 (dest)->inst_p0 = (val);        \
234                 (dest)->inst_i1 = (gpointer)MONO_PATCH_INFO_CLASS; \
235                 (dest)->type = STACK_PTR;       \
236         } while (0)
237
238 #define NEW_IMAGECONST(cfg,dest,val) do {       \
239                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
240                 (dest)->opcode = mono_compile_aot ? OP_AOTCONST : OP_ICONST;    \
241                 (dest)->inst_p0 = (val);        \
242                 (dest)->inst_i1 = (gpointer)MONO_PATCH_INFO_IMAGE; \
243                 (dest)->type = STACK_PTR;       \
244         } while (0)
245
246 #define NEW_FIELDCONST(cfg,dest,field) do {     \
247                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
248                 (dest)->opcode = mono_compile_aot ? OP_AOTCONST : OP_ICONST;    \
249                 (dest)->inst_p0 = (field);      \
250                 (dest)->inst_i1 = (gpointer)MONO_PATCH_INFO_FIELD; \
251                 (dest)->type = STACK_PTR;       \
252         } while (0)
253
254 #define NEW_METHODCONST(cfg,dest,val) do {      \
255                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
256                 (dest)->opcode = mono_compile_aot ? OP_AOTCONST : OP_ICONST;    \
257                 (dest)->inst_p0 = (val);        \
258                 (dest)->inst_i1 = (gpointer)MONO_PATCH_INFO_METHODCONST; \
259                 (dest)->type = STACK_PTR;       \
260         } while (0)
261
262 #define NEW_DOMAINCONST(cfg,dest) do { \
263                if ((cfg->opt & MONO_OPT_SAHRED) || mono_compile_aot) { \
264                        NEW_TEMPLOAD (cfg, dest, mono_get_domainvar (cfg)->inst_c0); \
265                } else { \
266                        NEW_PCONST (cfg, dest, (cfg)->domain); \
267                } \
268         } while (0)
269
270 #define GET_VARINFO_INST(cfg,num) ((cfg)->varinfo [(num)]->inst)
271
272 #define NEW_ARGLOAD(cfg,dest,num) do {  \
273                 if (arg_array [(num)]->opcode == OP_ICONST) (dest) = arg_array [(num)]; else { \
274                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
275                 (dest)->ssa_op = MONO_SSA_LOAD; \
276                 (dest)->inst_i0 = arg_array [(num)];    \
277                 (dest)->opcode = mono_type_to_ldind ((dest)->inst_i0->inst_vtype);      \
278                 type_to_eval_stack_type (param_types [(num)], (dest));  \
279                 (dest)->klass = (dest)->inst_i0->klass; \
280         }} while (0)
281
282 #define NEW_LOCLOAD(cfg,dest,num) do {  \
283                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
284                 (dest)->ssa_op = MONO_SSA_LOAD; \
285                 (dest)->inst_i0 = (cfg)->varinfo [locals_offset + (num)];       \
286                 (dest)->opcode = mono_type_to_ldind ((dest)->inst_i0->inst_vtype);      \
287                 type_to_eval_stack_type (header->locals [(num)], (dest));       \
288                 (dest)->klass = (dest)->inst_i0->klass; \
289         } while (0)
290
291 #define NEW_LOCLOADA(cfg,dest,num) do { \
292                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
293                 (dest)->ssa_op = MONO_SSA_MAYBE_LOAD;   \
294                 (dest)->inst_i0 = (cfg)->varinfo [locals_offset + (num)];       \
295                 (dest)->inst_i0->flags |= MONO_INST_INDIRECT;   \
296                 (dest)->opcode = OP_LDADDR;     \
297                 (dest)->type = STACK_MP;        \
298                 (dest)->klass = (dest)->inst_i0->klass; \
299                 (cfg)->disable_ssa = TRUE; \
300         } while (0)
301
302 #define NEW_RETLOADA(cfg,dest) do {     \
303                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
304                 (dest)->ssa_op = MONO_SSA_MAYBE_LOAD;   \
305                 (dest)->inst_i0 = (cfg)->ret;   \
306                 (dest)->inst_i0->flags |= MONO_INST_INDIRECT;   \
307                 (dest)->opcode = CEE_LDIND_I;   \
308                 (dest)->type = STACK_MP;        \
309                 (dest)->klass = (dest)->inst_i0->klass; \
310                 (cfg)->disable_ssa = TRUE; \
311         } while (0)
312
313 #define NEW_ARGLOADA(cfg,dest,num) do { \
314                 if (arg_array [(num)]->opcode == OP_ICONST) goto inline_failure; \
315                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
316                 (dest)->ssa_op = MONO_SSA_MAYBE_LOAD;   \
317                 (dest)->inst_i0 = arg_array [(num)];    \
318                 (dest)->inst_i0->flags |= MONO_INST_INDIRECT;   \
319                 (dest)->opcode = OP_LDADDR;     \
320                 (dest)->type = STACK_MP;        \
321                 (dest)->klass = (dest)->inst_i0->klass; \
322                 (cfg)->disable_ssa = TRUE; \
323         } while (0)
324
325 #define NEW_TEMPLOAD(cfg,dest,num) do { \
326                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
327                 (dest)->ssa_op = MONO_SSA_LOAD; \
328                 (dest)->inst_i0 = (cfg)->varinfo [(num)];       \
329                 (dest)->opcode = mono_type_to_ldind ((dest)->inst_i0->inst_vtype);      \
330                 type_to_eval_stack_type ((dest)->inst_i0->inst_vtype, (dest));  \
331                 (dest)->klass = (dest)->inst_i0->klass; \
332         } while (0)
333
334 #define NEW_TEMPLOADA(cfg,dest,num) do {        \
335                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
336                 (dest)->ssa_op = MONO_SSA_MAYBE_LOAD;   \
337                 (dest)->inst_i0 = (cfg)->varinfo [(num)];       \
338                 (dest)->inst_i0->flags |= MONO_INST_INDIRECT;   \
339                 (dest)->opcode = OP_LDADDR;     \
340                 (dest)->type = STACK_MP;        \
341                 (dest)->klass = (dest)->inst_i0->klass; \
342                 (cfg)->disable_ssa = TRUE; \
343         } while (0)
344
345
346 #define NEW_INDLOAD(cfg,dest,addr,vtype) do {   \
347                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
348                 (dest)->inst_left = addr;       \
349                 (dest)->opcode = mono_type_to_ldind (vtype);    \
350                 type_to_eval_stack_type (vtype, (dest));        \
351                 /* FIXME: (dest)->klass = (dest)->inst_i0->klass;*/     \
352         } while (0)
353
354 #define NEW_INDSTORE(cfg,dest,addr,value,vtype) do {    \
355                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
356                 (dest)->inst_i0 = addr; \
357                 (dest)->opcode = mono_type_to_stind (vtype);    \
358                 (dest)->inst_i1 = (value);      \
359                 /* FIXME: (dest)->klass = (dest)->inst_i0->klass;*/     \
360         } while (0)
361
362 #define NEW_TEMPSTORE(cfg,dest,num,inst) do {   \
363                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
364                 (dest)->ssa_op = MONO_SSA_STORE;        \
365                 (dest)->inst_i0 = (cfg)->varinfo [(num)];       \
366                 (dest)->opcode = mono_type_to_stind ((dest)->inst_i0->inst_vtype);      \
367                 (dest)->inst_i1 = (inst);       \
368                 (dest)->klass = (dest)->inst_i0->klass; \
369         } while (0)
370
371 #define NEW_LOCSTORE(cfg,dest,num,inst) do {    \
372                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
373                 (dest)->opcode = mono_type_to_stind (header->locals [(num)]);   \
374                 (dest)->ssa_op = MONO_SSA_STORE;        \
375                 (dest)->inst_i0 = (cfg)->varinfo [locals_offset + (num)];       \
376                 (dest)->inst_i1 = (inst);       \
377                 (dest)->klass = (dest)->inst_i0->klass; \
378         } while (0)
379
380 #define NEW_ARGSTORE(cfg,dest,num,inst) do {    \
381                 if (arg_array [(num)]->opcode == OP_ICONST) goto inline_failure; \
382                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
383                 (dest)->opcode = mono_type_to_stind (param_types [(num)]);      \
384                 (dest)->ssa_op = MONO_SSA_STORE;        \
385                 (dest)->inst_i0 = arg_array [(num)];    \
386                 (dest)->inst_i1 = (inst);       \
387                 (dest)->klass = (dest)->inst_i0->klass; \
388         } while (0)
389
390 #define ADD_BINOP(op) do {      \
391                 MONO_INST_NEW (cfg, ins, (op)); \
392                 ins->cil_code = ip;     \
393                 sp -= 2;        \
394                 ins->inst_i0 = sp [0];  \
395                 ins->inst_i1 = sp [1];  \
396                 *sp++ = ins;    \
397                 type_from_op (ins);     \
398                 CHECK_TYPE (ins);       \
399         } while (0)
400
401 #define ADD_UNOP(op) do {       \
402                 MONO_INST_NEW (cfg, ins, (op)); \
403                 ins->cil_code = ip;     \
404                 sp--;   \
405                 ins->inst_i0 = sp [0];  \
406                 *sp++ = ins;    \
407                 type_from_op (ins);     \
408                 CHECK_TYPE (ins);       \
409         } while (0)
410
411 #define ADD_BINCOND(next_block) do {    \
412                 MonoInst *cmp;  \
413                 MONO_INST_NEW(cfg, cmp, OP_COMPARE);    \
414                 sp -= 2;                \
415                 cmp->inst_i0 = sp [0];  \
416                 cmp->inst_i1 = sp [1];  \
417                 cmp->cil_code = ins->cil_code;  \
418                 type_from_op (cmp);     \
419                 CHECK_TYPE (cmp);       \
420                 ins->inst_i0 = cmp;     \
421                 MONO_ADD_INS (bblock, ins);     \
422                 ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);      \
423                 GET_BBLOCK (cfg, bbhash, tblock, target);               \
424                 link_bblock (cfg, bblock, tblock);      \
425                 ins->inst_true_bb = tblock;     \
426                 CHECK_BBLOCK (target, ip, tblock);      \
427                 if ((next_block)) {     \
428                         link_bblock (cfg, bblock, (next_block));        \
429                         ins->inst_false_bb = (next_block);      \
430                         start_new_bblock = 1;   \
431                 } else {        \
432                         GET_BBLOCK (cfg, bbhash, tblock, ip);           \
433                         link_bblock (cfg, bblock, tblock);      \
434                         ins->inst_false_bb = tblock;    \
435                         start_new_bblock = 2;   \
436                 }       \
437         } while (0)
438
439 /* FIXME: handle float, long ... */
440 #define ADD_UNCOND(istrue) do { \
441                 MonoInst *cmp;  \
442                 MONO_INST_NEW(cfg, cmp, OP_COMPARE);    \
443                 sp--;           \
444                 cmp->inst_i0 = sp [0];  \
445                 switch (cmp->inst_i0->type) { \
446                 case STACK_I8: \
447                         cmp->inst_i1 = zero_int64; break; \
448                 case STACK_R8: \
449                         cmp->inst_i1 = zero_r8; break; \
450                 case STACK_PTR: \
451                 case STACK_MP: \
452                         cmp->inst_i1 = zero_ptr; break; \
453                 case STACK_OBJ: \
454                         cmp->inst_i1 = zero_obj; break; \
455                 default: \
456                         cmp->inst_i1 = zero_int32;  \
457                 }  \
458                 cmp->cil_code = ins->cil_code;  \
459                 type_from_op (cmp);     \
460                 CHECK_TYPE (cmp);       \
461                 ins->inst_i0 = cmp;     \
462                 ins->opcode = (istrue)? CEE_BNE_UN: CEE_BEQ;    \
463                 MONO_ADD_INS (bblock, ins);     \
464                 ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);      \
465                 GET_BBLOCK (cfg, bbhash, tblock, target);               \
466                 link_bblock (cfg, bblock, tblock);      \
467                 ins->inst_true_bb = tblock;     \
468                 CHECK_BBLOCK (target, ip, tblock);      \
469                 GET_BBLOCK (cfg, bbhash, tblock, ip);           \
470                 link_bblock (cfg, bblock, tblock);      \
471                 ins->inst_false_bb = tblock;    \
472                 start_new_bblock = 2;   \
473         } while (0)
474
475 #define NEW_LDELEMA(cfg,dest,sp,k) do { \
476                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
477                 (dest)->opcode = CEE_LDELEMA;   \
478                 (dest)->inst_left = (sp) [0];   \
479                 (dest)->inst_right = (sp) [1];  \
480                 (dest)->type = STACK_MP;        \
481                 (dest)->klass = (k);    \
482         } while (0)
483
484 #define NEW_GROUP(cfg,dest,el1,el2) do {        \
485                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
486                 (dest)->opcode = OP_GROUP;      \
487                 (dest)->inst_left = (el1);      \
488                 (dest)->inst_right = (el2);     \
489         } while (0)
490
491 static GHashTable *coverage_hash = NULL;
492
493 MonoCoverageInfo *
494 mono_allocate_coverage_info (MonoMethod *method, int size)
495 {
496         MonoCoverageInfo *res;
497
498         if (!coverage_hash)
499                 coverage_hash = g_hash_table_new (NULL, NULL);
500
501         res = g_malloc0 (sizeof (MonoCoverageInfo) + sizeof (int) * size * 2);
502
503         res->entries = size;
504
505         g_hash_table_insert (coverage_hash, method, res);
506
507         return res;
508 }
509
510 MonoCoverageInfo *
511 mono_get_coverage_info (MonoMethod *method)
512 {
513         if (!coverage_hash)
514                 return NULL;
515
516         return g_hash_table_lookup (coverage_hash, method);
517 }
518                 
519 #if 0
520 static gint
521 compare_bblock (gconstpointer a, gconstpointer b)
522 {
523         const MonoBasicBlock *b1 = a;
524         const MonoBasicBlock *b2 = b;
525
526         return b2->cil_code - b1->cil_code;
527 }
528 #endif
529
530 /* *
531  * link_bblock: Links two basic blocks
532  *
533  * links two basic blocks in the control flow graph, the 'from'
534  * argument is the starting block and the 'to' argument is the block
535  * the control flow ends to after 'from'.
536  */
537 static void
538 link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
539 {
540         MonoBasicBlock **newa;
541         int i, found;
542
543 #if 0
544         if (from->cil_code) {
545                 if (to->cil_code)
546                         g_print ("edge from IL%04x to IL_%04x\n", from->cil_code - cfg->cil_code, to->cil_code - cfg->cil_code);
547                 else
548                         g_print ("edge from IL%04x to exit\n", from->cil_code - cfg->cil_code);
549         } else {
550                 if (to->cil_code)
551                         g_print ("edge from entry to IL_%04x\n", to->cil_code - cfg->cil_code);
552                 else
553                         g_print ("edge from entry to exit\n");
554         }
555 #endif
556         found = FALSE;
557         for (i = 0; i < from->out_count; ++i) {
558                 if (to == from->out_bb [i]) {
559                         found = TRUE;
560                         break;
561                 }
562         }
563         if (!found) {
564                 newa = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (from->out_count + 1));
565                 for (i = 0; i < from->out_count; ++i) {
566                         newa [i] = from->out_bb [i];
567                 }
568                 newa [i] = to;
569                 from->out_count++;
570                 from->out_bb = newa;
571         }
572
573         found = FALSE;
574         for (i = 0; i < to->in_count; ++i) {
575                 if (from == to->in_bb [i]) {
576                         found = TRUE;
577                         break;
578                 }
579         }
580         if (!found) {
581                 newa = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (to->in_count + 1));
582                 for (i = 0; i < to->in_count; ++i) {
583                         newa [i] = to->in_bb [i];
584                 }
585                 newa [i] = from;
586                 to->in_count++;
587                 to->in_bb = newa;
588         }
589 }
590
591 /*
592  * We mark each basic block with a region ID. We use that to avoid BB
593  * optimizations when blocks are in different regions. 
594  */
595 static int
596 mono_find_block_region (MonoCompile *cfg, int offset, int *filter_lengths)
597 {
598         MonoMethod *method = cfg->method;
599         MonoMethodHeader *header = ((MonoMethodNormal *)method)->header;
600         MonoExceptionClause *clause;
601         int i;
602
603         /* first search for handlers and filters */
604         for (i = 0; i < header->num_clauses; ++i) {
605                 clause = &header->clauses [i];
606                 if ((clause->flags & MONO_EXCEPTION_CLAUSE_FILTER) && (offset >= clause->token_or_filter) &&
607                     (offset < (clause->token_or_filter + filter_lengths [i])))
608                         return (i << 8) | 128 | clause->flags;
609                            
610                 if (MONO_OFFSET_IN_HANDLER (clause, offset)) {
611                         return (i << 8) | 64 | clause->flags;
612                 }
613         }
614
615         /* search the try blocks */
616         for (i = 0; i < header->num_clauses; ++i) {
617                 clause = &header->clauses [i];
618                 if (MONO_OFFSET_IN_CLAUSE (clause, offset))
619                         return (i << 8) | clause->flags;
620         }
621
622         return -1;
623 }
624
625 static MonoBasicBlock *
626 mono_find_final_block (MonoCompile *cfg, unsigned char *ip, unsigned char *target, int type)
627 {
628         MonoMethod *method = cfg->method;
629         MonoMethodHeader *header = ((MonoMethodNormal *)method)->header;
630         MonoExceptionClause *clause;
631         MonoBasicBlock *handler;
632         int i;
633
634         for (i = 0; i < header->num_clauses; ++i) {
635                 clause = &header->clauses [i];
636                 if (MONO_OFFSET_IN_CLAUSE (clause, (ip - header->code)) && 
637                     (!MONO_OFFSET_IN_CLAUSE (clause, (target - header->code)))) {
638                         if (clause->flags & type) {
639                                 handler = g_hash_table_lookup (cfg->bb_hash, header->code + clause->handler_offset);
640                                 g_assert (handler);
641                                 return handler;
642                         }
643                 }
644         }
645         return NULL;
646 }
647
648
649 static void
650 df_visit (MonoBasicBlock *start, int *dfn, MonoBasicBlock **array)
651 {
652         int i;
653
654         array [*dfn] = start;
655         /*g_print ("visit %d at %p\n", *dfn, start->cil_code);*/
656         for (i = 0; i < start->out_count; ++i) {
657                 if (start->out_bb [i]->dfn)
658                         continue;
659                 (*dfn)++;
660                 start->out_bb [i]->dfn = *dfn;
661                 start->out_bb [i]->df_parent = start;
662                 array [*dfn] = start->out_bb [i];
663                 df_visit (start->out_bb [i], dfn, array);
664         }
665 }
666
667 typedef struct {
668         const guchar *code;
669         MonoBasicBlock *best;
670 } PrevStruct;
671
672 static void
673 previous_foreach (gconstpointer key, gpointer val, gpointer data)
674 {
675         PrevStruct *p = data;
676         MonoBasicBlock *bb = val;
677         //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,
678         //bb->method == p->best->method, bb->cil_code < p->code, bb->cil_code > p->best->cil_code);
679
680         if (bb->cil_code && bb->cil_code < p->code && bb->cil_code > p->best->cil_code)
681                 p->best = bb;
682 }
683
684 static MonoBasicBlock*
685 find_previous (GHashTable *bb_hash, MonoBasicBlock *start, const guchar *code) {
686         PrevStruct p;
687
688         p.code = code;
689         p.best = start;
690
691         g_hash_table_foreach (bb_hash, (GHFunc)previous_foreach, &p);
692         return p.best;
693 }
694
695 static void
696 split_bblock (MonoCompile *cfg, MonoBasicBlock *first, MonoBasicBlock *second) {
697         int i, j;
698         MonoInst *inst;
699         MonoBasicBlock *bb;
700
701         if (second->code)
702                 return;
703         
704         /* 
705          * FIXME: take into account all the details:
706          * second may have been the target of more than one bblock
707          */
708         second->out_count = first->out_count;
709         second->out_bb = first->out_bb;
710
711         for (i = 0; i < first->out_count; ++i) {
712                 bb = first->out_bb [i];
713                 for (j = 0; j < bb->in_count; ++j) {
714                         if (bb->in_bb [j] == first)
715                                 bb->in_bb [j] = second;
716                 }
717         }
718
719         first->out_count = 0;
720         first->out_bb = NULL;
721         link_bblock (cfg, first, second);
722
723         second->last_ins = first->last_ins;
724
725         /*g_print ("start search at %p for %p\n", first->cil_code, second->cil_code);*/
726         for (inst = first->code; inst && inst->next; inst = inst->next) {
727                 /*char *code = mono_disasm_code_one (NULL, cfg->method, inst->next->cil_code, NULL);
728                 g_print ("found %p: %s", inst->next->cil_code, code);
729                 g_free (code);*/
730                 if (inst->cil_code < second->cil_code && inst->next->cil_code >= second->cil_code) {
731                         second->code = inst->next;
732                         inst->next = NULL;
733                         first->last_ins = inst;
734                         second->next_bb = first->next_bb;
735                         first->next_bb = second;
736                         return;
737                 }
738         }
739         if (!second->code) {
740                 g_warning ("bblock split failed in %s::%s\n", cfg->method->klass->name, cfg->method->name);
741                 //G_BREAKPOINT ();
742         }
743 }
744
745 guint
746 mono_type_to_ldind (MonoType *type)
747 {
748         int t = type->type;
749
750         if (type->byref)
751                 return CEE_LDIND_I;
752
753 handle_enum:
754         switch (t) {
755         case MONO_TYPE_I1:
756                 return CEE_LDIND_I1;
757         case MONO_TYPE_U1:
758         case MONO_TYPE_BOOLEAN:
759                 return CEE_LDIND_U1;
760         case MONO_TYPE_I2:
761                 return CEE_LDIND_I2;
762         case MONO_TYPE_U2:
763         case MONO_TYPE_CHAR:
764                 return CEE_LDIND_U2;
765         case MONO_TYPE_I4:
766                 return CEE_LDIND_I4;
767         case MONO_TYPE_U4:
768                 return CEE_LDIND_U4;
769         case MONO_TYPE_I:
770         case MONO_TYPE_U:
771         case MONO_TYPE_PTR:
772         case MONO_TYPE_FNPTR:
773                 return CEE_LDIND_I;
774         case MONO_TYPE_CLASS:
775         case MONO_TYPE_STRING:
776         case MONO_TYPE_OBJECT:
777         case MONO_TYPE_SZARRAY:
778         case MONO_TYPE_ARRAY:    
779                 return CEE_LDIND_REF;
780         case MONO_TYPE_I8:
781         case MONO_TYPE_U8:
782                 return CEE_LDIND_I8;
783         case MONO_TYPE_R4:
784                 return CEE_LDIND_R4;
785         case MONO_TYPE_R8:
786                 return CEE_LDIND_R8;
787         case MONO_TYPE_VALUETYPE:
788                 if (type->data.klass->enumtype) {
789                         t = type->data.klass->enum_basetype->type;
790                         goto handle_enum;
791                 }
792                 return CEE_LDOBJ;
793         default:
794                 g_error ("unknown type 0x%02x in type_to_ldind", type->type);
795         }
796         return -1;
797 }
798
799 guint
800 mono_type_to_stind (MonoType *type)
801 {
802         int t = type->type;
803
804         if (type->byref)
805                 return CEE_STIND_I;
806
807 handle_enum:
808         switch (t) {
809         case MONO_TYPE_I1:
810         case MONO_TYPE_U1:
811         case MONO_TYPE_BOOLEAN:
812                 return CEE_STIND_I1;
813         case MONO_TYPE_I2:
814         case MONO_TYPE_U2:
815         case MONO_TYPE_CHAR:
816                 return CEE_STIND_I2;
817         case MONO_TYPE_I4:
818         case MONO_TYPE_U4:
819                 return CEE_STIND_I4;
820         case MONO_TYPE_I:
821         case MONO_TYPE_U:
822         case MONO_TYPE_PTR:
823         case MONO_TYPE_FNPTR:
824                 return CEE_STIND_I;
825         case MONO_TYPE_CLASS:
826         case MONO_TYPE_STRING:
827         case MONO_TYPE_OBJECT:
828         case MONO_TYPE_SZARRAY:
829         case MONO_TYPE_ARRAY:    
830                 return CEE_STIND_REF;
831         case MONO_TYPE_I8:
832         case MONO_TYPE_U8:
833                 return CEE_STIND_I8;
834         case MONO_TYPE_R4:
835                 return CEE_STIND_R4;
836         case MONO_TYPE_R8:
837                 return CEE_STIND_R8;
838         case MONO_TYPE_VALUETYPE:
839                 if (type->data.klass->enumtype) {
840                         t = type->data.klass->enum_basetype->type;
841                         goto handle_enum;
842                 }
843                 return CEE_STOBJ;
844                 /* fail right now */
845         default:
846                 g_error ("unknown type %02x in type_to_stind", type->type);
847         }
848         return -1;
849 }
850
851 /*
852  * Returns the type used in the eval stack when @type is loaded.
853  * FIXME: return a MonoType/MonoClass for the byref and VALUETYPE cases.
854  */
855 static void
856 type_to_eval_stack_type (MonoType *type, MonoInst *inst) {
857         int t = type->type;
858
859         if (type->byref) {
860                 inst->type = STACK_MP;
861                 return;
862         }
863
864 handle_enum:
865         switch (t) {
866         case MONO_TYPE_I1:
867         case MONO_TYPE_U1:
868         case MONO_TYPE_BOOLEAN:
869         case MONO_TYPE_I2:
870         case MONO_TYPE_U2:
871         case MONO_TYPE_CHAR:
872         case MONO_TYPE_I4:
873         case MONO_TYPE_U4:
874                 inst->type = STACK_I4;
875                 return;
876         case MONO_TYPE_I:
877         case MONO_TYPE_U:
878         case MONO_TYPE_PTR:
879         case MONO_TYPE_FNPTR:
880                 inst->type = STACK_PTR;
881                 return;
882         case MONO_TYPE_CLASS:
883         case MONO_TYPE_STRING:
884         case MONO_TYPE_OBJECT:
885         case MONO_TYPE_SZARRAY:
886         case MONO_TYPE_ARRAY:    
887                 inst->type = STACK_OBJ;
888                 return;
889         case MONO_TYPE_I8:
890         case MONO_TYPE_U8:
891                 inst->type = STACK_I8;
892                 return;
893         case MONO_TYPE_R4:
894         case MONO_TYPE_R8:
895                 inst->type = STACK_R8;
896                 return;
897         case MONO_TYPE_VALUETYPE:
898                 if (type->data.klass->enumtype) {
899                         t = type->data.klass->enum_basetype->type;
900                         goto handle_enum;
901                 } else {
902                         inst->klass = type->data.klass;
903                         inst->type = STACK_VTYPE;
904                         return;
905                 }
906         default:
907                 g_error ("unknown type 0x%02x in eval stack type", type->type);
908         }
909 }
910
911 /*
912  * The following tables are used to quickly validate the IL code in type_from_op ().
913  */
914 static const char
915 bin_num_table [STACK_MAX] [STACK_MAX] = {
916         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
917         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
918         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
919         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
920         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_R8,  STACK_INV, STACK_INV, STACK_INV},
921         {STACK_INV, STACK_MP,  STACK_INV, STACK_MP,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV},
922         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
923         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
924 };
925
926 static const char 
927 neg_table [] = {
928         STACK_INV, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_INV, STACK_INV, STACK_INV
929 };
930
931 /* reduce the size of this table */
932 static const char
933 bin_int_table [STACK_MAX] [STACK_MAX] = {
934         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
935         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
936         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
937         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
938         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
939         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
940         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
941         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
942 };
943
944 static const char
945 bin_comp_table [STACK_MAX] [STACK_MAX] = {
946         {0},
947         {0, 1, 0, 1, 0, 0, 4, 0},
948         {0, 0, 1, 0, 0, 0, 0, 0},
949         {0, 1, 0, 1, 0, 2, 4, 0},
950         {0, 0, 0, 0, 1, 0, 0, 0},
951         {0, 0, 0, 2, 0, 1, 0, 0},
952         {0, 4, 0, 4, 0, 0, 3, 0},
953         {0, 0, 0, 0, 0, 0, 0, 0},
954 };
955
956 /* reduce the size of this table */
957 static const char
958 shift_table [STACK_MAX] [STACK_MAX] = {
959         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
960         {STACK_INV, STACK_I4,  STACK_INV, STACK_I4,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
961         {STACK_INV, STACK_I8,  STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
962         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
963         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
964         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
965         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
966         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
967 };
968
969 /*
970  * Tables to map from the non-specific opcode to the matching
971  * type-specific opcode.
972  */
973 /* handles from CEE_ADD to CEE_SHR_UN (CEE_REM_UN for floats) */
974 static const guint16
975 binops_op_map [STACK_MAX] = {
976         0, 0, OP_LADD-CEE_ADD, OP_PADD-CEE_ADD, OP_FADD-CEE_ADD, 0
977 };
978
979 /* handles from CEE_NEG to CEE_CONV_U8 */
980 static const guint16
981 unops_op_map [STACK_MAX] = {
982         0, 0, OP_LNEG-CEE_NEG, OP_PNEG-CEE_NEG, OP_FNEG-CEE_NEG, 0
983 };
984
985 /* handles from CEE_CONV_U2 to CEE_SUB_OVF_UN */
986 static const guint16
987 ovfops_op_map [STACK_MAX] = {
988         0, 0, OP_LCONV_TO_U2-CEE_CONV_U2, OP_PCONV_TO_U2-CEE_CONV_U2, OP_FCONV_TO_U2-CEE_CONV_U2, 0
989 };
990
991 /* handles from CEE_CONV_OVF_I1_UN to CEE_CONV_OVF_U_UN */
992 static const guint16
993 ovf2ops_op_map [STACK_MAX] = {
994         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
995 };
996
997 /* handles from CEE_CONV_OVF_I1 to CEE_CONV_OVF_U8 */
998 static const guint16
999 ovf3ops_op_map [STACK_MAX] = {
1000         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
1001 };
1002
1003 /* handles from CEE_CEQ to CEE_CLT_UN */
1004 static const guint16
1005 ceqops_op_map [STACK_MAX] = {
1006         0, 0, OP_LCEQ-CEE_CEQ, OP_PCEQ-CEE_CEQ, OP_FCEQ-CEE_CEQ, 0
1007 };
1008
1009 /*
1010  * Sets ins->type (the type on the eval stack) according to the
1011  * type of the opcode and the arguments to it.
1012  * Invalid IL code is marked by setting ins->type to the invalid value STACK_INV.
1013  *
1014  * FIXME: this function sets ins->type unconditionally in some cases, but
1015  * it should set it to invalid for some types (a conv.x on an object)
1016  */
1017 static void
1018 type_from_op (MonoInst *ins) {
1019         switch (ins->opcode) {
1020         /* binops */
1021         case CEE_ADD:
1022         case CEE_SUB:
1023         case CEE_MUL:
1024         case CEE_DIV:
1025         case CEE_REM:
1026                 /* FIXME: check unverifiable args for STACK_MP */
1027                 ins->type = bin_num_table [ins->inst_i0->type] [ins->inst_i1->type];
1028                 ins->opcode += binops_op_map [ins->type];
1029                 return;
1030         case CEE_DIV_UN:
1031         case CEE_REM_UN:
1032         case CEE_AND:
1033         case CEE_OR:
1034         case CEE_XOR:
1035                 ins->type = bin_int_table [ins->inst_i0->type] [ins->inst_i1->type];
1036                 ins->opcode += binops_op_map [ins->type];
1037                 return;
1038         case CEE_SHL:
1039         case CEE_SHR:
1040         case CEE_SHR_UN:
1041                 ins->type = shift_table [ins->inst_i0->type] [ins->inst_i1->type];
1042                 ins->opcode += binops_op_map [ins->type];
1043                 return;
1044         case OP_COMPARE:
1045                 /* FIXME: handle some specifics with ins->next->type */
1046                 ins->type = bin_comp_table [ins->inst_i0->type] [ins->inst_i1->type] ? STACK_I4: STACK_INV;
1047                 return;
1048         case 256+CEE_CEQ:
1049         case 256+CEE_CGT:
1050         case 256+CEE_CGT_UN:
1051         case 256+CEE_CLT:
1052         case 256+CEE_CLT_UN:
1053                 ins->type = bin_comp_table [ins->inst_i0->type] [ins->inst_i1->type] ? STACK_I4: STACK_INV;
1054                 ins->opcode += ceqops_op_map [ins->inst_i0->type];
1055                 return;
1056         /* unops */
1057         case CEE_NEG:
1058                 ins->type = neg_table [ins->inst_i0->type];
1059                 ins->opcode += unops_op_map [ins->type];
1060                 return;
1061         case CEE_NOT:
1062                 if (ins->inst_i0->type >= STACK_I4 && ins->inst_i0->type <= STACK_PTR)
1063                         ins->type = ins->inst_i0->type;
1064                 else
1065                         ins->type = STACK_INV;
1066                 ins->opcode += unops_op_map [ins->type];
1067                 return;
1068         case CEE_CONV_I1:
1069         case CEE_CONV_I2:
1070         case CEE_CONV_I4:
1071         case CEE_CONV_U4:
1072                 ins->type = STACK_I4;
1073                 ins->opcode += unops_op_map [ins->inst_i0->type];
1074                 return;
1075         case CEE_CONV_R_UN:
1076                 ins->type = STACK_R8;
1077                 switch (ins->inst_i0->type) {
1078                 case STACK_I4:
1079                 case STACK_PTR:
1080                         break;
1081                 case STACK_I8:
1082                         ins->opcode = OP_LCONV_TO_R_UN; 
1083                         break;
1084                 }
1085                 return;
1086         case CEE_CONV_OVF_I1:
1087         case CEE_CONV_OVF_U1:
1088         case CEE_CONV_OVF_I2:
1089         case CEE_CONV_OVF_U2:
1090         case CEE_CONV_OVF_I4:
1091         case CEE_CONV_OVF_U4:
1092                 ins->type = STACK_I4;
1093                 ins->opcode += ovf3ops_op_map [ins->inst_i0->type];
1094                 return;
1095         case CEE_CONV_OVF_I_UN:
1096         case CEE_CONV_OVF_U_UN:
1097                 ins->type = STACK_PTR;
1098                 ins->opcode += ovf2ops_op_map [ins->inst_i0->type];
1099                 return;
1100         case CEE_CONV_OVF_I1_UN:
1101         case CEE_CONV_OVF_I2_UN:
1102         case CEE_CONV_OVF_I4_UN:
1103         case CEE_CONV_OVF_U1_UN:
1104         case CEE_CONV_OVF_U2_UN:
1105         case CEE_CONV_OVF_U4_UN:
1106                 ins->type = STACK_I4;
1107                 ins->opcode += ovf2ops_op_map [ins->inst_i0->type];
1108                 return;
1109         case CEE_CONV_U:
1110                 ins->type = STACK_PTR;
1111                 switch (ins->inst_i0->type) {
1112                 case STACK_I4:
1113                 case STACK_PTR:
1114                 case STACK_MP:
1115                         break;
1116                 case STACK_I8:
1117                         ins->opcode = OP_LCONV_TO_U;
1118                         break;
1119                 case STACK_R8:
1120                         ins->opcode = OP_FCONV_TO_U;
1121                         break;
1122                 }
1123                 return;
1124         case CEE_CONV_I8:
1125         case CEE_CONV_U8:
1126                 ins->type = STACK_I8;
1127                 ins->opcode += unops_op_map [ins->inst_i0->type];
1128                 return;
1129         case CEE_CONV_OVF_I8:
1130         case CEE_CONV_OVF_U8:
1131                 ins->type = STACK_I8;
1132                 ins->opcode += ovf3ops_op_map [ins->inst_i0->type];
1133                 return;
1134         case CEE_CONV_OVF_U8_UN:
1135         case CEE_CONV_OVF_I8_UN:
1136                 ins->type = STACK_I8;
1137                 ins->opcode += ovf2ops_op_map [ins->inst_i0->type];
1138                 return;
1139         case CEE_CONV_R4:
1140         case CEE_CONV_R8:
1141                 ins->type = STACK_R8;
1142                 ins->opcode += unops_op_map [ins->inst_i0->type];
1143                 return;
1144         case CEE_CKFINITE:
1145                 ins->type = STACK_R8;           
1146                 return;
1147         case CEE_CONV_U2:
1148         case CEE_CONV_U1:
1149                 ins->type = STACK_I4;
1150                 ins->opcode += ovfops_op_map [ins->inst_i0->type];
1151                 break;
1152         case CEE_CONV_I:
1153         case CEE_CONV_OVF_I:
1154         case CEE_CONV_OVF_U:
1155                 ins->type = STACK_PTR;
1156                 ins->opcode += ovfops_op_map [ins->inst_i0->type];
1157                 return;
1158         case CEE_ADD_OVF:
1159         case CEE_ADD_OVF_UN:
1160         case CEE_MUL_OVF:
1161         case CEE_MUL_OVF_UN:
1162         case CEE_SUB_OVF:
1163         case CEE_SUB_OVF_UN:
1164                 ins->type = bin_num_table [ins->inst_i0->type] [ins->inst_i1->type];
1165                 ins->opcode += ovfops_op_map [ins->inst_i0->type];
1166                 return;
1167         default:
1168                 g_error ("opcode 0x%04x not handled in type from op", ins->opcode);
1169                 break;
1170         }
1171 }
1172
1173 static const char 
1174 ldind_type [] = {
1175         STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I8, STACK_MP, STACK_R8, STACK_R8, STACK_OBJ
1176 };
1177
1178 /* map ldelem.x to the matching ldind.x opcode */
1179 static const guchar
1180 ldelem_to_ldind [] = {
1181         CEE_LDIND_I1,
1182         CEE_LDIND_U1,
1183         CEE_LDIND_I2,
1184         CEE_LDIND_U2,
1185         CEE_LDIND_I4,
1186         CEE_LDIND_U4,
1187         CEE_LDIND_I8,
1188         CEE_LDIND_I,
1189         CEE_LDIND_R4,
1190         CEE_LDIND_R8,
1191         CEE_LDIND_REF
1192 };
1193
1194 /* map stelem.x to the matching stind.x opcode */
1195 static const guchar
1196 stelem_to_stind [] = {
1197         CEE_STIND_I,
1198         CEE_STIND_I1,
1199         CEE_STIND_I2,
1200         CEE_STIND_I4,
1201         CEE_STIND_I8,
1202         CEE_STIND_R4,
1203         CEE_STIND_R8,
1204         CEE_STIND_REF
1205 };
1206
1207 #if 0
1208
1209 static const char
1210 param_table [STACK_MAX] [STACK_MAX] = {
1211         {0},
1212 };
1213
1214 static int
1215 check_values_to_signature (MonoInst *args, MonoType *this, MonoMethodSignature *sig) {
1216         int i;
1217
1218         if (sig->hasthis) {
1219                 switch (args->type) {
1220                 case STACK_I4:
1221                 case STACK_I8:
1222                 case STACK_R8:
1223                 case STACK_VTYPE:
1224                 case STACK_INV:
1225                         return 0;
1226                 }
1227                 args++;
1228         }
1229         for (i = 0; i < sig->param_count; ++i) {
1230                 switch (args [i].type) {
1231                 case STACK_INV:
1232                         return 0;
1233                 case STACK_MP:
1234                         if (!sig->params [i]->byref)
1235                                 return 0;
1236                         continue;
1237                 case STACK_OBJ:
1238                         if (sig->params [i]->byref)
1239                                 return 0;
1240                         switch (sig->params [i]->type) {
1241                         case MONO_TYPE_CLASS:
1242                         case MONO_TYPE_STRING:
1243                         case MONO_TYPE_OBJECT:
1244                         case MONO_TYPE_SZARRAY:
1245                         case MONO_TYPE_ARRAY:
1246                                 break;
1247                         default:
1248                                 return 0;
1249                         }
1250                         continue;
1251                 case STACK_R8:
1252                         if (sig->params [i]->byref)
1253                                 return 0;
1254                         if (sig->params [i]->type != MONO_TYPE_R4 && sig->params [i]->type != MONO_TYPE_R8)
1255                                 return 0;
1256                         continue;
1257                 case STACK_PTR:
1258                 case STACK_I4:
1259                 case STACK_I8:
1260                 case STACK_VTYPE:
1261                         break;
1262                 }
1263                 /*if (!param_table [args [i].type] [sig->params [i]->type])
1264                         return 0;*/
1265         }
1266         return 1;
1267 }
1268 #endif
1269
1270 /*
1271  * When we need a pointer to the current domain many times in a method, we
1272  * call mono_domain_get() once and we store the result in a local variable.
1273  * This function returns the variable that represents the MonoDomain*.
1274  */
1275 inline static MonoInst *
1276 mono_get_domainvar (MonoCompile *cfg)
1277 {
1278         if (!cfg->domainvar)
1279                 cfg->domainvar = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1280         return cfg->domainvar;
1281 }
1282
1283 MonoInst*
1284 mono_compile_create_var (MonoCompile *cfg, MonoType *type, int opcode)
1285 {
1286         MonoInst *inst;
1287         int num = cfg->num_varinfo;
1288
1289         if ((num + 1) >= cfg->varinfo_count) {
1290                 cfg->varinfo_count = (cfg->varinfo_count + 2) * 2;
1291                 cfg->varinfo = (MonoInst **)g_realloc (cfg->varinfo, sizeof (MonoInst*) * cfg->varinfo_count);
1292                 cfg->vars = (MonoMethodVar **)g_realloc (cfg->vars, sizeof (MonoMethodVar*) * cfg->varinfo_count);      
1293         }
1294
1295         mono_jit_stats.allocate_var++;
1296
1297         MONO_INST_NEW (cfg, inst, opcode);
1298         inst->inst_c0 = num;
1299         inst->inst_vtype = type;
1300         inst->klass = mono_class_from_mono_type (type);
1301         /* if set to 1 the variable is native */
1302         inst->unused = 0;
1303
1304         cfg->varinfo [num] = inst;
1305
1306         cfg->vars [num] = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoMethodVar));
1307         MONO_INIT_VARINFO (cfg->vars [num], num);
1308
1309         cfg->num_varinfo++;
1310         //g_print ("created temp %d of type %s\n", num, mono_type_get_name (type));
1311         return inst;
1312 }
1313
1314 static MonoType*
1315 type_from_stack_type (MonoInst *ins) {
1316         switch (ins->type) {
1317         case STACK_I4: return &mono_defaults.int32_class->byval_arg;
1318         case STACK_I8: return &mono_defaults.int64_class->byval_arg;
1319         case STACK_PTR: return &mono_defaults.int_class->byval_arg;
1320         case STACK_R8: return &mono_defaults.double_class->byval_arg;
1321         case STACK_MP: return &mono_defaults.int_class->byval_arg;
1322         case STACK_OBJ: return &mono_defaults.object_class->byval_arg;
1323         case STACK_VTYPE: return &ins->klass->byval_arg;
1324         default:
1325                 g_error ("stack type %d to montype not handled\n", ins->type);
1326         }
1327         return NULL;
1328 }
1329
1330 static MonoClass*
1331 array_access_to_klass (int opcode)
1332 {
1333         switch (opcode) {
1334         case CEE_LDELEM_U1:
1335                 return mono_defaults.byte_class;
1336         case CEE_LDELEM_U2:
1337                 return mono_defaults.uint16_class;
1338         case CEE_LDELEM_I:
1339         case CEE_STELEM_I:
1340                 return mono_defaults.int_class;
1341         case CEE_LDELEM_I1:
1342         case CEE_STELEM_I1:
1343                 return mono_defaults.sbyte_class;
1344         case CEE_LDELEM_I2:
1345         case CEE_STELEM_I2:
1346                 return mono_defaults.int16_class;
1347         case CEE_LDELEM_I4:
1348         case CEE_STELEM_I4:
1349                 return mono_defaults.int32_class;
1350         case CEE_LDELEM_U4:
1351                 return mono_defaults.uint32_class;
1352         case CEE_LDELEM_I8:
1353         case CEE_STELEM_I8:
1354                 return mono_defaults.int64_class;
1355         case CEE_LDELEM_R4:
1356         case CEE_STELEM_R4:
1357                 return mono_defaults.single_class;
1358         case CEE_LDELEM_R8:
1359         case CEE_STELEM_R8:
1360                 return mono_defaults.double_class;
1361         case CEE_LDELEM_REF:
1362         case CEE_STELEM_REF:
1363                 return mono_defaults.object_class;
1364         default:
1365                 g_assert_not_reached ();
1366         }
1367         return NULL;
1368 }
1369
1370 static void
1371 mono_add_ins_to_end (MonoBasicBlock *bb, MonoInst *inst)
1372 {
1373         MonoInst *prev;
1374         if (!bb->code) {
1375                 MONO_ADD_INS (bb, inst);
1376                 return;
1377         }
1378         switch (bb->last_ins->opcode) {
1379         case CEE_BEQ:
1380         case CEE_BGE:
1381         case CEE_BGT:
1382         case CEE_BLE:
1383         case CEE_BLT:
1384         case CEE_BNE_UN:
1385         case CEE_BGE_UN:
1386         case CEE_BGT_UN:
1387         case CEE_BLE_UN:
1388         case CEE_BLT_UN:
1389         case CEE_BR:
1390                 prev = bb->code;
1391                 while (prev->next && prev->next != bb->last_ins)
1392                         prev = prev->next;
1393                 if (prev == bb->code) {
1394                         if (bb->last_ins == bb->code) {
1395                                 inst->next = bb->code;
1396                                 bb->code = inst;
1397                         } else {
1398                                 inst->next = prev->next;
1399                                 prev->next = inst;
1400                         }
1401                 } else {
1402                         inst->next = bb->last_ins;
1403                         prev->next = inst;
1404                 }
1405                 break;
1406         //      g_warning ("handle conditional jump in add_ins_to_end ()\n");
1407         default:
1408                 MONO_ADD_INS (bb, inst);
1409                 break;
1410         }
1411 }
1412
1413 void
1414 mono_add_varcopy_to_end (MonoCompile *cfg, MonoBasicBlock *bb, int src, int dest)
1415 {
1416         MonoInst *inst, *load;
1417
1418         NEW_TEMPLOAD (cfg, load, src);
1419
1420         NEW_TEMPSTORE (cfg, inst, dest, load);
1421         if (inst->opcode == CEE_STOBJ) {
1422                 NEW_TEMPLOADA (cfg, inst, dest);
1423                 handle_stobj (cfg, bb, inst, load, NULL, inst->klass, TRUE, FALSE);
1424         } else {
1425                 inst->cil_code = NULL;
1426                 mono_add_ins_to_end (bb, inst);
1427         }
1428 }
1429
1430 /*
1431  * This function is called to handle items that are left on the evaluation stack
1432  * at basic block boundaries. What happens is that we save the values to local variables
1433  * and we reload them later when first entering the target basic block (with the
1434  * handle_loaded_temps () function).
1435  * A single joint point will use the same variables (stored in the array bb->out_stack or
1436  * bb->in_stack, if the basic block is before or after the joint point).
1437  */
1438 static int
1439 handle_stack_args (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst **sp, int count) {
1440         int i;
1441         MonoBasicBlock *outb;
1442         MonoInst *inst, **locals;
1443
1444         if (!count)
1445                 return 0;
1446         if (cfg->verbose_level > 3)
1447                 g_print ("%d item(s) on exit from B%d\n", count, bb->block_num);
1448         if (!bb->out_scount) {
1449                 int found = 0;
1450                 bb->out_scount = count;
1451                 //g_print ("bblock %d has out:", bb->block_num);
1452                 for (i = 0; i < bb->out_count; ++i) {
1453                         outb = bb->out_bb [i];
1454                         //g_print (" %d", outb->block_num);
1455                         if (outb->in_stack) {
1456                                 found = 1;
1457                                 bb->out_stack = outb->in_stack;
1458                                 break;
1459                         }
1460                 }
1461                 //g_print ("\n");
1462                 if (!found) {
1463                         bb->out_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * count);
1464                         for (i = 0; i < count; ++i) {
1465                                 /* 
1466                                  * dietmar suggests that we can reuse temps already allocated 
1467                                  * for this purpouse, if they occupy the same stack slot and if 
1468                                  * they are of the same type.
1469                                  */
1470                                 bb->out_stack [i] = mono_compile_create_var (cfg, type_from_stack_type (sp [i]), OP_LOCAL);
1471                         }
1472                 }
1473         }
1474         locals = bb->out_stack;
1475         for (i = 0; i < count; ++i) {
1476                 /* add store ops at the end of the bb, before the branch */
1477                 NEW_TEMPSTORE (cfg, inst, locals [i]->inst_c0, sp [i]);
1478                 if (inst->opcode == CEE_STOBJ) {
1479                         NEW_TEMPLOADA (cfg, inst, locals [i]->inst_c0);
1480                         handle_stobj (cfg, bb, inst, sp [i], sp [i]->cil_code, inst->klass, TRUE, FALSE);
1481                 } else {
1482                         inst->cil_code = sp [i]->cil_code;
1483                         mono_add_ins_to_end (bb, inst);
1484                 }
1485                 if (cfg->verbose_level > 3)
1486                         g_print ("storing %d to temp %d\n", i, locals [i]->inst_c0);
1487         }
1488         
1489         for (i = 0; i < bb->out_count; ++i) {
1490                 outb = bb->out_bb [i];
1491                 if (outb->in_scount)
1492                         continue; /* check they are the same locals */
1493                 outb->in_scount = count;
1494                 outb->in_stack = locals;
1495         }
1496         return 0;
1497 }
1498
1499 static int
1500 ret_type_to_call_opcode (MonoType *type, int calli, int virt)
1501 {
1502         int t = type->type;
1503
1504         if (type->byref)
1505                 return calli? OP_CALL_REG: virt? CEE_CALLVIRT: CEE_CALL;
1506
1507 handle_enum:
1508         switch (t) {
1509         case MONO_TYPE_VOID:
1510                 return calli? OP_VOIDCALL_REG: virt? OP_VOIDCALLVIRT: OP_VOIDCALL;
1511         case MONO_TYPE_I1:
1512         case MONO_TYPE_U1:
1513         case MONO_TYPE_BOOLEAN:
1514         case MONO_TYPE_I2:
1515         case MONO_TYPE_U2:
1516         case MONO_TYPE_CHAR:
1517         case MONO_TYPE_I4:
1518         case MONO_TYPE_U4:
1519                 return calli? OP_CALL_REG: virt? CEE_CALLVIRT: CEE_CALL;
1520         case MONO_TYPE_I:
1521         case MONO_TYPE_U:
1522         case MONO_TYPE_PTR:
1523                 return calli? OP_CALL_REG: virt? CEE_CALLVIRT: CEE_CALL;
1524         case MONO_TYPE_CLASS:
1525         case MONO_TYPE_STRING:
1526         case MONO_TYPE_OBJECT:
1527         case MONO_TYPE_SZARRAY:
1528         case MONO_TYPE_ARRAY:    
1529                 return calli? OP_CALL_REG: virt? CEE_CALLVIRT: CEE_CALL;
1530         case MONO_TYPE_I8:
1531         case MONO_TYPE_U8:
1532                 return calli? OP_LCALL_REG: virt? OP_LCALLVIRT: OP_LCALL;
1533         case MONO_TYPE_R4:
1534         case MONO_TYPE_R8:
1535                 return calli? OP_FCALL_REG: virt? OP_FCALLVIRT: OP_FCALL;
1536         case MONO_TYPE_VALUETYPE:
1537                 if (type->data.klass->enumtype) {
1538                         t = type->data.klass->enum_basetype->type;
1539                         goto handle_enum;
1540                 } else
1541                         return calli? OP_VCALL_REG: virt? OP_VCALLVIRT: OP_VCALL;
1542         default:
1543                 g_error ("unknown type %02x in ret_type_to_call_opcode", type->type);
1544         }
1545         return -1;
1546 }
1547
1548 void
1549 mono_create_jump_table (MonoCompile *cfg, MonoInst *label, MonoBasicBlock **bbs, int num_blocks)
1550 {
1551         MonoJumpInfo *ji = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfo));
1552         
1553         ji->ip.label = label;
1554         ji->type = MONO_PATCH_INFO_SWITCH;
1555         ji->data.table = bbs;
1556         ji->next = cfg->patch_info;
1557         ji->table_size = num_blocks;
1558         cfg->patch_info = ji;
1559 }
1560
1561 /*
1562  * When we add a tree of instructions, we need to ensure the instructions currently
1563  * on the stack are executed before (like, if we load a value from a local).
1564  * We ensure this by saving the currently loaded values to temps and rewriting the
1565  * instructions to load the values.
1566  * This is not done for opcodes that terminate a basic block (because it's handled already
1567  * by handle_stack_args ()) and for opcodes that can't change values, like POP.
1568  */
1569 static void
1570 handle_loaded_temps (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst **stack, MonoInst **sp)
1571 {
1572         MonoInst *load, *store, *temp, *ins;
1573
1574         while (stack < sp) {
1575                 ins = *stack;
1576                 /* handle also other constants */
1577                 if (ins->opcode != OP_ICONST) {
1578                         temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1579                         NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
1580                         store->cil_code = ins->cil_code;
1581                         if (store->opcode == CEE_STOBJ) {
1582                                 NEW_TEMPLOADA (cfg, store, temp->inst_c0);
1583                                 handle_stobj (cfg, bblock, store, ins, ins->cil_code, temp->klass, FALSE, FALSE);
1584                         } else
1585                                 MONO_ADD_INS (bblock, store);
1586                         NEW_TEMPLOAD (cfg, load, temp->inst_c0);
1587                         load->cil_code = ins->cil_code;
1588                         *stack = load;
1589                 }
1590                 stack++;
1591         }
1592 }
1593
1594 inline static int
1595 mono_spill_call (MonoCompile *cfg, MonoBasicBlock *bblock, MonoCallInst *call, MonoMethodSignature *sig, gboolean ret_object, 
1596                  const guint8 *ip, gboolean to_end)
1597 {
1598         MonoInst *temp, *store, *ins = (MonoInst*)call;
1599         MonoType *ret = sig->ret;
1600
1601         if (!MONO_TYPE_IS_VOID (ret) || ret_object) {
1602                 if (ret_object) {
1603                         call->inst.type = STACK_OBJ;
1604                         call->inst.opcode = CEE_CALL;
1605                         temp = mono_compile_create_var (cfg, &mono_defaults.string_class->byval_arg, OP_LOCAL);
1606                 } else {
1607                         type_to_eval_stack_type (ret, ins);
1608                         temp = mono_compile_create_var (cfg, ret, OP_LOCAL);
1609                 }
1610
1611                 if (MONO_TYPE_ISSTRUCT (ret)) {
1612                         MonoInst *loada;
1613
1614                         /* we use this to allocate native sized structs */
1615                         temp->unused = sig->pinvoke;
1616
1617                         NEW_TEMPLOADA (cfg, loada, temp->inst_c0);
1618                         if (call->inst.opcode == OP_VCALL)
1619                                 ins->inst_left = loada;
1620                         else
1621                                 ins->inst_right = loada; /* a virtual or indirect call */
1622
1623                         if (to_end)
1624                                 mono_add_ins_to_end (bblock, ins);
1625                         else
1626                                 MONO_ADD_INS (bblock, ins);
1627                 } else {
1628                         NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
1629                         store->cil_code = ip;
1630                         if (to_end)
1631                                 mono_add_ins_to_end (bblock, store);
1632                         else
1633                                 MONO_ADD_INS (bblock, store);
1634                 }
1635                 return temp->inst_c0;
1636         } else {
1637                 if (to_end)
1638                         mono_add_ins_to_end (bblock, ins);
1639                 else
1640                         MONO_ADD_INS (bblock, ins);
1641                 return -1;
1642         }
1643 }
1644
1645 inline static MonoCallInst *
1646 mono_emit_call_args (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethodSignature *sig, 
1647                      MonoInst **args, int calli, int virtual, const guint8 *ip, gboolean to_end)
1648 {
1649         MonoCallInst *call;
1650         int i;
1651
1652         MONO_INST_NEW_CALL (cfg, call, ret_type_to_call_opcode (sig->ret, calli, virtual));
1653         
1654         call->inst.cil_code = ip;
1655         call->args = args;
1656         call->signature = sig;
1657         call = mono_arch_call_opcode (cfg, bblock, call, virtual);
1658
1659         for (i = 0; i < (sig->param_count + sig->hasthis); ++i) {
1660                 if (call->args [i]) {
1661                         if (to_end)
1662                                 mono_add_ins_to_end (bblock, call->args [i]);
1663                         else
1664                                 MONO_ADD_INS (bblock, call->args [i]);
1665                 }
1666         }
1667         return call;
1668 }
1669
1670 inline static int
1671 mono_emit_calli (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethodSignature *sig, 
1672                  MonoInst **args, MonoInst *addr, const guint8 *ip)
1673 {
1674         MonoCallInst *call = mono_emit_call_args (cfg, bblock, sig, args, TRUE, FALSE, ip, FALSE);
1675
1676         call->inst.inst_i0 = addr;
1677
1678         return mono_spill_call (cfg, bblock, call, sig, FALSE, ip, FALSE);
1679 }
1680
1681 static MonoCallInst*
1682 mono_emit_method_call (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *method, MonoMethodSignature *sig,
1683                        MonoInst **args, const guint8 *ip, MonoInst *this)
1684 {
1685         gboolean virtual = this != NULL;
1686         MonoCallInst *call;
1687
1688         call = mono_emit_call_args (cfg, bblock, sig, args, FALSE, virtual, ip, FALSE);
1689
1690         if (this && sig->hasthis && 
1691             (method->klass->marshalbyref || method->klass == mono_defaults.object_class) && 
1692             !(method->flags & METHOD_ATTRIBUTE_VIRTUAL) && !MONO_CHECK_THIS (this)) {
1693                 call->method = mono_marshal_get_remoting_invoke_with_check (method);
1694         } else {
1695                 call->method = method;
1696         }
1697         call->inst.flags |= MONO_INST_HAS_METHOD;
1698         call->inst.inst_left = this;
1699
1700         return call;
1701 }
1702
1703 inline static int
1704 mono_emit_method_call_spilled (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *method,  
1705                        MonoInst **args, const guint8 *ip, MonoInst *this)
1706 {
1707         MonoCallInst *call = mono_emit_method_call (cfg, bblock, method, method->signature, args, ip, this);
1708
1709         return mono_spill_call (cfg, bblock, call, method->signature, method->string_ctor, ip, FALSE);
1710 }
1711
1712 inline static int
1713 mono_emit_native_call (MonoCompile *cfg, MonoBasicBlock *bblock, gconstpointer func, MonoMethodSignature *sig,
1714                        MonoInst **args, const guint8 *ip, gboolean to_end)
1715 {
1716         MonoCallInst *call;
1717
1718         g_assert (sig);
1719
1720         call = mono_emit_call_args (cfg, bblock, sig, args, FALSE, FALSE, ip, to_end);
1721         call->fptr = func;
1722         return mono_spill_call (cfg, bblock, call, sig, func == mono_array_new_va, ip, to_end);
1723 }
1724
1725 inline static int
1726 mono_emit_jit_icall (MonoCompile *cfg, MonoBasicBlock *bblock, gconstpointer func, MonoInst **args, const guint8 *ip)
1727 {
1728         MonoJitICallInfo *info = mono_find_jit_icall_by_addr (func);
1729         
1730         if (!info) {
1731                 g_warning ("unregistered JIT ICall");
1732                 g_assert_not_reached ();
1733         }
1734
1735         return mono_emit_native_call (cfg, bblock, info->wrapper, info->sig, args, ip, FALSE);
1736 }
1737
1738 static void
1739 mono_emulate_opcode (MonoCompile *cfg, MonoInst *tree, MonoInst **iargs, MonoJitICallInfo *info)
1740 {
1741         MonoInst *ins, *temp = NULL, *store, *load;
1742         int i, nargs;
1743         MonoCallInst *call;
1744
1745         /*g_print ("emulating: ");
1746         mono_print_tree (tree);
1747         g_print ("\n");*/
1748         MONO_INST_NEW_CALL (cfg, call, ret_type_to_call_opcode (info->sig->ret, FALSE, FALSE));
1749         ins = (MonoInst*)call;
1750         
1751         call->inst.cil_code = tree->cil_code;
1752         call->args = iargs;
1753         call->signature = info->sig;
1754
1755         call = mono_arch_call_opcode (cfg, cfg->cbb, call, FALSE);
1756
1757         if (!MONO_TYPE_IS_VOID (info->sig->ret)) {
1758                 temp = mono_compile_create_var (cfg, info->sig->ret, OP_LOCAL);
1759                 NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
1760                 store->cil_code = tree->cil_code;
1761         } else {
1762                 store = ins;
1763         }
1764
1765         nargs = info->sig->param_count + info->sig->hasthis;
1766
1767         for (i = 1; i < nargs; i++) {
1768                 call->args [i - 1]->next = call->args [i];
1769         }
1770
1771         if (nargs)
1772                 call->args [nargs - 1]->next = store;
1773
1774         if (cfg->prev_ins) {
1775                 store->next = cfg->prev_ins->next;
1776                 if (nargs)
1777                         cfg->prev_ins->next =  call->args [0];
1778                 else
1779                         cfg->prev_ins->next = store;
1780         } else {
1781                 store->next = cfg->cbb->code;
1782                 if (nargs)              
1783                         cfg->cbb->code = call->args [0];
1784                 else
1785                         cfg->cbb->code = store;
1786         }
1787
1788         
1789         call->fptr = info->wrapper;
1790
1791         if (!MONO_TYPE_IS_VOID (info->sig->ret)) {
1792                 NEW_TEMPLOAD (cfg, load, temp->inst_c0);
1793                 *tree = *load;
1794         }
1795 }
1796
1797 static MonoMethodSignature *
1798 mono_get_element_address_signature (int arity)
1799 {
1800         static GHashTable *sighash = NULL;
1801         MonoMethodSignature *res;
1802         int i;
1803
1804         if (!sighash)
1805                 sighash = g_hash_table_new (NULL, NULL);
1806
1807
1808         if ((res = g_hash_table_lookup (sighash, (gpointer)arity)))
1809                 return res;
1810
1811         res = mono_metadata_signature_alloc (mono_defaults.corlib, arity + 1);
1812
1813         res->params [0] = &mono_defaults.array_class->byval_arg; 
1814         
1815         for (i = 1; i <= arity; i++)
1816                 res->params [i] = &mono_defaults.int_class->byval_arg;
1817
1818         res->ret = &mono_defaults.int_class->byval_arg;
1819
1820         g_hash_table_insert (sighash, (gpointer)arity, res);
1821
1822         return res;
1823 }
1824
1825 static void
1826 handle_stobj (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *dest, MonoInst *src, const unsigned char *ip, MonoClass *klass, gboolean to_end, gboolean native) {
1827         MonoInst *iargs [3];
1828         int n;
1829
1830         g_assert (klass);
1831         /*
1832          * This check breaks with spilled vars... need to handle it during verification anyway.
1833          * g_assert (klass && klass == src->klass && klass == dest->klass);
1834          */
1835
1836         if (native)
1837                 n = mono_class_native_size (klass, NULL);
1838         else
1839                 n = mono_class_value_size (klass, NULL);
1840
1841         iargs [0] = dest;
1842         iargs [1] = src;
1843         NEW_ICONST (cfg, iargs [2], n);
1844
1845         mono_emit_native_call (cfg, bblock, helper_memcpy, helper_sig_memcpy, iargs, ip, to_end);
1846 }
1847
1848 static void
1849 handle_initobj (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *dest, const guchar *ip, MonoClass *klass, MonoInst **stack_start, MonoInst **sp)
1850 {
1851         MonoInst *iargs [2];
1852         MonoInst *ins, *zero_int32;
1853         int n;
1854
1855         NEW_ICONST (cfg, zero_int32, 0);
1856
1857         mono_class_init (klass);
1858         n = mono_class_value_size (klass, NULL);
1859         MONO_INST_NEW (cfg, ins, 0);
1860         ins->cil_code = ip;
1861         ins->inst_left = dest;
1862         ins->inst_right = zero_int32;
1863         switch (n) {
1864         case 1:
1865                 ins->opcode = CEE_STIND_I1;
1866                 MONO_ADD_INS (bblock, ins);
1867                 break;
1868         case 2:
1869                 ins->opcode = CEE_STIND_I2;
1870                 MONO_ADD_INS (bblock, ins);
1871                 break;
1872         case 4:
1873                 ins->opcode = CEE_STIND_I4;
1874                 MONO_ADD_INS (bblock, ins);
1875                 break;
1876         default:
1877                 handle_loaded_temps (cfg, bblock, stack_start, sp);
1878                 NEW_ICONST (cfg, ins, n);
1879                 iargs [0] = dest;
1880                 iargs [1] = ins;
1881                 mono_emit_jit_icall (cfg, bblock, helper_initobj, iargs, ip);
1882                 break;
1883         }
1884 }
1885
1886 #define CODE_IS_STLOC(ip) (((ip) [0] >= CEE_STLOC_0 && (ip) [0] <= CEE_STLOC_3) || ((ip) [0] == CEE_STLOC_S))
1887
1888 static gboolean
1889 mono_method_check_inlining (MonoMethod *method)
1890 {
1891         MonoMethodHeader *header = ((MonoMethodNormal *)method)->header;
1892         MonoMethodSignature *signature = method->signature;
1893         int i;
1894
1895         /* fixme: we should inline wrappers */
1896         if (method->wrapper_type != MONO_WRAPPER_NONE)
1897                 return FALSE;
1898
1899         if ((method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
1900             (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
1901             (method->iflags & METHOD_IMPL_ATTRIBUTE_NOINLINING) ||
1902             (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) ||
1903             (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
1904             (method->klass->marshalbyref) ||
1905             !header || header->num_clauses ||
1906             /* fixme: why cant we inline valuetype returns? */
1907             MONO_TYPE_ISSTRUCT (signature->ret))
1908                 return FALSE;
1909
1910         /* its not worth to inline methods with valuetype arguments?? */
1911         for (i = 0; i < signature->param_count; i++) {
1912                 if (MONO_TYPE_ISSTRUCT (signature->params [i])) {
1913                         return FALSE;
1914                 }
1915         }
1916
1917         //if (!MONO_TYPE_IS_VOID (signature->ret)) return FALSE;
1918
1919         /* also consider num_locals? */
1920         if (header->code_size < 20)
1921                 return TRUE;
1922
1923         return FALSE;
1924 }
1925
1926 static MonoInst*
1927 mini_get_opcode_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
1928 {
1929         int pc, op;
1930         MonoInst *ins;
1931
1932         if (cmethod->klass == mono_defaults.string_class) {
1933                 if (cmethod->name [0] != 'g' || strcmp (cmethod->name, "get_Chars"))
1934                         return NULL;
1935                 op = OP_GETCHR;
1936         } else if (cmethod->klass == mono_defaults.math_class) {
1937                 if (strcmp (cmethod->name, "Sin") == 0)
1938                         op = OP_SIN;
1939                 else if (strcmp (cmethod->name, "Cos") == 0)
1940                         op = OP_COS;
1941                 else if (strcmp (cmethod->name, "Tan") == 0)
1942                         op = OP_TAN;
1943                 else if (strcmp (cmethod->name, "Atan") == 0)
1944                         op = OP_ATAN;
1945                 else if (strcmp (cmethod->name, "Sqrt") == 0)
1946                         op = OP_SQRT;
1947                 else if (strcmp (cmethod->name, "Abs") == 0 && fsig->params [0]->type == MONO_TYPE_R8)
1948                         op = OP_ABS;
1949                 else
1950                         return NULL;
1951         } else {
1952                 return NULL;
1953         }
1954         pc = fsig->param_count + fsig->hasthis;
1955         MONO_INST_NEW (cfg, ins, op);
1956
1957         if (pc > 0) {
1958                 ins->inst_i0 = args [0];
1959                 if (pc > 1)
1960                         ins->inst_i1 = args [1];
1961         }
1962
1963         return ins;
1964 }
1965
1966 static void
1967 mono_save_args (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethodSignature *sig, MonoInst **sp, MonoInst **args)
1968 {
1969         MonoInst *store, *temp;
1970         int i;
1971
1972         g_assert (!MONO_TYPE_ISSTRUCT (sig->ret));
1973
1974         if (!sig->hasthis && sig->param_count == 0) 
1975                 return;
1976
1977         if (sig->hasthis) {
1978                 if (sp [0]->opcode == OP_ICONST) {
1979                         *args++ = sp [0];
1980                 } else {
1981                         temp = mono_compile_create_var (cfg, type_from_stack_type (*sp), OP_LOCAL);
1982                         *args++ = temp;
1983                         NEW_TEMPSTORE (cfg, store, temp->inst_c0, *sp);
1984                         store->cil_code = sp [0]->cil_code;
1985                         MONO_ADD_INS (bblock, store);
1986                 }
1987                 sp++;
1988         }
1989
1990         for (i = 0; i < sig->param_count; ++i) {
1991                 if (sp [0]->opcode == OP_ICONST) {
1992                         *args++ = sp [0];
1993                 } else {
1994                         temp = mono_compile_create_var (cfg, type_from_stack_type (*sp), OP_LOCAL);
1995                         *args++ = temp;
1996                         NEW_TEMPSTORE (cfg, store, temp->inst_c0, *sp);
1997                         store->cil_code = sp [0]->cil_code;
1998                         if (store->opcode == CEE_STOBJ) {
1999                                 NEW_TEMPLOADA (cfg, store, temp->inst_c0);
2000                                 handle_stobj (cfg, bblock, store, *sp, sp [0]->cil_code, temp->klass, FALSE, FALSE);
2001                         } else {
2002                                 MONO_ADD_INS (bblock, store);
2003                         } 
2004                 }
2005                 sp++;
2006         }
2007 }
2008
2009 static int
2010 inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoBasicBlock *bblock, MonoInst **sp,
2011                 guchar *ip, guint real_offset, GList *dont_inline, MonoBasicBlock **last_b)
2012 {
2013         MonoInst *ins, *rvar = NULL;
2014         MonoMethodHeader *cheader;
2015         MonoBasicBlock *ebblock, *sbblock;
2016         int i, costs, new_locals_offset;
2017                                 
2018         if (cfg->verbose_level > 2)
2019                 g_print ("INLINE START %p %s\n", cmethod,  mono_method_full_name (cmethod, TRUE));
2020
2021         cheader = ((MonoMethodNormal *)cmethod)->header;
2022
2023         if (!cmethod->inline_info) {
2024                 mono_jit_stats.inlineable_methods++;
2025                 cmethod->inline_info = 1;
2026         }
2027         /* allocate space to store the return value */
2028         if (!MONO_TYPE_IS_VOID (fsig->ret)) 
2029                 rvar =  mono_compile_create_var (cfg, fsig->ret, OP_LOCAL);
2030
2031         /* allocate local variables */
2032         new_locals_offset = cfg->num_varinfo;
2033         for (i = 0; i < cheader->num_locals; ++i)
2034                 mono_compile_create_var (cfg, cheader->locals [i], OP_LOCAL);
2035         
2036         /* allocate starte and end blocks */
2037         sbblock = NEW_BBLOCK (cfg);
2038         sbblock->block_num = cfg->num_bblocks++;
2039         sbblock->real_offset = real_offset;
2040
2041         ebblock = NEW_BBLOCK (cfg);
2042         ebblock->block_num = cfg->num_bblocks++;
2043         ebblock->real_offset = real_offset;
2044         
2045         costs = mono_method_to_ir (cfg, cmethod, sbblock, ebblock, new_locals_offset, rvar, dont_inline, sp, real_offset);
2046         
2047         if (costs >= 0 && costs < 60) {
2048                 if (cfg->verbose_level > 2)
2049                         g_print ("INLINE END %s\n", mono_method_full_name (cmethod, TRUE));
2050                 
2051                 mono_jit_stats.inlined_methods++;
2052
2053                 /* always add some code to avoid block split failures */
2054                 MONO_INST_NEW (cfg, ins, CEE_NOP);
2055                 MONO_ADD_INS (bblock, ins);
2056                 ins->cil_code = ip;
2057
2058                 bblock->next_bb = sbblock;
2059                 link_bblock (cfg, bblock, sbblock);
2060
2061                 if (rvar) {
2062                         NEW_TEMPLOAD (cfg, ins, rvar->inst_c0);
2063                         *sp++ = ins;
2064                 }
2065                 *last_b = ebblock;
2066                 return costs + 1;
2067         } else {
2068                 if (cfg->verbose_level > 2)
2069                         g_print ("INLINE ABORTED %s\n", mono_method_full_name (cmethod, TRUE));
2070         }
2071         return 0;
2072 }
2073
2074 /*
2075  * Some of these comments may well be out-of-date.
2076  * Design decisions: we do a single pass over the IL code (and we do bblock 
2077  * splitting/merging in the few cases when it's required: a back jump to an IL
2078  * address that was not already seen as bblock starting point).
2079  * Code is validated as we go (full verification is still better left to metadata/verify.c).
2080  * Complex operations are decomposed in simpler ones right away. We need to let the 
2081  * arch-specific code peek and poke inside this process somehow (except when the 
2082  * optimizations can take advantage of the full semantic info of coarse opcodes).
2083  * All the opcodes of the form opcode.s are 'normalized' to opcode.
2084  * MonoInst->opcode initially is the IL opcode or some simplification of that 
2085  * (OP_LOAD, OP_STORE). The arch-specific code may rearrange it to an arch-specific 
2086  * opcode with value bigger than OP_LAST.
2087  * At this point the IR can be handed over to an interpreter, a dumb code generator
2088  * or to the optimizing code generator that will translate it to SSA form.
2089  *
2090  * Profiling directed optimizations.
2091  * We may compile by default with few or no optimizations and instrument the code
2092  * or the user may indicate what methods to optimize the most either in a config file
2093  * or through repeated runs where the compiler applies offline the optimizations to 
2094  * each method and then decides if it was worth it.
2095  *
2096  * TODO:
2097  * * consider using an array instead of an hash table (bb_hash)
2098  */
2099
2100 #define CHECK_TYPE(ins) if (!(ins)->type) goto unverified
2101 #define CHECK_STACK(num) if ((sp - stack_start) < (num)) goto unverified
2102 #define CHECK_STACK_OVF(num) if (((sp - stack_start) + (num)) > header->max_stack) goto unverified
2103
2104 /* offset from br.s -> br like opcodes */
2105 #define BIG_BRANCH_OFFSET 13
2106
2107 /*
2108  * mono_method_to_ir: translates IL into basic blocks containing trees
2109  */
2110 static int
2111 mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock, 
2112                    int locals_offset, MonoInst *return_var, GList *dont_inline, MonoInst **inline_args, 
2113                    guint inline_offset)
2114 {
2115         MonoInst *zero_int32, *zero_int64, *zero_ptr, *zero_obj, *zero_r8;
2116         MonoInst *ins, **sp, **stack_start;
2117         MonoBasicBlock *bblock, *tblock = NULL, *init_localsbb = NULL;
2118         GHashTable *bbhash;
2119         MonoMethod *cmethod;
2120         MonoInst **arg_array;
2121         MonoMethodHeader *header;
2122         MonoImage *image;
2123         guint32 token, ins_flag;
2124         MonoClass *klass;
2125         unsigned char *ip, *end, *target;
2126         static double r8_0 = 0.0;
2127         MonoMethodSignature *sig;
2128         MonoType **param_types;
2129         GList *bb_recheck = NULL, *tmp;
2130         int i, n, start_new_bblock, align;
2131         int num_calls = 0, inline_costs = 0;
2132         int *filter_lengths = NULL;
2133         int breakpoint_id = 0;
2134         guint real_offset;
2135
2136         image = method->klass->image;
2137         header = ((MonoMethodNormal *)method)->header;
2138         sig = method->signature;
2139         ip = (unsigned char*)header->code;
2140         end = ip + header->code_size;
2141         mono_jit_stats.cil_code_size += header->code_size;
2142
2143         if (cfg->method == method) {
2144                 real_offset = 0;
2145                 bbhash = cfg->bb_hash;
2146         } else {
2147                 real_offset = inline_offset;
2148                 bbhash = g_hash_table_new (g_direct_hash, NULL);
2149         }
2150
2151         dont_inline = g_list_prepend (dont_inline, method);
2152         if (cfg->method == method) {
2153
2154                 /* ENTRY BLOCK */
2155                 cfg->bb_entry = start_bblock = NEW_BBLOCK (cfg);
2156                 start_bblock->cil_code = NULL;
2157                 start_bblock->cil_length = 0;
2158                 start_bblock->block_num = cfg->num_bblocks++;
2159
2160                 /* EXIT BLOCK */
2161                 cfg->bb_exit = end_bblock = NEW_BBLOCK (cfg);
2162                 end_bblock->cil_code = NULL;
2163                 end_bblock->cil_length = 0;
2164                 end_bblock->block_num = cfg->num_bblocks++;
2165                 g_assert (cfg->num_bblocks == 2);
2166
2167                 arg_array = alloca (sizeof (MonoInst *) * (sig->hasthis + sig->param_count));
2168                 for (i = sig->hasthis + sig->param_count - 1; i >= 0; i--)
2169                         arg_array [i] = cfg->varinfo [i];
2170
2171                 if (mono_compile_aot) 
2172                         cfg->opt |= MONO_OPT_SAHRED;
2173
2174                 if (header->num_clauses) {
2175                         int size = sizeof (int) * header->num_clauses;
2176                         filter_lengths = alloca (size);
2177                         memset (filter_lengths, 0, size);
2178                 }
2179                 /* handle exception clauses */
2180                 for (i = 0; i < header->num_clauses; ++i) {
2181                         //unsigned char *p = ip;
2182                         MonoExceptionClause *clause = &header->clauses [i];
2183                         GET_BBLOCK (cfg, bbhash, tblock, ip + clause->try_offset);
2184                         tblock->real_offset = clause->try_offset;
2185                         GET_BBLOCK (cfg, bbhash, tblock, ip + clause->handler_offset);
2186                         tblock->real_offset = clause->handler_offset;
2187                         /*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);
2188                           while (p < end) {
2189                           g_print ("%s", mono_disasm_code_one (NULL, method, p, &p));
2190                           }*/
2191                         /* catch and filter blocks get the exception object on the stack */
2192                         if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE ||
2193                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
2194                                 /* mostly like handle_stack_args (), but just sets the input args */
2195                                 /* g_print ("handling clause at IL_%04x\n", clause->handler_offset); */
2196                                 if (!cfg->exvar) {
2197                                         cfg->exvar = mono_compile_create_var (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL);
2198                                         /* prevent it from being register allocated */
2199                                         cfg->exvar->flags |= MONO_INST_INDIRECT;
2200                                 }
2201                                 tblock->in_scount = 1;
2202                                 tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
2203                                 tblock->in_stack [0] = cfg->exvar;
2204                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
2205                                         GET_BBLOCK (cfg, bbhash, tblock, ip + clause->token_or_filter);
2206                                         tblock->real_offset = clause->token_or_filter;
2207                                         tblock->in_scount = 1;
2208                                         tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
2209                                         tblock->in_stack [0] = cfg->exvar;
2210                                 }
2211                         }
2212                 }
2213
2214         } else {
2215                 arg_array = alloca (sizeof (MonoInst *) * (sig->hasthis + sig->param_count));
2216                 mono_save_args (cfg, start_bblock, sig, inline_args, arg_array);
2217         }
2218
2219         /* FIRST CODE BLOCK */
2220         bblock = NEW_BBLOCK (cfg);
2221         bblock->cil_code = ip;
2222
2223         ADD_BBLOCK (cfg, bbhash, bblock);
2224
2225         if (cfg->method == method) {
2226                 breakpoint_id = mono_debugger_method_has_breakpoint (method);
2227                 if (breakpoint_id && (mono_debug_format != MONO_DEBUG_FORMAT_DEBUGGER)) {
2228                         MONO_INST_NEW (cfg, ins, CEE_BREAK);
2229                         MONO_ADD_INS (bblock, ins);
2230                 }
2231         }
2232         
2233         if ((header->init_locals || (cfg->method == method && (cfg->opt & MONO_OPT_SAHRED)))) {
2234                 /* we use a separate basic block for the initialization code */
2235                 cfg->bb_init = init_localsbb = NEW_BBLOCK (cfg);
2236                 init_localsbb->real_offset = real_offset;
2237                 start_bblock->next_bb = init_localsbb;
2238                 init_localsbb->next_bb = bblock;
2239                 link_bblock (cfg, start_bblock, init_localsbb);
2240                 link_bblock (cfg, init_localsbb, bblock);
2241                 init_localsbb->block_num = cfg->num_bblocks++;
2242         } else {
2243                 start_bblock->next_bb = bblock;
2244                 link_bblock (cfg, start_bblock, bblock);
2245         }
2246
2247         mono_debug_init_method (cfg, bblock, breakpoint_id);
2248
2249         param_types = mono_mempool_alloc (cfg->mempool, sizeof (MonoType*) * (sig->hasthis + sig->param_count));
2250         if (sig->hasthis)
2251                 param_types [0] = method->klass->valuetype?&method->klass->this_arg:&method->klass->byval_arg;
2252         for (n = 0; n < sig->param_count; ++n)
2253                 param_types [n + sig->hasthis] = sig->params [n];
2254
2255         /* do this somewhere outside - not here */
2256         NEW_ICONST (cfg, zero_int32, 0);
2257         NEW_ICONST (cfg, zero_int64, 0);
2258         zero_int64->type = STACK_I8;
2259         NEW_PCONST (cfg, zero_ptr, 0);
2260         NEW_PCONST (cfg, zero_obj, 0);
2261         zero_obj->type = STACK_OBJ;
2262
2263         MONO_INST_NEW (cfg, zero_r8, OP_R8CONST);
2264         zero_r8->type = STACK_R8;
2265         zero_r8->inst_p0 = &r8_0;
2266
2267         /* add a check for this != NULL to inlined methods */
2268         if (cfg->method != method && sig->hasthis) {
2269                 MONO_INST_NEW (cfg, ins, OP_CHECK_THIS);
2270                 NEW_ARGLOAD (cfg, ins->inst_left, 0);
2271                 ins->cil_code = ip;
2272                 MONO_ADD_INS (bblock, ins);
2273         }
2274
2275         /* we use a spare stack slot in SWITCH and NEWOBJ and others */
2276         stack_start = sp = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * (header->max_stack + 1));
2277
2278         ins_flag = 0;
2279         start_new_bblock = 0;
2280         while (ip < end) {
2281
2282                 if (cfg->method == method)
2283                         real_offset = ip - header->code;
2284                 else
2285                         real_offset = inline_offset;
2286
2287                 if (start_new_bblock) {
2288                         bblock->cil_length = ip - bblock->cil_code;
2289                         if (start_new_bblock == 2) {
2290                                 g_assert (ip == tblock->cil_code);
2291                         } else {
2292                                 GET_BBLOCK (cfg, bbhash, tblock, ip);
2293                         }
2294                         bblock->next_bb = tblock;
2295                         bblock = tblock;
2296                         start_new_bblock = 0;
2297                         for (i = 0; i < bblock->in_scount; ++i) {
2298                                 NEW_TEMPLOAD (cfg, ins, bblock->in_stack [i]->inst_c0);
2299                                 *sp++ = ins;
2300                         }
2301                 } else {
2302                         if ((tblock = g_hash_table_lookup (bbhash, ip)) && (tblock != bblock)) {
2303                                 link_bblock (cfg, bblock, tblock);
2304                                 if (sp != stack_start) {
2305                                         handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
2306                                         sp = stack_start;
2307                                 }
2308                                 bblock->next_bb = tblock;
2309                                 bblock = tblock;
2310                                 for (i = 0; i < bblock->in_scount; ++i) {
2311                                         NEW_TEMPLOAD (cfg, ins, bblock->in_stack [i]->inst_c0);
2312                                         *sp++ = ins;
2313                                 }
2314                         }
2315                 }
2316
2317                 if (cfg->verbose_level > 3)
2318                         g_print ("converting (in B%d: stack: %d) %s", bblock->block_num, sp-stack_start, mono_disasm_code_one (NULL, method, ip, NULL));
2319
2320                 switch (*ip) {
2321                 case CEE_NOP:
2322                         ++ip;
2323                         break;
2324                 case CEE_BREAK:
2325                         MONO_INST_NEW (cfg, ins, CEE_BREAK);
2326                         ins->cil_code = ip++;
2327                         MONO_ADD_INS (bblock, ins);
2328                         break;
2329                 case CEE_LDARG_0:
2330                 case CEE_LDARG_1:
2331                 case CEE_LDARG_2:
2332                 case CEE_LDARG_3:
2333                         CHECK_STACK_OVF (1);
2334                         n = (*ip)-CEE_LDARG_0;
2335                         NEW_ARGLOAD (cfg, ins, n);
2336                         ins->cil_code = ip++;
2337                         *sp++ = ins;
2338                         break;
2339                 case CEE_LDLOC_0:
2340                 case CEE_LDLOC_1:
2341                 case CEE_LDLOC_2:
2342                 case CEE_LDLOC_3:
2343                         CHECK_STACK_OVF (1);
2344                         n = (*ip)-CEE_LDLOC_0;
2345                         NEW_LOCLOAD (cfg, ins, n);
2346                         ins->cil_code = ip++;
2347                         *sp++ = ins;
2348                         break;
2349                 case CEE_STLOC_0:
2350                 case CEE_STLOC_1:
2351                 case CEE_STLOC_2:
2352                 case CEE_STLOC_3:
2353                         CHECK_STACK (1);
2354                         n = (*ip)-CEE_STLOC_0;
2355                         --sp;
2356                         handle_loaded_temps (cfg, bblock, stack_start, sp);
2357                         NEW_LOCSTORE (cfg, ins, n, *sp);
2358                         ins->cil_code = ip;
2359                         if (ins->opcode == CEE_STOBJ) {
2360                                 NEW_LOCLOADA (cfg, ins, n);
2361                                 handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE);
2362                         } else
2363                                 MONO_ADD_INS (bblock, ins);
2364                         ++ip;
2365                         inline_costs += 1;
2366                         break;
2367                 case CEE_LDARG_S:
2368                         CHECK_STACK_OVF (1);
2369                         NEW_ARGLOAD (cfg, ins, ip [1]);
2370                         ins->cil_code = ip;
2371                         *sp++ = ins;
2372                         ip += 2;
2373                         break;
2374                 case CEE_LDARGA_S:
2375                         CHECK_STACK_OVF (1);
2376                         NEW_ARGLOADA (cfg, ins, ip [1]);
2377                         ins->cil_code = ip;
2378                         *sp++ = ins;
2379                         ip += 2;
2380                         break;
2381                 case CEE_STARG_S:
2382                         CHECK_STACK (1);
2383                         --sp;
2384                         NEW_ARGSTORE (cfg, ins, ip [1], *sp);
2385                         handle_loaded_temps (cfg, bblock, stack_start, sp);
2386                         ins->cil_code = ip;
2387                         if (ins->opcode == CEE_STOBJ) {
2388                                 NEW_ARGLOADA (cfg, ins, ip [1]);
2389                                 handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE);
2390                         } else
2391                                 MONO_ADD_INS (bblock, ins);
2392                         ip += 2;
2393                         break;
2394                 case CEE_LDLOC_S:
2395                         CHECK_STACK_OVF (1);
2396                         NEW_LOCLOAD (cfg, ins, ip [1]);
2397                         ins->cil_code = ip;
2398                         *sp++ = ins;
2399                         ip += 2;
2400                         break;
2401                 case CEE_LDLOCA_S:
2402                         CHECK_STACK_OVF (1);
2403                         NEW_LOCLOADA (cfg, ins, ip [1]);
2404                         ins->cil_code = ip;
2405                         *sp++ = ins;
2406                         ip += 2;
2407                         break;
2408                 case CEE_STLOC_S:
2409                         CHECK_STACK (1);
2410                         --sp;
2411                         handle_loaded_temps (cfg, bblock, stack_start, sp);
2412                         NEW_LOCSTORE (cfg, ins, ip [1], *sp);
2413                         ins->cil_code = ip;
2414                         if (ins->opcode == CEE_STOBJ) {
2415                                 NEW_LOCLOADA (cfg, ins, ip [1]);
2416                                 handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE);
2417                         } else
2418                                 MONO_ADD_INS (bblock, ins);
2419                         ip += 2;
2420                         inline_costs += 1;
2421                         break;
2422                 case CEE_LDNULL:
2423                         CHECK_STACK_OVF (1);
2424                         NEW_PCONST (cfg, ins, NULL);
2425                         ins->cil_code = ip;
2426                         ins->type = STACK_OBJ;
2427                         ++ip;
2428                         *sp++ = ins;
2429                         break;
2430                 case CEE_LDC_I4_M1:
2431                         CHECK_STACK_OVF (1);
2432                         NEW_ICONST (cfg, ins, -1);
2433                         ins->cil_code = ip;
2434                         ++ip;
2435                         *sp++ = ins;
2436                         break;
2437                 case CEE_LDC_I4_0:
2438                 case CEE_LDC_I4_1:
2439                 case CEE_LDC_I4_2:
2440                 case CEE_LDC_I4_3:
2441                 case CEE_LDC_I4_4:
2442                 case CEE_LDC_I4_5:
2443                 case CEE_LDC_I4_6:
2444                 case CEE_LDC_I4_7:
2445                 case CEE_LDC_I4_8:
2446                         CHECK_STACK_OVF (1);
2447                         NEW_ICONST (cfg, ins, (*ip) - CEE_LDC_I4_0);
2448                         ins->cil_code = ip;
2449                         ++ip;
2450                         *sp++ = ins;
2451                         break;
2452                 case CEE_LDC_I4_S:
2453                         CHECK_STACK_OVF (1);
2454                         ++ip;
2455                         NEW_ICONST (cfg, ins, *((signed char*)ip));
2456                         ins->cil_code = ip;
2457                         ++ip;
2458                         *sp++ = ins;
2459                         break;
2460                 case CEE_LDC_I4:
2461                         CHECK_STACK_OVF (1);
2462                         NEW_ICONST (cfg, ins, (gint32)read32 (ip + 1));
2463                         ins->cil_code = ip;
2464                         ip += 5;
2465                         *sp++ = ins;
2466                         break;
2467                 case CEE_LDC_I8:
2468                         CHECK_STACK_OVF (1);
2469                         MONO_INST_NEW (cfg, ins, OP_I8CONST);
2470                         ins->cil_code = ip;
2471                         ins->type = STACK_I8;
2472                         ++ip;
2473                         ins->inst_l = (gint64)read64 (ip);
2474                         ip += 8;
2475                         *sp++ = ins;
2476                         break;
2477                 case CEE_LDC_R4: {
2478                         float *f = g_malloc (sizeof (float));
2479                         CHECK_STACK_OVF (1);
2480                         MONO_INST_NEW (cfg, ins, OP_R4CONST);
2481                         ins->type = STACK_R8;
2482                         ++ip;
2483                         readr4 (ip, f);
2484                         ins->inst_p0 = f;
2485                         ip += 4;
2486                         *sp++ = ins;                    
2487                         break;
2488                 }
2489                 case CEE_LDC_R8: {
2490                         double *d = g_malloc (sizeof (double));
2491                         CHECK_STACK_OVF (1);
2492                         MONO_INST_NEW (cfg, ins, OP_R8CONST);
2493                         ins->type = STACK_R8;
2494                         ++ip;
2495                         readr8 (ip, d);
2496                         ins->inst_p0 = d;
2497                         ip += 8;
2498                         *sp++ = ins;                    
2499                         break;
2500                 }
2501                 case CEE_DUP: {
2502                         MonoInst *temp, *store;
2503                         CHECK_STACK (1);
2504                         CHECK_STACK_OVF (1);
2505                         sp--;
2506                         ins = *sp;
2507                 
2508                         /* 
2509                          * small optimization: if the loaded value was from a local already,
2510                          * just load it twice.
2511                          */
2512                         if (ins->ssa_op == MONO_SSA_LOAD && 
2513                             (ins->inst_i0->opcode == OP_LOCAL || ins->inst_i0->opcode == OP_ARG)) {
2514                                 sp++;
2515                                 MONO_INST_NEW (cfg, temp, 0);
2516                                 *temp = *ins;
2517                                 temp->cil_code = ip;
2518                                 *sp++ = temp;
2519                         } else {
2520                                 temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
2521                                 temp->cil_code = ip;
2522                                 NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
2523                                 store->cil_code = ip;
2524                                 MONO_ADD_INS (bblock, store);
2525                                 NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
2526                                 *sp++ = ins;
2527                                 ins->cil_code = ip;
2528                                 NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
2529                                 *sp++ = ins;
2530                                 ins->cil_code = ip;
2531                         }
2532                         ++ip;
2533                         inline_costs += 2;
2534                         break;
2535                 }
2536                 case CEE_POP:
2537                         CHECK_STACK (1);
2538                         MONO_INST_NEW (cfg, ins, CEE_POP);
2539                         MONO_ADD_INS (bblock, ins);
2540                         ins->cil_code = ip++;
2541                         --sp;
2542                         ins->inst_i0 = *sp;
2543                         break;
2544                 case CEE_JMP:
2545                         if (stack_start != sp)
2546                                 goto unverified;
2547                         MONO_INST_NEW (cfg, ins, CEE_JMP);
2548                         token = read32 (ip + 1);
2549                         /* FIXME: check the signature matches */
2550                         cmethod = mono_get_method (image, token, NULL);
2551                         /*
2552                          * The current magic trampoline can't handle this
2553                          * apparently, so we compile the method right away.
2554                          * Later, we may need to fix the trampoline or use a different one.
2555                          */
2556                         ins->inst_p0 = mono_compile_method (cmethod);
2557                         MONO_ADD_INS (bblock, ins);
2558                         ip += 5;
2559                         start_new_bblock = 1;
2560                         break;
2561                 case CEE_CALLI:
2562                 case CEE_CALL:
2563                 case CEE_CALLVIRT: {
2564                         MonoInst *addr = NULL;
2565                         MonoMethodSignature *fsig = NULL;
2566                         int temp, array_rank = 0;
2567                         int virtual = *ip == CEE_CALLVIRT;
2568
2569                         token = read32 (ip + 1);
2570
2571                         if (*ip == CEE_CALLI) {
2572                                 cmethod = NULL;
2573                                 CHECK_STACK (1);
2574                                 --sp;
2575                                 addr = *sp;
2576                                 if (method->wrapper_type != MONO_WRAPPER_NONE)
2577                                         fsig = (MonoMethodSignature *)mono_method_get_wrapper_data (method, token);
2578                                 else
2579                                         fsig = mono_metadata_parse_signature (image, token);
2580
2581                                 n = fsig->param_count + fsig->hasthis;
2582
2583                         } else {
2584                                 cmethod = mono_get_method (image, token, NULL);
2585
2586                                 if (!cmethod->klass->inited)
2587                                         mono_class_init (cmethod->klass);
2588
2589                                 if (cmethod->signature->pinvoke) {
2590 #ifdef MONO_USE_EXC_TABLES
2591                                         if (mono_method_blittable (cmethod)) {
2592                                                 fsig = cmethod->signature;
2593                                         } else {
2594 #endif
2595                                                 MonoMethod *wrapper = mono_marshal_get_native_wrapper (cmethod);
2596                                                 fsig = wrapper->signature;
2597 #ifdef MONO_USE_EXC_TABLES
2598                                         }
2599 #endif
2600                                 } else {
2601                                         fsig = cmethod->signature;
2602                                 }
2603
2604                                 n = fsig->param_count + fsig->hasthis;
2605
2606                                 if (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL &&
2607                                     cmethod->klass->parent == mono_defaults.array_class) {
2608                                         array_rank = cmethod->klass->rank;
2609                                 }
2610
2611                                 if (cmethod->string_ctor)
2612                                         g_assert_not_reached ();
2613
2614                         }
2615
2616                         CHECK_STACK (n);
2617
2618                         //g_assert (!virtual || fsig->hasthis);
2619
2620                         sp -= n;
2621
2622                         if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_get_opcode_for_method (cfg, cmethod, fsig, sp))) {
2623                                 ins->cil_code = ip;
2624
2625                                 if (MONO_TYPE_IS_VOID (fsig->ret)) {
2626                                         MONO_ADD_INS (bblock, ins);
2627                                 } else {
2628                                         type_to_eval_stack_type (fsig->ret, ins);
2629                                         *sp = ins;
2630                                         sp++;
2631                                 }
2632
2633                                 ip += 5;
2634                                 break;
2635                         }
2636
2637                         if ((cfg->opt & MONO_OPT_INLINE) && cmethod &&
2638                             (!virtual || !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) || (cmethod->flags & METHOD_ATTRIBUTE_FINAL)) && 
2639                             mono_method_check_inlining (cmethod) &&
2640                             !g_list_find (dont_inline, cmethod)) {
2641                                 int costs;
2642                                 MonoBasicBlock *ebblock;
2643                                 
2644                                 if ((costs = inline_method (cfg, cmethod, fsig, bblock, sp, ip, real_offset, dont_inline, &ebblock))) {
2645                                         ip += 5;
2646                                         real_offset += 5;
2647
2648                                         GET_BBLOCK (cfg, bbhash, bblock, ip);
2649                                         ebblock->next_bb = bblock;
2650                                         link_bblock (cfg, ebblock, bblock);
2651                                         if (!MONO_TYPE_IS_VOID (fsig->ret))
2652                                                 sp++;
2653
2654                                         if (sp != stack_start) {
2655                                                 handle_stack_args (cfg, ebblock, stack_start, sp - stack_start);
2656                                                 sp = stack_start;
2657                                         }
2658                                         start_new_bblock = 1;
2659
2660                                         inline_costs += costs;
2661                                         break;
2662                                 }
2663                         }
2664                         
2665                         inline_costs += 10 * num_calls++;
2666                         handle_loaded_temps (cfg, bblock, stack_start, sp);
2667
2668                         /* tail recursion elimination */
2669                         if ((cfg->opt & MONO_OPT_TAILC) && *ip == CEE_CALL && cmethod == cfg->method && ip [5] == CEE_RET) {
2670                                 gboolean has_vtargs = FALSE;
2671                                 int i;
2672                                 
2673                                 /* keep it simple */
2674                                 for (i =  fsig->param_count - 1; i >= 0; i--) {
2675                                         if (MONO_TYPE_ISSTRUCT (cmethod->signature->params [i])) 
2676                                                 has_vtargs = TRUE;
2677                                 }
2678
2679                                 if (!has_vtargs) {
2680                                         for (i = 0; i < n; ++i) {
2681                                                 NEW_ARGSTORE (cfg, ins, i, sp [i]);
2682                                                 ins->cil_code = ip;
2683                                                 MONO_ADD_INS (bblock, ins);
2684                                         }
2685                                         MONO_INST_NEW (cfg, ins, CEE_BR);
2686                                         ins->cil_code = ip;
2687                                         MONO_ADD_INS (bblock, ins);
2688                                         tblock = start_bblock->out_bb [0];
2689                                         link_bblock (cfg, bblock, tblock);
2690                                         ins->inst_target_bb = tblock;
2691                                         start_new_bblock = 1;
2692                                         ip += 5;
2693                                         
2694                                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
2695                                                 /* just create a dummy - the value is never used */
2696                                                 ins = mono_compile_create_var (cfg, fsig->ret, OP_LOCAL);
2697                                                 NEW_TEMPLOAD (cfg, *sp, ins->inst_c0);
2698                                                 sp++;
2699                                         }
2700
2701                                         break;
2702                                 }
2703                         }
2704
2705                         if (*ip == CEE_CALLI) {
2706
2707                                 if ((temp = mono_emit_calli (cfg, bblock, fsig, sp, addr, ip)) != -1) {
2708                                         NEW_TEMPLOAD (cfg, *sp, temp);
2709                                         sp++;
2710                                 }
2711                                         
2712                         } else if (array_rank) {
2713                                 MonoMethodSignature *esig;
2714                                 MonoInst *addr;
2715
2716                                 if (strcmp (cmethod->name, "Set") == 0) { /* array Set */ 
2717                                         esig = mono_get_element_address_signature (fsig->param_count - 1);
2718                                         
2719                                         temp = mono_emit_native_call (cfg, bblock, ves_array_element_address, esig, sp, ip, FALSE);
2720                                         NEW_TEMPLOAD (cfg, addr, temp);
2721                                         NEW_INDSTORE (cfg, ins, addr, sp [fsig->param_count], fsig->params [fsig->param_count - 1]);
2722                                         ins->cil_code = ip;
2723                                         if (ins->opcode == CEE_STOBJ) {
2724                                                 handle_stobj (cfg, bblock, addr, sp [fsig->param_count], ip, mono_class_from_mono_type (fsig->params [fsig->param_count-1]), FALSE, FALSE);
2725                                         } else {
2726                                                 MONO_ADD_INS (bblock, ins);
2727                                         }
2728
2729                                 } else if (strcmp (cmethod->name, "Get") == 0) { /* array Get */
2730                                         esig = mono_get_element_address_signature (fsig->param_count);
2731
2732                                         temp = mono_emit_native_call (cfg, bblock, ves_array_element_address, esig, sp, ip, FALSE);
2733                                         NEW_TEMPLOAD (cfg, addr, temp);
2734                                         NEW_INDLOAD (cfg, ins, addr, fsig->ret);
2735                                         ins->cil_code = ip;
2736
2737                                         *sp++ = ins;
2738                                 } else if (strcmp (cmethod->name, "Address") == 0) { /* array Address */
2739                                         /* implement me */
2740                                         esig = mono_get_element_address_signature (fsig->param_count);
2741
2742                                         temp = mono_emit_native_call (cfg, bblock, ves_array_element_address, esig, sp, ip, FALSE);
2743                                         NEW_TEMPLOAD (cfg, *sp, temp);
2744                                         sp++;
2745                                 } else {
2746                                         g_assert_not_reached ();
2747                                 }
2748
2749                         } else {
2750                                 if (0 && CODE_IS_STLOC (ip + 5) && (!MONO_TYPE_ISSTRUCT (fsig->ret)) && (!MONO_TYPE_IS_VOID (fsig->ret) || cmethod->string_ctor)) {
2751                                         /* no need to spill */
2752                                         ins = (MonoInst*)mono_emit_method_call (cfg, bblock, cmethod, fsig, sp, ip, virtual ? sp [0] : NULL);
2753                                         *sp++ = ins;
2754                                 } else {
2755                                         if ((temp = mono_emit_method_call_spilled (cfg, bblock, cmethod, sp, ip, virtual ? sp [0] : NULL)) != -1) {
2756                                                 NEW_TEMPLOAD (cfg, *sp, temp);
2757                                                 sp++;
2758                                         }
2759                                 }
2760                         }
2761
2762                         ip += 5;
2763                         break;
2764                 }
2765                 case CEE_RET:
2766                         if (cfg->method != method) {
2767                                 /* return from inlined methode */
2768                                 if (return_var) {
2769                                         MonoInst *store;
2770                                         CHECK_STACK (1);
2771                                         --sp;
2772                                         //g_assert (returnvar != -1);
2773                                         NEW_TEMPSTORE (cfg, store, return_var->inst_c0, *sp);
2774                                         store->cil_code = sp [0]->cil_code;
2775                                         if (store->opcode == CEE_STOBJ) {
2776                                                 g_assert_not_reached ();
2777                                                 NEW_TEMPLOADA (cfg, store, return_var->inst_c0);
2778                                                 handle_stobj (cfg, bblock, store, *sp, sp [0]->cil_code, return_var->klass, FALSE, FALSE);
2779                                         } else
2780                                                 MONO_ADD_INS (bblock, store);
2781                                 } 
2782                         } else {
2783                                 if (cfg->ret) {
2784                                         g_assert (!return_var);
2785                                         CHECK_STACK (1);
2786                                         --sp;
2787                                         MONO_INST_NEW (cfg, ins, CEE_NOP);
2788                                         ins->opcode = mono_type_to_stind (method->signature->ret);
2789                                         if (ins->opcode == CEE_STOBJ) {
2790                                                 NEW_RETLOADA (cfg, ins);
2791                                                 handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE);
2792                                         } else {
2793                                                 ins->opcode = OP_SETRET;
2794                                                 ins->cil_code = ip;
2795                                                 ins->inst_i0 = *sp;;
2796                                                 ins->inst_i1 = NULL;
2797                                                 MONO_ADD_INS (bblock, ins);
2798                                         }
2799                                 }
2800                         }
2801                         if (sp != stack_start)
2802                                 goto unverified;
2803                         MONO_INST_NEW (cfg, ins, CEE_BR);
2804                         ins->cil_code = ip++;
2805                         ins->inst_target_bb = end_bblock;
2806                         MONO_ADD_INS (bblock, ins);
2807                         link_bblock (cfg, bblock, end_bblock);
2808                         start_new_bblock = 1;
2809                         break;
2810                 case CEE_BR_S:
2811                         MONO_INST_NEW (cfg, ins, CEE_BR);
2812                         ins->cil_code = ip++;
2813                         MONO_ADD_INS (bblock, ins);
2814                         target = ip + 1 + (signed char)(*ip);
2815                         ++ip;
2816                         GET_BBLOCK (cfg, bbhash, tblock, target);
2817                         link_bblock (cfg, bblock, tblock);
2818                         CHECK_BBLOCK (target, ip, tblock);
2819                         ins->inst_target_bb = tblock;
2820                         if (sp != stack_start) {
2821                                 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
2822                                 sp = stack_start;
2823                         }
2824                         start_new_bblock = 1;
2825                         inline_costs += 10;
2826                         break;
2827                 case CEE_BRFALSE_S:
2828                 case CEE_BRTRUE_S:
2829                         CHECK_STACK (1);
2830                         MONO_INST_NEW (cfg, ins, *ip + BIG_BRANCH_OFFSET);
2831                         ins->cil_code = ip++;
2832                         target = ip + 1 + *(signed char*)ip;
2833                         ip++;
2834                         ADD_UNCOND (ins->opcode == CEE_BRTRUE);
2835                         if (sp != stack_start) {
2836                                 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
2837                                 sp = stack_start;
2838                         }
2839                         inline_costs += 10;
2840                         break;
2841                 case CEE_BEQ_S:
2842                 case CEE_BGE_S:
2843                 case CEE_BGT_S:
2844                 case CEE_BLE_S:
2845                 case CEE_BLT_S:
2846                 case CEE_BNE_UN_S:
2847                 case CEE_BGE_UN_S:
2848                 case CEE_BGT_UN_S:
2849                 case CEE_BLE_UN_S:
2850                 case CEE_BLT_UN_S:
2851                         CHECK_STACK (2);
2852                         MONO_INST_NEW (cfg, ins, *ip + BIG_BRANCH_OFFSET);
2853                         ins->cil_code = ip++;
2854                         target = ip + 1 + *(signed char*)ip;
2855                         ip++;
2856                         ADD_BINCOND (NULL);
2857                         if (sp != stack_start) {
2858                                 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
2859                                 sp = stack_start;
2860                         }
2861                         inline_costs += 10;
2862                         break;
2863                 case CEE_BR:
2864                         MONO_INST_NEW (cfg, ins, CEE_BR);
2865                         ins->cil_code = ip++;
2866                         MONO_ADD_INS (bblock, ins);
2867                         target = ip + 4 + (gint32)read32(ip);
2868                         ip += 4;
2869                         GET_BBLOCK (cfg, bbhash, tblock, target);
2870                         link_bblock (cfg, bblock, tblock);
2871                         CHECK_BBLOCK (target, ip, tblock);
2872                         ins->inst_target_bb = tblock;
2873                         if (sp != stack_start) {
2874                                 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
2875                                 sp = stack_start;
2876                         }
2877                         start_new_bblock = 1;
2878                         inline_costs += 10;
2879                         break;
2880                 case CEE_BRFALSE:
2881                 case CEE_BRTRUE:
2882                         CHECK_STACK (1);
2883                         MONO_INST_NEW (cfg, ins, *ip);
2884                         ins->cil_code = ip++;
2885                         target = ip + 4 + (gint32)read32(ip);
2886                         ip += 4;
2887                         ADD_UNCOND(ins->opcode == CEE_BRTRUE);
2888                         if (sp != stack_start) {
2889                                 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
2890                                 sp = stack_start;
2891                         }
2892                         inline_costs += 10;
2893                         break;
2894                 case CEE_BEQ:
2895                 case CEE_BGE:
2896                 case CEE_BGT:
2897                 case CEE_BLE:
2898                 case CEE_BLT:
2899                 case CEE_BNE_UN:
2900                 case CEE_BGE_UN:
2901                 case CEE_BGT_UN:
2902                 case CEE_BLE_UN:
2903                 case CEE_BLT_UN:
2904                         CHECK_STACK (2);
2905                         MONO_INST_NEW (cfg, ins, *ip);
2906                         ins->cil_code = ip++;
2907                         target = ip + 4 + (gint32)read32(ip);
2908                         ip += 4;
2909                         ADD_BINCOND(NULL);
2910                         if (sp != stack_start) {
2911                                 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
2912                                 sp = stack_start;
2913                         }
2914                         inline_costs += 10;
2915                         break;
2916                 case CEE_SWITCH:
2917                         CHECK_STACK (1);
2918                         n = read32 (ip + 1);
2919                         MONO_INST_NEW (cfg, ins, *ip);
2920                         --sp;
2921                         ins->inst_left = *sp;
2922                         if (ins->inst_left->type != STACK_I4) goto unverified;
2923                         ins->cil_code = ip;
2924                         ip += 5;
2925                         target = ip + n * sizeof (guint32);
2926                         MONO_ADD_INS (bblock, ins);
2927                         GET_BBLOCK (cfg, bbhash, tblock, target);
2928                         link_bblock (cfg, bblock, tblock);
2929                         ins->klass = GUINT_TO_POINTER (n);
2930                         ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * (n + 1));
2931                         ins->inst_many_bb [n] = tblock;
2932
2933                         for (i = 0; i < n; ++i) {
2934                                 GET_BBLOCK (cfg, bbhash, tblock, target + (gint32)read32(ip));
2935                                 link_bblock (cfg, bblock, tblock);
2936                                 ins->inst_many_bb [i] = tblock;
2937                                 ip += 4;
2938                         }
2939                         /* FIXME: handle stack args */
2940                         inline_costs += 20;
2941                         break;
2942                 case CEE_LDIND_I1:
2943                 case CEE_LDIND_U1:
2944                 case CEE_LDIND_I2:
2945                 case CEE_LDIND_U2:
2946                 case CEE_LDIND_I4:
2947                 case CEE_LDIND_U4:
2948                 case CEE_LDIND_I8:
2949                 case CEE_LDIND_I:
2950                 case CEE_LDIND_R4:
2951                 case CEE_LDIND_R8:
2952                 case CEE_LDIND_REF:
2953                         CHECK_STACK (1);
2954                         MONO_INST_NEW (cfg, ins, *ip);
2955                         ins->cil_code = ip;
2956                         --sp;
2957                         ins->inst_i0 = *sp;
2958                         *sp++ = ins;
2959                         ins->type = ldind_type [*ip - CEE_LDIND_I1];
2960                         ins->flags |= ins_flag;
2961                         ins_flag = 0;
2962                         ++ip;
2963                         break;
2964                 case CEE_STIND_REF:
2965                 case CEE_STIND_I1:
2966                 case CEE_STIND_I2:
2967                 case CEE_STIND_I4:
2968                 case CEE_STIND_I8:
2969                 case CEE_STIND_R4:
2970                 case CEE_STIND_R8:
2971                         CHECK_STACK (2);
2972                         MONO_INST_NEW (cfg, ins, *ip);
2973                         ins->cil_code = ip++;
2974                         sp -= 2;
2975                         handle_loaded_temps (cfg, bblock, stack_start, sp);
2976                         MONO_ADD_INS (bblock, ins);
2977                         ins->inst_i0 = sp [0];
2978                         ins->inst_i1 = sp [1];
2979                         ins->flags |= ins_flag;
2980                         ins_flag = 0;
2981                         inline_costs += 1;
2982                         break;
2983                 case CEE_ADD:
2984                 case CEE_SUB:
2985                 case CEE_MUL:
2986                 case CEE_DIV:
2987                 case CEE_DIV_UN:
2988                 case CEE_REM:
2989                 case CEE_REM_UN:
2990                 case CEE_AND:
2991                 case CEE_OR:
2992                 case CEE_XOR:
2993                 case CEE_SHL:
2994                 case CEE_SHR:
2995                 case CEE_SHR_UN:
2996                         CHECK_STACK (2);
2997                         ADD_BINOP (*ip);
2998                         ip++;
2999                         break;
3000                 case CEE_NEG:
3001                 case CEE_NOT:
3002                 case CEE_CONV_I1:
3003                 case CEE_CONV_I2:
3004                 case CEE_CONV_I4:
3005                 case CEE_CONV_I8:
3006                 case CEE_CONV_R4:
3007                 case CEE_CONV_R8:
3008                 case CEE_CONV_U4:
3009                 case CEE_CONV_U8:
3010                 case CEE_CONV_OVF_I8:
3011                 case CEE_CONV_OVF_U8:
3012                 case CEE_CONV_R_UN:
3013                         CHECK_STACK (1);
3014                         ADD_UNOP (*ip);
3015                         ip++;
3016                         break;
3017                 case CEE_CONV_OVF_I4:
3018                 case CEE_CONV_OVF_I1:
3019                 case CEE_CONV_OVF_I2:
3020                 case CEE_CONV_OVF_I:
3021                 case CEE_CONV_OVF_U:
3022                         CHECK_STACK (1);
3023
3024                         if (sp [-1]->type == STACK_R8) {
3025                                 ADD_UNOP (CEE_CONV_OVF_I8);
3026                                 ADD_UNOP (*ip);
3027                         } else {
3028                                 ADD_UNOP (*ip);
3029                         }
3030
3031                         ip++;
3032                         break;
3033                 case CEE_CONV_OVF_U1:
3034                 case CEE_CONV_OVF_U2:
3035                 case CEE_CONV_OVF_U4:
3036                         CHECK_STACK (1);
3037
3038                         if (sp [-1]->type == STACK_R8) {
3039                                 ADD_UNOP (CEE_CONV_OVF_U8);
3040                                 ADD_UNOP (*ip);
3041                         } else {
3042                                 ADD_UNOP (*ip);
3043                         }
3044
3045                         ip++;
3046                         break;
3047                 case CEE_CONV_OVF_I1_UN:
3048                 case CEE_CONV_OVF_I2_UN:
3049                 case CEE_CONV_OVF_I4_UN:
3050                 case CEE_CONV_OVF_I8_UN:
3051                 case CEE_CONV_OVF_U1_UN:
3052                 case CEE_CONV_OVF_U2_UN:
3053                 case CEE_CONV_OVF_U4_UN:
3054                 case CEE_CONV_OVF_U8_UN:
3055                 case CEE_CONV_OVF_I_UN:
3056                 case CEE_CONV_OVF_U_UN:
3057                         CHECK_STACK (1);
3058                         ADD_UNOP (*ip);
3059                         ip++;
3060                         break;
3061                 case CEE_CPOBJ:
3062                         g_error ("opcode 0x%02x not handled", *ip);
3063                         break;
3064                 case CEE_LDOBJ: {
3065                         MonoInst *iargs [3];
3066                         CHECK_STACK (1);
3067                         --sp;
3068                         token = read32 (ip + 1);
3069                         if (method->wrapper_type != MONO_WRAPPER_NONE)
3070                                 klass = mono_method_get_wrapper_data (method, token);
3071                         else
3072                                 klass = mono_class_get (image, token);
3073
3074                         mono_class_init (klass);
3075                         n = mono_class_value_size (klass, NULL);
3076                         ins = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
3077                         NEW_TEMPLOADA (cfg, iargs [0], ins->inst_c0);
3078                         iargs [1] = *sp;
3079                         NEW_ICONST (cfg, iargs [2], n);
3080                         iargs [2]->cil_code = ip;
3081
3082                         mono_emit_jit_icall (cfg, bblock, helper_memcpy, iargs, ip);
3083                         NEW_TEMPLOAD (cfg, *sp, ins->inst_c0);
3084                         ++sp;
3085                         ip += 5;
3086                         inline_costs += 1;
3087                         break;
3088                 }
3089                 case CEE_LDSTR:
3090                         CHECK_STACK_OVF (1);
3091                         n = read32 (ip + 1);
3092
3093                         if (mono_compile_aot) {
3094                                 cfg->ldstr_list = g_list_prepend (cfg->ldstr_list, (gpointer)n);
3095                         }
3096
3097                         if ((cfg->opt & MONO_OPT_SAHRED) || mono_compile_aot) {
3098                                 int temp;
3099                                 MonoInst *iargs [3];
3100                                 NEW_TEMPLOAD (cfg, iargs [0], mono_get_domainvar (cfg)->inst_c0);
3101                                 NEW_IMAGECONST (cfg, iargs [1], image);
3102                                 NEW_ICONST (cfg, iargs [2], mono_metadata_token_index (n));
3103                                 temp = mono_emit_jit_icall (cfg, bblock, mono_ldstr, iargs, ip);
3104                                 NEW_TEMPLOAD (cfg, *sp, temp);
3105                                 mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
3106                         } else {
3107                                 NEW_PCONST (cfg, ins, NULL);
3108                                 ins->cil_code = ip;
3109                                 ins->type = STACK_OBJ;
3110                                 ins->inst_p0 = mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
3111                                 *sp = ins;
3112                         }
3113                         sp++;
3114                         ip += 5;
3115                         break;
3116                 case CEE_NEWOBJ: {
3117                         MonoInst *iargs [2];
3118                         int temp;
3119
3120                         token = read32 (ip + 1);
3121                         if (method->wrapper_type != MONO_WRAPPER_NONE) {
3122                                 cmethod = mono_method_get_wrapper_data (method, token);
3123                         } else
3124                                 cmethod = mono_get_method (image, token, NULL);
3125
3126                         mono_class_init (cmethod->klass);
3127
3128                         n = cmethod->signature->param_count;
3129                         CHECK_STACK (n);
3130
3131                         /* move the args to allow room for 'this' in the first position */
3132                         while (n--) {
3133                                 --sp;
3134                                 sp [1] = sp [0];
3135                         }
3136
3137                         handle_loaded_temps (cfg, bblock, stack_start, sp);
3138                         
3139
3140                         if (cmethod->klass->parent == mono_defaults.array_class) {
3141                                 NEW_METHODCONST (cfg, *sp, cmethod);
3142                                 temp = mono_emit_native_call (cfg, bblock, mono_array_new_va, cmethod->signature, sp, ip, FALSE);
3143
3144                         } else if (cmethod->string_ctor) {
3145                                 /* we simply pass a null pointer */
3146                                 NEW_PCONST (cfg, *sp, NULL); 
3147                                 /* now call the string ctor */
3148                                 temp = mono_emit_method_call_spilled (cfg, bblock, cmethod, sp, ip, NULL);
3149                         } else {
3150                                 if (cmethod->klass->valuetype) {
3151                                         iargs [0] = mono_compile_create_var (cfg, &cmethod->klass->byval_arg, OP_LOCAL);
3152                                         temp = iargs [0]->inst_c0;
3153                                         NEW_TEMPLOADA (cfg, *sp, temp);
3154                                 } else {
3155                                         NEW_DOMAINCONST (cfg, iargs [0]);
3156                                         NEW_CLASSCONST (cfg, iargs [1], cmethod->klass);
3157
3158                                         temp = mono_emit_jit_icall (cfg, bblock, mono_object_new, iargs, ip);
3159                                         NEW_TEMPLOAD (cfg, *sp, temp);
3160                                 }
3161
3162                                 if ((cfg->opt & MONO_OPT_INLINE) && cmethod &&
3163                                     mono_method_check_inlining (cmethod) &&
3164                                     !mono_class_is_subclass_of (cmethod->klass, mono_defaults.exception_class, FALSE) &&
3165                                     !g_list_find (dont_inline, cmethod)) {
3166                                         int costs;
3167                                         MonoBasicBlock *ebblock;
3168                                         if ((costs = inline_method (cfg, cmethod, cmethod->signature, bblock, sp, ip, real_offset, dont_inline, &ebblock))) {
3169
3170                                                 GET_BBLOCK (cfg, bbhash, bblock, ip + 5);
3171                                                 ebblock->next_bb = bblock;
3172                                                 link_bblock (cfg, ebblock, bblock);
3173
3174                                                 /*if (sp != stack_start) {
3175                                                         handle_stack_args (cfg, ebblock, stack_start, sp - stack_start);
3176                                                         sp = stack_start;
3177                                                 }
3178                                                 start_new_bblock = 1;*/
3179
3180                                                 inline_costs += costs;
3181                                                 /*g_print ("inlined newobj for %s\n", cmethod->klass->name);*/
3182                                         }
3183                                 } else {
3184                                         /* now call the actual ctor */
3185                                         mono_emit_method_call_spilled (cfg, bblock, cmethod, sp, ip, NULL);
3186                                 }
3187                         }
3188
3189                         NEW_TEMPLOAD (cfg, *sp, temp);
3190                         sp++;
3191                         
3192                         ip += 5;
3193                         inline_costs += 5;
3194                         break;
3195                 }
3196                 case CEE_ISINST:
3197                         CHECK_STACK (1);
3198                         MONO_INST_NEW (cfg, ins, *ip);
3199                         --sp;
3200                         klass = mono_class_get (image, read32 (ip + 1));
3201                         mono_class_init (klass);
3202                         ins->type = STACK_OBJ;
3203                         ins->inst_left = *sp;
3204                         ins->inst_newa_class = klass;
3205                         ins->cil_code = ip;
3206                         ip += 5;
3207                         *sp++ = ins;
3208                         break;
3209                 case CEE_UNBOX: {
3210                         MonoInst *add, *vtoffset;
3211                         /* FIXME: need to check class: move to inssel.brg? */
3212                         CHECK_STACK (1);
3213                         --sp;
3214                         token = read32 (ip + 1);
3215                         if (method->wrapper_type != MONO_WRAPPER_NONE)
3216                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
3217                         else 
3218                                 klass = mono_class_get (image, token);
3219                         mono_class_init (klass);
3220                         MONO_INST_NEW (cfg, add, CEE_ADD);
3221                         NEW_ICONST (cfg, vtoffset, sizeof (MonoObject));
3222                         add->inst_left = *sp;
3223                         add->inst_right = vtoffset;
3224                         add->type = STACK_MP;
3225                         *sp++ = add;
3226                         ip += 5;
3227                         inline_costs += 1;
3228                         break;
3229                 }
3230                 case CEE_CASTCLASS:
3231                         CHECK_STACK (1);
3232                         MONO_INST_NEW (cfg, ins, *ip);
3233                         --sp;
3234                         klass = mono_class_get (image, read32 (ip + 1));
3235                         mono_class_init (klass);
3236                         ins->type = STACK_OBJ;
3237                         ins->inst_left = *sp;
3238                         ins->klass = klass;
3239                         ins->inst_newa_class = klass;
3240                         ins->cil_code = ip;
3241                         ip += 5;
3242                         *sp++ = ins;
3243                         break;
3244                 case CEE_THROW:
3245                         CHECK_STACK (1);
3246                         MONO_INST_NEW (cfg, ins, *ip);
3247                         --sp;
3248                         ins->inst_left = *sp;
3249                         ins->cil_code = ip++;
3250                         MONO_ADD_INS (bblock, ins);
3251                         sp = stack_start;
3252                         start_new_bblock = 1;
3253                         break;
3254                 case CEE_LDFLD:
3255                 case CEE_LDFLDA:
3256                 case CEE_STFLD: {
3257                         MonoInst *offset_ins;
3258                         MonoClassField *field;
3259                         guint foffset;
3260
3261                         if (*ip == CEE_STFLD) {
3262                                 CHECK_STACK (2);
3263                                 sp -= 2;
3264                         } else {
3265                                 CHECK_STACK (1);
3266                                 --sp;
3267                         }
3268                         // FIXME: enable this test later.
3269                         //if (sp [0]->type != STACK_OBJ && sp [0]->type != STACK_MP)
3270                         //      goto unverified;
3271                         token = read32 (ip + 1);
3272                         field = mono_field_from_token (image, token, &klass);
3273                         mono_class_init (klass);
3274                         foffset = klass->valuetype? field->offset - sizeof (MonoObject): field->offset;
3275                         /* FIXME: mark instructions for use in SSA */
3276                         if (*ip == CEE_STFLD) {
3277                                 if (klass->marshalbyref && !MONO_CHECK_THIS (sp [0])) {
3278                                         /* fixme: we need to inline that call somehow */
3279                                         MonoMethod *stfld_wrapper = mono_marshal_get_stfld_wrapper (field->type); 
3280                                         MonoInst *iargs [5];
3281                                         iargs [0] = sp [0];
3282                                         NEW_CLASSCONST (cfg, iargs [1], klass);
3283                                         NEW_FIELDCONST (cfg, iargs [2], field);
3284                                         NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : field->offset);
3285                                         iargs [4] = sp [1];
3286                                         mono_emit_method_call_spilled (cfg, bblock, stfld_wrapper, iargs, ip, NULL);
3287                                 } else {
3288                                         MonoInst *store;
3289                                         NEW_ICONST (cfg, offset_ins, foffset);
3290                                         MONO_INST_NEW (cfg, ins, CEE_ADD);
3291                                         ins->cil_code = ip;
3292                                         ins->inst_left = *sp;
3293                                         ins->inst_right = offset_ins;
3294                                         ins->type = STACK_MP;
3295
3296                                         MONO_INST_NEW (cfg, store, mono_type_to_stind (field->type));
3297                                         store->cil_code = ip;
3298                                         store->inst_left = ins;
3299                                         store->inst_right = sp [1];
3300                                         handle_loaded_temps (cfg, bblock, stack_start, sp);
3301                                         store->flags |= ins_flag;
3302                                         ins_flag = 0;
3303                                         if (store->opcode == CEE_STOBJ) {
3304                                                 handle_stobj (cfg, bblock, ins, sp [1], ip, 
3305                                                               mono_class_from_mono_type (field->type), FALSE, FALSE);
3306                                         } else
3307                                                 MONO_ADD_INS (bblock, store);
3308                                 }
3309                         } else {
3310                                 if (klass->marshalbyref && !MONO_CHECK_THIS (sp [0])) {
3311                                         /* fixme: we need to inline that call somehow */
3312                                         MonoMethod *ldfld_wrapper = mono_marshal_get_ldfld_wrapper (field->type); 
3313                                         MonoInst *iargs [4];
3314                                         int temp;
3315                                         iargs [0] = sp [0];
3316                                         NEW_CLASSCONST (cfg, iargs [1], klass);
3317                                         NEW_FIELDCONST (cfg, iargs [2], field);
3318                                         NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : field->offset);
3319                                         temp = mono_emit_method_call_spilled (cfg, bblock, ldfld_wrapper, iargs, ip, NULL);
3320                                         if (*ip == CEE_LDFLDA) {
3321                                                 /* not sure howto handle this */
3322                                                 NEW_TEMPLOADA (cfg, *sp, temp);
3323                                         } else {
3324                                                 NEW_TEMPLOAD (cfg, *sp, temp);
3325                                         }
3326                                         sp++;
3327                                 } else {
3328                                         NEW_ICONST (cfg, offset_ins, foffset);
3329                                         MONO_INST_NEW (cfg, ins, CEE_ADD);
3330                                         ins->cil_code = ip;
3331                                         ins->inst_left = *sp;
3332                                         ins->inst_right = offset_ins;
3333                                         ins->type = STACK_MP;
3334
3335                                         if (*ip == CEE_LDFLDA) {
3336                                                 *sp++ = ins;
3337                                         } else {
3338                                                 MonoInst *load;
3339                                                 MONO_INST_NEW (cfg, load, mono_type_to_ldind (field->type));
3340                                                 type_to_eval_stack_type (field->type, load);
3341                                                 load->cil_code = ip;
3342                                                 load->inst_left = ins;
3343                                                 load->flags |= ins_flag;
3344                                                 ins_flag = 0;
3345                                                 *sp++ = load;
3346                                         }
3347                                 }
3348                         }
3349                         ip += 5;
3350                         break;
3351                 }
3352                 case CEE_LDSFLD:
3353                 case CEE_LDSFLDA:
3354                 case CEE_STSFLD: {
3355                         MonoClassField *field;
3356                         MonoVTable *vtable;
3357
3358                         token = read32 (ip + 1);
3359
3360                         field = mono_field_from_token (image, token, &klass);
3361                         mono_class_init (klass);
3362
3363                         handle_loaded_temps (cfg, bblock, stack_start, sp);
3364                                 
3365                         if (((cfg->opt & MONO_OPT_SAHRED) || mono_compile_aot)) {
3366                                 int temp;
3367                                 MonoInst *iargs [2];
3368                                 g_assert (field->parent);
3369                                 NEW_TEMPLOAD (cfg, iargs [0], mono_get_domainvar (cfg)->inst_c0);
3370                                 NEW_FIELDCONST (cfg, iargs [1], field);
3371                                 temp = mono_emit_jit_icall (cfg, bblock, mono_class_static_field_address, iargs, ip);
3372                                 NEW_TEMPLOAD (cfg, ins, temp);
3373                         } else {
3374                                 vtable = mono_class_vtable (cfg->domain, klass);
3375                                 NEW_PCONST (cfg, ins, (char*)vtable->data + field->offset);
3376                                 ins->cil_code = ip;
3377                         }
3378
3379                         /* FIXME: mark instructions for use in SSA */
3380                         if (*ip == CEE_LDSFLDA) {
3381                                 *sp++ = ins;
3382                         } else if (*ip == CEE_STSFLD) {
3383                                 MonoInst *store;
3384                                 CHECK_STACK (1);
3385                                 sp--;
3386                                 MONO_INST_NEW (cfg, store, mono_type_to_stind (field->type));
3387                                 store->cil_code = ip;
3388                                 store->inst_left = ins;
3389                                 store->inst_right = sp [0];
3390                                 store->flags |= ins_flag;
3391                                 ins_flag = 0;
3392
3393                                 if (store->opcode == CEE_STOBJ) {
3394                                         handle_stobj (cfg, bblock, ins, sp [0], ip, mono_class_from_mono_type (field->type), FALSE, FALSE);
3395                                 } else
3396                                         MONO_ADD_INS (bblock, store);
3397                         } else {
3398                                 MonoInst *load;
3399                                 CHECK_STACK_OVF (1);
3400                                 MONO_INST_NEW (cfg, load, mono_type_to_ldind (field->type));
3401                                 type_to_eval_stack_type (field->type, load);
3402                                 load->cil_code = ip;
3403                                 load->inst_left = ins;
3404                                 *sp++ = load;
3405                                 load->flags |= ins_flag;
3406                                 ins_flag = 0;
3407                         /* fixme: dont see the problem why this does not work */
3408                                 //cfg->disable_aot = TRUE;
3409                         }
3410                         ip += 5;
3411                         break;
3412                 }
3413                 case CEE_STOBJ:
3414                         CHECK_STACK (2);
3415                         sp -= 2;
3416                         token = read32 (ip + 1);
3417                         if (method->wrapper_type != MONO_WRAPPER_NONE)
3418                                 klass = mono_method_get_wrapper_data (method, token);
3419                         else
3420                                 klass = mono_class_get (image, token);
3421                         mono_class_init (klass);
3422                         handle_stobj (cfg, bblock, sp [0], sp [1], ip, klass, FALSE, FALSE);
3423                         ip += 5;
3424                         inline_costs += 1;
3425                         break;
3426                 case CEE_BOX: {
3427                         MonoInst *iargs [2];
3428                         MonoInst *load, *vtoffset, *add, *val, *vstore;
3429                         int temp;
3430                         CHECK_STACK (1);
3431                         --sp;
3432                         val = *sp;
3433                         token = read32 (ip + 1);
3434                         if (method->wrapper_type != MONO_WRAPPER_NONE)
3435                                 klass = mono_method_get_wrapper_data (method, token);
3436                         else
3437                                 klass = mono_class_get (image, token);
3438                         mono_class_init (klass);
3439
3440                         /* much like NEWOBJ */
3441                         NEW_DOMAINCONST (cfg, iargs [0]);
3442                         NEW_CLASSCONST (cfg, iargs [1], klass);
3443                         
3444                         temp = mono_emit_jit_icall (cfg, bblock, mono_object_new, iargs, ip);
3445                         NEW_TEMPLOAD (cfg, load, temp);
3446                         NEW_ICONST (cfg, vtoffset, sizeof (MonoObject));
3447                         MONO_INST_NEW (cfg, add, CEE_ADD);
3448                         add->inst_left = load;
3449                         add->inst_right = vtoffset;
3450                         add->cil_code = ip;
3451                         add->klass = klass;
3452                         MONO_INST_NEW (cfg, vstore, CEE_STIND_I);
3453                         vstore->opcode = mono_type_to_stind (&klass->byval_arg);
3454                         vstore->cil_code = ip;
3455                         vstore->inst_left = add;
3456                         vstore->inst_right = val;
3457
3458                         if (vstore->opcode == CEE_STOBJ) {
3459                                 handle_stobj (cfg, bblock, add, val, ip, klass, FALSE, FALSE);
3460                         } else
3461                                 MONO_ADD_INS (bblock, vstore);
3462
3463                         NEW_TEMPLOAD (cfg, load, temp);
3464                         *sp++ = load;
3465                         ip += 5;
3466                         inline_costs += 1;
3467                         break;
3468                 }
3469                 case CEE_NEWARR:
3470                         CHECK_STACK (1);
3471                         MONO_INST_NEW (cfg, ins, *ip);
3472                         ins->cil_code = ip;
3473                         --sp;
3474
3475                         token = read32 (ip + 1);
3476
3477                         /* allocate the domainvar - becaus this is used in decompose_foreach */
3478                         if ((cfg->opt & MONO_OPT_SAHRED) || mono_compile_aot)
3479                                 mono_get_domainvar (cfg);
3480                         
3481                         if (method->wrapper_type != MONO_WRAPPER_NONE)
3482                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
3483                         else
3484                                 klass = mono_class_get (image, token);
3485
3486                         mono_class_init (klass);
3487                         ins->inst_newa_class = klass;
3488                         ins->inst_newa_len = *sp;
3489                         ins->type = STACK_OBJ;
3490                         ip += 5;
3491                         *sp++ = ins;
3492                         inline_costs += 1;
3493                         break;
3494                 case CEE_LDLEN:
3495                         CHECK_STACK (1);
3496                         MONO_INST_NEW (cfg, ins, *ip);
3497                         ins->cil_code = ip++;
3498                         --sp;
3499                         ins->inst_left = *sp;
3500                         ins->type = STACK_PTR;
3501                         *sp++ = ins;
3502                         break;
3503                 case CEE_LDELEMA:
3504                         CHECK_STACK (2);
3505                         sp -= 2;
3506                         klass = mono_class_get (image, read32 (ip + 1));
3507                         mono_class_init (klass);
3508                         NEW_LDELEMA (cfg, ins, sp, klass);
3509                         ins->cil_code = ip;
3510                         *sp++ = ins;
3511                         ip += 5;
3512                         break;
3513                 case CEE_LDELEM_I1:
3514                 case CEE_LDELEM_U1:
3515                 case CEE_LDELEM_I2:
3516                 case CEE_LDELEM_U2:
3517                 case CEE_LDELEM_I4:
3518                 case CEE_LDELEM_U4:
3519                 case CEE_LDELEM_I8:
3520                 case CEE_LDELEM_I:
3521                 case CEE_LDELEM_R4:
3522                 case CEE_LDELEM_R8:
3523                 case CEE_LDELEM_REF: {
3524                         MonoInst *load;
3525                         /*
3526                          * translate to:
3527                          * ldind.x (ldelema (array, index))
3528                          * ldelema does the bounds check
3529                          */
3530                         CHECK_STACK (2);
3531                         sp -= 2;
3532                         klass = array_access_to_klass (*ip);
3533                         NEW_LDELEMA (cfg, load, sp, klass);
3534                         load->cil_code = ip;
3535                         MONO_INST_NEW (cfg, ins, ldelem_to_ldind [*ip - CEE_LDELEM_I1]);
3536                         ins->cil_code = ip;
3537                         ins->inst_left = load;
3538                         *sp++ = ins;
3539                         ins->type = ldind_type [ins->opcode - CEE_LDIND_I1];
3540                         ++ip;
3541                         break;
3542                 }
3543                 case CEE_STELEM_I:
3544                 case CEE_STELEM_I1:
3545                 case CEE_STELEM_I2:
3546                 case CEE_STELEM_I4:
3547                 case CEE_STELEM_I8:
3548                 case CEE_STELEM_R4:
3549                 case CEE_STELEM_R8: {
3550                         MonoInst *load;
3551                         /*
3552                          * translate to:
3553                          * stind.x (ldelema (array, index), val)
3554                          * ldelema does the bounds check
3555                          */
3556                         CHECK_STACK (3);
3557                         sp -= 3;
3558                         klass = array_access_to_klass (*ip);
3559                         NEW_LDELEMA (cfg, load, sp, klass);
3560                         load->cil_code = ip;
3561                         MONO_INST_NEW (cfg, ins, stelem_to_stind [*ip - CEE_STELEM_I]);
3562                         ins->cil_code = ip;
3563                         ins->inst_left = load;
3564                         ins->inst_right = sp [2];
3565                         ++ip;
3566                         handle_loaded_temps (cfg, bblock, stack_start, sp);
3567                         MONO_ADD_INS (bblock, ins);
3568                         /* FIXME: add the implicit STELEM_REF castclass */
3569                         inline_costs += 1;
3570                         cfg->disable_ssa = TRUE;
3571                         break;
3572                 }
3573                 case CEE_STELEM_REF: {
3574                         MonoInst *iargs [3];
3575
3576                         CHECK_STACK (3);
3577                         sp -= 3;
3578
3579                         handle_loaded_temps (cfg, bblock, stack_start, sp);
3580
3581                         iargs [2] = sp [2];
3582                         iargs [1] = sp [1];
3583                         iargs [0] = sp [0];
3584                         
3585                         mono_emit_jit_icall (cfg, bblock, helper_stelem_ref, iargs, ip);
3586
3587                         /*
3588                         MonoInst *group;
3589                         NEW_GROUP (cfg, group, sp [0], sp [1]);
3590                         MONO_INST_NEW (cfg, ins, CEE_STELEM_REF);
3591                         ins->cil_code = ip;
3592                         ins->inst_left = group;
3593                         ins->inst_right = sp [2];
3594                         MONO_ADD_INS (bblock, ins);
3595                         */
3596
3597                         ++ip;
3598                         inline_costs += 1;
3599                         cfg->disable_ssa = TRUE;
3600                         break;
3601                 }
3602                 case CEE_CKFINITE: {
3603                         MonoInst *store, *temp;
3604                         CHECK_STACK (1);
3605
3606                         /* this instr. can throw exceptions as side effect,
3607                          * so we cant eliminate dead code which contains CKFINITE opdodes.
3608                          * Spilling to memory makes sure that we always perform
3609                          * this check */
3610
3611                         
3612                         MONO_INST_NEW (cfg, ins, CEE_CKFINITE);
3613                         ins->cil_code = ip;
3614                         ins->inst_left = sp [-1];
3615                         temp = mono_compile_create_var (cfg, &mono_defaults.double_class->byval_arg, OP_LOCAL);
3616
3617                         NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
3618                         store->cil_code = ip;
3619                         MONO_ADD_INS (bblock, store);
3620
3621                         NEW_TEMPLOAD (cfg, sp [-1], temp->inst_c0);
3622                        
3623                         ++ip;
3624                         break;
3625                 }
3626                 case CEE_REFANYVAL:
3627                 case CEE_MKREFANY:
3628                         g_error ("opcode 0x%02x not handled", *ip);
3629                         break;
3630                 case CEE_LDTOKEN: {
3631                         gpointer handle;
3632                         MonoClass *handle_class;
3633
3634                         CHECK_STACK_OVF (1);
3635
3636                         n = read32 (ip + 1);
3637
3638                         handle = mono_ldtoken (image, n, &handle_class);
3639                         mono_class_init (handle_class);
3640
3641                         if (((cfg->opt & MONO_OPT_SAHRED) || mono_compile_aot)) {
3642                                 int temp;
3643                                 MonoInst *res, *store, *addr, *vtvar, *iargs [2];
3644
3645                                 vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL); 
3646
3647                                 NEW_IMAGECONST (cfg, iargs [0], image);
3648                                 NEW_ICONST (cfg, iargs [1], n);
3649                                 temp = mono_emit_jit_icall (cfg, bblock, mono_ldtoken_wrapper, iargs, ip);
3650                                 NEW_TEMPLOAD (cfg, res, temp);
3651                                 NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
3652                                 NEW_INDSTORE (cfg, store, addr, res, &mono_defaults.int_class->byval_arg);
3653                                 MONO_ADD_INS (bblock, store);
3654                                 NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
3655                         } else {
3656                                 if ((ip [5] == CEE_CALL) && (cmethod = mono_get_method (image, read32 (ip + 6), NULL)) &&
3657                                                 (cmethod->klass == mono_defaults.monotype_class->parent) &&
3658                                                 (strcmp (cmethod->name, "GetTypeFromHandle") == 0)) {
3659                                         MonoClass *tclass = mono_class_from_mono_type (handle);
3660                                         mono_class_init (tclass);
3661                                         NEW_PCONST (cfg, ins, mono_type_get_object (cfg->domain, handle));
3662                                         ins->type = STACK_OBJ;
3663                                         ins->klass = cmethod->klass;
3664                                         ip += 5;
3665                                 } else {
3666                                         NEW_PCONST (cfg, ins, handle);
3667                                         ins->type = STACK_VTYPE;
3668                                         ins->klass = handle_class;
3669                                 }
3670                         }
3671
3672                         *sp++ = ins;
3673                         ip += 5;
3674                         break;
3675                 }
3676                 case CEE_CONV_U2:
3677                 case CEE_CONV_U1:
3678                 case CEE_CONV_I:
3679                         CHECK_STACK (1);
3680                         ADD_UNOP (*ip);
3681                         ip++;
3682                         break;
3683                 case CEE_ADD_OVF:
3684                 case CEE_ADD_OVF_UN:
3685                 case CEE_MUL_OVF:
3686                 case CEE_MUL_OVF_UN:
3687                 case CEE_SUB_OVF:
3688                 case CEE_SUB_OVF_UN:
3689                         CHECK_STACK (2);
3690                         ADD_BINOP (*ip);
3691                         ip++;
3692                         break;
3693                 case CEE_ENDFINALLY:
3694                         /* FIXME: check stack state */
3695                         MONO_INST_NEW (cfg, ins, *ip);
3696                         MONO_ADD_INS (bblock, ins);
3697                         ins->cil_code = ip++;
3698                         start_new_bblock = 1;
3699                         break;
3700                 case CEE_LEAVE:
3701                 case CEE_LEAVE_S:
3702                         if (*ip == CEE_LEAVE) {
3703                                 target = ip + 5 + (gint32)read32(ip + 1);
3704                         } else {
3705                                 target = ip + 2 + (signed char)(ip [1]);
3706                         }
3707
3708                         /* empty the stack */
3709                         while (sp != stack_start) {
3710                                 MONO_INST_NEW (cfg, ins, CEE_POP);
3711                                 ins->cil_code = ip;
3712                                 sp--;
3713                                 ins->inst_i0 = *sp;
3714                                 MONO_ADD_INS (bblock, ins);
3715                         }
3716
3717                         /* fixme: call fault handler ? */
3718
3719                         if ((tblock = mono_find_final_block (cfg, ip, target, MONO_EXCEPTION_CLAUSE_FINALLY))) {
3720                                 link_bblock (cfg, bblock, tblock);
3721                                 MONO_INST_NEW (cfg, ins, OP_HANDLER);
3722                                 ins->cil_code = ip;
3723                                 ins->inst_target_bb = tblock;
3724                                 MONO_ADD_INS (bblock, ins);
3725                         } 
3726
3727
3728                         MONO_INST_NEW (cfg, ins, CEE_BR);
3729                         ins->cil_code = ip;
3730                         MONO_ADD_INS (bblock, ins);
3731                         GET_BBLOCK (cfg, bbhash, tblock, target);
3732                         link_bblock (cfg, bblock, tblock);
3733                         CHECK_BBLOCK (target, ip, tblock);
3734                         ins->inst_target_bb = tblock;
3735                         start_new_bblock = 1;
3736
3737                         if (*ip == CEE_LEAVE)
3738                                 ip += 5;
3739                         else
3740                                 ip += 2;
3741
3742
3743                         break;
3744                 case CEE_STIND_I:
3745                         CHECK_STACK (2);
3746                         MONO_INST_NEW (cfg, ins, *ip);
3747                         sp -= 2;
3748                         handle_loaded_temps (cfg, bblock, stack_start, sp);
3749                         MONO_ADD_INS (bblock, ins);
3750                         ins->cil_code = ip++;
3751                         ins->inst_i0 = sp [0];
3752                         ins->inst_i1 = sp [1];
3753                         inline_costs += 1;
3754                         break;
3755                 case CEE_CONV_U:
3756                         CHECK_STACK (1);
3757                         ADD_UNOP (*ip);
3758                         ip++;
3759                         break;
3760                 /* trampoline mono specific opcodes */
3761                 case MONO_CUSTOM_PREFIX: {
3762
3763                         g_assert (method->wrapper_type != MONO_WRAPPER_NONE);
3764
3765                         switch (ip [1]) {
3766
3767                         case CEE_MONO_FUNC1: {
3768                                 int temp;
3769                                 gpointer func = NULL;
3770                                 CHECK_STACK (1);
3771                                 sp--;
3772
3773                                 switch (ip [2]) {
3774                                 case MONO_MARSHAL_CONV_STR_LPWSTR:
3775                                         func = mono_string_to_utf16;
3776                                         break;
3777                                 case MONO_MARSHAL_CONV_LPWSTR_STR:
3778                                         func = mono_string_from_utf16;
3779                                         break;
3780                                 case MONO_MARSHAL_CONV_LPSTR_STR:
3781                                         func = mono_string_new_wrapper;
3782                                         break;
3783                                 case MONO_MARSHAL_CONV_STR_LPTSTR:
3784                                 case MONO_MARSHAL_CONV_STR_LPSTR:
3785                                         func = mono_string_to_utf8;
3786                                         break;
3787                                 case MONO_MARSHAL_CONV_STR_BSTR:
3788                                         func = mono_string_to_bstr;
3789                                         break;
3790                                 case MONO_MARSHAL_CONV_STR_TBSTR:
3791                                 case MONO_MARSHAL_CONV_STR_ANSIBSTR:
3792                                         func = mono_string_to_ansibstr;
3793                                         break;
3794                                 case MONO_MARSHAL_CONV_SB_LPSTR:
3795                                         func = mono_string_builder_to_utf8;
3796                                         break;
3797                                 case MONO_MARSHAL_CONV_ARRAY_SAVEARRAY:
3798                                         func = mono_array_to_savearray;
3799                                         break;
3800                                 case MONO_MARSHAL_CONV_ARRAY_LPARRAY:
3801                                         func = mono_array_to_lparray;
3802                                         break;
3803                                 case MONO_MARSHAL_CONV_DEL_FTN:
3804                                         func = mono_delegate_to_ftnptr;
3805                                         break;
3806                                 case MONO_MARSHAL_CONV_STRARRAY_STRLPARRAY:
3807                                         func = mono_marshal_string_array;
3808                                         break;
3809                                 default:
3810                                         g_warning ("unknown conversion %d\n", ip [2]);
3811                                         g_assert_not_reached ();
3812                                 }
3813
3814                                 temp = mono_emit_jit_icall (cfg, bblock, func, sp, ip);
3815                                 NEW_TEMPLOAD (cfg, *sp, temp);
3816                                 sp++;
3817
3818                                 ip += 3;
3819                                 inline_costs += 10 * num_calls++;
3820                                 break;
3821                         }
3822                         case CEE_MONO_PROC2: {
3823                                 gpointer func = NULL;
3824                                 CHECK_STACK (2);
3825                                 sp -= 2;
3826
3827                                 switch (ip [2]) {
3828                                 case MONO_MARSHAL_CONV_LPSTR_SB:
3829                                         func = mono_string_utf8_to_builder;
3830                                         break;
3831                                 case MONO_MARSHAL_FREE_ARRAY:
3832                                         func = mono_marshal_free_array;
3833                                         break;
3834                                 default:
3835                                         g_assert_not_reached ();
3836                                 }
3837
3838                                 mono_emit_jit_icall (cfg, bblock, func, sp, ip);
3839                                 ip += 3;
3840                                 inline_costs += 10 * num_calls++;
3841                                 break;
3842                         }
3843                         case CEE_MONO_PROC3: {
3844                                 gpointer func = NULL;
3845                                 CHECK_STACK (3);
3846                                 sp -= 3;
3847
3848                                 switch (ip [2]) {
3849                                 case MONO_MARSHAL_CONV_STR_BYVALSTR:
3850                                         func = mono_string_to_byvalstr;
3851                                         break;
3852                                 case MONO_MARSHAL_CONV_STR_BYVALWSTR:
3853                                         func = mono_string_to_byvalwstr;
3854                                         break;
3855                                 default:
3856                                         g_assert_not_reached ();
3857                                 }
3858
3859                                 mono_emit_jit_icall (cfg, bblock, func, sp, ip);
3860                                 ip += 3;
3861                                 inline_costs += 10 * num_calls++;
3862                                 break;
3863                         }
3864                         case CEE_MONO_FREE:
3865                                 CHECK_STACK (1);
3866                                 sp -= 1;
3867                                 mono_emit_jit_icall (cfg, bblock, g_free, sp, ip);
3868                                 ip += 2;
3869                                 inline_costs += 10 * num_calls++;
3870                                 break;
3871                         case CEE_MONO_LDPTR:
3872                                 CHECK_STACK_OVF (1);
3873                                 token = read32 (ip + 2);
3874                                 NEW_PCONST (cfg, ins, mono_method_get_wrapper_data (method, token));
3875                                 ins->cil_code = ip;
3876                                 *sp++ = ins;
3877                                 ip += 6;
3878                                 inline_costs += 10 * num_calls++;
3879                                 break;
3880                         case CEE_MONO_VTADDR:
3881                                 CHECK_STACK (1);
3882                                 --sp;
3883                                 MONO_INST_NEW (cfg, ins, OP_VTADDR);
3884                                 ins->cil_code = ip;
3885                                 ins->type = STACK_MP;
3886                                 ins->inst_left = *sp;
3887                                 *sp++ = ins;
3888                                 ip += 2;
3889                                 break;
3890                         case CEE_MONO_NEWOBJ: {
3891                                 MonoInst *iargs [2];
3892                                 int temp;
3893                                 CHECK_STACK_OVF (1);
3894                                 token = read32 (ip + 2);
3895                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
3896                                 mono_class_init (klass);
3897                                 NEW_DOMAINCONST (cfg, iargs [0]);
3898                                 NEW_CLASSCONST (cfg, iargs [1], klass);
3899                                 temp = mono_emit_jit_icall (cfg, bblock, mono_object_new, iargs, ip);
3900                                 NEW_TEMPLOAD (cfg, *sp, temp);
3901                                 sp++;
3902                                 ip += 6;
3903                                 inline_costs += 10 * num_calls++;
3904                                 break;
3905                         }
3906                         case CEE_MONO_OBJADDR:
3907                                 CHECK_STACK (1);
3908                                 --sp;
3909                                 MONO_INST_NEW (cfg, ins, OP_OBJADDR);
3910                                 ins->cil_code = ip;
3911                                 ins->type = STACK_MP;
3912                                 ins->inst_left = *sp;
3913                                 *sp++ = ins;
3914                                 ip += 2;
3915                                 break;
3916                         case CEE_MONO_LDNATIVEOBJ:
3917                                 CHECK_STACK (1);
3918                                 token = read32 (ip + 2);
3919                                 klass = mono_method_get_wrapper_data (method, token);
3920                                 g_assert (klass->valuetype);
3921                                 mono_class_init (klass);
3922                                 NEW_INDLOAD (cfg, ins, sp [-1], &klass->byval_arg);
3923                                 sp [-1] = ins;
3924                                 ip += 6;
3925                                 break;
3926                         case CEE_MONO_RETOBJ:
3927                                 g_assert (cfg->ret);
3928                                 g_assert (method->signature->pinvoke); 
3929                                 CHECK_STACK (1);
3930                                 --sp;
3931                                 
3932                                 token = read32 (ip + 2);    
3933                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
3934
3935                                 NEW_RETLOADA (cfg, ins);
3936                                 handle_stobj (cfg, bblock, ins, *sp, ip, klass, FALSE, TRUE);
3937                                 
3938                                 if (sp != stack_start)
3939                                         goto unverified;
3940                                 
3941                                 MONO_INST_NEW (cfg, ins, CEE_BR);
3942                                 ins->cil_code = ip;
3943                                 ins->inst_target_bb = end_bblock;
3944                                 MONO_ADD_INS (bblock, ins);
3945                                 link_bblock (cfg, bblock, end_bblock);
3946                                 start_new_bblock = 1;
3947                                 ip += 6;
3948                                 break;
3949                         default:
3950                                 g_error ("opcode 0x%02x 0x%02x not handled", MONO_CUSTOM_PREFIX, ip [1]);
3951                                 break;
3952                         }
3953                         break;
3954                 }
3955                 case CEE_PREFIX1: {
3956                         switch (ip [1]) {
3957                         case CEE_ARGLIST:
3958                                 g_error ("opcode 0xfe 0x%02x not handled", ip [1]);
3959                                 break;
3960                         case CEE_CEQ:
3961                         case CEE_CGT:
3962                         case CEE_CGT_UN:
3963                         case CEE_CLT:
3964                         case CEE_CLT_UN: {
3965                                 MonoInst *cmp;
3966                                 CHECK_STACK (2);
3967                                 MONO_INST_NEW (cfg, cmp, 256 + ip [1]);
3968                                 MONO_INST_NEW (cfg, ins, cmp->opcode);
3969                                 sp -= 2;
3970                                 cmp->inst_i0 = sp [0];
3971                                 cmp->inst_i1 = sp [1];
3972                                 cmp->cil_code = ip;
3973                                 type_from_op (cmp);
3974                                 CHECK_TYPE (cmp);
3975                                 cmp->opcode = OP_COMPARE;
3976                                 ins->cil_code = ip;
3977                                 ins->type = STACK_I4;
3978                                 ins->inst_i0 = cmp;
3979                                 *sp++ = ins;
3980                                 ip += 2;
3981                                 break;
3982                         }
3983                         case CEE_LDFTN: {
3984                                 MonoInst *argconst;
3985                                 int temp;
3986
3987                                 CHECK_STACK_OVF (1);
3988                                 n = read32 (ip + 2);
3989                                 if (method->wrapper_type != MONO_WRAPPER_NONE)
3990                                         cmethod = mono_method_get_wrapper_data (method, n);
3991                                 else {
3992                                         cmethod = mono_get_method (image, n, NULL);
3993
3994                                         /*
3995                                          * We can't do this in mono_ldftn, since it is used in
3996                                          * the synchronized wrapper, leading to an infinite loop.
3997                                          */
3998                                         if (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
3999                                                 cmethod = mono_marshal_get_synchronized_wrapper (cmethod);
4000                                 }
4001
4002                                 mono_class_init (cmethod->klass);
4003                                 handle_loaded_temps (cfg, bblock, stack_start, sp);
4004
4005                                 NEW_METHODCONST (cfg, argconst, cmethod);
4006                                 temp = mono_emit_jit_icall (cfg, bblock, mono_ldftn, &argconst, ip);
4007                                 NEW_TEMPLOAD (cfg, *sp, temp);
4008                                 sp ++;
4009                                 
4010                                 ip += 6;
4011                                 inline_costs += 10 * num_calls++;
4012                                 break;
4013                         }
4014                         case CEE_LDVIRTFTN: {
4015                                 MonoInst *args [2];
4016                                 int temp;
4017
4018                                 CHECK_STACK (1);
4019                                 n = read32 (ip + 2);
4020                                 if (method->wrapper_type != MONO_WRAPPER_NONE)
4021                                         cmethod = mono_method_get_wrapper_data (method, n);
4022                                 else
4023                                         cmethod = mono_get_method (image, n, NULL);
4024
4025                                 mono_class_init (cmethod->klass);
4026                                 handle_loaded_temps (cfg, bblock, stack_start, sp);
4027
4028                                 --sp;
4029                                 args [0] = *sp;
4030                                 NEW_METHODCONST (cfg, args [1], cmethod);
4031                                 temp = mono_emit_jit_icall (cfg, bblock, mono_ldvirtfn, args, ip);
4032                                 NEW_TEMPLOAD (cfg, *sp, temp);
4033                                 sp ++;
4034
4035                                 ip += 6;
4036                                 inline_costs += 10 * num_calls++;
4037                                 break;
4038                         }
4039                         case CEE_LDARG:
4040                                 CHECK_STACK_OVF (1);
4041                                 NEW_ARGLOAD (cfg, ins, read16 (ip + 2));
4042                                 ins->cil_code = ip;
4043                                 *sp++ = ins;
4044                                 ip += 4;
4045                                 break;
4046                         case CEE_LDARGA:
4047                                 CHECK_STACK_OVF (1);
4048                                 NEW_ARGLOADA (cfg, ins, read16 (ip + 2));
4049                                 ins->cil_code = ip;
4050                                 *sp++ = ins;
4051                                 ip += 4;
4052                                 break;
4053                         case CEE_STARG:
4054                                 CHECK_STACK (1);
4055                                 --sp;
4056                                 handle_loaded_temps (cfg, bblock, stack_start, sp);
4057                                 n = read16 (ip + 2);
4058                                 NEW_ARGSTORE (cfg, ins, n, *sp);
4059                                 ins->cil_code = ip;
4060                                 if (ins->opcode == CEE_STOBJ) {
4061                                         NEW_ARGLOADA (cfg, ins, n);
4062                                         handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE);
4063                                 } else
4064                                         MONO_ADD_INS (bblock, ins);
4065                                 ip += 4;
4066                                 break;
4067                         case CEE_LDLOC:
4068                                 CHECK_STACK_OVF (1);
4069                                 NEW_LOCLOAD (cfg, ins, read16 (ip + 2));
4070                                 ins->cil_code = ip;
4071                                 *sp++ = ins;
4072                                 ip += 4;
4073                                 break;
4074                         case CEE_LDLOCA:
4075                                 CHECK_STACK_OVF (1);
4076                                 NEW_LOCLOADA (cfg, ins, read16 (ip + 2));
4077                                 ins->cil_code = ip;
4078                                 *sp++ = ins;
4079                                 ip += 4;
4080                                 break;
4081                         case CEE_STLOC:
4082                                 CHECK_STACK (1);
4083                                 --sp;
4084                                 n = read16 (ip + 2);
4085                                 handle_loaded_temps (cfg, bblock, stack_start, sp);
4086                                 NEW_LOCSTORE (cfg, ins, n, *sp);
4087                                 ins->cil_code = ip;
4088                                 if (ins->opcode == CEE_STOBJ) {
4089                                         NEW_LOCLOADA (cfg, ins, n);
4090                                         handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE);
4091                                 } else
4092                                         MONO_ADD_INS (bblock, ins);
4093                                 ip += 4;
4094                                 inline_costs += 1;
4095                                 break;
4096                         case CEE_LOCALLOC:
4097                                 CHECK_STACK (1);
4098                                 --sp;
4099                                 if (sp != stack_start) 
4100                                         goto unverified;
4101                                 MONO_INST_NEW (cfg, ins, 256 + ip [1]);
4102                                 ins->inst_left = *sp;
4103                                 ins->cil_code = ip;
4104
4105                                 if (header->init_locals)
4106                                         ins->flags |= MONO_INST_INIT;
4107
4108                                 *sp++ = ins;
4109                                 ip += 2;
4110                                 /* FIXME: set init flag if locals init is set in this method */
4111                                 break;
4112                         case CEE_ENDFILTER: {
4113                                 MonoExceptionClause *clause, *nearest;
4114                                 int cc, nearest_num;
4115
4116                                 CHECK_STACK (1);
4117                                 --sp;
4118                                 if ((sp != stack_start) || (sp [0]->type != STACK_I4)) 
4119                                         goto unverified;
4120                                 MONO_INST_NEW (cfg, ins, OP_ENDFILTER);
4121                                 ins->inst_left = *sp;
4122                                 ins->cil_code = ip;
4123                                 MONO_ADD_INS (bblock, ins);
4124                                 start_new_bblock = 1;
4125                                 ip += 2;
4126
4127                                 nearest = NULL;
4128                                 for (cc = 0; cc < header->num_clauses; ++cc) {
4129                                         clause = &header->clauses [cc];
4130                                         if ((clause->flags & MONO_EXCEPTION_CLAUSE_FILTER) &&
4131                                             (!nearest || (clause->token_or_filter > nearest->token_or_filter))) {
4132                                                 nearest = clause;
4133                                                 nearest_num = cc;
4134                                         }
4135                                 }
4136                                 g_assert (nearest);
4137                                 filter_lengths [nearest_num] = (ip - header->code) -  nearest->token_or_filter;
4138
4139                                 break;
4140                         }
4141                         case CEE_UNALIGNED_:
4142                                 ins_flag |= MONO_INST_UNALIGNED;
4143                                 ip += 3;
4144                                 break;
4145                         case CEE_VOLATILE_:
4146                                 ins_flag |= MONO_INST_VOLATILE;
4147                                 ip += 2;
4148                                 break;
4149                         case CEE_TAIL_:
4150                                 ins_flag |= MONO_INST_TAILCALL;
4151                                 ip += 2;
4152                                 break;
4153                         case CEE_INITOBJ:
4154                                 CHECK_STACK (1);
4155                                 --sp;
4156                                 token = read32 (ip + 2);
4157                                 if (method->wrapper_type != MONO_WRAPPER_NONE)
4158                                         klass = mono_method_get_wrapper_data (method, token);
4159                                 else
4160                                         klass = mono_class_get (image, token);
4161                                 handle_initobj (cfg, bblock, *sp, NULL, klass, stack_start, sp);
4162                                 ip += 6;
4163                                 inline_costs += 1;
4164                                 break;
4165                         case CEE_CPBLK:
4166                         case CEE_INITBLK: {
4167                                 MonoInst *iargs [3];
4168                                 CHECK_STACK (3);
4169                                 sp -= 3;
4170                                 iargs [0] = sp [0];
4171                                 iargs [1] = sp [1];
4172                                 iargs [2] = sp [2];
4173                                 handle_loaded_temps (cfg, bblock, stack_start, sp);
4174                                 if (ip [1] == CEE_CPBLK) {
4175                                         mono_emit_jit_icall (cfg, bblock, helper_memcpy, iargs, ip);
4176                                 } else {
4177                                         mono_emit_jit_icall (cfg, bblock, helper_memset, iargs, ip);
4178                                 }
4179                                 ip += 2;
4180                                 inline_costs += 1;
4181                                 break;
4182                         }
4183                         case CEE_RETHROW: {
4184                                 MonoInst *load;
4185                                 /* FIXME: check we are in a catch handler */
4186                                 NEW_TEMPLOAD (cfg, load, cfg->exvar->inst_c0);
4187                                 load->cil_code = ip;
4188                                 MONO_INST_NEW (cfg, ins, CEE_THROW);
4189                                 ins->inst_left = load;
4190                                 ins->cil_code = ip;
4191                                 MONO_ADD_INS (bblock, ins);
4192                                 sp = stack_start;
4193                                 start_new_bblock = 1;
4194                                 ip += 2;
4195                                 break;
4196                         }
4197                         case CEE_SIZEOF:
4198                                 CHECK_STACK_OVF (1);
4199                                 token = read32 (ip + 2);
4200                                 if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC) {
4201                                         MonoType *type = mono_type_create_from_typespec (image, token);
4202                                         token = mono_type_size (type, &align);
4203                                         mono_metadata_free_type (type);
4204                                 } else {
4205                                         MonoClass *szclass = mono_class_get (image, token);
4206                                         mono_class_init (szclass);
4207                                         token = mono_class_value_size (szclass, &align);
4208                                 }
4209                                 NEW_ICONST (cfg, ins, token);
4210                                 ins->cil_code = ip;
4211                                 *sp++= ins;
4212                                 ip += 6;
4213                                 break;
4214                         case CEE_REFANYTYPE:
4215                                 g_error ("opcode 0xfe 0x%02x not handled", ip [1]);
4216                                 break;
4217                         default:
4218                                 g_error ("opcode 0xfe 0x%02x not handled", ip [1]);
4219                         }
4220                         break;
4221                 }
4222                 default:
4223                         g_error ("opcode 0x%02x not handled", *ip);
4224                 }
4225         }
4226         if (start_new_bblock != 1)
4227                 goto unverified;
4228
4229         bblock->cil_length = ip - bblock->cil_code;
4230         bblock->next_bb = end_bblock;
4231         link_bblock (cfg, bblock, end_bblock);
4232
4233         if (cfg->method == method && cfg->domainvar) {
4234                 MonoCallInst *call;
4235                 MonoInst *store;
4236
4237                 MONO_INST_NEW_CALL (cfg, call, CEE_CALL);
4238                 call->signature = helper_sig_domain_get;
4239                 call->inst.type = STACK_PTR;
4240                 call->fptr = mono_domain_get;
4241                 NEW_TEMPSTORE (cfg, store, cfg->domainvar->inst_c0, (MonoInst*)call);
4242                 
4243                 MONO_ADD_INS (init_localsbb, store);
4244         }
4245
4246         if (header->init_locals) {
4247                 MonoInst *store;
4248                 for (i = 0; i < header->num_locals; ++i) {
4249                         int t = header->locals [i]->type;
4250                         if (t == MONO_TYPE_VALUETYPE && header->locals [i]->data.klass->enumtype)
4251                                 t = header->locals [i]->data.klass->enum_basetype->type;
4252                         /* FIXME: use initobj for valuetypes, handle pointers, long, float. */
4253                         if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
4254                                 NEW_ICONST (cfg, ins, 0);
4255                                 NEW_LOCSTORE (cfg, store, i, ins);
4256                                 MONO_ADD_INS (init_localsbb, store);
4257                         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
4258                                 MONO_INST_NEW (cfg, ins, OP_I8CONST);
4259                                 ins->type = STACK_I8;
4260                                 ins->inst_l = 0;
4261                                 NEW_LOCSTORE (cfg, store, i, ins);
4262                                 MONO_ADD_INS (init_localsbb, store);
4263                         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
4264                                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
4265                                 ins->type = STACK_R8;
4266                                 ins->inst_p0 = (void*)&r8_0;
4267                                 NEW_LOCSTORE (cfg, store, i, ins);
4268                                 MONO_ADD_INS (init_localsbb, store);
4269                         } else if (t == MONO_TYPE_VALUETYPE) {
4270                                 NEW_LOCLOADA (cfg, ins, i);
4271                                 handle_initobj (cfg, init_localsbb, ins, NULL, mono_class_from_mono_type (header->locals [i]), NULL, NULL);
4272                                 break;
4273                         } else {
4274                                 NEW_PCONST (cfg, ins, NULL);
4275                                 NEW_LOCSTORE (cfg, store, i, ins);
4276                                 MONO_ADD_INS (init_localsbb, store);
4277                         }
4278                 }
4279         }
4280
4281         
4282         /* resolve backward branches in the middle of an existing basic block */
4283         for (tmp = bb_recheck; tmp; tmp = tmp->next) {
4284                 bblock = tmp->data;
4285                 /*g_print ("need recheck in %s at IL_%04x\n", method->name, bblock->cil_code - header->code);*/
4286                 tblock = find_previous (bbhash, start_bblock, bblock->cil_code);
4287                 if (tblock != start_bblock) {
4288                         int l;
4289                         split_bblock (cfg, tblock, bblock);
4290                         l = bblock->cil_code - header->code;
4291                         bblock->cil_length = tblock->cil_length - l;
4292                         tblock->cil_length = l;
4293                 } else {
4294                         g_print ("recheck failed.\n");
4295                 }
4296         }
4297
4298         /* we compute regions here, because the length of filter clauses is not known in advance.
4299         * It is computed in the CEE_ENDFILTER case in the above switch statement*/
4300         if (cfg->method == method) {
4301                 MonoBasicBlock *bb;
4302                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4303                         bb->region = mono_find_block_region (cfg, bb->real_offset, filter_lengths);
4304                         if (cfg->verbose_level > 2)
4305                                 g_print ("REGION BB%d IL_%04x ID_%08X\n", bb->block_num, bb->real_offset, bb->region);
4306                 }
4307         } else {
4308                 g_hash_table_destroy (bbhash);
4309         }
4310
4311         dont_inline = g_list_remove (dont_inline, method);
4312         return inline_costs;
4313
4314  inline_failure:
4315         if (cfg->method != method) 
4316                 g_hash_table_destroy (bbhash);
4317         dont_inline = g_list_remove (dont_inline, method);
4318         return -1;
4319
4320  unverified:
4321         if (cfg->method != method) 
4322                 g_hash_table_destroy (bbhash);
4323         g_error ("Invalid IL code at IL%04x in %s: %s\n", ip - header->code, 
4324                  mono_method_full_name (method, TRUE), mono_disasm_code_one (NULL, method, ip, NULL));
4325         dont_inline = g_list_remove (dont_inline, method);
4326         return -1;
4327 }
4328
4329 void
4330 mono_print_tree (MonoInst *tree) {
4331         int arity;
4332
4333         if (!tree)
4334                 return;
4335
4336         arity = mono_burg_arity [tree->opcode];
4337
4338         printf (" %s%s", arity?"(":"",  mono_inst_name (tree->opcode));
4339
4340         switch (tree->opcode) {
4341         case OP_ICONST:
4342                 printf ("[%d]", tree->inst_c0);
4343                 break;
4344         case OP_I8CONST:
4345                 printf ("[%lld]", tree->inst_l);
4346                 break;
4347         case OP_R8CONST:
4348                 printf ("[%f]", *(double*)tree->inst_p0);
4349                 break;
4350         case OP_R4CONST:
4351                 printf ("[%f]", *(float*)tree->inst_p0);
4352                 break;
4353         case OP_ARG:
4354         case OP_LOCAL:
4355                 printf ("[%d]", tree->inst_c0);
4356                 break;
4357         case OP_REGOFFSET:
4358                 printf ("[0x%x(%s)]", tree->inst_offset, mono_arch_regname (tree->inst_basereg));
4359                 break;
4360         case OP_REGVAR:
4361                 printf ("[%s]", mono_arch_regname (tree->dreg));
4362                 break;
4363         case CEE_NEWARR:
4364                 printf ("[%s]",  tree->inst_newa_class->name);
4365                 mono_print_tree (tree->inst_newa_len);
4366                 break;
4367         case CEE_CALL:
4368         case CEE_CALLVIRT:
4369         case OP_FCALL:
4370         case OP_FCALLVIRT:
4371         case OP_LCALL:
4372         case OP_LCALLVIRT:
4373         case OP_VCALL:
4374         case OP_VCALLVIRT:
4375         case OP_VOIDCALL:
4376         case OP_VOIDCALLVIRT: {
4377                 MonoCallInst *call = (MonoCallInst*)tree;
4378                 if (call->method)
4379                         printf ("[%s]", call->method->name);
4380                 break;
4381         }
4382         case OP_PHI: {
4383                 int i;
4384                 printf ("[%d (", tree->inst_c0);
4385                 for (i = 0; i < tree->inst_phi_args [0]; i++) {
4386                         if (i)
4387                                 printf (", ");
4388                         printf ("%d", tree->inst_phi_args [i + 1]);
4389                 }
4390                 printf (")]");
4391                 break;
4392         }
4393         case OP_RENAME:
4394         case OP_RETARG:
4395         case CEE_NOP:
4396         case CEE_JMP:
4397         case CEE_BREAK:
4398                 break;
4399         case CEE_BR:
4400                 printf ("[B%d]", tree->inst_target_bb->block_num);
4401                 break;
4402         case CEE_SWITCH:
4403         case CEE_ISINST:
4404         case CEE_CASTCLASS:
4405         case OP_OUTARG:
4406         case OP_CALL_REG:
4407         case OP_FCALL_REG:
4408         case OP_LCALL_REG:
4409         case OP_VCALL_REG:
4410         case OP_VOIDCALL_REG:
4411                 mono_print_tree (tree->inst_left);
4412                 break;
4413         case CEE_BNE_UN:
4414         case CEE_BEQ:
4415         case CEE_BLT:
4416         case CEE_BLT_UN:
4417         case CEE_BGT:
4418         case CEE_BGT_UN:
4419         case CEE_BGE:
4420         case CEE_BGE_UN:
4421         case CEE_BLE:
4422         case CEE_BLE_UN:
4423                 printf ("[B%dB%d]", tree->inst_true_bb->block_num, tree->inst_false_bb->block_num);
4424                 mono_print_tree (tree->inst_left);
4425                 break;
4426         default:
4427                 if (arity) {
4428                         mono_print_tree (tree->inst_left);
4429                         if (arity > 1)
4430                                 mono_print_tree (tree->inst_right);
4431                 }
4432                 break;
4433         }
4434
4435         if (arity)
4436                 printf (")");
4437 }
4438
4439 static void
4440 create_helper_signature (void)
4441 {
4442         /* FIXME: set call conv */
4443         /* MonoArray * mono_array_new (MonoDomain *domain, MonoClass *klass, gint32 len) */
4444         helper_sig_newarr = mono_metadata_signature_alloc (mono_defaults.corlib, 3);
4445         helper_sig_newarr->params [0] = helper_sig_newarr->params [1] = &mono_defaults.int_class->byval_arg;
4446         helper_sig_newarr->ret = &mono_defaults.object_class->byval_arg;
4447         helper_sig_newarr->params [2] = &mono_defaults.int32_class->byval_arg;
4448         helper_sig_newarr->pinvoke = 1;
4449
4450         /* MonoObject * mono_object_new (MonoDomain *domain, MonoClass *klass) */
4451         helper_sig_object_new = mono_metadata_signature_alloc (mono_defaults.corlib, 2);
4452         helper_sig_object_new->params [0] = helper_sig_object_new->params [1] = &mono_defaults.int_class->byval_arg;
4453         helper_sig_object_new->ret = &mono_defaults.object_class->byval_arg;
4454         helper_sig_object_new->pinvoke = 1;
4455
4456         /* void* mono_method_compile (MonoMethod*) */
4457         helper_sig_compile = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
4458         helper_sig_compile->params [0] = helper_sig_compile->ret = &mono_defaults.int_class->byval_arg;
4459         helper_sig_compile->pinvoke = 1;
4460
4461         /* void* mono_ldvirtfn (MonoObject *, MonoMethod*) */
4462         helper_sig_compile_virt = mono_metadata_signature_alloc (mono_defaults.corlib, 2);
4463         helper_sig_compile_virt->params [0] = &mono_defaults.object_class->byval_arg;
4464         helper_sig_compile_virt->params [1] = helper_sig_compile_virt->ret = &mono_defaults.int_class->byval_arg;
4465         helper_sig_compile_virt->pinvoke = 1;
4466
4467         /* MonoString* mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 str_index) */
4468         helper_sig_ldstr = mono_metadata_signature_alloc (mono_defaults.corlib, 3);
4469         helper_sig_ldstr->params [0] = helper_sig_ldstr->params [1] = &mono_defaults.int_class->byval_arg;
4470         helper_sig_ldstr->params [2] = &mono_defaults.int32_class->byval_arg;
4471         helper_sig_ldstr->ret = &mono_defaults.object_class->byval_arg;
4472         helper_sig_ldstr->pinvoke = 1;
4473
4474         /* MonoDomain *mono_domain_get (void) */
4475         helper_sig_domain_get = mono_metadata_signature_alloc (mono_defaults.corlib, 0);
4476         helper_sig_domain_get->ret = &mono_defaults.int_class->byval_arg;
4477         helper_sig_domain_get->pinvoke = 1;
4478
4479         /* void* stelem_ref (MonoArray *, int index, MonoObject *) */
4480         helper_sig_stelem_ref = mono_metadata_signature_alloc (mono_defaults.corlib, 3);
4481         helper_sig_stelem_ref->params [0] = &mono_defaults.array_class->byval_arg;
4482         helper_sig_stelem_ref->params [1] = &mono_defaults.int32_class->byval_arg;
4483         helper_sig_stelem_ref->params [2] = &mono_defaults.object_class->byval_arg;
4484         helper_sig_stelem_ref->ret = &mono_defaults.void_class->byval_arg;
4485         helper_sig_stelem_ref->pinvoke = 1;
4486
4487         /* long amethod (long, long) */
4488         helper_sig_long_long_long = mono_metadata_signature_alloc (mono_defaults.corlib, 2);
4489         helper_sig_long_long_long->params [0] = helper_sig_long_long_long->params [1] = 
4490                 &mono_defaults.int64_class->byval_arg;
4491         helper_sig_long_long_long->ret = &mono_defaults.int64_class->byval_arg;
4492         helper_sig_long_long_long->pinvoke = 1;
4493
4494         /* object  amethod (intptr) */
4495         helper_sig_obj_ptr = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
4496         helper_sig_obj_ptr->params [0] = &mono_defaults.int_class->byval_arg;
4497         helper_sig_obj_ptr->ret = &mono_defaults.object_class->byval_arg;
4498         helper_sig_obj_ptr->pinvoke = 1;
4499
4500         /* void amethod (intptr) */
4501         helper_sig_void_ptr = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
4502         helper_sig_void_ptr->params [0] = &mono_defaults.int_class->byval_arg;
4503         helper_sig_void_ptr->ret = &mono_defaults.void_class->byval_arg;
4504         helper_sig_void_ptr->pinvoke = 1;
4505
4506         /* void amethod (MonoObject *obj) */
4507         helper_sig_void_obj = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
4508         helper_sig_void_obj->params [0] = &mono_defaults.object_class->byval_arg;
4509         helper_sig_void_obj->ret = &mono_defaults.void_class->byval_arg;
4510         helper_sig_void_obj->pinvoke = 1;
4511
4512         /* intptr amethod (void) */
4513         helper_sig_ptr_void = mono_metadata_signature_alloc (mono_defaults.corlib, 0);
4514         helper_sig_ptr_void->ret = &mono_defaults.int_class->byval_arg;
4515         helper_sig_ptr_void->pinvoke = 1;
4516
4517         /* void  amethod (intptr, intptr) */
4518         helper_sig_void_ptr_ptr = mono_metadata_signature_alloc (mono_defaults.corlib, 2);
4519         helper_sig_void_ptr_ptr->params [0] = &mono_defaults.int_class->byval_arg;
4520         helper_sig_void_ptr_ptr->params [1] = &mono_defaults.int_class->byval_arg;
4521         helper_sig_void_ptr_ptr->ret = &mono_defaults.void_class->byval_arg;
4522         helper_sig_void_ptr_ptr->pinvoke = 1;
4523
4524         /* void  amethod (intptr, intptr, intptr) */
4525         helper_sig_void_ptr_ptr_ptr = mono_metadata_signature_alloc (mono_defaults.corlib, 3);
4526         helper_sig_void_ptr_ptr_ptr->params [0] = &mono_defaults.int_class->byval_arg;
4527         helper_sig_void_ptr_ptr_ptr->params [1] = &mono_defaults.int_class->byval_arg;
4528         helper_sig_void_ptr_ptr_ptr->params [2] = &mono_defaults.int_class->byval_arg;
4529         helper_sig_void_ptr_ptr_ptr->ret = &mono_defaults.void_class->byval_arg;
4530         helper_sig_void_ptr_ptr_ptr->pinvoke = 1;
4531
4532         /* intptr  amethod (intptr, intptr) */
4533         helper_sig_ptr_ptr_ptr = mono_metadata_signature_alloc (mono_defaults.corlib, 2);
4534         helper_sig_ptr_ptr_ptr->params [0] = &mono_defaults.int_class->byval_arg;
4535         helper_sig_ptr_ptr_ptr->params [1] = &mono_defaults.int_class->byval_arg;
4536         helper_sig_ptr_ptr_ptr->ret = &mono_defaults.int_class->byval_arg;
4537         helper_sig_ptr_ptr_ptr->pinvoke = 1;
4538
4539         /* IntPtr  amethod (object) */
4540         helper_sig_ptr_obj = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
4541         helper_sig_ptr_obj->params [0] = &mono_defaults.object_class->byval_arg;
4542         helper_sig_ptr_obj->ret = &mono_defaults.int_class->byval_arg;
4543         helper_sig_ptr_obj->pinvoke = 1;
4544
4545         /* long amethod (long, guint32) */
4546         helper_sig_long_long_int = mono_metadata_signature_alloc (mono_defaults.corlib, 2);
4547         helper_sig_long_long_int->params [0] = &mono_defaults.int64_class->byval_arg;
4548         helper_sig_long_long_int->params [1] = &mono_defaults.int32_class->byval_arg;
4549         helper_sig_long_long_int->ret = &mono_defaults.int64_class->byval_arg;
4550         helper_sig_long_long_int->pinvoke = 1;
4551
4552         /* ulong amethod (double) */
4553         helper_sig_ulong_double = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
4554         helper_sig_ulong_double->params [0] = &mono_defaults.double_class->byval_arg;
4555         helper_sig_ulong_double->ret = &mono_defaults.uint64_class->byval_arg;
4556         helper_sig_ulong_double->pinvoke = 1;
4557
4558         /* long amethod (double) */
4559         helper_sig_long_double = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
4560         helper_sig_long_double->params [0] = &mono_defaults.double_class->byval_arg;
4561         helper_sig_long_double->ret = &mono_defaults.int64_class->byval_arg;
4562         helper_sig_long_double->pinvoke = 1;
4563
4564         /* uint amethod (double) */
4565         helper_sig_uint_double = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
4566         helper_sig_uint_double->params [0] = &mono_defaults.double_class->byval_arg;
4567         helper_sig_uint_double->ret = &mono_defaults.uint32_class->byval_arg;
4568         helper_sig_uint_double->pinvoke = 1;
4569
4570         /* int amethod (double) */
4571         helper_sig_int_double = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
4572         helper_sig_int_double->params [0] = &mono_defaults.double_class->byval_arg;
4573         helper_sig_int_double->ret = &mono_defaults.int32_class->byval_arg;
4574         helper_sig_int_double->pinvoke = 1;
4575
4576         /* void  initobj (intptr, int size) */
4577         helper_sig_initobj = mono_metadata_signature_alloc (mono_defaults.corlib, 2);
4578         helper_sig_initobj->params [0] = &mono_defaults.int_class->byval_arg;
4579         helper_sig_initobj->params [1] = &mono_defaults.int32_class->byval_arg;
4580         helper_sig_initobj->ret = &mono_defaults.void_class->byval_arg;
4581         helper_sig_initobj->pinvoke = 1;
4582
4583         /* void  memcpy (intptr, intptr, int size) */
4584         helper_sig_memcpy = mono_metadata_signature_alloc (mono_defaults.corlib, 3);
4585         helper_sig_memcpy->params [0] = &mono_defaults.int_class->byval_arg;
4586         helper_sig_memcpy->params [1] = &mono_defaults.int_class->byval_arg;
4587         helper_sig_memcpy->params [2] = &mono_defaults.int32_class->byval_arg;
4588         helper_sig_memcpy->ret = &mono_defaults.void_class->byval_arg;
4589         helper_sig_memcpy->pinvoke = 1;
4590
4591         /* void  memset (intptr, int val, int size) */
4592         helper_sig_memset = mono_metadata_signature_alloc (mono_defaults.corlib, 3);
4593         helper_sig_memset->params [0] = &mono_defaults.int_class->byval_arg;
4594         helper_sig_memset->params [1] = &mono_defaults.int32_class->byval_arg;
4595         helper_sig_memset->params [2] = &mono_defaults.int32_class->byval_arg;
4596         helper_sig_memset->ret = &mono_defaults.void_class->byval_arg;
4597         helper_sig_memset->pinvoke = 1;
4598 }
4599
4600 static GHashTable *jit_icall_hash_name = NULL;
4601 static GHashTable *jit_icall_hash_addr = NULL;
4602
4603 MonoJitICallInfo *
4604 mono_find_jit_icall_by_name (const char *name)
4605 {
4606         g_assert (jit_icall_hash_name);
4607
4608         //printf ("lookup addr %s %p\n", name, g_hash_table_lookup (jit_icall_hash_name, name));
4609         return g_hash_table_lookup (jit_icall_hash_name, name);
4610 }
4611
4612 MonoJitICallInfo *
4613 mono_find_jit_icall_by_addr (gconstpointer addr)
4614 {
4615         g_assert (jit_icall_hash_addr);
4616
4617         return g_hash_table_lookup (jit_icall_hash_addr, (gpointer)addr);
4618 }
4619
4620 MonoJitICallInfo *
4621 mono_register_jit_icall (gconstpointer func, const char *name, MonoMethodSignature *sig, gboolean is_save)
4622 {
4623         MonoJitICallInfo *info;
4624         MonoMethod *wrapper;
4625         char *n;
4626         
4627         g_assert (func);
4628         g_assert (name);
4629
4630         if (!jit_icall_hash_name) {
4631                 jit_icall_hash_name = g_hash_table_new (g_str_hash, g_str_equal);
4632                 jit_icall_hash_addr = g_hash_table_new (NULL, NULL);
4633         }
4634
4635         if (g_hash_table_lookup (jit_icall_hash_name, name)) {
4636                 g_warning ("jit icall already defined \"%s\"\n", name);
4637                 g_assert_not_reached ();
4638         }
4639
4640         info = g_new (MonoJitICallInfo, 1);
4641         
4642         info->name = g_strdup (name);
4643         info->func = func;
4644         info->sig = sig;
4645                 
4646         if (is_save
4647 #ifdef MONO_USE_EXC_TABLES
4648             || mono_arch_has_unwind_info (func)
4649 #endif
4650             ) {
4651                 info->wrapper = func;
4652         } else {
4653                 g_assert (sig);
4654                 n = g_strdup_printf ("__icall_wrapper_%s", name);       
4655                 wrapper = mono_marshal_get_icall_wrapper (sig, n, func);
4656                 info->wrapper = mono_jit_compile_method (wrapper);
4657                 g_free (n);
4658         }
4659
4660         g_hash_table_insert (jit_icall_hash_name, info->name, info);
4661         g_hash_table_insert (jit_icall_hash_addr, (gpointer)func, info);
4662         if (func != info->wrapper)
4663                 g_hash_table_insert (jit_icall_hash_addr, (gpointer)info->wrapper, info);
4664
4665         return info;
4666 }
4667
4668 static GHashTable *emul_opcode_hash = NULL;
4669
4670 static MonoJitICallInfo *
4671 mono_find_jit_opcode_emulation (int opcode)
4672 {
4673         if  (emul_opcode_hash)
4674                 return g_hash_table_lookup (emul_opcode_hash, (gpointer)opcode);
4675         else
4676                 return NULL;
4677 }
4678
4679 void
4680 mono_register_opcode_emulation (int opcode, MonoMethodSignature *sig, gpointer func)
4681 {
4682         MonoJitICallInfo *info;
4683         char *name;
4684
4685         if (!emul_opcode_hash)
4686                 emul_opcode_hash = g_hash_table_new (NULL, NULL);
4687
4688         g_assert (!sig->hasthis);
4689         g_assert (sig->param_count < 3);
4690
4691         name = g_strdup_printf ("__emulate_%s",  mono_inst_name (opcode));
4692
4693         info = mono_register_jit_icall (func, name, sig, FALSE);
4694
4695         g_free (name);
4696
4697         g_hash_table_insert (emul_opcode_hash, (gpointer)opcode, info);
4698 }
4699
4700 static void
4701 decompose_foreach (MonoInst *tree, gpointer data) 
4702 {
4703         static MonoJitICallInfo *newarr_info = NULL;
4704
4705         switch (tree->opcode) {
4706         case CEE_NEWARR: {
4707                 MonoCompile *cfg = data;
4708                 MonoInst *iargs [3];
4709
4710                 NEW_DOMAINCONST (cfg, iargs [0]);
4711                 NEW_CLASSCONST (cfg, iargs [1], tree->inst_newa_class);
4712                 iargs [2] = tree->inst_newa_len;
4713
4714                 if (!newarr_info) {
4715                         newarr_info =  mono_find_jit_icall_by_addr (mono_array_new);
4716                         g_assert (newarr_info);
4717                 }
4718
4719                 mono_emulate_opcode (cfg, tree, iargs, newarr_info);
4720                 break;
4721         }
4722
4723         default:
4724                 break;
4725         }
4726 }
4727
4728 void
4729 mono_inst_foreach (MonoInst *tree, MonoInstFunc func, gpointer data) {
4730
4731         switch (mono_burg_arity [tree->opcode]) {
4732         case 0: break;
4733         case 1: 
4734                 mono_inst_foreach (tree->inst_left, func, data);
4735                 break;
4736         case 2: 
4737                 mono_inst_foreach (tree->inst_left, func, data);
4738                 mono_inst_foreach (tree->inst_right, func, data);
4739                 break;
4740         default:
4741                 g_assert_not_reached ();
4742         }
4743         func (tree, data);
4744 }
4745
4746 #if 0
4747 static void
4748 mono_print_bb_code (MonoBasicBlock *bb) {
4749         if (bb->code) {
4750                 MonoInst *c = bb->code;
4751                 while (c) {
4752                         mono_print_tree (c);
4753                         g_print ("\n");
4754                         c = c->next;
4755                 }
4756         }
4757 }
4758 #endif
4759
4760 static void
4761 print_dfn (MonoCompile *cfg) {
4762         int i, j;
4763         char *code;
4764         MonoBasicBlock *bb;
4765
4766         g_print ("IR code for method %s\n", mono_method_full_name (cfg->method, TRUE));
4767
4768         for (i = 0; i < cfg->num_bblocks; ++i) {
4769                 bb = cfg->bblocks [i];
4770                 if (bb->cil_code) {
4771                         char* code1, *code2;
4772                         code1 = mono_disasm_code_one (NULL, cfg->method, bb->cil_code, NULL);
4773                         if (bb->last_ins->cil_code)
4774                                 code2 = mono_disasm_code_one (NULL, cfg->method, bb->last_ins->cil_code, NULL);
4775                         else
4776                                 code2 = g_strdup ("");
4777
4778                         code1 [strlen (code1) - 1] = 0;
4779                         code = g_strdup_printf ("%s -> %s", code1, code2);
4780                         g_free (code1);
4781                         g_free (code2);
4782                 } else
4783                         code = g_strdup ("\n");
4784                 g_print ("\nBB%d DFN%d (len: %d): %s", bb->block_num, i, bb->cil_length, code);
4785                 if (bb->code) {
4786                         MonoInst *c = bb->code;
4787                         while (c) {
4788                                 mono_print_tree (c);
4789                                 g_print ("\n");
4790                                 c = c->next;
4791                         }
4792                 } else {
4793
4794                 }
4795
4796                 g_print ("\tprev:");
4797                 for (j = 0; j < bb->in_count; ++j) {
4798                         g_print (" BB%d", bb->in_bb [j]->block_num);
4799                 }
4800                 g_print ("\t\tsucc:");
4801                 for (j = 0; j < bb->out_count; ++j) {
4802                         g_print (" BB%d", bb->out_bb [j]->block_num);
4803                 }
4804                 g_print ("\n\tidom: BB%d\n", bb->idom? bb->idom->block_num: -1);
4805
4806                 if (bb->idom)
4807                         g_assert (mono_bitset_test_fast (bb->dominators, bb->idom->dfn));
4808
4809                 if (bb->dominators)
4810                         mono_blockset_print (cfg, bb->dominators, "\tdominators", bb->idom? bb->idom->dfn: -1);
4811                 if (bb->dfrontier)
4812                         mono_blockset_print (cfg, bb->dfrontier, "\tdfrontier", -1);
4813                 g_free (code);
4814         }
4815
4816         g_print ("\n");
4817 }
4818
4819 /*
4820  * returns the offset used by spillvar. It allocates a new
4821  * spill variable if necessary. 
4822  */
4823 int
4824 mono_spillvar_offset (MonoCompile *cfg, int spillvar)
4825 {
4826         MonoSpillInfo **si, *info;
4827         int i = 0;
4828
4829         si = &cfg->spill_info; 
4830         
4831         while (i <= spillvar) {
4832
4833                 if (!*si) {
4834                         *si = info = mono_mempool_alloc (cfg->mempool, sizeof (MonoSpillInfo));
4835                         info->next = NULL;
4836                         cfg->stack_offset -= sizeof (gpointer);
4837                         info->offset = cfg->stack_offset;
4838                 }
4839
4840                 if (i == spillvar)
4841                         return (*si)->offset;
4842
4843                 i++;
4844                 si = &(*si)->next;
4845         }
4846
4847         g_assert_not_reached ();
4848         return 0;
4849 }
4850
4851 void
4852 mono_bblock_add_inst (MonoBasicBlock *bb, MonoInst *inst)
4853 {
4854         inst->next = NULL;
4855         if (bb->last_ins) {
4856                 g_assert (bb->code);
4857                 bb->last_ins->next = inst;
4858                 bb->last_ins = inst;
4859         } else {
4860                 bb->last_ins = bb->code = inst;
4861         }
4862 }
4863
4864 void
4865 mono_destroy_compile (MonoCompile *cfg)
4866 {
4867         //mono_mempool_stats (cfg->mempool);
4868         g_hash_table_destroy (cfg->bb_hash);
4869         if (cfg->rs)
4870                 mono_regstate_free (cfg->rs);
4871         mono_mempool_destroy (cfg->mempool);
4872         g_list_free (cfg->ldstr_list);
4873
4874         g_free (cfg->varinfo);
4875         g_free (cfg->vars);
4876         g_free (cfg);
4877 }
4878
4879 gpointer 
4880 mono_get_lmf_addr (void)
4881 {
4882         MonoJitTlsData *jit_tls;        
4883
4884         if ((jit_tls = TlsGetValue (mono_jit_tls_id)))
4885                 return &jit_tls->lmf;
4886
4887         g_assert_not_reached ();
4888         return NULL;
4889 }
4890
4891 /**
4892  * mono_thread_abort:
4893  * @obj: exception object
4894  *
4895  * abort the thread, print exception information and stack trace
4896  */
4897 static void
4898 mono_thread_abort (MonoObject *obj)
4899 {
4900         MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
4901         
4902         g_free (jit_tls);
4903
4904         ExitThread (-1);
4905 }
4906
4907 static void
4908 mono_thread_start_cb (guint32 tid, gpointer stack_start, gpointer func)
4909 {
4910         MonoJitTlsData *jit_tls;
4911         MonoLMF *lmf;
4912
4913         jit_tls = g_new0 (MonoJitTlsData, 1);
4914
4915         TlsSetValue (mono_jit_tls_id, jit_tls);
4916
4917         jit_tls->abort_func = mono_thread_abort;
4918         jit_tls->end_of_stack = stack_start;
4919
4920         lmf = g_new0 (MonoLMF, 1);
4921         lmf->ebp = -1;
4922
4923         jit_tls->lmf = lmf;
4924 }
4925
4926 void (*mono_thread_attach_aborted_cb ) (MonoObject *obj) = NULL;
4927
4928 static void
4929 mono_thread_abort_dummy (MonoObject *obj)
4930 {
4931   if (mono_thread_attach_aborted_cb)
4932     mono_thread_attach_aborted_cb (obj);
4933   else
4934     mono_thread_abort (obj);
4935 }
4936
4937 static void
4938 mono_thread_attach_cb (guint32 tid, gpointer stack_start)
4939 {
4940         MonoJitTlsData *jit_tls;
4941         MonoLMF *lmf;
4942
4943         jit_tls = g_new0 (MonoJitTlsData, 1);
4944
4945         TlsSetValue (mono_jit_tls_id, jit_tls);
4946
4947         jit_tls->abort_func = mono_thread_abort_dummy;
4948         jit_tls->end_of_stack = stack_start;
4949
4950         lmf = g_new0 (MonoLMF, 1);
4951         lmf->ebp = -1;
4952
4953         jit_tls->lmf = lmf;
4954 }
4955
4956 void
4957 mono_add_patch_info (MonoCompile *cfg, int ip, MonoJumpInfoType type, gconstpointer target)
4958 {
4959         MonoJumpInfo *ji = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfo));
4960
4961         ji->ip.i = ip;
4962         ji->type = type;
4963         ji->data.target = target;
4964         ji->next = cfg->patch_info;
4965
4966         cfg->patch_info = ji;
4967 }
4968
4969 void
4970 mono_remove_patch_info (MonoCompile *cfg, int ip)
4971 {
4972         MonoJumpInfo **ji = &cfg->patch_info;
4973
4974         while (*ji) {
4975                 if ((*ji)->ip.i == ip)
4976                         *ji = (*ji)->next;
4977                 else
4978                         ji = &((*ji)->next);
4979         }
4980 }
4981
4982 static void
4983 dec_foreach (MonoInst *tree, MonoCompile *cfg) {
4984         MonoJitICallInfo *info;
4985
4986         switch (mono_burg_arity [tree->opcode]) {
4987         case 0: break;
4988         case 1: 
4989                 dec_foreach (tree->inst_left, cfg);
4990
4991                 if ((info = mono_find_jit_opcode_emulation (tree->opcode))) {
4992                         MonoInst *iargs [2];
4993                 
4994                         iargs [0] = tree->inst_left;
4995
4996                         mono_emulate_opcode (cfg, tree, iargs, info);
4997                         return;
4998                 }
4999
5000                 break;
5001         case 2: 
5002                 if ((info = mono_find_jit_opcode_emulation (tree->opcode))) {
5003                         MonoInst *iargs [2];
5004                 
5005                         iargs [0] = tree->inst_i0;
5006                         iargs [1] = tree->inst_i1;
5007                 
5008                         mono_emulate_opcode (cfg, tree, iargs, info);
5009
5010                         dec_foreach (iargs [0], cfg);
5011                         dec_foreach (iargs [1], cfg);
5012                         return;
5013                 } else {
5014                         dec_foreach (tree->inst_left, cfg);
5015                         dec_foreach (tree->inst_right, cfg);
5016                 }
5017                 break;
5018         default:
5019                 g_assert_not_reached ();
5020         }
5021         decompose_foreach (tree, cfg);
5022 }
5023
5024 static void
5025 decompose_pass (MonoCompile *cfg) {
5026         MonoBasicBlock *bb;
5027
5028         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
5029                 MonoInst *tree;
5030                 cfg->cbb = bb;
5031                 cfg->prev_ins = NULL;
5032                 for (tree = cfg->cbb->code; tree; tree = tree->next) {
5033                         dec_foreach (tree, cfg);
5034                         cfg->prev_ins = tree;
5035                 }
5036         }
5037 }
5038
5039 static void
5040 nullify_basic_block (MonoBasicBlock *bb) 
5041 {
5042         bb->in_count = 0;
5043         bb->out_count = 0;
5044         bb->in_bb = NULL;
5045         bb->out_bb = NULL;
5046         bb->next_bb = NULL;
5047         bb->code = bb->last_ins = NULL;
5048 }
5049
5050 static void 
5051 replace_basic_block (MonoBasicBlock *bb, MonoBasicBlock *orig,  MonoBasicBlock *repl)
5052 {
5053         int i, j;
5054
5055         for (i = 0; i < bb->out_count; i++) {
5056                 MonoBasicBlock *ob = bb->out_bb [i];
5057                 for (j = 0; j < ob->in_count; j++) {
5058                         if (ob->in_bb [j] == orig)
5059                                 ob->in_bb [j] = repl;
5060                 }
5061         }
5062
5063 }
5064
5065 static void
5066 merge_basic_blocks (MonoBasicBlock *bb, MonoBasicBlock *bbn) 
5067 {
5068         bb->out_count = bbn->out_count;
5069         bb->out_bb = bbn->out_bb;
5070
5071         replace_basic_block (bb, bbn, bb);
5072
5073         if (bb->last_ins) {
5074                 if (bbn->code) {
5075                         bb->last_ins->next = bbn->code;
5076                         bb->last_ins = bbn->last_ins;
5077                 }
5078         } else {
5079                 bb->code = bbn->code;
5080                 bb->last_ins = bbn->last_ins;
5081         }
5082         bb->next_bb = bbn->next_bb;
5083         nullify_basic_block (bbn);
5084 }
5085
5086 static void
5087 optimize_branches (MonoCompile *cfg) {
5088         int changed = FALSE;
5089         MonoBasicBlock *bb, *bbn;
5090
5091         do {
5092                 changed = FALSE;
5093
5094                 /* we skip the entry block (exit is handled specially instead ) */
5095                 for (bb = cfg->bb_entry->next_bb; bb; bb = bb->next_bb) {
5096
5097                         if (bb->out_count == 1) {
5098                                 bbn = bb->out_bb [0];
5099
5100                                 if (bb->region == bbn->region && bb->next_bb == bbn) {
5101                                 /* the block are in sequence anyway ... */
5102
5103                                         /* 
5104                                          * miguel: I do not understand what the test below does, could we
5105                                          * use a macro, or a comment here?  opcode > CEE_BEQ && <= BLT_UN
5106                                          *
5107                                          * It could also test for bb->last_in only once, and the value
5108                                          * could be cached (last_ins->opcode)
5109                                          */
5110                                         if (bb->last_ins && (bb->last_ins->opcode == CEE_BR || (
5111                                                 (bb->last_ins && bb->last_ins->opcode >= CEE_BEQ && bb->last_ins->opcode <= CEE_BLT_UN)))) {
5112                                                 bb->last_ins->opcode = CEE_NOP;
5113                                                 changed = TRUE;
5114                                                 if (cfg->verbose_level > 2)
5115                                                         g_print ("br removal triggered %d -> %d\n", bb->block_num, bbn->block_num);
5116                                         }
5117                                         /* fixme: this causes problems with inlining */
5118                                         if (bbn->in_count == 1) {
5119
5120                                                 if (bbn != cfg->bb_exit) {
5121                                                         if (cfg->verbose_level > 2)
5122                                                                 g_print ("block merge triggered %d -> %d\n", bb->block_num, bbn->block_num);
5123                                                         merge_basic_blocks (bb, bbn);
5124                                                         changed = TRUE;
5125                                                 }
5126
5127                                                 //mono_print_bb_code (bb);
5128                                         }
5129                                 } else {
5130                                         if (bb->last_ins && bb->last_ins->opcode == CEE_BR) {
5131                                                 bbn = bb->last_ins->inst_target_bb;
5132                                                 if (bb->region == bbn->region && bbn->code && bbn->code->opcode == CEE_BR) {
5133                                                         /*
5134                                                         if (cfg->verbose_level > 2)
5135                                                                 g_print ("in %s branch to branch triggered %d -> %d\n", cfg->method->name, bb->block_num, bbn->block_num);
5136                                                         bb->out_bb [0] = bb->last_ins->inst_target_bb = bbn->code->inst_target_bb;
5137                                                         changed = TRUE;*/
5138                                                 }
5139                                         }
5140                                 }
5141                         } else if (bb->out_count == 2) {
5142                                 /* fixme: this does not correctly unlink the blocks, so we get serious problems in idom code */
5143                                 if (0 && bb->last_ins && bb->last_ins->opcode >= CEE_BEQ && bb->last_ins->opcode <= CEE_BLT_UN) {
5144                                         bbn = bb->last_ins->inst_true_bb;
5145                                         if (bb->region == bbn->region && bbn->code && bbn->code->opcode == CEE_BR) {
5146                                                 if (cfg->verbose_level > 2)
5147                                                         g_print ("cbranch to branch triggered %d -> %d (0x%02x)\n", bb->block_num, 
5148                                                                  bbn->block_num, bbn->code->opcode);
5149                                                  
5150                                                 if (bb->out_bb [0] == bbn) {
5151                                                         bb->out_bb [0] = bbn->code->inst_target_bb;
5152                                                 } else if (bb->out_bb [1] == bbn) {
5153                                                         bb->out_bb [1] = bbn->code->inst_target_bb;
5154                                                 }
5155                                                 bb->last_ins->inst_true_bb = bbn->code->inst_target_bb;
5156                                                 changed = TRUE;
5157                                         }
5158                                 }
5159                         }
5160                 }
5161         } while (changed);
5162 }
5163
5164 static void
5165 mono_compile_create_vars (MonoCompile *cfg)
5166 {
5167         MonoMethodSignature *sig;
5168         MonoMethodHeader *header;
5169         int i;
5170
5171         header = ((MonoMethodNormal *)cfg->method)->header;
5172
5173         sig = cfg->method->signature;
5174         
5175         if (!MONO_TYPE_IS_VOID (sig->ret)) {
5176                 cfg->ret = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst));
5177                 cfg->ret->opcode = OP_RETARG;
5178                 cfg->ret->inst_vtype = sig->ret;
5179                 cfg->ret->klass = mono_class_from_mono_type (sig->ret);
5180         }
5181
5182         if (sig->hasthis)
5183                 mono_compile_create_var (cfg, &cfg->method->klass->this_arg, OP_ARG);
5184
5185         for (i = 0; i < sig->param_count; ++i)
5186                 mono_compile_create_var (cfg, sig->params [i], OP_ARG);
5187
5188         cfg->locals_start = cfg->num_varinfo;
5189
5190         for (i = 0; i < header->num_locals; ++i)
5191                 mono_compile_create_var (cfg, header->locals [i], OP_LOCAL);
5192 }
5193
5194 #if 0
5195 static void
5196 mono_print_code (MonoCompile *cfg)
5197 {
5198         MonoBasicBlock *bb;
5199         
5200         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
5201                 MonoInst *tree = bb->code;      
5202
5203                 if (!tree)
5204                         continue;
5205                 
5206                 g_print ("CODE BLOCK %d (nesting %d):\n", bb->block_num, bb->nesting);
5207
5208                 for (; tree; tree = tree->next) {
5209                         mono_print_tree (tree);
5210                         g_print ("\n");
5211                 }
5212
5213                 if (bb->last_ins)
5214                         bb->last_ins->next = NULL;
5215         }
5216 }
5217 #endif
5218
5219 extern const char * const mono_burg_rule_string [];
5220
5221 static void
5222 emit_state (MonoCompile *cfg, MBState *state, int goal)
5223 {
5224         MBState *kids [10];
5225         int ern = mono_burg_rule (state, goal);
5226         const guint16 *nts = mono_burg_nts [ern];
5227         MBEmitFunc emit;
5228
5229         //g_print ("rule: %s\n", mono_burg_rule_string [ern]);
5230         switch (goal) {
5231         case MB_NTERM_reg:
5232                 //if (state->reg2)
5233                 //      state->reg1 = state->reg2; /* chain rule */
5234                 //else
5235                 state->reg1 = mono_regstate_next_int (cfg->rs);
5236                 //g_print ("alloc symbolic R%d (reg2: R%d) in block %d\n", state->reg1, state->reg2, cfg->cbb->block_num);
5237                 break;
5238         case MB_NTERM_lreg:
5239                 state->reg1 = mono_regstate_next_int (cfg->rs);
5240                 state->reg2 = mono_regstate_next_int (cfg->rs);
5241                 break;
5242         case MB_NTERM_freg:
5243                 state->reg1 = mono_regstate_next_float (cfg->rs);
5244                 break;
5245         default:
5246                 /* do nothing */
5247                 break;
5248         }
5249         if (nts [0]) {
5250                 mono_burg_kids (state, ern, kids);
5251
5252                 emit_state (cfg, kids [0], nts [0]);
5253                 if (nts [1]) {
5254                         emit_state (cfg, kids [1], nts [1]);
5255                         if (nts [2]) {
5256                                 g_assert (!nts [3]);
5257                                 emit_state (cfg, kids [2], nts [2]);
5258                         }
5259                 }
5260         }
5261
5262 //      g_print ("emit: %s (%p)\n", mono_burg_rule_string [ern], state);
5263         if ((emit = mono_burg_func [ern]))
5264                 emit (state, state->tree, cfg); 
5265 }
5266
5267 #define DEBUG_SELECTION
5268
5269 static void 
5270 mini_select_instructions (MonoCompile *cfg)
5271 {
5272         MonoBasicBlock *bb;
5273         
5274         cfg->state_pool = mono_mempool_new ();
5275         cfg->rs = mono_regstate_new ();
5276
5277 #ifdef DEBUG_SELECTION
5278         if (cfg->verbose_level >= 4) {
5279         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
5280                 MonoInst *tree = bb->code;      
5281                 g_print ("DUMP BLOCK %d:\n", bb->block_num);
5282                 if (!tree)
5283                         continue;
5284                 for (; tree; tree = tree->next) {
5285                         mono_print_tree (tree);
5286                         g_print ("\n");
5287                 }
5288         }
5289         }
5290 #endif
5291
5292         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
5293                 MonoInst *tree = bb->code, *next;       
5294                 MBState *mbstate;
5295
5296                 if (!tree)
5297                         continue;
5298                 bb->code = NULL;
5299                 bb->last_ins = NULL;
5300                 
5301                 cfg->cbb = bb;
5302                 mono_regstate_reset (cfg->rs);
5303
5304 #ifdef DEBUG_SELECTION
5305                 if (cfg->verbose_level >= 3)
5306                         g_print ("LABEL BLOCK %d:\n", bb->block_num);
5307 #endif
5308                 for (; tree; tree = next) {
5309                         next = tree->next;
5310 #ifdef DEBUG_SELECTION
5311                         if (cfg->verbose_level >= 3) {
5312                                 mono_print_tree (tree);
5313                                 g_print ("\n");
5314                         }
5315 #endif
5316
5317                         if (!(mbstate = mono_burg_label (tree, cfg))) {
5318                                 g_warning ("unabled to label tree %p", tree);
5319                                 mono_print_tree (tree);
5320                                 g_print ("\n");                         
5321                                 g_assert_not_reached ();
5322                         }
5323                         emit_state (cfg, mbstate, MB_NTERM_stmt);
5324                 }
5325                 bb->max_ireg = cfg->rs->next_vireg;
5326                 bb->max_freg = cfg->rs->next_vfreg;
5327
5328                 if (bb->last_ins)
5329                         bb->last_ins->next = NULL;
5330
5331                 mono_mempool_empty (cfg->state_pool); 
5332         }
5333         mono_mempool_destroy (cfg->state_pool); 
5334 }
5335
5336 void
5337 mono_codegen (MonoCompile *cfg)
5338 {
5339         MonoJumpInfo *patch_info;
5340         MonoBasicBlock *bb;
5341         int i, max_epilog_size;
5342         guint8 *code;
5343
5344         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
5345                 cfg->spill_count = 0;
5346                 /* we reuse dfn here */
5347                 /* bb->dfn = bb_count++; */
5348                 mono_arch_local_regalloc (cfg, bb);
5349         }
5350
5351         if (mono_trace_coverage)
5352                 mono_allocate_coverage_info (cfg->method, cfg->num_bblocks);
5353
5354         code = mono_arch_emit_prolog (cfg);
5355
5356         if (mono_jit_profile)
5357                 code = mono_arch_instrument_prolog (cfg, mono_profiler_method_enter, code, FALSE);
5358
5359         cfg->code_len = code - cfg->native_code;
5360         cfg->prolog_end = cfg->code_len;
5361
5362         mono_debug_open_method (cfg);
5363              
5364         /* emit code all basic blocks */
5365         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
5366                 bb->native_offset = cfg->code_len;
5367                 mono_arch_output_basic_block (cfg, bb);
5368         }
5369         cfg->bb_exit->native_offset = cfg->code_len;
5370
5371         code = cfg->native_code + cfg->code_len;
5372
5373         max_epilog_size = mono_arch_max_epilog_size (cfg);
5374
5375         /* we always allocate code in cfg->domain->code_mp to increase locality */
5376         cfg->code_size = cfg->code_len + max_epilog_size;
5377         /* fixme: align to MONO_ARCH_CODE_ALIGNMENT */
5378         code = mono_mempool_alloc (cfg->domain->code_mp, cfg->code_size);
5379         memcpy (code, cfg->native_code, cfg->code_len);
5380         g_free (cfg->native_code);
5381         cfg->native_code = code;
5382         code = cfg->native_code + cfg->code_len;
5383   
5384         /* g_assert (((int)cfg->native_code & (MONO_ARCH_CODE_ALIGNMENT - 1)) == 0); */
5385
5386         cfg->epilog_begin = cfg->code_len;
5387
5388         if (mono_jit_profile)
5389                 code = mono_arch_instrument_epilog (cfg, mono_profiler_method_leave, code, FALSE);
5390
5391         cfg->code_len = code - cfg->native_code;
5392
5393         mono_arch_emit_epilog (cfg);
5394
5395         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5396                 switch (patch_info->type) {
5397                 case MONO_PATCH_INFO_ABS: {
5398                         MonoJitICallInfo *info = mono_find_jit_icall_by_addr (patch_info->data.target);
5399                         if (info) {
5400                                 //printf ("TEST %s %p\n", info->name, patch_info->data.target);
5401                                 patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
5402                                 patch_info->data.name = info->name;
5403                         }
5404                         break;
5405                 }
5406                 case MONO_PATCH_INFO_SWITCH: {
5407                         gpointer *table = g_new (gpointer, patch_info->table_size);
5408                         patch_info->ip.i = patch_info->ip.label->inst_c0;
5409                         for (i = 0; i < patch_info->table_size; i++) {
5410                                 table [i] = (gpointer)patch_info->data.table [i]->native_offset;
5411                         }
5412                         patch_info->data.target = table;
5413                         break;
5414                 }
5415                 default:
5416                         /* do nothing */
5417                         break;
5418                 }
5419         }
5420        
5421         if (cfg->verbose_level > 1)
5422                 g_print ("Method %s::%s emmitted at %p to %p\n", cfg->method->klass->name, 
5423                          cfg->method->name, cfg->native_code, cfg->native_code + cfg->code_len);
5424
5425         mono_arch_patch_code (cfg->method, cfg->domain, cfg->native_code, cfg->patch_info);
5426
5427         mono_debug_close_method (cfg);
5428 }
5429
5430 static void
5431 mono_cprop_copy_values (MonoCompile *cfg, MonoInst *tree, MonoInst **acp)
5432 {
5433         MonoInst *cp;
5434         int arity;
5435
5436         if (tree->ssa_op == MONO_SSA_LOAD && (tree->inst_i0->opcode == OP_LOCAL || tree->inst_i0->opcode == OP_ARG) && 
5437             (cp = acp [tree->inst_i0->inst_c0]) && !tree->inst_i0->flags) {
5438
5439                 if (cp->opcode == OP_ICONST) {
5440                         if (cfg->opt & MONO_OPT_CONSPROP) {
5441                                 //{ static int c = 0; printf ("CCOPY %d %d %s\n", c++, cp->inst_c0, mono_method_full_name (cfg->method, TRUE)); }
5442                                 *tree = *cp;
5443                         }
5444                 } else {
5445                         if (tree->inst_i0->inst_vtype->type == cp->inst_vtype->type) {
5446                                 if (cfg->opt & MONO_OPT_COPYPROP) {
5447                                         //{ static int c = 0; printf ("VCOPY %d\n", ++c); }
5448                                         tree->inst_i0 = cp;
5449                                 } 
5450                         }
5451                 } 
5452         } else {
5453                 arity = mono_burg_arity [tree->opcode];
5454
5455                 if (arity) {
5456                         mono_cprop_copy_values (cfg, tree->inst_i0, acp);
5457                         if (cfg->opt & MONO_OPT_CFOLD)
5458                                 mono_constant_fold_inst (tree, NULL); 
5459                         if (arity > 1) {
5460                                 mono_cprop_copy_values (cfg, tree->inst_i1, acp);
5461                                 if (cfg->opt & MONO_OPT_CFOLD)
5462                                         mono_constant_fold_inst (tree, NULL); 
5463                         }
5464                         mono_constant_fold_inst (tree, NULL); 
5465                 }
5466         }
5467 }
5468
5469 static void
5470 mono_cprop_invalidate_values (MonoInst *tree, MonoInst **acp, int acp_size)
5471 {
5472         int arity;
5473
5474         switch (tree->opcode) {
5475         case CEE_STIND_I:
5476         case CEE_STIND_I1:
5477         case CEE_STIND_I2:
5478         case CEE_STIND_I4:
5479         case CEE_STIND_REF:
5480         case CEE_STIND_I8:
5481         case CEE_STIND_R4:
5482         case CEE_STIND_R8:
5483         case CEE_STOBJ:
5484                 if (tree->ssa_op == MONO_SSA_NOP) {
5485                         memset (acp, 0, sizeof (MonoInst *) * acp_size);
5486                         return;
5487                 }
5488
5489                 break;
5490         case CEE_CALL:
5491         case OP_CALL_REG:
5492         case CEE_CALLVIRT:
5493         case OP_LCALL_REG:
5494         case OP_LCALLVIRT:
5495         case OP_LCALL:
5496         case OP_FCALL_REG:
5497         case OP_FCALLVIRT:
5498         case OP_FCALL:
5499         case OP_VCALL_REG:
5500         case OP_VCALLVIRT:
5501         case OP_VCALL:
5502         case OP_VOIDCALL_REG:
5503         case OP_VOIDCALLVIRT:
5504         case OP_VOIDCALL: {
5505                 MonoCallInst *call = (MonoCallInst *)tree;
5506                 MonoMethodSignature *sig = call->signature;
5507                 int i, byref = FALSE;
5508
5509                 for (i = 0; i < sig->param_count; i++) {
5510                         if (sig->params [i]->byref) {
5511                                 byref = TRUE;
5512                                 break;
5513                         }
5514                 }
5515
5516                 if (byref)
5517                         memset (acp, 0, sizeof (MonoInst *) * acp_size);
5518
5519                 return;
5520         }
5521         default:
5522                 break;
5523         }
5524
5525         arity = mono_burg_arity [tree->opcode];
5526
5527         switch (arity) {
5528         case 0:
5529                 break;
5530         case 1:
5531                 mono_cprop_invalidate_values (tree->inst_i0, acp, acp_size);
5532                 break;
5533         case 2:
5534                 mono_cprop_invalidate_values (tree->inst_i0, acp, acp_size);
5535                 mono_cprop_invalidate_values (tree->inst_i1, acp, acp_size);
5536                 break;
5537         default:
5538                 g_assert_not_reached ();
5539         }
5540 }
5541
5542 static void
5543 mono_local_cprop_bb (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst **acp, int acp_size)
5544 {
5545         MonoInst *tree = bb->code;      
5546         int i;
5547
5548         if (!tree)
5549                 return;
5550
5551         for (; tree; tree = tree->next) {
5552
5553                 mono_cprop_copy_values (cfg, tree, acp);
5554
5555                 mono_cprop_invalidate_values (tree, acp, acp_size);
5556
5557                 if (tree->ssa_op == MONO_SSA_STORE  && 
5558                     (tree->inst_i0->opcode == OP_LOCAL || tree->inst_i0->opcode == OP_ARG)) {
5559                         MonoInst *i1 = tree->inst_i1;
5560
5561                         acp [tree->inst_i0->inst_c0] = NULL;
5562
5563                         for (i = 0; i < acp_size; i++) {
5564                                 if (acp [i] && acp [i]->opcode != OP_ICONST && 
5565                                     acp [i]->inst_c0 == tree->inst_i0->inst_c0) {
5566                                         acp [i] = NULL;
5567                                 }
5568                         }
5569
5570                         if (i1->opcode == OP_ICONST) {
5571                                 acp [tree->inst_i0->inst_c0] = i1;
5572                                 //printf ("DEF1 BB%d %d\n", bb->block_num,tree->inst_i0->inst_c0);
5573                         }
5574                         if (i1->ssa_op == MONO_SSA_LOAD && 
5575                             (i1->inst_i0->opcode == OP_LOCAL || i1->inst_i0->opcode == OP_ARG) &&
5576                             (i1->inst_i0->inst_c0 != tree->inst_i0->inst_c0)) {
5577                                 acp [tree->inst_i0->inst_c0] = i1->inst_i0;
5578                                 //printf ("DEF2 BB%d %d %d\n", bb->block_num,tree->inst_i0->inst_c0,i1->inst_i0->inst_c0);
5579                         }
5580                 }
5581
5582                 /*
5583                   if (tree->opcode == CEE_BEQ) {
5584                   g_assert (tree->inst_i0->opcode == OP_COMPARE);
5585                   if (tree->inst_i0->inst_i0->opcode == OP_ICONST &&
5586                   tree->inst_i0->inst_i1->opcode == OP_ICONST) {
5587                   
5588                   tree->opcode = CEE_BR;
5589                   if (tree->inst_i0->inst_i0->opcode == tree->inst_i0->inst_i1->opcode) {
5590                   tree->inst_target_bb = tree->inst_true_bb;
5591                   } else {
5592                   tree->inst_target_bb = tree->inst_false_bb;
5593                   }
5594                   }
5595                   }
5596                 */
5597         }
5598 }
5599
5600 static void
5601 mono_local_cprop (MonoCompile *cfg)
5602 {
5603         MonoBasicBlock *bb;
5604         MonoInst **acp;
5605
5606         acp = alloca (sizeof (MonoInst *) * cfg->num_varinfo);
5607
5608         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
5609                 memset (acp, 0, sizeof (MonoInst *) * cfg->num_varinfo);
5610                 mono_local_cprop_bb (cfg, bb, acp, cfg->num_varinfo);
5611         }
5612 }
5613
5614 MonoCompile*
5615 mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, int parts)
5616 {
5617         MonoMethodHeader *header = ((MonoMethodNormal *)method)->header;
5618         guint8 *ip = (guint8 *)header->code;
5619         MonoCompile *cfg;
5620         MonoJitInfo *jinfo;
5621         int dfn = 0, i, code_size_ratio;
5622
5623         mono_jit_stats.methods_compiled++;
5624         if (mono_jit_profile)
5625                 mono_profiler_method_jit (method);
5626
5627         cfg = g_new0 (MonoCompile, 1);
5628         cfg->method = method;
5629         cfg->mempool = mono_mempool_new ();
5630         cfg->opt = opts;
5631         cfg->bb_hash = g_hash_table_new (g_direct_hash, NULL);
5632         cfg->domain = domain;
5633         cfg->verbose_level = mini_verbose;
5634
5635         /*
5636          * create MonoInst* which represents arguments and local variables
5637          */
5638         mono_compile_create_vars (cfg);
5639
5640         if (cfg->verbose_level > 2)
5641                 g_print ("converting method %s\n", mono_method_full_name (method, TRUE));
5642
5643         if ((i = mono_method_to_ir (cfg, method, NULL, NULL, cfg->locals_start, NULL, NULL, NULL, 0)) < 0) {
5644                 mono_destroy_compile (cfg);
5645                 if (mono_jit_profile)
5646                         mono_profiler_method_end_jit (method, MONO_PROFILE_FAILED);
5647                 return NULL;
5648         }
5649
5650         mono_jit_stats.basic_blocks += cfg->num_bblocks;
5651         mono_jit_stats.max_basic_blocks = MAX (cfg->num_bblocks, mono_jit_stats.max_basic_blocks);
5652
5653         /*g_print ("numblocks = %d\n", cfg->num_bblocks);*/
5654
5655         /* Depth-first ordering on basic blocks */
5656         cfg->bblocks = mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * (cfg->num_bblocks + 1));
5657
5658         if (cfg->opt & MONO_OPT_BRANCH)
5659                 optimize_branches (cfg);
5660
5661         df_visit (cfg->bb_entry, &dfn, cfg->bblocks);
5662         if (cfg->num_bblocks != dfn + 1) {
5663                 if (cfg->verbose_level > 1)
5664                         g_print ("unreachable code?\n");
5665                 cfg->num_bblocks = dfn + 1;
5666         }
5667
5668         if (cfg->opt & MONO_OPT_LOOP) {
5669                 mono_compile_dominator_info (cfg, MONO_COMP_DOM | MONO_COMP_IDOM);
5670                 mono_compute_natural_loops (cfg);
5671         }
5672
5673
5674         /* after method_to_ir */
5675         if (parts == 1)
5676                 return cfg;
5677
5678 //#define DEBUGSSA "logic_run"
5679 #define DEBUGSSA_CLASS "Tests"
5680 #ifdef DEBUGSSA
5681
5682
5683         if (!header->num_clauses && !cfg->disable_ssa) {
5684                 mono_local_cprop (cfg);
5685                 mono_ssa_compute (cfg);
5686         }
5687 #else 
5688
5689         /* fixme: add all optimizations which requires SSA */
5690         if (cfg->opt & (MONO_OPT_DEADCE)) {
5691                 if (!(cfg->comp_done & MONO_COMP_SSA) && !header->num_clauses && !cfg->disable_ssa) {
5692                         mono_local_cprop (cfg);
5693                         mono_ssa_compute (cfg);
5694
5695                         if (cfg->verbose_level >= 2) {
5696                                 print_dfn (cfg);
5697                         }
5698                 }
5699         }
5700 #endif
5701
5702         /* after SSA translation */
5703         if (parts == 2)
5704                 return cfg;
5705
5706         if ((cfg->opt & MONO_OPT_CONSPROP) ||  (cfg->opt & MONO_OPT_COPYPROP)) {
5707                 if (cfg->comp_done & MONO_COMP_SSA) {
5708                         mono_ssa_cprop (cfg);
5709                 } else {
5710                         mono_local_cprop (cfg);
5711                 }
5712         }
5713
5714         if (cfg->comp_done & MONO_COMP_SSA) {                   
5715                 mono_ssa_deadce (cfg);
5716
5717                 //mono_ssa_strength_reduction (cfg);
5718
5719                 mono_ssa_remove (cfg);
5720
5721                 if (cfg->opt & MONO_OPT_BRANCH)
5722                         optimize_branches (cfg);
5723         }
5724
5725         /* after SSA removal */
5726         if (parts == 3)
5727                 return cfg;
5728         
5729         decompose_pass (cfg);
5730
5731         if (cfg->opt & MONO_OPT_LINEARS) {
5732                 GList *vars, *regs;
5733
5734                 /* fixme: maybe we can avoid to compute livenesss here if already computed ? */
5735                 cfg->comp_done &= ~MONO_COMP_LIVENESS;
5736                 if (!(cfg->comp_done & MONO_COMP_LIVENESS))
5737                         mono_analyze_liveness (cfg);
5738                 
5739                 if ((vars = mono_arch_get_allocatable_int_vars (cfg))) {
5740                         regs = mono_arch_get_global_int_regs (cfg);
5741                         mono_linear_scan (cfg, vars, regs, &cfg->used_int_regs);
5742                 }
5743         }
5744
5745         //mono_print_code (cfg);
5746         
5747         //print_dfn (cfg);
5748
5749         /* variables are allocated after decompose, since decompose could create temps */
5750         mono_arch_allocate_vars (cfg);
5751
5752         if (cfg->opt & MONO_OPT_CFOLD)
5753                 mono_constant_fold (cfg);
5754
5755         mini_select_instructions (cfg);
5756
5757         mono_codegen (cfg);
5758         if (cfg->verbose_level >= 2) {
5759                 char *id =  mono_method_full_name (cfg->method, FALSE);
5760                 mono_disassemble_code (cfg->native_code, cfg->code_len, id + 3);
5761                 g_free (id);
5762         }
5763         
5764         jinfo = mono_mempool_alloc0 (cfg->domain->mp, sizeof (MonoJitInfo));
5765
5766         jinfo = g_new0 (MonoJitInfo, 1);
5767         jinfo->method = method;
5768         jinfo->code_start = cfg->native_code;
5769         jinfo->code_size = cfg->code_len;
5770         jinfo->used_regs = cfg->used_int_regs;
5771
5772         if (header->num_clauses) {
5773                 int i;
5774
5775                 jinfo->exvar_offset = cfg->exvar? cfg->exvar->inst_offset: 0;
5776                 jinfo->num_clauses = header->num_clauses;
5777                 jinfo->clauses = mono_mempool_alloc0 (cfg->domain->mp, 
5778                         sizeof (MonoJitExceptionInfo) * header->num_clauses);
5779
5780                 for (i = 0; i < header->num_clauses; i++) {
5781                         MonoExceptionClause *ec = &header->clauses [i];
5782                         MonoJitExceptionInfo *ei = &jinfo->clauses [i];
5783                         MonoBasicBlock *tblock;
5784
5785                         ei->flags = ec->flags;
5786
5787                         if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
5788                                 tblock = g_hash_table_lookup (cfg->bb_hash, ip + ec->token_or_filter);
5789                                 g_assert (tblock);
5790                                 ei->data.filter = cfg->native_code + tblock->native_offset;
5791                         } else {
5792                                 ei->data.token = ec->token_or_filter;
5793                         }
5794
5795                         tblock = g_hash_table_lookup (cfg->bb_hash, ip + ec->try_offset);
5796                         g_assert (tblock);
5797                         ei->try_start = cfg->native_code + tblock->native_offset;
5798                         tblock = g_hash_table_lookup (cfg->bb_hash, ip + ec->try_offset + ec->try_len);
5799                         g_assert (tblock);
5800                         ei->try_end = cfg->native_code + tblock->native_offset;
5801                         tblock = g_hash_table_lookup (cfg->bb_hash, ip + ec->handler_offset);
5802                         g_assert (tblock);
5803                         ei->handler_start = cfg->native_code + tblock->native_offset;
5804
5805                 }
5806         }
5807
5808         mono_jit_info_table_add (cfg->domain, jinfo);
5809
5810         /* collect statistics */
5811         mono_jit_stats.allocated_code_size += cfg->code_len;
5812         code_size_ratio = cfg->code_len;
5813         if (code_size_ratio > mono_jit_stats.biggest_method_size) {
5814                         mono_jit_stats.biggest_method_size = code_size_ratio;
5815                         mono_jit_stats.biggest_method = method;
5816         }
5817         code_size_ratio = (code_size_ratio * 100) / ((MonoMethodNormal *)method)->header->code_size;
5818         if (code_size_ratio > mono_jit_stats.max_code_size_ratio) {
5819                 mono_jit_stats.max_code_size_ratio = code_size_ratio;
5820                 mono_jit_stats.max_ratio_method = method;
5821         }
5822         mono_jit_stats.native_code_size += cfg->code_len;
5823
5824         if (mono_jit_profile)
5825                 mono_profiler_method_end_jit (method, MONO_PROFILE_OK);
5826
5827         return cfg;
5828 }
5829
5830 static gpointer
5831 mono_jit_compile_method (MonoMethod *method)
5832 {
5833         /* FIXME: later copy the code from mono */
5834         MonoDomain *target_domain, *domain = mono_domain_get ();
5835         MonoCompile *cfg;
5836         GHashTable *jit_code_hash;
5837         gpointer code;
5838
5839         if (default_opt & MONO_OPT_SAHRED)
5840                 target_domain = mono_root_domain;
5841         else 
5842                 target_domain = domain;
5843
5844         jit_code_hash = target_domain->jit_code_hash;
5845
5846         if ((code = g_hash_table_lookup (jit_code_hash, method))) {
5847                 mono_jit_stats.methods_lookups++;
5848                 return code;
5849         }
5850
5851 #ifdef MONO_USE_AOT_COMPILER
5852         if (!mono_compile_aot) {
5853                 mono_class_init (method->klass);
5854                 if ((code = mono_aot_get_method (method))) {
5855                         g_hash_table_insert (jit_code_hash, method, code);
5856                         return code;
5857                 }
5858         }
5859 #endif
5860
5861         if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
5862             (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
5863                 if (!method->info) {
5864                         MonoMethod *nm;
5865
5866                         if (!method->addr && (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL))
5867                                 mono_lookup_pinvoke_call (method);
5868 #ifdef MONO_USE_EXC_TABLES
5869                         if (mono_method_blittable (method)) {
5870                                 method->info = method->addr;
5871                         } else {
5872 #endif
5873                                 nm = mono_marshal_get_native_wrapper (method);
5874                                 method->info = mono_compile_method (nm);
5875
5876                                 //if (mono_debug_format != MONO_DEBUG_FORMAT_NONE) 
5877                                 //mono_debug_add_wrapper (method, nm);
5878 #ifdef MONO_USE_EXC_TABLES
5879                         }
5880 #endif
5881                 }
5882                 return method->info;
5883         } else if ((method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME)) {
5884                 const char *name = method->name;
5885                 MonoMethod *nm;
5886
5887                 if (method->klass->parent == mono_defaults.multicastdelegate_class) {
5888                         if (*name == '.' && (strcmp (name, ".ctor") == 0)) {
5889                                 /* FIXME: uhm, we need a wrapper to handle exceptions? */
5890                                 return (gpointer)mono_delegate_ctor;
5891                         } else if (*name == 'I' && (strcmp (name, "Invoke") == 0)) {
5892                                 nm = mono_marshal_get_delegate_invoke (method);
5893                                 return mono_jit_compile_method (nm);
5894                         } else if (*name == 'B' && (strcmp (name, "BeginInvoke") == 0)) {
5895                                 nm = mono_marshal_get_delegate_begin_invoke (method);
5896                                 return mono_jit_compile_method (nm);
5897                         } else if (*name == 'E' && (strcmp (name, "EndInvoke") == 0)) {
5898                                 nm = mono_marshal_get_delegate_end_invoke (method);
5899                                 return mono_jit_compile_method (nm);
5900                         }
5901                 }
5902                 return NULL;
5903         }
5904
5905         cfg = mini_method_compile (method, default_opt, target_domain, 0);
5906         code = cfg->native_code;
5907         mono_destroy_compile (cfg);
5908
5909         g_hash_table_insert (jit_code_hash, method, code);
5910
5911         /* make sure runtime_init is called */
5912         mono_class_vtable (target_domain, method->klass);
5913
5914         return code;
5915 }
5916
5917 /**
5918  * mono_jit_runtime_invoke:
5919  * @method: the method to invoke
5920  * @obj: this pointer
5921  * @params: array of parameter values.
5922  * @exc: used to catch exceptions objects
5923  */
5924 static MonoObject*
5925 mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
5926 {
5927         MonoMethod *invoke;
5928         MonoObject *(*runtime_invoke) (MonoObject *this, void **params, MonoObject **exc);
5929         invoke = mono_marshal_get_runtime_invoke (method);
5930         runtime_invoke = mono_jit_compile_method (invoke);      
5931         return runtime_invoke (obj, params, exc);
5932 }
5933
5934 #ifdef PLATFORM_WIN32
5935 #define GET_CONTEXT \
5936         struct sigcontext *ctx = (struct sigcontext*)_dummy;
5937 #else
5938 #define GET_CONTEXT \
5939         void **_p = (void **)&_dummy; \
5940         struct sigcontext *ctx = (struct sigcontext *)++_p;
5941 #endif
5942
5943 static void
5944 sigfpe_signal_handler (int _dummy)
5945 {
5946         MonoException *exc;
5947         GET_CONTEXT
5948
5949         exc = mono_get_exception_divide_by_zero ();
5950         
5951         mono_arch_handle_exception (ctx, exc, FALSE);
5952 }
5953
5954 static void
5955 sigill_signal_handler (int _dummy)
5956 {
5957         MonoException *exc;
5958         GET_CONTEXT
5959         exc = mono_get_exception_execution_engine ("SIGILL");
5960         
5961         mono_arch_handle_exception (ctx, exc, FALSE);
5962 }
5963
5964 static void
5965 sigsegv_signal_handler (int _dummy)
5966 {
5967         MonoException *exc;
5968         GET_CONTEXT
5969
5970         exc = mono_get_exception_null_reference ();
5971         
5972         mono_arch_handle_exception (ctx, exc, FALSE);
5973 }
5974
5975 static void
5976 sigusr1_signal_handler (int _dummy)
5977 {
5978         MonoThread *thread;
5979         GET_CONTEXT
5980         
5981         thread = mono_thread_current ();
5982         
5983         g_assert (thread->abort_exc);
5984
5985         mono_arch_handle_exception (ctx, thread->abort_exc, FALSE);
5986 }
5987
5988 static void
5989 mono_runtime_install_handlers (void)
5990 {
5991 #ifndef PLATFORM_WIN32
5992         struct sigaction sa;
5993 #endif
5994
5995 #ifdef PLATFORM_WIN32
5996         win32_seh_init();
5997         win32_seh_set_handler(SIGFPE, sigfpe_signal_handler);
5998         win32_seh_set_handler(SIGILL, sigill_signal_handler);
5999         win32_seh_set_handler(SIGSEGV, sigsegv_signal_handler);
6000 #else /* !PLATFORM_WIN32 */
6001
6002         /* libpthreads has its own implementation of sigaction(),
6003          * but it seems to work well with our current exception
6004          * handlers. If not we must call syscall directly instead 
6005          * of sigaction */
6006         
6007         /* catch SIGFPE */
6008         sa.sa_handler = sigfpe_signal_handler;
6009         sigemptyset (&sa.sa_mask);
6010         sa.sa_flags = 0;
6011         //g_assert (syscall (SYS_sigaction, SIGFPE, &sa, NULL) != -1);
6012         g_assert (sigaction (SIGFPE, &sa, NULL) != -1);
6013
6014         /* catch SIGILL */
6015         sa.sa_handler = sigill_signal_handler;
6016         sigemptyset (&sa.sa_mask);
6017         sa.sa_flags = 0;
6018         //g_assert (syscall (SYS_sigaction, SIGILL, &sa, NULL) != -1);
6019         g_assert (sigaction (SIGILL, &sa, NULL) != -1);
6020
6021         /* catch thread abort signal */
6022         sa.sa_handler = sigusr1_signal_handler;
6023         sigemptyset (&sa.sa_mask);
6024         sa.sa_flags = 0;
6025         //g_assert (syscall (SYS_sigaction, SIGILL, &sa, NULL) != -1);
6026         g_assert (sigaction (mono_thread_get_abort_signal (), &sa, NULL) != -1);
6027
6028 #if 1
6029         /* catch SIGSEGV */
6030         sa.sa_handler = sigsegv_signal_handler;
6031         sigemptyset (&sa.sa_mask);
6032         sa.sa_flags = 0;
6033         //g_assert (syscall (SYS_sigaction, SIGSEGV, &sa, NULL) != -1);
6034         g_assert (sigaction (SIGSEGV, &sa, NULL) != -1);
6035 #endif
6036 #endif /* PLATFORM_WIN32 */
6037 }
6038
6039 /* mono_jit_create_remoting_trampoline:
6040  * @method: pointer to the method info
6041  *
6042  * Creates a trampoline which calls the remoting functions. This
6043  * is used in the vtable of transparent proxies.
6044  * 
6045  * Returns: a pointer to the newly created code 
6046  */
6047 static gpointer
6048 mono_jit_create_remoting_trampoline (MonoMethod *method)
6049 {
6050         MonoMethod *nm;
6051         guint8 *addr = NULL;
6052
6053         if (method->signature->hasthis && (method->klass->marshalbyref || method->klass == mono_defaults.object_class)) {
6054                 nm = mono_marshal_get_remoting_invoke (method);
6055                 addr = mono_compile_method (nm);
6056         } else {
6057                 addr = mono_compile_method (method);
6058         }
6059         return addr;
6060 }
6061
6062 static CRITICAL_SECTION ms;
6063
6064 MonoDomain *
6065 mini_init (const char *filename)
6066 {
6067         MonoDomain *domain;
6068         
6069         metadata_section = &ms;
6070         InitializeCriticalSection (metadata_section);
6071
6072         mono_jit_tls_id = TlsAlloc ();
6073         mono_thread_start_cb (GetCurrentThreadId (), (gpointer)-1, NULL);
6074
6075         mono_burg_init ();
6076
6077         mono_runtime_install_handlers ();
6078
6079         mono_install_compile_method (mono_jit_compile_method);
6080         mono_install_trampoline (mono_arch_create_jit_trampoline);
6081         mono_install_remoting_trampoline (mono_jit_create_remoting_trampoline);
6082         mono_install_runtime_invoke (mono_jit_runtime_invoke);
6083         mono_install_handler (mono_arch_get_throw_exception ());
6084         mono_install_stack_walk (mono_jit_walk_stack);
6085         mono_install_get_config_dir ();
6086
6087         domain = mono_init (filename);
6088         mono_init_icall ();
6089
6090         mono_add_internal_call ("System.Diagnostics.StackFrame::get_frame_info", 
6091                                 ves_icall_get_frame_info);
6092         mono_add_internal_call ("System.Diagnostics.StackTrace::get_trace", 
6093                                 ves_icall_get_trace);
6094         mono_add_internal_call ("Mono.Runtime::mono_runtime_install_handlers", 
6095                                 mono_runtime_install_handlers);
6096
6097
6098         create_helper_signature ();
6099
6100         mono_arch_register_lowlevel_calls ();
6101         mono_register_jit_icall (mono_profiler_method_enter, "mono_profiler_method_enter", NULL, TRUE);
6102         mono_register_jit_icall (mono_profiler_method_leave, "mono_profiler_method_leave", NULL, TRUE);
6103
6104         mono_register_jit_icall (mono_get_lmf_addr, "mono_get_lmf_addr", helper_sig_ptr_void, TRUE);
6105         mono_register_jit_icall (mono_domain_get, "mono_domain_get", helper_sig_domain_get, TRUE);
6106
6107         /* fixme: we cant hanlde vararg methods this way, because the signature is not constant */
6108         //mono_register_jit_icall (ves_array_element_address, "ves_array_element_address", NULL);
6109         //mono_register_jit_icall (mono_array_new_va, "mono_array_new_va", NULL);
6110
6111         mono_register_jit_icall (mono_arch_get_throw_exception (), "mono_arch_throw_exception", helper_sig_void_obj, TRUE);
6112         mono_register_jit_icall (mono_arch_get_throw_exception_by_name (), "mono_arch_throw_exception_by_name", 
6113                                  helper_sig_void_ptr, TRUE);
6114
6115         /* 
6116          * NOTE, NOTE, NOTE, NOTE:
6117          * when adding emulation for some opcodes, remember to also add a dummy
6118          * rule to the burg files, because we need the arity information to be correct.
6119          */
6120         mono_register_opcode_emulation (OP_LMUL, helper_sig_long_long_long, mono_llmult);
6121         mono_register_opcode_emulation (OP_LMUL_OVF_UN, helper_sig_long_long_long, mono_llmult_ovf_un);
6122         mono_register_opcode_emulation (OP_LMUL_OVF, helper_sig_long_long_long, mono_llmult_ovf);
6123         mono_register_opcode_emulation (OP_LDIV, helper_sig_long_long_long, mono_lldiv);
6124         mono_register_opcode_emulation (OP_LDIV_UN, helper_sig_long_long_long, mono_lldiv_un);
6125         mono_register_opcode_emulation (OP_LREM, helper_sig_long_long_long, mono_llrem);
6126         mono_register_opcode_emulation (OP_LREM_UN, helper_sig_long_long_long, mono_llrem_un);
6127
6128         mono_register_opcode_emulation (OP_LSHL, helper_sig_long_long_int, mono_lshl);
6129         mono_register_opcode_emulation (OP_LSHR, helper_sig_long_long_int, mono_lshr);
6130         mono_register_opcode_emulation (OP_LSHR_UN, helper_sig_long_long_int, mono_lshr_un);
6131
6132         mono_register_opcode_emulation (OP_FCONV_TO_U8, helper_sig_ulong_double, mono_fconv_u8);
6133         mono_register_opcode_emulation (OP_FCONV_TO_U4, helper_sig_uint_double, mono_fconv_u4);
6134         mono_register_opcode_emulation (OP_FCONV_TO_OVF_I8, helper_sig_long_double, mono_fconv_ovf_i8);
6135         mono_register_opcode_emulation (OP_FCONV_TO_OVF_U8, helper_sig_ulong_double, mono_fconv_ovf_u8);
6136
6137 #if SIZEOF_VOID_P == 4
6138         mono_register_opcode_emulation (OP_FCONV_TO_U, helper_sig_uint_double, mono_fconv_u4);
6139 #else
6140 #warning "fixme: add opcode emulation"
6141 #endif
6142
6143         /* other jit icalls */
6144         mono_register_jit_icall (mono_class_static_field_address , "mono_class_static_field_address", 
6145                                  helper_sig_ptr_ptr_ptr, FALSE);
6146         mono_register_jit_icall (mono_ldtoken_wrapper, "mono_ldtoken_wrapper", helper_sig_ptr_ptr_ptr, FALSE);
6147         mono_register_jit_icall (mono_ldstr, "mono_ldstr", helper_sig_ldstr, FALSE);
6148         mono_register_jit_icall (helper_memcpy, "helper_memcpy", helper_sig_memcpy, FALSE);
6149         mono_register_jit_icall (helper_memset, "helper_memset", helper_sig_memset, FALSE);
6150         mono_register_jit_icall (helper_initobj, "helper_initobj", helper_sig_initobj, FALSE);
6151         mono_register_jit_icall (helper_stelem_ref, "helper_stelem_ref", helper_sig_stelem_ref, FALSE);
6152         mono_register_jit_icall (mono_object_new, "mono_object_new", helper_sig_object_new, FALSE);
6153         mono_register_jit_icall (mono_array_new, "mono_array_new", helper_sig_newarr, FALSE);
6154         mono_register_jit_icall (mono_string_to_utf16, "mono_string_to_utf16", helper_sig_ptr_obj, FALSE);
6155         mono_register_jit_icall (mono_string_from_utf16, "mono_string_from_utf16", helper_sig_obj_ptr, FALSE);
6156         mono_register_jit_icall (mono_string_new_wrapper, "mono_string_new_wrapper", helper_sig_obj_ptr, FALSE);
6157         mono_register_jit_icall (mono_string_to_utf8, "mono_string_to_utf8", helper_sig_ptr_obj, FALSE);
6158         mono_register_jit_icall (mono_string_to_bstr, "mono_string_to_bstr", helper_sig_ptr_obj, FALSE);
6159         mono_register_jit_icall (mono_string_to_ansibstr, "mono_string_to_ansibstr", helper_sig_ptr_obj, FALSE);
6160         mono_register_jit_icall (mono_string_builder_to_utf8, "mono_string_builder_to_utf8", helper_sig_ptr_obj, FALSE);
6161         mono_register_jit_icall (mono_array_to_savearray, "mono_array_to_savearray", helper_sig_ptr_obj, FALSE);
6162         mono_register_jit_icall (mono_array_to_lparray, "mono_array_to_lparray", helper_sig_ptr_obj, FALSE);
6163         mono_register_jit_icall (mono_delegate_to_ftnptr, "mono_delegate_to_ftnptr", helper_sig_ptr_obj, FALSE);
6164         mono_register_jit_icall (mono_marshal_string_array, "mono_marshal_string_array", helper_sig_ptr_obj, FALSE);
6165         mono_register_jit_icall (mono_string_utf8_to_builder, "mono_string_utf8_to_builder", helper_sig_void_ptr_ptr, FALSE);
6166         mono_register_jit_icall (mono_marshal_free_array, "mono_marshal_free_array", helper_sig_void_ptr_ptr, FALSE);
6167         mono_register_jit_icall (mono_string_to_byvalstr, "mono_string_to_byvalstr", helper_sig_void_ptr_ptr_ptr, FALSE);
6168         mono_register_jit_icall (mono_string_to_byvalwstr, "mono_string_to_byvalwstr", helper_sig_void_ptr_ptr_ptr, FALSE);
6169         mono_register_jit_icall (g_free, "g_free", helper_sig_void_ptr, FALSE);
6170         mono_register_jit_icall (mono_ldftn, "mono_ldftn", helper_sig_compile, FALSE);
6171         mono_register_jit_icall (mono_ldvirtfn, "mono_ldvirtfn", helper_sig_compile_virt, FALSE);
6172
6173         mono_runtime_init (domain, mono_thread_start_cb,
6174                            mono_thread_attach_cb);
6175
6176         //mono_thread_attach (domain);
6177         return domain;
6178 }
6179
6180 MonoJitStats mono_jit_stats = {0};
6181
6182 static void 
6183 print_jit_stats (void)
6184 {
6185         if (mono_jit_stats.enabled) {
6186                 g_print ("Mono Jit statistics\n");
6187                 g_print ("Compiled methods:       %ld\n", mono_jit_stats.methods_compiled);
6188                 g_print ("Methods from AOT:       %ld\n", mono_jit_stats.methods_aot);
6189                 g_print ("Methods cache lookup:   %ld\n", mono_jit_stats.methods_lookups);
6190                 g_print ("Method trampolines:     %ld\n", mono_jit_stats.method_trampolines);
6191                 g_print ("Basic blocks:           %ld\n", mono_jit_stats.basic_blocks);
6192                 g_print ("Max basic blocks:       %ld\n", mono_jit_stats.max_basic_blocks);
6193                 g_print ("Allocated vars:         %ld\n", mono_jit_stats.allocate_var);
6194                 g_print ("Analyze stack repeat:   %ld\n", mono_jit_stats.analyze_stack_repeat);
6195                 g_print ("Compiled CIL code size: %ld\n", mono_jit_stats.cil_code_size);
6196                 g_print ("Native code size:       %ld\n", mono_jit_stats.native_code_size);
6197                 g_print ("Max code size ratio:    %.2f (%s::%s)\n", mono_jit_stats.max_code_size_ratio/100.0,
6198                                 mono_jit_stats.max_ratio_method->klass->name, mono_jit_stats.max_ratio_method->name);
6199                 g_print ("Biggest method:         %ld (%s::%s)\n", mono_jit_stats.biggest_method_size,
6200                                 mono_jit_stats.biggest_method->klass->name, mono_jit_stats.biggest_method->name);
6201                 g_print ("Code reallocs:          %ld\n", mono_jit_stats.code_reallocs);
6202                 g_print ("Allocated code size:    %ld\n", mono_jit_stats.allocated_code_size);
6203                 g_print ("Inlineable methods:     %ld\n", mono_jit_stats.inlineable_methods);
6204                 g_print ("Inlined methods:        %ld\n", mono_jit_stats.inlined_methods);
6205                 
6206                 g_print ("\nCreated object count:   %ld\n", mono_stats.new_object_count);
6207                 g_print ("Initialized classes:    %ld\n", mono_stats.initialized_class_count);
6208                 g_print ("Used classes:           %ld\n", mono_stats.used_class_count);
6209                 g_print ("Static data size:       %ld\n", mono_stats.class_static_data_size);
6210                 g_print ("VTable data size:       %ld\n", mono_stats.class_vtable_size);
6211         }
6212 }
6213
6214 void
6215 mini_cleanup (MonoDomain *domain)
6216 {
6217         /* 
6218          * mono_runtime_cleanup() and mono_domain_finalize () need to
6219          * be called early since they need the execution engine still
6220          * fully working (mono_domain_finalize may invoke managed finalizers
6221          * and mono_runtime_cleanup will wait for other threads to finish).
6222          */
6223         mono_domain_finalize (domain);
6224
6225         mono_runtime_cleanup (domain);
6226
6227         mono_profiler_shutdown ();
6228
6229         mono_debug_cleanup ();
6230 #ifdef PLATFORM_WIN32
6231         win32_seh_cleanup();
6232 #endif
6233
6234         mono_domain_unload (domain, TRUE);
6235
6236         print_jit_stats ();
6237         DeleteCriticalSection (metadata_section);
6238 }
6239
6240 void
6241 mini_set_defaults (int verbose_level, guint32 opts)
6242 {
6243         mini_verbose = verbose_level;
6244         default_opt = opts;
6245 }
6246