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