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