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