2007-08-20 Mark Probst <mark.probst@gmail.com>
[mono.git] / mono / mini / mini.c
1 /*
2  * mini.c: The new Mono code generator.
3  *
4  * Author:
5  *   Paolo Molaro (lupus@ximian.com)
6  *   Dietmar Maurer (dietmar@ximian.com)
7  *
8  * (C) 2002 Ximian, Inc.
9  */
10
11 #include <config.h>
12 #include <signal.h>
13 #ifdef HAVE_UNISTD_H
14 #include <unistd.h>
15 #endif
16 #include <math.h>
17 #ifdef HAVE_SYS_TIME_H
18 #include <sys/time.h>
19 #endif
20
21 #ifdef PLATFORM_MACOSX
22 #include <mach/mach.h>
23 #include <mach/mach_error.h>
24 #include <mach/exception.h>
25 #include <mach/task.h>
26 #include <pthread.h>
27 #endif
28
29 #ifdef PLATFORM_WIN32
30 #define _WIN32_WINNT 0x0500
31 #endif
32
33 #ifdef HAVE_VALGRIND_MEMCHECK_H
34 #include <valgrind/memcheck.h>
35 #endif
36
37 #include <mono/metadata/assembly.h>
38 #include <mono/metadata/loader.h>
39 #include <mono/metadata/cil-coff.h>
40 #include <mono/metadata/tabledefs.h>
41 #include <mono/metadata/class.h>
42 #include <mono/metadata/object.h>
43 #include <mono/metadata/exception.h>
44 #include <mono/metadata/opcodes.h>
45 #include <mono/metadata/mono-endian.h>
46 #include <mono/metadata/tokentype.h>
47 #include <mono/metadata/tabledefs.h>
48 #include <mono/metadata/threads.h>
49 #include <mono/metadata/marshal.h>
50 #include <mono/metadata/socket-io.h>
51 #include <mono/metadata/appdomain.h>
52 #include <mono/metadata/debug-helpers.h>
53 #include <mono/io-layer/io-layer.h>
54 #include "mono/metadata/profiler.h"
55 #include <mono/metadata/profiler-private.h>
56 #include <mono/metadata/mono-config.h>
57 #include <mono/metadata/environment.h>
58 #include <mono/metadata/mono-debug.h>
59 #include <mono/metadata/monitor.h>
60 #include <mono/metadata/security-manager.h>
61 #include <mono/metadata/threads-types.h>
62 #include <mono/metadata/rawbuffer.h>
63 #include <mono/metadata/security-core-clr.h>
64 #include <mono/utils/mono-math.h>
65 #include <mono/utils/mono-compiler.h>
66 #include <mono/utils/mono-counters.h>
67 #include <mono/utils/mono-logger.h>
68 #include <mono/utils/mono-mmap.h>
69 #include <mono/os/gc_wrapper.h>
70
71 #include "mini.h"
72 #include <string.h>
73 #include <ctype.h>
74 #include "inssel.h"
75 #include "trace.h"
76
77 #include "jit-icalls.h"
78
79 #include "aliasing.h"
80
81 #define BRANCH_COST 100
82 #define INLINE_LENGTH_LIMIT 20
83 #define INLINE_FAILURE do {\
84                 if ((cfg->method != method) && (method->wrapper_type == MONO_WRAPPER_NONE))\
85                         goto inline_failure;\
86         } while (0)
87 #define CHECK_CFG_EXCEPTION do {\
88                 if (cfg->exception_type != MONO_EXCEPTION_NONE)\
89                         goto exception_exit;\
90         } while (0)
91
92 /* 
93  * this is used to determine when some branch optimizations are possible: we exclude FP compares
94  * because they have weird semantics with NaNs.
95  */
96 #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))
97 #define MONO_IS_COND_BRANCH_NOFP(ins) (MONO_IS_COND_BRANCH_OP(ins) && (ins)->inst_left->inst_left->type != STACK_R8)
98
99 #define MONO_IS_BRANCH_OP(ins) (MONO_IS_COND_BRANCH_OP(ins) || ((ins)->opcode == OP_BR) || ((ins)->opcode == OP_BR_REG) || ((ins)->opcode == CEE_SWITCH))
100
101 #define MONO_CHECK_THIS(ins) (mono_method_signature (cfg->method)->hasthis && (ins)->ssa_op == MONO_SSA_LOAD && (ins)->inst_left->inst_c0 == 0)
102
103 static void setup_stat_profiler (void);
104 gboolean  mono_arch_print_tree(MonoInst *tree, int arity);
105 static gpointer mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt);
106 static gpointer mono_jit_compile_method (MonoMethod *method);
107 static gpointer mono_jit_find_compiled_method (MonoDomain *domain, MonoMethod *method);
108 static gpointer mono_create_jit_trampoline_in_domain (MonoDomain *domain, MonoMethod *method);
109 inline static int mono_emit_jit_icall (MonoCompile *cfg, MonoBasicBlock *bblock, gconstpointer func, MonoInst **args, const guint8 *ip);
110
111 static void handle_stobj (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *dest, MonoInst *src, 
112                           const unsigned char *ip, MonoClass *klass, gboolean to_end, gboolean native, gboolean write_barrier);
113
114 static void dec_foreach (MonoInst *tree, MonoCompile *cfg);
115
116 static int mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock, 
117                    int locals_offset, MonoInst *return_var, GList *dont_inline, MonoInst **inline_args, 
118                    guint inline_offset, gboolean is_virtual_call);
119
120 /* helper methods signature */
121 static MonoMethodSignature *helper_sig_class_init_trampoline = NULL;
122 static MonoMethodSignature *helper_sig_domain_get = NULL;
123
124 static guint32 default_opt = 0;
125 static gboolean default_opt_set = FALSE;
126
127 guint32 mono_jit_tls_id = -1;
128 MonoTraceSpec *mono_jit_trace_calls = NULL;
129 gboolean mono_break_on_exc = FALSE;
130 #ifndef DISABLE_AOT
131 gboolean mono_compile_aot = FALSE;
132 #endif
133
134 static int mini_verbose = 0;
135
136 #define mono_jit_lock() EnterCriticalSection (&jit_mutex)
137 #define mono_jit_unlock() LeaveCriticalSection (&jit_mutex)
138 static CRITICAL_SECTION jit_mutex;
139
140 static GHashTable *class_init_hash_addr = NULL;
141
142 static MonoCodeManager *global_codeman = NULL;
143
144 static GHashTable *jit_icall_name_hash = NULL;
145
146 static MonoDebugOptions debug_options;
147
148 #ifdef VALGRIND_JIT_REGISTER_MAP
149 static int valgrind_register = 0;
150 #endif
151
152 /*
153  * Address of the trampoline code.  This is used by the debugger to check
154  * whether a method is a trampoline.
155  */
156 guint8* mono_trampoline_code [MONO_TRAMPOLINE_NUM];
157
158 gboolean
159 mono_running_on_valgrind (void)
160 {
161 #ifdef HAVE_VALGRIND_MEMCHECK_H
162                 if (RUNNING_ON_VALGRIND){
163 #ifdef VALGRIND_JIT_REGISTER_MAP
164                         valgrind_register = TRUE;
165 #endif
166                         return TRUE;
167                 } else
168                         return FALSE;
169 #else
170                 return FALSE;
171 #endif
172 }
173
174 /*
175  * mono_create_ftnptr:
176  *
177  *   Given a function address, create a function descriptor for it.
178  * This is only needed on IA64.
179  */
180 gpointer
181 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
182 {
183 #ifdef __ia64__
184         gpointer *desc;
185
186         mono_domain_lock (domain);
187         desc = mono_code_manager_reserve (domain->code_mp, 2 * sizeof (gpointer));
188         mono_domain_unlock (domain);
189
190         desc [0] = addr;
191         desc [1] = NULL;
192
193         return desc;
194 #else
195         return addr;
196 #endif
197 }
198
199 typedef struct {
200         void *ip;
201         MonoMethod *method;
202 } FindTrampUserData;
203
204 static void
205 find_tramp (gpointer key, gpointer value, gpointer user_data)
206 {
207         FindTrampUserData *ud = (FindTrampUserData*)user_data;
208
209         if (value == ud->ip)
210                 ud->method = (MonoMethod*)key;
211 }
212
213 /* debug function */
214 G_GNUC_UNUSED static char*
215 get_method_from_ip (void *ip)
216 {
217         MonoJitInfo *ji;
218         char *method;
219         char *res;
220         MonoDomain *domain = mono_domain_get ();
221         MonoDebugSourceLocation *location;
222         FindTrampUserData user_data;
223         
224         ji = mono_jit_info_table_find (domain, ip);
225         if (!ji) {
226                 user_data.ip = ip;
227                 user_data.method = NULL;
228                 mono_domain_lock (domain);
229                 g_hash_table_foreach (domain->jit_trampoline_hash, find_tramp, &user_data);
230                 mono_domain_unlock (domain);
231                 if (user_data.method) {
232                         char *mname = mono_method_full_name (user_data.method, TRUE);
233                         res = g_strdup_printf ("<%p - JIT trampoline for %s>", ip, mname);
234                         g_free (mname);
235                         return res;
236                 }
237                 else
238                         return NULL;
239         }
240         method = mono_method_full_name (ji->method, TRUE);
241         /* FIXME: unused ? */
242         location = mono_debug_lookup_source_location (ji->method, (guint32)((guint8*)ip - (guint8*)ji->code_start), domain);
243
244         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);
245
246         mono_debug_free_source_location (location);
247         g_free (method);
248
249         return res;
250 }
251
252 /** 
253  * mono_pmip:
254  * @ip: an instruction pointer address
255  *
256  * This method is used from a debugger to get the name of the
257  * method at address @ip.   This routine is typically invoked from
258  * a debugger like this:
259  *
260  * (gdb) print mono_pmip ($pc)
261  *
262  * Returns: the name of the method at address @ip.
263  */
264 G_GNUC_UNUSED char *
265 mono_pmip (void *ip)
266 {
267         return get_method_from_ip (ip);
268 }
269
270 /** 
271  * mono_print_method_from_ip
272  * @ip: an instruction pointer address
273  *
274  * This method is used from a debugger to get the name of the
275  * method at address @ip.
276  *
277  * This prints the name of the method at address @ip in the standard
278  * output.  Unlike mono_pmip which returns a string, this routine
279  * prints the value on the standard output. 
280  */
281 void
282 mono_print_method_from_ip (void *ip)
283 {
284         MonoJitInfo *ji;
285         char *method;
286         MonoDebugSourceLocation *source;
287         MonoDomain *domain = mono_domain_get ();
288         FindTrampUserData user_data;
289         
290         ji = mono_jit_info_table_find (domain, ip);
291         if (!ji) {
292                 user_data.ip = ip;
293                 user_data.method = NULL;
294                 mono_domain_lock (domain);
295                 g_hash_table_foreach (domain->jit_trampoline_hash, find_tramp, &user_data);
296                 mono_domain_unlock (domain);
297                 if (user_data.method) {
298                         char *mname = mono_method_full_name (user_data.method, TRUE);
299                         printf ("IP %p is a JIT trampoline for %s\n", ip, mname);
300                         g_free (mname);
301                 }
302                 else
303                         g_print ("No method at %p\n", ip);
304                 return;
305         }
306         method = mono_method_full_name (ji->method, TRUE);
307         source = mono_debug_lookup_source_location (ji->method, (guint32)((guint8*)ip - (guint8*)ji->code_start), domain);
308
309         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);
310
311         if (source)
312                 g_print ("%s:%d\n", source->source_file, source->row);
313
314         mono_debug_free_source_location (source);
315         g_free (method);
316 }
317         
318 /* 
319  * mono_method_same_domain:
320  *
321  * Determine whenever two compiled methods are in the same domain, thus
322  * the address of the callee can be embedded in the caller.
323  */
324 gboolean mono_method_same_domain (MonoJitInfo *caller, MonoJitInfo *callee)
325 {
326         if (!caller || !callee)
327                 return FALSE;
328
329         /*
330          * If the call was made from domain-neutral to domain-specific 
331          * code, we can't patch the call site.
332          */
333         if (caller->domain_neutral && !callee->domain_neutral)
334                 return FALSE;
335
336         if ((caller->method->klass == mono_defaults.appdomain_class) &&
337                 (strstr (caller->method->name, "InvokeInDomain"))) {
338                  /* The InvokeInDomain methods change the current appdomain */
339                 return FALSE;
340         }
341
342         return TRUE;
343 }
344
345 /*
346  * mono_global_codeman_reserve:
347  *
348  *  Allocate code memory from the global code manager.
349  */
350 void *mono_global_codeman_reserve (int size)
351 {
352         void *ptr;
353
354         if (!global_codeman) {
355                 /* This can happen during startup */
356                 global_codeman = mono_code_manager_new ();
357                 return mono_code_manager_reserve (global_codeman, size);
358         }
359         else {
360                 mono_jit_lock ();
361                 ptr = mono_code_manager_reserve (global_codeman, size);
362                 mono_jit_unlock ();
363                 return ptr;
364         }
365 }
366
367 MonoJumpInfoToken *
368 mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
369 {
370         MonoJumpInfoToken *res = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoToken));
371         res->image = image;
372         res->token = token;
373
374         return res;
375 }
376
377 #define MONO_INIT_VARINFO(vi,id) do { \
378         (vi)->range.first_use.pos.bid = 0xffff; \
379         (vi)->reg = -1; \
380         (vi)->idx = (id); \
381 } while (0)
382
383 //#define UNVERIFIED do { G_BREAKPOINT (); goto unverified; } while (0)
384 #define UNVERIFIED do { if (debug_options.break_on_unverified) G_BREAKPOINT (); else goto unverified; } while (0)
385
386 /*
387  * Basic blocks have two numeric identifiers:
388  * dfn: Depth First Number
389  * block_num: unique ID assigned at bblock creation
390  */
391 #define NEW_BBLOCK(cfg) (mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock)))
392 #define ADD_BBLOCK(cfg,b) do {  \
393                 cfg->cil_offset_to_bb [(b)->cil_code - cfg->cil_start] = (b);   \
394                 (b)->block_num = cfg->num_bblocks++;    \
395                 (b)->real_offset = real_offset; \
396         } while (0)
397
398 #define GET_BBLOCK(cfg,tblock,ip) do {  \
399                 (tblock) = cfg->cil_offset_to_bb [(ip) - cfg->cil_start]; \
400                 if (!(tblock)) {        \
401                         if ((ip) >= end || (ip) < header->code) UNVERIFIED; \
402                         (tblock) = NEW_BBLOCK (cfg);    \
403                         (tblock)->cil_code = (ip);      \
404                         ADD_BBLOCK (cfg, (tblock));     \
405                 } \
406         } while (0)
407
408 #define CHECK_BBLOCK(target,ip,tblock) do {     \
409                 if ((target) < (ip) && !(tblock)->code) {       \
410                         bb_recheck = g_list_prepend (bb_recheck, (tblock));     \
411                         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));     \
412                 }       \
413         } while (0)
414
415 #define NEW_ICONST(cfg,dest,val) do {   \
416                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
417                 (dest)->opcode = OP_ICONST;     \
418                 (dest)->inst_c0 = (val);        \
419                 (dest)->type = STACK_I4;        \
420         } while (0)
421
422 #define NEW_PCONST(cfg,dest,val) do {   \
423                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
424                 (dest)->opcode = OP_PCONST;     \
425                 (dest)->inst_p0 = (val);        \
426                 (dest)->type = STACK_PTR;       \
427         } while (0)
428
429
430 #ifdef MONO_ARCH_NEED_GOT_VAR
431
432 #define NEW_PATCH_INFO(cfg,dest,el1,el2) do {   \
433                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
434                 (dest)->opcode = OP_PATCH_INFO; \
435                 (dest)->inst_left = (gpointer)(el1);    \
436                 (dest)->inst_right = (gpointer)(el2);   \
437         } while (0)
438
439 #define NEW_AOTCONST(cfg,dest,patch_type,cons) do {                     \
440                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
441                 (dest)->opcode = cfg->compile_aot ? OP_GOT_ENTRY : OP_PCONST; \
442                 if (cfg->compile_aot) {                                 \
443                         MonoInst *group, *got_var, *got_loc;            \
444                         got_loc = mono_get_got_var (cfg);               \
445                         NEW_TEMPLOAD ((cfg), got_var, got_loc->inst_c0); \
446                         NEW_PATCH_INFO ((cfg), group, cons, patch_type); \
447                         (dest)->inst_p0 = got_var;                      \
448                         (dest)->inst_p1 = group;                        \
449                 } else {                                                \
450                         (dest)->inst_p0 = (cons);                       \
451                         (dest)->inst_i1 = (gpointer)(patch_type);       \
452                 }                                                       \
453                 (dest)->type = STACK_PTR;                               \
454         } while (0)
455
456 #define NEW_AOTCONST_TOKEN(cfg,dest,patch_type,image,token,stack_type,stack_class) do { \
457                 MonoInst *group, *got_var, *got_loc;                    \
458                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
459                 (dest)->opcode = OP_GOT_ENTRY;                          \
460                 got_loc = mono_get_got_var (cfg);                       \
461                 NEW_TEMPLOAD ((cfg), got_var, got_loc->inst_c0);        \
462                 NEW_PATCH_INFO ((cfg), group, NULL, patch_type);        \
463                 group->inst_p0 = mono_jump_info_token_new ((cfg)->mempool, (image), (token)); \
464                 (dest)->inst_p0 = got_var;                              \
465                 (dest)->inst_p1 = group;                                \
466                 (dest)->type = (stack_type);                    \
467         (dest)->klass = (stack_class);          \
468         } while (0)
469
470 #else
471
472 #define NEW_AOTCONST(cfg,dest,patch_type,cons) do {    \
473                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
474                 (dest)->opcode = cfg->compile_aot ? OP_AOTCONST : OP_PCONST;    \
475                 (dest)->inst_p0 = (cons);       \
476                 (dest)->inst_i1 = (gpointer)(patch_type); \
477                 (dest)->type = STACK_PTR;       \
478     } while (0)
479
480 #define NEW_AOTCONST_TOKEN(cfg,dest,patch_type,image,token,stack_type,stack_class) do { \
481                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
482                 (dest)->opcode = OP_AOTCONST;   \
483                 (dest)->inst_p0 = mono_jump_info_token_new ((cfg)->mempool, (image), (token));  \
484                 (dest)->inst_p1 = (gpointer)(patch_type); \
485                 (dest)->type = (stack_type);    \
486         (dest)->klass = (stack_class);          \
487     } while (0)
488
489 #endif
490
491 #define NEW_CLASSCONST(cfg,dest,val) NEW_AOTCONST ((cfg), (dest), MONO_PATCH_INFO_CLASS, (val))
492
493 #define NEW_IMAGECONST(cfg,dest,val) NEW_AOTCONST ((cfg), (dest), MONO_PATCH_INFO_IMAGE, (val))
494
495 #define NEW_FIELDCONST(cfg,dest,val) NEW_AOTCONST ((cfg), (dest), MONO_PATCH_INFO_FIELD, (val))
496
497 #define NEW_METHODCONST(cfg,dest,val) NEW_AOTCONST ((cfg), (dest), MONO_PATCH_INFO_METHODCONST, (val))
498
499 #define NEW_VTABLECONST(cfg,dest,vtable) NEW_AOTCONST ((cfg), (dest), MONO_PATCH_INFO_VTABLE, cfg->compile_aot ? (gpointer)((vtable)->klass) : (vtable))
500
501 #define NEW_SFLDACONST(cfg,dest,val) NEW_AOTCONST ((cfg), (dest), MONO_PATCH_INFO_SFLDA, (val))
502
503 #define NEW_LDSTRCONST(cfg,dest,image,token) NEW_AOTCONST_TOKEN ((cfg), (dest), MONO_PATCH_INFO_LDSTR, (image), (token), STACK_OBJ, mono_defaults.string_class)
504
505 #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, mono_defaults.monotype_class)
506
507 #define NEW_LDTOKENCONST(cfg,dest,image,token) NEW_AOTCONST_TOKEN ((cfg), (dest), MONO_PATCH_INFO_LDTOKEN, (image), (token), STACK_PTR, NULL)
508
509 #define NEW_DECLSECCONST(cfg,dest,image,entry) do { \
510                 if (cfg->compile_aot) { \
511                         NEW_AOTCONST_TOKEN (cfg, dest, MONO_PATCH_INFO_DECLSEC, image, (entry).index, STACK_OBJ, NULL); \
512                 } else { \
513                         NEW_PCONST (cfg, args [0], (entry).blob); \
514                 } \
515         } while (0)
516
517 #define NEW_DOMAINCONST(cfg,dest) do { \
518                 if (cfg->opt & MONO_OPT_SHARED) { \
519                         /* avoid depending on undefined C behavior in sequence points */ \
520                         MonoInst* __domain_var = mono_get_domainvar (cfg); \
521                         NEW_TEMPLOAD (cfg, dest, __domain_var->inst_c0); \
522                 } else { \
523                         NEW_PCONST (cfg, dest, (cfg)->domain); \
524                 } \
525         } while (0)
526
527 #define GET_VARINFO_INST(cfg,num) ((cfg)->varinfo [(num)]->inst)
528
529 #define NEW_ARGLOAD(cfg,dest,num) do {  \
530                 if (arg_array [(num)]->opcode == OP_ICONST) (dest) = arg_array [(num)]; else { \
531                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
532                 (dest)->ssa_op = MONO_SSA_LOAD; \
533                 (dest)->inst_i0 = arg_array [(num)];    \
534                 (dest)->opcode = mono_type_to_ldind ((dest)->inst_i0->inst_vtype);      \
535                 type_to_eval_stack_type (param_types [(num)], (dest));  \
536                 (dest)->klass = (dest)->inst_i0->klass; \
537         }} while (0)
538
539 #define NEW_LOCLOAD(cfg,dest,num) do {  \
540                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
541                 (dest)->ssa_op = MONO_SSA_LOAD; \
542                 (dest)->inst_i0 = (cfg)->varinfo [locals_offset + (num)];       \
543                 (dest)->opcode = mono_type_to_ldind ((dest)->inst_i0->inst_vtype);      \
544                 type_to_eval_stack_type (header->locals [(num)], (dest));       \
545                 (dest)->klass = (dest)->inst_i0->klass; \
546         } while (0)
547
548 #define NEW_LOCLOADA(cfg,dest,num) do { \
549                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
550                 (dest)->ssa_op = MONO_SSA_ADDRESS_TAKEN;        \
551                 (dest)->inst_i0 = (cfg)->varinfo [locals_offset + (num)];       \
552                 (dest)->inst_i0->flags |= MONO_INST_INDIRECT;   \
553                 (dest)->opcode = OP_LDADDR;     \
554                 (dest)->type = STACK_MP;        \
555                 (dest)->klass = (dest)->inst_i0->klass; \
556         if (!MONO_TYPE_ISSTRUCT (header->locals [(num)])) \
557            (cfg)->disable_ssa = TRUE; \
558         } while (0)
559
560 #define NEW_RETLOADA(cfg,dest) do {     \
561                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
562                 (dest)->ssa_op = MONO_SSA_ADDRESS_TAKEN;        \
563                 (dest)->inst_i0 = (cfg)->ret;   \
564                 (dest)->inst_i0->flags |= MONO_INST_INDIRECT;   \
565                 (dest)->opcode = cfg->ret_var_is_local ? OP_LDADDR : CEE_LDIND_I;       \
566                 (dest)->type = STACK_MP;        \
567                 (dest)->klass = (dest)->inst_i0->klass; \
568                 (cfg)->disable_ssa = TRUE; \
569         } while (0)
570
571 #define NEW_ARGLOADA(cfg,dest,num) do { \
572                 if (arg_array [(num)]->opcode == OP_ICONST) goto inline_failure; \
573                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
574                 (dest)->ssa_op = MONO_SSA_ADDRESS_TAKEN;        \
575                 (dest)->inst_i0 = arg_array [(num)];    \
576                 (dest)->inst_i0->flags |= MONO_INST_INDIRECT;   \
577                 (dest)->opcode = OP_LDADDR;     \
578                 (dest)->type = STACK_MP;        \
579                 (dest)->klass = (dest)->inst_i0->klass; \
580                 (cfg)->disable_ssa = TRUE; \
581         } while (0)
582
583 #define NEW_TEMPLOAD(cfg,dest,num) do { \
584                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
585                 (dest)->ssa_op = MONO_SSA_LOAD; \
586                 (dest)->inst_i0 = (cfg)->varinfo [(num)];       \
587                 (dest)->opcode = mono_type_to_ldind ((dest)->inst_i0->inst_vtype);      \
588                 type_to_eval_stack_type ((dest)->inst_i0->inst_vtype, (dest));  \
589                 (dest)->klass = (dest)->inst_i0->klass; \
590         } while (0)
591
592 #define NEW_TEMPLOADA(cfg,dest,num) do {        \
593                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
594                 (dest)->ssa_op = MONO_SSA_ADDRESS_TAKEN;        \
595                 (dest)->inst_i0 = (cfg)->varinfo [(num)];       \
596                 (dest)->inst_i0->flags |= MONO_INST_INDIRECT;   \
597                 (dest)->opcode = OP_LDADDR;     \
598                 (dest)->type = STACK_MP;        \
599                 (dest)->klass = (dest)->inst_i0->klass; \
600         if (!MONO_TYPE_ISSTRUCT (cfg->varinfo [(num)]->inst_vtype)) \
601            (cfg)->disable_ssa = TRUE; \
602         } while (0)
603
604
605 #define NEW_INDLOAD(cfg,dest,addr,vtype) do {   \
606                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
607                 (dest)->inst_left = addr;       \
608                 (dest)->opcode = mono_type_to_ldind (vtype);    \
609                 type_to_eval_stack_type (vtype, (dest));        \
610                 /* FIXME: (dest)->klass = (dest)->inst_i0->klass;*/     \
611         } while (0)
612
613 #define NEW_INDSTORE(cfg,dest,addr,value,vtype) do {    \
614                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
615                 (dest)->inst_i0 = addr; \
616                 (dest)->opcode = mono_type_to_stind (vtype);    \
617                 (dest)->inst_i1 = (value);      \
618                 /* FIXME: (dest)->klass = (dest)->inst_i0->klass;*/     \
619         } while (0)
620
621 #define NEW_TEMPSTORE(cfg,dest,num,inst) do {   \
622                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
623                 (dest)->ssa_op = MONO_SSA_STORE;        \
624                 (dest)->inst_i0 = (cfg)->varinfo [(num)];       \
625                 (dest)->opcode = mono_type_to_stind ((dest)->inst_i0->inst_vtype);      \
626                 (dest)->inst_i1 = (inst);       \
627                 (dest)->klass = (dest)->inst_i0->klass; \
628         } while (0)
629
630 #define NEW_LOCSTORE(cfg,dest,num,inst) do {    \
631                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
632                 (dest)->opcode = mono_type_to_stind (header->locals [(num)]);   \
633                 (dest)->ssa_op = MONO_SSA_STORE;        \
634                 (dest)->inst_i0 = (cfg)->varinfo [locals_offset + (num)];       \
635                 (dest)->inst_i1 = (inst);       \
636                 (dest)->klass = (dest)->inst_i0->klass; \
637         } while (0)
638
639 #define NEW_ARGSTORE(cfg,dest,num,inst) do {    \
640                 if (arg_array [(num)]->opcode == OP_ICONST) goto inline_failure; \
641                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
642                 (dest)->opcode = mono_type_to_stind (param_types [(num)]);      \
643                 (dest)->ssa_op = MONO_SSA_STORE;        \
644                 (dest)->inst_i0 = arg_array [(num)];    \
645                 (dest)->inst_i1 = (inst);       \
646                 (dest)->klass = (dest)->inst_i0->klass; \
647         } while (0)
648
649 #define NEW_DUMMY_USE(cfg,dest,load) do { \
650                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
651                 (dest)->opcode = OP_DUMMY_USE; \
652                 (dest)->inst_left = (load); \
653     } while (0)
654
655 #define NEW_DUMMY_STORE(cfg,dest,num) do { \
656                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
657                 (dest)->inst_i0 = (cfg)->varinfo [(num)];       \
658                 (dest)->opcode = OP_DUMMY_STORE; \
659                 (dest)->klass = (dest)->inst_i0->klass; \
660         } while (0)
661
662 #define ADD_BINOP(op) do {      \
663                 MONO_INST_NEW (cfg, ins, (op)); \
664                 ins->cil_code = ip;     \
665                 sp -= 2;        \
666                 ins->inst_i0 = sp [0];  \
667                 ins->inst_i1 = sp [1];  \
668                 *sp++ = ins;    \
669                 type_from_op (ins);     \
670                 CHECK_TYPE (ins);       \
671         } while (0)
672
673 #define ADD_UNOP(op) do {       \
674                 MONO_INST_NEW (cfg, ins, (op)); \
675                 ins->cil_code = ip;     \
676                 sp--;   \
677                 ins->inst_i0 = sp [0];  \
678                 *sp++ = ins;    \
679                 type_from_op (ins);     \
680                 CHECK_TYPE (ins);       \
681         } while (0)
682
683 #define ADD_BINCOND(next_block) do {    \
684                 MonoInst *cmp;  \
685                 sp -= 2;                \
686                 MONO_INST_NEW(cfg, cmp, OP_COMPARE);    \
687                 cmp->inst_i0 = sp [0];  \
688                 cmp->inst_i1 = sp [1];  \
689                 cmp->cil_code = ins->cil_code;  \
690                 type_from_op (cmp);     \
691                 CHECK_TYPE (cmp);       \
692                 ins->inst_i0 = cmp;     \
693                 MONO_ADD_INS (bblock, ins);     \
694                 ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);      \
695                 GET_BBLOCK (cfg, tblock, target);               \
696                 link_bblock (cfg, bblock, tblock);      \
697                 ins->inst_true_bb = tblock;     \
698                 CHECK_BBLOCK (target, ip, tblock);      \
699                 if ((next_block)) {     \
700                         link_bblock (cfg, bblock, (next_block));        \
701                         ins->inst_false_bb = (next_block);      \
702                         start_new_bblock = 1;   \
703                 } else {        \
704                         GET_BBLOCK (cfg, tblock, ip);           \
705                         link_bblock (cfg, bblock, tblock);      \
706                         ins->inst_false_bb = tblock;    \
707                         start_new_bblock = 2;   \
708                 }       \
709         } while (0)
710
711 /* FIXME: handle float, long ... */
712 #define ADD_UNCOND(istrue) do { \
713                 MonoInst *cmp;  \
714                 sp--;           \
715                 MONO_INST_NEW(cfg, cmp, OP_COMPARE);    \
716                 cmp->inst_i0 = sp [0];  \
717                 switch (cmp->inst_i0->type) { \
718                 case STACK_I8: \
719                         cmp->inst_i1 = zero_int64; break; \
720                 case STACK_R8: \
721                         cmp->inst_i1 = zero_r8; break; \
722                 case STACK_PTR: \
723                 case STACK_MP: \
724                         cmp->inst_i1 = zero_ptr; break; \
725                 case STACK_OBJ: \
726                         cmp->inst_i1 = zero_obj; break; \
727                 default: \
728                         cmp->inst_i1 = zero_int32;  \
729                 }  \
730                 cmp->cil_code = ins->cil_code;  \
731                 type_from_op (cmp);     \
732                 CHECK_TYPE (cmp);       \
733                 ins->inst_i0 = cmp;     \
734                 ins->opcode = (istrue)? CEE_BNE_UN: CEE_BEQ;    \
735                 MONO_ADD_INS (bblock, ins);     \
736                 ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);      \
737                 GET_BBLOCK (cfg, tblock, target);               \
738                 link_bblock (cfg, bblock, tblock);      \
739                 ins->inst_true_bb = tblock;     \
740                 CHECK_BBLOCK (target, ip, tblock);      \
741                 GET_BBLOCK (cfg, tblock, ip);           \
742                 link_bblock (cfg, bblock, tblock);      \
743                 ins->inst_false_bb = tblock;    \
744                 start_new_bblock = 2;   \
745         } while (0)
746
747 #define NEW_LDELEMA(cfg,dest,sp,k) do { \
748                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
749                 (dest)->opcode = CEE_LDELEMA;   \
750                 (dest)->inst_left = (sp) [0];   \
751                 (dest)->inst_right = (sp) [1];  \
752                 (dest)->type = STACK_MP;        \
753                 (dest)->klass = (k);    \
754                 (cfg)->flags |= MONO_CFG_HAS_LDELEMA; \
755         } while (0)
756
757 #define NEW_GROUP(cfg,dest,el1,el2) do {        \
758                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
759                 (dest)->opcode = OP_GROUP;      \
760                 (dest)->inst_left = (el1);      \
761                 (dest)->inst_right = (el2);     \
762         } while (0)
763
764 #if 0
765 static gint
766 compare_bblock (gconstpointer a, gconstpointer b)
767 {
768         const MonoBasicBlock *b1 = a;
769         const MonoBasicBlock *b2 = b;
770
771         return b2->cil_code - b1->cil_code;
772 }
773 #endif
774
775 /* *
776  * link_bblock: Links two basic blocks
777  *
778  * links two basic blocks in the control flow graph, the 'from'
779  * argument is the starting block and the 'to' argument is the block
780  * the control flow ends to after 'from'.
781  */
782 static void
783 link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
784 {
785         MonoBasicBlock **newa;
786         int i, found;
787
788 #if 0
789         if (from->cil_code) {
790                 if (to->cil_code)
791                         g_print ("edge from IL%04x to IL_%04x\n", from->cil_code - cfg->cil_code, to->cil_code - cfg->cil_code);
792                 else
793                         g_print ("edge from IL%04x to exit\n", from->cil_code - cfg->cil_code);
794         } else {
795                 if (to->cil_code)
796                         g_print ("edge from entry to IL_%04x\n", to->cil_code - cfg->cil_code);
797                 else
798                         g_print ("edge from entry to exit\n");
799         }
800 #endif
801         found = FALSE;
802         for (i = 0; i < from->out_count; ++i) {
803                 if (to == from->out_bb [i]) {
804                         found = TRUE;
805                         break;
806                 }
807         }
808         if (!found) {
809                 newa = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (from->out_count + 1));
810                 for (i = 0; i < from->out_count; ++i) {
811                         newa [i] = from->out_bb [i];
812                 }
813                 newa [i] = to;
814                 from->out_count++;
815                 from->out_bb = newa;
816         }
817
818         found = FALSE;
819         for (i = 0; i < to->in_count; ++i) {
820                 if (from == to->in_bb [i]) {
821                         found = TRUE;
822                         break;
823                 }
824         }
825         if (!found) {
826                 newa = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (to->in_count + 1));
827                 for (i = 0; i < to->in_count; ++i) {
828                         newa [i] = to->in_bb [i];
829                 }
830                 newa [i] = from;
831                 to->in_count++;
832                 to->in_bb = newa;
833         }
834 }
835
836 /**
837  * mono_unlink_bblock:
838  *
839  *   Unlink two basic blocks.
840  */
841 static void
842 mono_unlink_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
843 {
844         int i, pos;
845         gboolean found;
846
847         found = FALSE;
848         for (i = 0; i < from->out_count; ++i) {
849                 if (to == from->out_bb [i]) {
850                         found = TRUE;
851                         break;
852                 }
853         }
854         if (found) {
855                 pos = 0;
856                 for (i = 0; i < from->out_count; ++i) {
857                         if (from->out_bb [i] != to)
858                                 from->out_bb [pos ++] = from->out_bb [i];
859                 }
860                 g_assert (pos == from->out_count - 1);
861                 from->out_count--;
862         }
863
864         found = FALSE;
865         for (i = 0; i < to->in_count; ++i) {
866                 if (from == to->in_bb [i]) {
867                         found = TRUE;
868                         break;
869                 }
870         }
871         if (found) {
872                 pos = 0;
873                 for (i = 0; i < to->in_count; ++i) {
874                         if (to->in_bb [i] != from)
875                                 to->in_bb [pos ++] = to->in_bb [i];
876                 }
877                 g_assert (pos == to->in_count - 1);
878                 to->in_count--;
879         }
880 }
881
882 /**
883  * mono_find_block_region:
884  *
885  *   We mark each basic block with a region ID. We use that to avoid BB
886  *   optimizations when blocks are in different regions.
887  *
888  * Returns:
889  *   A region token that encodes where this region is, and information
890  *   about the clause owner for this block.
891  *
892  *   The region encodes the try/catch/filter clause that owns this block
893  *   as well as the type.  -1 is a special value that represents a block
894  *   that is in none of try/catch/filter.
895  */
896 static int
897 mono_find_block_region (MonoCompile *cfg, int offset)
898 {
899         MonoMethod *method = cfg->method;
900         MonoMethodHeader *header = mono_method_get_header (method);
901         MonoExceptionClause *clause;
902         int i;
903
904         /* first search for handlers and filters */
905         for (i = 0; i < header->num_clauses; ++i) {
906                 clause = &header->clauses [i];
907                 if ((clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) && (offset >= clause->data.filter_offset) &&
908                     (offset < (clause->handler_offset)))
909                         return ((i + 1) << 8) | MONO_REGION_FILTER | clause->flags;
910                            
911                 if (MONO_OFFSET_IN_HANDLER (clause, offset)) {
912                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY)
913                                 return ((i + 1) << 8) | MONO_REGION_FINALLY | clause->flags;
914                         else if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
915                                 return ((i + 1) << 8) | MONO_REGION_FAULT | clause->flags;
916                         else if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE)
917                                 return ((i + 1) << 8) | MONO_REGION_CATCH | clause->flags;
918                 }
919         }
920
921         /* search the try blocks */
922         for (i = 0; i < header->num_clauses; ++i) {
923                 clause = &header->clauses [i];
924                 if (MONO_OFFSET_IN_CLAUSE (clause, offset))
925                         return ((i + 1) << 8) | clause->flags;
926         }
927
928         return -1;
929 }
930
931 static GList*
932 mono_find_final_block (MonoCompile *cfg, unsigned char *ip, unsigned char *target, int type)
933 {
934         MonoMethod *method = cfg->method;
935         MonoMethodHeader *header = mono_method_get_header (method);
936         MonoExceptionClause *clause;
937         MonoBasicBlock *handler;
938         int i;
939         GList *res = NULL;
940
941         for (i = 0; i < header->num_clauses; ++i) {
942                 clause = &header->clauses [i];
943                 if (MONO_OFFSET_IN_CLAUSE (clause, (ip - header->code)) && 
944                     (!MONO_OFFSET_IN_CLAUSE (clause, (target - header->code)))) {
945                         if (clause->flags == type) {
946                                 handler = cfg->cil_offset_to_bb [clause->handler_offset];
947                                 g_assert (handler);
948                                 res = g_list_append (res, handler);
949                         }
950                 }
951         }
952         return res;
953 }
954
955 MonoInst *
956 mono_find_spvar_for_region (MonoCompile *cfg, int region)
957 {
958         return g_hash_table_lookup (cfg->spvars, GINT_TO_POINTER (region));
959 }
960
961 static void
962 mono_create_spvar_for_region (MonoCompile *cfg, int region)
963 {
964         MonoInst *var;
965
966         var = g_hash_table_lookup (cfg->spvars, GINT_TO_POINTER (region));
967         if (var)
968                 return;
969
970         var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
971         /* prevent it from being register allocated */
972         var->flags |= MONO_INST_INDIRECT;
973
974         g_hash_table_insert (cfg->spvars, GINT_TO_POINTER (region), var);
975 }
976
977 static MonoInst *
978 mono_find_exvar_for_offset (MonoCompile *cfg, int offset)
979 {
980         return g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
981 }
982
983 static MonoInst*
984 mono_create_exvar_for_offset (MonoCompile *cfg, int offset)
985 {
986         MonoInst *var;
987
988         var = g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
989         if (var)
990                 return var;
991
992         var = mono_compile_create_var (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL);
993         /* prevent it from being register allocated */
994         var->flags |= MONO_INST_INDIRECT;
995
996         g_hash_table_insert (cfg->exvars, GINT_TO_POINTER (offset), var);
997
998         return var;
999 }
1000
1001 static void
1002 df_visit (MonoBasicBlock *start, int *dfn, MonoBasicBlock **array)
1003 {
1004         int i;
1005
1006         array [*dfn] = start;
1007         /*g_print ("visit %d at %p (BB%ld)\n", *dfn, start->cil_code, start->block_num);*/
1008         for (i = 0; i < start->out_count; ++i) {
1009                 if (start->out_bb [i]->dfn)
1010                         continue;
1011                 (*dfn)++;
1012                 start->out_bb [i]->dfn = *dfn;
1013                 start->out_bb [i]->df_parent = start;
1014                 array [*dfn] = start->out_bb [i];
1015                 df_visit (start->out_bb [i], dfn, array);
1016         }
1017 }
1018
1019 static MonoBasicBlock*
1020 find_previous (MonoBasicBlock **bblocks, guint32 n_bblocks, MonoBasicBlock *start, const guchar *code)
1021 {
1022         MonoBasicBlock *best = start;
1023         int i;
1024
1025         for (i = 0; i < n_bblocks; ++i) {
1026                 if (bblocks [i]) {
1027                         MonoBasicBlock *bb = bblocks [i];
1028
1029                         if (bb->cil_code && bb->cil_code < code && bb->cil_code > best->cil_code)
1030                                 best = bb;
1031                 }
1032         }
1033
1034         return best;
1035 }
1036
1037 static void
1038 split_bblock (MonoCompile *cfg, MonoBasicBlock *first, MonoBasicBlock *second) {
1039         int i, j;
1040         MonoInst *inst;
1041         MonoBasicBlock *bb;
1042
1043         if (second->code)
1044                 return;
1045         
1046         /* 
1047          * FIXME: take into account all the details:
1048          * second may have been the target of more than one bblock
1049          */
1050         second->out_count = first->out_count;
1051         second->out_bb = first->out_bb;
1052
1053         for (i = 0; i < first->out_count; ++i) {
1054                 bb = first->out_bb [i];
1055                 for (j = 0; j < bb->in_count; ++j) {
1056                         if (bb->in_bb [j] == first)
1057                                 bb->in_bb [j] = second;
1058                 }
1059         }
1060
1061         first->out_count = 0;
1062         first->out_bb = NULL;
1063         link_bblock (cfg, first, second);
1064
1065         second->last_ins = first->last_ins;
1066
1067         /*g_print ("start search at %p for %p\n", first->cil_code, second->cil_code);*/
1068         for (inst = first->code; inst && inst->next; inst = inst->next) {
1069                 /*char *code = mono_disasm_code_one (NULL, cfg->method, inst->next->cil_code, NULL);
1070                 g_print ("found %p: %s", inst->next->cil_code, code);
1071                 g_free (code);*/
1072                 if (inst->cil_code < second->cil_code && inst->next->cil_code >= second->cil_code) {
1073                         second->code = inst->next;
1074                         inst->next = NULL;
1075                         first->last_ins = inst;
1076                         second->next_bb = first->next_bb;
1077                         first->next_bb = second;
1078                         return;
1079                 }
1080         }
1081         if (!second->code) {
1082                 g_warning ("bblock split failed in %s::%s\n", cfg->method->klass->name, cfg->method->name);
1083                 //G_BREAKPOINT ();
1084         }
1085 }
1086
1087 static guint32
1088 reverse_branch_op (guint32 opcode)
1089 {
1090         static const int reverse_map [] = {
1091                 CEE_BNE_UN, CEE_BLT, CEE_BLE, CEE_BGT, CEE_BGE,
1092                 CEE_BEQ, CEE_BLT_UN, CEE_BLE_UN, CEE_BGT_UN, CEE_BGE_UN
1093         };
1094         static const int reverse_fmap [] = {
1095                 OP_FBNE_UN, OP_FBLT, OP_FBLE, OP_FBGT, OP_FBGE,
1096                 OP_FBEQ, OP_FBLT_UN, OP_FBLE_UN, OP_FBGT_UN, OP_FBGE_UN
1097         };
1098         static const int reverse_lmap [] = {
1099                 OP_LBNE_UN, OP_LBLT, OP_LBLE, OP_LBGT, OP_LBGE,
1100                 OP_LBEQ, OP_LBLT_UN, OP_LBLE_UN, OP_LBGT_UN, OP_LBGE_UN
1101         };
1102         static const int reverse_imap [] = {
1103                 OP_IBNE_UN, OP_IBLT, OP_IBLE, OP_IBGT, OP_IBGE,
1104                 OP_IBEQ, OP_IBLT_UN, OP_IBLE_UN, OP_IBGT_UN, OP_IBGE_UN
1105         };
1106                                 
1107         if (opcode >= CEE_BEQ && opcode <= CEE_BLT_UN) {
1108                 opcode = reverse_map [opcode - CEE_BEQ];
1109         } else if (opcode >= OP_FBEQ && opcode <= OP_FBLT_UN) {
1110                 opcode = reverse_fmap [opcode - OP_FBEQ];
1111         } else if (opcode >= OP_LBEQ && opcode <= OP_LBLT_UN) {
1112                 opcode = reverse_lmap [opcode - OP_LBEQ];
1113         } else if (opcode >= OP_IBEQ && opcode <= OP_IBLT_UN) {
1114                 opcode = reverse_imap [opcode - OP_IBEQ];
1115         } else
1116                 g_assert_not_reached ();
1117
1118         return opcode;
1119 }
1120
1121 #ifdef MONO_ARCH_SOFT_FLOAT
1122 static int
1123 condbr_to_fp_br (int opcode)
1124 {
1125         switch (opcode) {
1126         case CEE_BEQ: return OP_FBEQ;
1127         case CEE_BGE: return OP_FBGE;
1128         case CEE_BGT: return OP_FBGT;
1129         case CEE_BLE: return OP_FBLE;
1130         case CEE_BLT: return OP_FBLT;
1131         case CEE_BNE_UN: return OP_FBNE_UN;
1132         case CEE_BGE_UN: return OP_FBGE_UN;
1133         case CEE_BGT_UN: return OP_FBGT_UN;
1134         case CEE_BLE_UN: return OP_FBLE_UN;
1135         case CEE_BLT_UN: return OP_FBLT_UN;
1136         }
1137         g_assert_not_reached ();
1138         return 0;
1139 }
1140 #endif
1141
1142 /*
1143  * Returns the type used in the eval stack when @type is loaded.
1144  * FIXME: return a MonoType/MonoClass for the byref and VALUETYPE cases.
1145  */
1146 static void
1147 type_to_eval_stack_type (MonoType *type, MonoInst *inst)
1148 {
1149         MonoClass *klass;
1150
1151         inst->klass = klass = mono_class_from_mono_type (type);
1152         if (type->byref) {
1153                 inst->type = STACK_MP;
1154                 return;
1155         }
1156
1157 handle_enum:
1158         switch (type->type) {
1159         case MONO_TYPE_VOID:
1160                 inst->type = STACK_INV;
1161                 return;
1162         case MONO_TYPE_I1:
1163         case MONO_TYPE_U1:
1164         case MONO_TYPE_BOOLEAN:
1165         case MONO_TYPE_I2:
1166         case MONO_TYPE_U2:
1167         case MONO_TYPE_CHAR:
1168         case MONO_TYPE_I4:
1169         case MONO_TYPE_U4:
1170                 inst->type = STACK_I4;
1171                 return;
1172         case MONO_TYPE_I:
1173         case MONO_TYPE_U:
1174         case MONO_TYPE_PTR:
1175         case MONO_TYPE_FNPTR:
1176                 inst->type = STACK_PTR;
1177                 return;
1178         case MONO_TYPE_CLASS:
1179         case MONO_TYPE_STRING:
1180         case MONO_TYPE_OBJECT:
1181         case MONO_TYPE_SZARRAY:
1182         case MONO_TYPE_ARRAY:    
1183                 inst->type = STACK_OBJ;
1184                 return;
1185         case MONO_TYPE_I8:
1186         case MONO_TYPE_U8:
1187                 inst->type = STACK_I8;
1188                 return;
1189         case MONO_TYPE_R4:
1190         case MONO_TYPE_R8:
1191                 inst->type = STACK_R8;
1192                 return;
1193         case MONO_TYPE_VALUETYPE:
1194                 if (type->data.klass->enumtype) {
1195                         type = type->data.klass->enum_basetype;
1196                         goto handle_enum;
1197                 } else {
1198                         inst->klass = klass;
1199                         inst->type = STACK_VTYPE;
1200                         return;
1201                 }
1202         case MONO_TYPE_TYPEDBYREF:
1203                 inst->klass = mono_defaults.typed_reference_class;
1204                 inst->type = STACK_VTYPE;
1205                 return;
1206         case MONO_TYPE_GENERICINST:
1207                 type = &type->data.generic_class->container_class->byval_arg;
1208                 goto handle_enum;
1209         default:
1210                 g_error ("unknown type 0x%02x in eval stack type", type->type);
1211         }
1212 }
1213
1214 /*
1215  * The following tables are used to quickly validate the IL code in type_from_op ().
1216  */
1217 static const char
1218 bin_num_table [STACK_MAX] [STACK_MAX] = {
1219         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1220         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
1221         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1222         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
1223         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_R8,  STACK_INV, STACK_INV, STACK_INV},
1224         {STACK_INV, STACK_MP,  STACK_INV, STACK_MP,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV},
1225         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1226         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
1227 };
1228
1229 static const char 
1230 neg_table [] = {
1231         STACK_INV, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_INV, STACK_INV, STACK_INV
1232 };
1233
1234 /* reduce the size of this table */
1235 static const char
1236 bin_int_table [STACK_MAX] [STACK_MAX] = {
1237         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1238         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1239         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1240         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1241         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1242         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1243         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1244         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
1245 };
1246
1247 static const char
1248 bin_comp_table [STACK_MAX] [STACK_MAX] = {
1249 /*      Inv i  L  p  F  &  O  vt */
1250         {0},
1251         {0, 1, 0, 1, 0, 0, 0, 0}, /* i, int32 */
1252         {0, 0, 1, 0, 0, 0, 0, 0}, /* L, int64 */
1253         {0, 1, 0, 1, 0, 2, 4, 0}, /* p, ptr */
1254         {0, 0, 0, 0, 1, 0, 0, 0}, /* F, R8 */
1255         {0, 0, 0, 2, 0, 1, 0, 0}, /* &, managed pointer */
1256         {0, 0, 0, 4, 0, 0, 3, 0}, /* O, reference */
1257         {0, 0, 0, 0, 0, 0, 0, 0}, /* vt value type */
1258 };
1259
1260 /* reduce the size of this table */
1261 static const char
1262 shift_table [STACK_MAX] [STACK_MAX] = {
1263         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1264         {STACK_INV, STACK_I4,  STACK_INV, STACK_I4,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1265         {STACK_INV, STACK_I8,  STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1266         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1267         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1268         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1269         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1270         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
1271 };
1272
1273 /*
1274  * Tables to map from the non-specific opcode to the matching
1275  * type-specific opcode.
1276  */
1277 /* handles from CEE_ADD to CEE_SHR_UN (CEE_REM_UN for floats) */
1278 static const guint16
1279 binops_op_map [STACK_MAX] = {
1280         0, 0, OP_LADD-CEE_ADD, OP_PADD-CEE_ADD, OP_FADD-CEE_ADD, OP_PADD-CEE_ADD
1281 };
1282
1283 /* handles from CEE_NEG to CEE_CONV_U8 */
1284 static const guint16
1285 unops_op_map [STACK_MAX] = {
1286         0, 0, OP_LNEG-CEE_NEG, OP_PNEG-CEE_NEG, OP_FNEG-CEE_NEG, OP_PNEG-CEE_NEG
1287 };
1288
1289 /* handles from CEE_CONV_U2 to CEE_SUB_OVF_UN */
1290 static const guint16
1291 ovfops_op_map [STACK_MAX] = {
1292         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
1293 };
1294
1295 /* handles from CEE_CONV_OVF_I1_UN to CEE_CONV_OVF_U_UN */
1296 static const guint16
1297 ovf2ops_op_map [STACK_MAX] = {
1298         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
1299 };
1300
1301 /* handles from CEE_CONV_OVF_I1 to CEE_CONV_OVF_U8 */
1302 static const guint16
1303 ovf3ops_op_map [STACK_MAX] = {
1304         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
1305 };
1306
1307 /* handles from CEE_CEQ to CEE_CLT_UN */
1308 static const guint16
1309 ceqops_op_map [STACK_MAX] = {
1310         0, 0, OP_LCEQ-OP_CEQ, OP_PCEQ-OP_CEQ, OP_FCEQ-OP_CEQ, OP_LCEQ-OP_CEQ
1311 };
1312
1313 /*
1314  * Sets ins->type (the type on the eval stack) according to the
1315  * type of the opcode and the arguments to it.
1316  * Invalid IL code is marked by setting ins->type to the invalid value STACK_INV.
1317  *
1318  * FIXME: this function sets ins->type unconditionally in some cases, but
1319  * it should set it to invalid for some types (a conv.x on an object)
1320  */
1321 static void
1322 type_from_op (MonoInst *ins) {
1323         switch (ins->opcode) {
1324         /* binops */
1325         case CEE_ADD:
1326         case CEE_SUB:
1327         case CEE_MUL:
1328         case CEE_DIV:
1329         case CEE_REM:
1330                 /* FIXME: check unverifiable args for STACK_MP */
1331                 ins->type = bin_num_table [ins->inst_i0->type] [ins->inst_i1->type];
1332                 ins->opcode += binops_op_map [ins->type];
1333                 return;
1334         case CEE_DIV_UN:
1335         case CEE_REM_UN:
1336         case CEE_AND:
1337         case CEE_OR:
1338         case CEE_XOR:
1339                 ins->type = bin_int_table [ins->inst_i0->type] [ins->inst_i1->type];
1340                 ins->opcode += binops_op_map [ins->type];
1341                 return;
1342         case CEE_SHL:
1343         case CEE_SHR:
1344         case CEE_SHR_UN:
1345                 ins->type = shift_table [ins->inst_i0->type] [ins->inst_i1->type];
1346                 ins->opcode += binops_op_map [ins->type];
1347                 return;
1348         case OP_COMPARE:
1349         case OP_LCOMPARE:
1350                 /* FIXME: handle some specifics with ins->next->type */
1351                 ins->type = bin_comp_table [ins->inst_i0->type] [ins->inst_i1->type] ? STACK_I4: STACK_INV;
1352                 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))))
1353                         ins->opcode = OP_LCOMPARE;
1354                 return;
1355         case OP_CEQ:
1356                 ins->type = bin_comp_table [ins->inst_i0->type] [ins->inst_i1->type] ? STACK_I4: STACK_INV;
1357                 ins->opcode += ceqops_op_map [ins->inst_i0->type];
1358                 return;
1359                 
1360         case OP_CGT:
1361         case OP_CGT_UN:
1362         case OP_CLT:
1363         case OP_CLT_UN:
1364                 ins->type = (bin_comp_table [ins->inst_i0->type] [ins->inst_i1->type] & 1) ? STACK_I4: STACK_INV;
1365                 ins->opcode += ceqops_op_map [ins->inst_i0->type];
1366                 return;
1367         /* unops */
1368         case CEE_NEG:
1369                 ins->type = neg_table [ins->inst_i0->type];
1370                 ins->opcode += unops_op_map [ins->type];
1371                 return;
1372         case CEE_NOT:
1373                 if (ins->inst_i0->type >= STACK_I4 && ins->inst_i0->type <= STACK_PTR)
1374                         ins->type = ins->inst_i0->type;
1375                 else
1376                         ins->type = STACK_INV;
1377                 ins->opcode += unops_op_map [ins->type];
1378                 return;
1379         case CEE_CONV_I1:
1380         case CEE_CONV_I2:
1381         case CEE_CONV_I4:
1382         case CEE_CONV_U4:
1383                 ins->type = STACK_I4;
1384                 ins->opcode += unops_op_map [ins->inst_i0->type];
1385                 return;
1386         case CEE_CONV_R_UN:
1387                 ins->type = STACK_R8;
1388                 switch (ins->inst_i0->type) {
1389                 case STACK_I4:
1390                 case STACK_PTR:
1391                         break;
1392                 case STACK_I8:
1393                         ins->opcode = OP_LCONV_TO_R_UN; 
1394                         break;
1395                 }
1396                 return;
1397         case CEE_CONV_OVF_I1:
1398         case CEE_CONV_OVF_U1:
1399         case CEE_CONV_OVF_I2:
1400         case CEE_CONV_OVF_U2:
1401         case CEE_CONV_OVF_I4:
1402         case CEE_CONV_OVF_U4:
1403                 ins->type = STACK_I4;
1404                 ins->opcode += ovf3ops_op_map [ins->inst_i0->type];
1405                 return;
1406         case CEE_CONV_OVF_I_UN:
1407         case CEE_CONV_OVF_U_UN:
1408                 ins->type = STACK_PTR;
1409                 ins->opcode += ovf2ops_op_map [ins->inst_i0->type];
1410                 return;
1411         case CEE_CONV_OVF_I1_UN:
1412         case CEE_CONV_OVF_I2_UN:
1413         case CEE_CONV_OVF_I4_UN:
1414         case CEE_CONV_OVF_U1_UN:
1415         case CEE_CONV_OVF_U2_UN:
1416         case CEE_CONV_OVF_U4_UN:
1417                 ins->type = STACK_I4;
1418                 ins->opcode += ovf2ops_op_map [ins->inst_i0->type];
1419                 return;
1420         case CEE_CONV_U:
1421                 ins->type = STACK_PTR;
1422                 switch (ins->inst_i0->type) {
1423                 case STACK_I4:
1424                         break;
1425                 case STACK_PTR:
1426                 case STACK_MP:
1427 #if SIZEOF_VOID_P == 8
1428                         ins->opcode = OP_LCONV_TO_U;
1429 #endif
1430                         break;
1431                 case STACK_I8:
1432                         ins->opcode = OP_LCONV_TO_U;
1433                         break;
1434                 case STACK_R8:
1435                         ins->opcode = OP_FCONV_TO_U;
1436                         break;
1437                 }
1438                 return;
1439         case CEE_CONV_I8:
1440         case CEE_CONV_U8:
1441                 ins->type = STACK_I8;
1442                 ins->opcode += unops_op_map [ins->inst_i0->type];
1443                 return;
1444         case CEE_CONV_OVF_I8:
1445         case CEE_CONV_OVF_U8:
1446                 ins->type = STACK_I8;
1447                 ins->opcode += ovf3ops_op_map [ins->inst_i0->type];
1448                 return;
1449         case CEE_CONV_OVF_U8_UN:
1450         case CEE_CONV_OVF_I8_UN:
1451                 ins->type = STACK_I8;
1452                 ins->opcode += ovf2ops_op_map [ins->inst_i0->type];
1453                 return;
1454         case CEE_CONV_R4:
1455         case CEE_CONV_R8:
1456                 ins->type = STACK_R8;
1457                 ins->opcode += unops_op_map [ins->inst_i0->type];
1458                 return;
1459         case OP_CKFINITE:
1460                 ins->type = STACK_R8;           
1461                 return;
1462         case CEE_CONV_U2:
1463         case CEE_CONV_U1:
1464                 ins->type = STACK_I4;
1465                 ins->opcode += ovfops_op_map [ins->inst_i0->type];
1466                 break;
1467         case CEE_CONV_I:
1468         case CEE_CONV_OVF_I:
1469         case CEE_CONV_OVF_U:
1470                 ins->type = STACK_PTR;
1471                 ins->opcode += ovfops_op_map [ins->inst_i0->type];
1472                 return;
1473         case CEE_ADD_OVF:
1474         case CEE_ADD_OVF_UN:
1475         case CEE_MUL_OVF:
1476         case CEE_MUL_OVF_UN:
1477         case CEE_SUB_OVF:
1478         case CEE_SUB_OVF_UN:
1479                 ins->type = bin_num_table [ins->inst_i0->type] [ins->inst_i1->type];
1480                 ins->opcode += ovfops_op_map [ins->inst_i0->type];
1481                 return;
1482         default:
1483                 g_error ("opcode 0x%04x not handled in type from op", ins->opcode);
1484                 break;
1485         }
1486 }
1487
1488 static const char 
1489 ldind_type [] = {
1490         STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_R8, STACK_OBJ
1491 };
1492
1493 /* map ldelem.x to the matching ldind.x opcode */
1494 static const guchar
1495 ldelem_to_ldind [] = {
1496         CEE_LDIND_I1,
1497         CEE_LDIND_U1,
1498         CEE_LDIND_I2,
1499         CEE_LDIND_U2,
1500         CEE_LDIND_I4,
1501         CEE_LDIND_U4,
1502         CEE_LDIND_I8,
1503         CEE_LDIND_I,
1504         CEE_LDIND_R4,
1505         CEE_LDIND_R8,
1506         CEE_LDIND_REF
1507 };
1508
1509 /* map stelem.x to the matching stind.x opcode */
1510 static const guchar
1511 stelem_to_stind [] = {
1512         CEE_STIND_I,
1513         CEE_STIND_I1,
1514         CEE_STIND_I2,
1515         CEE_STIND_I4,
1516         CEE_STIND_I8,
1517         CEE_STIND_R4,
1518         CEE_STIND_R8,
1519         CEE_STIND_REF
1520 };
1521
1522 #if 0
1523
1524 static const char
1525 param_table [STACK_MAX] [STACK_MAX] = {
1526         {0},
1527 };
1528
1529 static int
1530 check_values_to_signature (MonoInst *args, MonoType *this, MonoMethodSignature *sig) {
1531         int i;
1532
1533         if (sig->hasthis) {
1534                 switch (args->type) {
1535                 case STACK_I4:
1536                 case STACK_I8:
1537                 case STACK_R8:
1538                 case STACK_VTYPE:
1539                 case STACK_INV:
1540                         return 0;
1541                 }
1542                 args++;
1543         }
1544         for (i = 0; i < sig->param_count; ++i) {
1545                 switch (args [i].type) {
1546                 case STACK_INV:
1547                         return 0;
1548                 case STACK_MP:
1549                         if (!sig->params [i]->byref)
1550                                 return 0;
1551                         continue;
1552                 case STACK_OBJ:
1553                         if (sig->params [i]->byref)
1554                                 return 0;
1555                         switch (sig->params [i]->type) {
1556                         case MONO_TYPE_CLASS:
1557                         case MONO_TYPE_STRING:
1558                         case MONO_TYPE_OBJECT:
1559                         case MONO_TYPE_SZARRAY:
1560                         case MONO_TYPE_ARRAY:
1561                                 break;
1562                         default:
1563                                 return 0;
1564                         }
1565                         continue;
1566                 case STACK_R8:
1567                         if (sig->params [i]->byref)
1568                                 return 0;
1569                         if (sig->params [i]->type != MONO_TYPE_R4 && sig->params [i]->type != MONO_TYPE_R8)
1570                                 return 0;
1571                         continue;
1572                 case STACK_PTR:
1573                 case STACK_I4:
1574                 case STACK_I8:
1575                 case STACK_VTYPE:
1576                         break;
1577                 }
1578                 /*if (!param_table [args [i].type] [sig->params [i]->type])
1579                         return 0;*/
1580         }
1581         return 1;
1582 }
1583 #endif
1584
1585 /*
1586  * When we need a pointer to the current domain many times in a method, we
1587  * call mono_domain_get() once and we store the result in a local variable.
1588  * This function returns the variable that represents the MonoDomain*.
1589  */
1590 inline static MonoInst *
1591 mono_get_domainvar (MonoCompile *cfg)
1592 {
1593         if (!cfg->domainvar)
1594                 cfg->domainvar = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1595         return cfg->domainvar;
1596 }
1597
1598 /*
1599  * The got_var contains the address of the Global Offset Table when AOT 
1600  * compiling.
1601  */
1602 inline static MonoInst *
1603 mono_get_got_var (MonoCompile *cfg)
1604 {
1605 #ifdef MONO_ARCH_NEED_GOT_VAR
1606         if (!cfg->compile_aot)
1607                 return NULL;
1608         if (!cfg->got_var) {
1609                 cfg->got_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1610         }
1611         return cfg->got_var;
1612 #else
1613         return NULL;
1614 #endif
1615 }
1616
1617 MonoInst*
1618 mono_compile_create_var (MonoCompile *cfg, MonoType *type, int opcode)
1619 {
1620         MonoInst *inst;
1621         int num = cfg->num_varinfo;
1622
1623         if ((num + 1) >= cfg->varinfo_count) {
1624                 cfg->varinfo_count = (cfg->varinfo_count + 2) * 2;
1625                 cfg->varinfo = (MonoInst **)g_realloc (cfg->varinfo, sizeof (MonoInst*) * cfg->varinfo_count);
1626                 cfg->vars = (MonoMethodVar **)g_realloc (cfg->vars, sizeof (MonoMethodVar*) * cfg->varinfo_count);      
1627         }
1628
1629         /*g_print ("created temp %d of type 0x%x\n", num, type->type);*/
1630         mono_jit_stats.allocate_var++;
1631
1632         MONO_INST_NEW (cfg, inst, opcode);
1633         inst->inst_c0 = num;
1634         inst->inst_vtype = type;
1635         inst->klass = mono_class_from_mono_type (type);
1636         /* if set to 1 the variable is native */
1637         inst->backend.is_pinvoke = 0;
1638
1639         cfg->varinfo [num] = inst;
1640
1641         cfg->vars [num] = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoMethodVar));
1642         MONO_INIT_VARINFO (cfg->vars [num], num);
1643
1644         cfg->num_varinfo++;
1645         if (cfg->verbose_level > 2)
1646                 g_print ("created temp %d of type %s\n", num, mono_type_get_name (type));
1647         return inst;
1648 }
1649
1650 /*
1651  * Transform a MonoInst into a load from the variable of index var_index.
1652  */
1653 void
1654 mono_compile_make_var_load (MonoCompile *cfg, MonoInst *dest, gssize var_index) {
1655         memset (dest, 0, sizeof (MonoInst));
1656         dest->ssa_op = MONO_SSA_LOAD;
1657         dest->inst_i0 = cfg->varinfo [var_index];
1658         dest->opcode = mono_type_to_ldind (dest->inst_i0->inst_vtype);
1659         type_to_eval_stack_type (dest->inst_i0->inst_vtype, dest);
1660         dest->klass = dest->inst_i0->klass;
1661 }
1662
1663 /*
1664  * Create a MonoInst that is a load from the variable of index var_index.
1665  */
1666 MonoInst*
1667 mono_compile_create_var_load (MonoCompile *cfg, gssize var_index) {
1668         MonoInst *dest;
1669         NEW_TEMPLOAD (cfg,dest,var_index);
1670         return dest;
1671 }
1672
1673 /*
1674  * Create a MonoInst that is a store of the given value into the variable of index var_index.
1675  */
1676 MonoInst*
1677 mono_compile_create_var_store (MonoCompile *cfg, gssize var_index, MonoInst *value) {
1678         MonoInst *dest;
1679         NEW_TEMPSTORE (cfg, dest, var_index, value);
1680         return dest;
1681 }
1682
1683 static MonoType*
1684 type_from_stack_type (MonoInst *ins) {
1685         switch (ins->type) {
1686         case STACK_I4: return &mono_defaults.int32_class->byval_arg;
1687         case STACK_I8: return &mono_defaults.int64_class->byval_arg;
1688         case STACK_PTR: return &mono_defaults.int_class->byval_arg;
1689         case STACK_R8: return &mono_defaults.double_class->byval_arg;
1690         case STACK_MP:
1691                 /* 
1692                  * this if used to be commented without any specific reason, but
1693                  * it breaks #80235 when commented
1694                  */
1695                 if (ins->klass)
1696                         return &ins->klass->this_arg;
1697                 else
1698                         return &mono_defaults.object_class->this_arg;
1699         case STACK_OBJ:
1700                 /* ins->klass may not be set for ldnull.
1701                  * Also, if we have a boxed valuetype, we want an object lass,
1702                  * not the valuetype class
1703                  */
1704                 if (ins->klass && !ins->klass->valuetype)
1705                         return &ins->klass->byval_arg;
1706                 return &mono_defaults.object_class->byval_arg;
1707         case STACK_VTYPE: return &ins->klass->byval_arg;
1708         default:
1709                 g_error ("stack type %d to montype not handled\n", ins->type);
1710         }
1711         return NULL;
1712 }
1713
1714 MonoType*
1715 mono_type_from_stack_type (MonoInst *ins) {
1716         return type_from_stack_type (ins);
1717 }
1718
1719 static MonoClass*
1720 array_access_to_klass (int opcode, MonoInst *array_obj)
1721 {
1722         switch (opcode) {
1723         case CEE_LDELEM_U1:
1724                 return mono_defaults.byte_class;
1725         case CEE_LDELEM_U2:
1726                 return mono_defaults.uint16_class;
1727         case CEE_LDELEM_I:
1728         case CEE_STELEM_I:
1729                 return mono_defaults.int_class;
1730         case CEE_LDELEM_I1:
1731         case CEE_STELEM_I1:
1732                 return mono_defaults.sbyte_class;
1733         case CEE_LDELEM_I2:
1734         case CEE_STELEM_I2:
1735                 return mono_defaults.int16_class;
1736         case CEE_LDELEM_I4:
1737         case CEE_STELEM_I4:
1738                 return mono_defaults.int32_class;
1739         case CEE_LDELEM_U4:
1740                 return mono_defaults.uint32_class;
1741         case CEE_LDELEM_I8:
1742         case CEE_STELEM_I8:
1743                 return mono_defaults.int64_class;
1744         case CEE_LDELEM_R4:
1745         case CEE_STELEM_R4:
1746                 return mono_defaults.single_class;
1747         case CEE_LDELEM_R8:
1748         case CEE_STELEM_R8:
1749                 return mono_defaults.double_class;
1750         case CEE_LDELEM_REF:
1751         case CEE_STELEM_REF: {
1752                 MonoClass *klass = array_obj->klass;
1753                 /* FIXME: add assert */
1754                 if (klass && klass->rank)
1755                         return klass->element_class;
1756                 return mono_defaults.object_class;
1757         }
1758         default:
1759                 g_assert_not_reached ();
1760         }
1761         return NULL;
1762 }
1763
1764 void
1765 mono_add_ins_to_end (MonoBasicBlock *bb, MonoInst *inst)
1766 {
1767         MonoInst *prev;
1768         if (!bb->code) {
1769                 MONO_ADD_INS (bb, inst);
1770                 return;
1771         }
1772         switch (bb->last_ins->opcode) {
1773         case CEE_BEQ:
1774         case CEE_BGE:
1775         case CEE_BGT:
1776         case CEE_BLE:
1777         case CEE_BLT:
1778         case CEE_BNE_UN:
1779         case CEE_BGE_UN:
1780         case CEE_BGT_UN:
1781         case CEE_BLE_UN:
1782         case CEE_BLT_UN:
1783         case OP_BR:
1784         case CEE_SWITCH:
1785                 prev = bb->code;
1786                 while (prev->next && prev->next != bb->last_ins)
1787                         prev = prev->next;
1788                 if (prev == bb->code) {
1789                         if (bb->last_ins == bb->code) {
1790                                 inst->next = bb->code;
1791                                 bb->code = inst;
1792                         } else {
1793                                 inst->next = prev->next;
1794                                 prev->next = inst;
1795                         }
1796                 } else {
1797                         inst->next = bb->last_ins;
1798                         prev->next = inst;
1799                 }
1800                 break;
1801         //      g_warning ("handle conditional jump in add_ins_to_end ()\n");
1802         default:
1803                 MONO_ADD_INS (bb, inst);
1804                 break;
1805         }
1806 }
1807
1808 void
1809 mono_add_varcopy_to_end (MonoCompile *cfg, MonoBasicBlock *bb, int src, int dest)
1810 {
1811         MonoInst *inst, *load;
1812
1813         NEW_TEMPLOAD (cfg, load, src);
1814
1815         NEW_TEMPSTORE (cfg, inst, dest, load);
1816         if (inst->opcode == CEE_STOBJ) {
1817                 NEW_TEMPLOADA (cfg, inst, dest);
1818                 handle_stobj (cfg, bb, inst, load, NULL, inst->klass, TRUE, FALSE, FALSE);
1819         } else {
1820                 inst->cil_code = NULL;
1821                 mono_add_ins_to_end (bb, inst);
1822         }
1823 }
1824
1825 /*
1826  * merge_stacks:
1827  *
1828  * Merge stack state between two basic blocks according to Ecma 335, Partition III,
1829  * section 1.8.1.1. Store the resulting stack state into stack_2.
1830  * Returns: TRUE, if verification succeeds, FALSE otherwise.
1831  * FIXME: We should store the stack state in a dedicated structure instead of in
1832  * MonoInst's.
1833  */
1834 static gboolean
1835 merge_stacks (MonoCompile *cfg, MonoStackSlot *state_1, MonoStackSlot *state_2, guint32 size)
1836 {
1837         int i;
1838
1839         if (cfg->dont_verify_stack_merge)
1840                 return TRUE;
1841
1842         /* FIXME: Implement all checks from the spec */
1843
1844         for (i = 0; i < size; ++i) {
1845                 MonoStackSlot *slot1 = &state_1 [i];
1846                 MonoStackSlot *slot2 = &state_2 [i];
1847
1848                 if (slot1->type != slot2->type)
1849                         return FALSE;
1850
1851                 switch (slot1->type) {
1852                 case STACK_PTR:
1853                         /* FIXME: Perform merge ? */
1854                         /* klass == NULL means a native int */
1855                         if (slot1->klass && slot2->klass) {
1856                                 if (slot1->klass != slot2->klass)
1857                                         return FALSE;
1858                         }
1859                         break;
1860                 case STACK_MP:
1861                         /* FIXME: Change this to an assert and fix the JIT to allways fill this */
1862                         if (slot1->klass && slot2->klass) {
1863                                 if (slot1->klass != slot2->klass)
1864                                         return FALSE;
1865                         }
1866                         break;
1867                 case STACK_OBJ: {
1868                         MonoClass *klass1 = slot1->klass;
1869                         MonoClass *klass2 = slot2->klass;
1870
1871                         if (!klass1) {
1872                                 /* slot1 is ldnull */
1873                         } else if (!klass2) {
1874                                 /* slot2 is ldnull */
1875                                 slot2->klass = slot1->klass;
1876                         }
1877                         break;
1878                 }
1879                 }
1880         }
1881
1882         return TRUE;
1883 }
1884
1885 /*
1886  * This function is called to handle items that are left on the evaluation stack
1887  * at basic block boundaries. What happens is that we save the values to local variables
1888  * and we reload them later when first entering the target basic block (with the
1889  * handle_loaded_temps () function).
1890  * It is also used to handle items on the stack in store opcodes, since it is
1891  * possible that the variable to be stored into is already on the stack, in
1892  * which case its old value should be used.
1893  * A single joint point will use the same variables (stored in the array bb->out_stack or
1894  * bb->in_stack, if the basic block is before or after the joint point).
1895  * If the stack merge fails at a join point, cfg->unverifiable is set.
1896  */
1897 static int
1898 handle_stack_args (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst **sp, int count) {
1899         int i, bindex;
1900         MonoBasicBlock *outb;
1901         MonoInst *inst, **locals;
1902         MonoStackSlot *stack_state;
1903         gboolean found;
1904
1905         if (!count)
1906                 return 0;
1907         if (cfg->verbose_level > 3)
1908                 g_print ("%d item(s) on exit from B%d\n", count, bb->block_num);
1909
1910         stack_state = mono_mempool_alloc (cfg->mempool, sizeof (MonoStackSlot) * count);
1911         for (i = 0; i < count; ++i) {
1912                 stack_state [i].type = sp [i]->type;
1913                 stack_state [i].klass = sp [i]->klass;
1914
1915                 /* Check that instructions other than ldnull have ins->klass set */
1916                 if (!cfg->dont_verify_stack_merge && (sp [i]->type == STACK_OBJ) && !((sp [i]->opcode == OP_PCONST) && sp [i]->inst_c0 == 0))
1917                         g_assert (sp [i]->klass);
1918         }
1919
1920         /* Perform verification and stack state merge */
1921         for (i = 0; i < bb->out_count; ++i) {
1922                 outb = bb->out_bb [i];
1923
1924                 /* exception handlers are linked, but they should not be considered for stack args */
1925                 if (outb->flags & BB_EXCEPTION_HANDLER)
1926                         continue;
1927                 if (outb->stack_state) {
1928                         gboolean verified;
1929
1930                         if (count != outb->in_scount) {
1931                                 cfg->unverifiable = TRUE;
1932                                 return 0;
1933                         }
1934                         verified = merge_stacks (cfg, stack_state, outb->stack_state, count);
1935                         if (!verified) {
1936                                 cfg->unverifiable = TRUE;
1937                                 return 0;
1938                         }
1939
1940                         if (cfg->verbose_level > 3) {
1941                                 int j;
1942
1943                                 for (j = 0; j < count; ++j)
1944                                         printf ("\tStack state of BB%d, slot %d=%d\n", outb->block_num, j, outb->stack_state [j].type);
1945                         }
1946                 } else {
1947                         /* Make a copy of the stack state */
1948                         outb->stack_state = mono_mempool_alloc (cfg->mempool, sizeof (MonoStackSlot) * count);
1949                         memcpy (outb->stack_state, stack_state, sizeof (MonoStackSlot) * count);
1950                 }
1951         }
1952
1953         if (!bb->out_scount) {
1954                 bb->out_scount = count;
1955                 //g_print ("bblock %d has out:", bb->block_num);
1956                 found = FALSE;
1957                 for (i = 0; i < bb->out_count; ++i) {
1958                         outb = bb->out_bb [i];
1959                         /* exception handlers are linked, but they should not be considered for stack args */
1960                         if (outb->flags & BB_EXCEPTION_HANDLER)
1961                                 continue;
1962                         //g_print (" %d", outb->block_num);
1963                         if (outb->in_stack) {
1964                                 found = TRUE;
1965                                 bb->out_stack = outb->in_stack;
1966                                 break;
1967                         }
1968                 }
1969                 //g_print ("\n");
1970                 if (!found) {
1971                         bb->out_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * count);
1972                         for (i = 0; i < count; ++i) {
1973                                 /* 
1974                                  * try to reuse temps already allocated for this purpouse, if they occupy the same
1975                                  * stack slot and if they are of the same type.
1976                                  * This won't cause conflicts since if 'local' is used to 
1977                                  * store one of the values in the in_stack of a bblock, then
1978                                  * the same variable will be used for the same outgoing stack 
1979                                  * slot as well. 
1980                                  * This doesn't work when inlining methods, since the bblocks
1981                                  * in the inlined methods do not inherit their in_stack from
1982                                  * the bblock they are inlined to. See bug #58863 for an
1983                                  * example.
1984                                  * This hack is disabled since it also prevents proper tracking of types.
1985                                  */
1986 #if 1
1987                                 bb->out_stack [i] = mono_compile_create_var (cfg, type_from_stack_type (sp [i]), OP_LOCAL);
1988 #else
1989                                 if (cfg->inlined_method)
1990                                         bb->out_stack [i] = mono_compile_create_var (cfg, type_from_stack_type (sp [i]), OP_LOCAL);
1991                                 else
1992                                         bb->out_stack [i] = mono_compile_get_interface_var (cfg, i, sp [i]);
1993 #endif
1994                         }
1995                 }
1996         }
1997
1998         for (i = 0; i < bb->out_count; ++i) {
1999                 outb = bb->out_bb [i];
2000                 /* exception handlers are linked, but they should not be considered for stack args */
2001                 if (outb->flags & BB_EXCEPTION_HANDLER)
2002                         continue;
2003                 if (outb->in_scount) {
2004                         if (outb->in_scount != bb->out_scount)
2005                                 G_BREAKPOINT ();
2006                         continue; /* check they are the same locals */
2007                 }
2008                 outb->in_scount = count;
2009                 outb->in_stack = bb->out_stack;
2010         }
2011
2012         locals = bb->out_stack;
2013         for (i = 0; i < count; ++i) {
2014                 /* add store ops at the end of the bb, before the branch */
2015                 NEW_TEMPSTORE (cfg, inst, locals [i]->inst_c0, sp [i]);
2016                 if (inst->opcode == CEE_STOBJ) {
2017                         NEW_TEMPLOADA (cfg, inst, locals [i]->inst_c0);
2018                         handle_stobj (cfg, bb, inst, sp [i], sp [i]->cil_code, inst->klass, TRUE, FALSE, FALSE);
2019                 } else {
2020                         inst->cil_code = sp [i]->cil_code;
2021                         mono_add_ins_to_end (bb, inst);
2022                 }
2023                 if (cfg->verbose_level > 3)
2024                         g_print ("storing %d to temp %d\n", i, (int)locals [i]->inst_c0);
2025         }
2026
2027         /*
2028          * It is possible that the out bblocks already have in_stack assigned, and
2029          * the in_stacks differ. In this case, we will store to all the different 
2030          * in_stacks.
2031          */
2032
2033         found = TRUE;
2034         bindex = 0;
2035         while (found) {
2036                 /* Find a bblock which has a different in_stack */
2037                 found = FALSE;
2038                 while (bindex < bb->out_count) {
2039                         outb = bb->out_bb [bindex];
2040                         /* exception handlers are linked, but they should not be considered for stack args */
2041                         if (outb->flags & BB_EXCEPTION_HANDLER) {
2042                                 bindex++;
2043                                 continue;
2044                         }
2045                         if (outb->in_stack != locals) {
2046                                 /* 
2047                                  * Instead of storing sp [i] to locals [i], we need to store
2048                                  * locals [i] to <new locals>[i], since the sp [i] tree can't
2049                                  * be shared between trees.
2050                                  */
2051                                 for (i = 0; i < count; ++i)
2052                                         mono_add_varcopy_to_end (cfg, bb, locals [i]->inst_c0, outb->in_stack [i]->inst_c0);
2053                                 locals = outb->in_stack;
2054                                 found = TRUE;
2055                                 break;
2056                         }
2057                         bindex ++;
2058                 }
2059         }
2060         
2061         return 0;
2062 }
2063
2064 static int
2065 ret_type_to_call_opcode (MonoType *type, int calli, int virt)
2066 {
2067         if (type->byref)
2068                 return calli? OP_CALL_REG: virt? CEE_CALLVIRT: CEE_CALL;
2069
2070 handle_enum:
2071         switch (type->type) {
2072         case MONO_TYPE_VOID:
2073                 return calli? OP_VOIDCALL_REG: virt? OP_VOIDCALLVIRT: OP_VOIDCALL;
2074         case MONO_TYPE_I1:
2075         case MONO_TYPE_U1:
2076         case MONO_TYPE_BOOLEAN:
2077         case MONO_TYPE_I2:
2078         case MONO_TYPE_U2:
2079         case MONO_TYPE_CHAR:
2080         case MONO_TYPE_I4:
2081         case MONO_TYPE_U4:
2082                 return calli? OP_CALL_REG: virt? CEE_CALLVIRT: CEE_CALL;
2083         case MONO_TYPE_I:
2084         case MONO_TYPE_U:
2085         case MONO_TYPE_PTR:
2086         case MONO_TYPE_FNPTR:
2087                 return calli? OP_CALL_REG: virt? CEE_CALLVIRT: CEE_CALL;
2088         case MONO_TYPE_CLASS:
2089         case MONO_TYPE_STRING:
2090         case MONO_TYPE_OBJECT:
2091         case MONO_TYPE_SZARRAY:
2092         case MONO_TYPE_ARRAY:    
2093                 return calli? OP_CALL_REG: virt? CEE_CALLVIRT: CEE_CALL;
2094         case MONO_TYPE_I8:
2095         case MONO_TYPE_U8:
2096                 return calli? OP_LCALL_REG: virt? OP_LCALLVIRT: OP_LCALL;
2097         case MONO_TYPE_R4:
2098         case MONO_TYPE_R8:
2099                 return calli? OP_FCALL_REG: virt? OP_FCALLVIRT: OP_FCALL;
2100         case MONO_TYPE_VALUETYPE:
2101                 if (type->data.klass->enumtype) {
2102                         type = type->data.klass->enum_basetype;
2103                         goto handle_enum;
2104                 } else
2105                         return calli? OP_VCALL_REG: virt? OP_VCALLVIRT: OP_VCALL;
2106         case MONO_TYPE_TYPEDBYREF:
2107                 return calli? OP_VCALL_REG: virt? OP_VCALLVIRT: OP_VCALL;
2108         case MONO_TYPE_GENERICINST:
2109                 type = &type->data.generic_class->container_class->byval_arg;
2110                 goto handle_enum;
2111         default:
2112                 g_error ("unknown type 0x%02x in ret_type_to_call_opcode", type->type);
2113         }
2114         return -1;
2115 }
2116
2117 void
2118 mono_create_jump_table (MonoCompile *cfg, MonoInst *label, MonoBasicBlock **bbs, int num_blocks)
2119 {
2120         MonoJumpInfo *ji = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfo));
2121         MonoJumpInfoBBTable *table;
2122
2123         table = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfoBBTable));
2124         table->table = bbs;
2125         table->table_size = num_blocks;
2126         
2127         ji->ip.label = label;
2128         ji->type = MONO_PATCH_INFO_SWITCH;
2129         ji->data.table = table;
2130         ji->next = cfg->patch_info;
2131         cfg->patch_info = ji;
2132 }
2133
2134 static void
2135 mono_save_token_info (MonoCompile *cfg, MonoImage *image, guint32 token, gpointer key)
2136 {
2137         if (cfg->compile_aot) {
2138                 MonoJumpInfoToken *jump_info_token = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoToken));
2139                 jump_info_token->image = image;
2140                 jump_info_token->token = token;
2141                 g_hash_table_insert (cfg->token_info_hash, key, jump_info_token);
2142         }
2143 }
2144
2145 /*
2146  * When we add a tree of instructions, we need to ensure the instructions currently
2147  * on the stack are executed before (like, if we load a value from a local).
2148  * We ensure this by saving the currently loaded values to temps and rewriting the
2149  * instructions to load the values.
2150  * This is not done for opcodes that terminate a basic block (because it's handled already
2151  * by handle_stack_args ()) and for opcodes that can't change values, like POP.
2152  */
2153 static void
2154 handle_loaded_temps (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst **stack, MonoInst **sp)
2155 {
2156         MonoInst *load, *store, *temp, *ins;
2157
2158         while (stack < sp) {
2159                 ins = *stack;
2160                 /* handle also other constants */
2161                 if ((ins->opcode != OP_ICONST) &&
2162                     /* temps never get written to again, so we can safely avoid duplicating them */
2163                     !(ins->ssa_op == MONO_SSA_LOAD && ins->inst_i0->opcode == OP_LOCAL && ins->inst_i0->flags & MONO_INST_IS_TEMP)) {
2164                         temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
2165                         temp->flags |= MONO_INST_IS_TEMP;
2166                         NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
2167                         store->cil_code = ins->cil_code;
2168                         if (store->opcode == CEE_STOBJ) {
2169                                 NEW_TEMPLOADA (cfg, store, temp->inst_c0);
2170                                 handle_stobj (cfg, bblock, store, ins, ins->cil_code, temp->klass, FALSE, FALSE, FALSE);
2171                         } else
2172                                 MONO_ADD_INS (bblock, store);
2173                         NEW_TEMPLOAD (cfg, load, temp->inst_c0);
2174                         load->cil_code = ins->cil_code;
2175                         *stack = load;
2176                 }
2177                 stack++;
2178         }
2179 }
2180
2181 /*
2182  * target_type_is_incompatible:
2183  * @cfg: MonoCompile context
2184  *
2185  * Check that the item @arg on the evaluation stack can be stored
2186  * in the target type (can be a local, or field, etc).
2187  * The cfg arg can be used to check if we need verification or just
2188  * validity checks.
2189  *
2190  * Returns: non-0 value if arg can't be stored on a target.
2191  */
2192 static int
2193 target_type_is_incompatible (MonoCompile *cfg, MonoType *target, MonoInst *arg)
2194 {
2195         MonoType *simple_type;
2196         MonoClass *klass;
2197
2198         if (target->byref) {
2199                 /* FIXME: check that the pointed to types match */
2200                 if (arg->type == STACK_MP)
2201                         return arg->klass != mono_class_from_mono_type (target);
2202                 if (arg->type == STACK_PTR)
2203                         return 0;
2204                 return 1;
2205         }
2206         simple_type = mono_type_get_underlying_type (target);
2207         switch (simple_type->type) {
2208         case MONO_TYPE_VOID:
2209                 return 1;
2210         case MONO_TYPE_I1:
2211         case MONO_TYPE_U1:
2212         case MONO_TYPE_BOOLEAN:
2213         case MONO_TYPE_I2:
2214         case MONO_TYPE_U2:
2215         case MONO_TYPE_CHAR:
2216         case MONO_TYPE_I4:
2217         case MONO_TYPE_U4:
2218                 if (arg->type != STACK_I4 && arg->type != STACK_PTR)
2219                         return 1;
2220                 return 0;
2221         case MONO_TYPE_PTR:
2222                 /* STACK_MP is needed when setting pinned locals */
2223                 if (arg->type != STACK_I4 && arg->type != STACK_PTR && arg->type != STACK_MP)
2224                         return 1;
2225                 return 0;
2226         case MONO_TYPE_I:
2227         case MONO_TYPE_U:
2228         case MONO_TYPE_FNPTR:
2229                 if (arg->type != STACK_I4 && arg->type != STACK_PTR)
2230                         return 1;
2231                 return 0;
2232         case MONO_TYPE_OBJECT:
2233                 if (arg->type != STACK_OBJ)
2234                         return 1;
2235                 return 0;
2236         case MONO_TYPE_STRING:
2237                 if (arg->type != STACK_OBJ)
2238                         return 1;
2239                 /* ldnull has arg->klass unset */
2240                 /*if (arg->klass && arg->klass != mono_defaults.string_class) {
2241                         G_BREAKPOINT ();
2242                         return 1;
2243                 }*/
2244                 return 0;
2245         case MONO_TYPE_CLASS:
2246         case MONO_TYPE_SZARRAY:
2247         case MONO_TYPE_ARRAY:    
2248                 if (arg->type != STACK_OBJ)
2249                         return 1;
2250                 /* FIXME: check type compatibility */
2251                 return 0;
2252         case MONO_TYPE_I8:
2253         case MONO_TYPE_U8:
2254                 if (arg->type != STACK_I8)
2255                         return 1;
2256                 return 0;
2257         case MONO_TYPE_R4:
2258         case MONO_TYPE_R8:
2259                 if (arg->type != STACK_R8)
2260                         return 1;
2261                 return 0;
2262         case MONO_TYPE_VALUETYPE:
2263                 if (arg->type != STACK_VTYPE)
2264                         return 1;
2265                 klass = mono_class_from_mono_type (simple_type);
2266                 if (klass != arg->klass)
2267                         return 1;
2268                 return 0;
2269         case MONO_TYPE_TYPEDBYREF:
2270                 if (arg->type != STACK_VTYPE)
2271                         return 1;
2272                 klass = mono_class_from_mono_type (simple_type);
2273                 if (klass != arg->klass)
2274                         return 1;
2275                 return 0;
2276         case MONO_TYPE_GENERICINST:
2277                 if (mono_type_generic_inst_is_valuetype (simple_type)) {
2278                         klass = mono_class_from_mono_type (simple_type);
2279                         if (klass->enumtype)
2280                                 return target_type_is_incompatible (cfg, klass->enum_basetype, arg);
2281                         if (arg->type != STACK_VTYPE)
2282                                 return 1;
2283                         if (klass != arg->klass)
2284                                 return 1;
2285                         return 0;
2286                 } else {
2287                         if (arg->type != STACK_OBJ)
2288                                 return 1;
2289                         /* FIXME: check type compatibility */
2290                         return 0;
2291                 }
2292         default:
2293                 g_error ("unknown type 0x%02x in target_type_is_incompatible", simple_type->type);
2294         }
2295         return 1;
2296 }
2297
2298 /*
2299  * Prepare arguments for passing to a function call.
2300  * Return a non-zero value if the arguments can't be passed to the given
2301  * signature.
2302  * The type checks are not yet complete and some conversions may need
2303  * casts on 32 or 64 bit architectures.
2304  *
2305  * FIXME: implement this using target_type_is_incompatible ()
2306  */
2307 static int
2308 check_call_signature (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args)
2309 {
2310         MonoType *simple_type;
2311         int i;
2312
2313         if (sig->hasthis) {
2314                 if (args [0]->type != STACK_OBJ && args [0]->type != STACK_MP && args [0]->type != STACK_PTR)
2315                         return 1;
2316                 args++;
2317         }
2318         for (i = 0; i < sig->param_count; ++i) {
2319                 if (sig->params [i]->byref) {
2320                         if (args [i]->type != STACK_MP && args [i]->type != STACK_PTR)
2321                                 return 1;
2322                         continue;
2323                 }
2324                 simple_type = sig->params [i];
2325 handle_enum:
2326                 switch (simple_type->type) {
2327                 case MONO_TYPE_VOID:
2328                         return 1;
2329                         continue;
2330                 case MONO_TYPE_I1:
2331                 case MONO_TYPE_U1:
2332                 case MONO_TYPE_BOOLEAN:
2333                 case MONO_TYPE_I2:
2334                 case MONO_TYPE_U2:
2335                 case MONO_TYPE_CHAR:
2336                 case MONO_TYPE_I4:
2337                 case MONO_TYPE_U4:
2338                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR)
2339                                 return 1;
2340                         continue;
2341                 case MONO_TYPE_I:
2342                 case MONO_TYPE_U:
2343                 case MONO_TYPE_PTR:
2344                 case MONO_TYPE_FNPTR:
2345                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR && args [i]->type != STACK_MP && args [i]->type != STACK_OBJ)
2346                                 return 1;
2347                         continue;
2348                 case MONO_TYPE_CLASS:
2349                 case MONO_TYPE_STRING:
2350                 case MONO_TYPE_OBJECT:
2351                 case MONO_TYPE_SZARRAY:
2352                 case MONO_TYPE_ARRAY:    
2353                         if (args [i]->type != STACK_OBJ)
2354                                 return 1;
2355                         continue;
2356                 case MONO_TYPE_I8:
2357                 case MONO_TYPE_U8:
2358                         if (args [i]->type != STACK_I8)
2359                                 return 1;
2360                         continue;
2361                 case MONO_TYPE_R4:
2362                 case MONO_TYPE_R8:
2363                         if (args [i]->type != STACK_R8)
2364                                 return 1;
2365                         continue;
2366                 case MONO_TYPE_VALUETYPE:
2367                         if (simple_type->data.klass->enumtype) {
2368                                 simple_type = simple_type->data.klass->enum_basetype;
2369                                 goto handle_enum;
2370                         }
2371                         if (args [i]->type != STACK_VTYPE)
2372                                 return 1;
2373                         continue;
2374                 case MONO_TYPE_TYPEDBYREF:
2375                         if (args [i]->type != STACK_VTYPE)
2376                                 return 1;
2377                         continue;
2378                 case MONO_TYPE_GENERICINST:
2379                         simple_type = &simple_type->data.generic_class->container_class->byval_arg;
2380                         goto handle_enum;
2381
2382                 default:
2383                         g_error ("unknown type 0x%02x in check_call_signature",
2384                                  simple_type->type);
2385                 }
2386         }
2387         return 0;
2388 }
2389
2390 inline static int
2391 mono_spill_call (MonoCompile *cfg, MonoBasicBlock *bblock, MonoCallInst *call, MonoMethodSignature *sig, gboolean ret_object, 
2392                  const guint8 *ip, gboolean to_end)
2393 {
2394         MonoInst *temp, *store, *ins = (MonoInst*)call;
2395         MonoType *ret = sig->ret;
2396
2397         if (!MONO_TYPE_IS_VOID (ret) || ret_object) {
2398                 if (ret_object) {
2399                         call->inst.type = STACK_OBJ;
2400                         call->inst.opcode = CEE_CALL;
2401                         temp = mono_compile_create_var (cfg, &mono_defaults.string_class->byval_arg, OP_LOCAL);
2402                 } else {
2403                         type_to_eval_stack_type (ret, ins);
2404                         temp = mono_compile_create_var (cfg, ret, OP_LOCAL);
2405                 }
2406                 
2407                 temp->flags |= MONO_INST_IS_TEMP;
2408
2409                 if (MONO_TYPE_ISSTRUCT (ret)) {
2410                         MonoInst *loada, *dummy_store;
2411
2412                         /* 
2413                          * Emit a dummy store to the local holding the result so the
2414                          * liveness info remains correct.
2415                          */
2416                         NEW_DUMMY_STORE (cfg, dummy_store, temp->inst_c0);
2417                         if (to_end)
2418                                 mono_add_ins_to_end (bblock, dummy_store);
2419                         else
2420                                 MONO_ADD_INS (bblock, dummy_store);
2421
2422                         /* we use this to allocate native sized structs */
2423                         temp->backend.is_pinvoke = sig->pinvoke;
2424
2425                         NEW_TEMPLOADA (cfg, loada, temp->inst_c0);
2426                         if (call->inst.opcode == OP_VCALL)
2427                                 ins->inst_left = loada;
2428                         else
2429                                 ins->inst_right = loada; /* a virtual or indirect call */
2430
2431                         if (to_end)
2432                                 mono_add_ins_to_end (bblock, ins);
2433                         else
2434                                 MONO_ADD_INS (bblock, ins);
2435                 } else {
2436                         NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
2437                         store->cil_code = ip;
2438                         if (to_end)
2439                                 mono_add_ins_to_end (bblock, store);
2440                         else
2441                                 MONO_ADD_INS (bblock, store);
2442                 }
2443                 return temp->inst_c0;
2444         } else {
2445                 if (to_end)
2446                         mono_add_ins_to_end (bblock, ins);
2447                 else
2448                         MONO_ADD_INS (bblock, ins);
2449                 return -1;
2450         }
2451 }
2452
2453 inline static MonoCallInst *
2454 mono_emit_call_args (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethodSignature *sig, 
2455                      MonoInst **args, int calli, int virtual, const guint8 *ip, gboolean to_end)
2456 {
2457         MonoCallInst *call;
2458         MonoInst *arg;
2459
2460         MONO_INST_NEW_CALL (cfg, call, ret_type_to_call_opcode (sig->ret, calli, virtual));
2461
2462 #ifdef MONO_ARCH_SOFT_FLOAT
2463         /* we need to convert the r4 value to an int value */
2464         {
2465                 int i;
2466                 for (i = 0; i < sig->param_count; ++i) {
2467                         if (!sig->params [i]->byref && sig->params [i]->type == MONO_TYPE_R4) {
2468                                 MonoInst *iargs [1];
2469                                 int temp;
2470                                 iargs [0] = args [i + sig->hasthis];
2471
2472                                 temp = mono_emit_jit_icall (cfg, bblock, mono_fload_r4_arg, iargs, ip);
2473                                 NEW_TEMPLOAD (cfg, arg, temp);
2474                                 args [i + sig->hasthis] = arg;
2475                         }
2476                 }
2477         }
2478 #endif
2479
2480         call->inst.cil_code = ip;
2481         call->args = args;
2482         call->signature = sig;
2483         call = mono_arch_call_opcode (cfg, bblock, call, virtual);
2484         type_to_eval_stack_type (sig->ret, &call->inst);
2485
2486         for (arg = call->out_args; arg;) {
2487                 MonoInst *narg = arg->next;
2488                 arg->next = NULL;
2489                 if (!arg->cil_code)
2490                         arg->cil_code = ip;
2491                 if (to_end)
2492                         mono_add_ins_to_end (bblock, arg);
2493                 else
2494                         MONO_ADD_INS (bblock, arg);
2495                 arg = narg;
2496         }
2497         return call;
2498 }
2499
2500 inline static int
2501 mono_emit_calli (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethodSignature *sig, 
2502                  MonoInst **args, MonoInst *addr, const guint8 *ip)
2503 {
2504         MonoCallInst *call = mono_emit_call_args (cfg, bblock, sig, args, TRUE, FALSE, ip, FALSE);
2505
2506         call->inst.inst_i0 = addr;
2507
2508         return mono_spill_call (cfg, bblock, call, sig, FALSE, ip, FALSE);
2509 }
2510
2511 static MonoCallInst*
2512 mono_emit_method_call_full (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *method, MonoMethodSignature *sig,
2513                        MonoInst **args, const guint8 *ip, MonoInst *this, gboolean to_end)
2514 {
2515         gboolean virtual = this != NULL;
2516         MonoCallInst *call;
2517
2518         call = mono_emit_call_args (cfg, bblock, sig, args, FALSE, virtual, ip, to_end);
2519
2520         if (this && sig->hasthis && 
2521             (method->klass->marshalbyref || method->klass == mono_defaults.object_class) && 
2522             !(method->flags & METHOD_ATTRIBUTE_VIRTUAL) && !MONO_CHECK_THIS (this)) {
2523                 call->method = mono_marshal_get_remoting_invoke_with_check (method);
2524         } else {
2525                 call->method = method;
2526         }
2527         call->inst.flags |= MONO_INST_HAS_METHOD;
2528         call->inst.inst_left = this;
2529
2530         if (call->method->klass->flags & TYPE_ATTRIBUTE_INTERFACE)
2531                 /* Needed by the code generated in inssel.brg */
2532                 mono_get_got_var (cfg);
2533
2534         return call;
2535 }
2536
2537 static MonoCallInst*
2538 mono_emit_method_call (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *method, MonoMethodSignature *sig,
2539                        MonoInst **args, const guint8 *ip, MonoInst *this)
2540 {
2541         return mono_emit_method_call_full (cfg, bblock, method, sig, args, ip, this, FALSE);
2542 }
2543
2544 inline static int
2545 mono_emit_method_call_spilled (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *method,  
2546                        MonoMethodSignature *signature, MonoInst **args, const guint8 *ip, MonoInst *this)
2547 {
2548         MonoCallInst *call = mono_emit_method_call (cfg, bblock, method, signature, args, ip, this);
2549
2550         return mono_spill_call (cfg, bblock, call, signature, method->string_ctor, ip, FALSE);
2551 }
2552
2553 inline static int
2554 mono_emit_method_call_spilled_full (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *method,  
2555                        MonoMethodSignature *signature, MonoInst **args, const guint8 *ip, MonoInst *this,
2556                        gboolean ret_object, gboolean to_end)
2557 {
2558         MonoCallInst *call = mono_emit_method_call_full (cfg, bblock, method, signature, args, ip, this, to_end);
2559
2560         return mono_spill_call (cfg, bblock, call, signature, ret_object, ip, to_end);
2561 }
2562
2563 inline static int
2564 mono_emit_native_call (MonoCompile *cfg, MonoBasicBlock *bblock, gconstpointer func, MonoMethodSignature *sig,
2565                        MonoInst **args, const guint8 *ip, gboolean ret_object, gboolean to_end)
2566 {
2567         MonoCallInst *call;
2568
2569         g_assert (sig);
2570
2571         call = mono_emit_call_args (cfg, bblock, sig, args, FALSE, FALSE, ip, to_end);
2572         call->fptr = func;
2573
2574         return mono_spill_call (cfg, bblock, call, sig, ret_object, ip, to_end);
2575 }
2576
2577 inline static int
2578 mono_emit_jit_icall (MonoCompile *cfg, MonoBasicBlock *bblock, gconstpointer func, MonoInst **args, const guint8 *ip)
2579 {
2580         MonoJitICallInfo *info = mono_find_jit_icall_by_addr (func);
2581         
2582         if (!info) {
2583                 g_warning ("unregistered JIT ICall");
2584                 g_assert_not_reached ();
2585         }
2586
2587         return mono_emit_native_call (cfg, bblock, mono_icall_get_wrapper (info), info->sig, args, ip, FALSE, FALSE);
2588 }
2589
2590 static void
2591 mono_emulate_opcode (MonoCompile *cfg, MonoInst *tree, MonoInst **iargs, MonoJitICallInfo *info)
2592 {
2593         MonoInst *ins, *temp = NULL, *store, *load, *begin;
2594         MonoInst *last_arg = NULL;
2595         int nargs;
2596         MonoCallInst *call;
2597
2598         //g_print ("emulating: ");
2599         //mono_print_tree_nl (tree);
2600         MONO_INST_NEW_CALL (cfg, call, ret_type_to_call_opcode (info->sig->ret, FALSE, FALSE));
2601         ins = (MonoInst*)call;
2602         
2603         call->inst.cil_code = tree->cil_code;
2604         call->args = iargs;
2605         call->signature = info->sig;
2606
2607         call = mono_arch_call_opcode (cfg, cfg->cbb, call, FALSE);
2608
2609         if (!MONO_TYPE_IS_VOID (info->sig->ret)) {
2610                 temp = mono_compile_create_var (cfg, info->sig->ret, OP_LOCAL);
2611                 temp->flags |= MONO_INST_IS_TEMP;
2612                 NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
2613                 store->cil_code = tree->cil_code;
2614         } else {
2615                 store = ins;
2616         }
2617
2618         nargs = info->sig->param_count + info->sig->hasthis;
2619
2620         for (last_arg = call->out_args; last_arg && last_arg->next; last_arg = last_arg->next) ;
2621
2622         if (nargs)
2623                 last_arg->next = store;
2624
2625         if (nargs)
2626                 begin = call->out_args;
2627         else
2628                 begin = store;
2629
2630         if (cfg->prev_ins) {
2631                 /* 
2632                  * This assumes that that in a tree, emulate_opcode is called for a
2633                  * node before it is called for its children. dec_foreach needs to
2634                  * take this into account.
2635                  */
2636                 store->next = cfg->prev_ins->next;
2637                 cfg->prev_ins->next = begin;
2638         } else {
2639                 store->next = cfg->cbb->code;
2640                 cfg->cbb->code = begin;
2641         }
2642
2643         call->fptr = mono_icall_get_wrapper (info);
2644
2645         if (!MONO_TYPE_IS_VOID (info->sig->ret)) {
2646                 NEW_TEMPLOAD (cfg, load, temp->inst_c0);
2647                 *tree = *load;
2648         }
2649 }
2650
2651 static MonoMethodSignature *
2652 mono_get_array_new_va_signature (int arity)
2653 {
2654         static GHashTable *sighash = NULL;
2655         MonoMethodSignature *res;
2656         int i;
2657
2658         mono_jit_lock ();
2659         if (!sighash) {
2660                 sighash = g_hash_table_new (NULL, NULL);
2661         }
2662         else if ((res = g_hash_table_lookup (sighash, GINT_TO_POINTER (arity)))) {
2663                 mono_jit_unlock ();
2664                 return res;
2665         }
2666
2667         res = mono_metadata_signature_alloc (mono_defaults.corlib, arity + 1);
2668
2669         res->pinvoke = 1;
2670 #ifdef MONO_ARCH_VARARG_ICALLS
2671         /* Only set this only some archs since not all backends can handle varargs+pinvoke */
2672         res->call_convention = MONO_CALL_VARARG;
2673 #endif
2674
2675 #ifdef PLATFORM_WIN32
2676         res->call_convention = MONO_CALL_C;
2677 #endif
2678
2679         res->params [0] = &mono_defaults.int_class->byval_arg;  
2680         for (i = 0; i < arity; i++)
2681                 res->params [i + 1] = &mono_defaults.int_class->byval_arg;
2682
2683         res->ret = &mono_defaults.int_class->byval_arg;
2684
2685         g_hash_table_insert (sighash, GINT_TO_POINTER (arity), res);
2686         mono_jit_unlock ();
2687
2688         return res;
2689 }
2690
2691 #ifdef MONO_ARCH_SOFT_FLOAT
2692 static void
2693 handle_store_float (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *ptr, MonoInst *val, const unsigned char *ip)
2694 {
2695         MonoInst *iargs [2];
2696         iargs [0] = val;
2697         iargs [1] = ptr;
2698
2699         mono_emit_jit_icall (cfg, bblock, mono_fstore_r4, iargs, ip);
2700 }
2701
2702 static int
2703 handle_load_float (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *ptr, const unsigned char *ip)
2704 {
2705         MonoInst *iargs [1];
2706         iargs [0] = ptr;
2707
2708         return mono_emit_jit_icall (cfg, bblock, mono_fload_r4, iargs, ip);
2709 }
2710
2711 #define LDLOC_SOFT_FLOAT(cfg,ins,idx,ip) do {\
2712                 if (header->locals [(idx)]->type == MONO_TYPE_R4 && !header->locals [(idx)]->byref) {   \
2713                         int temp;       \
2714                         NEW_LOCLOADA (cfg, (ins), (idx));       \
2715                         temp = handle_load_float (cfg, bblock, (ins), (ip));    \
2716                         NEW_TEMPLOAD (cfg, (ins), temp);        \
2717                 }       \
2718         } while (0)
2719 #define STLOC_SOFT_FLOAT(cfg,ins,idx,ip) do {\
2720                 if (header->locals [(idx)]->type == MONO_TYPE_R4 && !header->locals [(idx)]->byref) {   \
2721                         int temp;       \
2722                         NEW_LOCLOADA (cfg, (ins), (idx));       \
2723                         handle_store_float (cfg, bblock, (ins), *sp, (ip));     \
2724                         MONO_INST_NEW (cfg, (ins), OP_NOP);     \
2725                 }       \
2726         } while (0)
2727 #define LDARG_SOFT_FLOAT(cfg,ins,idx,ip) do {\
2728                 if (param_types [(idx)]->type == MONO_TYPE_R4 && !param_types [(idx)]->byref) { \
2729                         int temp;       \
2730                         NEW_ARGLOADA (cfg, (ins), (idx));       \
2731                         temp = handle_load_float (cfg, bblock, (ins), (ip));    \
2732                         NEW_TEMPLOAD (cfg, (ins), temp);        \
2733                 }       \
2734         } while (0)
2735 #define STARG_SOFT_FLOAT(cfg,ins,idx,ip) do {\
2736                 if (param_types [(idx)]->type == MONO_TYPE_R4 && !param_types [(idx)]->byref) { \
2737                         int temp;       \
2738                         NEW_ARGLOADA (cfg, (ins), (idx));       \
2739                         handle_store_float (cfg, bblock, (ins), *sp, (ip));     \
2740                         MONO_INST_NEW (cfg, (ins), OP_NOP);     \
2741                 }       \
2742         } while (0)
2743 #else
2744 #define LDLOC_SOFT_FLOAT(cfg,ins,idx,ip)
2745 #define STLOC_SOFT_FLOAT(cfg,ins,idx,ip)
2746 #define LDARG_SOFT_FLOAT(cfg,ins,idx,ip)
2747 #define STARG_SOFT_FLOAT(cfg,ins,idx,ip)
2748 #endif
2749
2750 static MonoMethod*
2751 get_memcpy_method (void)
2752 {
2753         static MonoMethod *memcpy_method = NULL;
2754         if (!memcpy_method) {
2755                 memcpy_method = mono_class_get_method_from_name (mono_defaults.string_class, "memcpy", 3);
2756                 if (!memcpy_method)
2757                         g_error ("Old corlib found. Install a new one");
2758         }
2759         return memcpy_method;
2760 }
2761
2762 static void
2763 handle_stobj (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *dest, MonoInst *src, const unsigned char *ip, MonoClass *klass, gboolean to_end, gboolean native, gboolean write_barrier) {
2764         MonoInst *iargs [3];
2765         int n;
2766         guint32 align = 0;
2767         MonoMethod *memcpy_method;
2768
2769         g_assert (klass);
2770         /*
2771          * This check breaks with spilled vars... need to handle it during verification anyway.
2772          * g_assert (klass && klass == src->klass && klass == dest->klass);
2773          */
2774
2775         if (native)
2776                 n = mono_class_native_size (klass, &align);
2777         else
2778                 n = mono_class_value_size (klass, &align);
2779
2780 #if HAVE_WRITE_BARRIERS
2781         /* if native is true there should be no references in the struct */
2782         if (write_barrier && klass->has_references && !native) {
2783                 iargs [0] = dest;
2784                 iargs [1] = src;
2785                 NEW_PCONST (cfg, iargs [2], klass);
2786
2787                 mono_emit_jit_icall (cfg, bblock, mono_value_copy, iargs, ip);
2788                 return;
2789         }
2790 #endif
2791
2792         /* FIXME: add write barrier handling */
2793         if ((cfg->opt & MONO_OPT_INTRINS) && !to_end && n <= sizeof (gpointer) * 5) {
2794                 MonoInst *inst;
2795                 if (dest->opcode == OP_LDADDR) {
2796                         /* Keep liveness info correct */
2797                         NEW_DUMMY_STORE (cfg, inst, dest->inst_i0->inst_c0);
2798                         MONO_ADD_INS (bblock, inst);
2799                 }
2800                 MONO_INST_NEW (cfg, inst, OP_MEMCPY);
2801                 inst->inst_left = dest;
2802                 inst->inst_right = src;
2803                 inst->cil_code = ip;
2804                 inst->backend.size = n;
2805                 MONO_ADD_INS (bblock, inst);
2806                 return;
2807         }
2808         iargs [0] = dest;
2809         iargs [1] = src;
2810         NEW_ICONST (cfg, iargs [2], n);
2811
2812         memcpy_method = get_memcpy_method ();
2813         mono_emit_method_call_spilled_full (cfg, bblock, memcpy_method, memcpy_method->signature, iargs, ip, NULL, FALSE, to_end);
2814 }
2815
2816 static MonoMethod*
2817 get_memset_method (void)
2818 {
2819         static MonoMethod *memset_method = NULL;
2820         if (!memset_method) {
2821                 memset_method = mono_class_get_method_from_name (mono_defaults.string_class, "memset", 3);
2822                 if (!memset_method)
2823                         g_error ("Old corlib found. Install a new one");
2824         }
2825         return memset_method;
2826 }
2827
2828 static void
2829 handle_initobj (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *dest, const guchar *ip, MonoClass *klass, MonoInst **stack_start, MonoInst **sp)
2830 {
2831         MonoInst *iargs [3];
2832         MonoInst *ins, *zero_int32;
2833         int n;
2834         MonoMethod *memset_method;
2835
2836         NEW_ICONST (cfg, zero_int32, 0);
2837
2838         mono_class_init (klass);
2839         n = mono_class_value_size (klass, NULL);
2840         MONO_INST_NEW (cfg, ins, 0);
2841         ins->cil_code = ip;
2842         ins->inst_left = dest;
2843         ins->inst_right = zero_int32;
2844         switch (n) {
2845         case 1:
2846                 ins->opcode = CEE_STIND_I1;
2847                 MONO_ADD_INS (bblock, ins);
2848                 break;
2849         case 2:
2850                 ins->opcode = CEE_STIND_I2;
2851                 MONO_ADD_INS (bblock, ins);
2852                 break;
2853         case 4:
2854                 ins->opcode = CEE_STIND_I4;
2855                 MONO_ADD_INS (bblock, ins);
2856                 break;
2857         default:
2858                 if (n <= sizeof (gpointer) * 5) {
2859                         ins->opcode = OP_MEMSET;
2860                         ins->inst_imm = 0;
2861                         ins->backend.size = n;
2862                         MONO_ADD_INS (bblock, ins);
2863                         break;
2864                 }
2865                 memset_method = get_memset_method ();
2866                 handle_loaded_temps (cfg, bblock, stack_start, sp);
2867                 iargs [0] = dest;
2868                 NEW_ICONST (cfg, iargs [1], 0);
2869                 NEW_ICONST (cfg, iargs [2], n);
2870                 mono_emit_method_call_spilled (cfg, bblock, memset_method, memset_method->signature, iargs, ip, NULL);
2871                 break;
2872         }
2873 }
2874
2875 static int
2876 handle_alloc (MonoCompile *cfg, MonoBasicBlock *bblock, MonoClass *klass, gboolean for_box, const guchar *ip)
2877 {
2878         MonoInst *iargs [2];
2879         void *alloc_ftn;
2880
2881         if (cfg->opt & MONO_OPT_SHARED) {
2882                 NEW_DOMAINCONST (cfg, iargs [0]);
2883                 NEW_CLASSCONST (cfg, iargs [1], klass);
2884
2885                 alloc_ftn = mono_object_new;
2886         } else if (cfg->compile_aot && bblock->out_of_line && klass->type_token && klass->image == mono_defaults.corlib) {
2887                 /* This happens often in argument checking code, eg. throw new FooException... */
2888                 /* Avoid relocations by calling a helper function specialized to mscorlib */
2889                 NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (klass->type_token));
2890                 return mono_emit_jit_icall (cfg, bblock, mono_helper_newobj_mscorlib, iargs, ip);
2891         } else {
2892                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
2893                 gboolean pass_lw;
2894
2895                 alloc_ftn = mono_class_get_allocation_ftn (vtable, for_box, &pass_lw);
2896                 if (pass_lw) {
2897                         guint32 lw = vtable->klass->instance_size;
2898                         lw = ((lw + (sizeof (gpointer) - 1)) & ~(sizeof (gpointer) - 1)) / sizeof (gpointer);
2899                         NEW_ICONST (cfg, iargs [0], lw);
2900                         NEW_VTABLECONST (cfg, iargs [1], vtable);
2901                 }
2902                 else
2903                         NEW_VTABLECONST (cfg, iargs [0], vtable);
2904         }
2905
2906         return mono_emit_jit_icall (cfg, bblock, alloc_ftn, iargs, ip);
2907 }
2908
2909 /**
2910  * Handles unbox of a Nullable<T>, returning a temp variable
2911  * where the result is stored
2912  */
2913 static int
2914 handle_unbox_nullable (MonoCompile* cfg, MonoBasicBlock* bblock, MonoInst* val, const guchar *ip, MonoClass* klass)
2915 {
2916        MonoMethod* method = mono_class_get_method_from_name (klass, "Unbox", 1);
2917        return mono_emit_method_call_spilled (cfg, bblock, method, mono_method_signature (method), &val, ip, NULL);
2918         
2919 }
2920
2921
2922
2923 static MonoInst *
2924 handle_box (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *val, const guchar *ip, MonoClass *klass)
2925 {
2926         MonoInst *dest, *vtoffset, *add, *vstore;
2927         int temp;
2928
2929        if (mono_class_is_nullable (klass)) {
2930                MonoMethod* method = mono_class_get_method_from_name (klass, "Box", 1);
2931                temp = mono_emit_method_call_spilled (cfg, bblock, method, mono_method_signature (method), &val, ip, NULL);
2932                NEW_TEMPLOAD (cfg, dest, temp);
2933                return dest;
2934        }
2935
2936
2937         temp = handle_alloc (cfg, bblock, klass, TRUE, ip);
2938         NEW_TEMPLOAD (cfg, dest, temp);
2939         NEW_ICONST (cfg, vtoffset, sizeof (MonoObject));
2940         MONO_INST_NEW (cfg, add, OP_PADD);
2941         add->inst_left = dest;
2942         add->inst_right = vtoffset;
2943         add->cil_code = ip;
2944         add->klass = klass;
2945         MONO_INST_NEW (cfg, vstore, CEE_STIND_I);
2946         vstore->opcode = mono_type_to_stind (&klass->byval_arg);
2947         vstore->cil_code = ip;
2948         vstore->inst_left = add;
2949         vstore->inst_right = val;
2950
2951 #ifdef MONO_ARCH_SOFT_FLOAT
2952         if (vstore->opcode == CEE_STIND_R4) {
2953                 handle_store_float (cfg, bblock, add, val, ip);
2954         } else
2955 #endif
2956         if (vstore->opcode == CEE_STOBJ) {
2957                 handle_stobj (cfg, bblock, add, val, ip, klass, FALSE, FALSE, TRUE);
2958         } else
2959                 MONO_ADD_INS (bblock, vstore);
2960
2961         NEW_TEMPLOAD (cfg, dest, temp);
2962         return dest;
2963 }
2964
2965 static int
2966 handle_array_new (MonoCompile *cfg, MonoBasicBlock *bblock, int rank, MonoInst **sp, unsigned char *ip)
2967 {
2968         MonoMethodSignature *esig;
2969         char icall_name [256];
2970         char *name;
2971         MonoJitICallInfo *info;
2972
2973         /* Need to register the icall so it gets an icall wrapper */
2974         sprintf (icall_name, "ves_array_new_va_%d", rank);
2975
2976         mono_jit_lock ();
2977         info = mono_find_jit_icall_by_name (icall_name);
2978         if (info == NULL) {
2979                 esig = mono_get_array_new_va_signature (rank);
2980                 name = g_strdup (icall_name);
2981                 info = mono_register_jit_icall (mono_array_new_va, name, esig, FALSE);
2982
2983                 g_hash_table_insert (jit_icall_name_hash, name, name);
2984         }
2985         mono_jit_unlock ();
2986
2987         cfg->flags |= MONO_CFG_HAS_VARARGS;
2988
2989         /* FIXME: This uses info->sig, but it should use the signature of the wrapper */
2990         return mono_emit_native_call (cfg, bblock, mono_icall_get_wrapper (info), info->sig, sp, ip, TRUE, FALSE);
2991 }
2992
2993 static void
2994 mono_emit_load_got_addr (MonoCompile *cfg)
2995 {
2996         MonoInst *load, *store, *dummy_use;
2997         MonoInst *get_got;
2998
2999         if (!cfg->got_var || cfg->got_var_allocated)
3000                 return;
3001
3002         MONO_INST_NEW (cfg, get_got, OP_LOAD_GOTADDR);
3003         NEW_TEMPSTORE (cfg, store, cfg->got_var->inst_c0, get_got);
3004
3005         /* Add it to the start of the first bblock */
3006         if (cfg->bb_entry->code) {
3007                 store->next = cfg->bb_entry->code;
3008                 cfg->bb_entry->code = store;
3009         }
3010         else
3011                 MONO_ADD_INS (cfg->bb_entry, store);
3012
3013         cfg->got_var_allocated = TRUE;
3014
3015         /* 
3016          * Add a dummy use to keep the got_var alive, since real uses might
3017          * only be generated in the decompose or instruction selection phases.
3018          * Add it to end_bblock, so the variable's lifetime covers the whole
3019          * method.
3020          */
3021         NEW_TEMPLOAD (cfg, load, cfg->got_var->inst_c0);
3022         NEW_DUMMY_USE (cfg, dummy_use, load);
3023         MONO_ADD_INS (cfg->bb_exit, dummy_use);
3024 }
3025
3026 #define CODE_IS_STLOC(ip) (((ip) [0] >= CEE_STLOC_0 && (ip) [0] <= CEE_STLOC_3) || ((ip) [0] == CEE_STLOC_S))
3027
3028 static gboolean
3029 mini_class_is_system_array (MonoClass *klass)
3030 {
3031         if (klass->parent == mono_defaults.array_class)
3032                 return TRUE;
3033         else
3034                 return FALSE;
3035 }
3036
3037 static gboolean
3038 mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method)
3039 {
3040         MonoMethodHeader *header = mono_method_get_header (method);
3041         MonoMethodSignature *signature = mono_method_signature (method);
3042         MonoVTable *vtable;
3043         int i;
3044
3045 #ifdef MONO_ARCH_HAVE_LMF_OPS
3046         if (((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
3047                  (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) &&
3048             !MONO_TYPE_ISSTRUCT (signature->ret) && !mini_class_is_system_array (method->klass))
3049                 return TRUE;
3050 #endif
3051
3052         if ((method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
3053             (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
3054             (method->iflags & METHOD_IMPL_ATTRIBUTE_NOINLINING) ||
3055             (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) ||
3056             (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
3057             (method->klass->marshalbyref) ||
3058             !header || header->num_clauses ||
3059             /* fixme: why cant we inline valuetype returns? */
3060             MONO_TYPE_ISSTRUCT (signature->ret))
3061                 return FALSE;
3062
3063 #ifdef MONO_ARCH_SOFT_FLOAT
3064         /* this complicates things, fix later */
3065         if (signature->ret->type == MONO_TYPE_R4)
3066                 return FALSE;
3067 #endif
3068         /* its not worth to inline methods with valuetype arguments?? */
3069         for (i = 0; i < signature->param_count; i++) {
3070                 if (MONO_TYPE_ISSTRUCT (signature->params [i])) {
3071                         return FALSE;
3072                 }
3073 #ifdef MONO_ARCH_SOFT_FLOAT
3074                 /* this complicates things, fix later */
3075                 if (!signature->params [i]->byref && signature->params [i]->type == MONO_TYPE_R4)
3076                         return FALSE;
3077 #endif
3078         }
3079
3080         /*
3081          * if we can initialize the class of the method right away, we do,
3082          * otherwise we don't allow inlining if the class needs initialization,
3083          * since it would mean inserting a call to mono_runtime_class_init()
3084          * inside the inlined code
3085          */
3086         if (!(cfg->opt & MONO_OPT_SHARED)) {
3087                 vtable = mono_class_vtable (cfg->domain, method->klass);
3088                 if (method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) {
3089                         if (cfg->run_cctors) {
3090                                 /* This makes so that inline cannot trigger */
3091                                 /* .cctors: too many apps depend on them */
3092                                 /* running with a specific order... */
3093                                 if (! vtable->initialized)
3094                                         return FALSE;
3095                                 mono_runtime_class_init (vtable);
3096                         }
3097                 }
3098                 else if (!vtable->initialized && mono_class_needs_cctor_run (method->klass, NULL))
3099                         return FALSE;
3100         } else {
3101                 /* 
3102                  * If we're compiling for shared code
3103                  * the cctor will need to be run at aot method load time, for example,
3104                  * or at the end of the compilation of the inlining method.
3105                  */
3106                 if (mono_class_needs_cctor_run (method->klass, NULL) && !((method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT)))
3107                         return FALSE;
3108         }
3109         //if (!MONO_TYPE_IS_VOID (signature->ret)) return FALSE;
3110
3111         /*
3112          * CAS - do not inline methods with declarative security
3113          * Note: this has to be before any possible return TRUE;
3114          */
3115         if (mono_method_has_declsec (method))
3116                 return FALSE;
3117
3118         /* also consider num_locals? */
3119         if (getenv ("MONO_INLINELIMIT")) {
3120                 if (header->code_size < atoi (getenv ("MONO_INLINELIMIT"))) {
3121                         return TRUE;
3122                 }
3123         } else if (header->code_size < INLINE_LENGTH_LIMIT)
3124                 return TRUE;
3125
3126         return FALSE;
3127 }
3128
3129 static gboolean
3130 mini_field_access_needs_cctor_run (MonoCompile *cfg, MonoMethod *method, MonoVTable *vtable)
3131 {
3132         if (vtable->initialized && !cfg->compile_aot)
3133                 return FALSE;
3134
3135         if (vtable->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT)
3136                 return FALSE;
3137
3138         if (!mono_class_needs_cctor_run (vtable->klass, method))
3139                 return FALSE;
3140
3141         if (! (method->flags & METHOD_ATTRIBUTE_STATIC) && (vtable->klass == method->klass))
3142                 /* The initialization is already done before the method is called */
3143                 return FALSE;
3144
3145         return TRUE;
3146 }
3147
3148 static MonoInst*
3149 mini_get_ldelema_ins (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *cmethod, MonoInst **sp, unsigned char *ip, gboolean is_set)
3150 {
3151         int temp, rank;
3152         MonoInst *addr;
3153         MonoMethod *addr_method;
3154         int element_size;
3155
3156         rank = mono_method_signature (cmethod)->param_count - (is_set? 1: 0);
3157
3158         if (rank == 1) {
3159                 MONO_INST_NEW (cfg, addr, CEE_LDELEMA);
3160                 addr->inst_left = sp [0];
3161                 addr->inst_right = sp [1];
3162                 addr->cil_code = ip;
3163                 addr->type = STACK_MP;
3164                 addr->klass = cmethod->klass->element_class;
3165                 return addr;
3166         }
3167
3168         if (rank == 2 && (cfg->opt & MONO_OPT_INTRINS)) {
3169 #if defined(MONO_ARCH_EMULATE_MUL_DIV) && !defined(MONO_ARCH_NO_EMULATE_MUL)
3170                 /* OP_LDELEMA2D depends on OP_LMUL */
3171 #else
3172                 MonoInst *indexes;
3173                 NEW_GROUP (cfg, indexes, sp [1], sp [2]);
3174                 MONO_INST_NEW (cfg, addr, OP_LDELEMA2D);
3175                 addr->inst_left = sp [0];
3176                 addr->inst_right = indexes;
3177                 addr->cil_code = ip;
3178                 addr->type = STACK_MP;
3179                 addr->klass = cmethod->klass->element_class;
3180                 return addr;
3181 #endif
3182         }
3183
3184         element_size = mono_class_array_element_size (cmethod->klass->element_class);
3185         addr_method = mono_marshal_get_array_address (rank, element_size);
3186         temp = mono_emit_method_call_spilled (cfg, bblock, addr_method, addr_method->signature, sp, ip, NULL);
3187         NEW_TEMPLOAD (cfg, addr, temp);
3188         return addr;
3189
3190 }
3191
3192 static MonoJitICallInfo **emul_opcode_map = NULL;
3193
3194 MonoJitICallInfo *
3195 mono_find_jit_opcode_emulation (int opcode)
3196 {
3197         g_assert (opcode >= 0 && opcode <= OP_LAST);
3198         if  (emul_opcode_map)
3199                 return emul_opcode_map [opcode];
3200         else
3201                 return NULL;
3202 }
3203
3204 static int
3205 is_unsigned_regsize_type (MonoType *type)
3206 {
3207         switch (type->type) {
3208         case MONO_TYPE_U1:
3209         case MONO_TYPE_U2:
3210         case MONO_TYPE_U4:
3211 #if SIZEOF_VOID_P == 8
3212         /*case MONO_TYPE_U8: this requires different opcodes in inssel.brg */
3213 #endif
3214                 return TRUE;
3215         default:
3216                 return FALSE;
3217         }
3218 }
3219
3220 static MonoInst*
3221 mini_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
3222 {
3223         MonoInst *ins = NULL;
3224         
3225         static MonoClass *runtime_helpers_class = NULL;
3226         if (! runtime_helpers_class)
3227                 runtime_helpers_class = mono_class_from_name (mono_defaults.corlib,
3228                         "System.Runtime.CompilerServices", "RuntimeHelpers");
3229
3230         if (cmethod->klass == mono_defaults.string_class) {
3231                 if (strcmp (cmethod->name, "get_Chars") == 0) {
3232                         MONO_INST_NEW (cfg, ins, OP_GETCHR);
3233                         ins->inst_i0 = args [0];
3234                         ins->inst_i1 = args [1];
3235                         return ins;
3236                 } else if (strcmp (cmethod->name, "get_Length") == 0) {
3237                         MONO_INST_NEW (cfg, ins, OP_STRLEN);
3238                         ins->inst_i0 = args [0];
3239                         return ins;
3240                 } else if (strcmp (cmethod->name, "InternalSetChar") == 0) {
3241                         MonoInst *get_addr;
3242                         MONO_INST_NEW (cfg, get_addr, OP_STR_CHAR_ADDR);
3243                         get_addr->inst_i0 = args [0];
3244                         get_addr->inst_i1 = args [1];
3245                         MONO_INST_NEW (cfg, ins, CEE_STIND_I2);
3246                         ins->inst_i0 = get_addr;
3247                         ins->inst_i1 = args [2];
3248                         return ins;
3249                 } else 
3250                         return NULL;
3251         } else if (cmethod->klass == mono_defaults.object_class) {
3252                 if (strcmp (cmethod->name, "GetType") == 0) {
3253                         MONO_INST_NEW (cfg, ins, OP_GETTYPE);
3254                         ins->inst_i0 = args [0];
3255                         return ins;
3256                 /* The OP_GETHASHCODE rule depends on OP_MUL */
3257 #if !defined(MONO_ARCH_EMULATE_MUL_DIV) && !defined(HAVE_MOVING_COLLECTOR)
3258                 } else if (strcmp (cmethod->name, "InternalGetHashCode") == 0) {
3259                         MONO_INST_NEW (cfg, ins, OP_GETHASHCODE);
3260                         ins->inst_i0 = args [0];
3261                         return ins;
3262 #endif
3263                 } else if (strcmp (cmethod->name, ".ctor") == 0) {
3264                         MONO_INST_NEW (cfg, ins, OP_NOP);
3265                         return ins;
3266                 } else
3267                         return NULL;
3268         } else if (cmethod->klass == mono_defaults.array_class) {
3269                 if (cmethod->name [0] != 'g')
3270                         return NULL;
3271
3272                 if (strcmp (cmethod->name, "get_Rank") == 0) {
3273                         MONO_INST_NEW (cfg, ins, OP_ARRAY_RANK);
3274                         ins->inst_i0 = args [0];
3275                         return ins;
3276                 } else if (strcmp (cmethod->name, "get_Length") == 0) {
3277                         MONO_INST_NEW (cfg, ins, CEE_LDLEN);
3278                         ins->inst_i0 = args [0];
3279                         return ins;
3280                 } else
3281                         return NULL;
3282         } else if (cmethod->klass == runtime_helpers_class) {
3283                 if (strcmp (cmethod->name, "get_OffsetToStringData") == 0) {
3284                         NEW_ICONST (cfg, ins, G_STRUCT_OFFSET (MonoString, chars));
3285                         return ins;
3286                 } else
3287                         return NULL;
3288         } else if (cmethod->klass == mono_defaults.thread_class) {
3289                 if (strcmp (cmethod->name, "get_CurrentThread") == 0 && (ins = mono_arch_get_thread_intrinsic (cfg)))
3290                         return ins;
3291         } else if (mini_class_is_system_array (cmethod->klass) &&
3292                         strcmp (cmethod->name, "GetGenericValueImpl") == 0) {
3293                 MonoInst *sp [2];
3294                 MonoInst *ldelem, *store, *load;
3295                 MonoClass *eklass = mono_class_from_mono_type (fsig->params [1]);
3296                 int n;
3297                 n = mono_type_to_stind (&eklass->byval_arg);
3298                 if (n == CEE_STOBJ)
3299                         return NULL;
3300                 sp [0] = args [0];
3301                 sp [1] = args [1];
3302                 NEW_LDELEMA (cfg, ldelem, sp, eklass);
3303                 ldelem->flags |= MONO_INST_NORANGECHECK;
3304                 MONO_INST_NEW (cfg, store, n);
3305                 n = mono_type_to_ldind (&eklass->byval_arg);
3306                 MONO_INST_NEW (cfg, load, mono_type_to_ldind (&eklass->byval_arg));
3307                 type_to_eval_stack_type (&eklass->byval_arg, load);
3308                 load->inst_left = ldelem;
3309                 store->inst_left = args [2];
3310                 store->inst_right = load;
3311                 return store;
3312         } else if (cmethod->klass == mono_defaults.math_class) {
3313                 if (strcmp (cmethod->name, "Min") == 0) {
3314                         if (is_unsigned_regsize_type (fsig->params [0])) {
3315                                 MONO_INST_NEW (cfg, ins, OP_MIN);
3316                                 ins->inst_i0 = args [0];
3317                                 ins->inst_i1 = args [1];
3318                                 return ins;
3319                         }
3320                 } else if (strcmp (cmethod->name, "Max") == 0) {
3321                         if (is_unsigned_regsize_type (fsig->params [0])) {
3322                                 MONO_INST_NEW (cfg, ins, OP_MAX);
3323                                 ins->inst_i0 = args [0];
3324                                 ins->inst_i1 = args [1];
3325                                 return ins;
3326                         }
3327                 }
3328         } else if (cmethod->klass->image == mono_defaults.corlib) {
3329                 if (cmethod->name [0] == 'B' && strcmp (cmethod->name, "Break") == 0
3330                                 && strcmp (cmethod->klass->name, "Debugger") == 0) {
3331                         MONO_INST_NEW (cfg, ins, OP_BREAK);
3332                         return ins;
3333                 }
3334                 if (cmethod->name [0] == 'g' && strcmp (cmethod->name, "get_IsRunningOnWindows") == 0
3335                                 && strcmp (cmethod->klass->name, "Environment") == 0) {
3336 #ifdef PLATFORM_WIN32
3337                         NEW_ICONST (cfg, ins, 1);
3338 #else
3339                         NEW_ICONST (cfg, ins, 0);
3340 #endif
3341                         return ins;
3342                 }
3343         }
3344
3345         return mono_arch_get_inst_for_method (cfg, cmethod, fsig, args);
3346 }
3347
3348 static void
3349 mono_save_args (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethodSignature *sig, MonoInst **sp, MonoInst **args)
3350 {
3351         MonoInst *store, *temp;
3352         int i;
3353
3354         g_assert (!MONO_TYPE_ISSTRUCT (sig->ret));
3355
3356         if (!sig->hasthis && sig->param_count == 0) 
3357                 return;
3358
3359         if (sig->hasthis) {
3360                 if (sp [0]->opcode == OP_ICONST) {
3361                         *args++ = sp [0];
3362                 } else {
3363                         temp = mono_compile_create_var (cfg, type_from_stack_type (*sp), OP_LOCAL);
3364                         *args++ = temp;
3365                         NEW_TEMPSTORE (cfg, store, temp->inst_c0, *sp);
3366                         store->cil_code = sp [0]->cil_code;
3367                         MONO_ADD_INS (bblock, store);
3368                 }
3369                 sp++;
3370         }
3371
3372         for (i = 0; i < sig->param_count; ++i) {
3373                 if (sp [0]->opcode == OP_ICONST) {
3374                         *args++ = sp [0];
3375                 } else {
3376                         temp = mono_compile_create_var (cfg, sig->params [i], OP_LOCAL);
3377                         *args++ = temp;
3378                         NEW_TEMPSTORE (cfg, store, temp->inst_c0, *sp);
3379                         store->cil_code = sp [0]->cil_code;
3380                         if (store->opcode == CEE_STOBJ) {
3381                                 NEW_TEMPLOADA (cfg, store, temp->inst_c0);
3382                                 handle_stobj (cfg, bblock, store, *sp, sp [0]->cil_code, temp->klass, FALSE, FALSE, FALSE);
3383                         } else {
3384                                 MONO_ADD_INS (bblock, store);
3385                         } 
3386                 }
3387                 sp++;
3388         }
3389 }
3390 #define MONO_INLINE_CALLED_LIMITED_METHODS 0
3391 #define MONO_INLINE_CALLER_LIMITED_METHODS 0
3392
3393 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
3394 static char*
3395 mono_inline_called_method_name_limit = NULL;
3396 static gboolean check_inline_called_method_name_limit (MonoMethod *called_method) {
3397         char *called_method_name = mono_method_full_name (called_method, TRUE);
3398         int strncmp_result;
3399         
3400         if (mono_inline_called_method_name_limit == NULL) {
3401                 char *limit_string = getenv ("MONO_INLINE_CALLED_METHOD_NAME_LIMIT");
3402                 if (limit_string != NULL) {
3403                         mono_inline_called_method_name_limit = limit_string;
3404                 } else {
3405                         mono_inline_called_method_name_limit = (char *) "";
3406                 }
3407         }
3408         
3409         strncmp_result = strncmp (called_method_name, mono_inline_called_method_name_limit, strlen (mono_inline_called_method_name_limit));
3410         g_free (called_method_name);
3411         
3412         //return (strncmp_result <= 0);
3413         return (strncmp_result == 0);
3414 }
3415 #endif
3416
3417 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
3418 static char*
3419 mono_inline_caller_method_name_limit = NULL;
3420 static gboolean check_inline_caller_method_name_limit (MonoMethod *caller_method) {
3421         char *caller_method_name = mono_method_full_name (caller_method, TRUE);
3422         int strncmp_result;
3423         
3424         if (mono_inline_caller_method_name_limit == NULL) {
3425                 char *limit_string = getenv ("MONO_INLINE_CALLER_METHOD_NAME_LIMIT");
3426                 if (limit_string != NULL) {
3427                         mono_inline_caller_method_name_limit = limit_string;
3428                 } else {
3429                         mono_inline_caller_method_name_limit = (char *) "";
3430                 }
3431         }
3432         
3433         strncmp_result = strncmp (caller_method_name, mono_inline_caller_method_name_limit, strlen (mono_inline_caller_method_name_limit));
3434         g_free (caller_method_name);
3435         
3436         //return (strncmp_result <= 0);
3437         return (strncmp_result == 0);
3438 }
3439 #endif
3440
3441 static int
3442 inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoBasicBlock *bblock, MonoInst **sp,
3443                 guchar *ip, guint real_offset, GList *dont_inline, MonoBasicBlock **last_b, gboolean inline_allways)
3444 {
3445         MonoInst *ins, *rvar = NULL;
3446         MonoMethodHeader *cheader;
3447         MonoBasicBlock *ebblock, *sbblock;
3448         int i, costs, new_locals_offset;
3449         MonoMethod *prev_inlined_method;
3450         MonoBasicBlock **prev_cil_offset_to_bb;
3451         unsigned char* prev_cil_start;
3452         guint32 prev_cil_offset_to_bb_len;
3453
3454         g_assert (cfg->exception_type == MONO_EXCEPTION_NONE);
3455
3456 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
3457         if ((! inline_allways) && ! check_inline_called_method_name_limit (cmethod))
3458                 return 0;
3459 #endif
3460 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
3461         if ((! inline_allways) && ! check_inline_caller_method_name_limit (cfg->method))
3462                 return 0;
3463 #endif
3464
3465         if (bblock->out_of_line && !inline_allways)
3466                 return 0;
3467
3468         if (cfg->verbose_level > 2)
3469                 g_print ("INLINE START %p %s -> %s\n", cmethod,  mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
3470
3471         if (!cmethod->inline_info) {
3472                 mono_jit_stats.inlineable_methods++;
3473                 cmethod->inline_info = 1;
3474         }
3475         /* allocate space to store the return value */
3476         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
3477                 rvar =  mono_compile_create_var (cfg, fsig->ret, OP_LOCAL);
3478         }
3479
3480         /* allocate local variables */
3481         cheader = mono_method_get_header (cmethod);
3482         new_locals_offset = cfg->num_varinfo;
3483         for (i = 0; i < cheader->num_locals; ++i)
3484                 mono_compile_create_var (cfg, cheader->locals [i], OP_LOCAL);
3485         
3486         /* allocate starte and end blocks */
3487         sbblock = NEW_BBLOCK (cfg);
3488         sbblock->block_num = cfg->num_bblocks++;
3489         sbblock->real_offset = real_offset;
3490
3491         ebblock = NEW_BBLOCK (cfg);
3492         ebblock->block_num = cfg->num_bblocks++;
3493         ebblock->real_offset = real_offset;
3494
3495         prev_inlined_method = cfg->inlined_method;
3496         cfg->inlined_method = cmethod;
3497         prev_cil_offset_to_bb = cfg->cil_offset_to_bb;
3498         prev_cil_offset_to_bb_len = cfg->cil_offset_to_bb_len;
3499         prev_cil_start = cfg->cil_start;
3500
3501         costs = mono_method_to_ir (cfg, cmethod, sbblock, ebblock, new_locals_offset, rvar, dont_inline, sp, real_offset, *ip == CEE_CALLVIRT);
3502
3503         cfg->inlined_method = prev_inlined_method;
3504         cfg->cil_offset_to_bb = prev_cil_offset_to_bb;
3505         cfg->cil_offset_to_bb_len = prev_cil_offset_to_bb_len;
3506         cfg->cil_start = prev_cil_start;
3507
3508         if ((costs >= 0 && costs < 60) || inline_allways) {
3509                 if (cfg->verbose_level > 2)
3510                         g_print ("INLINE END %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
3511                 
3512                 mono_jit_stats.inlined_methods++;
3513
3514                 /* always add some code to avoid block split failures */
3515                 MONO_INST_NEW (cfg, ins, OP_NOP);
3516                 MONO_ADD_INS (bblock, ins);
3517                 ins->cil_code = ip;
3518
3519                 bblock->next_bb = sbblock;
3520                 link_bblock (cfg, bblock, sbblock);
3521
3522                 if (rvar) {
3523                         NEW_TEMPLOAD (cfg, ins, rvar->inst_c0);
3524                         *sp++ = ins;
3525                 }
3526                 *last_b = ebblock;
3527                 return costs + 1;
3528         } else {
3529                 if (cfg->verbose_level > 2)
3530                         g_print ("INLINE ABORTED %s\n", mono_method_full_name (cmethod, TRUE));
3531                 cfg->exception_type = MONO_EXCEPTION_NONE;
3532         }
3533         return 0;
3534 }
3535
3536 /*
3537  * Some of these comments may well be out-of-date.
3538  * Design decisions: we do a single pass over the IL code (and we do bblock 
3539  * splitting/merging in the few cases when it's required: a back jump to an IL
3540  * address that was not already seen as bblock starting point).
3541  * Code is validated as we go (full verification is still better left to metadata/verify.c).
3542  * Complex operations are decomposed in simpler ones right away. We need to let the 
3543  * arch-specific code peek and poke inside this process somehow (except when the 
3544  * optimizations can take advantage of the full semantic info of coarse opcodes).
3545  * All the opcodes of the form opcode.s are 'normalized' to opcode.
3546  * MonoInst->opcode initially is the IL opcode or some simplification of that 
3547  * (OP_LOAD, OP_STORE). The arch-specific code may rearrange it to an arch-specific 
3548  * opcode with value bigger than OP_LAST.
3549  * At this point the IR can be handed over to an interpreter, a dumb code generator
3550  * or to the optimizing code generator that will translate it to SSA form.
3551  *
3552  * Profiling directed optimizations.
3553  * We may compile by default with few or no optimizations and instrument the code
3554  * or the user may indicate what methods to optimize the most either in a config file
3555  * or through repeated runs where the compiler applies offline the optimizations to 
3556  * each method and then decides if it was worth it.
3557  *
3558  */
3559
3560 #define CHECK_TYPE(ins) if (!(ins)->type) UNVERIFIED
3561 #define CHECK_STACK(num) if ((sp - stack_start) < (num)) UNVERIFIED
3562 #define CHECK_STACK_OVF(num) if (((sp - stack_start) + (num)) > header->max_stack) UNVERIFIED
3563 #define CHECK_ARG(num) if ((unsigned)(num) >= (unsigned)num_args) UNVERIFIED
3564 #define CHECK_LOCAL(num) if ((unsigned)(num) >= (unsigned)header->num_locals) UNVERIFIED
3565 #define CHECK_OPSIZE(size) if (ip + size > end) UNVERIFIED
3566 #define CHECK_UNVERIFIABLE(cfg) if (cfg->unverifiable) UNVERIFIED
3567 #define CHECK_TYPELOAD(klass) if (!(klass) || (klass)->exception_type) {cfg->exception_ptr = klass; goto load_error;}
3568
3569 /* offset from br.s -> br like opcodes */
3570 #define BIG_BRANCH_OFFSET 13
3571
3572 static inline gboolean
3573 ip_in_bb (MonoCompile *cfg, MonoBasicBlock *bb, const guint8* ip)
3574 {
3575         MonoBasicBlock *b = cfg->cil_offset_to_bb [ip - cfg->cil_start];
3576         
3577         return b == NULL || b == bb;
3578 }
3579
3580 static int
3581 get_basic_blocks (MonoCompile *cfg, MonoMethodHeader* header, guint real_offset, unsigned char *start, unsigned char *end, unsigned char **pos)
3582 {
3583         unsigned char *ip = start;
3584         unsigned char *target;
3585         int i;
3586         guint cli_addr;
3587         MonoBasicBlock *bblock;
3588         const MonoOpcode *opcode;
3589
3590         while (ip < end) {
3591                 cli_addr = ip - start;
3592                 i = mono_opcode_value ((const guint8 **)&ip, end);
3593                 if (i < 0)
3594                         UNVERIFIED;
3595                 opcode = &mono_opcodes [i];
3596                 switch (opcode->argument) {
3597                 case MonoInlineNone:
3598                         ip++; 
3599                         break;
3600                 case MonoInlineString:
3601                 case MonoInlineType:
3602                 case MonoInlineField:
3603                 case MonoInlineMethod:
3604                 case MonoInlineTok:
3605                 case MonoInlineSig:
3606                 case MonoShortInlineR:
3607                 case MonoInlineI:
3608                         ip += 5;
3609                         break;
3610                 case MonoInlineVar:
3611                         ip += 3;
3612                         break;
3613                 case MonoShortInlineVar:
3614                 case MonoShortInlineI:
3615                         ip += 2;
3616                         break;
3617                 case MonoShortInlineBrTarget:
3618                         target = start + cli_addr + 2 + (signed char)ip [1];
3619                         GET_BBLOCK (cfg, bblock, target);
3620                         ip += 2;
3621                         if (ip < end)
3622                                 GET_BBLOCK (cfg, bblock, ip);
3623                         break;
3624                 case MonoInlineBrTarget:
3625                         target = start + cli_addr + 5 + (gint32)read32 (ip + 1);
3626                         GET_BBLOCK (cfg, bblock, target);
3627                         ip += 5;
3628                         if (ip < end)
3629                                 GET_BBLOCK (cfg, bblock, ip);
3630                         break;
3631                 case MonoInlineSwitch: {
3632                         guint32 n = read32 (ip + 1);
3633                         guint32 j;
3634                         ip += 5;
3635                         cli_addr += 5 + 4 * n;
3636                         target = start + cli_addr;
3637                         GET_BBLOCK (cfg, bblock, target);
3638                         
3639                         for (j = 0; j < n; ++j) {
3640                                 target = start + cli_addr + (gint32)read32 (ip);
3641                                 GET_BBLOCK (cfg, bblock, target);
3642                                 ip += 4;
3643                         }
3644                         break;
3645                 }
3646                 case MonoInlineR:
3647                 case MonoInlineI8:
3648                         ip += 9;
3649                         break;
3650                 default:
3651                         g_assert_not_reached ();
3652                 }
3653
3654                 if (i == CEE_THROW) {
3655                         unsigned char *bb_start = ip - 1;
3656                         
3657                         /* Find the start of the bblock containing the throw */
3658                         bblock = NULL;
3659                         while ((bb_start >= start) && !bblock) {
3660                                 bblock = cfg->cil_offset_to_bb [(bb_start) - start];
3661                                 bb_start --;
3662                         }
3663                         if (bblock)
3664                                 bblock->out_of_line = 1;
3665                 }
3666         }
3667         return 0;
3668 unverified:
3669         *pos = ip;
3670         return 1;
3671 }
3672
3673 static MonoInst*
3674 emit_tree (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *ins, const guint8* ip_next)
3675 {
3676         MonoInst *store, *temp, *load;
3677         
3678         if (ip_in_bb (cfg, bblock, ip_next) &&
3679                 (CODE_IS_STLOC (ip_next) || *ip_next == CEE_RET))
3680                         return ins;
3681         
3682         temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
3683         temp->flags |= MONO_INST_IS_TEMP;
3684         NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
3685         store->cil_code = ins->cil_code;
3686         MONO_ADD_INS (bblock, store);
3687         NEW_TEMPLOAD (cfg, load, temp->inst_c0);
3688         load->cil_code = ins->cil_code;
3689         return load;
3690 }
3691
3692 static inline MonoMethod *
3693 mini_get_method (MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
3694 {
3695         MonoMethod *method;
3696
3697         if (m->wrapper_type != MONO_WRAPPER_NONE)
3698                 return mono_method_get_wrapper_data (m, token);
3699
3700         method = mono_get_method_full (m->klass->image, token, klass, context);
3701
3702         return method;
3703 }
3704
3705 static inline MonoClass*
3706 mini_get_class (MonoMethod *method, guint32 token, MonoGenericContext *context)
3707 {
3708         MonoClass *klass;
3709
3710         if (method->wrapper_type != MONO_WRAPPER_NONE)
3711                 klass = mono_method_get_wrapper_data (method, token);
3712         else
3713                 klass = mono_class_get_full (method->klass->image, token, context);
3714         if (klass)
3715                 mono_class_init (klass);
3716         return klass;
3717 }
3718
3719 /*
3720  * Returns TRUE if the JIT should abort inlining because "callee"
3721  * is influenced by security attributes.
3722  */
3723 static
3724 gboolean check_linkdemand (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee, MonoBasicBlock *bblock, unsigned char *ip)
3725 {
3726         guint32 result;
3727         
3728         if ((cfg->method != caller) && mono_method_has_declsec (callee)) {
3729                 return TRUE;
3730         }
3731         
3732         result = mono_declsec_linkdemand (cfg->domain, caller, callee);
3733         if (result == MONO_JIT_SECURITY_OK)
3734                 return FALSE;
3735
3736         if (result == MONO_JIT_LINKDEMAND_ECMA) {
3737                 /* Generate code to throw a SecurityException before the actual call/link */
3738                 MonoAssembly *assembly = mono_image_get_assembly (caller->klass->image);
3739                 MonoReflectionAssembly *refass = (MonoReflectionAssembly*) mono_assembly_get_object (cfg->domain, assembly);
3740                 MonoReflectionMethod *refmet = mono_method_get_object (cfg->domain, caller, NULL);
3741                 MonoSecurityManager *secman = mono_security_manager_get_methods ();
3742                 MonoInst *args [3];
3743
3744                 NEW_ICONST (cfg, args [0], 4);
3745                 NEW_PCONST (cfg, args [1], refass);
3746                 NEW_PCONST (cfg, args [2], refmet);
3747                 mono_emit_method_call_spilled (cfg, bblock, secman->linkdemandsecurityexception, mono_method_signature (secman->linkdemandsecurityexception), args, ip, NULL);
3748         } else if (cfg->exception_type == MONO_EXCEPTION_NONE) {
3749                  /* don't hide previous results */
3750                 cfg->exception_type = MONO_EXCEPTION_SECURITY_LINKDEMAND;
3751                 cfg->exception_data = result;
3752                 return TRUE;
3753         }
3754         
3755         return FALSE;
3756 }
3757
3758 static MonoMethod*
3759 method_access_exception (void)
3760 {
3761         static MonoMethod *method = NULL;
3762
3763         if (!method) {
3764                 MonoSecurityManager *secman = mono_security_manager_get_methods ();
3765                 method = mono_class_get_method_from_name (secman->securitymanager,
3766                                                           "MethodAccessException", 2);
3767         }
3768         g_assert (method);
3769         return method;
3770 }
3771
3772 static void
3773 emit_throw_method_access_exception (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee,
3774                                     MonoBasicBlock *bblock, unsigned char *ip)
3775 {
3776         MonoMethod *thrower = method_access_exception ();
3777         MonoInst *args [2];
3778
3779         NEW_METHODCONST (cfg, args [0], caller);
3780         NEW_METHODCONST (cfg, args [1], callee);
3781         mono_emit_method_call_spilled (cfg, bblock, thrower,
3782                 mono_method_signature (thrower), args, ip, NULL);
3783 }
3784
3785 static MonoMethod*
3786 verification_exception (void)
3787 {
3788         static MonoMethod *method = NULL;
3789
3790         if (!method) {
3791                 MonoSecurityManager *secman = mono_security_manager_get_methods ();
3792                 method = mono_class_get_method_from_name (secman->securitymanager,
3793                                                           "VerificationException", 0);
3794         }
3795         g_assert (method);
3796         return method;
3797 }
3798
3799 static void
3800 emit_throw_verification_exception (MonoCompile *cfg, MonoBasicBlock *bblock, unsigned char *ip)
3801 {
3802         MonoMethod *thrower = verification_exception ();
3803
3804         mono_emit_method_call_spilled (cfg, bblock, thrower,
3805                 mono_method_signature (thrower),
3806                 NULL, ip, NULL);
3807 }
3808
3809 static void
3810 ensure_method_is_allowed_to_call_method (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee,
3811                                          MonoBasicBlock *bblock, unsigned char *ip)
3812 {
3813         MonoSecurityCoreCLRLevel caller_level = mono_security_core_clr_method_level (caller, TRUE);
3814         MonoSecurityCoreCLRLevel callee_level = mono_security_core_clr_method_level (callee, TRUE);
3815         gboolean is_safe = TRUE;
3816
3817         if (!(caller_level >= callee_level ||
3818                         caller_level == MONO_SECURITY_CORE_CLR_SAFE_CRITICAL ||
3819                         callee_level == MONO_SECURITY_CORE_CLR_SAFE_CRITICAL)) {
3820                 is_safe = FALSE;
3821         }
3822
3823         if (!is_safe)
3824                 emit_throw_method_access_exception (cfg, caller, callee, bblock, ip);
3825 }
3826
3827 static gboolean
3828 method_is_safe (MonoMethod *method)
3829 {
3830         /*
3831         if (strcmp (method->name, "unsafeMethod") == 0)
3832                 return FALSE;
3833         */
3834         return TRUE;
3835 }
3836
3837 /*
3838  * Check that the IL instructions at ip are the array initialization
3839  * sequence and return the pointer to the data and the size.
3840  */
3841 static const char*
3842 initialize_array_data (MonoMethod *method, gboolean aot, unsigned char *ip, MonoInst *newarr, int *out_size)
3843 {
3844         /*
3845          * newarr[System.Int32]
3846          * dup
3847          * ldtoken field valuetype ...
3848          * call void class [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype [mscorlib]System.RuntimeFieldHandle)
3849          */
3850         if (ip [0] == CEE_DUP && ip [1] == CEE_LDTOKEN && ip [5] == 0x4 && ip [6] == CEE_CALL) {
3851                 MonoClass *klass = newarr->inst_newa_class;
3852                 guint32 token = read32 (ip + 7);
3853                 guint32 rva, field_index;
3854                 const char *data_ptr;
3855                 int size = 0;
3856                 MonoMethod *cmethod;
3857
3858                 if (newarr->inst_newa_len->opcode != OP_ICONST)
3859                         return NULL;
3860                 cmethod = mini_get_method (method, token, NULL, NULL);
3861                 if (!cmethod)
3862                         return NULL;
3863                 if (strcmp (cmethod->name, "InitializeArray") || strcmp (cmethod->klass->name, "RuntimeHelpers") || cmethod->klass->image != mono_defaults.corlib)
3864                         return NULL;
3865                 switch (mono_type_get_underlying_type (&klass->byval_arg)->type) {
3866                 case MONO_TYPE_BOOLEAN:
3867                 case MONO_TYPE_I1:
3868                 case MONO_TYPE_U1:
3869                         size = 1; break;
3870                 /* we need to swap on big endian, so punt. Should we handle R4 and R8 as well? */
3871 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
3872                 case MONO_TYPE_CHAR:
3873                 case MONO_TYPE_I2:
3874                 case MONO_TYPE_U2:
3875                         size = 2; break;
3876                 case MONO_TYPE_I4:
3877                 case MONO_TYPE_U4:
3878                 case MONO_TYPE_R4:
3879                         size = 4; break;
3880                 case MONO_TYPE_R8:
3881 #ifdef ARM_FPU_FPA
3882                         return NULL; /* stupid ARM FP swapped format */
3883 #endif
3884                 case MONO_TYPE_I8:
3885                 case MONO_TYPE_U8:
3886                         size = 8; break;
3887 #endif
3888                 default:
3889                         return NULL;
3890                 }
3891                 size *= newarr->inst_newa_len->inst_c0;
3892                 *out_size = size;
3893                 /*g_print ("optimized in %s: size: %d, numelems: %d\n", method->name, size, newarr->inst_newa_len->inst_c0);*/
3894                 field_index = read32 (ip + 2) & 0xffffff;
3895                 mono_metadata_field_info (method->klass->image, field_index - 1, NULL, &rva, NULL);
3896                 data_ptr = mono_image_rva_map (method->klass->image, rva);
3897                 /*g_print ("field: 0x%08x, rva: %d, rva_ptr: %p\n", read32 (ip + 2), rva, data_ptr);*/
3898                 /* for aot code we do the lookup on load */
3899                 if (aot && data_ptr)
3900                         return GUINT_TO_POINTER (rva);
3901                 return data_ptr;
3902         }
3903         return NULL;
3904 }
3905
3906 /*
3907  * mono_method_to_ir: translates IL into basic blocks containing trees
3908  */
3909 static int
3910 mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock, 
3911                    int locals_offset, MonoInst *return_var, GList *dont_inline, MonoInst **inline_args, 
3912                    guint inline_offset, gboolean is_virtual_call)
3913 {
3914         MonoInst *zero_int32, *zero_int64, *zero_ptr, *zero_obj, *zero_r8;
3915         MonoInst *ins, **sp, **stack_start;
3916         MonoBasicBlock *bblock, *tblock = NULL, *init_localsbb = NULL;
3917         MonoMethod *cmethod;
3918         MonoInst **arg_array;
3919         MonoMethodHeader *header;
3920         MonoImage *image;
3921         guint32 token, ins_flag;
3922         MonoClass *klass;
3923         MonoClass *constrained_call = NULL;
3924         unsigned char *ip, *end, *target, *err_pos;
3925         static double r8_0 = 0.0;
3926         MonoMethodSignature *sig;
3927         MonoGenericContext *generic_context = NULL;
3928         MonoGenericContainer *generic_container = NULL;
3929         MonoType **param_types;
3930         GList *bb_recheck = NULL, *tmp;
3931         int i, n, start_new_bblock, ialign;
3932         int num_calls = 0, inline_costs = 0;
3933         int breakpoint_id = 0;
3934         guint32 align;
3935         guint real_offset, num_args;
3936         MonoBoolean security, pinvoke;
3937         MonoSecurityManager* secman = NULL;
3938         MonoDeclSecurityActions actions;
3939         GSList *class_inits = NULL;
3940         gboolean dont_verify, dont_verify_stloc;
3941
3942         /* serialization and xdomain stuff may need access to private fields and methods */
3943         dont_verify = method->klass->image->assembly->corlib_internal? TRUE: FALSE;
3944         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE;
3945         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH;
3946         dont_verify |= method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE; /* bug #77896 */
3947         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP;
3948         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP_INVOKE;
3949
3950         /* turn off visibility checks for smcs */
3951         dont_verify |= mono_security_get_mode () == MONO_SECURITY_MODE_SMCS_HACK;
3952
3953         /* still some type unsafety issues in marshal wrappers... (unknown is PtrToStructure) */
3954         dont_verify_stloc = method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE;
3955         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_UNKNOWN;
3956         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED;
3957
3958         /* Not turned on yet */
3959         cfg->dont_verify_stack_merge = TRUE;
3960
3961         image = method->klass->image;
3962         header = mono_method_get_header (method);
3963         generic_container = method->generic_container;
3964         sig = mono_method_signature (method);
3965         num_args = sig->hasthis + sig->param_count;
3966         ip = (unsigned char*)header->code;
3967         cfg->cil_start = ip;
3968         end = ip + header->code_size;
3969         mono_jit_stats.cil_code_size += header->code_size;
3970
3971         if (sig->is_inflated)
3972                 generic_context = mono_method_get_context (method);
3973         else if (generic_container)
3974                 generic_context = &generic_container->context;
3975
3976         g_assert (!sig->has_type_parameters);
3977
3978         if (cfg->method == method)
3979                 real_offset = 0;
3980         else
3981                 real_offset = inline_offset;
3982
3983         cfg->cil_offset_to_bb = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoBasicBlock*) * header->code_size);
3984         cfg->cil_offset_to_bb_len = header->code_size;
3985
3986         if (cfg->verbose_level > 2)
3987                 g_print ("method to IR %s\n", mono_method_full_name (method, TRUE));
3988
3989         dont_inline = g_list_prepend (dont_inline, method);
3990         if (cfg->method == method) {
3991
3992                 if (cfg->prof_options & MONO_PROFILE_INS_COVERAGE)
3993                         cfg->coverage_info = mono_profiler_coverage_alloc (cfg->method, header->code_size);
3994
3995                 /* ENTRY BLOCK */
3996                 cfg->bb_entry = start_bblock = NEW_BBLOCK (cfg);
3997                 start_bblock->cil_code = NULL;
3998                 start_bblock->cil_length = 0;
3999                 start_bblock->block_num = cfg->num_bblocks++;
4000
4001                 /* EXIT BLOCK */
4002                 cfg->bb_exit = end_bblock = NEW_BBLOCK (cfg);
4003                 end_bblock->cil_code = NULL;
4004                 end_bblock->cil_length = 0;
4005                 end_bblock->block_num = cfg->num_bblocks++;
4006                 g_assert (cfg->num_bblocks == 2);
4007
4008                 arg_array = alloca (sizeof (MonoInst *) * num_args);
4009                 for (i = num_args - 1; i >= 0; i--)
4010                         arg_array [i] = cfg->varinfo [i];
4011
4012                 if (header->num_clauses) {
4013                         cfg->spvars = g_hash_table_new (NULL, NULL);
4014                         cfg->exvars = g_hash_table_new (NULL, NULL);
4015                 }
4016                 /* handle exception clauses */
4017                 for (i = 0; i < header->num_clauses; ++i) {
4018                         MonoBasicBlock *try_bb;
4019                         MonoExceptionClause *clause = &header->clauses [i];
4020                         GET_BBLOCK (cfg, try_bb, ip + clause->try_offset);
4021                         try_bb->real_offset = clause->try_offset;
4022                         GET_BBLOCK (cfg, tblock, ip + clause->handler_offset);
4023                         tblock->real_offset = clause->handler_offset;
4024                         tblock->flags |= BB_EXCEPTION_HANDLER;
4025
4026                         link_bblock (cfg, try_bb, tblock);
4027
4028                         if (*(ip + clause->handler_offset) == CEE_POP)
4029                                 tblock->flags |= BB_EXCEPTION_DEAD_OBJ;
4030
4031                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY ||
4032                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER ||
4033                             clause->flags == MONO_EXCEPTION_CLAUSE_FAULT) {
4034                                 MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
4035                                 MONO_ADD_INS (tblock, ins);
4036
4037                                 /* todo: is a fault block unsafe to optimize? */
4038                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
4039                                         tblock->flags |= BB_EXCEPTION_UNSAFE;
4040                         }
4041
4042
4043                         /*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);
4044                           while (p < end) {
4045                           g_print ("%s", mono_disasm_code_one (NULL, method, p, &p));
4046                           }*/
4047                         /* catch and filter blocks get the exception object on the stack */
4048                         if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE ||
4049                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
4050                                 MonoInst *load, *dummy_use;
4051
4052                                 /* mostly like handle_stack_args (), but just sets the input args */
4053                                 /* g_print ("handling clause at IL_%04x\n", clause->handler_offset); */
4054                                 tblock->in_scount = 1;
4055                                 tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
4056                                 tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
4057                                 tblock->stack_state = mono_mempool_alloc (cfg->mempool, sizeof (MonoStackSlot));
4058                                 tblock->stack_state [0].type = STACK_OBJ;
4059                                 /* FIXME? */
4060                                 tblock->stack_state [0].klass = mono_defaults.object_class;
4061
4062                                 /* 
4063                                  * Add a dummy use for the exvar so its liveness info will be
4064                                  * correct.
4065                                  */
4066                                 NEW_TEMPLOAD (cfg, load, tblock->in_stack [0]->inst_c0);
4067                                 NEW_DUMMY_USE (cfg, dummy_use, load);
4068                                 MONO_ADD_INS (tblock, dummy_use);
4069                                 
4070                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
4071                                         GET_BBLOCK (cfg, tblock, ip + clause->data.filter_offset);
4072                                         tblock->real_offset = clause->data.filter_offset;
4073                                         tblock->in_scount = 1;
4074                                         tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
4075                                         tblock->stack_state = mono_mempool_alloc (cfg->mempool, sizeof (MonoStackSlot));
4076                                         tblock->stack_state [0].type = STACK_OBJ;
4077                                         /* FIXME? */
4078                                         tblock->stack_state [0].klass = mono_defaults.object_class;
4079
4080                                         /* The filter block shares the exvar with the handler block */
4081                                         tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
4082                                         MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
4083                                         MONO_ADD_INS (tblock, ins);
4084                                 }
4085                         }
4086                 }
4087         } else {
4088                 arg_array = alloca (sizeof (MonoInst *) * num_args);
4089                 mono_save_args (cfg, start_bblock, sig, inline_args, arg_array);
4090         }
4091
4092         /* FIRST CODE BLOCK */
4093         bblock = NEW_BBLOCK (cfg);
4094         bblock->cil_code = ip;
4095
4096         ADD_BBLOCK (cfg, bblock);
4097
4098         if (cfg->method == method) {
4099                 breakpoint_id = mono_debugger_method_has_breakpoint (method);
4100                 if (breakpoint_id && (mono_debug_format != MONO_DEBUG_FORMAT_DEBUGGER)) {
4101                         MONO_INST_NEW (cfg, ins, OP_BREAK);
4102                         MONO_ADD_INS (bblock, ins);
4103                 }
4104         }
4105
4106         if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS)
4107                 secman = mono_security_manager_get_methods ();
4108
4109         security = (secman && mono_method_has_declsec (method));
4110         /* at this point having security doesn't mean we have any code to generate */
4111         if (security && (cfg->method == method)) {
4112                 /* Only Demand, NonCasDemand and DemandChoice requires code generation.
4113                  * And we do not want to enter the next section (with allocation) if we
4114                  * have nothing to generate */
4115                 security = mono_declsec_get_demands (method, &actions);
4116         }
4117
4118         /* we must Demand SecurityPermission.Unmanaged before P/Invoking */
4119         pinvoke = (secman && (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE));
4120         if (pinvoke) {
4121                 MonoMethod *wrapped = mono_marshal_method_from_wrapper (method);
4122                 if (wrapped && (wrapped->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
4123                         MonoCustomAttrInfo* custom = mono_custom_attrs_from_method (wrapped);
4124
4125                         /* unless the method or it's class has the [SuppressUnmanagedCodeSecurity] attribute */
4126                         if (custom && mono_custom_attrs_has_attr (custom, secman->suppressunmanagedcodesecurity)) {
4127                                 pinvoke = FALSE;
4128                         }
4129
4130                         if (pinvoke) {
4131                                 custom = mono_custom_attrs_from_class (wrapped->klass);
4132                                 if (custom && mono_custom_attrs_has_attr (custom, secman->suppressunmanagedcodesecurity)) {
4133                                         pinvoke = FALSE;
4134                                 }
4135                         }
4136                 } else {
4137                         /* not a P/Invoke after all */
4138                         pinvoke = FALSE;
4139                 }
4140         }
4141         
4142         if ((header->init_locals || (cfg->method == method && (cfg->opt & MONO_OPT_SHARED))) || cfg->compile_aot || security || pinvoke) {
4143                 /* we use a separate basic block for the initialization code */
4144                 cfg->bb_init = init_localsbb = NEW_BBLOCK (cfg);
4145                 init_localsbb->real_offset = real_offset;
4146                 start_bblock->next_bb = init_localsbb;
4147                 init_localsbb->next_bb = bblock;
4148                 link_bblock (cfg, start_bblock, init_localsbb);
4149                 link_bblock (cfg, init_localsbb, bblock);
4150                 init_localsbb->block_num = cfg->num_bblocks++;
4151         } else {
4152                 start_bblock->next_bb = bblock;
4153                 link_bblock (cfg, start_bblock, bblock);
4154         }
4155
4156         /* at this point we know, if security is TRUE, that some code needs to be generated */
4157         if (security && (cfg->method == method)) {
4158                 MonoInst *args [2];
4159
4160                 mono_jit_stats.cas_demand_generation++;
4161
4162                 if (actions.demand.blob) {
4163                         /* Add code for SecurityAction.Demand */
4164                         NEW_DECLSECCONST (cfg, args[0], image, actions.demand);
4165                         NEW_ICONST (cfg, args [1], actions.demand.size);
4166                         /* Calls static void SecurityManager.InternalDemand (byte* permissions, int size); */
4167                         mono_emit_method_call_spilled (cfg, init_localsbb, secman->demand, mono_method_signature (secman->demand), args, ip, NULL);
4168                 }
4169                 if (actions.noncasdemand.blob) {
4170                         /* CLR 1.x uses a .noncasdemand (but 2.x doesn't) */
4171                         /* For Mono we re-route non-CAS Demand to Demand (as the managed code must deal with it anyway) */
4172                         NEW_DECLSECCONST (cfg, args[0], image, actions.noncasdemand);
4173                         NEW_ICONST (cfg, args [1], actions.noncasdemand.size);
4174                         /* Calls static void SecurityManager.InternalDemand (byte* permissions, int size); */
4175                         mono_emit_method_call_spilled (cfg, init_localsbb, secman->demand, mono_method_signature (secman->demand), args, ip, NULL);
4176                 }
4177                 if (actions.demandchoice.blob) {
4178                         /* New in 2.0, Demand must succeed for one of the permissions (i.e. not all) */
4179                         NEW_DECLSECCONST (cfg, args[0], image, actions.demandchoice);
4180                         NEW_ICONST (cfg, args [1], actions.demandchoice.size);
4181                         /* Calls static void SecurityManager.InternalDemandChoice (byte* permissions, int size); */
4182                         mono_emit_method_call_spilled (cfg, init_localsbb, secman->demandchoice, mono_method_signature (secman->demandchoice), args, ip, NULL);
4183                 }
4184         }
4185
4186         /* we must Demand SecurityPermission.Unmanaged before p/invoking */
4187         if (pinvoke) {
4188                 mono_emit_method_call_spilled (cfg, init_localsbb, secman->demandunmanaged, mono_method_signature (secman->demandunmanaged), NULL, ip, NULL);
4189         }
4190
4191         if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR) {
4192                 if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
4193                         MonoMethod *wrapped = mono_marshal_method_from_wrapper (method);
4194                         if (wrapped && (wrapped->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
4195                                 if (!(method->klass && method->klass->image &&
4196                                                 mono_security_core_clr_is_platform_image (method->klass->image))) {
4197                                         emit_throw_method_access_exception (cfg, method, wrapped, bblock, ip);
4198                                 }
4199                         }
4200                 }
4201                 if (!method_is_safe (method))
4202                         emit_throw_verification_exception (cfg, bblock, ip);
4203         }
4204
4205         if (get_basic_blocks (cfg, header, real_offset, ip, end, &err_pos)) {
4206                 ip = err_pos;
4207                 UNVERIFIED;
4208         }
4209
4210         if (cfg->method == method)
4211                 mono_debug_init_method (cfg, bblock, breakpoint_id);
4212
4213         param_types = mono_mempool_alloc (cfg->mempool, sizeof (MonoType*) * num_args);
4214         if (sig->hasthis)
4215                 param_types [0] = method->klass->valuetype?&method->klass->this_arg:&method->klass->byval_arg;
4216         for (n = 0; n < sig->param_count; ++n)
4217                 param_types [n + sig->hasthis] = sig->params [n];
4218         for (n = 0; n < header->num_locals; ++n) {
4219                 if (header->locals [n]->type == MONO_TYPE_VOID && !header->locals [n]->byref)
4220                         UNVERIFIED;
4221         }
4222         class_inits = NULL;
4223
4224         /* do this somewhere outside - not here */
4225         NEW_ICONST (cfg, zero_int32, 0);
4226         NEW_ICONST (cfg, zero_int64, 0);
4227         zero_int64->type = STACK_I8;
4228         NEW_PCONST (cfg, zero_ptr, 0);
4229         NEW_PCONST (cfg, zero_obj, 0);
4230         zero_obj->type = STACK_OBJ;
4231
4232         MONO_INST_NEW (cfg, zero_r8, OP_R8CONST);
4233         zero_r8->type = STACK_R8;
4234         zero_r8->inst_p0 = &r8_0;
4235
4236         /* add a check for this != NULL to inlined methods */
4237         if (is_virtual_call) {
4238                 MONO_INST_NEW (cfg, ins, OP_CHECK_THIS);
4239                 NEW_ARGLOAD (cfg, ins->inst_left, 0);
4240                 ins->cil_code = ip;
4241                 MONO_ADD_INS (bblock, ins);
4242         }
4243
4244         /* we use a spare stack slot in SWITCH and NEWOBJ and others */
4245         stack_start = sp = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * (header->max_stack + 1));
4246
4247         ins_flag = 0;
4248         start_new_bblock = 0;
4249         while (ip < end) {
4250
4251                 if (cfg->method == method)
4252                         real_offset = ip - header->code;
4253                 else
4254                         real_offset = inline_offset;
4255
4256                 if (start_new_bblock) {
4257                         bblock->cil_length = ip - bblock->cil_code;
4258                         if (start_new_bblock == 2) {
4259                                 g_assert (ip == tblock->cil_code);
4260                         } else {
4261                                 GET_BBLOCK (cfg, tblock, ip);
4262                         }
4263                         bblock->next_bb = tblock;
4264                         bblock = tblock;
4265                         start_new_bblock = 0;
4266                         for (i = 0; i < bblock->in_scount; ++i) {
4267                                 if (cfg->verbose_level > 3)
4268                                         g_print ("loading %d from temp %d\n", i, (int)bblock->in_stack [i]->inst_c0);                                           
4269                                 NEW_TEMPLOAD (cfg, ins, bblock->in_stack [i]->inst_c0);
4270                                 *sp++ = ins;
4271                         }
4272                         g_slist_free (class_inits);
4273                         class_inits = NULL;
4274                 } else {
4275                         if ((tblock = cfg->cil_offset_to_bb [ip - cfg->cil_start]) && (tblock != bblock)) {
4276                                 link_bblock (cfg, bblock, tblock);
4277                                 if (sp != stack_start) {
4278                                         handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
4279                                         sp = stack_start;
4280                                         CHECK_UNVERIFIABLE (cfg);
4281                                 }
4282                                 bblock->next_bb = tblock;
4283                                 bblock = tblock;
4284                                 for (i = 0; i < bblock->in_scount; ++i) {
4285                                         if (cfg->verbose_level > 3)
4286                                                 g_print ("loading %d from temp %d\n", i, (int)bblock->in_stack [i]->inst_c0);                                           
4287                                         NEW_TEMPLOAD (cfg, ins, bblock->in_stack [i]->inst_c0);
4288                                         *sp++ = ins;
4289                                 }
4290                                 g_slist_free (class_inits);
4291                                 class_inits = NULL;
4292                         }
4293                 }
4294
4295                 bblock->real_offset = real_offset;
4296
4297                 if ((cfg->method == method) && cfg->coverage_info) {
4298                         MonoInst *store, *one;
4299                         guint32 cil_offset = ip - header->code;
4300                         cfg->coverage_info->data [cil_offset].cil_code = ip;
4301
4302                         /* TODO: Use an increment here */
4303                         NEW_ICONST (cfg, one, 1);
4304                         one->cil_code = ip;
4305
4306                         NEW_PCONST (cfg, ins, &(cfg->coverage_info->data [cil_offset].count));
4307                         ins->cil_code = ip;
4308
4309                         MONO_INST_NEW (cfg, store, CEE_STIND_I);
4310                         store->cil_code = ip;
4311                         store->inst_left = ins;
4312                         store->inst_right = one;
4313
4314                         MONO_ADD_INS (bblock, store);
4315                 }
4316
4317                 if (cfg->verbose_level > 3)
4318                         g_print ("converting (in B%d: stack: %d) %s", bblock->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
4319
4320                 switch (*ip) {
4321                 case CEE_NOP:
4322                         MONO_INST_NEW (cfg, ins, OP_NOP);
4323                         ins->cil_code = ip++;
4324                         MONO_ADD_INS (bblock, ins);
4325                         break;
4326                 case CEE_BREAK:
4327                         MONO_INST_NEW (cfg, ins, OP_BREAK);
4328                         ins->cil_code = ip++;
4329                         MONO_ADD_INS (bblock, ins);
4330                         break;
4331                 case CEE_LDARG_0:
4332                 case CEE_LDARG_1:
4333                 case CEE_LDARG_2:
4334                 case CEE_LDARG_3:
4335                         CHECK_STACK_OVF (1);
4336                         n = (*ip)-CEE_LDARG_0;
4337                         CHECK_ARG (n);
4338                         NEW_ARGLOAD (cfg, ins, n);
4339                         LDARG_SOFT_FLOAT (cfg, ins, n, ip);
4340                         ins->cil_code = ip++;
4341                         *sp++ = ins;
4342                         break;
4343                 case CEE_LDLOC_0:
4344                 case CEE_LDLOC_1:
4345                 case CEE_LDLOC_2:
4346                 case CEE_LDLOC_3:
4347                         CHECK_STACK_OVF (1);
4348                         n = (*ip)-CEE_LDLOC_0;
4349                         CHECK_LOCAL (n);
4350                         NEW_LOCLOAD (cfg, ins, n);
4351                         LDLOC_SOFT_FLOAT (cfg, ins, n, ip);
4352                         ins->cil_code = ip++;
4353                         *sp++ = ins;
4354                         break;
4355                 case CEE_STLOC_0:
4356                 case CEE_STLOC_1:
4357                 case CEE_STLOC_2:
4358                 case CEE_STLOC_3:
4359                         CHECK_STACK (1);
4360                         n = (*ip)-CEE_STLOC_0;
4361                         CHECK_LOCAL (n);
4362                         --sp;
4363                         handle_loaded_temps (cfg, bblock, stack_start, sp);
4364                         NEW_LOCSTORE (cfg, ins, n, *sp);
4365                         ins->cil_code = ip;
4366                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
4367                                 UNVERIFIED;
4368                         STLOC_SOFT_FLOAT (cfg, ins, n, ip);
4369                         if (ins->opcode == CEE_STOBJ) {
4370                                 NEW_LOCLOADA (cfg, ins, n);
4371                                 handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE, FALSE);
4372                         } else
4373                                 MONO_ADD_INS (bblock, ins);
4374                         ++ip;
4375                         inline_costs += 1;
4376                         break;
4377                 case CEE_LDARG_S:
4378                         CHECK_OPSIZE (2);
4379                         CHECK_STACK_OVF (1);
4380                         CHECK_ARG (ip [1]);
4381                         NEW_ARGLOAD (cfg, ins, ip [1]);
4382                         LDARG_SOFT_FLOAT (cfg, ins, ip [1], ip);
4383                         ins->cil_code = ip;
4384                         *sp++ = ins;
4385                         ip += 2;
4386                         break;
4387                 case CEE_LDARGA_S:
4388                         CHECK_OPSIZE (2);
4389                         CHECK_STACK_OVF (1);
4390                         CHECK_ARG (ip [1]);
4391                         NEW_ARGLOADA (cfg, ins, ip [1]);
4392                         ins->cil_code = ip;
4393                         *sp++ = ins;
4394                         ip += 2;
4395                         break;
4396                 case CEE_STARG_S:
4397                         CHECK_OPSIZE (2);
4398                         CHECK_STACK (1);
4399                         --sp;
4400                         CHECK_ARG (ip [1]);
4401                         NEW_ARGSTORE (cfg, ins, ip [1], *sp);
4402                         handle_loaded_temps (cfg, bblock, stack_start, sp);
4403                         ins->cil_code = ip;
4404                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [ip [1]], *sp))
4405                                 UNVERIFIED;
4406                         STARG_SOFT_FLOAT (cfg, ins, ip [1], ip);
4407                         if (ins->opcode == CEE_STOBJ) {
4408                                 NEW_ARGLOADA (cfg, ins, ip [1]);
4409                                 handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE, FALSE);
4410                         } else
4411                                 MONO_ADD_INS (bblock, ins);
4412                         ip += 2;
4413                         break;
4414                 case CEE_LDLOC_S:
4415                         CHECK_OPSIZE (2);
4416                         CHECK_STACK_OVF (1);
4417                         CHECK_LOCAL (ip [1]);
4418                         NEW_LOCLOAD (cfg, ins, ip [1]);
4419                         LDLOC_SOFT_FLOAT (cfg, ins, ip [1], ip);
4420                         ins->cil_code = ip;
4421                         *sp++ = ins;
4422                         ip += 2;
4423                         break;
4424                 case CEE_LDLOCA_S:
4425                         CHECK_OPSIZE (2);
4426                         CHECK_STACK_OVF (1);
4427                         CHECK_LOCAL (ip [1]);
4428                         NEW_LOCLOADA (cfg, ins, ip [1]);
4429                         ins->cil_code = ip;
4430                         *sp++ = ins;
4431                         ip += 2;
4432                         break;
4433                 case CEE_STLOC_S:
4434                         CHECK_OPSIZE (2);
4435                         CHECK_STACK (1);
4436                         --sp;
4437                         handle_loaded_temps (cfg, bblock, stack_start, sp);
4438                         CHECK_LOCAL (ip [1]);
4439                         NEW_LOCSTORE (cfg, ins, ip [1], *sp);
4440                         ins->cil_code = ip;
4441                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [ip [1]], *sp))
4442                                 UNVERIFIED;
4443                         STLOC_SOFT_FLOAT (cfg, ins, ip [1], ip);
4444                         if (ins->opcode == CEE_STOBJ) {
4445                                 NEW_LOCLOADA (cfg, ins, ip [1]);
4446                                 handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE, FALSE);
4447                         } else
4448                                 MONO_ADD_INS (bblock, ins);
4449                         ip += 2;
4450                         inline_costs += 1;
4451                         break;
4452                 case CEE_LDNULL:
4453                         CHECK_STACK_OVF (1);
4454                         NEW_PCONST (cfg, ins, NULL);
4455                         ins->cil_code = ip;
4456                         ins->type = STACK_OBJ;
4457                         ++ip;
4458                         *sp++ = ins;
4459                         break;
4460                 case CEE_LDC_I4_M1:
4461                         CHECK_STACK_OVF (1);
4462                         NEW_ICONST (cfg, ins, -1);
4463                         ins->cil_code = ip;
4464                         ++ip;
4465                         *sp++ = ins;
4466                         break;
4467                 case CEE_LDC_I4_0:
4468                 case CEE_LDC_I4_1:
4469                 case CEE_LDC_I4_2:
4470                 case CEE_LDC_I4_3:
4471                 case CEE_LDC_I4_4:
4472                 case CEE_LDC_I4_5:
4473                 case CEE_LDC_I4_6:
4474                 case CEE_LDC_I4_7:
4475                 case CEE_LDC_I4_8:
4476                         CHECK_STACK_OVF (1);
4477                         NEW_ICONST (cfg, ins, (*ip) - CEE_LDC_I4_0);
4478                         ins->cil_code = ip;
4479                         ++ip;
4480                         *sp++ = ins;
4481                         break;
4482                 case CEE_LDC_I4_S:
4483                         CHECK_OPSIZE (2);
4484                         CHECK_STACK_OVF (1);
4485                         ++ip;
4486                         NEW_ICONST (cfg, ins, *((signed char*)ip));
4487                         ins->cil_code = ip;
4488                         ++ip;
4489                         *sp++ = ins;
4490                         break;
4491                 case CEE_LDC_I4:
4492                         CHECK_OPSIZE (5);
4493                         CHECK_STACK_OVF (1);
4494                         NEW_ICONST (cfg, ins, (gint32)read32 (ip + 1));
4495                         ins->cil_code = ip;
4496                         ip += 5;
4497                         *sp++ = ins;
4498                         break;
4499                 case CEE_LDC_I8:
4500                         CHECK_OPSIZE (9);
4501                         CHECK_STACK_OVF (1);
4502                         MONO_INST_NEW (cfg, ins, OP_I8CONST);
4503                         ins->cil_code = ip;
4504                         ins->type = STACK_I8;
4505                         ++ip;
4506                         ins->inst_l = (gint64)read64 (ip);
4507                         ip += 8;
4508                         *sp++ = ins;
4509                         break;
4510                 case CEE_LDC_R4: {
4511                         float *f;
4512                         /* we should really allocate this only late in the compilation process */
4513                         mono_domain_lock (cfg->domain);
4514                         f = mono_mempool_alloc (cfg->domain->mp, sizeof (float));
4515                         mono_domain_unlock (cfg->domain);
4516                         CHECK_OPSIZE (5);
4517                         CHECK_STACK_OVF (1);
4518                         MONO_INST_NEW (cfg, ins, OP_R4CONST);
4519                         ins->type = STACK_R8;
4520                         ++ip;
4521                         readr4 (ip, f);
4522                         ins->inst_p0 = f;
4523
4524                         ip += 4;
4525                         *sp++ = ins;                    
4526                         break;
4527                 }
4528                 case CEE_LDC_R8: {
4529                         double *d;
4530                         mono_domain_lock (cfg->domain);
4531                         d = mono_mempool_alloc (cfg->domain->mp, sizeof (double));
4532                         mono_domain_unlock (cfg->domain);
4533                         CHECK_OPSIZE (9);
4534                         CHECK_STACK_OVF (1);
4535                         MONO_INST_NEW (cfg, ins, OP_R8CONST);
4536                         ins->type = STACK_R8;
4537                         ++ip;
4538                         readr8 (ip, d);
4539                         ins->inst_p0 = d;
4540
4541                         ip += 8;
4542                         *sp++ = ins;                    
4543                         break;
4544                 }
4545                 case CEE_DUP: {
4546                         MonoInst *temp, *store;
4547                         CHECK_STACK (1);
4548                         CHECK_STACK_OVF (1);
4549                         sp--;
4550                         ins = *sp;
4551                 
4552                         /* 
4553                          * small optimization: if the loaded value was from a local already,
4554                          * just load it twice.
4555                          */
4556                         if (ins->ssa_op == MONO_SSA_LOAD && 
4557                             (ins->inst_i0->opcode == OP_LOCAL || ins->inst_i0->opcode == OP_ARG)) {
4558                                 sp++;
4559                                 MONO_INST_NEW (cfg, temp, 0);
4560                                 *temp = *ins;
4561                                 temp->cil_code = ip;
4562                                 *sp++ = temp;
4563                         } else {
4564                                 temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
4565                                 temp->flags |= MONO_INST_IS_TEMP;
4566                                 temp->cil_code = ip;
4567                                 NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
4568                                 store->cil_code = ip;
4569                                 if (store->opcode == CEE_STOBJ) {
4570                                         NEW_TEMPLOADA (cfg, store, temp->inst_c0);
4571                                         handle_stobj (cfg, bblock, store, sp [0], sp [0]->cil_code, store->klass, TRUE, FALSE, FALSE);
4572                                 } else {
4573                                         MONO_ADD_INS (bblock, store);
4574                                 }
4575                                 NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
4576                                 *sp++ = ins;
4577                                 ins->cil_code = ip;
4578                                 NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
4579                                 *sp++ = ins;
4580                                 ins->cil_code = ip;
4581                         }
4582                         ++ip;
4583                         inline_costs += 2;
4584                         break;
4585                 }
4586                 case CEE_POP:
4587                         CHECK_STACK (1);
4588                         MONO_INST_NEW (cfg, ins, CEE_POP);
4589                         MONO_ADD_INS (bblock, ins);
4590                         ins->cil_code = ip++;
4591                         --sp;
4592                         ins->inst_i0 = *sp;
4593                         break;
4594                 case CEE_JMP:
4595                         CHECK_OPSIZE (5);
4596                         if (stack_start != sp)
4597                                 UNVERIFIED;
4598                         MONO_INST_NEW (cfg, ins, OP_JMP);
4599                         token = read32 (ip + 1);
4600                         /* FIXME: check the signature matches */
4601                         cmethod = mini_get_method (method, token, NULL, generic_context);
4602
4603                         if (!cmethod)
4604                                 goto load_error;
4605
4606                         if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS) {
4607                                 if (check_linkdemand (cfg, method, cmethod, bblock, ip))
4608                                         INLINE_FAILURE;
4609                                 CHECK_CFG_EXCEPTION;
4610                         }
4611
4612                         ins->inst_p0 = cmethod;
4613                         MONO_ADD_INS (bblock, ins);
4614                         ip += 5;
4615                         start_new_bblock = 1;
4616                         break;
4617                 case CEE_CALLI:
4618                 case CEE_CALL:
4619                 case CEE_CALLVIRT: {
4620                         MonoInst *addr = NULL;
4621                         MonoMethodSignature *fsig = NULL;
4622                         int temp, array_rank = 0;
4623                         int virtual = *ip == CEE_CALLVIRT;
4624
4625                         CHECK_OPSIZE (5);
4626                         token = read32 (ip + 1);
4627
4628                         if (*ip == CEE_CALLI) {
4629                                 cmethod = NULL;
4630                                 CHECK_STACK (1);
4631                                 --sp;
4632                                 addr = *sp;
4633                                 if (method->wrapper_type != MONO_WRAPPER_NONE)
4634                                         fsig = (MonoMethodSignature *)mono_method_get_wrapper_data (method, token);
4635                                 else
4636                                         fsig = mono_metadata_parse_signature (image, token);
4637
4638                                 n = fsig->param_count + fsig->hasthis;
4639                         } else {
4640                                 MonoMethod *cil_method;
4641                                 
4642                                 if (method->wrapper_type != MONO_WRAPPER_NONE) {
4643                                         cmethod =  (MonoMethod *)mono_method_get_wrapper_data (method, token);
4644                                         cil_method = cmethod;
4645                                 } else if (constrained_call) {
4646                                         cmethod = mono_get_method_constrained (image, token, constrained_call, generic_context, &cil_method);
4647                                         cil_method = cmethod;
4648                                 } else {
4649                                         cmethod = mini_get_method (method, token, NULL, generic_context);
4650                                         cil_method = cmethod;
4651                                 }
4652
4653                                 if (!cmethod)
4654                                         goto load_error;
4655                                 if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_method (method, cil_method))
4656                                         UNVERIFIED;
4657
4658                                 if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR)
4659                                         ensure_method_is_allowed_to_call_method (cfg, method, cil_method, bblock, ip);
4660
4661                                 if (!virtual && (cmethod->flags & METHOD_ATTRIBUTE_ABSTRACT))
4662                                         /* MS.NET seems to silently convert this to a callvirt */
4663                                         virtual = 1;
4664
4665                                 if (!cmethod->klass->inited){
4666                                         if (!mono_class_init (cmethod->klass))
4667                                                 goto load_error;
4668                                 }
4669
4670                                 if (mono_method_signature (cmethod)->pinvoke) {
4671                                         MonoMethod *wrapper = mono_marshal_get_native_wrapper (cmethod);
4672                                         fsig = mono_method_signature (wrapper);
4673                                 } else if (constrained_call) {
4674                                         fsig = mono_method_signature (cmethod);
4675                                 } else {
4676                                         fsig = mono_method_get_signature_full (cmethod, image, token, generic_context);
4677                                 }
4678
4679                                 mono_save_token_info (cfg, image, token, cmethod);
4680
4681                                 n = fsig->param_count + fsig->hasthis;
4682
4683                                 if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS) {
4684                                         if (check_linkdemand (cfg, method, cmethod, bblock, ip))
4685                                                 INLINE_FAILURE;
4686                                         CHECK_CFG_EXCEPTION;
4687                                 }
4688
4689                                 if (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL &&
4690                                     mini_class_is_system_array (cmethod->klass)) {
4691                                         array_rank = cmethod->klass->rank;
4692                                 }
4693
4694                                 if (cmethod->string_ctor)
4695                                         g_assert_not_reached ();
4696
4697                         }
4698
4699                         if (cmethod && cmethod->klass->generic_container)
4700                                 UNVERIFIED;
4701
4702                         CHECK_STACK (n);
4703
4704                         //g_assert (!virtual || fsig->hasthis);
4705
4706                         sp -= n;
4707
4708                         if (constrained_call) {
4709                                 /*
4710                                  * We have the `constrained.' prefix opcode.
4711                                  */
4712                                 if (constrained_call->valuetype && !cmethod->klass->valuetype) {
4713                                         MonoInst *load;
4714                                         /*
4715                                          * The type parameter is instantiated as a valuetype,
4716                                          * but that type doesn't override the method we're
4717                                          * calling, so we need to box `this'.
4718                                          * sp [0] is a pointer to the data: we need the value
4719                                          * in handle_box (), so load it here.
4720                                          */
4721                                         MONO_INST_NEW (cfg, load, mono_type_to_ldind (&constrained_call->byval_arg));
4722                                         type_to_eval_stack_type (&constrained_call->byval_arg, load);
4723                                         load->cil_code = ip;
4724                                         load->inst_left = sp [0];
4725                                         sp [0] = handle_box (cfg, bblock, load, ip, constrained_call);
4726                                 } else if (!constrained_call->valuetype) {
4727                                         MonoInst *ins;
4728
4729                                         /*
4730                                          * The type parameter is instantiated as a reference
4731                                          * type.  We have a managed pointer on the stack, so
4732                                          * we need to dereference it here.
4733                                          */
4734
4735                                         MONO_INST_NEW (cfg, ins, CEE_LDIND_REF);
4736                                         ins->cil_code = ip;
4737                                         ins->inst_i0 = sp [0];
4738                                         ins->type = STACK_OBJ;
4739                                         ins->klass = mono_class_from_mono_type (&constrained_call->byval_arg);
4740                                         sp [0] = ins;
4741                                 } else if (cmethod->klass->valuetype)
4742                                         virtual = 0;
4743                                 constrained_call = NULL;
4744                         }
4745
4746                         if (*ip != CEE_CALLI && check_call_signature (cfg, fsig, sp))
4747                                 UNVERIFIED;
4748
4749                         if (cmethod && virtual && 
4750                             (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) && 
4751                             !((cmethod->flags & METHOD_ATTRIBUTE_FINAL) && 
4752                               cmethod->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK) &&
4753                             mono_method_signature (cmethod)->generic_param_count) {
4754                                 MonoInst *this_temp, *this_arg_temp, *store;
4755                                 MonoInst *iargs [4];
4756
4757                                 g_assert (mono_method_signature (cmethod)->is_inflated);
4758                                 /* Prevent inlining of methods that contain indirect calls */
4759                                 INLINE_FAILURE;
4760
4761                                 this_temp = mono_compile_create_var (cfg, type_from_stack_type (sp [0]), OP_LOCAL);
4762                                 this_temp->cil_code = ip;
4763                                 NEW_TEMPSTORE (cfg, store, this_temp->inst_c0, sp [0]);
4764
4765                                 store->cil_code = ip;
4766                                 MONO_ADD_INS (bblock, store);
4767
4768                                 /* FIXME: This should be a managed pointer */
4769                                 this_arg_temp = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
4770                                 this_arg_temp->cil_code = ip;
4771
4772                                 /* Because of the PCONST below */
4773                                 cfg->disable_aot = TRUE;
4774                                 NEW_TEMPLOAD (cfg, iargs [0], this_temp->inst_c0);
4775                                 NEW_METHODCONST (cfg, iargs [1], cmethod);
4776                                 NEW_PCONST (cfg, iargs [2], mono_method_get_context (cmethod));
4777                                 NEW_TEMPLOADA (cfg, iargs [3], this_arg_temp->inst_c0);
4778                                 temp = mono_emit_jit_icall (cfg, bblock, mono_helper_compile_generic_method, iargs, ip);
4779
4780                                 NEW_TEMPLOAD (cfg, addr, temp);
4781                                 NEW_TEMPLOAD (cfg, sp [0], this_arg_temp->inst_c0);
4782
4783                                 if ((temp = mono_emit_calli (cfg, bblock, fsig, sp, addr, ip)) != -1) {
4784                                         NEW_TEMPLOAD (cfg, *sp, temp);
4785                                         sp++;
4786                                 }
4787
4788                                 ip += 5;
4789                                 ins_flag = 0;
4790                                 break;
4791                         }
4792
4793                         if ((ins_flag & MONO_INST_TAILCALL) && cmethod && (*ip == CEE_CALL) &&
4794                                  (mono_metadata_signature_equal (mono_method_signature (method), mono_method_signature (cmethod)))) {
4795                                 int i;
4796
4797                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
4798                                 INLINE_FAILURE;
4799                                 /* FIXME: This assumes the two methods has the same number and type of arguments */
4800                                 /*
4801                                  * We implement tail calls by storing the actual arguments into the 
4802                                  * argument variables, then emitting a OP_JMP. Since the actual arguments
4803                                  * can refer to the arg variables, we have to spill them.
4804                                  */
4805                                 handle_loaded_temps (cfg, bblock, sp, sp + n);
4806                                 for (i = 0; i < n; ++i) {
4807                                         /* Prevent argument from being register allocated */
4808                                         arg_array [i]->flags |= MONO_INST_VOLATILE;
4809
4810                                         /* Check if argument is the same */
4811                                         /* 
4812                                          * FIXME: This loses liveness info, so it can only be done if the
4813                                          * argument is not register allocated.
4814                                          */
4815                                         NEW_ARGLOAD (cfg, ins, i);
4816                                         if ((ins->opcode == sp [i]->opcode) && (ins->inst_i0 == sp [i]->inst_i0))
4817                                                 continue;
4818
4819                                         NEW_ARGSTORE (cfg, ins, i, sp [i]);
4820                                         ins->cil_code = ip;
4821                                         if (ins->opcode == CEE_STOBJ) {
4822                                                 NEW_ARGLOADA (cfg, ins, i);
4823                                                 handle_stobj (cfg, bblock, ins, sp [i], sp [i]->cil_code, ins->klass, FALSE, FALSE, FALSE);
4824                                         }
4825                                         else
4826                                                 MONO_ADD_INS (bblock, ins);
4827                                 }
4828                                 MONO_INST_NEW (cfg, ins, OP_JMP);
4829                                 ins->cil_code = ip;
4830                                 ins->inst_p0 = cmethod;
4831                                 ins->inst_p1 = arg_array [0];
4832                                 MONO_ADD_INS (bblock, ins);
4833                                 link_bblock (cfg, bblock, end_bblock);                  
4834                                 start_new_bblock = 1;
4835                                 /* skip CEE_RET as well */
4836                                 ip += 6;
4837                                 ins_flag = 0;
4838                                 break;
4839                         }
4840                         if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_get_inst_for_method (cfg, cmethod, fsig, sp))) {
4841                                 ins->cil_code = ip;
4842
4843                                 if (MONO_TYPE_IS_VOID (fsig->ret)) {
4844                                         MONO_ADD_INS (bblock, ins);
4845                                 } else {
4846                                         type_to_eval_stack_type (fsig->ret, ins);
4847                                         *sp = ins;
4848                                         sp++;
4849                                 }
4850
4851                                 ip += 5;
4852                                 ins_flag = 0;
4853                                 break;
4854                         }
4855
4856                         handle_loaded_temps (cfg, bblock, stack_start, sp);
4857
4858                         if ((cfg->opt & MONO_OPT_INLINE) && cmethod &&
4859                             (!virtual || !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) || (cmethod->flags & METHOD_ATTRIBUTE_FINAL)) && 
4860                             mono_method_check_inlining (cfg, cmethod) &&
4861                                  !g_list_find (dont_inline, cmethod)) {
4862                                 int costs;
4863                                 MonoBasicBlock *ebblock;
4864                                 gboolean allways = FALSE;
4865
4866                                 if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
4867                                         (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
4868                                         /* Prevent inlining of methods that call wrappers */
4869                                         INLINE_FAILURE;
4870                                         cmethod = mono_marshal_get_native_wrapper (cmethod);
4871                                         allways = TRUE;
4872                                 }
4873
4874                                 if ((costs = inline_method (cfg, cmethod, fsig, bblock, sp, ip, real_offset, dont_inline, &ebblock, allways))) {
4875                                         ip += 5;
4876                                         real_offset += 5;
4877
4878                                         GET_BBLOCK (cfg, bblock, ip);
4879                                         ebblock->next_bb = bblock;
4880                                         link_bblock (cfg, ebblock, bblock);
4881
4882                                         if (!MONO_TYPE_IS_VOID (fsig->ret))
4883                                                 sp++;
4884
4885                                         /* indicates start of a new block, and triggers a load of all 
4886                                            stack arguments at bb boundarie */
4887                                         bblock = ebblock;
4888
4889                                         inline_costs += costs;
4890                                         ins_flag = 0;
4891                                         break;
4892                                 }
4893                         }
4894                         
4895                         inline_costs += 10 * num_calls++;
4896
4897                         /* tail recursion elimination */
4898                         if ((cfg->opt & MONO_OPT_TAILC) && *ip == CEE_CALL && cmethod == method && ip [5] == CEE_RET) {
4899                                 gboolean has_vtargs = FALSE;
4900                                 int i;
4901                                 
4902                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
4903                                 INLINE_FAILURE;
4904                                 /* keep it simple */
4905                                 for (i =  fsig->param_count - 1; i >= 0; i--) {
4906                                         if (MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->params [i])) 
4907                                                 has_vtargs = TRUE;
4908                                 }
4909
4910                                 if (!has_vtargs) {
4911                                         for (i = 0; i < n; ++i) {
4912                                                 NEW_ARGSTORE (cfg, ins, i, sp [i]);
4913                                                 ins->cil_code = ip;
4914                                                 MONO_ADD_INS (bblock, ins);
4915                                         }
4916                                         MONO_INST_NEW (cfg, ins, OP_BR);
4917                                         ins->cil_code = ip;
4918                                         MONO_ADD_INS (bblock, ins);
4919                                         tblock = start_bblock->out_bb [0];
4920                                         link_bblock (cfg, bblock, tblock);
4921                                         ins->inst_target_bb = tblock;
4922                                         start_new_bblock = 1;
4923
4924                                         /* skip the CEE_RET, too */
4925                                         if (ip_in_bb (cfg, bblock, ip + 5))
4926                                                 ip += 6;
4927                                         else
4928                                                 ip += 5;
4929                                         ins_flag = 0;
4930                                         break;
4931                                 }
4932                         }
4933
4934                         if (*ip == CEE_CALLI) {
4935                                 /* Prevent inlining of methods with indirect calls */
4936                                 INLINE_FAILURE;
4937                                 if ((temp = mono_emit_calli (cfg, bblock, fsig, sp, addr, ip)) != -1) {
4938                                         NEW_TEMPLOAD (cfg, *sp, temp);
4939                                         sp++;
4940                                 }                                       
4941                         } else if (array_rank) {
4942                                 MonoInst *addr;
4943
4944                                 if (strcmp (cmethod->name, "Set") == 0) { /* array Set */ 
4945                                         if (sp [fsig->param_count]->type == STACK_OBJ) {
4946                                                 MonoInst *iargs [2];
4947                                                 MonoInst *array, *to_store, *store;
4948
4949                                                 handle_loaded_temps (cfg, bblock, stack_start, sp);
4950                                                 
4951                                                 array = mono_compile_create_var (cfg, type_from_stack_type (sp [0]), OP_LOCAL);
4952                                                 NEW_TEMPSTORE (cfg, store, array->inst_c0, sp [0]);
4953                                                 store->cil_code = ip;
4954                                                 MONO_ADD_INS (bblock, store);
4955                                                 NEW_TEMPLOAD (cfg, iargs [0], array->inst_c0);
4956
4957                                                 to_store = mono_compile_create_var (cfg, type_from_stack_type (sp [fsig->param_count]), OP_LOCAL);
4958                                                 NEW_TEMPSTORE (cfg, store, to_store->inst_c0, sp [fsig->param_count]);
4959                                                 store->cil_code = ip;
4960                                                 MONO_ADD_INS (bblock, store);
4961                                                 NEW_TEMPLOAD (cfg, iargs [1], to_store->inst_c0);
4962
4963                                                 /*
4964                                                  * We first save the args for the call so that the args are copied to the stack
4965                                                  * and a new instruction tree for them is created. If we don't do this,
4966                                                  * the same MonoInst is added to two different trees and this is not 
4967                                                  * allowed by burg.
4968                                                  */
4969                                                 mono_emit_jit_icall (cfg, bblock, mono_helper_stelem_ref_check, iargs, ip);
4970
4971                                                 NEW_TEMPLOAD (cfg, sp [0], array->inst_c0);
4972                                                 NEW_TEMPLOAD (cfg, sp [fsig->param_count], to_store->inst_c0);
4973                                         }
4974
4975                                         addr = mini_get_ldelema_ins (cfg, bblock, cmethod, sp, ip, TRUE);
4976                                         NEW_INDSTORE (cfg, ins, addr, sp [fsig->param_count], fsig->params [fsig->param_count - 1]);
4977                                         ins->cil_code = ip;
4978                                         if (ins->opcode == CEE_STOBJ) {
4979                                                 handle_stobj (cfg, bblock, addr, sp [fsig->param_count], ip, mono_class_from_mono_type (fsig->params [fsig->param_count-1]), FALSE, FALSE, TRUE);
4980                                         } else {
4981                                                 MONO_ADD_INS (bblock, ins);
4982                                         }
4983
4984                                 } else if (strcmp (cmethod->name, "Get") == 0) { /* array Get */
4985                                         addr = mini_get_ldelema_ins (cfg, bblock, cmethod, sp, ip, FALSE);
4986                                         NEW_INDLOAD (cfg, ins, addr, fsig->ret);
4987                                         ins->cil_code = ip;
4988
4989                                         *sp++ = ins;
4990                                 } else if (strcmp (cmethod->name, "Address") == 0) { /* array Address */
4991                                         addr = mini_get_ldelema_ins (cfg, bblock, cmethod, sp, ip, FALSE);
4992                                         *sp++ = addr;
4993                                 } else {
4994                                         g_assert_not_reached ();
4995                                 }
4996
4997                         } else {
4998                                 /* Prevent inlining of methods which call other methods */
4999                                 INLINE_FAILURE;
5000                                 if (ip_in_bb (cfg, bblock, ip + 5) 
5001                                     && (!MONO_TYPE_ISSTRUCT (fsig->ret))
5002                                     && (!MONO_TYPE_IS_VOID (fsig->ret) || cmethod->string_ctor)
5003                                     && (CODE_IS_STLOC (ip + 5) || ip [5] == CEE_POP || ip [5] == CEE_RET)) {
5004                                         /* no need to spill */
5005                                         ins = (MonoInst*)mono_emit_method_call (cfg, bblock, cmethod, fsig, sp, ip, virtual ? sp [0] : NULL);
5006                                         *sp++ = ins;
5007                                 } else {
5008                                         if ((temp = mono_emit_method_call_spilled (cfg, bblock, cmethod, fsig, sp, ip, virtual ? sp [0] : NULL)) != -1) {
5009                                                 NEW_TEMPLOAD (cfg, *sp, temp);
5010                                                 sp++;
5011                                         }
5012                                 }
5013                         }
5014
5015                         ip += 5;
5016                         ins_flag = 0;
5017                         break;
5018                 }
5019                 case CEE_RET:
5020                         if (cfg->method != method) {
5021                                 /* return from inlined methode */
5022                                 if (return_var) {
5023                                         MonoInst *store;
5024                                         CHECK_STACK (1);
5025                                         --sp;
5026                                         //g_assert (returnvar != -1);
5027                                         NEW_TEMPSTORE (cfg, store, return_var->inst_c0, *sp);
5028                                         store->cil_code = sp [0]->cil_code;
5029                                         if (store->opcode == CEE_STOBJ) {
5030                                                 g_assert_not_reached ();
5031                                                 NEW_TEMPLOADA (cfg, store, return_var->inst_c0);
5032                                                 /* FIXME: it is possible some optimization will pass the a heap pointer for the struct address, so we'll need the write barrier */
5033                                                 handle_stobj (cfg, bblock, store, *sp, sp [0]->cil_code, return_var->klass, FALSE, FALSE, FALSE);
5034                                         } else
5035                                                 MONO_ADD_INS (bblock, store);
5036                                 } 
5037                         } else {
5038                                 if (cfg->ret) {
5039                                         g_assert (!return_var);
5040                                         CHECK_STACK (1);
5041                                         --sp;
5042                                         MONO_INST_NEW (cfg, ins, OP_NOP);
5043                                         ins->opcode = mono_type_to_stind (mono_method_signature (method)->ret);
5044                                         if (ins->opcode == CEE_STOBJ) {
5045                                                 NEW_RETLOADA (cfg, ins);
5046                                                 /* FIXME: it is possible some optimization will pass the a heap pointer for the struct address, so we'll need the write barrier */
5047                                                 handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE, FALSE);
5048                                         } else {
5049                                                 ins->opcode = OP_SETRET;
5050                                                 ins->cil_code = ip;
5051                                                 ins->inst_i0 = *sp;;
5052                                                 ins->inst_i1 = NULL;
5053                                                 MONO_ADD_INS (bblock, ins);
5054                                         }
5055                                 }
5056                         }
5057                         if (sp != stack_start)
5058                                 UNVERIFIED;
5059                         MONO_INST_NEW (cfg, ins, OP_BR);
5060                         ins->cil_code = ip++;
5061                         ins->inst_target_bb = end_bblock;
5062                         MONO_ADD_INS (bblock, ins);
5063                         link_bblock (cfg, bblock, end_bblock);
5064                         start_new_bblock = 1;
5065                         break;
5066                 case CEE_BR_S:
5067                         CHECK_OPSIZE (2);
5068                         MONO_INST_NEW (cfg, ins, OP_BR);
5069                         ins->cil_code = ip++;
5070                         MONO_ADD_INS (bblock, ins);
5071                         target = ip + 1 + (signed char)(*ip);
5072                         ++ip;
5073                         GET_BBLOCK (cfg, tblock, target);
5074                         link_bblock (cfg, bblock, tblock);
5075                         CHECK_BBLOCK (target, ip, tblock);
5076                         ins->inst_target_bb = tblock;
5077                         if (sp != stack_start) {
5078                                 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
5079                                 sp = stack_start;
5080                                 CHECK_UNVERIFIABLE (cfg);
5081                         }
5082                         start_new_bblock = 1;
5083                         inline_costs += BRANCH_COST;
5084                         break;
5085                 case CEE_BRFALSE_S:
5086                 case CEE_BRTRUE_S:
5087                         CHECK_OPSIZE (2);
5088                         CHECK_STACK (1);
5089                         if (sp [-1]->type == STACK_VTYPE || sp [-1]->type == STACK_R8)
5090                                 UNVERIFIED;
5091                         MONO_INST_NEW (cfg, ins, *ip + BIG_BRANCH_OFFSET);
5092                         ins->cil_code = ip++;
5093                         target = ip + 1 + *(signed char*)ip;
5094                         ip++;
5095                         ADD_UNCOND (ins->opcode == CEE_BRTRUE);
5096                         if (sp != stack_start) {
5097                                 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
5098                                 sp = stack_start;
5099                                 CHECK_UNVERIFIABLE (cfg);
5100                         }
5101                         inline_costs += BRANCH_COST;
5102                         break;
5103                 case CEE_BEQ_S:
5104                 case CEE_BGE_S:
5105                 case CEE_BGT_S:
5106                 case CEE_BLE_S:
5107                 case CEE_BLT_S:
5108                 case CEE_BNE_UN_S:
5109                 case CEE_BGE_UN_S:
5110                 case CEE_BGT_UN_S:
5111                 case CEE_BLE_UN_S:
5112                 case CEE_BLT_UN_S:
5113                         CHECK_OPSIZE (2);
5114                         CHECK_STACK (2);
5115                         MONO_INST_NEW (cfg, ins, *ip + BIG_BRANCH_OFFSET);
5116                         ins->cil_code = ip++;
5117                         target = ip + 1 + *(signed char*)ip;
5118                         ip++;
5119 #ifdef MONO_ARCH_SOFT_FLOAT
5120                         if (sp [-1]->type == STACK_R8 || sp [-2]->type == STACK_R8) {
5121                                 ins->opcode = condbr_to_fp_br (ins->opcode);
5122                                 sp -= 2;
5123                                 ins->inst_left = sp [0];
5124                                 ins->inst_right = sp [1];
5125                                 ins->type = STACK_I4;
5126                                 *sp++ = emit_tree (cfg, bblock, ins, ins->cil_code);
5127                                 MONO_INST_NEW (cfg, ins, CEE_BRTRUE);
5128                                 ADD_UNCOND (TRUE);
5129                         } else {
5130                                 ADD_BINCOND (NULL);
5131                         }
5132 #else
5133                         ADD_BINCOND (NULL);
5134 #endif
5135                         if (sp != stack_start) {
5136                                 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
5137                                 sp = stack_start;
5138                                 CHECK_UNVERIFIABLE (cfg);
5139                         }
5140                         inline_costs += BRANCH_COST;
5141                         break;
5142                 case CEE_BR:
5143                         CHECK_OPSIZE (5);
5144                         MONO_INST_NEW (cfg, ins, OP_BR);
5145                         ins->cil_code = ip++;
5146                         MONO_ADD_INS (bblock, ins);
5147                         target = ip + 4 + (gint32)read32(ip);
5148                         ip += 4;
5149                         GET_BBLOCK (cfg, tblock, target);
5150                         link_bblock (cfg, bblock, tblock);
5151                         CHECK_BBLOCK (target, ip, tblock);
5152                         ins->inst_target_bb = tblock;
5153                         if (sp != stack_start) {
5154                                 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
5155                                 sp = stack_start;
5156                                 CHECK_UNVERIFIABLE (cfg);
5157                         }
5158                         start_new_bblock = 1;
5159                         inline_costs += BRANCH_COST;
5160                         break;
5161                 case CEE_BRFALSE:
5162                 case CEE_BRTRUE:
5163                         CHECK_OPSIZE (5);
5164                         CHECK_STACK (1);
5165                         if (sp [-1]->type == STACK_VTYPE || sp [-1]->type == STACK_R8)
5166                                 UNVERIFIED;
5167                         MONO_INST_NEW (cfg, ins, *ip);
5168                         ins->cil_code = ip++;
5169                         target = ip + 4 + (gint32)read32(ip);
5170                         ip += 4;
5171                         ADD_UNCOND(ins->opcode == CEE_BRTRUE);
5172                         if (sp != stack_start) {
5173                                 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
5174                                 sp = stack_start;
5175                                 CHECK_UNVERIFIABLE (cfg);
5176                         }
5177                         inline_costs += BRANCH_COST;
5178                         break;
5179                 case CEE_BEQ:
5180                 case CEE_BGE:
5181                 case CEE_BGT:
5182                 case CEE_BLE:
5183                 case CEE_BLT:
5184                 case CEE_BNE_UN:
5185                 case CEE_BGE_UN:
5186                 case CEE_BGT_UN:
5187                 case CEE_BLE_UN:
5188                 case CEE_BLT_UN:
5189                         CHECK_OPSIZE (5);
5190                         CHECK_STACK (2);
5191                         MONO_INST_NEW (cfg, ins, *ip);
5192                         ins->cil_code = ip++;
5193                         target = ip + 4 + (gint32)read32(ip);
5194                         ip += 4;
5195 #ifdef MONO_ARCH_SOFT_FLOAT
5196                         if (sp [-1]->type == STACK_R8 || sp [-2]->type == STACK_R8) {
5197                                 ins->opcode = condbr_to_fp_br (ins->opcode);
5198                                 sp -= 2;
5199                                 ins->inst_left = sp [0];
5200                                 ins->inst_right = sp [1];
5201                                 ins->type = STACK_I4;
5202                                 *sp++ = emit_tree (cfg, bblock, ins, ins->cil_code);
5203                                 MONO_INST_NEW (cfg, ins, CEE_BRTRUE);
5204                                 ADD_UNCOND (TRUE);
5205                         } else {
5206                                 ADD_BINCOND (NULL);
5207                         }
5208 #else
5209                         ADD_BINCOND (NULL);
5210 #endif
5211                         if (sp != stack_start) {
5212                                 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
5213                                 sp = stack_start;
5214                                 CHECK_UNVERIFIABLE (cfg);
5215                         }
5216                         inline_costs += BRANCH_COST;
5217                         break;
5218                 case CEE_SWITCH:
5219                         CHECK_OPSIZE (5);
5220                         CHECK_STACK (1);
5221                         n = read32 (ip + 1);
5222                         MONO_INST_NEW (cfg, ins, *ip);
5223                         --sp;
5224                         ins->inst_left = *sp;
5225                         if ((ins->inst_left->type != STACK_I4) && (ins->inst_left->type != STACK_PTR)) 
5226                                 UNVERIFIED;
5227                         ins->cil_code = ip;
5228                         ip += 5;
5229                         CHECK_OPSIZE (n * sizeof (guint32));
5230                         target = ip + n * sizeof (guint32);
5231                         MONO_ADD_INS (bblock, ins);
5232                         GET_BBLOCK (cfg, tblock, target);
5233                         link_bblock (cfg, bblock, tblock);
5234                         ins->klass = GUINT_TO_POINTER (n);
5235                         ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * (n + 1));
5236                         ins->inst_many_bb [n] = tblock;
5237
5238                         for (i = 0; i < n; ++i) {
5239                                 GET_BBLOCK (cfg, tblock, target + (gint32)read32(ip));
5240                                 link_bblock (cfg, bblock, tblock);
5241                                 ins->inst_many_bb [i] = tblock;
5242                                 ip += 4;
5243                         }
5244                         if (sp != stack_start) {
5245                                 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
5246                                 sp = stack_start;
5247                                 CHECK_UNVERIFIABLE (cfg);
5248                         }
5249                         /* Needed by the code generated in inssel.brg */
5250                         mono_get_got_var (cfg);
5251                         inline_costs += (BRANCH_COST * 2);
5252                         break;
5253                 case CEE_LDIND_I1:
5254                 case CEE_LDIND_U1:
5255                 case CEE_LDIND_I2:
5256                 case CEE_LDIND_U2:
5257                 case CEE_LDIND_I4:
5258                 case CEE_LDIND_U4:
5259                 case CEE_LDIND_I8:
5260                 case CEE_LDIND_I:
5261                 case CEE_LDIND_R4:
5262                 case CEE_LDIND_R8:
5263                 case CEE_LDIND_REF:
5264                         CHECK_STACK (1);
5265                         MONO_INST_NEW (cfg, ins, *ip);
5266                         ins->cil_code = ip;
5267                         --sp;
5268                         ins->inst_i0 = *sp;
5269                         *sp++ = ins;
5270                         ins->type = ldind_type [*ip - CEE_LDIND_I1];
5271                         ins->flags |= ins_flag;
5272                         ins_flag = 0;
5273                         if (ins->type == STACK_OBJ)
5274                                 ins->klass = mono_defaults.object_class;
5275 #ifdef MONO_ARCH_SOFT_FLOAT
5276                         if (*ip == CEE_LDIND_R4) {
5277                                 int temp;
5278                                 --sp;
5279                                 temp = handle_load_float (cfg, bblock, ins->inst_i0, ip);
5280                                 NEW_TEMPLOAD (cfg, *sp, temp);
5281                                 sp++;
5282                         }
5283 #endif
5284                         ++ip;
5285                         break;
5286                 case CEE_STIND_REF:
5287                 case CEE_STIND_I1:
5288                 case CEE_STIND_I2:
5289                 case CEE_STIND_I4:
5290                 case CEE_STIND_I8:
5291                 case CEE_STIND_R4:
5292                 case CEE_STIND_R8:
5293                         CHECK_STACK (2);
5294 #ifdef MONO_ARCH_SOFT_FLOAT
5295                         if (*ip == CEE_STIND_R4) {
5296                                 sp -= 2;
5297                                 handle_store_float (cfg, bblock, sp [0], sp [1], ip);
5298                                 ip++;
5299                                 break;
5300                         }
5301 #endif
5302 #if HAVE_WRITE_BARRIERS
5303                         if (*ip == CEE_STIND_REF && method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER) {
5304                                 /* insert call to write barrier */
5305                                 MonoMethod *write_barrier = mono_marshal_get_write_barrier ();
5306                                 sp -= 2;
5307                                 mono_emit_method_call_spilled (cfg, bblock, write_barrier, mono_method_signature (write_barrier), sp, ip, NULL);
5308                                 ip++;
5309                                 break;
5310                         }
5311 #endif
5312                         MONO_INST_NEW (cfg, ins, *ip);
5313                         ins->cil_code = ip++;
5314                         sp -= 2;
5315                         handle_loaded_temps (cfg, bblock, stack_start, sp);
5316                         MONO_ADD_INS (bblock, ins);
5317                         ins->inst_i0 = sp [0];
5318                         ins->inst_i1 = sp [1];
5319                         ins->flags |= ins_flag;
5320                         ins_flag = 0;
5321                         inline_costs += 1;
5322                         break;
5323                 case CEE_MUL:
5324                         CHECK_STACK (2);
5325                         ADD_BINOP (*ip);
5326
5327 #ifdef MONO_ARCH_NO_EMULATE_MUL_IMM
5328                         /* FIXME: This breaks with ssapre (mono -O=ssapre loader.exe) */
5329                         if ((ins->inst_right->opcode == OP_ICONST) && !(cfg->opt & MONO_OPT_SSAPRE)) {
5330                                 switch (ins->opcode) {
5331                                 case CEE_MUL:
5332                                         ins->opcode = OP_IMUL_IMM;
5333                                         ins->inst_imm = ins->inst_right->inst_c0;
5334                                         break;
5335                                 case OP_LMUL:
5336                                         ins->opcode = OP_LMUL_IMM;
5337                                         ins->inst_imm = ins->inst_right->inst_c0;
5338                                         break;
5339                                 default:
5340                                         g_assert_not_reached ();
5341                                 }
5342                         }
5343 #endif
5344
5345                         if (mono_find_jit_opcode_emulation (ins->opcode)) {
5346                                 --sp;
5347                                 *sp++ = emit_tree (cfg, bblock, ins, ip + 1);
5348                         }
5349                         ip++;
5350                         break;
5351                 case CEE_ADD:
5352                 case CEE_SUB:
5353                 case CEE_DIV:
5354                 case CEE_DIV_UN:
5355                 case CEE_REM:
5356                 case CEE_REM_UN:
5357                 case CEE_AND:
5358                 case CEE_OR:
5359                 case CEE_XOR:
5360                 case CEE_SHL:
5361                 case CEE_SHR:
5362                 case CEE_SHR_UN:
5363                         CHECK_STACK (2);
5364                         ADD_BINOP (*ip);
5365                         /* special case that gives a nice speedup and happens to workaorund a ppc jit but (for the release)
5366                          * later apply the speedup to the left shift as well
5367                          * See BUG# 57957.
5368                          */
5369                         if ((ins->opcode == OP_LSHR_UN) && (ins->type == STACK_I8) 
5370                                         && (ins->inst_right->opcode == OP_ICONST) && (ins->inst_right->inst_c0 == 32)) {
5371                                 ins->opcode = OP_LONG_SHRUN_32;
5372                                 /*g_print ("applied long shr speedup to %s\n", cfg->method->name);*/
5373                                 ip++;
5374                                 break;
5375                         }
5376                         if (mono_find_jit_opcode_emulation (ins->opcode)) {
5377                                 --sp;
5378                                 *sp++ = emit_tree (cfg, bblock, ins, ip + 1);
5379                         }
5380                         ip++;
5381                         break;
5382                 case CEE_NEG:
5383                 case CEE_NOT:
5384                 case CEE_CONV_I1:
5385                 case CEE_CONV_I2:
5386                 case CEE_CONV_I4:
5387                 case CEE_CONV_R4:
5388                 case CEE_CONV_R8:
5389                 case CEE_CONV_U4:
5390                 case CEE_CONV_I8:
5391                 case CEE_CONV_U8:
5392                 case CEE_CONV_OVF_I8:
5393                 case CEE_CONV_OVF_U8:
5394                 case CEE_CONV_R_UN:
5395                         CHECK_STACK (1);
5396                         ADD_UNOP (*ip);
5397                         if (mono_find_jit_opcode_emulation (ins->opcode)) {
5398                                 --sp;
5399                                 *sp++ = emit_tree (cfg, bblock, ins, ip + 1);
5400                         }
5401                         ip++;                   
5402                         break;
5403                 case CEE_CONV_OVF_I4:
5404                 case CEE_CONV_OVF_I1:
5405                 case CEE_CONV_OVF_I2:
5406                 case CEE_CONV_OVF_I:
5407                 case CEE_CONV_OVF_U:
5408                         CHECK_STACK (1);
5409
5410                         if (sp [-1]->type == STACK_R8) {
5411                                 ADD_UNOP (CEE_CONV_OVF_I8);
5412                                 ADD_UNOP (*ip);
5413                         } else {
5414                                 ADD_UNOP (*ip);
5415                         }
5416
5417                         ip++;
5418                         break;
5419                 case CEE_CONV_OVF_U1:
5420                 case CEE_CONV_OVF_U2:
5421                 case CEE_CONV_OVF_U4:
5422                         CHECK_STACK (1);
5423
5424                         if (sp [-1]->type == STACK_R8) {
5425                                 ADD_UNOP (CEE_CONV_OVF_U8);
5426                                 ADD_UNOP (*ip);
5427                         } else {
5428                                 ADD_UNOP (*ip);
5429                         }
5430
5431                         ip++;
5432                         break;
5433                 case CEE_CONV_OVF_I1_UN:
5434                 case CEE_CONV_OVF_I2_UN:
5435                 case CEE_CONV_OVF_I4_UN:
5436                 case CEE_CONV_OVF_I8_UN:
5437                 case CEE_CONV_OVF_U1_UN:
5438                 case CEE_CONV_OVF_U2_UN:
5439                 case CEE_CONV_OVF_U4_UN:
5440                 case CEE_CONV_OVF_U8_UN:
5441                 case CEE_CONV_OVF_I_UN:
5442                 case CEE_CONV_OVF_U_UN:
5443                         CHECK_STACK (1);
5444                         ADD_UNOP (*ip);
5445                         ip++;
5446                         break;
5447                 case CEE_CPOBJ:
5448                         CHECK_OPSIZE (5);
5449                         CHECK_STACK (2);
5450                         token = read32 (ip + 1);
5451                         klass = mini_get_class (method, token, generic_context);
5452                         CHECK_TYPELOAD (klass);
5453                         sp -= 2;
5454                         if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
5455                                 MonoInst *store, *load;
5456                                 MONO_INST_NEW (cfg, load, CEE_LDIND_REF);
5457                                 load->cil_code = ip;
5458                                 load->inst_i0 = sp [1];
5459                                 load->type = STACK_OBJ;
5460                                 load->klass = klass;
5461                                 load->flags |= ins_flag;
5462                                 MONO_INST_NEW (cfg, store, CEE_STIND_REF);
5463                                 store->cil_code = ip;
5464                                 handle_loaded_temps (cfg, bblock, stack_start, sp);
5465                                 MONO_ADD_INS (bblock, store);
5466                                 store->inst_i0 = sp [0];
5467                                 store->inst_i1 = load;
5468                                 store->flags |= ins_flag;
5469                         } else {
5470                                 n = mono_class_value_size (klass, NULL);
5471                                 if ((cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 5) {
5472                                         MonoInst *copy;
5473                                         MONO_INST_NEW (cfg, copy, OP_MEMCPY);
5474                                         copy->inst_left = sp [0];
5475                                         copy->inst_right = sp [1];
5476                                         copy->cil_code = ip;
5477                                         copy->backend.size = n;
5478                                         MONO_ADD_INS (bblock, copy);
5479                                 } else {
5480                                         MonoMethod *memcpy_method = get_memcpy_method ();
5481                                         MonoInst *iargs [3];
5482                                         iargs [0] = sp [0];
5483                                         iargs [1] = sp [1];
5484                                         NEW_ICONST (cfg, iargs [2], n);
5485                                         iargs [2]->cil_code = ip;
5486
5487                                         mono_emit_method_call_spilled (cfg, bblock, memcpy_method, memcpy_method->signature, iargs, ip, NULL);
5488                                 }
5489                         }
5490                         ins_flag = 0;
5491                         ip += 5;
5492                         break;
5493                 case CEE_LDOBJ: {
5494                         MonoInst *iargs [3];
5495                         int loc_index = -1;
5496                         int stloc_len = 0;
5497                         CHECK_OPSIZE (5);
5498                         CHECK_STACK (1);
5499                         --sp;
5500                         token = read32 (ip + 1);
5501                         klass = mini_get_class (method, token, generic_context);
5502                         CHECK_TYPELOAD (klass);
5503                         if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
5504                                 MONO_INST_NEW (cfg, ins, CEE_LDIND_REF);
5505                                 ins->cil_code = ip;
5506                                 ins->inst_i0 = sp [0];
5507                                 ins->type = STACK_OBJ;
5508                                 ins->klass = klass;
5509                                 ins->flags |= ins_flag;
5510                                 ins_flag = 0;
5511                                 *sp++ = ins;
5512                                 ip += 5;
5513                                 break;
5514                         }
5515
5516                         /* Optimize the common ldobj+stloc combination */
5517                         switch (ip [5]) {
5518                         case CEE_STLOC_S:
5519                                 loc_index = ip [6];
5520                                 stloc_len = 2;
5521                                 break;
5522                         case CEE_STLOC_0:
5523                         case CEE_STLOC_1:
5524                         case CEE_STLOC_2:
5525                         case CEE_STLOC_3:
5526                                 loc_index = ip [5] - CEE_STLOC_0;
5527                                 stloc_len = 1;
5528                                 break;
5529                         default:
5530                                 break;
5531                         }
5532
5533                         if ((loc_index != -1) && ip_in_bb (cfg, bblock, ip + 5)) {
5534                                 CHECK_LOCAL (loc_index);
5535                                 NEW_LOCSTORE (cfg, ins, loc_index, *sp);
5536
5537                                 if (ins->opcode == CEE_STOBJ) {
5538                                         handle_loaded_temps (cfg, bblock, stack_start, sp);
5539                                         ins->cil_code = ip;
5540                                         g_assert (ins->opcode == CEE_STOBJ);
5541                                         NEW_LOCLOADA (cfg, ins, loc_index);
5542                                         handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE, FALSE);
5543                                         ip += 5;
5544                                         ip += stloc_len;
5545                                         break;
5546                                 }
5547                         }
5548
5549                         n = mono_class_value_size (klass, NULL);
5550                         ins = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
5551                         NEW_TEMPLOADA (cfg, iargs [0], ins->inst_c0);
5552                         if ((cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 5) {
5553                                 MonoInst *copy;
5554                                 MONO_INST_NEW (cfg, copy, OP_MEMCPY);
5555                                 copy->inst_left = iargs [0];
5556                                 copy->inst_right = *sp;
5557                                 copy->cil_code = ip;
5558                                 copy->backend.size = n;
5559                                 MONO_ADD_INS (bblock, copy);
5560                         } else {
5561                                 MonoMethod *memcpy_method = get_memcpy_method ();
5562                                 iargs [1] = *sp;
5563                                 NEW_ICONST (cfg, iargs [2], n);
5564                                 iargs [2]->cil_code = ip;
5565
5566                                 mono_emit_method_call_spilled (cfg, bblock, memcpy_method, memcpy_method->signature, iargs, ip, NULL);
5567                         }
5568                         NEW_TEMPLOAD (cfg, *sp, ins->inst_c0);
5569                         ++sp;
5570                         ip += 5;
5571                         ins_flag = 0;
5572                         inline_costs += 1;
5573                         break;
5574                 }
5575                 case CEE_LDSTR:
5576                         CHECK_STACK_OVF (1);
5577                         CHECK_OPSIZE (5);
5578                         n = read32 (ip + 1);
5579
5580                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
5581                                 /* FIXME: moving GC */
5582                                 NEW_PCONST (cfg, ins, mono_method_get_wrapper_data (method, n));
5583                                 ins->cil_code = ip;
5584                                 ins->type = STACK_OBJ;
5585                                 ins->klass = mono_defaults.string_class;
5586                                 *sp = ins;
5587                         }
5588                         else if (method->wrapper_type != MONO_WRAPPER_NONE) {
5589                                 int temp;
5590                                 MonoInst *iargs [1];
5591
5592                                 NEW_PCONST (cfg, iargs [0], mono_method_get_wrapper_data (method, n));                          
5593                                 temp = mono_emit_jit_icall (cfg, bblock, mono_string_new_wrapper, iargs, ip);
5594                                 NEW_TEMPLOAD (cfg, *sp, temp);
5595
5596                         } else {
5597
5598                                 if (cfg->opt & MONO_OPT_SHARED) {
5599                                         int temp;
5600                                         MonoInst *iargs [3];
5601                                         MonoInst* domain_var;
5602                                         
5603                                         if (cfg->compile_aot) {
5604                                                 /* FIXME: bug when inlining methods from different assemblies (n is a token valid just in one). */
5605                                                 cfg->ldstr_list = g_list_prepend (cfg->ldstr_list, GINT_TO_POINTER (n));
5606                                         }
5607                                         /* avoid depending on undefined C behavior in sequence points */
5608                                         domain_var = mono_get_domainvar (cfg);
5609                                         NEW_TEMPLOAD (cfg, iargs [0], domain_var->inst_c0);
5610                                         NEW_IMAGECONST (cfg, iargs [1], image);
5611                                         NEW_ICONST (cfg, iargs [2], mono_metadata_token_index (n));
5612                                         temp = mono_emit_jit_icall (cfg, bblock, mono_ldstr, iargs, ip);
5613                                         NEW_TEMPLOAD (cfg, *sp, temp);
5614                                         mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
5615                                 } else {
5616                                         if (bblock->out_of_line) {
5617                                                 MonoInst *iargs [2];
5618                                                 int temp;
5619
5620                                                 if (cfg->compile_aot && cfg->method->klass->image == mono_defaults.corlib) {
5621                                                         /* 
5622                                                          * Avoid relocations by using a version of helper_ldstr
5623                                                          * specialized to mscorlib.
5624                                                          */
5625                                                         NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (n));
5626                                                         temp = mono_emit_jit_icall (cfg, bblock, mono_helper_ldstr_mscorlib, iargs, ip);
5627                                                 } else {
5628                                                         /* Avoid creating the string object */
5629                                                         NEW_IMAGECONST (cfg, iargs [0], image);
5630                                                         NEW_ICONST (cfg, iargs [1], mono_metadata_token_index (n));
5631                                                         temp = mono_emit_jit_icall (cfg, bblock, mono_helper_ldstr, iargs, ip);
5632                                                 }
5633                                                 NEW_TEMPLOAD (cfg, *sp, temp);
5634                                         } 
5635                                         else
5636                                         if (cfg->compile_aot) {
5637                                                 NEW_LDSTRCONST (cfg, ins, image, n);
5638                                                 *sp = ins;
5639                                         } 
5640                                         else {
5641                                                 NEW_PCONST (cfg, ins, NULL);
5642                                                 ins->cil_code = ip;
5643                                                 ins->type = STACK_OBJ;
5644                                                 ins->inst_p0 = mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
5645                                                 ins->klass = mono_defaults.string_class;
5646                                                 *sp = ins;
5647                                         }
5648                                 }
5649                         }
5650
5651                         sp++;
5652                         ip += 5;
5653                         break;
5654                 case CEE_NEWOBJ: {
5655                         MonoInst *iargs [2];
5656                         MonoMethodSignature *fsig;
5657                         int temp;
5658                         
5659                         CHECK_OPSIZE (5);
5660                         token = read32 (ip + 1);
5661                         cmethod = mini_get_method (method, token, NULL, generic_context);
5662                         if (!cmethod)
5663                                 goto load_error;
5664                         fsig = mono_method_get_signature (cmethod, image, token);
5665
5666                         mono_save_token_info (cfg, image, token, cmethod);
5667
5668                         if (!mono_class_init (cmethod->klass))
5669                                 goto load_error;
5670
5671                         if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS) {
5672                                 if (check_linkdemand (cfg, method, cmethod, bblock, ip))
5673                                         INLINE_FAILURE;
5674                                 CHECK_CFG_EXCEPTION;
5675                         } else if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR) {
5676                                 ensure_method_is_allowed_to_call_method (cfg, method, cmethod, bblock, ip);
5677                         }
5678
5679                         n = fsig->param_count;
5680                         CHECK_STACK (n);
5681
5682                         /* move the args to allow room for 'this' in the first position */
5683                         while (n--) {
5684                                 --sp;
5685                                 sp [1] = sp [0];
5686                         }
5687
5688                         handle_loaded_temps (cfg, bblock, stack_start, sp);
5689
5690                         if (mini_class_is_system_array (cmethod->klass)) {
5691                                 NEW_METHODCONST (cfg, *sp, cmethod);
5692                                 temp = handle_array_new (cfg, bblock, fsig->param_count, sp, ip);
5693                         } else if (cmethod->string_ctor) {
5694                                 /* we simply pass a null pointer */
5695                                 NEW_PCONST (cfg, *sp, NULL); 
5696                                 /* now call the string ctor */
5697                                 temp = mono_emit_method_call_spilled (cfg, bblock, cmethod, fsig, sp, ip, NULL);
5698                         } else {
5699                                 MonoInst* callvirt_this_arg = NULL;
5700                                 
5701                                 if (cmethod->klass->valuetype) {
5702                                         iargs [0] = mono_compile_create_var (cfg, &cmethod->klass->byval_arg, OP_LOCAL);
5703                                         temp = iargs [0]->inst_c0;
5704
5705                                         NEW_TEMPLOADA (cfg, *sp, temp);
5706
5707                                         handle_initobj (cfg, bblock, *sp, NULL, cmethod->klass, stack_start, sp);
5708
5709                                         NEW_TEMPLOADA (cfg, *sp, temp);
5710
5711                                         /* 
5712                                          * The code generated by mini_emit_virtual_call () expects
5713                                          * iargs [0] to be a boxed instance, but luckily the vcall
5714                                          * will be transformed into a normal call there.
5715                                          */
5716                                 } else {
5717                                         temp = handle_alloc (cfg, bblock, cmethod->klass, FALSE, ip);
5718                                         NEW_TEMPLOAD (cfg, *sp, temp);
5719                                 }
5720
5721                                 /* Avoid virtual calls to ctors if possible */
5722                                 if (cmethod->klass->marshalbyref)
5723                                         callvirt_this_arg = sp [0];
5724                                 
5725                                 if ((cfg->opt & MONO_OPT_INLINE) && cmethod &&
5726                                     mono_method_check_inlining (cfg, cmethod) &&
5727                                     !mono_class_is_subclass_of (cmethod->klass, mono_defaults.exception_class, FALSE) &&
5728                                     !g_list_find (dont_inline, cmethod)) {
5729                                         int costs;
5730                                         MonoBasicBlock *ebblock;
5731                                         if ((costs = inline_method (cfg, cmethod, fsig, bblock, sp, ip, real_offset, dont_inline, &ebblock, FALSE))) {
5732
5733                                                 ip += 5;
5734                                                 real_offset += 5;
5735                                                 
5736                                                 GET_BBLOCK (cfg, bblock, ip);
5737                                                 ebblock->next_bb = bblock;
5738                                                 link_bblock (cfg, ebblock, bblock);
5739
5740                                                 NEW_TEMPLOAD (cfg, *sp, temp);
5741                                                 sp++;
5742
5743                                                 /* indicates start of a new block, and triggers a load 
5744                                                    of all stack arguments at bb boundarie */
5745                                                 bblock = ebblock;
5746
5747                                                 inline_costs += costs;
5748                                                 break;
5749                                                 
5750                                         } else {
5751                                                 /* Prevent inlining of methods which call other methods */
5752                                                 INLINE_FAILURE;
5753                                                 mono_emit_method_call_spilled (cfg, bblock, cmethod, fsig, sp, ip, callvirt_this_arg);
5754                                         }
5755                                 } else {
5756                                         /* Prevent inlining of methods which call other methods */
5757                                         INLINE_FAILURE;
5758                                         /* now call the actual ctor */
5759                                         mono_emit_method_call_spilled (cfg, bblock, cmethod, fsig, sp, ip, callvirt_this_arg);
5760                                 }
5761                         }
5762
5763                         NEW_TEMPLOAD (cfg, *sp, temp);
5764                         sp++;
5765                         
5766                         ip += 5;
5767                         inline_costs += 5;
5768                         break;
5769                 }
5770                 case CEE_ISINST:
5771                         CHECK_STACK (1);
5772                         --sp;
5773                         CHECK_OPSIZE (5);
5774                         token = read32 (ip + 1);
5775                         klass = mini_get_class (method, token, generic_context);
5776                         CHECK_TYPELOAD (klass);
5777                         if (sp [0]->type != STACK_OBJ)
5778                                 UNVERIFIED;
5779
5780                         /* Needed by the code generated in inssel.brg */
5781                         mono_get_got_var (cfg);
5782
5783                         if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
5784                         
5785                                 MonoMethod *mono_isinst;
5786                                 MonoInst *iargs [1];
5787                                 MonoBasicBlock *ebblock;
5788                                 int costs;
5789                                 int temp;
5790                                 
5791                                 mono_isinst = mono_marshal_get_isinst (klass); 
5792                                 iargs [0] = sp [0];
5793                                 
5794                                 costs = inline_method (cfg, mono_isinst, mono_method_signature (mono_isinst), bblock, 
5795                                                            iargs, ip, real_offset, dont_inline, &ebblock, TRUE);
5796                         
5797                                 g_assert (costs > 0);
5798                                 
5799                                 ip += 5;
5800                                 real_offset += 5;
5801                         
5802                                 GET_BBLOCK (cfg, bblock, ip);
5803                                 ebblock->next_bb = bblock;
5804                                 link_bblock (cfg, ebblock, bblock);
5805
5806                                 temp = iargs [0]->inst_i0->inst_c0;
5807                                 NEW_TEMPLOAD (cfg, *sp, temp);
5808                                 
5809                                 sp++;
5810                                 bblock = ebblock;
5811                                 inline_costs += costs;
5812                         } else {
5813                                 MONO_INST_NEW (cfg, ins, *ip);
5814                                 ins->type = STACK_OBJ;
5815                                 ins->inst_left = *sp;
5816                                 ins->inst_newa_class = klass;
5817                                 ins->klass = klass;
5818                                 ins->cil_code = ip;
5819                                 *sp++ = emit_tree (cfg, bblock, ins, ip + 5);
5820                                 ip += 5;
5821                         }
5822                         break;
5823                 case CEE_UNBOX_ANY: {
5824                         MonoInst *add, *vtoffset;
5825                         MonoInst *iargs [3];
5826
5827                         CHECK_STACK (1);
5828                         --sp;
5829                         CHECK_OPSIZE (5);
5830                         token = read32 (ip + 1);
5831                         klass = mini_get_class (method, token, generic_context);
5832                         CHECK_TYPELOAD (klass);
5833
5834                         if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
5835                                 /* CASTCLASS */
5836                                 if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
5837                                         MonoMethod *mono_castclass;
5838                                         MonoInst *iargs [1];
5839                                         MonoBasicBlock *ebblock;
5840                                         int costs;
5841                                         int temp;
5842                                         
5843                                         mono_castclass = mono_marshal_get_castclass (klass); 
5844                                         iargs [0] = sp [0];
5845                                         
5846                                         costs = inline_method (cfg, mono_castclass, mono_method_signature (mono_castclass), bblock, 
5847                                                                    iargs, ip, real_offset, dont_inline, &ebblock, TRUE);
5848                                 
5849                                         g_assert (costs > 0);
5850                                         
5851                                         ip += 5;
5852                                         real_offset += 5;
5853                                 
5854                                         GET_BBLOCK (cfg, bblock, ip);
5855                                         ebblock->next_bb = bblock;
5856                                         link_bblock (cfg, ebblock, bblock);
5857         
5858                                         temp = iargs [0]->inst_i0->inst_c0;
5859                                         NEW_TEMPLOAD (cfg, *sp, temp);
5860                                         
5861                                         sp++;
5862                                         bblock = ebblock;
5863                                         inline_costs += costs;                          
5864                                 } else {
5865                                         MONO_INST_NEW (cfg, ins, CEE_CASTCLASS);
5866                                         ins->type = STACK_OBJ;
5867                                         ins->inst_left = *sp;
5868                                         ins->klass = klass;
5869                                         ins->inst_newa_class = klass;
5870                                         ins->cil_code = ip;
5871                                         *sp++ = ins;
5872                                         ip += 5;
5873                                 }
5874                                 break;
5875                         }
5876
5877                         if (mono_class_is_nullable (klass)) {
5878                                 int v = handle_unbox_nullable (cfg, bblock, *sp, ip, klass);
5879                                 NEW_TEMPLOAD (cfg, *sp, v);
5880                                 sp ++;
5881                                 ip += 5;
5882                                 break;
5883                         }
5884
5885                         MONO_INST_NEW (cfg, ins, OP_UNBOXCAST);
5886                         ins->type = STACK_OBJ;
5887                         ins->inst_left = *sp;
5888                         ins->klass = klass;
5889                         ins->inst_newa_class = klass;
5890                         ins->cil_code = ip;
5891
5892                         MONO_INST_NEW (cfg, add, OP_PADD);
5893                         NEW_ICONST (cfg, vtoffset, sizeof (MonoObject));
5894                         add->inst_left = ins;
5895                         add->inst_right = vtoffset;
5896                         add->type = STACK_MP;
5897                         add->klass = mono_defaults.object_class;
5898                         *sp = add;
5899                         ip += 5;
5900                         /* LDOBJ impl */
5901                         n = mono_class_value_size (klass, NULL);
5902                         ins = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
5903                         NEW_TEMPLOADA (cfg, iargs [0], ins->inst_c0);
5904                         if ((cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 5) {
5905                                 MonoInst *copy;
5906                                 MONO_INST_NEW (cfg, copy, OP_MEMCPY);
5907                                 copy->inst_left = iargs [0];
5908                                 copy->inst_right = *sp;
5909                                 copy->cil_code = ip;
5910                                 copy->backend.size = n;
5911                                 MONO_ADD_INS (bblock, copy);
5912                         } else {
5913                                 MonoMethod *memcpy_method = get_memcpy_method ();
5914                                 iargs [1] = *sp;
5915                                 NEW_ICONST (cfg, iargs [2], n);
5916                                 iargs [2]->cil_code = ip;
5917
5918                                 mono_emit_method_call_spilled (cfg, bblock, memcpy_method, memcpy_method->signature, iargs, ip, NULL);
5919                         }
5920                         NEW_TEMPLOAD (cfg, *sp, ins->inst_c0);
5921                         ++sp;
5922                         inline_costs += 2;
5923                         break;
5924                 }
5925                 case CEE_UNBOX: {
5926                         MonoInst *add, *vtoffset;
5927
5928                         CHECK_STACK (1);
5929                         --sp;
5930                         CHECK_OPSIZE (5);
5931                         token = read32 (ip + 1);
5932                         klass = mini_get_class (method, token, generic_context);
5933                         CHECK_TYPELOAD (klass);
5934
5935                         if (mono_class_is_nullable (klass)) {
5936                                 int v = handle_unbox_nullable (cfg, bblock, *sp, ip, klass);
5937                                 NEW_TEMPLOAD (cfg, *sp, v);
5938                                 sp ++;
5939                                 ip += 5;
5940                                 break;
5941                         }
5942
5943                         /* Needed by the code generated in inssel.brg */
5944                         mono_get_got_var (cfg);
5945
5946                         MONO_INST_NEW (cfg, ins, OP_UNBOXCAST);
5947                         ins->type = STACK_OBJ;
5948                         ins->inst_left = *sp;
5949                         ins->klass = klass;
5950                         ins->inst_newa_class = klass;
5951                         ins->cil_code = ip;
5952
5953                         MONO_INST_NEW (cfg, add, OP_PADD);
5954                         NEW_ICONST (cfg, vtoffset, sizeof (MonoObject));
5955                         add->inst_left = ins;
5956                         add->inst_right = vtoffset;
5957                         add->type = STACK_MP;
5958                         add->klass = klass;
5959                         *sp++ = add;
5960                         ip += 5;
5961                         inline_costs += 2;
5962                         break;
5963                 }
5964                 case CEE_CASTCLASS:
5965                         CHECK_STACK (1);
5966                         --sp;
5967                         CHECK_OPSIZE (5);
5968                         token = read32 (ip + 1);
5969                         klass = mini_get_class (method, token, generic_context);
5970                         CHECK_TYPELOAD (klass);
5971                         if (sp [0]->type != STACK_OBJ)
5972                                 UNVERIFIED;
5973
5974                         /* Needed by the code generated in inssel.brg */
5975                         mono_get_got_var (cfg);
5976                 
5977                         if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
5978                                 
5979                                 MonoMethod *mono_castclass;
5980                                 MonoInst *iargs [1];
5981                                 MonoBasicBlock *ebblock;
5982                                 int costs;
5983                                 int temp;
5984                                 
5985                                 mono_castclass = mono_marshal_get_castclass (klass); 
5986                                 iargs [0] = sp [0];
5987                                 
5988                                 costs = inline_method (cfg, mono_castclass, mono_method_signature (mono_castclass), bblock, 
5989                                                            iargs, ip, real_offset, dont_inline, &ebblock, TRUE);
5990                         
5991                                 g_assert (costs > 0);
5992                                 
5993                                 ip += 5;
5994                                 real_offset += 5;
5995                         
5996                                 GET_BBLOCK (cfg, bblock, ip);
5997                                 ebblock->next_bb = bblock;
5998                                 link_bblock (cfg, ebblock, bblock);
5999
6000                                 temp = iargs [0]->inst_i0->inst_c0;
6001                                 NEW_TEMPLOAD (cfg, *sp, temp);
6002                                 
6003                                 sp++;
6004                                 bblock = ebblock;
6005                                 inline_costs += costs;
6006                         } else {
6007                                 MONO_INST_NEW (cfg, ins, *ip);
6008                                 ins->type = STACK_OBJ;
6009                                 ins->inst_left = *sp;
6010                                 ins->klass = klass;
6011                                 ins->inst_newa_class = klass;
6012                                 ins->cil_code = ip;
6013                                 *sp++ = emit_tree (cfg, bblock, ins, ip + 5);
6014                                 ip += 5;
6015                         }
6016                         break;
6017                 case CEE_THROW:
6018                         CHECK_STACK (1);
6019                         MONO_INST_NEW (cfg, ins, OP_THROW);
6020                         --sp;
6021                         ins->inst_left = *sp;
6022                         ins->cil_code = ip++;
6023                         bblock->out_of_line = TRUE;
6024                         MONO_ADD_INS (bblock, ins);
6025                         MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
6026                         ins->cil_code = ip - 1;
6027                         MONO_ADD_INS (bblock, ins);
6028                         sp = stack_start;
6029                         
6030                         link_bblock (cfg, bblock, end_bblock);
6031                         start_new_bblock = 1;
6032                         break;
6033                 case CEE_LDFLD:
6034                 case CEE_LDFLDA:
6035                 case CEE_STFLD: {
6036                         MonoInst *offset_ins;
6037                         MonoClassField *field;
6038                         MonoBasicBlock *ebblock;
6039                         int costs;
6040                         guint foffset;
6041
6042                         if (*ip == CEE_STFLD) {
6043                                 CHECK_STACK (2);
6044                                 sp -= 2;
6045                         } else {
6046                                 CHECK_STACK (1);
6047                                 --sp;
6048                         }
6049                         if (sp [0]->type == STACK_I4 || sp [0]->type == STACK_I8 || sp [0]->type == STACK_R8)
6050                                 UNVERIFIED;
6051                         if (*ip != CEE_LDFLD && sp [0]->type == STACK_VTYPE)
6052                                 UNVERIFIED;
6053                         CHECK_OPSIZE (5);
6054                         token = read32 (ip + 1);
6055                         if (method->wrapper_type != MONO_WRAPPER_NONE) {
6056                                 field = mono_method_get_wrapper_data (method, token);
6057                                 klass = field->parent;
6058                         } else {
6059                                 field = mono_field_from_token (image, token, &klass, generic_context);
6060                         }
6061                         if (!field)
6062                                 goto load_error;
6063                         mono_class_init (klass);
6064                         if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_field (method, field))
6065                                 UNVERIFIED;
6066
6067                         foffset = klass->valuetype? field->offset - sizeof (MonoObject): field->offset;
6068                         /* FIXME: mark instructions for use in SSA */
6069                         if (*ip == CEE_STFLD) {
6070                                 if (target_type_is_incompatible (cfg, field->type, sp [1]))
6071                                         UNVERIFIED;
6072                                 if ((klass->marshalbyref && !MONO_CHECK_THIS (sp [0])) || klass->contextbound || klass == mono_defaults.marshalbyrefobject_class) {
6073                                         MonoMethod *stfld_wrapper = mono_marshal_get_stfld_wrapper (field->type); 
6074                                         MonoInst *iargs [5];
6075
6076                                         iargs [0] = sp [0];
6077                                         NEW_CLASSCONST (cfg, iargs [1], klass);
6078                                         NEW_FIELDCONST (cfg, iargs [2], field);
6079                                         NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : 
6080                                                     field->offset);
6081                                         iargs [4] = sp [1];
6082
6083                                         if (cfg->opt & MONO_OPT_INLINE) {
6084                                                 costs = inline_method (cfg, stfld_wrapper, mono_method_signature (stfld_wrapper), bblock, 
6085                                                                        iargs, ip, real_offset, dont_inline, &ebblock, TRUE);
6086                                                 g_assert (costs > 0);
6087                                                       
6088                                                 ip += 5;
6089                                                 real_offset += 5;
6090
6091                                                 GET_BBLOCK (cfg, bblock, ip);
6092                                                 ebblock->next_bb = bblock;
6093                                                 link_bblock (cfg, ebblock, bblock);
6094
6095                                                 /* indicates start of a new block, and triggers a load 
6096                                                    of all stack arguments at bb boundarie */
6097                                                 bblock = ebblock;
6098
6099                                                 inline_costs += costs;
6100                                                 break;
6101                                         } else {
6102                                                 mono_emit_method_call_spilled (cfg, bblock, stfld_wrapper, mono_method_signature (stfld_wrapper), iargs, ip, NULL);
6103                                         }
6104 #if HAVE_WRITE_BARRIERS
6105                                 } else if (mono_type_to_stind (field->type) == CEE_STIND_REF) {
6106                                         /* insert call to write barrier */
6107                                         MonoMethod *write_barrier = mono_marshal_get_write_barrier ();
6108                                         MonoInst *iargs [2];
6109                                         NEW_ICONST (cfg, offset_ins, foffset);
6110                                         MONO_INST_NEW (cfg, ins, OP_PADD);
6111                                         ins->cil_code = ip;
6112                                         ins->inst_left = *sp;
6113                                         ins->inst_right = offset_ins;
6114                                         ins->type = STACK_MP;
6115                                         ins->klass = mono_defaults.object_class;
6116                                         iargs [0] = ins;
6117                                         iargs [1] = sp [1];
6118                                         mono_emit_method_call_spilled (cfg, bblock, write_barrier, mono_method_signature (write_barrier), iargs, ip, NULL);
6119 #endif
6120 #ifdef MONO_ARCH_SOFT_FLOAT
6121                                 } else if (mono_type_to_stind (field->type) == CEE_STIND_R4) {
6122                                         NEW_ICONST (cfg, offset_ins, foffset);
6123                                         MONO_INST_NEW (cfg, ins, OP_PADD);
6124                                         ins->cil_code = ip;
6125                                         ins->inst_left = *sp;
6126                                         ins->inst_right = offset_ins;
6127                                         ins->type = STACK_MP;
6128                                         ins->klass = mono_defaults.object_class;
6129                                         handle_store_float (cfg, bblock, ins, sp [1], ip);
6130 #endif
6131                                 } else {
6132                                         MonoInst *store;
6133                                         NEW_ICONST (cfg, offset_ins, foffset);
6134                                         MONO_INST_NEW (cfg, ins, OP_PADD);
6135                                         ins->cil_code = ip;
6136                                         ins->inst_left = *sp;
6137                                         ins->inst_right = offset_ins;
6138                                         ins->type = STACK_MP;
6139
6140                                         MONO_INST_NEW (cfg, store, mono_type_to_stind (field->type));
6141                                         store->cil_code = ip;
6142                                         store->inst_left = ins;
6143                                         store->inst_right = sp [1];
6144                                         handle_loaded_temps (cfg, bblock, stack_start, sp);
6145                                         store->flags |= ins_flag;
6146                                         ins_flag = 0;
6147                                         if (store->opcode == CEE_STOBJ) {
6148                                                 handle_stobj (cfg, bblock, ins, sp [1], ip, 
6149                                                               mono_class_from_mono_type (field->type), FALSE, FALSE, TRUE);
6150                                         } else
6151                                                 MONO_ADD_INS (bblock, store);
6152                                 }
6153                         } else {
6154                                 if ((klass->marshalbyref && !MONO_CHECK_THIS (sp [0])) || klass->contextbound || klass == mono_defaults.marshalbyrefobject_class) {
6155                                         MonoMethod *wrapper = (*ip == CEE_LDFLDA) ? mono_marshal_get_ldflda_wrapper (field->type) : mono_marshal_get_ldfld_wrapper (field->type); 
6156                                         MonoInst *iargs [4];
6157                                         int temp;
6158                                         
6159                                         iargs [0] = sp [0];
6160                                         NEW_CLASSCONST (cfg, iargs [1], klass);
6161                                         NEW_FIELDCONST (cfg, iargs [2], field);
6162                                         NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : field->offset);
6163                                         if ((cfg->opt & MONO_OPT_INLINE) && !MONO_TYPE_ISSTRUCT (mono_method_signature (wrapper)->ret)) {
6164                                                 costs = inline_method (cfg, wrapper, mono_method_signature (wrapper), bblock, 
6165                                                                        iargs, ip, real_offset, dont_inline, &ebblock, TRUE);
6166                                                 g_assert (costs > 0);
6167                                                       
6168                                                 ip += 5;
6169                                                 real_offset += 5;
6170
6171                                                 GET_BBLOCK (cfg, bblock, ip);
6172                                                 ebblock->next_bb = bblock;
6173                                                 link_bblock (cfg, ebblock, bblock);
6174
6175                                                 temp = iargs [0]->inst_i0->inst_c0;
6176
6177                                                 NEW_TEMPLOAD (cfg, *sp, temp);
6178                                                 sp++;
6179
6180                                                 /* indicates start of a new block, and triggers a load of
6181                                                    all stack arguments at bb boundarie */
6182                                                 bblock = ebblock;
6183                                                 
6184                                                 inline_costs += costs;
6185                                                 break;
6186                                         } else {
6187                                                 temp = mono_emit_method_call_spilled (cfg, bblock, wrapper, mono_method_signature (wrapper), iargs, ip, NULL);
6188                                                 NEW_TEMPLOAD (cfg, *sp, temp);
6189                                                 sp++;
6190                                         }
6191                                 } else {
6192                                         NEW_ICONST (cfg, offset_ins, foffset);
6193                                         MONO_INST_NEW (cfg, ins, OP_PADD);
6194                                         ins->cil_code = ip;
6195                                         ins->inst_left = *sp;
6196                                         ins->inst_right = offset_ins;
6197                                         ins->type = STACK_MP;
6198
6199                                         if (*ip == CEE_LDFLDA) {
6200                                                 ins->klass = mono_class_from_mono_type (field->type);
6201                                                 *sp++ = ins;
6202                                         } else {
6203                                                 MonoInst *load;
6204                                                 MONO_INST_NEW (cfg, load, mono_type_to_ldind (field->type));
6205                                                 type_to_eval_stack_type (field->type, load);
6206                                                 load->cil_code = ip;
6207                                                 load->inst_left = ins;
6208                                                 load->flags |= ins_flag;
6209                                                 ins_flag = 0;
6210 #ifdef MONO_ARCH_SOFT_FLOAT
6211                                                 if (mono_type_to_ldind (field->type) == CEE_LDIND_R4) {
6212                                                         int temp;
6213                                                         temp = handle_load_float (cfg, bblock, ins, ip);
6214                                                         NEW_TEMPLOAD (cfg, *sp, temp);
6215                                                         sp++;
6216                                                 } else
6217 #endif
6218                                                 *sp++ = load;
6219                                         }
6220                                 }
6221                         }
6222                         ip += 5;
6223                         break;
6224                 }
6225                 case CEE_LDSFLD:
6226                 case CEE_LDSFLDA:
6227                 case CEE_STSFLD: {
6228                         MonoClassField *field;
6229                         gpointer addr = NULL;
6230
6231                         CHECK_OPSIZE (5);
6232                         token = read32 (ip + 1);
6233                         if (method->wrapper_type != MONO_WRAPPER_NONE) {
6234                                 field = mono_method_get_wrapper_data (method, token);
6235                                 klass = field->parent;
6236                         }
6237                         else
6238                                 field = mono_field_from_token (image, token, &klass, generic_context);
6239                         if (!field)
6240                                 goto load_error;
6241                         mono_class_init (klass);
6242
6243                         g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
6244
6245                         if ((*ip) == CEE_STSFLD)
6246                                 handle_loaded_temps (cfg, bblock, stack_start, sp);
6247
6248                         /* The special_static_fields field is init'd in mono_class_vtable, so it needs
6249                          * to be called here.
6250                          */
6251                         if (!(cfg->opt & MONO_OPT_SHARED))
6252                                 mono_class_vtable (cfg->domain, klass);
6253                         mono_domain_lock (cfg->domain);
6254                         if (cfg->domain->special_static_fields)
6255                                 addr = g_hash_table_lookup (cfg->domain->special_static_fields, field);
6256                         mono_domain_unlock (cfg->domain);
6257
6258                         if ((cfg->opt & MONO_OPT_SHARED) || (cfg->compile_aot && addr)) {
6259                                 int temp;
6260                                 MonoInst *iargs [2];
6261                                 MonoInst *domain_var;
6262                                 
6263                                 g_assert (field->parent);
6264                                 /* avoid depending on undefined C behavior in sequence points */
6265                                 domain_var = mono_get_domainvar (cfg);
6266                                 NEW_TEMPLOAD (cfg, iargs [0], domain_var->inst_c0);
6267                                 NEW_FIELDCONST (cfg, iargs [1], field);
6268                                 temp = mono_emit_jit_icall (cfg, bblock, mono_class_static_field_address, iargs, ip);
6269                                 NEW_TEMPLOAD (cfg, ins, temp);
6270                         } else {
6271                                 MonoVTable *vtable;
6272                                 vtable = mono_class_vtable (cfg->domain, klass);
6273                                 if (!addr) {
6274                                         if (mini_field_access_needs_cctor_run (cfg, method, vtable) && !(g_slist_find (class_inits, vtable))) {
6275                                                 guint8 *tramp = mono_create_class_init_trampoline (vtable);
6276                                                 mono_emit_native_call (cfg, bblock, tramp, 
6277                                                                                            helper_sig_class_init_trampoline,
6278                                                                                            NULL, ip, FALSE, FALSE);
6279                                                 if (cfg->verbose_level > 2)
6280                                                         g_print ("class %s.%s needs init call for %s\n", klass->name_space, klass->name, field->name);
6281                                                 class_inits = g_slist_prepend (class_inits, vtable);
6282                                         } else {
6283                                                 if (cfg->run_cctors) {
6284                                                         /* This makes so that inline cannot trigger */
6285                                                         /* .cctors: too many apps depend on them */
6286                                                         /* running with a specific order... */
6287                                                         if (! vtable->initialized)
6288                                                                 INLINE_FAILURE;
6289                                                         mono_runtime_class_init (vtable);
6290                                                 }
6291                                         }
6292                                         addr = (char*)vtable->data + field->offset;
6293
6294                                         if (cfg->compile_aot)
6295                                                 NEW_SFLDACONST (cfg, ins, field);
6296                                         else
6297                                                 NEW_PCONST (cfg, ins, addr);
6298                                         ins->cil_code = ip;
6299                                 } else {
6300                                         /* 
6301                                          * insert call to mono_threads_get_static_data (GPOINTER_TO_UINT (addr)) 
6302                                          * This could be later optimized to do just a couple of
6303                                          * memory dereferences with constant offsets.
6304                                          */
6305                                         int temp;
6306                                         MonoInst *iargs [1];
6307                                         NEW_ICONST (cfg, iargs [0], GPOINTER_TO_UINT (addr));
6308                                         temp = mono_emit_jit_icall (cfg, bblock, mono_get_special_static_data, iargs, ip);
6309                                         NEW_TEMPLOAD (cfg, ins, temp);
6310                                 }
6311                         }
6312
6313                         /* FIXME: mark instructions for use in SSA */
6314                         if (*ip == CEE_LDSFLDA) {
6315                                 ins->klass = mono_class_from_mono_type (field->type);
6316                                 *sp++ = ins;
6317                         } else if (*ip == CEE_STSFLD) {
6318                                 MonoInst *store;
6319                                 CHECK_STACK (1);
6320                                 sp--;
6321                                 MONO_INST_NEW (cfg, store, mono_type_to_stind (field->type));
6322                                 store->cil_code = ip;
6323                                 store->inst_left = ins;
6324                                 store->inst_right = sp [0];
6325                                 store->flags |= ins_flag;
6326                                 ins_flag = 0;
6327
6328                                 if (store->opcode == CEE_STOBJ) {
6329                                         handle_stobj (cfg, bblock, ins, sp [0], ip, mono_class_from_mono_type (field->type), FALSE, FALSE, FALSE);
6330                                 } else
6331                                         MONO_ADD_INS (bblock, store);
6332                         } else {
6333                                 gboolean is_const = FALSE;
6334                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
6335                                 if (!((cfg->opt & MONO_OPT_SHARED) || cfg->compile_aot) && 
6336                                     vtable->initialized && (field->type->attrs & FIELD_ATTRIBUTE_INIT_ONLY)) {
6337                                         gpointer addr = (char*)vtable->data + field->offset;
6338                                         int ro_type = field->type->type;
6339                                         if (ro_type == MONO_TYPE_VALUETYPE && field->type->data.klass->enumtype) {
6340                                                 ro_type = field->type->data.klass->enum_basetype->type;
6341                                         }
6342                                         /* g_print ("RO-FIELD %s.%s:%s\n", klass->name_space, klass->name, field->name);*/
6343                                         is_const = TRUE;
6344                                         switch (ro_type) {
6345                                         case MONO_TYPE_BOOLEAN:
6346                                         case MONO_TYPE_U1:
6347                                                 NEW_ICONST (cfg, *sp, *((guint8 *)addr));
6348                                                 sp++;
6349                                                 break;
6350                                         case MONO_TYPE_I1:
6351                                                 NEW_ICONST (cfg, *sp, *((gint8 *)addr));
6352                                                 sp++;
6353                                                 break;                                          
6354                                         case MONO_TYPE_CHAR:
6355                                         case MONO_TYPE_U2:
6356                                                 NEW_ICONST (cfg, *sp, *((guint16 *)addr));
6357                                                 sp++;
6358                                                 break;
6359                                         case MONO_TYPE_I2:
6360                                                 NEW_ICONST (cfg, *sp, *((gint16 *)addr));
6361                                                 sp++;
6362                                                 break;
6363                                                 break;
6364                                         case MONO_TYPE_I4:
6365                                                 NEW_ICONST (cfg, *sp, *((gint32 *)addr));
6366                                                 sp++;
6367                                                 break;                                          
6368                                         case MONO_TYPE_U4:
6369                                                 NEW_ICONST (cfg, *sp, *((guint32 *)addr));
6370                                                 sp++;
6371                                                 break;
6372 #ifndef HAVE_MOVING_COLLECTOR
6373                                         case MONO_TYPE_I:
6374                                         case MONO_TYPE_U:
6375                                         case MONO_TYPE_STRING:
6376                                         case MONO_TYPE_OBJECT:
6377                                         case MONO_TYPE_CLASS:
6378                                         case MONO_TYPE_SZARRAY:
6379                                         case MONO_TYPE_PTR:
6380                                         case MONO_TYPE_FNPTR:
6381                                         case MONO_TYPE_ARRAY:
6382                                                 NEW_PCONST (cfg, *sp, *((gpointer *)addr));
6383                                                 type_to_eval_stack_type (field->type, *sp);
6384                                                 sp++;
6385                                                 break;
6386 #endif
6387                                         case MONO_TYPE_I8:
6388                                         case MONO_TYPE_U8:
6389                                                 MONO_INST_NEW (cfg, *sp, OP_I8CONST);
6390                                                 sp [0]->type = STACK_I8;
6391                                                 sp [0]->inst_l = *((gint64 *)addr);
6392                                                 sp++;
6393                                                 break;
6394                                         case MONO_TYPE_R4:
6395                                         case MONO_TYPE_R8:
6396                                         case MONO_TYPE_VALUETYPE:
6397                                         default:
6398                                                 is_const = FALSE;
6399                                                 break;
6400                                         }
6401                                 }
6402
6403                                 if (!is_const) {
6404                                         MonoInst *load;
6405                                         CHECK_STACK_OVF (1);
6406                                         MONO_INST_NEW (cfg, load, mono_type_to_ldind (field->type));
6407                                         type_to_eval_stack_type (field->type, load);
6408                                         load->cil_code = ip;
6409                                         load->inst_left = ins;
6410                                         *sp++ = load;
6411                                         load->flags |= ins_flag;
6412                                         ins_flag = 0;
6413                                         /* fixme: dont see the problem why this does not work */
6414                                         //cfg->disable_aot = TRUE;
6415                                 }
6416                         }
6417                         ip += 5;
6418                         break;
6419                 }
6420                 case CEE_STOBJ:
6421                         CHECK_STACK (2);
6422                         sp -= 2;
6423                         CHECK_OPSIZE (5);
6424                         token = read32 (ip + 1);
6425                         klass = mini_get_class (method, token, generic_context);
6426                         CHECK_TYPELOAD (klass);
6427                         n = mono_type_to_stind (&klass->byval_arg);
6428                         if (n == CEE_STOBJ) {
6429                                 handle_stobj (cfg, bblock, sp [0], sp [1], ip, klass, FALSE, FALSE, TRUE);
6430                         } else {
6431                                 /* FIXME: should check item at sp [1] is compatible with the type of the store. */
6432                                 MonoInst *store;
6433                                 MONO_INST_NEW (cfg, store, n);
6434                                 store->cil_code = ip;
6435                                 store->inst_left = sp [0];
6436                                 store->inst_right = sp [1];
6437                                 store->flags |= ins_flag;
6438                                 MONO_ADD_INS (bblock, store);
6439                         }
6440                         ins_flag = 0;
6441                         ip += 5;
6442                         inline_costs += 1;
6443                         break;
6444                 case CEE_BOX: {
6445                         MonoInst *val;
6446                         CHECK_STACK (1);
6447                         --sp;
6448                         val = *sp;
6449                         CHECK_OPSIZE (5);
6450                         token = read32 (ip + 1);
6451                         klass = mini_get_class (method, token, generic_context);
6452                         CHECK_TYPELOAD (klass);
6453
6454                         if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
6455                                 *sp++ = val;
6456                                 ip += 5;
6457                                 break;
6458                         }
6459                         if (klass == mono_defaults.void_class)
6460                                 UNVERIFIED;
6461                         if (target_type_is_incompatible (cfg, &klass->byval_arg, *sp))
6462                                 UNVERIFIED;
6463                         /* frequent check in generic code: box (struct), brtrue */
6464                         if (!mono_class_is_nullable (klass) &&
6465                             ip + 5 < end && ip_in_bb (cfg, bblock, ip + 5) && (ip [5] == CEE_BRTRUE || ip [5] == CEE_BRTRUE_S)) {
6466                                 /*g_print ("box-brtrue opt at 0x%04x in %s\n", real_offset, method->name);*/
6467                                 MONO_INST_NEW (cfg, ins, CEE_POP);
6468                                 MONO_ADD_INS (bblock, ins);
6469                                 ins->cil_code = ip;
6470                                 ins->inst_i0 = *sp;
6471                                 ip += 5;
6472                                 MONO_INST_NEW (cfg, ins, OP_BR);
6473                                 ins->cil_code = ip;
6474                                 MONO_ADD_INS (bblock, ins);
6475                                 if (*ip == CEE_BRTRUE_S) {
6476                                         CHECK_OPSIZE (2);
6477                                         ip++;
6478                                         target = ip + 1 + (signed char)(*ip);
6479                                         ip++;
6480                                 } else {
6481                                         CHECK_OPSIZE (5);
6482                                         ip++;
6483                                         target = ip + 4 + (gint)(read32 (ip));
6484                                         ip += 4;
6485                                 }
6486                                 GET_BBLOCK (cfg, tblock, target);
6487                                 link_bblock (cfg, bblock, tblock);
6488                                 CHECK_BBLOCK (target, ip, tblock);
6489                                 ins->inst_target_bb = tblock;
6490                                 GET_BBLOCK (cfg, tblock, ip);
6491                                 link_bblock (cfg, bblock, tblock);
6492                                 if (sp != stack_start) {
6493                                         handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
6494                                         sp = stack_start;
6495                                         CHECK_UNVERIFIABLE (cfg);
6496                                 }
6497                                 start_new_bblock = 1;
6498                                 break;
6499                         }
6500                         *sp++ = handle_box (cfg, bblock, val, ip, klass);
6501                         ip += 5;
6502                         inline_costs += 1;
6503                         break;
6504                 }
6505                 case CEE_NEWARR:
6506                         CHECK_STACK (1);
6507                         MONO_INST_NEW (cfg, ins, *ip);
6508                         ins->cil_code = ip;
6509                         --sp;
6510
6511                         CHECK_OPSIZE (5);
6512                         token = read32 (ip + 1);
6513
6514                         /* allocate the domainvar - becaus this is used in decompose_foreach */
6515                         if (cfg->opt & MONO_OPT_SHARED) {
6516                                 mono_get_domainvar (cfg);
6517                                 /* LAME-IR: Mark it as used since otherwise it will be optimized away */
6518                                 cfg->domainvar->flags |= MONO_INST_VOLATILE;
6519                         }
6520
6521                         /* Ditto */
6522                         mono_get_got_var (cfg);
6523
6524                         klass = mini_get_class (method, token, generic_context);
6525                         CHECK_TYPELOAD (klass);
6526                         ins->inst_newa_class = klass;
6527                         ins->inst_newa_len = *sp;
6528                         ins->type = STACK_OBJ;
6529                         ins->klass = mono_array_class_get (klass, 1);
6530                         ip += 5;
6531                         *sp++ = ins;
6532                         /* 
6533                          * we store the object so calls to create the array are not interleaved
6534                          * with the arguments of other calls.
6535                          */
6536                         if (1) {
6537                                 MonoInst *store, *temp, *load;
6538                                 const char *data_ptr;
6539                                 int data_size = 0;
6540                                 --sp;
6541                                 temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
6542                                 NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
6543                                 store->cil_code = ins->cil_code;
6544                                 MONO_ADD_INS (bblock, store);
6545                                 /* 
6546                                  * we inline/optimize the initialization sequence if possible.
6547                                  * we should also allocate the array as not cleared, since we spend as much time clearing to 0 as initializing
6548                                  * for small sizes open code the memcpy
6549                                  * ensure the rva field is big enough
6550                                  */
6551                                 if ((cfg->opt & MONO_OPT_INTRINS) && ip_in_bb (cfg, bblock, ip + 6) && (data_ptr = initialize_array_data (method, cfg->compile_aot, ip, ins, &data_size))) {
6552                                         MonoMethod *memcpy_method = get_memcpy_method ();
6553                                         MonoInst *data_offset, *add;
6554                                         MonoInst *iargs [3];
6555                                         NEW_ICONST (cfg, iargs [2], data_size);
6556                                         NEW_TEMPLOAD (cfg, load, temp->inst_c0);
6557                                         load->cil_code = ins->cil_code;
6558                                         NEW_ICONST (cfg, data_offset, G_STRUCT_OFFSET (MonoArray, vector));
6559                                         MONO_INST_NEW (cfg, add, OP_PADD);
6560                                         add->inst_left = load;
6561                                         add->inst_right = data_offset;
6562                                         add->cil_code = ip;
6563                                         iargs [0] = add;
6564                                         if (cfg->compile_aot) {
6565                                                 NEW_AOTCONST_TOKEN (cfg, iargs [1], MONO_PATCH_INFO_RVA, method->klass->image, GPOINTER_TO_UINT(data_ptr), STACK_PTR, NULL);
6566                                         } else {
6567                                                 NEW_PCONST (cfg, iargs [1], (char*)data_ptr);
6568                                         }
6569                                         mono_emit_method_call_spilled (cfg, bblock, memcpy_method, memcpy_method->signature, iargs, ip, NULL);
6570                                         ip += 11;
6571                                 }
6572                                 NEW_TEMPLOAD (cfg, load, temp->inst_c0);
6573                                 load->cil_code = ins->cil_code;
6574                                 *sp++ = load;
6575                         }
6576                         inline_costs += 1;
6577                         break;
6578                 case CEE_LDLEN:
6579                         CHECK_STACK (1);
6580                         --sp;
6581                         if (sp [0]->type != STACK_OBJ)
6582                                 UNVERIFIED;
6583                         MONO_INST_NEW (cfg, ins, *ip);
6584                         ins->cil_code = ip++;
6585                         ins->inst_left = *sp;
6586                         ins->type = STACK_PTR;
6587                         *sp++ = ins;
6588                         break;
6589                 case CEE_LDELEMA:
6590                         CHECK_STACK (2);
6591                         sp -= 2;
6592                         CHECK_OPSIZE (5);
6593                         if (sp [0]->type != STACK_OBJ)
6594                                 UNVERIFIED;
6595
6596                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
6597                         CHECK_TYPELOAD (klass);
6598                         /* we need to make sure that this array is exactly the type it needs
6599                          * to be for correctness. the wrappers are lax with their usage
6600                          * so we need to ignore them here
6601                          */
6602                         if (!klass->valuetype && method->wrapper_type == MONO_WRAPPER_NONE) {
6603                                 MonoInst* check;
6604
6605                                 /* Needed by the code generated in inssel.brg */
6606                                 mono_get_got_var (cfg);
6607
6608                                 MONO_INST_NEW (cfg, check, OP_CHECK_ARRAY_TYPE);
6609                                 check->cil_code = ip;
6610                                 check->klass = klass;
6611                                 check->inst_left = sp [0];
6612                                 check->type = STACK_OBJ;
6613                                 check->klass = klass;
6614                                 sp [0] = check;
6615                         }
6616                         
6617                         mono_class_init (klass);
6618                         NEW_LDELEMA (cfg, ins, sp, klass);
6619                         ins->cil_code = ip;
6620                         *sp++ = ins;
6621                         ip += 5;
6622                         break;
6623                 case CEE_LDELEM_ANY: {
6624                         MonoInst *load;
6625                         CHECK_STACK (2);
6626                         sp -= 2;
6627                         if (sp [0]->type != STACK_OBJ)
6628                                 UNVERIFIED;
6629                         CHECK_OPSIZE (5);
6630                         token = read32 (ip + 1);
6631                         klass = mono_class_get_full (image, token, generic_context);
6632                         CHECK_TYPELOAD (klass);
6633                         mono_class_init (klass);
6634                         NEW_LDELEMA (cfg, load, sp, klass);
6635                         load->cil_code = ip;
6636                         MONO_INST_NEW (cfg, ins, mono_type_to_ldind (&klass->byval_arg));
6637                         ins->cil_code = ip;
6638                         ins->inst_left = load;
6639                         *sp++ = ins;
6640                         type_to_eval_stack_type (&klass->byval_arg, ins);
6641                         ip += 5;
6642                         break;
6643                 }
6644                 case CEE_LDELEM_I1:
6645                 case CEE_LDELEM_U1:
6646                 case CEE_LDELEM_I2:
6647                 case CEE_LDELEM_U2:
6648                 case CEE_LDELEM_I4:
6649                 case CEE_LDELEM_U4:
6650                 case CEE_LDELEM_I8:
6651                 case CEE_LDELEM_I:
6652                 case CEE_LDELEM_R4:
6653                 case CEE_LDELEM_R8:
6654                 case CEE_LDELEM_REF: {
6655                         MonoInst *load;
6656                         /*
6657                          * translate to:
6658                          * ldind.x (ldelema (array, index))
6659                          * ldelema does the bounds check
6660                          */
6661                         CHECK_STACK (2);
6662                         sp -= 2;
6663                         if (sp [0]->type != STACK_OBJ)
6664                                 UNVERIFIED;
6665                         klass = array_access_to_klass (*ip, sp [0]);
6666                         NEW_LDELEMA (cfg, load, sp, klass);
6667                         load->cil_code = ip;
6668 #ifdef MONO_ARCH_SOFT_FLOAT
6669                         if (*ip == CEE_LDELEM_R4) {
6670                                 int temp;
6671                                 temp = handle_load_float (cfg, bblock, load, ip);
6672                                 NEW_TEMPLOAD (cfg, *sp, temp);
6673                                 sp++;
6674                                 ++ip;
6675                                 break;
6676                         }
6677 #endif
6678                         MONO_INST_NEW (cfg, ins, ldelem_to_ldind [*ip - CEE_LDELEM_I1]);
6679                         ins->cil_code = ip;
6680                         ins->inst_left = load;
6681                         *sp++ = ins;
6682                         ins->type = ldind_type [ins->opcode - CEE_LDIND_I1];
6683                         ins->klass = klass;
6684                         ++ip;
6685                         break;
6686                 }
6687                 case CEE_STELEM_I:
6688                 case CEE_STELEM_I1:
6689                 case CEE_STELEM_I2:
6690                 case CEE_STELEM_I4:
6691                 case CEE_STELEM_I8:
6692                 case CEE_STELEM_R4:
6693                 case CEE_STELEM_R8: {
6694                         MonoInst *load;
6695                         /*
6696                          * translate to:
6697                          * stind.x (ldelema (array, index), val)
6698                          * ldelema does the bounds check
6699                          */
6700                         CHECK_STACK (3);
6701                         sp -= 3;
6702                         if (sp [0]->type != STACK_OBJ)
6703                                 UNVERIFIED;
6704                         klass = array_access_to_klass (*ip, sp [0]);
6705                         NEW_LDELEMA (cfg, load, sp, klass);
6706                         load->cil_code = ip;
6707 #ifdef MONO_ARCH_SOFT_FLOAT
6708                         if (*ip == CEE_STELEM_R4) {
6709                                 handle_store_float (cfg, bblock, load, sp [2], ip);
6710                                 ip++;
6711                                 break;
6712                         }
6713 #endif
6714                         MONO_INST_NEW (cfg, ins, stelem_to_stind [*ip - CEE_STELEM_I]);
6715                         ins->cil_code = ip;
6716                         ins->inst_left = load;
6717                         ins->inst_right = sp [2];
6718                         ++ip;
6719                         handle_loaded_temps (cfg, bblock, stack_start, sp);
6720                         MONO_ADD_INS (bblock, ins);
6721                         inline_costs += 1;
6722                         break;
6723                 }
6724                 case CEE_STELEM_ANY: {
6725                         MonoInst *load;
6726                         /*
6727                          * translate to:
6728                          * stind.x (ldelema (array, index), val)
6729                          * ldelema does the bounds check
6730                          */
6731                         CHECK_STACK (3);
6732                         sp -= 3;
6733                         if (sp [0]->type != STACK_OBJ)
6734                                 UNVERIFIED;
6735                         CHECK_OPSIZE (5);
6736                         token = read32 (ip + 1);
6737                         klass = mono_class_get_full (image, token, generic_context);
6738                         CHECK_TYPELOAD (klass);
6739                         mono_class_init (klass);
6740                         if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
6741                                 /* storing a NULL doesn't need any of the complex checks in stelemref */
6742                                 if (sp [2]->opcode == OP_PCONST && sp [2]->inst_p0 == NULL) {
6743                                         MonoInst *load;
6744                                         NEW_LDELEMA (cfg, load, sp, mono_defaults.object_class);
6745                                         load->cil_code = ip;
6746                                         MONO_INST_NEW (cfg, ins, stelem_to_stind [*ip - CEE_STELEM_I]);
6747                                         ins->cil_code = ip;
6748                                         ins->inst_left = load;
6749                                         ins->inst_right = sp [2];
6750                                         MONO_ADD_INS (bblock, ins);
6751                                 } else {
6752                                         MonoMethod* helper = mono_marshal_get_stelemref ();
6753                                         MonoInst *iargs [3];
6754                                         handle_loaded_temps (cfg, bblock, stack_start, sp);
6755
6756                                         iargs [2] = sp [2];
6757                                         iargs [1] = sp [1];
6758                                         iargs [0] = sp [0];
6759
6760                                         mono_emit_method_call_spilled (cfg, bblock, helper, mono_method_signature (helper), iargs, ip, NULL);
6761                                 }
6762                         } else {
6763                                 NEW_LDELEMA (cfg, load, sp, klass);
6764                                 load->cil_code = ip;
6765
6766                                 n = mono_type_to_stind (&klass->byval_arg);
6767                                 if (n == CEE_STOBJ)
6768                                         handle_stobj (cfg, bblock, load, sp [2], ip, klass, FALSE, FALSE, TRUE);
6769                                 else {
6770                                         MONO_INST_NEW (cfg, ins, n);
6771                                         ins->cil_code = ip;
6772                                         ins->inst_left = load;
6773                                         ins->inst_right = sp [2];
6774                                         handle_loaded_temps (cfg, bblock, stack_start, sp);
6775                                         MONO_ADD_INS (bblock, ins);
6776                                 }
6777                         }
6778                         ip += 5;
6779                         inline_costs += 1;
6780                         break;
6781                 }
6782                 case CEE_STELEM_REF: {
6783                         MonoInst *iargs [3];
6784                         MonoMethod* helper = mono_marshal_get_stelemref ();
6785
6786                         CHECK_STACK (3);
6787                         sp -= 3;
6788                         if (sp [0]->type != STACK_OBJ)
6789                                 UNVERIFIED;
6790                         if (sp [2]->type != STACK_OBJ)
6791                                 UNVERIFIED;
6792
6793                         handle_loaded_temps (cfg, bblock, stack_start, sp);
6794
6795                         /* storing a NULL doesn't need any of the complex checks in stelemref */
6796                         if (sp [2]->opcode == OP_PCONST && sp [2]->inst_p0 == NULL) {
6797                                 MonoInst *load;
6798                                 NEW_LDELEMA (cfg, load, sp, mono_defaults.object_class);
6799                                 load->cil_code = ip;
6800                                 MONO_INST_NEW (cfg, ins, stelem_to_stind [*ip - CEE_STELEM_I]);
6801                                 ins->cil_code = ip;
6802                                 ins->inst_left = load;
6803                                 ins->inst_right = sp [2];
6804                                 MONO_ADD_INS (bblock, ins);
6805                         } else {
6806                                 iargs [2] = sp [2];
6807                                 iargs [1] = sp [1];
6808                                 iargs [0] = sp [0];
6809                         
6810                                 mono_emit_method_call_spilled (cfg, bblock, helper, mono_method_signature (helper), iargs, ip, NULL);
6811                                 inline_costs += 1;
6812                         }
6813
6814                         ++ip;
6815                         break;
6816                 }
6817                 case CEE_CKFINITE: {
6818                         MonoInst *store, *temp;
6819                         CHECK_STACK (1);
6820
6821                         /* this instr. can throw exceptions as side effect,
6822                          * so we cant eliminate dead code which contains CKFINITE opdodes.
6823                          * Spilling to memory makes sure that we always perform
6824                          * this check */
6825
6826                         
6827                         MONO_INST_NEW (cfg, ins, OP_CKFINITE);
6828                         ins->cil_code = ip;
6829                         ins->inst_left = sp [-1];
6830                         temp = mono_compile_create_var (cfg, &mono_defaults.double_class->byval_arg, OP_LOCAL);
6831
6832                         NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
6833                         store->cil_code = ip;
6834                         MONO_ADD_INS (bblock, store);
6835
6836                         NEW_TEMPLOAD (cfg, sp [-1], temp->inst_c0);
6837                        
6838                         ++ip;
6839                         break;
6840                 }
6841                 case CEE_REFANYVAL:
6842                         CHECK_STACK (1);
6843                         MONO_INST_NEW (cfg, ins, *ip);
6844                         --sp;
6845                         CHECK_OPSIZE (5);
6846                         klass = mono_class_get_full (image, read32 (ip + 1), generic_context);
6847                         CHECK_TYPELOAD (klass);
6848                         mono_class_init (klass);
6849                         ins->type = STACK_MP;
6850                         ins->inst_left = *sp;
6851                         ins->klass = klass;
6852                         ins->inst_newa_class = klass;
6853                         ins->cil_code = ip;
6854                         ip += 5;
6855                         *sp++ = ins;
6856                         break;
6857                 case CEE_MKREFANY: {
6858                         MonoInst *loc, *klassconst;
6859
6860                         CHECK_STACK (1);
6861                         MONO_INST_NEW (cfg, ins, *ip);
6862                         --sp;
6863                         CHECK_OPSIZE (5);
6864                         klass = mono_class_get_full (image, read32 (ip + 1), generic_context);
6865                         CHECK_TYPELOAD (klass);
6866                         mono_class_init (klass);
6867                         ins->cil_code = ip;
6868
6869                         loc = mono_compile_create_var (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL);
6870                         NEW_TEMPLOADA (cfg, ins->inst_right, loc->inst_c0);
6871
6872                         NEW_PCONST (cfg, klassconst, klass);
6873                         NEW_GROUP (cfg, ins->inst_left, *sp, klassconst);
6874                         
6875                         MONO_ADD_INS (bblock, ins);
6876
6877                         NEW_TEMPLOAD (cfg, *sp, loc->inst_c0);
6878                         ++sp;
6879                         ip += 5;
6880                         break;
6881                 }
6882                 case CEE_LDTOKEN: {
6883                         gpointer handle;
6884                         MonoClass *handle_class;
6885
6886                         CHECK_STACK_OVF (1);
6887
6888                         CHECK_OPSIZE (5);
6889                         n = read32 (ip + 1);
6890
6891                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
6892                                 handle = mono_method_get_wrapper_data (method, n);
6893                                 handle_class = mono_method_get_wrapper_data (method, n + 1);
6894                                 if (handle_class == mono_defaults.typehandle_class)
6895                                         handle = &((MonoClass*)handle)->byval_arg;
6896                         }
6897                         else {
6898                                 handle = mono_ldtoken (image, n, &handle_class, generic_context);
6899                         }
6900                         if (!handle)
6901                                 goto load_error;
6902                         mono_class_init (handle_class);
6903
6904                         if (cfg->opt & MONO_OPT_SHARED) {
6905                                 int temp;
6906                                 MonoInst *res, *store, *addr, *vtvar, *iargs [3];
6907
6908                                 vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL); 
6909
6910                                 NEW_IMAGECONST (cfg, iargs [0], image);
6911                                 NEW_ICONST (cfg, iargs [1], n);
6912                                 NEW_PCONST (cfg, iargs [2], generic_context);
6913                                 temp = mono_emit_jit_icall (cfg, bblock, mono_ldtoken_wrapper, iargs, ip);
6914                                 NEW_TEMPLOAD (cfg, res, temp);
6915                                 NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
6916                                 NEW_INDSTORE (cfg, store, addr, res, &mono_defaults.int_class->byval_arg);
6917                                 MONO_ADD_INS (bblock, store);
6918                                 NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
6919                         } else {
6920                                 if ((ip [5] == CEE_CALL) && (cmethod = mini_get_method (method, read32 (ip + 6), NULL, generic_context)) &&
6921                                                 (cmethod->klass == mono_defaults.monotype_class->parent) &&
6922                                                 (strcmp (cmethod->name, "GetTypeFromHandle") == 0) && ip_in_bb (cfg, bblock, ip + 5)) {
6923                                         MonoClass *tclass = mono_class_from_mono_type (handle);
6924                                         mono_class_init (tclass);
6925                                         if (cfg->compile_aot)
6926                                                 NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, image, n);
6927                                         else
6928                                                 NEW_PCONST (cfg, ins, mono_type_get_object (cfg->domain, handle));
6929                                         ins->type = STACK_OBJ;
6930                                         ins->klass = cmethod->klass;
6931                                         ip += 5;
6932                                 } else {
6933                                         MonoInst *store, *addr, *vtvar;
6934
6935                                         if (cfg->compile_aot)
6936                                                 NEW_LDTOKENCONST (cfg, ins, image, n);
6937                                         else
6938                                                 NEW_PCONST (cfg, ins, handle);
6939                                         vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL);
6940                                         NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
6941                                         NEW_INDSTORE (cfg, store, addr, ins, &mono_defaults.int_class->byval_arg);
6942                                         MONO_ADD_INS (bblock, store);
6943                                         NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
6944                                 }
6945                         }
6946
6947                         *sp++ = ins;
6948                         ip += 5;
6949                         break;
6950                 }
6951                 case CEE_CONV_U2:
6952                 case CEE_CONV_U1:
6953                 case CEE_CONV_I:
6954                         CHECK_STACK (1);
6955                         ADD_UNOP (*ip);
6956                         ip++;
6957                         break;
6958                 case CEE_ADD_OVF:
6959                 case CEE_ADD_OVF_UN:
6960                 case CEE_MUL_OVF:
6961                 case CEE_MUL_OVF_UN:
6962                 case CEE_SUB_OVF:
6963                 case CEE_SUB_OVF_UN:
6964                         CHECK_STACK (2);
6965                         ADD_BINOP (*ip);
6966                         if (mono_find_jit_opcode_emulation (ins->opcode)) {
6967                                 --sp;
6968                                 *sp++ = emit_tree (cfg, bblock, ins, ip + 1);
6969                         }
6970                         ip++;
6971                         break;
6972                 case CEE_ENDFINALLY:
6973                         MONO_INST_NEW (cfg, ins, OP_ENDFINALLY);
6974                         MONO_ADD_INS (bblock, ins);
6975                         ins->cil_code = ip++;
6976                         start_new_bblock = 1;
6977
6978                         /*
6979                          * Control will leave the method so empty the stack, otherwise
6980                          * the next basic block will start with a nonempty stack.
6981                          */
6982                         while (sp != stack_start) {
6983                                 MONO_INST_NEW (cfg, ins, CEE_POP);
6984                                 ins->cil_code = ip;
6985                                 sp--;
6986                                 ins->inst_i0 = *sp;
6987                                 MONO_ADD_INS (bblock, ins);
6988                         }
6989                         break;
6990                 case CEE_LEAVE:
6991                 case CEE_LEAVE_S: {
6992                         GList *handlers;
6993
6994                         if (*ip == CEE_LEAVE) {
6995                                 CHECK_OPSIZE (5);
6996                                 target = ip + 5 + (gint32)read32(ip + 1);
6997                         } else {
6998                                 CHECK_OPSIZE (2);
6999                                 target = ip + 2 + (signed char)(ip [1]);
7000                         }
7001
7002                         /* empty the stack */
7003                         while (sp != stack_start) {
7004                                 MONO_INST_NEW (cfg, ins, CEE_POP);
7005                                 ins->cil_code = ip;
7006                                 sp--;
7007                                 ins->inst_i0 = *sp;
7008                                 MONO_ADD_INS (bblock, ins);
7009                         }
7010
7011                         /* 
7012                          * If this leave statement is in a catch block, check for a
7013                          * pending exception, and rethrow it if necessary.
7014                          */
7015                         for (i = 0; i < header->num_clauses; ++i) {
7016                                 MonoExceptionClause *clause = &header->clauses [i];
7017
7018                                 /* 
7019                                  * Use <= in the final comparison to handle clauses with multiple
7020                                  * leave statements, like in bug #78024.
7021                                  * The ordering of the exception clauses guarantees that we find the
7022                                  * innermost clause.
7023                                  */
7024                                 if (MONO_OFFSET_IN_HANDLER (clause, ip - header->code) && (clause->flags == MONO_EXCEPTION_CLAUSE_NONE) && (ip - header->code + ((*ip == CEE_LEAVE) ? 5 : 2)) <= (clause->handler_offset + clause->handler_len)) {
7025                                         int temp;
7026                                         MonoInst *load;
7027
7028                                         NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, clause->handler_offset)->inst_c0);
7029                                         load->cil_code = ip;
7030
7031                                         temp = mono_emit_jit_icall (cfg, bblock, mono_thread_get_pending_exception, NULL, ip);
7032                                         NEW_TEMPLOAD (cfg, *sp, temp);
7033                                 
7034                                         MONO_INST_NEW (cfg, ins, OP_THROW_OR_NULL);
7035                                         ins->inst_left = *sp;
7036                                         ins->inst_right = load;
7037                                         ins->cil_code = ip;
7038                                         MONO_ADD_INS (bblock, ins);
7039                                 }
7040                         }
7041
7042                         if ((handlers = mono_find_final_block (cfg, ip, target, MONO_EXCEPTION_CLAUSE_FINALLY))) {
7043                                 GList *tmp;
7044                                 for (tmp = handlers; tmp; tmp = tmp->next) {
7045                                         tblock = tmp->data;
7046                                         link_bblock (cfg, bblock, tblock);
7047                                         MONO_INST_NEW (cfg, ins, OP_CALL_HANDLER);
7048                                         ins->cil_code = ip;
7049                                         ins->inst_target_bb = tblock;
7050                                         MONO_ADD_INS (bblock, ins);
7051                                 }
7052                                 g_list_free (handlers);
7053                         } 
7054
7055                         MONO_INST_NEW (cfg, ins, OP_BR);
7056                         ins->cil_code = ip;
7057                         MONO_ADD_INS (bblock, ins);
7058                         GET_BBLOCK (cfg, tblock, target);
7059                         link_bblock (cfg, bblock, tblock);
7060                         CHECK_BBLOCK (target, ip, tblock);
7061                         ins->inst_target_bb = tblock;
7062                         start_new_bblock = 1;
7063
7064                         if (*ip == CEE_LEAVE)
7065                                 ip += 5;
7066                         else
7067                                 ip += 2;
7068
7069                         break;
7070                 }
7071                 case CEE_STIND_I:
7072                         CHECK_STACK (2);
7073                         MONO_INST_NEW (cfg, ins, *ip);
7074                         sp -= 2;
7075                         handle_loaded_temps (cfg, bblock, stack_start, sp);
7076                         MONO_ADD_INS (bblock, ins);
7077                         ins->cil_code = ip++;
7078                         ins->inst_i0 = sp [0];
7079                         ins->inst_i1 = sp [1];
7080                         inline_costs += 1;
7081                         break;
7082                 case CEE_CONV_U:
7083                         CHECK_STACK (1);
7084                         ADD_UNOP (*ip);
7085                         ip++;
7086                         break;
7087                 /* trampoline mono specific opcodes */
7088                 case MONO_CUSTOM_PREFIX: {
7089
7090                         g_assert (method->wrapper_type != MONO_WRAPPER_NONE);
7091
7092                         CHECK_OPSIZE (2);
7093                         switch (ip [1]) {
7094
7095                         case CEE_MONO_ICALL: {
7096                                 int temp;
7097                                 gpointer func;
7098                                 MonoJitICallInfo *info;
7099
7100                                 token = read32 (ip + 2);
7101                                 func = mono_method_get_wrapper_data (method, token);
7102                                 info = mono_find_jit_icall_by_addr (func);
7103                                 if (info == NULL){
7104                                         g_error ("An attempt has been made to perform an icall to address %p, "
7105                                                  "but the address has not been registered as an icall\n", info);
7106                                         g_assert_not_reached ();
7107                                 }
7108
7109                                 CHECK_STACK (info->sig->param_count);
7110                                 sp -= info->sig->param_count;
7111
7112                                 temp = mono_emit_jit_icall (cfg, bblock, info->func, sp, ip);
7113                                 if (!MONO_TYPE_IS_VOID (info->sig->ret)) {
7114                                         NEW_TEMPLOAD (cfg, *sp, temp);
7115                                         sp++;
7116                                 }
7117
7118                                 ip += 6;
7119                                 inline_costs += 10 * num_calls++;
7120
7121                                 break;
7122                         }
7123                         case CEE_MONO_LDPTR:
7124                                 CHECK_STACK_OVF (1);
7125                                 CHECK_OPSIZE (6);
7126                                 token = read32 (ip + 2);
7127                                 NEW_PCONST (cfg, ins, mono_method_get_wrapper_data (method, token));
7128                                 ins->cil_code = ip;
7129                                 *sp++ = ins;
7130                                 ip += 6;
7131                                 inline_costs += 10 * num_calls++;
7132                                 /* Can't embed random pointers into AOT code */
7133                                 cfg->disable_aot = 1;
7134                                 break;
7135                         case CEE_MONO_VTADDR:
7136                                 CHECK_STACK (1);
7137                                 --sp;
7138                                 MONO_INST_NEW (cfg, ins, OP_VTADDR);
7139                                 ins->cil_code = ip;
7140                                 ins->type = STACK_MP;
7141                                 ins->inst_left = *sp;
7142                                 *sp++ = ins;
7143                                 ip += 2;
7144                                 break;
7145                         case CEE_MONO_NEWOBJ: {
7146                                 MonoInst *iargs [2];
7147                                 int temp;
7148                                 CHECK_STACK_OVF (1);
7149                                 CHECK_OPSIZE (6);
7150                                 token = read32 (ip + 2);
7151                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
7152                                 mono_class_init (klass);
7153                                 NEW_DOMAINCONST (cfg, iargs [0]);
7154                                 NEW_CLASSCONST (cfg, iargs [1], klass);
7155                                 temp = mono_emit_jit_icall (cfg, bblock, mono_object_new, iargs, ip);
7156                                 NEW_TEMPLOAD (cfg, *sp, temp);
7157                                 sp++;
7158                                 ip += 6;
7159                                 inline_costs += 10 * num_calls++;
7160                                 break;
7161                         }
7162                         case CEE_MONO_OBJADDR:
7163                                 CHECK_STACK (1);
7164                                 --sp;
7165                                 MONO_INST_NEW (cfg, ins, OP_OBJADDR);
7166                                 ins->cil_code = ip;
7167                                 ins->type = STACK_MP;
7168                                 ins->inst_left = *sp;
7169                                 *sp++ = ins;
7170                                 ip += 2;
7171                                 break;
7172                         case CEE_MONO_LDNATIVEOBJ:
7173                                 CHECK_STACK (1);
7174                                 CHECK_OPSIZE (6);
7175                                 token = read32 (ip + 2);
7176                                 klass = mono_method_get_wrapper_data (method, token);
7177                                 g_assert (klass->valuetype);
7178                                 mono_class_init (klass);
7179                                 NEW_INDLOAD (cfg, ins, sp [-1], &klass->byval_arg);
7180                                 sp [-1] = ins;
7181                                 ip += 6;
7182                                 break;
7183                         case CEE_MONO_RETOBJ:
7184                                 g_assert (cfg->ret);
7185                                 g_assert (mono_method_signature (method)->pinvoke); 
7186                                 CHECK_STACK (1);
7187                                 --sp;
7188                                 
7189                                 CHECK_OPSIZE (6);
7190                                 token = read32 (ip + 2);    
7191                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
7192
7193                                 NEW_RETLOADA (cfg, ins);
7194                                 handle_stobj (cfg, bblock, ins, *sp, ip, klass, FALSE, TRUE, FALSE);
7195                                 
7196                                 if (sp != stack_start)
7197                                         UNVERIFIED;
7198                                 
7199                                 MONO_INST_NEW (cfg, ins, OP_BR);
7200                                 ins->cil_code = ip;
7201                                 ins->inst_target_bb = end_bblock;
7202                                 MONO_ADD_INS (bblock, ins);
7203                                 link_bblock (cfg, bblock, end_bblock);
7204                                 start_new_bblock = 1;
7205                                 ip += 6;
7206                                 break;
7207                         case CEE_MONO_CISINST:
7208                         case CEE_MONO_CCASTCLASS: {
7209                                 int token;
7210                                 CHECK_STACK (1);
7211                                 --sp;
7212                                 CHECK_OPSIZE (6);
7213                                 token = read32 (ip + 2);
7214                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
7215                                 MONO_INST_NEW (cfg, ins, (ip [1] == CEE_MONO_CISINST) ? OP_CISINST : OP_CCASTCLASS);
7216                                 ins->type = STACK_I4;
7217                                 ins->inst_left = *sp;
7218                                 ins->inst_newa_class = klass;
7219                                 ins->cil_code = ip;
7220                                 *sp++ = emit_tree (cfg, bblock, ins, ip + 6);
7221                                 ip += 6;
7222                                 break;
7223                         }
7224                         case CEE_MONO_SAVE_LMF:
7225                         case CEE_MONO_RESTORE_LMF:
7226 #ifdef MONO_ARCH_HAVE_LMF_OPS
7227                                 MONO_INST_NEW (cfg, ins, (ip [1] == CEE_MONO_SAVE_LMF) ? OP_SAVE_LMF : OP_RESTORE_LMF);
7228                                 MONO_ADD_INS (bblock, ins);
7229                                 cfg->need_lmf_area = TRUE;
7230 #endif
7231                                 ip += 2;
7232                                 break;
7233                         case CEE_MONO_CLASSCONST:
7234                                 CHECK_STACK_OVF (1);
7235                                 CHECK_OPSIZE (6);
7236                                 token = read32 (ip + 2);
7237                                 NEW_CLASSCONST (cfg, ins, mono_method_get_wrapper_data (method, token));
7238                                 ins->cil_code = ip;
7239                                 *sp++ = ins;
7240                                 ip += 6;
7241                                 inline_costs += 10 * num_calls++;
7242                                 break;
7243                         case CEE_MONO_NOT_TAKEN:
7244                                 bblock->out_of_line = TRUE;
7245                                 ip += 2;
7246                                 break;
7247                         default:
7248                                 g_error ("opcode 0x%02x 0x%02x not handled", MONO_CUSTOM_PREFIX, ip [1]);
7249                                 break;
7250                         }
7251                         break;
7252                 }
7253                 case CEE_PREFIX1: {
7254                         CHECK_OPSIZE (2);
7255                         switch (ip [1]) {
7256                         case CEE_ARGLIST: {
7257                                 /* somewhat similar to LDTOKEN */
7258                                 MonoInst *addr, *vtvar;
7259                                 CHECK_STACK_OVF (1);
7260                                 vtvar = mono_compile_create_var (cfg, &mono_defaults.argumenthandle_class->byval_arg, OP_LOCAL); 
7261
7262                                 NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
7263                                 addr->cil_code = ip;
7264                                 MONO_INST_NEW (cfg, ins, OP_ARGLIST);
7265                                 ins->cil_code = ip;
7266                                 ins->inst_left = addr;
7267                                 MONO_ADD_INS (bblock, ins);
7268                                 NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
7269                                 ins->cil_code = ip;
7270                                 *sp++ = ins;
7271                                 ip += 2;
7272                                 break;
7273                         }
7274                         case CEE_CEQ:
7275                         case CEE_CGT:
7276                         case CEE_CGT_UN:
7277                         case CEE_CLT:
7278                         case CEE_CLT_UN: {
7279                                 MonoInst *cmp;
7280                                 CHECK_STACK (2);
7281                                 /*
7282                                  * The following transforms:
7283                                  *    CEE_CEQ    into OP_CEQ
7284                                  *    CEE_CGT    into OP_CGT
7285                                  *    CEE_CGT_UN into OP_CGT_UN
7286                                  *    CEE_CLT    into OP_CLT
7287                                  *    CEE_CLT_UN into OP_CLT_UN
7288                                  */
7289                                 MONO_INST_NEW (cfg, cmp, 256 + ip [1]);
7290                                 
7291                                 MONO_INST_NEW (cfg, ins, cmp->opcode);
7292                                 sp -= 2;
7293                                 cmp->inst_i0 = sp [0];
7294                                 cmp->inst_i1 = sp [1];
7295                                 cmp->cil_code = ip;
7296                                 type_from_op (cmp);
7297                                 CHECK_TYPE (cmp);
7298                                 ins->cil_code = ip;
7299                                 ins->type = STACK_I4;
7300                                 ins->inst_i0 = cmp;
7301 #if MONO_ARCH_SOFT_FLOAT
7302                                 if (sp [0]->type == STACK_R8) {
7303                                         cmp->type = STACK_I4;
7304                                         *sp++ = emit_tree (cfg, bblock, cmp, ip + 2);
7305                                         ip += 2;
7306                                         break;
7307                                 }
7308 #endif
7309                                 if ((sp [0]->type == STACK_I8) || ((sizeof (gpointer) == 8) && ((sp [0]->type == STACK_PTR) || (sp [0]->type == STACK_OBJ) || (sp [0]->type == STACK_MP))))
7310                                         cmp->opcode = OP_LCOMPARE;
7311                                 else
7312                                         cmp->opcode = OP_COMPARE;
7313                                 *sp++ = ins;
7314                                 /* spill it to reduce the expression complexity
7315                                  * and workaround bug 54209 
7316                                  */
7317                                 if (cmp->inst_left->type == STACK_I8) {
7318                                         --sp;
7319                                         *sp++ = emit_tree (cfg, bblock, ins, ip + 2);
7320                                 }
7321                                 ip += 2;
7322                                 break;
7323                         }
7324                         case CEE_LDFTN: {
7325                                 MonoInst *argconst;
7326                                 int temp;
7327
7328                                 CHECK_STACK_OVF (1);
7329                                 CHECK_OPSIZE (6);
7330                                 n = read32 (ip + 2);
7331                                 cmethod = mini_get_method (method, n, NULL, generic_context);
7332                                 if (!cmethod)
7333                                         goto load_error;
7334                                 mono_class_init (cmethod->klass);
7335
7336                                 if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS) {
7337                                         if (check_linkdemand (cfg, method, cmethod, bblock, ip))
7338                                                 INLINE_FAILURE;
7339                                         CHECK_CFG_EXCEPTION;
7340                                 } else if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR) {
7341                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod, bblock, ip);
7342                                 }
7343
7344                                 handle_loaded_temps (cfg, bblock, stack_start, sp);
7345
7346                                 NEW_METHODCONST (cfg, argconst, cmethod);
7347                                 if (method->wrapper_type != MONO_WRAPPER_SYNCHRONIZED)
7348                                         temp = mono_emit_jit_icall (cfg, bblock, mono_ldftn, &argconst, ip);
7349                                 else
7350                                         temp = mono_emit_jit_icall (cfg, bblock, mono_ldftn_nosync, &argconst, ip);
7351                                 NEW_TEMPLOAD (cfg, *sp, temp);
7352                                 sp ++;
7353                                 
7354                                 ip += 6;
7355                                 inline_costs += 10 * num_calls++;
7356                                 break;
7357                         }
7358                         case CEE_LDVIRTFTN: {
7359                                 MonoInst *args [2];
7360                                 int temp;
7361
7362                                 CHECK_STACK (1);
7363                                 CHECK_OPSIZE (6);
7364                                 n = read32 (ip + 2);
7365                                 cmethod = mini_get_method (method, n, NULL, generic_context);
7366                                 if (!cmethod)
7367                                         goto load_error;
7368                                 mono_class_init (cmethod->klass);
7369
7370                                 if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS) {
7371                                         if (check_linkdemand (cfg, method, cmethod, bblock, ip))
7372                                                 INLINE_FAILURE;
7373                                         CHECK_CFG_EXCEPTION;
7374                                 } else if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR) {
7375                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod, bblock, ip);
7376                                 }
7377
7378                                 handle_loaded_temps (cfg, bblock, stack_start, sp);
7379
7380                                 --sp;
7381                                 args [0] = *sp;
7382                                 NEW_METHODCONST (cfg, args [1], cmethod);
7383                                 temp = mono_emit_jit_icall (cfg, bblock, mono_ldvirtfn, args, ip);
7384                                 NEW_TEMPLOAD (cfg, *sp, temp);
7385                                 sp ++;
7386
7387                                 ip += 6;
7388                                 inline_costs += 10 * num_calls++;
7389                                 break;
7390                         }
7391                         case CEE_LDARG:
7392                                 CHECK_STACK_OVF (1);
7393                                 CHECK_OPSIZE (4);
7394                                 n = read16 (ip + 2);
7395                                 CHECK_ARG (n);
7396                                 NEW_ARGLOAD (cfg, ins, n);
7397                                 LDARG_SOFT_FLOAT (cfg, ins, n, ip);
7398                                 ins->cil_code = ip;
7399                                 *sp++ = ins;
7400                                 ip += 4;
7401                                 break;
7402                         case CEE_LDARGA:
7403                                 CHECK_STACK_OVF (1);
7404                                 CHECK_OPSIZE (4);
7405                                 n = read16 (ip + 2);
7406                                 CHECK_ARG (n);
7407                                 NEW_ARGLOADA (cfg, ins, n);
7408                                 ins->cil_code = ip;
7409                                 *sp++ = ins;
7410                                 ip += 4;
7411                                 break;
7412                         case CEE_STARG:
7413                                 CHECK_STACK (1);
7414                                 --sp;
7415                                 handle_loaded_temps (cfg, bblock, stack_start, sp);
7416                                 CHECK_OPSIZE (4);
7417                                 n = read16 (ip + 2);
7418                                 CHECK_ARG (n);
7419                                 NEW_ARGSTORE (cfg, ins, n, *sp);
7420                                 ins->cil_code = ip;
7421                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [n], *sp))
7422                                         UNVERIFIED;
7423                                 STARG_SOFT_FLOAT (cfg, ins, n, ip);
7424                                 if (ins->opcode == CEE_STOBJ) {
7425                                         NEW_ARGLOADA (cfg, ins, n);
7426                                         handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE, FALSE);
7427                                 } else
7428                                         MONO_ADD_INS (bblock, ins);
7429                                 ip += 4;
7430                                 break;
7431                         case CEE_LDLOC:
7432                                 CHECK_STACK_OVF (1);
7433                                 CHECK_OPSIZE (4);
7434                                 n = read16 (ip + 2);
7435                                 CHECK_LOCAL (n);
7436                                 NEW_LOCLOAD (cfg, ins, n);
7437                                 LDLOC_SOFT_FLOAT (cfg, ins, n, ip);
7438                                 ins->cil_code = ip;
7439                                 *sp++ = ins;
7440                                 ip += 4;
7441                                 break;
7442                         case CEE_LDLOCA:
7443                                 CHECK_STACK_OVF (1);
7444                                 CHECK_OPSIZE (4);
7445                                 n = read16 (ip + 2);
7446                                 CHECK_LOCAL (n);
7447                                 NEW_LOCLOADA (cfg, ins, n);
7448                                 ins->cil_code = ip;
7449                                 *sp++ = ins;
7450                                 ip += 4;
7451                                 break;
7452                         case CEE_STLOC:
7453                                 CHECK_STACK (1);
7454                                 --sp;
7455                                 CHECK_OPSIZE (4);
7456                                 n = read16 (ip + 2);
7457                                 CHECK_LOCAL (n);
7458                                 handle_loaded_temps (cfg, bblock, stack_start, sp);
7459                                 NEW_LOCSTORE (cfg, ins, n, *sp);
7460                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
7461                                         UNVERIFIED;
7462                                 ins->cil_code = ip;
7463                                 STLOC_SOFT_FLOAT (cfg, ins, n, ip);
7464                                 if (ins->opcode == CEE_STOBJ) {
7465                                         NEW_LOCLOADA (cfg, ins, n);
7466                                         handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE, FALSE);
7467                                 } else
7468                                         MONO_ADD_INS (bblock, ins);
7469                                 ip += 4;
7470                                 inline_costs += 1;
7471                                 break;
7472                         case CEE_LOCALLOC:
7473                                 CHECK_STACK (1);
7474                                 --sp;
7475                                 if (sp != stack_start) 
7476                                         UNVERIFIED;
7477                                 if (cfg->method != method) 
7478                                         /* 
7479                                          * Inlining this into a loop in a parent could lead to 
7480                                          * stack overflows which is different behavior than the
7481                                          * non-inlined case, thus disable inlining in this case.
7482                                          */
7483                                         goto inline_failure;
7484                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
7485                                 ins->inst_left = *sp;
7486                                 ins->cil_code = ip;
7487                                 ins->type = STACK_PTR;
7488
7489                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
7490                                 if (header->init_locals)
7491                                         ins->flags |= MONO_INST_INIT;
7492
7493                                 *sp++ = ins;
7494                                 ip += 2;
7495                                 /* FIXME: set init flag if locals init is set in this method */
7496                                 break;
7497                         case CEE_ENDFILTER: {
7498                                 MonoExceptionClause *clause, *nearest;
7499                                 int cc, nearest_num;
7500
7501                                 CHECK_STACK (1);
7502                                 --sp;
7503                                 if ((sp != stack_start) || (sp [0]->type != STACK_I4)) 
7504                                         UNVERIFIED;
7505                                 MONO_INST_NEW (cfg, ins, OP_ENDFILTER);
7506                                 ins->inst_left = *sp;
7507                                 ins->cil_code = ip;
7508                                 MONO_ADD_INS (bblock, ins);
7509                                 start_new_bblock = 1;
7510                                 ip += 2;
7511
7512                                 nearest = NULL;
7513                                 nearest_num = 0;
7514                                 for (cc = 0; cc < header->num_clauses; ++cc) {
7515                                         clause = &header->clauses [cc];
7516                                         if ((clause->flags & MONO_EXCEPTION_CLAUSE_FILTER) &&
7517                                                 ((ip - header->code) > clause->data.filter_offset && (ip - header->code) <= clause->handler_offset) &&
7518                                             (!nearest || (clause->data.filter_offset < nearest->data.filter_offset))) {
7519                                                 nearest = clause;
7520                                                 nearest_num = cc;
7521                                         }
7522                                 }
7523                                 g_assert (nearest);
7524                                 if ((ip - header->code) != nearest->handler_offset)
7525                                         UNVERIFIED;
7526
7527                                 break;
7528                         }
7529                         case CEE_UNALIGNED_:
7530                                 ins_flag |= MONO_INST_UNALIGNED;
7531                                 /* FIXME: record alignment? we can assume 1 for now */
7532                                 CHECK_OPSIZE (3);
7533                                 ip += 3;
7534                                 break;
7535                         case CEE_VOLATILE_:
7536                                 ins_flag |= MONO_INST_VOLATILE;
7537                                 ip += 2;
7538                                 break;
7539                         case CEE_TAIL_:
7540                                 ins_flag   |= MONO_INST_TAILCALL;
7541                                 cfg->flags |= MONO_CFG_HAS_TAIL;
7542                                 /* Can't inline tail calls at this time */
7543                                 inline_costs += 100000;
7544                                 ip += 2;
7545                                 break;
7546                         case CEE_INITOBJ:
7547                                 CHECK_STACK (1);
7548                                 --sp;
7549                                 CHECK_OPSIZE (6);
7550                                 token = read32 (ip + 2);
7551                                 klass = mini_get_class (method, token, generic_context);
7552                                 CHECK_TYPELOAD (klass);
7553                                 if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
7554                                         MonoInst *store, *load;
7555                                         NEW_PCONST (cfg, load, NULL);
7556                                         load->cil_code = ip;
7557                                         load->type = STACK_OBJ;
7558                                         load->klass = klass;
7559                                         MONO_INST_NEW (cfg, store, CEE_STIND_REF);
7560                                         store->cil_code = ip;
7561                                         handle_loaded_temps (cfg, bblock, stack_start, sp);
7562                                         MONO_ADD_INS (bblock, store);
7563                                         store->inst_i0 = sp [0];
7564                                         store->inst_i1 = load;
7565                                 } else {
7566                                         handle_initobj (cfg, bblock, *sp, NULL, klass, stack_start, sp);
7567                                 }
7568                                 ip += 6;
7569                                 inline_costs += 1;
7570                                 break;
7571                         case CEE_CONSTRAINED_:
7572                                 /* FIXME: implement */
7573                                 CHECK_OPSIZE (6);
7574                                 token = read32 (ip + 2);
7575                                 constrained_call = mono_class_get_full (image, token, generic_context);
7576                                 CHECK_TYPELOAD (constrained_call);
7577                                 ip += 6;
7578                                 break;
7579                         case CEE_CPBLK:
7580                         case CEE_INITBLK: {
7581                                 MonoInst *iargs [3];
7582                                 CHECK_STACK (3);
7583                                 sp -= 3;
7584                                 if ((cfg->opt & MONO_OPT_INTRINS) && (ip [1] == CEE_CPBLK) && (sp [2]->opcode == OP_ICONST) && ((n = sp [2]->inst_c0) <= sizeof (gpointer) * 5)) {
7585                                         MonoInst *copy;
7586                                         MONO_INST_NEW (cfg, copy, OP_MEMCPY);
7587                                         copy->inst_left = sp [0];
7588                                         copy->inst_right = sp [1];
7589                                         copy->cil_code = ip;
7590                                         copy->backend.size = n;
7591                                         MONO_ADD_INS (bblock, copy);
7592                                         ip += 2;
7593                                         break;
7594                                 }
7595                                 iargs [0] = sp [0];
7596                                 iargs [1] = sp [1];
7597                                 iargs [2] = sp [2];
7598                                 handle_loaded_temps (cfg, bblock, stack_start, sp);
7599                                 if (ip [1] == CEE_CPBLK) {
7600                                         MonoMethod *memcpy_method = get_memcpy_method ();
7601                                         mono_emit_method_call_spilled (cfg, bblock, memcpy_method, memcpy_method->signature, iargs, ip, NULL);
7602                                 } else {
7603                                         MonoMethod *memset_method = get_memset_method ();
7604                                         mono_emit_method_call_spilled (cfg, bblock, memset_method, memset_method->signature, iargs, ip, NULL);
7605                                 }
7606                                 ip += 2;
7607                                 inline_costs += 1;
7608                                 break;
7609                         }
7610                         case CEE_NO_:
7611                                 CHECK_OPSIZE (3);
7612                                 if (ip [2] & 0x1)
7613                                         ins_flag |= MONO_INST_NOTYPECHECK;
7614                                 if (ip [2] & 0x2)
7615                                         ins_flag |= MONO_INST_NORANGECHECK;
7616                                 /* we ignore the no-nullcheck for now since we
7617                                  * really do it explicitly only when doing callvirt->call
7618                                  */
7619                                 ip += 3;
7620                                 break;
7621                         case CEE_RETHROW: {
7622                                 MonoInst *load;
7623                                 int handler_offset = -1;
7624
7625                                 for (i = 0; i < header->num_clauses; ++i) {
7626                                         MonoExceptionClause *clause = &header->clauses [i];
7627                                         if (MONO_OFFSET_IN_HANDLER (clause, ip - header->code) && !(clause->flags & MONO_EXCEPTION_CLAUSE_FINALLY))
7628                                                 handler_offset = clause->handler_offset;
7629                                 }
7630
7631                                 bblock->flags |= BB_EXCEPTION_UNSAFE;
7632
7633                                 g_assert (handler_offset != -1);
7634
7635                                 NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, handler_offset)->inst_c0);
7636                                 load->cil_code = ip;
7637                                 MONO_INST_NEW (cfg, ins, OP_RETHROW);
7638                                 ins->inst_left = load;
7639                                 ins->cil_code = ip;
7640                                 MONO_ADD_INS (bblock, ins);
7641                                 sp = stack_start;
7642                                 link_bblock (cfg, bblock, end_bblock);
7643                                 start_new_bblock = 1;
7644                                 ip += 2;
7645                                 break;
7646                         }
7647                         case CEE_SIZEOF:
7648                                 CHECK_STACK_OVF (1);
7649                                 CHECK_OPSIZE (6);
7650                                 token = read32 (ip + 2);
7651                                 /* FIXXME: handle generics. */
7652                                 if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC) {
7653                                         MonoType *type = mono_type_create_from_typespec (image, token);
7654                                         token = mono_type_size (type, &ialign);
7655                                 } else {
7656                                         MonoClass *klass = mono_class_get_full (image, token, generic_context);
7657                                         CHECK_TYPELOAD (klass);
7658                                         mono_class_init (klass);
7659                                         token = mono_class_value_size (klass, &align);
7660                                 }
7661                                 NEW_ICONST (cfg, ins, token);
7662                                 ins->cil_code = ip;
7663                                 *sp++= ins;
7664                                 ip += 6;
7665                                 break;
7666                         case CEE_REFANYTYPE:
7667                                 CHECK_STACK (1);
7668                                 MONO_INST_NEW (cfg, ins, OP_REFANYTYPE);
7669                                 --sp;
7670                                 ins->type = STACK_MP;
7671                                 ins->inst_left = *sp;
7672                                 ins->type = STACK_VTYPE;
7673                                 ins->klass = mono_defaults.typehandle_class;
7674                                 ins->cil_code = ip;
7675                                 ip += 2;
7676                                 *sp++ = ins;
7677                                 break;
7678                         case CEE_READONLY_:
7679                                 ip += 2;
7680                                 break;
7681                         default:
7682                                 g_error ("opcode 0xfe 0x%02x not handled", ip [1]);
7683                         }
7684                         break;
7685                 }
7686                 default:
7687                         g_error ("opcode 0x%02x not handled", *ip);
7688                 }
7689         }
7690         if (start_new_bblock != 1)
7691                 UNVERIFIED;
7692
7693         bblock->cil_length = ip - bblock->cil_code;
7694         bblock->next_bb = end_bblock;
7695
7696         if (cfg->method == method && cfg->domainvar) {
7697                 MonoInst *store;
7698                 MonoInst *get_domain;
7699                 
7700                 if (! (get_domain = mono_arch_get_domain_intrinsic (cfg))) {
7701                         MonoCallInst *call;
7702                         
7703                         MONO_INST_NEW_CALL (cfg, call, CEE_CALL);
7704                         call->signature = helper_sig_domain_get;
7705                         call->inst.type = STACK_PTR;
7706                         call->fptr = mono_domain_get;
7707                         get_domain = (MonoInst*)call;
7708                 }
7709                 
7710                 NEW_TEMPSTORE (cfg, store, cfg->domainvar->inst_c0, get_domain);
7711                 MONO_ADD_INS (init_localsbb, store);
7712         }
7713
7714         if (cfg->method == method && cfg->got_var)
7715                 mono_emit_load_got_addr (cfg);
7716
7717         if (header->init_locals) {
7718                 MonoInst *store;
7719                 for (i = 0; i < header->num_locals; ++i) {
7720                         MonoType *ptype = header->locals [i];
7721                         int t = ptype->type;
7722                         if (t == MONO_TYPE_VALUETYPE && ptype->data.klass->enumtype)
7723                                 t = ptype->data.klass->enum_basetype->type;
7724                         if (ptype->byref) {
7725                                 NEW_PCONST (cfg, ins, NULL);
7726                                 NEW_LOCSTORE (cfg, store, i, ins);
7727                                 MONO_ADD_INS (init_localsbb, store);
7728                         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
7729                                 NEW_ICONST (cfg, ins, 0);
7730                                 NEW_LOCSTORE (cfg, store, i, ins);
7731                                 MONO_ADD_INS (init_localsbb, store);
7732                         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
7733                                 MONO_INST_NEW (cfg, ins, OP_I8CONST);
7734                                 ins->type = STACK_I8;
7735                                 ins->inst_l = 0;
7736                                 NEW_LOCSTORE (cfg, store, i, ins);
7737                                 MONO_ADD_INS (init_localsbb, store);
7738                         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
7739 #ifdef MONO_ARCH_SOFT_FLOAT
7740                                 /* FIXME: handle init of R4 */
7741 #else
7742                                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
7743                                 ins->type = STACK_R8;
7744                                 ins->inst_p0 = (void*)&r8_0;
7745                                 NEW_LOCSTORE (cfg, store, i, ins);
7746                                 MONO_ADD_INS (init_localsbb, store);
7747 #endif
7748                         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
7749                                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (ptype))) {
7750                                 NEW_LOCLOADA (cfg, ins, i);
7751                                 handle_initobj (cfg, init_localsbb, ins, NULL, mono_class_from_mono_type (ptype), NULL, NULL);
7752                         } else {
7753                                 NEW_PCONST (cfg, ins, NULL);
7754                                 NEW_LOCSTORE (cfg, store, i, ins);
7755                                 MONO_ADD_INS (init_localsbb, store);
7756                         }
7757                 }
7758         }
7759
7760         /* resolve backward branches in the middle of an existing basic block */
7761         for (tmp = bb_recheck; tmp; tmp = tmp->next) {
7762                 bblock = tmp->data;
7763                 /*g_print ("need recheck in %s at IL_%04x\n", method->name, bblock->cil_code - header->code);*/
7764                 tblock = find_previous (cfg->cil_offset_to_bb, header->code_size, start_bblock, bblock->cil_code);
7765                 if (tblock != start_bblock) {
7766                         int l;
7767                         split_bblock (cfg, tblock, bblock);
7768                         l = bblock->cil_code - header->code;
7769                         bblock->cil_length = tblock->cil_length - l;
7770                         tblock->cil_length = l;
7771                 } else {
7772                         g_print ("recheck failed.\n");
7773                 }
7774         }
7775
7776         if (cfg->method == method) {
7777                 MonoBasicBlock *bb;
7778                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
7779                         bb->region = mono_find_block_region (cfg, bb->real_offset);
7780                         if (cfg->spvars)
7781                                 mono_create_spvar_for_region (cfg, bb->region);
7782                         if (cfg->verbose_level > 2)
7783                                 g_print ("REGION BB%d IL_%04x ID_%08X\n", bb->block_num, bb->real_offset, bb->region);
7784                 }
7785         }
7786
7787         g_slist_free (class_inits);
7788         dont_inline = g_list_remove (dont_inline, method);
7789
7790         if (inline_costs < 0) {
7791                 char *mname;
7792
7793                 /* Method is too large */
7794                 mname = mono_method_full_name (method, TRUE);
7795                 cfg->exception_type = MONO_EXCEPTION_INVALID_PROGRAM;
7796                 cfg->exception_message = g_strdup_printf ("Method %s is too complex.", mname);
7797                 g_free (mname);
7798                 return -1;
7799         }
7800
7801         return inline_costs;
7802
7803  exception_exit:
7804         g_assert (cfg->exception_type != MONO_EXCEPTION_NONE);
7805         g_slist_free (class_inits);
7806         dont_inline = g_list_remove (dont_inline, method);
7807         return -1;
7808
7809  inline_failure:
7810         g_slist_free (class_inits);
7811         dont_inline = g_list_remove (dont_inline, method);
7812         return -1;
7813
7814  load_error:
7815         g_slist_free (class_inits);
7816         dont_inline = g_list_remove (dont_inline, method);
7817         cfg->exception_type = MONO_EXCEPTION_TYPE_LOAD;
7818         return -1;
7819
7820  unverified:
7821         g_slist_free (class_inits);
7822         dont_inline = g_list_remove (dont_inline, method);
7823         cfg->exception_type = MONO_EXCEPTION_INVALID_PROGRAM;
7824         cfg->exception_message = g_strdup_printf ("Invalid IL code in %s: %s\n",
7825                  mono_method_full_name (method, TRUE), mono_disasm_code_one (NULL, method, ip, NULL));
7826         return -1;
7827 }
7828
7829 void
7830 mono_print_tree (MonoInst *tree) {
7831         int arity;
7832
7833         if (!tree)
7834                 return;
7835
7836         arity = mono_burg_arity [tree->opcode];
7837
7838         printf (" %s%s", arity?"(":"",  mono_inst_name (tree->opcode));
7839
7840         switch (tree->opcode) {
7841         case OP_ICONST:
7842                 printf ("[%d]", (int)tree->inst_c0);
7843                 break;
7844         case OP_I8CONST:
7845                 printf ("[%lld]", (long long)tree->inst_l);
7846                 break;
7847         case OP_R8CONST:
7848                 printf ("[%f]", *(double*)tree->inst_p0);
7849                 break;
7850         case OP_R4CONST:
7851                 printf ("[%f]", *(float*)tree->inst_p0);
7852                 break;
7853         case OP_ARG:
7854         case OP_LOCAL:
7855                 printf ("[%d]", (int)tree->inst_c0);
7856                 break;
7857         case OP_REGOFFSET:
7858                 if (tree->inst_offset < 0)
7859                         printf ("[-0x%x(%s)]", (int)(-tree->inst_offset), mono_arch_regname (tree->inst_basereg));
7860                 else
7861                         printf ("[0x%x(%s)]", (int)(tree->inst_offset), mono_arch_regname (tree->inst_basereg));
7862                 break;
7863         case OP_REGVAR:
7864                 printf ("[%s]", mono_arch_regname (tree->dreg));
7865                 break;
7866         case CEE_NEWARR:
7867                 printf ("[%s]",  tree->inst_newa_class->name);
7868                 mono_print_tree (tree->inst_newa_len);
7869                 break;
7870         case CEE_CALL:
7871         case CEE_CALLVIRT:
7872         case OP_FCALL:
7873         case OP_FCALLVIRT:
7874         case OP_LCALL:
7875         case OP_LCALLVIRT:
7876         case OP_VCALL:
7877         case OP_VCALLVIRT:
7878         case OP_VOIDCALL:
7879         case OP_VOIDCALLVIRT: {
7880                 MonoCallInst *call = (MonoCallInst*)tree;
7881                 if (call->method)
7882                         printf ("[%s]", call->method->name);
7883                 else if (call->fptr) {
7884                         MonoJitICallInfo *info = mono_find_jit_icall_by_addr (call->fptr);
7885                         if (info)
7886                                 printf ("[%s]", info->name);
7887                 }
7888                 break;
7889         }
7890         case OP_PHI: {
7891                 int i;
7892                 printf ("[%d (", (int)tree->inst_c0);
7893                 for (i = 0; i < tree->inst_phi_args [0]; i++) {
7894                         if (i)
7895                                 printf (", ");
7896                         printf ("%d", tree->inst_phi_args [i + 1]);
7897                 }
7898                 printf (")]");
7899                 break;
7900         }
7901         case OP_RENAME:
7902         case OP_RETARG:
7903         case OP_NOP:
7904         case OP_JMP:
7905         case OP_BREAK:
7906                 break;
7907         case OP_LOAD_MEMBASE:
7908         case OP_LOADI4_MEMBASE:
7909         case OP_LOADU4_MEMBASE:
7910         case OP_LOADU1_MEMBASE:
7911         case OP_LOADI1_MEMBASE:
7912         case OP_LOADU2_MEMBASE:
7913         case OP_LOADI2_MEMBASE:
7914                 printf ("[%s] <- [%s + 0x%x]", mono_arch_regname (tree->dreg), mono_arch_regname (tree->inst_basereg), (int)tree->inst_offset);
7915                 break;
7916         case OP_BR:
7917         case OP_CALL_HANDLER:
7918                 printf ("[B%d]", tree->inst_target_bb->block_num);
7919                 break;
7920         case CEE_SWITCH:
7921         case CEE_ISINST:
7922         case CEE_CASTCLASS:
7923         case OP_OUTARG:
7924         case OP_CALL_REG:
7925         case OP_FCALL_REG:
7926         case OP_LCALL_REG:
7927         case OP_VCALL_REG:
7928         case OP_VOIDCALL_REG:
7929                 mono_print_tree (tree->inst_left);
7930                 break;
7931         case CEE_BNE_UN:
7932         case CEE_BEQ:
7933         case CEE_BLT:
7934         case CEE_BLT_UN:
7935         case CEE_BGT:
7936         case CEE_BGT_UN:
7937         case CEE_BGE:
7938         case CEE_BGE_UN:
7939         case CEE_BLE:
7940         case CEE_BLE_UN:
7941                 printf ("[B%dB%d]", tree->inst_true_bb->block_num, tree->inst_false_bb->block_num);
7942                 mono_print_tree (tree->inst_left);
7943                 break;
7944         default:
7945                 if (!mono_arch_print_tree(tree, arity)) {
7946                         if (arity) {
7947                                 mono_print_tree (tree->inst_left);
7948                                 if (arity > 1)
7949                                         mono_print_tree (tree->inst_right);
7950                         }
7951                 }
7952                 break;
7953         }
7954
7955         if (arity)
7956                 printf (")");
7957 }
7958
7959 void
7960 mono_print_tree_nl (MonoInst *tree)
7961 {
7962         mono_print_tree (tree);
7963         printf ("\n");
7964 }
7965
7966 static void
7967 create_helper_signature (void)
7968 {
7969         helper_sig_domain_get = mono_create_icall_signature ("ptr");
7970         helper_sig_class_init_trampoline = mono_create_icall_signature ("void");
7971 }
7972
7973 gconstpointer
7974 mono_icall_get_wrapper (MonoJitICallInfo* callinfo)
7975 {
7976         char *name;
7977         MonoMethod *wrapper;
7978         gconstpointer trampoline;
7979         MonoDomain *domain = mono_get_root_domain ();
7980         
7981         if (callinfo->wrapper) {
7982                 return callinfo->wrapper;
7983         }
7984
7985         if (callinfo->trampoline)
7986                 return callinfo->trampoline;
7987
7988         /* 
7989          * We use the lock on the root domain instead of the JIT lock to protect 
7990          * callinfo->trampoline, since we do a lot of stuff inside the critical section.
7991          */
7992         mono_domain_lock (domain);
7993
7994         if (callinfo->trampoline) {
7995                 mono_domain_unlock (domain);
7996                 return callinfo->trampoline;
7997         }
7998
7999         name = g_strdup_printf ("__icall_wrapper_%s", callinfo->name);
8000         wrapper = mono_marshal_get_icall_wrapper (callinfo->sig, name, callinfo->func);
8001         g_free (name);
8002
8003         trampoline = mono_create_ftnptr (domain, mono_create_jit_trampoline_in_domain (domain, wrapper));
8004         mono_register_jit_icall_wrapper (callinfo, trampoline);
8005
8006         callinfo->trampoline = trampoline;
8007
8008         mono_domain_unlock (domain);
8009         
8010         return callinfo->trampoline;
8011 }
8012
8013 static void
8014 mono_init_trampolines (void)
8015 {
8016         mono_trampoline_code [MONO_TRAMPOLINE_GENERIC] = mono_arch_create_trampoline_code (MONO_TRAMPOLINE_GENERIC);
8017         mono_trampoline_code [MONO_TRAMPOLINE_JUMP] = mono_arch_create_trampoline_code (MONO_TRAMPOLINE_JUMP);
8018         mono_trampoline_code [MONO_TRAMPOLINE_CLASS_INIT] = mono_arch_create_trampoline_code (MONO_TRAMPOLINE_CLASS_INIT);
8019 #ifdef MONO_ARCH_HAVE_PIC_AOT
8020         mono_trampoline_code [MONO_TRAMPOLINE_AOT] = mono_arch_create_trampoline_code (MONO_TRAMPOLINE_AOT);
8021         mono_trampoline_code [MONO_TRAMPOLINE_AOT_PLT] = mono_arch_create_trampoline_code (MONO_TRAMPOLINE_AOT_PLT);
8022 #endif
8023 #ifdef MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE
8024         mono_trampoline_code [MONO_TRAMPOLINE_DELEGATE] = mono_arch_create_trampoline_code (MONO_TRAMPOLINE_DELEGATE);
8025 #endif
8026 }
8027
8028 static void
8029 mono_init_exceptions (void)
8030 {
8031 #ifndef CUSTOM_EXCEPTION_HANDLING
8032         mono_arch_get_restore_context ();
8033         mono_arch_get_call_filter ();
8034         mono_arch_get_throw_exception ();
8035         mono_arch_get_rethrow_exception ();
8036 #endif
8037 }
8038
8039 guint8 *
8040 mono_get_trampoline_code (MonoTrampolineType tramp_type)
8041 {
8042         return mono_trampoline_code [tramp_type];
8043 }
8044
8045 gpointer
8046 mono_create_class_init_trampoline (MonoVTable *vtable)
8047 {
8048         gpointer code, ptr;
8049
8050         /* previously created trampoline code */
8051         mono_domain_lock (vtable->domain);
8052         ptr = 
8053                 g_hash_table_lookup (vtable->domain->class_init_trampoline_hash,
8054                                                                   vtable);
8055         mono_domain_unlock (vtable->domain);
8056         if (ptr)
8057                 return ptr;
8058
8059 #ifdef MONO_ARCH_HAVE_CREATE_SPECIFIC_TRAMPOLINE
8060         code = mono_arch_create_specific_trampoline (vtable, MONO_TRAMPOLINE_CLASS_INIT, vtable->domain, NULL);
8061 #else
8062         code = mono_arch_create_class_init_trampoline (vtable);
8063 #endif
8064
8065         ptr = mono_create_ftnptr (vtable->domain, code);
8066
8067         /* store trampoline address */
8068         mono_domain_lock (vtable->domain);
8069         g_hash_table_insert (vtable->domain->class_init_trampoline_hash,
8070                                                           vtable, ptr);
8071         mono_domain_unlock (vtable->domain);
8072
8073         mono_jit_lock ();
8074         if (!class_init_hash_addr)
8075                 class_init_hash_addr = g_hash_table_new (NULL, NULL);
8076         g_hash_table_insert (class_init_hash_addr, ptr, vtable);
8077         mono_jit_unlock ();
8078
8079         return ptr;
8080 }
8081
8082 gpointer
8083 mono_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, 
8084                                                          gboolean add_sync_wrapper)
8085 {
8086         MonoJitInfo *ji;
8087         gpointer code;
8088 #ifdef MONO_ARCH_HAVE_CREATE_SPECIFIC_TRAMPOLINE
8089         guint32 code_size;
8090 #endif
8091
8092         if (add_sync_wrapper && method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
8093                 return mono_create_jump_trampoline (domain, mono_marshal_get_synchronized_wrapper (method), FALSE);
8094
8095         code = mono_jit_find_compiled_method (domain, method);
8096         if (code)
8097                 return code;
8098
8099         mono_domain_lock (domain);
8100         code = g_hash_table_lookup (domain->jump_trampoline_hash, method);
8101         mono_domain_unlock (domain);
8102         if (code)
8103                 return code;
8104
8105 #ifdef MONO_ARCH_HAVE_CREATE_SPECIFIC_TRAMPOLINE
8106         code = mono_arch_create_specific_trampoline (method, MONO_TRAMPOLINE_JUMP, mono_domain_get (), &code_size);
8107
8108         mono_domain_lock (domain);
8109         ji = mono_mempool_alloc0 (domain->mp, sizeof (MonoJitInfo));
8110         mono_domain_unlock (domain);
8111         ji->code_start = code;
8112         ji->code_size = code_size;
8113         ji->method = method;
8114 #else
8115         ji = mono_arch_create_jump_trampoline (method);
8116 #endif
8117
8118         /*
8119          * mono_delegate_ctor needs to find the method metadata from the 
8120          * trampoline address, so we save it here.
8121          */
8122
8123         mono_jit_info_table_add (domain, ji);
8124
8125         mono_domain_lock (domain);
8126         g_hash_table_insert (domain->jump_trampoline_hash, method, ji->code_start);
8127         mono_domain_unlock (domain);
8128
8129         return ji->code_start;
8130 }
8131
8132 static gpointer
8133 mono_create_jit_trampoline_in_domain (MonoDomain *domain, MonoMethod *method)
8134 {
8135         gpointer tramp;
8136
8137         mono_domain_lock (domain);
8138         tramp = g_hash_table_lookup (domain->jit_trampoline_hash, method);
8139         mono_domain_unlock (domain);
8140         if (tramp)
8141                 return tramp;
8142
8143         if (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
8144                 return mono_create_jit_trampoline (mono_marshal_get_synchronized_wrapper (method));
8145
8146 #ifdef MONO_ARCH_HAVE_CREATE_SPECIFIC_TRAMPOLINE
8147         tramp =  mono_arch_create_specific_trampoline (method, MONO_TRAMPOLINE_GENERIC, domain, NULL);
8148 #else
8149         tramp = mono_arch_create_jit_trampoline (method);
8150 #endif
8151         
8152         mono_domain_lock (domain);
8153         g_hash_table_insert (domain->jit_trampoline_hash, method, tramp);
8154         mono_domain_unlock (domain);
8155
8156         mono_jit_stats.method_trampolines++;
8157
8158         return tramp;
8159 }       
8160
8161 gpointer
8162 mono_create_jit_trampoline (MonoMethod *method)
8163 {
8164         return mono_create_jit_trampoline_in_domain (mono_domain_get (), method);
8165 }
8166
8167 #ifdef MONO_ARCH_HAVE_CREATE_TRAMPOLINE_FROM_TOKEN
8168 gpointer
8169 mono_create_jit_trampoline_from_token (MonoImage *image, guint32 token)
8170 {
8171         gpointer tramp;
8172
8173         MonoDomain *domain = mono_domain_get ();
8174         guint8 *buf, *start;
8175
8176         mono_domain_lock (domain);
8177         buf = start = mono_code_manager_reserve (domain->code_mp, 2 * sizeof (gpointer));
8178         mono_domain_unlock (domain);
8179
8180         *(gpointer*)(gpointer)buf = image;
8181         buf += sizeof (gpointer);
8182         *(guint32*)(gpointer)buf = token;
8183
8184         tramp = mono_arch_create_specific_trampoline (start, MONO_TRAMPOLINE_AOT, domain, NULL);
8185
8186         mono_jit_stats.method_trampolines++;
8187
8188         return tramp;
8189 }       
8190 #endif
8191
8192 static gpointer
8193 mono_create_delegate_trampoline (MonoClass *klass)
8194 {
8195 #ifdef MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE
8196         MonoDomain *domain = mono_domain_get ();
8197         gpointer code, ptr;
8198         guint32 code_size;
8199
8200         mono_domain_lock (domain);
8201         ptr = g_hash_table_lookup (domain->delegate_trampoline_hash, klass);
8202         mono_domain_unlock (domain);
8203         if (ptr)
8204                 return ptr;
8205
8206     code = mono_arch_create_specific_trampoline (klass, MONO_TRAMPOLINE_DELEGATE, mono_domain_get (), &code_size);
8207
8208         ptr = mono_create_ftnptr (domain, code);
8209
8210         /* store trampoline address */
8211         mono_domain_lock (domain);
8212         g_hash_table_insert (domain->delegate_trampoline_hash,
8213                                                           klass, ptr);
8214         mono_domain_unlock (domain);
8215
8216         return ptr;
8217 #else
8218         return NULL;
8219 #endif
8220 }
8221
8222 MonoVTable*
8223 mono_find_class_init_trampoline_by_addr (gconstpointer addr)
8224 {
8225         MonoVTable *res;
8226
8227         mono_jit_lock ();
8228         if (class_init_hash_addr)
8229                 res = g_hash_table_lookup (class_init_hash_addr, addr);
8230         else
8231                 res = NULL;
8232         mono_jit_unlock ();
8233         return res;
8234 }
8235
8236 static void
8237 mono_dynamic_code_hash_insert (MonoDomain *domain, MonoMethod *method, MonoJitDynamicMethodInfo *ji)
8238 {
8239         if (!domain->dynamic_code_hash)
8240                 domain->dynamic_code_hash = g_hash_table_new (NULL, NULL);
8241         g_hash_table_insert (domain->dynamic_code_hash, method, ji);
8242 }
8243
8244 static MonoJitDynamicMethodInfo*
8245 mono_dynamic_code_hash_lookup (MonoDomain *domain, MonoMethod *method)
8246 {
8247         MonoJitDynamicMethodInfo *res;
8248
8249         if (domain->dynamic_code_hash)
8250                 res = g_hash_table_lookup (domain->dynamic_code_hash, method);
8251         else
8252                 res = NULL;
8253         return res;
8254 }
8255
8256 typedef struct {
8257         MonoClass *vtype;
8258         GList *active;
8259         GSList *slots;
8260 } StackSlotInfo;
8261
8262 static inline GSList*
8263 g_slist_prepend_mempool (MonoMemPool *mp, GSList   *list,
8264                                                  gpointer  data)
8265 {
8266   GSList *new_list;
8267
8268   new_list = mono_mempool_alloc (mp, sizeof (GSList));
8269   new_list->data = data;
8270   new_list->next = list;
8271
8272   return new_list;
8273 }
8274
8275 /*
8276  *  mono_allocate_stack_slots_full:
8277  *
8278  *  Allocate stack slots for all non register allocated variables using a
8279  * linear scan algorithm.
8280  * Returns: an array of stack offsets.
8281  * STACK_SIZE is set to the amount of stack space needed.
8282  * STACK_ALIGN is set to the alignment needed by the locals area.
8283  */
8284 gint32*
8285 mono_allocate_stack_slots_full (MonoCompile *m, gboolean backward, guint32 *stack_size, guint32 *stack_align)
8286 {
8287         int i, slot, offset, size;
8288         guint32 align;
8289         MonoMethodVar *vmv;
8290         MonoInst *inst;
8291         gint32 *offsets;
8292         GList *vars = NULL, *l;
8293         StackSlotInfo *scalar_stack_slots, *vtype_stack_slots, *slot_info;
8294         MonoType *t;
8295         int nvtypes;
8296
8297         scalar_stack_slots = mono_mempool_alloc0 (m->mempool, sizeof (StackSlotInfo) * MONO_TYPE_PINNED);
8298         vtype_stack_slots = NULL;
8299         nvtypes = 0;
8300
8301         offsets = mono_mempool_alloc (m->mempool, sizeof (gint32) * m->num_varinfo);
8302         for (i = 0; i < m->num_varinfo; ++i)
8303                 offsets [i] = -1;
8304
8305         for (i = m->locals_start; i < m->num_varinfo; i++) {
8306                 inst = m->varinfo [i];
8307                 vmv = MONO_VARINFO (m, i);
8308
8309                 if ((inst->flags & MONO_INST_IS_DEAD) || inst->opcode == OP_REGVAR || inst->opcode == OP_REGOFFSET)
8310                         continue;
8311
8312                 vars = g_list_prepend (vars, vmv);
8313         }
8314
8315         vars = mono_varlist_sort (m, vars, 0);
8316         offset = 0;
8317         *stack_align = 0;
8318         for (l = vars; l; l = l->next) {
8319                 vmv = l->data;
8320                 inst = m->varinfo [vmv->idx];
8321
8322                 /* inst->backend.is_pinvoke indicates native sized value types, this is used by the
8323                 * pinvoke wrappers when they call functions returning structures */
8324                 if (inst->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (inst->inst_vtype) && inst->inst_vtype->type != MONO_TYPE_TYPEDBYREF)
8325                         size = mono_class_native_size (inst->inst_vtype->data.klass, &align);
8326                 else {
8327                         int ialign;
8328
8329                         size = mono_type_size (inst->inst_vtype, &ialign);
8330                         align = ialign;
8331                 }
8332
8333                 t = mono_type_get_underlying_type (inst->inst_vtype);
8334                 if (t->byref) {
8335                         slot_info = &scalar_stack_slots [MONO_TYPE_I];
8336                 } else {
8337                         switch (t->type) {
8338                         case MONO_TYPE_GENERICINST:
8339                                 if (!mono_type_generic_inst_is_valuetype (t)) {
8340                                         slot_info = &scalar_stack_slots [t->type];
8341                                         break;
8342                                 }
8343                                 /* Fall through */
8344                         case MONO_TYPE_VALUETYPE:
8345                                 if (!vtype_stack_slots)
8346                                         vtype_stack_slots = mono_mempool_alloc0 (m->mempool, sizeof (StackSlotInfo) * 256);
8347                                 for (i = 0; i < nvtypes; ++i)
8348                                         if (t->data.klass == vtype_stack_slots [i].vtype)
8349                                                 break;
8350                                 if (i < nvtypes)
8351                                         slot_info = &vtype_stack_slots [i];
8352                                 else {
8353                                         g_assert (nvtypes < 256);
8354                                         vtype_stack_slots [nvtypes].vtype = t->data.klass;
8355                                         slot_info = &vtype_stack_slots [nvtypes];
8356                                         nvtypes ++;
8357                                 }
8358                                 break;
8359                         case MONO_TYPE_CLASS:
8360                         case MONO_TYPE_OBJECT:
8361                         case MONO_TYPE_ARRAY:
8362                         case MONO_TYPE_SZARRAY:
8363                         case MONO_TYPE_STRING:
8364                         case MONO_TYPE_PTR:
8365                         case MONO_TYPE_I:
8366                         case MONO_TYPE_U:
8367 #if SIZEOF_VOID_P == 4
8368                         case MONO_TYPE_I4:
8369 #else
8370                         case MONO_TYPE_I8:
8371 #endif
8372                                 /* Share non-float stack slots of the same size */
8373                                 slot_info = &scalar_stack_slots [MONO_TYPE_CLASS];
8374                                 break;
8375                         default:
8376                                 slot_info = &scalar_stack_slots [t->type];
8377                         }
8378                 }
8379
8380                 slot = 0xffffff;
8381                 if (m->comp_done & MONO_COMP_LIVENESS) {
8382                         //printf ("START  %2d %08x %08x\n",  vmv->idx, vmv->range.first_use.abs_pos, vmv->range.last_use.abs_pos);
8383                         
8384                         /* expire old intervals in active */
8385                         while (slot_info->active) {
8386                                 MonoMethodVar *amv = (MonoMethodVar *)slot_info->active->data;
8387
8388                                 if (amv->range.last_use.abs_pos > vmv->range.first_use.abs_pos)
8389                                         break;
8390
8391                                 //printf ("EXPIR  %2d %08x %08x C%d R%d\n", amv->idx, amv->range.first_use.abs_pos, amv->range.last_use.abs_pos, amv->spill_costs, amv->reg);
8392
8393                                 slot_info->active = g_list_delete_link (slot_info->active, slot_info->active);
8394                                 slot_info->slots = g_slist_prepend_mempool (m->mempool, slot_info->slots, GINT_TO_POINTER (offsets [amv->idx]));
8395                         }
8396
8397                         /* 
8398                          * This also handles the case when the variable is used in an
8399                          * exception region, as liveness info is not computed there.
8400                          */
8401                         /* 
8402                          * FIXME: All valuetypes are marked as INDIRECT because of LDADDR
8403                          * opcodes.
8404                          */
8405                         if (! (inst->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT))) {
8406                                 if (slot_info->slots) {
8407                                         slot = GPOINTER_TO_INT (slot_info->slots->data);
8408
8409                                         slot_info->slots = slot_info->slots->next;
8410                                 }
8411
8412                                 slot_info->active = mono_varlist_insert_sorted (m, slot_info->active, vmv, TRUE);
8413                         }
8414                 }
8415
8416                 {
8417                         static int count = 0;
8418                         count ++;
8419
8420                         /*
8421                         if (count == atoi (getenv ("COUNT")))
8422                                 printf ("LAST: %s\n", mono_method_full_name (m->method, TRUE));
8423                         if (count > atoi (getenv ("COUNT")))
8424                                 slot = 0xffffff;
8425                         else {
8426                                 mono_print_tree_nl (inst);
8427                                 }
8428                         */
8429                 }
8430                 if (slot == 0xffffff) {
8431                         /*
8432                          * Allways allocate valuetypes to sizeof (gpointer) to allow more
8433                          * efficient copying (and to work around the fact that OP_MEMCPY
8434                          * and OP_MEMSET ignores alignment).
8435                          */
8436                         if (MONO_TYPE_ISSTRUCT (t))
8437                                 align = sizeof (gpointer);
8438
8439                         if (backward) {
8440                                 offset += size;
8441                                 offset += align - 1;
8442                                 offset &= ~(align - 1);
8443                                 slot = offset;
8444                         }
8445                         else {
8446                                 offset += align - 1;
8447                                 offset &= ~(align - 1);
8448                                 slot = offset;
8449                                 offset += size;
8450                         }
8451
8452                         if (*stack_align == 0)
8453                                 *stack_align = align;
8454                 }
8455
8456                 offsets [vmv->idx] = slot;
8457         }
8458         g_list_free (vars);
8459         for (i = 0; i < MONO_TYPE_PINNED; ++i) {
8460                 if (scalar_stack_slots [i].active)
8461                         g_list_free (scalar_stack_slots [i].active);
8462         }
8463         for (i = 0; i < nvtypes; ++i) {
8464                 if (vtype_stack_slots [i].active)
8465                         g_list_free (vtype_stack_slots [i].active);
8466         }
8467
8468         mono_jit_stats.locals_stack_size += offset;
8469
8470         *stack_size = offset;
8471         return offsets;
8472 }
8473
8474 gint32*
8475 mono_allocate_stack_slots (MonoCompile *m, guint32 *stack_size, guint32 *stack_align)
8476 {
8477         return mono_allocate_stack_slots_full (m, TRUE, stack_size, stack_align);
8478 }
8479
8480 void
8481 mono_register_opcode_emulation (int opcode, const char *name, const char *sigstr, gpointer func, gboolean no_throw)
8482 {
8483         MonoJitICallInfo *info;
8484         MonoMethodSignature *sig = mono_create_icall_signature (sigstr);
8485
8486         if (!emul_opcode_map)
8487                 emul_opcode_map = g_new0 (MonoJitICallInfo*, OP_LAST + 1);
8488
8489         g_assert (!sig->hasthis);
8490         g_assert (sig->param_count < 3);
8491
8492         info = mono_register_jit_icall (func, name, sig, no_throw);
8493
8494         emul_opcode_map [opcode] = info;
8495 }
8496
8497 static void
8498 register_icall (gpointer func, const char *name, const char *sigstr, gboolean save)
8499 {
8500         MonoMethodSignature *sig;
8501
8502         if (sigstr)
8503                 sig = mono_create_icall_signature (sigstr);
8504         else
8505                 sig = NULL;
8506
8507         mono_register_jit_icall (func, name, sig, save);
8508 }
8509
8510 static void
8511 decompose_foreach (MonoInst *tree, gpointer data) 
8512 {
8513         static MonoJitICallInfo *newarr_info = NULL;
8514         static MonoJitICallInfo *newarr_specific_info = NULL;
8515         MonoJitICallInfo *info;
8516         int i;
8517
8518         switch (tree->opcode) {
8519         case CEE_NEWARR: {
8520                 MonoCompile *cfg = data;
8521                 MonoInst *iargs [3];
8522
8523                 if (!newarr_info) {
8524                         newarr_info = mono_find_jit_icall_by_addr (mono_array_new);
8525                         g_assert (newarr_info);
8526                         newarr_specific_info = mono_find_jit_icall_by_addr (mono_array_new_specific);
8527                         g_assert (newarr_specific_info);
8528                 }
8529
8530                 if (cfg->opt & MONO_OPT_SHARED) {
8531                         NEW_DOMAINCONST (cfg, iargs [0]);
8532                         NEW_CLASSCONST (cfg, iargs [1], tree->inst_newa_class);
8533                         iargs [2] = tree->inst_newa_len;
8534
8535                         info = newarr_info;
8536                 }
8537                 else {
8538                         MonoVTable *vtable = mono_class_vtable (cfg->domain, mono_array_class_get (tree->inst_newa_class, 1));
8539
8540                         NEW_VTABLECONST (cfg, iargs [0], vtable);
8541                         iargs [1] = tree->inst_newa_len;
8542
8543                         info = newarr_specific_info;
8544                 }
8545
8546                 mono_emulate_opcode (cfg, tree, iargs, info);
8547
8548                 /* Need to decompose arguments after the the opcode is decomposed */
8549                 for (i = 0; i < info->sig->param_count; ++i)
8550                         dec_foreach (iargs [i], cfg);
8551                 break;
8552         }
8553 #ifdef MONO_ARCH_SOFT_FLOAT
8554         case OP_FBEQ:
8555         case OP_FBGE:
8556         case OP_FBGT:
8557         case OP_FBLE:
8558         case OP_FBLT:
8559         case OP_FBNE_UN:
8560         case OP_FBGE_UN:
8561         case OP_FBGT_UN:
8562         case OP_FBLE_UN:
8563         case OP_FBLT_UN: {
8564                 if ((info = mono_find_jit_opcode_emulation (tree->opcode))) {
8565                         MonoCompile *cfg = data;
8566                         MonoInst *iargs [2];
8567                 
8568                         iargs [0] = tree->inst_i0;
8569                         iargs [1] = tree->inst_i1;
8570                 
8571                         mono_emulate_opcode (cfg, tree, iargs, info);
8572
8573                         dec_foreach (iargs [0], cfg);
8574                         dec_foreach (iargs [1], cfg);
8575                         break;
8576                 } else {
8577                         g_assert_not_reached ();
8578                 }
8579                 break;
8580         }
8581         case OP_FCEQ:
8582         case OP_FCGT:
8583         case OP_FCGT_UN:
8584         case OP_FCLT:
8585         case OP_FCLT_UN: {
8586                 if ((info = mono_find_jit_opcode_emulation (tree->opcode))) {
8587                         MonoCompile *cfg = data;
8588                         MonoInst *iargs [2];
8589
8590                         /* the args are in the compare opcode ... */
8591                         iargs [0] = tree->inst_i0;
8592                         iargs [1] = tree->inst_i1;
8593                 
8594                         mono_emulate_opcode (cfg, tree, iargs, info);
8595
8596                         dec_foreach (iargs [0], cfg);
8597                         dec_foreach (iargs [1], cfg);
8598                         break;
8599                 } else {
8600                         g_assert_not_reached ();
8601                 }
8602                 break;
8603         }
8604 #endif
8605
8606         default:
8607                 break;
8608         }
8609 }
8610
8611 void
8612 mono_inst_foreach (MonoInst *tree, MonoInstFunc func, gpointer data) {
8613
8614         switch (mono_burg_arity [tree->opcode]) {
8615         case 0: break;
8616         case 1: 
8617                 mono_inst_foreach (tree->inst_left, func, data);
8618                 break;
8619         case 2: 
8620                 mono_inst_foreach (tree->inst_left, func, data);
8621                 mono_inst_foreach (tree->inst_right, func, data);
8622                 break;
8623         default:
8624                 g_assert_not_reached ();
8625         }
8626         func (tree, data);
8627 }
8628
8629 G_GNUC_UNUSED
8630 static void
8631 mono_print_bb_code (MonoBasicBlock *bb) {
8632         if (bb->code) {
8633                 MonoInst *c = bb->code;
8634                 while (c) {
8635                         mono_print_tree (c);
8636                         g_print ("\n");
8637                         c = c->next;
8638                 }
8639         }
8640 }
8641
8642 static void
8643 print_dfn (MonoCompile *cfg) {
8644         int i, j;
8645         char *code;
8646         MonoBasicBlock *bb;
8647
8648         g_print ("IR code for method %s\n", mono_method_full_name (cfg->method, TRUE));
8649
8650         for (i = 0; i < cfg->num_bblocks; ++i) {
8651                 bb = cfg->bblocks [i];
8652                 /*if (bb->cil_code) {
8653                         char* code1, *code2;
8654                         code1 = mono_disasm_code_one (NULL, cfg->method, bb->cil_code, NULL);
8655                         if (bb->last_ins->cil_code)
8656                                 code2 = mono_disasm_code_one (NULL, cfg->method, bb->last_ins->cil_code, NULL);
8657                         else
8658                                 code2 = g_strdup ("");
8659
8660                         code1 [strlen (code1) - 1] = 0;
8661                         code = g_strdup_printf ("%s -> %s", code1, code2);
8662                         g_free (code1);
8663                         g_free (code2);
8664                 } else*/
8665                         code = g_strdup ("\n");
8666                 g_print ("\nBB%d DFN%d (len: %d): %s", bb->block_num, i, bb->cil_length, code);
8667                 if (bb->code) {
8668                         MonoInst *c = bb->code;
8669                         while (c) {
8670                                 mono_print_tree (c);
8671                                 g_print ("\n");
8672                                 c = c->next;
8673                         }
8674                 } else {
8675
8676                 }
8677
8678                 g_print ("\tprev:");
8679                 for (j = 0; j < bb->in_count; ++j) {
8680                         g_print (" BB%d", bb->in_bb [j]->block_num);
8681                 }
8682                 g_print ("\t\tsucc:");
8683                 for (j = 0; j < bb->out_count; ++j) {
8684                         g_print (" BB%d", bb->out_bb [j]->block_num);
8685                 }
8686                 g_print ("\n\tidom: BB%d\n", bb->idom? bb->idom->block_num: -1);
8687
8688                 if (bb->idom)
8689                         g_assert (mono_bitset_test_fast (bb->dominators, bb->idom->dfn));
8690
8691                 if (bb->dominators)
8692                         mono_blockset_print (cfg, bb->dominators, "\tdominators", bb->idom? bb->idom->dfn: -1);
8693                 if (bb->dfrontier)
8694                         mono_blockset_print (cfg, bb->dfrontier, "\tdfrontier", -1);
8695                 g_free (code);
8696         }
8697
8698         g_print ("\n");
8699 }
8700
8701 void
8702 mono_bblock_add_inst (MonoBasicBlock *bb, MonoInst *inst)
8703 {
8704         inst->next = NULL;
8705         if (bb->last_ins) {
8706                 g_assert (bb->code);
8707                 bb->last_ins->next = inst;
8708                 bb->last_ins = inst;
8709         } else {
8710                 bb->last_ins = bb->code = inst;
8711         }
8712 }
8713
8714 void
8715 mono_destroy_compile (MonoCompile *cfg)
8716 {
8717         //mono_mempool_stats (cfg->mempool);
8718         mono_free_loop_info (cfg);
8719         if (cfg->rs)
8720                 mono_regstate_free (cfg->rs);
8721         if (cfg->spvars)
8722                 g_hash_table_destroy (cfg->spvars);
8723         if (cfg->exvars)
8724                 g_hash_table_destroy (cfg->exvars);
8725         mono_mempool_destroy (cfg->mempool);
8726         g_list_free (cfg->ldstr_list);
8727         g_hash_table_destroy (cfg->token_info_hash);
8728
8729         g_free (cfg->varinfo);
8730         g_free (cfg->vars);
8731         g_free (cfg->exception_message);
8732         g_free (cfg);
8733 }
8734
8735 #ifdef HAVE_KW_THREAD
8736 static __thread gpointer mono_lmf_addr MONO_TLS_FAST;
8737 #ifdef MONO_ARCH_ENABLE_MONO_LMF_VAR
8738 /* 
8739  * When this is defined, the current lmf is stored in this tls variable instead of in 
8740  * jit_tls->lmf.
8741  */
8742 static __thread gpointer mono_lmf MONO_TLS_FAST;
8743 #endif
8744 #endif
8745
8746 guint32
8747 mono_get_jit_tls_key (void)
8748 {
8749         return mono_jit_tls_id;
8750 }
8751
8752 gint32
8753 mono_get_lmf_tls_offset (void)
8754 {
8755 #if defined(HAVE_KW_THREAD) && defined(MONO_ARCH_ENABLE_MONO_LMF_VAR)
8756         int offset;
8757         MONO_THREAD_VAR_OFFSET(mono_lmf,offset);
8758         return offset;
8759 #else
8760         return -1;
8761 #endif
8762 }
8763
8764 gint32
8765 mono_get_lmf_addr_tls_offset (void)
8766 {
8767         int offset;
8768         MONO_THREAD_VAR_OFFSET(mono_lmf_addr,offset);
8769         return offset;
8770 }
8771
8772 MonoLMF *
8773 mono_get_lmf (void)
8774 {
8775 #if defined(HAVE_KW_THREAD) && defined(MONO_ARCH_ENABLE_MONO_LMF_VAR)
8776         return mono_lmf;
8777 #else
8778         MonoJitTlsData *jit_tls;
8779
8780         if ((jit_tls = TlsGetValue (mono_jit_tls_id)))
8781                 return jit_tls->lmf;
8782
8783         g_assert_not_reached ();
8784         return NULL;
8785 #endif
8786 }
8787
8788 MonoLMF **
8789 mono_get_lmf_addr (void)
8790 {
8791 #ifdef HAVE_KW_THREAD
8792         return mono_lmf_addr;
8793 #else
8794         MonoJitTlsData *jit_tls;
8795
8796         if ((jit_tls = TlsGetValue (mono_jit_tls_id)))
8797                 return &jit_tls->lmf;
8798
8799         g_assert_not_reached ();
8800         return NULL;
8801 #endif
8802 }
8803
8804 /* Called by native->managed wrappers */
8805 void
8806 mono_jit_thread_attach (MonoDomain *domain)
8807 {
8808 #ifdef HAVE_KW_THREAD
8809         if (!mono_lmf_addr) {
8810                 mono_thread_attach (domain);
8811         }
8812 #else
8813         if (!TlsGetValue (mono_jit_tls_id))
8814                 mono_thread_attach (domain);
8815 #endif
8816 }       
8817
8818 /**
8819  * mono_thread_abort:
8820  * @obj: exception object
8821  *
8822  * abort the thread, print exception information and stack trace
8823  */
8824 static void
8825 mono_thread_abort (MonoObject *obj)
8826 {
8827         /* MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id); */
8828         
8829         /* handle_remove should be eventually called for this thread, too
8830         g_free (jit_tls);*/
8831
8832         mono_thread_exit ();
8833 }
8834
8835 static void*
8836 setup_jit_tls_data (gpointer stack_start, gpointer abort_func)
8837 {
8838         MonoJitTlsData *jit_tls;
8839         MonoLMF *lmf;
8840
8841         jit_tls = TlsGetValue (mono_jit_tls_id);
8842         if (jit_tls)
8843                 return jit_tls;
8844
8845         jit_tls = g_new0 (MonoJitTlsData, 1);
8846
8847         TlsSetValue (mono_jit_tls_id, jit_tls);
8848
8849         jit_tls->abort_func = abort_func;
8850         jit_tls->end_of_stack = stack_start;
8851
8852         lmf = g_new0 (MonoLMF, 1);
8853         lmf->ebp = -1;
8854
8855         jit_tls->first_lmf = lmf;
8856
8857 #if defined(HAVE_KW_THREAD) && defined(MONO_ARCH_ENABLE_MONO_LMF_VAR)
8858         /* jit_tls->lmf is unused */
8859         mono_lmf = lmf;
8860         mono_lmf_addr = &mono_lmf;
8861 #else
8862 #if defined(HAVE_KW_THREAD)
8863         mono_lmf_addr = &jit_tls->lmf;  
8864 #endif
8865
8866         jit_tls->lmf = lmf;
8867 #endif
8868
8869         mono_arch_setup_jit_tls_data (jit_tls);
8870         mono_setup_altstack (jit_tls);
8871
8872         return jit_tls;
8873 }
8874
8875 static void
8876 mono_thread_start_cb (gsize tid, gpointer stack_start, gpointer func)
8877 {
8878         MonoThread *thread;
8879         void *jit_tls = setup_jit_tls_data (stack_start, mono_thread_abort);
8880         thread = mono_thread_current ();
8881         if (thread)
8882                 thread->jit_data = jit_tls;
8883 }
8884
8885 void (*mono_thread_attach_aborted_cb ) (MonoObject *obj) = NULL;
8886
8887 static void
8888 mono_thread_abort_dummy (MonoObject *obj)
8889 {
8890   if (mono_thread_attach_aborted_cb)
8891     mono_thread_attach_aborted_cb (obj);
8892   else
8893     mono_thread_abort (obj);
8894 }
8895
8896 static void
8897 mono_thread_attach_cb (gsize tid, gpointer stack_start)
8898 {
8899         MonoThread *thread;
8900         void *jit_tls = setup_jit_tls_data (stack_start, mono_thread_abort_dummy);
8901         thread = mono_thread_current ();
8902         if (thread)
8903                 thread->jit_data = jit_tls;
8904         if (mono_profiler_get_events () & MONO_PROFILE_STATISTICAL)
8905                 setup_stat_profiler ();
8906 }
8907
8908 static void
8909 mini_thread_cleanup (MonoThread *thread)
8910 {
8911         MonoJitTlsData *jit_tls = thread->jit_data;
8912
8913         if (jit_tls) {
8914                 mono_arch_free_jit_tls_data (jit_tls);
8915
8916                 mono_free_altstack (jit_tls);
8917                 g_free (jit_tls->first_lmf);
8918                 g_free (jit_tls);
8919                 thread->jit_data = NULL;
8920                 TlsSetValue (mono_jit_tls_id, NULL);
8921         }
8922 }
8923
8924 void
8925 mono_add_patch_info (MonoCompile *cfg, int ip, MonoJumpInfoType type, gconstpointer target)
8926 {
8927         MonoJumpInfo *ji = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfo));
8928
8929         ji->ip.i = ip;
8930         ji->type = type;
8931         ji->data.target = target;
8932         ji->next = cfg->patch_info;
8933
8934         cfg->patch_info = ji;
8935 }
8936
8937 void
8938 mono_remove_patch_info (MonoCompile *cfg, int ip)
8939 {
8940         MonoJumpInfo **ji = &cfg->patch_info;
8941
8942         while (*ji) {
8943                 if ((*ji)->ip.i == ip)
8944                         *ji = (*ji)->next;
8945                 else
8946                         ji = &((*ji)->next);
8947         }
8948 }
8949
8950 /**
8951  * mono_patch_info_dup_mp:
8952  *
8953  * Make a copy of PATCH_INFO, allocating memory from the mempool MP.
8954  */
8955 MonoJumpInfo*
8956 mono_patch_info_dup_mp (MonoMemPool *mp, MonoJumpInfo *patch_info)
8957 {
8958         MonoJumpInfo *res = mono_mempool_alloc (mp, sizeof (MonoJumpInfo));
8959         memcpy (res, patch_info, sizeof (MonoJumpInfo));
8960
8961         switch (patch_info->type) {
8962         case MONO_PATCH_INFO_RVA:
8963         case MONO_PATCH_INFO_LDSTR:
8964         case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
8965         case MONO_PATCH_INFO_LDTOKEN:
8966         case MONO_PATCH_INFO_DECLSEC:
8967                 res->data.token = mono_mempool_alloc (mp, sizeof (MonoJumpInfoToken));
8968                 memcpy (res->data.token, patch_info->data.token, sizeof (MonoJumpInfoToken));
8969                 break;
8970         case MONO_PATCH_INFO_SWITCH:
8971                 res->data.table = mono_mempool_alloc (mp, sizeof (MonoJumpInfoBBTable));
8972                 memcpy (res->data.table, patch_info->data.table, sizeof (MonoJumpInfoBBTable));
8973                 break;
8974         default:
8975                 break;
8976         }
8977
8978         return res;
8979 }
8980
8981 guint
8982 mono_patch_info_hash (gconstpointer data)
8983 {
8984         const MonoJumpInfo *ji = (MonoJumpInfo*)data;
8985
8986         switch (ji->type) {
8987         case MONO_PATCH_INFO_RVA:
8988         case MONO_PATCH_INFO_LDSTR:
8989         case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
8990         case MONO_PATCH_INFO_LDTOKEN:
8991         case MONO_PATCH_INFO_DECLSEC:
8992                 return (ji->type << 8) | ji->data.token->token;
8993         default:
8994                 return (ji->type << 8);
8995         }
8996 }
8997
8998 /* 
8999  * mono_patch_info_equal:
9000  * 
9001  * This might fail to recognize equivalent patches, i.e. floats, so its only
9002  * usable in those cases where this is not a problem, i.e. sharing GOT slots
9003  * in AOT.
9004  */
9005 gint
9006 mono_patch_info_equal (gconstpointer ka, gconstpointer kb)
9007 {
9008         const MonoJumpInfo *ji1 = (MonoJumpInfo*)ka;
9009         const MonoJumpInfo *ji2 = (MonoJumpInfo*)kb;
9010
9011         if (ji1->type != ji2->type)
9012                 return 0;
9013
9014         switch (ji1->type) {
9015         case MONO_PATCH_INFO_RVA:
9016         case MONO_PATCH_INFO_LDSTR:
9017         case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
9018         case MONO_PATCH_INFO_LDTOKEN:
9019         case MONO_PATCH_INFO_DECLSEC:
9020                 if ((ji1->data.token->image != ji2->data.token->image) ||
9021                         (ji1->data.token->token != ji2->data.token->token))
9022                         return 0;
9023                 break;
9024         default:
9025                 if (ji1->data.name != ji2->data.name)
9026                         return 0;
9027                 break;
9028         }
9029
9030         return 1;
9031 }
9032
9033 gpointer
9034 mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *patch_info, gboolean run_cctors)
9035 {
9036         unsigned char *ip = patch_info->ip.i + code;
9037         gconstpointer target = NULL;
9038
9039         switch (patch_info->type) {
9040         case MONO_PATCH_INFO_BB:
9041                 target = patch_info->data.bb->native_offset + code;
9042                 break;
9043         case MONO_PATCH_INFO_ABS:
9044                 target = patch_info->data.target;
9045                 break;
9046         case MONO_PATCH_INFO_LABEL:
9047                 target = patch_info->data.inst->inst_c0 + code;
9048                 break;
9049         case MONO_PATCH_INFO_IP:
9050                 target = ip;
9051                 break;
9052         case MONO_PATCH_INFO_METHOD_REL:
9053                 target = code + patch_info->data.offset;
9054                 break;
9055         case MONO_PATCH_INFO_INTERNAL_METHOD: {
9056                 MonoJitICallInfo *mi = mono_find_jit_icall_by_name (patch_info->data.name);
9057                 if (!mi) {
9058                         g_warning ("unknown MONO_PATCH_INFO_INTERNAL_METHOD %s", patch_info->data.name);
9059                         g_assert_not_reached ();
9060                 }
9061                 target = mono_icall_get_wrapper (mi);
9062                 break;
9063         }
9064         case MONO_PATCH_INFO_METHOD_JUMP: {
9065                 GSList *list;
9066
9067                 /* get the trampoline to the method from the domain */
9068                 target = mono_create_jump_trampoline (domain, patch_info->data.method, TRUE);
9069                 if (!domain->jump_target_hash)
9070                         domain->jump_target_hash = g_hash_table_new (NULL, NULL);
9071                 list = g_hash_table_lookup (domain->jump_target_hash, patch_info->data.method);
9072                 list = g_slist_prepend (list, ip);
9073                 g_hash_table_insert (domain->jump_target_hash, patch_info->data.method, list);
9074                 break;
9075         }
9076         case MONO_PATCH_INFO_METHOD:
9077                 if (patch_info->data.method == method) {
9078                         target = code;
9079                 } else
9080                         /* get the trampoline to the method from the domain */
9081                         target = mono_create_jit_trampoline (patch_info->data.method);
9082                 break;
9083         case MONO_PATCH_INFO_SWITCH: {
9084                 gpointer *jump_table;
9085                 int i;
9086
9087                 if (method && method->dynamic) {
9088                         jump_table = mono_code_manager_reserve (mono_dynamic_code_hash_lookup (domain, method)->code_mp, sizeof (gpointer) * patch_info->data.table->table_size);
9089                 } else {
9090                         mono_domain_lock (domain);
9091                         jump_table = mono_code_manager_reserve (domain->code_mp, sizeof (gpointer) * patch_info->data.table->table_size);
9092                         mono_domain_unlock (domain);
9093                 }
9094
9095                 for (i = 0; i < patch_info->data.table->table_size; i++) {
9096                         jump_table [i] = code + GPOINTER_TO_INT (patch_info->data.table->table [i]);
9097                 }
9098                 target = jump_table;
9099                 break;
9100         }
9101         case MONO_PATCH_INFO_METHODCONST:
9102         case MONO_PATCH_INFO_CLASS:
9103         case MONO_PATCH_INFO_IMAGE:
9104         case MONO_PATCH_INFO_FIELD:
9105                 target = patch_info->data.target;
9106                 break;
9107         case MONO_PATCH_INFO_IID:
9108                 mono_class_init (patch_info->data.klass);
9109                 target = GINT_TO_POINTER ((int)patch_info->data.klass->interface_id);
9110                 break;
9111         case MONO_PATCH_INFO_ADJUSTED_IID:
9112                 mono_class_init (patch_info->data.klass);
9113                 target = GINT_TO_POINTER ((int)(-((patch_info->data.klass->interface_id + 1) * SIZEOF_VOID_P)));
9114                 break;
9115         case MONO_PATCH_INFO_VTABLE:
9116                 target = mono_class_vtable (domain, patch_info->data.klass);
9117                 break;
9118         case MONO_PATCH_INFO_CLASS_INIT:
9119                 target = mono_create_class_init_trampoline (mono_class_vtable (domain, patch_info->data.klass));
9120                 break;
9121         case MONO_PATCH_INFO_SFLDA: {
9122                 MonoVTable *vtable = mono_class_vtable (domain, patch_info->data.field->parent);
9123                 if (!vtable->initialized && !(vtable->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) && (method && mono_class_needs_cctor_run (vtable->klass, method)))
9124                         /* Done by the generated code */
9125                         ;
9126                 else {
9127                         if (run_cctors)
9128                                 mono_runtime_class_init (vtable);
9129                 }
9130                 target = (char*)vtable->data + patch_info->data.field->offset;
9131                 break;
9132         }
9133         case MONO_PATCH_INFO_RVA:
9134                 target = mono_image_rva_map (patch_info->data.token->image, patch_info->data.token->token);
9135                 break;
9136         case MONO_PATCH_INFO_R4:
9137         case MONO_PATCH_INFO_R8:
9138                 target = patch_info->data.target;
9139                 break;
9140         case MONO_PATCH_INFO_EXC_NAME:
9141                 target = patch_info->data.name;
9142                 break;
9143         case MONO_PATCH_INFO_LDSTR:
9144                 target =
9145                         mono_ldstr (domain, patch_info->data.token->image, 
9146                                                 mono_metadata_token_index (patch_info->data.token->token));
9147                 break;
9148         case MONO_PATCH_INFO_TYPE_FROM_HANDLE: {
9149                 gpointer handle;
9150                 MonoClass *handle_class;
9151
9152                 handle = mono_ldtoken (patch_info->data.token->image, 
9153                                        patch_info->data.token->token, &handle_class, NULL);
9154                 mono_class_init (handle_class);
9155                 mono_class_init (mono_class_from_mono_type (handle));
9156
9157                 target =
9158                         mono_type_get_object (domain, handle);
9159                 break;
9160         }
9161         case MONO_PATCH_INFO_LDTOKEN: {
9162                 gpointer handle;
9163                 MonoClass *handle_class;
9164                 
9165                 handle = mono_ldtoken (patch_info->data.token->image,
9166                                        patch_info->data.token->token, &handle_class, NULL);
9167                 mono_class_init (handle_class);
9168                 
9169                 target = handle;
9170                 break;
9171         }
9172         case MONO_PATCH_INFO_DECLSEC:
9173                 target = (mono_metadata_blob_heap (patch_info->data.token->image, patch_info->data.token->token) + 2);
9174                 break;
9175         case MONO_PATCH_INFO_BB_OVF:
9176         case MONO_PATCH_INFO_EXC_OVF:
9177         case MONO_PATCH_INFO_GOT_OFFSET:
9178         case MONO_PATCH_INFO_NONE:
9179                 break;
9180         default:
9181                 g_assert_not_reached ();
9182         }
9183
9184         return (gpointer)target;
9185 }
9186
9187 static void
9188 dec_foreach (MonoInst *tree, MonoCompile *cfg) {
9189         MonoJitICallInfo *info;
9190
9191         decompose_foreach (tree, cfg);
9192
9193         switch (mono_burg_arity [tree->opcode]) {
9194         case 0: break;
9195         case 1: 
9196                 dec_foreach (tree->inst_left, cfg);
9197
9198                 if ((info = mono_find_jit_opcode_emulation (tree->opcode))) {
9199                         MonoInst *iargs [2];
9200                 
9201                         iargs [0] = tree->inst_left;
9202
9203                         mono_emulate_opcode (cfg, tree, iargs, info);
9204                         return;
9205                 }
9206
9207                 break;
9208         case 2:
9209 #ifdef MONO_ARCH_BIGMUL_INTRINS
9210                 if (tree->opcode == OP_LMUL
9211                                 && (cfg->opt & MONO_OPT_INTRINS)
9212                                 && (tree->inst_left->opcode == CEE_CONV_I8 
9213                                         || tree->inst_left->opcode == CEE_CONV_U8)
9214                                 && tree->inst_left->inst_left->type == STACK_I4
9215                                 && (tree->inst_right->opcode == CEE_CONV_I8 
9216                                         || tree->inst_right->opcode == CEE_CONV_U8)
9217                                 && tree->inst_right->inst_left->type == STACK_I4
9218                                 && tree->inst_left->opcode == tree->inst_right->opcode) {
9219                         tree->opcode = (tree->inst_left->opcode == CEE_CONV_I8 ? OP_BIGMUL: OP_BIGMUL_UN);
9220                         tree->inst_left = tree->inst_left->inst_left;
9221                         tree->inst_right = tree->inst_right->inst_left;
9222                         dec_foreach (tree, cfg);
9223                 } else 
9224 #endif
9225                         if ((info = mono_find_jit_opcode_emulation (tree->opcode))) {
9226                         MonoInst *iargs [2];
9227                 
9228                         iargs [0] = tree->inst_i0;
9229                         iargs [1] = tree->inst_i1;
9230                 
9231                         mono_emulate_opcode (cfg, tree, iargs, info);
9232
9233                         dec_foreach (iargs [0], cfg);
9234                         dec_foreach (iargs [1], cfg);
9235                         return;
9236                 } else {
9237                         dec_foreach (tree->inst_left, cfg);
9238                         dec_foreach (tree->inst_right, cfg);
9239                 }
9240                 break;
9241         default:
9242                 g_assert_not_reached ();
9243         }
9244 }
9245
9246 static void
9247 decompose_pass (MonoCompile *cfg) {
9248         MonoBasicBlock *bb;
9249
9250         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
9251                 MonoInst *tree;
9252                 cfg->cbb = bb;
9253                 cfg->prev_ins = NULL;
9254                 for (tree = cfg->cbb->code; tree; tree = tree->next) {
9255                         dec_foreach (tree, cfg);
9256                         cfg->prev_ins = tree;
9257                 }
9258         }
9259 }
9260
9261 static void
9262 nullify_basic_block (MonoBasicBlock *bb) 
9263 {
9264         bb->in_count = 0;
9265         bb->out_count = 0;
9266         bb->in_bb = NULL;
9267         bb->out_bb = NULL;
9268         bb->next_bb = NULL;
9269         bb->code = bb->last_ins = NULL;
9270         bb->cil_code = NULL;
9271 }
9272
9273 static void 
9274 replace_out_block (MonoBasicBlock *bb, MonoBasicBlock *orig,  MonoBasicBlock *repl)
9275 {
9276         int i;
9277
9278         for (i = 0; i < bb->out_count; i++) {
9279                 MonoBasicBlock *ob = bb->out_bb [i];
9280                 if (ob == orig) {
9281                         if (!repl) {
9282                                 if (bb->out_count > 1) {
9283                                         bb->out_bb [i] = bb->out_bb [bb->out_count - 1];
9284                                 }
9285                                 bb->out_count--;
9286                         } else {
9287                                 bb->out_bb [i] = repl;
9288                         }
9289                 }
9290         }
9291 }
9292
9293 static void 
9294 replace_in_block (MonoBasicBlock *bb, MonoBasicBlock *orig, MonoBasicBlock *repl)
9295 {
9296         int i;
9297
9298         for (i = 0; i < bb->in_count; i++) {
9299                 MonoBasicBlock *ib = bb->in_bb [i];
9300                 if (ib == orig) {
9301                         if (!repl) {
9302                                 if (bb->in_count > 1) {
9303                                         bb->in_bb [i] = bb->in_bb [bb->in_count - 1];
9304                                 }
9305                                 bb->in_count--;
9306                         } else {
9307                                 bb->in_bb [i] = repl;
9308                         }
9309                 }
9310         }
9311 }
9312
9313 static void
9314 replace_out_block_in_code (MonoBasicBlock *bb, MonoBasicBlock *orig, MonoBasicBlock *repl) {
9315         MonoInst *inst;
9316         
9317         for (inst = bb->code; inst != NULL; inst = inst->next) {
9318                 if (inst->opcode == OP_CALL_HANDLER) {
9319                         if (inst->inst_target_bb == orig) {
9320                                 inst->inst_target_bb = repl;
9321                         }
9322                 }
9323         }
9324         if (bb->last_ins != NULL) {
9325                 switch (bb->last_ins->opcode) {
9326                 case OP_BR:
9327                         if (bb->last_ins->inst_target_bb == orig) {
9328                                 bb->last_ins->inst_target_bb = repl;
9329                         }
9330                         break;
9331                 case CEE_SWITCH: {
9332                         int i;
9333                         int n = GPOINTER_TO_INT (bb->last_ins->klass);
9334                         for (i = 0; i < n; i++ ) {
9335                                 if (bb->last_ins->inst_many_bb [i] == orig) {
9336                                         bb->last_ins->inst_many_bb [i] = repl;
9337                                 }
9338                         }
9339                         break;
9340                 }
9341                 case CEE_BNE_UN:
9342                 case CEE_BEQ:
9343                 case CEE_BLT:
9344                 case CEE_BLT_UN:
9345                 case CEE_BGT:
9346                 case CEE_BGT_UN:
9347                 case CEE_BGE:
9348                 case CEE_BGE_UN:
9349                 case CEE_BLE:
9350                 case CEE_BLE_UN:
9351                         if (bb->last_ins->inst_true_bb == orig) {
9352                                 bb->last_ins->inst_true_bb = repl;
9353                         }
9354                         if (bb->last_ins->inst_false_bb == orig) {
9355                                 bb->last_ins->inst_false_bb = repl;
9356                         }
9357                         break;
9358                 default:
9359                         break;
9360                 }
9361         }
9362 }
9363
9364 static void 
9365 replace_basic_block (MonoBasicBlock *bb, MonoBasicBlock *orig,  MonoBasicBlock *repl)
9366 {
9367         int i, j;
9368
9369         for (i = 0; i < bb->out_count; i++) {
9370                 MonoBasicBlock *ob = bb->out_bb [i];
9371                 for (j = 0; j < ob->in_count; j++) {
9372                         if (ob->in_bb [j] == orig) {
9373                                 ob->in_bb [j] = repl;
9374                         }
9375                 }
9376         }
9377
9378 }
9379
9380 /**
9381   * Check if a bb is useless (is just made of NOPs and ends with an
9382   * unconditional branch, or nothing).
9383   * If it is so, unlink it from the CFG and nullify it, and return TRUE.
9384   * Otherwise, return FALSE;
9385   */
9386 static gboolean
9387 remove_block_if_useless (MonoCompile *cfg, MonoBasicBlock *bb, MonoBasicBlock *previous_bb) {
9388         MonoBasicBlock *target_bb = NULL;
9389         MonoInst *inst;
9390         
9391         /* Do not touch handlers */
9392         if (bb->region != -1) {
9393                 bb->not_useless = TRUE;
9394                 return FALSE;
9395         }
9396         
9397         for (inst = bb->code; inst != NULL; inst = inst->next) {
9398                 switch (inst->opcode) {
9399                 case OP_NOP:
9400                         break;
9401                 case OP_BR:
9402                         target_bb = inst->inst_target_bb;
9403                         break;
9404                 default:
9405                         bb->not_useless = TRUE;
9406                         return FALSE;
9407                 }
9408         }
9409         
9410         if (target_bb == NULL) {
9411                 if ((bb->out_count == 1) && (bb->out_bb [0] == bb->next_bb)) {
9412                         target_bb = bb->next_bb;
9413                 } else {
9414                         /* Do not touch empty BBs that do not "fall through" to their next BB (like the exit BB) */
9415                         return FALSE;
9416                 }
9417         }
9418         
9419         /* Do not touch BBs following a switch (they are the "default" branch) */
9420         if ((previous_bb->last_ins != NULL) && (previous_bb->last_ins->opcode == CEE_SWITCH)) {
9421                 return FALSE;
9422         }
9423         
9424         /* Do not touch BBs following the entry BB and jumping to something that is not */
9425         /* thiry "next" bb (the entry BB cannot contain the branch) */
9426         if ((previous_bb == cfg->bb_entry) && (bb->next_bb != target_bb)) {
9427                 return FALSE;
9428         }
9429
9430         /* 
9431          * Do not touch BBs following a try block as the code in 
9432          * mini_method_compile needs them to compute the length of the try block.
9433          */
9434         if (MONO_BBLOCK_IS_IN_REGION (previous_bb, MONO_REGION_TRY))
9435                 return FALSE;
9436         
9437         /* Check that there is a target BB, and that bb is not an empty loop (Bug 75061) */
9438         if ((target_bb != NULL) && (target_bb != bb)) {
9439                 int i;
9440
9441                 if (cfg->verbose_level > 1) {
9442                         printf ("remove_block_if_useless %s, removed BB%d\n", mono_method_full_name (cfg->method, TRUE), bb->block_num);
9443                 }
9444                 
9445                 /* unlink_bblock () modifies the bb->in_bb array so can't use a for loop here */
9446                 while (bb->in_count) {
9447                         MonoBasicBlock *in_bb = bb->in_bb [0];
9448                         mono_unlink_bblock (cfg, in_bb, bb);
9449                         link_bblock (cfg, in_bb, target_bb);
9450                         replace_out_block_in_code (in_bb, bb, target_bb);
9451                 }
9452                 
9453                 mono_unlink_bblock (cfg, bb, target_bb);
9454                 
9455                 if ((previous_bb != cfg->bb_entry) &&
9456                                 (previous_bb->region == bb->region) &&
9457                                 ((previous_bb->last_ins == NULL) ||
9458                                 ((previous_bb->last_ins->opcode != OP_BR) &&
9459                                 (! (MONO_IS_COND_BRANCH_OP (previous_bb->last_ins))) &&
9460                                 (previous_bb->last_ins->opcode != CEE_SWITCH)))) {
9461                         for (i = 0; i < previous_bb->out_count; i++) {
9462                                 if (previous_bb->out_bb [i] == target_bb) {
9463                                         MonoInst *jump;
9464                                         MONO_INST_NEW (cfg, jump, OP_BR);
9465                                         MONO_ADD_INS (previous_bb, jump);
9466                                         jump->cil_code = previous_bb->cil_code;
9467                                         jump->inst_target_bb = target_bb;
9468                                         break;
9469                                 }
9470                         }
9471                 }
9472                 
9473                 previous_bb->next_bb = bb->next_bb;
9474                 nullify_basic_block (bb);
9475                 
9476                 return TRUE;
9477         } else {
9478                 return FALSE;
9479         }
9480 }
9481
9482 static void
9483 merge_basic_blocks (MonoBasicBlock *bb, MonoBasicBlock *bbn) 
9484 {
9485         bb->out_count = bbn->out_count;
9486         bb->out_bb = bbn->out_bb;
9487
9488         replace_basic_block (bb, bbn, bb);
9489
9490         /* Nullify branch at the end of bb */
9491         if (bb->last_ins && MONO_IS_BRANCH_OP (bb->last_ins)) {
9492                 bb->last_ins->opcode = OP_NOP;
9493         }               
9494
9495         if (bb->last_ins) {
9496                 if (bbn->code) {
9497                         bb->last_ins->next = bbn->code;
9498                         bb->last_ins = bbn->last_ins;
9499                 }
9500         } else {
9501                 bb->code = bbn->code;
9502                 bb->last_ins = bbn->last_ins;
9503         }
9504         bb->next_bb = bbn->next_bb;
9505         nullify_basic_block (bbn);
9506 }
9507
9508 static void
9509 move_basic_block_to_end (MonoCompile *cfg, MonoBasicBlock *bb)
9510 {
9511         MonoBasicBlock *bbn, *next;
9512
9513         next = bb->next_bb;
9514
9515         /* Find the previous */
9516         for (bbn = cfg->bb_entry; bbn->next_bb && bbn->next_bb != bb; bbn = bbn->next_bb)
9517                 ;
9518         if (bbn->next_bb) {
9519                 bbn->next_bb = bb->next_bb;
9520         }
9521
9522         /* Find the last */
9523         for (bbn = cfg->bb_entry; bbn->next_bb; bbn = bbn->next_bb)
9524                 ;
9525         bbn->next_bb = bb;
9526         bb->next_bb = NULL;
9527
9528         /* Add a branch */
9529         if (next && (!bb->last_ins || (bb->last_ins->opcode != OP_NOT_REACHED))) {
9530                 MonoInst *ins;
9531
9532                 MONO_INST_NEW (cfg, ins, OP_BR);
9533                 MONO_ADD_INS (bb, ins);
9534                 link_bblock (cfg, bb, next);
9535                 ins->inst_target_bb = next;
9536         }               
9537 }
9538
9539 /* checks that a and b represent the same instructions, conservatively,
9540  * it can return FALSE also for two trees that are equal.
9541  * FIXME: also make sure there are no side effects.
9542  */
9543 static int
9544 same_trees (MonoInst *a, MonoInst *b)
9545 {
9546         int arity;
9547         if (a->opcode != b->opcode)
9548                 return FALSE;
9549         arity = mono_burg_arity [a->opcode];
9550         if (arity == 1) {
9551                 if (a->ssa_op == b->ssa_op && a->ssa_op == MONO_SSA_LOAD && a->inst_i0 == b->inst_i0)
9552                         return TRUE;
9553                 return same_trees (a->inst_left, b->inst_left);
9554         } else if (arity == 2) {
9555                 return same_trees (a->inst_left, b->inst_left) && same_trees (a->inst_right, b->inst_right);
9556         } else if (arity == 0) {
9557                 switch (a->opcode) {
9558                 case OP_ICONST:
9559                         return a->inst_c0 == b->inst_c0;
9560                 default:
9561                         return FALSE;
9562                 }
9563         }
9564         return FALSE;
9565 }
9566
9567 static int
9568 get_unsigned_condbranch (int opcode)
9569 {
9570         switch (opcode) {
9571         case CEE_BLE: return CEE_BLE_UN;
9572         case CEE_BLT: return CEE_BLT_UN;
9573         case CEE_BGE: return CEE_BGE_UN;
9574         case CEE_BGT: return CEE_BGT_UN;
9575         }
9576         g_assert_not_reached ();
9577         return 0;
9578 }
9579
9580 static int
9581 tree_is_unsigned (MonoInst* ins) {
9582         switch (ins->opcode) {
9583         case OP_ICONST:
9584                 return (int)ins->inst_c0 >= 0;
9585         /* array lengths are positive as are string sizes */
9586         case CEE_LDLEN:
9587         case OP_STRLEN:
9588                 return TRUE;
9589         case CEE_CONV_U1:
9590         case CEE_CONV_U2:
9591         case CEE_CONV_U4:
9592         case CEE_CONV_OVF_U1:
9593         case CEE_CONV_OVF_U2:
9594         case CEE_CONV_OVF_U4:
9595                 return TRUE;
9596         case CEE_LDIND_U1:
9597         case CEE_LDIND_U2:
9598         case CEE_LDIND_U4:
9599                 return TRUE;
9600         default:
9601                 return FALSE;
9602         }
9603 }
9604
9605 /* check if an unsigned compare can be used instead of two signed compares
9606  * for (val < 0 || val > limit) conditionals.
9607  * Returns TRUE if the optimization has been applied.
9608  * Note that this can't be applied if the second arg is not positive...
9609  */
9610 static int
9611 try_unsigned_compare (MonoCompile *cfg, MonoBasicBlock *bb)
9612 {
9613         MonoBasicBlock *truet, *falset;
9614         MonoInst *cmp_inst = bb->last_ins->inst_left;
9615         MonoInst *condb;
9616         if (!cmp_inst->inst_right->inst_c0 == 0)
9617                 return FALSE;
9618         truet = bb->last_ins->inst_true_bb;
9619         falset = bb->last_ins->inst_false_bb;
9620         if (falset->in_count != 1)
9621                 return FALSE;
9622         condb = falset->last_ins;
9623         /* target bb must have one instruction */
9624         if (!condb || (condb != falset->code))
9625                 return FALSE;
9626         if ((((condb->opcode == CEE_BLE || condb->opcode == CEE_BLT) && (condb->inst_false_bb == truet))
9627                         || ((condb->opcode == CEE_BGE || condb->opcode == CEE_BGT) && (condb->inst_true_bb == truet)))
9628                         && same_trees (cmp_inst->inst_left, condb->inst_left->inst_left)) {
9629                 if (!tree_is_unsigned (condb->inst_left->inst_right))
9630                         return FALSE;
9631                 condb->opcode = get_unsigned_condbranch (condb->opcode);
9632                 /* change the original condbranch to just point to the new unsigned check */
9633                 bb->last_ins->opcode = OP_BR;
9634                 bb->last_ins->inst_target_bb = falset;
9635                 replace_out_block (bb, truet, NULL);
9636                 replace_in_block (truet, bb, NULL);
9637                 return TRUE;
9638         }
9639         return FALSE;
9640 }
9641
9642 /*
9643  * Optimizes the branches on the Control Flow Graph
9644  *
9645  */
9646 static void
9647 optimize_branches (MonoCompile *cfg)
9648 {
9649         int i, changed = FALSE;
9650         MonoBasicBlock *bb, *bbn;
9651         guint32 niterations;
9652
9653         /*
9654          * Some crazy loops could cause the code below to go into an infinite
9655          * loop, see bug #53003 for an example. To prevent this, we put an upper
9656          * bound on the number of iterations.
9657          */
9658         if (cfg->num_bblocks > 1000)
9659                 niterations = cfg->num_bblocks * 2;
9660         else
9661                 niterations = 1000;
9662
9663         do {
9664                 MonoBasicBlock *previous_bb;
9665                 changed = FALSE;
9666                 niterations --;
9667
9668                 /* we skip the entry block (exit is handled specially instead ) */
9669                 for (previous_bb = cfg->bb_entry, bb = cfg->bb_entry->next_bb; bb; previous_bb = bb, bb = bb->next_bb) {
9670
9671                         /* dont touch code inside exception clauses */
9672                         if (bb->region != -1)
9673                                 continue;
9674
9675                         if (!bb->not_useless && remove_block_if_useless (cfg, bb, previous_bb)) {
9676                                 changed = TRUE;
9677                                 continue;
9678                         }
9679
9680                         if ((bbn = bb->next_bb) && bbn->in_count == 0 && bb->region == bbn->region) {
9681                                 if (cfg->verbose_level > 2)
9682                                         g_print ("nullify block triggered %d\n", bbn->block_num);
9683
9684                                 bb->next_bb = bbn->next_bb;
9685
9686                                 for (i = 0; i < bbn->out_count; i++)
9687                                         replace_in_block (bbn->out_bb [i], bbn, NULL);
9688
9689                                 nullify_basic_block (bbn);                      
9690                                 changed = TRUE;
9691                         }
9692
9693                         if (bb->out_count == 1) {
9694                                 bbn = bb->out_bb [0];
9695
9696                                 /* conditional branches where true and false targets are the same can be also replaced with OP_BR */
9697                                 if (bb->last_ins && MONO_IS_COND_BRANCH_OP (bb->last_ins)) {
9698                                         MonoInst *pop;
9699                                         MONO_INST_NEW (cfg, pop, CEE_POP);
9700                                         pop->inst_left = bb->last_ins->inst_left->inst_left;
9701                                         mono_add_ins_to_end (bb, pop);
9702                                         MONO_INST_NEW (cfg, pop, CEE_POP);
9703                                         pop->inst_left = bb->last_ins->inst_left->inst_right;
9704                                         mono_add_ins_to_end (bb, pop);
9705                                         bb->last_ins->opcode = OP_BR;
9706                                         bb->last_ins->inst_target_bb = bb->last_ins->inst_true_bb;
9707                                         changed = TRUE;
9708                                         if (cfg->verbose_level > 2)
9709                                                 g_print ("cond branch removal triggered in %d %d\n", bb->block_num, bb->out_count);
9710                                 }
9711
9712                                 if (bb->region == bbn->region && bb->next_bb == bbn) {
9713                                         /* the block are in sequence anyway ... */
9714
9715                                         /* branches to the following block can be removed */
9716                                         if (bb->last_ins && bb->last_ins->opcode == OP_BR) {
9717                                                 bb->last_ins->opcode = OP_NOP;
9718                                                 changed = TRUE;
9719                                                 if (cfg->verbose_level > 2)
9720                                                         g_print ("br removal triggered %d -> %d\n", bb->block_num, bbn->block_num);
9721                                         }
9722
9723                                         if (bbn->in_count == 1) {
9724
9725                                                 if (bbn != cfg->bb_exit) {
9726                                                         if (cfg->verbose_level > 2)
9727                                                                 g_print ("block merge triggered %d -> %d\n", bb->block_num, bbn->block_num);
9728                                                         merge_basic_blocks (bb, bbn);
9729                                                         changed = TRUE;
9730                                                         continue;
9731                                                 }
9732
9733                                                 //mono_print_bb_code (bb);
9734                                         }
9735                                 }
9736                         }
9737                         if ((bbn = bb->next_bb) && bbn->in_count == 0 && bb->region == bbn->region) {
9738                                 if (cfg->verbose_level > 2) {
9739                                         g_print ("nullify block triggered %d\n", bbn->block_num);
9740                                 }
9741                                 bb->next_bb = bbn->next_bb;
9742
9743                                 for (i = 0; i < bbn->out_count; i++)
9744                                         replace_in_block (bbn->out_bb [i], bbn, NULL);
9745
9746                                 nullify_basic_block (bbn);                      
9747                                 changed = TRUE;
9748                                 continue;
9749                         }
9750
9751                         if (bb->out_count == 1) {
9752                                 bbn = bb->out_bb [0];
9753
9754                                 if (bb->last_ins && bb->last_ins->opcode == OP_BR) {
9755                                         bbn = bb->last_ins->inst_target_bb;
9756                                         if (bb->region == bbn->region && bbn->code && bbn->code->opcode == OP_BR &&
9757                                             bbn->code->inst_target_bb->region == bb->region) {
9758                                                 
9759                                                 if (cfg->verbose_level > 2)
9760                                                         g_print ("in %s branch to branch triggered %d -> %d -> %d\n", cfg->method->name, 
9761                                                                  bb->block_num, bbn->block_num, bbn->code->inst_target_bb->block_num);
9762
9763                                                 replace_in_block (bbn, bb, NULL);
9764                                                 replace_out_block (bb, bbn, bbn->code->inst_target_bb);
9765                                                 link_bblock (cfg, bb, bbn->code->inst_target_bb);
9766                                                 bb->last_ins->inst_target_bb = bbn->code->inst_target_bb;
9767                                                 changed = TRUE;
9768                                                 continue;
9769                                         }
9770                                 }
9771                         } else if (bb->out_count == 2) {
9772                                 if (bb->last_ins && MONO_IS_COND_BRANCH_NOFP (bb->last_ins)) {
9773                                         int branch_result = mono_eval_cond_branch (bb->last_ins);
9774                                         MonoBasicBlock *taken_branch_target = NULL, *untaken_branch_target = NULL;
9775                                         if (branch_result == BRANCH_TAKEN) {
9776                                                 taken_branch_target = bb->last_ins->inst_true_bb;
9777                                                 untaken_branch_target = bb->last_ins->inst_false_bb;
9778                                         } else if (branch_result == BRANCH_NOT_TAKEN) {
9779                                                 taken_branch_target = bb->last_ins->inst_false_bb;
9780                                                 untaken_branch_target = bb->last_ins->inst_true_bb;
9781                                         }
9782                                         if (taken_branch_target) {
9783                                                 /* if mono_eval_cond_branch () is ever taken to handle 
9784                                                  * non-constant values to compare, issue a pop here.
9785                                                  */
9786                                                 bb->last_ins->opcode = OP_BR;
9787                                                 bb->last_ins->inst_target_bb = taken_branch_target;
9788                                                 mono_unlink_bblock (cfg, bb, untaken_branch_target);
9789                                                 changed = TRUE;
9790                                                 continue;
9791                                         }
9792                                         bbn = bb->last_ins->inst_true_bb;
9793                                         if (bb->region == bbn->region && bbn->code && bbn->code->opcode == OP_BR &&
9794                                             bbn->code->inst_target_bb->region == bb->region) {
9795                                                 if (cfg->verbose_level > 2)             
9796                                                         g_print ("cbranch1 to branch triggered %d -> (%d) %d (0x%02x)\n", 
9797                                                                  bb->block_num, bbn->block_num, bbn->code->inst_target_bb->block_num, 
9798                                                                  bbn->code->opcode);
9799
9800                                                 /* 
9801                                                  * Unlink, then relink bblocks to avoid various
9802                                                  * tricky situations when the two targets of the branch
9803                                                  * are equal, or will become equal after the change.
9804                                                  */
9805                                                 mono_unlink_bblock (cfg, bb, bb->last_ins->inst_true_bb);
9806                                                 mono_unlink_bblock (cfg, bb, bb->last_ins->inst_false_bb);
9807
9808                                                 bb->last_ins->inst_true_bb = bbn->code->inst_target_bb;
9809
9810                                                 link_bblock (cfg, bb, bb->last_ins->inst_true_bb);
9811                                                 link_bblock (cfg, bb, bb->last_ins->inst_false_bb);
9812
9813                                                 changed = TRUE;
9814                                                 continue;
9815                                         }
9816
9817                                         bbn = bb->last_ins->inst_false_bb;
9818                                         if (bb->region == bbn->region && bbn->code && bbn->code->opcode == OP_BR &&
9819                                             bbn->code->inst_target_bb->region == bb->region) {
9820                                                 if (cfg->verbose_level > 2)
9821                                                         g_print ("cbranch2 to branch triggered %d -> (%d) %d (0x%02x)\n", 
9822                                                                  bb->block_num, bbn->block_num, bbn->code->inst_target_bb->block_num, 
9823                                                                  bbn->code->opcode);
9824
9825                                                 mono_unlink_bblock (cfg, bb, bb->last_ins->inst_true_bb);
9826                                                 mono_unlink_bblock (cfg, bb, bb->last_ins->inst_false_bb);
9827
9828                                                 bb->last_ins->inst_false_bb = bbn->code->inst_target_bb;
9829
9830                                                 link_bblock (cfg, bb, bb->last_ins->inst_true_bb);
9831                                                 link_bblock (cfg, bb, bb->last_ins->inst_false_bb);
9832
9833                                                 changed = TRUE;
9834                                                 continue;
9835                                         }
9836                                 }
9837
9838                                 /* detect and optimize to unsigned compares checks like: if (v < 0 || v > limit */
9839                                 if (bb->last_ins && bb->last_ins->opcode == CEE_BLT && bb->last_ins->inst_left->inst_right->opcode == OP_ICONST) {
9840                                         if (try_unsigned_compare (cfg, bb)) {
9841                                                 /*g_print ("applied in bb %d (->%d) %s\n", bb->block_num, bb->last_ins->inst_target_bb->block_num, mono_method_full_name (cfg->method, TRUE));*/
9842                                                 changed = TRUE;
9843                                                 continue;
9844                                         }
9845                                 }
9846
9847                                 if (bb->last_ins && MONO_IS_COND_BRANCH_NOFP (bb->last_ins)) {
9848                                         if (bb->last_ins->inst_false_bb->out_of_line && (bb->region == bb->last_ins->inst_false_bb->region)) {
9849                                                 /* Reverse the branch */
9850                                                 bb->last_ins->opcode = reverse_branch_op (bb->last_ins->opcode);
9851                                                 bbn = bb->last_ins->inst_false_bb;
9852                                                 bb->last_ins->inst_false_bb = bb->last_ins->inst_true_bb;
9853                                                 bb->last_ins->inst_true_bb = bbn;
9854
9855                                                 move_basic_block_to_end (cfg, bb->last_ins->inst_true_bb);
9856                                                 if (cfg->verbose_level > 2)
9857                                                         g_print ("cbranch to throw block triggered %d.\n", 
9858                                                                          bb->block_num);
9859                                         }
9860                                 }
9861                         }
9862                 }
9863         } while (changed && (niterations > 0));
9864
9865 }
9866
9867 static void
9868 mono_compile_create_vars (MonoCompile *cfg)
9869 {
9870         MonoMethodSignature *sig;
9871         MonoMethodHeader *header;
9872         int i;
9873
9874         header = mono_method_get_header (cfg->method);
9875
9876         sig = mono_method_signature (cfg->method);
9877         
9878         if (!MONO_TYPE_IS_VOID (sig->ret)) {
9879                 cfg->ret = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst));
9880                 cfg->ret->opcode = OP_RETARG;
9881                 cfg->ret->inst_vtype = sig->ret;
9882                 cfg->ret->klass = mono_class_from_mono_type (sig->ret);
9883         }
9884         if (cfg->verbose_level > 2)
9885                 g_print ("creating vars\n");
9886
9887         cfg->args = mono_mempool_alloc0 (cfg->mempool, (sig->param_count + sig->hasthis) * sizeof (MonoInst*));
9888
9889         if (sig->hasthis)
9890                 cfg->args [0] = mono_compile_create_var (cfg, &cfg->method->klass->this_arg, OP_ARG);
9891
9892         for (i = 0; i < sig->param_count; ++i) {
9893                 cfg->args [i + sig->hasthis] = mono_compile_create_var (cfg, sig->params [i], OP_ARG);
9894                 if (sig->params [i]->byref) {
9895                         cfg->disable_ssa = TRUE;
9896                 }
9897         }
9898
9899         cfg->locals_start = cfg->num_varinfo;
9900
9901         if (cfg->verbose_level > 2)
9902                 g_print ("creating locals\n");
9903         for (i = 0; i < header->num_locals; ++i)
9904                 mono_compile_create_var (cfg, header->locals [i], OP_LOCAL);
9905         if (cfg->verbose_level > 2)
9906                 g_print ("locals done\n");
9907
9908 #ifdef MONO_ARCH_HAVE_CREATE_VARS
9909         mono_arch_create_vars (cfg);
9910 #endif
9911 }
9912
9913 void
9914 mono_print_code (MonoCompile *cfg)
9915 {
9916         MonoBasicBlock *bb;
9917         
9918         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
9919                 MonoInst *tree = bb->code;      
9920
9921                 if (!tree)
9922                         continue;
9923                 
9924                 g_print ("CODE BLOCK %d (nesting %d):\n", bb->block_num, bb->nesting);
9925
9926                 for (; tree; tree = tree->next) {
9927                         mono_print_tree (tree);
9928                         g_print ("\n");
9929                 }
9930
9931                 if (bb->last_ins)
9932                         bb->last_ins->next = NULL;
9933         }
9934 }
9935
9936 extern const char * const mono_burg_rule_string [];
9937
9938 static void
9939 emit_state (MonoCompile *cfg, MBState *state, int goal)
9940 {
9941         MBState *kids [10];
9942         int ern = mono_burg_rule (state, goal);
9943         const guint16 *nts = mono_burg_nts_data + mono_burg_nts [ern];
9944
9945         //g_print ("rule: %s\n", mono_burg_rule_string [ern]);
9946         switch (goal) {
9947         case MB_NTERM_reg:
9948                 //if (state->reg2)
9949                 //      state->reg1 = state->reg2; /* chain rule */
9950                 //else
9951 #ifdef MONO_ARCH_ENABLE_EMIT_STATE_OPT
9952                 if (!state->reg1)
9953 #endif
9954                         state->reg1 = mono_regstate_next_int (cfg->rs);
9955                 //g_print ("alloc symbolic R%d (reg2: R%d) in block %d\n", state->reg1, state->reg2, cfg->cbb->block_num);
9956                 break;
9957         case MB_NTERM_lreg:
9958                 state->reg1 = mono_regstate_next_int (cfg->rs);
9959                 state->reg2 = mono_regstate_next_int (cfg->rs);
9960                 break;
9961         case MB_NTERM_freg:
9962 #ifdef MONO_ARCH_SOFT_FLOAT
9963                 state->reg1 = mono_regstate_next_int (cfg->rs);
9964                 state->reg2 = mono_regstate_next_int (cfg->rs);
9965 #else
9966                 state->reg1 = mono_regstate_next_float (cfg->rs);
9967 #endif
9968                 break;
9969         default:
9970 #ifdef MONO_ARCH_ENABLE_EMIT_STATE_OPT
9971                 /*
9972                  * Enabling this might cause bugs to surface in the local register
9973                  * allocators on some architectures like x86.
9974                  */
9975                 if ((state->tree->ssa_op == MONO_SSA_STORE) && (state->left->tree->opcode == OP_REGVAR)) {
9976                         /* Do not optimize away reg-reg moves */
9977                         if (! ((state->right->tree->ssa_op == MONO_SSA_LOAD) && (state->right->left->tree->opcode == OP_REGVAR))) {
9978                                 state->right->reg1 = state->left->tree->dreg;
9979                         }
9980                 }
9981 #endif
9982
9983                 /* do nothing */
9984                 break;
9985         }
9986         if (nts [0]) {
9987                 mono_burg_kids (state, ern, kids);
9988
9989                 emit_state (cfg, kids [0], nts [0]);
9990                 if (nts [1]) {
9991                         emit_state (cfg, kids [1], nts [1]);
9992                         if (nts [2]) {
9993                                 g_assert (!nts [3]);
9994                                 emit_state (cfg, kids [2], nts [2]);
9995                         }
9996                 }
9997         }
9998
9999 //      g_print ("emit: %s (%p)\n", mono_burg_rule_string [ern], state);
10000         mono_burg_emit (ern, state, state->tree, cfg);
10001 }
10002
10003 #define DEBUG_SELECTION
10004
10005 static void 
10006 mini_select_instructions (MonoCompile *cfg)
10007 {
10008         MonoBasicBlock *bb;
10009         
10010         cfg->state_pool = mono_mempool_new ();
10011         cfg->rs = mono_regstate_new ();
10012
10013         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
10014                 if (bb->last_ins && MONO_IS_COND_BRANCH_OP (bb->last_ins) &&
10015                     bb->next_bb != bb->last_ins->inst_false_bb) {
10016
10017                         /* we are careful when inverting, since bugs like #59580
10018                          * could show up when dealing with NaNs.
10019                          */
10020                         if (MONO_IS_COND_BRANCH_NOFP(bb->last_ins) && bb->next_bb == bb->last_ins->inst_true_bb) {
10021                                 MonoBasicBlock *tmp =  bb->last_ins->inst_true_bb;
10022                                 bb->last_ins->inst_true_bb = bb->last_ins->inst_false_bb;
10023                                 bb->last_ins->inst_false_bb = tmp;
10024
10025                                 bb->last_ins->opcode = reverse_branch_op (bb->last_ins->opcode);
10026                         } else {                        
10027                                 MonoInst *inst = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst));
10028                                 inst->opcode = OP_BR;
10029                                 inst->inst_target_bb = bb->last_ins->inst_false_bb;
10030                                 mono_bblock_add_inst (bb, inst);
10031                         }
10032                 }
10033         }
10034
10035 #ifdef DEBUG_SELECTION
10036         if (cfg->verbose_level >= 4) {
10037         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
10038                 MonoInst *tree = bb->code;      
10039                 g_print ("DUMP BLOCK %d:\n", bb->block_num);
10040                 if (!tree)
10041                         continue;
10042                 for (; tree; tree = tree->next) {
10043                         mono_print_tree (tree);
10044                         g_print ("\n");
10045                 }
10046         }
10047         }
10048 #endif
10049
10050         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
10051                 MonoInst *tree = bb->code, *next;       
10052                 MBState *mbstate;
10053
10054                 if (!tree)
10055                         continue;
10056                 bb->code = NULL;
10057                 bb->last_ins = NULL;
10058                 
10059                 cfg->cbb = bb;
10060                 mono_regstate_reset (cfg->rs);
10061
10062 #ifdef DEBUG_SELECTION
10063                 if (cfg->verbose_level >= 3)
10064                         g_print ("LABEL BLOCK %d:\n", bb->block_num);
10065 #endif
10066                 for (; tree; tree = next) {
10067                         next = tree->next;
10068 #ifdef DEBUG_SELECTION
10069                         if (cfg->verbose_level >= 3) {
10070                                 mono_print_tree (tree);
10071                                 g_print ("\n");
10072                         }
10073 #endif
10074
10075                         if (!(mbstate = mono_burg_label (tree, cfg))) {
10076                                 g_warning ("unable to label tree %p", tree);
10077                                 mono_print_tree (tree);
10078                                 g_print ("\n");                         
10079                                 g_assert_not_reached ();
10080                         }
10081                         emit_state (cfg, mbstate, MB_NTERM_stmt);
10082                 }
10083                 bb->max_vreg = cfg->rs->next_vreg;
10084
10085                 if (bb->last_ins)
10086                         bb->last_ins->next = NULL;
10087
10088                 mono_mempool_empty (cfg->state_pool); 
10089         }
10090         mono_mempool_destroy (cfg->state_pool); 
10091 }
10092
10093 void
10094 mono_codegen (MonoCompile *cfg)
10095 {
10096         MonoJumpInfo *patch_info;
10097         MonoBasicBlock *bb;
10098         int i, max_epilog_size;
10099         guint8 *code;
10100
10101         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
10102                 cfg->spill_count = 0;
10103                 /* we reuse dfn here */
10104                 /* bb->dfn = bb_count++; */
10105                 mono_arch_local_regalloc (cfg, bb);
10106         }
10107
10108         if (cfg->prof_options & MONO_PROFILE_COVERAGE)
10109                 cfg->coverage_info = mono_profiler_coverage_alloc (cfg->method, cfg->num_bblocks);
10110
10111         code = mono_arch_emit_prolog (cfg);
10112
10113         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
10114                 code = mono_arch_instrument_prolog (cfg, mono_profiler_method_enter, code, FALSE);
10115
10116         cfg->code_len = code - cfg->native_code;
10117         cfg->prolog_end = cfg->code_len;
10118
10119         mono_debug_open_method (cfg);
10120
10121         /* emit code all basic blocks */
10122         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
10123                 bb->native_offset = cfg->code_len;
10124                 mono_arch_output_basic_block (cfg, bb);
10125
10126                 if (bb == cfg->bb_exit) {
10127                         cfg->epilog_begin = cfg->code_len;
10128
10129                         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE) {
10130                                 code = cfg->native_code + cfg->code_len;
10131                                 code = mono_arch_instrument_epilog (cfg, mono_profiler_method_leave, code, FALSE);
10132                                 cfg->code_len = code - cfg->native_code;
10133                                 g_assert (cfg->code_len < cfg->code_size);
10134                         }
10135
10136                         mono_arch_emit_epilog (cfg);
10137                 }
10138         }
10139
10140         mono_arch_emit_exceptions (cfg);
10141
10142         max_epilog_size = 0;
10143
10144         code = cfg->native_code + cfg->code_len;
10145
10146         /* we always allocate code in cfg->domain->code_mp to increase locality */
10147         cfg->code_size = cfg->code_len + max_epilog_size;
10148         /* fixme: align to MONO_ARCH_CODE_ALIGNMENT */
10149
10150         if (cfg->method->dynamic) {
10151                 /* Allocate the code into a separate memory pool so it can be freed */
10152                 cfg->dynamic_info = g_new0 (MonoJitDynamicMethodInfo, 1);
10153                 cfg->dynamic_info->code_mp = mono_code_manager_new_dynamic ();
10154                 mono_domain_lock (cfg->domain);
10155                 mono_dynamic_code_hash_insert (cfg->domain, cfg->method, cfg->dynamic_info);
10156                 mono_domain_unlock (cfg->domain);
10157
10158                 code = mono_code_manager_reserve (cfg->dynamic_info->code_mp, cfg->code_size);
10159         } else {
10160                 mono_domain_lock (cfg->domain);
10161                 code = mono_code_manager_reserve (cfg->domain->code_mp, cfg->code_size);
10162                 mono_domain_unlock (cfg->domain);
10163         }
10164
10165         memcpy (code, cfg->native_code, cfg->code_len);
10166         g_free (cfg->native_code);
10167         cfg->native_code = code;
10168         code = cfg->native_code + cfg->code_len;
10169   
10170         /* g_assert (((int)cfg->native_code & (MONO_ARCH_CODE_ALIGNMENT - 1)) == 0); */
10171         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
10172                 switch (patch_info->type) {
10173                 case MONO_PATCH_INFO_ABS: {
10174                         MonoJitICallInfo *info = mono_find_jit_icall_by_addr (patch_info->data.target);
10175                         if (info) {
10176                                 //printf ("TEST %s %p\n", info->name, patch_info->data.target);
10177                                 if ((cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) && 
10178                                         strstr (cfg->method->name, info->name))
10179                                         /*
10180                                          * This is an icall wrapper, and this is a call to the
10181                                          * wrapped function.
10182                                          */
10183                                         ;
10184                                 else {
10185                                         /* for these array methods we currently register the same function pointer
10186                                          * since it's a vararg function. But this means that mono_find_jit_icall_by_addr ()
10187                                          * will return the incorrect one depending on the order they are registered.
10188                                          * See tests/test-arr.cs
10189                                          */
10190                                         if (strstr (info->name, "ves_array_new_va_") == NULL && strstr (info->name, "ves_array_element_address_") == NULL) {
10191                                                 patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
10192                                                 patch_info->data.name = info->name;
10193                                         }
10194                                 }
10195                         }
10196                         else {
10197                                 MonoVTable *vtable = mono_find_class_init_trampoline_by_addr (patch_info->data.target);
10198                                 if (vtable) {
10199                                         patch_info->type = MONO_PATCH_INFO_CLASS_INIT;
10200                                         patch_info->data.klass = vtable->klass;
10201                                 }
10202                         }
10203                         break;
10204                 }
10205                 case MONO_PATCH_INFO_SWITCH: {
10206                         gpointer *table;
10207                         if (cfg->method->dynamic) {
10208                                 table = mono_code_manager_reserve (cfg->dynamic_info->code_mp, sizeof (gpointer) * patch_info->data.table->table_size);
10209                         } else {
10210                                 mono_domain_lock (cfg->domain);
10211                                 table = mono_code_manager_reserve (cfg->domain->code_mp, sizeof (gpointer) * patch_info->data.table->table_size);
10212                                 mono_domain_unlock (cfg->domain);
10213                         }
10214
10215                         if (!cfg->compile_aot)
10216                                 /* In the aot case, the patch already points to the correct location */
10217                                 patch_info->ip.i = patch_info->ip.label->inst_c0;
10218                         for (i = 0; i < patch_info->data.table->table_size; i++) {
10219                                 table [i] = GINT_TO_POINTER (patch_info->data.table->table [i]->native_offset);
10220                         }
10221                         patch_info->data.table->table = (MonoBasicBlock**)table;
10222                         break;
10223                 }
10224                 default:
10225                         /* do nothing */
10226                         break;
10227                 }
10228         }
10229
10230 #ifdef VALGRIND_JIT_REGISTER_MAP
10231 if (valgrind_register){
10232                 char* nm = mono_method_full_name (cfg->method, TRUE);
10233                 VALGRIND_JIT_REGISTER_MAP (nm, cfg->native_code, cfg->native_code + cfg->code_len);
10234                 g_free (nm);
10235         }
10236 #endif
10237  
10238         if (cfg->verbose_level > 0) {
10239                 char* nm = mono_method_full_name (cfg->method, TRUE);
10240                 g_print ("Method %s emitted at %p to %p (code length %d) [%s]\n", 
10241                                  nm, 
10242                                  cfg->native_code, cfg->native_code + cfg->code_len, cfg->code_len, cfg->domain->friendly_name);
10243                 g_free (nm);
10244         }
10245
10246 #ifdef MONO_ARCH_HAVE_SAVE_UNWIND_INFO
10247         mono_arch_save_unwind_info (cfg);
10248 #endif
10249         
10250         mono_arch_patch_code (cfg->method, cfg->domain, cfg->native_code, cfg->patch_info, cfg->run_cctors);
10251
10252         if (cfg->method->dynamic) {
10253                 mono_code_manager_commit (cfg->dynamic_info->code_mp, cfg->native_code, cfg->code_size, cfg->code_len);
10254         } else {
10255                 mono_domain_lock (cfg->domain);
10256                 mono_code_manager_commit (cfg->domain->code_mp, cfg->native_code, cfg->code_size, cfg->code_len);
10257                 mono_domain_unlock (cfg->domain);
10258         }
10259         
10260         mono_arch_flush_icache (cfg->native_code, cfg->code_len);
10261
10262         mono_debug_close_method (cfg);
10263 }
10264
10265
10266
10267 static void
10268 remove_critical_edges (MonoCompile *cfg) {
10269         MonoBasicBlock *bb;
10270         MonoBasicBlock *previous_bb;
10271         
10272         if (cfg->verbose_level > 3) {
10273                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
10274                         int i;
10275                         printf ("remove_critical_edges %s, BEFORE BB%d (in:", mono_method_full_name (cfg->method, TRUE), bb->block_num);
10276                         for (i = 0; i < bb->in_count; i++) {
10277                                 printf (" %d", bb->in_bb [i]->block_num);
10278                         }
10279                         printf (") (out:");
10280                         for (i = 0; i < bb->out_count; i++) {
10281                                 printf (" %d", bb->out_bb [i]->block_num);
10282                         }
10283                         printf (")");
10284                         if (bb->last_ins != NULL) {
10285                                 printf (" ");
10286                                 mono_print_tree (bb->last_ins);
10287                         }
10288                         printf ("\n");
10289                 }
10290         }
10291         
10292         for (previous_bb = cfg->bb_entry, bb = previous_bb->next_bb; bb != NULL; previous_bb = previous_bb->next_bb, bb = bb->next_bb) {
10293                 if (bb->in_count > 1) {
10294                         int in_bb_index;
10295                         for (in_bb_index = 0; in_bb_index < bb->in_count; in_bb_index++) {
10296                                 MonoBasicBlock *in_bb = bb->in_bb [in_bb_index];
10297                                 if (in_bb->out_count > 1) {
10298                                         MonoBasicBlock *new_bb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
10299                                         new_bb->block_num = cfg->num_bblocks++;
10300 //                                      new_bb->real_offset = bb->real_offset;
10301                                         new_bb->region = bb->region;
10302                                         
10303                                         /* Do not alter the CFG while altering the BB list */
10304                                         if (previous_bb->region == bb->region) {
10305                                                 if (previous_bb != cfg->bb_entry) {
10306                                                         /* If previous_bb "followed through" to bb, */
10307                                                         /* keep it linked with a OP_BR */
10308                                                         if ((previous_bb->last_ins == NULL) ||
10309                                                                         ((previous_bb->last_ins->opcode != OP_BR) &&
10310                                                                         (! (MONO_IS_COND_BRANCH_OP (previous_bb->last_ins))) &&
10311                                                                         (previous_bb->last_ins->opcode != CEE_SWITCH))) {
10312                                                                 int i;
10313                                                                 /* Make sure previous_bb really falls through bb */
10314                                                                 for (i = 0; i < previous_bb->out_count; i++) {
10315                                                                         if (previous_bb->out_bb [i] == bb) {
10316                                                                                 MonoInst *jump;
10317                                                                                 MONO_INST_NEW (cfg, jump, OP_BR);
10318                                                                                 MONO_ADD_INS (previous_bb, jump);
10319                                                                                 jump->cil_code = previous_bb->cil_code;
10320                                                                                 jump->inst_target_bb = bb;
10321                                                                                 break;
10322                                                                         }
10323                                                                 }
10324                                                         }
10325                                                 } else {
10326                                                         /* We cannot add any inst to the entry BB, so we must */
10327                                                         /* put a new BB in the middle to hold the OP_BR */
10328                                                         MonoInst *jump;
10329                                                         MonoBasicBlock *new_bb_after_entry = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
10330                                                         new_bb_after_entry->block_num = cfg->num_bblocks++;
10331 //                                                      new_bb_after_entry->real_offset = bb->real_offset;
10332                                                         new_bb_after_entry->region = bb->region;
10333                                                         
10334                                                         MONO_INST_NEW (cfg, jump, OP_BR);
10335                                                         MONO_ADD_INS (new_bb_after_entry, jump);
10336                                                         jump->cil_code = bb->cil_code;
10337                                                         jump->inst_target_bb = bb;
10338                                                         
10339                                                         previous_bb->next_bb = new_bb_after_entry;
10340                                                         previous_bb = new_bb_after_entry;
10341                                                         
10342                                                         if (cfg->verbose_level > 2) {
10343                                                                 printf ("remove_critical_edges %s, added helper BB%d jumping to BB%d\n", mono_method_full_name (cfg->method, TRUE), new_bb_after_entry->block_num, bb->block_num);
10344                                                         }
10345                                                 }
10346                                         }
10347                                         
10348                                         /* Insert new_bb in the BB list */
10349                                         previous_bb->next_bb = new_bb;
10350                                         new_bb->next_bb = bb;
10351                                         previous_bb = new_bb;
10352                                         
10353                                         /* Setup in_bb and out_bb */
10354                                         new_bb->in_bb = mono_mempool_alloc ((cfg)->mempool, sizeof (MonoBasicBlock*));
10355                                         new_bb->in_bb [0] = in_bb;
10356                                         new_bb->in_count = 1;
10357                                         new_bb->out_bb = mono_mempool_alloc ((cfg)->mempool, sizeof (MonoBasicBlock*));
10358                                         new_bb->out_bb [0] = bb;
10359                                         new_bb->out_count = 1;
10360                                         
10361                                         /* Relink in_bb and bb to (from) new_bb */
10362                                         replace_out_block (in_bb, bb, new_bb);
10363                                         replace_out_block_in_code (in_bb, bb, new_bb);
10364                                         replace_in_block (bb, in_bb, new_bb);
10365                                         
10366                                         if (cfg->verbose_level > 2) {
10367                                                 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), in_bb->block_num, bb->block_num, new_bb->block_num);
10368                                         }
10369                                 }
10370                         }
10371                 }
10372         }
10373         
10374         if (cfg->verbose_level > 3) {
10375                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
10376                         int i;
10377                         printf ("remove_critical_edges %s, AFTER BB%d (in:", mono_method_full_name (cfg->method, TRUE), bb->block_num);
10378                         for (i = 0; i < bb->in_count; i++) {
10379                                 printf (" %d", bb->in_bb [i]->block_num);
10380                         }
10381                         printf (") (out:");
10382                         for (i = 0; i < bb->out_count; i++) {
10383                                 printf (" %d", bb->out_bb [i]->block_num);
10384                         }
10385                         printf (")");
10386                         if (bb->last_ins != NULL) {
10387                                 printf (" ");
10388                                 mono_print_tree (bb->last_ins);
10389                         }
10390                         printf ("\n");
10391                 }
10392         }
10393 }
10394
10395 /*
10396  * mini_method_compile:
10397  * @method: the method to compile
10398  * @opts: the optimization flags to use
10399  * @domain: the domain where the method will be compiled in
10400  * @run_cctors: whether we should run type ctors if possible
10401  * @compile_aot: whether this is an AOT compilation
10402  * @parts: debug flag
10403  *
10404  * Returns: a MonoCompile* pointer. Caller must check the exception_type
10405  * field in the returned struct to see if compilation succeded.
10406  */
10407 MonoCompile*
10408 mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gboolean run_cctors, gboolean compile_aot, int parts)
10409 {
10410         MonoMethodHeader *header = mono_method_get_header (method);
10411         guint8 *ip;
10412         MonoCompile *cfg;
10413         MonoJitInfo *jinfo;
10414         int dfn = 0, i, code_size_ratio;
10415         gboolean deadce_has_run = FALSE;
10416
10417         mono_jit_stats.methods_compiled++;
10418         if (mono_profiler_get_events () & MONO_PROFILE_JIT_COMPILATION)
10419                 mono_profiler_method_jit (method);
10420
10421         cfg = g_new0 (MonoCompile, 1);
10422         cfg->method = method;
10423         cfg->mempool = mono_mempool_new ();
10424         cfg->opt = opts;
10425         cfg->prof_options = mono_profiler_get_events ();
10426         cfg->run_cctors = run_cctors;
10427         cfg->domain = domain;
10428         cfg->verbose_level = mini_verbose;
10429         cfg->compile_aot = compile_aot;
10430         cfg->skip_visibility = method->skip_visibility;
10431         cfg->token_info_hash = g_hash_table_new (NULL, NULL);
10432         if (!header) {
10433                 cfg->exception_type = MONO_EXCEPTION_INVALID_PROGRAM;
10434                 cfg->exception_message = g_strdup_printf ("Missing or incorrect header for method %s", cfg->method->name);
10435                 if (cfg->prof_options & MONO_PROFILE_JIT_COMPILATION)
10436                         mono_profiler_method_end_jit (method, NULL, MONO_PROFILE_FAILED);
10437                 return cfg;
10438         }
10439
10440         ip = (guint8 *)header->code;
10441
10442         cfg->intvars = mono_mempool_alloc0 (cfg->mempool, sizeof (guint16) * STACK_MAX * header->max_stack);
10443         cfg->aliasing_info = NULL;
10444         
10445         if (cfg->verbose_level > 2)
10446                 g_print ("converting method %s\n", mono_method_full_name (method, TRUE));
10447
10448         /*
10449          * create MonoInst* which represents arguments and local variables
10450          */
10451         mono_compile_create_vars (cfg);
10452
10453         if ((i = mono_method_to_ir (cfg, method, NULL, NULL, cfg->locals_start, NULL, NULL, NULL, 0, FALSE)) < 0) {
10454                 if (cfg->prof_options & MONO_PROFILE_JIT_COMPILATION)
10455                         mono_profiler_method_end_jit (method, NULL, MONO_PROFILE_FAILED);
10456                 /* cfg contains the details of the failure, so let the caller cleanup */
10457                 return cfg;
10458         }
10459
10460         mono_jit_stats.basic_blocks += cfg->num_bblocks;
10461         mono_jit_stats.max_basic_blocks = MAX (cfg->num_bblocks, mono_jit_stats.max_basic_blocks);
10462
10463         if ((cfg->num_varinfo > 2000) && !cfg->compile_aot) {
10464                 /* 
10465                  * we disable some optimizations if there are too many variables
10466                  * because JIT time may become too expensive. The actual number needs 
10467                  * to be tweaked and eventually the non-linear algorithms should be fixed.
10468                  */
10469                 cfg->opt &= ~ (MONO_OPT_LINEARS | MONO_OPT_COPYPROP | MONO_OPT_CONSPROP);
10470                 cfg->disable_ssa = TRUE;
10471         }
10472
10473         /*g_print ("numblocks = %d\n", cfg->num_bblocks);*/
10474
10475         if (cfg->opt & MONO_OPT_BRANCH)
10476                 optimize_branches (cfg);
10477
10478         if (cfg->opt & MONO_OPT_SSAPRE) {
10479                 remove_critical_edges (cfg);
10480         }
10481
10482         /* Depth-first ordering on basic blocks */
10483         cfg->bblocks = mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * (cfg->num_bblocks + 1));
10484
10485         df_visit (cfg->bb_entry, &dfn, cfg->bblocks);
10486         if (cfg->num_bblocks != dfn + 1) {
10487                 MonoBasicBlock *bb;
10488
10489                 cfg->num_bblocks = dfn + 1;
10490
10491                 if (!header->clauses) {
10492                         /* remove unreachable code, because the code in them may be 
10493                          * inconsistent  (access to dead variables for example) */
10494                         for (bb = cfg->bb_entry; bb;) {
10495                                 MonoBasicBlock *bbn = bb->next_bb;
10496
10497                                 if (bbn && bbn->region == -1 && !bbn->dfn) {
10498                                         if (cfg->verbose_level > 1)
10499                                                 g_print ("found unreachable code in BB%d\n", bbn->block_num);
10500                                         bb->next_bb = bbn->next_bb;
10501                                         nullify_basic_block (bbn);                      
10502                                 } else {
10503                                         bb = bb->next_bb;
10504                                 }
10505                         }
10506                 }
10507         }
10508
10509         if (cfg->opt & MONO_OPT_LOOP) {
10510                 mono_compile_dominator_info (cfg, MONO_COMP_DOM | MONO_COMP_IDOM);
10511                 mono_compute_natural_loops (cfg);
10512         }
10513
10514         /* after method_to_ir */
10515         if (parts == 1)
10516                 return cfg;
10517
10518 //#define DEBUGSSA "logic_run"
10519 #define DEBUGSSA_CLASS "Tests"
10520 #ifdef DEBUGSSA
10521
10522         if (!header->num_clauses && !cfg->disable_ssa) {
10523                 mono_local_cprop (cfg);
10524                 mono_ssa_compute (cfg);
10525         }
10526 #else 
10527
10528         /* fixme: add all optimizations which requires SSA */
10529         if (cfg->opt & (MONO_OPT_SSA | MONO_OPT_ABCREM | MONO_OPT_SSAPRE)) {
10530                 if (!(cfg->comp_done & MONO_COMP_SSA) && !header->num_clauses && !cfg->disable_ssa) {
10531                         mono_local_cprop (cfg);
10532                         mono_ssa_compute (cfg);
10533
10534                         if (cfg->verbose_level >= 2) {
10535                                 print_dfn (cfg);
10536                         }
10537                 }
10538         }
10539 #endif
10540
10541         /* after SSA translation */
10542         if (parts == 2)
10543                 return cfg;
10544
10545         if ((cfg->opt & MONO_OPT_CONSPROP) || (cfg->opt & MONO_OPT_COPYPROP)) {
10546                 if (cfg->comp_done & MONO_COMP_SSA) {
10547                         mono_ssa_cprop (cfg);
10548                 } else {
10549                         mono_local_cprop (cfg);
10550                 }
10551         }
10552
10553         if (cfg->comp_done & MONO_COMP_SSA) {                   
10554                 //mono_ssa_deadce (cfg);
10555
10556                 //mono_ssa_strength_reduction (cfg);
10557
10558                 if (cfg->opt & MONO_OPT_SSAPRE) {
10559                         mono_perform_ssapre (cfg);
10560                         //mono_local_cprop (cfg);
10561                 }
10562                 
10563                 if (cfg->opt & MONO_OPT_DEADCE) {
10564                         mono_ssa_deadce (cfg);
10565                         deadce_has_run = TRUE;
10566                 }
10567                 
10568                 if ((cfg->flags & MONO_CFG_HAS_LDELEMA) && (cfg->opt & MONO_OPT_ABCREM))
10569                         mono_perform_abc_removal (cfg);
10570                 
10571                 mono_ssa_remove (cfg);
10572
10573                 if (cfg->opt & MONO_OPT_BRANCH)
10574                         optimize_branches (cfg);
10575         }
10576
10577         /* after SSA removal */
10578         if (parts == 3)
10579                 return cfg;
10580
10581         if (cfg->verbose_level > 4) {
10582                 printf ("BEFORE DECOMPSE START\n");
10583                 mono_print_code (cfg);
10584                 printf ("BEFORE DECOMPSE END\n");
10585         }
10586         
10587         decompose_pass (cfg);
10588
10589         if (cfg->got_var) {
10590                 GList *regs;
10591
10592                 g_assert (cfg->got_var_allocated);
10593
10594                 /* 
10595                  * Allways allocate the GOT var to a register, because keeping it
10596                  * in memory will increase the number of live temporaries in some
10597                  * code created by inssel.brg, leading to the well known spills+
10598                  * branches problem. Testcase: mcs crash in 
10599                  * System.MonoCustomAttrs:GetCustomAttributes.
10600                  */
10601                 regs = mono_arch_get_global_int_regs (cfg);
10602                 g_assert (regs);
10603                 cfg->got_var->opcode = OP_REGVAR;
10604                 cfg->got_var->dreg = GPOINTER_TO_INT (regs->data);
10605                 cfg->used_int_regs |= 1LL << cfg->got_var->dreg;
10606                 
10607                 g_list_free (regs);
10608         }
10609
10610         /* todo: remove code when we have verified that the liveness for try/catch blocks
10611          * works perfectly 
10612          */
10613         /* 
10614          * Currently, this can't be commented out since exception blocks are not
10615          * processed during liveness analysis.
10616          */
10617         mono_liveness_handle_exception_clauses (cfg);
10618
10619         if (cfg->opt & MONO_OPT_LINEARS) {
10620                 GList *vars, *regs;
10621                 
10622                 /* For now, compute aliasing info only if needed for deadce... */
10623                 if ((cfg->opt & MONO_OPT_DEADCE) && (! deadce_has_run) && (header->num_clauses == 0)) {
10624                         cfg->aliasing_info = mono_build_aliasing_information (cfg);
10625                 }
10626
10627                 /* fixme: maybe we can avoid to compute livenesss here if already computed ? */
10628                 cfg->comp_done &= ~MONO_COMP_LIVENESS;
10629                 if (!(cfg->comp_done & MONO_COMP_LIVENESS))
10630                         mono_analyze_liveness (cfg);
10631
10632                 if (cfg->aliasing_info != NULL) {
10633                         mono_aliasing_deadce (cfg->aliasing_info);
10634                         deadce_has_run = TRUE;
10635                 }
10636                 
10637                 if ((vars = mono_arch_get_allocatable_int_vars (cfg))) {
10638                         regs = mono_arch_get_global_int_regs (cfg);
10639                         if (cfg->got_var)
10640                                 regs = g_list_delete_link (regs, regs);
10641                         mono_linear_scan (cfg, vars, regs, &cfg->used_int_regs);
10642                 }
10643                 
10644                 if (cfg->aliasing_info != NULL) {
10645                         mono_destroy_aliasing_information (cfg->aliasing_info);
10646                         cfg->aliasing_info = NULL;
10647                 }
10648         }
10649
10650         //mono_print_code (cfg);
10651
10652     //print_dfn (cfg);
10653         
10654         /* variables are allocated after decompose, since decompose could create temps */
10655         mono_arch_allocate_vars (cfg);
10656
10657         if (cfg->opt & MONO_OPT_CFOLD)
10658                 mono_constant_fold (cfg);
10659
10660         mini_select_instructions (cfg);
10661
10662         mono_codegen (cfg);
10663         if (cfg->verbose_level >= 2) {
10664                 char *id =  mono_method_full_name (cfg->method, FALSE);
10665                 mono_disassemble_code (cfg, cfg->native_code, cfg->code_len, id + 3);
10666                 g_free (id);
10667         }
10668         
10669         if (cfg->method->dynamic) {
10670                 jinfo = g_malloc0 (sizeof (MonoJitInfo) + (header->num_clauses * sizeof (MonoJitExceptionInfo)));
10671         } else {
10672                 /* we access cfg->domain->mp */
10673                 mono_domain_lock (cfg->domain);
10674                 jinfo = mono_mempool_alloc0 (cfg->domain->mp, sizeof (MonoJitInfo) + (header->num_clauses * sizeof (MonoJitExceptionInfo)));
10675                 mono_domain_unlock (cfg->domain);
10676         }
10677
10678         jinfo->method = method;
10679         jinfo->code_start = cfg->native_code;
10680         jinfo->code_size = cfg->code_len;
10681         jinfo->used_regs = cfg->used_int_regs;
10682         jinfo->domain_neutral = (cfg->opt & MONO_OPT_SHARED) != 0;
10683         jinfo->cas_inited = FALSE; /* initialization delayed at the first stalk walk using this method */
10684
10685         if (header->num_clauses) {
10686                 int i;
10687
10688                 jinfo->num_clauses = header->num_clauses;
10689
10690                 for (i = 0; i < header->num_clauses; i++) {
10691                         MonoExceptionClause *ec = &header->clauses [i];
10692                         MonoJitExceptionInfo *ei = &jinfo->clauses [i];
10693                         MonoBasicBlock *tblock;
10694                         MonoInst *exvar;
10695
10696                         ei->flags = ec->flags;
10697
10698                         exvar = mono_find_exvar_for_offset (cfg, ec->handler_offset);
10699                         ei->exvar_offset = exvar ? exvar->inst_offset : 0;
10700
10701                         if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
10702                                 tblock = cfg->cil_offset_to_bb [ec->data.filter_offset];
10703                                 g_assert (tblock);
10704                                 ei->data.filter = cfg->native_code + tblock->native_offset;
10705                         } else {
10706                                 ei->data.catch_class = ec->data.catch_class;
10707                         }
10708
10709                         tblock = cfg->cil_offset_to_bb [ec->try_offset];
10710                         g_assert (tblock);
10711                         ei->try_start = cfg->native_code + tblock->native_offset;
10712                         g_assert (tblock->native_offset);
10713                         tblock = cfg->cil_offset_to_bb [ec->try_offset + ec->try_len];
10714                         g_assert (tblock);
10715                         ei->try_end = cfg->native_code + tblock->native_offset;
10716                         g_assert (tblock->native_offset);
10717                         tblock = cfg->cil_offset_to_bb [ec->handler_offset];
10718                         g_assert (tblock);
10719                         ei->handler_start = cfg->native_code + tblock->native_offset;
10720                 }
10721         }
10722
10723         cfg->jit_info = jinfo;
10724 #if defined(__arm__)
10725         mono_arch_fixup_jinfo (cfg);
10726 #endif
10727
10728         mono_domain_lock (cfg->domain);
10729         mono_jit_info_table_add (cfg->domain, jinfo);
10730
10731         if (cfg->method->dynamic)
10732                 mono_dynamic_code_hash_lookup (cfg->domain, cfg->method)->ji = jinfo;
10733         mono_domain_unlock (cfg->domain);
10734
10735         /* collect statistics */
10736         mono_jit_stats.allocated_code_size += cfg->code_len;
10737         code_size_ratio = cfg->code_len;
10738         if (code_size_ratio > mono_jit_stats.biggest_method_size) {
10739                         mono_jit_stats.biggest_method_size = code_size_ratio;
10740                         mono_jit_stats.biggest_method = method;
10741         }
10742         code_size_ratio = (code_size_ratio * 100) / mono_method_get_header (method)->code_size;
10743         if (code_size_ratio > mono_jit_stats.max_code_size_ratio) {
10744                 mono_jit_stats.max_code_size_ratio = code_size_ratio;
10745                 mono_jit_stats.max_ratio_method = method;
10746         }
10747         mono_jit_stats.native_code_size += cfg->code_len;
10748
10749         if (cfg->prof_options & MONO_PROFILE_JIT_COMPILATION)
10750                 mono_profiler_method_end_jit (method, jinfo, MONO_PROFILE_OK);
10751
10752         return cfg;
10753 }
10754
10755 static gpointer
10756 mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, int opt)
10757 {
10758         MonoCompile *cfg;
10759         gpointer code = NULL;
10760         MonoJitInfo *info;
10761
10762 #ifdef MONO_USE_AOT_COMPILER
10763         if ((opt & MONO_OPT_AOT) && !(mono_profiler_get_events () & MONO_PROFILE_JIT_COMPILATION)) {
10764                 MonoDomain *domain = mono_domain_get ();
10765
10766                 mono_class_init (method->klass);
10767
10768                 mono_domain_lock (domain);
10769                 if ((code = mono_aot_get_method (domain, method))) {
10770                         mono_domain_unlock (domain);
10771                         mono_runtime_class_init (mono_class_vtable (domain, method->klass));
10772                         return code;
10773                 }
10774
10775                 mono_domain_unlock (domain);
10776         }
10777 #endif
10778
10779         if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
10780             (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
10781                 MonoMethod *nm;
10782                 MonoMethodPInvoke* piinfo = (MonoMethodPInvoke *) method;
10783
10784                 if (method->iflags & METHOD_IMPL_ATTRIBUTE_NATIVE && !MONO_CLASS_IS_IMPORT(method->klass))
10785                         g_error ("Method '%s' in assembly '%s' contains native code and mono can't run it. The assembly was probably created by Managed C++.\n", mono_method_full_name (method, TRUE), method->klass->image->name);
10786
10787                 if (!piinfo->addr) {
10788                         if (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL)
10789                                 piinfo->addr = mono_lookup_internal_call (method);
10790                         else
10791                                 if (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
10792                                         mono_lookup_pinvoke_call (method, NULL, NULL);
10793                 }
10794                         nm = mono_marshal_get_native_wrapper (method);
10795                         return mono_get_addr_from_ftnptr (mono_compile_method (nm));
10796
10797                         //if (mono_debug_format != MONO_DEBUG_FORMAT_NONE) 
10798                         //mono_debug_add_wrapper (method, nm);
10799         } else if ((method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME)) {
10800                 const char *name = method->name;
10801                 MonoMethod *nm;
10802
10803                 if (method->klass->parent == mono_defaults.multicastdelegate_class) {
10804                         if (*name == '.' && (strcmp (name, ".ctor") == 0)) {
10805                                 MonoJitICallInfo *mi = mono_find_jit_icall_by_name ("mono_delegate_ctor");
10806                                 g_assert (mi);
10807                                 return mono_get_addr_from_ftnptr ((gpointer)mono_icall_get_wrapper (mi));
10808                         } else if (*name == 'I' && (strcmp (name, "Invoke") == 0)) {
10809                                 nm = mono_marshal_get_delegate_invoke (method);
10810                                         return mono_get_addr_from_ftnptr (mono_compile_method (nm));
10811                         } else if (*name == 'B' && (strcmp (name, "BeginInvoke") == 0)) {
10812                                 nm = mono_marshal_get_delegate_begin_invoke (method);
10813                                 return mono_get_addr_from_ftnptr (mono_compile_method (nm));
10814                         } else if (*name == 'E' && (strcmp (name, "EndInvoke") == 0)) {
10815                                 nm = mono_marshal_get_delegate_end_invoke (method);
10816                                 return mono_get_addr_from_ftnptr (mono_compile_method (nm));
10817                         }
10818                 }
10819                 return NULL;
10820         }
10821
10822         cfg = mini_method_compile (method, opt, target_domain, TRUE, FALSE, 0);
10823
10824         switch (cfg->exception_type) {
10825         case MONO_EXCEPTION_NONE: break;
10826         case MONO_EXCEPTION_TYPE_LOAD:
10827         case MONO_EXCEPTION_MISSING_FIELD:
10828         case MONO_EXCEPTION_MISSING_METHOD:
10829         case MONO_EXCEPTION_FILE_NOT_FOUND: {
10830                 /* Throw a type load exception if needed */
10831                 MonoLoaderError *error = mono_loader_get_last_error ();
10832                 MonoException *ex;
10833
10834                 if (error) {
10835                         ex = mono_loader_error_prepare_exception (error);
10836                 } else {
10837                         if (cfg->exception_ptr) {
10838                                 ex = mono_class_get_exception_for_failure (cfg->exception_ptr);
10839                         } else {
10840                                 if (cfg->exception_type == MONO_EXCEPTION_MISSING_FIELD)
10841                                         ex = mono_exception_from_name_msg (mono_defaults.corlib, "System", "MissingFieldException", cfg->exception_message);
10842                                 else if (cfg->exception_type == MONO_EXCEPTION_MISSING_METHOD)
10843                                         ex = mono_exception_from_name_msg (mono_defaults.corlib, "System", "MissingMethodException", cfg->exception_message);
10844                                 else if (cfg->exception_type == MONO_EXCEPTION_TYPE_LOAD)
10845                                         ex = mono_exception_from_name_msg (mono_defaults.corlib, "System", "TypeLoadException", cfg->exception_message);
10846                                 else if (cfg->exception_type == MONO_EXCEPTION_FILE_NOT_FOUND)
10847                                         ex = mono_exception_from_name_msg (mono_defaults.corlib, "System", "FileNotFoundException", cfg->exception_message);
10848                                 else
10849                                         g_assert_not_reached ();
10850                         }
10851                 }
10852                 mono_destroy_compile (cfg);
10853                 mono_raise_exception (ex);
10854                 break;
10855         }
10856         case MONO_EXCEPTION_INVALID_PROGRAM: {
10857                 MonoException *ex = mono_exception_from_name_msg (mono_defaults.corlib, "System", "InvalidProgramException", cfg->exception_message);
10858                 mono_destroy_compile (cfg);
10859                 mono_raise_exception (ex);
10860                 break;
10861         }
10862         case MONO_EXCEPTION_UNVERIFIABLE_IL: {
10863                 MonoException *ex = mono_exception_from_name_msg (mono_defaults.corlib, "System.Security", "VerificationException", cfg->exception_message);
10864                 mono_destroy_compile (cfg);
10865                 mono_raise_exception (ex);
10866                 break;
10867         }
10868         /* this can only be set if the security manager is active */
10869         case MONO_EXCEPTION_SECURITY_LINKDEMAND: {
10870                 MonoAssembly *assembly = mono_image_get_assembly (method->klass->image);
10871                 MonoReflectionAssembly *refass = (MonoReflectionAssembly*) mono_assembly_get_object (target_domain, assembly);
10872                 MonoReflectionMethod *refmet = mono_method_get_object (target_domain, method, NULL);
10873                 MonoSecurityManager* secman = mono_security_manager_get_methods ();
10874                 MonoObject *exc = NULL;
10875                 gpointer args [3];
10876
10877                 args [0] = &cfg->exception_data;
10878                 args [1] = refass;
10879                 args [2] = refmet;
10880                 mono_runtime_invoke (secman->linkdemandsecurityexception, NULL, args, &exc);
10881
10882                 mono_destroy_compile (cfg);
10883                 cfg = NULL;
10884
10885                 mono_raise_exception ((MonoException*)exc);
10886         }
10887         default:
10888                 g_assert_not_reached ();
10889         }
10890
10891         mono_domain_lock (target_domain);
10892
10893         /* Check if some other thread already did the job. In this case, we can
10894        discard the code this thread generated. */
10895
10896         if ((info = mono_internal_hash_table_lookup (&target_domain->jit_code_hash, method))) {
10897                 /* We can't use a domain specific method in another domain */
10898                 if ((target_domain == mono_domain_get ()) || info->domain_neutral) {
10899                         code = info->code_start;
10900 //                      printf("Discarding code for method %s\n", method->name);
10901                 }
10902         }
10903         
10904         if (code == NULL) {
10905                 mono_internal_hash_table_insert (&target_domain->jit_code_hash, method, cfg->jit_info);
10906                 code = cfg->native_code;
10907         }
10908
10909         mono_destroy_compile (cfg);
10910
10911         if (target_domain->jump_target_hash) {
10912                 MonoJumpInfo patch_info;
10913                 GSList *list, *tmp;
10914                 list = g_hash_table_lookup (target_domain->jump_target_hash, method);
10915                 if (list) {
10916                         patch_info.next = NULL;
10917                         patch_info.ip.i = 0;
10918                         patch_info.type = MONO_PATCH_INFO_METHOD_JUMP;
10919                         patch_info.data.method = method;
10920                         g_hash_table_remove (target_domain->jump_target_hash, method);
10921                 }
10922                 for (tmp = list; tmp; tmp = tmp->next)
10923                         mono_arch_patch_code (NULL, target_domain, tmp->data, &patch_info, TRUE);
10924                 g_slist_free (list);
10925         }
10926
10927         mono_domain_unlock (target_domain);
10928
10929         mono_runtime_class_init (mono_class_vtable (target_domain, method->klass));
10930         return code;
10931 }
10932
10933 static gpointer
10934 mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt)
10935 {
10936         MonoDomain *target_domain, *domain = mono_domain_get ();
10937         MonoJitInfo *info;
10938         gpointer p;
10939         MonoJitICallInfo *callinfo = NULL;
10940
10941         /*
10942          * ICALL wrappers are handled specially, since there is only one copy of them
10943          * shared by all appdomains.
10944          */
10945         if ((method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) && (strstr (method->name, "__icall_wrapper_") == method->name)) {
10946                 const char *icall_name;
10947
10948                 icall_name = method->name + strlen ("__icall_wrapper_");
10949                 g_assert (icall_name);
10950                 callinfo = mono_find_jit_icall_by_name (icall_name);
10951                 g_assert (callinfo);
10952
10953                 /* Must be domain neutral since there is only one copy */
10954                 opt |= MONO_OPT_SHARED;
10955         }
10956
10957         if (opt & MONO_OPT_SHARED)
10958                 target_domain = mono_get_root_domain ();
10959         else 
10960                 target_domain = domain;
10961
10962         mono_domain_lock (target_domain);
10963
10964         if ((info = mono_internal_hash_table_lookup (&target_domain->jit_code_hash, method))) {
10965                 /* We can't use a domain specific method in another domain */
10966                 if (! ((domain != target_domain) && !info->domain_neutral)) {
10967                         mono_domain_unlock (target_domain);
10968                         mono_jit_stats.methods_lookups++;
10969                         mono_runtime_class_init (mono_class_vtable (domain, method->klass));
10970                         return mono_create_ftnptr (target_domain, info->code_start);
10971                 }
10972         }
10973
10974         mono_domain_unlock (target_domain);
10975         p = mono_create_ftnptr (target_domain, mono_jit_compile_method_inner (method, target_domain, opt));
10976
10977         if (callinfo) {
10978                 mono_jit_lock ();
10979                 if (!callinfo->wrapper) {
10980                         callinfo->wrapper = p;
10981                         mono_register_jit_icall_wrapper (callinfo, p);
10982                         mono_debug_add_icall_wrapper (method, callinfo);
10983                 }
10984                 mono_jit_unlock ();
10985         }
10986
10987         return p;
10988 }
10989
10990 static gpointer
10991 mono_jit_compile_method (MonoMethod *method)
10992 {
10993         return mono_jit_compile_method_with_opt (method, default_opt);
10994 }
10995
10996 static void
10997 invalidated_delegate_trampoline (char *desc)
10998 {
10999         g_error ("Unmanaged code called delegate of type %s which was already garbage collected.\n"
11000                  "See http://www.go-mono.com/delegate.html for an explanation and ways to fix this.",
11001                  desc);
11002 }
11003
11004 /*
11005  * mono_jit_free_method:
11006  *
11007  *  Free all memory allocated by the JIT for METHOD.
11008  */
11009 static void
11010 mono_jit_free_method (MonoDomain *domain, MonoMethod *method)
11011 {
11012         MonoJitDynamicMethodInfo *ji;
11013         gboolean destroy = TRUE;
11014
11015         g_assert (method->dynamic);
11016
11017         mono_domain_lock (domain);
11018         ji = mono_dynamic_code_hash_lookup (domain, method);
11019         mono_domain_unlock (domain);
11020
11021         if (!ji)
11022                 return;
11023         mono_domain_lock (domain);
11024         g_hash_table_remove (domain->dynamic_code_hash, method);
11025         mono_internal_hash_table_remove (&domain->jit_code_hash, method);
11026         g_hash_table_remove (domain->jump_trampoline_hash, method);
11027         mono_domain_unlock (domain);
11028
11029 #ifdef MONO_ARCH_HAVE_INVALIDATE_METHOD
11030         if (debug_options.keep_delegates && method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
11031                 /*
11032                  * Instead of freeing the code, change it to call an error routine
11033                  * so people can fix their code.
11034                  */
11035                 char *type = mono_type_full_name (&method->klass->byval_arg);
11036                 char *type_and_method = g_strdup_printf ("%s.%s", type, method->name);
11037
11038                 g_free (type);
11039                 mono_arch_invalidate_method (ji->ji, invalidated_delegate_trampoline, type_and_method);
11040                 destroy = FALSE;
11041         }
11042 #endif
11043
11044         /* 
11045          * This needs to be done before freeing code_mp, since the code address is the
11046          * key in the table, so if we free the code_mp first, another thread can grab the
11047          * same code address and replace our entry in the table.
11048          */
11049         mono_jit_info_table_remove (domain, ji->ji);
11050
11051         if (destroy)
11052                 mono_code_manager_destroy (ji->code_mp);
11053         mono_thread_hazardous_free_or_queue (ji->ji, g_free);
11054         g_free (ji);
11055 }
11056
11057 static gpointer
11058 mono_jit_find_compiled_method (MonoDomain *domain, MonoMethod *method)
11059 {
11060         MonoDomain *target_domain;
11061         MonoJitInfo *info;
11062
11063         if (default_opt & MONO_OPT_SHARED)
11064                 target_domain = mono_get_root_domain ();
11065         else 
11066                 target_domain = domain;
11067
11068         mono_domain_lock (target_domain);
11069
11070         if ((info = mono_internal_hash_table_lookup (&target_domain->jit_code_hash, method))) {
11071                 /* We can't use a domain specific method in another domain */
11072                 if (! ((domain != target_domain) && !info->domain_neutral)) {
11073                         mono_domain_unlock (target_domain);
11074                         mono_jit_stats.methods_lookups++;
11075                         return info->code_start;
11076                 }
11077         }
11078
11079         mono_domain_unlock (target_domain);
11080
11081         return NULL;
11082 }
11083
11084 /**
11085  * mono_jit_runtime_invoke:
11086  * @method: the method to invoke
11087  * @obj: this pointer
11088  * @params: array of parameter values.
11089  * @exc: used to catch exceptions objects
11090  */
11091 static MonoObject*
11092 mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
11093 {
11094         MonoMethod *invoke;
11095         MonoObject *(*runtime_invoke) (MonoObject *this, void **params, MonoObject **exc, void* compiled_method);
11096         void* compiled_method;
11097
11098         if (obj == NULL && !(method->flags & METHOD_ATTRIBUTE_STATIC) && !method->string_ctor && (method->wrapper_type == 0)) {
11099                 g_warning ("Ignoring invocation of an instance method on a NULL instance.\n");
11100                 return NULL;
11101         }
11102
11103         invoke = mono_marshal_get_runtime_invoke (method);
11104         runtime_invoke = mono_jit_compile_method (invoke);
11105         
11106         /* We need this here becuase mono_marshal_get_runtime_invoke can be place 
11107          * the helper method in System.Object and not the target class
11108          */
11109         mono_runtime_class_init (mono_class_vtable (mono_domain_get (), method->klass));
11110
11111         compiled_method = mono_jit_compile_method (method);
11112         return runtime_invoke (obj, params, exc, compiled_method);
11113 }
11114
11115 #ifdef MONO_GET_CONTEXT
11116 #define GET_CONTEXT MONO_GET_CONTEXT
11117 #endif
11118
11119 #ifndef GET_CONTEXT
11120 #ifdef PLATFORM_WIN32
11121 #define GET_CONTEXT \
11122         struct sigcontext *ctx = (struct sigcontext*)_dummy;
11123 #else
11124 #ifdef MONO_ARCH_USE_SIGACTION
11125 #define GET_CONTEXT \
11126     void *ctx = context;
11127 #elif defined(__sparc__)
11128 #define GET_CONTEXT \
11129     void *ctx = sigctx;
11130 #else
11131 #define GET_CONTEXT \
11132         void **_p = (void **)&_dummy; \
11133         struct sigcontext *ctx = (struct sigcontext *)++_p;
11134 #endif
11135 #endif
11136 #endif
11137
11138 #ifdef MONO_ARCH_USE_SIGACTION
11139 #define SIG_HANDLER_SIGNATURE(ftn) ftn (int _dummy, siginfo_t *info, void *context)
11140 #elif defined(__sparc__)
11141 #define SIG_HANDLER_SIGNATURE(ftn) ftn (int _dummy, void *sigctx)
11142 #else
11143 #define SIG_HANDLER_SIGNATURE(ftn) ftn (int _dummy)
11144 #endif
11145
11146 static void
11147 SIG_HANDLER_SIGNATURE (sigfpe_signal_handler)
11148 {
11149         MonoException *exc = NULL;
11150 #ifndef MONO_ARCH_USE_SIGACTION
11151         void *info = NULL;
11152 #endif
11153         GET_CONTEXT;
11154
11155 #if defined(MONO_ARCH_HAVE_IS_INT_OVERFLOW)
11156         if (mono_arch_is_int_overflow (ctx, info))
11157                 exc = mono_get_exception_arithmetic ();
11158         else
11159                 exc = mono_get_exception_divide_by_zero ();
11160 #else
11161         exc = mono_get_exception_divide_by_zero ();
11162 #endif
11163         
11164         mono_arch_handle_exception (ctx, exc, FALSE);
11165 }
11166
11167 static void
11168 SIG_HANDLER_SIGNATURE (sigill_signal_handler)
11169 {
11170         MonoException *exc;
11171         GET_CONTEXT;
11172
11173         exc = mono_get_exception_execution_engine ("SIGILL");
11174         
11175         mono_arch_handle_exception (ctx, exc, FALSE);
11176 }
11177
11178 static void
11179 SIG_HANDLER_SIGNATURE (sigsegv_signal_handler)
11180 {
11181 #ifndef MONO_ARCH_SIGSEGV_ON_ALTSTACK
11182         MonoException *exc = NULL;
11183 #endif
11184         MonoJitInfo *ji;
11185
11186 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
11187         MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
11188 #endif
11189         GET_CONTEXT;
11190
11191 #ifdef MONO_ARCH_USE_SIGACTION
11192         if (debug_options.collect_pagefault_stats) {
11193                 if (mono_raw_buffer_is_pagefault (info->si_addr)) {
11194                         mono_raw_buffer_handle_pagefault (info->si_addr);
11195                         return;
11196                 }
11197                 if (mono_aot_is_pagefault (info->si_addr)) {
11198                         mono_aot_handle_pagefault (info->si_addr);
11199                         return;
11200                 }
11201         }
11202 #endif
11203
11204         ji = mono_jit_info_table_find (mono_domain_get (), mono_arch_ip_from_context (ctx));
11205
11206 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
11207         /* we got a stack overflow in the soft-guard pages
11208          * There are two cases:
11209          * 1) managed code caused the overflow: we unprotect the soft-guard page
11210          * and let the arch-specific code trigger the exception handling mechanism
11211          * in the thread stack. The soft-guard pages will be protected again as the stack is unwound.
11212          * 2) unmanaged code caused the overflow: we unprotect the soft-guard page
11213          * and hope we can continue with those enabled, at least until the hard-guard page
11214          * is hit. The alternative to continuing here is to just print a message and abort.
11215          * We may add in the future the code to protect the pages again in the codepath
11216          * when we return from unmanaged to managed code.
11217          */
11218         if (jit_tls->stack_ovf_guard_size && (guint8*)info->si_addr >= (guint8*)jit_tls->stack_ovf_guard_base &&
11219                         (guint8*)info->si_addr < (guint8*)jit_tls->stack_ovf_guard_base + jit_tls->stack_ovf_guard_size) {
11220                 mono_mprotect (jit_tls->stack_ovf_guard_base, jit_tls->stack_ovf_guard_size, MONO_MMAP_READ|MONO_MMAP_WRITE|MONO_MMAP_EXEC);
11221                 if (ji) {
11222                         mono_arch_handle_altstack_exception (ctx, info->si_addr, TRUE);
11223                 } else {
11224                         /* We print a message: after this even managed stack overflows
11225                          * may crash the runtime
11226                          */
11227                         fprintf (stderr, "Stack overflow in unmanaged: IP: %p, fault addr: %p\n", mono_arch_ip_from_context (ctx), (gpointer)info->si_addr);
11228                 }
11229                 return;
11230         }
11231         /* The hard-guard page has been hit: there is not much we can do anymore
11232          * Print a hopefully clear message and abort.
11233          */
11234         if (jit_tls->stack_size && 
11235                         ABS ((guint8*)info->si_addr - ((guint8*)jit_tls->end_of_stack - jit_tls->stack_size)) < 32768) {
11236                 const char *method;
11237                 /* we don't do much now, but we can warn the user with a useful message */
11238                 fprintf (stderr, "Stack overflow: IP: %p, fault addr: %p\n", mono_arch_ip_from_context (ctx), (gpointer)info->si_addr);
11239                 if (ji && ji->method)
11240                         method = mono_method_full_name (ji->method, TRUE);
11241                 else
11242                         method = "Unmanaged";
11243                 fprintf (stderr, "At %s\n", method);
11244                 abort ();
11245         } else {
11246                 mono_arch_handle_altstack_exception (ctx, info->si_addr, FALSE);
11247         }
11248 #else
11249
11250         if (!ji) {
11251                 mono_handle_native_sigsegv (SIGSEGV, ctx);
11252         }
11253                         
11254         mono_arch_handle_exception (ctx, exc, FALSE);
11255 #endif
11256 }
11257
11258 #ifndef PLATFORM_WIN32
11259
11260 static void
11261 SIG_HANDLER_SIGNATURE (sigabrt_signal_handler)
11262 {
11263         MonoJitInfo *ji;
11264         GET_CONTEXT;
11265
11266         ji = mono_jit_info_table_find (mono_domain_get (), mono_arch_ip_from_context(ctx));
11267         if (!ji) {
11268                 mono_handle_native_sigsegv (SIGABRT, ctx);
11269         }
11270 }
11271
11272 static void
11273 SIG_HANDLER_SIGNATURE (sigusr1_signal_handler)
11274 {
11275         gboolean running_managed;
11276         MonoException *exc;
11277         MonoThread *thread = mono_thread_current ();
11278         void *ji;
11279         
11280         GET_CONTEXT;
11281
11282         if (thread->thread_dump_requested) {
11283                 thread->thread_dump_requested = FALSE;
11284
11285                 mono_print_thread_dump (ctx);
11286         }
11287
11288         /*
11289          * FIXME:
11290          * This is an async signal, so the code below must not call anything which
11291          * is not async safe. That includes the pthread locking functions. If we
11292          * know that we interrupted managed code, then locking is safe.
11293          */
11294         ji = mono_jit_info_table_find (mono_domain_get (), mono_arch_ip_from_context(ctx));
11295         running_managed = ji != NULL;
11296         
11297         exc = mono_thread_request_interruption (running_managed); 
11298         if (!exc) return;
11299
11300         mono_arch_handle_exception (ctx, exc, FALSE);
11301 }
11302
11303 static void
11304 SIG_HANDLER_SIGNATURE (sigprof_signal_handler)
11305 {
11306         GET_CONTEXT;
11307
11308         mono_profiler_stat_hit (mono_arch_ip_from_context (ctx), ctx);
11309 }
11310
11311 static void
11312 SIG_HANDLER_SIGNATURE (sigquit_signal_handler)
11313 {
11314         GET_CONTEXT;
11315
11316         printf ("Full thread dump:\n");
11317
11318         mono_threads_request_thread_dump ();
11319
11320         /*
11321          * print_thread_dump () skips the current thread, since sending a signal
11322          * to it would invoke the signal handler below the sigquit signal handler,
11323          * and signal handlers don't create an lmf, so the stack walk could not
11324          * be performed.
11325          */
11326         mono_print_thread_dump (ctx);
11327 }
11328
11329 static void
11330 SIG_HANDLER_SIGNATURE (sigusr2_signal_handler)
11331 {
11332         gboolean enabled = mono_trace_is_enabled ();
11333
11334         mono_trace_enable (!enabled);
11335 }
11336
11337 #endif
11338
11339 static void
11340 SIG_HANDLER_SIGNATURE (sigint_signal_handler)
11341 {
11342         MonoException *exc;
11343         GET_CONTEXT;
11344
11345         exc = mono_get_exception_execution_engine ("Interrupted (SIGINT).");
11346         
11347         mono_arch_handle_exception (ctx, exc, FALSE);
11348 }
11349
11350 #ifdef PLATFORM_MACOSX
11351
11352 /*
11353  * This code disables the CrashReporter of MacOS X by installing
11354  * a dummy Mach exception handler.
11355  */
11356
11357 /*
11358  * http://darwinsource.opendarwin.org/10.4.3/xnu-792.6.22/osfmk/man/exc_server.html
11359  */
11360 extern
11361 boolean_t
11362 exc_server (mach_msg_header_t *request_msg,
11363             mach_msg_header_t *reply_msg);
11364
11365 /*
11366  * The exception message
11367  */
11368 typedef struct {
11369         mach_msg_base_t msg;  /* common mach message header */
11370         char payload [1024];  /* opaque */
11371 } mach_exception_msg_t;
11372
11373 /* The exception port */
11374 static mach_port_t mach_exception_port = VM_MAP_NULL;
11375
11376 /*
11377  * Implicitly called by exc_server. Must be public.
11378  *
11379  * http://darwinsource.opendarwin.org/10.4.3/xnu-792.6.22/osfmk/man/catch_exception_raise.html
11380  */
11381 kern_return_t
11382 catch_exception_raise (
11383         mach_port_t exception_port,
11384         mach_port_t thread,
11385         mach_port_t task,
11386         exception_type_t exception,
11387         exception_data_t code,
11388         mach_msg_type_number_t code_count)
11389 {
11390         /* consume the exception */
11391         return KERN_FAILURE;
11392 }
11393
11394 /*
11395  * Exception thread handler.
11396  */
11397 static
11398 void *
11399 mach_exception_thread (void *arg)
11400 {
11401         for (;;) {
11402                 mach_exception_msg_t request;
11403                 mach_exception_msg_t reply;
11404                 mach_msg_return_t result;
11405
11406                 /* receive from "mach_exception_port" */
11407                 result = mach_msg (&request.msg.header,
11408                                    MACH_RCV_MSG | MACH_RCV_LARGE,
11409                                    0,
11410                                    sizeof (request),
11411                                    mach_exception_port,
11412                                    MACH_MSG_TIMEOUT_NONE,
11413                                    MACH_PORT_NULL);
11414
11415                 g_assert (result == MACH_MSG_SUCCESS);
11416
11417                 /* dispatch to catch_exception_raise () */
11418                 exc_server (&request.msg.header, &reply.msg.header);
11419
11420                 /* send back to sender */
11421                 result = mach_msg (&reply.msg.header,
11422                                    MACH_SEND_MSG,
11423                                    reply.msg.header.msgh_size,
11424                                    0,
11425                                    MACH_PORT_NULL,
11426                                    MACH_MSG_TIMEOUT_NONE,
11427                                    MACH_PORT_NULL);
11428
11429                 g_assert (result == MACH_MSG_SUCCESS);
11430         }
11431         return NULL;
11432 }
11433
11434 static void
11435 macosx_register_exception_handler ()
11436 {
11437         mach_port_t task;
11438         pthread_attr_t attr;
11439         pthread_t thread;
11440
11441         if (mach_exception_port != VM_MAP_NULL)
11442                 return;
11443
11444         task = mach_task_self ();
11445
11446         /* create the "mach_exception_port" with send & receive rights */
11447         g_assert (mach_port_allocate (task, MACH_PORT_RIGHT_RECEIVE,
11448                                       &mach_exception_port) == KERN_SUCCESS);
11449         g_assert (mach_port_insert_right (task, mach_exception_port, mach_exception_port,
11450                                           MACH_MSG_TYPE_MAKE_SEND) == KERN_SUCCESS);
11451
11452         /* create the exception handler thread */
11453         g_assert (!pthread_attr_init (&attr));
11454         g_assert (!pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED));
11455         g_assert (!pthread_create (&thread, &attr, mach_exception_thread, NULL));
11456         pthread_attr_destroy (&attr);
11457
11458         /*
11459          * register "mach_exception_port" as a receiver for the
11460          * EXC_BAD_ACCESS exception
11461          *
11462          * http://darwinsource.opendarwin.org/10.4.3/xnu-792.6.22/osfmk/man/task_set_exception_ports.html
11463          */
11464         g_assert (task_set_exception_ports (task, EXC_MASK_BAD_ACCESS,
11465                                             mach_exception_port,
11466                                             EXCEPTION_DEFAULT,
11467                                             MACHINE_THREAD_STATE) == KERN_SUCCESS);
11468 }
11469 #endif
11470
11471 #ifndef PLATFORM_WIN32
11472 static void
11473 add_signal_handler (int signo, gpointer handler)
11474 {
11475         struct sigaction sa;
11476
11477 #ifdef MONO_ARCH_USE_SIGACTION
11478         sa.sa_sigaction = handler;
11479         sigemptyset (&sa.sa_mask);
11480         sa.sa_flags = SA_SIGINFO;
11481 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
11482         if (signo == SIGSEGV)
11483                 sa.sa_flags |= SA_ONSTACK;
11484 #endif
11485 #else
11486         sa.sa_handler = handler;
11487         sigemptyset (&sa.sa_mask);
11488         sa.sa_flags = 0;
11489 #endif
11490         g_assert (sigaction (signo, &sa, NULL) != -1);
11491 }
11492
11493 static void
11494 remove_signal_handler (int signo)
11495 {
11496         struct sigaction sa;
11497
11498         sa.sa_handler = SIG_DFL;
11499         sigemptyset (&sa.sa_mask);
11500         sa.sa_flags = 0;
11501
11502         g_assert (sigaction (signo, &sa, NULL) != -1);
11503 }
11504 #endif
11505
11506 static void
11507 mono_runtime_install_handlers (void)
11508 {
11509 #ifdef PLATFORM_WIN32
11510         win32_seh_init();
11511         win32_seh_set_handler(SIGFPE, sigfpe_signal_handler);
11512         win32_seh_set_handler(SIGILL, sigill_signal_handler);
11513         win32_seh_set_handler(SIGSEGV, sigsegv_signal_handler);
11514         if (debug_options.handle_sigint)
11515                 win32_seh_set_handler(SIGINT, sigint_signal_handler);
11516
11517 #else /* !PLATFORM_WIN32 */
11518
11519
11520 #ifdef PLATFORM_MACOSX
11521         macosx_register_exception_handler ();
11522 #endif
11523
11524         if (debug_options.handle_sigint)
11525                 add_signal_handler (SIGINT, sigint_signal_handler);
11526
11527         add_signal_handler (SIGFPE, sigfpe_signal_handler);
11528         add_signal_handler (SIGQUIT, sigquit_signal_handler);
11529         add_signal_handler (SIGILL, sigill_signal_handler);
11530         add_signal_handler (SIGBUS, sigsegv_signal_handler);
11531         if (mono_jit_trace_calls != NULL)
11532                 add_signal_handler (SIGUSR2, sigusr2_signal_handler);
11533
11534         add_signal_handler (mono_thread_get_abort_signal (), sigusr1_signal_handler);
11535         signal (SIGPIPE, SIG_IGN);
11536
11537         add_signal_handler (SIGABRT, sigabrt_signal_handler);
11538
11539         /* catch SIGSEGV */
11540         add_signal_handler (SIGSEGV, sigsegv_signal_handler);
11541 #endif /* PLATFORM_WIN32 */
11542 }
11543
11544 static void
11545 mono_runtime_cleanup_handlers (void)
11546 {
11547 #ifdef PLATFORM_WIN32
11548         win32_seh_cleanup();
11549 #else
11550         if (debug_options.handle_sigint)
11551                 remove_signal_handler (SIGINT);
11552
11553         remove_signal_handler (SIGFPE);
11554         remove_signal_handler (SIGQUIT);
11555         remove_signal_handler (SIGILL);
11556         remove_signal_handler (SIGBUS);
11557         if (mono_jit_trace_calls != NULL)
11558                 remove_signal_handler (SIGUSR2);
11559
11560         remove_signal_handler (mono_thread_get_abort_signal ());
11561
11562         remove_signal_handler (SIGABRT);
11563
11564         remove_signal_handler (SIGSEGV);
11565 #endif /* PLATFORM_WIN32 */
11566 }
11567
11568
11569 #ifdef HAVE_LINUX_RTC_H
11570 #include <linux/rtc.h>
11571 #include <sys/ioctl.h>
11572 #include <fcntl.h>
11573 static int rtc_fd = -1;
11574
11575 static int
11576 enable_rtc_timer (gboolean enable)
11577 {
11578         int flags;
11579         flags = fcntl (rtc_fd, F_GETFL);
11580         if (flags < 0) {
11581                 perror ("getflags");
11582                 return 0;
11583         }
11584         if (enable)
11585                 flags |= FASYNC;
11586         else
11587                 flags &= ~FASYNC;
11588         if (fcntl (rtc_fd, F_SETFL, flags) == -1) {
11589                 perror ("setflags");
11590                 return 0;
11591         }
11592         return 1;
11593 }
11594 #endif
11595
11596 #ifdef PLATFORM_WIN32
11597 static HANDLE win32_main_thread;
11598 static MMRESULT win32_timer;
11599
11600 static void CALLBACK
11601 win32_time_proc (UINT uID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2)
11602 {
11603         CONTEXT context;
11604
11605         context.ContextFlags = CONTEXT_CONTROL;
11606         if (GetThreadContext (win32_main_thread, &context)) {
11607 #ifdef _WIN64
11608                 mono_profiler_stat_hit ((guchar *) context.Rip, &context);
11609 #else
11610                 mono_profiler_stat_hit ((guchar *) context.Eip, &context);
11611 #endif
11612         }
11613 }
11614 #endif
11615
11616 static void
11617 setup_stat_profiler (void)
11618 {
11619 #ifdef ITIMER_PROF
11620         struct itimerval itval;
11621         static int inited = 0;
11622 #ifdef HAVE_LINUX_RTC_H
11623         const char *rtc_freq;
11624         if (!inited && (rtc_freq = g_getenv ("MONO_RTC"))) {
11625                 int freq = 0;
11626                 inited = 1;
11627                 if (*rtc_freq)
11628                         freq = atoi (rtc_freq);
11629                 if (!freq)
11630                         freq = 1024;
11631                 rtc_fd = open ("/dev/rtc", O_RDONLY);
11632                 if (rtc_fd == -1) {
11633                         perror ("open /dev/rtc");
11634                         return;
11635                 }
11636                 add_signal_handler (SIGPROF, sigprof_signal_handler);
11637                 if (ioctl (rtc_fd, RTC_IRQP_SET, freq) == -1) {
11638                         perror ("set rtc freq");
11639                         return;
11640                 }
11641                 if (ioctl (rtc_fd, RTC_PIE_ON, 0) == -1) {
11642                         perror ("start rtc");
11643                         return;
11644                 }
11645                 if (fcntl (rtc_fd, F_SETSIG, SIGPROF) == -1) {
11646                         perror ("setsig");
11647                         return;
11648                 }
11649                 if (fcntl (rtc_fd, F_SETOWN, getpid ()) == -1) {
11650                         perror ("setown");
11651                         return;
11652                 }
11653                 enable_rtc_timer (TRUE);
11654                 return;
11655         }
11656         if (rtc_fd >= 0)
11657                 return;
11658 #endif
11659
11660         itval.it_interval.tv_usec = 999;
11661         itval.it_interval.tv_sec = 0;
11662         itval.it_value = itval.it_interval;
11663         setitimer (ITIMER_PROF, &itval, NULL);
11664         if (inited)
11665                 return;
11666         inited = 1;
11667         add_signal_handler (SIGPROF, sigprof_signal_handler);
11668 #elif defined (PLATFORM_WIN32)
11669         static int inited = 0;
11670         TIMECAPS timecaps;
11671
11672         if (inited)
11673                 return;
11674
11675         inited = 1;
11676         if (timeGetDevCaps (&timecaps, sizeof (timecaps)) != TIMERR_NOERROR)
11677                 return;
11678
11679         if ((win32_main_thread = OpenThread (READ_CONTROL | THREAD_GET_CONTEXT, FALSE, GetCurrentThreadId ())) == NULL)
11680                 return;
11681
11682         if (timeBeginPeriod (1) != TIMERR_NOERROR)
11683                 return;
11684
11685         if ((win32_timer = timeSetEvent (1, 0, win32_time_proc, 0, TIME_PERIODIC)) == 0) {
11686                 timeEndPeriod (1);
11687                 return;
11688         }
11689 #endif
11690 }
11691
11692 /* mono_jit_create_remoting_trampoline:
11693  * @method: pointer to the method info
11694  *
11695  * Creates a trampoline which calls the remoting functions. This
11696  * is used in the vtable of transparent proxies.
11697  * 
11698  * Returns: a pointer to the newly created code 
11699  */
11700 static gpointer
11701 mono_jit_create_remoting_trampoline (MonoMethod *method, MonoRemotingTarget target)
11702 {
11703         MonoMethod *nm;
11704         guint8 *addr = NULL;
11705
11706         if ((method->flags & METHOD_ATTRIBUTE_ABSTRACT) || 
11707             (mono_method_signature (method)->hasthis && (method->klass->marshalbyref || method->klass == mono_defaults.object_class))) {
11708                 nm = mono_marshal_get_remoting_invoke_for_target (method, target);
11709                 addr = mono_compile_method (nm);
11710         } else {
11711                 addr = mono_compile_method (method);
11712         }
11713         return mono_get_addr_from_ftnptr (addr);
11714 }
11715
11716 static void
11717 mini_parse_debug_options (void)
11718 {
11719         char *options = getenv ("MONO_DEBUG");
11720         gchar **args, **ptr;
11721         
11722         if (!options)
11723                 return;
11724
11725         args = g_strsplit (options, ",", -1);
11726
11727         for (ptr = args; ptr && *ptr; ptr++) {
11728                 const char *arg = *ptr;
11729
11730                 if (!strcmp (arg, "handle-sigint"))
11731                         debug_options.handle_sigint = TRUE;
11732                 else if (!strcmp (arg, "keep-delegates"))
11733                         debug_options.keep_delegates = TRUE;
11734                 else if (!strcmp (arg, "collect-pagefault-stats"))
11735                         debug_options.collect_pagefault_stats = TRUE;
11736                 else if (!strcmp (arg, "break-on-unverified"))
11737                         debug_options.break_on_unverified = TRUE;
11738                 else {
11739                         fprintf (stderr, "Invalid option for the MONO_DEBUG env variable: %s\n", arg);
11740                         fprintf (stderr, "Available options: 'handle-sigint', 'keep-delegates', 'collect-pagefault-stats', 'break-on-unverified'\n");
11741                         exit (1);
11742                 }
11743         }
11744 }
11745
11746 MonoDomain *
11747 mini_init (const char *filename, const char *runtime_version)
11748 {
11749         MonoDomain *domain;
11750
11751 #ifdef __linux__
11752         if (access ("/proc/self/maps", F_OK) != 0) {
11753                 g_print ("Mono requires /proc to be mounted.\n");
11754                 exit (1);
11755         }
11756 #endif
11757
11758         /* Happens when using the embedding interface */
11759         if (!default_opt_set)
11760                 default_opt = mono_parse_default_optimizations (NULL);
11761
11762         InitializeCriticalSection (&jit_mutex);
11763
11764         global_codeman = mono_code_manager_new ();
11765         jit_icall_name_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
11766
11767         mono_arch_cpu_init ();
11768
11769         mono_init_trampolines ();
11770
11771         mono_init_exceptions ();
11772
11773         if (!g_thread_supported ())
11774                 g_thread_init (NULL);
11775
11776         if (getenv ("MONO_DEBUG") != NULL)
11777                 mini_parse_debug_options ();
11778
11779         /*
11780          * Handle the case when we are called from a thread different from the main thread,
11781          * confusing libgc.
11782          * FIXME: Move this to libgc where it belongs.
11783          *
11784          * we used to do this only when running on valgrind,
11785          * but it happens also in other setups.
11786          */
11787 #if defined(HAVE_BOEHM_GC)
11788 #if defined(HAVE_PTHREAD_GETATTR_NP) && defined(HAVE_PTHREAD_ATTR_GETSTACK)
11789         {
11790                 size_t size;
11791                 void *sstart;
11792                 pthread_attr_t attr;
11793                 pthread_getattr_np (pthread_self (), &attr);
11794                 pthread_attr_getstack (&attr, &sstart, &size);
11795                 pthread_attr_destroy (&attr); 
11796                 /*g_print ("stackbottom pth is: %p\n", (char*)sstart + size);*/
11797 #ifdef __ia64__
11798                 /*
11799                  * The calculation above doesn't seem to work on ia64, also we need to set
11800                  * GC_register_stackbottom as well, but don't know how.
11801                  */
11802 #else
11803                 /* apparently with some linuxthreads implementations sstart can be NULL,
11804                  * fallback to the more imprecise method (bug# 78096).
11805                  */
11806                 if (sstart) {
11807                         GC_stackbottom = (char*)sstart + size;
11808                 } else {
11809                         gsize stack_bottom = (gsize)&domain;
11810                         stack_bottom += 4095;
11811                         stack_bottom &= ~4095;
11812                         GC_stackbottom = (char*)stack_bottom;
11813                 }
11814 #endif
11815         }
11816 #elif defined(HAVE_PTHREAD_GET_STACKSIZE_NP) && defined(HAVE_PTHREAD_GET_STACKADDR_NP)
11817                 GC_stackbottom = (char*)pthread_get_stackaddr_np (pthread_self ());
11818 #else
11819         {
11820                 gsize stack_bottom = (gsize)&domain;
11821                 stack_bottom += 4095;
11822                 stack_bottom &= ~4095;
11823                 /*g_print ("stackbottom is: %p\n", (char*)stack_bottom);*/
11824                 GC_stackbottom = (char*)stack_bottom;
11825         }
11826 #endif
11827 #endif
11828         MONO_GC_PRE_INIT ();
11829
11830         mono_jit_tls_id = TlsAlloc ();
11831         setup_jit_tls_data ((gpointer)-1, mono_thread_abort);
11832
11833         mono_burg_init ();
11834
11835         if (default_opt & MONO_OPT_AOT)
11836                 mono_aot_init ();
11837
11838         mono_runtime_install_handlers ();
11839         mono_threads_install_cleanup (mini_thread_cleanup);
11840
11841 #define JIT_TRAMPOLINES_WORK
11842 #ifdef JIT_TRAMPOLINES_WORK
11843         mono_install_compile_method (mono_jit_compile_method);
11844         mono_install_free_method (mono_jit_free_method);
11845         mono_install_trampoline (mono_create_jit_trampoline);
11846         mono_install_remoting_trampoline (mono_jit_create_remoting_trampoline);
11847         mono_install_delegate_trampoline (mono_create_delegate_trampoline);
11848 #endif
11849 #define JIT_INVOKE_WORKS
11850 #ifdef JIT_INVOKE_WORKS
11851         mono_install_runtime_invoke (mono_jit_runtime_invoke);
11852         mono_install_handler (mono_arch_get_throw_exception ());
11853 #endif
11854         mono_install_stack_walk (mono_jit_walk_stack);
11855         mono_install_init_vtable (mono_aot_init_vtable);
11856         mono_install_get_cached_class_info (mono_aot_get_cached_class_info);
11857         mono_install_get_class_from_name (mono_aot_get_class_from_name);
11858         mono_install_jit_info_find_in_aot (mono_aot_find_jit_info);
11859
11860 #ifdef MONO_ARCH_HAVE_IMT
11861         mono_install_imt_thunk_builder (mono_arch_build_imt_thunk);
11862 #endif
11863         if (debug_options.collect_pagefault_stats) {
11864                 mono_raw_buffer_set_make_unreadable (TRUE);
11865                 mono_aot_set_make_unreadable (TRUE);
11866         }
11867
11868         if (runtime_version)
11869                 domain = mono_init_version (filename, runtime_version);
11870         else
11871                 domain = mono_init_from_assembly (filename, filename);
11872         mono_icall_init ();
11873
11874         mono_add_internal_call ("System.Diagnostics.StackFrame::get_frame_info", 
11875                                 ves_icall_get_frame_info);
11876         mono_add_internal_call ("System.Diagnostics.StackTrace::get_trace", 
11877                                 ves_icall_get_trace);
11878         mono_add_internal_call ("System.Exception::get_trace", 
11879                                 ves_icall_System_Exception_get_trace);
11880         mono_add_internal_call ("System.Security.SecurityFrame::_GetSecurityFrame",
11881                                 ves_icall_System_Security_SecurityFrame_GetSecurityFrame);
11882         mono_add_internal_call ("System.Security.SecurityFrame::_GetSecurityStack",
11883                                 ves_icall_System_Security_SecurityFrame_GetSecurityStack);
11884         mono_add_internal_call ("Mono.Runtime::mono_runtime_install_handlers", 
11885                                 mono_runtime_install_handlers);
11886
11887
11888         create_helper_signature ();
11889
11890 #define JIT_CALLS_WORK
11891 #ifdef JIT_CALLS_WORK
11892         /* Needs to be called here since register_jit_icall depends on it */
11893         mono_marshal_init ();
11894
11895         mono_arch_register_lowlevel_calls ();
11896         register_icall (mono_profiler_method_enter, "mono_profiler_method_enter", NULL, TRUE);
11897         register_icall (mono_profiler_method_leave, "mono_profiler_method_leave", NULL, TRUE);
11898         register_icall (mono_trace_enter_method, "mono_trace_enter_method", NULL, TRUE);
11899         register_icall (mono_trace_leave_method, "mono_trace_leave_method", NULL, TRUE);
11900         register_icall (mono_get_lmf_addr, "mono_get_lmf_addr", "ptr", TRUE);
11901         register_icall (mono_jit_thread_attach, "mono_jit_thread_attach", "void", TRUE);
11902         register_icall (mono_domain_get, "mono_domain_get", "ptr", TRUE);
11903
11904         register_icall (mono_arch_get_throw_exception (), "mono_arch_throw_exception", "void object", TRUE);
11905         register_icall (mono_arch_get_rethrow_exception (), "mono_arch_rethrow_exception", "void object", TRUE);
11906         register_icall (mono_arch_get_throw_exception_by_name (), "mono_arch_throw_exception_by_name", "void ptr", TRUE); 
11907 #if MONO_ARCH_HAVE_THROW_CORLIB_EXCEPTION
11908         register_icall (mono_arch_get_throw_corlib_exception (), "mono_arch_throw_corlib_exception", 
11909                                  "void ptr", TRUE);
11910 #endif
11911         register_icall (mono_thread_get_pending_exception, "mono_thread_get_pending_exception", "object", FALSE);
11912         register_icall (mono_thread_interruption_checkpoint, "mono_thread_interruption_checkpoint", "void", FALSE);
11913         register_icall (mono_thread_force_interruption_checkpoint, "mono_thread_force_interruption_checkpoint", "void", FALSE);
11914         register_icall (mono_load_remote_field_new, "mono_load_remote_field_new", "object object ptr ptr", FALSE);
11915         register_icall (mono_store_remote_field_new, "mono_store_remote_field_new", "void object ptr ptr object", FALSE);
11916
11917         /* 
11918          * NOTE, NOTE, NOTE, NOTE:
11919          * when adding emulation for some opcodes, remember to also add a dummy
11920          * rule to the burg files, because we need the arity information to be correct.
11921          */
11922 #ifndef MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS
11923         mono_register_opcode_emulation (OP_LMUL, "__emul_lmul", "long long long", mono_llmult, TRUE);
11924         mono_register_opcode_emulation (OP_LDIV, "__emul_ldiv", "long long long", mono_lldiv, FALSE);
11925         mono_register_opcode_emulation (OP_LDIV_UN, "__emul_ldiv_un", "long long long", mono_lldiv_un, FALSE);
11926         mono_register_opcode_emulation (OP_LREM, "__emul_lrem", "long long long", mono_llrem, FALSE);
11927         mono_register_opcode_emulation (OP_LREM_UN, "__emul_lrem_un", "long long long", mono_llrem_un, FALSE);
11928         mono_register_opcode_emulation (OP_LMUL_OVF_UN, "__emul_lmul_ovf_un", "long long long", mono_llmult_ovf_un, FALSE);
11929         mono_register_opcode_emulation (OP_LMUL_OVF, "__emul_lmul_ovf", "long long long", mono_llmult_ovf, FALSE);
11930 #endif
11931
11932 #ifndef MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
11933         mono_register_opcode_emulation (OP_LSHL, "__emul_lshl", "long long int32", mono_lshl, TRUE);
11934         mono_register_opcode_emulation (OP_LSHR, "__emul_lshr", "long long int32", mono_lshr, TRUE);
11935         mono_register_opcode_emulation (OP_LSHR_UN, "__emul_lshr_un", "long long int32", mono_lshr_un, TRUE);
11936 #endif
11937
11938 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
11939         mono_register_opcode_emulation (CEE_DIV, "__emul_idiv", "int32 int32 int32", mono_idiv, FALSE);
11940         mono_register_opcode_emulation (CEE_DIV_UN, "__emul_idiv_un", "int32 int32 int32", mono_idiv_un, FALSE);
11941         mono_register_opcode_emulation (CEE_REM, "__emul_irem", "int32 int32 int32", mono_irem, FALSE);
11942         mono_register_opcode_emulation (CEE_REM_UN, "__emul_irem_un", "int32 int32 int32", mono_irem_un, FALSE);
11943 #endif
11944
11945 #ifdef MONO_ARCH_EMULATE_MUL_DIV
11946         mono_register_opcode_emulation (CEE_MUL_OVF, "__emul_imul_ovf", "int32 int32 int32", mono_imul_ovf, FALSE);
11947         mono_register_opcode_emulation (CEE_MUL_OVF_UN, "__emul_imul_ovf_un", "int32 int32 int32", mono_imul_ovf_un, FALSE);
11948         mono_register_opcode_emulation (CEE_MUL, "__emul_imul", "int32 int32 int32", mono_imul, TRUE);
11949 #endif
11950 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_SOFT_FLOAT)
11951         mono_register_opcode_emulation (OP_FDIV, "__emul_fdiv", "double double double", mono_fdiv, FALSE);
11952 #endif
11953
11954         mono_register_opcode_emulation (OP_FCONV_TO_U8, "__emul_fconv_to_u8", "ulong double", mono_fconv_u8, FALSE);
11955         mono_register_opcode_emulation (OP_FCONV_TO_U4, "__emul_fconv_to_u4", "uint32 double", mono_fconv_u4, FALSE);
11956         mono_register_opcode_emulation (OP_FCONV_TO_OVF_I8, "__emul_fconv_to_ovf_i8", "long double", mono_fconv_ovf_i8, FALSE);
11957         mono_register_opcode_emulation (OP_FCONV_TO_OVF_U8, "__emul_fconv_to_ovf_u8", "ulong double", mono_fconv_ovf_u8, FALSE);
11958
11959 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
11960         mono_register_opcode_emulation (OP_FCONV_TO_I8, "__emul_fconv_to_i8", "long double", mono_fconv_i8, FALSE);
11961 #endif
11962 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
11963         mono_register_opcode_emulation (CEE_CONV_R_UN, "__emul_conv_r_un", "double int32", mono_conv_to_r8_un, FALSE);
11964 #endif
11965 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
11966         mono_register_opcode_emulation (OP_LCONV_TO_R8, "__emul_lconv_to_r8", "double long", mono_lconv_to_r8, FALSE);
11967 #endif
11968 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
11969         mono_register_opcode_emulation (OP_LCONV_TO_R4, "__emul_lconv_to_r4", "float long", mono_lconv_to_r4, FALSE);
11970 #endif
11971 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
11972         mono_register_opcode_emulation (OP_LCONV_TO_R_UN, "__emul_lconv_to_r8_un", "double long", mono_lconv_to_r8_un, FALSE);
11973 #endif
11974 #ifdef MONO_ARCH_EMULATE_FREM
11975         mono_register_opcode_emulation (OP_FREM, "__emul_frem", "double double double", fmod, FALSE);
11976 #endif
11977
11978 #ifdef MONO_ARCH_SOFT_FLOAT
11979         mono_register_opcode_emulation (OP_FSUB, "__emul_fsub", "double double double", mono_fsub, FALSE);
11980         mono_register_opcode_emulation (OP_FADD, "__emul_fadd", "double double double", mono_fadd, FALSE);
11981         mono_register_opcode_emulation (OP_FMUL, "__emul_fmul", "double double double", mono_fmul, FALSE);
11982         mono_register_opcode_emulation (OP_FNEG, "__emul_fneg", "double double", mono_fneg, FALSE);
11983         mono_register_opcode_emulation (CEE_CONV_R8, "__emul_conv_r8", "double int32", mono_conv_to_r8, FALSE);
11984         mono_register_opcode_emulation (CEE_CONV_R4, "__emul_conv_r4", "double int32", mono_conv_to_r4, FALSE);
11985         mono_register_opcode_emulation (OP_FCONV_TO_R4, "__emul_fconv_to_r4", "double double", mono_fconv_r4, FALSE);
11986         mono_register_opcode_emulation (OP_FCONV_TO_I1, "__emul_fconv_to_i1", "int8 double", mono_fconv_i1, FALSE);
11987         mono_register_opcode_emulation (OP_FCONV_TO_I2, "__emul_fconv_to_i2", "int16 double", mono_fconv_i2, FALSE);
11988         mono_register_opcode_emulation (OP_FCONV_TO_I4, "__emul_fconv_to_i4", "int32 double", mono_fconv_i4, FALSE);
11989         mono_register_opcode_emulation (OP_FCONV_TO_U1, "__emul_fconv_to_u1", "uint8 double", mono_fconv_u1, FALSE);
11990         mono_register_opcode_emulation (OP_FCONV_TO_U2, "__emul_fconv_to_u2", "uint16 double", mono_fconv_u2, FALSE);
11991
11992         mono_register_opcode_emulation (OP_FBEQ, "__emul_fcmp_eq", "uint32 double double", mono_fcmp_eq, FALSE);
11993         mono_register_opcode_emulation (OP_FBLT, "__emul_fcmp_lt", "uint32 double double", mono_fcmp_lt, FALSE);
11994         mono_register_opcode_emulation (OP_FBGT, "__emul_fcmp_gt", "uint32 double double", mono_fcmp_gt, FALSE);
11995         mono_register_opcode_emulation (OP_FBLE, "__emul_fcmp_le", "uint32 double double", mono_fcmp_le, FALSE);
11996         mono_register_opcode_emulation (OP_FBGE, "__emul_fcmp_ge", "uint32 double double", mono_fcmp_ge, FALSE);
11997         mono_register_opcode_emulation (OP_FBNE_UN, "__emul_fcmp_ne_un", "uint32 double double", mono_fcmp_ne_un, FALSE);
11998         mono_register_opcode_emulation (OP_FBLT_UN, "__emul_fcmp_lt_un", "uint32 double double", mono_fcmp_lt_un, FALSE);
11999         mono_register_opcode_emulation (OP_FBGT_UN, "__emul_fcmp_gt_un", "uint32 double double", mono_fcmp_gt_un, FALSE);
12000         mono_register_opcode_emulation (OP_FBLE_UN, "__emul_fcmp_le_un", "uint32 double double", mono_fcmp_le_un, FALSE);
12001         mono_register_opcode_emulation (OP_FBGE_UN, "__emul_fcmp_ge_un", "uint32 double double", mono_fcmp_ge_un, FALSE);
12002
12003         mono_register_opcode_emulation (OP_FCEQ, "__emul_fcmp_ceq", "uint32 double double", mono_fceq, FALSE);
12004         mono_register_opcode_emulation (OP_FCGT, "__emul_fcmp_cgt", "uint32 double double", mono_fcgt, FALSE);
12005         mono_register_opcode_emulation (OP_FCGT_UN, "__emul_fcmp_cgt_un", "uint32 double double", mono_fcgt_un, FALSE);
12006         mono_register_opcode_emulation (OP_FCLT, "__emul_fcmp_clt", "uint32 double double", mono_fclt, FALSE);
12007         mono_register_opcode_emulation (OP_FCLT_UN, "__emul_fcmp_clt_un", "uint32 double double", mono_fclt_un, FALSE);
12008
12009         register_icall (mono_fload_r4, "mono_fload_r4", "double ptr", FALSE);
12010         register_icall (mono_fstore_r4, "mono_fstore_r4", "void double ptr", FALSE);
12011         register_icall (mono_fload_r4_arg, "mono_fload_r4_arg", "uint32 double", FALSE);
12012 #endif
12013
12014 #if SIZEOF_VOID_P == 4
12015         mono_register_opcode_emulation (OP_FCONV_TO_U, "__emul_fconv_to_u", "uint32 double", mono_fconv_u4, TRUE);
12016 #endif
12017
12018         /* other jit icalls */
12019         register_icall (mono_delegate_ctor, "mono_delegate_ctor", "void object object ptr", FALSE);
12020         register_icall (mono_class_static_field_address , "mono_class_static_field_address", 
12021                                  "ptr ptr ptr", FALSE);
12022         register_icall (mono_ldtoken_wrapper, "mono_ldtoken_wrapper", "ptr ptr ptr ptr", FALSE);
12023         register_icall (mono_get_special_static_data, "mono_get_special_static_data", "ptr int", FALSE);
12024         register_icall (mono_ldstr, "mono_ldstr", "object ptr ptr int32", FALSE);
12025         register_icall (mono_helper_stelem_ref_check, "helper_stelem_ref_check", "void object object", FALSE);
12026         register_icall (mono_object_new, "mono_object_new", "object ptr ptr", FALSE);
12027         register_icall (mono_object_new_specific, "mono_object_new_specific", "object ptr", FALSE);
12028         register_icall (mono_array_new, "mono_array_new", "object ptr ptr int32", FALSE);
12029         register_icall (mono_array_new_specific, "mono_array_new_specific", "object ptr int32", FALSE);
12030         register_icall (mono_runtime_class_init, "mono_runtime_class_init", "void ptr", FALSE);
12031         register_icall (mono_ldftn, "mono_ldftn", "ptr ptr", FALSE);
12032         register_icall (mono_ldftn_nosync, "mono_ldftn_nosync", "ptr ptr", FALSE);
12033         register_icall (mono_ldvirtfn, "mono_ldvirtfn", "ptr object ptr", FALSE);
12034         register_icall (mono_helper_compile_generic_method, "compile_generic_method", "ptr object ptr ptr ptr", FALSE);
12035         register_icall (mono_helper_ldstr, "helper_ldstr", "object ptr int", FALSE);
12036         register_icall (mono_helper_ldstr_mscorlib, "helper_ldstr_mscorlib", "object int", FALSE);
12037         register_icall (mono_helper_newobj_mscorlib, "helper_newobj_mscorlib", "object int", FALSE);
12038         register_icall (mono_value_copy, "mono_value_copy", "void ptr ptr ptr", FALSE);
12039 #endif
12040
12041 #define JIT_RUNTIME_WORKS
12042 #ifdef JIT_RUNTIME_WORKS
12043         mono_install_runtime_cleanup ((MonoDomainFunc)mini_cleanup);
12044         mono_runtime_init (domain, mono_thread_start_cb, mono_thread_attach_cb);
12045 #endif
12046
12047         mono_thread_attach (domain);
12048         return domain;
12049 }
12050
12051 MonoJitStats mono_jit_stats = {0};
12052
12053 static void 
12054 print_jit_stats (void)
12055 {
12056         if (mono_jit_stats.enabled) {
12057                 g_print ("Mono Jit statistics\n");
12058                 g_print ("Compiled methods:       %ld\n", mono_jit_stats.methods_compiled);
12059                 g_print ("Methods from AOT:       %ld\n", mono_jit_stats.methods_aot);
12060                 g_print ("Methods cache lookup:   %ld\n", mono_jit_stats.methods_lookups);
12061                 g_print ("Method trampolines:     %ld\n", mono_jit_stats.method_trampolines);
12062                 g_print ("Basic blocks:           %ld\n", mono_jit_stats.basic_blocks);
12063                 g_print ("Max basic blocks:       %ld\n", mono_jit_stats.max_basic_blocks);
12064                 g_print ("Allocated vars:         %ld\n", mono_jit_stats.allocate_var);
12065                 g_print ("Analyze stack repeat:   %ld\n", mono_jit_stats.analyze_stack_repeat);
12066                 g_print ("Compiled CIL code size: %ld\n", mono_jit_stats.cil_code_size);
12067                 g_print ("Native code size:       %ld\n", mono_jit_stats.native_code_size);
12068                 g_print ("Max code size ratio:    %.2f (%s::%s)\n", mono_jit_stats.max_code_size_ratio/100.0,
12069                                 mono_jit_stats.max_ratio_method->klass->name, mono_jit_stats.max_ratio_method->name);
12070                 g_print ("Biggest method:         %ld (%s::%s)\n", mono_jit_stats.biggest_method_size,
12071                                 mono_jit_stats.biggest_method->klass->name, mono_jit_stats.biggest_method->name);
12072                 g_print ("Code reallocs:          %ld\n", mono_jit_stats.code_reallocs);
12073                 g_print ("Allocated code size:    %ld\n", mono_jit_stats.allocated_code_size);
12074                 g_print ("Inlineable methods:     %ld\n", mono_jit_stats.inlineable_methods);
12075                 g_print ("Inlined methods:        %ld\n", mono_jit_stats.inlined_methods);
12076                 g_print ("Locals stack size:      %ld\n", mono_jit_stats.locals_stack_size);
12077
12078                 g_print ("\nCreated object count:   %ld\n", mono_stats.new_object_count);
12079                 g_print ("Initialized classes:    %ld\n", mono_stats.initialized_class_count);
12080                 g_print ("Used classes:           %ld\n", mono_stats.used_class_count);
12081                 g_print ("Generic vtables:        %ld\n", mono_stats.generic_vtable_count);
12082                 g_print ("Methods:                %ld\n", mono_stats.method_count);
12083                 g_print ("Static data size:       %ld\n", mono_stats.class_static_data_size);
12084                 g_print ("VTable data size:       %ld\n", mono_stats.class_vtable_size);
12085                 g_print ("Mscorlib mempool size:  %d\n", mono_mempool_get_allocated (mono_defaults.corlib->mempool));
12086
12087                 g_print ("\nGeneric instances:      %ld\n", mono_stats.generic_instance_count);
12088                 g_print ("Initialized classes:    %ld\n", mono_stats.generic_class_count);
12089                 g_print ("Inflated methods:       %ld / %ld\n", mono_stats.inflated_method_count_2,
12090                          mono_stats.inflated_method_count);
12091                 g_print ("Inflated types:         %ld\n", mono_stats.inflated_type_count);
12092                 g_print ("Generics metadata size: %ld\n", mono_stats.generics_metadata_size);
12093                 g_print ("Generics virtual invokes: %ld\n", mono_jit_stats.generic_virtual_invocations);
12094
12095                 g_print ("Dynamic code allocs:    %ld\n", mono_stats.dynamic_code_alloc_count);
12096                 g_print ("Dynamic code bytes:     %ld\n", mono_stats.dynamic_code_bytes_count);
12097                 g_print ("Dynamic code frees:     %ld\n", mono_stats.dynamic_code_frees_count);
12098
12099                 g_print ("IMT tables size:        %ld\n", mono_stats.imt_tables_size);
12100                 g_print ("IMT number of tables:   %ld\n", mono_stats.imt_number_of_tables);
12101                 g_print ("IMT number of methods:  %ld\n", mono_stats.imt_number_of_methods);
12102                 g_print ("IMT used slots:         %ld\n", mono_stats.imt_used_slots);
12103                 g_print ("IMT colliding slots:    %ld\n", mono_stats.imt_slots_with_collisions);
12104                 g_print ("IMT max collisions:     %ld\n", mono_stats.imt_max_collisions_in_slot);
12105                 g_print ("IMT methods at max col: %ld\n", mono_stats.imt_method_count_when_max_collisions);
12106                 g_print ("IMT thunks size:        %ld\n", mono_stats.imt_thunks_size);
12107
12108                 g_print ("JIT info table inserts: %ld\n", mono_stats.jit_info_table_insert_count);
12109                 g_print ("JIT info table removes: %ld\n", mono_stats.jit_info_table_remove_count);
12110                 g_print ("JIT info table lookups: %ld\n", mono_stats.jit_info_table_lookup_count);
12111
12112                 g_print ("Hazardous pointers:     %ld\n", mono_stats.hazardous_pointer_count);
12113
12114                 if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS) {
12115                         g_print ("\nDecl security check   : %ld\n", mono_jit_stats.cas_declsec_check);
12116                         g_print ("LinkDemand (user)     : %ld\n", mono_jit_stats.cas_linkdemand);
12117                         g_print ("LinkDemand (icall)    : %ld\n", mono_jit_stats.cas_linkdemand_icall);
12118                         g_print ("LinkDemand (pinvoke)  : %ld\n", mono_jit_stats.cas_linkdemand_pinvoke);
12119                         g_print ("LinkDemand (aptc)     : %ld\n", mono_jit_stats.cas_linkdemand_aptc);
12120                         g_print ("Demand (code gen)     : %ld\n", mono_jit_stats.cas_demand_generation);
12121                 }
12122                 if (debug_options.collect_pagefault_stats) {
12123                         g_print ("Metadata pagefaults   : %d\n", mono_raw_buffer_get_n_pagefaults ());
12124                         g_print ("AOT pagefaults        : %d\n", mono_aot_get_n_pagefaults ());
12125                 }
12126         }
12127 }
12128
12129 void
12130 mini_cleanup (MonoDomain *domain)
12131 {
12132 #ifdef HAVE_LINUX_RTC_H
12133         if (rtc_fd >= 0)
12134                 enable_rtc_timer (FALSE);
12135 #endif
12136
12137         /* 
12138          * mono_runtime_cleanup() and mono_domain_finalize () need to
12139          * be called early since they need the execution engine still
12140          * fully working (mono_domain_finalize may invoke managed finalizers
12141          * and mono_runtime_cleanup will wait for other threads to finish).
12142          */
12143         mono_domain_finalize (domain, 2000);
12144
12145         /* This accesses metadata so needs to be called before runtime shutdown */
12146         print_jit_stats ();
12147
12148         mono_runtime_cleanup (domain);
12149
12150         mono_profiler_shutdown ();
12151
12152         mono_debug_cleanup ();
12153
12154         mono_icall_cleanup ();
12155
12156         mono_runtime_cleanup_handlers ();
12157
12158         mono_domain_free (domain, TRUE);
12159
12160         mono_code_manager_destroy (global_codeman);
12161         g_hash_table_destroy (jit_icall_name_hash);
12162         if (class_init_hash_addr)
12163                 g_hash_table_destroy (class_init_hash_addr);
12164         g_free (emul_opcode_map);
12165
12166         mono_cleanup ();
12167
12168         mono_trace_cleanup ();
12169
12170         mono_counters_dump (-1, stdout);
12171
12172         TlsFree(mono_jit_tls_id);
12173
12174         DeleteCriticalSection (&jit_mutex);
12175
12176         DeleteCriticalSection (&mono_delegate_section);
12177 }
12178
12179 void
12180 mono_set_defaults (int verbose_level, guint32 opts)
12181 {
12182         mini_verbose = verbose_level;
12183         default_opt = opts;
12184         default_opt_set = TRUE;
12185 }
12186
12187 static void
12188 mono_precompile_assembly (MonoAssembly *ass, void *user_data)
12189 {
12190         GHashTable *assemblies = (GHashTable*)user_data;
12191         MonoImage *image = mono_assembly_get_image (ass);
12192         MonoMethod *method, *invoke;
12193         int i, count = 0;
12194
12195         if (g_hash_table_lookup (assemblies, ass))
12196                 return;
12197
12198         g_hash_table_insert (assemblies, ass, ass);
12199
12200         if (mini_verbose > 0)
12201                 printf ("PRECOMPILE: %s.\n", mono_image_get_filename (image));
12202
12203         for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_METHOD); ++i) {
12204                 method = mono_get_method (image, MONO_TOKEN_METHOD_DEF | (i + 1), NULL);
12205                 if (method->flags & METHOD_ATTRIBUTE_ABSTRACT)
12206                         continue;
12207
12208                 count++;
12209                 if (mini_verbose > 1) {
12210                         char * desc = mono_method_full_name (method, TRUE);
12211                         g_print ("Compiling %d %s\n", count, desc);
12212                         g_free (desc);
12213                 }
12214                 mono_compile_method (method);
12215                 if (strcmp (method->name, "Finalize") == 0) {
12216                         invoke = mono_marshal_get_runtime_invoke (method);
12217                         mono_compile_method (invoke);
12218                 }
12219                 if (method->klass->marshalbyref && mono_method_signature (method)->hasthis) {
12220                         invoke = mono_marshal_get_remoting_invoke_with_check (method);
12221                         mono_compile_method (invoke);
12222                 }
12223         }
12224
12225         /* Load and precompile referenced assemblies as well */
12226         for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_ASSEMBLYREF); ++i) {
12227                 mono_assembly_load_reference (image, i);
12228                 if (image->references [i])
12229                         mono_precompile_assembly (image->references [i], assemblies);
12230         }
12231 }
12232
12233 void mono_precompile_assemblies ()
12234 {
12235         GHashTable *assemblies = g_hash_table_new (NULL, NULL);
12236
12237         mono_assembly_foreach ((GFunc)mono_precompile_assembly, assemblies);
12238
12239         g_hash_table_destroy (assemblies);
12240 }