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