2005-01-06 Zoltan Varga <vargaz@freemail.hu>
[mono.git] / mono / mini / mini.c
1 /*
2  * mini.c: The new Mono code generator.
3  *
4  * Author:
5  *   Paolo Molaro (lupus@ximian.com)
6  *   Dietmar Maurer (dietmar@ximian.com)
7  *
8  * (C) 2002 Ximian, Inc.
9  */
10
11 #include <config.h>
12 #include <signal.h>
13 #include <unistd.h>
14 #include <math.h>
15 #include <sys/time.h>
16
17 #ifdef sun    // Solaris x86
18 #include <sys/types.h>
19 #include <sys/ucontext.h>
20 #endif
21
22 #ifdef HAVE_VALGRIND_MEMCHECK_H
23 #include <valgrind/memcheck.h>
24 #endif
25
26 #include <mono/metadata/assembly.h>
27 #include <mono/metadata/loader.h>
28 #include <mono/metadata/cil-coff.h>
29 #include <mono/metadata/tabledefs.h>
30 #include <mono/metadata/class.h>
31 #include <mono/metadata/object.h>
32 #include <mono/metadata/exception.h>
33 #include <mono/metadata/opcodes.h>
34 #include <mono/metadata/mono-endian.h>
35 #include <mono/metadata/tokentype.h>
36 #include <mono/metadata/tabledefs.h>
37 #include <mono/metadata/threads.h>
38 #include <mono/metadata/marshal.h>
39 #include <mono/metadata/socket-io.h>
40 #include <mono/metadata/appdomain.h>
41 #include <mono/metadata/debug-helpers.h>
42 #include <mono/io-layer/io-layer.h>
43 #include "mono/metadata/profiler.h"
44 #include <mono/metadata/profiler-private.h>
45 #include <mono/metadata/mono-config.h>
46 #include <mono/metadata/environment.h>
47 #include <mono/metadata/mono-debug.h>
48 #include <mono/metadata/mono-debug-debugger.h>
49 #include <mono/metadata/monitor.h>
50 #include <mono/utils/mono-math.h>
51 #include <mono/os/gc_wrapper.h>
52
53 #include "mini.h"
54 #include <string.h>
55 #include <ctype.h>
56 #include "inssel.h"
57 #include "trace.h"
58
59 #include "jit-icalls.c"
60
61 /* 
62  * this is used to determine when some branch optimizations are possible: we exclude FP compares
63  * because they have weird semantics with NaNs.
64  */
65 #define MONO_IS_COND_BRANCH_OP(ins) (((ins)->opcode >= CEE_BEQ && (ins)->opcode <= CEE_BLT_UN) || ((ins)->opcode >= OP_LBEQ && (ins)->opcode <= OP_LBLT_UN) || ((ins)->opcode >= OP_FBEQ && (ins)->opcode <= OP_FBLT_UN) || ((ins)->opcode >= OP_IBEQ && (ins)->opcode <= OP_IBLT_UN))
66 #define MONO_IS_COND_BRANCH_NOFP(ins) (MONO_IS_COND_BRANCH_OP(ins) && (ins)->inst_left->inst_left->type != STACK_R8)
67
68 #define MONO_CHECK_THIS(ins) (cfg->method->signature->hasthis && (ins)->ssa_op == MONO_SSA_LOAD && (ins)->inst_left->inst_c0 == 0)
69
70 static void setup_stat_profiler (void);
71 gboolean  mono_arch_print_tree(MonoInst *tree, int arity);
72 static gpointer mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt);
73 static gpointer mono_jit_compile_method (MonoMethod *method);
74 static gpointer mono_jit_find_compiled_method (MonoDomain *domain, MonoMethod *method);
75
76 static void handle_stobj (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *dest, MonoInst *src, 
77                           const unsigned char *ip, MonoClass *klass, gboolean to_end, gboolean native);
78
79 static void dec_foreach (MonoInst *tree, MonoCompile *cfg);
80
81 static int mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock, 
82                    int locals_offset, MonoInst *return_var, GList *dont_inline, MonoInst **inline_args, 
83                    guint inline_offset, gboolean is_virtual_call);
84
85 extern guint8 mono_burg_arity [];
86 /* helper methods signature */
87 static MonoMethodSignature *helper_sig_long_long_long = NULL;
88 static MonoMethodSignature *helper_sig_long_long_int = NULL;
89 static MonoMethodSignature *helper_sig_newarr = NULL;
90 static MonoMethodSignature *helper_sig_newarr_specific = NULL;
91 static MonoMethodSignature *helper_sig_ldstr = NULL;
92 static MonoMethodSignature *helper_sig_domain_get = NULL;
93 static MonoMethodSignature *helper_sig_object_new = NULL;
94 static MonoMethodSignature *helper_sig_object_new_specific = NULL;
95 static MonoMethodSignature *helper_sig_compile = NULL;
96 static MonoMethodSignature *helper_sig_compile_virt = NULL;
97 static MonoMethodSignature *helper_sig_obj_ptr = NULL;
98 static MonoMethodSignature *helper_sig_obj_ptr_ptr = NULL;
99 static MonoMethodSignature *helper_sig_obj_obj_ptr_ptr = NULL;
100 static MonoMethodSignature *helper_sig_obj_void = NULL;
101 static MonoMethodSignature *helper_sig_ptr_void = NULL;
102 static MonoMethodSignature *helper_sig_void_void = NULL;
103 static MonoMethodSignature *helper_sig_void_ptr = NULL;
104 static MonoMethodSignature *helper_sig_void_obj = NULL;
105 static MonoMethodSignature *helper_sig_void_obj_ptr_int = NULL;
106 static MonoMethodSignature *helper_sig_void_obj_ptr_ptr_obj = NULL;
107 static MonoMethodSignature *helper_sig_void_ptr_ptr = NULL;
108 static MonoMethodSignature *helper_sig_void_ptr_ptr_ptr = NULL;
109 static MonoMethodSignature *helper_sig_ptr_ptr_ptr = NULL;
110 static MonoMethodSignature *helper_sig_ptr_ptr_ptr_ptr = NULL;
111 static MonoMethodSignature *helper_sig_ptr_obj = NULL;
112 static MonoMethodSignature *helper_sig_ptr_obj_int = NULL;
113 static MonoMethodSignature *helper_sig_ptr_int = NULL;
114 static MonoMethodSignature *helper_sig_initobj = NULL;
115 static MonoMethodSignature *helper_sig_memcpy = NULL;
116 static MonoMethodSignature *helper_sig_memset = NULL;
117 static MonoMethodSignature *helper_sig_ulong_double = NULL;
118 static MonoMethodSignature *helper_sig_long_double = NULL;
119 static MonoMethodSignature *helper_sig_double_long = NULL;
120 static MonoMethodSignature *helper_sig_double_int = NULL;
121 static MonoMethodSignature *helper_sig_float_long = NULL;
122 static MonoMethodSignature *helper_sig_double_double_double = NULL;
123 static MonoMethodSignature *helper_sig_uint_double = NULL;
124 static MonoMethodSignature *helper_sig_int_double = NULL;
125 static MonoMethodSignature *helper_sig_stelem_ref = NULL;
126 static MonoMethodSignature *helper_sig_stelem_ref_check = NULL;
127 static MonoMethodSignature *helper_sig_class_init_trampoline = NULL;
128 static MonoMethodSignature *helper_sig_compile_generic_method = NULL;
129
130 static guint32 default_opt = MONO_OPT_PEEPHOLE;
131
132 guint32 mono_jit_tls_id = -1;
133 MonoTraceSpec *mono_jit_trace_calls = NULL;
134 gboolean mono_break_on_exc = FALSE;
135 #ifndef DISABLE_AOT
136 gboolean mono_compile_aot = FALSE;
137 #endif
138
139 static int mini_verbose = 0;
140
141 static CRITICAL_SECTION jit_mutex;
142
143 static GHashTable *class_init_hash_addr = NULL;
144
145 gboolean
146 mono_running_on_valgrind (void)
147 {
148 #ifdef HAVE_VALGRIND_MEMCHECK_H
149                 if (RUNNING_ON_VALGRIND)
150                         return TRUE;
151                 else
152                         return FALSE;
153 #else
154                 return FALSE;
155 #endif
156 }
157
158 /* debug function */
159 G_GNUC_UNUSED static char*
160 get_method_from_ip (void *ip)
161 {
162         MonoJitInfo *ji;
163         char *method;
164         char *source;
165         char *res;
166         MonoDomain *domain = mono_domain_get ();
167         
168         ji = mono_jit_info_table_find (domain, ip);
169         if (!ji) {
170                 return NULL;
171         }
172         method = mono_method_full_name (ji->method, TRUE);
173         source = mono_debug_source_location_from_address (ji->method, (int) ip, NULL, domain);
174
175         res = g_strdup_printf (" %s + 0x%x (%p %p) [%p - %s]", method, (int)((char*)ip - (char*)ji->code_start), ji->code_start, (char*)ji->code_start + ji->code_size, domain, domain->friendly_name);
176
177         g_free (source);
178         g_free (method);
179
180         return res;
181 }
182
183 /* debug function */
184 G_GNUC_UNUSED static void
185 print_method_from_ip (void *ip)
186 {
187         MonoJitInfo *ji;
188         char *method;
189         char *source;
190         MonoDomain *domain = mono_domain_get ();
191         
192         ji = mono_jit_info_table_find (domain, ip);
193         if (!ji) {
194                 g_print ("No method at %p\n", ip);
195                 return;
196         }
197         method = mono_method_full_name (ji->method, TRUE);
198         source = mono_debug_source_location_from_address (ji->method, (int) ip, NULL, domain);
199
200         g_print ("IP %p at offset 0x%x of method %s (%p %p)[domain %p - %s]\n", ip, (int)((char*)ip - (char*)ji->code_start), method, ji->code_start, (char*)ji->code_start + ji->code_size, domain, domain->friendly_name);
201
202         if (source)
203                 g_print ("%s\n", source);
204
205         g_free (source);
206         g_free (method);
207 }
208
209 G_GNUC_UNUSED void
210 mono_print_method_from_ip (void *ip)
211 {
212         print_method_from_ip (ip);
213 }
214         
215 /* 
216  * mono_method_same_domain:
217  *
218  * Determine whenever two compiled methods are in the same domain, thus
219  * the address of the callee can be embedded in the caller.
220  */
221 gboolean mono_method_same_domain (MonoJitInfo *caller, MonoJitInfo *callee)
222 {
223         if (!caller || !callee)
224                 return FALSE;
225
226         /*
227          * If the call was made from domain-neutral to domain-specific 
228          * code, we can't patch the call site.
229          */
230         if (caller->domain_neutral && !callee->domain_neutral)
231                 return FALSE;
232
233         if ((caller->method->klass == mono_defaults.appdomain_class) &&
234                 (strstr (caller->method->name, "InvokeInDomain"))) {
235                  /* The InvokeInDomain methods change the current appdomain */
236                 return FALSE;
237         }
238
239         return TRUE;
240 }
241
242 MonoJumpInfoToken *
243 mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
244 {
245         MonoJumpInfoToken *res = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoToken));
246         res->image = image;
247         res->token = token;
248
249         return res;
250 }
251
252 #define MONO_INIT_VARINFO(vi,id) do { \
253         (vi)->range.first_use.pos.bid = 0xffff; \
254         (vi)->reg = -1; \
255         (vi)->idx = (id); \
256 } while (0)
257
258 /*
259  * Basic blocks have two numeric identifiers:
260  * dfn: Depth First Number
261  * block_num: unique ID assigned at bblock creation
262  */
263 #define NEW_BBLOCK(cfg) (mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock)))
264 #define ADD_BBLOCK(cfg,bbhash,b) do {   \
265                 g_hash_table_insert (bbhash, (b)->cil_code, (b));       \
266                 (b)->block_num = cfg->num_bblocks++;    \
267                 (b)->real_offset = real_offset; \
268         } while (0)
269
270 #define GET_BBLOCK(cfg,bbhash,tblock,ip) do {   \
271                 (tblock) = g_hash_table_lookup (bbhash, (ip));  \
272                 if (!(tblock)) {        \
273                         if ((ip) >= end || (ip) < header->code) goto unverified; \
274                         (tblock) = NEW_BBLOCK (cfg);    \
275                         (tblock)->cil_code = (ip);      \
276                         ADD_BBLOCK (cfg, (bbhash), (tblock));   \
277                 } \
278         } while (0)
279
280 #define CHECK_BBLOCK(target,ip,tblock) do {     \
281                 if ((target) < (ip) && !(tblock)->code) {       \
282                         bb_recheck = g_list_prepend (bb_recheck, (tblock));     \
283                         if (cfg->verbose_level > 2) g_print ("queued block %d for check at IL%04x from IL%04x\n", (tblock)->block_num, (int)((target) - header->code), (int)((ip) - header->code));     \
284                 }       \
285         } while (0)
286
287 #define NEW_ICONST(cfg,dest,val) do {   \
288                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
289                 (dest)->opcode = OP_ICONST;     \
290                 (dest)->inst_c0 = (val);        \
291                 (dest)->type = STACK_I4;        \
292         } while (0)
293
294 #if SIZEOF_VOID_P == 8
295 #define OP_PCONST OP_I8CONST
296 #else
297 #define OP_PCONST OP_ICONST
298 #endif
299
300 #define NEW_PCONST(cfg,dest,val) do {   \
301                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
302                 (dest)->opcode = OP_PCONST;     \
303                 (dest)->inst_p0 = (val);        \
304                 (dest)->type = STACK_PTR;       \
305         } while (0)
306
307
308 #ifdef MONO_ARCH_NEED_GOT_VAR
309
310 #define NEW_PATCH_INFO(cfg,dest,el1,el2) do {   \
311                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
312                 (dest)->opcode = OP_PATCH_INFO; \
313                 (dest)->inst_left = (gpointer)(el1);    \
314                 (dest)->inst_right = (gpointer)(el2);   \
315         } while (0)
316
317 #define NEW_AOTCONST(cfg,dest,patch_type,cons) do {    \
318                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
319                 (dest)->opcode = cfg->compile_aot ? OP_GOT_ENTRY : OP_PCONST;   \
320         if (cfg->compile_aot) { \
321             MonoInst *group, *got_var; \
322             NEW_TEMPLOAD ((cfg), got_var, mono_get_got_var (cfg)->inst_c0); \
323                     NEW_PATCH_INFO ((cfg), group, cons, patch_type); \
324             (dest)->inst_p0 = got_var; \
325             (dest)->inst_p1 = group; \
326         } else { \
327                      (dest)->inst_p0 = (cons);  \
328              (dest)->inst_i1 = (gpointer)(patch_type); \
329         } \
330                 (dest)->type = STACK_PTR;       \
331     } while (0)
332
333 #define NEW_AOTCONST_TOKEN(cfg,dest,patch_type,image,token,stack_type) do { \
334         MonoInst *group, *got_var; \
335                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
336                 (dest)->opcode = OP_GOT_ENTRY;  \
337         NEW_TEMPLOAD ((cfg), got_var, mono_get_got_var (cfg)->inst_c0); \
338                 NEW_PATCH_INFO ((cfg), group, NULL, patch_type); \
339         group->inst_p0 = mono_jump_info_token_new ((cfg)->mempool, (image), (token)); \
340         (dest)->inst_p0 = got_var; \
341         (dest)->inst_p1 = group; \
342                 (dest)->type = (stack_type);    \
343     } while (0)
344
345 #else
346
347 #define NEW_AOTCONST(cfg,dest,patch_type,cons) do {    \
348                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
349                 (dest)->opcode = cfg->compile_aot ? OP_AOTCONST : OP_PCONST;    \
350                 (dest)->inst_p0 = (cons);       \
351                 (dest)->inst_i1 = (gpointer)(patch_type); \
352                 (dest)->type = STACK_PTR;       \
353     } while (0)
354
355 #define NEW_AOTCONST_TOKEN(cfg,dest,patch_type,image,token,stack_type) do {    \
356                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
357                 (dest)->opcode = OP_AOTCONST;   \
358                 (dest)->inst_p0 = mono_jump_info_token_new ((cfg)->mempool, (image), (token));  \
359                 (dest)->inst_p1 = (gpointer)(patch_type); \
360                 (dest)->type = (stack_type);    \
361     } while (0)
362
363 #endif
364
365 #define NEW_CLASSCONST(cfg,dest,val) NEW_AOTCONST ((cfg), (dest), MONO_PATCH_INFO_CLASS, (val))
366
367 #define NEW_IMAGECONST(cfg,dest,val) NEW_AOTCONST ((cfg), (dest), MONO_PATCH_INFO_IMAGE, (val))
368
369 #define NEW_FIELDCONST(cfg,dest,val) NEW_AOTCONST ((cfg), (dest), MONO_PATCH_INFO_FIELD, (val))
370
371 #define NEW_METHODCONST(cfg,dest,val) NEW_AOTCONST ((cfg), (dest), MONO_PATCH_INFO_METHODCONST, (val))
372
373 #define NEW_VTABLECONST(cfg,dest,vtable) NEW_AOTCONST ((cfg), (dest), MONO_PATCH_INFO_VTABLE, cfg->compile_aot ? (gpointer)((vtable)->klass) : (vtable))
374
375 #define NEW_SFLDACONST(cfg,dest,val) NEW_AOTCONST ((cfg), (dest), MONO_PATCH_INFO_SFLDA, (val))
376
377 #define NEW_LDSTRCONST(cfg,dest,image,token) NEW_AOTCONST_TOKEN ((cfg), (dest), MONO_PATCH_INFO_LDSTR, (image), (token), STACK_OBJ)
378
379 #define NEW_TYPE_FROM_HANDLE_CONST(cfg,dest,image,token) NEW_AOTCONST_TOKEN ((cfg), (dest), MONO_PATCH_INFO_TYPE_FROM_HANDLE, (image), (token), STACK_OBJ)
380
381 #define NEW_LDTOKENCONST(cfg,dest,image,token) NEW_AOTCONST_TOKEN ((cfg), (dest), MONO_PATCH_INFO_LDTOKEN, (image), (token), STACK_PTR)
382
383 #define NEW_DOMAINCONST(cfg,dest) do { \
384                if (cfg->opt & MONO_OPT_SHARED) { \
385                        NEW_TEMPLOAD (cfg, dest, mono_get_domainvar (cfg)->inst_c0); \
386                } else { \
387                        NEW_PCONST (cfg, dest, (cfg)->domain); \
388                } \
389         } while (0)
390
391 #define GET_VARINFO_INST(cfg,num) ((cfg)->varinfo [(num)]->inst)
392
393 #define NEW_ARGLOAD(cfg,dest,num) do {  \
394                 if (arg_array [(num)]->opcode == OP_ICONST) (dest) = arg_array [(num)]; else { \
395                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
396                 (dest)->ssa_op = MONO_SSA_LOAD; \
397                 (dest)->inst_i0 = arg_array [(num)];    \
398                 (dest)->opcode = mono_type_to_ldind ((dest)->inst_i0->inst_vtype);      \
399                 type_to_eval_stack_type (param_types [(num)], (dest));  \
400                 (dest)->klass = (dest)->inst_i0->klass; \
401         }} while (0)
402
403 #define NEW_LOCLOAD(cfg,dest,num) do {  \
404                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
405                 (dest)->ssa_op = MONO_SSA_LOAD; \
406                 (dest)->inst_i0 = (cfg)->varinfo [locals_offset + (num)];       \
407                 (dest)->opcode = mono_type_to_ldind ((dest)->inst_i0->inst_vtype);      \
408                 type_to_eval_stack_type (header->locals [(num)], (dest));       \
409                 (dest)->klass = (dest)->inst_i0->klass; \
410         } while (0)
411
412 #define NEW_LOCLOADA(cfg,dest,num) do { \
413                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
414                 (dest)->ssa_op = MONO_SSA_MAYBE_LOAD;   \
415                 (dest)->inst_i0 = (cfg)->varinfo [locals_offset + (num)];       \
416                 (dest)->inst_i0->flags |= MONO_INST_INDIRECT;   \
417                 (dest)->opcode = OP_LDADDR;     \
418                 (dest)->type = STACK_MP;        \
419                 (dest)->klass = (dest)->inst_i0->klass; \
420         if (!MONO_TYPE_ISSTRUCT (header->locals [(num)])) \
421            (cfg)->disable_ssa = TRUE; \
422         } while (0)
423
424 #define NEW_RETLOADA(cfg,dest) do {     \
425                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
426                 (dest)->ssa_op = MONO_SSA_MAYBE_LOAD;   \
427                 (dest)->inst_i0 = (cfg)->ret;   \
428                 (dest)->inst_i0->flags |= MONO_INST_INDIRECT;   \
429                 (dest)->opcode = CEE_LDIND_I;   \
430                 (dest)->type = STACK_MP;        \
431                 (dest)->klass = (dest)->inst_i0->klass; \
432                 (cfg)->disable_ssa = TRUE; \
433         } while (0)
434
435 #define NEW_ARGLOADA(cfg,dest,num) do { \
436                 if (arg_array [(num)]->opcode == OP_ICONST) goto inline_failure; \
437                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
438                 (dest)->ssa_op = MONO_SSA_MAYBE_LOAD;   \
439                 (dest)->inst_i0 = arg_array [(num)];    \
440                 (dest)->inst_i0->flags |= MONO_INST_INDIRECT;   \
441                 (dest)->opcode = OP_LDADDR;     \
442                 (dest)->type = STACK_MP;        \
443                 (dest)->klass = (dest)->inst_i0->klass; \
444                 (cfg)->disable_ssa = TRUE; \
445         } while (0)
446
447 #define NEW_TEMPLOAD(cfg,dest,num) do { \
448                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
449                 (dest)->ssa_op = MONO_SSA_LOAD; \
450                 (dest)->inst_i0 = (cfg)->varinfo [(num)];       \
451                 (dest)->opcode = mono_type_to_ldind ((dest)->inst_i0->inst_vtype);      \
452                 type_to_eval_stack_type ((dest)->inst_i0->inst_vtype, (dest));  \
453                 (dest)->klass = (dest)->inst_i0->klass; \
454         } while (0)
455
456 #define NEW_TEMPLOADA(cfg,dest,num) do {        \
457                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
458                 (dest)->ssa_op = MONO_SSA_MAYBE_LOAD;   \
459                 (dest)->inst_i0 = (cfg)->varinfo [(num)];       \
460                 (dest)->inst_i0->flags |= MONO_INST_INDIRECT;   \
461                 (dest)->opcode = OP_LDADDR;     \
462                 (dest)->type = STACK_MP;        \
463                 (dest)->klass = (dest)->inst_i0->klass; \
464         if (!MONO_TYPE_ISSTRUCT (cfg->varinfo [(num)]->inst_vtype)) \
465            (cfg)->disable_ssa = TRUE; \
466         } while (0)
467
468
469 #define NEW_INDLOAD(cfg,dest,addr,vtype) do {   \
470                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
471                 (dest)->inst_left = addr;       \
472                 (dest)->opcode = mono_type_to_ldind (vtype);    \
473                 type_to_eval_stack_type (vtype, (dest));        \
474                 /* FIXME: (dest)->klass = (dest)->inst_i0->klass;*/     \
475         } while (0)
476
477 #define NEW_INDSTORE(cfg,dest,addr,value,vtype) do {    \
478                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
479                 (dest)->inst_i0 = addr; \
480                 (dest)->opcode = mono_type_to_stind (vtype);    \
481                 (dest)->inst_i1 = (value);      \
482                 /* FIXME: (dest)->klass = (dest)->inst_i0->klass;*/     \
483         } while (0)
484
485 #define NEW_TEMPSTORE(cfg,dest,num,inst) do {   \
486                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
487                 (dest)->ssa_op = MONO_SSA_STORE;        \
488                 (dest)->inst_i0 = (cfg)->varinfo [(num)];       \
489                 (dest)->opcode = mono_type_to_stind ((dest)->inst_i0->inst_vtype);      \
490                 (dest)->inst_i1 = (inst);       \
491                 (dest)->klass = (dest)->inst_i0->klass; \
492         } while (0)
493
494 #define NEW_LOCSTORE(cfg,dest,num,inst) do {    \
495                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
496                 (dest)->opcode = mono_type_to_stind (header->locals [(num)]);   \
497                 (dest)->ssa_op = MONO_SSA_STORE;        \
498                 (dest)->inst_i0 = (cfg)->varinfo [locals_offset + (num)];       \
499                 (dest)->inst_i1 = (inst);       \
500                 (dest)->klass = (dest)->inst_i0->klass; \
501         } while (0)
502
503 #define NEW_ARGSTORE(cfg,dest,num,inst) do {    \
504                 if (arg_array [(num)]->opcode == OP_ICONST) goto inline_failure; \
505                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
506                 (dest)->opcode = mono_type_to_stind (param_types [(num)]);      \
507                 (dest)->ssa_op = MONO_SSA_STORE;        \
508                 (dest)->inst_i0 = arg_array [(num)];    \
509                 (dest)->inst_i1 = (inst);       \
510                 (dest)->klass = (dest)->inst_i0->klass; \
511         } while (0)
512
513 #define NEW_DUMMY_USE(cfg,dest,load) do { \
514                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
515                 (dest)->opcode = OP_DUMMY_USE; \
516                 (dest)->inst_left = (load); \
517     } while (0)
518
519 #define ADD_BINOP(op) do {      \
520                 MONO_INST_NEW (cfg, ins, (op)); \
521                 ins->cil_code = ip;     \
522                 sp -= 2;        \
523                 ins->inst_i0 = sp [0];  \
524                 ins->inst_i1 = sp [1];  \
525                 *sp++ = ins;    \
526                 type_from_op (ins);     \
527                 CHECK_TYPE (ins);       \
528         } while (0)
529
530 #define ADD_UNOP(op) do {       \
531                 MONO_INST_NEW (cfg, ins, (op)); \
532                 ins->cil_code = ip;     \
533                 sp--;   \
534                 ins->inst_i0 = sp [0];  \
535                 *sp++ = ins;    \
536                 type_from_op (ins);     \
537                 CHECK_TYPE (ins);       \
538         } while (0)
539
540 #define ADD_BINCOND(next_block) do {    \
541                 MonoInst *cmp;  \
542                 sp -= 2;                \
543                 MONO_INST_NEW(cfg, cmp, OP_COMPARE);    \
544                 cmp->inst_i0 = sp [0];  \
545                 cmp->inst_i1 = sp [1];  \
546                 cmp->cil_code = ins->cil_code;  \
547                 type_from_op (cmp);     \
548                 CHECK_TYPE (cmp);       \
549                 ins->inst_i0 = cmp;     \
550                 MONO_ADD_INS (bblock, ins);     \
551                 ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);      \
552                 GET_BBLOCK (cfg, bbhash, tblock, target);               \
553                 link_bblock (cfg, bblock, tblock);      \
554                 ins->inst_true_bb = tblock;     \
555                 CHECK_BBLOCK (target, ip, tblock);      \
556                 if ((next_block)) {     \
557                         link_bblock (cfg, bblock, (next_block));        \
558                         ins->inst_false_bb = (next_block);      \
559                         start_new_bblock = 1;   \
560                 } else {        \
561                         GET_BBLOCK (cfg, bbhash, tblock, ip);           \
562                         link_bblock (cfg, bblock, tblock);      \
563                         ins->inst_false_bb = tblock;    \
564                         start_new_bblock = 2;   \
565                 }       \
566         } while (0)
567
568 /* FIXME: handle float, long ... */
569 #define ADD_UNCOND(istrue) do { \
570                 MonoInst *cmp;  \
571                 sp--;           \
572                 MONO_INST_NEW(cfg, cmp, OP_COMPARE);    \
573                 cmp->inst_i0 = sp [0];  \
574                 switch (cmp->inst_i0->type) { \
575                 case STACK_I8: \
576                         cmp->inst_i1 = zero_int64; break; \
577                 case STACK_R8: \
578                         cmp->inst_i1 = zero_r8; break; \
579                 case STACK_PTR: \
580                 case STACK_MP: \
581                         cmp->inst_i1 = zero_ptr; break; \
582                 case STACK_OBJ: \
583                         cmp->inst_i1 = zero_obj; break; \
584                 default: \
585                         cmp->inst_i1 = zero_int32;  \
586                 }  \
587                 cmp->cil_code = ins->cil_code;  \
588                 type_from_op (cmp);     \
589                 CHECK_TYPE (cmp);       \
590                 ins->inst_i0 = cmp;     \
591                 ins->opcode = (istrue)? CEE_BNE_UN: CEE_BEQ;    \
592                 MONO_ADD_INS (bblock, ins);     \
593                 ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);      \
594                 GET_BBLOCK (cfg, bbhash, tblock, target);               \
595                 link_bblock (cfg, bblock, tblock);      \
596                 ins->inst_true_bb = tblock;     \
597                 CHECK_BBLOCK (target, ip, tblock);      \
598                 GET_BBLOCK (cfg, bbhash, tblock, ip);           \
599                 link_bblock (cfg, bblock, tblock);      \
600                 ins->inst_false_bb = tblock;    \
601                 start_new_bblock = 2;   \
602         } while (0)
603
604 #define NEW_LDELEMA(cfg,dest,sp,k) do { \
605                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
606                 (dest)->opcode = CEE_LDELEMA;   \
607                 (dest)->inst_left = (sp) [0];   \
608                 (dest)->inst_right = (sp) [1];  \
609                 (dest)->type = STACK_MP;        \
610                 (dest)->klass = (k);    \
611                 (cfg)->flags |= MONO_CFG_HAS_LDELEMA; \
612         } while (0)
613
614 #define NEW_GROUP(cfg,dest,el1,el2) do {        \
615                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
616                 (dest)->opcode = OP_GROUP;      \
617                 (dest)->inst_left = (el1);      \
618                 (dest)->inst_right = (el2);     \
619         } while (0)
620
621 #if 0
622 static gint
623 compare_bblock (gconstpointer a, gconstpointer b)
624 {
625         const MonoBasicBlock *b1 = a;
626         const MonoBasicBlock *b2 = b;
627
628         return b2->cil_code - b1->cil_code;
629 }
630 #endif
631
632 /* *
633  * link_bblock: Links two basic blocks
634  *
635  * links two basic blocks in the control flow graph, the 'from'
636  * argument is the starting block and the 'to' argument is the block
637  * the control flow ends to after 'from'.
638  */
639 static void
640 link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
641 {
642         MonoBasicBlock **newa;
643         int i, found;
644
645 #if 0
646         if (from->cil_code) {
647                 if (to->cil_code)
648                         g_print ("edge from IL%04x to IL_%04x\n", from->cil_code - cfg->cil_code, to->cil_code - cfg->cil_code);
649                 else
650                         g_print ("edge from IL%04x to exit\n", from->cil_code - cfg->cil_code);
651         } else {
652                 if (to->cil_code)
653                         g_print ("edge from entry to IL_%04x\n", to->cil_code - cfg->cil_code);
654                 else
655                         g_print ("edge from entry to exit\n");
656         }
657 #endif
658         found = FALSE;
659         for (i = 0; i < from->out_count; ++i) {
660                 if (to == from->out_bb [i]) {
661                         found = TRUE;
662                         break;
663                 }
664         }
665         if (!found) {
666                 newa = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (from->out_count + 1));
667                 for (i = 0; i < from->out_count; ++i) {
668                         newa [i] = from->out_bb [i];
669                 }
670                 newa [i] = to;
671                 from->out_count++;
672                 from->out_bb = newa;
673         }
674
675         found = FALSE;
676         for (i = 0; i < to->in_count; ++i) {
677                 if (from == to->in_bb [i]) {
678                         found = TRUE;
679                         break;
680                 }
681         }
682         if (!found) {
683                 newa = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (to->in_count + 1));
684                 for (i = 0; i < to->in_count; ++i) {
685                         newa [i] = to->in_bb [i];
686                 }
687                 newa [i] = from;
688                 to->in_count++;
689                 to->in_bb = newa;
690         }
691 }
692
693 /**
694  * mono_find_block_region:
695  *
696  *   We mark each basic block with a region ID. We use that to avoid BB
697  *   optimizations when blocks are in different regions.
698  *
699  * Returns:
700  *   A region token that encodes where this region is, and information
701  *   about the clause owner for this block.
702  *
703  *   The region encodes the try/catch/filter clause that owns this block
704  *   as well as the type.  -1 is a special value that represents a block
705  *   that is in none of try/catch/filter.
706  */
707 static int
708 mono_find_block_region (MonoCompile *cfg, int offset, int *filter_lengths)
709 {
710         MonoMethod *method = cfg->method;
711         MonoMethodHeader *header = mono_method_get_header (method);
712         MonoExceptionClause *clause;
713         int i;
714
715         /* first search for handlers and filters */
716         for (i = 0; i < header->num_clauses; ++i) {
717                 clause = &header->clauses [i];
718                 if ((clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) && (offset >= clause->data.filter_offset) &&
719                     (offset < (clause->data.filter_offset + filter_lengths [i])))
720                         return ((i + 1) << 8) | MONO_REGION_FILTER | clause->flags;
721                            
722                 if (MONO_OFFSET_IN_HANDLER (clause, offset)) {
723                         if (clause->flags & MONO_EXCEPTION_CLAUSE_FINALLY)
724                                 return ((i + 1) << 8) | MONO_REGION_FINALLY | clause->flags;
725                         else
726                                 return ((i + 1) << 8) | MONO_REGION_CATCH | clause->flags;
727                 }
728         }
729
730         /* search the try blocks */
731         for (i = 0; i < header->num_clauses; ++i) {
732                 clause = &header->clauses [i];
733                 if (MONO_OFFSET_IN_CLAUSE (clause, offset))
734                         return ((i + 1) << 8) | clause->flags;
735         }
736
737         return -1;
738 }
739
740 static GList*
741 mono_find_final_block (MonoCompile *cfg, unsigned char *ip, unsigned char *target, int type)
742 {
743         MonoMethod *method = cfg->method;
744         MonoMethodHeader *header = mono_method_get_header (method);
745         MonoExceptionClause *clause;
746         MonoBasicBlock *handler;
747         int i;
748         GList *res = NULL;
749
750         for (i = 0; i < header->num_clauses; ++i) {
751                 clause = &header->clauses [i];
752                 if (MONO_OFFSET_IN_CLAUSE (clause, (ip - header->code)) && 
753                     (!MONO_OFFSET_IN_CLAUSE (clause, (target - header->code)))) {
754                         if (clause->flags == type) {
755                                 handler = g_hash_table_lookup (cfg->bb_hash, header->code + clause->handler_offset);
756                                 g_assert (handler);
757                                 res = g_list_append (res, handler);
758                         }
759                 }
760         }
761         return res;
762 }
763
764 MonoInst *
765 mono_find_spvar_for_region (MonoCompile *cfg, int region)
766 {
767         return g_hash_table_lookup (cfg->spvars, GINT_TO_POINTER (region));
768 }
769
770 static void
771 mono_create_spvar_for_region (MonoCompile *cfg, int region)
772 {
773         MonoInst *var;
774
775         var = g_hash_table_lookup (cfg->spvars, GINT_TO_POINTER (region));
776         if (var)
777                 return;
778
779         var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
780         /* prevent it from being register allocated */
781         var->flags |= MONO_INST_INDIRECT;
782
783         g_hash_table_insert (cfg->spvars, GINT_TO_POINTER (region), var);
784 }
785
786 static void
787 df_visit (MonoBasicBlock *start, int *dfn, MonoBasicBlock **array)
788 {
789         int i;
790
791         array [*dfn] = start;
792         /*g_print ("visit %d at %p\n", *dfn, start->cil_code);*/
793         for (i = 0; i < start->out_count; ++i) {
794                 if (start->out_bb [i]->dfn)
795                         continue;
796                 (*dfn)++;
797                 start->out_bb [i]->dfn = *dfn;
798                 start->out_bb [i]->df_parent = start;
799                 array [*dfn] = start->out_bb [i];
800                 df_visit (start->out_bb [i], dfn, array);
801         }
802 }
803
804 typedef struct {
805         const guchar *code;
806         MonoBasicBlock *best;
807 } PrevStruct;
808
809 static void
810 previous_foreach (gconstpointer key, gpointer val, gpointer data)
811 {
812         PrevStruct *p = data;
813         MonoBasicBlock *bb = val;
814         //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,
815         //bb->method == p->best->method, bb->cil_code < p->code, bb->cil_code > p->best->cil_code);
816
817         if (bb->cil_code && bb->cil_code < p->code && bb->cil_code > p->best->cil_code)
818                 p->best = bb;
819 }
820
821 static MonoBasicBlock*
822 find_previous (GHashTable *bb_hash, MonoBasicBlock *start, const guchar *code) {
823         PrevStruct p;
824
825         p.code = code;
826         p.best = start;
827
828         g_hash_table_foreach (bb_hash, (GHFunc)previous_foreach, &p);
829         return p.best;
830 }
831
832 static void
833 split_bblock (MonoCompile *cfg, MonoBasicBlock *first, MonoBasicBlock *second) {
834         int i, j;
835         MonoInst *inst;
836         MonoBasicBlock *bb;
837
838         if (second->code)
839                 return;
840         
841         /* 
842          * FIXME: take into account all the details:
843          * second may have been the target of more than one bblock
844          */
845         second->out_count = first->out_count;
846         second->out_bb = first->out_bb;
847
848         for (i = 0; i < first->out_count; ++i) {
849                 bb = first->out_bb [i];
850                 for (j = 0; j < bb->in_count; ++j) {
851                         if (bb->in_bb [j] == first)
852                                 bb->in_bb [j] = second;
853                 }
854         }
855
856         first->out_count = 0;
857         first->out_bb = NULL;
858         link_bblock (cfg, first, second);
859
860         second->last_ins = first->last_ins;
861
862         /*g_print ("start search at %p for %p\n", first->cil_code, second->cil_code);*/
863         for (inst = first->code; inst && inst->next; inst = inst->next) {
864                 /*char *code = mono_disasm_code_one (NULL, cfg->method, inst->next->cil_code, NULL);
865                 g_print ("found %p: %s", inst->next->cil_code, code);
866                 g_free (code);*/
867                 if (inst->cil_code < second->cil_code && inst->next->cil_code >= second->cil_code) {
868                         second->code = inst->next;
869                         inst->next = NULL;
870                         first->last_ins = inst;
871                         second->next_bb = first->next_bb;
872                         first->next_bb = second;
873                         return;
874                 }
875         }
876         if (!second->code) {
877                 g_warning ("bblock split failed in %s::%s\n", cfg->method->klass->name, cfg->method->name);
878                 //G_BREAKPOINT ();
879         }
880 }
881
882 static guint32
883 reverse_branch_op (guint32 opcode)
884 {
885         static const int reverse_map [] = {
886                 CEE_BNE_UN, CEE_BLT, CEE_BLE, CEE_BGT, CEE_BGE,
887                 CEE_BEQ, CEE_BLT_UN, CEE_BLE_UN, CEE_BGT_UN, CEE_BGE_UN
888         };
889         static const int reverse_fmap [] = {
890                 OP_FBNE_UN, OP_FBLT, OP_FBLE, OP_FBGT, OP_FBGE,
891                 OP_FBEQ, OP_FBLT_UN, OP_FBLE_UN, OP_FBGT_UN, OP_FBGE_UN
892         };
893         static const int reverse_lmap [] = {
894                 OP_LBNE_UN, OP_LBLT, OP_LBLE, OP_LBGT, OP_LBGE,
895                 OP_LBEQ, OP_LBLT_UN, OP_LBLE_UN, OP_LBGT_UN, OP_LBGE_UN
896         };
897         static const int reverse_imap [] = {
898                 OP_IBNE_UN, OP_IBLT, OP_IBLE, OP_IBGT, OP_IBGE,
899                 OP_IBEQ, OP_IBLT_UN, OP_IBLE_UN, OP_IBGT_UN, OP_IBGE_UN
900         };
901                                 
902         if (opcode >= CEE_BEQ && opcode <= CEE_BLT_UN) {
903                 opcode = reverse_map [opcode - CEE_BEQ];
904         } else if (opcode >= OP_FBEQ && opcode <= OP_FBLT_UN) {
905                 opcode = reverse_fmap [opcode - OP_FBEQ];
906         } else if (opcode >= OP_LBEQ && opcode <= OP_LBLT_UN) {
907                 opcode = reverse_lmap [opcode - OP_LBEQ];
908         } else if (opcode >= OP_IBEQ && opcode <= OP_IBLT_UN) {
909                 opcode = reverse_imap [opcode - OP_IBEQ];
910         } else
911                 g_assert_not_reached ();
912
913         return opcode;
914 }
915
916 guint
917 mono_type_to_ldind (MonoType *type)
918 {
919         if (type->byref)
920                 return CEE_LDIND_I;
921
922 handle_enum:
923         switch (type->type) {
924         case MONO_TYPE_I1:
925                 return CEE_LDIND_I1;
926         case MONO_TYPE_U1:
927         case MONO_TYPE_BOOLEAN:
928                 return CEE_LDIND_U1;
929         case MONO_TYPE_I2:
930                 return CEE_LDIND_I2;
931         case MONO_TYPE_U2:
932         case MONO_TYPE_CHAR:
933                 return CEE_LDIND_U2;
934         case MONO_TYPE_I4:
935                 return CEE_LDIND_I4;
936         case MONO_TYPE_U4:
937                 return CEE_LDIND_U4;
938         case MONO_TYPE_I:
939         case MONO_TYPE_U:
940         case MONO_TYPE_PTR:
941         case MONO_TYPE_FNPTR:
942                 return CEE_LDIND_I;
943         case MONO_TYPE_CLASS:
944         case MONO_TYPE_STRING:
945         case MONO_TYPE_OBJECT:
946         case MONO_TYPE_SZARRAY:
947         case MONO_TYPE_ARRAY:    
948                 return CEE_LDIND_REF;
949         case MONO_TYPE_I8:
950         case MONO_TYPE_U8:
951                 return CEE_LDIND_I8;
952         case MONO_TYPE_R4:
953                 return CEE_LDIND_R4;
954         case MONO_TYPE_R8:
955                 return CEE_LDIND_R8;
956         case MONO_TYPE_VALUETYPE:
957                 if (type->data.klass->enumtype) {
958                         type = type->data.klass->enum_basetype;
959                         goto handle_enum;
960                 }
961                 return CEE_LDOBJ;
962         case MONO_TYPE_TYPEDBYREF:
963                 return CEE_LDOBJ;
964         case MONO_TYPE_GENERICINST:
965                 type = &type->data.generic_class->container_class->byval_arg;
966                 goto handle_enum;
967         default:
968                 g_error ("unknown type 0x%02x in type_to_ldind", type->type);
969         }
970         return -1;
971 }
972
973 guint
974 mono_type_to_stind (MonoType *type)
975 {
976         if (type->byref)
977                 return CEE_STIND_I;
978
979 handle_enum:
980         switch (type->type) {
981         case MONO_TYPE_I1:
982         case MONO_TYPE_U1:
983         case MONO_TYPE_BOOLEAN:
984                 return CEE_STIND_I1;
985         case MONO_TYPE_I2:
986         case MONO_TYPE_U2:
987         case MONO_TYPE_CHAR:
988                 return CEE_STIND_I2;
989         case MONO_TYPE_I4:
990         case MONO_TYPE_U4:
991                 return CEE_STIND_I4;
992         case MONO_TYPE_I:
993         case MONO_TYPE_U:
994         case MONO_TYPE_PTR:
995         case MONO_TYPE_FNPTR:
996                 return CEE_STIND_I;
997         case MONO_TYPE_CLASS:
998         case MONO_TYPE_STRING:
999         case MONO_TYPE_OBJECT:
1000         case MONO_TYPE_SZARRAY:
1001         case MONO_TYPE_ARRAY:    
1002                 return CEE_STIND_REF;
1003         case MONO_TYPE_I8:
1004         case MONO_TYPE_U8:
1005                 return CEE_STIND_I8;
1006         case MONO_TYPE_R4:
1007                 return CEE_STIND_R4;
1008         case MONO_TYPE_R8:
1009                 return CEE_STIND_R8;
1010         case MONO_TYPE_VALUETYPE:
1011                 if (type->data.klass->enumtype) {
1012                         type = type->data.klass->enum_basetype;
1013                         goto handle_enum;
1014                 }
1015                 return CEE_STOBJ;
1016         case MONO_TYPE_TYPEDBYREF:
1017                 return CEE_STOBJ;
1018         case MONO_TYPE_GENERICINST:
1019                 type = &type->data.generic_class->container_class->byval_arg;
1020                 goto handle_enum;
1021         default:
1022                 g_error ("unknown type 0x%02x in type_to_stind", type->type);
1023         }
1024         return -1;
1025 }
1026
1027 /*
1028  * Returns the type used in the eval stack when @type is loaded.
1029  * FIXME: return a MonoType/MonoClass for the byref and VALUETYPE cases.
1030  */
1031 static void
1032 type_to_eval_stack_type (MonoType *type, MonoInst *inst)
1033 {
1034         MonoClass *klass;
1035
1036         if (type->byref) {
1037                 inst->type = STACK_MP;
1038                 return;
1039         }
1040
1041         klass = mono_class_from_mono_type (type);
1042
1043 handle_enum:
1044         switch (type->type) {
1045         case MONO_TYPE_VOID:
1046                 inst->type = STACK_INV;
1047                 return;
1048         case MONO_TYPE_I1:
1049         case MONO_TYPE_U1:
1050         case MONO_TYPE_BOOLEAN:
1051         case MONO_TYPE_I2:
1052         case MONO_TYPE_U2:
1053         case MONO_TYPE_CHAR:
1054         case MONO_TYPE_I4:
1055         case MONO_TYPE_U4:
1056                 inst->type = STACK_I4;
1057                 return;
1058         case MONO_TYPE_I:
1059         case MONO_TYPE_U:
1060         case MONO_TYPE_PTR:
1061         case MONO_TYPE_FNPTR:
1062                 inst->type = STACK_PTR;
1063                 return;
1064         case MONO_TYPE_CLASS:
1065         case MONO_TYPE_STRING:
1066         case MONO_TYPE_OBJECT:
1067         case MONO_TYPE_SZARRAY:
1068         case MONO_TYPE_ARRAY:    
1069                 inst->type = STACK_OBJ;
1070                 return;
1071         case MONO_TYPE_I8:
1072         case MONO_TYPE_U8:
1073                 inst->type = STACK_I8;
1074                 return;
1075         case MONO_TYPE_R4:
1076         case MONO_TYPE_R8:
1077                 inst->type = STACK_R8;
1078                 return;
1079         case MONO_TYPE_VALUETYPE:
1080                 if (type->data.klass->enumtype) {
1081                         type = type->data.klass->enum_basetype;
1082                         goto handle_enum;
1083                 } else {
1084                         inst->klass = klass;
1085                         inst->type = STACK_VTYPE;
1086                         return;
1087                 }
1088         case MONO_TYPE_TYPEDBYREF:
1089                 inst->klass = mono_defaults.typed_reference_class;
1090                 inst->type = STACK_VTYPE;
1091                 return;
1092         case MONO_TYPE_GENERICINST:
1093                 type = &type->data.generic_class->container_class->byval_arg;
1094                 goto handle_enum;
1095         default:
1096                 g_error ("unknown type 0x%02x in eval stack type", type->type);
1097         }
1098 }
1099
1100 /*
1101  * The following tables are used to quickly validate the IL code in type_from_op ().
1102  */
1103 static const char
1104 bin_num_table [STACK_MAX] [STACK_MAX] = {
1105         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1106         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
1107         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1108         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
1109         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_R8,  STACK_INV, STACK_INV, STACK_INV},
1110         {STACK_INV, STACK_MP,  STACK_INV, STACK_MP,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV},
1111         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1112         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
1113 };
1114
1115 static const char 
1116 neg_table [] = {
1117         STACK_INV, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_INV, STACK_INV, STACK_INV
1118 };
1119
1120 /* reduce the size of this table */
1121 static const char
1122 bin_int_table [STACK_MAX] [STACK_MAX] = {
1123         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1124         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1125         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1126         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1127         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1128         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1129         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1130         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
1131 };
1132
1133 static const char
1134 bin_comp_table [STACK_MAX] [STACK_MAX] = {
1135         {0},
1136         {0, 1, 0, 1, 0, 0, 4, 0},
1137         {0, 0, 1, 0, 0, 0, 0, 0},
1138         {0, 1, 0, 1, 0, 2, 4, 0},
1139         {0, 0, 0, 0, 1, 0, 0, 0},
1140         {0, 0, 0, 2, 0, 1, 0, 0},
1141         {0, 4, 0, 4, 0, 0, 3, 0},
1142         {0, 0, 0, 0, 0, 0, 0, 0},
1143 };
1144
1145 /* reduce the size of this table */
1146 static const char
1147 shift_table [STACK_MAX] [STACK_MAX] = {
1148         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1149         {STACK_INV, STACK_I4,  STACK_INV, STACK_I4,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1150         {STACK_INV, STACK_I8,  STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1151         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1152         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1153         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1154         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1155         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
1156 };
1157
1158 /*
1159  * Tables to map from the non-specific opcode to the matching
1160  * type-specific opcode.
1161  */
1162 /* handles from CEE_ADD to CEE_SHR_UN (CEE_REM_UN for floats) */
1163 static const guint16
1164 binops_op_map [STACK_MAX] = {
1165         0, 0, OP_LADD-CEE_ADD, OP_PADD-CEE_ADD, OP_FADD-CEE_ADD, OP_PADD-CEE_ADD
1166 };
1167
1168 /* handles from CEE_NEG to CEE_CONV_U8 */
1169 static const guint16
1170 unops_op_map [STACK_MAX] = {
1171         0, 0, OP_LNEG-CEE_NEG, OP_PNEG-CEE_NEG, OP_FNEG-CEE_NEG, OP_PNEG-CEE_NEG
1172 };
1173
1174 /* handles from CEE_CONV_U2 to CEE_SUB_OVF_UN */
1175 static const guint16
1176 ovfops_op_map [STACK_MAX] = {
1177         0, 0, OP_LCONV_TO_U2-CEE_CONV_U2, OP_PCONV_TO_U2-CEE_CONV_U2, OP_FCONV_TO_U2-CEE_CONV_U2, OP_PCONV_TO_U2-CEE_CONV_U2, OP_PCONV_TO_U2-CEE_CONV_U2
1178 };
1179
1180 /* handles from CEE_CONV_OVF_I1_UN to CEE_CONV_OVF_U_UN */
1181 static const guint16
1182 ovf2ops_op_map [STACK_MAX] = {
1183         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, OP_PCONV_TO_OVF_I1_UN-CEE_CONV_OVF_I1_UN
1184 };
1185
1186 /* handles from CEE_CONV_OVF_I1 to CEE_CONV_OVF_U8 */
1187 static const guint16
1188 ovf3ops_op_map [STACK_MAX] = {
1189         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, OP_PCONV_TO_OVF_I1-CEE_CONV_OVF_I1
1190 };
1191
1192 /* handles from CEE_CEQ to CEE_CLT_UN */
1193 static const guint16
1194 ceqops_op_map [STACK_MAX] = {
1195         0, 0, OP_LCEQ-CEE_CEQ, OP_PCEQ-CEE_CEQ, OP_FCEQ-CEE_CEQ, OP_LCEQ-CEE_CEQ
1196 };
1197
1198 /*
1199  * Sets ins->type (the type on the eval stack) according to the
1200  * type of the opcode and the arguments to it.
1201  * Invalid IL code is marked by setting ins->type to the invalid value STACK_INV.
1202  *
1203  * FIXME: this function sets ins->type unconditionally in some cases, but
1204  * it should set it to invalid for some types (a conv.x on an object)
1205  */
1206 static void
1207 type_from_op (MonoInst *ins) {
1208         switch (ins->opcode) {
1209         /* binops */
1210         case CEE_ADD:
1211         case CEE_SUB:
1212         case CEE_MUL:
1213         case CEE_DIV:
1214         case CEE_REM:
1215                 /* FIXME: check unverifiable args for STACK_MP */
1216                 ins->type = bin_num_table [ins->inst_i0->type] [ins->inst_i1->type];
1217                 ins->opcode += binops_op_map [ins->type];
1218                 return;
1219         case CEE_DIV_UN:
1220         case CEE_REM_UN:
1221         case CEE_AND:
1222         case CEE_OR:
1223         case CEE_XOR:
1224                 ins->type = bin_int_table [ins->inst_i0->type] [ins->inst_i1->type];
1225                 ins->opcode += binops_op_map [ins->type];
1226                 return;
1227         case CEE_SHL:
1228         case CEE_SHR:
1229         case CEE_SHR_UN:
1230                 ins->type = shift_table [ins->inst_i0->type] [ins->inst_i1->type];
1231                 ins->opcode += binops_op_map [ins->type];
1232                 return;
1233         case OP_COMPARE:
1234         case OP_LCOMPARE:
1235                 /* FIXME: handle some specifics with ins->next->type */
1236                 ins->type = bin_comp_table [ins->inst_i0->type] [ins->inst_i1->type] ? STACK_I4: STACK_INV;
1237                 if ((ins->inst_i0->type == STACK_I8) || ((sizeof (gpointer) == 8) && ((ins->inst_i0->type == STACK_PTR) || (ins->inst_i0->type == STACK_OBJ) || (ins->inst_i0->type == STACK_MP))))
1238                         ins->opcode = OP_LCOMPARE;
1239                 return;
1240         case OP_CEQ:
1241         case OP_CGT:
1242         case OP_CGT_UN:
1243         case OP_CLT:
1244         case OP_CLT_UN:
1245                 ins->type = bin_comp_table [ins->inst_i0->type] [ins->inst_i1->type] ? STACK_I4: STACK_INV;
1246                 ins->opcode += ceqops_op_map [ins->inst_i0->type];
1247                 return;
1248         /* unops */
1249         case CEE_NEG:
1250                 ins->type = neg_table [ins->inst_i0->type];
1251                 ins->opcode += unops_op_map [ins->type];
1252                 return;
1253         case CEE_NOT:
1254                 if (ins->inst_i0->type >= STACK_I4 && ins->inst_i0->type <= STACK_PTR)
1255                         ins->type = ins->inst_i0->type;
1256                 else
1257                         ins->type = STACK_INV;
1258                 ins->opcode += unops_op_map [ins->type];
1259                 return;
1260         case CEE_CONV_I1:
1261         case CEE_CONV_I2:
1262         case CEE_CONV_I4:
1263         case CEE_CONV_U4:
1264                 ins->type = STACK_I4;
1265                 ins->opcode += unops_op_map [ins->inst_i0->type];
1266                 return;
1267         case CEE_CONV_R_UN:
1268                 ins->type = STACK_R8;
1269                 switch (ins->inst_i0->type) {
1270                 case STACK_I4:
1271                 case STACK_PTR:
1272                         break;
1273                 case STACK_I8:
1274                         ins->opcode = OP_LCONV_TO_R_UN; 
1275                         break;
1276                 }
1277                 return;
1278         case CEE_CONV_OVF_I1:
1279         case CEE_CONV_OVF_U1:
1280         case CEE_CONV_OVF_I2:
1281         case CEE_CONV_OVF_U2:
1282         case CEE_CONV_OVF_I4:
1283         case CEE_CONV_OVF_U4:
1284                 ins->type = STACK_I4;
1285                 ins->opcode += ovf3ops_op_map [ins->inst_i0->type];
1286                 return;
1287         case CEE_CONV_OVF_I_UN:
1288         case CEE_CONV_OVF_U_UN:
1289                 ins->type = STACK_PTR;
1290                 ins->opcode += ovf2ops_op_map [ins->inst_i0->type];
1291                 return;
1292         case CEE_CONV_OVF_I1_UN:
1293         case CEE_CONV_OVF_I2_UN:
1294         case CEE_CONV_OVF_I4_UN:
1295         case CEE_CONV_OVF_U1_UN:
1296         case CEE_CONV_OVF_U2_UN:
1297         case CEE_CONV_OVF_U4_UN:
1298                 ins->type = STACK_I4;
1299                 ins->opcode += ovf2ops_op_map [ins->inst_i0->type];
1300                 return;
1301         case CEE_CONV_U:
1302                 ins->type = STACK_PTR;
1303                 switch (ins->inst_i0->type) {
1304                 case STACK_I4:
1305                 case STACK_PTR:
1306                 case STACK_MP:
1307                         break;
1308                 case STACK_I8:
1309                         ins->opcode = OP_LCONV_TO_U;
1310                         break;
1311                 case STACK_R8:
1312                         ins->opcode = OP_FCONV_TO_U;
1313                         break;
1314                 }
1315                 return;
1316         case CEE_CONV_I8:
1317         case CEE_CONV_U8:
1318                 ins->type = STACK_I8;
1319                 ins->opcode += unops_op_map [ins->inst_i0->type];
1320                 return;
1321         case CEE_CONV_OVF_I8:
1322         case CEE_CONV_OVF_U8:
1323                 ins->type = STACK_I8;
1324                 ins->opcode += ovf3ops_op_map [ins->inst_i0->type];
1325                 return;
1326         case CEE_CONV_OVF_U8_UN:
1327         case CEE_CONV_OVF_I8_UN:
1328                 ins->type = STACK_I8;
1329                 ins->opcode += ovf2ops_op_map [ins->inst_i0->type];
1330                 return;
1331         case CEE_CONV_R4:
1332         case CEE_CONV_R8:
1333                 ins->type = STACK_R8;
1334                 ins->opcode += unops_op_map [ins->inst_i0->type];
1335                 return;
1336         case CEE_CKFINITE:
1337                 ins->type = STACK_R8;           
1338                 return;
1339         case CEE_CONV_U2:
1340         case CEE_CONV_U1:
1341                 ins->type = STACK_I4;
1342                 ins->opcode += ovfops_op_map [ins->inst_i0->type];
1343                 break;
1344         case CEE_CONV_I:
1345         case CEE_CONV_OVF_I:
1346         case CEE_CONV_OVF_U:
1347                 ins->type = STACK_PTR;
1348                 ins->opcode += ovfops_op_map [ins->inst_i0->type];
1349                 return;
1350         case CEE_ADD_OVF:
1351         case CEE_ADD_OVF_UN:
1352         case CEE_MUL_OVF:
1353         case CEE_MUL_OVF_UN:
1354         case CEE_SUB_OVF:
1355         case CEE_SUB_OVF_UN:
1356                 ins->type = bin_num_table [ins->inst_i0->type] [ins->inst_i1->type];
1357                 ins->opcode += ovfops_op_map [ins->inst_i0->type];
1358                 return;
1359         default:
1360                 g_error ("opcode 0x%04x not handled in type from op", ins->opcode);
1361                 break;
1362         }
1363 }
1364
1365 static const char 
1366 ldind_type [] = {
1367         STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I8, STACK_MP, STACK_R8, STACK_R8, STACK_OBJ
1368 };
1369
1370 /* map ldelem.x to the matching ldind.x opcode */
1371 static const guchar
1372 ldelem_to_ldind [] = {
1373         CEE_LDIND_I1,
1374         CEE_LDIND_U1,
1375         CEE_LDIND_I2,
1376         CEE_LDIND_U2,
1377         CEE_LDIND_I4,
1378         CEE_LDIND_U4,
1379         CEE_LDIND_I8,
1380         CEE_LDIND_I,
1381         CEE_LDIND_R4,
1382         CEE_LDIND_R8,
1383         CEE_LDIND_REF
1384 };
1385
1386 /* map stelem.x to the matching stind.x opcode */
1387 static const guchar
1388 stelem_to_stind [] = {
1389         CEE_STIND_I,
1390         CEE_STIND_I1,
1391         CEE_STIND_I2,
1392         CEE_STIND_I4,
1393         CEE_STIND_I8,
1394         CEE_STIND_R4,
1395         CEE_STIND_R8,
1396         CEE_STIND_REF
1397 };
1398
1399 #if 0
1400
1401 static const char
1402 param_table [STACK_MAX] [STACK_MAX] = {
1403         {0},
1404 };
1405
1406 static int
1407 check_values_to_signature (MonoInst *args, MonoType *this, MonoMethodSignature *sig) {
1408         int i;
1409
1410         if (sig->hasthis) {
1411                 switch (args->type) {
1412                 case STACK_I4:
1413                 case STACK_I8:
1414                 case STACK_R8:
1415                 case STACK_VTYPE:
1416                 case STACK_INV:
1417                         return 0;
1418                 }
1419                 args++;
1420         }
1421         for (i = 0; i < sig->param_count; ++i) {
1422                 switch (args [i].type) {
1423                 case STACK_INV:
1424                         return 0;
1425                 case STACK_MP:
1426                         if (!sig->params [i]->byref)
1427                                 return 0;
1428                         continue;
1429                 case STACK_OBJ:
1430                         if (sig->params [i]->byref)
1431                                 return 0;
1432                         switch (sig->params [i]->type) {
1433                         case MONO_TYPE_CLASS:
1434                         case MONO_TYPE_STRING:
1435                         case MONO_TYPE_OBJECT:
1436                         case MONO_TYPE_SZARRAY:
1437                         case MONO_TYPE_ARRAY:
1438                                 break;
1439                         default:
1440                                 return 0;
1441                         }
1442                         continue;
1443                 case STACK_R8:
1444                         if (sig->params [i]->byref)
1445                                 return 0;
1446                         if (sig->params [i]->type != MONO_TYPE_R4 && sig->params [i]->type != MONO_TYPE_R8)
1447                                 return 0;
1448                         continue;
1449                 case STACK_PTR:
1450                 case STACK_I4:
1451                 case STACK_I8:
1452                 case STACK_VTYPE:
1453                         break;
1454                 }
1455                 /*if (!param_table [args [i].type] [sig->params [i]->type])
1456                         return 0;*/
1457         }
1458         return 1;
1459 }
1460 #endif
1461
1462 /*
1463  * When we need a pointer to the current domain many times in a method, we
1464  * call mono_domain_get() once and we store the result in a local variable.
1465  * This function returns the variable that represents the MonoDomain*.
1466  */
1467 inline static MonoInst *
1468 mono_get_domainvar (MonoCompile *cfg)
1469 {
1470         if (!cfg->domainvar)
1471                 cfg->domainvar = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1472         return cfg->domainvar;
1473 }
1474
1475 /*
1476  * The got_var contains the address of the Global Offset Table when AOT 
1477  * compiling.
1478  */
1479 inline static MonoInst *
1480 mono_get_got_var (MonoCompile *cfg)
1481 {
1482 #ifdef MONO_ARCH_NEED_GOT_VAR
1483         if (!cfg->compile_aot)
1484                 return NULL;
1485         if (!cfg->got_var) {
1486                 cfg->got_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1487         }
1488         return cfg->got_var;
1489 #else
1490         return NULL;
1491 #endif
1492 }
1493
1494 MonoInst*
1495 mono_compile_create_var (MonoCompile *cfg, MonoType *type, int opcode)
1496 {
1497         MonoInst *inst;
1498         int num = cfg->num_varinfo;
1499
1500         if ((num + 1) >= cfg->varinfo_count) {
1501                 cfg->varinfo_count = (cfg->varinfo_count + 2) * 2;
1502                 cfg->varinfo = (MonoInst **)g_realloc (cfg->varinfo, sizeof (MonoInst*) * cfg->varinfo_count);
1503                 cfg->vars = (MonoMethodVar **)g_realloc (cfg->vars, sizeof (MonoMethodVar*) * cfg->varinfo_count);      
1504         }
1505
1506         /*g_print ("created temp %d of type 0x%x\n", num, type->type);*/
1507         mono_jit_stats.allocate_var++;
1508
1509         MONO_INST_NEW (cfg, inst, opcode);
1510         inst->inst_c0 = num;
1511         inst->inst_vtype = type;
1512         inst->klass = mono_class_from_mono_type (type);
1513         /* if set to 1 the variable is native */
1514         inst->unused = 0;
1515
1516         cfg->varinfo [num] = inst;
1517
1518         cfg->vars [num] = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoMethodVar));
1519         MONO_INIT_VARINFO (cfg->vars [num], num);
1520
1521         cfg->num_varinfo++;
1522         //g_print ("created temp %d of type %s\n", num, mono_type_get_name (type));
1523         return inst;
1524 }
1525
1526 /*
1527  * Transform a MonoInst into a load from the variable of index var_index.
1528  */
1529 void
1530 mono_compile_make_var_load (MonoCompile *cfg, MonoInst *dest, gssize var_index) {
1531         memset (dest, 0, sizeof (MonoInst));
1532         dest->ssa_op = MONO_SSA_LOAD;
1533         dest->inst_i0 = cfg->varinfo [var_index];
1534         dest->opcode = mono_type_to_ldind (dest->inst_i0->inst_vtype);
1535         type_to_eval_stack_type (dest->inst_i0->inst_vtype, dest);
1536         dest->klass = dest->inst_i0->klass;
1537 }
1538
1539 /*
1540  * Create a MonoInst that is a load from the variable of index var_index.
1541  */
1542 MonoInst*
1543 mono_compile_create_var_load (MonoCompile *cfg, gssize var_index) {
1544         MonoInst *dest;
1545         NEW_TEMPLOAD (cfg,dest,var_index);
1546         return dest;
1547 }
1548
1549 /*
1550  * Create a MonoInst that is a store of the given value into the variable of index var_index.
1551  */
1552 MonoInst*
1553 mono_compile_create_var_store (MonoCompile *cfg, gssize var_index, MonoInst *value) {
1554         MonoInst *dest;
1555         NEW_TEMPSTORE (cfg, dest, var_index, value);
1556         return dest;
1557 }
1558
1559 static MonoType*
1560 type_from_stack_type (MonoInst *ins) {
1561         switch (ins->type) {
1562         case STACK_I4: return &mono_defaults.int32_class->byval_arg;
1563         case STACK_I8: return &mono_defaults.int64_class->byval_arg;
1564         case STACK_PTR: return &mono_defaults.int_class->byval_arg;
1565         case STACK_R8: return &mono_defaults.double_class->byval_arg;
1566         case STACK_MP: return &mono_defaults.int_class->byval_arg;
1567         case STACK_OBJ: return &mono_defaults.object_class->byval_arg;
1568         case STACK_VTYPE: return &ins->klass->byval_arg;
1569         default:
1570                 g_error ("stack type %d to montype not handled\n", ins->type);
1571         }
1572         return NULL;
1573 }
1574
1575 MonoType*
1576 mono_type_from_stack_type (MonoInst *ins) {
1577         return type_from_stack_type (ins);
1578 }
1579
1580 static MonoClass*
1581 array_access_to_klass (int opcode)
1582 {
1583         switch (opcode) {
1584         case CEE_LDELEM_U1:
1585                 return mono_defaults.byte_class;
1586         case CEE_LDELEM_U2:
1587                 return mono_defaults.uint16_class;
1588         case CEE_LDELEM_I:
1589         case CEE_STELEM_I:
1590                 return mono_defaults.int_class;
1591         case CEE_LDELEM_I1:
1592         case CEE_STELEM_I1:
1593                 return mono_defaults.sbyte_class;
1594         case CEE_LDELEM_I2:
1595         case CEE_STELEM_I2:
1596                 return mono_defaults.int16_class;
1597         case CEE_LDELEM_I4:
1598         case CEE_STELEM_I4:
1599                 return mono_defaults.int32_class;
1600         case CEE_LDELEM_U4:
1601                 return mono_defaults.uint32_class;
1602         case CEE_LDELEM_I8:
1603         case CEE_STELEM_I8:
1604                 return mono_defaults.int64_class;
1605         case CEE_LDELEM_R4:
1606         case CEE_STELEM_R4:
1607                 return mono_defaults.single_class;
1608         case CEE_LDELEM_R8:
1609         case CEE_STELEM_R8:
1610                 return mono_defaults.double_class;
1611         case CEE_LDELEM_REF:
1612         case CEE_STELEM_REF:
1613                 return mono_defaults.object_class;
1614         default:
1615                 g_assert_not_reached ();
1616         }
1617         return NULL;
1618 }
1619
1620 void
1621 mono_add_ins_to_end (MonoBasicBlock *bb, MonoInst *inst)
1622 {
1623         MonoInst *prev;
1624         if (!bb->code) {
1625                 MONO_ADD_INS (bb, inst);
1626                 return;
1627         }
1628         switch (bb->last_ins->opcode) {
1629         case CEE_BEQ:
1630         case CEE_BGE:
1631         case CEE_BGT:
1632         case CEE_BLE:
1633         case CEE_BLT:
1634         case CEE_BNE_UN:
1635         case CEE_BGE_UN:
1636         case CEE_BGT_UN:
1637         case CEE_BLE_UN:
1638         case CEE_BLT_UN:
1639         case CEE_BR:
1640         case CEE_SWITCH:
1641                 prev = bb->code;
1642                 while (prev->next && prev->next != bb->last_ins)
1643                         prev = prev->next;
1644                 if (prev == bb->code) {
1645                         if (bb->last_ins == bb->code) {
1646                                 inst->next = bb->code;
1647                                 bb->code = inst;
1648                         } else {
1649                                 inst->next = prev->next;
1650                                 prev->next = inst;
1651                         }
1652                 } else {
1653                         inst->next = bb->last_ins;
1654                         prev->next = inst;
1655                 }
1656                 break;
1657         //      g_warning ("handle conditional jump in add_ins_to_end ()\n");
1658         default:
1659                 MONO_ADD_INS (bb, inst);
1660                 break;
1661         }
1662 }
1663
1664 void
1665 mono_add_varcopy_to_end (MonoCompile *cfg, MonoBasicBlock *bb, int src, int dest)
1666 {
1667         MonoInst *inst, *load;
1668
1669         NEW_TEMPLOAD (cfg, load, src);
1670
1671         NEW_TEMPSTORE (cfg, inst, dest, load);
1672         if (inst->opcode == CEE_STOBJ) {
1673                 NEW_TEMPLOADA (cfg, inst, dest);
1674                 handle_stobj (cfg, bb, inst, load, NULL, inst->klass, TRUE, FALSE);
1675         } else {
1676                 inst->cil_code = NULL;
1677                 mono_add_ins_to_end (bb, inst);
1678         }
1679 }
1680
1681 /*
1682  * We try to share variables when possible
1683  */
1684 static MonoInst *
1685 mono_compile_get_interface_var (MonoCompile *cfg, int slot, MonoInst *ins)
1686 {
1687         MonoInst *res;
1688         int pos, vnum;
1689
1690         /* inlining can result in deeper stacks */ 
1691         if (slot >= mono_method_get_header (cfg->method)->max_stack)
1692                 return mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1693
1694         pos = ins->type - 1 + slot * STACK_MAX;
1695
1696         switch (ins->type) {
1697         case STACK_I4:
1698         case STACK_I8:
1699         case STACK_R8:
1700         case STACK_PTR:
1701         case STACK_MP:
1702         case STACK_OBJ:
1703                 if ((vnum = cfg->intvars [pos]))
1704                         return cfg->varinfo [vnum];
1705                 res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1706                 cfg->intvars [pos] = res->inst_c0;
1707                 break;
1708         default:
1709                 res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1710         }
1711         return res;
1712 }
1713
1714 /*
1715  * This function is called to handle items that are left on the evaluation stack
1716  * at basic block boundaries. What happens is that we save the values to local variables
1717  * and we reload them later when first entering the target basic block (with the
1718  * handle_loaded_temps () function).
1719  * It is also used to handle items on the stack in store opcodes, since it is
1720  * possible that the variable to be stored into is already on the stack, in
1721  * which case its old value should be used.
1722  * A single joint point will use the same variables (stored in the array bb->out_stack or
1723  * bb->in_stack, if the basic block is before or after the joint point).
1724  */
1725 static int
1726 handle_stack_args (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst **sp, int count) {
1727         int i, bindex;
1728         MonoBasicBlock *outb;
1729         MonoInst *inst, **locals;
1730         gboolean found;
1731
1732         if (!count)
1733                 return 0;
1734         if (cfg->verbose_level > 3)
1735                 g_print ("%d item(s) on exit from B%d\n", count, bb->block_num);
1736         if (!bb->out_scount) {
1737                 bb->out_scount = count;
1738                 //g_print ("bblock %d has out:", bb->block_num);
1739                 found = FALSE;
1740                 for (i = 0; i < bb->out_count; ++i) {
1741                         outb = bb->out_bb [i];
1742                         //g_print (" %d", outb->block_num);
1743                         if (outb->in_stack) {
1744                                 found = TRUE;
1745                                 bb->out_stack = outb->in_stack;
1746                                 break;
1747                         }
1748                 }
1749                 //g_print ("\n");
1750                 if (!found) {
1751                         bb->out_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * count);
1752                         for (i = 0; i < count; ++i) {
1753                                 /* 
1754                                  * try to reuse temps already allocated for this purpouse, if they occupy the same
1755                                  * stack slot and if they are of the same type.
1756                                  * This won't cause conflicts since if 'local' is used to 
1757                                  * store one of the values in the in_stack of a bblock, then
1758                                  * the same variable will be used for the same outgoing stack 
1759                                  * slot as well. 
1760                                  * This doesn't work when inlining methods, since the bblocks
1761                                  * in the inlined methods do not inherit their in_stack from
1762                                  * the bblock they are inlined to. See bug #58863 for an
1763                                  * example.
1764                                  */
1765                                 if (cfg->inlined_method)
1766                                         bb->out_stack [i] = mono_compile_create_var (cfg, type_from_stack_type (sp [i]), OP_LOCAL);
1767                                 else
1768                                         bb->out_stack [i] = mono_compile_get_interface_var (cfg, i, sp [i]);
1769                         }
1770                 }
1771         }
1772
1773         for (i = 0; i < bb->out_count; ++i) {
1774                 outb = bb->out_bb [i];
1775                 if (outb->in_scount)
1776                         continue; /* check they are the same locals */
1777                 outb->in_scount = count;
1778                 outb->in_stack = bb->out_stack;
1779         }
1780
1781         locals = bb->out_stack;
1782         for (i = 0; i < count; ++i) {
1783                 /* add store ops at the end of the bb, before the branch */
1784                 NEW_TEMPSTORE (cfg, inst, locals [i]->inst_c0, sp [i]);
1785                 if (inst->opcode == CEE_STOBJ) {
1786                         NEW_TEMPLOADA (cfg, inst, locals [i]->inst_c0);
1787                         handle_stobj (cfg, bb, inst, sp [i], sp [i]->cil_code, inst->klass, TRUE, FALSE);
1788                 } else {
1789                         inst->cil_code = sp [i]->cil_code;
1790                         mono_add_ins_to_end (bb, inst);
1791                 }
1792                 if (cfg->verbose_level > 3)
1793                         g_print ("storing %d to temp %d\n", i, (int)locals [i]->inst_c0);
1794         }
1795
1796         /*
1797          * It is possible that the out bblocks already have in_stack assigned, and
1798          * the in_stacks differ. In this case, we will store to all the different 
1799          * in_stacks.
1800          */
1801
1802         found = TRUE;
1803         bindex = 0;
1804         while (found) {
1805                 /* Find a bblock which has a different in_stack */
1806                 found = FALSE;
1807                 while (bindex < bb->out_count) {
1808                         outb = bb->out_bb [bindex];
1809                         if (outb->in_stack != locals) {
1810                                 /* 
1811                                  * Instead of storing sp [i] to locals [i], we need to store
1812                                  * locals [i] to <new locals>[i], since the sp [i] tree can't
1813                                  * be shared between trees.
1814                                  */
1815                                 for (i = 0; i < count; ++i)
1816                                         mono_add_varcopy_to_end (cfg, bb, locals [i]->inst_c0, outb->in_stack [i]->inst_c0);
1817                                 locals = outb->in_stack;
1818                                 found = TRUE;
1819                                 break;
1820                         }
1821                         bindex ++;
1822                 }
1823         }
1824         
1825         return 0;
1826 }
1827
1828 static int
1829 ret_type_to_call_opcode (MonoType *type, int calli, int virt)
1830 {
1831         if (type->byref)
1832                 return calli? OP_CALL_REG: virt? CEE_CALLVIRT: CEE_CALL;
1833
1834 handle_enum:
1835         switch (type->type) {
1836         case MONO_TYPE_VOID:
1837                 return calli? OP_VOIDCALL_REG: virt? OP_VOIDCALLVIRT: OP_VOIDCALL;
1838         case MONO_TYPE_I1:
1839         case MONO_TYPE_U1:
1840         case MONO_TYPE_BOOLEAN:
1841         case MONO_TYPE_I2:
1842         case MONO_TYPE_U2:
1843         case MONO_TYPE_CHAR:
1844         case MONO_TYPE_I4:
1845         case MONO_TYPE_U4:
1846                 return calli? OP_CALL_REG: virt? CEE_CALLVIRT: CEE_CALL;
1847         case MONO_TYPE_I:
1848         case MONO_TYPE_U:
1849         case MONO_TYPE_PTR:
1850                 return calli? OP_CALL_REG: virt? CEE_CALLVIRT: CEE_CALL;
1851         case MONO_TYPE_CLASS:
1852         case MONO_TYPE_STRING:
1853         case MONO_TYPE_OBJECT:
1854         case MONO_TYPE_SZARRAY:
1855         case MONO_TYPE_ARRAY:    
1856                 return calli? OP_CALL_REG: virt? CEE_CALLVIRT: CEE_CALL;
1857         case MONO_TYPE_I8:
1858         case MONO_TYPE_U8:
1859                 return calli? OP_LCALL_REG: virt? OP_LCALLVIRT: OP_LCALL;
1860         case MONO_TYPE_R4:
1861         case MONO_TYPE_R8:
1862                 return calli? OP_FCALL_REG: virt? OP_FCALLVIRT: OP_FCALL;
1863         case MONO_TYPE_VALUETYPE:
1864                 if (type->data.klass->enumtype) {
1865                         type = type->data.klass->enum_basetype;
1866                         goto handle_enum;
1867                 } else
1868                         return calli? OP_VCALL_REG: virt? OP_VCALLVIRT: OP_VCALL;
1869         case MONO_TYPE_TYPEDBYREF:
1870                 return calli? OP_VCALL_REG: virt? OP_VCALLVIRT: OP_VCALL;
1871         case MONO_TYPE_GENERICINST:
1872                 type = &type->data.generic_class->container_class->byval_arg;
1873                 goto handle_enum;
1874         default:
1875                 g_error ("unknown type 0x%02x in ret_type_to_call_opcode", type->type);
1876         }
1877         return -1;
1878 }
1879
1880 void
1881 mono_create_jump_table (MonoCompile *cfg, MonoInst *label, MonoBasicBlock **bbs, int num_blocks)
1882 {
1883         MonoJumpInfo *ji = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfo));
1884         MonoJumpInfoBBTable *table;
1885
1886         table = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfoBBTable));
1887         table->table = bbs;
1888         table->table_size = num_blocks;
1889         
1890         ji->ip.label = label;
1891         ji->type = MONO_PATCH_INFO_SWITCH;
1892         ji->data.table = table;
1893         ji->next = cfg->patch_info;
1894         cfg->patch_info = ji;
1895 }
1896
1897 /*
1898  * When we add a tree of instructions, we need to ensure the instructions currently
1899  * on the stack are executed before (like, if we load a value from a local).
1900  * We ensure this by saving the currently loaded values to temps and rewriting the
1901  * instructions to load the values.
1902  * This is not done for opcodes that terminate a basic block (because it's handled already
1903  * by handle_stack_args ()) and for opcodes that can't change values, like POP.
1904  */
1905 static void
1906 handle_loaded_temps (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst **stack, MonoInst **sp)
1907 {
1908         MonoInst *load, *store, *temp, *ins;
1909
1910         while (stack < sp) {
1911                 ins = *stack;
1912                 /* handle also other constants */
1913                 if ((ins->opcode != OP_ICONST) &&
1914                     /* temps never get written to again, so we can safely avoid duplicating them */
1915                     !(ins->ssa_op == MONO_SSA_LOAD && ins->inst_i0->opcode == OP_LOCAL && ins->inst_i0->flags & MONO_INST_IS_TEMP)) {
1916                         temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1917                         temp->flags |= MONO_INST_IS_TEMP;
1918                         NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
1919                         store->cil_code = ins->cil_code;
1920                         if (store->opcode == CEE_STOBJ) {
1921                                 NEW_TEMPLOADA (cfg, store, temp->inst_c0);
1922                                 handle_stobj (cfg, bblock, store, ins, ins->cil_code, temp->klass, FALSE, FALSE);
1923                         } else
1924                                 MONO_ADD_INS (bblock, store);
1925                         NEW_TEMPLOAD (cfg, load, temp->inst_c0);
1926                         load->cil_code = ins->cil_code;
1927                         *stack = load;
1928                 }
1929                 stack++;
1930         }
1931 }
1932
1933 /*
1934  * Prepare arguments for passing to a function call.
1935  * Return a non-zero value if the arguments can't be passed to the given
1936  * signature.
1937  * The type checks are not yet complete and some conversions may need
1938  * casts on 32 or 64 bit architectures.
1939  */
1940 static int
1941 check_call_signature (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args)
1942 {
1943         MonoType *simple_type;
1944         int i;
1945
1946         if (sig->hasthis) {
1947                 if (args [0]->type != STACK_OBJ && args [0]->type != STACK_MP && args [0]->type != STACK_PTR)
1948                         return 1;
1949                 args++;
1950         }
1951         for (i = 0; i < sig->param_count; ++i) {
1952                 if (sig->params [i]->byref) {
1953                         if (args [i]->type != STACK_MP && args [i]->type != STACK_PTR)
1954                                 return 1;
1955                         continue;
1956                 }
1957                 simple_type = sig->params [i];
1958 handle_enum:
1959                 switch (simple_type->type) {
1960                 case MONO_TYPE_VOID:
1961                         return 1;
1962                         continue;
1963                 case MONO_TYPE_I1:
1964                 case MONO_TYPE_U1:
1965                 case MONO_TYPE_BOOLEAN:
1966                 case MONO_TYPE_I2:
1967                 case MONO_TYPE_U2:
1968                 case MONO_TYPE_CHAR:
1969                 case MONO_TYPE_I4:
1970                 case MONO_TYPE_U4:
1971                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR)
1972                                 return 1;
1973                         continue;
1974                 case MONO_TYPE_I:
1975                 case MONO_TYPE_U:
1976                 case MONO_TYPE_PTR:
1977                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR && args [i]->type != STACK_MP && args [i]->type != STACK_OBJ)
1978                                 return 1;
1979                         continue;
1980                 case MONO_TYPE_CLASS:
1981                 case MONO_TYPE_STRING:
1982                 case MONO_TYPE_OBJECT:
1983                 case MONO_TYPE_SZARRAY:
1984                 case MONO_TYPE_ARRAY:    
1985                         if (args [i]->type != STACK_OBJ)
1986                                 return 1;
1987                         continue;
1988                 case MONO_TYPE_I8:
1989                 case MONO_TYPE_U8:
1990                         if (args [i]->type != STACK_I8)
1991                                 return 1;
1992                         continue;
1993                 case MONO_TYPE_R4:
1994                 case MONO_TYPE_R8:
1995                         if (args [i]->type != STACK_R8)
1996                                 return 1;
1997                         continue;
1998                 case MONO_TYPE_VALUETYPE:
1999                         if (simple_type->data.klass->enumtype) {
2000                                 simple_type = simple_type->data.klass->enum_basetype;
2001                                 goto handle_enum;
2002                         }
2003                         if (args [i]->type != STACK_VTYPE)
2004                                 return 1;
2005                         continue;
2006                 case MONO_TYPE_TYPEDBYREF:
2007                         if (args [i]->type != STACK_VTYPE)
2008                                 return 1;
2009                         continue;
2010                 case MONO_TYPE_GENERICINST:
2011                         simple_type = &simple_type->data.generic_class->container_class->byval_arg;
2012                         goto handle_enum;
2013
2014                 default:
2015                         g_error ("unknown type 0x%02x in check_call_signature",
2016                                  simple_type->type);
2017                 }
2018         }
2019         return 0;
2020 }
2021
2022 inline static int
2023 mono_spill_call (MonoCompile *cfg, MonoBasicBlock *bblock, MonoCallInst *call, MonoMethodSignature *sig, gboolean ret_object, 
2024                  const guint8 *ip, gboolean to_end)
2025 {
2026         MonoInst *temp, *store, *ins = (MonoInst*)call;
2027         MonoType *ret = sig->ret;
2028
2029         if (!MONO_TYPE_IS_VOID (ret) || ret_object) {
2030                 if (ret_object) {
2031                         call->inst.type = STACK_OBJ;
2032                         call->inst.opcode = CEE_CALL;
2033                         temp = mono_compile_create_var (cfg, &mono_defaults.string_class->byval_arg, OP_LOCAL);
2034                 } else {
2035                         type_to_eval_stack_type (ret, ins);
2036                         temp = mono_compile_create_var (cfg, ret, OP_LOCAL);
2037                 }
2038                 
2039                 temp->flags |= MONO_INST_IS_TEMP;
2040
2041                 if (MONO_TYPE_ISSTRUCT (ret)) {
2042                         MonoInst *loada;
2043
2044                         /* we use this to allocate native sized structs */
2045                         temp->unused = sig->pinvoke;
2046
2047                         NEW_TEMPLOADA (cfg, loada, temp->inst_c0);
2048                         if (call->inst.opcode == OP_VCALL)
2049                                 ins->inst_left = loada;
2050                         else
2051                                 ins->inst_right = loada; /* a virtual or indirect call */
2052
2053                         if (to_end)
2054                                 mono_add_ins_to_end (bblock, ins);
2055                         else
2056                                 MONO_ADD_INS (bblock, ins);
2057                 } else {
2058                         NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
2059                         store->cil_code = ip;
2060                         if (to_end)
2061                                 mono_add_ins_to_end (bblock, store);
2062                         else
2063                                 MONO_ADD_INS (bblock, store);
2064                 }
2065                 return temp->inst_c0;
2066         } else {
2067                 if (to_end)
2068                         mono_add_ins_to_end (bblock, ins);
2069                 else
2070                         MONO_ADD_INS (bblock, ins);
2071                 return -1;
2072         }
2073 }
2074
2075 inline static MonoCallInst *
2076 mono_emit_call_args (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethodSignature *sig, 
2077                      MonoInst **args, int calli, int virtual, const guint8 *ip, gboolean to_end)
2078 {
2079         MonoCallInst *call;
2080         MonoInst *arg;
2081
2082         MONO_INST_NEW_CALL (cfg, call, ret_type_to_call_opcode (sig->ret, calli, virtual));
2083         
2084         call->inst.cil_code = ip;
2085         call->args = args;
2086         call->signature = sig;
2087         call = mono_arch_call_opcode (cfg, bblock, call, virtual);
2088         type_to_eval_stack_type (sig->ret, &call->inst);
2089         
2090         for (arg = call->out_args; arg;) {
2091                 MonoInst *narg = arg->next;
2092                 arg->next = NULL;
2093                 if (!arg->cil_code)
2094                         arg->cil_code = ip;
2095                 if (to_end)
2096                         mono_add_ins_to_end (bblock, arg);
2097                 else
2098                         MONO_ADD_INS (bblock, arg);
2099                 arg = narg;
2100         }
2101         return call;
2102 }
2103
2104 inline static int
2105 mono_emit_calli (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethodSignature *sig, 
2106                  MonoInst **args, MonoInst *addr, const guint8 *ip)
2107 {
2108         MonoCallInst *call = mono_emit_call_args (cfg, bblock, sig, args, TRUE, FALSE, ip, FALSE);
2109
2110         call->inst.inst_i0 = addr;
2111
2112         return mono_spill_call (cfg, bblock, call, sig, FALSE, ip, FALSE);
2113 }
2114
2115 static MonoCallInst*
2116 mono_emit_method_call (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *method, MonoMethodSignature *sig,
2117                        MonoInst **args, const guint8 *ip, MonoInst *this)
2118 {
2119         gboolean virtual = this != NULL;
2120         MonoCallInst *call;
2121
2122         call = mono_emit_call_args (cfg, bblock, sig, args, FALSE, virtual, ip, FALSE);
2123
2124         if (this && sig->hasthis && 
2125             (method->klass->marshalbyref || method->klass == mono_defaults.object_class) && 
2126             !(method->flags & METHOD_ATTRIBUTE_VIRTUAL) && !MONO_CHECK_THIS (this)) {
2127                 call->method = mono_marshal_get_remoting_invoke_with_check (method);
2128         } else {
2129                 call->method = method;
2130         }
2131         call->inst.flags |= MONO_INST_HAS_METHOD;
2132         call->inst.inst_left = this;
2133
2134         if (!virtual)
2135                 mono_get_got_var (cfg);
2136         else if (call->method->klass->flags & TYPE_ATTRIBUTE_INTERFACE)
2137                 /* Needed by the code generated in inssel.brg */
2138                 mono_get_got_var (cfg);
2139
2140         return call;
2141 }
2142
2143 inline static int
2144 mono_emit_method_call_spilled (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *method,  
2145                        MonoMethodSignature *signature, MonoInst **args, const guint8 *ip, MonoInst *this)
2146 {
2147         MonoCallInst *call = mono_emit_method_call (cfg, bblock, method, signature, args, ip, this);
2148
2149         return mono_spill_call (cfg, bblock, call, signature, method->string_ctor, ip, FALSE);
2150 }
2151
2152 inline static int
2153 mono_emit_native_call (MonoCompile *cfg, MonoBasicBlock *bblock, gconstpointer func, MonoMethodSignature *sig,
2154                        MonoInst **args, const guint8 *ip, gboolean ret_object, gboolean to_end)
2155 {
2156         MonoCallInst *call;
2157
2158         g_assert (sig);
2159
2160         call = mono_emit_call_args (cfg, bblock, sig, args, FALSE, FALSE, ip, to_end);
2161         call->fptr = func;
2162         return mono_spill_call (cfg, bblock, call, sig, ret_object, ip, to_end);
2163 }
2164
2165 inline static int
2166 mono_emit_jit_icall (MonoCompile *cfg, MonoBasicBlock *bblock, gconstpointer func, MonoInst **args, const guint8 *ip)
2167 {
2168         MonoJitICallInfo *info = mono_find_jit_icall_by_addr (func);
2169         
2170         if (!info) {
2171                 g_warning ("unregistered JIT ICall");
2172                 g_assert_not_reached ();
2173         }
2174
2175         mono_get_got_var (cfg);
2176         return mono_emit_native_call (cfg, bblock, mono_icall_get_wrapper (info), info->sig, args, ip, FALSE, FALSE);
2177 }
2178
2179 static void
2180 mono_emulate_opcode (MonoCompile *cfg, MonoInst *tree, MonoInst **iargs, MonoJitICallInfo *info)
2181 {
2182         MonoInst *ins, *temp = NULL, *store, *load, *begin;
2183         MonoInst *last_arg = NULL;
2184         int nargs;
2185         MonoCallInst *call;
2186
2187         //g_print ("emulating: ");
2188         //mono_print_tree_nl (tree);
2189         MONO_INST_NEW_CALL (cfg, call, ret_type_to_call_opcode (info->sig->ret, FALSE, FALSE));
2190         ins = (MonoInst*)call;
2191         
2192         call->inst.cil_code = tree->cil_code;
2193         call->args = iargs;
2194         call->signature = info->sig;
2195
2196         call = mono_arch_call_opcode (cfg, cfg->cbb, call, FALSE);
2197
2198         mono_get_got_var (cfg);
2199
2200         if (!MONO_TYPE_IS_VOID (info->sig->ret)) {
2201                 temp = mono_compile_create_var (cfg, info->sig->ret, OP_LOCAL);
2202                 temp->flags |= MONO_INST_IS_TEMP;
2203                 NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
2204                 store->cil_code = tree->cil_code;
2205         } else {
2206                 store = ins;
2207         }
2208
2209         nargs = info->sig->param_count + info->sig->hasthis;
2210
2211         for (last_arg = call->out_args; last_arg && last_arg->next; last_arg = last_arg->next) ;
2212
2213         if (nargs)
2214                 last_arg->next = store;
2215
2216         if (nargs)
2217                 begin = call->out_args;
2218         else
2219                 begin = store;
2220
2221         if (cfg->prev_ins) {
2222                 /* 
2223                  * This assumes that that in a tree, emulate_opcode is called for a
2224                  * node before it is called for its children. dec_foreach needs to
2225                  * take this into account.
2226                  */
2227                 store->next = cfg->prev_ins->next;
2228                 cfg->prev_ins->next = begin;
2229         } else {
2230                 store->next = cfg->cbb->code;
2231                 cfg->cbb->code = begin;
2232         }
2233
2234         call->fptr = mono_icall_get_wrapper (info);
2235
2236         if (!MONO_TYPE_IS_VOID (info->sig->ret)) {
2237                 NEW_TEMPLOAD (cfg, load, temp->inst_c0);
2238                 *tree = *load;
2239         }
2240 }
2241
2242 static MonoMethodSignature *
2243 mono_get_element_address_signature (int arity)
2244 {
2245         static GHashTable *sighash = NULL;
2246         MonoMethodSignature *res;
2247         int i;
2248
2249         EnterCriticalSection (&jit_mutex);
2250         if (!sighash) {
2251                 sighash = g_hash_table_new (NULL, NULL);
2252         }
2253         else if ((res = g_hash_table_lookup (sighash, GINT_TO_POINTER (arity)))) {
2254                 LeaveCriticalSection (&jit_mutex);
2255                 return res;
2256         }
2257
2258         res = mono_metadata_signature_alloc (mono_defaults.corlib, arity + 1);
2259
2260         res->pinvoke = 1;
2261 #ifdef MONO_ARCH_VARARG_ICALLS
2262         /* Only set this only some archs since not all backends can handle varargs+pinvoke */
2263         res->call_convention = MONO_CALL_VARARG;
2264 #endif
2265         res->params [0] = &mono_defaults.array_class->byval_arg; 
2266         
2267         for (i = 1; i <= arity; i++)
2268                 res->params [i] = &mono_defaults.int_class->byval_arg;
2269
2270         res->ret = &mono_defaults.int_class->byval_arg;
2271
2272         g_hash_table_insert (sighash, GINT_TO_POINTER (arity), res);
2273         LeaveCriticalSection (&jit_mutex);
2274
2275         return res;
2276 }
2277
2278 static MonoMethodSignature *
2279 mono_get_array_new_va_signature (int arity)
2280 {
2281         static GHashTable *sighash = NULL;
2282         MonoMethodSignature *res;
2283         int i;
2284
2285         EnterCriticalSection (&jit_mutex);
2286         if (!sighash) {
2287                 sighash = g_hash_table_new (NULL, NULL);
2288         }
2289         else if ((res = g_hash_table_lookup (sighash, GINT_TO_POINTER (arity)))) {
2290                 LeaveCriticalSection (&jit_mutex);
2291                 return res;
2292         }
2293
2294         res = mono_metadata_signature_alloc (mono_defaults.corlib, arity + 1);
2295
2296         res->pinvoke = 1;
2297 #ifdef MONO_ARCH_VARARG_ICALLS
2298         /* Only set this only some archs since not all backends can handle varargs+pinvoke */
2299         res->call_convention = MONO_CALL_VARARG;
2300 #endif
2301
2302         res->params [0] = &mono_defaults.int_class->byval_arg;  
2303         for (i = 0; i < arity; i++)
2304                 res->params [i + 1] = &mono_defaults.int_class->byval_arg;
2305
2306         res->ret = &mono_defaults.int_class->byval_arg;
2307
2308         g_hash_table_insert (sighash, GINT_TO_POINTER (arity), res);
2309         LeaveCriticalSection (&jit_mutex);
2310
2311         return res;
2312 }
2313
2314 static void
2315 handle_stobj (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *dest, MonoInst *src, const unsigned char *ip, MonoClass *klass, gboolean to_end, gboolean native) {
2316         MonoInst *iargs [3];
2317         int n;
2318         guint32 align = 0;
2319
2320         g_assert (klass);
2321         /*
2322          * This check breaks with spilled vars... need to handle it during verification anyway.
2323          * g_assert (klass && klass == src->klass && klass == dest->klass);
2324          */
2325
2326         if (native)
2327                 n = mono_class_native_size (klass, &align);
2328         else
2329                 n = mono_class_value_size (klass, &align);
2330
2331         if ((cfg->opt & MONO_OPT_INTRINS) && !to_end && n <= sizeof (gpointer) * 5) {
2332                 MonoInst *inst;
2333                 MONO_INST_NEW (cfg, inst, OP_MEMCPY);
2334                 inst->inst_left = dest;
2335                 inst->inst_right = src;
2336                 inst->cil_code = ip;
2337                 inst->unused = n;
2338                 MONO_ADD_INS (bblock, inst);
2339                 return;
2340         }
2341         iargs [0] = dest;
2342         iargs [1] = src;
2343         NEW_ICONST (cfg, iargs [2], n);
2344
2345         mono_emit_native_call (cfg, bblock, helper_memcpy, helper_sig_memcpy, iargs, ip, FALSE, to_end);
2346 }
2347
2348 static void
2349 handle_initobj (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *dest, const guchar *ip, MonoClass *klass, MonoInst **stack_start, MonoInst **sp)
2350 {
2351         MonoInst *iargs [2];
2352         MonoInst *ins, *zero_int32;
2353         int n;
2354
2355         NEW_ICONST (cfg, zero_int32, 0);
2356
2357         mono_class_init (klass);
2358         n = mono_class_value_size (klass, NULL);
2359         MONO_INST_NEW (cfg, ins, 0);
2360         ins->cil_code = ip;
2361         ins->inst_left = dest;
2362         ins->inst_right = zero_int32;
2363         switch (n) {
2364         case 1:
2365                 ins->opcode = CEE_STIND_I1;
2366                 MONO_ADD_INS (bblock, ins);
2367                 break;
2368         case 2:
2369                 ins->opcode = CEE_STIND_I2;
2370                 MONO_ADD_INS (bblock, ins);
2371                 break;
2372         case 4:
2373                 ins->opcode = CEE_STIND_I4;
2374                 MONO_ADD_INS (bblock, ins);
2375                 break;
2376         default:
2377                 if (n <= sizeof (gpointer) * 5) {
2378                         ins->opcode = OP_MEMSET;
2379                         ins->inst_imm = 0;
2380                         ins->unused = n;
2381                         MONO_ADD_INS (bblock, ins);
2382                         break;
2383                 }
2384                 handle_loaded_temps (cfg, bblock, stack_start, sp);
2385                 NEW_ICONST (cfg, ins, n);
2386                 iargs [0] = dest;
2387                 iargs [1] = ins;
2388                 mono_emit_jit_icall (cfg, bblock, helper_initobj, iargs, ip);
2389                 break;
2390         }
2391 }
2392
2393 static int
2394 handle_alloc (MonoCompile *cfg, MonoBasicBlock *bblock, MonoClass *klass, const guchar *ip)
2395 {
2396         MonoInst *iargs [2];
2397         void *alloc_ftn;
2398
2399         if (cfg->opt & MONO_OPT_SHARED) {
2400                 NEW_DOMAINCONST (cfg, iargs [0]);
2401                 NEW_CLASSCONST (cfg, iargs [1], klass);
2402
2403                 alloc_ftn = mono_object_new;
2404         } else {
2405                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
2406                 gboolean pass_lw;
2407                 
2408                 alloc_ftn = mono_class_get_allocation_ftn (vtable, &pass_lw);
2409                 if (pass_lw) {
2410                         guint32 lw = vtable->klass->instance_size;
2411                         lw = ((lw + (sizeof (gpointer) - 1)) & ~(sizeof (gpointer) - 1)) / sizeof (gpointer);
2412                         NEW_ICONST (cfg, iargs [0], lw);
2413                         NEW_VTABLECONST (cfg, iargs [1], vtable);
2414                 }
2415                 else
2416                         NEW_VTABLECONST (cfg, iargs [0], vtable);
2417         }
2418
2419         return mono_emit_jit_icall (cfg, bblock, alloc_ftn, iargs, ip);
2420 }
2421         
2422 static MonoInst *
2423 handle_box (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *val, const guchar *ip, MonoClass *klass)
2424 {
2425         MonoInst *dest, *vtoffset, *add, *vstore;
2426         int temp;
2427
2428         temp = handle_alloc (cfg, bblock, klass, ip);
2429         NEW_TEMPLOAD (cfg, dest, temp);
2430         NEW_ICONST (cfg, vtoffset, sizeof (MonoObject));
2431         MONO_INST_NEW (cfg, add, OP_PADD);
2432         add->inst_left = dest;
2433         add->inst_right = vtoffset;
2434         add->cil_code = ip;
2435         add->klass = klass;
2436         MONO_INST_NEW (cfg, vstore, CEE_STIND_I);
2437         vstore->opcode = mono_type_to_stind (&klass->byval_arg);
2438         vstore->cil_code = ip;
2439         vstore->inst_left = add;
2440         vstore->inst_right = val;
2441
2442         if (vstore->opcode == CEE_STOBJ) {
2443                 handle_stobj (cfg, bblock, add, val, ip, klass, FALSE, FALSE);
2444         } else
2445                 MONO_ADD_INS (bblock, vstore);
2446
2447         NEW_TEMPLOAD (cfg, dest, temp);
2448         return dest;
2449 }
2450
2451 static int
2452 handle_array_new (MonoCompile *cfg, MonoBasicBlock *bblock, int rank, MonoInst **sp, unsigned char *ip)
2453 {
2454         MonoMethodSignature *esig;
2455         char icall_name [256];
2456         MonoJitICallInfo *info;
2457
2458         /* Need to register the icall so it gets an icall wrapper */
2459         sprintf (icall_name, "ves_array_new_va_%d", rank);
2460
2461         info = mono_find_jit_icall_by_name (icall_name);
2462         if (info == NULL) {
2463                 esig = mono_get_array_new_va_signature (rank);
2464                 info = mono_register_jit_icall (mono_array_new_va, g_strdup (icall_name), esig, FALSE);
2465         }
2466
2467         cfg->flags |= MONO_CFG_HAS_VARARGS;
2468
2469         return mono_emit_native_call (cfg, bblock, mono_icall_get_wrapper (info), info->sig, sp, ip, TRUE, FALSE);
2470 }
2471
2472 static void
2473 mono_emit_load_got_addr (MonoCompile *cfg)
2474 {
2475         MonoInst *load, *store, *dummy_use;
2476         MonoInst *get_got;
2477
2478         if (!cfg->got_var || cfg->got_var_allocated)
2479                 return;
2480
2481         MONO_INST_NEW (cfg, get_got, OP_LOAD_GOTADDR);
2482         NEW_TEMPSTORE (cfg, store, cfg->got_var->inst_c0, get_got);
2483
2484         /* Add it to the start of the first bblock */
2485         if (cfg->bb_entry->code) {
2486                 store->next = cfg->bb_entry->code;
2487                 cfg->bb_entry->code = store;
2488         }
2489         else
2490                 MONO_ADD_INS (cfg->bb_entry, store);
2491
2492         cfg->got_var_allocated = TRUE;
2493
2494         /* 
2495          * Add a dummy use to keep the got_var alive, since real uses might
2496          * only be generated in the decompose or instruction selection phases.
2497          * Add it to end_bblock, so the variable's lifetime covers the whole
2498          * method.
2499          */
2500         NEW_TEMPLOAD (cfg, load, cfg->got_var->inst_c0);
2501         NEW_DUMMY_USE (cfg, dummy_use, load);
2502         MONO_ADD_INS (cfg->bb_exit, dummy_use);
2503 }
2504
2505 #define CODE_IS_STLOC(ip) (((ip) [0] >= CEE_STLOC_0 && (ip) [0] <= CEE_STLOC_3) || ((ip) [0] == CEE_STLOC_S))
2506
2507 static gboolean
2508 mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method)
2509 {
2510         MonoMethodHeader *header = mono_method_get_header (method);
2511         MonoMethodSignature *signature = method->signature;
2512         MonoVTable *vtable;
2513         int i;
2514
2515 #ifdef MONO_ARCH_HAVE_LMF_OPS
2516         if (((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
2517                  (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) &&
2518             !MONO_TYPE_ISSTRUCT (signature->ret) && (method->klass->parent != mono_defaults.array_class))
2519                 return TRUE;
2520 #endif
2521
2522         if ((method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
2523             (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
2524             (method->iflags & METHOD_IMPL_ATTRIBUTE_NOINLINING) ||
2525             (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) ||
2526             (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
2527             (method->klass->marshalbyref) ||
2528             !header || header->num_clauses ||
2529             /* fixme: why cant we inline valuetype returns? */
2530             MONO_TYPE_ISSTRUCT (signature->ret))
2531                 return FALSE;
2532
2533         /* its not worth to inline methods with valuetype arguments?? */
2534         for (i = 0; i < signature->param_count; i++) {
2535                 if (MONO_TYPE_ISSTRUCT (signature->params [i])) {
2536                         return FALSE;
2537                 }
2538         }
2539
2540         /*
2541          * if we can initialize the class of the method right away, we do,
2542          * otherwise we don't allow inlining if the class needs initialization,
2543          * since it would mean inserting a call to mono_runtime_class_init()
2544          * inside the inlined code
2545          */
2546         if (!(cfg->opt & MONO_OPT_SHARED)) {
2547                 vtable = mono_class_vtable (cfg->domain, method->klass);
2548                 if (method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) {
2549                         if (cfg->run_cctors)
2550                                 mono_runtime_class_init (vtable);
2551                 }
2552                 else if (!vtable->initialized && mono_class_needs_cctor_run (method->klass, NULL))
2553                         return FALSE;
2554         } else {
2555                 /* 
2556                  * If we're compiling for shared code
2557                  * the cctor will need to be run at aot method load time, for example,
2558                  * or at the end of the compilation of the inlining method.
2559                  */
2560                 if (mono_class_needs_cctor_run (method->klass, NULL) && !((method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT)))
2561                         return FALSE;
2562         }
2563         //if (!MONO_TYPE_IS_VOID (signature->ret)) return FALSE;
2564
2565         /*
2566          * CAS - do not inline methods with declarative security
2567          * Note: this has to be before any possible return TRUE;
2568          */
2569         if (mono_method_has_declsec (method))
2570                 return FALSE;
2571
2572         /* also consider num_locals? */
2573         if (getenv ("MONO_INLINELIMIT")) {
2574                 if (header->code_size < atoi (getenv ("MONO_INLINELIMIT"))) {
2575                         return TRUE;
2576                 }
2577         } else if (header->code_size < 20)
2578                 return TRUE;
2579
2580         return FALSE;
2581 }
2582
2583 static MonoInst*
2584 mini_get_ldelema_ins (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *cmethod, MonoInst **sp, unsigned char *ip, gboolean is_set)
2585 {
2586         int temp, rank;
2587         MonoInst *addr;
2588         MonoMethodSignature *esig;
2589         char icall_name [256];
2590         MonoJitICallInfo *info;
2591
2592         rank = cmethod->signature->param_count - (is_set? 1: 0);
2593
2594         if (rank == 2 && (cfg->opt & MONO_OPT_INTRINS)) {
2595                 MonoInst *indexes;
2596                 NEW_GROUP (cfg, indexes, sp [1], sp [2]);
2597                 MONO_INST_NEW (cfg, addr, OP_LDELEMA2D);
2598                 addr->inst_left = sp [0];
2599                 addr->inst_right = indexes;
2600                 addr->cil_code = ip;
2601                 addr->type = STACK_MP;
2602                 addr->klass = cmethod->klass;
2603                 return addr;
2604         }
2605
2606         /* Need to register the icall so it gets an icall wrapper */
2607         sprintf (icall_name, "ves_array_element_address_%d", rank);
2608
2609         info = mono_find_jit_icall_by_name (icall_name);
2610         if (info == NULL) {
2611                 esig = mono_get_element_address_signature (rank);
2612                 info = mono_register_jit_icall (ves_array_element_address, g_strdup (icall_name), esig, FALSE);
2613         }
2614
2615         temp = mono_emit_native_call (cfg, bblock, mono_icall_get_wrapper (info), info->sig, sp, ip, FALSE, FALSE);
2616         cfg->flags |= MONO_CFG_HAS_VARARGS;
2617
2618         NEW_TEMPLOAD (cfg, addr, temp);
2619         return addr;
2620 }
2621
2622 static MonoJitICallInfo **emul_opcode_map = NULL;
2623
2624 static inline MonoJitICallInfo *
2625 mono_find_jit_opcode_emulation (int opcode)
2626 {
2627         if  (emul_opcode_map)
2628                 return emul_opcode_map [opcode];
2629         else
2630                 return NULL;
2631 }
2632
2633 static MonoInst*
2634 mini_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
2635 {
2636         MonoInst *ins = NULL;
2637         
2638         static MonoClass *runtime_helpers_class = NULL;
2639         if (! runtime_helpers_class)
2640                 runtime_helpers_class = mono_class_from_name (mono_defaults.corlib,
2641                         "System.Runtime.CompilerServices", "RuntimeHelpers");
2642
2643         if (cmethod->klass == mono_defaults.string_class) {
2644                 if (cmethod->name [0] != 'g')
2645                         return NULL;
2646  
2647                 if (strcmp (cmethod->name, "get_Chars") == 0) {
2648                         MONO_INST_NEW (cfg, ins, OP_GETCHR);
2649                         ins->inst_i0 = args [0];
2650                         ins->inst_i1 = args [1];
2651                         return ins;
2652                 } else if (strcmp (cmethod->name, "get_Length") == 0) {
2653                         MONO_INST_NEW (cfg, ins, OP_STRLEN);
2654                         ins->inst_i0 = args [0];
2655                         return ins;
2656                 } else 
2657                         return NULL;
2658         } else if (cmethod->klass == mono_defaults.object_class) {
2659                 if (strcmp (cmethod->name, "GetType") == 0) {
2660                         MONO_INST_NEW (cfg, ins, OP_GETTYPE);
2661                         ins->inst_i0 = args [0];
2662                         return ins;
2663                 } else if (strcmp (cmethod->name, "InternalGetHashCode") == 0) {
2664                         MONO_INST_NEW (cfg, ins, OP_GETHASHCODE);
2665                         ins->inst_i0 = args [0];
2666                         return ins;
2667                 } else
2668                         return NULL;
2669         } else if (cmethod->klass == mono_defaults.array_class) {
2670                 if (cmethod->name [0] != 'g')
2671                         return NULL;
2672
2673                 if (strcmp (cmethod->name, "get_Rank") == 0) {
2674                         MONO_INST_NEW (cfg, ins, OP_ARRAY_RANK);
2675                         ins->inst_i0 = args [0];
2676                         return ins;
2677                 } else if (strcmp (cmethod->name, "get_Length") == 0) {
2678                         MONO_INST_NEW (cfg, ins, CEE_LDLEN);
2679                         ins->inst_i0 = args [0];
2680                         return ins;
2681                 } else
2682                         return NULL;
2683         } else if (cmethod->klass == runtime_helpers_class) {
2684                 if (strcmp (cmethod->name, "get_OffsetToStringData") == 0) {
2685                         NEW_ICONST (cfg, ins, G_STRUCT_OFFSET (MonoString, chars));
2686                         return ins;
2687                 } else
2688                         return NULL;
2689         } else if (cmethod->klass == mono_defaults.thread_class) {
2690                 if (strcmp (cmethod->name, "get_CurrentThread") == 0 && (ins = mono_arch_get_thread_intrinsic (cfg)))
2691                         return ins;
2692                 return NULL;
2693         }
2694
2695         return mono_arch_get_inst_for_method (cfg, cmethod, fsig, args);
2696 }
2697
2698 static void
2699 mono_save_args (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethodSignature *sig, MonoInst **sp, MonoInst **args)
2700 {
2701         MonoInst *store, *temp;
2702         int i;
2703
2704         g_assert (!MONO_TYPE_ISSTRUCT (sig->ret));
2705
2706         if (!sig->hasthis && sig->param_count == 0) 
2707                 return;
2708
2709         if (sig->hasthis) {
2710                 if (sp [0]->opcode == OP_ICONST) {
2711                         *args++ = sp [0];
2712                 } else {
2713                         temp = mono_compile_create_var (cfg, type_from_stack_type (*sp), OP_LOCAL);
2714                         *args++ = temp;
2715                         NEW_TEMPSTORE (cfg, store, temp->inst_c0, *sp);
2716                         store->cil_code = sp [0]->cil_code;
2717                         MONO_ADD_INS (bblock, store);
2718                 }
2719                 sp++;
2720         }
2721
2722         for (i = 0; i < sig->param_count; ++i) {
2723                 if (sp [0]->opcode == OP_ICONST) {
2724                         *args++ = sp [0];
2725                 } else {
2726                         temp = mono_compile_create_var (cfg, sig->params [i], OP_LOCAL);
2727                         *args++ = temp;
2728                         NEW_TEMPSTORE (cfg, store, temp->inst_c0, *sp);
2729                         store->cil_code = sp [0]->cil_code;
2730                         if (store->opcode == CEE_STOBJ) {
2731                                 NEW_TEMPLOADA (cfg, store, temp->inst_c0);
2732                                 handle_stobj (cfg, bblock, store, *sp, sp [0]->cil_code, temp->klass, FALSE, FALSE);
2733                         } else {
2734                                 MONO_ADD_INS (bblock, store);
2735                         } 
2736                 }
2737                 sp++;
2738         }
2739 }
2740
2741 static int
2742 inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoBasicBlock *bblock, MonoInst **sp,
2743                 guchar *ip, guint real_offset, GList *dont_inline, MonoBasicBlock **last_b, gboolean inline_allways)
2744 {
2745         MonoInst *ins, *rvar = NULL;
2746         MonoMethodHeader *cheader;
2747         MonoBasicBlock *ebblock, *sbblock;
2748         int i, costs, new_locals_offset;
2749         MonoMethod *prev_inlined_method;
2750
2751         if (cfg->verbose_level > 2)
2752                 g_print ("INLINE START %p %s -> %s\n", cmethod,  mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
2753
2754         if (!cmethod->inline_info) {
2755                 mono_jit_stats.inlineable_methods++;
2756                 cmethod->inline_info = 1;
2757         }
2758         /* allocate space to store the return value */
2759         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
2760                 rvar =  mono_compile_create_var (cfg, fsig->ret, OP_LOCAL);
2761         }
2762
2763         /* allocate local variables */
2764         cheader = mono_method_get_header (cmethod);
2765         new_locals_offset = cfg->num_varinfo;
2766         for (i = 0; i < cheader->num_locals; ++i)
2767                 mono_compile_create_var (cfg, cheader->locals [i], OP_LOCAL);
2768         
2769         /* allocate starte and end blocks */
2770         sbblock = NEW_BBLOCK (cfg);
2771         sbblock->block_num = cfg->num_bblocks++;
2772         sbblock->real_offset = real_offset;
2773
2774         ebblock = NEW_BBLOCK (cfg);
2775         ebblock->block_num = cfg->num_bblocks++;
2776         ebblock->real_offset = real_offset;
2777
2778         prev_inlined_method = cfg->inlined_method;
2779         cfg->inlined_method = cmethod;
2780
2781         costs = mono_method_to_ir (cfg, cmethod, sbblock, ebblock, new_locals_offset, rvar, dont_inline, sp, real_offset, *ip == CEE_CALLVIRT);
2782
2783         cfg->inlined_method = prev_inlined_method;
2784
2785         if ((costs >= 0 && costs < 60) || inline_allways) {
2786                 if (cfg->verbose_level > 2)
2787                         g_print ("INLINE END %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
2788                 
2789                 mono_jit_stats.inlined_methods++;
2790
2791                 /* always add some code to avoid block split failures */
2792                 MONO_INST_NEW (cfg, ins, CEE_NOP);
2793                 MONO_ADD_INS (bblock, ins);
2794                 ins->cil_code = ip;
2795
2796                 bblock->next_bb = sbblock;
2797                 link_bblock (cfg, bblock, sbblock);
2798
2799                 if (rvar) {
2800                         NEW_TEMPLOAD (cfg, ins, rvar->inst_c0);
2801                         *sp++ = ins;
2802                 }
2803                 *last_b = ebblock;
2804                 return costs + 1;
2805         } else {
2806                 if (cfg->verbose_level > 2)
2807                         g_print ("INLINE ABORTED %s\n", mono_method_full_name (cmethod, TRUE));
2808         }
2809         return 0;
2810 }
2811
2812 /*
2813  * Some of these comments may well be out-of-date.
2814  * Design decisions: we do a single pass over the IL code (and we do bblock 
2815  * splitting/merging in the few cases when it's required: a back jump to an IL
2816  * address that was not already seen as bblock starting point).
2817  * Code is validated as we go (full verification is still better left to metadata/verify.c).
2818  * Complex operations are decomposed in simpler ones right away. We need to let the 
2819  * arch-specific code peek and poke inside this process somehow (except when the 
2820  * optimizations can take advantage of the full semantic info of coarse opcodes).
2821  * All the opcodes of the form opcode.s are 'normalized' to opcode.
2822  * MonoInst->opcode initially is the IL opcode or some simplification of that 
2823  * (OP_LOAD, OP_STORE). The arch-specific code may rearrange it to an arch-specific 
2824  * opcode with value bigger than OP_LAST.
2825  * At this point the IR can be handed over to an interpreter, a dumb code generator
2826  * or to the optimizing code generator that will translate it to SSA form.
2827  *
2828  * Profiling directed optimizations.
2829  * We may compile by default with few or no optimizations and instrument the code
2830  * or the user may indicate what methods to optimize the most either in a config file
2831  * or through repeated runs where the compiler applies offline the optimizations to 
2832  * each method and then decides if it was worth it.
2833  *
2834  * TODO:
2835  * * consider using an array instead of an hash table (bb_hash)
2836  */
2837
2838 #define CHECK_TYPE(ins) if (!(ins)->type) goto unverified
2839 #define CHECK_STACK(num) if ((sp - stack_start) < (num)) goto unverified
2840 #define CHECK_STACK_OVF(num) if (((sp - stack_start) + (num)) > header->max_stack) goto unverified
2841 #define CHECK_ARG(num) if ((unsigned)(num) >= (unsigned)num_args) goto unverified
2842 #define CHECK_LOCAL(num) if ((unsigned)(num) >= (unsigned)header->num_locals) goto unverified
2843 #define CHECK_OPSIZE(size) if (ip + size > end) goto unverified
2844
2845
2846 /* offset from br.s -> br like opcodes */
2847 #define BIG_BRANCH_OFFSET 13
2848
2849 static gboolean
2850 ip_in_bb (MonoCompile *cfg, MonoBasicBlock *bb, const guint8* ip)
2851 {
2852         MonoBasicBlock *b = g_hash_table_lookup (cfg->bb_hash, ip);
2853         
2854         return b == NULL || b == bb;
2855 }
2856
2857 static int
2858 get_basic_blocks (MonoCompile *cfg, GHashTable *bbhash, MonoMethodHeader* header, guint real_offset, unsigned char *start, unsigned char *end, unsigned char **pos)
2859 {
2860         unsigned char *ip = start;
2861         unsigned char *target;
2862         int i;
2863         guint cli_addr;
2864         MonoBasicBlock *bblock;
2865         const MonoOpcode *opcode;
2866
2867         while (ip < end) {
2868                 cli_addr = ip - start;
2869                 i = mono_opcode_value ((const guint8 **)&ip, end);
2870                 if (i < 0)
2871                         goto unverified;
2872                 opcode = &mono_opcodes [i];
2873                 switch (opcode->argument) {
2874                 case MonoInlineNone:
2875                         ip++; 
2876                         break;
2877                 case MonoInlineString:
2878                 case MonoInlineType:
2879                 case MonoInlineField:
2880                 case MonoInlineMethod:
2881                 case MonoInlineTok:
2882                 case MonoInlineSig:
2883                 case MonoShortInlineR:
2884                 case MonoInlineI:
2885                         ip += 5;
2886                         break;
2887                 case MonoInlineVar:
2888                         ip += 3;
2889                         break;
2890                 case MonoShortInlineVar:
2891                 case MonoShortInlineI:
2892                         ip += 2;
2893                         break;
2894                 case MonoShortInlineBrTarget:
2895                         target = start + cli_addr + 2 + (signed char)ip [1];
2896                         GET_BBLOCK (cfg, bbhash, bblock, target);
2897                         ip += 2;
2898                         break;
2899                 case MonoInlineBrTarget:
2900                         target = start + cli_addr + 5 + (gint32)read32 (ip + 1);
2901                         GET_BBLOCK (cfg, bbhash, bblock, target);
2902                         ip += 5;
2903                         break;
2904                 case MonoInlineSwitch: {
2905                         guint32 n = read32 (ip + 1);
2906                         guint32 j;
2907                         ip += 5;
2908                         cli_addr += 5 + 4 * n;
2909                         target = start + cli_addr;
2910                         GET_BBLOCK (cfg, bbhash, bblock, target);
2911                         
2912                         for (j = 0; j < n; ++j) {
2913                                 target = start + cli_addr + (gint32)read32 (ip);
2914                                 GET_BBLOCK (cfg, bbhash, bblock, target);
2915                                 ip += 4;
2916                         }
2917                         break;
2918                 }
2919                 case MonoInlineR:
2920                 case MonoInlineI8:
2921                         ip += 9;
2922                         break;
2923                 default:
2924                         g_assert_not_reached ();
2925                 }
2926         }
2927         return 0;
2928 unverified:
2929         *pos = ip;
2930         return 1;
2931 }
2932
2933 static MonoInst*
2934 emit_tree (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *ins, const guint8* ip_next)
2935 {
2936         MonoInst *store, *temp, *load;
2937         
2938         if (ip_in_bb (cfg, bblock, ip_next) &&
2939                 (CODE_IS_STLOC (ip_next) || *ip_next == CEE_BRTRUE || *ip_next == CEE_BRFALSE ||
2940                 *ip_next == CEE_BRTRUE_S || *ip_next == CEE_BRFALSE_S || *ip_next == CEE_RET))
2941                         return ins;
2942         
2943         temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
2944         temp->flags |= MONO_INST_IS_TEMP;
2945         NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
2946         store->cil_code = ins->cil_code;
2947         MONO_ADD_INS (bblock, store);
2948         NEW_TEMPLOAD (cfg, load, temp->inst_c0);
2949         load->cil_code = ins->cil_code;
2950         return load;
2951 }
2952
2953 static inline MonoMethod *
2954 mini_get_method (MonoImage *image, guint32 token, MonoClass *klass, MonoGenericContext *context)
2955 {
2956         MonoMethod *method = mono_get_method_full (image, token, klass, context);
2957
2958         if (method->is_inflated)
2959                 method = mono_get_inflated_method (method);
2960
2961         return method;
2962 }
2963
2964 /*
2965  * mono_method_to_ir: translates IL into basic blocks containing trees
2966  */
2967 static int
2968 mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock, 
2969                    int locals_offset, MonoInst *return_var, GList *dont_inline, MonoInst **inline_args, 
2970                    guint inline_offset, gboolean is_virtual_call)
2971 {
2972         MonoInst *zero_int32, *zero_int64, *zero_ptr, *zero_obj, *zero_r8;
2973         MonoInst *ins, **sp, **stack_start;
2974         MonoBasicBlock *bblock, *tblock = NULL, *init_localsbb = NULL;
2975         GHashTable *bbhash;
2976         MonoMethod *cmethod;
2977         MonoInst **arg_array;
2978         MonoMethodHeader *header;
2979         MonoImage *image;
2980         guint32 token, ins_flag;
2981         MonoClass *klass;
2982         MonoClass *constrained_call = NULL;
2983         unsigned char *ip, *end, *target, *err_pos;
2984         static double r8_0 = 0.0;
2985         MonoMethodSignature *sig;
2986         MonoGenericContext *generic_context = NULL;
2987         MonoGenericContainer *generic_container = NULL;
2988         MonoType **param_types;
2989         GList *bb_recheck = NULL, *tmp;
2990         int i, n, start_new_bblock, align;
2991         int num_calls = 0, inline_costs = 0;
2992         int *filter_lengths = NULL;
2993         int breakpoint_id = 0;
2994         guint real_offset, num_args;
2995
2996         image = method->klass->image;
2997         header = mono_method_get_header (method);
2998         generic_container = ((MonoMethodNormal *)method)->generic_container;
2999         sig = method->signature;
3000         num_args = sig->hasthis + sig->param_count;
3001         ip = (unsigned char*)header->code;
3002         end = ip + header->code_size;
3003         mono_jit_stats.cil_code_size += header->code_size;
3004
3005         if (method->signature->is_inflated)
3006                 generic_context = ((MonoMethodInflated *) method)->context;
3007         else if (generic_container)
3008                 generic_context = &generic_container->context;
3009
3010         g_assert (!method->signature->has_type_parameters);
3011
3012         if (cfg->method == method) {
3013                 real_offset = 0;
3014                 bbhash = cfg->bb_hash;
3015         } else {
3016                 real_offset = inline_offset;
3017                 bbhash = g_hash_table_new (g_direct_hash, NULL);
3018         }
3019
3020         if (cfg->verbose_level > 2)
3021                 g_print ("method to IR %s\n", mono_method_full_name (method, TRUE));
3022
3023         dont_inline = g_list_prepend (dont_inline, method);
3024         if (cfg->method == method) {
3025
3026                 if (cfg->method->save_lmf)
3027                         /* Needed by the prolog code */
3028                         mono_get_got_var (cfg);
3029
3030                 if (cfg->prof_options & MONO_PROFILE_INS_COVERAGE)
3031                         cfg->coverage_info = mono_profiler_coverage_alloc (cfg->method, header->code_size);
3032
3033                 /* ENTRY BLOCK */
3034                 cfg->bb_entry = start_bblock = NEW_BBLOCK (cfg);
3035                 start_bblock->cil_code = NULL;
3036                 start_bblock->cil_length = 0;
3037                 start_bblock->block_num = cfg->num_bblocks++;
3038
3039                 /* EXIT BLOCK */
3040                 cfg->bb_exit = end_bblock = NEW_BBLOCK (cfg);
3041                 end_bblock->cil_code = NULL;
3042                 end_bblock->cil_length = 0;
3043                 end_bblock->block_num = cfg->num_bblocks++;
3044                 g_assert (cfg->num_bblocks == 2);
3045
3046                 arg_array = alloca (sizeof (MonoInst *) * num_args);
3047                 for (i = num_args - 1; i >= 0; i--)
3048                         arg_array [i] = cfg->varinfo [i];
3049
3050                 if (header->num_clauses) {
3051                         int size = sizeof (int) * header->num_clauses;
3052                         filter_lengths = alloca (size);
3053                         memset (filter_lengths, 0, size);
3054
3055                         cfg->spvars = g_hash_table_new (NULL, NULL);
3056                 }
3057                 /* handle exception clauses */
3058                 for (i = 0; i < header->num_clauses; ++i) {
3059                         //unsigned char *p = ip;
3060                         MonoExceptionClause *clause = &header->clauses [i];
3061                         GET_BBLOCK (cfg, bbhash, tblock, ip + clause->try_offset);
3062                         tblock->real_offset = clause->try_offset;
3063                         GET_BBLOCK (cfg, bbhash, tblock, ip + clause->handler_offset);
3064                         tblock->real_offset = clause->handler_offset;
3065
3066                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY ||
3067                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
3068                                 MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
3069                                 MONO_ADD_INS (tblock, ins);
3070                         }
3071
3072                         /*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);
3073                           while (p < end) {
3074                           g_print ("%s", mono_disasm_code_one (NULL, method, p, &p));
3075                           }*/
3076                         /* catch and filter blocks get the exception object on the stack */
3077                         if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE ||
3078                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
3079                                 /* mostly like handle_stack_args (), but just sets the input args */
3080                                 /* g_print ("handling clause at IL_%04x\n", clause->handler_offset); */
3081                                 if (!cfg->exvar) {
3082                                         cfg->exvar = mono_compile_create_var (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL);
3083                                         /* prevent it from being register allocated */
3084                                         cfg->exvar->flags |= MONO_INST_INDIRECT;
3085                                 }
3086                                 tblock->in_scount = 1;
3087                                 tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
3088                                 tblock->in_stack [0] = cfg->exvar;
3089                                 
3090                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
3091                                         GET_BBLOCK (cfg, bbhash, tblock, ip + clause->data.filter_offset);
3092                                         tblock->real_offset = clause->data.filter_offset;
3093                                         tblock->in_scount = 1;
3094                                         tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
3095                                         tblock->in_stack [0] = cfg->exvar;
3096                                         MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
3097                                         MONO_ADD_INS (tblock, ins);
3098                                 }
3099                         }
3100                 }
3101         } else {
3102                 arg_array = alloca (sizeof (MonoInst *) * num_args);
3103                 mono_save_args (cfg, start_bblock, sig, inline_args, arg_array);
3104         }
3105
3106         /* FIRST CODE BLOCK */
3107         bblock = NEW_BBLOCK (cfg);
3108         bblock->cil_code = ip;
3109
3110         ADD_BBLOCK (cfg, bbhash, bblock);
3111
3112         if (cfg->method == method) {
3113                 breakpoint_id = mono_debugger_method_has_breakpoint (method);
3114                 if (breakpoint_id && (mono_debug_format != MONO_DEBUG_FORMAT_DEBUGGER)) {
3115                         MONO_INST_NEW (cfg, ins, CEE_BREAK);
3116                         MONO_ADD_INS (bblock, ins);
3117                 }
3118         }
3119         
3120         if ((header->init_locals || (cfg->method == method && (cfg->opt & MONO_OPT_SHARED))) || cfg->compile_aot) {
3121                 /* we use a separate basic block for the initialization code */
3122                 cfg->bb_init = init_localsbb = NEW_BBLOCK (cfg);
3123                 init_localsbb->real_offset = real_offset;
3124                 start_bblock->next_bb = init_localsbb;
3125                 init_localsbb->next_bb = bblock;
3126                 link_bblock (cfg, start_bblock, init_localsbb);
3127                 link_bblock (cfg, init_localsbb, bblock);
3128                 init_localsbb->block_num = cfg->num_bblocks++;
3129         } else {
3130                 start_bblock->next_bb = bblock;
3131                 link_bblock (cfg, start_bblock, bblock);
3132         }
3133
3134         if (get_basic_blocks (cfg, bbhash, header, real_offset, ip, end, &err_pos)) {
3135                 ip = err_pos;
3136                 goto unverified;
3137         }
3138
3139         if (cfg->method == method)
3140                 mono_debug_init_method (cfg, bblock, breakpoint_id);
3141
3142         param_types = mono_mempool_alloc (cfg->mempool, sizeof (MonoType*) * num_args);
3143         if (sig->hasthis)
3144                 param_types [0] = method->klass->valuetype?&method->klass->this_arg:&method->klass->byval_arg;
3145         for (n = 0; n < sig->param_count; ++n)
3146                 param_types [n + sig->hasthis] = sig->params [n];
3147
3148         /* do this somewhere outside - not here */
3149         NEW_ICONST (cfg, zero_int32, 0);
3150         NEW_ICONST (cfg, zero_int64, 0);
3151         zero_int64->type = STACK_I8;
3152         NEW_PCONST (cfg, zero_ptr, 0);
3153         NEW_PCONST (cfg, zero_obj, 0);
3154         zero_obj->type = STACK_OBJ;
3155
3156         MONO_INST_NEW (cfg, zero_r8, OP_R8CONST);
3157         zero_r8->type = STACK_R8;
3158         zero_r8->inst_p0 = &r8_0;
3159
3160         /* add a check for this != NULL to inlined methods */
3161         if (is_virtual_call) {
3162                 MONO_INST_NEW (cfg, ins, OP_CHECK_THIS);
3163                 NEW_ARGLOAD (cfg, ins->inst_left, 0);
3164                 ins->cil_code = ip;
3165                 MONO_ADD_INS (bblock, ins);
3166         }
3167
3168         /* we use a spare stack slot in SWITCH and NEWOBJ and others */
3169         stack_start = sp = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * (header->max_stack + 1));
3170
3171         ins_flag = 0;
3172         start_new_bblock = 0;
3173         while (ip < end) {
3174
3175                 if (cfg->method == method)
3176                         real_offset = ip - header->code;
3177                 else
3178                         real_offset = inline_offset;
3179
3180                 if (start_new_bblock) {
3181                         bblock->cil_length = ip - bblock->cil_code;
3182                         if (start_new_bblock == 2) {
3183                                 g_assert (ip == tblock->cil_code);
3184                         } else {
3185                                 GET_BBLOCK (cfg, bbhash, tblock, ip);
3186                         }
3187                         bblock->next_bb = tblock;
3188                         bblock = tblock;
3189                         start_new_bblock = 0;
3190                         for (i = 0; i < bblock->in_scount; ++i) {
3191                                 if (cfg->verbose_level > 3)
3192                                         g_print ("loading %d from temp %d\n", i, (int)bblock->in_stack [i]->inst_c0);                                           
3193                                 NEW_TEMPLOAD (cfg, ins, bblock->in_stack [i]->inst_c0);
3194                                 *sp++ = ins;
3195                         }
3196                 } else {
3197                         if ((tblock = g_hash_table_lookup (bbhash, ip)) && (tblock != bblock)) {
3198                                 link_bblock (cfg, bblock, tblock);
3199                                 if (sp != stack_start) {
3200                                         handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
3201                                         sp = stack_start;
3202                                 }
3203                                 bblock->next_bb = tblock;
3204                                 bblock = tblock;
3205                                 for (i = 0; i < bblock->in_scount; ++i) {
3206                                         if (cfg->verbose_level > 3)
3207                                                 g_print ("loading %d from temp %d\n", i, (int)bblock->in_stack [i]->inst_c0);                                           
3208                                         NEW_TEMPLOAD (cfg, ins, bblock->in_stack [i]->inst_c0);
3209                                         *sp++ = ins;
3210                                 }
3211                         }
3212                 }
3213
3214                 bblock->real_offset = real_offset;
3215
3216                 if ((cfg->method == method) && cfg->coverage_info) {
3217                         MonoInst *store, *one;
3218                         guint32 cil_offset = ip - header->code;
3219                         cfg->coverage_info->data [cil_offset].cil_code = ip;
3220
3221                         /* TODO: Use an increment here */
3222                         NEW_ICONST (cfg, one, 1);
3223                         one->cil_code = ip;
3224
3225                         NEW_PCONST (cfg, ins, &(cfg->coverage_info->data [cil_offset].count));
3226                         ins->cil_code = ip;
3227
3228                         MONO_INST_NEW (cfg, store, CEE_STIND_I);
3229                         store->cil_code = ip;
3230                         store->inst_left = ins;
3231                         store->inst_right = one;
3232
3233                         MONO_ADD_INS (bblock, store);
3234                 }
3235
3236                 if (cfg->verbose_level > 3)
3237                         g_print ("converting (in B%d: stack: %d) %s", bblock->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
3238
3239                 switch (*ip) {
3240                 case CEE_NOP:
3241                         ++ip;
3242                         break;
3243                 case CEE_BREAK:
3244                         MONO_INST_NEW (cfg, ins, CEE_BREAK);
3245                         ins->cil_code = ip++;
3246                         MONO_ADD_INS (bblock, ins);
3247                         break;
3248                 case CEE_LDARG_0:
3249                 case CEE_LDARG_1:
3250                 case CEE_LDARG_2:
3251                 case CEE_LDARG_3:
3252                         CHECK_STACK_OVF (1);
3253                         n = (*ip)-CEE_LDARG_0;
3254                         CHECK_ARG (n);
3255                         NEW_ARGLOAD (cfg, ins, n);
3256                         ins->cil_code = ip++;
3257                         *sp++ = ins;
3258                         break;
3259                 case CEE_LDLOC_0:
3260                 case CEE_LDLOC_1:
3261                 case CEE_LDLOC_2:
3262                 case CEE_LDLOC_3:
3263                         CHECK_STACK_OVF (1);
3264                         n = (*ip)-CEE_LDLOC_0;
3265                         CHECK_LOCAL (n);
3266                         NEW_LOCLOAD (cfg, ins, n);
3267                         ins->cil_code = ip++;
3268                         *sp++ = ins;
3269                         break;
3270                 case CEE_STLOC_0:
3271                 case CEE_STLOC_1:
3272                 case CEE_STLOC_2:
3273                 case CEE_STLOC_3:
3274                         CHECK_STACK (1);
3275                         n = (*ip)-CEE_STLOC_0;
3276                         CHECK_LOCAL (n);
3277                         --sp;
3278                         handle_loaded_temps (cfg, bblock, stack_start, sp);
3279                         NEW_LOCSTORE (cfg, ins, n, *sp);
3280                         ins->cil_code = ip;
3281                         if (ins->opcode == CEE_STOBJ) {
3282                                 NEW_LOCLOADA (cfg, ins, n);
3283                                 handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE);
3284                         } else
3285                                 MONO_ADD_INS (bblock, ins);
3286                         ++ip;
3287                         inline_costs += 1;
3288                         break;
3289                 case CEE_LDARG_S:
3290                         CHECK_OPSIZE (2);
3291                         CHECK_STACK_OVF (1);
3292                         CHECK_ARG (ip [1]);
3293                         NEW_ARGLOAD (cfg, ins, ip [1]);
3294                         ins->cil_code = ip;
3295                         *sp++ = ins;
3296                         ip += 2;
3297                         break;
3298                 case CEE_LDARGA_S:
3299                         CHECK_OPSIZE (2);
3300                         CHECK_STACK_OVF (1);
3301                         CHECK_ARG (ip [1]);
3302                         NEW_ARGLOADA (cfg, ins, ip [1]);
3303                         ins->cil_code = ip;
3304                         *sp++ = ins;
3305                         ip += 2;
3306                         break;
3307                 case CEE_STARG_S:
3308                         CHECK_OPSIZE (2);
3309                         CHECK_STACK (1);
3310                         --sp;
3311                         CHECK_ARG (ip [1]);
3312                         NEW_ARGSTORE (cfg, ins, ip [1], *sp);
3313                         handle_loaded_temps (cfg, bblock, stack_start, sp);
3314                         ins->cil_code = ip;
3315                         if (ins->opcode == CEE_STOBJ) {
3316                                 NEW_ARGLOADA (cfg, ins, ip [1]);
3317                                 handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE);
3318                         } else
3319                                 MONO_ADD_INS (bblock, ins);
3320                         ip += 2;
3321                         break;
3322                 case CEE_LDLOC_S:
3323                         CHECK_OPSIZE (2);
3324                         CHECK_STACK_OVF (1);
3325                         CHECK_LOCAL (ip [1]);
3326                         NEW_LOCLOAD (cfg, ins, ip [1]);
3327                         ins->cil_code = ip;
3328                         *sp++ = ins;
3329                         ip += 2;
3330                         break;
3331                 case CEE_LDLOCA_S:
3332                         CHECK_OPSIZE (2);
3333                         CHECK_STACK_OVF (1);
3334                         CHECK_LOCAL (ip [1]);
3335                         NEW_LOCLOADA (cfg, ins, ip [1]);
3336                         ins->cil_code = ip;
3337                         *sp++ = ins;
3338                         ip += 2;
3339                         break;
3340                 case CEE_STLOC_S:
3341                         CHECK_OPSIZE (2);
3342                         CHECK_STACK (1);
3343                         --sp;
3344                         handle_loaded_temps (cfg, bblock, stack_start, sp);
3345                         CHECK_LOCAL (ip [1]);
3346                         NEW_LOCSTORE (cfg, ins, ip [1], *sp);
3347                         ins->cil_code = ip;
3348                         if (ins->opcode == CEE_STOBJ) {
3349                                 NEW_LOCLOADA (cfg, ins, ip [1]);
3350                                 handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE);
3351                         } else
3352                                 MONO_ADD_INS (bblock, ins);
3353                         ip += 2;
3354                         inline_costs += 1;
3355                         break;
3356                 case CEE_LDNULL:
3357                         CHECK_STACK_OVF (1);
3358                         NEW_PCONST (cfg, ins, NULL);
3359                         ins->cil_code = ip;
3360                         ins->type = STACK_OBJ;
3361                         ++ip;
3362                         *sp++ = ins;
3363                         break;
3364                 case CEE_LDC_I4_M1:
3365                         CHECK_STACK_OVF (1);
3366                         NEW_ICONST (cfg, ins, -1);
3367                         ins->cil_code = ip;
3368                         ++ip;
3369                         *sp++ = ins;
3370                         break;
3371                 case CEE_LDC_I4_0:
3372                 case CEE_LDC_I4_1:
3373                 case CEE_LDC_I4_2:
3374                 case CEE_LDC_I4_3:
3375                 case CEE_LDC_I4_4:
3376                 case CEE_LDC_I4_5:
3377                 case CEE_LDC_I4_6:
3378                 case CEE_LDC_I4_7:
3379                 case CEE_LDC_I4_8:
3380                         CHECK_STACK_OVF (1);
3381                         NEW_ICONST (cfg, ins, (*ip) - CEE_LDC_I4_0);
3382                         ins->cil_code = ip;
3383                         ++ip;
3384                         *sp++ = ins;
3385                         break;
3386                 case CEE_LDC_I4_S:
3387                         CHECK_OPSIZE (2);
3388                         CHECK_STACK_OVF (1);
3389                         ++ip;
3390                         NEW_ICONST (cfg, ins, *((signed char*)ip));
3391                         ins->cil_code = ip;
3392                         ++ip;
3393                         *sp++ = ins;
3394                         break;
3395                 case CEE_LDC_I4:
3396                         CHECK_OPSIZE (5);
3397                         CHECK_STACK_OVF (1);
3398                         NEW_ICONST (cfg, ins, (gint32)read32 (ip + 1));
3399                         ins->cil_code = ip;
3400                         ip += 5;
3401                         *sp++ = ins;
3402                         break;
3403                 case CEE_LDC_I8:
3404                         CHECK_OPSIZE (9);
3405                         CHECK_STACK_OVF (1);
3406                         MONO_INST_NEW (cfg, ins, OP_I8CONST);
3407                         ins->cil_code = ip;
3408                         ins->type = STACK_I8;
3409                         ++ip;
3410                         ins->inst_l = (gint64)read64 (ip);
3411                         ip += 8;
3412                         *sp++ = ins;
3413                         break;
3414                 case CEE_LDC_R4: {
3415                         float *f = mono_mempool_alloc (cfg->domain->mp, sizeof (float));
3416                         CHECK_OPSIZE (5);
3417                         CHECK_STACK_OVF (1);
3418                         MONO_INST_NEW (cfg, ins, OP_R4CONST);
3419                         ins->type = STACK_R8;
3420                         ++ip;
3421                         readr4 (ip, f);
3422                         ins->inst_p0 = f;
3423
3424                         ip += 4;
3425                         *sp++ = ins;                    
3426                         break;
3427                 }
3428                 case CEE_LDC_R8: {
3429                         double *d = mono_mempool_alloc (cfg->domain->mp, sizeof (double));
3430                         CHECK_OPSIZE (9);
3431                         CHECK_STACK_OVF (1);
3432                         MONO_INST_NEW (cfg, ins, OP_R8CONST);
3433                         ins->type = STACK_R8;
3434                         ++ip;
3435                         readr8 (ip, d);
3436                         ins->inst_p0 = d;
3437
3438                         ip += 8;
3439                         *sp++ = ins;                    
3440                         break;
3441                 }
3442                 case CEE_DUP: {
3443                         MonoInst *temp, *store;
3444                         CHECK_STACK (1);
3445                         CHECK_STACK_OVF (1);
3446                         sp--;
3447                         ins = *sp;
3448                 
3449                         /* 
3450                          * small optimization: if the loaded value was from a local already,
3451                          * just load it twice.
3452                          */
3453                         if (ins->ssa_op == MONO_SSA_LOAD && 
3454                             (ins->inst_i0->opcode == OP_LOCAL || ins->inst_i0->opcode == OP_ARG)) {
3455                                 sp++;
3456                                 MONO_INST_NEW (cfg, temp, 0);
3457                                 *temp = *ins;
3458                                 temp->cil_code = ip;
3459                                 *sp++ = temp;
3460                         } else {
3461                                 /* Common idiom: ... / dup / stloc.x */
3462                                 int ins_len = 0;
3463                                 if (ip_in_bb (cfg, bblock, ip + 1)) {
3464                                         switch (ip [1]) {
3465                                         case CEE_STLOC_0:
3466                                         case CEE_STLOC_1:
3467                                         case CEE_STLOC_2:
3468                                         case CEE_STLOC_3:
3469                                                 n = (ip [1]) - CEE_STLOC_0;
3470                                                 ins_len = 1;
3471                                                 break;
3472                                         
3473                                         case CEE_STLOC_S:
3474                                                 n = ip [2];
3475                                                 ins_len = 2;
3476                                                 break;
3477                                         
3478                                         case CEE_PREFIX1:
3479                                                 if (ip [2] == CEE_LDLOC) {
3480                                                         n = read16 (ip + 3);
3481                                                         ins_len = 4;
3482                                                 }
3483                                         }
3484                                 }
3485                                 
3486                                 if (ins_len) {
3487                                         CHECK_LOCAL (n);
3488                                         handle_loaded_temps (cfg, bblock, stack_start, sp - 1);
3489                                         NEW_LOCSTORE (cfg, ins, n, *sp);
3490                                         ins->cil_code = ip;
3491                                         if (ins->opcode == CEE_STOBJ) {
3492                                                 NEW_LOCLOADA (cfg, ins, n);
3493                                                 handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE);
3494                                         } else
3495                                                 MONO_ADD_INS (bblock, ins);
3496                                         
3497                                         NEW_LOCLOAD (cfg, *sp, n);
3498                                         (*sp)->cil_code = ip;
3499                                         ip += ins_len;
3500                                         sp++;
3501                                 } else {
3502                                         temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
3503                                         temp->flags |= MONO_INST_IS_TEMP;
3504                                         temp->cil_code = ip;
3505                                         NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
3506                                         store->cil_code = ip;
3507                                         MONO_ADD_INS (bblock, store);
3508                                         NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
3509                                         *sp++ = ins;
3510                                         ins->cil_code = ip;
3511                                         NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
3512                                         *sp++ = ins;
3513                                         ins->cil_code = ip;
3514                                 }
3515                         }
3516                         ++ip;
3517                         inline_costs += 2;
3518                         break;
3519                 }
3520                 case CEE_POP:
3521                         CHECK_STACK (1);
3522                         MONO_INST_NEW (cfg, ins, CEE_POP);
3523                         MONO_ADD_INS (bblock, ins);
3524                         ins->cil_code = ip++;
3525                         --sp;
3526                         ins->inst_i0 = *sp;
3527                         break;
3528                 case CEE_JMP:
3529                         CHECK_OPSIZE (5);
3530                         if (stack_start != sp)
3531                                 goto unverified;
3532                         MONO_INST_NEW (cfg, ins, CEE_JMP);
3533                         token = read32 (ip + 1);
3534                         /* FIXME: check the signature matches */
3535                         cmethod = mini_get_method (image, token, NULL, generic_context);
3536                         ins->inst_p0 = cmethod;
3537                         MONO_ADD_INS (bblock, ins);
3538                         ip += 5;
3539                         start_new_bblock = 1;
3540                         break;
3541                 case CEE_CALLI:
3542                 case CEE_CALL:
3543                 case CEE_CALLVIRT: {
3544                         MonoInst *addr = NULL;
3545                         MonoMethodSignature *fsig = NULL;
3546                         int temp, array_rank = 0;
3547                         int virtual = *ip == CEE_CALLVIRT;
3548
3549                         CHECK_OPSIZE (5);
3550                         token = read32 (ip + 1);
3551
3552                         if (*ip == CEE_CALLI) {
3553                                 cmethod = NULL;
3554                                 CHECK_STACK (1);
3555                                 --sp;
3556                                 addr = *sp;
3557                                 if (method->wrapper_type != MONO_WRAPPER_NONE)
3558                                         fsig = (MonoMethodSignature *)mono_method_get_wrapper_data (method, token);
3559                                 else
3560                                         fsig = mono_metadata_parse_signature (image, token);
3561
3562                                 n = fsig->param_count + fsig->hasthis;
3563                         } else {
3564                                 if (method->wrapper_type != MONO_WRAPPER_NONE) {
3565                                         cmethod =  (MonoMethod *)mono_method_get_wrapper_data (method, token);
3566                                 } else if (constrained_call) {
3567                                         cmethod = mono_get_method_constrained (image, token, constrained_call, generic_context);
3568                                 } else {
3569                                         cmethod = mini_get_method (image, token, NULL, generic_context);
3570                                 }
3571
3572                                 g_assert (cmethod);
3573
3574                                 if (!cmethod->klass->inited)
3575                                         mono_class_init (cmethod->klass);
3576
3577                                 if (cmethod->signature->pinvoke) {
3578                                         MonoMethod *wrapper = mono_marshal_get_native_wrapper (cmethod);
3579                                         fsig = wrapper->signature;
3580                                 } else if (constrained_call) {
3581                                         fsig = cmethod->signature;
3582                                 } else {
3583                                         fsig = mono_method_get_signature_full (cmethod, image, token, generic_context);
3584                                 }
3585
3586                                 n = fsig->param_count + fsig->hasthis;
3587
3588                                 if (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL &&
3589                                     cmethod->klass->parent == mono_defaults.array_class) {
3590                                         array_rank = cmethod->klass->rank;
3591                                 }
3592
3593                                 if (cmethod->string_ctor)
3594                                         g_assert_not_reached ();
3595
3596                         }
3597
3598                         if (!virtual) {
3599                                 mono_get_got_var (cfg);
3600                         } else {
3601                                 /* code in inssel.brg might transform a virtual call to a normal call */
3602                                 if (!(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) || 
3603                                         ((cmethod->flags & METHOD_ATTRIBUTE_FINAL) && 
3604                                          cmethod->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK))
3605                                         mono_get_got_var (cfg);
3606                         }
3607
3608                         if (cmethod && cmethod->klass->generic_container) {
3609                                 G_BREAKPOINT ();
3610                                 goto unverified;
3611                         }
3612
3613                         CHECK_STACK (n);
3614
3615                         //g_assert (!virtual || fsig->hasthis);
3616
3617                         sp -= n;
3618
3619                         if (constrained_call) {
3620                                 /*
3621                                  * We have the `constrained.' prefix opcode.
3622                                  */
3623                                 if (constrained_call->valuetype && !cmethod->klass->valuetype) {
3624                                         MonoInst *load;
3625                                         /*
3626                                          * The type parameter is instantiated as a valuetype,
3627                                          * but that type doesn't override the method we're
3628                                          * calling, so we need to box `this'.
3629                                          * sp [0] is a pointer to the data: we need the value
3630                                          * in handle_box (), so load it here.
3631                                          */
3632                                         MONO_INST_NEW (cfg, load, mono_type_to_ldind (&constrained_call->byval_arg));
3633                                         type_to_eval_stack_type (&constrained_call->byval_arg, load);
3634                                         load->cil_code = ip;
3635                                         load->inst_left = sp [0];
3636                                         sp [0] = handle_box (cfg, bblock, load, ip, constrained_call);
3637                                 } else if (!constrained_call->valuetype) {
3638                                         MonoInst *ins;
3639
3640                                         /*
3641                                          * The type parameter is instantiated as a reference
3642                                          * type.  We have a managed pointer on the stack, so
3643                                          * we need to dereference it here.
3644                                          */
3645
3646                                         MONO_INST_NEW (cfg, ins, CEE_LDIND_REF);
3647                                         ins->cil_code = ip;
3648                                         ins->inst_i0 = sp [0];
3649                                         ins->type = STACK_OBJ;
3650                                         sp [0] = ins;
3651                                 } else if (cmethod->klass->valuetype)
3652                                         virtual = 0;
3653                                 constrained_call = NULL;
3654                         }
3655
3656                         if (*ip != CEE_CALLI && check_call_signature (cfg, fsig, sp)) {
3657                                 G_BREAKPOINT ();
3658                                 goto unverified;
3659                         }
3660
3661                         if (cmethod && virtual && cmethod->signature->generic_param_count) {
3662                                 MonoInst *this_temp, *store;
3663                                 MonoInst *iargs [3];
3664
3665                                 g_assert (cmethod->signature->is_inflated);
3666
3667                                 this_temp = mono_compile_create_var (cfg, type_from_stack_type (sp [0]), OP_LOCAL);
3668                                 this_temp->cil_code = ip;
3669                                 NEW_TEMPSTORE (cfg, store, this_temp->inst_c0, sp [0]);
3670
3671                                 store->cil_code = ip;
3672                                 MONO_ADD_INS (bblock, store);
3673
3674                                 NEW_TEMPLOAD (cfg, iargs [0], this_temp->inst_c0);
3675                                 NEW_PCONST (cfg, iargs [1], cmethod);
3676                                 NEW_PCONST (cfg, iargs [2], ((MonoMethodInflated *) cmethod)->context);
3677                                 temp = mono_emit_jit_icall (cfg, bblock, helper_compile_generic_method, iargs, ip);
3678
3679                                 NEW_TEMPLOAD (cfg, addr, temp);
3680                                 NEW_TEMPLOAD (cfg, sp [0], this_temp->inst_c0);
3681
3682                                 if ((temp = mono_emit_calli (cfg, bblock, fsig, sp, addr, ip)) != -1) {
3683                                         NEW_TEMPLOAD (cfg, *sp, temp);
3684                                         sp++;
3685                                 }
3686
3687                                 ip += 5;
3688                                 break;
3689                         }
3690
3691                         if ((ins_flag & MONO_INST_TAILCALL) && cmethod && (*ip == CEE_CALL) && (mono_metadata_signature_equal (method->signature, cmethod->signature))) {
3692                                 int i;
3693                                 /* FIXME: This assumes the two methods has the same number and type of arguments */
3694                                 for (i = 0; i < n; ++i) {
3695                                         /* Check if argument is the same */
3696                                         NEW_ARGLOAD (cfg, ins, i);
3697                                         if ((ins->opcode == sp [i]->opcode) && (ins->inst_i0 == sp [i]->inst_i0))
3698                                                 continue;
3699
3700                                         /* Prevent argument from being register allocated */
3701                                         arg_array [i]->flags |= MONO_INST_VOLATILE;
3702                                         NEW_ARGSTORE (cfg, ins, i, sp [i]);
3703                                         ins->cil_code = ip;
3704                                         if (ins->opcode == CEE_STOBJ) {
3705                                                 NEW_ARGLOADA (cfg, ins, i);
3706                                                 handle_stobj (cfg, bblock, ins, sp [i], sp [i]->cil_code, ins->klass, FALSE, FALSE);
3707                                         }
3708                                         else
3709                                                 MONO_ADD_INS (bblock, ins);
3710                                 }
3711                                 MONO_INST_NEW (cfg, ins, CEE_JMP);
3712                                 ins->cil_code = ip;
3713                                 ins->inst_p0 = cmethod;
3714                                 ins->inst_p1 = arg_array [0];
3715                                 MONO_ADD_INS (bblock, ins);
3716                                 link_bblock (cfg, bblock, end_bblock);                  
3717                                 start_new_bblock = 1;
3718                                 /* skip CEE_RET as well */
3719                                 ip += 6;
3720                                 ins_flag = 0;
3721                                 break;
3722                         }
3723                         if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_get_inst_for_method (cfg, cmethod, fsig, sp))) {
3724                                 ins->cil_code = ip;
3725
3726                                 if (MONO_TYPE_IS_VOID (fsig->ret)) {
3727                                         MONO_ADD_INS (bblock, ins);
3728                                 } else {
3729                                         type_to_eval_stack_type (fsig->ret, ins);
3730                                         *sp = ins;
3731                                         sp++;
3732                                 }
3733
3734                                 ip += 5;
3735                                 break;
3736                         }
3737
3738                         handle_loaded_temps (cfg, bblock, stack_start, sp);
3739
3740                         if ((cfg->opt & MONO_OPT_INLINE) && cmethod &&
3741                             (!virtual || !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) || (cmethod->flags & METHOD_ATTRIBUTE_FINAL)) && 
3742                             mono_method_check_inlining (cfg, cmethod) &&
3743                                  !g_list_find (dont_inline, cmethod)) {
3744                                 int costs;
3745                                 MonoBasicBlock *ebblock;
3746                                 gboolean allways = FALSE;
3747
3748                                 if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
3749                                         (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
3750                                         cmethod = mono_marshal_get_native_wrapper (cmethod);
3751                                         allways = TRUE;
3752                                 }
3753
3754                                 if ((costs = inline_method (cfg, cmethod, fsig, bblock, sp, ip, real_offset, dont_inline, &ebblock, allways))) {
3755                                         ip += 5;
3756                                         real_offset += 5;
3757
3758                                         GET_BBLOCK (cfg, bbhash, bblock, ip);
3759                                         ebblock->next_bb = bblock;
3760                                         link_bblock (cfg, ebblock, bblock);
3761
3762                                         if (!MONO_TYPE_IS_VOID (fsig->ret))
3763                                                 sp++;
3764
3765                                         /* indicates start of a new block, and triggers a load of all 
3766                                            stack arguments at bb boundarie */
3767                                         bblock = ebblock;
3768
3769                                         inline_costs += costs;
3770                                         break;
3771                                 }
3772                         }
3773                         
3774                         inline_costs += 10 * num_calls++;
3775
3776                         /* tail recursion elimination */
3777                         if ((cfg->opt & MONO_OPT_TAILC) && *ip == CEE_CALL && cmethod == method && ip [5] == CEE_RET) {
3778                                 gboolean has_vtargs = FALSE;
3779                                 int i;
3780                                 
3781                                 /* keep it simple */
3782                                 for (i =  fsig->param_count - 1; i >= 0; i--) {
3783                                         if (MONO_TYPE_ISSTRUCT (cmethod->signature->params [i])) 
3784                                                 has_vtargs = TRUE;
3785                                 }
3786
3787                                 if (!has_vtargs) {
3788                                         for (i = 0; i < n; ++i) {
3789                                                 NEW_ARGSTORE (cfg, ins, i, sp [i]);
3790                                                 ins->cil_code = ip;
3791                                                 MONO_ADD_INS (bblock, ins);
3792                                         }
3793                                         MONO_INST_NEW (cfg, ins, CEE_BR);
3794                                         ins->cil_code = ip;
3795                                         MONO_ADD_INS (bblock, ins);
3796                                         tblock = start_bblock->out_bb [0];
3797                                         link_bblock (cfg, bblock, tblock);
3798                                         ins->inst_target_bb = tblock;
3799                                         start_new_bblock = 1;
3800                                         ip += 5;
3801                                         
3802                                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
3803                                                 /* just create a dummy - the value is never used */
3804                                                 ins = mono_compile_create_var (cfg, fsig->ret, OP_LOCAL);
3805                                                 NEW_TEMPLOAD (cfg, *sp, ins->inst_c0);
3806                                                 sp++;
3807                                         }
3808
3809                                         break;
3810                                 }
3811                         }
3812
3813                         if (*ip == CEE_CALLI) {
3814
3815                                 if ((temp = mono_emit_calli (cfg, bblock, fsig, sp, addr, ip)) != -1) {
3816                                         NEW_TEMPLOAD (cfg, *sp, temp);
3817                                         sp++;
3818                                 }
3819                                         
3820                         } else if (array_rank) {
3821                                 MonoInst *addr;
3822
3823                                 if (strcmp (cmethod->name, "Set") == 0) { /* array Set */ 
3824                                         if (sp [fsig->param_count]->type == STACK_OBJ) {
3825                                                 MonoInst *iargs [2];
3826                                                 MonoInst *array, *to_store, *store;
3827
3828                                                 handle_loaded_temps (cfg, bblock, stack_start, sp);
3829                                                 
3830                                                 array = mono_compile_create_var (cfg, type_from_stack_type (sp [0]), OP_LOCAL);
3831                                                 NEW_TEMPSTORE (cfg, store, array->inst_c0, sp [0]);
3832                                                 store->cil_code = ip;
3833                                                 MONO_ADD_INS (bblock, store);
3834                                                 NEW_TEMPLOAD (cfg, iargs [0], array->inst_c0);
3835
3836                                                 to_store = mono_compile_create_var (cfg, type_from_stack_type (sp [fsig->param_count]), OP_LOCAL);
3837                                                 NEW_TEMPSTORE (cfg, store, to_store->inst_c0, sp [fsig->param_count]);
3838                                                 store->cil_code = ip;
3839                                                 MONO_ADD_INS (bblock, store);
3840                                                 NEW_TEMPLOAD (cfg, iargs [1], to_store->inst_c0);
3841
3842                                                 /*
3843                                                  * We first save the args for the call so that the args are copied to the stack
3844                                                  * and a new instruction tree for them is created. If we don't do this,
3845                                                  * the same MonoInst is added to two different trees and this is not 
3846                                                  * allowed by burg.
3847                                                  */
3848                                                 mono_emit_jit_icall (cfg, bblock, helper_stelem_ref_check, iargs, ip);
3849
3850                                                 NEW_TEMPLOAD (cfg, sp [0], array->inst_c0);
3851                                                 NEW_TEMPLOAD (cfg, sp [fsig->param_count], to_store->inst_c0);
3852                                         }
3853
3854                                         addr = mini_get_ldelema_ins (cfg, bblock, cmethod, sp, ip, TRUE);
3855                                         NEW_INDSTORE (cfg, ins, addr, sp [fsig->param_count], fsig->params [fsig->param_count - 1]);
3856                                         ins->cil_code = ip;
3857                                         if (ins->opcode == CEE_STOBJ) {
3858                                                 handle_stobj (cfg, bblock, addr, sp [fsig->param_count], ip, mono_class_from_mono_type (fsig->params [fsig->param_count-1]), FALSE, FALSE);
3859                                         } else {
3860                                                 MONO_ADD_INS (bblock, ins);
3861                                         }
3862
3863                                 } else if (strcmp (cmethod->name, "Get") == 0) { /* array Get */
3864                                         addr = mini_get_ldelema_ins (cfg, bblock, cmethod, sp, ip, FALSE);
3865                                         NEW_INDLOAD (cfg, ins, addr, fsig->ret);
3866                                         ins->cil_code = ip;
3867
3868                                         *sp++ = ins;
3869                                 } else if (strcmp (cmethod->name, "Address") == 0) { /* array Address */
3870                                         addr = mini_get_ldelema_ins (cfg, bblock, cmethod, sp, ip, FALSE);
3871                                         *sp++ = addr;
3872                                 } else {
3873                                         g_assert_not_reached ();
3874                                 }
3875
3876                         } else {
3877                                 if (ip_in_bb (cfg, bblock, ip + 5) 
3878                                     && (!MONO_TYPE_ISSTRUCT (fsig->ret))
3879                                     && (!MONO_TYPE_IS_VOID (fsig->ret) || cmethod->string_ctor)
3880                                     && (CODE_IS_STLOC (ip + 5) || ip [5] == CEE_POP || ip [5] == CEE_BRTRUE || ip [5] == CEE_BRFALSE ||
3881                                         ip [5] == CEE_BRTRUE_S || ip [5] == CEE_BRFALSE_S || ip [5] == CEE_RET)) {
3882                                         /* no need to spill */
3883                                         ins = (MonoInst*)mono_emit_method_call (cfg, bblock, cmethod, fsig, sp, ip, virtual ? sp [0] : NULL);
3884                                         *sp++ = ins;
3885                                 } else {
3886                                         if ((temp = mono_emit_method_call_spilled (cfg, bblock, cmethod, fsig, sp, ip, virtual ? sp [0] : NULL)) != -1) {
3887                                                 NEW_TEMPLOAD (cfg, *sp, temp);
3888                                                 sp++;
3889                                         }
3890                                 }
3891                         }
3892
3893                         ip += 5;
3894                         break;
3895                 }
3896                 case CEE_RET:
3897                         if (cfg->method != method) {
3898                                 /* return from inlined methode */
3899                                 if (return_var) {
3900                                         MonoInst *store;
3901                                         CHECK_STACK (1);
3902                                         --sp;
3903                                         //g_assert (returnvar != -1);
3904                                         NEW_TEMPSTORE (cfg, store, return_var->inst_c0, *sp);
3905                                         store->cil_code = sp [0]->cil_code;
3906                                         if (store->opcode == CEE_STOBJ) {
3907                                                 g_assert_not_reached ();
3908                                                 NEW_TEMPLOADA (cfg, store, return_var->inst_c0);
3909                                                 handle_stobj (cfg, bblock, store, *sp, sp [0]->cil_code, return_var->klass, FALSE, FALSE);
3910                                         } else
3911                                                 MONO_ADD_INS (bblock, store);
3912                                 } 
3913                         } else {
3914                                 if (cfg->ret) {
3915                                         g_assert (!return_var);
3916                                         CHECK_STACK (1);
3917                                         --sp;
3918                                         MONO_INST_NEW (cfg, ins, CEE_NOP);
3919                                         ins->opcode = mono_type_to_stind (method->signature->ret);
3920                                         if (ins->opcode == CEE_STOBJ) {
3921                                                 NEW_RETLOADA (cfg, ins);
3922                                                 handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE);
3923                                         } else {
3924                                                 ins->opcode = OP_SETRET;
3925                                                 ins->cil_code = ip;
3926                                                 ins->inst_i0 = *sp;;
3927                                                 ins->inst_i1 = NULL;
3928                                                 MONO_ADD_INS (bblock, ins);
3929                                         }
3930                                 }
3931                         }
3932                         if (sp != stack_start)
3933                                 goto unverified;
3934                         MONO_INST_NEW (cfg, ins, CEE_BR);
3935                         ins->cil_code = ip++;
3936                         ins->inst_target_bb = end_bblock;
3937                         MONO_ADD_INS (bblock, ins);
3938                         link_bblock (cfg, bblock, end_bblock);
3939                         start_new_bblock = 1;
3940                         break;
3941                 case CEE_BR_S:
3942                         CHECK_OPSIZE (2);
3943                         MONO_INST_NEW (cfg, ins, CEE_BR);
3944                         ins->cil_code = ip++;
3945                         MONO_ADD_INS (bblock, ins);
3946                         target = ip + 1 + (signed char)(*ip);
3947                         ++ip;
3948                         GET_BBLOCK (cfg, bbhash, tblock, target);
3949                         link_bblock (cfg, bblock, tblock);
3950                         CHECK_BBLOCK (target, ip, tblock);
3951                         ins->inst_target_bb = tblock;
3952                         if (sp != stack_start) {
3953                                 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
3954                                 sp = stack_start;
3955                         }
3956                         start_new_bblock = 1;
3957                         inline_costs += 10;
3958                         break;
3959                 case CEE_BRFALSE_S:
3960                 case CEE_BRTRUE_S:
3961                         CHECK_OPSIZE (2);
3962                         CHECK_STACK (1);
3963                         MONO_INST_NEW (cfg, ins, *ip + BIG_BRANCH_OFFSET);
3964                         ins->cil_code = ip++;
3965                         target = ip + 1 + *(signed char*)ip;
3966                         ip++;
3967                         ADD_UNCOND (ins->opcode == CEE_BRTRUE);
3968                         if (sp != stack_start) {
3969                                 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
3970                                 sp = stack_start;
3971                         }
3972                         inline_costs += 10;
3973                         break;
3974                 case CEE_BEQ_S:
3975                 case CEE_BGE_S:
3976                 case CEE_BGT_S:
3977                 case CEE_BLE_S:
3978                 case CEE_BLT_S:
3979                 case CEE_BNE_UN_S:
3980                 case CEE_BGE_UN_S:
3981                 case CEE_BGT_UN_S:
3982                 case CEE_BLE_UN_S:
3983                 case CEE_BLT_UN_S:
3984                         CHECK_OPSIZE (2);
3985                         CHECK_STACK (2);
3986                         MONO_INST_NEW (cfg, ins, *ip + BIG_BRANCH_OFFSET);
3987                         ins->cil_code = ip++;
3988                         target = ip + 1 + *(signed char*)ip;
3989                         ip++;
3990                         ADD_BINCOND (NULL);
3991                         if (sp != stack_start) {
3992                                 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
3993                                 sp = stack_start;
3994                         }
3995                         inline_costs += 10;
3996                         break;
3997                 case CEE_BR:
3998                         CHECK_OPSIZE (5);
3999                         MONO_INST_NEW (cfg, ins, CEE_BR);
4000                         ins->cil_code = ip++;
4001                         MONO_ADD_INS (bblock, ins);
4002                         target = ip + 4 + (gint32)read32(ip);
4003                         ip += 4;
4004                         GET_BBLOCK (cfg, bbhash, tblock, target);
4005                         link_bblock (cfg, bblock, tblock);
4006                         CHECK_BBLOCK (target, ip, tblock);
4007                         ins->inst_target_bb = tblock;
4008                         if (sp != stack_start) {
4009                                 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
4010                                 sp = stack_start;
4011                         }
4012                         start_new_bblock = 1;
4013                         inline_costs += 10;
4014                         break;
4015                 case CEE_BRFALSE:
4016                 case CEE_BRTRUE:
4017                         CHECK_OPSIZE (5);
4018                         CHECK_STACK (1);
4019                         MONO_INST_NEW (cfg, ins, *ip);
4020                         ins->cil_code = ip++;
4021                         target = ip + 4 + (gint32)read32(ip);
4022                         ip += 4;
4023                         ADD_UNCOND(ins->opcode == CEE_BRTRUE);
4024                         if (sp != stack_start) {
4025                                 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
4026                                 sp = stack_start;
4027                         }
4028                         inline_costs += 10;
4029                         break;
4030                 case CEE_BEQ:
4031                 case CEE_BGE:
4032                 case CEE_BGT:
4033                 case CEE_BLE:
4034                 case CEE_BLT:
4035                 case CEE_BNE_UN:
4036                 case CEE_BGE_UN:
4037                 case CEE_BGT_UN:
4038                 case CEE_BLE_UN:
4039                 case CEE_BLT_UN:
4040                         CHECK_OPSIZE (5);
4041                         CHECK_STACK (2);
4042                         MONO_INST_NEW (cfg, ins, *ip);
4043                         ins->cil_code = ip++;
4044                         target = ip + 4 + (gint32)read32(ip);
4045                         ip += 4;
4046                         ADD_BINCOND(NULL);
4047                         if (sp != stack_start) {
4048                                 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
4049                                 sp = stack_start;
4050                         }
4051                         inline_costs += 10;
4052                         break;
4053                 case CEE_SWITCH:
4054                         CHECK_OPSIZE (5);
4055                         CHECK_STACK (1);
4056                         n = read32 (ip + 1);
4057                         MONO_INST_NEW (cfg, ins, *ip);
4058                         --sp;
4059                         ins->inst_left = *sp;
4060                         if (ins->inst_left->type != STACK_I4) goto unverified;
4061                         ins->cil_code = ip;
4062                         ip += 5;
4063                         CHECK_OPSIZE (n * sizeof (guint32));
4064                         target = ip + n * sizeof (guint32);
4065                         MONO_ADD_INS (bblock, ins);
4066                         GET_BBLOCK (cfg, bbhash, tblock, target);
4067                         link_bblock (cfg, bblock, tblock);
4068                         ins->klass = GUINT_TO_POINTER (n);
4069                         ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * (n + 1));
4070                         ins->inst_many_bb [n] = tblock;
4071
4072                         for (i = 0; i < n; ++i) {
4073                                 GET_BBLOCK (cfg, bbhash, tblock, target + (gint32)read32(ip));
4074                                 link_bblock (cfg, bblock, tblock);
4075                                 ins->inst_many_bb [i] = tblock;
4076                                 ip += 4;
4077                         }
4078                         if (sp != stack_start) {
4079                                 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
4080                                 sp = stack_start;
4081                         }
4082                         /* Needed by the code generated in inssel.brg */
4083                         mono_get_got_var (cfg);
4084                         inline_costs += 20;
4085                         break;
4086                 case CEE_LDIND_I1:
4087                 case CEE_LDIND_U1:
4088                 case CEE_LDIND_I2:
4089                 case CEE_LDIND_U2:
4090                 case CEE_LDIND_I4:
4091                 case CEE_LDIND_U4:
4092                 case CEE_LDIND_I8:
4093                 case CEE_LDIND_I:
4094                 case CEE_LDIND_R4:
4095                 case CEE_LDIND_R8:
4096                 case CEE_LDIND_REF:
4097                         CHECK_STACK (1);
4098                         MONO_INST_NEW (cfg, ins, *ip);
4099                         ins->cil_code = ip;
4100                         --sp;
4101                         ins->inst_i0 = *sp;
4102                         *sp++ = ins;
4103                         ins->type = ldind_type [*ip - CEE_LDIND_I1];
4104                         ins->flags |= ins_flag;
4105                         ins_flag = 0;
4106                         ++ip;
4107                         break;
4108                 case CEE_STIND_REF:
4109                 case CEE_STIND_I1:
4110                 case CEE_STIND_I2:
4111                 case CEE_STIND_I4:
4112                 case CEE_STIND_I8:
4113                 case CEE_STIND_R4:
4114                 case CEE_STIND_R8:
4115                         CHECK_STACK (2);
4116                         MONO_INST_NEW (cfg, ins, *ip);
4117                         ins->cil_code = ip++;
4118                         sp -= 2;
4119                         handle_loaded_temps (cfg, bblock, stack_start, sp);
4120                         MONO_ADD_INS (bblock, ins);
4121                         ins->inst_i0 = sp [0];
4122                         ins->inst_i1 = sp [1];
4123                         ins->flags |= ins_flag;
4124                         ins_flag = 0;
4125                         inline_costs += 1;
4126                         break;
4127                 case CEE_ADD:
4128                 case CEE_SUB:
4129                 case CEE_MUL:
4130                 case CEE_DIV:
4131                 case CEE_DIV_UN:
4132                 case CEE_REM:
4133                 case CEE_REM_UN:
4134                 case CEE_AND:
4135                 case CEE_OR:
4136                 case CEE_XOR:
4137                 case CEE_SHL:
4138                 case CEE_SHR:
4139                 case CEE_SHR_UN:
4140                         CHECK_STACK (2);
4141                         ADD_BINOP (*ip);
4142                         /* special case that gives a nice speedup and happens to workaorund a ppc jit but (for the release)
4143                          * later apply the speedup to the left shift as well
4144                          * See BUG# 57957.
4145                          */
4146                         if ((ins->opcode == OP_LSHR_UN) && (ins->type == STACK_I8) 
4147                                         && (ins->inst_right->opcode == OP_ICONST) && (ins->inst_right->inst_c0 == 32)) {
4148                                 ins->opcode = OP_LONG_SHRUN_32;
4149                                 /*g_print ("applied long shr speedup to %s\n", cfg->method->name);*/
4150                                 ip++;
4151                                 break;
4152                         }
4153                         if (mono_find_jit_opcode_emulation (ins->opcode)) {
4154                                 --sp;
4155                                 *sp++ = emit_tree (cfg, bblock, ins, ip + 1);
4156                         }
4157                         ip++;
4158                         break;
4159                 case CEE_NEG:
4160                 case CEE_NOT:
4161                 case CEE_CONV_I1:
4162                 case CEE_CONV_I2:
4163                 case CEE_CONV_I4:
4164                 case CEE_CONV_R4:
4165                 case CEE_CONV_R8:
4166                 case CEE_CONV_U4:
4167                 case CEE_CONV_I8:
4168                 case CEE_CONV_U8:
4169                 case CEE_CONV_OVF_I8:
4170                 case CEE_CONV_OVF_U8:
4171                 case CEE_CONV_R_UN:
4172                         CHECK_STACK (1);
4173                         ADD_UNOP (*ip);
4174                         if (mono_find_jit_opcode_emulation (ins->opcode)) {
4175                                 --sp;
4176                                 *sp++ = emit_tree (cfg, bblock, ins, ip + 1);
4177                         }
4178                         ip++;                   
4179                         break;
4180                 case CEE_CONV_OVF_I4:
4181                 case CEE_CONV_OVF_I1:
4182                 case CEE_CONV_OVF_I2:
4183                 case CEE_CONV_OVF_I:
4184                 case CEE_CONV_OVF_U:
4185                         CHECK_STACK (1);
4186
4187                         if (sp [-1]->type == STACK_R8) {
4188                                 ADD_UNOP (CEE_CONV_OVF_I8);
4189                                 ADD_UNOP (*ip);
4190                         } else {
4191                                 ADD_UNOP (*ip);
4192                         }
4193
4194                         ip++;
4195                         break;
4196                 case CEE_CONV_OVF_U1:
4197                 case CEE_CONV_OVF_U2:
4198                 case CEE_CONV_OVF_U4:
4199                         CHECK_STACK (1);
4200
4201                         if (sp [-1]->type == STACK_R8) {
4202                                 ADD_UNOP (CEE_CONV_OVF_U8);
4203                                 ADD_UNOP (*ip);
4204                         } else {
4205                                 ADD_UNOP (*ip);
4206                         }
4207
4208                         ip++;
4209                         break;
4210                 case CEE_CONV_OVF_I1_UN:
4211                 case CEE_CONV_OVF_I2_UN:
4212                 case CEE_CONV_OVF_I4_UN:
4213                 case CEE_CONV_OVF_I8_UN:
4214                 case CEE_CONV_OVF_U1_UN:
4215                 case CEE_CONV_OVF_U2_UN:
4216                 case CEE_CONV_OVF_U4_UN:
4217                 case CEE_CONV_OVF_U8_UN:
4218                 case CEE_CONV_OVF_I_UN:
4219                 case CEE_CONV_OVF_U_UN:
4220                         CHECK_STACK (1);
4221                         ADD_UNOP (*ip);
4222                         ip++;
4223                         break;
4224                 case CEE_CPOBJ:
4225                         CHECK_OPSIZE (5);
4226                         CHECK_STACK (2);
4227                         token = read32 (ip + 1);
4228                         if (method->wrapper_type != MONO_WRAPPER_NONE)
4229                                 klass = mono_method_get_wrapper_data (method, token);
4230                         else
4231                                 klass = mono_class_get_full (image, token, generic_context);
4232
4233                         mono_class_init (klass);
4234                         sp -= 2;
4235                         if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
4236                                 MonoInst *store, *load;
4237                                 MONO_INST_NEW (cfg, load, CEE_LDIND_REF);
4238                                 load->cil_code = ip;
4239                                 load->inst_i0 = sp [1];
4240                                 load->type = STACK_OBJ;
4241                                 load->flags |= ins_flag;
4242                                 MONO_INST_NEW (cfg, store, CEE_STIND_REF);
4243                                 store->cil_code = ip;
4244                                 handle_loaded_temps (cfg, bblock, stack_start, sp);
4245                                 MONO_ADD_INS (bblock, store);
4246                                 store->inst_i0 = sp [0];
4247                                 store->inst_i1 = load;
4248                                 store->flags |= ins_flag;
4249                         } else {
4250                                 n = mono_class_value_size (klass, NULL);
4251                                 if ((cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 5) {
4252                                         MonoInst *copy;
4253                                         MONO_INST_NEW (cfg, copy, OP_MEMCPY);
4254                                         copy->inst_left = sp [0];
4255                                         copy->inst_right = sp [1];
4256                                         copy->cil_code = ip;
4257                                         copy->unused = n;
4258                                         MONO_ADD_INS (bblock, copy);
4259                                 } else {
4260                                         MonoInst *iargs [3];
4261                                         iargs [0] = sp [0];
4262                                         iargs [1] = sp [1];
4263                                         NEW_ICONST (cfg, iargs [2], n);
4264                                         iargs [2]->cil_code = ip;
4265
4266                                         mono_emit_jit_icall (cfg, bblock, helper_memcpy, iargs, ip);
4267                                 }
4268                         }
4269                         ins_flag = 0;
4270                         ip += 5;
4271                         break;
4272                 case CEE_LDOBJ: {
4273                         MonoInst *iargs [3];
4274                         int loc_index = -1;
4275                         int stloc_len = 0;
4276                         CHECK_OPSIZE (5);
4277                         CHECK_STACK (1);
4278                         --sp;
4279                         token = read32 (ip + 1);
4280                         if (method->wrapper_type != MONO_WRAPPER_NONE)
4281                                 klass = mono_method_get_wrapper_data (method, token);
4282                         else
4283                                 klass = mono_class_get_full (image, token, generic_context);
4284
4285                         mono_class_init (klass);
4286                         if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
4287                                 MONO_INST_NEW (cfg, ins, CEE_LDIND_REF);
4288                                 ins->cil_code = ip;
4289                                 ins->inst_i0 = sp [0];
4290                                 ins->type = STACK_OBJ;
4291                                 ins->flags |= ins_flag;
4292                                 ins_flag = 0;
4293                                 *sp++ = ins;
4294                                 ip += 5;
4295                                 break;
4296                         }
4297
4298                         /* Optimize the common ldobj+stloc combination */
4299                         switch (ip [5]) {
4300                         case CEE_STLOC_S:
4301                                 loc_index = ip [6];
4302                                 stloc_len = 2;
4303                                 break;
4304                         case CEE_STLOC_0:
4305                         case CEE_STLOC_1:
4306                         case CEE_STLOC_2:
4307                         case CEE_STLOC_3:
4308                                 loc_index = ip [5] - CEE_STLOC_0;
4309                                 stloc_len = 1;
4310                                 break;
4311                         default:
4312                                 break;
4313                         }
4314
4315                         if ((loc_index != -1) && ip_in_bb (cfg, bblock, ip + 5)) {
4316                                 CHECK_LOCAL (loc_index);
4317                                 NEW_LOCSTORE (cfg, ins, loc_index, *sp);
4318
4319                                 if (ins->opcode == CEE_STOBJ) {
4320                                         handle_loaded_temps (cfg, bblock, stack_start, sp);
4321                                         ins->cil_code = ip;
4322                                         g_assert (ins->opcode == CEE_STOBJ);
4323                                         NEW_LOCLOADA (cfg, ins, loc_index);
4324                                         handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE);
4325                                         ip += 5;
4326                                         ip += stloc_len;
4327                                         break;
4328                                 }
4329                         }
4330
4331                         n = mono_class_value_size (klass, NULL);
4332                         ins = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
4333                         NEW_TEMPLOADA (cfg, iargs [0], ins->inst_c0);
4334                         if ((cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 5) {
4335                                 MonoInst *copy;
4336                                 MONO_INST_NEW (cfg, copy, OP_MEMCPY);
4337                                 copy->inst_left = iargs [0];
4338                                 copy->inst_right = *sp;
4339                                 copy->cil_code = ip;
4340                                 copy->unused = n;
4341                                 MONO_ADD_INS (bblock, copy);
4342                         } else {
4343                                 iargs [1] = *sp;
4344                                 NEW_ICONST (cfg, iargs [2], n);
4345                                 iargs [2]->cil_code = ip;
4346
4347                                 mono_emit_jit_icall (cfg, bblock, helper_memcpy, iargs, ip);
4348                         }
4349                         NEW_TEMPLOAD (cfg, *sp, ins->inst_c0);
4350                         ++sp;
4351                         ip += 5;
4352                         ins_flag = 0;
4353                         inline_costs += 1;
4354                         break;
4355                 }
4356                 case CEE_LDSTR:
4357                         CHECK_STACK_OVF (1);
4358                         CHECK_OPSIZE (5);
4359                         n = read32 (ip + 1);
4360
4361                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
4362                                 NEW_PCONST (cfg, ins, mono_method_get_wrapper_data (method, n));                                                                
4363                                 ins->cil_code = ip;
4364                                 ins->type = STACK_OBJ;
4365                                 *sp = ins;
4366                         }
4367                         else if (method->wrapper_type != MONO_WRAPPER_NONE) {
4368                                 int temp;
4369                                 MonoInst *iargs [1];
4370
4371                                 NEW_PCONST (cfg, iargs [0], mono_method_get_wrapper_data (method, n));                          
4372                                 temp = mono_emit_jit_icall (cfg, bblock, mono_string_new_wrapper, iargs, ip);
4373                                 NEW_TEMPLOAD (cfg, *sp, temp);
4374
4375                         } else {
4376
4377                                 if (cfg->opt & MONO_OPT_SHARED) {
4378                                         int temp;
4379                                         MonoInst *iargs [3];
4380
4381                                         if (cfg->compile_aot) {
4382                                                 cfg->ldstr_list = g_list_prepend (cfg->ldstr_list, GINT_TO_POINTER (n));
4383                                         }
4384
4385                                         NEW_TEMPLOAD (cfg, iargs [0], mono_get_domainvar (cfg)->inst_c0);
4386                                         NEW_IMAGECONST (cfg, iargs [1], image);
4387                                         NEW_ICONST (cfg, iargs [2], mono_metadata_token_index (n));
4388                                         temp = mono_emit_jit_icall (cfg, bblock, mono_ldstr, iargs, ip);
4389                                         NEW_TEMPLOAD (cfg, *sp, temp);
4390                                         mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
4391                                 } else {
4392                                         if (cfg->compile_aot)
4393                                                 NEW_LDSTRCONST (cfg, ins, image, n);
4394                                         else {
4395                                                 NEW_PCONST (cfg, ins, NULL);
4396                                                 ins->cil_code = ip;
4397                                                 ins->type = STACK_OBJ;
4398                                                 ins->inst_p0 = mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
4399                                         }
4400                                         *sp = ins;
4401                                 }
4402                         }
4403
4404                         sp++;
4405                         ip += 5;
4406                         break;
4407                 case CEE_NEWOBJ: {
4408                         MonoInst *iargs [2];
4409                         MonoMethodSignature *fsig;
4410                         int temp;
4411
4412                         CHECK_OPSIZE (5);
4413                         token = read32 (ip + 1);
4414                         if (method->wrapper_type != MONO_WRAPPER_NONE) {
4415                                 cmethod = mono_method_get_wrapper_data (method, token);
4416                         } else
4417                                 cmethod = mini_get_method (image, token, NULL, generic_context);
4418                         fsig = mono_method_get_signature (cmethod, image, token);
4419
4420                         mono_class_init (cmethod->klass);
4421
4422                         n = fsig->param_count;
4423                         CHECK_STACK (n);
4424
4425                         /* move the args to allow room for 'this' in the first position */
4426                         while (n--) {
4427                                 --sp;
4428                                 sp [1] = sp [0];
4429                         }
4430
4431                         handle_loaded_temps (cfg, bblock, stack_start, sp);
4432                         
4433
4434                         if (cmethod->klass->parent == mono_defaults.array_class) {
4435                                 NEW_METHODCONST (cfg, *sp, cmethod);
4436                                 temp = handle_array_new (cfg, bblock, fsig->param_count, sp, ip);
4437                         } else if (cmethod->string_ctor) {
4438                                 /* we simply pass a null pointer */
4439                                 NEW_PCONST (cfg, *sp, NULL); 
4440                                 /* now call the string ctor */
4441                                 temp = mono_emit_method_call_spilled (cfg, bblock, cmethod, fsig, sp, ip, NULL);
4442                         } else {
4443                                 if (cmethod->klass->valuetype) {
4444                                         iargs [0] = mono_compile_create_var (cfg, &cmethod->klass->byval_arg, OP_LOCAL);
4445                                         temp = iargs [0]->inst_c0;
4446                                         NEW_TEMPLOADA (cfg, *sp, temp);
4447                                 } else {
4448                                         temp = handle_alloc (cfg, bblock, cmethod->klass, ip);
4449                                         NEW_TEMPLOAD (cfg, *sp, temp);
4450                                 }
4451
4452                                 if ((cfg->opt & MONO_OPT_INLINE) && cmethod &&
4453                                     mono_method_check_inlining (cfg, cmethod) &&
4454                                     !mono_class_is_subclass_of (cmethod->klass, mono_defaults.exception_class, FALSE) &&
4455                                     !g_list_find (dont_inline, cmethod)) {
4456                                         int costs;
4457                                         MonoBasicBlock *ebblock;
4458                                         if ((costs = inline_method (cfg, cmethod, fsig, bblock, sp, ip, real_offset, dont_inline, &ebblock, FALSE))) {
4459
4460                                                 ip += 5;
4461                                                 real_offset += 5;
4462                                                 
4463                                                 GET_BBLOCK (cfg, bbhash, bblock, ip);
4464                                                 ebblock->next_bb = bblock;
4465                                                 link_bblock (cfg, ebblock, bblock);
4466
4467                                                 NEW_TEMPLOAD (cfg, *sp, temp);
4468                                                 sp++;
4469
4470                                                 /* indicates start of a new block, and triggers a load 
4471                                                    of all stack arguments at bb boundarie */
4472                                                 bblock = ebblock;
4473
4474                                                 inline_costs += costs;
4475                                                 break;
4476                                                 
4477                                         } else {
4478                                                 mono_emit_method_call_spilled (cfg, bblock, cmethod, fsig, sp, ip, sp[0]);
4479                                         }
4480                                 } else {
4481                                         /* now call the actual ctor */
4482                                         mono_emit_method_call_spilled (cfg, bblock, cmethod, fsig, sp, ip, sp[0]);
4483                                 }
4484                         }
4485
4486                         NEW_TEMPLOAD (cfg, *sp, temp);
4487                         sp++;
4488                         
4489                         ip += 5;
4490                         inline_costs += 5;
4491                         break;
4492                 }
4493                 case CEE_ISINST:
4494                         CHECK_STACK (1);
4495                         --sp;
4496                         CHECK_OPSIZE (5);
4497                         token = read32 (ip + 1);
4498                         if (method->wrapper_type != MONO_WRAPPER_NONE)
4499                                 klass = mono_method_get_wrapper_data (method, token);
4500                         else
4501                                 klass = mono_class_get_full (image, token, generic_context);
4502                         mono_class_init (klass);
4503
4504                         /* Needed by the code generated in inssel.brg */
4505                         mono_get_got_var (cfg);
4506
4507                         if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4508                         
4509                                 MonoMethod *mono_isinst;
4510                                 MonoInst *iargs [1];
4511                                 MonoBasicBlock *ebblock;
4512                                 int costs;
4513                                 int temp;
4514                                 
4515                                 mono_isinst = mono_marshal_get_isinst (klass); 
4516                                 iargs [0] = sp [0];
4517                                 
4518                                 costs = inline_method (cfg, mono_isinst, mono_isinst->signature, bblock, 
4519                                                            iargs, ip, real_offset, dont_inline, &ebblock, TRUE);
4520                         
4521                                 g_assert (costs > 0);
4522                                 
4523                                 ip += 5;
4524                                 real_offset += 5;
4525                         
4526                                 GET_BBLOCK (cfg, bbhash, bblock, ip);
4527                                 ebblock->next_bb = bblock;
4528                                 link_bblock (cfg, ebblock, bblock);
4529
4530                                 temp = iargs [0]->inst_i0->inst_c0;
4531                                 NEW_TEMPLOAD (cfg, *sp, temp);
4532                                 
4533                                 sp++;
4534                                 bblock = ebblock;
4535                                 inline_costs += costs;
4536
4537                         }
4538                         else {
4539                                 MONO_INST_NEW (cfg, ins, *ip);
4540                                 ins->type = STACK_OBJ;
4541                                 ins->inst_left = *sp;
4542                                 ins->inst_newa_class = klass;
4543                                 ins->cil_code = ip;
4544                                 *sp++ = emit_tree (cfg, bblock, ins, ip + 5);
4545                                 ip += 5;
4546                         }
4547                         break;
4548                 case CEE_UNBOX_ANY: {
4549                         MonoInst *add, *vtoffset;
4550                         MonoInst *iargs [3];
4551
4552                         CHECK_STACK (1);
4553                         --sp;
4554                         CHECK_OPSIZE (5);
4555                         token = read32 (ip + 1);
4556                         if (method->wrapper_type != MONO_WRAPPER_NONE)
4557                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
4558                         else 
4559                                 klass = mono_class_get_full (image, token, generic_context);
4560                         mono_class_init (klass);
4561
4562                         if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
4563                                 /* CASTCLASS */
4564                                 if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4565                                         MonoMethod *mono_castclass;
4566                                         MonoInst *iargs [1];
4567                                         MonoBasicBlock *ebblock;
4568                                         int costs;
4569                                         int temp;
4570                                         
4571                                         mono_castclass = mono_marshal_get_castclass (klass); 
4572                                         iargs [0] = sp [0];
4573                                         
4574                                         costs = inline_method (cfg, mono_castclass, mono_castclass->signature, bblock, 
4575                                                                    iargs, ip, real_offset, dont_inline, &ebblock, TRUE);
4576                                 
4577                                         g_assert (costs > 0);
4578                                         
4579                                         ip += 5;
4580                                         real_offset += 5;
4581                                 
4582                                         GET_BBLOCK (cfg, bbhash, bblock, ip);
4583                                         ebblock->next_bb = bblock;
4584                                         link_bblock (cfg, ebblock, bblock);
4585         
4586                                         temp = iargs [0]->inst_i0->inst_c0;
4587                                         NEW_TEMPLOAD (cfg, *sp, temp);
4588                                         
4589                                         sp++;
4590                                         bblock = ebblock;
4591                                         inline_costs += costs;                          
4592                                 }
4593                                 else {
4594                                         MONO_INST_NEW (cfg, ins, CEE_CASTCLASS);
4595                                         ins->type = STACK_OBJ;
4596                                         ins->inst_left = *sp;
4597                                         ins->klass = klass;
4598                                         ins->inst_newa_class = klass;
4599                                         ins->cil_code = ip;
4600                                         *sp++ = ins;
4601                                 }
4602                                 ip += 5;
4603                                 break;
4604                         }
4605
4606                         MONO_INST_NEW (cfg, ins, OP_UNBOXCAST);
4607                         ins->type = STACK_OBJ;
4608                         ins->inst_left = *sp;
4609                         ins->klass = klass;
4610                         ins->inst_newa_class = klass;
4611                         ins->cil_code = ip;
4612
4613                         MONO_INST_NEW (cfg, add, OP_PADD);
4614                         NEW_ICONST (cfg, vtoffset, sizeof (MonoObject));
4615                         add->inst_left = ins;
4616                         add->inst_right = vtoffset;
4617                         add->type = STACK_MP;
4618                         *sp = add;
4619                         ip += 5;
4620                         /* LDOBJ impl */
4621                         n = mono_class_value_size (klass, NULL);
4622                         ins = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
4623                         NEW_TEMPLOADA (cfg, iargs [0], ins->inst_c0);
4624                         if ((cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 5) {
4625                                 MonoInst *copy;
4626                                 MONO_INST_NEW (cfg, copy, OP_MEMCPY);
4627                                 copy->inst_left = iargs [0];
4628                                 copy->inst_right = *sp;
4629                                 copy->cil_code = ip;
4630                                 copy->unused = n;
4631                                 MONO_ADD_INS (bblock, copy);
4632                         } else {
4633                                 iargs [1] = *sp;
4634                                 NEW_ICONST (cfg, iargs [2], n);
4635                                 iargs [2]->cil_code = ip;
4636
4637                                 mono_emit_jit_icall (cfg, bblock, helper_memcpy, iargs, ip);
4638                         }
4639                         NEW_TEMPLOAD (cfg, *sp, ins->inst_c0);
4640                         ++sp;
4641                         inline_costs += 2;
4642                         break;
4643                 }
4644                 case CEE_UNBOX: {
4645                         MonoInst *add, *vtoffset;
4646
4647                         CHECK_STACK (1);
4648                         --sp;
4649                         CHECK_OPSIZE (5);
4650                         token = read32 (ip + 1);
4651                         if (method->wrapper_type != MONO_WRAPPER_NONE)
4652                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
4653                         else 
4654                                 klass = mono_class_get_full (image, token, generic_context);
4655                         mono_class_init (klass);
4656
4657                         /* Needed by the code generated in inssel.brg */
4658                         mono_get_got_var (cfg);
4659
4660                         MONO_INST_NEW (cfg, ins, OP_UNBOXCAST);
4661                         ins->type = STACK_OBJ;
4662                         ins->inst_left = *sp;
4663                         ins->klass = klass;
4664                         ins->inst_newa_class = klass;
4665                         ins->cil_code = ip;
4666
4667                         MONO_INST_NEW (cfg, add, OP_PADD);
4668                         NEW_ICONST (cfg, vtoffset, sizeof (MonoObject));
4669                         add->inst_left = ins;
4670                         add->inst_right = vtoffset;
4671                         add->type = STACK_MP;
4672                         *sp++ = add;
4673                         ip += 5;
4674                         inline_costs += 2;
4675                         break;
4676                 }
4677                 case CEE_CASTCLASS:
4678                         CHECK_STACK (1);
4679                         --sp;
4680                         CHECK_OPSIZE (5);
4681                         token = read32 (ip + 1);
4682                         if (method->wrapper_type != MONO_WRAPPER_NONE)
4683                                 klass = mono_method_get_wrapper_data (method, token);
4684                         else
4685                                 klass = mono_class_get_full (image, token, generic_context);
4686                         mono_class_init (klass);
4687
4688                         /* Needed by the code generated in inssel.brg */
4689                         mono_get_got_var (cfg);
4690                 
4691                         if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4692                                 
4693                                 MonoMethod *mono_castclass;
4694                                 MonoInst *iargs [1];
4695                                 MonoBasicBlock *ebblock;
4696                                 int costs;
4697                                 int temp;
4698                                 
4699                                 mono_castclass = mono_marshal_get_castclass (klass); 
4700                                 iargs [0] = sp [0];
4701                                 
4702                                 costs = inline_method (cfg, mono_castclass, mono_castclass->signature, bblock, 
4703                                                            iargs, ip, real_offset, dont_inline, &ebblock, TRUE);
4704                         
4705                                 g_assert (costs > 0);
4706                                 
4707                                 ip += 5;
4708                                 real_offset += 5;
4709                         
4710                                 GET_BBLOCK (cfg, bbhash, bblock, ip);
4711                                 ebblock->next_bb = bblock;
4712                                 link_bblock (cfg, ebblock, bblock);
4713
4714                                 temp = iargs [0]->inst_i0->inst_c0;
4715                                 NEW_TEMPLOAD (cfg, *sp, temp);
4716                                 
4717                                 sp++;
4718                                 bblock = ebblock;
4719                                 inline_costs += costs;
4720                         }
4721                         else {
4722                                 MONO_INST_NEW (cfg, ins, *ip);
4723                                 ins->type = STACK_OBJ;
4724                                 ins->inst_left = *sp;
4725                                 ins->klass = klass;
4726                                 ins->inst_newa_class = klass;
4727                                 ins->cil_code = ip;
4728                                 *sp++ = emit_tree (cfg, bblock, ins, ip + 5);
4729                                 ip += 5;
4730                         }
4731                         break;
4732                 case CEE_THROW:
4733                         CHECK_STACK (1);
4734                         MONO_INST_NEW (cfg, ins, *ip);
4735                         --sp;
4736                         ins->inst_left = *sp;
4737                         ins->cil_code = ip++;
4738                         bblock->out_of_line = TRUE;
4739                         MONO_ADD_INS (bblock, ins);
4740                         sp = stack_start;
4741                         link_bblock (cfg, bblock, end_bblock);
4742                         start_new_bblock = 1;
4743                         break;
4744                 case CEE_LDFLD:
4745                 case CEE_LDFLDA:
4746                 case CEE_STFLD: {
4747                         MonoInst *offset_ins;
4748                         MonoClassField *field;
4749                         MonoBasicBlock *ebblock;
4750                         int costs;
4751                         guint foffset;
4752
4753                         if (*ip == CEE_STFLD) {
4754                                 CHECK_STACK (2);
4755                                 sp -= 2;
4756                         } else {
4757                                 CHECK_STACK (1);
4758                                 --sp;
4759                         }
4760                         // FIXME: enable this test later.
4761                         //if (sp [0]->type != STACK_OBJ && sp [0]->type != STACK_MP)
4762                         //      goto unverified;
4763                         CHECK_OPSIZE (5);
4764                         token = read32 (ip + 1);
4765                         field = mono_field_from_token (image, token, &klass, generic_context);
4766                         mono_class_init (klass);
4767
4768                         foffset = klass->valuetype? field->offset - sizeof (MonoObject): field->offset;
4769                         /* FIXME: mark instructions for use in SSA */
4770                         if (*ip == CEE_STFLD) {
4771                                 if ((klass->marshalbyref && !MONO_CHECK_THIS (sp [0])) || klass->contextbound || klass == mono_defaults.marshalbyrefobject_class) {
4772                                         MonoMethod *stfld_wrapper = mono_marshal_get_stfld_wrapper (field->type); 
4773                                         MonoInst *iargs [5];
4774
4775                                         iargs [0] = sp [0];
4776                                         NEW_CLASSCONST (cfg, iargs [1], klass);
4777                                         NEW_FIELDCONST (cfg, iargs [2], field);
4778                                         NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : 
4779                                                     field->offset);
4780                                         iargs [4] = sp [1];
4781
4782                                         if (cfg->opt & MONO_OPT_INLINE) {
4783                                                 costs = inline_method (cfg, stfld_wrapper, stfld_wrapper->signature, bblock, 
4784                                                                        iargs, ip, real_offset, dont_inline, &ebblock, TRUE);
4785                                                 g_assert (costs > 0);
4786                                                       
4787                                                 ip += 5;
4788                                                 real_offset += 5;
4789
4790                                                 GET_BBLOCK (cfg, bbhash, bblock, ip);
4791                                                 ebblock->next_bb = bblock;
4792                                                 link_bblock (cfg, ebblock, bblock);
4793
4794                                                 /* indicates start of a new block, and triggers a load 
4795                                                    of all stack arguments at bb boundarie */
4796                                                 bblock = ebblock;
4797
4798                                                 inline_costs += costs;
4799                                                 break;
4800                                         } else {
4801                                                 mono_emit_method_call_spilled (cfg, bblock, stfld_wrapper, stfld_wrapper->signature, iargs, ip, NULL);
4802                                         }
4803                                 } else {
4804                                         MonoInst *store;
4805                                         NEW_ICONST (cfg, offset_ins, foffset);
4806                                         MONO_INST_NEW (cfg, ins, OP_PADD);
4807                                         ins->cil_code = ip;
4808                                         ins->inst_left = *sp;
4809                                         ins->inst_right = offset_ins;
4810                                         ins->type = STACK_MP;
4811
4812                                         MONO_INST_NEW (cfg, store, mono_type_to_stind (field->type));
4813                                         store->cil_code = ip;
4814                                         store->inst_left = ins;
4815                                         store->inst_right = sp [1];
4816                                         handle_loaded_temps (cfg, bblock, stack_start, sp);
4817                                         store->flags |= ins_flag;
4818                                         ins_flag = 0;
4819                                         if (store->opcode == CEE_STOBJ) {
4820                                                 handle_stobj (cfg, bblock, ins, sp [1], ip, 
4821                                                               mono_class_from_mono_type (field->type), FALSE, FALSE);
4822                                         } else
4823                                                 MONO_ADD_INS (bblock, store);
4824                                 }
4825                         } else {
4826                                 if ((klass->marshalbyref && !MONO_CHECK_THIS (sp [0])) || klass->contextbound || klass == mono_defaults.marshalbyrefobject_class) {
4827                                         /* fixme: we need to inline that call somehow */
4828                                         MonoMethod *ldfld_wrapper = mono_marshal_get_ldfld_wrapper (field->type); 
4829                                         MonoInst *iargs [4];
4830                                         int temp;
4831                                         
4832                                         iargs [0] = sp [0];
4833                                         NEW_CLASSCONST (cfg, iargs [1], klass);
4834                                         NEW_FIELDCONST (cfg, iargs [2], field);
4835                                         NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : field->offset);
4836                                         if (cfg->opt & MONO_OPT_INLINE) {
4837                                                 costs = inline_method (cfg, ldfld_wrapper, ldfld_wrapper->signature, bblock, 
4838                                                                        iargs, ip, real_offset, dont_inline, &ebblock, TRUE);
4839                                                 g_assert (costs > 0);
4840                                                       
4841                                                 ip += 5;
4842                                                 real_offset += 5;
4843
4844                                                 GET_BBLOCK (cfg, bbhash, bblock, ip);
4845                                                 ebblock->next_bb = bblock;
4846                                                 link_bblock (cfg, ebblock, bblock);
4847
4848                                                 temp = iargs [0]->inst_i0->inst_c0;
4849
4850                                                 if (*ip == CEE_LDFLDA) {
4851                                                         /* not sure howto handle this */
4852                                                         NEW_TEMPLOADA (cfg, *sp, temp);
4853                                                 } else {
4854                                                         NEW_TEMPLOAD (cfg, *sp, temp);
4855                                                 }
4856                                                 sp++;
4857
4858                                                 /* indicates start of a new block, and triggers a load of
4859                                                    all stack arguments at bb boundarie */
4860                                                 bblock = ebblock;
4861                                                 
4862                                                 inline_costs += costs;
4863                                                 break;
4864                                         } else {
4865                                                 temp = mono_emit_method_call_spilled (cfg, bblock, ldfld_wrapper, ldfld_wrapper->signature, iargs, ip, NULL);
4866                                                 if (*ip == CEE_LDFLDA) {
4867                                                         /* not sure howto handle this */
4868                                                         NEW_TEMPLOADA (cfg, *sp, temp);
4869                                                 } else {
4870                                                         NEW_TEMPLOAD (cfg, *sp, temp);
4871                                                 }
4872                                                 sp++;
4873                                         }
4874                                 } else {
4875                                         NEW_ICONST (cfg, offset_ins, foffset);
4876                                         MONO_INST_NEW (cfg, ins, OP_PADD);
4877                                         ins->cil_code = ip;
4878                                         ins->inst_left = *sp;
4879                                         ins->inst_right = offset_ins;
4880                                         ins->type = STACK_MP;
4881
4882                                         if (*ip == CEE_LDFLDA) {
4883                                                 *sp++ = ins;
4884                                         } else {
4885                                                 MonoInst *load;
4886                                                 MONO_INST_NEW (cfg, load, mono_type_to_ldind (field->type));
4887                                                 type_to_eval_stack_type (field->type, load);
4888                                                 load->cil_code = ip;
4889                                                 load->inst_left = ins;
4890                                                 load->flags |= ins_flag;
4891                                                 ins_flag = 0;
4892                                                 *sp++ = load;
4893                                         }
4894                                 }
4895                         }
4896                         ip += 5;
4897                         break;
4898                 }
4899                 case CEE_LDSFLD:
4900                 case CEE_LDSFLDA:
4901                 case CEE_STSFLD: {
4902                         MonoClassField *field;
4903                         gpointer addr = NULL;
4904
4905                         CHECK_OPSIZE (5);
4906                         token = read32 (ip + 1);
4907
4908                         field = mono_field_from_token (image, token, &klass, generic_context);
4909                         mono_class_init (klass);
4910
4911                         if ((*ip) == CEE_STSFLD)
4912                                 handle_loaded_temps (cfg, bblock, stack_start, sp);
4913
4914                         /* The special_static_fields field is init'd in mono_class_vtable, so it needs
4915                          * to be called here.
4916                          */
4917                         if (!(cfg->opt & MONO_OPT_SHARED))
4918                                 mono_class_vtable (cfg->domain, klass);
4919                         
4920                         if (cfg->domain->special_static_fields)
4921                                 addr = g_hash_table_lookup (cfg->domain->special_static_fields, field);
4922
4923                         if ((cfg->opt & MONO_OPT_SHARED) || (cfg->compile_aot && addr)) {
4924                                 int temp;
4925                                 MonoInst *iargs [2];
4926                                 g_assert (field->parent);
4927                                 NEW_TEMPLOAD (cfg, iargs [0], mono_get_domainvar (cfg)->inst_c0);
4928                                 NEW_FIELDCONST (cfg, iargs [1], field);
4929                                 temp = mono_emit_jit_icall (cfg, bblock, mono_class_static_field_address, iargs, ip);
4930                                 NEW_TEMPLOAD (cfg, ins, temp);
4931                         } else {
4932                                 MonoVTable *vtable;
4933                                 vtable = mono_class_vtable (cfg->domain, klass);
4934                                 if (!addr) {
4935                                         if ((!vtable->initialized || cfg->compile_aot) && !(klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) && mono_class_needs_cctor_run (klass, method)) {
4936                                                 guint8 *tramp = mono_create_class_init_trampoline (vtable);
4937                                                 mono_emit_native_call (cfg, bblock, tramp, 
4938                                                                                            helper_sig_class_init_trampoline,
4939                                                                                            NULL, ip, FALSE, FALSE);
4940                                                 if (cfg->verbose_level > 2)
4941                                                         g_print ("class %s.%s needs init call for %s\n", klass->name_space, klass->name, field->name);
4942                                         } else {
4943                                                 if (cfg->run_cctors)
4944                                                         mono_runtime_class_init (vtable);
4945                                         }
4946                                         addr = (char*)vtable->data + field->offset;
4947
4948                                         if (cfg->compile_aot)
4949                                                 NEW_SFLDACONST (cfg, ins, field);
4950                                         else
4951                                                 NEW_PCONST (cfg, ins, addr);
4952                                         ins->cil_code = ip;
4953                                 } else {
4954                                         /* 
4955                                          * insert call to mono_threads_get_static_data (GPOINTER_TO_UINT (addr)) 
4956                                          * This could be later optimized to do just a couple of
4957                                          * memory dereferences with constant offsets.
4958                                          */
4959                                         int temp;
4960                                         MonoInst *iargs [1];
4961                                         NEW_ICONST (cfg, iargs [0], GPOINTER_TO_UINT (addr));
4962                                         temp = mono_emit_jit_icall (cfg, bblock, mono_get_special_static_data, iargs, ip);
4963                                         NEW_TEMPLOAD (cfg, ins, temp);
4964                                 }
4965                         }
4966
4967                         /* FIXME: mark instructions for use in SSA */
4968                         if (*ip == CEE_LDSFLDA) {
4969                                 *sp++ = ins;
4970                         } else if (*ip == CEE_STSFLD) {
4971                                 MonoInst *store;
4972                                 CHECK_STACK (1);
4973                                 sp--;
4974                                 MONO_INST_NEW (cfg, store, mono_type_to_stind (field->type));
4975                                 store->cil_code = ip;
4976                                 store->inst_left = ins;
4977                                 store->inst_right = sp [0];
4978                                 store->flags |= ins_flag;
4979                                 ins_flag = 0;
4980
4981                                 if (store->opcode == CEE_STOBJ) {
4982                                         handle_stobj (cfg, bblock, ins, sp [0], ip, mono_class_from_mono_type (field->type), FALSE, FALSE);
4983                                 } else
4984                                         MONO_ADD_INS (bblock, store);
4985                         } else {
4986                                 gboolean is_const = FALSE;
4987                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
4988                                 if (!((cfg->opt & MONO_OPT_SHARED) || cfg->compile_aot) && 
4989                                     vtable->initialized && (field->type->attrs & FIELD_ATTRIBUTE_INIT_ONLY)) {
4990                                         gpointer addr = (char*)vtable->data + field->offset;
4991                                         /* g_print ("RO-FIELD %s.%s:%s\n", klass->name_space, klass->name, field->name);*/
4992                                         is_const = TRUE;
4993                                         switch (field->type->type) {
4994                                         case MONO_TYPE_BOOLEAN:
4995                                         case MONO_TYPE_U1:
4996                                                 NEW_ICONST (cfg, *sp, *((guint8 *)addr));
4997                                                 sp++;
4998                                                 break;
4999                                         case MONO_TYPE_I1:
5000                                                 NEW_ICONST (cfg, *sp, *((gint8 *)addr));
5001                                                 sp++;
5002                                                 break;                                          
5003                                         case MONO_TYPE_CHAR:
5004                                         case MONO_TYPE_U2:
5005                                                 NEW_ICONST (cfg, *sp, *((guint16 *)addr));
5006                                                 sp++;
5007                                                 break;
5008                                         case MONO_TYPE_I2:
5009                                                 NEW_ICONST (cfg, *sp, *((gint16 *)addr));
5010                                                 sp++;
5011                                                 break;
5012                                                 break;
5013                                         case MONO_TYPE_I4:
5014                                                 NEW_ICONST (cfg, *sp, *((gint32 *)addr));
5015                                                 sp++;
5016                                                 break;                                          
5017                                         case MONO_TYPE_U4:
5018                                                 NEW_ICONST (cfg, *sp, *((guint32 *)addr));
5019                                                 sp++;
5020                                                 break;
5021                                         case MONO_TYPE_I:
5022                                         case MONO_TYPE_U:
5023                                         case MONO_TYPE_STRING:
5024                                         case MONO_TYPE_OBJECT:
5025                                         case MONO_TYPE_CLASS:
5026                                         case MONO_TYPE_SZARRAY:
5027                                         case MONO_TYPE_PTR:
5028                                         case MONO_TYPE_FNPTR:
5029                                         case MONO_TYPE_ARRAY:
5030                                                 NEW_PCONST (cfg, *sp, *((gpointer *)addr));
5031                                                 type_to_eval_stack_type (field->type, *sp);
5032                                                 sp++;
5033                                                 break;
5034                                         case MONO_TYPE_I8:
5035                                         case MONO_TYPE_U8:
5036                                                 MONO_INST_NEW (cfg, *sp, OP_I8CONST);
5037                                                 sp [0]->type = STACK_I8;
5038                                                 sp [0]->inst_l = *((gint64 *)addr);
5039                                                 sp++;
5040                                                 break;
5041                                         case MONO_TYPE_R4:
5042                                         case MONO_TYPE_R8:
5043                                         case MONO_TYPE_VALUETYPE:
5044                                         default:
5045                                                 is_const = FALSE;
5046                                                 break;
5047                                         }
5048                                 }
5049
5050                                 if (!is_const) {
5051                                         MonoInst *load;
5052                                         CHECK_STACK_OVF (1);
5053                                         MONO_INST_NEW (cfg, load, mono_type_to_ldind (field->type));
5054                                         type_to_eval_stack_type (field->type, load);
5055                                         load->cil_code = ip;
5056                                         load->inst_left = ins;
5057                                         *sp++ = load;
5058                                         load->flags |= ins_flag;
5059                                         ins_flag = 0;
5060                                         /* fixme: dont see the problem why this does not work */
5061                                         //cfg->disable_aot = TRUE;
5062                                 }
5063                         }
5064                         ip += 5;
5065                         break;
5066                 }
5067                 case CEE_STOBJ:
5068                         CHECK_STACK (2);
5069                         sp -= 2;
5070                         CHECK_OPSIZE (5);
5071                         token = read32 (ip + 1);
5072                         if (method->wrapper_type != MONO_WRAPPER_NONE)
5073                                 klass = mono_method_get_wrapper_data (method, token);
5074                         else
5075                                 klass = mono_class_get_full (image, token, generic_context);
5076                         mono_class_init (klass);
5077                         n = mono_type_to_stind (&klass->byval_arg);
5078                         if (n == CEE_STOBJ) {
5079                                 handle_stobj (cfg, bblock, sp [0], sp [1], ip, klass, FALSE, FALSE);
5080                         } else {
5081                                 /* FIXME: should check item at sp [1] is compatible with the type of the store. */
5082                                 MonoInst *store;
5083                                 MONO_INST_NEW (cfg, store, n);
5084                                 store->cil_code = ip;
5085                                 store->inst_left = sp [0];
5086                                 store->inst_right = sp [1];
5087                                 store->flags |= ins_flag;
5088                                 MONO_ADD_INS (bblock, store);
5089                         }
5090                         ins_flag = 0;
5091                         ip += 5;
5092                         inline_costs += 1;
5093                         break;
5094                 case CEE_BOX: {
5095                         MonoInst *val;
5096                         CHECK_STACK (1);
5097                         --sp;
5098                         val = *sp;
5099                         CHECK_OPSIZE (5);
5100                         token = read32 (ip + 1);
5101                         if (method->wrapper_type != MONO_WRAPPER_NONE)
5102                                 klass = mono_method_get_wrapper_data (method, token);
5103                         else
5104                                 klass = mono_class_get_full (image, token, generic_context);
5105                         mono_class_init (klass);
5106
5107                         if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
5108                                 *sp++ = val;
5109                                 ip += 5;
5110                                 break;
5111                         }
5112                         *sp++ = handle_box (cfg, bblock, val, ip, klass);
5113                         ip += 5;
5114                         inline_costs += 1;
5115                         break;
5116                 }
5117                 case CEE_NEWARR:
5118                         CHECK_STACK (1);
5119                         MONO_INST_NEW (cfg, ins, *ip);
5120                         ins->cil_code = ip;
5121                         --sp;
5122
5123                         CHECK_OPSIZE (5);
5124                         token = read32 (ip + 1);
5125
5126                         /* allocate the domainvar - becaus this is used in decompose_foreach */
5127                         if (cfg->opt & MONO_OPT_SHARED) {
5128                                 mono_get_domainvar (cfg);
5129                                 /* LAME-IR: Mark it as used since otherwise it will be optimized away */
5130                                 cfg->domainvar->flags |= MONO_INST_VOLATILE;
5131                         }
5132
5133                         /* Ditto */
5134                         mono_get_got_var (cfg);
5135
5136                         if (method->wrapper_type != MONO_WRAPPER_NONE)
5137                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
5138                         else
5139                                 klass = mono_class_get_full (image, token, generic_context);
5140
5141                         mono_class_init (klass);
5142                         ins->inst_newa_class = klass;
5143                         ins->inst_newa_len = *sp;
5144                         ins->type = STACK_OBJ;
5145                         ip += 5;
5146                         *sp++ = ins;
5147                         /* 
5148                          * we store the object so calls to create the array are not interleaved
5149                          * with the arguments of other calls.
5150                          */
5151                         if (1) {
5152                                 MonoInst *store, *temp, *load;
5153                                 --sp;
5154                                 temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
5155                                 NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
5156                                 store->cil_code = ins->cil_code;
5157                                 MONO_ADD_INS (bblock, store);
5158                                 NEW_TEMPLOAD (cfg, load, temp->inst_c0);
5159                                 load->cil_code = ins->cil_code;
5160                                 *sp++ = load;
5161                         }
5162                         inline_costs += 1;
5163                         break;
5164                 case CEE_LDLEN:
5165                         CHECK_STACK (1);
5166                         MONO_INST_NEW (cfg, ins, *ip);
5167                         ins->cil_code = ip++;
5168                         --sp;
5169                         ins->inst_left = *sp;
5170                         ins->type = STACK_PTR;
5171                         *sp++ = ins;
5172                         break;
5173                 case CEE_LDELEMA:
5174                         CHECK_STACK (2);
5175                         sp -= 2;
5176                         CHECK_OPSIZE (5);
5177
5178                         if (method->wrapper_type != MONO_WRAPPER_NONE)
5179                                 klass = (MonoClass*)mono_method_get_wrapper_data (method, read32 (ip + 1));
5180                         else
5181                                 klass = mono_class_get_full (image, read32 (ip + 1), generic_context);
5182                         
5183                         /* we need to make sure that this array is exactly the type it needs
5184                          * to be for correctness. the wrappers are lax with their usage
5185                          * so we need to ignore them here
5186                          */
5187                         if (!klass->valuetype && method->wrapper_type == MONO_WRAPPER_NONE) {
5188                                 MonoInst* check;
5189                                 MONO_INST_NEW (cfg, check, OP_CHECK_ARRAY_TYPE);
5190                                 check->cil_code = ip;
5191                                 check->klass = klass;
5192                                 check->inst_left = sp [0];
5193                                 check->type = STACK_OBJ;
5194                                 sp [0] = check;
5195                         }
5196                         
5197                         mono_class_init (klass);
5198                         NEW_LDELEMA (cfg, ins, sp, klass);
5199                         ins->cil_code = ip;
5200                         *sp++ = ins;
5201                         ip += 5;
5202                         break;
5203                 case CEE_LDELEM_ANY: {
5204                         MonoInst *load;
5205                         CHECK_STACK (2);
5206                         sp -= 2;
5207                         CHECK_OPSIZE (5);
5208                         token = read32 (ip + 1);
5209                         klass = mono_class_get_full (image, token, generic_context);
5210                         mono_class_init (klass);
5211                         NEW_LDELEMA (cfg, load, sp, klass);
5212                         load->cil_code = ip;
5213                         MONO_INST_NEW (cfg, ins, mono_type_to_ldind (&klass->byval_arg));
5214                         ins->cil_code = ip;
5215                         ins->inst_left = load;
5216                         *sp++ = ins;
5217                         type_to_eval_stack_type (&klass->byval_arg, ins);
5218                         ip += 5;
5219                         break;
5220                 }
5221                 case CEE_LDELEM_I1:
5222                 case CEE_LDELEM_U1:
5223                 case CEE_LDELEM_I2:
5224                 case CEE_LDELEM_U2:
5225                 case CEE_LDELEM_I4:
5226                 case CEE_LDELEM_U4:
5227                 case CEE_LDELEM_I8:
5228                 case CEE_LDELEM_I:
5229                 case CEE_LDELEM_R4:
5230                 case CEE_LDELEM_R8:
5231                 case CEE_LDELEM_REF: {
5232                         MonoInst *load;
5233                         /*
5234                          * translate to:
5235                          * ldind.x (ldelema (array, index))
5236                          * ldelema does the bounds check
5237                          */
5238                         CHECK_STACK (2);
5239                         sp -= 2;
5240                         klass = array_access_to_klass (*ip);
5241                         NEW_LDELEMA (cfg, load, sp, klass);
5242                         load->cil_code = ip;
5243                         MONO_INST_NEW (cfg, ins, ldelem_to_ldind [*ip - CEE_LDELEM_I1]);
5244                         ins->cil_code = ip;
5245                         ins->inst_left = load;
5246                         *sp++ = ins;
5247                         ins->type = ldind_type [ins->opcode - CEE_LDIND_I1];
5248                         ++ip;
5249                         break;
5250                 }
5251                 case CEE_STELEM_I:
5252                 case CEE_STELEM_I1:
5253                 case CEE_STELEM_I2:
5254                 case CEE_STELEM_I4:
5255                 case CEE_STELEM_I8:
5256                 case CEE_STELEM_R4:
5257                 case CEE_STELEM_R8: {
5258                         MonoInst *load;
5259                         /*
5260                          * translate to:
5261                          * stind.x (ldelema (array, index), val)
5262                          * ldelema does the bounds check
5263                          */
5264                         CHECK_STACK (3);
5265                         sp -= 3;
5266                         klass = array_access_to_klass (*ip);
5267                         NEW_LDELEMA (cfg, load, sp, klass);
5268                         load->cil_code = ip;
5269                         MONO_INST_NEW (cfg, ins, stelem_to_stind [*ip - CEE_STELEM_I]);
5270                         ins->cil_code = ip;
5271                         ins->inst_left = load;
5272                         ins->inst_right = sp [2];
5273                         ++ip;
5274                         handle_loaded_temps (cfg, bblock, stack_start, sp);
5275                         MONO_ADD_INS (bblock, ins);
5276                         inline_costs += 1;
5277                         break;
5278                 }
5279                 case CEE_STELEM_ANY: {
5280                         MonoInst *load;
5281                         /*
5282                          * translate to:
5283                          * stind.x (ldelema (array, index), val)
5284                          * ldelema does the bounds check
5285                          */
5286                         CHECK_STACK (3);
5287                         sp -= 3;
5288                         CHECK_OPSIZE (5);
5289                         token = read32 (ip + 1);
5290                         klass = mono_class_get_full (image, token, generic_context);
5291                         mono_class_init (klass);
5292                         if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
5293                                 MonoMethod* helper = mono_marshal_get_stelemref ();
5294                                 MonoInst *iargs [3];
5295                                 handle_loaded_temps (cfg, bblock, stack_start, sp);
5296
5297                                 iargs [2] = sp [2];
5298                                 iargs [1] = sp [1];
5299                                 iargs [0] = sp [0];
5300                                 
5301                                 mono_emit_method_call_spilled (cfg, bblock, helper, helper->signature, iargs, ip, NULL);
5302                         } else {
5303                                 NEW_LDELEMA (cfg, load, sp, klass);
5304                                 load->cil_code = ip;
5305
5306                                 n = mono_type_to_stind (&klass->byval_arg);
5307                                 if (n == CEE_STOBJ)
5308                                         handle_stobj (cfg, bblock, load, sp [2], ip, klass, FALSE, FALSE);
5309                                 else {
5310                                         MONO_INST_NEW (cfg, ins, n);
5311                                         ins->cil_code = ip;
5312                                         ins->inst_left = load;
5313                                         ins->inst_right = sp [2];
5314                                         handle_loaded_temps (cfg, bblock, stack_start, sp);
5315                                         MONO_ADD_INS (bblock, ins);
5316                                 }
5317                         }
5318                         ip += 5;
5319                         inline_costs += 1;
5320                         break;
5321                 }
5322                 case CEE_STELEM_REF: {
5323                         MonoInst *iargs [3];
5324                         MonoMethod* helper = mono_marshal_get_stelemref ();
5325
5326                         CHECK_STACK (3);
5327                         sp -= 3;
5328
5329                         handle_loaded_temps (cfg, bblock, stack_start, sp);
5330
5331                         iargs [2] = sp [2];
5332                         iargs [1] = sp [1];
5333                         iargs [0] = sp [0];
5334                         
5335                         mono_emit_method_call_spilled (cfg, bblock, helper, helper->signature, iargs, ip, NULL);
5336
5337                         /*
5338                         MonoInst *group;
5339                         NEW_GROUP (cfg, group, sp [0], sp [1]);
5340                         MONO_INST_NEW (cfg, ins, CEE_STELEM_REF);
5341                         ins->cil_code = ip;
5342                         ins->inst_left = group;
5343                         ins->inst_right = sp [2];
5344                         MONO_ADD_INS (bblock, ins);
5345                         */
5346
5347                         ++ip;
5348                         inline_costs += 1;
5349                         break;
5350                 }
5351                 case CEE_CKFINITE: {
5352                         MonoInst *store, *temp;
5353                         CHECK_STACK (1);
5354
5355                         /* this instr. can throw exceptions as side effect,
5356                          * so we cant eliminate dead code which contains CKFINITE opdodes.
5357                          * Spilling to memory makes sure that we always perform
5358                          * this check */
5359
5360                         
5361                         MONO_INST_NEW (cfg, ins, CEE_CKFINITE);
5362                         ins->cil_code = ip;
5363                         ins->inst_left = sp [-1];
5364                         temp = mono_compile_create_var (cfg, &mono_defaults.double_class->byval_arg, OP_LOCAL);
5365
5366                         NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
5367                         store->cil_code = ip;
5368                         MONO_ADD_INS (bblock, store);
5369
5370                         NEW_TEMPLOAD (cfg, sp [-1], temp->inst_c0);
5371                        
5372                         ++ip;
5373                         break;
5374                 }
5375                 case CEE_REFANYVAL:
5376                         CHECK_STACK (1);
5377                         MONO_INST_NEW (cfg, ins, *ip);
5378                         --sp;
5379                         CHECK_OPSIZE (5);
5380                         klass = mono_class_get_full (image, read32 (ip + 1), generic_context);
5381                         mono_class_init (klass);
5382                         ins->type = STACK_MP;
5383                         ins->inst_left = *sp;
5384                         ins->klass = klass;
5385                         ins->inst_newa_class = klass;
5386                         ins->cil_code = ip;
5387                         ip += 5;
5388                         *sp++ = ins;
5389                         break;
5390                 case CEE_MKREFANY: {
5391                         MonoInst *loc, *klassconst;
5392
5393                         CHECK_STACK (1);
5394                         MONO_INST_NEW (cfg, ins, *ip);
5395                         --sp;
5396                         CHECK_OPSIZE (5);
5397                         klass = mono_class_get_full (image, read32 (ip + 1), generic_context);
5398                         mono_class_init (klass);
5399                         ins->cil_code = ip;
5400
5401                         loc = mono_compile_create_var (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL);
5402                         NEW_TEMPLOADA (cfg, ins->inst_right, loc->inst_c0);
5403
5404                         NEW_PCONST (cfg, klassconst, klass);
5405                         NEW_GROUP (cfg, ins->inst_left, *sp, klassconst);
5406                         
5407                         MONO_ADD_INS (bblock, ins);
5408
5409                         NEW_TEMPLOAD (cfg, *sp, loc->inst_c0);
5410                         ++sp;
5411                         ip += 5;
5412                         break;
5413                 }
5414                 case CEE_LDTOKEN: {
5415                         gpointer handle;
5416                         MonoClass *handle_class;
5417
5418                         CHECK_STACK_OVF (1);
5419
5420                         CHECK_OPSIZE (5);
5421                         n = read32 (ip + 1);
5422
5423                         handle = mono_ldtoken (image, n, &handle_class, generic_context);
5424                         mono_class_init (handle_class);
5425
5426                         if (cfg->opt & MONO_OPT_SHARED) {
5427                                 int temp;
5428                                 MonoInst *res, *store, *addr, *vtvar, *iargs [3];
5429
5430                                 vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL); 
5431
5432                                 NEW_IMAGECONST (cfg, iargs [0], image);
5433                                 NEW_ICONST (cfg, iargs [1], n);
5434                                 NEW_PCONST (cfg, iargs [2], generic_context);
5435                                 temp = mono_emit_jit_icall (cfg, bblock, mono_ldtoken_wrapper, iargs, ip);
5436                                 NEW_TEMPLOAD (cfg, res, temp);
5437                                 NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
5438                                 NEW_INDSTORE (cfg, store, addr, res, &mono_defaults.int_class->byval_arg);
5439                                 MONO_ADD_INS (bblock, store);
5440                                 NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
5441                         } else {
5442                                 if ((ip [5] == CEE_CALL) && (cmethod = mini_get_method (image, read32 (ip + 6), NULL, generic_context)) &&
5443                                                 (cmethod->klass == mono_defaults.monotype_class->parent) &&
5444                                                 (strcmp (cmethod->name, "GetTypeFromHandle") == 0) && ip_in_bb (cfg, bblock, ip + 5)) {
5445                                         MonoClass *tclass = mono_class_from_mono_type (handle);
5446                                         mono_class_init (tclass);
5447                                         if (cfg->compile_aot)
5448                                                 NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, image, n);
5449                                         else
5450                                                 NEW_PCONST (cfg, ins, mono_type_get_object (cfg->domain, handle));
5451                                         ins->type = STACK_OBJ;
5452                                         ins->klass = cmethod->klass;
5453                                         ip += 5;
5454                                 } else {
5455                                         MonoInst *store, *addr, *vtvar;
5456
5457                                         if (cfg->compile_aot)
5458                                                 NEW_LDTOKENCONST (cfg, ins, image, n);
5459                                         else
5460                                                 NEW_PCONST (cfg, ins, handle);
5461                                         vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL);
5462                                         NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
5463                                         NEW_INDSTORE (cfg, store, addr, ins, &mono_defaults.int_class->byval_arg);
5464                                         MONO_ADD_INS (bblock, store);
5465                                         NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
5466                                 }
5467                         }
5468
5469                         *sp++ = ins;
5470                         ip += 5;
5471                         break;
5472                 }
5473                 case CEE_CONV_U2:
5474                 case CEE_CONV_U1:
5475                 case CEE_CONV_I:
5476                         CHECK_STACK (1);
5477                         ADD_UNOP (*ip);
5478                         ip++;
5479                         break;
5480                 case CEE_ADD_OVF:
5481                 case CEE_ADD_OVF_UN:
5482                 case CEE_MUL_OVF:
5483                 case CEE_MUL_OVF_UN:
5484                 case CEE_SUB_OVF:
5485                 case CEE_SUB_OVF_UN:
5486                         CHECK_STACK (2);
5487                         ADD_BINOP (*ip);
5488                         if (mono_find_jit_opcode_emulation (ins->opcode)) {
5489                                 --sp;
5490                                 *sp++ = emit_tree (cfg, bblock, ins, ip + 1);
5491                         }
5492                         ip++;
5493                         break;
5494                 case CEE_ENDFINALLY:
5495                         MONO_INST_NEW (cfg, ins, *ip);
5496                         MONO_ADD_INS (bblock, ins);
5497                         ins->cil_code = ip++;
5498                         start_new_bblock = 1;
5499
5500                         /*
5501                          * Control will leave the method so empty the stack, otherwise
5502                          * the next basic block will start with a nonempty stack.
5503                          */
5504                         while (sp != stack_start) {
5505                                 MONO_INST_NEW (cfg, ins, CEE_POP);
5506                                 ins->cil_code = ip;
5507                                 sp--;
5508                                 ins->inst_i0 = *sp;
5509                                 MONO_ADD_INS (bblock, ins);
5510                         }
5511                         break;
5512                 case CEE_LEAVE:
5513                 case CEE_LEAVE_S: {
5514                         GList *handlers;
5515                         if (*ip == CEE_LEAVE) {
5516                                 CHECK_OPSIZE (5);
5517                                 target = ip + 5 + (gint32)read32(ip + 1);
5518                         } else {
5519                                 CHECK_OPSIZE (2);
5520                                 target = ip + 2 + (signed char)(ip [1]);
5521                         }
5522
5523                         /* empty the stack */
5524                         while (sp != stack_start) {
5525                                 MONO_INST_NEW (cfg, ins, CEE_POP);
5526                                 ins->cil_code = ip;
5527                                 sp--;
5528                                 ins->inst_i0 = *sp;
5529                                 MONO_ADD_INS (bblock, ins);
5530                         }
5531
5532                         /* 
5533                          * If this leave statement is in a catch block, check for a
5534                          * pending exception, and rethrow it if necessary.
5535                          */
5536                         for (i = 0; i < header->num_clauses; ++i) {
5537                                 MonoExceptionClause *clause = &header->clauses [i];
5538                                 if (MONO_OFFSET_IN_HANDLER (clause, ip - header->code)) {
5539                                         int temp;
5540
5541                                         temp = mono_emit_jit_icall (cfg, bblock, mono_thread_get_pending_exception, NULL, ip);
5542                                         NEW_TEMPLOAD (cfg, *sp, temp);
5543
5544                                         MONO_INST_NEW (cfg, ins, OP_THROW_OR_NULL);
5545                                         ins->inst_left = *sp;
5546                                         ins->cil_code = ip;
5547                                         MONO_ADD_INS (bblock, ins);
5548                                 }
5549                         }
5550
5551                         /* fixme: call fault handler ? */
5552
5553                         if ((handlers = mono_find_final_block (cfg, ip, target, MONO_EXCEPTION_CLAUSE_FINALLY))) {
5554                                 GList *tmp;
5555                                 for (tmp = handlers; tmp; tmp = tmp->next) {
5556                                         tblock = tmp->data;
5557                                         link_bblock (cfg, bblock, tblock);
5558                                         MONO_INST_NEW (cfg, ins, OP_CALL_HANDLER);
5559                                         ins->cil_code = ip;
5560                                         ins->inst_target_bb = tblock;
5561                                         MONO_ADD_INS (bblock, ins);
5562                                 }
5563                                 g_list_free (handlers);
5564                         } 
5565
5566                         MONO_INST_NEW (cfg, ins, CEE_BR);
5567                         ins->cil_code = ip;
5568                         MONO_ADD_INS (bblock, ins);
5569                         GET_BBLOCK (cfg, bbhash, tblock, target);
5570                         link_bblock (cfg, bblock, tblock);
5571                         CHECK_BBLOCK (target, ip, tblock);
5572                         ins->inst_target_bb = tblock;
5573                         start_new_bblock = 1;
5574
5575                         if (*ip == CEE_LEAVE)
5576                                 ip += 5;
5577                         else
5578                                 ip += 2;
5579
5580                         break;
5581                 }
5582                 case CEE_STIND_I:
5583                         CHECK_STACK (2);
5584                         MONO_INST_NEW (cfg, ins, *ip);
5585                         sp -= 2;
5586                         handle_loaded_temps (cfg, bblock, stack_start, sp);
5587                         MONO_ADD_INS (bblock, ins);
5588                         ins->cil_code = ip++;
5589                         ins->inst_i0 = sp [0];
5590                         ins->inst_i1 = sp [1];
5591                         inline_costs += 1;
5592                         break;
5593                 case CEE_CONV_U:
5594                         CHECK_STACK (1);
5595                         ADD_UNOP (*ip);
5596                         ip++;
5597                         break;
5598                 /* trampoline mono specific opcodes */
5599                 case MONO_CUSTOM_PREFIX: {
5600
5601                         g_assert (method->wrapper_type != MONO_WRAPPER_NONE);
5602
5603                         CHECK_OPSIZE (2);
5604                         switch (ip [1]) {
5605
5606                         case CEE_MONO_ICALL: {
5607                                 int temp;
5608                                 gpointer func;
5609                                 MonoJitICallInfo *info;
5610
5611                                 token = read32 (ip + 2);
5612                                 func = mono_method_get_wrapper_data (method, token);
5613                                 info = mono_find_jit_icall_by_addr (func);
5614                                 g_assert (info);
5615
5616                                 CHECK_STACK (info->sig->param_count);
5617                                 sp -= info->sig->param_count;
5618
5619                                 temp = mono_emit_jit_icall (cfg, bblock, info->func, sp, ip);
5620                                 if (!MONO_TYPE_IS_VOID (info->sig->ret)) {
5621                                         NEW_TEMPLOAD (cfg, *sp, temp);
5622                                         sp++;
5623                                 }
5624
5625                                 ip += 6;
5626                                 inline_costs += 10 * num_calls++;
5627
5628                                 break;
5629                         }
5630                         case CEE_MONO_LDPTR:
5631                                 CHECK_STACK_OVF (1);
5632                                 CHECK_OPSIZE (6);
5633                                 token = read32 (ip + 2);
5634                                 NEW_PCONST (cfg, ins, mono_method_get_wrapper_data (method, token));
5635                                 ins->cil_code = ip;
5636                                 *sp++ = ins;
5637                                 ip += 6;
5638                                 inline_costs += 10 * num_calls++;
5639                                 /* Can't embed random pointers into AOT code */
5640                                 cfg->disable_aot = 1;
5641                                 break;
5642                         case CEE_MONO_VTADDR:
5643                                 CHECK_STACK (1);
5644                                 --sp;
5645                                 MONO_INST_NEW (cfg, ins, OP_VTADDR);
5646                                 ins->cil_code = ip;
5647                                 ins->type = STACK_MP;
5648                                 ins->inst_left = *sp;
5649                                 *sp++ = ins;
5650                                 ip += 2;
5651                                 break;
5652                         case CEE_MONO_NEWOBJ: {
5653                                 MonoInst *iargs [2];
5654                                 int temp;
5655                                 CHECK_STACK_OVF (1);
5656                                 CHECK_OPSIZE (6);
5657                                 token = read32 (ip + 2);
5658                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
5659                                 mono_class_init (klass);
5660                                 NEW_DOMAINCONST (cfg, iargs [0]);
5661                                 NEW_CLASSCONST (cfg, iargs [1], klass);
5662                                 temp = mono_emit_jit_icall (cfg, bblock, mono_object_new, iargs, ip);
5663                                 NEW_TEMPLOAD (cfg, *sp, temp);
5664                                 sp++;
5665                                 ip += 6;
5666                                 inline_costs += 10 * num_calls++;
5667                                 break;
5668                         }
5669                         case CEE_MONO_OBJADDR:
5670                                 CHECK_STACK (1);
5671                                 --sp;
5672                                 MONO_INST_NEW (cfg, ins, OP_OBJADDR);
5673                                 ins->cil_code = ip;
5674                                 ins->type = STACK_MP;
5675                                 ins->inst_left = *sp;
5676                                 *sp++ = ins;
5677                                 ip += 2;
5678                                 break;
5679                         case CEE_MONO_LDNATIVEOBJ:
5680                                 CHECK_STACK (1);
5681                                 CHECK_OPSIZE (6);
5682                                 token = read32 (ip + 2);
5683                                 klass = mono_method_get_wrapper_data (method, token);
5684                                 g_assert (klass->valuetype);
5685                                 mono_class_init (klass);
5686                                 NEW_INDLOAD (cfg, ins, sp [-1], &klass->byval_arg);
5687                                 sp [-1] = ins;
5688                                 ip += 6;
5689                                 break;
5690                         case CEE_MONO_RETOBJ:
5691                                 g_assert (cfg->ret);
5692                                 g_assert (method->signature->pinvoke); 
5693                                 CHECK_STACK (1);
5694                                 --sp;
5695                                 
5696                                 CHECK_OPSIZE (6);
5697                                 token = read32 (ip + 2);    
5698                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
5699
5700                                 NEW_RETLOADA (cfg, ins);
5701                                 handle_stobj (cfg, bblock, ins, *sp, ip, klass, FALSE, TRUE);
5702                                 
5703                                 if (sp != stack_start)
5704                                         goto unverified;
5705                                 
5706                                 MONO_INST_NEW (cfg, ins, CEE_BR);
5707                                 ins->cil_code = ip;
5708                                 ins->inst_target_bb = end_bblock;
5709                                 MONO_ADD_INS (bblock, ins);
5710                                 link_bblock (cfg, bblock, end_bblock);
5711                                 start_new_bblock = 1;
5712                                 ip += 6;
5713                                 break;
5714                         case CEE_MONO_CISINST:
5715                         case CEE_MONO_CCASTCLASS: {
5716                                 int token;
5717                                 CHECK_STACK (1);
5718                                 --sp;
5719                                 CHECK_OPSIZE (6);
5720                                 token = read32 (ip + 2);
5721                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
5722                                 MONO_INST_NEW (cfg, ins, (ip [1] == CEE_MONO_CISINST) ? OP_CISINST : OP_CCASTCLASS);
5723                                 ins->type = STACK_I4;
5724                                 ins->inst_left = *sp;
5725                                 ins->inst_newa_class = klass;
5726                                 ins->cil_code = ip;
5727                                 *sp++ = emit_tree (cfg, bblock, ins, ip + 6);
5728                                 ip += 6;
5729                                 break;
5730                         }
5731                         case CEE_MONO_SAVE_LMF:
5732                         case CEE_MONO_RESTORE_LMF:
5733 #ifdef MONO_ARCH_HAVE_LMF_OPS
5734                                 MONO_INST_NEW (cfg, ins, (ip [1] == CEE_MONO_SAVE_LMF) ? OP_SAVE_LMF : OP_RESTORE_LMF);
5735                                 MONO_ADD_INS (bblock, ins);
5736                                 cfg->need_lmf_area = TRUE;
5737 #endif
5738                                 ip += 2;
5739                                 break;
5740                         case CEE_MONO_CLASSCONST:
5741                                 CHECK_STACK_OVF (1);
5742                                 CHECK_OPSIZE (6);
5743                                 token = read32 (ip + 2);
5744                                 NEW_CLASSCONST (cfg, ins, mono_method_get_wrapper_data (method, token));
5745                                 ins->cil_code = ip;
5746                                 *sp++ = ins;
5747                                 ip += 6;
5748                                 inline_costs += 10 * num_calls++;
5749                                 break;
5750                         default:
5751                                 g_error ("opcode 0x%02x 0x%02x not handled", MONO_CUSTOM_PREFIX, ip [1]);
5752                                 break;
5753                         }
5754                         break;
5755                 }
5756                 case CEE_PREFIX1: {
5757                         CHECK_OPSIZE (2);
5758                         switch (ip [1]) {
5759                         case CEE_ARGLIST: {
5760                                 /* somewhat similar to LDTOKEN */
5761                                 MonoInst *addr, *vtvar;
5762                                 CHECK_STACK_OVF (1);
5763                                 vtvar = mono_compile_create_var (cfg, &mono_defaults.argumenthandle_class->byval_arg, OP_LOCAL); 
5764
5765                                 NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
5766                                 addr->cil_code = ip;
5767                                 MONO_INST_NEW (cfg, ins, OP_ARGLIST);
5768                                 ins->cil_code = ip;
5769                                 ins->inst_left = addr;
5770                                 MONO_ADD_INS (bblock, ins);
5771                                 NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
5772                                 ins->cil_code = ip;
5773                                 *sp++ = ins;
5774                                 ip += 2;
5775                                 break;
5776                         }
5777                         case CEE_CEQ:
5778                         case CEE_CGT:
5779                         case CEE_CGT_UN:
5780                         case CEE_CLT:
5781                         case CEE_CLT_UN: {
5782                                 MonoInst *cmp;
5783                                 CHECK_STACK (2);
5784                                 /*
5785                                  * The following transforms:
5786                                  *    CEE_CEQ    into OP_CEQ
5787                                  *    CEE_CGT    into OP_CGT
5788                                  *    CEE_CGT_UN into OP_CGT_UN
5789                                  *    CEE_CLT    into OP_CLT
5790                                  *    CEE_CLT_UN into OP_CLT_UN
5791                                  */
5792                                 MONO_INST_NEW (cfg, cmp, 256 + ip [1]);
5793                                 
5794                                 MONO_INST_NEW (cfg, ins, cmp->opcode);
5795                                 sp -= 2;
5796                                 cmp->inst_i0 = sp [0];
5797                                 cmp->inst_i1 = sp [1];
5798                                 cmp->cil_code = ip;
5799                                 type_from_op (cmp);
5800                                 CHECK_TYPE (cmp);
5801                                 if ((sp [0]->type == STACK_I8) || ((sizeof (gpointer) == 8) && ((sp [0]->type == STACK_PTR) || (sp [0]->type == STACK_OBJ) || (sp [0]->type == STACK_MP))))
5802                                         cmp->opcode = OP_LCOMPARE;
5803                                 else
5804                                         cmp->opcode = OP_COMPARE;
5805                                 ins->cil_code = ip;
5806                                 ins->type = STACK_I4;
5807                                 ins->inst_i0 = cmp;
5808                                 *sp++ = ins;
5809                                 /* spill it to reduce the expression complexity
5810                                  * and workaround bug 54209 
5811                                  */
5812                                 if (cmp->inst_left->type == STACK_I8) {
5813                                         --sp;
5814                                         *sp++ = emit_tree (cfg, bblock, ins, ip + 2);
5815                                 }
5816                                 ip += 2;
5817                                 break;
5818                         }
5819                         case CEE_LDFTN: {
5820                                 MonoInst *argconst;
5821                                 int temp;
5822
5823                                 CHECK_STACK_OVF (1);
5824                                 CHECK_OPSIZE (6);
5825                                 n = read32 (ip + 2);
5826                                 if (method->wrapper_type != MONO_WRAPPER_NONE)
5827                                         cmethod = mono_method_get_wrapper_data (method, n);
5828                                 else {
5829                                         cmethod = mini_get_method (image, n, NULL, generic_context);
5830                                 }
5831
5832                                 mono_class_init (cmethod->klass);
5833                                 handle_loaded_temps (cfg, bblock, stack_start, sp);
5834
5835                                 NEW_METHODCONST (cfg, argconst, cmethod);
5836                                 if (method->wrapper_type != MONO_WRAPPER_SYNCHRONIZED)
5837                                         temp = mono_emit_jit_icall (cfg, bblock, mono_ldftn, &argconst, ip);
5838                                 else
5839                                         temp = mono_emit_jit_icall (cfg, bblock, mono_ldftn_nosync, &argconst, ip);
5840                                 NEW_TEMPLOAD (cfg, *sp, temp);
5841                                 sp ++;
5842                                 
5843                                 ip += 6;
5844                                 inline_costs += 10 * num_calls++;
5845                                 break;
5846                         }
5847                         case CEE_LDVIRTFTN: {
5848                                 MonoInst *args [2];
5849                                 int temp;
5850
5851                                 CHECK_STACK (1);
5852                                 CHECK_OPSIZE (6);
5853                                 n = read32 (ip + 2);
5854                                 if (method->wrapper_type != MONO_WRAPPER_NONE)
5855                                         cmethod = mono_method_get_wrapper_data (method, n);
5856                                 else
5857                                         cmethod = mini_get_method (image, n, NULL, generic_context);
5858
5859                                 mono_class_init (cmethod->klass);
5860                                 handle_loaded_temps (cfg, bblock, stack_start, sp);
5861
5862                                 --sp;
5863                                 args [0] = *sp;
5864                                 NEW_METHODCONST (cfg, args [1], cmethod);
5865                                 temp = mono_emit_jit_icall (cfg, bblock, mono_ldvirtfn, args, ip);
5866                                 NEW_TEMPLOAD (cfg, *sp, temp);
5867                                 sp ++;
5868
5869                                 ip += 6;
5870                                 inline_costs += 10 * num_calls++;
5871                                 break;
5872                         }
5873                         case CEE_LDARG:
5874                                 CHECK_STACK_OVF (1);
5875                                 CHECK_OPSIZE (4);
5876                                 n = read16 (ip + 2);
5877                                 CHECK_ARG (n);
5878                                 NEW_ARGLOAD (cfg, ins, n);
5879                                 ins->cil_code = ip;
5880                                 *sp++ = ins;
5881                                 ip += 4;
5882                                 break;
5883                         case CEE_LDARGA:
5884                                 CHECK_STACK_OVF (1);
5885                                 CHECK_OPSIZE (4);
5886                                 n = read16 (ip + 2);
5887                                 CHECK_ARG (n);
5888                                 NEW_ARGLOADA (cfg, ins, n);
5889                                 ins->cil_code = ip;
5890                                 *sp++ = ins;
5891                                 ip += 4;
5892                                 break;
5893                         case CEE_STARG:
5894                                 CHECK_STACK (1);
5895                                 --sp;
5896                                 handle_loaded_temps (cfg, bblock, stack_start, sp);
5897                                 CHECK_OPSIZE (4);
5898                                 n = read16 (ip + 2);
5899                                 CHECK_ARG (n);
5900                                 NEW_ARGSTORE (cfg, ins, n, *sp);
5901                                 ins->cil_code = ip;
5902                                 if (ins->opcode == CEE_STOBJ) {
5903                                         NEW_ARGLOADA (cfg, ins, n);
5904                                         handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE);
5905                                 } else
5906                                         MONO_ADD_INS (bblock, ins);
5907                                 ip += 4;
5908                                 break;
5909                         case CEE_LDLOC:
5910                                 CHECK_STACK_OVF (1);
5911                                 CHECK_OPSIZE (4);
5912                                 n = read16 (ip + 2);
5913                                 CHECK_LOCAL (n);
5914                                 NEW_LOCLOAD (cfg, ins, n);
5915                                 ins->cil_code = ip;
5916                                 *sp++ = ins;
5917                                 ip += 4;
5918                                 break;
5919                         case CEE_LDLOCA:
5920                                 CHECK_STACK_OVF (1);
5921                                 CHECK_OPSIZE (4);
5922                                 n = read16 (ip + 2);
5923                                 CHECK_LOCAL (n);
5924                                 NEW_LOCLOADA (cfg, ins, n);
5925                                 ins->cil_code = ip;
5926                                 *sp++ = ins;
5927                                 ip += 4;
5928                                 break;
5929                         case CEE_STLOC:
5930                                 CHECK_STACK (1);
5931                                 --sp;
5932                                 CHECK_OPSIZE (4);
5933                                 n = read16 (ip + 2);
5934                                 CHECK_LOCAL (n);
5935                                 handle_loaded_temps (cfg, bblock, stack_start, sp);
5936                                 NEW_LOCSTORE (cfg, ins, n, *sp);
5937                                 ins->cil_code = ip;
5938                                 if (ins->opcode == CEE_STOBJ) {
5939                                         NEW_LOCLOADA (cfg, ins, n);
5940                                         handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE);
5941                                 } else
5942                                         MONO_ADD_INS (bblock, ins);
5943                                 ip += 4;
5944                                 inline_costs += 1;
5945                                 break;
5946                         case CEE_LOCALLOC:
5947                                 CHECK_STACK (1);
5948                                 --sp;
5949                                 if (sp != stack_start) 
5950                                         goto unverified;
5951                                 if (cfg->method != method) 
5952                                         /* 
5953                                          * Inlining this into a loop in a parent could lead to 
5954                                          * stack overflows which is different behavior than the
5955                                          * non-inlined case, thus disable inlining in this case.
5956                                          */
5957                                         goto inline_failure;
5958                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
5959                                 ins->inst_left = *sp;
5960                                 ins->cil_code = ip;
5961                                 ins->type = STACK_MP;
5962
5963                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
5964                                 if (header->init_locals)
5965                                         ins->flags |= MONO_INST_INIT;
5966
5967                                 *sp++ = ins;
5968                                 ip += 2;
5969                                 /* FIXME: set init flag if locals init is set in this method */
5970                                 break;
5971                         case CEE_ENDFILTER: {
5972                                 MonoExceptionClause *clause, *nearest;
5973                                 int cc, nearest_num;
5974
5975                                 CHECK_STACK (1);
5976                                 --sp;
5977                                 if ((sp != stack_start) || (sp [0]->type != STACK_I4)) 
5978                                         goto unverified;
5979                                 MONO_INST_NEW (cfg, ins, OP_ENDFILTER);
5980                                 ins->inst_left = *sp;
5981                                 ins->cil_code = ip;
5982                                 MONO_ADD_INS (bblock, ins);
5983                                 start_new_bblock = 1;
5984                                 ip += 2;
5985
5986                                 nearest = NULL;
5987                                 nearest_num = 0;
5988                                 for (cc = 0; cc < header->num_clauses; ++cc) {
5989                                         clause = &header->clauses [cc];
5990                                         if ((clause->flags & MONO_EXCEPTION_CLAUSE_FILTER) &&
5991                                             (!nearest || (clause->data.filter_offset > nearest->data.filter_offset))) {
5992                                                 nearest = clause;
5993                                                 nearest_num = cc;
5994                                         }
5995                                 }
5996                                 g_assert (nearest);
5997                                 filter_lengths [nearest_num] = (ip - header->code) -  nearest->data.filter_offset;
5998
5999                                 break;
6000                         }
6001                         case CEE_UNALIGNED_:
6002                                 ins_flag |= MONO_INST_UNALIGNED;
6003                                 /* FIXME: record alignment? we can assume 1 for now */
6004                                 CHECK_OPSIZE (3);
6005                                 ip += 3;
6006                                 break;
6007                         case CEE_VOLATILE_:
6008                                 ins_flag |= MONO_INST_VOLATILE;
6009                                 ip += 2;
6010                                 break;
6011                         case CEE_TAIL_:
6012                                 ins_flag   |= MONO_INST_TAILCALL;
6013                                 cfg->flags |= MONO_CFG_HAS_TAIL;
6014                                 /* Can't inline tail calls at this time */
6015                                 inline_costs += 100000;
6016                                 ip += 2;
6017                                 break;
6018                         case CEE_INITOBJ:
6019                                 CHECK_STACK (1);
6020                                 --sp;
6021                                 CHECK_OPSIZE (6);
6022                                 token = read32 (ip + 2);
6023                                 if (method->wrapper_type != MONO_WRAPPER_NONE)
6024                                         klass = mono_method_get_wrapper_data (method, token);
6025                                 else
6026                                         klass = mono_class_get_full (image, token, generic_context);
6027                                 if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
6028                                         MonoInst *store, *load;
6029                                         NEW_PCONST (cfg, load, NULL);
6030                                         load->cil_code = ip;
6031                                         load->type = STACK_OBJ;
6032                                         MONO_INST_NEW (cfg, store, CEE_STIND_REF);
6033                                         store->cil_code = ip;
6034                                         handle_loaded_temps (cfg, bblock, stack_start, sp);
6035                                         MONO_ADD_INS (bblock, store);
6036                                         store->inst_i0 = sp [0];
6037                                         store->inst_i1 = load;
6038                                 } else {
6039                                         handle_initobj (cfg, bblock, *sp, NULL, klass, stack_start, sp);
6040                                 }
6041                                 ip += 6;
6042                                 inline_costs += 1;
6043                                 break;
6044                         case CEE_CONSTRAINED_:
6045                                 /* FIXME: implement */
6046                                 CHECK_OPSIZE (6);
6047                                 token = read32 (ip + 2);
6048                                 constrained_call = mono_class_get_full (image, token, generic_context);
6049                                 ip += 6;
6050                                 break;
6051                         case CEE_CPBLK:
6052                         case CEE_INITBLK: {
6053                                 MonoInst *iargs [3];
6054                                 CHECK_STACK (3);
6055                                 sp -= 3;
6056                                 if ((cfg->opt & MONO_OPT_INTRINS) && (ip [1] == CEE_CPBLK) && (sp [2]->opcode == OP_ICONST) && ((n = sp [2]->inst_c0) <= sizeof (gpointer) * 5)) {
6057                                         MonoInst *copy;
6058                                         MONO_INST_NEW (cfg, copy, OP_MEMCPY);
6059                                         copy->inst_left = sp [0];
6060                                         copy->inst_right = sp [1];
6061                                         copy->cil_code = ip;
6062                                         copy->unused = n;
6063                                         MONO_ADD_INS (bblock, copy);
6064                                         ip += 2;
6065                                         break;
6066                                 }
6067                                 iargs [0] = sp [0];
6068                                 iargs [1] = sp [1];
6069                                 iargs [2] = sp [2];
6070                                 handle_loaded_temps (cfg, bblock, stack_start, sp);
6071                                 if (ip [1] == CEE_CPBLK) {
6072                                         mono_emit_jit_icall (cfg, bblock, helper_memcpy, iargs, ip);
6073                                 } else {
6074                                         mono_emit_jit_icall (cfg, bblock, helper_memset, iargs, ip);
6075                                 }
6076                                 ip += 2;
6077                                 inline_costs += 1;
6078                                 break;
6079                         }
6080                         case CEE_NO_:
6081                                 CHECK_OPSIZE (3);
6082                                 if (ip [2] & 0x1)
6083                                         ins_flag |= MONO_INST_NOTYPECHECK;
6084                                 if (ip [2] & 0x2)
6085                                         ins_flag |= MONO_INST_NORANGECHECK;
6086                                 /* we ignore the no-nullcheck for now since we
6087                                  * really do it explicitly only when doing callvirt->call
6088                                  */
6089                                 ip += 3;
6090                                 break;
6091                         case CEE_RETHROW: {
6092                                 MonoInst *load;
6093                                 /* FIXME: check we are in a catch handler */
6094                                 NEW_TEMPLOAD (cfg, load, cfg->exvar->inst_c0);
6095                                 load->cil_code = ip;
6096                                 MONO_INST_NEW (cfg, ins, OP_RETHROW);
6097                                 ins->inst_left = load;
6098                                 ins->cil_code = ip;
6099                                 MONO_ADD_INS (bblock, ins);
6100                                 sp = stack_start;
6101                                 link_bblock (cfg, bblock, end_bblock);
6102                                 start_new_bblock = 1;
6103                                 ip += 2;
6104                                 break;
6105                         }
6106                         case CEE_SIZEOF:
6107                                 CHECK_STACK_OVF (1);
6108                                 CHECK_OPSIZE (6);
6109                                 token = read32 (ip + 2);
6110                                 /* FIXXME: handle generics. */
6111                                 if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC) {
6112                                         MonoType *type = mono_type_create_from_typespec (image, token);
6113                                         token = mono_type_size (type, &align);
6114                                 } else {
6115                                         MonoClass *szclass = mono_class_get_full (image, token, generic_context);
6116                                         mono_class_init (szclass);
6117                                         token = mono_class_value_size (szclass, &align);
6118                                 }
6119                                 NEW_ICONST (cfg, ins, token);
6120                                 ins->cil_code = ip;
6121                                 *sp++= ins;
6122                                 ip += 6;
6123                                 break;
6124                         case CEE_REFANYTYPE:
6125                                 CHECK_STACK (1);
6126                                 MONO_INST_NEW (cfg, ins, OP_REFANYTYPE);
6127                                 --sp;
6128                                 ins->type = STACK_MP;
6129                                 ins->inst_left = *sp;
6130                                 ins->type = STACK_VTYPE;
6131                                 ins->klass = mono_defaults.typehandle_class;
6132                                 ins->cil_code = ip;
6133                                 ip += 2;
6134                                 *sp++ = ins;
6135                                 break;
6136                         case CEE_READONLY_:
6137                                 ip += 2;
6138                                 break;
6139                         default:
6140                                 g_error ("opcode 0xfe 0x%02x not handled", ip [1]);
6141                         }
6142                         break;
6143                 }
6144                 default:
6145                         g_error ("opcode 0x%02x not handled", *ip);
6146                 }
6147         }
6148         if (start_new_bblock != 1)
6149                 goto unverified;
6150
6151         bblock->cil_length = ip - bblock->cil_code;
6152         bblock->next_bb = end_bblock;
6153
6154         if (cfg->method == method && cfg->domainvar) {
6155                 MonoInst *store;
6156                 MonoInst *get_domain;
6157                 
6158                 if (! (get_domain = mono_arch_get_domain_intrinsic (cfg))) {
6159                         MonoCallInst *call;
6160                         
6161                         MONO_INST_NEW_CALL (cfg, call, CEE_CALL);
6162                         call->signature = helper_sig_domain_get;
6163                         call->inst.type = STACK_PTR;
6164                         call->fptr = mono_domain_get;
6165                         get_domain = (MonoInst*)call;
6166                 }
6167                 
6168                 NEW_TEMPSTORE (cfg, store, cfg->domainvar->inst_c0, get_domain);
6169                 MONO_ADD_INS (init_localsbb, store);
6170         }
6171
6172         if (cfg->method == method && cfg->got_var)
6173                 mono_emit_load_got_addr (cfg);
6174
6175         if (header->init_locals) {
6176                 MonoInst *store;
6177                 for (i = 0; i < header->num_locals; ++i) {
6178                         MonoType *ptype = header->locals [i];
6179                         int t = ptype->type;
6180                         if (t == MONO_TYPE_VALUETYPE && ptype->data.klass->enumtype)
6181                                 t = ptype->data.klass->enum_basetype->type;
6182                         /* FIXME: use initobj for valuetypes, handle pointers, long, float. */
6183                         if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
6184                                 NEW_ICONST (cfg, ins, 0);
6185                                 NEW_LOCSTORE (cfg, store, i, ins);
6186                                 MONO_ADD_INS (init_localsbb, store);
6187                         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
6188                                 MONO_INST_NEW (cfg, ins, OP_I8CONST);
6189                                 ins->type = STACK_I8;
6190                                 ins->inst_l = 0;
6191                                 NEW_LOCSTORE (cfg, store, i, ins);
6192                                 MONO_ADD_INS (init_localsbb, store);
6193                         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
6194                                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
6195                                 ins->type = STACK_R8;
6196                                 ins->inst_p0 = (void*)&r8_0;
6197                                 NEW_LOCSTORE (cfg, store, i, ins);
6198                                 MONO_ADD_INS (init_localsbb, store);
6199                         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
6200                                    ((t == MONO_TYPE_GENERICINST) && mono_metadata_generic_class_is_valuetype (ptype->data.generic_class))) {
6201                                 NEW_LOCLOADA (cfg, ins, i);
6202                                 handle_initobj (cfg, init_localsbb, ins, NULL, mono_class_from_mono_type (ptype), NULL, NULL);
6203                                 break;
6204                         } else {
6205                                 NEW_PCONST (cfg, ins, NULL);
6206                                 NEW_LOCSTORE (cfg, store, i, ins);
6207                                 MONO_ADD_INS (init_localsbb, store);
6208                         }
6209                 }
6210         }
6211
6212         /* resolve backward branches in the middle of an existing basic block */
6213         for (tmp = bb_recheck; tmp; tmp = tmp->next) {
6214                 bblock = tmp->data;
6215                 /*g_print ("need recheck in %s at IL_%04x\n", method->name, bblock->cil_code - header->code);*/
6216                 tblock = find_previous (bbhash, start_bblock, bblock->cil_code);
6217                 if (tblock != start_bblock) {
6218                         int l;
6219                         split_bblock (cfg, tblock, bblock);
6220                         l = bblock->cil_code - header->code;
6221                         bblock->cil_length = tblock->cil_length - l;
6222                         tblock->cil_length = l;
6223                 } else {
6224                         g_print ("recheck failed.\n");
6225                 }
6226         }
6227
6228         /*
6229          * we compute regions here, because the length of filter clauses is not known in advance.
6230          * It is computed in the CEE_ENDFILTER case in the above switch statement
6231          */
6232         if (cfg->method == method) {
6233                 MonoBasicBlock *bb;
6234                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
6235                         bb->region = mono_find_block_region (cfg, bb->real_offset, filter_lengths);
6236                         if (cfg->spvars)
6237                                 mono_create_spvar_for_region (cfg, bb->region);
6238                         if (cfg->verbose_level > 2)
6239                                 g_print ("REGION BB%d IL_%04x ID_%08X\n", bb->block_num, bb->real_offset, bb->region);
6240                 }
6241         } else {
6242                 g_hash_table_destroy (bbhash);
6243         }
6244
6245         dont_inline = g_list_remove (dont_inline, method);
6246         return inline_costs;
6247
6248  inline_failure:
6249         if (cfg->method != method) 
6250                 g_hash_table_destroy (bbhash);
6251         dont_inline = g_list_remove (dont_inline, method);
6252         return -1;
6253
6254  unverified:
6255         if (cfg->method != method) 
6256                 g_hash_table_destroy (bbhash);
6257         g_error ("Invalid IL code at IL%04x in %s: %s\n", (int)(ip - header->code), 
6258                  mono_method_full_name (method, TRUE), mono_disasm_code_one (NULL, method, ip, NULL));
6259         dont_inline = g_list_remove (dont_inline, method);
6260         return -1;
6261 }
6262
6263 void
6264 mono_print_tree (MonoInst *tree) {
6265         int arity;
6266
6267         if (!tree)
6268                 return;
6269
6270         arity = mono_burg_arity [tree->opcode];
6271
6272         printf (" %s%s", arity?"(":"",  mono_inst_name (tree->opcode));
6273
6274         switch (tree->opcode) {
6275         case OP_ICONST:
6276                 printf ("[%d]", (int)tree->inst_c0);
6277                 break;
6278         case OP_I8CONST:
6279                 printf ("[%lld]", (long long)tree->inst_l);
6280                 break;
6281         case OP_R8CONST:
6282                 printf ("[%f]", *(double*)tree->inst_p0);
6283                 break;
6284         case OP_R4CONST:
6285                 printf ("[%f]", *(float*)tree->inst_p0);
6286                 break;
6287         case OP_ARG:
6288         case OP_LOCAL:
6289                 printf ("[%d]", (int)tree->inst_c0);
6290                 break;
6291         case OP_REGOFFSET:
6292                 if (tree->inst_offset < 0)
6293                         printf ("[-0x%x(%s)]", (int)(-tree->inst_offset), mono_arch_regname (tree->inst_basereg));
6294                 else
6295                         printf ("[0x%x(%s)]", (int)(tree->inst_offset), mono_arch_regname (tree->inst_basereg));
6296                 break;
6297         case OP_REGVAR:
6298                 printf ("[%s]", mono_arch_regname (tree->dreg));
6299                 break;
6300         case CEE_NEWARR:
6301                 printf ("[%s]",  tree->inst_newa_class->name);
6302                 mono_print_tree (tree->inst_newa_len);
6303                 break;
6304         case CEE_CALL:
6305         case CEE_CALLVIRT:
6306         case OP_FCALL:
6307         case OP_FCALLVIRT:
6308         case OP_LCALL:
6309         case OP_LCALLVIRT:
6310         case OP_VCALL:
6311         case OP_VCALLVIRT:
6312         case OP_VOIDCALL:
6313         case OP_VOIDCALLVIRT: {
6314                 MonoCallInst *call = (MonoCallInst*)tree;
6315                 if (call->method)
6316                         printf ("[%s]", call->method->name);
6317                 break;
6318         }
6319         case OP_PHI: {
6320                 int i;
6321                 printf ("[%d (", (int)tree->inst_c0);
6322                 for (i = 0; i < tree->inst_phi_args [0]; i++) {
6323                         if (i)
6324                                 printf (", ");
6325                         printf ("%d", tree->inst_phi_args [i + 1]);
6326                 }
6327                 printf (")]");
6328                 break;
6329         }
6330         case OP_RENAME:
6331         case OP_RETARG:
6332         case CEE_NOP:
6333         case CEE_JMP:
6334         case CEE_BREAK:
6335                 break;
6336         case OP_LOAD_MEMBASE:
6337         case OP_LOADI4_MEMBASE:
6338         case OP_LOADU4_MEMBASE:
6339         case OP_LOADU1_MEMBASE:
6340         case OP_LOADI1_MEMBASE:
6341         case OP_LOADU2_MEMBASE:
6342         case OP_LOADI2_MEMBASE:
6343                 printf ("[%s] <- [%s + 0x%x]", mono_arch_regname (tree->dreg), mono_arch_regname (tree->inst_basereg), (int)tree->inst_offset);
6344                 break;
6345         case CEE_BR:
6346         case OP_CALL_HANDLER:
6347                 printf ("[B%d]", tree->inst_target_bb->block_num);
6348                 break;
6349         case CEE_SWITCH:
6350         case CEE_ISINST:
6351         case CEE_CASTCLASS:
6352         case OP_OUTARG:
6353         case OP_CALL_REG:
6354         case OP_FCALL_REG:
6355         case OP_LCALL_REG:
6356         case OP_VCALL_REG:
6357         case OP_VOIDCALL_REG:
6358                 mono_print_tree (tree->inst_left);
6359                 break;
6360         case CEE_BNE_UN:
6361         case CEE_BEQ:
6362         case CEE_BLT:
6363         case CEE_BLT_UN:
6364         case CEE_BGT:
6365         case CEE_BGT_UN:
6366         case CEE_BGE:
6367         case CEE_BGE_UN:
6368         case CEE_BLE:
6369         case CEE_BLE_UN:
6370                 printf ("[B%dB%d]", tree->inst_true_bb->block_num, tree->inst_false_bb->block_num);
6371                 mono_print_tree (tree->inst_left);
6372                 break;
6373         default:
6374                 if (!mono_arch_print_tree(tree, arity)) {
6375                         if (arity) {
6376                                 mono_print_tree (tree->inst_left);
6377                                 if (arity > 1)
6378                                         mono_print_tree (tree->inst_right);
6379                         }
6380                 }
6381                 break;
6382         }
6383
6384         if (arity)
6385                 printf (")");
6386 }
6387
6388 void
6389 mono_print_tree_nl (MonoInst *tree)
6390 {
6391         mono_print_tree (tree);
6392         printf ("\n");
6393 }
6394
6395 #define make_icall_sig mono_create_icall_signature
6396
6397 static void
6398 create_helper_signature (void)
6399 {
6400         /* MonoArray * mono_array_new (MonoDomain *domain, MonoClass *klass, gint32 len) */
6401         helper_sig_newarr = make_icall_sig ("object ptr ptr int32");
6402
6403         /* MonoArray * mono_array_new_specific (MonoVTable *vtable, guint32 len) */
6404         helper_sig_newarr_specific = make_icall_sig ("object ptr int32");
6405
6406         /* MonoObject * mono_object_new (MonoDomain *domain, MonoClass *klass) */
6407         helper_sig_object_new = make_icall_sig ("object ptr ptr");
6408
6409         /* MonoObject * mono_object_new_specific (MonoVTable *vtable) */
6410         helper_sig_object_new_specific = make_icall_sig ("object ptr");
6411
6412         /* void* mono_method_compile (MonoMethod*) */
6413         helper_sig_compile = make_icall_sig ("ptr ptr");
6414
6415         /* void* mono_ldvirtfn (MonoObject *, MonoMethod*) */
6416         helper_sig_compile_virt = make_icall_sig ("ptr object ptr");
6417
6418         /* MonoString* mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 str_index) */
6419         helper_sig_ldstr = make_icall_sig ("object ptr ptr int32");
6420
6421         /* MonoDomain *mono_domain_get (void) */
6422         helper_sig_domain_get = make_icall_sig ("ptr");
6423
6424         /* void stelem_ref (MonoArray *, int index, MonoObject *) */
6425         helper_sig_stelem_ref = make_icall_sig ("void ptr int32 object");
6426
6427         /* void stelem_ref_check (MonoArray *, MonoObject *) */
6428         helper_sig_stelem_ref_check = make_icall_sig ("void object object");
6429
6430         /* void *helper_compile_generic_method (MonoObject *, MonoMethod *, MonoGenericContext *) */
6431         helper_sig_compile_generic_method = make_icall_sig ("ptr object ptr ptr");
6432
6433         /* long amethod (long, long) */
6434         helper_sig_long_long_long = make_icall_sig ("long long long");
6435
6436         /* object  amethod (intptr) */
6437         helper_sig_obj_ptr = make_icall_sig ("object ptr");
6438
6439         helper_sig_obj_ptr_ptr = make_icall_sig ("object ptr ptr");
6440
6441         helper_sig_obj_obj_ptr_ptr = make_icall_sig ("object object ptr ptr");
6442
6443         helper_sig_void_void = make_icall_sig ("void");
6444
6445         /* void amethod (intptr) */
6446         helper_sig_void_ptr = make_icall_sig ("void ptr");
6447
6448         /* void amethod (MonoObject *obj) */
6449         helper_sig_void_obj = make_icall_sig ("void object");
6450
6451         /* void amethod (MonoObject *obj, void *ptr, int i) */
6452         helper_sig_void_obj_ptr_int = make_icall_sig ("void object ptr int");
6453
6454         helper_sig_void_obj_ptr_ptr_obj = make_icall_sig ("void object ptr ptr object");
6455
6456         /* intptr amethod (void) */
6457         helper_sig_ptr_void = make_icall_sig ("ptr");
6458
6459         /* object amethod (void) */
6460         helper_sig_obj_void = make_icall_sig ("object");
6461
6462         /* void  amethod (intptr, intptr) */
6463         helper_sig_void_ptr_ptr = make_icall_sig ("void ptr ptr");
6464
6465         /* void  amethod (intptr, intptr, intptr) */
6466         helper_sig_void_ptr_ptr_ptr = make_icall_sig ("void ptr ptr ptr");
6467
6468         /* intptr  amethod (intptr, intptr) */
6469         helper_sig_ptr_ptr_ptr = make_icall_sig ("ptr ptr ptr");
6470
6471         helper_sig_ptr_ptr_ptr_ptr = make_icall_sig ("ptr ptr ptr ptr");
6472
6473         /* IntPtr  amethod (object) */
6474         helper_sig_ptr_obj = make_icall_sig ("ptr object");
6475
6476         /* IntPtr  amethod (object, int) */
6477         helper_sig_ptr_obj_int = make_icall_sig ("ptr object int");
6478
6479         /* IntPtr  amethod (int) */
6480         helper_sig_ptr_int = make_icall_sig ("ptr int32");
6481
6482         /* long amethod (long, guint32) */
6483         helper_sig_long_long_int = make_icall_sig ("long long int32");
6484
6485         /* ulong amethod (double) */
6486         helper_sig_ulong_double = make_icall_sig ("ulong double");
6487
6488         /* long amethod (double) */
6489         helper_sig_long_double = make_icall_sig ("long double");
6490
6491         /* double amethod (long) */
6492         helper_sig_double_long = make_icall_sig ("double long");
6493
6494         /* double amethod (int) */
6495         helper_sig_double_int = make_icall_sig ("double int32");
6496
6497         /* float amethod (long) */
6498         helper_sig_float_long = make_icall_sig ("float long");
6499
6500         /* double amethod (double, double) */
6501         helper_sig_double_double_double = make_icall_sig ("double double double");
6502
6503         /* uint amethod (double) */
6504         helper_sig_uint_double = make_icall_sig ("uint32 double");
6505
6506         /* int amethod (double) */
6507         helper_sig_int_double = make_icall_sig ("int32 double");
6508
6509         /* void  initobj (intptr, int size) */
6510         helper_sig_initobj = make_icall_sig ("void ptr int32");
6511
6512         /* void  memcpy (intptr, intptr, int size) */
6513         helper_sig_memcpy = make_icall_sig ("void ptr ptr int32");
6514
6515         /* void  memset (intptr, int val, int size) */
6516         helper_sig_memset = make_icall_sig ("void ptr int32 int32");
6517
6518         helper_sig_class_init_trampoline = make_icall_sig ("void");
6519 }
6520
6521 gconstpointer
6522 mono_icall_get_wrapper (MonoJitICallInfo* callinfo)
6523 {
6524         char *name;
6525         MonoMethod *wrapper;
6526         gconstpointer code;
6527         
6528         if (callinfo->wrapper)
6529                 return callinfo->wrapper;
6530         
6531         name = g_strdup_printf ("__icall_wrapper_%s", callinfo->name);
6532         wrapper = mono_marshal_get_icall_wrapper (callinfo->sig, name, callinfo->func);
6533         /* Must be domain neutral since there is only one copy */
6534         code = mono_jit_compile_method_with_opt (wrapper, default_opt | MONO_OPT_SHARED);
6535
6536         if (!callinfo->wrapper) {
6537                 callinfo->wrapper = code;
6538                 mono_register_jit_icall_wrapper (callinfo, code);
6539                 mono_debug_add_icall_wrapper (wrapper, callinfo);
6540         }
6541
6542         g_free (name);
6543         return callinfo->wrapper;
6544 }
6545
6546 gpointer
6547 mono_create_class_init_trampoline (MonoVTable *vtable)
6548 {
6549         gpointer code;
6550
6551         /* previously created trampoline code */
6552         mono_domain_lock (vtable->domain);
6553         code = 
6554                 g_hash_table_lookup (vtable->domain->class_init_trampoline_hash,
6555                                                                   vtable);
6556         mono_domain_unlock (vtable->domain);
6557         if (code)
6558                 return code;
6559
6560         code = mono_arch_create_class_init_trampoline (vtable);
6561
6562         /* store trampoline address */
6563         mono_domain_lock (vtable->domain);
6564         g_hash_table_insert (vtable->domain->class_init_trampoline_hash,
6565                                                           vtable, code);
6566         mono_domain_unlock (vtable->domain);
6567
6568         EnterCriticalSection (&jit_mutex);
6569         if (!class_init_hash_addr)
6570                 class_init_hash_addr = g_hash_table_new (NULL, NULL);
6571         g_hash_table_insert (class_init_hash_addr, code, vtable);
6572         LeaveCriticalSection (&jit_mutex);
6573
6574         return code;
6575 }
6576
6577 gpointer
6578 mono_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, 
6579                                                          gboolean add_sync_wrapper)
6580 {
6581         MonoJitInfo *ji;
6582         gpointer code;
6583
6584         if (add_sync_wrapper && method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
6585                 return mono_create_jump_trampoline (domain, mono_marshal_get_synchronized_wrapper (method), FALSE);
6586
6587         code = mono_jit_find_compiled_method (domain, method);
6588         if (code)
6589                 return code;
6590
6591         mono_domain_lock (domain);
6592         code = g_hash_table_lookup (domain->jump_trampoline_hash, method);
6593         mono_domain_unlock (domain);
6594         if (code)
6595                 return code;
6596
6597         ji = mono_arch_create_jump_trampoline (method);
6598
6599         /*
6600          * mono_delegate_ctor needs to find the method metadata from the 
6601          * trampoline address, so we save it here.
6602          */
6603
6604         mono_jit_info_table_add (mono_get_root_domain (), ji);
6605
6606         mono_domain_lock (domain);
6607         g_hash_table_insert (domain->jump_trampoline_hash, method, ji->code_start);
6608         mono_domain_unlock (domain);
6609
6610         return ji->code_start;
6611 }
6612
6613 gpointer
6614 mono_create_jit_trampoline (MonoMethod *method)
6615 {
6616         MonoDomain *domain = mono_domain_get ();
6617         gpointer tramp;
6618
6619         /* Trampoline are domain specific, so cache only the one used in the root domain */
6620         if ((domain == mono_get_root_domain ()) && method->info)
6621                 return method->info;
6622
6623         if (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
6624                 return mono_create_jit_trampoline (mono_marshal_get_synchronized_wrapper (method));
6625
6626         tramp = mono_arch_create_jit_trampoline (method);
6627         if (domain == mono_get_root_domain ())
6628                 method->info = tramp;
6629
6630         mono_jit_stats.method_trampolines++;
6631
6632         return tramp;
6633 }       
6634
6635 MonoVTable*
6636 mono_find_class_init_trampoline_by_addr (gconstpointer addr)
6637 {
6638         MonoVTable *res;
6639
6640         EnterCriticalSection (&jit_mutex);
6641         if (class_init_hash_addr)
6642                 res = g_hash_table_lookup (class_init_hash_addr, addr);
6643         else
6644                 res = NULL;
6645         LeaveCriticalSection (&jit_mutex);
6646         return res;
6647 }
6648
6649 static void
6650 mono_dynamic_code_hash_insert (MonoDomain *domain, MonoMethod *method, MonoJitDynamicMethodInfo *ji)
6651 {
6652         if (!domain->dynamic_code_hash)
6653                 domain->dynamic_code_hash = g_hash_table_new (NULL, NULL);
6654         g_hash_table_insert (domain->dynamic_code_hash, method, ji);
6655 }
6656
6657 static MonoJitDynamicMethodInfo*
6658 mono_dynamic_code_hash_lookup (MonoDomain *domain, MonoMethod *method)
6659 {
6660         MonoJitDynamicMethodInfo *res;
6661
6662         if (domain->dynamic_code_hash)
6663                 res = g_hash_table_lookup (domain->dynamic_code_hash, method);
6664         else
6665                 res = NULL;
6666         return res;
6667 }
6668
6669 void
6670 mono_register_opcode_emulation (int opcode, const char *name, MonoMethodSignature *sig, gpointer func, gboolean no_throw)
6671 {
6672         MonoJitICallInfo *info;
6673
6674         if (!emul_opcode_map)
6675                 emul_opcode_map = g_new0 (MonoJitICallInfo*, OP_LAST + 1);
6676
6677         g_assert (!sig->hasthis);
6678         g_assert (sig->param_count < 3);
6679
6680         info = mono_register_jit_icall (func, name, sig, no_throw);
6681
6682         emul_opcode_map [opcode] = info;
6683 }
6684
6685 static void
6686 decompose_foreach (MonoInst *tree, gpointer data) 
6687 {
6688         static MonoJitICallInfo *newarr_info = NULL;
6689         static MonoJitICallInfo *newarr_specific_info = NULL;
6690         MonoJitICallInfo *info;
6691         int i;
6692
6693         switch (tree->opcode) {
6694         case CEE_NEWARR: {
6695                 MonoCompile *cfg = data;
6696                 MonoInst *iargs [3];
6697
6698                 if (!newarr_info) {
6699                         newarr_info = mono_find_jit_icall_by_addr (mono_array_new);
6700                         g_assert (newarr_info);
6701                         newarr_specific_info = mono_find_jit_icall_by_addr (mono_array_new_specific);
6702                         g_assert (newarr_specific_info);
6703                 }
6704
6705                 if (cfg->opt & MONO_OPT_SHARED) {
6706                         NEW_DOMAINCONST (cfg, iargs [0]);
6707                         NEW_CLASSCONST (cfg, iargs [1], tree->inst_newa_class);
6708                         iargs [2] = tree->inst_newa_len;
6709
6710                         info = newarr_info;
6711                 }
6712                 else {
6713                         MonoVTable *vtable = mono_class_vtable (cfg->domain, mono_array_class_get (tree->inst_newa_class, 1));
6714
6715                         NEW_VTABLECONST (cfg, iargs [0], vtable);
6716                         iargs [1] = tree->inst_newa_len;
6717
6718                         info = newarr_specific_info;
6719                 }
6720
6721                 mono_emulate_opcode (cfg, tree, iargs, info);
6722
6723                 /* Need to decompose arguments after the the opcode is decomposed */
6724                 for (i = 0; i < info->sig->param_count; ++i)
6725                         dec_foreach (iargs [i], cfg);
6726                 break;
6727         }
6728
6729         default:
6730                 break;
6731         }
6732 }
6733
6734 void
6735 mono_inst_foreach (MonoInst *tree, MonoInstFunc func, gpointer data) {
6736
6737         switch (mono_burg_arity [tree->opcode]) {
6738         case 0: break;
6739         case 1: 
6740                 mono_inst_foreach (tree->inst_left, func, data);
6741                 break;
6742         case 2: 
6743                 mono_inst_foreach (tree->inst_left, func, data);
6744                 mono_inst_foreach (tree->inst_right, func, data);
6745                 break;
6746         default:
6747                 g_assert_not_reached ();
6748         }
6749         func (tree, data);
6750 }
6751
6752 G_GNUC_UNUSED
6753 static void
6754 mono_print_bb_code (MonoBasicBlock *bb) {
6755         if (bb->code) {
6756                 MonoInst *c = bb->code;
6757                 while (c) {
6758                         mono_print_tree (c);
6759                         g_print ("\n");
6760                         c = c->next;
6761                 }
6762         }
6763 }
6764
6765 static void
6766 print_dfn (MonoCompile *cfg) {
6767         int i, j;
6768         char *code;
6769         MonoBasicBlock *bb;
6770
6771         g_print ("IR code for method %s\n", mono_method_full_name (cfg->method, TRUE));
6772
6773         for (i = 0; i < cfg->num_bblocks; ++i) {
6774                 bb = cfg->bblocks [i];
6775                 /*if (bb->cil_code) {
6776                         char* code1, *code2;
6777                         code1 = mono_disasm_code_one (NULL, cfg->method, bb->cil_code, NULL);
6778                         if (bb->last_ins->cil_code)
6779                                 code2 = mono_disasm_code_one (NULL, cfg->method, bb->last_ins->cil_code, NULL);
6780                         else
6781                                 code2 = g_strdup ("");
6782
6783                         code1 [strlen (code1) - 1] = 0;
6784                         code = g_strdup_printf ("%s -> %s", code1, code2);
6785                         g_free (code1);
6786                         g_free (code2);
6787                 } else*/
6788                         code = g_strdup ("\n");
6789                 g_print ("\nBB%d DFN%d (len: %d): %s", bb->block_num, i, bb->cil_length, code);
6790                 if (bb->code) {
6791                         MonoInst *c = bb->code;
6792                         while (c) {
6793                                 mono_print_tree (c);
6794                                 g_print ("\n");
6795                                 c = c->next;
6796                         }
6797                 } else {
6798
6799                 }
6800
6801                 g_print ("\tprev:");
6802                 for (j = 0; j < bb->in_count; ++j) {
6803                         g_print (" BB%d", bb->in_bb [j]->block_num);
6804                 }
6805                 g_print ("\t\tsucc:");
6806                 for (j = 0; j < bb->out_count; ++j) {
6807                         g_print (" BB%d", bb->out_bb [j]->block_num);
6808                 }
6809                 g_print ("\n\tidom: BB%d\n", bb->idom? bb->idom->block_num: -1);
6810
6811                 if (bb->idom)
6812                         g_assert (mono_bitset_test_fast (bb->dominators, bb->idom->dfn));
6813
6814                 if (bb->dominators)
6815                         mono_blockset_print (cfg, bb->dominators, "\tdominators", bb->idom? bb->idom->dfn: -1);
6816                 if (bb->dfrontier)
6817                         mono_blockset_print (cfg, bb->dfrontier, "\tdfrontier", -1);
6818                 g_free (code);
6819         }
6820
6821         g_print ("\n");
6822 }
6823
6824 void
6825 mono_bblock_add_inst (MonoBasicBlock *bb, MonoInst *inst)
6826 {
6827         inst->next = NULL;
6828         if (bb->last_ins) {
6829                 g_assert (bb->code);
6830                 bb->last_ins->next = inst;
6831                 bb->last_ins = inst;
6832         } else {
6833                 bb->last_ins = bb->code = inst;
6834         }
6835 }
6836
6837 void
6838 mono_destroy_compile (MonoCompile *cfg)
6839 {
6840         //mono_mempool_stats (cfg->mempool);
6841         g_hash_table_destroy (cfg->bb_hash);
6842         mono_free_loop_info (cfg);
6843         if (cfg->rs)
6844                 mono_regstate_free (cfg->rs);
6845         if (cfg->spvars)
6846                 g_hash_table_destroy (cfg->spvars);
6847         mono_mempool_destroy (cfg->mempool);
6848         g_list_free (cfg->ldstr_list);
6849
6850         g_free (cfg->varinfo);
6851         g_free (cfg->vars);
6852         g_free (cfg);
6853 }
6854
6855 #ifdef HAVE_KW_THREAD
6856 static __thread gpointer mono_lmf_addr;
6857 #endif
6858
6859 MonoLMF **
6860 mono_get_lmf_addr (void)
6861 {
6862 #ifdef HAVE_KW_THREAD
6863         return mono_lmf_addr;
6864 #else
6865         MonoJitTlsData *jit_tls;
6866
6867         if ((jit_tls = TlsGetValue (mono_jit_tls_id)))
6868                 return &jit_tls->lmf;
6869
6870         g_assert_not_reached ();
6871         return NULL;
6872 #endif
6873 }
6874
6875 /**
6876  * mono_thread_abort:
6877  * @obj: exception object
6878  *
6879  * abort the thread, print exception information and stack trace
6880  */
6881 static void
6882 mono_thread_abort (MonoObject *obj)
6883 {
6884         /* MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id); */
6885         
6886         /* handle_remove should be eventually called for this thread, too
6887         g_free (jit_tls);*/
6888
6889         mono_thread_exit ();
6890 }
6891
6892 static void*
6893 setup_jit_tls_data (gpointer stack_start, gpointer abort_func)
6894 {
6895         MonoJitTlsData *jit_tls;
6896         MonoLMF *lmf;
6897
6898         jit_tls = TlsGetValue (mono_jit_tls_id);
6899         if (jit_tls)
6900                 return jit_tls;
6901
6902         jit_tls = g_new0 (MonoJitTlsData, 1);
6903
6904         TlsSetValue (mono_jit_tls_id, jit_tls);
6905
6906         jit_tls->abort_func = abort_func;
6907         jit_tls->end_of_stack = stack_start;
6908
6909         lmf = g_new0 (MonoLMF, 1);
6910         lmf->ebp = -1;
6911
6912         jit_tls->lmf = jit_tls->first_lmf = lmf;
6913
6914 #ifdef HAVE_KW_THREAD
6915         mono_lmf_addr = &jit_tls->lmf;
6916 #endif
6917
6918         mono_arch_setup_jit_tls_data (jit_tls);
6919
6920         return jit_tls;
6921 }
6922
6923 static void
6924 mono_thread_start_cb (guint32 tid, gpointer stack_start, gpointer func)
6925 {
6926         MonoThread *thread;
6927         void *jit_tls = setup_jit_tls_data (stack_start, mono_thread_abort);
6928         thread = mono_thread_current ();
6929         if (thread)
6930                 thread->jit_data = jit_tls;
6931         if (mono_profiler_get_events () & MONO_PROFILE_STATISTICAL)
6932                 setup_stat_profiler ();
6933 }
6934
6935 void (*mono_thread_attach_aborted_cb ) (MonoObject *obj) = NULL;
6936
6937 static void
6938 mono_thread_abort_dummy (MonoObject *obj)
6939 {
6940   if (mono_thread_attach_aborted_cb)
6941     mono_thread_attach_aborted_cb (obj);
6942   else
6943     mono_thread_abort (obj);
6944 }
6945
6946 static void
6947 mono_thread_attach_cb (guint32 tid, gpointer stack_start)
6948 {
6949         MonoThread *thread;
6950         void *jit_tls = setup_jit_tls_data (stack_start, mono_thread_abort_dummy);
6951         thread = mono_thread_current ();
6952         if (thread)
6953                 thread->jit_data = jit_tls;
6954 }
6955
6956 static void
6957 mini_thread_cleanup (MonoThread *thread)
6958 {
6959         MonoJitTlsData *jit_tls = thread->jit_data;
6960
6961         if (jit_tls) {
6962                 mono_arch_free_jit_tls_data (jit_tls);
6963                 g_free (jit_tls->first_lmf);
6964                 g_free (jit_tls);
6965                 thread->jit_data = NULL;
6966         }
6967 }
6968
6969 void
6970 mono_add_patch_info (MonoCompile *cfg, int ip, MonoJumpInfoType type, gconstpointer target)
6971 {
6972         MonoJumpInfo *ji = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfo));
6973
6974         ji->ip.i = ip;
6975         ji->type = type;
6976         ji->data.target = target;
6977         ji->next = cfg->patch_info;
6978
6979         cfg->patch_info = ji;
6980 }
6981
6982 void
6983 mono_remove_patch_info (MonoCompile *cfg, int ip)
6984 {
6985         MonoJumpInfo **ji = &cfg->patch_info;
6986
6987         while (*ji) {
6988                 if ((*ji)->ip.i == ip)
6989                         *ji = (*ji)->next;
6990                 else
6991                         ji = &((*ji)->next);
6992         }
6993 }
6994
6995 gpointer
6996 mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *patch_info, gboolean run_cctors)
6997 {
6998         unsigned char *ip = patch_info->ip.i + code;
6999         gconstpointer target = NULL;
7000
7001         switch (patch_info->type) {
7002         case MONO_PATCH_INFO_BB:
7003                 target = patch_info->data.bb->native_offset + code;
7004                 break;
7005         case MONO_PATCH_INFO_ABS:
7006                 target = patch_info->data.target;
7007                 break;
7008         case MONO_PATCH_INFO_LABEL:
7009                 target = patch_info->data.inst->inst_c0 + code;
7010                 break;
7011         case MONO_PATCH_INFO_IP:
7012                 target = ip;
7013                 break;
7014         case MONO_PATCH_INFO_METHOD_REL:
7015                 target = code + patch_info->data.offset;
7016                 break;
7017         case MONO_PATCH_INFO_INTERNAL_METHOD: {
7018                 MonoJitICallInfo *mi = mono_find_jit_icall_by_name (patch_info->data.name);
7019                 if (!mi) {
7020                         g_warning ("unknown MONO_PATCH_INFO_INTERNAL_METHOD %s", patch_info->data.name);
7021                         g_assert_not_reached ();
7022                 }
7023                 target = mono_icall_get_wrapper (mi);
7024                 break;
7025         }
7026         case MONO_PATCH_INFO_METHOD_JUMP: {
7027                 GSList *list;
7028
7029                 /* get the trampoline to the method from the domain */
7030                 target = mono_create_jump_trampoline (domain, patch_info->data.method, TRUE);
7031                 if (!domain->jump_target_hash)
7032                         domain->jump_target_hash = g_hash_table_new (NULL, NULL);
7033                 list = g_hash_table_lookup (domain->jump_target_hash, patch_info->data.method);
7034                 list = g_slist_prepend (list, ip);
7035                 g_hash_table_insert (domain->jump_target_hash, patch_info->data.method, list);
7036                 break;
7037         }
7038         case MONO_PATCH_INFO_METHOD:
7039                 if (patch_info->data.method == method) {
7040                         target = code;
7041                 } else
7042                         /* get the trampoline to the method from the domain */
7043                         target = mono_create_jit_trampoline (patch_info->data.method);
7044                 break;
7045         case MONO_PATCH_INFO_SWITCH: {
7046                 gpointer *jump_table;
7047                 int i;
7048
7049                 if (method->dynamic) {
7050                         jump_table = mono_code_manager_reserve (mono_dynamic_code_hash_lookup (domain, method)->code_mp, sizeof (gpointer) * patch_info->data.table->table_size);
7051                 } else {
7052                         mono_domain_lock (domain);
7053                         jump_table = mono_code_manager_reserve (domain->code_mp, sizeof (gpointer) * patch_info->data.table->table_size);
7054                         mono_domain_unlock (domain);
7055                 }
7056
7057                 for (i = 0; i < patch_info->data.table->table_size; i++) {
7058                         jump_table [i] = code + GPOINTER_TO_INT (patch_info->data.table->table [i]);
7059                 }
7060                 target = jump_table;
7061                 break;
7062         }
7063         case MONO_PATCH_INFO_METHODCONST:
7064         case MONO_PATCH_INFO_CLASS:
7065         case MONO_PATCH_INFO_IMAGE:
7066         case MONO_PATCH_INFO_FIELD:
7067                 target = patch_info->data.target;
7068                 break;
7069         case MONO_PATCH_INFO_IID:
7070                 mono_class_init (patch_info->data.klass);
7071                 target = GINT_TO_POINTER (patch_info->data.klass->interface_id);
7072                 break;
7073         case MONO_PATCH_INFO_VTABLE:
7074                 target = mono_class_vtable (domain, patch_info->data.klass);
7075                 break;
7076         case MONO_PATCH_INFO_CLASS_INIT:
7077                 target = mono_create_class_init_trampoline (mono_class_vtable (domain, patch_info->data.klass));
7078                 break;
7079         case MONO_PATCH_INFO_SFLDA: {
7080                 MonoVTable *vtable = mono_class_vtable (domain, patch_info->data.field->parent);
7081                 if (!vtable->initialized && !(vtable->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) && mono_class_needs_cctor_run (vtable->klass, method))
7082                         /* Done by the generated code */
7083                         ;
7084                 else {
7085                         if (run_cctors)
7086                                 mono_runtime_class_init (vtable);
7087                 }
7088                 target = (char*)vtable->data + patch_info->data.field->offset;
7089                 break;
7090         }
7091         case MONO_PATCH_INFO_R4:
7092         case MONO_PATCH_INFO_R8:
7093                 target = patch_info->data.target;
7094                 break;
7095         case MONO_PATCH_INFO_EXC_NAME:
7096                 target = patch_info->data.name;
7097                 break;
7098         case MONO_PATCH_INFO_LDSTR:
7099                 target =
7100                         mono_ldstr (domain, patch_info->data.token->image, 
7101                                                 mono_metadata_token_index (patch_info->data.token->token));
7102                 break;
7103         case MONO_PATCH_INFO_TYPE_FROM_HANDLE: {
7104                 gpointer handle;
7105                 MonoClass *handle_class;
7106
7107                 handle = mono_ldtoken (patch_info->data.token->image, 
7108                                        patch_info->data.token->token, &handle_class, NULL);
7109                 mono_class_init (handle_class);
7110                 mono_class_init (mono_class_from_mono_type (handle));
7111
7112                 target =
7113                         mono_type_get_object (domain, handle);
7114                 break;
7115         }
7116         case MONO_PATCH_INFO_LDTOKEN: {
7117                 gpointer handle;
7118                 MonoClass *handle_class;
7119                 
7120                 handle = mono_ldtoken (patch_info->data.token->image,
7121                                        patch_info->data.token->token, &handle_class, NULL);
7122                 mono_class_init (handle_class);
7123                 
7124                 target = handle;
7125                 break;
7126         }
7127         case MONO_PATCH_INFO_BB_OVF:
7128         case MONO_PATCH_INFO_EXC_OVF:
7129         case MONO_PATCH_INFO_GOT_OFFSET:
7130         case MONO_PATCH_INFO_NONE:
7131                 break;
7132         default:
7133                 g_assert_not_reached ();
7134         }
7135
7136         return (gpointer)target;
7137 }
7138
7139 static void
7140 dec_foreach (MonoInst *tree, MonoCompile *cfg) {
7141         MonoJitICallInfo *info;
7142
7143         decompose_foreach (tree, cfg);
7144
7145         switch (mono_burg_arity [tree->opcode]) {
7146         case 0: break;
7147         case 1: 
7148                 dec_foreach (tree->inst_left, cfg);
7149
7150                 if ((info = mono_find_jit_opcode_emulation (tree->opcode))) {
7151                         MonoInst *iargs [2];
7152                 
7153                         iargs [0] = tree->inst_left;
7154
7155                         mono_emulate_opcode (cfg, tree, iargs, info);
7156                         return;
7157                 }
7158
7159                 break;
7160         case 2:
7161 #ifdef MONO_ARCH_BIGMUL_INTRINS
7162                 if (tree->opcode == OP_LMUL
7163                                 && (cfg->opt & MONO_OPT_INTRINS)
7164                                 && (tree->inst_left->opcode == CEE_CONV_I8 
7165                                         || tree->inst_left->opcode == CEE_CONV_U8)
7166                                 && tree->inst_left->inst_left->type == STACK_I4
7167                                 && (tree->inst_right->opcode == CEE_CONV_I8 
7168                                         || tree->inst_right->opcode == CEE_CONV_U8)
7169                                 && tree->inst_right->inst_left->type == STACK_I4
7170                                 && tree->inst_left->opcode == tree->inst_right->opcode) {
7171                         tree->opcode = (tree->inst_left->opcode == CEE_CONV_I8 ? OP_BIGMUL: OP_BIGMUL_UN);
7172                         tree->inst_left = tree->inst_left->inst_left;
7173                         tree->inst_right = tree->inst_right->inst_left;
7174                         dec_foreach (tree, cfg);
7175                 } else 
7176 #endif
7177                         if ((info = mono_find_jit_opcode_emulation (tree->opcode))) {
7178                         MonoInst *iargs [2];
7179                 
7180                         iargs [0] = tree->inst_i0;
7181                         iargs [1] = tree->inst_i1;
7182                 
7183                         mono_emulate_opcode (cfg, tree, iargs, info);
7184
7185                         dec_foreach (iargs [0], cfg);
7186                         dec_foreach (iargs [1], cfg);
7187                         return;
7188                 } else {
7189                         dec_foreach (tree->inst_left, cfg);
7190                         dec_foreach (tree->inst_right, cfg);
7191                 }
7192                 break;
7193         default:
7194                 g_assert_not_reached ();
7195         }
7196 }
7197
7198 static void
7199 decompose_pass (MonoCompile *cfg) {
7200         MonoBasicBlock *bb;
7201
7202         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
7203                 MonoInst *tree;
7204                 cfg->cbb = bb;
7205                 cfg->prev_ins = NULL;
7206                 for (tree = cfg->cbb->code; tree; tree = tree->next) {
7207                         dec_foreach (tree, cfg);
7208                         cfg->prev_ins = tree;
7209                 }
7210         }
7211 }
7212
7213 static void
7214 nullify_basic_block (MonoBasicBlock *bb) 
7215 {
7216         bb->in_count = 0;
7217         bb->out_count = 0;
7218         bb->in_bb = NULL;
7219         bb->out_bb = NULL;
7220         bb->next_bb = NULL;
7221         bb->code = bb->last_ins = NULL;
7222         bb->cil_code = NULL;
7223 }
7224
7225 static void 
7226 replace_out_block (MonoBasicBlock *bb, MonoBasicBlock *orig,  MonoBasicBlock *repl)
7227 {
7228         int i;
7229
7230         for (i = 0; i < bb->out_count; i++) {
7231                 MonoBasicBlock *ob = bb->out_bb [i];
7232                 if (ob == orig) {
7233                         if (!repl) {
7234                                 if (bb->out_count > 1) {
7235                                         bb->out_bb [i] = bb->out_bb [bb->out_count - 1];
7236                                 }
7237                                 bb->out_count--;
7238                         } else {
7239                                 bb->out_bb [i] = repl;
7240                         }
7241                 }
7242         }
7243 }
7244
7245 static void 
7246 replace_in_block (MonoBasicBlock *bb, MonoBasicBlock *orig, MonoBasicBlock *repl)
7247 {
7248         int i;
7249
7250         for (i = 0; i < bb->in_count; i++) {
7251                 MonoBasicBlock *ib = bb->in_bb [i];
7252                 if (ib == orig) {
7253                         if (!repl) {
7254                                 if (bb->in_count > 1) {
7255                                         bb->in_bb [i] = bb->in_bb [bb->in_count - 1];
7256                                 }
7257                                 bb->in_count--;
7258                         } else {
7259                                 bb->in_bb [i] = repl;
7260                         }
7261                 }
7262         }
7263 }
7264
7265 static void 
7266 replace_basic_block (MonoBasicBlock *bb, MonoBasicBlock *orig,  MonoBasicBlock *repl)
7267 {
7268         int i, j;
7269
7270         for (i = 0; i < bb->out_count; i++) {
7271                 MonoBasicBlock *ob = bb->out_bb [i];
7272                 for (j = 0; j < ob->in_count; j++) {
7273                         if (ob->in_bb [j] == orig) {
7274                                 ob->in_bb [j] = repl;
7275                         }
7276                 }
7277         }
7278
7279 }
7280
7281
7282 static void
7283 merge_basic_blocks (MonoBasicBlock *bb, MonoBasicBlock *bbn) 
7284 {
7285         bb->out_count = bbn->out_count;
7286         bb->out_bb = bbn->out_bb;
7287
7288         replace_basic_block (bb, bbn, bb);
7289
7290         if (bb->last_ins) {
7291                 if (bbn->code) {
7292                         bb->last_ins->next = bbn->code;
7293                         bb->last_ins = bbn->last_ins;
7294                 }
7295         } else {
7296                 bb->code = bbn->code;
7297                 bb->last_ins = bbn->last_ins;
7298         }
7299         bb->next_bb = bbn->next_bb;
7300         nullify_basic_block (bbn);
7301 }
7302
7303 static void
7304 move_basic_block_to_end (MonoCompile *cfg, MonoBasicBlock *bb)
7305 {
7306         MonoBasicBlock *bbn;
7307
7308         /* Find the previous */
7309         for (bbn = cfg->bb_entry; bbn->next_bb && bbn->next_bb != bb; bbn = bbn->next_bb)
7310                 ;
7311         if (bbn->next_bb) {
7312                 bbn->next_bb = bb->next_bb;
7313         }
7314
7315         /* Find the last */
7316         for (bbn = cfg->bb_entry; bbn->next_bb; bbn = bbn->next_bb)
7317                 ;
7318         bbn->next_bb = bb;
7319         bb->next_bb = NULL;
7320 }
7321
7322 /*
7323  * Optimizes the branches on the Control Flow Graph
7324  *
7325  */
7326 static void
7327 optimize_branches (MonoCompile *cfg)
7328 {
7329         int i, changed = FALSE;
7330         MonoBasicBlock *bb, *bbn;
7331         guint32 niterations;
7332
7333         /*
7334          * Some crazy loops could cause the code below to go into an infinite
7335          * loop, see bug #53003 for an example. To prevent this, we put an upper
7336          * bound on the number of iterations.
7337          */
7338         niterations = 1000;
7339         do {
7340                 changed = FALSE;
7341                 niterations --;
7342
7343                 /* we skip the entry block (exit is handled specially instead ) */
7344                 for (bb = cfg->bb_entry->next_bb; bb; bb = bb->next_bb) {
7345
7346                         /* dont touch code inside exception clauses */
7347                         if (bb->region != -1)
7348                                 continue;
7349
7350                         if ((bbn = bb->next_bb) && bbn->in_count == 0 && bb->region == bbn->region) {
7351                                 if (cfg->verbose_level > 2)
7352                                         g_print ("nullify block triggered %d\n", bbn->block_num);
7353
7354                                 bb->next_bb = bbn->next_bb;
7355
7356                                 for (i = 0; i < bbn->out_count; i++)
7357                                         replace_in_block (bbn->out_bb [i], bbn, NULL);
7358
7359                                 nullify_basic_block (bbn);                      
7360                                 changed = TRUE;
7361                         }
7362
7363                         if (bb->out_count == 1) {
7364                                 bbn = bb->out_bb [0];
7365
7366                                 /* conditional branches where true and false targets are the same can be also replaced with CEE_BR */
7367                                 if (bb->last_ins && MONO_IS_COND_BRANCH_OP (bb->last_ins)) {
7368                                         bb->last_ins->opcode = CEE_BR;
7369                                         bb->last_ins->inst_target_bb = bb->last_ins->inst_true_bb;
7370                                         changed = TRUE;
7371                                         if (cfg->verbose_level > 2)
7372                                                 g_print ("cond branch removal triggered in %d %d\n", bb->block_num, bb->out_count);
7373                                 }
7374
7375                                 if (bb->region == bbn->region && bb->next_bb == bbn) {
7376                                         /* the block are in sequence anyway ... */
7377
7378                                         /* branches to the following block can be removed */
7379                                         if (bb->last_ins && bb->last_ins->opcode == CEE_BR) {
7380                                                 bb->last_ins->opcode = CEE_NOP;
7381                                                 changed = TRUE;
7382                                                 if (cfg->verbose_level > 2)
7383                                                         g_print ("br removal triggered %d -> %d\n", bb->block_num, bbn->block_num);
7384                                         }
7385
7386                                         if (bbn->in_count == 1) {
7387
7388                                                 if (bbn != cfg->bb_exit) {
7389                                                         if (cfg->verbose_level > 2)
7390                                                                 g_print ("block merge triggered %d -> %d\n", bb->block_num, bbn->block_num);
7391                                                         merge_basic_blocks (bb, bbn);
7392                                                         changed = TRUE;
7393                                                 }
7394
7395                                                 //mono_print_bb_code (bb);
7396                                         }
7397                                 }                               
7398                         }
7399                 }
7400         } while (changed && (niterations > 0));
7401
7402         niterations = 1000;
7403         do {
7404                 changed = FALSE;
7405                 niterations --;
7406
7407                 /* we skip the entry block (exit is handled specially instead ) */
7408                 for (bb = cfg->bb_entry->next_bb; bb; bb = bb->next_bb) {
7409
7410                         /* dont touch code inside exception clauses */
7411                         if (bb->region != -1)
7412                                 continue;
7413
7414                         if ((bbn = bb->next_bb) && bbn->in_count == 0 && bb->region == bbn->region) {
7415                                 if (cfg->verbose_level > 2) {
7416                                         g_print ("nullify block triggered %d\n", bbn->block_num);
7417                                 }
7418                                 bb->next_bb = bbn->next_bb;
7419
7420                                 for (i = 0; i < bbn->out_count; i++)
7421                                         replace_in_block (bbn->out_bb [i], bbn, NULL);
7422
7423                                 nullify_basic_block (bbn);                      
7424                                 changed = TRUE;
7425                                 break;
7426                         }
7427
7428
7429                         if (bb->out_count == 1) {
7430                                 bbn = bb->out_bb [0];
7431
7432                                 if (bb->last_ins && bb->last_ins->opcode == CEE_BR) {
7433                                         bbn = bb->last_ins->inst_target_bb;
7434                                         if (bb->region == bbn->region && bbn->code && bbn->code->opcode == CEE_BR &&
7435                                             bbn->code->inst_target_bb->region == bb->region) {
7436                                                 
7437                                                 if (cfg->verbose_level > 2)
7438                                                         g_print ("in %s branch to branch triggered %d -> %d -> %d\n", cfg->method->name, 
7439                                                                  bb->block_num, bbn->block_num, bbn->code->inst_target_bb->block_num);
7440
7441                                                 replace_in_block (bbn, bb, NULL);
7442                                                 replace_out_block (bb, bbn, bbn->code->inst_target_bb);
7443                                                 link_bblock (cfg, bb, bbn->code->inst_target_bb);
7444                                                 bb->last_ins->inst_target_bb = bbn->code->inst_target_bb;
7445                                                 changed = TRUE;
7446                                                 break;
7447                                         }
7448                                 }
7449                         } else if (bb->out_count == 2) {
7450                                 if (bb->last_ins && MONO_IS_COND_BRANCH_NOFP (bb->last_ins)) {
7451                                         bbn = bb->last_ins->inst_true_bb;
7452                                         if (bb->region == bbn->region && bbn->code && bbn->code->opcode == CEE_BR &&
7453                                             bbn->code->inst_target_bb->region == bb->region) {
7454                                                 if (cfg->verbose_level > 2)             
7455                                                         g_print ("cbranch1 to branch triggered %d -> (%d) %d (0x%02x)\n", 
7456                                                                  bb->block_num, bbn->block_num, bbn->code->inst_target_bb->block_num, 
7457                                                                  bbn->code->opcode);
7458
7459                                                 bb->last_ins->inst_true_bb = bbn->code->inst_target_bb;
7460
7461                                                 replace_in_block (bbn, bb, NULL);
7462                                                 if (!bbn->in_count)
7463                                                         replace_in_block (bbn->code->inst_target_bb, bbn, bb);
7464                                                 replace_out_block (bb, bbn, bbn->code->inst_target_bb);
7465
7466                                                 link_bblock (cfg, bb, bbn->code->inst_target_bb);
7467
7468                                                 changed = TRUE;
7469                                                 break;
7470                                         }
7471
7472                                         bbn = bb->last_ins->inst_false_bb;
7473                                         if (bb->region == bbn->region && bbn->code && bbn->code->opcode == CEE_BR &&
7474                                             bbn->code->inst_target_bb->region == bb->region) {
7475                                                 if (cfg->verbose_level > 2)
7476                                                         g_print ("cbranch2 to branch triggered %d -> (%d) %d (0x%02x)\n", 
7477                                                                  bb->block_num, bbn->block_num, bbn->code->inst_target_bb->block_num, 
7478                                                                  bbn->code->opcode);
7479
7480                                                 bb->last_ins->inst_false_bb = bbn->code->inst_target_bb;
7481
7482                                                 replace_in_block (bbn, bb, NULL);
7483                                                 if (!bbn->in_count)
7484                                                         replace_in_block (bbn->code->inst_target_bb, bbn, bb);
7485                                                 replace_out_block (bb, bbn, bbn->code->inst_target_bb);
7486
7487                                                 link_bblock (cfg, bb, bbn->code->inst_target_bb);
7488
7489                                                 changed = TRUE;
7490                                                 break;
7491                                         }
7492                                 }
7493
7494 #ifdef MONO_ARCH_HAVE_OUT_OF_LINE_BBLOCKS
7495                                 if (bb->last_ins && MONO_IS_COND_BRANCH_NOFP (bb->last_ins)) {
7496                                         if (bb->last_ins->inst_false_bb->out_of_line) {
7497                                                 /* Reverse the branch */
7498                                                 bb->last_ins->opcode = reverse_branch_op (bb->last_ins->opcode);
7499                                                 bbn = bb->last_ins->inst_false_bb;
7500                                                 bb->last_ins->inst_false_bb = bb->last_ins->inst_true_bb;
7501                                                 bb->last_ins->inst_true_bb = bbn;
7502
7503                                                 move_basic_block_to_end (cfg, bb->last_ins->inst_true_bb);
7504                                                 if (cfg->verbose_level > 2)
7505                                                         g_print ("cbranch to throw block triggered %d.\n", 
7506                                                                          bb->block_num);
7507                                         }
7508                                 }
7509 #endif
7510                         }
7511                 }
7512         } while (changed && (niterations > 0));
7513
7514 }
7515
7516 static void
7517 mono_compile_create_vars (MonoCompile *cfg)
7518 {
7519         MonoMethodSignature *sig;
7520         MonoMethodHeader *header;
7521         int i;
7522
7523         header = mono_method_get_header (cfg->method);
7524
7525         sig = cfg->method->signature;
7526         
7527         if (!MONO_TYPE_IS_VOID (sig->ret)) {
7528                 cfg->ret = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst));
7529                 cfg->ret->opcode = OP_RETARG;
7530                 cfg->ret->inst_vtype = sig->ret;
7531                 cfg->ret->klass = mono_class_from_mono_type (sig->ret);
7532         }
7533         if (cfg->verbose_level > 2)
7534                 g_print ("creating vars\n");
7535
7536         if (sig->hasthis)
7537                 mono_compile_create_var (cfg, &cfg->method->klass->this_arg, OP_ARG);
7538
7539         for (i = 0; i < sig->param_count; ++i) {
7540                 mono_compile_create_var (cfg, sig->params [i], OP_ARG);
7541                 if (sig->params [i]->byref) {
7542                         cfg->disable_ssa = TRUE;
7543                 }
7544         }
7545
7546         cfg->locals_start = cfg->num_varinfo;
7547
7548         if (cfg->verbose_level > 2)
7549                 g_print ("creating locals\n");
7550         for (i = 0; i < header->num_locals; ++i)
7551                 mono_compile_create_var (cfg, header->locals [i], OP_LOCAL);
7552         if (cfg->verbose_level > 2)
7553                 g_print ("locals done\n");
7554 }
7555
7556 void
7557 mono_print_code (MonoCompile *cfg)
7558 {
7559         MonoBasicBlock *bb;
7560         
7561         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
7562                 MonoInst *tree = bb->code;      
7563
7564                 if (!tree)
7565                         continue;
7566                 
7567                 g_print ("CODE BLOCK %d (nesting %d):\n", bb->block_num, bb->nesting);
7568
7569                 for (; tree; tree = tree->next) {
7570                         mono_print_tree (tree);
7571                         g_print ("\n");
7572                 }
7573
7574                 if (bb->last_ins)
7575                         bb->last_ins->next = NULL;
7576         }
7577 }
7578
7579 extern const char * const mono_burg_rule_string [];
7580
7581 static void
7582 emit_state (MonoCompile *cfg, MBState *state, int goal)
7583 {
7584         MBState *kids [10];
7585         int ern = mono_burg_rule (state, goal);
7586         const guint16 *nts = mono_burg_nts [ern];
7587         MBEmitFunc emit;
7588
7589         //g_print ("rule: %s\n", mono_burg_rule_string [ern]);
7590         switch (goal) {
7591         case MB_NTERM_reg:
7592                 //if (state->reg2)
7593                 //      state->reg1 = state->reg2; /* chain rule */
7594                 //else
7595 #ifdef MONO_ARCH_ENABLE_EMIT_STATE_OPT
7596                 if (!state->reg1)
7597 #endif
7598                         state->reg1 = mono_regstate_next_int (cfg->rs);
7599                 //g_print ("alloc symbolic R%d (reg2: R%d) in block %d\n", state->reg1, state->reg2, cfg->cbb->block_num);
7600                 break;
7601         case MB_NTERM_lreg:
7602                 state->reg1 = mono_regstate_next_int (cfg->rs);
7603                 state->reg2 = mono_regstate_next_int (cfg->rs);
7604                 break;
7605         case MB_NTERM_freg:
7606                 state->reg1 = mono_regstate_next_float (cfg->rs);
7607                 break;
7608         default:
7609 #ifdef MONO_ARCH_ENABLE_EMIT_STATE_OPT
7610                 /*
7611                  * Enabling this might cause bugs to surface in the local register
7612                  * allocators on some architectures like x86.
7613                  */
7614                 if ((state->tree->ssa_op == MONO_SSA_STORE) && (state->left->tree->opcode == OP_REGVAR)) {
7615                         /* Do not optimize away reg-reg moves */
7616                         if (! ((state->right->tree->ssa_op == MONO_SSA_LOAD) && (state->right->left->tree->opcode == OP_REGVAR))) {
7617                                 state->right->reg1 = state->left->tree->dreg;
7618                         }
7619                 }
7620 #endif
7621
7622                 /* do nothing */
7623                 break;
7624         }
7625         if (nts [0]) {
7626                 mono_burg_kids (state, ern, kids);
7627
7628                 emit_state (cfg, kids [0], nts [0]);
7629                 if (nts [1]) {
7630                         emit_state (cfg, kids [1], nts [1]);
7631                         if (nts [2]) {
7632                                 g_assert (!nts [3]);
7633                                 emit_state (cfg, kids [2], nts [2]);
7634                         }
7635                 }
7636         }
7637
7638 //      g_print ("emit: %s (%p)\n", mono_burg_rule_string [ern], state);
7639         if ((emit = mono_burg_func [ern]))
7640                 emit (state, state->tree, cfg); 
7641 }
7642
7643 #define DEBUG_SELECTION
7644
7645 static void 
7646 mini_select_instructions (MonoCompile *cfg)
7647 {
7648         MonoBasicBlock *bb;
7649         
7650         cfg->state_pool = mono_mempool_new ();
7651         cfg->rs = mono_regstate_new ();
7652
7653         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
7654                 if (bb->last_ins && MONO_IS_COND_BRANCH_OP (bb->last_ins) &&
7655                     bb->next_bb != bb->last_ins->inst_false_bb) {
7656
7657                         /* we are careful when inverting, since bugs like #59580
7658                          * could show up when dealing with NaNs.
7659                          */
7660                         if (MONO_IS_COND_BRANCH_NOFP(bb->last_ins) && bb->next_bb == bb->last_ins->inst_true_bb) {
7661                                 MonoBasicBlock *tmp =  bb->last_ins->inst_true_bb;
7662                                 bb->last_ins->inst_true_bb = bb->last_ins->inst_false_bb;
7663                                 bb->last_ins->inst_false_bb = tmp;
7664
7665                                 bb->last_ins->opcode = reverse_branch_op (bb->last_ins->opcode);
7666                         } else {                        
7667                                 MonoInst *inst = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst));
7668                                 inst->opcode = CEE_BR;
7669                                 inst->inst_target_bb = bb->last_ins->inst_false_bb;
7670                                 mono_bblock_add_inst (bb, inst);
7671                         }
7672                 }
7673         }
7674
7675 #ifdef DEBUG_SELECTION
7676         if (cfg->verbose_level >= 4) {
7677         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
7678                 MonoInst *tree = bb->code;      
7679                 g_print ("DUMP BLOCK %d:\n", bb->block_num);
7680                 if (!tree)
7681                         continue;
7682                 for (; tree; tree = tree->next) {
7683                         mono_print_tree (tree);
7684                         g_print ("\n");
7685                 }
7686         }
7687         }
7688 #endif
7689
7690         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
7691                 MonoInst *tree = bb->code, *next;       
7692                 MBState *mbstate;
7693
7694                 if (!tree)
7695                         continue;
7696                 bb->code = NULL;
7697                 bb->last_ins = NULL;
7698                 
7699                 cfg->cbb = bb;
7700                 mono_regstate_reset (cfg->rs);
7701
7702 #ifdef DEBUG_SELECTION
7703                 if (cfg->verbose_level >= 3)
7704                         g_print ("LABEL BLOCK %d:\n", bb->block_num);
7705 #endif
7706                 for (; tree; tree = next) {
7707                         next = tree->next;
7708 #ifdef DEBUG_SELECTION
7709                         if (cfg->verbose_level >= 3) {
7710                                 mono_print_tree (tree);
7711                                 g_print ("\n");
7712                         }
7713 #endif
7714
7715                         if (!(mbstate = mono_burg_label (tree, cfg))) {
7716                                 g_warning ("unable to label tree %p", tree);
7717                                 mono_print_tree (tree);
7718                                 g_print ("\n");                         
7719                                 g_assert_not_reached ();
7720                         }
7721                         emit_state (cfg, mbstate, MB_NTERM_stmt);
7722                 }
7723                 bb->max_ireg = cfg->rs->next_vireg;
7724                 bb->max_freg = cfg->rs->next_vfreg;
7725
7726                 if (bb->last_ins)
7727                         bb->last_ins->next = NULL;
7728
7729                 mono_mempool_empty (cfg->state_pool); 
7730         }
7731         mono_mempool_destroy (cfg->state_pool); 
7732 }
7733
7734 void
7735 mono_codegen (MonoCompile *cfg)
7736 {
7737         MonoJumpInfo *patch_info;
7738         MonoBasicBlock *bb;
7739         int i, max_epilog_size;
7740         guint8 *code;
7741
7742         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
7743                 cfg->spill_count = 0;
7744                 /* we reuse dfn here */
7745                 /* bb->dfn = bb_count++; */
7746                 mono_arch_local_regalloc (cfg, bb);
7747         }
7748
7749         if (cfg->prof_options & MONO_PROFILE_COVERAGE)
7750                 cfg->coverage_info = mono_profiler_coverage_alloc (cfg->method, cfg->num_bblocks);
7751
7752         code = mono_arch_emit_prolog (cfg);
7753
7754         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
7755                 code = mono_arch_instrument_prolog (cfg, mono_profiler_method_enter, code, FALSE);
7756
7757         cfg->code_len = code - cfg->native_code;
7758         cfg->prolog_end = cfg->code_len;
7759
7760         mono_debug_open_method (cfg);
7761
7762         /* emit code all basic blocks */
7763         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
7764                 bb->native_offset = cfg->code_len;
7765                 mono_arch_output_basic_block (cfg, bb);
7766
7767 #ifdef MONO_ARCH_HAVE_OUT_OF_LINE_BBLOCKS
7768                 if (bb == cfg->bb_exit) {
7769                         cfg->epilog_begin = cfg->code_len;
7770
7771                         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE) {
7772                                 code = mono_arch_instrument_epilog (cfg, mono_profiler_method_leave, cfg->native_code, FALSE);
7773                                 cfg->code_len = code - cfg->native_code;
7774                         }
7775
7776                         mono_arch_emit_epilog (cfg);
7777                 }
7778 #endif
7779         }
7780
7781 #ifndef MONO_ARCH_HAVE_OUT_OF_LINE_BBLOCKS
7782         cfg->bb_exit->native_offset = cfg->code_len;
7783         max_epilog_size = mono_arch_max_epilog_size (cfg);
7784 #else
7785         mono_arch_emit_exceptions (cfg);
7786
7787         max_epilog_size = 0;
7788 #endif
7789
7790         code = cfg->native_code + cfg->code_len;
7791
7792         /* we always allocate code in cfg->domain->code_mp to increase locality */
7793         cfg->code_size = cfg->code_len + max_epilog_size;
7794         /* fixme: align to MONO_ARCH_CODE_ALIGNMENT */
7795
7796         if (cfg->method->dynamic) {
7797                 /* Allocate the code into a separate memory pool so it can be freed */
7798                 cfg->dynamic_info = g_new0 (MonoJitDynamicMethodInfo, 1);
7799                 cfg->dynamic_info->code_mp = mono_code_manager_new_dynamic ();
7800                 mono_domain_lock (cfg->domain);
7801                 mono_dynamic_code_hash_insert (cfg->domain, cfg->method, cfg->dynamic_info);
7802                 mono_domain_unlock (cfg->domain);
7803
7804                 code = mono_code_manager_reserve (cfg->dynamic_info->code_mp, cfg->code_size);
7805         } else {
7806                 mono_domain_lock (cfg->domain);
7807                 code = mono_code_manager_reserve (cfg->domain->code_mp, cfg->code_size);
7808                 mono_domain_unlock (cfg->domain);
7809         }
7810
7811         memcpy (code, cfg->native_code, cfg->code_len);
7812         g_free (cfg->native_code);
7813         cfg->native_code = code;
7814         code = cfg->native_code + cfg->code_len;
7815   
7816         /* g_assert (((int)cfg->native_code & (MONO_ARCH_CODE_ALIGNMENT - 1)) == 0); */
7817
7818 #ifndef MONO_ARCH_HAVE_OUT_OF_LINE_BBLOCKS
7819         cfg->epilog_begin = cfg->code_len;
7820
7821         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
7822                 code = mono_arch_instrument_epilog (cfg, mono_profiler_method_leave, code, FALSE);
7823
7824         cfg->code_len = code - cfg->native_code;
7825
7826         mono_arch_emit_epilog (cfg);
7827 #endif
7828
7829         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
7830                 switch (patch_info->type) {
7831                 case MONO_PATCH_INFO_ABS: {
7832                         MonoJitICallInfo *info = mono_find_jit_icall_by_addr (patch_info->data.target);
7833                         if (info) {
7834                                 //printf ("TEST %s %p\n", info->name, patch_info->data.target);
7835                                 if ((cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) && 
7836                                         strstr (cfg->method->name, info->name))
7837                                         /*
7838                                          * This is an icall wrapper, and this is a call to the
7839                                          * wrapped function.
7840                                          */
7841                                         ;
7842                                 else {
7843                                         patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
7844                                         patch_info->data.name = info->name;
7845                                 }
7846                         }
7847                         else {
7848                                 MonoVTable *vtable = mono_find_class_init_trampoline_by_addr (patch_info->data.target);
7849                                 if (vtable) {
7850                                         patch_info->type = MONO_PATCH_INFO_CLASS_INIT;
7851                                         patch_info->data.klass = vtable->klass;
7852                                 }
7853                         }
7854                         break;
7855                 }
7856                 case MONO_PATCH_INFO_SWITCH: {
7857                         gpointer *table;
7858                         if (cfg->method->dynamic) {
7859                                 table = mono_code_manager_reserve (cfg->dynamic_info->code_mp, sizeof (gpointer) * patch_info->data.table->table_size);
7860                         } else {
7861                                 mono_domain_lock (cfg->domain);
7862                                 table = mono_code_manager_reserve (cfg->domain->code_mp, sizeof (gpointer) * patch_info->data.table->table_size);
7863                                 mono_domain_unlock (cfg->domain);
7864                         }
7865
7866                         if (!cfg->compile_aot)
7867                                 /* In the aot case, the patch already points to the correct location */
7868                                 patch_info->ip.i = patch_info->ip.label->inst_c0;
7869                         for (i = 0; i < patch_info->data.table->table_size; i++) {
7870                                 table [i] = GINT_TO_POINTER (patch_info->data.table->table [i]->native_offset);
7871                         }
7872                         patch_info->data.table->table = (MonoBasicBlock**)table;
7873                         break;
7874                 }
7875                 default:
7876                         /* do nothing */
7877                         break;
7878                 }
7879         }
7880        
7881         if (cfg->verbose_level > 0)
7882                 g_print ("Method %s emitted at %p to %p [%s]\n", 
7883                                  mono_method_full_name (cfg->method, TRUE), 
7884                                  cfg->native_code, cfg->native_code + cfg->code_len, cfg->domain->friendly_name);
7885
7886         mono_arch_patch_code (cfg->method, cfg->domain, cfg->native_code, cfg->patch_info, cfg->run_cctors);
7887
7888         if (cfg->method->dynamic) {
7889                 mono_code_manager_commit (cfg->dynamic_info->code_mp, cfg->native_code, cfg->code_size, cfg->code_len);
7890         } else {
7891                 mono_domain_lock (cfg->domain);
7892                 mono_code_manager_commit (cfg->domain->code_mp, cfg->native_code, cfg->code_size, cfg->code_len);
7893                 mono_domain_unlock (cfg->domain);
7894         }
7895         
7896         mono_arch_flush_icache (cfg->native_code, cfg->code_len);
7897
7898         mono_debug_close_method (cfg);
7899 }
7900
7901 static void
7902 mono_cprop_copy_values (MonoCompile *cfg, MonoInst *tree, MonoInst **acp)
7903 {
7904         MonoInst *cp;
7905         int arity;
7906
7907         if (tree->ssa_op == MONO_SSA_LOAD && (tree->inst_i0->opcode == OP_LOCAL || tree->inst_i0->opcode == OP_ARG) && 
7908             (cp = acp [tree->inst_i0->inst_c0]) && !tree->inst_i0->flags) {
7909
7910                 if (cp->opcode == OP_ICONST) {
7911                         if (cfg->opt & MONO_OPT_CONSPROP) {
7912                                 //{ static int c = 0; printf ("CCOPY %d %d %s\n", c++, cp->inst_c0, mono_method_full_name (cfg->method, TRUE)); }
7913                                 *tree = *cp;
7914                         }
7915                 } else {
7916                         if (tree->inst_i0->inst_vtype->type == cp->inst_vtype->type) {
7917                                 if (cfg->opt & MONO_OPT_COPYPROP) {
7918                                         //{ static int c = 0; printf ("VCOPY %d\n", ++c); }
7919                                         tree->inst_i0 = cp;
7920                                 } 
7921                         }
7922                 } 
7923         } else {
7924                 arity = mono_burg_arity [tree->opcode];
7925
7926                 if (arity) {
7927                         mono_cprop_copy_values (cfg, tree->inst_i0, acp);
7928                         if (cfg->opt & MONO_OPT_CFOLD)
7929                                 mono_constant_fold_inst (tree, NULL); 
7930                         /* The opcode may have changed */
7931                         if (mono_burg_arity [tree->opcode] > 1) {
7932                                 mono_cprop_copy_values (cfg, tree->inst_i1, acp);
7933                                 if (cfg->opt & MONO_OPT_CFOLD)
7934                                         mono_constant_fold_inst (tree, NULL); 
7935                         }
7936                         mono_constant_fold_inst (tree, NULL); 
7937                 }
7938         }
7939 }
7940
7941 static void
7942 mono_cprop_invalidate_values (MonoInst *tree, MonoInst **acp, int acp_size)
7943 {
7944         int arity;
7945
7946         switch (tree->opcode) {
7947         case CEE_STIND_I:
7948         case CEE_STIND_I1:
7949         case CEE_STIND_I2:
7950         case CEE_STIND_I4:
7951         case CEE_STIND_REF:
7952         case CEE_STIND_I8:
7953         case CEE_STIND_R4:
7954         case CEE_STIND_R8:
7955         case CEE_STOBJ:
7956                 if (tree->ssa_op == MONO_SSA_NOP) {
7957                         memset (acp, 0, sizeof (MonoInst *) * acp_size);
7958                         return;
7959                 }
7960
7961                 break;
7962         case CEE_CALL:
7963         case OP_CALL_REG:
7964         case CEE_CALLVIRT:
7965         case OP_LCALL_REG:
7966         case OP_LCALLVIRT:
7967         case OP_LCALL:
7968         case OP_FCALL_REG:
7969         case OP_FCALLVIRT:
7970         case OP_FCALL:
7971         case OP_VCALL_REG:
7972         case OP_VCALLVIRT:
7973         case OP_VCALL:
7974         case OP_VOIDCALL_REG:
7975         case OP_VOIDCALLVIRT:
7976         case OP_VOIDCALL: {
7977                 MonoCallInst *call = (MonoCallInst *)tree;
7978                 MonoMethodSignature *sig = call->signature;
7979                 int i, byref = FALSE;
7980
7981                 for (i = 0; i < sig->param_count; i++) {
7982                         if (sig->params [i]->byref) {
7983                                 byref = TRUE;
7984                                 break;
7985                         }
7986                 }
7987
7988                 if (byref)
7989                         memset (acp, 0, sizeof (MonoInst *) * acp_size);
7990
7991                 return;
7992         }
7993         default:
7994                 break;
7995         }
7996
7997         arity = mono_burg_arity [tree->opcode];
7998
7999         switch (arity) {
8000         case 0:
8001                 break;
8002         case 1:
8003                 mono_cprop_invalidate_values (tree->inst_i0, acp, acp_size);
8004                 break;
8005         case 2:
8006                 mono_cprop_invalidate_values (tree->inst_i0, acp, acp_size);
8007                 mono_cprop_invalidate_values (tree->inst_i1, acp, acp_size);
8008                 break;
8009         default:
8010                 g_assert_not_reached ();
8011         }
8012 }
8013
8014 static void
8015 mono_local_cprop_bb (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst **acp, int acp_size)
8016 {
8017         MonoInst *tree = bb->code;      
8018         int i;
8019
8020         if (!tree)
8021                 return;
8022
8023         for (; tree; tree = tree->next) {
8024
8025                 mono_cprop_copy_values (cfg, tree, acp);
8026
8027                 mono_cprop_invalidate_values (tree, acp, acp_size);
8028
8029                 if (tree->ssa_op == MONO_SSA_STORE  && 
8030                     (tree->inst_i0->opcode == OP_LOCAL || tree->inst_i0->opcode == OP_ARG)) {
8031                         MonoInst *i1 = tree->inst_i1;
8032
8033                         acp [tree->inst_i0->inst_c0] = NULL;
8034
8035                         for (i = 0; i < acp_size; i++) {
8036                                 if (acp [i] && acp [i]->opcode != OP_ICONST && 
8037                                     acp [i]->inst_c0 == tree->inst_i0->inst_c0) {
8038                                         acp [i] = NULL;
8039                                 }
8040                         }
8041
8042                         if (i1->opcode == OP_ICONST) {
8043                                 acp [tree->inst_i0->inst_c0] = i1;
8044                                 //printf ("DEF1 BB%d %d\n", bb->block_num,tree->inst_i0->inst_c0);
8045                         }
8046                         if (i1->ssa_op == MONO_SSA_LOAD && 
8047                             (i1->inst_i0->opcode == OP_LOCAL || i1->inst_i0->opcode == OP_ARG) &&
8048                             (i1->inst_i0->inst_c0 != tree->inst_i0->inst_c0)) {
8049                                 acp [tree->inst_i0->inst_c0] = i1->inst_i0;
8050                                 //printf ("DEF2 BB%d %d %d\n", bb->block_num,tree->inst_i0->inst_c0,i1->inst_i0->inst_c0);
8051                         }
8052                 }
8053
8054                 /*
8055                   if (tree->opcode == CEE_BEQ) {
8056                   g_assert (tree->inst_i0->opcode == OP_COMPARE);
8057                   if (tree->inst_i0->inst_i0->opcode == OP_ICONST &&
8058                   tree->inst_i0->inst_i1->opcode == OP_ICONST) {
8059                   
8060                   tree->opcode = CEE_BR;
8061                   if (tree->inst_i0->inst_i0->opcode == tree->inst_i0->inst_i1->opcode) {
8062                   tree->inst_target_bb = tree->inst_true_bb;
8063                   } else {
8064                   tree->inst_target_bb = tree->inst_false_bb;
8065                   }
8066                   }
8067                   }
8068                 */
8069         }
8070 }
8071
8072 static void
8073 mono_local_cprop (MonoCompile *cfg)
8074 {
8075         MonoBasicBlock *bb;
8076         MonoInst **acp;
8077
8078         acp = alloca (sizeof (MonoInst *) * cfg->num_varinfo);
8079
8080         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
8081                 memset (acp, 0, sizeof (MonoInst *) * cfg->num_varinfo);
8082                 mono_local_cprop_bb (cfg, bb, acp, cfg->num_varinfo);
8083         }
8084 }
8085
8086 static void
8087 remove_critical_edges (MonoCompile *cfg) {
8088         MonoBasicBlock *bb;
8089         
8090         if (cfg->verbose_level > 3) {
8091                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
8092                         int i;
8093                         printf ("remove_critical_edges %s, BEFORE BB%d (in:", mono_method_full_name (cfg->method, TRUE), bb->block_num);
8094                         for (i = 0; i < bb->in_count; i++) {
8095                                 printf (" %d", bb->in_bb [i]->block_num);
8096                         }
8097                         printf (") (out:");
8098                         for (i = 0; i < bb->out_count; i++) {
8099                                 printf (" %d", bb->out_bb [i]->block_num);
8100                         }
8101                         printf (")");
8102                         if (bb->last_ins != NULL) {
8103                                 printf (" ");
8104                                 mono_print_tree (bb->last_ins);
8105                         }
8106                         printf ("\n");
8107                 }
8108         }
8109         
8110         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
8111                 if (bb->out_count > 1) {
8112                         int out_bb_index;
8113                         for (out_bb_index = 0; out_bb_index < bb->out_count; out_bb_index++) {
8114                                 MonoBasicBlock *out_bb = bb->out_bb [out_bb_index];
8115                                 if (out_bb->in_count > 1) {
8116                                         MonoInst *inst;
8117                                         MonoBasicBlock *new_bb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
8118                                         new_bb->block_num = cfg->num_bblocks++;
8119                                         new_bb->next_bb = bb->next_bb;
8120                                         bb->next_bb = new_bb;
8121                                         new_bb->in_bb = mono_mempool_alloc ((cfg)->mempool, sizeof (MonoBasicBlock*));
8122                                         new_bb->in_bb [0] = bb;
8123                                         new_bb->in_count = 1;
8124                                         new_bb->out_bb = mono_mempool_alloc ((cfg)->mempool, sizeof (MonoBasicBlock*));
8125                                         new_bb->out_bb [0] = out_bb;
8126                                         new_bb->out_count = 1;
8127                                         replace_out_block (bb, out_bb, new_bb);
8128                                         replace_in_block (out_bb, bb, new_bb);
8129                                         for (inst = bb->code; inst != NULL; inst = inst->next) {
8130                                                 if (inst->opcode == OP_CALL_HANDLER) {
8131                                                         if (inst->inst_target_bb == out_bb) {
8132                                                                 inst->inst_target_bb = new_bb;
8133                                                         }
8134                                                 }
8135                                         }
8136                                         if (bb->last_ins != NULL) {
8137                                                 switch (bb->last_ins->opcode) {
8138                                                 case CEE_BR:
8139                                                         if (bb->last_ins->inst_target_bb == out_bb) {
8140                                                                 bb->last_ins->inst_target_bb = new_bb;
8141                                                         }
8142                                                         break;
8143                                                 case CEE_SWITCH: {
8144                                                         int i;
8145                                                         int n = GPOINTER_TO_INT (bb->last_ins->klass);
8146                                                         for (i = 0; i < n; i++ ) {
8147                                                                 if (bb->last_ins->inst_many_bb [i] == out_bb) {
8148                                                                         bb->last_ins->inst_many_bb [i] = new_bb;
8149                                                                         break;
8150                                                                 }
8151                                                         }
8152                                                         break;
8153                                                 }
8154                                                 case CEE_BNE_UN:
8155                                                 case CEE_BEQ:
8156                                                 case CEE_BLT:
8157                                                 case CEE_BLT_UN:
8158                                                 case CEE_BGT:
8159                                                 case CEE_BGT_UN:
8160                                                 case CEE_BGE:
8161                                                 case CEE_BGE_UN:
8162                                                 case CEE_BLE:
8163                                                 case CEE_BLE_UN:
8164                                                         if (bb->last_ins->inst_true_bb == out_bb) {
8165                                                                 bb->last_ins->inst_true_bb = new_bb;
8166                                                         }
8167                                                         if (bb->last_ins->inst_false_bb == out_bb) {
8168                                                                 bb->last_ins->inst_false_bb = new_bb;
8169                                                         }
8170                                                         break;
8171                                                 default:
8172                                                         break;
8173                                                 }
8174                                         }
8175 //                                      new_bb->real_offset = bb->real_offset;
8176                                         new_bb->region = bb->region;
8177                                         
8178                                         if (new_bb->next_bb != out_bb) {
8179                                                 MonoInst *jump;
8180                                                 MONO_INST_NEW (cfg, jump, CEE_BR);
8181                                                 MONO_ADD_INS (new_bb, jump);
8182                                                 jump->cil_code = bb->cil_code;
8183                                                 jump->inst_target_bb = out_bb;
8184                                         }
8185                                         
8186                                         if (cfg->verbose_level > 2) {
8187                                                 printf ("remove_critical_edges %s, removed critical edge from BB%d to BB%d (added BB%d)\n", mono_method_full_name (cfg->method, TRUE), bb->block_num, out_bb->block_num, new_bb->block_num);
8188                                         }
8189                                 }
8190                         }
8191                 }
8192         }
8193         
8194         if (cfg->verbose_level > 3) {
8195                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
8196                         int i;
8197                         printf ("remove_critical_edges %s, AFTER BB%d (in:", mono_method_full_name (cfg->method, TRUE), bb->block_num);
8198                         for (i = 0; i < bb->in_count; i++) {
8199                                 printf (" %d", bb->in_bb [i]->block_num);
8200                         }
8201                         printf (") (out:");
8202                         for (i = 0; i < bb->out_count; i++) {
8203                                 printf (" %d", bb->out_bb [i]->block_num);
8204                         }
8205                         printf (")");
8206                         if (bb->last_ins != NULL) {
8207                                 printf (" ");
8208                                 mono_print_tree (bb->last_ins);
8209                         }
8210                         printf ("\n");
8211                 }
8212         }
8213 }
8214
8215
8216 MonoCompile*
8217 mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gboolean run_cctors, gboolean compile_aot, int parts)
8218 {
8219         MonoMethodHeader *header = mono_method_get_header (method);
8220         guint8 *ip = (guint8 *)header->code;
8221         MonoCompile *cfg;
8222         MonoJitInfo *jinfo;
8223         int dfn = 0, i, code_size_ratio;
8224
8225         mono_jit_stats.methods_compiled++;
8226         if (mono_profiler_get_events () & MONO_PROFILE_JIT_COMPILATION)
8227                 mono_profiler_method_jit (method);
8228
8229         cfg = g_new0 (MonoCompile, 1);
8230         cfg->method = method;
8231         cfg->mempool = mono_mempool_new ();
8232         cfg->opt = opts;
8233         cfg->prof_options = mono_profiler_get_events ();
8234         cfg->run_cctors = run_cctors;
8235         cfg->bb_hash = g_hash_table_new (NULL, NULL);
8236         cfg->domain = domain;
8237         cfg->verbose_level = mini_verbose;
8238         cfg->compile_aot = compile_aot;
8239         cfg->intvars = mono_mempool_alloc0 (cfg->mempool, sizeof (guint16) * STACK_MAX * 
8240                                             mono_method_get_header (method)->max_stack);
8241
8242         if (cfg->verbose_level > 2)
8243                 g_print ("converting method %s\n", mono_method_full_name (method, TRUE));
8244
8245         /*
8246          * create MonoInst* which represents arguments and local variables
8247          */
8248         mono_compile_create_vars (cfg);
8249
8250         if ((i = mono_method_to_ir (cfg, method, NULL, NULL, cfg->locals_start, NULL, NULL, NULL, 0, FALSE)) < 0) {
8251                 if (cfg->prof_options & MONO_PROFILE_JIT_COMPILATION)
8252                         mono_profiler_method_end_jit (method, MONO_PROFILE_FAILED);
8253                 mono_destroy_compile (cfg);
8254                 return NULL;
8255         }
8256
8257         mono_jit_stats.basic_blocks += cfg->num_bblocks;
8258         mono_jit_stats.max_basic_blocks = MAX (cfg->num_bblocks, mono_jit_stats.max_basic_blocks);
8259
8260         if (cfg->num_varinfo > 2000) {
8261                 /* 
8262                  * we disable some optimizations if there are too many variables
8263                  * because JIT time may become too expensive. The actual number needs 
8264                  * to be tweaked and eventually the non-linear algorithms should be fixed.
8265                  */
8266                 cfg->opt &= ~ (MONO_OPT_LINEARS | MONO_OPT_COPYPROP | MONO_OPT_CONSPROP);
8267                 cfg->disable_ssa = TRUE;
8268         }
8269         /*g_print ("numblocks = %d\n", cfg->num_bblocks);*/
8270
8271         if (cfg->opt & MONO_OPT_BRANCH)
8272                 optimize_branches (cfg);
8273
8274         if (cfg->opt & MONO_OPT_SSAPRE) {
8275                 remove_critical_edges (cfg);
8276         }
8277
8278         /* Depth-first ordering on basic blocks */
8279         cfg->bblocks = mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * (cfg->num_bblocks + 1));
8280
8281         df_visit (cfg->bb_entry, &dfn, cfg->bblocks);
8282         if (cfg->num_bblocks != dfn + 1) {
8283                 MonoBasicBlock *bb;
8284
8285                 cfg->num_bblocks = dfn + 1;
8286
8287                 if (!header->clauses) {
8288                         /* remove unreachable code, because the code in them may be 
8289                          * inconsistent  (access to dead variables for example) */
8290                         for (bb = cfg->bb_entry; bb;) {
8291                                 MonoBasicBlock *bbn = bb->next_bb;
8292
8293                                 if (bbn && bbn->region == -1 && !bbn->dfn) {
8294                                         if (cfg->verbose_level > 1)
8295                                                 g_print ("found unreachabel code in BB%d\n", bbn->block_num);
8296                                         bb->next_bb = bbn->next_bb;
8297                                         nullify_basic_block (bbn);                      
8298                                 } else {
8299                                         bb = bb->next_bb;
8300                                 }
8301                         }
8302                 }
8303         }
8304
8305         if (cfg->opt & MONO_OPT_LOOP) {
8306                 mono_compile_dominator_info (cfg, MONO_COMP_DOM | MONO_COMP_IDOM);
8307                 mono_compute_natural_loops (cfg);
8308         }
8309
8310         /* after method_to_ir */
8311         if (parts == 1)
8312                 return cfg;
8313
8314 //#define DEBUGSSA "logic_run"
8315 #define DEBUGSSA_CLASS "Tests"
8316 #ifdef DEBUGSSA
8317
8318         if (!header->num_clauses && !cfg->disable_ssa) {
8319                 mono_local_cprop (cfg);
8320                 mono_ssa_compute (cfg);
8321         }
8322 #else 
8323
8324         /* fixme: add all optimizations which requires SSA */
8325         if (cfg->opt & (MONO_OPT_DEADCE | MONO_OPT_ABCREM | MONO_OPT_SSAPRE)) {
8326                 if (!(cfg->comp_done & MONO_COMP_SSA) && !header->num_clauses && !cfg->disable_ssa) {
8327                         mono_local_cprop (cfg);
8328                         mono_ssa_compute (cfg);
8329
8330                         if (cfg->verbose_level >= 2) {
8331                                 print_dfn (cfg);
8332                         }
8333                 }
8334         }
8335 #endif
8336
8337         /* after SSA translation */
8338         if (parts == 2)
8339                 return cfg;
8340
8341         if ((cfg->opt & MONO_OPT_CONSPROP) || (cfg->opt & MONO_OPT_COPYPROP)) {
8342                 if (cfg->comp_done & MONO_COMP_SSA) {
8343                         mono_ssa_cprop (cfg);
8344                 } else {
8345                         mono_local_cprop (cfg);
8346                 }
8347         }
8348
8349         if (cfg->comp_done & MONO_COMP_SSA) {                   
8350                 mono_ssa_deadce (cfg);
8351
8352                 //mono_ssa_strength_reduction (cfg);
8353
8354                 if ((cfg->flags & MONO_CFG_HAS_LDELEMA) && (cfg->opt & MONO_OPT_ABCREM))
8355                         mono_perform_abc_removal (cfg);
8356                 
8357                 if (cfg->opt & MONO_OPT_SSAPRE)
8358                         mono_perform_ssapre (cfg);
8359                 
8360                 mono_ssa_remove (cfg);
8361
8362                 if (cfg->opt & MONO_OPT_BRANCH)
8363                         optimize_branches (cfg);
8364         }
8365
8366         /* after SSA removal */
8367         if (parts == 3)
8368                 return cfg;
8369
8370         decompose_pass (cfg);
8371
8372         if (cfg->got_var) {
8373                 GList *regs;
8374
8375                 /* The decompose pass may create calls which need the got var */
8376                 mono_emit_load_got_addr (cfg);
8377
8378                 /* 
8379                  * Allways allocate the GOT var to a register, because keeping it
8380                  * in memory will increase the number of live temporaries in some
8381                  * code created by inssel.brg, leading to the well known spills+
8382                  * branches problem. Testcase: mcs crash in 
8383                  * System.MonoCustomAttrs:GetCustomAttributes.
8384                  */
8385                 regs = mono_arch_get_global_int_regs (cfg);
8386                 g_assert (regs);
8387                 cfg->got_var->opcode = OP_REGVAR;
8388                 cfg->got_var->dreg = GPOINTER_TO_INT (regs->data);
8389                 cfg->used_int_regs |= 1LL << cfg->got_var->dreg;
8390                 
8391                 g_list_free (regs);
8392         }
8393
8394         if (cfg->opt & MONO_OPT_LINEARS) {
8395                 GList *vars, *regs;
8396
8397                 /* fixme: maybe we can avoid to compute livenesss here if already computed ? */
8398                 cfg->comp_done &= ~MONO_COMP_LIVENESS;
8399                 if (!(cfg->comp_done & MONO_COMP_LIVENESS))
8400                         mono_analyze_liveness (cfg);
8401
8402                 if ((vars = mono_arch_get_allocatable_int_vars (cfg))) {
8403                         regs = mono_arch_get_global_int_regs (cfg);
8404                         if (cfg->got_var)
8405                                 regs = g_list_delete_link (regs, regs);
8406                         mono_linear_scan (cfg, vars, regs, &cfg->used_int_regs);
8407                 }
8408         }
8409
8410         //mono_print_code (cfg);
8411
8412        //print_dfn (cfg);
8413         
8414         /* variables are allocated after decompose, since decompose could create temps */
8415         mono_arch_allocate_vars (cfg);
8416
8417         if (cfg->opt & MONO_OPT_CFOLD)
8418                 mono_constant_fold (cfg);
8419
8420         mini_select_instructions (cfg);
8421
8422         mono_codegen (cfg);
8423         if (cfg->verbose_level >= 2) {
8424                 char *id =  mono_method_full_name (cfg->method, FALSE);
8425                 mono_disassemble_code (cfg->native_code, cfg->code_len, id + 3);
8426                 g_free (id);
8427         }
8428         
8429         if (cfg->method->dynamic)
8430                 jinfo = g_new0 (MonoJitInfo, 1);
8431         else
8432                 jinfo = mono_mempool_alloc0 (cfg->domain->mp, sizeof (MonoJitInfo));
8433
8434         jinfo->method = method;
8435         jinfo->code_start = cfg->native_code;
8436         jinfo->code_size = cfg->code_len;
8437         jinfo->used_regs = cfg->used_int_regs;
8438         jinfo->domain_neutral = (cfg->opt & MONO_OPT_SHARED) != 0;
8439         jinfo->cas_inited = FALSE; /* initialization delayed at the first stalk walk using this method */
8440
8441         if (header->num_clauses) {
8442                 int i;
8443
8444                 jinfo->exvar_offset = cfg->exvar? cfg->exvar->inst_offset: 0;
8445                 jinfo->num_clauses = header->num_clauses;
8446                 jinfo->clauses = mono_mempool_alloc0 (cfg->domain->mp, 
8447                         sizeof (MonoJitExceptionInfo) * header->num_clauses);
8448
8449                 for (i = 0; i < header->num_clauses; i++) {
8450                         MonoExceptionClause *ec = &header->clauses [i];
8451                         MonoJitExceptionInfo *ei = &jinfo->clauses [i];
8452                         MonoBasicBlock *tblock;
8453
8454                         ei->flags = ec->flags;
8455
8456                         if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
8457                                 tblock = g_hash_table_lookup (cfg->bb_hash, ip + ec->data.filter_offset);
8458                                 g_assert (tblock);
8459                                 ei->data.filter = cfg->native_code + tblock->native_offset;
8460                         } else {
8461                                 ei->data.catch_class = ec->data.catch_class;
8462                         }
8463
8464                         tblock = g_hash_table_lookup (cfg->bb_hash, ip + ec->try_offset);
8465                         g_assert (tblock);
8466                         ei->try_start = cfg->native_code + tblock->native_offset;
8467                         g_assert (tblock->native_offset);
8468                         tblock = g_hash_table_lookup (cfg->bb_hash, ip + ec->try_offset + ec->try_len);
8469                         g_assert (tblock);
8470                         ei->try_end = cfg->native_code + tblock->native_offset;
8471                         g_assert (tblock->native_offset);
8472                         tblock = g_hash_table_lookup (cfg->bb_hash, ip + ec->handler_offset);
8473                         g_assert (tblock);
8474                         ei->handler_start = cfg->native_code + tblock->native_offset;
8475                 }
8476         }
8477
8478         cfg->jit_info = jinfo;
8479
8480         mono_jit_info_table_add (cfg->domain, jinfo);
8481
8482         if (cfg->method->dynamic)
8483                 mono_dynamic_code_hash_lookup (cfg->domain, cfg->method)->ji = jinfo;
8484
8485         /* collect statistics */
8486         mono_jit_stats.allocated_code_size += cfg->code_len;
8487         code_size_ratio = cfg->code_len;
8488         if (code_size_ratio > mono_jit_stats.biggest_method_size) {
8489                         mono_jit_stats.biggest_method_size = code_size_ratio;
8490                         mono_jit_stats.biggest_method = method;
8491         }
8492         code_size_ratio = (code_size_ratio * 100) / mono_method_get_header (method)->code_size;
8493         if (code_size_ratio > mono_jit_stats.max_code_size_ratio) {
8494                 mono_jit_stats.max_code_size_ratio = code_size_ratio;
8495                 mono_jit_stats.max_ratio_method = method;
8496         }
8497         mono_jit_stats.native_code_size += cfg->code_len;
8498
8499         if (cfg->prof_options & MONO_PROFILE_JIT_COMPILATION)
8500                 mono_profiler_method_end_jit (method, MONO_PROFILE_OK);
8501
8502         return cfg;
8503 }
8504
8505 static gpointer
8506 mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain)
8507 {
8508         MonoCompile *cfg;
8509         GHashTable *jit_code_hash;
8510         gpointer code = NULL;
8511         guint32 opt;
8512         MonoJitInfo *info;
8513
8514         opt = default_opt;
8515
8516         jit_code_hash = target_domain->jit_code_hash;
8517
8518 #ifdef MONO_USE_AOT_COMPILER
8519         if (!mono_compile_aot && (opt & MONO_OPT_AOT)) {
8520                 MonoJitInfo *info;
8521                 MonoDomain *domain = mono_domain_get ();
8522
8523                 mono_domain_lock (domain);
8524
8525                 mono_class_init (method->klass);
8526                 if ((info = mono_aot_get_method (domain, method))) {
8527                         g_hash_table_insert (domain->jit_code_hash, method, info);
8528                         mono_domain_unlock (domain);
8529                         mono_runtime_class_init (mono_class_vtable (domain, method->klass));
8530                         return info->code_start;
8531                 }
8532
8533                 mono_domain_unlock (domain);
8534         }
8535 #endif
8536
8537         if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
8538             (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
8539                 MonoMethod *nm;
8540                 MonoMethodPInvoke* piinfo = (MonoMethodPInvoke *) method;
8541
8542                 if (!piinfo->addr) {
8543                         if (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL)
8544                                 piinfo->addr = mono_lookup_internal_call (method);
8545                         else
8546                                 if (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
8547                                         mono_lookup_pinvoke_call (method, NULL, NULL);
8548                 }
8549                         nm = mono_marshal_get_native_wrapper (method);
8550                         return mono_compile_method (nm);
8551
8552                         //if (mono_debug_format != MONO_DEBUG_FORMAT_NONE) 
8553                         //mono_debug_add_wrapper (method, nm);
8554         } else if ((method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME)) {
8555                 const char *name = method->name;
8556                 MonoMethod *nm;
8557
8558                 if (method->klass->parent == mono_defaults.multicastdelegate_class) {
8559                         if (*name == '.' && (strcmp (name, ".ctor") == 0)) {
8560                                 /* FIXME: uhm, we need a wrapper to handle exceptions? */
8561                                 return (gpointer)mono_delegate_ctor;
8562                         } else if (*name == 'I' && (strcmp (name, "Invoke") == 0)) {
8563                                 nm = mono_marshal_get_delegate_invoke (method);
8564                                 return mono_jit_compile_method (nm);
8565                         } else if (*name == 'B' && (strcmp (name, "BeginInvoke") == 0)) {
8566                                 nm = mono_marshal_get_delegate_begin_invoke (method);
8567                                 return mono_jit_compile_method (nm);
8568                         } else if (*name == 'E' && (strcmp (name, "EndInvoke") == 0)) {
8569                                 nm = mono_marshal_get_delegate_end_invoke (method);
8570                                 return mono_jit_compile_method (nm);
8571                         }
8572                 }
8573                 return NULL;
8574         }
8575
8576         cfg = mini_method_compile (method, opt, target_domain, TRUE, FALSE, 0);
8577
8578         mono_domain_lock (target_domain);
8579
8580         /* Check if some other thread already did the job. In this case, we can
8581        discard the code this thread generated. */
8582
8583         if ((info = g_hash_table_lookup (target_domain->jit_code_hash, method))) {
8584                 /* We can't use a domain specific method in another domain */
8585                 if ((target_domain == mono_domain_get ()) || info->domain_neutral) {
8586                         code = info->code_start;
8587 //                      printf("Discarding code for method %s\n", method->name);
8588                 }
8589         }
8590         
8591         if (code == NULL) {
8592                 g_hash_table_insert (jit_code_hash, method, cfg->jit_info);
8593                 code = cfg->native_code;
8594         }
8595
8596         mono_destroy_compile (cfg);
8597
8598         if (target_domain->jump_target_hash) {
8599                 MonoJumpInfo patch_info;
8600                 GSList *list, *tmp;
8601                 list = g_hash_table_lookup (target_domain->jump_target_hash, method);
8602                 if (list) {
8603                         patch_info.next = NULL;
8604                         patch_info.ip.i = 0;
8605                         patch_info.type = MONO_PATCH_INFO_METHOD_JUMP;
8606                         patch_info.data.method = method;
8607                         g_hash_table_remove (target_domain->jump_target_hash, method);
8608                 }
8609                 for (tmp = list; tmp; tmp = tmp->next)
8610                         mono_arch_patch_code (NULL, target_domain, tmp->data, &patch_info, TRUE);
8611                 g_slist_free (list);
8612         }
8613
8614         mono_domain_unlock (target_domain);
8615
8616         mono_runtime_class_init (mono_class_vtable (target_domain, method->klass));
8617         return code;
8618 }
8619
8620 static gpointer
8621 mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt)
8622 {
8623         /* FIXME: later copy the code from mono */
8624         MonoDomain *target_domain, *domain = mono_domain_get ();
8625         MonoJitInfo *info;
8626         gpointer p;
8627
8628         if (opt & MONO_OPT_SHARED)
8629                 target_domain = mono_get_root_domain ();
8630         else 
8631                 target_domain = domain;
8632
8633         mono_domain_lock (target_domain);
8634
8635         if ((info = g_hash_table_lookup (target_domain->jit_code_hash, method))) {
8636                 /* We can't use a domain specific method in another domain */
8637                 if (! ((domain != target_domain) && !info->domain_neutral)) {
8638                         mono_domain_unlock (target_domain);
8639                         mono_jit_stats.methods_lookups++;
8640                         mono_runtime_class_init (mono_class_vtable (domain, method->klass));
8641                         return info->code_start;
8642                 }
8643         }
8644
8645         mono_domain_unlock (target_domain);
8646         p = mono_jit_compile_method_inner (method, target_domain);
8647         return p;
8648 }
8649
8650 static gpointer
8651 mono_jit_compile_method (MonoMethod *method)
8652 {
8653         return mono_jit_compile_method_with_opt (method, default_opt);
8654 }
8655
8656 static void
8657 invalidated_delegate_trampoline (MonoClass *klass)
8658 {
8659         g_error ("Unmanaged code called delegate of type %s which was already garbage collected.\n"
8660                  "See http://www.go-mono.com/delegate.html for an explanation and ways to fix this.",
8661                  mono_type_full_name (&klass->byval_arg));
8662 }
8663
8664 /*
8665  * mono_jit_free_method:
8666  *
8667  *  Free all memory allocated by the JIT for METHOD.
8668  */
8669 static void
8670 mono_jit_free_method (MonoDomain *domain, MonoMethod *method)
8671 {
8672         MonoJitDynamicMethodInfo *ji;
8673
8674         g_assert (method->dynamic);
8675
8676         mono_domain_lock (domain);
8677         ji = mono_dynamic_code_hash_lookup (domain, method);
8678         mono_domain_unlock (domain);
8679 #ifdef MONO_ARCH_HAVE_INVALIDATE_METHOD
8680         /* FIXME: only enable this with a env var */
8681         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
8682                 /*
8683                  * Instead of freeing the code, change it to call an error routine
8684                  * so people can fix their code.
8685                  */
8686                 if (ji){
8687                         char *type = mono_type_full_name (&method->klass->byval_arg);
8688                         char *type_and_method = g_strdup_printf ("%s.%s", type, method->name);
8689
8690                         g_free (type);
8691                         mono_arch_invalidate_method (ji->ji, invalidated_delegate_trampoline, type_and_method);
8692                 }
8693                 return;
8694         }
8695 #endif
8696
8697         if (!ji)
8698                 return;
8699         mono_domain_lock (domain);
8700         g_hash_table_remove (domain->dynamic_code_hash, ji);
8701         mono_domain_unlock (domain);
8702
8703         mono_code_manager_destroy (ji->code_mp);
8704         mono_jit_info_table_remove (domain, ji->ji);
8705         g_free (ji->ji);
8706         g_free (ji);
8707 }
8708
8709 static gpointer
8710 mono_jit_find_compiled_method (MonoDomain *domain, MonoMethod *method)
8711 {
8712         MonoDomain *target_domain;
8713         MonoJitInfo *info;
8714
8715         if (default_opt & MONO_OPT_SHARED)
8716                 target_domain = mono_get_root_domain ();
8717         else 
8718                 target_domain = domain;
8719
8720         mono_domain_lock (target_domain);
8721
8722         if ((info = g_hash_table_lookup (target_domain->jit_code_hash, method))) {
8723                 /* We can't use a domain specific method in another domain */
8724                 if (! ((domain != target_domain) && !info->domain_neutral)) {
8725                         mono_domain_unlock (target_domain);
8726                         mono_jit_stats.methods_lookups++;
8727                         return info->code_start;
8728                 }
8729         }
8730
8731         mono_domain_unlock (target_domain);
8732
8733         return NULL;
8734 }
8735
8736 /**
8737  * mono_jit_runtime_invoke:
8738  * @method: the method to invoke
8739  * @obj: this pointer
8740  * @params: array of parameter values.
8741  * @exc: used to catch exceptions objects
8742  */
8743 static MonoObject*
8744 mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
8745 {
8746         MonoMethod *invoke;
8747         MonoObject *(*runtime_invoke) (MonoObject *this, void **params, MonoObject **exc, void* compiled_method);
8748         void* compiled_method;
8749
8750         if (obj == NULL && !(method->flags & METHOD_ATTRIBUTE_STATIC) && !method->string_ctor && (method->wrapper_type == 0)) {
8751                 g_warning ("Ignoring invocation of an instance method on a NULL instance.\n");
8752                 return NULL;
8753         }
8754
8755         invoke = mono_marshal_get_runtime_invoke (method);
8756         runtime_invoke = mono_jit_compile_method (invoke);
8757         
8758         /* We need this here becuase mono_marshal_get_runtime_invoke can be place 
8759          * the helper method in System.Object and not the target class
8760          */
8761         mono_runtime_class_init (mono_class_vtable (mono_domain_get (), method->klass));
8762
8763         compiled_method = mono_jit_compile_method (method);
8764         return runtime_invoke (obj, params, exc, compiled_method);
8765 }
8766
8767 #ifdef PLATFORM_WIN32
8768 #define GET_CONTEXT \
8769         struct sigcontext *ctx = (struct sigcontext*)_dummy;
8770 #else
8771 #ifdef __sparc
8772 #define GET_CONTEXT \
8773     void *ctx = context;
8774 #elif defined(sun)    // Solaris x86
8775 #define GET_CONTEXT \
8776     ucontext_t *uctx = context; \
8777     struct sigcontext *ctx = (struct sigcontext *)&(uctx->uc_mcontext);
8778 #elif defined(__ppc__) || defined (__powerpc__) || defined (__s390__) || defined (MONO_ARCH_USE_SIGACTION)
8779 #define GET_CONTEXT \
8780     void *ctx = context;
8781 #else
8782 #define GET_CONTEXT \
8783         void **_p = (void **)&_dummy; \
8784         struct sigcontext *ctx = (struct sigcontext *)++_p;
8785 #endif
8786 #endif
8787
8788 #ifdef MONO_ARCH_USE_SIGACTION
8789 #define SIG_HANDLER_SIGNATURE(ftn) ftn (int _dummy, siginfo_t *info, void *context)
8790 #else
8791 #define SIG_HANDLER_SIGNATURE(ftn) ftn (int _dummy)
8792 #endif
8793
8794 static void
8795 SIG_HANDLER_SIGNATURE (sigfpe_signal_handler)
8796 {
8797         MonoException *exc = NULL;
8798 #ifndef MONO_ARCH_USE_SIGACTION
8799         void *info = NULL;
8800 #endif
8801         GET_CONTEXT;
8802
8803 #if defined(MONO_ARCH_HAVE_IS_INT_OVERFLOW)
8804         if (mono_arch_is_int_overflow (ctx, info))
8805                 exc = mono_get_exception_arithmetic ();
8806         else
8807                 exc = mono_get_exception_divide_by_zero ();
8808 #else
8809         exc = mono_get_exception_divide_by_zero ();
8810 #endif
8811         
8812         mono_arch_handle_exception (ctx, exc, FALSE);
8813 }
8814
8815 static void
8816 SIG_HANDLER_SIGNATURE (sigill_signal_handler)
8817 {
8818         MonoException *exc;
8819         GET_CONTEXT
8820         exc = mono_get_exception_execution_engine ("SIGILL");
8821         
8822         mono_arch_handle_exception (ctx, exc, FALSE);
8823 }
8824
8825 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
8826
8827 static void
8828 sigsegv_signal_handler (int _dummy, siginfo_t *info, void *context)
8829 {
8830         MonoException *exc;
8831         MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
8832         struct sigcontext *ctx = (struct sigcontext *)&(((ucontext_t*)context)->uc_mcontext);
8833
8834         /* Can't allocate memory using Boehm GC on altstack */
8835         if (jit_tls->stack_size && 
8836                 ((guint8*)info->si_addr >= (guint8*)jit_tls->end_of_stack - jit_tls->stack_size) &&
8837                 ((guint8*)info->si_addr < (guint8*)jit_tls->end_of_stack))
8838                 exc = mono_domain_get ()->stack_overflow_ex;
8839         else
8840                 exc = mono_domain_get ()->null_reference_ex;
8841                         
8842         mono_arch_handle_exception (ctx, exc, FALSE);
8843 }
8844
8845 #else
8846
8847 static void
8848 SIG_HANDLER_SIGNATURE (sigsegv_signal_handler)
8849 {
8850         GET_CONTEXT;
8851
8852         mono_arch_handle_exception (ctx, NULL, FALSE);
8853 }
8854
8855 #endif
8856
8857 static void
8858 SIG_HANDLER_SIGNATURE (sigusr1_signal_handler)
8859 {
8860         gboolean running_managed;
8861         MonoException *exc;
8862         
8863         GET_CONTEXT
8864
8865         running_managed = (mono_jit_info_table_find (mono_domain_get (), mono_arch_ip_from_context(ctx)) != NULL);
8866         
8867         exc = mono_thread_request_interruption (running_managed); 
8868         if (!exc) return;
8869
8870         mono_arch_handle_exception (ctx, exc, FALSE);
8871 }
8872
8873 static void
8874 SIG_HANDLER_SIGNATURE (sigprof_signal_handler)
8875 {
8876         GET_CONTEXT;
8877
8878         mono_profiler_stat_hit (mono_arch_ip_from_context (ctx), ctx);
8879 }
8880
8881 static void
8882 SIG_HANDLER_SIGNATURE (sigquit_signal_handler)
8883 {
8884        MonoException *exc;
8885        GET_CONTEXT
8886
8887        exc = mono_get_exception_execution_engine ("Interrupted (SIGQUIT).");
8888        
8889        mono_arch_handle_exception (ctx, exc, FALSE);
8890 }
8891
8892 static void
8893 SIG_HANDLER_SIGNATURE (sigint_signal_handler)
8894 {
8895         MonoException *exc;
8896         GET_CONTEXT
8897
8898         exc = mono_get_exception_execution_engine ("Interrupted (SIGINT).");
8899         
8900         mono_arch_handle_exception (ctx, exc, FALSE);
8901 }
8902
8903 #ifndef PLATFORM_WIN32
8904 static void
8905 add_signal_handler (int signo, gpointer handler)
8906 {
8907         struct sigaction sa;
8908
8909 #ifdef MONO_ARCH_USE_SIGACTION
8910         sa.sa_sigaction = handler;
8911         sigemptyset (&sa.sa_mask);
8912         sa.sa_flags = SA_SIGINFO;
8913 #else
8914         sa.sa_handler = handler;
8915         sigemptyset (&sa.sa_mask);
8916         sa.sa_flags = 0;
8917 #endif
8918         g_assert (sigaction (signo, &sa, NULL) != -1);
8919 }
8920 #endif
8921
8922 static void
8923 mono_runtime_install_handlers (void)
8924 {
8925 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
8926         struct sigaction sa;
8927 #endif
8928
8929 #ifdef PLATFORM_WIN32
8930         win32_seh_init();
8931         win32_seh_set_handler(SIGFPE, sigfpe_signal_handler);
8932         win32_seh_set_handler(SIGILL, sigill_signal_handler);
8933         win32_seh_set_handler(SIGSEGV, sigsegv_signal_handler);
8934         if (getenv ("MONO_DEBUG"))
8935                 win32_seh_set_handler(SIGINT, sigint_signal_handler);
8936 #else /* !PLATFORM_WIN32 */
8937
8938         /* libpthreads has its own implementation of sigaction(),
8939          * but it seems to work well with our current exception
8940          * handlers. If not we must call syscall directly instead 
8941          * of sigaction */
8942
8943         if (getenv ("MONO_DEBUG")) {
8944                 add_signal_handler (SIGINT, sigint_signal_handler);
8945         }
8946
8947         add_signal_handler (SIGFPE, sigfpe_signal_handler);
8948         add_signal_handler (SIGQUIT, sigquit_signal_handler);
8949         add_signal_handler (SIGILL, sigill_signal_handler);
8950         add_signal_handler (SIGBUS, sigsegv_signal_handler);
8951         add_signal_handler (mono_thread_get_abort_signal (), sigusr1_signal_handler);
8952
8953         /* catch SIGSEGV */
8954 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
8955         sa.sa_sigaction = sigsegv_signal_handler;
8956         sigemptyset (&sa.sa_mask);
8957         sa.sa_flags = SA_SIGINFO | SA_ONSTACK;
8958         g_assert (sigaction (SIGSEGV, &sa, NULL) != -1);
8959 #else
8960         add_signal_handler (SIGSEGV, sigsegv_signal_handler);
8961 #endif
8962
8963 #endif /* PLATFORM_WIN32 */
8964 }
8965
8966 static void
8967 setup_stat_profiler (void)
8968 {
8969 #ifdef ITIMER_PROF
8970         struct itimerval itval;
8971         static int inited = 0;
8972
8973         itval.it_interval.tv_usec = 1000;
8974         itval.it_interval.tv_sec = 0;
8975         itval.it_value = itval.it_interval;
8976         setitimer (ITIMER_PROF, &itval, NULL);
8977         if (inited)
8978                 return;
8979         inited = 1;
8980         add_signal_handler (SIGPROF, sigprof_signal_handler);
8981 #endif
8982 }
8983
8984 /* mono_jit_create_remoting_trampoline:
8985  * @method: pointer to the method info
8986  *
8987  * Creates a trampoline which calls the remoting functions. This
8988  * is used in the vtable of transparent proxies.
8989  * 
8990  * Returns: a pointer to the newly created code 
8991  */
8992 static gpointer
8993 mono_jit_create_remoting_trampoline (MonoMethod *method, MonoRemotingTarget target)
8994 {
8995         MonoMethod *nm;
8996         guint8 *addr = NULL;
8997
8998         if ((method->flags & METHOD_ATTRIBUTE_ABSTRACT) || 
8999             (method->signature->hasthis && (method->klass->marshalbyref || method->klass == mono_defaults.object_class))) {
9000                 nm = mono_marshal_get_remoting_invoke_for_target (method, target);
9001                 addr = mono_compile_method (nm);
9002         } else {
9003                 addr = mono_compile_method (method);
9004         }
9005         return addr;
9006 }
9007
9008 MonoDomain *
9009 mini_init (const char *filename)
9010 {
9011         MonoDomain *domain;
9012
9013         mono_arch_cpu_init ();
9014
9015         if (!g_thread_supported ())
9016                 g_thread_init (NULL);
9017         
9018         MONO_GC_PRE_INIT ();
9019
9020         mono_jit_tls_id = TlsAlloc ();
9021         setup_jit_tls_data ((gpointer)-1, mono_thread_abort);
9022
9023         InitializeCriticalSection (&jit_mutex);
9024
9025         mono_burg_init ();
9026
9027         if (default_opt & MONO_OPT_AOT)
9028                 mono_aot_init ();
9029
9030         mono_runtime_install_handlers ();
9031         mono_threads_install_cleanup (mini_thread_cleanup);
9032
9033 #define JIT_TRAMPOLINES_WORK
9034 #ifdef JIT_TRAMPOLINES_WORK
9035         mono_install_compile_method (mono_jit_compile_method);
9036         mono_install_free_method (mono_jit_free_method);
9037         mono_install_trampoline (mono_create_jit_trampoline);
9038         mono_install_remoting_trampoline (mono_jit_create_remoting_trampoline);
9039 #endif
9040 #define JIT_INVOKE_WORKS
9041 #ifdef JIT_INVOKE_WORKS
9042         mono_install_runtime_invoke (mono_jit_runtime_invoke);
9043         mono_install_handler (mono_arch_get_throw_exception ());
9044 #endif
9045         mono_install_stack_walk (mono_jit_walk_stack);
9046
9047         domain = mono_init_from_assembly (filename, filename);
9048         mono_init_icall ();
9049
9050         mono_add_internal_call ("System.Diagnostics.StackFrame::get_frame_info", 
9051                                 ves_icall_get_frame_info);
9052         mono_add_internal_call ("System.Diagnostics.StackTrace::get_trace", 
9053                                 ves_icall_get_trace);
9054         mono_add_internal_call ("System.Security.SecurityFrame::_GetSecurityFrame",
9055                                 ves_icall_System_Security_SecurityFrame_GetSecurityFrame);
9056         mono_add_internal_call ("System.Security.SecurityFrame::_GetSecurityStack",
9057                                 ves_icall_System_Security_SecurityFrame_GetSecurityStack);
9058         mono_add_internal_call ("Mono.Runtime::mono_runtime_install_handlers", 
9059                                 mono_runtime_install_handlers);
9060
9061
9062         create_helper_signature ();
9063
9064 #define JIT_CALLS_WORK
9065 #ifdef JIT_CALLS_WORK
9066         /* Needs to be called here since register_jit_icall depends on it */
9067         mono_marshal_init ();
9068
9069         mono_arch_register_lowlevel_calls ();
9070         mono_register_jit_icall (mono_profiler_method_enter, "mono_profiler_method_enter", NULL, TRUE);
9071         mono_register_jit_icall (mono_profiler_method_leave, "mono_profiler_method_leave", NULL, TRUE);
9072         mono_register_jit_icall (mono_trace_enter_method, "mono_trace_enter_method", NULL, TRUE);
9073         mono_register_jit_icall (mono_trace_leave_method, "mono_trace_leave_method", NULL, TRUE);
9074         mono_register_jit_icall (mono_get_lmf_addr, "mono_get_lmf_addr", helper_sig_ptr_void, TRUE);
9075         mono_register_jit_icall (mono_domain_get, "mono_domain_get", helper_sig_domain_get, TRUE);
9076
9077         mono_register_jit_icall (mono_arch_get_throw_exception (), "mono_arch_throw_exception", helper_sig_void_obj, TRUE);
9078         mono_register_jit_icall (mono_arch_get_rethrow_exception (), "mono_arch_rethrow_exception", helper_sig_void_obj, TRUE);
9079         mono_register_jit_icall (mono_arch_get_throw_exception_by_name (), "mono_arch_throw_exception_by_name", 
9080                                  helper_sig_void_ptr, TRUE);
9081 #if MONO_ARCH_HAVE_THROW_CORLIB_EXCEPTION
9082         mono_register_jit_icall (mono_arch_get_throw_corlib_exception (), "mono_arch_throw_corlib_exception", 
9083                                  helper_sig_void_ptr, TRUE);
9084 #endif
9085         mono_register_jit_icall (mono_thread_get_pending_exception, "mono_thread_get_pending_exception", helper_sig_obj_void, FALSE);
9086         mono_register_jit_icall (mono_thread_interruption_checkpoint, "mono_thread_interruption_checkpoint", helper_sig_void_void, FALSE);
9087         mono_register_jit_icall (mono_thread_force_interruption_checkpoint, "mono_thread_force_interruption_checkpoint", helper_sig_void_void, FALSE);
9088         mono_register_jit_icall (mono_load_remote_field_new, "mono_load_remote_field_new", helper_sig_obj_obj_ptr_ptr, FALSE);
9089         mono_register_jit_icall (mono_store_remote_field_new, "mono_store_remote_field_new", helper_sig_void_obj_ptr_ptr_obj, FALSE);
9090
9091         /* 
9092          * NOTE, NOTE, NOTE, NOTE:
9093          * when adding emulation for some opcodes, remember to also add a dummy
9094          * rule to the burg files, because we need the arity information to be correct.
9095          */
9096         mono_register_opcode_emulation (OP_LMUL, "__emul_lmul", helper_sig_long_long_long, mono_llmult, TRUE);
9097         mono_register_opcode_emulation (OP_LMUL_OVF_UN, "__emul_lmul_ovf_un", helper_sig_long_long_long, mono_llmult_ovf_un, FALSE);
9098         mono_register_opcode_emulation (OP_LMUL_OVF, "__emul_lmul_ovf", helper_sig_long_long_long, mono_llmult_ovf, FALSE);
9099         mono_register_opcode_emulation (OP_LDIV, "__emul_ldiv", helper_sig_long_long_long, mono_lldiv, FALSE);
9100         mono_register_opcode_emulation (OP_LDIV_UN, "__emul_ldiv_un", helper_sig_long_long_long, mono_lldiv_un, FALSE);
9101         mono_register_opcode_emulation (OP_LREM, "__emul_lrem", helper_sig_long_long_long, mono_llrem, FALSE);
9102         mono_register_opcode_emulation (OP_LREM_UN, "__emul_lrem_un", helper_sig_long_long_long, mono_llrem_un, FALSE);
9103
9104 #ifndef MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
9105         mono_register_opcode_emulation (OP_LSHL, "__emul_lshl", helper_sig_long_long_int, mono_lshl, TRUE);
9106         mono_register_opcode_emulation (OP_LSHR, "__emul_lshr", helper_sig_long_long_int, mono_lshr, TRUE);
9107         mono_register_opcode_emulation (OP_LSHR_UN, "__emul_lshr_un", helper_sig_long_long_int, mono_lshr_un, TRUE);
9108 #endif
9109
9110         mono_register_opcode_emulation (OP_FCONV_TO_U8, "__emul_fconv_to_u8", helper_sig_ulong_double, mono_fconv_u8, FALSE);
9111         mono_register_opcode_emulation (OP_FCONV_TO_U4, "__emul_fconv_to_u4", helper_sig_uint_double, mono_fconv_u4, FALSE);
9112         mono_register_opcode_emulation (OP_FCONV_TO_OVF_I8, "__emul_fconv_to_ovf_i8", helper_sig_long_double, mono_fconv_ovf_i8, FALSE);
9113         mono_register_opcode_emulation (OP_FCONV_TO_OVF_U8, "__emul_fconv_to_ovf_u8", helper_sig_ulong_double, mono_fconv_ovf_u8, FALSE);
9114
9115 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
9116         mono_register_opcode_emulation (OP_FCONV_TO_I8, "__emul_fconv_to_i8", helper_sig_long_double, mono_fconv_i8, FALSE);
9117 #endif
9118 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
9119         mono_register_opcode_emulation (CEE_CONV_R_UN, "__emul_conv_r_un", helper_sig_double_int, mono_conv_to_r8_un, FALSE);
9120 #endif
9121 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
9122         mono_register_opcode_emulation (OP_LCONV_TO_R8, "__emul_lconv_to_r8", helper_sig_double_long, mono_lconv_to_r8, FALSE);
9123 #endif
9124 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
9125         mono_register_opcode_emulation (OP_LCONV_TO_R4, "__emul_lconv_to_r4", helper_sig_float_long, mono_lconv_to_r4, FALSE);
9126 #endif
9127 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
9128         mono_register_opcode_emulation (OP_LCONV_TO_R_UN, "__emul_lconv_to_r8_un", helper_sig_double_long, mono_lconv_to_r8_un, FALSE);
9129 #endif
9130 #ifdef MONO_ARCH_EMULATE_FREM
9131         mono_register_opcode_emulation (OP_FREM, "__emul_frem", helper_sig_double_double_double, fmod, FALSE);
9132 #endif
9133
9134 #if SIZEOF_VOID_P == 4
9135         mono_register_opcode_emulation (OP_FCONV_TO_U, "__emul_fconv_to_u", helper_sig_uint_double, mono_fconv_u4, TRUE);
9136 #else
9137 #ifdef __GNUC__
9138 #warning "fixme: add opcode emulation"
9139 #endif
9140 #endif
9141
9142         /* other jit icalls */
9143         mono_register_jit_icall (mono_class_static_field_address , "mono_class_static_field_address", 
9144                                  helper_sig_ptr_ptr_ptr, FALSE);
9145         mono_register_jit_icall (mono_ldtoken_wrapper, "mono_ldtoken_wrapper", helper_sig_ptr_ptr_ptr_ptr, FALSE);
9146         mono_register_jit_icall (mono_get_special_static_data, "mono_get_special_static_data", helper_sig_ptr_int, FALSE);
9147         mono_register_jit_icall (mono_ldstr, "mono_ldstr", helper_sig_ldstr, FALSE);
9148         mono_register_jit_icall (helper_memcpy, "helper_memcpy", helper_sig_memcpy, FALSE);
9149         mono_register_jit_icall (helper_memset, "helper_memset", helper_sig_memset, FALSE);
9150         mono_register_jit_icall (helper_initobj, "helper_initobj", helper_sig_initobj, FALSE);
9151         mono_register_jit_icall (helper_stelem_ref, "helper_stelem_ref", helper_sig_stelem_ref, FALSE);
9152         mono_register_jit_icall (helper_stelem_ref_check, "helper_stelem_ref_check", helper_sig_stelem_ref_check, FALSE);
9153         mono_register_jit_icall (mono_object_new, "mono_object_new", helper_sig_object_new, FALSE);
9154         mono_register_jit_icall (mono_object_new_specific, "mono_object_new_specific", helper_sig_object_new_specific, FALSE);
9155         mono_register_jit_icall (mono_array_new, "mono_array_new", helper_sig_newarr, FALSE);
9156         mono_register_jit_icall (mono_array_new_specific, "mono_array_new_specific", helper_sig_newarr_specific, FALSE);
9157         mono_register_jit_icall (mono_runtime_class_init, "mono_runtime_class_init", helper_sig_void_ptr, FALSE);
9158         mono_register_jit_icall (mono_ldftn, "mono_ldftn", helper_sig_compile, FALSE);
9159         mono_register_jit_icall (mono_ldftn_nosync, "mono_ldftn_nosync", helper_sig_compile, FALSE);
9160         mono_register_jit_icall (mono_ldvirtfn, "mono_ldvirtfn", helper_sig_compile_virt, FALSE);
9161         mono_register_jit_icall (helper_compile_generic_method, "compile_generic_method", helper_sig_compile_generic_method, FALSE);
9162 #endif
9163
9164 #define JIT_RUNTIME_WORKS
9165 #ifdef JIT_RUNTIME_WORKS
9166         mono_install_runtime_cleanup ((MonoDomainFunc)mini_cleanup);
9167         mono_runtime_init (domain, mono_thread_start_cb, mono_thread_attach_cb);
9168 #endif
9169
9170         mono_thread_attach (domain);
9171         return domain;
9172 }
9173
9174 MonoJitStats mono_jit_stats = {0};
9175
9176 static void 
9177 print_jit_stats (void)
9178 {
9179         if (mono_jit_stats.enabled) {
9180                 g_print ("Mono Jit statistics\n");
9181                 g_print ("Compiled methods:       %ld\n", mono_jit_stats.methods_compiled);
9182                 g_print ("Methods from AOT:       %ld\n", mono_jit_stats.methods_aot);
9183                 g_print ("Methods cache lookup:   %ld\n", mono_jit_stats.methods_lookups);
9184                 g_print ("Method trampolines:     %ld\n", mono_jit_stats.method_trampolines);
9185                 g_print ("Basic blocks:           %ld\n", mono_jit_stats.basic_blocks);
9186                 g_print ("Max basic blocks:       %ld\n", mono_jit_stats.max_basic_blocks);
9187                 g_print ("Allocated vars:         %ld\n", mono_jit_stats.allocate_var);
9188                 g_print ("Analyze stack repeat:   %ld\n", mono_jit_stats.analyze_stack_repeat);
9189                 g_print ("Compiled CIL code size: %ld\n", mono_jit_stats.cil_code_size);
9190                 g_print ("Native code size:       %ld\n", mono_jit_stats.native_code_size);
9191                 g_print ("Max code size ratio:    %.2f (%s::%s)\n", mono_jit_stats.max_code_size_ratio/100.0,
9192                                 mono_jit_stats.max_ratio_method->klass->name, mono_jit_stats.max_ratio_method->name);
9193                 g_print ("Biggest method:         %ld (%s::%s)\n", mono_jit_stats.biggest_method_size,
9194                                 mono_jit_stats.biggest_method->klass->name, mono_jit_stats.biggest_method->name);
9195                 g_print ("Code reallocs:          %ld\n", mono_jit_stats.code_reallocs);
9196                 g_print ("Allocated code size:    %ld\n", mono_jit_stats.allocated_code_size);
9197                 g_print ("Inlineable methods:     %ld\n", mono_jit_stats.inlineable_methods);
9198                 g_print ("Inlined methods:        %ld\n", mono_jit_stats.inlined_methods);
9199                 
9200                 g_print ("\nCreated object count:   %ld\n", mono_stats.new_object_count);
9201                 g_print ("Initialized classes:    %ld\n", mono_stats.initialized_class_count);
9202                 g_print ("Used classes:           %ld\n", mono_stats.used_class_count);
9203                 g_print ("Static data size:       %ld\n", mono_stats.class_static_data_size);
9204                 g_print ("VTable data size:       %ld\n", mono_stats.class_vtable_size);
9205
9206                 g_print ("\nGeneric instances:      %ld\n", mono_stats.generic_instance_count);
9207                 g_print ("Initialized classes:    %ld\n", mono_stats.generic_class_count);
9208                 g_print ("Inflated methods:       %ld / %ld\n", mono_stats.inflated_method_count_2,
9209                          mono_stats.inflated_method_count);
9210                 g_print ("Inflated types:         %ld\n", mono_stats.inflated_type_count);
9211                 g_print ("Generics metadata size: %ld\n", mono_stats.generics_metadata_size);
9212         }
9213 }
9214
9215 void
9216 mini_cleanup (MonoDomain *domain)
9217 {
9218         /* 
9219          * mono_runtime_cleanup() and mono_domain_finalize () need to
9220          * be called early since they need the execution engine still
9221          * fully working (mono_domain_finalize may invoke managed finalizers
9222          * and mono_runtime_cleanup will wait for other threads to finish).
9223          */
9224         mono_domain_finalize (domain, 2000);
9225
9226         mono_runtime_cleanup (domain);
9227
9228         mono_profiler_shutdown ();
9229
9230         mono_debug_cleanup ();
9231
9232 #ifdef PLATFORM_WIN32
9233         win32_seh_cleanup();
9234 #endif
9235
9236         mono_domain_free (domain, TRUE);
9237
9238         print_jit_stats ();
9239 }
9240
9241 void
9242 mono_set_defaults (int verbose_level, guint32 opts)
9243 {
9244         mini_verbose = verbose_level;
9245         default_opt = opts;
9246 }
9247
9248 static void
9249 mono_precompile_assembly (MonoAssembly *ass, void *user_data)
9250 {
9251         MonoImage *image = mono_assembly_get_image (ass);
9252         MonoMethod *method, *invoke;
9253         int i, count = 0;
9254
9255         if (mini_verbose > 0)
9256                 printf ("PRECOMPILE: %s.\n", mono_image_get_filename (image));
9257
9258         for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_METHOD); ++i) {
9259                 method = mono_get_method (image, MONO_TOKEN_METHOD_DEF | (i + 1), NULL);
9260                 if (method->flags & METHOD_ATTRIBUTE_ABSTRACT)
9261                         continue;
9262
9263                 count++;
9264                 if (mini_verbose > 1) {
9265                         char * desc = mono_method_full_name (method, TRUE);
9266                         g_print ("Compiling %d %s\n", count, desc);
9267                         g_free (desc);
9268                 }
9269                 mono_compile_method (method);
9270                 if (strcmp (method->name, "Finalize") == 0) {
9271                         invoke = mono_marshal_get_runtime_invoke (method);
9272                         mono_compile_method (invoke);
9273                 }
9274                 if (method->klass->marshalbyref && method->signature->hasthis) {
9275                         invoke = mono_marshal_get_remoting_invoke_with_check (method);
9276                         mono_compile_method (invoke);
9277                 }
9278         }
9279 }
9280
9281 void mono_precompile_assemblies ()
9282 {
9283         mono_assembly_foreach ((GFunc)mono_precompile_assembly, NULL);
9284 }