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