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