2008-08-29 Geoff Norton <gnorton@novell.com>
[mono.git] / mono / mini / mini.c
1 /*
2  * mini.c: The new Mono code generator.
3  *
4  * Author:
5  *   Paolo Molaro (lupus@ximian.com)
6  *   Dietmar Maurer (dietmar@ximian.com)
7  *
8  * (C) 2002 Ximian, Inc.
9  */
10
11 #include <config.h>
12 #include <signal.h>
13 #ifdef HAVE_UNISTD_H
14 #include <unistd.h>
15 #endif
16 #include <math.h>
17 #ifdef HAVE_SYS_TIME_H
18 #include <sys/time.h>
19 #endif
20
21 #ifdef PLATFORM_MACOSX
22 #include <mach/mach.h>
23 #include <mach/mach_error.h>
24 #include <mach/exception.h>
25 #include <mach/task.h>
26 #include <pthread.h>
27 #endif
28
29 #ifdef 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/tabledefs.h>
36 #include <mono/metadata/class.h>
37 #include <mono/metadata/object.h>
38 #include <mono/metadata/exception.h>
39 #include <mono/metadata/opcodes.h>
40 #include <mono/metadata/mono-endian.h>
41 #include <mono/metadata/tokentype.h>
42 #include <mono/metadata/tabledefs.h>
43 #include <mono/metadata/threads.h>
44 #include <mono/metadata/marshal.h>
45 #include <mono/metadata/socket-io.h>
46 #include <mono/metadata/appdomain.h>
47 #include <mono/metadata/debug-helpers.h>
48 #include <mono/io-layer/io-layer.h>
49 #include "mono/metadata/profiler.h"
50 #include <mono/metadata/profiler-private.h>
51 #include <mono/metadata/mono-config.h>
52 #include <mono/metadata/environment.h>
53 #include <mono/metadata/mono-debug.h>
54 #include <mono/metadata/monitor.h>
55 #include <mono/metadata/gc-internal.h>
56 #include <mono/metadata/security-manager.h>
57 #include <mono/metadata/threads-types.h>
58 #include <mono/metadata/rawbuffer.h>
59 #include <mono/metadata/security-core-clr.h>
60 #include <mono/metadata/verify.h>
61 #include <mono/metadata/verify-internals.h>
62 #include <mono/metadata/mempool-internals.h>
63 #include <mono/utils/mono-math.h>
64 #include <mono/utils/mono-compiler.h>
65 #include <mono/utils/mono-counters.h>
66 #include <mono/utils/mono-logger.h>
67 #include <mono/utils/mono-mmap.h>
68 #include <mono/utils/dtrace.h>
69
70 #include "mini.h"
71 #include <string.h>
72 #include <ctype.h>
73 #include "inssel.h"
74 #include "trace.h"
75
76 #include "jit-icalls.h"
77
78 #include "aliasing.h"
79
80 #include "debug-mini.h"
81
82 #define BRANCH_COST 100
83 #define INLINE_LENGTH_LIMIT 20
84 #define INLINE_FAILURE do {\
85                 if ((cfg->method != method) && (method->wrapper_type == MONO_WRAPPER_NONE))\
86                         goto inline_failure;\
87         } while (0)
88 #define CHECK_CFG_EXCEPTION do {\
89                 if (cfg->exception_type != MONO_EXCEPTION_NONE)\
90                         goto exception_exit;\
91         } while (0)
92 #define METHOD_ACCESS_FAILURE do {      \
93                 char *method_fname = mono_method_full_name (method, TRUE);      \
94                 char *cil_method_fname = mono_method_full_name (cil_method, TRUE);      \
95                 cfg->exception_type = MONO_EXCEPTION_METHOD_ACCESS;     \
96                 cfg->exception_message = g_strdup_printf ("Method `%s' is inaccessible from method `%s'\n", cil_method_fname, method_fname);    \
97                 g_free (method_fname);  \
98                 g_free (cil_method_fname);      \
99                 goto exception_exit;    \
100         } while (0)
101 #define FIELD_ACCESS_FAILURE do {       \
102                 char *method_fname = mono_method_full_name (method, TRUE);      \
103                 char *field_fname = mono_field_full_name (field);       \
104                 cfg->exception_type = MONO_EXCEPTION_FIELD_ACCESS;      \
105                 cfg->exception_message = g_strdup_printf ("Field `%s' is inaccessible from method `%s'\n", field_fname, method_fname);  \
106                 g_free (method_fname);  \
107                 g_free (field_fname);   \
108                 goto exception_exit;    \
109         } while (0)
110 #define GENERIC_SHARING_FAILURE(opcode) do {            \
111                 if (cfg->generic_sharing_context) {     \
112             if (cfg->verbose_level > 1) \
113                             printf ("sharing failed for method %s.%s.%s/%d opcode %s line %d\n", method->klass->name_space, method->klass->name, method->name, method->signature->param_count, mono_opcode_name ((opcode)), __LINE__); \
114                         cfg->exception_type = MONO_EXCEPTION_GENERIC_SHARING_FAILED;    \
115                         goto exception_exit;    \
116                 }                       \
117         } while (0)
118 #define GENERIC_SHARING_FAILURE_IF_VALUETYPE_METHOD(opcode) do {                        \
119                 if (method->klass->valuetype)   \
120                         GENERIC_SHARING_FAILURE ((opcode)); \
121         } while (0)
122 #define GET_RGCTX(rgctx, context_used) do {                                             \
123                 MonoInst *this = NULL;                                  \
124                 g_assert (context_used);                                \
125                 GENERIC_SHARING_FAILURE_IF_VALUETYPE_METHOD(*ip);       \
126                 if (!(method->flags & METHOD_ATTRIBUTE_STATIC) &&       \
127                                 !((context_used) & MONO_GENERIC_CONTEXT_USED_METHOD)) \
128                         NEW_ARGLOAD (cfg, this, 0);                     \
129                 (rgctx) = get_runtime_generic_context (cfg, method, (context_used), this, ip); \
130         } while (0)
131
132
133 #define MONO_CHECK_THIS(ins) (mono_method_signature (cfg->method)->hasthis && (ins)->ssa_op == MONO_SSA_LOAD && (ins)->inst_left->inst_c0 == 0)
134
135 static void setup_stat_profiler (void);
136 gboolean  mono_arch_print_tree(MonoInst *tree, int arity);
137 static gpointer mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt);
138 static gpointer mono_jit_compile_method (MonoMethod *method);
139 inline static int mono_emit_jit_icall (MonoCompile *cfg, MonoBasicBlock *bblock, gconstpointer func, MonoInst **args, const guint8 *ip);
140
141 static void handle_stobj (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *dest, MonoInst *src, 
142                           const unsigned char *ip, MonoClass *klass, gboolean to_end, gboolean native, gboolean write_barrier);
143
144 static void dec_foreach (MonoInst *tree, MonoCompile *cfg);
145
146 int mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock, 
147                    MonoInst *return_var, GList *dont_inline, MonoInst **inline_args, 
148                    guint inline_offset, gboolean is_virtual_call);
149
150 static int mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock, 
151                    int locals_offset, MonoInst *return_var, GList *dont_inline, MonoInst **inline_args, 
152                    guint inline_offset, gboolean is_virtual_call);
153
154 #ifdef MONO_ARCH_SOFT_FLOAT
155 static void
156 handle_store_float (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *ptr, MonoInst *val, const unsigned char *ip);
157 #endif
158
159 /* helper methods signature */
160 /* FIXME: Make these static again */
161 MonoMethodSignature *helper_sig_class_init_trampoline = NULL;
162 MonoMethodSignature *helper_sig_domain_get = NULL;
163 MonoMethodSignature *helper_sig_generic_class_init_trampoline = NULL;
164 MonoMethodSignature *helper_sig_rgctx_lazy_fetch_trampoline = NULL;
165
166 static guint32 default_opt = 0;
167 static gboolean default_opt_set = FALSE;
168
169 guint32 mono_jit_tls_id = -1;
170
171 #ifdef HAVE_KW_THREAD
172 static __thread gpointer mono_jit_tls MONO_TLS_FAST;
173 #endif
174
175 MonoTraceSpec *mono_jit_trace_calls = NULL;
176 gboolean mono_break_on_exc = FALSE;
177 gboolean mono_compile_aot = FALSE;
178 /* If this is set, no code is generated dynamically, everything is taken from AOT files */
179 gboolean mono_aot_only = FALSE;
180 /* Whenever to use IMT */
181 #ifdef MONO_ARCH_HAVE_IMT
182 gboolean mono_use_imt = TRUE;
183 #else
184 gboolean mono_use_imt = FALSE;
185 #endif
186 MonoMethodDesc *mono_inject_async_exc_method = NULL;
187 int mono_inject_async_exc_pos;
188 MonoMethodDesc *mono_break_at_bb_method = NULL;
189 int mono_break_at_bb_bb_num;
190
191 static int mini_verbose = 0;
192
193 #define mono_jit_lock() EnterCriticalSection (&jit_mutex)
194 #define mono_jit_unlock() LeaveCriticalSection (&jit_mutex)
195 static CRITICAL_SECTION jit_mutex;
196
197 static MonoCodeManager *global_codeman = NULL;
198
199 /* FIXME: Make this static again */
200 GHashTable *jit_icall_name_hash = NULL;
201
202 static MonoDebugOptions debug_options;
203
204 #ifdef VALGRIND_JIT_REGISTER_MAP
205 static int valgrind_register = 0;
206 #endif
207
208 /*
209  * Table written to by the debugger with a 1-based index into the
210  * mono_breakpoint_info table, which contains changes made to
211  * the JIT instructions by the debugger.
212  */
213 gssize
214 mono_breakpoint_info_index [MONO_BREAKPOINT_ARRAY_SIZE];
215
216 /* Whenever to check for pending exceptions in managed-to-native wrappers */
217 gboolean check_for_pending_exc = TRUE;
218
219 /* Whenever to disable passing/returning small valuetypes in registers for managed methods */
220 gboolean disable_vtypes_in_regs = FALSE;
221
222 gboolean
223 mono_running_on_valgrind (void)
224 {
225 #ifdef HAVE_VALGRIND_MEMCHECK_H
226                 if (RUNNING_ON_VALGRIND){
227 #ifdef VALGRIND_JIT_REGISTER_MAP
228                         valgrind_register = TRUE;
229 #endif
230                         return TRUE;
231                 } else
232                         return FALSE;
233 #else
234                 return FALSE;
235 #endif
236 }
237
238 typedef struct {
239         void *ip;
240         MonoMethod *method;
241 } FindTrampUserData;
242
243 static void
244 find_tramp (gpointer key, gpointer value, gpointer user_data)
245 {
246         FindTrampUserData *ud = (FindTrampUserData*)user_data;
247
248         if (value == ud->ip)
249                 ud->method = (MonoMethod*)key;
250 }
251
252 /* debug function */
253 G_GNUC_UNUSED static char*
254 get_method_from_ip (void *ip)
255 {
256         MonoJitInfo *ji;
257         char *method;
258         char *res;
259         MonoDomain *domain = mono_domain_get ();
260         MonoDebugSourceLocation *location;
261         FindTrampUserData user_data;
262         
263         ji = mono_jit_info_table_find (domain, ip);
264         if (!ji) {
265                 user_data.ip = ip;
266                 user_data.method = NULL;
267                 mono_domain_lock (domain);
268                 g_hash_table_foreach (domain->jit_trampoline_hash, find_tramp, &user_data);
269                 mono_domain_unlock (domain);
270                 if (user_data.method) {
271                         char *mname = mono_method_full_name (user_data.method, TRUE);
272                         res = g_strdup_printf ("<%p - JIT trampoline for %s>", ip, mname);
273                         g_free (mname);
274                         return res;
275                 }
276                 else
277                         return NULL;
278         }
279         method = mono_method_full_name (ji->method, TRUE);
280         /* FIXME: unused ? */
281         location = mono_debug_lookup_source_location (ji->method, (guint32)((guint8*)ip - (guint8*)ji->code_start), domain);
282
283         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);
284
285         mono_debug_free_source_location (location);
286         g_free (method);
287
288         return res;
289 }
290
291 /** 
292  * mono_pmip:
293  * @ip: an instruction pointer address
294  *
295  * This method is used from a debugger to get the name of the
296  * method at address @ip.   This routine is typically invoked from
297  * a debugger like this:
298  *
299  * (gdb) print mono_pmip ($pc)
300  *
301  * Returns: the name of the method at address @ip.
302  */
303 G_GNUC_UNUSED char *
304 mono_pmip (void *ip)
305 {
306         return get_method_from_ip (ip);
307 }
308
309 /** 
310  * mono_print_method_from_ip
311  * @ip: an instruction pointer address
312  *
313  * This method is used from a debugger to get the name of the
314  * method at address @ip.
315  *
316  * This prints the name of the method at address @ip in the standard
317  * output.  Unlike mono_pmip which returns a string, this routine
318  * prints the value on the standard output. 
319  */
320 void
321 mono_print_method_from_ip (void *ip)
322 {
323         MonoJitInfo *ji;
324         char *method;
325         MonoDebugSourceLocation *source;
326         MonoDomain *domain = mono_domain_get ();
327         FindTrampUserData user_data;
328         
329         ji = mono_jit_info_table_find (domain, ip);
330         if (!ji) {
331                 user_data.ip = ip;
332                 user_data.method = NULL;
333                 mono_domain_lock (domain);
334                 g_hash_table_foreach (domain->jit_trampoline_hash, find_tramp, &user_data);
335                 mono_domain_unlock (domain);
336                 if (user_data.method) {
337                         char *mname = mono_method_full_name (user_data.method, TRUE);
338                         printf ("IP %p is a JIT trampoline for %s\n", ip, mname);
339                         g_free (mname);
340                 }
341                 else
342                         g_print ("No method at %p\n", ip);
343                 return;
344         }
345         method = mono_method_full_name (ji->method, TRUE);
346         source = mono_debug_lookup_source_location (ji->method, (guint32)((guint8*)ip - (guint8*)ji->code_start), domain);
347
348         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);
349
350         if (source)
351                 g_print ("%s:%d\n", source->source_file, source->row);
352
353         mono_debug_free_source_location (source);
354         g_free (method);
355 }
356         
357 /* 
358  * mono_method_same_domain:
359  *
360  * Determine whenever two compiled methods are in the same domain, thus
361  * the address of the callee can be embedded in the caller.
362  */
363 gboolean mono_method_same_domain (MonoJitInfo *caller, MonoJitInfo *callee)
364 {
365         if (!caller || !callee)
366                 return FALSE;
367
368         /*
369          * If the call was made from domain-neutral to domain-specific 
370          * code, we can't patch the call site.
371          */
372         if (caller->domain_neutral && !callee->domain_neutral)
373                 return FALSE;
374
375         if ((caller->method->klass == mono_defaults.appdomain_class) &&
376                 (strstr (caller->method->name, "InvokeInDomain"))) {
377                  /* The InvokeInDomain methods change the current appdomain */
378                 return FALSE;
379         }
380
381         return TRUE;
382 }
383
384 /*
385  * mono_global_codeman_reserve:
386  *
387  *  Allocate code memory from the global code manager.
388  */
389 void *mono_global_codeman_reserve (int size)
390 {
391         void *ptr;
392
393         if (mono_aot_only)
394                 g_error ("Attempting to allocate from the global code manager while running with --aot-only.\n");
395
396         if (!global_codeman) {
397                 /* This can happen during startup */
398                 global_codeman = mono_code_manager_new ();
399                 return mono_code_manager_reserve (global_codeman, size);
400         }
401         else {
402                 mono_jit_lock ();
403                 ptr = mono_code_manager_reserve (global_codeman, size);
404                 mono_jit_unlock ();
405                 return ptr;
406         }
407 }
408
409 MonoJumpInfoToken *
410 mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
411 {
412         MonoJumpInfoToken *res = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoToken));
413         res->image = image;
414         res->token = token;
415
416         return res;
417 }
418
419 #define MONO_INIT_VARINFO(vi,id) do { \
420         (vi)->range.first_use.pos.bid = 0xffff; \
421         (vi)->reg = -1; \
422         (vi)->idx = (id); \
423 } while (0)
424
425 //#define UNVERIFIED do { G_BREAKPOINT (); goto unverified; } while (0)
426 #define UNVERIFIED do { if (debug_options.break_on_unverified) G_BREAKPOINT (); else goto unverified; } while (0)
427
428 /*
429  * Basic blocks have two numeric identifiers:
430  * dfn: Depth First Number
431  * block_num: unique ID assigned at bblock creation
432  */
433 #define NEW_BBLOCK(cfg) (mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock)))
434 #define ADD_BBLOCK(cfg,b) do {  \
435                 cfg->cil_offset_to_bb [(b)->cil_code - cfg->cil_start] = (b);   \
436                 (b)->block_num = cfg->num_bblocks++;    \
437                 (b)->real_offset = real_offset; \
438         } while (0)
439
440 #define GET_BBLOCK(cfg,tblock,ip) do {  \
441                 (tblock) = cfg->cil_offset_to_bb [(ip) - cfg->cil_start]; \
442                 if (!(tblock)) {        \
443                         if ((ip) >= end || (ip) < header->code) UNVERIFIED; \
444                         (tblock) = NEW_BBLOCK (cfg);    \
445                         (tblock)->cil_code = (ip);      \
446                         ADD_BBLOCK (cfg, (tblock));     \
447                 } \
448         } while (0)
449
450 #define CHECK_BBLOCK(target,ip,tblock) do {     \
451                 if ((target) < (ip) && !(tblock)->code) {       \
452                         bb_recheck = g_list_prepend (bb_recheck, (tblock));     \
453                         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));     \
454                 }       \
455         } while (0)
456
457 #define NEW_ICONST(cfg,dest,val) do {   \
458                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
459                 (dest)->opcode = OP_ICONST;     \
460                 (dest)->inst_c0 = (val);        \
461                 (dest)->type = STACK_I4;        \
462         } while (0)
463
464 #define NEW_PCONST(cfg,dest,val) do {   \
465                 MONO_INST_NEW ((cfg), (dest), OP_PCONST);       \
466                 (dest)->inst_p0 = (val);        \
467                 (dest)->type = STACK_PTR;       \
468         } while (0)
469
470
471 #ifdef MONO_ARCH_NEED_GOT_VAR
472
473 #define NEW_PATCH_INFO(cfg,dest,el1,el2) do {   \
474                 MONO_INST_NEW ((cfg), (dest), OP_PATCH_INFO);   \
475                 (dest)->inst_left = (gpointer)(el1);    \
476                 (dest)->inst_right = (gpointer)(el2);   \
477         } while (0)
478
479 #define NEW_AOTCONST(cfg,dest,patch_type,cons) do {                     \
480                 MONO_INST_NEW ((cfg), (dest), OP_NOP); \
481                 (dest)->opcode = cfg->compile_aot ? OP_GOT_ENTRY : OP_PCONST; \
482                 if (cfg->compile_aot) {                                 \
483                         MonoInst *group, *got_var, *got_loc;            \
484                         got_loc = mono_get_got_var (cfg);               \
485                         NEW_TEMPLOAD ((cfg), got_var, got_loc->inst_c0); \
486                         NEW_PATCH_INFO ((cfg), group, cons, patch_type); \
487                         (dest)->inst_p0 = got_var;                      \
488                         (dest)->inst_p1 = group;                        \
489                 } else {                                                \
490                         (dest)->inst_p0 = (cons);                       \
491                         (dest)->inst_i1 = (gpointer)(patch_type);       \
492                 }                                                       \
493                 (dest)->type = STACK_PTR;                               \
494         } while (0)
495
496 #define NEW_AOTCONST_TOKEN(cfg,dest,patch_type,image,token,stack_type,stack_class) do { \
497                 MonoInst *group, *got_var, *got_loc;                    \
498                 MONO_INST_NEW ((cfg), (dest), OP_GOT_ENTRY); \
499                 got_loc = mono_get_got_var (cfg);                       \
500                 NEW_TEMPLOAD ((cfg), got_var, got_loc->inst_c0);        \
501                 NEW_PATCH_INFO ((cfg), group, NULL, patch_type);        \
502                 group->inst_p0 = mono_jump_info_token_new ((cfg)->mempool, (image), (token)); \
503                 (dest)->inst_p0 = got_var;                              \
504                 (dest)->inst_p1 = group;                                \
505                 (dest)->type = (stack_type);                    \
506         (dest)->klass = (stack_class);          \
507         } while (0)
508
509 #else
510
511 #define NEW_AOTCONST(cfg,dest,patch_type,cons) do {    \
512                 MONO_INST_NEW ((cfg), (dest), OP_NOP);  \
513                 (dest)->opcode = cfg->compile_aot ? OP_AOTCONST : OP_PCONST;    \
514                 (dest)->inst_p0 = (cons);       \
515                 (dest)->inst_i1 = (gpointer)(patch_type); \
516                 (dest)->type = STACK_PTR;       \
517     } while (0)
518
519 #define NEW_AOTCONST_TOKEN(cfg,dest,patch_type,image,token,stack_type,stack_class) do { \
520                 MONO_INST_NEW ((cfg), (dest), OP_AOTCONST);     \
521                 (dest)->inst_p0 = mono_jump_info_token_new ((cfg)->mempool, (image), (token));  \
522                 (dest)->inst_p1 = (gpointer)(patch_type); \
523                 (dest)->type = (stack_type);    \
524         (dest)->klass = (stack_class);          \
525     } while (0)
526
527 #endif
528
529 #define NEW_CLASSCONST(cfg,dest,val) NEW_AOTCONST ((cfg), (dest), MONO_PATCH_INFO_CLASS, (val))
530
531 #define NEW_IMAGECONST(cfg,dest,val) NEW_AOTCONST ((cfg), (dest), MONO_PATCH_INFO_IMAGE, (val))
532
533 #define NEW_FIELDCONST(cfg,dest,val) NEW_AOTCONST ((cfg), (dest), MONO_PATCH_INFO_FIELD, (val))
534
535 #define NEW_METHODCONST(cfg,dest,val) NEW_AOTCONST ((cfg), (dest), MONO_PATCH_INFO_METHODCONST, (val))
536
537 #define NEW_VTABLECONST(cfg,dest,vtable) NEW_AOTCONST ((cfg), (dest), MONO_PATCH_INFO_VTABLE, cfg->compile_aot ? (gpointer)((vtable)->klass) : (vtable))
538
539 #define NEW_SFLDACONST(cfg,dest,val) NEW_AOTCONST ((cfg), (dest), MONO_PATCH_INFO_SFLDA, (val))
540
541 #define NEW_LDSTRCONST(cfg,dest,image,token) NEW_AOTCONST_TOKEN ((cfg), (dest), MONO_PATCH_INFO_LDSTR, (image), (token), STACK_OBJ, mono_defaults.string_class)
542
543 #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)
544
545 #define NEW_LDTOKENCONST(cfg,dest,image,token) NEW_AOTCONST_TOKEN ((cfg), (dest), MONO_PATCH_INFO_LDTOKEN, (image), (token), STACK_PTR, NULL)
546
547 #define NEW_DECLSECCONST(cfg,dest,image,entry) do { \
548                 if (cfg->compile_aot) { \
549                         NEW_AOTCONST_TOKEN (cfg, dest, MONO_PATCH_INFO_DECLSEC, image, (entry).index, STACK_OBJ, NULL); \
550                 } else { \
551                         NEW_PCONST (cfg, args [0], (entry).blob); \
552                 } \
553         } while (0)
554
555 #define NEW_DOMAINCONST(cfg,dest) do { \
556                 if (cfg->opt & MONO_OPT_SHARED) { \
557                         /* avoid depending on undefined C behavior in sequence points */ \
558                         MonoInst* __domain_var = mono_get_domainvar (cfg); \
559                         NEW_TEMPLOAD (cfg, dest, __domain_var->inst_c0); \
560                 } else { \
561                         NEW_PCONST (cfg, dest, (cfg)->domain); \
562                 } \
563         } while (0)
564
565 #define GET_VARINFO_INST(cfg,num) ((cfg)->varinfo [(num)]->inst)
566
567 #define NEW_ARGLOAD(cfg,dest,num) do {  \
568                 if (arg_array [(num)]->opcode == OP_ICONST) (dest) = arg_array [(num)]; else { \
569                 MONO_INST_NEW ((cfg), (dest), OP_NOP);  \
570                 (dest)->ssa_op = MONO_SSA_LOAD; \
571                 (dest)->inst_i0 = arg_array [(num)];    \
572                 (dest)->opcode = mini_type_to_ldind ((cfg), (dest)->inst_i0->inst_vtype); \
573                 type_to_eval_stack_type ((cfg), param_types [(num)], (dest));   \
574                 (dest)->klass = (dest)->inst_i0->klass; \
575         }} while (0)
576
577 #define NEW_LOCLOAD(cfg,dest,num) do {  \
578                 MONO_INST_NEW ((cfg), (dest), OP_NOP);  \
579                 (dest)->ssa_op = MONO_SSA_LOAD; \
580                 (dest)->inst_i0 = (cfg)->varinfo [locals_offset + (num)];       \
581                 (dest)->opcode = mini_type_to_ldind ((cfg), (dest)->inst_i0->inst_vtype); \
582                 type_to_eval_stack_type ((cfg), header->locals [(num)], (dest));        \
583                 (dest)->klass = (dest)->inst_i0->klass; \
584         } while (0)
585
586 #define NEW_LOCLOADA(cfg,dest,num) do { \
587                 MONO_INST_NEW ((cfg), (dest), OP_LDADDR);       \
588                 (dest)->ssa_op = MONO_SSA_ADDRESS_TAKEN;        \
589                 (dest)->inst_i0 = (cfg)->varinfo [locals_offset + (num)];       \
590                 (dest)->inst_i0->flags |= MONO_INST_INDIRECT;   \
591                 (dest)->type = STACK_MP;        \
592                 (dest)->klass = (dest)->inst_i0->klass; \
593         if (!MONO_TYPE_ISSTRUCT (header->locals [(num)])) \
594            (cfg)->disable_ssa = TRUE; \
595         } while (0)
596
597 #define NEW_RETLOADA(cfg,dest) do {     \
598         if (cfg->vret_addr) { \
599                     MONO_INST_NEW ((cfg), (dest), OP_NOP);      \
600                     (dest)->ssa_op = MONO_SSA_LOAD;     \
601                     (dest)->inst_i0 = cfg->vret_addr; \
602                     (dest)->opcode = mini_type_to_ldind ((cfg), (dest)->inst_i0->inst_vtype); \
603             (dest)->type = STACK_MP; \
604                     (dest)->klass = (dest)->inst_i0->klass;     \
605         } else { \
606                         MONO_INST_NEW ((cfg), (dest), OP_NOP);  \
607                     (dest)->ssa_op = MONO_SSA_ADDRESS_TAKEN;    \
608                     (dest)->inst_i0 = (cfg)->ret;       \
609                     (dest)->inst_i0->flags |= MONO_INST_INDIRECT;       \
610                     (dest)->opcode = cfg->ret_var_is_local ? OP_LDADDR : CEE_LDIND_I;   \
611                     (dest)->type = STACK_MP;    \
612                     (dest)->klass = (dest)->inst_i0->klass;     \
613             (cfg)->disable_ssa = TRUE; \
614         } \
615         } while (0)
616
617 #define NEW_ARGLOADA(cfg,dest,num) do { \
618                 if (arg_array [(num)]->opcode == OP_ICONST) goto inline_failure; \
619                 MONO_INST_NEW ((cfg), (dest), OP_LDADDR);       \
620                 (dest)->ssa_op = MONO_SSA_ADDRESS_TAKEN;        \
621                 (dest)->inst_i0 = arg_array [(num)];    \
622                 (dest)->inst_i0->flags |= MONO_INST_INDIRECT;   \
623                 (dest)->type = STACK_MP;        \
624                 (dest)->klass = (dest)->inst_i0->klass; \
625                 (cfg)->disable_ssa = TRUE; \
626         } while (0)
627
628 #define NEW_TEMPLOAD(cfg,dest,num) do { \
629                 MONO_INST_NEW ((cfg), (dest), OP_NOP);  \
630                 (dest)->ssa_op = MONO_SSA_LOAD; \
631                 (dest)->inst_i0 = (cfg)->varinfo [(num)];       \
632                 (dest)->opcode = mini_type_to_ldind ((cfg), (dest)->inst_i0->inst_vtype); \
633                 type_to_eval_stack_type ((cfg), (dest)->inst_i0->inst_vtype, (dest));   \
634                 (dest)->klass = (dest)->inst_i0->klass; \
635         } while (0)
636
637 #define NEW_TEMPLOADA(cfg,dest,num) do {        \
638                 MONO_INST_NEW ((cfg), (dest), OP_LDADDR);       \
639                 (dest)->ssa_op = MONO_SSA_ADDRESS_TAKEN;        \
640                 (dest)->inst_i0 = (cfg)->varinfo [(num)];       \
641                 (dest)->inst_i0->flags |= MONO_INST_INDIRECT;   \
642                 (dest)->type = STACK_MP;        \
643                 (dest)->klass = (dest)->inst_i0->klass; \
644         if (!MONO_TYPE_ISSTRUCT (cfg->varinfo [(num)]->inst_vtype)) \
645            (cfg)->disable_ssa = TRUE; \
646         } while (0)
647
648 #define NEW_INDLOAD(cfg,dest,addr,vtype) do {   \
649                 MONO_INST_NEW ((cfg), (dest), OP_NOP);  \
650                 (dest)->inst_left = addr;       \
651                 (dest)->opcode = mini_type_to_ldind ((cfg), vtype);     \
652                 type_to_eval_stack_type ((cfg), vtype, (dest)); \
653                 /* FIXME: (dest)->klass = (dest)->inst_i0->klass;*/     \
654         } while (0)
655
656 #define NEW_INDSTORE(cfg,dest,addr,value,vtype) do {    \
657                 MONO_INST_NEW ((cfg), (dest), OP_NOP);  \
658                 (dest)->inst_i0 = addr; \
659                 (dest)->opcode = mini_type_to_stind ((cfg), vtype);     \
660                 (dest)->inst_i1 = (value);      \
661                 /* FIXME: (dest)->klass = (dest)->inst_i0->klass;*/     \
662         } while (0)
663
664 #define NEW_TEMPSTORE(cfg,dest,num,inst) do {   \
665                 MONO_INST_NEW ((cfg), (dest), OP_NOP);  \
666                 (dest)->ssa_op = MONO_SSA_STORE;        \
667                 (dest)->inst_i0 = (cfg)->varinfo [(num)];       \
668                 (dest)->opcode = mini_type_to_stind ((cfg), (dest)->inst_i0->inst_vtype); \
669                 (dest)->inst_i1 = (inst);       \
670                 (dest)->klass = (dest)->inst_i0->klass; \
671         } while (0)
672
673 #define NEW_LOCSTORE(cfg,dest,num,inst) do {    \
674                 MONO_INST_NEW ((cfg), (dest), OP_NOP);  \
675                 (dest)->opcode = mini_type_to_stind ((cfg), header->locals [(num)]); \
676                 (dest)->ssa_op = MONO_SSA_STORE;        \
677                 (dest)->inst_i0 = (cfg)->varinfo [locals_offset + (num)];       \
678                 (dest)->inst_i1 = (inst);       \
679                 (dest)->klass = (dest)->inst_i0->klass; \
680         } while (0)
681
682 #define NEW_ARGSTORE(cfg,dest,num,inst) do {    \
683                 if (arg_array [(num)]->opcode == OP_ICONST) goto inline_failure; \
684                 MONO_INST_NEW ((cfg), (dest), OP_NOP);  \
685                 (dest)->opcode = mini_type_to_stind ((cfg), param_types [(num)]); \
686                 (dest)->ssa_op = MONO_SSA_STORE;        \
687                 (dest)->inst_i0 = arg_array [(num)];    \
688                 (dest)->inst_i1 = (inst);       \
689                 (dest)->klass = (dest)->inst_i0->klass; \
690         } while (0)
691
692 #define NEW_MEMCPY(cfg,dest,dst,src,memcpy_size,memcpy_align) do { \
693                 MONO_INST_NEW (cfg, dest, OP_MEMCPY); \
694         (dest)->inst_left = (dst); \
695                 (dest)->inst_right = (src); \
696         (dest)->backend.memcpy_args = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoMemcpyArgs)); \
697                 (dest)->backend.memcpy_args->size = (memcpy_size); \
698                 (dest)->backend.memcpy_args->align = (memcpy_align); \
699     } while (0)
700
701 #define NEW_MEMSET(cfg,dest,dst,imm,memcpy_size,memcpy_align) do { \
702                 MONO_INST_NEW (cfg, dest, OP_MEMSET); \
703         (dest)->inst_left = (dst); \
704                 (dest)->inst_imm = (imm); \
705         (dest)->backend.memcpy_args = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoMemcpyArgs)); \
706                 (dest)->backend.memcpy_args->size = (memcpy_size); \
707                 (dest)->backend.memcpy_args->align = (memcpy_align); \
708     } while (0)
709
710 #define NEW_DUMMY_USE(cfg,dest,load) do { \
711                 MONO_INST_NEW ((cfg), (dest), OP_DUMMY_USE);    \
712                 (dest)->inst_left = (load); \
713     } while (0)
714
715 #define NEW_DUMMY_STORE(cfg,dest,num) do { \
716                 MONO_INST_NEW ((cfg), (dest), OP_DUMMY_STORE);  \
717                 (dest)->inst_i0 = (cfg)->varinfo [(num)];       \
718                 (dest)->klass = (dest)->inst_i0->klass; \
719         } while (0)
720
721 #define ADD_BINOP(op) do {      \
722                 MONO_INST_NEW (cfg, ins, (op)); \
723                 sp -= 2;        \
724                 ins->inst_i0 = sp [0];  \
725                 ins->inst_i1 = sp [1];  \
726                 *sp++ = ins;    \
727                 type_from_op (ins);     \
728                 CHECK_TYPE (ins);       \
729                 /* Have to insert a widening op */               \
730                 /* FIXME: Need to add many more cases */ \
731                 if (ins->inst_i0->type == STACK_PTR && ins->inst_i1->type == STACK_I4) { \
732                         MonoInst *widen;  \
733                         MONO_INST_NEW (cfg, widen, CEE_CONV_I); \
734             widen->inst_i0 = ins->inst_i1; \
735                         ins->inst_i1 = widen; \
736                 } \
737         } while (0)
738
739 #define ADD_UNOP(op) do {       \
740                 MONO_INST_NEW (cfg, ins, (op)); \
741                 sp--;   \
742                 ins->inst_i0 = sp [0];  \
743                 *sp++ = ins;    \
744                 type_from_op (ins);     \
745                 CHECK_TYPE (ins);       \
746         } while (0)
747
748 #define ADD_BINCOND(next_block) do {    \
749                 MonoInst *cmp;  \
750                 sp -= 2;                \
751                 MONO_INST_NEW(cfg, cmp, OP_COMPARE);    \
752                 cmp->inst_i0 = sp [0];  \
753                 cmp->inst_i1 = sp [1];  \
754                 cmp->cil_code = ins->cil_code;  \
755                 type_from_op (cmp);     \
756                 CHECK_TYPE (cmp);       \
757                 ins->inst_i0 = cmp;     \
758                 MONO_ADD_INS (bblock, ins);     \
759                 ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);      \
760                 GET_BBLOCK (cfg, tblock, target);               \
761                 link_bblock (cfg, bblock, tblock);      \
762                 ins->inst_true_bb = tblock;     \
763                 CHECK_BBLOCK (target, ip, tblock);      \
764                 if ((next_block)) {     \
765                         link_bblock (cfg, bblock, (next_block));        \
766                         ins->inst_false_bb = (next_block);      \
767                         start_new_bblock = 1;   \
768                 } else {        \
769                         GET_BBLOCK (cfg, tblock, ip);           \
770                         link_bblock (cfg, bblock, tblock);      \
771                         ins->inst_false_bb = tblock;    \
772                         start_new_bblock = 2;   \
773                 }       \
774         } while (0)
775
776 /* FIXME: handle float, long ... */
777 #define ADD_UNCOND(istrue) do { \
778                 MonoInst *cmp;  \
779                 sp--;           \
780                 MONO_INST_NEW(cfg, cmp, OP_COMPARE);    \
781                 cmp->inst_i0 = sp [0];  \
782                 switch (cmp->inst_i0->type) { \
783                 case STACK_I8: \
784                         cmp->inst_i1 = zero_int64; break; \
785                 case STACK_R8: \
786                         cmp->inst_i1 = zero_r8; break; \
787                 case STACK_PTR: \
788                 case STACK_MP: \
789                         cmp->inst_i1 = zero_ptr; break; \
790                 case STACK_OBJ: \
791                         cmp->inst_i1 = zero_obj; break; \
792                 default: \
793                         cmp->inst_i1 = zero_int32;  \
794                 }  \
795                 cmp->cil_code = ins->cil_code;  \
796                 type_from_op (cmp);     \
797                 CHECK_TYPE (cmp);       \
798                 ins->inst_i0 = cmp;     \
799                 ins->opcode = (istrue)? CEE_BNE_UN: CEE_BEQ;    \
800                 MONO_ADD_INS (bblock, ins);     \
801                 ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);      \
802                 GET_BBLOCK (cfg, tblock, target);               \
803                 link_bblock (cfg, bblock, tblock);      \
804                 ins->inst_true_bb = tblock;     \
805                 CHECK_BBLOCK (target, ip, tblock);      \
806                 GET_BBLOCK (cfg, tblock, ip);           \
807                 link_bblock (cfg, bblock, tblock);      \
808                 ins->inst_false_bb = tblock;    \
809                 start_new_bblock = 2;   \
810         } while (0)
811
812 #define NEW_LDELEMA(cfg,dest,sp,k) do { \
813                 MONO_INST_NEW ((cfg), (dest), CEE_LDELEMA);     \
814                 (dest)->inst_left = (sp) [0];   \
815                 (dest)->inst_right = (sp) [1];  \
816                 (dest)->type = STACK_MP;        \
817                 (dest)->klass = (k);    \
818                 (cfg)->flags |= MONO_CFG_HAS_LDELEMA; \
819         } while (0)
820
821 #define NEW_GROUP(cfg,dest,el1,el2) do {        \
822                 MONO_INST_NEW ((cfg), (dest), OP_GROUP);        \
823                 (dest)->inst_left = (el1);      \
824                 (dest)->inst_right = (el2);     \
825         } while (0)
826
827 #if 0
828 static gint
829 compare_bblock (gconstpointer a, gconstpointer b)
830 {
831         const MonoBasicBlock *b1 = a;
832         const MonoBasicBlock *b2 = b;
833
834         return b2->cil_code - b1->cil_code;
835 }
836 #endif
837
838 /* *
839  * link_bblock: Links two basic blocks
840  *
841  * links two basic blocks in the control flow graph, the 'from'
842  * argument is the starting block and the 'to' argument is the block
843  * the control flow ends to after 'from'.
844  */
845 static void
846 link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
847 {
848         MonoBasicBlock **newa;
849         int i, found;
850
851 #if 0
852         if (from->cil_code) {
853                 if (to->cil_code)
854                         g_print ("edge from IL%04x to IL_%04x\n", from->cil_code - cfg->cil_code, to->cil_code - cfg->cil_code);
855                 else
856                         g_print ("edge from IL%04x to exit\n", from->cil_code - cfg->cil_code);
857         } else {
858                 if (to->cil_code)
859                         g_print ("edge from entry to IL_%04x\n", to->cil_code - cfg->cil_code);
860                 else
861                         g_print ("edge from entry to exit\n");
862         }
863 #endif
864         found = FALSE;
865         for (i = 0; i < from->out_count; ++i) {
866                 if (to == from->out_bb [i]) {
867                         found = TRUE;
868                         break;
869                 }
870         }
871         if (!found) {
872                 newa = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (from->out_count + 1));
873                 for (i = 0; i < from->out_count; ++i) {
874                         newa [i] = from->out_bb [i];
875                 }
876                 newa [i] = to;
877                 from->out_count++;
878                 from->out_bb = newa;
879         }
880
881         found = FALSE;
882         for (i = 0; i < to->in_count; ++i) {
883                 if (from == to->in_bb [i]) {
884                         found = TRUE;
885                         break;
886                 }
887         }
888         if (!found) {
889                 newa = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (to->in_count + 1));
890                 for (i = 0; i < to->in_count; ++i) {
891                         newa [i] = to->in_bb [i];
892                 }
893                 newa [i] = from;
894                 to->in_count++;
895                 to->in_bb = newa;
896         }
897 }
898
899 /**
900  * mono_unlink_bblock:
901  *
902  *   Unlink two basic blocks.
903  */
904 void
905 mono_unlink_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
906 {
907         int i, pos;
908         gboolean found;
909
910         found = FALSE;
911         for (i = 0; i < from->out_count; ++i) {
912                 if (to == from->out_bb [i]) {
913                         found = TRUE;
914                         break;
915                 }
916         }
917         if (found) {
918                 pos = 0;
919                 for (i = 0; i < from->out_count; ++i) {
920                         if (from->out_bb [i] != to)
921                                 from->out_bb [pos ++] = from->out_bb [i];
922                 }
923                 g_assert (pos == from->out_count - 1);
924                 from->out_count--;
925         }
926
927         found = FALSE;
928         for (i = 0; i < to->in_count; ++i) {
929                 if (from == to->in_bb [i]) {
930                         found = TRUE;
931                         break;
932                 }
933         }
934         if (found) {
935                 pos = 0;
936                 for (i = 0; i < to->in_count; ++i) {
937                         if (to->in_bb [i] != from)
938                                 to->in_bb [pos ++] = to->in_bb [i];
939                 }
940                 g_assert (pos == to->in_count - 1);
941                 to->in_count--;
942         }
943 }
944
945 /*
946  * mono_bblocks_linked:
947  *
948  *   Return whenever BB1 and BB2 are linked in the CFG.
949  */
950 gboolean
951 mono_bblocks_linked (MonoBasicBlock *bb1, MonoBasicBlock *bb2)
952 {
953         int i;
954
955         for (i = 0; i < bb1->out_count; ++i) {
956                 if (bb1->out_bb [i] == bb2)
957                         return TRUE;
958         }
959
960         return FALSE;
961 }
962
963 /**
964  * mono_find_block_region:
965  *
966  *   We mark each basic block with a region ID. We use that to avoid BB
967  *   optimizations when blocks are in different regions.
968  *
969  * Returns:
970  *   A region token that encodes where this region is, and information
971  *   about the clause owner for this block.
972  *
973  *   The region encodes the try/catch/filter clause that owns this block
974  *   as well as the type.  -1 is a special value that represents a block
975  *   that is in none of try/catch/filter.
976  */
977 static int
978 mono_find_block_region (MonoCompile *cfg, int offset)
979 {
980         MonoMethod *method = cfg->method;
981         MonoMethodHeader *header = mono_method_get_header (method);
982         MonoExceptionClause *clause;
983         int i;
984
985         /* first search for handlers and filters */
986         for (i = 0; i < header->num_clauses; ++i) {
987                 clause = &header->clauses [i];
988                 if ((clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) && (offset >= clause->data.filter_offset) &&
989                     (offset < (clause->handler_offset)))
990                         return ((i + 1) << 8) | MONO_REGION_FILTER | clause->flags;
991                            
992                 if (MONO_OFFSET_IN_HANDLER (clause, offset)) {
993                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY)
994                                 return ((i + 1) << 8) | MONO_REGION_FINALLY | clause->flags;
995                         else if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
996                                 return ((i + 1) << 8) | MONO_REGION_FAULT | clause->flags;
997                         else if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE)
998                                 return ((i + 1) << 8) | MONO_REGION_CATCH | clause->flags;
999                 }
1000         }
1001
1002         /* search the try blocks */
1003         for (i = 0; i < header->num_clauses; ++i) {
1004                 clause = &header->clauses [i];
1005                 if (MONO_OFFSET_IN_CLAUSE (clause, offset))
1006                         return ((i + 1) << 8) | clause->flags;
1007         }
1008
1009         return -1;
1010 }
1011
1012 static GList*
1013 mono_find_final_block (MonoCompile *cfg, unsigned char *ip, unsigned char *target, int type)
1014 {
1015         MonoMethod *method = cfg->method;
1016         MonoMethodHeader *header = mono_method_get_header (method);
1017         MonoExceptionClause *clause;
1018         MonoBasicBlock *handler;
1019         int i;
1020         GList *res = NULL;
1021
1022         for (i = 0; i < header->num_clauses; ++i) {
1023                 clause = &header->clauses [i];
1024                 if (MONO_OFFSET_IN_CLAUSE (clause, (ip - header->code)) && 
1025                     (!MONO_OFFSET_IN_CLAUSE (clause, (target - header->code)))) {
1026                         if (clause->flags == type) {
1027                                 handler = cfg->cil_offset_to_bb [clause->handler_offset];
1028                                 g_assert (handler);
1029                                 res = g_list_append (res, handler);
1030                         }
1031                 }
1032         }
1033         return res;
1034 }
1035
1036 MonoInst *
1037 mono_find_spvar_for_region (MonoCompile *cfg, int region)
1038 {
1039         return g_hash_table_lookup (cfg->spvars, GINT_TO_POINTER (region));
1040 }
1041
1042 static void
1043 mono_create_spvar_for_region (MonoCompile *cfg, int region)
1044 {
1045         MonoInst *var;
1046
1047         var = g_hash_table_lookup (cfg->spvars, GINT_TO_POINTER (region));
1048         if (var)
1049                 return;
1050
1051         var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1052         /* prevent it from being register allocated */
1053         var->flags |= MONO_INST_INDIRECT;
1054
1055         g_hash_table_insert (cfg->spvars, GINT_TO_POINTER (region), var);
1056 }
1057
1058 static MonoInst *
1059 mono_find_exvar_for_offset (MonoCompile *cfg, int offset)
1060 {
1061         return g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
1062 }
1063
1064 static MonoInst*
1065 mono_create_exvar_for_offset (MonoCompile *cfg, int offset)
1066 {
1067         MonoInst *var;
1068
1069         var = g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
1070         if (var)
1071                 return var;
1072
1073         var = mono_compile_create_var (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL);
1074         /* prevent it from being register allocated */
1075         var->flags |= MONO_INST_INDIRECT;
1076
1077         g_hash_table_insert (cfg->exvars, GINT_TO_POINTER (offset), var);
1078
1079         return var;
1080 }
1081
1082 static void
1083 df_visit (MonoBasicBlock *start, int *dfn, MonoBasicBlock **array)
1084 {
1085         int i;
1086
1087         array [*dfn] = start;
1088         /* g_print ("visit %d at %p (BB%ld)\n", *dfn, start->cil_code, start->block_num); */
1089         for (i = 0; i < start->out_count; ++i) {
1090                 if (start->out_bb [i]->dfn)
1091                         continue;
1092                 (*dfn)++;
1093                 start->out_bb [i]->dfn = *dfn;
1094                 start->out_bb [i]->df_parent = start;
1095                 array [*dfn] = start->out_bb [i];
1096                 df_visit (start->out_bb [i], dfn, array);
1097         }
1098 }
1099
1100 static MonoBasicBlock*
1101 find_previous (MonoBasicBlock **bblocks, guint32 n_bblocks, MonoBasicBlock *start, const guchar *code)
1102 {
1103         MonoBasicBlock *best = start;
1104         int i;
1105
1106         for (i = 0; i < n_bblocks; ++i) {
1107                 if (bblocks [i]) {
1108                         MonoBasicBlock *bb = bblocks [i];
1109
1110                         if (bb->cil_code && bb->cil_code < code && bb->cil_code > best->cil_code)
1111                                 best = bb;
1112                 }
1113         }
1114
1115         return best;
1116 }
1117
1118 static void
1119 split_bblock (MonoCompile *cfg, MonoBasicBlock *first, MonoBasicBlock *second) {
1120         int i, j;
1121         MonoInst *inst;
1122         MonoBasicBlock *bb;
1123
1124         if (second->code)
1125                 return;
1126         
1127         /* 
1128          * FIXME: take into account all the details:
1129          * second may have been the target of more than one bblock
1130          */
1131         second->out_count = first->out_count;
1132         second->out_bb = first->out_bb;
1133
1134         for (i = 0; i < first->out_count; ++i) {
1135                 bb = first->out_bb [i];
1136                 for (j = 0; j < bb->in_count; ++j) {
1137                         if (bb->in_bb [j] == first)
1138                                 bb->in_bb [j] = second;
1139                 }
1140         }
1141
1142         first->out_count = 0;
1143         first->out_bb = NULL;
1144         link_bblock (cfg, first, second);
1145
1146         second->last_ins = first->last_ins;
1147
1148         /*g_print ("start search at %p for %p\n", first->cil_code, second->cil_code);*/
1149         MONO_BB_FOR_EACH_INS (first, inst) {
1150                 /*char *code = mono_disasm_code_one (NULL, cfg->method, inst->next->cil_code, NULL);
1151                 g_print ("found %p: %s", inst->next->cil_code, code);
1152                 g_free (code);*/
1153                 if (inst->cil_code < second->cil_code && inst->next->cil_code >= second->cil_code) {
1154                         second->code = inst->next;
1155                         inst->next = NULL;
1156                         first->last_ins = inst;
1157                         second->next_bb = first->next_bb;
1158                         first->next_bb = second;
1159                         return;
1160                 }
1161         }
1162         if (!second->code) {
1163                 g_warning ("bblock split failed in %s::%s\n", cfg->method->klass->name, cfg->method->name);
1164                 //G_BREAKPOINT ();
1165         }
1166 }
1167
1168 guint32
1169 mono_reverse_branch_op (guint32 opcode)
1170 {
1171         static const int reverse_map [] = {
1172                 CEE_BNE_UN, CEE_BLT, CEE_BLE, CEE_BGT, CEE_BGE,
1173                 CEE_BEQ, CEE_BLT_UN, CEE_BLE_UN, CEE_BGT_UN, CEE_BGE_UN
1174         };
1175         static const int reverse_fmap [] = {
1176                 OP_FBNE_UN, OP_FBLT, OP_FBLE, OP_FBGT, OP_FBGE,
1177                 OP_FBEQ, OP_FBLT_UN, OP_FBLE_UN, OP_FBGT_UN, OP_FBGE_UN
1178         };
1179         static const int reverse_lmap [] = {
1180                 OP_LBNE_UN, OP_LBLT, OP_LBLE, OP_LBGT, OP_LBGE,
1181                 OP_LBEQ, OP_LBLT_UN, OP_LBLE_UN, OP_LBGT_UN, OP_LBGE_UN
1182         };
1183         static const int reverse_imap [] = {
1184                 OP_IBNE_UN, OP_IBLT, OP_IBLE, OP_IBGT, OP_IBGE,
1185                 OP_IBEQ, OP_IBLT_UN, OP_IBLE_UN, OP_IBGT_UN, OP_IBGE_UN
1186         };
1187                                 
1188         if (opcode >= CEE_BEQ && opcode <= CEE_BLT_UN) {
1189                 opcode = reverse_map [opcode - CEE_BEQ];
1190         } else if (opcode >= OP_FBEQ && opcode <= OP_FBLT_UN) {
1191                 opcode = reverse_fmap [opcode - OP_FBEQ];
1192         } else if (opcode >= OP_LBEQ && opcode <= OP_LBLT_UN) {
1193                 opcode = reverse_lmap [opcode - OP_LBEQ];
1194         } else if (opcode >= OP_IBEQ && opcode <= OP_IBLT_UN) {
1195                 opcode = reverse_imap [opcode - OP_IBEQ];
1196         } else
1197                 g_assert_not_reached ();
1198
1199         return opcode;
1200 }
1201
1202 guint
1203 mono_type_to_store_membase (MonoCompile *cfg, MonoType *type)
1204 {
1205         if (type->byref)
1206                 return OP_STORE_MEMBASE_REG;
1207
1208 handle_enum:
1209         switch (type->type) {
1210         case MONO_TYPE_I1:
1211         case MONO_TYPE_U1:
1212         case MONO_TYPE_BOOLEAN:
1213                 return OP_STOREI1_MEMBASE_REG;
1214         case MONO_TYPE_I2:
1215         case MONO_TYPE_U2:
1216         case MONO_TYPE_CHAR:
1217                 return OP_STOREI2_MEMBASE_REG;
1218         case MONO_TYPE_I4:
1219         case MONO_TYPE_U4:
1220                 return OP_STOREI4_MEMBASE_REG;
1221         case MONO_TYPE_I:
1222         case MONO_TYPE_U:
1223         case MONO_TYPE_PTR:
1224         case MONO_TYPE_FNPTR:
1225                 return OP_STORE_MEMBASE_REG;
1226         case MONO_TYPE_CLASS:
1227         case MONO_TYPE_STRING:
1228         case MONO_TYPE_OBJECT:
1229         case MONO_TYPE_SZARRAY:
1230         case MONO_TYPE_ARRAY:    
1231                 return OP_STORE_MEMBASE_REG;
1232         case MONO_TYPE_I8:
1233         case MONO_TYPE_U8:
1234                 return OP_STOREI8_MEMBASE_REG;
1235         case MONO_TYPE_R4:
1236                 return OP_STORER4_MEMBASE_REG;
1237         case MONO_TYPE_R8:
1238                 return OP_STORER8_MEMBASE_REG;
1239         case MONO_TYPE_VALUETYPE:
1240                 if (type->data.klass->enumtype) {
1241                         type = type->data.klass->enum_basetype;
1242                         goto handle_enum;
1243                 }
1244                 return OP_STOREV_MEMBASE;
1245         case MONO_TYPE_TYPEDBYREF:
1246                 return OP_STOREV_MEMBASE;
1247         case MONO_TYPE_GENERICINST:
1248                 type = &type->data.generic_class->container_class->byval_arg;
1249                 goto handle_enum;
1250         case MONO_TYPE_VAR:
1251         case MONO_TYPE_MVAR:
1252                 /* FIXME: all the arguments must be references for now,
1253                  * later look inside cfg and see if the arg num is
1254                  * really a reference
1255                  */
1256                 g_assert (cfg->generic_sharing_context);
1257                 return OP_STORE_MEMBASE_REG;
1258         default:
1259                 g_error ("unknown type 0x%02x in type_to_store_membase", type->type);
1260         }
1261         return -1;
1262 }
1263
1264 guint
1265 mono_type_to_load_membase (MonoCompile *cfg, MonoType *type)
1266 {
1267         if (type->byref)
1268                 return OP_LOAD_MEMBASE;
1269
1270         switch (mono_type_get_underlying_type (type)->type) {
1271         case MONO_TYPE_I1:
1272                 return OP_LOADI1_MEMBASE;
1273         case MONO_TYPE_U1:
1274         case MONO_TYPE_BOOLEAN:
1275                 return OP_LOADU1_MEMBASE;
1276         case MONO_TYPE_I2:
1277                 return OP_LOADI2_MEMBASE;
1278         case MONO_TYPE_U2:
1279         case MONO_TYPE_CHAR:
1280                 return OP_LOADU2_MEMBASE;
1281         case MONO_TYPE_I4:
1282                 return OP_LOADI4_MEMBASE;
1283         case MONO_TYPE_U4:
1284                 return OP_LOADU4_MEMBASE;
1285         case MONO_TYPE_I:
1286         case MONO_TYPE_U:
1287         case MONO_TYPE_PTR:
1288         case MONO_TYPE_FNPTR:
1289                 return OP_LOAD_MEMBASE;
1290         case MONO_TYPE_CLASS:
1291         case MONO_TYPE_STRING:
1292         case MONO_TYPE_OBJECT:
1293         case MONO_TYPE_SZARRAY:
1294         case MONO_TYPE_ARRAY:    
1295                 return OP_LOAD_MEMBASE;
1296         case MONO_TYPE_I8:
1297         case MONO_TYPE_U8:
1298                 return OP_LOADI8_MEMBASE;
1299         case MONO_TYPE_R4:
1300                 return OP_LOADR4_MEMBASE;
1301         case MONO_TYPE_R8:
1302                 return OP_LOADR8_MEMBASE;
1303         case MONO_TYPE_VALUETYPE:
1304         case MONO_TYPE_TYPEDBYREF:
1305                 return OP_LOADV_MEMBASE;
1306         case MONO_TYPE_GENERICINST:
1307                 if (mono_type_generic_inst_is_valuetype (type))
1308                         return OP_LOADV_MEMBASE;
1309                 else
1310                         return OP_LOAD_MEMBASE;
1311                 break;
1312         case MONO_TYPE_VAR:
1313         case MONO_TYPE_MVAR:
1314                 /* FIXME: all the arguments must be references for now,
1315                  * later look inside cfg and see if the arg num is
1316                  * really a reference
1317                  */
1318                 g_assert (cfg->generic_sharing_context);
1319                 return OP_LOAD_MEMBASE;
1320         default:
1321                 g_error ("unknown type 0x%02x in type_to_load_membase", type->type);
1322         }
1323         return -1;
1324 }
1325
1326 #ifdef MONO_ARCH_SOFT_FLOAT
1327 static int
1328 condbr_to_fp_br (int opcode)
1329 {
1330         switch (opcode) {
1331         case CEE_BEQ: return OP_FBEQ;
1332         case CEE_BGE: return OP_FBGE;
1333         case CEE_BGT: return OP_FBGT;
1334         case CEE_BLE: return OP_FBLE;
1335         case CEE_BLT: return OP_FBLT;
1336         case CEE_BNE_UN: return OP_FBNE_UN;
1337         case CEE_BGE_UN: return OP_FBGE_UN;
1338         case CEE_BGT_UN: return OP_FBGT_UN;
1339         case CEE_BLE_UN: return OP_FBLE_UN;
1340         case CEE_BLT_UN: return OP_FBLT_UN;
1341         }
1342         g_assert_not_reached ();
1343         return 0;
1344 }
1345 #endif
1346
1347 /*
1348  * Returns the type used in the eval stack when @type is loaded.
1349  * FIXME: return a MonoType/MonoClass for the byref and VALUETYPE cases.
1350  */
1351 static void
1352 type_to_eval_stack_type (MonoCompile *cfg, MonoType *type, MonoInst *inst)
1353 {
1354         MonoClass *klass;
1355
1356         inst->klass = klass = mono_class_from_mono_type (type);
1357         if (type->byref) {
1358                 inst->type = STACK_MP;
1359                 return;
1360         }
1361
1362 handle_enum:
1363         switch (type->type) {
1364         case MONO_TYPE_VOID:
1365                 inst->type = STACK_INV;
1366                 return;
1367         case MONO_TYPE_I1:
1368         case MONO_TYPE_U1:
1369         case MONO_TYPE_BOOLEAN:
1370         case MONO_TYPE_I2:
1371         case MONO_TYPE_U2:
1372         case MONO_TYPE_CHAR:
1373         case MONO_TYPE_I4:
1374         case MONO_TYPE_U4:
1375                 inst->type = STACK_I4;
1376                 return;
1377         case MONO_TYPE_I:
1378         case MONO_TYPE_U:
1379         case MONO_TYPE_PTR:
1380         case MONO_TYPE_FNPTR:
1381                 inst->type = STACK_PTR;
1382                 return;
1383         case MONO_TYPE_CLASS:
1384         case MONO_TYPE_STRING:
1385         case MONO_TYPE_OBJECT:
1386         case MONO_TYPE_SZARRAY:
1387         case MONO_TYPE_ARRAY:    
1388                 inst->type = STACK_OBJ;
1389                 return;
1390         case MONO_TYPE_I8:
1391         case MONO_TYPE_U8:
1392                 inst->type = STACK_I8;
1393                 return;
1394         case MONO_TYPE_R4:
1395         case MONO_TYPE_R8:
1396                 inst->type = STACK_R8;
1397                 return;
1398         case MONO_TYPE_VALUETYPE:
1399                 if (type->data.klass->enumtype) {
1400                         type = type->data.klass->enum_basetype;
1401                         goto handle_enum;
1402                 } else {
1403                         inst->klass = klass;
1404                         inst->type = STACK_VTYPE;
1405                         return;
1406                 }
1407         case MONO_TYPE_TYPEDBYREF:
1408                 inst->klass = mono_defaults.typed_reference_class;
1409                 inst->type = STACK_VTYPE;
1410                 return;
1411         case MONO_TYPE_GENERICINST:
1412                 type = &type->data.generic_class->container_class->byval_arg;
1413                 goto handle_enum;
1414         case MONO_TYPE_VAR :
1415         case MONO_TYPE_MVAR :
1416                 /* FIXME: all the arguments must be references for now,
1417                  * later look inside cfg and see if the arg num is
1418                  * really a reference
1419                  */
1420                 g_assert (cfg->generic_sharing_context);
1421                 inst->type = STACK_OBJ;
1422                 return;
1423         default:
1424                 g_error ("unknown type 0x%02x in eval stack type", type->type);
1425         }
1426 }
1427
1428 /*
1429  * The following tables are used to quickly validate the IL code in type_from_op ().
1430  */
1431 static const char
1432 bin_num_table [STACK_MAX] [STACK_MAX] = {
1433         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1434         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
1435         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1436         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
1437         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_R8,  STACK_INV, STACK_INV, STACK_INV},
1438         {STACK_INV, STACK_MP,  STACK_INV, STACK_MP,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV},
1439         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1440         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
1441 };
1442
1443 static const char 
1444 neg_table [] = {
1445         STACK_INV, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_INV, STACK_INV, STACK_INV
1446 };
1447
1448 /* reduce the size of this table */
1449 static const char
1450 bin_int_table [STACK_MAX] [STACK_MAX] = {
1451         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1452         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1453         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1454         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1455         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1456         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1457         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1458         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
1459 };
1460
1461 static const char
1462 bin_comp_table [STACK_MAX] [STACK_MAX] = {
1463 /*      Inv i  L  p  F  &  O  vt */
1464         {0},
1465         {0, 1, 0, 1, 0, 0, 0, 0}, /* i, int32 */
1466         {0, 0, 1, 0, 0, 0, 0, 0}, /* L, int64 */
1467         {0, 1, 0, 1, 0, 2, 4, 0}, /* p, ptr */
1468         {0, 0, 0, 0, 1, 0, 0, 0}, /* F, R8 */
1469         {0, 0, 0, 2, 0, 1, 0, 0}, /* &, managed pointer */
1470         {0, 0, 0, 4, 0, 0, 3, 0}, /* O, reference */
1471         {0, 0, 0, 0, 0, 0, 0, 0}, /* vt value type */
1472 };
1473
1474 /* reduce the size of this table */
1475 static const char
1476 shift_table [STACK_MAX] [STACK_MAX] = {
1477         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1478         {STACK_INV, STACK_I4,  STACK_INV, STACK_I4,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1479         {STACK_INV, STACK_I8,  STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1480         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1481         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1482         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1483         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
1484         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
1485 };
1486
1487 /*
1488  * Tables to map from the non-specific opcode to the matching
1489  * type-specific opcode.
1490  */
1491 /* handles from CEE_ADD to CEE_SHR_UN (CEE_REM_UN for floats) */
1492 static const guint16
1493 binops_op_map [STACK_MAX] = {
1494         0, 0, OP_LADD-CEE_ADD, OP_PADD-CEE_ADD, OP_FADD-CEE_ADD, OP_PADD-CEE_ADD
1495 };
1496
1497 /* handles from CEE_NEG to CEE_CONV_U8 */
1498 static const guint16
1499 unops_op_map [STACK_MAX] = {
1500         0, 0, OP_LNEG-CEE_NEG, OP_PNEG-CEE_NEG, OP_FNEG-CEE_NEG, OP_PNEG-CEE_NEG
1501 };
1502
1503 /* handles from CEE_CONV_U2 to CEE_SUB_OVF_UN */
1504 static const guint16
1505 ovfops_op_map [STACK_MAX] = {
1506         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
1507 };
1508
1509 /* handles from CEE_CONV_OVF_I1_UN to CEE_CONV_OVF_U_UN */
1510 static const guint16
1511 ovf2ops_op_map [STACK_MAX] = {
1512         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
1513 };
1514
1515 /* handles from CEE_CONV_OVF_I1 to CEE_CONV_OVF_U8 */
1516 static const guint16
1517 ovf3ops_op_map [STACK_MAX] = {
1518         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
1519 };
1520
1521 /* handles from CEE_CEQ to CEE_CLT_UN */
1522 static const guint16
1523 ceqops_op_map [STACK_MAX] = {
1524         0, 0, OP_LCEQ-OP_CEQ, OP_PCEQ-OP_CEQ, OP_FCEQ-OP_CEQ, OP_LCEQ-OP_CEQ
1525 };
1526
1527 /*
1528  * Sets ins->type (the type on the eval stack) according to the
1529  * type of the opcode and the arguments to it.
1530  * Invalid IL code is marked by setting ins->type to the invalid value STACK_INV.
1531  *
1532  * FIXME: this function sets ins->type unconditionally in some cases, but
1533  * it should set it to invalid for some types (a conv.x on an object)
1534  */
1535 static void
1536 type_from_op (MonoInst *ins) {
1537         switch (ins->opcode) {
1538         /* binops */
1539         case CEE_ADD:
1540         case CEE_SUB:
1541         case CEE_MUL:
1542         case CEE_DIV:
1543         case CEE_REM:
1544                 /* FIXME: check unverifiable args for STACK_MP */
1545                 ins->type = bin_num_table [ins->inst_i0->type] [ins->inst_i1->type];
1546                 ins->opcode += binops_op_map [ins->type];
1547                 return;
1548         case CEE_DIV_UN:
1549         case CEE_REM_UN:
1550         case CEE_AND:
1551         case CEE_OR:
1552         case CEE_XOR:
1553                 ins->type = bin_int_table [ins->inst_i0->type] [ins->inst_i1->type];
1554                 ins->opcode += binops_op_map [ins->type];
1555                 return;
1556         case CEE_SHL:
1557         case CEE_SHR:
1558         case CEE_SHR_UN:
1559                 ins->type = shift_table [ins->inst_i0->type] [ins->inst_i1->type];
1560                 ins->opcode += binops_op_map [ins->type];
1561                 return;
1562         case OP_COMPARE:
1563         case OP_LCOMPARE:
1564                 /* FIXME: handle some specifics with ins->next->type */
1565                 ins->type = bin_comp_table [ins->inst_i0->type] [ins->inst_i1->type] ? STACK_I4: STACK_INV;
1566                 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))))
1567                         ins->opcode = OP_LCOMPARE;
1568                 return;
1569         case OP_CEQ:
1570                 ins->type = bin_comp_table [ins->inst_i0->type] [ins->inst_i1->type] ? STACK_I4: STACK_INV;
1571                 ins->opcode += ceqops_op_map [ins->inst_i0->type];
1572                 return;
1573                 
1574         case OP_CGT:
1575         case OP_CGT_UN:
1576         case OP_CLT:
1577         case OP_CLT_UN:
1578                 ins->type = (bin_comp_table [ins->inst_i0->type] [ins->inst_i1->type] & 1) ? STACK_I4: STACK_INV;
1579                 ins->opcode += ceqops_op_map [ins->inst_i0->type];
1580                 return;
1581         /* unops */
1582         case CEE_NEG:
1583                 ins->type = neg_table [ins->inst_i0->type];
1584                 ins->opcode += unops_op_map [ins->type];
1585                 return;
1586         case CEE_NOT:
1587                 if (ins->inst_i0->type >= STACK_I4 && ins->inst_i0->type <= STACK_PTR)
1588                         ins->type = ins->inst_i0->type;
1589                 else
1590                         ins->type = STACK_INV;
1591                 ins->opcode += unops_op_map [ins->type];
1592                 return;
1593         case CEE_CONV_I1:
1594         case CEE_CONV_I2:
1595         case CEE_CONV_I4:
1596         case CEE_CONV_U4:
1597                 ins->type = STACK_I4;
1598                 ins->opcode += unops_op_map [ins->inst_i0->type];
1599                 return;
1600         case CEE_CONV_R_UN:
1601                 ins->type = STACK_R8;
1602                 switch (ins->inst_i0->type) {
1603                 case STACK_I4:
1604                 case STACK_PTR:
1605                         break;
1606                 case STACK_I8:
1607                         ins->opcode = OP_LCONV_TO_R_UN; 
1608                         break;
1609                 }
1610                 return;
1611         case CEE_CONV_OVF_I1:
1612         case CEE_CONV_OVF_U1:
1613         case CEE_CONV_OVF_I2:
1614         case CEE_CONV_OVF_U2:
1615         case CEE_CONV_OVF_I4:
1616         case CEE_CONV_OVF_U4:
1617                 ins->type = STACK_I4;
1618                 ins->opcode += ovf3ops_op_map [ins->inst_i0->type];
1619                 return;
1620         case CEE_CONV_OVF_I_UN:
1621         case CEE_CONV_OVF_U_UN:
1622                 ins->type = STACK_PTR;
1623                 ins->opcode += ovf2ops_op_map [ins->inst_i0->type];
1624                 return;
1625         case CEE_CONV_OVF_I1_UN:
1626         case CEE_CONV_OVF_I2_UN:
1627         case CEE_CONV_OVF_I4_UN:
1628         case CEE_CONV_OVF_U1_UN:
1629         case CEE_CONV_OVF_U2_UN:
1630         case CEE_CONV_OVF_U4_UN:
1631                 ins->type = STACK_I4;
1632                 ins->opcode += ovf2ops_op_map [ins->inst_i0->type];
1633                 return;
1634         case CEE_CONV_U:
1635                 ins->type = STACK_PTR;
1636                 switch (ins->inst_i0->type) {
1637                 case STACK_I4:
1638                         break;
1639                 case STACK_PTR:
1640                 case STACK_MP:
1641 #if SIZEOF_VOID_P == 8
1642                         ins->opcode = OP_LCONV_TO_U;
1643 #endif
1644                         break;
1645                 case STACK_I8:
1646                         ins->opcode = OP_LCONV_TO_U;
1647                         break;
1648                 case STACK_R8:
1649                         ins->opcode = OP_FCONV_TO_U;
1650                         break;
1651                 }
1652                 return;
1653         case CEE_CONV_I8:
1654         case CEE_CONV_U8:
1655                 ins->type = STACK_I8;
1656                 ins->opcode += unops_op_map [ins->inst_i0->type];
1657                 return;
1658         case CEE_CONV_OVF_I8:
1659         case CEE_CONV_OVF_U8:
1660                 ins->type = STACK_I8;
1661                 ins->opcode += ovf3ops_op_map [ins->inst_i0->type];
1662                 return;
1663         case CEE_CONV_OVF_U8_UN:
1664         case CEE_CONV_OVF_I8_UN:
1665                 ins->type = STACK_I8;
1666                 ins->opcode += ovf2ops_op_map [ins->inst_i0->type];
1667                 return;
1668         case CEE_CONV_R4:
1669         case CEE_CONV_R8:
1670                 ins->type = STACK_R8;
1671                 ins->opcode += unops_op_map [ins->inst_i0->type];
1672                 return;
1673         case OP_CKFINITE:
1674                 ins->type = STACK_R8;           
1675                 return;
1676         case CEE_CONV_U2:
1677         case CEE_CONV_U1:
1678                 ins->type = STACK_I4;
1679                 ins->opcode += ovfops_op_map [ins->inst_i0->type];
1680                 break;
1681         case CEE_CONV_I:
1682         case CEE_CONV_OVF_I:
1683         case CEE_CONV_OVF_U:
1684                 ins->type = STACK_PTR;
1685                 ins->opcode += ovfops_op_map [ins->inst_i0->type];
1686                 return;
1687         case CEE_ADD_OVF:
1688         case CEE_ADD_OVF_UN:
1689         case CEE_MUL_OVF:
1690         case CEE_MUL_OVF_UN:
1691         case CEE_SUB_OVF:
1692         case CEE_SUB_OVF_UN:
1693                 ins->type = bin_num_table [ins->inst_i0->type] [ins->inst_i1->type];
1694                 ins->opcode += ovfops_op_map [ins->inst_i0->type];
1695                 if (ins->type == STACK_R8)
1696                         ins->type = STACK_INV;
1697                 return;
1698         default:
1699                 g_error ("opcode 0x%04x not handled in type from op", ins->opcode);
1700                 break;
1701         }
1702 }
1703
1704 static const char 
1705 ldind_type [] = {
1706         STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_R8, STACK_OBJ
1707 };
1708
1709 /* map ldelem.x to the matching ldind.x opcode */
1710 static const guchar
1711 ldelem_to_ldind [] = {
1712         CEE_LDIND_I1,
1713         CEE_LDIND_U1,
1714         CEE_LDIND_I2,
1715         CEE_LDIND_U2,
1716         CEE_LDIND_I4,
1717         CEE_LDIND_U4,
1718         CEE_LDIND_I8,
1719         CEE_LDIND_I,
1720         CEE_LDIND_R4,
1721         CEE_LDIND_R8,
1722         CEE_LDIND_REF
1723 };
1724
1725 /* map stelem.x to the matching stind.x opcode */
1726 static const guchar
1727 stelem_to_stind [] = {
1728         CEE_STIND_I,
1729         CEE_STIND_I1,
1730         CEE_STIND_I2,
1731         CEE_STIND_I4,
1732         CEE_STIND_I8,
1733         CEE_STIND_R4,
1734         CEE_STIND_R8,
1735         CEE_STIND_REF
1736 };
1737
1738
1739 #ifdef MONO_ARCH_SOFT_FLOAT
1740 static void
1741 handle_store_float (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *ptr, MonoInst *val, const unsigned char *ip)
1742 {
1743         MonoInst *iargs [2];
1744         iargs [0] = val;
1745         iargs [1] = ptr;
1746
1747         mono_emit_jit_icall (cfg, bblock, mono_fstore_r4, iargs, ip);
1748 }
1749
1750 static int
1751 handle_load_float (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *ptr, const unsigned char *ip)
1752 {
1753         MonoInst *iargs [1];
1754         iargs [0] = ptr;
1755
1756         return mono_emit_jit_icall (cfg, bblock, mono_fload_r4, iargs, ip);
1757 }
1758
1759 #define LDLOC_SOFT_FLOAT(cfg,ins,idx,ip) do {\
1760                 if (header->locals [(idx)]->type == MONO_TYPE_R4 && !header->locals [(idx)]->byref) {   \
1761                         int temp;       \
1762                         NEW_LOCLOADA (cfg, (ins), (idx));       \
1763                         temp = handle_load_float (cfg, bblock, (ins), (ip));    \
1764                         NEW_TEMPLOAD (cfg, (ins), temp);        \
1765                 }       \
1766         } while (0)
1767 #define STLOC_SOFT_FLOAT(cfg,ins,idx,ip) do {\
1768                 if (header->locals [(idx)]->type == MONO_TYPE_R4 && !header->locals [(idx)]->byref) {   \
1769                         NEW_LOCLOADA (cfg, (ins), (idx));       \
1770                         handle_store_float (cfg, bblock, (ins), *sp, (ip));     \
1771                         MONO_INST_NEW (cfg, (ins), OP_NOP);     \
1772                 }       \
1773         } while (0)
1774 #define LDARG_SOFT_FLOAT(cfg,ins,idx,ip) do {\
1775                 if (param_types [(idx)]->type == MONO_TYPE_R4 && !param_types [(idx)]->byref) { \
1776                         int temp;       \
1777                         NEW_ARGLOADA (cfg, (ins), (idx));       \
1778                         temp = handle_load_float (cfg, bblock, (ins), (ip));    \
1779                         NEW_TEMPLOAD (cfg, (ins), temp);        \
1780                 }       \
1781         } while (0)
1782 #define STARG_SOFT_FLOAT(cfg,ins,idx,ip) do {\
1783                 if (param_types [(idx)]->type == MONO_TYPE_R4 && !param_types [(idx)]->byref) { \
1784                         NEW_ARGLOADA (cfg, (ins), (idx));       \
1785                         handle_store_float (cfg, bblock, (ins), *sp, (ip));     \
1786                         MONO_INST_NEW (cfg, (ins), OP_NOP);     \
1787                 }       \
1788         } while (0)
1789
1790 #define NEW_TEMPLOAD_SOFT_FLOAT(cfg,bblock,ins,num,ip) do {             \
1791         if ((ins)->opcode == CEE_LDIND_R4) {                                            \
1792             int idx = (num);                                                                            \
1793             int temp;                                                                                   \
1794             NEW_TEMPLOADA (cfg, (ins), (idx));                                                  \
1795                 temp = handle_load_float (cfg, (bblock), (ins), ip);            \
1796                 NEW_TEMPLOAD (cfg, (ins), (temp));                                                      \
1797         }                                                                                                                               \
1798         } while (0)
1799
1800 #define NEW_TEMPSTORE_SOFT_FLOAT(cfg,bblock,ins,num,val,ip) do {                \
1801         if ((ins)->opcode == CEE_STIND_R4) {                                                            \
1802             int idx = (num);                                                                            \
1803                 NEW_TEMPLOADA (cfg, (ins), (idx)); \
1804                 handle_store_float ((cfg), (bblock), (ins), (val), (ip));       \
1805         } \
1806         } while (0)
1807
1808 #else
1809
1810 #define LDLOC_SOFT_FLOAT(cfg,ins,idx,ip)
1811 #define STLOC_SOFT_FLOAT(cfg,ins,idx,ip)
1812 #define LDARG_SOFT_FLOAT(cfg,ins,idx,ip)
1813 #define STARG_SOFT_FLOAT(cfg,ins,idx,ip)
1814 #define NEW_TEMPLOAD_SOFT_FLOAT(cfg,bblock,ins,num,ip)
1815 #define NEW_TEMPSTORE_SOFT_FLOAT(cfg,bblock,ins,num,val,ip)
1816 #endif
1817
1818 #if 0
1819
1820 static const char
1821 param_table [STACK_MAX] [STACK_MAX] = {
1822         {0},
1823 };
1824
1825 static int
1826 check_values_to_signature (MonoInst *args, MonoType *this, MonoMethodSignature *sig)
1827 {
1828         int i;
1829
1830         if (sig->hasthis) {
1831                 switch (args->type) {
1832                 case STACK_I4:
1833                 case STACK_I8:
1834                 case STACK_R8:
1835                 case STACK_VTYPE:
1836                 case STACK_INV:
1837                         return 0;
1838                 }
1839                 args++;
1840         }
1841         for (i = 0; i < sig->param_count; ++i) {
1842                 switch (args [i].type) {
1843                 case STACK_INV:
1844                         return 0;
1845                 case STACK_MP:
1846                         if (!sig->params [i]->byref)
1847                                 return 0;
1848                         continue;
1849                 case STACK_OBJ:
1850                         if (sig->params [i]->byref)
1851                                 return 0;
1852                         switch (sig->params [i]->type) {
1853                         case MONO_TYPE_CLASS:
1854                         case MONO_TYPE_STRING:
1855                         case MONO_TYPE_OBJECT:
1856                         case MONO_TYPE_SZARRAY:
1857                         case MONO_TYPE_ARRAY:
1858                                 break;
1859                         default:
1860                                 return 0;
1861                         }
1862                         continue;
1863                 case STACK_R8:
1864                         if (sig->params [i]->byref)
1865                                 return 0;
1866                         if (sig->params [i]->type != MONO_TYPE_R4 && sig->params [i]->type != MONO_TYPE_R8)
1867                                 return 0;
1868                         continue;
1869                 case STACK_PTR:
1870                 case STACK_I4:
1871                 case STACK_I8:
1872                 case STACK_VTYPE:
1873                         break;
1874                 }
1875                 /*if (!param_table [args [i].type] [sig->params [i]->type])
1876                         return 0;*/
1877         }
1878         return 1;
1879 }
1880 #endif
1881
1882 static guint
1883 mini_type_to_ldind (MonoCompile* cfg, MonoType *type)
1884 {
1885         if (cfg->generic_sharing_context && !type->byref) {
1886                 /* FIXME: all the arguments must be references for now,
1887                  * later look inside cfg and see if the arg num is
1888                  * really a reference
1889                  */
1890                 if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)
1891                         return CEE_LDIND_REF;
1892         }
1893         return mono_type_to_ldind (type);
1894 }
1895
1896 guint
1897 mini_type_to_stind (MonoCompile* cfg, MonoType *type)
1898 {
1899         if (cfg->generic_sharing_context && !type->byref) {
1900                 /* FIXME: all the arguments must be references for now,
1901                  * later look inside cfg and see if the arg num is
1902                  * really a reference
1903                  */
1904                 if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)
1905                         return CEE_STIND_REF;
1906         }
1907         return mono_type_to_stind (type);
1908 }
1909
1910 int
1911 mono_op_imm_to_op (int opcode)
1912 {
1913         switch (opcode) {
1914         case OP_ADD_IMM:
1915 #if SIZEOF_VOID_P == 4
1916                 return OP_IADD;
1917 #else
1918                 return OP_LADD;
1919 #endif
1920         case OP_IADD_IMM:
1921                 return OP_IADD;
1922         case OP_LADD_IMM:
1923                 return OP_LADD;
1924         case OP_ISUB_IMM:
1925                 return OP_ISUB;
1926         case OP_LSUB_IMM:
1927                 return OP_LSUB;
1928         case OP_IMUL_IMM:
1929                 return OP_IMUL;
1930         case OP_AND_IMM:
1931 #if SIZEOF_VOID_P == 4
1932                 return OP_IAND;
1933 #else
1934                 return OP_LAND;
1935 #endif
1936         case OP_IAND_IMM:
1937                 return OP_IAND;
1938         case OP_LAND_IMM:
1939                 return OP_LAND;
1940         case OP_IOR_IMM:
1941                 return OP_IOR;
1942         case OP_LOR_IMM:
1943                 return OP_LOR;
1944         case OP_IXOR_IMM:
1945                 return OP_IXOR;
1946         case OP_LXOR_IMM:
1947                 return OP_LXOR;
1948         case OP_ISHL_IMM:
1949                 return OP_ISHL;
1950         case OP_LSHL_IMM:
1951                 return OP_LSHL;
1952         case OP_ISHR_IMM:
1953                 return OP_ISHR;
1954         case OP_LSHR_IMM:
1955                 return OP_LSHR;
1956         case OP_ISHR_UN_IMM:
1957                 return OP_ISHR_UN;
1958         case OP_LSHR_UN_IMM:
1959                 return OP_LSHR_UN;
1960         case OP_IDIV_IMM:
1961                 return OP_IDIV;
1962         case OP_IDIV_UN_IMM:
1963                 return OP_IDIV_UN;
1964         case OP_IREM_UN_IMM:
1965                 return OP_IREM_UN;
1966         case OP_IREM_IMM:
1967                 return OP_IREM;
1968         case OP_DIV_IMM:
1969 #if SIZEOF_VOID_P == 4
1970                 return OP_IDIV;
1971 #else
1972                 return OP_LDIV;
1973 #endif
1974         case OP_REM_IMM:
1975 #if SIZEOF_VOID_P == 4
1976                 return OP_IREM;
1977 #else
1978                 return OP_LREM;
1979 #endif
1980         case OP_ADDCC_IMM:
1981                 return OP_ADDCC;
1982         case OP_ADC_IMM:
1983                 return OP_ADC;
1984         case OP_SUBCC_IMM:
1985                 return OP_SUBCC;
1986         case OP_SBB_IMM:
1987                 return OP_SBB;
1988         case OP_IADC_IMM:
1989                 return OP_IADC;
1990         case OP_ISBB_IMM:
1991                 return OP_ISBB;
1992         case OP_COMPARE_IMM:
1993                 return OP_COMPARE;
1994         case OP_ICOMPARE_IMM:
1995                 return OP_ICOMPARE;
1996         case OP_LOCALLOC_IMM:
1997                 return OP_LOCALLOC;
1998         default:
1999                 printf ("%s\n", mono_inst_name (opcode));
2000                 g_assert_not_reached ();
2001                 return -1;
2002         }
2003 }
2004
2005 /*
2006  * mono_decompose_op_imm:
2007  *
2008  *   Replace the OP_.._IMM INS with its non IMM variant.
2009  */
2010 void
2011 mono_decompose_op_imm (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst *ins)
2012 {
2013         MonoInst *temp;
2014
2015         MONO_INST_NEW (cfg, temp, OP_ICONST);
2016         temp->inst_c0 = ins->inst_imm;
2017         temp->dreg = mono_regstate_next_int (cfg->rs);
2018         mono_bblock_insert_before_ins (bb, ins, temp);
2019         ins->opcode = mono_op_imm_to_op (ins->opcode);
2020         if (ins->opcode == OP_LOCALLOC)
2021                 ins->sreg1 = temp->dreg;
2022         else
2023                 ins->sreg2 = temp->dreg;
2024
2025         bb->max_vreg = MAX (bb->max_vreg, cfg->rs->next_vreg);
2026 }
2027
2028 /*
2029  * When we need a pointer to the current domain many times in a method, we
2030  * call mono_domain_get() once and we store the result in a local variable.
2031  * This function returns the variable that represents the MonoDomain*.
2032  */
2033 inline static MonoInst *
2034 mono_get_domainvar (MonoCompile *cfg)
2035 {
2036         if (!cfg->domainvar)
2037                 cfg->domainvar = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2038         return cfg->domainvar;
2039 }
2040
2041 /*
2042  * The got_var contains the address of the Global Offset Table when AOT 
2043  * compiling.
2044  */
2045 inline static MonoInst *
2046 mono_get_got_var (MonoCompile *cfg)
2047 {
2048 #ifdef MONO_ARCH_NEED_GOT_VAR
2049         if (!cfg->compile_aot)
2050                 return NULL;
2051         if (!cfg->got_var) {
2052                 cfg->got_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2053         }
2054         return cfg->got_var;
2055 #else
2056         return NULL;
2057 #endif
2058 }
2059
2060 static MonoInst *
2061 mono_get_vtable_var (MonoCompile *cfg)
2062 {
2063         g_assert (cfg->generic_sharing_context);
2064
2065         if (!cfg->rgctx_var) {
2066                 cfg->rgctx_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2067                 /* force the var to be stack allocated */
2068                 cfg->rgctx_var->flags |= MONO_INST_INDIRECT;
2069         }
2070
2071         return cfg->rgctx_var;
2072 }
2073
2074 static void
2075 set_vreg_to_inst (MonoCompile *cfg, int vreg, MonoInst *inst)
2076 {
2077         if (vreg >= cfg->vreg_to_inst_len) {
2078                 MonoInst **tmp = cfg->vreg_to_inst;
2079                 int size = cfg->vreg_to_inst_len;
2080
2081                 while (vreg >= cfg->vreg_to_inst_len)
2082                         cfg->vreg_to_inst_len = cfg->vreg_to_inst_len ? cfg->vreg_to_inst_len * 2 : 32;
2083                 cfg->vreg_to_inst = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * cfg->vreg_to_inst_len);
2084                 if (size)
2085                         memcpy (cfg->vreg_to_inst, tmp, size * sizeof (MonoInst*));
2086         }
2087         cfg->vreg_to_inst [vreg] = inst;
2088 }
2089
2090 #define mono_type_is_long(type) (!(type)->byref && ((mono_type_get_underlying_type (type)->type == MONO_TYPE_I8) || (mono_type_get_underlying_type (type)->type == MONO_TYPE_U8)))
2091 #define mono_type_is_float(type) (!(type)->byref && (((type)->type == MONO_TYPE_R8) || ((type)->type == MONO_TYPE_R4)))
2092
2093 MonoInst*
2094 mono_compile_create_var_for_vreg (MonoCompile *cfg, MonoType *type, int opcode, int vreg)
2095 {
2096         MonoInst *inst;
2097         int num = cfg->num_varinfo;
2098         gboolean regpair;
2099
2100         if ((num + 1) >= cfg->varinfo_count) {
2101                 int orig_count = cfg->varinfo_count;
2102                 cfg->varinfo_count = cfg->varinfo_count ? (cfg->varinfo_count * 2) : 64;
2103                 cfg->varinfo = (MonoInst **)g_realloc (cfg->varinfo, sizeof (MonoInst*) * cfg->varinfo_count);
2104                 cfg->vars = (MonoMethodVar *)g_realloc (cfg->vars, sizeof (MonoMethodVar) * cfg->varinfo_count);
2105                 memset (&cfg->vars [orig_count], 0, (cfg->varinfo_count - orig_count) * sizeof (MonoMethodVar));
2106         }
2107
2108         mono_jit_stats.allocate_var++;
2109
2110         MONO_INST_NEW (cfg, inst, opcode);
2111         inst->inst_c0 = num;
2112         inst->inst_vtype = type;
2113         inst->klass = mono_class_from_mono_type (type);
2114         type_to_eval_stack_type (cfg, type, inst);
2115         /* if set to 1 the variable is native */
2116         inst->backend.is_pinvoke = 0;
2117         inst->dreg = vreg;
2118
2119         cfg->varinfo [num] = inst;
2120
2121         MONO_INIT_VARINFO (&cfg->vars [num], num);
2122
2123         if (vreg != -1)
2124                 set_vreg_to_inst (cfg, vreg, inst);
2125
2126 #if SIZEOF_VOID_P == 4
2127 #ifdef MONO_ARCH_SOFT_FLOAT
2128         regpair = mono_type_is_long (type) || mono_type_is_float (type);
2129 #else
2130         regpair = mono_type_is_long (type);
2131 #endif
2132 #else
2133         regpair = FALSE;
2134 #endif
2135
2136         if (regpair) {
2137                 MonoInst *tree;
2138
2139                 /* 
2140                  * These two cannot be allocated using create_var_for_vreg since that would
2141                  * put it into the cfg->varinfo array, confusing many parts of the JIT.
2142                  */
2143
2144                 /* 
2145                  * Set flags to VOLATILE so SSA skips it.
2146                  */
2147
2148                 if (cfg->verbose_level >= 4) {
2149                         printf ("  Create LVAR R%d (R%d, R%d)\n", inst->dreg, inst->dreg + 1, inst->dreg + 2);
2150                 }
2151
2152 #ifdef MONO_ARCH_SOFT_FLOAT
2153                 if (cfg->opt & MONO_OPT_SSA) {
2154                         if (mono_type_is_float (type))
2155                                 inst->flags = MONO_INST_VOLATILE;
2156                 }
2157 #endif
2158
2159                 /* Allocate a dummy MonoInst for the first vreg */
2160                 MONO_INST_NEW (cfg, tree, OP_LOCAL);
2161                 tree->dreg = inst->dreg + 1;
2162                 if (cfg->opt & MONO_OPT_SSA)
2163                         tree->flags = MONO_INST_VOLATILE;
2164                 tree->inst_c0 = num;
2165                 tree->type = STACK_I4;
2166                 tree->inst_vtype = &mono_defaults.int32_class->byval_arg;
2167                 tree->klass = mono_class_from_mono_type (tree->inst_vtype);
2168
2169                 set_vreg_to_inst (cfg, inst->dreg + 1, tree);
2170
2171                 /* Allocate a dummy MonoInst for the second vreg */
2172                 MONO_INST_NEW (cfg, tree, OP_LOCAL);
2173                 tree->dreg = inst->dreg + 2;
2174                 if (cfg->opt & MONO_OPT_SSA)
2175                         tree->flags = MONO_INST_VOLATILE;
2176                 tree->inst_c0 = num;
2177                 tree->type = STACK_I4;
2178                 tree->inst_vtype = &mono_defaults.int32_class->byval_arg;
2179                 tree->klass = mono_class_from_mono_type (tree->inst_vtype);
2180
2181                 set_vreg_to_inst (cfg, inst->dreg + 2, tree);
2182         }
2183
2184         cfg->num_varinfo++;
2185         if (cfg->verbose_level > 2)
2186                 g_print ("created temp %d (R%d) of type %s\n", num, vreg, mono_type_get_name (type));
2187         return inst;
2188 }
2189
2190 MonoInst*
2191 mono_compile_create_var (MonoCompile *cfg, MonoType *type, int opcode)
2192 {
2193         int dreg;
2194
2195         if (mono_type_is_long (type))
2196                 dreg = mono_alloc_dreg (cfg, STACK_I8);
2197 #ifdef MONO_ARCH_SOFT_FLOAT
2198         else if (mono_type_is_float (type))
2199                 dreg = mono_alloc_dreg (cfg, STACK_R8);
2200 #endif
2201         else
2202                 /* All the others are unified */
2203                 dreg = mono_alloc_preg (cfg);
2204
2205         return mono_compile_create_var_for_vreg (cfg, type, opcode, dreg);
2206 }
2207
2208 /*
2209  * Transform a MonoInst into a load from the variable of index var_index.
2210  */
2211 void
2212 mono_compile_make_var_load (MonoCompile *cfg, MonoInst *dest, gssize var_index) {
2213         memset (dest, 0, sizeof (MonoInst));
2214         dest->ssa_op = MONO_SSA_LOAD;
2215         dest->inst_i0 = cfg->varinfo [var_index];
2216         dest->opcode = mini_type_to_ldind (cfg, dest->inst_i0->inst_vtype);
2217         type_to_eval_stack_type (cfg, dest->inst_i0->inst_vtype, dest);
2218         dest->klass = dest->inst_i0->klass;
2219 }
2220
2221 /*
2222  * Create a MonoInst that is a load from the variable of index var_index.
2223  */
2224 MonoInst*
2225 mono_compile_create_var_load (MonoCompile *cfg, gssize var_index) {
2226         MonoInst *dest;
2227         NEW_TEMPLOAD (cfg,dest,var_index);
2228         return dest;
2229 }
2230
2231 /*
2232  * Create a MonoInst that is a store of the given value into the variable of index var_index.
2233  */
2234 MonoInst*
2235 mono_compile_create_var_store (MonoCompile *cfg, gssize var_index, MonoInst *value) {
2236         MonoInst *dest;
2237         NEW_TEMPSTORE (cfg, dest, var_index, value);
2238         return dest;
2239 }
2240
2241 static MonoType*
2242 type_from_stack_type (MonoInst *ins) {
2243         switch (ins->type) {
2244         case STACK_I4: return &mono_defaults.int32_class->byval_arg;
2245         case STACK_I8: return &mono_defaults.int64_class->byval_arg;
2246         case STACK_PTR: return &mono_defaults.int_class->byval_arg;
2247         case STACK_R8: return &mono_defaults.double_class->byval_arg;
2248         case STACK_MP:
2249                 /* 
2250                  * this if used to be commented without any specific reason, but
2251                  * it breaks #80235 when commented
2252                  */
2253                 if (ins->klass)
2254                         return &ins->klass->this_arg;
2255                 else
2256                         return &mono_defaults.object_class->this_arg;
2257         case STACK_OBJ:
2258                 /* ins->klass may not be set for ldnull.
2259                  * Also, if we have a boxed valuetype, we want an object lass,
2260                  * not the valuetype class
2261                  */
2262                 if (ins->klass && !ins->klass->valuetype)
2263                         return &ins->klass->byval_arg;
2264                 return &mono_defaults.object_class->byval_arg;
2265         case STACK_VTYPE: return &ins->klass->byval_arg;
2266         default:
2267                 g_error ("stack type %d to montype not handled\n", ins->type);
2268         }
2269         return NULL;
2270 }
2271
2272 MonoType*
2273 mono_type_from_stack_type (MonoInst *ins) {
2274         return type_from_stack_type (ins);
2275 }
2276
2277 static MonoClass*
2278 array_access_to_klass (int opcode, MonoInst *array_obj)
2279 {
2280         switch (opcode) {
2281         case CEE_LDELEM_U1:
2282                 return mono_defaults.byte_class;
2283         case CEE_LDELEM_U2:
2284                 return mono_defaults.uint16_class;
2285         case CEE_LDELEM_I:
2286         case CEE_STELEM_I:
2287                 return mono_defaults.int_class;
2288         case CEE_LDELEM_I1:
2289         case CEE_STELEM_I1:
2290                 return mono_defaults.sbyte_class;
2291         case CEE_LDELEM_I2:
2292         case CEE_STELEM_I2:
2293                 return mono_defaults.int16_class;
2294         case CEE_LDELEM_I4:
2295         case CEE_STELEM_I4:
2296                 return mono_defaults.int32_class;
2297         case CEE_LDELEM_U4:
2298                 return mono_defaults.uint32_class;
2299         case CEE_LDELEM_I8:
2300         case CEE_STELEM_I8:
2301                 return mono_defaults.int64_class;
2302         case CEE_LDELEM_R4:
2303         case CEE_STELEM_R4:
2304                 return mono_defaults.single_class;
2305         case CEE_LDELEM_R8:
2306         case CEE_STELEM_R8:
2307                 return mono_defaults.double_class;
2308         case CEE_LDELEM_REF:
2309         case CEE_STELEM_REF: {
2310                 MonoClass *klass = array_obj->klass;
2311                 /* FIXME: add assert */
2312                 if (klass && klass->rank)
2313                         return klass->element_class;
2314                 return mono_defaults.object_class;
2315         }
2316         default:
2317                 g_assert_not_reached ();
2318         }
2319         return NULL;
2320 }
2321
2322 /*
2323  * mono_add_ins_to_end:
2324  *
2325  *   Same as MONO_ADD_INS, but add INST before any branches at the end of BB.
2326  */
2327 void
2328 mono_add_ins_to_end (MonoBasicBlock *bb, MonoInst *inst)
2329 {
2330         int opcode;
2331
2332         if (!bb->code) {
2333                 MONO_ADD_INS (bb, inst);
2334                 return;
2335         }
2336
2337         switch (bb->last_ins->opcode) {
2338         case OP_BR:
2339         case OP_BR_REG:
2340         case CEE_BEQ:
2341         case CEE_BGE:
2342         case CEE_BGT:
2343         case CEE_BLE:
2344         case CEE_BLT:
2345         case CEE_BNE_UN:
2346         case CEE_BGE_UN:
2347         case CEE_BGT_UN:
2348         case CEE_BLE_UN:
2349         case CEE_BLT_UN:
2350         case OP_SWITCH:
2351                 mono_bblock_insert_before_ins (bb, bb->last_ins, inst);
2352                 break;
2353         default:
2354                 if (MONO_IS_COND_BRANCH_OP (bb->last_ins)) {
2355                         /* Need to insert the ins before the compare */
2356                         if (bb->code == bb->last_ins) {
2357                                 mono_bblock_insert_before_ins (bb, bb->last_ins, inst);
2358                                 return;
2359                         }
2360
2361                         if (bb->code->next == bb->last_ins) {
2362                                 /* Only two instructions */
2363                                 opcode = bb->code->opcode;
2364
2365                                 if ((opcode == OP_COMPARE) || (opcode == OP_COMPARE_IMM) || (opcode == OP_ICOMPARE) || (opcode == OP_ICOMPARE_IMM) || (opcode == OP_FCOMPARE) || (opcode == OP_LCOMPARE) || (opcode == OP_LCOMPARE_IMM)) {
2366                                         /* NEW IR */
2367                                         mono_bblock_insert_before_ins (bb, bb->code, inst);
2368                                 } else {
2369                                         mono_bblock_insert_before_ins (bb, bb->last_ins, inst);
2370                                 }
2371                         } else {
2372                                 opcode = bb->last_ins->prev->opcode;
2373
2374                                 if ((opcode == OP_COMPARE) || (opcode == OP_COMPARE_IMM) || (opcode == OP_ICOMPARE) || (opcode == OP_ICOMPARE_IMM) || (opcode == OP_FCOMPARE) || (opcode == OP_LCOMPARE) || (opcode == OP_LCOMPARE_IMM)) {
2375                                         /* NEW IR */
2376                                         mono_bblock_insert_before_ins (bb, bb->last_ins->prev, inst);
2377                                 } else {
2378                                         mono_bblock_insert_before_ins (bb, bb->last_ins, inst);
2379                                 }                                       
2380                         }
2381                 }
2382                 else
2383                         MONO_ADD_INS (bb, inst);
2384                 break;
2385         }
2386 }
2387
2388 /**
2389  * mono_replace_ins:
2390  *
2391  *   Replace INS with its decomposition which is stored in a series of bblocks starting
2392  * at FIRST_BB and ending at LAST_BB. On enter, PREV points to the predecessor of INS. 
2393  * On return, it will be set to the last ins of the decomposition.
2394  */
2395 void
2396 mono_replace_ins (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst *ins, MonoInst **prev, MonoBasicBlock *first_bb, MonoBasicBlock *last_bb)
2397 {
2398         MonoInst *next = ins->next;
2399
2400         if (next && next->opcode == OP_NOP) {
2401                 /* Avoid NOPs following branches */
2402                 ins->next = next->next;
2403                 next = next->next;
2404         }
2405
2406         if (first_bb == last_bb) {
2407                 /* 
2408                  * Only one replacement bb, merge the code into
2409                  * the current bb.
2410                  */
2411
2412                 /* Delete links between the first_bb and its successors */
2413                 while (first_bb->out_count)
2414                         mono_unlink_bblock (cfg, first_bb, first_bb->out_bb [0]);
2415
2416                 /* Head */
2417                 if (*prev) {
2418                         (*prev)->next = first_bb->code;
2419                         first_bb->code->prev = (*prev);
2420                 } else {
2421                         bb->code = first_bb->code;
2422                 }
2423
2424                 /* Tail */
2425                 last_bb->last_ins->next = next;
2426                 if (next)
2427                         next->prev = last_bb->last_ins;
2428                 else
2429                         bb->last_ins = last_bb->last_ins;
2430                 *prev = last_bb->last_ins;
2431         } else {
2432                 int i, count;
2433                 MonoBasicBlock **tmp_bblocks, *tmp;
2434                 MonoInst *last;
2435
2436                 /* Multiple BBs */
2437
2438                 /* Set region */
2439                 for (tmp = first_bb; tmp; tmp = tmp->next_bb)
2440                         tmp->region = bb->region;
2441
2442                 /* Split the original bb */
2443                 if (ins->next)
2444                         ins->next->prev = NULL;
2445                 ins->next = NULL;
2446                 bb->last_ins = ins;
2447
2448                 /* Merge the second part of the original bb into the last bb */
2449                 if (last_bb->last_ins) {
2450                         last_bb->last_ins->next = next;
2451                         if (next)
2452                                 next->prev = last_bb->last_ins;
2453                 } else {
2454                         last_bb->code = next;
2455                 }
2456
2457                 if (next) {
2458                         for (last = next; last->next != NULL; last = last->next)
2459                                 ;
2460                         last_bb->last_ins = last;
2461                 }
2462
2463                 for (i = 0; i < bb->out_count; ++i)
2464                         link_bblock (cfg, last_bb, bb->out_bb [i]);
2465
2466                 /* Merge the first (dummy) bb to the original bb */
2467                 if (*prev) {
2468                         (*prev)->next = first_bb->code;
2469                         first_bb->code->prev = (*prev);
2470                 } else {
2471                         bb->code = first_bb->code;
2472                 }
2473                 bb->last_ins = first_bb->last_ins;
2474
2475                 /* Delete the links between the original bb and its successors */
2476                 tmp_bblocks = bb->out_bb;
2477                 count = bb->out_count;
2478                 for (i = 0; i < count; ++i)
2479                         mono_unlink_bblock (cfg, bb, tmp_bblocks [i]);
2480
2481                 /* Add links between the original bb and the first_bb's successors */
2482                 for (i = 0; i < first_bb->out_count; ++i) {
2483                         MonoBasicBlock *out_bb = first_bb->out_bb [i];
2484
2485                         link_bblock (cfg, bb, out_bb);
2486                 }
2487                 /* Delete links between the first_bb and its successors */
2488                 for (i = 0; i < bb->out_count; ++i) {
2489                         MonoBasicBlock *out_bb = bb->out_bb [i];
2490
2491                         mono_unlink_bblock (cfg, first_bb, out_bb);
2492                 }
2493                 last_bb->next_bb = bb->next_bb;
2494                 bb->next_bb = first_bb->next_bb;
2495
2496                 *prev = NULL;
2497         }
2498 }
2499
2500 void
2501 mono_add_varcopy_to_end (MonoCompile *cfg, MonoBasicBlock *bb, int src, int dest)
2502 {
2503         MonoInst *inst, *load;
2504
2505         NEW_TEMPLOAD (cfg, load, src);
2506
2507         NEW_TEMPSTORE (cfg, inst, dest, load);
2508         /* FIXME: handle CEE_STIND_R4 */
2509         if (inst->opcode == CEE_STOBJ) {
2510                 NEW_TEMPLOADA (cfg, inst, dest);
2511                 handle_stobj (cfg, bb, inst, load, NULL, inst->klass, TRUE, FALSE, FALSE);
2512         } else {
2513                 inst->cil_code = NULL;
2514                 mono_add_ins_to_end (bb, inst);
2515         }
2516 }
2517
2518 /*
2519  * This function is called to handle items that are left on the evaluation stack
2520  * at basic block boundaries. What happens is that we save the values to local variables
2521  * and we reload them later when first entering the target basic block (with the
2522  * handle_loaded_temps () function).
2523  * It is also used to handle items on the stack in store opcodes, since it is
2524  * possible that the variable to be stored into is already on the stack, in
2525  * which case its old value should be used.
2526  * A single joint point will use the same variables (stored in the array bb->out_stack or
2527  * bb->in_stack, if the basic block is before or after the joint point).
2528  * If the stack merge fails at a join point, cfg->unverifiable is set.
2529  */
2530 static void
2531 handle_stack_args (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst **sp, int count)
2532 {
2533         int i, bindex;
2534         MonoBasicBlock *outb;
2535         MonoInst *inst, **locals;
2536         gboolean found;
2537
2538         if (!count)
2539                 return;
2540         if (cfg->verbose_level > 3)
2541                 g_print ("%d item(s) on exit from B%d\n", count, bb->block_num);
2542
2543         if (!bb->out_scount) {
2544                 bb->out_scount = count;
2545                 //g_print ("bblock %d has out:", bb->block_num);
2546                 found = FALSE;
2547                 for (i = 0; i < bb->out_count; ++i) {
2548                         outb = bb->out_bb [i];
2549                         /* exception handlers are linked, but they should not be considered for stack args */
2550                         if (outb->flags & BB_EXCEPTION_HANDLER)
2551                                 continue;
2552                         //g_print (" %d", outb->block_num);
2553                         if (outb->in_stack) {
2554                                 found = TRUE;
2555                                 bb->out_stack = outb->in_stack;
2556                                 break;
2557                         }
2558                 }
2559                 //g_print ("\n");
2560                 if (!found) {
2561                         bb->out_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * count);
2562                         for (i = 0; i < count; ++i) {
2563                                 /* 
2564                                  * try to reuse temps already allocated for this purpouse, if they occupy the same
2565                                  * stack slot and if they are of the same type.
2566                                  * This won't cause conflicts since if 'local' is used to 
2567                                  * store one of the values in the in_stack of a bblock, then
2568                                  * the same variable will be used for the same outgoing stack 
2569                                  * slot as well. 
2570                                  * This doesn't work when inlining methods, since the bblocks
2571                                  * in the inlined methods do not inherit their in_stack from
2572                                  * the bblock they are inlined to. See bug #58863 for an
2573                                  * example.
2574                                  * This hack is disabled since it also prevents proper tracking of types.
2575                                  */
2576 #if 1
2577                                 bb->out_stack [i] = mono_compile_create_var (cfg, type_from_stack_type (sp [i]), OP_LOCAL);
2578 #else
2579                                 if (cfg->inlined_method)
2580                                         bb->out_stack [i] = mono_compile_create_var (cfg, type_from_stack_type (sp [i]), OP_LOCAL);
2581                                 else
2582                                         bb->out_stack [i] = mono_compile_get_interface_var (cfg, i, sp [i]);
2583 #endif
2584                         }
2585                 }
2586         }
2587
2588         for (i = 0; i < bb->out_count; ++i) {
2589                 outb = bb->out_bb [i];
2590                 /* exception handlers are linked, but they should not be considered for stack args */
2591                 if (outb->flags & BB_EXCEPTION_HANDLER)
2592                         continue;
2593                 if (outb->in_scount) {
2594                         if (outb->in_scount != bb->out_scount) {
2595                                 cfg->unverifiable = TRUE;
2596                                 return;
2597                         }
2598                         continue; /* check they are the same locals */
2599                 }
2600                 outb->in_scount = count;
2601                 outb->in_stack = bb->out_stack;
2602         }
2603
2604         locals = bb->out_stack;
2605         for (i = 0; i < count; ++i) {
2606                 /* add store ops at the end of the bb, before the branch */
2607                 NEW_TEMPSTORE (cfg, inst, locals [i]->inst_c0, sp [i]);
2608                 if (inst->opcode == CEE_STOBJ) {
2609                         NEW_TEMPLOADA (cfg, inst, locals [i]->inst_c0);
2610                         handle_stobj (cfg, bb, inst, sp [i], sp [i]->cil_code, inst->klass, TRUE, FALSE, FALSE);
2611                 } else {
2612                         inst->cil_code = sp [i]->cil_code;
2613                         mono_add_ins_to_end (bb, inst);
2614                 }
2615                 if (cfg->verbose_level > 3)
2616                         g_print ("storing %d to temp %d\n", i, (int)locals [i]->inst_c0);
2617         }
2618
2619         /*
2620          * It is possible that the out bblocks already have in_stack assigned, and
2621          * the in_stacks differ. In this case, we will store to all the different 
2622          * in_stacks.
2623          */
2624
2625         found = TRUE;
2626         bindex = 0;
2627         while (found) {
2628                 /* Find a bblock which has a different in_stack */
2629                 found = FALSE;
2630                 while (bindex < bb->out_count) {
2631                         outb = bb->out_bb [bindex];
2632                         /* exception handlers are linked, but they should not be considered for stack args */
2633                         if (outb->flags & BB_EXCEPTION_HANDLER) {
2634                                 bindex++;
2635                                 continue;
2636                         }
2637                         if (outb->in_stack != locals) {
2638                                 /* 
2639                                  * Instead of storing sp [i] to locals [i], we need to store
2640                                  * locals [i] to <new locals>[i], since the sp [i] tree can't
2641                                  * be shared between trees.
2642                                  */
2643                                 for (i = 0; i < count; ++i)
2644                                         mono_add_varcopy_to_end (cfg, bb, locals [i]->inst_c0, outb->in_stack [i]->inst_c0);
2645                                 locals = outb->in_stack;
2646                                 found = TRUE;
2647                                 break;
2648                         }
2649                         bindex ++;
2650                 }
2651         }
2652 }
2653
2654 static int
2655 ret_type_to_call_opcode (MonoType *type, int calli, int virt, MonoGenericSharingContext *gsctx)
2656 {
2657         if (type->byref)
2658                 return calli? OP_CALL_REG: virt? OP_CALLVIRT: OP_CALL;
2659
2660 handle_enum:
2661         type = mini_get_basic_type_from_generic (gsctx, type);
2662         switch (type->type) {
2663         case MONO_TYPE_VOID:
2664                 return calli? OP_VOIDCALL_REG: virt? OP_VOIDCALLVIRT: OP_VOIDCALL;
2665         case MONO_TYPE_I1:
2666         case MONO_TYPE_U1:
2667         case MONO_TYPE_BOOLEAN:
2668         case MONO_TYPE_I2:
2669         case MONO_TYPE_U2:
2670         case MONO_TYPE_CHAR:
2671         case MONO_TYPE_I4:
2672         case MONO_TYPE_U4:
2673                 return calli? OP_CALL_REG: virt? OP_CALLVIRT: OP_CALL;
2674         case MONO_TYPE_I:
2675         case MONO_TYPE_U:
2676         case MONO_TYPE_PTR:
2677         case MONO_TYPE_FNPTR:
2678                 return calli? OP_CALL_REG: virt? OP_CALLVIRT: OP_CALL;
2679         case MONO_TYPE_CLASS:
2680         case MONO_TYPE_STRING:
2681         case MONO_TYPE_OBJECT:
2682         case MONO_TYPE_SZARRAY:
2683         case MONO_TYPE_ARRAY:    
2684                 return calli? OP_CALL_REG: virt? OP_CALLVIRT: OP_CALL;
2685         case MONO_TYPE_I8:
2686         case MONO_TYPE_U8:
2687                 return calli? OP_LCALL_REG: virt? OP_LCALLVIRT: OP_LCALL;
2688         case MONO_TYPE_R4:
2689         case MONO_TYPE_R8:
2690                 return calli? OP_FCALL_REG: virt? OP_FCALLVIRT: OP_FCALL;
2691         case MONO_TYPE_VALUETYPE:
2692                 if (type->data.klass->enumtype) {
2693                         type = type->data.klass->enum_basetype;
2694                         goto handle_enum;
2695                 } else
2696                         return calli? OP_VCALL_REG: virt? OP_VCALLVIRT: OP_VCALL;
2697         case MONO_TYPE_TYPEDBYREF:
2698                 return calli? OP_VCALL_REG: virt? OP_VCALLVIRT: OP_VCALL;
2699         case MONO_TYPE_GENERICINST:
2700                 type = &type->data.generic_class->container_class->byval_arg;
2701                 goto handle_enum;
2702         default:
2703                 g_error ("unknown type 0x%02x in ret_type_to_call_opcode", type->type);
2704         }
2705         return -1;
2706 }
2707
2708 void
2709 mono_create_jump_table (MonoCompile *cfg, MonoInst *label, MonoBasicBlock **bbs, int num_blocks)
2710 {
2711         MonoJumpInfo *ji = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfo));
2712         MonoJumpInfoBBTable *table;
2713
2714         table = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfoBBTable));
2715         table->table = bbs;
2716         table->table_size = num_blocks;
2717         
2718         ji->ip.label = label;
2719         ji->type = MONO_PATCH_INFO_SWITCH;
2720         ji->data.table = table;
2721         ji->next = cfg->patch_info;
2722         cfg->patch_info = ji;
2723 }
2724
2725 static void
2726 mono_save_token_info (MonoCompile *cfg, MonoImage *image, guint32 token, gpointer key)
2727 {
2728         if (cfg->compile_aot) {
2729                 MonoJumpInfoToken *jump_info_token = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoToken));
2730                 jump_info_token->image = image;
2731                 jump_info_token->token = token;
2732                 g_hash_table_insert (cfg->token_info_hash, key, jump_info_token);
2733         }
2734 }
2735
2736 /*
2737  * When we add a tree of instructions, we need to ensure the instructions currently
2738  * on the stack are executed before (like, if we load a value from a local).
2739  * We ensure this by saving the currently loaded values to temps and rewriting the
2740  * instructions to load the values.
2741  * This is not done for opcodes that terminate a basic block (because it's handled already
2742  * by handle_stack_args ()) and for opcodes that can't change values, like POP.
2743  */
2744 static void
2745 handle_loaded_temps (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst **stack, MonoInst **sp)
2746 {
2747         MonoInst *load, *store, *temp, *ins;
2748
2749         while (stack < sp) {
2750                 ins = *stack;
2751                 /* handle also other constants */
2752                 if ((ins->opcode != OP_ICONST) &&
2753                     /* temps never get written to again, so we can safely avoid duplicating them */
2754                     !(ins->ssa_op == MONO_SSA_LOAD && ins->inst_i0->opcode == OP_LOCAL && ins->inst_i0->flags & MONO_INST_IS_TEMP)) {
2755                         temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
2756                         temp->flags |= MONO_INST_IS_TEMP;
2757                         NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
2758                         store->cil_code = ins->cil_code;
2759                         if (store->opcode == CEE_STOBJ) {
2760                                 NEW_TEMPLOADA (cfg, store, temp->inst_c0);
2761                                 handle_stobj (cfg, bblock, store, ins, ins->cil_code, temp->klass, FALSE, FALSE, FALSE);
2762                         } else
2763                                 MONO_ADD_INS (bblock, store);
2764                         NEW_TEMPLOAD (cfg, load, temp->inst_c0);
2765                         load->cil_code = ins->cil_code;
2766                         *stack = load;
2767                 }
2768                 stack++;
2769         }
2770 }
2771
2772 /*
2773  * target_type_is_incompatible:
2774  * @cfg: MonoCompile context
2775  *
2776  * Check that the item @arg on the evaluation stack can be stored
2777  * in the target type (can be a local, or field, etc).
2778  * The cfg arg can be used to check if we need verification or just
2779  * validity checks.
2780  *
2781  * Returns: non-0 value if arg can't be stored on a target.
2782  */
2783 static int
2784 target_type_is_incompatible (MonoCompile *cfg, MonoType *target, MonoInst *arg)
2785 {
2786         MonoType *simple_type;
2787         MonoClass *klass;
2788
2789         if (target->byref) {
2790                 /* FIXME: check that the pointed to types match */
2791                 if (arg->type == STACK_MP)
2792                         return arg->klass != mono_class_from_mono_type (target);
2793                 if (arg->type == STACK_PTR)
2794                         return 0;
2795                 return 1;
2796         }
2797         simple_type = mono_type_get_underlying_type (target);
2798         switch (simple_type->type) {
2799         case MONO_TYPE_VOID:
2800                 return 1;
2801         case MONO_TYPE_I1:
2802         case MONO_TYPE_U1:
2803         case MONO_TYPE_BOOLEAN:
2804         case MONO_TYPE_I2:
2805         case MONO_TYPE_U2:
2806         case MONO_TYPE_CHAR:
2807         case MONO_TYPE_I4:
2808         case MONO_TYPE_U4:
2809                 if (arg->type != STACK_I4 && arg->type != STACK_PTR)
2810                         return 1;
2811                 return 0;
2812         case MONO_TYPE_PTR:
2813                 /* STACK_MP is needed when setting pinned locals */
2814                 if (arg->type != STACK_I4 && arg->type != STACK_PTR && arg->type != STACK_MP)
2815                         return 1;
2816                 return 0;
2817         case MONO_TYPE_I:
2818         case MONO_TYPE_U:
2819         case MONO_TYPE_FNPTR:
2820                 if (arg->type != STACK_I4 && arg->type != STACK_PTR)
2821                         return 1;
2822                 return 0;
2823         case MONO_TYPE_OBJECT:
2824                 if (arg->type != STACK_OBJ)
2825                         return 1;
2826                 return 0;
2827         case MONO_TYPE_STRING:
2828                 if (arg->type != STACK_OBJ)
2829                         return 1;
2830                 /* ldnull has arg->klass unset */
2831                 /*if (arg->klass && arg->klass != mono_defaults.string_class) {
2832                         G_BREAKPOINT ();
2833                         return 1;
2834                 }*/
2835                 return 0;
2836         case MONO_TYPE_CLASS:
2837         case MONO_TYPE_SZARRAY:
2838         case MONO_TYPE_ARRAY:    
2839                 if (arg->type != STACK_OBJ)
2840                         return 1;
2841                 /* FIXME: check type compatibility */
2842                 return 0;
2843         case MONO_TYPE_I8:
2844         case MONO_TYPE_U8:
2845                 if (arg->type != STACK_I8)
2846                         return 1;
2847                 return 0;
2848         case MONO_TYPE_R4:
2849         case MONO_TYPE_R8:
2850                 if (arg->type != STACK_R8)
2851                         return 1;
2852                 return 0;
2853         case MONO_TYPE_VALUETYPE:
2854                 if (arg->type != STACK_VTYPE)
2855                         return 1;
2856                 klass = mono_class_from_mono_type (simple_type);
2857                 if (klass != arg->klass)
2858                         return 1;
2859                 return 0;
2860         case MONO_TYPE_TYPEDBYREF:
2861                 if (arg->type != STACK_VTYPE)
2862                         return 1;
2863                 klass = mono_class_from_mono_type (simple_type);
2864                 if (klass != arg->klass)
2865                         return 1;
2866                 return 0;
2867         case MONO_TYPE_GENERICINST:
2868                 if (mono_type_generic_inst_is_valuetype (simple_type)) {
2869                         klass = mono_class_from_mono_type (simple_type);
2870                         if (klass->enumtype)
2871                                 return target_type_is_incompatible (cfg, klass->enum_basetype, arg);
2872                         if (arg->type != STACK_VTYPE)
2873                                 return 1;
2874                         if (klass != arg->klass)
2875                                 return 1;
2876                         return 0;
2877                 } else {
2878                         if (arg->type != STACK_OBJ)
2879                                 return 1;
2880                         /* FIXME: check type compatibility */
2881                         return 0;
2882                 }
2883         case MONO_TYPE_VAR:
2884         case MONO_TYPE_MVAR:
2885                 /* FIXME: all the arguments must be references for now,
2886                  * later look inside cfg and see if the arg num is
2887                  * really a reference
2888                  */
2889                 g_assert (cfg->generic_sharing_context);
2890                 if (arg->type != STACK_OBJ)
2891                         return 1;
2892                 return 0;
2893         default:
2894                 g_error ("unknown type 0x%02x in target_type_is_incompatible", simple_type->type);
2895         }
2896         return 1;
2897 }
2898
2899 /*
2900  * Prepare arguments for passing to a function call.
2901  * Return a non-zero value if the arguments can't be passed to the given
2902  * signature.
2903  * The type checks are not yet complete and some conversions may need
2904  * casts on 32 or 64 bit architectures.
2905  *
2906  * FIXME: implement this using target_type_is_incompatible ()
2907  */
2908 static int
2909 check_call_signature (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args)
2910 {
2911         MonoType *simple_type;
2912         int i;
2913
2914         if (sig->hasthis) {
2915                 if (args [0]->type != STACK_OBJ && args [0]->type != STACK_MP && args [0]->type != STACK_PTR)
2916                         return 1;
2917                 args++;
2918         }
2919         for (i = 0; i < sig->param_count; ++i) {
2920                 if (sig->params [i]->byref) {
2921                         if (args [i]->type != STACK_MP && args [i]->type != STACK_PTR)
2922                                 return 1;
2923                         continue;
2924                 }
2925                 simple_type = sig->params [i];
2926                 simple_type = mini_get_basic_type_from_generic (cfg->generic_sharing_context, simple_type);
2927 handle_enum:
2928                 switch (simple_type->type) {
2929                 case MONO_TYPE_VOID:
2930                         return 1;
2931                         continue;
2932                 case MONO_TYPE_I1:
2933                 case MONO_TYPE_U1:
2934                 case MONO_TYPE_BOOLEAN:
2935                 case MONO_TYPE_I2:
2936                 case MONO_TYPE_U2:
2937                 case MONO_TYPE_CHAR:
2938                 case MONO_TYPE_I4:
2939                 case MONO_TYPE_U4:
2940                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR)
2941                                 return 1;
2942                         continue;
2943                 case MONO_TYPE_I:
2944                 case MONO_TYPE_U:
2945                 case MONO_TYPE_PTR:
2946                 case MONO_TYPE_FNPTR:
2947                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR && args [i]->type != STACK_MP && args [i]->type != STACK_OBJ)
2948                                 return 1;
2949                         continue;
2950                 case MONO_TYPE_CLASS:
2951                 case MONO_TYPE_STRING:
2952                 case MONO_TYPE_OBJECT:
2953                 case MONO_TYPE_SZARRAY:
2954                 case MONO_TYPE_ARRAY:    
2955                         if (args [i]->type != STACK_OBJ)
2956                                 return 1;
2957                         continue;
2958                 case MONO_TYPE_I8:
2959                 case MONO_TYPE_U8:
2960                         if (args [i]->type != STACK_I8)
2961                                 return 1;
2962                         continue;
2963                 case MONO_TYPE_R4:
2964                 case MONO_TYPE_R8:
2965                         if (args [i]->type != STACK_R8)
2966                                 return 1;
2967                         continue;
2968                 case MONO_TYPE_VALUETYPE:
2969                         if (simple_type->data.klass->enumtype) {
2970                                 simple_type = simple_type->data.klass->enum_basetype;
2971                                 goto handle_enum;
2972                         }
2973                         if (args [i]->type != STACK_VTYPE)
2974                                 return 1;
2975                         continue;
2976                 case MONO_TYPE_TYPEDBYREF:
2977                         if (args [i]->type != STACK_VTYPE)
2978                                 return 1;
2979                         continue;
2980                 case MONO_TYPE_GENERICINST:
2981                         simple_type = &simple_type->data.generic_class->container_class->byval_arg;
2982                         goto handle_enum;
2983
2984                 default:
2985                         g_error ("unknown type 0x%02x in check_call_signature",
2986                                  simple_type->type);
2987                 }
2988         }
2989         return 0;
2990 }
2991
2992 inline static int
2993 mono_spill_call (MonoCompile *cfg, MonoBasicBlock *bblock, MonoCallInst *call, MonoMethodSignature *sig, gboolean ret_object, 
2994                  const guint8 *ip, gboolean to_end)
2995 {
2996         MonoInst *temp, *store, *ins = (MonoInst*)call;
2997         MonoType *ret = sig->ret;
2998
2999         if (!MONO_TYPE_IS_VOID (ret) || ret_object) {
3000                 if (ret_object) {
3001                         call->inst.type = STACK_OBJ;
3002                         call->inst.opcode = OP_CALL;
3003                         temp = mono_compile_create_var (cfg, &mono_defaults.string_class->byval_arg, OP_LOCAL);
3004                 } else {
3005                         type_to_eval_stack_type (cfg, ret, ins);
3006                         temp = mono_compile_create_var (cfg, ret, OP_LOCAL);
3007                 }
3008                 
3009                 temp->flags |= MONO_INST_IS_TEMP;
3010
3011                 if (MONO_TYPE_ISSTRUCT (ret)) {
3012                         MonoInst *loada, *dummy_store;
3013
3014                         /* 
3015                          * Emit a dummy store to the local holding the result so the
3016                          * liveness info remains correct.
3017                          */
3018                         NEW_DUMMY_STORE (cfg, dummy_store, temp->inst_c0);
3019                         if (to_end)
3020                                 mono_add_ins_to_end (bblock, dummy_store);
3021                         else
3022                                 MONO_ADD_INS (bblock, dummy_store);
3023
3024                         /* we use this to allocate native sized structs */
3025                         temp->backend.is_pinvoke = sig->pinvoke;
3026
3027                         NEW_TEMPLOADA (cfg, loada, temp->inst_c0);
3028                         if (call->inst.opcode == OP_VCALL || call->inst.opcode == OP_VCALL_RGCTX)
3029                                 ins->inst_left = loada;
3030                         else
3031                                 ins->inst_right = loada; /* a virtual or indirect call */
3032
3033                         if (to_end)
3034                                 mono_add_ins_to_end (bblock, ins);
3035                         else
3036                                 MONO_ADD_INS (bblock, ins);
3037                 } else {
3038                         NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
3039                         store->cil_code = ip;
3040                         
3041 #ifdef MONO_ARCH_SOFT_FLOAT
3042                         if (store->opcode == CEE_STIND_R4) {
3043                                 /*FIXME implement proper support for to_end*/
3044                                 g_assert (!to_end);
3045                                 NEW_TEMPLOADA (cfg, store, temp->inst_c0);
3046                                 handle_store_float (cfg, bblock, store, ins, ip);
3047                         } else
3048 #endif
3049                         if (to_end)
3050                                 mono_add_ins_to_end (bblock, store);
3051                         else
3052                                 MONO_ADD_INS (bblock, store);
3053                 }
3054                 return temp->inst_c0;
3055         } else {
3056                 if (to_end)
3057                         mono_add_ins_to_end (bblock, ins);
3058                 else
3059                         MONO_ADD_INS (bblock, ins);
3060                 return -1;
3061         }
3062 }
3063
3064 inline static MonoCallInst *
3065 mono_emit_call_args (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethodSignature *sig, 
3066                      MonoInst **args, int calli, int virtual, const guint8 *ip, gboolean to_end)
3067 {
3068         MonoCallInst *call;
3069         MonoInst *arg;
3070
3071         MONO_INST_NEW_CALL (cfg, call, ret_type_to_call_opcode (sig->ret, calli, virtual, cfg->generic_sharing_context));
3072
3073 #ifdef MONO_ARCH_SOFT_FLOAT
3074         /* we need to convert the r4 value to an int value */
3075         {
3076                 int i;
3077                 for (i = 0; i < sig->param_count; ++i) {
3078                         if (!sig->params [i]->byref && sig->params [i]->type == MONO_TYPE_R4) {
3079                                 MonoInst *iargs [1];
3080                                 int temp;
3081                                 iargs [0] = args [i + sig->hasthis];
3082
3083                                 temp = mono_emit_jit_icall (cfg, bblock, mono_fload_r4_arg, iargs, ip);
3084                                 NEW_TEMPLOAD (cfg, arg, temp);
3085                                 args [i + sig->hasthis] = arg;
3086                         }
3087                 }
3088         }
3089 #endif
3090
3091         call->inst.cil_code = ip;
3092         call->args = args;
3093         call->signature = sig;
3094         call = mono_arch_call_opcode (cfg, bblock, call, virtual);
3095         type_to_eval_stack_type (cfg, sig->ret, &call->inst);
3096
3097         for (arg = call->out_args; arg;) {
3098                 MonoInst *narg = arg->next;
3099                 arg->next = NULL;
3100                 if (!arg->cil_code)
3101                         arg->cil_code = ip;
3102                 if (to_end)
3103                         mono_add_ins_to_end (bblock, arg);
3104                 else
3105                         MONO_ADD_INS (bblock, arg);
3106                 arg = narg;
3107         }
3108         return call;
3109 }
3110
3111 inline static MonoCallInst*
3112 mono_emit_calli (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethodSignature *sig, 
3113                  MonoInst **args, MonoInst *addr, const guint8 *ip)
3114 {
3115         MonoCallInst *call = mono_emit_call_args (cfg, bblock, sig, args, TRUE, FALSE, ip, FALSE);
3116
3117         call->inst.inst_i0 = addr;
3118
3119         return call;
3120 }
3121
3122 inline static MonoCallInst*
3123 mono_emit_rgctx_calli (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethodSignature *sig,
3124         MonoInst **args, MonoInst *addr, MonoInst *rgctx_arg, const guint8 *ip)
3125 {
3126         MonoCallInst *call = mono_emit_calli (cfg, bblock, sig, args, addr, ip);
3127
3128         if (rgctx_arg) {
3129                 switch (call->inst.opcode) {
3130                 case OP_CALL_REG: call->inst.opcode = OP_CALL_REG_RGCTX; break;
3131                 case OP_VOIDCALL_REG: call->inst.opcode = OP_VOIDCALL_REG_RGCTX; break;
3132                 case OP_FCALL_REG: call->inst.opcode = OP_FCALL_REG_RGCTX; break;
3133                 case OP_LCALL_REG: call->inst.opcode = OP_LCALL_REG_RGCTX; break;
3134                 case OP_VCALL_REG: {
3135                         MonoInst *group;
3136
3137                         NEW_GROUP (cfg, group, call->inst.inst_left, NULL);
3138                         call->inst.inst_left = group;
3139                         call->inst.opcode = OP_VCALL_REG_RGCTX;
3140                         break;
3141                 }
3142                 default: g_assert_not_reached ();
3143                 }
3144
3145                 if (call->inst.opcode != OP_VCALL_REG_RGCTX) {
3146                         g_assert (!call->inst.inst_right);
3147                         call->inst.inst_right = rgctx_arg;
3148                 } else {
3149                         g_assert (!call->inst.inst_left->inst_right);
3150                         call->inst.inst_left->inst_right = rgctx_arg;
3151                 }
3152         }
3153
3154         return call;
3155 }
3156
3157 inline static int
3158 mono_emit_calli_spilled (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethodSignature *sig, 
3159                                                  MonoInst **args, MonoInst *addr, const guint8 *ip)
3160 {
3161         MonoCallInst *call = mono_emit_calli (cfg, bblock, sig, args, addr, ip);
3162
3163         return mono_spill_call (cfg, bblock, call, sig, FALSE, ip, FALSE);
3164 }
3165
3166 static int
3167 mono_emit_rgctx_calli_spilled (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethodSignature *sig,
3168         MonoInst **args, MonoInst *addr, MonoInst *rgctx_arg, const guint8 *ip)
3169 {
3170         MonoCallInst *call = mono_emit_rgctx_calli (cfg, bblock, sig, args, addr, rgctx_arg, ip);
3171
3172         return mono_spill_call (cfg, bblock, call, sig, FALSE, ip, FALSE);
3173 }
3174
3175 static MonoCallInst*
3176 mono_emit_method_call_full (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *method, MonoMethodSignature *sig,
3177                        MonoInst **args, const guint8 *ip, MonoInst *this, gboolean to_end)
3178 {
3179         gboolean virtual = this != NULL;
3180         MonoCallInst *call;
3181
3182         call = mono_emit_call_args (cfg, bblock, sig, args, FALSE, virtual, ip, to_end);
3183
3184         if (this && sig->hasthis && 
3185             (method->klass->marshalbyref || method->klass == mono_defaults.object_class) && 
3186             !(method->flags & METHOD_ATTRIBUTE_VIRTUAL) && !MONO_CHECK_THIS (this)) {
3187                 call->method = mono_marshal_get_remoting_invoke_with_check (method);
3188         } else {
3189                 call->method = method;
3190         }
3191         call->inst.flags |= MONO_INST_HAS_METHOD;
3192         call->inst.inst_left = this;
3193
3194         if (call->method->klass->flags & TYPE_ATTRIBUTE_INTERFACE)
3195                 /* Needed by the code generated in inssel.brg */
3196                 mono_get_got_var (cfg);
3197
3198         return call;
3199 }
3200
3201 static MonoCallInst*
3202 mono_emit_method_call (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *method, MonoMethodSignature *sig,
3203                        MonoInst **args, const guint8 *ip, MonoInst *this)
3204 {
3205         return mono_emit_method_call_full (cfg, bblock, method, sig, args, ip, this, FALSE);
3206 }
3207
3208 inline static int
3209 mono_emit_method_call_spilled (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *method,  
3210                        MonoMethodSignature *signature, MonoInst **args, const guint8 *ip, MonoInst *this)
3211 {
3212         MonoCallInst *call = mono_emit_method_call (cfg, bblock, method, signature, args, ip, this);
3213
3214         return mono_spill_call (cfg, bblock, call, signature, method->string_ctor, ip, FALSE);
3215 }
3216
3217 inline static int
3218 mono_emit_method_call_spilled_full (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *method,  
3219                        MonoMethodSignature *signature, MonoInst **args, const guint8 *ip, MonoInst *this,
3220                        gboolean ret_object, gboolean to_end)
3221 {
3222         MonoCallInst *call = mono_emit_method_call_full (cfg, bblock, method, signature, args, ip, this, to_end);
3223
3224         return mono_spill_call (cfg, bblock, call, signature, ret_object, ip, to_end);
3225 }
3226
3227 inline static int
3228 mono_emit_native_call (MonoCompile *cfg, MonoBasicBlock *bblock, gconstpointer func, MonoMethodSignature *sig,
3229                        MonoInst **args, const guint8 *ip, gboolean ret_object, gboolean to_end)
3230 {
3231         MonoCallInst *call;
3232
3233         g_assert (sig);
3234
3235         call = mono_emit_call_args (cfg, bblock, sig, args, FALSE, FALSE, ip, to_end);
3236         call->fptr = func;
3237
3238         return mono_spill_call (cfg, bblock, call, sig, ret_object, ip, to_end);
3239 }
3240
3241 inline static int
3242 mono_emit_jit_icall (MonoCompile *cfg, MonoBasicBlock *bblock, gconstpointer func, MonoInst **args, const guint8 *ip)
3243 {
3244         MonoJitICallInfo *info = mono_find_jit_icall_by_addr (func);
3245         
3246         if (!info) {
3247                 g_warning ("unregistered JIT ICall");
3248                 g_assert_not_reached ();
3249         }
3250
3251         return mono_emit_native_call (cfg, bblock, mono_icall_get_wrapper (info), info->sig, args, ip, FALSE, FALSE);
3252 }
3253
3254 static MonoCallInst*
3255 mono_emit_rgctx_method_call (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *method, MonoMethodSignature *sig,
3256                 MonoInst **args, MonoInst *rgctx_arg, MonoInst *imt_arg, const guint8 *ip, MonoInst *this)
3257 {
3258         MonoCallInst *call = mono_emit_method_call_full (cfg, bblock, method, sig, args, ip, this, FALSE);
3259
3260         g_assert (!(rgctx_arg && imt_arg));
3261
3262         if (rgctx_arg) {
3263                 switch (call->inst.opcode) {
3264                 case OP_CALL: call->inst.opcode = OP_CALL_RGCTX; break;
3265                 case OP_VOIDCALL: call->inst.opcode = OP_VOIDCALL_RGCTX; break;
3266                 case OP_FCALL: call->inst.opcode = OP_FCALL_RGCTX; break;
3267                 case OP_LCALL: call->inst.opcode = OP_LCALL_RGCTX; break;
3268                 case OP_VCALL: call->inst.opcode = OP_VCALL_RGCTX; break;
3269                 default: g_assert_not_reached ();
3270                 }
3271
3272                 if (call->inst.opcode != OP_VCALL_RGCTX) {
3273                         g_assert (!call->inst.inst_left);
3274                         call->inst.inst_left = rgctx_arg;
3275                 } else {
3276                         g_assert (!call->inst.inst_right);
3277                         call->inst.inst_right = rgctx_arg;
3278                 }
3279         } else if (imt_arg) {
3280                 switch (call->inst.opcode) {
3281                 case OP_CALLVIRT: call->inst.opcode = OP_CALLVIRT_IMT; break;
3282                 case OP_VOIDCALLVIRT: call->inst.opcode = OP_VOIDCALLVIRT_IMT; break;
3283                 case OP_FCALLVIRT: call->inst.opcode = OP_FCALLVIRT_IMT; break;
3284                 case OP_LCALLVIRT: call->inst.opcode = OP_LCALLVIRT_IMT; break;
3285                 case OP_VCALLVIRT: {
3286                         MonoInst *group;
3287
3288                         NEW_GROUP (cfg, group, call->inst.inst_left, NULL);
3289                         call->inst.inst_left = group;
3290                         call->inst.opcode = OP_VCALLVIRT_IMT;
3291                         break;
3292                 }
3293                 default: g_assert_not_reached ();
3294                 }
3295
3296                 if (call->inst.opcode != OP_VCALLVIRT_IMT) {
3297                         g_assert (!call->inst.inst_right);
3298                         call->inst.inst_right = imt_arg;
3299                 } else {
3300                         g_assert (!call->inst.inst_left->inst_right);
3301                         call->inst.inst_left->inst_right = imt_arg;
3302                 }
3303         }
3304
3305         return call;
3306 }
3307
3308 inline static int
3309 mono_emit_rgctx_method_call_spilled (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *method,  
3310                 MonoMethodSignature *signature, MonoInst **args, MonoInst *rgctx_arg, MonoInst *imt_arg,
3311                 const guint8 *ip, MonoInst *this)
3312 {
3313         MonoCallInst *call = mono_emit_rgctx_method_call (cfg, bblock, method, signature, args, rgctx_arg, imt_arg, ip, this);
3314
3315         return mono_spill_call (cfg, bblock, call, signature, method->string_ctor, ip, FALSE);
3316 }
3317
3318 static void
3319 mono_emulate_opcode (MonoCompile *cfg, MonoInst *tree, MonoInst **iargs, MonoJitICallInfo *info)
3320 {
3321         MonoInst *ins, *temp = NULL, *store, *load, *begin;
3322         MonoInst *last_arg = NULL;
3323         int nargs;
3324         MonoCallInst *call;
3325
3326         //g_print ("emulating: ");
3327         //mono_print_tree_nl (tree);
3328         MONO_INST_NEW_CALL (cfg, call, ret_type_to_call_opcode (info->sig->ret, FALSE, FALSE, cfg->generic_sharing_context));
3329         ins = (MonoInst*)call;
3330         
3331         call->inst.cil_code = tree->cil_code;
3332         call->args = iargs;
3333         call->signature = info->sig;
3334
3335         call = mono_arch_call_opcode (cfg, cfg->cbb, call, FALSE);
3336
3337         if (!MONO_TYPE_IS_VOID (info->sig->ret)) {
3338                 temp = mono_compile_create_var (cfg, info->sig->ret, OP_LOCAL);
3339                 temp->flags |= MONO_INST_IS_TEMP;
3340                 NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
3341                 /* FIXME: handle CEE_STIND_R4 */
3342                 store->cil_code = tree->cil_code;
3343         } else {
3344                 store = ins;
3345         }
3346
3347         nargs = info->sig->param_count + info->sig->hasthis;
3348
3349         for (last_arg = call->out_args; last_arg && last_arg->next; last_arg = last_arg->next) ;
3350
3351         if (nargs)
3352                 last_arg->next = store;
3353
3354         if (nargs)
3355                 begin = call->out_args;
3356         else
3357                 begin = store;
3358
3359         if (cfg->prev_ins) {
3360                 /* 
3361                  * This assumes that that in a tree, emulate_opcode is called for a
3362                  * node before it is called for its children. dec_foreach needs to
3363                  * take this into account.
3364                  */
3365                 store->next = cfg->prev_ins->next;
3366                 cfg->prev_ins->next = begin;
3367         } else {
3368                 store->next = cfg->cbb->code;
3369                 cfg->cbb->code = begin;
3370         }
3371
3372         call->fptr = mono_icall_get_wrapper (info);
3373
3374         if (!MONO_TYPE_IS_VOID (info->sig->ret)) {
3375                 NEW_TEMPLOAD (cfg, load, temp->inst_c0);
3376                 *tree = *load;
3377         }
3378 }
3379
3380 /*
3381  * This entry point could be used later for arbitrary method
3382  * redirection.
3383  */
3384 inline static int
3385 mini_redirect_call (int *temp, MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *method,  
3386                        MonoMethodSignature *signature, MonoInst **args, const guint8 *ip, MonoInst *this)
3387 {
3388
3389         if (method->klass == mono_defaults.string_class) {
3390                 /* managed string allocation support */
3391                 if (strcmp (method->name, "InternalAllocateStr") == 0) {
3392                         MonoInst *iargs [2];
3393                         MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
3394                         MonoMethod *managed_alloc = mono_gc_get_managed_allocator (vtable, FALSE);
3395                         if (!managed_alloc)
3396                                 return FALSE;
3397                         NEW_VTABLECONST (cfg, iargs [0], vtable);
3398                         iargs [1] = args [0];
3399                         *temp = mono_emit_method_call_spilled (cfg, bblock, managed_alloc, mono_method_signature (managed_alloc), iargs, ip, this);
3400                         return TRUE;
3401                 }
3402         }
3403         return FALSE;
3404 }
3405
3406 static MonoMethodSignature *
3407 mono_get_array_new_va_signature (int arity)
3408 {
3409         static GHashTable *sighash = NULL;
3410         MonoMethodSignature *res;
3411         int i;
3412
3413         mono_jit_lock ();
3414         if (!sighash) {
3415                 sighash = g_hash_table_new (NULL, NULL);
3416         }
3417         else if ((res = g_hash_table_lookup (sighash, GINT_TO_POINTER (arity)))) {
3418                 mono_jit_unlock ();
3419                 return res;
3420         }
3421
3422         res = mono_metadata_signature_alloc (mono_defaults.corlib, arity + 1);
3423
3424         res->pinvoke = 1;
3425 #ifdef MONO_ARCH_VARARG_ICALLS
3426         /* Only set this only some archs since not all backends can handle varargs+pinvoke */
3427         res->call_convention = MONO_CALL_VARARG;
3428 #endif
3429
3430 #ifdef PLATFORM_WIN32
3431         res->call_convention = MONO_CALL_C;
3432 #endif
3433
3434         res->params [0] = &mono_defaults.int_class->byval_arg;  
3435         for (i = 0; i < arity; i++)
3436                 res->params [i + 1] = &mono_defaults.int_class->byval_arg;
3437
3438         res->ret = &mono_defaults.object_class->byval_arg;
3439
3440         g_hash_table_insert (sighash, GINT_TO_POINTER (arity), res);
3441         mono_jit_unlock ();
3442
3443         return res;
3444 }
3445
3446 MonoJitICallInfo *
3447 mono_get_array_new_va_icall (int rank)
3448 {
3449         MonoMethodSignature *esig;
3450         char icall_name [256];
3451         char *name;
3452         MonoJitICallInfo *info;
3453
3454         /* Need to register the icall so it gets an icall wrapper */
3455         sprintf (icall_name, "ves_array_new_va_%d", rank);
3456
3457         mono_jit_lock ();
3458         info = mono_find_jit_icall_by_name (icall_name);
3459         if (info == NULL) {
3460                 esig = mono_get_array_new_va_signature (rank);
3461                 name = g_strdup (icall_name);
3462                 info = mono_register_jit_icall (mono_array_new_va, name, esig, FALSE);
3463
3464                 g_hash_table_insert (jit_icall_name_hash, name, name);
3465         }
3466         mono_jit_unlock ();
3467
3468         return info;
3469 }
3470
3471 static MonoMethod*
3472 get_memcpy_method (void)
3473 {
3474         static MonoMethod *memcpy_method = NULL;
3475         if (!memcpy_method) {
3476                 memcpy_method = mono_class_get_method_from_name (mono_defaults.string_class, "memcpy", 3);
3477                 if (!memcpy_method)
3478                         g_error ("Old corlib found. Install a new one");
3479         }
3480         return memcpy_method;
3481 }
3482
3483 static void
3484 handle_stobj (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *dest, MonoInst *src, const unsigned char *ip, MonoClass *klass, gboolean to_end, gboolean native, gboolean write_barrier) {
3485         MonoInst *iargs [3];
3486         int n;
3487         guint32 align = 0;
3488         MonoMethod *memcpy_method;
3489
3490         g_assert (klass);
3491         /*
3492          * This check breaks with spilled vars... need to handle it during verification anyway.
3493          * g_assert (klass && klass == src->klass && klass == dest->klass);
3494          */
3495
3496         if (native)
3497                 n = mono_class_native_size (klass, &align);
3498         else
3499                 n = mono_class_value_size (klass, &align);
3500
3501 #if HAVE_WRITE_BARRIERS
3502         /* if native is true there should be no references in the struct */
3503         if (write_barrier && klass->has_references && !native) {
3504                 iargs [0] = dest;
3505                 iargs [1] = src;
3506                 NEW_PCONST (cfg, iargs [2], klass);
3507
3508                 mono_emit_jit_icall (cfg, bblock, mono_value_copy, iargs, ip);
3509                 return;
3510         }
3511 #endif
3512
3513         /* FIXME: add write barrier handling */
3514         if ((cfg->opt & MONO_OPT_INTRINS) && !to_end && n <= sizeof (gpointer) * 5) {
3515                 MonoInst *inst;
3516                 if (dest->opcode == OP_LDADDR) {
3517                         /* Keep liveness info correct */
3518                         NEW_DUMMY_STORE (cfg, inst, dest->inst_i0->inst_c0);
3519                         MONO_ADD_INS (bblock, inst);
3520                 }
3521                 NEW_MEMCPY (cfg, inst, dest, src, n, align);
3522                 MONO_ADD_INS (bblock, inst);
3523                 return;
3524         }
3525         iargs [0] = dest;
3526         iargs [1] = src;
3527         NEW_ICONST (cfg, iargs [2], n);
3528
3529         memcpy_method = get_memcpy_method ();
3530         mono_emit_method_call_spilled_full (cfg, bblock, memcpy_method, memcpy_method->signature, iargs, ip, NULL, FALSE, to_end);
3531 }
3532
3533 static MonoMethod*
3534 get_memset_method (void)
3535 {
3536         static MonoMethod *memset_method = NULL;
3537         if (!memset_method) {
3538                 memset_method = mono_class_get_method_from_name (mono_defaults.string_class, "memset", 3);
3539                 if (!memset_method)
3540                         g_error ("Old corlib found. Install a new one");
3541         }
3542         return memset_method;
3543 }
3544
3545 static void
3546 handle_initobj (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *dest, const guchar *ip, MonoClass *klass, MonoInst **stack_start, MonoInst **sp)
3547 {
3548         MonoInst *iargs [3];
3549         MonoInst *ins, *zero_int32;
3550         int n;
3551         guint32 align;
3552         MonoMethod *memset_method;
3553
3554         NEW_ICONST (cfg, zero_int32, 0);
3555
3556         mono_class_init (klass);
3557         n = mono_class_value_size (klass, &align);
3558         MONO_INST_NEW (cfg, ins, 0);
3559         ins->cil_code = ip;
3560         ins->inst_left = dest;
3561         ins->inst_right = zero_int32;
3562         if (n == 1) {
3563                 ins->opcode = CEE_STIND_I1;
3564                 MONO_ADD_INS (bblock, ins);
3565         } else if ((n == 2) && (align >= 2)) {
3566                 ins->opcode = CEE_STIND_I2;
3567                 MONO_ADD_INS (bblock, ins);
3568         } else if ((n == 2) && (align >= 4)) {
3569                 ins->opcode = CEE_STIND_I4;
3570                 MONO_ADD_INS (bblock, ins);
3571         } else if (n <= sizeof (gpointer) * 5) {
3572                 NEW_MEMSET (cfg, ins, dest, 0, n, align);
3573                 MONO_ADD_INS (bblock, ins);
3574         } else {
3575                 memset_method = get_memset_method ();
3576                 handle_loaded_temps (cfg, bblock, stack_start, sp);
3577                 iargs [0] = dest;
3578                 NEW_ICONST (cfg, iargs [1], 0);
3579                 NEW_ICONST (cfg, iargs [2], n);
3580                 mono_emit_method_call_spilled (cfg, bblock, memset_method, memset_method->signature, iargs, ip, NULL);
3581         }
3582 }
3583
3584 static int
3585 handle_alloc (MonoCompile *cfg, MonoBasicBlock *bblock, MonoClass *klass, gboolean for_box, const guchar *ip)
3586 {
3587         MonoInst *iargs [2];
3588         void *alloc_ftn;
3589
3590         if (cfg->opt & MONO_OPT_SHARED) {
3591                 NEW_DOMAINCONST (cfg, iargs [0]);
3592                 NEW_CLASSCONST (cfg, iargs [1], klass);
3593
3594                 alloc_ftn = mono_object_new;
3595         } else if (cfg->compile_aot && bblock->out_of_line && klass->type_token && klass->image == mono_defaults.corlib) {
3596                 /* This happens often in argument checking code, eg. throw new FooException... */
3597                 /* Avoid relocations by calling a helper function specialized to mscorlib */
3598                 NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (klass->type_token));
3599                 return mono_emit_jit_icall (cfg, bblock, mono_helper_newobj_mscorlib, iargs, ip);
3600         } else {
3601                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
3602                 MonoMethod *managed_alloc = mono_gc_get_managed_allocator (vtable, for_box);
3603                 gboolean pass_lw;
3604
3605                 if (managed_alloc) {
3606                         NEW_VTABLECONST (cfg, iargs [0], vtable);
3607                         return mono_emit_method_call_spilled (cfg, bblock, managed_alloc, mono_method_signature (managed_alloc), iargs, ip, NULL);
3608                 }
3609                 alloc_ftn = mono_class_get_allocation_ftn (vtable, for_box, &pass_lw);
3610                 if (pass_lw) {
3611                         guint32 lw = vtable->klass->instance_size;
3612                         lw = ((lw + (sizeof (gpointer) - 1)) & ~(sizeof (gpointer) - 1)) / sizeof (gpointer);
3613                         NEW_ICONST (cfg, iargs [0], lw);
3614                         NEW_VTABLECONST (cfg, iargs [1], vtable);
3615                 }
3616                 else
3617                         NEW_VTABLECONST (cfg, iargs [0], vtable);
3618         }
3619
3620         return mono_emit_jit_icall (cfg, bblock, alloc_ftn, iargs, ip);
3621 }
3622
3623 static int
3624 handle_alloc_from_inst (MonoCompile *cfg, MonoBasicBlock *bblock, MonoClass *klass, MonoInst *data_inst,
3625                 gboolean for_box, const guchar *ip)
3626 {
3627         MonoInst *iargs [2];
3628         MonoMethod *managed_alloc = NULL;
3629         void *alloc_ftn;
3630         /*
3631           FIXME: we cannot get managed_alloc here because we can't get
3632           the class's vtable (because it's not a closed class)
3633
3634         MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
3635         MonoMethod *managed_alloc = mono_gc_get_managed_allocator (vtable, for_box);
3636         */
3637
3638         if (cfg->opt & MONO_OPT_SHARED) {
3639                 NEW_DOMAINCONST (cfg, iargs [0]);
3640                 iargs [1] = data_inst;
3641                 alloc_ftn = mono_object_new;
3642         } else {
3643                 g_assert (!cfg->compile_aot);
3644
3645                 if (managed_alloc) {
3646                         iargs [0] = data_inst;
3647                         return mono_emit_method_call_spilled (cfg, bblock, managed_alloc,
3648                                 mono_method_signature (managed_alloc), iargs, ip, NULL);
3649                 }
3650
3651                 iargs [0] = data_inst;
3652                 alloc_ftn = mono_object_new_specific;
3653         }
3654
3655         return mono_emit_jit_icall (cfg, bblock, alloc_ftn, iargs, ip);
3656 }
3657
3658 static MonoInst*
3659 handle_box_copy (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *val, const guchar *ip, MonoClass *klass, int temp)
3660 {
3661         MonoInst *dest, *vtoffset, *add, *vstore;
3662
3663         NEW_TEMPLOAD (cfg, dest, temp);
3664         NEW_ICONST (cfg, vtoffset, sizeof (MonoObject));
3665         MONO_INST_NEW (cfg, add, OP_PADD);
3666         add->inst_left = dest;
3667         add->inst_right = vtoffset;
3668         add->cil_code = ip;
3669         add->klass = klass;
3670         MONO_INST_NEW (cfg, vstore, CEE_STIND_I);
3671         vstore->opcode = mini_type_to_stind (cfg, &klass->byval_arg);
3672         vstore->cil_code = ip;
3673         vstore->inst_left = add;
3674         vstore->inst_right = val;
3675
3676 #ifdef MONO_ARCH_SOFT_FLOAT
3677         if (vstore->opcode == CEE_STIND_R4) {
3678                 handle_store_float (cfg, bblock, add, val, ip);
3679         } else
3680 #endif
3681         if (vstore->opcode == CEE_STOBJ) {
3682                 handle_stobj (cfg, bblock, add, val, ip, klass, FALSE, FALSE, TRUE);
3683         } else
3684                 MONO_ADD_INS (bblock, vstore);
3685
3686         NEW_TEMPLOAD (cfg, dest, temp);
3687         return dest;
3688 }
3689
3690 static MonoInst *
3691 handle_box (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *val, const guchar *ip, MonoClass *klass)
3692 {
3693         MonoInst *dest;
3694         int temp;
3695
3696         if (mono_class_is_nullable (klass)) {
3697                 MonoMethod* method = mono_class_get_method_from_name (klass, "Box", 1);
3698                 temp = mono_emit_method_call_spilled (cfg, bblock, method, mono_method_signature (method), &val, ip, NULL);
3699                 NEW_TEMPLOAD (cfg, dest, temp);
3700                 return dest;
3701         }
3702
3703         temp = handle_alloc (cfg, bblock, klass, TRUE, ip);
3704
3705         return handle_box_copy (cfg, bblock, val, ip, klass, temp);
3706 }
3707
3708 static MonoInst *
3709 handle_box_from_inst (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *val, const guchar *ip,
3710                 MonoClass *klass, MonoInst *data_inst)
3711 {
3712         int temp;
3713
3714         g_assert (!mono_class_is_nullable (klass));
3715
3716         temp = handle_alloc_from_inst (cfg, bblock, klass, data_inst, TRUE, ip);
3717
3718         return handle_box_copy (cfg, bblock, val, ip, klass, temp);
3719 }
3720
3721 static MonoInst*
3722 handle_delegate_ctor (MonoCompile *cfg, MonoBasicBlock *bblock, MonoClass *klass, MonoInst *target, MonoMethod *method, unsigned char *ip)
3723 {
3724         gpointer *trampoline;
3725         MonoInst *obj, *ins, *store, *offset_ins, *method_ins, *tramp_ins;
3726         int temp;
3727
3728         temp = handle_alloc (cfg, bblock, klass, FALSE, ip);
3729
3730         /* Inline the contents of mono_delegate_ctor */
3731
3732         /* Set target field */
3733         /* Optimize away setting of NULL target */
3734         if (!(target->opcode == OP_PCONST && target->inst_p0 == 0)) {
3735                 NEW_TEMPLOAD (cfg, obj, temp);
3736                 NEW_ICONST (cfg, offset_ins, G_STRUCT_OFFSET (MonoDelegate, target));
3737                 MONO_INST_NEW (cfg, ins, OP_PADD);
3738                 ins->inst_left = obj;
3739                 ins->inst_right = offset_ins;
3740
3741                 MONO_INST_NEW (cfg, store, CEE_STIND_REF);
3742                 store->inst_left = ins;
3743                 store->inst_right = target;
3744                 mono_bblock_add_inst (bblock, store);
3745         }
3746
3747         /* Set method field */
3748         NEW_TEMPLOAD (cfg, obj, temp);
3749         NEW_ICONST (cfg, offset_ins, G_STRUCT_OFFSET (MonoDelegate, method));
3750         MONO_INST_NEW (cfg, ins, OP_PADD);
3751         ins->inst_left = obj;
3752         ins->inst_right = offset_ins;
3753
3754         NEW_METHODCONST (cfg, method_ins, method);
3755
3756         MONO_INST_NEW (cfg, store, CEE_STIND_I);
3757         store->inst_left = ins;
3758         store->inst_right = method_ins;
3759         mono_bblock_add_inst (bblock, store);
3760
3761         /* Set invoke_impl field */
3762         NEW_TEMPLOAD (cfg, obj, temp);
3763         NEW_ICONST (cfg, offset_ins, G_STRUCT_OFFSET (MonoDelegate, invoke_impl));
3764         MONO_INST_NEW (cfg, ins, OP_PADD);
3765         ins->inst_left = obj;
3766         ins->inst_right = offset_ins;
3767
3768         trampoline = mono_create_delegate_trampoline (klass);
3769         NEW_AOTCONST (cfg, tramp_ins, MONO_PATCH_INFO_ABS, trampoline);
3770
3771         MONO_INST_NEW (cfg, store, CEE_STIND_I);
3772         store->inst_left = ins;
3773         store->inst_right = tramp_ins;
3774         mono_bblock_add_inst (bblock, store);
3775
3776         /* All the checks which are in mono_delegate_ctor () are done by the delegate trampoline */
3777
3778         NEW_TEMPLOAD (cfg, obj, temp);
3779
3780         return obj;
3781 }
3782
3783 static int
3784 handle_array_new (MonoCompile *cfg, MonoBasicBlock *bblock, int rank, MonoInst **sp, unsigned char *ip)
3785 {
3786         MonoJitICallInfo *info;
3787
3788         info = mono_get_array_new_va_icall (rank);
3789
3790         cfg->flags |= MONO_CFG_HAS_VARARGS;
3791
3792         /* FIXME: This uses info->sig, but it should use the signature of the wrapper */
3793         return mono_emit_native_call (cfg, bblock, mono_icall_get_wrapper (info), info->sig, sp, ip, TRUE, FALSE);
3794 }
3795
3796 static void
3797 mono_emit_load_got_addr (MonoCompile *cfg)
3798 {
3799         MonoInst *load, *store, *dummy_use;
3800         MonoInst *get_got;
3801
3802         if (!cfg->got_var || cfg->got_var_allocated)
3803                 return;
3804
3805         MONO_INST_NEW (cfg, get_got, OP_LOAD_GOTADDR);
3806         NEW_TEMPSTORE (cfg, store, cfg->got_var->inst_c0, get_got);
3807
3808         /* Add it to the start of the first bblock */
3809         if (cfg->bb_entry->code) {
3810                 store->next = cfg->bb_entry->code;
3811                 cfg->bb_entry->code = store;
3812         }
3813         else
3814                 MONO_ADD_INS (cfg->bb_entry, store);
3815
3816         cfg->got_var_allocated = TRUE;
3817
3818         /* 
3819          * Add a dummy use to keep the got_var alive, since real uses might
3820          * only be generated in the decompose or instruction selection phases.
3821          * Add it to end_bblock, so the variable's lifetime covers the whole
3822          * method.
3823          */
3824         NEW_TEMPLOAD (cfg, load, cfg->got_var->inst_c0);
3825         NEW_DUMMY_USE (cfg, dummy_use, load);
3826         MONO_ADD_INS (cfg->bb_exit, dummy_use);
3827 }
3828
3829 #define CODE_IS_STLOC(ip) (((ip) [0] >= CEE_STLOC_0 && (ip) [0] <= CEE_STLOC_3) || ((ip) [0] == CEE_STLOC_S))
3830
3831 gboolean
3832 mini_class_is_system_array (MonoClass *klass)
3833 {
3834         if (klass->parent == mono_defaults.array_class)
3835                 return TRUE;
3836         else
3837                 return FALSE;
3838 }
3839
3840 static gboolean
3841 mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method)
3842 {
3843         MonoMethodHeader *header = mono_method_get_header (method);
3844         MonoMethodSignature *signature = mono_method_signature (method);
3845         MonoVTable *vtable;
3846         int i;
3847
3848         if (cfg->generic_sharing_context)
3849                 return FALSE;
3850
3851         if (method->inline_failure)
3852                 return FALSE;
3853
3854 #ifdef MONO_ARCH_HAVE_LMF_OPS
3855         if (((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
3856                  (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) &&
3857             !MONO_TYPE_ISSTRUCT (signature->ret) && !mini_class_is_system_array (method->klass))
3858                 return TRUE;
3859 #endif
3860
3861         if ((method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
3862             (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
3863             (method->iflags & METHOD_IMPL_ATTRIBUTE_NOINLINING) ||
3864             (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) ||
3865             (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
3866             (method->klass->marshalbyref) ||
3867             !header || header->num_clauses ||
3868             /* fixme: why cant we inline valuetype returns? */
3869             MONO_TYPE_ISSTRUCT (signature->ret))
3870                 return FALSE;
3871
3872 #ifdef MONO_ARCH_SOFT_FLOAT
3873         /* this complicates things, fix later */
3874         if (signature->ret->type == MONO_TYPE_R4)
3875                 return FALSE;
3876 #endif
3877         /* its not worth to inline methods with valuetype arguments?? */
3878         for (i = 0; i < signature->param_count; i++) {
3879                 if (MONO_TYPE_ISSTRUCT (signature->params [i])) {
3880                         return FALSE;
3881                 }
3882 #ifdef MONO_ARCH_SOFT_FLOAT
3883                 /* this complicates things, fix later */
3884                 if (!signature->params [i]->byref && signature->params [i]->type == MONO_TYPE_R4)
3885                         return FALSE;
3886 #endif
3887         }
3888
3889         /* also consider num_locals? */
3890         /* Do the size check early to avoid creating vtables */
3891         if (getenv ("MONO_INLINELIMIT")) {
3892                 if (header->code_size >= atoi (getenv ("MONO_INLINELIMIT"))) {
3893                         return FALSE;
3894                 }
3895         } else if (header->code_size >= INLINE_LENGTH_LIMIT)
3896                 return FALSE;
3897
3898         /*
3899          * if we can initialize the class of the method right away, we do,
3900          * otherwise we don't allow inlining if the class needs initialization,
3901          * since it would mean inserting a call to mono_runtime_class_init()
3902          * inside the inlined code
3903          */
3904         if (!(cfg->opt & MONO_OPT_SHARED)) {
3905                 if (method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) {
3906                         if (cfg->run_cctors && method->klass->has_cctor) {
3907                                 if (!method->klass->runtime_info)
3908                                         /* No vtable created yet */
3909                                         return FALSE;
3910                                 vtable = mono_class_vtable (cfg->domain, method->klass);
3911                                 if (!vtable)
3912                                         return FALSE;
3913                                 /* This makes so that inline cannot trigger */
3914                                 /* .cctors: too many apps depend on them */
3915                                 /* running with a specific order... */
3916                                 if (! vtable->initialized)
3917                                         return FALSE;
3918                                 mono_runtime_class_init (vtable);
3919                         }
3920                 } else if (mono_class_needs_cctor_run (method->klass, NULL)) {
3921                         if (!method->klass->runtime_info)
3922                                 /* No vtable created yet */
3923                                 return FALSE;
3924                         vtable = mono_class_vtable (cfg->domain, method->klass);
3925                         if (!vtable)
3926                                 return FALSE;
3927                         if (!vtable->initialized)
3928                                 return FALSE;
3929                 }
3930         } else {
3931                 /* 
3932                  * If we're compiling for shared code
3933                  * the cctor will need to be run at aot method load time, for example,
3934                  * or at the end of the compilation of the inlining method.
3935                  */
3936                 if (mono_class_needs_cctor_run (method->klass, NULL) && !((method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT)))
3937                         return FALSE;
3938         }
3939         //if (!MONO_TYPE_IS_VOID (signature->ret)) return FALSE;
3940
3941         /*
3942          * CAS - do not inline methods with declarative security
3943          * Note: this has to be before any possible return TRUE;
3944          */
3945         if (mono_method_has_declsec (method))
3946                 return FALSE;
3947
3948         return TRUE;
3949 }
3950
3951 static gboolean
3952 mini_field_access_needs_cctor_run (MonoCompile *cfg, MonoMethod *method, MonoVTable *vtable)
3953 {
3954         if (vtable->initialized && !cfg->compile_aot)
3955                 return FALSE;
3956
3957         if (vtable->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT)
3958                 return FALSE;
3959
3960         if (!mono_class_needs_cctor_run (vtable->klass, method))
3961                 return FALSE;
3962
3963         if (! (method->flags & METHOD_ATTRIBUTE_STATIC) && (vtable->klass == method->klass))
3964                 /* The initialization is already done before the method is called */
3965                 return FALSE;
3966
3967         return TRUE;
3968 }
3969
3970 static MonoInst*
3971 mini_get_ldelema_ins (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *cmethod, MonoInst **sp, unsigned char *ip, gboolean is_set)
3972 {
3973         int temp, rank;
3974         MonoInst *addr;
3975         MonoMethod *addr_method;
3976         int element_size;
3977
3978         rank = mono_method_signature (cmethod)->param_count - (is_set? 1: 0);
3979
3980         if (rank == 1) {
3981                 MONO_INST_NEW (cfg, addr, CEE_LDELEMA);
3982                 addr->inst_left = sp [0];
3983                 addr->inst_right = sp [1];
3984                 addr->type = STACK_MP;
3985                 addr->klass = cmethod->klass->element_class;
3986                 return addr;
3987         }
3988
3989         if (rank == 2 && (cfg->opt & MONO_OPT_INTRINS)) {
3990 #if defined(MONO_ARCH_EMULATE_MUL_DIV) && !defined(MONO_ARCH_NO_EMULATE_MUL)
3991                 /* OP_LDELEMA2D depends on OP_LMUL */
3992 #else
3993                 MonoInst *indexes;
3994                 NEW_GROUP (cfg, indexes, sp [1], sp [2]);
3995                 MONO_INST_NEW (cfg, addr, OP_LDELEMA2D);
3996                 addr->inst_left = sp [0];
3997                 addr->inst_right = indexes;
3998                 addr->type = STACK_MP;
3999                 addr->klass = cmethod->klass->element_class;
4000                 return addr;
4001 #endif
4002         }
4003
4004         element_size = mono_class_array_element_size (cmethod->klass->element_class);
4005         addr_method = mono_marshal_get_array_address (rank, element_size);
4006         temp = mono_emit_method_call_spilled (cfg, bblock, addr_method, addr_method->signature, sp, ip, NULL);
4007         NEW_TEMPLOAD (cfg, addr, temp);
4008         return addr;
4009
4010 }
4011
4012 static MonoJitICallInfo **emul_opcode_map = NULL;
4013
4014 MonoJitICallInfo *
4015 mono_find_jit_opcode_emulation (int opcode)
4016 {
4017         g_assert (opcode >= 0 && opcode <= OP_LAST);
4018         if  (emul_opcode_map)
4019                 return emul_opcode_map [opcode];
4020         else
4021                 return NULL;
4022 }
4023
4024 static MonoInst*
4025 mini_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
4026 {
4027         MonoInst *ins = NULL;
4028         
4029         static MonoClass *runtime_helpers_class = NULL;
4030         if (! runtime_helpers_class)
4031                 runtime_helpers_class = mono_class_from_name (mono_defaults.corlib,
4032                         "System.Runtime.CompilerServices", "RuntimeHelpers");
4033
4034         if (cmethod->klass == mono_defaults.string_class) {
4035                 if (strcmp (cmethod->name, "get_Chars") == 0) {
4036                         MONO_INST_NEW (cfg, ins, OP_GETCHR);
4037                         ins->inst_i0 = args [0];
4038                         ins->inst_i1 = args [1];
4039                         return ins;
4040                 } else if (strcmp (cmethod->name, "get_Length") == 0) {
4041                         MONO_INST_NEW (cfg, ins, OP_STRLEN);
4042                         ins->inst_i0 = args [0];
4043                         return ins;
4044                 } else if (strcmp (cmethod->name, "InternalSetChar") == 0) {
4045                         MonoInst *get_addr;
4046                         MONO_INST_NEW (cfg, get_addr, OP_STR_CHAR_ADDR);
4047                         get_addr->inst_i0 = args [0];
4048                         get_addr->inst_i1 = args [1];
4049                         MONO_INST_NEW (cfg, ins, CEE_STIND_I2);
4050                         ins->inst_i0 = get_addr;
4051                         ins->inst_i1 = args [2];
4052                         return ins;
4053                 } else 
4054                         return NULL;
4055         } else if (cmethod->klass == mono_defaults.object_class) {
4056                 if (strcmp (cmethod->name, "GetType") == 0) {
4057                         MONO_INST_NEW (cfg, ins, OP_GETTYPE);
4058                         ins->inst_i0 = args [0];
4059                         return ins;
4060                 /* The OP_GETHASHCODE rule depends on OP_MUL */
4061 #if !defined(MONO_ARCH_EMULATE_MUL_DIV) && !defined(HAVE_MOVING_COLLECTOR)
4062                 } else if (strcmp (cmethod->name, "InternalGetHashCode") == 0) {
4063                         MONO_INST_NEW (cfg, ins, OP_GETHASHCODE);
4064                         ins->inst_i0 = args [0];
4065                         return ins;
4066 #endif
4067                 } else if (strcmp (cmethod->name, ".ctor") == 0) {
4068                         MONO_INST_NEW (cfg, ins, OP_NOP);
4069                         return ins;
4070                 } else
4071                         return NULL;
4072         } else if (cmethod->klass == mono_defaults.array_class) {
4073                 if (cmethod->name [0] != 'g')
4074                         return NULL;
4075
4076                 if (strcmp (cmethod->name, "get_Rank") == 0) {
4077                         MONO_INST_NEW (cfg, ins, OP_ARRAY_RANK);
4078                         ins->inst_i0 = args [0];
4079                         return ins;
4080                 } else if (strcmp (cmethod->name, "get_Length") == 0) {
4081                         MONO_INST_NEW (cfg, ins, CEE_LDLEN);
4082                         ins->inst_i0 = args [0];
4083                         return ins;
4084                 } else
4085                         return NULL;
4086         } else if (cmethod->klass == runtime_helpers_class) {
4087                 if (strcmp (cmethod->name, "get_OffsetToStringData") == 0) {
4088                         NEW_ICONST (cfg, ins, G_STRUCT_OFFSET (MonoString, chars));
4089                         return ins;
4090                 } else
4091                         return NULL;
4092         } else if (cmethod->klass == mono_defaults.thread_class) {
4093                 if (strcmp (cmethod->name, "get_CurrentThread") == 0 && (ins = mono_arch_get_thread_intrinsic (cfg)))
4094                         return ins;
4095                 if (strcmp (cmethod->name, "MemoryBarrier") == 0) {
4096                         MONO_INST_NEW (cfg, ins, OP_MEMORY_BARRIER);
4097                         return ins;
4098                 }
4099         } else if (mini_class_is_system_array (cmethod->klass) &&
4100                         strcmp (cmethod->name, "GetGenericValueImpl") == 0) {
4101                 MonoInst *sp [2];
4102                 MonoInst *ldelem, *store, *load;
4103                 MonoClass *eklass = mono_class_from_mono_type (fsig->params [1]);
4104                 int n;
4105                 n = mini_type_to_stind (cfg, &eklass->byval_arg);
4106                 if (n == CEE_STOBJ)
4107                         return NULL;
4108                 sp [0] = args [0];
4109                 sp [1] = args [1];
4110                 NEW_LDELEMA (cfg, ldelem, sp, eklass);
4111                 ldelem->flags |= MONO_INST_NORANGECHECK;
4112                 MONO_INST_NEW (cfg, store, n);
4113                 MONO_INST_NEW (cfg, load, mini_type_to_ldind (cfg, &eklass->byval_arg));
4114                 type_to_eval_stack_type (cfg, &eklass->byval_arg, load);
4115                 load->inst_left = ldelem;
4116                 store->inst_left = args [2];
4117                 store->inst_right = load;
4118                 return store;
4119         } else if (cmethod->klass == mono_defaults.math_class) {
4120                 /* 
4121                  * There is general branches code for Min/Max, but it does not work for 
4122                  * all inputs:
4123                  * http://everything2.com/?node_id=1051618
4124                  */
4125         } else if (cmethod->klass->image == mono_defaults.corlib &&
4126                            (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
4127                            (strcmp (cmethod->klass->name, "Interlocked") == 0)) {
4128                 ins = NULL;
4129
4130 #if SIZEOF_VOID_P == 8
4131                 if (strcmp (cmethod->name, "Read") == 0 && (fsig->params [0]->type == MONO_TYPE_I8)) {
4132                         /* 64 bit reads are already atomic */
4133                         MONO_INST_NEW (cfg, ins, CEE_LDIND_I8);
4134                         ins->inst_i0 = args [0];
4135                 }
4136 #endif
4137
4138 #ifdef MONO_ARCH_HAVE_ATOMIC_ADD
4139                 if (strcmp (cmethod->name, "Increment") == 0) {
4140                         MonoInst *ins_iconst;
4141                         guint32 opcode;
4142
4143                         if (fsig->params [0]->type == MONO_TYPE_I4)
4144                                 opcode = OP_ATOMIC_ADD_NEW_I4;
4145                         else if (fsig->params [0]->type == MONO_TYPE_I8)
4146                                 opcode = OP_ATOMIC_ADD_NEW_I8;
4147                         else
4148                                 g_assert_not_reached ();
4149
4150 #if SIZEOF_VOID_P == 4
4151                         if (opcode == OP_ATOMIC_ADD_NEW_I8)
4152                                 return NULL;
4153 #endif
4154
4155                         MONO_INST_NEW (cfg, ins, opcode);
4156                         MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
4157                         ins_iconst->inst_c0 = 1;
4158
4159                         ins->inst_i0 = args [0];
4160                         ins->inst_i1 = ins_iconst;
4161                 } else if (strcmp (cmethod->name, "Decrement") == 0) {
4162                         MonoInst *ins_iconst;
4163                         guint32 opcode;
4164
4165                         if (fsig->params [0]->type == MONO_TYPE_I4)
4166                                 opcode = OP_ATOMIC_ADD_NEW_I4;
4167                         else if (fsig->params [0]->type == MONO_TYPE_I8)
4168                                 opcode = OP_ATOMIC_ADD_NEW_I8;
4169                         else
4170                                 g_assert_not_reached ();
4171
4172 #if SIZEOF_VOID_P == 4
4173                         if (opcode == OP_ATOMIC_ADD_NEW_I8)
4174                                 return NULL;
4175 #endif
4176
4177                         MONO_INST_NEW (cfg, ins, opcode);
4178                         MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
4179                         ins_iconst->inst_c0 = -1;
4180
4181                         ins->inst_i0 = args [0];
4182                         ins->inst_i1 = ins_iconst;
4183                 } else if (strcmp (cmethod->name, "Add") == 0) {
4184                         guint32 opcode;
4185
4186                         if (fsig->params [0]->type == MONO_TYPE_I4)
4187                                 opcode = OP_ATOMIC_ADD_NEW_I4;
4188                         else if (fsig->params [0]->type == MONO_TYPE_I8)
4189                                 opcode = OP_ATOMIC_ADD_NEW_I8;
4190                         else
4191                                 g_assert_not_reached ();
4192
4193 #if SIZEOF_VOID_P == 4
4194                         if (opcode == OP_ATOMIC_ADD_NEW_I8)
4195                                 return NULL;
4196 #endif
4197                         
4198                         MONO_INST_NEW (cfg, ins, opcode);
4199
4200                         ins->inst_i0 = args [0];
4201                         ins->inst_i1 = args [1];
4202                 }
4203 #endif /* MONO_ARCH_HAVE_ATOMIC_ADD */
4204
4205 #ifdef MONO_ARCH_HAVE_ATOMIC_EXCHANGE
4206                 if (strcmp (cmethod->name, "Exchange") == 0) {
4207                         guint32 opcode;
4208
4209                         if (fsig->params [0]->type == MONO_TYPE_I4)
4210                                 opcode = OP_ATOMIC_EXCHANGE_I4;
4211 #if SIZEOF_VOID_P == 8
4212                         else if ((fsig->params [0]->type == MONO_TYPE_I8) ||
4213                                          (fsig->params [0]->type == MONO_TYPE_I) ||
4214                                          (fsig->params [0]->type == MONO_TYPE_OBJECT))
4215                                 opcode = OP_ATOMIC_EXCHANGE_I8;
4216 #else
4217                         else if ((fsig->params [0]->type == MONO_TYPE_I) ||
4218                                          (fsig->params [0]->type == MONO_TYPE_OBJECT))
4219                                 opcode = OP_ATOMIC_EXCHANGE_I4;
4220 #endif
4221                         else
4222                                 return NULL;
4223
4224 #if SIZEOF_VOID_P == 4
4225                         if (opcode == OP_ATOMIC_EXCHANGE_I8)
4226                                 return NULL;
4227 #endif
4228
4229                         MONO_INST_NEW (cfg, ins, opcode);
4230
4231                         ins->inst_i0 = args [0];
4232                         ins->inst_i1 = args [1];
4233                 }
4234 #endif /* MONO_ARCH_HAVE_ATOMIC_EXCHANGE */
4235
4236 #ifdef MONO_ARCH_HAVE_ATOMIC_CAS_IMM
4237                 /* 
4238                  * Can't implement CompareExchange methods this way since they have
4239                  * three arguments. We can implement one of the common cases, where the new
4240                  * value is a constant.
4241                  */
4242                 if ((strcmp (cmethod->name, "CompareExchange") == 0)) {
4243                         if (fsig->params [1]->type == MONO_TYPE_I4 && args [2]->opcode == OP_ICONST) {
4244                                 MONO_INST_NEW (cfg, ins, OP_ATOMIC_CAS_IMM_I4);
4245                                 ins->inst_i0 = args [0];
4246                                 ins->inst_i1 = args [1];
4247                                 ins->backend.data = GINT_TO_POINTER (args [2]->inst_c0);
4248                         }
4249                         /* The I8 case is hard to detect, since the arg might be a conv.i8 (iconst) tree */
4250                 }
4251 #endif /* MONO_ARCH_HAVE_ATOMIC_CAS_IMM */
4252
4253                 if (ins)
4254                         return ins;
4255         } else if (cmethod->klass->image == mono_defaults.corlib) {
4256                 if (cmethod->name [0] == 'B' && strcmp (cmethod->name, "Break") == 0
4257                                 && strcmp (cmethod->klass->name, "Debugger") == 0) {
4258                         MONO_INST_NEW (cfg, ins, OP_BREAK);
4259                         return ins;
4260                 }
4261                 if (cmethod->name [0] == 'g' && strcmp (cmethod->name, "get_IsRunningOnWindows") == 0
4262                                 && strcmp (cmethod->klass->name, "Environment") == 0) {
4263 #ifdef PLATFORM_WIN32
4264                         NEW_ICONST (cfg, ins, 1);
4265 #else
4266                         NEW_ICONST (cfg, ins, 0);
4267 #endif
4268                         return ins;
4269                 }
4270         }
4271
4272         return mono_arch_get_inst_for_method (cfg, cmethod, fsig, args);
4273 }
4274
4275 static void
4276 mono_save_args (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethodSignature *sig, MonoInst **sp, MonoInst **args)
4277 {
4278         MonoInst *store, *temp;
4279         int i;
4280
4281         g_assert (!MONO_TYPE_ISSTRUCT (sig->ret));
4282
4283         if (!sig->hasthis && sig->param_count == 0) 
4284                 return;
4285
4286         if (sig->hasthis) {
4287                 if (sp [0]->opcode == OP_ICONST) {
4288                         *args++ = sp [0];
4289                 } else {
4290                         temp = mono_compile_create_var (cfg, type_from_stack_type (*sp), OP_LOCAL);
4291                         *args++ = temp;
4292                         NEW_TEMPSTORE (cfg, store, temp->inst_c0, *sp);
4293                         /* FIXME: handle CEE_STIND_R4 */
4294                         store->cil_code = sp [0]->cil_code;
4295                         MONO_ADD_INS (bblock, store);
4296                 }
4297                 sp++;
4298         }
4299
4300         for (i = 0; i < sig->param_count; ++i) {
4301                 if (sp [0]->opcode == OP_ICONST) {
4302                         *args++ = sp [0];
4303                 } else {
4304                         temp = mono_compile_create_var (cfg, sig->params [i], OP_LOCAL);
4305                         *args++ = temp;
4306                         NEW_TEMPSTORE (cfg, store, temp->inst_c0, *sp);
4307                         store->cil_code = sp [0]->cil_code;
4308                         /* FIXME: handle CEE_STIND_R4 */
4309                         if (store->opcode == CEE_STOBJ) {
4310                                 NEW_TEMPLOADA (cfg, store, temp->inst_c0);
4311                                 handle_stobj (cfg, bblock, store, *sp, sp [0]->cil_code, temp->klass, FALSE, FALSE, FALSE);
4312 #ifdef MONO_ARCH_SOFT_FLOAT
4313                         } else if (store->opcode == CEE_STIND_R4) {
4314                                 NEW_TEMPLOADA (cfg, store, temp->inst_c0);
4315                                 handle_store_float (cfg, bblock, store, *sp, sp [0]->cil_code);
4316 #endif
4317                         } else {
4318                                 MONO_ADD_INS (bblock, store);
4319                         } 
4320                 }
4321                 sp++;
4322         }
4323 }
4324 #define MONO_INLINE_CALLED_LIMITED_METHODS 0
4325 #define MONO_INLINE_CALLER_LIMITED_METHODS 0
4326
4327 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
4328 static char*
4329 mono_inline_called_method_name_limit = NULL;
4330 static gboolean check_inline_called_method_name_limit (MonoMethod *called_method) {
4331         char *called_method_name = mono_method_full_name (called_method, TRUE);
4332         int strncmp_result;
4333         
4334         if (mono_inline_called_method_name_limit == NULL) {
4335                 char *limit_string = getenv ("MONO_INLINE_CALLED_METHOD_NAME_LIMIT");
4336                 if (limit_string != NULL) {
4337                         mono_inline_called_method_name_limit = limit_string;
4338                 } else {
4339                         mono_inline_called_method_name_limit = (char *) "";
4340                 }
4341         }
4342         
4343         strncmp_result = strncmp (called_method_name, mono_inline_called_method_name_limit, strlen (mono_inline_called_method_name_limit));
4344         g_free (called_method_name);
4345         
4346         //return (strncmp_result <= 0);
4347         return (strncmp_result == 0);
4348 }
4349 #endif
4350
4351 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
4352 static char*
4353 mono_inline_caller_method_name_limit = NULL;
4354 static gboolean check_inline_caller_method_name_limit (MonoMethod *caller_method) {
4355         char *caller_method_name = mono_method_full_name (caller_method, TRUE);
4356         int strncmp_result;
4357         
4358         if (mono_inline_caller_method_name_limit == NULL) {
4359                 char *limit_string = getenv ("MONO_INLINE_CALLER_METHOD_NAME_LIMIT");
4360                 if (limit_string != NULL) {
4361                         mono_inline_caller_method_name_limit = limit_string;
4362                 } else {
4363                         mono_inline_caller_method_name_limit = (char *) "";
4364                 }
4365         }
4366         
4367         strncmp_result = strncmp (caller_method_name, mono_inline_caller_method_name_limit, strlen (mono_inline_caller_method_name_limit));
4368         g_free (caller_method_name);
4369         
4370         //return (strncmp_result <= 0);
4371         return (strncmp_result == 0);
4372 }
4373 #endif
4374
4375 static int
4376 inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoBasicBlock *bblock, MonoInst **sp,
4377                 guchar *ip, guint real_offset, GList *dont_inline, MonoBasicBlock **last_b, gboolean inline_allways)
4378 {
4379         MonoInst *ins, *rvar = NULL;
4380         MonoMethodHeader *cheader;
4381         MonoBasicBlock *ebblock, *sbblock;
4382         int i, costs, new_locals_offset;
4383         MonoMethod *prev_inlined_method;
4384         MonoBasicBlock **prev_cil_offset_to_bb;
4385         unsigned char* prev_cil_start;
4386         guint32 prev_cil_offset_to_bb_len;
4387
4388         g_assert (cfg->exception_type == MONO_EXCEPTION_NONE);
4389
4390 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
4391         if ((! inline_allways) && ! check_inline_called_method_name_limit (cmethod))
4392                 return 0;
4393 #endif
4394 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
4395         if ((! inline_allways) && ! check_inline_caller_method_name_limit (cfg->method))
4396                 return 0;
4397 #endif
4398
4399         if (bblock->out_of_line && !inline_allways)
4400                 return 0;
4401
4402         if (cfg->verbose_level > 2)
4403                 g_print ("INLINE START %p %s -> %s\n", cmethod,  mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
4404
4405         if (!cmethod->inline_info) {
4406                 mono_jit_stats.inlineable_methods++;
4407                 cmethod->inline_info = 1;
4408         }
4409         /* allocate space to store the return value */
4410         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
4411                 rvar =  mono_compile_create_var (cfg, fsig->ret, OP_LOCAL);
4412         }
4413
4414         /* allocate local variables */
4415         cheader = mono_method_get_header (cmethod);
4416         new_locals_offset = cfg->num_varinfo;
4417         for (i = 0; i < cheader->num_locals; ++i)
4418                 mono_compile_create_var (cfg, cheader->locals [i], OP_LOCAL);
4419
4420         /* allocate starte and end blocks */
4421         sbblock = NEW_BBLOCK (cfg);
4422         sbblock->block_num = cfg->num_bblocks++;
4423         sbblock->real_offset = real_offset;
4424
4425         ebblock = NEW_BBLOCK (cfg);
4426         ebblock->block_num = cfg->num_bblocks++;
4427         ebblock->real_offset = real_offset;
4428
4429         prev_inlined_method = cfg->inlined_method;
4430         cfg->inlined_method = cmethod;
4431         prev_cil_offset_to_bb = cfg->cil_offset_to_bb;
4432         prev_cil_offset_to_bb_len = cfg->cil_offset_to_bb_len;
4433         prev_cil_start = cfg->cil_start;
4434
4435         costs = mono_method_to_ir (cfg, cmethod, sbblock, ebblock, new_locals_offset, rvar, dont_inline, sp, real_offset, *ip == CEE_CALLVIRT);
4436
4437         cfg->inlined_method = prev_inlined_method;
4438         cfg->cil_offset_to_bb = prev_cil_offset_to_bb;
4439         cfg->cil_offset_to_bb_len = prev_cil_offset_to_bb_len;
4440         cfg->cil_start = prev_cil_start;
4441
4442         if ((costs >= 0 && costs < 60) || inline_allways) {
4443                 if (cfg->verbose_level > 2)
4444                         g_print ("INLINE END %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
4445                 
4446                 mono_jit_stats.inlined_methods++;
4447
4448                 /* always add some code to avoid block split failures */
4449                 MONO_INST_NEW (cfg, ins, OP_NOP);
4450                 MONO_ADD_INS (bblock, ins);
4451                 ins->cil_code = ip;
4452
4453                 bblock->next_bb = sbblock;
4454                 link_bblock (cfg, bblock, sbblock);
4455
4456                 if (rvar) {
4457                         NEW_TEMPLOAD (cfg, ins, rvar->inst_c0);
4458                         NEW_TEMPLOAD_SOFT_FLOAT (cfg, ebblock, ins, rvar->inst_c0, ip);
4459                         *sp++ = ins;
4460                 }
4461                 *last_b = ebblock;
4462                 return costs + 1;
4463         } else {
4464                 if (cfg->verbose_level > 2)
4465                         g_print ("INLINE ABORTED %s\n", mono_method_full_name (cmethod, TRUE));
4466                 cfg->exception_type = MONO_EXCEPTION_NONE;
4467                 mono_loader_clear_error ();
4468                 cmethod->inline_failure = TRUE;
4469         }
4470         return 0;
4471 }
4472
4473 /*
4474  * Some of these comments may well be out-of-date.
4475  * Design decisions: we do a single pass over the IL code (and we do bblock 
4476  * splitting/merging in the few cases when it's required: a back jump to an IL
4477  * address that was not already seen as bblock starting point).
4478  * Code is validated as we go (full verification is still better left to metadata/verify.c).
4479  * Complex operations are decomposed in simpler ones right away. We need to let the 
4480  * arch-specific code peek and poke inside this process somehow (except when the 
4481  * optimizations can take advantage of the full semantic info of coarse opcodes).
4482  * All the opcodes of the form opcode.s are 'normalized' to opcode.
4483  * MonoInst->opcode initially is the IL opcode or some simplification of that 
4484  * (OP_LOAD, OP_STORE). The arch-specific code may rearrange it to an arch-specific 
4485  * opcode with value bigger than OP_LAST.
4486  * At this point the IR can be handed over to an interpreter, a dumb code generator
4487  * or to the optimizing code generator that will translate it to SSA form.
4488  *
4489  * Profiling directed optimizations.
4490  * We may compile by default with few or no optimizations and instrument the code
4491  * or the user may indicate what methods to optimize the most either in a config file
4492  * or through repeated runs where the compiler applies offline the optimizations to 
4493  * each method and then decides if it was worth it.
4494  *
4495  */
4496
4497 #define CHECK_TYPE(ins) if (!(ins)->type) UNVERIFIED
4498 #define CHECK_STACK(num) if ((sp - stack_start) < (num)) UNVERIFIED
4499 #define CHECK_STACK_OVF(num) if (((sp - stack_start) + (num)) > header->max_stack) UNVERIFIED
4500 #define CHECK_ARG(num) if ((unsigned)(num) >= (unsigned)num_args) UNVERIFIED
4501 #define CHECK_LOCAL(num) if ((unsigned)(num) >= (unsigned)header->num_locals) UNVERIFIED
4502 #define CHECK_OPSIZE(size) if (ip + size > end) UNVERIFIED
4503 #define CHECK_UNVERIFIABLE(cfg) if (cfg->unverifiable) UNVERIFIED
4504 #define CHECK_TYPELOAD(klass) if (!(klass) || (klass)->exception_type) {cfg->exception_ptr = klass; goto load_error;}
4505
4506 /* offset from br.s -> br like opcodes */
4507 #define BIG_BRANCH_OFFSET 13
4508
4509 static inline gboolean
4510 ip_in_bb (MonoCompile *cfg, MonoBasicBlock *bb, const guint8* ip)
4511 {
4512         MonoBasicBlock *b = cfg->cil_offset_to_bb [ip - cfg->cil_start];
4513         
4514         return b == NULL || b == bb;
4515 }
4516
4517 static int
4518 get_basic_blocks (MonoCompile *cfg, MonoMethodHeader* header, guint real_offset, unsigned char *start, unsigned char *end, unsigned char **pos)
4519 {
4520         unsigned char *ip = start;
4521         unsigned char *target;
4522         int i;
4523         guint cli_addr;
4524         MonoBasicBlock *bblock;
4525         const MonoOpcode *opcode;
4526
4527         while (ip < end) {
4528                 cli_addr = ip - start;
4529                 i = mono_opcode_value ((const guint8 **)&ip, end);
4530                 if (i < 0)
4531                         UNVERIFIED;
4532                 opcode = &mono_opcodes [i];
4533                 switch (opcode->argument) {
4534                 case MonoInlineNone:
4535                         ip++; 
4536                         break;
4537                 case MonoInlineString:
4538                 case MonoInlineType:
4539                 case MonoInlineField:
4540                 case MonoInlineMethod:
4541                 case MonoInlineTok:
4542                 case MonoInlineSig:
4543                 case MonoShortInlineR:
4544                 case MonoInlineI:
4545                         ip += 5;
4546                         break;
4547                 case MonoInlineVar:
4548                         ip += 3;
4549                         break;
4550                 case MonoShortInlineVar:
4551                 case MonoShortInlineI:
4552                         ip += 2;
4553                         break;
4554                 case MonoShortInlineBrTarget:
4555                         target = start + cli_addr + 2 + (signed char)ip [1];
4556                         GET_BBLOCK (cfg, bblock, target);
4557                         ip += 2;
4558                         if (ip < end)
4559                                 GET_BBLOCK (cfg, bblock, ip);
4560                         break;
4561                 case MonoInlineBrTarget:
4562                         target = start + cli_addr + 5 + (gint32)read32 (ip + 1);
4563                         GET_BBLOCK (cfg, bblock, target);
4564                         ip += 5;
4565                         if (ip < end)
4566                                 GET_BBLOCK (cfg, bblock, ip);
4567                         break;
4568                 case MonoInlineSwitch: {
4569                         guint32 n = read32 (ip + 1);
4570                         guint32 j;
4571                         ip += 5;
4572                         cli_addr += 5 + 4 * n;
4573                         target = start + cli_addr;
4574                         GET_BBLOCK (cfg, bblock, target);
4575                         
4576                         for (j = 0; j < n; ++j) {
4577                                 target = start + cli_addr + (gint32)read32 (ip);
4578                                 GET_BBLOCK (cfg, bblock, target);
4579                                 ip += 4;
4580                         }
4581                         break;
4582                 }
4583                 case MonoInlineR:
4584                 case MonoInlineI8:
4585                         ip += 9;
4586                         break;
4587                 default:
4588                         g_assert_not_reached ();
4589                 }
4590
4591                 if (i == CEE_THROW) {
4592                         unsigned char *bb_start = ip - 1;
4593                         
4594                         /* Find the start of the bblock containing the throw */
4595                         bblock = NULL;
4596                         while ((bb_start >= start) && !bblock) {
4597                                 bblock = cfg->cil_offset_to_bb [(bb_start) - start];
4598                                 bb_start --;
4599                         }
4600                         if (bblock)
4601                                 bblock->out_of_line = 1;
4602                 }
4603         }
4604         return 0;
4605 unverified:
4606         *pos = ip;
4607         return 1;
4608 }
4609
4610 static MonoInst*
4611 emit_tree (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *ins, const guint8* ip_next)
4612 {
4613         MonoInst *store, *temp, *load;
4614         
4615         if (ip_in_bb (cfg, bblock, ip_next) &&
4616                 (CODE_IS_STLOC (ip_next) || *ip_next == CEE_RET))
4617                         return ins;
4618         
4619         temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
4620         temp->flags |= MONO_INST_IS_TEMP;
4621         NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
4622         /* FIXME: handle CEE_STIND_R4 */
4623         store->cil_code = ins->cil_code;
4624         MONO_ADD_INS (bblock, store);
4625         NEW_TEMPLOAD (cfg, load, temp->inst_c0);
4626         load->cil_code = ins->cil_code;
4627         return load;
4628 }
4629
4630 static inline MonoMethod *
4631 mini_get_method_allow_open (MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
4632 {
4633         MonoMethod *method;
4634
4635         if (m->wrapper_type != MONO_WRAPPER_NONE)
4636                 return mono_method_get_wrapper_data (m, token);
4637
4638         method = mono_get_method_full (m->klass->image, token, klass, context);
4639
4640         return method;
4641 }
4642
4643 static inline MonoMethod *
4644 mini_get_method (MonoCompile *cfg, MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
4645 {
4646         MonoMethod *method = mini_get_method_allow_open (m, token, klass, context);
4647
4648         if (method && cfg && !cfg->generic_sharing_context && mono_class_is_open_constructed_type (&method->klass->byval_arg))
4649                 return NULL;
4650
4651         return method;
4652 }
4653
4654 static inline MonoClass*
4655 mini_get_class (MonoMethod *method, guint32 token, MonoGenericContext *context)
4656 {
4657         MonoClass *klass;
4658
4659         if (method->wrapper_type != MONO_WRAPPER_NONE)
4660                 klass = mono_method_get_wrapper_data (method, token);
4661         else
4662                 klass = mono_class_get_full (method->klass->image, token, context);
4663         if (klass)
4664                 mono_class_init (klass);
4665         return klass;
4666 }
4667
4668 /*
4669  * Returns TRUE if the JIT should abort inlining because "callee"
4670  * is influenced by security attributes.
4671  */
4672 static
4673 gboolean check_linkdemand (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee, MonoBasicBlock *bblock, unsigned char *ip)
4674 {
4675         guint32 result;
4676         
4677         if ((cfg->method != caller) && mono_method_has_declsec (callee)) {
4678                 return TRUE;
4679         }
4680         
4681         result = mono_declsec_linkdemand (cfg->domain, caller, callee);
4682         if (result == MONO_JIT_SECURITY_OK)
4683                 return FALSE;
4684
4685         if (result == MONO_JIT_LINKDEMAND_ECMA) {
4686                 /* Generate code to throw a SecurityException before the actual call/link */
4687                 MonoSecurityManager *secman = mono_security_manager_get_methods ();
4688                 MonoInst *args [2];
4689
4690                 NEW_ICONST (cfg, args [0], 4);
4691                 NEW_METHODCONST (cfg, args [1], caller);
4692                 mono_emit_method_call_spilled (cfg, bblock, secman->linkdemandsecurityexception, mono_method_signature (secman->linkdemandsecurityexception), args, ip, NULL);
4693         } else if (cfg->exception_type == MONO_EXCEPTION_NONE) {
4694                  /* don't hide previous results */
4695                 cfg->exception_type = MONO_EXCEPTION_SECURITY_LINKDEMAND;
4696                 cfg->exception_data = result;
4697                 return TRUE;
4698         }
4699         
4700         return FALSE;
4701 }
4702
4703 static MonoMethod*
4704 method_access_exception (void)
4705 {
4706         static MonoMethod *method = NULL;
4707
4708         if (!method) {
4709                 MonoSecurityManager *secman = mono_security_manager_get_methods ();
4710                 method = mono_class_get_method_from_name (secman->securitymanager,
4711                                                           "MethodAccessException", 2);
4712         }
4713         g_assert (method);
4714         return method;
4715 }
4716
4717 static void
4718 emit_throw_method_access_exception (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee,
4719                                     MonoBasicBlock *bblock, unsigned char *ip)
4720 {
4721         MonoMethod *thrower = method_access_exception ();
4722         MonoInst *args [2];
4723
4724         NEW_METHODCONST (cfg, args [0], caller);
4725         NEW_METHODCONST (cfg, args [1], callee);
4726         mono_emit_method_call_spilled (cfg, bblock, thrower,
4727                 mono_method_signature (thrower), args, ip, NULL);
4728 }
4729
4730 static MonoMethod*
4731 verification_exception (void)
4732 {
4733         static MonoMethod *method = NULL;
4734
4735         if (!method) {
4736                 MonoSecurityManager *secman = mono_security_manager_get_methods ();
4737                 method = mono_class_get_method_from_name (secman->securitymanager,
4738                                                           "VerificationException", 0);
4739         }
4740         g_assert (method);
4741         return method;
4742 }
4743
4744 static void
4745 emit_throw_verification_exception (MonoCompile *cfg, MonoBasicBlock *bblock, unsigned char *ip)
4746 {
4747         MonoMethod *thrower = verification_exception ();
4748
4749         mono_emit_method_call_spilled (cfg, bblock, thrower,
4750                 mono_method_signature (thrower),
4751                 NULL, ip, NULL);
4752 }
4753
4754 static void
4755 ensure_method_is_allowed_to_call_method (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee,
4756                                          MonoBasicBlock *bblock, unsigned char *ip)
4757 {
4758         MonoSecurityCoreCLRLevel caller_level = mono_security_core_clr_method_level (caller, TRUE);
4759         MonoSecurityCoreCLRLevel callee_level = mono_security_core_clr_method_level (callee, TRUE);
4760         gboolean is_safe = TRUE;
4761
4762         if (!(caller_level >= callee_level ||
4763                         caller_level == MONO_SECURITY_CORE_CLR_SAFE_CRITICAL ||
4764                         callee_level == MONO_SECURITY_CORE_CLR_SAFE_CRITICAL)) {
4765                 is_safe = FALSE;
4766         }
4767
4768         if (!is_safe)
4769                 emit_throw_method_access_exception (cfg, caller, callee, bblock, ip);
4770 }
4771
4772 static gboolean
4773 method_is_safe (MonoMethod *method)
4774 {
4775         /*
4776         if (strcmp (method->name, "unsafeMethod") == 0)
4777                 return FALSE;
4778         */
4779         return TRUE;
4780 }
4781
4782 /*
4783  * Check that the IL instructions at ip are the array initialization
4784  * sequence and return the pointer to the data and the size.
4785  */
4786 static const char*
4787 initialize_array_data (MonoMethod *method, gboolean aot, unsigned char *ip, MonoInst *newarr, int *out_size)
4788 {
4789         /*
4790          * newarr[System.Int32]
4791          * dup
4792          * ldtoken field valuetype ...
4793          * call void class [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype [mscorlib]System.RuntimeFieldHandle)
4794          */
4795         if (ip [0] == CEE_DUP && ip [1] == CEE_LDTOKEN && ip [5] == 0x4 && ip [6] == CEE_CALL) {
4796                 MonoClass *klass = newarr->inst_newa_class;
4797                 guint32 field_token = read32 (ip + 2);
4798                 guint32 field_index = field_token & 0xffffff;
4799                 guint32 token = read32 (ip + 7);
4800                 guint32 rva;
4801                 const char *data_ptr;
4802                 int size = 0;
4803                 MonoMethod *cmethod;
4804                 MonoClass *dummy_class;
4805                 MonoClassField *field = mono_field_from_token (method->klass->image, field_token, &dummy_class, NULL);
4806                 int dummy_align;
4807
4808                 if (!field)
4809                         return NULL;
4810
4811                 if (newarr->inst_newa_len->opcode != OP_ICONST)
4812                         return NULL;
4813                 cmethod = mini_get_method (NULL, method, token, NULL, NULL);
4814                 if (!cmethod)
4815                         return NULL;
4816                 if (strcmp (cmethod->name, "InitializeArray") || strcmp (cmethod->klass->name, "RuntimeHelpers") || cmethod->klass->image != mono_defaults.corlib)
4817                         return NULL;
4818                 switch (mono_type_get_underlying_type (&klass->byval_arg)->type) {
4819                 case MONO_TYPE_BOOLEAN:
4820                 case MONO_TYPE_I1:
4821                 case MONO_TYPE_U1:
4822                         size = 1; break;
4823                 /* we need to swap on big endian, so punt. Should we handle R4 and R8 as well? */
4824 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
4825                 case MONO_TYPE_CHAR:
4826                 case MONO_TYPE_I2:
4827                 case MONO_TYPE_U2:
4828                         size = 2; break;
4829                 case MONO_TYPE_I4:
4830                 case MONO_TYPE_U4:
4831                 case MONO_TYPE_R4:
4832                         size = 4; break;
4833                 case MONO_TYPE_R8:
4834 #ifdef ARM_FPU_FPA
4835                         return NULL; /* stupid ARM FP swapped format */
4836 #endif
4837                 case MONO_TYPE_I8:
4838                 case MONO_TYPE_U8:
4839                         size = 8; break;
4840 #endif
4841                 default:
4842                         return NULL;
4843                 }
4844                 size *= newarr->inst_newa_len->inst_c0;
4845                 if (size > mono_type_size (field->type, &dummy_align))
4846                     return NULL;
4847                 *out_size = size;
4848                 /*g_print ("optimized in %s: size: %d, numelems: %d\n", method->name, size, newarr->inst_newa_len->inst_c0);*/
4849                 field_index = read32 (ip + 2) & 0xffffff;
4850                 mono_metadata_field_info (method->klass->image, field_index - 1, NULL, &rva, NULL);
4851                 data_ptr = mono_image_rva_map (method->klass->image, rva);
4852                 /*g_print ("field: 0x%08x, rva: %d, rva_ptr: %p\n", read32 (ip + 2), rva, data_ptr);*/
4853                 /* for aot code we do the lookup on load */
4854                 if (aot && data_ptr)
4855                         return GUINT_TO_POINTER (rva);
4856                 return data_ptr;
4857         }
4858         return NULL;
4859 }
4860
4861 static void
4862 set_exception_type_from_invalid_il (MonoCompile *cfg, MonoMethod *method, unsigned char *ip)
4863 {
4864         char *method_fname = mono_method_full_name (method, TRUE);
4865         char *method_code;
4866
4867         if (mono_method_get_header (method)->code_size == 0)
4868                 method_code = g_strdup ("method body is empty.");
4869         else
4870                 method_code = mono_disasm_code_one (NULL, method, ip, NULL);
4871         cfg->exception_type = MONO_EXCEPTION_INVALID_PROGRAM;
4872         cfg->exception_message = g_strdup_printf ("Invalid IL code in %s: %s\n", method_fname, method_code);
4873         g_free (method_fname);
4874         g_free (method_code);
4875 }
4876
4877 static void
4878 set_exception_object (MonoCompile *cfg, MonoException *exception)
4879 {
4880         cfg->exception_type = MONO_EXCEPTION_OBJECT_SUPPLIED;
4881         MONO_GC_REGISTER_ROOT (cfg->exception_ptr);
4882         cfg->exception_ptr = exception;
4883 }
4884
4885 static MonoInst*
4886 get_runtime_generic_context (MonoCompile *cfg, MonoMethod *method, int context_used, MonoInst *this, unsigned char *ip)
4887 {
4888         g_assert (!method->klass->valuetype);
4889
4890         if (context_used & MONO_GENERIC_CONTEXT_USED_METHOD) {
4891                 MonoInst *mrgctx_loc, *mrgctx_var;
4892
4893                 g_assert (!this);
4894                 g_assert (method->is_inflated && mono_method_get_context (method)->method_inst);
4895
4896                 mrgctx_loc = mono_get_vtable_var (cfg);
4897                 NEW_TEMPLOAD (cfg, mrgctx_var, mrgctx_loc->inst_c0);
4898
4899                 return mrgctx_var;
4900         } else if (method->flags & METHOD_ATTRIBUTE_STATIC) {
4901                 MonoInst *vtable_loc, *vtable_var;
4902
4903                 g_assert (!this);
4904
4905                 vtable_loc = mono_get_vtable_var (cfg);
4906                 NEW_TEMPLOAD (cfg, vtable_var, vtable_loc->inst_c0);
4907
4908                 if (method->is_inflated && mono_method_get_context (method)->method_inst) {
4909                         MonoInst *mrgctx_var = vtable_var;
4910
4911                         g_assert (G_STRUCT_OFFSET (MonoMethodRuntimeGenericContext, class_vtable) == 0);
4912
4913                         MONO_INST_NEW (cfg, vtable_var, CEE_LDIND_I);
4914                         vtable_var->cil_code = ip;
4915                         vtable_var->inst_left = mrgctx_var;
4916                         vtable_var->type = STACK_PTR;
4917                 }
4918
4919                 return vtable_var;
4920         } else {
4921                 MonoInst *vtable;
4922
4923                 g_assert (this);
4924
4925                 MONO_INST_NEW (cfg, vtable, CEE_LDIND_I);
4926                 vtable->inst_left = this;
4927                 vtable->type = STACK_PTR;
4928
4929                 return vtable;
4930         }
4931 }
4932
4933 static MonoInst*
4934 get_runtime_generic_context_other_table_ptr (MonoCompile *cfg, MonoBasicBlock *bblock,
4935         MonoInst *rgc_ptr, guint32 slot, const unsigned char *ip)
4936 {
4937         MonoMethodSignature *sig = helper_sig_rgctx_lazy_fetch_trampoline;
4938         guint8 *tramp = mono_create_rgctx_lazy_fetch_trampoline (slot);
4939         int temp;
4940         MonoInst *field;
4941
4942         temp = mono_emit_native_call (cfg, bblock, tramp, sig, &rgc_ptr, ip, FALSE, FALSE);
4943
4944         NEW_TEMPLOAD (cfg, field, temp);
4945
4946         return field;
4947 }
4948
4949 static MonoInst*
4950 get_runtime_generic_context_ptr (MonoCompile *cfg, MonoMethod *method, int context_used, MonoBasicBlock *bblock,
4951         MonoClass *klass, MonoGenericContext *generic_context, MonoInst *rgctx, int rgctx_type, unsigned char *ip)
4952 {
4953         guint32 slot = mono_method_lookup_or_register_other_info (method,
4954                 context_used & MONO_GENERIC_CONTEXT_USED_METHOD, &klass->byval_arg, rgctx_type, generic_context);
4955
4956         return get_runtime_generic_context_other_table_ptr (cfg, bblock, rgctx, slot, ip);
4957 }
4958
4959 static MonoInst*
4960 get_runtime_generic_context_method (MonoCompile *cfg, MonoMethod *method, int context_used, MonoBasicBlock *bblock,
4961         MonoMethod *cmethod, MonoGenericContext *generic_context, MonoInst *rgctx, int rgctx_type, const unsigned char *ip)
4962 {
4963         guint32 slot = mono_method_lookup_or_register_other_info (method,
4964                 context_used & MONO_GENERIC_CONTEXT_USED_METHOD, cmethod, rgctx_type, generic_context);
4965
4966         return get_runtime_generic_context_other_table_ptr (cfg, bblock, rgctx, slot, ip);
4967 }
4968
4969 static MonoInst*
4970 get_runtime_generic_context_field (MonoCompile *cfg, MonoMethod *method, int context_used, MonoBasicBlock *bblock,
4971         MonoClassField *field, MonoGenericContext *generic_context, MonoInst *rgctx, int rgctx_type,
4972         const unsigned char *ip)
4973 {
4974         guint32 slot = mono_method_lookup_or_register_other_info (method,
4975                 context_used & MONO_GENERIC_CONTEXT_USED_METHOD, field, rgctx_type, generic_context);
4976
4977         return get_runtime_generic_context_other_table_ptr (cfg, bblock, rgctx, slot, ip);
4978 }
4979
4980 static MonoInst*
4981 get_runtime_generic_context_method_rgctx (MonoCompile *cfg, MonoMethod *method, int context_used, MonoBasicBlock *bblock,
4982         MonoMethod *rgctx_method, MonoGenericContext *generic_context, MonoInst *rgctx, const unsigned char *ip)
4983 {
4984         guint32 slot = mono_method_lookup_or_register_other_info (method,
4985                 context_used & MONO_GENERIC_CONTEXT_USED_METHOD, rgctx_method,
4986                 MONO_RGCTX_INFO_METHOD_RGCTX, generic_context);
4987
4988         return get_runtime_generic_context_other_table_ptr (cfg, bblock, rgctx, slot, ip);
4989 }
4990
4991 static gboolean
4992 generic_class_is_reference_type (MonoCompile *cfg, MonoClass *klass)
4993 {
4994         MonoType *type;
4995
4996         if (cfg->generic_sharing_context)
4997                 type = mini_get_basic_type_from_generic (cfg->generic_sharing_context, &klass->byval_arg);
4998         else
4999                 type = &klass->byval_arg;
5000         return MONO_TYPE_IS_REFERENCE (type);
5001 }
5002
5003 /**
5004  * Handles unbox of a Nullable<T>, returning a temp variable where the
5005  * result is stored.  If a rgctx is passed, then shared generic code
5006  * is generated.
5007  */
5008 static int
5009 handle_unbox_nullable (MonoCompile* cfg, MonoMethod *caller_method, int context_used, MonoBasicBlock* bblock,
5010         MonoInst* val, const guchar *ip, MonoClass* klass, MonoGenericContext *generic_context, MonoInst *rgctx)
5011 {
5012         MonoMethod* method = mono_class_get_method_from_name (klass, "Unbox", 1);
5013         MonoMethodSignature *signature = mono_method_signature (method);
5014
5015         if (rgctx) {
5016                 MonoInst *addr = get_runtime_generic_context_method (cfg, caller_method, context_used, bblock, method,
5017                         generic_context, rgctx, MONO_RGCTX_INFO_GENERIC_METHOD_CODE, ip);
5018
5019                 return mono_emit_rgctx_calli_spilled (cfg, bblock, signature, &val, addr, NULL, ip);
5020         } else {
5021                 return mono_emit_method_call_spilled (cfg, bblock, method, signature, &val, ip, NULL);
5022         }
5023 }
5024
5025 static MonoInst*
5026 handle_box_nullable_from_inst (MonoCompile *cfg, MonoMethod *caller_method, int context_used, MonoBasicBlock *bblock,
5027         MonoInst *val, const guchar *ip, MonoClass *klass, MonoGenericContext *generic_context, MonoInst *rgctx)
5028 {
5029         MonoMethod* method = mono_class_get_method_from_name (klass, "Box", 1);
5030         MonoInst *dest, *method_addr;
5031         int temp;
5032
5033         g_assert (mono_class_is_nullable (klass));
5034
5035         method_addr = get_runtime_generic_context_method (cfg, caller_method, context_used, bblock, method,
5036                         generic_context, rgctx, MONO_RGCTX_INFO_GENERIC_METHOD_CODE, ip);
5037         temp = mono_emit_rgctx_calli_spilled (cfg, bblock, mono_method_signature (method), &val,
5038                         method_addr, NULL, ip);
5039         NEW_TEMPLOAD (cfg, dest, temp);
5040         return dest;
5041 }
5042
5043 static int
5044 emit_castclass (MonoClass *klass, guint32 token, int context_used, gboolean inst_is_castclass, MonoCompile *cfg,
5045                 MonoMethod *method, MonoInst **arg_array, MonoType **param_types, GList *dont_inline,
5046                 unsigned char *end, MonoMethodHeader *header, MonoGenericContext *generic_context,
5047                 MonoBasicBlock **_bblock, unsigned char **_ip, MonoInst ***_sp, int *_inline_costs, guint *_real_offset)
5048 {
5049         MonoBasicBlock *bblock = *_bblock;
5050         unsigned char *ip = *_ip;
5051         MonoInst **sp = *_sp;
5052         int inline_costs = *_inline_costs;
5053         guint real_offset = *_real_offset;
5054         int return_value = 0;
5055
5056         if (context_used) {
5057                 MonoInst *rgctx, *args [2];
5058                 int temp;
5059
5060                 g_assert (!method->klass->valuetype);
5061
5062                 /* obj */
5063                 args [0] = *sp;
5064
5065                 /* klass */
5066                 GET_RGCTX (rgctx, context_used);
5067                 args [1] = get_runtime_generic_context_ptr (cfg, method, context_used, bblock, klass,
5068                                 generic_context, rgctx, MONO_RGCTX_INFO_KLASS, ip);
5069
5070                 temp = mono_emit_jit_icall (cfg, bblock, mono_object_castclass, args, ip);
5071                 NEW_TEMPLOAD (cfg, *sp, temp);
5072
5073                 sp++;
5074                 ip += 5;
5075                 inline_costs += 2;
5076         } else if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
5077
5078                 MonoMethod *mono_castclass;
5079                 MonoInst *iargs [1];
5080                 MonoBasicBlock *ebblock;
5081                 int costs;
5082                 int temp;
5083
5084                 mono_castclass = mono_marshal_get_castclass (klass);
5085                 iargs [0] = sp [0];
5086
5087                 costs = inline_method (cfg, mono_castclass, mono_method_signature (mono_castclass), bblock,
5088                                 iargs, ip, real_offset, dont_inline, &ebblock, TRUE);
5089
5090                 g_assert (costs > 0);
5091
5092                 ip += 5;
5093                 real_offset += 5;
5094
5095                 GET_BBLOCK (cfg, bblock, ip);
5096                 ebblock->next_bb = bblock;
5097                 link_bblock (cfg, ebblock, bblock);
5098
5099                 temp = iargs [0]->inst_i0->inst_c0;
5100                 NEW_TEMPLOAD (cfg, *sp, temp);
5101
5102                 sp++;
5103                 bblock = ebblock;
5104                 inline_costs += costs;
5105         } else {
5106                 MonoInst *ins;
5107
5108                 /* Needed by the code generated in inssel.brg */
5109                 mono_get_got_var (cfg);
5110
5111                 MONO_INST_NEW (cfg, ins, CEE_CASTCLASS);
5112                 ins->type = STACK_OBJ;
5113                 ins->inst_left = *sp;
5114                 ins->klass = klass;
5115                 ins->inst_newa_class = klass;
5116                 if (inst_is_castclass)
5117                         ins->backend.record_cast_details = debug_options.better_cast_details;
5118                 if (inst_is_castclass)
5119                         *sp++ = emit_tree (cfg, bblock, ins, ip + 5);
5120                 else
5121                         *sp++ = ins;
5122                 ip += 5;
5123         }
5124
5125 do_return:
5126         *_bblock = bblock;
5127         *_ip = ip;
5128         *_sp = sp;
5129         *_inline_costs = inline_costs;
5130         *_real_offset = real_offset;
5131         return return_value;
5132 exception_exit:
5133         return_value = -2;
5134         goto do_return;
5135 unverified:
5136         return_value = -1;
5137         goto do_return;
5138 }
5139
5140 static int
5141 emit_unbox (MonoClass *klass, guint32 token, int context_used,
5142                 MonoCompile *cfg, MonoMethod *method, MonoInst **arg_array, MonoType **param_types, GList *dont_inline,
5143                 unsigned char *end, MonoMethodHeader *header, MonoGenericContext *generic_context,
5144                 MonoBasicBlock **_bblock, unsigned char **_ip, MonoInst ***_sp, int *_inline_costs, guint *_real_offset)
5145 {
5146         MonoBasicBlock *bblock = *_bblock;
5147         unsigned char *ip = *_ip;
5148         MonoInst **sp = *_sp;
5149         int inline_costs = *_inline_costs;
5150         guint real_offset = *_real_offset;
5151         int return_value = 0;
5152
5153         MonoInst *add, *vtoffset, *ins;
5154
5155         /* Needed by the code generated in inssel.brg */
5156         mono_get_got_var (cfg);
5157
5158         if (context_used) {
5159                 MonoInst *rgctx, *element_class;
5160
5161                 /* This assertion is from the unboxcast insn */
5162                 g_assert (klass->rank == 0);
5163
5164                 GET_RGCTX (rgctx, context_used);
5165                 element_class = get_runtime_generic_context_ptr (cfg, method, context_used, bblock,
5166                                 klass->element_class, generic_context, rgctx, MONO_RGCTX_INFO_KLASS, ip);
5167
5168                 MONO_INST_NEW (cfg, ins, OP_UNBOXCAST_REG);
5169                 ins->type = STACK_OBJ;
5170                 ins->inst_left = *sp;
5171                 ins->inst_right = element_class;
5172                 ins->klass = klass;
5173                 ins->cil_code = ip;
5174         } else {
5175                 MONO_INST_NEW (cfg, ins, OP_UNBOXCAST);
5176                 ins->type = STACK_OBJ;
5177                 ins->inst_left = *sp;
5178                 ins->klass = klass;
5179                 ins->inst_newa_class = klass;
5180                 ins->cil_code = ip;
5181         }
5182
5183         MONO_INST_NEW (cfg, add, OP_PADD);
5184         NEW_ICONST (cfg, vtoffset, sizeof (MonoObject));
5185         add->inst_left = ins;
5186         add->inst_right = vtoffset;
5187         add->type = STACK_MP;
5188         add->klass = klass;
5189         *sp = add;
5190
5191 do_return:
5192         *_bblock = bblock;
5193         *_ip = ip;
5194         *_sp = sp;
5195         *_inline_costs = inline_costs;
5196         *_real_offset = real_offset;
5197         return return_value;
5198 exception_exit:
5199         return_value = -2;
5200         goto do_return;
5201 }
5202
5203 gboolean
5204 mini_assembly_can_skip_verification (MonoDomain *domain, MonoMethod *method)
5205 {
5206         MonoAssembly *assembly = method->klass->image->assembly;
5207         if (method->wrapper_type != MONO_WRAPPER_NONE)
5208                 return FALSE;
5209         if (assembly->in_gac || assembly->image == mono_defaults.corlib)
5210                 return FALSE;
5211         if (mono_security_get_mode () != MONO_SECURITY_MODE_NONE)
5212                 return FALSE;
5213         return mono_assembly_has_skip_verification (assembly);
5214 }
5215
5216 /*
5217  * mini_method_verify:
5218  * 
5219  * Verify the method using the new verfier.
5220  * 
5221  * Returns true if the method is invalid. 
5222  */
5223 gboolean
5224 mini_method_verify (MonoCompile *cfg, MonoMethod *method)
5225 {
5226         GSList *tmp, *res;
5227         gboolean is_fulltrust;
5228         MonoLoaderError *error;
5229
5230         if (method->verification_success)
5231                 return FALSE;
5232
5233         is_fulltrust = mono_verifier_is_method_full_trust (method);
5234
5235         if (!mono_verifier_is_enabled_for_method (method))
5236                 return FALSE;
5237
5238         res = mono_method_verify_with_current_settings (method, cfg->skip_visibility);
5239
5240         if ((error = mono_loader_get_last_error ())) {
5241                 cfg->exception_type = error->exception_type;
5242                 if (res)
5243                         mono_free_verify_list (res);
5244                 return TRUE;
5245         }
5246
5247         if (res) { 
5248                 for (tmp = res; tmp; tmp = tmp->next) {
5249                         MonoVerifyInfoExtended *info = (MonoVerifyInfoExtended *)tmp->data;
5250                         if (info->info.status == MONO_VERIFY_ERROR) {
5251                                 cfg->exception_type = info->exception_type;
5252                                 cfg->exception_message = g_strdup (info->info.message);
5253                                 mono_free_verify_list (res);
5254                                 return TRUE;
5255                         }
5256                         if (info->info.status == MONO_VERIFY_NOT_VERIFIABLE && !is_fulltrust) {
5257                                 cfg->exception_type = info->exception_type;
5258                                 cfg->exception_message = g_strdup (info->info.message);
5259                                 mono_free_verify_list (res);
5260                                 return TRUE;
5261                         }
5262                 }
5263                 mono_free_verify_list (res);
5264         }
5265         method->verification_success = 1;
5266         return FALSE;
5267 }
5268
5269 /*
5270  * mono_method_to_ir: translates IL into basic blocks containing trees
5271  */
5272 static int
5273 mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock, 
5274                    int locals_offset, MonoInst *return_var, GList *dont_inline, MonoInst **inline_args, 
5275                    guint inline_offset, gboolean is_virtual_call)
5276 {
5277         MonoInst *zero_int32, *zero_int64, *zero_ptr, *zero_obj, *zero_r8;
5278         MonoInst *ins, **sp, **stack_start;
5279         MonoBasicBlock *bblock, *tblock = NULL, *init_localsbb = NULL;
5280         MonoMethod *cmethod, *method_definition;
5281         MonoInst **arg_array;
5282         MonoMethodHeader *header;
5283         MonoImage *image;
5284         guint32 token, ins_flag;
5285         MonoClass *klass;
5286         MonoClass *constrained_call = NULL;
5287         unsigned char *ip, *end, *target, *err_pos;
5288         static double r8_0 = 0.0;
5289         MonoMethodSignature *sig;
5290         MonoGenericContext *generic_context = NULL;
5291         MonoGenericContainer *generic_container = NULL;
5292         MonoType **param_types;
5293         GList *bb_recheck = NULL, *tmp;
5294         int i, n, start_new_bblock, ialign;
5295         int num_calls = 0, inline_costs = 0;
5296         int breakpoint_id = 0;
5297         guint32 align;
5298         guint real_offset, num_args;
5299         MonoBoolean security, pinvoke;
5300         MonoSecurityManager* secman = NULL;
5301         MonoDeclSecurityActions actions;
5302         GSList *class_inits = NULL;
5303         gboolean dont_verify, dont_verify_stloc, readonly = FALSE;
5304         int context_used;
5305
5306         /* serialization and xdomain stuff may need access to private fields and methods */
5307         dont_verify = method->klass->image->assembly->corlib_internal? TRUE: FALSE;
5308         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE;
5309         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH;
5310         dont_verify |= method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE; /* bug #77896 */
5311         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP;
5312         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP_INVOKE;
5313
5314         /* turn off visibility checks for smcs */
5315         dont_verify |= mono_security_get_mode () == MONO_SECURITY_MODE_SMCS_HACK;
5316
5317         /* still some type unsafety issues in marshal wrappers... (unknown is PtrToStructure) */
5318         dont_verify_stloc = method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE;
5319         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_UNKNOWN;
5320         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED;
5321
5322         image = method->klass->image;
5323         header = mono_method_get_header (method);
5324         generic_container = mono_method_get_generic_container (method);
5325         sig = mono_method_signature (method);
5326         num_args = sig->hasthis + sig->param_count;
5327         ip = (unsigned char*)header->code;
5328         cfg->cil_start = ip;
5329         end = ip + header->code_size;
5330         mono_jit_stats.cil_code_size += header->code_size;
5331
5332         method_definition = method;
5333         while (method_definition->is_inflated) {
5334                 MonoMethodInflated *imethod = (MonoMethodInflated *) method_definition;
5335                 method_definition = imethod->declaring;
5336         }
5337
5338         /* SkipVerification is not allowed if core-clr is enabled */
5339         if (!dont_verify && mini_assembly_can_skip_verification (cfg->domain, method)) {
5340                 dont_verify = TRUE;
5341                 dont_verify_stloc = TRUE;
5342         }
5343
5344         if (!dont_verify && mini_method_verify (cfg, method_definition))
5345                 goto exception_exit;
5346
5347         if (sig->is_inflated)
5348                 generic_context = mono_method_get_context (method);
5349         else if (generic_container)
5350                 generic_context = &generic_container->context;
5351
5352         if (!cfg->generic_sharing_context)
5353                 g_assert (!sig->has_type_parameters);
5354
5355         if (sig->generic_param_count && method->wrapper_type == MONO_WRAPPER_NONE) {
5356                 g_assert (method->is_inflated);
5357                 g_assert (mono_method_get_context (method)->method_inst);
5358         }
5359         if (method->is_inflated && mono_method_get_context (method)->method_inst)
5360                 g_assert (sig->generic_param_count);
5361
5362         if (cfg->method == method)
5363                 real_offset = 0;
5364         else
5365                 real_offset = inline_offset;
5366
5367         cfg->cil_offset_to_bb = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoBasicBlock*) * header->code_size);
5368         cfg->cil_offset_to_bb_len = header->code_size;
5369
5370         if (cfg->verbose_level > 2)
5371                 g_print ("method to IR %s\n", mono_method_full_name (method, TRUE));
5372
5373         dont_inline = g_list_prepend (dont_inline, method);
5374         if (cfg->method == method) {
5375
5376                 if (cfg->prof_options & MONO_PROFILE_INS_COVERAGE)
5377                         cfg->coverage_info = mono_profiler_coverage_alloc (cfg->method, header->code_size);
5378
5379                 /* ENTRY BLOCK */
5380                 cfg->bb_entry = start_bblock = NEW_BBLOCK (cfg);
5381                 start_bblock->cil_code = NULL;
5382                 start_bblock->cil_length = 0;
5383                 start_bblock->block_num = cfg->num_bblocks++;
5384
5385                 /* EXIT BLOCK */
5386                 cfg->bb_exit = end_bblock = NEW_BBLOCK (cfg);
5387                 end_bblock->cil_code = NULL;
5388                 end_bblock->cil_length = 0;
5389                 end_bblock->block_num = cfg->num_bblocks++;
5390                 g_assert (cfg->num_bblocks == 2);
5391
5392                 arg_array = alloca (sizeof (MonoInst *) * num_args);
5393                 for (i = num_args - 1; i >= 0; i--)
5394                         arg_array [i] = cfg->varinfo [i];
5395
5396                 if (header->num_clauses) {
5397                         cfg->spvars = g_hash_table_new (NULL, NULL);
5398                         cfg->exvars = g_hash_table_new (NULL, NULL);
5399                 }
5400                 /* handle exception clauses */
5401                 for (i = 0; i < header->num_clauses; ++i) {
5402                         MonoBasicBlock *try_bb;
5403                         MonoExceptionClause *clause = &header->clauses [i];
5404
5405                         GET_BBLOCK (cfg, try_bb, ip + clause->try_offset);
5406                         try_bb->real_offset = clause->try_offset;
5407                         GET_BBLOCK (cfg, tblock, ip + clause->handler_offset);
5408                         tblock->real_offset = clause->handler_offset;
5409                         tblock->flags |= BB_EXCEPTION_HANDLER;
5410
5411                         link_bblock (cfg, try_bb, tblock);
5412
5413                         if (*(ip + clause->handler_offset) == CEE_POP)
5414                                 tblock->flags |= BB_EXCEPTION_DEAD_OBJ;
5415
5416                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY ||
5417                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER ||
5418                             clause->flags == MONO_EXCEPTION_CLAUSE_FAULT) {
5419                                 MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
5420                                 MONO_ADD_INS (tblock, ins);
5421
5422                                 /* todo: is a fault block unsafe to optimize? */
5423                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
5424                                         tblock->flags |= BB_EXCEPTION_UNSAFE;
5425                         }
5426
5427
5428                         /*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);
5429                           while (p < end) {
5430                           g_print ("%s", mono_disasm_code_one (NULL, method, p, &p));
5431                           }*/
5432                         /* catch and filter blocks get the exception object on the stack */
5433                         if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE ||
5434                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
5435                                 MonoInst *load, *dummy_use;
5436
5437                                 /* mostly like handle_stack_args (), but just sets the input args */
5438                                 /* g_print ("handling clause at IL_%04x\n", clause->handler_offset); */
5439                                 tblock->in_scount = 1;
5440                                 tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
5441                                 tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
5442
5443                                 /* 
5444                                  * Add a dummy use for the exvar so its liveness info will be
5445                                  * correct.
5446                                  */
5447                                 NEW_TEMPLOAD (cfg, load, tblock->in_stack [0]->inst_c0);
5448                                 NEW_DUMMY_USE (cfg, dummy_use, load);
5449                                 MONO_ADD_INS (tblock, dummy_use);
5450                                 
5451                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
5452                                         GET_BBLOCK (cfg, tblock, ip + clause->data.filter_offset);
5453                                         tblock->real_offset = clause->data.filter_offset;
5454                                         tblock->in_scount = 1;
5455                                         tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
5456                                         /* The filter block shares the exvar with the handler block */
5457                                         tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
5458                                         MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
5459                                         MONO_ADD_INS (tblock, ins);
5460                                 }
5461                         }
5462
5463                         if (clause->flags != MONO_EXCEPTION_CLAUSE_FILTER &&
5464                                         clause->data.catch_class &&
5465                                         cfg->generic_sharing_context &&
5466                                         mono_class_check_context_used (clause->data.catch_class)) {
5467                                 if (mono_method_get_context (method)->method_inst)
5468                                         GENERIC_SHARING_FAILURE (CEE_NOP);
5469
5470                                 /*
5471                                  * In shared generic code with catch
5472                                  * clauses containing type variables
5473                                  * the exception handling code has to
5474                                  * be able to get to the rgctx.
5475                                  * Therefore we have to make sure that
5476                                  * the vtable/mrgctx argument (for
5477                                  * static or generic methods) or the
5478                                  * "this" argument (for non-static
5479                                  * methods) are live.
5480                                  */
5481                                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
5482                                                 mini_method_get_context (method)->method_inst) {
5483                                         mono_get_vtable_var (cfg);
5484                                 } else {
5485                                         MonoInst *this, *dummy_use;
5486                                         MonoType *this_type;
5487
5488                                         if (method->klass->valuetype)
5489                                                 this_type = &method->klass->this_arg;
5490                                         else
5491                                                 this_type = &method->klass->byval_arg;
5492
5493                                         if (arg_array [0]->opcode == OP_ICONST) {
5494                                                 this = arg_array [0];
5495                                         } else {
5496                                                 this = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));
5497                                                 this->ssa_op = MONO_SSA_LOAD;
5498                                                 this->inst_i0 = arg_array [0];
5499                                                 this->opcode = mini_type_to_ldind ((cfg), this->inst_i0->inst_vtype);
5500                                                 type_to_eval_stack_type ((cfg), this_type, this);
5501                                                 this->klass = this->inst_i0->klass;
5502                                         }
5503
5504                                         NEW_DUMMY_USE (cfg, dummy_use, this);
5505                                         MONO_ADD_INS (tblock, dummy_use);
5506                                 }
5507                         }
5508                 }
5509         } else {
5510                 arg_array = alloca (sizeof (MonoInst *) * num_args);
5511                 mono_save_args (cfg, start_bblock, sig, inline_args, arg_array);
5512         }
5513
5514         /* FIRST CODE BLOCK */
5515         bblock = NEW_BBLOCK (cfg);
5516         bblock->cil_code = ip;
5517
5518         ADD_BBLOCK (cfg, bblock);
5519
5520         if (cfg->method == method) {
5521                 breakpoint_id = mono_debugger_method_has_breakpoint (method);
5522                 if (breakpoint_id && (mono_debug_format != MONO_DEBUG_FORMAT_DEBUGGER)) {
5523                         MONO_INST_NEW (cfg, ins, OP_BREAK);
5524                         MONO_ADD_INS (bblock, ins);
5525                 }
5526         }
5527
5528         if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS)
5529                 secman = mono_security_manager_get_methods ();
5530
5531         security = (secman && mono_method_has_declsec (method));
5532         /* at this point having security doesn't mean we have any code to generate */
5533         if (security && (cfg->method == method)) {
5534                 /* Only Demand, NonCasDemand and DemandChoice requires code generation.
5535                  * And we do not want to enter the next section (with allocation) if we
5536                  * have nothing to generate */
5537                 security = mono_declsec_get_demands (method, &actions);
5538         }
5539
5540         /* we must Demand SecurityPermission.Unmanaged before P/Invoking */
5541         pinvoke = (secman && (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE));
5542         if (pinvoke) {
5543                 MonoMethod *wrapped = mono_marshal_method_from_wrapper (method);
5544                 if (wrapped && (wrapped->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
5545                         MonoCustomAttrInfo* custom = mono_custom_attrs_from_method (wrapped);
5546
5547                         /* unless the method or it's class has the [SuppressUnmanagedCodeSecurity] attribute */
5548                         if (custom && mono_custom_attrs_has_attr (custom, secman->suppressunmanagedcodesecurity)) {
5549                                 pinvoke = FALSE;
5550                         }
5551                         if (custom)
5552                                 mono_custom_attrs_free (custom);
5553
5554                         if (pinvoke) {
5555                                 custom = mono_custom_attrs_from_class (wrapped->klass);
5556                                 if (custom && mono_custom_attrs_has_attr (custom, secman->suppressunmanagedcodesecurity)) {
5557                                         pinvoke = FALSE;
5558                                 }
5559                                 if (custom)
5560                                         mono_custom_attrs_free (custom);
5561                         }
5562                 } else {
5563                         /* not a P/Invoke after all */
5564                         pinvoke = FALSE;
5565                 }
5566         }
5567         
5568         if ((header->init_locals || (cfg->method == method && (cfg->opt & MONO_OPT_SHARED))) || cfg->compile_aot || security || pinvoke) {
5569                 /* we use a separate basic block for the initialization code */
5570                 cfg->bb_init = init_localsbb = NEW_BBLOCK (cfg);
5571                 init_localsbb->real_offset = real_offset;
5572                 start_bblock->next_bb = init_localsbb;
5573                 init_localsbb->next_bb = bblock;
5574                 link_bblock (cfg, start_bblock, init_localsbb);
5575                 link_bblock (cfg, init_localsbb, bblock);
5576                 init_localsbb->block_num = cfg->num_bblocks++;
5577         } else {
5578                 start_bblock->next_bb = bblock;
5579                 link_bblock (cfg, start_bblock, bblock);
5580         }
5581
5582         /* at this point we know, if security is TRUE, that some code needs to be generated */
5583         if (security && (cfg->method == method)) {
5584                 MonoInst *args [2];
5585
5586                 mono_jit_stats.cas_demand_generation++;
5587
5588                 if (actions.demand.blob) {
5589                         /* Add code for SecurityAction.Demand */
5590                         NEW_DECLSECCONST (cfg, args[0], image, actions.demand);
5591                         NEW_ICONST (cfg, args [1], actions.demand.size);
5592                         /* Calls static void SecurityManager.InternalDemand (byte* permissions, int size); */
5593                         mono_emit_method_call_spilled (cfg, init_localsbb, secman->demand, mono_method_signature (secman->demand), args, ip, NULL);
5594                 }
5595                 if (actions.noncasdemand.blob) {
5596                         /* CLR 1.x uses a .noncasdemand (but 2.x doesn't) */
5597                         /* For Mono we re-route non-CAS Demand to Demand (as the managed code must deal with it anyway) */
5598                         NEW_DECLSECCONST (cfg, args[0], image, actions.noncasdemand);
5599                         NEW_ICONST (cfg, args [1], actions.noncasdemand.size);
5600                         /* Calls static void SecurityManager.InternalDemand (byte* permissions, int size); */
5601                         mono_emit_method_call_spilled (cfg, init_localsbb, secman->demand, mono_method_signature (secman->demand), args, ip, NULL);
5602                 }
5603                 if (actions.demandchoice.blob) {
5604                         /* New in 2.0, Demand must succeed for one of the permissions (i.e. not all) */
5605                         NEW_DECLSECCONST (cfg, args[0], image, actions.demandchoice);
5606                         NEW_ICONST (cfg, args [1], actions.demandchoice.size);
5607                         /* Calls static void SecurityManager.InternalDemandChoice (byte* permissions, int size); */
5608                         mono_emit_method_call_spilled (cfg, init_localsbb, secman->demandchoice, mono_method_signature (secman->demandchoice), args, ip, NULL);
5609                 }
5610         }
5611
5612         /* we must Demand SecurityPermission.Unmanaged before p/invoking */
5613         if (pinvoke) {
5614                 mono_emit_method_call_spilled (cfg, init_localsbb, secman->demandunmanaged, mono_method_signature (secman->demandunmanaged), NULL, ip, NULL);
5615         }
5616
5617         if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR) {
5618                 if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
5619                         MonoMethod *wrapped = mono_marshal_method_from_wrapper (method);
5620                         if (wrapped && (wrapped->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
5621                                 if (!(method->klass && method->klass->image &&
5622                                                 mono_security_core_clr_is_platform_image (method->klass->image))) {
5623                                         emit_throw_method_access_exception (cfg, method, wrapped, bblock, ip);
5624                                 }
5625                         }
5626                 }
5627                 if (!method_is_safe (method))
5628                         emit_throw_verification_exception (cfg, bblock, ip);
5629         }
5630
5631         if (header->code_size == 0)
5632                 UNVERIFIED;
5633
5634         if (get_basic_blocks (cfg, header, real_offset, ip, end, &err_pos)) {
5635                 ip = err_pos;
5636                 UNVERIFIED;
5637         }
5638
5639         if (cfg->method == method)
5640                 mono_debug_init_method (cfg, bblock, breakpoint_id);
5641
5642         param_types = mono_mempool_alloc (cfg->mempool, sizeof (MonoType*) * num_args);
5643         if (sig->hasthis)
5644                 param_types [0] = method->klass->valuetype?&method->klass->this_arg:&method->klass->byval_arg;
5645         for (n = 0; n < sig->param_count; ++n)
5646                 param_types [n + sig->hasthis] = sig->params [n];
5647         for (n = 0; n < header->num_locals; ++n) {
5648                 if (header->locals [n]->type == MONO_TYPE_VOID && !header->locals [n]->byref)
5649                         UNVERIFIED;
5650         }
5651         class_inits = NULL;
5652
5653         /* do this somewhere outside - not here */
5654         NEW_ICONST (cfg, zero_int32, 0);
5655         NEW_ICONST (cfg, zero_int64, 0);
5656         zero_int64->type = STACK_I8;
5657         NEW_PCONST (cfg, zero_ptr, 0);
5658         NEW_PCONST (cfg, zero_obj, 0);
5659         zero_obj->type = STACK_OBJ;
5660
5661         MONO_INST_NEW (cfg, zero_r8, OP_R8CONST);
5662         zero_r8->type = STACK_R8;
5663         zero_r8->inst_p0 = &r8_0;
5664
5665         /* add a check for this != NULL to inlined methods */
5666         if (is_virtual_call) {
5667                 MONO_INST_NEW (cfg, ins, OP_CHECK_THIS);
5668                 NEW_ARGLOAD (cfg, ins->inst_left, 0);
5669                 ins->cil_code = ip;
5670                 MONO_ADD_INS (bblock, ins);
5671         }
5672
5673         /* we use a spare stack slot in SWITCH and NEWOBJ and others */
5674         stack_start = sp = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * (header->max_stack + 1));
5675
5676         ins_flag = 0;
5677         start_new_bblock = 0;
5678         while (ip < end) {
5679
5680                 if (cfg->method == method)
5681                         real_offset = ip - header->code;
5682                 else
5683                         real_offset = inline_offset;
5684                 cfg->ip = ip;
5685
5686                 context_used = 0;
5687
5688                 if (start_new_bblock) {
5689                         bblock->cil_length = ip - bblock->cil_code;
5690                         if (start_new_bblock == 2) {
5691                                 g_assert (ip == tblock->cil_code);
5692                         } else {
5693                                 GET_BBLOCK (cfg, tblock, ip);
5694                         }
5695                         bblock->next_bb = tblock;
5696                         bblock = tblock;
5697                         start_new_bblock = 0;
5698                         for (i = 0; i < bblock->in_scount; ++i) {
5699                                 if (cfg->verbose_level > 3)
5700                                         g_print ("loading %d from temp %d\n", i, (int)bblock->in_stack [i]->inst_c0);                                           
5701                                 NEW_TEMPLOAD (cfg, ins, bblock->in_stack [i]->inst_c0);
5702                                 *sp++ = ins;
5703                         }
5704                         g_slist_free (class_inits);
5705                         class_inits = NULL;
5706                 } else {
5707                         if ((tblock = cfg->cil_offset_to_bb [ip - cfg->cil_start]) && (tblock != bblock)) {
5708                                 link_bblock (cfg, bblock, tblock);
5709                                 if (sp != stack_start) {
5710                                         handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
5711                                         sp = stack_start;
5712                                         CHECK_UNVERIFIABLE (cfg);
5713                                 }
5714                                 bblock->next_bb = tblock;
5715                                 bblock = tblock;
5716                                 for (i = 0; i < bblock->in_scount; ++i) {
5717                                         if (cfg->verbose_level > 3)
5718                                                 g_print ("loading %d from temp %d\n", i, (int)bblock->in_stack [i]->inst_c0);                                           
5719                                         NEW_TEMPLOAD (cfg, ins, bblock->in_stack [i]->inst_c0);
5720                                         *sp++ = ins;
5721                                 }
5722                                 g_slist_free (class_inits);
5723                                 class_inits = NULL;
5724                         }
5725                 }
5726
5727                 bblock->real_offset = real_offset;
5728
5729                 if ((cfg->method == method) && cfg->coverage_info) {
5730                         MonoInst *store, *one;
5731                         guint32 cil_offset = ip - header->code;
5732                         cfg->coverage_info->data [cil_offset].cil_code = ip;
5733
5734                         /* TODO: Use an increment here */
5735                         NEW_ICONST (cfg, one, 1);
5736                         one->cil_code = ip;
5737
5738                         NEW_PCONST (cfg, ins, &(cfg->coverage_info->data [cil_offset].count));
5739                         ins->cil_code = ip;
5740
5741                         MONO_INST_NEW (cfg, store, CEE_STIND_I);
5742                         store->inst_left = ins;
5743                         store->inst_right = one;
5744
5745                         MONO_ADD_INS (bblock, store);
5746                 }
5747
5748                 if (cfg->verbose_level > 3)
5749                         g_print ("converting (in B%d: stack: %d) %s", bblock->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
5750
5751                 switch (*ip) {
5752                 case CEE_NOP:
5753                         MONO_INST_NEW (cfg, ins, OP_NOP);
5754                         ip++;
5755                         MONO_ADD_INS (bblock, ins);
5756                         break;
5757                 case CEE_BREAK:
5758                         MONO_INST_NEW (cfg, ins, OP_BREAK);
5759                         ip++;
5760                         MONO_ADD_INS (bblock, ins);
5761                         break;
5762                 case CEE_LDARG_0:
5763                 case CEE_LDARG_1:
5764                 case CEE_LDARG_2:
5765                 case CEE_LDARG_3:
5766                         CHECK_STACK_OVF (1);
5767                         n = (*ip)-CEE_LDARG_0;
5768                         CHECK_ARG (n);
5769                         NEW_ARGLOAD (cfg, ins, n);
5770                         LDARG_SOFT_FLOAT (cfg, ins, n, ip);
5771                         ip++;
5772                         *sp++ = ins;
5773                         break;
5774                 case CEE_LDLOC_0:
5775                 case CEE_LDLOC_1:
5776                 case CEE_LDLOC_2:
5777                 case CEE_LDLOC_3:
5778                         CHECK_STACK_OVF (1);
5779                         n = (*ip)-CEE_LDLOC_0;
5780                         CHECK_LOCAL (n);
5781                         NEW_LOCLOAD (cfg, ins, n);
5782                         LDLOC_SOFT_FLOAT (cfg, ins, n, ip);
5783                         ip++;
5784                         *sp++ = ins;
5785                         break;
5786                 case CEE_STLOC_0:
5787                 case CEE_STLOC_1:
5788                 case CEE_STLOC_2:
5789                 case CEE_STLOC_3:
5790                         CHECK_STACK (1);
5791                         n = (*ip)-CEE_STLOC_0;
5792                         CHECK_LOCAL (n);
5793                         --sp;
5794                         handle_loaded_temps (cfg, bblock, stack_start, sp);
5795                         NEW_LOCSTORE (cfg, ins, n, *sp);
5796                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
5797                                 UNVERIFIED;
5798                         STLOC_SOFT_FLOAT (cfg, ins, n, ip);
5799                         if (ins->opcode == CEE_STOBJ) {
5800                                 NEW_LOCLOADA (cfg, ins, n);
5801                                 handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE, FALSE);
5802                         } else
5803                                 MONO_ADD_INS (bblock, ins);
5804                         ++ip;
5805                         inline_costs += 1;
5806                         break;
5807                 case CEE_LDARG_S:
5808                         CHECK_OPSIZE (2);
5809                         CHECK_STACK_OVF (1);
5810                         CHECK_ARG (ip [1]);
5811                         NEW_ARGLOAD (cfg, ins, ip [1]);
5812                         LDARG_SOFT_FLOAT (cfg, ins, ip [1], ip);
5813                         *sp++ = ins;
5814                         ip += 2;
5815                         break;
5816                 case CEE_LDARGA_S:
5817                         CHECK_OPSIZE (2);
5818                         CHECK_STACK_OVF (1);
5819                         CHECK_ARG (ip [1]);
5820                         NEW_ARGLOADA (cfg, ins, ip [1]);
5821                         *sp++ = ins;
5822                         ip += 2;
5823                         break;
5824                 case CEE_STARG_S:
5825                         CHECK_OPSIZE (2);
5826                         CHECK_STACK (1);
5827                         --sp;
5828                         CHECK_ARG (ip [1]);
5829                         NEW_ARGSTORE (cfg, ins, ip [1], *sp);
5830                         handle_loaded_temps (cfg, bblock, stack_start, sp);
5831                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [ip [1]], *sp))
5832                                 UNVERIFIED;
5833                         STARG_SOFT_FLOAT (cfg, ins, ip [1], ip);
5834                         if (ins->opcode == CEE_STOBJ) {
5835                                 NEW_ARGLOADA (cfg, ins, ip [1]);
5836                                 handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE, FALSE);
5837                         } else
5838                                 MONO_ADD_INS (bblock, ins);
5839                         ip += 2;
5840                         break;
5841                 case CEE_LDLOC_S:
5842                         CHECK_OPSIZE (2);
5843                         CHECK_STACK_OVF (1);
5844                         CHECK_LOCAL (ip [1]);
5845                         NEW_LOCLOAD (cfg, ins, ip [1]);
5846                         LDLOC_SOFT_FLOAT (cfg, ins, ip [1], ip);
5847                         *sp++ = ins;
5848                         ip += 2;
5849                         break;
5850                 case CEE_LDLOCA_S:
5851                         CHECK_OPSIZE (2);
5852                         CHECK_STACK_OVF (1);
5853                         CHECK_LOCAL (ip [1]);
5854                         NEW_LOCLOADA (cfg, ins, ip [1]);
5855                         *sp++ = ins;
5856                         ip += 2;
5857                         break;
5858                 case CEE_STLOC_S:
5859                         CHECK_OPSIZE (2);
5860                         CHECK_STACK (1);
5861                         --sp;
5862                         handle_loaded_temps (cfg, bblock, stack_start, sp);
5863                         CHECK_LOCAL (ip [1]);
5864                         NEW_LOCSTORE (cfg, ins, ip [1], *sp);
5865                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [ip [1]], *sp))
5866                                 UNVERIFIED;
5867                         STLOC_SOFT_FLOAT (cfg, ins, ip [1], ip);
5868                         if (ins->opcode == CEE_STOBJ) {
5869                                 NEW_LOCLOADA (cfg, ins, ip [1]);
5870                                 handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE, FALSE);
5871                         } else
5872                                 MONO_ADD_INS (bblock, ins);
5873                         ip += 2;
5874                         inline_costs += 1;
5875                         break;
5876                 case CEE_LDNULL:
5877                         CHECK_STACK_OVF (1);
5878                         NEW_PCONST (cfg, ins, NULL);
5879                         ins->type = STACK_OBJ;
5880                         ++ip;
5881                         *sp++ = ins;
5882                         break;
5883                 case CEE_LDC_I4_M1:
5884                         CHECK_STACK_OVF (1);
5885                         NEW_ICONST (cfg, ins, -1);
5886                         ++ip;
5887                         *sp++ = ins;
5888                         break;
5889                 case CEE_LDC_I4_0:
5890                 case CEE_LDC_I4_1:
5891                 case CEE_LDC_I4_2:
5892                 case CEE_LDC_I4_3:
5893                 case CEE_LDC_I4_4:
5894                 case CEE_LDC_I4_5:
5895                 case CEE_LDC_I4_6:
5896                 case CEE_LDC_I4_7:
5897                 case CEE_LDC_I4_8:
5898                         CHECK_STACK_OVF (1);
5899                         NEW_ICONST (cfg, ins, (*ip) - CEE_LDC_I4_0);
5900                         ++ip;
5901                         *sp++ = ins;
5902                         break;
5903                 case CEE_LDC_I4_S:
5904                         CHECK_OPSIZE (2);
5905                         CHECK_STACK_OVF (1);
5906                         ++ip;
5907                         NEW_ICONST (cfg, ins, *((signed char*)ip));
5908                         ++ip;
5909                         *sp++ = ins;
5910                         break;
5911                 case CEE_LDC_I4:
5912                         CHECK_OPSIZE (5);
5913                         CHECK_STACK_OVF (1);
5914                         NEW_ICONST (cfg, ins, (gint32)read32 (ip + 1));
5915                         ip += 5;
5916                         *sp++ = ins;
5917                         break;
5918                 case CEE_LDC_I8:
5919                         CHECK_OPSIZE (9);
5920                         CHECK_STACK_OVF (1);
5921                         MONO_INST_NEW (cfg, ins, OP_I8CONST);
5922                         ins->type = STACK_I8;
5923                         ++ip;
5924                         ins->inst_l = (gint64)read64 (ip);
5925                         ip += 8;
5926                         *sp++ = ins;
5927                         break;
5928                 case CEE_LDC_R4: {
5929                         float *f;
5930                         /* we should really allocate this only late in the compilation process */
5931                         mono_domain_lock (cfg->domain);
5932                         f = mono_mempool_alloc (cfg->domain->mp, sizeof (float));
5933                         mono_domain_unlock (cfg->domain);
5934                         CHECK_OPSIZE (5);
5935                         CHECK_STACK_OVF (1);
5936                         MONO_INST_NEW (cfg, ins, OP_R4CONST);
5937                         ins->type = STACK_R8;
5938                         ++ip;
5939                         readr4 (ip, f);
5940                         ins->inst_p0 = f;
5941
5942                         ip += 4;
5943                         *sp++ = ins;                    
5944                         break;
5945                 }
5946                 case CEE_LDC_R8: {
5947                         double *d;
5948                         mono_domain_lock (cfg->domain);
5949                         d = mono_mempool_alloc (cfg->domain->mp, sizeof (double));
5950                         mono_domain_unlock (cfg->domain);
5951                         CHECK_OPSIZE (9);
5952                         CHECK_STACK_OVF (1);
5953                         MONO_INST_NEW (cfg, ins, OP_R8CONST);
5954                         ins->type = STACK_R8;
5955                         ++ip;
5956                         readr8 (ip, d);
5957                         ins->inst_p0 = d;
5958
5959                         ip += 8;
5960                         *sp++ = ins;                    
5961                         break;
5962                 }
5963                 case CEE_DUP: {
5964                         MonoInst *temp, *store;
5965                         CHECK_STACK (1);
5966                         CHECK_STACK_OVF (1);
5967                         sp--;
5968                         ins = *sp;
5969                 
5970                         /* 
5971                          * small optimization: if the loaded value was from a local already,
5972                          * just load it twice.
5973                          */
5974                         if (ins->ssa_op == MONO_SSA_LOAD && 
5975                             (ins->inst_i0->opcode == OP_LOCAL || ins->inst_i0->opcode == OP_ARG)) {
5976                                 sp++;
5977                                 MONO_INST_NEW (cfg, temp, 0);
5978                                 *temp = *ins;
5979                                 *sp++ = temp;
5980                         } else {
5981                                 temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
5982                                 temp->flags |= MONO_INST_IS_TEMP;
5983                                 NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
5984                                 /* FIXME: handle CEE_STIND_R4 */
5985                                 if (store->opcode == CEE_STOBJ) {
5986                                         NEW_TEMPLOADA (cfg, store, temp->inst_c0);
5987                                         handle_stobj (cfg, bblock, store, sp [0], sp [0]->cil_code, store->klass, TRUE, FALSE, FALSE);
5988                                 } else {
5989                                         MONO_ADD_INS (bblock, store);
5990                                 }
5991                                 NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
5992                                 *sp++ = ins;
5993                                 NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
5994                                 *sp++ = ins;
5995                         }
5996                         ++ip;
5997                         inline_costs += 2;
5998                         break;
5999                 }
6000                 case CEE_POP:
6001                         CHECK_STACK (1);
6002                         MONO_INST_NEW (cfg, ins, CEE_POP);
6003                         MONO_ADD_INS (bblock, ins);
6004                         ip++;
6005                         --sp;
6006                         ins->inst_i0 = *sp;
6007                         break;
6008                 case CEE_JMP:
6009                         CHECK_OPSIZE (5);
6010                         if (stack_start != sp)
6011                                 UNVERIFIED;
6012                         MONO_INST_NEW (cfg, ins, OP_JMP);
6013                         token = read32 (ip + 1);
6014                         /* FIXME: check the signature matches */
6015                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
6016
6017                         if (!cmethod)
6018                                 goto load_error;
6019
6020                         if (cfg->generic_sharing_context && mono_method_check_context_used (cmethod))
6021                                 GENERIC_SHARING_FAILURE (CEE_JMP);
6022
6023                         if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS) {
6024                                 if (check_linkdemand (cfg, method, cmethod, bblock, ip))
6025                                         INLINE_FAILURE;
6026                                 CHECK_CFG_EXCEPTION;
6027                         }
6028
6029                         ins->inst_p0 = cmethod;
6030                         MONO_ADD_INS (bblock, ins);
6031                         ip += 5;
6032                         start_new_bblock = 1;
6033                         break;
6034                 case CEE_CALLI:
6035                 case CEE_CALL:
6036                 case CEE_CALLVIRT: {
6037                         MonoInst *addr = NULL;
6038                         MonoMethodSignature *fsig = NULL;
6039                         int temp, array_rank = 0;
6040                         int virtual = *ip == CEE_CALLVIRT;
6041                         gboolean no_spill;
6042                         gboolean pass_imt_from_rgctx = FALSE;
6043                         MonoInst *imt_arg = NULL;
6044                         gboolean pass_vtable = FALSE;
6045                         gboolean pass_mrgctx = FALSE;
6046                         MonoInst *vtable_arg = NULL;
6047                         gboolean check_this = FALSE;
6048
6049                         CHECK_OPSIZE (5);
6050                         token = read32 (ip + 1);
6051
6052                         if (*ip == CEE_CALLI) {
6053                                 cmethod = NULL;
6054                                 CHECK_STACK (1);
6055                                 --sp;
6056                                 addr = *sp;
6057                                 if (method->wrapper_type != MONO_WRAPPER_NONE)
6058                                         fsig = (MonoMethodSignature *)mono_method_get_wrapper_data (method, token);
6059                                 else
6060                                         fsig = mono_metadata_parse_signature (image, token);
6061
6062                                 n = fsig->param_count + fsig->hasthis;
6063                         } else {
6064                                 MonoMethod *cil_method;
6065                                 
6066                                 if (method->wrapper_type != MONO_WRAPPER_NONE) {
6067                                         cmethod =  (MonoMethod *)mono_method_get_wrapper_data (method, token);
6068                                         cil_method = cmethod;
6069                                 } else if (constrained_call) {
6070                                         cmethod = mono_get_method_constrained (image, token, constrained_call, generic_context, &cil_method);
6071                                         cil_method = cmethod;
6072                                 } else {
6073                                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
6074                                         cil_method = cmethod;
6075                                 }
6076
6077                                 if (!cmethod)
6078                                         goto load_error;
6079                                 if (!dont_verify && !cfg->skip_visibility) {
6080                                         MonoMethod *target_method = cil_method;
6081                                         if (method->is_inflated) {
6082                                                 target_method = mini_get_method_allow_open (method, token, NULL, &(mono_method_get_generic_container (method_definition)->context));
6083                                         }
6084                                         if (!mono_method_can_access_method (method_definition, target_method) &&
6085                                                 !mono_method_can_access_method (method, cil_method))
6086                                                 METHOD_ACCESS_FAILURE;
6087                                 }
6088
6089                                 if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR)
6090                                         ensure_method_is_allowed_to_call_method (cfg, method, cil_method, bblock, ip);
6091
6092                                 if (!virtual && (cmethod->flags & METHOD_ATTRIBUTE_ABSTRACT))
6093                                         /* MS.NET seems to silently convert this to a callvirt */
6094                                         virtual = 1;
6095
6096                                 if (!cmethod->klass->inited){
6097                                         if (!mono_class_init (cmethod->klass))
6098                                                 goto load_error;
6099                                 }
6100
6101                                 if (mono_method_signature (cmethod)->pinvoke) {
6102                                         MonoMethod *wrapper = mono_marshal_get_native_wrapper (cmethod, check_for_pending_exc, FALSE);
6103                                         fsig = mono_method_signature (wrapper);
6104                                 } else if (constrained_call) {
6105                                         fsig = mono_method_signature (cmethod);
6106                                 } else {
6107                                         fsig = mono_method_get_signature_full (cmethod, image, token, generic_context);
6108                                 }
6109
6110                                 mono_save_token_info (cfg, image, token, cmethod);
6111
6112                                 n = fsig->param_count + fsig->hasthis;
6113
6114                                 if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS) {
6115                                         if (check_linkdemand (cfg, method, cmethod, bblock, ip))
6116                                                 INLINE_FAILURE;
6117                                         CHECK_CFG_EXCEPTION;
6118                                 }
6119
6120                                 if (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL &&
6121                                     mini_class_is_system_array (cmethod->klass)) {
6122                                         array_rank = cmethod->klass->rank;
6123                                 }
6124
6125                                 if (cmethod->string_ctor)
6126                                         g_assert_not_reached ();
6127
6128                         }
6129
6130                         if (!cfg->generic_sharing_context && cmethod && cmethod->klass->generic_container)
6131                                 UNVERIFIED;
6132
6133                         if (!cfg->generic_sharing_context && cmethod)
6134                                 g_assert (!mono_method_check_context_used (cmethod));
6135
6136                         CHECK_STACK (n);
6137
6138                         //g_assert (!virtual || fsig->hasthis);
6139
6140                         sp -= n;
6141
6142                         if (constrained_call) {
6143                                 /*
6144                                  * We have the `constrained.' prefix opcode.
6145                                  */
6146                                 if (constrained_call->valuetype && !cmethod->klass->valuetype) {
6147                                         MonoInst *load;
6148                                         /*
6149                                          * The type parameter is instantiated as a valuetype,
6150                                          * but that type doesn't override the method we're
6151                                          * calling, so we need to box `this'.
6152                                          * sp [0] is a pointer to the data: we need the value
6153                                          * in handle_box (), so load it here.
6154                                          */
6155                                         MONO_INST_NEW (cfg, load, mini_type_to_ldind (cfg, &constrained_call->byval_arg));
6156                                         type_to_eval_stack_type (cfg, &constrained_call->byval_arg, load);
6157                                         load->inst_left = sp [0];
6158                                         sp [0] = handle_box (cfg, bblock, load, ip, constrained_call);
6159                                 } else if (!constrained_call->valuetype) {
6160                                         MonoInst *ins;
6161
6162                                         /*
6163                                          * The type parameter is instantiated as a reference
6164                                          * type.  We have a managed pointer on the stack, so
6165                                          * we need to dereference it here.
6166                                          */
6167
6168                                         MONO_INST_NEW (cfg, ins, CEE_LDIND_REF);
6169                                         ins->inst_i0 = sp [0];
6170                                         ins->type = STACK_OBJ;
6171                                         ins->klass = mono_class_from_mono_type (&constrained_call->byval_arg);
6172                                         sp [0] = ins;
6173                                 } else if (cmethod->klass->valuetype)
6174                                         virtual = 0;
6175                                 constrained_call = NULL;
6176                         }
6177
6178                         if (*ip != CEE_CALLI && check_call_signature (cfg, fsig, sp))
6179                                 UNVERIFIED;
6180
6181                         if (cmethod && (cmethod->flags & METHOD_ATTRIBUTE_STATIC) &&
6182                                         (cmethod->klass->generic_class || cmethod->klass->generic_container)) {
6183                                 gboolean sharing_enabled = mono_class_generic_sharing_enabled (cmethod->klass);
6184                                 MonoGenericContext *context = mini_class_get_context (cmethod->klass);
6185                                 gboolean context_sharable = mono_generic_context_is_sharable (context, TRUE);
6186
6187                                 /*
6188                                  * Pass vtable iff target method might
6189                                  * be shared, which means that sharing
6190                                  * is enabled for its class and its
6191                                  * context is sharable (and it's not a
6192                                  * generic method).
6193                                  */
6194                                 if (sharing_enabled && context_sharable &&
6195                                         !(mini_method_get_context (cmethod) && mini_method_get_context (cmethod)->method_inst))
6196                                         pass_vtable = TRUE;
6197                         }
6198
6199                         if (cmethod && mini_method_get_context (cmethod) &&
6200                                         mini_method_get_context (cmethod)->method_inst) {
6201                                 gboolean sharing_enabled = mono_class_generic_sharing_enabled (cmethod->klass);
6202                                 MonoGenericContext *context = mini_method_get_context (cmethod);
6203                                 gboolean context_sharable = mono_generic_context_is_sharable (context, TRUE);
6204
6205                                 g_assert (!pass_vtable);
6206
6207                                 if (sharing_enabled && context_sharable)
6208                                         pass_mrgctx = TRUE;
6209                         }
6210
6211                         if (cfg->generic_sharing_context && cmethod) {
6212                                 MonoGenericContext *cmethod_context = mono_method_get_context (cmethod);
6213
6214                                 context_used = mono_method_check_context_used (cmethod);
6215
6216                                 if (context_used && (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
6217                                         /* Generic method interface
6218                                            calls are resolved via a
6219                                            helper function and don't
6220                                            need an imt. */
6221                                         if (!cmethod_context || !cmethod_context->method_inst)
6222                                                 pass_imt_from_rgctx = TRUE;
6223                                 }
6224
6225                                 /*
6226                                  * If a shared method calls another
6227                                  * shared method then the caller must
6228                                  * have a generic sharing context
6229                                  * because the magic trampoline
6230                                  * requires it.  FIXME: We shouldn't
6231                                  * have to force the vtable/mrgctx
6232                                  * variable here.  Instead there
6233                                  * should be a flag in the cfg to
6234                                  * request a generic sharing context.
6235                                  */
6236                                 if (context_used && method->flags & METHOD_ATTRIBUTE_STATIC)
6237                                         mono_get_vtable_var (cfg);
6238                         }
6239
6240                         if (pass_vtable) {
6241                                 if (context_used) {
6242                                         MonoInst *rgctx;
6243
6244                                         GET_RGCTX (rgctx, context_used);
6245                                         vtable_arg = get_runtime_generic_context_ptr (cfg, method, context_used,
6246                                                 bblock, cmethod->klass, generic_context, rgctx, MONO_RGCTX_INFO_VTABLE, ip);
6247                                 } else {
6248                                         MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
6249                                         
6250                                         CHECK_TYPELOAD (cmethod->klass);
6251                                         NEW_VTABLECONST (cfg, vtable_arg, vtable);
6252                                 }
6253                         }
6254
6255                         if (pass_mrgctx) {
6256                                 g_assert (!vtable_arg);
6257
6258                                 if (context_used) {
6259                                         MonoInst *rgctx;
6260
6261                                         GET_RGCTX (rgctx, context_used);
6262                                         vtable_arg = get_runtime_generic_context_method_rgctx (cfg, method,
6263                                                 context_used, bblock, cmethod, generic_context, rgctx, ip);
6264                                 } else {
6265                                         MonoMethodRuntimeGenericContext *mrgctx;
6266
6267                                         mrgctx = mono_method_lookup_rgctx (mono_class_vtable (cfg->domain, cmethod->klass),
6268                                                 mini_method_get_context (cmethod)->method_inst);
6269
6270                                         cfg->disable_aot = TRUE;
6271                                         NEW_PCONST (cfg, vtable_arg, mrgctx);
6272                                 }
6273
6274                                 if (!(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
6275                                                 (cmethod->flags & METHOD_ATTRIBUTE_FINAL)) {
6276                                         if (virtual)
6277                                                 check_this = TRUE;
6278                                         virtual = 0;
6279                                 }
6280                         }
6281
6282                         if (pass_imt_from_rgctx) {
6283                                 MonoInst *rgctx;
6284
6285                                 g_assert (!pass_vtable);
6286                                 g_assert (cmethod);
6287
6288                                 GET_RGCTX (rgctx, context_used);
6289                                 imt_arg = get_runtime_generic_context_method (cfg, method, context_used, bblock, cmethod,
6290                                                 generic_context, rgctx, MONO_RGCTX_INFO_METHOD, ip);
6291                         }
6292
6293                         if (check_this) {
6294                                 MonoInst *check;
6295
6296                                 MONO_INST_NEW (cfg, check, OP_CHECK_THIS_PASSTHROUGH);
6297                                 check->cil_code = ip;
6298                                 check->inst_left = sp [0];
6299                                 check->type = sp [0]->type;
6300                                 sp [0] = check;
6301                         }
6302
6303                         if (cmethod && virtual && 
6304                             (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) && 
6305                             !((cmethod->flags & METHOD_ATTRIBUTE_FINAL) && 
6306                               cmethod->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK) &&
6307                             mono_method_signature (cmethod)->generic_param_count) {
6308                                 MonoInst *this_temp, *this_arg_temp, *store;
6309                                 MonoInst *iargs [4];
6310
6311                                 g_assert (mono_method_signature (cmethod)->is_inflated);
6312                                 /* Prevent inlining of methods that contain indirect calls */
6313                                 INLINE_FAILURE;
6314
6315                                 this_temp = mono_compile_create_var (cfg, type_from_stack_type (sp [0]), OP_LOCAL);
6316                                 NEW_TEMPSTORE (cfg, store, this_temp->inst_c0, sp [0]);
6317                                 MONO_ADD_INS (bblock, store);
6318
6319                                 /* FIXME: This should be a managed pointer */
6320                                 this_arg_temp = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
6321
6322                                 /* Because of the PCONST below */
6323                                 cfg->disable_aot = TRUE;
6324                                 NEW_TEMPLOAD (cfg, iargs [0], this_temp->inst_c0);
6325                                 if (context_used) {
6326                                         MonoInst *rgctx;
6327
6328                                         GET_RGCTX (rgctx, context_used);
6329                                         iargs [1] = get_runtime_generic_context_method (cfg, method, context_used,
6330                                                         bblock, cmethod,
6331                                                         generic_context, rgctx, MONO_RGCTX_INFO_METHOD, ip);
6332                                         NEW_TEMPLOADA (cfg, iargs [2], this_arg_temp->inst_c0);
6333                                         temp = mono_emit_jit_icall (cfg, bblock,
6334                                                 mono_helper_compile_generic_method, iargs, ip);
6335                                 } else {
6336                                         NEW_METHODCONST (cfg, iargs [1], cmethod);
6337                                         NEW_TEMPLOADA (cfg, iargs [2], this_arg_temp->inst_c0);
6338                                         temp = mono_emit_jit_icall (cfg, bblock, mono_helper_compile_generic_method,
6339                                                 iargs, ip);
6340                                 }
6341
6342                                 NEW_TEMPLOAD (cfg, addr, temp);
6343                                 NEW_TEMPLOAD (cfg, sp [0], this_arg_temp->inst_c0);
6344
6345                                 if ((temp = mono_emit_calli_spilled (cfg, bblock, fsig, sp, addr, ip)) != -1) {
6346                                         NEW_TEMPLOAD (cfg, *sp, temp);
6347                                         sp++;
6348                                 }
6349
6350                                 ip += 5;
6351                                 ins_flag = 0;
6352                                 break;
6353                         }
6354
6355                         /* FIXME: runtime generic context pointer for jumps? */
6356                         /* FIXME: handle this for generic sharing eventually */
6357                         if ((ins_flag & MONO_INST_TAILCALL) && !cfg->generic_sharing_context && !vtable_arg && cmethod && (*ip == CEE_CALL) &&
6358                                  (mono_metadata_signature_equal (mono_method_signature (method), mono_method_signature (cmethod)))) {
6359                                 int i;
6360
6361                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
6362                                 INLINE_FAILURE;
6363                                 /* FIXME: This assumes the two methods has the same number and type of arguments */
6364                                 /*
6365                                  * We implement tail calls by storing the actual arguments into the 
6366                                  * argument variables, then emitting a OP_JMP. Since the actual arguments
6367                                  * can refer to the arg variables, we have to spill them.
6368                                  */
6369                                 handle_loaded_temps (cfg, bblock, sp, sp + n);
6370                                 for (i = 0; i < n; ++i) {
6371                                         /* Prevent argument from being register allocated */
6372                                         arg_array [i]->flags |= MONO_INST_VOLATILE;
6373
6374                                         /* Check if argument is the same */
6375                                         /* 
6376                                          * FIXME: This loses liveness info, so it can only be done if the
6377                                          * argument is not register allocated.
6378                                          */
6379                                         NEW_ARGLOAD (cfg, ins, i);
6380                                         if ((ins->opcode == sp [i]->opcode) && (ins->inst_i0 == sp [i]->inst_i0))
6381                                                 continue;
6382
6383                                         NEW_ARGSTORE (cfg, ins, i, sp [i]);
6384                                         /* FIXME: handle CEE_STIND_R4 */
6385                                         if (ins->opcode == CEE_STOBJ) {
6386                                                 NEW_ARGLOADA (cfg, ins, i);
6387                                                 handle_stobj (cfg, bblock, ins, sp [i], sp [i]->cil_code, ins->klass, FALSE, FALSE, FALSE);
6388                                         }
6389                                         else
6390                                                 MONO_ADD_INS (bblock, ins);
6391                                 }
6392                                 MONO_INST_NEW (cfg, ins, OP_JMP);
6393                                 ins->inst_p0 = cmethod;
6394                                 ins->inst_p1 = arg_array [0];
6395                                 MONO_ADD_INS (bblock, ins);
6396                                 link_bblock (cfg, bblock, end_bblock);                  
6397                                 start_new_bblock = 1;
6398                                 /* skip CEE_RET as well */
6399                                 ip += 6;
6400                                 ins_flag = 0;
6401                                 break;
6402                         }
6403                         if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_get_inst_for_method (cfg, cmethod, fsig, sp))) {
6404                                 if (MONO_TYPE_IS_VOID (fsig->ret)) {
6405                                         MONO_ADD_INS (bblock, ins);
6406                                 } else {
6407                                         type_to_eval_stack_type (cfg, fsig->ret, ins);
6408                                         *sp = ins;
6409                                         sp++;
6410                                 }
6411
6412                                 ip += 5;
6413                                 ins_flag = 0;
6414                                 break;
6415                         }
6416
6417                         handle_loaded_temps (cfg, bblock, stack_start, sp);
6418
6419                         if ((cfg->opt & MONO_OPT_INLINE) && cmethod && //!check_this &&
6420                             (!virtual || !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) || (cmethod->flags & METHOD_ATTRIBUTE_FINAL)) && 
6421                             mono_method_check_inlining (cfg, cmethod) &&
6422                                  !g_list_find (dont_inline, cmethod)) {
6423                                 int costs;
6424                                 MonoBasicBlock *ebblock;
6425                                 gboolean allways = FALSE;
6426
6427                                 if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
6428                                         (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
6429                                         /* Prevent inlining of methods that call wrappers */
6430                                         INLINE_FAILURE;
6431                                         cmethod = mono_marshal_get_native_wrapper (cmethod, check_for_pending_exc, FALSE);
6432                                         allways = TRUE;
6433                                 }
6434
6435                                 if ((costs = inline_method (cfg, cmethod, fsig, bblock, sp, ip, real_offset, dont_inline, &ebblock, allways))) {
6436                                         ip += 5;
6437                                         real_offset += 5;
6438
6439                                         GET_BBLOCK (cfg, bblock, ip);
6440                                         ebblock->next_bb = bblock;
6441                                         link_bblock (cfg, ebblock, bblock);
6442
6443                                         if (!MONO_TYPE_IS_VOID (fsig->ret))
6444                                                 sp++;
6445
6446                                         /* indicates start of a new block, and triggers a load of all 
6447                                            stack arguments at bb boundarie */
6448                                         bblock = ebblock;
6449
6450                                         inline_costs += costs;
6451                                         ins_flag = 0;
6452                                         break;
6453                                 }
6454                         }
6455                         
6456                         inline_costs += 10 * num_calls++;
6457
6458                         /* tail recursion elimination */
6459                         if ((cfg->opt & MONO_OPT_TAILC) && *ip == CEE_CALL && cmethod == method && ip [5] == CEE_RET &&
6460                                         !vtable_arg) {
6461                                 gboolean has_vtargs = FALSE;
6462                                 int i;
6463                                 
6464                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
6465                                 INLINE_FAILURE;
6466                                 /* keep it simple */
6467                                 for (i =  fsig->param_count - 1; i >= 0; i--) {
6468                                         if (MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->params [i])) 
6469                                                 has_vtargs = TRUE;
6470                                 }
6471
6472                                 if (!has_vtargs) {
6473                                         for (i = 0; i < n; ++i) {
6474                                                 /* FIXME: handle CEE_STIND_R4 */
6475                                                 NEW_ARGSTORE (cfg, ins, i, sp [i]);
6476                                                 MONO_ADD_INS (bblock, ins);
6477                                         }
6478                                         MONO_INST_NEW (cfg, ins, OP_BR);
6479                                         MONO_ADD_INS (bblock, ins);
6480                                         tblock = start_bblock->out_bb [0];
6481                                         link_bblock (cfg, bblock, tblock);
6482                                         ins->inst_target_bb = tblock;
6483                                         start_new_bblock = 1;
6484
6485                                         /* skip the CEE_RET, too */
6486                                         if (ip_in_bb (cfg, bblock, ip + 5))
6487                                                 ip += 6;
6488                                         else
6489                                                 ip += 5;
6490                                         ins_flag = 0;
6491                                         break;
6492                                 }
6493                         }
6494
6495                         if (ip_in_bb (cfg, bblock, ip + 5) 
6496                                 && (!MONO_TYPE_ISSTRUCT (fsig->ret))
6497                                 && (!MONO_TYPE_IS_VOID (fsig->ret) || (cmethod && cmethod->string_ctor))
6498                                 && (CODE_IS_STLOC (ip + 5) || ip [5] == CEE_POP || ip [5] == CEE_RET))
6499                                 /* No need to spill */
6500                                 no_spill = TRUE;
6501                         else
6502                                 no_spill = FALSE;
6503
6504                         /* FIXME: only do this for generic methods if
6505                            they are not shared! */
6506                         if (context_used &&
6507                                         (cmethod->klass->valuetype ||
6508                                         (cmethod->is_inflated && mono_method_get_context (cmethod)->method_inst && !pass_mrgctx) ||
6509                                         ((cmethod->flags & METHOD_ATTRIBUTE_STATIC) &&
6510                                                 mono_class_generic_sharing_enabled (cmethod->klass)) ||
6511                                         (!imt_arg && !mono_method_is_generic_sharable_impl (cmethod, TRUE) &&
6512                                                 (!virtual || cmethod->flags & METHOD_ATTRIBUTE_FINAL ||
6513                                                 !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))))) {
6514                                 MonoInst *rgctx;
6515
6516                                 INLINE_FAILURE;
6517
6518                                 g_assert (cfg->generic_sharing_context && cmethod);
6519                                 g_assert (!addr);
6520
6521                                 /*
6522                                  * We are compiling a call to
6523                                  * non-shared generic code from shared
6524                                  * code, which means that we have to
6525                                  * look up the method in the rgctx and
6526                                  * do an indirect call.
6527                                  */
6528                                 GET_RGCTX (rgctx, context_used);
6529                                 addr = get_runtime_generic_context_method (cfg, method, context_used, bblock, cmethod,
6530                                                 generic_context, rgctx, MONO_RGCTX_INFO_GENERIC_METHOD_CODE, ip);
6531
6532                         }
6533
6534                         if (addr) {
6535                                 g_assert (!imt_arg);
6536
6537                                 if (*ip == CEE_CALL) {
6538                                         g_assert (context_used);
6539                                 } else if (*ip == CEE_CALLI) {
6540                                         g_assert (!vtable_arg);
6541                                 } else {
6542                                         g_assert (cmethod->flags & METHOD_ATTRIBUTE_FINAL ||
6543                                                         !(cmethod->flags & METHOD_ATTRIBUTE_FINAL));
6544                                 }
6545
6546                                 /* Prevent inlining of methods with indirect calls */
6547                                 INLINE_FAILURE;
6548                                 if (no_spill) {
6549                                         ins = (MonoInst*)mono_emit_rgctx_calli (cfg, bblock, fsig, sp, addr, vtable_arg, ip);
6550                                         *sp++ = ins;                                    
6551                                 } else {
6552                                         temp = mono_emit_rgctx_calli_spilled (cfg, bblock, fsig, sp, addr, vtable_arg, ip);
6553                                         if (temp != -1) {
6554                                                 NEW_TEMPLOAD (cfg, *sp, temp);
6555                                                 NEW_TEMPLOAD_SOFT_FLOAT (cfg, bblock, *sp, temp, ip);
6556                                                 sp++;
6557                                         }
6558                                 }                       
6559                         } else if (array_rank) {
6560                                 MonoInst *addr;
6561
6562                                 if (strcmp (cmethod->name, "Set") == 0) { /* array Set */ 
6563                                         if (sp [fsig->param_count]->type == STACK_OBJ) {
6564                                                 MonoInst *iargs [2];
6565                                                 MonoInst *array, *to_store, *store;
6566
6567                                                 handle_loaded_temps (cfg, bblock, stack_start, sp);
6568                                                 
6569                                                 array = mono_compile_create_var (cfg, type_from_stack_type (sp [0]), OP_LOCAL);
6570                                                 NEW_TEMPSTORE (cfg, store, array->inst_c0, sp [0]);
6571                                                 MONO_ADD_INS (bblock, store);
6572                                                 NEW_TEMPLOAD (cfg, iargs [0], array->inst_c0);
6573
6574                                                 to_store = mono_compile_create_var (cfg, type_from_stack_type (sp [fsig->param_count]), OP_LOCAL);
6575                                                 NEW_TEMPSTORE (cfg, store, to_store->inst_c0, sp [fsig->param_count]);
6576                                                 /* FIXME: handle CEE_STIND_R4 */
6577                                                 MONO_ADD_INS (bblock, store);
6578                                                 NEW_TEMPLOAD (cfg, iargs [1], to_store->inst_c0);
6579
6580                                                 /*
6581                                                  * We first save the args for the call so that the args are copied to the stack
6582                                                  * and a new instruction tree for them is created. If we don't do this,
6583                                                  * the same MonoInst is added to two different trees and this is not 
6584                                                  * allowed by burg.
6585                                                  */
6586                                                 mono_emit_jit_icall (cfg, bblock, mono_helper_stelem_ref_check, iargs, ip);
6587
6588                                                 NEW_TEMPLOAD (cfg, sp [0], array->inst_c0);
6589                                                 NEW_TEMPLOAD (cfg, sp [fsig->param_count], to_store->inst_c0);
6590                                         }
6591
6592                                         addr = mini_get_ldelema_ins (cfg, bblock, cmethod, sp, ip, TRUE);
6593                                         NEW_INDSTORE (cfg, ins, addr, sp [fsig->param_count], fsig->params [fsig->param_count - 1]);
6594                                         /* FIXME: handle CEE_STIND_R4 */
6595                                         if (ins->opcode == CEE_STOBJ) {
6596                                                 handle_stobj (cfg, bblock, addr, sp [fsig->param_count], ip, mono_class_from_mono_type (fsig->params [fsig->param_count-1]), FALSE, FALSE, TRUE);
6597                                         } else {
6598                                                 MONO_ADD_INS (bblock, ins);
6599                                         }
6600
6601                                 } else if (strcmp (cmethod->name, "Get") == 0) { /* array Get */
6602                                         addr = mini_get_ldelema_ins (cfg, bblock, cmethod, sp, ip, FALSE);
6603                                         NEW_INDLOAD (cfg, ins, addr, fsig->ret);
6604
6605                                         *sp++ = ins;
6606                                 } else if (strcmp (cmethod->name, "Address") == 0) { /* array Address */
6607                                         if (!cmethod->klass->element_class->valuetype && !readonly) {
6608                                                 MonoInst* check;
6609                                                 //* Needed by the code generated in inssel.brg * /
6610                                                 mono_get_got_var (cfg);
6611
6612                                                 MONO_INST_NEW (cfg, check, OP_CHECK_ARRAY_TYPE);
6613                                                 check->klass = cmethod->klass;
6614                                                 check->inst_left = sp [0];
6615                                                 check->type = STACK_OBJ;
6616                                                 sp [0] = check;
6617                                         }
6618
6619                                         readonly = FALSE;
6620                                         addr = mini_get_ldelema_ins (cfg, bblock, cmethod, sp, ip, FALSE);
6621                                         *sp++ = addr;
6622                                 } else {
6623                                         g_assert_not_reached ();
6624                                 }
6625
6626                         } else {
6627                                 /* Prevent inlining of methods which call other methods */
6628                                 INLINE_FAILURE;
6629                                 if (mini_redirect_call (&temp, cfg, bblock, cmethod, fsig, sp, ip, virtual ? sp [0] : NULL)) {
6630                                         if (temp != -1) {
6631                                                 NEW_TEMPLOAD (cfg, *sp, temp);
6632                                                 sp++;
6633                                         }
6634                                 } else if (no_spill) {
6635                                         ins = (MonoInst*)mono_emit_rgctx_method_call (cfg, bblock, cmethod, fsig, sp,
6636                                                         vtable_arg, imt_arg, ip, virtual ? sp [0] : NULL);
6637                                         *sp++ = ins;
6638                                 } else {
6639                                         if ((temp = mono_emit_rgctx_method_call_spilled (cfg, bblock, cmethod, fsig, sp,
6640                                                         vtable_arg, imt_arg, ip, virtual ? sp [0] : NULL)) != -1) {
6641                                                 MonoInst *load;
6642                                                 NEW_TEMPLOAD (cfg, load, temp);
6643
6644 #ifdef MONO_ARCH_SOFT_FLOAT
6645                                                 if (load->opcode == CEE_LDIND_R4) {
6646                                                         NEW_TEMPLOADA (cfg, load, temp);
6647                                                         temp = handle_load_float (cfg, bblock, load, ip);
6648                                                         NEW_TEMPLOAD (cfg, load, temp);
6649                                                 }
6650 #endif
6651                                                 *sp++ = load;
6652                                         }
6653                                 }
6654                         }
6655
6656                         ip += 5;
6657                         ins_flag = 0;
6658                         break;
6659                 }
6660                 case CEE_RET:
6661                         if (cfg->method != method) {
6662                                 /* return from inlined method */
6663                                 if (return_var) {
6664                                         MonoInst *store;
6665                                         CHECK_STACK (1);
6666                                         --sp;
6667                                         //g_assert (returnvar != -1);
6668                                         NEW_TEMPSTORE (cfg, store, return_var->inst_c0, *sp);
6669                                         store->cil_code = sp [0]->cil_code;
6670                                         if (store->opcode == CEE_STOBJ) {
6671                                                 g_assert_not_reached ();
6672                                                 NEW_TEMPLOADA (cfg, store, return_var->inst_c0);
6673                                                 /* FIXME: it is possible some optimization will pass the a heap pointer for the struct address, so we'll need the write barrier */
6674                                                 handle_stobj (cfg, bblock, store, *sp, sp [0]->cil_code, return_var->klass, FALSE, FALSE, FALSE);
6675 #ifdef MONO_ARCH_SOFT_FLOAT
6676                                         } else if (store->opcode == CEE_STIND_R4) {
6677                                                 NEW_TEMPLOADA (cfg, store, return_var->inst_c0);
6678                                                 handle_store_float (cfg, bblock, store, *sp, sp [0]->cil_code);
6679 #endif
6680                                         } else
6681                                                 MONO_ADD_INS (bblock, store);
6682                                 } 
6683                         } else {
6684                                 if (cfg->ret) {
6685                                         g_assert (!return_var);
6686                                         CHECK_STACK (1);
6687                                         --sp;
6688                                         MONO_INST_NEW (cfg, ins, OP_NOP);
6689                                         ins->opcode = mini_type_to_stind (cfg, mono_method_signature (method)->ret);
6690                                         if (ins->opcode == CEE_STOBJ) {
6691                                                 NEW_RETLOADA (cfg, ins);
6692                                                 /* FIXME: it is possible some optimization will pass the a heap pointer for the struct address, so we'll need the write barrier */
6693                                                 handle_stobj (cfg, bblock, ins, *sp, ip, cfg->ret->klass, FALSE, FALSE, FALSE);
6694                                         } else {
6695                                                 ins->opcode = OP_SETRET;
6696                                                 ins->inst_i0 = *sp;;
6697                                                 ins->inst_i1 = NULL;
6698                                                 MONO_ADD_INS (bblock, ins);
6699                                         }
6700                                 }
6701                         }
6702                         if (sp != stack_start)
6703                                 UNVERIFIED;
6704                         MONO_INST_NEW (cfg, ins, OP_BR);
6705                         ip++;
6706                         ins->inst_target_bb = end_bblock;
6707                         MONO_ADD_INS (bblock, ins);
6708                         link_bblock (cfg, bblock, end_bblock);
6709                         start_new_bblock = 1;
6710                         break;
6711                 case CEE_BR_S:
6712                         CHECK_OPSIZE (2);
6713                         MONO_INST_NEW (cfg, ins, OP_BR);
6714                         ip++;
6715                         MONO_ADD_INS (bblock, ins);
6716                         target = ip + 1 + (signed char)(*ip);
6717                         ++ip;
6718                         GET_BBLOCK (cfg, tblock, target);
6719                         link_bblock (cfg, bblock, tblock);
6720                         CHECK_BBLOCK (target, ip, tblock);
6721                         ins->inst_target_bb = tblock;
6722                         if (sp != stack_start) {
6723                                 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
6724                                 sp = stack_start;
6725                                 CHECK_UNVERIFIABLE (cfg);
6726                         }
6727                         start_new_bblock = 1;
6728                         inline_costs += BRANCH_COST;
6729                         break;
6730                 case CEE_BRFALSE_S:
6731                 case CEE_BRTRUE_S:
6732                         CHECK_OPSIZE (2);
6733                         CHECK_STACK (1);
6734                         if (sp [-1]->type == STACK_VTYPE || sp [-1]->type == STACK_R8)
6735                                 UNVERIFIED;
6736                         MONO_INST_NEW (cfg, ins, *ip + BIG_BRANCH_OFFSET);
6737                         ip++;
6738                         target = ip + 1 + *(signed char*)ip;
6739                         ip++;
6740                         ADD_UNCOND (ins->opcode == CEE_BRTRUE);
6741                         if (sp != stack_start) {
6742                                 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
6743                                 sp = stack_start;
6744                                 CHECK_UNVERIFIABLE (cfg);
6745                         }
6746                         inline_costs += BRANCH_COST;
6747                         break;
6748                 case CEE_BEQ_S:
6749                 case CEE_BGE_S:
6750                 case CEE_BGT_S:
6751                 case CEE_BLE_S:
6752                 case CEE_BLT_S:
6753                 case CEE_BNE_UN_S:
6754                 case CEE_BGE_UN_S:
6755                 case CEE_BGT_UN_S:
6756                 case CEE_BLE_UN_S:
6757                 case CEE_BLT_UN_S:
6758                         CHECK_OPSIZE (2);
6759                         CHECK_STACK (2);
6760                         MONO_INST_NEW (cfg, ins, *ip + BIG_BRANCH_OFFSET);
6761                         ip++;
6762                         target = ip + 1 + *(signed char*)ip;
6763                         ip++;
6764 #ifdef MONO_ARCH_SOFT_FLOAT
6765                         if (sp [-1]->type == STACK_R8 || sp [-2]->type == STACK_R8) {
6766                                 ins->opcode = condbr_to_fp_br (ins->opcode);
6767                                 sp -= 2;
6768                                 ins->inst_left = sp [0];
6769                                 ins->inst_right = sp [1];
6770                                 ins->type = STACK_I4;
6771                                 *sp++ = emit_tree (cfg, bblock, ins, ins->cil_code);
6772                                 MONO_INST_NEW (cfg, ins, CEE_BRTRUE);
6773                                 ADD_UNCOND (TRUE);
6774                         } else {
6775                                 ADD_BINCOND (NULL);
6776                         }
6777 #else
6778                         ADD_BINCOND (NULL);
6779 #endif
6780                         if (sp != stack_start) {
6781                                 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
6782                                 sp = stack_start;
6783                                 CHECK_UNVERIFIABLE (cfg);
6784                         }
6785                         inline_costs += BRANCH_COST;
6786                         break;
6787                 case CEE_BR:
6788                         CHECK_OPSIZE (5);
6789                         MONO_INST_NEW (cfg, ins, OP_BR);
6790                         ip++;
6791                         MONO_ADD_INS (bblock, ins);
6792                         target = ip + 4 + (gint32)read32(ip);
6793                         ip += 4;
6794                         GET_BBLOCK (cfg, tblock, target);
6795                         link_bblock (cfg, bblock, tblock);
6796                         CHECK_BBLOCK (target, ip, tblock);
6797                         ins->inst_target_bb = tblock;
6798                         if (sp != stack_start) {
6799                                 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
6800                                 sp = stack_start;
6801                                 CHECK_UNVERIFIABLE (cfg);
6802                         }
6803                         start_new_bblock = 1;
6804                         inline_costs += BRANCH_COST;
6805                         break;
6806                 case CEE_BRFALSE:
6807                 case CEE_BRTRUE:
6808                         CHECK_OPSIZE (5);
6809                         CHECK_STACK (1);
6810                         if (sp [-1]->type == STACK_VTYPE || sp [-1]->type == STACK_R8)
6811                                 UNVERIFIED;
6812                         MONO_INST_NEW (cfg, ins, *ip);
6813                         ip++;
6814                         target = ip + 4 + (gint32)read32(ip);
6815                         ip += 4;
6816                         ADD_UNCOND(ins->opcode == CEE_BRTRUE);
6817                         if (sp != stack_start) {
6818                                 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
6819                                 sp = stack_start;
6820                                 CHECK_UNVERIFIABLE (cfg);
6821                         }
6822                         inline_costs += BRANCH_COST;
6823                         break;
6824                 case CEE_BEQ:
6825                 case CEE_BGE:
6826                 case CEE_BGT:
6827                 case CEE_BLE:
6828                 case CEE_BLT:
6829                 case CEE_BNE_UN:
6830                 case CEE_BGE_UN:
6831                 case CEE_BGT_UN:
6832                 case CEE_BLE_UN:
6833                 case CEE_BLT_UN:
6834                         CHECK_OPSIZE (5);
6835                         CHECK_STACK (2);
6836                         MONO_INST_NEW (cfg, ins, *ip);
6837                         ip++;
6838                         target = ip + 4 + (gint32)read32(ip);
6839                         ip += 4;
6840 #ifdef MONO_ARCH_SOFT_FLOAT
6841                         if (sp [-1]->type == STACK_R8 || sp [-2]->type == STACK_R8) {
6842                                 ins->opcode = condbr_to_fp_br (ins->opcode);
6843                                 sp -= 2;
6844                                 ins->inst_left = sp [0];
6845                                 ins->inst_right = sp [1];
6846                                 ins->type = STACK_I4;
6847                                 *sp++ = emit_tree (cfg, bblock, ins, ins->cil_code);
6848                                 MONO_INST_NEW (cfg, ins, CEE_BRTRUE);
6849                                 ADD_UNCOND (TRUE);
6850                         } else {
6851                                 ADD_BINCOND (NULL);
6852                         }
6853 #else
6854                         ADD_BINCOND (NULL);
6855 #endif
6856                         if (sp != stack_start) {
6857                                 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
6858                                 sp = stack_start;
6859                                 CHECK_UNVERIFIABLE (cfg);
6860                         }
6861                         inline_costs += BRANCH_COST;
6862                         break;
6863                 case CEE_SWITCH:
6864                         CHECK_OPSIZE (5);
6865                         CHECK_STACK (1);
6866                         n = read32 (ip + 1);
6867                         MONO_INST_NEW (cfg, ins, OP_SWITCH);
6868                         --sp;
6869                         ins->inst_left = *sp;
6870                         if ((ins->inst_left->type != STACK_I4) && (ins->inst_left->type != STACK_PTR)) 
6871                                 UNVERIFIED;
6872                         ip += 5;
6873                         CHECK_OPSIZE (n * sizeof (guint32));
6874                         target = ip + n * sizeof (guint32);
6875                         MONO_ADD_INS (bblock, ins);
6876                         GET_BBLOCK (cfg, tblock, target);
6877                         link_bblock (cfg, bblock, tblock);
6878                         ins->klass = GUINT_TO_POINTER (n);
6879                         ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * (n + 1));
6880                         ins->inst_many_bb [n] = tblock;
6881
6882                         for (i = 0; i < n; ++i) {
6883                                 GET_BBLOCK (cfg, tblock, target + (gint32)read32(ip));
6884                                 link_bblock (cfg, bblock, tblock);
6885                                 ins->inst_many_bb [i] = tblock;
6886                                 ip += 4;
6887                         }
6888                         if (sp != stack_start) {
6889                                 handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
6890                                 sp = stack_start;
6891                                 CHECK_UNVERIFIABLE (cfg);
6892                         }
6893                         /* Needed by the code generated in inssel.brg */
6894                         mono_get_got_var (cfg);
6895                         inline_costs += (BRANCH_COST * 2);
6896                         break;
6897                 case CEE_LDIND_I1:
6898                 case CEE_LDIND_U1:
6899                 case CEE_LDIND_I2:
6900                 case CEE_LDIND_U2:
6901                 case CEE_LDIND_I4:
6902                 case CEE_LDIND_U4:
6903                 case CEE_LDIND_I8:
6904                 case CEE_LDIND_I:
6905                 case CEE_LDIND_R4:
6906                 case CEE_LDIND_R8:
6907                 case CEE_LDIND_REF:
6908                         CHECK_STACK (1);
6909                         MONO_INST_NEW (cfg, ins, *ip);
6910                         --sp;
6911                         ins->inst_i0 = *sp;
6912                         *sp++ = ins;
6913                         ins->type = ldind_type [*ip - CEE_LDIND_I1];
6914                         ins->flags |= ins_flag;
6915                         ins_flag = 0;
6916                         if (ins->type == STACK_OBJ)
6917                                 ins->klass = mono_defaults.object_class;
6918 #ifdef MONO_ARCH_SOFT_FLOAT
6919                         if (*ip == CEE_LDIND_R4) {
6920                                 int temp;
6921                                 --sp;
6922                                 temp = handle_load_float (cfg, bblock, ins->inst_i0, ip);
6923                                 NEW_TEMPLOAD (cfg, *sp, temp);
6924                                 sp++;
6925                         }
6926 #endif
6927                         ++ip;
6928                         break;
6929                 case CEE_STIND_REF:
6930                 case CEE_STIND_I1:
6931                 case CEE_STIND_I2:
6932                 case CEE_STIND_I4:
6933                 case CEE_STIND_I8:
6934                 case CEE_STIND_R4:
6935                 case CEE_STIND_R8:
6936                         CHECK_STACK (2);
6937 #ifdef MONO_ARCH_SOFT_FLOAT
6938                         if (*ip == CEE_STIND_R4) {
6939                                 sp -= 2;
6940                                 handle_store_float (cfg, bblock, sp [0], sp [1], ip);
6941                                 ip++;
6942                                 break;
6943                         }
6944 #endif
6945 #if HAVE_WRITE_BARRIERS
6946                         if (*ip == CEE_STIND_REF && method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER && !((sp [-1]->opcode == OP_PCONST) && (sp [-1]->inst_p0 == 0))) {
6947                                 /* insert call to write barrier */
6948                                 MonoMethod *write_barrier = mono_marshal_get_write_barrier ();
6949                                 sp -= 2;
6950                                 mono_emit_method_call_spilled (cfg, bblock, write_barrier, mono_method_signature (write_barrier), sp, ip, NULL);
6951                                 ip++;
6952                                 break;
6953                         }
6954 #endif
6955                         MONO_INST_NEW (cfg, ins, *ip);
6956                         ip++;
6957                         sp -= 2;
6958                         handle_loaded_temps (cfg, bblock, stack_start, sp);
6959                         MONO_ADD_INS (bblock, ins);
6960                         ins->inst_i0 = sp [0];
6961                         ins->inst_i1 = sp [1];
6962                         ins->flags |= ins_flag;
6963                         ins_flag = 0;
6964                         inline_costs += 1;
6965                         break;
6966                 case CEE_MUL:
6967                         CHECK_STACK (2);
6968                         ADD_BINOP (*ip);
6969
6970 #ifdef MONO_ARCH_NO_EMULATE_MUL_IMM
6971                         /* FIXME: This breaks with ssapre (mono -O=ssapre loader.exe) */
6972                         if ((ins->inst_right->opcode == OP_ICONST) && !(cfg->opt & MONO_OPT_SSAPRE)) {
6973                                 switch (ins->opcode) {
6974                                 case CEE_MUL:
6975                                         ins->opcode = OP_IMUL_IMM;
6976                                         ins->inst_imm = ins->inst_right->inst_c0;
6977                                         break;
6978                                 case OP_LMUL:
6979                                         ins->opcode = OP_LMUL_IMM;
6980                                         ins->inst_imm = ins->inst_right->inst_c0;
6981                                         break;
6982                                 default:
6983                                         g_assert_not_reached ();
6984                                 }
6985                         }
6986 #endif
6987
6988                         if (mono_find_jit_opcode_emulation (ins->opcode)) {
6989                                 --sp;
6990                                 *sp++ = emit_tree (cfg, bblock, ins, ip + 1);
6991                         }
6992                         ip++;
6993                         break;
6994                 case CEE_ADD:
6995                 case CEE_SUB:
6996                 case CEE_DIV:
6997                 case CEE_DIV_UN:
6998                 case CEE_REM:
6999                 case CEE_REM_UN:
7000                 case CEE_AND:
7001                 case CEE_OR:
7002                 case CEE_XOR:
7003                 case CEE_SHL:
7004                 case CEE_SHR:
7005                 case CEE_SHR_UN:
7006                         CHECK_STACK (2);
7007                         ADD_BINOP (*ip);
7008                         /* special case that gives a nice speedup and happens to workaorund a ppc jit but (for the release)
7009                          * later apply the speedup to the left shift as well
7010                          * See BUG# 57957.
7011                          */
7012                         if ((ins->opcode == OP_LSHR_UN) && (ins->type == STACK_I8) 
7013                                         && (ins->inst_right->opcode == OP_ICONST) && (ins->inst_right->inst_c0 == 32)) {
7014                                 ins->opcode = OP_LSHR_UN_32;
7015                                 /*g_print ("applied long shr speedup to %s\n", cfg->method->name);*/
7016                                 ip++;
7017                                 break;
7018                         }
7019                         if (mono_find_jit_opcode_emulation (ins->opcode)) {
7020                                 --sp;
7021                                 *sp++ = emit_tree (cfg, bblock, ins, ip + 1);
7022                         }
7023                         ip++;
7024                         break;
7025                 case CEE_NEG:
7026                 case CEE_NOT:
7027                 case CEE_CONV_I1:
7028                 case CEE_CONV_I2:
7029                 case CEE_CONV_I4:
7030                 case CEE_CONV_R4:
7031                 case CEE_CONV_R8:
7032                 case CEE_CONV_U4:
7033                 case CEE_CONV_I8:
7034                 case CEE_CONV_U8:
7035                 case CEE_CONV_OVF_I8:
7036                 case CEE_CONV_OVF_U8:
7037                 case CEE_CONV_R_UN:
7038                         CHECK_STACK (1);
7039                         ADD_UNOP (*ip);
7040
7041 #ifdef MONO_ARCH_SOFT_FLOAT
7042                         /*
7043                          * Its rather hard to emit the soft float code during the decompose
7044                          * pass, so avoid it in some specific cases.
7045                          */
7046                         if (ins->opcode == OP_LCONV_TO_R4) {
7047                                 MonoInst *conv;
7048
7049                                 ins->opcode = OP_LCONV_TO_R8;
7050                                 ins->type = STACK_R8;
7051
7052                                 --sp;
7053                                 *sp++ = emit_tree (cfg, bblock, ins, ip + 1);
7054
7055                                 MONO_INST_NEW (cfg, conv, CEE_CONV_R4);
7056                                 conv->inst_left = sp [-1];
7057                                 conv->type = STACK_R8;
7058                                 sp [-1] = ins;
7059
7060                                 ip++;
7061                                 break;
7062                         }
7063 #endif
7064
7065                         if (mono_find_jit_opcode_emulation (ins->opcode)) {
7066                                 --sp;
7067                                 *sp++ = emit_tree (cfg, bblock, ins, ip + 1);
7068                         }
7069                         ip++;                   
7070                         break;
7071                 case CEE_CONV_OVF_I4:
7072                 case CEE_CONV_OVF_I1:
7073                 case CEE_CONV_OVF_I2:
7074                 case CEE_CONV_OVF_I:
7075                 case CEE_CONV_OVF_U:
7076                         CHECK_STACK (1);
7077
7078                         if (sp [-1]->type == STACK_R8) {
7079                                 ADD_UNOP (CEE_CONV_OVF_I8);
7080                                 ADD_UNOP (*ip);
7081                         } else {
7082                                 ADD_UNOP (*ip);
7083                         }
7084
7085                         ip++;
7086                         break;
7087                 case CEE_CONV_OVF_U1:
7088                 case CEE_CONV_OVF_U2:
7089                 case CEE_CONV_OVF_U4:
7090                         CHECK_STACK (1);
7091
7092                         if (sp [-1]->type == STACK_R8) {
7093                                 ADD_UNOP (CEE_CONV_OVF_U8);
7094                                 ADD_UNOP (*ip);
7095                         } else {
7096                                 ADD_UNOP (*ip);
7097                         }
7098
7099                         ip++;
7100                         break;
7101                 case CEE_CONV_OVF_I1_UN:
7102                 case CEE_CONV_OVF_I2_UN:
7103                 case CEE_CONV_OVF_I4_UN:
7104                 case CEE_CONV_OVF_I8_UN:
7105                 case CEE_CONV_OVF_U1_UN:
7106                 case CEE_CONV_OVF_U2_UN:
7107                 case CEE_CONV_OVF_U4_UN:
7108                 case CEE_CONV_OVF_U8_UN:
7109                 case CEE_CONV_OVF_I_UN:
7110                 case CEE_CONV_OVF_U_UN:
7111                         CHECK_STACK (1);
7112                         ADD_UNOP (*ip);
7113                         ip++;
7114                         break;
7115                 case CEE_CPOBJ:
7116                         CHECK_OPSIZE (5);
7117                         CHECK_STACK (2);
7118                         token = read32 (ip + 1);
7119                         klass = mini_get_class (method, token, generic_context);
7120                         CHECK_TYPELOAD (klass);
7121                         sp -= 2;
7122                         if (generic_class_is_reference_type (cfg, klass)) {
7123                                 MonoInst *store, *load;
7124                                 MONO_INST_NEW (cfg, load, CEE_LDIND_REF);
7125                                 load->inst_i0 = sp [1];
7126                                 load->type = STACK_OBJ;
7127                                 load->klass = klass;
7128                                 load->flags |= ins_flag;
7129                                 MONO_INST_NEW (cfg, store, CEE_STIND_REF);
7130                                 handle_loaded_temps (cfg, bblock, stack_start, sp);
7131                                 MONO_ADD_INS (bblock, store);
7132                                 store->inst_i0 = sp [0];
7133                                 store->inst_i1 = load;
7134                                 store->flags |= ins_flag;
7135                         } else {
7136                                 guint32 align;
7137
7138                                 n = mono_class_value_size (klass, &align);
7139                                 if ((cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 5) {
7140                                         MonoInst *copy;
7141                                         NEW_MEMCPY (cfg, copy, sp [0], sp [1], n, align);
7142                                         MONO_ADD_INS (bblock, copy);
7143                                 } else {
7144                                         MonoMethod *memcpy_method = get_memcpy_method ();
7145                                         MonoInst *iargs [3];
7146                                         iargs [0] = sp [0];
7147                                         iargs [1] = sp [1];
7148                                         NEW_ICONST (cfg, iargs [2], n);
7149
7150                                         mono_emit_method_call_spilled (cfg, bblock, memcpy_method, memcpy_method->signature, iargs, ip, NULL);
7151                                 }
7152                         }
7153                         ins_flag = 0;
7154                         ip += 5;
7155                         break;
7156                 case CEE_LDOBJ: {
7157                         MonoInst *iargs [3];
7158                         int loc_index = -1;
7159                         int stloc_len = 0;
7160                         guint32 align;
7161
7162                         CHECK_OPSIZE (5);
7163                         CHECK_STACK (1);
7164                         --sp;
7165                         token = read32 (ip + 1);
7166                         klass = mini_get_class (method, token, generic_context);
7167                         CHECK_TYPELOAD (klass);
7168                         if (generic_class_is_reference_type (cfg, klass)) {
7169                                 MONO_INST_NEW (cfg, ins, CEE_LDIND_REF);
7170                                 ins->inst_i0 = sp [0];
7171                                 ins->type = STACK_OBJ;
7172                                 ins->klass = klass;
7173                                 ins->flags |= ins_flag;
7174                                 ins_flag = 0;
7175                                 *sp++ = ins;
7176                                 ip += 5;
7177                                 break;
7178                         }
7179
7180                         /* Optimize the common ldobj+stloc combination */
7181                         switch (ip [5]) {
7182                         case CEE_STLOC_S:
7183                                 loc_index = ip [6];
7184                                 stloc_len = 2;
7185                                 break;
7186                         case CEE_STLOC_0:
7187                         case CEE_STLOC_1:
7188                         case CEE_STLOC_2:
7189                         case CEE_STLOC_3:
7190                                 loc_index = ip [5] - CEE_STLOC_0;
7191                                 stloc_len = 1;
7192                                 break;
7193                         default:
7194                                 break;
7195                         }
7196
7197                         if ((loc_index != -1) && ip_in_bb (cfg, bblock, ip + 5)) {
7198                                 CHECK_LOCAL (loc_index);
7199                                 NEW_LOCSTORE (cfg, ins, loc_index, *sp);
7200
7201                                 /* FIXME: handle CEE_STIND_R4 */
7202                                 if (ins->opcode == CEE_STOBJ) {
7203                                         handle_loaded_temps (cfg, bblock, stack_start, sp);
7204                                         g_assert (ins->opcode == CEE_STOBJ);
7205                                         NEW_LOCLOADA (cfg, ins, loc_index);
7206                                         handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE, FALSE);
7207                                         ip += 5;
7208                                         ip += stloc_len;
7209                                         break;
7210                                 }
7211                         }
7212
7213                         n = mono_class_value_size (klass, &align);
7214                         ins = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
7215                         NEW_TEMPLOADA (cfg, iargs [0], ins->inst_c0);
7216                         if ((cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 5) {
7217                                 MonoInst *copy;
7218                                 NEW_MEMCPY (cfg, copy, iargs [0], *sp, n, align);
7219                                 MONO_ADD_INS (bblock, copy);
7220                         } else {
7221                                 MonoMethod *memcpy_method = get_memcpy_method ();
7222                                 iargs [1] = *sp;
7223                                 NEW_ICONST (cfg, iargs [2], n);
7224
7225                                 mono_emit_method_call_spilled (cfg, bblock, memcpy_method, memcpy_method->signature, iargs, ip, NULL);
7226                         }
7227                         NEW_TEMPLOAD (cfg, *sp, ins->inst_c0);
7228                         ++sp;
7229                         ip += 5;
7230                         ins_flag = 0;
7231                         inline_costs += 1;
7232                         break;
7233                 }
7234                 case CEE_LDSTR:
7235                         CHECK_STACK_OVF (1);
7236                         CHECK_OPSIZE (5);
7237                         n = read32 (ip + 1);
7238
7239                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
7240                                 /* FIXME: moving GC */
7241                                 NEW_PCONST (cfg, ins, mono_method_get_wrapper_data (method, n));
7242                                 ins->type = STACK_OBJ;
7243                                 ins->klass = mono_defaults.string_class;
7244                                 *sp = ins;
7245                         }
7246                         else if (method->wrapper_type != MONO_WRAPPER_NONE) {
7247                                 int temp;
7248                                 MonoInst *iargs [1];
7249
7250                                 NEW_PCONST (cfg, iargs [0], mono_method_get_wrapper_data (method, n));                          
7251                                 temp = mono_emit_jit_icall (cfg, bblock, mono_string_new_wrapper, iargs, ip);
7252                                 NEW_TEMPLOAD (cfg, *sp, temp);
7253
7254                         } else {
7255
7256                                 if (cfg->opt & MONO_OPT_SHARED) {
7257                                         int temp;
7258                                         MonoInst *iargs [3];
7259                                         MonoInst* domain_var;
7260                                         
7261                                         if (cfg->compile_aot) {
7262                                                 /* FIXME: bug when inlining methods from different assemblies (n is a token valid just in one). */
7263                                                 cfg->ldstr_list = g_list_prepend (cfg->ldstr_list, GINT_TO_POINTER (n));
7264                                         }
7265                                         /* avoid depending on undefined C behavior in sequence points */
7266                                         domain_var = mono_get_domainvar (cfg);
7267                                         NEW_TEMPLOAD (cfg, iargs [0], domain_var->inst_c0);
7268                                         NEW_IMAGECONST (cfg, iargs [1], image);
7269                                         NEW_ICONST (cfg, iargs [2], mono_metadata_token_index (n));
7270                                         temp = mono_emit_jit_icall (cfg, bblock, mono_ldstr, iargs, ip);
7271                                         NEW_TEMPLOAD (cfg, *sp, temp);
7272                                         mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
7273                                 } else {
7274                                         if (bblock->out_of_line) {
7275                                                 MonoInst *iargs [2];
7276                                                 int temp;
7277
7278                                                 if (cfg->method->klass->image == mono_defaults.corlib) {
7279                                                         /* 
7280                                                          * Avoid relocations and save some code size by using a 
7281                                                          * version of helper_ldstr specialized to mscorlib.
7282                                                          */
7283                                                         NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (n));
7284                                                         temp = mono_emit_jit_icall (cfg, bblock, mono_helper_ldstr_mscorlib, iargs, ip);
7285                                                 } else {
7286                                                         /* Avoid creating the string object */
7287                                                         NEW_IMAGECONST (cfg, iargs [0], image);
7288                                                         NEW_ICONST (cfg, iargs [1], mono_metadata_token_index (n));
7289                                                         temp = mono_emit_jit_icall (cfg, bblock, mono_helper_ldstr, iargs, ip);
7290                                                 }
7291                                                 NEW_TEMPLOAD (cfg, *sp, temp);
7292                                         } 
7293                                         else
7294                                         if (cfg->compile_aot) {
7295                                                 NEW_LDSTRCONST (cfg, ins, image, n);
7296                                                 *sp = ins;
7297                                         } 
7298                                         else {
7299                                                 NEW_PCONST (cfg, ins, NULL);
7300                                                 ins->type = STACK_OBJ;
7301                                                 ins->inst_p0 = mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
7302                                                 ins->klass = mono_defaults.string_class;
7303                                                 *sp = ins;
7304                                         }
7305                                 }
7306                         }
7307
7308                         sp++;
7309                         ip += 5;
7310                         break;
7311                 case CEE_NEWOBJ: {
7312                         MonoInst *iargs [2];
7313                         MonoMethodSignature *fsig;
7314                         MonoInst this_ins;
7315                         int temp;
7316
7317                         CHECK_OPSIZE (5);
7318                         token = read32 (ip + 1);
7319                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
7320                         if (!cmethod)
7321                                 goto load_error;
7322                         fsig = mono_method_get_signature (cmethod, image, token);
7323
7324                         mono_save_token_info (cfg, image, token, cmethod);
7325
7326                         if (!mono_class_init (cmethod->klass))
7327                                 goto load_error;
7328
7329                         if (cfg->generic_sharing_context)
7330                                 context_used = mono_method_check_context_used (cmethod);
7331
7332                         if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS) {
7333                                 if (check_linkdemand (cfg, method, cmethod, bblock, ip))
7334                                         INLINE_FAILURE;
7335                                 CHECK_CFG_EXCEPTION;
7336                         } else if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR) {
7337                                 ensure_method_is_allowed_to_call_method (cfg, method, cmethod, bblock, ip);
7338                         }
7339
7340                         n = fsig->param_count;
7341                         CHECK_STACK (n);
7342  
7343                         /* 
7344                          * Generate smaller code for the common newobj <exception> instruction in
7345                          * argument checking code.
7346                          */
7347                         if (bblock->out_of_line && cmethod->klass->image == mono_defaults.corlib && n <= 2 && 
7348                                 ((n < 1) || (!fsig->params [0]->byref && fsig->params [0]->type == MONO_TYPE_STRING)) && 
7349                                 ((n < 2) || (!fsig->params [1]->byref && fsig->params [1]->type == MONO_TYPE_STRING))) {
7350                                 MonoInst *iargs [3];
7351                                 int temp;
7352                                 
7353                                 sp -= n;
7354
7355                                 NEW_ICONST (cfg, iargs [0], cmethod->klass->type_token);
7356                                 switch (n) {
7357                                 case 0:
7358                                         temp = mono_emit_jit_icall (cfg, bblock, mono_create_corlib_exception_0, iargs, ip);
7359                                         break;
7360                                 case 1:
7361                                         iargs [1] = sp [0];
7362                                         temp = mono_emit_jit_icall (cfg, bblock, mono_create_corlib_exception_1, iargs, ip);
7363                                         break;
7364                                 case 2:
7365                                         iargs [1] = sp [0];
7366                                         iargs [2] = sp [1];
7367                                         temp = mono_emit_jit_icall (cfg, bblock, mono_create_corlib_exception_2, iargs, ip);
7368                                         break;
7369                                 default:
7370                                         g_assert_not_reached ();
7371                                 }
7372                                 NEW_TEMPLOAD (cfg, ins, temp);
7373                                 *sp ++ = ins;
7374
7375                                 ip += 5;
7376                                 inline_costs += 5;
7377                                 break;
7378                         }
7379
7380                         /* move the args to allow room for 'this' in the first position */
7381                         while (n--) {
7382                                 --sp;
7383                                 sp [1] = sp [0];
7384                         }
7385
7386                         /* check_call_signature () requires sp[0] to be set */
7387                         this_ins.type = STACK_OBJ;
7388                         sp [0] = &this_ins;
7389                         if (check_call_signature (cfg, fsig, sp))
7390                                 UNVERIFIED;
7391
7392                         handle_loaded_temps (cfg, bblock, stack_start, sp);
7393
7394                         if (mini_class_is_system_array (cmethod->klass)) {
7395                                 g_assert (!context_used);
7396
7397                                 NEW_METHODCONST (cfg, *sp, cmethod);
7398
7399                                 if (fsig->param_count == 2)
7400                                         /* Avoid varargs in the common case */
7401                                         temp = mono_emit_jit_icall (cfg, bblock, mono_array_new_2, sp, ip);
7402                                 else
7403                                         temp = handle_array_new (cfg, bblock, fsig->param_count, sp, ip);
7404                         } else if (cmethod->string_ctor) {
7405                                 g_assert (!context_used);
7406
7407                                 /* we simply pass a null pointer */
7408                                 NEW_PCONST (cfg, *sp, NULL); 
7409                                 /* now call the string ctor */
7410                                 temp = mono_emit_method_call_spilled (cfg, bblock, cmethod, fsig, sp, ip, NULL);
7411                         } else {
7412                                 MonoInst* callvirt_this_arg = NULL;
7413                                 
7414                                 if (cmethod->klass->valuetype) {
7415                                         iargs [0] = mono_compile_create_var (cfg, &cmethod->klass->byval_arg, OP_LOCAL);
7416                                         temp = iargs [0]->inst_c0;
7417
7418                                         NEW_TEMPLOADA (cfg, *sp, temp);
7419
7420                                         handle_initobj (cfg, bblock, *sp, NULL, cmethod->klass, stack_start, sp);
7421
7422                                         NEW_TEMPLOADA (cfg, *sp, temp);
7423
7424                                         /* 
7425                                          * The code generated by mini_emit_virtual_call () expects
7426                                          * iargs [0] to be a boxed instance, but luckily the vcall
7427                                          * will be transformed into a normal call there.
7428                                          */
7429                                 } else if (context_used) {
7430                                         MonoInst *rgctx, *data;
7431                                         int rgctx_info;
7432
7433                                         GET_RGCTX (rgctx, context_used);
7434                                         if (cfg->opt & MONO_OPT_SHARED)
7435                                                 rgctx_info = MONO_RGCTX_INFO_KLASS;
7436                                         else
7437                                                 rgctx_info = MONO_RGCTX_INFO_VTABLE;
7438                                         data = get_runtime_generic_context_ptr (cfg, method, context_used, bblock,
7439                                                 cmethod->klass, generic_context, rgctx, rgctx_info, ip);
7440
7441                                         temp = handle_alloc_from_inst (cfg, bblock, cmethod->klass, data, FALSE, ip);
7442                                         NEW_TEMPLOAD (cfg, *sp, temp);
7443                                 } else {
7444                                         MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
7445
7446                                         CHECK_TYPELOAD (cmethod->klass);
7447                                         if (mini_field_access_needs_cctor_run (cfg, method, vtable) && !(g_slist_find (class_inits, vtable))) {
7448                                                 guint8 *tramp = mono_create_class_init_trampoline (vtable);
7449                                                 mono_emit_native_call (cfg, bblock, tramp, 
7450                                                                                            helper_sig_class_init_trampoline,
7451                                                                                            NULL, ip, FALSE, FALSE);
7452                                                 if (cfg->verbose_level > 2)
7453                                                         g_print ("class %s.%s needs init call for ctor\n", cmethod->klass->name_space, cmethod->klass->name);
7454                                                 class_inits = g_slist_prepend (class_inits, vtable);
7455                                         }
7456                                         temp = handle_alloc (cfg, bblock, cmethod->klass, FALSE, ip);
7457                                         NEW_TEMPLOAD (cfg, *sp, temp);
7458                                 }
7459
7460                                 /* Avoid virtual calls to ctors if possible */
7461                                 if (cmethod->klass->marshalbyref)
7462                                         callvirt_this_arg = sp [0];
7463                                 
7464                                 if ((cfg->opt & MONO_OPT_INLINE) && cmethod && !context_used &&
7465                                     mono_method_check_inlining (cfg, cmethod) &&
7466                                     !mono_class_is_subclass_of (cmethod->klass, mono_defaults.exception_class, FALSE) &&
7467                                     !g_list_find (dont_inline, cmethod)) {
7468                                         int costs;
7469                                         MonoBasicBlock *ebblock;
7470                                         if ((costs = inline_method (cfg, cmethod, fsig, bblock, sp, ip, real_offset, dont_inline, &ebblock, FALSE))) {
7471
7472                                                 ip += 5;
7473                                                 real_offset += 5;
7474                                                 
7475                                                 GET_BBLOCK (cfg, bblock, ip);
7476                                                 ebblock->next_bb = bblock;
7477                                                 link_bblock (cfg, ebblock, bblock);
7478
7479                                                 NEW_TEMPLOAD (cfg, *sp, temp);
7480                                                 sp++;
7481
7482                                                 /* indicates start of a new block, and triggers a load 
7483                                                    of all stack arguments at bb boundarie */
7484                                                 bblock = ebblock;
7485
7486                                                 inline_costs += costs;
7487                                                 break;
7488                                                 
7489                                         } else {
7490                                                 /* Prevent inlining of methods which call other methods */
7491                                                 INLINE_FAILURE;
7492                                                 mono_emit_method_call_spilled (cfg, bblock, cmethod, fsig, sp, ip, callvirt_this_arg);
7493                                         }
7494                                 } else if (context_used &&
7495                                                 (cmethod->klass->valuetype ||
7496                                                 !mono_method_is_generic_sharable_impl (cmethod, TRUE))) {
7497                                         MonoInst *rgctx, *cmethod_addr;
7498
7499                                         g_assert (!callvirt_this_arg);
7500
7501                                         GET_RGCTX (rgctx, context_used);
7502                                         cmethod_addr = get_runtime_generic_context_method (cfg, method, context_used,
7503                                                         bblock, cmethod,
7504                                                         generic_context, rgctx, MONO_RGCTX_INFO_GENERIC_METHOD_CODE, ip);
7505
7506                                         mono_emit_calli_spilled (cfg, bblock, fsig, sp, cmethod_addr, ip);
7507                                 } else {
7508                                         /* Prevent inlining of methods which call other methods */
7509                                         INLINE_FAILURE;
7510                                         /* now call the actual ctor */
7511                                         mono_emit_method_call_spilled (cfg, bblock, cmethod, fsig, sp, ip, callvirt_this_arg);
7512                                 }
7513                         }
7514
7515                         NEW_TEMPLOAD (cfg, *sp, temp);
7516                         sp++;
7517                         
7518                         ip += 5;
7519                         inline_costs += 5;
7520                         break;
7521                 }
7522                 case CEE_ISINST:
7523                         CHECK_STACK (1);
7524                         --sp;
7525                         CHECK_OPSIZE (5);
7526                         token = read32 (ip + 1);
7527                         klass = mini_get_class (method, token, generic_context);
7528                         CHECK_TYPELOAD (klass);
7529                         if (sp [0]->type != STACK_OBJ)
7530                                 UNVERIFIED;
7531
7532                         if (cfg->generic_sharing_context)
7533                                 context_used = mono_class_check_context_used (klass);
7534
7535                         /* Needed by the code generated in inssel.brg */
7536                         if (!context_used)
7537                                 mono_get_got_var (cfg);
7538
7539                         if (context_used) {
7540                                 MonoInst *rgctx, *args [2];
7541                                 int temp;
7542
7543                                 /* obj */
7544                                 args [0] = *sp;
7545
7546                                 /* klass */
7547                                 GET_RGCTX (rgctx, context_used);
7548                                 args [1] = get_runtime_generic_context_ptr (cfg, method, context_used, bblock, klass,
7549                                         generic_context, rgctx, MONO_RGCTX_INFO_KLASS, ip);
7550
7551                                 temp = mono_emit_jit_icall (cfg, bblock, mono_object_isinst, args, ip);
7552                                 NEW_TEMPLOAD (cfg, *sp, temp);
7553
7554                                 sp++;
7555                                 ip += 5;
7556                                 inline_costs += 2;
7557                         } else if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
7558                         
7559                                 MonoMethod *mono_isinst;
7560                                 MonoInst *iargs [1];
7561                                 MonoBasicBlock *ebblock;
7562                                 int costs;
7563                                 int temp;
7564                                 
7565                                 mono_isinst = mono_marshal_get_isinst (klass); 
7566                                 iargs [0] = sp [0];
7567                                 
7568                                 costs = inline_method (cfg, mono_isinst, mono_method_signature (mono_isinst), bblock, 
7569                                                        iargs, ip, real_offset, dont_inline, &ebblock, TRUE);
7570                         
7571                                 g_assert (costs > 0);
7572                                 
7573                                 ip += 5;
7574                                 real_offset += 5;
7575                         
7576                                 GET_BBLOCK (cfg, bblock, ip);
7577                                 ebblock->next_bb = bblock;
7578                                 link_bblock (cfg, ebblock, bblock);
7579
7580                                 temp = iargs [0]->inst_i0->inst_c0;
7581                                 NEW_TEMPLOAD (cfg, *sp, temp);
7582                                 
7583                                 sp++;
7584                                 bblock = ebblock;
7585                                 inline_costs += costs;
7586                         } else {
7587                                 MONO_INST_NEW (cfg, ins, *ip);
7588                                 ins->type = STACK_OBJ;
7589                                 ins->inst_left = *sp;
7590                                 ins->inst_newa_class = klass;
7591                                 ins->klass = klass;
7592                                 *sp++ = emit_tree (cfg, bblock, ins, ip + 5);
7593                                 ip += 5;
7594                         }
7595                         break;
7596                 case CEE_UNBOX_ANY: {
7597                         MonoInst *iargs [3];
7598                         guint32 align;
7599
7600                         CHECK_STACK (1);
7601                         --sp;
7602                         CHECK_OPSIZE (5);
7603                         token = read32 (ip + 1);
7604                         klass = mini_get_class (method, token, generic_context);
7605                         CHECK_TYPELOAD (klass);
7606
7607                         if (cfg->generic_sharing_context)
7608                                 context_used = mono_class_check_context_used (klass);
7609
7610                         if (generic_class_is_reference_type (cfg, klass)) {
7611                                 switch (emit_castclass (klass, token, context_used, FALSE,
7612                                                 cfg, method, arg_array, param_types, dont_inline, end, header,
7613                                                 generic_context, &bblock, &ip, &sp, &inline_costs, &real_offset)) {
7614                                 case 0: break;
7615                                 case -1: goto unverified;
7616                                 case -2: goto exception_exit;
7617                                 default: g_assert_not_reached ();
7618                                 }
7619                                 break;
7620                         }
7621
7622                         if (mono_class_is_nullable (klass)) {
7623                                 int v;
7624                                 MonoInst *rgctx = NULL;
7625
7626                                 if (context_used)
7627                                         GET_RGCTX (rgctx, context_used);
7628
7629                                 v = handle_unbox_nullable (cfg, method, context_used, bblock, *sp, ip, klass,
7630                                         generic_context, rgctx);
7631                                 NEW_TEMPLOAD (cfg, *sp, v);
7632                                 sp ++;
7633                                 ip += 5;
7634                                 break;
7635                         }
7636
7637                         switch (emit_unbox (klass, token, context_used,
7638                                         cfg, method, arg_array, param_types, dont_inline, end, header,
7639                                         generic_context, &bblock, &ip, &sp, &inline_costs, &real_offset)) {
7640                         case 0: break;
7641                         case -1: goto unverified;
7642                         case -2: goto exception_exit;
7643                         default: g_assert_not_reached ();
7644                         }
7645                         ip += 5;
7646                         /* LDOBJ impl */
7647                         n = mono_class_value_size (klass, &align);
7648                         ins = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
7649                         NEW_TEMPLOADA (cfg, iargs [0], ins->inst_c0);
7650                         if ((cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 5) {
7651                                 MonoInst *copy;
7652                                 NEW_MEMCPY (cfg, copy, iargs [0], *sp, n, align);
7653                                 MONO_ADD_INS (bblock, copy);
7654                         } else {
7655                                 MonoMethod *memcpy_method = get_memcpy_method ();
7656                                 iargs [1] = *sp;
7657                                 NEW_ICONST (cfg, iargs [2], n);
7658
7659                                 mono_emit_method_call_spilled (cfg, bblock, memcpy_method, memcpy_method->signature, iargs, ip, NULL);
7660                         }
7661                         NEW_TEMPLOAD (cfg, *sp, ins->inst_c0);
7662                         ++sp;
7663                         inline_costs += 2;
7664                         break;
7665                 }
7666                 case CEE_UNBOX:
7667                         CHECK_STACK (1);
7668                         --sp;
7669                         CHECK_OPSIZE (5);
7670                         token = read32 (ip + 1);
7671                         klass = mini_get_class (method, token, generic_context);
7672                         CHECK_TYPELOAD (klass);
7673
7674                         if (cfg->generic_sharing_context)
7675                                 context_used = mono_class_check_context_used (klass);
7676
7677                         if (mono_class_is_nullable (klass)) {
7678                                 int v;
7679                                 MonoInst *rgctx = NULL;
7680
7681                                 if (context_used)
7682                                         GET_RGCTX (rgctx, context_used);
7683                                 v = handle_unbox_nullable (cfg, method, context_used, bblock, *sp, ip, klass,
7684                                         generic_context, rgctx);
7685                                 NEW_TEMPLOAD (cfg, *sp, v);
7686                                 sp ++;
7687                                 ip += 5;
7688                                 break;
7689                         }
7690
7691                         switch (emit_unbox (klass, token, context_used,
7692                                         cfg, method, arg_array, param_types, dont_inline, end, header,
7693                                         generic_context, &bblock, &ip, &sp, &inline_costs, &real_offset)) {
7694                         case 0: break;
7695                         case -1: goto unverified;
7696                         case -2: goto exception_exit;
7697                         default: g_assert_not_reached ();
7698                         }
7699
7700                         sp++;
7701                         ip += 5;
7702                         inline_costs += 2;
7703                         break;
7704                 case CEE_CASTCLASS:
7705                         CHECK_STACK (1);
7706                         --sp;
7707                         CHECK_OPSIZE (5);
7708                         token = read32 (ip + 1);
7709                         klass = mini_get_class (method, token, generic_context);
7710                         CHECK_TYPELOAD (klass);
7711                         if (sp [0]->type != STACK_OBJ)
7712                                 UNVERIFIED;
7713
7714                         if (cfg->generic_sharing_context)
7715                                 context_used = mono_class_check_context_used (klass);
7716
7717                         switch (emit_castclass (klass, token, context_used, TRUE,
7718                                         cfg, method, arg_array, param_types, dont_inline, end, header,
7719                                         generic_context, &bblock, &ip, &sp, &inline_costs, &real_offset)) {
7720                         case 0: break;
7721                         case -1: goto unverified;
7722                         case -2: goto exception_exit;
7723                         default: g_assert_not_reached ();
7724                         }
7725                         break;
7726                 case CEE_THROW:
7727                         CHECK_STACK (1);
7728                         MONO_INST_NEW (cfg, ins, OP_THROW);
7729                         --sp;
7730                         ins->inst_left = *sp;
7731                         ip++;
7732                         bblock->out_of_line = TRUE;
7733                         MONO_ADD_INS (bblock, ins);
7734                         MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
7735                         ins->cil_code = ip - 1;
7736                         MONO_ADD_INS (bblock, ins);
7737                         sp = stack_start;
7738                         
7739                         link_bblock (cfg, bblock, end_bblock);
7740                         start_new_bblock = 1;
7741                         break;
7742                 case CEE_LDFLD:
7743                 case CEE_LDFLDA:
7744                 case CEE_STFLD: {
7745                         MonoInst *offset_ins;
7746                         MonoClassField *field;
7747                         MonoBasicBlock *ebblock;
7748                         int costs;
7749                         guint foffset;
7750
7751                         if (*ip == CEE_STFLD) {
7752                                 CHECK_STACK (2);
7753                                 sp -= 2;
7754                         } else {
7755                                 CHECK_STACK (1);
7756                                 --sp;
7757                         }
7758                         if (sp [0]->type == STACK_I4 || sp [0]->type == STACK_I8 || sp [0]->type == STACK_R8)
7759                                 UNVERIFIED;
7760                         if (*ip != CEE_LDFLD && sp [0]->type == STACK_VTYPE)
7761                                 UNVERIFIED;
7762                         CHECK_OPSIZE (5);
7763                         token = read32 (ip + 1);
7764                         if (method->wrapper_type != MONO_WRAPPER_NONE) {
7765                                 field = mono_method_get_wrapper_data (method, token);
7766                                 klass = field->parent;
7767                         } else {
7768                                 field = mono_field_from_token (image, token, &klass, generic_context);
7769                         }
7770                         if (!field)
7771                                 goto load_error;
7772                         mono_class_init (klass);
7773                         if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_field (method, field))
7774                                 FIELD_ACCESS_FAILURE;
7775
7776                         foffset = klass->valuetype? field->offset - sizeof (MonoObject): field->offset;
7777                         /* FIXME: mark instructions for use in SSA */
7778                         if (*ip == CEE_STFLD) {
7779                                 if (target_type_is_incompatible (cfg, field->type, sp [1]))
7780                                         UNVERIFIED;
7781                                 if ((klass->marshalbyref && !MONO_CHECK_THIS (sp [0])) || klass->contextbound || klass == mono_defaults.marshalbyrefobject_class) {
7782                                         MonoMethod *stfld_wrapper = mono_marshal_get_stfld_wrapper (field->type); 
7783                                         MonoInst *iargs [5];
7784
7785                                         iargs [0] = sp [0];
7786                                         NEW_CLASSCONST (cfg, iargs [1], klass);
7787                                         NEW_FIELDCONST (cfg, iargs [2], field);
7788                                         NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : 
7789                                                     field->offset);
7790                                         iargs [4] = sp [1];
7791
7792                                         if (cfg->opt & MONO_OPT_INLINE) {
7793                                                 costs = inline_method (cfg, stfld_wrapper, mono_method_signature (stfld_wrapper), bblock, 
7794                                                                 iargs, ip, real_offset, dont_inline, &ebblock, TRUE);
7795                                                 g_assert (costs > 0);
7796                                                       
7797                                                 ip += 5;
7798                                                 real_offset += 5;
7799
7800                                                 GET_BBLOCK (cfg, bblock, ip);
7801                                                 ebblock->next_bb = bblock;
7802                                                 link_bblock (cfg, ebblock, bblock);
7803
7804                                                 /* indicates start of a new block, and triggers a load 
7805                                                    of all stack arguments at bb boundarie */
7806                                                 bblock = ebblock;
7807
7808                                                 inline_costs += costs;
7809                                                 break;
7810                                         } else {
7811                                                 mono_emit_method_call_spilled (cfg, bblock, stfld_wrapper, mono_method_signature (stfld_wrapper), iargs, ip, NULL);
7812                                         }
7813 #if HAVE_WRITE_BARRIERS
7814                                 } else if (mini_type_to_stind (cfg, field->type) == CEE_STIND_REF && !(sp [1]->opcode == OP_PCONST && sp [1]->inst_c0 == 0)) {
7815                                         /* insert call to write barrier */
7816                                         MonoMethod *write_barrier = mono_marshal_get_write_barrier ();
7817                                         MonoInst *iargs [2];
7818                                         NEW_ICONST (cfg, offset_ins, foffset);
7819                                         MONO_INST_NEW (cfg, ins, OP_PADD);
7820                                         ins->inst_left = *sp;
7821                                         ins->inst_right = offset_ins;
7822                                         ins->type = STACK_MP;
7823                                         ins->klass = mono_defaults.object_class;
7824                                         iargs [0] = ins;
7825                                         iargs [1] = sp [1];
7826                                         mono_emit_method_call_spilled (cfg, bblock, write_barrier, mono_method_signature (write_barrier), iargs, ip, NULL);
7827 #endif
7828 #ifdef MONO_ARCH_SOFT_FLOAT
7829                                 } else if (mini_type_to_stind (cfg, field->type) == CEE_STIND_R4) {
7830                                         NEW_ICONST (cfg, offset_ins, foffset);
7831                                         MONO_INST_NEW (cfg, ins, OP_PADD);
7832                                         ins->inst_left = *sp;
7833                                         ins->inst_right = offset_ins;
7834                                         ins->type = STACK_MP;
7835                                         ins->klass = mono_defaults.object_class;
7836                                         handle_store_float (cfg, bblock, ins, sp [1], ip);
7837 #endif
7838                                 } else {
7839                                         MonoInst *store;
7840                                         NEW_ICONST (cfg, offset_ins, foffset);
7841                                         MONO_INST_NEW (cfg, ins, OP_PADD);
7842                                         ins->inst_left = *sp;
7843                                         ins->inst_right = offset_ins;
7844                                         ins->type = STACK_MP;
7845
7846                                         MONO_INST_NEW (cfg, store, mini_type_to_stind (cfg, field->type));
7847                                         store->inst_left = ins;
7848                                         store->inst_right = sp [1];
7849                                         handle_loaded_temps (cfg, bblock, stack_start, sp);
7850                                         store->flags |= ins_flag;
7851                                         ins_flag = 0;
7852                                         if (store->opcode == CEE_STOBJ) {
7853                                                 handle_stobj (cfg, bblock, ins, sp [1], ip, 
7854                                                               mono_class_from_mono_type (field->type), FALSE, FALSE, TRUE);
7855                                         } else
7856                                                 MONO_ADD_INS (bblock, store);
7857                                 }
7858                         } else {
7859                                 if ((klass->marshalbyref && !MONO_CHECK_THIS (sp [0])) || klass->contextbound || klass == mono_defaults.marshalbyrefobject_class) {
7860                                         MonoMethod *wrapper = (*ip == CEE_LDFLDA) ? mono_marshal_get_ldflda_wrapper (field->type) : mono_marshal_get_ldfld_wrapper (field->type); 
7861                                         MonoInst *iargs [4];
7862                                         int temp;
7863                                         
7864                                         iargs [0] = sp [0];
7865                                         NEW_CLASSCONST (cfg, iargs [1], klass);
7866                                         NEW_FIELDCONST (cfg, iargs [2], field);
7867                                         NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : field->offset);
7868                                         if ((cfg->opt & MONO_OPT_INLINE) && !MONO_TYPE_ISSTRUCT (mono_method_signature (wrapper)->ret)) {
7869                                                 costs = inline_method (cfg, wrapper, mono_method_signature (wrapper), bblock, 
7870                                                                 iargs, ip, real_offset, dont_inline, &ebblock, TRUE);
7871                                                 g_assert (costs > 0);
7872                                                       
7873                                                 ip += 5;
7874                                                 real_offset += 5;
7875
7876                                                 GET_BBLOCK (cfg, bblock, ip);
7877                                                 ebblock->next_bb = bblock;
7878                                                 link_bblock (cfg, ebblock, bblock);
7879
7880                                                 temp = iargs [0]->inst_i0->inst_c0;
7881
7882                                                 NEW_TEMPLOAD (cfg, *sp, temp);
7883                                                 sp++;
7884
7885                                                 /* indicates start of a new block, and triggers a load of
7886                                                    all stack arguments at bb boundarie */
7887                                                 bblock = ebblock;
7888                                                 
7889                                                 inline_costs += costs;
7890                                                 break;
7891                                         } else {
7892                                                 temp = mono_emit_method_call_spilled (cfg, bblock, wrapper, mono_method_signature (wrapper), iargs, ip, NULL);
7893                                                 NEW_TEMPLOAD (cfg, *sp, temp);
7894                                                 NEW_TEMPLOAD_SOFT_FLOAT (cfg, bblock, *sp, temp, ip);
7895                                                 sp++;
7896                                         }
7897                                 } else {
7898                                         NEW_ICONST (cfg, offset_ins, foffset);
7899                                         MONO_INST_NEW (cfg, ins, OP_PADD);
7900                                         ins->inst_left = *sp;
7901                                         ins->inst_right = offset_ins;
7902                                         ins->type = STACK_MP;
7903
7904                                         if (*ip == CEE_LDFLDA) {
7905                                                 ins->klass = mono_class_from_mono_type (field->type);
7906                                                 *sp++ = ins;
7907                                         } else {
7908                                                 MonoInst *load;
7909                                                 MONO_INST_NEW (cfg, load, mini_type_to_ldind (cfg, field->type));
7910                                                 type_to_eval_stack_type (cfg, field->type, load);
7911                                                 load->inst_left = ins;
7912                                                 load->flags |= ins_flag;
7913                                                 ins_flag = 0;
7914 #ifdef MONO_ARCH_SOFT_FLOAT
7915                                                 if (mini_type_to_ldind (cfg, field->type) == CEE_LDIND_R4) {
7916                                                         int temp;
7917                                                         temp = handle_load_float (cfg, bblock, ins, ip);
7918                                                         NEW_TEMPLOAD (cfg, *sp, temp);
7919                                                         sp++;
7920                                                 } else
7921 #endif
7922                                                 *sp++ = load;
7923                                         }
7924                                 }
7925                         }
7926                         ip += 5;
7927                         break;
7928                 }
7929                 case CEE_LDSFLD:
7930                 case CEE_LDSFLDA:
7931                 case CEE_STSFLD: {
7932                         MonoClassField *field;
7933                         gboolean is_special_static;
7934                         gpointer addr = NULL;
7935
7936                         CHECK_OPSIZE (5);
7937                         token = read32 (ip + 1);
7938                         if (method->wrapper_type != MONO_WRAPPER_NONE) {
7939                                 field = mono_method_get_wrapper_data (method, token);
7940                                 klass = field->parent;
7941                         }
7942                         else
7943                                 field = mono_field_from_token (image, token, &klass, generic_context);
7944                         if (!field)
7945                                 goto load_error;
7946                         mono_class_init (klass);
7947                         if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_field (method, field))
7948                                 FIELD_ACCESS_FAILURE;
7949
7950                         /*
7951                          * We can only support shared generic static
7952                          * field access on architectures where the
7953                          * trampoline code has been extended to handle
7954                          * the generic class init.
7955                          */
7956 #ifndef MONO_ARCH_VTABLE_REG
7957                         GENERIC_SHARING_FAILURE (*ip);
7958 #endif
7959
7960                         if (cfg->generic_sharing_context)
7961                                 context_used = mono_class_check_context_used (klass);
7962
7963                         g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
7964
7965                         if ((*ip) == CEE_STSFLD)
7966                                 handle_loaded_temps (cfg, bblock, stack_start, sp);
7967
7968                         is_special_static = mono_class_field_is_special_static (field);
7969
7970                         if ((cfg->opt & MONO_OPT_SHARED) ||
7971                                         (cfg->compile_aot && is_special_static) ||
7972                                         (context_used && is_special_static)) {
7973                                 int temp;
7974                                 MonoInst *iargs [2];
7975
7976                                 g_assert (field->parent);
7977                                 if ((cfg->opt & MONO_OPT_SHARED) || cfg->compile_aot) {
7978                                         MonoInst *domain_var;
7979                                         /* avoid depending on undefined C behavior in sequence points */
7980                                         domain_var = mono_get_domainvar (cfg);
7981                                         NEW_TEMPLOAD (cfg, iargs [0], domain_var->inst_c0);
7982                                 } else {
7983                                         NEW_DOMAINCONST (cfg, iargs [0]);
7984                                 }
7985                                 if (context_used) {
7986                                         MonoInst *rgctx;
7987
7988                                         GET_RGCTX (rgctx, context_used);
7989                                         iargs [1] = get_runtime_generic_context_field (cfg, method, context_used,
7990                                                         bblock, field,
7991                                                         generic_context, rgctx, MONO_RGCTX_INFO_CLASS_FIELD, ip);
7992                                 } else {
7993                                         NEW_FIELDCONST (cfg, iargs [1], field);
7994                                 }
7995                                 temp = mono_emit_jit_icall (cfg, bblock, mono_class_static_field_address, iargs, ip);
7996                                 NEW_TEMPLOAD (cfg, ins, temp);
7997                         } else if (context_used) {
7998                                 MonoInst *rgctx, *static_data;
7999
8000                                 /*
8001                                 g_print ("sharing static field access in %s.%s.%s - depth %d offset %d\n",
8002                                         method->klass->name_space, method->klass->name, method->name,
8003                                         depth, field->offset);
8004                                 */
8005
8006                                 if (mono_class_needs_cctor_run (klass, method)) {
8007                                         MonoMethodSignature *sig = helper_sig_generic_class_init_trampoline;
8008                                         MonoCallInst *call;
8009                                         MonoInst *vtable, *rgctx;
8010
8011                                         GET_RGCTX (rgctx, context_used);
8012                                         vtable = get_runtime_generic_context_ptr (cfg, method, context_used, bblock, klass,
8013                                                         generic_context, rgctx, MONO_RGCTX_INFO_VTABLE, ip);
8014
8015                                         call = mono_emit_call_args (cfg, bblock, sig, NULL, FALSE, FALSE, ip, FALSE);
8016                                         call->inst.opcode = OP_TRAMPCALL_VTABLE;
8017                                         call->fptr = mono_create_generic_class_init_trampoline ();
8018
8019                                         call->inst.inst_left = vtable;
8020
8021                                         mono_spill_call (cfg, bblock, call, sig, FALSE, ip, FALSE);
8022                                 }
8023
8024                                 /*
8025                                  * The pointer we're computing here is
8026                                  *
8027                                  *   super_info.static_data + field->offset
8028                                  */
8029                                 GET_RGCTX (rgctx, context_used);
8030                                 static_data = get_runtime_generic_context_ptr (cfg, method, context_used, bblock, klass,
8031                                         generic_context, rgctx, MONO_RGCTX_INFO_STATIC_DATA, ip);
8032
8033                                 if (field->offset == 0) {
8034                                         ins = static_data;
8035                                 } else {
8036                                         MonoInst *field_offset;
8037
8038                                         NEW_ICONST (cfg, field_offset, field->offset);
8039
8040                                         MONO_INST_NEW (cfg, ins, OP_PADD);
8041                                         ins->inst_left = static_data;
8042                                         ins->inst_right = field_offset;
8043                                         ins->type = STACK_PTR;
8044                                         ins->klass = klass;
8045                                 }
8046                         } else {
8047                                 MonoVTable *vtable;
8048
8049                                 vtable = mono_class_vtable (cfg->domain, klass);
8050                                 CHECK_TYPELOAD (klass);
8051                                 if (!is_special_static) {
8052                                         if (mini_field_access_needs_cctor_run (cfg, method, vtable) && !(g_slist_find (class_inits, vtable))) {
8053                                                 guint8 *tramp = mono_create_class_init_trampoline (vtable);
8054                                                 mono_emit_native_call (cfg, bblock, tramp, 
8055                                                                                            helper_sig_class_init_trampoline,
8056                                                                                            NULL, ip, FALSE, FALSE);
8057                                                 if (cfg->verbose_level > 2)
8058                                                         g_print ("class %s.%s needs init call for %s\n", klass->name_space, klass->name, field->name);
8059                                                 class_inits = g_slist_prepend (class_inits, vtable);
8060                                         } else {
8061                                                 if (cfg->run_cctors) {
8062                                                         MonoException *ex;
8063                                                         /* This makes so that inline cannot trigger */
8064                                                         /* .cctors: too many apps depend on them */
8065                                                         /* running with a specific order... */
8066                                                         if (! vtable->initialized)
8067                                                                 INLINE_FAILURE;
8068                                                         ex = mono_runtime_class_init_full (vtable, FALSE);
8069                                                         if (ex) {
8070                                                                 set_exception_object (cfg, ex);
8071                                                                 goto exception_exit;
8072                                                         }                                       
8073                                                 }
8074                                         }
8075                                         addr = (char*)vtable->data + field->offset;
8076
8077                                         if (cfg->compile_aot)
8078                                                 NEW_SFLDACONST (cfg, ins, field);
8079                                         else
8080                                                 NEW_PCONST (cfg, ins, addr);
8081                                 } else {
8082                                         int temp;
8083                                         MonoInst *iargs [1];
8084
8085                                         /* The special_static_fields
8086                                          * field is init'd in
8087                                          * mono_class_vtable, so it
8088                                          * needs to be called here.
8089                                          */
8090                                         if (!(cfg->opt & MONO_OPT_SHARED)) {
8091                                                 mono_class_vtable (cfg->domain, klass);
8092                                                 CHECK_TYPELOAD (klass);
8093                                         }
8094                                         mono_domain_lock (cfg->domain);
8095                                         if (cfg->domain->special_static_fields)
8096                                                 addr = g_hash_table_lookup (cfg->domain->special_static_fields, field);
8097                                         mono_domain_unlock (cfg->domain);
8098
8099                                         /* 
8100                                          * insert call to mono_threads_get_static_data (GPOINTER_TO_UINT (addr)) 
8101                                          * This could be later optimized to do just a couple of
8102                                          * memory dereferences with constant offsets.
8103                                          */
8104                                         NEW_ICONST (cfg, iargs [0], GPOINTER_TO_UINT (addr));
8105                                         temp = mono_emit_jit_icall (cfg, bblock, mono_get_special_static_data, iargs, ip);
8106                                         NEW_TEMPLOAD (cfg, ins, temp);
8107                                 }
8108                         }
8109
8110                         /* FIXME: mark instructions for use in SSA */
8111                         if (*ip == CEE_LDSFLDA) {
8112                                 ins->klass = mono_class_from_mono_type (field->type);
8113                                 *sp++ = ins;
8114                         } else if (*ip == CEE_STSFLD) {
8115                                 MonoInst *store;
8116                                 CHECK_STACK (1);
8117                                 sp--;
8118                                 MONO_INST_NEW (cfg, store, mini_type_to_stind (cfg, field->type));
8119                                 store->inst_left = ins;
8120                                 store->inst_right = sp [0];
8121                                 store->flags |= ins_flag;
8122                                 ins_flag = 0;
8123
8124 #ifdef MONO_ARCH_SOFT_FLOAT
8125                                 if (store->opcode == CEE_STIND_R4)
8126                                         handle_store_float (cfg, bblock, ins, sp [0], ip);
8127                                 else
8128 #endif
8129                                 if (store->opcode == CEE_STOBJ) {
8130                                         handle_stobj (cfg, bblock, ins, sp [0], ip, mono_class_from_mono_type (field->type), FALSE, FALSE, FALSE);
8131                                 } else
8132                                         MONO_ADD_INS (bblock, store);
8133                         } else {
8134                                 gboolean is_const = FALSE;
8135                                 MonoVTable *vtable = NULL;
8136
8137                                 if (!context_used)
8138                                         vtable = mono_class_vtable (cfg->domain, klass);
8139
8140                                 CHECK_TYPELOAD (klass);
8141                                 if (!context_used && !((cfg->opt & MONO_OPT_SHARED) || cfg->compile_aot) && 
8142                                     vtable->initialized && (field->type->attrs & FIELD_ATTRIBUTE_INIT_ONLY)) {
8143                                         gpointer addr = (char*)vtable->data + field->offset;
8144                                         int ro_type = field->type->type;
8145                                         if (ro_type == MONO_TYPE_VALUETYPE && field->type->data.klass->enumtype) {
8146                                                 ro_type = field->type->data.klass->enum_basetype->type;
8147                                         }
8148                                         /* g_print ("RO-FIELD %s.%s:%s\n", klass->name_space, klass->name, field->name);*/
8149                                         is_const = TRUE;
8150                                         switch (ro_type) {
8151                                         case MONO_TYPE_BOOLEAN:
8152                                         case MONO_TYPE_U1:
8153                                                 NEW_ICONST (cfg, *sp, *((guint8 *)addr));
8154                                                 sp++;
8155                                                 break;
8156                                         case MONO_TYPE_I1:
8157                                                 NEW_ICONST (cfg, *sp, *((gint8 *)addr));
8158                                                 sp++;
8159                                                 break;                                          
8160                                         case MONO_TYPE_CHAR:
8161                                         case MONO_TYPE_U2:
8162                                                 NEW_ICONST (cfg, *sp, *((guint16 *)addr));
8163                                                 sp++;
8164                                                 break;
8165                                         case MONO_TYPE_I2:
8166                                                 NEW_ICONST (cfg, *sp, *((gint16 *)addr));
8167                                                 sp++;
8168                                                 break;
8169                                                 break;
8170                                         case MONO_TYPE_I4:
8171                                                 NEW_ICONST (cfg, *sp, *((gint32 *)addr));
8172                                                 sp++;
8173                                                 break;                                          
8174                                         case MONO_TYPE_U4:
8175                                                 NEW_ICONST (cfg, *sp, *((guint32 *)addr));
8176                                                 sp++;
8177                                                 break;
8178 #ifndef HAVE_MOVING_COLLECTOR
8179                                         case MONO_TYPE_I:
8180                                         case MONO_TYPE_U:
8181                                         case MONO_TYPE_STRING:
8182                                         case MONO_TYPE_OBJECT:
8183                                         case MONO_TYPE_CLASS:
8184                                         case MONO_TYPE_SZARRAY:
8185                                         case MONO_TYPE_PTR:
8186                                         case MONO_TYPE_FNPTR:
8187                                         case MONO_TYPE_ARRAY:
8188                                                 NEW_PCONST (cfg, *sp, *((gpointer *)addr));
8189                                                 type_to_eval_stack_type (cfg, field->type, *sp);
8190                                                 sp++;
8191                                                 break;
8192 #endif
8193                                         case MONO_TYPE_I8:
8194                                         case MONO_TYPE_U8:
8195                                                 MONO_INST_NEW (cfg, *sp, OP_I8CONST);
8196                                                 sp [0]->type = STACK_I8;
8197                                                 sp [0]->inst_l = *((gint64 *)addr);
8198                                                 sp++;
8199                                                 break;
8200                                         case MONO_TYPE_R4:
8201                                         case MONO_TYPE_R8:
8202                                         case MONO_TYPE_VALUETYPE:
8203                                         default:
8204                                                 is_const = FALSE;
8205                                                 break;
8206                                         }
8207                                 }
8208
8209                                 if (!is_const) {
8210                                         MonoInst *load;
8211                                         CHECK_STACK_OVF (1);
8212                                         MONO_INST_NEW (cfg, load, mini_type_to_ldind (cfg, field->type));
8213                                         type_to_eval_stack_type (cfg, field->type, load);
8214                                         load->inst_left = ins;
8215                                         load->flags |= ins_flag;
8216 #ifdef MONO_ARCH_SOFT_FLOAT
8217                                         if (load->opcode == CEE_LDIND_R4) {
8218                                                 int temp;
8219                                                 temp = handle_load_float (cfg, bblock, ins, ip);
8220                                                 NEW_TEMPLOAD (cfg, load, temp);
8221                                         }
8222 #endif
8223                                         *sp++ = load;
8224                                         ins_flag = 0;
8225                                 }
8226                         }
8227                         ip += 5;
8228                         break;
8229                 }
8230                 case CEE_STOBJ:
8231                         CHECK_STACK (2);
8232                         sp -= 2;
8233                         CHECK_OPSIZE (5);
8234                         token = read32 (ip + 1);
8235                         klass = mini_get_class (method, token, generic_context);
8236                         CHECK_TYPELOAD (klass);
8237                         n = mini_type_to_stind (cfg, &klass->byval_arg);
8238                         /* FIXME: handle CEE_STIND_R4 */
8239                         if (n == CEE_STOBJ) {
8240                                 handle_stobj (cfg, bblock, sp [0], sp [1], ip, klass, FALSE, FALSE, TRUE);
8241                         } else {
8242                                 /* FIXME: should check item at sp [1] is compatible with the type of the store. */
8243                                 MonoInst *store;
8244                                 MONO_INST_NEW (cfg, store, n);
8245                                 store->inst_left = sp [0];
8246                                 store->inst_right = sp [1];
8247                                 store->flags |= ins_flag;
8248                                 MONO_ADD_INS (bblock, store);
8249                         }
8250                         ins_flag = 0;
8251                         ip += 5;
8252                         inline_costs += 1;
8253                         break;
8254                 case CEE_BOX: {
8255                         MonoInst *val;
8256
8257                         CHECK_STACK (1);
8258                         --sp;
8259                         val = *sp;
8260                         CHECK_OPSIZE (5);
8261                         token = read32 (ip + 1);
8262                         klass = mini_get_class (method, token, generic_context);
8263                         CHECK_TYPELOAD (klass);
8264
8265                         if (cfg->generic_sharing_context)
8266                                 context_used =  mono_class_check_context_used (klass);
8267
8268                         if (generic_class_is_reference_type (cfg, klass)) {
8269                                 *sp++ = val;
8270                                 ip += 5;
8271                                 break;
8272                         }
8273                         if (klass == mono_defaults.void_class)
8274                                 UNVERIFIED;
8275                         if (target_type_is_incompatible (cfg, &klass->byval_arg, *sp))
8276                                 UNVERIFIED;
8277                         /* frequent check in generic code: box (struct), brtrue */
8278                         if (!mono_class_is_nullable (klass) &&
8279                             ip + 5 < end && ip_in_bb (cfg, bblock, ip + 5) && (ip [5] == CEE_BRTRUE || ip [5] == CEE_BRTRUE_S)) {
8280                                 /*g_print ("box-brtrue opt at 0x%04x in %s\n", real_offset, method->name);*/
8281                                 MONO_INST_NEW (cfg, ins, CEE_POP);
8282                                 MONO_ADD_INS (bblock, ins);
8283                                 ins->inst_i0 = *sp;
8284                                 ip += 5;
8285                                 cfg->ip = ip;
8286                                 MONO_INST_NEW (cfg, ins, OP_BR);
8287                                 MONO_ADD_INS (bblock, ins);
8288                                 if (*ip == CEE_BRTRUE_S) {
8289                                         CHECK_OPSIZE (2);
8290                                         ip++;
8291                                         target = ip + 1 + (signed char)(*ip);
8292                                         ip++;
8293                                 } else {
8294                                         CHECK_OPSIZE (5);
8295                                         ip++;
8296                                         target = ip + 4 + (gint)(read32 (ip));
8297                                         ip += 4;
8298                                 }
8299                                 GET_BBLOCK (cfg, tblock, target);
8300                                 link_bblock (cfg, bblock, tblock);
8301                                 CHECK_BBLOCK (target, ip, tblock);
8302                                 ins->inst_target_bb = tblock;
8303                                 GET_BBLOCK (cfg, tblock, ip);
8304                                 link_bblock (cfg, bblock, tblock);
8305                                 if (sp != stack_start) {
8306                                         handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
8307                                         sp = stack_start;
8308                                         CHECK_UNVERIFIABLE (cfg);
8309                                 }
8310                                 start_new_bblock = 1;
8311                                 break;
8312                         }
8313                         if (context_used) {
8314                                 MonoInst *rgctx;
8315
8316                                 if (mono_class_is_nullable (klass)) {
8317                                         GET_RGCTX (rgctx, context_used);
8318                                         *sp++ = handle_box_nullable_from_inst (cfg, method, context_used, bblock, val,
8319                                                         ip, klass, generic_context, rgctx);
8320                                 } else {
8321                                         MonoInst *data;
8322                                         int rgctx_info;
8323
8324                                         GET_RGCTX (rgctx, context_used);
8325                                         if (cfg->opt & MONO_OPT_SHARED)
8326                                                 rgctx_info = MONO_RGCTX_INFO_KLASS;
8327                                         else
8328                                                 rgctx_info = MONO_RGCTX_INFO_VTABLE;
8329                                         data = get_runtime_generic_context_ptr (cfg, method, context_used, bblock, klass,
8330                                                         generic_context, rgctx, rgctx_info, ip);
8331
8332                                         *sp++ = handle_box_from_inst (cfg, bblock, val, ip, klass, data);
8333                                 }
8334                         } else {
8335                                 *sp++ = handle_box (cfg, bblock, val, ip, klass);
8336                         }
8337                         ip += 5;
8338                         inline_costs += 1;
8339                         break;
8340                 }
8341                 case CEE_NEWARR:
8342                         CHECK_STACK (1);
8343                         --sp;
8344
8345                         CHECK_OPSIZE (5);
8346                         token = read32 (ip + 1);
8347
8348                         /* allocate the domainvar - becaus this is used in decompose_foreach */
8349                         if (cfg->opt & MONO_OPT_SHARED) {
8350                                 mono_get_domainvar (cfg);
8351                                 /* LAME-IR: Mark it as used since otherwise it will be optimized away */
8352                                 cfg->domainvar->flags |= MONO_INST_VOLATILE;
8353                         }
8354
8355                         /* Ditto */
8356                         mono_get_got_var (cfg);
8357
8358                         klass = mini_get_class (method, token, generic_context);
8359                         CHECK_TYPELOAD (klass);
8360
8361                         if (cfg->generic_sharing_context)
8362                                 context_used = mono_class_check_context_used (klass);
8363
8364                         if (context_used) {
8365                                 MonoInst *rgctx, *args [3];
8366                                 int temp;
8367
8368                                 /* domain */
8369                                 /* FIXME: what about domain-neutral code? */
8370                                 NEW_DOMAINCONST (cfg, args [0]);
8371
8372                                 /* klass */
8373                                 GET_RGCTX (rgctx, context_used);
8374                                 args [1] = get_runtime_generic_context_ptr (cfg, method, context_used, bblock, klass,
8375                                         generic_context, rgctx, MONO_RGCTX_INFO_KLASS, ip);
8376
8377                                 /* array len */
8378                                 args [2] = *sp;
8379
8380                                 temp = mono_emit_jit_icall (cfg, bblock, mono_array_new, args, ip);
8381                                 NEW_TEMPLOAD (cfg, ins, temp);
8382                         } else {
8383                                 MONO_INST_NEW (cfg, ins, *ip);
8384                                 ins->inst_newa_class = klass;
8385                                 ins->inst_newa_len = *sp;
8386                                 ins->type = STACK_OBJ;
8387                                 ins->klass = mono_array_class_get (klass, 1);
8388                         }
8389
8390                         ip += 5;
8391                         *sp++ = ins;
8392                         /* 
8393                          * we store the object so calls to create the array are not interleaved
8394                          * with the arguments of other calls.
8395                          */
8396                         if (1) {
8397                                 MonoInst *store, *temp, *load;
8398                                 const char *data_ptr;
8399                                 int data_size = 0;
8400                                 --sp;
8401                                 temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
8402                                 NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
8403                                 store->cil_code = ins->cil_code;
8404                                 MONO_ADD_INS (bblock, store);
8405                                 /* 
8406                                  * we inline/optimize the initialization sequence if possible.
8407                                  * we should also allocate the array as not cleared, since we spend as much time clearing to 0 as initializing
8408                                  * for small sizes open code the memcpy
8409                                  * ensure the rva field is big enough
8410                                  */
8411                                 if ((cfg->opt & MONO_OPT_INTRINS) && ip + 6 < end && ip_in_bb (cfg, bblock, ip + 6) && (data_ptr = initialize_array_data (method, cfg->compile_aot, ip, ins, &data_size))) {
8412                                         MonoMethod *memcpy_method = get_memcpy_method ();
8413                                         MonoInst *data_offset, *add;
8414                                         MonoInst *iargs [3];
8415                                         NEW_ICONST (cfg, iargs [2], data_size);
8416                                         NEW_TEMPLOAD (cfg, load, temp->inst_c0);
8417                                         load->cil_code = ins->cil_code;
8418                                         NEW_ICONST (cfg, data_offset, G_STRUCT_OFFSET (MonoArray, vector));
8419                                         MONO_INST_NEW (cfg, add, OP_PADD);
8420                                         add->inst_left = load;
8421                                         add->inst_right = data_offset;
8422                                         iargs [0] = add;
8423                                         if (cfg->compile_aot) {
8424                                                 NEW_AOTCONST_TOKEN (cfg, iargs [1], MONO_PATCH_INFO_RVA, method->klass->image, GPOINTER_TO_UINT(data_ptr), STACK_PTR, NULL);
8425                                         } else {
8426                                                 NEW_PCONST (cfg, iargs [1], (char*)data_ptr);
8427                                         }
8428                                         mono_emit_method_call_spilled (cfg, bblock, memcpy_method, memcpy_method->signature, iargs, ip, NULL);
8429                                         ip += 11;
8430                                 }
8431                                 NEW_TEMPLOAD (cfg, load, temp->inst_c0);
8432                                 load->cil_code = ins->cil_code;
8433                                 *sp++ = load;
8434                         }
8435                         inline_costs += 1;
8436                         break;
8437                 case CEE_LDLEN:
8438                         CHECK_STACK (1);
8439                         --sp;
8440                         if (sp [0]->type != STACK_OBJ)
8441                                 UNVERIFIED;
8442                         MONO_INST_NEW (cfg, ins, *ip);
8443                         ip++;
8444                         ins->inst_left = *sp;
8445                         ins->type = STACK_PTR;
8446                         *sp++ = ins;
8447                         break;
8448                 case CEE_LDELEMA:
8449                         CHECK_STACK (2);
8450                         sp -= 2;
8451                         CHECK_OPSIZE (5);
8452                         if (sp [0]->type != STACK_OBJ)
8453                                 UNVERIFIED;
8454
8455                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
8456                         CHECK_TYPELOAD (klass);
8457                         /* we need to make sure that this array is exactly the type it needs
8458                          * to be for correctness. the wrappers are lax with their usage
8459                          * so we need to ignore them here
8460                          */
8461                         if (!klass->valuetype && method->wrapper_type == MONO_WRAPPER_NONE && !readonly) {
8462                                 MonoInst* check;
8463
8464                                 /* Needed by the code generated in inssel.brg */
8465                                 mono_get_got_var (cfg);
8466
8467                                 MONO_INST_NEW (cfg, check, OP_CHECK_ARRAY_TYPE);
8468                                 check->klass = mono_array_class_get (klass, 1);
8469                                 check->inst_left = sp [0];
8470                                 check->type = STACK_OBJ;
8471                                 sp [0] = check;
8472                         }
8473                         
8474                         readonly = FALSE;
8475                         mono_class_init (klass);
8476                         NEW_LDELEMA (cfg, ins, sp, klass);
8477                         *sp++ = ins;
8478                         ip += 5;
8479                         break;
8480                 case CEE_LDELEM_ANY: {
8481                         MonoInst *load;
8482                         CHECK_STACK (2);
8483                         sp -= 2;
8484                         if (sp [0]->type != STACK_OBJ)
8485                                 UNVERIFIED;
8486                         CHECK_OPSIZE (5);
8487                         token = read32 (ip + 1);
8488                         klass = mini_get_class (method, token, generic_context);
8489                         CHECK_TYPELOAD (klass);
8490                         mono_class_init (klass);
8491                         NEW_LDELEMA (cfg, load, sp, klass);
8492                         MONO_INST_NEW (cfg, ins, mini_type_to_ldind (cfg, &klass->byval_arg));
8493                         ins->inst_left = load;
8494                         *sp++ = ins;
8495                         type_to_eval_stack_type (cfg, &klass->byval_arg, ins);
8496                         ip += 5;
8497                         break;
8498                 }
8499                 case CEE_LDELEM_I1:
8500                 case CEE_LDELEM_U1:
8501                 case CEE_LDELEM_I2:
8502                 case CEE_LDELEM_U2:
8503                 case CEE_LDELEM_I4:
8504                 case CEE_LDELEM_U4:
8505                 case CEE_LDELEM_I8:
8506                 case CEE_LDELEM_I:
8507                 case CEE_LDELEM_R4:
8508                 case CEE_LDELEM_R8:
8509                 case CEE_LDELEM_REF: {
8510                         MonoInst *load;
8511                         /*
8512                          * translate to:
8513                          * ldind.x (ldelema (array, index))
8514                          * ldelema does the bounds check
8515                          */
8516                         CHECK_STACK (2);
8517                         sp -= 2;
8518                         if (sp [0]->type != STACK_OBJ)
8519                                 UNVERIFIED;
8520                         klass = array_access_to_klass (*ip, sp [0]);
8521                         NEW_LDELEMA (cfg, load, sp, klass);
8522 #ifdef MONO_ARCH_SOFT_FLOAT
8523                         if (*ip == CEE_LDELEM_R4) {
8524                                 int temp;
8525                                 temp = handle_load_float (cfg, bblock, load, ip);
8526                                 NEW_TEMPLOAD (cfg, *sp, temp);
8527                                 sp++;
8528                                 ++ip;
8529                                 break;
8530                         }
8531 #endif
8532                         MONO_INST_NEW (cfg, ins, ldelem_to_ldind [*ip - CEE_LDELEM_I1]);
8533                         ins->inst_left = load;
8534                         *sp++ = ins;
8535                         ins->type = ldind_type [ins->opcode - CEE_LDIND_I1];
8536                         ins->klass = klass;
8537                         ++ip;
8538                         break;
8539                 }
8540                 case CEE_STELEM_I:
8541                 case CEE_STELEM_I1:
8542                 case CEE_STELEM_I2:
8543                 case CEE_STELEM_I4:
8544                 case CEE_STELEM_I8:
8545                 case CEE_STELEM_R4:
8546                 case CEE_STELEM_R8: {
8547                         MonoInst *load;
8548                         /*
8549                          * translate to:
8550                          * stind.x (ldelema (array, index), val)
8551                          * ldelema does the bounds check
8552                          */
8553                         CHECK_STACK (3);
8554                         sp -= 3;
8555                         if (sp [0]->type != STACK_OBJ)
8556                                 UNVERIFIED;
8557                         klass = array_access_to_klass (*ip, sp [0]);
8558                         NEW_LDELEMA (cfg, load, sp, klass);
8559 #ifdef MONO_ARCH_SOFT_FLOAT
8560                         if (*ip == CEE_STELEM_R4) {
8561                                 handle_store_float (cfg, bblock, load, sp [2], ip);
8562                                 ip++;
8563                                 break;
8564                         }
8565 #endif
8566                         MONO_INST_NEW (cfg, ins, stelem_to_stind [*ip - CEE_STELEM_I]);
8567                         ins->inst_left = load;
8568                         ins->inst_right = sp [2];
8569                         ++ip;
8570                         handle_loaded_temps (cfg, bblock, stack_start, sp);
8571                         MONO_ADD_INS (bblock, ins);
8572                         inline_costs += 1;
8573                         break;
8574                 }
8575                 case CEE_STELEM_ANY: {
8576                         MonoInst *load;
8577                         /*
8578                          * translate to:
8579                          * stind.x (ldelema (array, index), val)
8580                          * ldelema does the bounds check
8581                          */
8582                         CHECK_STACK (3);
8583                         sp -= 3;
8584                         if (sp [0]->type != STACK_OBJ)
8585                                 UNVERIFIED;
8586                         CHECK_OPSIZE (5);
8587                         token = read32 (ip + 1);
8588                         klass = mini_get_class (method, token, generic_context);
8589                         CHECK_TYPELOAD (klass);
8590                         mono_class_init (klass);
8591                         if (generic_class_is_reference_type (cfg, klass)) {
8592                                 /* storing a NULL doesn't need any of the complex checks in stelemref */
8593                                 if (sp [2]->opcode == OP_PCONST && sp [2]->inst_p0 == NULL) {
8594                                         MonoInst *load;
8595                                         NEW_LDELEMA (cfg, load, sp, mono_defaults.object_class);
8596                                         MONO_INST_NEW (cfg, ins, CEE_STIND_REF);
8597                                         ins->inst_left = load;
8598                                         ins->inst_right = sp [2];
8599                                         MONO_ADD_INS (bblock, ins);
8600                                 } else {
8601                                         MonoMethod* helper = mono_marshal_get_stelemref ();
8602                                         MonoInst *iargs [3];
8603                                         handle_loaded_temps (cfg, bblock, stack_start, sp);
8604
8605                                         iargs [2] = sp [2];
8606                                         iargs [1] = sp [1];
8607                                         iargs [0] = sp [0];
8608
8609                                         mono_emit_method_call_spilled (cfg, bblock, helper, mono_method_signature (helper), iargs, ip, NULL);
8610                                 }
8611                         } else {
8612                                 NEW_LDELEMA (cfg, load, sp, klass);
8613
8614                                 n = mini_type_to_stind (cfg, &klass->byval_arg);
8615                                 /* FIXME: CEE_STIND_R4 */
8616                                 if (n == CEE_STOBJ)
8617                                         handle_stobj (cfg, bblock, load, sp [2], ip, klass, FALSE, FALSE, TRUE);
8618                                 else {
8619                                         MONO_INST_NEW (cfg, ins, n);
8620                                         ins->inst_left = load;
8621                                         ins->inst_right = sp [2];
8622                                         handle_loaded_temps (cfg, bblock, stack_start, sp);
8623                                         MONO_ADD_INS (bblock, ins);
8624                                 }
8625                         }
8626                         ip += 5;
8627                         inline_costs += 1;
8628                         break;
8629                 }
8630                 case CEE_STELEM_REF: {
8631                         MonoInst *iargs [3];
8632                         MonoMethod* helper = mono_marshal_get_stelemref ();
8633
8634                         CHECK_STACK (3);
8635                         sp -= 3;
8636                         if (sp [0]->type != STACK_OBJ)
8637                                 UNVERIFIED;
8638                         if (sp [2]->type != STACK_OBJ)
8639                                 UNVERIFIED;
8640
8641                         handle_loaded_temps (cfg, bblock, stack_start, sp);
8642
8643                         /* storing a NULL doesn't need any of the complex checks in stelemref */
8644                         if (sp [2]->opcode == OP_PCONST && sp [2]->inst_p0 == NULL) {
8645                                 MonoInst *load;
8646                                 NEW_LDELEMA (cfg, load, sp, mono_defaults.object_class);
8647                                 MONO_INST_NEW (cfg, ins, stelem_to_stind [*ip - CEE_STELEM_I]);
8648                                 ins->inst_left = load;
8649                                 ins->inst_right = sp [2];
8650                                 MONO_ADD_INS (bblock, ins);
8651                         } else {
8652                                 iargs [2] = sp [2];
8653                                 iargs [1] = sp [1];
8654                                 iargs [0] = sp [0];
8655                         
8656                                 mono_emit_method_call_spilled (cfg, bblock, helper, mono_method_signature (helper), iargs, ip, NULL);
8657                                 inline_costs += 1;
8658                         }
8659
8660                         ++ip;
8661                         break;
8662                 }
8663                 case CEE_CKFINITE: {
8664                         MonoInst *store, *temp;
8665                         CHECK_STACK (1);
8666
8667                         /* this instr. can throw exceptions as side effect,
8668                          * so we cant eliminate dead code which contains CKFINITE opdodes.
8669                          * Spilling to memory makes sure that we always perform
8670                          * this check */
8671
8672                         
8673                         MONO_INST_NEW (cfg, ins, OP_CKFINITE);
8674                         ins->inst_left = sp [-1];
8675                         temp = mono_compile_create_var (cfg, &mono_defaults.double_class->byval_arg, OP_LOCAL);
8676
8677                         NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
8678                         MONO_ADD_INS (bblock, store);
8679
8680                         NEW_TEMPLOAD (cfg, sp [-1], temp->inst_c0);
8681                        
8682                         ++ip;
8683                         break;
8684                 }
8685                 case CEE_REFANYVAL:
8686                         CHECK_STACK (1);
8687                         --sp;
8688                         CHECK_OPSIZE (5);
8689                         token = read32 (ip + 1);
8690                         klass = mono_class_get_full (image, token, generic_context);
8691                         CHECK_TYPELOAD (klass);
8692                         mono_class_init (klass);
8693
8694                         /* Needed by the code generated in inssel.brg */
8695                         mono_get_got_var (cfg);
8696
8697                         if (cfg->generic_sharing_context) {
8698                                 context_used = mono_class_check_context_used (klass);
8699                                 if (context_used && cfg->compile_aot)
8700                                         GENERIC_SHARING_FAILURE (*ip);
8701                         }
8702
8703                         if (context_used) {
8704                                 MonoInst *rgctx;
8705
8706                                 MONO_INST_NEW (cfg, ins, OP_REFANYVAL_REG);
8707                                 ins->type = STACK_MP;
8708                                 ins->inst_left = *sp;
8709                                 ins->klass = klass;
8710
8711                                 GET_RGCTX (rgctx, context_used);
8712                                 ins->inst_right = get_runtime_generic_context_ptr (cfg, method, context_used,
8713                                                 bblock, klass, generic_context, rgctx, MONO_RGCTX_INFO_KLASS, ip);
8714                         } else {
8715                                 MONO_INST_NEW (cfg, ins, *ip);
8716                                 ins->type = STACK_MP;
8717                                 ins->inst_left = *sp;
8718                                 ins->klass = klass;
8719                                 ins->inst_newa_class = klass;
8720                         }
8721                         ip += 5;
8722                         *sp++ = ins;
8723                         break;
8724                 case CEE_MKREFANY: {
8725                         MonoInst *loc;
8726
8727                         CHECK_STACK (1);
8728                         --sp;
8729                         CHECK_OPSIZE (5);
8730                         token = read32 (ip + 1);
8731                         klass = mono_class_get_full (image, token, generic_context);
8732                         CHECK_TYPELOAD (klass);
8733                         mono_class_init (klass);
8734
8735                         if (cfg->generic_sharing_context) {
8736                                 context_used = mono_class_check_context_used (klass);
8737                                 if (context_used && cfg->compile_aot)
8738                                         GENERIC_SHARING_FAILURE (CEE_MKREFANY);
8739                         }
8740
8741                         loc = mono_compile_create_var (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL);
8742                         if (context_used) {
8743                                 MonoInst *rgctx, *klass_type, *klass_klass, *loc_load;
8744
8745                                 GET_RGCTX (rgctx, context_used);
8746                                 klass_klass = get_runtime_generic_context_ptr (cfg, method, context_used, bblock, klass,
8747                                                 generic_context, rgctx, MONO_RGCTX_INFO_KLASS, ip);
8748                                 GET_RGCTX (rgctx, context_used);
8749                                 klass_type = get_runtime_generic_context_ptr (cfg, method, context_used, bblock, klass,
8750                                                 generic_context, rgctx, MONO_RGCTX_INFO_TYPE, ip);
8751
8752                                 NEW_TEMPLOADA (cfg, loc_load, loc->inst_c0);
8753
8754                                 MONO_INST_NEW (cfg, ins, OP_MKREFANY_REGS);
8755                                 NEW_GROUP (cfg, ins->inst_left, klass_type, klass_klass);
8756                                 NEW_GROUP (cfg, ins->inst_right, *sp, loc_load);
8757                         } else {
8758                                 MonoInst *klassconst;
8759
8760                                 NEW_PCONST (cfg, klassconst, klass);
8761
8762                                 MONO_INST_NEW (cfg, ins, *ip);
8763                                 NEW_TEMPLOADA (cfg, ins->inst_right, loc->inst_c0);
8764                                 NEW_GROUP (cfg, ins->inst_left, *sp, klassconst);
8765                         }
8766
8767                         MONO_ADD_INS (bblock, ins);
8768
8769                         NEW_TEMPLOAD (cfg, *sp, loc->inst_c0);
8770                         ++sp;
8771                         ip += 5;
8772                         break;
8773                 }
8774                 case CEE_LDTOKEN: {
8775                         gpointer handle;
8776                         MonoClass *handle_class;
8777
8778                         CHECK_STACK_OVF (1);
8779
8780                         CHECK_OPSIZE (5);
8781                         n = read32 (ip + 1);
8782
8783                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
8784                                 handle = mono_method_get_wrapper_data (method, n);
8785                                 handle_class = mono_method_get_wrapper_data (method, n + 1);
8786                                 if (handle_class == mono_defaults.typehandle_class)
8787                                         handle = &((MonoClass*)handle)->byval_arg;
8788                         }
8789                         else {
8790                                 handle = mono_ldtoken (image, n, &handle_class, generic_context);
8791                         }
8792                         if (!handle)
8793                                 goto load_error;
8794                         mono_class_init (handle_class);
8795
8796                         if (cfg->generic_sharing_context) {
8797                                 if (handle_class == mono_defaults.typehandle_class) {
8798                                         /* If we get a MONO_TYPE_CLASS
8799                                            then we need to provide the
8800                                            open type, not an
8801                                            instantiation of it. */
8802                                         if (mono_type_get_type (handle) == MONO_TYPE_CLASS)
8803                                                 context_used = 0;
8804                                         else
8805                                                 context_used = mono_class_check_context_used (mono_class_from_mono_type (handle));
8806                                 } else if (handle_class == mono_defaults.fieldhandle_class)
8807                                         context_used = mono_class_check_context_used (((MonoClassField*)handle)->parent);
8808                                 else if (handle_class == mono_defaults.methodhandle_class)
8809                                         context_used = mono_method_check_context_used (handle);
8810                                 else
8811                                         g_assert_not_reached ();
8812                         }
8813
8814                         if (cfg->opt & MONO_OPT_SHARED) {
8815                                 int temp;
8816                                 MonoInst *res, *store, *addr, *vtvar, *iargs [3];
8817                                 int method_context_used;
8818
8819                                 if (cfg->generic_sharing_context)
8820                                         method_context_used = mono_method_check_context_used (method);
8821                                 else
8822                                         method_context_used = 0;
8823
8824                                 vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL); 
8825
8826                                 NEW_IMAGECONST (cfg, iargs [0], image);
8827                                 NEW_ICONST (cfg, iargs [1], n);
8828                                 if (method_context_used) {
8829                                         MonoInst *rgctx;
8830
8831                                         GET_RGCTX (rgctx, method_context_used);
8832                                         iargs [2] = get_runtime_generic_context_method (cfg, method, method_context_used,
8833                                                         bblock, method,
8834                                                         generic_context, rgctx, MONO_RGCTX_INFO_METHOD, ip);
8835                                         temp = mono_emit_jit_icall (cfg, bblock, mono_ldtoken_wrapper_generic_shared,
8836                                                         iargs, ip);
8837                                 } else {
8838                                         NEW_PCONST (cfg, iargs [2], generic_context);
8839                                         temp = mono_emit_jit_icall (cfg, bblock, mono_ldtoken_wrapper, iargs, ip);
8840                                 }
8841                                 NEW_TEMPLOAD (cfg, res, temp);
8842                                 NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
8843                                 NEW_INDSTORE (cfg, store, addr, res, &mono_defaults.int_class->byval_arg);
8844                                 MONO_ADD_INS (bblock, store);
8845                                 NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
8846                         } else {
8847                                 if ((ip + 10 < end) && ip_in_bb (cfg, bblock, ip + 5) &&
8848                                         handle_class == mono_defaults.typehandle_class &&
8849                                         ((ip [5] == CEE_CALL) || (ip [5] == CEE_CALLVIRT)) && 
8850                                         (cmethod = mini_get_method (cfg, method, read32 (ip + 6), NULL, generic_context)) &&
8851                                         (cmethod->klass == mono_defaults.monotype_class->parent) &&
8852                                         (strcmp (cmethod->name, "GetTypeFromHandle") == 0)) {
8853                                         MonoClass *tclass = mono_class_from_mono_type (handle);
8854                                         mono_class_init (tclass);
8855                                         if (context_used) {
8856                                                 MonoInst *rgctx;
8857
8858                                                 g_assert (!cfg->compile_aot);
8859
8860                                                 GET_RGCTX (rgctx, context_used);
8861                                                 ins = get_runtime_generic_context_ptr (cfg, method, context_used, bblock, tclass,
8862                                                         generic_context, rgctx, MONO_RGCTX_INFO_REFLECTION_TYPE, ip);
8863                                         } else if (cfg->compile_aot) {
8864                                                 /*
8865                                                  * FIXME: We would have to include the context into the
8866                                                  * aot constant too (tests/generic-array-type.2.exe).
8867                                                  */
8868                                                 if (generic_context)
8869                                                         cfg->disable_aot = TRUE;
8870                                                 NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, image, n);
8871                                         } else {
8872                                                 NEW_PCONST (cfg, ins, mono_type_get_object (cfg->domain, handle));
8873                                         }
8874                                         ins->type = STACK_OBJ;
8875                                         ins->klass = cmethod->klass;
8876                                         ip += 5;
8877                                 } else {
8878                                         MonoInst *store, *addr, *vtvar;
8879
8880                                         if (context_used) {
8881                                                         MonoInst *rgctx;
8882
8883                                                 g_assert (!cfg->compile_aot);
8884
8885                                                 GET_RGCTX (rgctx, context_used);
8886                                                 if (handle_class == mono_defaults.typehandle_class) {
8887                                                         ins = get_runtime_generic_context_ptr (cfg, method,
8888                                                                         context_used, bblock,
8889                                                                         mono_class_from_mono_type (handle), generic_context,
8890                                                                         rgctx, MONO_RGCTX_INFO_TYPE, ip);
8891                                                 } else if (handle_class == mono_defaults.methodhandle_class) {
8892                                                         ins = get_runtime_generic_context_method (cfg, method,
8893                                                                         context_used, bblock, handle, generic_context,
8894                                                                         rgctx, MONO_RGCTX_INFO_METHOD, ip);
8895                                                 } else if (handle_class == mono_defaults.fieldhandle_class) {
8896                                                         ins = get_runtime_generic_context_field (cfg, method,
8897                                                                         context_used, bblock, handle, generic_context,
8898                                                                         rgctx, MONO_RGCTX_INFO_CLASS_FIELD, ip);
8899                                                 } else {
8900                                                         g_assert_not_reached ();
8901                                                 }
8902                                         }
8903                                         else if (cfg->compile_aot) {
8904                                                 NEW_LDTOKENCONST (cfg, ins, image, n);
8905                                         } else {
8906                                                 NEW_PCONST (cfg, ins, handle);
8907                                         }
8908                                         vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL);
8909                                         NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
8910                                         NEW_INDSTORE (cfg, store, addr, ins, &mono_defaults.int_class->byval_arg);
8911                                         MONO_ADD_INS (bblock, store);
8912                                         NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
8913                                 }
8914                         }
8915
8916                         *sp++ = ins;
8917                         ip += 5;
8918                         break;
8919                 }
8920                 case CEE_CONV_U2:
8921                 case CEE_CONV_U1:
8922                 case CEE_CONV_I:
8923                         CHECK_STACK (1);
8924                         ADD_UNOP (*ip);
8925                         ip++;
8926                         break;
8927                 case CEE_ADD_OVF:
8928                 case CEE_ADD_OVF_UN:
8929                 case CEE_MUL_OVF:
8930                 case CEE_MUL_OVF_UN:
8931                 case CEE_SUB_OVF:
8932                 case CEE_SUB_OVF_UN:
8933                         CHECK_STACK (2);
8934                         ADD_BINOP (*ip);
8935                         if (mono_find_jit_opcode_emulation (ins->opcode)) {
8936                                 --sp;
8937                                 *sp++ = emit_tree (cfg, bblock, ins, ip + 1);
8938                         }
8939                         ip++;
8940                         break;
8941                 case CEE_ENDFINALLY:
8942                         MONO_INST_NEW (cfg, ins, OP_ENDFINALLY);
8943                         MONO_ADD_INS (bblock, ins);
8944                         ip++;
8945                         start_new_bblock = 1;
8946
8947                         /*
8948                          * Control will leave the method so empty the stack, otherwise
8949                          * the next basic block will start with a nonempty stack.
8950                          */
8951                         while (sp != stack_start) {
8952                                 MONO_INST_NEW (cfg, ins, CEE_POP);
8953                                 sp--;
8954                                 ins->inst_i0 = *sp;
8955                                 MONO_ADD_INS (bblock, ins);
8956                         }
8957                         break;
8958                 case CEE_LEAVE:
8959                 case CEE_LEAVE_S: {
8960                         GList *handlers;
8961
8962                         if (*ip == CEE_LEAVE) {
8963                                 CHECK_OPSIZE (5);
8964                                 target = ip + 5 + (gint32)read32(ip + 1);
8965                         } else {
8966                                 CHECK_OPSIZE (2);
8967                                 target = ip + 2 + (signed char)(ip [1]);
8968                         }
8969
8970                         /* empty the stack */
8971                         while (sp != stack_start) {
8972                                 MONO_INST_NEW (cfg, ins, CEE_POP);
8973                                 sp--;
8974                                 ins->inst_i0 = *sp;
8975                                 MONO_ADD_INS (bblock, ins);
8976                         }
8977
8978                         /* 
8979                          * If this leave statement is in a catch block, check for a
8980                          * pending exception, and rethrow it if necessary.
8981                          */
8982                         for (i = 0; i < header->num_clauses; ++i) {
8983                                 MonoExceptionClause *clause = &header->clauses [i];
8984
8985                                 /* 
8986                                  * Use <= in the final comparison to handle clauses with multiple
8987                                  * leave statements, like in bug #78024.
8988                                  * The ordering of the exception clauses guarantees that we find the
8989                                  * innermost clause.
8990                                  */
8991                                 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)) {
8992                                         int temp;
8993                                         MonoInst *load;
8994
8995                                         NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, clause->handler_offset)->inst_c0);
8996
8997                                         temp = mono_emit_jit_icall (cfg, bblock, mono_thread_get_undeniable_exception, NULL, ip);
8998                                         NEW_TEMPLOAD (cfg, *sp, temp);
8999                                 
9000                                         MONO_INST_NEW (cfg, ins, OP_THROW_OR_NULL);
9001                                         ins->inst_left = *sp;
9002                                         ins->inst_right = load;
9003                                         MONO_ADD_INS (bblock, ins);
9004                                 }
9005                         }
9006
9007                         if ((handlers = mono_find_final_block (cfg, ip, target, MONO_EXCEPTION_CLAUSE_FINALLY))) {
9008                                 GList *tmp;
9009                                 for (tmp = handlers; tmp; tmp = tmp->next) {
9010                                         tblock = tmp->data;
9011                                         link_bblock (cfg, bblock, tblock);
9012                                         MONO_INST_NEW (cfg, ins, OP_CALL_HANDLER);
9013                                         ins->inst_target_bb = tblock;
9014                                         MONO_ADD_INS (bblock, ins);
9015                                 }
9016                                 g_list_free (handlers);
9017                         } 
9018
9019                         MONO_INST_NEW (cfg, ins, OP_BR);
9020                         MONO_ADD_INS (bblock, ins);
9021                         GET_BBLOCK (cfg, tblock, target);
9022                         link_bblock (cfg, bblock, tblock);
9023                         CHECK_BBLOCK (target, ip, tblock);
9024                         ins->inst_target_bb = tblock;
9025                         start_new_bblock = 1;
9026
9027                         if (*ip == CEE_LEAVE)
9028                                 ip += 5;
9029                         else
9030                                 ip += 2;
9031
9032                         break;
9033                 }
9034                 case CEE_STIND_I:
9035                         CHECK_STACK (2);
9036                         MONO_INST_NEW (cfg, ins, *ip);
9037                         sp -= 2;
9038                         handle_loaded_temps (cfg, bblock, stack_start, sp);
9039                         MONO_ADD_INS (bblock, ins);
9040                         ip++;
9041                         ins->inst_i0 = sp [0];
9042                         ins->inst_i1 = sp [1];
9043                         inline_costs += 1;
9044                         break;
9045                 case CEE_CONV_U:
9046                         CHECK_STACK (1);
9047                         ADD_UNOP (*ip);
9048                         ip++;
9049                         break;
9050                 /* trampoline mono specific opcodes */
9051                 case MONO_CUSTOM_PREFIX: {
9052
9053                         g_assert (method->wrapper_type != MONO_WRAPPER_NONE);
9054
9055                         CHECK_OPSIZE (2);
9056                         switch (ip [1]) {
9057
9058                         case CEE_MONO_ICALL: {
9059                                 int temp;
9060                                 gpointer func;
9061                                 MonoJitICallInfo *info;
9062
9063                                 token = read32 (ip + 2);
9064                                 func = mono_method_get_wrapper_data (method, token);
9065                                 info = mono_find_jit_icall_by_addr (func);
9066                                 if (info == NULL){
9067                                         g_error ("An attempt has been made to perform an icall to address %p, "
9068                                                  "but the address has not been registered as an icall\n", info);
9069                                         g_assert_not_reached ();
9070                                 }
9071
9072                                 CHECK_STACK (info->sig->param_count);
9073                                 sp -= info->sig->param_count;
9074
9075                                 temp = mono_emit_jit_icall (cfg, bblock, info->func, sp, ip);
9076                                 if (!MONO_TYPE_IS_VOID (info->sig->ret)) {
9077                                         NEW_TEMPLOAD (cfg, *sp, temp);
9078                                         sp++;
9079                                 }
9080
9081                                 ip += 6;
9082                                 inline_costs += 10 * num_calls++;
9083
9084                                 break;
9085                         }
9086                         case CEE_MONO_LDPTR: {
9087                                 gpointer ptr;
9088
9089                                 CHECK_STACK_OVF (1);
9090                                 CHECK_OPSIZE (6);
9091                                 token = read32 (ip + 2);
9092
9093                                 ptr = mono_method_get_wrapper_data (method, token);
9094                                 if (cfg->compile_aot && (cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE || cfg->method->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE)) {
9095                                         MonoMethod *wrapped = mono_marshal_method_from_wrapper (cfg->method);
9096
9097                                         if (wrapped && ptr != NULL && mono_lookup_internal_call (wrapped) == ptr) {
9098                                                 NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_ICALL_ADDR, wrapped);
9099                                                 *sp++ = ins;
9100                                                 ip += 6;
9101                                                 break;
9102                                         }
9103
9104                                         if ((method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) && (strstr (method->name, "__icall_wrapper_") == method->name)) {
9105                                                 MonoJitICallInfo *callinfo;
9106                                                 const char *icall_name;
9107
9108                                                 icall_name = method->name + strlen ("__icall_wrapper_");
9109                                                 g_assert (icall_name);
9110                                                 callinfo = mono_find_jit_icall_by_name (icall_name);
9111                                                 g_assert (callinfo);
9112
9113                                                 if (ptr == callinfo->func) {
9114                                                         /* Will be transformed into an AOTCONST later */
9115                                                         NEW_PCONST (cfg, ins, ptr);
9116                                                         *sp++ = ins;
9117                                                         ip += 6;
9118                                                         break;
9119                                                 }
9120                                         }
9121                                 }
9122                                 /* FIXME: Generalize this */
9123                                 if (cfg->compile_aot && ptr == mono_thread_interruption_request_flag ()) {
9124                                         NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG, NULL);
9125                                         *sp++ = ins;
9126                                         ip += 6;
9127                                         break;
9128                                 }
9129                                 NEW_PCONST (cfg, ins, ptr);
9130                                 *sp++ = ins;
9131                                 ip += 6;
9132                                 inline_costs += 10 * num_calls++;
9133                                 /* Can't embed random pointers into AOT code */
9134                                 cfg->disable_aot = 1;
9135                                 break;
9136                         }
9137                         case CEE_MONO_ICALL_ADDR: {
9138                                 MonoMethod *cmethod;
9139
9140                                 CHECK_STACK_OVF (1);
9141                                 CHECK_OPSIZE (6);
9142                                 token = read32 (ip + 2);
9143
9144                                 cmethod = mono_method_get_wrapper_data (method, token);
9145
9146                                 g_assert (cfg->compile_aot);
9147
9148                                 NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_ICALL_ADDR, cmethod);
9149                                 *sp++ = ins;
9150                                 ip += 6;
9151                                 break;
9152                         }
9153                         case CEE_MONO_VTADDR:
9154                                 CHECK_STACK (1);
9155                                 --sp;
9156                                 MONO_INST_NEW (cfg, ins, OP_VTADDR);
9157                                 ins->type = STACK_MP;
9158                                 ins->inst_left = *sp;
9159                                 *sp++ = ins;
9160                                 ip += 2;
9161                                 break;
9162                         case CEE_MONO_NEWOBJ: {
9163                                 MonoInst *iargs [2];
9164                                 int temp;
9165                                 CHECK_STACK_OVF (1);
9166                                 CHECK_OPSIZE (6);
9167                                 token = read32 (ip + 2);
9168                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
9169                                 mono_class_init (klass);
9170                                 NEW_DOMAINCONST (cfg, iargs [0]);
9171                                 NEW_CLASSCONST (cfg, iargs [1], klass);
9172                                 temp = mono_emit_jit_icall (cfg, bblock, mono_object_new, iargs, ip);
9173                                 NEW_TEMPLOAD (cfg, *sp, temp);
9174                                 sp++;
9175                                 ip += 6;
9176                                 inline_costs += 10 * num_calls++;
9177                                 break;
9178                         }
9179                         case CEE_MONO_OBJADDR:
9180                                 CHECK_STACK (1);
9181                                 --sp;
9182                                 MONO_INST_NEW (cfg, ins, OP_OBJADDR);
9183                                 ins->type = STACK_MP;
9184                                 ins->inst_left = *sp;
9185                                 *sp++ = ins;
9186                                 ip += 2;
9187                                 break;
9188                         case CEE_MONO_LDNATIVEOBJ:
9189                                 CHECK_STACK (1);
9190                                 CHECK_OPSIZE (6);
9191                                 token = read32 (ip + 2);
9192                                 klass = mono_method_get_wrapper_data (method, token);
9193                                 g_assert (klass->valuetype);
9194                                 mono_class_init (klass);
9195                                 NEW_INDLOAD (cfg, ins, sp [-1], &klass->byval_arg);
9196                                 sp [-1] = ins;
9197                                 ip += 6;
9198                                 break;
9199                         case CEE_MONO_RETOBJ:
9200                                 g_assert (cfg->ret);
9201                                 g_assert (mono_method_signature (method)->pinvoke); 
9202                                 CHECK_STACK (1);
9203                                 --sp;
9204                                 
9205                                 CHECK_OPSIZE (6);
9206                                 token = read32 (ip + 2);    
9207                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
9208
9209                                 NEW_RETLOADA (cfg, ins);
9210                                 handle_stobj (cfg, bblock, ins, *sp, ip, klass, FALSE, TRUE, FALSE);
9211                                 
9212                                 if (sp != stack_start)
9213                                         UNVERIFIED;
9214                                 
9215                                 MONO_INST_NEW (cfg, ins, OP_BR);
9216                                 ins->inst_target_bb = end_bblock;
9217                                 MONO_ADD_INS (bblock, ins);
9218                                 link_bblock (cfg, bblock, end_bblock);
9219                                 start_new_bblock = 1;
9220                                 ip += 6;
9221                                 break;
9222                         case CEE_MONO_CISINST:
9223                         case CEE_MONO_CCASTCLASS: {
9224                                 int token;
9225                                 CHECK_STACK (1);
9226                                 --sp;
9227                                 CHECK_OPSIZE (6);
9228                                 token = read32 (ip + 2);
9229                                 /* Needed by the code generated in inssel.brg */
9230                                 mono_get_got_var (cfg);
9231
9232 #ifdef __i386__
9233                                 /* 
9234                                  * The code generated for CCASTCLASS has too much register pressure
9235                                  * (obj+vtable+ibitmap_byte_reg+iid_reg), leading to the usual
9236                                  * branches-inside-bblocks problem.
9237                                  */
9238                                 cfg->disable_aot = TRUE;
9239 #endif
9240                 
9241                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
9242                                 MONO_INST_NEW (cfg, ins, (ip [1] == CEE_MONO_CISINST) ? OP_CISINST : OP_CCASTCLASS);
9243                                 ins->type = STACK_I4;
9244                                 ins->inst_left = *sp;
9245                                 ins->inst_newa_class = klass;
9246                                 *sp++ = emit_tree (cfg, bblock, ins, ip + 6);
9247                                 ip += 6;
9248                                 break;
9249                         }
9250                         case CEE_MONO_SAVE_LMF:
9251                         case CEE_MONO_RESTORE_LMF:
9252 #ifdef MONO_ARCH_HAVE_LMF_OPS
9253                                 MONO_INST_NEW (cfg, ins, (ip [1] == CEE_MONO_SAVE_LMF) ? OP_SAVE_LMF : OP_RESTORE_LMF);
9254                                 MONO_ADD_INS (bblock, ins);
9255                                 cfg->need_lmf_area = TRUE;
9256 #endif
9257                                 ip += 2;
9258                                 break;
9259                         case CEE_MONO_CLASSCONST:
9260                                 CHECK_STACK_OVF (1);
9261                                 CHECK_OPSIZE (6);
9262                                 token = read32 (ip + 2);
9263                                 NEW_CLASSCONST (cfg, ins, mono_method_get_wrapper_data (method, token));
9264                                 *sp++ = ins;
9265                                 ip += 6;
9266                                 inline_costs += 10 * num_calls++;
9267                                 break;
9268                         case CEE_MONO_NOT_TAKEN:
9269                                 bblock->out_of_line = TRUE;
9270                                 ip += 2;
9271                                 break;
9272                         case CEE_MONO_TLS:
9273                                 CHECK_STACK_OVF (1);
9274                                 CHECK_OPSIZE (6);
9275                                 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
9276                                 ins->inst_offset = (gint32)read32 (ip + 2);
9277                                 ins->type = STACK_PTR;
9278                                 *sp++ = ins;
9279                                 ip += 6;
9280                                 break;
9281                         default:
9282                                 g_error ("opcode 0x%02x 0x%02x not handled", MONO_CUSTOM_PREFIX, ip [1]);
9283                                 break;
9284                         }
9285                         break;
9286                 }
9287                 case CEE_PREFIX1: {
9288                         CHECK_OPSIZE (2);
9289                         switch (ip [1]) {
9290                         case CEE_ARGLIST: {
9291                                 /* somewhat similar to LDTOKEN */
9292                                 MonoInst *addr, *vtvar;
9293                                 CHECK_STACK_OVF (1);
9294                                 vtvar = mono_compile_create_var (cfg, &mono_defaults.argumenthandle_class->byval_arg, OP_LOCAL); 
9295
9296                                 NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
9297                                 MONO_INST_NEW (cfg, ins, OP_ARGLIST);
9298                                 ins->inst_left = addr;
9299                                 MONO_ADD_INS (bblock, ins);
9300                                 NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
9301                                 *sp++ = ins;
9302                                 ip += 2;
9303                                 break;
9304                         }
9305                         case CEE_CEQ:
9306                         case CEE_CGT:
9307                         case CEE_CGT_UN:
9308                         case CEE_CLT:
9309                         case CEE_CLT_UN: {
9310                                 MonoInst *cmp;
9311                                 CHECK_STACK (2);
9312                                 /*
9313                                  * The following transforms:
9314                                  *    CEE_CEQ    into OP_CEQ
9315                                  *    CEE_CGT    into OP_CGT
9316                                  *    CEE_CGT_UN into OP_CGT_UN
9317                                  *    CEE_CLT    into OP_CLT
9318                                  *    CEE_CLT_UN into OP_CLT_UN
9319                                  */
9320                                 MONO_INST_NEW (cfg, cmp, (OP_CEQ - CEE_CEQ) + ip [1]);
9321                                 
9322                                 MONO_INST_NEW (cfg, ins, cmp->opcode);
9323                                 sp -= 2;
9324                                 cmp->inst_i0 = sp [0];
9325                                 cmp->inst_i1 = sp [1];
9326                                 type_from_op (cmp);
9327                                 CHECK_TYPE (cmp);
9328                                 ins->type = STACK_I4;
9329                                 ins->inst_i0 = cmp;
9330 #if MONO_ARCH_SOFT_FLOAT
9331                                 if (sp [0]->type == STACK_R8) {
9332                                         cmp->type = STACK_I4;
9333                                         *sp++ = emit_tree (cfg, bblock, cmp, ip + 2);
9334                                         ip += 2;
9335                                         break;
9336                                 }
9337 #endif
9338                                 if ((sp [0]->type == STACK_I8) || ((sizeof (gpointer) == 8) && ((sp [0]->type == STACK_PTR) || (sp [0]->type == STACK_OBJ) || (sp [0]->type == STACK_MP))))
9339                                         cmp->opcode = OP_LCOMPARE;
9340                                 else
9341                                         cmp->opcode = OP_COMPARE;
9342                                 *sp++ = ins;
9343                                 /* spill it to reduce the expression complexity
9344                                  * and workaround bug 54209 
9345                                  */
9346                                 if (cmp->inst_left->type == STACK_I8) {
9347                                         --sp;
9348                                         *sp++ = emit_tree (cfg, bblock, ins, ip + 2);
9349                                 }
9350                                 ip += 2;
9351                                 break;
9352                         }
9353                         case CEE_LDFTN: {
9354                                 MonoInst *argconst;
9355                                 MonoMethod *cil_method, *ctor_method;
9356                                 int temp;
9357                                 gboolean is_shared = FALSE;
9358
9359                                 CHECK_STACK_OVF (1);
9360                                 CHECK_OPSIZE (6);
9361                                 n = read32 (ip + 2);
9362                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
9363                                 if (!cmethod)
9364                                         goto load_error;
9365                                 mono_class_init (cmethod->klass);
9366
9367                                 if (cfg->generic_sharing_context)
9368                                         context_used = mono_method_check_context_used (cmethod);
9369
9370                                 if (mono_class_generic_sharing_enabled (cmethod->klass)) {
9371                                         if ((cmethod->flags & METHOD_ATTRIBUTE_STATIC) &&
9372                                                         (cmethod->klass->generic_class ||
9373                                                         cmethod->klass->generic_container)) {
9374                                                 is_shared = TRUE;
9375                                         }
9376                                         if (cmethod->is_inflated && mono_method_get_context (cmethod)->method_inst)
9377                                                 is_shared = TRUE;
9378                                 }
9379
9380                                 cil_method = cmethod;
9381                                 if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_method (method, cmethod))
9382                                         METHOD_ACCESS_FAILURE;
9383                                 if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS) {
9384                                         if (check_linkdemand (cfg, method, cmethod, bblock, ip))
9385                                                 INLINE_FAILURE;
9386                                         CHECK_CFG_EXCEPTION;
9387                                 } else if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR) {
9388                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod, bblock, ip);
9389                                 }
9390
9391                                 /* 
9392                                  * Optimize the common case of ldftn+delegate creation
9393                                  */
9394 #if defined(MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE) && !defined(HAVE_WRITE_BARRIERS)
9395                                 /* FIXME: SGEN support */
9396                                 /* FIXME: handle shared static generic methods */
9397                                 /* FIXME: handle this in shared code */
9398                                 if (!is_shared && !context_used && (sp > stack_start) && (ip + 6 + 5 < end) && ip_in_bb (cfg, bblock, ip + 6) && (ip [6] == CEE_NEWOBJ) && (ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context)) && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
9399                                         MonoInst *target_ins;
9400
9401                                         ip += 6;
9402                                         if (cfg->verbose_level > 3)
9403                                                 g_print ("converting (in B%d: stack: %d) %s", bblock->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
9404                                         target_ins = sp [-1];
9405                                         sp --;
9406                                         *sp = handle_delegate_ctor (cfg, bblock, ctor_method->klass, target_ins, cmethod, ip);
9407                                         ip += 5;                                        
9408                                         sp ++;
9409                                         break;
9410                                 }
9411 #endif
9412
9413                                 handle_loaded_temps (cfg, bblock, stack_start, sp);
9414
9415                                 if (context_used) {
9416                                         MonoInst *rgctx;
9417
9418                                         if (is_shared)
9419                                                 cmethod = mono_marshal_get_static_rgctx_invoke (cmethod);
9420
9421                                         GET_RGCTX (rgctx, context_used);
9422                                         argconst = get_runtime_generic_context_method (cfg, method, context_used,
9423                                                         bblock, cmethod,
9424                                                         generic_context, rgctx, MONO_RGCTX_INFO_METHOD, ip);
9425                                 } else if (is_shared) {
9426                                         NEW_METHODCONST (cfg, argconst, mono_marshal_get_static_rgctx_invoke (cmethod));
9427                                 } else {
9428                                         NEW_METHODCONST (cfg, argconst, cmethod);
9429                                 }
9430                                 temp = mono_emit_jit_icall (cfg, bblock, mono_ldftn, &argconst, ip);
9431                                 NEW_TEMPLOAD (cfg, *sp, temp);
9432                                 sp ++;
9433                                 
9434                                 ip += 6;
9435                                 inline_costs += 10 * num_calls++;
9436                                 break;
9437                         }
9438                         case CEE_LDVIRTFTN: {
9439                                 MonoInst *args [2];
9440                                 int temp;
9441
9442                                 CHECK_STACK (1);
9443                                 CHECK_OPSIZE (6);
9444                                 n = read32 (ip + 2);
9445                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
9446                                 if (!cmethod)
9447                                         goto load_error;
9448                                 mono_class_init (cmethod->klass);
9449
9450                                 if (cfg->generic_sharing_context)
9451                                         context_used = mono_method_check_context_used (cmethod);
9452
9453                                 if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS) {
9454                                         if (check_linkdemand (cfg, method, cmethod, bblock, ip))
9455                                                 INLINE_FAILURE;
9456                                         CHECK_CFG_EXCEPTION;
9457                                 } else if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR) {
9458                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod, bblock, ip);
9459                                 }
9460
9461                                 handle_loaded_temps (cfg, bblock, stack_start, sp);
9462
9463                                 --sp;
9464                                 args [0] = *sp;
9465                                 if (context_used) {
9466                                         MonoInst *rgctx;
9467
9468                                         GET_RGCTX (rgctx, context_used);
9469                                         args [1] = get_runtime_generic_context_method (cfg, method, context_used,
9470                                                         bblock, cmethod,
9471                                                         generic_context, rgctx, MONO_RGCTX_INFO_METHOD, ip);
9472                                         temp = mono_emit_jit_icall (cfg, bblock, mono_ldvirtfn_gshared, args, ip);
9473                                 } else {
9474                                         NEW_METHODCONST (cfg, args [1], cmethod);
9475                                         temp = mono_emit_jit_icall (cfg, bblock, mono_ldvirtfn, args, ip);
9476                                 }
9477                                 NEW_TEMPLOAD (cfg, *sp, temp);
9478                                 sp ++;
9479
9480                                 ip += 6;
9481                                 inline_costs += 10 * num_calls++;
9482                                 break;
9483                         }
9484                         case CEE_LDARG:
9485                                 CHECK_STACK_OVF (1);
9486                                 CHECK_OPSIZE (4);
9487                                 n = read16 (ip + 2);
9488                                 CHECK_ARG (n);
9489                                 NEW_ARGLOAD (cfg, ins, n);
9490                                 LDARG_SOFT_FLOAT (cfg, ins, n, ip);
9491                                 *sp++ = ins;
9492                                 ip += 4;
9493                                 break;
9494                         case CEE_LDARGA:
9495                                 CHECK_STACK_OVF (1);
9496                                 CHECK_OPSIZE (4);
9497                                 n = read16 (ip + 2);
9498                                 CHECK_ARG (n);
9499                                 NEW_ARGLOADA (cfg, ins, n);
9500                                 *sp++ = ins;
9501                                 ip += 4;
9502                                 break;
9503                         case CEE_STARG:
9504                                 CHECK_STACK (1);
9505                                 --sp;
9506                                 handle_loaded_temps (cfg, bblock, stack_start, sp);
9507                                 CHECK_OPSIZE (4);
9508                                 n = read16 (ip + 2);
9509                                 CHECK_ARG (n);
9510                                 NEW_ARGSTORE (cfg, ins, n, *sp);
9511                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [n], *sp))
9512                                         UNVERIFIED;
9513                                 STARG_SOFT_FLOAT (cfg, ins, n, ip);
9514                                 if (ins->opcode == CEE_STOBJ) {
9515                                         NEW_ARGLOADA (cfg, ins, n);
9516                                         handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE, FALSE);
9517                                 } else
9518                                         MONO_ADD_INS (bblock, ins);
9519                                 ip += 4;
9520                                 break;
9521                         case CEE_LDLOC:
9522                                 CHECK_STACK_OVF (1);
9523                                 CHECK_OPSIZE (4);
9524                                 n = read16 (ip + 2);
9525                                 CHECK_LOCAL (n);
9526                                 NEW_LOCLOAD (cfg, ins, n);
9527                                 LDLOC_SOFT_FLOAT (cfg, ins, n, ip);
9528                                 *sp++ = ins;
9529                                 ip += 4;
9530                                 break;
9531                         case CEE_LDLOCA:
9532                                 CHECK_STACK_OVF (1);
9533                                 CHECK_OPSIZE (4);
9534                                 n = read16 (ip + 2);
9535                                 CHECK_LOCAL (n);
9536                                 NEW_LOCLOADA (cfg, ins, n);
9537                                 *sp++ = ins;
9538                                 ip += 4;
9539                                 break;
9540                         case CEE_STLOC:
9541                                 CHECK_STACK (1);
9542                                 --sp;
9543                                 CHECK_OPSIZE (4);
9544                                 n = read16 (ip + 2);
9545                                 CHECK_LOCAL (n);
9546                                 handle_loaded_temps (cfg, bblock, stack_start, sp);
9547                                 NEW_LOCSTORE (cfg, ins, n, *sp);
9548                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
9549                                         UNVERIFIED;
9550                                 STLOC_SOFT_FLOAT (cfg, ins, n, ip);
9551                                 if (ins->opcode == CEE_STOBJ) {
9552                                         NEW_LOCLOADA (cfg, ins, n);
9553                                         handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE, FALSE);
9554                                 } else
9555                                         MONO_ADD_INS (bblock, ins);
9556                                 ip += 4;
9557                                 inline_costs += 1;
9558                                 break;
9559                         case CEE_LOCALLOC:
9560                                 CHECK_STACK (1);
9561                                 --sp;
9562                                 if (sp != stack_start) 
9563                                         UNVERIFIED;
9564                                 if (cfg->method != method) 
9565                                         /* 
9566                                          * Inlining this into a loop in a parent could lead to 
9567                                          * stack overflows which is different behavior than the
9568                                          * non-inlined case, thus disable inlining in this case.
9569                                          */
9570                                         goto inline_failure;
9571                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
9572                                 ins->inst_left = *sp;
9573                                 ins->type = STACK_PTR;
9574
9575                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
9576                                 if (header->init_locals)
9577                                         ins->flags |= MONO_INST_INIT;
9578
9579                                 *sp++ = ins;
9580                                 ip += 2;
9581                                 /* FIXME: set init flag if locals init is set in this method */
9582                                 break;
9583                         case CEE_ENDFILTER: {
9584                                 MonoExceptionClause *clause, *nearest;
9585                                 int cc, nearest_num;
9586
9587                                 CHECK_STACK (1);
9588                                 --sp;
9589                                 if ((sp != stack_start) || (sp [0]->type != STACK_I4)) 
9590                                         UNVERIFIED;
9591                                 MONO_INST_NEW (cfg, ins, OP_ENDFILTER);
9592                                 ins->inst_left = *sp;
9593                                 MONO_ADD_INS (bblock, ins);
9594                                 start_new_bblock = 1;
9595                                 ip += 2;
9596
9597                                 nearest = NULL;
9598                                 nearest_num = 0;
9599                                 for (cc = 0; cc < header->num_clauses; ++cc) {
9600                                         clause = &header->clauses [cc];
9601                                         if ((clause->flags & MONO_EXCEPTION_CLAUSE_FILTER) &&
9602                                                 ((ip - header->code) > clause->data.filter_offset && (ip - header->code) <= clause->handler_offset) &&
9603                                             (!nearest || (clause->data.filter_offset < nearest->data.filter_offset))) {
9604                                                 nearest = clause;
9605                                                 nearest_num = cc;
9606                                         }
9607                                 }
9608                                 g_assert (nearest);
9609                                 if ((ip - header->code) != nearest->handler_offset)
9610                                         UNVERIFIED;
9611
9612                                 break;
9613                         }
9614                         case CEE_UNALIGNED_:
9615                                 ins_flag |= MONO_INST_UNALIGNED;
9616                                 /* FIXME: record alignment? we can assume 1 for now */
9617                                 CHECK_OPSIZE (3);
9618                                 ip += 3;
9619                                 break;
9620                         case CEE_VOLATILE_:
9621                                 ins_flag |= MONO_INST_VOLATILE;
9622                                 ip += 2;
9623                                 break;
9624                         case CEE_TAIL_:
9625                                 ins_flag   |= MONO_INST_TAILCALL;
9626                                 cfg->flags |= MONO_CFG_HAS_TAIL;
9627                                 /* Can't inline tail calls at this time */
9628                                 inline_costs += 100000;
9629                                 ip += 2;
9630                                 break;
9631                         case CEE_INITOBJ:
9632                                 CHECK_STACK (1);
9633                                 --sp;
9634                                 CHECK_OPSIZE (6);
9635                                 token = read32 (ip + 2);
9636                                 klass = mini_get_class (method, token, generic_context);
9637                                 CHECK_TYPELOAD (klass);
9638
9639                                 if (generic_class_is_reference_type (cfg, klass)) {
9640                                         MonoInst *store, *load;
9641                                         NEW_PCONST (cfg, load, NULL);
9642                                         load->type = STACK_OBJ;
9643                                         load->klass = klass;
9644                                         MONO_INST_NEW (cfg, store, CEE_STIND_REF);
9645                                         handle_loaded_temps (cfg, bblock, stack_start, sp);
9646                                         MONO_ADD_INS (bblock, store);
9647                                         store->inst_i0 = sp [0];
9648                                         store->inst_i1 = load;
9649                                 } else {
9650                                         handle_initobj (cfg, bblock, *sp, NULL, klass, stack_start, sp);
9651                                 }
9652                                 ip += 6;
9653                                 inline_costs += 1;
9654                                 break;
9655                         case CEE_CONSTRAINED_:
9656                                 /* FIXME: implement */
9657                                 CHECK_OPSIZE (6);
9658                                 token = read32 (ip + 2);
9659                                 constrained_call = mono_class_get_full (image, token, generic_context);
9660                                 CHECK_TYPELOAD (constrained_call);
9661                                 ip += 6;
9662                                 break;
9663                         case CEE_CPBLK:
9664                         case CEE_INITBLK: {
9665                                 MonoInst *iargs [3];
9666                                 CHECK_STACK (3);
9667                                 sp -= 3;
9668                                 if ((cfg->opt & MONO_OPT_INTRINS) && (ip [1] == CEE_CPBLK) && (sp [2]->opcode == OP_ICONST) && ((n = sp [2]->inst_c0) <= sizeof (gpointer) * 5)) {
9669                                         MonoInst *copy;
9670                                         NEW_MEMCPY (cfg, copy, sp [0], sp [1], n, 0);
9671                                         MONO_ADD_INS (bblock, copy);
9672                                         ip += 2;
9673                                         break;
9674                                 }
9675                                 iargs [0] = sp [0];
9676                                 iargs [1] = sp [1];
9677                                 iargs [2] = sp [2];
9678                                 handle_loaded_temps (cfg, bblock, stack_start, sp);
9679                                 if (ip [1] == CEE_CPBLK) {
9680                                         MonoMethod *memcpy_method = get_memcpy_method ();
9681                                         mono_emit_method_call_spilled (cfg, bblock, memcpy_method, memcpy_method->signature, iargs, ip, NULL);
9682                                 } else {
9683                                         MonoMethod *memset_method = get_memset_method ();
9684                                         mono_emit_method_call_spilled (cfg, bblock, memset_method, memset_method->signature, iargs, ip, NULL);
9685                                 }
9686                                 ip += 2;
9687                                 inline_costs += 1;
9688                                 break;
9689                         }
9690                         case CEE_NO_:
9691                                 CHECK_OPSIZE (3);
9692                                 if (ip [2] & 0x1)
9693                                         ins_flag |= MONO_INST_NOTYPECHECK;
9694                                 if (ip [2] & 0x2)
9695                                         ins_flag |= MONO_INST_NORANGECHECK;
9696                                 /* we ignore the no-nullcheck for now since we
9697                                  * really do it explicitly only when doing callvirt->call
9698                                  */
9699                                 ip += 3;
9700                                 break;
9701                         case CEE_RETHROW: {
9702                                 MonoInst *load;
9703                                 int handler_offset = -1;
9704
9705                                 for (i = 0; i < header->num_clauses; ++i) {
9706                                         MonoExceptionClause *clause = &header->clauses [i];
9707                                         if (MONO_OFFSET_IN_HANDLER (clause, ip - header->code) && !(clause->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
9708                                                 handler_offset = clause->handler_offset;
9709                                                 break;
9710                                         }
9711                                 }
9712
9713                                 bblock->flags |= BB_EXCEPTION_UNSAFE;
9714
9715                                 g_assert (handler_offset != -1);
9716
9717                                 NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, handler_offset)->inst_c0);
9718                                 MONO_INST_NEW (cfg, ins, OP_RETHROW);
9719                                 ins->inst_left = load;
9720                                 MONO_ADD_INS (bblock, ins);
9721                                 sp = stack_start;
9722                                 link_bblock (cfg, bblock, end_bblock);
9723                                 start_new_bblock = 1;
9724                                 ip += 2;
9725                                 break;
9726                         }
9727                         case CEE_SIZEOF:
9728                                 CHECK_STACK_OVF (1);
9729                                 CHECK_OPSIZE (6);
9730                                 token = read32 (ip + 2);
9731                                 /* FIXXME: handle generics. */
9732                                 if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC) {
9733                                         MonoType *type = mono_type_create_from_typespec (image, token);
9734                                         token = mono_type_size (type, &ialign);
9735                                 } else {
9736                                         MonoClass *klass = mono_class_get_full (image, token, generic_context);
9737                                         CHECK_TYPELOAD (klass);
9738                                         mono_class_init (klass);
9739                                         token = mono_class_value_size (klass, &align);
9740                                 }
9741                                 NEW_ICONST (cfg, ins, token);
9742                                 *sp++= ins;
9743                                 ip += 6;
9744                                 break;
9745                         case CEE_REFANYTYPE:
9746                                 CHECK_STACK (1);
9747                                 MONO_INST_NEW (cfg, ins, OP_REFANYTYPE);
9748                                 --sp;
9749                                 ins->type = STACK_MP;
9750                                 ins->inst_left = *sp;
9751                                 ins->type = STACK_VTYPE;
9752                                 ins->klass = mono_defaults.typehandle_class;
9753                                 ip += 2;
9754                                 *sp++ = ins;
9755                                 break;
9756                         case CEE_READONLY_:
9757                                 readonly = TRUE;
9758                                 ip += 2;
9759                                 break;
9760                         default:
9761                                 g_error ("opcode 0xfe 0x%02x not handled", ip [1]);
9762                         }
9763                         break;
9764                 }
9765                 default:
9766                         g_error ("opcode 0x%02x not handled", *ip);
9767                 }
9768         }
9769         if (start_new_bblock != 1)
9770                 UNVERIFIED;
9771
9772         bblock->cil_length = ip - bblock->cil_code;
9773         bblock->next_bb = end_bblock;
9774
9775         if (cfg->method == method && cfg->domainvar) {
9776                 MonoInst *store;
9777                 MonoInst *get_domain;
9778                 
9779                 if (! (get_domain = mono_arch_get_domain_intrinsic (cfg))) {
9780                         MonoCallInst *call;
9781                         
9782                         MONO_INST_NEW_CALL (cfg, call, OP_CALL);
9783                         call->signature = helper_sig_domain_get;
9784                         call->inst.type = STACK_PTR;
9785                         call->fptr = mono_domain_get;
9786                         get_domain = (MonoInst*)call;
9787                 }
9788                 
9789                 NEW_TEMPSTORE (cfg, store, cfg->domainvar->inst_c0, get_domain);
9790                 MONO_ADD_INS (init_localsbb, store);
9791         }
9792
9793         if (cfg->method == method && cfg->got_var)
9794                 mono_emit_load_got_addr (cfg);
9795
9796         if (header->init_locals) {
9797                 MonoInst *store;
9798                 cfg->ip = header->code;
9799                 for (i = 0; i < header->num_locals; ++i) {
9800                         MonoType *ptype = header->locals [i];
9801                         int t = ptype->type;
9802                         if (t == MONO_TYPE_VALUETYPE && ptype->data.klass->enumtype)
9803                                 t = ptype->data.klass->enum_basetype->type;
9804                         if (ptype->byref) {
9805                                 NEW_PCONST (cfg, ins, NULL);
9806                                 NEW_LOCSTORE (cfg, store, i, ins);
9807                                 MONO_ADD_INS (init_localsbb, store);
9808                         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
9809                                 NEW_ICONST (cfg, ins, 0);
9810                                 NEW_LOCSTORE (cfg, store, i, ins);
9811                                 MONO_ADD_INS (init_localsbb, store);
9812                         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
9813                                 MONO_INST_NEW (cfg, ins, OP_I8CONST);
9814                                 ins->type = STACK_I8;
9815                                 ins->inst_l = 0;
9816                                 NEW_LOCSTORE (cfg, store, i, ins);
9817                                 MONO_ADD_INS (init_localsbb, store);
9818                         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
9819 #ifdef MONO_ARCH_SOFT_FLOAT
9820                                 /* FIXME: handle init of R4 */
9821 #else
9822                                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
9823                                 ins->type = STACK_R8;
9824                                 ins->inst_p0 = (void*)&r8_0;
9825                                 NEW_LOCSTORE (cfg, store, i, ins);
9826                                 MONO_ADD_INS (init_localsbb, store);
9827 #endif
9828                         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
9829                                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (ptype))) {
9830                                 NEW_LOCLOADA (cfg, ins, i);
9831                                 handle_initobj (cfg, init_localsbb, ins, NULL, mono_class_from_mono_type (ptype), NULL, NULL);
9832                         } else {
9833                                 NEW_PCONST (cfg, ins, NULL);
9834                                 NEW_LOCSTORE (cfg, store, i, ins);
9835                                 MONO_ADD_INS (init_localsbb, store);
9836                         }
9837                 }
9838         }
9839
9840         cfg->ip = NULL;
9841
9842         /* resolve backward branches in the middle of an existing basic block */
9843         for (tmp = bb_recheck; tmp; tmp = tmp->next) {
9844                 bblock = tmp->data;
9845                 /*g_print ("need recheck in %s at IL_%04x\n", method->name, bblock->cil_code - header->code);*/
9846                 tblock = find_previous (cfg->cil_offset_to_bb, header->code_size, start_bblock, bblock->cil_code);
9847                 if (tblock != start_bblock) {
9848                         int l;
9849                         split_bblock (cfg, tblock, bblock);
9850                         l = bblock->cil_code - header->code;
9851                         bblock->cil_length = tblock->cil_length - l;
9852                         tblock->cil_length = l;
9853                 } else {
9854                         g_print ("recheck failed.\n");
9855                 }
9856         }
9857
9858         if (cfg->method == method) {
9859                 MonoBasicBlock *bb;
9860                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
9861                         bb->region = mono_find_block_region (cfg, bb->real_offset);
9862                         if (cfg->spvars)
9863                                 mono_create_spvar_for_region (cfg, bb->region);
9864                         if (cfg->verbose_level > 2)
9865                                 g_print ("REGION BB%d IL_%04x ID_%08X\n", bb->block_num, bb->real_offset, bb->region);
9866                 }
9867         }
9868
9869         g_slist_free (class_inits);
9870         dont_inline = g_list_remove (dont_inline, method);
9871
9872         if (inline_costs < 0) {
9873                 char *mname;
9874
9875                 /* Method is too large */
9876                 mname = mono_method_full_name (method, TRUE);
9877                 cfg->exception_type = MONO_EXCEPTION_INVALID_PROGRAM;
9878                 cfg->exception_message = g_strdup_printf ("Method %s is too complex.", mname);
9879                 g_free (mname);
9880                 return -1;
9881         }
9882
9883         return inline_costs;
9884
9885  exception_exit:
9886         g_assert (cfg->exception_type != MONO_EXCEPTION_NONE);
9887         g_slist_free (class_inits);
9888         dont_inline = g_list_remove (dont_inline, method);
9889         return -1;
9890
9891  inline_failure:
9892         g_slist_free (class_inits);
9893         dont_inline = g_list_remove (dont_inline, method);
9894         return -1;
9895
9896  load_error:
9897         g_slist_free (class_inits);
9898         dont_inline = g_list_remove (dont_inline, method);
9899         cfg->exception_type = MONO_EXCEPTION_TYPE_LOAD;
9900         return -1;
9901
9902  unverified:
9903         g_slist_free (class_inits);
9904         dont_inline = g_list_remove (dont_inline, method);
9905         set_exception_type_from_invalid_il (cfg, method, ip);
9906         return -1;
9907 }
9908
9909 void
9910 mono_print_tree (MonoInst *tree) {
9911         int arity;
9912
9913         if (!tree)
9914                 return;
9915
9916         arity = mono_burg_arity [tree->opcode];
9917
9918         printf (" %s%s", arity?"(":"",  mono_inst_name (tree->opcode));
9919
9920         switch (tree->opcode) {
9921         case OP_ICONST:
9922                 printf ("[%d]", (int)tree->inst_c0);
9923                 break;
9924         case OP_I8CONST:
9925                 printf ("[%lld]", (long long)tree->inst_l);
9926                 break;
9927         case OP_R8CONST:
9928                 printf ("[%f]", *(double*)tree->inst_p0);
9929                 break;
9930         case OP_R4CONST:
9931                 printf ("[%f]", *(float*)tree->inst_p0);
9932                 break;
9933         case OP_ARG:
9934         case OP_LOCAL:
9935                 printf ("[%d]", (int)tree->inst_c0);
9936                 break;
9937         case OP_REGOFFSET:
9938                 if (tree->inst_offset < 0)
9939                         printf ("[-0x%x(%s)]", (int)(-tree->inst_offset), mono_arch_regname (tree->inst_basereg));
9940                 else
9941                         printf ("[0x%x(%s)]", (int)(tree->inst_offset), mono_arch_regname (tree->inst_basereg));
9942                 break;
9943         case OP_REGVAR:
9944                 printf ("[%s]", mono_arch_regname (tree->dreg));
9945                 break;
9946         case CEE_NEWARR:
9947                 printf ("[%s]",  tree->inst_newa_class->name);
9948                 mono_print_tree (tree->inst_newa_len);
9949                 break;
9950         case OP_CALL:
9951         case OP_CALLVIRT:
9952         case OP_FCALL:
9953         case OP_FCALLVIRT:
9954         case OP_LCALL:
9955         case OP_LCALLVIRT:
9956         case OP_VCALL:
9957         case OP_VCALLVIRT:
9958         case OP_VOIDCALL:
9959         case OP_VOIDCALLVIRT:
9960         case OP_TRAMPCALL_VTABLE: {
9961                 MonoCallInst *call = (MonoCallInst*)tree;
9962                 if (call->method)
9963                         printf ("[%s]", call->method->name);
9964                 else if (call->fptr) {
9965                         MonoJitICallInfo *info = mono_find_jit_icall_by_addr (call->fptr);
9966                         if (info)
9967                                 printf ("[%s]", info->name);
9968                 }
9969                 break;
9970         }
9971         case OP_PHI: {
9972                 int i;
9973                 printf ("[%d (", (int)tree->inst_c0);
9974                 for (i = 0; i < tree->inst_phi_args [0]; i++) {
9975                         if (i)
9976                                 printf (", ");
9977                         printf ("%d", tree->inst_phi_args [i + 1]);
9978                 }
9979                 printf (")]");
9980                 break;
9981         }
9982         case OP_RENAME:
9983         case OP_RETARG:
9984         case OP_NOP:
9985         case OP_JMP:
9986         case OP_BREAK:
9987                 break;
9988         case OP_LOAD_MEMBASE:
9989         case OP_LOADI4_MEMBASE:
9990         case OP_LOADU4_MEMBASE:
9991         case OP_LOADU1_MEMBASE:
9992         case OP_LOADI1_MEMBASE:
9993         case OP_LOADU2_MEMBASE:
9994         case OP_LOADI2_MEMBASE:
9995                 printf ("[%s] <- [%s + 0x%x]", mono_arch_regname (tree->dreg), mono_arch_regname (tree->inst_basereg), (int)tree->inst_offset);
9996                 break;
9997         case OP_BR:
9998         case OP_CALL_HANDLER:
9999                 printf ("[B%d]", tree->inst_target_bb->block_num);
10000                 break;
10001         case OP_SWITCH:
10002         case CEE_ISINST:
10003         case CEE_CASTCLASS:
10004         case OP_OUTARG:
10005         case OP_CALL_REG:
10006         case OP_FCALL_REG:
10007         case OP_LCALL_REG:
10008         case OP_VCALL_REG:
10009         case OP_VOIDCALL_REG:
10010                 mono_print_tree (tree->inst_left);
10011                 break;
10012         case CEE_BNE_UN:
10013         case CEE_BEQ:
10014         case CEE_BLT:
10015         case CEE_BLT_UN:
10016         case CEE_BGT:
10017         case CEE_BGT_UN:
10018         case CEE_BGE:
10019         case CEE_BGE_UN:
10020         case CEE_BLE:
10021         case CEE_BLE_UN:
10022                 printf ("[B%dB%d]", tree->inst_true_bb->block_num, tree->inst_false_bb->block_num);
10023                 mono_print_tree (tree->inst_left);
10024                 break;
10025         default:
10026                 if (!mono_arch_print_tree(tree, arity)) {
10027                         if (arity) {
10028                                 mono_print_tree (tree->inst_left);
10029                                 if (arity > 1)
10030                                         mono_print_tree (tree->inst_right);
10031                         }
10032                 }
10033                 break;
10034         }
10035
10036         if (arity)
10037                 printf (")");
10038 }
10039
10040 void
10041 mono_print_tree_nl (MonoInst *tree)
10042 {
10043         mono_print_tree (tree);
10044         printf ("\n");
10045 }
10046
10047 static void
10048 create_helper_signature (void)
10049 {
10050         helper_sig_domain_get = mono_create_icall_signature ("ptr");
10051         helper_sig_class_init_trampoline = mono_create_icall_signature ("void");
10052         helper_sig_generic_class_init_trampoline = mono_create_icall_signature ("void");
10053         helper_sig_rgctx_lazy_fetch_trampoline = mono_create_icall_signature ("ptr ptr");
10054 }
10055
10056 gconstpointer
10057 mono_icall_get_wrapper (MonoJitICallInfo* callinfo)
10058 {
10059         char *name;
10060         MonoMethod *wrapper;
10061         gconstpointer trampoline;
10062         MonoDomain *domain = mono_get_root_domain ();
10063         
10064         if (callinfo->wrapper) {
10065                 return callinfo->wrapper;
10066         }
10067
10068         if (callinfo->trampoline)
10069                 return callinfo->trampoline;
10070
10071         /* 
10072          * We use the lock on the root domain instead of the JIT lock to protect 
10073          * callinfo->trampoline, since we do a lot of stuff inside the critical section.
10074          */
10075         mono_domain_lock (domain);
10076
10077         if (callinfo->trampoline) {
10078                 mono_domain_unlock (domain);
10079                 return callinfo->trampoline;
10080         }
10081
10082         name = g_strdup_printf ("__icall_wrapper_%s", callinfo->name);
10083         wrapper = mono_marshal_get_icall_wrapper (callinfo->sig, name, callinfo->func, check_for_pending_exc);
10084         g_free (name);
10085
10086         trampoline = mono_create_ftnptr (domain, mono_create_jit_trampoline_in_domain (domain, wrapper));
10087         mono_register_jit_icall_wrapper (callinfo, trampoline);
10088
10089         callinfo->trampoline = trampoline;
10090
10091         mono_domain_unlock (domain);
10092         
10093         return callinfo->trampoline;
10094 }
10095
10096 static void
10097 mono_dynamic_code_hash_insert (MonoDomain *domain, MonoMethod *method, MonoJitDynamicMethodInfo *ji)
10098 {
10099         if (!domain->dynamic_code_hash)
10100                 domain->dynamic_code_hash = g_hash_table_new (NULL, NULL);
10101         g_hash_table_insert (domain->dynamic_code_hash, method, ji);
10102 }
10103
10104 static MonoJitDynamicMethodInfo*
10105 mono_dynamic_code_hash_lookup (MonoDomain *domain, MonoMethod *method)
10106 {
10107         MonoJitDynamicMethodInfo *res;
10108
10109         if (domain->dynamic_code_hash)
10110                 res = g_hash_table_lookup (domain->dynamic_code_hash, method);
10111         else
10112                 res = NULL;
10113         return res;
10114 }
10115
10116 typedef struct {
10117         MonoClass *vtype;
10118         GList *active, *inactive;
10119         GSList *slots;
10120 } StackSlotInfo;
10121
10122 static gint 
10123 compare_by_interval_start_pos_func (gconstpointer a, gconstpointer b)
10124 {
10125         MonoMethodVar *v1 = (MonoMethodVar*)a;
10126         MonoMethodVar *v2 = (MonoMethodVar*)b;
10127
10128         if (v1 == v2)
10129                 return 0;
10130         else if (v1->interval->range && v2->interval->range)
10131                 return v1->interval->range->from - v2->interval->range->from;
10132         else if (v1->interval->range)
10133                 return -1;
10134         else
10135                 return 1;
10136 }
10137
10138 #if 0
10139 #define LSCAN_DEBUG(a) do { a; } while (0)
10140 #else
10141 #define LSCAN_DEBUG(a)
10142 #endif
10143
10144 static gint32*
10145 mono_allocate_stack_slots_full2 (MonoCompile *cfg, gboolean backward, guint32 *stack_size, guint32 *stack_align)
10146 {
10147         int i, slot, offset, size;
10148         guint32 align;
10149         MonoMethodVar *vmv;
10150         MonoInst *inst;
10151         gint32 *offsets;
10152         GList *vars = NULL, *l, *unhandled;
10153         StackSlotInfo *scalar_stack_slots, *vtype_stack_slots, *slot_info;
10154         MonoType *t;
10155         int nvtypes;
10156
10157         LSCAN_DEBUG (printf ("Allocate Stack Slots 2 for %s:\n", mono_method_full_name (cfg->method, TRUE)));
10158
10159         scalar_stack_slots = mono_mempool_alloc0 (cfg->mempool, sizeof (StackSlotInfo) * MONO_TYPE_PINNED);
10160         vtype_stack_slots = NULL;
10161         nvtypes = 0;
10162
10163         offsets = mono_mempool_alloc (cfg->mempool, sizeof (gint32) * cfg->num_varinfo);
10164         for (i = 0; i < cfg->num_varinfo; ++i)
10165                 offsets [i] = -1;
10166
10167         for (i = cfg->locals_start; i < cfg->num_varinfo; i++) {
10168                 inst = cfg->varinfo [i];
10169                 vmv = MONO_VARINFO (cfg, i);
10170
10171                 if ((inst->flags & MONO_INST_IS_DEAD) || inst->opcode == OP_REGVAR || inst->opcode == OP_REGOFFSET)
10172                         continue;
10173
10174                 vars = g_list_prepend (vars, vmv);
10175         }
10176
10177         vars = g_list_sort (g_list_copy (vars), compare_by_interval_start_pos_func);
10178
10179         /* Sanity check */
10180         /*
10181         i = 0;
10182         for (unhandled = vars; unhandled; unhandled = unhandled->next) {
10183                 MonoMethodVar *current = unhandled->data;
10184
10185                 if (current->interval->range) {
10186                         g_assert (current->interval->range->from >= i);
10187                         i = current->interval->range->from;
10188                 }
10189         }
10190         */
10191
10192         offset = 0;
10193         *stack_align = 0;
10194         for (unhandled = vars; unhandled; unhandled = unhandled->next) {
10195                 MonoMethodVar *current = unhandled->data;
10196
10197                 vmv = current;
10198                 inst = cfg->varinfo [vmv->idx];
10199
10200                 /* inst->backend.is_pinvoke indicates native sized value types, this is used by the
10201                 * pinvoke wrappers when they call functions returning structures */
10202                 if (inst->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (inst->inst_vtype) && inst->inst_vtype->type != MONO_TYPE_TYPEDBYREF)
10203                         size = mono_class_native_size (inst->inst_vtype->data.klass, &align);
10204                 else {
10205                         int ialign;
10206
10207                         size = mono_type_size (inst->inst_vtype, &ialign);
10208                         align = ialign;
10209                 }
10210
10211                 t = mono_type_get_underlying_type (inst->inst_vtype);
10212                 switch (t->type) {
10213                 case MONO_TYPE_GENERICINST:
10214                         if (!mono_type_generic_inst_is_valuetype (t)) {
10215                                 slot_info = &scalar_stack_slots [t->type];
10216                                 break;
10217                         }
10218                         /* Fall through */
10219                 case MONO_TYPE_VALUETYPE:
10220                         if (!vtype_stack_slots)
10221                                 vtype_stack_slots = mono_mempool_alloc0 (cfg->mempool, sizeof (StackSlotInfo) * 256);
10222                         for (i = 0; i < nvtypes; ++i)
10223                                 if (t->data.klass == vtype_stack_slots [i].vtype)
10224                                         break;
10225                         if (i < nvtypes)
10226                                 slot_info = &vtype_stack_slots [i];
10227                         else {
10228                                 g_assert (nvtypes < 256);
10229                                 vtype_stack_slots [nvtypes].vtype = t->data.klass;
10230                                 slot_info = &vtype_stack_slots [nvtypes];
10231                                 nvtypes ++;
10232                         }
10233                         break;
10234                 case MONO_TYPE_CLASS:
10235                 case MONO_TYPE_OBJECT:
10236                 case MONO_TYPE_ARRAY:
10237                 case MONO_TYPE_SZARRAY:
10238                 case MONO_TYPE_STRING:
10239                 case MONO_TYPE_PTR:
10240                 case MONO_TYPE_I:
10241                 case MONO_TYPE_U:
10242 #if SIZEOF_VOID_P == 4
10243                 case MONO_TYPE_I4:
10244 #else
10245                 case MONO_TYPE_I8:
10246                         /* Share non-float stack slots of the same size */
10247                         slot_info = &scalar_stack_slots [MONO_TYPE_CLASS];
10248                         break;
10249 #endif
10250                 default:
10251                         slot_info = &scalar_stack_slots [t->type];
10252                 }
10253
10254                 slot = 0xffffff;
10255                 if (cfg->comp_done & MONO_COMP_LIVENESS) {
10256                         int pos;
10257                         gboolean changed;
10258
10259                         //printf ("START  %2d %08x %08x\n",  vmv->idx, vmv->range.first_use.abs_pos, vmv->range.last_use.abs_pos);
10260
10261                         if (!current->interval->range) {
10262                                 if (inst->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT))
10263                                         pos = ~0;
10264                                 else {
10265                                         /* Dead */
10266                                         inst->flags |= MONO_INST_IS_DEAD;
10267                                         continue;
10268                                 }
10269                         }
10270                         else
10271                                 pos = current->interval->range->from;
10272
10273                         LSCAN_DEBUG (printf ("process R%d ", inst->dreg));
10274                         if (current->interval->range)
10275                                 LSCAN_DEBUG (mono_linterval_print (current->interval));
10276                         LSCAN_DEBUG (printf ("\n"));
10277
10278                         /* Check for intervals in active which expired or inactive */
10279                         changed = TRUE;
10280                         /* FIXME: Optimize this */
10281                         while (changed) {
10282                                 changed = FALSE;
10283                                 for (l = slot_info->active; l != NULL; l = l->next) {
10284                                         MonoMethodVar *v = (MonoMethodVar*)l->data;
10285
10286                                         if (v->interval->last_range->to < pos) {
10287                                                 slot_info->active = g_list_delete_link (slot_info->active, l);
10288                                                 slot_info->slots = g_slist_prepend_mempool (cfg->mempool, slot_info->slots, GINT_TO_POINTER (offsets [v->idx]));
10289                                                 LSCAN_DEBUG (printf ("Interval R%d has expired, adding 0x%x to slots\n", cfg->varinfo [v->idx]->dreg, offsets [v->idx]));
10290                                                 changed = TRUE;
10291                                                 break;
10292                                         }
10293                                         else if (!mono_linterval_covers (v->interval, pos)) {
10294                                                 slot_info->inactive = g_list_append (slot_info->inactive, v);
10295                                                 slot_info->active = g_list_delete_link (slot_info->active, l);
10296                                                 LSCAN_DEBUG (printf ("Interval R%d became inactive\n", cfg->varinfo [v->idx]->dreg));
10297                                                 changed = TRUE;
10298                                                 break;
10299                                         }
10300                                 }
10301                         }
10302
10303                         /* Check for intervals in inactive which expired or active */
10304                         changed = TRUE;
10305                         /* FIXME: Optimize this */
10306                         while (changed) {
10307                                 changed = FALSE;
10308                                 for (l = slot_info->inactive; l != NULL; l = l->next) {
10309                                         MonoMethodVar *v = (MonoMethodVar*)l->data;
10310
10311                                         if (v->interval->last_range->to < pos) {
10312                                                 slot_info->inactive = g_list_delete_link (slot_info->inactive, l);
10313                                                 // FIXME: Enabling this seems to cause impossible to debug crashes
10314                                                 //slot_info->slots = g_slist_prepend_mempool (cfg->mempool, slot_info->slots, GINT_TO_POINTER (offsets [v->idx]));
10315                                                 LSCAN_DEBUG (printf ("Interval R%d has expired, adding 0x%x to slots\n", cfg->varinfo [v->idx]->dreg, offsets [v->idx]));
10316                                                 changed = TRUE;
10317                                                 break;
10318                                         }
10319                                         else if (mono_linterval_covers (v->interval, pos)) {
10320                                                 slot_info->active = g_list_append (slot_info->active, v);
10321                                                 slot_info->inactive = g_list_delete_link (slot_info->inactive, l);
10322                                                 LSCAN_DEBUG (printf ("\tInterval R%d became active\n", cfg->varinfo [v->idx]->dreg));
10323                                                 changed = TRUE;
10324                                                 break;
10325                                         }
10326                                 }
10327                         }
10328
10329                         /* 
10330                          * This also handles the case when the variable is used in an
10331                          * exception region, as liveness info is not computed there.
10332                          */
10333                         /* 
10334                          * FIXME: All valuetypes are marked as INDIRECT because of LDADDR
10335                          * opcodes.
10336                          */
10337                         if (! (inst->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT))) {
10338                                 if (slot_info->slots) {
10339                                         slot = GPOINTER_TO_INT (slot_info->slots->data);
10340
10341                                         slot_info->slots = slot_info->slots->next;
10342                                 }
10343
10344                                 /* FIXME: We might want to consider the inactive intervals as well if slot_info->slots is empty */
10345
10346                                 slot_info->active = mono_varlist_insert_sorted (cfg, slot_info->active, vmv, TRUE);
10347                         }
10348                 }
10349
10350 #if 0
10351                 {
10352                         static int count = 0;
10353                         count ++;
10354
10355                         if (count == atoi (getenv ("COUNT3")))
10356                                 printf ("LAST: %s\n", mono_method_full_name (cfg->method, TRUE));
10357                         if (count > atoi (getenv ("COUNT3")))
10358                                 slot = 0xffffff;
10359                         else {
10360                                 mono_print_tree_nl (inst);
10361                                 }
10362                 }
10363 #endif
10364
10365                 LSCAN_DEBUG (printf ("R%d %s -> 0x%x\n", inst->dreg, mono_type_full_name (t), slot));
10366
10367                 if (slot == 0xffffff) {
10368                         /*
10369                          * Allways allocate valuetypes to sizeof (gpointer) to allow more
10370                          * efficient copying (and to work around the fact that OP_MEMCPY
10371                          * and OP_MEMSET ignores alignment).
10372                          */
10373                         if (MONO_TYPE_ISSTRUCT (t))
10374                                 align = sizeof (gpointer);
10375
10376                         if (backward) {
10377                                 offset += size;
10378                                 offset += align - 1;
10379                                 offset &= ~(align - 1);
10380                                 slot = offset;
10381                         }
10382                         else {
10383                                 offset += align - 1;
10384                                 offset &= ~(align - 1);
10385                                 slot = offset;
10386                                 offset += size;
10387                         }
10388
10389                         if (*stack_align == 0)
10390                                 *stack_align = align;
10391                 }
10392
10393                 offsets [vmv->idx] = slot;
10394         }
10395         g_list_free (vars);
10396         for (i = 0; i < MONO_TYPE_PINNED; ++i) {
10397                 if (scalar_stack_slots [i].active)
10398                         g_list_free (scalar_stack_slots [i].active);
10399         }
10400         for (i = 0; i < nvtypes; ++i) {
10401                 if (vtype_stack_slots [i].active)
10402                         g_list_free (vtype_stack_slots [i].active);
10403         }
10404
10405         mono_jit_stats.locals_stack_size += offset;
10406
10407         *stack_size = offset;
10408         return offsets;
10409 }
10410
10411 /*
10412  *  mono_allocate_stack_slots_full:
10413  *
10414  *  Allocate stack slots for all non register allocated variables using a
10415  * linear scan algorithm.
10416  * Returns: an array of stack offsets.
10417  * STACK_SIZE is set to the amount of stack space needed.
10418  * STACK_ALIGN is set to the alignment needed by the locals area.
10419  */
10420 gint32*
10421 mono_allocate_stack_slots_full (MonoCompile *cfg, gboolean backward, guint32 *stack_size, guint32 *stack_align)
10422 {
10423         int i, slot, offset, size;
10424         guint32 align;
10425         MonoMethodVar *vmv;
10426         MonoInst *inst;
10427         gint32 *offsets;
10428         GList *vars = NULL, *l;
10429         StackSlotInfo *scalar_stack_slots, *vtype_stack_slots, *slot_info;
10430         MonoType *t;
10431         int nvtypes;
10432
10433         if ((cfg->num_varinfo > 0) && MONO_VARINFO (cfg, 0)->interval)
10434                 return mono_allocate_stack_slots_full2 (cfg, backward, stack_size, stack_align);
10435
10436         scalar_stack_slots = mono_mempool_alloc0 (cfg->mempool, sizeof (StackSlotInfo) * MONO_TYPE_PINNED);
10437         vtype_stack_slots = NULL;
10438         nvtypes = 0;
10439
10440         offsets = mono_mempool_alloc (cfg->mempool, sizeof (gint32) * cfg->num_varinfo);
10441         for (i = 0; i < cfg->num_varinfo; ++i)
10442                 offsets [i] = -1;
10443
10444         for (i = cfg->locals_start; i < cfg->num_varinfo; i++) {
10445                 inst = cfg->varinfo [i];
10446                 vmv = MONO_VARINFO (cfg, i);
10447
10448                 if ((inst->flags & MONO_INST_IS_DEAD) || inst->opcode == OP_REGVAR || inst->opcode == OP_REGOFFSET)
10449                         continue;
10450
10451                 vars = g_list_prepend (vars, vmv);
10452         }
10453
10454         vars = mono_varlist_sort (cfg, vars, 0);
10455         offset = 0;
10456         *stack_align = 0;
10457         for (l = vars; l; l = l->next) {
10458                 vmv = l->data;
10459                 inst = cfg->varinfo [vmv->idx];
10460
10461                 /* inst->backend.is_pinvoke indicates native sized value types, this is used by the
10462                 * pinvoke wrappers when they call functions returning structures */
10463                 if (inst->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (inst->inst_vtype) && inst->inst_vtype->type != MONO_TYPE_TYPEDBYREF)
10464                         size = mono_class_native_size (inst->inst_vtype->data.klass, &align);
10465                 else {
10466                         int ialign;
10467
10468                         size = mono_type_size (inst->inst_vtype, &ialign);
10469                         align = ialign;
10470                 }
10471
10472                 t = mono_type_get_underlying_type (inst->inst_vtype);
10473                 if (t->byref) {
10474                         slot_info = &scalar_stack_slots [MONO_TYPE_I];
10475                 } else {
10476                         switch (t->type) {
10477                         case MONO_TYPE_GENERICINST:
10478                                 if (!mono_type_generic_inst_is_valuetype (t)) {
10479                                         slot_info = &scalar_stack_slots [t->type];
10480                                         break;
10481                                 }
10482                                 /* Fall through */
10483                         case MONO_TYPE_VALUETYPE:
10484                                 if (!vtype_stack_slots)
10485                                         vtype_stack_slots = mono_mempool_alloc0 (cfg->mempool, sizeof (StackSlotInfo) * 256);
10486                                 for (i = 0; i < nvtypes; ++i)
10487                                         if (t->data.klass == vtype_stack_slots [i].vtype)
10488                                                 break;
10489                                 if (i < nvtypes)
10490                                         slot_info = &vtype_stack_slots [i];
10491                                 else {
10492                                         g_assert (nvtypes < 256);
10493                                         vtype_stack_slots [nvtypes].vtype = t->data.klass;
10494                                         slot_info = &vtype_stack_slots [nvtypes];
10495                                         nvtypes ++;
10496                                 }
10497                                 break;
10498                         case MONO_TYPE_CLASS:
10499                         case MONO_TYPE_OBJECT:
10500                         case MONO_TYPE_ARRAY:
10501                         case MONO_TYPE_SZARRAY:
10502                         case MONO_TYPE_STRING:
10503                         case MONO_TYPE_PTR:
10504                         case MONO_TYPE_I:
10505                         case MONO_TYPE_U:
10506 #if SIZEOF_VOID_P == 4
10507                         case MONO_TYPE_I4:
10508 #else
10509                         case MONO_TYPE_I8:
10510 #endif
10511                                 /* Share non-float stack slots of the same size */
10512                                 slot_info = &scalar_stack_slots [MONO_TYPE_CLASS];
10513                                 break;
10514                         default:
10515                                 slot_info = &scalar_stack_slots [t->type];
10516                         }
10517                 }
10518
10519                 slot = 0xffffff;
10520                 if (cfg->comp_done & MONO_COMP_LIVENESS) {
10521                         //printf ("START  %2d %08x %08x\n",  vmv->idx, vmv->range.first_use.abs_pos, vmv->range.last_use.abs_pos);
10522                         
10523                         /* expire old intervals in active */
10524                         while (slot_info->active) {
10525                                 MonoMethodVar *amv = (MonoMethodVar *)slot_info->active->data;
10526
10527                                 if (amv->range.last_use.abs_pos > vmv->range.first_use.abs_pos)
10528                                         break;
10529
10530                                 //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);
10531
10532                                 slot_info->active = g_list_delete_link (slot_info->active, slot_info->active);
10533                                 slot_info->slots = g_slist_prepend_mempool (cfg->mempool, slot_info->slots, GINT_TO_POINTER (offsets [amv->idx]));
10534                         }
10535
10536                         /* 
10537                          * This also handles the case when the variable is used in an
10538                          * exception region, as liveness info is not computed there.
10539                          */
10540                         /* 
10541                          * FIXME: All valuetypes are marked as INDIRECT because of LDADDR
10542                          * opcodes.
10543                          */
10544                         if (! (inst->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT))) {
10545                                 if (slot_info->slots) {
10546                                         slot = GPOINTER_TO_INT (slot_info->slots->data);
10547
10548                                         slot_info->slots = slot_info->slots->next;
10549                                 }
10550
10551                                 slot_info->active = mono_varlist_insert_sorted (cfg, slot_info->active, vmv, TRUE);
10552                         }
10553                 }
10554
10555                 {
10556                         static int count = 0;
10557                         count ++;
10558
10559                         /*
10560                         if (count == atoi (getenv ("COUNT")))
10561                                 printf ("LAST: %s\n", mono_method_full_name (cfg->method, TRUE));
10562                         if (count > atoi (getenv ("COUNT")))
10563                                 slot = 0xffffff;
10564                         else {
10565                                 mono_print_tree_nl (inst);
10566                                 }
10567                         */
10568                 }
10569
10570                 if (cfg->disable_reuse_stack_slots)
10571                         slot = 0xffffff;
10572
10573                 if (slot == 0xffffff) {
10574                         /*
10575                          * Allways allocate valuetypes to sizeof (gpointer) to allow more
10576                          * efficient copying (and to work around the fact that OP_MEMCPY
10577                          * and OP_MEMSET ignores alignment).
10578                          */
10579                         if (MONO_TYPE_ISSTRUCT (t))
10580                                 align = sizeof (gpointer);
10581
10582                         if (backward) {
10583                                 offset += size;
10584                                 offset += align - 1;
10585                                 offset &= ~(align - 1);
10586                                 slot = offset;
10587                         }
10588                         else {
10589                                 offset += align - 1;
10590                                 offset &= ~(align - 1);
10591                                 slot = offset;
10592                                 offset += size;
10593                         }
10594
10595                         if (*stack_align == 0)
10596                                 *stack_align = align;
10597                 }
10598
10599                 offsets [vmv->idx] = slot;
10600         }
10601         g_list_free (vars);
10602         for (i = 0; i < MONO_TYPE_PINNED; ++i) {
10603                 if (scalar_stack_slots [i].active)
10604                         g_list_free (scalar_stack_slots [i].active);
10605         }
10606         for (i = 0; i < nvtypes; ++i) {
10607                 if (vtype_stack_slots [i].active)
10608                         g_list_free (vtype_stack_slots [i].active);
10609         }
10610
10611         mono_jit_stats.locals_stack_size += offset;
10612
10613         *stack_size = offset;
10614         return offsets;
10615 }
10616
10617 gint32*
10618 mono_allocate_stack_slots (MonoCompile *m, guint32 *stack_size, guint32 *stack_align)
10619 {
10620         return mono_allocate_stack_slots_full (m, TRUE, stack_size, stack_align);
10621 }
10622
10623 void
10624 mono_register_opcode_emulation (int opcode, const char *name, const char *sigstr, gpointer func, gboolean no_throw)
10625 {
10626         MonoJitICallInfo *info;
10627         MonoMethodSignature *sig = mono_create_icall_signature (sigstr);
10628
10629         if (!emul_opcode_map)
10630                 emul_opcode_map = g_new0 (MonoJitICallInfo*, OP_LAST + 1);
10631
10632         g_assert (!sig->hasthis);
10633         g_assert (sig->param_count < 3);
10634
10635         info = mono_register_jit_icall (func, name, sig, no_throw);
10636
10637         emul_opcode_map [opcode] = info;
10638 }
10639
10640 static void
10641 register_icall (gpointer func, const char *name, const char *sigstr, gboolean save)
10642 {
10643         MonoMethodSignature *sig;
10644
10645         if (sigstr)
10646                 sig = mono_create_icall_signature (sigstr);
10647         else
10648                 sig = NULL;
10649
10650         mono_register_jit_icall (func, name, sig, save);
10651 }
10652
10653 static void
10654 decompose_foreach (MonoInst *tree, gpointer data) 
10655 {
10656         static MonoJitICallInfo *newarr_info = NULL;
10657         static MonoJitICallInfo *newarr_specific_info = NULL;
10658         MonoJitICallInfo *info;
10659         int i;
10660
10661         switch (tree->opcode) {
10662         case CEE_NEWARR: {
10663                 MonoCompile *cfg = data;
10664                 MonoInst *iargs [3];
10665
10666                 if (!newarr_info) {
10667                         newarr_info = mono_find_jit_icall_by_addr (mono_array_new);
10668                         g_assert (newarr_info);
10669                         newarr_specific_info = mono_find_jit_icall_by_addr (mono_array_new_specific);
10670                         g_assert (newarr_specific_info);
10671                 }
10672
10673                 if (cfg->opt & MONO_OPT_SHARED) {
10674                         NEW_DOMAINCONST (cfg, iargs [0]);
10675                         NEW_CLASSCONST (cfg, iargs [1], tree->inst_newa_class);
10676                         iargs [2] = tree->inst_newa_len;
10677
10678                         info = newarr_info;
10679                 }
10680                 else {
10681                         MonoVTable *vtable = mono_class_vtable (cfg->domain, mono_array_class_get (tree->inst_newa_class, 1));
10682
10683                         g_assert (vtable);
10684                         NEW_VTABLECONST (cfg, iargs [0], vtable);
10685                         iargs [1] = tree->inst_newa_len;
10686
10687                         info = newarr_specific_info;
10688                 }
10689
10690                 mono_emulate_opcode (cfg, tree, iargs, info);
10691
10692                 /* Need to decompose arguments after the the opcode is decomposed */
10693                 for (i = 0; i < info->sig->param_count; ++i)
10694                         dec_foreach (iargs [i], cfg);
10695                 break;
10696         }
10697 #ifdef MONO_ARCH_SOFT_FLOAT
10698         case OP_FBEQ:
10699         case OP_FBGE:
10700         case OP_FBGT:
10701         case OP_FBLE:
10702         case OP_FBLT:
10703         case OP_FBNE_UN:
10704         case OP_FBGE_UN:
10705         case OP_FBGT_UN:
10706         case OP_FBLE_UN:
10707         case OP_FBLT_UN: {
10708                 if ((info = mono_find_jit_opcode_emulation (tree->opcode))) {
10709                         MonoCompile *cfg = data;
10710                         MonoInst *iargs [2];
10711                 
10712                         iargs [0] = tree->inst_i0;
10713                         iargs [1] = tree->inst_i1;
10714                 
10715                         mono_emulate_opcode (cfg, tree, iargs, info);
10716
10717                         dec_foreach (iargs [0], cfg);
10718                         dec_foreach (iargs [1], cfg);
10719                         break;
10720                 } else {
10721                         g_assert_not_reached ();
10722                 }
10723                 break;
10724         }
10725         case OP_FCEQ:
10726         case OP_FCGT:
10727         case OP_FCGT_UN:
10728         case OP_FCLT:
10729         case OP_FCLT_UN: {
10730                 if ((info = mono_find_jit_opcode_emulation (tree->opcode))) {
10731                         MonoCompile *cfg = data;
10732                         MonoInst *iargs [2];
10733
10734                         /* the args are in the compare opcode ... */
10735                         iargs [0] = tree->inst_i0;
10736                         iargs [1] = tree->inst_i1;
10737                 
10738                         mono_emulate_opcode (cfg, tree, iargs, info);
10739
10740                         dec_foreach (iargs [0], cfg);
10741                         dec_foreach (iargs [1], cfg);
10742                         break;
10743                 } else {
10744                         g_assert_not_reached ();
10745                 }
10746                 break;
10747         }
10748 #endif
10749
10750         default:
10751                 break;
10752         }
10753 }
10754
10755 void
10756 mono_inst_foreach (MonoInst *tree, MonoInstFunc func, gpointer data) {
10757
10758         switch (mono_burg_arity [tree->opcode]) {
10759         case 0: break;
10760         case 1: 
10761                 mono_inst_foreach (tree->inst_left, func, data);
10762                 break;
10763         case 2: 
10764                 mono_inst_foreach (tree->inst_left, func, data);
10765                 mono_inst_foreach (tree->inst_right, func, data);
10766                 break;
10767         default:
10768                 g_assert_not_reached ();
10769         }
10770         func (tree, data);
10771 }
10772
10773 G_GNUC_UNUSED
10774 static void
10775 mono_print_bb_code (MonoBasicBlock *bb)
10776 {
10777         MonoInst *c;
10778
10779         MONO_BB_FOR_EACH_INS (bb, c) {
10780                 mono_print_tree (c);
10781                 g_print ("\n");
10782         }
10783 }
10784
10785 static void
10786 print_dfn (MonoCompile *cfg) {
10787         int i, j;
10788         char *code;
10789         MonoBasicBlock *bb;
10790         MonoInst *c;
10791
10792         g_print ("IR code for method %s\n", mono_method_full_name (cfg->method, TRUE));
10793
10794         for (i = 0; i < cfg->num_bblocks; ++i) {
10795                 bb = cfg->bblocks [i];
10796                 /*if (bb->cil_code) {
10797                         char* code1, *code2;
10798                         code1 = mono_disasm_code_one (NULL, cfg->method, bb->cil_code, NULL);
10799                         if (bb->last_ins->cil_code)
10800                                 code2 = mono_disasm_code_one (NULL, cfg->method, bb->last_ins->cil_code, NULL);
10801                         else
10802                                 code2 = g_strdup ("");
10803
10804                         code1 [strlen (code1) - 1] = 0;
10805                         code = g_strdup_printf ("%s -> %s", code1, code2);
10806                         g_free (code1);
10807                         g_free (code2);
10808                 } else*/
10809                         code = g_strdup ("\n");
10810                 g_print ("\nBB%d (%d) (len: %d): %s", bb->block_num, i, bb->cil_length, code);
10811                 MONO_BB_FOR_EACH_INS (bb, c) {
10812                         if (cfg->new_ir) {
10813                                 mono_print_ins_index (-1, c);
10814                         } else {
10815                                 mono_print_tree (c);
10816                                 g_print ("\n");
10817                         }
10818                 }
10819
10820                 g_print ("\tprev:");
10821                 for (j = 0; j < bb->in_count; ++j) {
10822                         g_print (" BB%d", bb->in_bb [j]->block_num);
10823                 }
10824                 g_print ("\t\tsucc:");
10825                 for (j = 0; j < bb->out_count; ++j) {
10826                         g_print (" BB%d", bb->out_bb [j]->block_num);
10827                 }
10828                 g_print ("\n\tidom: BB%d\n", bb->idom? bb->idom->block_num: -1);
10829
10830                 if (bb->idom)
10831                         g_assert (mono_bitset_test_fast (bb->dominators, bb->idom->dfn));
10832
10833                 if (bb->dominators)
10834                         mono_blockset_print (cfg, bb->dominators, "\tdominators", bb->idom? bb->idom->dfn: -1);
10835                 if (bb->dfrontier)
10836                         mono_blockset_print (cfg, bb->dfrontier, "\tdfrontier", -1);
10837                 g_free (code);
10838         }
10839
10840         g_print ("\n");
10841 }
10842
10843 void
10844 mono_bblock_add_inst (MonoBasicBlock *bb, MonoInst *inst)
10845 {
10846         MONO_ADD_INS (bb, inst);
10847 }
10848
10849 void
10850 mono_bblock_insert_after_ins (MonoBasicBlock *bb, MonoInst *ins, MonoInst *ins_to_insert)
10851 {
10852         if (ins == NULL) {
10853                 ins = bb->code;
10854                 bb->code = ins_to_insert;
10855
10856                 /* Link with next */
10857                 ins_to_insert->next = ins;
10858                 if (ins)
10859                         ins->prev = ins_to_insert;
10860
10861                 if (bb->last_ins == NULL)
10862                         bb->last_ins = ins_to_insert;
10863         } else {
10864                 /* Link with next */
10865                 ins_to_insert->next = ins->next;
10866                 if (ins->next)
10867                         ins->next->prev = ins_to_insert;
10868
10869                 /* Link with previous */
10870                 ins->next = ins_to_insert;
10871                 ins_to_insert->prev = ins;
10872
10873                 if (bb->last_ins == ins)
10874                         bb->last_ins = ins_to_insert;
10875         }
10876 }
10877
10878 void
10879 mono_bblock_insert_before_ins (MonoBasicBlock *bb, MonoInst *ins, MonoInst *ins_to_insert)
10880 {
10881         if (ins == NULL) {
10882                 NOT_IMPLEMENTED;
10883                 ins = bb->code;
10884                 bb->code = ins_to_insert;
10885                 ins_to_insert->next = ins;
10886                 if (bb->last_ins == NULL)
10887                         bb->last_ins = ins_to_insert;
10888         } else {
10889                 /* Link with previous */
10890                 if (ins->prev)
10891                         ins->prev->next = ins_to_insert;
10892                 ins_to_insert->prev = ins->prev;
10893
10894                 /* Link with next */
10895                 ins->prev = ins_to_insert;
10896                 ins_to_insert->next = ins;
10897
10898                 if (bb->code == ins)
10899                         bb->code = ins_to_insert;
10900         }
10901 }
10902
10903 /*
10904  * mono_verify_bblock:
10905  *
10906  *   Verify that the next and prev pointers are consistent inside the instructions in BB.
10907  */
10908 void
10909 mono_verify_bblock (MonoBasicBlock *bb)
10910 {
10911         MonoInst *ins, *prev;
10912
10913         prev = NULL;
10914         for (ins = bb->code; ins; ins = ins->next) {
10915                 g_assert (ins->prev == prev);
10916                 prev = ins;
10917         }
10918         if (bb->last_ins)
10919                 g_assert (!bb->last_ins->next);
10920 }
10921
10922 /*
10923  * mono_verify_cfg:
10924  *
10925  *   Perform consistency checks on the JIT data structures and the IR
10926  */
10927 void
10928 mono_verify_cfg (MonoCompile *cfg)
10929 {
10930         MonoBasicBlock *bb;
10931
10932         for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
10933                 mono_verify_bblock (bb);
10934 }
10935
10936 void
10937 mono_destroy_compile (MonoCompile *cfg)
10938 {
10939         //mono_mempool_stats (cfg->mempool);
10940         mono_free_loop_info (cfg);
10941         if (cfg->rs)
10942                 mono_regstate_free (cfg->rs);
10943         if (cfg->spvars)
10944                 g_hash_table_destroy (cfg->spvars);
10945         if (cfg->exvars)
10946                 g_hash_table_destroy (cfg->exvars);
10947         mono_mempool_destroy (cfg->mempool);
10948         g_list_free (cfg->ldstr_list);
10949         g_hash_table_destroy (cfg->token_info_hash);
10950         if (cfg->abs_patches)
10951                 g_hash_table_destroy (cfg->abs_patches);
10952
10953         g_free (cfg->varinfo);
10954         g_free (cfg->vars);
10955         g_free (cfg->exception_message);
10956         g_free (cfg);
10957 }
10958
10959 #ifdef HAVE_KW_THREAD
10960 static __thread gpointer mono_lmf_addr MONO_TLS_FAST;
10961 #ifdef MONO_ARCH_ENABLE_MONO_LMF_VAR
10962 /* 
10963  * When this is defined, the current lmf is stored in this tls variable instead of in 
10964  * jit_tls->lmf.
10965  */
10966 static __thread gpointer mono_lmf MONO_TLS_FAST;
10967 #endif
10968 #endif
10969
10970 guint32
10971 mono_get_jit_tls_key (void)
10972 {
10973         return mono_jit_tls_id;
10974 }
10975
10976 gint32
10977 mono_get_jit_tls_offset (void)
10978 {
10979 #ifdef HAVE_KW_THREAD
10980         int offset;
10981         MONO_THREAD_VAR_OFFSET (mono_jit_tls, offset);
10982         return offset;
10983 #else
10984         return -1;
10985 #endif
10986 }
10987
10988 gint32
10989 mono_get_lmf_tls_offset (void)
10990 {
10991 #if defined(HAVE_KW_THREAD) && defined(MONO_ARCH_ENABLE_MONO_LMF_VAR)
10992         int offset;
10993         MONO_THREAD_VAR_OFFSET(mono_lmf,offset);
10994         return offset;
10995 #else
10996         return -1;
10997 #endif
10998 }
10999
11000 gint32
11001 mono_get_lmf_addr_tls_offset (void)
11002 {
11003         int offset;
11004         MONO_THREAD_VAR_OFFSET(mono_lmf_addr,offset);
11005         return offset;
11006 }
11007
11008 MonoLMF *
11009 mono_get_lmf (void)
11010 {
11011 #if defined(HAVE_KW_THREAD) && defined(MONO_ARCH_ENABLE_MONO_LMF_VAR)
11012         return mono_lmf;
11013 #else
11014         MonoJitTlsData *jit_tls;
11015
11016         if ((jit_tls = TlsGetValue (mono_jit_tls_id)))
11017                 return jit_tls->lmf;
11018
11019         g_assert_not_reached ();
11020         return NULL;
11021 #endif
11022 }
11023
11024 MonoLMF **
11025 mono_get_lmf_addr (void)
11026 {
11027 #ifdef HAVE_KW_THREAD
11028         return mono_lmf_addr;
11029 #else
11030         MonoJitTlsData *jit_tls;
11031
11032         if ((jit_tls = TlsGetValue (mono_jit_tls_id)))
11033                 return &jit_tls->lmf;
11034
11035         g_assert_not_reached ();
11036         return NULL;
11037 #endif
11038 }
11039
11040 /* Called by native->managed wrappers */
11041 void
11042 mono_jit_thread_attach (MonoDomain *domain)
11043 {
11044 #ifdef HAVE_KW_THREAD
11045         if (!mono_lmf_addr) {
11046                 mono_thread_attach (domain);
11047         }
11048 #else
11049         if (!TlsGetValue (mono_jit_tls_id))
11050                 mono_thread_attach (domain);
11051 #endif
11052         if (mono_domain_get () != domain)
11053                 mono_domain_set (domain, TRUE);
11054 }       
11055
11056 /**
11057  * mono_thread_abort:
11058  * @obj: exception object
11059  *
11060  * abort the thread, print exception information and stack trace
11061  */
11062 static void
11063 mono_thread_abort (MonoObject *obj)
11064 {
11065         /* MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id); */
11066         
11067         /* handle_remove should be eventually called for this thread, too
11068         g_free (jit_tls);*/
11069
11070         if ((mono_runtime_unhandled_exception_policy_get () == MONO_UNHANLED_POLICY_LEGACY) ||
11071                         (obj->vtable->klass == mono_defaults.threadabortexception_class)) {
11072                 mono_thread_exit ();
11073         } else {
11074                 exit (mono_environment_exitcode_get ());
11075         }
11076 }
11077
11078 static void*
11079 setup_jit_tls_data (gpointer stack_start, gpointer abort_func)
11080 {
11081         MonoJitTlsData *jit_tls;
11082         MonoLMF *lmf;
11083
11084         jit_tls = TlsGetValue (mono_jit_tls_id);
11085         if (jit_tls)
11086                 return jit_tls;
11087
11088         jit_tls = g_new0 (MonoJitTlsData, 1);
11089
11090         TlsSetValue (mono_jit_tls_id, jit_tls);
11091
11092 #ifdef HAVE_KW_THREAD
11093         mono_jit_tls = jit_tls;
11094 #endif
11095
11096         jit_tls->abort_func = abort_func;
11097         jit_tls->end_of_stack = stack_start;
11098
11099         lmf = g_new0 (MonoLMF, 1);
11100 #ifdef MONO_ARCH_INIT_TOP_LMF_ENTRY
11101         MONO_ARCH_INIT_TOP_LMF_ENTRY (lmf);
11102 #else
11103         lmf->ebp = -1;
11104 #endif
11105
11106         jit_tls->first_lmf = lmf;
11107
11108 #if defined(HAVE_KW_THREAD) && defined(MONO_ARCH_ENABLE_MONO_LMF_VAR)
11109         /* jit_tls->lmf is unused */
11110         mono_lmf = lmf;
11111         mono_lmf_addr = &mono_lmf;
11112 #else
11113 #if defined(HAVE_KW_THREAD)
11114         mono_lmf_addr = &jit_tls->lmf;  
11115 #endif
11116
11117         jit_tls->lmf = lmf;
11118 #endif
11119
11120         mono_arch_setup_jit_tls_data (jit_tls);
11121         mono_setup_altstack (jit_tls);
11122
11123         return jit_tls;
11124 }
11125
11126 static void
11127 mono_thread_start_cb (gsize tid, gpointer stack_start, gpointer func)
11128 {
11129         MonoThread *thread;
11130         void *jit_tls = setup_jit_tls_data (stack_start, mono_thread_abort);
11131         thread = mono_thread_current ();
11132         mono_debugger_thread_created (tid, thread, jit_tls);
11133         if (thread)
11134                 thread->jit_data = jit_tls;
11135 }
11136
11137 void (*mono_thread_attach_aborted_cb ) (MonoObject *obj) = NULL;
11138
11139 static void
11140 mono_thread_abort_dummy (MonoObject *obj)
11141 {
11142   if (mono_thread_attach_aborted_cb)
11143     mono_thread_attach_aborted_cb (obj);
11144   else
11145     mono_thread_abort (obj);
11146 }
11147
11148 static void
11149 mono_thread_attach_cb (gsize tid, gpointer stack_start)
11150 {
11151         MonoThread *thread;
11152         void *jit_tls = setup_jit_tls_data (stack_start, mono_thread_abort_dummy);
11153         thread = mono_thread_current ();
11154         mono_debugger_thread_created (tid, thread, (MonoJitTlsData *) jit_tls);
11155         if (thread)
11156                 thread->jit_data = jit_tls;
11157         if (mono_profiler_get_events () & MONO_PROFILE_STATISTICAL)
11158                 setup_stat_profiler ();
11159 }
11160
11161 static void
11162 mini_thread_cleanup (MonoThread *thread)
11163 {
11164         MonoJitTlsData *jit_tls = thread->jit_data;
11165
11166         if (jit_tls) {
11167                 mono_debugger_thread_cleanup (jit_tls);
11168                 mono_arch_free_jit_tls_data (jit_tls);
11169
11170                 mono_free_altstack (jit_tls);
11171                 g_free (jit_tls->first_lmf);
11172                 g_free (jit_tls);
11173                 thread->jit_data = NULL;
11174                 TlsSetValue (mono_jit_tls_id, NULL);
11175         }
11176 }
11177
11178 static MonoInst*
11179 mono_create_tls_get (MonoCompile *cfg, int offset)
11180 {
11181 #ifdef MONO_ARCH_HAVE_TLS_GET
11182         MonoInst* ins;
11183         
11184         if (offset == -1)
11185                 return NULL;
11186         
11187         MONO_INST_NEW (cfg, ins, OP_TLS_GET);
11188         ins->dreg = cfg->new_ir ? mono_alloc_preg (cfg) : mono_regstate_next_int (cfg->rs);
11189         ins->inst_offset = offset;
11190         return ins;
11191 #else
11192         return NULL;
11193 #endif
11194 }
11195
11196 MonoInst*
11197 mono_get_jit_tls_intrinsic (MonoCompile *cfg)
11198 {
11199         return mono_create_tls_get (cfg, mono_get_jit_tls_offset ());
11200 }
11201
11202 void
11203 mono_add_patch_info (MonoCompile *cfg, int ip, MonoJumpInfoType type, gconstpointer target)
11204 {
11205         MonoJumpInfo *ji = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfo));
11206
11207         ji->ip.i = ip;
11208         ji->type = type;
11209         ji->data.target = target;
11210         ji->next = cfg->patch_info;
11211
11212         cfg->patch_info = ji;
11213 }
11214
11215 MonoJumpInfo *
11216 mono_patch_info_list_prepend (MonoJumpInfo *list, int ip, MonoJumpInfoType type, gconstpointer target)
11217 {
11218         MonoJumpInfo *ji = g_new0 (MonoJumpInfo, 1);
11219
11220         ji->ip.i = ip;
11221         ji->type = type;
11222         ji->data.target = target;
11223         ji->next = list;
11224
11225         return ji;
11226 }
11227
11228 void
11229 mono_remove_patch_info (MonoCompile *cfg, int ip)
11230 {
11231         MonoJumpInfo **ji = &cfg->patch_info;
11232
11233         while (*ji) {
11234                 if ((*ji)->ip.i == ip)
11235                         *ji = (*ji)->next;
11236                 else
11237                         ji = &((*ji)->next);
11238         }
11239 }
11240
11241 /**
11242  * mono_patch_info_dup_mp:
11243  *
11244  * Make a copy of PATCH_INFO, allocating memory from the mempool MP.
11245  */
11246 MonoJumpInfo*
11247 mono_patch_info_dup_mp (MonoMemPool *mp, MonoJumpInfo *patch_info)
11248 {
11249         MonoJumpInfo *res = mono_mempool_alloc (mp, sizeof (MonoJumpInfo));
11250         memcpy (res, patch_info, sizeof (MonoJumpInfo));
11251
11252         switch (patch_info->type) {
11253         case MONO_PATCH_INFO_RVA:
11254         case MONO_PATCH_INFO_LDSTR:
11255         case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
11256         case MONO_PATCH_INFO_LDTOKEN:
11257         case MONO_PATCH_INFO_DECLSEC:
11258                 res->data.token = mono_mempool_alloc (mp, sizeof (MonoJumpInfoToken));
11259                 memcpy (res->data.token, patch_info->data.token, sizeof (MonoJumpInfoToken));
11260                 break;
11261         case MONO_PATCH_INFO_SWITCH:
11262                 res->data.table = mono_mempool_alloc (mp, sizeof (MonoJumpInfoBBTable));
11263                 memcpy (res->data.table, patch_info->data.table, sizeof (MonoJumpInfoBBTable));
11264                 break;
11265         case MONO_PATCH_INFO_RGCTX_FETCH:
11266                 res->data.rgctx_entry = mono_mempool_alloc (mp, sizeof (MonoJumpInfoRgctxEntry));
11267                 memcpy (res->data.rgctx_entry, patch_info->data.rgctx_entry, sizeof (MonoJumpInfoRgctxEntry));
11268                 res->data.rgctx_entry->data = mono_patch_info_dup_mp (mp, res->data.rgctx_entry->data);
11269                 break;
11270         default:
11271                 break;
11272         }
11273
11274         return res;
11275 }
11276
11277 guint
11278 mono_patch_info_hash (gconstpointer data)
11279 {
11280         const MonoJumpInfo *ji = (MonoJumpInfo*)data;
11281
11282         switch (ji->type) {
11283         case MONO_PATCH_INFO_RVA:
11284         case MONO_PATCH_INFO_LDSTR:
11285         case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
11286         case MONO_PATCH_INFO_LDTOKEN:
11287         case MONO_PATCH_INFO_DECLSEC:
11288                 return (ji->type << 8) | ji->data.token->token;
11289         case MONO_PATCH_INFO_VTABLE:
11290         case MONO_PATCH_INFO_CLASS:
11291         case MONO_PATCH_INFO_IID:
11292         case MONO_PATCH_INFO_ADJUSTED_IID:
11293         case MONO_PATCH_INFO_CLASS_INIT:
11294         case MONO_PATCH_INFO_METHODCONST:
11295         case MONO_PATCH_INFO_METHOD:
11296         case MONO_PATCH_INFO_METHOD_JUMP:
11297         case MONO_PATCH_INFO_IMAGE:
11298         case MONO_PATCH_INFO_INTERNAL_METHOD:
11299         case MONO_PATCH_INFO_JIT_ICALL_ADDR:
11300         case MONO_PATCH_INFO_FIELD:
11301         case MONO_PATCH_INFO_SFLDA:
11302                 return (ji->type << 8) | (gssize)ji->data.target;
11303         default:
11304                 return (ji->type << 8);
11305         }
11306 }
11307
11308 /* 
11309  * mono_patch_info_equal:
11310  * 
11311  * This might fail to recognize equivalent patches, i.e. floats, so its only
11312  * usable in those cases where this is not a problem, i.e. sharing GOT slots
11313  * in AOT.
11314  */
11315 gint
11316 mono_patch_info_equal (gconstpointer ka, gconstpointer kb)
11317 {
11318         const MonoJumpInfo *ji1 = (MonoJumpInfo*)ka;
11319         const MonoJumpInfo *ji2 = (MonoJumpInfo*)kb;
11320
11321         if (ji1->type != ji2->type)
11322                 return 0;
11323
11324         switch (ji1->type) {
11325         case MONO_PATCH_INFO_RVA:
11326         case MONO_PATCH_INFO_LDSTR:
11327         case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
11328         case MONO_PATCH_INFO_LDTOKEN:
11329         case MONO_PATCH_INFO_DECLSEC:
11330                 if ((ji1->data.token->image != ji2->data.token->image) ||
11331                         (ji1->data.token->token != ji2->data.token->token))
11332                         return 0;
11333                 break;
11334         default:
11335                 if (ji1->data.target != ji2->data.target)
11336                         return 0;
11337                 break;
11338         }
11339
11340         return 1;
11341 }
11342
11343 gpointer
11344 mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *patch_info, gboolean run_cctors)
11345 {
11346         unsigned char *ip = patch_info->ip.i + code;
11347         gconstpointer target = NULL;
11348
11349         switch (patch_info->type) {
11350         case MONO_PATCH_INFO_BB:
11351                 g_assert (patch_info->data.bb->native_offset);
11352                 target = patch_info->data.bb->native_offset + code;
11353                 break;
11354         case MONO_PATCH_INFO_ABS:
11355                 target = patch_info->data.target;
11356                 break;
11357         case MONO_PATCH_INFO_LABEL:
11358                 target = patch_info->data.inst->inst_c0 + code;
11359                 break;
11360         case MONO_PATCH_INFO_IP:
11361                 target = ip;
11362                 break;
11363         case MONO_PATCH_INFO_METHOD_REL:
11364                 target = code + patch_info->data.offset;
11365                 break;
11366         case MONO_PATCH_INFO_INTERNAL_METHOD: {
11367                 MonoJitICallInfo *mi = mono_find_jit_icall_by_name (patch_info->data.name);
11368                 if (!mi) {
11369                         g_warning ("unknown MONO_PATCH_INFO_INTERNAL_METHOD %s", patch_info->data.name);
11370                         g_assert_not_reached ();
11371                 }
11372                 target = mono_icall_get_wrapper (mi);
11373                 break;
11374         }
11375         case MONO_PATCH_INFO_METHOD_JUMP:
11376                 target = mono_create_jump_trampoline (domain, patch_info->data.method, FALSE);
11377                 break;
11378         case MONO_PATCH_INFO_METHOD:
11379                 if (patch_info->data.method == method) {
11380                         target = code;
11381                 } else {
11382                         /* get the trampoline to the method from the domain */
11383                         if (method && method->wrapper_type == MONO_WRAPPER_STATIC_RGCTX_INVOKE) {
11384                                 target = mono_create_jit_trampoline_in_domain (mono_domain_get (),
11385                                         patch_info->data.method);
11386                         } else {
11387                                 target = mono_create_jit_trampoline (patch_info->data.method);
11388                         }
11389                 }
11390                 break;
11391         case MONO_PATCH_INFO_SWITCH: {
11392                 gpointer *jump_table;
11393                 int i;
11394
11395                 if (method && method->dynamic) {
11396                         jump_table = mono_code_manager_reserve (mono_dynamic_code_hash_lookup (domain, method)->code_mp, sizeof (gpointer) * patch_info->data.table->table_size);
11397                 } else {
11398                         mono_domain_lock (domain);
11399                         if (mono_aot_only)
11400                                 jump_table = mono_mempool_alloc (domain->mp, sizeof (gpointer) * patch_info->data.table->table_size);
11401                         else
11402                                 jump_table = mono_code_manager_reserve (domain->code_mp, sizeof (gpointer) * patch_info->data.table->table_size);
11403                         mono_domain_unlock (domain);
11404                 }
11405
11406                 for (i = 0; i < patch_info->data.table->table_size; i++)
11407                         jump_table [i] = code + GPOINTER_TO_INT (patch_info->data.table->table [i]);
11408                 target = jump_table;
11409                 break;
11410         }
11411         case MONO_PATCH_INFO_METHODCONST:
11412         case MONO_PATCH_INFO_CLASS:
11413         case MONO_PATCH_INFO_IMAGE:
11414         case MONO_PATCH_INFO_FIELD:
11415                 target = patch_info->data.target;
11416                 break;
11417         case MONO_PATCH_INFO_IID:
11418                 mono_class_init (patch_info->data.klass);
11419                 target = GINT_TO_POINTER ((int)patch_info->data.klass->interface_id);
11420                 break;
11421         case MONO_PATCH_INFO_ADJUSTED_IID:
11422                 mono_class_init (patch_info->data.klass);
11423                 target = GINT_TO_POINTER ((int)(-((patch_info->data.klass->interface_id + 1) * SIZEOF_VOID_P)));
11424                 break;
11425         case MONO_PATCH_INFO_VTABLE:
11426                 target = mono_class_vtable (domain, patch_info->data.klass);
11427                 g_assert (target);
11428                 break;
11429         case MONO_PATCH_INFO_CLASS_INIT: {
11430                 MonoVTable *vtable = mono_class_vtable (domain, patch_info->data.klass);
11431
11432                 g_assert (vtable);
11433                 target = mono_create_class_init_trampoline (vtable);
11434                 break;
11435         }
11436         case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE:
11437                 target = mono_create_delegate_trampoline (patch_info->data.klass);
11438                 break;
11439         case MONO_PATCH_INFO_SFLDA: {
11440                 MonoVTable *vtable = mono_class_vtable (domain, patch_info->data.field->parent);
11441
11442                 g_assert (vtable);
11443                 if (!vtable->initialized && !(vtable->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) && (method && mono_class_needs_cctor_run (vtable->klass, method)))
11444                         /* Done by the generated code */
11445                         ;
11446                 else {
11447                         if (run_cctors)
11448                                 mono_runtime_class_init (vtable);
11449                 }
11450                 target = (char*)vtable->data + patch_info->data.field->offset;
11451                 break;
11452         }
11453         case MONO_PATCH_INFO_RVA:
11454                 target = mono_image_rva_map (patch_info->data.token->image, patch_info->data.token->token);
11455                 break;
11456         case MONO_PATCH_INFO_R4:
11457         case MONO_PATCH_INFO_R8:
11458                 target = patch_info->data.target;
11459                 break;
11460         case MONO_PATCH_INFO_EXC_NAME:
11461                 target = patch_info->data.name;
11462                 break;
11463         case MONO_PATCH_INFO_LDSTR:
11464                 target =
11465                         mono_ldstr (domain, patch_info->data.token->image, 
11466                                                 mono_metadata_token_index (patch_info->data.token->token));
11467                 break;
11468         case MONO_PATCH_INFO_TYPE_FROM_HANDLE: {
11469                 gpointer handle;
11470                 MonoClass *handle_class;
11471
11472                 handle = mono_ldtoken (patch_info->data.token->image, 
11473                                        patch_info->data.token->token, &handle_class, NULL);
11474                 mono_class_init (handle_class);
11475                 mono_class_init (mono_class_from_mono_type (handle));
11476
11477                 target =
11478                         mono_type_get_object (domain, handle);
11479                 break;
11480         }
11481         case MONO_PATCH_INFO_LDTOKEN: {
11482                 gpointer handle;
11483                 MonoClass *handle_class;
11484                 
11485                 handle = mono_ldtoken (patch_info->data.token->image,
11486                                        patch_info->data.token->token, &handle_class, NULL);
11487                 mono_class_init (handle_class);
11488                 
11489                 target = handle;
11490                 break;
11491         }
11492         case MONO_PATCH_INFO_DECLSEC:
11493                 target = (mono_metadata_blob_heap (patch_info->data.token->image, patch_info->data.token->token) + 2);
11494                 break;
11495         case MONO_PATCH_INFO_ICALL_ADDR:
11496                 target = mono_lookup_internal_call (patch_info->data.method);
11497                 /* run_cctors == 0 -> AOT */
11498                 if (!target && run_cctors)
11499                         g_error ("Unregistered icall '%s'\n", mono_method_full_name (patch_info->data.method, TRUE));
11500                 break;
11501         case MONO_PATCH_INFO_JIT_ICALL_ADDR: {
11502                 MonoJitICallInfo *mi = mono_find_jit_icall_by_name (patch_info->data.name);
11503                 if (!mi) {
11504                         g_warning ("unknown MONO_PATCH_INFO_JIT_ICALL_ADDR %s", patch_info->data.name);
11505                         g_assert_not_reached ();
11506                 }
11507                 target = mi->func;
11508                 break;
11509         }
11510         case MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG:
11511                 target = mono_thread_interruption_request_flag ();
11512                 break;
11513         case MONO_PATCH_INFO_METHOD_RGCTX:
11514                 target = mono_method_lookup_rgctx (mono_class_vtable (domain, patch_info->data.method->klass), mini_method_get_context (patch_info->data.method)->method_inst);
11515                 break;
11516         case MONO_PATCH_INFO_BB_OVF:
11517         case MONO_PATCH_INFO_EXC_OVF:
11518         case MONO_PATCH_INFO_GOT_OFFSET:
11519         case MONO_PATCH_INFO_NONE:
11520                 break;
11521         case MONO_PATCH_INFO_RGCTX_FETCH: {
11522                 MonoJumpInfoRgctxEntry *entry = patch_info->data.rgctx_entry;
11523                 guint32 slot = -1;
11524
11525                 switch (entry->data->type) {
11526                 case MONO_PATCH_INFO_CLASS:
11527                         slot = mono_method_lookup_or_register_other_info (entry->method, entry->in_mrgctx, &entry->data->data.klass->byval_arg, entry->info_type, mono_method_get_context (entry->method));
11528                         break;
11529                 case MONO_PATCH_INFO_METHOD:
11530                 case MONO_PATCH_INFO_METHODCONST:
11531                         slot = mono_method_lookup_or_register_other_info (entry->method, entry->in_mrgctx, entry->data->data.method, entry->info_type, mono_method_get_context (entry->method));
11532                         break;
11533                 case MONO_PATCH_INFO_FIELD:
11534                         slot = mono_method_lookup_or_register_other_info (entry->method, entry->in_mrgctx, entry->data->data.field, entry->info_type, mono_method_get_context (entry->method));
11535                         break;
11536                 default:
11537                         g_assert_not_reached ();
11538                         break;
11539                 }
11540
11541                 target = mono_create_rgctx_lazy_fetch_trampoline (slot);
11542                 break;
11543         }
11544         case MONO_PATCH_INFO_GENERIC_CLASS_INIT:
11545                 target = mono_create_generic_class_init_trampoline ();
11546                 break;
11547         default:
11548                 g_assert_not_reached ();
11549         }
11550
11551         return (gpointer)target;
11552 }
11553
11554 static void
11555 dec_foreach (MonoInst *tree, MonoCompile *cfg) {
11556         MonoJitICallInfo *info;
11557
11558         decompose_foreach (tree, cfg);
11559
11560         switch (mono_burg_arity [tree->opcode]) {
11561         case 0: break;
11562         case 1: 
11563                 dec_foreach (tree->inst_left, cfg);
11564
11565                 if ((info = mono_find_jit_opcode_emulation (tree->opcode))) {
11566                         MonoInst *iargs [2];
11567                 
11568                         iargs [0] = tree->inst_left;
11569
11570                         mono_emulate_opcode (cfg, tree, iargs, info);
11571                         return;
11572                 }
11573
11574                 break;
11575         case 2:
11576 #ifdef MONO_ARCH_BIGMUL_INTRINS
11577                 if (tree->opcode == OP_LMUL
11578                                 && (cfg->opt & MONO_OPT_INTRINS)
11579                                 && (tree->inst_left->opcode == CEE_CONV_I8 
11580                                         || tree->inst_left->opcode == CEE_CONV_U8)
11581                                 && tree->inst_left->inst_left->type == STACK_I4
11582                                 && (tree->inst_right->opcode == CEE_CONV_I8 
11583                                         || tree->inst_right->opcode == CEE_CONV_U8)
11584                                 && tree->inst_right->inst_left->type == STACK_I4
11585                                 && tree->inst_left->opcode == tree->inst_right->opcode) {
11586                         tree->opcode = (tree->inst_left->opcode == CEE_CONV_I8 ? OP_BIGMUL: OP_BIGMUL_UN);
11587                         tree->inst_left = tree->inst_left->inst_left;
11588                         tree->inst_right = tree->inst_right->inst_left;
11589                         dec_foreach (tree, cfg);
11590                 } else 
11591 #endif
11592                         if ((info = mono_find_jit_opcode_emulation (tree->opcode))) {
11593                         MonoInst *iargs [2];
11594                 
11595                         iargs [0] = tree->inst_i0;
11596                         iargs [1] = tree->inst_i1;
11597                 
11598                         mono_emulate_opcode (cfg, tree, iargs, info);
11599
11600                         dec_foreach (iargs [0], cfg);
11601                         dec_foreach (iargs [1], cfg);
11602                         return;
11603                 } else {
11604                         dec_foreach (tree->inst_left, cfg);
11605                         dec_foreach (tree->inst_right, cfg);
11606                 }
11607                 break;
11608         default:
11609                 g_assert_not_reached ();
11610         }
11611 }
11612
11613 static void
11614 decompose_pass (MonoCompile *cfg) {
11615         MonoBasicBlock *bb;
11616
11617         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
11618                 MonoInst *tree;
11619                 cfg->cbb = bb;
11620                 cfg->prev_ins = NULL;
11621                 MONO_BB_FOR_EACH_INS (cfg->cbb, tree) {
11622                         dec_foreach (tree, cfg);
11623                         cfg->prev_ins = tree;
11624                 }
11625         }
11626 }
11627
11628 static void
11629 mono_compile_create_vars (MonoCompile *cfg)
11630 {
11631         MonoMethodSignature *sig;
11632         MonoMethodHeader *header;
11633         int i;
11634
11635         header = mono_method_get_header (cfg->method);
11636
11637         sig = mono_method_signature (cfg->method);
11638         
11639         if (!MONO_TYPE_IS_VOID (sig->ret)) {
11640                 if (cfg->new_ir) {
11641                         cfg->ret = mono_compile_create_var (cfg, sig->ret, OP_ARG);
11642                         /* Inhibit optimizations */
11643                         cfg->ret->flags |= MONO_INST_VOLATILE;
11644                 } else {
11645                         cfg->ret = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst));
11646                         cfg->ret->opcode = OP_RETARG;
11647                         cfg->ret->inst_vtype = sig->ret;
11648                         cfg->ret->klass = mono_class_from_mono_type (sig->ret);
11649                 }
11650         }
11651         if (cfg->verbose_level > 2)
11652                 g_print ("creating vars\n");
11653
11654         cfg->args = mono_mempool_alloc0 (cfg->mempool, (sig->param_count + sig->hasthis) * sizeof (MonoInst*));
11655
11656         if (sig->hasthis)
11657                 cfg->args [0] = mono_compile_create_var (cfg, &cfg->method->klass->this_arg, OP_ARG);
11658
11659         for (i = 0; i < sig->param_count; ++i) {
11660                 cfg->args [i + sig->hasthis] = mono_compile_create_var (cfg, sig->params [i], OP_ARG);
11661                 if (sig->params [i]->byref) {
11662                         if (!cfg->new_ir) cfg->disable_ssa = TRUE;
11663                 }
11664         }
11665
11666         if (cfg->new_ir && cfg->verbose_level > 2) {
11667                 if (cfg->ret) {
11668                         printf ("\treturn : ");
11669                         mono_print_ins (cfg->ret);
11670                 }
11671
11672                 if (sig->hasthis) {
11673                         printf ("\tthis: ");
11674                         mono_print_ins (cfg->args [0]);
11675                 }
11676
11677                 for (i = 0; i < sig->param_count; ++i) {
11678                         printf ("\targ [%d]: ", i);
11679                         mono_print_ins (cfg->args [i + sig->hasthis]);
11680                 }
11681         }
11682
11683         cfg->locals_start = cfg->num_varinfo;
11684         cfg->locals = mono_mempool_alloc0 (cfg->mempool, header->num_locals * sizeof (MonoInst*));
11685
11686         if (cfg->verbose_level > 2)
11687                 g_print ("creating locals\n");
11688
11689         for (i = 0; i < header->num_locals; ++i)
11690                 cfg->locals [i] = mono_compile_create_var (cfg, header->locals [i], OP_LOCAL);
11691
11692         if (cfg->verbose_level > 2)
11693                 g_print ("locals done\n");
11694
11695         mono_arch_create_vars (cfg);
11696 }
11697
11698 void
11699 mono_print_code (MonoCompile *cfg, const char* msg)
11700 {
11701         MonoBasicBlock *bb;
11702         
11703         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
11704                 MonoInst *tree = bb->code;      
11705
11706                 if (cfg->new_ir) {
11707                         mono_print_bb (bb, msg);
11708                 } else {
11709                         if (!tree)
11710                                 continue;
11711                         
11712                         g_print ("%s CODE BLOCK %d (nesting %d):\n", msg, bb->block_num, bb->nesting);
11713
11714                         MONO_BB_FOR_EACH_INS (bb, tree) {
11715                                 mono_print_tree (tree);
11716                                 g_print ("\n");
11717                         }
11718                 }
11719         }
11720 }
11721
11722 extern const char * const mono_burg_rule_string [];
11723
11724 static void
11725 emit_state (MonoCompile *cfg, MBState *state, int goal)
11726 {
11727         MBState *kids [10];
11728         int ern = mono_burg_rule (state, goal);
11729         const guint16 *nts = mono_burg_nts_data + mono_burg_nts [ern];
11730
11731         //g_print ("rule: %s\n", mono_burg_rule_string [ern]);
11732         switch (goal) {
11733         case MB_NTERM_reg:
11734                 //if (state->reg2)
11735                 //      state->reg1 = state->reg2; /* chain rule */
11736                 //else
11737 #ifdef MONO_ARCH_ENABLE_EMIT_STATE_OPT
11738                 if (!state->reg1)
11739 #endif
11740                         state->reg1 = mono_regstate_next_int (cfg->rs);
11741                 //g_print ("alloc symbolic R%d (reg2: R%d) in block %d\n", state->reg1, state->reg2, cfg->cbb->block_num);
11742                 break;
11743         case MB_NTERM_lreg:
11744                 state->reg1 = mono_regstate_next_int (cfg->rs);
11745                 state->reg2 = mono_regstate_next_int (cfg->rs);
11746                 break;
11747         case MB_NTERM_freg:
11748 #ifdef MONO_ARCH_SOFT_FLOAT
11749                 state->reg1 = mono_regstate_next_int (cfg->rs);
11750                 state->reg2 = mono_regstate_next_int (cfg->rs);
11751 #else
11752                 state->reg1 = mono_regstate_next_float (cfg->rs);
11753 #endif
11754                 break;
11755         default:
11756 #ifdef MONO_ARCH_ENABLE_EMIT_STATE_OPT
11757                 /*
11758                  * Enabling this might cause bugs to surface in the local register
11759                  * allocators on some architectures like x86.
11760                  */
11761                 if ((state->tree->ssa_op == MONO_SSA_STORE) && (state->left->tree->opcode == OP_REGVAR)) {
11762                         /* Do not optimize away reg-reg moves */
11763                         if (! ((state->right->tree->ssa_op == MONO_SSA_LOAD) && (state->right->left->tree->opcode == OP_REGVAR))) {
11764                                 state->right->reg1 = state->left->tree->dreg;
11765                         }
11766                 }
11767 #endif
11768
11769                 /* do nothing */
11770                 break;
11771         }
11772         if (nts [0]) {
11773                 mono_burg_kids (state, ern, kids);
11774
11775                 emit_state (cfg, kids [0], nts [0]);
11776                 if (nts [1]) {
11777                         emit_state (cfg, kids [1], nts [1]);
11778                         if (nts [2]) {
11779                                 emit_state (cfg, kids [2], nts [2]);
11780                                 if (nts [3]) {
11781                                         g_assert (!nts [4]);
11782                                         emit_state (cfg, kids [3], nts [3]);
11783                                 }
11784                         }
11785                 }
11786         }
11787
11788 //      g_print ("emit: %s (%p)\n", mono_burg_rule_string [ern], state);
11789         mono_burg_emit (ern, state, state->tree, cfg);
11790 }
11791
11792 #define DEBUG_SELECTION
11793
11794 static void 
11795 mini_select_instructions (MonoCompile *cfg)
11796 {
11797         MonoBasicBlock *bb;
11798         
11799         cfg->state_pool = mono_mempool_new ();
11800         cfg->rs = mono_regstate_new ();
11801
11802         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
11803                 if (bb->last_ins && MONO_IS_COND_BRANCH_OP (bb->last_ins) &&
11804                     bb->last_ins->inst_false_bb && bb->next_bb != bb->last_ins->inst_false_bb) {
11805
11806                         /* we are careful when inverting, since bugs like #59580
11807                          * could show up when dealing with NaNs.
11808                          */
11809                         if (MONO_IS_COND_BRANCH_NOFP(bb->last_ins) && bb->next_bb == bb->last_ins->inst_true_bb) {
11810                                 MonoBasicBlock *tmp =  bb->last_ins->inst_true_bb;
11811                                 bb->last_ins->inst_true_bb = bb->last_ins->inst_false_bb;
11812                                 bb->last_ins->inst_false_bb = tmp;
11813
11814                                 bb->last_ins->opcode = mono_reverse_branch_op (bb->last_ins->opcode);
11815                         } else {                        
11816                                 MonoInst *ins;
11817
11818                                 MONO_INST_NEW (cfg, ins, OP_BR);
11819                                 ins->inst_target_bb = bb->last_ins->inst_false_bb;
11820                                 MONO_ADD_INS (bb, ins);
11821                         }
11822                 }
11823         }
11824
11825 #ifdef DEBUG_SELECTION
11826         if (cfg->verbose_level >= 4) {
11827                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
11828                         MonoInst *tree;
11829                         g_print ("DUMP BLOCK %d:\n", bb->block_num);
11830                         MONO_BB_FOR_EACH_INS (bb, tree) {
11831                                 mono_print_tree (tree);
11832                                 g_print ("\n");
11833                         }
11834                 }
11835         }
11836 #endif
11837
11838         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
11839                 MonoInst *tree = bb->code, *next;       
11840                 MBState *mbstate;
11841
11842                 if (!tree)
11843                         continue;
11844                 bb->code = NULL;
11845                 bb->last_ins = NULL;
11846                 
11847                 cfg->cbb = bb;
11848                 mono_regstate_reset (cfg->rs);
11849
11850 #ifdef DEBUG_SELECTION
11851                 if (cfg->verbose_level >= 3)
11852                         g_print ("LABEL BLOCK %d:\n", bb->block_num);
11853 #endif
11854                 for (; tree; tree = next) {
11855                         next = tree->next;
11856 #ifdef DEBUG_SELECTION
11857                         if (cfg->verbose_level >= 3) {
11858                                 mono_print_tree (tree);
11859                                 g_print ("\n");
11860                         }
11861 #endif
11862
11863                         cfg->ip = tree->cil_code;
11864                         if (!(mbstate = mono_burg_label (tree, cfg))) {
11865                                 g_warning ("unable to label tree %p", tree);
11866                                 mono_print_tree (tree);
11867                                 g_print ("\n");                         
11868                                 g_assert_not_reached ();
11869                         }
11870                         emit_state (cfg, mbstate, MB_NTERM_stmt);
11871                 }
11872                 bb->max_vreg = cfg->rs->next_vreg;
11873
11874                 if (bb->last_ins)
11875                         bb->last_ins->next = NULL;
11876
11877                 mono_mempool_empty (cfg->state_pool); 
11878         }
11879         mono_mempool_destroy (cfg->state_pool); 
11880
11881         cfg->ip = NULL;
11882 }
11883
11884 /*
11885  * mono_normalize_opcodes:
11886  *
11887  *   Replace CEE_ and OP_ opcodes with the corresponding OP_I or OP_L opcodes.
11888  */
11889
11890 static gint16 *remap_table;
11891
11892 #if SIZEOF_VOID_P == 8
11893 #define REMAP_OPCODE(opcode) OP_L ## opcode
11894 #else
11895 #define REMAP_OPCODE(opcode) OP_I ## opcode
11896 #endif
11897
11898 static G_GNUC_UNUSED void
11899 mono_normalize_opcodes (MonoCompile *cfg, MonoBasicBlock *bb)
11900 {
11901         MonoInst *ins;
11902
11903         if (!remap_table) {
11904                 remap_table = g_new0 (gint16, OP_LAST);
11905
11906 #if SIZEOF_VOID_P == 8
11907                 remap_table [CEE_CONV_U8] = OP_ZEXT_I4;
11908                 remap_table [CEE_CONV_U] = OP_ZEXT_I4;
11909                 remap_table [CEE_CONV_I8] = OP_SEXT_I4;
11910                 remap_table [CEE_CONV_I] = OP_SEXT_I4;
11911                 remap_table [CEE_CONV_OVF_U4] = OP_LCONV_TO_OVF_U4;
11912                 remap_table [CEE_CONV_OVF_I4_UN] = OP_LCONV_TO_OVF_I4_UN;
11913 #else
11914 #endif
11915                 remap_table [CEE_CONV_R4] = OP_ICONV_TO_R4;
11916                 remap_table [CEE_CONV_R8] = OP_ICONV_TO_R8;
11917                 remap_table [CEE_CONV_I4] = OP_MOVE;
11918                 remap_table [CEE_CONV_U4] = OP_MOVE;
11919                 remap_table [CEE_CONV_I1] = REMAP_OPCODE (CONV_TO_I1);
11920                 remap_table [CEE_CONV_I2] = REMAP_OPCODE (CONV_TO_I2);
11921                 remap_table [CEE_CONV_U1] = REMAP_OPCODE (CONV_TO_U1);
11922                 remap_table [CEE_CONV_U2] = REMAP_OPCODE (CONV_TO_U2);
11923                 remap_table [CEE_CONV_R_UN] = REMAP_OPCODE (CONV_TO_R_UN);
11924                 remap_table [CEE_ADD] = REMAP_OPCODE (ADD);
11925                 remap_table [CEE_SUB] = REMAP_OPCODE (SUB);
11926                 remap_table [CEE_MUL] = REMAP_OPCODE (MUL);
11927                 remap_table [CEE_DIV] = REMAP_OPCODE (DIV);
11928                 remap_table [CEE_REM] = REMAP_OPCODE (REM);
11929                 remap_table [CEE_DIV_UN] = REMAP_OPCODE (DIV_UN);
11930                 remap_table [CEE_REM_UN] = REMAP_OPCODE (REM_UN);
11931                 remap_table [CEE_AND] = REMAP_OPCODE (AND);
11932                 remap_table [CEE_OR] = REMAP_OPCODE (OR);
11933                 remap_table [CEE_XOR] = REMAP_OPCODE (XOR);
11934                 remap_table [CEE_SHL] = REMAP_OPCODE (SHL);
11935                 remap_table [CEE_SHR] = REMAP_OPCODE (SHR);
11936                 remap_table [CEE_SHR_UN] = REMAP_OPCODE (SHR_UN);
11937                 remap_table [CEE_NOT] = REMAP_OPCODE (NOT);
11938                 remap_table [CEE_NEG] = REMAP_OPCODE (NEG);
11939                 remap_table [CEE_CALL] = OP_CALL;
11940                 remap_table [CEE_BEQ] = REMAP_OPCODE (BEQ);
11941                 remap_table [CEE_BNE_UN] = REMAP_OPCODE (BNE_UN);
11942                 remap_table [CEE_BLT] = REMAP_OPCODE (BLT);
11943                 remap_table [CEE_BLT_UN] = REMAP_OPCODE (BLT_UN);
11944                 remap_table [CEE_BGT] = REMAP_OPCODE (BGT);
11945                 remap_table [CEE_BGT_UN] = REMAP_OPCODE (BGT_UN);
11946                 remap_table [CEE_BGE] = REMAP_OPCODE (BGE);
11947                 remap_table [CEE_BGE_UN] = REMAP_OPCODE (BGE_UN);
11948                 remap_table [CEE_BLE] = REMAP_OPCODE (BLE);
11949                 remap_table [CEE_BLE_UN] = REMAP_OPCODE (BLE_UN);
11950                 remap_table [CEE_ADD_OVF] = REMAP_OPCODE (ADD_OVF);
11951                 remap_table [CEE_ADD_OVF_UN] = REMAP_OPCODE (ADD_OVF_UN);
11952                 remap_table [CEE_SUB_OVF] = REMAP_OPCODE (SUB_OVF);
11953                 remap_table [CEE_SUB_OVF_UN] = REMAP_OPCODE (SUB_OVF_UN);
11954                 remap_table [CEE_MUL_OVF] = REMAP_OPCODE (MUL_OVF);
11955                 remap_table [CEE_MUL_OVF_UN] = REMAP_OPCODE (MUL_OVF_UN);
11956         }
11957
11958         MONO_BB_FOR_EACH_INS (bb, ins) {
11959                 int remapped = remap_table [ins->opcode];
11960                 if (remapped)
11961                         ins->opcode = remapped;
11962         }
11963 }
11964
11965 void
11966 mono_codegen (MonoCompile *cfg)
11967 {
11968         MonoJumpInfo *patch_info;
11969         MonoBasicBlock *bb;
11970         int i, max_epilog_size;
11971         guint8 *code;
11972
11973         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
11974                 cfg->spill_count = 0;
11975                 /* we reuse dfn here */
11976                 /* bb->dfn = bb_count++; */
11977 #ifdef MONO_ARCH_ENABLE_NORMALIZE_OPCODES
11978                 if (!cfg->new_ir)
11979                         mono_normalize_opcodes (cfg, bb);
11980 #endif
11981
11982                 mono_arch_lowering_pass (cfg, bb);
11983
11984                 if (cfg->opt & MONO_OPT_PEEPHOLE)
11985                         mono_arch_peephole_pass_1 (cfg, bb);
11986
11987                 if (!cfg->globalra)
11988                         mono_local_regalloc (cfg, bb);
11989
11990                 if (cfg->opt & MONO_OPT_PEEPHOLE)
11991                         mono_arch_peephole_pass_2 (cfg, bb);
11992         }
11993
11994         if (cfg->prof_options & MONO_PROFILE_COVERAGE)
11995                 cfg->coverage_info = mono_profiler_coverage_alloc (cfg->method, cfg->num_bblocks);
11996
11997         code = mono_arch_emit_prolog (cfg);
11998
11999         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
12000                 code = mono_arch_instrument_prolog (cfg, mono_profiler_method_enter, code, FALSE);
12001
12002         cfg->code_len = code - cfg->native_code;
12003         cfg->prolog_end = cfg->code_len;
12004
12005         mono_debug_open_method (cfg);
12006
12007         /* emit code all basic blocks */
12008         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
12009                 bb->native_offset = cfg->code_len;
12010                 //if ((bb == cfg->bb_entry) || !(bb->region == -1 && !bb->dfn))
12011                         mono_arch_output_basic_block (cfg, bb);
12012
12013                 if (bb == cfg->bb_exit) {
12014                         cfg->epilog_begin = cfg->code_len;
12015
12016                         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE) {
12017                                 code = cfg->native_code + cfg->code_len;
12018                                 code = mono_arch_instrument_epilog (cfg, mono_profiler_method_leave, code, FALSE);
12019                                 cfg->code_len = code - cfg->native_code;
12020                                 g_assert (cfg->code_len < cfg->code_size);
12021                         }
12022
12023                         mono_arch_emit_epilog (cfg);
12024                 }
12025         }
12026
12027         mono_arch_emit_exceptions (cfg);
12028
12029         max_epilog_size = 0;
12030
12031         code = cfg->native_code + cfg->code_len;
12032
12033         /* we always allocate code in cfg->domain->code_mp to increase locality */
12034         cfg->code_size = cfg->code_len + max_epilog_size;
12035         /* fixme: align to MONO_ARCH_CODE_ALIGNMENT */
12036
12037         if (cfg->method->dynamic) {
12038                 guint unwindlen = 0;
12039 #ifdef MONO_ARCH_HAVE_UNWIND_TABLE
12040                 unwindlen = mono_arch_unwindinfo_get_size (cfg->arch.unwindinfo);
12041 #endif
12042                 /* Allocate the code into a separate memory pool so it can be freed */
12043                 cfg->dynamic_info = g_new0 (MonoJitDynamicMethodInfo, 1);
12044                 cfg->dynamic_info->code_mp = mono_code_manager_new_dynamic ();
12045                 mono_domain_lock (cfg->domain);
12046                 mono_dynamic_code_hash_insert (cfg->domain, cfg->method, cfg->dynamic_info);
12047                 mono_domain_unlock (cfg->domain);
12048
12049                 code = mono_code_manager_reserve (cfg->dynamic_info->code_mp, cfg->code_size + unwindlen);
12050         } else {
12051                 guint unwindlen = 0;
12052 #ifdef MONO_ARCH_HAVE_UNWIND_TABLE
12053                 unwindlen = mono_arch_unwindinfo_get_size (cfg->arch.unwindinfo);
12054 #endif
12055                 mono_domain_lock (cfg->domain);
12056                 code = mono_code_manager_reserve (cfg->domain->code_mp, cfg->code_size + unwindlen);
12057                 mono_domain_unlock (cfg->domain);
12058         }
12059
12060         memcpy (code, cfg->native_code, cfg->code_len);
12061         g_free (cfg->native_code);
12062         cfg->native_code = code;
12063         code = cfg->native_code + cfg->code_len;
12064   
12065         /* g_assert (((int)cfg->native_code & (MONO_ARCH_CODE_ALIGNMENT - 1)) == 0); */
12066         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
12067                 switch (patch_info->type) {
12068                 case MONO_PATCH_INFO_ABS: {
12069                         MonoJitICallInfo *info = mono_find_jit_icall_by_addr (patch_info->data.target);
12070
12071                         /*
12072                          * Change patches of type MONO_PATCH_INFO_ABS into patches describing the 
12073                          * absolute address.
12074                          */
12075                         if (info) {
12076                                 //printf ("TEST %s %p\n", info->name, patch_info->data.target);
12077                                 // FIXME: CLEAN UP THIS MESS.
12078                                 if ((cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) && 
12079                                         strstr (cfg->method->name, info->name)) {
12080                                         /*
12081                                          * This is an icall wrapper, and this is a call to the
12082                                          * wrapped function.
12083                                          */
12084                                         if (cfg->compile_aot) {
12085                                                 patch_info->type = MONO_PATCH_INFO_JIT_ICALL_ADDR;
12086                                                 patch_info->data.name = info->name;
12087                                         }
12088                                 } else {
12089                                         /* for these array methods we currently register the same function pointer
12090                                          * since it's a vararg function. But this means that mono_find_jit_icall_by_addr ()
12091                                          * will return the incorrect one depending on the order they are registered.
12092                                          * See tests/test-arr.cs
12093                                          */
12094                                         if (strstr (info->name, "ves_array_new_va_") == NULL && strstr (info->name, "ves_array_element_address_") == NULL) {
12095                                                 patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
12096                                                 patch_info->data.name = info->name;
12097                                         }
12098                                 }
12099                         }
12100                         
12101                         if (patch_info->type == MONO_PATCH_INFO_ABS && !cfg->new_ir) {
12102                                 MonoVTable *vtable = mono_find_class_init_trampoline_by_addr (patch_info->data.target);
12103                                 if (vtable) {
12104                                         patch_info->type = MONO_PATCH_INFO_CLASS_INIT;
12105                                         patch_info->data.klass = vtable->klass;
12106                                 }
12107                         }
12108
12109                         if (patch_info->type == MONO_PATCH_INFO_ABS) {
12110                                 MonoClass *klass = mono_find_delegate_trampoline_by_addr (patch_info->data.target);
12111                                 if (klass) {
12112                                         patch_info->type = MONO_PATCH_INFO_DELEGATE_TRAMPOLINE;
12113                                         patch_info->data.klass = klass;
12114                                 }
12115                         }
12116
12117                         if (patch_info->type == MONO_PATCH_INFO_ABS) {
12118                                 if (cfg->abs_patches) {
12119                                         MonoJumpInfo *abs_ji = g_hash_table_lookup (cfg->abs_patches, patch_info->data.target);
12120                                         if (abs_ji) {
12121                                                 patch_info->type = abs_ji->type;
12122                                                 patch_info->data.target = abs_ji->data.target;
12123                                         }
12124                                 }
12125                         }
12126
12127                         break;
12128                 }
12129                 case MONO_PATCH_INFO_SWITCH: {
12130                         gpointer *table;
12131                         if (cfg->method->dynamic) {
12132                                 table = mono_code_manager_reserve (cfg->dynamic_info->code_mp, sizeof (gpointer) * patch_info->data.table->table_size);
12133                         } else {
12134                                 mono_domain_lock (cfg->domain);
12135                                 table = mono_code_manager_reserve (cfg->domain->code_mp, sizeof (gpointer) * patch_info->data.table->table_size);
12136                                 mono_domain_unlock (cfg->domain);
12137                         }
12138
12139                         if (!cfg->compile_aot && !cfg->new_ir)
12140                                 /* In the aot case, the patch already points to the correct location */
12141                                 patch_info->ip.i = patch_info->ip.label->inst_c0;
12142                         for (i = 0; i < patch_info->data.table->table_size; i++) {
12143                                 /* Might be NULL if the switch is eliminated */
12144                                 if (patch_info->data.table->table [i]) {
12145                                         g_assert (patch_info->data.table->table [i]->native_offset);
12146                                         table [i] = GINT_TO_POINTER (patch_info->data.table->table [i]->native_offset);
12147                                 } else {
12148                                         table [i] = NULL;
12149                                 }
12150                         }
12151                         patch_info->data.table->table = (MonoBasicBlock**)table;
12152                         break;
12153                 }
12154                 case MONO_PATCH_INFO_METHOD_JUMP: {
12155                         GSList *list;
12156                         MonoDomain *domain = cfg->domain;
12157                         unsigned char *ip = cfg->native_code + patch_info->ip.i;
12158
12159                         mono_domain_lock (domain);
12160                         if (!domain->jump_target_hash)
12161                                 domain->jump_target_hash = g_hash_table_new (NULL, NULL);
12162                         list = g_hash_table_lookup (domain->jump_target_hash, patch_info->data.method);
12163                         list = g_slist_prepend (list, ip);
12164                         g_hash_table_insert (domain->jump_target_hash, patch_info->data.method, list);
12165                         mono_domain_unlock (domain);
12166                         break;
12167                 }
12168                 default:
12169                         /* do nothing */
12170                         break;
12171                 }
12172         }
12173
12174 #ifdef VALGRIND_JIT_REGISTER_MAP
12175 if (valgrind_register){
12176                 char* nm = mono_method_full_name (cfg->method, TRUE);
12177                 VALGRIND_JIT_REGISTER_MAP (nm, cfg->native_code, cfg->native_code + cfg->code_len);
12178                 g_free (nm);
12179         }
12180 #endif
12181  
12182         if (cfg->verbose_level > 0) {
12183                 char* nm = mono_method_full_name (cfg->method, TRUE);
12184                 g_print ("Method %s emitted at %p to %p (code length %d) [%s]\n", 
12185                                  nm, 
12186                                  cfg->native_code, cfg->native_code + cfg->code_len, cfg->code_len, cfg->domain->friendly_name);
12187                 g_free (nm);
12188         }
12189
12190         {
12191                 gboolean is_generic = FALSE;
12192
12193                 if (cfg->method->is_inflated || mono_method_get_generic_container (cfg->method) ||
12194                                 cfg->method->klass->generic_container || cfg->method->klass->generic_class) {
12195                         is_generic = TRUE;
12196                 }
12197
12198                 if (cfg->generic_sharing_context)
12199                         g_assert (is_generic);
12200         }
12201
12202 #ifdef MONO_ARCH_HAVE_SAVE_UNWIND_INFO
12203         mono_arch_save_unwind_info (cfg);
12204 #endif
12205         
12206         mono_arch_patch_code (cfg->method, cfg->domain, cfg->native_code, cfg->patch_info, cfg->run_cctors);
12207
12208         if (cfg->method->dynamic) {
12209                 mono_code_manager_commit (cfg->dynamic_info->code_mp, cfg->native_code, cfg->code_size, cfg->code_len);
12210         } else {
12211                 mono_domain_lock (cfg->domain);
12212                 mono_code_manager_commit (cfg->domain->code_mp, cfg->native_code, cfg->code_size, cfg->code_len);
12213                 mono_domain_unlock (cfg->domain);
12214         }
12215         
12216         mono_arch_flush_icache (cfg->native_code, cfg->code_len);
12217
12218         mono_debug_close_method (cfg);
12219 #ifdef MONO_ARCH_HAVE_UNWIND_TABLE
12220         mono_arch_unwindinfo_install_unwind_info (&cfg->arch.unwindinfo, cfg->native_code, cfg->code_len);
12221 #endif
12222 }
12223
12224 static MonoGenericInst*
12225 get_object_generic_inst (int type_argc)
12226 {
12227         MonoType **type_argv;
12228         int i;
12229
12230         type_argv = alloca (sizeof (MonoType*) * type_argc);
12231
12232         for (i = 0; i < type_argc; ++i)
12233                 type_argv [i] = &mono_defaults.object_class->byval_arg;
12234
12235         return mono_metadata_get_generic_inst (type_argc, type_argv);
12236 }
12237
12238 /*
12239  * mini_method_compile:
12240  * @method: the method to compile
12241  * @opts: the optimization flags to use
12242  * @domain: the domain where the method will be compiled in
12243  * @run_cctors: whether we should run type ctors if possible
12244  * @compile_aot: whether this is an AOT compilation
12245  * @parts: debug flag
12246  *
12247  * Returns: a MonoCompile* pointer. Caller must check the exception_type
12248  * field in the returned struct to see if compilation succeded.
12249  */
12250 MonoCompile*
12251 mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gboolean run_cctors, gboolean compile_aot, int parts)
12252 {
12253         MonoMethodHeader *header;
12254         guint8 *ip;
12255         MonoCompile *cfg;
12256         MonoJitInfo *jinfo;
12257         int dfn, i, code_size_ratio;
12258         gboolean deadce_has_run = FALSE;
12259         gboolean try_generic_shared;
12260         MonoMethod *method_to_compile, *method_to_register;
12261         int generic_info_size;
12262
12263         mono_jit_stats.methods_compiled++;
12264         if (mono_profiler_get_events () & MONO_PROFILE_JIT_COMPILATION)
12265                 mono_profiler_method_jit (method);
12266         if (MONO_PROBE_METHOD_COMPILE_BEGIN_ENABLED ())
12267                 MONO_PROBE_METHOD_COMPILE_BEGIN (method);
12268  
12269         if (compile_aot)
12270                 /* We are passed the original generic method definition */
12271                 try_generic_shared = mono_class_generic_sharing_enabled (method->klass) &&
12272                         (opts & MONO_OPT_GSHARED) && (method->is_generic || method->klass->generic_container);
12273         else
12274                 try_generic_shared = mono_class_generic_sharing_enabled (method->klass) &&
12275                         (opts & MONO_OPT_GSHARED) && mono_method_is_generic_sharable_impl (method, FALSE);
12276
12277         if (opts & MONO_OPT_GSHARED) {
12278                 if (try_generic_shared)
12279                         mono_stats.generics_sharable_methods++;
12280                 else if (mono_method_is_generic_impl (method))
12281                         mono_stats.generics_unsharable_methods++;
12282         }
12283
12284  restart_compile:
12285         if (try_generic_shared) {
12286                 MonoMethod *declaring_method;
12287                 MonoGenericContext *shared_context;
12288
12289                 if (compile_aot) {
12290                         declaring_method = method;
12291                 } else {
12292                         declaring_method = mono_method_get_declaring_generic_method (method);
12293                         if (method->klass->generic_class)
12294                                 g_assert (method->klass->generic_class->container_class == declaring_method->klass);
12295                         else
12296                                 g_assert (method->klass == declaring_method->klass);
12297                 }
12298
12299                 if (declaring_method->is_generic)
12300                         shared_context = &(mono_method_get_generic_container (declaring_method)->context);
12301                 else
12302                         shared_context = &declaring_method->klass->generic_container->context;
12303
12304                 method_to_compile = mono_class_inflate_generic_method (declaring_method, shared_context);
12305                 g_assert (method_to_compile);
12306         } else {
12307                 method_to_compile = method;
12308         }
12309
12310         cfg = g_new0 (MonoCompile, 1);
12311         cfg->method = method_to_compile;
12312         cfg->mempool = mono_mempool_new ();
12313         cfg->opt = opts;
12314         cfg->prof_options = mono_profiler_get_events ();
12315         cfg->run_cctors = run_cctors;
12316         cfg->domain = domain;
12317         cfg->verbose_level = mini_verbose;
12318         cfg->compile_aot = compile_aot;
12319         cfg->skip_visibility = method->skip_visibility;
12320         cfg->orig_method = method;
12321         if (try_generic_shared)
12322                 cfg->generic_sharing_context = (MonoGenericSharingContext*)&cfg->generic_sharing_context;
12323         cfg->token_info_hash = g_hash_table_new (NULL, NULL);
12324
12325         if (cfg->compile_aot && !try_generic_shared && (method->is_generic || method->klass->generic_container)) {
12326                 cfg->exception_type = MONO_EXCEPTION_GENERIC_SHARING_FAILED;
12327                 return cfg;
12328         }
12329
12330         /* The debugger has no liveness information, so avoid sharing registers/stack slots */
12331         if (mono_debug_using_mono_debugger () || debug_options.mdb_optimizations) {
12332                 cfg->disable_reuse_registers = TRUE;
12333                 cfg->disable_reuse_stack_slots = TRUE;
12334                 /* 
12335                  * This decreases the change the debugger will read registers/stack slots which are
12336                  * not yet initialized.
12337                  */
12338                 cfg->disable_initlocals_opt = TRUE;
12339
12340                 /* Temporarily disable this when running in the debugger until we have support
12341                  * for this in the debugger. */
12342                 cfg->disable_omit_fp = TRUE;
12343
12344                 // cfg->opt |= MONO_OPT_SHARED;
12345                 cfg->opt &= ~MONO_OPT_INLINE;
12346                 cfg->opt &= ~MONO_OPT_COPYPROP;
12347                 cfg->opt &= ~MONO_OPT_CONSPROP;
12348                 cfg->opt &= ~MONO_OPT_GSHARED;
12349         }
12350
12351         header = mono_method_get_header (method_to_compile);
12352         if (!header) {
12353                 cfg->exception_type = MONO_EXCEPTION_INVALID_PROGRAM;
12354                 cfg->exception_message = g_strdup_printf ("Missing or incorrect header for method %s", cfg->method->name);
12355                 if (MONO_PROBE_METHOD_COMPILE_END_ENABLED ())
12356                         MONO_PROBE_METHOD_COMPILE_END (method, FALSE);
12357                 if (cfg->prof_options & MONO_PROFILE_JIT_COMPILATION)
12358                         mono_profiler_method_end_jit (method, NULL, MONO_PROFILE_FAILED);
12359                 return cfg;
12360         }
12361
12362         if (getenv ("MONO_VERBOSE_METHOD")) {
12363                 if (strcmp (cfg->method->name, getenv ("MONO_VERBOSE_METHOD")) == 0)
12364                         cfg->verbose_level = 4;
12365         }
12366
12367         ip = (guint8 *)header->code;
12368
12369         cfg->intvars = mono_mempool_alloc0 (cfg->mempool, sizeof (guint16) * STACK_MAX * header->max_stack);
12370
12371         if (cfg->verbose_level > 2) {
12372                 if (cfg->generic_sharing_context)
12373                         g_print ("converting shared method %s\n", mono_method_full_name (method, TRUE));
12374                 else
12375                         g_print ("converting method %s\n", mono_method_full_name (method, TRUE));
12376         }
12377
12378         if (cfg->opt & (MONO_OPT_ABCREM | MONO_OPT_SSAPRE))
12379                 cfg->opt |= MONO_OPT_SSA;
12380
12381         {
12382                 static int count = 0;
12383
12384                 count ++;
12385
12386                 if (getenv ("MONO_COUNT")) {
12387                         if (count == atoi (getenv ("MONO_COUNT"))) {
12388                                 printf ("LAST: %s\n", mono_method_full_name (method, TRUE));
12389                                 //cfg->verbose_level = 5;
12390                         }
12391                         if (count <= atoi (getenv ("MONO_COUNT")))
12392                                 cfg->new_ir = TRUE;
12393
12394                         /*
12395                          * Passing/returning vtypes in registers in managed methods is an ABI change 
12396                          * from the old JIT.
12397                          */
12398                         disable_vtypes_in_regs = TRUE;
12399                 }
12400                 else
12401                         cfg->new_ir = TRUE;
12402         }
12403
12404         /* 
12405         if ((cfg->method->klass->image != mono_defaults.corlib) || (strstr (cfg->method->klass->name, "StackOverflowException") && strstr (cfg->method->name, ".ctor")) || (strstr (cfg->method->klass->name, "OutOfMemoryException") && strstr (cfg->method->name, ".ctor")))
12406                 cfg->globalra = TRUE;
12407         */
12408
12409         //cfg->globalra = TRUE;
12410
12411         //if (!strcmp (cfg->method->klass->name, "Tests") && !cfg->method->wrapper_type)
12412         //      cfg->globalra = TRUE;
12413
12414         {
12415                 static int count = 0;
12416                 count ++;
12417
12418                 if (getenv ("COUNT2")) {
12419                         if (count == atoi (getenv ("COUNT2")))
12420                                 printf ("LAST: %s\n", mono_method_full_name (cfg->method, TRUE));
12421                         if (count > atoi (getenv ("COUNT2")))
12422                                 cfg->globalra = FALSE;
12423                 }
12424         }
12425
12426         if (header->clauses)
12427                 cfg->globalra = FALSE;
12428
12429         if (cfg->method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED)
12430                 /* The code in the prolog clobbers caller saved registers */
12431                 cfg->globalra = FALSE;
12432
12433         // FIXME: Disable globalra in case of tracing/profiling
12434
12435         if (cfg->method->save_lmf)
12436                 /* The LMF saving code might clobber caller saved registers */
12437                 cfg->globalra = FALSE;
12438
12439         // FIXME:
12440         if (!strcmp (cfg->method->name, "CompareInternal"))
12441                 cfg->globalra = FALSE;
12442
12443         /*
12444         if (strstr (cfg->method->name, "LoadData"))
12445                 cfg->new_ir = FALSE;
12446         */
12447
12448         if (cfg->new_ir) {
12449                 cfg->rs = mono_regstate_new ();
12450                 cfg->next_vreg = cfg->rs->next_vreg;
12451         }
12452
12453         /* FIXME: Fix SSA to handle branches inside bblocks */
12454         if (cfg->opt & MONO_OPT_SSA)
12455                 cfg->enable_extended_bblocks = FALSE;
12456
12457         /*
12458          * FIXME: This confuses liveness analysis because variables which are assigned after
12459          * a branch inside a bblock become part of the kill set, even though the assignment
12460          * might not get executed. This causes the optimize_initlocals pass to delete some
12461          * assignments which are needed.
12462          * Also, the mono_if_conversion pass needs to be modified to recognize the code
12463          * created by this.
12464          */
12465         //cfg->enable_extended_bblocks = TRUE;
12466
12467         /*
12468          * create MonoInst* which represents arguments and local variables
12469          */
12470         mono_compile_create_vars (cfg);
12471
12472         if (cfg->new_ir) {
12473                 /* SSAPRE is not supported on linear IR */
12474                 cfg->opt &= ~MONO_OPT_SSAPRE;
12475
12476                 i = mono_method_to_ir2 (cfg, method_to_compile, NULL, NULL, NULL, NULL, NULL, 0, FALSE);
12477         }
12478         else {
12479                 i = mono_method_to_ir (cfg, method_to_compile, NULL, NULL, cfg->locals_start, NULL, NULL, NULL, 0, FALSE);
12480         }
12481
12482         if (i < 0) {
12483                 if (try_generic_shared && cfg->exception_type == MONO_EXCEPTION_GENERIC_SHARING_FAILED) {
12484                         if (compile_aot) {
12485                                 if (MONO_PROBE_METHOD_COMPILE_END_ENABLED ())
12486                                         MONO_PROBE_METHOD_COMPILE_END (method, FALSE);
12487                                 return cfg;
12488                         }
12489                         mono_destroy_compile (cfg);
12490                         try_generic_shared = FALSE;
12491                         goto restart_compile;
12492                 }
12493                 g_assert (cfg->exception_type != MONO_EXCEPTION_GENERIC_SHARING_FAILED);
12494
12495                 if (MONO_PROBE_METHOD_COMPILE_END_ENABLED ())
12496                         MONO_PROBE_METHOD_COMPILE_END (method, FALSE);
12497                 if (cfg->prof_options & MONO_PROFILE_JIT_COMPILATION)
12498                         mono_profiler_method_end_jit (method, NULL, MONO_PROFILE_FAILED);
12499                 /* cfg contains the details of the failure, so let the caller cleanup */
12500                 return cfg;
12501         }
12502
12503         mono_jit_stats.basic_blocks += cfg->num_bblocks;
12504         mono_jit_stats.max_basic_blocks = MAX (cfg->num_bblocks, mono_jit_stats.max_basic_blocks);
12505
12506         /*g_print ("numblocks = %d\n", cfg->num_bblocks);*/
12507
12508         if (cfg->new_ir) {
12509                 mono_decompose_long_opts (cfg);
12510
12511                 /* Should be done before branch opts */
12512                 if (cfg->opt & (MONO_OPT_CONSPROP | MONO_OPT_COPYPROP))
12513                         mono_local_cprop2 (cfg);
12514         }
12515
12516         if (cfg->opt & MONO_OPT_BRANCH)
12517                 mono_optimize_branches (cfg);
12518
12519         if (cfg->new_ir) {
12520                 /* This must be done _before_ global reg alloc and _after_ decompose */
12521                 mono_handle_global_vregs (cfg);
12522                 mono_local_deadce (cfg);
12523                 mono_if_conversion (cfg);
12524         }
12525
12526         if ((cfg->opt & MONO_OPT_SSAPRE) || cfg->globalra)
12527                 mono_remove_critical_edges (cfg);
12528
12529         /* Depth-first ordering on basic blocks */
12530         cfg->bblocks = mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * (cfg->num_bblocks + 1));
12531
12532         dfn = 0;
12533         df_visit (cfg->bb_entry, &dfn, cfg->bblocks);
12534         if (cfg->num_bblocks != dfn + 1) {
12535                 MonoBasicBlock *bb;
12536
12537                 cfg->num_bblocks = dfn + 1;
12538
12539                 /* remove unreachable code, because the code in them may be 
12540                  * inconsistent  (access to dead variables for example) */
12541                 for (bb = cfg->bb_entry; bb;) {
12542                         MonoBasicBlock *bbn = bb->next_bb;
12543
12544                         /* 
12545                          * FIXME: Can't use the second case in methods with clauses, since the 
12546                          * bblocks inside the clauses are not processed during dfn computation.
12547                          */
12548                         if ((header->clauses && (bbn && bbn->region == -1 && bbn->in_count == 0)) ||
12549                                 (!header->clauses && (bbn && bbn->region == -1 && !bbn->dfn))) {
12550                                 if (cfg->verbose_level > 1)
12551                                         g_print ("found unreachable code in BB%d\n", bbn->block_num);
12552                                 /* There may exist unreachable branches to this bb */
12553                                 bb->next_bb = bbn->next_bb;
12554                                 mono_nullify_basic_block (bbn);                 
12555                         } else {
12556                                 bb = bb->next_bb;
12557                         }
12558                 }
12559         }
12560
12561         if (((cfg->num_varinfo > 2000) || (cfg->num_bblocks > 1000)) && !cfg->compile_aot) {
12562                 /* 
12563                  * we disable some optimizations if there are too many variables
12564                  * because JIT time may become too expensive. The actual number needs 
12565                  * to be tweaked and eventually the non-linear algorithms should be fixed.
12566                  */
12567                 cfg->opt &= ~ (MONO_OPT_LINEARS | MONO_OPT_COPYPROP | MONO_OPT_CONSPROP);
12568                 cfg->disable_ssa = TRUE;
12569         }
12570
12571         if (cfg->opt & MONO_OPT_LOOP) {
12572                 mono_compile_dominator_info (cfg, MONO_COMP_DOM | MONO_COMP_IDOM);
12573                 mono_compute_natural_loops (cfg);
12574         }
12575
12576         /* after method_to_ir */
12577         if (parts == 1) {
12578                 if (MONO_PROBE_METHOD_COMPILE_END_ENABLED ())
12579                         MONO_PROBE_METHOD_COMPILE_END (method, TRUE);
12580                 return cfg;
12581         }
12582
12583 //#define DEBUGSSA "logic_run"
12584 #define DEBUGSSA_CLASS "Tests"
12585 #ifdef DEBUGSSA
12586
12587         if (!header->num_clauses && !cfg->disable_ssa) {
12588                 mono_local_cprop (cfg);
12589
12590 #ifndef DISABLE_SSA
12591                 if (cfg->new_ir)
12592                         mono_ssa_compute2 (cfg);
12593                 else
12594                         mono_ssa_compute (cfg);
12595 #endif
12596         }
12597 #else 
12598         if (cfg->opt & MONO_OPT_SSA) {
12599                 if (!(cfg->comp_done & MONO_COMP_SSA) && !header->num_clauses && !cfg->disable_ssa) {
12600 #ifndef DISABLE_SSA
12601                         if (!cfg->new_ir)
12602                                 mono_local_cprop (cfg);
12603                         if (cfg->new_ir)
12604                                 mono_ssa_compute2 (cfg);
12605                         else
12606                                 mono_ssa_compute (cfg);
12607 #endif
12608
12609                         if (cfg->verbose_level >= 2) {
12610                                 print_dfn (cfg);
12611                         }
12612                 }
12613         }
12614 #endif
12615
12616         /* after SSA translation */
12617         if (parts == 2) {
12618                 if (MONO_PROBE_METHOD_COMPILE_END_ENABLED ())
12619                         MONO_PROBE_METHOD_COMPILE_END (method, TRUE);
12620                 return cfg;
12621         }
12622
12623         if ((cfg->opt & MONO_OPT_CONSPROP) || (cfg->opt & MONO_OPT_COPYPROP)) {
12624                 if (cfg->comp_done & MONO_COMP_SSA) {
12625 #ifndef DISABLE_SSA
12626                         if (cfg->new_ir)
12627                                 mono_ssa_cprop2 (cfg);
12628                         else
12629                                 mono_ssa_cprop (cfg);
12630 #endif
12631                 } else {
12632                         if (!cfg->new_ir)
12633                                 mono_local_cprop (cfg);
12634                 }
12635         }
12636
12637 #ifndef DISABLE_SSA
12638         if (cfg->comp_done & MONO_COMP_SSA) {                   
12639                 //mono_ssa_strength_reduction (cfg);
12640
12641                 if (cfg->opt & MONO_OPT_SSAPRE) {
12642                         mono_perform_ssapre (cfg);
12643                         //mono_local_cprop (cfg);
12644                 }
12645
12646                 if (cfg->opt & MONO_OPT_DEADCE) {
12647                         if (cfg->new_ir)
12648                                 mono_ssa_deadce2 (cfg);
12649                         else
12650                                 mono_ssa_deadce (cfg);
12651                         deadce_has_run = TRUE;
12652                 }
12653
12654                 if (cfg->new_ir) {
12655                         if ((cfg->flags & (MONO_CFG_HAS_LDELEMA|MONO_CFG_HAS_CHECK_THIS)) && (cfg->opt & MONO_OPT_ABCREM))
12656                                 mono_perform_abc_removal2 (cfg);
12657                 } else {
12658                         if ((cfg->flags & MONO_CFG_HAS_LDELEMA) && (cfg->opt & MONO_OPT_ABCREM))
12659                                 mono_perform_abc_removal (cfg);
12660                 }
12661
12662                 if (cfg->new_ir) {
12663                         mono_ssa_remove2 (cfg);
12664                         mono_local_cprop2 (cfg);
12665                         mono_handle_global_vregs (cfg);
12666                         mono_local_deadce (cfg);
12667                 }
12668                 else
12669                         mono_ssa_remove (cfg);
12670
12671                 if (cfg->opt & MONO_OPT_BRANCH) {
12672                         MonoBasicBlock *bb;
12673
12674                         mono_optimize_branches (cfg);
12675
12676                         /* Have to recompute cfg->bblocks and bb->dfn */
12677                         if (cfg->globalra) {
12678                                 mono_remove_critical_edges (cfg);
12679
12680                                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
12681                                         bb->dfn = 0;
12682
12683                                 /* Depth-first ordering on basic blocks */
12684                                 cfg->bblocks = mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * (cfg->num_bblocks + 1));
12685
12686                                 dfn = 0;
12687                                 df_visit (cfg->bb_entry, &dfn, cfg->bblocks);
12688                                 cfg->num_bblocks = dfn + 1;
12689                         }
12690                 }
12691         }
12692 #endif
12693
12694         /* after SSA removal */
12695         if (parts == 3) {
12696                 if (MONO_PROBE_METHOD_COMPILE_END_ENABLED ())
12697                         MONO_PROBE_METHOD_COMPILE_END (method, TRUE);
12698                 return cfg;
12699         }
12700
12701         if (cfg->new_ir) {
12702 #ifdef MONO_ARCH_SOFT_FLOAT
12703                 mono_handle_soft_float (cfg);
12704 #endif
12705                 mono_decompose_vtype_opts (cfg);
12706                 if (cfg->flags & MONO_CFG_HAS_ARRAY_ACCESS)
12707                         mono_decompose_array_access_opts (cfg);
12708         }
12709
12710         if (!cfg->new_ir) {
12711                 if (cfg->verbose_level > 4)
12712                         mono_print_code (cfg, "BEFORE DECOMPOSE");
12713
12714                 decompose_pass (cfg);
12715         }
12716
12717         if (cfg->got_var) {
12718                 GList *regs;
12719
12720                 g_assert (cfg->got_var_allocated);
12721
12722                 /* 
12723                  * Allways allocate the GOT var to a register, because keeping it
12724                  * in memory will increase the number of live temporaries in some
12725                  * code created by inssel.brg, leading to the well known spills+
12726                  * branches problem. Testcase: mcs crash in 
12727                  * System.MonoCustomAttrs:GetCustomAttributes.
12728                  */
12729                 regs = mono_arch_get_global_int_regs (cfg);
12730                 g_assert (regs);
12731                 cfg->got_var->opcode = OP_REGVAR;
12732                 cfg->got_var->dreg = GPOINTER_TO_INT (regs->data);
12733                 cfg->used_int_regs |= 1LL << cfg->got_var->dreg;
12734                 
12735                 g_list_free (regs);
12736         }
12737
12738         /* todo: remove code when we have verified that the liveness for try/catch blocks
12739          * works perfectly 
12740          */
12741         /* 
12742          * Currently, this can't be commented out since exception blocks are not
12743          * processed during liveness analysis.
12744          */
12745         mono_liveness_handle_exception_clauses (cfg);
12746
12747         if (cfg->globalra) {
12748                 MonoBasicBlock *bb;
12749
12750                 /* Have to do this before regalloc since it can create vregs */
12751                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
12752                         mono_arch_lowering_pass (cfg, bb);
12753
12754                 mono_global_regalloc (cfg);
12755         }
12756
12757         if ((cfg->opt & MONO_OPT_LINEARS) && !cfg->globalra) {
12758                 GList *vars, *regs;
12759                 
12760                 /* For now, compute aliasing info only if needed for deadce... */
12761                 if (!cfg->new_ir && (cfg->opt & MONO_OPT_DEADCE) && (! deadce_has_run) && (header->num_clauses == 0)) {
12762                         cfg->aliasing_info = mono_build_aliasing_information (cfg);
12763                 }
12764
12765                 /* fixme: maybe we can avoid to compute livenesss here if already computed ? */
12766                 cfg->comp_done &= ~MONO_COMP_LIVENESS;
12767                 if (!(cfg->comp_done & MONO_COMP_LIVENESS))
12768                         mono_analyze_liveness (cfg);
12769
12770                 if (cfg->aliasing_info != NULL) {
12771                         mono_aliasing_deadce (cfg->aliasing_info);
12772                         deadce_has_run = TRUE;
12773                 }
12774                 
12775                 if ((vars = mono_arch_get_allocatable_int_vars (cfg))) {
12776                         regs = mono_arch_get_global_int_regs (cfg);
12777                         if (cfg->got_var)
12778                                 regs = g_list_delete_link (regs, regs);
12779                         mono_linear_scan (cfg, vars, regs, &cfg->used_int_regs);
12780                 }
12781                 
12782                 if (cfg->aliasing_info != NULL) {
12783                         mono_destroy_aliasing_information (cfg->aliasing_info);
12784                         cfg->aliasing_info = NULL;
12785                 }
12786         }
12787
12788         //mono_print_code (cfg);
12789
12790     //print_dfn (cfg);
12791         
12792         /* variables are allocated after decompose, since decompose could create temps */
12793         if (!cfg->globalra)
12794                 mono_arch_allocate_vars (cfg);
12795
12796         if (!cfg->new_ir && cfg->opt & MONO_OPT_CFOLD)
12797                 mono_constant_fold (cfg);
12798
12799         if (cfg->new_ir) {
12800                 MonoBasicBlock *bb;
12801                 gboolean need_local_opts;
12802
12803                 if (!cfg->globalra) {
12804                         mono_spill_global_vars (cfg, &need_local_opts);
12805
12806                         if (need_local_opts || cfg->compile_aot) {
12807                                 /* To optimize code created by spill_global_vars */
12808                                 mono_local_cprop2 (cfg);
12809                                 mono_local_deadce (cfg);
12810                         }
12811                 }
12812
12813                 /* Add branches between non-consecutive bblocks */
12814                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
12815                         if (bb->last_ins && MONO_IS_COND_BRANCH_OP (bb->last_ins) &&
12816                                 bb->last_ins->inst_false_bb && bb->next_bb != bb->last_ins->inst_false_bb) {
12817                                 /* we are careful when inverting, since bugs like #59580
12818                                  * could show up when dealing with NaNs.
12819                                  */
12820                                 if (MONO_IS_COND_BRANCH_NOFP(bb->last_ins) && bb->next_bb == bb->last_ins->inst_true_bb) {
12821                                         MonoBasicBlock *tmp =  bb->last_ins->inst_true_bb;
12822                                         bb->last_ins->inst_true_bb = bb->last_ins->inst_false_bb;
12823                                         bb->last_ins->inst_false_bb = tmp;
12824
12825                                         bb->last_ins->opcode = mono_reverse_branch_op (bb->last_ins->opcode);
12826                                 } else {                        
12827                                         MonoInst *inst = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst));
12828                                         inst->opcode = OP_BR;
12829                                         inst->inst_target_bb = bb->last_ins->inst_false_bb;
12830                                         mono_bblock_add_inst (bb, inst);
12831                                 }
12832                         }
12833                 }
12834
12835                 if (cfg->verbose_level >= 4 && !cfg->globalra) {
12836                         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
12837                                 MonoInst *tree = bb->code;      
12838                                 g_print ("DUMP BLOCK %d:\n", bb->block_num);
12839                                 if (!tree)
12840                                         continue;
12841                                 for (; tree; tree = tree->next) {
12842                                         mono_print_ins_index (-1, tree);
12843                                 }
12844                         }
12845                 }
12846
12847                 /* FIXME: */
12848                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
12849                         bb->max_vreg = cfg->next_vreg;
12850                 }
12851         }
12852         else
12853                 mini_select_instructions (cfg);
12854
12855         mono_codegen (cfg);
12856         if (cfg->verbose_level >= 2) {
12857                 char *id =  mono_method_full_name (cfg->method, FALSE);
12858                 mono_disassemble_code (cfg, cfg->native_code, cfg->code_len, id + 3);
12859                 g_free (id);
12860         }
12861
12862         if (cfg->generic_sharing_context)
12863                 generic_info_size = sizeof (MonoGenericJitInfo);
12864         else
12865                 generic_info_size = 0;
12866
12867         if (cfg->method->dynamic) {
12868                 jinfo = g_malloc0 (sizeof (MonoJitInfo) + (header->num_clauses * sizeof (MonoJitExceptionInfo)) +
12869                                 generic_info_size);
12870         } else {
12871                 /* we access cfg->domain->mp */
12872                 mono_domain_lock (cfg->domain);
12873                 jinfo = mono_mempool_alloc0 (cfg->domain->mp, sizeof (MonoJitInfo) +
12874                                 (header->num_clauses * sizeof (MonoJitExceptionInfo)) +
12875                                 generic_info_size);
12876                 mono_domain_unlock (cfg->domain);
12877         }
12878
12879         if (cfg->generic_sharing_context) {
12880                 MonoGenericContext object_context;
12881
12882                 g_assert (!method_to_compile->klass->generic_class);
12883                 if (method_to_compile->klass->generic_container) {
12884                         int type_argc = method_to_compile->klass->generic_container->type_argc;
12885
12886                         object_context.class_inst = get_object_generic_inst (type_argc);
12887                 } else {
12888                         object_context.class_inst = NULL;
12889                 }
12890
12891                 if (mini_method_get_context (method_to_compile)->method_inst) {
12892                         int type_argc = mini_method_get_context (method_to_compile)->method_inst->type_argc;
12893
12894                         object_context.method_inst = get_object_generic_inst (type_argc);
12895                 } else {
12896                         object_context.method_inst = NULL;
12897                 }
12898
12899                 g_assert (object_context.class_inst || object_context.method_inst);
12900
12901                 method_to_register = mono_class_inflate_generic_method (method_to_compile, &object_context);
12902         } else {
12903                 g_assert (method == method_to_compile);
12904                 method_to_register = method;
12905         }
12906
12907         jinfo->method = method_to_register;
12908         jinfo->code_start = cfg->native_code;
12909         jinfo->code_size = cfg->code_len;
12910         jinfo->used_regs = cfg->used_int_regs;
12911         jinfo->domain_neutral = (cfg->opt & MONO_OPT_SHARED) != 0;
12912         jinfo->cas_inited = FALSE; /* initialization delayed at the first stalk walk using this method */
12913         jinfo->num_clauses = header->num_clauses;
12914
12915         if (cfg->generic_sharing_context) {
12916                 MonoInst *inst;
12917                 MonoGenericJitInfo *gi;
12918
12919                 jinfo->has_generic_jit_info = 1;
12920
12921                 gi = mono_jit_info_get_generic_jit_info (jinfo);
12922                 g_assert (gi);
12923
12924                 gi->generic_sharing_context = cfg->generic_sharing_context;
12925
12926                 /*
12927                  * Non-generic static methods only get a "this" info
12928                  * if they use the rgctx variable (which they are
12929                  * forced to if they have any open catch clauses).
12930                  */
12931                 if (cfg->rgctx_var ||
12932                                 (!(method_to_compile->flags & METHOD_ATTRIBUTE_STATIC) &&
12933                                 !mini_method_get_context (method_to_compile)->method_inst)) {
12934                         gi->has_this = 1;
12935
12936                         if ((method_to_compile->flags & METHOD_ATTRIBUTE_STATIC) ||
12937                                         mini_method_get_context (method_to_compile)->method_inst) {
12938                                 inst = cfg->rgctx_var;
12939                                 g_assert (inst->opcode == OP_REGOFFSET);
12940                         } else {
12941                                 inst = cfg->args [0];
12942                         }
12943
12944                         if (inst->opcode == OP_REGVAR) {
12945                                 gi->this_in_reg = 1;
12946                                 gi->this_reg = inst->dreg;
12947
12948                                 //g_print ("this in reg %d\n", inst->dreg);
12949                         } else {
12950                                 g_assert (inst->opcode == OP_REGOFFSET);
12951 #ifdef __i386__
12952                                 g_assert (inst->inst_basereg == X86_EBP);
12953 #elif defined(__x86_64__)
12954                                 g_assert (inst->inst_basereg == X86_EBP || inst->inst_basereg == X86_ESP);
12955 #endif
12956                                 g_assert (inst->inst_offset >= G_MININT32 && inst->inst_offset <= G_MAXINT32);
12957
12958                                 gi->this_in_reg = 0;
12959                                 gi->this_reg = inst->inst_basereg;
12960                                 gi->this_offset = inst->inst_offset;
12961
12962                                 //g_print ("this at offset %d from reg %d\n", gi->this_offset, gi->this_reg);
12963                         }
12964                 } else {
12965                         gi->has_this = 0;
12966                 }
12967         }
12968
12969         if (header->num_clauses) {
12970                 int i;
12971
12972                 for (i = 0; i < header->num_clauses; i++) {
12973                         MonoExceptionClause *ec = &header->clauses [i];
12974                         MonoJitExceptionInfo *ei = &jinfo->clauses [i];
12975                         MonoBasicBlock *tblock;
12976                         MonoInst *exvar;
12977
12978                         ei->flags = ec->flags;
12979
12980                         exvar = mono_find_exvar_for_offset (cfg, ec->handler_offset);
12981                         ei->exvar_offset = exvar ? exvar->inst_offset : 0;
12982
12983                         if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
12984                                 tblock = cfg->cil_offset_to_bb [ec->data.filter_offset];
12985                                 g_assert (tblock);
12986                                 ei->data.filter = cfg->native_code + tblock->native_offset;
12987                         } else {
12988                                 ei->data.catch_class = ec->data.catch_class;
12989                         }
12990
12991                         tblock = cfg->cil_offset_to_bb [ec->try_offset];
12992                         g_assert (tblock);
12993                         ei->try_start = cfg->native_code + tblock->native_offset;
12994                         g_assert (tblock->native_offset);
12995                         tblock = cfg->cil_offset_to_bb [ec->try_offset + ec->try_len];
12996                         g_assert (tblock);
12997                         ei->try_end = cfg->native_code + tblock->native_offset;
12998                         g_assert (tblock->native_offset);
12999                         tblock = cfg->cil_offset_to_bb [ec->handler_offset];
13000                         g_assert (tblock);
13001                         ei->handler_start = cfg->native_code + tblock->native_offset;
13002                 }
13003         }
13004
13005         cfg->jit_info = jinfo;
13006 #if defined(__arm__)
13007         mono_arch_fixup_jinfo (cfg);
13008 #endif
13009
13010         if (!cfg->compile_aot) {
13011                 mono_domain_lock (cfg->domain);
13012                 mono_jit_info_table_add (cfg->domain, jinfo);
13013
13014                 if (cfg->method->dynamic)
13015                         mono_dynamic_code_hash_lookup (cfg->domain, cfg->method)->ji = jinfo;
13016                 mono_domain_unlock (cfg->domain);
13017         }
13018
13019         /* collect statistics */
13020         mono_perfcounters->jit_methods++;
13021         mono_perfcounters->jit_bytes += header->code_size;
13022         mono_jit_stats.allocated_code_size += cfg->code_len;
13023         code_size_ratio = cfg->code_len;
13024         if (code_size_ratio > mono_jit_stats.biggest_method_size && mono_jit_stats.enabled) {
13025                 mono_jit_stats.biggest_method_size = code_size_ratio;
13026                 g_free (mono_jit_stats.biggest_method);
13027                 mono_jit_stats.biggest_method = g_strdup_printf ("%s::%s)", method->klass->name, method->name);
13028         }
13029         code_size_ratio = (code_size_ratio * 100) / mono_method_get_header (method)->code_size;
13030         if (code_size_ratio > mono_jit_stats.max_code_size_ratio && mono_jit_stats.enabled) {
13031                 mono_jit_stats.max_code_size_ratio = code_size_ratio;
13032                 g_free (mono_jit_stats.max_ratio_method);
13033                 mono_jit_stats.max_ratio_method = g_strdup_printf ("%s::%s)", method->klass->name, method->name);
13034         }
13035         mono_jit_stats.native_code_size += cfg->code_len;
13036
13037         if (MONO_PROBE_METHOD_COMPILE_END_ENABLED ())
13038                 MONO_PROBE_METHOD_COMPILE_END (method, TRUE);
13039         if (cfg->prof_options & MONO_PROFILE_JIT_COMPILATION)
13040                 mono_profiler_method_end_jit (method, jinfo, MONO_PROFILE_OK);
13041
13042         return cfg;
13043 }
13044
13045 static MonoJitInfo*
13046 lookup_generic_method (MonoDomain *domain, MonoMethod *method)
13047 {
13048         MonoMethod *open_method;
13049
13050         if (!mono_method_is_generic_sharable_impl (method, FALSE))
13051                 return NULL;
13052
13053         open_method = mono_method_get_declaring_generic_method (method);
13054
13055         return mono_domain_lookup_shared_generic (domain, open_method);
13056 }
13057
13058 /*
13059  * LOCKING: Assumes domain->jit_code_hash_lock is held.
13060  */
13061 static MonoJitInfo*
13062 lookup_method_inner (MonoDomain *domain, MonoMethod *method)
13063 {
13064         MonoJitInfo *ji = mono_internal_hash_table_lookup (&domain->jit_code_hash, method);
13065
13066         if (ji)
13067                 return ji;
13068
13069         return lookup_generic_method (domain, method);
13070 }
13071
13072 static MonoJitInfo*
13073 lookup_method (MonoDomain *domain, MonoMethod *method)
13074 {
13075         MonoJitInfo *info;
13076
13077         mono_domain_jit_code_hash_lock (domain);
13078         info = lookup_method_inner (domain, method);
13079         mono_domain_jit_code_hash_unlock (domain);
13080
13081         return info;
13082 }
13083
13084 static gpointer
13085 mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, int opt)
13086 {
13087         MonoCompile *cfg;
13088         gpointer code = NULL;
13089         MonoJitInfo *info;
13090         MonoVTable *vtable;
13091
13092 #ifdef MONO_USE_AOT_COMPILER
13093         if ((opt & MONO_OPT_AOT) && !(mono_profiler_get_events () & MONO_PROFILE_JIT_COMPILATION)) {
13094                 MonoDomain *domain = mono_domain_get ();
13095
13096                 mono_class_init (method->klass);
13097
13098                 mono_domain_lock (domain);
13099                 if ((code = mono_aot_get_method (domain, method))) {
13100                         mono_domain_unlock (domain);
13101                         vtable = mono_class_vtable (domain, method->klass);
13102                         g_assert (vtable);
13103                         mono_runtime_class_init (vtable);
13104                         return code;
13105                 }
13106
13107                 mono_domain_unlock (domain);
13108         }
13109 #endif
13110
13111         if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
13112             (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
13113                 MonoMethod *nm;
13114                 MonoMethodPInvoke* piinfo = (MonoMethodPInvoke *) method;
13115
13116                 if (!piinfo->addr) {
13117                         if (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL)
13118                                 piinfo->addr = mono_lookup_internal_call (method);
13119                         else if (method->iflags & METHOD_IMPL_ATTRIBUTE_NATIVE)
13120 #ifdef PLATFORM_WIN32
13121                                 g_warning ("Method '%s' in assembly '%s' contains native code that cannot be executed by Mono in modules loaded from byte arrays. The assembly was probably created using C++/CLI.\n", mono_method_full_name (method, TRUE), method->klass->image->name);
13122 #else
13123                                 g_warning ("Method '%s' in assembly '%s' contains native code that cannot be executed by Mono on this platform. The assembly was probably created using C++/CLI.\n", mono_method_full_name (method, TRUE), method->klass->image->name);
13124 #endif
13125                         else
13126                                 mono_lookup_pinvoke_call (method, NULL, NULL);
13127                 }
13128                 nm = mono_marshal_get_native_wrapper (method, check_for_pending_exc, FALSE);
13129                 return mono_get_addr_from_ftnptr (mono_compile_method (nm));
13130
13131                 //if (mono_debug_format != MONO_DEBUG_FORMAT_NONE) 
13132                 //mono_debug_add_wrapper (method, nm);
13133         } else if ((method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME)) {
13134                 const char *name = method->name;
13135                 MonoMethod *nm;
13136
13137                 if (method->klass->parent == mono_defaults.multicastdelegate_class) {
13138                         if (*name == '.' && (strcmp (name, ".ctor") == 0)) {
13139                                 MonoJitICallInfo *mi = mono_find_jit_icall_by_name ("mono_delegate_ctor");
13140                                 g_assert (mi);
13141                                 return mono_get_addr_from_ftnptr ((gpointer)mono_icall_get_wrapper (mi));
13142                         } else if (*name == 'I' && (strcmp (name, "Invoke") == 0)) {
13143 #ifdef MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE
13144                                 return mono_create_delegate_trampoline (method->klass);
13145 #else
13146                                 nm = mono_marshal_get_delegate_invoke (method, NULL);
13147                                 return mono_get_addr_from_ftnptr (mono_compile_method (nm));
13148 #endif
13149                         } else if (*name == 'B' && (strcmp (name, "BeginInvoke") == 0)) {
13150                                 nm = mono_marshal_get_delegate_begin_invoke (method);
13151                                 return mono_get_addr_from_ftnptr (mono_compile_method (nm));
13152                         } else if (*name == 'E' && (strcmp (name, "EndInvoke") == 0)) {
13153                                 nm = mono_marshal_get_delegate_end_invoke (method);
13154                                 return mono_get_addr_from_ftnptr (mono_compile_method (nm));
13155                         }
13156                 }
13157                 return NULL;
13158         }
13159
13160         if (mono_aot_only)
13161                 g_error ("Attempting to JIT compile method '%s' while running with --aot-only.\n", mono_method_full_name (method, TRUE));
13162
13163         cfg = mini_method_compile (method, opt, target_domain, TRUE, FALSE, 0);
13164
13165         switch (cfg->exception_type) {
13166         case MONO_EXCEPTION_NONE:
13167                 break;
13168         case MONO_EXCEPTION_TYPE_LOAD:
13169         case MONO_EXCEPTION_MISSING_FIELD:
13170         case MONO_EXCEPTION_MISSING_METHOD:
13171         case MONO_EXCEPTION_FILE_NOT_FOUND:
13172         case MONO_EXCEPTION_BAD_IMAGE: {
13173                 /* Throw a type load exception if needed */
13174                 MonoLoaderError *error = mono_loader_get_last_error ();
13175                 MonoException *ex;
13176
13177                 if (error) {
13178                         ex = mono_loader_error_prepare_exception (error);
13179                 } else {
13180                         if (cfg->exception_ptr) {
13181                                 ex = mono_class_get_exception_for_failure (cfg->exception_ptr);
13182                         } else {
13183                                 if (cfg->exception_type == MONO_EXCEPTION_MISSING_FIELD)
13184                                         ex = mono_exception_from_name_msg (mono_defaults.corlib, "System", "MissingFieldException", cfg->exception_message);
13185                                 else if (cfg->exception_type == MONO_EXCEPTION_MISSING_METHOD)
13186                                         ex = mono_exception_from_name_msg (mono_defaults.corlib, "System", "MissingMethodException", cfg->exception_message);
13187                                 else if (cfg->exception_type == MONO_EXCEPTION_TYPE_LOAD)
13188                                         ex = mono_exception_from_name_msg (mono_defaults.corlib, "System", "TypeLoadException", cfg->exception_message);
13189                                 else if (cfg->exception_type == MONO_EXCEPTION_FILE_NOT_FOUND)
13190                                         ex = mono_exception_from_name_msg (mono_defaults.corlib, "System", "FileNotFoundException", cfg->exception_message);
13191                                 else if (cfg->exception_type == MONO_EXCEPTION_BAD_IMAGE)
13192                                         ex = mono_get_exception_bad_image_format (cfg->exception_message);
13193                                 else
13194                                         g_assert_not_reached ();
13195                         }
13196                 }
13197                 mono_destroy_compile (cfg);
13198                 mono_raise_exception (ex);
13199                 break;
13200         }
13201         case MONO_EXCEPTION_INVALID_PROGRAM: {
13202                 MonoException *ex = mono_exception_from_name_msg (mono_defaults.corlib, "System", "InvalidProgramException", cfg->exception_message);
13203                 mono_destroy_compile (cfg);
13204                 mono_raise_exception (ex);
13205                 break;
13206         }
13207         case MONO_EXCEPTION_UNVERIFIABLE_IL: {
13208                 MonoException *ex = mono_exception_from_name_msg (mono_defaults.corlib, "System.Security", "VerificationException", cfg->exception_message);
13209                 mono_destroy_compile (cfg);
13210                 mono_raise_exception (ex);
13211                 break;
13212         }
13213         case MONO_EXCEPTION_METHOD_ACCESS: {
13214                 MonoException *ex = mono_exception_from_name_msg (mono_defaults.corlib, "System", "MethodAccessException", cfg->exception_message);
13215                 mono_destroy_compile (cfg);
13216                 mono_raise_exception (ex);
13217                 break;
13218         }
13219         case MONO_EXCEPTION_FIELD_ACCESS: {
13220                 MonoException *ex = mono_exception_from_name_msg (mono_defaults.corlib, "System", "FieldAccessException", cfg->exception_message);
13221                 mono_destroy_compile (cfg);
13222                 mono_raise_exception (ex);
13223                 break;
13224         }
13225         /* this can only be set if the security manager is active */
13226         case MONO_EXCEPTION_SECURITY_LINKDEMAND: {
13227                 MonoSecurityManager* secman = mono_security_manager_get_methods ();
13228                 MonoObject *exc = NULL;
13229                 gpointer args [2];
13230
13231                 args [0] = &cfg->exception_data;
13232                 args [1] = &method;
13233                 mono_runtime_invoke (secman->linkdemandsecurityexception, NULL, args, &exc);
13234
13235                 mono_destroy_compile (cfg);
13236                 cfg = NULL;
13237
13238                 mono_raise_exception ((MonoException*)exc);
13239         }
13240         case MONO_EXCEPTION_OBJECT_SUPPLIED: {
13241                 MonoException *exp = cfg->exception_ptr;
13242                 MONO_GC_UNREGISTER_ROOT (cfg->exception_ptr);
13243                 mono_destroy_compile (cfg);
13244                 mono_raise_exception (exp);
13245                 break;
13246         }
13247         default:
13248                 g_assert_not_reached ();
13249         }
13250
13251         mono_domain_lock (target_domain);
13252
13253         /* Check if some other thread already did the job. In this case, we can
13254        discard the code this thread generated. */
13255
13256         mono_domain_jit_code_hash_lock (target_domain);
13257
13258         info = lookup_method_inner (target_domain, method);
13259         if (info) {
13260                 /* We can't use a domain specific method in another domain */
13261                 if ((target_domain == mono_domain_get ()) || info->domain_neutral) {
13262                         code = info->code_start;
13263 //                      printf("Discarding code for method %s\n", method->name);
13264                 }
13265         }
13266         
13267         if (code == NULL) {
13268                 mono_internal_hash_table_insert (&target_domain->jit_code_hash, cfg->jit_info->method, cfg->jit_info);
13269                 mono_domain_jit_code_hash_unlock (target_domain);
13270                 code = cfg->native_code;
13271
13272                 if (cfg->generic_sharing_context && mono_method_is_generic_sharable_impl (method, FALSE)) {
13273                         /* g_print ("inserting method %s.%s.%s\n", method->klass->name_space, method->klass->name, method->name); */
13274                         mono_domain_register_shared_generic (target_domain, 
13275                                 mono_method_get_declaring_generic_method (method), cfg->jit_info);
13276                         mono_stats.generics_shared_methods++;
13277                 }
13278         } else {
13279                 mono_domain_jit_code_hash_unlock (target_domain);
13280         }
13281
13282         mono_destroy_compile (cfg);
13283
13284         if (target_domain->jump_target_hash) {
13285                 MonoJumpInfo patch_info;
13286                 GSList *list, *tmp;
13287                 list = g_hash_table_lookup (target_domain->jump_target_hash, method);
13288                 if (list) {
13289                         patch_info.next = NULL;
13290                         patch_info.ip.i = 0;
13291                         patch_info.type = MONO_PATCH_INFO_METHOD_JUMP;
13292                         patch_info.data.method = method;
13293                         g_hash_table_remove (target_domain->jump_target_hash, method);
13294                 }
13295                 for (tmp = list; tmp; tmp = tmp->next)
13296                         mono_arch_patch_code (NULL, target_domain, tmp->data, &patch_info, TRUE);
13297                 g_slist_free (list);
13298         }
13299
13300         mono_domain_unlock (target_domain);
13301
13302         vtable = mono_class_vtable (target_domain, method->klass);
13303         if (!vtable) {
13304                 MonoException *exc;
13305                 exc = mono_class_get_exception_for_failure (method->klass);
13306                 g_assert (exc);
13307                 mono_raise_exception (exc);
13308         }
13309         mono_runtime_class_init (vtable);
13310         return code;
13311 }
13312
13313 static gpointer
13314 mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt)
13315 {
13316         MonoDomain *target_domain, *domain = mono_domain_get ();
13317         MonoJitInfo *info;
13318         gpointer p;
13319         MonoJitICallInfo *callinfo = NULL;
13320
13321         /*
13322          * ICALL wrappers are handled specially, since there is only one copy of them
13323          * shared by all appdomains.
13324          */
13325         if ((method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) && (strstr (method->name, "__icall_wrapper_") == method->name)) {
13326                 const char *icall_name;
13327
13328                 icall_name = method->name + strlen ("__icall_wrapper_");
13329                 g_assert (icall_name);
13330                 callinfo = mono_find_jit_icall_by_name (icall_name);
13331                 g_assert (callinfo);
13332
13333                 /* Must be domain neutral since there is only one copy */
13334                 opt |= MONO_OPT_SHARED;
13335         }
13336
13337         if (opt & MONO_OPT_SHARED)
13338                 target_domain = mono_get_root_domain ();
13339         else 
13340                 target_domain = domain;
13341
13342         info = lookup_method (target_domain, method);
13343         if (info) {
13344                 /* We can't use a domain specific method in another domain */
13345                 if (! ((domain != target_domain) && !info->domain_neutral)) {
13346                         MonoVTable *vtable;
13347
13348                         mono_jit_stats.methods_lookups++;
13349                         vtable = mono_class_vtable (domain, method->klass);
13350                         mono_runtime_class_init (vtable);
13351                         return mono_create_ftnptr (target_domain, info->code_start);
13352                 }
13353         }
13354
13355         p = mono_create_ftnptr (target_domain, mono_jit_compile_method_inner (method, target_domain, opt));
13356
13357         if (callinfo) {
13358                 mono_jit_lock ();
13359                 if (!callinfo->wrapper) {
13360                         callinfo->wrapper = p;
13361                         mono_register_jit_icall_wrapper (callinfo, p);
13362                         mono_debug_add_icall_wrapper (method, callinfo);
13363                 }
13364                 mono_jit_unlock ();
13365         }
13366
13367         return p;
13368 }
13369
13370 static gpointer
13371 mono_jit_compile_method (MonoMethod *method)
13372 {
13373         return mono_jit_compile_method_with_opt (method, default_opt);
13374 }
13375
13376 #ifdef MONO_ARCH_HAVE_INVALIDATE_METHOD
13377 static void
13378 invalidated_delegate_trampoline (char *desc)
13379 {
13380         g_error ("Unmanaged code called delegate of type %s which was already garbage collected.\n"
13381                  "See http://www.go-mono.com/delegate.html for an explanation and ways to fix this.",
13382                  desc);
13383 }
13384 #endif
13385
13386 /*
13387  * mono_jit_free_method:
13388  *
13389  *  Free all memory allocated by the JIT for METHOD.
13390  */
13391 static void
13392 mono_jit_free_method (MonoDomain *domain, MonoMethod *method)
13393 {
13394         MonoJitDynamicMethodInfo *ji;
13395         gboolean destroy = TRUE;
13396
13397         g_assert (method->dynamic);
13398
13399         mono_domain_lock (domain);
13400         ji = mono_dynamic_code_hash_lookup (domain, method);
13401         mono_domain_unlock (domain);
13402
13403         if (!ji)
13404                 return;
13405         mono_domain_lock (domain);
13406         g_hash_table_remove (domain->dynamic_code_hash, method);
13407         mono_internal_hash_table_remove (&domain->jit_code_hash, method);
13408         g_hash_table_remove (domain->jump_trampoline_hash, method);
13409         mono_domain_unlock (domain);
13410
13411 #ifdef MONO_ARCH_HAVE_INVALIDATE_METHOD
13412         if (debug_options.keep_delegates && method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
13413                 /*
13414                  * Instead of freeing the code, change it to call an error routine
13415                  * so people can fix their code.
13416                  */
13417                 char *type = mono_type_full_name (&method->klass->byval_arg);
13418                 char *type_and_method = g_strdup_printf ("%s.%s", type, method->name);
13419
13420                 g_free (type);
13421                 mono_arch_invalidate_method (ji->ji, invalidated_delegate_trampoline, type_and_method);
13422                 destroy = FALSE;
13423         }
13424 #endif
13425
13426         /* 
13427          * This needs to be done before freeing code_mp, since the code address is the
13428          * key in the table, so if we free the code_mp first, another thread can grab the
13429          * same code address and replace our entry in the table.
13430          */
13431         mono_jit_info_table_remove (domain, ji->ji);
13432
13433         if (destroy)
13434                 mono_code_manager_destroy (ji->code_mp);
13435         g_free (ji);
13436 }
13437
13438 gpointer
13439 mono_jit_find_compiled_method (MonoDomain *domain, MonoMethod *method)
13440 {
13441         MonoDomain *target_domain;
13442         MonoJitInfo *info;
13443
13444         if (default_opt & MONO_OPT_SHARED)
13445                 target_domain = mono_get_root_domain ();
13446         else 
13447                 target_domain = domain;
13448
13449         info = lookup_method (target_domain, method);
13450         if (info) {
13451                 /* We can't use a domain specific method in another domain */
13452                 if (! ((domain != target_domain) && !info->domain_neutral)) {
13453                         mono_jit_stats.methods_lookups++;
13454                         return info->code_start;
13455                 }
13456         }
13457
13458         return NULL;
13459 }
13460
13461 /**
13462  * mono_jit_runtime_invoke:
13463  * @method: the method to invoke
13464  * @obj: this pointer
13465  * @params: array of parameter values.
13466  * @exc: used to catch exceptions objects
13467  */
13468 static MonoObject*
13469 mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
13470 {
13471         MonoMethod *to_compile;
13472         MonoMethod *invoke;
13473         MonoObject *(*runtime_invoke) (MonoObject *this, void **params, MonoObject **exc, void* compiled_method);
13474         void* compiled_method;
13475         MonoVTable *vtable;
13476
13477         if (obj == NULL && !(method->flags & METHOD_ATTRIBUTE_STATIC) && !method->string_ctor && (method->wrapper_type == 0)) {
13478                 g_warning ("Ignoring invocation of an instance method on a NULL instance.\n");
13479                 return NULL;
13480         }
13481
13482         if (((method->flags & METHOD_ATTRIBUTE_STATIC) ||
13483                                 (method->is_inflated && mono_method_get_context (method)->method_inst)) &&
13484                         mono_class_generic_sharing_enabled (method->klass) &&
13485                         mono_method_is_generic_sharable_impl (method, FALSE)) {
13486                 to_compile = mono_marshal_get_static_rgctx_invoke (method);
13487         } else {
13488                 to_compile = method;
13489         }
13490
13491         invoke = mono_marshal_get_runtime_invoke (method);
13492         runtime_invoke = mono_jit_compile_method (invoke);
13493         
13494         /* We need this here becuase mono_marshal_get_runtime_invoke can be place 
13495          * the helper method in System.Object and not the target class
13496          */
13497         vtable = mono_class_vtable (mono_domain_get (), method->klass);
13498         g_assert (vtable);
13499         mono_runtime_class_init (vtable);
13500
13501         if (method->klass->rank && (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) &&
13502                 (method->iflags & METHOD_IMPL_ATTRIBUTE_NATIVE)) {
13503                 /* 
13504                  * Array Get/Set/Address methods. The JIT implements them using inline code 
13505                  * inside the runtime invoke wrappers, so no need to compile them.
13506                  */
13507                 compiled_method = NULL;
13508         } else {
13509                 compiled_method = mono_jit_compile_method (to_compile);
13510         }
13511         return runtime_invoke (obj, params, exc, compiled_method);
13512 }
13513
13514 #ifdef MONO_GET_CONTEXT
13515 #define GET_CONTEXT MONO_GET_CONTEXT
13516 #endif
13517
13518 #ifndef GET_CONTEXT
13519 #ifdef PLATFORM_WIN32
13520 #define GET_CONTEXT \
13521         struct sigcontext *ctx = (struct sigcontext*)_dummy;
13522 #else
13523 #ifdef MONO_ARCH_USE_SIGACTION
13524 #define GET_CONTEXT \
13525     void *ctx = context;
13526 #elif defined(__sparc__)
13527 #define GET_CONTEXT \
13528     void *ctx = sigctx;
13529 #else
13530 #define GET_CONTEXT \
13531         void **_p = (void **)&_dummy; \
13532         struct sigcontext *ctx = (struct sigcontext *)++_p;
13533 #endif
13534 #endif
13535 #endif
13536
13537 #ifdef MONO_ARCH_USE_SIGACTION
13538 #define SIG_HANDLER_SIGNATURE(ftn) ftn (int _dummy, siginfo_t *info, void *context)
13539 #elif defined(__sparc__)
13540 #define SIG_HANDLER_SIGNATURE(ftn) ftn (int _dummy, void *sigctx)
13541 #else
13542 #define SIG_HANDLER_SIGNATURE(ftn) ftn (int _dummy)
13543 #endif
13544
13545 static void
13546 SIG_HANDLER_SIGNATURE (sigfpe_signal_handler)
13547 {
13548         MonoException *exc = NULL;
13549 #ifndef MONO_ARCH_USE_SIGACTION
13550         void *info = NULL;
13551 #endif
13552         GET_CONTEXT;
13553
13554 #if defined(MONO_ARCH_HAVE_IS_INT_OVERFLOW)
13555         if (mono_arch_is_int_overflow (ctx, info))
13556                 exc = mono_get_exception_arithmetic ();
13557         else
13558                 exc = mono_get_exception_divide_by_zero ();
13559 #else
13560         exc = mono_get_exception_divide_by_zero ();
13561 #endif
13562         
13563         mono_arch_handle_exception (ctx, exc, FALSE);
13564 }
13565
13566 static void
13567 SIG_HANDLER_SIGNATURE (sigill_signal_handler)
13568 {
13569         MonoException *exc;
13570         GET_CONTEXT;
13571
13572         exc = mono_get_exception_execution_engine ("SIGILL");
13573         
13574         mono_arch_handle_exception (ctx, exc, FALSE);
13575 }
13576
13577 static void
13578 SIG_HANDLER_SIGNATURE (sigsegv_signal_handler)
13579 {
13580 #ifndef MONO_ARCH_SIGSEGV_ON_ALTSTACK
13581         MonoException *exc = NULL;
13582 #endif
13583         MonoJitInfo *ji;
13584         MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
13585
13586         GET_CONTEXT;
13587
13588 #ifdef MONO_ARCH_USE_SIGACTION
13589         if (debug_options.collect_pagefault_stats) {
13590                 if (mono_raw_buffer_is_pagefault (info->si_addr)) {
13591                         mono_raw_buffer_handle_pagefault (info->si_addr);
13592                         return;
13593                 }
13594                 if (mono_aot_is_pagefault (info->si_addr)) {
13595                         mono_aot_handle_pagefault (info->si_addr);
13596                         return;
13597                 }
13598         }
13599 #endif
13600
13601         /* The thread might no be registered with the runtime */
13602         if (!mono_domain_get () || !jit_tls)
13603                 mono_handle_native_sigsegv (SIGSEGV, ctx);
13604
13605         ji = mono_jit_info_table_find (mono_domain_get (), mono_arch_ip_from_context (ctx));
13606
13607 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
13608         /* we got a stack overflow in the soft-guard pages
13609          * There are two cases:
13610          * 1) managed code caused the overflow: we unprotect the soft-guard page
13611          * and let the arch-specific code trigger the exception handling mechanism
13612          * in the thread stack. The soft-guard pages will be protected again as the stack is unwound.
13613          * 2) unmanaged code caused the overflow: we unprotect the soft-guard page
13614          * and hope we can continue with those enabled, at least until the hard-guard page
13615          * is hit. The alternative to continuing here is to just print a message and abort.
13616          * We may add in the future the code to protect the pages again in the codepath
13617          * when we return from unmanaged to managed code.
13618          */
13619         if (jit_tls->stack_ovf_guard_size && (guint8*)info->si_addr >= (guint8*)jit_tls->stack_ovf_guard_base &&
13620                         (guint8*)info->si_addr < (guint8*)jit_tls->stack_ovf_guard_base + jit_tls->stack_ovf_guard_size) {
13621                 mono_mprotect (jit_tls->stack_ovf_guard_base, jit_tls->stack_ovf_guard_size, MONO_MMAP_READ|MONO_MMAP_WRITE|MONO_MMAP_EXEC);
13622                 if (ji) {
13623                         mono_arch_handle_altstack_exception (ctx, info->si_addr, TRUE);
13624                 } else {
13625                         /* We print a message: after this even managed stack overflows
13626                          * may crash the runtime
13627                          */
13628                         fprintf (stderr, "Stack overflow in unmanaged: IP: %p, fault addr: %p\n", mono_arch_ip_from_context (ctx), (gpointer)info->si_addr);
13629                 }
13630                 return;
13631         }
13632         /* The hard-guard page has been hit: there is not much we can do anymore
13633          * Print a hopefully clear message and abort.
13634          */
13635         if (jit_tls->stack_size && 
13636                         ABS ((guint8*)info->si_addr - ((guint8*)jit_tls->end_of_stack - jit_tls->stack_size)) < 32768) {
13637                 const char *method;
13638                 /* we don't do much now, but we can warn the user with a useful message */
13639                 fprintf (stderr, "Stack overflow: IP: %p, fault addr: %p\n", mono_arch_ip_from_context (ctx), (gpointer)info->si_addr);
13640                 if (ji && ji->method)
13641                         method = mono_method_full_name (ji->method, TRUE);
13642                 else
13643                         method = "Unmanaged";
13644                 fprintf (stderr, "At %s\n", method);
13645                 abort ();
13646         } else {
13647                 mono_arch_handle_altstack_exception (ctx, info->si_addr, FALSE);
13648         }
13649 #else
13650
13651         if (!ji) {
13652                 mono_handle_native_sigsegv (SIGSEGV, ctx);
13653         }
13654                         
13655         mono_arch_handle_exception (ctx, exc, FALSE);
13656 #endif
13657 }
13658
13659 #ifndef PLATFORM_WIN32
13660
13661 static void
13662 SIG_HANDLER_SIGNATURE (sigabrt_signal_handler)
13663 {
13664         MonoJitInfo *ji;
13665         GET_CONTEXT;
13666
13667         ji = mono_jit_info_table_find (mono_domain_get (), mono_arch_ip_from_context(ctx));
13668         if (!ji) {
13669                 mono_handle_native_sigsegv (SIGABRT, ctx);
13670         }
13671 }
13672
13673 static void
13674 SIG_HANDLER_SIGNATURE (sigusr1_signal_handler)
13675 {
13676         gboolean running_managed;
13677         MonoException *exc;
13678         MonoThread *thread = mono_thread_current ();
13679         void *ji;
13680         
13681         GET_CONTEXT;
13682
13683         if (thread->thread_dump_requested) {
13684                 thread->thread_dump_requested = FALSE;
13685
13686                 mono_print_thread_dump (ctx);
13687         }
13688
13689         /*
13690          * FIXME:
13691          * This is an async signal, so the code below must not call anything which
13692          * is not async safe. That includes the pthread locking functions. If we
13693          * know that we interrupted managed code, then locking is safe.
13694          */
13695         ji = mono_jit_info_table_find (mono_domain_get (), mono_arch_ip_from_context(ctx));
13696         running_managed = ji != NULL;
13697         
13698         exc = mono_thread_request_interruption (running_managed); 
13699         if (!exc) return;
13700
13701         mono_arch_handle_exception (ctx, exc, FALSE);
13702 }
13703
13704 #if defined(__i386__) || defined(__x86_64__)
13705 #define FULL_STAT_PROFILER_BACKTRACE 1
13706 #define CURRENT_FRAME_GET_BASE_POINTER(f) (* (gpointer*)(f))
13707 #define CURRENT_FRAME_GET_RETURN_ADDRESS(f) (* (((gpointer*)(f)) + 1))
13708 #if MONO_ARCH_STACK_GROWS_UP
13709 #define IS_BEFORE_ON_STACK <
13710 #define IS_AFTER_ON_STACK >
13711 #else
13712 #define IS_BEFORE_ON_STACK >
13713 #define IS_AFTER_ON_STACK <
13714 #endif
13715 #else
13716 #define FULL_STAT_PROFILER_BACKTRACE 0
13717 #endif
13718
13719 #if defined(__ia64__) || defined(__sparc__) || defined(sparc) || defined(__s390__) || defined(s390)
13720
13721 static void
13722 SIG_HANDLER_SIGNATURE (sigprof_signal_handler)
13723 {
13724         NOT_IMPLEMENTED;
13725 }
13726
13727 #else
13728
13729 static void
13730 SIG_HANDLER_SIGNATURE (sigprof_signal_handler)
13731 {
13732         int call_chain_depth = mono_profiler_stat_get_call_chain_depth ();
13733         GET_CONTEXT;
13734         
13735         if (call_chain_depth == 0) {
13736                 mono_profiler_stat_hit (mono_arch_ip_from_context (ctx), ctx);
13737         } else {
13738                 MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
13739                 int current_frame_index = 1;
13740                 MonoContext mono_context;
13741 #if FULL_STAT_PROFILER_BACKTRACE
13742                 guchar *current_frame;
13743                 guchar *stack_bottom;
13744                 guchar *stack_top;
13745 #else
13746                 MonoDomain *domain;
13747 #endif
13748                 guchar *ips [call_chain_depth + 1];
13749
13750                 mono_arch_sigctx_to_monoctx (ctx, &mono_context);
13751                 ips [0] = MONO_CONTEXT_GET_IP (&mono_context);
13752                 
13753                 if (jit_tls != NULL) {
13754 #if FULL_STAT_PROFILER_BACKTRACE
13755                         stack_bottom = jit_tls->end_of_stack;
13756                         stack_top = MONO_CONTEXT_GET_SP (&mono_context);
13757                         current_frame = MONO_CONTEXT_GET_BP (&mono_context);
13758                         
13759                         while ((current_frame_index <= call_chain_depth) &&
13760                                         (stack_bottom IS_BEFORE_ON_STACK (guchar*) current_frame) &&
13761                                         ((guchar*) current_frame IS_BEFORE_ON_STACK stack_top)) {
13762                                 ips [current_frame_index] = CURRENT_FRAME_GET_RETURN_ADDRESS (current_frame);
13763                                 current_frame_index ++;
13764                                 stack_top = current_frame;
13765                                 current_frame = CURRENT_FRAME_GET_BASE_POINTER (current_frame);
13766                         }
13767 #else
13768                         domain = mono_domain_get ();
13769                         if (domain != NULL) {
13770                                 MonoLMF *lmf = NULL;
13771                                 MonoJitInfo *ji;
13772                                 MonoJitInfo res;
13773                                 MonoContext new_mono_context;
13774                                 int native_offset;
13775                                 ji = mono_find_jit_info (domain, jit_tls, &res, NULL, &mono_context,
13776                                                 &new_mono_context, NULL, &lmf, &native_offset, NULL);
13777                                 while ((ji != NULL) && (current_frame_index <= call_chain_depth)) {
13778                                         ips [current_frame_index] = MONO_CONTEXT_GET_IP (&new_mono_context);
13779                                         current_frame_index ++;
13780                                         mono_context = new_mono_context;
13781                                         ji = mono_find_jit_info (domain, jit_tls, &res, NULL, &mono_context,
13782                                                         &new_mono_context, NULL, &lmf, &native_offset, NULL);
13783                                 }
13784                         }
13785 #endif
13786                 }
13787                 
13788                 
13789                 mono_profiler_stat_call_chain (current_frame_index, & ips [0], ctx);
13790         }
13791 }
13792
13793 #endif
13794
13795 static void
13796 SIG_HANDLER_SIGNATURE (sigquit_signal_handler)
13797 {
13798         GET_CONTEXT;
13799
13800         printf ("Full thread dump:\n");
13801
13802         mono_threads_request_thread_dump ();
13803
13804         /*
13805          * print_thread_dump () skips the current thread, since sending a signal
13806          * to it would invoke the signal handler below the sigquit signal handler,
13807          * and signal handlers don't create an lmf, so the stack walk could not
13808          * be performed.
13809          */
13810         mono_print_thread_dump (ctx);
13811 }
13812
13813 static void
13814 SIG_HANDLER_SIGNATURE (sigusr2_signal_handler)
13815 {
13816         gboolean enabled = mono_trace_is_enabled ();
13817
13818         mono_trace_enable (!enabled);
13819 }
13820
13821 #endif
13822
13823 static void
13824 SIG_HANDLER_SIGNATURE (sigint_signal_handler)
13825 {
13826         MonoException *exc;
13827         GET_CONTEXT;
13828
13829         exc = mono_get_exception_execution_engine ("Interrupted (SIGINT).");
13830         
13831         mono_arch_handle_exception (ctx, exc, FALSE);
13832 }
13833
13834 #ifdef PLATFORM_MACOSX
13835
13836 /*
13837  * This code disables the CrashReporter of MacOS X by installing
13838  * a dummy Mach exception handler.
13839  */
13840
13841 /*
13842  * http://darwinsource.opendarwin.org/10.4.3/xnu-792.6.22/osfmk/man/exc_server.html
13843  */
13844 extern
13845 boolean_t
13846 exc_server (mach_msg_header_t *request_msg,
13847             mach_msg_header_t *reply_msg);
13848
13849 /*
13850  * The exception message
13851  */
13852 typedef struct {
13853         mach_msg_base_t msg;  /* common mach message header */
13854         char payload [1024];  /* opaque */
13855 } mach_exception_msg_t;
13856
13857 /* The exception port */
13858 static mach_port_t mach_exception_port = VM_MAP_NULL;
13859
13860 /*
13861  * Implicitly called by exc_server. Must be public.
13862  *
13863  * http://darwinsource.opendarwin.org/10.4.3/xnu-792.6.22/osfmk/man/catch_exception_raise.html
13864  */
13865 kern_return_t
13866 catch_exception_raise (
13867         mach_port_t exception_port,
13868         mach_port_t thread,
13869         mach_port_t task,
13870         exception_type_t exception,
13871         exception_data_t code,
13872         mach_msg_type_number_t code_count)
13873 {
13874         /* consume the exception */
13875         return KERN_FAILURE;
13876 }
13877
13878 /*
13879  * Exception thread handler.
13880  */
13881 static
13882 void *
13883 mach_exception_thread (void *arg)
13884 {
13885         for (;;) {
13886                 mach_exception_msg_t request;
13887                 mach_exception_msg_t reply;
13888                 mach_msg_return_t result;
13889
13890                 /* receive from "mach_exception_port" */
13891                 result = mach_msg (&request.msg.header,
13892                                    MACH_RCV_MSG | MACH_RCV_LARGE,
13893                                    0,
13894                                    sizeof (request),
13895                                    mach_exception_port,
13896                                    MACH_MSG_TIMEOUT_NONE,
13897                                    MACH_PORT_NULL);
13898
13899                 g_assert (result == MACH_MSG_SUCCESS);
13900
13901                 /* dispatch to catch_exception_raise () */
13902                 exc_server (&request.msg.header, &reply.msg.header);
13903
13904                 /* send back to sender */
13905                 result = mach_msg (&reply.msg.header,
13906                                    MACH_SEND_MSG,
13907                                    reply.msg.header.msgh_size,
13908                                    0,
13909                                    MACH_PORT_NULL,
13910                                    MACH_MSG_TIMEOUT_NONE,
13911                                    MACH_PORT_NULL);
13912
13913                 g_assert (result == MACH_MSG_SUCCESS);
13914         }
13915         return NULL;
13916 }
13917
13918 static void
13919 macosx_register_exception_handler ()
13920 {
13921         mach_port_t task;
13922         pthread_attr_t attr;
13923         pthread_t thread;
13924
13925         if (mach_exception_port != VM_MAP_NULL)
13926                 return;
13927
13928         task = mach_task_self ();
13929
13930         /* create the "mach_exception_port" with send & receive rights */
13931         g_assert (mach_port_allocate (task, MACH_PORT_RIGHT_RECEIVE,
13932                                       &mach_exception_port) == KERN_SUCCESS);
13933         g_assert (mach_port_insert_right (task, mach_exception_port, mach_exception_port,
13934                                           MACH_MSG_TYPE_MAKE_SEND) == KERN_SUCCESS);
13935
13936         /* create the exception handler thread */
13937         g_assert (!pthread_attr_init (&attr));
13938         g_assert (!pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED));
13939         g_assert (!pthread_create (&thread, &attr, mach_exception_thread, NULL));
13940         pthread_attr_destroy (&attr);
13941
13942         /*
13943          * register "mach_exception_port" as a receiver for the
13944          * EXC_BAD_ACCESS exception
13945          *
13946          * http://darwinsource.opendarwin.org/10.4.3/xnu-792.6.22/osfmk/man/task_set_exception_ports.html
13947          */
13948         g_assert (task_set_exception_ports (task, EXC_MASK_BAD_ACCESS,
13949                                             mach_exception_port,
13950                                             EXCEPTION_DEFAULT,
13951                                             MACHINE_THREAD_STATE) == KERN_SUCCESS);
13952 }
13953 #endif
13954
13955 #ifndef PLATFORM_WIN32
13956 static void
13957 add_signal_handler (int signo, gpointer handler)
13958 {
13959         struct sigaction sa;
13960
13961 #ifdef MONO_ARCH_USE_SIGACTION
13962         sa.sa_sigaction = handler;
13963         sigemptyset (&sa.sa_mask);
13964         sa.sa_flags = SA_SIGINFO;
13965 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
13966         if (signo == SIGSEGV)
13967                 sa.sa_flags |= SA_ONSTACK;
13968 #endif
13969 #else
13970         sa.sa_handler = handler;
13971         sigemptyset (&sa.sa_mask);
13972         sa.sa_flags = 0;
13973 #endif
13974         g_assert (sigaction (signo, &sa, NULL) != -1);
13975 }
13976
13977 static void
13978 remove_signal_handler (int signo)
13979 {
13980         struct sigaction sa;
13981
13982         sa.sa_handler = SIG_DFL;
13983         sigemptyset (&sa.sa_mask);
13984         sa.sa_flags = 0;
13985
13986         g_assert (sigaction (signo, &sa, NULL) != -1);
13987 }
13988 #endif
13989
13990 static void
13991 mono_runtime_install_handlers (void)
13992 {
13993 #ifdef PLATFORM_WIN32
13994         win32_seh_init();
13995         win32_seh_set_handler(SIGFPE, sigfpe_signal_handler);
13996         win32_seh_set_handler(SIGILL, sigill_signal_handler);
13997         win32_seh_set_handler(SIGSEGV, sigsegv_signal_handler);
13998         if (debug_options.handle_sigint)
13999                 win32_seh_set_handler(SIGINT, sigint_signal_handler);
14000
14001 #else /* !PLATFORM_WIN32 */
14002
14003
14004 #if defined(PLATFORM_MACOSX) && !defined(__arm__)
14005         macosx_register_exception_handler ();
14006 #endif
14007
14008         if (debug_options.handle_sigint)
14009                 add_signal_handler (SIGINT, sigint_signal_handler);
14010
14011         add_signal_handler (SIGFPE, sigfpe_signal_handler);
14012         add_signal_handler (SIGQUIT, sigquit_signal_handler);
14013         add_signal_handler (SIGILL, sigill_signal_handler);
14014         add_signal_handler (SIGBUS, sigsegv_signal_handler);
14015         if (mono_jit_trace_calls != NULL)
14016                 add_signal_handler (SIGUSR2, sigusr2_signal_handler);
14017
14018         add_signal_handler (mono_thread_get_abort_signal (), sigusr1_signal_handler);
14019         signal (SIGPIPE, SIG_IGN);
14020
14021         add_signal_handler (SIGABRT, sigabrt_signal_handler);
14022
14023         /* catch SIGSEGV */
14024         add_signal_handler (SIGSEGV, sigsegv_signal_handler);
14025 #endif /* PLATFORM_WIN32 */
14026 }
14027
14028 static void
14029 mono_runtime_cleanup_handlers (void)
14030 {
14031 #ifdef PLATFORM_WIN32
14032         win32_seh_cleanup();
14033 #else
14034         if (debug_options.handle_sigint)
14035                 remove_signal_handler (SIGINT);
14036
14037         remove_signal_handler (SIGFPE);
14038         remove_signal_handler (SIGQUIT);
14039         remove_signal_handler (SIGILL);
14040         remove_signal_handler (SIGBUS);
14041         if (mono_jit_trace_calls != NULL)
14042                 remove_signal_handler (SIGUSR2);
14043
14044         remove_signal_handler (mono_thread_get_abort_signal ());
14045
14046         remove_signal_handler (SIGABRT);
14047
14048         remove_signal_handler (SIGSEGV);
14049 #endif /* PLATFORM_WIN32 */
14050 }
14051
14052
14053 #ifdef HAVE_LINUX_RTC_H
14054 #include <linux/rtc.h>
14055 #include <sys/ioctl.h>
14056 #include <fcntl.h>
14057 static int rtc_fd = -1;
14058
14059 static int
14060 enable_rtc_timer (gboolean enable)
14061 {
14062         int flags;
14063         flags = fcntl (rtc_fd, F_GETFL);
14064         if (flags < 0) {
14065                 perror ("getflags");
14066                 return 0;
14067         }
14068         if (enable)
14069                 flags |= FASYNC;
14070         else
14071                 flags &= ~FASYNC;
14072         if (fcntl (rtc_fd, F_SETFL, flags) == -1) {
14073                 perror ("setflags");
14074                 return 0;
14075         }
14076         return 1;
14077 }
14078 #endif
14079
14080 #ifdef PLATFORM_WIN32
14081 static HANDLE win32_main_thread;
14082 static MMRESULT win32_timer;
14083
14084 static void CALLBACK
14085 win32_time_proc (UINT uID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2)
14086 {
14087         CONTEXT context;
14088
14089         context.ContextFlags = CONTEXT_CONTROL;
14090         if (GetThreadContext (win32_main_thread, &context)) {
14091 #ifdef _WIN64
14092                 mono_profiler_stat_hit ((guchar *) context.Rip, &context);
14093 #else
14094                 mono_profiler_stat_hit ((guchar *) context.Eip, &context);
14095 #endif
14096         }
14097 }
14098 #endif
14099
14100 static void
14101 setup_stat_profiler (void)
14102 {
14103 #ifdef ITIMER_PROF
14104         struct itimerval itval;
14105         static int inited = 0;
14106 #ifdef HAVE_LINUX_RTC_H
14107         const char *rtc_freq;
14108         if (!inited && (rtc_freq = g_getenv ("MONO_RTC"))) {
14109                 int freq = 0;
14110                 inited = 1;
14111                 if (*rtc_freq)
14112                         freq = atoi (rtc_freq);
14113                 if (!freq)
14114                         freq = 1024;
14115                 rtc_fd = open ("/dev/rtc", O_RDONLY);
14116                 if (rtc_fd == -1) {
14117                         perror ("open /dev/rtc");
14118                         return;
14119                 }
14120                 add_signal_handler (SIGPROF, sigprof_signal_handler);
14121                 if (ioctl (rtc_fd, RTC_IRQP_SET, freq) == -1) {
14122                         perror ("set rtc freq");
14123                         return;
14124                 }
14125                 if (ioctl (rtc_fd, RTC_PIE_ON, 0) == -1) {
14126                         perror ("start rtc");
14127                         return;
14128                 }
14129                 if (fcntl (rtc_fd, F_SETSIG, SIGPROF) == -1) {
14130                         perror ("setsig");
14131                         return;
14132                 }
14133                 if (fcntl (rtc_fd, F_SETOWN, getpid ()) == -1) {
14134                         perror ("setown");
14135                         return;
14136                 }
14137                 enable_rtc_timer (TRUE);
14138                 return;
14139         }
14140         if (rtc_fd >= 0)
14141                 return;
14142 #endif
14143
14144         itval.it_interval.tv_usec = 999;
14145         itval.it_interval.tv_sec = 0;
14146         itval.it_value = itval.it_interval;
14147         setitimer (ITIMER_PROF, &itval, NULL);
14148         if (inited)
14149                 return;
14150         inited = 1;
14151         add_signal_handler (SIGPROF, sigprof_signal_handler);
14152 #elif defined (PLATFORM_WIN32)
14153         static int inited = 0;
14154         TIMECAPS timecaps;
14155
14156         if (inited)
14157                 return;
14158
14159         inited = 1;
14160         if (timeGetDevCaps (&timecaps, sizeof (timecaps)) != TIMERR_NOERROR)
14161                 return;
14162
14163         if ((win32_main_thread = OpenThread (READ_CONTROL | THREAD_GET_CONTEXT, FALSE, GetCurrentThreadId ())) == NULL)
14164                 return;
14165
14166         if (timeBeginPeriod (1) != TIMERR_NOERROR)
14167                 return;
14168
14169         if ((win32_timer = timeSetEvent (1, 0, win32_time_proc, 0, TIME_PERIODIC)) == 0) {
14170                 timeEndPeriod (1);
14171                 return;
14172         }
14173 #endif
14174 }
14175
14176 /* mono_jit_create_remoting_trampoline:
14177  * @method: pointer to the method info
14178  *
14179  * Creates a trampoline which calls the remoting functions. This
14180  * is used in the vtable of transparent proxies.
14181  * 
14182  * Returns: a pointer to the newly created code 
14183  */
14184 static gpointer
14185 mono_jit_create_remoting_trampoline (MonoMethod *method, MonoRemotingTarget target)
14186 {
14187         MonoMethod *nm;
14188         guint8 *addr = NULL;
14189
14190         if ((method->flags & METHOD_ATTRIBUTE_ABSTRACT) || 
14191             (mono_method_signature (method)->hasthis && (method->klass->marshalbyref || method->klass == mono_defaults.object_class))) {
14192                 nm = mono_marshal_get_remoting_invoke_for_target (method, target);
14193                 addr = mono_compile_method (nm);
14194         } else {
14195                 addr = mono_compile_method (method);
14196         }
14197         return mono_get_addr_from_ftnptr (addr);
14198 }
14199
14200 #ifdef MONO_ARCH_HAVE_IMT
14201 static gpointer
14202 mini_get_imt_trampoline (void)
14203 {
14204         static gpointer tramp = NULL;
14205         if (!tramp)
14206                 tramp = mono_create_specific_trampoline (MONO_FAKE_IMT_METHOD, MONO_TRAMPOLINE_JIT, mono_get_root_domain (), NULL);
14207         return tramp;
14208 }
14209 #endif
14210
14211 #ifdef MONO_ARCH_COMMON_VTABLE_TRAMPOLINE
14212 gpointer
14213 mini_get_vtable_trampoline (void)
14214 {
14215         static gpointer tramp = NULL;
14216         if (!tramp)
14217                 tramp = mono_create_specific_trampoline (MONO_FAKE_VTABLE_METHOD, MONO_TRAMPOLINE_JIT, mono_get_root_domain (), NULL);
14218         return tramp;
14219 }
14220 #endif
14221
14222 static void
14223 mini_parse_debug_options (void)
14224 {
14225         char *options = getenv ("MONO_DEBUG");
14226         gchar **args, **ptr;
14227         
14228         if (!options)
14229                 return;
14230
14231         args = g_strsplit (options, ",", -1);
14232
14233         for (ptr = args; ptr && *ptr; ptr++) {
14234                 const char *arg = *ptr;
14235
14236                 if (!strcmp (arg, "handle-sigint"))
14237                         debug_options.handle_sigint = TRUE;
14238                 else if (!strcmp (arg, "keep-delegates"))
14239                         debug_options.keep_delegates = TRUE;
14240                 else if (!strcmp (arg, "collect-pagefault-stats"))
14241                         debug_options.collect_pagefault_stats = TRUE;
14242                 else if (!strcmp (arg, "break-on-unverified"))
14243                         debug_options.break_on_unverified = TRUE;
14244                 else if (!strcmp (arg, "no-gdb-backtrace"))
14245                         debug_options.no_gdb_backtrace = TRUE;
14246                 else if (!strcmp (arg, "dont-free-domains"))
14247                         mono_dont_free_domains = TRUE;
14248                 else {
14249                         fprintf (stderr, "Invalid option for the MONO_DEBUG env variable: %s\n", arg);
14250                         fprintf (stderr, "Available options: 'handle-sigint', 'keep-delegates', 'collect-pagefault-stats', 'break-on-unverified', 'no-gdb-backtrace', 'dont-free-domains'\n");
14251                         exit (1);
14252                 }
14253         }
14254
14255         g_strfreev (args);
14256 }
14257
14258 MonoDebugOptions *
14259 mini_get_debug_options (void)
14260 {
14261         return &debug_options;
14262 }
14263  
14264 static void
14265 mini_create_jit_domain_info (MonoDomain *domain)
14266 {
14267         MonoJitDomainInfo *info = g_new0 (MonoJitDomainInfo, 1);
14268
14269         domain->runtime_info = info;
14270 }
14271
14272 static void
14273 delete_jump_list (gpointer key, gpointer value, gpointer user_data)
14274 {
14275         g_slist_free (value);
14276 }
14277
14278 static void
14279 mini_free_jit_domain_info (MonoDomain *domain)
14280 {
14281         MonoJitDomainInfo *info = jit_domain_info (domain);
14282
14283         if (info->jump_target_got_slot_hash) {
14284                 g_hash_table_foreach (info->jump_target_got_slot_hash, delete_jump_list, NULL);
14285                 g_hash_table_destroy (info->jump_target_got_slot_hash);
14286         }
14287         g_free (domain->runtime_info);
14288 }
14289
14290 MonoDomain *
14291 mini_init (const char *filename, const char *runtime_version)
14292 {
14293         MonoDomain *domain;
14294
14295         MONO_PROBE_VES_INIT_BEGIN ();
14296
14297 #ifdef __linux__
14298         if (access ("/proc/self/maps", F_OK) != 0) {
14299                 g_print ("Mono requires /proc to be mounted.\n");
14300                 exit (1);
14301         }
14302 #endif
14303
14304         /* Happens when using the embedding interface */
14305         if (!default_opt_set)
14306                 default_opt = mono_parse_default_optimizations (NULL);
14307
14308         InitializeCriticalSection (&jit_mutex);
14309
14310         if (!global_codeman)
14311                 global_codeman = mono_code_manager_new ();
14312         jit_icall_name_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
14313
14314         mono_arch_cpu_init ();
14315
14316         mono_arch_init ();
14317
14318         mono_trampolines_init ();
14319
14320         if (!g_thread_supported ())
14321                 g_thread_init (NULL);
14322
14323         if (getenv ("MONO_DEBUG") != NULL)
14324                 mini_parse_debug_options ();
14325
14326         mono_gc_base_init ();
14327
14328         mono_jit_tls_id = TlsAlloc ();
14329         setup_jit_tls_data ((gpointer)-1, mono_thread_abort);
14330
14331         mono_burg_init ();
14332
14333         if (default_opt & MONO_OPT_AOT)
14334                 mono_aot_init ();
14335
14336         mono_runtime_install_handlers ();
14337         mono_threads_install_cleanup (mini_thread_cleanup);
14338
14339 #ifdef MONO_ARCH_HAVE_NOTIFY_PENDING_EXC
14340         // This is experimental code so provide an env var to switch it off
14341         if (getenv ("MONO_DISABLE_PENDING_EXCEPTIONS")) {
14342                 printf ("MONO_DISABLE_PENDING_EXCEPTIONS env var set.\n");
14343         } else {
14344                 check_for_pending_exc = FALSE;
14345                 mono_threads_install_notify_pending_exc (mono_arch_notify_pending_exc);
14346         }
14347 #endif
14348
14349 #define JIT_TRAMPOLINES_WORK
14350 #ifdef JIT_TRAMPOLINES_WORK
14351         mono_install_compile_method (mono_jit_compile_method);
14352         mono_install_free_method (mono_jit_free_method);
14353         mono_install_trampoline (mono_create_jit_trampoline);
14354         mono_install_jump_trampoline (mono_create_jump_trampoline);
14355         mono_install_remoting_trampoline (mono_jit_create_remoting_trampoline);
14356         mono_install_delegate_trampoline (mono_create_delegate_trampoline);
14357         mono_install_create_domain_hook (mini_create_jit_domain_info);
14358         mono_install_free_domain_hook (mini_free_jit_domain_info);
14359 #endif
14360 #define JIT_INVOKE_WORKS
14361 #ifdef JIT_INVOKE_WORKS
14362         mono_install_runtime_invoke (mono_jit_runtime_invoke);
14363 #endif
14364         mono_install_stack_walk (mono_jit_walk_stack);
14365         mono_install_get_cached_class_info (mono_aot_get_cached_class_info);
14366         mono_install_get_class_from_name (mono_aot_get_class_from_name);
14367         mono_install_jit_info_find_in_aot (mono_aot_find_jit_info);
14368
14369         if (debug_options.collect_pagefault_stats) {
14370                 mono_raw_buffer_set_make_unreadable (TRUE);
14371                 mono_aot_set_make_unreadable (TRUE);
14372         }
14373
14374         if (runtime_version)
14375                 domain = mono_init_version (filename, runtime_version);
14376         else
14377                 domain = mono_init_from_assembly (filename, filename);
14378
14379         if (mono_aot_only) {
14380                 /* The IMT tables are very dynamic thus they are hard to AOT */
14381                 mono_use_imt = FALSE;
14382                 /* This helps catch code allocation requests */
14383                 mono_code_manager_set_read_only (domain->code_mp);
14384         }
14385
14386 #ifdef MONO_ARCH_HAVE_IMT
14387         if (mono_use_imt) {
14388                 mono_install_imt_thunk_builder (mono_arch_build_imt_thunk);
14389                 mono_install_imt_trampoline (mini_get_imt_trampoline ());
14390 #if MONO_ARCH_COMMON_VTABLE_TRAMPOLINE
14391                 mono_install_vtable_trampoline (mini_get_vtable_trampoline ());
14392 #endif
14393         }
14394 #endif
14395
14396         /* This must come after mono_init () in the aot-only case */
14397         mono_exceptions_init ();
14398         mono_install_handler (mono_get_throw_exception ());
14399
14400         mono_icall_init ();
14401
14402         mono_add_internal_call ("System.Diagnostics.StackFrame::get_frame_info", 
14403                                 ves_icall_get_frame_info);
14404         mono_add_internal_call ("System.Diagnostics.StackTrace::get_trace", 
14405                                 ves_icall_get_trace);
14406         mono_add_internal_call ("System.Exception::get_trace", 
14407                                 ves_icall_System_Exception_get_trace);
14408         mono_add_internal_call ("System.Security.SecurityFrame::_GetSecurityFrame",
14409                                 ves_icall_System_Security_SecurityFrame_GetSecurityFrame);
14410         mono_add_internal_call ("System.Security.SecurityFrame::_GetSecurityStack",
14411                                 ves_icall_System_Security_SecurityFrame_GetSecurityStack);
14412         mono_add_internal_call ("Mono.Runtime::mono_runtime_install_handlers", 
14413                                 mono_runtime_install_handlers);
14414
14415
14416         create_helper_signature ();
14417
14418 #define JIT_CALLS_WORK
14419 #ifdef JIT_CALLS_WORK
14420         /* Needs to be called here since register_jit_icall depends on it */
14421         mono_marshal_init ();
14422
14423         mono_arch_register_lowlevel_calls ();
14424         register_icall (mono_profiler_method_enter, "mono_profiler_method_enter", NULL, TRUE);
14425         register_icall (mono_profiler_method_leave, "mono_profiler_method_leave", NULL, TRUE);
14426         register_icall (mono_trace_enter_method, "mono_trace_enter_method", NULL, TRUE);
14427         register_icall (mono_trace_leave_method, "mono_trace_leave_method", NULL, TRUE);
14428         register_icall (mono_get_lmf_addr, "mono_get_lmf_addr", "ptr", TRUE);
14429         register_icall (mono_jit_thread_attach, "mono_jit_thread_attach", "void", TRUE);
14430         register_icall (mono_domain_get, "mono_domain_get", "ptr", TRUE);
14431
14432         register_icall (mono_get_throw_exception (), "mono_arch_throw_exception", "void object", TRUE);
14433         register_icall (mono_get_rethrow_exception (), "mono_arch_rethrow_exception", "void object", TRUE);
14434         register_icall (mono_get_throw_exception_by_name (), "mono_arch_throw_exception_by_name", "void ptr", TRUE); 
14435 #if MONO_ARCH_HAVE_THROW_CORLIB_EXCEPTION
14436         register_icall (mono_get_throw_corlib_exception (), "mono_arch_throw_corlib_exception", 
14437                                  "void ptr", TRUE);
14438 #endif
14439         register_icall (mono_thread_get_undeniable_exception, "mono_thread_get_undeniable_exception", "object", FALSE);
14440         register_icall (mono_thread_interruption_checkpoint, "mono_thread_interruption_checkpoint", "void", FALSE);
14441         register_icall (mono_thread_force_interruption_checkpoint, "mono_thread_force_interruption_checkpoint", "void", FALSE);
14442         register_icall (mono_load_remote_field_new, "mono_load_remote_field_new", "object object ptr ptr", FALSE);
14443         register_icall (mono_store_remote_field_new, "mono_store_remote_field_new", "void object ptr ptr object", FALSE);
14444
14445         /* 
14446          * NOTE, NOTE, NOTE, NOTE:
14447          * when adding emulation for some opcodes, remember to also add a dummy
14448          * rule to the burg files, because we need the arity information to be correct.
14449          */
14450 #ifndef MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS
14451         mono_register_opcode_emulation (OP_LMUL, "__emul_lmul", "long long long", mono_llmult, TRUE);
14452         mono_register_opcode_emulation (OP_LDIV, "__emul_ldiv", "long long long", mono_lldiv, FALSE);
14453         mono_register_opcode_emulation (OP_LDIV_UN, "__emul_ldiv_un", "long long long", mono_lldiv_un, FALSE);
14454         mono_register_opcode_emulation (OP_LREM, "__emul_lrem", "long long long", mono_llrem, FALSE);
14455         mono_register_opcode_emulation (OP_LREM_UN, "__emul_lrem_un", "long long long", mono_llrem_un, FALSE);
14456         mono_register_opcode_emulation (OP_LMUL_OVF_UN, "__emul_lmul_ovf_un", "long long long", mono_llmult_ovf_un, FALSE);
14457         mono_register_opcode_emulation (OP_LMUL_OVF, "__emul_lmul_ovf", "long long long", mono_llmult_ovf, FALSE);
14458 #endif
14459
14460 #ifndef MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
14461         mono_register_opcode_emulation (OP_LSHL, "__emul_lshl", "long long int32", mono_lshl, TRUE);
14462         mono_register_opcode_emulation (OP_LSHR, "__emul_lshr", "long long int32", mono_lshr, TRUE);
14463         mono_register_opcode_emulation (OP_LSHR_UN, "__emul_lshr_un", "long long int32", mono_lshr_un, TRUE);
14464 #endif
14465
14466 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
14467         mono_register_opcode_emulation (CEE_DIV, "__emul_idiv", "int32 int32 int32", mono_idiv, FALSE);
14468         mono_register_opcode_emulation (CEE_DIV_UN, "__emul_idiv_un", "int32 int32 int32", mono_idiv_un, FALSE);
14469         mono_register_opcode_emulation (CEE_REM, "__emul_irem", "int32 int32 int32", mono_irem, FALSE);
14470         mono_register_opcode_emulation (CEE_REM_UN, "__emul_irem_un", "int32 int32 int32", mono_irem_un, FALSE);
14471         mono_register_opcode_emulation (OP_IDIV, "__emul_op_idiv", "int32 int32 int32", mono_idiv, FALSE);
14472         mono_register_opcode_emulation (OP_IDIV_UN, "__emul_op_idiv_un", "int32 int32 int32", mono_idiv_un, FALSE);
14473         mono_register_opcode_emulation (OP_IREM, "__emul_op_irem", "int32 int32 int32", mono_irem, FALSE);
14474         mono_register_opcode_emulation (OP_IREM_UN, "__emul_op_irem_un", "int32 int32 int32", mono_irem_un, FALSE);
14475 #endif
14476
14477 #ifdef MONO_ARCH_EMULATE_MUL_DIV
14478         mono_register_opcode_emulation (CEE_MUL_OVF, "__emul_imul_ovf", "int32 int32 int32", mono_imul_ovf, FALSE);
14479         mono_register_opcode_emulation (CEE_MUL_OVF_UN, "__emul_imul_ovf_un", "int32 int32 int32", mono_imul_ovf_un, FALSE);
14480         mono_register_opcode_emulation (CEE_MUL, "__emul_imul", "int32 int32 int32", mono_imul, TRUE);
14481         mono_register_opcode_emulation (OP_IMUL, "__emul_op_imul", "int32 int32 int32", mono_imul, TRUE);
14482         mono_register_opcode_emulation (OP_IMUL_OVF, "__emul_op_imul_ovf", "int32 int32 int32", mono_imul_ovf, FALSE);
14483         mono_register_opcode_emulation (OP_IMUL_OVF_UN, "__emul_op_imul_ovf_un", "int32 int32 int32", mono_imul_ovf_un, FALSE);
14484 #endif
14485 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_SOFT_FLOAT)
14486         mono_register_opcode_emulation (OP_FDIV, "__emul_fdiv", "double double double", mono_fdiv, FALSE);
14487 #endif
14488
14489         mono_register_opcode_emulation (OP_FCONV_TO_U8, "__emul_fconv_to_u8", "ulong double", mono_fconv_u8, FALSE);
14490         mono_register_opcode_emulation (OP_FCONV_TO_U4, "__emul_fconv_to_u4", "uint32 double", mono_fconv_u4, FALSE);
14491         mono_register_opcode_emulation (OP_FCONV_TO_OVF_I8, "__emul_fconv_to_ovf_i8", "long double", mono_fconv_ovf_i8, FALSE);
14492         mono_register_opcode_emulation (OP_FCONV_TO_OVF_U8, "__emul_fconv_to_ovf_u8", "ulong double", mono_fconv_ovf_u8, FALSE);
14493
14494 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
14495         mono_register_opcode_emulation (OP_FCONV_TO_I8, "__emul_fconv_to_i8", "long double", mono_fconv_i8, FALSE);
14496 #endif
14497 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
14498         mono_register_opcode_emulation (CEE_CONV_R_UN, "__emul_conv_r_un", "double int32", mono_conv_to_r8_un, FALSE);
14499         mono_register_opcode_emulation (OP_ICONV_TO_R_UN, "__emul_iconv_to_r_un", "double int32", mono_conv_to_r8_un, FALSE);
14500 #endif
14501 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
14502         mono_register_opcode_emulation (OP_LCONV_TO_R8, "__emul_lconv_to_r8", "double long", mono_lconv_to_r8, FALSE);
14503 #endif
14504 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
14505         mono_register_opcode_emulation (OP_LCONV_TO_R4, "__emul_lconv_to_r4", "float long", mono_lconv_to_r4, FALSE);
14506 #endif
14507 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
14508         mono_register_opcode_emulation (OP_LCONV_TO_R_UN, "__emul_lconv_to_r8_un", "double long", mono_lconv_to_r8_un, FALSE);
14509 #endif
14510 #ifdef MONO_ARCH_EMULATE_FREM
14511         mono_register_opcode_emulation (OP_FREM, "__emul_frem", "double double double", fmod, FALSE);
14512 #endif
14513
14514 #ifdef MONO_ARCH_SOFT_FLOAT
14515         mono_register_opcode_emulation (OP_FSUB, "__emul_fsub", "double double double", mono_fsub, FALSE);
14516         mono_register_opcode_emulation (OP_FADD, "__emul_fadd", "double double double", mono_fadd, FALSE);
14517         mono_register_opcode_emulation (OP_FMUL, "__emul_fmul", "double double double", mono_fmul, FALSE);
14518         mono_register_opcode_emulation (OP_FNEG, "__emul_fneg", "double double", mono_fneg, FALSE);
14519         mono_register_opcode_emulation (CEE_CONV_R8, "__emul_conv_r8", "double int32", mono_conv_to_r8, FALSE);
14520         mono_register_opcode_emulation (OP_ICONV_TO_R8, "__emul_iconv_to_r8", "double int32", mono_conv_to_r8, FALSE);
14521         mono_register_opcode_emulation (CEE_CONV_R4, "__emul_conv_r4", "double int32", mono_conv_to_r4, FALSE);
14522         mono_register_opcode_emulation (OP_ICONV_TO_R4, "__emul_iconv_to_r4", "double int32", mono_conv_to_r4, FALSE);
14523         mono_register_opcode_emulation (OP_FCONV_TO_R4, "__emul_fconv_to_r4", "double double", mono_fconv_r4, FALSE);
14524         mono_register_opcode_emulation (OP_FCONV_TO_I1, "__emul_fconv_to_i1", "int8 double", mono_fconv_i1, FALSE);
14525         mono_register_opcode_emulation (OP_FCONV_TO_I2, "__emul_fconv_to_i2", "int16 double", mono_fconv_i2, FALSE);
14526         mono_register_opcode_emulation (OP_FCONV_TO_I4, "__emul_fconv_to_i4", "int32 double", mono_fconv_i4, FALSE);
14527         mono_register_opcode_emulation (OP_FCONV_TO_U1, "__emul_fconv_to_u1", "uint8 double", mono_fconv_u1, FALSE);
14528         mono_register_opcode_emulation (OP_FCONV_TO_U2, "__emul_fconv_to_u2", "uint16 double", mono_fconv_u2, FALSE);
14529
14530         mono_register_opcode_emulation (OP_FBEQ, "__emul_fcmp_eq", "uint32 double double", mono_fcmp_eq, FALSE);
14531         mono_register_opcode_emulation (OP_FBLT, "__emul_fcmp_lt", "uint32 double double", mono_fcmp_lt, FALSE);
14532         mono_register_opcode_emulation (OP_FBGT, "__emul_fcmp_gt", "uint32 double double", mono_fcmp_gt, FALSE);
14533         mono_register_opcode_emulation (OP_FBLE, "__emul_fcmp_le", "uint32 double double", mono_fcmp_le, FALSE);
14534         mono_register_opcode_emulation (OP_FBGE, "__emul_fcmp_ge", "uint32 double double", mono_fcmp_ge, FALSE);
14535         mono_register_opcode_emulation (OP_FBNE_UN, "__emul_fcmp_ne_un", "uint32 double double", mono_fcmp_ne_un, FALSE);
14536         mono_register_opcode_emulation (OP_FBLT_UN, "__emul_fcmp_lt_un", "uint32 double double", mono_fcmp_lt_un, FALSE);
14537         mono_register_opcode_emulation (OP_FBGT_UN, "__emul_fcmp_gt_un", "uint32 double double", mono_fcmp_gt_un, FALSE);
14538         mono_register_opcode_emulation (OP_FBLE_UN, "__emul_fcmp_le_un", "uint32 double double", mono_fcmp_le_un, FALSE);
14539         mono_register_opcode_emulation (OP_FBGE_UN, "__emul_fcmp_ge_un", "uint32 double double", mono_fcmp_ge_un, FALSE);
14540
14541         mono_register_opcode_emulation (OP_FCEQ, "__emul_fcmp_ceq", "uint32 double double", mono_fceq, FALSE);
14542         mono_register_opcode_emulation (OP_FCGT, "__emul_fcmp_cgt", "uint32 double double", mono_fcgt, FALSE);
14543         mono_register_opcode_emulation (OP_FCGT_UN, "__emul_fcmp_cgt_un", "uint32 double double", mono_fcgt_un, FALSE);
14544         mono_register_opcode_emulation (OP_FCLT, "__emul_fcmp_clt", "uint32 double double", mono_fclt, FALSE);
14545         mono_register_opcode_emulation (OP_FCLT_UN, "__emul_fcmp_clt_un", "uint32 double double", mono_fclt_un, FALSE);
14546
14547         register_icall (mono_fload_r4, "mono_fload_r4", "double ptr", FALSE);
14548         register_icall (mono_fstore_r4, "mono_fstore_r4", "void double ptr", FALSE);
14549         register_icall (mono_fload_r4_arg, "mono_fload_r4_arg", "uint32 double", FALSE);
14550 #endif
14551
14552 #if SIZEOF_VOID_P == 4
14553         mono_register_opcode_emulation (OP_FCONV_TO_U, "__emul_fconv_to_u", "uint32 double", mono_fconv_u4, TRUE);
14554 #endif
14555
14556         /* other jit icalls */
14557         register_icall (mono_delegate_ctor, "mono_delegate_ctor", "void object object ptr", FALSE);
14558         register_icall (mono_class_static_field_address , "mono_class_static_field_address", 
14559                                  "ptr ptr ptr", FALSE);
14560         register_icall (mono_ldtoken_wrapper, "mono_ldtoken_wrapper", "ptr ptr ptr ptr", FALSE);
14561         register_icall (mono_ldtoken_wrapper_generic_shared, "mono_ldtoken_wrapper_generic_shared",
14562                 "ptr ptr ptr ptr", FALSE);
14563         register_icall (mono_get_special_static_data, "mono_get_special_static_data", "ptr int", FALSE);
14564         register_icall (mono_ldstr, "mono_ldstr", "object ptr ptr int32", FALSE);
14565         register_icall (mono_helper_stelem_ref_check, "helper_stelem_ref_check", "void object object", FALSE);
14566         register_icall (mono_object_new, "mono_object_new", "object ptr ptr", FALSE);
14567         register_icall (mono_object_new_specific, "mono_object_new_specific", "object ptr", FALSE);
14568         register_icall (mono_array_new, "mono_array_new", "object ptr ptr int32", FALSE);
14569         register_icall (mono_array_new_specific, "mono_array_new_specific", "object ptr int32", FALSE);
14570         register_icall (mono_runtime_class_init, "mono_runtime_class_init", "void ptr", FALSE);
14571         register_icall (mono_ldftn, "mono_ldftn", "ptr ptr", FALSE);
14572         register_icall (mono_ldvirtfn, "mono_ldvirtfn", "ptr object ptr", FALSE);
14573         register_icall (mono_ldvirtfn_gshared, "mono_ldvirtfn_gshared", "ptr object ptr", FALSE);
14574         register_icall (mono_helper_compile_generic_method, "compile_generic_method", "ptr object ptr ptr", FALSE);
14575         register_icall (mono_helper_ldstr, "helper_ldstr", "object ptr int", FALSE);
14576         register_icall (mono_helper_ldstr_mscorlib, "helper_ldstr_mscorlib", "object int", FALSE);
14577         register_icall (mono_helper_newobj_mscorlib, "helper_newobj_mscorlib", "object int", FALSE);
14578         register_icall (mono_value_copy, "mono_value_copy", "void ptr ptr ptr", FALSE);
14579         register_icall (mono_object_castclass, "mono_object_castclass", "object object ptr", FALSE);
14580         register_icall (mono_break, "mono_break", NULL, TRUE);
14581         register_icall (mono_create_corlib_exception_0, "mono_create_corlib_exception_0", "object int", TRUE);
14582         register_icall (mono_create_corlib_exception_1, "mono_create_corlib_exception_1", "object int object", TRUE);
14583         register_icall (mono_create_corlib_exception_2, "mono_create_corlib_exception_2", "object int object object", TRUE);
14584         register_icall (mono_array_new_1, "mono_array_new_1", "object ptr int", FALSE);
14585         register_icall (mono_array_new_2, "mono_array_new_2", "object ptr int int", FALSE);
14586 #endif
14587
14588         mono_generic_sharing_init ();
14589
14590         if (mono_compile_aot)
14591                 /* 
14592                  * Avoid running managed code when AOT compiling, since the platform
14593                  * might only support aot-only execution.
14594                  */
14595                 mono_runtime_set_no_exec (TRUE);
14596
14597 #define JIT_RUNTIME_WORKS
14598 #ifdef JIT_RUNTIME_WORKS
14599         mono_install_runtime_cleanup ((MonoDomainFunc)mini_cleanup);
14600         mono_runtime_init (domain, mono_thread_start_cb, mono_thread_attach_cb);
14601         mono_thread_attach (domain);
14602 #endif
14603
14604         mono_profiler_runtime_initialized ();
14605         
14606         MONO_PROBE_VES_INIT_END ();
14607         
14608         return domain;
14609 }
14610
14611 MonoJitStats mono_jit_stats = {0};
14612
14613 static void 
14614 print_jit_stats (void)
14615 {
14616         if (mono_jit_stats.enabled) {
14617                 g_print ("Mono Jit statistics\n");
14618                 g_print ("Compiled methods:       %ld\n", mono_jit_stats.methods_compiled);
14619                 g_print ("Methods from AOT:       %ld\n", mono_jit_stats.methods_aot);
14620                 g_print ("Methods cache lookup:   %ld\n", mono_jit_stats.methods_lookups);
14621                 g_print ("Method trampolines:     %ld\n", mono_jit_stats.method_trampolines);
14622                 g_print ("Basic blocks:           %ld\n", mono_jit_stats.basic_blocks);
14623                 g_print ("Max basic blocks:       %ld\n", mono_jit_stats.max_basic_blocks);
14624                 g_print ("Allocated vars:         %ld\n", mono_jit_stats.allocate_var);
14625                 g_print ("Analyze stack repeat:   %ld\n", mono_jit_stats.analyze_stack_repeat);
14626                 g_print ("Compiled CIL code size: %ld\n", mono_jit_stats.cil_code_size);
14627                 g_print ("Native code size:       %ld\n", mono_jit_stats.native_code_size);
14628                 g_print ("Max code size ratio:    %.2f (%s)\n", mono_jit_stats.max_code_size_ratio/100.0,
14629                                  mono_jit_stats.max_ratio_method);
14630                 g_print ("Biggest method:         %ld (%s)\n", mono_jit_stats.biggest_method_size,
14631                                  mono_jit_stats.biggest_method);
14632                 g_print ("Code reallocs:          %ld\n", mono_jit_stats.code_reallocs);
14633                 g_print ("Allocated code size:    %ld\n", mono_jit_stats.allocated_code_size);
14634                 g_print ("Inlineable methods:     %ld\n", mono_jit_stats.inlineable_methods);
14635                 g_print ("Inlined methods:        %ld\n", mono_jit_stats.inlined_methods);
14636                 g_print ("Regvars:                %ld\n", mono_jit_stats.regvars);
14637                 g_print ("Locals stack size:      %ld\n", mono_jit_stats.locals_stack_size);
14638
14639                 g_print ("\nCreated object count:   %ld\n", mono_stats.new_object_count);
14640                 g_print ("Delegates created:      %ld\n", mono_stats.delegate_creations);
14641                 g_print ("Initialized classes:    %ld\n", mono_stats.initialized_class_count);
14642                 g_print ("Used classes:           %ld\n", mono_stats.used_class_count);
14643                 g_print ("Generic vtables:        %ld\n", mono_stats.generic_vtable_count);
14644                 g_print ("Methods:                %ld\n", mono_stats.method_count);
14645                 g_print ("Static data size:       %ld\n", mono_stats.class_static_data_size);
14646                 g_print ("VTable data size:       %ld\n", mono_stats.class_vtable_size);
14647                 g_print ("Mscorlib mempool size:  %d\n", mono_mempool_get_allocated (mono_defaults.corlib->mempool));
14648
14649                 g_print ("\nGeneric instances:      %ld\n", mono_stats.generic_instance_count);
14650                 g_print ("Initialized classes:    %ld\n", mono_stats.generic_class_count);
14651                 g_print ("Inflated methods:       %ld / %ld\n", mono_stats.inflated_method_count_2,
14652                          mono_stats.inflated_method_count);
14653                 g_print ("Inflated types:         %ld\n", mono_stats.inflated_type_count);
14654                 g_print ("Generics metadata size: %ld\n", mono_stats.generics_metadata_size);
14655                 g_print ("Generics virtual invokes: %ld\n", mono_jit_stats.generic_virtual_invocations);
14656
14657                 g_print ("Sharable generic methods: %ld\n", mono_stats.generics_sharable_methods);
14658                 g_print ("Unsharable generic methods: %ld\n", mono_stats.generics_unsharable_methods);
14659                 g_print ("Shared generic methods: %ld\n", mono_stats.generics_shared_methods);
14660
14661                 g_print ("Dynamic code allocs:    %ld\n", mono_stats.dynamic_code_alloc_count);
14662                 g_print ("Dynamic code bytes:     %ld\n", mono_stats.dynamic_code_bytes_count);
14663                 g_print ("Dynamic code frees:     %ld\n", mono_stats.dynamic_code_frees_count);
14664
14665                 g_print ("IMT tables size:        %ld\n", mono_stats.imt_tables_size);
14666                 g_print ("IMT number of tables:   %ld\n", mono_stats.imt_number_of_tables);
14667                 g_print ("IMT number of methods:  %ld\n", mono_stats.imt_number_of_methods);
14668                 g_print ("IMT used slots:         %ld\n", mono_stats.imt_used_slots);
14669                 g_print ("IMT colliding slots:    %ld\n", mono_stats.imt_slots_with_collisions);
14670                 g_print ("IMT max collisions:     %ld\n", mono_stats.imt_max_collisions_in_slot);
14671                 g_print ("IMT methods at max col: %ld\n", mono_stats.imt_method_count_when_max_collisions);
14672                 g_print ("IMT thunks size:        %ld\n", mono_stats.imt_thunks_size);
14673
14674                 g_print ("JIT info table inserts: %ld\n", mono_stats.jit_info_table_insert_count);
14675                 g_print ("JIT info table removes: %ld\n", mono_stats.jit_info_table_remove_count);
14676                 g_print ("JIT info table lookups: %ld\n", mono_stats.jit_info_table_lookup_count);
14677
14678                 g_print ("Hazardous pointers:     %ld\n", mono_stats.hazardous_pointer_count);
14679 #ifdef HAVE_SGEN_GC
14680                 g_print ("Minor GC collections:   %ld\n", mono_stats.minor_gc_count);
14681                 g_print ("Major GC collections:   %ld\n", mono_stats.major_gc_count);
14682                 g_print ("Minor GC time in msecs: %lf\n", (double)mono_stats.minor_gc_time_usecs / 1000.0);
14683                 g_print ("Major GC time in msecs: %lf\n", (double)mono_stats.major_gc_time_usecs / 1000.0);
14684 #endif
14685                 if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS) {
14686                         g_print ("\nDecl security check   : %ld\n", mono_jit_stats.cas_declsec_check);
14687                         g_print ("LinkDemand (user)     : %ld\n", mono_jit_stats.cas_linkdemand);
14688                         g_print ("LinkDemand (icall)    : %ld\n", mono_jit_stats.cas_linkdemand_icall);
14689                         g_print ("LinkDemand (pinvoke)  : %ld\n", mono_jit_stats.cas_linkdemand_pinvoke);
14690                         g_print ("LinkDemand (aptc)     : %ld\n", mono_jit_stats.cas_linkdemand_aptc);
14691                         g_print ("Demand (code gen)     : %ld\n", mono_jit_stats.cas_demand_generation);
14692                 }
14693                 if (debug_options.collect_pagefault_stats) {
14694                         g_print ("Metadata pagefaults   : %d\n", mono_raw_buffer_get_n_pagefaults ());
14695                         g_print ("AOT pagefaults        : %d\n", mono_aot_get_n_pagefaults ());
14696                 }
14697
14698                 g_free (mono_jit_stats.max_ratio_method);
14699                 mono_jit_stats.max_ratio_method = NULL;
14700                 g_free (mono_jit_stats.biggest_method);
14701                 mono_jit_stats.biggest_method = NULL;
14702         }
14703 }
14704
14705 void
14706 mini_cleanup (MonoDomain *domain)
14707 {
14708 #ifdef HAVE_LINUX_RTC_H
14709         if (rtc_fd >= 0)
14710                 enable_rtc_timer (FALSE);
14711 #endif
14712
14713         /* 
14714          * mono_runtime_cleanup() and mono_domain_finalize () need to
14715          * be called early since they need the execution engine still
14716          * fully working (mono_domain_finalize may invoke managed finalizers
14717          * and mono_runtime_cleanup will wait for other threads to finish).
14718          */
14719         mono_domain_finalize (domain, 2000);
14720
14721         /* This accesses metadata so needs to be called before runtime shutdown */
14722         print_jit_stats ();
14723
14724         mono_runtime_cleanup (domain);
14725
14726         mono_profiler_shutdown ();
14727
14728         mono_icall_cleanup ();
14729
14730         mono_runtime_cleanup_handlers ();
14731
14732         mono_domain_free (domain, TRUE);
14733
14734         mono_debugger_cleanup ();
14735
14736         mono_trampolines_cleanup ();
14737
14738         mono_code_manager_destroy (global_codeman);
14739         g_hash_table_destroy (jit_icall_name_hash);
14740         g_free (emul_opcode_map);
14741
14742         mono_arch_cleanup ();
14743
14744         mono_cleanup ();
14745
14746         mono_trace_cleanup ();
14747
14748         mono_counters_dump (-1, stdout);
14749
14750         if (mono_inject_async_exc_method)
14751                 mono_method_desc_free (mono_inject_async_exc_method);
14752
14753         TlsFree(mono_jit_tls_id);
14754
14755         DeleteCriticalSection (&jit_mutex);
14756
14757         DeleteCriticalSection (&mono_delegate_section);
14758 }
14759
14760 void
14761 mono_set_defaults (int verbose_level, guint32 opts)
14762 {
14763         mini_verbose = verbose_level;
14764         default_opt = opts;
14765         default_opt_set = TRUE;
14766 }
14767
14768 static void
14769 mono_precompile_assembly (MonoAssembly *ass, void *user_data)
14770 {
14771         GHashTable *assemblies = (GHashTable*)user_data;
14772         MonoImage *image = mono_assembly_get_image (ass);
14773         MonoMethod *method, *invoke;
14774         int i, count = 0;
14775
14776         if (g_hash_table_lookup (assemblies, ass))
14777                 return;
14778
14779         g_hash_table_insert (assemblies, ass, ass);
14780
14781         if (mini_verbose > 0)
14782                 printf ("PRECOMPILE: %s.\n", mono_image_get_filename (image));
14783
14784         for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_METHOD); ++i) {
14785                 method = mono_get_method (image, MONO_TOKEN_METHOD_DEF | (i + 1), NULL);
14786                 if (method->flags & METHOD_ATTRIBUTE_ABSTRACT)
14787                         continue;
14788
14789                 count++;
14790                 if (mini_verbose > 1) {
14791                         char * desc = mono_method_full_name (method, TRUE);
14792                         g_print ("Compiling %d %s\n", count, desc);
14793                         g_free (desc);
14794                 }
14795                 mono_compile_method (method);
14796                 if (strcmp (method->name, "Finalize") == 0) {
14797                         invoke = mono_marshal_get_runtime_invoke (method);
14798                         mono_compile_method (invoke);
14799                 }
14800                 if (method->klass->marshalbyref && mono_method_signature (method)->hasthis) {
14801                         invoke = mono_marshal_get_remoting_invoke_with_check (method);
14802                         mono_compile_method (invoke);
14803                 }
14804         }
14805
14806         /* Load and precompile referenced assemblies as well */
14807         for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_ASSEMBLYREF); ++i) {
14808                 mono_assembly_load_reference (image, i);
14809                 if (image->references [i])
14810                         mono_precompile_assembly (image->references [i], assemblies);
14811         }
14812 }
14813
14814 void mono_precompile_assemblies ()
14815 {
14816         GHashTable *assemblies = g_hash_table_new (NULL, NULL);
14817
14818         mono_assembly_foreach ((GFunc)mono_precompile_assembly, assemblies);
14819
14820         g_hash_table_destroy (assemblies);
14821 }