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