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